Option to choose what buttons show up in the bottom reader sheet

+ Lots of optimizations/refactoring to custom preferences
This commit is contained in:
Jays2Kings 2021-04-15 02:55:46 -04:00
parent 053a5149c2
commit f12be4a480
10 changed files with 140 additions and 57 deletions

View File

@ -73,6 +73,8 @@ object PreferenceKeys {
const val invertDoublePages = "invert_double_pages" const val invertDoublePages = "invert_double_pages"
const val readerBottomButtons = "reader_bottom_buttons"
const val showNavigationOverlayNewUser = "reader_navigation_overlay_new_user" const val showNavigationOverlayNewUser = "reader_navigation_overlay_new_user"
const val showNavigationOverlayNewUserWebtoon = "reader_navigation_overlay_new_user_webtoon" const val showNavigationOverlayNewUserWebtoon = "reader_navigation_overlay_new_user_webtoon"

View File

@ -11,6 +11,7 @@ import com.f2prateek.rx.preferences.RxSharedPreferences
import com.tfcporciuncula.flow.FlowSharedPreferences import com.tfcporciuncula.flow.FlowSharedPreferences
import eu.kanade.tachiyomi.R import eu.kanade.tachiyomi.R
import eu.kanade.tachiyomi.data.track.TrackService 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.ViewerNavigation
import eu.kanade.tachiyomi.ui.reader.viewer.pager.PageLayout import eu.kanade.tachiyomi.ui.reader.viewer.pager.PageLayout
import eu.kanade.tachiyomi.ui.recents.RecentMangaAdapter import eu.kanade.tachiyomi.ui.recents.RecentMangaAdapter
@ -167,6 +168,11 @@ class PreferencesHelper(val context: Context) {
fun invertDoublePages() = flowPrefs.getBoolean(Keys.invertDoublePages, false) fun invertDoublePages() = flowPrefs.getBoolean(Keys.invertDoublePages, false)
fun readerBottomButtons() = flowPrefs.getStringSet(
Keys.readerBottomButtons,
ReaderActivity.BUTTONS_DEFAULTS
)
fun showNavigationOverlayNewUser() = flowPrefs.getBoolean(Keys.showNavigationOverlayNewUser, true) fun showNavigationOverlayNewUser() = flowPrefs.getBoolean(Keys.showNavigationOverlayNewUser, true)
fun showNavigationOverlayNewUserWebtoon() = flowPrefs.getBoolean(Keys.showNavigationOverlayNewUserWebtoon, true) fun showNavigationOverlayNewUserWebtoon() = flowPrefs.getBoolean(Keys.showNavigationOverlayNewUserWebtoon, true)

View File

@ -23,6 +23,7 @@ import android.view.WindowManager
import android.view.animation.Animation import android.view.animation.Animation
import android.view.animation.AnimationUtils import android.view.animation.AnimationUtils
import android.widget.SeekBar import android.widget.SeekBar
import androidx.annotation.StringRes
import androidx.core.content.ContextCompat import androidx.core.content.ContextCompat
import androidx.core.graphics.ColorUtils import androidx.core.graphics.ColorUtils
import androidx.core.view.isVisible import androidx.core.view.isVisible
@ -194,6 +195,13 @@ class ReaderActivity :
const val SHIFTED_PAGE_INDEX = "shiftedPageIndex" const val SHIFTED_PAGE_INDEX = "shiftedPageIndex"
const val SHIFTED_CHAP_INDEX = "shiftedChapterIndex" 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 { fun newIntent(context: Context, manga: Manga, chapter: Chapter): Intent {
val intent = Intent(context, ReaderActivity::class.java) val intent = Intent(context, ReaderActivity::class.java)
intent.putExtra("manga", manga.id) 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. * Called when the activity is created. Initializes the presenter and configuration.
*/ */
@ -324,8 +341,8 @@ class ReaderActivity :
override fun onPrepareOptionsMenu(menu: Menu?): Boolean { override fun onPrepareOptionsMenu(menu: Menu?): Boolean {
val splitItem = menu?.findItem(R.id.action_shift_double_page) val splitItem = menu?.findItem(R.id.action_shift_double_page)
splitItem?.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) && isTablet() binding.chaptersSheet.shiftPageButton.isVisible = ((viewer as? PagerViewer)?.config?.doublePages ?: false) && canShowSplitAtBottom()
(viewer as? PagerViewer)?.config?.let { config -> (viewer as? PagerViewer)?.config?.let { config ->
val icon = ContextCompat.getDrawable( val icon = ContextCompat.getDrawable(
this, this,
@ -344,6 +361,14 @@ class ReaderActivity :
return super.onPrepareOptionsMenu(menu) 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) { fun setBottomNavButtons(pageLayout: Int) {
val isDoublePage = pageLayout == PageLayout.DOUBLE_PAGES || val isDoublePage = pageLayout == PageLayout.DOUBLE_PAGES ||
(pageLayout == PageLayout.AUTOMATIC && (viewer as? PagerViewer)?.config?.doublePages ?: false) (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 * Called when an item of the options menu was clicked. Used to handle clicks on our menu
* entries. * entries.
@ -527,7 +565,8 @@ class ReaderActivity :
} }
} }
binding.chaptersSheet.doublePage.setOnClickListener { with(binding.chaptersSheet) {
doublePage.setOnClickListener {
if (preferences.pageLayout().get() == PageLayout.AUTOMATIC) { if (preferences.pageLayout().get() == PageLayout.AUTOMATIC) {
(viewer as? PagerViewer)?.config?.let { config -> (viewer as? PagerViewer)?.config?.let { config ->
config.doublePages = !config.doublePages config.doublePages = !config.doublePages
@ -537,9 +576,11 @@ class ReaderActivity :
preferences.pageLayout().set(1 - preferences.pageLayout().get()) preferences.pageLayout().set(1 - preferences.pageLayout().get())
} }
} }
binding.chaptersSheet.cropBordersSheetButton.setOnClickListener { cropBordersSheetButton.setOnClickListener {
(viewer as? WebtoonViewer)?.let { val pref =
val pref = if (it.hasMargins) preferences.cropBorders() else preferences.cropBordersWebtoon() if ((viewer as? WebtoonViewer)?.hasMargins == true ||
(viewer is PagerViewer)
) preferences.cropBorders() else preferences.cropBordersWebtoon()
pref.toggle() pref.toggle()
} }
} }
@ -793,8 +834,6 @@ class ReaderActivity :
binding.viewerContainer.removeAllViews() binding.viewerContainer.removeAllViews()
} }
viewer = newViewer viewer = newViewer
binding.chaptersSheet.doublePage.isVisible = viewer is PagerViewer
binding.chaptersSheet.cropBordersSheetButton.isVisible = viewer !is PagerViewer
binding.viewerContainer.addView(newViewer.getView()) binding.viewerContainer.addView(newViewer.getView())
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { 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)) binding.pleaseWait.startAnimation(AnimationUtils.loadAnimation(this, R.anim.fade_in_long))
invalidateOptionsMenu() invalidateOptionsMenu()
updateCropBordersShortcut() updateCropBordersShortcut()
updateBasicShortcuts()
} }
override fun onPause() { override fun onPause() {
@ -1351,6 +1391,12 @@ class ReaderActivity :
setBottomNavButtons(it) setBottomNavButtons(it)
} }
.launchIn(scope) .launchIn(scope)
preferences.readerBottomButtons().asFlow()
.onEach {
updateBasicShortcuts()
}
.launchIn(scope)
} }
/** /**

View File

@ -95,18 +95,6 @@ class SettingsDownloadController : SettingsController() {
allSelectionRes = R.string.all allSelectionRes = R.string.all
preferences.downloadNew().asImmediateFlow(viewScope) { isVisible = it } 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 { preferenceCategory {
intListPreference(activity) { intListPreference(activity) {

View File

@ -6,7 +6,6 @@ import eu.kanade.tachiyomi.R
import eu.kanade.tachiyomi.data.database.DatabaseHelper import eu.kanade.tachiyomi.data.database.DatabaseHelper
import eu.kanade.tachiyomi.data.database.models.Category import eu.kanade.tachiyomi.data.database.models.Category
import eu.kanade.tachiyomi.data.library.LibraryUpdateJob 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.ui.category.CategoryController
import eu.kanade.tachiyomi.util.view.withFadeTransaction import eu.kanade.tachiyomi.util.view.withFadeTransaction
import uy.kohesive.injekt.Injekt import uy.kohesive.injekt.Injekt
@ -134,16 +133,6 @@ class SettingsLibraryController : SettingsController() {
entries = dbCategories.map { it.name } entries = dbCategories.map { it.name }
entryValues = dbCategories.map { it.id.toString() } entryValues = dbCategories.map { it.id.toString() }
allSelectionRes = R.string.all 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) { intListPreference(activity) {
key = Keys.updateOnRefresh key = Keys.updateOnRefresh

View File

@ -4,6 +4,7 @@ import android.os.Build
import androidx.preference.PreferenceScreen import androidx.preference.PreferenceScreen
import eu.kanade.tachiyomi.R import eu.kanade.tachiyomi.R
import eu.kanade.tachiyomi.data.preference.asImmediateFlow 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.ViewerNavigation
import eu.kanade.tachiyomi.ui.reader.viewer.pager.PageLayout import eu.kanade.tachiyomi.ui.reader.viewer.pager.PageLayout
import eu.kanade.tachiyomi.util.lang.addBetaTag import eu.kanade.tachiyomi.util.lang.addBetaTag
@ -66,6 +67,18 @@ class SettingsReaderController : SettingsController() {
defaultValue = 6 defaultValue = 6
summaryRes = R.string.amount_of_pages_to_preload 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 { preferenceCategory {

View File

@ -23,7 +23,7 @@ open class ListMatPreference @JvmOverloads constructor(
var entriesRes: Array<Int> var entriesRes: Array<Int>
get() = emptyArray() get() = emptyArray()
set(value) { entries = value.map { context.getString(it) } } set(value) { entries = value.map { context.getString(it) } }
protected var defValue: String = "" private var defValue: String = ""
var entries: List<String> = emptyList() var entries: List<String> = emptyList()
override fun onSetInitialValue(defaultValue: Any?) { override fun onSetInitialValue(defaultValue: Any?) {

View File

@ -50,6 +50,7 @@ open class MatPreference @JvmOverloads constructor(
summaryProvider = customSummaryProvider summaryProvider = customSummaryProvider
return return
} else { } else {
customSummaryProvider = null
summaryProvider = null summaryProvider = null
} }
super.setSummary(summaryResId) super.setSummary(summaryResId)
@ -60,6 +61,7 @@ open class MatPreference @JvmOverloads constructor(
summaryProvider = customSummaryProvider summaryProvider = customSummaryProvider
return return
} else { } else {
customSummaryProvider = null
summaryProvider = null summaryProvider = null
} }
super.setSummary(summary) super.setSummary(summary)

View File

@ -10,6 +10,7 @@ import com.afollestad.materialdialogs.list.isItemChecked
import com.afollestad.materialdialogs.list.listItemsMultiChoice import com.afollestad.materialdialogs.list.listItemsMultiChoice
import com.afollestad.materialdialogs.list.uncheckItem import com.afollestad.materialdialogs.list.uncheckItem
import eu.kanade.tachiyomi.data.preference.getOrDefault import eu.kanade.tachiyomi.data.preference.getOrDefault
import eu.kanade.tachiyomi.ui.setting.defaultValue
class MultiListMatPreference @JvmOverloads constructor( class MultiListMatPreference @JvmOverloads constructor(
activity: Activity?, activity: Activity?,
@ -21,49 +22,80 @@ class MultiListMatPreference @JvmOverloads constructor(
var allSelectionRes: Int? = null var allSelectionRes: Int? = null
override var customSummaryProvider: SummaryProvider<MatPreference>? = SummaryProvider<MatPreference> { /** All item is always selected and uncheckabele */
prefs.getStringSet(key, emptySet<String>()).getOrDefault().mapNotNull { var allIsAlwaysSelected = false
if (entryValues.indexOf(it) == -1) null set(value) {
else entryValues.indexOf(it) + if (allSelectionRes != null) 1 else 0 field = value
}.toIntArray().joinToString(",") { notifyChanged()
entries[it]
} }
/** All Item is moved to bottom of list if true */
var showAllLast = false
set(value) {
field = value
notifyChanged()
}
private var defValue: Set<String> = emptySet()
override fun onSetInitialValue(defaultValue: Any?) {
super.onSetInitialValue(defaultValue)
defValue = (defaultValue as? Set<*>).orEmpty().mapNotNull { it as? String }.toSet()
}
override var customSummaryProvider: SummaryProvider<MatPreference>? = SummaryProvider<MatPreference> {
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") @SuppressLint("CheckResult")
override fun MaterialDialog.setItems() { override fun MaterialDialog.setItems() {
val set = prefs.getStringSet(key, emptySet()).getOrDefault() val set = prefs.getStringSet(key, defValue).getOrDefault()
var default = set.mapNotNull { var default = set.mapNotNull {
if (entryValues.indexOf(it) == -1) null 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() .toIntArray()
if (allSelectionRes != null && default.isEmpty()) default = intArrayOf(0)
val items = if (allSelectionRes != null) { 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 } 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) { positiveButton(android.R.string.ok) {
val pos = mutableListOf<Int>() val pos = mutableListOf<Int>()
for (i in items.indices) 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 { var value = pos.mapNotNull {
entryValues.getOrNull(it - if (allSelectionRes != null) 1 else 0) entryValues.getOrNull(it - if (allSelectionRes != null && !showAllLast) 1 else 0)
}.toSet() }.toSet()
if (allSelectionRes != null && isItemChecked(0)) value = emptySet() if (allSelectionRes != null && !allIsAlwaysSelected && isItemChecked(0)) value = emptySet()
prefs.getStringSet(key, emptySet()).set(value) prefs.getStringSet(key, emptySet()).set(value)
callChangeListener(value) callChangeListener(value)
this@MultiListMatPreference.summary = this@MultiListMatPreference.summary notifyChanged()
} }
listItemsMultiChoice( listItemsMultiChoice(
items = items, items = items,
allowEmptySelection = true, allowEmptySelection = true,
disabledIndices = if (allSelectionRes != null) intArrayOf(0) else null, disabledIndices = if (allSelectionRes != null) intArrayOf(allPos) else null,
waitForPositiveButton = false, waitForPositiveButton = false,
initialSelection = default initialSelection = default
) { _, pos, _ -> ) { _, pos, _ ->
if (allSelectionRes != null) { if (allSelectionRes != null && !allIsAlwaysSelected) {
if (pos.isEmpty()) checkItem(0) if (pos.isEmpty()) checkItem(allPos)
else uncheckItem(0) else uncheckItem(allPos)
} }
} }
} }

View File

@ -166,6 +166,7 @@
<string name="hide_hopper_on_scroll">Hide category hopper on scroll</string> <string name="hide_hopper_on_scroll">Hide category hopper on scroll</string>
<string name="more_library_settings">More library settings</string> <string name="more_library_settings">More library settings</string>
<string name="shift_one_page_over">Shift one page over</string> <string name="shift_one_page_over">Shift one page over</string>
<string name="shift_double_pages">Shift double pages</string>
<!-- Library update service notifications --> <!-- Library update service notifications -->
<string name="new_chapters_found">New chapters found</string> <string name="new_chapters_found">New chapters found</string>
@ -198,6 +199,8 @@
<string name="auto_refresh_covers_summary">Refresh covers in library as well <string name="auto_refresh_covers_summary">Refresh covers in library as well
when updating library</string> when updating library</string>
<string name="show_notification_error">Show a notification for errors</string> <string name="show_notification_error">Show a notification for errors</string>
<string name="display_buttons_bottom_reader">Buttons at bottom of reader</string>
<string name="certain_buttons_can_be_found">Certain buttons can be found in other places if disabled here</string>
<!-- Recents --> <!-- Recents -->
<string name="recents">Recents</string> <string name="recents">Recents</string>
@ -332,6 +335,8 @@
performance</string> performance</string>
<string name="invert_double_pages">Invert double pages</string> <string name="invert_double_pages">Invert double pages</string>
<string name="crop_borders">Crop borders</string> <string name="crop_borders">Crop borders</string>
<string name="crop_borders_paged">Crop borders (Paged)</string>
<string name="crop_borders_webtoon">Crop borders (Webtoon)</string>
<string name="remove_crop">Remove crop</string> <string name="remove_crop">Remove crop</string>
<string name="use_custom_brightness">Use custom brightness</string> <string name="use_custom_brightness">Use custom brightness</string>
<string name="use_custom_color_filter">Use custom color filter</string> <string name="use_custom_color_filter">Use custom color filter</string>