1.2 Beta last state !!!
This commit is contained in:
parent
d632e7ac0d
commit
dc2a67ac0d
@ -40,6 +40,13 @@ import kotlinx.coroutines.flow.Flow
|
||||
import inhale.rip.epook.data.Book
|
||||
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)
|
||||
@Composable
|
||||
fun ReaderScreen(
|
||||
@ -53,7 +60,7 @@ fun ReaderScreen(
|
||||
var currentSettings by remember { mutableStateOf(Settings()) }
|
||||
|
||||
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 showControls by remember { mutableStateOf(true) }
|
||||
@ -62,6 +69,9 @@ fun ReaderScreen(
|
||||
val backgroundColor = MaterialTheme.colorScheme.background.toArgb()
|
||||
val textColor = MaterialTheme.colorScheme.onBackground.toArgb()
|
||||
|
||||
// Add state for reading position
|
||||
var currentReadingPosition by remember { mutableStateOf(0) }
|
||||
|
||||
LaunchedEffect(Unit) {
|
||||
try {
|
||||
currentSettings = settingsStore.getSettings()
|
||||
@ -72,17 +82,62 @@ fun ReaderScreen(
|
||||
|
||||
LaunchedEffect(bookId) {
|
||||
try {
|
||||
currentChapterIndex = bookStore.getReadingPosition(bookId).first()
|
||||
val bookPath = bookStore.getBookPath(bookId)
|
||||
val epubBook = EpubReader().readEpub(FileInputStream(bookPath))
|
||||
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) {
|
||||
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(
|
||||
topBar = {
|
||||
AnimatedVisibility(
|
||||
@ -149,28 +204,30 @@ fun ReaderScreen(
|
||||
}
|
||||
},
|
||||
update = { webView ->
|
||||
val chapter = chapters[currentChapterIndex]
|
||||
val html = """
|
||||
<html>
|
||||
<head>
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<style>
|
||||
body {
|
||||
font-family: ${currentSettings.fontFamily};
|
||||
line-height: ${currentSettings.lineHeight};
|
||||
padding: ${currentSettings.padding}px;
|
||||
margin: 0;
|
||||
background-color: #${backgroundColor.toString(16)};
|
||||
color: #${textColor.toString(16)};
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
${String(chapter.data, Charset.defaultCharset())}
|
||||
</body>
|
||||
</html>
|
||||
""".trimIndent()
|
||||
webView.loadDataWithBaseURL(null, html, "text/html", "UTF-8", null)
|
||||
val chapter = chapters.getOrNull(currentChapterIndex)?.resource
|
||||
chapter?.let { resource ->
|
||||
val html = """
|
||||
<html>
|
||||
<head>
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<style>
|
||||
body {
|
||||
font-family: ${currentSettings.fontFamily};
|
||||
line-height: ${currentSettings.lineHeight};
|
||||
padding: ${currentSettings.padding}px;
|
||||
margin: 0;
|
||||
background-color: #${backgroundColor.toString(16)};
|
||||
color: #${textColor.toString(16)};
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
${String(resource.data, Charset.defaultCharset())}
|
||||
</body>
|
||||
</html>
|
||||
""".trimIndent()
|
||||
webView.loadDataWithBaseURL(null, html, "text/html", "UTF-8", null)
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
||||
@ -224,31 +281,33 @@ fun ReaderScreen(
|
||||
if (showChapterList) {
|
||||
AlertDialog(
|
||||
onDismissRequest = { showChapterList = false },
|
||||
title = { Text("Chapters") },
|
||||
title = { Text("Table of Contents") },
|
||||
text = {
|
||||
LazyColumn {
|
||||
items(
|
||||
items = List(chapters.size) { it },
|
||||
key = { it }
|
||||
) { index ->
|
||||
items = chapters,
|
||||
key = { chapter: Chapter -> chapter.index }
|
||||
) { chapter ->
|
||||
ListItem(
|
||||
headlineContent = {
|
||||
Text("Chapter ${index + 1}")
|
||||
Text(
|
||||
text = chapter.title,
|
||||
maxLines = 2,
|
||||
overflow = TextOverflow.Ellipsis
|
||||
)
|
||||
},
|
||||
modifier = Modifier.clickable {
|
||||
currentChapterIndex = index
|
||||
currentChapterIndex = chapter.index
|
||||
showChapterList = false
|
||||
},
|
||||
leadingContent = if (currentChapterIndex == index) {
|
||||
{
|
||||
leadingContent = {
|
||||
if (currentChapterIndex == chapter.index) {
|
||||
Icon(
|
||||
Icons.Default.RadioButtonChecked,
|
||||
contentDescription = null,
|
||||
tint = MaterialTheme.colorScheme.primary
|
||||
)
|
||||
}
|
||||
} else {
|
||||
{
|
||||
} else {
|
||||
Icon(
|
||||
Icons.Default.RadioButtonUnchecked,
|
||||
contentDescription = null
|
||||
|
||||
@ -12,6 +12,7 @@ import android.util.Log
|
||||
import nl.siegmann.epublib.domain.Book as EpubBook
|
||||
import nl.siegmann.epublib.epub.EpubReader
|
||||
import java.io.FileInputStream
|
||||
import timber.log.Timber
|
||||
|
||||
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) {
|
||||
bookDao.updateReadingPosition(bookId, position)
|
||||
try {
|
||||
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> {
|
||||
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) {
|
||||
Log.e(TAG, "🔥 DELETE BOOK STARTED 🔥")
|
||||
Log.e(TAG, "Attempting to delete book with ID: $bookId")
|
||||
|
||||
Loading…
Reference in New Issue
Block a user