mirror of
https://github.com/tapframe/NuvioStreaming.git
synced 2026-05-17 15:32:01 +00:00
fix: localising desktop
This commit is contained in:
parent
b30ad31b37
commit
b1b5a82fce
5 changed files with 56 additions and 7 deletions
|
|
@ -100,7 +100,9 @@ actual object ThemeSettingsStorage {
|
|||
actual fun replaceFromSyncPayload(payload: JsonObject) {
|
||||
preferences?.edit()?.apply {
|
||||
profileScopedSyncKeys.forEach { remove(ProfileScopedKey.of(it)) }
|
||||
globalSyncKeys.forEach { remove(it) }
|
||||
globalSyncKeys
|
||||
.filter(payload::containsKey)
|
||||
.forEach { remove(it) }
|
||||
}?.apply()
|
||||
|
||||
payload.decodeSyncString(selectedThemeKey)?.let(::saveSelectedTheme)
|
||||
|
|
|
|||
|
|
@ -55,6 +55,7 @@ import kotlinx.serialization.json.encodeToJsonElement
|
|||
import kotlinx.serialization.json.put
|
||||
|
||||
private const val PUSH_DEBOUNCE_MS = 1500L
|
||||
private const val APP_LANGUAGE_SYNC_KEY = "selected_app_language"
|
||||
|
||||
object ProfileSettingsSync {
|
||||
private val scope = CoroutineScope(SupervisorJob() + Dispatchers.Default)
|
||||
|
|
@ -74,6 +75,9 @@ object ProfileSettingsSync {
|
|||
@Volatile
|
||||
private var skipNextPushSignature: String? = null
|
||||
|
||||
@Volatile
|
||||
private var pendingLocalAppLanguageCode: String? = null
|
||||
|
||||
private var observeJob: Job? = null
|
||||
|
||||
fun startObserving() {
|
||||
|
|
@ -121,7 +125,7 @@ object ProfileSettingsSync {
|
|||
return@withLock false
|
||||
}
|
||||
|
||||
applyRemoteBlob(remoteBlob)
|
||||
applyRemoteBlob(remoteBlob.withPendingLocalAppLanguage())
|
||||
skipNextPushSignature = currentObservedStateSignature()
|
||||
} finally {
|
||||
isApplyingRemoteBlob = false
|
||||
|
|
@ -140,21 +144,31 @@ object ProfileSettingsSync {
|
|||
|
||||
suspend fun pushCurrentProfileToRemote() {
|
||||
ensureRepositoriesLoaded()
|
||||
val authState = AuthRepository.state.value
|
||||
if (authState !is AuthState.Authenticated || authState.isAnonymous) return
|
||||
syncMutex.withLock {
|
||||
runCatching {
|
||||
pushToRemoteLocked(ProfileRepository.activeProfileId, exportSettingsBlob())
|
||||
if (pendingLocalAppLanguageCode == ThemeSettingsRepository.selectedAppLanguage.value.code) {
|
||||
pendingLocalAppLanguageCode = null
|
||||
}
|
||||
}.onFailure { error ->
|
||||
log.e(error) { "pushCurrentProfileToRemote() — FAILED" }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun markAppLanguageChanged() {
|
||||
pendingLocalAppLanguageCode = ThemeSettingsRepository.selectedAppLanguage.value.code
|
||||
}
|
||||
|
||||
@OptIn(FlowPreview::class)
|
||||
private fun observeLocalChangesAndPush() {
|
||||
val signatureFlows = listOf(
|
||||
ThemeSettingsRepository.selectedTheme.map { "theme" },
|
||||
ThemeSettingsRepository.amoledEnabled.map { "amoled" },
|
||||
ThemeSettingsRepository.liquidGlassNativeTabBarEnabled.map { "liquid_glass_tab_bar" },
|
||||
ThemeSettingsRepository.selectedAppLanguage.map { "app_language" },
|
||||
PosterCardStyleRepository.uiState.map { "poster_card_style" },
|
||||
PlayerSettingsRepository.uiState.map { "player" },
|
||||
TmdbSettingsRepository.uiState.map { "tmdb" },
|
||||
|
|
@ -275,6 +289,7 @@ object ProfileSettingsSync {
|
|||
"theme=${ThemeSettingsRepository.selectedTheme.value.name}",
|
||||
"amoled=${ThemeSettingsRepository.amoledEnabled.value}",
|
||||
"liquid_glass_tab_bar=${ThemeSettingsRepository.liquidGlassNativeTabBarEnabled.value}",
|
||||
"app_language=${ThemeSettingsRepository.selectedAppLanguage.value.code}",
|
||||
"poster_card_style=${PosterCardStyleRepository.uiState.value}",
|
||||
"player=${PlayerSettingsRepository.uiState.value}",
|
||||
"tmdb=${TmdbSettingsRepository.uiState.value}",
|
||||
|
|
@ -286,6 +301,18 @@ object ProfileSettingsSync {
|
|||
"trakt_comments=${TraktCommentsSettings.enabled.value}",
|
||||
"episode_release_alerts=${EpisodeReleaseNotificationsRepository.uiState.value.isEnabled}",
|
||||
).joinToString(separator = "||")
|
||||
|
||||
private fun MobileProfileSettingsBlob.withPendingLocalAppLanguage(): MobileProfileSettingsBlob {
|
||||
val languageCode = pendingLocalAppLanguageCode ?: return this
|
||||
return copy(
|
||||
features = features.copy(
|
||||
themeSettings = buildJsonObject {
|
||||
features.themeSettings.forEach { (key, value) -> put(key, value) }
|
||||
put(APP_LANGUAGE_SYNC_KEY, encodeSyncString(languageCode))
|
||||
},
|
||||
),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@Serializable
|
||||
|
|
|
|||
|
|
@ -47,6 +47,7 @@ import androidx.compose.ui.text.font.FontWeight
|
|||
import androidx.compose.ui.unit.dp
|
||||
import androidx.compose.ui.unit.max
|
||||
import androidx.lifecycle.compose.collectAsStateWithLifecycle
|
||||
import com.nuvio.app.core.sync.ProfileSettingsSync
|
||||
import com.nuvio.app.core.ui.AppTheme
|
||||
import com.nuvio.app.core.ui.LocalNuvioBottomNavigationOverlayPadding
|
||||
import com.nuvio.app.core.ui.NuvioScreen
|
||||
|
|
@ -119,6 +120,16 @@ fun SettingsScreen(
|
|||
}.collectAsStateWithLifecycle()
|
||||
val liquidGlassNativeTabBarSupported = remember { isLiquidGlassNativeTabBarSupported() }
|
||||
val selectedAppLanguage by remember { ThemeSettingsRepository.selectedAppLanguage }.collectAsStateWithLifecycle()
|
||||
val settingsSyncScope = rememberCoroutineScope()
|
||||
val onAppLanguageSelected: (AppLanguage) -> Unit = remember(settingsSyncScope) {
|
||||
{ language ->
|
||||
ThemeSettingsRepository.setAppLanguage(language)
|
||||
ProfileSettingsSync.markAppLanguageChanged()
|
||||
settingsSyncScope.launch {
|
||||
ProfileSettingsSync.pushCurrentProfileToRemote()
|
||||
}
|
||||
}
|
||||
}
|
||||
val tmdbSettings by remember {
|
||||
TmdbSettingsRepository.ensureLoaded()
|
||||
TmdbSettingsRepository.uiState
|
||||
|
|
@ -228,7 +239,7 @@ fun SettingsScreen(
|
|||
liquidGlassNativeTabBarEnabled = liquidGlassNativeTabBarEnabled,
|
||||
onLiquidGlassNativeTabBarToggle = ThemeSettingsRepository::setLiquidGlassNativeTabBar,
|
||||
selectedAppLanguage = selectedAppLanguage,
|
||||
onAppLanguageSelected = ThemeSettingsRepository::setAppLanguage,
|
||||
onAppLanguageSelected = onAppLanguageSelected,
|
||||
episodeReleaseNotificationsUiState = episodeReleaseNotificationsUiState,
|
||||
tmdbSettings = tmdbSettings,
|
||||
mdbListSettings = mdbListSettings,
|
||||
|
|
@ -275,7 +286,7 @@ fun SettingsScreen(
|
|||
liquidGlassNativeTabBarEnabled = liquidGlassNativeTabBarEnabled,
|
||||
onLiquidGlassNativeTabBarToggle = ThemeSettingsRepository::setLiquidGlassNativeTabBar,
|
||||
selectedAppLanguage = selectedAppLanguage,
|
||||
onAppLanguageSelected = ThemeSettingsRepository::setAppLanguage,
|
||||
onAppLanguageSelected = onAppLanguageSelected,
|
||||
episodeReleaseNotificationsUiState = episodeReleaseNotificationsUiState,
|
||||
tmdbSettings = tmdbSettings,
|
||||
mdbListSettings = mdbListSettings,
|
||||
|
|
|
|||
|
|
@ -18,6 +18,7 @@ import nuvio.composeapp.generated.resources.mdblist_logo
|
|||
import nuvio.composeapp.generated.resources.rating_tmdb
|
||||
import nuvio.composeapp.generated.resources.trakt_tv_favicon
|
||||
import org.jetbrains.compose.resources.painterResource
|
||||
import java.util.Locale
|
||||
|
||||
internal actual object ThemeSettingsStorage {
|
||||
private const val preferencesName = "nuvio_theme_settings"
|
||||
|
|
@ -65,7 +66,13 @@ internal actual object ThemeSettingsStorage {
|
|||
DesktopPreferences.putString(preferencesName, selectedAppLanguageKey, languageCode)
|
||||
}
|
||||
|
||||
actual fun applySelectedAppLanguage(languageCode: String) = Unit
|
||||
actual fun applySelectedAppLanguage(languageCode: String) {
|
||||
val normalizedCode = languageCode
|
||||
.trim()
|
||||
.takeIf { it.isNotBlank() }
|
||||
?: AppLanguage.ENGLISH.code
|
||||
Locale.setDefault(Locale.forLanguageTag(normalizedCode))
|
||||
}
|
||||
|
||||
actual fun exportToSyncPayload(): JsonObject = buildJsonObject {
|
||||
loadSelectedTheme()?.let { put(selectedThemeKey, encodeSyncString(it)) }
|
||||
|
|
@ -76,7 +83,9 @@ internal actual object ThemeSettingsStorage {
|
|||
|
||||
actual fun replaceFromSyncPayload(payload: JsonObject) {
|
||||
profileScopedSyncKeys.forEach { DesktopPreferences.remove(preferencesName, ProfileScopedKey.of(it)) }
|
||||
globalSyncKeys.forEach { DesktopPreferences.remove(preferencesName, it) }
|
||||
globalSyncKeys
|
||||
.filter(payload::containsKey)
|
||||
.forEach { DesktopPreferences.remove(preferencesName, it) }
|
||||
|
||||
payload.decodeSyncString(selectedThemeKey)?.let(::saveSelectedTheme)
|
||||
payload.decodeSyncBoolean(amoledEnabledKey)?.let(::saveAmoledEnabled)
|
||||
|
|
|
|||
|
|
@ -95,7 +95,7 @@ actual object ThemeSettingsStorage {
|
|||
profileScopedSyncKeys.forEach { key ->
|
||||
NSUserDefaults.standardUserDefaults.removeObjectForKey(ProfileScopedKey.of(key))
|
||||
}
|
||||
globalSyncKeys.forEach { key ->
|
||||
globalSyncKeys.filter(payload::containsKey).forEach { key ->
|
||||
NSUserDefaults.standardUserDefaults.removeObjectForKey(key)
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue