diff --git a/autotests/qmltests/tst_NavigationActionBar.qml b/autotests/qmltests/tst_NavigationActionBar.qml
index 8e88f19d..fe0c24a0 100644
--- a/autotests/qmltests/tst_NavigationActionBar.qml
+++ b/autotests/qmltests/tst_NavigationActionBar.qml
@@ -1,322 +1,318 @@
/*
* Copyright 2018 Alexander Stippich .
*/
import QtQuick 2.3
import QtTest 1.0
import "../../src/qml"
FocusScope {
- property bool expandedFilterView: false
+ Item {
+ id: persistentSettings
+
+ property bool expandedFilterView: false
+ }
function i18nc(string1,string2) {
return string2
}
Item {
id: elisaTheme
property int layoutHorizontalMargin: 8
property int layoutVerticalMargin: 6
property int defaultFontPointSize: 12
property int filterClearButtonMargin: layoutVerticalMargin
property int ratingStarSize: 15
+ property int navigationBarHeight: 100
+ property int navigationBarFilterHeight: 44
}
SystemPalette {
id: myPalette
colorGroup: SystemPalette.Active
}
- Binding {
- target: navigationActionBar1
- property: "expandedFilterView"
- value: expandedFilterView
- }
-
NavigationActionBar {
id: navigationActionBar1
mainTitle: 'testTitle1'
secondaryTitle: 'secondaryTitle1'
enableGoBack: true
allowArtistNavigation: true
showRating: true
height: 100
}
NavigationActionBar {
id: navigationActionBar2
mainTitle: 'testTitle2'
secondaryTitle: 'secondaryTitle2'
enableGoBack: false
allowArtistNavigation: false
showRating: false
expandedFilterView: true
height: 100
y: 200
}
TestCase {
name: "TestNavigationActionBar"
SignalSpy {
id: enqueueSpy1
target: navigationActionBar1
signalName: "enqueue"
}
SignalSpy {
id: enqueueSpy2
target: navigationActionBar2
signalName: "enqueue"
}
SignalSpy {
id: replaceAndPlaySpy1
target: navigationActionBar1
signalName: "replaceAndPlay"
}
SignalSpy {
id: replaceAndPlaySpy2
target: navigationActionBar2
signalName: "replaceAndPlay"
}
SignalSpy {
id: goBackSpy1
target: navigationActionBar1
signalName: "goBack"
}
SignalSpy {
id: goBackSpy2
target: navigationActionBar2
signalName: "goBack"
}
SignalSpy {
id: filterViewChangedSpy1
target: navigationActionBar1
- signalName: "filterViewChanged"
+ signalName: "expandedFilterViewChanged"
}
SignalSpy {
id: filterViewChangedSpy2
target: navigationActionBar2
- signalName: "filterViewChanged"
+ signalName: "expandedFilterViewChanged"
}
SignalSpy {
id: showArtistSpy1
target: navigationActionBar1
signalName: "showArtist"
}
SignalSpy {
id: showArtistSpy2
target: navigationActionBar2
signalName: "showArtist"
}
when: windowShown
function init() {
enqueueSpy1.clear();
enqueueSpy2.clear();
replaceAndPlaySpy1.clear();
replaceAndPlaySpy2.clear();
goBackSpy1.clear();
goBackSpy2.clear();
filterViewChangedSpy1.clear();
filterViewChangedSpy2.clear();
showArtistSpy1.clear();
showArtistSpy2.clear();
- expandedFilterView = false;
+ persistentSettings.expandedFilterView = false;
}
function test_goBack() {
compare(enqueueSpy1.count, 0);
compare(enqueueSpy2.count, 0);
compare(replaceAndPlaySpy1.count, 0);
compare(replaceAndPlaySpy2.count, 0);
compare(goBackSpy1.count, 0);
compare(goBackSpy2.count, 0);
compare(filterViewChangedSpy1.count, 0);
compare(filterViewChangedSpy2.count, 0);
compare(showArtistSpy1.count, 0);
compare(showArtistSpy2.count, 0);
var goPreviousButtonItem1 = findChild(navigationActionBar1, "goPreviousButton");
verify(goPreviousButtonItem1 !== null, "valid goPreviousButton")
mouseClick(goPreviousButtonItem1);
compare(goBackSpy1.count, 1);
var goPreviousButtonItem2 = findChild(navigationActionBar2, "goPreviousButton");
verify(goPreviousButtonItem2 !== null, "valid goPreviousButton")
mouseClick(goPreviousButtonItem2);
compare(goBackSpy2.count, 0);
}
function test_enqueue() {
compare(enqueueSpy1.count, 0);
compare(enqueueSpy2.count, 0);
compare(replaceAndPlaySpy1.count, 0);
compare(replaceAndPlaySpy2.count, 0);
compare(goBackSpy1.count, 0);
compare(goBackSpy2.count, 0);
compare(filterViewChangedSpy1.count, 0);
compare(filterViewChangedSpy2.count, 0);
compare(showArtistSpy1.count, 0);
compare(showArtistSpy2.count, 0);
var enqueueButtonItem = findChild(navigationActionBar1, "enqueueButton");
verify(enqueueButtonItem !== null, "valid enqueueButton")
mouseClick(enqueueButtonItem);
compare(enqueueSpy1.count, 1);
}
function test_filterState() {
compare(enqueueSpy1.count, 0);
compare(enqueueSpy2.count, 0);
compare(replaceAndPlaySpy1.count, 0);
compare(replaceAndPlaySpy2.count, 0);
compare(goBackSpy1.count, 0);
compare(goBackSpy2.count, 0);
- compare(filterViewChangedSpy1.count, 0);
+ compare(filterViewChangedSpy1.count, 1);
compare(filterViewChangedSpy2.count, 0);
compare(showArtistSpy1.count, 0);
compare(showArtistSpy2.count, 0);
var showFilterButtonItem1 = findChild(navigationActionBar1, "showFilterButton");
verify(showFilterButtonItem1 !== null, "valid showFilterButton")
mouseClick(showFilterButtonItem1);
- compare(filterViewChangedSpy1.count, 1);
+ compare(filterViewChangedSpy1.count, 2);
var signalArgument1 = filterViewChangedSpy1.signalArguments[0];
- expandedFilterView = signalArgument1[0];
- compare(expandedFilterView,true);
+ compare(navigationActionBar1.expandedFilterView, true);
compare(navigationActionBar1.state,'expanded')
var showFilterButtonItem2 = findChild(navigationActionBar2, "showFilterButton");
verify(showFilterButtonItem2 !== null, "valid showFilterButton")
mouseClick(showFilterButtonItem2);
compare(filterViewChangedSpy2.count, 1);
var signalArgument2 = filterViewChangedSpy2.signalArguments[0];
- compare(signalArgument2[0],false)
- expandedFilterView = signalArgument2[0];
- compare(expandedFilterView,false)
- compare(navigationActionBar1.expandedFilterView, false)
- compare(navigationActionBar1.state,'collapsed')
+ compare(navigationActionBar2.expandedFilterView, false)
+ compare(navigationActionBar2.state, 'collapsed')
}
function test_replaceAndPlay() {
compare(enqueueSpy1.count, 0);
compare(enqueueSpy2.count, 0);
compare(replaceAndPlaySpy1.count, 0);
compare(replaceAndPlaySpy2.count, 0);
compare(goBackSpy1.count, 0);
compare(goBackSpy2.count, 0);
compare(filterViewChangedSpy1.count, 0);
compare(filterViewChangedSpy2.count, 0);
compare(showArtistSpy1.count, 0);
compare(showArtistSpy2.count, 0);
var replaceAndPlayButtonItem = findChild(navigationActionBar1, "replaceAndPlayButton");
verify(replaceAndPlayButtonItem !== null, "valid replaceAndPlayButton")
mouseClick(replaceAndPlayButtonItem);
compare(replaceAndPlaySpy1.count, 1);
}
function test_showArtist() {
compare(enqueueSpy1.count, 0);
compare(enqueueSpy2.count, 0);
compare(replaceAndPlaySpy1.count, 0);
compare(replaceAndPlaySpy2.count, 0);
compare(goBackSpy1.count, 0);
compare(goBackSpy2.count, 0);
compare(filterViewChangedSpy1.count, 0);
compare(filterViewChangedSpy2.count, 0);
compare(showArtistSpy1.count, 0);
compare(showArtistSpy2.count, 0);
var showArtistButtonItem1 = findChild(navigationActionBar1, "showArtistButton");
verify(showArtistButtonItem1 !== null, "valid showArtistButton")
mouseClick(showArtistButtonItem1);
compare(showArtistSpy1.count, 1);
var showArtistButtonItem2 = findChild(navigationActionBar2, "showArtistButton");
verify(showArtistButtonItem2 !== null, "valid showArtistButton")
mouseClick(showArtistButtonItem2);
compare(showArtistSpy2.count, 0);
}
function test_filterRating() {
- expandedFilterView = true;
+ persistentSettings.expandedFilterView = true;
wait(200);
var ratingFilterItem1 = findChild(navigationActionBar1, "ratingFilter");
verify(ratingFilterItem1 !== null, "valid ratingFilter")
mouseClick(ratingFilterItem1,1);
compare(navigationActionBar1.filterRating, 2);
mouseClick(ratingFilterItem1,1);
compare(navigationActionBar1.filterRating, 0);
mouseClick(ratingFilterItem1,1 + elisaTheme.ratingStarSize);
compare(navigationActionBar1.filterRating, 4);
mouseClick(ratingFilterItem1,1 + elisaTheme.ratingStarSize);
compare(navigationActionBar1.filterRating, 0);
mouseClick(ratingFilterItem1,1 + 2 * elisaTheme.ratingStarSize);
compare(navigationActionBar1.filterRating, 6);
mouseClick(ratingFilterItem1,1 + 2 * elisaTheme.ratingStarSize);
compare(navigationActionBar1.filterRating, 0);
mouseClick(ratingFilterItem1,1 + 3 * elisaTheme.ratingStarSize);
compare(navigationActionBar1.filterRating, 8);
mouseClick(ratingFilterItem1,1 + 3 * elisaTheme.ratingStarSize);
compare(navigationActionBar1.filterRating, 0);
mouseClick(ratingFilterItem1,1 + 4 * elisaTheme.ratingStarSize);
compare(navigationActionBar1.filterRating, 10);
mouseClick(ratingFilterItem1,1 + 4 * elisaTheme.ratingStarSize);
compare(navigationActionBar1.filterRating, 0);
var ratingFilterItem2 = findChild(navigationActionBar2, "ratingFilter");
verify(ratingFilterItem2 !== null, "valid ratingFilter")
mouseClick(ratingFilterItem2,1);
compare(navigationActionBar2.filterRating, 0);
mouseClick(ratingFilterItem2,1 + elisaTheme.ratingStarSize);
compare(navigationActionBar2.filterRating, 0);
mouseClick(ratingFilterItem2,1 + 2 * elisaTheme.ratingStarSize);
compare(navigationActionBar2.filterRating, 0);
mouseClick(ratingFilterItem2,1 + 3 * elisaTheme.ratingStarSize);
compare(navigationActionBar2.filterRating, 0);
mouseClick(ratingFilterItem2,1 + 4 * elisaTheme.ratingStarSize);
compare(navigationActionBar2.filterRating, 0);
}
function test_filterText() {
var textsFilterItem1 = findChild(navigationActionBar1, "filterTextInput");
verify(textsFilterItem1 !== null, "valid filterTextInput")
compare(textsFilterItem1.focus, false);
mouseClick(textsFilterItem1);
compare(textsFilterItem1.focus, true);
keyClick(Qt.Key_T);
keyClick(Qt.Key_E);
keyClick(Qt.Key_S);
keyClick(Qt.Key_T);
compare(navigationActionBar1.filterText, 'test');
mouseClick(textsFilterItem1,textsFilterItem1.width - textsFilterItem1.height);
compare(navigationActionBar1.filterText, "");
}
}
}
diff --git a/src/qml/ContentView.qml b/src/qml/ContentView.qml
index a67d800a..11876264 100644
--- a/src/qml/ContentView.qml
+++ b/src/qml/ContentView.qml
@@ -1,858 +1,792 @@
/*
* 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 alias currentViewIndex: listViews.currentIndex
signal toggleSearch()
function goBack() {
viewManager.goBack()
}
ViewManager {
id: viewManager
onSwitchAllAlbumsView: {
elisa.allAlbumsProxyModel.genreFilterText = ''
listViews.currentIndex = 1
localArtistsLoader.opacity = 0
localTracksLoader.opacity = 0
localAlbumsLoader.opacity = 1
localGenresLoader.opacity = 0
localFilesLoader.opacity = 0
}
onSwitchOneAlbumView: {
elisa.singleAlbumProxyModel.loadAlbumData(databaseId)
currentStackView.push(albumView, {
mainTitle: mainTitle,
secondaryTitle: secondaryTitle,
image: imageUrl,
stackView: currentStackView,
})
oneAlbumViewIsLoaded()
}
onSwitchAllArtistsView: {
elisa.allArtistsProxyModel.genreFilterText = ''
listViews.currentIndex = 2
localArtistsLoader.opacity = 1
localTracksLoader.opacity = 0
localAlbumsLoader.opacity = 0
localGenresLoader.opacity = 0
localFilesLoader.opacity = 0
}
onSwitchOneArtistView: {
elisa.singleArtistProxyModel.setArtistFilterText(mainTitle)
elisa.singleArtistProxyModel.genreFilterText = ''
currentStackView.push(innerAlbumView, {
mainTitle: mainTitle,
secondaryTitle: secondaryTitle,
image: imageUrl,
stackView: currentStackView,
})
oneArtistViewIsLoaded()
}
onSwitchOneArtistFromGenreView: {
elisa.singleArtistProxyModel.setArtistFilterText(mainTitle)
elisa.singleArtistProxyModel.genreFilterText = genreName
currentStackView.push(innerAlbumView, {
mainTitle: mainTitle,
secondaryTitle: secondaryTitle,
image: imageUrl,
stackView: currentStackView,
})
oneArtistViewIsLoaded()
}
onSwitchAllTracksView: {
elisa.allTracksProxyModel.genreFilterText = ''
listViews.currentIndex = 3
localArtistsLoader.opacity = 0
localTracksLoader.opacity = 1
localAlbumsLoader.opacity = 0
localGenresLoader.opacity = 0
localFilesLoader.opacity = 0
}
onSwitchAllGenresView: {
listViews.currentIndex = 4
localArtistsLoader.opacity = 0
localTracksLoader.opacity = 0
localAlbumsLoader.opacity = 0
localGenresLoader.opacity = 1
localFilesLoader.opacity = 0
}
onSwitchFilesBrowserView: {
listViews.currentIndex = 5
localArtistsLoader.opacity = 0
localTracksLoader.opacity = 0
localAlbumsLoader.opacity = 0
localGenresLoader.opacity = 0
localFilesLoader.opacity = 1
}
onSwitchAllArtistsFromGenreView: {
elisa.allArtistsProxyModel.genreFilterText = genreName
currentStackView.push(innerArtistView, {
contentModel: elisa.allArtistsProxyModel,
mainTitle: genreName,
secondaryTitle: '',
image: elisaTheme.artistIcon,
stackView: currentStackView,
})
allArtistsFromGenreViewIsLoaded()
}
onSwitchOffAllViews: {
localArtistsLoader.opacity = 0
localTracksLoader.opacity = 0
localAlbumsLoader.opacity = 0
localGenresLoader.opacity = 0
localFilesLoader.opacity = 0
}
}
ViewSelector {
id: listViews
Layout.fillHeight: true
Layout.maximumWidth: mainWindow.width * 0.11
maximumSize: mainWindow.width * 0.11
Behavior on Layout.maximumWidth {
NumberAnimation {
duration: 150
}
}
onSwitchView: if (index === 1) {
viewManager.openAllAlbums()
} else if (index === 2) {
viewManager.openAllArtists()
} else if (index === 3) {
viewManager.openAllTracks()
} else if (index === 4) {
viewManager.openAllGenres()
} else if (index === 5) {
viewManager.openFilesBrowser()
} else {
viewManager.closeAllViews()
}
}
Rectangle {
id: viewSelectorSeparatorItem
border.width: 1
border.color: myPalette.mid
color: myPalette.mid
visible: true
Layout.bottomMargin: elisaTheme.layoutVerticalMargin
Layout.topMargin: elisaTheme.layoutVerticalMargin
Layout.alignment: Qt.AlignVCenter | Qt.AlignHCenter
Layout.fillHeight: true
Layout.preferredWidth: 1
Layout.minimumWidth: 1
Layout.maximumWidth: 1
}
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
Layout.minimumWidth: 0
Layout.maximumWidth: 0
Layout.preferredWidth: 0
visible: Layout.minimumWidth != 0
Rectangle {
border {
color: (mainContentView.activeFocus ? myPalette.highlight : myPalette.base)
width: 1
}
radius: 3
color: myPalette.base
anchors.fill: parent
Loader {
anchors.fill: parent
anchors.leftMargin: parent.width / 3
anchors.rightMargin: parent.width / 3
anchors.topMargin: parent.height / 3
anchors.bottomMargin: parent.height / 3
z: 2
sourceComponent: BusyIndicator {
id: busyScanningMusic
hoverEnabled: false
anchors.fill: parent
opacity: 0.8
visible: true
running: true
z: 2
}
active: elisa.musicManager.indexerBusy
}
Loader {
id: localAlbumsLoader
active: opacity > 0
visible: opacity > 0
anchors.fill: parent
onLoaded: viewManager.allAlbumsViewIsLoaded(item.stackView)
sourceComponent: MediaBrowser {
id: localAlbums
focus: true
anchors {
fill: parent
leftMargin: elisaTheme.layoutHorizontalMargin
rightMargin: elisaTheme.layoutHorizontalMargin
}
firstPage: GridBrowserView {
id: allAlbumsView
focus: true
contentModel: elisa.allAlbumsProxyModel
image: elisaTheme.albumIcon
mainTitle: i18nc("Title of the view of all albums", "Albums")
onOpen: {
viewManager.openOneAlbum(localAlbums.stackView, innerMainTitle, innerSecondaryTitle, innerImage, databaseId)
}
onGoBack: viewManager.goBack()
-
- Binding {
- target: allAlbumsView
- property: 'expandedFilterView'
- value: persistentSettings.expandedFilterView
- }
-
- onFilterViewChanged: persistentSettings.expandedFilterView = expandedFilterView
}
}
Behavior on opacity {
NumberAnimation {
easing.type: Easing.InOutQuad
duration: 300
}
}
}
Loader {
id: localArtistsLoader
active: opacity > 0
visible: opacity > 0
opacity: 0
anchors.fill: parent
onLoaded: viewManager.allArtistsViewIsLoaded(item.stackView)
sourceComponent: MediaBrowser {
id: localArtists
focus: true
anchors {
fill: parent
leftMargin: elisaTheme.layoutHorizontalMargin
rightMargin: elisaTheme.layoutHorizontalMargin
}
firstPage: GridBrowserView {
id: allArtistsView
focus: true
showRating: false
delegateDisplaySecondaryText: false
contentModel: elisa.allArtistsProxyModel
image: elisaTheme.artistIcon
mainTitle: i18nc("Title of the view of all artists", "Artists")
onOpen: {
viewManager.openOneArtist(localArtists.stackView, innerMainTitle, innerImage, 0)
}
onGoBack: viewManager.goBack()
-
- Binding {
- target: allArtistsView
- property: 'expandedFilterView'
- value: persistentSettings.expandedFilterView
- }
-
- onFilterViewChanged: persistentSettings.expandedFilterView = expandedFilterView
}
}
Behavior on opacity {
NumberAnimation {
easing.type: Easing.InOutQuad
duration: 300
}
}
}
Loader {
id: localTracksLoader
active: opacity > 0
visible: opacity > 0
opacity: 0
anchors.fill: parent
onLoaded: viewManager.allTracksViewIsLoaded(item)
sourceComponent: MediaBrowser {
id: localTracks
focus: true
anchors {
fill: parent
leftMargin: elisaTheme.layoutHorizontalMargin
rightMargin: elisaTheme.layoutHorizontalMargin
}
firstPage: ListBrowserView {
id: allTracksView
focus: true
contentModel: elisa.allTracksProxyModel
delegate: MediaTrackDelegate {
id: entry
width: allTracksView.delegateWidth
height: elisaTheme.trackDelegateHeight
focus: true
trackData: model.containerData
isFirstTrackOfDisc: false
isSingleDiscAlbum: model.isSingleDiscAlbum
onEnqueue: elisa.mediaPlayList.enqueue(data)
onReplaceAndPlay: elisa.mediaPlayList.replaceAndPlay(data)
onClicked: contentDirectoryView.currentIndex = index
}
image: elisaTheme.tracksIcon
mainTitle: i18nc("Title of the view of all tracks", "Tracks")
-
- Binding {
- target: allTracksView
- property: 'expandedFilterView'
- value: persistentSettings.expandedFilterView
- }
-
- onFilterViewChanged: persistentSettings.expandedFilterView = expandedFilterView
}
}
Behavior on opacity {
NumberAnimation {
easing.type: Easing.InOutQuad
duration: 300
}
}
}
Loader {
id: localGenresLoader
active: opacity > 0
visible: opacity > 0
opacity: 0
anchors.fill: parent
onLoaded: viewManager.allGenresViewIsLoaded(item.stackView)
sourceComponent: MediaBrowser {
id: localGenres
focus: true
anchors {
fill: parent
leftMargin: elisaTheme.layoutHorizontalMargin
rightMargin: elisaTheme.layoutHorizontalMargin
}
firstPage: GridBrowserView {
id: allGenresView
focus: true
showRating: false
delegateDisplaySecondaryText: false
contentModel: elisa.allGenresProxyModel
image: elisaTheme.genresIcon
mainTitle: i18nc("Title of the view of all genres", "Genres")
onOpen: {
viewManager.openAllArtistsFromGenre(localGenres.stackView, innerMainTitle)
}
onGoBack: viewManager.goBack()
-
- Binding {
- target: allGenresView
- property: 'expandedFilterView'
- value: persistentSettings.expandedFilterView
- }
-
- onFilterViewChanged: persistentSettings.expandedFilterView = expandedFilterView
}
}
Behavior on opacity {
NumberAnimation {
easing.type: Easing.InOutQuad
duration: 300
}
}
}
Loader {
id: localFilesLoader
anchors.fill: parent
active: opacity > 0
visible: opacity > 0
opacity: 0
anchors {
fill: parent
leftMargin: elisaTheme.layoutHorizontalMargin
rightMargin: elisaTheme.layoutHorizontalMargin
}
onLoaded: viewManager.filesBrowserViewIsLoaded(item)
sourceComponent: FileBrowserView {
id: localFiles
focus: true
contentModel: elisa.fileBrowserProxyModel
-
- Binding {
- target: localFiles
- property: 'expandedFilterView'
- value: persistentSettings.expandedFilterView
- }
-
- onFilterViewChanged: persistentSettings.expandedFilterView = expandedFilterView
}
Behavior on opacity {
NumberAnimation {
easing.type: Easing.InOutQuad
duration: 300
}
}
}
Behavior on border.color {
ColorAnimation {
duration: 300
}
}
}
}
Rectangle {
id: firstViewSeparatorItem
border.width: 1
border.color: myPalette.mid
color: myPalette.mid
visible: true
Layout.bottomMargin: elisaTheme.layoutVerticalMargin
Layout.topMargin: elisaTheme.layoutVerticalMargin
Layout.alignment: Qt.AlignVCenter | Qt.AlignHCenter
Layout.fillHeight: true
Layout.preferredWidth: 1
Layout.minimumWidth: 1
Layout.maximumWidth: 1
}
MediaPlayListView {
id: playList
playListModel: elisa.mediaPlayList
Layout.fillHeight: true
Layout.leftMargin: elisaTheme.layoutHorizontalMargin
Layout.rightMargin: elisaTheme.layoutHorizontalMargin
Layout.minimumWidth: contentZone.width
Layout.maximumWidth: contentZone.width
Layout.preferredWidth: contentZone.width
onStartPlayback: elisa.audioControl.ensurePlay()
onPausePlayback: elisa.audioControl.playPause()
onDisplayError: messageNotification.showNotification(errorText)
}
Rectangle {
id: viewSeparatorItem
border.width: 1
border.color: myPalette.mid
color: myPalette.mid
visible: Layout.minimumWidth != 0
Layout.bottomMargin: elisaTheme.layoutVerticalMargin
Layout.topMargin: elisaTheme.layoutVerticalMargin
Layout.alignment: Qt.AlignVCenter | Qt.AlignHCenter
Layout.fillHeight: true
Layout.preferredWidth: 1
Layout.minimumWidth: 1
Layout.maximumWidth: 1
}
ContextView {
id: albumContext
Layout.fillHeight: true
Layout.minimumWidth: contentZone.width
Layout.maximumWidth: contentZone.width
Layout.preferredWidth: contentZone.width
visible: Layout.minimumWidth != 0
artistName: elisa.manageHeaderBar.artist
albumName: elisa.manageHeaderBar.album
albumArtUrl: elisa.manageHeaderBar.image
}
}
}
states: [
State {
name: 'playList'
when: listViews.currentIndex === 0
PropertyChanges {
target: mainContentView
Layout.fillWidth: false
Layout.minimumWidth: 0
Layout.maximumWidth: 0
Layout.preferredWidth: 0
}
PropertyChanges {
target: firstViewSeparatorItem
Layout.minimumWidth: 0
Layout.maximumWidth: 0
Layout.preferredWidth: 0
}
PropertyChanges {
target: playList
Layout.minimumWidth: contentZone.width / 2
Layout.maximumWidth: contentZone.width / 2
Layout.preferredWidth: contentZone.width / 2
}
PropertyChanges {
target: viewSeparatorItem
Layout.minimumWidth: 1
Layout.maximumWidth: 1
Layout.preferredWidth: 1
}
PropertyChanges {
target: albumContext
Layout.minimumWidth: contentZone.width / 2
Layout.maximumWidth: contentZone.width / 2
Layout.preferredWidth: contentZone.width / 2
}
},
State {
name: "browsingViewsNoPlaylist"
when: listViews.currentIndex !== 0 && contentViewContainer.showPlaylist !== true
extend: "browsingViews"
PropertyChanges {
target: mainContentView
Layout.fillWidth: true
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: listViews.currentIndex !== 0
PropertyChanges {
target: mainContentView
Layout.fillWidth: true
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
}
PropertyChanges {
target: playList
Layout.minimumWidth: contentZone.width * 0.33
Layout.maximumWidth: contentZone.width * 0.33
Layout.preferredWidth: contentZone.width * 0.33
}
PropertyChanges {
target: viewSeparatorItem
Layout.minimumWidth: 0
Layout.maximumWidth: 0
Layout.preferredWidth: 0
}
PropertyChanges {
target: albumContext
Layout.minimumWidth: 0
Layout.maximumWidth: 0
Layout.preferredWidth: 0
}
}
]
transitions: Transition {
NumberAnimation {
properties: "Layout.minimumWidth, Layout.maximumWidth, Layout.preferredWidth, opacity"
easing.type: Easing.InOutQuad
duration: 300
}
}
}
Component {
id: innerAlbumView
GridBrowserView {
id: innerAlbumGridView
contentModel: elisa.singleArtistProxyModel
isSubPage: true
onOpen: {
viewManager.openOneAlbum(stackView, innerMainTitle, innerSecondaryTitle, innerImage, databaseId)
}
onGoBack: viewManager.goBack()
-
- Binding {
- target: innerAlbumGridView
- property: 'expandedFilterView'
- value: persistentSettings.expandedFilterView
- }
-
- onFilterViewChanged: persistentSettings.expandedFilterView = expandedFilterView
}
}
Component {
id: innerArtistView
GridBrowserView {
id: innerAlbumGridView
delegateDisplaySecondaryText: false
isSubPage: true
onOpen: {
viewManager.openOneArtist(stackView, innerMainTitle, innerImage, 0)
}
onGoBack: viewManager.goBack()
-
- Binding {
- target: innerAlbumGridView
- property: 'expandedFilterView'
- value: persistentSettings.expandedFilterView
- }
-
- onFilterViewChanged: persistentSettings.expandedFilterView = expandedFilterView
}
}
Component {
id: albumView
ListBrowserView {
id: albumGridView
contentModel: elisa.singleAlbumProxyModel
isSubPage: true
enableSorting: false
delegate: MediaAlbumTrackDelegate {
id: entry
width: albumGridView.delegateWidth
height: ((model.isFirstTrackOfDisc && !isSingleDiscAlbum) ? elisaTheme.delegateHeight*2 : elisaTheme.delegateHeight)
focus: true
mediaTrack.trackData: model.containerData
mediaTrack.isFirstTrackOfDisc: model.isFirstTrackOfDisc
mediaTrack.isSingleDiscAlbum: model.isSingleDiscAlbum
mediaTrack.onEnqueue: elisa.mediaPlayList.enqueue(data)
mediaTrack.onReplaceAndPlay: elisa.mediaPlayList.replaceAndPlay(data)
mediaTrack.isAlternateColor: (index % 2) === 1
mediaTrack.onClicked: albumGridView.currentIndex = index
}
allowArtistNavigation: true
onShowArtist: {
viewManager.openOneArtist(stackView, name, elisaTheme.artistIcon, 0)
}
onGoBack: viewManager.goBack()
-
- expandedFilterView: true
-
- Binding {
- target: albumGridView
- property: 'expandedFilterView'
- value: persistentSettings.expandedFilterView
- }
-
- onFilterViewChanged: persistentSettings.expandedFilterView = expandedFilterView
}
}
}
diff --git a/src/qml/ElisaMainWindow.qml b/src/qml/ElisaMainWindow.qml
index 453aac1c..4cb25f8d 100644
--- a/src/qml/ElisaMainWindow.qml
+++ b/src/qml/ElisaMainWindow.qml
@@ -1,322 +1,309 @@
/*
* 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.Controls 1.4 as Controls1
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")
property var goBackAction: elisa.action("go_back")
- property var findAction: elisa.action("edit_find")
-
- Controls1.Action {
- shortcut: findAction.shortcut
- onTriggered: {
- if ( persistentSettings.expandedFilterView == true)
- {
- persistentSettings.expandedFilterView = false
- } else {
- persistentSettings.expandedFilterView = true
- }
- }
- }
Controls1.Action {
shortcut: goBackAction.shortcut
onTriggered: contentView.goBack()
}
Controls1.Action {
id: applicationMenuAction
text: i18nc("open application menu", "Application Menu")
iconName: "application-menu"
onTriggered: applicationMenu.popup()
}
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 playControlItemRepeat : false
property bool playControlItemShuffle : false
property bool expandedFilterView: false
property bool showPlaylist: true
property bool headerBarIsMaximized: false
}
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.playControlItemRepeat = headerBar.playerControl.repeat
persistentSettings.playControlItemShuffle = headerBar.playerControl.shuffle
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
}
Connections {
target: elisa.mediaPlayList
onPlayListLoadFailed: {
messageNotification.showNotification(i18nc("message of passive notification when playlist load failed", "Load of playlist failed"), 3000)
}
}
PassiveNotification {
id: messageNotification
}
Rectangle {
color: myPalette.base
anchors.fill: parent
ColumnLayout {
anchors.fill: parent
spacing: 0
Item {
id: headerBarParent
Layout.minimumHeight: mainWindow.height * 0.2 + elisaTheme.mediaPlayerControlHeight
Layout.maximumHeight: mainWindow.height * 0.2 + elisaTheme.mediaPlayerControlHeight
Layout.fillWidth: true
HeaderBar {
id: headerBar
focus: true
anchors.fill: parent
tracksCount: elisa.manageHeaderBar.remainingTracks
album: elisa.manageHeaderBar.album
title: elisa.manageHeaderBar.title
artist: elisa.manageHeaderBar.artist
image: elisa.manageHeaderBar.image
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: persistentSettings.playControlItemRepeat
playerControl.shuffle: persistentSettings.playControlItemShuffle
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
TrackImportNotification {
id: importedTracksCountNotification
anchors
{
right: headerBar.right
top: headerBar.top
rightMargin: elisaTheme.layoutHorizontalMargin * 1.75
topMargin: elisaTheme.layoutHorizontalMargin * 3
}
}
Binding {
target: importedTracksCountNotification
property: 'musicManager'
value: elisa.musicManager
when: elisa.musicManager !== undefined
}
Loader {
sourceComponent: Binding {
target: importedTracksCountNotification
property: 'indexingRunning'
value: elisa.musicManager.indexingRunning
}
active: elisa.musicManager !== undefined
}
Loader {
sourceComponent: Binding {
target: importedTracksCountNotification
property: 'importedTracksCount'
value: elisa.musicManager.importedTracksCount
}
active: elisa.musicManager !== undefined
}
}
}
ContentView {
id: contentView
Layout.fillHeight: true
Layout.fillWidth: true
showPlaylist: persistentSettings.showPlaylist
}
}
}
StateGroup {
id: mainWindowState
states: [
State {
name: "headerBarIsMaximized"
when: headerBar.isMaximized
changes: [
PropertyChanges {
target: mainWindow
minimumHeight: 120 + elisaTheme.mediaPlayerControlHeight
explicit: true
},
PropertyChanges {
target: headerBarParent
Layout.minimumHeight: mainWindow.height
Layout.maximumHeight: mainWindow.height
},
PropertyChanges {
target: contentView
height: 0
visible: false
}
]
}
]
}
Component.onCompleted:
{
elisa.initialize()
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})
if (persistentSettings.playListState) {
elisa.mediaPlayList.persistentState = persistentSettings.playListState
}
if (persistentSettings.audioPlayerState) {
elisa.audioControl.persistentState = persistentSettings.audioPlayerState
}
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/FileBrowserView.qml b/src/qml/FileBrowserView.qml
index a632e963..2eee6623 100644
--- a/src/qml/FileBrowserView.qml
+++ b/src/qml/FileBrowserView.qml
@@ -1,155 +1,152 @@
/*
* Copyright 2016-2018 Matthieu Gallien
* Copyright 2018 Alexander Stippich
*
* 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 QtQml.Models 2.2
import QtQuick.Layouts 1.2
import org.kde.elisa 1.0
FocusScope {
id: fileView
property bool isSubPage: false
property alias contentModel: contentDirectoryView.model
property alias expandedFilterView: navigationBar.expandedFilterView
- signal filterViewChanged(bool expandedFilterView)
-
function goBack() {
contentModel.openParentFolder()
}
function loadFolderAndClear(data) {
contentModel.openFolder(data)
navigationBar.filterText = ""
}
SystemPalette {
id: myPalette
colorGroup: SystemPalette.Active
}
Theme {
id: elisaTheme
}
MouseArea {
anchors.fill: parent
hoverEnabled: false
acceptedButtons: Qt.BackButton
onClicked: contentModel.openParentFolder()
}
ColumnLayout {
anchors.fill: parent
spacing: 0
NavigationActionBar {
id: navigationBar
mainTitle: i18nc("Title of the file browser view", "Files")
image: elisaTheme.folderIcon
secondaryTitle: contentModel.url
enableGoBack: contentModel.canGoBack
sortOrder: contentModel.sortedAscending
showRating: false
height: elisaTheme.navigationBarHeight
Layout.preferredHeight: height
Layout.minimumHeight: height
Layout.maximumHeight: height
Layout.fillWidth: true
Binding {
target: contentModel
property: 'filterText'
value: navigationBar.filterText
}
onEnqueue: contentModel.enqueueToPlayList()
onReplaceAndPlay: contentModel.replaceAndPlayOfPlayList()
onGoBack: contentModel.openParentFolder()
- onFilterViewChanged: fileView.filterViewChanged(expandedFilterView)
onSort: contentModel.sortModel(order)
}
Rectangle {
color: myPalette.base
Layout.fillHeight: true
Layout.fillWidth: true
clip: true
GridView {
id: contentDirectoryView
anchors.topMargin: 20
anchors.fill: parent
focus: true
ScrollBar.vertical: ScrollBar {
id: scrollBar
}
boundsBehavior: Flickable.StopAtBounds
add: Transition {
PropertyAnimation {
property: "opacity"
from: 0
to: 1
duration: 100
}
}
remove: Transition {
PropertyAnimation {
property: "opacity"
from: 0
to: 1
duration: 100
}
}
cellWidth: elisaTheme.gridDelegateWidth
cellHeight:elisaTheme.gridDelegateHeight
delegate: FileBrowserDelegate {
width: contentDirectoryView.cellWidth
height: contentDirectoryView.cellHeight
focus: true
isDirectory: model.directory
fileName: model.name
fileUrl: model.containerData
imageUrl: model.imageUrl
contentModel: fileView.contentModel
onEnqueue: elisa.mediaPlayList.enqueue(data)
onReplaceAndPlay: elisa.mediaPlayList.replaceAndPlay(data)
onSelected: {
forceActiveFocus()
contentDirectoryView.currentIndex = model.index
}
onOpen: loadFolderAndClear(data)
}
}
}
}
}
diff --git a/src/qml/GridBrowserView.qml b/src/qml/GridBrowserView.qml
index 01260e0b..395a6be8 100644
--- a/src/qml/GridBrowserView.qml
+++ b/src/qml/GridBrowserView.qml
@@ -1,157 +1,154 @@
/*
* Copyright 2016-2017 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.Window 2.2
import QtQml.Models 2.1
import QtQuick.Layouts 1.2
import QtGraphicalEffects 1.0
import org.kde.elisa 1.0
FocusScope {
id: gridView
property bool isSubPage: false
property string mainTitle
property string secondaryTitle
property url image
property alias contentModel: contentDirectoryView.model
property alias showRating: navigationBar.showRating
property bool delegateDisplaySecondaryText: true
property alias expandedFilterView: navigationBar.expandedFilterView
property var stackView
signal open(var innerMainTitle, var innerSecondaryTitle, var innerImage, var databaseId)
signal goBack()
- signal filterViewChanged(bool expandedFilterView)
SystemPalette {
id: myPalette
colorGroup: SystemPalette.Active
}
Theme {
id: elisaTheme
}
ColumnLayout {
anchors.fill: parent
spacing: 0
NavigationActionBar {
id: navigationBar
mainTitle: gridView.mainTitle
secondaryTitle: gridView.secondaryTitle
image: gridView.image
enableGoBack: isSubPage
sortOrder: if (contentModel) {contentModel.sortedAscending} else true
height: elisaTheme.navigationBarHeight
Layout.preferredHeight: height
Layout.minimumHeight: height
Layout.maximumHeight: height
Layout.fillWidth: true
Loader {
active: contentModel !== undefined
sourceComponent: Binding {
target: contentModel
property: 'filterText'
value: navigationBar.filterText
}
}
Loader {
active: contentModel
sourceComponent: Binding {
target: contentModel
property: 'filterRating'
value: navigationBar.filterRating
}
}
onEnqueue: contentModel.enqueueToPlayList()
onReplaceAndPlay:contentModel.replaceAndPlayOfPlayList()
onGoBack: gridView.goBack()
- onFilterViewChanged: gridView.filterViewChanged(expandedFilterView)
-
onSort: contentModel.sortModel(order)
}
Rectangle {
color: myPalette.base
Layout.fillHeight: true
Layout.fillWidth: true
clip: true
GridView {
id: contentDirectoryView
anchors.topMargin: 20
focus: true
anchors.fill: parent
ScrollBar.vertical: ScrollBar {
id: scrollBar
}
boundsBehavior: Flickable.StopAtBounds
TextMetrics {
id: secondaryLabelSize
text: 'example'
}
cellWidth: elisaTheme.gridDelegateWidth
cellHeight: (delegateDisplaySecondaryText ? elisaTheme.gridDelegateHeight : elisaTheme.gridDelegateHeight - secondaryLabelSize.height)
delegate: GridBrowserDelegate {
width: contentDirectoryView.cellWidth
height: contentDirectoryView.cellHeight
focus: true
isPartial: false
mainText: model.display
secondaryText: if (gridView.delegateDisplaySecondaryText) {model.secondaryText} else {""}
imageUrl: model.imageUrl
shadowForImage: if (model.shadowForImage) {model.shadowForImage} else {false}
containerData: model.containerData
delegateDisplaySecondaryText: gridView.delegateDisplaySecondaryText
onEnqueue: elisa.mediaPlayList.enqueue(data)
onReplaceAndPlay: elisa.mediaPlayList.replaceAndPlay(data)
onOpen: gridView.open(model.display, model.secondaryText, model.imageUrl, model.databaseId)
onSelected: {
forceActiveFocus()
contentDirectoryView.currentIndex = model.index
}
}
}
}
}
}
diff --git a/src/qml/ListBrowserView.qml b/src/qml/ListBrowserView.qml
index 6055642f..a9682ec4 100644
--- a/src/qml/ListBrowserView.qml
+++ b/src/qml/ListBrowserView.qml
@@ -1,120 +1,117 @@
/*
* Copyright 2016-2017 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.Window 2.2
import QtQml.Models 2.2
import QtQuick.Layouts 1.2
import QtGraphicalEffects 1.0
import org.kde.elisa 1.0
FocusScope {
id: listView
property bool isSubPage: false
property alias mainTitle: navigationBar.mainTitle
property alias secondaryTitle: navigationBar.secondaryTitle
property alias image: navigationBar.image
property alias delegate: contentDirectoryView.delegate
property alias contentModel: contentDirectoryView.model
property alias expandedFilterView: navigationBar.expandedFilterView
property alias showRating: navigationBar.showRating
property alias allowArtistNavigation: navigationBar.allowArtistNavigation
property var delegateWidth: scrollBar.visible ? contentDirectoryView.width - scrollBar.width : contentDirectoryView.width
property alias currentIndex: contentDirectoryView.currentIndex
property alias enableSorting: navigationBar.enableSorting
property var stackView
signal goBack()
signal showArtist(var name)
- signal filterViewChanged(bool expandedFilterView)
SystemPalette {
id: myPalette
colorGroup: SystemPalette.Active
}
Theme {
id: elisaTheme
}
ColumnLayout {
anchors.fill: parent
spacing: 0
NavigationActionBar {
id: navigationBar
enableGoBack: listView.isSubPage
sortOrder: contentModel.sortedAscending
height: elisaTheme.navigationBarHeight
Layout.preferredHeight: height
Layout.minimumHeight: height
Layout.maximumHeight: height
Layout.fillWidth: true
Binding {
target: contentModel
property: 'filterText'
value: navigationBar.filterText
}
Binding {
target: contentModel
property: 'filterRating'
value: navigationBar.filterRating
}
onEnqueue: contentModel.enqueueToPlayList()
- onFilterViewChanged: listView.filterViewChanged(expandedFilterView)
-
onReplaceAndPlay: contentModel.replaceAndPlayOfPlayList()
onGoBack: listView.goBack()
onShowArtist: listView.showArtist(listView.contentModel.sourceModel.author)
onSort: contentModel.sortModel(order)
}
Rectangle {
color: myPalette.base
Layout.fillHeight: true
Layout.fillWidth: true
ListView {
id: contentDirectoryView
anchors.topMargin: 20
anchors.fill: parent
focus: true
ScrollBar.vertical: ScrollBar {
id: scrollBar
}
boundsBehavior: Flickable.StopAtBounds
clip: true
}
}
}
}
diff --git a/src/qml/NavigationActionBar.qml b/src/qml/NavigationActionBar.qml
index 233b453e..7ec7635b 100644
--- a/src/qml/NavigationActionBar.qml
+++ b/src/qml/NavigationActionBar.qml
@@ -1,399 +1,407 @@
/*
* 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.2
import QtQuick.Controls 1.4 as Controls1
FocusScope {
id: navigationBar
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: false
+ property bool expandedFilterView: persistentSettings.expandedFilterView
property bool enableSorting: true
property bool sortOrder
signal enqueue();
signal replaceAndPlay();
signal goBack();
signal showArtist();
- signal filterViewChanged(bool expandedFilterView);
signal sort(var order);
Controls1.Action {
id: goPreviousAction
text: i18nc("navigate back in the views stack", "Back")
iconName: (Qt.application.layoutDirection == Qt.RightToLeft) ? "go-next" : "go-previous"
onTriggered: goBack()
}
+ property var findAction: elisa.action("edit_find")
+
Controls1.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")
iconName: !navigationBar.expandedFilterView ? "go-down-search" : "go-up-search"
- onTriggered: filterViewChanged(!navigationBar.expandedFilterView)
+ onTriggered: {
+ persistentSettings.expandedFilterView = !persistentSettings.expandedFilterView
+ expandedFilterView = persistentSettings.expandedFilterView
+ if (expandedFilterView) {
+ filterTextInput.forceActiveFocus()
+ }
+ }
}
Controls1.Action {
id: sortAction
text: i18nc("Toggle between ascending and descending order", "Toggle sort order")
iconName: sortOrder ? "view-sort-ascending" : "view-sort-descending"
onTriggered: sortOrder ? sort(Qt.DescendingOrder) : sort(Qt.AscendingOrder)
}
ColumnLayout {
anchors.fill: parent
spacing: 0
anchors.topMargin: elisaTheme.layoutVerticalMargin
anchors.bottomMargin: elisaTheme.layoutVerticalMargin
RowLayout {
spacing: 0
Layout.alignment: Qt.AlignTop
Layout.preferredHeight: elisaTheme.navigationBarHeight
Layout.minimumHeight: elisaTheme.navigationBarHeight
Layout.maximumHeight: elisaTheme.navigationBarHeight
Controls1.ToolButton {
action: goPreviousAction
objectName: 'goPreviousButton'
Layout.leftMargin: !LayoutMirroring.enabled ? elisaTheme.layoutHorizontalMargin : 0
Layout.rightMargin: LayoutMirroring.enabled ? elisaTheme.layoutHorizontalMargin : 0
visible: enableGoBack
}
Image {
id: mainIcon
source: image
asynchronous: true
sourceSize.height: elisaTheme.coverImageSize / 2
sourceSize.width: elisaTheme.coverImageSize / 2
fillMode: Image.PreserveAspectFit
Layout.alignment: Qt.AlignVCenter | Qt.AlignLeft
Layout.preferredHeight: elisaTheme.coverImageSize / 2
Layout.minimumHeight: elisaTheme.coverImageSize / 2
Layout.maximumHeight: elisaTheme.coverImageSize / 2
Layout.preferredWidth: elisaTheme.coverImageSize / 2
Layout.minimumWidth: elisaTheme.coverImageSize / 2
Layout.maximumWidth: elisaTheme.coverImageSize / 2
Layout.leftMargin: !LayoutMirroring.enabled ? elisaTheme.layoutHorizontalMargin : 0
Layout.rightMargin: LayoutMirroring.enabled ? elisaTheme.layoutHorizontalMargin : 0
}
ColumnLayout {
Layout.preferredHeight: elisaTheme.coverImageSize / 1.9
Layout.minimumHeight: elisaTheme.coverImageSize / 1.9
Layout.maximumHeight: elisaTheme.coverImageSize / 1.9
spacing: 0
Layout.fillWidth: true
Layout.leftMargin: !LayoutMirroring.enabled ? elisaTheme.layoutHorizontalMargin : 0
Layout.rightMargin: LayoutMirroring.enabled ? elisaTheme.layoutHorizontalMargin : 0
TextMetrics {
id: albumTextSize
text: albumLabel.text
font.pointSize: albumLabel.font.pointSize
font.bold: albumLabel.font.bold
}
LabelWithToolTip {
id: albumLabel
text: mainTitle
Layout.fillWidth: true
Layout.alignment: Qt.AlignTop | Qt.AlignLeft
Layout.topMargin: secondaryTitle !== "" ? 0 : 9
elide: Text.ElideRight
fontSizeMode: Text.Fit
Layout.preferredHeight: elisaTheme.coverImageSize / 5
Layout.minimumHeight: elisaTheme.coverImageSize / 5
Layout.maximumHeight: elisaTheme.coverImageSize / 5
color: myPalette.text
font {
pointSize: elisaTheme.defaultFontPointSize * 2
}
}
TextMetrics {
id: authorTextSize
text: authorLabel.text
font.pointSize: authorLabel.font.pointSize
font.bold: authorLabel.font.bold
}
LabelWithToolTip {
id: authorLabel
text: secondaryTitle
color: myPalette.text
Layout.fillWidth: true
Layout.alignment: Qt.AlignLeft | Qt.AlignVCenter
font {
pointSize: elisaTheme.defaultFontPointSize
}
elide: Text.ElideRight
visible: secondaryTitle !== ""
}
RowLayout {
Layout.fillWidth: true
spacing: 0
Layout.bottomMargin: secondaryTitle !== "" ? 0 : 14
Controls1.Button {
objectName: 'enqueueButton'
text: i18nc("Add current list to playlist", "Enqueue")
iconName: "media-track-add-amarok"
onClicked: enqueue()
Layout.leftMargin: 0
Layout.rightMargin: 0
}
Controls1.Button {
objectName: 'replaceAndPlayButton'
text: i18nc("Clear playlist and play", "Replace and Play")
tooltip: i18nc("Clear playlist and add current list to it", "Replace PlayList and Play Now")
iconName: "media-playback-start"
onClicked: replaceAndPlay()
Layout.leftMargin: !LayoutMirroring.enabled ? elisaTheme.layoutHorizontalMargin : 0
Layout.rightMargin: LayoutMirroring.enabled ? elisaTheme.layoutHorizontalMargin : 0
}
Controls1.Button {
objectName: 'showArtistButton'
id: showArtistButton
visible: allowArtistNavigation
text: i18nc("Button to navigate to the artist of the album", "Display Artist")
iconName: "view-media-artist"
onClicked: showArtist()
Layout.leftMargin: !LayoutMirroring.enabled ? elisaTheme.layoutHorizontalMargin : 0
Layout.rightMargin: LayoutMirroring.enabled ? elisaTheme.layoutHorizontalMargin : 0
}
Item {
Layout.fillWidth: true
}
Controls1.ToolButton {
action: showFilterAction
objectName: 'showFilterButton'
Layout.alignment: Qt.AlignRight
Layout.leftMargin: !LayoutMirroring.enabled ? elisaTheme.layoutHorizontalMargin : 0
Layout.rightMargin: LayoutMirroring.enabled ? elisaTheme.layoutHorizontalMargin : 0
}
}
}
}
RowLayout {
id: filterRow
spacing: 0
visible: opacity > 0.0
opacity: 0
Layout.preferredHeight: elisaTheme.navigationBarFilterHeight
Layout.minimumHeight: elisaTheme.navigationBarFilterHeight
Layout.maximumHeight: elisaTheme.navigationBarFilterHeight
Layout.fillWidth: true
Layout.topMargin: elisaTheme.layoutVerticalMargin * 2
Layout.leftMargin: !LayoutMirroring.enabled ? elisaTheme.layoutHorizontalMargin : 0
Layout.rightMargin: LayoutMirroring.enabled ? elisaTheme.layoutHorizontalMargin : 0
Layout.alignment: Qt.AlignTop
LabelWithToolTip {
text: i18nc("before the TextField input of the filter", "Search: ")
font.bold: true
Layout.bottomMargin: 0
color: myPalette.text
}
TextField {
id: filterTextInput
objectName: 'filterTextInput'
horizontalAlignment: TextInput.AlignLeft
placeholderText: i18nc("Placeholder text in the filter text box", "Album name, artist, etc.")
Layout.bottomMargin: 0
Layout.fillWidth: true
Layout.minimumWidth: placeHolderTextWidth.width * 1.2
implicitWidth: placeHolderTextWidth.width * 1.2
TextMetrics {
id: placeHolderTextWidth
text: filterTextInput.placeholderText
}
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()
}
}
}
}
LabelWithToolTip {
text: i18nc("before the Rating widget input of the filter", "Rating: ")
visible: showRating
font.bold: true
color: myPalette.text
Layout.bottomMargin: 0
Layout.leftMargin: !LayoutMirroring.enabled ? (elisaTheme.layoutHorizontalMargin * 2) : 0
Layout.rightMargin: LayoutMirroring.enabled ? (elisaTheme.layoutHorizontalMargin * 2) : 0
}
RatingStar {
id: ratingFilter
objectName: 'ratingFilter'
visible: showRating
hoverWidgetOpacity: 1
readOnly: false
starSize: elisaTheme.ratingStarSize
Layout.bottomMargin: 0
}
Item {
Layout.fillWidth: true
implicitWidth: elisaTheme.layoutHorizontalMargin * 4
}
Controls1.ToolButton {
action: sortAction
objectName: 'sortAscendingButton'
Layout.alignment: Qt.AlignRight
Layout.leftMargin: !LayoutMirroring.enabled ? elisaTheme.layoutHorizontalMargin : 0
Layout.rightMargin: LayoutMirroring.enabled ? elisaTheme.layoutHorizontalMargin : 0
visible: enableSorting
}
}
}
states: [
State {
name: 'collapsed'
when: !expandedFilterView
PropertyChanges {
target: navigationBar
height: elisaTheme.navigationBarHeight + elisaTheme.layoutVerticalMargin * 2
}
PropertyChanges {
target: filterRow
opacity: 0.0
}
},
State {
name: 'expanded'
when: expandedFilterView
PropertyChanges {
target: navigationBar
height: elisaTheme.navigationBarHeight + elisaTheme.navigationBarFilterHeight + elisaTheme.layoutVerticalMargin * 4
}
PropertyChanges {
target: filterRow
opacity: 1.0
}
}
]
transitions: Transition {
from: "expanded,collapsed"
PropertyAnimation {
properties: "height"
easing.type: Easing.Linear
duration: 250
}
PropertyAnimation {
properties: "opacity"
easing.type: Easing.Linear
duration: 250
}
}
}