diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/reader/ChapterNavigator.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/reader/ChapterNavigator.kt
new file mode 100644
index 000000000..d011e1a4c
--- /dev/null
+++ b/app/src/main/java/eu/kanade/tachiyomi/ui/reader/ChapterNavigator.kt
@@ -0,0 +1,84 @@
+package eu.kanade.tachiyomi.ui.reader
+
+import androidx.compose.foundation.background
+import androidx.compose.foundation.interaction.MutableInteractionSource
+import androidx.compose.foundation.interaction.collectIsDraggedAsState
+import androidx.compose.foundation.isSystemInDarkTheme
+import androidx.compose.foundation.layout.Row
+import androidx.compose.foundation.layout.fillMaxWidth
+import androidx.compose.foundation.layout.padding
+import androidx.compose.foundation.shape.RoundedCornerShape
+import androidx.compose.material3.MaterialTheme
+import androidx.compose.material3.Slider
+import androidx.compose.material3.Text
+import androidx.compose.material3.surfaceColorAtElevation
+import androidx.compose.runtime.Composable
+import androidx.compose.runtime.CompositionLocalProvider
+import androidx.compose.runtime.LaunchedEffect
+import androidx.compose.runtime.getValue
+import androidx.compose.runtime.remember
+import androidx.compose.ui.Alignment
+import androidx.compose.ui.Modifier
+import androidx.compose.ui.draw.clip
+import androidx.compose.ui.hapticfeedback.HapticFeedbackType
+import androidx.compose.ui.platform.LocalConfiguration
+import androidx.compose.ui.platform.LocalHapticFeedback
+import androidx.compose.ui.platform.LocalLayoutDirection
+import androidx.compose.ui.unit.LayoutDirection
+import androidx.compose.ui.unit.dp
+import eu.kanade.tachiyomi.util.system.isTabletUi
+import kotlin.math.roundToInt
+
+@Composable
+fun ChapterNavigator(
+ isRtl: Boolean,
+ currentPage: Int,
+ totalPages: Int,
+ onSliderValueChange: (Int) -> Unit,
+) {
+ val isTabletUi = LocalConfiguration.current.isTabletUi()
+ val horizontalPadding = if (isTabletUi) 24.dp else 16.dp
+ val layoutDirection = if (isRtl) LayoutDirection.Rtl else LayoutDirection.Ltr
+ val haptic = LocalHapticFeedback.current
+
+ // We explicitly handle direction based on the reader viewer rather than the system direction
+ CompositionLocalProvider(LocalLayoutDirection provides LayoutDirection.Ltr) {
+ Row(
+ modifier = Modifier.fillMaxWidth().padding(horizontal = horizontalPadding),
+ verticalAlignment = Alignment.CenterVertically,
+ ) {
+ // Match with toolbar background color set in ReaderActivity
+ val backgroundColor = MaterialTheme.colorScheme.surfaceColorAtElevation(3.dp).copy(alpha = if (isSystemInDarkTheme()) 0.9f else 0.95f)
+ if (totalPages > 1) {
+ CompositionLocalProvider(LocalLayoutDirection provides layoutDirection) {
+ Row(
+ modifier = Modifier.weight(1f).clip(RoundedCornerShape(24.dp)).background(backgroundColor).padding(horizontal = 16.dp),
+ verticalAlignment = Alignment.CenterVertically,
+ ) {
+ Text(text = currentPage.toString())
+
+ val interactionSource = remember { MutableInteractionSource() }
+ val sliderDragged by interactionSource.collectIsDraggedAsState()
+ LaunchedEffect(currentPage) {
+ if (sliderDragged) {
+ haptic.performHapticFeedback(HapticFeedbackType.TextHandleMove)
+ }
+ }
+ Slider(
+ modifier = Modifier.weight(1f).padding(horizontal = 8.dp),
+ value = currentPage.toFloat(),
+ valueRange = 1f..totalPages.toFloat(),
+ steps = totalPages - 2,
+ onValueChange = {
+ onSliderValueChange(it.roundToInt() - 1)
+ },
+ interactionSource = interactionSource,
+ )
+
+ Text(text = totalPages.toString())
+ }
+ }
+ }
+ }
+ }
+}
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 c033a3797..1317f986a 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
@@ -35,7 +35,6 @@ import android.os.Environment
import android.os.ParcelFileDescriptor
import android.os.ParcelFileDescriptor.MODE_READ_ONLY
import android.provider.MediaStore
-import android.view.HapticFeedbackConstants
import android.view.KeyEvent
import android.view.MotionEvent
import android.view.View.LAYER_TYPE_HARDWARE
@@ -49,6 +48,7 @@ import androidx.activity.result.contract.ActivityResultContracts.CreateDocument
import androidx.appcompat.app.AlertDialog
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableIntStateOf
+import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.setValue
import androidx.core.content.ContextCompat
import androidx.core.content.FileProvider
@@ -59,7 +59,6 @@ import androidx.core.view.WindowInsetsControllerCompat
import androidx.core.view.isVisible
import androidx.lifecycle.lifecycleScope
import com.google.android.material.shape.MaterialShapeDrawable
-import com.google.android.material.slider.Slider
import com.google.android.material.transition.MaterialContainerTransform
import com.hippo.ehviewer.AppConfig
import com.hippo.ehviewer.BuildConfig
@@ -113,7 +112,6 @@ import java.util.concurrent.atomic.AtomicReference
import kotlin.coroutines.Continuation
import kotlin.coroutines.resume
import kotlin.math.abs
-import kotlin.math.max
class ReaderActivity : EhActivity() {
lateinit var binding: ReaderActivityBinding
@@ -352,7 +350,7 @@ class ReaderActivity : EhActivity() {
binding.actionReadingMode.setImageResource(viewerMode.iconRes)
viewer?.destroy()
viewer = ReadingModeType.toViewer(ReaderPreferences.defaultReadingMode().get(), this)
- binding.pageSlider.isRTL = viewer is R2LPagerViewer
+ isRtl = viewer is R2LPagerViewer
updateViewerInset(ReaderPreferences.fullscreen().get())
binding.viewerContainer.removeAllViews()
setOrientation(ReaderPreferences.defaultOrientationType().get())
@@ -660,6 +658,7 @@ class ReaderActivity : EhActivity() {
}
private var currentPage by mutableIntStateOf(-1)
+ private var isRtl by mutableStateOf(false)
/**
* Initializes the reader menu. It sets up click listeners and the initial visibility.
@@ -672,31 +671,26 @@ class ReaderActivity : EhActivity() {
}
}
+ val totalPages = mGalleryProvider?.takeIf { it.isReady }?.size ?: -1
+
binding.pageNumber.setReaderMD3Content {
PageIndicatorText(
currentPage = currentPage,
- totalPages = mGalleryProvider?.takeIf { it.isReady }?.size ?: -1,
+ totalPages = totalPages,
)
}
// Init listeners on bottom menu
- binding.pageSlider.addOnSliderTouchListener(
- object : Slider.OnSliderTouchListener {
- override fun onStartTrackingTouch(slider: Slider) {
+ binding.readerNav.setReaderMD3Content {
+ ChapterNavigator(
+ isRtl = isRtl,
+ currentPage = currentPage,
+ totalPages = totalPages,
+ onSliderValueChange = {
isScrollingThroughPages = true
- }
-
- override fun onStopTrackingTouch(slider: Slider) {
- isScrollingThroughPages = false
- }
- },
- )
- binding.pageSlider.addOnChangeListener { slider, value, fromUser ->
- if (viewer != null && fromUser) {
- isScrollingThroughPages = true
- moveToPageIndex(value.toInt())
- slider.performHapticFeedback(HapticFeedbackConstants.CLOCK_TICK)
- }
+ moveToPageIndex(it)
+ },
+ )
}
initBottomShortcuts()
@@ -708,10 +702,6 @@ class ReaderActivity : EhActivity() {
}
binding.toolbarBottom.background = toolbarBackground.copy(this@ReaderActivity)
- binding.readerSeekbar.background = toolbarBackground.copy(this@ReaderActivity)?.apply {
- setCornerSize(999F)
- }
-
val toolbarColor = ColorUtils.setAlphaComponent(
toolbarBackground.resolvedTintColor,
toolbarBackground.alpha,
@@ -866,25 +856,9 @@ class ReaderActivity : EhActivity() {
*/
@SuppressLint("SetTextI18n")
fun onPageSelected(page: ReaderPage) {
- val pages = mGalleryProvider?.mPages ?: return
-
// Set bottom page number
currentPage = page.number
- // Set page numbers
- if (viewer !is R2LPagerViewer) {
- binding.leftPageText.text = "${page.number}"
- binding.rightPageText.text = "${pages.size}"
- } else {
- binding.rightPageText.text = "${page.number}"
- binding.leftPageText.text = "${pages.size}"
- }
-
- // Set slider progress
- binding.pageSlider.isEnabled = pages.size > 1
- binding.pageSlider.valueTo = max(pages.lastIndex.toFloat(), 1f)
- binding.pageSlider.value = page.index.toFloat()
-
mCurrentIndex = page.index
mGalleryProvider?.putStartPage(mCurrentIndex)
}
@@ -1064,7 +1038,7 @@ class ReaderActivity : EhActivity() {
}
fun setReaderSeekbarVisibility(visible: Boolean) {
- binding.readerSeekbar.isVisible = visible
+ binding.readerNav.isVisible = visible
}
/**
diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/reader/ReaderSlider.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/reader/ReaderSlider.kt
deleted file mode 100644
index 94f857785..000000000
--- a/app/src/main/java/eu/kanade/tachiyomi/ui/reader/ReaderSlider.kt
+++ /dev/null
@@ -1,30 +0,0 @@
-package eu.kanade.tachiyomi.ui.reader
-
-import android.content.Context
-import android.util.AttributeSet
-import com.google.android.material.slider.Slider
-
-/**
- * Slider to show current chapter progress.
- */
-class ReaderSlider @JvmOverloads constructor(
- context: Context,
- attrs: AttributeSet? = null,
-) : Slider(context, attrs) {
-
- init {
- stepSize = 1f
- setLabelFormatter { value ->
- (value.toInt() + 1).toString()
- }
- }
-
- /**
- * Whether the slider should draw from right to left.
- */
- var isRTL: Boolean
- set(value) {
- layoutDirection = if (value) LAYOUT_DIRECTION_RTL else LAYOUT_DIRECTION_LTR
- }
- get() = layoutDirection == LAYOUT_DIRECTION_RTL
-}
diff --git a/app/src/main/res/layout/reader_activity.xml b/app/src/main/res/layout/reader_activity.xml
index b564d854a..009b34a27 100644
--- a/app/src/main/res/layout/reader_activity.xml
+++ b/app/src/main/res/layout/reader_activity.xml
@@ -54,58 +54,12 @@
android:layout_gravity="bottom"
android:orientation="vertical">
-
-
-
-
-
-
-
-
-
-
-
-
-
+ android:layoutDirection="ltr" />