Lettore 0.3.3: paginazione per contenuto + versione nelle impostazioni

- Tap avanti/indietro per PAGINA DI TESTO (offset in caratteri dai text node):
  positionJs (sopra) + charsInViewportJs (nella viewport) + scrollToCharJs;
  fine capitolo = offset >= chapterTextLength (C++), mai dallo scroll del
  WebView. window.scrollY non riflette lo scroll reale e contentHeight/
  scrollPosition nativi non sono scrivibili su Qt 5.6 (0.3.1 e 0.3.2 falliti)
- SettingsPage: label 'Version' in fondo (appVersion da setApplicationVersion)
- Traduzione IT aggiunta; log build aggiornato
This commit is contained in:
2026-08-21 10:47:40 +02:00
parent fc2d4d9d3d
commit 00877a0223
5 changed files with 113 additions and 45 deletions
+86 -43
View File
@@ -15,6 +15,9 @@ Page {
// posizione di lettura nel capitolo corrente, in caratteri di testo
// (conteggio JS sui text node: stabile al variare di font/margini)
property int charOffset: 0
// caratteri di testo per pagina (stimati dalla viewport corrente): usato
// per il passo di pagina e per la label "pagina corrente/totale"
property int charsPerPage: 1
// offset da ripristinare al load del capitolo (-1 = nessuno)
property int restoreCharOffset: -1
// ultimo offset assoluto salvato (evita scritture continue)
@@ -144,9 +147,11 @@ Page {
page.restoreCharOffset = -1
if (off >= book.chapterTextLength(page.currentChapter)) {
// oltre la fine = vai all'ultima pagina (usato da
// prevPage per non saltare la coda del capitolo)
web.scrollPosition = Qt.point(0, Math.max(1, web.contentHeight - web.height))
readScrollPosition()
// prevPage per non saltare la coda del capitolo):
// scrollTo oltre il limite porta in fondo al documento
web.runJavaScript(
"window.scrollTo(0,9999999);true",
function() { readScrollPosition() })
} else {
web.runJavaScript(page.scrollToCharJs(off), function() {
readScrollPosition()
@@ -275,6 +280,28 @@ Page {
+ "return o;})()"
}
// JS che conta i caratteri di testo NELLA viewport corrente (per il passo
// di pagina): stessa tecnica di positionJs, ma sulla fascia [0, innerHeight]
function charsInViewportJs() {
return "(function(){"
+ "var b=document.body;"
+ "var vh=window.innerHeight;"
+ "var c=0;"
+ "var it=document.createTreeWalker(b,NodeFilter.SHOW_TEXT);"
+ "var n;"
+ "while((n=it.nextNode())){"
+ "var p=n.parentNode;"
+ "if(!p||p.tagName==='SCRIPT'||p.tagName==='STYLE'||p.tagName==='NOSCRIPT')continue;"
+ "var r=document.createRange();r.selectNodeContents(n);"
+ "var rect=r.getBoundingClientRect();"
+ "if(rect.bottom<=0||rect.top>=vh)continue;"
+ "var top=Math.max(0,rect.top),bot=Math.min(vh,rect.bottom);"
+ "var h=rect.bottom-rect.top;"
+ "if(h>0)c+=Math.round(n.data.length*(bot-top)/h);"
+ "}"
+ "return c;})()"
}
// JS che porta in cima alla viewport il carattere 'off' del capitolo
function scrollToCharJs(off) {
return "(function(){"
@@ -296,16 +323,17 @@ Page {
function readScrollPosition() {
if (!web.loaded)
return
// posizione letta dalle proprietà NATIVE del WebView (affidabili),
// il JS serve solo a contare i caratteri per il bookmark
var vh = Math.max(1, web.height)
var max = Math.max(1, web.contentHeight - vh)
var y = Math.max(0, Math.min(max, web.scrollPosition.y))
page.chapterFraction = y / max
page.pageIndex = Math.floor(y / vh) + 1
page.pageCount = Math.max(1, Math.floor(max / vh) + 1)
web.runJavaScript(page.positionJs(), function(o) {
page.charOffset = o || 0
// avanzamento per CARATTERI: stabile e indipendente dallo scroll reale
var total = book.chapterStartChar(book.chapterCount)
var start = book.chapterStartChar(page.currentChapter)
if (total > 0)
page.chapterFraction = (start + page.charOffset) / total
var len = book.chapterTextLength(page.currentChapter)
var pp = Math.max(1, page.charsPerPage)
page.pageIndex = Math.floor(page.charOffset / pp) + 1
page.pageCount = Math.max(1, Math.ceil(len / pp))
maybeSave(false)
})
}
@@ -346,46 +374,61 @@ Page {
loadChapter()
}
// pagina successiva: una viewport avanti, usando le proprietà native del
// WebView (contentHeight/scrollPosition) — niente JS di navigazione, quindi
// nessuna dipendenza da runJavaScript/scrollY per il cambio capitolo.
// A fine capitolo (y >= max-2) passa al capitolo successivo.
// pagina successiva: avanza di una "pagina di testo" (i caratteri visibili
// nella viewport corrente). La fine del capitolo è determinata dal CONFRONTO
// CON LA LUNGHEZZA IN CARATTERI (nota in C++), non dallo scroll reale del
// WebView — quindi il passaggio al capitolo successivo è sempre affidabile.
function nextPage() {
if (!web.loaded || !page.ready)
return
var vh = Math.max(1, web.height)
var max = Math.max(1, web.contentHeight - vh)
var y = web.scrollPosition.y
if (y >= max - 2) {
// fine capitolo (o capitolo non scrollabile) -> avanti
gotoChapter(page.currentChapter + 1)
return
}
web.scrollPosition = Qt.point(0, Math.min(max, y + vh))
readScrollPosition()
web.runJavaScript(page.positionJs(), function(o) {
page.charOffset = o || 0
web.runJavaScript(page.charsInViewportJs(), function(c) {
page.charsPerPage = Math.max(1, Math.round(c || 1))
var target = page.charOffset + page.charsPerPage
if (target >= book.chapterTextLength(page.currentChapter)) {
// fine capitolo: segna la coda come letta e passa avanti
page.charOffset = Math.max(0, book.chapterTextLength(page.currentChapter) - 1)
maybeSave(true)
gotoChapter(page.currentChapter + 1)
} else {
web.runJavaScript(page.scrollToCharJs(target), function() {
readScrollPosition()
})
}
})
})
}
// pagina precedente: una viewport indietro; all'inizio -> capitolo prima
// SULL'ULTIMA PAGINA (non salta la coda del capitolo)
// pagina precedente: torna indietro di una pagina di testo; dall'inizio del
// capitolo va al capitolo prima SULL'ULTIMA PAGINA (non salta la coda)
function prevPage() {
if (!web.loaded || !page.ready)
return
var vh = Math.max(1, web.height)
var y = web.scrollPosition.y
if (y > 1) {
web.scrollPosition = Qt.point(0, Math.max(0, y - vh))
readScrollPosition()
} else if (page.currentChapter > 0) {
maybeSave(true)
page.currentChapter -= 1
page.chapterFraction = 0
page.charOffset = 0
// sentinella "fine capitolo": va oltre la lunghezza, così
// onLoadedChanged porta all'ultima pagina
page.restoreCharOffset = book.chapterTextLength(page.currentChapter) + 1
page.lastSavedAbs = -1
loadChapter()
}
web.runJavaScript(page.positionJs(), function(o) {
page.charOffset = o || 0
web.runJavaScript(page.charsInViewportJs(), function(c) {
page.charsPerPage = Math.max(1, Math.round(c || 1))
var target = page.charOffset - page.charsPerPage
if (target <= 0) {
if (page.currentChapter > 0) {
maybeSave(true)
page.currentChapter -= 1
page.chapterFraction = 0
page.charOffset = 0
// sentinella "fine capitolo": va oltre la lunghezza, così
// onLoadedChanged porta all'ultima pagina
page.restoreCharOffset = book.chapterTextLength(page.currentChapter) + 1
page.lastSavedAbs = -1
loadChapter()
}
} else {
web.runJavaScript(page.scrollToCharJs(target), function() {
readScrollPosition()
})
}
})
})
}
function fontPx() {