Refactor Queue and EntryList to use a GenericEntryDelegate

Still to be done is putting the actions into the GenericEntryDelegate
itself.
This commit is contained in:
Bart De Vries 2021-04-17 16:49:03 +02:00
parent 0bf3540dbd
commit 952dbdea5e
6 changed files with 159 additions and 220 deletions

View File

@ -9,7 +9,7 @@ import QtQuick 2.14
import QtQuick.Controls 2.14 as Controls import QtQuick.Controls 2.14 as Controls
import QtQuick.Layouts 1.14 import QtQuick.Layouts 1.14
import QtGraphicalEffects 1.15 import QtGraphicalEffects 1.15
import QtMultimedia 5.15
import org.kde.kirigami 2.12 as Kirigami import org.kde.kirigami 2.12 as Kirigami
import org.kde.alligator 1.0 import org.kde.alligator 1.0
@ -66,7 +66,47 @@ Kirigami.ScrollablePage {
Component { Component {
id: entryListDelegate id: entryListDelegate
EntryListDelegate { } GenericEntryDelegate {
listView: entryList
entryActions: [ // TODO: put the actions back into GenericEntryDelegate
Kirigami.Action {
text: i18n("Download")
icon.name: "download"
onTriggered: {
entry.queueStatus = true;
entry.enclosure.download();
}
visible: entry.enclosure && entry.enclosure.status === Enclosure.Downloadable
},
Kirigami.Action {
text: i18n("Cancel download")
icon.name: "edit-delete-remove"
onTriggered: entry.enclosure.cancelDownload()
visible: entry.enclosure && entry.enclosure.status === Enclosure.Downloading
},
Kirigami.Action {
text: i18n("Add to queue")
icon.name: "media-playlist-append"
visible: !entry.queueStatus && entry.enclosure && entry.enclosure.status === Enclosure.Downloaded
onTriggered: entry.queueStatus = true
},
Kirigami.Action {
text: i18n("Play")
icon.name: "media-playback-start"
visible: entry.queueStatus && entry.enclosure && entry.enclosure.status === Enclosure.Downloaded && (audio.entry !== entry || audio.playbackState !== Audio.PlayingState)
onTriggered: {
audio.entry = entry
audio.play()
}
},
Kirigami.Action {
text: i18n("Pause")
icon.name: "media-playback-pause"
visible: entry.queueStatus && entry.enclosure && entry.enclosure.status === Enclosure.Downloaded && audio.entry === entry && audio.playbackState === Audio.PlayingState
onTriggered: audio.pause()
}
]
}
} }
ListView { ListView {

View File

@ -50,7 +50,7 @@ Kirigami.ScrollablePage {
text: !entry.enclosure ? i18n("Open in Browser") : text: !entry.enclosure ? i18n("Open in Browser") :
entry.enclosure.status === Enclosure.Downloadable ? i18n("Download") : entry.enclosure.status === Enclosure.Downloadable ? i18n("Download") :
entry.enclosure.status === Enclosure.Downloading ? i18n("Cancel download") : entry.enclosure.status === Enclosure.Downloading ? i18n("Cancel download") :
!entry.queueStatus ? i18("Add to Queue") : !entry.queueStatus ? i18n("Add to Queue") :
(audio.entry === entry) && audio.playbackState === Audio.PlayingState ? i18n("Play") : (audio.entry === entry) && audio.playbackState === Audio.PlayingState ? i18n("Play") :
i18n("Pause") i18n("Pause")
icon.name: !entry.enclosure ? "globe" : icon.name: !entry.enclosure ? "globe" :

View File

@ -1,10 +1,10 @@
/** /**
* SPDX-FileCopyrightText: 2020 Tobias Fella <fella@posteo.de> SPDX-FileCopyrightText: 2021 Bart De Vries <bart@mogwai.be>
* 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
*/
SPDX-License-Identifier: GPL-2.0-or-later
*/
// Includes relevant modules used by the QML
import QtQuick 2.14 import QtQuick 2.14
import QtQuick.Controls 2.14 as Controls import QtQuick.Controls 2.14 as Controls
import QtQuick.Layouts 1.14 import QtQuick.Layouts 1.14
@ -12,25 +12,81 @@ import org.kde.kirigami 2.13 as Kirigami
import QtMultimedia 5.15 import QtMultimedia 5.15
import org.kde.alligator 1.0 import org.kde.alligator 1.0
Kirigami.SwipeListItem { Kirigami.SwipeListItem {
id: listItem
alwaysVisibleActions: true alwaysVisibleActions: true
property bool isQueue: false
property var listView: ""
property list<Controls.Action> entryActions
property list<Controls.Action> defaultActions: [
Kirigami.Action {
text: i18n("Download")
icon.name: "download"
onTriggered: {
entry.queueStatus = true;
entry.enclosure.download();
}
visible: entry.enclosure && entry.enclosure.status === Enclosure.Downloadable
},
Kirigami.Action {
text: i18n("Cancel download")
icon.name: "edit-delete-remove"
onTriggered: entry.enclosure.cancelDownload()
visible: entry.enclosure && entry.enclosure.status === Enclosure.Downloading
},
Kirigami.Action {
text: i18n("Add to queue")
icon.name: "media-playlist-append"
visible: !entry.queueStatus && entry.enclosure && entry.enclosure.status === Enclosure.Downloaded
onTriggered: entry.queueStatus = true
},
Kirigami.Action {
text: i18n("Play")
icon.name: "media-playback-start"
visible: entry.queueStatus && entry.enclosure && entry.enclosure.status === Enclosure.Downloaded && (audio.entry !== entry || audio.playbackState !== Audio.PlayingState)
onTriggered: {
audio.entry = entry
audio.play()
}
},
Kirigami.Action {
text: i18n("Pause")
icon.name: "media-playback-pause"
visible: entry.queueStatus && entry.enclosure && entry.enclosure.status === Enclosure.Downloaded && audio.entry === entry && audio.playbackState === Audio.PlayingState
onTriggered: audio.pause()
}
]
contentItem: RowLayout { contentItem: RowLayout {
Loader {
property var loaderListView: listView
property var loaderListItem: listItem
sourceComponent: dragHandleComponent
active: isQueue
}
Component {
id: dragHandleComponent
Kirigami.ListItemDragHandle {
listItem: loaderListItem
listView: loaderListView
onMoveRequested: DataManager.moveQueueItem(oldIndex, newIndex)
}
}
Image { Image {
asynchronous: true asynchronous: true
source: entry.image === "" ? "logo.png" : "file://"+Fetcher.image(entry.image) source: entry.image === "" ? "logo.png" : "file://"+Fetcher.image(entry.image)
fillMode: Image.PreserveAspectFit fillMode: Image.PreserveAspectFit
property int size: Kirigami.Units.gridUnit * 3 property int size: Kirigami.Units.gridUnit * 3
Layout.maximumHeight: size
Layout.maximumWidth: size
height: size
width: size
sourceSize.width: size sourceSize.width: size
sourceSize.height: size sourceSize.height: size
Layout.rightMargin: Kirigami.Units.smallSpacing Layout.maximumHeight: size
Layout.maximumWidth: size
Layout.rightMargin:Kirigami.Units.smallSpacing
} }
ColumnLayout { ColumnLayout {
spacing: 0 spacing: Kirigami.Units.smallSpacing
Layout.fillWidth: true Layout.fillWidth: true
Layout.alignment: Qt.AlignVCenter Layout.alignment: Qt.AlignVCenter
RowLayout{ RowLayout{
@ -45,12 +101,12 @@ Kirigami.SwipeListItem {
Layout.maximumHeight: 0.8 * supertitle.implicitHeight Layout.maximumHeight: 0.8 * supertitle.implicitHeight
Layout.maximumWidth: 0.8 * supertitle.implicitHeight Layout.maximumWidth: 0.8 * supertitle.implicitHeight
source: "source-playlist" source: "source-playlist"
visible: entry.queueStatus visible: !isQueue && entry.queueStatus
opacity: (entry.read) ? 0.4 : 0.7 opacity: (entry.read) ? 0.4 : 0.7
} }
Controls.Label { Controls.Label {
id: supertitle id: supertitle
text: (entry.queueStatus ? "· " : "") + entry.updated.toLocaleDateString(Qt.locale(), Locale.NarrowFormat) + (entry.enclosure ? ( entry.enclosure.size !== 0 ? " · " + Math.floor(entry.enclosure.size/(1024*1024)) + "MB" : "") : "" ) text: (!isQueue && entry.queueStatus ? "· " : "") + entry.updated.toLocaleDateString(Qt.locale(), Locale.NarrowFormat) + (entry.enclosure ? ( entry.enclosure.size !== 0 ? " · " + Math.floor(entry.enclosure.size/(1024*1024)) + "MB" : "") : "" )
Layout.fillWidth: true Layout.fillWidth: true
elide: Text.ElideRight elide: Text.ElideRight
font: Kirigami.Theme.smallFont font: Kirigami.Theme.smallFont
@ -116,50 +172,25 @@ Kirigami.SwipeListItem {
} }
onClicked: { onClicked: {
// only mark pure rss feeds as read; podcasts should only be marked read once they have been listened to // only mark pure rss feeds as read + not new;
// podcasts should only be marked read once they have been listened to, and only
// marked as non-new once they've been downloaded
if (!entry.enclosure) { if (!entry.enclosure) {
entry.read = true; entry.read = true;
entry.new = false; entry.new = false;
} }
if (isQueue) {
lastEntry = entry.id;
}
pageStack.push("qrc:/EntryPage.qml", {"entry": entry}) pageStack.push("qrc:/EntryPage.qml", {"entry": entry})
} }
actions: [ Component.onCompleted: {
Kirigami.Action { if(entryActions) {
text: i18n("Download") actions = entryActions;
icon.name: "download" } else {
onTriggered: { actions = defaultActions;
entry.queueStatus = true;
entry.enclosure.download();
} }
visible: entry.enclosure && entry.enclosure.status === Enclosure.Downloadable
},
Kirigami.Action {
text: i18n("Cancel download")
icon.name: "edit-delete-remove"
onTriggered: entry.enclosure.cancelDownload()
visible: entry.enclosure && entry.enclosure.status === Enclosure.Downloading
},
Kirigami.Action {
text: i18n("Add to queue")
icon.name: "media-playlist-append"
visible: !entry.queueStatus && entry.enclosure && entry.enclosure.status === Enclosure.Downloaded
onTriggered: entry.queueStatus = true
},
Kirigami.Action {
text: i18n("Play")
icon.name: "media-playback-start"
visible: entry.queueStatus && entry.enclosure && entry.enclosure.status === Enclosure.Downloaded && (audio.entry !== entry || audio.playbackState !== Audio.PlayingState)
onTriggered: {
audio.entry = entry
audio.play()
} }
},
Kirigami.Action {
text: i18n("Pause")
icon.name: "media-playback-pause"
visible: entry.queueStatus && entry.enclosure && entry.enclosure.status === Enclosure.Downloaded && audio.entry === entry && audio.playbackState === Audio.PlayingState
onTriggered: audio.pause()
}
]
} }

View File

@ -1,163 +0,0 @@
/**
SPDX-FileCopyrightText: 2021 Bart De Vries <bart@mogwai.be>
SPDX-License-Identifier: GPL-2.0-or-later
*/
// Includes relevant modules used by the QML
import QtQuick 2.14
import QtQuick.Controls 2.14 as Controls
import QtQuick.Layouts 1.14
import org.kde.kirigami 2.13 as Kirigami
import QtMultimedia 5.15
import org.kde.alligator 1.0
Kirigami.SwipeListItem {
id: listItem
alwaysVisibleActions: true
contentItem: RowLayout {
Kirigami.ListItemDragHandle {
listItem: listItem
listView: queueList
onMoveRequested: DataManager.moveQueueItem(oldIndex, newIndex)
}
Image {
asynchronous: true
source: entry.image === "" ? "logo.png" : "file://"+Fetcher.image(entry.image)
fillMode: Image.PreserveAspectFit
property int size: Kirigami.Units.gridUnit * 3
sourceSize.width: size
sourceSize.height: size
Layout.maximumHeight: size
Layout.maximumWidth: size
Layout.rightMargin:Kirigami.Units.smallSpacing
}
ColumnLayout {
spacing: Kirigami.Units.smallSpacing
Layout.fillWidth: true
Layout.alignment: Qt.AlignVCenter
RowLayout{
Controls.Label {
text: entry.new ? i18n("new") + " ·" : ""
font.capitalization: Font.AllUppercase
color: Kirigami.Theme.highlightColor
visible: entry.new
opacity: (entry.read) ? 0.4 : 0.7
}
Controls.Label {
id: supertitle
text: entry.updated.toLocaleDateString(Qt.locale(), Locale.NarrowFormat) + (entry.enclosure ? ( entry.enclosure.size !== 0 ? " · " + Math.floor(entry.enclosure.size/(1024*1024)) + "MB" : "") : "" )
Layout.fillWidth: true
elide: Text.ElideRight
font: Kirigami.Theme.smallFont
opacity: (entry.read) ? 0.4 : 0.7
}
}
Controls.Label {
text: entry.title
Layout.fillWidth: true
elide: Text.ElideRight
font.weight: Font.Normal
opacity: (entry.read) ? 0.6 : 1
}
Loader {
sourceComponent: entry.enclosure && entry.enclosure.status === Enclosure.Downloading ? downloadProgress : ( entry.enclosure && entry.enclosure.playPosition > 0 ?playProgress : subtitle)
Layout.fillWidth: true
}
Component {
id: subtitle
Controls.Label {
text: (Math.floor(entry.enclosure.duration/3600) < 10 ? "0" : "") + Math.floor(entry.enclosure.duration/3600) + ":" + (Math.floor(entry.enclosure.duration/60) % 60 < 10 ? "0" : "") + Math.floor(entry.enclosure.duration/60) % 60 + ":" + (Math.floor(entry.enclosure.duration) % 60 < 10 ? "0" : "") + Math.floor(entry.enclosure.duration) % 60
Layout.fillWidth: true
elide: Text.ElideRight
font: Kirigami.Theme.smallFont
opacity: 0.7
visible: !downloadProgress.visible
}
}
Component {
id: downloadProgress
Controls.ProgressBar {
from: 0
to: 100
value: entry.enclosure.downloadProgress
visible: entry.enclosure && entry.enclosure.status === Enclosure.Downloading
Layout.fillWidth: true
}
}
Component {
id: playProgress
RowLayout {
Controls.Label {
text: (Math.floor(entry.enclosure.playPosition/3600000) < 10 ? "0" : "") + Math.floor(entry.enclosure.playPosition/3600000) + ":" + (Math.floor(entry.enclosure.playPosition/60000) % 60 < 10 ? "0" : "") + Math.floor(entry.enclosure.playPosition/60000) % 60 + ":" + (Math.floor(entry.enclosure.playPosition/1000) % 60 < 10 ? "0" : "") + Math.floor(entry.enclosure.playPosition/1000) % 60
elide: Text.ElideRight
font: Kirigami.Theme.smallFont
opacity: 0.7
}
Controls.ProgressBar {
from: 0
to: entry.enclosure.duration
value: entry.enclosure.playPosition/1000
Layout.fillWidth: true
}
Controls.Label {
text: (Math.floor(entry.enclosure.duration/3600) < 10 ? "0" : "") + Math.floor(entry.enclosure.duration/3600) + ":" + (Math.floor(entry.enclosure.duration/60) % 60 < 10 ? "0" : "") + Math.floor(entry.enclosure.duration/60) % 60 + ":" + (Math.floor(entry.enclosure.duration) % 60 < 10 ? "0" : "") + Math.floor(entry.enclosure.duration) % 60
elide: Text.ElideRight
font: Kirigami.Theme.smallFont
opacity: 0.7
}
}
}
}
}
onClicked: {
// only mark pure rss feeds as read + not new;
// podcasts should only be marked read once they have been listened to, and only
// marked as non-new once they've been downloaded
if (!entry.enclosure) {
entry.read = true;
entry.new = false;
}
lastEntry = entry.id;
pageStack.push("qrc:/EntryPage.qml", {"entry": entry})
}
actions: [
/*Kirigami.Action {
text: i18n("Remove from Queue")
icon.name: "list-remove"
onTriggered: entry.queueStatus = false
},*/
Kirigami.Action {
text: i18n("Download")
icon.name: "download"
onTriggered: entry.enclosure.download()
visible: entry.enclosure && entry.enclosure.status === Enclosure.Downloadable
},
Kirigami.Action {
text: i18n("Cancel download")
icon.name: "edit-delete-remove"
onTriggered: entry.enclosure.cancelDownload()
visible: entry.enclosure && entry.enclosure.status === Enclosure.Downloading
},
Kirigami.Action {
text: i18n("Play")
icon.name: "media-playback-start"
visible: entry.enclosure && entry.enclosure.status === Enclosure.Downloaded && (audio.entry !== entry || audio.playbackState !== Audio.PlayingState)
onTriggered: {
audio.entry = entry
audio.play()
}
},
Kirigami.Action {
text: i18n("Pause")
icon.name: "media-playback-pause"
visible: entry.enclosure && entry.enclosure.status === Enclosure.Downloaded && audio.entry === entry && audio.playbackState === Audio.PlayingState
onTriggered: audio.pause()
}
]
}

View File

@ -43,7 +43,39 @@ Kirigami.ScrollablePage {
Component { Component {
id: delegateComponent id: delegateComponent
QueueDelegate { } GenericEntryDelegate {
isQueue: true
listView: queueList
entryActions: [
Kirigami.Action {
text: i18n("Download")
icon.name: "download"
onTriggered: entry.enclosure.download()
visible: entry.enclosure && entry.enclosure.status === Enclosure.Downloadable
},
Kirigami.Action {
text: i18n("Cancel download")
icon.name: "edit-delete-remove"
onTriggered: entry.enclosure.cancelDownload()
visible: entry.enclosure && entry.enclosure.status === Enclosure.Downloading
},
Kirigami.Action {
text: i18n("Play")
icon.name: "media-playback-start"
visible: entry.enclosure && entry.enclosure.status === Enclosure.Downloaded && (audio.entry !== entry || audio.playbackState !== Audio.PlayingState)
onTriggered: {
audio.entry = entry
audio.play()
}
},
Kirigami.Action {
text: i18n("Pause")
icon.name: "media-playback-pause"
visible: entry.enclosure && entry.enclosure.status === Enclosure.Downloaded && audio.entry === entry && audio.playbackState === Audio.PlayingState
onTriggered: audio.pause()
}
]
}
} }
ListView { ListView {

View File

@ -7,15 +7,14 @@
<file alias="SettingsPage.qml">qml/SettingsPage.qml</file> <file alias="SettingsPage.qml">qml/SettingsPage.qml</file>
<file alias="AboutPage.qml">qml/AboutPage.qml</file> <file alias="AboutPage.qml">qml/AboutPage.qml</file>
<file alias="FeedDetailsPage.qml">qml/FeedDetailsPage.qml</file> <file alias="FeedDetailsPage.qml">qml/FeedDetailsPage.qml</file>
<file alias="EntryListDelegate.qml">qml/EntryListDelegate.qml</file>
<file alias="AddFeedSheet.qml">qml/AddFeedSheet.qml</file> <file alias="AddFeedSheet.qml">qml/AddFeedSheet.qml</file>
<file alias="FeedListDelegate.qml">qml/FeedListDelegate.qml</file> <file alias="FeedListDelegate.qml">qml/FeedListDelegate.qml</file>
<file alias="MinimizedPlayerControls.qml">qml/MinimizedPlayerControls.qml</file> <file alias="MinimizedPlayerControls.qml">qml/MinimizedPlayerControls.qml</file>
<file alias="PlayerControls.qml">qml/PlayerControls.qml</file> <file alias="PlayerControls.qml">qml/PlayerControls.qml</file>
<file alias="FooterBar.qml">qml/FooterBar.qml</file> <file alias="FooterBar.qml">qml/FooterBar.qml</file>
<file alias="QueuePage.qml">qml/QueuePage.qml</file> <file alias="QueuePage.qml">qml/QueuePage.qml</file>
<file alias="QueueDelegate.qml">qml/QueueDelegate.qml</file>
<file alias="GenericListHeader.qml">qml/GenericListHeader.qml</file> <file alias="GenericListHeader.qml">qml/GenericListHeader.qml</file>
<file alias="GenericEntryDelegate.qml">qml/GenericEntryDelegate.qml</file>
<file alias="logo.png">../logo.png</file> <file alias="logo.png">../logo.png</file>
<file>qtquickcontrols2.conf</file> <file>qtquickcontrols2.conf</file>
</qresource> </qresource>