# 主题模式切换 Implementation Plan > **For agentic workers:** REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (`- [ ]`) syntax for tracking. **Goal:** Add theme mode toggle (follow-system/light/dark) and fix dark mode font visibility **Architecture:** Add ThemeMode enum + PreferencesManager storage, thread themeMode through InspectionCameraTheme, replace all hardcoded Color values with MaterialTheme.colorScheme.* across all screens **Tech Stack:** Jetpack Compose, Material3, DataStore Preferences --- ### Task 1: Add ThemeMode enum **Files:** - Modify: `app/src/main/java/com/inspection/camera/data/models/WatermarkModels.kt` - [ ] **Step 1: Add ThemeMode enum** Add after the existing enums at end of file: ```kotlin enum class ThemeMode { FOLLOW_SYSTEM, LIGHT, DARK } ``` - [ ] **Step 2: Verify compilation** Run: `cd android-CheckShot && ./gradlew :app:compileDebugKotlin` Expected: BUILD SUCCESSFUL - [ ] **Step 3: Commit** ```bash git add app/src/main/java/com/inspection/camera/data/models/WatermarkModels.kt git commit -m "feat: add ThemeMode enum (follow-system/light/dark)" ``` --- ### Task 2: Add themeMode to PreferencesManager **Files:** - Modify: `app/src/main/java/com/inspection/camera/data/PreferencesManager.kt` - [ ] **Step 1: Add KEY_THEME_MODE + themeMode Flow + setter** After `KEY_FILE_NAME_TEMPLATE` line, add: ```kotlin private val KEY_THEME_MODE = stringPreferencesKey("theme_mode") ``` After `fileNameTemplate` Flow, add: ```kotlin val themeMode: Flow = context.dataStore.data.map { prefs -> val mode = prefs[KEY_THEME_MODE] ?: ThemeMode.FOLLOW_SYSTEM.name try { ThemeMode.valueOf(mode) } catch (e: Exception) { ThemeMode.FOLLOW_SYSTEM } } ``` After `setFileNameTemplate`, add: ```kotlin suspend fun setThemeMode(mode: ThemeMode) { context.dataStore.edit { prefs -> prefs[KEY_THEME_MODE] = mode.name } } ``` Add import for ThemeMode above existing imports: ```kotlin import com.inspection.camera.data.models.ThemeMode ``` - [ ] **Step 2: Verify compilation** Run: `cd android-CheckShot && ./gradlew :app:compileDebugKotlin` Expected: BUILD SUCCESSFUL - [ ] **Step 3: Commit** ```bash git add app/src/main/java/com/inspection/camera/data/PreferencesManager.kt git commit -m "feat: add themeMode preference to DataStore" ``` --- ### Task 3: Update InspectionCameraTheme to accept themeMode **Files:** - Modify: `app/src/main/java/com/inspection/camera/ui/theme/Theme.kt` - [ ] **Step 1: Replace darkTheme param with themeMode** Change the function signature from: ```kotlin fun InspectionCameraTheme( darkTheme: Boolean = isSystemInDarkTheme(), content: @Composable () -> Unit ) ``` to: ```kotlin fun InspectionCameraTheme( themeMode: ThemeMode = ThemeMode.FOLLOW_SYSTEM, content: @Composable () -> Unit ) { val isDark = when (themeMode) { ThemeMode.FOLLOW_SYSTEM -> isSystemInDarkTheme() ThemeMode.LIGHT -> false ThemeMode.DARK -> true } val colorScheme = if (isDark) DarkColorScheme else LightColorScheme // ... rest stays the same } ``` Also remove the old `darkTheme: Boolean = isSystemInDarkTheme()` parameter and the `val colorScheme = if (darkTheme) DarkColorScheme else LightColorScheme` line since it's now inside the function. Add import: ```kotlin import com.inspection.camera.data.models.ThemeMode ``` The final function should look like: ```kotlin @Composable fun InspectionCameraTheme( themeMode: ThemeMode = ThemeMode.FOLLOW_SYSTEM, content: @Composable () -> Unit ) { val isDark = when (themeMode) { ThemeMode.FOLLOW_SYSTEM -> isSystemInDarkTheme() ThemeMode.LIGHT -> false ThemeMode.DARK -> true } val colorScheme = if (isDark) DarkColorScheme else LightColorScheme // ... rest unchanged } ``` - [ ] **Step 2: Verify compilation** Run: `cd android-CheckShot && ./gradlew :app:compileDebugKotlin` Expected: BUILD SUCCESSFUL - [ ] **Step 3: Commit** ```bash git add app/src/main/java/com/inspection/camera/ui/theme/Theme.kt git commit -m "refactor: replace darkTheme param with themeMode in InspectionCameraTheme" ``` --- ### Task 4: Update MainActivity to pass themeMode **Files:** - Modify: `app/src/main/java/com/inspection/camera/ui/MainActivity.kt` - [ ] **Step 1: Read themeMode from PreferencesManager and pass to theme** Add `var themeMode` state variable and collect the Flow. Pass to `InspectionCameraTheme`: ```kotlin import androidx.compose.runtime.getValue import androidx.compose.runtime.setValue import com.inspection.camera.data.models.ThemeMode class MainActivity : ComponentActivity() { private lateinit var preferencesManager: PreferencesManager override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) enableEdgeToEdge() preferencesManager = PreferencesManager(this) setContent { var themeMode by remember { mutableStateOf(ThemeMode.FOLLOW_SYSTEM) } LaunchedEffect(Unit) { preferencesManager.themeMode.collect { themeMode = it } } InspectionCameraTheme(themeMode = themeMode) { MainApp(preferencesManager = preferencesManager) } } } } ``` Remove `import androidx.compose.foundation.isSystemInDarkTheme` if it was previously used only through `InspectionCameraTheme`'s default. - [ ] **Step 2: Verify compilation** Run: `cd android-CheckShot && ./gradlew :app:compileDebugKotlin` Expected: BUILD SUCCESSFUL - [ ] **Step 3: Commit** ```bash git add app/src/main/java/com/inspection/camera/ui/MainActivity.kt git commit -m "feat: read themeMode preference and pass to InspectionCameraTheme" ``` --- ### Task 5: Add theme selector to SettingsScreen **Files:** - Modify: `app/src/main/java/com/inspection/camera/ui/settings/SettingsScreen.kt` - [ ] **Step 1: Add themeMode state and collect from preferences** Add state variable alongside existing ones: ```kotlin var themeMode by remember { mutableStateOf(ThemeMode.FOLLOW_SYSTEM) } ``` Add collection logic: ```kotlin scope.launch { preferencesManager.themeMode.collect { themeMode = it } } ``` - [ ] **Step 2: Add theme section UI before "通用设置" section** Add before the "通用设置" section (before `Spacer(modifier = Modifier.height(16.dp))` that precedes `SettingsSection(title = "通用设置")`): ```kotlin Spacer(modifier = Modifier.height(16.dp)) // 主题设置 SettingsSection(title = "主题设置") { SettingsItem(title = "界面主题") { listOf( ThemeMode.FOLLOW_SYSTEM to "跟随系统", ThemeMode.LIGHT to "浅色模式", ThemeMode.DARK to "暗色模式" ).forEach { (mode, label) -> Row( modifier = Modifier .fillMaxWidth() .clickable { scope.launch { preferencesManager.setThemeMode(mode) } } .padding(vertical = 8.dp), verticalAlignment = Alignment.CenterVertically ) { RadioButton( selected = themeMode == mode, onClick = { scope.launch { preferencesManager.setThemeMode(mode) } } ) Spacer(modifier = Modifier.width(8.dp)) Text(label) } } } } ``` Replace hardcoded settings colors. Change `CardDefaults.cardColors(containerColor = Color.White)` (line 352): ```kotlin colors = CardDefaults.cardColors(containerColor = MaterialTheme.colorScheme.surface) ``` Change section title `Primary` (line 358) to `MaterialTheme.colorScheme.primary`. Note: TopAppBar colors, description text colors, etc. will be fixed in Task 7 (global pass). Add import: ```kotlin import com.inspection.camera.data.models.ThemeMode import androidx.compose.material3.MaterialTheme ``` - [ ] **Step 3: Verify compilation** Run: `cd android-CheckShot && ./gradlew :app:compileDebugKotlin` Expected: BUILD SUCCESSFUL - [ ] **Step 4: Commit** ```bash git add app/src/main/java/com/inspection/camera/ui/settings/SettingsScreen.kt git commit -m "feat: add theme selector UI to settings screen" ``` --- ### Task 6: Replace hardcoded colors in GalleryScreen **Files:** - Modify: `app/src/main/java/com/inspection/camera/ui/gallery/GalleryScreen.kt` - [ ] **Step 1: Replace color values** Replace TopAppBar colors (lines 132-137): ```kotlin colors = TopAppBarDefaults.topAppBarColors( containerColor = MaterialTheme.colorScheme.primary, titleContentColor = MaterialTheme.colorScheme.onPrimary, navigationIconContentColor = MaterialTheme.colorScheme.onPrimary, actionIconContentColor = MaterialTheme.colorScheme.onPrimary ) ``` Replace `Color.LightGray` placeholder background (line 171): ```kotlin .background(MaterialTheme.colorScheme.surfaceVariant) ``` Replace `Color.Red` delete icon tint (line 239): ```kotlin Icon(Icons.Default.Delete, contentDescription = "删除", tint = MaterialTheme.colorScheme.error) ``` Replace `Color.Red` delete button text (line 274): ```kotlin Text("确定删除", color = MaterialTheme.colorScheme.error) ``` Replace `Color.Black.copy(alpha = 0.05f)` zoomable background (line 296): ```kotlin .background(MaterialTheme.colorScheme.surfaceVariant) ``` Remove unused imports: `import com.inspection.camera.ui.theme.Primary` - [ ] **Step 2: Verify compilation** Run: `cd android-CheckShot && ./gradlew :app:compileDebugKotlin` Expected: BUILD SUCCESSFUL - [ ] **Step 3: Commit** ```bash git add app/src/main/java/com/inspection/camera/ui/gallery/GalleryScreen.kt git commit -m "fix: replace hardcoded colors with MaterialTheme.colorScheme in GalleryScreen" ``` --- ### Task 7: Replace hardcoded colors in MergeScreen **Files:** - Modify: `app/src/main/java/com/inspection/camera/ui/merge/MergeScreen.kt` - [ ] **Step 1: Replace color values** TopAppBar colors (lines 294-298): ```kotlin colors = TopAppBarDefaults.topAppBarColors( containerColor = MaterialTheme.colorScheme.primary, titleContentColor = MaterialTheme.colorScheme.onPrimary, navigationIconContentColor = MaterialTheme.colorScheme.onPrimary ) ``` Auto-import text color (line 344): ```kotlin color = MaterialTheme.colorScheme.primary ``` Quality/layout button backgrounds (lines 368, 636): ```kotlin .background(if (imageQuality == quality) MaterialTheme.colorScheme.primary else MaterialTheme.colorScheme.surfaceVariant) ``` Quality button text (line 374): ```kotlin color = if (imageQuality == quality) MaterialTheme.colorScheme.onPrimary else MaterialTheme.colorScheme.onSurface ``` Placeholder background (line 406): ```kotlin .background(MaterialTheme.colorScheme.surfaceVariant) ``` Selection overlay (line 438): ```kotlin .background(MaterialTheme.colorScheme.scrim.copy(alpha = 0.5f), CircleShape) ``` Check icon tint (lines 443, 649): ```kotlin tint = MaterialTheme.colorScheme.onPrimary ``` Add icon tint (line 451): ```kotlin tint = MaterialTheme.colorScheme.onSurfaceVariant ``` Layout option backgrounds (line 636): ```kotlin .background(if (isSelected) MaterialTheme.colorScheme.primary else MaterialTheme.colorScheme.surfaceVariant) ``` Layout option text (line 643): ```kotlin color = if (isSelected) MaterialTheme.colorScheme.onPrimary else MaterialTheme.colorScheme.onSurface ``` Remove unused import: `import com.inspection.camera.ui.theme.Primary` - [ ] **Step 2: Verify compilation** Run: `cd android-CheckShot && ./gradlew :app:compileDebugKotlin` Expected: BUILD SUCCESSFUL - [ ] **Step 3: Commit** ```bash git add app/src/main/java/com/inspection/camera/ui/merge/MergeScreen.kt git commit -m "fix: replace hardcoded colors with MaterialTheme.colorScheme in MergeScreen" ``` --- ### Task 8: Replace hardcoded colors in SettingsScreen (remaining) **Files:** - Modify: `app/src/main/java/com/inspection/camera/ui/settings/SettingsScreen.kt` - [ ] **Step 1: Replace remaining hardcoded colors** Save button text (line 117): ```kotlin Text("保存", color = MaterialTheme.colorScheme.onPrimary) ``` TopAppBar colors (lines 120-124): ```kotlin colors = TopAppBarDefaults.topAppBarColors( containerColor = MaterialTheme.colorScheme.primary, titleContentColor = MaterialTheme.colorScheme.onPrimary, navigationIconContentColor = MaterialTheme.colorScheme.onPrimary ) ``` Description text colors (lines 160, 274, 324): ```kotlin color = MaterialTheme.colorScheme.onSurfaceVariant ``` ```kotlin color = MaterialTheme.colorScheme.onSurfaceVariant ``` ```kotlin color = MaterialTheme.colorScheme.onSurfaceVariant ``` Section title color (line 358) — already changed in Task 5 to `MaterialTheme.colorScheme.primary`. - [ ] **Step 2: Verify compilation** Run: `cd android-CheckShot && ./gradlew :app:compileDebugKotlin` Expected: BUILD SUCCESSFUL - [ ] **Step 3: Commit** ```bash git add app/src/main/java/com/inspection/camera/ui/settings/SettingsScreen.kt git commit -m "fix: replace hardcoded TopAppBar/card/description colors with MaterialTheme.colorScheme in SettingsScreen" ``` --- ### Task 9: Verify CameraScreen overlay colors unchanged **Files:** - Inspect: `app/src/main/java/com/inspection/camera/ui/camera/CameraScreen.kt` - [ ] **Step 1: Confirm camera overlay colors are preserved** CameraScreen uses semi-transparent overlays over the live camera preview: - `Color.Black.copy(alpha = 0.3f)` for top/bottom control bars - `Color.White` for FAB and icons - `Color.Black.copy(alpha = 0.6f)` for location card - `Color.Black.copy(alpha = 0.9f)` for flash effect These should remain as-is since they overlay live camera preview, not app background. - [ ] **Step 2: Optional — replace non-overlay colors if any are missed** The PermissionRequest composable uses no hardcoded colors that need changing (text with default style inherits from MaterialTheme). - [ ] **Step 3: Commit** ```bash git add app/src/main/java/com/inspection/camera/ui/camera/CameraScreen.kt git commit -m "chore: confirm CameraScreen overlay colors are correct for dark mode" ``` --- ### Verification: Full build - [ ] **Step 1: Full build** ```bash cd android-CheckShot && ./gradlew :app:assembleDebug ``` Expected: BUILD SUCCESSFUL - [ ] **Step 2: Remove unused imports across all modified files** Ensure no unused imports remain (e.g., `import com.inspection.camera.ui.theme.Primary` removed from GalleryScreen, MergeScreen).