feat(v1.8.0): IMPL_01 Language Settings - Smooth Language Switching

- Prevent activity recreate during language changes via configChanges
- Add onConfigurationChanged() handler in ComposeSettingsActivity
- Simplify setAppLanguage() - let system handle locale change smoothly
- Update language_info strings to reflect smooth transition
- Remove unused Activity parameter and imports

Fixes flicker during language switching by handling configuration
changes instead of recreating the entire activity. Compose recomposes
automatically when locale changes, providing seamless UX.
This commit is contained in:
inventory69
2026-02-10 14:02:42 +01:00
parent 1da1a63566
commit 881c0fd0fa
5 changed files with 24 additions and 14 deletions

View File

@@ -69,8 +69,10 @@
android:parentActivityName=".ui.main.ComposeMainActivity" /> android:parentActivityName=".ui.main.ComposeMainActivity" />
<!-- Settings Activity v1.5.0 (Jetpack Compose) --> <!-- Settings Activity v1.5.0 (Jetpack Compose) -->
<!-- v1.8.0: Handle locale changes without recreate for smooth language switching -->
<activity <activity
android:name=".ui.settings.ComposeSettingsActivity" android:name=".ui.settings.ComposeSettingsActivity"
android:configChanges="locale|layoutDirection"
android:parentActivityName=".ui.main.ComposeMainActivity" android:parentActivityName=".ui.main.ComposeMainActivity"
android:theme="@style/Theme.SimpleNotes" /> android:theme="@style/Theme.SimpleNotes" />

View File

@@ -189,4 +189,16 @@ class ComposeSettingsActivity : AppCompatActivity() {
Logger.e(TAG, "❌ Failed to restart NetworkMonitor: ${e.message}") Logger.e(TAG, "❌ Failed to restart NetworkMonitor: ${e.message}")
} }
} }
/**
* Handle configuration changes (e.g., locale) without recreating activity
* v1.8.0: Prevents flickering during language changes by avoiding full recreate
* Compose automatically recomposes when configuration changes
*/
override fun onConfigurationChanged(newConfig: android.content.res.Configuration) {
super.onConfigurationChanged(newConfig)
Logger.d(TAG, "📱 Configuration changed (likely locale switch) - Compose will recompose")
// Compose handles UI updates automatically via recomposition
// No manual action needed - stringResource() etc. will pick up new locale
}
} }

View File

@@ -1,6 +1,5 @@
package dev.dettmer.simplenotes.ui.settings.screens package dev.dettmer.simplenotes.ui.settings.screens
import android.app.Activity
import androidx.appcompat.app.AppCompatDelegate import androidx.appcompat.app.AppCompatDelegate
import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.Spacer
@@ -15,7 +14,6 @@ import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue import androidx.compose.runtime.setValue
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.res.stringResource import androidx.compose.ui.res.stringResource
import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.dp
import androidx.core.os.LocaleListCompat import androidx.core.os.LocaleListCompat
@@ -35,8 +33,6 @@ import dev.dettmer.simplenotes.ui.settings.components.SettingsScaffold
fun LanguageSettingsScreen( fun LanguageSettingsScreen(
onBack: () -> Unit onBack: () -> Unit
) { ) {
val context = LocalContext.current
// Get current app locale - fresh value each time (no remember, always reads current state) // Get current app locale - fresh value each time (no remember, always reads current state)
val currentLocale = AppCompatDelegate.getApplicationLocales() val currentLocale = AppCompatDelegate.getApplicationLocales()
val currentLanguageCode = if (currentLocale.isEmpty) { val currentLanguageCode = if (currentLocale.isEmpty) {
@@ -92,7 +88,7 @@ fun LanguageSettingsScreen(
onValueSelected = { newLanguage -> onValueSelected = { newLanguage ->
if (newLanguage != selectedLanguage) { if (newLanguage != selectedLanguage) {
selectedLanguage = newLanguage selectedLanguage = newLanguage
setAppLanguage(newLanguage, context as Activity) setAppLanguage(newLanguage)
} }
} }
) )
@@ -102,19 +98,19 @@ fun LanguageSettingsScreen(
/** /**
* Set app language using AppCompatDelegate * Set app language using AppCompatDelegate
* Works on Android 13+ natively, falls back to AppCompat on older versions * v1.8.0: Smooth language change without activity recreate
*
* ComposeSettingsActivity handles locale changes via android:configChanges="locale"
* in AndroidManifest.xml, preventing full activity recreate and eliminating flicker.
* Compose automatically recomposes when the configuration changes.
*/ */
private fun setAppLanguage(languageCode: String, activity: Activity) { private fun setAppLanguage(languageCode: String) {
val localeList = if (languageCode.isEmpty()) { val localeList = if (languageCode.isEmpty()) {
LocaleListCompat.getEmptyLocaleList() LocaleListCompat.getEmptyLocaleList()
} else { } else {
LocaleListCompat.forLanguageTags(languageCode) LocaleListCompat.forLanguageTags(languageCode)
} }
// Sets the app locale - triggers onConfigurationChanged() instead of recreate()
AppCompatDelegate.setApplicationLocales(localeList) AppCompatDelegate.setApplicationLocales(localeList)
// Restart the activity to apply the change
// On Android 13+ the system handles this automatically for some apps,
// but we need to recreate to ensure our Compose UI recomposes with new locale
activity.recreate()
} }

View File

@@ -409,7 +409,7 @@
<string name="language_system_default">Systemstandard</string> <string name="language_system_default">Systemstandard</string>
<string name="language_english">English</string> <string name="language_english">English</string>
<string name="language_german">Deutsch</string> <string name="language_german">Deutsch</string>
<string name="language_info"> Wähle deine bevorzugte Sprache. Die App wird neu gestartet, um die Änderung anzuwenden.</string> <string name="language_info"> Wähle deine bevorzugte Sprache. Die Ansicht wird kurz aktualisiert, um die Änderung anzuwenden.</string>
<string name="language_changed_restart">Sprache geändert. Neustart…</string> <string name="language_changed_restart">Sprache geändert. Neustart…</string>
<!-- ============================= --> <!-- ============================= -->

View File

@@ -409,7 +409,7 @@
<string name="language_system_default">System Default</string> <string name="language_system_default">System Default</string>
<string name="language_english">English</string> <string name="language_english">English</string>
<string name="language_german">Deutsch</string> <string name="language_german">Deutsch</string>
<string name="language_info"> Choose your preferred language. The app will restart to apply the change.</string> <string name="language_info"> Choose your preferred language. The view will briefly refresh to apply the change.</string>
<string name="language_changed_restart">Language changed. Restarting…</string> <string name="language_changed_restart">Language changed. Restarting…</string>
<!-- ============================= --> <!-- ============================= -->