diff --git a/src/qml/ContentView.qml b/src/qml/ContentView.qml index bc1ff06d..129c89ff 100644 --- a/src/qml/ContentView.qml +++ b/src/qml/ContentView.qml @@ -1,393 +1,395 @@ /* * Copyright 2016-2018 Matthieu Gallien * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 3 of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . */ import QtQuick 2.7 import QtQuick.Controls 2.2 import QtQuick.Layouts 1.2 import QtQuick.Window 2.2 import org.kde.elisa 1.0 RowLayout { id: contentViewContainer spacing: 0 property bool showPlaylist + property bool showExpandedFilterView property alias currentViewIndex: listViews.currentIndex - signal toggleSearch() - function goBack() { viewManager.goBack() } function openArtist(name) { viewManager.openChildView(name, '', elisaTheme.artistIcon, 0, ElisaUtils.Artist, ViewManager.NoDiscHeaders) } function openAlbum(album, artist, image, albumID, showDiscHeader) { image = !image ? elisaTheme.defaultAlbumImage : image; viewManager.openChildView(album, artist, image, albumID, ElisaUtils.Album, showDiscHeader); } function openNowPlaying() { viewManager.closeAllViews(); } ViewManager { id: viewManager onSwitchOffAllViews: { listViews.setCurrentIndex(pageModel.indexFromViewType(viewType)) while(browseStackView.depth > 1) { browseStackView.pop() } } onOpenGridView: { if (expectedDepth === 1) { listViews.setCurrentIndex(pageModel.indexFromViewType(viewType)) } while(browseStackView.depth > expectedDepth) { browseStackView.pop() } browseStackView.push(dataGridView, { viewType: viewType, filterType: filterType, mainTitle: pageModel.viewMainTitle(viewType, mainTitle), secondaryTitle: secondaryTitle, image: pageModel.viewImageUrl(viewType, imageUrl), modelType: dataType, defaultIcon: viewDefaultIcon, showRating: viewShowRating, delegateDisplaySecondaryText: viewDelegateDisplaySecondaryText, genreFilterText: genreNameFilter, artistFilter: artistNameFilter, isSubPage: (browseStackView.depth >= 2), stackView: browseStackView, opacity: 0, }) } onOpenListView: { listViews.setCurrentIndex(pageModel.indexFromViewType(viewType)) while(browseStackView.depth > expectedDepth) { browseStackView.pop() } browseStackView.push(dataListView, { viewType: viewType, filterType: filterType, isSubPage: expectedDepth > 1, mainTitle: mainTitle, secondaryTitle: secondaryTitle, databaseId: databaseId, image: imageUrl, modelType: dataType, sortRole: sortRole, sortAscending: sortOrder, stackView: browseStackView, displaySingleAlbum: displaySingleAlbum, showSection: showDiscHeaders, opacity: 0, }) } onSwitchFilesBrowserView: { listViews.setCurrentIndex(pageModel.indexFromViewType(viewType)) while(browseStackView.depth > expectedDepth) { browseStackView.pop() } browseStackView.push(filesBrowserView, { viewType: viewType, mainTitle: mainTitle, image: imageUrl, opacity: 0, }) } onSwitchContextView: { listViews.setCurrentIndex(pageModel.indexFromViewType(viewType)) while(browseStackView.depth > expectedDepth) { browseStackView.pop() } browseStackView.push(albumContext, { viewType: viewType, mainTitle: mainTitle, image: imageUrl, opacity: 0, }) } onPopOneView: { if (browseStackView.depth > 2) { browseStackView.pop() } } } ViewsModel { id: pageModel } ViewSelector { id: listViews model: pageModel Layout.fillHeight: true Behavior on Layout.maximumWidth { NumberAnimation { duration: 150 } } onSwitchView: viewManager.openParentView(viewType, pageModel.viewMainTitle(viewType, ""), pageModel.viewImageUrl(viewType, "")) } Rectangle { id: viewSelectorSeparatorItem Layout.fillHeight: true width: 1 color: myPalette.mid } ColumnLayout { Layout.fillHeight: true Layout.fillWidth: true spacing: 0 TopNotification { id: invalidBalooConfiguration Layout.fillWidth: true musicManager: elisa.musicManager focus: true } Item { Layout.fillHeight: true Layout.fillWidth: true RowLayout { anchors.fill: parent spacing: 0 id: contentZone FocusScope { id: mainContentView focus: true Layout.fillHeight: true visible: Layout.minimumWidth != 0 MouseArea { anchors.fill: parent acceptedButtons: Qt.BackButton onClicked: goBack() } Rectangle { radius: 3 color: myPalette.base anchors.fill: parent StackView { id: browseStackView anchors.fill: parent clip: true initialItem: Item { } popEnter: Transition { OpacityAnimator { from: 0.0 to: 1.0 duration: 300 } } popExit: Transition { OpacityAnimator { from: 1.0 to: 0.0 duration: 300 } } pushEnter: Transition { OpacityAnimator { from: 0.0 to: 1.0 duration: 300 } } pushExit: Transition { OpacityAnimator { from: 1.0 to: 0.0 duration: 300 } } replaceEnter: Transition { OpacityAnimator { from: 0.0 to: 1.0 duration: 300 } } replaceExit: Transition { OpacityAnimator { from: 1.0 to: 0.0 duration: 300 } } } } } Rectangle { id: firstViewSeparatorItem Layout.fillHeight: true width: 1 color: myPalette.mid } MediaPlayListView { id: playList Layout.fillHeight: true Layout.fillWidth: true onStartPlayback: elisa.audioControl.ensurePlay() onPausePlayback: elisa.audioControl.playPause() } } } states: [ State { name: "browsingViewsNoPlaylist" when: contentViewContainer.showPlaylist === false extend: "browsingViews" PropertyChanges { target: mainContentView Layout.minimumWidth: contentZone.width Layout.maximumWidth: contentZone.width Layout.preferredWidth: contentZone.width } PropertyChanges { target: playList Layout.minimumWidth: 0 Layout.maximumWidth: 0 Layout.preferredWidth: 0 } }, State { name: 'browsingViews' when: contentViewContainer.showPlaylist === true PropertyChanges { target: mainContentView Layout.minimumWidth: contentZone.width * 0.66 Layout.maximumWidth: contentZone.width * 0.68 Layout.preferredWidth: contentZone.width * 0.68 } PropertyChanges { target: firstViewSeparatorItem Layout.minimumWidth: 1 Layout.maximumWidth: 1 Layout.preferredWidth: 1 } } ] transitions: Transition { NumberAnimation { properties: "Layout.minimumWidth, Layout.maximumWidth, Layout.preferredWidth, opacity" easing.type: Easing.InOutQuad duration: 300 } } } Component { id: dataGridView DataGridView { StackView.onActivated: viewManager.viewIsLoaded(viewType) + expandedFilterView: showExpandedFilterView } } Component { id: dataListView DataListView { StackView.onActivated: viewManager.viewIsLoaded(viewType) + expandedFilterView: showExpandedFilterView } } Component { id: filesBrowserView FileBrowserView { StackView.onActivated: viewManager.viewIsLoaded(viewType) + expandedFilterView: showExpandedFilterView } } Component { id: albumContext ContextView { StackView.onActivated: viewManager.viewIsLoaded(viewType) databaseId: elisa.manageHeaderBar.databaseId title: elisa.manageHeaderBar.title artistName: elisa.manageHeaderBar.artist albumName: elisa.manageHeaderBar.album albumArtUrl: elisa.manageHeaderBar.image fileUrl: elisa.manageHeaderBar.fileName } } } diff --git a/src/qml/DataGridView.qml b/src/qml/DataGridView.qml index b0bec678..87266c71 100644 --- a/src/qml/DataGridView.qml +++ b/src/qml/DataGridView.qml @@ -1,109 +1,110 @@ /* * Copyright 2018 Matthieu Gallien * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 3 of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . */ import QtQuick 2.10 import QtQuick.Controls 2.3 import org.kde.kirigami 2.5 as Kirigami import org.kde.elisa 1.0 FocusScope { id: viewHeader property var viewType property var filterType property alias mainTitle: gridView.mainTitle property alias secondaryTitle: gridView.secondaryTitle property alias image: gridView.image property var modelType property alias defaultIcon: gridView.defaultIcon property alias showRating: gridView.showRating property alias delegateDisplaySecondaryText: gridView.delegateDisplaySecondaryText property alias isSubPage: gridView.isSubPage + property alias expandedFilterView: gridView.expandedFilterView property string genreFilterText property string artistFilter focus: true Accessible.role: Accessible.Pane Accessible.name: mainTitle function initializeModel() { realModel.initialize(elisa.musicManager, elisa.musicManager.viewDatabase, modelType, filterType, genreFilterText, artistFilter, 0) } DataModel { id: realModel } GridViewProxyModel { id: proxyModel sourceModel: realModel dataType: modelType onEntriesToEnqueue: elisa.mediaPlayList.enqueue(newEntries, databaseIdType, enqueueMode, triggerPlay) } GridBrowserView { id: gridView focus: true anchors.fill: parent contentModel: proxyModel onEnqueue: elisa.mediaPlayList.enqueue(databaseId, name, modelType, ElisaUtils.AppendPlayList, ElisaUtils.DoNotTriggerPlay) onReplaceAndPlay: elisa.mediaPlayList.enqueue(databaseId, name, modelType, ElisaUtils.ReplacePlayList, ElisaUtils.TriggerPlay) onOpen: viewManager.openChildView(innerMainTitle, innerSecondaryTitle, innerImage, databaseId, dataType, showDiscHeader) onGoBack: viewManager.goBack() Loader { anchors.centerIn: parent height: Kirigami.Units.gridUnit * 5 width: height visible: realModel.isBusy active: realModel.isBusy sourceComponent: BusyIndicator { anchors.centerIn: parent } } } Connections { target: elisa onMusicManagerChanged: initializeModel() } Component.onCompleted: { if (elisa.musicManager) { initializeModel() } } } diff --git a/src/qml/DataListView.qml b/src/qml/DataListView.qml index 6bbe41d1..14b54c06 100644 --- a/src/qml/DataListView.qml +++ b/src/qml/DataListView.qml @@ -1,190 +1,191 @@ /* * Copyright 2018 Matthieu Gallien * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 3 of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . */ import QtQuick 2.10 import QtQuick.Controls 2.3 import org.kde.kirigami 2.5 as Kirigami import org.kde.elisa 1.0 FocusScope { id: viewHeader property var viewType property var filterType property alias isSubPage: listView.isSubPage property alias mainTitle: listView.mainTitle property alias secondaryTitle: listView.secondaryTitle property int databaseId property alias showSection: listView.showSection + property alias expandedFilterView: listView.expandedFilterView property alias image: listView.image property var modelType property alias sortRole: proxyModel.sortRole property var sortAscending property bool displaySingleAlbum: false DataModel { id: realModel } AllTracksProxyModel { id: proxyModel sourceModel: realModel onEntriesToEnqueue: elisa.mediaPlayList.enqueue(newEntries, databaseIdType, enqueueMode, triggerPlay) } Component { id: singleAlbumDelegate ListBrowserDelegate { id: entry width: listView.delegateWidth height: ((true && !true) ? elisaTheme.delegateHeight*2 : elisaTheme.delegateHeight) focus: true databaseId: model.databaseId title: model.title ? model.title : '' artist: model.artist ? model.artist : '' album: model.album ? model.album : '' albumArtist: model.albumArtist ? model.albumArtist : '' duration: model.duration imageUrl: model.imageUrl ? model.imageUrl : '' trackNumber: model.trackNumber ? model.trackNumber : -1 discNumber: model.discNumber ? model.discNumber : -1 rating: model.rating isSingleDiscAlbum: true isSelected: listView.currentIndex === index isAlternateColor: (index % 2) === 1 detailedView: false onEnqueue: elisa.mediaPlayList.enqueue(databaseId, name, ElisaUtils.Track, ElisaUtils.AppendPlayList, ElisaUtils.DoNotTriggerPlay) onReplaceAndPlay: elisa.mediaPlayList.enqueue(databaseId, name, ElisaUtils.Track, ElisaUtils.ReplacePlayList, ElisaUtils.TriggerPlay) onClicked: listView.currentIndex = index onActiveFocusChanged: { if (activeFocus && listView.currentIndex !== index) { listView.currentIndex = index } } } } Component { id: multipleDiscDelegate ListBrowserDelegate { id: entry width: listView.delegateWidth height: elisaTheme.trackDelegateHeight focus: true databaseId: model.databaseId title: model.title ? model.title : '' artist: model.artist ? model.artist : '' album: model.album ? model.album : '' albumArtist: model.albumArtist ? model.albumArtist : '' duration: model.duration imageUrl: model.imageUrl ? model.imageUrl : '' trackNumber: model.trackNumber ? model.trackNumber : -1 discNumber: model.discNumber ? model.discNumber : -1 rating: model.rating isSingleDiscAlbum: model.isSingleDiscAlbum isSelected: listView.currentIndex === index isAlternateColor: (index % 2) === 1 onEnqueue: elisa.mediaPlayList.enqueue(databaseId, name, modelType, ElisaUtils.AppendPlayList, ElisaUtils.DoNotTriggerPlay) onReplaceAndPlay: elisa.mediaPlayList.enqueue(databaseId, name, modelType, ElisaUtils.ReplacePlayList, ElisaUtils.TriggerPlay) onClicked: { listView.currentIndex = index entry.forceActiveFocus() } } } ListBrowserView { id: listView focus: true anchors.fill: parent contentModel: proxyModel delegate: (displaySingleAlbum ? singleAlbumDelegate : multipleDiscDelegate) enableSorting: !displaySingleAlbum allowArtistNavigation: isSubPage onShowArtist: { viewManager.openChildView(secondaryTitle, '', elisaTheme.artistIcon, 0, ElisaUtils.Artist, ViewManager.NoDiscHeaders) } onGoBack: viewManager.goBack() Loader { anchors.centerIn: parent height: Kirigami.Units.gridUnit * 5 width: height visible: realModel.isBusy active: realModel.isBusy sourceComponent: BusyIndicator { anchors.centerIn: parent } } } Connections { target: elisa onMusicManagerChanged: realModel.initialize(elisa.musicManager, elisa.musicManager.viewDatabase, modelType) } Component.onCompleted: { if (elisa.musicManager) { realModel.initialize(elisa.musicManager, elisa.musicManager.viewDatabase, modelType, filterType, mainTitle, secondaryTitle, databaseId) } if (sortAscending === ViewManager.SortAscending) { proxyModel.sortModel(Qt.AscendingOrder) } else if (sortAscending === ViewManager.SortDescending) { proxyModel.sortModel(Qt.DescendingOrder) } } } diff --git a/src/qml/ElisaMainWindow.qml b/src/qml/ElisaMainWindow.qml index 29c19c38..d93c0ff8 100644 --- a/src/qml/ElisaMainWindow.qml +++ b/src/qml/ElisaMainWindow.qml @@ -1,321 +1,328 @@ /* * Copyright 2016-2018 Matthieu Gallien * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 3 of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . */ import QtQuick 2.7 import QtQuick.Controls 2.3 import QtQuick.Layouts 1.1 import QtQuick.Window 2.2 import org.kde.elisa 1.0 import Qt.labs.settings 1.0 ApplicationWindow { id: mainWindow visible: true minimumWidth: contentView.showPlaylist ? 1100 : 700 minimumHeight: 600 LayoutMirroring.enabled: Qt.application.layoutDirection == Qt.RightToLeft LayoutMirroring.childrenInherit: true x: persistentSettings.x y: persistentSettings.y width: persistentSettings.width height: persistentSettings.height title: i18n("Elisa") Accessible.role: Accessible.Application Accessible.name: title property var goBackAction: elisa.action("go_back") property var seekAction: elisa.action("Seek") property var scrubAction: elisa.action("Scrub") property var playPauseAction: elisa.action("Play-Pause") + property var findAction: elisa.action("edit_find") Action { shortcut: goBackAction.shortcut onTriggered: contentView.goBack() } Action { - shortcut: seekAction.shortcut - onTriggered: elisa.audioControl.seek(headerBar.playerControl.position + 10000) + shortcut: seekAction.shortcut + onTriggered: elisa.audioControl.seek(headerBar.playerControl.position + 10000) } Action { - shortcut: scrubAction.shortcut - onTriggered: elisa.audioControl.seek(headerBar.playerControl.position - 10000) + shortcut: scrubAction.shortcut + onTriggered: elisa.audioControl.seek(headerBar.playerControl.position - 10000) } Action { - shortcut: playPauseAction.shortcut - onTriggered: elisa.audioControl.playPause() + shortcut: playPauseAction.shortcut + onTriggered: elisa.audioControl.playPause() + } + + Action { + shortcut: findAction.shortcut + onTriggered: persistentSettings.expandedFilterView = !persistentSettings.expandedFilterView } ApplicationMenu { id: applicationMenu } SystemPalette { id: myPalette colorGroup: SystemPalette.Active } Theme { id: elisaTheme } Settings { id: persistentSettings property int x property int y property int width : 1100 property int height : 600 property var playListState property var audioPlayerState property double playControlItemVolume : 100.0 property bool playControlItemMuted : false property bool expandedFilterView: false property bool showPlaylist: true property bool headerBarIsMaximized: false } Connections { target: headerBar.playerControl onOpenMenu: applicationMenu.popup() } Connections { target: Qt.application onAboutToQuit: { persistentSettings.x = mainWindow.x; persistentSettings.y = mainWindow.y; persistentSettings.width = mainWindow.width; persistentSettings.height = mainWindow.height; persistentSettings.playListState = elisa.mediaPlayList.persistentState; persistentSettings.audioPlayerState = elisa.audioControl.persistentState persistentSettings.playControlItemVolume = headerBar.playerControl.volume persistentSettings.playControlItemMuted = headerBar.playerControl.muted persistentSettings.showPlaylist = contentView.showPlaylist persistentSettings.headerBarIsMaximized = headerBar.isMaximized } } Loader { id: mprisloader active: false sourceComponent: PlatformIntegration { id: platformInterface playListModel: elisa.mediaPlayList audioPlayerManager: elisa.audioControl player: elisa.audioPlayer headerBarManager: elisa.manageHeaderBar manageMediaPlayerControl: elisa.playerControl onRaisePlayer: { mainWindow.show() mainWindow.raise() mainWindow.requestActivate() } } } Connections { target: elisa.audioPlayer onVolumeChanged: headerBar.playerControl.volume = elisa.audioPlayer.volume onMutedChanged: headerBar.playerControl.muted = elisa.audioPlayer.muted } Rectangle { color: myPalette.base anchors.fill: parent ColumnLayout { anchors.fill: parent spacing: 0 HeaderBar { id: headerBar focus: true Layout.minimumHeight: mainWindow.height * 0.2 + elisaTheme.mediaPlayerControlHeight Layout.maximumHeight: mainWindow.height * 0.2 + elisaTheme.mediaPlayerControlHeight Layout.fillWidth: true tracksCount: elisa.manageHeaderBar.remainingTracks album: elisa.manageHeaderBar.album title: elisa.manageHeaderBar.title artist: elisa.manageHeaderBar.artist albumArtist: elisa.manageHeaderBar.albumArtist image: elisa.manageHeaderBar.image albumID: elisa.manageHeaderBar.albumId ratingVisible: false playerControl.duration: elisa.audioPlayer.duration playerControl.seekable: elisa.audioPlayer.seekable playerControl.volume: persistentSettings.playControlItemVolume playerControl.muted: persistentSettings.playControlItemMuted playerControl.position: elisa.audioPlayer.position playerControl.skipBackwardEnabled: elisa.playerControl.skipBackwardControlEnabled playerControl.skipForwardEnabled: elisa.playerControl.skipForwardControlEnabled playerControl.playEnabled: elisa.playerControl.playControlEnabled playerControl.isPlaying: elisa.playerControl.musicPlaying playerControl.repeat: elisa.mediaPlayList.repeatPlay playerControl.shuffle: elisa.mediaPlayList.randomPlay playerControl.onSeek: elisa.audioPlayer.seek(position) playerControl.onPlay: elisa.audioControl.playPause() playerControl.onPause: elisa.audioControl.playPause() playerControl.onPlayPrevious: elisa.mediaPlayList.skipPreviousTrack() playerControl.onPlayNext: elisa.mediaPlayList.skipNextTrack() playerControl.isMaximized: persistentSettings.headerBarIsMaximized onOpenArtist: { contentView.openArtist(artist) } onOpenNowPlaying: { contentView.openNowPlaying() } onOpenAlbum: { contentView.openAlbum(album, albumArtist, image, albumID) } TrackImportNotification { id: importedTracksCountNotification anchors { right: headerBar.right top: headerBar.top rightMargin: elisaTheme.layoutHorizontalMargin * 1.75 topMargin: elisaTheme.layoutHorizontalMargin * 3 } } Binding { id: indexerBusyBinding target: importedTracksCountNotification property: 'indexingRunning' value: elisa.musicManager.indexerBusy when: elisa.musicManager !== undefined } Binding { target: importedTracksCountNotification property: 'importedTracksCount' value: elisa.musicManager.importedTracksCount when: elisa.musicManager !== undefined } } Rectangle { Layout.fillWidth: true height: 1 color: myPalette.mid } ContentView { id: contentView Layout.fillHeight: true Layout.fillWidth: true showPlaylist: persistentSettings.showPlaylist + showExpandedFilterView: persistentSettings.expandedFilterView } } } StateGroup { id: mainWindowState states: [ State { name: "headerBarIsNormal" when: !headerBar.isMaximized changes: [ PropertyChanges { target: mainWindow minimumHeight: 600 explicit: true }, PropertyChanges { target: headerBar Layout.minimumHeight: mainWindow.height * 0.2 + elisaTheme.mediaPlayerControlHeight Layout.maximumHeight: mainWindow.height * 0.2 + elisaTheme.mediaPlayerControlHeight } ] }, State { name: "headerBarIsMaximized" when: headerBar.isMaximized changes: [ PropertyChanges { target: mainWindow minimumHeight: 120 + elisaTheme.mediaPlayerControlHeight explicit: true }, PropertyChanges { target: headerBar Layout.minimumHeight: mainWindow.height Layout.maximumHeight: mainWindow.height } ] } ] transitions: Transition { NumberAnimation { properties: "Layout.minimumHeight, Layout.maximumHeight, minimumHeight" easing.type: Easing.InOutQuad duration: 300 } } } Component.onCompleted: { elisa.initialize() if (persistentSettings.playListState) { elisa.mediaPlayList.persistentState = persistentSettings.playListState } if (persistentSettings.audioPlayerState) { elisa.audioControl.persistentState = persistentSettings.audioPlayerState } elisa.mediaPlayList.randomPlay = Qt.binding(function() { return headerBar.playerControl.shuffle }) elisa.mediaPlayList.repeatPlay = Qt.binding(function() { return headerBar.playerControl.repeat }) elisa.playerControl.randomOrContinuePlay = Qt.binding(function() { return headerBar.playerControl.shuffle || headerBar.playerControl.repeat}) elisa.audioPlayer.muted = Qt.binding(function() { return headerBar.playerControl.muted }) elisa.audioPlayer.volume = Qt.binding(function() { return headerBar.playerControl.volume }) mprisloader.active = true } } diff --git a/src/qml/NavigationActionBar.qml b/src/qml/NavigationActionBar.qml index 2af350c3..611bc137 100644 --- a/src/qml/NavigationActionBar.qml +++ b/src/qml/NavigationActionBar.qml @@ -1,309 +1,305 @@ /* * Copyright 2016 Matthieu Gallien * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 3 of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . */ import QtQml 2.2 import QtQuick 2.7 import QtQuick.Layouts 1.3 import QtQuick.Controls 2.3 ColumnLayout { id: navigationBar spacing: 0 property string mainTitle property string secondaryTitle property url image property bool allowArtistNavigation: false property string labelText property bool showRating: true property alias filterText: filterTextInput.text property alias filterRating: ratingFilter.starRating property bool enableGoBack: true - property bool expandedFilterView: persistentSettings.expandedFilterView + property bool expandedFilterView property bool enableSorting: true property bool sortOrder - property var findAction: elisa.action("edit_find") + signal enqueue(); signal replaceAndPlay(); signal goBack(); signal showArtist(); signal sort(var order); Action { id: goPreviousAction text: i18nc("navigate back in the views stack", "Back") icon.name: (Qt.application.layoutDirection == Qt.RightToLeft) ? "go-next" : "go-previous" onTriggered: goBack() enabled: enableGoBack } Action { id: replaceAndPlayAction text: i18n("Play now, replacing contents of Playlist") icon.name: "media-playback-start" onTriggered: replaceAndPlay() } Action { id: enqueueAction text: i18nc("Add current list to playlist", "Enqueue") icon.name: "media-track-add-amarok" onTriggered: enqueue() } Action { id: showFilterAction - shortcut: findAction.shortcut text: !navigationBar.expandedFilterView ? i18nc("Show filters in the navigation bar", "Show Search Options") : i18nc("Hide filters in the navigation bar", "Hide Search Options") icon.name: 'search' checkable: true - checked: filterRow.opacity == 1.0 - onTriggered: { - persistentSettings.expandedFilterView = !persistentSettings.expandedFilterView - expandedFilterView = persistentSettings.expandedFilterView - if (expandedFilterView) { - filterTextInput.forceActiveFocus() - } - } + checked: expandedFilterView + onTriggered: persistentSettings.expandedFilterView = !persistentSettings.expandedFilterView } Action { id: sortAction text: i18nc("Toggle between ascending and descending order", "Toggle sort order") icon.name: sortOrder ? "view-sort-ascending" : "view-sort-descending" onTriggered: sortOrder ? sort(Qt.DescendingOrder) : sort(Qt.AscendingOrder) } Action { id: showArtistAction text: i18nc("Button to navigate to the artist of the album", "Display Artist") icon.name: "view-media-artist" onTriggered: showArtist() } HeaderFooterToolbar { type: filterRow.visible? "other" : "header" contentItems: [ FlatButtonWithToolTip { action: goPreviousAction id: goPreviousButton objectName: 'goPreviousButton' icon.height: elisaTheme.smallControlButtonSize icon.width: elisaTheme.smallControlButtonSize focus: enableGoBack visible: enableGoBack }, Item { id: spacer width: elisaTheme.layoutHorizontalMargin visible: goPreviousButton.visible }, Image { id: mainIcon source: image height: authorAndAlbumLayout.height width: height sourceSize.height: height sourceSize.width: width fillMode: Image.PreserveAspectFit asynchronous: true Layout.alignment: Qt.AlignVCenter | Qt.AlignLeft }, Item { width: elisaTheme.layoutHorizontalMargin visible: mainIcon.visible }, ColumnLayout { Layout.fillWidth: true Layout.fillHeight: true id: authorAndAlbumLayout LabelWithToolTip { id: albumLabel Layout.alignment: Qt.AlignLeft | Qt.AlignVCenter Layout.fillWidth: true text: mainTitle font.pointSize: authorLabel.visible ? Math.round(elisaTheme.defaultFontPointSize * 1.2) : elisaTheme.headerTitleFontSize font.weight: authorLabel.visible ? Font.Bold : Font.Normal elide: Text.ElideRight } LabelWithToolTip { id: authorLabel Layout.alignment: Qt.AlignLeft | Qt.AlignVCenter Layout.fillWidth: true text: secondaryTitle font.pointSize: elisaTheme.defaultFontPointSize elide: Text.ElideRight visible: secondaryTitle !== "" } }, FlatButtonWithToolTip { action: enqueueAction objectName: 'enqueueButton' icon.height: elisaTheme.smallControlButtonSize icon.width: elisaTheme.smallControlButtonSize focus: true }, FlatButtonWithToolTip { action: replaceAndPlayAction objectName: 'replaceAndPlayButton' icon.height: elisaTheme.smallControlButtonSize icon.width: elisaTheme.smallControlButtonSize }, FlatButtonWithToolTip { action: showArtistAction objectName: 'showArtistButton' icon.height: elisaTheme.smallControlButtonSize icon.width: elisaTheme.smallControlButtonSize visible: allowArtistNavigation }, FlatButtonWithToolTip { action: sortAction objectName: 'sortAscendingButton' icon.height: elisaTheme.smallControlButtonSize icon.width: elisaTheme.smallControlButtonSize visible: enableSorting }, FlatButtonWithToolTip { action: showFilterAction objectName: 'showFilterButton' icon.height: elisaTheme.smallControlButtonSize icon.width: elisaTheme.smallControlButtonSize } ] } HeaderFooterToolbar { type: "header" id: filterRow visible: opacity > 0.0 opacity: 0 contentItems: [ TextField { id: filterTextInput objectName: 'filterTextInput' Layout.fillWidth: true Accessible.role: Accessible.EditableText placeholderText: i18n("Search for album name, artist, etc.") Image { anchors.top: parent.top anchors.bottom: parent.bottom anchors.right: parent.right anchors.margins: elisaTheme.filterClearButtonMargin id: clearText fillMode: Image.PreserveAspectFit smooth: true visible: parent.text source: Qt.resolvedUrl(elisaTheme.clearIcon) height: parent.height width: parent.height sourceSize.width: parent.height sourceSize.height: parent.height mirror: LayoutMirroring.enabled MouseArea { id: clear anchors { horizontalCenter: parent.horizontalCenter; verticalCenter: parent.verticalCenter } height: parent.parent.height width: parent.parent.height onClicked: { parent.parent.text = "" parent.parent.forceActiveFocus() } } } }, Item { width: elisaTheme.layoutHorizontalMargin }, LabelWithToolTip { text: i18n("Filter by rating: ") visible: showRating }, RatingStar { id: ratingFilter objectName: 'ratingFilter' visible: showRating hoverWidgetOpacity: 1 readOnly: false starSize: elisaTheme.ratingStarSize } ] } states: [ State { name: 'collapsed' when: !expandedFilterView PropertyChanges { target: filterRow opacity: 0.0 } }, State { name: 'expanded' when: expandedFilterView PropertyChanges { target: filterRow opacity: 1.0 } + StateChangeScript { + script: filterTextInput.forceActiveFocus() + } } ] transitions: Transition { from: "expanded,collapsed" PropertyAnimation { properties: "opacity" easing.type: Easing.Linear duration: 250 } } }