From 17cfd884976b4accbb2ad6af6acf3578d0c6ec53 Mon Sep 17 00:00:00 2001 From: Claude Date: Wed, 3 Jun 2026 01:01:00 +0000 Subject: Add night vision mode toggle Single-tap moon FAB (stacked below layers FAB) toggles red-on-black night vision mode. NightVision theme now has a full M3 color palette (surface, surfaceVariant, outline, secondary, error) all in dark red tones. Screen brightness is set to 30% in night mode and restored to system default on exit. State persists across sessions; recreate() applies the theme switch cleanly. https://claude.ai/code/session_01KXYBuAHZkvv63DeUG6XaZD --- .../src/main/kotlin/org/terst/nav/MainActivity.kt | 21 ++++++++++++++++ .../app/src/main/res/drawable/ic_night_mode.xml | 10 ++++++++ .../app/src/main/res/layout/activity_main.xml | 14 +++++++++++ android-app/app/src/main/res/values/colors.xml | 29 +++++++++++++++++----- android-app/app/src/main/res/values/themes.xml | 26 ++++++++++++++++--- 5 files changed, 90 insertions(+), 10 deletions(-) create mode 100644 android-app/app/src/main/res/drawable/ic_night_mode.xml (limited to 'android-app/app') diff --git a/android-app/app/src/main/kotlin/org/terst/nav/MainActivity.kt b/android-app/app/src/main/kotlin/org/terst/nav/MainActivity.kt index da887f4..69ca666 100644 --- a/android-app/app/src/main/kotlin/org/terst/nav/MainActivity.kt +++ b/android-app/app/src/main/kotlin/org/terst/nav/MainActivity.kt @@ -54,6 +54,7 @@ import org.terst.nav.ui.safety.SafetyFragment import org.terst.nav.ui.vessel.VesselRegistryFragment import org.terst.nav.ui.voicelog.VoiceLogFragment import java.util.* +import android.view.WindowManager import org.terst.nav.data.model.MarineConditions import org.terst.nav.safety.AnchorWatchState @@ -61,6 +62,11 @@ class MainActivity : AppCompatActivity(), SafetyFragment.SafetyListener { private val featureFlags get() = (application as NavApplication).featureFlags + private val nightModePrefs by lazy { getSharedPreferences("night_mode", MODE_PRIVATE) } + private var isNightMode: Boolean + get() = nightModePrefs.getBoolean("enabled", false) + set(v) { nightModePrefs.edit().putBoolean("enabled", v).apply() } + private var mapView: MapView? = null private var mobHandler: MobHandler? = null private var instrumentHandler: InstrumentHandler? = null @@ -75,6 +81,7 @@ class MainActivity : AppCompatActivity(), SafetyFragment.SafetyListener { private lateinit var fragmentContainer: FrameLayout private lateinit var fabRecordTrack: FloatingActionButton private lateinit var fabLayers: FloatingActionButton + private lateinit var fabNightMode: FloatingActionButton private lateinit var fabRecenter: MaterialButton private lateinit var bottomSheet: CardView private lateinit var bottomNav: BottomNavigationView @@ -134,6 +141,7 @@ class MainActivity : AppCompatActivity(), SafetyFragment.SafetyListener { } override fun onCreate(savedInstanceState: Bundle?) { + if (isNightMode) setTheme(R.style.Theme_Nav_NightVision) super.onCreate(savedInstanceState) MapLibre.getInstance(this) setContentView(R.layout.activity_main) @@ -200,10 +208,17 @@ class MainActivity : AppCompatActivity(), SafetyFragment.SafetyListener { fragmentContainer = findViewById(R.id.fragment_container) fabRecordTrack = findViewById(R.id.fab_record_track) fabLayers = findViewById(R.id.fab_layers) + fabNightMode = findViewById(R.id.fab_night_mode) fabRecenter = findViewById(R.id.fab_recenter) fabLayers.setOnClickListener { buildLayerPickerSheet().show(supportFragmentManager, "layer_picker") } + fabNightMode.setOnClickListener { + isNightMode = !isNightMode + applyScreenBrightness() + recreate() + } + applyScreenBrightness() bottomSheet = findViewById(R.id.instrument_bottom_sheet) bottomNav = findViewById(R.id.bottom_navigation) mapCrosshair = findViewById(R.id.map_crosshair) @@ -307,6 +322,12 @@ class MainActivity : AppCompatActivity(), SafetyFragment.SafetyListener { } /** Updates all static unit label TextViews to match current [unitPrefs]. */ + private fun applyScreenBrightness() { + val lp = window.attributes + lp.screenBrightness = if (isNightMode) 0.3f else WindowManager.LayoutParams.BRIGHTNESS_OVERRIDE_NONE + window.attributes = lp + } + private fun applyUnitLabels() { unitHudSog.text = unitPrefs.speedUnitLabel() unitHudBsp.text = unitPrefs.speedUnitLabel() diff --git a/android-app/app/src/main/res/drawable/ic_night_mode.xml b/android-app/app/src/main/res/drawable/ic_night_mode.xml new file mode 100644 index 0000000..b19aeb7 --- /dev/null +++ b/android-app/app/src/main/res/drawable/ic_night_mode.xml @@ -0,0 +1,10 @@ + + + + diff --git a/android-app/app/src/main/res/layout/activity_main.xml b/android-app/app/src/main/res/layout/activity_main.xml index 6832daa..ca13105 100644 --- a/android-app/app/src/main/res/layout/activity_main.xml +++ b/android-app/app/src/main/res/layout/activity_main.xml @@ -53,6 +53,20 @@ app:layout_constraintTop_toBottomOf="@id/nav_hud" app:layout_constraintEnd_toEndOf="parent" /> + + + #50FFFFFF #80FFFFFF - - #FFFF0000 - #FFBB0000 - #FF000000 + #FF000000 - #FF110000 - #FFFF0000 + #FF0F0000 + #FF1C0000 + #FF200000 + + #FFFF3300 + #FFCC2200 + + #FF3D0000 + #FF1F0000 + + #FFFF3300 + #FF000000 + #FF1C0000 + #FFFF3300 + + #FF881100 + #FF000000 + #FF1C0000 + #FFFF3300 + + #FFFF6B6B + #FF000000 diff --git a/android-app/app/src/main/res/values/themes.xml b/android-app/app/src/main/res/values/themes.xml index 93f5209..25af4e8 100755 --- a/android-app/app/src/main/res/values/themes.xml +++ b/android-app/app/src/main/res/values/themes.xml @@ -27,14 +27,32 @@ false - - -- cgit v1.2.3