Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions api/anilist/src/main/graphql/fragments/User.graphql
Original file line number Diff line number Diff line change
Expand Up @@ -34,4 +34,12 @@ fragment User on User {
}
}
}
mediaListOptions {
animeList {
sectionOrder
}
mangaList {
sectionOrder
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ class AnilistUserRepository(
type: MediaType?,
useNetwork: Boolean,
language: Media.Language = Media.Language.DEFAULT,
mediaListOrder: List<String>
): Flow<Result<User.MediaCollection>> {
return apolloClient.query(
UserMediaListQuery(
Expand All @@ -55,6 +56,6 @@ class AnilistUserRepository(
)
.toFlow()
.filter { it.exception == null }
.asResult { User.MediaCollection(it, type, language) }
.asResult { User.MediaCollection(it, type, language, mediaListOrder) }
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import com.imashnake.animite.api.anilist.sanitize.profile.User.ListNames.Compani
import com.imashnake.animite.api.anilist.type.MediaType
import kotlinx.collections.immutable.ImmutableList
import kotlinx.collections.immutable.toImmutableList
import kotlin.collections.indexOf
import kotlin.time.Duration.Companion.minutes
import kotlin.time.DurationUnit

Expand Down Expand Up @@ -48,6 +49,13 @@ data class User(
val genres: ImmutableList<Genre>,
// endregion

// region Anime
/** @see User.AnimeList.sectionOrder */
val animeListOrder: List<String>,
/** @see User.MangaList.sectionOrder */
val mangaListOrder: List<String>,
// endregion

// region Fave
/** @see User.favourites */
val favourites: ImmutableList<FavouriteCollection.FavouriteList>,
Expand Down Expand Up @@ -102,10 +110,13 @@ data class User(
internal constructor(
query: UserMediaListQuery.Data,
type: MediaType?,
language: Language
language: Language,
mediaListOrder: List<String>
) : this(
type = type?.name?.let { Type.valueOf(it) } ?: Type.UNKNOWN,
namedLists = query.mediaListCollection?.lists.orEmpty().mapNotNull {
namedLists = query.mediaListCollection?.lists.orEmpty().sortedBy {
mediaListOrder.indexOf(it?.name)
}.mapNotNull {
NamedTrackingList(it ?: return@mapNotNull null, language)
}.toImmutableList()
)
Expand Down Expand Up @@ -182,6 +193,8 @@ data class User(
it.mediaCount > totalCount/20
}.sortedByDescending { it.mediaCount }
}.toImmutableList(),
animeListOrder = query.mediaListOptions?.animeList?.sectionOrder.orEmpty().filterNotNull(),
mangaListOrder = query.mediaListOptions?.mangaList?.sectionOrder.orEmpty().filterNotNull(),
favourites = listOfNotNull(
query.favourites?.anime?.let { FavouriteCollection.FavouriteList(it, language) }.takeIf { it?.list?.isNotEmpty() == true },
query.favourites?.manga?.let { FavouriteCollection.FavouriteList(it, language) }.takeIf { it?.list?.isNotEmpty() == true },
Expand Down
2 changes: 2 additions & 0 deletions api/preferences/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ plugins {
alias(libs.plugins.android.libraryMultiplatform)
alias(libs.plugins.kotlin.multiplatform)
alias(libs.plugins.detekt)
alias(libs.plugins.kotlin.serialization)
}

kotlin {
Expand All @@ -14,6 +15,7 @@ kotlin {
sourceSets {
commonMain.dependencies {
implementation(libs.datastore)
implementation(libs.kotlinx.serialization.json)
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import androidx.datastore.preferences.core.stringPreferencesKey
import com.imashnake.animite.api.preferences.ext.getValue
import com.imashnake.animite.api.preferences.ext.setValue
import kotlinx.coroutines.flow.firstOrNull
import kotlinx.serialization.json.Json

private const val DEFAULT_THEME_KEY = "DEVICE_THEME"
private const val DEFAULT_DENSITY_KEY = "COMFY"
Expand Down Expand Up @@ -87,6 +88,18 @@ class PreferencesRepository internal constructor(
dataStore.setValue(viewerIdKey, viewerId.toString())
}

private val animeListOrderKey = stringPreferencesKey("anime_list_order")
val animeListOrder = dataStore.getValue(animeListOrderKey, null)
suspend fun setAnimeListOrder(animeListOrder: List<String>?) {
dataStore.setValue(animeListOrderKey, Json.encodeToString(animeListOrder))
}

private val mangaListOrderKey = stringPreferencesKey("manga_list_order")
val mangaListOrder = dataStore.getValue(mangaListOrderKey, null)
suspend fun setMangaListOrder(mangaListOrder: List<String>?) {
dataStore.setValue(mangaListOrderKey, Json.encodeToString(mangaListOrder))
}

private val viewerAvatarKey = stringPreferencesKey("viewer_avatar")
val viewerAvatar = dataStore.getValue(viewerAvatarKey, null)
suspend fun setViewerAvatar(avatarUrl: String?) {
Expand Down
1 change: 1 addition & 0 deletions gradle/libs.versions.toml
Original file line number Diff line number Diff line change
Expand Up @@ -148,6 +148,7 @@ kotlinx-collectionsImmutable = { group = "org.jetbrains.kotlinx", name = "kotlin
kotlinx-coroutines-android = { group = "org.jetbrains.kotlinx", name = "kotlinx-coroutines-android", version.ref = "coroutines" }
kotlinx-coroutines-core = { group = "org.jetbrains.kotlinx", name = "kotlinx-coroutines-core", version.ref = "coroutines" }
kotlinx-serialization-core = { group = "org.jetbrains.kotlinx", name = "kotlinx-serialization-core", version.ref = "serialization" }
kotlinx-serialization-json = { group = "org.jetbrains.kotlinx", name = "kotlinx-serialization-json", version.ref = "serialization" }
kotlinx-datetime = { group = "org.jetbrains.kotlinx", name = "kotlinx-datetime", version.ref = "kotlinxTime" }
datastore = { group = "androidx.datastore", name = "datastore-preferences", version.ref = "datastore" }
hilt-android = { group = "com.google.dagger", name = "hilt-android", version.ref = "dagger" }
Expand Down
1 change: 1 addition & 0 deletions profile/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,7 @@ dependencies {
implementation(libs.kotlinx.coroutines.android)
implementation(libs.kotlinx.coroutines.core)
implementation(libs.kotlinx.serialization.core)
implementation(libs.kotlinx.serialization.json)

// Hilt
implementation(libs.hilt.android)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -469,6 +469,7 @@
val onBackground = MaterialTheme.colorScheme.onBackground
val horizontalContentPadding = contentPadding.horizontalOnly

// TODO: Store these in prefs.

Check warning

Code scanning / detekt

Flags a forbidden comment. Warning

Forbidden TODO todo marker in comment, please do the changes.
val animeListVisibility = remember(animeCollection?.namedLists?.size) {
mutableStateMapOf(
*List(animeCollection?.namedLists?.size ?: 0) { it to true }.toTypedArray()
Expand Down Expand Up @@ -568,7 +569,6 @@
) + contentPadding.copy(top = 0.dp)

val mediaTabContentPadding = PaddingValues(
top = LocalPaddings.current.small,
start = LocalPaddings.current.medium,
end = LocalPaddings.current.medium,
bottom = LocalPaddings.current.medium
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ import kotlinx.coroutines.flow.onEach
import kotlinx.coroutines.flow.onStart
import kotlinx.coroutines.flow.stateIn
import kotlinx.coroutines.launch
import kotlinx.serialization.json.Json
import javax.inject.Inject

@OptIn(ExperimentalCoroutinesApi::class)
Expand All @@ -51,7 +52,11 @@ class ProfileViewModel @Inject constructor(
).flatMapLatest {
userRepository.fetchViewer(useNetwork, Media.Language.valueOf(it.second))
}.asResource().onEach {
it.data?.let { user -> preferencesRepository.setViewerId(user.id) }
it.data?.let { user ->
preferencesRepository.setViewerId(user.id)
preferencesRepository.setAnimeListOrder(user.animeListOrder)
preferencesRepository.setMangaListOrder(user.mangaListOrder)
}
}.stateIn(
scope = viewModelScope,
started = SharingStarted.WhileSubscribed(1000),
Expand All @@ -60,15 +65,22 @@ class ProfileViewModel @Inject constructor(

val viewerAnimeLists = combine(
flow = refreshTrigger.onStart { emit(Unit) },
flow2 = preferencesRepository.viewerId.filterNotNull(),
flow3 = preferencesRepository.language.filterNotNull(),
flow2 = combine(
preferencesRepository.viewerId.filterNotNull(),
preferencesRepository.language.filterNotNull(),
::Pair
),
flow3 = preferencesRepository.animeListOrder.filterNotNull().map {
Json.decodeFromString<List<String>>(it)
},
transform = ::Triple,
).flatMapLatest {
userRepository.fetchUserMediaList(
id = it.second.toIntOrNull(),
id = it.second.first.toIntOrNull(),
type = MediaType.ANIME,
useNetwork = useNetwork,
language = Media.Language.valueOf(it.third)
language = Media.Language.valueOf(it.second.second),
mediaListOrder = it.third
)
}.asResource().stateIn(
scope = viewModelScope,
Expand All @@ -78,15 +90,22 @@ class ProfileViewModel @Inject constructor(

val viewerMangaLists = combine(
flow = refreshTrigger.onStart { emit(Unit) },
flow2 = preferencesRepository.viewerId.filterNotNull(),
flow3 = preferencesRepository.language.filterNotNull(),
flow2 = combine(
preferencesRepository.viewerId.filterNotNull(),
preferencesRepository.language.filterNotNull(),
::Pair
),
flow3 = preferencesRepository.mangaListOrder.filterNotNull().map {
Json.decodeFromString<List<String>>(it)
},
transform = ::Triple,
).flatMapLatest {
userRepository.fetchUserMediaList(
id = it.second.toIntOrNull(),
id = it.second.first.toIntOrNull(),
type = MediaType.MANGA,
useNetwork = useNetwork,
language = Media.Language.valueOf(it.third)
language = Media.Language.valueOf(it.second.second),
mediaListOrder = it.third
)
}.asResource().stateIn(
scope = viewModelScope,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -138,6 +138,8 @@
}
}
is Media.Credit -> {
// TODO: Make character sheet top level (like quick search) or have a

Check warning

Code scanning / detekt

Flags a forbidden comment. Warning

Forbidden TODO todo marker in comment, please do the changes.
// dedicated page.
CharacterCard(
image = item.image,
tag = null,
Expand Down
Loading
Loading