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 830e420501..160d6801e2 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 @@ -49,8 +49,6 @@ object PreferenceKeys { const val readWithTapping = "reader_tap" - const val readWithLongTap = "reader_long_tap" - const val readWithVolumeKeys = "reader_volume_keys" const val readWithVolumeKeysInverted = "reader_volume_keys_inverted" 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 1064798ee7..16a8ab554d 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 @@ -126,8 +126,6 @@ class PreferencesHelper(val context: Context) { fun readWithTapping() = flowPrefs.getBoolean(Keys.readWithTapping, true) - fun readWithLongTap() = flowPrefs.getBoolean(Keys.readWithLongTap, true) - fun readWithVolumeKeys() = flowPrefs.getBoolean(Keys.readWithVolumeKeys, false) fun readWithVolumeKeysInverted() = flowPrefs.getBoolean(Keys.readWithVolumeKeysInverted, false) diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/library/display/LibraryBadgesView.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/library/display/LibraryBadgesView.kt index c5ef27e6da..cdb839d6e7 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/library/display/LibraryBadgesView.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/library/display/LibraryBadgesView.kt @@ -2,7 +2,7 @@ package eu.kanade.tachiyomi.ui.library.display import android.content.Context import android.util.AttributeSet -import eu.kanade.tachiyomi.ui.library.LibraryController +import eu.kanade.tachiyomi.util.bindToPreference import kotlinx.android.synthetic.main.library_badges_layout.view.* class LibraryBadgesView @JvmOverloads constructor(context: Context, attrs: AttributeSet? = null) : diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/library/display/LibraryCategoryView.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/library/display/LibraryCategoryView.kt index b172b7e12e..6a43e3e1f3 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/library/display/LibraryCategoryView.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/library/display/LibraryCategoryView.kt @@ -2,6 +2,7 @@ package eu.kanade.tachiyomi.ui.library.display import android.content.Context import android.util.AttributeSet +import eu.kanade.tachiyomi.util.bindToPreference import kotlinx.android.synthetic.main.library_category_layout.view.* class LibraryCategoryView @JvmOverloads constructor(context: Context, attrs: AttributeSet? = null) : diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/library/display/LibraryDisplayView.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/library/display/LibraryDisplayView.kt index 45e34b96a0..841d794904 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/library/display/LibraryDisplayView.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/library/display/LibraryDisplayView.kt @@ -2,6 +2,7 @@ package eu.kanade.tachiyomi.ui.library.display import android.content.Context import android.util.AttributeSet +import eu.kanade.tachiyomi.util.bindToPreference import kotlinx.android.synthetic.main.library_display_layout.view.* class LibraryDisplayView @JvmOverloads constructor(context: Context, attrs: AttributeSet? = null) : diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/library/display/LibraryPreferenceView.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/library/display/LibraryPreferenceView.kt index 3ca80daaa9..14629dcec4 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/library/display/LibraryPreferenceView.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/library/display/LibraryPreferenceView.kt @@ -25,42 +25,4 @@ abstract class LibraryPreferenceView @JvmOverloads constructor(context: Context, super.onFinishInflate() initGeneralPreferences() } - - /** - * Binds a checkbox or switch view with a boolean preference. - */ - internal fun CompoundButton.bindToPreference(pref: Preference, block: (() -> Unit)? = null) { - isChecked = pref.getOrDefault() - setOnCheckedChangeListener { _, isChecked -> - pref.set(isChecked) - block?.invoke() - } - } - - /** - * Binds a checkbox or switch view with a boolean preference. - */ - internal fun CompoundButton.bindToPreference( - pref: com.tfcporciuncula.flow - .Preference, - block: ((Boolean) -> Unit)? = null - ) { - isChecked = pref.get() - setOnCheckedChangeListener { _, isChecked -> - pref.set(isChecked) - block?.invoke(isChecked) - } - } - - /** - * Binds a radio group with a int preference. - */ - internal fun RadioGroup.bindToPreference(pref: Preference, block: (() -> Unit)? = null) { - (getChildAt(pref.getOrDefault()) as RadioButton).isChecked = true - setOnCheckedChangeListener { _, checkedId -> - val index = indexOfChild(findViewById(checkedId)) - pref.set(index) - block?.invoke() - } - } } \ No newline at end of file diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/library/display/TabbedLibraryDisplaySheet.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/library/display/TabbedLibraryDisplaySheet.kt index 06399dbd58..4917c89967 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/library/display/TabbedLibraryDisplaySheet.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/library/display/TabbedLibraryDisplaySheet.kt @@ -12,7 +12,7 @@ import eu.kanade.tachiyomi.widget.TabbedBottomSheetDialog import kotlinx.android.synthetic.main.tabbed_bottom_sheet.* open class TabbedLibraryDisplaySheet(controller: LibraryController): - TabbedBottomSheetDialog(controller) { + TabbedBottomSheetDialog(controller.activity!!) { private val displayView: LibraryDisplayView = inflate(controller.activity!!, R.layout.library_display_layout, null) as LibraryDisplayView private val badgesView: LibraryBadgesView = inflate(controller.activity!!, R.layout.library_badges_layout, null) as LibraryBadgesView diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/main/MainActivity.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/main/MainActivity.kt index 7d27566344..14aad42238 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/main/MainActivity.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/main/MainActivity.kt @@ -693,6 +693,7 @@ open class MainActivity : BaseActivity(), DownloadServiceListener { const val SHORTCUT_BROWSE = "eu.kanade.tachiyomi.SHOW_BROWSE" const val SHORTCUT_DOWNLOADS = "eu.kanade.tachiyomi.SHOW_DOWNLOADS" const val SHORTCUT_MANGA = "eu.kanade.tachiyomi.SHOW_MANGA" + const val SHORTCUT_READER_SETTINGS = "eu.kanade.tachiyomi.READER_SETTINGS" const val SHORTCUT_EXTENSIONS = "eu.kanade.tachiyomi.EXTENSIONS" const val INTENT_SEARCH = "eu.kanade.tachiyomi.SEARCH" diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/main/SearchActivity.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/main/SearchActivity.kt index 4f6b650186..78dda395c1 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/main/SearchActivity.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/main/SearchActivity.kt @@ -12,6 +12,7 @@ import eu.kanade.tachiyomi.data.notification.NotificationReceiver import eu.kanade.tachiyomi.ui.base.controller.DialogController import eu.kanade.tachiyomi.ui.manga.MangaDetailsController import eu.kanade.tachiyomi.ui.security.SecureActivityDelegate +import eu.kanade.tachiyomi.ui.setting.SettingsReaderController import eu.kanade.tachiyomi.ui.source.global_search.GlobalSearchController import eu.kanade.tachiyomi.util.view.gone import eu.kanade.tachiyomi.util.view.withFadeTransaction @@ -35,7 +36,7 @@ class SearchActivity : MainActivity() { } private fun popToRoot() { - if (intent.action == SHORTCUT_MANGA) { + if (intent.action == SHORTCUT_MANGA || intent.action == SHORTCUT_READER_SETTINGS) { onBackPressed() } else if (!router.handleBack()) { val intent = Intent(this, MainActivity::class.java).apply { @@ -97,6 +98,13 @@ class SearchActivity : MainActivity() { .popChangeHandler(FadeChangeHandler()) ) } + SHORTCUT_READER_SETTINGS -> { + router.replaceTopController( + RouterTransaction.with(SettingsReaderController()) + .pushChangeHandler(SimpleSwapChangeHandler()) + .popChangeHandler(FadeChangeHandler()) + ) + } else -> return false } return true @@ -112,5 +120,14 @@ class SearchActivity : MainActivity() { action = SHORTCUT_MANGA putExtra(MangaDetailsController.MANGA_EXTRA, id) } + + fun openReaderSettings(context: Context) = Intent( + context, + SearchActivity::class + .java + ) + .apply { + action = SHORTCUT_READER_SETTINGS + } } } 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 5debb8e552..f2c65b62db 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 @@ -43,6 +43,7 @@ import eu.kanade.tachiyomi.ui.reader.ReaderPresenter.SetAsCoverResult.Success import eu.kanade.tachiyomi.ui.reader.model.ReaderChapter import eu.kanade.tachiyomi.ui.reader.model.ReaderPage import eu.kanade.tachiyomi.ui.reader.model.ViewerChapters +import eu.kanade.tachiyomi.ui.reader.settings.TabbedReaderSettingsSheet import eu.kanade.tachiyomi.ui.reader.viewer.BaseViewer import eu.kanade.tachiyomi.ui.reader.viewer.pager.L2RPagerViewer import eu.kanade.tachiyomi.ui.reader.viewer.pager.R2LPagerViewer @@ -279,21 +280,46 @@ class ReaderActivity : return true } + override fun onPrepareOptionsMenu(menu: Menu?): Boolean { + val detailsItem = menu?.findItem(R.id.action_manga_details) + if (presenter.manga?.mangaType(this) != null) { + detailsItem?.title = getString(R.string._details, + presenter.manga?.mangaType(this)?.capitalize(Locale.ROOT) ?: "") + } else { + detailsItem?.title = getString(R.string.details) + } + return super.onPrepareOptionsMenu(menu) + } + /** * Called when an item of the options menu was clicked. Used to handle clicks on our menu * entries. */ override fun onOptionsItemSelected(item: MenuItem): Boolean { coroutine?.cancel() - bottomSheet = when (item.itemId) { - R.id.action_settings -> ReaderSettingsSheet(this) - R.id.action_custom_filter -> ReaderColorFilterSheet(this) + when (item.itemId) { + R.id.action_display_settings -> TabbedReaderSettingsSheet(this).show() + R.id.action_manga_details -> { + presenter.manga?.id?.let { id -> + val intent = SearchActivity.openMangaIntent(this, id) + startActivity(intent) + } + } + R.id.action_share_page, R.id.action_set_page_as_cover, R.id.action_save_page -> { + val currentChapter = presenter.getCurrentChapter() ?: return true + val page = currentChapter.pages?.getOrNull(page_seekbar.progress) ?: return true + when (item.itemId) { + R.id.action_share_page -> shareImage(page) + R.id.action_set_page_as_cover -> showSetCoverPrompt(page) + R.id.action_save_page -> saveImage(page) + } + } + R.id.action_reader_settings -> { + val intent = SearchActivity.openReaderSettings(this) + startActivity(intent) + } else -> return super.onOptionsItemSelected(item) } - bottomSheet?.show() - if (chapters_bottom_sheet.sheetBehavior.isExpanded()) { - chapters_bottom_sheet.sheetBehavior?.collapse() - } return true } @@ -357,13 +383,6 @@ class ReaderActivity : popToMain() } - toolbar.setOnClickListener { - presenter.manga?.id?.let { id -> - val intent = SearchActivity.openMangaIntent(this, id) - startActivity(intent) - } - } - // Init listeners on bottom menu page_seekbar.setOnSeekBarChangeListener( object : SimpleSeekBarListener() { @@ -477,6 +496,7 @@ class ReaderActivity : val prevViewer = viewer val noDefault = manga.viewer == -1 val mangaViewer = presenter.getMangaViewer() + invalidateOptionsMenu() val newViewer = when (mangaViewer) { RIGHT_TO_LEFT -> R2LPagerViewer(this) VERTICAL -> VerticalPagerViewer(this) @@ -615,41 +635,6 @@ class ReaderActivity : page_seekbar.progress = page.index } - /** - * Called from the viewer whenever a [page] is long clicked. A bottom sheet with a list of - * actions to perform is shown. - */ - fun onPageLongTap(page: ReaderPage) { - val items = listOf( - MaterialMenuSheet.MenuSheetItem( - 0, - R.drawable.ic_photo_24dp, - R.string.set_as_cover - ), - MaterialMenuSheet.MenuSheetItem( - 1, - R.drawable.ic_share_24dp, - R.string.share - ), - MaterialMenuSheet.MenuSheetItem( - 2, - R.drawable.ic_save_24dp, - R.string.save - ) - ) - MaterialMenuSheet(this, items) { _, item -> - when (item) { - 0 -> showSetCoverPrompt(page) - 1 -> shareImage(page) - 2 -> saveImage(page) - } - true - }.show() - if (chapters_bottom_sheet.sheetBehavior.isExpanded()) { - chapters_bottom_sheet.sheetBehavior?.collapse() - } - } - /** * Called from the viewer when the given [chapter] should be preloaded. It should be called when * the viewer is reaching the beginning or end of a chapter or the transition page is active. diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/reader/ReaderSettingsSheet.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/reader/ReaderSettingsSheet.kt deleted file mode 100644 index ce19647924..0000000000 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/reader/ReaderSettingsSheet.kt +++ /dev/null @@ -1,194 +0,0 @@ -package eu.kanade.tachiyomi.ui.reader - -import android.content.res.Configuration -import android.graphics.Color -import android.os.Build -import android.os.Bundle -import android.view.View -import android.view.ViewGroup -import android.widget.CompoundButton -import android.widget.Spinner -import androidx.annotation.ArrayRes -import com.google.android.material.bottomsheet.BottomSheetBehavior -import com.google.android.material.bottomsheet.BottomSheetDialog -import com.tfcporciuncula.flow.Preference -import eu.kanade.tachiyomi.R -import eu.kanade.tachiyomi.data.preference.PreferencesHelper -import eu.kanade.tachiyomi.ui.reader.viewer.pager.PagerViewer -import eu.kanade.tachiyomi.ui.reader.viewer.webtoon.WebtoonViewer -import eu.kanade.tachiyomi.util.system.dpToPx -import eu.kanade.tachiyomi.util.system.hasSideNavBar -import eu.kanade.tachiyomi.util.system.isInNightMode -import eu.kanade.tachiyomi.util.view.gone -import eu.kanade.tachiyomi.util.view.setBottomEdge -import eu.kanade.tachiyomi.util.view.setEdgeToEdge -import eu.kanade.tachiyomi.util.view.visible -import eu.kanade.tachiyomi.util.view.visibleIf -import eu.kanade.tachiyomi.widget.IgnoreFirstSpinnerListener -import kotlinx.android.synthetic.main.reader_settings_sheet.* -import uy.kohesive.injekt.injectLazy -import kotlin.math.max - -/** - * Sheet to show reader and viewer preferences. - */ -class ReaderSettingsSheet(private val activity: ReaderActivity) : - BottomSheetDialog(activity, R.style.BottomSheetDialogTheme) { - - /** - * Preferences helper. - */ - private val preferences by injectLazy() - - private var sheetBehavior: BottomSheetBehavior<*> - - init { - // Use activity theme for this layout - val view = activity.layoutInflater.inflate(R.layout.reader_settings_sheet, null) - setContentView(view) - - sheetBehavior = BottomSheetBehavior.from(view.parent as ViewGroup) - setEdgeToEdge( - activity, - view, - if (context.resources.configuration.orientation == Configuration.ORIENTATION_LANDSCAPE) - 0 else -1 - ) - window?.navigationBarColor = Color.TRANSPARENT - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O && - !context.isInNightMode() && - !activity.window.decorView.rootWindowInsets.hasSideNavBar() - ) { - window?.decorView?.systemUiVisibility = View.SYSTEM_UI_FLAG_LIGHT_NAVIGATION_BAR - } - - val height = activity.window.decorView.rootWindowInsets.systemWindowInsetBottom - sheetBehavior.peekHeight = 550.dpToPx + height - - sheetBehavior.addBottomSheetCallback( - object : BottomSheetBehavior.BottomSheetCallback() { - override fun onSlide(bottomSheet: View, progress: Float) { - if (progress.isNaN()) - pill.alpha = 0f - else - pill.alpha = (1 - max(0f, progress)) * 0.25f - } - - override fun onStateChanged(p0: View, state: Int) { - if (state == BottomSheetBehavior.STATE_EXPANDED) { - sheetBehavior.skipCollapsed = true - } - } - } - ) - } - - /** - * Called when the sheet is created. It initializes the listeners and values of the preferences. - */ - override fun onCreate(savedInstanceState: Bundle?) { - super.onCreate(savedInstanceState) - - initGeneralPreferences() - - when (val view = activity.viewer) { - is PagerViewer -> initPagerPreferences() - is WebtoonViewer -> initWebtoonPreferences(view.hasMargins) - } - - setBottomEdge(constraint_layout, activity) - - close_button.setOnClickListener { - dismiss() - } - settings_scroll_view.viewTreeObserver.addOnGlobalLayoutListener { - val isScrollable = - settings_scroll_view.height < constraint_layout.height + - settings_scroll_view.paddingTop + settings_scroll_view.paddingBottom - close_button.visibleIf(isScrollable) - pill.visibleIf(!isScrollable) - } - } - - /** - * Init general reader preferences. - */ - private fun initGeneralPreferences() { - viewer.onItemSelectedListener = IgnoreFirstSpinnerListener { position -> - activity.presenter.setMangaViewer(position) - - val mangaViewer = activity.presenter.getMangaViewer() - if (mangaViewer == ReaderActivity.WEBTOON || mangaViewer == ReaderActivity.VERTICAL_PLUS) { - initWebtoonPreferences(mangaViewer == ReaderActivity.VERTICAL_PLUS) - } else { - initPagerPreferences() - } - } - viewer.setSelection(activity.presenter.manga?.viewer ?: 0, false) - - rotation_mode.bindToPreference(preferences.rotation(), 1) - background_color.bindToPreference(preferences.readerTheme(), 0) - show_page_number.bindToPreference(preferences.showPageNumber()) - fullscreen.bindToPreference(preferences.fullscreen()) - keepscreen.bindToPreference(preferences.keepScreenOn()) - always_show_chapter_transition.bindToPreference(preferences.alwaysShowChapterTransition()) - } - - /** - * Init the preferences for the pager reader. - */ - private fun initPagerPreferences() { - pager_prefs_group.visible() - webtoon_prefs_group.gone() - scale_type.bindToPreference(preferences.imageScaleType(), 1) - zoom_start.bindToPreference(preferences.zoomStart(), 1) - crop_borders.bindToPreference(preferences.cropBorders()) - page_transitions.bindToPreference(preferences.pageTransitions()) - } - - /** - * Init the preferences for the webtoon reader. - */ - private fun initWebtoonPreferences(hasMargins: Boolean) { - webtoon_prefs_group.visible() - pager_prefs_group.gone() - crop_borders_webtoon.bindToPreference(if (hasMargins) preferences.cropBorders() else preferences.cropBordersWebtoon()) - webtoon_side_padding.bindToIntPreference(preferences.webtoonSidePadding(), R.array.webtoon_side_padding_values) - webtoon_enable_zoom_out.bindToPreference(preferences.webtoonEnableZoomOut()) - } - - /** - * Binds a checkbox or switch view with a boolean preference. - */ - private fun CompoundButton.bindToPreference(pref: Preference) { - setOnCheckedChangeListener(null) - isChecked = pref.get() - setOnCheckedChangeListener { _, isChecked -> pref.set(isChecked) } - } - - /** - * Binds a spinner to an int preference with an optional offset for the value. - */ - private fun Spinner.bindToPreference( - pref: Preference, - offset: Int = 0 - ) { - onItemSelectedListener = IgnoreFirstSpinnerListener { position -> - pref.set(position + offset) - } - setSelection(pref.get() - offset, false) - } - - /** - * Binds a spinner to an int preference. The position of the spinner item must - * correlate with the [intValues] resource item (in arrays.xml), which is a - * of int values that will be parsed here and applied to the preference. - */ - private fun Spinner.bindToIntPreference(pref: Preference, @ArrayRes intValuesResource: Int) { - val intValues = resources.getStringArray(intValuesResource).map { it.toIntOrNull() } - onItemSelectedListener = IgnoreFirstSpinnerListener { position -> - pref.set(intValues[position] ?: 0) - } - setSelection(intValues.indexOf(pref.get()), false) - } -} diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/reader/settings/BaseReaderSettingsView.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/reader/settings/BaseReaderSettingsView.kt new file mode 100644 index 0000000000..a0bd99060b --- /dev/null +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/reader/settings/BaseReaderSettingsView.kt @@ -0,0 +1,25 @@ +package eu.kanade.tachiyomi.ui.reader.settings + +import android.content.Context +import android.util.AttributeSet +import android.widget.FrameLayout +import android.widget.LinearLayout +import com.google.android.material.tabs.TabLayout +import eu.kanade.tachiyomi.data.preference.PreferencesHelper +import eu.kanade.tachiyomi.ui.library.LibraryController +import eu.kanade.tachiyomi.ui.reader.ReaderActivity +import uy.kohesive.injekt.injectLazy + +abstract class BaseReaderSettingsView @JvmOverloads constructor(context: Context, attrs: AttributeSet? = null) : + FrameLayout(context, attrs) { + + internal val preferences by injectLazy() + lateinit var activity: ReaderActivity + + abstract fun initGeneralPreferences() + + override fun onFinishInflate() { + super.onFinishInflate() + initGeneralPreferences() + } +} \ No newline at end of file diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/reader/ReaderColorFilterSheet.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/reader/settings/ReaderFilterView.kt similarity index 63% rename from app/src/main/java/eu/kanade/tachiyomi/ui/reader/ReaderColorFilterSheet.kt rename to app/src/main/java/eu/kanade/tachiyomi/ui/reader/settings/ReaderFilterView.kt index c8b13807cf..902e7b0382 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/reader/ReaderColorFilterSheet.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/reader/settings/ReaderFilterView.kt @@ -1,74 +1,44 @@ -package eu.kanade.tachiyomi.ui.reader +package eu.kanade.tachiyomi.ui.reader.settings -import android.graphics.Color -import android.os.Build -import android.view.View -import android.view.ViewGroup +import android.content.Context +import android.util.AttributeSet import android.widget.SeekBar import androidx.annotation.ColorInt -import com.google.android.material.bottomsheet.BottomSheetBehavior -import com.google.android.material.bottomsheet.BottomSheetDialog -import eu.kanade.tachiyomi.R -import eu.kanade.tachiyomi.data.preference.PreferencesHelper -import eu.kanade.tachiyomi.util.system.hasSideNavBar -import eu.kanade.tachiyomi.util.system.isInNightMode -import eu.kanade.tachiyomi.util.view.expand -import eu.kanade.tachiyomi.util.view.gone -import eu.kanade.tachiyomi.util.view.setBottomEdge -import eu.kanade.tachiyomi.util.view.setEdgeToEdge -import eu.kanade.tachiyomi.util.view.visible +import eu.kanade.tachiyomi.ui.reader.ReaderActivity +import eu.kanade.tachiyomi.util.view.RecyclerWindowInsetsListener import eu.kanade.tachiyomi.widget.IgnoreFirstSpinnerListener import eu.kanade.tachiyomi.widget.SimpleSeekBarListener import kotlinx.android.synthetic.main.reader_color_filter.* -import kotlinx.android.synthetic.main.reader_color_filter_sheet.* +import kotlinx.android.synthetic.main.reader_color_filter.view.* +import kotlinx.android.synthetic.main.reader_color_filter.view.settings_scroll_view +import kotlinx.android.synthetic.main.reader_general_layout.view.* import kotlinx.coroutines.flow.launchIn import kotlinx.coroutines.flow.onEach import kotlinx.coroutines.flow.sample -import uy.kohesive.injekt.injectLazy -import kotlin.math.abs -/** - * Color filter sheet to toggle custom filter and brightness overlay. - */ -class ReaderColorFilterSheet(private val activity: ReaderActivity) : BottomSheetDialog -(activity, R.style.BottomSheetDialogTheme) { - - private val preferences by injectLazy() - - private var sheetBehavior: BottomSheetBehavior<*>? = null - - init { - val view = activity.layoutInflater.inflate(R.layout.reader_color_filter_sheet, null) - setContentView(view) - - setEdgeToEdge(activity, view, 0) - window?.navigationBarColor = Color.TRANSPARENT - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O && - !context.isInNightMode() && - !activity.window.decorView.rootWindowInsets.hasSideNavBar() - ) - window?.decorView?.systemUiVisibility = View.SYSTEM_UI_FLAG_LIGHT_NAVIGATION_BAR - setBottomEdge(brightness_seekbar, activity) - - sheetBehavior = BottomSheetBehavior.from(view.parent as ViewGroup) +class ReaderFilterView @JvmOverloads constructor(context: Context, attrs: AttributeSet? = null) : + BaseReaderSettingsView(context, attrs) { + override fun initGeneralPreferences() { + activity = context as ReaderActivity + settings_scroll_view.setOnApplyWindowInsetsListener(RecyclerWindowInsetsListener) preferences.colorFilter().asFlow() - .onEach { setColorFilter(it, view) } + .onEach { setColorFilter(it) } .launchIn(activity.scope) preferences.colorFilterMode().asFlow() - .onEach { setColorFilter(preferences.colorFilter().get(), view) } + .onEach { setColorFilter(preferences.colorFilter().get()) } .launchIn(activity.scope) preferences.customBrightness().asFlow() - .onEach { setCustomBrightness(it, view) } + .onEach { setCustomBrightness(it) } .launchIn(activity.scope) // Get color and update values val color = preferences.colorFilterValue().get() val brightness = preferences.customBrightnessValue().get() - val argb = setValues(color, view) + val argb = setValues(color) // Set brightness value txt_brightness_seekbar_value.text = brightness.toString() @@ -91,14 +61,13 @@ class ReaderColorFilterSheet(private val activity: ReaderActivity) : BottomSheet preferences.customBrightness().set(isChecked) } - color_filter_mode.onItemSelectedListener = IgnoreFirstSpinnerListener { position -> - preferences.colorFilterMode().set(position) - } - color_filter_mode.setSelection(preferences.colorFilterMode().get(), false) - + color_filter_mode.bindToPreference(preferences.colorFilterMode()) seekbar_color_filter_alpha.setOnSeekBarChangeListener( object : SimpleSeekBarListener() { override fun onProgressChanged(seekBar: SeekBar, value: Int, fromUser: Boolean) { + seekbar_color_filter_red.isEnabled = value > 0 && seekbar_color_filter_alpha.isEnabled + seekbar_color_filter_green.isEnabled = value > 0 && seekbar_color_filter_alpha.isEnabled + seekbar_color_filter_blue.isEnabled = value > 0 && seekbar_color_filter_alpha.isEnabled if (fromUser) { setColorValue(value, ALPHA_MASK, 24) } @@ -147,39 +116,31 @@ class ReaderColorFilterSheet(private val activity: ReaderActivity) : BottomSheet ) } - override fun onStart() { - super.onStart() - sheetBehavior?.skipCollapsed = true - sheetBehavior?.expand() - } /** * Set enabled status of seekBars belonging to color filter * @param enabled determines if seekBar gets enabled - * @param view view of the dialog */ - private fun setColorFilterSeekBar(enabled: Boolean, view: View) = with(view) { - seekbar_color_filter_red.isEnabled = enabled - seekbar_color_filter_green.isEnabled = enabled - seekbar_color_filter_blue.isEnabled = enabled + private fun setColorFilterSeekBar(enabled: Boolean) { + seekbar_color_filter_red.isEnabled = seekbar_color_filter_alpha.progress > 0 && enabled + seekbar_color_filter_green.isEnabled = seekbar_color_filter_alpha.progress > 0 && enabled + seekbar_color_filter_blue.isEnabled = seekbar_color_filter_alpha.progress > 0 && enabled seekbar_color_filter_alpha.isEnabled = enabled } /** * Set enabled status of seekBars belonging to custom brightness * @param enabled value which determines if seekBar gets enabled - * @param view view of the dialog */ - private fun setCustomBrightnessSeekBar(enabled: Boolean, view: View) = with(view) { + private fun setCustomBrightnessSeekBar(enabled: Boolean) { brightness_seekbar.isEnabled = enabled } /** * Set the text value's of color filter * @param color integer containing color information - * @param view view of the dialog */ - fun setValues(color: Int, view: View): Array { + private fun setValues(color: Int): Array { val alpha = getAlphaFromColor(color) val red = getRedFromColor(color) val green = getGreenFromColor(color) @@ -197,18 +158,17 @@ class ReaderColorFilterSheet(private val activity: ReaderActivity) : BottomSheet /** * Manages the custom brightness value subscription * @param enabled determines if the subscription get (un)subscribed - * @param view view of the dialog */ - private fun setCustomBrightness(enabled: Boolean, view: View) { + private fun setCustomBrightness(enabled: Boolean) { if (enabled) { preferences.customBrightnessValue().asFlow() .sample(100) - .onEach { setCustomBrightnessValue(it, view) } + .onEach { setCustomBrightnessValue(it) } .launchIn(activity.scope) } else { - setCustomBrightnessValue(0, view, true) + setCustomBrightnessValue(0, true) } - setCustomBrightnessSeekBar(enabled, view) + setCustomBrightnessSeekBar(enabled) } /** @@ -217,16 +177,8 @@ class ReaderColorFilterSheet(private val activity: ReaderActivity) : BottomSheet * From 1 to 100 it sets that value as brightness. * 0 sets system brightness and hides the overlay. */ - private fun setCustomBrightnessValue(value: Int, view: View, isDisabled: Boolean = false) = with(view) { + private fun setCustomBrightnessValue(value: Int, isDisabled: Boolean = false) { // Set black overlay visibility. - if (value < 0) { - brightness_overlay.visible() - val alpha = (abs(value) * 2.56).toInt() - brightness_overlay.setBackgroundColor(Color.argb(alpha, 0, 0, 0)) - } else { - brightness_overlay.gone() - } - if (!isDisabled) { txt_brightness_seekbar_value.text = value.toString() } @@ -237,27 +189,22 @@ class ReaderColorFilterSheet(private val activity: ReaderActivity) : BottomSheet * @param enabled determines if the subscription get (un)subscribed * @param view view of the dialog */ - private fun setColorFilter(enabled: Boolean, view: View) { + private fun setColorFilter(enabled: Boolean) { if (enabled) { preferences.colorFilterValue().asFlow() .sample(100) - .onEach { setColorFilterValue(it, view) } + .onEach { setColorFilterValue(it) } .launchIn(activity.scope) - } else { - color_overlay.gone() } - setColorFilterSeekBar(enabled, view) + setColorFilterSeekBar(enabled) } /** * Sets the color filter overlay of the screen. Determined by HEX of integer * @param color hex of color. - * @param view view of the dialog */ - private fun setColorFilterValue(@ColorInt color: Int, view: View) = with(view) { - color_overlay.visible() - color_overlay.setFilterColor(color, preferences.colorFilterMode().get()) - setValues(color, view) + private fun setColorFilterValue(@ColorInt color: Int) { + setValues(color) } /** @@ -290,15 +237,6 @@ class ReaderColorFilterSheet(private val activity: ReaderActivity) : BottomSheet return color shr 16 and 0xFF } - /** - * Returns the green value from the Color Hex - * @param color color hex as int - * @return green of color - */ - fun getGreenFromColor(color: Int): Int { - return color shr 8 and 0xFF - } - /** * Returns the blue value from the Color Hex * @param color color hex as int @@ -322,3 +260,12 @@ class ReaderColorFilterSheet(private val activity: ReaderActivity) : BottomSheet const val BLUE_MASK: Long = 0x000000FF } } + +/** + * Returns the green value from the Color Hex + * @param color color hex as int + * @return green of color + */ +fun ReaderFilterView.getGreenFromColor(color: Int): Int { + return color shr 8 and 0xFF +} \ No newline at end of file diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/reader/settings/ReaderGeneralView.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/reader/settings/ReaderGeneralView.kt new file mode 100644 index 0000000000..3db90555e4 --- /dev/null +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/reader/settings/ReaderGeneralView.kt @@ -0,0 +1,46 @@ +package eu.kanade.tachiyomi.ui.reader.settings + +import android.content.Context +import android.util.AttributeSet +import eu.kanade.tachiyomi.ui.reader.ReaderActivity +import eu.kanade.tachiyomi.util.bindToPreference +import eu.kanade.tachiyomi.util.view.RecyclerWindowInsetsListener +import eu.kanade.tachiyomi.widget.IgnoreFirstSpinnerListener +import kotlinx.android.synthetic.main.reader_general_layout.view.* + +class ReaderGeneralView @JvmOverloads constructor(context: Context, attrs: AttributeSet? = null) : + BaseReaderSettingsView(context, attrs) { + + lateinit var sheet: TabbedReaderSettingsSheet + override fun initGeneralPreferences() { + settings_scroll_view.setOnApplyWindowInsetsListener(RecyclerWindowInsetsListener) + viewer_series.onItemSelectedListener = { position -> + activity.presenter.setMangaViewer(position) + + val mangaViewer = activity.presenter.getMangaViewer() + if (mangaViewer == ReaderActivity.WEBTOON || mangaViewer == ReaderActivity.VERTICAL_PLUS) { + initWebtoonPreferences() + } else { + initPagerPreferences() + } + } + viewer_series.setSelection((context as? ReaderActivity)?.presenter?.manga?.viewer ?: 0) + rotation_mode.bindToPreference(preferences.rotation(), 1) + background_color.bindToPreference(preferences.readerTheme(), 0) + show_page_number.bindToPreference(preferences.showPageNumber()) + fullscreen.bindToPreference(preferences.fullscreen()) + keepscreen.bindToPreference(preferences.keepScreenOn()) + always_show_chapter_transition.bindToPreference(preferences.alwaysShowChapterTransition()) + } + + /** + * Init the preferences for the webtoon reader. + */ + private fun initWebtoonPreferences() { + sheet.updateTabs(true) + } + + private fun initPagerPreferences() { + sheet.updateTabs(false) + } +} \ No newline at end of file diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/reader/settings/ReaderPagedView.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/reader/settings/ReaderPagedView.kt new file mode 100644 index 0000000000..df82b91950 --- /dev/null +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/reader/settings/ReaderPagedView.kt @@ -0,0 +1,49 @@ +package eu.kanade.tachiyomi.ui.reader.settings + +import android.content.Context +import android.util.AttributeSet +import eu.kanade.tachiyomi.R +import eu.kanade.tachiyomi.ui.reader.ReaderActivity +import eu.kanade.tachiyomi.util.bindToIntPreference +import eu.kanade.tachiyomi.util.bindToPreference +import eu.kanade.tachiyomi.util.view.RecyclerWindowInsetsListener +import eu.kanade.tachiyomi.util.view.visibleIf +import kotlinx.android.synthetic.main.reader_paged_layout.view.* +import kotlinx.android.synthetic.main.reader_paged_layout.view.crop_borders_webtoon +import kotlinx.android.synthetic.main.reader_paged_layout.view.settings_scroll_view +import kotlinx.android.synthetic.main.reader_paged_layout.view.webtoon_enable_zoom_out +import kotlinx.android.synthetic.main.reader_paged_layout.view.webtoon_side_padding + +class ReaderPagedView @JvmOverloads constructor(context: Context, attrs: AttributeSet? = null) : + BaseReaderSettingsView(context, attrs) { + + override fun initGeneralPreferences() { + scale_type.bindToPreference(preferences.imageScaleType(), 1) + zoom_start.bindToPreference(preferences.zoomStart(), 1) + crop_borders.bindToPreference(preferences.cropBorders()) + page_transitions.bindToPreference(preferences.pageTransitions()) + + settings_scroll_view.setOnApplyWindowInsetsListener(RecyclerWindowInsetsListener) + val mangaViewer = (context as ReaderActivity).presenter.getMangaViewer() + val isWebtoonView = mangaViewer == ReaderActivity.WEBTOON || mangaViewer == ReaderActivity.VERTICAL_PLUS + val hasMargins = mangaViewer == ReaderActivity.VERTICAL_PLUS + crop_borders_webtoon.bindToPreference(if (hasMargins) preferences.cropBorders() else preferences.cropBordersWebtoon()) + webtoon_side_padding.bindToIntPreference(preferences.webtoonSidePadding(), R.array.webtoon_side_padding_values) + webtoon_enable_zoom_out.bindToPreference(preferences.webtoonEnableZoomOut()) + + updatePagedGroup(!isWebtoonView) + } + + fun updatePrefs() { + val mangaViewer = activity.presenter.getMangaViewer() + val isWebtoonView = mangaViewer == ReaderActivity.WEBTOON || mangaViewer == ReaderActivity.VERTICAL_PLUS + val hasMargins = mangaViewer == ReaderActivity.VERTICAL_PLUS + crop_borders_webtoon.bindToPreference(if (hasMargins) preferences.cropBorders() else preferences.cropBordersWebtoon()) + updatePagedGroup(!isWebtoonView) + } + + fun updatePagedGroup(show: Boolean) { + listOf(scale_type, zoom_start, crop_borders, page_transitions).forEach { it.visibleIf(show) } + listOf(crop_borders_webtoon, webtoon_side_padding, webtoon_enable_zoom_out).forEach { it.visibleIf(!show) } + } +} \ No newline at end of file diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/reader/settings/ReaderPreferenceView.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/reader/settings/ReaderPreferenceView.kt new file mode 100644 index 0000000000..de7b413100 --- /dev/null +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/reader/settings/ReaderPreferenceView.kt @@ -0,0 +1,134 @@ +package eu.kanade.tachiyomi.ui.reader.settings + +import android.content.Context +import android.util.AttributeSet +import android.view.Gravity +import android.view.MenuItem +import android.widget.FrameLayout +import androidx.annotation.ArrayRes +import androidx.appcompat.widget.PopupMenu +import androidx.core.view.get +import com.tfcporciuncula.flow.Preference +import eu.kanade.tachiyomi.R +import kotlinx.android.synthetic.main.reader_preference.view.* + + +class ReaderPreferenceView @JvmOverloads constructor(context: Context, attrs: AttributeSet?) : + FrameLayout(context, attrs) { + + + private var entries = emptyList() + private var selectedPosition = 0 + private var pref: Preference? = null + private var prefOffset = 0 + var onItemSelectedListener: ((Int) -> Unit)? = null + set(value) { + field = value + if (value != null) { + val popup = makeSettingsPopup() + setOnTouchListener(popup.dragToOpenListener) + setOnClickListener { + popup.show() + } + } + } + + init { + inflate(context, R.layout.reader_preference, this) + val a = context.obtainStyledAttributes(attrs, R.styleable.ReaderPreferenceView, 0, 0) + + val str = a.getString(R.styleable.ReaderPreferenceView_title) ?: "" + title_view.text = str + + val entries = (a.getTextArray(R.styleable.ReaderPreferenceView_android_entries) ?: emptyArray()).map { it.toString() } + this.entries = entries + + detail_view.text = entries.firstOrNull().orEmpty() + + a.recycle() + } + + fun setSelection(selection: Int) { + selectedPosition = selection + detail_view.text = entries.getOrNull(selection).orEmpty() + } + + fun bindToPreference(pref: Preference, offset: Int = 0, block: ((Int) -> Unit)? = null) { + setSelection(pref.get() - offset) + this.pref = pref + prefOffset = offset + val popup = makeSettingsPopup(pref, prefOffset, block) + setOnTouchListener(popup.dragToOpenListener) + setOnClickListener { + popup.show() + } + } + + fun bindToIntPreference(pref: Preference, @ArrayRes intValuesResource: Int, block: ((Int) -> Unit)? = null) { + setSelection(pref.get()) + this.pref = pref + prefOffset = 0 + val intValues = resources.getStringArray(intValuesResource).map { it.toIntOrNull() } + val popup = makeSettingsPopup(pref, intValues, block) + setOnTouchListener(popup.dragToOpenListener) + setOnClickListener { + popup.show() + } + } + + private fun makeSettingsPopup(preference: Preference, intValues: List, block: ((Int) -> Unit)? = null): PopupMenu { + val popup = popup() + // Set a listener so we are notified if a menu item is clicked + popup.setOnMenuItemClickListener { menuItem -> + val pos = popup.menuClicked(menuItem) + preference.set(intValues[pos] ?: 0) + block?.invoke(pos) + true + } + return popup + } + + private fun makeSettingsPopup(preference: Preference, offset: Int = 0, block: ((Int) -> Unit)? = null): PopupMenu { + val popup = popup() + // Set a listener so we are notified if a menu item is clicked + popup.setOnMenuItemClickListener { menuItem -> + val pos = popup.menuClicked(menuItem) + preference.set(pos + offset) + block?.invoke(pos) + true + } + return popup + } + + private fun makeSettingsPopup(): PopupMenu { + val popup = popup() + + // Set a listener so we are notified if a menu item is clicked + popup.setOnMenuItemClickListener { menuItem -> + val pos = popup.menuClicked(menuItem) + onItemSelectedListener?.invoke(pos) + true + } + return popup + } + + private fun PopupMenu.menuClicked(menuItem: MenuItem): Int { + val pos = menuItem.itemId + menu[selectedPosition].isCheckable = false + menu[selectedPosition].isChecked = false + setSelection(pos) + menu[pos].isCheckable = true + menu[pos].isChecked = true + return pos + } + + private fun popup(): PopupMenu { + val popup = PopupMenu(context, this, Gravity.END) + entries.forEachIndexed { index, entry -> + popup.menu.add(0, index, 0, entry) + } + popup.menu[selectedPosition].isCheckable = true + popup.menu[selectedPosition].isChecked = true + return popup + } +} \ No newline at end of file diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/reader/settings/TabbedReaderSettingsSheet.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/reader/settings/TabbedReaderSettingsSheet.kt new file mode 100644 index 0000000000..6405775075 --- /dev/null +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/reader/settings/TabbedReaderSettingsSheet.kt @@ -0,0 +1,99 @@ +package eu.kanade.tachiyomi.ui.reader.settings + +import android.view.View +import com.google.android.material.tabs.TabLayout +import eu.kanade.tachiyomi.R +import eu.kanade.tachiyomi.ui.library.display.LibraryBadgesView +import eu.kanade.tachiyomi.ui.reader.ReaderActivity +import eu.kanade.tachiyomi.util.view.gone +import eu.kanade.tachiyomi.util.view.visInvisIf +import eu.kanade.tachiyomi.util.view.visible +import eu.kanade.tachiyomi.util.view.visibleIf +import eu.kanade.tachiyomi.widget.TabbedBottomSheetDialog +import kotlinx.android.synthetic.main.reader_activity.* +import kotlinx.android.synthetic.main.reader_color_filter.view.* +import kotlinx.android.synthetic.main.recycler_with_scroller.view.* +import kotlinx.android.synthetic.main.tabbed_bottom_sheet.* + +class TabbedReaderSettingsSheet(val readerActivity: ReaderActivity): TabbedBottomSheetDialog( + readerActivity +) { + private val generalView: ReaderGeneralView = View.inflate( + readerActivity, + R.layout.reader_general_layout, + null + ) as ReaderGeneralView + private val pagedView: ReaderPagedView = View.inflate( + readerActivity, + R.layout.reader_paged_layout, + null + ) as ReaderPagedView + private val filterView: ReaderFilterView = View.inflate( + readerActivity, + R.layout.reader_color_filter, + null + ) as ReaderFilterView + + var showWebview: Boolean = { + val mangaViewer = readerActivity.presenter.getMangaViewer() + mangaViewer == ReaderActivity.WEBTOON || mangaViewer == ReaderActivity.VERTICAL_PLUS + }() + + override var offset = 0 + + override fun getTabViews(): List = listOf( + generalView, + pagedView, + filterView + ) + + override fun getTabTitles(): List = listOf( + R.string.general, + if (showWebview) R.string.webtoon else R.string.paged, + R.string.filter + ) + + init { + generalView.activity = readerActivity + pagedView.activity = readerActivity + filterView.activity = readerActivity + generalView.sheet = this + + menu.gone() + val attrs = window?.attributes + val ogDim = attrs?.dimAmount ?: 0.25f + pager.adapter?.notifyDataSetChanged() + tabs.addOnTabSelectedListener(object : TabLayout.OnTabSelectedListener { + override fun onTabSelected(tab: TabLayout.Tab?) { + window?.setDimAmount(if (tab?.position == 2) 0f else ogDim) + val view = getTabViews()[tab?.position ?: 0] + view.settings_scroll_view?.isNestedScrollingEnabled = true + view.settings_scroll_view?.requestLayout() + readerActivity.appbar.visInvisIf(tab?.position != 2) + } + + override fun onTabUnselected(tab: TabLayout.Tab?) { + val view = getTabViews()[tab?.position ?: 0] + view.settings_scroll_view?.isNestedScrollingEnabled = false + view.settings_scroll_view?.requestLayout() + } + + override fun onTabReselected(tab: TabLayout.Tab?) { + val view = getTabViews()[tab?.position ?: 0] + view.settings_scroll_view?.isNestedScrollingEnabled = true + view.settings_scroll_view?.requestLayout() + } + }) + } + + override fun dismiss() { + super.dismiss() + readerActivity.appbar.visible() + } + + fun updateTabs(isWebtoon: Boolean) { + showWebview = isWebtoon + pager.adapter?.notifyDataSetChanged() + pagedView.updatePrefs() + } +} diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/reader/viewer/ViewerConfig.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/reader/viewer/ViewerConfig.kt index fab2958314..1aeef22345 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/reader/viewer/ViewerConfig.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/reader/viewer/ViewerConfig.kt @@ -18,7 +18,6 @@ abstract class ViewerConfig(preferences: PreferencesHelper) { var imagePropertyChangedListener: (() -> Unit)? = null var tappingEnabled = true - var longTapEnabled = true var doubleTapAnimDuration = 500 var volumeKeysEnabled = false var volumeKeysInverted = false @@ -28,9 +27,6 @@ abstract class ViewerConfig(preferences: PreferencesHelper) { preferences.readWithTapping() .register({ tappingEnabled = it }) - preferences.readWithLongTap() - .register({ longTapEnabled = it }) - preferences.doubleTapAnimSpeed() .register({ doubleTapAnimDuration = it }) diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/reader/viewer/pager/PagerViewer.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/reader/viewer/pager/PagerViewer.kt index 545e7e04cc..36e48b0b21 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/reader/viewer/pager/PagerViewer.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/reader/viewer/pager/PagerViewer.kt @@ -89,16 +89,6 @@ abstract class PagerViewer(val activity: ReaderActivity) : BaseViewer { else -> activity.toggleMenu() } } - pager.longTapListener = f@{ - if (activity.menuVisible || config.longTapEnabled) { - val item = adapter.items.getOrNull(pager.currentItem) - if (item is ReaderPage) { - activity.onPageLongTap(item) - return@f true - } - } - false - } config.imagePropertyChangedListener = { refreshAdapter() diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/reader/viewer/webtoon/WebtoonViewer.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/reader/viewer/webtoon/WebtoonViewer.kt index 5ad24913cb..fc380cbab9 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/reader/viewer/webtoon/WebtoonViewer.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/reader/viewer/webtoon/WebtoonViewer.kt @@ -106,20 +106,6 @@ class WebtoonViewer(val activity: ReaderActivity, val hasMargins: Boolean = fals else -> activity.toggleMenu() } } - recycler.longTapListener = f@{ event -> - if (activity.menuVisible || config.longTapEnabled) { - val child = recycler.findChildViewUnder(event.x, event.y) - if (child != null) { - val position = recycler.getChildAdapterPosition(child) - val item = adapter.items.getOrNull(position) - if (item is ReaderPage) { - activity.onPageLongTap(item) - return@f true - } - } - } - false - } config.imagePropertyChangedListener = { refreshAdapter() 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 d6a97b88b7..46a4eee4ef 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 @@ -188,11 +188,6 @@ class SettingsReaderController : SettingsController() { titleRes = R.string.tapping defaultValue = true } - switchPreference { - key = Keys.readWithLongTap - titleRes = R.string.long_tap_dialog - defaultValue = true - } switchPreference { key = Keys.readWithVolumeKeys titleRes = R.string.volume_keys diff --git a/app/src/main/java/eu/kanade/tachiyomi/util/PreferenceExtensions.kt b/app/src/main/java/eu/kanade/tachiyomi/util/PreferenceExtensions.kt index 0148d0b1cd..515c55ae7f 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/util/PreferenceExtensions.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/util/PreferenceExtensions.kt @@ -1,6 +1,15 @@ package eu.kanade.tachiyomi.util import android.content.SharedPreferences +import android.widget.CompoundButton +import android.widget.RadioButton +import android.widget.RadioGroup +import android.widget.Spinner +import androidx.annotation.ArrayRes +import androidx.appcompat.widget.AppCompatSpinner +import com.f2prateek.rx.preferences.Preference +import eu.kanade.tachiyomi.data.preference.getOrDefault +import eu.kanade.tachiyomi.widget.IgnoreFirstSpinnerListener import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.channels.awaitClose @@ -40,3 +49,68 @@ inline fun SharedPreferences.getItem(key: String, default: T): T { else -> throw IllegalArgumentException("Generic type not handled: ${T::class.java.name}") } } + + +/** + * Binds a checkbox or switch view with a boolean preference. + */ +fun CompoundButton.bindToPreference(pref: Preference, block: (() -> Unit)? = null) { + isChecked = pref.getOrDefault() + setOnCheckedChangeListener { _, isChecked -> + pref.set(isChecked) + block?.invoke() + } +} + +/** + * Binds a checkbox or switch view with a boolean preference. + */ +fun CompoundButton.bindToPreference( + pref: com.tfcporciuncula.flow + .Preference, + block: ((Boolean) -> Unit)? = null +) { + isChecked = pref.get() + setOnCheckedChangeListener { _, isChecked -> + pref.set(isChecked) + block?.invoke(isChecked) + } +} + +/** + * Binds a radio group with a int preference. + */ +fun RadioGroup.bindToPreference(pref: Preference, block: (() -> Unit)? = null) { + (getChildAt(pref.getOrDefault()) as RadioButton).isChecked = true + setOnCheckedChangeListener { _, checkedId -> + val index = indexOfChild(findViewById(checkedId)) + pref.set(index) + block?.invoke() + } +} + +/** + * Binds a spinner to an int preference with an optional offset for the value. + */ +fun Spinner.bindToPreference( + pref: com.tfcporciuncula.flow.Preference, + offset: Int = 0 +) { + onItemSelectedListener = IgnoreFirstSpinnerListener { position -> + pref.set(position + offset) + } + setSelection(pref.get() - offset, false) +} + +/** + * Binds a spinner to an int preference. The position of the spinner item must + * correlate with the [intValues] resource item (in arrays.xml), which is a + * of int values that will be parsed here and applied to the preference. + */ +fun Spinner.bindToIntPreference(pref: com.tfcporciuncula.flow.Preference, @ArrayRes intValuesResource: Int) { + val intValues = resources.getStringArray(intValuesResource).map { it.toIntOrNull() } + onItemSelectedListener = IgnoreFirstSpinnerListener { position -> + pref.set(intValues[position] ?: 0) + } + setSelection(intValues.indexOf(pref.get()), false) +} \ No newline at end of file diff --git a/app/src/main/java/eu/kanade/tachiyomi/widget/TabbedBottomSheet.kt b/app/src/main/java/eu/kanade/tachiyomi/widget/TabbedBottomSheet.kt index 3534055cb5..f71087ca51 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/widget/TabbedBottomSheet.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/widget/TabbedBottomSheet.kt @@ -1,27 +1,32 @@ package eu.kanade.tachiyomi.widget +import android.app.Activity import android.content.Context import android.util.AttributeSet +import android.view.Gravity import android.view.View import android.view.ViewGroup +import androidx.coordinatorlayout.widget.CoordinatorLayout import androidx.viewpager.widget.ViewPager import com.google.android.material.bottomsheet.BottomSheetBehavior import com.google.android.material.bottomsheet.BottomSheetDialog import eu.kanade.tachiyomi.R import eu.kanade.tachiyomi.ui.base.controller.BaseController +import eu.kanade.tachiyomi.util.system.dpToPx import eu.kanade.tachiyomi.util.view.expand import eu.kanade.tachiyomi.util.view.setEdgeToEdge +import eu.kanade.tachiyomi.util.view.updateLayoutParams +import kotlinx.android.synthetic.main.library_list_controller.* import kotlinx.android.synthetic.main.tabbed_bottom_sheet.* -abstract class TabbedBottomSheetDialog(private val controller: BaseController) : +abstract class TabbedBottomSheetDialog(private val activity: Activity) : BottomSheetDialog - (controller.activity!!, R.style.BottomSheetDialogTheme) { + (activity, R.style.BottomSheetDialogTheme) { private var sheetBehavior: BottomSheetBehavior<*> - val activity = controller.activity!! - + open var offset = -1 init { // Use activity theme for this layout val view = activity.layoutInflater.inflate(R.layout.tabbed_bottom_sheet, null) @@ -29,7 +34,9 @@ abstract class TabbedBottomSheetDialog(private val controller: BaseController) : setContentView(view) sheetBehavior = BottomSheetBehavior.from(view.parent as ViewGroup) setEdgeToEdge(activity, view) - val height = activity.window.decorView.rootWindowInsets.systemWindowInsetBottom + + val height = activity.window.decorView.rootWindowInsets.systemWindowInsetTop + pager.maxHeight = activity.window.decorView.height - height - 125.dpToPx val adapter = TabbedSheetAdapter() pager.offscreenPageLimit = 2 @@ -41,6 +48,7 @@ abstract class TabbedBottomSheetDialog(private val controller: BaseController) : super.onStart() sheetBehavior.skipCollapsed = true sheetBehavior.expand() + val height = activity.window.decorView.rootWindowInsets.systemWindowInsetTop } abstract fun getTabViews(): List @@ -64,6 +72,13 @@ abstract class TabbedBottomSheetDialog(private val controller: BaseController) : } class MeasuredViewPager @JvmOverloads constructor(context: Context, attrs: AttributeSet? = null): ViewPager(context, attrs) { + + var maxHeight = 0 + set(value) { + field = value + requestLayout() + } + override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) { var heightMeasureSpec = heightMeasureSpec super.onMeasure(widthMeasureSpec, heightMeasureSpec) @@ -84,6 +99,9 @@ class MeasuredViewPager @JvmOverloads constructor(context: Context, attrs: Attri if (height != 0) { heightMeasureSpec = MeasureSpec.makeMeasureSpec(height, MeasureSpec.EXACTLY) + (rootWindowInsets?.systemWindowInsetBottom ?: 0) } + if (maxHeight < height) { + heightMeasureSpec = MeasureSpec.makeMeasureSpec(maxHeight, MeasureSpec.AT_MOST) + (rootWindowInsets?.systemWindowInsetBottom ?: 0) + } super.onMeasure(widthMeasureSpec, heightMeasureSpec) } } \ No newline at end of file diff --git a/app/src/main/res/drawable/filter_mock.webp b/app/src/main/res/drawable/filter_mock.webp deleted file mode 100644 index c65b390cb6..0000000000 Binary files a/app/src/main/res/drawable/filter_mock.webp and /dev/null differ diff --git a/app/src/main/res/drawable/ic_book_24dp.xml b/app/src/main/res/drawable/ic_book_24dp.xml index 811d5ac4bd..b98b4c1b96 100644 --- a/app/src/main/res/drawable/ic_book_24dp.xml +++ b/app/src/main/res/drawable/ic_book_24dp.xml @@ -2,7 +2,8 @@ android:width="24dp" android:height="24dp" android:viewportWidth="24.0" - android:viewportHeight="24.0"> + android:viewportHeight="24.0" + android:tint="?attr/actionBarTintColor"> diff --git a/app/src/main/res/layout-land/reader_color_filter_sheet.xml b/app/src/main/res/layout-land/reader_color_filter_sheet.xml deleted file mode 100644 index 6df89dc7c6..0000000000 --- a/app/src/main/res/layout-land/reader_color_filter_sheet.xml +++ /dev/null @@ -1,49 +0,0 @@ - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/app/src/main/res/layout/reader_color_filter.xml b/app/src/main/res/layout/reader_color_filter.xml index 9aa2015202..8356768432 100644 --- a/app/src/main/res/layout/reader_color_filter.xml +++ b/app/src/main/res/layout/reader_color_filter.xml @@ -1,236 +1,245 @@ - + android:background="@drawable/bottom_sheet_rounded_background" + android:forceDarkAllowed="false"> - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + android:clipToPadding="false" + android:layout_height="wrap_content"> - + - + - + - + - + - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/reader_color_filter_sheet.xml b/app/src/main/res/layout/reader_color_filter_sheet.xml deleted file mode 100644 index f6c40f06d4..0000000000 --- a/app/src/main/res/layout/reader_color_filter_sheet.xml +++ /dev/null @@ -1,41 +0,0 @@ - - - - - - - - - - - - - - - - - - - diff --git a/app/src/main/res/layout/reader_general_layout.xml b/app/src/main/res/layout/reader_general_layout.xml new file mode 100644 index 0000000000..1e881e505e --- /dev/null +++ b/app/src/main/res/layout/reader_general_layout.xml @@ -0,0 +1,86 @@ + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/reader_paged_layout.xml b/app/src/main/res/layout/reader_paged_layout.xml new file mode 100644 index 0000000000..3ff7e29e98 --- /dev/null +++ b/app/src/main/res/layout/reader_paged_layout.xml @@ -0,0 +1,104 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/reader_preference.xml b/app/src/main/res/layout/reader_preference.xml new file mode 100644 index 0000000000..642cede686 --- /dev/null +++ b/app/src/main/res/layout/reader_preference.xml @@ -0,0 +1,61 @@ + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/reader_settings_sheet.xml b/app/src/main/res/layout/reader_settings_sheet.xml deleted file mode 100644 index b48c8a27af..0000000000 --- a/app/src/main/res/layout/reader_settings_sheet.xml +++ /dev/null @@ -1,328 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/app/src/main/res/menu/reader.xml b/app/src/main/res/menu/reader.xml index b011162b48..5763d837c2 100644 --- a/app/src/main/res/menu/reader.xml +++ b/app/src/main/res/menu/reader.xml @@ -1,18 +1,42 @@ + xmlns:app="http://schemas.android.com/apk/res-auto"> + + + + + + + + + + android:title="@string/reader_settings" + app:showAsAction="never" /> diff --git a/app/src/main/res/values/attrs.xml b/app/src/main/res/values/attrs.xml index 8b7fbbe1e2..6bd1e44d86 100644 --- a/app/src/main/res/values/attrs.xml +++ b/app/src/main/res/values/attrs.xml @@ -15,4 +15,10 @@ + + + + + + diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 08970908f1..e701e10847 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -278,6 +278,11 @@ Custom filter Set as cover + Set page as cover + Share page + Save page + %1$s details + Reader settings Set as default for all Cover updated Page %1$d