476 lines
15 KiB
QML
476 lines
15 KiB
QML
/*
|
|
Copyright (C) 2016 Michal Kosciesza <michal@mkiol.net>
|
|
|
|
This file is part of Kaktus.
|
|
|
|
Kaktus is free software: you can redistribute it and/or modify
|
|
it under the terms of the GNU General Public License as published by
|
|
the Free Software Foundation, either version 3 of the License, or
|
|
(at your option) any later version.
|
|
|
|
Kaktus is distributed in the hope that it will be useful,
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
GNU General Public License for more details.
|
|
|
|
You should have received a copy of the GNU General Public License
|
|
along with Kaktus. If not, see <http://www.gnu.org/licenses/>.
|
|
*/
|
|
|
|
import QtQuick 2.0
|
|
import Sailfish.Silica 1.0
|
|
import QtWebKit 3.0
|
|
|
|
Page {
|
|
id: root
|
|
|
|
property bool showBar: false
|
|
|
|
property string title
|
|
property string content
|
|
property string entryId
|
|
property string offlineUrl
|
|
property string onlineUrl
|
|
property bool stared
|
|
property bool liked
|
|
property bool read
|
|
property bool broadcast
|
|
property int index
|
|
property int feedindex
|
|
property bool cached
|
|
property bool autoRead: true
|
|
|
|
property variant _settings: settings
|
|
property bool themeApply: true
|
|
readonly property color bgColor: Theme.colorScheme ? Qt.lighter(Theme.highlightBackgroundColor, 1.9) :
|
|
Qt.darker(Theme.highlightBackgroundColor, 4.0)
|
|
|
|
property bool navigateBackPop: true
|
|
|
|
function init() {
|
|
view.loadHtml(utils.formatHtml(content, settings.offlineMode, ""))
|
|
navigateBackPop = true
|
|
themeApply = true
|
|
if (!read) {
|
|
read = true
|
|
entryModel.setData(index, "read", 1, "");
|
|
}
|
|
}
|
|
|
|
function navigateBack() {
|
|
if (view.canGoBack)
|
|
view.goBack()
|
|
else
|
|
if (navigateBackPop)
|
|
pageStack.pop()
|
|
else
|
|
init()
|
|
}
|
|
|
|
allowedOrientations: {
|
|
switch (settings.allowedOrientations) {
|
|
case 1:
|
|
return Orientation.PortraitMask;
|
|
case 2:
|
|
return Orientation.LandscapeMask;
|
|
}
|
|
return Orientation.All;
|
|
}
|
|
|
|
Component.onCompleted: {
|
|
bar.hide()
|
|
controlbar.show()
|
|
init()
|
|
}
|
|
|
|
Connections {
|
|
target: fetcher
|
|
onBusyChanged: {
|
|
if(fetcher.busy) {
|
|
pageStack.pop();
|
|
}
|
|
}
|
|
}
|
|
|
|
function share() {
|
|
pageStack.push(Qt.resolvedUrl("ShareLinkPage.qml"),{"link": root.onlineUrl, "linkTitle": root.title});
|
|
}
|
|
|
|
function check() {
|
|
// Not allowed while Syncing
|
|
if (dm.busy || fetcher.busy || dm.removerBusy) {
|
|
notification.show(qsTr("Wait until current task is complete"));
|
|
return false;
|
|
}
|
|
|
|
// Entry not cached and offline mode enabled
|
|
if (settings.offlineMode && !cached) {
|
|
notification.show(qsTr("Offline version not available"));
|
|
return false;
|
|
}
|
|
|
|
// Switch to Offline mode if no network
|
|
if (!settings.offlineMode && !dm.online) {
|
|
if (cached) {
|
|
// Entry cached
|
|
notification.show(qsTr("Enabling offline mode because network is disconnected"));
|
|
settings.offlineMode = true;
|
|
} else {
|
|
// Entry not cached
|
|
notification.show(qsTr("Network is disconnected"));
|
|
return false;
|
|
}
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
function openEntryInBrowser() {
|
|
openUrlEntryInBrowser(onlineUrl)
|
|
}
|
|
|
|
function openUrlEntryInBrowser(url) {
|
|
Qt.openUrlExternally(url);
|
|
}
|
|
|
|
function openEntryInViewer() {
|
|
pageStack.replace(Qt.resolvedUrl("WebPreviewPage.qml"),
|
|
{"entryId": entryId,
|
|
"onlineUrl": onlineUrl,
|
|
"offlineUrl": offlineUrl,
|
|
"title": title,
|
|
"stared": stared,
|
|
"liked": liked,
|
|
"broadcast": broadcast,
|
|
"index": index,
|
|
"feedindex": feedindex,
|
|
"read" : read,
|
|
"cached" : cached,
|
|
"autoRead" : autoRead
|
|
});
|
|
}
|
|
|
|
function openUrlInViewer(url) {
|
|
pageStack.replace(Qt.resolvedUrl("WebPreviewPage.qml"),
|
|
{"entryId": entryId,
|
|
"onlineUrl": url,
|
|
"offlineUrl": url,
|
|
"title": title,
|
|
"stared": stared,
|
|
"liked": liked,
|
|
"broadcast": broadcast,
|
|
"index": index,
|
|
"feedindex": feedindex,
|
|
"read" : read,
|
|
"cached" : cached
|
|
});
|
|
}
|
|
|
|
function openEntry() {
|
|
if (!check()) {
|
|
return;
|
|
}
|
|
|
|
if (settings.clickBehavior === 1) {
|
|
openEntryInBrowser();
|
|
return;
|
|
}
|
|
|
|
openEntryInViewer();
|
|
}
|
|
|
|
function initTheme() {
|
|
var theme = { "primaryColor": Theme.rgba(Theme.primaryColor, 1.0).toString(),
|
|
"secondaryColor": Theme.rgba(Theme.secondaryColor, 1.0).toString(),
|
|
"highlightColor": Theme.rgba(Theme.highlightColor, 1.0).toString(),
|
|
"bgColor": root.bgColor.toString(),
|
|
"fontFamily": Theme.fontFamily,
|
|
"fontFamilyHeading": Theme.fontFamilyHeading,
|
|
"pageMargin": Theme.horizontalPageMargin/Theme.pixelRatio,
|
|
"pageMarginBottom": Theme.itemSizeMedium/Theme.pixelRatio,
|
|
"fontSize": Theme.fontSizeMedium,
|
|
"fontSizeTitle": Theme.fontSizeLarge,
|
|
"zoom": settings.zoom}
|
|
postMessage("theme_set", { "theme": theme })
|
|
postMessage("theme_apply")
|
|
}
|
|
|
|
function updateZoom(delta) {
|
|
var zoom = settings.zoom;
|
|
settings.zoom = ((zoom + delta) <= 0.5) || ((zoom + delta) >= 2.0) ? zoom : zoom + delta
|
|
var theme = { "zoom": settings.zoom }
|
|
postMessage("theme_set", { "theme": theme })
|
|
postMessage("theme_apply")
|
|
baner.show("" + Math.floor(settings.zoom * 100) + "%")
|
|
}
|
|
|
|
function messageReceivedHandler(message) {
|
|
if (message.type === "inited") {
|
|
if (root.themeApply) {
|
|
initTheme()
|
|
root.themeApply = false
|
|
}
|
|
postMessage("readability_apply_fixups")
|
|
}
|
|
}
|
|
|
|
function postMessage(message, data) {
|
|
view.experimental.postMessage(JSON.stringify({ "type": message, "data": data }));
|
|
}
|
|
|
|
Connections {
|
|
target: settings
|
|
onFontSizeChanged: updateFontSize()
|
|
}
|
|
|
|
Rectangle {
|
|
anchors.fill: parent
|
|
color: root.bgColor
|
|
}
|
|
|
|
SilicaWebView {
|
|
id: view
|
|
|
|
anchors.fill: parent
|
|
experimental.transparentBackground: true
|
|
experimental.overview: false
|
|
experimental.enableResizeContent: true
|
|
experimental.preferences.javascriptEnabled: true
|
|
experimental.preferences.navigatorQtObjectEnabled: true
|
|
|
|
/*onLoadingChanged: {
|
|
console.log("onLoadingChanged:")
|
|
console.log(" url: ", loadRequest.url)
|
|
console.log(" status: ", loadRequest.status)
|
|
console.log(" error string: ", loadRequest.errorString)
|
|
console.log(" error code:: ", loadRequest.errorCode)
|
|
|
|
if (loadRequest.status === WebView.LoadSucceededStatus) {
|
|
console.log(" LoadSucceededStatus")
|
|
}
|
|
}*/
|
|
|
|
experimental.userScripts: [
|
|
Qt.resolvedUrl("js/Kaktus.js"),
|
|
Qt.resolvedUrl("js/Console.js"),
|
|
Qt.resolvedUrl("js/MessageListener.js"),
|
|
Qt.resolvedUrl("js/Readability.js"),
|
|
Qt.resolvedUrl("js/Theme.js"),
|
|
Qt.resolvedUrl("js/ReaderMode.js"),
|
|
Qt.resolvedUrl("js/init.js")]
|
|
|
|
experimental.onMessageReceived: {
|
|
console.log("onMessageReceived data:", message.data)
|
|
root.messageReceivedHandler(JSON.parse(message.data))
|
|
}
|
|
|
|
onNavigationRequested: {
|
|
if (!Qt.application.active) {
|
|
request.action = WebView.IgnoreRequest;
|
|
return
|
|
}
|
|
|
|
/*console.log("onNavigationRequested: ")
|
|
console.log(" url:",request.url)
|
|
console.log(" navigation type:", request.navigationType)
|
|
console.log(" navigation LinkClickedNavigation:", request.navigationType === WebView.LinkClickedNavigation)
|
|
console.log(" navigation FormSubmittedNavigation:", request.navigationType === WebView.FormSubmittedNavigation)
|
|
console.log(" navigation BackForwardNavigation:", request.navigationType === WebView.BackForwardNavigation)
|
|
console.log(" navigation ReloadNavigation:", request.navigationType === WebView.ReloadNavigation)
|
|
console.log(" navigation FormResubmittedNavigation:", request.navigationType === WebView.FormResubmittedNavigation)
|
|
console.log(" navigation OtherNavigation:", request.navigationType === WebView.OtherNavigation)
|
|
console.log(" action:", request.action)*/
|
|
|
|
if (request.url.toString() === root.onlineUrl ||
|
|
request.url.toString() === root.offlineUrl) {
|
|
|
|
if (_settings.webviewNavigation === 0) {
|
|
request.action = WebView.IgnoreRequest
|
|
return
|
|
}
|
|
|
|
if (_settings.webviewNavigation === 1 && !_settings.offlineMode) {
|
|
request.action = WebView.IgnoreRequest
|
|
root.openUrlEntryInBrowser(request.url)
|
|
return
|
|
}
|
|
|
|
root.openEntryInViewer()
|
|
request.action = WebView.IgnoreRequest
|
|
return
|
|
}
|
|
|
|
// Offline
|
|
if (settings.offlineMode) {
|
|
if (request.navigationType === WebView.LinkClickedNavigation) {
|
|
request.action = WebView.IgnoreRequest
|
|
} else {
|
|
request.action = WebView.AcceptRequest
|
|
}
|
|
return
|
|
}
|
|
|
|
// Online
|
|
if (request.navigationType === WebView.LinkClickedNavigation) {
|
|
|
|
if (_settings.webviewNavigation === 0) {
|
|
request.action = WebView.IgnoreRequest
|
|
return
|
|
}
|
|
|
|
if (_settings.webviewNavigation === 1) {
|
|
request.action = WebView.IgnoreRequest
|
|
root.openUrlEntryInBrowser(request.url)
|
|
return
|
|
}
|
|
|
|
if (_settings.webviewNavigation === 2) {
|
|
root.openUrlInViewer(request.url)
|
|
request.action = WebView.IgnoreRequest
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
|
|
header: PageHeader {
|
|
title: root.title
|
|
}
|
|
}
|
|
|
|
VerticalScrollDecorator {
|
|
flickable: view
|
|
}
|
|
|
|
TempBaner {
|
|
id: baner
|
|
anchors.centerIn: root
|
|
}
|
|
|
|
IconBar {
|
|
id: controlbar
|
|
flickable: view
|
|
color: root.bgColor
|
|
|
|
IconBarItem {
|
|
text: qsTr("Back")
|
|
icon: "image://theme/icon-m-back"
|
|
onClicked: root.navigateBack()
|
|
}
|
|
|
|
IconBarItem {
|
|
text: qsTr("Toggle Read")
|
|
icon: root.read ? "image://icons/icon-m-read-selected" : "image://icons/icon-m-read"
|
|
onClicked: {
|
|
root.autoRead=false;
|
|
if (root.read) {
|
|
root.read=false;
|
|
entryModel.setData(root.index, "read", 0, "");
|
|
} else {
|
|
root.read=true;
|
|
entryModel.setData(root.index, "read", 1, "");
|
|
}
|
|
}
|
|
}
|
|
|
|
IconBarItem {
|
|
text: app.isNetvibes ?
|
|
qsTr("Toggle Save") : qsTr("Toggle Star")
|
|
icon: root.stared ? "image://theme/icon-m-favorite-selected" : "image://theme/icon-m-favorite"
|
|
onClicked: {
|
|
if (root.stared) {
|
|
root.stared=false;
|
|
entryModel.setData(root.index, "readlater", 0, "");
|
|
} else {
|
|
root.stared=true;
|
|
entryModel.setData(root.index, "readlater", 1, "");
|
|
}
|
|
}
|
|
}
|
|
|
|
IconBarItem {
|
|
text: qsTr("Viewer")
|
|
icon: "image://icons/icon-m-webview"
|
|
onClicked: {
|
|
if (!root.check())
|
|
return;
|
|
root.openEntryInViewer();
|
|
}
|
|
}
|
|
|
|
IconBarItem {
|
|
text: qsTr("Browser")
|
|
icon: "image://icons/icon-m-browser"
|
|
onClicked: {
|
|
root.openEntryInBrowser();
|
|
}
|
|
}
|
|
|
|
IconMenuItem_ {
|
|
text: qsTr("Add to Pocket")
|
|
visible: settings.pocketEnabled
|
|
enabled: settings.pocketEnabled && dm.online
|
|
icon.source: "image://icons/icon-m-pocket?" + Theme.primaryColor
|
|
busy: pocket.busy
|
|
onClicked: {
|
|
pocket.add(root.onlineUrl, root.title)
|
|
}
|
|
}
|
|
|
|
// not available in harbour package
|
|
IconMenuItem_ {
|
|
text: qsTr("Share link")
|
|
icon.source: "image://theme/icon-m-share"
|
|
onClicked: root.share()
|
|
visible: !settings.isHarbour()
|
|
}
|
|
|
|
IconBarItem {
|
|
text: qsTr("Toggle Like")
|
|
icon: root.liked ? "image://icons/icon-m-like-selected" : "image://icons/icon-m-like"
|
|
enabled: settings.showBroadcast && app.isOldReader
|
|
onClicked: {
|
|
entryModel.setData(root.index, "liked", !root.liked, "");
|
|
root.liked = !root.liked
|
|
}
|
|
}
|
|
|
|
IconBarItem {
|
|
text: qsTr("Toggle Share")
|
|
icon: root.broadcast ? "image://icons/icon-m-share-selected" : "image://icons/icon-m-share"
|
|
enabled: settings.showBroadcast && app.isOldReader && !root.friendStream
|
|
onClicked: {
|
|
if (root.broadcast) {
|
|
entryModel.setData(root.index, "broadcast", false, "");
|
|
} else {
|
|
pageStack.push(Qt.resolvedUrl("ShareDialog.qml"),{"index": root.index});
|
|
}
|
|
root.broadcast = !root.broadcast
|
|
}
|
|
}
|
|
|
|
IconBarItem {
|
|
text: qsTr("Copy URL")
|
|
icon: "image://theme/icon-m-clipboard"
|
|
onClicked: {
|
|
notification.show(qsTr("URL was copied to the clipboard"));
|
|
Clipboard.text = root.onlineUrl;
|
|
}
|
|
}
|
|
|
|
IconBarItem {
|
|
text: qsTr("Decrease font")
|
|
icon: "image://icons/icon-m-fontdown"
|
|
onClicked: {
|
|
root.updateZoom(-0.1)
|
|
}
|
|
}
|
|
|
|
IconBarItem {
|
|
text: qsTr("Increase font")
|
|
icon: "image://icons/icon-m-fontup"
|
|
onClicked: {
|
|
root.updateZoom(0.1)
|
|
}
|
|
}
|
|
}
|
|
}
|