创建src代码目录和doc文档目录

master
gududeyumao 2 weeks ago
parent 76f756d9a2
commit d43ee855b7

Binary file not shown.

After

Width:  |  Height:  |  Size: 120 KiB

@ -0,0 +1,619 @@
# 4人小组代码注释任务分配带责任人提示
## 📋 任务总览
| 成员 | 负责文件 | 预计时间 | Git分支 | 当前状态 |
|------|---------|---------|---------|---------|
| **刘洋(A)** | Note.kt<br>NoteDao.kt<br>NoteDatabase.kt | 2小时 | a_branch | ⚠️ 待开始 |
| **王子函(B)** | NoteRepository.kt | 1.5小时 | b_branch | ⚠️ 待开始 |
| **崔宇航(C)** | NoteViewModel.kt | 2.5小时 | c_branch | ⚠️ 待开始 |
| **刘奔(D)** | MainActivity.kt<br>NoteEditorScreen.kt<br>NoteItem.kt<br>NoteListScreen.kt<br>Color.kt<br>Theme.kt<br>Type.kt | 4小时 | d_branch | ⚠️ 待开始 |
---
## 👤 成员刘洋任务2小时
### 📁 负责文件
#### 1. Note.kt ✅ 待开始
**文件路径**`app/src/main/java/com/example/myapplication/data/Note.kt`
**需要完成**
- [ ] 为类添加详细注释(说明数据模型的作用)
- [ ] 为所有字段添加注释
- [ ] 为构造函数添加注释
- [ ] 为所有getter方法添加注释
- [ ] 为所有setter方法添加注释
- [ ] 解释数据加载流程
**注释示例**
```kotlin
/**
* 便签数据模型类
*
* 职责:
* 1. 封装便签的所有属性
* 2. 提供数据加载和保存功能
* 3. 管理便签的状态
*
* @author 刘洋
* @since 2026-05-02
*/
class Note {
/** 便签ID数据库主键 */
private var mId: Long = 0
/** 父文件夹ID */
private var mParentId: Long = 0
// ... 其他字段
/**
* 从Cursor加载数据
*
* @param cursor 数据库查询结果
*/
fun loadFromCursor(cursor: Cursor) {
// ... 实现
}
}
```
---
#### 2. NoteDao.kt ✅ 待开始
**文件路径**`app/src/main/java/com/example/myapplication/data/NoteDao.kt`
**需要完成**
- [ ] 为接口添加详细注释说明DAO层职责
- [ ] 为所有方法添加注释insert, update, delete, query等
- [ ] 解释Room数据库操作原理
- [ ] 注释异步操作处理
**注释示例**
```kotlin
/**
* 便签数据访问对象接口
*
* 职责:
* 1. 定义数据库操作接口
* 2. 封装CRUD操作
* 3. 提供类型安全的数据访问
*
* @author 刘洋
* @since 2026-05-02
*/
@Dao
interface NoteDao {
/**
* 插入便签到数据库
*
* @param note 要插入的便签对象
* @return 插入的便签ID
*/
@Insert(onConflict = OnConflictStrategy.REPLACE)
suspend fun insert(note: Note): Long
/**
* 更新便签数据
*
* @param note 要更新的便签对象
* @return 更新的记录数
*/
@Update
suspend fun update(note: Note): Int
}
```
---
#### 3. NoteDatabase.kt ✅ 待开始
**文件路径**`app/src/main/java/com/example/myapplication/data/NoteDatabase.kt`
**需要完成**
- [ ] 为数据库类添加详细注释
- [ ] 为数据库实例化方法添加注释
- [ ] 解释数据库版本管理
- [ ] 注释数据库迁移策略
- [ ] 解释单例模式实现
**注释示例**
```kotlin
/**
* 便签数据库类
*
* 职责:
* 1. 初始化Room数据库实例
* 2. 管理数据库版本和迁移
* 3. 提供数据库访问入口
*
* 设计模式:
* - 单例模式:确保数据库实例唯一
* - 工厂模式:数据库构建器
*
* @author 刘洋
* @since 2026-05-02
*/
@Database(
entities = [Note::class],
version = 1,
exportSchema = false
)
abstract class NoteDatabase : RoomDatabase() {
/**
* 获取NoteDao实例
*
* @return NoteDao对象
*/
abstract fun noteDao(): NoteDao
/**
* 获取数据库实例(单例)
*
* 工作流程:
* 1. 检查是否已存在实例
* 2. 如果不存在,创建新实例
* 3. 返回数据库实例
*
* @param context 应用上下文
* @return 数据库实例
*/
companion object {
@Volatile
private var INSTANCE: NoteDatabase? = null
fun getDatabase(context: Context): NoteDatabase {
return INSTANCE ?: synchronized(this) {
INSTANCE ?: buildDatabase(context).also { INSTANCE = it }
}
}
}
}
```
---
## 👤 成员王子函任务1.5小时)
### 📁 负责文件
#### 1. NoteRepository.kt ✅ 待开始
**文件路径**`app/src/main/java/com/example/myapplication/data/NoteRepository.kt`
**需要完成**
- [ ] 为类添加详细注释说明Repository层职责
- [ ] 为所有方法添加注释getNotes, insertNote, updateNote等
- [ ] 解释数据源协调逻辑
- [ ] 注释错误处理机制
- [ ] 解释缓存策略
**注释示例**
```kotlin
/**
* 便签仓库类
*
* 职责:
* 1. 协调数据源(本地数据库 + 远程服务)
* 2. 提供统一的数据访问接口
* 3. 实现业务逻辑和数据转换
*
* 设计模式:
* - 仓库模式:抽象数据访问细节
* - 观察者模式LiveData通知UI更新
*
* @author 王子函
* @since 2026-05-02
*/
class NoteRepository(private val noteDao: NoteDao) {
/**
* 获取所有便签列表
*
* 工作流程:
* 1. 从数据库查询所有便签
* 2. 将结果包装为LiveData
* 3. 返回可观察的数据源
*
* @return 包含便签列表的LiveData
*/
fun getNotes(): LiveData<List<Note>> {
return noteDao.getAllNotes()
}
/**
* 插入新便签
*
* @param note 要插入的便签对象
* @return 插入的便签ID
*/
suspend fun insertNote(note: Note): Long {
return noteDao.insert(note)
}
}
```
---
## 👤 成员崔宇航任务2.5小时)
### 📁 负责文件
#### 1. NoteViewModel.kt ✅ 待开始
**文件路径**`app/src/main/java/com/example/myapplication/viewmodel/NoteViewModel.kt`
**需要完成**
- [ ] 为类添加详细注释说明ViewModel层职责
- [ ] 为所有方法添加注释getNotes, addNote, updateNote等
- [ ] 解释生命周期感知特性
- [ ] 注释状态管理逻辑
- [ ] 解释与Repository的协作关系
**注释示例**
```kotlin
/**
* 便签视图模型类
*
* 职责:
* 1. 管理UI相关的数据
* 2. 处理业务逻辑
* 3. 与Repository交互获取数据
* 4. 提供生命周期感知的数据流
*
* 设计模式:
* - MVVM架构分离UI逻辑和业务逻辑
* - 观察者模式LiveData通知UI更新
*
* @author 崔宇航
* @since 2026-05-02
*/
class NoteViewModel(application: Application) : AndroidViewModel(application) {
private val repository: NoteRepository
/**
* 便签列表数据流
*
* @return 包含便签列表的LiveData
*/
val notes: LiveData<List<Note>>
/**
* 初始化ViewModel
*
* 工作流程:
* 1. 获取Application上下文
* 2. 创建Repository实例
* 3. 初始化LiveData
* 4. 加载初始数据
*
* @param application Application上下文
*/
init {
val noteDao = NoteDatabase.getDatabase(application).noteDao()
repository = NoteRepository(noteDao)
notes = repository.getNotes()
}
/**
* 添加新便签
*
* @param note 要添加的便签对象
*/
fun addNote(note: Note) {
viewModelScope.launch {
repository.insertNote(note)
}
}
}
```
---
## 👤 成员刘奔任务4小时
### 📁 负责文件
#### 1. MainActivity.kt ✅ 待开始
**文件路径**`app/src/main/java/com/example/myapplication/MainActivity.kt`
**需要完成**
- [ ] 为类添加详细注释说明Activity职责
- [ ] 为所有生命周期方法添加注释onCreate等
- [ ] 为所有事件处理方法添加注释
- [ ] 解释导航逻辑
- [ ] 注释主题切换功能
**注释示例**
```kotlin
/**
* 主Activity
*
* 主要功能:
* 1. 应用启动入口
* 2. 导航到不同屏幕(列表/编辑)
* 3. 管理应用主题
* 4. 处理全局配置
*
* @author 刘奔
* @since 2026-05-02
*/
class MainActivity : AppCompatActivity() {
/**
* Activity创建时调用
*
* 工作流程:
* 1. 设置主题
* 2. 设置布局
* 3. 初始化ViewModel
* 4. 设置导航组件
*
* @param savedInstanceState 保存的实例状态
*/
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
// 初始化导航
val navHostFragment = supportFragmentManager
.findFragmentById(R.id.nav_host_fragment) as NavHostFragment
val navController = navHostFragment.navController
// 设置底部导航
findViewById<BottomNavigationView>(R.id.bottom_navigation).setupWithNavController(navController)
}
}
```
---
#### 2. NoteEditorScreen.kt ✅ 待开始
**文件路径**`app/src/main/java/com/example/myapplication/ui/NoteEditorScreen.kt`
**需要完成**
- [ ] 为类添加详细注释(说明编辑屏幕职责)
- [ ] 为所有Composable函数添加注释
- [ ] 解释状态管理
- [ ] 注释输入验证逻辑
- [ ] 解释保存流程
#### 3. NoteItem.kt ✅ 待开始
**文件路径**`app/src/main/java/com/example/myapplication/ui/NoteItem.kt`
**需要完成**
- [ ] 为类添加详细注释(说明列表项职责)
- [ ] 为所有Composable函数添加注释
- [ ] 解释点击事件处理
- [ ] 注释状态显示逻辑
- [ ] 解释主题适配
#### 4. NoteListScreen.kt ✅ 待开始
**文件路径**`app/src/main/java/com/example/myapplication/ui/NoteListScreen.kt`
**需要完成**
- [ ] 为类添加详细注释(说明列表屏幕职责)
- [ ] 为所有Composable函数添加注释
- [ ] 解释列表加载流程
- [ ] 注释搜索功能
- [ ] 解释批量操作
#### 5. Color.kt ✅ 待开始
**文件路径**`app/src/main/java/com/example/myapplication/ui/theme/Color.kt`
**需要完成**
- [ ] 为颜色常量添加注释
- [ ] 解释深色/浅色主题适配
- [ ] 注释颜色使用场景
#### 6. Theme.kt ✅ 待开始
**文件路径**`app/src/main/java/com/example/myapplication/ui/theme/Theme.kt`
**需要完成**
- [ ] 为主题类添加详细注释
- [ ] 为MaterialTheme扩展添加注释
- [ ] 解释主题切换逻辑
- [ ] 注释动态主题适配
#### 7. Type.kt ✅ 待开始
**文件路径**`app/src/main/java/com/example/myapplication/ui/theme/Type.kt`
**需要完成**
- [ ] 为字体样式添加注释
- [ ] 解释字体大小适配
- [ ] 注释不同文本样式的使用场景
---
## 🔧 Git工作流程
### 每个成员的操作步骤
#### 步骤1切换到个人分支
```bash
# 刘洋(A)
git checkout a_branch
# 王子函(B)
git checkout b_branch
# 崔宇航(C)
git checkout c_branch
# 刘奔(D)
git checkout d_branch
```
#### 步骤2开始注释代码
```
1. 在IDEA中打开负责的文件
2. 按照上面的注释要求添加注释
3. 使用KotlinDoc格式与JavaDoc类似
4. 保存文件
```
#### 步骤3提交到个人分支
```bash
# 刘洋(A) - Note相关文件
git add app/src/main/java/com/example/myapplication/data/Note.kt
git add app/src/main/java/com/example/myapplication/data/NoteDao.kt
git add app/src/main/java/com/example/myapplication/data/NoteDatabase.kt
git commit -m "A完成Note、NoteDao、Database 160行"
git push origin a_branch
# 王子函(B) - Repository文件
git add app/src/main/java/com/example/myapplication/data/NoteRepository.kt
git commit -m "B完成Repository 74行"
git push origin b_branch
# 崔宇航(C) - ViewModel文件
git add app/src/main/java/com/example/myapplication/viewmodel/NoteViewModel.kt
git commit -m "C完成ViewModel 160行"
git push origin c_branch
# 刘奔(D) - MainActivity和UI文件
git add app/src/main/java/com/example/myapplication/MainActivity.kt
git add app/src/main/java/com/example/myapplication/ui/NoteEditorScreen.kt
git add app/src/main/java/com/example/myapplication/ui/NoteItem.kt
git add app/src/main/java/com/example/myapplication/ui/NoteListScreen.kt
git add app/src/main/java/com/example/myapplication/ui/theme/Color.kt
git add app/src/main/java/com/example/myapplication/ui/theme/Theme.kt
git add app/src/main/java/com/example/myapplication/ui/theme/Type.kt
git commit -m "D完成MainActivity、UI、theme 350行"
git push origin d_branch
```
---
## 📝 注释规范
### KotlinDoc格式
```kotlin
/**
* 方法说明
*
* 详细描述(可选):
* - 工作流程
* - 注意事项
* - 设计模式
*
* @param 参数名 参数说明
* @return 返回值说明
* @throws 异常名 异常说明
*/
fun methodName(param: ParamType): ReturnType {
// 实现
}
```
### 字段注释
```kotlin
/** 字段说明 */
private var fieldName: Int = 0
```
### 代码块注释
```kotlin
// 步骤1初始化数据
initData()
// 步骤2处理业务逻辑
processData()
// 步骤3更新UI
updateUI()
```
---
## ✅ 完成检查清单
### 刘洋(A)
- [ ] Note.kt 所有方法已注释
- [ ] NoteDao.kt 所有方法已注释
- [ ] NoteDatabase.kt 所有方法已注释
- [ ] 提交到 a_branch
### 王子函(B)
- [ ] NoteRepository.kt 所有方法已注释
- [ ] 提交到 b_branch
### 崔宇航(C)
- [ ] NoteViewModel.kt 所有方法已注释
- [ ] 提交到 c_branch
### 刘奔(D)
- [ ] MainActivity.kt 所有方法已注释
- [ ] NoteEditorScreen.kt 所有方法已注释
- [ ] NoteItem.kt 所有方法已注释
- [ ] NoteListScreen.kt 所有方法已注释
- [ ] Color.kt 所有方法已注释
- [ ] Theme.kt 所有方法已注释
- [ ] Type.kt 所有方法已注释
- [ ] 提交到 d_branch
---
## 🎯 合并流程
### 所有成员完成后
```bash
# 1. 合并到develop分支
git checkout develop
git merge a_branch
git merge b_branch
git merge c_branch
git merge d_branch
# 2. 测试功能
# 在IDEA中运行项目验证所有功能
# 3. 合并到master
git checkout master
git merge develop
# 4. 推送
git push origin master
```
---
## 💡 提示
1. **注释要详细**每个方法都要有KotlinDoc注释
2. **解释关键逻辑**:复杂的业务逻辑要说明
3. **标注新功能**:在注释中标明"新功能成员X添加"
4. **保持格式一致**:使用统一的注释风格
5. **及时提交**:完成一个文件就提交一次
---
## 📊 进度跟踪
| 成员 | 进度 | 预计完成时间 |
|------|------|------------|
| 刘洋(A) | 0% | 2小时 |
| 王子函(B) | 0% | 1.5小时 |
| 崔宇航(C) | 0% | 2.5小时 |
| 刘奔(D) | 0% | 4小时 |
**总进度**: 0% (0/13文件)
---
**文档创建日期**: 2026年5月2日
**最后更新**: 2026年5月2日
**目标完成时间**: 4人协作预计1-2天

