Crash fixes (#38)
* Updated animation specifications for UI controls and overlays to use a 200ms tween duration. * Implemented fallback file picker and improved CSS rule merging efficiency to fix OOM.
This commit is contained in:
parent
77a09c545f
commit
3a31e4fc7b
7 changed files with 133 additions and 58 deletions
|
|
@ -53,29 +53,52 @@ class LocatorConverter(
|
|||
try {
|
||||
val chapter = book.chapters.getOrNull(chapterIndex) ?: return@withContext null
|
||||
|
||||
// 1. Parse CSS from the book
|
||||
var parsingCssRules = OptimizedCssRules()
|
||||
val mergedByTag = mutableMapOf<String, MutableList<CssRule>>()
|
||||
val mergedByClass = mutableMapOf<String, MutableList<CssRule>>()
|
||||
val mergedById = mutableMapOf<String, MutableList<CssRule>>()
|
||||
val mergedOtherComplex = mutableListOf<CssRule>()
|
||||
|
||||
val density = Density(context)
|
||||
val displayMetrics = context.resources.displayMetrics
|
||||
val constraints = Constraints(maxWidth = displayMetrics.widthPixels, maxHeight = displayMetrics.heightPixels)
|
||||
|
||||
fun aggregateRules(
|
||||
target: MutableMap<String, MutableList<CssRule>>,
|
||||
source: Map<String, List<CssRule>>
|
||||
) {
|
||||
source.forEach { (k, v) ->
|
||||
target.getOrPut(k) { mutableListOf() }.addAll(v)
|
||||
}
|
||||
}
|
||||
|
||||
book.css.forEach { (path, content) ->
|
||||
val bookCssResult = CssParser.parse(
|
||||
cssContent = content,
|
||||
cssPath = path,
|
||||
baseFontSizeSp = 16f, // A reasonable default for non-rendering parsing
|
||||
baseFontSizeSp = 16f,
|
||||
density = density.density,
|
||||
constraints = constraints,
|
||||
isDarkTheme = false
|
||||
)
|
||||
parsingCssRules = parsingCssRules.merge(bookCssResult.rules)
|
||||
|
||||
val rules = bookCssResult.rules
|
||||
aggregateRules(mergedByTag, rules.byTag)
|
||||
aggregateRules(mergedByClass, rules.byClass)
|
||||
aggregateRules(mergedById, rules.byId)
|
||||
mergedOtherComplex.addAll(rules.otherComplex)
|
||||
}
|
||||
|
||||
// 2. Parse HTML to SemanticBlocks
|
||||
val parsingCssRules = OptimizedCssRules(
|
||||
byTag = mergedByTag,
|
||||
byClass = mergedByClass,
|
||||
byId = mergedById,
|
||||
otherComplex = mergedOtherComplex
|
||||
)
|
||||
|
||||
val semanticBlocks = htmlToSemanticBlocks(
|
||||
html = chapter.htmlContent,
|
||||
cssRules = parsingCssRules,
|
||||
textStyle = TextStyle(), // Not used for rendering, so a default is fine
|
||||
textStyle = TextStyle(),
|
||||
chapterAbsPath = chapter.absPath,
|
||||
extractionBasePath = book.extractionBasePath,
|
||||
density = density,
|
||||
|
|
@ -83,13 +106,12 @@ class LocatorConverter(
|
|||
constraints = constraints
|
||||
)
|
||||
|
||||
// 3. Serialize and cache the result
|
||||
val protoBytes = proto.encodeToByteArray(semanticBlocks)
|
||||
val newCacheEntry = ProcessedChapter(
|
||||
bookId = book.title,
|
||||
chapterIndex = chapterIndex,
|
||||
contentBlocksProto = protoBytes,
|
||||
estimatedPageCount = 0 // Page count is not relevant for locator conversion
|
||||
estimatedPageCount = 0
|
||||
)
|
||||
bookCacheDao.insertProcessedChapters(listOf(newCacheEntry))
|
||||
Timber.i("On-demand processing SUCCESS for chapter $chapterIndex.")
|
||||
|
|
|
|||
|
|
@ -354,21 +354,31 @@ data class OptimizedCssRules(
|
|||
@ProtoNumber(4) val otherComplex: List<CssRule> = emptyList()
|
||||
) {
|
||||
fun merge(other: OptimizedCssRules): OptimizedCssRules {
|
||||
val mergedByTag = (this.byTag.asSequence() + other.byTag.asSequence())
|
||||
.groupBy({ it.key }, { it.value })
|
||||
.mapValues { (_, values) -> values.flatten() }
|
||||
fun mergeMap(
|
||||
m1: Map<String, List<CssRule>>,
|
||||
m2: Map<String, List<CssRule>>
|
||||
): Map<String, List<CssRule>> {
|
||||
if (m1.isEmpty()) return m2
|
||||
if (m2.isEmpty()) return m1
|
||||
|
||||
val mergedByClass = (this.byClass.asSequence() + other.byClass.asSequence())
|
||||
.groupBy({ it.key }, { it.value })
|
||||
.mapValues { (_, values) -> values.flatten() }
|
||||
val result = LinkedHashMap(m1)
|
||||
for ((key, value) in m2) {
|
||||
val existing = result[key]
|
||||
if (existing != null) {
|
||||
result[key] = existing + value
|
||||
} else {
|
||||
result[key] = value
|
||||
}
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
val mergedById = (this.byId.asSequence() + other.byId.asSequence())
|
||||
.groupBy({ it.key }, { it.value })
|
||||
.mapValues { (_, values) -> values.flatten() }
|
||||
|
||||
val mergedOtherComplex = this.otherComplex + other.otherComplex
|
||||
|
||||
return OptimizedCssRules(mergedByTag, mergedByClass, mergedById, mergedOtherComplex)
|
||||
return OptimizedCssRules(
|
||||
byTag = mergeMap(this.byTag, other.byTag),
|
||||
byClass = mergeMap(this.byClass, other.byClass),
|
||||
byId = mergeMap(this.byId, other.byId),
|
||||
otherComplex = this.otherComplex + other.otherComplex
|
||||
)
|
||||
}
|
||||
|
||||
fun toFlatList(): List<CssRule> {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue