diff --git a/composeApp/src/commonMain/kotlin/dev/datlag/aniflow/common/ExtendMedium.kt b/composeApp/src/commonMain/kotlin/dev/datlag/aniflow/common/ExtendMedium.kt index 8a901ab..8422502 100644 --- a/composeApp/src/commonMain/kotlin/dev/datlag/aniflow/common/ExtendMedium.kt +++ b/composeApp/src/commonMain/kotlin/dev/datlag/aniflow/common/ExtendMedium.kt @@ -16,30 +16,18 @@ import dev.datlag.tooling.decompose.lifecycle.collectAsStateWithLifecycle import dev.icerock.moko.resources.StringResource import org.kodein.di.instance -@Composable fun Medium.preferred(setting: AppSettings.TitleLanguage? = null): String { - val appSettings by LocalDI.current.instance() - val title by appSettings.titleLanguage.collectAsStateWithLifecycle(null) - - return this.title.preferred(setting ?: title).ifBlank { this.id.toString() } + return this.title.preferred(setting).ifBlank { this.id.toString() } } -@Composable fun Medium.notPreferred(setting: AppSettings.TitleLanguage? = null): String? { - val appSettings by LocalDI.current.instance() - val title by appSettings.titleLanguage.collectAsStateWithLifecycle(null) - - return this.title.notPreferred(setting ?: title)?.ifBlank { null } + return this.title.notPreferred(setting)?.ifBlank { null } } expect fun Medium.Title.preferred(setting: AppSettings.TitleLanguage? = null): String -@Composable fun Medium.Title.notPreferred(setting: AppSettings.TitleLanguage? = null): String? { - val appSettings by LocalDI.current.instance() - val title by appSettings.titleLanguage.collectAsStateWithLifecycle(null) - - val preferred = this.preferred(setting ?: title).trim() + val preferred = this.preferred(setting).trim() val notPreferred = when { this.native?.trim().equals(preferred, ignoreCase = true) -> { when { diff --git a/composeApp/src/commonMain/kotlin/dev/datlag/aniflow/other/StateSaver.kt b/composeApp/src/commonMain/kotlin/dev/datlag/aniflow/other/StateSaver.kt index 9f33ddc..eea787a 100644 --- a/composeApp/src/commonMain/kotlin/dev/datlag/aniflow/other/StateSaver.kt +++ b/composeApp/src/commonMain/kotlin/dev/datlag/aniflow/other/StateSaver.kt @@ -69,7 +69,7 @@ data object StateSaver { t1.isLoadingOrWaiting && t2.isLoadingOrWaiting && t3.isLoadingOrWaiting && t4.isLoadingOrWaiting }.flowOn( context = ioDispatcher() - ) + ).distinctUntilChanged() fun updateAiring(state: AiringTodayStateMachine.State) = _airingState.updateAndGet { state diff --git a/composeApp/src/commonMain/kotlin/dev/datlag/aniflow/ui/navigation/screen/initial/home/HomeComponent.kt b/composeApp/src/commonMain/kotlin/dev/datlag/aniflow/ui/navigation/screen/initial/home/HomeComponent.kt index 4012229..6b6db21 100644 --- a/composeApp/src/commonMain/kotlin/dev/datlag/aniflow/ui/navigation/screen/initial/home/HomeComponent.kt +++ b/composeApp/src/commonMain/kotlin/dev/datlag/aniflow/ui/navigation/screen/initial/home/HomeComponent.kt @@ -7,6 +7,7 @@ import dev.datlag.aniflow.anilist.PopularSeasonStateMachine import dev.datlag.aniflow.anilist.TrendingAnimeStateMachine import dev.datlag.aniflow.anilist.model.Medium import dev.datlag.aniflow.anilist.state.SeasonState +import dev.datlag.aniflow.settings.model.AppSettings import dev.datlag.aniflow.trace.TraceStateMachine import dev.datlag.aniflow.ui.navigation.Component import dev.datlag.aniflow.ui.navigation.ContentHolderComponent @@ -16,6 +17,8 @@ import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.StateFlow interface HomeComponent : ContentHolderComponent { + val titleLanguage: Flow + val airingState: Flow val trendingState: Flow val popularSeasonState: Flow diff --git a/composeApp/src/commonMain/kotlin/dev/datlag/aniflow/ui/navigation/screen/initial/home/HomeScreen.kt b/composeApp/src/commonMain/kotlin/dev/datlag/aniflow/ui/navigation/screen/initial/home/HomeScreen.kt index 8c6bb5b..853ddd3 100644 --- a/composeApp/src/commonMain/kotlin/dev/datlag/aniflow/ui/navigation/screen/initial/home/HomeScreen.kt +++ b/composeApp/src/commonMain/kotlin/dev/datlag/aniflow/ui/navigation/screen/initial/home/HomeScreen.kt @@ -105,13 +105,14 @@ private fun MainView(component: HomeComponent, modifier: Modifier = Modifier) { ) } val useCase = rememberUseCaseState(visible = results.isNotEmpty()) + val titleLanguage by component.titleLanguage.collectAsStateWithLifecycle(null) OptionDialog( state = useCase, selection = OptionSelection.Single( options = results.map { Option( - titleText = it.aniList.asMedium().title.preferred(), + titleText = it.aniList.asMedium().title.preferred(titleLanguage), details = OptionDetails( title = stringResource(SharedRes.strings.similarity_title), body = if (it.isSingle) { @@ -151,6 +152,7 @@ private fun MainView(component: HomeComponent, modifier: Modifier = Modifier) { item { AiringOverview( state = component.airingState, + titleLanguage = component.titleLanguage, onClick = component::details ) } @@ -165,6 +167,7 @@ private fun MainView(component: HomeComponent, modifier: Modifier = Modifier) { item { TrendingOverview( state = component.trendingState, + titleLanguage = component.titleLanguage, onClick = component::details ) } @@ -180,6 +183,7 @@ private fun MainView(component: HomeComponent, modifier: Modifier = Modifier) { PopularSeasonOverview( state = component.popularSeasonState, current = true, + titleLanguage = component.titleLanguage, onClick = component::details, ) } @@ -195,6 +199,7 @@ private fun MainView(component: HomeComponent, modifier: Modifier = Modifier) { PopularSeasonOverview( state = component.popularNextSeasonState, current = false, + titleLanguage = component.titleLanguage, onClick = component::details ) } diff --git a/composeApp/src/commonMain/kotlin/dev/datlag/aniflow/ui/navigation/screen/initial/home/HomeScreenComponent.kt b/composeApp/src/commonMain/kotlin/dev/datlag/aniflow/ui/navigation/screen/initial/home/HomeScreenComponent.kt index 3bbd3e3..b55337d 100644 --- a/composeApp/src/commonMain/kotlin/dev/datlag/aniflow/ui/navigation/screen/initial/home/HomeScreenComponent.kt +++ b/composeApp/src/commonMain/kotlin/dev/datlag/aniflow/ui/navigation/screen/initial/home/HomeScreenComponent.kt @@ -1,9 +1,11 @@ package dev.datlag.aniflow.ui.navigation.screen.initial.home import androidx.compose.runtime.Composable +import androidx.compose.runtime.getValue import com.arkivanov.decompose.ComponentContext import com.arkivanov.decompose.router.slot.* import com.arkivanov.decompose.value.Value +import dev.datlag.aniflow.LocalDI import dev.datlag.aniflow.anilist.AiringTodayStateMachine import dev.datlag.aniflow.anilist.PopularNextSeasonStateMachine import dev.datlag.aniflow.anilist.PopularSeasonStateMachine @@ -12,11 +14,14 @@ import dev.datlag.aniflow.anilist.model.Medium import dev.datlag.aniflow.anilist.state.SeasonState import dev.datlag.aniflow.common.onRender import dev.datlag.aniflow.other.StateSaver +import dev.datlag.aniflow.settings.Settings +import dev.datlag.aniflow.settings.model.AppSettings import dev.datlag.aniflow.trace.TraceStateMachine import dev.datlag.aniflow.ui.navigation.Component import dev.datlag.aniflow.ui.navigation.screen.medium.MediumScreenComponent import dev.datlag.tooling.compose.ioDispatcher import dev.datlag.tooling.decompose.ioScope +import dev.datlag.tooling.decompose.lifecycle.collectAsStateWithLifecycle import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.delay import kotlinx.coroutines.flow.* @@ -30,33 +35,36 @@ class HomeScreenComponent( private val onMediumDetails: (Medium) -> Unit ) : HomeComponent, ComponentContext by componentContext { + private val appSettings by di.instance() + override val titleLanguage: Flow = appSettings.titleLanguage.flowOn(ioDispatcher()) + private val airingTodayStateMachine by di.instance() override val airingState: Flow = airingTodayStateMachine.state.map { StateSaver.Home.updateAiring(it) }.flowOn( context = ioDispatcher() - ) + ).distinctUntilChanged() private val trendingAnimeStateMachine by di.instance() override val trendingState: Flow = trendingAnimeStateMachine.state.map { StateSaver.Home.updateTrending(it) }.flowOn( context = ioDispatcher() - ) + ).distinctUntilChanged() private val popularSeasonStateMachine by di.instance() override val popularSeasonState: Flow = popularSeasonStateMachine.state.map { StateSaver.Home.updatePopularCurrent(it) }.flowOn( context = ioDispatcher() - ) + ).distinctUntilChanged() private val popularNextSeasonStateMachine by di.instance() override val popularNextSeasonState: Flow = popularNextSeasonStateMachine.state.map { StateSaver.Home.updatePopularNext(it) }.flowOn( context = ioDispatcher() - ) + ).distinctUntilChanged() private val traceStateMachine by di.instance() override val traceState: Flow = traceStateMachine.state.flowOn( diff --git a/composeApp/src/commonMain/kotlin/dev/datlag/aniflow/ui/navigation/screen/initial/home/component/AiringCard.kt b/composeApp/src/commonMain/kotlin/dev/datlag/aniflow/ui/navigation/screen/initial/home/component/AiringCard.kt index cbf4273..08612ab 100644 --- a/composeApp/src/commonMain/kotlin/dev/datlag/aniflow/ui/navigation/screen/initial/home/component/AiringCard.kt +++ b/composeApp/src/commonMain/kotlin/dev/datlag/aniflow/ui/navigation/screen/initial/home/component/AiringCard.kt @@ -23,12 +23,14 @@ import dev.datlag.aniflow.settings.Settings import dev.datlag.aniflow.settings.model.AppSettings import dev.datlag.aniflow.ui.theme.SchemeTheme import dev.datlag.tooling.decompose.lifecycle.collectAsStateWithLifecycle +import kotlinx.coroutines.flow.Flow import org.kodein.di.instance import org.kodein.di.instanceOrNull @Composable fun AiringCard( airing: AiringQuery.AiringSchedule, + titleLanguageFlow: Flow, modifier: Modifier = Modifier, onClick: (Medium) -> Unit ) { @@ -45,10 +47,12 @@ fun AiringCard( modifier = Modifier.fillMaxWidth(), horizontalArrangement = Arrangement.spacedBy(8.dp) ) { + val titleLanguage by titleLanguageFlow.collectAsStateWithLifecycle(null) + AsyncImage( modifier = Modifier.widthIn(min = 100.dp, max = 120.dp).fillMaxHeight().clip(MaterialTheme.shapes.medium), model = media.coverImage.extraLarge, - contentDescription = media.preferred(), + contentDescription = media.preferred(titleLanguage), contentScale = ContentScale.Crop, error = rememberAsyncImagePainter( model = media.coverImage.large, @@ -85,7 +89,7 @@ fun AiringCard( verticalArrangement = Arrangement.spacedBy(8.dp) ) { Text( - text = media.preferred(), + text = media.preferred(titleLanguage), style = MaterialTheme.typography.titleLarge, overflow = TextOverflow.Ellipsis, softWrap = true, diff --git a/composeApp/src/commonMain/kotlin/dev/datlag/aniflow/ui/navigation/screen/initial/home/component/AiringOverview.kt b/composeApp/src/commonMain/kotlin/dev/datlag/aniflow/ui/navigation/screen/initial/home/component/AiringOverview.kt index 5b16c8c..d32d651 100644 --- a/composeApp/src/commonMain/kotlin/dev/datlag/aniflow/ui/navigation/screen/initial/home/component/AiringOverview.kt +++ b/composeApp/src/commonMain/kotlin/dev/datlag/aniflow/ui/navigation/screen/initial/home/component/AiringOverview.kt @@ -22,6 +22,7 @@ import dev.datlag.aniflow.anilist.AiringTodayStateMachine import dev.datlag.aniflow.anilist.model.Medium import dev.datlag.aniflow.common.shimmer import dev.datlag.aniflow.other.StateSaver +import dev.datlag.aniflow.settings.model.AppSettings import dev.datlag.tooling.decompose.lifecycle.collectAsStateWithLifecycle import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.StateFlow @@ -29,6 +30,7 @@ import kotlinx.coroutines.flow.StateFlow @Composable fun AiringOverview( state: Flow, + titleLanguage: Flow, onClick: (Medium) -> Unit ) { val loadingState by state.collectAsStateWithLifecycle(StateSaver.Home.airingState) @@ -40,6 +42,7 @@ fun AiringOverview( is AiringTodayStateMachine.State.Success -> { SuccessContent( data = reachedState.data.Page?.airingSchedulesFilterNotNull() ?: emptyList(), + titleLanguage = titleLanguage, onClick = onClick ) } @@ -65,6 +68,7 @@ private fun Loading() { @Composable private fun SuccessContent( data: List, + titleLanguage: Flow, onClick: (Medium) -> Unit ) { val state = rememberLazyListState( @@ -82,6 +86,7 @@ private fun SuccessContent( items(data, key = { it.episode to it.media?.id }) { media -> AiringCard( airing = media, + titleLanguageFlow = titleLanguage, modifier = Modifier .height(150.dp) .fillParentMaxWidth(fraction = 0.9F) diff --git a/composeApp/src/commonMain/kotlin/dev/datlag/aniflow/ui/navigation/screen/initial/home/component/MediumCard.kt b/composeApp/src/commonMain/kotlin/dev/datlag/aniflow/ui/navigation/screen/initial/home/component/MediumCard.kt index 7a10705..c359a81 100644 --- a/composeApp/src/commonMain/kotlin/dev/datlag/aniflow/ui/navigation/screen/initial/home/component/MediumCard.kt +++ b/composeApp/src/commonMain/kotlin/dev/datlag/aniflow/ui/navigation/screen/initial/home/component/MediumCard.kt @@ -24,15 +24,19 @@ import coil3.compose.rememberAsyncImagePainter import dev.datlag.aniflow.anilist.model.Medium import dev.datlag.aniflow.common.bottomShadowBrush import dev.datlag.aniflow.common.preferred +import dev.datlag.aniflow.settings.model.AppSettings import dev.datlag.aniflow.ui.custom.alignment.rememberParallaxAlignment import dev.datlag.aniflow.ui.theme.SchemeTheme import dev.datlag.aniflow.ui.theme.rememberSchemeThemeDominantColorState +import dev.datlag.tooling.decompose.lifecycle.collectAsStateWithLifecycle import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.flow.Flow @OptIn(ExperimentalStdlibApi::class) @Composable fun MediumCard( medium: Medium, + titleLanguageFlow: Flow, modifier: Modifier = Modifier, onClick: (Medium) -> Unit ) { @@ -106,8 +110,10 @@ fun MediumCard( .padding(top = 16.dp), verticalArrangement = Arrangement.spacedBy(8.dp) ) { + val titleLanguage by titleLanguageFlow.collectAsStateWithLifecycle(null) + Text( - text = medium.preferred(), + text = medium.preferred(titleLanguage), style = MaterialTheme.typography.titleLarge, maxLines = if (medium.averageScore > 0F) { 1 diff --git a/composeApp/src/commonMain/kotlin/dev/datlag/aniflow/ui/navigation/screen/initial/home/component/PopularSeasonOverview.kt b/composeApp/src/commonMain/kotlin/dev/datlag/aniflow/ui/navigation/screen/initial/home/component/PopularSeasonOverview.kt index 4da5b4b..a7aea65 100644 --- a/composeApp/src/commonMain/kotlin/dev/datlag/aniflow/ui/navigation/screen/initial/home/component/PopularSeasonOverview.kt +++ b/composeApp/src/commonMain/kotlin/dev/datlag/aniflow/ui/navigation/screen/initial/home/component/PopularSeasonOverview.kt @@ -20,6 +20,7 @@ import dev.datlag.aniflow.anilist.model.Medium import dev.datlag.aniflow.anilist.state.SeasonState import dev.datlag.aniflow.common.shimmer import dev.datlag.aniflow.other.StateSaver +import dev.datlag.aniflow.settings.model.AppSettings import dev.datlag.tooling.decompose.lifecycle.collectAsStateWithLifecycle import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.flow.Flow @@ -30,6 +31,7 @@ import kotlinx.coroutines.flow.distinctUntilChanged fun PopularSeasonOverview( state: Flow, current: Boolean, + titleLanguage: Flow, onClick: (Medium) -> Unit, ) { val loadingState by state.collectAsStateWithLifecycle( @@ -48,6 +50,7 @@ fun PopularSeasonOverview( SuccessContent( data = reachedState.data.Page?.mediaFilterNotNull() ?: emptyList(), current = current, + titleLanguage = titleLanguage, onClick = onClick ) } @@ -74,6 +77,7 @@ private fun Loading() { private fun SuccessContent( data: List, current: Boolean, + titleLanguage: Flow, onClick: (Medium) -> Unit ) { val listState = rememberLazyListState( @@ -98,6 +102,7 @@ private fun SuccessContent( itemsIndexed(data, key = { _, it -> it.id }) { _, medium -> MediumCard( medium = Medium(medium), + titleLanguageFlow = titleLanguage, modifier = Modifier .width(200.dp) .height(280.dp) diff --git a/composeApp/src/commonMain/kotlin/dev/datlag/aniflow/ui/navigation/screen/initial/home/component/TrendingOverview.kt b/composeApp/src/commonMain/kotlin/dev/datlag/aniflow/ui/navigation/screen/initial/home/component/TrendingOverview.kt index cc8eb30..76eed57 100644 --- a/composeApp/src/commonMain/kotlin/dev/datlag/aniflow/ui/navigation/screen/initial/home/component/TrendingOverview.kt +++ b/composeApp/src/commonMain/kotlin/dev/datlag/aniflow/ui/navigation/screen/initial/home/component/TrendingOverview.kt @@ -18,6 +18,7 @@ import dev.datlag.aniflow.anilist.TrendingQuery import dev.datlag.aniflow.anilist.model.Medium import dev.datlag.aniflow.common.shimmer import dev.datlag.aniflow.other.StateSaver +import dev.datlag.aniflow.settings.model.AppSettings import dev.datlag.tooling.decompose.lifecycle.collectAsStateWithLifecycle import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.flow.Flow @@ -27,6 +28,7 @@ import kotlinx.coroutines.flow.distinctUntilChanged @Composable fun TrendingOverview( state: Flow, + titleLanguage: Flow, onClick: (Medium) -> Unit, ) { val loadingState by state.collectAsStateWithLifecycle(StateSaver.Home.trendingState) @@ -38,6 +40,7 @@ fun TrendingOverview( is TrendingAnimeStateMachine.State.Success -> { SuccessContent( data = reachedState.data.Page?.mediaFilterNotNull() ?: emptyList(), + titleLanguage = titleLanguage, onClick = onClick ) } @@ -63,6 +66,7 @@ private fun Loading() { @Composable private fun SuccessContent( data: List, + titleLanguage: Flow, onClick: (Medium) -> Unit ) { val listState = rememberLazyListState( @@ -79,6 +83,7 @@ private fun SuccessContent( itemsIndexed(data, key = { _, it -> it.id }) { _, medium -> MediumCard( medium = Medium(medium), + titleLanguageFlow = titleLanguage, modifier = Modifier .width(200.dp) .height(280.dp) diff --git a/composeApp/src/commonMain/kotlin/dev/datlag/aniflow/ui/navigation/screen/medium/MediumComponent.kt b/composeApp/src/commonMain/kotlin/dev/datlag/aniflow/ui/navigation/screen/medium/MediumComponent.kt index 904b545..34a46d3 100644 --- a/composeApp/src/commonMain/kotlin/dev/datlag/aniflow/ui/navigation/screen/medium/MediumComponent.kt +++ b/composeApp/src/commonMain/kotlin/dev/datlag/aniflow/ui/navigation/screen/medium/MediumComponent.kt @@ -7,6 +7,7 @@ import dev.datlag.aniflow.anilist.model.Character import dev.datlag.aniflow.anilist.model.Medium import dev.datlag.aniflow.anilist.type.MediaFormat import dev.datlag.aniflow.anilist.type.MediaStatus +import dev.datlag.aniflow.settings.model.AppSettings import dev.datlag.aniflow.ui.navigation.Component import dev.datlag.aniflow.ui.navigation.ContentHolderComponent import dev.datlag.aniflow.ui.navigation.DialogComponent @@ -15,6 +16,7 @@ import kotlinx.coroutines.flow.StateFlow interface MediumComponent : ContentHolderComponent { val initialMedium: Medium + val titleLanguage: Flow val mediumState: StateFlow val isAdult: Flow diff --git a/composeApp/src/commonMain/kotlin/dev/datlag/aniflow/ui/navigation/screen/medium/MediumScreen.kt b/composeApp/src/commonMain/kotlin/dev/datlag/aniflow/ui/navigation/screen/medium/MediumScreen.kt index 17011c5..bfe15e5 100644 --- a/composeApp/src/commonMain/kotlin/dev/datlag/aniflow/ui/navigation/screen/medium/MediumScreen.kt +++ b/composeApp/src/commonMain/kotlin/dev/datlag/aniflow/ui/navigation/screen/medium/MediumScreen.kt @@ -65,6 +65,7 @@ fun MediumScreen(component: MediumComponent) { state = appBarState, scrollBehavior = scrollState, initialMedium = component.initialMedium, + titleLanguageFlow = component.titleLanguage, mediumStateFlow = component.mediumState, bannerImageFlow = component.bannerImage, coverImage = coverImage, diff --git a/composeApp/src/commonMain/kotlin/dev/datlag/aniflow/ui/navigation/screen/medium/MediumScreenComponent.kt b/composeApp/src/commonMain/kotlin/dev/datlag/aniflow/ui/navigation/screen/medium/MediumScreenComponent.kt index 730d84e..1d3a0e1 100644 --- a/composeApp/src/commonMain/kotlin/dev/datlag/aniflow/ui/navigation/screen/medium/MediumScreenComponent.kt +++ b/composeApp/src/commonMain/kotlin/dev/datlag/aniflow/ui/navigation/screen/medium/MediumScreenComponent.kt @@ -24,6 +24,7 @@ import dev.datlag.aniflow.other.BurningSeriesResolver import dev.datlag.aniflow.other.Constants import dev.datlag.aniflow.other.UserHelper import dev.datlag.aniflow.settings.Settings +import dev.datlag.aniflow.settings.model.AppSettings import dev.datlag.aniflow.ui.navigation.DialogComponent import dev.datlag.aniflow.ui.navigation.screen.medium.dialog.character.CharacterDialogComponent import dev.datlag.tooling.alsoTrue @@ -53,6 +54,8 @@ class MediumScreenComponent( private val appSettings by di.instance() private val userHelper by di.instance() + override val titleLanguage: Flow = appSettings.titleLanguage.flowOn(ioDispatcher()) + private val mediumStateMachine = MediumStateMachine( client = aniListClient, fallbackClient = aniListFallbackClient, diff --git a/composeApp/src/commonMain/kotlin/dev/datlag/aniflow/ui/navigation/screen/medium/component/CollapsingToolbar.kt b/composeApp/src/commonMain/kotlin/dev/datlag/aniflow/ui/navigation/screen/medium/component/CollapsingToolbar.kt index 2bed53f..c5aab86 100644 --- a/composeApp/src/commonMain/kotlin/dev/datlag/aniflow/ui/navigation/screen/medium/component/CollapsingToolbar.kt +++ b/composeApp/src/commonMain/kotlin/dev/datlag/aniflow/ui/navigation/screen/medium/component/CollapsingToolbar.kt @@ -33,6 +33,7 @@ import dev.datlag.aniflow.anilist.MediumStateMachine import dev.datlag.aniflow.anilist.model.Medium import dev.datlag.aniflow.common.notPreferred import dev.datlag.aniflow.common.preferred +import dev.datlag.aniflow.settings.model.AppSettings import dev.datlag.aniflow.ui.custom.shareHandler import dev.datlag.tooling.compose.ifFalse import dev.datlag.tooling.compose.ifTrue @@ -48,6 +49,7 @@ fun CollapsingToolbar( state: TopAppBarState, scrollBehavior: TopAppBarScrollBehavior, initialMedium: Medium, + titleLanguageFlow: Flow, mediumStateFlow: StateFlow, bannerImageFlow: Flow, coverImage: Medium.CoverImage, @@ -108,14 +110,17 @@ fun CollapsingToolbar( } }, title = { - val title by titleFlow.collectAsStateWithLifecycle(initialMedium.title) + Column( modifier = Modifier.fillMaxWidth(), verticalArrangement = Arrangement.spacedBy(4.dp, Alignment.CenterVertically) ) { + val title by titleFlow.collectAsStateWithLifecycle(initialMedium.title) + val titleLanguage by titleLanguageFlow.collectAsStateWithLifecycle(null) + Text( - text = title.preferred(), + text = title.preferred(titleLanguage), softWrap = true, overflow = TextOverflow.Ellipsis, maxLines = 1, @@ -131,7 +136,7 @@ fun CollapsingToolbar( LocalTextStyle.current } ) - title.notPreferred()?.let { + title.notPreferred(titleLanguage)?.let { Text( text = it, softWrap = true, diff --git a/composeApp/src/commonMain/kotlin/dev/datlag/aniflow/ui/theme/DynamicMaterialTheme.kt b/composeApp/src/commonMain/kotlin/dev/datlag/aniflow/ui/theme/DynamicMaterialTheme.kt index f988b24..60ee9fc 100644 --- a/composeApp/src/commonMain/kotlin/dev/datlag/aniflow/ui/theme/DynamicMaterialTheme.kt +++ b/composeApp/src/commonMain/kotlin/dev/datlag/aniflow/ui/theme/DynamicMaterialTheme.kt @@ -29,44 +29,43 @@ fun DynamicMaterialTheme( } else { MaterialTheme.colorScheme } - val animationSpec: AnimationSpec = spring(stiffness = Spring.StiffnessLow) val colorScheme = dynamicColorScheme.copy( - primary = dynamicColorScheme.primary.animate(animationSpec), - primaryContainer = dynamicColorScheme.primaryContainer.animate(animationSpec), - secondary = dynamicColorScheme.secondary.animate(animationSpec), - secondaryContainer = dynamicColorScheme.secondaryContainer.animate(animationSpec), - tertiary = dynamicColorScheme.tertiary.animate(animationSpec), - tertiaryContainer = dynamicColorScheme.tertiaryContainer.animate(animationSpec), - background = dynamicColorScheme.background.animate(animationSpec), - surface = dynamicColorScheme.surface.animate(animationSpec), - surfaceTint = dynamicColorScheme.surfaceTint.animate(animationSpec), - surfaceBright = dynamicColorScheme.surfaceBright.animate(animationSpec), - surfaceDim = dynamicColorScheme.surfaceDim.animate(animationSpec), - surfaceContainer = dynamicColorScheme.surfaceContainer.animate(animationSpec), - surfaceContainerHigh = dynamicColorScheme.surfaceContainerHigh.animate(animationSpec), - surfaceContainerHighest = dynamicColorScheme.surfaceContainerHighest.animate(animationSpec), - surfaceContainerLow = dynamicColorScheme.surfaceContainerLow.animate(animationSpec), - surfaceContainerLowest = dynamicColorScheme.surfaceContainerLowest.animate(animationSpec), - surfaceVariant = dynamicColorScheme.surfaceVariant.animate(animationSpec), - error = dynamicColorScheme.error.animate(animationSpec), - errorContainer = dynamicColorScheme.errorContainer.animate(animationSpec), - onPrimary = dynamicColorScheme.onPrimary.animate(animationSpec), - onPrimaryContainer = dynamicColorScheme.onPrimaryContainer.animate(animationSpec), - onSecondary = dynamicColorScheme.onSecondary.animate(animationSpec), - onSecondaryContainer = dynamicColorScheme.onSecondaryContainer.animate(animationSpec), - onTertiary = dynamicColorScheme.onTertiary.animate(animationSpec), - onTertiaryContainer = dynamicColorScheme.onTertiaryContainer.animate(animationSpec), - onBackground = dynamicColorScheme.onBackground.animate(animationSpec), - onSurface = dynamicColorScheme.onSurface.animate(animationSpec), - onSurfaceVariant = dynamicColorScheme.onSurfaceVariant.animate(animationSpec), - onError = dynamicColorScheme.onError.animate(animationSpec), - onErrorContainer = dynamicColorScheme.onErrorContainer.animate(animationSpec), - inversePrimary = dynamicColorScheme.inversePrimary.animate(animationSpec), - inverseSurface = dynamicColorScheme.inverseSurface.animate(animationSpec), - inverseOnSurface = dynamicColorScheme.inverseOnSurface.animate(animationSpec), - outline = dynamicColorScheme.outline.animate(animationSpec), - outlineVariant = dynamicColorScheme.outlineVariant.animate(animationSpec), - scrim = dynamicColorScheme.scrim.animate(animationSpec), + primary = dynamicColorScheme.primary, + primaryContainer = dynamicColorScheme.primaryContainer, + secondary = dynamicColorScheme.secondary, + secondaryContainer = dynamicColorScheme.secondaryContainer, + tertiary = dynamicColorScheme.tertiary, + tertiaryContainer = dynamicColorScheme.tertiaryContainer, + background = dynamicColorScheme.background, + surface = dynamicColorScheme.surface, + surfaceTint = dynamicColorScheme.surfaceTint, + surfaceBright = dynamicColorScheme.surfaceBright, + surfaceDim = dynamicColorScheme.surfaceDim, + surfaceContainer = dynamicColorScheme.surfaceContainer, + surfaceContainerHigh = dynamicColorScheme.surfaceContainerHigh, + surfaceContainerHighest = dynamicColorScheme.surfaceContainerHighest, + surfaceContainerLow = dynamicColorScheme.surfaceContainerLow, + surfaceContainerLowest = dynamicColorScheme.surfaceContainerLowest, + surfaceVariant = dynamicColorScheme.surfaceVariant, + error = dynamicColorScheme.error, + errorContainer = dynamicColorScheme.errorContainer, + onPrimary = dynamicColorScheme.onPrimary, + onPrimaryContainer = dynamicColorScheme.onPrimaryContainer, + onSecondary = dynamicColorScheme.onSecondary, + onSecondaryContainer = dynamicColorScheme.onSecondaryContainer, + onTertiary = dynamicColorScheme.onTertiary, + onTertiaryContainer = dynamicColorScheme.onTertiaryContainer, + onBackground = dynamicColorScheme.onBackground, + onSurface = dynamicColorScheme.onSurface, + onSurfaceVariant = dynamicColorScheme.onSurfaceVariant, + onError = dynamicColorScheme.onError, + onErrorContainer = dynamicColorScheme.onErrorContainer, + inversePrimary = dynamicColorScheme.inversePrimary, + inverseSurface = dynamicColorScheme.inverseSurface, + inverseOnSurface = dynamicColorScheme.inverseOnSurface, + outline = dynamicColorScheme.outline, + outlineVariant = dynamicColorScheme.outlineVariant, + scrim = dynamicColorScheme.scrim, ) MaterialTheme( diff --git a/settings/src/commonMain/kotlin/dev/datlag/aniflow/settings/DataStoreAppSettings.kt b/settings/src/commonMain/kotlin/dev/datlag/aniflow/settings/DataStoreAppSettings.kt index 41924b8..d0786cd 100644 --- a/settings/src/commonMain/kotlin/dev/datlag/aniflow/settings/DataStoreAppSettings.kt +++ b/settings/src/commonMain/kotlin/dev/datlag/aniflow/settings/DataStoreAppSettings.kt @@ -3,14 +3,15 @@ package dev.datlag.aniflow.settings import androidx.datastore.core.DataStore import dev.datlag.aniflow.settings.model.AppSettings import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.distinctUntilChanged import kotlinx.coroutines.flow.map class DataStoreAppSettings( private val dateStore: DataStore ) : Settings.PlatformAppSettings { - override val adultContent: Flow = dateStore.data.map { it.adultContent } - override val color: Flow = dateStore.data.map { it.color } - override val titleLanguage: Flow = dateStore.data.map { it.titleLanguage } + override val adultContent: Flow = dateStore.data.map { it.adultContent }.distinctUntilChanged() + override val color: Flow = dateStore.data.map { it.color }.distinctUntilChanged() + override val titleLanguage: Flow = dateStore.data.map { it.titleLanguage }.distinctUntilChanged() override suspend fun setAdultContent(value: Boolean) { dateStore.updateData { diff --git a/settings/src/commonMain/kotlin/dev/datlag/aniflow/settings/DataStoreUserSettings.kt b/settings/src/commonMain/kotlin/dev/datlag/aniflow/settings/DataStoreUserSettings.kt index 99c8e36..539a0ab 100644 --- a/settings/src/commonMain/kotlin/dev/datlag/aniflow/settings/DataStoreUserSettings.kt +++ b/settings/src/commonMain/kotlin/dev/datlag/aniflow/settings/DataStoreUserSettings.kt @@ -12,7 +12,7 @@ import kotlin.time.Duration.Companion.minutes class DataStoreUserSettings( private val dataStore: DataStore ) : Settings.PlatformUserSettings { - override val aniList: Flow = dataStore.data.map { it.aniList } + override val aniList: Flow = dataStore.data.map { it.aniList }.distinctUntilChanged() private val clockNow = flow { do { emit(Clock.System.now()) @@ -24,7 +24,7 @@ class DataStoreUserSettings( clockNow ) { data, now -> data.accessToken != null && now.epochSeconds < (data.expires ?: 0) - } + }.distinctUntilChanged() override suspend fun setAniListAccessToken(token: String) { dataStore.updateData {