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 23dfa36351..f313e029de 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 @@ -73,6 +73,8 @@ object PreferenceKeys { const val invertDoublePages = "invert_double_pages" + const val readerBottomButtons = "reader_bottom_buttons" + const val showNavigationOverlayNewUser = "reader_navigation_overlay_new_user" const val showNavigationOverlayNewUserWebtoon = "reader_navigation_overlay_new_user_webtoon" 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 2e3e131a2b..68fd2791a2 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 @@ -11,6 +11,7 @@ import com.f2prateek.rx.preferences.RxSharedPreferences import com.tfcporciuncula.flow.FlowSharedPreferences import eu.kanade.tachiyomi.R import eu.kanade.tachiyomi.data.track.TrackService +import eu.kanade.tachiyomi.ui.reader.ReaderActivity import eu.kanade.tachiyomi.ui.reader.viewer.ViewerNavigation import eu.kanade.tachiyomi.ui.reader.viewer.pager.PageLayout import eu.kanade.tachiyomi.ui.recents.RecentMangaAdapter @@ -167,6 +168,11 @@ class PreferencesHelper(val context: Context) { fun invertDoublePages() = flowPrefs.getBoolean(Keys.invertDoublePages, false) + fun readerBottomButtons() = flowPrefs.getStringSet( + Keys.readerBottomButtons, + ReaderActivity.BUTTONS_DEFAULTS + ) + fun showNavigationOverlayNewUser() = flowPrefs.getBoolean(Keys.showNavigationOverlayNewUser, true) fun showNavigationOverlayNewUserWebtoon() = flowPrefs.getBoolean(Keys.showNavigationOverlayNewUserWebtoon, true) diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/reader/ReaderActivity.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/reader/ReaderActivity.kt index fbac8a0cd9..83f5b76008 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/reader/ReaderActivity.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/reader/ReaderActivity.kt @@ -23,6 +23,7 @@ import android.view.WindowManager import android.view.animation.Animation import android.view.animation.AnimationUtils import android.widget.SeekBar +import androidx.annotation.StringRes import androidx.core.content.ContextCompat import androidx.core.graphics.ColorUtils import androidx.core.view.isVisible @@ -194,6 +195,13 @@ class ReaderActivity : const val SHIFTED_PAGE_INDEX = "shiftedPageIndex" const val SHIFTED_CHAP_INDEX = "shiftedChapterIndex" + val BUTTONS_DEFAULTS = setOf( + BottomButton.ViewChapters, + BottomButton.WebView, + BottomButton.PageLayout, + BottomButton.CropBordersWebtoon + ).map { it.value }.toSet() + fun newIntent(context: Context, manga: Manga, chapter: Chapter): Intent { val intent = Intent(context, ReaderActivity::class.java) intent.putExtra("manga", manga.id) @@ -203,6 +211,15 @@ class ReaderActivity : } } + enum class BottomButton(val value: String, @StringRes val stringRes: Int) { + ViewChapters("vc", R.string.view_chapters), + WebView("wb", R.string.open_in_webview), + CropBordersPaged("cbp", R.string.crop_borders_paged), + CropBordersWebtoon("cbw", R.string.crop_borders_webtoon), + PageLayout("pl", R.string.page_layout), + ShiftDoublePage("sdp", R.string.shift_double_pages) + } + /** * Called when the activity is created. Initializes the presenter and configuration. */ @@ -324,8 +341,8 @@ class ReaderActivity : override fun onPrepareOptionsMenu(menu: Menu?): Boolean { val splitItem = menu?.findItem(R.id.action_shift_double_page) - splitItem?.isVisible = ((viewer as? PagerViewer)?.config?.doublePages ?: false) && !isTablet() - binding.chaptersSheet.shiftPageButton.isVisible = ((viewer as? PagerViewer)?.config?.doublePages ?: false) && isTablet() + splitItem?.isVisible = ((viewer as? PagerViewer)?.config?.doublePages ?: false) && !canShowSplitAtBottom() + binding.chaptersSheet.shiftPageButton.isVisible = ((viewer as? PagerViewer)?.config?.doublePages ?: false) && canShowSplitAtBottom() (viewer as? PagerViewer)?.config?.let { config -> val icon = ContextCompat.getDrawable( this, @@ -344,6 +361,14 @@ class ReaderActivity : return super.onPrepareOptionsMenu(menu) } + private fun canShowSplitAtBottom(): Boolean { + return if (preferences.readerBottomButtons().isNotSet()) { + isTablet() + } else { + BottomButton.ShiftDoublePage.value in preferences.readerBottomButtons().get() + } + } + fun setBottomNavButtons(pageLayout: Int) { val isDoublePage = pageLayout == PageLayout.DOUBLE_PAGES || (pageLayout == PageLayout.AUTOMATIC && (viewer as? PagerViewer)?.config?.doublePages ?: false) @@ -395,6 +420,19 @@ class ReaderActivity : } } + private fun updateBasicShortcuts() { + with(binding.chaptersSheet) { + doublePage.isVisible = viewer is PagerViewer && + BottomButton.PageLayout.value in preferences.readerBottomButtons().get() + cropBordersSheetButton.isVisible = + if (viewer is PagerViewer) BottomButton.CropBordersPaged.value in preferences.readerBottomButtons().get() + else BottomButton.CropBordersWebtoon.value in preferences.readerBottomButtons().get() + webviewButton.isVisible = BottomButton.WebView.value in preferences.readerBottomButtons().get() + chaptersButton.isVisible = BottomButton.ViewChapters.value in preferences.readerBottomButtons().get() + shiftPageButton.isVisible = ((viewer as? PagerViewer)?.config?.doublePages ?: false) && canShowSplitAtBottom() + } + } + /** * Called when an item of the options menu was clicked. Used to handle clicks on our menu * entries. @@ -527,19 +565,22 @@ class ReaderActivity : } } - binding.chaptersSheet.doublePage.setOnClickListener { - if (preferences.pageLayout().get() == PageLayout.AUTOMATIC) { - (viewer as? PagerViewer)?.config?.let { config -> - config.doublePages = !config.doublePages - reloadChapters(config.doublePages, true) + with(binding.chaptersSheet) { + doublePage.setOnClickListener { + if (preferences.pageLayout().get() == PageLayout.AUTOMATIC) { + (viewer as? PagerViewer)?.config?.let { config -> + config.doublePages = !config.doublePages + reloadChapters(config.doublePages, true) + } + } else { + preferences.pageLayout().set(1 - preferences.pageLayout().get()) } - } else { - preferences.pageLayout().set(1 - preferences.pageLayout().get()) } - } - binding.chaptersSheet.cropBordersSheetButton.setOnClickListener { - (viewer as? WebtoonViewer)?.let { - val pref = if (it.hasMargins) preferences.cropBorders() else preferences.cropBordersWebtoon() + cropBordersSheetButton.setOnClickListener { + val pref = + if ((viewer as? WebtoonViewer)?.hasMargins == true || + (viewer is PagerViewer) + ) preferences.cropBorders() else preferences.cropBordersWebtoon() pref.toggle() } } @@ -793,8 +834,6 @@ class ReaderActivity : binding.viewerContainer.removeAllViews() } viewer = newViewer - binding.chaptersSheet.doublePage.isVisible = viewer is PagerViewer - binding.chaptersSheet.cropBordersSheetButton.isVisible = viewer !is PagerViewer binding.viewerContainer.addView(newViewer.getView()) if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { @@ -831,6 +870,7 @@ class ReaderActivity : binding.pleaseWait.startAnimation(AnimationUtils.loadAnimation(this, R.anim.fade_in_long)) invalidateOptionsMenu() updateCropBordersShortcut() + updateBasicShortcuts() } override fun onPause() { @@ -1351,6 +1391,12 @@ class ReaderActivity : setBottomNavButtons(it) } .launchIn(scope) + + preferences.readerBottomButtons().asFlow() + .onEach { + updateBasicShortcuts() + } + .launchIn(scope) } /** diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/setting/SettingsDownloadController.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/setting/SettingsDownloadController.kt index 2dae209867..171e8591d0 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/setting/SettingsDownloadController.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/setting/SettingsDownloadController.kt @@ -95,18 +95,6 @@ class SettingsDownloadController : SettingsController() { allSelectionRes = R.string.all preferences.downloadNew().asImmediateFlow(viewScope) { isVisible = it } - - preferences.downloadNewCategories().asImmediateFlow(viewScope) { list -> - val selectedCategories = list - .mapNotNull { id -> dbCategories.find { it.id == id.toInt() } } - .sortedBy { it.order } - - summary = if (selectedCategories.isEmpty()) { - resources?.getString(R.string.all) - } else { - selectedCategories.joinToString { it.name } - } - } } preferenceCategory { intListPreference(activity) { diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/setting/SettingsLibraryController.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/setting/SettingsLibraryController.kt index fa9322c2ef..c7d042fa23 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/setting/SettingsLibraryController.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/setting/SettingsLibraryController.kt @@ -6,7 +6,6 @@ import eu.kanade.tachiyomi.R import eu.kanade.tachiyomi.data.database.DatabaseHelper import eu.kanade.tachiyomi.data.database.models.Category import eu.kanade.tachiyomi.data.library.LibraryUpdateJob -import eu.kanade.tachiyomi.data.preference.asImmediateFlow import eu.kanade.tachiyomi.ui.category.CategoryController import eu.kanade.tachiyomi.util.view.withFadeTransaction import uy.kohesive.injekt.Injekt @@ -134,16 +133,6 @@ class SettingsLibraryController : SettingsController() { entries = dbCategories.map { it.name } entryValues = dbCategories.map { it.id.toString() } allSelectionRes = R.string.all - - preferences.libraryUpdateCategories().asImmediateFlow { list -> - val selectedCategories = - list.mapNotNull { id -> dbCategories.find { it.id == id.toInt() } } - .sortedBy { it.order } - - summary = - if (selectedCategories.isEmpty()) context.getString(R.string.all) - else selectedCategories.joinToString { it.name } - } } intListPreference(activity) { key = Keys.updateOnRefresh diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/setting/SettingsReaderController.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/setting/SettingsReaderController.kt index 7c58b1201a..6d09a2b7bb 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/setting/SettingsReaderController.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/setting/SettingsReaderController.kt @@ -4,6 +4,7 @@ import android.os.Build import androidx.preference.PreferenceScreen import eu.kanade.tachiyomi.R import eu.kanade.tachiyomi.data.preference.asImmediateFlow +import eu.kanade.tachiyomi.ui.reader.ReaderActivity import eu.kanade.tachiyomi.ui.reader.viewer.ViewerNavigation import eu.kanade.tachiyomi.ui.reader.viewer.pager.PageLayout import eu.kanade.tachiyomi.util.lang.addBetaTag @@ -66,6 +67,18 @@ class SettingsReaderController : SettingsController() { defaultValue = 6 summaryRes = R.string.amount_of_pages_to_preload } + multiSelectListPreferenceMat(activity) { + key = Keys.readerBottomButtons + titleRes = R.string.display_buttons_bottom_reader + val enumConstants = ReaderActivity.BottomButton::class.java.enumConstants + entriesRes = enumConstants?.map { it.stringRes }.orEmpty().toTypedArray() + entryValues = enumConstants?.map { it.value }.orEmpty() + allSelectionRes = R.string.display_options + allIsAlwaysSelected = true + showAllLast = true + defaultValue = ReaderActivity.BUTTONS_DEFAULTS + } + infoPreference(R.string.certain_buttons_can_be_found) } preferenceCategory { diff --git a/app/src/main/java/eu/kanade/tachiyomi/widget/preference/ListMatPreference.kt b/app/src/main/java/eu/kanade/tachiyomi/widget/preference/ListMatPreference.kt index 106b358e86..e03c5f4c64 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/widget/preference/ListMatPreference.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/widget/preference/ListMatPreference.kt @@ -23,7 +23,7 @@ open class ListMatPreference @JvmOverloads constructor( var entriesRes: Array get() = emptyArray() set(value) { entries = value.map { context.getString(it) } } - protected var defValue: String = "" + private var defValue: String = "" var entries: List = emptyList() override fun onSetInitialValue(defaultValue: Any?) { diff --git a/app/src/main/java/eu/kanade/tachiyomi/widget/preference/MatPreference.kt b/app/src/main/java/eu/kanade/tachiyomi/widget/preference/MatPreference.kt index 576e154b9b..66dcd7cae1 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/widget/preference/MatPreference.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/widget/preference/MatPreference.kt @@ -50,6 +50,7 @@ open class MatPreference @JvmOverloads constructor( summaryProvider = customSummaryProvider return } else { + customSummaryProvider = null summaryProvider = null } super.setSummary(summaryResId) @@ -60,6 +61,7 @@ open class MatPreference @JvmOverloads constructor( summaryProvider = customSummaryProvider return } else { + customSummaryProvider = null summaryProvider = null } super.setSummary(summary) diff --git a/app/src/main/java/eu/kanade/tachiyomi/widget/preference/MultiListMatPreference.kt b/app/src/main/java/eu/kanade/tachiyomi/widget/preference/MultiListMatPreference.kt index 5ee3385b54..733fbf3146 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/widget/preference/MultiListMatPreference.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/widget/preference/MultiListMatPreference.kt @@ -10,6 +10,7 @@ import com.afollestad.materialdialogs.list.isItemChecked import com.afollestad.materialdialogs.list.listItemsMultiChoice import com.afollestad.materialdialogs.list.uncheckItem import eu.kanade.tachiyomi.data.preference.getOrDefault +import eu.kanade.tachiyomi.ui.setting.defaultValue class MultiListMatPreference @JvmOverloads constructor( activity: Activity?, @@ -21,49 +22,80 @@ class MultiListMatPreference @JvmOverloads constructor( var allSelectionRes: Int? = null - override var customSummaryProvider: SummaryProvider? = SummaryProvider { - prefs.getStringSet(key, emptySet()).getOrDefault().mapNotNull { - if (entryValues.indexOf(it) == -1) null - else entryValues.indexOf(it) + if (allSelectionRes != null) 1 else 0 - }.toIntArray().joinToString(",") { - entries[it] + /** All item is always selected and uncheckabele */ + var allIsAlwaysSelected = false + set(value) { + field = value + notifyChanged() } + + /** All Item is moved to bottom of list if true */ + var showAllLast = false + set(value) { + field = value + notifyChanged() + } + + private var defValue: Set = emptySet() + + override fun onSetInitialValue(defaultValue: Any?) { + super.onSetInitialValue(defaultValue) + defValue = (defaultValue as? Set<*>).orEmpty().mapNotNull { it as? String }.toSet() + } + + override var customSummaryProvider: SummaryProvider? = SummaryProvider { + var values = prefs.getStringSet(key, defValue).getOrDefault().mapNotNull { value -> + entryValues.indexOf(value).takeUnless { it == -1 } + }.toIntArray().sorted().map { entries[it] } + allSelectionRes?.let { allRes -> + when { + values.isEmpty() -> values = listOf(context.getString(allRes)) + allIsAlwaysSelected && !showAllLast -> + values = + listOf(context.getString(allRes)) + values + allIsAlwaysSelected -> values = values + context.getString(allRes) + } + } + values.joinToString() } @SuppressLint("CheckResult") override fun MaterialDialog.setItems() { - val set = prefs.getStringSet(key, emptySet()).getOrDefault() + val set = prefs.getStringSet(key, defValue).getOrDefault() var default = set.mapNotNull { if (entryValues.indexOf(it) == -1) null - else entryValues.indexOf(it) + if (allSelectionRes != null) 1 else 0 + else entryValues.indexOf(it) + if (allSelectionRes != null && !showAllLast) 1 else 0 } .toIntArray() - if (allSelectionRes != null && default.isEmpty()) default = intArrayOf(0) val items = if (allSelectionRes != null) { - (listOf(context.getString(allSelectionRes!!)) + entries) + if (showAllLast) entries + listOf(context.getString(allSelectionRes!!)) + else listOf(context.getString(allSelectionRes!!)) + entries } else entries + val allPos = if (showAllLast) items.size - 1 else 0 + if (allSelectionRes != null && default.isEmpty()) default = intArrayOf(allPos) + else if (allSelectionRes != null && allIsAlwaysSelected) default += allPos positiveButton(android.R.string.ok) { val pos = mutableListOf() for (i in items.indices) - if (!(allSelectionRes != null && i == 0) && isItemChecked(i)) pos.add(i) + if (!(allSelectionRes != null && i == allPos) && isItemChecked(i)) pos.add(i) var value = pos.mapNotNull { - entryValues.getOrNull(it - if (allSelectionRes != null) 1 else 0) + entryValues.getOrNull(it - if (allSelectionRes != null && !showAllLast) 1 else 0) }.toSet() - if (allSelectionRes != null && isItemChecked(0)) value = emptySet() + if (allSelectionRes != null && !allIsAlwaysSelected && isItemChecked(0)) value = emptySet() prefs.getStringSet(key, emptySet()).set(value) callChangeListener(value) - this@MultiListMatPreference.summary = this@MultiListMatPreference.summary + notifyChanged() } listItemsMultiChoice( items = items, allowEmptySelection = true, - disabledIndices = if (allSelectionRes != null) intArrayOf(0) else null, + disabledIndices = if (allSelectionRes != null) intArrayOf(allPos) else null, waitForPositiveButton = false, initialSelection = default ) { _, pos, _ -> - if (allSelectionRes != null) { - if (pos.isEmpty()) checkItem(0) - else uncheckItem(0) + if (allSelectionRes != null && !allIsAlwaysSelected) { + if (pos.isEmpty()) checkItem(allPos) + else uncheckItem(allPos) } } } diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 885775df12..3bb84cb425 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -166,6 +166,7 @@ Hide category hopper on scroll More library settings Shift one page over + Shift double pages New chapters found @@ -198,6 +199,8 @@ Refresh covers in library as well when updating library Show a notification for errors + Buttons at bottom of reader + Certain buttons can be found in other places if disabled here Recents @@ -332,6 +335,8 @@ performance Invert double pages Crop borders + Crop borders (Paged) + Crop borders (Webtoon) Remove crop Use custom brightness Use custom color filter