Skip to content

Commit

Permalink
added character dialog
Browse files Browse the repository at this point in the history
  • Loading branch information
DatL4g committed Apr 22, 2024
1 parent aefeea5 commit cd653cc
Show file tree
Hide file tree
Showing 34 changed files with 736 additions and 164 deletions.
1 change: 1 addition & 0 deletions anilist/src/commonMain/graphql/MediumQuery.graphql
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ query MediumQuery($id: Int, $statusVersion: Int, $html: Boolean) {
genres,
characters(sort: [FAVOURITES_DESC,RELEVANCE]) {
nodes {
id,
name {
first,
middle
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ class AiringTodayStateMachine(
}.mapError {
val query = fallbackClient.query(state.snapshot.query)

query.execute().data ?: query.toFlow().saveFirstOrNull()?.dataOrThrow()
query.execute().data ?: query.toFlow().saveFirstOrNull()?.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 @@ -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 com.freeletics.flowredux.dsl.State
import dev.datlag.aniflow.anilist.model.Character
import dev.datlag.aniflow.firebase.FirebaseFactory
import dev.datlag.aniflow.model.CatchResult
Expand All @@ -15,21 +16,17 @@ import kotlin.time.Duration.Companion.seconds
class CharacterStateMachine(
private val client: ApolloClient,
private val fallbackClient: ApolloClient,
private val crashlytics: FirebaseFactory.Crashlytics?
private val crashlytics: FirebaseFactory.Crashlytics?,
private val id: Int
) : FlowReduxStateMachine<CharacterStateMachine.State, CharacterStateMachine.Action>(
initialState = currentState
initialState = State.Loading(id)
) {

var currentState: State = State.Loading(id)
private set

init {
spec {
inState<State.Waiting> {
onEnterEffect {
currentState = it
}
on<Action.Load> { action, state ->
state.override { State.Loading(action.id) }
}
}
inState<State.Loading> {
onEnterEffect {
currentState = it
Expand All @@ -46,18 +43,20 @@ class CharacterStateMachine(
}.mapError {
val query = fallbackClient.query(state.snapshot.query)

query.execute().data ?: query.toFlow().saveFirstOrNull()?.dataOrThrow()
query.execute().data ?: query.toFlow().saveFirstOrNull()?.data
}.mapSuccess<State> {
it.Character?.let { data ->
State.Success(state.snapshot.query, Character(data))
Character(data)?.let { char ->
State.Success(state.snapshot.query, char)
}
}
}

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

State.Error
State.Error(query)
}
}
}
Expand All @@ -67,46 +66,39 @@ class CharacterStateMachine(
Cache.setCharacter(it.query, it.character)
currentState = it
}
on<Action.Load> { action, state ->
state.override { State.Loading(action.id) }
}
}
inState<State.Error> {
onEnterEffect {
currentState = it
}
on<Action.Load> { action, state ->
state.override { State.Loading(action.id) }
on<Action.Retry> { _, state ->
state.override {
State.Loading(state.snapshot.query)
}
}
}
}
}

sealed interface State {
data object Waiting : State
data class Loading(internal val query: CharacterQuery) : State {
constructor(id: Int) : this(
query = CharacterQuery(
id = Optional.present(id)
id = Optional.present(id),
html = Optional.present(true)
)
)
}
data class Success(
internal val query: CharacterQuery,
val character: Character
) : State
data object Error : State
data class Error(
internal val query: CharacterQuery,
) : State
}

sealed interface Action {
data class Load(val id: Int) : Action
}

companion object {
var currentState: State
get() = StateSaver.character
set(value) {
StateSaver.character = value
}
data object Retry : Action
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ class MediumStateMachine(
}.mapError {
val query = fallbackClient.query(state.snapshot.query)

query.execute().data ?: query.toFlow().saveFirstOrNull()?.dataOrThrow()
query.execute().data ?: query.toFlow().saveFirstOrNull()?.data
}.mapSuccess<State> {
it.Media?.let { data ->
State.Success(state.snapshot.query, Medium.Full(data))
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ class PopularNextSeasonStateMachine(
}.mapError {
val query = fallbackClient.query(state.snapshot.query)

query.execute().data ?: query.toFlow().saveFirstOrNull()?.dataOrThrow()
query.execute().data ?: query.toFlow().saveFirstOrNull()?.data
}.mapSuccess<SeasonState> {
SeasonState.Success(state.snapshot.query, it)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ class PopularSeasonStateMachine(
}.mapError {
val query = fallbackClient.query(state.snapshot.query)

query.execute().data ?: query.toFlow().saveFirstOrNull()?.dataOrThrow()
query.execute().data ?: query.toFlow().saveFirstOrNull()?.data
}.mapSuccess<SeasonState> {
SeasonState.Success(state.snapshot.query, it)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,5 +17,4 @@ internal object StateSaver {
year = nextYear
)
}
var character: CharacterStateMachine.State = CharacterStateMachine.State.Waiting
}
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ class TrendingAnimeStateMachine(
}.mapError {
val query = fallbackClient.query(state.snapshot.query)

query.execute().data ?: query.toFlow().saveFirstOrNull()?.dataOrThrow()
query.execute().data ?: query.toFlow().saveFirstOrNull()?.data
}.mapSuccess<State> {
State.Success(state.snapshot.query, it)
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,17 +1,204 @@
package dev.datlag.aniflow.anilist.model

import dev.datlag.aniflow.anilist.CharacterQuery
import dev.datlag.aniflow.anilist.MediumQuery
import kotlinx.serialization.Serializable

@Serializable
open class Character(
/**
* The id of the character
*/
open val id: Int,

/**
* The names of the character
*/
open val name: Name,

/**
* Character images
*/
open val image: Image,

/**
* The character's gender.
* Usually Male, Female, or Non-binary but can be any string.
*/
open val gender: String?,

/**
* The characters blood type
*/
open val bloodType: String?,

/**
* The character's birthdate
*/
open val birthDate: Character.BirthDate?,

/**
* A general description of the character
*/
open val description: String?,
) {
constructor(char: CharacterQuery.Character) : this(
id = char.id,
gender = char.gender?.ifBlank { null },
bloodType = char.bloodType?.ifBlank { null },
)
}

@Serializable
data class Name(
/**
* The character's given name
*/
val first: String?,

/**
* The character's middle name
*/
val middle: String?,

/**
* The character's surname
*/
val last: String?,

/**
* The character's first and last name
*/
val full: String?,

/**
* The character's full name in their native language
*/
val native: String?,

/**
* The currently authenticated users preferred name language. Default romaji for
* non-authenticated
*/
val userPreferred: String?
) {
constructor(name: MediumQuery.Name) : this(
first = name.first?.ifBlank { null },
middle = name.middle?.ifBlank { null },
last = name.last?.ifBlank { null },
full = name.full?.ifBlank { null },
native = name.native?.ifBlank { null },
userPreferred = name.userPreferred?.ifBlank { null }
)

constructor(name: CharacterQuery.Name) : this(
first = name.first?.ifBlank { null },
middle = name.middle?.ifBlank { null },
last = name.last?.ifBlank { null },
full = name.full?.ifBlank { null },
native = name.native?.ifBlank { null },
userPreferred = name.userPreferred?.ifBlank { null }
)
}

@Serializable
data class Image(
val large: String?,
val medium: String?
) {
constructor(image: MediumQuery.Image) : this(
large = image.large?.ifBlank { null },
medium = image.medium?.ifBlank { null }
)

constructor(image: CharacterQuery.Image) : this(
large = image.large?.ifBlank { null },
medium = image.medium?.ifBlank { null },
)
}

@Serializable
data class BirthDate(
val day: Int?,
val month: Int?,
val year: Int?
) {
fun format(): String {
return buildString {
if (day != null) {
if (day <= 9) {
append("0$day")
} else {
append(day)
}
append(". ")
}
if (month != null) {
when (month) {
1 -> append("Jan")
2 -> append("Feb")
3 -> append("Mar")
4 -> append("Apr")
5 -> append("May")
6 -> append("Jun")
7 -> append("Jul")
8 -> append("Aug")
9 -> append("Sep")
10 -> append("Oct")
11 -> append("Nov")
12 -> append("Dec")
else -> if (month <= 9) {
append("0$month.")
} else {
append("$month.")
}
}
append(' ')
}
if (year != null) {
append(year)
}
}.trim()
}

companion object {
operator fun invoke(birth: CharacterQuery.DateOfBirth) : BirthDate? {
if (birth.day == null && birth.month == null && birth.year == null) {
return null
}

return BirthDate(
day = birth.day,
month = birth.month,
year = birth.year
)
}
}
}

companion object {
operator fun invoke(character: MediumQuery.Node) : Character? {
val name = character.name?.let(::Name) ?: return null
val image = character.image?.let(::Image) ?: return null

return Character(
id = character.id,
name = name,
image = image,
gender = null,
bloodType = null,
birthDate = null,
description = null
)
}

operator fun invoke(character: CharacterQuery.Character) : Character? {
val name = character.name?.let(::Name) ?: return null
val image = character.image?.let(::Image) ?: return null

return Character(
id = character.id,
name = name,
image = image,
gender = character.gender?.ifBlank { null },
bloodType = character.bloodType?.ifBlank { null },
birthDate = character.dateOfBirth?.let { BirthDate(it) },
description = character.description?.ifBlank { null }
)
}
}
}
Loading

0 comments on commit cd653cc

Please sign in to comment.