@ -1,302 +0,0 @@
# 小米便签应用 - UML 用例图
## 一、用例图概述
用例图Use Case Diagram展示了系统的功能需求和外部参与者之间的交互关系。它从用户的角度描述系统应该做什么而不关心系统如何实现这些功能。
---
## 二、参与者分析
### 2.1 主要参与者
**用户 (User)**
- 便签应用的主要使用者
- 可以是任何需要记录信息的用户
- 通过手机界面与应用交互
### 2.2 参与者特征
- **类型**: 人类用户
- **交互方式**: 触摸屏幕操作
- **使用场景**: 日常记录、备忘、灵感捕捉
---
## 三、用例详细描述
### 用例 1: 查看便签列表
**用例名称**: 查看便签列表
**参与者**: 用户
**前置条件**:
- 应用已启动
- 数据库中存在便签(可选)
**基本流程**:
1. 用户打开应用
2. 系统显示便签列表页面
3. 系统按更新时间倒序显示所有便签
4. 每个便签显示标题、内容预览和更新时间
**后置条件**:
- 用户可以看到所有便签
**扩展流程**:
- 3a. 如果没有便签
- 系统显示空状态提示
- 提示用户点击添加按钮
**业务规则**:
- 便签按更新时间降序排列
- 最新更新的便签显示在最上面
---
### 用例 2: 创建新便签
**用例名称**: 创建新便签
**参与者**: 用户
**前置条件**:
- 用户在便签列表页面
**基本流程**:
1. 用户点击右下角浮动操作按钮FAB
2. 系统打开便签编辑页面
3. 用户输入标题
4. 用户输入内容
5. 用户点击保存按钮
6. 系统保存便签到数据库
7. 系统返回便签列表页面
8. 列表自动刷新显示新便签
**后置条件**:
- 新便签已保存到数据库
- 列表中显示新创建的便签
**扩展流程**:
- 3a. 用户未输入标题
- 系统使用"无标题"作为默认标题
- 5a. 用户点击返回按钮
- 系统询问是否保存
- 用户确认则保存,否则放弃
**业务规则**:
- 标题和内容可以为空
- 自动记录创建时间和更新时间
---
### 用例 3: 编辑便签
**用例名称**: 编辑便签
**参与者**: 用户
**前置条件**:
- 便签列表中存在至少一个便签
**基本流程**:
1. 用户在列表中点击要编辑的便签
2. 系统打开编辑页面并加载便签数据
3. 用户修改标题或内容
4. 用户点击保存按钮
5. 系统更新数据库中的便签
6. 系统返回便签列表页面
7. 列表自动刷新显示更新后的便签
**后置条件**:
- 便签已更新
- 更新时间已刷新
**扩展流程**:
- 4a. 用户点击返回按钮
- 系统自动保存修改
- 返回列表页面
**业务规则**:
- 修改后自动更新更新时间字段
- 列表按更新时间重新排序
---
### 用例 4: 删除便签
**用例名称**: 删除便签
**参与者**: 用户
**前置条件**:
- 便签列表中存在至少一个便签
**基本流程**:
1. 用户点击便签卡片上的删除按钮
2. 系统从数据库中删除该便签
3. 系统刷新列表
4. 被删除的便签从列表中消失
**后置条件**:
- 便签已从数据库删除
- 列表不再显示该便签
**扩展流程**:
- 1a. 用户误触删除按钮
- 可以提供撤销功能(未来扩展)
**业务规则**:
- 删除操作不可恢复(当前版本)
- 删除后列表自动重新排序
---
## 四、用例关系
### 4.1 包含关系include
```
创建新便签 --> 保存便签
编辑便签 --> 保存便签
```
"保存便签"是一个被多个用例包含的公共功能。
### 4.2 扩展关系extend
```
空状态提示 <.. 便
```
当没有便签时,"空状态提示"扩展了"查看便签列表"用例。
---
## 五、UML 用例图Mermaid 格式)
```mermaid
usecaseDiagram
actor "用户" as User
package "小米便签系统" {
usecase "查看便签列表" as UC1
usecase "创建新便签" as UC2
usecase "编辑便签" as UC3
usecase "删除便签" as UC4
usecase "保存便签" as UC5
usecase "显示空状态" as UC6
}
User --> UC1
User --> UC2
User --> UC3
User --> UC4
UC2 ..> UC5 : include
UC3 ..> UC5 : include
UC6 .> UC1 : extend
```
---
## 六、用例场景
### 场景 1: 首次使用应用
1. 用户首次打开应用
2. 系统显示空状态:"暂无便签,点击右下角按钮添加新便签"
3. 用户点击 FAB 按钮
4. 用户创建第一条便签
5. 系统返回列表并显示新便签
### 场景 2: 日常使用
1. 用户打开应用查看便签列表
2. 用户点击某条便签进行编辑
3. 用户修改内容后保存
4. 该便签自动排序到列表顶部(因为更新时间最新)
### 场景 3: 清理便签
1. 用户查看列表找到过时的便签
2. 用户点击删除按钮
3. 便签被删除,列表自动刷新
---
## 七、非功能需求
### 7.1 性能需求
- 应用启动时间 < 2
- 列表滚动帧率 ≥ 60 FPS
- 数据库操作响应时间 < 100ms
### 7.2 可用性需求
- 界面简洁直观
- 操作步骤最少化
- 提供即时反馈
### 7.3 可靠性需求
- 数据持久化存储
- 应用崩溃后数据不丢失
- 支持后台运行
### 7.4 兼容性需求
- 最低支持 Android 7.0 (API 24)
- 支持亮色和暗色主题
- 适配不同屏幕尺寸
---
## 八、未来扩展用例
### 8.1 搜索便签
- 用户可以输入关键词搜索便签
- 支持标题和内容全文搜索
### 8.2 分类管理
- 用户可以创建分类标签
- 便签可以关联到不同分类
### 8.3 数据同步
- 支持云端备份和同步
- 多设备数据一致性
### 8.4 分享便签
- 将便签内容分享给其他应用
- 生成图片或文本分享
### 8.5 提醒功能
- 为便签设置提醒时间
- 到期推送通知
---
## 九、总结
本用例图完整描述了小米便签应用的核心功能:
**4 个核心用例**: 查看、创建、编辑、删除
**1 个参与者**: 用户
**清晰的关系**: include 和 extend 关系
**详细的流程**: 基本流程和扩展流程
**业务规则**: 明确的约束条件
用例图为后续的系统设计和实现提供了清晰的功能需求指导。
---
**文档版本**: v1.0
**创建日期**: 2026年4月24日

