calendar-widget/android-app-requirements.md
Ching L c790cee472
All checks were successful
continuous-integration/drone/push Build is passing
feat: implement android app with widget support
- Created comprehensive Android app requirements document
  - Built complete Android project with Kotlin and Jetpack Compose
  - Implemented task management with control and display screens
  - Added Android widget with 5-minute auto-refresh capability
  - Integrated Room database for offline support
  - Set up MVVM architecture with Hilt dependency injection
  - Configured Retrofit for API communication
  - Added Material Design 3 theming and UI components
2025-11-17 18:28:22 +08:00

396 lines
11 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# 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
<!-- widget_layout.xml -->
<LinearLayout android:background="#f5f5f9"
android:padding="10dp">
<GridLayout android:columnCount="@integer/widget_columns"
android:rowCount="@integer/widget_rows">
<!-- 任务卡片 -->
<LinearLayout android:background="#f2f2f2"
android:padding="10dp"
android:gravity="center">
<TextView android:id="@+id/task_name"
android:textSize="14sp"
android:textColor="@android:color/black"/>
<View android:id="@+id/color_bar"
android:layout_height="10dp"
android:layout_marginTop="8dp"/>
</LinearLayout>
</GridLayout>
</LinearLayout>
```
## 数据管理
### API 接口层
```kotlin
interface TaskApiService {
@GET("tasks")
suspend fun getTasks(@Header("X-Api-Key") apiKey: String): List<Task>
@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<List<TaskEntity>>
@Insert(onConflict = OnConflictStrategy.REPLACE)
suspend fun insertTasks(tasks: List<TaskEntity>)
@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<TaskUiState> = _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
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.VIBRATE" />
```
## 构建配置
### 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. **国际化**
- 支持多语言
- 适配不同地区日期格式
- 时区自动转换