From e5c830d08b84e6edba1e14c26240908ffd646b70 Mon Sep 17 00:00:00 2001 From: AntsyLich <59261191+AntsyLich@users.noreply.github.com> Date: Sat, 6 Jul 2024 07:25:33 +0600 Subject: [PATCH] Observe tracker login state instead of fetching once (mihonapp/mihon#987) * Observe tracker login state instead of fetching once * Review changes (cherry picked from commit 2092c81bad59fd745a8514af320e534ecf40a5da) # 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 --- .../library/LibrarySettingsDialog.kt | 23 +++--- .../more/settings/PreferenceItem.kt | 20 +++--- .../tachiyomi/data/track/BaseTracker.kt | 11 +++ .../eu/kanade/tachiyomi/data/track/Tracker.kt | 3 + .../tachiyomi/data/track/TrackerManager.kt | 9 +++ .../ui/library/LibraryScreenModel.kt | 44 +++++++----- .../ui/library/LibrarySettingsScreenModel.kt | 13 +++- .../kanade/tachiyomi/ui/manga/MangaScreen.kt | 2 +- .../tachiyomi/ui/manga/MangaScreenModel.kt | 72 ++++++++++++++----- .../ui/manga/track/TrackInfoDialog.kt | 2 +- .../tachiyomi/ui/stats/StatsScreenModel.kt | 2 +- .../main/java/eu/kanade/test/DummyTracker.kt | 3 + 12 files changed, 142 insertions(+), 62 deletions(-) diff --git a/app/src/main/java/eu/kanade/presentation/library/LibrarySettingsDialog.kt b/app/src/main/java/eu/kanade/presentation/library/LibrarySettingsDialog.kt index c87060d398..1cfdead822 100644 --- a/app/src/main/java/eu/kanade/presentation/library/LibrarySettingsDialog.kt +++ b/app/src/main/java/eu/kanade/presentation/library/LibrarySettingsDialog.kt @@ -92,6 +92,7 @@ fun LibrarySettingsDialog( } } +@Suppress("UnusedReceiverParameter") @Composable private fun ColumnScope.FilterPage( screenModel: LibrarySettingsScreenModel, @@ -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 @@ -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) { @@ -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, @@ -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, @@ -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) { diff --git a/app/src/main/java/eu/kanade/presentation/more/settings/PreferenceItem.kt b/app/src/main/java/eu/kanade/presentation/more/settings/PreferenceItem.kt index b22e69323a..5a3c9d53ba 100644 --- a/app/src/main/java/eu/kanade/presentation/more/settings/PreferenceItem.kt +++ b/app/src/main/java/eu/kanade/presentation/more/settings/PreferenceItem.kt @@ -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 @@ -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 } @@ -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) diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/track/BaseTracker.kt b/app/src/main/java/eu/kanade/tachiyomi/data/track/BaseTracker.kt index 8f88f1051f..33caf65554 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/data/track/BaseTracker.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/data/track/BaseTracker.kt @@ -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 @@ -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() diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/track/Tracker.kt b/app/src/main/java/eu/kanade/tachiyomi/data/track/Tracker.kt index 06ca272c4e..a908cdd9de 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/data/track/Tracker.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/data/track/Tracker.kt @@ -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 @@ -61,6 +62,8 @@ interface Tracker { val isLoggedIn: Boolean + val isLoggedInFlow: Flow<Boolean> + fun getUsername(): String fun getPassword(): String diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/track/TrackerManager.kt b/app/src/main/java/eu/kanade/tachiyomi/data/track/TrackerManager.kt index 813f565284..9a45b37c58 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/data/track/TrackerManager.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/data/track/TrackerManager.kt @@ -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 { @@ -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 } } diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/library/LibraryScreenModel.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/library/LibraryScreenModel.kt index 1eb906e88c..ce29fa5b83 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/library/LibraryScreenModel.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/library/LibraryScreenModel.kt @@ -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 @@ -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 @@ -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 @@ -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 --> @@ -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 { @@ -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 @@ -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()) } } @@ -878,7 +887,6 @@ class LibraryScreenModel( } // SY --> - fun getCategoryName( context: Context, category: Category?, diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/library/LibrarySettingsScreenModel.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/library/LibrarySettingsScreenModel.kt index 55497e05f3..652ec1d506 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/library/LibrarySettingsScreenModel.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/library/LibrarySettingsScreenModel.kt @@ -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 @@ -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) diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/manga/MangaScreen.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/manga/MangaScreen.kt index 005e01a186..57e67fd037 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/manga/MangaScreen.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/manga/MangaScreen.kt @@ -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() diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/manga/MangaScreenModel.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/manga/MangaScreenModel.kt index f128d95e72..c88d102e35 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/manga/MangaScreenModel.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/manga/MangaScreenModel.kt @@ -49,6 +49,7 @@ import eu.kanade.tachiyomi.data.download.DownloadCache import eu.kanade.tachiyomi.data.download.DownloadManager import eu.kanade.tachiyomi.data.download.model.Download import eu.kanade.tachiyomi.data.track.EnhancedTracker +import eu.kanade.tachiyomi.data.track.Tracker import eu.kanade.tachiyomi.data.track.TrackerManager import eu.kanade.tachiyomi.data.track.mdlist.MdList import eu.kanade.tachiyomi.network.HttpException @@ -166,8 +167,10 @@ import androidx.compose.runtime.State as RuntimeState class MangaScreenModel( val context: Context, val mangaId: Long, + // SY --> private val isFromSource: Boolean, val smartSearched: Boolean, + // SY <-- private val downloadPreferences: DownloadPreferences = Injekt.get(), private val libraryPreferences: LibraryPreferences = Injekt.get(), readerPreferences: ReaderPreferences = Injekt.get(), @@ -219,8 +222,6 @@ class MangaScreenModel( private val successState: State.Success? get() = state.value as? State.Success - val loggedInTrackers by lazy { trackerManager.trackers.filter { it.isLoggedIn } } - // KMK --> val useNewSourceNavigation by uiPreferences.useNewSourceNavigation().asState(screenModelScope) val themeCoverBased = uiPreferences.themeCoverBased().get() @@ -246,7 +247,8 @@ class MangaScreenModel( private val skipFiltered by readerPreferences.skipFiltered().asState(screenModelScope) - val isUpdateIntervalEnabled = LibraryPreferences.MANGA_OUTSIDE_RELEASE_PERIOD in libraryPreferences.autoUpdateMangaRestrictions().get() + val isUpdateIntervalEnabled = + LibraryPreferences.MANGA_OUTSIDE_RELEASE_PERIOD in libraryPreferences.autoUpdateMangaRestrictions().get() private val selectedPositions: Array<Int> = arrayOf(-1, -1) // first and last selected index in list private val selectedChapterIds: HashSet<Long> = HashSet() @@ -259,6 +261,7 @@ class MangaScreenModel( data class EXHRedirect(val mangaId: Long) // EXH <-- + // SY --> private data class CombineState( val manga: Manga, val chapters: List<Chapter>, @@ -269,6 +272,7 @@ class MangaScreenModel( constructor(pair: Pair<Manga, List<Chapter>>, flatMetadata: FlatMetadata?) : this(pair.first, pair.second, flatMetadata) } + // SY <-- /** * Helper function to update the UI state only if it's currently in success state @@ -284,8 +288,7 @@ class MangaScreenModel( init { screenModelScope.launchIO { - getMangaAndChapters.subscribe(mangaId, applyScanlatorFilter = true) - .distinctUntilChanged() + getMangaAndChapters.subscribe(mangaId, applyScanlatorFilter = true).distinctUntilChanged() // SY --> .combine( getMergedChaptersByMangaId.subscribe(mangaId, true, applyScanlatorFilter = true) @@ -397,6 +400,16 @@ class MangaScreenModel( } } + screenModelScope.launchIO { + trackerManager.loggedInTrackersFlow() + .distinctUntilChanged() + .collectLatest { trackers -> + updateSuccessState { + it.copy(loggedInTracker = trackers) + } + } + } + observeDownloads() screenModelScope.launchIO { @@ -425,7 +438,9 @@ class MangaScreenModel( // Show what we have earlier mutableState.update { + // SY --> val source = sourceManager.getOrStub(manga.source) + // SY <-- State.Success( manga = manga, source = source, @@ -1099,7 +1114,9 @@ class MangaScreenModel( private fun List<Chapter>.toChapterListItems( manga: Manga, + // SY --> mergedData: MergedMangaData?, + // SY <-- ): List<ChapterList.Item> { val isLocal = manga.isLocal() // SY --> @@ -1175,7 +1192,9 @@ class MangaScreenModel( val state = successState ?: return try { withIOContext { + // SY --> if (state.source !is MergedSource) { + // SY <-- val chapters = state.source.getChapterList(state.manga.toSManga()) val newChapters = syncChaptersWithSource.await( @@ -1188,9 +1207,11 @@ class MangaScreenModel( if (manualFetch) { downloadNewChapters(newChapters) } + // SY --> } else { state.source.fetchChaptersForMergedManga(state.manga, manualFetch) } + // SY <-- } } catch (e: Throwable) { val message = if (e is NoChaptersException) { @@ -1471,6 +1492,7 @@ class MangaScreenModel( * @param chapters the list of chapters to download. */ private fun downloadChapters(chapters: List<Chapter>) { + // SY --> val state = successState ?: return if (state.source is MergedSource) { chapters.groupBy { it.mangaId }.forEach { map -> @@ -1478,7 +1500,7 @@ class MangaScreenModel( downloadManager.downloadChapters(manga, map.value) } } else { - /* SY <-- */ + // SY <-- val manga = state.manga downloadManager.downloadChapters(manga, chapters) } @@ -1524,7 +1546,15 @@ class MangaScreenModel( screenModelScope.launchNonCancellable { val manga = successState?.manga ?: return@launchNonCancellable val categories = getCategories.await(manga.id).map { it.id } - if (chapters.isEmpty() || !manga.shouldDownloadNewChapters(categories, downloadPreferences) || manga.isEhBasedManga()) return@launchNonCancellable + if ( + chapters.isEmpty() || + !manga.shouldDownloadNewChapters(categories, downloadPreferences) || + // EXH --> + manga.isEhBasedManga() + // EXH <-- + ) { + return@launchNonCancellable + } downloadChapters(chapters) } } @@ -1721,15 +1751,16 @@ class MangaScreenModel( val manga = state?.manga ?: return screenModelScope.launchIO { - getTracks.subscribe(manga.id) - .catch { logcat(LogPriority.ERROR, it) } - .map { tracks -> - loggedInTrackers - // Map to TrackItem - .map { service -> TrackItem(tracks.find { it.trackerId == service.id }, service) } - // Show only if the service supports this manga's source - .filter { (it.tracker as? EnhancedTracker)?.accept(source!!) ?: true } - } + combine( + getTracks.subscribe(manga.id).catch { logcat(LogPriority.ERROR, it) }, + trackerManager.loggedInTrackersFlow(), + ) { mangaTracks, loggedInTrackers -> + loggedInTrackers + // Map to TrackItem + .map { service -> TrackItem(mangaTracks.find { it.trackerId == service.id }, service) } + // Show only if the service supports this manga's source + .filter { (it.tracker as? EnhancedTracker)?.accept(source!!) ?: true } + } // SY --> .map { trackItems -> if (manga.source in mangaDexSourceIds || state.mergedData?.manga?.values.orEmpty().any { @@ -1869,6 +1900,8 @@ class MangaScreenModel( val isRefreshingData: Boolean = false, val dialog: MangaScreenModel.Dialog? = null, val hasPromptedToAddBefore: Boolean = false, + val loggedInTracker: List<Tracker> = emptyList(), + // SY --> val meta: RaisedSearchMetadata?, val mergedData: MergedMangaData?, @@ -1950,7 +1983,10 @@ class MangaScreenModel( val trackingCount: Int get() = trackItems.count { - it.track != null && ((it.tracker is MdList && it.track.status != FollowStatus.UNFOLLOWED.long) || it.tracker !is MdList) + it.track != null && ( + it.tracker !is MdList || + it.track.status != FollowStatus.UNFOLLOWED.long + ) } /** @@ -1972,11 +2008,13 @@ class MangaScreenModel( } } +// SY --> data class MergedMangaData( val references: List<MergedMangaReference>, val manga: Map<Long, Manga>, val sources: List<Source>, ) +// SY <-- @Immutable sealed class ChapterList { diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/manga/track/TrackInfoDialog.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/manga/track/TrackInfoDialog.kt index 1ba697f245..4c66940c97 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/manga/track/TrackInfoDialog.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/manga/track/TrackInfoDialog.kt @@ -239,7 +239,7 @@ data class TrackInfoDialogHomeScreen( } private fun List<Track>.mapToTrackItem(): List<TrackItem> { - val loggedInTrackers = Injekt.get<TrackerManager>().trackers.filter { it.isLoggedIn } + val loggedInTrackers = Injekt.get<TrackerManager>().loggedInTrackers() val source = Injekt.get<SourceManager>().getOrStub(sourceId) return loggedInTrackers // Map to TrackItem diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/stats/StatsScreenModel.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/stats/StatsScreenModel.kt index 66d7354f59..db44cd6728 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/stats/StatsScreenModel.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/stats/StatsScreenModel.kt @@ -43,7 +43,7 @@ class StatsScreenModel( // SY <-- ) : StateScreenModel<StatsScreenState>(StatsScreenState.Loading) { - private val loggedInTrackers by lazy { trackerManager.trackers.fastFilter { it.isLoggedIn } } + private val loggedInTrackers by lazy { trackerManager.loggedInTrackers() } // SY --> private val _allRead = MutableStateFlow(false) diff --git a/app/src/main/java/eu/kanade/test/DummyTracker.kt b/app/src/main/java/eu/kanade/test/DummyTracker.kt index 68e0c2f78a..415425e2cf 100644 --- a/app/src/main/java/eu/kanade/test/DummyTracker.kt +++ b/app/src/main/java/eu/kanade/test/DummyTracker.kt @@ -7,6 +7,8 @@ import eu.kanade.tachiyomi.data.track.Tracker import eu.kanade.tachiyomi.data.track.model.TrackSearch import kotlinx.collections.immutable.ImmutableList import kotlinx.collections.immutable.toImmutableList +import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.flowOf import okhttp3.OkHttpClient import tachiyomi.domain.track.model.Track import tachiyomi.i18n.MR @@ -16,6 +18,7 @@ data class DummyTracker( override val name: String, override val supportsReadingDates: Boolean = false, override val isLoggedIn: Boolean = false, + override val isLoggedInFlow: Flow<Boolean> = flowOf(false), val valLogoColor: Int = Color.rgb(18, 25, 35), val valLogo: Int = R.drawable.ic_tracker_anilist, val valStatuses: List<Long> = (1L..6L).toList(),