diff --git a/app/src/main/java/eu/kanade/tachiyomi/Migrations.kt b/app/src/main/java/eu/kanade/tachiyomi/Migrations.kt index b4a97664e6..e4c09c7e04 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/Migrations.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/Migrations.kt @@ -111,6 +111,10 @@ object Migrations { } } } + if (oldVersion < 73) { + // Reset rotation to Free after replacing Lock + preferences.rotation().set(1) + } return true } return false 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 bdd232ef4a..9545a03c6f 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 @@ -4,7 +4,6 @@ import android.annotation.SuppressLint import android.content.ClipData import android.content.Context import android.content.Intent -import android.content.pm.ActivityInfo import android.content.res.ColorStateList import android.content.res.Configuration import android.graphics.Bitmap @@ -56,6 +55,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.OrientationType import eu.kanade.tachiyomi.ui.reader.settings.ReadingModeType import eu.kanade.tachiyomi.ui.reader.settings.TabbedReaderSettingsSheet import eu.kanade.tachiyomi.ui.reader.viewer.BaseViewer @@ -93,6 +93,7 @@ import eu.kanade.tachiyomi.util.view.hide import eu.kanade.tachiyomi.util.view.invisible import eu.kanade.tachiyomi.util.view.isCollapsed import eu.kanade.tachiyomi.util.view.isExpanded +import eu.kanade.tachiyomi.util.view.popupMenu import eu.kanade.tachiyomi.util.view.snack import eu.kanade.tachiyomi.util.view.updateLayoutParams import eu.kanade.tachiyomi.util.view.updatePaddingRelative @@ -225,6 +226,7 @@ class ReaderActivity : ViewChapters("vc", R.string.view_chapters), WebView("wb", R.string.open_in_webview), ReadingMode("rm", R.string.reading_mode), + Rotation("rot", R.string.rotation), CropBordersPaged("cbp", R.string.crop_borders_paged), CropBordersWebtoon("cbw", R.string.crop_borders_webtoon), PageLayout("pl", R.string.page_layout), @@ -405,6 +407,11 @@ class ReaderActivity : ) } + private fun updateRotationShortcut(preference: Int) { + val orientation = OrientationType.fromPreference(preference) + binding.chaptersSheet.rotationSheetButton.setImageResource(orientation.iconRes) + } + private fun updateCropBordersShortcut() { val isPagerType = viewer is PagerViewer || (viewer as? WebtoonViewer)?.hasMargins == true val enabled = if (isPagerType) { @@ -434,22 +441,25 @@ class ReaderActivity : } private fun updateBottomShortcuts() { + val enabledButtons = preferences.readerBottomButtons().get() with(binding.chaptersSheet) { readingMode.isVisible = presenter?.manga?.isLongStrip() != true && - BottomButton.ReadingMode.value in preferences.readerBottomButtons().get() + BottomButton.ReadingMode.value in enabledButtons + rotationSheetButton.isVisible = + BottomButton.Rotation.value in enabledButtons doublePage.isVisible = viewer is PagerViewer && - BottomButton.PageLayout.value in preferences.readerBottomButtons().get() + BottomButton.PageLayout.value in enabledButtons cropBordersSheetButton.isVisible = if (viewer is PagerViewer) { - BottomButton.CropBordersPaged.value in preferences.readerBottomButtons().get() + BottomButton.CropBordersPaged.value in enabledButtons } else { - BottomButton.CropBordersWebtoon.value in preferences.readerBottomButtons().get() + BottomButton.CropBordersWebtoon.value in enabledButtons } webviewButton.isVisible = - BottomButton.WebView.value in preferences.readerBottomButtons().get() + BottomButton.WebView.value in enabledButtons chaptersButton.isVisible = - BottomButton.ViewChapters.value in preferences.readerBottomButtons().get() + BottomButton.ViewChapters.value in enabledButtons shiftPageButton.isVisible = ((viewer as? PagerViewer)?.config?.doublePages ?: false) && canShowSplitAtBottom() binding.toolbar.menu.findItem(R.id.action_shift_double_page)?.isVisible = @@ -613,6 +623,22 @@ class ReaderActivity : pref.toggle() } + with(rotationSheetButton) { + compatToolTipText = getString(R.string.rotation) + + setOnClickListener { + popupMenu( + items = OrientationType.values().map { it.prefValue to it.stringRes }, + selectedItemId = preferences.rotation().get(), + ) { + val newOrientation = OrientationType.fromPreference(itemId) + + preferences.rotation().set(newOrientation.prefValue) + setOrientation(newOrientation.flag) + } + } + } + webviewButton.setOnClickListener { openMangaInBrowser() } @@ -667,6 +693,7 @@ class ReaderActivity : .onEach { updateCropBordersShortcut() } .launchIn(scope) } + preferences.rotation().asImmediateFlowIn(scope) { updateRotationShortcut(it) } binding.chaptersSheet.shiftPageButton.setOnClickListener { shiftDoublePages() @@ -1412,6 +1439,16 @@ class ReaderActivity : startActivity(intent) } + /** + * Forces the user preferred [orientation] on the activity. + */ + private fun setOrientation(orientation: Int) { + val newOrientation = OrientationType.fromPreference(orientation) + if (newOrientation.flag != requestedOrientation) { + requestedOrientation = newOrientation.flag + } + } + /** * Class that handles the user preferences of the reader. */ @@ -1461,33 +1498,6 @@ class ReaderActivity : } } - /** - * Forces the user preferred [orientation] on the activity. - */ - private fun setOrientation(orientation: Int) { - val newOrientation = when (orientation) { - // Lock in current orientation - 2 -> { - val currentOrientation = resources.configuration.orientation - if (currentOrientation == Configuration.ORIENTATION_PORTRAIT) { - ActivityInfo.SCREEN_ORIENTATION_SENSOR_PORTRAIT - } else { - ActivityInfo.SCREEN_ORIENTATION_SENSOR_LANDSCAPE - } - } - // Lock in portrait - 3 -> ActivityInfo.SCREEN_ORIENTATION_SENSOR_PORTRAIT - // Lock in landscape - 4 -> ActivityInfo.SCREEN_ORIENTATION_SENSOR_LANDSCAPE - // Rotation free - else -> ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED - } - - if (newOrientation != requestedOrientation) { - requestedOrientation = newOrientation - } - } - /** * Sets the visibility of the bottom page indicator according to [visible]. */ diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/reader/settings/OrientationType.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/reader/settings/OrientationType.kt new file mode 100644 index 0000000000..86f94e7024 --- /dev/null +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/reader/settings/OrientationType.kt @@ -0,0 +1,20 @@ +package eu.kanade.tachiyomi.ui.reader.settings + +import android.content.pm.ActivityInfo +import androidx.annotation.DrawableRes +import androidx.annotation.StringRes +import eu.kanade.tachiyomi.R + +enum class OrientationType(val prefValue: Int, val flag: Int, @StringRes val stringRes: Int, @DrawableRes val iconRes: Int) { + FREE(1, ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED, R.string.free, R.drawable.ic_screen_rotation_24dp), + PORTRAIT(2, ActivityInfo.SCREEN_ORIENTATION_SENSOR_PORTRAIT, R.string.portrait, R.drawable.ic_stay_current_portrait_24dp), + LANDSCAPE(3, ActivityInfo.SCREEN_ORIENTATION_SENSOR_LANDSCAPE, R.string.landscape, R.drawable.ic_stay_current_landscape_24dp), + LOCKED_PORTRAIT(4, ActivityInfo.SCREEN_ORIENTATION_PORTRAIT, R.string.locked_portrait, R.drawable.ic_screen_lock_portrait_24dp), + LOCKED_LANDSCAPE(5, ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE, R.string.locked_landscape, R.drawable.ic_screen_lock_landscape_24dp), + ; + + companion object { + fun fromPreference(preference: Int): OrientationType = + values().find { it.prefValue == preference } ?: FREE + } +} 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 76590c95b7..79f8eee5a3 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 @@ -6,6 +6,7 @@ import eu.kanade.tachiyomi.R import eu.kanade.tachiyomi.data.preference.asImmediateFlow import eu.kanade.tachiyomi.data.preference.asImmediateFlowIn import eu.kanade.tachiyomi.ui.reader.ReaderActivity +import eu.kanade.tachiyomi.ui.reader.settings.OrientationType import eu.kanade.tachiyomi.ui.reader.viewer.ViewerNavigation import eu.kanade.tachiyomi.ui.reader.viewer.pager.PageLayout import eu.kanade.tachiyomi.util.lang.addBetaTag @@ -93,13 +94,9 @@ class SettingsReaderController : SettingsController() { intListPreference(activity) { key = Keys.rotation titleRes = R.string.rotation - entriesRes = arrayOf( - R.string.free, - R.string.lock, - R.string.force_portrait, - R.string.force_landscape - ) - entryRange = 1..4 + val enumConstants = OrientationType::class.java.enumConstants + entriesRes = enumConstants?.map { it.stringRes }.orEmpty().toTypedArray() + entryRange = 1..(enumConstants?.size ?: 5) defaultValue = 1 } intListPreference(activity) { diff --git a/app/src/main/java/eu/kanade/tachiyomi/util/view/ViewExtensions.kt b/app/src/main/java/eu/kanade/tachiyomi/util/view/ViewExtensions.kt index 69d53c3875..0aa64debdd 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/util/view/ViewExtensions.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/util/view/ViewExtensions.kt @@ -8,6 +8,8 @@ import android.content.res.ColorStateList import android.graphics.Color import android.graphics.Point import android.os.Build +import android.view.Gravity +import android.view.MenuItem import android.view.View import android.view.ViewGroup import android.view.ViewTreeObserver @@ -19,8 +21,11 @@ import androidx.annotation.ColorRes import androidx.annotation.IdRes import androidx.annotation.Px import androidx.appcompat.view.menu.MenuBuilder +import androidx.appcompat.widget.PopupMenu +import androidx.core.content.ContextCompat import androidx.core.graphics.ColorUtils import androidx.core.view.ViewCompat +import androidx.core.view.forEach import androidx.recyclerview.widget.LinearLayoutManager import androidx.recyclerview.widget.LinearSmoothScroller import androidx.recyclerview.widget.RecyclerView @@ -33,6 +38,7 @@ import com.google.android.material.bottomsheet.BottomSheetDialog import com.google.android.material.button.MaterialButton import com.google.android.material.snackbar.Snackbar import eu.kanade.tachiyomi.R +import eu.kanade.tachiyomi.util.lang.tintText import eu.kanade.tachiyomi.util.system.ThemeUtil import eu.kanade.tachiyomi.util.system.contextCompatColor import eu.kanade.tachiyomi.util.system.getPrefTheme @@ -363,3 +369,44 @@ var View.compatToolTipText: CharSequence? set(value) { ViewCompat.setTooltipText(this, value) } + +@SuppressLint("RestrictedApi") +inline fun View.popupMenu( + items: List>, + selectedItemId: Int? = null, + noinline onMenuItemClick: MenuItem.() -> Unit +): PopupMenu { + val popup = PopupMenu(context, this, Gravity.NO_GRAVITY) + items.forEach { (id, stringRes) -> + popup.menu.add(0, id, 0, stringRes) + } + + if (selectedItemId != null) { + val blendedAccent = ColorUtils.blendARGB( + context.getResourceColor(android.R.attr.colorAccent), + context.getResourceColor(android.R.attr.textColorPrimary), + 0.5f + ) + (popup.menu as? MenuBuilder)?.setOptionalIconsVisible(true) + val emptyIcon = ContextCompat.getDrawable(context, R.drawable.ic_blank_24dp) + popup.menu.forEach { item -> + item.icon = when (item.itemId) { + selectedItemId -> ContextCompat.getDrawable(context, R.drawable.ic_check_24dp)?.mutate()?.apply { + setTint(blendedAccent) + } + else -> emptyIcon + } + if (item.itemId == selectedItemId) { + item.title = item.title?.tintText(blendedAccent) + } + } + } + + popup.setOnMenuItemClickListener { + it.onMenuItemClick() + true + } + + popup.show() + return popup +} diff --git a/app/src/main/res/drawable/ic_screen_lock_landscape_24dp.xml b/app/src/main/res/drawable/ic_screen_lock_landscape_24dp.xml new file mode 100644 index 0000000000..f78d9a5d43 --- /dev/null +++ b/app/src/main/res/drawable/ic_screen_lock_landscape_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_screen_lock_portrait_24dp.xml b/app/src/main/res/drawable/ic_screen_lock_portrait_24dp.xml new file mode 100644 index 0000000000..718ca70baf --- /dev/null +++ b/app/src/main/res/drawable/ic_screen_lock_portrait_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_screen_rotation_24dp.xml b/app/src/main/res/drawable/ic_screen_rotation_24dp.xml new file mode 100644 index 0000000000..3243d5a75d --- /dev/null +++ b/app/src/main/res/drawable/ic_screen_rotation_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_stay_current_landscape_24dp.xml b/app/src/main/res/drawable/ic_stay_current_landscape_24dp.xml new file mode 100644 index 0000000000..ac185cda4b --- /dev/null +++ b/app/src/main/res/drawable/ic_stay_current_landscape_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_stay_current_portrait_24dp.xml b/app/src/main/res/drawable/ic_stay_current_portrait_24dp.xml new file mode 100644 index 0000000000..23e9f4f263 --- /dev/null +++ b/app/src/main/res/drawable/ic_stay_current_portrait_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/layout/reader_chapters_sheet.xml b/app/src/main/res/layout/reader_chapters_sheet.xml index 052ffa22a0..37cf130214 100644 --- a/app/src/main/res/layout/reader_chapters_sheet.xml +++ b/app/src/main/res/layout/reader_chapters_sheet.xml @@ -25,109 +25,134 @@ android:alpha="0.25" android:contentDescription="@string/drag_handle" android:src="@drawable/draggable_pill" - app:tint="?actionBarTintColor" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintStart_toStartOf="parent" - app:layout_constraintTop_toTopOf="parent" /> + app:layout_constraintTop_toTopOf="parent" + app:tint="?actionBarTintColor" /> + app:srcCompat="@drawable/ic_format_list_numbered_24dp" + app:tint="?actionBarTintColor" /> + app:layout_constraintWidth_max="wrap" + app:srcCompat="@drawable/ic_open_in_webview_24dp" + app:tint="?actionBarTintColor" /> + app:layout_constraintWidth_max="wrap" + app:srcCompat="@drawable/ic_reader_default_24dp" + app:tint="?actionBarTintColor" /> + app:layout_constraintWidth_max="wrap" + app:srcCompat="@drawable/ic_screen_rotation_24dp" + app:tint="?actionBarTintColor" + tools:visibility="visible" /> + + + app:layout_constraintWidth_max="wrap" + app:srcCompat="@drawable/ic_book_open_variant_24dp" + app:tint="?actionBarTintColor" /> + app:srcCompat="@drawable/ic_tune_24dp" + app:tint="?actionBarTintColor" /> @string/free - @string/lock - @string/force_portrait - @string/force_landscape + @string/portrait + @string/landscape + @string/locked_portrait + @string/locked_landscape diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 9a679afa8a..4efbeeffc9 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -393,8 +393,10 @@ Single page Switch to double pages Switch to single page - Force portrait - Force landscape + Portrait + Landscape + Locked portrait + Locked landscape R G B