mirror of
https://github.com/FluxaMedia/fluxa.git
synced 2026-08-18 21:18:32 +00:00
Refine mobile navigation and poster actions
This commit is contained in:
parent
909425202a
commit
62d20e23c4
20 changed files with 293 additions and 144 deletions
|
|
@ -173,9 +173,12 @@ class AndroidSettingsDataSource(
|
|||
appearance = SettingsAppearanceUiModel(
|
||||
accentColorArgb = profile.safeAccentColorArgb.toLong() and 0xffffffffL,
|
||||
amoledMode = profile.safeAmoledMode,
|
||||
animationsEnabled = profile.safeAnimationsEnabled
|
||||
animationsEnabled = profile.safeAnimationsEnabled,
|
||||
floatingBottomBar = profile.floatingBottomBar ?: false,
|
||||
bottomBarLabels = profile.bottomBarLabels ?: false
|
||||
),
|
||||
appearanceHome = SettingsAppearanceHomeUiModel(
|
||||
topBarEnabled = profile.homeTopBarEnabled ?: true,
|
||||
cardCornerPreset = profile.safeCardCornerPreset,
|
||||
interfaceDensity = profile.safeInterfaceDensity,
|
||||
posterWidthPreset = profile.safePosterWidthPreset,
|
||||
|
|
@ -290,12 +293,15 @@ class AndroidSettingsDataSource(
|
|||
accentColorArgb = value.accentColorArgb.toInt(),
|
||||
amoledMode = value.amoledMode,
|
||||
appTheme = if (value.amoledMode) "dark" else it.appTheme,
|
||||
animationsEnabled = value.animationsEnabled
|
||||
animationsEnabled = value.animationsEnabled,
|
||||
floatingBottomBar = value.floatingBottomBar,
|
||||
bottomBarLabels = value.bottomBarLabels
|
||||
)
|
||||
}
|
||||
|
||||
override suspend fun updateAppearanceHome(value: SettingsAppearanceHomeUiModel) = update {
|
||||
it.copy(
|
||||
homeTopBarEnabled = value.topBarEnabled,
|
||||
cardCornerPreset = value.cardCornerPreset,
|
||||
interfaceDensity = value.interfaceDensity,
|
||||
posterWidthPreset = value.posterWidthPreset,
|
||||
|
|
|
|||
|
|
@ -485,6 +485,12 @@ class HomeViewModel @Inject constructor(
|
|||
}
|
||||
}
|
||||
|
||||
fun addToWatchlist(meta: Meta) {
|
||||
viewModelScope.launch {
|
||||
if (!watchlistManager.isInWatchlist(meta.id)) toggleWatchlist(meta)
|
||||
}
|
||||
}
|
||||
|
||||
fun toggleBillboardWatchlist() {
|
||||
val movie = billboardState.movieValue ?: return
|
||||
viewModelScope.launch {
|
||||
|
|
|
|||
|
|
@ -133,6 +133,11 @@ internal fun AppRoutesHost(
|
|||
.resolveMeta(action.item.id, action.item.type)
|
||||
?.let(homeViewModel::forgetPlaybackProgress)
|
||||
}
|
||||
is com.fluxa.app.shared.feature.catalog.CatalogAction.AddToLibraryRequested -> {
|
||||
androidFluxaPlatformServices!!.catalogHomeDataSource
|
||||
.resolveMeta(action.item.id, action.item.type)
|
||||
?.let(homeViewModel::addToWatchlist)
|
||||
}
|
||||
else -> Unit
|
||||
}
|
||||
},
|
||||
|
|
|
|||
|
|
@ -1091,5 +1091,12 @@
|
|||
"settings.season_posters_on_hero": "Season Posters on Hero",
|
||||
"settings.detail_season_posters_on_hero_desc": "Use season posters in the detail page hero.",
|
||||
"settings.home_season_posters_on_hero_desc": "Use season posters in the home hero banner.",
|
||||
"format.season_short": "S%s"
|
||||
"format.season_short": "S%s",
|
||||
"settings.floating_bottom_bar": "Floating bottom bar",
|
||||
"settings.floating_bottom_bar_desc": "Lift the navigation bar above the bottom edge.",
|
||||
"settings.bottom_bar_labels": "Show bottom bar labels",
|
||||
"settings.bottom_bar_labels_desc": "Display destination names below navigation icons.",
|
||||
"settings.home_top_bar": "Home top bar",
|
||||
"settings.home_top_bar_desc": "Show Home, Series, Movies, notifications, and profile above the hero.",
|
||||
"common.add_to_library": "Add to Library"
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1091,5 +1091,12 @@
|
|||
"settings.season_posters_on_hero": "Hero'da Sezon Afişleri",
|
||||
"settings.detail_season_posters_on_hero_desc": "Detay sayfası hero alanında sezon afişlerini kullanır.",
|
||||
"settings.home_season_posters_on_hero_desc": "Ana sayfa hero bannerında sezon afişlerini kullanır.",
|
||||
"format.season_short": "S%s"
|
||||
"format.season_short": "S%s",
|
||||
"settings.floating_bottom_bar": "Yüzen alt çubuk",
|
||||
"settings.floating_bottom_bar_desc": "Gezinme çubuğunu alt kenarın üzerinde gösterir.",
|
||||
"settings.bottom_bar_labels": "Alt çubuk etiketlerini göster",
|
||||
"settings.bottom_bar_labels_desc": "Gezinme simgelerinin altında hedef adlarını gösterir.",
|
||||
"settings.home_top_bar": "Ana sayfa üst çubuğu",
|
||||
"settings.home_top_bar_desc": "Hero alanının üzerinde Ana Sayfa, Diziler, Filmler, bildirimler ve profili gösterir.",
|
||||
"common.add_to_library": "Kitaplığa ekle"
|
||||
}
|
||||
|
|
|
|||
|
|
@ -121,6 +121,9 @@ data class UserProfile(
|
|||
val detailSeasonPostersOnHero: Boolean? = true,
|
||||
val homeSeasonPostersOnHero: Boolean? = true,
|
||||
val animationsEnabled: Boolean? = true,
|
||||
val floatingBottomBar: Boolean? = false,
|
||||
val bottomBarLabels: Boolean? = false,
|
||||
val homeTopBarEnabled: Boolean? = true,
|
||||
val reduceMotion: Boolean? = false,
|
||||
val gifAutoplayEnabled: Boolean? = true,
|
||||
val startPage: String? = "home",
|
||||
|
|
|
|||
|
|
@ -2,16 +2,14 @@ package com.fluxa.app.shared
|
|||
|
||||
import androidx.compose.animation.AnimatedContent
|
||||
import androidx.compose.animation.animateColorAsState
|
||||
import androidx.compose.animation.core.Spring
|
||||
import androidx.compose.animation.core.animateDpAsState
|
||||
import androidx.compose.animation.core.animateFloatAsState
|
||||
import androidx.compose.animation.core.spring
|
||||
import androidx.compose.animation.core.tween
|
||||
import androidx.compose.animation.fadeIn
|
||||
import androidx.compose.animation.fadeOut
|
||||
import androidx.compose.animation.scaleIn
|
||||
import androidx.compose.animation.togetherWith
|
||||
import androidx.compose.foundation.background
|
||||
import androidx.compose.foundation.border
|
||||
import androidx.compose.foundation.clickable
|
||||
import androidx.compose.foundation.layout.Arrangement
|
||||
import androidx.compose.foundation.layout.Box
|
||||
|
|
@ -42,6 +40,7 @@ import androidx.compose.foundation.shape.CircleShape
|
|||
import androidx.compose.foundation.shape.RoundedCornerShape
|
||||
import androidx.compose.material.icons.Icons
|
||||
import androidx.compose.material.icons.automirrored.filled.ArrowForward
|
||||
import androidx.compose.material.icons.rounded.PlayArrow
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.material3.darkColorScheme
|
||||
import androidx.compose.material3.CircularProgressIndicator
|
||||
|
|
@ -60,7 +59,6 @@ import androidx.compose.ui.Modifier
|
|||
import androidx.compose.ui.draw.clip
|
||||
import androidx.compose.ui.graphics.Brush
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.graphics.graphicsLayer
|
||||
import androidx.compose.ui.graphics.vector.ImageVector
|
||||
import androidx.compose.ui.layout.ContentScale
|
||||
import androidx.compose.ui.layout.onGloballyPositioned
|
||||
|
|
@ -121,6 +119,7 @@ import com.fluxa.app.shared.feature.player.PlayerRenderAction
|
|||
import com.fluxa.app.shared.feature.player.PlayerRenderState
|
||||
import com.fluxa.app.ui.catalog.CatalogCard
|
||||
import com.fluxa.app.ui.catalog.FluxaColors
|
||||
import com.fluxa.app.ui.catalog.PosterActionSheet
|
||||
|
||||
private val FluxaColorScheme = darkColorScheme(
|
||||
background = FluxaColors.background,
|
||||
|
|
@ -318,6 +317,7 @@ fun FluxaApp(
|
|||
language = state.language,
|
||||
onQueryChanged = { value -> onSearchAction(SearchAction.QueryChanged(value)) },
|
||||
onItemSelected = { item -> onSearchAction(SearchAction.ItemSelected(item)) },
|
||||
onAddToLibrary = { item -> onCatalogAction(CatalogAction.AddToLibraryRequested(item)) },
|
||||
onClearHistory = { onSearchAction(SearchAction.ClearHistory) },
|
||||
modifier = Modifier.fillMaxSize()
|
||||
)
|
||||
|
|
@ -326,6 +326,7 @@ fun FluxaApp(
|
|||
language = state.language,
|
||||
onQueryChanged = { value -> onSearchAction(SearchAction.QueryChanged(value)) },
|
||||
onItemSelected = { item -> onSearchAction(SearchAction.ItemSelected(item)) },
|
||||
onAddToLibrary = { item -> onCatalogAction(CatalogAction.AddToLibraryRequested(item)) },
|
||||
onClearHistory = { onSearchAction(SearchAction.ClearHistory) },
|
||||
modifier = Modifier.fillMaxSize()
|
||||
)
|
||||
|
|
@ -438,6 +439,7 @@ fun FluxaApp(
|
|||
onAvatarClick = { onDestinationSelected(FluxaDestination.Settings) },
|
||||
onCategorySelected = onCategorySelected,
|
||||
profileAvatarUrl = profileState?.activeProfile?.avatarUrl,
|
||||
topBarEnabled = settingsState?.appearanceHome?.topBarEnabled != false,
|
||||
modifier = Modifier.fillMaxSize()
|
||||
)
|
||||
else -> FluxaDestinationPlaceholder(
|
||||
|
|
@ -452,6 +454,10 @@ fun FluxaApp(
|
|||
FluxaNavigationBar(
|
||||
destination = state.destination,
|
||||
accentColorArgb = profileState?.activeProfile?.accentColorArgb,
|
||||
floating = settingsState?.appearance?.floatingBottomBar == true,
|
||||
showLabels = settingsState?.appearance?.bottomBarLabels == true,
|
||||
showProfile = settingsState?.appearanceHome?.topBarEnabled == false,
|
||||
profileAvatarUrl = profileState?.activeProfile?.avatarUrl,
|
||||
language = state.language,
|
||||
calendarState = calendarState,
|
||||
onDestinationSelected = onDestinationSelected,
|
||||
|
|
@ -491,6 +497,10 @@ private fun CalendarUiState.hasUnseenReleases(): Boolean {
|
|||
private fun FluxaNavigationBar(
|
||||
destination: FluxaDestination,
|
||||
accentColorArgb: Long?,
|
||||
floating: Boolean,
|
||||
showLabels: Boolean,
|
||||
showProfile: Boolean,
|
||||
profileAvatarUrl: String?,
|
||||
language: String?,
|
||||
calendarState: CalendarUiState?,
|
||||
onDestinationSelected: (FluxaDestination) -> Unit,
|
||||
|
|
@ -499,62 +509,70 @@ private fun FluxaNavigationBar(
|
|||
val selectedColor = accentColorArgb?.let { Color(it) } ?: Color.White
|
||||
val inactiveColor = Color(0xFFA0A5AD)
|
||||
val hasCalendarBadge = calendarState?.hasUnseenReleases() == true
|
||||
Column(
|
||||
val barShape = RoundedCornerShape(if (floating) 28.dp else 0.dp)
|
||||
val items = if (showProfile) {
|
||||
FluxaBottomNavItems + FluxaBottomNavItem(FluxaDestination.Settings, FluxaIcons.BottomSettings, FluxaIcons.BottomSettingsOutline)
|
||||
} else {
|
||||
FluxaBottomNavItems
|
||||
}
|
||||
Box(
|
||||
modifier = modifier
|
||||
.fillMaxWidth()
|
||||
.background(
|
||||
Brush.verticalGradient(
|
||||
colorStops = arrayOf(
|
||||
0f to FluxaColors.background.copy(alpha = 0f),
|
||||
0.4f to FluxaColors.background
|
||||
)
|
||||
)
|
||||
)
|
||||
.windowInsetsPadding(WindowInsets.safeDrawing.only(WindowInsetsSides.Bottom))
|
||||
.padding(horizontal = if (floating) 12.dp else 0.dp)
|
||||
.padding(bottom = if (floating) 10.dp else 0.dp)
|
||||
) {
|
||||
Box(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.height(1.dp)
|
||||
.background(Color.White.copy(alpha = 0.08f))
|
||||
)
|
||||
Row(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.windowInsetsPadding(WindowInsets.safeDrawing.only(WindowInsetsSides.Bottom))
|
||||
.clip(barShape)
|
||||
.background(if (floating) Color(0xF2222222) else Color(0xFF111111))
|
||||
.padding(horizontal = 12.dp)
|
||||
.padding(top = 10.dp, bottom = 10.dp),
|
||||
.height(if (showLabels) 68.dp else 64.dp),
|
||||
horizontalArrangement = Arrangement.SpaceEvenly,
|
||||
verticalAlignment = Alignment.CenterVertically
|
||||
) {
|
||||
FluxaBottomNavItems.forEach { item ->
|
||||
items.forEach { item ->
|
||||
val isSelected = item.destination == destination
|
||||
val tint by animateColorAsState(
|
||||
targetValue = if (isSelected) selectedColor else inactiveColor,
|
||||
label = "nav-item-tint"
|
||||
)
|
||||
val scale by animateFloatAsState(
|
||||
targetValue = if (isSelected) 1.1f else 1f,
|
||||
animationSpec = spring(dampingRatio = Spring.DampingRatioMediumBouncy, stiffness = Spring.StiffnessMedium),
|
||||
label = "nav-item-scale"
|
||||
)
|
||||
Column(
|
||||
modifier = Modifier
|
||||
.weight(1f)
|
||||
.clip(RoundedCornerShape(14.dp))
|
||||
.clip(RoundedCornerShape(18.dp))
|
||||
.clickable { onDestinationSelected(item.destination) }
|
||||
.padding(vertical = 4.dp),
|
||||
.padding(vertical = 8.dp),
|
||||
horizontalAlignment = Alignment.CenterHorizontally,
|
||||
verticalArrangement = Arrangement.spacedBy(2.dp)
|
||||
) {
|
||||
Box {
|
||||
Icon(
|
||||
if (isSelected) item.selectedIcon else item.icon,
|
||||
contentDescription = null,
|
||||
tint = tint,
|
||||
modifier = Modifier
|
||||
.size(24.dp)
|
||||
.graphicsLayer(scaleX = scale, scaleY = scale)
|
||||
)
|
||||
if (item.destination == FluxaDestination.Settings && !profileAvatarUrl.isNullOrBlank()) {
|
||||
FluxaRemoteImage(
|
||||
imageUrl = profileAvatarUrl,
|
||||
cacheKey = "bottom-profile:$profileAvatarUrl",
|
||||
contentDescription = null,
|
||||
modifier = Modifier
|
||||
.size(32.dp)
|
||||
.then(
|
||||
if (isSelected) {
|
||||
Modifier.border(2.dp, tint, CircleShape).padding(2.dp)
|
||||
} else {
|
||||
Modifier
|
||||
}
|
||||
)
|
||||
.clip(CircleShape),
|
||||
contentScale = ContentScale.Crop
|
||||
)
|
||||
} else {
|
||||
Icon(
|
||||
if (isSelected) item.selectedIcon else item.icon,
|
||||
contentDescription = null,
|
||||
tint = tint,
|
||||
modifier = Modifier.size(29.dp)
|
||||
)
|
||||
}
|
||||
if (item.showsCalendarBadge && hasCalendarBadge) {
|
||||
Box(
|
||||
modifier = Modifier
|
||||
|
|
@ -566,13 +584,15 @@ private fun FluxaNavigationBar(
|
|||
)
|
||||
}
|
||||
}
|
||||
Text(
|
||||
text = AppStrings.t(language, item.destination.titleKey),
|
||||
color = tint,
|
||||
fontSize = 11.sp,
|
||||
maxLines = 1,
|
||||
overflow = TextOverflow.Ellipsis
|
||||
)
|
||||
if (showLabels) {
|
||||
Text(
|
||||
text = AppStrings.t(language, item.destination.titleKey),
|
||||
color = tint,
|
||||
fontSize = 10.sp,
|
||||
maxLines = 1,
|
||||
overflow = TextOverflow.Ellipsis
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -668,6 +688,7 @@ private fun FluxaHomeContent(
|
|||
onAvatarClick: () -> Unit,
|
||||
onCategorySelected: (id: String, title: String) -> Unit,
|
||||
profileAvatarUrl: String?,
|
||||
topBarEnabled: Boolean,
|
||||
modifier: Modifier
|
||||
) {
|
||||
if (state.catalogHome.isLoading && state.catalogHome.rows.isEmpty()) {
|
||||
|
|
@ -688,7 +709,7 @@ private fun FluxaHomeContent(
|
|||
val showHero = state.catalogHome.showHeroSection && heroItems.isNotEmpty()
|
||||
val listState = rememberLazyListState()
|
||||
var heroHeightPx by remember { mutableIntStateOf(0) }
|
||||
var continueWatchingActionItem by remember { mutableStateOf<CatalogItemUiModel?>(null) }
|
||||
var posterActionItem by remember { mutableStateOf<CatalogItemUiModel?>(null) }
|
||||
val scrimAlpha by remember {
|
||||
androidx.compose.runtime.derivedStateOf {
|
||||
when {
|
||||
|
|
@ -777,18 +798,14 @@ private fun FluxaHomeContent(
|
|||
CatalogCard(
|
||||
model = item.card,
|
||||
onClick = { onCatalogAction(CatalogAction.ItemSelected(item)) },
|
||||
onLongClick = if (row.categoryType == "continue_watching") {
|
||||
{ continueWatchingActionItem = item }
|
||||
} else {
|
||||
null
|
||||
}
|
||||
onLongClick = { posterActionItem = item }
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (showHero) {
|
||||
if (showHero && topBarEnabled) {
|
||||
FluxaHomeOverlayBar(
|
||||
activeFilter = state.catalogHome.activeFilter,
|
||||
language = state.language,
|
||||
|
|
@ -802,72 +819,19 @@ private fun FluxaHomeContent(
|
|||
}
|
||||
}
|
||||
|
||||
continueWatchingActionItem?.let { item ->
|
||||
ContinueWatchingActionSheet(
|
||||
posterActionItem?.let { item ->
|
||||
PosterActionSheet(
|
||||
item = item,
|
||||
language = state.language,
|
||||
onDismiss = { continueWatchingActionItem = null },
|
||||
onPlayManually = {
|
||||
continueWatchingActionItem = null
|
||||
onCatalogAction(CatalogAction.PlayRequested(item))
|
||||
},
|
||||
onDetails = {
|
||||
continueWatchingActionItem = null
|
||||
onCatalogAction(CatalogAction.ItemSelected(item))
|
||||
},
|
||||
onMarkWatched = {
|
||||
continueWatchingActionItem = null
|
||||
onCatalogAction(CatalogAction.MarkWatchedRequested(item))
|
||||
},
|
||||
onDrop = {
|
||||
continueWatchingActionItem = null
|
||||
onCatalogAction(CatalogAction.DropRequested(item))
|
||||
onDismiss = { posterActionItem = null },
|
||||
onAddToLibrary = {
|
||||
posterActionItem = null
|
||||
onCatalogAction(CatalogAction.AddToLibraryRequested(item))
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@OptIn(androidx.compose.material3.ExperimentalMaterial3Api::class)
|
||||
@Composable
|
||||
private fun ContinueWatchingActionSheet(
|
||||
language: String?,
|
||||
onDismiss: () -> Unit,
|
||||
onPlayManually: () -> Unit,
|
||||
onDetails: () -> Unit,
|
||||
onMarkWatched: () -> Unit,
|
||||
onDrop: () -> Unit
|
||||
) {
|
||||
val sheetState = androidx.compose.material3.rememberModalBottomSheetState(skipPartiallyExpanded = true)
|
||||
androidx.compose.material3.ModalBottomSheet(
|
||||
onDismissRequest = onDismiss,
|
||||
sheetState = sheetState,
|
||||
containerColor = FluxaColors.surfaceRaised
|
||||
) {
|
||||
Column(modifier = Modifier.padding(bottom = 24.dp)) {
|
||||
ContinueWatchingActionRow(AppStrings.t(language, "home.play_manually"), onPlayManually)
|
||||
ContinueWatchingActionRow(AppStrings.t(language, "home.view_details"), onDetails)
|
||||
ContinueWatchingActionRow(AppStrings.t(language, "detail.mark_watched"), onMarkWatched)
|
||||
ContinueWatchingActionRow(AppStrings.t(language, "home.forget_progress"), onDrop)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun ContinueWatchingActionRow(label: String, onClick: () -> Unit) {
|
||||
Row(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.clickable(onClick = onClick)
|
||||
.padding(horizontal = 20.dp, vertical = 14.dp),
|
||||
verticalAlignment = Alignment.CenterVertically
|
||||
) {
|
||||
Text(
|
||||
text = label,
|
||||
color = Color.White,
|
||||
fontSize = 15.sp
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun FluxaHomeSkeleton(modifier: Modifier = Modifier) {
|
||||
LazyColumn(
|
||||
|
|
@ -1053,26 +1017,27 @@ private fun FluxaHomeHeroSlide(
|
|||
}
|
||||
Row(
|
||||
modifier = Modifier
|
||||
.padding(top = 4.dp)
|
||||
.clip(RoundedCornerShape(8.dp))
|
||||
.padding(top = 6.dp)
|
||||
.height(48.dp)
|
||||
.clip(RoundedCornerShape(14.dp))
|
||||
.background(Color.White)
|
||||
.clickable { onCatalogAction(CatalogAction.PlayRequested(item)) }
|
||||
.padding(horizontal = 20.dp, vertical = 10.dp),
|
||||
.padding(horizontal = 24.dp),
|
||||
horizontalArrangement = Arrangement.Center,
|
||||
verticalAlignment = Alignment.CenterVertically
|
||||
) {
|
||||
Icon(
|
||||
imageVector = FluxaIcons.PlayArrow,
|
||||
imageVector = Icons.Rounded.PlayArrow,
|
||||
contentDescription = null,
|
||||
tint = Color.Black,
|
||||
modifier = Modifier.size(18.dp)
|
||||
modifier = Modifier.size(26.dp)
|
||||
)
|
||||
Text(
|
||||
text = AppStrings.t(language, "common.play"),
|
||||
color = Color.Black,
|
||||
fontWeight = FontWeight.Bold,
|
||||
fontSize = 14.sp,
|
||||
modifier = Modifier.padding(start = 6.dp)
|
||||
fontWeight = FontWeight.ExtraBold,
|
||||
fontSize = 15.sp,
|
||||
modifier = Modifier.padding(start = 7.dp)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -445,7 +445,6 @@ fun FluxaAppHost(
|
|||
SettingsAction.ConnectSimklRequested -> onConnectSimklRequested()
|
||||
SettingsAction.ConnectAnilistRequested -> onConnectAnilistRequested()
|
||||
SettingsAction.CheckForUpdateRequested -> onCheckForUpdateRequested()
|
||||
SettingsAction.ManageDownloadsRequested -> appState.openLibraryDownloads()
|
||||
else -> scope.launch { settingsStore?.dispatch(action) }
|
||||
}
|
||||
},
|
||||
|
|
|
|||
|
|
@ -66,6 +66,7 @@ sealed interface CatalogAction {
|
|||
data class FilterChanged(val filter: String) : CatalogAction
|
||||
data class MarkWatchedRequested(val item: CatalogItemUiModel) : CatalogAction
|
||||
data class DropRequested(val item: CatalogItemUiModel) : CatalogAction
|
||||
data class AddToLibraryRequested(val item: CatalogItemUiModel) : CatalogAction
|
||||
}
|
||||
|
||||
interface CatalogHomeDataSource {
|
||||
|
|
|
|||
|
|
@ -22,7 +22,8 @@ class CatalogHomeStore(
|
|||
is CatalogAction.ResumeRequested,
|
||||
is CatalogAction.ItemFocused,
|
||||
is CatalogAction.MarkWatchedRequested,
|
||||
is CatalogAction.DropRequested -> Unit
|
||||
is CatalogAction.DropRequested,
|
||||
is CatalogAction.AddToLibraryRequested -> Unit
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -28,6 +28,7 @@ import androidx.compose.material.icons.filled.Download
|
|||
import androidx.compose.material.icons.filled.PlayArrow
|
||||
import androidx.compose.material.icons.filled.Refresh
|
||||
import androidx.compose.material.icons.filled.Share
|
||||
import androidx.compose.material.icons.rounded.PlayArrow
|
||||
import androidx.compose.material3.CircularProgressIndicator
|
||||
import androidx.compose.material3.Icon
|
||||
import androidx.compose.material3.Text
|
||||
|
|
@ -284,17 +285,24 @@ private fun ResumeButton(content: DetailUiModel, language: String?, onAction: (D
|
|||
horizontalAlignment = Alignment.CenterHorizontally,
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.clip(RoundedCornerShape(6.dp))
|
||||
.background(Color(0xFFE0E0E0))
|
||||
.height(54.dp)
|
||||
.clip(RoundedCornerShape(14.dp))
|
||||
.background(Color.White)
|
||||
.clickable { onAction(DetailAction.Play()) }
|
||||
.padding(horizontal = 16.dp, vertical = 12.dp)
|
||||
.padding(horizontal = 18.dp),
|
||||
verticalArrangement = Arrangement.Center
|
||||
) {
|
||||
Row(verticalAlignment = Alignment.CenterVertically) {
|
||||
Icon(Icons.Filled.PlayArrow, contentDescription = null, tint = Color.Black, modifier = Modifier.size(20.dp))
|
||||
Icon(
|
||||
Icons.Rounded.PlayArrow,
|
||||
contentDescription = null,
|
||||
tint = Color.Black,
|
||||
modifier = Modifier.size(27.dp)
|
||||
)
|
||||
Text(
|
||||
text = label,
|
||||
color = Color.Black,
|
||||
fontWeight = FontWeight.Bold,
|
||||
fontWeight = FontWeight.ExtraBold,
|
||||
fontSize = 16.sp,
|
||||
modifier = Modifier.padding(start = 8.dp)
|
||||
)
|
||||
|
|
|
|||
|
|
@ -19,6 +19,10 @@ import androidx.compose.foundation.lazy.grid.items as gridItems
|
|||
import androidx.compose.material3.OutlinedTextField
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.runtime.mutableStateOf
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.runtime.setValue
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.graphics.Color
|
||||
|
|
@ -32,6 +36,7 @@ import com.fluxa.app.shared.feature.catalog.CatalogRowUiModel
|
|||
import com.fluxa.app.shared.skeletonShimmer
|
||||
import com.fluxa.app.ui.catalog.CatalogCard
|
||||
import com.fluxa.app.ui.catalog.FluxaColors
|
||||
import com.fluxa.app.ui.catalog.PosterActionSheet
|
||||
|
||||
@Composable
|
||||
fun SearchScreen(
|
||||
|
|
@ -39,9 +44,11 @@ fun SearchScreen(
|
|||
language: String?,
|
||||
onQueryChanged: (String) -> Unit,
|
||||
onItemSelected: (CatalogItemUiModel) -> Unit,
|
||||
onAddToLibrary: (CatalogItemUiModel) -> Unit = {},
|
||||
onClearHistory: () -> Unit = {},
|
||||
modifier: Modifier = Modifier
|
||||
) {
|
||||
var actionItem by remember { mutableStateOf<CatalogItemUiModel?>(null) }
|
||||
Column(
|
||||
modifier = modifier
|
||||
.fillMaxSize()
|
||||
|
|
@ -61,11 +68,13 @@ fun SearchScreen(
|
|||
state.resultRows.isNotEmpty() -> SearchResultRows(
|
||||
rows = state.resultRows,
|
||||
onItemSelected = onItemSelected,
|
||||
onItemLongPressed = { actionItem = it },
|
||||
modifier = Modifier.weight(1f)
|
||||
)
|
||||
state.results.isNotEmpty() -> SearchResults(
|
||||
items = state.results,
|
||||
onItemSelected = onItemSelected,
|
||||
onItemLongPressed = { actionItem = it },
|
||||
modifier = Modifier.weight(1f)
|
||||
)
|
||||
state.isLoading -> SearchSkeletonGrid(modifier = Modifier.weight(1f))
|
||||
|
|
@ -74,6 +83,7 @@ fun SearchScreen(
|
|||
language = language,
|
||||
recentItems = state.recentItems,
|
||||
onItemSelected = onItemSelected,
|
||||
onItemLongPressed = { actionItem = it },
|
||||
modifier = Modifier.weight(1f)
|
||||
)
|
||||
state.recentItems.isNotEmpty() -> SearchHistory(
|
||||
|
|
@ -81,6 +91,7 @@ fun SearchScreen(
|
|||
clearLabel = AppStrings.t(language, "auto.clear_search"),
|
||||
items = state.recentItems,
|
||||
onItemSelected = onItemSelected,
|
||||
onItemLongPressed = { actionItem = it },
|
||||
onClearHistory = onClearHistory,
|
||||
modifier = Modifier.weight(1f)
|
||||
)
|
||||
|
|
@ -90,6 +101,17 @@ fun SearchScreen(
|
|||
)
|
||||
}
|
||||
}
|
||||
actionItem?.let { item ->
|
||||
PosterActionSheet(
|
||||
item = item,
|
||||
language = language,
|
||||
onDismiss = { actionItem = null },
|
||||
onAddToLibrary = {
|
||||
actionItem = null
|
||||
onAddToLibrary(item)
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
|
|
@ -98,6 +120,7 @@ private fun SearchNoResultsForQuery(
|
|||
language: String?,
|
||||
recentItems: List<CatalogItemUiModel>,
|
||||
onItemSelected: (CatalogItemUiModel) -> Unit,
|
||||
onItemLongPressed: (CatalogItemUiModel) -> Unit = {},
|
||||
modifier: Modifier
|
||||
) {
|
||||
Column(modifier = modifier.fillMaxSize()) {
|
||||
|
|
@ -111,6 +134,7 @@ private fun SearchNoResultsForQuery(
|
|||
SearchResults(
|
||||
items = recentItems.take(5),
|
||||
onItemSelected = onItemSelected,
|
||||
onItemLongPressed = onItemLongPressed,
|
||||
modifier = Modifier.fillMaxSize()
|
||||
)
|
||||
}
|
||||
|
|
@ -123,6 +147,7 @@ private fun SearchHistory(
|
|||
clearLabel: String,
|
||||
items: List<CatalogItemUiModel>,
|
||||
onItemSelected: (CatalogItemUiModel) -> Unit,
|
||||
onItemLongPressed: (CatalogItemUiModel) -> Unit = {},
|
||||
onClearHistory: () -> Unit,
|
||||
modifier: Modifier
|
||||
) {
|
||||
|
|
@ -143,6 +168,7 @@ private fun SearchHistory(
|
|||
SearchResults(
|
||||
items = items,
|
||||
onItemSelected = onItemSelected,
|
||||
onItemLongPressed = onItemLongPressed,
|
||||
modifier = Modifier.fillMaxSize()
|
||||
)
|
||||
}
|
||||
|
|
@ -152,6 +178,7 @@ private fun SearchHistory(
|
|||
internal fun SearchResultRows(
|
||||
rows: List<CatalogRowUiModel>,
|
||||
onItemSelected: (CatalogItemUiModel) -> Unit,
|
||||
onItemLongPressed: (CatalogItemUiModel) -> Unit = {},
|
||||
modifier: Modifier
|
||||
) {
|
||||
LazyColumn(
|
||||
|
|
@ -170,7 +197,7 @@ internal fun SearchResultRows(
|
|||
)
|
||||
LazyRow(horizontalArrangement = Arrangement.spacedBy(12.dp)) {
|
||||
items(row.items, key = { it.id }) { item ->
|
||||
CatalogCard(model = item.card, onClick = { onItemSelected(item) })
|
||||
CatalogCard(model = item.card, onClick = { onItemSelected(item) }, onLongClick = { onItemLongPressed(item) })
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -182,6 +209,7 @@ internal fun SearchResultRows(
|
|||
internal fun SearchResults(
|
||||
items: List<CatalogItemUiModel>,
|
||||
onItemSelected: (CatalogItemUiModel) -> Unit,
|
||||
onItemLongPressed: (CatalogItemUiModel) -> Unit = {},
|
||||
modifier: Modifier
|
||||
) {
|
||||
LazyVerticalGrid(
|
||||
|
|
@ -192,7 +220,7 @@ internal fun SearchResults(
|
|||
verticalArrangement = Arrangement.spacedBy(16.dp)
|
||||
) {
|
||||
gridItems(items, key = { it.id }) { item ->
|
||||
CatalogCard(model = item.card, onClick = { onItemSelected(item) })
|
||||
CatalogCard(model = item.card, onClick = { onItemSelected(item) }, onLongClick = { onItemLongPressed(item) })
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -12,6 +12,7 @@ fun TvSearchScreen(
|
|||
language: String?,
|
||||
onQueryChanged: (String) -> Unit,
|
||||
onItemSelected: (CatalogItemUiModel) -> Unit,
|
||||
onAddToLibrary: (CatalogItemUiModel) -> Unit = {},
|
||||
onClearHistory: () -> Unit = {},
|
||||
modifier: Modifier = Modifier
|
||||
) {
|
||||
|
|
@ -20,6 +21,7 @@ fun TvSearchScreen(
|
|||
language = language,
|
||||
onQueryChanged = onQueryChanged,
|
||||
onItemSelected = onItemSelected,
|
||||
onAddToLibrary = onAddToLibrary,
|
||||
onClearHistory = onClearHistory,
|
||||
modifier = modifier.padding(start = 38.dp, top = 56.dp, end = 38.dp, bottom = 24.dp)
|
||||
)
|
||||
|
|
|
|||
|
|
@ -58,10 +58,13 @@ data class SettingsGeneralUiModel(
|
|||
data class SettingsAppearanceUiModel(
|
||||
val accentColorArgb: Long = 0xFFFFFFFFL,
|
||||
val amoledMode: Boolean = false,
|
||||
val animationsEnabled: Boolean = true
|
||||
val animationsEnabled: Boolean = true,
|
||||
val floatingBottomBar: Boolean = false,
|
||||
val bottomBarLabels: Boolean = false
|
||||
)
|
||||
|
||||
data class SettingsAppearanceHomeUiModel(
|
||||
val topBarEnabled: Boolean = true,
|
||||
val cardCornerPreset: String = "medium",
|
||||
val interfaceDensity: String = "normal",
|
||||
val posterWidthPreset: String = "medium",
|
||||
|
|
@ -220,7 +223,6 @@ sealed interface SettingsAction {
|
|||
data object DisconnectSyncRequested : SettingsAction
|
||||
data object SwitchProfilesRequested : SettingsAction
|
||||
data object CheckForUpdateRequested : SettingsAction
|
||||
data object ManageDownloadsRequested : SettingsAction
|
||||
}
|
||||
|
||||
interface SettingsDataSource {
|
||||
|
|
|
|||
|
|
@ -649,6 +649,12 @@ private fun SettingsAppearanceContent(model: SettingsAppearanceUiModel, lang: St
|
|||
SettingsToggleRow(AppStrings.t(lang, "auto.disable_animations"), value = !model.animationsEnabled) {
|
||||
onAction(SettingsAction.AppearanceChanged(model.copy(animationsEnabled = !it)))
|
||||
}
|
||||
SettingsToggleRow(AppStrings.t(lang, "settings.floating_bottom_bar"), description = AppStrings.t(lang, "settings.floating_bottom_bar_desc"), value = model.floatingBottomBar) {
|
||||
onAction(SettingsAction.AppearanceChanged(model.copy(floatingBottomBar = it)))
|
||||
}
|
||||
SettingsToggleRow(AppStrings.t(lang, "settings.bottom_bar_labels"), description = AppStrings.t(lang, "settings.bottom_bar_labels_desc"), value = model.bottomBarLabels) {
|
||||
onAction(SettingsAction.AppearanceChanged(model.copy(bottomBarLabels = it)))
|
||||
}
|
||||
}
|
||||
Spacer(Modifier.height(20.dp))
|
||||
SettingsGroupCard {
|
||||
|
|
@ -688,6 +694,9 @@ private fun SettingsAppearanceHomeContent(model: SettingsAppearanceHomeUiModel,
|
|||
)
|
||||
SettingsSectionHeader(AppStrings.t(lang, "settings.layout"))
|
||||
SettingsGroupCard {
|
||||
SettingsToggleRow(AppStrings.t(lang, "settings.home_top_bar"), description = AppStrings.t(lang, "settings.home_top_bar_desc"), value = model.topBarEnabled) {
|
||||
onAction(SettingsAction.AppearanceHomeChanged(model.copy(topBarEnabled = it)))
|
||||
}
|
||||
SettingsChoiceRow(AppStrings.t(lang, "auto.card_corners"), model.cardCornerPreset, cornerOptions) { onAction(SettingsAction.AppearanceHomeChanged(model.copy(cardCornerPreset = it))) }
|
||||
SettingsChoiceRow(AppStrings.t(lang, "auto.interface_density"), model.interfaceDensity, densityOptions) { onAction(SettingsAction.AppearanceHomeChanged(model.copy(interfaceDensity = it))) }
|
||||
SettingsChoiceRow(AppStrings.t(lang, "auto.poster_width"), model.posterWidthPreset, posterWidthOptions) { onAction(SettingsAction.AppearanceHomeChanged(model.copy(posterWidthPreset = it))) }
|
||||
|
|
@ -1024,10 +1033,6 @@ private fun SettingsDownloadsContent(model: SettingsDownloadsUiModel, lang: Stri
|
|||
}
|
||||
}
|
||||
|
||||
SettingsSectionHeader(AppStrings.t(lang, "auto.downloads"))
|
||||
SettingsGroupCard {
|
||||
SettingsActionRow(AppStrings.t(lang, "settings.manage_downloads")) { onAction(SettingsAction.ManageDownloadsRequested) }
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
|
|
|
|||
|
|
@ -64,7 +64,6 @@ private val SETTINGS_SEARCH_KEYS: List<Pair<String, SettingsCategory>> = listOf(
|
|||
"settings.top_10_catalogs" to SettingsCategory.Content,
|
||||
"settings.download_source_selection" to SettingsCategory.Downloads,
|
||||
"settings.download_subtitle" to SettingsCategory.Downloads,
|
||||
"settings.manage_downloads" to SettingsCategory.Downloads,
|
||||
"settings.automatic_updates" to SettingsCategory.Hub,
|
||||
"settings.check_for_updates" to SettingsCategory.Hub,
|
||||
"settings.developer" to SettingsCategory.Developer
|
||||
|
|
|
|||
|
|
@ -43,7 +43,6 @@ class SettingsStore(
|
|||
SettingsAction.DisconnectSyncRequested -> dataSource.disconnectSync()
|
||||
SettingsAction.SwitchProfilesRequested -> Unit
|
||||
SettingsAction.CheckForUpdateRequested -> Unit
|
||||
SettingsAction.ManageDownloadsRequested -> Unit
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -12,8 +12,8 @@ import androidx.compose.material.icons.automirrored.filled.VolumeOff
|
|||
import androidx.compose.material.icons.automirrored.filled.VolumeUp
|
||||
import androidx.compose.material.icons.filled.*
|
||||
import androidx.compose.material.icons.outlined.DateRange
|
||||
import androidx.compose.material.icons.outlined.Explore
|
||||
import androidx.compose.material.icons.outlined.Home
|
||||
import androidx.compose.material.icons.outlined.Search
|
||||
import androidx.compose.material.icons.outlined.Settings
|
||||
import androidx.compose.material.icons.outlined.VideoLibrary
|
||||
import androidx.compose.ui.graphics.vector.ImageVector
|
||||
|
|
@ -33,8 +33,8 @@ object FluxaIcons {
|
|||
val BookmarkBorder: ImageVector = Icons.Filled.Bookmark
|
||||
val BottomCalendar: ImageVector = Icons.Filled.DateRange
|
||||
val BottomCalendarOutline: ImageVector = Icons.Outlined.DateRange
|
||||
val BottomDiscover: ImageVector = Icons.Filled.Explore
|
||||
val BottomDiscoverOutline: ImageVector = Icons.Outlined.Explore
|
||||
val BottomDiscover: ImageVector = Icons.Filled.Search
|
||||
val BottomDiscoverOutline: ImageVector = Icons.Outlined.Search
|
||||
val BottomHome: ImageVector = Icons.Filled.Home
|
||||
val BottomHomeOutline: ImageVector = Icons.Outlined.Home
|
||||
val BottomLibrary: ImageVector = Icons.Filled.VideoLibrary
|
||||
|
|
|
|||
|
|
@ -0,0 +1,97 @@
|
|||
package com.fluxa.app.ui.catalog
|
||||
|
||||
import androidx.compose.foundation.background
|
||||
import androidx.compose.foundation.clickable
|
||||
import androidx.compose.foundation.layout.Arrangement
|
||||
import androidx.compose.foundation.layout.Box
|
||||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.layout.Row
|
||||
import androidx.compose.foundation.layout.fillMaxWidth
|
||||
import androidx.compose.foundation.layout.height
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.foundation.layout.width
|
||||
import androidx.compose.foundation.shape.RoundedCornerShape
|
||||
import androidx.compose.material.icons.Icons
|
||||
import androidx.compose.material.icons.filled.Add
|
||||
import androidx.compose.material3.Icon
|
||||
import androidx.compose.material3.ModalBottomSheet
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.material3.rememberModalBottomSheetState
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.draw.clip
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.layout.ContentScale
|
||||
import androidx.compose.ui.text.font.FontWeight
|
||||
import androidx.compose.ui.text.style.TextOverflow
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.compose.ui.unit.sp
|
||||
import com.fluxa.app.common.AppStrings
|
||||
import com.fluxa.app.shared.feature.catalog.CatalogItemUiModel
|
||||
import com.fluxa.app.shared.image.FluxaRemoteImage
|
||||
|
||||
@OptIn(androidx.compose.material3.ExperimentalMaterial3Api::class)
|
||||
@Composable
|
||||
fun PosterActionSheet(
|
||||
item: CatalogItemUiModel,
|
||||
language: String?,
|
||||
onDismiss: () -> Unit,
|
||||
onAddToLibrary: () -> Unit
|
||||
) {
|
||||
ModalBottomSheet(
|
||||
onDismissRequest = onDismiss,
|
||||
sheetState = rememberModalBottomSheetState(skipPartiallyExpanded = true),
|
||||
containerColor = FluxaColors.surfaceRaised
|
||||
) {
|
||||
Column(
|
||||
modifier = Modifier.fillMaxWidth().padding(horizontal = 20.dp).padding(bottom = 28.dp),
|
||||
verticalArrangement = Arrangement.spacedBy(18.dp)
|
||||
) {
|
||||
Row(horizontalArrangement = Arrangement.spacedBy(16.dp)) {
|
||||
FluxaRemoteImage(
|
||||
imageUrl = item.card.artworkUrl,
|
||||
cacheKey = "poster-sheet:${item.card.artworkUrl}",
|
||||
contentDescription = null,
|
||||
modifier = Modifier.width(92.dp).height(138.dp).clip(RoundedCornerShape(10.dp)),
|
||||
contentScale = ContentScale.Crop
|
||||
)
|
||||
Column(verticalArrangement = Arrangement.spacedBy(8.dp), modifier = Modifier.weight(1f)) {
|
||||
Text(item.card.title, color = Color.White, fontSize = 20.sp, fontWeight = FontWeight.Bold, maxLines = 2, overflow = TextOverflow.Ellipsis)
|
||||
item.card.subtitle.takeIf { it.isNotBlank() }?.let {
|
||||
Text(it, color = Color.White.copy(alpha = 0.65f), fontSize = 13.sp, maxLines = 1, overflow = TextOverflow.Ellipsis)
|
||||
}
|
||||
val metadata = listOfNotNull(
|
||||
item.ageRating?.takeIf { it.isNotBlank() },
|
||||
item.runtimeLabel?.takeIf { it.isNotBlank() },
|
||||
item.seasonsCount?.takeIf { it > 0 }?.let { "$it ${AppStrings.t(language, "auto.seasons")}" }
|
||||
).joinToString(" • ")
|
||||
if (metadata.isNotBlank()) {
|
||||
Text(metadata, color = Color.White.copy(alpha = 0.72f), fontSize = 13.sp)
|
||||
}
|
||||
item.description?.takeIf { it.isNotBlank() }?.let {
|
||||
Text(it, color = Color.White.copy(alpha = 0.78f), fontSize = 13.sp, lineHeight = 17.sp, maxLines = 4, overflow = TextOverflow.Ellipsis)
|
||||
}
|
||||
}
|
||||
}
|
||||
Row(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.height(50.dp)
|
||||
.clip(RoundedCornerShape(12.dp))
|
||||
.background(Color.White)
|
||||
.clickable(onClick = onAddToLibrary),
|
||||
horizontalArrangement = Arrangement.Center,
|
||||
verticalAlignment = Alignment.CenterVertically
|
||||
) {
|
||||
Icon(Icons.Filled.Add, contentDescription = null, tint = Color.Black)
|
||||
Text(
|
||||
AppStrings.t(language, "common.add_to_library"),
|
||||
color = Color.Black,
|
||||
fontWeight = FontWeight.Bold,
|
||||
modifier = Modifier.padding(start = 8.dp)
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -42,10 +42,13 @@ class AppleSettingsDataSource : SettingsDataSource {
|
|||
defaults.setDouble(value.accentColorArgb.toDouble(), K.accentColorArgb)
|
||||
defaults.setBool(value.amoledMode, K.amoledMode)
|
||||
defaults.setBool(value.animationsEnabled, K.animationsEnabled)
|
||||
defaults.setBool(value.floatingBottomBar, K.floatingBottomBar)
|
||||
defaults.setBool(value.bottomBarLabels, K.bottomBarLabels)
|
||||
state.value = state.value.copy(appearance = value)
|
||||
}
|
||||
|
||||
override suspend fun updateAppearanceHome(value: SettingsAppearanceHomeUiModel) {
|
||||
defaults.setBool(value.topBarEnabled, K.homeTopBarEnabled)
|
||||
defaults.setObject(value.cardCornerPreset, K.cardCornerPreset)
|
||||
defaults.setObject(value.interfaceDensity, K.interfaceDensity)
|
||||
defaults.setObject(value.posterWidthPreset, K.posterWidthPreset)
|
||||
|
|
@ -221,9 +224,12 @@ class AppleSettingsDataSource : SettingsDataSource {
|
|||
appearance = SettingsAppearanceUiModel(
|
||||
accentColorArgb = defaults.objectForKey(K.accentColorArgb)?.let { defaults.doubleForKey(K.accentColorArgb).toLong() } ?: 0xFFFFFFFFL,
|
||||
amoledMode = defaults.boolOrDefault(K.amoledMode, false),
|
||||
animationsEnabled = defaults.boolOrDefault(K.animationsEnabled, true)
|
||||
animationsEnabled = defaults.boolOrDefault(K.animationsEnabled, true),
|
||||
floatingBottomBar = defaults.boolOrDefault(K.floatingBottomBar, false),
|
||||
bottomBarLabels = defaults.boolOrDefault(K.bottomBarLabels, false)
|
||||
),
|
||||
appearanceHome = SettingsAppearanceHomeUiModel(
|
||||
topBarEnabled = defaults.boolOrDefault(K.homeTopBarEnabled, true),
|
||||
cardCornerPreset = defaults.stringForKey(K.cardCornerPreset) ?: "medium",
|
||||
interfaceDensity = defaults.stringForKey(K.interfaceDensity) ?: "normal",
|
||||
posterWidthPreset = defaults.stringForKey(K.posterWidthPreset) ?: "medium",
|
||||
|
|
@ -318,6 +324,9 @@ class AppleSettingsDataSource : SettingsDataSource {
|
|||
const val accentColorArgb = "fluxa.apple.settings.accentColorArgb"
|
||||
const val amoledMode = "fluxa.apple.settings.amoledMode"
|
||||
const val animationsEnabled = "fluxa.apple.settings.animationsEnabled"
|
||||
const val homeTopBarEnabled = "fluxa.apple.settings.homeTopBarEnabled"
|
||||
const val floatingBottomBar = "fluxa.apple.settings.floatingBottomBar"
|
||||
const val bottomBarLabels = "fluxa.apple.settings.bottomBarLabels"
|
||||
const val cardCornerPreset = "fluxa.apple.settings.cardCornerPreset"
|
||||
const val interfaceDensity = "fluxa.apple.settings.interfaceDensity"
|
||||
const val posterWidthPreset = "fluxa.apple.settings.posterWidthPreset"
|
||||
|
|
|
|||
Loading…
Reference in a new issue