diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/database/queries/MangaQueries.kt b/app/src/main/java/eu/kanade/tachiyomi/data/database/queries/MangaQueries.kt index d5d20d87a0..99ae7cbb84 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/data/database/queries/MangaQueries.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/data/database/queries/MangaQueries.kt @@ -83,6 +83,11 @@ interface MangaQueries : DbProvider { .withPutResolver(MangaFlagsPutResolver()) .prepare() + fun updateFlags(mangas: List) = db.put() + .objects(mangas) + .withPutResolver(MangaFlagsPutResolver(true)) + .prepare() + fun updateLastUpdated(manga: Manga) = db.put() .`object`(manga) .withPutResolver(MangaLastUpdatedPutResolver()) diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/database/resolvers/MangaFlagsPutResolver.kt b/app/src/main/java/eu/kanade/tachiyomi/data/database/resolvers/MangaFlagsPutResolver.kt index 0a30da7dab..2a8e083838 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/data/database/resolvers/MangaFlagsPutResolver.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/data/database/resolvers/MangaFlagsPutResolver.kt @@ -9,7 +9,7 @@ import eu.kanade.tachiyomi.data.database.inTransactionReturn import eu.kanade.tachiyomi.data.database.models.Manga import eu.kanade.tachiyomi.data.database.tables.MangaTable -class MangaFlagsPutResolver : PutResolver() { +class MangaFlagsPutResolver(private val updateAll: Boolean = false) : PutResolver() { override fun performPut(db: StorIOSQLite, manga: Manga) = db.inTransactionReturn { val updateQuery = mapToUpdateQuery(manga) @@ -19,11 +19,21 @@ class MangaFlagsPutResolver : PutResolver() { PutResult.newUpdateResult(numberOfRowsUpdated, updateQuery.table()) } - fun mapToUpdateQuery(manga: Manga) = UpdateQuery.builder() - .table(MangaTable.TABLE) - .where("${MangaTable.COL_ID} = ?") - .whereArgs(manga.id) - .build() + fun mapToUpdateQuery(manga: Manga): UpdateQuery { + val builder = UpdateQuery.builder() + + return if (updateAll) { + builder + .table(MangaTable.TABLE) + .build() + } else { + builder + .table(MangaTable.TABLE) + .where("${MangaTable.COL_ID} = ?") + .whereArgs(manga.id) + .build() + } + } fun mapToContentValues(manga: Manga) = ContentValues(1).apply { put(MangaTable.COL_CHAPTER_FLAGS, manga.chapter_flags) diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/preference/PreferenceKeys.kt b/app/src/main/java/eu/kanade/tachiyomi/data/preference/PreferenceKeys.kt index 2c7f66dcf1..d9a7781ceb 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/data/preference/PreferenceKeys.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/data/preference/PreferenceKeys.kt @@ -165,6 +165,18 @@ object PreferenceKeys { const val enableDoh = "enable_doh" + const val defaultChapterFilterByRead = "default_chapter_filter_by_read" + + const val defaultChapterFilterByDownloaded = "default_chapter_filter_by_downloaded" + + const val defaultChapterFilterByBookmarked = "default_chapter_filter_by_bookmarked" + + const val defaultChapterSortBySourceOrNumber = "default_chapter_sort_by_source_or_number" // and upload date + + const val defaultChapterSortByAscendingOrDescending = "default_chapter_sort_by_ascending_or_descending" + + const val defaultChapterDisplayByNameOrNumber = "default_chapter_display_by_name_or_number" + fun trackUsername(syncId: Int) = "pref_mangasync_username_$syncId" fun trackPassword(syncId: Int) = "pref_mangasync_password_$syncId" 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 f0f121583d..b1836fee9a 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/data/preference/PreferencesHelper.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/data/preference/PreferencesHelper.kt @@ -2,11 +2,15 @@ package eu.kanade.tachiyomi.data.preference import android.content.Context import android.os.Environment +import androidx.core.content.edit import androidx.core.net.toUri import androidx.preference.PreferenceManager import com.tfcporciuncula.flow.FlowSharedPreferences import com.tfcporciuncula.flow.Preference import eu.kanade.tachiyomi.R +import eu.kanade.tachiyomi.data.database.models.Manga +import eu.kanade.tachiyomi.data.preference.PreferenceKeys as Keys +import eu.kanade.tachiyomi.data.preference.PreferenceValues as Values import eu.kanade.tachiyomi.data.preference.PreferenceValues.DisplayMode import eu.kanade.tachiyomi.data.preference.PreferenceValues.NsfwAllowance import eu.kanade.tachiyomi.data.track.TrackService @@ -18,8 +22,6 @@ import java.io.File import java.text.DateFormat import java.text.SimpleDateFormat import java.util.Locale -import eu.kanade.tachiyomi.data.preference.PreferenceKeys as Keys -import eu.kanade.tachiyomi.data.preference.PreferenceValues as Values @OptIn(ExperimentalCoroutinesApi::class) fun Preference.asImmediateFlow(block: (value: T) -> Unit): Flow { @@ -249,4 +251,29 @@ class PreferencesHelper(val context: Context) { fun trustedSignatures() = flowPrefs.getStringSet("trusted_signatures", emptySet()) fun enableDoh() = prefs.getBoolean(Keys.enableDoh, false) + + fun filterChapterByRead() = prefs.getInt(Keys.defaultChapterFilterByRead, Manga.SHOW_ALL) + + fun filterChapterByDownloaded() = prefs.getInt(Keys.defaultChapterFilterByDownloaded, Manga.SHOW_ALL) + + fun filterChapterByBookmarked() = prefs.getInt(Keys.defaultChapterFilterByBookmarked, Manga.SHOW_ALL) + + fun sortChapterBySourceOrNumber() = prefs.getInt(Keys.defaultChapterSortBySourceOrNumber, Manga.SORTING_SOURCE) + + fun displayChapterByNameOrNumber() = prefs.getInt(Keys.defaultChapterDisplayByNameOrNumber, Manga.DISPLAY_NAME) + + fun sortChapterByAscendingOrDescending() = prefs.getInt(Keys.defaultChapterSortByAscendingOrDescending, Manga.SORT_DESC) + + fun setChapterSettingsDefault(m: Manga) { + prefs.edit { + putInt(Keys.defaultChapterFilterByRead, m.readFilter) + putInt(Keys.defaultChapterFilterByDownloaded, m.downloadedFilter) + putInt(Keys.defaultChapterFilterByBookmarked, m.bookmarkedFilter) + putInt(Keys.defaultChapterSortBySourceOrNumber, m.sorting) + putInt(Keys.defaultChapterDisplayByNameOrNumber, m.displayMode) + } + + if (m.sortDescending()) prefs.edit { putInt(Keys.defaultChapterSortByAscendingOrDescending, Manga.SORT_DESC) } + else prefs.edit { putInt(Keys.defaultChapterSortByAscendingOrDescending, Manga.SORT_ASC) } + } } 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 d7fb3e5231..39be964aaa 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 @@ -28,6 +28,7 @@ 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.removeCovers import kotlinx.coroutines.flow.subscribe import rx.Observable @@ -268,6 +269,8 @@ open class BrowseSourcePresenter( if (!manga.favorite) { manga.removeCovers(coverCache) + } else { + ChapterSettingsHelper.applySettingDefaultsFromPreferences(manga) } db.insertManga(manga).executeAsBlocking() 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 4a8e021916..103dd27247 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 @@ -18,6 +18,7 @@ import eu.kanade.tachiyomi.source.LocalSource import eu.kanade.tachiyomi.source.Source import eu.kanade.tachiyomi.ui.base.presenter.BasePresenter import eu.kanade.tachiyomi.ui.manga.chapter.ChapterItem +import eu.kanade.tachiyomi.util.chapter.ChapterSettingsHelper import eu.kanade.tachiyomi.util.chapter.syncChaptersWithSource import eu.kanade.tachiyomi.util.isLocal import eu.kanade.tachiyomi.util.lang.isNullOrUnsubscribed @@ -82,6 +83,10 @@ class MangaPresenter( override fun onCreate(savedState: Bundle?) { super.onCreate(savedState) + if (!manga.favorite) { + ChapterSettingsHelper.applySettingDefaultsFromPreferences(manga) + } + // Manga info - start getMangaObservable() diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/manga/chapter/ChaptersSettingsSheet.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/manga/chapter/ChaptersSettingsSheet.kt index af34bfbf5e..60fb9a8697 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/manga/chapter/ChaptersSettingsSheet.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/manga/chapter/ChaptersSettingsSheet.kt @@ -14,7 +14,7 @@ class ChaptersSettingsSheet( activity: Activity, private val presenter: MangaPresenter, onGroupClickListener: (ExtendedNavigationView.Group) -> Unit -) : TabbedBottomSheetDialog(activity) { +) : TabbedBottomSheetDialog(activity, presenter.manga) { val filters: Filter private val sort: Sort 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 new file mode 100644 index 0000000000..4ba7d83c6e --- /dev/null +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/manga/chapter/SetChapterSettingsDialog.kt @@ -0,0 +1,46 @@ +package eu.kanade.tachiyomi.ui.manga.chapter + +import android.app.Dialog +import android.content.Context +import com.afollestad.materialdialogs.MaterialDialog +import com.afollestad.materialdialogs.customview.customView +import eu.kanade.tachiyomi.R +import eu.kanade.tachiyomi.data.database.models.Manga +import eu.kanade.tachiyomi.util.chapter.ChapterSettingsHelper +import eu.kanade.tachiyomi.util.system.toast +import eu.kanade.tachiyomi.widget.DialogCheckboxView + +class SetChapterSettingsDialog(val context: Context, val manga: Manga) { + private var dialog: Dialog + + init { + this.dialog = buildDialog() + } + + private fun buildDialog(): Dialog { + val view = DialogCheckboxView(context).apply { + setDescription(R.string.confirm_set_chapter_settings) + setOptionDescription(R.string.also_set_chapter_settings_for_library) + } + + return MaterialDialog(context) + .title(R.string.action_chapter_settings) + .customView( + view = view, + horizontalPadding = true + ) + .positiveButton(android.R.string.ok) { + ChapterSettingsHelper.setNewSettingDefaults(manga) + if (view.isChecked()) { + ChapterSettingsHelper.updateAllMangasWithDefaultsFromPreferences() + } + + context.toast(context.getString(R.string.chapter_settings_updated)) + } + .negativeButton(android.R.string.cancel) + } + + fun showDialog() = dialog.show() + + fun dismissDialog() = dialog.dismiss() +} 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 new file mode 100644 index 0000000000..a797c3799d --- /dev/null +++ b/app/src/main/java/eu/kanade/tachiyomi/util/chapter/ChapterSettingsHelper.kt @@ -0,0 +1,57 @@ +package eu.kanade.tachiyomi.util.chapter + +import eu.kanade.tachiyomi.data.database.DatabaseHelper +import eu.kanade.tachiyomi.data.database.models.Manga +import eu.kanade.tachiyomi.data.preference.PreferencesHelper +import eu.kanade.tachiyomi.util.lang.launchIO +import uy.kohesive.injekt.Injekt +import uy.kohesive.injekt.api.get + +object ChapterSettingsHelper { + private val prefs = Injekt.get() + private val db: DatabaseHelper = Injekt.get() + + /** + * updates the Chapter Settings in Preferences + */ + fun setNewSettingDefaults(m: Manga?) { + m?.let { + prefs.setChapterSettingsDefault(it) + db.updateFlags(it).executeAsBlocking() + } + } + + /** + * updates a single manga's Chapter Settings to match what's set in Preferences + */ + fun applySettingDefaultsFromPreferences(m: Manga) { + m.readFilter = prefs.filterChapterByRead() + m.downloadedFilter = prefs.filterChapterByDownloaded() + m.bookmarkedFilter = prefs.filterChapterByBookmarked() + m.sorting = prefs.sortChapterBySourceOrNumber() + m.displayMode = prefs.displayChapterByNameOrNumber() + m.setChapterOrder(prefs.sortChapterByAscendingOrDescending()) + db.updateFlags(m).executeAsBlocking() + } + + /** + * updates all mangas in database Chapter Settings to match what's set in Preferences + */ + fun updateAllMangasWithDefaultsFromPreferences() { + launchIO { + val dbMangas = db.getMangas().executeAsBlocking().toMutableList() + + val updatedMangas = dbMangas.map { m -> + m.readFilter = prefs.filterChapterByRead() + m.downloadedFilter = prefs.filterChapterByDownloaded() + m.bookmarkedFilter = prefs.filterChapterByBookmarked() + m.sorting = prefs.sortChapterBySourceOrNumber() + m.displayMode = prefs.displayChapterByNameOrNumber() + m.setChapterOrder(prefs.sortChapterByAscendingOrDescending()) + m + }.toList() + + db.updateFlags(updatedMangas).executeAsBlocking() + } + } +} diff --git a/app/src/main/java/eu/kanade/tachiyomi/util/view/ViewExtensions.kt b/app/src/main/java/eu/kanade/tachiyomi/util/view/ViewExtensions.kt index a215ea01d3..c50f111bf7 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/util/view/ViewExtensions.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/util/view/ViewExtensions.kt @@ -64,7 +64,7 @@ inline fun View.popupMenu( @MenuRes menuRes: Int, noinline initMenu: (Menu.() -> Unit)? = null, noinline onMenuItemClick: MenuItem.() -> Boolean -) { +): PopupMenu { val popup = PopupMenu(context, this, Gravity.NO_GRAVITY, R.attr.actionOverflowMenuStyle, 0) popup.menuInflater.inflate(menuRes, popup.menu) @@ -74,6 +74,7 @@ inline fun View.popupMenu( popup.setOnMenuItemClickListener { it.onMenuItemClick() } popup.show() + return popup } /** diff --git a/app/src/main/java/eu/kanade/tachiyomi/widget/TabbedBottomSheetDialog.kt b/app/src/main/java/eu/kanade/tachiyomi/widget/TabbedBottomSheetDialog.kt index 80b196f3e8..07b72f6598 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/widget/TabbedBottomSheetDialog.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/widget/TabbedBottomSheetDialog.kt @@ -4,21 +4,49 @@ import android.app.Activity import android.view.View import android.view.ViewGroup import com.google.android.material.bottomsheet.BottomSheetDialog +import eu.kanade.tachiyomi.R +import eu.kanade.tachiyomi.data.database.models.Manga import eu.kanade.tachiyomi.databinding.CommonTabbedSheetBinding +import eu.kanade.tachiyomi.ui.manga.chapter.SetChapterSettingsDialog +import eu.kanade.tachiyomi.util.view.popupMenu -abstract class TabbedBottomSheetDialog(private val activity: Activity) : BottomSheetDialog(activity) { +abstract class TabbedBottomSheetDialog(private val activity: Activity, private val manga: Manga? = null) : BottomSheetDialog(activity) { + val binding: CommonTabbedSheetBinding = CommonTabbedSheetBinding.inflate(activity.layoutInflater) init { - val binding: CommonTabbedSheetBinding = CommonTabbedSheetBinding.inflate(activity.layoutInflater) - val adapter = LibrarySettingsSheetAdapter() binding.pager.offscreenPageLimit = 2 binding.pager.adapter = adapter binding.tabs.setupWithViewPager(binding.pager) + // currently, we only need to show the overflow menu if this is a ChaptersSettingsSheet + if (manga != null) { + binding.menu.visibility = View.VISIBLE + binding.menu.setOnClickListener { it.post { showPopupMenu(it) } } + } else { + binding.menu.visibility = View.GONE + } + setContentView(binding.root) } + private fun showPopupMenu(view: View) { + view.popupMenu( + R.menu.default_chapter_filter, + { + }, + { + when (this.itemId) { + R.id.save_as_default -> { + manga?.let { SetChapterSettingsDialog(context, it).showDialog() } + true + } + else -> true + } + } + ) + } + abstract fun getTabViews(): List abstract fun getTabTitles(): List diff --git a/app/src/main/res/layout/common_tabbed_sheet.xml b/app/src/main/res/layout/common_tabbed_sheet.xml index 22904a7343..15792728fa 100644 --- a/app/src/main/res/layout/common_tabbed_sheet.xml +++ b/app/src/main/res/layout/common_tabbed_sheet.xml @@ -1,17 +1,42 @@ - + android:layout_height="wrap_content"> + + + + + + + + + + diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 3108520858..df8a41ea4d 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -30,6 +30,7 @@ Settings + Chapter Settings Menu Filter Downloaded @@ -524,6 +525,9 @@ Unread Are you sure you want to delete the selected chapters? Invalid download location + Are you sure you want to save these settings as default? + Also apply to all manga in my Library + Set as Default No chapters found @@ -678,6 +682,7 @@ Failed to bypass Cloudflare WebView is required for Tachiyomi Please update the WebView app for better compatibility + Updated default chapter settings Downloader @@ -705,4 +710,5 @@ Horizontal Vertical Both +