Skip to content

Commit

Permalink
improve home performance
Browse files Browse the repository at this point in the history
  • Loading branch information
DatL4g committed Apr 29, 2024
1 parent d69d509 commit 455003e
Show file tree
Hide file tree
Showing 24 changed files with 317 additions and 249 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package dev.datlag.aniflow.anilist
import com.apollographql.apollo3.ApolloClient
import com.apollographql.apollo3.api.Optional
import com.freeletics.flowredux.dsl.FlowReduxStateMachine
import dev.datlag.aniflow.anilist.state.CommonState
import dev.datlag.aniflow.anilist.type.AiringSort
import dev.datlag.aniflow.firebase.FirebaseFactory
import dev.datlag.aniflow.model.CatchResult
Expand Down Expand Up @@ -98,7 +99,11 @@ class AiringTodayStateMachine(
}
}

sealed interface State {
sealed interface State : CommonState {

override val isLoadingOrWaiting: Boolean
get() = this is Loading

data class Loading(
internal val query: AiringQuery,
val adultContent: Boolean = false
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import com.apollographql.apollo3.ApolloClient
import com.apollographql.apollo3.annotations.ApolloExperimental
import com.apollographql.apollo3.api.Optional
import com.freeletics.flowredux.dsl.FlowReduxStateMachine
import dev.datlag.aniflow.anilist.state.CommonState
import dev.datlag.aniflow.anilist.type.MediaSort
import dev.datlag.aniflow.anilist.type.MediaType
import dev.datlag.aniflow.firebase.FirebaseFactory
Expand Down Expand Up @@ -73,7 +74,11 @@ class TrendingAnimeStateMachine(
}
}

sealed interface State {
sealed interface State : CommonState {

override val isLoadingOrWaiting: Boolean
get() = this is Loading

data class Loading(
internal val query: TrendingQuery
) : State {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,10 @@ import dev.datlag.aniflow.anilist.type.MediaFormat
import dev.datlag.aniflow.anilist.type.MediaRankType
import dev.datlag.aniflow.anilist.type.MediaStatus
import dev.datlag.aniflow.anilist.type.MediaType
import dev.datlag.aniflow.model.ifValue
import dev.datlag.aniflow.model.toInt
import kotlinx.datetime.Clock
import kotlinx.datetime.Instant
import kotlinx.datetime.Month
import kotlinx.serialization.Serializable
import kotlinx.serialization.Transient
Expand All @@ -19,7 +22,7 @@ data class Medium(
val type: MediaType = MediaType.UNKNOWN__,
val status: MediaStatus = MediaStatus.UNKNOWN__,
val description: String? = null,
val episodes: Int = -1,
private val _episodes: Int = -1,
val avgEpisodeDurationInMin: Int = -1,
val format: MediaFormat = MediaFormat.UNKNOWN__,
private val _isAdult: Boolean = false,
Expand Down Expand Up @@ -54,7 +57,7 @@ data class Medium(
type = trending.type ?: MediaType.UNKNOWN__,
status = trending.status ?: MediaStatus.UNKNOWN__,
description = trending.description?.ifBlank { null },
episodes = trending.episodes ?: -1,
_episodes = trending.episodes ?: -1,
avgEpisodeDurationInMin = trending.duration ?: -1,
format = trending.format ?: MediaFormat.UNKNOWN__,
_isAdult = trending.isAdult ?: false,
Expand Down Expand Up @@ -103,7 +106,7 @@ data class Medium(
type = airing.type ?: MediaType.UNKNOWN__,
status = airing.status ?: MediaStatus.UNKNOWN__,
description = airing.description?.ifBlank { null },
episodes = airing.episodes ?: -1,
_episodes = airing.episodes ?: -1,
avgEpisodeDurationInMin = airing.duration ?: -1,
format = airing.format ?: MediaFormat.UNKNOWN__,
_isAdult = airing.isAdult ?: false,
Expand Down Expand Up @@ -152,7 +155,7 @@ data class Medium(
type = season.type ?: MediaType.UNKNOWN__,
status = season.status ?: MediaStatus.UNKNOWN__,
description = season.description?.ifBlank { null },
episodes = season.episodes ?: -1,
_episodes = season.episodes ?: -1,
avgEpisodeDurationInMin = season.duration ?: -1,
format = season.format ?: MediaFormat.UNKNOWN__,
_isAdult = season.isAdult ?: false,
Expand Down Expand Up @@ -201,7 +204,7 @@ data class Medium(
type = query.type ?: MediaType.UNKNOWN__,
status = query.status ?: MediaStatus.UNKNOWN__,
description = query.description?.ifBlank { null },
episodes = query.episodes ?: -1,
_episodes = query.episodes ?: -1,
avgEpisodeDurationInMin = query.duration ?: -1,
format = query.format ?: MediaFormat.UNKNOWN__,
_isAdult = query.isAdult ?: false,
Expand Down Expand Up @@ -255,6 +258,17 @@ data class Medium(
@Transient
val isFavoriteBlocked: Boolean = _isFavoriteBlocked || type == MediaType.UNKNOWN__

val episodes: Int
get() = _episodes.ifValue(-1) {
nextAiringEpisode?.let {
if (Instant.fromEpochSeconds(it.airingAt.toLong()) <= Clock.System.now()) {
it.episodes
} else {
it.episodes - 1
}
} ?: -1
}

@Serializable
data class Title(
/**
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
package dev.datlag.aniflow.anilist.state

interface CommonState {
val isLoadingOrWaiting: Boolean
}
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,11 @@ import dev.datlag.aniflow.anilist.type.MediaType
import kotlinx.datetime.Clock
import kotlinx.datetime.Instant

sealed interface SeasonState {
sealed interface SeasonState : CommonState {

override val isLoadingOrWaiting: Boolean
get() = this is Loading

data class Loading(
internal val query: SeasonQuery
) : SeasonState {
Expand Down
63 changes: 4 additions & 59 deletions composeApp/src/commonMain/kotlin/dev/datlag/aniflow/App.kt
Original file line number Diff line number Diff line change
Expand Up @@ -14,13 +14,13 @@ import androidx.compose.ui.graphics.Color
import androidx.compose.ui.text.font.FontFamily
import androidx.compose.ui.text.font.FontStyle
import androidx.compose.ui.text.font.FontWeight
import com.materialkolor.*
import dev.chrisbanes.haze.HazeState
import dev.datlag.aniflow.common.toComposeColor
import dev.datlag.aniflow.settings.Settings
import dev.datlag.aniflow.settings.model.AppSettings
import dev.datlag.aniflow.ui.theme.Colors
import dev.datlag.aniflow.ui.theme.CommonSchemeTheme
import dev.datlag.aniflow.ui.theme.DynamicMaterialTheme
import dev.datlag.tooling.compose.toTypography
import dev.datlag.tooling.decompose.lifecycle.collectAsStateWithLifecycle
import dev.icerock.moko.resources.compose.asFont
Expand Down Expand Up @@ -54,59 +54,9 @@ internal fun App(
appSettings.color
}.collectAsStateWithLifecycle(null)
val seedColor = remember(savedColor) { savedColor?.toComposeColor() }
val dynamicColorScheme = if (seedColor != null) {
rememberDynamicColorScheme(
seedColor = seedColor,
isDark = LocalDarkMode.current,
style = PaletteStyle.TonalSpot,
contrastLevel = Contrast.Default.value,
isExtendedFidelity = false
)
} else {
MaterialTheme.colorScheme
}
val animationSpec: AnimationSpec<Color> = 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),
)

MaterialTheme(
colorScheme = colorScheme
DynamicMaterialTheme(
seedColor = seedColor
) {
CommonSchemeTheme {
Surface(
Expand Down Expand Up @@ -151,9 +101,4 @@ fun ManropeFontFamily(): FontFamily {
}

@Composable
expect fun SystemAppearance(isDark: Boolean = LocalDarkMode.current)

@Composable
private fun Color.animate(animationSpec: AnimationSpec<Color>): Color {
return animateColorAsState(this, animationSpec).value
}
expect fun SystemAppearance(isDark: Boolean = LocalDarkMode.current)
Original file line number Diff line number Diff line change
Expand Up @@ -145,11 +145,6 @@ fun Modifier.shimmer(shape: Shape = RectangleShape): Modifier = composed {
)
}

@Composable
fun shimmerPainter(): BrushPainter {
return BrushPainter(shimmerBrush())
}


@Composable
fun LazyListState.isScrollingUp(): Boolean {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,15 @@
package dev.datlag.aniflow.other

import dev.datlag.aniflow.anilist.AiringTodayStateMachine
import dev.datlag.aniflow.anilist.PopularNextSeasonStateMachine
import dev.datlag.aniflow.anilist.PopularSeasonStateMachine
import dev.datlag.aniflow.anilist.TrendingAnimeStateMachine
import dev.datlag.aniflow.anilist.state.SeasonState
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.combine
import kotlinx.coroutines.flow.update
import kotlinx.coroutines.flow.updateAndGet

data object StateSaver {
var sekretLibraryLoaded: Boolean = false

Expand Down Expand Up @@ -27,4 +37,54 @@ data object StateSaver {
var popularNextOverviewOffset: Int = 0
}
}

data object Home {
private val _airingState = MutableStateFlow(airingState)
private val _trendingState = MutableStateFlow(trendingState)
private val _popularCurrentState = MutableStateFlow(popularCurrentState)
private val _popularNextState = MutableStateFlow(popularNextState)

val airingState: AiringTodayStateMachine.State
get() = AiringTodayStateMachine.currentState

val trendingState: TrendingAnimeStateMachine.State
get() = TrendingAnimeStateMachine.currentState

val popularCurrentState: SeasonState
get() = PopularSeasonStateMachine.currentState

val popularNextState: SeasonState
get() = PopularNextSeasonStateMachine.currentState

val currentAllLoading: Boolean
get() = _airingState.value.isLoadingOrWaiting
&& _trendingState.value.isLoadingOrWaiting
&& _popularCurrentState.value.isLoadingOrWaiting
&& _popularNextState.value.isLoadingOrWaiting

val isAllLoading = combine(
_airingState,
_trendingState,
_popularCurrentState,
_popularNextState
) { t1, t2, t3, t4 ->
t1.isLoadingOrWaiting && t2.isLoadingOrWaiting && t3.isLoadingOrWaiting && t4.isLoadingOrWaiting
}

fun updateAiring(state: AiringTodayStateMachine.State) = _airingState.updateAndGet {
state
}

fun updateTrending(state: TrendingAnimeStateMachine.State) = _trendingState.updateAndGet {
state
}

fun updatePopularCurrent(state: SeasonState) = _popularCurrentState.updateAndGet {
state
}

fun updatePopularNext(state: SeasonState) = _popularNextState.updateAndGet {
state
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -11,14 +11,16 @@ import dev.datlag.aniflow.trace.TraceStateMachine
import dev.datlag.aniflow.ui.navigation.Component
import dev.datlag.aniflow.ui.navigation.ContentHolderComponent
import io.ktor.utils.io.*
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.StateFlow

interface HomeComponent : ContentHolderComponent {
val airingState: StateFlow<AiringTodayStateMachine.State>
val trendingState: StateFlow<TrendingAnimeStateMachine.State>
val popularSeasonState: StateFlow<SeasonState>
val popularNextSeasonState: StateFlow<SeasonState>
val airingState: Flow<AiringTodayStateMachine.State>
val trendingState: Flow<TrendingAnimeStateMachine.State>
val popularSeasonState: Flow<SeasonState>
val popularNextSeasonState: Flow<SeasonState>

val traceState: Flow<TraceStateMachine.State>

fun details(medium: Medium)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,11 @@ package dev.datlag.aniflow.ui.navigation.screen.initial.home
import androidx.compose.animation.AnimatedVisibility
import androidx.compose.animation.fadeIn
import androidx.compose.animation.fadeOut
import androidx.compose.foundation.background
import androidx.compose.foundation.layout.*
import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.foundation.lazy.rememberLazyListState
import androidx.compose.foundation.shape.CircleShape
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.Camera
import androidx.compose.material.icons.filled.CameraEnhance
Expand All @@ -14,7 +16,9 @@ import androidx.compose.material3.windowsizeclass.ExperimentalMaterial3WindowSiz
import androidx.compose.material3.windowsizeclass.WindowWidthSizeClass
import androidx.compose.material3.windowsizeclass.calculateWindowSizeClass
import androidx.compose.runtime.*
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.clip
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.unit.dp
import com.arkivanov.decompose.extensions.compose.subscribeAsState
Expand Down Expand Up @@ -46,7 +50,24 @@ import dev.icerock.moko.resources.compose.stringResource

@Composable
fun HomeScreen(component: HomeComponent) {
MainView(component, Modifier.fillMaxWidth())
val isAllLoading by StateSaver.Home.isAllLoading.collectAsStateWithLifecycle(StateSaver.Home.currentAllLoading)

Box(
modifier = Modifier.fillMaxSize()
) {
MainView(component, Modifier.fillMaxWidth())

if (isAllLoading) {
Box(
modifier = Modifier.fillMaxSize().background(MaterialTheme.colorScheme.background),
contentAlignment = Alignment.Center
) {
LinearProgressIndicator(
modifier = Modifier.fillMaxWidth(fraction = 0.2F).clip(CircleShape)
)
}
}
}
}

@OptIn(ExperimentalMaterial3Api::class)
Expand Down
Loading

0 comments on commit 455003e

Please sign in to comment.