bug fixes after changes

This commit is contained in:
inhale-dir
2024-12-13 15:30:29 +01:00
parent 6e795bd7d1
commit 3295816550
2 changed files with 173 additions and 142 deletions
+28 -1
View File
@@ -36,7 +36,7 @@ Epook is a sleek, modern EPUB reader built for Android using Jetpack Compose. It
- Reading progress persistence - Reading progress persistence
- Organized book collection view - Organized book collection view
### 🔧 Technical Features ### Technical Features
- CSS stylesheet handling - CSS stylesheet handling
- HTML content processing - HTML content processing
- Efficient file management - Efficient file management
@@ -77,3 +77,30 @@ This project is licensed under the MIT License - see the LICENSE file for detail
- [epublib](https://github.com/psiegman/epublib) for EPUB processing - [epublib](https://github.com/psiegman/epublib) for EPUB processing
- [Jsoup](https://jsoup.org/) for HTML parsing - [Jsoup](https://jsoup.org/) for HTML parsing
- [Material Design 3](https://m3.material.io/) for design guidelines - [Material Design 3](https://m3.material.io/) for design guidelines
## 🎨 App Icon Design
### Primary Design
A minimalist, modern book icon featuring:
- A stylized open book in Material Design style
- Primary color: Deep Purple (#6750A4) with white pages
- Subtle gradient background from lighter to darker purple
- Rounded corners following Material Design 3 guidelines
- Clean, simple lines with minimal detail
### Specifications
- Size: 512x512px (Play Store master icon)
- Adaptive Icon Layers:
- Foreground: Book icon in white/light purple
- Background: Gradient from #6750A4 to #4F378B
- Safe zone: 384x384px centered
- Corner radius: 100dp (Material 3 spec)
### Alternative Sizes
- 48x48dp (mdpi)
- 72x72dp (hdpi)
- 96x96dp (xhdpi)
- 144x144dp (xxhdpi)
- 192x192dp (xxxhdpi)
### Design Elements
+145 -141
View File
@@ -50,6 +50,7 @@ import android.webkit.WebResourceRequest
import android.webkit.WebResourceResponse import android.webkit.WebResourceResponse
import android.webkit.WebResourceError import android.webkit.WebResourceError
import android.webkit.WebSettings import android.webkit.WebSettings
import android.view.View
// Move the Chapter data class outside the composable // Move the Chapter data class outside the composable
private data class Chapter( private data class Chapter(
@@ -58,6 +59,9 @@ private data class Chapter(
val resource: Resource val resource: Resource
) )
// First, add a constant for the swipe area height
private const val SWIPE_AREA_HEIGHT = 80 // in dp
@OptIn(ExperimentalMaterial3Api::class) @OptIn(ExperimentalMaterial3Api::class)
@Composable @Composable
fun ReaderScreen( fun ReaderScreen(
@@ -149,130 +153,154 @@ fun ReaderScreen(
} }
} }
Box(modifier = Modifier.fillMaxSize()) { Box(
Box( modifier = Modifier
modifier = Modifier .fillMaxSize()
.fillMaxSize() .background(MaterialTheme.colorScheme.background)
.padding(bottom = if (showControls) 80.dp else 0.dp) ) {
.pointerInput(Unit) { // WebView without swipe gesture
detectTapGestures( AndroidView(
onTap = { showControls = !showControls } factory = { context ->
) WebView(context).apply {
} webViewClient = object : WebViewClient() {
.pointerInput(Unit) { override fun onReceivedError(
var initialX = 0f view: WebView?,
detectHorizontalDragGestures( request: WebResourceRequest?,
onDragStart = { offset -> error: WebResourceError?
initialX = offset.x ) {
}, Timber.e("WebView error loading ${request?.url}: ${error?.description}")
onDragEnd = { super.onReceivedError(view, request, error)
// Implement drag threshold for swipe
val dragThreshold = size.width * 0.2f // 20% of screen width
val dragDistance = initialX - currentX
when {
dragDistance > dragThreshold && currentChapterIndex < chapters.size - 1 -> {
// Swiped left - next chapter
currentChapterIndex++
}
dragDistance < -dragThreshold && currentChapterIndex > 0 -> {
// Swiped right - previous chapter
currentChapterIndex--
}
}
}
) { change, _ ->
currentX = change.position.x
change.consume()
}
}
) {
AndroidView(
factory = { context ->
WebView(context).apply {
webViewClient = object : WebViewClient() {
override fun onReceivedError(
view: WebView?,
request: WebResourceRequest?,
error: WebResourceError?
) {
Timber.e("WebView error loading ${request?.url}: ${error?.description}")
super.onReceivedError(view, request, error)
}
override fun shouldInterceptRequest(
view: WebView?,
request: WebResourceRequest
): WebResourceResponse? {
val url = request.url.toString()
Timber.d("Loading resource: $url")
try {
if (url.endsWith(".css") && extractedPath != null) {
val possiblePaths = listOf(
url.substringAfterLast("/"),
"Styles/${url.substringAfterLast("/")}",
url.substringAfter("/extracted/")
)
for (cssPath in possiblePaths) {
val cssFile = File(extractedPath!!, cssPath)
if (cssFile.exists()) {
Timber.d("Found CSS file at: ${cssFile.absolutePath}")
return WebResourceResponse(
"text/css",
"UTF-8",
cssFile.inputStream()
)
}
}
}
} catch (e: Exception) {
Timber.e(e, "Error intercepting resource request")
}
return super.shouldInterceptRequest(view, request)
}
} }
settings.apply { override fun shouldInterceptRequest(
javaScriptEnabled = true view: WebView?,
builtInZoomControls = true request: WebResourceRequest
displayZoomControls = false ): WebResourceResponse? {
allowFileAccess = true val url = request.url.toString()
@Suppress("DEPRECATION") Timber.d("Loading resource: $url")
allowFileAccessFromFileURLs = true
@Suppress("DEPRECATION")
allowUniversalAccessFromFileURLs = true
mixedContentMode = WebSettings.MIXED_CONTENT_ALWAYS_ALLOW
domStorageEnabled = true
cacheMode = WebSettings.LOAD_DEFAULT
}
}.also { webView = it }
},
update = { view ->
val chapter = chapters.getOrNull(currentChapterIndex)?.resource
chapter?.let { resource ->
scope.launch {
try { try {
extractedPath = bookStore.getBook(bookId)?.extractedPath if (url.endsWith(".css") && extractedPath != null) {
?: throw IllegalStateException("Book not properly extracted") val possiblePaths = listOf(
url.substringAfterLast("/"),
val baseUrl = "file://$extractedPath/" "Styles/${url.substringAfterLast("/")}",
val fullUrl = baseUrl + resource.href.replace("../", "") url.substringAfter("/extracted/")
)
Timber.d("Loading chapter from: $fullUrl")
Timber.d("Base URL: $baseUrl") for (cssPath in possiblePaths) {
val cssFile = File(extractedPath!!, cssPath)
view.loadUrl(fullUrl) if (cssFile.exists()) {
Timber.d("Found CSS file at: ${cssFile.absolutePath}")
return WebResourceResponse(
"text/css",
"UTF-8",
cssFile.inputStream()
)
}
}
}
} catch (e: Exception) { } catch (e: Exception) {
Timber.e(e, "Error loading chapter") Timber.e(e, "Error intercepting resource request")
}
return super.shouldInterceptRequest(view, request)
}
}
settings.apply {
javaScriptEnabled = true
builtInZoomControls = true
displayZoomControls = false
allowFileAccess = true
@Suppress("DEPRECATION")
allowFileAccessFromFileURLs = true
@Suppress("DEPRECATION")
allowUniversalAccessFromFileURLs = true
mixedContentMode = WebSettings.MIXED_CONTENT_ALWAYS_ALLOW
domStorageEnabled = true
cacheMode = WebSettings.LOAD_DEFAULT
// Add these specific scrolling optimizations
@Suppress("DEPRECATION")
setRenderPriority(WebSettings.RenderPriority.HIGH)
// Disable features that might cause stuttering
loadsImagesAutomatically = true
blockNetworkImage = true // Since we're reading locally
blockNetworkLoads = true // Since we're reading locally
// Enable hardware acceleration
setLayerType(View.LAYER_TYPE_HARDWARE, null)
}
// Set better scrolling properties
overScrollMode = View.OVER_SCROLL_NEVER
isVerticalScrollBarEnabled = false // Hide scrollbar for smoother scrolling
// Set scroll sensitivity
@Suppress("DEPRECATION")
setScrollBarStyle(View.SCROLLBARS_INSIDE_OVERLAY)
// Enable smooth scrolling
isScrollContainer = true
// Set better touch handling
isNestedScrollingEnabled = true
}.also { webView = it }
},
update = { view ->
val chapter = chapters.getOrNull(currentChapterIndex)?.resource
chapter?.let { resource ->
scope.launch {
try {
extractedPath = bookStore.getBook(bookId)?.extractedPath
?: throw IllegalStateException("Book not properly extracted")
val baseUrl = "file://$extractedPath/"
val fullUrl = baseUrl + resource.href.replace("../", "")
Timber.d("Loading chapter from: $fullUrl")
Timber.d("Base URL: $baseUrl")
view.loadUrl(fullUrl)
} catch (e: Exception) {
Timber.e(e, "Error loading chapter")
}
}
}
},
modifier = Modifier
.fillMaxSize()
.padding(bottom = if (showControls) SWIPE_AREA_HEIGHT.dp else 0.dp)
)
// Add swipe area at the bottom
Box(
modifier = Modifier
.fillMaxWidth()
.height(SWIPE_AREA_HEIGHT.dp)
.align(Alignment.BottomCenter)
.background(MaterialTheme.colorScheme.surface.copy(alpha = 0.1f))
.pointerInput(Unit) {
detectHorizontalDragGestures { _, dragAmount ->
currentX += dragAmount
when {
currentX > 100 -> {
if (currentChapterIndex > 0) {
currentChapterIndex--
}
currentX = 0f
}
currentX < -100 -> {
if (currentChapterIndex < chapters.size - 1) {
currentChapterIndex++
}
currentX = 0f
} }
} }
} }
}, }
modifier = Modifier.fillMaxSize() )
)
}
// Controls overlay // Controls overlay
AnimatedVisibility( AnimatedVisibility(
@@ -340,30 +368,6 @@ fun ReaderScreen(
} }
} }
} }
// Back button overlay
AnimatedVisibility(
visible = showControls,
enter = fadeIn(),
exit = fadeOut(),
modifier = Modifier
.align(Alignment.TopStart)
.statusBarsPadding()
.padding(8.dp)
) {
IconButton(
onClick = onNavigateBack,
colors = IconButtonDefaults.iconButtonColors(
containerColor = MaterialTheme.colorScheme.surface.copy(alpha = 0.9f),
contentColor = MaterialTheme.colorScheme.onSurface
)
) {
Icon(
imageVector = Icons.AutoMirrored.Filled.ArrowBack,
contentDescription = "Back"
)
}
}
} }
// Chapter list dialog // Chapter list dialog