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..040b899 --- /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).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 { + 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..adda5af --- /dev/null +++ b/app/src/main/java/com/example/chatapp/ui/guide/ChatKnowledgeContent.kt @@ -0,0 +1,23 @@ +package com.example.chatapp.ui.guide + +import androidx.annotation.StringRes +import com.example.chatapp.R + +data class ChatKnowledgeContent( + @StringRes val introductionResId: Int, + @StringRes val codeExampleResId: Int, + @StringRes val scenarioDesignResId: Int, + @StringRes val explanationResId: Int +) + +object ChatKnowledgeContentProvider { + + fun getContent(): ChatKnowledgeContent { + return ChatKnowledgeContent( + 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/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..2c7afa9 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..4d4cb20 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -1,3 +1,23 @@ Chatapp - \ No newline at end of file + 聊天应用知识点介绍 + 知识点介绍 + 编写代码 + 场景设计 + 解释说明 + 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 new file mode 100644 index 0000000..cd0b9f5 --- /dev/null +++ b/app/src/test/java/com/example/chatapp/ui/guide/ChatKnowledgeContentProviderTest.kt @@ -0,0 +1,18 @@ +package com.example.chatapp.ui.guide + +import com.example.chatapp.R +import org.junit.Assert.assertEquals +import org.junit.Test + +class ChatKnowledgeContentProviderTest { + + @Test + fun getContent_returnsAllLearningSections() { + val content = ChatKnowledgeContentProvider.getContent() + + 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) + } +} 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" } - diff --git a/gradlew b/gradlew old mode 100644 new mode 100755