From 1229e9626ec51e80017c90c2065f652d1665823b Mon Sep 17 00:00:00 2001 From: Koitharu Date: Sun, 11 May 2025 16:26:17 +0300 Subject: [PATCH] Move bookmark button to bottom reader bar --- .../kotatsu/core/prefs/ReaderControl.kt | 2 +- .../kotatsu/reader/ui/ReaderActionsView.kt | 35 ++++++++++- .../kotatsu/reader/ui/ReaderActivity.kt | 13 +++- .../reader/ui/ReaderControlDelegate.kt | 4 +- .../kotatsu/reader/ui/ReaderMenuProvider.kt | 20 +----- .../kotatsu/reader/ui/ReaderViewModel.kt | 47 ++++++-------- .../reader/ui/config/ReaderConfigSheet.kt | 21 ++++++- .../main/res/layout/layout_reader_actions.xml | 50 ++++++++++----- .../main/res/layout/sheet_reader_config.xml | 63 +++++++++++-------- app/src/main/res/menu/opt_reader.xml | 8 +-- app/src/main/res/values/arrays.xml | 1 + app/src/main/res/values/styles.xml | 6 -- 12 files changed, 166 insertions(+), 104 deletions(-) diff --git a/app/src/main/kotlin/org/koitharu/kotatsu/core/prefs/ReaderControl.kt b/app/src/main/kotlin/org/koitharu/kotatsu/core/prefs/ReaderControl.kt index 53ba8c4b7..df977ff02 100644 --- a/app/src/main/kotlin/org/koitharu/kotatsu/core/prefs/ReaderControl.kt +++ b/app/src/main/kotlin/org/koitharu/kotatsu/core/prefs/ReaderControl.kt @@ -4,7 +4,7 @@ import java.util.EnumSet enum class ReaderControl { - PREV_CHAPTER, NEXT_CHAPTER, SLIDER, PAGES_SHEET, SCREEN_ROTATION, SAVE_PAGE, TIMER; + PREV_CHAPTER, NEXT_CHAPTER, SLIDER, PAGES_SHEET, SCREEN_ROTATION, SAVE_PAGE, TIMER, BOOKMARK; companion object { diff --git a/app/src/main/kotlin/org/koitharu/kotatsu/reader/ui/ReaderActionsView.kt b/app/src/main/kotlin/org/koitharu/kotatsu/reader/ui/ReaderActionsView.kt index d61ae72e4..53062c990 100644 --- a/app/src/main/kotlin/org/koitharu/kotatsu/reader/ui/ReaderActionsView.kt +++ b/app/src/main/kotlin/org/koitharu/kotatsu/reader/ui/ReaderActionsView.kt @@ -26,6 +26,7 @@ import org.koitharu.kotatsu.core.util.ext.hasVisibleChildren import org.koitharu.kotatsu.core.util.ext.isRtl import org.koitharu.kotatsu.core.util.ext.setValueRounded import org.koitharu.kotatsu.databinding.LayoutReaderActionsBinding +import org.koitharu.kotatsu.details.ui.pager.ChaptersPagesSheet import org.koitharu.kotatsu.details.ui.pager.ChaptersPagesSheet.Companion.TAB_PAGES import org.koitharu.kotatsu.reader.ui.ReaderControlDelegate.OnInteractionListener import javax.inject.Inject @@ -40,7 +41,7 @@ class ReaderActionsView @JvmOverloads constructor( View.OnClickListener, SharedPreferences.OnSharedPreferenceChangeListener, Slider.OnChangeListener, - Slider.OnSliderTouchListener { + Slider.OnSliderTouchListener, View.OnLongClickListener { @Inject lateinit var settings: AppSettings @@ -73,6 +74,14 @@ class ReaderActionsView @JvmOverloads constructor( binding.buttonPrev.isEnabled = value } + var isBookmarkAdded: Boolean = false + set(value) { + if (field != value) { + field = value + updateBookmarkButton() + } + } + var listener: OnInteractionListener? = null init { @@ -85,6 +94,7 @@ class ReaderActionsView @JvmOverloads constructor( binding.buttonScreenRotation.initAction() binding.buttonPagesThumbs.initAction() binding.buttonTimer.initAction() + binding.buttonBookmark.initAction() binding.slider.setLabelFormatter(PageLabelFormatter()) binding.slider.addOnChangeListener(this) binding.slider.addOnSliderTouchListener(this) @@ -112,13 +122,22 @@ class ReaderActionsView @JvmOverloads constructor( R.id.button_prev -> listener?.switchChapterBy(-1) R.id.button_next -> listener?.switchChapterBy(1) R.id.button_save -> listener?.onSavePageClick() - R.id.button_timer -> listener?.onScrollTimerClick() + R.id.button_timer -> listener?.onScrollTimerClick(isLongClick = false) R.id.button_pages_thumbs -> AppRouter.from(this)?.showChapterPagesSheet() R.id.button_screen_rotation -> listener?.toggleScreenOrientation() R.id.button_options -> listener?.openMenu() + R.id.button_bookmark -> listener?.onBookmarkClick() } } + override fun onLongClick(v: View): Boolean = when (v.id) { + R.id.button_bookmark -> AppRouter.from(this) + ?.showChapterPagesSheet(ChaptersPagesSheet.TAB_BOOKMARKS) + R.id.button_timer -> listener?.onScrollTimerClick(isLongClick = true) + R.id.button_options -> AppRouter.from(this)?.openReaderSettings() + else -> null + } != null + override fun onValueChange(slider: Slider, value: Float, fromUser: Boolean) { if (fromUser) { if (isSliderTracking) { @@ -175,6 +194,7 @@ class ReaderActionsView @JvmOverloads constructor( binding.buttonScreenRotation.isVisible = ReaderControl.SCREEN_ROTATION in controls binding.buttonSave.isVisible = ReaderControl.SAVE_PAGE in controls binding.buttonTimer.isVisible = ReaderControl.TIMER in controls + binding.buttonBookmark.isVisible = ReaderControl.BOOKMARK in controls binding.slider.isVisible = ReaderControl.SLIDER in controls adjustLayoutParams() } @@ -190,6 +210,16 @@ class ReaderActionsView @JvmOverloads constructor( ) } + private fun updateBookmarkButton() { + val button = binding.buttonBookmark + button.setIconResource( + if (isBookmarkAdded) R.drawable.ic_bookmark_added else R.drawable.ic_bookmark, + ) + button.setTitle( + if (isBookmarkAdded) R.string.bookmark_remove else R.string.bookmark_add, + ) + } + private fun adjustLayoutParams() { val isSliderVisible = binding.slider.isVisible repeat(childCount) { i -> @@ -222,6 +252,7 @@ class ReaderActionsView @JvmOverloads constructor( private fun Button.initAction() { setOnClickListener(this@ReaderActionsView) + setOnLongClickListener(this@ReaderActionsView) ViewCompat.setTooltipText(this, contentDescription) } diff --git a/app/src/main/kotlin/org/koitharu/kotatsu/reader/ui/ReaderActivity.kt b/app/src/main/kotlin/org/koitharu/kotatsu/reader/ui/ReaderActivity.kt index 371d21514..32dba40e5 100644 --- a/app/src/main/kotlin/org/koitharu/kotatsu/reader/ui/ReaderActivity.kt +++ b/app/src/main/kotlin/org/koitharu/kotatsu/reader/ui/ReaderActivity.kt @@ -114,6 +114,7 @@ class ReaderActivity : viewBinding.actionsView.listener = this idlingDetector.bindToLifecycle(this) screenOrientationHelper.applySettings() + viewModel.isBookmarkAdded.observe(this) { viewBinding.actionsView.isBookmarkAdded = it } scrollTimer.isActive.observe(this) { viewBinding.actionsView.setTimerActive(it) } viewBinding.timerControl.attach(scrollTimer, this) if (resources.getBoolean(R.bool.is_tablet)) { @@ -371,12 +372,20 @@ class ReaderActivity : return reader.isResumed && supportFragmentManager.fragments.lastOrNull() === reader } + override fun onBookmarkClick() { + viewModel.toggleBookmark() + } + override fun onSavePageClick() { viewModel.saveCurrentPage(pageSaveHelper) } - override fun onScrollTimerClick() { - viewBinding.timerControl.showOrHide() + override fun onScrollTimerClick(isLongClick: Boolean) { + if (isLongClick) { + scrollTimer.setActive(!scrollTimer.isActive.value) + } else { + viewBinding.timerControl.showOrHide() + } } override fun toggleScreenOrientation() { diff --git a/app/src/main/kotlin/org/koitharu/kotatsu/reader/ui/ReaderControlDelegate.kt b/app/src/main/kotlin/org/koitharu/kotatsu/reader/ui/ReaderControlDelegate.kt index 47da7c937..d2151dd4f 100644 --- a/app/src/main/kotlin/org/koitharu/kotatsu/reader/ui/ReaderControlDelegate.kt +++ b/app/src/main/kotlin/org/koitharu/kotatsu/reader/ui/ReaderControlDelegate.kt @@ -138,11 +138,13 @@ class ReaderControlDelegate( fun toggleUiVisibility() + fun onBookmarkClick() + fun openMenu() fun onSavePageClick() - fun onScrollTimerClick() + fun onScrollTimerClick(isLongClick: Boolean) fun toggleScreenOrientation() diff --git a/app/src/main/kotlin/org/koitharu/kotatsu/reader/ui/ReaderMenuProvider.kt b/app/src/main/kotlin/org/koitharu/kotatsu/reader/ui/ReaderMenuProvider.kt index 04a3b4522..fd93a2005 100644 --- a/app/src/main/kotlin/org/koitharu/kotatsu/reader/ui/ReaderMenuProvider.kt +++ b/app/src/main/kotlin/org/koitharu/kotatsu/reader/ui/ReaderMenuProvider.kt @@ -14,26 +14,10 @@ class ReaderMenuProvider( menuInflater.inflate(R.menu.opt_reader, menu) } - override fun onPrepareMenu(menu: Menu) { - menu.findItem(R.id.action_bookmark)?.let { bookmarkItem -> - val hasPages = viewModel.content.value.pages.isNotEmpty() - bookmarkItem.isEnabled = hasPages - if (hasPages) { - val hasBookmark = viewModel.isBookmarkAdded.value - bookmarkItem.setTitle(if (hasBookmark) R.string.bookmark_remove else R.string.bookmark_add) - bookmarkItem.setIcon(if (hasBookmark) R.drawable.ic_bookmark_added else R.drawable.ic_bookmark) - } - } - } - override fun onMenuItemSelected(menuItem: MenuItem): Boolean { return when (menuItem.itemId) { - R.id.action_bookmark -> { - if (viewModel.isBookmarkAdded.value) { - viewModel.removeBookmark() - } else { - viewModel.addBookmark() - } + R.id.action_info -> { + // TODO true } diff --git a/app/src/main/kotlin/org/koitharu/kotatsu/reader/ui/ReaderViewModel.kt b/app/src/main/kotlin/org/koitharu/kotatsu/reader/ui/ReaderViewModel.kt index 9226f364e..985b05a60 100644 --- a/app/src/main/kotlin/org/koitharu/kotatsu/reader/ui/ReaderViewModel.kt +++ b/app/src/main/kotlin/org/koitharu/kotatsu/reader/ui/ReaderViewModel.kt @@ -346,39 +346,32 @@ class ReaderViewModel @Inject constructor( } } - fun addBookmark() { + fun toggleBookmark() { if (bookmarkJob?.isActive == true) { return } bookmarkJob = launchJob(Dispatchers.Default) { loadingJob?.join() - val state = checkNotNull(readingState.value) - val page = checkNotNull(getCurrentPage()) { "Page not found" } - val bookmark = Bookmark( - manga = requireManga(), - pageId = page.id, - chapterId = state.chapterId, - page = state.page, - scroll = state.scroll, - imageUrl = page.preview.ifNullOrEmpty { page.url }, - createdAt = Instant.now(), - percent = computePercent(state.chapterId, state.page), - ) - bookmarksRepository.addBookmark(bookmark) - onShowToast.call(R.string.bookmark_added) - } - } - - fun removeBookmark() { - if (bookmarkJob?.isActive == true) { - return - } - bookmarkJob = launchJob { - loadingJob?.join() - val manga = requireManga() val state = checkNotNull(getCurrentState()) - bookmarksRepository.removeBookmark(manga.id, state.chapterId, state.page) - onShowToast.call(R.string.bookmark_removed) + if (isBookmarkAdded.value) { + val manga = requireManga() + bookmarksRepository.removeBookmark(manga.id, state.chapterId, state.page) + onShowToast.call(R.string.bookmark_removed) + } else { + val page = checkNotNull(getCurrentPage()) { "Page not found" } + val bookmark = Bookmark( + manga = requireManga(), + pageId = page.id, + chapterId = state.chapterId, + page = state.page, + scroll = state.scroll, + imageUrl = page.preview.ifNullOrEmpty { page.url }, + createdAt = Instant.now(), + percent = computePercent(state.chapterId, state.page), + ) + bookmarksRepository.addBookmark(bookmark) + onShowToast.call(R.string.bookmark_added) + } } } diff --git a/app/src/main/kotlin/org/koitharu/kotatsu/reader/ui/config/ReaderConfigSheet.kt b/app/src/main/kotlin/org/koitharu/kotatsu/reader/ui/config/ReaderConfigSheet.kt index 788c98be5..21f5fac4f 100644 --- a/app/src/main/kotlin/org/koitharu/kotatsu/reader/ui/config/ReaderConfigSheet.kt +++ b/app/src/main/kotlin/org/koitharu/kotatsu/reader/ui/config/ReaderConfigSheet.kt @@ -4,8 +4,10 @@ import android.os.Bundle import android.view.LayoutInflater import android.view.View import android.view.ViewGroup +import android.widget.Button import android.widget.CompoundButton import androidx.core.view.WindowInsetsCompat +import androidx.core.view.children import androidx.core.view.isGone import androidx.core.view.isVisible import androidx.core.view.updatePadding @@ -24,6 +26,7 @@ import org.koitharu.kotatsu.core.prefs.ReaderMode import org.koitharu.kotatsu.core.ui.sheet.BaseAdaptiveSheet import org.koitharu.kotatsu.core.util.ext.consume import org.koitharu.kotatsu.core.util.ext.findParentCallback +import org.koitharu.kotatsu.core.util.ext.observe import org.koitharu.kotatsu.core.util.ext.viewLifecycleScope import org.koitharu.kotatsu.databinding.SheetReaderConfigBinding import org.koitharu.kotatsu.reader.domain.PageLoader @@ -93,8 +96,16 @@ class ReaderConfigSheet : binding.buttonImageServer.setOnClickListener(this) binding.buttonColorFilter.setOnClickListener(this) binding.buttonScrollTimer.setOnClickListener(this) + binding.buttonBookmark.setOnClickListener(this) binding.switchDoubleReader.setOnCheckedChangeListener(this) + viewModel.isBookmarkAdded.observe(viewLifecycleOwner) { + binding.buttonBookmark.setText(if (it) R.string.bookmark_remove else R.string.bookmark_add) + binding.buttonBookmark.setCompoundDrawablesRelativeWithIntrinsicBounds( + if (it) R.drawable.ic_bookmark_checked else R.drawable.ic_bookmark, 0, 0, 0, + ) + } + viewLifecycleScope.launch { val isAvailable = imageServerDelegate.isAvailable() if (isAvailable) { @@ -120,7 +131,7 @@ class ReaderConfigSheet : } R.id.button_scroll_timer -> { - findParentCallback(Callback::class.java)?.onScrollTimerClick() ?: return + findParentCallback(Callback::class.java)?.onScrollTimerClick(false) ?: return dismissAllowingStateLoss() } @@ -133,6 +144,10 @@ class ReaderConfigSheet : orientationHelper.isLandscape = !orientationHelper.isLandscape } + R.id.button_bookmark -> { + viewModel.toggleBookmark() + } + R.id.button_color_filter -> { val page = viewModel.getCurrentPage() ?: return val manga = viewModel.getMangaOrNull() ?: return @@ -219,6 +234,8 @@ class ReaderConfigSheet : fun onSavePageClick() - fun onScrollTimerClick() + fun onScrollTimerClick(isLongClick: Boolean) + + fun onBookmarkClick() } } diff --git a/app/src/main/res/layout/layout_reader_actions.xml b/app/src/main/res/layout/layout_reader_actions.xml index eee3166e9..7a5986f34 100644 --- a/app/src/main/res/layout/layout_reader_actions.xml +++ b/app/src/main/res/layout/layout_reader_actions.xml @@ -6,7 +6,8 @@ tools:layout_height="wrap_content" tools:layout_width="match_parent" tools:orientation="horizontal" - tools:parentTag="android.widget.LinearLayout"> + tools:parentTag="android.widget.LinearLayout" + tools:style="?dockedToolbarStyle"> @@ -39,9 +41,10 @@ @@ -52,9 +55,10 @@ @@ -65,10 +69,11 @@ @@ -78,9 +83,10 @@ @@ -90,10 +96,25 @@ android:layout_height="wrap_content"> + + + + + @@ -104,9 +125,10 @@ diff --git a/app/src/main/res/layout/sheet_reader_config.xml b/app/src/main/res/layout/sheet_reader_config.xml index ff679f07a..c08038ac6 100644 --- a/app/src/main/res/layout/sheet_reader_config.xml +++ b/app/src/main/res/layout/sheet_reader_config.xml @@ -38,32 +38,27 @@ app:drawableStartCompat="@drawable/ic_save" /> + app:drawableStartCompat="@drawable/ic_bookmark" /> - + + + + - - diff --git a/app/src/main/res/values/arrays.xml b/app/src/main/res/values/arrays.xml index fb8fd705d..87116f7e6 100644 --- a/app/src/main/res/values/arrays.xml +++ b/app/src/main/res/values/arrays.xml @@ -132,6 +132,7 @@ @string/screen_orientation @string/save_page @string/automatic_scroll + @string/bookmark_add @string/favourites diff --git a/app/src/main/res/values/styles.xml b/app/src/main/res/values/styles.xml index 1abac0400..05409eef8 100644 --- a/app/src/main/res/values/styles.xml +++ b/app/src/main/res/values/styles.xml @@ -118,10 +118,6 @@ 42dp - -