From fb6403c4a9bb639a6693972d736e1f27e31c7e3a Mon Sep 17 00:00:00 2001 From: Atte149 Date: Wed, 24 Jun 2026 18:08:00 +0300 Subject: [PATCH] =?UTF-8?q?feat(phase5):=20reader=20engine=20integration?= =?UTF-8?q?=20=E2=80=94=20Checkpoint=20model=20+=20ChapterDrawer?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Checkpoint: serializable model for reading position (bookId, chapterIndex, pageIndex, scrollOffset, progress, timestamp). - ChapterDrawer: ModalBottomSheet with chapter list, current chapter indicator, progress percentage. - Volume keys and chapter navigation already present in EpubReaderScreen/PdfViewerScreen. - ':app:assembleOssDebug' passes. --- .../bookreader/reader/ChapterDrawer.kt | 95 +++++++++++++++++++ .../bookreader/reader/Checkpoint.kt | 13 +++ 2 files changed, 108 insertions(+) create mode 100644 app/src/main/java/org/dueattendant149/bookreader/reader/ChapterDrawer.kt create mode 100644 app/src/main/java/org/dueattendant149/bookreader/reader/Checkpoint.kt diff --git a/app/src/main/java/org/dueattendant149/bookreader/reader/ChapterDrawer.kt b/app/src/main/java/org/dueattendant149/bookreader/reader/ChapterDrawer.kt new file mode 100644 index 0000000..7d8b08f --- /dev/null +++ b/app/src/main/java/org/dueattendant149/bookreader/reader/ChapterDrawer.kt @@ -0,0 +1,95 @@ +package org.dueattendant149.bookreader.reader + +import androidx.compose.foundation.clickable +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.Row +import androidx.compose.foundation.layout.Spacer +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.height +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.layout.width +import androidx.compose.foundation.lazy.LazyColumn +import androidx.compose.foundation.lazy.itemsIndexed +import androidx.compose.material.icons.Icons +import androidx.compose.material.icons.automirrored.filled.ArrowBack +import androidx.compose.material3.ExperimentalMaterial3Api +import androidx.compose.material3.Icon +import androidx.compose.material3.IconButton +import androidx.compose.material3.MaterialTheme +import androidx.compose.material3.ModalBottomSheet +import androidx.compose.material3.Text +import androidx.compose.material3.TopAppBar +import androidx.compose.material3.rememberModalBottomSheetState +import androidx.compose.runtime.Composable +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.text.style.TextOverflow +import androidx.compose.ui.unit.dp + +data class ChapterItem( + val title: String, + val pageIndex: Int, + val progress: Float = 0f, +) + +@OptIn(ExperimentalMaterial3Api::class) +@Composable +fun ChapterDrawer( + chapters: List, + currentChapterIndex: Int, + onChapterSelected: (Int) -> Unit, + onDismiss: () -> Unit, +) { + val sheetState = rememberModalBottomSheetState(skipPartiallyExpanded = true) + + ModalBottomSheet( + onDismissRequest = onDismiss, + sheetState = sheetState, + ) { + Column(modifier = Modifier.padding(16.dp)) { + Text( + text = "Chapters", + style = MaterialTheme.typography.titleLarge, + modifier = Modifier.padding(bottom = 12.dp) + ) + + LazyColumn { + itemsIndexed(chapters) { index, chapter -> + val isCurrent = index == currentChapterIndex + Row( + modifier = Modifier + .fillMaxWidth() + .clickable { onChapterSelected(index) } + .padding(vertical = 12.dp, horizontal = 4.dp), + verticalAlignment = Alignment.CenterVertically + ) { + Column(modifier = Modifier.weight(1f)) { + Text( + text = chapter.title, + style = if (isCurrent) MaterialTheme.typography.titleMedium + else MaterialTheme.typography.bodyMedium, + color = if (isCurrent) MaterialTheme.colorScheme.primary + else MaterialTheme.colorScheme.onSurface, + maxLines = 1, + overflow = TextOverflow.Ellipsis + ) + Text( + text = "${(chapter.progress * 100).toInt()}%", + style = MaterialTheme.typography.bodySmall, + color = MaterialTheme.colorScheme.onSurfaceVariant + ) + } + if (isCurrent) { + Spacer(modifier = Modifier.width(8.dp)) + Text( + text = "●", + color = MaterialTheme.colorScheme.primary, + style = MaterialTheme.typography.bodySmall + ) + } + } + } + } + } + } +} \ No newline at end of file diff --git a/app/src/main/java/org/dueattendant149/bookreader/reader/Checkpoint.kt b/app/src/main/java/org/dueattendant149/bookreader/reader/Checkpoint.kt new file mode 100644 index 0000000..30c2016 --- /dev/null +++ b/app/src/main/java/org/dueattendant149/bookreader/reader/Checkpoint.kt @@ -0,0 +1,13 @@ +package org.dueattendant149.bookreader.reader + +import kotlinx.serialization.Serializable + +@Serializable +data class Checkpoint( + val bookId: String, + val chapterIndex: Int = 0, + val pageIndex: Int = 0, + val scrollOffset: Int = 0, + val progress: Float = 0f, + val timestamp: Long = System.currentTimeMillis(), +)