@ -1,677 +0,0 @@
# 小米便签应用 - UML 类图
## 一、类图概述
类图Class Diagram是软件工程中用于描述系统结构的静态图。它展示了系统中的类、接口以及它们之间的关系。类图是面向对象建模的核心工具。
---
## 二、系统架构分层
```
┌────────────────────────────────────────┐
│ Presentation Layer │
│ ┌────────────┐ ┌──────────────┐ │
│ │NoteList │ │NoteEditor │ │
│ │Screen │ │Screen │ │
│ └────────────┘ └──────────────┘ │
│ ┌────────────┐ │
│ │NoteItem │ │
│ └────────────┘ │
└──────────────┬─────────────────────────┘
┌──────────────▼─────────────────────────┐
│ ViewModel Layer │
│ ┌──────────────────────────┐ │
│ │ NoteViewModel │ │
│ └──────────────────────────┘ │
└──────────────┬─────────────────────────┘
┌──────────────▼─────────────────────────┐
│ Data Layer │
│ ┌────────┐ ┌───────┐ ┌──────────┐ │
│ │ Note │ │NoteDao│ │NoteDatabase│ │
│ └────────┘ └───────┘ └──────────┘ │
│ ┌──────────────────────────┐ │
│ │ NoteRepository │ │
│ └──────────────────────────┘ │
└──────────────────────────────────────┘
```
---
## 三、类详细说明
### 3.1 实体类
#### Note
**职责**: 便签数据模型,映射数据库表
**属性**:
```
- id: Int (主键,自增)
- title: String (便签标题)
- content: String (便签内容)
- createTime: Long (创建时间戳)
- updateTime: Long (更新时间戳)
```
**方法**:
```
+ Note(id, title, content, createTime, updateTime)
+ componentN(): 数据类自动生成
+ copy(): 数据类自动生成
+ equals(): 数据类自动生成
+ hashCode(): 数据类自动生成
+ toString(): 数据类自动生成
```
**注解**:
- `@Entity(tableName = "notes")`
- `@PrimaryKey(autoGenerate = true)`
**设计模式**: 数据类Data Class
---
### 3.2 数据访问层
#### NoteDao
**职责**: 定义数据库操作的接口
**方法**:
```
+ getAllNotes(): Flow<List<Note>>
+ getNoteById(noteId: Int): Flow<Note?>
+ insertNote(note: Note): Long
+ updateNote(note: Note): Unit
+ deleteNote(note: Note): Unit
+ deleteNoteById(noteId: Int): Unit
+ deleteAllNotes(): Unit
```
**注解**:
- `@Dao`
- `@Query`
- `@Insert`
- `@Update`
- `@Delete`
**设计模式**: 数据访问对象模式DAO Pattern
---
### 3.3 数据库层
#### NoteDatabase
**职责**: 管理 SQLite 数据库实例
**属性**:
```
# INSTANCE: NoteDatabase? (单例实例)
```
**方法**:
```
+ abstract noteDao(): NoteDao
+ static getDatabase(context: Context): NoteDatabase
```
**注解**:
- `@Database(entities = [Note::class], version = 1)`
**设计模式**:
- 单例模式Singleton
- 抽象工厂模式Abstract Factory
**线程安全**:
- `@Volatile` 保证可见性
- `synchronized` 保证原子性
---
### 3.4 仓库层
#### NoteRepository
**职责**: 封装数据操作,提供统一的数据访问接口
**属性**:
```
- noteDao: NoteDao (数据访问对象)
```
**方法**:
```
+ getAllNotes(): Flow<List<Note>>
+ getNoteById(noteId: Int): Flow<Note?>
+ createNote(note: Note): Long
+ updateNote(note: Note): Unit
+ deleteNote(note: Note): Unit
+ deleteNoteById(noteId: Int): Unit
+ deleteAllNotes(): Unit
```
**设计模式**: 仓库模式Repository Pattern
---
### 3.5 ViewModel 层
#### NoteViewModel
**职责**: 管理 UI 状态和业务逻辑
**属性**:
```
- repository: NoteRepository (数据仓库)
- _allNotes: MutableStateFlow<List<Note>> (便签列表)
- allNotes: StateFlow<List<Note>> (公开只读)
- _currentNote: MutableStateFlow<Note?> (当前便签)
- currentNote: StateFlow<Note?> (公开只读)
- _isLoading: MutableStateFlow<Boolean> (加载状态)
- isLoading: StateFlow<Boolean> (公开只读)
```
**方法**:
```
+ NoteViewModel(application: Application)
- observeNotes(): Unit
+ loadNote(noteId: Int): Unit
+ createNote(title: String, content: String): Unit
+ updateNote(note: Note): Unit
+ saveNote(title: String, content: String, noteId: Int?): Unit
+ deleteNote(note: Note): Unit
+ deleteNoteById(noteId: Int): Unit
+ clearCurrentNote(): Unit
```
**继承**:
- 继承自 `AndroidViewModel`
**设计模式**:
- MVVM 模式
- 观察者模式(通过 Flow
---
### 3.6 UI 层
#### MainActivity
**职责**: 应用入口,初始化 Compose UI 和导航
**属性**:
```
- viewModel: NoteViewModel (by viewModels)
```
**方法**:
```
+ onCreate(savedInstanceState: Bundle?): Unit
```
**继承**:
- 继承自 `ComponentActivity`
---
#### NoteListScreen (Composable)
**职责**: 显示便签列表
**参数**:
```
- navController: NavController
- viewModel: NoteViewModel
```
**内部组件**:
- TopAppBar
- LazyColumn
- FloatingActionButton
- EmptyState
---
#### NoteEditorScreen (Composable)
**职责**: 编辑或创建便签
**参数**:
```
- navController: NavController
- viewModel: NoteViewModel
- noteId: Int
```
**内部状态**:
- title: String (remember)
- content: String (remember)
**内部组件**:
- TopAppBar
- OutlinedTextField (标题)
- OutlinedTextField (内容)
---
#### NoteItem (Composable)
**职责**: 显示单个便签卡片
**参数**:
```
- note: Note
- onClick: () -> Unit
- onDelete: () -> Unit
```
**内部组件**:
- Card
- Text (标题)
- Text (内容)
- Text (时间)
- IconButton (删除)
---
### 3.7 主题配置
#### Color
**定义的颜色常量**:
```
+ XiaomiOrange: Color
+ XiaomiOrangeDark: Color
+ BackgroundLight: Color
+ BackgroundDark: Color
+ CardBackgroundLight: Color
+ CardBackgroundDark: Color
+ TextPrimaryLight: Color
+ TextPrimaryDark: Color
+ TextSecondaryLight: Color
+ TextSecondaryDark: Color
+ DividerLight: Color
+ DividerDark: Color
+ DeleteRed: Color
+ DeleteRedDark: Color
+ NoteColors: List<Color>
```
---
#### Theme
**方法**:
```
+ XiaomiNoteTheme(
darkTheme: Boolean,
dynamicColor: Boolean,
content: @Composable () -> Unit
): Unit
```
**内部配置**:
- LightColorScheme
- DarkColorScheme
---
#### Type
**定义的排版样式**:
```
+ Typography: Typography
- headlineLarge
- headlineMedium
- titleLarge
- bodyLarge
- bodyMedium
- bodySmall
- labelLarge
- labelSmall
```
---
## 四、类关系
### 4.1 关联关系Association
```
MainActivity "1" --> "1" NoteViewModel : 拥有
NoteViewModel "1" --> "1" NoteRepository : 使用
NoteRepository "1" --> "1" NoteDao : 使用
NoteDatabase "1" --> "*" NoteDao : 创建
```
### 4.2 依赖关系Dependency
```
NoteListScreen ..> NoteViewModel : 观察状态
NoteListScreen ..> NoteItem : 使用
NoteEditorScreen ..> NoteViewModel : 调用方法
NoteDao ..> Note : 操作
NoteRepository ..> Note : 操作
```
### 4.3 继承关系Inheritance
```
NoteViewModel --|> AndroidViewModel
MainActivity --|> ComponentActivity
```
### 4.4 实现关系Realization
```
NoteDao ..|> DAO接口
```
---
## 五、UML 类图Mermaid 格式)
```mermaid
classDiagram
%% 实体类
class Note {
<<Entity>>
-id: Int
-title: String
-content: String
-createTime: Long
-updateTime: Long
+Note()
}
%% 数据访问层
class NoteDao {
<<DAO>>
+getAllNotes() Flow~List~Note~~
+getNoteById(noteId: Int) Flow~Note?~
+insertNote(note: Note) Long
+updateNote(note: Note) void
+deleteNote(note: Note) void
+deleteNoteById(noteId: Int) void
+deleteAllNotes() void
}
%% 数据库层
class NoteDatabase {
<<Database>>
-INSTANCE: NoteDatabase?
+noteDao() NoteDao
+getDatabase(context: Context) NoteDatabase
}
%% 仓库层
class NoteRepository {
-noteDao: NoteDao
+getAllNotes() Flow~List~Note~~
+getNoteById(noteId: Int) Flow~Note?~
+createNote(note: Note) Long
+updateNote(note: Note) void
+deleteNote(note: Note) void
+deleteNoteById(noteId: Int) void
+deleteAllNotes() void
}
%% ViewModel层
class NoteViewModel {
-repository: NoteRepository
-_allNotes: MutableStateFlow~List~Note~~
+allNotes: StateFlow~List~Note~~
-_currentNote: MutableStateFlow~Note?~
+currentNote: StateFlow~Note?~
+NoteViewModel(application: Application)
-observeNotes() void
+loadNote(noteId: Int) void
+saveNote(title: String, content: String, noteId: Int?) void
+deleteNote(note: Note) void
+deleteNoteById(noteId: Int) void
+clearCurrentNote() void
}
%% UI层
class MainActivity {
-viewModel: NoteViewModel
+onCreate(savedInstanceState: Bundle?) void
}
class NoteListScreen {
<<Composable>>
+NoteListScreen(navController, viewModel) void
}
class NoteEditorScreen {
<<Composable>>
+NoteEditorScreen(navController, viewModel, noteId) void
}
class NoteItem {
<<Composable>>
+NoteItem(note, onClick, onDelete) void
}
%% 关系
NoteViewModel --|> AndroidViewModel
MainActivity --|> ComponentActivity
MainActivity "1" --> "1" NoteViewModel : 拥有
NoteViewModel "1" --> "1" NoteRepository : 使用
NoteRepository "1" --> "1" NoteDao : 使用
NoteDatabase "1" --> "1" NoteDao : 创建
NoteDao ..> Note : 操作
NoteRepository ..> Note : 操作
NoteListScreen ..> NoteViewModel : 观察
NoteListScreen ..> NoteItem : 使用
NoteEditorScreen ..> NoteViewModel : 调用
```
---
## 六、设计模式应用
### 6.1 MVVM 模式
**实现**:
- **Model**: Note, NoteDao, NoteDatabase, NoteRepository
- **View**: MainActivity, NoteListScreen, NoteEditorScreen, NoteItem
- **ViewModel**: NoteViewModel
**优势**:
- 关注点分离
- 可测试性强
- 生命周期感知
### 6.2 Repository 模式
**实现**: NoteRepository 封装所有数据操作
**优势**:
- 统一数据访问接口
- 便于切换数据源
- 业务逻辑与数据访问分离
### 6.3 单例模式
**实现**: NoteDatabase 使用双重检查锁定
**优势**:
- 全局唯一数据库实例
- 线程安全
- 延迟初始化
### 6.4 观察者模式
**实现**: Flow 响应式数据流
**优势**:
- 自动更新 UI
- 解耦数据源和观察者
- 支持背压
### 6.5 工厂模式
**实现**: NoteDatabase.getDatabase() 创建数据库实例
**优势**:
- 封装创建逻辑
- 控制实例化过程
---
## 七、数据流分析
### 7.1 数据读取流程
```
用户打开应用
MainActivity 初始化
创建 NoteViewModel
初始化 NoteRepository
获取 NoteDao
查询数据库 (Flow)
更新 StateFlow
UI 自动刷新 (collectAsState)
```
### 7.2 数据写入流程
```
用户点击保存
NoteEditorScreen 调用 ViewModel
NoteViewModel.saveNote()
NoteRepository.createNote() / updateNote()
NoteDao.insertNote() / updateNote()
写入 SQLite 数据库
Flow 自动发射新数据
StateFlow 更新
UI 自动刷新
```
---
## 八、关键设计决策
### 8.1 为什么使用 Flow 而不是 LiveData
**选择 Flow 的原因**:
1. 更强大的操作符
2. 更好的协程集成
3. 支持冷流和热流
4. 更灵活的线程控制
### 8.2 为什么使用 StateFlow 而不是 MutableStateFlow 公开?
**封装原则**:
- 内部使用 MutableStateFlow 可变
- 外部暴露 StateFlow 只读
- 防止外部意外修改状态
### 8.3 为什么使用 Repository 模式?
**优势**:
- 单一职责原则
- 便于添加缓存层
- 易于单元测试
- 支持多数据源扩展
---
## 九、扩展性设计
### 9.1 添加搜索功能
**扩展点**:
```kotlin
// 在 NoteDao 中添加
@Query("SELECT * FROM notes WHERE title LIKE :query OR content LIKE :query")
fun searchNotes(query: String): Flow<List<Note>>
// 在 NoteRepository 中添加
fun searchNotes(query: String): Flow<List<Note>>
// 在 NoteViewModel 中添加
fun searchNotes(query: String)
```
### 9.2 添加分类功能
**扩展点**:
```kotlin
// 扩展 Note 实体
data class Note(
val id: Int = 0,
val title: String = "",
val content: String = "",
val categoryId: Int? = null, // 新增
val createTime: Long = System.currentTimeMillis(),
val updateTime: Long = System.currentTimeMillis()
)
// 创建 Category 实体
@Entity(tableName = "categories")
data class Category(
@PrimaryKey(autoGenerate = true)
val id: Int = 0,
val name: String
)
```
### 9.3 添加云同步
**扩展点**:
```kotlin
// 创建远程数据源
class RemoteNoteDataSource {
suspend fun syncNotes(notes: List<Note>)
suspend fun fetchNotes(): List<Note>
}
// 扩展 Repository
class NoteRepository(
private val localDao: NoteDao,
private val remoteDataSource: RemoteNoteDataSource
)
```
---
## 十、总结
本类图展示了小米便签应用的完整架构设计:
**清晰的分层**: Presentation、ViewModel、Data 三层
**合理的职责划分**: 每个类都有明确的职责
**优秀的设计模式**: MVVM、Repository、Singleton、Observer
**高内聚低耦合**: 类之间关系清晰,依赖合理
**良好的扩展性**: 易于添加新功能
**架构评级**: ⭐⭐⭐⭐⭐ 优秀
---
**文档版本**: v1.0
**创建日期**: 2026年4月24日

@ -0,0 +1,29 @@
# 项目源代码目录
此目录包含小米便签应用的核心源代码按照标准Java包结构组织
- `com/example/myapplication/` - 主包
- `com/example/myapplication/data/` - 数据层Room实体、DAO、数据库、仓库
- `com/example/myapplication/ui/` - UI层Compose界面组件
- `com/example/myapplication/viewmodel/` - ViewModel层业务逻辑和状态管理
## 包含的文件
### 主入口
- `MainActivity.kt` - 应用主活动
### 数据层
- `data/Note.kt` - 便签数据实体类
- `data/NoteDao.kt` - 数据访问对象接口
- `data/NoteDatabase.kt` - Room数据库抽象类
- `data/NoteRepository.kt` - 数据仓库类
### UI层
- `ui/NoteListScreen.kt` - 便签列表界面
- `ui/NoteEditorScreen.kt` - 便签编辑界面
- `ui/NoteItem.kt` - 便签列表项组件
### ViewModel层
- `viewmodel/NoteViewModel.kt` - 便签ViewModel类
此目录结构便于在非Android开发环境中查看和分析项目架构。

@ -0,0 +1,76 @@
package com.example.myapplication
import android.os.Bundle
import androidx.activity.ComponentActivity
import androidx.activity.compose.setContent
import androidx.activity.viewModels
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Surface
import androidx.compose.ui.Modifier
import androidx.navigation.NavType
import androidx.navigation.compose.NavHost
import androidx.navigation.compose.composable
import androidx.navigation.compose.rememberNavController
import androidx.navigation.navArgument
import com.example.myapplication.ui.NoteEditorScreen
import com.example.myapplication.ui.NoteListScreen
import com.example.myapplication.ui.theme.XiaomiNoteTheme
import com.example.myapplication.viewmodel.NoteViewModel
/**
* 小米便签主活动
*
* 应用入口点负责初始化 Compose UI 和导航
* 使用 MVVM 架构通过 ViewModel 管理业务逻辑
*/
class MainActivity : ComponentActivity() {
// ViewModel 实例,由 Android 自动管理生命周期
private val viewModel: NoteViewModel by viewModels()
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
// 使用 Compose 设置 UI
setContent {
XiaomiNoteTheme {
Surface(
modifier = Modifier.fillMaxSize(),
color = MaterialTheme.colorScheme.background
) {
// 导航宿主
val navController = rememberNavController()
NavHost(
navController = navController,
startDestination = "list"
) {
// 列表页面
composable("list") {
NoteListScreen(
navController = navController,
viewModel = viewModel
)
}
// 编辑页面
composable(
route = "editor/{noteId}",
arguments = listOf(
navArgument("noteId") { type = NavType.IntType }
)
) { backStackEntry ->
val noteId = backStackEntry.arguments?.getInt("noteId") ?: 0
NoteEditorScreen(
navController = navController,
viewModel = viewModel,
noteId = noteId
)
}
}
}
}
}
}
}

