228 lines
6.6 KiB
QML
228 lines
6.6 KiB
QML
import QtQuick 2.0
|
|
import Sailfish.Silica 1.0
|
|
import Sailfish.WebView 1.0
|
|
import harbour.calibreweb 1.0
|
|
|
|
Page {
|
|
id: page
|
|
|
|
property string epubPath: ""
|
|
property int bookId: 0
|
|
property string bookFormat: "epub"
|
|
|
|
property int currentChapter: 0
|
|
property double chapterFraction: 0.0
|
|
property bool restoring: false
|
|
property int saveCounter: 0
|
|
property int syncCounter: 0
|
|
property string errorMessage: ""
|
|
|
|
allowedOrientations: Orientation.All
|
|
|
|
EpubBook {
|
|
id: book
|
|
}
|
|
|
|
SilicaFlickable {
|
|
anchors.top: parent.top
|
|
anchors.left: parent.left
|
|
anchors.right: parent.right
|
|
anchors.bottom: toolbar.top
|
|
contentHeight: parent.height
|
|
WebView {
|
|
id: web
|
|
anchors.fill: parent
|
|
active: true
|
|
onLoadedChanged: {
|
|
if (!loaded)
|
|
return
|
|
if (page.restoring)
|
|
page.restoring = false
|
|
else
|
|
restorePosition()
|
|
page.ready = true
|
|
}
|
|
}
|
|
}
|
|
|
|
BusyIndicator {
|
|
anchors.centerIn: parent
|
|
running: !page.ready
|
|
size: BusyIndicatorSize.Large
|
|
}
|
|
|
|
Label {
|
|
anchors.centerIn: parent
|
|
text: page.errorMessage
|
|
color: Theme.errorColor
|
|
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)
|
|
}
|
|
|
|
Label {
|
|
id: chapterLabel
|
|
anchors.left: prevBtn.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
|
|
}
|
|
}
|
|
|
|
PullDownMenu {
|
|
MenuItem {
|
|
text: "Indice capitoli"
|
|
onClicked: showChapterList()
|
|
}
|
|
MenuItem {
|
|
text: "Aggiorna posizione sul server"
|
|
onClicked: syncNow()
|
|
}
|
|
}
|
|
|
|
// ---- timer di tracciamento ----
|
|
Timer {
|
|
id: trackTimer
|
|
interval: 2000
|
|
running: page.ready
|
|
repeat: true
|
|
onTriggered: readScrollPosition()
|
|
}
|
|
|
|
function overallProgress() {
|
|
if (book.chapterCount <= 0)
|
|
return 0
|
|
return (page.currentChapter + page.chapterFraction) / book.chapterCount
|
|
}
|
|
|
|
function readScrollPosition() {
|
|
if (!web.loaded)
|
|
return
|
|
web.runJavaScript(
|
|
"window.scrollY / Math.max(1, document.documentElement.scrollHeight - window.innerHeight)",
|
|
function(f) {
|
|
var v = Math.max(0, Math.min(1, f))
|
|
if (Math.abs(v - page.chapterFraction) > 0.005) {
|
|
page.chapterFraction = v
|
|
maybeSave(true)
|
|
}
|
|
})
|
|
}
|
|
|
|
function maybeSave(force) {
|
|
if (bookId <= 0)
|
|
return
|
|
page.saveCounter++
|
|
// salva locale ogni ~10 s, sync server ogni ~30 s
|
|
if (force || page.saveCounter % 5 === 0) {
|
|
appSettings.setBookmarkKey(page.bookId, page.bookFormat,
|
|
book.makeBookmarkKey(page.currentChapter, page.chapterFraction))
|
|
}
|
|
if (force || page.syncCounter++ % 15 === 0)
|
|
syncNow()
|
|
}
|
|
|
|
function syncNow() {
|
|
if (bookId <= 0)
|
|
return
|
|
apiClient.postBookmark(page.bookId, page.bookFormat,
|
|
book.makeBookmarkKey(page.currentChapter, page.chapterFraction))
|
|
}
|
|
|
|
function gotoChapter(index) {
|
|
if (index < 0 || index >= book.chapterCount)
|
|
return
|
|
if (index !== page.currentChapter) {
|
|
maybeSave(true)
|
|
page.chapterFraction = 0
|
|
}
|
|
page.currentChapter = index
|
|
page.restoring = true
|
|
page.ready = false
|
|
web.url = "file://" + book.chapterFilePath(index)
|
|
}
|
|
|
|
function restorePosition() {
|
|
if (page.chapterFraction > 0.01) {
|
|
web.runJavaScript(
|
|
"window.scrollTo(0, " + page.chapterFraction
|
|
+ " * Math.max(1, document.documentElement.scrollHeight - window.innerHeight)); true",
|
|
function() { })
|
|
}
|
|
}
|
|
|
|
function showChapterList() {
|
|
var dialog = pageStack.push(Qt.resolvedUrl("ChapterListDialog.qml"),
|
|
{ model: book.chapterList() })
|
|
dialog.accepted.connect(function() {
|
|
gotoChapter(dialog.selectedIndex)
|
|
})
|
|
}
|
|
|
|
Component.onCompleted: {
|
|
page.ready = false
|
|
if (!book.open(page.epubPath)) {
|
|
page.errorMessage = "Impossibile aprire il libro EPUB"
|
|
page.ready = true
|
|
return
|
|
}
|
|
// ripristina il segno locale
|
|
var key = appSettings.bookmarkKey(page.bookId, page.bookFormat)
|
|
var ch = 0
|
|
var fr = 0.0
|
|
if (key.length > 0 && book.parseBookmarkKey(key, ch, fr)) {
|
|
page.currentChapter = Math.max(0, Math.min(ch, book.chapterCount - 1))
|
|
page.chapterFraction = fr
|
|
}
|
|
web.url = "file://" + book.chapterFilePath(page.currentChapter)
|
|
}
|
|
|
|
onStatusChanged: {
|
|
if (status === PageStatus.Inactive)
|
|
maybeSave(true)
|
|
}
|
|
}
|