From b4fddabb2bbbc3a7aaffa0d811fe7b7b34b19a56 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sat, 7 Mar 2026 11:47:09 +0000 Subject: [PATCH 1/4] Initial plan From 2c3a7162019f8fcd7e4e23e227969b1f72059a37 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sat, 7 Mar 2026 11:49:23 +0000 Subject: [PATCH 2/4] chore: outline plan for educational content feature Co-authored-by: NITEACE <135036433+NITEACE@users.noreply.github.com> --- gradlew | 0 1 file changed, 0 insertions(+), 0 deletions(-) mode change 100644 => 100755 gradlew diff --git a/gradlew b/gradlew old mode 100644 new mode 100755 From 012c23728e1e556a45aaabd593cbd16e9bf981e5 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sat, 7 Mar 2026 11:52:58 +0000 Subject: [PATCH 3/4] feat: add chat knowledge guide screen Co-authored-by: NITEACE <135036433+NITEACE@users.noreply.github.com> --- app/build.gradle.kts | 6 +- app/src/main/AndroidManifest.xml | 6 +- .../conversation/ConversationListActivity.kt | 7 +- .../chatapp/ui/guide/ChatKnowledgeActivity.kt | 36 +++++++++ .../chatapp/ui/guide/ChatKnowledgeContent.kt | 45 +++++++++++ .../res/layout/activity_chat_knowledge.xml | 80 +++++++++++++++++++ .../main/res/menu/menu_conversation_list.xml | 8 +- app/src/main/res/values/strings.xml | 7 +- .../guide/ChatKnowledgeContentProviderTest.kt | 17 ++++ gradle/libs.versions.toml | 1 - 10 files changed, 207 insertions(+), 6 deletions(-) create mode 100644 app/src/main/java/com/example/chatapp/ui/guide/ChatKnowledgeActivity.kt create mode 100644 app/src/main/java/com/example/chatapp/ui/guide/ChatKnowledgeContent.kt create mode 100644 app/src/main/res/layout/activity_chat_knowledge.xml create mode 100644 app/src/test/java/com/example/chatapp/ui/guide/ChatKnowledgeContentProviderTest.kt diff --git a/app/build.gradle.kts b/app/build.gradle.kts index 0021804..ec7a88c 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -67,4 +67,8 @@ dependencies { // CoordinatorLayout (用于FloatingActionButton) implementation("androidx.coordinatorlayout:coordinatorlayout:1.2.0") -} \ No newline at end of file + testImplementation("junit:junit:4.13.2") + androidTestImplementation("androidx.test.ext:junit:1.1.5") + androidTestImplementation("androidx.test.espresso:espresso-core:3.5.1") + +} diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 18f1f76..fe20371 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -34,6 +34,10 @@ android:windowSoftInputMode="adjustResize" android:exported="false" /> + + - \ No newline at end of file + diff --git a/app/src/main/java/com/example/chatapp/ui/conversation/ConversationListActivity.kt b/app/src/main/java/com/example/chatapp/ui/conversation/ConversationListActivity.kt index d33bec0..dae41c2 100644 --- a/app/src/main/java/com/example/chatapp/ui/conversation/ConversationListActivity.kt +++ b/app/src/main/java/com/example/chatapp/ui/conversation/ConversationListActivity.kt @@ -13,6 +13,7 @@ import androidx.recyclerview.widget.RecyclerView import com.example.chatapp.R import com.example.chatapp.data.database.entity.Conversation import com.example.chatapp.ui.chat.ChatActivity +import com.example.chatapp.ui.guide.ChatKnowledgeActivity import com.google.android.material.floatingactionbutton.FloatingActionButton class ConversationListActivity : AppCompatActivity() { @@ -138,6 +139,10 @@ class ConversationListActivity : AppCompatActivity() { override fun onOptionsItemSelected(item: MenuItem): Boolean { return when (item.itemId) { + R.id.action_knowledge_guide -> { + startActivity(Intent(this, ChatKnowledgeActivity::class.java)) + true + } R.id.action_clear_all -> { showClearAllDialog() true @@ -163,4 +168,4 @@ class ConversationListActivity : AppCompatActivity() { super.onDestroy() recyclerView.adapter = null } -} \ No newline at end of file +} diff --git a/app/src/main/java/com/example/chatapp/ui/guide/ChatKnowledgeActivity.kt b/app/src/main/java/com/example/chatapp/ui/guide/ChatKnowledgeActivity.kt new file mode 100644 index 0000000..4ed3be7 --- /dev/null +++ b/app/src/main/java/com/example/chatapp/ui/guide/ChatKnowledgeActivity.kt @@ -0,0 +1,36 @@ +package com.example.chatapp.ui.guide + +import android.os.Bundle +import android.view.MenuItem +import android.widget.TextView +import androidx.appcompat.app.AppCompatActivity +import com.example.chatapp.R + +class ChatKnowledgeActivity : AppCompatActivity() { + + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + setContentView(R.layout.activity_chat_knowledge) + + supportActionBar?.apply { + title = getString(R.string.knowledge_intro_title) + setDisplayHomeAsUpEnabled(true) + } + + val content = ChatKnowledgeContentProvider.getContent() + findViewById(R.id.tv_knowledge_intro).text = content.introduction + findViewById(R.id.tv_knowledge_code).text = content.codeExample + findViewById(R.id.tv_knowledge_scenario).text = content.scenarioDesign + findViewById(R.id.tv_knowledge_explanation).text = content.explanation + } + + override fun onOptionsItemSelected(item: MenuItem): Boolean { + return when (item.itemId) { + android.R.id.home -> { + finish() + true + } + else -> super.onOptionsItemSelected(item) + } + } +} diff --git a/app/src/main/java/com/example/chatapp/ui/guide/ChatKnowledgeContent.kt b/app/src/main/java/com/example/chatapp/ui/guide/ChatKnowledgeContent.kt new file mode 100644 index 0000000..83102e9 --- /dev/null +++ b/app/src/main/java/com/example/chatapp/ui/guide/ChatKnowledgeContent.kt @@ -0,0 +1,45 @@ +package com.example.chatapp.ui.guide + +data class ChatKnowledgeContent( + val introduction: String, + val codeExample: String, + val scenarioDesign: String, + val explanation: String +) + +object ChatKnowledgeContentProvider { + + fun getContent(): ChatKnowledgeContent { + return ChatKnowledgeContent( + introduction = """ + 1. 会话列表:通过 RecyclerView 展示联系人、最后一条消息和未读数,帮助用户快速定位目标会话。 + 2. 消息流:聊天页根据消息发送者区分左右气泡,并支持文字与图片两种消息类型。 + 3. 数据持久化:使用 Room 保存会话与消息记录,保证重新进入应用后仍能查看历史内容。 + """.trimIndent(), + codeExample = """ + val message = Message( + conversationId = conversationId, + senderId = currentUserId, + content = "你好,欢迎来到聊天学习页!", + type = MessageType.TEXT + ) + viewModel.sendMessage( + conversationId = message.conversationId, + senderId = message.senderId, + content = message.content, + type = message.type + ) + """.trimIndent(), + scenarioDesign = """ + 场景:新成员首次接触本项目,需要在几分钟内理解聊天应用的核心结构。 + 做法:先阅读会话列表与聊天页的职责,再结合示例代码理解消息对象如何创建、保存和展示。 + 结果:学习者可以快速上手新增消息类型、优化自动回复逻辑,或扩展更多聊天功能。 + """.trimIndent(), + explanation = """ + 上面的示例代码强调“先构造消息对象,再调用 ViewModel 完成写入”的流程。 + 这种设计将界面层与数据层解耦,既方便测试,也方便未来接入网络请求或更复杂的业务规则。 + 因此,这个学习页既能帮助理解知识点,也能作为后续功能设计时的参考模板。 + """.trimIndent() + ) + } +} diff --git a/app/src/main/res/layout/activity_chat_knowledge.xml b/app/src/main/res/layout/activity_chat_knowledge.xml new file mode 100644 index 0000000..8b4b9f9 --- /dev/null +++ b/app/src/main/res/layout/activity_chat_knowledge.xml @@ -0,0 +1,80 @@ + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/app/src/main/res/menu/menu_conversation_list.xml b/app/src/main/res/menu/menu_conversation_list.xml index 7eee5b5..d8b117c 100644 --- a/app/src/main/res/menu/menu_conversation_list.xml +++ b/app/src/main/res/menu/menu_conversation_list.xml @@ -2,10 +2,16 @@ + + - \ No newline at end of file + diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 6c72cec..6d7634e 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -1,3 +1,8 @@ Chatapp - \ No newline at end of file + 聊天应用知识点介绍 + 知识点介绍 + 编写代码 + 场景设计 + 解释说明 + diff --git a/app/src/test/java/com/example/chatapp/ui/guide/ChatKnowledgeContentProviderTest.kt b/app/src/test/java/com/example/chatapp/ui/guide/ChatKnowledgeContentProviderTest.kt new file mode 100644 index 0000000..b881b76 --- /dev/null +++ b/app/src/test/java/com/example/chatapp/ui/guide/ChatKnowledgeContentProviderTest.kt @@ -0,0 +1,17 @@ +package com.example.chatapp.ui.guide + +import org.junit.Assert.assertTrue +import org.junit.Test + +class ChatKnowledgeContentProviderTest { + + @Test + fun getContent_returnsAllLearningSections() { + val content = ChatKnowledgeContentProvider.getContent() + + assertTrue(content.introduction.contains("RecyclerView")) + assertTrue(content.codeExample.contains("viewModel.sendMessage")) + assertTrue(content.scenarioDesign.contains("场景")) + assertTrue(content.explanation.contains("ViewModel")) + } +} diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 4623cb6..7289d81 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -29,4 +29,3 @@ androidx-compose-material3 = { group = "androidx.compose.material3", name = "mat android-application = { id = "com.android.application", version.ref = "agp" } kotlin-android = { id = "org.jetbrains.kotlin.android", version.ref = "kotlin" } kotlin-compose = { id = "org.jetbrains.kotlin.plugin.compose", version.ref = "kotlin" } - From eb44eaa4a706a3f66ffd8530b5dcbc67585501e6 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sat, 7 Mar 2026 11:55:03 +0000 Subject: [PATCH 4/4] refactor: move knowledge guide content into resources Co-authored-by: NITEACE <135036433+NITEACE@users.noreply.github.com> --- .../chatapp/ui/guide/ChatKnowledgeActivity.kt | 8 ++-- .../chatapp/ui/guide/ChatKnowledgeContent.kt | 44 +++++-------------- .../main/res/menu/menu_conversation_list.xml | 2 +- app/src/main/res/values/strings.xml | 15 +++++++ .../guide/ChatKnowledgeContentProviderTest.kt | 11 ++--- 5 files changed, 37 insertions(+), 43 deletions(-) diff --git a/app/src/main/java/com/example/chatapp/ui/guide/ChatKnowledgeActivity.kt b/app/src/main/java/com/example/chatapp/ui/guide/ChatKnowledgeActivity.kt index 4ed3be7..040b899 100644 --- a/app/src/main/java/com/example/chatapp/ui/guide/ChatKnowledgeActivity.kt +++ b/app/src/main/java/com/example/chatapp/ui/guide/ChatKnowledgeActivity.kt @@ -18,10 +18,10 @@ class ChatKnowledgeActivity : AppCompatActivity() { } val content = ChatKnowledgeContentProvider.getContent() - findViewById(R.id.tv_knowledge_intro).text = content.introduction - findViewById(R.id.tv_knowledge_code).text = content.codeExample - findViewById(R.id.tv_knowledge_scenario).text = content.scenarioDesign - findViewById(R.id.tv_knowledge_explanation).text = content.explanation + findViewById(R.id.tv_knowledge_intro).setText(content.introductionResId) + findViewById(R.id.tv_knowledge_code).setText(content.codeExampleResId) + findViewById(R.id.tv_knowledge_scenario).setText(content.scenarioDesignResId) + findViewById(R.id.tv_knowledge_explanation).setText(content.explanationResId) } override fun onOptionsItemSelected(item: MenuItem): Boolean { diff --git a/app/src/main/java/com/example/chatapp/ui/guide/ChatKnowledgeContent.kt b/app/src/main/java/com/example/chatapp/ui/guide/ChatKnowledgeContent.kt index 83102e9..adda5af 100644 --- a/app/src/main/java/com/example/chatapp/ui/guide/ChatKnowledgeContent.kt +++ b/app/src/main/java/com/example/chatapp/ui/guide/ChatKnowledgeContent.kt @@ -1,45 +1,23 @@ package com.example.chatapp.ui.guide +import androidx.annotation.StringRes +import com.example.chatapp.R + data class ChatKnowledgeContent( - val introduction: String, - val codeExample: String, - val scenarioDesign: String, - val explanation: String + @StringRes val introductionResId: Int, + @StringRes val codeExampleResId: Int, + @StringRes val scenarioDesignResId: Int, + @StringRes val explanationResId: Int ) object ChatKnowledgeContentProvider { fun getContent(): ChatKnowledgeContent { return ChatKnowledgeContent( - introduction = """ - 1. 会话列表:通过 RecyclerView 展示联系人、最后一条消息和未读数,帮助用户快速定位目标会话。 - 2. 消息流:聊天页根据消息发送者区分左右气泡,并支持文字与图片两种消息类型。 - 3. 数据持久化:使用 Room 保存会话与消息记录,保证重新进入应用后仍能查看历史内容。 - """.trimIndent(), - codeExample = """ - val message = Message( - conversationId = conversationId, - senderId = currentUserId, - content = "你好,欢迎来到聊天学习页!", - type = MessageType.TEXT - ) - viewModel.sendMessage( - conversationId = message.conversationId, - senderId = message.senderId, - content = message.content, - type = message.type - ) - """.trimIndent(), - scenarioDesign = """ - 场景:新成员首次接触本项目,需要在几分钟内理解聊天应用的核心结构。 - 做法:先阅读会话列表与聊天页的职责,再结合示例代码理解消息对象如何创建、保存和展示。 - 结果:学习者可以快速上手新增消息类型、优化自动回复逻辑,或扩展更多聊天功能。 - """.trimIndent(), - explanation = """ - 上面的示例代码强调“先构造消息对象,再调用 ViewModel 完成写入”的流程。 - 这种设计将界面层与数据层解耦,既方便测试,也方便未来接入网络请求或更复杂的业务规则。 - 因此,这个学习页既能帮助理解知识点,也能作为后续功能设计时的参考模板。 - """.trimIndent() + introductionResId = R.string.knowledge_intro_content, + codeExampleResId = R.string.knowledge_code_content, + scenarioDesignResId = R.string.knowledge_scenario_content, + explanationResId = R.string.knowledge_explanation_content ) } } diff --git a/app/src/main/res/menu/menu_conversation_list.xml b/app/src/main/res/menu/menu_conversation_list.xml index d8b117c..2c7afa9 100644 --- a/app/src/main/res/menu/menu_conversation_list.xml +++ b/app/src/main/res/menu/menu_conversation_list.xml @@ -4,7 +4,7 @@ diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 6d7634e..4d4cb20 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -5,4 +5,19 @@ 编写代码 场景设计 解释说明 + 1. 会话列表:通过 RecyclerView 展示联系人、最后一条消息和未读数,帮助用户快速定位目标会话。 +2. 消息流:聊天页根据消息发送者区分左右气泡,并支持文字与图片两种消息类型。 +3. 数据持久化:使用 Room 保存会话与消息记录,保证重新进入应用后仍能查看历史内容。 + viewModel.sendMessage( + conversationId = conversationId, + senderId = currentUserId, + content = "你好,欢迎来到聊天学习页!", + type = MessageType.TEXT +) + 场景:新成员首次接触本项目,需要在几分钟内理解聊天应用的核心结构。 +做法:先阅读会话列表与聊天页的职责,再结合示例代码理解消息对象如何创建、保存和展示。 +结果:学习者可以快速上手新增消息类型、优化自动回复逻辑,或扩展更多聊天功能。 + 上面的示例代码强调“由界面层调用 ViewModel 完成消息发送”的流程。 +这种设计将界面层与数据层解耦,既方便测试,也方便未来接入网络请求或更复杂的业务规则。 +因此,这个学习页既能帮助理解知识点,也能作为后续功能设计时的参考模板。 diff --git a/app/src/test/java/com/example/chatapp/ui/guide/ChatKnowledgeContentProviderTest.kt b/app/src/test/java/com/example/chatapp/ui/guide/ChatKnowledgeContentProviderTest.kt index b881b76..cd0b9f5 100644 --- a/app/src/test/java/com/example/chatapp/ui/guide/ChatKnowledgeContentProviderTest.kt +++ b/app/src/test/java/com/example/chatapp/ui/guide/ChatKnowledgeContentProviderTest.kt @@ -1,6 +1,7 @@ package com.example.chatapp.ui.guide -import org.junit.Assert.assertTrue +import com.example.chatapp.R +import org.junit.Assert.assertEquals import org.junit.Test class ChatKnowledgeContentProviderTest { @@ -9,9 +10,9 @@ class ChatKnowledgeContentProviderTest { fun getContent_returnsAllLearningSections() { val content = ChatKnowledgeContentProvider.getContent() - assertTrue(content.introduction.contains("RecyclerView")) - assertTrue(content.codeExample.contains("viewModel.sendMessage")) - assertTrue(content.scenarioDesign.contains("场景")) - assertTrue(content.explanation.contains("ViewModel")) + assertEquals(R.string.knowledge_intro_content, content.introductionResId) + assertEquals(R.string.knowledge_code_content, content.codeExampleResId) + assertEquals(R.string.knowledge_scenario_content, content.scenarioDesignResId) + assertEquals(R.string.knowledge_explanation_content, content.explanationResId) } }