Move PageSlider to Compose
This commit is contained in:
1 parent
571fbabf4f
commit
64841e6e3b
4 files changed
+102
-120
No files matched your search
@@ -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())
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -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
|
||||
}
|
||||
Reference in new issue
Block a user