From 8eb4244eee809eba25ca529094bcf47c0c8ef30f Mon Sep 17 00:00:00 2001 From: Carlo Baratto Date: Wed, 12 Aug 2026 17:00:27 +0200 Subject: [PATCH] Lettore: margini configurabili (Settings.readerMargin + Slider nelle impostazioni, iniettati nello stile del capitolo) + controlli in PushUpMenu (un solo trascinamento in alto) --- qml/pages/ReaderPage.qml | 139 ++++++++++++++++--------------------- qml/pages/SettingsPage.qml | 13 ++++ src/epub.cpp | 7 +- src/epub.h | 4 +- src/settings.cpp | 14 ++++ src/settings.h | 5 ++ 6 files changed, 97 insertions(+), 85 deletions(-) diff --git a/qml/pages/ReaderPage.qml b/qml/pages/ReaderPage.qml index 1b0a8ad..9e47afc 100644 --- a/qml/pages/ReaderPage.qml +++ b/qml/pages/ReaderPage.qml @@ -27,10 +27,7 @@ Page { } SilicaFlickable { - anchors.top: parent.top - anchors.left: parent.left - anchors.right: parent.right - anchors.bottom: toolbar.top + anchors.fill: parent contentHeight: parent.height // il PullDownMenu va DENTRO una vista Silica, non a livello di Page @@ -45,6 +42,59 @@ Page { } } + // controlli del lettore: un solo trascinamento in alto li apre + PushUpMenu { + id: readerMenu + + Label { + anchors.horizontalCenter: parent.horizontalCenter + width: parent.width - 2 * Theme.horizontalPageMargin + text: (book.chapterCount > 0) + ? (page.currentChapter + 1) + "/" + book.chapterCount + + " · " + book.chapterTitle(page.currentChapter) + + " · " + Math.round(page.overallProgress() * 100) + "%" + : "…" + truncationMode: TruncationMode.Elide + color: Theme.primaryColor + horizontalAlignment: Text.AlignHCenter + font.pixelSize: Theme.fontSizeSmall + } + + Row { + anchors.horizontalCenter: parent.horizontalCenter + spacing: Theme.paddingSmall + IconButton { + icon.source: "image://theme/icon-m-left" + enabled: page.currentChapter > 0 + onClicked: gotoChapter(page.currentChapter - 1) + } + Button { + text: "A−" + width: Theme.itemSizeSmall + height: Theme.itemSizeMedium + onClicked: page.changeFontScale(-0.15) + } + Button { + text: "A+" + width: Theme.itemSizeSmall + height: Theme.itemSizeMedium + onClicked: page.changeFontScale(0.15) + } + IconButton { + icon.source: "image://theme/icon-m-right" + enabled: page.currentChapter < book.chapterCount - 1 + onClicked: gotoChapter(page.currentChapter + 1) + } + } + + ProgressBar { + width: parent.width + value: page.overallProgress() + minimumValue: 0 + maximumValue: 1 + } + } + WebView { id: web anchors.fill: parent @@ -98,79 +148,7 @@ Page { visible: page.errorMessage.length > 0 } - // ---- barra di controllo ---- - Rectangle { - id: toolbar - anchors.left: parent.left - anchors.right: parent.right - anchors.bottom: parent.bottom - height: Theme.itemSizeMedium - color: Theme.rgba(Theme.primaryColor, 0.08) - - IconButton { - id: prevBtn - anchors.left: parent.left - anchors.verticalCenter: parent.verticalCenter - icon.source: "image://theme/icon-m-left" - enabled: page.currentChapter > 0 - onClicked: gotoChapter(page.currentChapter - 1) - } - - Button { - id: fontMinus - anchors.left: prevBtn.right - anchors.verticalCenter: parent.verticalCenter - width: Theme.itemSizeSmall - height: Theme.itemSizeMedium - text: "A−" - onClicked: page.changeFontScale(-0.15) - } - - Button { - id: fontPlus - anchors.left: fontMinus.right - anchors.verticalCenter: parent.verticalCenter - width: Theme.itemSizeSmall - height: Theme.itemSizeMedium - text: "A+" - onClicked: page.changeFontScale(0.15) - } - - Label { - id: chapterLabel - anchors.left: fontPlus.right - anchors.right: nextBtn.left - anchors.verticalCenter: parent.verticalCenter - text: (book.chapterCount > 0) - ? (page.currentChapter + 1) + "/" + book.chapterCount - + " · " + book.chapterTitle(page.currentChapter) - + " · " + Math.round(page.overallProgress() * 100) + "%" - : "…" - truncationMode: TruncationMode.Elide - color: Theme.primaryColor - horizontalAlignment: Text.AlignHCenter - font.pixelSize: Theme.fontSizeSmall - } - - IconButton { - id: nextBtn - anchors.right: parent.right - anchors.verticalCenter: parent.verticalCenter - icon.source: "image://theme/icon-m-right" - enabled: page.currentChapter < book.chapterCount - 1 - onClicked: gotoChapter(page.currentChapter + 1) - } - - ProgressBar { - anchors.left: parent.left - anchors.right: parent.right - anchors.bottom: parent.bottom - height: 6 - value: page.overallProgress() - minimumValue: 0 - maximumValue: 1 - } - } + // ---- controlli spostati nel PushUpMenu (trascina in alto) ---- // ---- timer di tracciamento ---- Timer { @@ -242,10 +220,11 @@ Page { return Math.round(16 * page.fontScale * 100) / 100 } - // carica il capitolo corrente via loadHtml: lo stile di reflow (font-size) - // è iniettato nell'HTML dal parser, quindi niente JS post-load + // carica il capitolo corrente via loadHtml: lo stile di reflow (font-size + // e margini) è iniettato nell'HTML dal parser, quindi niente JS post-load function loadChapter() { - var html = book.chapterHtml(page.currentChapter, page.fontPx()) + var html = book.chapterHtml(page.currentChapter, page.fontPx(), + appSettings.readerMargin) if (html.length === 0) { page.errorMessage = "Capitolo non leggibile" page.ready = true diff --git a/qml/pages/SettingsPage.qml b/qml/pages/SettingsPage.qml index 5ff5dab..bb5f616 100644 --- a/qml/pages/SettingsPage.qml +++ b/qml/pages/SettingsPage.qml @@ -57,6 +57,19 @@ Page { onCheckedChanged: appSettings.ignoreSslErrors = checked } + SectionHeader { text: "Lettore" } + + Slider { + id: marginSlider + label: "Margini del testo" + minimumValue: 0 + maximumValue: 80 + stepSize: 4 + value: appSettings.readerMargin + valueText: value + " px" + onValueChanged: appSettings.readerMargin = value + } + SectionHeader { text: "Connessione" } Button { diff --git a/src/epub.cpp b/src/epub.cpp index 2206707..f4ade5c 100644 --- a/src/epub.cpp +++ b/src/epub.cpp @@ -406,7 +406,7 @@ QVariantList EpubBook::chapterList() const return list; } -QString EpubBook::chapterHtml(int index, int fontSizePx) const +QString EpubBook::chapterHtml(int index, int fontSizePx, int marginPx) const { if (index < 0 || index >= m_chapters.size()) return QString(); @@ -417,9 +417,10 @@ QString EpubBook::chapterHtml(int index, int fontSizePx) const // stile di reflow iniettato nel documento: !important vince sui CSS del libro const QString style = QStringLiteral( - "") - .arg(fontSizePx); + .arg(fontSizePx).arg(marginPx); const int headEnd = html.indexOf(QStringLiteral(""), 0, Qt::CaseInsensitive); if (headEnd >= 0) html.insert(headEnd, style); diff --git a/src/epub.h b/src/epub.h index b846c5f..a68b936 100644 --- a/src/epub.h +++ b/src/epub.h @@ -36,8 +36,8 @@ public: Q_INVOKABLE QString chapterTitle(int index) const; // elenco [{index, title}] per la lista capitoli Q_INVOKABLE QVariantList chapterList() const; - // HTML del capitolo con lo stile di reflow iniettato (font-size in px) - Q_INVOKABLE QString chapterHtml(int index, int fontSizePx) const; + // HTML del capitolo con lo stile di reflow iniettato (font-size e margini in px) + Q_INVOKABLE QString chapterHtml(int index, int fontSizePx, int marginPx) const; // base URL (file://) per risolvere immagini/CSS relativi del capitolo Q_INVOKABLE QString chapterBaseUrl(int index) const; diff --git a/src/settings.cpp b/src/settings.cpp index 8cb5d8f..f1a06a1 100644 --- a/src/settings.cpp +++ b/src/settings.cpp @@ -66,6 +66,20 @@ void Settings::setIgnoreSslErrors(bool value) emit ignoreSslErrorsChanged(); } +int Settings::readerMargin() const +{ + return m_settings.value(QStringLiteral("readerMargin"), 24).toInt(); +} + +void Settings::setReaderMargin(int value) +{ + if (value == readerMargin()) + return; + m_settings.setValue(QStringLiteral("readerMargin"), value); + m_settings.sync(); + emit readerMarginChanged(); +} + QString Settings::downloadDir() const { QString dir = QStandardPaths::writableLocation(QStandardPaths::DownloadLocation); diff --git a/src/settings.h b/src/settings.h index 5162a28..f7df14e 100644 --- a/src/settings.h +++ b/src/settings.h @@ -12,6 +12,7 @@ class Settings : public QObject Q_PROPERTY(QString username READ username WRITE setUsername NOTIFY usernameChanged) Q_PROPERTY(QString password READ password WRITE setPassword NOTIFY passwordChanged) Q_PROPERTY(bool ignoreSslErrors READ ignoreSslErrors WRITE setIgnoreSslErrors NOTIFY ignoreSslErrorsChanged) + Q_PROPERTY(int readerMargin READ readerMargin WRITE setReaderMargin NOTIFY readerMarginChanged) Q_PROPERTY(QString downloadDir READ downloadDir CONSTANT) // derivata da serverUrl (senza slash finale): accesso QML come appSettings.baseUrl Q_PROPERTY(QString baseUrl READ baseUrl NOTIFY baseUrlChanged) @@ -31,6 +32,10 @@ public: bool ignoreSslErrors() const; void setIgnoreSslErrors(bool value); + // margine laterale del testo nel lettore, in px + int readerMargin() const; + void setReaderMargin(int value); + QString downloadDir() const; // Header "Authorization: Basic ..." pronto da usare, vuoto se utente non impostato