Skip to content

Commit

Permalink
toggle favorite on medium or character
Browse files Browse the repository at this point in the history
  • Loading branch information
DatL4g committed Apr 26, 2024
1 parent 1a288e5 commit e2ab9f5
Show file tree
Hide file tree
Showing 17 changed files with 135 additions and 107 deletions.
23 changes: 23 additions & 0 deletions anilist/src/commonMain/graphql/FavoriteToggleMutation.graphql
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
mutation FavoriteToggleMutation(
$animeId: Int,
$mangaId: Int,
$characterId: Int
) {
ToggleFavourite(animeId: $animeId, mangaId: $mangaId, characterId: $characterId) {
anime {
nodes {
id
}
},
manga {
nodes {
id
}
},
characters {
nodes {
id
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,19 +3,14 @@ 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.model.Medium
import dev.datlag.aniflow.anilist.type.AiringSort
import dev.datlag.aniflow.firebase.FirebaseFactory
import dev.datlag.aniflow.model.CatchResult
import dev.datlag.aniflow.model.mapError
import dev.datlag.aniflow.model.saveFirstOrNull
import dev.datlag.tooling.async.suspendCatching
import dev.datlag.aniflow.model.safeFirstOrNull
import dev.datlag.tooling.safeSubList
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.datetime.Clock
import kotlinx.datetime.TimeZone
import kotlinx.datetime.atStartOfDayIn
import kotlinx.datetime.toLocalDateTime
import kotlin.time.Duration.Companion.hours
import kotlin.time.Duration.Companion.seconds

Expand All @@ -42,11 +37,11 @@ class AiringTodayStateMachine(
val response = CatchResult.repeat(times = 2, timeoutDuration = 30.seconds) {
val query = client.query(state.snapshot.query)

query.execute().data ?: query.toFlow().saveFirstOrNull()?.dataOrThrow()
query.execute().data ?: query.toFlow().safeFirstOrNull()?.dataOrThrow()
}.mapError {
val query = fallbackClient.query(state.snapshot.query)

query.execute().data ?: query.toFlow().saveFirstOrNull()?.data
query.execute().data ?: query.toFlow().safeFirstOrNull()?.data
}.mapSuccess<State> {
val wantedContent = if (!state.snapshot.adultContent) {
val content = it.Page?.airingSchedulesFilterNotNull() ?: emptyList()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ internal object Cache {

suspend fun getTrending(key: TrendingQuery): TrendingQuery.Data? {
return suspendCatching {
trendingAnime.get(key)
trendingAnime.getIfAvailable(key)
}.getOrNull()
}

Expand All @@ -57,7 +57,7 @@ internal object Cache {

suspend fun getAiring(key: AiringQuery): AiringQuery.Data? {
return suspendCatching {
airing.get(key)
airing.getIfAvailable(key)
}.getOrNull()
}

Expand All @@ -69,7 +69,7 @@ internal object Cache {

suspend fun getSeason(key: SeasonQuery): SeasonQuery.Data? {
return suspendCatching {
season.get(key)
season.getIfAvailable(key)
}.getOrNull()
}

Expand All @@ -81,7 +81,7 @@ internal object Cache {

suspend fun getMedium(key: MediumQuery): Medium? {
return suspendCatching {
medium.get(key)
medium.getIfAvailable(key)
}.getOrNull()
}

Expand All @@ -93,7 +93,7 @@ internal object Cache {

suspend fun getCharacter(key: CharacterQuery) : Character? {
return suspendCatching {
character.get(key)
character.getIfAvailable(key)
}.getOrNull()
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,11 @@ package dev.datlag.aniflow.anilist
import com.apollographql.apollo3.ApolloClient
import com.apollographql.apollo3.api.Optional
import com.freeletics.flowredux.dsl.FlowReduxStateMachine
import com.freeletics.flowredux.dsl.State
import dev.datlag.aniflow.anilist.model.Character
import dev.datlag.aniflow.firebase.FirebaseFactory
import dev.datlag.aniflow.model.CatchResult
import dev.datlag.aniflow.model.mapError
import dev.datlag.aniflow.model.saveFirstOrNull
import dev.datlag.aniflow.model.safeFirstOrNull
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlin.time.Duration.Companion.seconds

Expand All @@ -32,18 +31,14 @@ class CharacterStateMachine(
currentState = it
}
onEnter { state ->
Cache.getCharacter(state.snapshot.query)?.let {
return@onEnter state.override { State.Success(state.snapshot.query, it) }
}

val response = CatchResult.repeat(2, timeoutDuration = 30.seconds) {
val query = client.query(state.snapshot.query)

query.execute().data ?: query.toFlow().saveFirstOrNull()?.dataOrThrow()
query.execute().data ?: query.toFlow().safeFirstOrNull()?.dataOrThrow()
}.mapError {
val query = fallbackClient.query(state.snapshot.query)

query.execute().data ?: query.toFlow().saveFirstOrNull()?.data
query.execute().data ?: query.toFlow().safeFirstOrNull()?.data
}.mapSuccess<State> {
it.Character?.let { data ->
Character(data)?.let { char ->
Expand All @@ -52,11 +47,17 @@ class CharacterStateMachine(
}
}

val cached = Cache.getCharacter(state.snapshot.query)

state.override {
response.asSuccess {
crashlytics?.log(it)

State.Error(query)
if (cached != null) {
State.Success(query, cached)
} else {
State.Error(query)
}
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,7 @@ import dev.datlag.aniflow.anilist.model.Medium
import dev.datlag.aniflow.firebase.FirebaseFactory
import dev.datlag.aniflow.model.CatchResult
import dev.datlag.aniflow.model.mapError
import dev.datlag.aniflow.model.saveFirstOrNull
import dev.datlag.tooling.async.suspendCatching
import dev.datlag.aniflow.model.safeFirstOrNull
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlin.time.Duration.Companion.seconds

Expand All @@ -35,11 +34,11 @@ class MediumStateMachine(
val response = CatchResult.repeat(times = 2, timeoutDuration = 30.seconds) {
val query = client.query(state.snapshot.query)

query.execute().data ?: query.toFlow().saveFirstOrNull()?.dataOrThrow()
query.execute().data ?: query.toFlow().safeFirstOrNull()?.dataOrThrow()
}.mapError {
val query = fallbackClient.query(state.snapshot.query)

query.execute().data ?: query.toFlow().saveFirstOrNull()?.data
query.execute().data ?: query.toFlow().safeFirstOrNull()?.data
}.mapSuccess<State> {
it.Media?.let { data ->
State.Success(state.snapshot.query, Medium(data))
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,7 @@ import dev.datlag.aniflow.anilist.state.SeasonState
import dev.datlag.aniflow.firebase.FirebaseFactory
import dev.datlag.aniflow.model.CatchResult
import dev.datlag.aniflow.model.mapError
import dev.datlag.aniflow.model.saveFirstOrNull
import dev.datlag.tooling.async.suspendCatching
import dev.datlag.aniflow.model.safeFirstOrNull
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlin.time.Duration.Companion.seconds

Expand All @@ -35,11 +34,11 @@ class PopularNextSeasonStateMachine(
val response = CatchResult.repeat(times = 2, timeoutDuration = 30.seconds) {
val query = client.query(state.snapshot.query)

query.execute().data ?: query.toFlow().saveFirstOrNull()?.dataOrThrow()
query.execute().data ?: query.toFlow().safeFirstOrNull()?.dataOrThrow()
}.mapError {
val query = fallbackClient.query(state.snapshot.query)

query.execute().data ?: query.toFlow().saveFirstOrNull()?.data
query.execute().data ?: query.toFlow().safeFirstOrNull()?.data
}.mapSuccess<SeasonState> {
SeasonState.Success(state.snapshot.query, it)
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,26 +1,14 @@
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.common.nextSeason
import dev.datlag.aniflow.anilist.common.season
import dev.datlag.aniflow.anilist.common.year
import dev.datlag.aniflow.anilist.state.SeasonAction
import dev.datlag.aniflow.anilist.state.SeasonState
import dev.datlag.aniflow.anilist.type.MediaSeason
import dev.datlag.aniflow.anilist.type.MediaSort
import dev.datlag.aniflow.anilist.type.MediaType
import dev.datlag.aniflow.firebase.FirebaseFactory
import dev.datlag.aniflow.model.CatchResult
import dev.datlag.aniflow.model.mapError
import dev.datlag.aniflow.model.saveFirstOrNull
import dev.datlag.tooling.async.suspendCatching
import dev.datlag.aniflow.model.safeFirstOrNull
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.datetime.Clock
import kotlinx.datetime.Instant
import kotlinx.datetime.TimeZone
import kotlinx.datetime.toLocalDateTime
import kotlin.time.Duration.Companion.seconds

@OptIn(ExperimentalCoroutinesApi::class)
Expand All @@ -46,11 +34,11 @@ class PopularSeasonStateMachine(
val response = CatchResult.repeat(times = 2, timeoutDuration = 30.seconds) {
val query = client.query(state.snapshot.query)

query.execute().data ?: query.toFlow().saveFirstOrNull()?.dataOrThrow()
query.execute().data ?: query.toFlow().safeFirstOrNull()?.dataOrThrow()
}.mapError {
val query = fallbackClient.query(state.snapshot.query)

query.execute().data ?: query.toFlow().saveFirstOrNull()?.data
query.execute().data ?: query.toFlow().safeFirstOrNull()?.data
}.mapSuccess<SeasonState> {
SeasonState.Success(state.snapshot.query, it)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,11 @@ package dev.datlag.aniflow.anilist
import com.apollographql.apollo3.ApolloClient
import com.apollographql.apollo3.annotations.ApolloExperimental
import com.apollographql.apollo3.api.Optional
import com.apollographql.apollo3.api.map
import com.freeletics.flowredux.dsl.FlowReduxStateMachine
import dev.datlag.aniflow.anilist.type.MediaSort
import dev.datlag.aniflow.anilist.type.MediaType
import dev.datlag.aniflow.firebase.FirebaseFactory
import dev.datlag.aniflow.model.*
import dev.datlag.tooling.async.suspendCatching
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlin.time.Duration.Companion.seconds

Expand All @@ -36,11 +34,11 @@ class TrendingAnimeStateMachine(
val response = CatchResult.repeat(2, timeoutDuration = 30.seconds) {
val query = client.query(state.snapshot.query)

query.execute().data ?: query.toFlow().saveFirstOrNull()?.dataOrThrow()
query.execute().data ?: query.toFlow().safeFirstOrNull()?.dataOrThrow()
}.mapError {
val query = fallbackClient.query(state.snapshot.query)

query.execute().data ?: query.toFlow().saveFirstOrNull()?.data
query.execute().data ?: query.toFlow().safeFirstOrNull()?.data
}.mapSuccess<State> {
State.Success(state.snapshot.query, it)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ 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.toInt
import kotlinx.datetime.Month
import kotlinx.serialization.Serializable
import kotlinx.serialization.Transient
Expand Down Expand Up @@ -244,7 +245,9 @@ data class Medium(
}

@Transient
val characters: Set<Character> = _characters.filterNot { it.id == 36309 }.toSet()
val characters: Set<Character> = _characters.filterNot { it.id == 36309 }.sortedByDescending {
it.isFavorite.toInt()
}.toSet()

@Transient
val isFavoriteBlocked: Boolean = _isFavoriteBlocked || type == MediaType.UNKNOWN__
Expand Down
Original file line number Diff line number Diff line change
@@ -1,14 +1,8 @@
package dev.datlag.aniflow.other

import dev.datlag.aniflow.model.saveFirstOrNull
import dev.datlag.aniflow.settings.DataStoreUserSettings
import dev.datlag.aniflow.model.safeFirstOrNull
import dev.datlag.aniflow.settings.Settings
import io.github.aakira.napier.Napier
import kotlinx.coroutines.flow.firstOrNull
import kotlinx.coroutines.sync.Mutex
import kotlinx.coroutines.sync.withLock
import kotlinx.datetime.Clock
import kotlinx.datetime.Instant
import org.publicvalue.multiplatform.oidc.OpenIdConnectClient
import org.publicvalue.multiplatform.oidc.tokenstore.OauthTokens
import org.publicvalue.multiplatform.oidc.types.remote.AccessTokenResponse
Expand All @@ -22,15 +16,15 @@ class TokenRefreshHandler(
private var memoryAccessToken: String? = null

suspend fun getAccessToken(): String? {
return storeUserSettings.aniList.saveFirstOrNull()?.accessToken?.ifBlank { null } ?: memoryAccessToken
return storeUserSettings.aniList.safeFirstOrNull()?.accessToken?.ifBlank { null } ?: memoryAccessToken
}

suspend fun refreshAndSaveToken(client: OpenIdConnectClient, oldAccessToken: String): OauthTokens {
return refreshAndSaveToken(client::refreshToken, oldAccessToken)
}

suspend fun refreshAndSaveToken(refreshCall: suspend (String) -> AccessTokenResponse, oldAccessToken: String): OauthTokens {
val storeData = storeUserSettings.aniList.saveFirstOrNull()
val storeData = storeUserSettings.aniList.safeFirstOrNull()
val currentTokens = storeData?.let {
OauthTokens(
accessToken = it.accessToken ?: return@let null,
Expand All @@ -45,7 +39,7 @@ class TokenRefreshHandler(
return if (currentTokens != null && currentTokens.accessToken != oldAccessToken && !requiresRefresh) {
currentTokens
} else {
val refreshToken = storeUserSettings.aniListRefreshToken.saveFirstOrNull()
val refreshToken = storeUserSettings.aniListRefreshToken.safeFirstOrNull()
val newTokens = refreshCall(refreshToken ?: "")
updateStoredToken(newTokens)
lastRefresh = Clock.System.now().epochSeconds.toInt()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,6 @@ import com.arkivanov.decompose.router.stack.pop
import com.arkivanov.decompose.router.stack.push
import dev.datlag.aniflow.common.onRender
import dev.datlag.aniflow.ui.navigation.screen.initial.InitialScreenComponent
import dev.datlag.aniflow.ui.navigation.screen.medium.MediumScreen
import dev.datlag.aniflow.ui.navigation.screen.medium.MediumScreenComponent
import org.kodein.di.DI

Expand Down
Loading

0 comments on commit e2ab9f5

Please sign in to comment.