Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -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() } }
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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) }
}
Expand Down
24 changes: 14 additions & 10 deletions app/src/main/java/be/scri/helpers/PreferencesHelper.kt
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down Expand Up @@ -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 {
Expand Down Expand Up @@ -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
}

Expand Down
40 changes: 38 additions & 2 deletions app/src/main/java/be/scri/ui/screens/settings/SettingsScreen.kt
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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.
Expand Down Expand Up @@ -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(
Expand Down Expand Up @@ -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))
}
},
)
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,11 @@ class SettingsViewModel(
MutableStateFlow(sharedPrefs.getBoolean("show_popup_on_keypress", false))
val popupOnKeypress: StateFlow<Boolean> = _popupOnKeypress

private val _isUserDarkMode = MutableStateFlow(sharedPrefs.getBoolean("dark_mode", false))
private val _isUserDarkMode =
MutableStateFlow(
be.scri.helpers.PreferencesHelper
.getIsDarkModeOrNot(context),
)
val isUserDarkMode: StateFlow<Boolean> = _isUserDarkMode

private val _holdForAltKeys = MutableStateFlow(sharedPrefs.getBoolean("hold_for_alt_keys", false))
Expand Down
22 changes: 9 additions & 13 deletions app/src/main/java/be/scri/views/KeyboardView.kt
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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(
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -1486,10 +1483,9 @@ class KeyboardView
.findViewById<View>(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(
Expand Down
7 changes: 7 additions & 0 deletions app/src/main/res/values/theme_strings.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<string name="i18n_theme_warning_title">Theme Override</string>
<string name="i18n_theme_warning_message">You are selecting a theme that goes against your system default. Are you sure you want to proceed?</string>
<string name="i18n_ok">OK</string>
<string name="i18n_cancel">Cancel</string>
</resources>
Loading