mirror of https://github.com/KDE/kasts.git
Add capability to check whether network connection is metered
For now this only works with NetworkManager. The related settings are greyed out on systems not using NetworkManager. Some details of the implementation: - Implement settings in the settings menu to enable/disable feed updates, episode downloads and/ or image downloads on metered connections. If the option(s) is disabled, an overlay dialog is shown with options to "not allow", "allow once", or "allow always". - If the network is down, no attempt is made to download images and the fallback image will be used until the network is up again. This also solves an issue where the application hangs when the network is down and feed images have not been cached yet. - Next to this, part of the cachedImage implementation in Entry and Feed has been refactored to re-use code as part of the image() method in Fetcher. - In case something unexpected happens, an error will be logged.
This commit is contained in:
parent
acef37fa58
commit
d0bc5b2b26
|
@ -91,6 +91,7 @@ else()
|
|||
|
||||
qt5_add_dbus_interface(SRCS dbus-interfaces/org.freedesktop.PowerManagement.Inhibit.xml inhibitinterface)
|
||||
qt5_add_dbus_interface(SRCS dbus-interfaces/org.gnome.SessionManager.xml gnomesessioninterface)
|
||||
qt5_add_dbus_interface(SRCS dbus-interfaces/org.freedesktop.NetworkManager.xml NMinterface)
|
||||
endif()
|
||||
|
||||
add_executable(kasts ${SRCS})
|
||||
|
|
|
@ -0,0 +1,14 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!--
|
||||
SPDX-FileCopyrightText: none
|
||||
SPDX-License-Identifier: CC0-1.0
|
||||
-->
|
||||
<!DOCTYPE node PUBLIC "-//freedesktop//DTD D-BUS Object Introspection 1.0//EN" "http://www.freedesktop.org/standards/dbus/1.0/introspect.dtd">
|
||||
<node name="/">
|
||||
<interface name="org.freedesktop.NetworkManager">
|
||||
<method name="state">
|
||||
<arg name="state" type="u" direction="out"/>
|
||||
</method>
|
||||
<property name="Metered" type="u" access="read"/>
|
||||
</interface>
|
||||
</node>
|
|
@ -8,6 +8,7 @@
|
|||
#include "enclosure.h"
|
||||
#include "enclosurelogging.h"
|
||||
|
||||
#include <KLocalizedString>
|
||||
#include <QFile>
|
||||
#include <QNetworkReply>
|
||||
#include <QSqlQuery>
|
||||
|
@ -21,6 +22,7 @@
|
|||
#include "error.h"
|
||||
#include "errorlogmodel.h"
|
||||
#include "fetcher.h"
|
||||
#include "settingsmanager.h"
|
||||
|
||||
Enclosure::Enclosure(Entry *entry)
|
||||
: QObject(entry)
|
||||
|
@ -84,6 +86,15 @@ Enclosure::Status Enclosure::dbToStatus(int value)
|
|||
|
||||
void Enclosure::download()
|
||||
{
|
||||
if (Fetcher::instance().isMeteredConnection() && !SettingsManager::self()->allowMeteredEpisodeDownloads()) {
|
||||
Q_EMIT downloadError(Error::Type::MeteredNotAllowed,
|
||||
m_entry->feed()->url(),
|
||||
m_entry->id(),
|
||||
0,
|
||||
i18n("Podcast downloads not allowed due to user setting"));
|
||||
return;
|
||||
}
|
||||
|
||||
checkSizeOnDisk();
|
||||
EnclosureDownloadJob *downloadJob = new EnclosureDownloadJob(m_url, path(), m_entry->title());
|
||||
downloadJob->start();
|
||||
|
|
|
@ -217,16 +217,7 @@ QString Entry::cachedImage() const
|
|||
image = m_feed->image();
|
||||
}
|
||||
|
||||
if (image.isEmpty()) { // this will only happen if the feed also doesn't have an image
|
||||
return QStringLiteral("no-image");
|
||||
} else {
|
||||
QString imagePath = Fetcher::instance().image(image);
|
||||
if (imagePath.isEmpty()) {
|
||||
return QStringLiteral("fetching");
|
||||
} else {
|
||||
return QStringLiteral("file://") + imagePath;
|
||||
}
|
||||
}
|
||||
return Fetcher::instance().image(image);
|
||||
}
|
||||
|
||||
bool Entry::queueStatus() const
|
||||
|
|
11
src/feed.cpp
11
src/feed.cpp
|
@ -152,16 +152,7 @@ QString Feed::image() const
|
|||
|
||||
QString Feed::cachedImage() const
|
||||
{
|
||||
if (m_image.isEmpty()) {
|
||||
return QStringLiteral("no-image");
|
||||
} else {
|
||||
QString imagePath = Fetcher::instance().image(m_image);
|
||||
if (imagePath.isEmpty()) {
|
||||
return QStringLiteral("fetching");
|
||||
} else {
|
||||
return QStringLiteral("file://") + imagePath;
|
||||
}
|
||||
}
|
||||
return Fetcher::instance().image(m_image);
|
||||
}
|
||||
|
||||
QString Feed::link() const
|
||||
|
|
|
@ -5,6 +5,7 @@
|
|||
* SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only OR LicenseRef-KDE-Accepted-GPL
|
||||
*/
|
||||
|
||||
#include <KLocalizedString>
|
||||
#include <QCryptographicHash>
|
||||
#include <QDateTime>
|
||||
#include <QDebug>
|
||||
|
@ -36,6 +37,13 @@ Fetcher::Fetcher()
|
|||
manager->setRedirectPolicy(QNetworkRequest::NoLessSafeRedirectPolicy);
|
||||
manager->setStrictTransportSecurityEnabled(true);
|
||||
manager->enableStrictTransportSecurityStore(true);
|
||||
|
||||
#if !defined Q_OS_ANDROID && !defined Q_OS_WIN
|
||||
m_nmInterface = new OrgFreedesktopNetworkManagerInterface(QStringLiteral("org.freedesktop.NetworkManager"),
|
||||
QStringLiteral("/org/freedesktop/NetworkManager"),
|
||||
QDBusConnection::systemBus(),
|
||||
this);
|
||||
#endif
|
||||
}
|
||||
|
||||
void Fetcher::fetch(const QString &url)
|
||||
|
@ -80,6 +88,13 @@ void Fetcher::fetchAll()
|
|||
|
||||
void Fetcher::retrieveFeed(const QString &url)
|
||||
{
|
||||
if (isMeteredConnection() && !SettingsManager::self()->allowMeteredFeedUpdates()) {
|
||||
Q_EMIT error(Error::Type::MeteredNotAllowed, url, QString(), 0, i18n("Podcast updates not allowed due to user setting"));
|
||||
m_updateProgress++;
|
||||
Q_EMIT updateProgressChanged(m_updateProgress);
|
||||
return;
|
||||
}
|
||||
|
||||
qCDebug(kastsFetcher) << "Starting to fetch" << url;
|
||||
|
||||
Q_EMIT startedFetchingFeed(url);
|
||||
|
@ -346,15 +361,31 @@ void Fetcher::processEnclosure(Syndication::EnclosurePtr enclosure, Syndication:
|
|||
|
||||
QString Fetcher::image(const QString &url) const
|
||||
{
|
||||
QString path = imagePath(url);
|
||||
if (QFileInfo::exists(path)) {
|
||||
if (QFileInfo(path).size() != 0)
|
||||
return path;
|
||||
if (url.isEmpty()) {
|
||||
return QLatin1String("no-image");
|
||||
}
|
||||
|
||||
download(url, path);
|
||||
// if image is already cached, then return the path
|
||||
QString path = imagePath(url);
|
||||
if (QFileInfo::exists(path)) {
|
||||
if (QFileInfo(path).size() != 0) {
|
||||
return QStringLiteral("file://") + path;
|
||||
}
|
||||
}
|
||||
|
||||
return QLatin1String("");
|
||||
// if image has not yet been cached, then check for network connectivity if
|
||||
// possible; and download the image
|
||||
if (canCheckNetworkStatus()) {
|
||||
if (networkConnected() && (!isMeteredConnection() || SettingsManager::self()->allowMeteredImageDownloads())) {
|
||||
download(url, path);
|
||||
} else {
|
||||
return QLatin1String("no-image");
|
||||
}
|
||||
} else {
|
||||
download(url, path);
|
||||
}
|
||||
|
||||
return QLatin1String("fetching");
|
||||
}
|
||||
|
||||
QNetworkReply *Fetcher::download(const QString &url, const QString &filePath) const
|
||||
|
@ -456,3 +487,43 @@ void Fetcher::setHeader(QNetworkRequest &request) const
|
|||
{
|
||||
request.setRawHeader("User-Agent", "Kasts/0.1; Syndication");
|
||||
}
|
||||
|
||||
bool Fetcher::canCheckNetworkStatus() const
|
||||
{
|
||||
#if !defined Q_OS_ANDROID && !defined Q_OS_WIN
|
||||
qCDebug(kastsFetcher) << "Can NetworkManager be reached?" << m_nmInterface->isValid();
|
||||
return (m_nmInterface && m_nmInterface->isValid());
|
||||
#else
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
|
||||
bool Fetcher::networkConnected() const
|
||||
{
|
||||
#if !defined Q_OS_ANDROID && !defined Q_OS_WIN
|
||||
qCDebug(kastsFetcher) << "Network connected?" << (m_nmInterface->state() >= 70) << m_nmInterface->state();
|
||||
return (m_nmInterface && m_nmInterface->state() >= 70);
|
||||
#else
|
||||
return true;
|
||||
#endif
|
||||
}
|
||||
|
||||
bool Fetcher::isMeteredConnection() const
|
||||
{
|
||||
#if !defined Q_OS_ANDROID && !defined Q_OS_WIN
|
||||
if (canCheckNetworkStatus()) {
|
||||
// Get network connection status through DBus (NetworkManager)
|
||||
// state == 1: explicitly configured as metered
|
||||
// state == 3: connection guessed as metered
|
||||
uint state = m_nmInterface->metered();
|
||||
qCDebug(kastsFetcher) << "Network Status:" << state;
|
||||
qCDebug(kastsFetcher) << "Connection is metered?" << (state == 1 || state == 3);
|
||||
return (state == 1 || state == 3);
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
#else
|
||||
// TODO: get network connection type for Android and windows
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
|
|
|
@ -16,6 +16,10 @@
|
|||
|
||||
#include "error.h"
|
||||
|
||||
#if !defined Q_OS_ANDROID && !defined Q_OS_WIN
|
||||
#include "NMinterface.h"
|
||||
#endif
|
||||
|
||||
class Fetcher : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
|
@ -41,6 +45,11 @@ public:
|
|||
QString imagePath(const QString &url) const;
|
||||
QString enclosurePath(const QString &url) const;
|
||||
|
||||
// Network status related methods
|
||||
Q_INVOKABLE bool canCheckNetworkStatus() const;
|
||||
bool networkConnected() const;
|
||||
Q_INVOKABLE bool isMeteredConnection() const;
|
||||
|
||||
Q_SIGNALS:
|
||||
void startedFetchingFeed(const QString &url);
|
||||
void feedUpdated(const QString &url);
|
||||
|
@ -79,4 +88,8 @@ private:
|
|||
int m_updateProgress;
|
||||
int m_updateTotal;
|
||||
bool m_updating;
|
||||
|
||||
#if !defined Q_OS_ANDROID && !defined Q_OS_WIN
|
||||
OrgFreedesktopNetworkManagerInterface *m_nmInterface;
|
||||
#endif
|
||||
};
|
||||
|
|
|
@ -32,6 +32,7 @@
|
|||
#include "androidlogging.h"
|
||||
#endif
|
||||
#include "audiomanager.h"
|
||||
#include "author.h"
|
||||
#include "database.h"
|
||||
#include "datamanager.h"
|
||||
#include "downloadmodel.h"
|
||||
|
|
|
@ -30,13 +30,22 @@ Kirigami.OverlaySheet {
|
|||
Layout.fillWidth: true
|
||||
text: "https://"
|
||||
}
|
||||
|
||||
// This item can be used to trigger the addition of a feed; it will open an
|
||||
// overlay with options in case the operation is not allowed by the settings
|
||||
ConnectionCheckAction {
|
||||
id: addFeed
|
||||
function action() {
|
||||
DataManager.addFeed(urlField.text)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
footer: Controls.Button {
|
||||
text: i18n("Add Podcast")
|
||||
enabled: urlField.text
|
||||
onClicked: {
|
||||
DataManager.addFeed(urlField.text)
|
||||
addFeed.run()
|
||||
addSheet.close()
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,102 @@
|
|||
/**
|
||||
* SPDX-FileCopyrightText: 2021 Bart De Vries <bart@mogwai.be>
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only OR LicenseRef-KDE-Accepted-GPL
|
||||
*/
|
||||
|
||||
import QtQuick 2.14
|
||||
import QtQuick.Controls 2.14 as Controls
|
||||
import QtQuick.Layouts 1.14
|
||||
|
||||
import org.kde.kirigami 2.14 as Kirigami
|
||||
|
||||
import org.kde.kasts 1.0
|
||||
|
||||
Kirigami.OverlaySheet {
|
||||
id: overlay
|
||||
parent: applicationWindow().overlay
|
||||
|
||||
property string headingText: i18n("Podcast updates are currently not allowed on metered connections")
|
||||
property bool condition: SettingsManager.allowMeteredFeedUpdates
|
||||
|
||||
// Function to be overloaded where this is instantiated with another purpose
|
||||
// than refreshing all feeds
|
||||
function action() {
|
||||
Fetcher.fetchAll();
|
||||
}
|
||||
|
||||
// This function will be executed when "Don't allow" is chosen; can be overloaded
|
||||
function abortAction() { }
|
||||
|
||||
// This function will be executed when the "Allow once" action is chosen; can be overloaded
|
||||
function allowOnceAction() {
|
||||
SettingsManager.allowMeteredFeedUpdates = true;
|
||||
action()
|
||||
SettingsManager.allowMeteredFeedUpdates = false;
|
||||
}
|
||||
|
||||
// This function will be executed when the "Always allow" action is chosed; can be overloaded
|
||||
function alwaysAllowAction() {
|
||||
SettingsManager.allowMeteredFeedUpdates = true;
|
||||
action()
|
||||
}
|
||||
|
||||
// this is the function that should be called if the action should be
|
||||
// triggered conditionally (on the basis that the condition is passed)
|
||||
function run() {
|
||||
if (!Fetcher.isMeteredConnection() || condition) {
|
||||
action();
|
||||
} else {
|
||||
overlay.open();
|
||||
}
|
||||
}
|
||||
|
||||
header: Kirigami.Heading {
|
||||
text: overlay.headingText
|
||||
level: 2
|
||||
wrapMode: Text.Wrap
|
||||
elide: Text.ElideRight
|
||||
maximumLineCount: 3
|
||||
}
|
||||
|
||||
contentItem: ColumnLayout {
|
||||
|
||||
spacing: 0
|
||||
|
||||
Kirigami.BasicListItem {
|
||||
Layout.fillWidth: true
|
||||
Layout.preferredHeight: Kirigami.Units.gridUnit * 2
|
||||
leftPadding: Kirigami.Units.smallSpacing
|
||||
rightPadding: 0
|
||||
text: i18n("Don't Allow")
|
||||
onClicked: {
|
||||
abortAction();
|
||||
close();
|
||||
}
|
||||
}
|
||||
|
||||
Kirigami.BasicListItem {
|
||||
Layout.fillWidth: true
|
||||
Layout.preferredHeight: Kirigami.Units.gridUnit * 2
|
||||
leftPadding: Kirigami.Units.smallSpacing
|
||||
rightPadding: 0
|
||||
text: i18n("Allow Once")
|
||||
onClicked: {
|
||||
allowOnceAction();
|
||||
close();
|
||||
}
|
||||
}
|
||||
|
||||
Kirigami.BasicListItem {
|
||||
Layout.fillWidth: true
|
||||
Layout.preferredHeight: Kirigami.Units.gridUnit * 2
|
||||
leftPadding: Kirigami.Units.smallSpacing
|
||||
rightPadding: 0
|
||||
text: i18n("Always Allow")
|
||||
onClicked: {
|
||||
alwaysAllowAction();
|
||||
close();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -21,16 +21,16 @@ Kirigami.ScrollablePage {
|
|||
supportsRefreshing: true
|
||||
onRefreshingChanged: {
|
||||
if(refreshing) {
|
||||
Fetcher.fetchAll()
|
||||
refreshing = false
|
||||
updateAllFeeds.run();
|
||||
refreshing = false;
|
||||
}
|
||||
}
|
||||
|
||||
actions.main: Kirigami.Action {
|
||||
iconName: "view-refresh"
|
||||
text: i18n("Refresh All Podcasts")
|
||||
onTriggered: refreshing = true
|
||||
visible: !Kirigami.Settings.isMobile
|
||||
onTriggered: Fetcher.fetchAll()
|
||||
}
|
||||
|
||||
Kirigami.PlaceholderMessage {
|
||||
|
|
|
@ -21,11 +21,26 @@ Kirigami.ScrollablePage {
|
|||
title: feed.name
|
||||
supportsRefreshing: true
|
||||
|
||||
onRefreshingChanged:
|
||||
onRefreshingChanged: {
|
||||
if(refreshing) {
|
||||
updateFeed.run()
|
||||
}
|
||||
}
|
||||
|
||||
// Overlay dialog box showing options what to do on metered connections
|
||||
ConnectionCheckAction {
|
||||
id: updateFeed
|
||||
|
||||
function action() {
|
||||
feed.refresh()
|
||||
}
|
||||
|
||||
function abortAction() {
|
||||
page.refreshing = false
|
||||
}
|
||||
}
|
||||
|
||||
// Make sure that this feed is also showing as "refreshing" on FeedListPage
|
||||
Connections {
|
||||
target: feed
|
||||
function onRefreshingChanged(refreshing) {
|
||||
|
|
|
@ -105,7 +105,8 @@ Kirigami.ScrollablePage {
|
|||
if (!entry.enclosure) {
|
||||
Qt.openUrlExternally(entry.link)
|
||||
} else if (entry.enclosure.status === Enclosure.Downloadable || entry.enclosure.status === Enclosure.PartiallyDownloaded) {
|
||||
entry.enclosure.download()
|
||||
downloadOverlay.entry = entry;
|
||||
downloadOverlay.run();
|
||||
} else if (entry.enclosure.status === Enclosure.Downloading) {
|
||||
entry.enclosure.cancelDownload()
|
||||
} else if (!entry.queueStatus) {
|
||||
|
@ -164,4 +165,4 @@ Kirigami.ScrollablePage {
|
|||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
|
@ -20,8 +20,8 @@ Kirigami.ScrollablePage {
|
|||
supportsRefreshing: true
|
||||
onRefreshingChanged: {
|
||||
if(refreshing) {
|
||||
Fetcher.fetchAll()
|
||||
refreshing = false
|
||||
updateAllFeeds.run();
|
||||
refreshing = false;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -22,7 +22,7 @@ Kirigami.Page {
|
|||
iconName: "view-refresh"
|
||||
text: i18n("Refresh All Podcasts")
|
||||
visible: !Kirigami.Settings.isMobile
|
||||
onTriggered: Fetcher.fetchAll()
|
||||
onTriggered: updateAllFeeds.run()
|
||||
}
|
||||
|
||||
header: Loader {
|
||||
|
|
|
@ -26,8 +26,8 @@ Kirigami.ScrollablePage {
|
|||
supportsRefreshing: true
|
||||
onRefreshingChanged: {
|
||||
if(refreshing) {
|
||||
Fetcher.fetchAll()
|
||||
refreshing = false
|
||||
updateAllFeeds.run();
|
||||
refreshing = false;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -194,8 +194,8 @@ Kirigami.SwipeListItem {
|
|||
text: i18n("Download")
|
||||
icon.name: "download"
|
||||
onTriggered: {
|
||||
entry.queueStatus = true;
|
||||
entry.enclosure.download();
|
||||
downloadOverlay.entry = entry;
|
||||
downloadOverlay.run();
|
||||
}
|
||||
visible: (!isDownloads || entry.enclosure.status === Enclosure.PartiallyDownloaded) && entry.enclosure && (entry.enclosure.status === Enclosure.Downloadable || entry.enclosure.status === Enclosure.PartiallyDownloaded)
|
||||
},
|
||||
|
|
|
@ -22,8 +22,8 @@ Kirigami.ScrollablePage {
|
|||
supportsRefreshing: true
|
||||
onRefreshingChanged: {
|
||||
if(refreshing) {
|
||||
Fetcher.fetchAll()
|
||||
refreshing = false
|
||||
updateAllFeeds.run();
|
||||
refreshing = false;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -20,7 +20,18 @@ Kirigami.ScrollablePage {
|
|||
|
||||
Kirigami.Heading {
|
||||
Kirigami.FormData.isSection: true
|
||||
text: i18n("Appearance")
|
||||
}
|
||||
|
||||
Controls.CheckBox {
|
||||
id: alwaysShowFeedTitles
|
||||
checked: SettingsManager.alwaysShowFeedTitles
|
||||
text: i18n("Always show podcast titles in subscription view")
|
||||
onToggled: SettingsManager.alwaysShowFeedTitles = checked
|
||||
}
|
||||
|
||||
Kirigami.Heading {
|
||||
Kirigami.FormData.isSection: true
|
||||
text: i18n("Play Settings")
|
||||
}
|
||||
|
||||
|
@ -68,15 +79,32 @@ Kirigami.ScrollablePage {
|
|||
|
||||
Kirigami.Heading {
|
||||
Kirigami.FormData.isSection: true
|
||||
text: i18n("Appearance")
|
||||
text: i18n("Network")
|
||||
}
|
||||
|
||||
Controls.CheckBox {
|
||||
id: allowMeteredFeedUpdates
|
||||
checked: SettingsManager.allowMeteredFeedUpdates || !Fetcher.canCheckNetworkStatus()
|
||||
Kirigami.FormData.label: i18n("On metered connections:")
|
||||
text: i18n("Allow podcast updates")
|
||||
onToggled: SettingsManager.allowMeteredFeedUpdates = checked
|
||||
enabled: Fetcher.canCheckNetworkStatus()
|
||||
}
|
||||
|
||||
Controls.CheckBox {
|
||||
id: alwaysShowFeedTitles
|
||||
checked: SettingsManager.alwaysShowFeedTitles
|
||||
text: i18n("Always show podcast titles in subscription view")
|
||||
onToggled: SettingsManager.alwaysShowFeedTitles = checked
|
||||
id: allowMeteredEpisodeDownloads
|
||||
checked: SettingsManager.allowMeteredEpisodeDownloads || !Fetcher.canCheckNetworkStatus()
|
||||
text: i18n("Allow episode downloads")
|
||||
onToggled: SettingsManager.allowMeteredEpisodeDownloads = checked
|
||||
enabled: Fetcher.canCheckNetworkStatus()
|
||||
}
|
||||
|
||||
Controls.CheckBox {
|
||||
id: allowMeteredImageDownloads
|
||||
checked: SettingsManager.allowMeteredImageDownloads || !Fetcher.canCheckNetworkStatus()
|
||||
text: i18n("Allow image downloads")
|
||||
onToggled: SettingsManager.allowMeteredImageDownloads = checked
|
||||
enabled: Fetcher.canCheckNetworkStatus()
|
||||
}
|
||||
|
||||
Kirigami.Heading {
|
||||
|
|
|
@ -58,7 +58,13 @@ Kirigami.ApplicationWindow {
|
|||
: 0
|
||||
currentPage = SettingsManager.lastOpenedPage
|
||||
pageStack.initialPage = getPage(SettingsManager.lastOpenedPage)
|
||||
if (SettingsManager.refreshOnStartup) Fetcher.fetchAll();
|
||||
|
||||
// Refresh feeds on startup if allowed
|
||||
if (SettingsManager.refreshOnStartup) {
|
||||
if (SettingsManager.allowMeteredFeedUpdates || !Fetcher.isMeteredConnection()) {
|
||||
Fetcher.fetchAll();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
globalDrawer: Kirigami.GlobalDrawer {
|
||||
|
@ -211,6 +217,9 @@ Kirigami.ApplicationWindow {
|
|||
|
||||
}
|
||||
|
||||
// Notification that shows the progress of feed updates
|
||||
// It mimicks the behaviour of an InlineMessage, because InlineMessage does
|
||||
// not allow to add a BusyIndicator
|
||||
UpdateNotification {
|
||||
z: 2
|
||||
id: updateNotification
|
||||
|
@ -222,6 +231,7 @@ Kirigami.ApplicationWindow {
|
|||
}
|
||||
}
|
||||
|
||||
// This InlineMessage is used for displaying error messages
|
||||
ErrorNotification {
|
||||
id: errorNotification
|
||||
}
|
||||
|
@ -230,4 +240,35 @@ Kirigami.ApplicationWindow {
|
|||
ErrorListOverlay {
|
||||
id: errorOverlay
|
||||
}
|
||||
|
||||
// This item can be used to trigger an update of all feeds; it will open an
|
||||
// overlay with options in case the operation is not allowed by the settings
|
||||
ConnectionCheckAction {
|
||||
id: updateAllFeeds
|
||||
}
|
||||
|
||||
// Overlay with options what to do when metered downloads are not allowed
|
||||
ConnectionCheckAction {
|
||||
id: downloadOverlay
|
||||
|
||||
headingText: i18n("Podcast downloads are currently not allowed on metered connections")
|
||||
condition: SettingsManager.allowMeteredEpisodeDownloads
|
||||
property var entry: undefined
|
||||
|
||||
function action() {
|
||||
entry.queueStatus = true;
|
||||
entry.enclosure.download();
|
||||
}
|
||||
|
||||
function allowOnceAction() {
|
||||
SettingsManager.allowMeteredEpisodeDownloads = true;
|
||||
action();
|
||||
SettingsManager.allowMeteredEpisodeDownloads = false;
|
||||
}
|
||||
|
||||
function alwaysAllowAction() {
|
||||
SettingsManager.allowMeteredEpisodeDownloads = true;
|
||||
action();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -25,6 +25,7 @@
|
|||
<file alias="UpdateNotification.qml">qml/UpdateNotification.qml</file>
|
||||
<file alias="HeaderBar.qml">qml/HeaderBar.qml</file>
|
||||
<file alias="ErrorNotification.qml">qml/ErrorNotification.qml</file>
|
||||
<file alias="ConnectionCheckAction.qml">qml/ConnectionCheckAction.qml</file>
|
||||
<file>qtquickcontrols2.conf</file>
|
||||
<file alias="logo.svg">../kasts.svg</file>
|
||||
</qresource>
|
||||
|
|
|
@ -38,6 +38,20 @@
|
|||
<default>true</default>
|
||||
</entry>
|
||||
</group>
|
||||
<group name="Network">
|
||||
<entry name="allowMeteredFeedUpdates" type="Bool">
|
||||
<label>Allow podcast updates on metered connections</label>
|
||||
<default>false</default>
|
||||
</entry>
|
||||
<entry name="allowMeteredEpisodeDownloads" type="Bool">
|
||||
<label>Allow podcast downloads on metered connections</label>
|
||||
<default>false</default>
|
||||
</entry>
|
||||
<entry name="allowMeteredImageDownloads" type="Bool">
|
||||
<label>Allow image downloads on metered connections</label>
|
||||
<default>false</default>
|
||||
</entry>
|
||||
</group>
|
||||
<group name="Persistency">
|
||||
<entry name="lastOpenedPage" type="String">
|
||||
<label>The top-level page that was open at shutdown</label>
|
||||
|
|
Loading…
Reference in New Issue