Add Liquid Glass appearance mode for the bottom navigation bar

New opt-in Appearance toggle (default off), mirroring how amoledMode
is wired through UserProfile and both settings data sources. Enabling
it swaps the nav bar's flat fill for a translucent frosted surface
with a soft top-light gradient and a hairline glass-edge border.
This commit is contained in:
KhooLy 2026-07-19 18:59:54 +03:00
parent 7ad3aa9fac
commit 0e3d57b7a5
9 changed files with 32 additions and 1 deletions

View file

@ -173,6 +173,7 @@ class AndroidSettingsDataSource(
appearance = SettingsAppearanceUiModel(
accentColorArgb = profile.safeAccentColorArgb.toLong() and 0xffffffffL,
amoledMode = profile.safeAmoledMode,
liquidGlassMode = profile.safeLiquidGlassMode,
animationsEnabled = profile.safeAnimationsEnabled,
floatingBottomBar = profile.floatingBottomBar ?: false,
bottomBarLabels = profile.bottomBarLabels ?: false
@ -294,6 +295,7 @@ class AndroidSettingsDataSource(
accentColorArgb = value.accentColorArgb.toInt(),
amoledMode = value.amoledMode,
appTheme = if (value.amoledMode) "dark" else it.appTheme,
liquidGlassMode = value.liquidGlassMode,
animationsEnabled = value.animationsEnabled,
floatingBottomBar = value.floatingBottomBar,
bottomBarLabels = value.bottomBarLabels

View file

@ -969,6 +969,8 @@
"player.exoplayer": "ExoPlayer",
"player.mpv": "MPV",
"settings.amoled": "AMOLED",
"settings.liquid_glass": "Liquid Glass",
"settings.liquid_glass_desc": "Gives the navigation bar a frosted, translucent glass look.",
"preview.sample_title": "The Last of Us",
"integration.connected_accounts": "Trakt.tv, MAL, Simkl",
"integration.login_page_title": "%s TV - Sign In",

View file

@ -969,6 +969,8 @@
"player.exoplayer": "ExoPlayer",
"player.mpv": "MPV",
"settings.amoled": "AMOLED",
"settings.liquid_glass": "Sıvı Cam",
"settings.liquid_glass_desc": "Gezinme çubuğuna buzlu, yarı saydam bir cam görünümü verir.",
"preview.sample_title": "The Last of Us",
"integration.connected_accounts": "Trakt.tv, MAL, Simkl",
"integration.login_page_title": "%s TV - Giriş Yap",

View file

@ -114,6 +114,7 @@ data class UserProfile(
val cardCornerPreset: String? = "medium",
val interfaceDensity: String? = "medium",
val amoledMode: Boolean? = false,
val liquidGlassMode: Boolean? = false,
val posterWidthPreset: String? = "medium",
val posterLandscapeMode: Boolean? = false,
val posterHideTitles: Boolean? = false,
@ -218,6 +219,7 @@ data class UserProfile(
}
val safeUseChapterSkip: Boolean get() = useChapterSkip ?: true
val safeContentWarningsEnabled: Boolean get() = contentWarningsEnabled ?: true
val safeLiquidGlassMode: Boolean get() = liquidGlassMode ?: false
val safeDownloadSourceRegexPattern: String get() = downloadSourceRegexPattern.orEmpty()
val safeDownloadSubtitleLanguage: String get() = downloadSubtitleLanguage?.takeIf { it in setOf("off", "preferred", "tr", "en", "ja", "es", "fr", "de") } ?: "preferred"
val safeMpvCustomOptions: String get() = mpvCustomOptions.orEmpty()

View file

@ -454,6 +454,7 @@ fun FluxaApp(
destination = state.destination,
accentColorArgb = profileState?.activeProfile?.accentColorArgb,
floating = settingsState?.appearance?.floatingBottomBar == true,
liquidGlass = settingsState?.appearance?.liquidGlassMode == true,
showLabels = settingsState?.appearance?.bottomBarLabels == true,
showProfile = settingsState?.appearanceHome?.topBarEnabled == false,
profileAvatarUrl = profileState?.activeProfile?.avatarUrl,
@ -486,6 +487,7 @@ private fun FluxaNavigationBar(
destination: FluxaDestination,
accentColorArgb: Long?,
floating: Boolean,
liquidGlass: Boolean,
showLabels: Boolean,
showProfile: Boolean,
profileAvatarUrl: String?,
@ -512,7 +514,20 @@ private fun FluxaNavigationBar(
modifier = Modifier
.fillMaxWidth()
.clip(barShape)
.background(if (floating) Color(0xF2222222) else Color(0xFF111111))
.then(
if (liquidGlass) {
Modifier
.background(
Brush.verticalGradient(
listOf(Color(0x33FFFFFF), Color(0x1AFFFFFF))
)
)
.background(if (floating) Color(0x99222222) else Color(0x99111111))
.border(1.dp, Color(0x26FFFFFF), barShape)
} else {
Modifier.background(if (floating) Color(0xF2222222) else Color(0xFF111111))
}
)
.padding(horizontal = 12.dp)
.height(if (showLabels) 68.dp else 64.dp),
horizontalArrangement = Arrangement.SpaceEvenly,

View file

@ -60,6 +60,7 @@ data class SettingsGeneralUiModel(
data class SettingsAppearanceUiModel(
val accentColorArgb: Long = 0xFFFFFFFFL,
val amoledMode: Boolean = false,
val liquidGlassMode: Boolean = false,
val animationsEnabled: Boolean = true,
val floatingBottomBar: Boolean = false,
val bottomBarLabels: Boolean = false

View file

@ -652,6 +652,9 @@ private fun SettingsAppearanceContent(model: SettingsAppearanceUiModel, lang: St
}
}
SettingsToggleRow(AppStrings.t(lang, "settings.amoled"), value = model.amoledMode) { onAction(SettingsAction.AppearanceChanged(model.copy(amoledMode = it))) }
SettingsToggleRow(AppStrings.t(lang, "settings.liquid_glass"), description = AppStrings.t(lang, "settings.liquid_glass_desc"), value = model.liquidGlassMode) {
onAction(SettingsAction.AppearanceChanged(model.copy(liquidGlassMode = it)))
}
SettingsToggleRow(AppStrings.t(lang, "auto.disable_animations"), value = !model.animationsEnabled) {
onAction(SettingsAction.AppearanceChanged(model.copy(animationsEnabled = !it)))
}

View file

@ -21,6 +21,7 @@ private val SETTINGS_SEARCH_KEYS: List<Pair<String, SettingsCategory>> = listOf(
"auto.background_playback" to SettingsCategory.General,
"auto.accent_color" to SettingsCategory.Appearance,
"settings.amoled" to SettingsCategory.Appearance,
"settings.liquid_glass" to SettingsCategory.Appearance,
"auto.disable_animations" to SettingsCategory.Appearance,
"settings.appearance_home_screen" to SettingsCategory.AppearanceHome,
"auto.card_corners" to SettingsCategory.AppearanceHome,

View file

@ -41,6 +41,7 @@ class AppleSettingsDataSource : SettingsDataSource {
override suspend fun updateAppearance(value: SettingsAppearanceUiModel) {
defaults.setDouble(value.accentColorArgb.toDouble(), K.accentColorArgb)
defaults.setBool(value.amoledMode, K.amoledMode)
defaults.setBool(value.liquidGlassMode, K.liquidGlassMode)
defaults.setBool(value.animationsEnabled, K.animationsEnabled)
defaults.setBool(value.floatingBottomBar, K.floatingBottomBar)
defaults.setBool(value.bottomBarLabels, K.bottomBarLabels)
@ -223,6 +224,7 @@ class AppleSettingsDataSource : SettingsDataSource {
appearance = SettingsAppearanceUiModel(
accentColorArgb = defaults.objectForKey(K.accentColorArgb)?.let { defaults.doubleForKey(K.accentColorArgb).toLong() } ?: 0xFFFFFFFFL,
amoledMode = defaults.boolOrDefault(K.amoledMode, false),
liquidGlassMode = defaults.boolOrDefault(K.liquidGlassMode, false),
animationsEnabled = defaults.boolOrDefault(K.animationsEnabled, true),
floatingBottomBar = defaults.boolOrDefault(K.floatingBottomBar, false),
bottomBarLabels = defaults.boolOrDefault(K.bottomBarLabels, false)
@ -320,6 +322,7 @@ class AppleSettingsDataSource : SettingsDataSource {
const val backgroundPlayback = "fluxa.apple.settings.backgroundPlayback"
const val accentColorArgb = "fluxa.apple.settings.accentColorArgb"
const val amoledMode = "fluxa.apple.settings.amoledMode"
const val liquidGlassMode = "fluxa.apple.settings.liquidGlassMode"
const val animationsEnabled = "fluxa.apple.settings.animationsEnabled"
const val homeTopBarEnabled = "fluxa.apple.settings.homeTopBarEnabled"
const val floatingBottomBar = "fluxa.apple.settings.floatingBottomBar"