🚀 Improve progress display in Reader
* Book and chapter (in "($cp)") progress * Sync chapter & book progress calculation Resolves: #103
This commit is contained in:
parent
2e2dee9e26
commit
7690cafec5
3 changed files with 50 additions and 52 deletions
|
|
@ -168,7 +168,6 @@ fun ReaderScreenRoot(screen: Screen.Reader) {
|
||||||
onLibraryEvent(LibraryEvent.OnUpdateBook(it))
|
onLibraryEvent(LibraryEvent.OnUpdateBook(it))
|
||||||
onHistoryEvent(HistoryEvent.OnUpdateBook(it))
|
onHistoryEvent(HistoryEvent.OnUpdateBook(it))
|
||||||
}
|
}
|
||||||
viewModel.onUpdateCurrentChapter()
|
|
||||||
}
|
}
|
||||||
DisposableEffect(mainState.value.screenOrientation) {
|
DisposableEffect(mainState.value.screenOrientation) {
|
||||||
context.requestedOrientation = mainState.value.screenOrientation.code
|
context.requestedOrientation = mainState.value.screenOrientation.code
|
||||||
|
|
|
||||||
|
|
@ -53,11 +53,23 @@ fun ReaderBottomBar() {
|
||||||
val onLibraryEvent = LocalLibraryViewModel.current.onEvent
|
val onLibraryEvent = LocalLibraryViewModel.current.onEvent
|
||||||
val onHistoryEvent = LocalHistoryViewModel.current.onEvent
|
val onHistoryEvent = LocalHistoryViewModel.current.onEvent
|
||||||
|
|
||||||
|
val bookProgress by remember {
|
||||||
|
derivedStateOf {
|
||||||
|
"${state.value.book.progress.calculateProgress(2)}%"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
val chapterProgress by remember {
|
||||||
|
derivedStateOf {
|
||||||
|
if (state.value.currentChapter == null) return@derivedStateOf ""
|
||||||
|
" (${state.value.currentChapterProgress.calculateProgress(2)}%)"
|
||||||
|
}
|
||||||
|
}
|
||||||
val progress by remember {
|
val progress by remember {
|
||||||
derivedStateOf {
|
derivedStateOf {
|
||||||
"${state.value.book.progress.calculateProgress(4)}%"
|
"$bookProgress$chapterProgress"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
val arrowDirection by remember {
|
val arrowDirection by remember {
|
||||||
derivedStateOf {
|
derivedStateOf {
|
||||||
val checkpoint = state.value.checkpoint.first
|
val checkpoint = state.value.checkpoint.first
|
||||||
|
|
|
||||||
|
|
@ -26,6 +26,7 @@ import kotlinx.coroutines.withContext
|
||||||
import kotlinx.coroutines.yield
|
import kotlinx.coroutines.yield
|
||||||
import ua.acclorite.book_story.R
|
import ua.acclorite.book_story.R
|
||||||
import ua.acclorite.book_story.domain.model.Book
|
import ua.acclorite.book_story.domain.model.Book
|
||||||
|
import ua.acclorite.book_story.domain.model.Chapter
|
||||||
import ua.acclorite.book_story.domain.use_case.book.CheckForTextUpdate
|
import ua.acclorite.book_story.domain.use_case.book.CheckForTextUpdate
|
||||||
import ua.acclorite.book_story.domain.use_case.book.GetBookById
|
import ua.acclorite.book_story.domain.use_case.book.GetBookById
|
||||||
import ua.acclorite.book_story.domain.use_case.book.GetText
|
import ua.acclorite.book_story.domain.use_case.book.GetText
|
||||||
|
|
@ -96,10 +97,13 @@ class ReaderViewModel @Inject constructor(
|
||||||
}.collectLatest { itemsCount ->
|
}.collectLatest { itemsCount ->
|
||||||
if (itemsCount < _state.value.text.size) return@collectLatest
|
if (itemsCount < _state.value.text.size) return@collectLatest
|
||||||
|
|
||||||
|
_state.value.book.apply {
|
||||||
_state.value.listState.requestScrollToItem(
|
_state.value.listState.requestScrollToItem(
|
||||||
_state.value.book.scrollIndex,
|
scrollIndex,
|
||||||
_state.value.book.scrollOffset
|
scrollOffset
|
||||||
)
|
)
|
||||||
|
updateChapter(index = scrollIndex)
|
||||||
|
}
|
||||||
|
|
||||||
event.checkForUpdate()
|
event.checkForUpdate()
|
||||||
|
|
||||||
|
|
@ -564,53 +568,41 @@ class ReaderViewModel @Inject constructor(
|
||||||
fun onUpdateProgress(refreshList: (Book) -> Unit) {
|
fun onUpdateProgress(refreshList: (Book) -> Unit) {
|
||||||
viewModelScope.launch(Dispatchers.Main) {
|
viewModelScope.launch(Dispatchers.Main) {
|
||||||
snapshotFlow {
|
snapshotFlow {
|
||||||
_state.value.listState.firstVisibleItemIndex to _state.value.listState.firstVisibleItemScrollOffset
|
_state.value.listState.run { firstVisibleItemIndex to firstVisibleItemScrollOffset }
|
||||||
}
|
}.distinctUntilChanged().debounce(300).collectLatest { (index, offset) ->
|
||||||
.distinctUntilChanged()
|
val progress = calculateProgress(index)
|
||||||
.debounce(300)
|
if (progress == _state.value.book.progress) return@collectLatest
|
||||||
.collectLatest { (firstVisibleItemIndex, firstVisibleItemOffset) ->
|
val (currentChapter, currentChapterProgress) = calculateCurrentChapter(index)
|
||||||
calculateProgress(firstVisibleItemIndex).apply {
|
|
||||||
if (this == _state.value.book.progress) return@apply
|
|
||||||
|
|
||||||
onEvent(
|
|
||||||
ReaderEvent.OnChangeProgress(
|
|
||||||
progress = this,
|
|
||||||
firstVisibleItemIndex = firstVisibleItemIndex,
|
|
||||||
firstVisibleItemOffset = firstVisibleItemOffset,
|
|
||||||
refreshList = { book ->
|
|
||||||
refreshList(book)
|
|
||||||
}
|
|
||||||
)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@OptIn(FlowPreview::class)
|
|
||||||
fun onUpdateCurrentChapter() {
|
|
||||||
viewModelScope.launch(Dispatchers.Main) {
|
|
||||||
snapshotFlow {
|
|
||||||
_state.value.listState.firstVisibleItemIndex
|
|
||||||
}
|
|
||||||
.distinctUntilChanged()
|
|
||||||
.debounce(300)
|
|
||||||
.collectLatest { index ->
|
|
||||||
if (_state.value.book.chapters.isEmpty()) {
|
|
||||||
_state.update {
|
_state.update {
|
||||||
it.copy(
|
it.copy(
|
||||||
currentChapter = null
|
book = it.book.copy(
|
||||||
|
progress = progress,
|
||||||
|
scrollIndex = index,
|
||||||
|
scrollOffset = offset
|
||||||
|
),
|
||||||
|
currentChapter = currentChapter,
|
||||||
|
currentChapterProgress = currentChapterProgress
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
return@collectLatest
|
|
||||||
}
|
|
||||||
|
|
||||||
updateChapter(index)
|
updateBook.execute(_state.value.book)
|
||||||
|
refreshList(_state.value.book)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun updateChapter(index: Int) {
|
private fun updateChapter(index: Int) {
|
||||||
|
val (currentChapter, currentChapterProgress) = calculateCurrentChapter(index)
|
||||||
|
_state.update {
|
||||||
|
it.copy(
|
||||||
|
currentChapter = currentChapter,
|
||||||
|
currentChapterProgress = currentChapterProgress
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun calculateCurrentChapter(index: Int): Pair<Chapter?, Float> {
|
||||||
val currentChapter = _state.value.book.chapters.find { chapter ->
|
val currentChapter = _state.value.book.chapters.find { chapter ->
|
||||||
index in chapter.startIndex..chapter.endIndex
|
index in chapter.startIndex..chapter.endIndex
|
||||||
}
|
}
|
||||||
|
|
@ -622,12 +614,7 @@ class ReaderViewModel @Inject constructor(
|
||||||
(currentIndex / endIndex.toFloat())
|
(currentIndex / endIndex.toFloat())
|
||||||
}.coerceAndPreventNaN()
|
}.coerceAndPreventNaN()
|
||||||
|
|
||||||
_state.update {
|
return currentChapter to currentChapterProgress
|
||||||
it.copy(
|
|
||||||
currentChapter = currentChapter,
|
|
||||||
currentChapterProgress = currentChapterProgress
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun calculateProgress(firstVisibleItemIndex: Int? = null): Float {
|
private fun calculateProgress(firstVisibleItemIndex: Int? = null): Float {
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue