mirror of
https://github.com/Suwayomi/TachideskJUI.git
synced 2025-12-10 06:42:05 +01:00
Improve separation of current chapter from UI
This commit is contained in:
@@ -244,13 +244,13 @@ fun WideReaderMenu(
|
||||
fitSize: Boolean,
|
||||
maxSize: Int,
|
||||
navigationViewer: ViewerNavigation,
|
||||
currentPage: Int,
|
||||
currentPage: ReaderItem?,
|
||||
currentPageOffset: Int,
|
||||
navigate: (Int) -> Unit,
|
||||
navigateTap: (Navigation) -> Unit,
|
||||
pageEmitterHolder: StableHolder<SharedFlow<PageMove>>,
|
||||
retry: (ReaderPage) -> Unit,
|
||||
progress: (Int) -> Unit,
|
||||
progress: (ReaderItem) -> Unit,
|
||||
updateLastPageReadOffset: (Int) -> Unit,
|
||||
sideMenuOpen: Boolean,
|
||||
setSideMenuOpen: (Boolean) -> Unit,
|
||||
@@ -273,6 +273,7 @@ fun WideReaderMenu(
|
||||
) {
|
||||
ReaderSideMenu(
|
||||
chapter = chapter,
|
||||
pages = pages,
|
||||
currentPage = currentPage,
|
||||
readerModes = readerModes,
|
||||
selectedMode = readerMode,
|
||||
@@ -325,13 +326,13 @@ fun ThinReaderMenu(
|
||||
fitSize: Boolean,
|
||||
maxSize: Int,
|
||||
navigationViewer: ViewerNavigation,
|
||||
currentPage: Int,
|
||||
currentPage: ReaderItem?,
|
||||
currentPageOffset: Int,
|
||||
navigate: (Int) -> Unit,
|
||||
navigateTap: (Navigation) -> Unit,
|
||||
pageEmitterHolder: StableHolder<SharedFlow<PageMove>>,
|
||||
retry: (ReaderPage) -> Unit,
|
||||
progress: (Int) -> Unit,
|
||||
progress: (ReaderItem) -> Unit,
|
||||
updateLastPageReadOffset: (Int) -> Unit,
|
||||
readerMenuOpen: Boolean,
|
||||
setMangaReaderMode: (String) -> Unit,
|
||||
@@ -407,6 +408,7 @@ fun ThinReaderMenu(
|
||||
chapter = chapter,
|
||||
nextChapter = nextChapter,
|
||||
direction = direction,
|
||||
pages = pages,
|
||||
currentPage = currentPage,
|
||||
navigate = navigate,
|
||||
readerMenuOpen = readerMenuOpen,
|
||||
@@ -427,12 +429,12 @@ fun ReaderLayout(
|
||||
fitSize: Boolean,
|
||||
maxSize: Int,
|
||||
navigationViewer: ViewerNavigation,
|
||||
currentPage: Int,
|
||||
currentPage: ReaderItem?,
|
||||
currentPageOffset: Int,
|
||||
navigateTap: (Navigation) -> Unit,
|
||||
pageEmitterHolder: StableHolder<SharedFlow<PageMove>>,
|
||||
retry: (ReaderPage) -> Unit,
|
||||
progress: (Int) -> Unit,
|
||||
progress: (ReaderItem) -> Unit,
|
||||
updateLastPageReadOffset: (Int) -> Unit
|
||||
) {
|
||||
val loadingModifier = Modifier.widthIn(max = 700.dp)
|
||||
|
||||
@@ -95,7 +95,7 @@ class ReaderMenuViewModel @Inject constructor(
|
||||
private val _pages = MutableStateFlow<ImmutableList<ReaderItem>>(persistentListOf())
|
||||
val pages = _pages.asStateFlow()
|
||||
|
||||
private val _currentPage = MutableStateFlow(1)
|
||||
private val _currentPage = MutableStateFlow<ReaderItem?>(null)
|
||||
val currentPage = _currentPage.asStateFlow()
|
||||
|
||||
private val _currentPageOffset = MutableStateFlow(1)
|
||||
@@ -163,7 +163,7 @@ class ReaderMenuViewModel @Inject constructor(
|
||||
}
|
||||
}
|
||||
if (moveTo != null) {
|
||||
_pageEmitter.emit(PageMove.Direction(moveTo, currentPage.value))
|
||||
_pageEmitter.emit(PageMove.Direction(moveTo))
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -171,24 +171,24 @@ class ReaderMenuViewModel @Inject constructor(
|
||||
fun navigate(page: Int) {
|
||||
log.info { "Navigate to $page" }
|
||||
scope.launch {
|
||||
_pageEmitter.emit(PageMove.Page(page))
|
||||
_pageEmitter.emit(PageMove.Page(pages.value.getOrNull(page) ?: return@launch))
|
||||
}
|
||||
}
|
||||
|
||||
fun progress(index: Int) {
|
||||
log.info { "Progressed to $index" }
|
||||
_currentPage.value = index
|
||||
fun progress(page: ReaderItem) {
|
||||
log.info { "Progressed to $page" }
|
||||
_currentPage.value = page
|
||||
}
|
||||
|
||||
fun retry(page: ReaderPage) {
|
||||
log.info { "Retrying $page" }
|
||||
log.info { "Retrying ${page.index}" }
|
||||
chapter.value?.pageLoader?.retryPage(page)
|
||||
}
|
||||
|
||||
private fun resetValues() {
|
||||
viewerChapters.recycle()
|
||||
_pages.value = persistentListOf()
|
||||
_currentPage.value = 1
|
||||
_currentPage.value = null
|
||||
}
|
||||
|
||||
fun setMangaReaderMode(mode: String) {
|
||||
@@ -279,11 +279,6 @@ class ReaderMenuViewModel @Inject constructor(
|
||||
)
|
||||
}
|
||||
|
||||
val lastPageRead = chapter.chapter.lastPageRead
|
||||
if (lastPageRead != 0) {
|
||||
_currentPage.value = lastPageRead.coerceAtMost(chapter.chapter.pageCount!!)
|
||||
}
|
||||
|
||||
val lastPageReadOffset = chapter.chapter.meta.juiPageOffset
|
||||
if (lastPageReadOffset != 0) {
|
||||
_currentPageOffset.value = lastPageReadOffset
|
||||
@@ -300,14 +295,20 @@ class ReaderMenuViewModel @Inject constructor(
|
||||
val prevSeparator = ReaderPageSeparator(viewerChapters.prevChapter.value, chapter)
|
||||
val nextSeparator = ReaderPageSeparator(chapter, viewerChapters.nextChapter.value)
|
||||
_pages.value = (_pages.value.ifEmpty { listOf(prevSeparator) } + pageList + nextSeparator).toImmutableList()
|
||||
pageList.getOrNull(_currentPage.value - 1)?.let { chapter.pageLoader?.loadPage(it) }
|
||||
val lastPageRead = chapter.chapter.lastPageRead
|
||||
_currentPage.value = if (lastPageRead != 0) {
|
||||
pageList[lastPageRead.coerceAtMost(pageList.lastIndex)]
|
||||
} else {
|
||||
pageList.first()
|
||||
}.also { chapter.pageLoader?.loadPage(it) }
|
||||
}
|
||||
.launchIn(chapter.scope)
|
||||
|
||||
_currentPage
|
||||
.onEach { index ->
|
||||
(_pages.value.getOrNull(_currentPage.value - 1) as? ReaderPage)?.let { chapter.pageLoader?.loadPage(it) }
|
||||
if (index == _pages.value.lastIndex) {
|
||||
.filterIsInstance<ReaderPage>()
|
||||
.onEach { page ->
|
||||
chapter.pageLoader?.loadPage(page)
|
||||
if ((page.index + 1) >= chapter.chapter.pageCount!!) {
|
||||
markChapterRead(chapter)
|
||||
}
|
||||
}
|
||||
@@ -315,14 +316,25 @@ class ReaderMenuViewModel @Inject constructor(
|
||||
}
|
||||
|
||||
private fun markChapterRead(chapter: ReaderChapter) {
|
||||
scope.launch { updateChapterRead.await(chapter.chapter, read = true, onError = { toast(it.message.orEmpty()) }) }
|
||||
scope.launch {
|
||||
updateChapterRead.await(chapter.chapter, read = true, onError = { toast(it.message.orEmpty()) })
|
||||
}
|
||||
}
|
||||
|
||||
@OptIn(DelicateCoroutinesApi::class)
|
||||
fun sendProgress(chapter: Chapter? = this.chapter.value?.chapter, lastPageRead: Int = currentPage.value) {
|
||||
fun sendProgress(
|
||||
chapter: Chapter? = this.chapter.value?.chapter,
|
||||
lastPageRead: Int = (currentPage.value as? ReaderPage)?.index ?: 0
|
||||
) {
|
||||
chapter ?: return
|
||||
if (chapter.read) return
|
||||
GlobalScope.launch { updateChapterLastPageRead.await(chapter, lastPageRead = lastPageRead, onError = { toast(it.message.orEmpty()) }) }
|
||||
GlobalScope.launch {
|
||||
updateChapterLastPageRead.await(
|
||||
chapter,
|
||||
lastPageRead = lastPageRead,
|
||||
onError = { toast(it.message.orEmpty()) }
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
fun updateLastPageReadOffset(offset: Int) {
|
||||
@@ -331,7 +343,9 @@ class ReaderMenuViewModel @Inject constructor(
|
||||
|
||||
@OptIn(DelicateCoroutinesApi::class)
|
||||
private fun updateLastPageReadOffset(chapter: Chapter, offset: Int) {
|
||||
GlobalScope.launch { updateChapterMeta.await(chapter, offset, onError = { toast(it.message.orEmpty()) }) }
|
||||
GlobalScope.launch {
|
||||
updateChapterMeta.await(chapter, offset, onError = { toast(it.message.orEmpty()) })
|
||||
}
|
||||
}
|
||||
|
||||
override fun onDispose() {
|
||||
|
||||
@@ -56,6 +56,7 @@ import ca.gosyer.jui.domain.manga.model.MangaMeta
|
||||
import ca.gosyer.jui.domain.reader.model.Direction
|
||||
import ca.gosyer.jui.i18n.MR
|
||||
import ca.gosyer.jui.ui.reader.model.ReaderChapter
|
||||
import ca.gosyer.jui.ui.reader.model.ReaderItem
|
||||
import ca.gosyer.jui.uicore.components.AroundLayout
|
||||
import ca.gosyer.jui.uicore.components.Spinner
|
||||
import ca.gosyer.jui.uicore.resources.stringResource
|
||||
@@ -67,7 +68,8 @@ import kotlin.math.roundToInt
|
||||
@Composable
|
||||
fun ReaderSideMenu(
|
||||
chapter: ReaderChapter,
|
||||
currentPage: Int,
|
||||
pages: ImmutableList<ReaderItem>,
|
||||
currentPage: ReaderItem?,
|
||||
readerModes: ImmutableList<String>,
|
||||
selectedMode: String,
|
||||
onNewPageClicked: (Int) -> Unit,
|
||||
@@ -86,6 +88,7 @@ fun ReaderSideMenu(
|
||||
onSetReaderMode = onSetReaderMode
|
||||
)
|
||||
ReaderProgressSlider(
|
||||
pages = pages,
|
||||
currentPage = currentPage,
|
||||
pageCount = pageCount,
|
||||
onNewPageClicked = onNewPageClicked,
|
||||
@@ -106,7 +109,8 @@ fun ReaderExpandBottomMenu(
|
||||
chapter: ReaderChapter,
|
||||
nextChapter: ReaderChapter?,
|
||||
direction: Direction,
|
||||
currentPage: Int,
|
||||
pages: ImmutableList<ReaderItem>,
|
||||
currentPage: ReaderItem?,
|
||||
navigate: (Int) -> Unit,
|
||||
readerMenuOpen: Boolean,
|
||||
movePrevChapter: () -> Unit,
|
||||
@@ -170,7 +174,7 @@ fun ReaderExpandBottomMenu(
|
||||
startLayout = {
|
||||
Box(Modifier.fillMaxHeight().width(32.dp), contentAlignment = Alignment.Center) {
|
||||
val text = if (!isRtL) {
|
||||
currentPage
|
||||
pages.indexOf(currentPage)
|
||||
} else {
|
||||
chapter.chapter.pageCount!!
|
||||
}.toString()
|
||||
@@ -180,7 +184,7 @@ fun ReaderExpandBottomMenu(
|
||||
endLayout = {
|
||||
Box(Modifier.fillMaxHeight().width(32.dp), contentAlignment = Alignment.Center) {
|
||||
val text = if (isRtL) {
|
||||
currentPage
|
||||
pages.indexOf(currentPage)
|
||||
} else {
|
||||
chapter.chapter.pageCount!!
|
||||
}.toString()
|
||||
@@ -192,6 +196,7 @@ fun ReaderExpandBottomMenu(
|
||||
modifier = Modifier.fillMaxWidth()
|
||||
.padding(paddingValues)
|
||||
.padding(horizontal = 4.dp),
|
||||
pages = pages,
|
||||
currentPage = currentPage,
|
||||
pageCount = chapter.chapter.pageCount!!,
|
||||
onNewPageClicked = navigate,
|
||||
@@ -253,13 +258,14 @@ private fun ReaderMenuToolbar(onCloseSideMenuClicked: () -> Unit) {
|
||||
@Composable
|
||||
private fun ReaderProgressSlider(
|
||||
modifier: Modifier = Modifier,
|
||||
currentPage: Int,
|
||||
pages: ImmutableList<ReaderItem>,
|
||||
currentPage: ReaderItem?,
|
||||
pageCount: Int,
|
||||
onNewPageClicked: (Int) -> Unit,
|
||||
isRtL: Boolean
|
||||
) {
|
||||
val animatedProgress by animateFloatAsState(
|
||||
targetValue = currentPage.toFloat(),
|
||||
targetValue = pages.indexOf(currentPage).toFloat(),
|
||||
animationSpec = ProgressIndicatorDefaults.ProgressAnimationSpec
|
||||
)
|
||||
var isValueChanging by remember { mutableStateOf(false) }
|
||||
|
||||
@@ -7,6 +7,6 @@
|
||||
package ca.gosyer.jui.ui.reader.model
|
||||
|
||||
sealed class PageMove {
|
||||
data class Direction(val moveTo: MoveTo, val currentPage: Int) : PageMove()
|
||||
data class Page(val pageNumber: Int) : PageMove()
|
||||
data class Direction(val moveTo: MoveTo) : PageMove()
|
||||
data class Page(val page: ReaderItem) : PageMove()
|
||||
}
|
||||
|
||||
@@ -49,6 +49,7 @@ import kotlinx.coroutines.flow.SharedFlow
|
||||
import kotlinx.coroutines.flow.filterNotNull
|
||||
import kotlinx.coroutines.flow.launchIn
|
||||
import kotlinx.coroutines.flow.mapLatest
|
||||
import kotlinx.coroutines.flow.mapNotNull
|
||||
|
||||
@Composable
|
||||
fun ContinuousReader(
|
||||
@@ -57,17 +58,17 @@ fun ContinuousReader(
|
||||
direction: Direction,
|
||||
maxSize: Int,
|
||||
padding: Int,
|
||||
currentPage: Int,
|
||||
currentPage: ReaderItem?,
|
||||
currentPageOffset: Int,
|
||||
loadingModifier: Modifier,
|
||||
pageContentScale: ContentScale,
|
||||
pageEmitterHolder: StableHolder<SharedFlow<PageMove>>,
|
||||
retry: (ReaderPage) -> Unit,
|
||||
progress: (Int) -> Unit,
|
||||
progress: (ReaderItem) -> Unit,
|
||||
updateLastPageReadOffset: (Int) -> Unit
|
||||
) {
|
||||
BoxWithConstraints(modifier then Modifier.fillMaxSize()) {
|
||||
val state = rememberLazyListState(currentPage, currentPageOffset)
|
||||
val state = rememberLazyListState(pages.indexOf(currentPage).coerceAtLeast(1), currentPageOffset)
|
||||
val density = LocalDensity.current
|
||||
LaunchedEffect(Unit) {
|
||||
pageEmitterHolder.item
|
||||
@@ -87,8 +88,8 @@ fun ContinuousReader(
|
||||
Unit
|
||||
}
|
||||
is PageMove.Page -> {
|
||||
val (pageNumber) = pageMove
|
||||
if (pageNumber in 0..pages.size) {
|
||||
val pageNumber = pages.indexOf(pageMove.page)
|
||||
if (pageNumber > -1) {
|
||||
state.animateScrollToItem(pageNumber)
|
||||
}
|
||||
}
|
||||
@@ -104,6 +105,7 @@ fun ContinuousReader(
|
||||
LaunchedEffect(state) {
|
||||
snapshotFlow { state.layoutInfo.visibleItemsInfo.lastOrNull()?.index }
|
||||
.filterNotNull()
|
||||
.mapNotNull { pages.getOrNull(it) }
|
||||
.collect(progress)
|
||||
}
|
||||
|
||||
|
||||
@@ -10,6 +10,7 @@ import androidx.compose.foundation.layout.fillMaxSize
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.LaunchedEffect
|
||||
import androidx.compose.runtime.collectAsState
|
||||
import androidx.compose.runtime.rememberUpdatedState
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.layout.ContentScale
|
||||
import ca.gosyer.jui.domain.reader.model.Direction
|
||||
@@ -33,34 +34,36 @@ import kotlinx.coroutines.flow.mapLatest
|
||||
fun PagerReader(
|
||||
parentModifier: Modifier,
|
||||
direction: Direction,
|
||||
currentPage: Int,
|
||||
currentPage: ReaderItem?,
|
||||
pages: ImmutableList<ReaderItem>,
|
||||
loadingModifier: Modifier,
|
||||
pageContentScale: ContentScale,
|
||||
pageEmitterHolder: StableHolder<SharedFlow<PageMove>>,
|
||||
retry: (ReaderPage) -> Unit,
|
||||
progress: (Int) -> Unit
|
||||
progress: (ReaderItem) -> Unit
|
||||
) {
|
||||
val state = rememberPagerState(initialPage = currentPage)
|
||||
val state = rememberPagerState(initialPage = pages.indexOf(currentPage).coerceAtLeast(1))
|
||||
val currentPageState = rememberUpdatedState(currentPage)
|
||||
|
||||
LaunchedEffect(pages.size) {
|
||||
LaunchedEffect(pages.size, state, currentPageState) {
|
||||
val pageRange = 0..(pages.size + 1)
|
||||
pageEmitterHolder.item
|
||||
.mapLatest { pageMove ->
|
||||
when (pageMove) {
|
||||
is PageMove.Direction -> {
|
||||
val (moveTo, currentPage) = pageMove
|
||||
val currentPage = currentPageState.value ?: return@mapLatest
|
||||
val (moveTo) = pageMove
|
||||
val page = when (moveTo) {
|
||||
MoveTo.Previous -> currentPage - 1
|
||||
MoveTo.Next -> currentPage + 1
|
||||
MoveTo.Previous -> pages.indexOf(currentPage) - 1
|
||||
MoveTo.Next -> pages.indexOf(currentPage) + 1
|
||||
}
|
||||
if (page in pageRange) {
|
||||
state.animateScrollToPage(page)
|
||||
}
|
||||
}
|
||||
is PageMove.Page -> {
|
||||
val (pageNumber) = pageMove
|
||||
if (pageNumber in pageRange) {
|
||||
val pageNumber = pages.indexOf(pageMove.page)
|
||||
if (pageNumber > -1) {
|
||||
state.animateScrollToPage(pageNumber)
|
||||
}
|
||||
}
|
||||
@@ -70,8 +73,9 @@ fun PagerReader(
|
||||
}
|
||||
|
||||
LaunchedEffect(state.currentPage) {
|
||||
if (state.currentPage != currentPage) {
|
||||
progress(state.currentPage)
|
||||
val page = pages.getOrNull(state.currentPage)
|
||||
if (page != null) {
|
||||
progress(page)
|
||||
}
|
||||
}
|
||||
val modifier = parentModifier then Modifier.fillMaxSize()
|
||||
|
||||
Reference in New Issue
Block a user