diff --git a/app/src/androidTestKeyboards/kotlin/be/scri/helpers/KeyboardTest.kt b/app/src/androidTestKeyboards/kotlin/be/scri/helpers/KeyboardTest.kt index 09e31f4f1..0d3d917a0 100644 --- a/app/src/androidTestKeyboards/kotlin/be/scri/helpers/KeyboardTest.kt +++ b/app/src/androidTestKeyboards/kotlin/be/scri/helpers/KeyboardTest.kt @@ -106,8 +106,8 @@ class KeyboardTest { suggestionHandler.processLinguisticSuggestions("in") - verify { conjugateBtn.text = match { it.isNotEmpty() } } - verify { pluralBtn.text = match { it.isNotEmpty() } } - verify { translateBtn.text = match { it.isNotEmpty() } } + verify(timeout = 2000) { conjugateBtn.text = match { it.isNotEmpty() } } + verify(timeout = 2000) { pluralBtn.text = match { it.isNotEmpty() } } + verify(timeout = 2000) { translateBtn.text = match { it.isNotEmpty() } } } } diff --git a/app/src/androidTestKeyboards/kotlin/be/scri/ui/screens/settings/SettingsScreenInstrumentedTest.kt b/app/src/androidTestKeyboards/kotlin/be/scri/ui/screens/settings/SettingsScreenInstrumentedTest.kt index c984cadbe..e0a85a91c 100644 --- a/app/src/androidTestKeyboards/kotlin/be/scri/ui/screens/settings/SettingsScreenInstrumentedTest.kt +++ b/app/src/androidTestKeyboards/kotlin/be/scri/ui/screens/settings/SettingsScreenInstrumentedTest.kt @@ -8,6 +8,7 @@ import androidx.compose.runtime.Composable import androidx.compose.ui.test.assertHasClickAction import androidx.compose.ui.test.assertIsDisplayed import androidx.compose.ui.test.junit4.createAndroidComposeRule +import androidx.compose.ui.test.onAllNodesWithText import androidx.compose.ui.test.onNodeWithText import androidx.compose.ui.test.performClick import androidx.test.ext.junit.runners.AndroidJUnit4 @@ -256,6 +257,14 @@ class SettingsScreenInstrumentedTest { composeTestRule.waitForIdle() + // Click OK on the warning dialog if it appeared (since it goes against system theme) + composeTestRule.onAllNodesWithText("OK").apply { + if (fetchSemanticsNodes().isNotEmpty()) { + get(0).performClick() + composeTestRule.waitForIdle() + } + } + verify(timeout = 3000) { mockViewModelSpy.setLightDarkMode(true) } verify(timeout = 3000) { onDarkModeChangeMock(true) } } diff --git a/app/src/main/java/be/scri/helpers/PreferencesHelper.kt b/app/src/main/java/be/scri/helpers/PreferencesHelper.kt index 1427bb8a0..6a2451093 100644 --- a/app/src/main/java/be/scri/helpers/PreferencesHelper.kt +++ b/app/src/main/java/be/scri/helpers/PreferencesHelper.kt @@ -2,12 +2,10 @@ package be.scri.helpers -import android.app.UiModeManager import android.content.Context import android.content.Context.MODE_PRIVATE import android.content.res.Configuration import android.widget.Toast -import androidx.appcompat.app.AppCompatActivity.UI_MODE_SERVICE import androidx.appcompat.app.AppCompatDelegate import androidx.core.content.edit @@ -304,13 +302,7 @@ object PreferencesHelper { * @return The dark mode setting as an integer value (AppCompatDelegate.MODE_NIGHT_YES or MODE_NIGHT_NO). */ fun getUserDarkModePreference(context: Context): Int { - val sharedPref = context.getSharedPreferences(SCRIBE_PREFS, Context.MODE_PRIVATE) - val uiModeManager = context.getSystemService(UI_MODE_SERVICE) as UiModeManager - val isSystemDarkTheme = uiModeManager.nightMode == UiModeManager.MODE_NIGHT_YES - val isUserDarkMode = sharedPref.getBoolean("dark_mode", isSystemDarkTheme) - if (!sharedPref.contains("dark_mode")) { - setLightDarkModePreference(context, isUserDarkMode) - } + val isUserDarkMode = getIsDarkModeOrNot(context) return if (isUserDarkMode) { AppCompatDelegate.MODE_NIGHT_YES } else { @@ -427,7 +419,19 @@ object PreferencesHelper { val sharedPref = context.getSharedPreferences(SCRIBE_PREFS, MODE_PRIVATE) val currentNightMode = context.resources.configuration.uiMode and Configuration.UI_MODE_NIGHT_MASK val isSystemDarkMode = currentNightMode == Configuration.UI_MODE_NIGHT_YES - val isUserDarkMode = sharedPref.getBoolean("dark_mode", isSystemDarkMode) + + val lastSystemTheme = sharedPref.getBoolean("last_system_dark_mode", isSystemDarkMode) + var isUserDarkMode = sharedPref.getBoolean("dark_mode", isSystemDarkMode) + + if (!sharedPref.contains("last_system_dark_mode") || lastSystemTheme != isSystemDarkMode) { + isUserDarkMode = isSystemDarkMode + sharedPref + .edit() + .putBoolean("dark_mode", isUserDarkMode) + .putBoolean("last_system_dark_mode", isSystemDarkMode) + .apply() + } + return isUserDarkMode } diff --git a/app/src/main/java/be/scri/ui/screens/settings/SettingsScreen.kt b/app/src/main/java/be/scri/ui/screens/settings/SettingsScreen.kt index 455853f4f..e19360995 100644 --- a/app/src/main/java/be/scri/ui/screens/settings/SettingsScreen.kt +++ b/app/src/main/java/be/scri/ui/screens/settings/SettingsScreen.kt @@ -12,6 +12,7 @@ import androidx.compose.runtime.Composable import androidx.compose.runtime.DisposableEffect import androidx.compose.runtime.collectAsState import androidx.compose.runtime.getValue +import androidx.compose.runtime.setValue import androidx.compose.ui.Modifier import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.res.stringResource @@ -52,6 +53,10 @@ fun SettingsScreen( val isUserDarkMode by viewModel.isUserDarkMode.collectAsState() val isIncreaseTextSize by viewModel.isIncreaseTextSize.collectAsState() + val isSystemDarkMode = androidx.compose.foundation.isSystemInDarkTheme() + var showThemeWarningDialog by androidx.compose.runtime.remember { androidx.compose.runtime.mutableStateOf(false) } + var pendingDarkMode by androidx.compose.runtime.remember { androidx.compose.runtime.mutableStateOf(false) } + val lifecycleOwner = LocalLifecycleOwner.current // Observe lifecycle events. @@ -85,8 +90,13 @@ fun SettingsScreen( desc = R.string.i18n_app_settings_menu_app_color_mode_description, state = isUserDarkMode, onToggle = { newDarkMode -> - viewModel.setLightDarkMode(newDarkMode) - onDarkModeChange(newDarkMode) + if (newDarkMode != isSystemDarkMode) { + pendingDarkMode = newDarkMode + showThemeWarningDialog = true + } else { + viewModel.setLightDarkMode(newDarkMode) + onDarkModeChange(newDarkMode) + } }, ), ScribeItem.SwitchItem( @@ -146,5 +156,31 @@ fun SettingsScreen( item { Spacer(modifier = Modifier.height(10.dp)) } } + + if (showThemeWarningDialog) { + androidx.compose.material3.AlertDialog( + onDismissRequest = { showThemeWarningDialog = false }, + title = { androidx.compose.material3.Text(text = stringResource(R.string.i18n_theme_warning_title)) }, + text = { androidx.compose.material3.Text(text = stringResource(R.string.i18n_theme_warning_message)) }, + confirmButton = { + androidx.compose.material3.TextButton( + onClick = { + viewModel.setLightDarkMode(pendingDarkMode) + onDarkModeChange(pendingDarkMode) + showThemeWarningDialog = false + }, + ) { + androidx.compose.material3.Text(text = stringResource(R.string.i18n_ok)) + } + }, + dismissButton = { + androidx.compose.material3.TextButton( + onClick = { showThemeWarningDialog = false }, + ) { + androidx.compose.material3.Text(text = stringResource(R.string.i18n_cancel)) + } + }, + ) + } } } diff --git a/app/src/main/java/be/scri/ui/screens/settings/SettingsViewModel.kt b/app/src/main/java/be/scri/ui/screens/settings/SettingsViewModel.kt index 6656c6939..8e22d04d6 100644 --- a/app/src/main/java/be/scri/ui/screens/settings/SettingsViewModel.kt +++ b/app/src/main/java/be/scri/ui/screens/settings/SettingsViewModel.kt @@ -29,7 +29,11 @@ class SettingsViewModel( MutableStateFlow(sharedPrefs.getBoolean("show_popup_on_keypress", false)) val popupOnKeypress: StateFlow = _popupOnKeypress - private val _isUserDarkMode = MutableStateFlow(sharedPrefs.getBoolean("dark_mode", false)) + private val _isUserDarkMode = + MutableStateFlow( + be.scri.helpers.PreferencesHelper + .getIsDarkModeOrNot(context), + ) val isUserDarkMode: StateFlow = _isUserDarkMode private val _holdForAltKeys = MutableStateFlow(sharedPrefs.getBoolean("hold_for_alt_keys", false)) diff --git a/app/src/main/java/be/scri/views/KeyboardView.kt b/app/src/main/java/be/scri/views/KeyboardView.kt index 0e959a38a..e020e7cd5 100644 --- a/app/src/main/java/be/scri/views/KeyboardView.kt +++ b/app/src/main/java/be/scri/views/KeyboardView.kt @@ -4,7 +4,6 @@ package be.scri.views import android.annotation.SuppressLint import android.content.Context -import android.content.res.Configuration import android.graphics.Bitmap import android.graphics.Canvas import android.graphics.Color @@ -598,10 +597,9 @@ class KeyboardView mBackgroundColor } - val sharedPref = context.getSharedPreferences("app_preferences", Context.MODE_PRIVATE) - val currentNightMode = context.resources.configuration.uiMode and Configuration.UI_MODE_NIGHT_MASK - val isSystemDarkMode = currentNightMode == Configuration.UI_MODE_NIGHT_YES - val isUserDarkMode = sharedPref.getBoolean("dark_mode", isSystemDarkMode) + val isUserDarkMode = + be.scri.helpers.PreferencesHelper + .getIsDarkModeOrNot(context) val miniKeyboardBackgroundColor = resources.getColor( @@ -814,10 +812,9 @@ class KeyboardView canvas!!.clipRect(mDirtyRect) val paint = mPaint val keys = mKeys - val sharedPref = context.getSharedPreferences("app_preferences", Context.MODE_PRIVATE) - val currentNightMode = context.resources.configuration.uiMode and Configuration.UI_MODE_NIGHT_MASK - val isSystemDarkMode = currentNightMode == Configuration.UI_MODE_NIGHT_YES - val isUserDarkMode = sharedPref.getBoolean("dark_mode", isSystemDarkMode) + val isUserDarkMode = + be.scri.helpers.PreferencesHelper + .getIsDarkModeOrNot(context) val keyBackgroundColor = if (isUserDarkMode) { Color.DKGRAY @@ -1486,10 +1483,9 @@ class KeyboardView .findViewById(R.id.mini_keyboard_view) as KeyboardView } - val sharedPref = context.getSharedPreferences("app_preferences", Context.MODE_PRIVATE) - val currentNightMode = context.resources.configuration.uiMode and Configuration.UI_MODE_NIGHT_MASK - val isSystemDarkMode = currentNightMode == Configuration.UI_MODE_NIGHT_YES - val isUserDarkMode = sharedPref.getBoolean("dark_mode", isSystemDarkMode) + val isUserDarkMode = + be.scri.helpers.PreferencesHelper + .getIsDarkModeOrNot(context) val miniKeyboardBackgroundColor = resources.getColor( diff --git a/app/src/main/res/values/theme_strings.xml b/app/src/main/res/values/theme_strings.xml new file mode 100644 index 000000000..1f04ed935 --- /dev/null +++ b/app/src/main/res/values/theme_strings.xml @@ -0,0 +1,7 @@ + + + Theme Override + You are selecting a theme that goes against your system default. Are you sure you want to proceed? + OK + Cancel +