Skip to content

Commit

Permalink
airing repository re-write with flowredux
Browse files Browse the repository at this point in the history
  • Loading branch information
DatL4g committed May 21, 2024
1 parent 03a0168 commit 17185f7
Show file tree
Hide file tree
Showing 11 changed files with 217 additions and 156 deletions.
4 changes: 2 additions & 2 deletions anilist/src/commonMain/graphql/AiringQuery.graphql
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
query AiringQuery(
$page: Int,
$perPage: Int,
$statusVersion: Int,
$html: Boolean,
$statusVersion: Int!,
$html: Boolean!,
$sort: [AiringSort],
$airingAtGreater: Int
) {
Expand Down

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
package dev.datlag.aniflow.anilist

import com.apollographql.apollo3.ApolloClient
import com.freeletics.flowredux.dsl.FlowReduxStateMachine
import dev.datlag.aniflow.anilist.model.PageAiringQuery
import dev.datlag.aniflow.anilist.state.HomeAiringState
import dev.datlag.aniflow.anilist.state.HomeDefaultAction
import dev.datlag.aniflow.firebase.FirebaseFactory
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.distinctUntilChanged
import kotlinx.coroutines.flow.flowOf
import kotlinx.coroutines.flow.mapLatest

@OptIn(ExperimentalCoroutinesApi::class)
class AiringTodayStateMachine(
private val client: ApolloClient,
private val fallbackClient: ApolloClient,
private val nsfw: Flow<Boolean> = flowOf(false),
private val crashlytics: FirebaseFactory.Crashlytics?
) : FlowReduxStateMachine<HomeAiringState, HomeDefaultAction>(
initialState = currentState
) {

var currentState: HomeAiringState
get() = Companion.currentState
private set(value) {
Companion.currentState = value
}

private val query = nsfw.distinctUntilChanged().mapLatest {
PageAiringQuery.Today(
nsfw = it
)
}.distinctUntilChanged()

init {
spec {
inState<HomeAiringState> {
onEnterEffect {
currentState = it
}
collectWhileInState(query) { q, state ->
state.override {
HomeAiringState.Loading(
query = q,
fallback = false
)
}
}
}
inState<HomeAiringState.Loading> {
collectWhileInState(
flowBuilder = {
val usedClient = if (it.fallback) {
fallbackClient
} else {
client
}

usedClient.query(it.query.toGraphQL()).toFlow()
}
) { response, state ->
state.override {
fromGraphQL(response)
}
}
}
inState<HomeAiringState.Error> {
onEnterEffect {
crashlytics?.log(it.throwable)
}
}
}
}

companion object {
var currentState: HomeAiringState
get() = StateSaver.airingState
private set(value) {
StateSaver.airingState = value
}
}
}
Original file line number Diff line number Diff line change
@@ -1,8 +1,11 @@
package dev.datlag.aniflow.anilist

import dev.datlag.aniflow.anilist.state.HomeAiringState
import dev.datlag.aniflow.anilist.state.HomeDefaultState

internal object StateSaver {
var airingState: HomeAiringState = HomeAiringState.None

var trendingState: HomeDefaultState = HomeDefaultState.None
var popularSeasonState: HomeDefaultState = HomeDefaultState.None
var popularNextSeasonState: HomeDefaultState = HomeDefaultState.None
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
package dev.datlag.aniflow.anilist.model

import com.apollographql.apollo3.api.Optional
import dev.datlag.aniflow.anilist.AiringQuery
import dev.datlag.aniflow.anilist.common.presentAsList
import dev.datlag.aniflow.anilist.type.AiringSort
import kotlinx.datetime.Clock
import kotlin.time.Duration.Companion.hours
import dev.datlag.aniflow.anilist.AiringQuery as AiringGraphQL

sealed interface PageAiringQuery {

val nsfw: Boolean

fun toGraphQL(): AiringGraphQL

data class Today(
override val nsfw: Boolean
) : PageAiringQuery {
override fun toGraphQL() = AiringQuery(
perPage = Optional.present(20),
sort = Optional.presentAsList(AiringSort.TIME),
airingAtGreater = Optional.present(
Clock.System.now().minus(1.hours).epochSeconds.toInt()
),
statusVersion = 2,
html = true
)
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
package dev.datlag.aniflow.anilist.state

import com.apollographql.apollo3.api.ApolloResponse
import dev.datlag.aniflow.anilist.AdultContent
import dev.datlag.aniflow.anilist.model.PageAiringQuery

import dev.datlag.aniflow.anilist.AiringQuery as PageAiringGraphQL

sealed interface HomeAiringState {

val isLoading: Boolean
get() = this !is PostLoading

val isError: Boolean
get() = this is Error

data object None : HomeAiringState

data class Loading(
internal val query: PageAiringQuery,
internal val fallback: Boolean
) : HomeAiringState {

private val nsfw: Boolean
get() = query.nsfw

fun fromGraphQL(response: ApolloResponse<PageAiringGraphQL.Data>): HomeAiringState {
val data = response.data

return if (data == null) {
if (fallback) {
Error(throwable = response.exception)
} else {
copy(fallback = true)
}
} else {
val airingList = data.Page?.airingSchedulesFilterNotNull()?.mapNotNull {
if (nsfw) {
it
} else {
if (AdultContent.isAdultContent(it)) {
null
} else {
it
}
}
}

if (airingList.isNullOrEmpty()) {
if (fallback) {
Error(throwable = response.exception)
} else {
copy(fallback = true)
}
} else {
Success(airingList)
}
}
}
}

private sealed interface PostLoading : HomeAiringState

data class Success(
val collection: Collection<PageAiringGraphQL.AiringSchedule>
) : PostLoading

data class Error(
internal val throwable: Throwable?
) : PostLoading
}
Original file line number Diff line number Diff line change
Expand Up @@ -125,15 +125,6 @@ data object NetworkModule {
baseUrl("https://api.nekosapi.com/v3/")
}.create<Nekos>()
}
bindSingleton<AiringTodayRepository> {
val appSettings = instance<Settings.PlatformAppSettings>()

AiringTodayRepository(
apolloClient = instance(Constants.AniList.APOLLO_CLIENT),
fallbackClient = instance(Constants.AniList.FALLBACK_APOLLO_CLIENT),
nsfw = appSettings.adultContent
)
}
bindSingleton<CharacterRepository> {
CharacterRepository(
client = instance<ApolloClient>(Constants.AniList.APOLLO_CLIENT).newBuilder().fetchPolicy(FetchPolicy.NetworkFirst).build(),
Expand Down Expand Up @@ -228,5 +219,15 @@ data object NetworkModule {
crashlytics = nullableFirebaseInstance()?.crashlytics
)
}
bindProvider<AiringTodayStateMachine> {
val appSettings = instance<Settings.PlatformAppSettings>()

AiringTodayStateMachine(
client = instance(Constants.AniList.APOLLO_CLIENT),
fallbackClient = instance(Constants.AniList.FALLBACK_APOLLO_CLIENT),
nsfw = appSettings.adultContent,
crashlytics = nullableFirebaseInstance()?.crashlytics
)
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import com.mayakapps.kache.InMemoryKache
import com.mayakapps.kache.KacheStrategy
import dev.datlag.aniflow.anilist.*
import dev.datlag.aniflow.anilist.state.CollectionState
import dev.datlag.aniflow.anilist.state.HomeAiringState
import dev.datlag.aniflow.anilist.state.HomeDefaultAction
import dev.datlag.aniflow.anilist.state.HomeDefaultState
import dev.datlag.aniflow.settings.model.AppSettings
Expand Down Expand Up @@ -70,7 +71,7 @@ data object StateSaver {
t1 && t2 && t3 && t4
}.flowOn(ioDispatcher()).distinctUntilChanged()

fun updateAiring(state: AiringTodayRepository.State): AiringTodayRepository.State {
fun updateAiring(state: HomeAiringState): HomeAiringState {
airingLoading.update { false }
return state
}
Expand Down
Loading

0 comments on commit 17185f7

Please sign in to comment.