diff --git a/.idea/AndroidProjectSystem.xml b/.idea/AndroidProjectSystem.xml
new file mode 100644
index 000000000..4a53bee8c
--- /dev/null
+++ b/.idea/AndroidProjectSystem.xml
@@ -0,0 +1,6 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/kotlin/org/koitharu/kotatsu/core/prefs/AppSettings.kt b/app/src/main/kotlin/org/koitharu/kotatsu/core/prefs/AppSettings.kt
index e677c4b13..05ccaa494 100644
--- a/app/src/main/kotlin/org/koitharu/kotatsu/core/prefs/AppSettings.kt
+++ b/app/src/main/kotlin/org/koitharu/kotatsu/core/prefs/AppSettings.kt
@@ -362,8 +362,9 @@ class AppSettings @Inject constructor(@ApplicationContext context: Context) {
val isReaderBarEnabled: Boolean
get() = prefs.getBoolean(KEY_READER_BAR, true)
- val isReaderSliderEnabled: Boolean
+ var isReaderSliderEnabled: Boolean
get() = prefs.getBoolean(KEY_READER_SLIDER, true)
+ set(value) = prefs.edit { putBoolean(KEY_READER_SLIDER, value) }
val isReaderKeepScreenOn: Boolean
get() = prefs.getBoolean(KEY_READER_SCREEN_ON, true)
diff --git a/app/src/main/kotlin/org/koitharu/kotatsu/details/ui/ReadButtonDelegate.kt b/app/src/main/kotlin/org/koitharu/kotatsu/details/ui/ReadButtonDelegate.kt
index 48a8d22c5..5457fbd44 100644
--- a/app/src/main/kotlin/org/koitharu/kotatsu/details/ui/ReadButtonDelegate.kt
+++ b/app/src/main/kotlin/org/koitharu/kotatsu/details/ui/ReadButtonDelegate.kt
@@ -20,6 +20,7 @@ import androidx.lifecycle.LifecycleOwner
import com.google.android.material.button.MaterialButton
import com.google.android.material.button.MaterialSplitButton
import com.google.android.material.snackbar.Snackbar
+import kotlinx.coroutines.flow.combine
import org.koitharu.kotatsu.R
import org.koitharu.kotatsu.core.model.isLocal
import org.koitharu.kotatsu.core.util.ext.findActivity
@@ -30,7 +31,7 @@ import org.koitharu.kotatsu.download.ui.dialog.DownloadDialogFragment
import org.koitharu.kotatsu.reader.ui.ReaderActivity
class ReadButtonDelegate(
- splitButton: MaterialSplitButton,
+ private val splitButton: MaterialSplitButton,
private val viewModel: DetailsViewModel,
) : View.OnClickListener, PopupMenu.OnMenuItemClickListener, PopupMenu.OnDismissListener {
@@ -73,7 +74,10 @@ class ReadButtonDelegate(
fun attach(lifecycleOwner: LifecycleOwner) {
buttonRead.setOnClickListener(this)
buttonMenu.setOnClickListener(this)
- viewModel.historyInfo.observe(lifecycleOwner, this::onHistoryChanged)
+ combine(viewModel.isLoading, viewModel.historyInfo, ::Pair)
+ .observe(lifecycleOwner) { (isLoading, historyInfo) ->
+ onHistoryChanged(isLoading, historyInfo)
+ }
}
private fun showMenu() {
@@ -97,16 +101,15 @@ class ReadButtonDelegate(
}
private fun openReader(isIncognitoMode: Boolean) {
- val detailsViewModel = viewModel as? DetailsViewModel ?: return
val manga = viewModel.manga.value ?: return
- if (detailsViewModel.historyInfo.value.isChapterMissing) {
+ if (viewModel.historyInfo.value.isChapterMissing) {
Snackbar.make(buttonRead, R.string.chapter_is_missing, Snackbar.LENGTH_SHORT)
.show() // TODO
} else {
context.startActivity(
ReaderActivity.IntentBuilder(context)
.manga(manga)
- .branch(detailsViewModel.selectedBranchValue)
+ .branch(viewModel.selectedBranchValue)
.incognito(isIncognitoMode)
.build(),
)
@@ -116,9 +119,16 @@ class ReadButtonDelegate(
}
}
- private fun onHistoryChanged(info: HistoryInfo) {
- buttonRead.setText(if (info.canContinue) R.string._continue else R.string.read)
- buttonRead.isEnabled = info.isValid
+ private fun onHistoryChanged(isLoading: Boolean, info: HistoryInfo) {
+ buttonRead.setText(
+ when {
+ isLoading -> R.string.loading_
+ info.isIncognitoMode -> R.string.incognito
+ info.canContinue -> R.string._continue
+ else -> R.string.read
+ },
+ )
+ splitButton.isEnabled = !isLoading && info.isValid
}
private fun Menu.populateBranchList() {
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 4adbad36a..98bccb250 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
@@ -2,7 +2,6 @@ package org.koitharu.kotatsu.reader.ui
import android.content.Context
import android.content.Intent
-import android.net.Uri
import android.os.Bundle
import android.transition.Fade
import android.transition.Slide
@@ -42,7 +41,6 @@ import org.koitharu.kotatsu.core.ui.BaseFullscreenActivity
import org.koitharu.kotatsu.core.ui.util.MenuInvalidator
import org.koitharu.kotatsu.core.ui.widgets.ZoomControl
import org.koitharu.kotatsu.core.util.IdlingDetector
-import org.koitharu.kotatsu.core.util.ShareHelper
import org.koitharu.kotatsu.core.util.ext.hasGlobalPoint
import org.koitharu.kotatsu.core.util.ext.isAnimationsEnabled
import org.koitharu.kotatsu.core.util.ext.isRtl
@@ -127,6 +125,8 @@ class ReaderActivity :
ReaderSliderListener(viewModel, this).attachToSlider(viewBinding.slider)
insetsDelegate.interceptingWindowInsetsListener = this
idlingDetector.bindToLifecycle(this)
+ viewBinding.buttonPrev.setOnClickListener(controlDelegate)
+ viewBinding.buttonNext.setOnClickListener(controlDelegate)
viewModel.onError.observeEvent(
this,
@@ -150,10 +150,12 @@ class ReaderActivity :
viewModel.content.observe(this) {
onLoadingStateChanged(viewModel.isLoading.value)
}
+ viewModel.isSliderVisible.observe(this, this::onSliderVisibilityChanged)
viewModel.isKeepScreenOnEnabled.observe(this, this::setKeepScreenOn)
viewModel.isInfoBarEnabled.observe(this, ::onReaderBarChanged)
- viewModel.isBookmarkAdded.observe(this, MenuInvalidator(this))
- viewModel.isPagesSheetEnabled.observe(this, MenuInvalidator(viewBinding.toolbarBottom))
+ val bottomMenuInvalidator = MenuInvalidator(viewBinding.toolbarBottom)
+ viewModel.isBookmarkAdded.observe(this, bottomMenuInvalidator)
+ viewModel.isPagesSheetEnabled.observe(this, bottomMenuInvalidator)
viewModel.onShowToast.observeEvent(this) { msgId ->
Snackbar.make(viewBinding.container, msgId, Snackbar.LENGTH_SHORT)
.setAnchorView(viewBinding.appbarBottom)
@@ -243,7 +245,7 @@ class ReaderActivity :
false
} else {
val touchables = window.peekDecorView()?.touchables
- touchables?.none { it.hasGlobalPoint(rawX, rawY) } ?: true
+ touchables?.none { it.hasGlobalPoint(rawX, rawY) } != false
}
}
@@ -307,6 +309,9 @@ class ReaderActivity :
.addTransition(Fade().addTarget(viewBinding.infoBar))
viewBinding.appbarBottom?.let { bottomBar ->
transition.addTransition(Slide(Gravity.BOTTOM).addTarget(bottomBar))
+ transition.addTransition(Slide(Gravity.BOTTOM).addTarget(viewBinding.floatingToolbar))
+ } ?: run {
+ transition.addTransition(Slide(Gravity.END).addTarget(viewBinding.floatingToolbar))
}
TransitionManager.beginDelayedTransition(viewBinding.root, transition)
}
@@ -315,10 +320,15 @@ class ReaderActivity :
viewBinding.appbarBottom?.isVisible = isUiVisible
viewBinding.infoBar.isGone = isUiVisible || (!viewModel.isInfoBarEnabled.value)
viewBinding.infoBar.isTimeVisible = isFullscreen
+ viewBinding.floatingToolbar.isVisible = isUiVisible && viewModel.isSliderVisible.value
systemUiController.setSystemUiVisible(isUiVisible || !isFullscreen)
}
}
+ private fun onSliderVisibilityChanged(isSliderVisible: Boolean) {
+ viewBinding.floatingToolbar.isVisible = isSliderVisible && viewBinding.appbarTop.isVisible
+ }
+
override fun onApplyWindowInsets(v: View, insets: WindowInsetsCompat): WindowInsetsCompat {
gestureInsets = insets.getInsets(WindowInsetsCompat.Type.systemGestures())
val systemBars = insets.getInsets(WindowInsetsCompat.Type.systemBars())
@@ -357,7 +367,7 @@ class ReaderActivity :
}
override fun scrollBy(delta: Int, smooth: Boolean): Boolean {
- return readerManager.currentReader?.scrollBy(delta, smooth) ?: false
+ return readerManager.currentReader?.scrollBy(delta, smooth) == true
}
override fun toggleUiVisibility() {
diff --git a/app/src/main/kotlin/org/koitharu/kotatsu/reader/ui/ReaderBottomMenuProvider.kt b/app/src/main/kotlin/org/koitharu/kotatsu/reader/ui/ReaderBottomMenuProvider.kt
index ab1013374..d02125ede 100644
--- a/app/src/main/kotlin/org/koitharu/kotatsu/reader/ui/ReaderBottomMenuProvider.kt
+++ b/app/src/main/kotlin/org/koitharu/kotatsu/reader/ui/ReaderBottomMenuProvider.kt
@@ -28,6 +28,15 @@ class ReaderBottomMenuProvider(
setIcon(if (viewModel.isPagesSheetEnabled.value) R.drawable.ic_grid else R.drawable.ic_list)
}
}
+ 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 {
@@ -44,6 +53,20 @@ class ReaderBottomMenuProvider(
true
}
+ R.id.action_slider -> {
+ viewModel.setSliderVisibility(!viewModel.isSliderVisible.value)
+ true
+ }
+
+ R.id.action_bookmark -> {
+ if (viewModel.isBookmarkAdded.value) {
+ viewModel.removeBookmark()
+ } else {
+ viewModel.addBookmark()
+ }
+ true
+ }
+
else -> false
}
}
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 53421d319..2076a50b5 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
@@ -2,6 +2,7 @@ package org.koitharu.kotatsu.reader.ui
import android.content.res.Resources
import android.view.KeyEvent
+import android.view.View
import org.koitharu.kotatsu.R
import org.koitharu.kotatsu.core.prefs.AppSettings
import org.koitharu.kotatsu.core.prefs.ReaderMode
@@ -14,10 +15,17 @@ class ReaderControlDelegate(
private val settings: AppSettings,
private val tapGridSettings: TapGridSettings,
private val listener: OnInteractionListener,
-) {
+) : View.OnClickListener {
private var minScrollDelta = resources.getDimensionPixelSize(R.dimen.reader_scroll_delta_min)
+ override fun onClick(v: View) {
+ when (v.id) {
+ R.id.button_prev -> listener.switchChapterBy(-1)
+ R.id.button_next -> listener.switchChapterBy(1)
+ }
+ }
+
fun onGridTouch(area: TapGridArea): Boolean {
val action = tapGridSettings.getTapAction(
area = area,
@@ -63,7 +71,7 @@ class ReaderControlDelegate(
KeyEvent.KEYCODE_SPACE,
KeyEvent.KEYCODE_PAGE_DOWN,
- -> {
+ -> {
listener.switchPageBy(1)
true
}
@@ -74,7 +82,7 @@ class ReaderControlDelegate(
}
KeyEvent.KEYCODE_PAGE_UP,
- -> {
+ -> {
listener.switchPageBy(-1)
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 f7649b4b7..93b2e42d7 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
@@ -131,6 +131,12 @@ class ReaderViewModel @Inject constructor(
valueProducer = { readerAnimation },
)
+ val isSliderVisible = settings.observeAsStateFlow(
+ scope = viewModelScope + Dispatchers.Default,
+ key = AppSettings.KEY_READER_SLIDER,
+ valueProducer = { isReaderSliderEnabled },
+ )
+
val isInfoBarEnabled = settings.observeAsStateFlow(
scope = viewModelScope + Dispatchers.Default,
key = AppSettings.KEY_READER_BAR,
@@ -213,6 +219,10 @@ class ReaderViewModel @Inject constructor(
}
}
+ fun setSliderVisibility(visible: Boolean) {
+ settings.isReaderSliderEnabled = visible
+ }
+
fun switchMode(newMode: ReaderMode) {
launchJob {
val manga = checkNotNull(getMangaOrNull())
diff --git a/app/src/main/res/drawable/ic_move_horizontal.xml b/app/src/main/res/drawable/ic_move_horizontal.xml
new file mode 100644
index 000000000..5c67c54df
--- /dev/null
+++ b/app/src/main/res/drawable/ic_move_horizontal.xml
@@ -0,0 +1,11 @@
+
+
+
diff --git a/app/src/main/res/drawable/ic_next.xml b/app/src/main/res/drawable/ic_next.xml
new file mode 100644
index 000000000..6c80ccb83
--- /dev/null
+++ b/app/src/main/res/drawable/ic_next.xml
@@ -0,0 +1,12 @@
+
+
+
+
diff --git a/app/src/main/res/drawable/ic_prev.xml b/app/src/main/res/drawable/ic_prev.xml
new file mode 100644
index 000000000..8822aa243
--- /dev/null
+++ b/app/src/main/res/drawable/ic_prev.xml
@@ -0,0 +1,12 @@
+
+
+
+
diff --git a/app/src/main/res/layout-w600dp-land/activity_reader.xml b/app/src/main/res/layout-w600dp-land/activity_reader.xml
index 4ee41c34a..92ec14325 100644
--- a/app/src/main/res/layout-w600dp-land/activity_reader.xml
+++ b/app/src/main/res/layout-w600dp-land/activity_reader.xml
@@ -59,23 +59,64 @@
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
- tools:menu="@menu/opt_reader_bottom">
-
-
-
-
+ tools:menu="@menu/opt_reader_bottom" />
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ tools:menu="@menu/opt_reader_bottom" />
+
+
+
+
+
+
+
+
-
+
-
+
+
+
+
+
+
+
- Source
Translation
%1$s (%2$s)
+ Show slider
+
+ Incognito
diff --git a/app/src/main/res/values/styles.xml b/app/src/main/res/values/styles.xml
index b48a87d7a..fd3ffe310 100644
--- a/app/src/main/res/values/styles.xml
+++ b/app/src/main/res/values/styles.xml
@@ -144,6 +144,12 @@
- ?shapeAppearanceCornerMedium
+
+
diff --git a/app/src/main/res/xml/pref_reader.xml b/app/src/main/res/xml/pref_reader.xml
index 0c7386ea1..531fe26fb 100644
--- a/app/src/main/res/xml/pref_reader.xml
+++ b/app/src/main/res/xml/pref_reader.xml
@@ -121,11 +121,6 @@
android:title="@string/reader_info_bar"
app:allowDividerAbove="true" />
-
-