diff --git a/presentation/src/commonMain/kotlin/ca/gosyer/jui/ui/reader/ReaderMenu.kt b/presentation/src/commonMain/kotlin/ca/gosyer/jui/ui/reader/ReaderMenu.kt index 9410079a..9a102b4e 100644 --- a/presentation/src/commonMain/kotlin/ca/gosyer/jui/ui/reader/ReaderMenu.kt +++ b/presentation/src/commonMain/kotlin/ca/gosyer/jui/ui/reader/ReaderMenu.kt @@ -25,6 +25,7 @@ import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.height import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.layout.widthIn import androidx.compose.material.Icon import androidx.compose.material.IconButton import androidx.compose.material.ModalBottomSheetLayout @@ -64,6 +65,7 @@ import ca.gosyer.jui.ui.base.navigation.Toolbar import ca.gosyer.jui.ui.reader.model.Navigation import ca.gosyer.jui.ui.reader.model.PageMove import ca.gosyer.jui.ui.reader.model.ReaderChapter +import ca.gosyer.jui.ui.reader.model.ReaderItem import ca.gosyer.jui.ui.reader.model.ReaderPage import ca.gosyer.jui.ui.reader.navigation.EdgeNavigation import ca.gosyer.jui.ui.reader.navigation.KindlishNavigation @@ -159,9 +161,7 @@ fun ReaderMenu( BoxWithConstraints { if (maxWidth > 720.dp) { WideReaderMenu( - previousChapter = previousChapter, chapter = chapter, - nextChapter = nextChapter, pages = pages, readerModes = readerModes, readerMode = readerMode, @@ -233,10 +233,8 @@ fun ReaderMenu( @Composable fun WideReaderMenu( - previousChapter: ReaderChapter?, chapter: ReaderChapter, - nextChapter: ReaderChapter?, - pages: ImmutableList, + pages: ImmutableList, readerModes: ImmutableList, readerMode: String, continuous: Boolean, @@ -292,9 +290,6 @@ fun WideReaderMenu( Modifier.padding(start = sideMenuSize).fillMaxSize() ) { ReaderLayout( - previousChapter = previousChapter, - chapter = chapter, - nextChapter = nextChapter, pages = pages, continuous = continuous, direction = direction, @@ -320,7 +315,7 @@ fun ThinReaderMenu( previousChapter: ReaderChapter?, chapter: ReaderChapter, nextChapter: ReaderChapter?, - pages: ImmutableList, + pages: ImmutableList, readerModes: ImmutableList, readerMode: String, continuous: Boolean, @@ -365,9 +360,6 @@ fun ThinReaderMenu( ) { Box { ReaderLayout( - previousChapter = previousChapter, - chapter = chapter, - nextChapter = nextChapter, pages = pages, continuous = continuous, direction = direction, @@ -427,10 +419,7 @@ fun ThinReaderMenu( @Composable fun ReaderLayout( - previousChapter: ReaderChapter?, - chapter: ReaderChapter, - nextChapter: ReaderChapter?, - pages: ImmutableList, + pages: ImmutableList, continuous: Boolean, direction: Direction, padding: Int, @@ -464,9 +453,6 @@ fun ReaderLayout( padding = padding, currentPage = currentPage, currentPageOffset = currentPageOffset, - previousChapter = previousChapter, - currentChapter = chapter, - nextChapter = nextChapter, loadingModifier = loadingModifier, pageContentScale = if (fitSize) { if (direction == Direction.Up || direction == Direction.Down) { @@ -488,9 +474,6 @@ fun ReaderLayout( direction = direction, currentPage = currentPage, pages = pages, - previousChapter = previousChapter, - currentChapter = chapter, - nextChapter = nextChapter, loadingModifier = loadingModifier, pageContentScale = imageScale.toContentScale(), pageEmitterHolder = pageEmitterHolder, diff --git a/presentation/src/commonMain/kotlin/ca/gosyer/jui/ui/reader/ReaderMenuViewModel.kt b/presentation/src/commonMain/kotlin/ca/gosyer/jui/ui/reader/ReaderMenuViewModel.kt index d9ccd67d..586b981d 100644 --- a/presentation/src/commonMain/kotlin/ca/gosyer/jui/ui/reader/ReaderMenuViewModel.kt +++ b/presentation/src/commonMain/kotlin/ca/gosyer/jui/ui/reader/ReaderMenuViewModel.kt @@ -30,7 +30,9 @@ import ca.gosyer.jui.ui.reader.model.MoveTo import ca.gosyer.jui.ui.reader.model.Navigation import ca.gosyer.jui.ui.reader.model.PageMove import ca.gosyer.jui.ui.reader.model.ReaderChapter +import ca.gosyer.jui.ui.reader.model.ReaderItem import ca.gosyer.jui.ui.reader.model.ReaderPage +import ca.gosyer.jui.ui.reader.model.ReaderPageSeparator import ca.gosyer.jui.ui.reader.model.ViewerChapters import ca.gosyer.jui.uicore.prefs.asStateIn import ca.gosyer.jui.uicore.vm.ContextWrapper @@ -89,7 +91,7 @@ class ReaderMenuViewModel @Inject constructor( private val _state = MutableStateFlow(ReaderChapter.State.Wait) val state = _state.asStateFlow() - private val _pages = MutableStateFlow>(persistentListOf()) + private val _pages = MutableStateFlow>(persistentListOf()) val pages = _pages.asStateFlow() private val _currentPage = MutableStateFlow(1) @@ -251,28 +253,28 @@ class ReaderMenuViewModel @Inject constructor( ) val pages = loader.loadChapter(chapter) viewerChapters.currChapter.value = chapter - scope.launchDefault { - val chapters = getChapters.asFlow(mangaId) - .catch { - log.warn(it) { "Error getting chapter list" } - // TODO: 2022-07-01 Error toast - emit(emptyList()) - } - .single() - val nextChapter = chapters.find { it.index == chapterIndex + 1 } - if (nextChapter != null) { - viewerChapters.nextChapter.value = ReaderChapter( - nextChapter - ) - } - val prevChapter = chapters.find { it.index == chapterIndex - 1 } - if (prevChapter != null) { - viewerChapters.prevChapter.value = ReaderChapter( - prevChapter - ) + val chapters = getChapters.asFlow(mangaId) + .catch { + log.warn(it) { "Error getting chapter list" } + // TODO: 2022-07-01 Error toast + emit(emptyList()) } + .single() + + val nextChapter = chapters.find { it.index == chapterIndex + 1 } + if (nextChapter != null) { + viewerChapters.nextChapter.value = ReaderChapter( + nextChapter + ) } + val prevChapter = chapters.find { it.index == chapterIndex - 1 } + if (prevChapter != null) { + viewerChapters.prevChapter.value = ReaderChapter( + prevChapter + ) + } + val lastPageRead = chapter.chapter.lastPageRead if (lastPageRead != 0) { _currentPage.value = lastPageRead.coerceAtMost(chapter.chapter.pageCount!!) @@ -291,14 +293,16 @@ class ReaderMenuViewModel @Inject constructor( pages .filterIsInstance() .onEach { (pageList) -> - _pages.value = pageList.toImmutableList() + 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) } } .launchIn(chapter.scope) _currentPage .onEach { index -> - _pages.value.getOrNull(_currentPage.value - 1)?.let { chapter.pageLoader?.loadPage(it) } + (_pages.value.getOrNull(_currentPage.value - 1) as? ReaderPage)?.let { chapter.pageLoader?.loadPage(it) } if (index == _pages.value.size) { markChapterRead(chapter) } diff --git a/presentation/src/commonMain/kotlin/ca/gosyer/jui/ui/reader/model/ReaderPage.kt b/presentation/src/commonMain/kotlin/ca/gosyer/jui/ui/reader/model/ReaderPage.kt index 071b5c55..5206a898 100644 --- a/presentation/src/commonMain/kotlin/ca/gosyer/jui/ui/reader/model/ReaderPage.kt +++ b/presentation/src/commonMain/kotlin/ca/gosyer/jui/ui/reader/model/ReaderPage.kt @@ -19,7 +19,7 @@ data class ReaderPage( val status: MutableStateFlow, val error: MutableStateFlow, val chapter: ReaderChapter -) { +) : ReaderItem() { enum class Status { QUEUE, WORKING, diff --git a/presentation/src/commonMain/kotlin/ca/gosyer/jui/ui/reader/viewer/Continuous.kt b/presentation/src/commonMain/kotlin/ca/gosyer/jui/ui/reader/viewer/Continuous.kt index b0fb29ef..c2facba1 100644 --- a/presentation/src/commonMain/kotlin/ca/gosyer/jui/ui/reader/viewer/Continuous.kt +++ b/presentation/src/commonMain/kotlin/ca/gosyer/jui/ui/reader/viewer/Continuous.kt @@ -37,8 +37,9 @@ import ca.gosyer.jui.ui.reader.ChapterSeparator import ca.gosyer.jui.ui.reader.ReaderImage import ca.gosyer.jui.ui.reader.model.MoveTo import ca.gosyer.jui.ui.reader.model.PageMove -import ca.gosyer.jui.ui.reader.model.ReaderChapter +import ca.gosyer.jui.ui.reader.model.ReaderItem import ca.gosyer.jui.ui.reader.model.ReaderPage +import ca.gosyer.jui.ui.reader.model.ReaderPageSeparator import ca.gosyer.jui.uicore.components.HorizontalScrollbar import ca.gosyer.jui.uicore.components.VerticalScrollbar import ca.gosyer.jui.uicore.components.rememberScrollbarAdapter @@ -52,15 +53,12 @@ import kotlinx.coroutines.flow.mapLatest @Composable fun ContinuousReader( modifier: Modifier, - pages: ImmutableList, + pages: ImmutableList, direction: Direction, maxSize: Int, padding: Int, currentPage: Int, currentPageOffset: Int, - previousChapter: ReaderChapter?, - currentChapter: ReaderChapter, - nextChapter: ReaderChapter?, loadingModifier: Modifier, pageContentScale: ContentScale, pageEmitterHolder: StableHolder>, @@ -123,7 +121,7 @@ fun ContinuousReader( Direction.Up -> PaddingValues(top = padding.dp) Direction.Down -> PaddingValues(bottom = padding.dp) } - fun retry(index: Int) { pages.find { it.index == index }?.let { retry(it) } } + fun retry(index: Int) { pages.find { it is ReaderPage && it.index == index }?.let { retry(it as ReaderPage) } } when (direction) { Direction.Down, Direction.Up -> { @@ -137,9 +135,6 @@ fun ContinuousReader( modifier = Modifier.fillMaxWidth() .padding(contentPadding), pages = pages, - previousChapter = previousChapter, - currentChapter = currentChapter, - nextChapter = nextChapter, imageModifier = imageModifier, loadingModifier = loadingModifier, pageContentScale = pageContentScale, @@ -165,9 +160,6 @@ fun ContinuousReader( modifier = Modifier.fillMaxHeight() .padding(contentPadding), pages = pages, - previousChapter = previousChapter, - currentChapter = currentChapter, - nextChapter = nextChapter, imageModifier = imageModifier, loadingModifier = loadingModifier, pageContentScale = pageContentScale, @@ -187,34 +179,36 @@ fun ContinuousReader( private fun LazyListScope.items( modifier: Modifier, - pages: ImmutableList, - previousChapter: ReaderChapter?, - currentChapter: ReaderChapter, - nextChapter: ReaderChapter?, + pages: ImmutableList, imageModifier: Modifier, loadingModifier: Modifier, pageContentScale: ContentScale, retry: (Int) -> Unit ) { - item { - ChapterSeparator(previousChapter, currentChapter) - } - items(pages) { image -> - Box(modifier, contentAlignment = Alignment.Center) { - ReaderImage( - imageIndex = image.index, - drawableHolder = image.bitmap.collectAsState().value, - progress = image.progress.collectAsState().value, - status = image.status.collectAsState().value, - error = image.error.collectAsState().value, - imageModifier = imageModifier, - loadingModifier = loadingModifier, - contentScale = pageContentScale, - retry = retry - ) + items( + pages, + key = { + when (it) { + is ReaderPage -> it.chapter.chapter.index to it.index + is ReaderPageSeparator -> it.previousChapter?.chapter?.index to it.nextChapter?.chapter?.index + } + } + ) { image -> + when (image) { + is ReaderPage -> Box(modifier, contentAlignment = Alignment.Center) { + ReaderImage( + imageIndex = image.index, + drawableHolder = image.bitmap.collectAsState().value, + progress = image.progress.collectAsState().value, + status = image.status.collectAsState().value, + error = image.error.collectAsState().value, + imageModifier = imageModifier, + loadingModifier = loadingModifier, + contentScale = pageContentScale, + retry = retry + ) + } + is ReaderPageSeparator -> ChapterSeparator(previousChapter = image.previousChapter, nextChapter = image.nextChapter) } } - item { - ChapterSeparator(previousChapter = currentChapter, nextChapter = nextChapter) - } } diff --git a/presentation/src/commonMain/kotlin/ca/gosyer/jui/ui/reader/viewer/Pager.kt b/presentation/src/commonMain/kotlin/ca/gosyer/jui/ui/reader/viewer/Pager.kt index be966f14..da121411 100644 --- a/presentation/src/commonMain/kotlin/ca/gosyer/jui/ui/reader/viewer/Pager.kt +++ b/presentation/src/commonMain/kotlin/ca/gosyer/jui/ui/reader/viewer/Pager.kt @@ -18,8 +18,9 @@ import ca.gosyer.jui.ui.reader.ChapterSeparator import ca.gosyer.jui.ui.reader.ReaderImage import ca.gosyer.jui.ui.reader.model.MoveTo import ca.gosyer.jui.ui.reader.model.PageMove -import ca.gosyer.jui.ui.reader.model.ReaderChapter +import ca.gosyer.jui.ui.reader.model.ReaderItem import ca.gosyer.jui.ui.reader.model.ReaderPage +import ca.gosyer.jui.ui.reader.model.ReaderPageSeparator import com.google.accompanist.pager.HorizontalPager import com.google.accompanist.pager.VerticalPager import com.google.accompanist.pager.rememberPagerState @@ -33,10 +34,7 @@ fun PagerReader( parentModifier: Modifier, direction: Direction, currentPage: Int, - pages: ImmutableList, - previousChapter: ReaderChapter?, - currentChapter: ReaderChapter, - nextChapter: ReaderChapter?, + pages: ImmutableList, loadingModifier: Modifier, pageContentScale: ContentScale, pageEmitterHolder: StableHolder>, @@ -77,11 +75,11 @@ fun PagerReader( } } val modifier = parentModifier then Modifier.fillMaxSize() - fun retry(index: Int) { pages.find { it.index == index }?.let { retry(it) } } + fun retry(index: Int) { pages.find { it is ReaderPage && it.index == index }?.let { retry(it as ReaderPage) } } if (direction == Direction.Down || direction == Direction.Up) { VerticalPager( - count = pages.size + 2, + count = pages.size, state = state, reverseLayout = direction == Direction.Up, modifier = modifier @@ -89,9 +87,6 @@ fun PagerReader( HandlePager( pages = pages, page = it, - previousChapter = previousChapter, - currentChapter = currentChapter, - nextChapter = nextChapter, loadingModifier = loadingModifier, pageContentScale = pageContentScale, retry = ::retry @@ -99,7 +94,7 @@ fun PagerReader( } } else { HorizontalPager( - count = pages.size + 2, + count = pages.size, state = state, reverseLayout = direction == Direction.Left, modifier = modifier @@ -107,9 +102,6 @@ fun PagerReader( HandlePager( pages = pages, page = it, - previousChapter = previousChapter, - currentChapter = currentChapter, - nextChapter = nextChapter, loadingModifier = loadingModifier, pageContentScale = pageContentScale, retry = ::retry @@ -120,20 +112,14 @@ fun PagerReader( @Composable fun HandlePager( - pages: ImmutableList, + pages: ImmutableList, page: Int, - previousChapter: ReaderChapter?, - currentChapter: ReaderChapter, - nextChapter: ReaderChapter?, loadingModifier: Modifier, pageContentScale: ContentScale, retry: (Int) -> Unit ) { - when (page) { - 0 -> ChapterSeparator(previousChapter, currentChapter) - pages.size + 1 -> ChapterSeparator(currentChapter, nextChapter) - else -> { - val image = pages[page - 1] + when (val image = pages[page]) { + is ReaderPage -> { ReaderImage( imageIndex = image.index, drawableHolder = image.bitmap.collectAsState().value, @@ -145,5 +131,6 @@ fun HandlePager( contentScale = pageContentScale ) } + is ReaderPageSeparator -> ChapterSeparator(image.previousChapter, image.nextChapter) } }