@ -0,0 +1,34 @@
package com.example.myapplication.data
import androidx.room.Entity
import androidx.room.PrimaryKey
/**
* 便签数据实体类
*
* 使用 Room @Entity 注解定义数据库表结构
* 存储便签的标题内容创建时间和更新时间
*
* @property id 便签的唯一标识符自增主键
* @property title 便签标题
* @property content 便签内容
* @property createTime 创建时间毫秒时间戳
* @property updateTime 最后更新时间毫秒时间戳
*/
@Entity(tableName = "notes")
data class Note(
@PrimaryKey(autoGenerate = true)
val id: Int = 0,
/** 便签标题 */
val title: String = "",
/** 便签内容 */
val content: String = "",
/** 创建时间(毫秒时间戳) */
val createTime: Long = System.currentTimeMillis(),
/** 最后更新时间(毫秒时间戳) */
val updateTime: Long = System.currentTimeMillis()
)

@ -0,0 +1,70 @@
package com.example.myapplication.data
import androidx.room.*
import kotlinx.coroutines.flow.Flow
/**
* 便签数据访问对象DAO
*
* 定义所有与数据库交互的方法
* 使用 Flow 实现响应式数据流当数据库数据变化时自动更新
*/
@Dao
interface NoteDao {
/**
* 查询所有便签按更新时间倒序排列
*
* @return 返回 Flow<List<Note>>当数据库变化时自动发射新数据
*/
@Query("SELECT * FROM notes ORDER BY updateTime DESC")
fun getAllNotes(): Flow<List<Note>>
/**
* 根据 ID 查询单个便签
*
* @param noteId 便签 ID
* @return 返回 Flow<Note?>当该便签数据变化时自动更新
*/
@Query("SELECT * FROM notes WHERE id = :noteId")
fun getNoteById(noteId: Int): Flow<Note?>
/**
* 插入新便签
*
* @param note 要插入的便签对象
* @return 返回新插入便签的 ID
*/
@Insert(onConflict = OnConflictStrategy.REPLACE)
suspend fun insertNote(note: Note): Long
/**
* 更新现有便签
*
* @param note 要更新的便签对象
*/
@Update
suspend fun updateNote(note: Note)
/**
* 删除便签
*
* @param note 要删除的便签对象
*/
@Delete
suspend fun deleteNote(note: Note)
/**
* 根据 ID 删除便签
*
* @param noteId 要删除的便签 ID
*/
@Query("DELETE FROM notes WHERE id = :noteId")
suspend fun deleteNoteById(noteId: Int)
/**
* 删除所有便签
*/
@Query("DELETE FROM notes")
suspend fun deleteAllNotes()
}

