diff --git a/app/k9mail/src/main/java/com/fsck/k9/App.kt b/app/k9mail/src/main/java/com/fsck/k9/App.kt
index 68991190e..0598ad958 100644
--- a/app/k9mail/src/main/java/com/fsck/k9/App.kt
+++ b/app/k9mail/src/main/java/com/fsck/k9/App.kt
@@ -6,6 +6,7 @@ import android.content.res.Resources
import com.fsck.k9.activity.MessageCompose
import com.fsck.k9.controller.MessagingController
import com.fsck.k9.external.MessageProvider
+import com.fsck.k9.notification.NotificationChannelManager
import com.fsck.k9.ui.base.AppLanguageManager
import com.fsck.k9.ui.base.ThemeManager
import com.fsck.k9.ui.base.extensions.currentLocale
@@ -13,6 +14,7 @@ import java.util.Locale
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.GlobalScope
+import kotlinx.coroutines.flow.distinctUntilChanged
import kotlinx.coroutines.flow.drop
import kotlinx.coroutines.flow.launchIn
import kotlinx.coroutines.flow.onEach
@@ -25,6 +27,7 @@ class App : Application() {
private val messagingListenerProvider: MessagingListenerProvider by inject()
private val themeManager: ThemeManager by inject()
private val appLanguageManager: AppLanguageManager by inject()
+ private val notificationChannelManager: NotificationChannelManager by inject()
private val appCoroutineScope: CoroutineScope = GlobalScope + Dispatchers.Main
private var appLanguageManagerInitialized = false
@@ -39,6 +42,7 @@ class App : Application() {
Core.init(this)
MessageProvider.init()
initializeAppLanguage()
+ updateNotificationChannelsOnAppLanguageChanges()
themeManager.init()
messagingListenerProvider.listeners.forEach { listener ->
@@ -109,6 +113,13 @@ class App : Application() {
return resources
}
+ private fun updateNotificationChannelsOnAppLanguageChanges() {
+ appLanguageManager.appLocale
+ .distinctUntilChanged()
+ .onEach { notificationChannelManager.updateChannels() }
+ .launchIn(appCoroutineScope)
+ }
+
companion object {
val appConfig = AppConfig(
componentsToDisable = listOf(MessageCompose::class.java)
diff --git a/app/ui/base/src/main/AndroidManifest.xml b/app/ui/base/src/main/AndroidManifest.xml
index 27dc68b7a..f69b1cd3c 100644
--- a/app/ui/base/src/main/AndroidManifest.xml
+++ b/app/ui/base/src/main/AndroidManifest.xml
@@ -1,2 +1,18 @@
-
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/app/ui/base/src/main/java/com/fsck/k9/ui/base/AppLanguageManager.kt b/app/ui/base/src/main/java/com/fsck/k9/ui/base/AppLanguageManager.kt
index 328490f52..dd306f095 100644
--- a/app/ui/base/src/main/java/com/fsck/k9/ui/base/AppLanguageManager.kt
+++ b/app/ui/base/src/main/java/com/fsck/k9/ui/base/AppLanguageManager.kt
@@ -3,6 +3,8 @@ package com.fsck.k9.ui.base
import android.content.res.Resources
import com.fsck.k9.K9
import com.fsck.k9.ui.base.extensions.currentLocale
+import com.fsck.k9.ui.base.locale.SystemLocaleChangeListener
+import com.fsck.k9.ui.base.locale.SystemLocaleManager
import java.util.Locale
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
@@ -19,11 +21,20 @@ import kotlinx.coroutines.plus
* - Notifies listeners when the app language has changed.
*/
class AppLanguageManager(
+ private val systemLocaleManager: SystemLocaleManager,
private val coroutineScope: CoroutineScope = GlobalScope + Dispatchers.Main
) {
private var currentOverrideLocale: Locale? = null
private val _overrideLocale = MutableSharedFlow(replay = 1)
+ private val _appLocale = MutableSharedFlow(replay = 1)
val overrideLocale: Flow = _overrideLocale
+ val appLocale: Flow = _appLocale
+
+ private val systemLocaleListener = SystemLocaleChangeListener {
+ coroutineScope.launch {
+ _appLocale.emit(systemLocale)
+ }
+ }
fun init() {
setLocale(K9.k9Language)
@@ -58,8 +69,15 @@ class AppLanguageManager(
val locale = overrideLocale ?: systemLocale
Locale.setDefault(locale)
+ if (overrideLocale == null) {
+ systemLocaleManager.addListener(systemLocaleListener)
+ } else {
+ systemLocaleManager.removeListener(systemLocaleListener)
+ }
+
coroutineScope.launch {
_overrideLocale.emit(overrideLocale)
+ _appLocale.emit(locale)
}
}
diff --git a/app/ui/base/src/main/java/com/fsck/k9/ui/base/KoinModule.kt b/app/ui/base/src/main/java/com/fsck/k9/ui/base/KoinModule.kt
index a23592e87..7fc76c252 100644
--- a/app/ui/base/src/main/java/com/fsck/k9/ui/base/KoinModule.kt
+++ b/app/ui/base/src/main/java/com/fsck/k9/ui/base/KoinModule.kt
@@ -1,9 +1,18 @@
package com.fsck.k9.ui.base
+import com.fsck.k9.ui.base.locale.SystemLocaleManager
import org.koin.core.qualifier.named
import org.koin.dsl.module
val uiBaseModule = module {
- single { ThemeManager(context = get(), themeProvider = get(), generalSettingsManager = get(), appCoroutineScope = get(named("AppCoroutineScope"))) }
- single { AppLanguageManager() }
+ single {
+ ThemeManager(
+ context = get(),
+ themeProvider = get(),
+ generalSettingsManager = get(),
+ appCoroutineScope = get(named("AppCoroutineScope"))
+ )
+ }
+ single { AppLanguageManager(systemLocaleManager = get()) }
+ single { SystemLocaleManager(context = get()) }
}
diff --git a/app/ui/base/src/main/java/com/fsck/k9/ui/base/locale/LocaleBroadcastReceiver.kt b/app/ui/base/src/main/java/com/fsck/k9/ui/base/locale/LocaleBroadcastReceiver.kt
new file mode 100644
index 000000000..cbcb78b08
--- /dev/null
+++ b/app/ui/base/src/main/java/com/fsck/k9/ui/base/locale/LocaleBroadcastReceiver.kt
@@ -0,0 +1,17 @@
+package com.fsck.k9.ui.base.locale
+
+import android.content.BroadcastReceiver
+import android.content.Context
+import android.content.Intent
+import org.koin.core.component.KoinComponent
+import org.koin.core.component.inject
+
+class LocaleBroadcastReceiver : BroadcastReceiver(), KoinComponent {
+ private val systemLocaleManager: SystemLocaleManager by inject()
+
+ override fun onReceive(context: Context, intent: Intent?) {
+ if (intent?.action == Intent.ACTION_LOCALE_CHANGED) {
+ systemLocaleManager.notifyListeners()
+ }
+ }
+}
diff --git a/app/ui/base/src/main/java/com/fsck/k9/ui/base/locale/SystemLocaleManager.kt b/app/ui/base/src/main/java/com/fsck/k9/ui/base/locale/SystemLocaleManager.kt
new file mode 100644
index 000000000..f3d1674e2
--- /dev/null
+++ b/app/ui/base/src/main/java/com/fsck/k9/ui/base/locale/SystemLocaleManager.kt
@@ -0,0 +1,68 @@
+package com.fsck.k9.ui.base.locale
+
+import android.content.ComponentName
+import android.content.Context
+import android.content.pm.PackageManager
+import java.util.concurrent.CopyOnWriteArraySet
+import timber.log.Timber
+
+class SystemLocaleManager(context: Context) {
+ private val packageManager = context.packageManager
+ private val componentName = ComponentName(context, LocaleBroadcastReceiver::class.java)
+
+ private val listeners = CopyOnWriteArraySet()
+
+ @Synchronized
+ fun addListener(listener: SystemLocaleChangeListener) {
+ if (listeners.isEmpty()) {
+ enableReceiver()
+ }
+
+ listeners.add(listener)
+ }
+
+ @Synchronized
+ fun removeListener(listener: SystemLocaleChangeListener) {
+ listeners.remove(listener)
+
+ if (listeners.isEmpty()) {
+ disableReceiver()
+ }
+ }
+
+ internal fun notifyListeners() {
+ for (listener in listeners) {
+ listener.onSystemLocaleChanged()
+ }
+ }
+
+ private fun enableReceiver() {
+ Timber.v("Enable LocaleBroadcastReceiver")
+ try {
+ packageManager.setComponentEnabledSetting(
+ componentName,
+ PackageManager.COMPONENT_ENABLED_STATE_ENABLED,
+ PackageManager.DONT_KILL_APP
+ )
+ } catch (e: Exception) {
+ Timber.e(e, "Error enabling LocaleBroadcastReceiver")
+ }
+ }
+
+ private fun disableReceiver() {
+ Timber.v("Disable LocaleBroadcastReceiver")
+ try {
+ packageManager.setComponentEnabledSetting(
+ componentName,
+ PackageManager.COMPONENT_ENABLED_STATE_DISABLED,
+ PackageManager.DONT_KILL_APP
+ )
+ } catch (e: Exception) {
+ Timber.e(e, "Error disabling LocaleBroadcastReceiver")
+ }
+ }
+}
+
+fun interface SystemLocaleChangeListener {
+ fun onSystemLocaleChanged()
+}
diff --git a/app/ui/legacy/src/main/java/com/fsck/k9/activity/MessageList.kt b/app/ui/legacy/src/main/java/com/fsck/k9/activity/MessageList.kt
index 510982e81..da6bce71a 100644
--- a/app/ui/legacy/src/main/java/com/fsck/k9/activity/MessageList.kt
+++ b/app/ui/legacy/src/main/java/com/fsck/k9/activity/MessageList.kt
@@ -38,7 +38,6 @@ import com.fsck.k9.fragment.MessageListFragment.MessageListFragmentListener
import com.fsck.k9.helper.Contacts
import com.fsck.k9.helper.ParcelableUtil
import com.fsck.k9.mailstore.SearchStatusManager
-import com.fsck.k9.notification.NotificationChannelManager
import com.fsck.k9.preferences.GeneralSettingsManager
import com.fsck.k9.search.LocalSearch
import com.fsck.k9.search.SearchAccount
@@ -90,7 +89,6 @@ open class MessageList :
protected val searchStatusManager: SearchStatusManager by inject()
private val preferences: Preferences by inject()
- private val channelUtils: NotificationChannelManager by inject()
private val defaultFolderProvider: DefaultFolderProvider by inject()
private val accountRemover: BackgroundAccountRemover by inject()
private val generalSettingsManager: GeneralSettingsManager by inject()
@@ -205,7 +203,6 @@ open class MessageList :
initializeFragments()
displayViews()
initializeRecentChangesSnackbar()
- channelUtils.updateChannels()
if (savedInstanceState == null) {
checkAndRequestPermissions()