From 3388e45c4e83b913aa9b5f0803a0300f21bcf150 Mon Sep 17 00:00:00 2001 From: Kelvin Sande <98394184+sande11@users.noreply.github.com> Date: Thu, 13 Nov 2025 16:20:16 +0200 Subject: [PATCH 1/3] Comment out onZoomOut() call in WebView setup The onZoomOut() method call in setupWebView was commented out, to prevent automatic zooming behavior which was causing conflicts in font size persistence and causing content to be pushed to the left of the screen --- .../apphatchery/gatbreferenceguide/ui/fragments/BodyFragment.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/src/main/java/org/apphatchery/gatbreferenceguide/ui/fragments/BodyFragment.kt b/app/src/main/java/org/apphatchery/gatbreferenceguide/ui/fragments/BodyFragment.kt index 57440e3..32539f9 100644 --- a/app/src/main/java/org/apphatchery/gatbreferenceguide/ui/fragments/BodyFragment.kt +++ b/app/src/main/java/org/apphatchery/gatbreferenceguide/ui/fragments/BodyFragment.kt @@ -814,7 +814,7 @@ class BodyFragment : BaseFragment(R.layout.fragment_body) { var urlGlobal: String? = null private fun setupWebView() = bind.bodyWebView.apply { - onZoomOut() + // onZoomOut() // JavaScript interface for search results addJavascriptInterface(object { From 2b7a55869a2af0649e57efc66baadaae86bb7eb8 Mon Sep 17 00:00:00 2001 From: Kelvin Sande <98394184+sande11@users.noreply.github.com> Date: Fri, 14 Nov 2025 14:18:42 +0200 Subject: [PATCH 2/3] Dynamically scale chapter icons with font size Added logic to compute and apply chapter icon size in the WebView based on the current font size. This includes setting a CSS variable, tagging relevant images, injecting override styles, and applying inline sizing to ensure consistent scaling even if external styles are missing. The update is triggered after layout and on every page load. --- .../ui/fragments/BodyFragment.kt | 84 +++++++++++++++++++ 1 file changed, 84 insertions(+) diff --git a/app/src/main/java/org/apphatchery/gatbreferenceguide/ui/fragments/BodyFragment.kt b/app/src/main/java/org/apphatchery/gatbreferenceguide/ui/fragments/BodyFragment.kt index 32539f9..75d8de3 100644 --- a/app/src/main/java/org/apphatchery/gatbreferenceguide/ui/fragments/BodyFragment.kt +++ b/app/src/main/java/org/apphatchery/gatbreferenceguide/ui/fragments/BodyFragment.kt @@ -179,6 +179,87 @@ class BodyFragment : BaseFragment(R.layout.fragment_body) { } webViewFont.settings.textZoom = fontSize + + // Compute target pixel size for chapter icon relative to 16px @ 125% baseline + val scaleFactor = fontSize / 125.0 + val iconPx = 16.0 * scaleFactor + val iconPxStr = String.format("%.2f", iconPx) + + // 1) Set CSS variable consumed by .ic_chapter_icon in style.css (which uses !important) + val setVar = """ + (function(){ + try { + var size='${iconPxStr}px'; + document.documentElement.style.setProperty('--chapter-icon-size', size); + } catch(e) {} + })(); + """.trimIndent() + + // 2) Ensure chapter icon image gets the class so the CSS rule applies, without touching other content images + val tagIcons = """ + (function(){ + try { + var nodes = document.querySelectorAll('img[src$="ic_chapter.svg"], img[src*="/ic_chapter.svg"], img[src*="ic_chapter.svg"]'); + nodes.forEach(function(n){ + if(n.classList && !n.classList.contains('ic_chapter_icon')) n.classList.add('ic_chapter_icon'); + }); + } catch(e) {} + })(); + """.trimIndent() + + // 3) Inject an explicit override rule with !important placed after external CSS + val injectOverride = """ + (function(){ + try { + var style = document.getElementById('chapter-icon-override'); + if(!style){ + style = document.createElement('style'); + style.id = 'chapter-icon-override'; + document.head.appendChild(style); + } + var size='${iconPxStr}px'; + style.textContent = '.ic_chapter_icon{width:'+size+' !important;height:'+size+' !important;}'; + } catch(e) {} + })(); + """.trimIndent() + + // 4) Also apply inline size and attributes so pages missing style.css still resize correctly + val sizeIcons = """ + (function(){ + try { + var cssSize='${iconPxStr}px'; + var attrSize='${iconPxStr}'; + var nodes = document.querySelectorAll('img[src$=\"ic_chapter.svg\"], img[src*=\"/ic_chapter.svg\"], img[src*=\"ic_chapter.svg\"]'); + nodes.forEach(function(n){ + // Ensure the parent wrapper also reserves space for the icon + var p = n.parentElement; + if (p) { + p.style.width = cssSize; + p.style.height = cssSize; + p.style.flex = '0 0 auto'; + } + // Apply explicit sizing on the image + n.style.display = 'inline-block'; + n.style.width = cssSize; + n.style.height = cssSize; + n.style.maxWidth = cssSize; + n.style.maxHeight = cssSize; + if (n.setAttribute) { + n.setAttribute('width', attrSize); + n.setAttribute('height', attrSize); + } + }); + } catch(e) {} + })(); + """.trimIndent() + + // Execute after WebView layout pass + webViewFont.post { + webViewFont.evaluateJavascript(setVar, null) + webViewFont.evaluateJavascript(tagIcons, null) + webViewFont.evaluateJavascript(injectOverride, null) + webViewFont.evaluateJavascript(sizeIcons, null) + } } private fun showFontDialog() { @@ -835,6 +916,9 @@ class BodyFragment : BaseFragment(R.layout.fragment_body) { super.onPageFinished(view, url) urlGlobal = url + // Re-apply font and icon scaling on every page load + updateFont() + val searchInput = bodyUrl.searchQuery if (searchInput.isNotEmpty() && !isOnlyWhitespace(searchInput)) { From 9c4b5ab0db55e1398bd252c333a056b7148d01f1 Mon Sep 17 00:00:00 2001 From: Kelvin Sande <98394184+sande11@users.noreply.github.com> Date: Fri, 14 Nov 2025 14:57:21 +0200 Subject: [PATCH 3/3] Scale decorative line in paragraphs with text zoom Adds logic to dynamically scale the `.uk-paragraph::before` decorative line in response to text zoom, ensuring consistent appearance. The computed CSS values are injected via a style element in the WebView. --- .../ui/fragments/BodyFragment.kt | 42 ++++++++++++++++++- 1 file changed, 41 insertions(+), 1 deletion(-) diff --git a/app/src/main/java/org/apphatchery/gatbreferenceguide/ui/fragments/BodyFragment.kt b/app/src/main/java/org/apphatchery/gatbreferenceguide/ui/fragments/BodyFragment.kt index 75d8de3..473e8f3 100644 --- a/app/src/main/java/org/apphatchery/gatbreferenceguide/ui/fragments/BodyFragment.kt +++ b/app/src/main/java/org/apphatchery/gatbreferenceguide/ui/fragments/BodyFragment.kt @@ -185,6 +185,17 @@ class BodyFragment : BaseFragment(R.layout.fragment_body) { val iconPx = 16.0 * scaleFactor val iconPxStr = String.format("%.2f", iconPx) + // Compute scaled metrics for the decorative line used by `.uk-paragraph` + val remBasePx = 16.0 // 1rem baseline + val ukHeightPx = 2.0 * remBasePx * scaleFactor // was 2rem + val ukWidthPx = 0.5 * remBasePx * scaleFactor // was 0.5rem + val ukTopPx = -0.25 * remBasePx * scaleFactor // was -0.25rem + val ukRadiusPx = 0.25 * remBasePx * scaleFactor // was 0.25rem + val ukHeightPxStr = String.format("%.2f", ukHeightPx) + val ukWidthPxStr = String.format("%.2f", ukWidthPx) + val ukTopPxStr = String.format("%.2f", ukTopPx) + val ukRadiusPxStr = String.format("%.2f", ukRadiusPx) + // 1) Set CSS variable consumed by .ic_chapter_icon in style.css (which uses !important) val setVar = """ (function(){ @@ -223,7 +234,7 @@ class BodyFragment : BaseFragment(R.layout.fragment_body) { })(); """.trimIndent() - // 4) Also apply inline size and attributes so pages missing style.css still resize correctly + // 4) also apply inline size and attributes so pages missing style.css still resize correctly val sizeIcons = """ (function(){ try { @@ -253,12 +264,41 @@ class BodyFragment : BaseFragment(R.layout.fragment_body) { })(); """.trimIndent() + // 5) Scale the decorative line for paragraphs `.uk-paragraph::before` to match text zoom + val paragraphOverride = """ + (function(){ + try { + var style = document.getElementById('uk-paragraph-override'); + if(!style){ + style = document.createElement('style'); + style.id = 'uk-paragraph-override'; + document.head.appendChild(style); + } + var h='${ukHeightPxStr}px'; + var w='${ukWidthPxStr}px'; + var t='${ukTopPxStr}px'; + var r='${ukRadiusPxStr}px'; + style.textContent = ''+ + '.uk-paragraph{position: relative;}'+ + '.uk-paragraph::before{'+ + 'content:""; position:absolute; left:0; '+ + 'top:'+t+' !important; '+ + 'height:'+h+' !important; '+ + 'width:'+w+' !important; '+ + 'background-color: var(--primary-color); '+ + 'border-radius:'+r+' !important;'+ + '}'; + } catch(e) {} + })(); + """.trimIndent() + // Execute after WebView layout pass webViewFont.post { webViewFont.evaluateJavascript(setVar, null) webViewFont.evaluateJavascript(tagIcons, null) webViewFont.evaluateJavascript(injectOverride, null) webViewFont.evaluateJavascript(sizeIcons, null) + webViewFont.evaluateJavascript(paragraphOverride, null) } }