mirror of https://github.com/KDE/kasts.git
Expanded the model with more roles and designed frontend.
This commit is contained in:
parent
fa1c308c2d
commit
95ee97aefe
|
@ -141,6 +141,8 @@ if(ANDROID)
|
|||
overflow-menu
|
||||
checkbox
|
||||
error
|
||||
search
|
||||
kt-add-feeds
|
||||
)
|
||||
else()
|
||||
target_link_libraries(kasts PRIVATE Qt::Widgets Qt::DBus)
|
||||
|
|
|
@ -626,3 +626,8 @@ void DataManager::updateQueueListnrs() const
|
|||
Database::instance().execute(query);
|
||||
}
|
||||
}
|
||||
|
||||
bool DataManager::isFeedExists(const QString &url)
|
||||
{
|
||||
return m_feeds.contains(url);
|
||||
}
|
||||
|
|
|
@ -59,6 +59,7 @@ public:
|
|||
|
||||
Q_INVOKABLE void importFeeds(const QString &path);
|
||||
Q_INVOKABLE void exportFeeds(const QString &path);
|
||||
Q_INVOKABLE bool isFeedExists(const QString &url);
|
||||
|
||||
Q_SIGNALS:
|
||||
void feedAdded(const QString &url);
|
||||
|
|
|
@ -30,15 +30,95 @@ QVariant PodcastSearchModel::data(const QModelIndex &index, int role) const
|
|||
// invalid index
|
||||
return QVariant::fromValue(QStringLiteral("DEADBEEF"));
|
||||
}
|
||||
if (role == Title) {
|
||||
switch (role) {
|
||||
case Id:
|
||||
return m_data[QStringLiteral("feeds")].toArray()[index.row()].toObject()[QStringLiteral("id")].toInt();
|
||||
case Title:
|
||||
return m_data[QStringLiteral("feeds")].toArray()[index.row()].toObject()[QStringLiteral("title")].toString();
|
||||
case Url:
|
||||
return m_data[QStringLiteral("feeds")].toArray()[index.row()].toObject()[QStringLiteral("url")].toString();
|
||||
case OriginalUrl:
|
||||
return m_data[QStringLiteral("feeds")].toArray()[index.row()].toObject()[QStringLiteral("originalUrl")].toString();
|
||||
case Link:
|
||||
return m_data[QStringLiteral("feeds")].toArray()[index.row()].toObject()[QStringLiteral("link")].toString();
|
||||
case Description:
|
||||
return m_data[QStringLiteral("feeds")].toArray()[index.row()].toObject()[QStringLiteral("description")].toString();
|
||||
case Author:
|
||||
return m_data[QStringLiteral("feeds")].toArray()[index.row()].toObject()[QStringLiteral("author")].toString();
|
||||
case OwnerName:
|
||||
return m_data[QStringLiteral("feeds")].toArray()[index.row()].toObject()[QStringLiteral("ownerName")].toString();
|
||||
case Image:
|
||||
return m_data[QStringLiteral("feeds")].toArray()[index.row()].toObject()[QStringLiteral("image")].toString();
|
||||
case Artwork:
|
||||
return m_data[QStringLiteral("feeds")].toArray()[index.row()].toObject()[QStringLiteral("artwork")].toString();
|
||||
case LastUpdateTime:
|
||||
return m_data[QStringLiteral("feeds")].toArray()[index.row()].toObject()[QStringLiteral("lastUpdateTime")].toInt();
|
||||
case LastCrawlTime:
|
||||
return m_data[QStringLiteral("feeds")].toArray()[index.row()].toObject()[QStringLiteral("lastCrawlTime")].toInt();
|
||||
case LastParseTime:
|
||||
return m_data[QStringLiteral("feeds")].toArray()[index.row()].toObject()[QStringLiteral("lastParseTime")].toInt();
|
||||
case LastGoodHttpStatusTime:
|
||||
return m_data[QStringLiteral("feeds")].toArray()[index.row()].toObject()[QStringLiteral("lastGoodHttpStatusTime")].toInt();
|
||||
case LastHttpStatus:
|
||||
return m_data[QStringLiteral("feeds")].toArray()[index.row()].toObject()[QStringLiteral("lastHttpStatus")].toInt();
|
||||
case ContentType:
|
||||
return m_data[QStringLiteral("feeds")].toArray()[index.row()].toObject()[QStringLiteral("contentType")].toString();
|
||||
case ItunesId:
|
||||
return m_data[QStringLiteral("feeds")].toArray()[index.row()].toObject()[QStringLiteral("itunesId")].toInt();
|
||||
case Generator:
|
||||
return m_data[QStringLiteral("feeds")].toArray()[index.row()].toObject()[QStringLiteral("generator")].toString();
|
||||
case Language:
|
||||
return m_data[QStringLiteral("feeds")].toArray()[index.row()].toObject()[QStringLiteral("language")].toString();
|
||||
case Type:
|
||||
return m_data[QStringLiteral("feeds")].toArray()[index.row()].toObject()[QStringLiteral("type")].toInt();
|
||||
case Dead:
|
||||
return m_data[QStringLiteral("feeds")].toArray()[index.row()].toObject()[QStringLiteral("dead")].toInt();
|
||||
case CrawlErrors:
|
||||
return m_data[QStringLiteral("feeds")].toArray()[index.row()].toObject()[QStringLiteral("crawlErrors")].toInt();
|
||||
case ParseErrors:
|
||||
return m_data[QStringLiteral("feeds")].toArray()[index.row()].toObject()[QStringLiteral("parseErrors")].toInt();
|
||||
case Categories: {
|
||||
// TODO: Implement this function to add to the list of categories.
|
||||
}
|
||||
case Locked:
|
||||
return m_data[QStringLiteral("feeds")].toArray()[index.row()].toObject()[QStringLiteral("locked")].toInt();
|
||||
case ImageUrlHash:
|
||||
return m_data[QStringLiteral("feeds")].toArray()[index.row()].toObject()[QStringLiteral("imageUrlHash")].toInt();
|
||||
default:
|
||||
return QVariant();
|
||||
}
|
||||
return QVariant();
|
||||
}
|
||||
|
||||
QHash<int, QByteArray> PodcastSearchModel::roleNames() const
|
||||
{
|
||||
return {{Title, "title"}};
|
||||
return {
|
||||
{Id, "id"},
|
||||
{Title, "title"},
|
||||
{Url, "url"},
|
||||
{OriginalUrl, "originalUrl"},
|
||||
{Link, "link"},
|
||||
{Description, "description"},
|
||||
{Author, "author"},
|
||||
{OwnerName, "ownerName"},
|
||||
{Image, "image"},
|
||||
{Artwork, "artwork"},
|
||||
{LastUpdateTime, "lastUpdateTime"},
|
||||
{LastCrawlTime, "lastCrawlTime"},
|
||||
{LastParseTime, "lastParseTime"},
|
||||
{LastGoodHttpStatusTime, "lastGoodHttpStatusTime"},
|
||||
{LastHttpStatus, "lastHttpStatus"},
|
||||
{ContentType, "contentType"},
|
||||
{ItunesId, "itunesId"},
|
||||
{Generator, "generator"},
|
||||
{Language, "language"},
|
||||
{Type, "type"},
|
||||
{Dead, "dead"},
|
||||
{CrawlErrors, "crawlErrors"},
|
||||
{ParseErrors, "parseErrors"},
|
||||
{Categories, "categories"},
|
||||
{Locked, "locked"},
|
||||
{ImageUrlHash, "imageUrlHash"},
|
||||
};
|
||||
}
|
||||
|
||||
int PodcastSearchModel::rowCount(const QModelIndex &parent) const
|
||||
|
@ -47,7 +127,8 @@ int PodcastSearchModel::rowCount(const QModelIndex &parent) const
|
|||
if (m_data.isEmpty()) {
|
||||
return 0;
|
||||
}
|
||||
return m_data[QStringLiteral("feeds")].toArray().size();
|
||||
return m_data[QStringLiteral("feeds")].toArray().size();
|
||||
|
||||
}
|
||||
|
||||
void PodcastSearchModel::search(const QString &text)
|
||||
|
|
|
@ -17,10 +17,34 @@
|
|||
class PodcastSearchModel : public QAbstractListModel
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
enum Roles {
|
||||
Id,
|
||||
Title,
|
||||
Url,
|
||||
OriginalUrl,
|
||||
Link,
|
||||
Description,
|
||||
Author,
|
||||
OwnerName,
|
||||
Image,
|
||||
Artwork,
|
||||
LastUpdateTime,
|
||||
LastCrawlTime,
|
||||
LastParseTime,
|
||||
LastGoodHttpStatusTime,
|
||||
LastHttpStatus,
|
||||
ContentType,
|
||||
ItunesId,
|
||||
Generator,
|
||||
Language,
|
||||
Type,
|
||||
Dead,
|
||||
CrawlErrors,
|
||||
ParseErrors,
|
||||
Categories,
|
||||
Locked,
|
||||
ImageUrlHash,
|
||||
};
|
||||
explicit PodcastSearchModel(QObject *parent = nullptr);
|
||||
QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override;
|
||||
|
|
|
@ -0,0 +1,119 @@
|
|||
/**
|
||||
* SPDX-FileCopyrightText: 2021 Swapnil Tripathi <swapnil06.st@gmail.com>
|
||||
*
|
||||
* 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.15 as Controls
|
||||
import QtQuick.Layouts 1.14
|
||||
|
||||
import org.kde.kirigami 2.15 as Kirigami
|
||||
import org.kde.kasts 1.0
|
||||
|
||||
Kirigami.ScrollablePage {
|
||||
id: page
|
||||
title: i18n("Discover")
|
||||
property var feedModel: ""
|
||||
header: RowLayout {
|
||||
width: parent.width
|
||||
anchors.topMargin: Kirigami.Units.smallSpacing
|
||||
Kirigami.SearchField {
|
||||
id: textField
|
||||
placeholderText: i18n("Search podcastindex.org")
|
||||
Layout.fillWidth: true
|
||||
Layout.leftMargin: Kirigami.Units.smallSpacing
|
||||
}
|
||||
Controls.Button {
|
||||
id: searchButton
|
||||
text: isWidescreen ? i18n("Search") : ""
|
||||
icon.name: "search"
|
||||
Layout.rightMargin: Kirigami.Units.smallSpacing
|
||||
onClicked: {
|
||||
podcastSearchModel.search(textField.text);
|
||||
}
|
||||
}
|
||||
}
|
||||
Component.onCompleted: {
|
||||
textField.forceActiveFocus();
|
||||
}
|
||||
Component {
|
||||
id: delegateComponent
|
||||
Kirigami.SwipeListItem {
|
||||
id: listItem
|
||||
contentItem: RowLayout {
|
||||
Kirigami.Icon {
|
||||
source: model.image
|
||||
Layout.fillHeight: true
|
||||
Layout.maximumHeight: Kirigami.Units.iconSizes.huge
|
||||
Layout.preferredWidth: height
|
||||
}
|
||||
Controls.Label {
|
||||
Layout.fillWidth: true
|
||||
height: Math.max(implicitHeight, Kirigami.Units.iconSizes.smallMedium)
|
||||
text: model.title
|
||||
elide: Text.ElideRight
|
||||
color: listItem.checked || (listItem.pressed && !listItem.checked && !listItem.sectionDelegate) ? listItem.activeTextColor : listItem.textColor
|
||||
}
|
||||
}
|
||||
actions: [
|
||||
Kirigami.Action {
|
||||
text: enabled ? i18n("Subscribe") : i18n("Subscribed")
|
||||
icon.name: "kt-add-feeds"
|
||||
enabled: !DataManager.isFeedExists(model.url)
|
||||
onTriggered: {
|
||||
DataManager.addFeed(model.url)
|
||||
}
|
||||
}
|
||||
]
|
||||
onClicked: {
|
||||
feedModel = model
|
||||
detailDrawer.open();
|
||||
}
|
||||
}
|
||||
}
|
||||
ListView {
|
||||
anchors.fill: parent
|
||||
model: PodcastSearchModel {
|
||||
id: podcastSearchModel
|
||||
}
|
||||
spacing: 5
|
||||
clip: true
|
||||
delegate: Kirigami.DelegateRecycler {
|
||||
width: parent ? parent.width : implicitWidth
|
||||
sourceComponent: delegateComponent
|
||||
}
|
||||
}
|
||||
Kirigami.OverlaySheet {
|
||||
id: detailDrawer
|
||||
showCloseButton: true
|
||||
contentItem: ColumnLayout {
|
||||
Layout.preferredWidth: Kirigami.Units.gridUnit * 25
|
||||
GenericHeader {
|
||||
image: feedModel.image
|
||||
title: feedModel.title
|
||||
subtitle: feedModel.author
|
||||
Controls.Button {
|
||||
text: enabled ? "Subscribe" : "Subscribed"
|
||||
icon.name: "kt-add-feeds"
|
||||
anchors.right: parent.right
|
||||
anchors.top: parent.top
|
||||
anchors.rightMargin: Kirigami.Units.largeSpacing
|
||||
anchors.topMargin: Kirigami.Units.largeSpacing
|
||||
onClicked: {
|
||||
DataManager.addFeed(feedModel.url)
|
||||
}
|
||||
enabled: !DataManager.isFeedExists(feedModel.url)
|
||||
}
|
||||
}
|
||||
Controls.Label {
|
||||
text: i18n("%1 \n\nAuthor: %2 \nOwner: %3", feedModel.description, feedModel.author, feedModel.ownerName)
|
||||
Layout.margins: Kirigami.Units.gridUnit
|
||||
wrapMode: Text.WordWrap
|
||||
Layout.fillWidth: true
|
||||
onLinkActivated: Qt.openUrlExternally(link)
|
||||
font.pointSize: SettingsManager && !(SettingsManager.articleFontUseSystem) ? SettingsManager.articleFontSize : Kirigami.Units.fontMetrics.font.pointSize
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -38,6 +38,7 @@ Kirigami.ApplicationWindow {
|
|||
switch (page) {
|
||||
case "QueuePage": return "qrc:/QueuePage.qml";
|
||||
case "EpisodeSwipePage": return "qrc:/EpisodeSwipePage.qml";
|
||||
case "DiscoverPage": return "qrc:/DiscoverPage.qml";
|
||||
case "FeedListPage": return "qrc:/FeedListPage.qml";
|
||||
case "DownloadListPage": return "qrc:/DownloadListPage.qml";
|
||||
case "SettingsPage": return "qrc:/SettingsPage.qml";
|
||||
|
@ -56,6 +57,7 @@ Kirigami.ApplicationWindow {
|
|||
: SettingsManager.lastOpenedPage === "QueuePage" ? 0
|
||||
: SettingsManager.lastOpenedPage === "EpisodeSwipePage" ? 1
|
||||
: SettingsManager.lastOpenedPage === "DownloadListPage" ? 0
|
||||
: SettingsManager.lastOpenedPage === "DiscoverPage" ? 0
|
||||
: 0
|
||||
currentPage = SettingsManager.lastOpenedPage
|
||||
pageStack.initialPage = getPage(SettingsManager.lastOpenedPage)
|
||||
|
@ -103,6 +105,16 @@ Kirigami.ApplicationWindow {
|
|||
tabBarActive = 0
|
||||
}
|
||||
},
|
||||
Kirigami.Action {
|
||||
text: i18n("Discover")
|
||||
iconName: "search"
|
||||
checked: currentPage == "DiscoverPage"
|
||||
onTriggered: {
|
||||
pushPage("DiscoverPage")
|
||||
SettingsManager.lastOpenedPage = "DiscoverPage" // for persistency
|
||||
tabBarActive = 0
|
||||
}
|
||||
},
|
||||
Kirigami.Action {
|
||||
text: i18n("Episodes")
|
||||
iconName: "rss"
|
||||
|
|
|
@ -21,6 +21,7 @@
|
|||
<file alias="EpisodeSwipePage.qml">qml/EpisodeSwipePage.qml</file>
|
||||
<file alias="GenericHeader.qml">qml/GenericHeader.qml</file>
|
||||
<file alias="GenericEntryDelegate.qml">qml/GenericEntryDelegate.qml</file>
|
||||
<file alias="DiscoverPage.qml">qml/DiscoverPage.qml</file>
|
||||
<file alias="ImageWithFallback.qml">qml/ImageWithFallback.qml</file>
|
||||
<file alias="UpdateNotification.qml">qml/UpdateNotification.qml</file>
|
||||
<file alias="HeaderBar.qml">qml/HeaderBar.qml</file>
|
||||
|
|
Loading…
Reference in New Issue