463 lines
14 KiB
QML
463 lines
14 KiB
QML
/* Copyright (C) 2014-2022 Michal Kosciesza <michal@mkiol.net>
|
|
*
|
|
* This Source Code Form is subject to the terms of the Mozilla Public
|
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
|
*/
|
|
|
|
import QtQuick 2.0
|
|
import Sailfish.Silica 1.0
|
|
import QtQuick.Window 2.0
|
|
|
|
import harbour.kaktus.Settings 1.0
|
|
|
|
ApplicationWindow {
|
|
id: app
|
|
|
|
property bool progress: false
|
|
property var oldViewMode
|
|
|
|
readonly property bool isTablet: Screen.sizeCategory === Screen.Large || Screen.sizeCategory === Screen.ExtraLarge
|
|
readonly property bool isNetvibes: settings.signinType >= 0 && settings.signinType < 10
|
|
readonly property bool isOldReader: settings.signinType >= 10 && settings.signinType < 20
|
|
readonly property bool isTTRss: settings.signinType >= 30 && settings.signinType < 40
|
|
readonly property int stdHeight: isPortraitOrientation(orientation) ? Theme.itemSizeMedium : 0.8 * Theme.itemSizeMedium
|
|
|
|
cover: CoverPage {}
|
|
|
|
Component.onCompleted: {
|
|
db.init();
|
|
|
|
if (settings.autoOffline) {
|
|
if (dm.online) {
|
|
if (settings.offlineMode) {
|
|
settings.offlineMode = false
|
|
}
|
|
} else {
|
|
if (!settings.offlineMode) {
|
|
settings.offlineMode = true
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
function isPortraitOrientation(orientation) {
|
|
return orientation === Orientation.Portrait || orientation === Orientation.PortraitInverted;
|
|
}
|
|
|
|
function hideBar() {
|
|
bar.hide();
|
|
}
|
|
|
|
function showBar() {
|
|
bar.show();
|
|
}
|
|
|
|
function resetView() {
|
|
if (!settings.signedIn) {
|
|
pageStack.replaceAbove(null,Qt.resolvedUrl("FirstPage.qml"));
|
|
return;
|
|
}
|
|
|
|
// Reconnect fetcher
|
|
if (typeof fetcher === 'undefined') {
|
|
var type = settings.signinType;
|
|
|
|
if (type < 10)
|
|
reconnectFetcher(1);
|
|
else if (type < 20)
|
|
reconnectFetcher(2);
|
|
else if (type < 30)
|
|
reconnectFetcher(3);
|
|
else if (type < 40)
|
|
reconnectFetcher(4);
|
|
}
|
|
|
|
utils.setRootModel();
|
|
|
|
var newViewMode = settings.viewMode;
|
|
if ((oldViewMode === Settings.AllEntries || oldViewMode === Settings.SavedEntries ||
|
|
oldViewMode === Settings.SlowEntries || oldViewMode === Settings.LikedEntries ||
|
|
oldViewMode === Settings.BroadcastedEntries) &&
|
|
(newViewMode === Settings.AllEntries || newViewMode === Settings.SavedEntries ||
|
|
newViewMode === Settings.SlowEntries || newViewMode === Settings.LikedEntries ||
|
|
newViewMode === Settings.BroadcastedEntries)) {
|
|
// No need to change stack
|
|
app.progress = false;
|
|
} else {
|
|
pageStack.busyChanged.connect(resetViewDone);
|
|
|
|
switch (settings.viewMode) {
|
|
case 0:
|
|
case 1:
|
|
pageStack.replaceAbove(null,Qt.resolvedUrl("TabPage.qml"));
|
|
break;
|
|
case 2:
|
|
pageStack.replaceAbove(null,Qt.resolvedUrl("FeedPage.qml"),{"title": qsTr("Feeds")});
|
|
break;
|
|
case 3:
|
|
case 4:
|
|
case 5:
|
|
case 6:
|
|
case 7:
|
|
pageStack.replaceAbove(null,Qt.resolvedUrl("EntryPage.qml"));
|
|
break;
|
|
}
|
|
}
|
|
|
|
oldViewMode = newViewMode;
|
|
}
|
|
|
|
function resetViewDone() {
|
|
if (!pageStack.busy) {
|
|
pageStack.busyChanged.disconnect(resetViewDone);
|
|
app.progress = false;
|
|
}
|
|
}
|
|
|
|
Connections {
|
|
target: settings
|
|
|
|
onError: {
|
|
console.log("Settings error: code=" + code);
|
|
Qt.quit();
|
|
}
|
|
|
|
onDashboardInUseChanged: {
|
|
resetView();
|
|
}
|
|
|
|
onViewModeChanged: {
|
|
resetView();
|
|
}
|
|
|
|
onSignedInChanged: {
|
|
if (!settings.signedIn) {
|
|
fetcher.cancel(); dm.cancel();
|
|
db.init();
|
|
}
|
|
}
|
|
|
|
onShowBroadcastChanged: {
|
|
if (!settings.showBroadcast && settings.viewMode === Settings.LikedEntries) {
|
|
settings.viewMode = Settings.SavedEntries;
|
|
}
|
|
}
|
|
}
|
|
|
|
Connections {
|
|
target: db
|
|
|
|
onError: {
|
|
console.log("DB error: code="+code);
|
|
if (code == 511) {
|
|
notification.show(qsTr("Restart the app to rebuild cache data"));
|
|
return;
|
|
}
|
|
Qt.quit();
|
|
}
|
|
|
|
onEmpty: {
|
|
dm.removeCache();
|
|
if (settings.viewMode !== Settings.TabsFeedsEntries)
|
|
settings.viewMode = Settings.TabsFeedsEntries;
|
|
else
|
|
resetView();
|
|
}
|
|
|
|
onNotEmpty: {
|
|
resetView()
|
|
}
|
|
}
|
|
|
|
Connections {
|
|
target: dm
|
|
|
|
onProgress: {
|
|
if (!app.fetcherBusyStatus) {
|
|
if (current > 0 && total != 0) {
|
|
bar.progressText= qsTr("Caching... %1 of %2").arg(current).arg(total);
|
|
bar.progress = current / total;
|
|
} else {
|
|
bar.progressText = qsTr("Caching...");
|
|
}
|
|
}
|
|
}
|
|
|
|
onOnlineChanged: {
|
|
if (settings.autoOffline) {
|
|
if (dm.online) {
|
|
if (settings.offlineMode) {
|
|
settings.offlineMode = false
|
|
}
|
|
} else {
|
|
if (!settings.offlineMode) {
|
|
settings.offlineMode = true
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
onNetworkNotAccessible: {
|
|
notification.show(qsTr("Download has failed because network is disconnected"));
|
|
}
|
|
|
|
onRemoverProgressChanged: {
|
|
bar.progress = current / total;
|
|
bar.progressText = qsTr("Removing cache data... %1 of %2").arg(current).arg(total);
|
|
}
|
|
}
|
|
|
|
function reconnectFetcher(type) {
|
|
disconnectFetcher();
|
|
cover.disconnectFetcher();
|
|
utils.resetFetcher(type);
|
|
connectFetcher();
|
|
cover.connectFetcher();
|
|
}
|
|
|
|
function connectFetcher() {
|
|
if (typeof fetcher === 'undefined')
|
|
return;
|
|
fetcher.ready.connect(fetcherReady);
|
|
fetcher.newAuthUrl.connect(fetcherNewAuthUrl);
|
|
fetcher.errorGettingAuthUrl.connect(fetcherErrorGettingAuthUrl);
|
|
fetcher.networkNotAccessible.connect(fetcherNetworkNotAccessible);
|
|
fetcher.error.connect(fetcherError);
|
|
fetcher.errorCheckingCredentials.connect(fetcherErrorCheckingCredentials);
|
|
fetcher.credentialsValid.connect(fetcherCredentialsValid);
|
|
fetcher.progress.connect(fetcherProgress);
|
|
fetcher.uploadProgress.connect(fetcherUploadProgress);
|
|
fetcher.uploading.connect(fetcherUploading);
|
|
fetcher.busyChanged.connect(fetcherBusyChanged);
|
|
fetcher.canceled.connect(fetcherCanceled);
|
|
fetcher.imageSaved.connect(fetcherImageSaved);
|
|
}
|
|
|
|
function disconnectFetcher() {
|
|
if (typeof fetcher === 'undefined')
|
|
return;
|
|
fetcher.ready.disconnect(fetcherReady);
|
|
fetcher.newAuthUrl.disconnect(fetcherNewAuthUrl);
|
|
fetcher.errorGettingAuthUrl.disconnect(fetcherErrorGettingAuthUrl);
|
|
fetcher.networkNotAccessible.disconnect(fetcherNetworkNotAccessible);
|
|
fetcher.error.disconnect(fetcherError);
|
|
fetcher.errorCheckingCredentials.disconnect(fetcherErrorCheckingCredentials);
|
|
fetcher.credentialsValid.disconnect(fetcherCredentialsValid);
|
|
fetcher.progress.disconnect(fetcherProgress);
|
|
fetcher.uploadProgress.disconnect(fetcherUploadProgress);
|
|
fetcher.uploading.disconnect(fetcherUploading);
|
|
fetcher.busyChanged.disconnect(fetcherBusyChanged);
|
|
fetcher.canceled.disconnect(fetcherCanceled);
|
|
fetcher.imageSaved.disconnect(fetcherImageSaved);
|
|
}
|
|
|
|
property bool fetcherBusyStatus: false
|
|
|
|
function fetcherReady() {
|
|
resetView();
|
|
|
|
switch (settings.cachingMode) {
|
|
case 0:
|
|
return;
|
|
case 1:
|
|
if (dm.isWLANConnected()) {
|
|
dm.startFeedDownload();
|
|
}
|
|
return;
|
|
case 2:
|
|
dm.startFeedDownload();
|
|
return;
|
|
}
|
|
}
|
|
|
|
function fetcherNewAuthUrl(url, type) {
|
|
pageStack.push(Qt.resolvedUrl("AuthWebViewPage.qml"),{"url":url,"type":type,"code": 400});
|
|
}
|
|
|
|
function fetcherErrorGettingAuthUrl() {
|
|
notification.show(qsTr("Unable to sign in"));
|
|
}
|
|
|
|
function fetcherNetworkNotAccessible() {
|
|
notification.show(qsTr("Network connection is unavailable"));
|
|
}
|
|
|
|
function fetcherError(code) {
|
|
console.log("Fetcher error: code=" + code);
|
|
|
|
if (code < 400)
|
|
return;
|
|
if (code === 700 || (code >= 400 && code < 500)) {
|
|
if (code === 402)
|
|
notification.show(qsTr("The user name or password is incorrect"));
|
|
else if (code === 404) // TT-RSS API disabled
|
|
notification.show(qsTr("Access through API is disabled on a server"));
|
|
else if (code === 700) // SSL error
|
|
notification.show(qsTr("Problem with SSL certificate"));
|
|
|
|
// Sign in
|
|
var type = settings.signinType;
|
|
if (type < 10) {
|
|
pageStack.push(Qt.resolvedUrl("NvSignInDialog.qml"),{"code": code});
|
|
return;
|
|
}
|
|
if (type < 20) {
|
|
pageStack.push(Qt.resolvedUrl("OldReaderSignInDialog.qml"),{"code": code});
|
|
return;
|
|
}
|
|
if (type < 40) {
|
|
pageStack.push(Qt.resolvedUrl("TTRssSignInDialog.qml"),{"code": code});
|
|
return;
|
|
}
|
|
} else if (code === 800) {
|
|
notification.show(qsTr("Cannot save image in gallery"));
|
|
} else if (code === 801) {
|
|
notification.show(qsTr("Image already exists in gallery"));
|
|
} else {
|
|
// Unknown error
|
|
notification.show(qsTr("Unknown error"));
|
|
resetView();
|
|
}
|
|
}
|
|
|
|
function fetcherErrorCheckingCredentials() {
|
|
notification.show(qsTr("The user name or password is incorrect"));
|
|
}
|
|
|
|
function fetcherCredentialsValid() {
|
|
notification.show(qsTr("You are signed in"));
|
|
}
|
|
|
|
function fetcherProgress(current, total) {
|
|
//console.log("fetcherProgress", current, total);
|
|
bar.progressText = qsTr("Receiving data...");
|
|
bar.progress = current / total;
|
|
}
|
|
|
|
function fetcherUploadProgress(current, total) {
|
|
//console.log("fetcherUploadProgress", current, total);
|
|
bar.progressText = qsTr("Sending data...");
|
|
bar.progress = current / total;
|
|
}
|
|
|
|
function fetcherUploading() {
|
|
//console.log("fetcherUploading");
|
|
bar.progressText = qsTr("Sending data...");
|
|
}
|
|
|
|
function fetcherBusyChanged() {
|
|
//console.log("fetcherBusyChanged:", fetcher.busy, app.fetcherBusyStatus)
|
|
if (app.fetcherBusyStatus != fetcher.busy)
|
|
app.fetcherBusyStatus = fetcher.busy;
|
|
|
|
switch(fetcher.busyType) {
|
|
case 1:
|
|
bar.progressText = qsTr("Initiating...");
|
|
bar.progress = 0;
|
|
break;
|
|
case 2:
|
|
bar.progressText = qsTr("Updating...");
|
|
bar.progress = 0;
|
|
break;
|
|
case 3:
|
|
bar.progressText = qsTr("Signing in...");
|
|
bar.progress = 0;
|
|
break;
|
|
case 4:
|
|
bar.progressText = qsTr("Signing in...");
|
|
bar.progress = 0;
|
|
break;
|
|
case 11:
|
|
bar.progressText = qsTr("Waiting for network...");
|
|
bar.progress = 0;
|
|
break;
|
|
case 21:
|
|
bar.progressText = qsTr("Waiting for network...");
|
|
bar.progress = 0;
|
|
break;
|
|
case 31:
|
|
bar.progressText = qsTr("Waiting for network...");
|
|
bar.progress = 0;
|
|
break;
|
|
}
|
|
}
|
|
|
|
function fetcherCanceled() {
|
|
resetView();
|
|
}
|
|
|
|
function fetcherImageSaved(filename) {
|
|
notification.show(qsTr("Image saved in gallery as \"" + filename + "\""));
|
|
}
|
|
|
|
Notification {
|
|
id: notification
|
|
}
|
|
|
|
property int panelWidth: isPortraitOrientation(app.orientation) ? Screen.width : Screen.height
|
|
property int landscapeContentPanelWidth: isTablet ?
|
|
isPortraitOrientation(app.orientation) ? Screen.width-700 : Screen.height-700 :
|
|
isPortraitOrientation(app.orientation) ? Screen.width/2 : Screen.height/2
|
|
property int flickHeight: {
|
|
var size = 0
|
|
if (bar.open)
|
|
size += bar.stdHeight
|
|
return isPortraitOrientation(app.orientation) ? Screen.height-size : Screen.width-size;
|
|
}
|
|
|
|
property int barX: {
|
|
switch (app.orientation) {
|
|
case Orientation.Portrait: return 0;
|
|
case Orientation.Landscape: return bar.height;
|
|
case Orientation.PortraitInverted: return Screen.width;
|
|
case Orientation.LandscapeInverted: return Screen.width - bar.height;
|
|
}
|
|
}
|
|
|
|
property int barY: {
|
|
switch (app.orientation) {
|
|
case Orientation.Portrait: return Screen.height - bar.height;
|
|
case Orientation.Landscape: return 0;
|
|
case Orientation.PortraitInverted: return bar.height;
|
|
case Orientation.LandscapeInverted: return Screen.height;
|
|
}
|
|
}
|
|
|
|
readonly property alias barHeight: bar.height
|
|
|
|
ControlBar {
|
|
id: bar
|
|
busy: app.fetcherBusyStatus || dm.removerBusy || dm.busy
|
|
|
|
rotation: {
|
|
switch (app.orientation) {
|
|
case Orientation.Portrait: return 0;
|
|
case Orientation.Landscape: return 90;
|
|
case Orientation.PortraitInverted: return 180;
|
|
case Orientation.LandscapeInverted: return 270;
|
|
}
|
|
}
|
|
|
|
transformOrigin: Item.TopLeft
|
|
width: app.panelWidth
|
|
|
|
onCancelClicked: {
|
|
dm.cancel()
|
|
fetcher.cancel()
|
|
dm.removerCancel()
|
|
}
|
|
|
|
onBusyChanged: {
|
|
if (!busy) hide()
|
|
}
|
|
|
|
y: app.barY
|
|
x: app.barX
|
|
}
|
|
|
|
Pocket {
|
|
id: pocket
|
|
}
|
|
}
|
|
|