1.2 Beta last state !!!

This commit is contained in:
inhale-dir
2024-12-13 13:11:17 +01:00
parent d632e7ac0d
commit dc2a67ac0d
2 changed files with 112 additions and 37 deletions
@@ -40,6 +40,13 @@ import kotlinx.coroutines.flow.Flow
import inhale.rip.epook.data.Book import inhale.rip.epook.data.Book
import nl.siegmann.epublib.domain.Book as EpubBook import nl.siegmann.epublib.domain.Book as EpubBook
// Move the Chapter data class outside the composable
private data class Chapter(
val index: Int,
val title: String,
val resource: Resource
)
@OptIn(ExperimentalMaterial3Api::class) @OptIn(ExperimentalMaterial3Api::class)
@Composable @Composable
fun ReaderScreen( fun ReaderScreen(
@@ -53,7 +60,7 @@ fun ReaderScreen(
var currentSettings by remember { mutableStateOf(Settings()) } var currentSettings by remember { mutableStateOf(Settings()) }
var currentChapterIndex by remember { mutableStateOf(0) } var currentChapterIndex by remember { mutableStateOf(0) }
var chapters by remember { mutableStateOf(listOf<Resource>()) } var chapters by remember { mutableStateOf<List<Chapter>>(emptyList()) }
var book by remember { mutableStateOf<EpubBook?>(null) } var book by remember { mutableStateOf<EpubBook?>(null) }
var showControls by remember { mutableStateOf(true) } var showControls by remember { mutableStateOf(true) }
@@ -62,6 +69,9 @@ fun ReaderScreen(
val backgroundColor = MaterialTheme.colorScheme.background.toArgb() val backgroundColor = MaterialTheme.colorScheme.background.toArgb()
val textColor = MaterialTheme.colorScheme.onBackground.toArgb() val textColor = MaterialTheme.colorScheme.onBackground.toArgb()
// Add state for reading position
var currentReadingPosition by remember { mutableStateOf(0) }
LaunchedEffect(Unit) { LaunchedEffect(Unit) {
try { try {
currentSettings = settingsStore.getSettings() currentSettings = settingsStore.getSettings()
@@ -72,17 +82,62 @@ fun ReaderScreen(
LaunchedEffect(bookId) { LaunchedEffect(bookId) {
try { try {
currentChapterIndex = bookStore.getReadingPosition(bookId).first()
val bookPath = bookStore.getBookPath(bookId) val bookPath = bookStore.getBookPath(bookId)
val epubBook = EpubReader().readEpub(FileInputStream(bookPath)) val epubBook = EpubReader().readEpub(FileInputStream(bookPath))
book = epubBook book = epubBook
chapters = epubBook.spine.spineReferences.mapNotNull { spineRef: nl.siegmann.epublib.domain.SpineReference ->
spineRef.resource // Extract chapters with titles
chapters = epubBook.spine.spineReferences.mapIndexed { index, spineRef ->
val resource = spineRef.resource
val title = when {
// Try to get title from TOC
epubBook.tableOfContents.allUniqueResources.contains(resource) -> {
epubBook.tableOfContents.allUniqueResources
.find { it == resource }
?.title ?: "Chapter ${index + 1}"
}
// Try to parse HTML for title
resource.mediaType.toString().contains("html") -> {
try {
val html = String(resource.data, Charset.defaultCharset())
val doc = Jsoup.parse(html)
doc.select("h1, h2, h3, title").firstOrNull()?.text()
?: "Chapter ${index + 1}"
} catch (e: Exception) {
"Chapter ${index + 1}"
}
}
else -> "Chapter ${index + 1}"
}
Chapter(index, title, resource)
} }
} catch (e: Exception) { } catch (e: Exception) {
Timber.e(e, "Error loading book") Timber.e(e, "Error loading book")
} }
} }
// Save position when chapter changes
LaunchedEffect(currentChapterIndex) {
try {
bookStore.updateReadingPosition(bookId, currentChapterIndex)
} catch (e: Exception) {
Timber.e(e, "Error saving reading position")
}
}
// Handle back button to save position before leaving
BackHandler {
scope.launch {
try {
bookStore.updateReadingPosition(bookId, currentChapterIndex)
} catch (e: Exception) {
Timber.e(e, "Error saving reading position on exit")
}
onNavigateBack()
}
}
Scaffold( Scaffold(
topBar = { topBar = {
AnimatedVisibility( AnimatedVisibility(
@@ -149,7 +204,8 @@ fun ReaderScreen(
} }
}, },
update = { webView -> update = { webView ->
val chapter = chapters[currentChapterIndex] val chapter = chapters.getOrNull(currentChapterIndex)?.resource
chapter?.let { resource ->
val html = """ val html = """
<html> <html>
<head> <head>
@@ -166,12 +222,13 @@ fun ReaderScreen(
</style> </style>
</head> </head>
<body> <body>
${String(chapter.data, Charset.defaultCharset())} ${String(resource.data, Charset.defaultCharset())}
</body> </body>
</html> </html>
""".trimIndent() """.trimIndent()
webView.loadDataWithBaseURL(null, html, "text/html", "UTF-8", null) webView.loadDataWithBaseURL(null, html, "text/html", "UTF-8", null)
} }
}
) )
} }
@@ -224,31 +281,33 @@ fun ReaderScreen(
if (showChapterList) { if (showChapterList) {
AlertDialog( AlertDialog(
onDismissRequest = { showChapterList = false }, onDismissRequest = { showChapterList = false },
title = { Text("Chapters") }, title = { Text("Table of Contents") },
text = { text = {
LazyColumn { LazyColumn {
items( items(
items = List(chapters.size) { it }, items = chapters,
key = { it } key = { chapter: Chapter -> chapter.index }
) { index -> ) { chapter ->
ListItem( ListItem(
headlineContent = { headlineContent = {
Text("Chapter ${index + 1}") Text(
text = chapter.title,
maxLines = 2,
overflow = TextOverflow.Ellipsis
)
}, },
modifier = Modifier.clickable { modifier = Modifier.clickable {
currentChapterIndex = index currentChapterIndex = chapter.index
showChapterList = false showChapterList = false
}, },
leadingContent = if (currentChapterIndex == index) { leadingContent = {
{ if (currentChapterIndex == chapter.index) {
Icon( Icon(
Icons.Default.RadioButtonChecked, Icons.Default.RadioButtonChecked,
contentDescription = null, contentDescription = null,
tint = MaterialTheme.colorScheme.primary tint = MaterialTheme.colorScheme.primary
) )
}
} else { } else {
{
Icon( Icon(
Icons.Default.RadioButtonUnchecked, Icons.Default.RadioButtonUnchecked,
contentDescription = null contentDescription = null
@@ -12,6 +12,7 @@ import android.util.Log
import nl.siegmann.epublib.domain.Book as EpubBook import nl.siegmann.epublib.domain.Book as EpubBook
import nl.siegmann.epublib.epub.EpubReader import nl.siegmann.epublib.epub.EpubReader
import java.io.FileInputStream import java.io.FileInputStream
import timber.log.Timber
private val Context.dataStore: DataStore<Preferences> by preferencesDataStore(name = "books") private val Context.dataStore: DataStore<Preferences> by preferencesDataStore(name = "books")
@@ -35,13 +36,28 @@ class BookStore(private val context: Context) {
} }
suspend fun updateReadingPosition(bookId: String, position: Int) { suspend fun updateReadingPosition(bookId: String, position: Int) {
try {
bookDao.updateReadingPosition(bookId, position) bookDao.updateReadingPosition(bookId, position)
Timber.d("Updated reading position for book $bookId to $position")
} catch (e: Exception) {
Timber.e(e, "Failed to update reading position")
throw e
}
} }
fun getReadingPosition(bookId: String): Flow<Int> { fun getReadingPosition(bookId: String): Flow<Int> {
return bookDao.getBookPosition(bookId) return bookDao.getBookPosition(bookId)
} }
suspend fun getInitialReadingPosition(bookId: String): Int {
return try {
bookDao.getBook(bookId)?.readingPosition ?: 0
} catch (e: Exception) {
Timber.e(e, "Failed to get initial reading position")
0
}
}
suspend fun deleteBook(bookId: String) { suspend fun deleteBook(bookId: String) {
Log.e(TAG, "🔥 DELETE BOOK STARTED 🔥") Log.e(TAG, "🔥 DELETE BOOK STARTED 🔥")
Log.e(TAG, "Attempting to delete book with ID: $bookId") Log.e(TAG, "Attempting to delete book with ID: $bookId")