Fixed lagging in downloads screen, but screen position in the epub remains broken. Updated README.md.

This commit is contained in:
sNice/Python
2026-03-31 09:59:05 -05:00
parent 271651ff02
commit 667d4e1a7b
4 changed files with 64 additions and 28 deletions
@@ -213,7 +213,10 @@ fun DownloadsScreen(
}
}
items(items) { item ->
items(
items = items,
key = { it.absolutePath }
) { item ->
ListItem(
headlineContent = { Text(item.name) },
supportingContent = {
@@ -1,5 +1,6 @@
package net.pythonsden.ao3_.reader
import android.view.ViewTreeObserver
import android.webkit.WebView
import android.webkit.WebViewClient
import androidx.compose.foundation.layout.Box
@@ -19,6 +20,9 @@ import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.collectAsState
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
@@ -74,12 +78,13 @@ fun ReaderScreen(
CircularProgressIndicator(modifier = Modifier.align(Alignment.Center))
}
is ReaderUiState.Success -> {
var hasRestoredScroll by remember(file.absolutePath) { mutableStateOf(false) }
AndroidView(
modifier = Modifier.fillMaxSize(),
factory = { ctx ->
WebView(ctx).apply {
setBackgroundColor(android.graphics.Color.parseColor("#121212"))
// Security: Disable JavaScript for EPUB reading unless strictly needed
settings.javaScriptEnabled = false
settings.allowFileAccess = false
settings.allowContentAccess = false
@@ -87,18 +92,33 @@ fun ReaderScreen(
webViewClient = object : WebViewClient() {
override fun onPageFinished(view: WebView?, url: String?) {
super.onPageFinished(view, url)
if (state.initialScroll > 0) {
// Restore scroll position
if (!hasRestoredScroll && state.initialScroll > 0) {
view?.scrollTo(0, state.initialScroll)
// Multiple attempts to ensure it works after layout
view?.postDelayed({ view.scrollTo(0, state.initialScroll) }, 100)
view?.postDelayed({ view.scrollTo(0, state.initialScroll) }, 300)
}
}
}
val layoutListener = object : ViewTreeObserver.OnGlobalLayoutListener {
override fun onGlobalLayout() {
if (!hasRestoredScroll && state.initialScroll > 0) {
if (contentHeight > 0) {
scrollTo(0, state.initialScroll)
// If we've scrolled to or past the target, or reached bottom
if (scrollY >= state.initialScroll || scrollY > 0) {
hasRestoredScroll = true
}
}
} else if (state.initialScroll == 0) {
hasRestoredScroll = true
}
}
}
viewTreeObserver.addOnGlobalLayoutListener(layoutListener)
setOnScrollChangeListener { _, _, _, scrollY, _ ->
viewModel.saveScrollPosition(file.absolutePath, scrollY)
if (hasRestoredScroll) {
viewModel.saveScrollPosition(file.absolutePath, scrollY)
}
}
}
},
@@ -2,11 +2,13 @@ package net.pythonsden.ao3_.viewmodel
import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.asStateFlow
import kotlinx.coroutines.flow.combine
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
import net.pythonsden.ao3_.data.repository.EpubRepository
import net.pythonsden.ao3_.data.repository.FileRepository
import java.io.File
@@ -46,23 +48,26 @@ class DownloadsViewModel(
}
private suspend fun refreshFiles(dir: File, query: String, sort: SortOrder) {
val allItems = fileRepository.listFiles(dir)
val filtered = if (query.isBlank()) {
allItems
} else {
allItems.filter { it.name.contains(query, ignoreCase = true) }
}
withContext(Dispatchers.Default) {
val allItems = fileRepository.listFiles(dir)
val filtered = if (query.isBlank()) {
allItems
} else {
allItems.filter { it.name.contains(query, ignoreCase = true) }
}
_items.value = filtered.sortedWith { f1, f2 ->
if (f1.isDirectory && !f2.isDirectory) -1
else if (!f1.isDirectory && f2.isDirectory) 1
else {
when (sort) {
SortOrder.NAME -> f1.name.lowercase().compareTo(f2.name.lowercase())
SortOrder.DATE -> f2.lastModified().compareTo(f1.lastModified())
SortOrder.SIZE -> f2.length().compareTo(f1.length())
val sorted = filtered.sortedWith { f1, f2 ->
if (f1.isDirectory && !f2.isDirectory) -1
else if (!f1.isDirectory && f2.isDirectory) 1
else {
when (sort) {
SortOrder.NAME -> f1.name.lowercase().compareTo(f2.name.lowercase())
SortOrder.DATE -> f2.lastModified().compareTo(f1.lastModified())
SortOrder.SIZE -> f2.length().compareTo(f1.length())
}
}
}
_items.value = sorted
}
}