@ -0,0 +1,56 @@
package com.example.myapplication.data
import android.content.Context
import androidx.room.Database
import androidx.room.Room
import androidx.room.RoomDatabase
/**
* 便签数据库类
*
* 使用 Room 持久化库管理 SQLite 数据库
* 采用单例模式确保整个应用只有一个数据库实例
*
* @property noteDao 提供便签数据访问对象
*/
@Database(
entities = [Note::class],
version = 1,
exportSchema = false
)
abstract class NoteDatabase : RoomDatabase() {
/**
* 获取便签数据访问对象
*
* @return NoteDao 实例用于执行数据库操作
*/
abstract fun noteDao(): NoteDao
companion object {
@Volatile
private var INSTANCE: NoteDatabase? = null
/**
* 获取数据库单例实例
*
* 使用双重检查锁定模式确保线程安全
*
* @param context 应用上下文
* @return NoteDatabase 单例实例
*/
fun getDatabase(context: Context): NoteDatabase {
return INSTANCE ?: synchronized(this) {
val instance = Room.databaseBuilder(
context.applicationContext,
NoteDatabase::class.java,
"note_database"
)
.fallbackToDestructiveMigration() // 数据库版本变化时销毁重建
.build()
INSTANCE = instance
instance
}
}
}
}

@ -0,0 +1,73 @@
package com.example.myapplication.data
import kotlinx.coroutines.flow.Flow
/**
* 便签数据仓库
*
* 作为数据层的统一入口封装所有数据操作
* 遵循单一职责原则只负责数据管理
*
* @property noteDao 数据访问对象执行实际的数据库操作
*/
class NoteRepository(private val noteDao: NoteDao) {
/**
* 获取所有便签列表响应式
*
* @return Flow<List<Note>> 当数据库变化时自动更新
*/
fun getAllNotes(): Flow<List<Note>> = noteDao.getAllNotes()
/**
* 根据 ID 获取单个便签响应式
*
* @param noteId 便签 ID
* @return Flow<Note?> 当该便签变化时自动更新
*/
fun getNoteById(noteId: Int): Flow<Note?> = noteDao.getNoteById(noteId)
/**
* 创建新便签
*
* @param note 要创建的便签对象
* @return 新创建便签的 ID
*/
suspend fun createNote(note: Note): Long {
return noteDao.insertNote(note)
}
/**
* 更新现有便签
*
* @param note 要更新的便签对象
*/
suspend fun updateNote(note: Note) {
noteDao.updateNote(note)
}
/**
* 删除便签
*
* @param note 要删除的便签对象
*/
suspend fun deleteNote(note: Note) {
noteDao.deleteNote(note)
}
/**
* 根据 ID 删除便签
*
* @param noteId 要删除的便签 ID
*/
suspend fun deleteNoteById(noteId: Int) {
noteDao.deleteNoteById(noteId)
}
/**
* 删除所有便签
*/
suspend fun deleteAllNotes() {
noteDao.deleteAllNotes()
}
}

