Merge branch 'cmp-rewrite' into desktopweb

This commit is contained in:
tapframe 2026-06-10 18:22:33 +05:30
commit 330d2537d9
4 changed files with 71 additions and 51 deletions

View file

@ -26,7 +26,6 @@ actual object ThemeSettingsStorage {
liquidGlassNativeTabBarEnabledKey,
desktopNavigationLayoutKey,
)
private val globalSyncKeys = listOf(selectedAppLanguageKey)
private var preferences: SharedPreferences? = null
@ -107,20 +106,17 @@ actual object ThemeSettingsStorage {
loadAmoledEnabled()?.let { put(amoledEnabledKey, encodeSyncBoolean(it)) }
loadLiquidGlassNativeTabBarEnabled()?.let { put(liquidGlassNativeTabBarEnabledKey, encodeSyncBoolean(it)) }
loadDesktopNavigationLayout()?.let { put(desktopNavigationLayoutKey, encodeSyncString(it)) }
loadSelectedAppLanguage()?.let { put(selectedAppLanguageKey, encodeSyncString(it)) }
}
actual fun replaceFromSyncPayload(payload: JsonObject) {
preferences?.edit()?.apply {
profileScopedSyncKeys.forEach { remove(ProfileScopedKey.of(it)) }
globalSyncKeys.forEach { remove(it) }
}?.apply()
payload.decodeSyncString(selectedThemeKey)?.let(::saveSelectedTheme)
payload.decodeSyncBoolean(amoledEnabledKey)?.let(::saveAmoledEnabled)
payload.decodeSyncBoolean(liquidGlassNativeTabBarEnabledKey)?.let(::saveLiquidGlassNativeTabBarEnabled)
payload.decodeSyncString(desktopNavigationLayoutKey)?.let(::saveDesktopNavigationLayout)
payload.decodeSyncString(selectedAppLanguageKey)?.let(::saveSelectedAppLanguage)
applySelectedAppLanguage(loadSelectedAppLanguage() ?: AppLanguage.ENGLISH.code)
}
}

View file

