Skip to content

Commit

Permalink
Observe tracker login state instead of fetching once (mihonapp/mihon#987
Browse files Browse the repository at this point in the history
)

* Observe tracker login state instead of fetching once

* Review changes

(cherry picked from commit 2092c81)

# Conflicts:
#	app/src/main/java/eu/kanade/presentation/library/LibrarySettingsDialog.kt
#	app/src/main/java/eu/kanade/tachiyomi/ui/library/LibraryScreenModel.kt
#	app/src/main/java/eu/kanade/tachiyomi/ui/manga/MangaScreenModel.kt
  • Loading branch information
AntsyLich authored and cuong-tran committed Jul 6, 2024
1 parent 274aefb commit e5c830d
Show file tree
Hide file tree
Showing 12 changed files with 142 additions and 62 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,7 @@ fun LibrarySettingsDialog(
}
}

@Suppress("UnusedReceiverParameter")
@Composable
private fun ColumnScope.FilterPage(
screenModel: LibrarySettingsScreenModel,
Expand Down Expand Up @@ -155,7 +156,7 @@ private fun ColumnScope.FilterPage(
)
// SY <--

val trackers = remember { screenModel.trackers }
val trackers by screenModel.trackersFlow.collectAsState()
when (trackers.size) {
0 -> {
// No trackers
Expand Down Expand Up @@ -183,11 +184,13 @@ private fun ColumnScope.FilterPage(
}
}

@Suppress("UnusedReceiverParameter")
@Composable
private fun ColumnScope.SortPage(
category: Category?,
screenModel: LibrarySettingsScreenModel,
) {
val trackers by screenModel.trackersFlow.collectAsState()
// SY -->
val globalSortMode by screenModel.libraryPreferences.sortingMode().collectAsState()
val sortingMode = if (screenModel.grouping == LibraryGroup.BY_DEFAULT) {
Expand All @@ -206,12 +209,11 @@ private fun ColumnScope.SortPage(
}.collectAsState(initial = screenModel.libraryPreferences.sortTagsForLibrary().get().isNotEmpty())
// SY <--

val trackerSortOption =
if (screenModel.trackers.isEmpty()) {
emptyList()
} else {
listOf(MR.strings.action_sort_tracker_score to LibrarySort.Type.TrackerMean)
}
val trackerSortOption = if (trackers.isEmpty()) {
emptyList()
} else {
listOf(MR.strings.action_sort_tracker_score to LibrarySort.Type.TrackerMean)
}

listOfNotNull(
MR.strings.action_sort_alpha to LibrarySort.Type.Alphabetical,
Expand Down Expand Up @@ -256,6 +258,7 @@ private val displayModes = listOf(
MR.strings.action_display_list to LibraryDisplayMode.List,
)

@Suppress("UnusedReceiverParameter")
@Composable
private fun ColumnScope.DisplayPage(
screenModel: LibrarySettingsScreenModel,
Expand Down Expand Up @@ -341,17 +344,19 @@ private fun groupTypeDrawableRes(type: Int): Int {
}
}

@Suppress("UnusedReceiverParameter")
@Composable
private fun ColumnScope.GroupPage(
screenModel: LibrarySettingsScreenModel,
hasCategories: Boolean,
) {
val groups = remember(hasCategories, screenModel.trackers) {
val trackers by screenModel.trackersFlow.collectAsState()
val groups = remember(hasCategories, trackers) {
buildList {
add(LibraryGroup.BY_DEFAULT)
add(LibraryGroup.BY_SOURCE)
add(LibraryGroup.BY_STATUS)
if (screenModel.trackers.isNotEmpty()) {
if (trackers.isNotEmpty()) {
add(LibraryGroup.BY_TRACK_STATUS)
}
if (hasCategories) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,12 @@ import androidx.compose.animation.fadeOut
import androidx.compose.animation.shrinkVertically
import androidx.compose.runtime.Composable
import androidx.compose.runtime.CompositionLocalProvider
import androidx.compose.runtime.collectAsState
import androidx.compose.runtime.compositionLocalOf
import androidx.compose.runtime.getValue
import androidx.compose.runtime.rememberCoroutineScope
import androidx.compose.runtime.structuralEqualityPolicy
import androidx.compose.ui.unit.dp
import eu.kanade.domain.track.service.TrackPreferences
import eu.kanade.presentation.more.settings.widget.EditTextPreferenceWidget
import eu.kanade.presentation.more.settings.widget.InfoWidget
import eu.kanade.presentation.more.settings.widget.ListPreferenceWidget
Expand All @@ -23,8 +23,6 @@ import eu.kanade.presentation.more.settings.widget.TrackingPreferenceWidget
import kotlinx.coroutines.launch
import tachiyomi.presentation.core.components.SliderItem
import tachiyomi.presentation.core.util.collectAsState
import uy.kohesive.injekt.Injekt
import uy.kohesive.injekt.api.get

val LocalPreferenceHighlighted = compositionLocalOf(structuralEqualityPolicy()) { false }
val LocalPreferenceMinHeight = compositionLocalOf(structuralEqualityPolicy()) { 56.dp }
Expand Down Expand Up @@ -156,16 +154,14 @@ internal fun PreferenceItem(
)
}
is Preference.PreferenceItem.TrackerPreference -> {
val uName by Injekt.get<TrackPreferences>()
.trackUsername(item.tracker)
.collectAsState()
item.tracker.run {
TrackingPreferenceWidget(
tracker = this,
checked = uName.isNotEmpty(),
onClick = { if (isLoggedIn) item.logout() else item.login() },
)
val isLoggedIn by item.tracker.let { tracker ->
tracker.isLoggedInFlow.collectAsState(tracker.isLoggedIn)
}
TrackingPreferenceWidget(
tracker = item.tracker,
checked = isLoggedIn,
onClick = { if (isLoggedIn) item.logout() else item.login() },
)
}
is Preference.PreferenceItem.InfoPreference -> {
InfoWidget(text = item.title)
Expand Down
11 changes: 11 additions & 0 deletions app/src/main/java/eu/kanade/tachiyomi/data/track/BaseTracker.kt
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@ import eu.kanade.domain.track.service.TrackPreferences
import eu.kanade.tachiyomi.data.database.models.Track
import eu.kanade.tachiyomi.network.NetworkHelper
import eu.kanade.tachiyomi.util.system.toast
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.combine
import logcat.LogPriority
import okhttp3.OkHttpClient
import tachiyomi.core.common.util.lang.withIOContext
Expand Down Expand Up @@ -53,6 +55,15 @@ abstract class BaseTracker(
get() = getUsername().isNotEmpty() &&
getPassword().isNotEmpty()

override val isLoggedInFlow: Flow<Boolean> by lazy {
combine(
trackPreferences.trackUsername(this).changes(),
trackPreferences.trackPassword(this).changes(),
) { username, password ->
username.isNotEmpty() && password.isNotEmpty()
}
}

override fun getUsername() = trackPreferences.trackUsername(this).get()

override fun getPassword() = trackPreferences.trackPassword(this).get()
Expand Down
3 changes: 3 additions & 0 deletions app/src/main/java/eu/kanade/tachiyomi/data/track/Tracker.kt
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import dev.icerock.moko.resources.StringResource
import eu.kanade.tachiyomi.data.database.models.Track
import eu.kanade.tachiyomi.data.track.model.TrackSearch
import kotlinx.collections.immutable.ImmutableList
import kotlinx.coroutines.flow.Flow
import okhttp3.OkHttpClient
import tachiyomi.domain.track.model.Track as DomainTrack

Expand Down Expand Up @@ -61,6 +62,8 @@ interface Tracker {

val isLoggedIn: Boolean

val isLoggedInFlow: Flow<Boolean>

fun getUsername(): String

fun getPassword(): String
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import eu.kanade.tachiyomi.data.track.mdlist.MdList
import eu.kanade.tachiyomi.data.track.myanimelist.MyAnimeList
import eu.kanade.tachiyomi.data.track.shikimori.Shikimori
import eu.kanade.tachiyomi.data.track.suwayomi.Suwayomi
import kotlinx.coroutines.flow.combine

class TrackerManager {

Expand Down Expand Up @@ -40,5 +41,13 @@ class TrackerManager {

fun loggedInTrackers() = trackers.filter { it.isLoggedIn }

fun loggedInTrackersFlow() = combine(trackers.map { it.isLoggedInFlow }) {
it.mapIndexedNotNull { index, isLoggedIn ->
if (isLoggedIn) trackers[index] else null
}
}

fun get(id: Long) = trackers.find { it.id == id }

fun getAll(ids: Set<Long>) = trackers.filter { it.id in ids }
}
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,7 @@ import kotlinx.coroutines.flow.debounce
import kotlinx.coroutines.flow.distinctUntilChanged
import kotlinx.coroutines.flow.filter
import kotlinx.coroutines.flow.first
import kotlinx.coroutines.flow.flatMapLatest
import kotlinx.coroutines.flow.flowOf
import kotlinx.coroutines.flow.launchIn
import kotlinx.coroutines.flow.map
Expand Down Expand Up @@ -177,18 +178,24 @@ class LibraryScreenModel(
::Pair,
),
// SY <--
) { searchQuery, library, tracks, (loggedInTrackers, _), (groupType, sort) ->
) { searchQuery, library, tracks, (trackingFiler, _), (groupType, sort) ->
library
// SY -->
.applyGrouping(groupType)
// SY <--
.applyFilters(tracks, loggedInTrackers)
.applySort(tracks, /* SY --> */sort.takeIf { groupType != LibraryGroup.BY_DEFAULT } /* SY <-- */)
.applyFilters(tracks, trackingFiler)
.applySort(
tracks,
trackingFiler.keys,
// SY -->
sort.takeIf { groupType != LibraryGroup.BY_DEFAULT },
// SY <--
)
.mapValues { (_, value) ->
if (searchQuery != null) {
// Filter query
// SY -->
filterLibrary(value, searchQuery, loggedInTrackers)
filterLibrary(value, searchQuery, trackingFiler)
// SY <--
} else {
// Don't do anything
Expand Down Expand Up @@ -277,9 +284,10 @@ class LibraryScreenModel(
/**
* Applies library filters to the given map of manga.
*/
@Suppress("LongMethod", "CyclomaticComplexMethod")
private suspend fun LibraryMap.applyFilters(
trackMap: Map<Long, List<Track>>,
loggedInTrackers: Map<Long, TriState>,
trackingFiler: Map<Long, TriState>,
): LibraryMap {
val prefs = getLibraryItemPreferencesFlow().first()
val downloadedOnly = prefs.globalFilterDownloaded
Expand All @@ -291,10 +299,10 @@ class LibraryScreenModel(
val filterCompleted = prefs.filterCompleted
val filterIntervalCustom = prefs.filterIntervalCustom

val isNotLoggedInAnyTrack = loggedInTrackers.isEmpty()
val isNotLoggedInAnyTrack = trackingFiler.isEmpty()

val excludedTracks = loggedInTrackers.mapNotNull { if (it.value == TriState.ENABLED_NOT) it.key else null }
val includedTracks = loggedInTrackers.mapNotNull { if (it.value == TriState.ENABLED_IS) it.key else null }
val excludedTracks = trackingFiler.mapNotNull { if (it.value == TriState.ENABLED_NOT) it.key else null }
val includedTracks = trackingFiler.mapNotNull { if (it.value == TriState.ENABLED_IS) it.key else null }
val trackFiltersIsIgnored = includedTracks.isEmpty() && excludedTracks.isEmpty()

// SY -->
Expand Down Expand Up @@ -371,9 +379,11 @@ class LibraryScreenModel(
/**
* Applies library sorting to the given map of manga.
*/
@Suppress("LongMethod", "CyclomaticComplexMethod")
private fun LibraryMap.applySort(
// Map<MangaId, List<Track>>
trackMap: Map<Long, List<Track>>,
loggedInTrackerIds: Set<Long>,
/* SY --> */
groupSort: LibrarySort? = null, /* SY <-- */
): LibraryMap {
Expand All @@ -397,7 +407,7 @@ class LibraryScreenModel(

val defaultTrackerScoreSortValue = -1.0
val trackerScores by lazy {
val trackerMap = trackerManager.loggedInTrackers().associateBy { e -> e.id }
val trackerMap = trackerManager.getAll(loggedInTrackerIds).associateBy { e -> e.id }
trackMap.mapValues { entry ->
when {
entry.value.isEmpty() -> null
Expand Down Expand Up @@ -596,18 +606,17 @@ class LibraryScreenModel(
* @return map of track id with the filter value
*/
private fun getTrackingFilterFlow(): Flow<Map<Long, TriState>> {
val loggedInTrackers = trackerManager.loggedInTrackers()
return if (loggedInTrackers.isNotEmpty()) {
val prefFlows = loggedInTrackers
.map { libraryPreferences.filterTracking(it.id.toInt()).changes() }
.toTypedArray()
combine(*prefFlows) {
return trackerManager.loggedInTrackersFlow().flatMapLatest { loggedInTrackers ->
if (loggedInTrackers.isEmpty()) return@flatMapLatest flowOf(emptyMap())

val prefFlows = loggedInTrackers.map { tracker ->
libraryPreferences.filterTracking(tracker.id.toInt()).changes()
}
combine(prefFlows) {
loggedInTrackers
.mapIndexed { index, tracker -> tracker.id to it[index] }
.toMap()
}
} else {
flowOf(emptyMap())
}
}

Expand Down Expand Up @@ -878,7 +887,6 @@ class LibraryScreenModel(
}

// SY -->

fun getCategoryName(
context: Context,
category: Category?,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@ import cafe.adriel.voyager.core.model.screenModelScope
import eu.kanade.core.preference.asState
import eu.kanade.domain.base.BasePreferences
import eu.kanade.tachiyomi.data.track.TrackerManager
import kotlinx.coroutines.flow.SharingStarted
import kotlinx.coroutines.flow.stateIn
import tachiyomi.core.common.preference.Preference
import tachiyomi.core.common.preference.TriState
import tachiyomi.core.common.preference.getAndSet
Expand All @@ -18,17 +20,22 @@ import tachiyomi.domain.library.model.LibrarySort
import tachiyomi.domain.library.service.LibraryPreferences
import uy.kohesive.injekt.Injekt
import uy.kohesive.injekt.api.get
import kotlin.time.Duration.Companion.seconds

class LibrarySettingsScreenModel(
val preferences: BasePreferences = Injekt.get(),
val libraryPreferences: LibraryPreferences = Injekt.get(),
private val setDisplayMode: SetDisplayMode = Injekt.get(),
private val setSortModeForCategory: SetSortModeForCategory = Injekt.get(),
private val trackerManager: TrackerManager = Injekt.get(),
trackerManager: TrackerManager = Injekt.get(),
) : ScreenModel {

val trackers
get() = trackerManager.trackers.filter { it.isLoggedIn }
val trackersFlow = trackerManager.loggedInTrackersFlow()
.stateIn(
scope = screenModelScope,
started = SharingStarted.WhileSubscribed(5.seconds.inWholeMilliseconds),
initialValue = trackerManager.loggedInTrackers()
)

// SY -->
val grouping by libraryPreferences.groupLibraryBy().asState(screenModelScope)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -290,7 +290,7 @@ class MangaScreen(
)
}.takeIf { isHttpSource },
onTrackingClicked = {
if (screenModel.loggedInTrackers.isEmpty()) {
if (successState.loggedInTracker.isEmpty()) {
navigator.push(SettingsScreen(SettingsScreen.Destination.Tracking))
} else {
screenModel.showTrackDialog()
Expand Down
Loading

0 comments on commit e5c830d

Please sign in to comment.