@ -0,0 +1,123 @@
package com.example.myapplication.ui
import androidx.compose.foundation.layout.*
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.ArrowBack
import androidx.compose.material.icons.filled.Check
import androidx.compose.material3.*
import androidx.compose.runtime.*
import androidx.compose.ui.Modifier
import androidx.compose.ui.unit.dp
import androidx.lifecycle.compose.collectAsStateWithLifecycle
import androidx.navigation.NavController
import com.example.myapplication.viewmodel.NoteViewModel
/**
* 便签编辑页面
*
* 用于创建新便签或编辑现有便签
* 提供标题和内容输入框支持保存和返回操作
*
* @param navController 导航控制器
* @param viewModel 便签 ViewModel
* @param noteId 便签 ID0 表示创建新便签
*/
@OptIn(ExperimentalMaterial3Api::class)
@Composable
fun NoteEditorScreen(
navController: NavController,
viewModel: NoteViewModel,
noteId: Int
) {
// 收集当前编辑的便签
val currentNote by viewModel.currentNote.collectAsStateWithLifecycle()
// 输入框状态
var title by remember { mutableStateOf("") }
var content by remember { mutableStateOf("") }
// 如果是编辑现有便签,加载数据
LaunchedEffect(noteId) {
if (noteId > 0) {
viewModel.loadNote(noteId)
}
}
// 当加载到便签数据时,填充输入框
LaunchedEffect(currentNote) {
currentNote?.let { note ->
title = note.title
content = note.content
}
}
Scaffold(
topBar = {
// 顶部应用栏
TopAppBar(
title = { Text(if (noteId > 0) "编辑便签" else "新建便签") },
navigationIcon = {
// 返回按钮
IconButton(onClick = { navController.popBackStack() }) {
Icon(
imageVector = Icons.Default.ArrowBack,
contentDescription = "返回"
)
}
},
actions = {
// 保存按钮
IconButton(
onClick = {
viewModel.saveNote(title, content, if (noteId > 0) noteId else null)
navController.popBackStack()
}
) {
Icon(
imageVector = Icons.Default.Check,
contentDescription = "保存"
)
}
},
colors = TopAppBarDefaults.topAppBarColors(
containerColor = MaterialTheme.colorScheme.primary,
titleContentColor = MaterialTheme.colorScheme.onPrimary,
navigationIconContentColor = MaterialTheme.colorScheme.onPrimary,
actionIconContentColor = MaterialTheme.colorScheme.onPrimary
)
)
}
) { paddingValues ->
// 编辑区域
Column(
modifier = Modifier
.fillMaxSize()
.padding(paddingValues)
.padding(16.dp)
) {
// 标题输入框
OutlinedTextField(
value = title,
onValueChange = { title = it },
label = { Text("标题") },
modifier = Modifier.fillMaxWidth(),
singleLine = true,
textStyle = MaterialTheme.typography.headlineMedium
)
Spacer(modifier = Modifier.height(16.dp))
// 内容输入框
OutlinedTextField(
value = content,
onValueChange = { content = it },
label = { Text("内容") },
modifier = Modifier
.fillMaxWidth()
.weight(1f),
textStyle = MaterialTheme.typography.bodyLarge,
maxLines = Int.MAX_VALUE
)
}
}
}

