Improve separation of current chapter from UI

This commit is contained in:
Syer10
2022-12-27 20:06:52 -05:00
parent 055a517457
commit 4f20c6aa55
6 changed files with 79 additions and 51 deletions

View File

@@ -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)

View File

@@ -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() {

View File

@@ -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) }

View File

@@ -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()
}

View File

@@ -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)
}

View File

@@ -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()