import QtQuick 2.15 import QtQuick.Controls 2.3 import QtQuick.Layouts 1.0 import org.kde.kirigami 2.20 as Kirigami import "../../Mpdw.js" as Mpdw import "../../Components/Elements" import "../../Components/Songlist" import "../../Components/Queue" Kirigami.ScrollablePage { id: queuePage readonly property string globalShortcut: "1" Layout.fillWidth: true title: qsTr("Queue") visible: false globalToolBarStyle: Kirigami.ApplicationHeaderStyle.None header: ToolBar { RowLayout { anchors.fill: parent GlobalNav { } RowLayout { Kirigami.ActionToolBar { id: actionToolBar alignment: Qt.AlignRight actions: [ Kirigami.Action { id: followCurrentSong text: qsTr("Follow Playing Song") icon.name: Mpdw.icons.queueFollowMode tooltip: qsTr("Follow Mode - Scroll the queue to keep the currently playing song visible.") + " (" + qsTr("L") + ")" // @i18n shortcut: "shift+l" displayHint: Kirigami.DisplayHint.IconOnly checkable: true checked: true }, Kirigami.Action { text: qsTr("Queue") Kirigami.Action { icon.name: Mpdw.icons.queueSaveNew text: qsTr("Save as New Playlist…") shortcut: "s" onTriggered: { queueDialogSave.open() } } Kirigami.Action { icon.name: Mpdw.icons.queueSaveReplace text: qsTr("Replace Playlist…") shortcut: "shift+s" onTriggered: { queueDialogReplacePl.open() } } Kirigami.Action { separator: true } Kirigami.Action { icon.name: mpdToggleConsumeAct.icon.name text: mpdToggleConsumeAct.text shortcut: mpdToggleConsumeAct.shortcut tooltip: mpdToggleConsumeAct.tooltip onTriggered: mpdToggleConsumeAct.onTriggered() } Kirigami.Action { icon.name: mpdToggleRandomAct.icon.name text: mpdToggleRandomAct.text shortcut: mpdToggleRandomAct.shortcut tooltip: mpdToggleRandomAct.tooltip onTriggered: mpdToggleRandomAct.onTriggered() } Kirigami.Action { icon.name: mpdToggleRepeatAct.icon.name text: mpdToggleRepeatAct.text shortcut: mpdToggleRepeatAct.shortcut tooltip: mpdToggleRepeatAct.tooltip onTriggered: mpdToggleRepeatAct.onTriggered() } Kirigami.Action { separator: true } Kirigami.Action { text: qsTr("Clear Queue") icon.name: Mpdw.icons.queueClear tooltip: text + " (" + qsTr("Shift+C") + ")" // @i18n shortcut: "shift+c" displayHint: Kirigami.DisplayHint.IconOnly onTriggered: { mpdState.clearQueue() } } } ] } } } } SonglistView { id: songlistView header: SonglistHeader { leftActions: [ Kirigami.Action { id: rmSelctBtn text: qsTr("Remove") tooltip: qsTr("Remove Selected Songs") icon.name: Mpdw.icons.queueRemoveSelected shortcut: "Del" enabled: numberSelected onTriggered: { let positions = songlistView.getSelectedPositionsMpdBased() songlistView.removeSelection() songlistView.updateMpdPositions() mpdState.removeFromQueue(positions) } } ] // @TODO Should be default action of SonglistView without repeating here rightActions: [ Kirigami.Action { text: appWindow.narrowLayout ? "" : qsTr("Deselect") tooltip: qsTr("Deselect All") icon.name: Mpdw.icons.selectNone shortcut: "Shift+D" onTriggered: { songlistView.deselectAll() } } ] } function showCurrentItemInList() { if (!appWindow.visible) { return } let index = mpdState.mpdInfo.position - 1 songlistView.currentIndex = index centerInView(index) } onSelectedChanged: { // @TODO songlistView.headerItem.numberSelected = selected.length } Kirigami.PlaceholderMessage { anchors.centerIn: parent width: parent.width - (Kirigami.Units.largeSpacing * 4) text: qsTr("Queue is empty") visible: !mpdState.countQueue() } delegate: SonglistItem { id: songlistItem coverLoadingPriority: 50 isSortable: true parentView: songlistView playingIndex: mpdState.mpdInfo.position ? mpdState.mpdInfo.position - 1 : -1 carretIndex: songlistView.currentIndex actions: [ Kirigami.Action { icon.name: (playingIndex === model.index && mpdState.mpdPlaying) ? Mpdw.icons.queuePause : Mpdw.icons.queuePlay text: qsTr("Play Now") onTriggered: { if (playingIndex === model.index) { mpdState.toggle() } else { mpdState.playInQueue(model.position) } } }, Kirigami.Action { icon.name: Mpdw.icons.queueRemoveSingle text: qsTr("Remove from Queue") visible: !appWindow.narrowLayout onTriggered: { let index = model.index songlistView.model.remove(index) songlistView.updateMpdPositions() mpdState.removeFromQueue([index + 1]) } } ] } Keys.onPressed: { if (event.key === Qt.Key_L) { songlistView.showCurrentItemInList() } } Connections { function onUserInteracted() { if (!followCurrentSong.checked) { return } followCurrentSong.checked = false disableFollowOnEditTimer.restart() } } Timer { id: disableFollowOnEditTimer interval: 120000 onTriggered: { followCurrentSong.checked = true songlistView.showCurrentItemInList() } } } Connections { target: mpdState function onMpdQueueChanged() { // Queue is empty, clear everything if (mpdState.mpdQueue.length === 0) { songlistView.model.clear() return } var i = 0 for (i; i < mpdState.mpdQueue.length; i++) { let mpdSong = mpdState.mpdQueue[i] let ourSong = songlistView.model.get(i) //console.log("------- Queue Refresh Item ---------") //console.log(`mpd-file: ${mpdSong.file}`) if (ourSong) { // console.log(`our-file: ${ourSong.file}`) if (mpdSong.file === ourSong.file) { //console.log('Keeping our song.') // As long as mpd-queue matches ours do nothing continue } else { // Clear out selection (cache) of the item songlistView.select(i, false) // console.log('Removing our song.') songlistView.model.remove(i) } } songlistView.model.insert(i, mpdSong) } // Remove all additional items in our queue not in mpd's for (let k = songlistView.count - 1; k >= i; k--) { songlistView.model.remove(k) } if (followCurrentSong.checked) { songlistView.showCurrentItemInList() } } function onMpdInfoChanged() { if (followCurrentSong.checked) { songlistView.showCurrentItemInList() } } function onPlayedPlaylist(playlist) { queueDialogReplacePl.selectPlaylist(playlist) } } Component.onCompleted: { // @BOGUS Initiates triggering populating Queue and Playlists on app // window opening. Make it ask properly for the already available data from // mpdState in both places. Required for Loader those pages anyway. mpdState.update() } Connections { target: appWindow function onHeightChanged() { if (followCurrentSong.checked) { songlistView.showCurrentItemInList() } } } onVisibleChanged: { if (visible) { songlistView.forceActiveFocus() } } // @SOMEDAY loader QueueDialogSave { id: queueDialogSave } // @SOMEDAY loader QueueDialogReplacePl { id: queueDialogReplacePl } }