diff --git a/app/build.gradle.kts b/app/build.gradle.kts index 1c0083fe7..9dddc82f0 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -28,7 +28,7 @@ android { applicationId = "eu.kanade.tachiyomi.sy" minSdk = AndroidConfig.minSdk targetSdk = AndroidConfig.targetSdk - versionCode = 40 + versionCode = 41 versionName = "1.8.5" buildConfigField("String", "COMMIT_COUNT", "\"${getCommitCount()}\"") diff --git a/app/src/main/java/eu/kanade/domain/DomainModule.kt b/app/src/main/java/eu/kanade/domain/DomainModule.kt index c5e283d7b..1a24bef95 100644 --- a/app/src/main/java/eu/kanade/domain/DomainModule.kt +++ b/app/src/main/java/eu/kanade/domain/DomainModule.kt @@ -21,6 +21,7 @@ import eu.kanade.domain.category.interactor.UpdateCategory import eu.kanade.domain.category.repository.CategoryRepository import eu.kanade.domain.chapter.interactor.GetChapter import eu.kanade.domain.chapter.interactor.GetChapterByMangaId +import eu.kanade.domain.chapter.interactor.SetMangaDefaultChapterFlags import eu.kanade.domain.chapter.interactor.SetReadStatus import eu.kanade.domain.chapter.interactor.ShouldUpdateDbChapter import eu.kanade.domain.chapter.interactor.SyncChaptersWithSource @@ -95,6 +96,7 @@ class DomainModule : InjektModule { addFactory { GetNextChapter(get()) } addFactory { ResetViewerFlags(get()) } addFactory { SetMangaChapterFlags(get()) } + addFactory { SetMangaDefaultChapterFlags(get(), get(), get()) } addFactory { SetMangaViewerFlags(get()) } addFactory { InsertManga(get()) } addFactory { UpdateManga(get()) } diff --git a/app/src/main/java/eu/kanade/domain/chapter/interactor/SetDefaultChapterSettings.kt b/app/src/main/java/eu/kanade/domain/chapter/interactor/SetDefaultChapterSettings.kt new file mode 100644 index 000000000..45432c5d5 --- /dev/null +++ b/app/src/main/java/eu/kanade/domain/chapter/interactor/SetDefaultChapterSettings.kt @@ -0,0 +1,36 @@ +package eu.kanade.domain.chapter.interactor + +import eu.kanade.domain.library.service.LibraryPreferences +import eu.kanade.domain.manga.interactor.GetFavorites +import eu.kanade.domain.manga.interactor.SetMangaChapterFlags +import eu.kanade.domain.manga.model.Manga +import eu.kanade.tachiyomi.util.lang.withNonCancellableContext + +class SetMangaDefaultChapterFlags( + private val libraryPreferences: LibraryPreferences, + private val setMangaChapterFlags: SetMangaChapterFlags, + private val getFavorites: GetFavorites, +) { + + suspend fun await(manga: Manga) { + withNonCancellableContext { + with(libraryPreferences) { + setMangaChapterFlags.awaitSetAllFlags( + mangaId = manga.id, + unreadFilter = filterChapterByRead().get(), + downloadedFilter = filterChapterByDownloaded().get(), + bookmarkedFilter = filterChapterByBookmarked().get(), + sortingMode = sortChapterBySourceOrNumber().get(), + sortingDirection = sortChapterByAscendingOrDescending().get(), + displayMode = displayChapterByNameOrNumber().get(), + ) + } + } + } + + suspend fun awaitAll() { + withNonCancellableContext { + getFavorites.await().forEach { await(it) } + } + } +} diff --git a/app/src/main/java/eu/kanade/domain/library/service/LibraryPreferences.kt b/app/src/main/java/eu/kanade/domain/library/service/LibraryPreferences.kt index d150a2bc1..03ecc2d74 100644 --- a/app/src/main/java/eu/kanade/domain/library/service/LibraryPreferences.kt +++ b/app/src/main/java/eu/kanade/domain/library/service/LibraryPreferences.kt @@ -4,6 +4,7 @@ import eu.kanade.domain.library.model.GroupLibraryMode import eu.kanade.domain.library.model.LibraryDisplayMode import eu.kanade.domain.library.model.LibraryGroup import eu.kanade.domain.library.model.LibrarySort +import eu.kanade.domain.manga.model.Manga import eu.kanade.tachiyomi.core.preference.PreferenceStore import eu.kanade.tachiyomi.core.preference.getEnum import eu.kanade.tachiyomi.data.preference.DEVICE_ONLY_ON_WIFI @@ -85,6 +86,32 @@ class LibraryPreferences( // endregion + // region Chapter + + fun filterChapterByRead() = preferenceStore.getLong("default_chapter_filter_by_read", Manga.SHOW_ALL) + + fun filterChapterByDownloaded() = preferenceStore.getLong("default_chapter_filter_by_downloaded", Manga.SHOW_ALL) + + fun filterChapterByBookmarked() = preferenceStore.getLong("default_chapter_filter_by_bookmarked", Manga.SHOW_ALL) + + // and upload date + fun sortChapterBySourceOrNumber() = preferenceStore.getLong("default_chapter_sort_by_source_or_number", Manga.CHAPTER_SORTING_SOURCE) + + fun displayChapterByNameOrNumber() = preferenceStore.getLong("default_chapter_display_by_name_or_number", Manga.CHAPTER_DISPLAY_NAME) + + fun sortChapterByAscendingOrDescending() = preferenceStore.getLong("default_chapter_sort_by_ascending_or_descending", Manga.CHAPTER_SORT_DESC) + + fun setChapterSettingsDefault(manga: Manga) { + filterChapterByRead().set(manga.unreadFilterRaw) + filterChapterByDownloaded().set(manga.downloadedFilterRaw) + filterChapterByBookmarked().set(manga.bookmarkedFilterRaw) + sortChapterBySourceOrNumber().set(manga.sorting) + displayChapterByNameOrNumber().set(manga.displayMode) + sortChapterByAscendingOrDescending().set(if (manga.sortDescending()) Manga.CHAPTER_SORT_DESC else Manga.CHAPTER_SORT_ASC) + } + + // endregion + // SY --> fun sortTagsForLibrary() = preferenceStore.getStringSet("sort_tags_for_library", mutableSetOf()) diff --git a/app/src/main/java/eu/kanade/tachiyomi/Migrations.kt b/app/src/main/java/eu/kanade/tachiyomi/Migrations.kt index 0bb4fb8e2..c790695e5 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/Migrations.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/Migrations.kt @@ -309,6 +309,26 @@ object Migrations { BackupCreatorJob.setupTask(context) } } + if (oldVersion < 85) { + val preferences = listOf( + libraryPreferences.filterChapterByRead(), + libraryPreferences.filterChapterByDownloaded(), + libraryPreferences.filterChapterByBookmarked(), + libraryPreferences.sortChapterBySourceOrNumber(), + libraryPreferences.displayChapterByNameOrNumber(), + libraryPreferences.sortChapterByAscendingOrDescending(), + ) + + prefs.edit { + preferences.forEach { preference -> + val key = preference.key() + val value = prefs.getInt(key, Int.MIN_VALUE) + if (value == Int.MIN_VALUE) return@forEach + remove(key) + putLong(key, value.toLong()) + } + } + } return true } diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/preference/PreferencesHelper.kt b/app/src/main/java/eu/kanade/tachiyomi/data/preference/PreferencesHelper.kt index fc6f5eb9b..63cdb5834 100755 --- a/app/src/main/java/eu/kanade/tachiyomi/data/preference/PreferencesHelper.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/data/preference/PreferencesHelper.kt @@ -4,13 +4,11 @@ import android.content.Context import android.os.Build import eu.kanade.tachiyomi.core.preference.PreferenceStore import eu.kanade.tachiyomi.core.preference.getEnum -import eu.kanade.tachiyomi.data.database.models.Manga import eu.kanade.tachiyomi.util.system.DeviceUtil import eu.kanade.tachiyomi.util.system.isDynamicColorAvailable import java.text.DateFormat import java.text.SimpleDateFormat import java.util.Locale -import eu.kanade.domain.manga.model.Manga as DomainManga import eu.kanade.tachiyomi.data.preference.PreferenceKeys as Keys import eu.kanade.tachiyomi.data.preference.PreferenceValues as Values @@ -53,19 +51,6 @@ class PreferencesHelper( fun migrateFlags() = preferenceStore.getInt("migrate_flags", Int.MAX_VALUE) - fun filterChapterByRead() = preferenceStore.getInt("default_chapter_filter_by_read", DomainManga.SHOW_ALL.toInt()) - - fun filterChapterByDownloaded() = preferenceStore.getInt("default_chapter_filter_by_downloaded", DomainManga.SHOW_ALL.toInt()) - - fun filterChapterByBookmarked() = preferenceStore.getInt("default_chapter_filter_by_bookmarked", DomainManga.SHOW_ALL.toInt()) - - // and upload date - fun sortChapterBySourceOrNumber() = preferenceStore.getInt("default_chapter_sort_by_source_or_number", DomainManga.CHAPTER_SORTING_SOURCE.toInt()) - - fun displayChapterByNameOrNumber() = preferenceStore.getInt("default_chapter_display_by_name_or_number", DomainManga.CHAPTER_DISPLAY_NAME.toInt()) - - fun sortChapterByAscendingOrDescending() = preferenceStore.getInt("default_chapter_sort_by_ascending_or_descending", DomainManga.CHAPTER_SORT_DESC.toInt()) - fun incognitoMode() = preferenceStore.getBoolean("incognito_mode", false) fun tabletUiMode() = preferenceStore.getEnum("tablet_ui_mode", Values.TabletUiMode.AUTOMATIC) @@ -77,14 +62,6 @@ class PreferencesHelper( fun autoClearChapterCache() = preferenceStore.getBoolean("auto_clear_chapter_cache", false) - fun setChapterSettingsDefault(manga: Manga) { - filterChapterByRead().set(manga.readFilter) - filterChapterByDownloaded().set(manga.downloadedFilter) - filterChapterByBookmarked().set(manga.bookmarkedFilter) - sortChapterBySourceOrNumber().set(manga.sorting) - displayChapterByNameOrNumber().set(manga.displayMode) - sortChapterByAscendingOrDescending().set(if (manga.sortDescending()) DomainManga.CHAPTER_SORT_DESC.toInt() else DomainManga.CHAPTER_SORT_ASC.toInt()) - } // SY --> fun defaultMangaOrder() = preferenceStore.getString("default_manga_order", "") diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/browse/feed/FeedPresenter.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/browse/feed/FeedPresenter.kt index f68243ef7..cdfbc0e90 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/browse/feed/FeedPresenter.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/browse/feed/FeedPresenter.kt @@ -27,7 +27,7 @@ import eu.kanade.tachiyomi.source.model.FilterList import eu.kanade.tachiyomi.source.model.MangasPage import eu.kanade.tachiyomi.source.model.SManga import eu.kanade.tachiyomi.util.lang.launchIO -import eu.kanade.tachiyomi.util.lang.launchNonCancellableIO +import eu.kanade.tachiyomi.util.lang.launchNonCancellable import eu.kanade.tachiyomi.util.lang.withIOContext import eu.kanade.tachiyomi.util.system.LocaleHelper import eu.kanade.tachiyomi.util.system.logcat @@ -141,7 +141,7 @@ open class FeedPresenter( } fun createFeed(source: CatalogueSource, savedSearch: SavedSearch?) { - presenterScope.launchNonCancellableIO { + presenterScope.launchNonCancellable { insertFeedSavedSearch.await( FeedSavedSearch( id = -1, @@ -154,7 +154,7 @@ open class FeedPresenter( } fun deleteFeed(feed: FeedSavedSearch) { - presenterScope.launchNonCancellableIO { + presenterScope.launchNonCancellable { deleteFeedSavedSearchById.await(feed.id) } } diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/browse/source/browse/BrowseSourcePresenter.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/browse/source/browse/BrowseSourcePresenter.kt index 67dcf31e3..a34be6354 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/browse/source/browse/BrowseSourcePresenter.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/browse/source/browse/BrowseSourcePresenter.kt @@ -22,6 +22,7 @@ import eu.kanade.core.prefs.mapAsCheckboxState import eu.kanade.domain.category.interactor.GetCategories import eu.kanade.domain.category.interactor.SetMangaCategories import eu.kanade.domain.chapter.interactor.GetChapterByMangaId +import eu.kanade.domain.chapter.interactor.SetMangaDefaultChapterFlags import eu.kanade.domain.chapter.interactor.SyncChaptersWithTrackServiceTwoWay import eu.kanade.domain.library.service.LibraryPreferences import eu.kanade.domain.manga.interactor.GetDuplicateLibraryManga @@ -71,7 +72,6 @@ import eu.kanade.tachiyomi.ui.browse.source.filter.TextItem import eu.kanade.tachiyomi.ui.browse.source.filter.TextSectionItem import eu.kanade.tachiyomi.ui.browse.source.filter.TriStateItem import eu.kanade.tachiyomi.ui.browse.source.filter.TriStateSectionItem -import eu.kanade.tachiyomi.util.chapter.ChapterSettingsHelper import eu.kanade.tachiyomi.util.lang.launchIO import eu.kanade.tachiyomi.util.lang.withIOContext import eu.kanade.tachiyomi.util.lang.withUIContext @@ -122,6 +122,7 @@ open class BrowseSourcePresenter( private val getCategories: GetCategories = Injekt.get(), private val getChapterByMangaId: GetChapterByMangaId = Injekt.get(), private val setMangaCategories: SetMangaCategories = Injekt.get(), + private val setMangaDefaultChapterFlags: SetMangaDefaultChapterFlags = Injekt.get(), private val insertManga: InsertManga = Injekt.get(), private val updateManga: UpdateManga = Injekt.get(), private val insertTrack: InsertTrack = Injekt.get(), @@ -331,7 +332,7 @@ open class BrowseSourcePresenter( if (!new.favorite) { new = new.removeCovers(coverCache) } else { - ChapterSettingsHelper.applySettingDefaults(manga.id) + setMangaDefaultChapterFlags.await(manga) autoAddTrack(manga) } diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/browse/source/feed/SourceFeedPresenter.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/browse/source/feed/SourceFeedPresenter.kt index a92d11b75..8337f8d76 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/browse/source/feed/SourceFeedPresenter.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/browse/source/feed/SourceFeedPresenter.kt @@ -27,7 +27,7 @@ import eu.kanade.tachiyomi.source.model.FilterList import eu.kanade.tachiyomi.source.model.MangasPage import eu.kanade.tachiyomi.source.model.SManga import eu.kanade.tachiyomi.ui.base.presenter.BasePresenter -import eu.kanade.tachiyomi.util.lang.launchNonCancellableIO +import eu.kanade.tachiyomi.util.lang.launchNonCancellable import eu.kanade.tachiyomi.util.lang.withIOContext import eu.kanade.tachiyomi.util.system.logcat import exh.savedsearches.models.FeedSavedSearch @@ -108,7 +108,7 @@ open class SourceFeedPresenter( } fun createFeed(savedSearchId: Long) { - presenterScope.launchNonCancellableIO { + presenterScope.launchNonCancellable { insertFeedSavedSearch.await( FeedSavedSearch( id = -1, @@ -121,7 +121,7 @@ open class SourceFeedPresenter( } fun deleteFeed(feed: FeedSavedSearch) { - presenterScope.launchNonCancellableIO { + presenterScope.launchNonCancellable { deleteFeedSavedSearchById.await(feed.id) } } diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/library/LibraryPresenter.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/library/LibraryPresenter.kt index 9d230f942..0e7e71ecb 100755 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/library/LibraryPresenter.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/library/LibraryPresenter.kt @@ -66,7 +66,7 @@ import eu.kanade.tachiyomi.source.online.all.MergedSource import eu.kanade.tachiyomi.ui.base.presenter.BasePresenter import eu.kanade.tachiyomi.util.lang.combineLatest import eu.kanade.tachiyomi.util.lang.launchIO -import eu.kanade.tachiyomi.util.lang.launchNonCancellableIO +import eu.kanade.tachiyomi.util.lang.launchNonCancellable import eu.kanade.tachiyomi.util.lang.withIOContext import eu.kanade.tachiyomi.util.removeCovers import eu.kanade.tachiyomi.widget.ExtendedNavigationView.Item.TriStateGroup.State @@ -749,7 +749,7 @@ class LibraryPresenter( * @param mangas the list of manga. */ fun downloadUnreadChapters(mangas: List) { - presenterScope.launchNonCancellableIO { + presenterScope.launchNonCancellable { mangas.forEach { manga -> if (manga.source == MERGED_SOURCE_ID) { val mergedSource = sourceManager.get(MERGED_SOURCE_ID) as MergedSource @@ -821,7 +821,7 @@ class LibraryPresenter( * @param mangas the list of manga. */ fun markReadStatus(mangas: List, read: Boolean) { - presenterScope.launchNonCancellableIO { + presenterScope.launchNonCancellable { mangas.forEach { manga -> setReadStatus.await( manga = manga, @@ -839,7 +839,7 @@ class LibraryPresenter( * @param deleteChapters whether to delete downloaded chapters. */ fun removeMangas(mangaList: List, deleteFromLibrary: Boolean, deleteChapters: Boolean) { - presenterScope.launchNonCancellableIO { + presenterScope.launchNonCancellable { val mangaToDelete = mangaList.distinctBy { it.id } if (deleteFromLibrary) { @@ -881,7 +881,7 @@ class LibraryPresenter( * @param removeCategories the categories to remove in all mangas. */ fun setMangaCategories(mangaList: List, addCategories: List, removeCategories: List) { - presenterScope.launchNonCancellableIO { + presenterScope.launchNonCancellable { mangaList.map { manga -> val categoryIds = getCategories.await(manga.id) .map { it.id } diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/manga/MangaPresenter.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/manga/MangaPresenter.kt index 198b8b71e..0a6c1406a 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/manga/MangaPresenter.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/manga/MangaPresenter.kt @@ -10,6 +10,7 @@ import eu.kanade.domain.category.interactor.GetCategories import eu.kanade.domain.category.interactor.SetMangaCategories import eu.kanade.domain.category.model.Category import eu.kanade.domain.chapter.interactor.GetMergedChapterByMangaId +import eu.kanade.domain.chapter.interactor.SetMangaDefaultChapterFlags import eu.kanade.domain.chapter.interactor.SetReadStatus import eu.kanade.domain.chapter.interactor.SyncChaptersWithSource import eu.kanade.domain.chapter.interactor.SyncChaptersWithTrackServiceTwoWay @@ -63,10 +64,9 @@ import eu.kanade.tachiyomi.source.online.all.MergedSource import eu.kanade.tachiyomi.ui.base.presenter.BasePresenter import eu.kanade.tachiyomi.ui.manga.track.TrackItem import eu.kanade.tachiyomi.ui.reader.setting.ReaderPreferences -import eu.kanade.tachiyomi.util.chapter.ChapterSettingsHelper import eu.kanade.tachiyomi.util.chapter.getChapterSort import eu.kanade.tachiyomi.util.lang.launchIO -import eu.kanade.tachiyomi.util.lang.launchNonCancellableIO +import eu.kanade.tachiyomi.util.lang.launchNonCancellable import eu.kanade.tachiyomi.util.lang.toRelativeString import eu.kanade.tachiyomi.util.lang.withUIContext import eu.kanade.tachiyomi.util.preference.asHotFlow @@ -151,6 +151,7 @@ class MangaPresenter( // SY <-- private val getDuplicateLibraryManga: GetDuplicateLibraryManga = Injekt.get(), private val setMangaChapterFlags: SetMangaChapterFlags = Injekt.get(), + private val setMangaDefaultChapterFlags: SetMangaDefaultChapterFlags = Injekt.get(), private val setReadStatus: SetReadStatus = Injekt.get(), private val updateChapter: UpdateChapter = Injekt.get(), private val updateManga: UpdateManga = Injekt.get(), @@ -247,7 +248,7 @@ class MangaPresenter( val manga = getMangaAndChapters.awaitManga(mangaId) if (!manga.favorite) { - ChapterSettingsHelper.applySettingDefaults(mangaId) + setMangaDefaultChapterFlags.await(manga) } // Show what we have earlier. @@ -1136,7 +1137,7 @@ class MangaPresenter( * @param chapters the list of chapters to delete. */ fun deleteChapters(chapters: List) { - presenterScope.launchNonCancellableIO { + presenterScope.launchNonCancellable { val chapters2 = chapters.map { it.toDbChapter() } try { updateSuccessState { successState -> @@ -1168,10 +1169,10 @@ class MangaPresenter( } private fun downloadNewChapters(chapters: List) { - presenterScope.launchNonCancellableIO { - val manga = successState?.manga ?: return@launchNonCancellableIO + presenterScope.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@launchNonCancellableIO + if (chapters.isEmpty() || !manga.shouldDownloadNewChapters(categories, downloadPreferences) || manga.isEhBasedManga()) return@launchNonCancellable downloadChapters(chapters) } } @@ -1188,7 +1189,7 @@ class MangaPresenter( State.INCLUDE -> DomainManga.CHAPTER_SHOW_UNREAD State.EXCLUDE -> DomainManga.CHAPTER_SHOW_READ } - presenterScope.launchNonCancellableIO { + presenterScope.launchNonCancellable { setMangaChapterFlags.awaitSetUnreadFilter(manga, flag) } } @@ -1206,7 +1207,7 @@ class MangaPresenter( State.EXCLUDE -> DomainManga.CHAPTER_SHOW_NOT_DOWNLOADED } - presenterScope.launchNonCancellableIO { + presenterScope.launchNonCancellable { setMangaChapterFlags.awaitSetDownloadedFilter(manga, flag) } } @@ -1224,7 +1225,7 @@ class MangaPresenter( State.EXCLUDE -> DomainManga.CHAPTER_SHOW_NOT_BOOKMARKED } - presenterScope.launchNonCancellableIO { + presenterScope.launchNonCancellable { setMangaChapterFlags.awaitSetBookmarkFilter(manga, flag) } } @@ -1245,7 +1246,7 @@ class MangaPresenter( fun setDisplayMode(mode: Long) { val manga = successState?.manga ?: return - presenterScope.launchNonCancellableIO { + presenterScope.launchNonCancellable { setMangaChapterFlags.awaitSetDisplayMode(manga, mode) } } @@ -1257,7 +1258,7 @@ class MangaPresenter( fun setSorting(sort: Long) { val manga = successState?.manga ?: return - presenterScope.launchNonCancellableIO { + presenterScope.launchNonCancellable { setMangaChapterFlags.awaitSetSortingModeOrFlipOrder(manga, sort) } } @@ -1404,7 +1405,7 @@ class MangaPresenter( fun refreshTrackers() { refreshTrackersJob?.cancel() - refreshTrackersJob = presenterScope.launchNonCancellableIO { + refreshTrackersJob = presenterScope.launchNonCancellable { supervisorScope { try { trackList @@ -1454,7 +1455,7 @@ class MangaPresenter( val successState = successState ?: return if (item != null) { item.manga_id = successState.manga.id - presenterScope.launchNonCancellableIO { + presenterScope.launchNonCancellable { try { val allChapters = successState.chapters.map { it.chapter } val hasReadChapters = allChapters.any { it.read } @@ -1496,13 +1497,13 @@ class MangaPresenter( fun unregisterTracking(service: TrackService) { val manga = successState?.manga ?: return - presenterScope.launchNonCancellableIO { + presenterScope.launchNonCancellable { deleteTrack.await(manga.id, service.id) } } private fun updateRemote(track: Track, service: TrackService) { - presenterScope.launchNonCancellableIO { + presenterScope.launchNonCancellable { try { service.update(track) diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/manga/chapter/SetChapterSettingsDialog.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/manga/chapter/SetChapterSettingsDialog.kt index 7403d2134..73637770d 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/manga/chapter/SetChapterSettingsDialog.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/manga/chapter/SetChapterSettingsDialog.kt @@ -4,16 +4,27 @@ import android.app.Dialog import android.os.Bundle import androidx.core.os.bundleOf import com.google.android.material.dialog.MaterialAlertDialogBuilder +import eu.kanade.domain.chapter.interactor.SetMangaDefaultChapterFlags +import eu.kanade.domain.library.service.LibraryPreferences import eu.kanade.domain.manga.model.Manga import eu.kanade.tachiyomi.R import eu.kanade.tachiyomi.ui.base.controller.DialogController -import eu.kanade.tachiyomi.util.chapter.ChapterSettingsHelper import eu.kanade.tachiyomi.util.system.getSerializableCompat import eu.kanade.tachiyomi.util.system.toast import eu.kanade.tachiyomi.widget.DialogCheckboxView +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.cancel +import kotlinx.coroutines.launch +import uy.kohesive.injekt.injectLazy class SetChapterSettingsDialog(bundle: Bundle? = null) : DialogController(bundle) { + private val scope = CoroutineScope(Dispatchers.IO) + + private val libraryPreferences: LibraryPreferences by injectLazy() + private val setMangaDefaultChapterFlags: SetMangaDefaultChapterFlags by injectLazy() + constructor(manga: Manga) : this( bundleOf(MANGA_KEY to manga), ) @@ -28,9 +39,11 @@ class SetChapterSettingsDialog(bundle: Bundle? = null) : DialogController(bundle .setTitle(R.string.chapter_settings) .setView(view) .setPositiveButton(android.R.string.ok) { _, _ -> - ChapterSettingsHelper.setGlobalSettings(args.getSerializableCompat(MANGA_KEY)!!) + libraryPreferences.setChapterSettingsDefault(args.getSerializableCompat(MANGA_KEY)!!) if (view.isChecked()) { - ChapterSettingsHelper.updateAllMangasWithGlobalDefaults() + scope.launch { + setMangaDefaultChapterFlags.awaitAll() + } } activity?.toast(activity!!.getString(R.string.chapter_settings_updated)) @@ -38,6 +51,11 @@ class SetChapterSettingsDialog(bundle: Bundle? = null) : DialogController(bundle .setNegativeButton(android.R.string.cancel, null) .create() } + + override fun onDestroy() { + super.onDestroy() + scope.cancel() + } } private const val MANGA_KEY = "manga" diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/reader/ReaderPresenter.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/reader/ReaderPresenter.kt index f66c56c26..7e7854ccf 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/reader/ReaderPresenter.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/reader/ReaderPresenter.kt @@ -57,7 +57,7 @@ import eu.kanade.tachiyomi.util.chapter.getChapterSort import eu.kanade.tachiyomi.util.editCover import eu.kanade.tachiyomi.util.lang.byteSize import eu.kanade.tachiyomi.util.lang.launchIO -import eu.kanade.tachiyomi.util.lang.launchNonCancellableIO +import eu.kanade.tachiyomi.util.lang.launchNonCancellable import eu.kanade.tachiyomi.util.lang.takeBytes import eu.kanade.tachiyomi.util.lang.withUIContext import eu.kanade.tachiyomi.util.storage.DiskUtil @@ -285,7 +285,7 @@ class ReaderPresenter( */ fun onSaveInstanceStateNonConfigurationChange() { val currentChapter = getCurrentChapter() ?: return - presenterScope.launchNonCancellableIO { + presenterScope.launchNonCancellable { saveChapterProgress(currentChapter) } } @@ -631,7 +631,7 @@ class ReaderPresenter( * Called when reader chapter is changed in reader or when activity is paused. */ private fun saveReadingProgress(readerChapter: ReaderChapter) { - presenterScope.launchNonCancellableIO { + presenterScope.launchNonCancellable { saveChapterProgress(readerChapter) saveChapterHistory(readerChapter) } @@ -712,7 +712,7 @@ class ReaderPresenter( fun bookmarkCurrentChapter(bookmarked: Boolean) { val chapter = getCurrentChapter()?.chapter ?: return chapter.bookmark = bookmarked // Otherwise the bookmark icon doesn't update - presenterScope.launchNonCancellableIO { + presenterScope.launchNonCancellable { updateChapter.await( ChapterUpdate( id = chapter.id!!.toLong(), @@ -847,7 +847,7 @@ class ReaderPresenter( // Copy file in background. try { - presenterScope.launchNonCancellableIO { + presenterScope.launchNonCancellable { val uri = imageSaver.save( image = Image.Page( inputStream = page.stream!!, @@ -951,7 +951,7 @@ class ReaderPresenter( val filename = generateFilename(manga, page) try { - presenterScope.launchNonCancellableIO { + presenterScope.launchNonCancellable { destDir.deleteRecursively() val uri = imageSaver.save( image = Image.Page( @@ -1007,7 +1007,7 @@ class ReaderPresenter( val manga = manga?.toDomainManga() ?: return val stream = page.stream ?: return - presenterScope.launchNonCancellableIO { + presenterScope.launchNonCancellable { try { manga.editCover(context, stream()) withUIContext { @@ -1053,7 +1053,7 @@ class ReaderPresenter( val trackManager = Injekt.get() val context = Injekt.get() - presenterScope.launchNonCancellableIO { + presenterScope.launchNonCancellable { getTracks.await(manga.id!!) .mapNotNull { track -> val service = trackManager.getService(track.syncId) @@ -1097,7 +1097,7 @@ class ReaderPresenter( } ?: return // SY <-- - presenterScope.launchNonCancellableIO { + presenterScope.launchNonCancellable { downloadManager.enqueueDeleteChapters(listOf(chapter.chapter), manga.toDomainManga()!!) } } @@ -1107,7 +1107,7 @@ class ReaderPresenter( * are ignored. */ private fun deletePendingChapters() { - presenterScope.launchNonCancellableIO { + presenterScope.launchNonCancellable { downloadManager.deletePendingChapters() } } diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/recent/updates/UpdatesPresenter.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/recent/updates/UpdatesPresenter.kt index ce3635038..d160acdfc 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/recent/updates/UpdatesPresenter.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/recent/updates/UpdatesPresenter.kt @@ -23,7 +23,7 @@ import eu.kanade.tachiyomi.data.preference.PreferencesHelper import eu.kanade.tachiyomi.source.SourceManager import eu.kanade.tachiyomi.ui.base.presenter.BasePresenter import eu.kanade.tachiyomi.util.lang.launchIO -import eu.kanade.tachiyomi.util.lang.launchNonCancellableIO +import eu.kanade.tachiyomi.util.lang.launchNonCancellable import eu.kanade.tachiyomi.util.lang.withUIContext import eu.kanade.tachiyomi.util.system.logcat import kotlinx.coroutines.Job @@ -238,7 +238,7 @@ class UpdatesPresenter( * @param updatesItem the list of chapters to download. */ fun downloadChapters(updatesItem: List) { - presenterScope.launchNonCancellableIO { + presenterScope.launchNonCancellable { val groupedUpdates = updatesItem.groupBy { it.update.mangaId }.values for (updates in groupedUpdates) { val mangaId = updates.first().update.mangaId @@ -257,7 +257,7 @@ class UpdatesPresenter( * @param updatesItem list of chapters */ fun deleteChapters(updatesItem: List) { - presenterScope.launchNonCancellableIO { + presenterScope.launchNonCancellable { val groupedUpdates = updatesItem.groupBy { it.update.mangaId }.values val deletedIds = groupedUpdates.flatMap { updates -> val mangaId = updates.first().update.mangaId @@ -270,7 +270,7 @@ class UpdatesPresenter( val deletedUpdates = items.filter { deletedIds.contains(it.update.chapterId) } - if (deletedUpdates.isEmpty()) return@launchNonCancellableIO + if (deletedUpdates.isEmpty()) return@launchNonCancellable // TODO: Don't do this fake status update state.items = items.toMutableList().apply { diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/setting/SettingsAdvancedController.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/setting/SettingsAdvancedController.kt index 2e1fae8b8..11423228a 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/setting/SettingsAdvancedController.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/setting/SettingsAdvancedController.kt @@ -48,7 +48,7 @@ import eu.kanade.tachiyomi.ui.base.controller.pushController import eu.kanade.tachiyomi.ui.setting.database.ClearDatabaseController import eu.kanade.tachiyomi.util.CrashLogUtil import eu.kanade.tachiyomi.util.lang.launchIO -import eu.kanade.tachiyomi.util.lang.launchNonCancellableIO +import eu.kanade.tachiyomi.util.lang.launchNonCancellable import eu.kanade.tachiyomi.util.lang.withUIContext import eu.kanade.tachiyomi.util.preference.bindTo import eu.kanade.tachiyomi.util.preference.defaultValue @@ -108,7 +108,7 @@ class SettingsAdvancedController( summaryRes = R.string.pref_dump_crash_logs_summary onClick { - viewScope.launchNonCancellableIO { + viewScope.launchNonCancellable { CrashLogUtil(context).dumpLogs() } } @@ -593,7 +593,7 @@ class SettingsAdvancedController( private fun clearChapterCache() { val activity = activity ?: return - viewScope.launchNonCancellableIO { + viewScope.launchNonCancellable { try { val deletedFiles = chapterCache.clear() withUIContext { @@ -629,7 +629,7 @@ class SettingsAdvancedController( private fun resetViewerFlags() { val activity = activity ?: return - viewScope.launchNonCancellableIO { + viewScope.launchNonCancellable { val success = mangaRepository.resetViewerFlags() withUIContext { val message = if (success) { diff --git a/app/src/main/java/eu/kanade/tachiyomi/util/chapter/ChapterSettingsHelper.kt b/app/src/main/java/eu/kanade/tachiyomi/util/chapter/ChapterSettingsHelper.kt deleted file mode 100644 index 134c388c5..000000000 --- a/app/src/main/java/eu/kanade/tachiyomi/util/chapter/ChapterSettingsHelper.kt +++ /dev/null @@ -1,58 +0,0 @@ -package eu.kanade.tachiyomi.util.chapter - -import eu.kanade.domain.manga.interactor.GetFavorites -import eu.kanade.domain.manga.interactor.SetMangaChapterFlags -import eu.kanade.domain.manga.model.Manga -import eu.kanade.domain.manga.model.toDbManga -import eu.kanade.tachiyomi.data.preference.PreferencesHelper -import eu.kanade.tachiyomi.util.lang.launchIO -import uy.kohesive.injekt.injectLazy - -object ChapterSettingsHelper { - - private val preferences: PreferencesHelper by injectLazy() - private val getFavorites: GetFavorites by injectLazy() - private val setMangaChapterFlags: SetMangaChapterFlags by injectLazy() - - /** - * Updates the global Chapter Settings in Preferences. - */ - fun setGlobalSettings(manga: Manga) { - preferences.setChapterSettingsDefault(manga.toDbManga()) - } - - /** - * Updates a single manga's Chapter Settings to match what's set in Preferences. - */ - suspend fun applySettingDefaults(mangaId: Long) { - setMangaChapterFlags.awaitSetAllFlags( - mangaId = mangaId, - unreadFilter = preferences.filterChapterByRead().get().toLong(), - downloadedFilter = preferences.filterChapterByDownloaded().get().toLong(), - bookmarkedFilter = preferences.filterChapterByBookmarked().get().toLong(), - sortingMode = preferences.sortChapterBySourceOrNumber().get().toLong(), - sortingDirection = preferences.sortChapterByAscendingOrDescending().get().toLong(), - displayMode = preferences.displayChapterByNameOrNumber().get().toLong(), - ) - } - - /** - * Updates all mangas in library with global Chapter Settings. - */ - fun updateAllMangasWithGlobalDefaults() { - launchIO { - getFavorites.await() - .map { manga -> - setMangaChapterFlags.awaitSetAllFlags( - mangaId = manga.id, - unreadFilter = preferences.filterChapterByRead().get().toLong(), - downloadedFilter = preferences.filterChapterByDownloaded().get().toLong(), - bookmarkedFilter = preferences.filterChapterByBookmarked().get().toLong(), - sortingMode = preferences.sortChapterBySourceOrNumber().get().toLong(), - sortingDirection = preferences.sortChapterByAscendingOrDescending().get().toLong(), - displayMode = preferences.displayChapterByNameOrNumber().get().toLong(), - ) - } - } - } -} diff --git a/app/src/main/java/exh/EXHMigrations.kt b/app/src/main/java/exh/EXHMigrations.kt index 5f1015a8d..183eb1d4a 100644 --- a/app/src/main/java/exh/EXHMigrations.kt +++ b/app/src/main/java/exh/EXHMigrations.kt @@ -471,6 +471,27 @@ object EXHMigrations { BackupCreatorJob.setupTask(context) } } + if (oldVersion under 41) { + @Suppress("NAME_SHADOWING") + val preferences = listOf( + libraryPreferences.filterChapterByRead(), + libraryPreferences.filterChapterByDownloaded(), + libraryPreferences.filterChapterByBookmarked(), + libraryPreferences.sortChapterBySourceOrNumber(), + libraryPreferences.displayChapterByNameOrNumber(), + libraryPreferences.sortChapterByAscendingOrDescending(), + ) + + prefs.edit { + preferences.forEach { preference -> + val key = preference.key() + val value = prefs.getInt(key, Int.MIN_VALUE) + if (value == Int.MIN_VALUE) return@forEach + remove(key) + putLong(key, value.toLong()) + } + } + } // if (oldVersion under 1) { } (1 is current release version) // do stuff here when releasing changed crap diff --git a/app/src/main/java/exh/ui/metadata/MetadataViewPresenter.kt b/app/src/main/java/exh/ui/metadata/MetadataViewPresenter.kt index f80acd028..a2f7bfaa7 100644 --- a/app/src/main/java/exh/ui/metadata/MetadataViewPresenter.kt +++ b/app/src/main/java/exh/ui/metadata/MetadataViewPresenter.kt @@ -6,7 +6,7 @@ import eu.kanade.domain.manga.model.Manga import eu.kanade.tachiyomi.source.Source import eu.kanade.tachiyomi.source.online.MetadataSource import eu.kanade.tachiyomi.ui.base.presenter.BasePresenter -import eu.kanade.tachiyomi.util.lang.launchNonCancellableIO +import eu.kanade.tachiyomi.util.lang.launchNonCancellable import exh.metadata.metadata.base.RaisedSearchMetadata import exh.source.getMainSource import kotlinx.coroutines.flow.MutableStateFlow @@ -25,11 +25,11 @@ class MetadataViewPresenter( override fun onCreate(savedState: Bundle?) { super.onCreate(savedState) - presenterScope.launchNonCancellableIO { + presenterScope.launchNonCancellable { val metadataSource = source.getMainSource>() if (metadataSource == null) { _state.value = MetadataViewState.SourceNotFound - return@launchNonCancellableIO + return@launchNonCancellable } _state.value = when (val flatMetadata = getFlatMetadataById.await(manga.id)) { diff --git a/core/src/main/java/eu/kanade/tachiyomi/util/lang/CoroutinesExtensions.kt b/core/src/main/java/eu/kanade/tachiyomi/util/lang/CoroutinesExtensions.kt index 31eef3cff..41d697024 100644 --- a/core/src/main/java/eu/kanade/tachiyomi/util/lang/CoroutinesExtensions.kt +++ b/core/src/main/java/eu/kanade/tachiyomi/util/lang/CoroutinesExtensions.kt @@ -49,9 +49,12 @@ fun CoroutineScope.launchUI(block: suspend CoroutineScope.() -> Unit): Job = fun CoroutineScope.launchIO(block: suspend CoroutineScope.() -> Unit): Job = launch(Dispatchers.IO, block = block) -fun CoroutineScope.launchNonCancellableIO(block: suspend CoroutineScope.() -> Unit): Job = +fun CoroutineScope.launchNonCancellable(block: suspend CoroutineScope.() -> Unit): Job = launchIO { withContext(NonCancellable, block) } suspend fun withUIContext(block: suspend CoroutineScope.() -> T) = withContext(Dispatchers.Main, block) suspend fun withIOContext(block: suspend CoroutineScope.() -> T) = withContext(Dispatchers.IO, block) + +suspend fun withNonCancellableContext(block: suspend CoroutineScope.() -> T) = + withContext(NonCancellable, block)