Lettore: margini configurabili (Settings.readerMargin + Slider nelle impostazioni, iniettati nello stile del capitolo) + controlli in PushUpMenu (un solo trascinamento in alto)
This commit is contained in:
+59
-80
@@ -27,10 +27,7 @@ Page {
|
|||||||
}
|
}
|
||||||
|
|
||||||
SilicaFlickable {
|
SilicaFlickable {
|
||||||
anchors.top: parent.top
|
anchors.fill: parent
|
||||||
anchors.left: parent.left
|
|
||||||
anchors.right: parent.right
|
|
||||||
anchors.bottom: toolbar.top
|
|
||||||
contentHeight: parent.height
|
contentHeight: parent.height
|
||||||
|
|
||||||
// il PullDownMenu va DENTRO una vista Silica, non a livello di Page
|
// 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 {
|
WebView {
|
||||||
id: web
|
id: web
|
||||||
anchors.fill: parent
|
anchors.fill: parent
|
||||||
@@ -98,79 +148,7 @@ Page {
|
|||||||
visible: page.errorMessage.length > 0
|
visible: page.errorMessage.length > 0
|
||||||
}
|
}
|
||||||
|
|
||||||
// ---- barra di controllo ----
|
// ---- controlli spostati nel PushUpMenu (trascina in alto) ----
|
||||||
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
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// ---- timer di tracciamento ----
|
// ---- timer di tracciamento ----
|
||||||
Timer {
|
Timer {
|
||||||
@@ -242,10 +220,11 @@ Page {
|
|||||||
return Math.round(16 * page.fontScale * 100) / 100
|
return Math.round(16 * page.fontScale * 100) / 100
|
||||||
}
|
}
|
||||||
|
|
||||||
// carica il capitolo corrente via loadHtml: lo stile di reflow (font-size)
|
// carica il capitolo corrente via loadHtml: lo stile di reflow (font-size
|
||||||
// è iniettato nell'HTML dal parser, quindi niente JS post-load
|
// e margini) è iniettato nell'HTML dal parser, quindi niente JS post-load
|
||||||
function loadChapter() {
|
function loadChapter() {
|
||||||
var html = book.chapterHtml(page.currentChapter, page.fontPx())
|
var html = book.chapterHtml(page.currentChapter, page.fontPx(),
|
||||||
|
appSettings.readerMargin)
|
||||||
if (html.length === 0) {
|
if (html.length === 0) {
|
||||||
page.errorMessage = "Capitolo non leggibile"
|
page.errorMessage = "Capitolo non leggibile"
|
||||||
page.ready = true
|
page.ready = true
|
||||||
|
|||||||
@@ -57,6 +57,19 @@ Page {
|
|||||||
onCheckedChanged: appSettings.ignoreSslErrors = checked
|
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" }
|
SectionHeader { text: "Connessione" }
|
||||||
|
|
||||||
Button {
|
Button {
|
||||||
|
|||||||
+4
-3
@@ -406,7 +406,7 @@ QVariantList EpubBook::chapterList() const
|
|||||||
return list;
|
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())
|
if (index < 0 || index >= m_chapters.size())
|
||||||
return QString();
|
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
|
// stile di reflow iniettato nel documento: !important vince sui CSS del libro
|
||||||
const QString style = QStringLiteral(
|
const QString style = QStringLiteral(
|
||||||
"<style id=\"cw-font\">html,body{font-size:%1px!important}"
|
"<style id=\"cw-font\">html,body{font-size:%1px!important;"
|
||||||
|
"margin-left:%2px!important;margin-right:%2px!important}"
|
||||||
"p,div,li,td,blockquote,section{font-size:1em!important}</style>")
|
"p,div,li,td,blockquote,section{font-size:1em!important}</style>")
|
||||||
.arg(fontSizePx);
|
.arg(fontSizePx).arg(marginPx);
|
||||||
const int headEnd = html.indexOf(QStringLiteral("</head>"), 0, Qt::CaseInsensitive);
|
const int headEnd = html.indexOf(QStringLiteral("</head>"), 0, Qt::CaseInsensitive);
|
||||||
if (headEnd >= 0)
|
if (headEnd >= 0)
|
||||||
html.insert(headEnd, style);
|
html.insert(headEnd, style);
|
||||||
|
|||||||
+2
-2
@@ -36,8 +36,8 @@ public:
|
|||||||
Q_INVOKABLE QString chapterTitle(int index) const;
|
Q_INVOKABLE QString chapterTitle(int index) const;
|
||||||
// elenco [{index, title}] per la lista capitoli
|
// elenco [{index, title}] per la lista capitoli
|
||||||
Q_INVOKABLE QVariantList chapterList() const;
|
Q_INVOKABLE QVariantList chapterList() const;
|
||||||
// HTML del capitolo con lo stile di reflow iniettato (font-size in px)
|
// HTML del capitolo con lo stile di reflow iniettato (font-size e margini in px)
|
||||||
Q_INVOKABLE QString chapterHtml(int index, int fontSizePx) const;
|
Q_INVOKABLE QString chapterHtml(int index, int fontSizePx, int marginPx) const;
|
||||||
// base URL (file://) per risolvere immagini/CSS relativi del capitolo
|
// base URL (file://) per risolvere immagini/CSS relativi del capitolo
|
||||||
Q_INVOKABLE QString chapterBaseUrl(int index) const;
|
Q_INVOKABLE QString chapterBaseUrl(int index) const;
|
||||||
|
|
||||||
|
|||||||
@@ -66,6 +66,20 @@ void Settings::setIgnoreSslErrors(bool value)
|
|||||||
emit ignoreSslErrorsChanged();
|
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 Settings::downloadDir() const
|
||||||
{
|
{
|
||||||
QString dir = QStandardPaths::writableLocation(QStandardPaths::DownloadLocation);
|
QString dir = QStandardPaths::writableLocation(QStandardPaths::DownloadLocation);
|
||||||
|
|||||||
@@ -12,6 +12,7 @@ class Settings : public QObject
|
|||||||
Q_PROPERTY(QString username READ username WRITE setUsername NOTIFY usernameChanged)
|
Q_PROPERTY(QString username READ username WRITE setUsername NOTIFY usernameChanged)
|
||||||
Q_PROPERTY(QString password READ password WRITE setPassword NOTIFY passwordChanged)
|
Q_PROPERTY(QString password READ password WRITE setPassword NOTIFY passwordChanged)
|
||||||
Q_PROPERTY(bool ignoreSslErrors READ ignoreSslErrors WRITE setIgnoreSslErrors NOTIFY ignoreSslErrorsChanged)
|
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)
|
Q_PROPERTY(QString downloadDir READ downloadDir CONSTANT)
|
||||||
// derivata da serverUrl (senza slash finale): accesso QML come appSettings.baseUrl
|
// derivata da serverUrl (senza slash finale): accesso QML come appSettings.baseUrl
|
||||||
Q_PROPERTY(QString baseUrl READ baseUrl NOTIFY baseUrlChanged)
|
Q_PROPERTY(QString baseUrl READ baseUrl NOTIFY baseUrlChanged)
|
||||||
@@ -31,6 +32,10 @@ public:
|
|||||||
bool ignoreSslErrors() const;
|
bool ignoreSslErrors() const;
|
||||||
void setIgnoreSslErrors(bool value);
|
void setIgnoreSslErrors(bool value);
|
||||||
|
|
||||||
|
// margine laterale del testo nel lettore, in px
|
||||||
|
int readerMargin() const;
|
||||||
|
void setReaderMargin(int value);
|
||||||
|
|
||||||
QString downloadDir() const;
|
QString downloadDir() const;
|
||||||
|
|
||||||
// Header "Authorization: Basic ..." pronto da usare, vuoto se utente non impostato
|
// Header "Authorization: Basic ..." pronto da usare, vuoto se utente non impostato
|
||||||
|
|||||||
Reference in New Issue
Block a user