feat(chat): 添加聊天功能和Markwon富文本支持
- 集成io.noties.markwon库用于Markdown渲染 - 新增ChatItem数据模型类 - 创建ChatActivity实现聊天界面和离线命令监听 - 添加ChatVM视图模型提供聊天数据 - 设计activity_chat.xml和item_chat.xml布局文件 - 在WelcomeActivity中添加决策中心入口按钮 - 配置AndroidManifest.xml注册ChatActivity - 移除base模块中的Maven发布配置
这个提交包含在:
父节点
c77b59cee4
当前提交
aba8c69a0c
@ -78,6 +78,7 @@ dependencies {
|
|||||||
implementation 'androidx.legacy:legacy-support-v4:1.0.0'
|
implementation 'androidx.legacy:legacy-support-v4:1.0.0'
|
||||||
implementation 'androidx.appcompat:appcompat:1.3.0'
|
implementation 'androidx.appcompat:appcompat:1.3.0'
|
||||||
implementation 'com.google.android.material:material:1.3.0'
|
implementation 'com.google.android.material:material:1.3.0'
|
||||||
|
implementation "io.noties.markwon:core:4.6.2"
|
||||||
|
|
||||||
implementation ('com.rokid.security:glass3.open.sdk:2.1.5-E') {
|
implementation ('com.rokid.security:glass3.open.sdk:2.1.5-E') {
|
||||||
exclude group: "org.slf4j"
|
exclude group: "org.slf4j"
|
||||||
|
|||||||
@ -75,6 +75,9 @@
|
|||||||
<activity
|
<activity
|
||||||
android:name=".ui.TaskListActivity"
|
android:name=".ui.TaskListActivity"
|
||||||
android:exported="false" />
|
android:exported="false" />
|
||||||
|
<activity
|
||||||
|
android:name=".ui.ChatActivity"
|
||||||
|
android:exported="false" />
|
||||||
<activity
|
<activity
|
||||||
android:name=".ui.InspectionActivity"
|
android:name=".ui.InspectionActivity"
|
||||||
android:exported="false" />
|
android:exported="false" />
|
||||||
|
|||||||
@ -0,0 +1,6 @@
|
|||||||
|
package com.nova.brain.glass.model
|
||||||
|
|
||||||
|
import com.xuqm.base.adapter.BaseItem
|
||||||
|
|
||||||
|
data class ChatItem(val title: String, val content: String): BaseItem() {
|
||||||
|
}
|
||||||
@ -0,0 +1,54 @@
|
|||||||
|
package com.nova.brain.glass.ui
|
||||||
|
|
||||||
|
import android.widget.TextView
|
||||||
|
import com.nova.brain.glass.R
|
||||||
|
import com.nova.brain.glass.helper.OfflineCmdListener
|
||||||
|
import com.nova.brain.glass.helper.OfflineCmdServiceHelper
|
||||||
|
import com.nova.brain.glass.model.ChatItem
|
||||||
|
import com.nova.brain.glass.viewmodel.ChatVM
|
||||||
|
import com.xuqm.base.adapter.BasePagedAdapter
|
||||||
|
import com.xuqm.base.adapter.CommonPagedAdapter
|
||||||
|
import com.xuqm.base.adapter.ViewHolder
|
||||||
|
import com.xuqm.base.ui.BaseListActivity
|
||||||
|
import io.noties.markwon.Markwon
|
||||||
|
|
||||||
|
class ChatActivity : BaseListActivity<ChatItem, ChatVM>() {
|
||||||
|
private val listener = object : OfflineCmdListener {
|
||||||
|
override fun onOfflineCmd(cmd: String) {
|
||||||
|
runOnUiThread {
|
||||||
|
when (cmd) {
|
||||||
|
"退出", "返回", "退回" -> {
|
||||||
|
finish()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
private lateinit var markwon: Markwon
|
||||||
|
override fun initData() {
|
||||||
|
super.initData()
|
||||||
|
|
||||||
|
markwon = Markwon.create(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onResume() {
|
||||||
|
super.onResume()
|
||||||
|
OfflineCmdServiceHelper.addOnLineListener(listener)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onPause() {
|
||||||
|
super.onPause()
|
||||||
|
OfflineCmdServiceHelper.removeOnLineListener(listener)
|
||||||
|
}
|
||||||
|
|
||||||
|
private val adapter = object : CommonPagedAdapter<ChatItem>(R.layout.item_chat) {
|
||||||
|
override fun convert(holder: ViewHolder, item: ChatItem, position: Int) {
|
||||||
|
holder.setText(R.id.title, item.title)
|
||||||
|
|
||||||
|
val tv = holder.getView<TextView>(R.id.content)
|
||||||
|
markwon.setMarkdown(tv, item.content);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun adapter(): BasePagedAdapter<ChatItem> = adapter
|
||||||
|
}
|
||||||
@ -9,6 +9,7 @@ import com.nova.brain.glass.helper.OfflineCmdListener
|
|||||||
import com.nova.brain.glass.helper.OfflineCmdServiceHelper
|
import com.nova.brain.glass.helper.OfflineCmdServiceHelper
|
||||||
import com.nova.brain.glass.viewmodel.WelcomeVM
|
import com.nova.brain.glass.viewmodel.WelcomeVM
|
||||||
import com.xuqm.base.ui.BaseActivity
|
import com.xuqm.base.ui.BaseActivity
|
||||||
|
import kotlin.jvm.java
|
||||||
|
|
||||||
class WelcomeActivity : BaseActivity<ActivityWelcomeBinding>() {
|
class WelcomeActivity : BaseActivity<ActivityWelcomeBinding>() {
|
||||||
|
|
||||||
@ -27,6 +28,7 @@ class WelcomeActivity : BaseActivity<ActivityWelcomeBinding>() {
|
|||||||
binding.btnGet.setOnClickListener { vm.demoGet() }
|
binding.btnGet.setOnClickListener { vm.demoGet() }
|
||||||
binding.btnPost.setOnClickListener { vm.demoPost() }
|
binding.btnPost.setOnClickListener { vm.demoPost() }
|
||||||
binding.btnSse.setOnClickListener { vm.demoPostSse() }
|
binding.btnSse.setOnClickListener { vm.demoPostSse() }
|
||||||
|
binding.md.setOnClickListener { startActivity(Intent(this@WelcomeActivity, ChatActivity::class.java)) }
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun initData() {
|
override fun initData() {
|
||||||
|
|||||||
@ -0,0 +1,46 @@
|
|||||||
|
package com.nova.brain.glass.viewmodel
|
||||||
|
|
||||||
|
import com.nova.brain.glass.model.ChatItem
|
||||||
|
import com.xuqm.base.viewmodel.BaseListViewModel
|
||||||
|
import com.xuqm.base.viewmodel.callback.Response
|
||||||
|
|
||||||
|
|
||||||
|
class ChatVM : BaseListViewModel<ChatItem>() {
|
||||||
|
override fun loadData(
|
||||||
|
page: Int,
|
||||||
|
onResponse: Response<ChatItem>
|
||||||
|
) {
|
||||||
|
onResponse.onResponse(arrayListOf<ChatItem>().apply {
|
||||||
|
add(
|
||||||
|
ChatItem(
|
||||||
|
"本周周报", """
|
||||||
|
## 统计数据截止到:2026年3月19日 1:36
|
||||||
|
|
||||||
|
### 纪检Agent3期产品设计】明日到达计划完成时间。
|
||||||
|
|
||||||
|
#### *重点关注*:张三【测试运维部】负责的“C大脑-脑实例- V2.24-测试方案设计
|
||||||
|
|
||||||
|
* 当前状态:已延期13天,严重程度为【严重延期】。
|
||||||
|
* 参谋建议:建议高优处理。
|
||||||
|
|
||||||
|
""".trimIndent()
|
||||||
|
)
|
||||||
|
)
|
||||||
|
add(
|
||||||
|
ChatItem(
|
||||||
|
"我最紧急的任务是哪个", """
|
||||||
|
|
||||||
|
# 标题
|
||||||
|
|
||||||
|
这是 **加粗**、*斜体*、~~删除线~~
|
||||||
|
|
||||||
|
- 列表1
|
||||||
|
- 列表2
|
||||||
|
|
||||||
|
[点击跳转](https://openai.com)
|
||||||
|
""".trimIndent()
|
||||||
|
)
|
||||||
|
)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,32 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<layout>
|
||||||
|
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||||
|
xmlns:tools="http://schemas.android.com/tools"
|
||||||
|
android:id="@+id/main"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
android:background="@color/app_color_black">
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/tvTaskHeader"
|
||||||
|
android:layout_width="0dp"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:text="130工序要求如下:"
|
||||||
|
android:textColor="#ff40FF5E"
|
||||||
|
android:textSize="20sp"
|
||||||
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
|
app:layout_constraintTop_toTopOf="parent" />
|
||||||
|
<WebView
|
||||||
|
android:id="@+id/content"
|
||||||
|
android:layout_width="0dp"
|
||||||
|
android:layout_height="0dp"
|
||||||
|
android:layout_marginTop="10dp"
|
||||||
|
app:layout_constraintBottom_toBottomOf="parent"
|
||||||
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
|
app:layout_constraintTop_toBottomOf="@+id/tvTaskHeader" />
|
||||||
|
|
||||||
|
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||||
|
</layout>
|
||||||
@ -64,13 +64,38 @@
|
|||||||
android:textSize="14sp"
|
android:textSize="14sp"
|
||||||
android:text="SSE演示" />
|
android:text="SSE演示" />
|
||||||
</LinearLayout>
|
</LinearLayout>
|
||||||
|
<LinearLayout
|
||||||
|
android:id="@+id/btnRow2"
|
||||||
|
android:layout_width="0dp"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:orientation="horizontal"
|
||||||
|
android:gravity="center"
|
||||||
|
android:layout_marginHorizontal="16dp"
|
||||||
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
|
android:layout_marginTop="10dp"
|
||||||
|
app:layout_constraintTop_toBottomOf="@id/btnRow">
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/md"
|
||||||
|
android:layout_width="0dp"
|
||||||
|
android:layout_height="40dp"
|
||||||
|
android:layout_weight="1"
|
||||||
|
android:layout_marginEnd="8dp"
|
||||||
|
android:gravity="center"
|
||||||
|
android:background="#33FFFFFF"
|
||||||
|
android:textColor="#ff3FFF5F"
|
||||||
|
android:textSize="14sp"
|
||||||
|
android:text="决策中心" />
|
||||||
|
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
<ScrollView
|
<ScrollView
|
||||||
android:id="@+id/scrollResult"
|
android:id="@+id/scrollResult"
|
||||||
android:layout_width="0dp"
|
android:layout_width="0dp"
|
||||||
android:layout_height="0dp"
|
android:layout_height="0dp"
|
||||||
android:layout_marginTop="8dp"
|
android:layout_marginTop="8dp"
|
||||||
app:layout_constraintTop_toBottomOf="@id/btnRow"
|
app:layout_constraintTop_toBottomOf="@id/btnRow2"
|
||||||
app:layout_constraintBottom_toBottomOf="parent"
|
app:layout_constraintBottom_toBottomOf="parent"
|
||||||
app:layout_constraintStart_toStartOf="parent"
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
app:layout_constraintEnd_toEndOf="parent">
|
app:layout_constraintEnd_toEndOf="parent">
|
||||||
|
|||||||
@ -0,0 +1,26 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginBottom="20dp"
|
||||||
|
android:paddingHorizontal="29dp"
|
||||||
|
android:paddingVertical="10dp"
|
||||||
|
android:orientation="vertical">
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/title"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:text="驳回"
|
||||||
|
android:textColor="#2EB242"
|
||||||
|
android:textSize="10sp" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/content"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginTop="10dp"
|
||||||
|
android:text="驳回"
|
||||||
|
android:textColor="#ff40FF5E"
|
||||||
|
android:textSize="14sp" />
|
||||||
|
</LinearLayout>
|
||||||
@ -1,10 +1,5 @@
|
|||||||
apply plugin: 'com.android.library'
|
apply plugin: 'com.android.library'
|
||||||
apply plugin: 'kotlin-android'
|
apply plugin: 'kotlin-android'
|
||||||
apply plugin: 'maven-publish'
|
|
||||||
|
|
||||||
// 声明aar包的版本号
|
|
||||||
def aarVersion = "0.0.1.101"
|
|
||||||
|
|
||||||
|
|
||||||
android {
|
android {
|
||||||
compileSdkVersion versions.compileSdk
|
compileSdkVersion versions.compileSdk
|
||||||
@ -54,47 +49,3 @@ task sourceJar(type: Jar) {
|
|||||||
archiveClassifier.set('sources')
|
archiveClassifier.set('sources')
|
||||||
from android.sourceSets.main.java.srcDirs
|
from android.sourceSets.main.java.srcDirs
|
||||||
}
|
}
|
||||||
afterEvaluate {
|
|
||||||
publishing {
|
|
||||||
publications {
|
|
||||||
// 这里的debug名字是自己起的
|
|
||||||
release(MavenPublication) {
|
|
||||||
groupId = 'cn.org.bjca.trust.android'
|
|
||||||
artifactId = 'base'
|
|
||||||
version = aarVersion
|
|
||||||
// 这里除了有debug 还有release
|
|
||||||
from components.release
|
|
||||||
// 运行任务,把源码打进去
|
|
||||||
artifact sourceJar
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// 添加仓库地址
|
|
||||||
repositories {
|
|
||||||
// 本地仓库
|
|
||||||
// mavenLocal()
|
|
||||||
// 当上传到远端仓库
|
|
||||||
// maven {
|
|
||||||
// allowInsecureProtocol true
|
|
||||||
// url("http://nexus.51trust.net/repository/android-hosted/")
|
|
||||||
// credentials {
|
|
||||||
// username = "deployment"
|
|
||||||
// password = "deployment123"
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
maven {
|
|
||||||
allowInsecureProtocol true
|
|
||||||
url("http://xuqinmin.com.cn:8081/repository/android-releases/")
|
|
||||||
credentials {
|
|
||||||
// 从 local.properties 读取,避免凭据提交到版本控制
|
|
||||||
def props = new Properties()
|
|
||||||
def localPropertiesFile = rootProject.file("local.properties")
|
|
||||||
if (localPropertiesFile.exists()) {
|
|
||||||
localPropertiesFile.withInputStream { props.load(it) }
|
|
||||||
}
|
|
||||||
username = props.getProperty("nexus.username", "")
|
|
||||||
password = props.getProperty("nexus.password", "")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
正在加载...
在新工单中引用
屏蔽一个用户