@ -5,9 +5,9 @@ import androidx.compose.foundation.border
import androidx.compose.foundation.clickable
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.BoxWithConstraints
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.ExperimentalLayoutApi
import androidx.compose.foundation.layout.FlowRow
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height
@ -38,6 +38,7 @@ import androidx.compose.ui.draw.clip
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.text.style.TextAlign
import androidx.compose.ui.text.style.TextOverflow
import androidx.compose.ui.unit.dp
import androidx.lifecycle.compose.collectAsStateWithLifecycle
import com.nuvio.app.isDesktop
@ -71,7 +72,6 @@ import org.jetbrains.compose.resources.stringResource
import androidx.compose.material3.ExperimentalMaterial3Api
import androidx.compose.material3.rememberModalBottomSheetState
@OptIn(ExperimentalLayoutApi::class)
internal fun LazyListScope.appearanceSettingsContent(
isTablet: Boolean,
selectedTheme: AppTheme,
@ -93,28 +93,50 @@ internal fun LazyListScope.appearanceSettingsContent(
) {
SettingsGroup(isTablet = isTablet) {
val themes = listOf(AppTheme.WHITE) + AppTheme.entries.filterNot { it == AppTheme.WHITE }
FlowRow(
val horizontalPadding = if (isTablet) 20.dp else 16.dp
val verticalPadding = if (isTablet) 18.dp else 14.dp
val themeSpacing = if (isTablet) 16.dp else 12.dp
BoxWithConstraints(
modifier = Modifier
.fillMaxWidth()
.padding(
horizontal = if (isTablet) 20.dp else 16.dp,
vertical = if (isTablet) 18.dp else 14.dp,
horizontal = horizontalPadding,
vertical = verticalPadding,
),
horizontalArrangement = Arrangement.spacedBy(if (isTablet) 16.dp else 12.dp),
verticalArrangement = Arrangement.spacedBy(if (isTablet) 16.dp else 12.dp),
) {
themes.forEach { theme ->
ThemeChip(
theme = theme,
isSelected = theme == selectedTheme,
onClick = { onThemeSelected(theme) },
)
val preferredColumns = if (isTablet) 4 else 3
val minThemeCellWidth = if (isTablet) 92.dp else 78.dp
val themeColumns = ((maxWidth + themeSpacing) / (minThemeCellWidth + themeSpacing))
.toInt()
.coerceAtLeast(1)
.coerceAtMost(preferredColumns)
Column(
verticalArrangement = Arrangement.spacedBy(themeSpacing),
) {
themes.chunked(themeColumns).forEach { rowThemes ->
Row(
modifier = Modifier.fillMaxWidth(),
horizontalArrangement = Arrangement.spacedBy(themeSpacing),
) {
rowThemes.forEach { theme ->
ThemeChip(
theme = theme,
isSelected = theme == selectedTheme,
onClick = { onThemeSelected(theme) },
modifier = Modifier.weight(1f),
)
}
repeat(themeColumns - rowThemes.size) {
Spacer(modifier = Modifier.weight(1f))
}
}
}
}
}
}
}
}
item {
var showLanguageSheet by remember { mutableStateOf(false) }
var showDesktopNavigationSheet by remember { mutableStateOf(false) }
@ -352,41 +374,48 @@ private fun ThemeChip(
theme: AppTheme,
isSelected: Boolean,
onClick: () -> Unit,
modifier: Modifier = Modifier,
) {
val palette = ThemeColors.getColorPalette(theme)
Column(
modifier = Modifier
modifier = modifier
.clip(RoundedCornerShape(12.dp))
.clickable(onClick = onClick)
.then(
if (isSelected) {
Modifier.border(
width = 1.5.dp,
color = palette.focusRing,
shape = RoundedCornerShape(12.dp),
)
} else {
Modifier
},
)
.padding(horizontal = 12.dp, vertical = 10.dp),
.padding(horizontal = 4.dp, vertical = 8.dp),
horizontalAlignment = Alignment.CenterHorizontally,
) {
Box(
modifier = Modifier
.size(44.dp)
.clip(CircleShape)
.background(palette.secondary),
.size(56.dp)
.then(
if (isSelected) {
Modifier.border(
width = 1.5.dp,
color = palette.focusRing,
shape = RoundedCornerShape(14.dp),
)
} else {
Modifier
},
),
contentAlignment = Alignment.Center,
) {
if (isSelected) {
Icon(
imageVector = Icons.Default.Check,
contentDescription = stringResource(Res.string.cd_selected),
tint = palette.onSecondary,
modifier = Modifier.size(22.dp),
)
Box(
modifier = Modifier
.size(44.dp)
.clip(CircleShape)
.background(palette.secondary),
contentAlignment = Alignment.Center,
) {
if (isSelected) {
Icon(
imageVector = Icons.Default.Check,
contentDescription = stringResource(Res.string.cd_selected),
tint = palette.onSecondary,
modifier = Modifier.size(22.dp),
)
}
}
}
@ -402,6 +431,9 @@ private fun ThemeChip(
},
fontWeight = if (isSelected) FontWeight.SemiBold else FontWeight.Medium,
textAlign = TextAlign.Center,
maxLines = 2,
overflow = TextOverflow.Ellipsis,
modifier = Modifier.fillMaxWidth(),
)
Spacer(modifier = Modifier.height(4.dp))

View file

@ -70,16 +70,14 @@ internal actual object ThemeSettingsStorage {
loadAmoledEnabled()?.let { put(amoledEnabledKey, encodeSyncBoolean(it)) }
loadLiquidGlassNativeTabBarEnabled()?.let { put(liquidGlassNativeTabBarEnabledKey, encodeSyncBoolean(it)) }
loadDesktopNavigationLayout()?.let { put(desktopNavigationLayoutKey, encodeSyncString(it)) }
loadSelectedAppLanguage()?.let { put(selectedAppLanguageKey, encodeSyncString(it)) }
}
actual fun replaceFromSyncPayload(payload: JsonObject) {
store.removeAll(profileScopedSyncKeys.map(ProfileScopedKey::of) + selectedAppLanguageKey)
store.removeAll(profileScopedSyncKeys.map(ProfileScopedKey::of))
payload.decodeSyncString(selectedThemeKey)?.let(::saveSelectedTheme)
payload.decodeSyncBoolean(amoledEnabledKey)?.let(::saveAmoledEnabled)
payload.decodeSyncBoolean(liquidGlassNativeTabBarEnabledKey)?.let(::saveLiquidGlassNativeTabBarEnabled)
payload.decodeSyncString(desktopNavigationLayoutKey)?.let(::saveDesktopNavigationLayout)
payload.decodeSyncString(selectedAppLanguageKey)?.let(::saveSelectedAppLanguage)
applySelectedAppLanguage(loadSelectedAppLanguage() ?: AppLanguage.ENGLISH.code)
}
}

View file

@ -22,7 +22,6 @@ actual object ThemeSettingsStorage {
liquidGlassNativeTabBarEnabledKey,
desktopNavigationLayoutKey,
)
private val globalSyncKeys = listOf(selectedAppLanguageKey)
actual fun loadSelectedTheme(): String? =
NSUserDefaults.standardUserDefaults.stringForKey(ProfileScopedKey.of(selectedThemeKey))
@ -101,22 +100,17 @@ actual object ThemeSettingsStorage {
loadAmoledEnabled()?.let { put(amoledEnabledKey, encodeSyncBoolean(it)) }
loadLiquidGlassNativeTabBarEnabled()?.let { put(liquidGlassNativeTabBarEnabledKey, encodeSyncBoolean(it)) }
loadDesktopNavigationLayout()?.let { put(desktopNavigationLayoutKey, encodeSyncString(it)) }
loadSelectedAppLanguage()?.let { put(selectedAppLanguageKey, encodeSyncString(it)) }
}
actual fun replaceFromSyncPayload(payload: JsonObject) {
profileScopedSyncKeys.forEach { key ->
NSUserDefaults.standardUserDefaults.removeObjectForKey(ProfileScopedKey.of(key))
}
globalSyncKeys.forEach { key ->
NSUserDefaults.standardUserDefaults.removeObjectForKey(key)
}
payload.decodeSyncString(selectedThemeKey)?.let(::saveSelectedTheme)
payload.decodeSyncBoolean(amoledEnabledKey)?.let(::saveAmoledEnabled)
payload.decodeSyncBoolean(liquidGlassNativeTabBarEnabledKey)?.let(::saveLiquidGlassNativeTabBarEnabled)
payload.decodeSyncString(desktopNavigationLayoutKey)?.let(::saveDesktopNavigationLayout)
payload.decodeSyncString(selectedAppLanguageKey)?.let(::saveSelectedAppLanguage)
applySelectedAppLanguage(loadSelectedAppLanguage() ?: AppLanguage.ENGLISH.code)
}
}