diff --git a/app/src/main/java/com/rtbishop/look4sat/MainActivity.kt b/app/src/main/java/com/rtbishop/look4sat/MainActivity.kt index 80913a63..09145d28 100644 --- a/app/src/main/java/com/rtbishop/look4sat/MainActivity.kt +++ b/app/src/main/java/com/rtbishop/look4sat/MainActivity.kt @@ -27,6 +27,8 @@ import android.view.View import androidx.activity.ComponentActivity import androidx.activity.compose.setContent import androidx.activity.enableEdgeToEdge +import androidx.compose.runtime.collectAsState +import androidx.compose.runtime.getValue import androidx.core.splashscreen.SplashScreen.Companion.installSplashScreen import androidx.lifecycle.lifecycleScope import com.rtbishop.look4sat.core.domain.repository.IContainerProvider @@ -48,8 +50,10 @@ class MainActivity : ComponentActivity() { enableEdgeToEdge() super.onCreate(savedInstanceState) observeNightFilterState() + val settingsRepo = (applicationContext as IContainerProvider).getMainContainer().settingsRepo setContent { - MainTheme(isDarkTheme = true) { NavRoot() } + val otherSettings by settingsRepo.otherSettings.collectAsState() + MainTheme(isDarkTheme = !otherSettings.stateOfLightTheme) { NavRoot() } } } diff --git a/core/presentation/src/main/java/com/rtbishop/look4sat/core/presentation/MainTheme.kt b/core/presentation/src/main/java/com/rtbishop/look4sat/core/presentation/MainTheme.kt index fe5a4acf..69cf257c 100644 --- a/core/presentation/src/main/java/com/rtbishop/look4sat/core/presentation/MainTheme.kt +++ b/core/presentation/src/main/java/com/rtbishop/look4sat/core/presentation/MainTheme.kt @@ -61,8 +61,8 @@ fun MainTheme(isDarkTheme: Boolean = isSystemInDarkTheme(), content: @Composable SideEffect { val window = (view.context as ComponentActivity).window val insetsController = WindowCompat.getInsetsController(window, view) - insetsController.isAppearanceLightStatusBars = false - insetsController.isAppearanceLightNavigationBars = false + insetsController.isAppearanceLightStatusBars = !isDarkTheme + insetsController.isAppearanceLightNavigationBars = !isDarkTheme if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) { window.isNavigationBarContrastEnforced = false } diff --git a/core/presentation/src/main/res/values/strings.xml b/core/presentation/src/main/res/values/strings.xml index ed1b585f..c36c1738 100644 --- a/core/presentation/src/main/res/values/strings.xml +++ b/core/presentation/src/main/res/values/strings.xml @@ -266,6 +266,7 @@ Radar sweep Use sensors Night filter + Light theme Radar compass offset Radar compass offset (elev) diff --git a/feature/map/src/main/java/com/rtbishop/look4sat/feature/map/MapScreen.kt b/feature/map/src/main/java/com/rtbishop/look4sat/feature/map/MapScreen.kt index fec5a37d..46d7402b 100644 --- a/feature/map/src/main/java/com/rtbishop/look4sat/feature/map/MapScreen.kt +++ b/feature/map/src/main/java/com/rtbishop/look4sat/feature/map/MapScreen.kt @@ -122,6 +122,39 @@ private val moonIconPaint = Paint(Paint.ANTI_ALIAS_FLAG).apply { android.graphics.PorterDuffColorFilter("#E0E0E0".toColorInt(), android.graphics.PorterDuff.Mode.SRC_IN) } +/** Accent used for the station marker; recolored per theme so it stays visible on a light map. */ +private var mapAccentColor = "#FFE082".toColorInt() + +/** The dark-map filter (grayscale + invert) is only applied when NOT in light theme; cached to avoid rebuilds. */ +private val darkTileFilter by lazy { createColorFilter() } + +/** + * Recolor the shared overlay paints for the current theme. The light OSM tiles are white, so the + * dark-theme amber/grey overlays would vanish; light theme swaps them for dark, high-contrast colors. + * Must run before the set*() overlay builders on each frame, as several icons cache the paint color. + */ +private fun applyMapColors(isLightUi: Boolean) { + if (isLightUi) { + mapAccentColor = "#715C0C".toColorInt() // dark amber (matches app lightScheme primary) + footprintPaint.color = mapAccentColor + textPaint.color = "#1E1B13".toColorInt() + textPaint.setShadowLayer(3f, 3f, 3f, Color.WHITE) + sunIconPaint.colorFilter = + android.graphics.PorterDuffColorFilter(mapAccentColor, android.graphics.PorterDuff.Mode.SRC_IN) + moonIconPaint.colorFilter = + android.graphics.PorterDuffColorFilter("#4C4639".toColorInt(), android.graphics.PorterDuff.Mode.SRC_IN) + } else { + mapAccentColor = "#FFE082".toColorInt() + footprintPaint.color = mapAccentColor + textPaint.color = mapAccentColor + textPaint.setShadowLayer(3f, 3f, 3f, Color.BLACK) + sunIconPaint.colorFilter = + android.graphics.PorterDuffColorFilter(mapAccentColor, android.graphics.PorterDuff.Mode.SRC_IN) + moonIconPaint.colorFilter = + android.graphics.PorterDuffColorFilter("#E0E0E0".toColorInt(), android.graphics.PorterDuff.Mode.SRC_IN) + } +} + @Composable fun MapDestination() { val context = LocalContext.current @@ -177,6 +210,8 @@ private fun MapScreen(uiState: MapState, onAction: (MapAction) -> Unit, mapView: ElevatedCard(modifier = Modifier.weight(1f)) { Box(contentAlignment = Alignment.BottomCenter) { AndroidView({ mapView }) { view -> + applyMapColors(uiState.isLightUi) + view.overlayManager.tilesOverlay.setColorFilter(if (uiState.isLightUi) null else darkTileFilter) uiState.stationPosition?.let { setStationPosition(it, view) } uiState.track?.let { setSatelliteTrack(it, view) } uiState.footprint?.let { setFootprint(it, view) } @@ -288,7 +323,9 @@ private fun setStationPosition(stationPos: GeoPos, mapView: MapView) { mapView.overlays[OVERLAY_STATION] = Marker(mapView).apply { setInfoWindow(null) setAnchor(Marker.ANCHOR_CENTER, Marker.ANCHOR_BOTTOM) - icon = ContextCompat.getDrawable(mapView.context, R.drawable.ic_position) + icon = ContextCompat.getDrawable(mapView.context, R.drawable.ic_position)?.apply { + setTint(mapAccentColor) + } position = GeoPoint(stationPos.latitude, stationPos.longitude) } } @@ -585,7 +622,7 @@ private fun rememberMapViewWithLifecycle(): MapView { zoomController.setVisibility(CustomZoomButtonsController.Visibility.NEVER) overlayManager.tilesOverlay.loadingBackgroundColor = Color.TRANSPARENT overlayManager.tilesOverlay.loadingLineColor = Color.TRANSPARENT - overlayManager.tilesOverlay.setColorFilter(createColorFilter()) + // Tile color filter (dark inversion vs light) is applied per-theme in the AndroidView update block. setScrollableAreaLimitLatitude(maxLat, minLat, 0) overlays.addAll(Array(OVERLAY_COUNT) { FolderOverlay() }) } diff --git a/feature/map/src/main/java/com/rtbishop/look4sat/feature/map/MapViewModel.kt b/feature/map/src/main/java/com/rtbishop/look4sat/feature/map/MapViewModel.kt index 59407aa4..91524290 100644 --- a/feature/map/src/main/java/com/rtbishop/look4sat/feature/map/MapViewModel.kt +++ b/feature/map/src/main/java/com/rtbishop/look4sat/feature/map/MapViewModel.kt @@ -80,7 +80,7 @@ class MapViewModel( init { viewModelScope.launch { settingsRepo.otherSettings.collectLatest { settings -> - _uiState.update { it.copy(isUtc = settings.stateOfUtc) } + _uiState.update { it.copy(isUtc = settings.stateOfUtc, isLightUi = settings.stateOfLightTheme) } } } val (selectedCatNum, _) = satelliteRepo.selectedPass.value diff --git a/feature/settings/src/main/java/com/rtbishop/look4sat/feature/settings/SettingsScreen.kt b/feature/settings/src/main/java/com/rtbishop/look4sat/feature/settings/SettingsScreen.kt index ea67b40b..8192c3c8 100644 --- a/feature/settings/src/main/java/com/rtbishop/look4sat/feature/settings/SettingsScreen.kt +++ b/feature/settings/src/main/java/com/rtbishop/look4sat/feature/settings/SettingsScreen.kt @@ -495,12 +495,24 @@ private fun OtherCard(settings: OtherSettings, onAction: (SettingsAction) -> Uni color = MaterialTheme.colorScheme.primary ) Spacer(modifier = Modifier.height(4.dp)) + // Appearance: light theme (paired with a spacer to align with the two-column rows) + Row(modifier = Modifier.fillMaxWidth(), horizontalArrangement = Arrangement.spacedBy(8.dp)) { + SwitchTile(R.string.prefs_other_switch_light_theme, settings.stateOfLightTheme) { + onAction(SettingsAction.ToggleLightTheme(it)) + } + Spacer(modifier = Modifier.weight(1f)) + } + Spacer(modifier = Modifier.height(4.dp)) // Display preferences: UTC clock + night filter Row(modifier = Modifier.fillMaxWidth(), horizontalArrangement = Arrangement.spacedBy(8.dp)) { SwitchTile(R.string.prefs_other_switch_utc, settings.stateOfUtc) { onAction(SettingsAction.ToggleUtc(it)) } - SwitchTile(R.string.prefs_other_switch_night_mode, settings.stateOfNightMode) { + SwitchTile( + R.string.prefs_other_switch_night_mode, + settings.stateOfNightMode, + enabled = !settings.stateOfLightTheme + ) { onAction(SettingsAction.ToggleNightMode(it)) } } @@ -573,7 +585,12 @@ private fun SwitchRow(labelResId: Int, checked: Boolean, onCheckedChange: (Boole } @Composable -private fun RowScope.SwitchTile(labelResId: Int, checked: Boolean, onCheckedChange: (Boolean) -> Unit) { +private fun RowScope.SwitchTile( + labelResId: Int, + checked: Boolean, + enabled: Boolean = true, + onCheckedChange: (Boolean) -> Unit +) { Row( horizontalArrangement = Arrangement.SpaceBetween, verticalAlignment = Alignment.CenterVertically, @@ -583,7 +600,7 @@ private fun RowScope.SwitchTile(labelResId: Int, checked: Boolean, onCheckedChan text = stringResource(id = labelResId), modifier = Modifier.weight(1f) ) - Switch(checked = checked, onCheckedChange = onCheckedChange) + Switch(checked = checked, enabled = enabled, onCheckedChange = onCheckedChange) } } diff --git a/feature/settings/src/main/java/com/rtbishop/look4sat/feature/settings/SettingsViewModel.kt b/feature/settings/src/main/java/com/rtbishop/look4sat/feature/settings/SettingsViewModel.kt index 351b0e69..f933398c 100644 --- a/feature/settings/src/main/java/com/rtbishop/look4sat/feature/settings/SettingsViewModel.kt +++ b/feature/settings/src/main/java/com/rtbishop/look4sat/feature/settings/SettingsViewModel.kt @@ -127,7 +127,10 @@ class SettingsViewModel( is SettingsAction.ToggleUpdate -> settingsRepo.updateOtherSettings { it.copy(stateOfAutoUpdate = action.value) } is SettingsAction.ToggleSweep -> settingsRepo.updateOtherSettings { it.copy(stateOfSweep = action.value) } is SettingsAction.ToggleSensor -> settingsRepo.updateOtherSettings { it.copy(stateOfSensors = action.value) } - is SettingsAction.ToggleLightTheme -> settingsRepo.updateOtherSettings { it.copy(stateOfLightTheme = action.value) } + is SettingsAction.ToggleLightTheme -> settingsRepo.updateOtherSettings { + // Night filter (red-only overlay) is incompatible with the light theme, so turn it off. + it.copy(stateOfLightTheme = action.value, stateOfNightMode = if (action.value) false else it.stateOfNightMode) + } is SettingsAction.ToggleNightMode -> settingsRepo.updateOtherSettings { it.copy(stateOfNightMode = action.value) } is SettingsAction.SetRadarCompassOffset -> settingsRepo.updateOtherSettings { it.copy(radarCompassOffset = action.value) } is SettingsAction.SetRadarCompassOffsetElev -> settingsRepo.updateOtherSettings { it.copy(radarCompassOffsetElev = action.value) }