@ -0,0 +1,110 @@
package com.example.myapplication.ui
import androidx.compose.foundation.clickable
import androidx.compose.foundation.layout.*
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.Delete
import androidx.compose.material3.*
import androidx.compose.runtime.Composable
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.text.style.TextOverflow
import androidx.compose.ui.unit.dp
import com.example.myapplication.data.Note
import com.example.myapplication.ui.theme.TextSecondaryLight
import java.text.SimpleDateFormat
import java.util.*
/**
* 便签列表项组件
*
* 显示单个便签的标题内容预览和更新时间
* 支持点击编辑和长按删除操作
*
* @param note 要显示的便签数据
* @param onClick 点击便签时的回调
* @param onDelete 点击删除按钮时的回调
*/
@Composable
fun NoteItem(
note: Note,
onClick: () -> Unit,
onDelete: () -> Unit
) {
Card(
modifier = Modifier
.fillMaxWidth()
.padding(horizontal = 16.dp, vertical = 8.dp)
.clickable(onClick = onClick),
shape = RoundedCornerShape(12.dp),
elevation = CardDefaults.cardElevation(defaultElevation = 2.dp)
) {
Column(
modifier = Modifier
.fillMaxWidth()
.padding(16.dp)
) {
// 标题和删除按钮
Row(
modifier = Modifier.fillMaxWidth(),
horizontalArrangement = Arrangement.SpaceBetween,
verticalAlignment = Alignment.CenterVertically
) {
// 便签标题
Text(
text = if (note.title.isNotEmpty()) note.title else "无标题",
style = MaterialTheme.typography.titleLarge,
maxLines = 1,
overflow = TextOverflow.Ellipsis,
modifier = Modifier.weight(1f)
)
// 删除按钮
IconButton(
onClick = onDelete,
modifier = Modifier.size(32.dp)
) {
Icon(
imageVector = Icons.Default.Delete,
contentDescription = "删除便签",
tint = MaterialTheme.colorScheme.error
)
}
}
Spacer(modifier = Modifier.height(8.dp))
// 内容预览
if (note.content.isNotEmpty()) {
Text(
text = note.content,
style = MaterialTheme.typography.bodyMedium,
maxLines = 3,
overflow = TextOverflow.Ellipsis,
color = MaterialTheme.colorScheme.onSurfaceVariant
)
Spacer(modifier = Modifier.height(8.dp))
}
// 更新时间
Text(
text = formatTime(note.updateTime),
style = MaterialTheme.typography.bodySmall,
color = TextSecondaryLight
)
}
}
}
/**
* 格式化时间戳为可读字符串
*
* @param timestamp 毫秒时间戳
* @return 格式化后的时间字符串
*/
private fun formatTime(timestamp: Long): String {
val dateFormat = SimpleDateFormat("yyyy-MM-dd HH:mm", Locale.getDefault())
return dateFormat.format(Date(timestamp))
}

