General improvments (#114)
* Add "Keep Screen On" feature to PDF and Epub readers. * Add `rawLibraryFiles` to `MainViewModel` and improve file path resolution in `SharedComposables`. Specifically: - Updated `MainViewModel` state and UI logic to track and provide unfiltered library files. - Enhanced file path formatting in `SharedComposables` to better handle Document, Tree, and primary storage URIs. - Added scrollable support for long text values in `DetailItem` composable. - Passed `rawLibraryFiles` to `FolderSyncScreen` to ensure sync logic uses the base file list. * Update info bar background and text colors in EpubReaderScreen to match the selected theme. * Prevent accidental UI bar toggles immediately after scrolling in EPUB vertical mode. * feat: implement EPUB highlights sync and legacy migration - Implement Cloud and Local Folder sync for EPUB highlights. - Add highlight JSON serialization/deserialization helpers in EpubReaderAnnotations. - Implement automatic migration of highlights from SharedPreferences to the Database on book open. - Add cleanup logic to remove legacy SharedPreferences data after successful DB migration. - Update RecentFilesRepository to trigger local folder metadata sync when highlights are modified. - Update FolderSyncWorker to pull highlights and custom names from linked folder metadata. * Update intent filters
This commit is contained in:
parent
60dacf9c12
commit
4c5cd20b21
17 changed files with 404 additions and 84 deletions
|
|
@ -5,9 +5,7 @@ import android.content.Context
|
|||
import android.graphics.Bitmap
|
||||
import android.net.Uri
|
||||
import android.util.Base64
|
||||
import io.legere.pdfiumandroid.PdfiumCore
|
||||
import io.legere.pdfiumandroid.suspend.PdfDocumentKt
|
||||
import io.legere.pdfiumandroid.suspend.PdfiumCoreKt
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.withContext
|
||||
import timber.log.Timber
|
||||
|
|
@ -219,9 +217,17 @@ object PdfToHtmlGenerator {
|
|||
val c = rawText[i]
|
||||
val code = c.code
|
||||
|
||||
if (code == 0 || code == 13) continue
|
||||
if (code == 0) continue
|
||||
|
||||
if (c == '\r') {
|
||||
commitLine()
|
||||
continue
|
||||
}
|
||||
|
||||
if (c == '\n') {
|
||||
if (i > 0 && rawText[i - 1] == '\r') {
|
||||
continue
|
||||
}
|
||||
commitLine()
|
||||
continue
|
||||
}
|
||||
|
|
@ -292,7 +298,7 @@ object PdfToHtmlGenerator {
|
|||
}
|
||||
|
||||
buildPageHtml(pageNumber, finalElements, headerFooterStrings)
|
||||
} ?: buildEmptyPageSection(pageNumber)
|
||||
}
|
||||
} ?: buildEmptyPageSection(pageNumber)
|
||||
} catch (e: Exception) {
|
||||
Timber.tag(TAG).w(e, "Error extracting page $pageIdx")
|
||||
|
|
@ -339,9 +345,12 @@ object PdfToHtmlGenerator {
|
|||
var inParagraph = false
|
||||
var inUl = false
|
||||
var inOl = false
|
||||
var inLi = false
|
||||
|
||||
fun closeParagraph() { if (inParagraph) { sb.append("</p>\n"); inParagraph = false } }
|
||||
fun closeLi() { if (inLi) { sb.append("</li>\n"); inLi = false } }
|
||||
fun closeList() {
|
||||
closeLi()
|
||||
if (inUl) { sb.append("</ul>\n"); inUl = false }
|
||||
if (inOl) { sb.append("</ol>\n"); inOl = false }
|
||||
}
|
||||
|
|
@ -404,29 +413,40 @@ object PdfToHtmlGenerator {
|
|||
sb.append("<$tag>${renderSpans(line.spans, insideHeading = true)}</$tag>\n")
|
||||
}
|
||||
isBullet -> {
|
||||
closeParagraph()
|
||||
closeParagraph(); closeLi()
|
||||
if (inOl) { sb.append("</ol>\n"); inOl = false }
|
||||
if (!inUl) { sb.append("<ul>\n"); inUl = true }
|
||||
val content = trimmed.removePrefix("•").removePrefix("▪").removePrefix("◦").removePrefix("–").removePrefix("- ").trim()
|
||||
sb.append("<li>${content.escapeHtml()}</li>\n")
|
||||
sb.append("<li>${content.escapeHtml()}")
|
||||
inLi = true
|
||||
}
|
||||
numberedMatch -> {
|
||||
closeParagraph()
|
||||
closeParagraph(); closeLi()
|
||||
if (inUl) { sb.append("</ul>\n"); inUl = false }
|
||||
if (!inOl) { sb.append("<ol>\n"); inOl = true }
|
||||
val content = trimmed.substringAfter(" ").trim()
|
||||
sb.append("<li>${content.escapeHtml()}</li>\n")
|
||||
sb.append("<li>${content.escapeHtml()}")
|
||||
inLi = true
|
||||
}
|
||||
shouldBreakParagraph -> {
|
||||
closeList()
|
||||
if (!inParagraph) { sb.append("<p>"); inParagraph = true }
|
||||
sb.append(renderSpans(line.spans))
|
||||
closeParagraph()
|
||||
if (inLi) {
|
||||
sb.append(" ").append(renderSpans(line.spans))
|
||||
closeLi()
|
||||
} else {
|
||||
closeList()
|
||||
if (!inParagraph) { sb.append("<p>"); inParagraph = true }
|
||||
sb.append(renderSpans(line.spans))
|
||||
closeParagraph()
|
||||
}
|
||||
}
|
||||
else -> {
|
||||
closeList()
|
||||
if (!inParagraph) { sb.append("<p>"); inParagraph = true } else sb.append(" ")
|
||||
sb.append(renderSpans(line.spans))
|
||||
if (inLi) {
|
||||
sb.append(" ").append(renderSpans(line.spans))
|
||||
} else {
|
||||
closeList()
|
||||
if (!inParagraph) { sb.append("<p>"); inParagraph = true } else sb.append(" ")
|
||||
sb.append(renderSpans(line.spans))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -347,6 +347,17 @@ private const val PREF_EXTERNAL_DICT_PKG = "external_dictionary_package"
|
|||
private const val PREF_EXTERNAL_TRANSLATE_PKG = "external_translate_package"
|
||||
private const val PREF_EXTERNAL_SEARCH_PKG = "external_search_package"
|
||||
private const val PDF_THEME_KEY = "pdf_reader_theme"
|
||||
private const val PDF_KEEP_SCREEN_ON_KEY = "pdf_keep_screen_on_enabled"
|
||||
|
||||
private fun saveKeepScreenOn(context: Context, isEnabled: Boolean) {
|
||||
val prefs = context.getSharedPreferences(SETTINGS_PREFS_NAME, Context.MODE_PRIVATE)
|
||||
prefs.edit { putBoolean(PDF_KEEP_SCREEN_ON_KEY, isEnabled) }
|
||||
}
|
||||
|
||||
private fun loadKeepScreenOn(context: Context): Boolean {
|
||||
val prefs = context.getSharedPreferences(SETTINGS_PREFS_NAME, Context.MODE_PRIVATE)
|
||||
return prefs.getBoolean(PDF_KEEP_SCREEN_ON_KEY, false)
|
||||
}
|
||||
|
||||
private fun savePdfThemeId(context: Context, themeId: String) {
|
||||
val prefs = context.getSharedPreferences(SETTINGS_PREFS_NAME, Context.MODE_PRIVATE)
|
||||
|
|
@ -1152,7 +1163,7 @@ fun PdfViewerScreen(
|
|||
?: pdfUri.lastPathSegment ?: "Document.pdf"
|
||||
}
|
||||
}
|
||||
|
||||
val view = LocalView.current
|
||||
var isDockDragging by remember { mutableStateOf(false) }
|
||||
var initialScrollDone by remember { mutableStateOf(false) }
|
||||
|
||||
|
|
@ -1167,6 +1178,14 @@ fun PdfViewerScreen(
|
|||
var isStylusOnlyMode by remember { mutableStateOf(loadStylusOnlyMode(context)) }
|
||||
var currentTtsMode by remember { mutableStateOf(loadTtsMode(context)) }
|
||||
var showTtsSettingsSheet by remember { mutableStateOf(false) }
|
||||
var isKeepScreenOn by remember { mutableStateOf(loadKeepScreenOn(context)) }
|
||||
|
||||
DisposableEffect(isKeepScreenOn) {
|
||||
view.keepScreenOn = isKeepScreenOn
|
||||
onDispose {
|
||||
view.keepScreenOn = false
|
||||
}
|
||||
}
|
||||
|
||||
var showDictionarySettingsSheet by remember { mutableStateOf(false) }
|
||||
var useOnlineDictionary by remember { mutableStateOf(loadUseOnlineDict(context)) }
|
||||
|
|
@ -1338,7 +1357,6 @@ fun PdfViewerScreen(
|
|||
}
|
||||
}
|
||||
|
||||
val view = LocalView.current
|
||||
val window = (view.context as? Activity)?.window
|
||||
LaunchedEffect(isFullScreen) {
|
||||
if (window != null) {
|
||||
|
|
@ -5423,6 +5441,23 @@ fun PdfViewerScreen(
|
|||
}
|
||||
})
|
||||
HorizontalDivider()
|
||||
DropdownMenuItem(
|
||||
text = { Text("Keep Screen On") },
|
||||
onClick = {
|
||||
isKeepScreenOn = !isKeepScreenOn
|
||||
saveKeepScreenOn(context, isKeepScreenOn)
|
||||
showMoreMenu = false
|
||||
},
|
||||
trailingIcon = {
|
||||
if (isKeepScreenOn) {
|
||||
Icon(
|
||||
imageVector = Icons.Filled.Check,
|
||||
contentDescription = "Selected"
|
||||
)
|
||||
}
|
||||
}
|
||||
)
|
||||
HorizontalDivider()
|
||||
DropdownMenuItem(
|
||||
text = { Text("Auto Scroll") },
|
||||
enabled = !isTtsSessionActive && displayMode == DisplayMode.VERTICAL_SCROLL,
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue