# Calendar Widget Android 应用需求文档
## 项目概述
将现有的 Calendar Widget 任务管理系统迁移到 Android 平台,保持核心功能的同时提供原生移动应用体验。
## 技术栈
- **开发语言**: Kotlin
- **UI框架**: Jetpack Compose
- **架构模式**: MVVM (Model-View-ViewModel)
- **网络请求**: Retrofit + OkHttp
- **本地存储**: Room Database
- **依赖注入**: Hilt
- **小组件**: Android App Widget API
## 应用结构
### 1. 控制页面 (MainActivity)
#### 功能需求
- **任务列表展示**
- 显示所有任务的列表视图
- 每个任务项显示:名称、状态颜色、最小间隔天数、上次执行时间
- 支持下拉刷新更新任务列表
- **任务管理**
- 添加新任务:浮动操作按钮触发对话框
- 编辑任务:长按任务项进入编辑模式
- 删除任务:侧滑删除或长按菜单删除
- 拖拽排序:长按拖动重新排列任务优先级
- **任务执行**
- 点击"执行"按钮记录任务执行时间
- 成功执行后自动刷新状态颜色
#### UI设计要点
```kotlin
// 主界面布局结构
@Composable
fun ControlScreen() {
Scaffold(
topBar = { /* 应用标题栏 */ },
floatingActionButton = { /* 添加任务按钮 */ }
) {
LazyColumn {
items(tasks) { task ->
TaskCard(
task = task,
onExecute = { /* 执行任务 */ },
onEdit = { /* 编辑任务 */ },
onDelete = { /* 删除任务 */ }
)
}
}
}
}
```
### 2. 展示页面 (DisplayActivity)
#### 功能需求
- **任务状态可视化**
- 网格布局展示任务卡片
- 动态适配屏幕大小(横屏4列,竖屏2列)
- 每个卡片显示任务名称和颜色条
- 点击卡片快速执行任务
- **视图模式**
- 紧凑模式:仅显示名称和颜色
- 详细模式:显示名称、颜色、剩余天数
#### UI设计要点
```kotlin
@Composable
fun DisplayScreen() {
val configuration = LocalConfiguration.current
val columns = if (configuration.orientation == Configuration.ORIENTATION_LANDSCAPE) 4 else 2
LazyVerticalGrid(
columns = GridCells.Fixed(columns),
contentPadding = PaddingValues(16.dp)
) {
items(tasks) { task ->
TaskDisplayCard(
task = task,
onClick = { /* 执行任务 */ }
)
}
}
}
```
### 3. Android 小组件 (Widget)
#### 功能需求
- **尺寸支持**
- 小型 (2x1): 显示1个任务
- 中型 (2x2): 显示4个任务
- 大型 (4x2): 显示8个任务
- **交互功能**
- 点击任务执行并刷新小组件
- 自动每5分钟更新一次
- 支持手动刷新按钮
#### 实现要点
```kotlin
class TaskWidgetProvider : AppWidgetProvider() {
override fun onUpdate(context: Context, appWidgetManager: AppWidgetManager, appWidgetIds: IntArray) {
for (appWidgetId in appWidgetIds) {
val size = getWidgetSize(appWidgetManager, appWidgetId)
val views = createRemoteViews(context, size)
appWidgetManager.updateAppWidget(appWidgetId, views)
}
// 设置下次更新时间为5分钟后
scheduleNextUpdate(context)
}
private fun scheduleNextUpdate(context: Context) {
val alarmManager = context.getSystemService(Context.ALARM_SERVICE) as AlarmManager
val intent = Intent(context, TaskWidgetProvider::class.java).apply {
action = AppWidgetManager.ACTION_APPWIDGET_UPDATE
}
val pendingIntent = PendingIntent.getBroadcast(context, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT)
// 5分钟后更新
val updateInterval = 5 * 60 * 1000L // 5分钟转换为毫秒
alarmManager.setExactAndAllowWhileIdle(
AlarmManager.RTC,
System.currentTimeMillis() + updateInterval,
pendingIntent
)
}
}
```
#### 小组件布局 (仿照 widget.js 样式)
```xml
```
## 数据管理
### API 接口层
```kotlin
interface TaskApiService {
@GET("tasks")
suspend fun getTasks(@Header("X-Api-Key") apiKey: String): List
@POST("tasks")
suspend fun createTask(@Header("X-Api-Key") apiKey: String, @Body task: CreateTaskRequest): Task
@PUT("tasks/{id}")
suspend fun updateTask(@Header("X-Api-Key") apiKey: String, @Path("id") id: Int, @Body task: UpdateTaskRequest): Task
@DELETE("tasks/{id}")
suspend fun deleteTask(@Header("X-Api-Key") apiKey: String, @Path("id") id: Int)
@POST("tasks/{id}/schedule")
suspend fun scheduleTask(@Header("X-Api-Key") apiKey: String, @Path("id") id: Int)
@POST("tasks/reorder")
suspend fun reorderTasks(@Header("X-Api-Key") apiKey: String, @Body request: ReorderRequest)
}
```
### 本地缓存
```kotlin
@Entity(tableName = "tasks")
data class TaskEntity(
@PrimaryKey val id: Int,
val name: String,
val color: String,
val minIntervalDays: Int,
val lastExecutionTime: String?,
val priority: Int
)
@Dao
interface TaskDao {
@Query("SELECT * FROM tasks ORDER BY priority")
fun getAllTasks(): Flow>
@Insert(onConflict = OnConflictStrategy.REPLACE)
suspend fun insertTasks(tasks: List)
@Query("DELETE FROM tasks")
suspend fun deleteAllTasks()
}
```
## 状态管理
### ViewModel 实现
```kotlin
@HiltViewModel
class TaskViewModel @Inject constructor(
private val repository: TaskRepository
) : ViewModel() {
private val _uiState = MutableStateFlow(TaskUiState())
val uiState: StateFlow = _uiState.asStateFlow()
fun loadTasks() {
viewModelScope.launch {
repository.getTasks()
.catch { /* 处理错误,使用缓存 */ }
.collect { tasks ->
_uiState.update { it.copy(tasks = tasks) }
}
}
}
fun executeTask(taskId: Int) {
viewModelScope.launch {
repository.scheduleTask(taskId)
loadTasks() // 刷新列表
updateWidget() // 更新小组件
}
}
}
```
## 应用设置
### SharedPreferences 配置
```kotlin
object AppSettings {
private const val PREF_NAME = "calendar_widget_prefs"
private const val KEY_API_KEY = "api_key"
private const val KEY_API_HOST = "api_host"
private const val KEY_AUTO_REFRESH = "auto_refresh"
private const val KEY_REFRESH_INTERVAL = "refresh_interval"
fun saveApiKey(context: Context, apiKey: String) {
context.getSharedPreferences(PREF_NAME, Context.MODE_PRIVATE)
.edit()
.putString(KEY_API_KEY, apiKey)
.apply()
}
}
```
### 设置页面功能
- API密钥配置
- 服务器地址配置
- 小组件自动刷新间隔(默认5分钟,可选1/5/10/15/30/60分钟)
- 主题选择(浅色/深色)
- 通知设置
## UI/UX 设计规范
### 颜色主题
```kotlin
val CalendarWidgetTheme = lightColorScheme(
primary = Color(0xFF667EEA),
secondary = Color(0xFF764BA2),
background = Color(0xFFF5F5F9),
surface = Color(0xFFF2F2F2),
error = Color(0xFFFF4757),
onPrimary = Color.White,
onSecondary = Color.White,
onBackground = Color.Black,
onSurface = Color.Black
)
// 任务状态颜色
object TaskColors {
val Green = Color(0xFF00B894)
val Yellow = Color(0xFFFDCB6E)
val Red = Color(0xFFFF4757)
}
```
### Material Design 3 组件
- 使用 Material You 动态主题
- 圆角卡片设计(16dp corner radius)
- 浮动操作按钮
- 底部导航栏
- Snackbar 提示信息
## 权限需求
```xml
```
## 构建配置
### build.gradle.kts (Module)
```kotlin
android {
compileSdk = 34
defaultConfig {
applicationId = "com.tunpok.calendarwidget"
minSdk = 24
targetSdk = 34
versionCode = 1
versionName = "1.0.0"
}
buildFeatures {
compose = true
}
}
dependencies {
// Compose
implementation("androidx.compose.ui:ui:1.5.4")
implementation("androidx.compose.material3:material3:1.1.2")
// Navigation
implementation("androidx.navigation:navigation-compose:2.7.5")
// Network
implementation("com.squareup.retrofit2:retrofit:2.9.0")
implementation("com.squareup.okhttp3:okhttp:4.12.0")
// Database
implementation("androidx.room:room-runtime:2.6.0")
implementation("androidx.room:room-ktx:2.6.0")
// Dependency Injection
implementation("com.google.dagger:hilt-android:2.48")
// Widget
implementation("androidx.glance:glance-appwidget:1.0.0")
}
```
## 测试策略
### 单元测试
- Repository 层测试
- ViewModel 逻辑测试
- 日期计算和颜色映射测试
### UI 测试
- Compose UI 测试
- 小组件更新测试
- 网络请求模拟测试
## 发布准备
### ProGuard 规则
```proguard
-keep class com.tunpok.calendarwidget.data.model.** { *; }
-keepattributes Signature
-keepattributes *Annotation*
```
### 版本管理
- 使用语义化版本号
- 维护 CHANGELOG.md
- 配置自动化构建和发布流程
## 后续优化建议
1. **性能优化**
- 实现图片和数据懒加载
- 使用 WorkManager 进行后台同步
- 实现智能更新策略(活动时5分钟更新,空闲时降低频率以节省电量)
2. **功能扩展**
- 添加任务提醒通知
- 支持任务分类和标签
- 实现任务统计图表
- 添加批量操作功能
3. **用户体验**
- 实现手势操作
- 添加动画效果
- 支持快捷方式
- 深色模式自动切换
4. **国际化**
- 支持多语言
- 适配不同地区日期格式
- 时区自动转换