@ -0,0 +1,127 @@
package com.example.myapplication.ui
import androidx.compose.foundation.layout.*
import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.foundation.lazy.items
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.Add
import androidx.compose.material3.*
import androidx.compose.runtime.Composable
import androidx.compose.runtime.collectAsState
import androidx.compose.runtime.getValue
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.text.style.TextAlign
import androidx.compose.ui.unit.dp
import androidx.navigation.NavController
import com.example.myapplication.data.Note
import com.example.myapplication.viewmodel.NoteViewModel
/**
* 便签列表页面
*
* 显示所有便签的列表支持创建新便签
* 提供空状态提示和浮动操作按钮
*
* @param navController 导航控制器
* @param viewModel 便签 ViewModel
*/
@OptIn(ExperimentalMaterial3Api::class)
@Composable
fun NoteListScreen(
navController: NavController,
viewModel: NoteViewModel
) {
// 收集便签列表状态
val notes by viewModel.allNotes.collectAsState()
Scaffold(
topBar = {
// 顶部应用栏
TopAppBar(
title = { Text("小米便签") },
colors = TopAppBarDefaults.topAppBarColors(
containerColor = MaterialTheme.colorScheme.primary,
titleContentColor = MaterialTheme.colorScheme.onPrimary
)
)
},
floatingActionButton = {
// 浮动操作按钮 - 添加新便签
FloatingActionButton(
onClick = {
viewModel.clearCurrentNote()
navController.navigate("editor/0")
},
containerColor = MaterialTheme.colorScheme.primary
) {
Icon(
imageVector = Icons.Default.Add,
contentDescription = "添加新便签",
tint = MaterialTheme.colorScheme.onPrimary
)
}
}
) { paddingValues ->
// 主内容区域
Box(
modifier = Modifier
.fillMaxSize()
.padding(paddingValues)
) {
if (notes.isEmpty()) {
// 空状态提示
EmptyState()
} else {
// 便签列表
LazyColumn(
modifier = Modifier.fillMaxSize(),
contentPadding = PaddingValues(vertical = 8.dp)
) {
items(notes, key = { it.id }) { note ->
NoteItem(
note = note,
onClick = {
navController.navigate("editor/${note.id}")
},
onDelete = {
viewModel.deleteNote(note)
}
)
}
}
}
}
}
}
/**
* 空状态提示组件
*
* 当没有便签时显示提示信息
*/
@Composable
private fun EmptyState() {
Column(
modifier = Modifier
.fillMaxSize()
.padding(32.dp),
horizontalAlignment = Alignment.CenterHorizontally,
verticalArrangement = Arrangement.Center
) {
Text(
text = "暂无便签",
style = MaterialTheme.typography.headlineMedium,
color = MaterialTheme.colorScheme.onSurfaceVariant
)
Spacer(modifier = Modifier.height(16.dp))
Text(
text = "点击右下角按钮添加新便签",
style = MaterialTheme.typography.bodyLarge,
color = MaterialTheme.colorScheme.onSurfaceVariant,
textAlign = TextAlign.Center
)
}
}

@ -0,0 +1,159 @@
package com.example.myapplication.viewmodel
import android.app.Application
import androidx.lifecycle.AndroidViewModel
import androidx.lifecycle.viewModelScope
import com.example.myapplication.data.Note
import com.example.myapplication.data.NoteDatabase
import com.example.myapplication.data.NoteRepository
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.asStateFlow
import kotlinx.coroutines.launch
/**
* 便签 ViewModel
*
* 负责管理便签相关的业务逻辑和 UI 状态
* 作为 View 层和 Model 层之间的桥梁
*
* @param application 应用程序上下文
*/
class NoteViewModel(application: Application) : AndroidViewModel(application) {
// 数据仓库实例
private val repository: NoteRepository
// 所有便签列表的状态流
private val _allNotes = MutableStateFlow<List<Note>>(emptyList())
val allNotes: StateFlow<List<Note>> = _allNotes.asStateFlow()
// 当前编辑的便签
private val _currentNote = MutableStateFlow<Note?>(null)
val currentNote: StateFlow<Note?> = _currentNote.asStateFlow()
// 加载状态
private val _isLoading = MutableStateFlow(false)
val isLoading: StateFlow<Boolean> = _isLoading.asStateFlow()
init {
// 初始化数据仓库
val noteDao = NoteDatabase.getDatabase(application).noteDao()
repository = NoteRepository(noteDao)
// 开始监听数据库变化
observeNotes()
}
/**
* 监听便签数据变化
*
* 当数据库中的便签数据发生变化时自动更新 StateFlow
*/
private fun observeNotes() {
viewModelScope.launch {
repository.getAllNotes().collect { notes ->
_allNotes.value = notes
}
}
}
/**
* 加载指定 ID 的便签
*
* @param noteId 便签 ID
*/
fun loadNote(noteId: Int) {
viewModelScope.launch {
repository.getNoteById(noteId).collect { note ->
_currentNote.value = note
}
}
}
/**
* 创建新便签
*
* @param title 便签标题
* @param content 便签内容
*/
fun createNote(title: String, content: String) {
viewModelScope.launch {
val note = Note(
title = title,
content = content,
createTime = System.currentTimeMillis(),
updateTime = System.currentTimeMillis()
)
repository.createNote(note)
}
}
/**
* 更新现有便签
*
* @param note 要更新的便签对象
*/
fun updateNote(note: Note) {
viewModelScope.launch {
val updatedNote = note.copy(updateTime = System.currentTimeMillis())
repository.updateNote(updatedNote)
}
}
/**
* 保存便签创建或更新
*
* @param title 便签标题
* @param content 便签内容
* @param noteId 如果是编辑现有便签传入其 ID否则传 0 null
*/
fun saveNote(title: String, content: String, noteId: Int? = null) {
viewModelScope.launch {
_isLoading.value = true
try {
if (noteId != null && noteId > 0) {
// 更新现有便签
val existingNote = _currentNote.value
if (existingNote != null) {
updateNote(existingNote.copy(title = title, content = content))
}
} else {
// 创建新便签
createNote(title, content)
}
} finally {
_isLoading.value = false
}
}
}
/**
* 删除便签
*
* @param note 要删除的便签对象
*/
fun deleteNote(note: Note) {
viewModelScope.launch {
repository.deleteNote(note)
}
}
/**
* 根据 ID 删除便签
*
* @param noteId 要删除的便签 ID
*/
fun deleteNoteById(noteId: Int) {
viewModelScope.launch {
repository.deleteNoteById(noteId)
}
}
/**
* 清空当前编辑的便签
*/
fun clearCurrentNote() {
_currentNote.value = null
}
}
Loading…
Cancel
Save