From a50c8bf001d4f2a54e471b6c7c664f8a27d5072a Mon Sep 17 00:00:00 2001 From: Bart De Vries Date: Wed, 21 Apr 2021 23:09:19 +0200 Subject: [PATCH] Add capability to monitor ongoing downloads --- src/CMakeLists.txt | 1 + src/downloadprogressmodel.cpp | 53 +++++++++++++++++++++++++++++++++++ src/downloadprogressmodel.h | 38 +++++++++++++++++++++++++ src/enclosure.cpp | 7 +++++ src/enclosure.h | 1 + src/main.cpp | 11 ++++---- src/qml/DownloadSwipePage.qml | 4 +-- src/qml/EpisodeListPage.qml | 21 ++++++++++---- 8 files changed, 123 insertions(+), 13 deletions(-) create mode 100644 src/downloadprogressmodel.cpp create mode 100644 src/downloadprogressmodel.h diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 8977166f..5a2c494a 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -11,6 +11,7 @@ add_executable(alligator enclosuredownloadjob.cpp queuemodel.cpp episodemodel.cpp + downloadprogressmodel.cpp datamanager.cpp audiomanager.cpp powermanagementinterface.cpp diff --git a/src/downloadprogressmodel.cpp b/src/downloadprogressmodel.cpp new file mode 100644 index 00000000..f13d9724 --- /dev/null +++ b/src/downloadprogressmodel.cpp @@ -0,0 +1,53 @@ +/** + * SPDX-FileCopyrightText: 2021 Bart De Vries + * + * SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only OR LicenseRef-KDE-Accepted-GPL + */ + +#include "downloadprogressmodel.h" +#include "datamanager.h" + + +DownloadProgressModel::DownloadProgressModel() + : QAbstractListModel(nullptr) +{ + m_entries.clear(); +} + +QVariant DownloadProgressModel::data(const QModelIndex &index, int role) const +{ + if (role != 0) + return QVariant(); + return QVariant::fromValue(DataManager::instance().getEntry(m_entries[index.row()])); +} + +QHash DownloadProgressModel::roleNames() const +{ + QHash roleNames; + roleNames[0] = "entry"; + return roleNames; +} + +int DownloadProgressModel::rowCount(const QModelIndex &parent) const +{ + Q_UNUSED(parent) + return m_entries.count(); +} + +void DownloadProgressModel::monitorDownloadProgress(Entry* entry, Enclosure::Status status) +{ + qDebug() << "download status changed:" << entry->title() << status; + if (status == Enclosure::Downloading && !m_entries.contains(entry->id())) { + qDebug() << "inserting dowloading entry" << entry->id() << "in position" << m_entries.count(); + beginInsertRows(QModelIndex(), m_entries.count(), m_entries.count()); + m_entries += entry->id(); + endInsertRows(); + } + if (status != Enclosure::Downloading && m_entries.contains(entry->id())) { + int index = m_entries.indexOf(entry->id()); + qDebug() << "removing dowloading entry" << entry->id() << "in position" << index; + beginRemoveRows(QModelIndex(), index, index); + m_entries.removeAt(index); + endRemoveRows(); + } +} diff --git a/src/downloadprogressmodel.h b/src/downloadprogressmodel.h new file mode 100644 index 00000000..4e710f8e --- /dev/null +++ b/src/downloadprogressmodel.h @@ -0,0 +1,38 @@ +/** + * SPDX-FileCopyrightText: 2021 Bart De Vries + * + * SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only OR LicenseRef-KDE-Accepted-GPL + */ + +#pragma once + +#include +#include +#include +#include + +#include "entry.h" +#include "enclosure.h" + +class DownloadProgressModel : public QAbstractListModel +{ + Q_OBJECT + +public: + static DownloadProgressModel &instance() + { + static DownloadProgressModel _instance; + return _instance; + } + + QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override; + QHash roleNames() const override; + int rowCount(const QModelIndex &parent) const override; + +public Q_SLOTS: + void monitorDownloadProgress(Entry* entry, Enclosure::Status status); + +private: + explicit DownloadProgressModel(); + QStringList m_entries; +}; diff --git a/src/enclosure.cpp b/src/enclosure.cpp index 17d01735..e371726c 100644 --- a/src/enclosure.cpp +++ b/src/enclosure.cpp @@ -16,11 +16,18 @@ #include "enclosuredownloadjob.h" #include "entry.h" #include "fetcher.h" +#include "downloadprogressmodel.h" Enclosure::Enclosure(Entry *entry) : QObject(entry) , m_entry(entry) { + // Set up signals to make DownloadProgressModel aware of ongoing downloads + connect(this, &Enclosure::statusChanged, this, [this]() { + Q_EMIT downloadStatusChanged(m_entry, m_status); + }); + connect(this, &Enclosure::downloadStatusChanged, &DownloadProgressModel::instance(), &DownloadProgressModel::monitorDownloadProgress); + QSqlQuery query; query.prepare(QStringLiteral("SELECT * FROM Enclosures WHERE id=:id")); query.bindValue(QStringLiteral(":id"), entry->id()); diff --git a/src/enclosure.h b/src/enclosure.h index 6fc8f5b7..f083a29a 100644 --- a/src/enclosure.h +++ b/src/enclosure.h @@ -59,6 +59,7 @@ Q_SIGNALS: void playPositionChanged(); void durationChanged(); void sizeChanged(); + void downloadStatusChanged(Entry* entry, Status status); private: diff --git a/src/main.cpp b/src/main.cpp index bb8b068e..109a6050 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -30,6 +30,7 @@ #include "fetcher.h" #include "queuemodel.h" #include "episodemodel.h" +#include "downloadprogressmodel.h" #include "datamanager.h" #include "audiomanager.h" #include "mpris2/mpris2.h" @@ -71,10 +72,10 @@ int main(int argc, char *argv[]) engine->setObjectOwnership(SettingsManager::self(), QQmlEngine::CppOwnership); return SettingsManager::self(); }); - /*qmlRegisterSingletonType("org.kde.alligator", 1, 0, "AudioManager", [](QQmlEngine *engine, QJSEngine *) -> QObject * { - engine->setObjectOwnership(&AudioManager::instance(), QQmlEngine::CppOwnership); - return &AudioManager::instance(); - });*/ + qmlRegisterSingletonType("org.kde.alligator", 1, 0, "DownloadProgressModel", [](QQmlEngine *engine, QJSEngine *) -> QObject * { + engine->setObjectOwnership(&DownloadProgressModel::instance(), QQmlEngine::CppOwnership); + return &DownloadProgressModel::instance(); + }); qmlRegisterType("org.kde.alligator", 1, 0, "AudioManager"); qmlRegisterType("org.kde.alligator", 1, 0, "Mpris2"); @@ -104,7 +105,7 @@ int main(int argc, char *argv[]) DataManager::instance(); - //AudioManager::instance(); + DownloadProgressModel::instance(); engine.load(QUrl(QStringLiteral("qrc:///main.qml"))); diff --git a/src/qml/DownloadSwipePage.qml b/src/qml/DownloadSwipePage.qml index 4d0c7734..0f5c495e 100644 --- a/src/qml/DownloadSwipePage.qml +++ b/src/qml/DownloadSwipePage.qml @@ -44,7 +44,7 @@ Kirigami.Page { Controls.TabButton { width: parent.parent.width/parent.count height: tabBarHeight - text: i18n("Running") + text: i18n("In Progress") } Controls.TabButton { width: parent.parent.width/parent.count @@ -60,7 +60,7 @@ Kirigami.Page { currentIndex: Kirigami.Settings.isMobile ? footerLoader.item.currentIndex : headerLoader.item.currentIndex EpisodeListPage { - title: i18n("Running") + title: i18n("In Progress") episodeType: EpisodeModel.Downloading } diff --git a/src/qml/EpisodeListPage.qml b/src/qml/EpisodeListPage.qml index 23d3c1fe..b5ce3e11 100644 --- a/src/qml/EpisodeListPage.qml +++ b/src/qml/EpisodeListPage.qml @@ -34,10 +34,12 @@ Kirigami.ScrollablePage { width: Kirigami.Units.gridUnit * 20 anchors.centerIn: parent - text: i18n("No %1 available", episodeType === EpisodeModel.All ? i18n("episodes") - : episodeType === EpisodeModel.New ? i18n("new episodes") - : episodeType === EpisodeModel.Unread ? i18n("unread episodes") - : i18n("episodes")) + text: i18n(episodeType === EpisodeModel.All ? i18n("No episodes available") + : episodeType === EpisodeModel.New ? i18n("No new episodes") + : episodeType === EpisodeModel.Unread ? i18n("No unread episodes") + : episodeType === EpisodeModel.Downloaded ? i18n("No downloaded episodes") + : episodeType === EpisodeModel.Downloading ? i18n("No downloads in progress") + : i18n("No episodes available")) } Component { id: episodeListDelegate @@ -46,14 +48,21 @@ Kirigami.ScrollablePage { isDownloads: episodeType == EpisodeModel.Downloaded || episodeType == EpisodeModel.Downloading } } + + EpisodeModel { + id: episodeModel + type: episodeType + } + ListView { anchors.fill: parent id: episodeList visible: count !== 0 - model: EpisodeModel { type: episodeType } + model: episodeType === EpisodeModel.Downloading ? DownloadProgressModel + : episodeModel delegate: Kirigami.DelegateRecycler { - width: episodeList.width + width: episodeList.width sourceComponent: episodeListDelegate } }