mirror of https://github.com/KDE/kasts.git
324 lines
14 KiB
QML
324 lines
14 KiB
QML
/**
|
|
* 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.15
|
|
import QtQuick.Controls 2.14 as Controls
|
|
import QtQuick.Layouts 1.2
|
|
import QtQml.Models 2.15
|
|
|
|
import org.kde.kirigami 2.13 as Kirigami
|
|
|
|
import org.kde.kasts 1.0
|
|
|
|
ListView {
|
|
id: listView
|
|
clip: true
|
|
property bool isQueue: false
|
|
property bool isDownloads: false
|
|
|
|
property var selectionForContextMenu: []
|
|
property var singleSelectedEntry: undefined
|
|
property ItemSelectionModel selectionModel: ItemSelectionModel {
|
|
id: selectionModel
|
|
model: listView.model
|
|
onSelectionChanged: {
|
|
selectionForContextMenu = selectedIndexes;
|
|
}
|
|
}
|
|
|
|
onSelectionForContextMenuChanged: {
|
|
if (selectionForContextMenu.length === 1) {
|
|
singleSelectedEntry = selectionForContextMenu[0].model.data(selectionForContextMenu[0], AbstractEpisodeModel.EntryRole);
|
|
} else {
|
|
singleSelectedEntry = undefined;
|
|
}
|
|
}
|
|
|
|
// The selection is not updated when the model is reset, so we have to take
|
|
// this into account manually.
|
|
// TODO: Fix the fact that the current item is not highlighted after reset
|
|
Connections {
|
|
target: listView.model
|
|
function onModelAboutToBeReset() {
|
|
selectionForContextMenu = [];
|
|
listView.selectionModel.clear();
|
|
listView.selectionModel.setCurrentIndex(model.index(0, 0), ItemSelectionModel.Current); // Only set current item; don't select it
|
|
currentIndex = 0;
|
|
}
|
|
}
|
|
|
|
Keys.onPressed: {
|
|
if (event.matches(StandardKey.SelectAll)) {
|
|
listView.selectionModel.select(model.index(0, 0), ItemSelectionModel.ClearAndSelect | ItemSelectionModel.Columns);
|
|
return;
|
|
}
|
|
switch (event.key) {
|
|
case Qt.Key_Up:
|
|
selectRelative(-1, event.modifiers == Qt.ShiftModifier);
|
|
return;
|
|
case Qt.Key_Down:
|
|
selectRelative(1, event.modifiers == Qt.ShiftModifier);
|
|
return;
|
|
case Qt.Key_PageUp:
|
|
if (!atYBeginning) {
|
|
if ((contentY - listView.height) < 0) {
|
|
contentY = 0
|
|
} else {
|
|
contentY -= listView.height
|
|
}
|
|
returnToBounds()
|
|
}
|
|
return;
|
|
case Qt.Key_PageDown:
|
|
if (!atYEnd) {
|
|
if ((contentY + listView.height) > contentHeight - height) {
|
|
contentY = contentHeight - height
|
|
} else {
|
|
contentY += listView.height
|
|
}
|
|
returnToBounds()
|
|
}
|
|
return;
|
|
case Qt.Key_Home:
|
|
if (!atYBeginning) {
|
|
contentY = 0
|
|
returnToBounds()
|
|
}
|
|
return;
|
|
case Qt.Key_End:
|
|
if (!atYEnd) {
|
|
contentY = contentHeight - height
|
|
returnToBounds()
|
|
}
|
|
return;
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
|
|
onActiveFocusChanged: {
|
|
if (activeFocus && !selectionModel.hasSelection) {
|
|
selectionModel.clear();
|
|
selectionModel.setCurrentIndex(model.index(0, 0), ItemSelectionModel.Current); // Only set current item; don't select it
|
|
}
|
|
}
|
|
|
|
function selectRelative(delta, append) {
|
|
var nextRow = listView.currentIndex + delta;
|
|
if (nextRow < 0) {
|
|
nextRow = 0;
|
|
}
|
|
if (nextRow >= listView.count) {
|
|
nextRow = listView.count - 1;
|
|
}
|
|
if (append) {
|
|
listView.selectionModel.select(listView.model.createSelection(nextRow, listView.selectionModel.currentIndex.row), ItemSelectionModel.ClearAndSelect | ItemSelectionModel.Rows);
|
|
} else {
|
|
listView.selectionModel.setCurrentIndex(model.index(nextRow, 0), ItemSelectionModel.ClearAndSelect | ItemSelectionModel.Rows);
|
|
}
|
|
}
|
|
|
|
// For lack of a better place, we put generic entry list actions here so
|
|
// they can be re-used across the different ListViews.
|
|
readonly property var selectAllAction: Kirigami.Action {
|
|
icon.name: "edit-select-all"
|
|
text: i18n("Select All")
|
|
visible: true
|
|
onTriggered: {
|
|
listView.selectionModel.select(model.index(0, 0), ItemSelectionModel.ClearAndSelect | ItemSelectionModel.Columns);
|
|
}
|
|
}
|
|
|
|
readonly property var selectNoneAction: Kirigami.Action {
|
|
icon.name: "edit-select-none"
|
|
text: i18n("Deselect All")
|
|
visible: listView.selectionModel.hasSelection
|
|
onTriggered: {
|
|
listView.selectionModel.clearSelection();
|
|
}
|
|
}
|
|
|
|
readonly property var addToQueueAction: Kirigami.Action {
|
|
text: i18n("Add to Queue")
|
|
icon.name: "media-playlist-append"
|
|
visible: listView.selectionModel.hasSelection && !listView.isQueue && (singleSelectedEntry ? !singleSelectedEntry.queueStatus : true)
|
|
//visible: listView.selectionModel.hasSelection && !listView.isQueue
|
|
onTriggered: {
|
|
DataManager.bulkQueueStatusByIndex(true, selectionForContextMenu);
|
|
}
|
|
}
|
|
|
|
readonly property var removeFromQueueAction: Kirigami.Action {
|
|
text: i18n("Remove from Queue")
|
|
icon.name: "list-remove"
|
|
visible: listView.selectionModel.hasSelection && (singleSelectedEntry ? singleSelectedEntry.queueStatus : true)
|
|
//visible: listView.selectionModel.hasSelection
|
|
onTriggered: {
|
|
DataManager.bulkQueueStatusByIndex(false, selectionForContextMenu);
|
|
}
|
|
}
|
|
|
|
readonly property var markPlayedAction: Kirigami.Action {
|
|
text: i18n("Mark as Played")
|
|
visible: listView.selectionModel.hasSelection && (singleSelectedEntry ? !singleSelectedEntry.read : true)
|
|
onTriggered: {
|
|
DataManager.bulkMarkReadByIndex(true, selectionForContextMenu);
|
|
}
|
|
}
|
|
|
|
readonly property var markNotPlayedAction: Kirigami.Action {
|
|
text: i18n("Mark as Unplayed")
|
|
visible: listView.selectionModel.hasSelection && (singleSelectedEntry ? singleSelectedEntry.read : true)
|
|
onTriggered: {
|
|
DataManager.bulkMarkReadByIndex(false, selectionForContextMenu);
|
|
}
|
|
}
|
|
|
|
readonly property var markNewAction: Kirigami.Action {
|
|
text: i18n("Label as \"New\"")
|
|
visible: listView.selectionModel.hasSelection && (singleSelectedEntry ? !singleSelectedEntry.new : true)
|
|
onTriggered: {
|
|
DataManager.bulkMarkNewByIndex(true, selectionForContextMenu);
|
|
}
|
|
}
|
|
|
|
readonly property var markNotNewAction: Kirigami.Action {
|
|
text: i18n("Remove \"New\" Label")
|
|
visible: listView.selectionModel.hasSelection && (singleSelectedEntry ? singleSelectedEntry.new : true)
|
|
onTriggered: {
|
|
DataManager.bulkMarkNewByIndex(false, selectionForContextMenu);
|
|
}
|
|
}
|
|
|
|
readonly property var markFavoriteAction: Kirigami.Action {
|
|
text: i18nc("@action:intoolbar Button to add a podcast episode as favorite", "Add to Favorites")
|
|
icon.name: "starred-symbolic"
|
|
visible: listView.selectionModel.hasSelection && (singleSelectedEntry ? !singleSelectedEntry.favorite : true)
|
|
onTriggered: {
|
|
DataManager.bulkMarkFavoriteByIndex(true, selectionForContextMenu);
|
|
}
|
|
}
|
|
|
|
readonly property var markNotFavoriteAction: Kirigami.Action {
|
|
text: i18nc("@action:intoolbar Button to remove the \"favorite\" property of a podcast episode", "Remove from Favorites")
|
|
icon.name: "non-starred-symbolic"
|
|
visible: listView.selectionModel.hasSelection && (singleSelectedEntry ? singleSelectedEntry.favorite : true)
|
|
onTriggered: {
|
|
DataManager.bulkMarkFavoriteByIndex(false, selectionForContextMenu);
|
|
}
|
|
}
|
|
|
|
readonly property var downloadEnclosureAction: Kirigami.Action {
|
|
text: i18n("Download")
|
|
icon.name: "download"
|
|
visible: listView.selectionModel.hasSelection && (singleSelectedEntry ? (singleSelectedEntry.hasEnclosure ? singleSelectedEntry.enclosure.status !== Enclosure.Downloaded : false) : true)
|
|
onTriggered: {
|
|
downloadOverlay.selection = selectionForContextMenu;
|
|
downloadOverlay.run();
|
|
}
|
|
}
|
|
|
|
readonly property var deleteEnclosureAction: Kirigami.Action {
|
|
text: i18ncp("context menu action", "Delete Download", "Delete Downloads", selectionForContextMenu.length)
|
|
icon.name: "delete"
|
|
visible: listView.selectionModel.hasSelection && (singleSelectedEntry ? (singleSelectedEntry.hasEnclosure ? singleSelectedEntry.enclosure.status !== Enclosure.Downloadable : false) : true)
|
|
onTriggered: {
|
|
DataManager.bulkDeleteEnclosuresByIndex(selectionForContextMenu);
|
|
}
|
|
}
|
|
|
|
readonly property var streamAction: Kirigami.Action {
|
|
text: i18nc("@action:inmenu Action to start playback by streaming the episode rather than downloading it first", "Stream")
|
|
icon.name: "media-playback-cloud"
|
|
visible: listView.selectionModel.hasSelection && (singleSelectedEntry ? (singleSelectedEntry.hasEnclosure ? singleSelectedEntry.enclosure.status !== Enclosure.Downloaded : false) : false)
|
|
onTriggered: {
|
|
if (!singleSelectedEntry.queueStatus) {
|
|
singleSelectedEntry.queueStatus = true;
|
|
}
|
|
AudioManager.entry = singleSelectedEntry;
|
|
AudioManager.play();
|
|
}
|
|
}
|
|
|
|
readonly property var defaultActionList: [addToQueueAction,
|
|
removeFromQueueAction,
|
|
markPlayedAction,
|
|
markNotPlayedAction,
|
|
markNewAction,
|
|
markNotNewAction,
|
|
markFavoriteAction,
|
|
markNotFavoriteAction,
|
|
downloadEnclosureAction,
|
|
deleteEnclosureAction,
|
|
streamAction,
|
|
selectAllAction,
|
|
selectNoneAction]
|
|
|
|
property Controls.Menu contextMenu: Controls.Menu {
|
|
id: contextMenu
|
|
|
|
Controls.MenuItem {
|
|
action: listView.addToQueueAction
|
|
visible: !listView.isQueue && (singleSelectedEntry ? !singleSelectedEntry.queueStatus : true)
|
|
height: visible ? implicitHeight : 0 // workaround for qqc2-breeze-style
|
|
}
|
|
Controls.MenuItem {
|
|
action: listView.removeFromQueueAction
|
|
visible: singleSelectedEntry ? singleSelectedEntry.queueStatus : true
|
|
height: visible ? implicitHeight : 0 // workaround for qqc2-breeze-style
|
|
}
|
|
Controls.MenuItem {
|
|
action: listView.markPlayedAction
|
|
visible: singleSelectedEntry ? !singleSelectedEntry.read : true
|
|
height: visible ? implicitHeight : 0 // workaround for qqc2-breeze-style
|
|
}
|
|
Controls.MenuItem {
|
|
action: listView.markNotPlayedAction
|
|
visible: singleSelectedEntry ? singleSelectedEntry.read : true
|
|
height: visible ? implicitHeight : 0 // workaround for qqc2-breeze-style
|
|
}
|
|
Controls.MenuItem {
|
|
action: listView.markNewAction
|
|
visible: singleSelectedEntry ? !singleSelectedEntry.new : true
|
|
height: visible ? implicitHeight : 0 // workaround for qqc2-breeze-style
|
|
}
|
|
Controls.MenuItem {
|
|
action: listView.markNotNewAction
|
|
visible: singleSelectedEntry ? singleSelectedEntry.new : true
|
|
height: visible ? implicitHeight : 0 // workaround for qqc2-breeze-style
|
|
}
|
|
Controls.MenuItem {
|
|
action: listView.markFavoriteAction
|
|
visible: singleSelectedEntry ? !singleSelectedEntry.favorite : true
|
|
height: visible ? implicitHeight : 0 // workaround for qqc2-breeze-style
|
|
}
|
|
Controls.MenuItem {
|
|
action: listView.markNotFavoriteAction
|
|
visible: singleSelectedEntry ? singleSelectedEntry.favorite : true
|
|
height: visible ? implicitHeight : 0 // workaround for qqc2-breeze-style
|
|
}
|
|
Controls.MenuItem {
|
|
action: listView.downloadEnclosureAction
|
|
visible: singleSelectedEntry ? (singleSelectedEntry.hasEnclosure ? singleSelectedEntry.enclosure.status !== Enclosure.Downloaded : false) : true
|
|
height: visible ? implicitHeight : 0 // workaround for qqc2-breeze-style
|
|
}
|
|
Controls.MenuItem {
|
|
action: listView.deleteEnclosureAction
|
|
visible: singleSelectedEntry ? (singleSelectedEntry.hasEnclosure ? singleSelectedEntry.enclosure.status !== Enclosure.Downloadable : false) : true
|
|
height: visible ? implicitHeight : 0 // workaround for qqc2-breeze-style
|
|
}
|
|
Controls.MenuItem {
|
|
action: listView.streamAction
|
|
visible: singleSelectedEntry ? (singleSelectedEntry.hasEnclosure ? singleSelectedEntry.enclosure.status !== Enclosure.Downloaded : false) : false
|
|
height: visible ? implicitHeight : 0 // workaround for qqc2-breeze-style
|
|
}
|
|
onClosed: {
|
|
// reset to normal selection if this context menu is closed
|
|
listView.selectionForContextMenu = listView.selectionModel.selectedIndexes;
|
|
}
|
|
}
|
|
}
|