Files
anroid-CheckShot/docs/superpowers/plans/2026-05-13-theme-mode-plan.md

14 KiB

主题模式切换 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:

enum class ThemeMode {
    FOLLOW_SYSTEM,
    LIGHT,
    DARK
}
  • Step 2: Verify compilation

Run: cd android-CheckShot && ./gradlew :app:compileDebugKotlin Expected: BUILD SUCCESSFUL

  • Step 3: Commit
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:

private val KEY_THEME_MODE = stringPreferencesKey("theme_mode")

After fileNameTemplate Flow, add:

val themeMode: Flow<ThemeMode> = 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:

suspend fun setThemeMode(mode: ThemeMode) {
    context.dataStore.edit { prefs ->
        prefs[KEY_THEME_MODE] = mode.name
    }
}

Add import for ThemeMode above existing imports:

import com.inspection.camera.data.models.ThemeMode
  • Step 2: Verify compilation

Run: cd android-CheckShot && ./gradlew :app:compileDebugKotlin Expected: BUILD SUCCESSFUL

  • Step 3: Commit
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:

fun InspectionCameraTheme(
    darkTheme: Boolean = isSystemInDarkTheme(),
    content: @Composable () -> Unit
)

to:

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:

import com.inspection.camera.data.models.ThemeMode

The final function should look like:

@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
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:

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
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:

var themeMode by remember { mutableStateOf(ThemeMode.FOLLOW_SYSTEM) }

Add collection logic:

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 = "通用设置")):

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):

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:

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
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):

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):

.background(MaterialTheme.colorScheme.surfaceVariant)

Replace Color.Red delete icon tint (line 239):

Icon(Icons.Default.Delete, contentDescription = "删除", tint = MaterialTheme.colorScheme.error)

Replace Color.Red delete button text (line 274):

Text("确定删除", color = MaterialTheme.colorScheme.error)

Replace Color.Black.copy(alpha = 0.05f) zoomable background (line 296):

.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
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):

colors = TopAppBarDefaults.topAppBarColors(
    containerColor = MaterialTheme.colorScheme.primary,
    titleContentColor = MaterialTheme.colorScheme.onPrimary,
    navigationIconContentColor = MaterialTheme.colorScheme.onPrimary
)

Auto-import text color (line 344):

color = MaterialTheme.colorScheme.primary

Quality/layout button backgrounds (lines 368, 636):

.background(if (imageQuality == quality) MaterialTheme.colorScheme.primary else MaterialTheme.colorScheme.surfaceVariant)

Quality button text (line 374):

color = if (imageQuality == quality) MaterialTheme.colorScheme.onPrimary else MaterialTheme.colorScheme.onSurface

Placeholder background (line 406):

.background(MaterialTheme.colorScheme.surfaceVariant)

Selection overlay (line 438):

.background(MaterialTheme.colorScheme.scrim.copy(alpha = 0.5f), CircleShape)

Check icon tint (lines 443, 649):

tint = MaterialTheme.colorScheme.onPrimary

Add icon tint (line 451):

tint = MaterialTheme.colorScheme.onSurfaceVariant

Layout option backgrounds (line 636):

.background(if (isSelected) MaterialTheme.colorScheme.primary else MaterialTheme.colorScheme.surfaceVariant)

Layout option text (line 643):

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
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):

Text("保存", color = MaterialTheme.colorScheme.onPrimary)

TopAppBar colors (lines 120-124):

colors = TopAppBarDefaults.topAppBarColors(
    containerColor = MaterialTheme.colorScheme.primary,
    titleContentColor = MaterialTheme.colorScheme.onPrimary,
    navigationIconContentColor = MaterialTheme.colorScheme.onPrimary
)

Description text colors (lines 160, 274, 324):

color = MaterialTheme.colorScheme.onSurfaceVariant
color = MaterialTheme.colorScheme.onSurfaceVariant
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
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
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
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).