diff --git a/data_models/db_model.qml b/data_models/db_model.qml index 551a02e..e6a5ff9 100644 --- a/data_models/db_model.qml +++ b/data_models/db_model.qml @@ -1,7 +1,7 @@ -import QtQuick 2.9 -import QtQuick.Controls 2.2 +import QtQuick 2.10 +import QtQuick.Controls 2.10 import QtQuick.Layouts 1.3 Item { } diff --git a/main.qml b/main.qml index eecb440..74bf30c 100644 --- a/main.qml +++ b/main.qml @@ -1,985 +1,963 @@ -import QtQuick 2.9 -import QtQuick.Controls 2.3 +import QtQuick 2.10 +import QtQuick.Controls 2.10 import QtQuick.Layouts 1.3 import QtGraphicalEffects 1.0 import QtQuick.Controls.Material 2.1 import "utils" import "widgets" import "widgets/PlaylistsView" import "widgets/MainPlaylist" import "widgets/SettingsView" import "widgets/SearchView" import "widgets/CloudView" import "view_models" import "view_models/BabeTable" import "services/local" import "services/web" //import "services/web/Spotify" import "view_models/BabeGrid" import "widgets/InfoView" import "db/Queries.js" as Q import "utils/Help.js" as H import "utils/Player.js" as Player import org.kde.kirigami 2.7 as Kirigami import org.kde.mauikit 1.0 as Maui import Player 1.0 import AlbumsList 1.0 import TracksList 1.0 import TracksList 1.0 Maui.ApplicationWindow { id: root title: qsTr("vvave") /***************************************************/ /******************** ALIASES ********************/ /*************************************************/ property alias mainPlaylist: mainPlaylist property alias selectionBar: _selectionBar property alias progressBar: progressBar property alias dialog : _dialogLoader.item Maui.App.iconName: "qrc:/assets/vvave.svg" Maui.App.description: qsTr("VVAVE will handle your whole music collection by retreaving semantic information from the web. Just relax, enjoy and discover your new music ") /***************************************************/ /******************** PLAYBACK ********************/ /*************************************************/ property bool isShuffle: Maui.FM.loadSettings("SHUFFLE","PLAYBACK", false) property var currentTrack: ({ fav: "0", stars: "0" }) property int currentTrackIndex: -1 property int prevTrackIndex: 0 property string currentArtwork: !mainlistEmpty ? mainPlaylist.list.get(0).artwork : "" property bool currentBabe: currentTrack.fav == "0" ? false : true property alias durationTimeLabel: player.duration property string progressTimeLabel: player.transformTime((player.duration/1000) *(player.pos/ 1000)) property alias isPlaying: player.playing property int onQueue: 0 property bool mainlistEmpty: !mainPlaylist.table.count > 0 /***************************************************/ /******************** HANDLERS ********************/ /*************************************************/ readonly property var viewsIndex: ({ tracks: 0, cloud : 1, albums: 2, artists: 3, playlists: 4, folders: 5, youtube: 6, search: 7}) property string syncPlaylist: "" property bool sync: false property string infoMsg: "" property bool infoLabels: Maui.FM.loadSettings("LABELS", "PLAYBACK", false) == "true" ? true : false property bool focusView : false property bool selectionMode : false /***************************************************/ /******************** UI COLORS *******************/ /*************************************************/ readonly property color babeColor: "#f84172" /*SIGNALS*/ signal missingAlert(var track) /*HANDLE EVENTS*/ onClosing: Player.savePlaylist() onMissingAlert: { var message = qsTr("Missing file...") var messageBody = track.title + " by " + track.artist + " is missing.\nDo you want to remove it from your collection?" notify("dialog-question", message, messageBody, function () { mainPlaylist.list.remove(mainPlaylist.table.currentIndex) }) } /*COMPONENTS*/ Player { id: player volume: 100 onFinishedChanged: if (!mainlistEmpty) { if (currentTrack.url) mainPlaylist.list.countUp(currentTrackIndex) Player.nextTrack() } } FloatingDisk { id: _floatingDisk opacity: 1 - _drawer.position } headBar.middleContent : Maui.ActionGroup { id: _actionGroup Layout.fillWidth: true Layout.fillHeight: true Layout.minimumWidth: implicitWidth currentIndex : swipeView.currentIndex + onCurrentIndexChanged: swipeView.currentIndex = currentIndex hiddenActions: [ Action { text: qsTr("Folders") icon.name: "folder" }, Action { text: qsTr("YouTube") icon.name: "internet-services" } ] Action { icon.name: "view-media-track" text: qsTr("Tracks") } Action { text: qsTr("Cloud") icon.name: "folder-cloud" } Action { text: qsTr("Albums") icon.name: /*"album"*/ "view-media-album-cover" } Action { text: qsTr("Artists") icon.name: "view-media-artist" } Action { text: qsTr("Playlists") icon.name: "view-media-playlist" } } onSearchButtonClicked: { _actionGroup.currentIndex = viewsIndex.search - searchView.searchInput.forceActiveFocus() + // searchView.searchInput.forceActiveFocus() } Loader { id: _dialogLoader } InfoView { id: infoView maxWidth: parent.width * 0.8 maxHeight: parent.height * 0.9 } Loader { id: _focusViewLoader focus: true source: focusView ? "widgets/FocusView.qml" : "" } Component { id: _shareDialogComponent Maui.ShareDialog {} } Component { id: _fmDialogComponent Maui.FileDialog { } } SourcesDialog { id: sourcesDialog } mainMenu: [ // Maui.MenuItem // { // text: "Vvave Stream" // icon.name: "headphones" // onTriggered: // { // pageStack.currentIndex = 1 // currentView = viewsIndex.vvave // } // }, // Maui.MenuItem // { // text: qsTr("Linking") // icon.name: "view-links" // onTriggered: // { // pageStack.currentIndex = 1 // currentView = viewsIndex.linking // if(!isLinked) linkingView.linkingConf.open() // } // }, // Maui.MenuItem // { // text: qsTr("Cloud") // icon.name: "folder-cloud" // onTriggered: // { // pageStack.currentIndex = 1 // currentView = viewsIndex.cloud // } // }, // Maui.MenuItem // { // text: qsTr("Spotify") // icon.name: "internet-services" // onTriggered: // { // pageStack.currentIndex = 1 // currentView = viewsIndex.spotify // } // }, MenuSeparator{}, MenuItem { text: qsTr("Sources") icon.name: "folder-add" onTriggered: sourcesDialog.open() }, MenuItem { text: qsTr("Open") icon.name: "folder-add" onTriggered: { _dialogLoader.sourceComponent = _fmDialogComponent root.dialog.settings.onlyDirs = false + root.dialog.currentPath = "file:///home/camilo/Music" root.dialog.settings.filterType = Maui.FMList.AUDIO console.log("SETTIGN FILTER TYPE FISR", root.dialog.settings.filterType, Maui.FMList.AUDIO) root.dialog.show(function(paths) { vvave.openUrls(paths) root.dialog.close() }) } }/*, Menu { title: qsTr("Collection") // icon.name: "settings-configure" MenuItem { text: qsTr("Re-Scan") onTriggered: bae.refreshCollection(); } MenuItem { text: qsTr("Refresh...") onTriggered: H.refreshCollection(); } MenuItem { text: qsTr("Clean") onTriggered: bae.removeMissingTracks(); } }*/ // Maui.Menu // { // title: qsTr("Settings...") // // Kirigami.Action // // { // // text: "Brainz" // // Kirigami.Action // // { // // id: brainzToggle // // text: checked ? "Turn OFF" : "Turn ON" // // checked: bae.brainzState() // // checkable: true // // onToggled: // // { // // checked = !checked // // bae.saveSetting("AUTO", checked, "BRAINZ") // //// bae.brainz(checked) // // } // // } // // } // Maui.MenuItem // { // text: "Info label" + checked ? "ON" : "OFF" // checked: infoLabels // checkable: true // onToggled: // { // infoLabels = checked // bae.saveSetting("LABELS", infoLabels ? true : false, "PLAYBACK") // } // } // Maui.MenuItem // { // text: "Autoplay" // checked: autoplay // checkable: true // onToggled: // { // autoplay = checked // bae.saveSetting("AUTOPLAY", autoplay ? true : false, "BABE") // } // } // } ] - Item - { - id: message - visible: infoMsg.length && sync - anchors.bottom: parent.bottom - width: parent.width - height: Maui.Style.rowHeight - z: 999 - - Rectangle - { - id: infoBg - - anchors.fill: parent - z: -999 - color: "#333" - opacity: 0.8 - - SequentialAnimation - { - id: animBg - PropertyAnimation - { - target: infoBg - property: "color" - easing.type: Easing.InOutQuad - to: babeColor - duration: 250 - } - - PropertyAnimation - { - target: infoBg - property: "color" - easing.type: Easing.InOutQuad - to: "#333" - duration: 500 - } - } - } - - Label - { - id: infoTxt - anchors.centerIn: parent - anchors.fill: parent - height: parent.height - width: parent.width - font.pointSize: Maui.Style.fontSizes.medium - text: infoMsg - horizontalAlignment: Qt.AlignHCenter - verticalAlignment: Qt.AlignVCenter - color: Kirigami.Theme.textColor - - SequentialAnimation - { - id: animTxt - PropertyAnimation - { - target: infoTxt - property: "color" - easing.type: Easing.InOutQuad - to: "white" - duration: 250 - } - - PropertyAnimation - { - target: infoTxt - property: "color" - easing.type: Easing.InOutQuad - to: Kirigami.Theme.textColor - duration: 500 - } - } - } - } - PlaylistDialog { id: playlistDialog } sideBar: Maui.AbstractSideBar { id: _drawer width: visible ? Math.min(Kirigami.Units.gridUnit * 18, root.width) : 0 modal: !isWide height: _drawer.modal ? implicitHeight - _mainPage.footer.height : implicitHeight MainPlaylist { id: mainPlaylist anchors.fill: parent Connections { target: mainPlaylist onCoverPressed: Player.appendAll(tracks) onCoverDoubleClicked: Player.playAll(tracks) } } } Maui.Page { id: _mainPage anchors.fill: parent footer: ColumnLayout { id: _footerLayout visible: !mainlistEmpty height: visible ? Maui.Style.toolBarHeight * 1.2 : 0 width: parent.width spacing: 0 Kirigami.Separator { Layout.fillWidth: true } Slider { id: progressBar Layout.preferredHeight: Maui.Style.unit * (Kirigami.Settings.isMobile ? 6 : 8) Layout.fillWidth: true padding: 0 from: 0 to: 1000 value: player.pos spacing: 0 focus: true onMoved: { player.pos = value } background: Rectangle { implicitWidth: progressBar.width implicitHeight: progressBar.height width: progressBar.availableWidth height: implicitHeight color: "transparent" Rectangle { width: progressBar.visualPosition * parent.width height: progressBar.height color: Kirigami.Theme.highlightColor } } handle: Rectangle { x: progressBar.leftPadding + progressBar.visualPosition * (progressBar.availableWidth - width) y: -(progressBar.height * 0.8) implicitWidth: progressBar.pressed ? Maui.Style.iconSizes.medium : 0 implicitHeight: progressBar.pressed ? Maui.Style.iconSizes.medium : 0 radius: progressBar.pressed ? Maui.Style.iconSizes.medium : 0 color: Kirigami.Theme.highlightColor } } Maui.ToolBar { Layout.fillHeight: true Layout.fillWidth: true position: ToolBar.Footer middleContent: [ ToolButton { id: babeBtnIcon icon.name: "love" enabled: currentTrackIndex >= 0 icon.color: currentBabe ? babeColor : Kirigami.Theme.textColor onClicked: if (!mainlistEmpty) { mainPlaylist.list.fav(currentTrackIndex, !(mainPlaylist.list.get(currentTrackIndex).fav == "1")) currentBabe = mainPlaylist.list.get(currentTrackIndex).fav == "1" } }, ToolButton { icon.name: "media-skip-backward" icon.color: Kirigami.Theme.textColor onClicked: Player.previousTrack() onPressAndHold: Player.playAt(prevTrackIndex) }, ToolButton { id: playIcon enabled: currentTrackIndex >= 0 icon.color: Kirigami.Theme.textColor icon.name: isPlaying ? "media-playback-pause" : "media-playback-start" onClicked: player.playing = !player.playing }, ToolButton { id: nextBtn icon.color: Kirigami.Theme.textColor icon.name: "media-skip-forward" onClicked: Player.nextTrack() onPressAndHold: Player.playAt(Player.shuffle()) }, ToolButton { id: shuffleBtn icon.color: babeColor icon.name: isShuffle ? "media-playlist-shuffle" : "media-playlist-normal" onClicked: { isShuffle = !isShuffle Maui.FM.saveSettings("SHUFFLE", isShuffle, "PLAYBACK") } } ] } } ColumnLayout { anchors.fill: parent SwipeView { id: swipeView Layout.fillHeight: true Layout.fillWidth: true - interactive: Kirigami.Settings.isMobile + // interactive: Kirigami.Settings.isMobile currentIndex: _actionGroup.currentIndex onCurrentIndexChanged: _actionGroup.currentIndex = currentIndex clip: true onCurrentItemChanged: currentItem.forceActiveFocus() TracksView { id: tracksView + + Connections + { + target: vvave + onRefreshTables: tracksView.list.refresh() + } + Connections { target: tracksView onRowClicked: Player.quickPlay(tracksView.list.get(index)) onQuickPlayTrack: Player.quickPlay(tracksView.list.get(index)) onAppendTrack: Player.addTrack(tracksView.list.get(index)) onPlayAll: { var query = Q.GET.allTracks mainPlaylist.list.clear() mainPlaylist.list.query = query Player.playAll() } onAppendAll: { mainPlaylist.list.appendQuery(Q.GET.allTracks) mainPlaylist.listView.positionViewAtEnd() } onQueueTrack: Player.queueTracks([tracksView.list.get(index)], index) } } - CloudView + Loader { - id: cloudView + active: SwipeView.isCurrentItem || SwipeView.isNextItem || SwipeView.isPreviousItem + sourceComponent: CloudView + { + id: cloudView + } } - AlbumsView + Loader { - id: albumsView - - holder.emoji: "qrc:/assets/MusicBox.png" - holder.isMask: false - holder.title : "No Albums!" - holder.body: "Add new music sources" - holder.emojiSize: Maui.Style.iconSizes.huge - title: count + qsTr(" albums") - list.query: Albums.ALBUMS - list.sortBy: Albums.ALBUM - - Connections + active: SwipeView.isCurrentItem || SwipeView.isNextItem || SwipeView.isPreviousItem + sourceComponent:AlbumsView { - target: albumsView - onRowClicked: Player.quickPlay(track) - onAppendTrack: Player.addTrack(track) - onPlayTrack: Player.quickPlay(track) - - onAlbumCoverClicked: albumsView.populateTable(album, artist) - - onAlbumCoverPressedAndHold: + id: albumsView + + holder.emoji: "qrc:/assets/MusicBox.png" + holder.isMask: false + holder.title : "No Albums!" + holder.body: "Add new music sources" + holder.emojiSize: Maui.Style.iconSizes.huge + title: count + qsTr(" albums") + list.query: Albums.ALBUMS + list.sortBy: Albums.ALBUM + + Connections { - var query = Q.GET.albumTracks_.arg(album) - query = query.arg(artist) - - mainPlaylist.list.clear() - mainPlaylist.list.sortBy = Tracks.NONE - mainPlaylist.list.query = query - Player.playAll() + target: vvave + onRefreshTables: albumsView.list.refresh() } - onPlayAll: + Connections { - var query = Q.GET.albumTracks_.arg(album) - query = query.arg(artist) - query = query.arg(data.artist) - - mainPlaylist.list.clear() - mainPlaylist.list.query = query - Player.playAll() - } - - onAppendAll: - { - var query = Q.GET.albumTracks_.arg(album) - query = query.arg(artist) - - mainPlaylist.list.appendQuery(query) - mainPlaylist.listView.positionViewAtEnd() + target: albumsView + onRowClicked: Player.quickPlay(track) + onAppendTrack: Player.addTrack(track) + onPlayTrack: Player.quickPlay(track) + + onAlbumCoverClicked: albumsView.populateTable(album, artist) + + onAlbumCoverPressedAndHold: + { + var query = Q.GET.albumTracks_.arg(album) + query = query.arg(artist) + + mainPlaylist.list.clear() + mainPlaylist.list.sortBy = Tracks.NONE + mainPlaylist.list.query = query + Player.playAll() + } + + onPlayAll: + { + var query = Q.GET.albumTracks_.arg(album) + query = query.arg(artist) + query = query.arg(data.artist) + + mainPlaylist.list.clear() + mainPlaylist.list.query = query + Player.playAll() + } + + onAppendAll: + { + var query = Q.GET.albumTracks_.arg(album) + query = query.arg(artist) + + mainPlaylist.list.appendQuery(query) + mainPlaylist.listView.positionViewAtEnd() + } } } } - AlbumsView + Loader { - id: artistsView - - holder.emoji: "qrc:/assets/MusicBox.png" - holder.isMask: false - holder.title : qsTr("No Artists!") - holder.body: qsTr("Add new music sources") - holder.emojiSize: Maui.Style.iconSizes.huge - title: count + qsTr(" artists") - list.query: Albums.ARTISTS - list.sortBy: Albums.ARTIST - table.list.sortBy: Tracks.NONE + active: SwipeView.isCurrentItem || SwipeView.isNextItem || SwipeView.isPreviousItem - Connections + sourceComponent: AlbumsView { - target: artistsView - onRowClicked: Player.quickPlay(track) - onAppendTrack: Player.addTrack(track) - onPlayTrack: Player.quickPlay(track) - onAlbumCoverClicked: artistsView.populateTable(undefined, artist) - - onAlbumCoverPressedAndHold: - { - var query = Q.GET.artistTracks_.arg(artist) - mainPlaylist.list.clear() - mainPlaylist.list.sortBy = Tracks.NONE - mainPlaylist.list.query = query - Player.playAll() - } - - onPlayAll: + id: artistsView + + holder.emoji: "qrc:/assets/MusicBox.png" + holder.isMask: false + holder.title : qsTr("No Artists!") + holder.body: qsTr("Add new music sources") + holder.emojiSize: Maui.Style.iconSizes.huge + title: count + qsTr(" artists") + list.query: Albums.ARTISTS + list.sortBy: Albums.ARTIST + table.list.sortBy: Tracks.NONE + + Connections { - var query = Q.GET.artistTracks_.arg(artist) - query = query.arg(data.artist) - - mainPlaylist.list.clear() - mainPlaylist.list.sortBy = Tracks.NONE - mainPlaylist.list.query = query - Player.playAll() + target: vvave + onRefreshTables: artistsView.list.refresh() } - onAppendAll: + Connections { - var query = Q.GET.artistTracks_.arg(artist) - - mainPlaylist.list.appendQuery(query) - mainPlaylist.listView.positionViewAtEnd() + target: artistsView + onRowClicked: Player.quickPlay(track) + onAppendTrack: Player.addTrack(track) + onPlayTrack: Player.quickPlay(track) + onAlbumCoverClicked: artistsView.populateTable(undefined, artist) + + onAlbumCoverPressedAndHold: + { + var query = Q.GET.artistTracks_.arg(artist) + mainPlaylist.list.clear() + mainPlaylist.list.sortBy = Tracks.NONE + mainPlaylist.list.query = query + Player.playAll() + } + + onPlayAll: + { + var query = Q.GET.artistTracks_.arg(artist) + query = query.arg(data.artist) + + mainPlaylist.list.clear() + mainPlaylist.list.sortBy = Tracks.NONE + mainPlaylist.list.query = query + Player.playAll() + } + + onAppendAll: + { + var query = Q.GET.artistTracks_.arg(artist) + + mainPlaylist.list.appendQuery(query) + mainPlaylist.listView.positionViewAtEnd() + } } } } - PlaylistsView + Loader { - id: playlistsView - - Connections + active: SwipeView.isCurrentItem || SwipeView.isNextItem || SwipeView.isPreviousItem + sourceComponent:PlaylistsView { - target: playlistsView - - onRowClicked: Player.quickPlay(track) - onAppendTrack: Player.addTrack(track) - onPlayTrack: Player.quickPlay(track) + id: playlistsView - onPlayAll: - { - var query = playlistsView.playlistQuery - mainPlaylist.list.clear() - mainPlaylist.list.sortBy = Tracks.NONE - mainPlaylist.list.query = query - Player.playAll() - } - - onAppendAll: + Connections { - var query = playlistsView.playlistQuery - - mainPlaylist.list.appendQuery(query) - mainPlaylist.listView.positionViewAtEnd() - } - - onPlaySync: - { - var query = playlistsView.playlistQuery - mainPlaylist.list.appendQuery(query) - Player.playAll() - - root.sync = true - root.syncPlaylist = playlist - root.infoMsg = qsTr("Syncing to ") + playlist + target: playlistsView + + onRowClicked: Player.quickPlay(track) + onAppendTrack: Player.addTrack(track) + onPlayTrack: Player.quickPlay(track) + + onPlayAll: + { + var query = playlistsView.playlistQuery + mainPlaylist.list.clear() + mainPlaylist.list.sortBy = Tracks.NONE + mainPlaylist.list.query = query + Player.playAll() + } + + onAppendAll: + { + var query = playlistsView.playlistQuery + + mainPlaylist.list.appendQuery(query) + mainPlaylist.listView.positionViewAtEnd() + } + + onPlaySync: + { + var query = playlistsView.playlistQuery + mainPlaylist.list.appendQuery(query) + Player.playAll() + + root.sync = true + root.syncPlaylist = playlist + root.infoMsg = qsTr("Syncing to ") + playlist + } } } } - FoldersView + Loader { - id: foldersView - - Connections + active: SwipeView.isCurrentItem + sourceComponent: FoldersView { - target: foldersView.list - - onRowClicked: Player.quickPlay(foldersView.list.model.get(index)) - onQuickPlayTrack: Player.quickPlay(foldersView.list.model.get(index)) - - onAppendTrack: Player.addTrack(foldersView.list.model.get(index)) + id: foldersView - onPlayAll: + Connections { - mainPlaylist.list.clear() - // mainPlaylist.list.sortBy = Tracks.NONE - mainPlaylist.list.query = foldersView.list.list.query - Player.playAll() + target: vvave + onRefreshTables: foldersView.populate() } - onAppendAll: + Connections { - var query = foldersView.list.list.query - mainPlaylist.list.appendQuery(query) - mainPlaylist.listView.positionViewAtEnd() - } + target: foldersView.list + + onRowClicked: Player.quickPlay(foldersView.list.model.get(index)) + onQuickPlayTrack: Player.quickPlay(foldersView.list.model.get(index)) + + onAppendTrack: Player.addTrack(foldersView.list.model.get(index)) - onQueueTrack: Player.queueTracks([foldersView.list.model.get(index)], index) + onPlayAll: + { + mainPlaylist.list.clear() + // mainPlaylist.list.sortBy = Tracks.NONE + mainPlaylist.list.query = foldersView.list.list.query + Player.playAll() + } + + onAppendAll: + { + var query = foldersView.list.list.query + mainPlaylist.list.appendQuery(query) + mainPlaylist.listView.positionViewAtEnd() + } + + onQueueTrack: Player.queueTracks([foldersView.list.model.get(index)], index) + } } } - YouTube + Loader { - id: youtubeView + active: SwipeView.isCurrentItem + sourceComponent: YouTube + { + id: youtubeView + } } - SearchTable + Loader { - id: searchView - - Connections + active: SwipeView.isCurrentItem + sourceComponent: SearchTable { - target: searchView - onRowClicked: Player.quickPlay(searchView.list.get(index)) - onQuickPlayTrack: Player.quickPlay(searchView.list.get(index)) - onAppendTrack: Player.addTrack(searchView.list.get(index)) - onPlayAll: - { - mainPlaylist.list.clear() - var tracks = searchView.list.getAll() - for(var i in tracks) - Player.appendTrack(tracks[i]) + id: searchView - Player.playAll() - } - - onAppendAll: Player.appendAll(searchView.list.getAll()) - onArtworkDoubleClicked: + Connections { - var query = Q.GET.albumTracks_.arg( - searchView.list.get( - index).album) - query = query.arg(searchView.list.get(index).artist) - - mainPlaylist.list.clear() - mainPlaylist.list.sortBy = Tracks.NONE - mainPlaylist.list.query = query - Player.playAll() + target: searchView + onRowClicked: Player.quickPlay(searchView.list.get(index)) + onQuickPlayTrack: Player.quickPlay(searchView.list.get(index)) + onAppendTrack: Player.addTrack(searchView.list.get(index)) + onPlayAll: + { + mainPlaylist.list.clear() + var tracks = searchView.list.getAll() + for(var i in tracks) + Player.appendTrack(tracks[i]) + + Player.playAll() + } + + onAppendAll: Player.appendAll(searchView.list.getAll()) + onArtworkDoubleClicked: + { + var query = Q.GET.albumTracks_.arg( + searchView.list.get( + index).album) + query = query.arg(searchView.list.get(index).artist) + + mainPlaylist.list.clear() + mainPlaylist.list.sortBy = Tracks.NONE + mainPlaylist.list.query = query + Player.playAll() + } } } } } Maui.SelectionBar { id: _selectionBar property alias listView: _selectionBar.selectionList Layout.fillWidth: true Layout.margins: Maui.Style.space.big Layout.topMargin: Maui.Style.space.small Layout.bottomMargin: Maui.Style.space.big onIconClicked: _contextMenu.popup() onExitClicked: { root.selectionMode = false clear() } SelectionBarMenu { id: _contextMenu } } } } /*animations*/ /*FUNCTIONS*/ function infoMsgAnim() { animBg.running = true animTxt.running = true } function toggleMaximized() { if (root.visibility === Window.Maximized) { root.showNormal(); } else { root.showMaximized(); } } /*CONNECTIONS*/ Connections { target: vvave onRefreshTables: H.refreshCollection(size) // onRefreshTracks: H.refreshTracks() // onRefreshAlbums: H.refreshAlbums() // onRefreshArtists: H.refreshArtists() // onCoverReady: // { // root.currentArtwork = path // currentTrack.artwork = currentArtwork // mainPlaylist.list.update(currentTrack, currentTrackIndex); // } // onTrackLyricsReady: // { // console.log(lyrics) // if (url === currentTrack.url) // Player.setLyrics(lyrics) // } // onSkipTrack: Player.nextTrack() // onBabeIt: if (!mainlistEmpty) // { // mainPlaylist.list.fav(currentTrackIndex, !(mainPlaylist.list.get(currentTrackIndex).fav == "1")) // currentBabe = mainPlaylist.list.get(currentTrackIndex).fav == "1" // } onOpenFiles: { Player.appendTracksAt(tracks, 0) Player.playAt(0) } } Component.onCompleted: { if(isAndroid) { Maui.Android.statusbarColor(Kirigami.Theme.backgroundColor, true) Maui.Android.navBarColor(Kirigami.Theme.backgroundColor, true) } } } diff --git a/models/albums/albumsmodel.cpp b/models/albums/albumsmodel.cpp index c76ea0f..15d4090 100644 --- a/models/albums/albumsmodel.cpp +++ b/models/albums/albumsmodel.cpp @@ -1,287 +1,288 @@ #include "albumsmodel.h" #include "db/collectionDB.h" #include "utils/brain.h" #include AlbumsModel::AlbumsModel(QObject *parent) : MauiList(parent), db(CollectionDB::getInstance()) {} void AlbumsModel::componentComplete() { + this->setList(); connect(this, &AlbumsModel::queryChanged, this, &AlbumsModel::setList); } FMH::MODEL_LIST AlbumsModel::items() const { return this->list; } void AlbumsModel::setQuery(const QUERY &query) { if(this->query == query) return; this->query = query; emit this->queryChanged(); } AlbumsModel::QUERY AlbumsModel::getQuery() const { return this->query; } void AlbumsModel::setSortBy(const SORTBY &sort) { if(this->sort == sort) return; this->sort = sort; emit this->preListChanged(); this->sortList(); emit this->postListChanged(); emit this->sortByChanged(); } AlbumsModel::SORTBY AlbumsModel::getSortBy() const { return this->sort; } void AlbumsModel::sortList() { const auto key = static_cast(this->sort); qDebug()<< "SORTING LIST BY"<< this->sort; std::sort(this->list.begin(), this->list.end(), [key](const FMH::MODEL &e1, const FMH::MODEL &e2) -> bool { const auto role = key; switch(role) { case FMH::MODEL_KEY::RELEASEDATE: { if(e1[role].toDouble() > e2[role].toDouble()) return true; break; } case FMH::MODEL_KEY::ADDDATE: { const auto date1 = QDateTime::fromString(e1[role], Qt::TextDate); const auto date2 = QDateTime::fromString(e2[role], Qt::TextDate); if(date1.secsTo(QDateTime::currentDateTime()) < date2.secsTo(QDateTime::currentDateTime())) return true; break; } case FMH::MODEL_KEY::ARTIST: case FMH::MODEL_KEY::ALBUM: { const auto str1 = QString(e1[role]).toLower(); const auto str2 = QString(e2[role]).toLower(); if(str1 < str2) return true; break; } default: if(e1[role] < e2[role]) return true; } return false; }); } void AlbumsModel::setList() { emit this->preListChanged(); QString m_Query; if(this->query == AlbumsModel::QUERY::ALBUMS) m_Query = "select * from albums order by album asc"; else if(this->query == AlbumsModel::QUERY::ARTISTS) m_Query = "select * from artists order by artist asc"; //get albums data with modifier for missing images for artworks this->list = this->db->getDBData(m_Query, [&](FMH::MODEL &item) { if(item[FMH::MODEL_KEY::ARTWORK].isEmpty()) return; if(!FMH::fileExists(item[FMH::MODEL_KEY::ARTWORK])) { const auto table = this->query == AlbumsModel::QUERY::ALBUMS ? "albums" : "artists"; this->db->removeArtwork(table, FMH::toMap(item)); item[FMH::MODEL_KEY::ARTWORK] = ""; }}); this->sortList(); emit this->postListChanged(); -if(this->query == AlbumsModel::QUERY::ALBUMS) -this->fetchInformation(); +//if(this->query == AlbumsModel::QUERY::ALBUMS) +//this->fetchInformation(); } void AlbumsModel::fetchInformation() { qDebug() << "RNUNGING BRAIN EFFORRTS"; QFutureWatcher *watcher = new QFutureWatcher; QObject::connect(watcher, &QFutureWatcher::finished, watcher, &QFutureWatcher::deleteLater); // QObject::connect(this, &AlbumsModel::destroyed, watcher, &QFutureWatcher::waitForFinished); auto func = [&, stop = bool()]() mutable { stop = false; QList requests; int index = -1; for(auto &album : this->list) { index++; if(!album[FMH::MODEL_KEY::ARTWORK].isEmpty()) continue; if(BAE::artworkCache(album, FMH::MODEL_KEY::ALBUM)) { this->db->insertArtwork(album); emit this->updateModel(index, {FMH::MODEL_KEY::ARTWORK}); continue; } PULPO::REQUEST request; request.track = album; request.ontology = this->query == AlbumsModel::QUERY::ALBUMS ? PULPO::ONTOLOGY::ALBUM : PULPO::ONTOLOGY::ARTIST; request.services = {PULPO::SERVICES::LastFm, PULPO::SERVICES::Spotify, PULPO::SERVICES::MusicBrainz}; request.info = {PULPO::INFO::ARTWORK}; request.callback = [&, index](PULPO::REQUEST request, PULPO::RESPONSES responses) { qDebug() << "DONE WITH " << request.track ; for(const auto &res : responses) { if(res.context == PULPO::CONTEXT::IMAGE && !res.value.toString().isEmpty()) { auto downloader = new FMH::Downloader; QObject::connect(downloader, &FMH::Downloader::fileSaved, [&, index, request, _downloader = std::move(downloader)](QString path) { FMH::MODEL newTrack = request.track; newTrack[FMH::MODEL_KEY::ARTWORK] = QUrl::fromLocalFile(path).toString(); this->db->insertArtwork(newTrack); // this->updateArtwork(index, path); album[FMH::MODEL_KEY::ARTWORK] = newTrack[FMH::MODEL_KEY::ARTWORK]; emit this->updateModel(index, {FMH::MODEL_KEY::ARTWORK}); _downloader->deleteLater(); }); QStringList filePathList = res.value.toString().split('/'); const auto format = "." + filePathList.at(filePathList.count() - 1).split(".").last(); QString name = !request.track[FMH::MODEL_KEY::ALBUM].isEmpty() ? request.track[FMH::MODEL_KEY::ARTIST] + "_" + request.track[FMH::MODEL_KEY::ALBUM] : request.track[FMH::MODEL_KEY::ARTIST]; name.replace("/", "-"); name.replace("&", "-"); downloader->setFile(res.value.toString(), BAE::CachePath + name + format); qDebug()<<"SAVING ARTWORK FOR: " << request.track[FMH::MODEL_KEY::ALBUM]<< BAE::CachePath + name + format; } } }; requests << request; } Pulpo pulpo; QEventLoop loop; QObject::connect(&pulpo, &Pulpo::finished, &loop, &QEventLoop::quit); QObject::connect(this, &AlbumsModel::destroyed, [&pulpo, &loop, &stop]() { qDebug()<< stop << &stop; pulpo.disconnect(); stop = true; if(loop.isRunning()) loop.quit(); qDebug()<< stop << &stop; }); for(const auto &req : requests) { if(stop) { qDebug()<< "TRYING EXITING THREAD LOADINFO" << loop.isRunning(); qDebug()<< "EXITING THREAD LOADINFO" << loop.isRunning(); break; }else { pulpo.request(req); loop.exec(); } } qDebug()<< "DISCONNET SIGNAL"; // disconnect(this, SIGNAL(destroyed())); }; QFuture t1 = QtConcurrent::run(func); watcher->setFuture(t1); } void AlbumsModel::updateArtwork(const int index, const QString &artwork) { if(index >= this->list.size() || index < 0) return; this->list[index][FMH::MODEL_KEY::ARTWORK] = artwork; emit this->updateModel(index, {FMH::MODEL_KEY::ARTWORK}); } QVariantMap AlbumsModel::get(const int &index) const { if(index >= this->list.size() || index < 0) return QVariantMap(); return FMH::toMap(this->list.at(index)); } void AlbumsModel::append(const QVariantMap &item) { if(item.isEmpty()) return; emit this->preItemAppended(); FMH::MODEL model; for(auto key : item.keys()) model.insert(FMH::MODEL_NAME_KEY[key], item[key].toString()); this->list << model; emit this->postItemAppended(); } void AlbumsModel::append(const QVariantMap &item, const int &at) { if(item.isEmpty()) return; if(at > this->list.size() || at < 0) return; qDebug()<< "trying to append at" << at << item["title"]; emit this->preItemAppendedAt(at); FMH::MODEL model; for(auto key : item.keys()) model.insert(FMH::MODEL_NAME_KEY[key], item[key].toString()); this->list.insert(at, model); emit this->postItemAppended(); } void AlbumsModel::refresh() { this->setList(); } diff --git a/services/local/LinkingDialog.qml b/services/local/LinkingDialog.qml index 8665283..f3e84fd 100644 --- a/services/local/LinkingDialog.qml +++ b/services/local/LinkingDialog.qml @@ -1,106 +1,106 @@ -import QtQuick 2.9 -import QtQuick.Controls 2.2 +import QtQuick 2.10 +import QtQuick.Controls 2.10 import QtQuick.Layouts 1.3 import "../../utils/Help.js" as H import org.kde.mauikit 1.0 as Maui Maui.Dialog { id: linkingDialogRoot maxHeight: Maui.Style.unit *400 onAccepted: { if(ipField.text === link.deviceIp()) H.notify("Error", "Please provide a different IP address") else { bae.saveSetting("LINKINGIP", ipField.text, "BABE") link.connectTo(ipField.text, link.getPort()) } } ScrollView { anchors.fill: parent clip: true contentWidth: linkingDialogRoot.width contentHeight: contentLayout.implicitHeight ColumnLayout { id: contentLayout width: linkingDialogRoot.width Label { text:qsTr("Linking allows to connect two devices on the same network. Just provide the device IP address to which you want to connect") verticalAlignment: Qt.AlignVCenter elide: Text.ElideRight font.pointSize: Maui.Style.fontSizes.default wrapMode: Text.Wrap Layout.fillWidth: true } Label { text: qsTr("IP Address") verticalAlignment: Qt.AlignVCenter elide: Text.ElideRight font.pointSize: Maui.Style.fontSizes.default Layout.fillWidth: true } Maui.TextField { id: ipField Layout.fillWidth: true text: bae.loadSetting("LINKINGIP", "BABE", link.getIp()) } CheckBox { id: autoLink checked: bae.loadSetting("AUTOLINKING", "BABE", false) text: qsTr("Autolink to IP address") onCheckedChanged: { bae.saveSetting("AUTOLINKING", checked, "BABE") } } CheckBox { id: linkState checked: isLinked text: isLinked ? qsTr("Linked to ")+ link.getIp(): "You're not linked" enabled: false } CheckBox { id: servingState checked: isServing text: isServing ? qsTr("Serving to ")+ link.getDeviceName() : "You're not serving" enabled: false } Label { text:qsTr("This Device IP address: \n") +link.deviceIp() verticalAlignment: Qt.AlignVCenter elide: Text.ElideRight font.pointSize: Maui.Style.fontSizes.small Layout.fillWidth: true } } } } diff --git a/services/local/LinkingListModel.qml b/services/local/LinkingListModel.qml index 818c7f0..0ae4d09 100644 --- a/services/local/LinkingListModel.qml +++ b/services/local/LinkingListModel.qml @@ -1,132 +1,132 @@ -import QtQuick 2.9 +import QtQuick 2.10 import QtQuick.Layouts 1.3 -import QtQuick.Controls 2.2 +import QtQuick.Controls 2.10 import org.kde.kirigami 2.2 as Kirigami import org.kde.mauikit 1.0 as Maui import "../../utils" import "../../widgets/PlaylistsView" import "../../view_models" import "../../db/Queries.js" as Q import "../../utils/Help.js" as H import Link.Codes 1.0 BabeList { id: linkingListRoot headBarExit: false headBarTitle: isLinked ?link.getIp() : qsTr("Disconnected") headBar.leftContent: ToolButton { icon.name : "view-refresh" onClicked : refreshPlaylists() } headBar.rightContent: ToolButton { id: menuBtn icon.name: "application-menu" onClicked: linkingConf.open() } ListModel { id: linkingListModel ListElement { playlist: qsTr("Albums"); icon: "view-media-album-cover"} ListElement { playlist: qsTr("Artists"); icon: "view-media-artist"} ListElement { playlist: qsTr("Most Played"); icon: "view-media-playcount" /*query: Q.Query.mostPlayedTracks*/ } ListElement { playlist: qsTr("Favorites"); icon: "view-media-favorite"} ListElement { playlist: qsTr("Recent"); icon: "view-media-recent"} ListElement { playlist: qsTr("Babes"); icon: "love"} ListElement { playlist: qsTr("Online"); icon: "internet-services"} ListElement { playlist: qsTr("Tags"); icon: "tag"} ListElement { playlist: qsTr("Relationships"); icon: "view-media-similarartists"} ListElement { playlist: qsTr("Popular"); icon: "view-media-chart"} ListElement { playlist: qsTr("Genres"); icon: "view-media-genre"} } model: linkingListModel delegate : Maui.ListDelegate { id: delegate width: linkingListRoot.width label: model.playlist Connections { target : delegate onClicked : { currentIndex = index var playlist = linkingListModel.get(index).playlist switch(playlist) { case "Artists": populateExtra(LINK.FILTER, "select artist as tag from artists", playlist) break case "Albums": populateExtra(LINK.FILTER, "select album as tag, artist from albums", playlist) break case "Most Played": playlistViewRoot.populate(Q.GET.mostPlayedTracks); break; case "Favorites": filterList.section.property = "stars" playlistViewRoot.populate(Q.GET.favoriteTracks); break; case "Recent": playlistViewRoot.populate(Q.GET.recentTracks); break; case "Babes": playlistViewRoot.populate(Q.GET.babedTracks); break; case "Online": playlistViewRoot.populate(Q.GET.favoriteTracks); break; case "Tags": populateExtra(LINK.FILTER, Q.GET.tags, playlist) break; case "Relationships": playlistViewRoot.populate(Q.GET.favoriteTracks); break; case "Popular": playlistViewRoot.populate(Q.GET.favoriteTracks); break; case "Genres": populateExtra(LINK.FILTER, Q.GET.genres, playlist) break; default: playlistViewRoot.populate(Q.GET.playlistTracks_.arg(playlist)); break; } } } } } diff --git a/services/local/LinkingView.qml b/services/local/LinkingView.qml index eac1e79..edc6eaf 100644 --- a/services/local/LinkingView.qml +++ b/services/local/LinkingView.qml @@ -1,350 +1,350 @@ -import QtQuick 2.9 -import QtQuick.Controls 2.2 +import QtQuick 2.10 +import QtQuick.Controls 2.10 import QtQuick.Layouts 1.3 import "../../view_models" import "../../view_models/BabeTable" import "../../widgets/PlaylistsView" import "../../utils/Help.js" as H import "../../db/Queries.js" as Q import Link.Codes 1.0 import org.kde.kirigami 2.2 as Kirigami import org.kde.mauikit 1.0 as Maui ColumnLayout { id: linkingViewRoot property alias linkingConf : linkingConf signal rowClicked(var track) signal quickPlayTrack(var track) signal playAll(var tracks) signal playSync(var playlist) signal appendAll(var tracks) spacing: 0 Kirigami.PageRow { id: linkingPage Layout.fillHeight: true Layout.fillWidth: true clip: true separatorVisible: wideMode initialPage: [playlistList, filterList] defaultColumnWidth: Kirigami.Units.gridUnit * 15 interactive: false LinkingDialog { id: linkingConf } Page { id: playlistList clip: true anchors.fill: parent SwipeView { id: linkingSwipe anchors.fill: parent interactive: false clip: true LinkingListModel { id: linkingModel } BabeList { id: linkingFilter headBarExitIcon: "go-previous" model : ListModel {} delegate: Maui.LabelDelegate { id: delegate label : tag Connections { target: delegate onClicked: populateFromFilter(index, linkingFilter.headBarTitle) } } onExit: linkingSwipe.currentIndex = 0 } } } BabeTable { id: filterList anchors.fill: parent clip: true coverArtVisible: false headBar.visible: true headBarExitIcon: "go-previous" headBarExit: !linkingPage.wideMode headBarTitle: linkingPage.wideMode ? "" : linkingModel.model.get(linkingModel.currentIndex).playlist onExit: if(!linkingPage.wideMode) linkingPage.currentIndex = 0 holder.emoji: "qrc:/assets/USB.png" holder.isMask: false holder.title : link.getDeviceName() ? link.getDeviceName() : "Disconnected!" holder.body: "Your linked playlist is empty" holder.emojiSize: Maui.Style.iconSizes.huge appendBtn.visible: false playAllBtn.visible: false menuBtn.visible: false section.criteria: ViewSection.FullString section.delegate: Maui.LabelDelegate { label: filterList.section.property === qsTr("stars") ? H.setStars(section) : section isSection: true boldLabel: true labelTxt.font.family: "Material Design Icons" } Connections { target: filterList onRowClicked: {} onQuickPlayTrack: { // link.collectTrack(filterList.model.get(index).url) // player.playRemote("ftp://"+link.getIp()+filterList.model.get(index).url) } onPlayAll: {} onPulled: {} } } } Kirigami.Separator { visible: !isMobile Layout.fillWidth: true width: parent.width height: 1 } ToolBar { id: searchBox Layout.fillWidth: true // width: parent.width // height: Maui.Style.toolBarHeight position: ToolBar.Footer Rectangle { anchors.fill: parent z: -999 color: backgroundColor } RowLayout { anchors.fill: parent TextInput { id: searchInput color: textColor Layout.fillWidth: true Layout.fillHeight: true horizontalAlignment: Text.AlignHCenter verticalAlignment: Text.AlignVCenter selectByMouse: !root.isMobile selectionColor: highlightColor selectedTextColor: highlightedTextColor focus: true text: "" wrapMode: TextEdit.Wrap onAccepted: runSearch(searchInput.text) } ToolButton { Layout.rightMargin: contentMargins icon.name: "edit-clear" onClicked: searchInput.clear() } } } Connections { target: link onServerConReady: { isServing = true H.notify(deviceName, "You're now linked!") } onClientConError: { isLinked = false H.notify("Linking error", "error connecting to server") } onDevicesLinked: { isLinked = true H.notify("Linked!", "The link is ready") refreshPlaylists() } onClientConDisconnected: { isLinked = false; H.notify("Unlinked!", "The client is disconnected") } onServerConDisconnected: { isServing = false; H.notify("Unlinked!", "The server is disconnected") } onResponseReady: parseResponse(res) } function refreshPlaylists() { for(var i=11; i < linkingModel.count; i++) linkingModel.model.remove(i) if(isLinked) link.ask(LINK.PLAYLISTS, Q.GET.playlists) } function appendPlaylists(res) { if(res.length>0) for(var i in res) linkingModel.model.append(res[i]) } function appendToExtraList(res) { if(res.length>0) for(var i in res) linkingFilter.model.append(res[i]) } function populateExtra(code, query, title) { linkingSwipe.currentIndex = 1 link.ask(code, query) linkingFilter.clearTable() linkingFilter.headBarTitle = title } function parseResponse(res) { switch(res.CODE) { case LINK.PLAYLISTS: appendPlaylists(res.MSG) break case LINK.FILTER: appendToExtraList(res.MSG) break case LINK.QUERY: case LINK.SEARCHFOR: populate(res.MSG) break default: console.log(res.CODE, res.MSG); break; } } function populateFromFilter(index, title) { linkingFilter.currentIndex = index var tag = linkingFilter.model.get(index).tag switch(title) { case "Albums": var artist = linkingFilter.model.get(index).artist var query = Q.GET.albumTracks_.arg(tag) link.ask(LINK.QUERY, query.arg(artist)) break case "Artists": query = Q.GET.artistTracks_.arg(tag) link.ask(LINK.QUERY, query.arg(tag)) break case "Genres": query = Q.GET.genreTracks_.arg(tag) link.ask(LINK.QUERY, query.arg(tag)) break case "Tags": query = Q.GET.tagTracks_.arg(tag) link.ask(LINK.QUERY, query.arg(tag)) break default: break } } function populate(tracks) { if(!linkingPage.wideMode) linkingPage.currentIndex = 1 filterList.clearTable() if(tracks.length>0) for(var i in tracks) filterList.model.append(tracks[i]) } function runSearch(searchTxt) { if(searchTxt) if(searchTxt !== filterList.headBarTitle) { filterList.headBarTitle = searchTxt link.ask(LINK.SEARCHFOR, searchTxt) } } function clearSearch() { searchInput.clear() youtubeTable.clearTable() youtubeTable.headBarTitle = "" searchRes = [] } } diff --git a/services/web/Spotify/LoginForm.qml b/services/web/Spotify/LoginForm.qml index 04ac8c4..d6dd472 100644 --- a/services/web/Spotify/LoginForm.qml +++ b/services/web/Spotify/LoginForm.qml @@ -1,40 +1,40 @@ -import QtQuick 2.9 -import QtQuick.Controls 2.2 +import QtQuick 2.10 +import QtQuick.Controls 2.10 import QtQuick.Layouts 1.3 import QtWebEngine 1.5 import "../../../view_models" BabePopup { padding: 0 maxHeight: parent.height * 0.8 maxWidth: parent.width * 0.5 closePolicy: Popup.CloseOnPressOutsideParent WebEngineView { anchors.fill: parent url: "https://accounts.spotify.com/en/authorize?response_type=token&client_id=a49552c9276745f5b4752250c2d84367&scope=streaming user-read-private user-read-email&redirect_uri=vvave:%2F%2Fcallback" onLoadingChanged: { var myUrl = url.toString() if(myUrl.startsWith("vvave://callback/#access_token=")) { var code = myUrl.slice(("vvave://callback/#access_token=").length, myUrl.length) spotify.setCode(code); url = "qrc:/services/web/Spotify/spotify.html" } if(loadRequest.status === WebEngineLoadRequest.LoadSucceededStatus) console.log("page loaded sucessfully") } onNewViewRequested: { console.log("new view requested") } } } diff --git a/services/web/Spotify/Spotify.qml b/services/web/Spotify/Spotify.qml index 4fa252b..c333860 100644 --- a/services/web/Spotify/Spotify.qml +++ b/services/web/Spotify/Spotify.qml @@ -1,80 +1,80 @@ -import QtQuick 2.9 -import QtQuick.Controls 2.2 +import QtQuick 2.10 +import QtQuick.Controls 2.10 import QtQuick.Layouts 1.3 import "../../../view_models" import "../../../view_models/BabeTable" import org.kde.kirigami 2.2 as Kirigami import org.kde.mauikit 1.0 as Maui Page { Loader { id: loginLoader } ColumnLayout { anchors.fill: parent spacing: 0 BabeTable { Layout.fillWidth: true Layout.fillHeight: true headBarExit: false headBar.leftContent: ToolButton { icon.name: "internet-services" onClicked:if(!isAndroid) { loginLoader.source = "LoginForm.qml" loginLoader.item.parent = spotifyView loginLoader.item.open() } } } ToolBar { id: searchBox Layout.fillWidth: true position: ToolBar.Footer RowLayout { anchors.fill: parent TextInput { id: searchInput color: textColor Layout.fillWidth: true Layout.fillHeight: true horizontalAlignment: Text.AlignHCenter verticalAlignment: Text.AlignVCenter selectByMouse: !isMobile selectionColor: highlightColor selectedTextColor: highlightedTextColor focus: true text: "" wrapMode: TextEdit.Wrap onAccepted: runSearch(searchInput.text) } ToolButton { Layout.rightMargin: contentMargins icon.name: "edit-clear" onClicked: searchInput.clear() } } } } } diff --git a/services/web/YouTube.qml b/services/web/YouTube.qml index 24d15b9..31ada39 100644 --- a/services/web/YouTube.qml +++ b/services/web/YouTube.qml @@ -1,281 +1,281 @@ -import QtQuick 2.9 -import QtQuick.Controls 2.2 +import QtQuick 2.10 +import QtQuick.Controls 2.10 import QtQuick.Layouts 1.3 import "../../view_models" import "../../view_models/BabeTable" import org.kde.kirigami 2.2 as Kirigami import org.kde.mauikit 1.0 as Maui Maui.Page { id: youtubeViewRoot property var searchRes : [] clip: true property alias viewer : youtubeViewer property int openVideo : 0 headBar.visible: false Connections { target: youtube onQueryResultsReady: { searchRes = res; populate(searchRes) youtubeTable.forceActiveFocus() if(openVideo > 0) { console.log("trying to open video") watchVideo(youtubeTable.model.get(openVideo-1)) openVideo = 0 } } } /*this is for playing the track sin the background without showing the actual video*/ Loader { id: youtubePlayer source: isAndroid ? "qrc:/services/web/YoutubePlayer_A.qml" : "qrc:/services/web/YoutubePlayer.qml" } Maui.Dialog { id: configPopup parent: parent margins: Maui.Style.contentMargins widthHint: 0.9 heightHint: 0.9 maxHeight: 200 maxWidth: 300 defaultButtons: false GridLayout { anchors.fill: parent columns: 1 rows: 6 clip: true Item { Layout.column: 1 Layout.row: 1 Layout.fillWidth: true Layout.fillHeight: true } Label { text: qsTr("Custom API Key") verticalAlignment: Qt.AlignVCenter elide: Text.ElideRight font.pointSize: Maui.Style.fontSizes.default Layout.column: 1 Layout.row: 2 Layout.fillWidth: true } TextField { Layout.column: 1 Layout.row: 3 Layout.fillWidth: true text: Maui.FM.loadSettings("YOUTUBEKEY", "BABE", youtube.getKey()) } Label { text: qsTr("Search results") verticalAlignment: Qt.AlignVCenter elide: Text.ElideRight font.pointSize: Maui.Style.fontSizes.default Layout.column: 1 Layout.row: 4 Layout.fillWidth: true } SpinBox { Layout.alignment: Qt.AlignRight Layout.column: 1 Layout.row: 5 Layout.fillWidth: true from: 1 to: 50 value: Maui.FM.loadSettings("YOUTUBELIMIT", "BABE", 25) editable: true onValueChanged: { Maui.FM.saveSettings("YOUTUBELIMIT", value, "BABE") } } Item { Layout.column: 1 Layout.row: 6 Layout.fillWidth: true Layout.fillHeight: true } } } StackView { id: stackView anchors.fill: parent focus: true pushEnter: Transition { PropertyAnimation { property: "opacity" from: 0 to:1 duration: 200 } } pushExit: Transition { PropertyAnimation { property: "opacity" from: 1 to:0 duration: 200 } } popEnter: Transition { PropertyAnimation { property: "opacity" from: 0 to:1 duration: 200 } } popExit: Transition { PropertyAnimation { property: "opacity" from: 1 to:0 duration: 200 } } initialItem: BabeTable { id: youtubeTable trackNumberVisible: false headBar.visible: false holder.emoji: "qrc:/assets/Astronaut.png" holder.isMask: false holder.title : "No Results!" holder.body: "Try with another query" holder.emojiSize: Maui.Style.iconSizes.huge coverArtVisible: true model: ListModel{} onRowClicked: { watchVideo(youtubeTable.model.get(index)) } onQuickPlayTrack: { playTrack(youtubeTable.model.get(index).url) } } YoutubeViewer { id: youtubeViewer } } footBar.leftContent: ToolButton { id: menuBtn icon.name: "application-menu" onClicked: configPopup.open() } footBar.rightContent: ToolButton { icon.name: "edit-clear" onClicked: clearSearch() } footBar.middleContent: Maui.TextField { id: searchInput Layout.fillWidth: true placeholderText: qsTr("Search videos...") wrapMode: TextEdit.Wrap onAccepted: runSearch(searchInput.text) } function watchVideo(track) { if(track && track.url) { var url = track.url if(url && url.length > 0) { youtubeViewer.currentYt = track youtubeViewer.webView.url = url+"?autoplay=1" stackView.push(youtubeViewer) } } } function playTrack(url) { if(url && url.length > 0) { var newURL = url.replace("embed/", "watch?v=") console.log(newURL) youtubePlayer.item.url = newURL+"?autoplay=1+&vq=tiny" youtubePlayer.item.runJavaScript("document.title", function(result) { console.log(result); }); } } function runSearch(searchTxt) { if(searchTxt) if(searchTxt !== youtubeTable.title) { youtubeTable.title = searchTxt youtube.getQuery(searchTxt, Maui.FM.loadSettings("YOUTUBELIMIT", "BABE", 25)) } } function clearSearch() { searchInput.clear() youtubeTable.listView.model.clear() youtubeTable.title = "" searchRes = [] } function populate(tracks) { youtubeTable.model.clear() for(var i in tracks) youtubeTable.model.append(tracks[i]) } } diff --git a/services/web/YoutubePlayer.qml b/services/web/YoutubePlayer.qml index 9220190..45e7060 100644 --- a/services/web/YoutubePlayer.qml +++ b/services/web/YoutubePlayer.qml @@ -1,31 +1,31 @@ -import QtQuick 2.9 -import QtQuick.Controls 2.2 +import QtQuick 2.10 +import QtQuick.Controls 2.10 import QtQuick.Layouts 1.3 import "../../view_models" import QtWebEngine 1.5 import "../../utils/Player.js" as Player import "YoutubeHelper.js" as YTH WebEngineView { id: webView anchors.fill: parent visible: true property bool wasPlaying: false onLoadingChanged: { if (loadRequest.errorString) console.error(loadRequest.errorString); } onRecentlyAudibleChanged: { console.log("is playing", recentlyAudible) if(recentlyAudible && isPlaying) Player.pauseTrack() if(!recentlyAudible && wasPlaying) Player.resumeTrack() } } diff --git a/services/web/YoutubePlayer_A.qml b/services/web/YoutubePlayer_A.qml index 4744cc9..4b82d50 100644 --- a/services/web/YoutubePlayer_A.qml +++ b/services/web/YoutubePlayer_A.qml @@ -1,33 +1,33 @@ -import QtQuick 2.9 -import QtQuick.Controls 2.2 +import QtQuick 2.10 +import QtQuick.Controls 2.10 import QtQuick.Layouts 1.3 import "../../view_models" import QtWebView 1.1 import "../../utils/Player.js" as Player import "YoutubeHelper.js" as YTH WebView { id: webView anchors.fill: parent visible: false clip: true property bool wasPlaying: false onLoadingChanged: { if (loadRequest.errorString) console.error(loadRequest.errorString); } // onRecentlyAudibleChanged: // { // console.log("is playing", recentlyAudible) // if(recentlyAudible && isPlaying) // Player.pauseTrack() // if(!recentlyAudible && wasPlaying) // Player.resumeTrack() // } } diff --git a/services/web/YoutubeViewer.qml b/services/web/YoutubeViewer.qml index c6a7442..f662cf1 100644 --- a/services/web/YoutubeViewer.qml +++ b/services/web/YoutubeViewer.qml @@ -1,48 +1,48 @@ -import QtQuick 2.9 -import QtQuick.Controls 2.2 +import QtQuick 2.10 +import QtQuick.Controls 2.10 import QtQuick.Layouts 1.3 import "../../view_models" import org.kde.kirigami 2.2 as Kirigami import org.kde.mauikit 1.0 as Maui Maui.Page { id: videoPlayback property alias webView: webViewer.item property bool wasPlaying: false property var currentYt : ({}) title: currentYt ? currentYt.title : "YouTube" headBar.leftContent: ToolButton { icon.name: "go-previous" onClicked: stackView.pop(youtubeTable) } headBar.rightContent: [ ToolButton { icon.name : "link" onClicked: webView.url = currentYt.url.replace("embed/", "watch?v=") }, ToolButton { icon.name : "download" onClicked: bae.getYoutubeTrack(JSON.stringify(currentYt)) } ] Loader { id: webViewer clip: true anchors.fill: parent source: isAndroid ? "qrc:/services/web/WebView_A.qml" : "qrc:/services/web/WebView.qml" onVisibleChanged: if(!visible) webView.url = "about:blank" } } diff --git a/utils/Help.js b/utils/Help.js index a3a863d..4b18995 100644 --- a/utils/Help.js +++ b/utils/Help.js @@ -1,115 +1,112 @@ function rootWidth() { return root.width; } function rootHeight() { return root.height; } function setStars(stars) { switch (stars) { case "0": case 0: return ""; case "1": case 1: return "\uf4CE"; case "2": case 2: return "\uf4CE \uf4CE"; case "3": case 3: return "\uf4CE \uf4CE \uf4CE"; case "4": case 4: return "\uf4CE \uf4CE \uf4CE \uf4CE"; case "5": case 5: return "\uf4CE \uf4CE \uf4CE \uf4CE \uf4CE"; default: return "error"; } } function refreshCollection(size) { if(size>0) root.notify("emblem-info", "Collection updated", size+" new tracks added...") - refreshTracks() - refreshAlbums() - refreshArtists() - refreshFolders() + } function refreshFolders() { foldersView.populate() } function refreshTracks() { tracksView.list.refresh() } function refreshAlbums() { albumsView.list.refresh() // albumsView.list.fetchInformation(); } function refreshArtists() { artistsView.list.refresh() } function notify(title, body) { if(isMobile) root.notify(title+"\n"+body) else bae.notify(title, body) } function addPlaylist(playlist) { playlistsView.playlistViewModel.model.insert(0, playlist) } function searchFor(query) { if(currentView !== viewsIndex.search) currentView = viewsIndex.search searchView.runSearch(query) } function addSource() { sourcesDialog.open() } function addToSelection(item) { if(selectionBar.contains(item.url)) { selectionBar.removeAtPath(item.url) return } item.thumbnail= item.artwork item.icon = "audio-x-generic" item.label= item.title item.mime= "image/png" item.tooltip= item.url item.path= item.url selectionBar.append(item) } diff --git a/view_models/BabeGrid/BabeAlbum.qml b/view_models/BabeGrid/BabeAlbum.qml index e85e41b..be3f760 100644 --- a/view_models/BabeGrid/BabeAlbum.qml +++ b/view_models/BabeGrid/BabeAlbum.qml @@ -1,221 +1,221 @@ -import QtQuick 2.9 +import QtQuick 2.10 import QtGraphicalEffects 1.0 -import QtQuick.Controls 2.2 +import QtQuick.Controls 2.10 import QtQuick.Layouts 1.3 import AlbumsList 1.0 import org.kde.kirigami 2.7 as Kirigami import org.kde.mauikit 1.0 as Maui Maui.ItemDelegate { id: control property int albumSize : Maui.Style.iconSizes.huge property int albumRadius : 0 property bool albumCard : true property string fillColor : Qt.darker(Kirigami.Theme.backgroundColor, 1.1) property bool hide : false property bool showLabels : true property bool showIndicator : false property bool hideRepeated : false property bool increaseCurrentItem : false property alias label1 : _label1 property alias label2 : _label2 property alias image : _image isCurrentItem: GridView.isCurrentItem // height: typeof album === 'undefined' ? parseInt(albumSize+(albumSize*0.3)) : parseInt(albumSize+(albumSize*0.4)) readonly property bool sameAlbum : { if(hideRepeated) { if(albumsRollRoot.model.get(index-1)) { if(albumsRollRoot.model.get(index-1).album === album && albumsRollRoot.model.get(index-1).artist === artist) true else false }else false }else false } visible: !sameAlbum Item { id: _cover anchors.fill: parent anchors.margins: Maui.Style.space.tiny Image { id: _image width: parent.width height: width sourceSize.width: width sourceSize.height: height fillMode: Image.PreserveAspectFit smooth: true asynchronous: true onStatusChanged: { if (status == Image.Error) source = "qrc:/assets/cover.png"; } layer.enabled: albumRadius layer.effect: OpacityMask { maskSource: Item { width: _image.width height: _image.height Rectangle { anchors.centerIn: parent width: _image.adapt ? _image.width : Math.min(_image.width, _image.height) height: _image.adapt ? _image.height : width radius: albumRadius } } } } Rectangle { visible : showIndicator && currentTrackIndex === index height: _image.height * 0.1 width: _image.width * 0.1 anchors.bottom: parent.bottom anchors.bottomMargin: Maui.Style.space.big anchors.horizontalCenter:parent.horizontalCenter radius: Math.min(width, height) color: "#f84172" AnimatedImage { source: "qrc:/assets/heart_indicator_white.gif" anchors.centerIn: parent height: parent.height * 0.6 width: parent.width * 0.6 playing: parent.visible } } Item { id: _labelBg height: Math.min (parent.height * 0.3, _labelsLayout.implicitHeight ) + Maui.Style.space.big width: parent.width anchors.bottom: parent.bottom visible: showLabels Kirigami.Theme.inherit: false Kirigami.Theme.backgroundColor: "#333"; Kirigami.Theme.textColor: "#fafafa" FastBlur { id: blur anchors.fill: parent source: ShaderEffectSource { sourceItem: _image sourceRect:Qt.rect(0, _image.height - _labelBg.height, _labelBg.width, _labelBg.height) } radius: 50 Rectangle { anchors.fill: parent color: _labelBg.Kirigami.Theme.backgroundColor opacity: 0.4 } layer.enabled: true layer.effect: OpacityMask { maskSource: Item { width: blur.width height: blur.height Rectangle { anchors.centerIn: parent width: parent.width height: parent.height radius: albumRadius Rectangle { anchors.top: parent.top width: parent.width height: parent.radius } } } } } ColumnLayout { id: _labelsLayout anchors.centerIn: parent width: parent.width * 0.9 height: Math.min(parent.height * 0.9, implicitHeight) spacing: 0 Label { id: _label1 Layout.fillWidth: visible Layout.fillHeight: visible visible: text && control.width > 50 horizontalAlignment: Qt.AlignLeft elide: Text.ElideRight font.pointSize: Maui.Style.fontSizes.default font.bold: true font.weight: Font.Bold color: Kirigami.Theme.textColor wrapMode: Text.NoWrap } Label { id: _label2 Layout.fillWidth: visible Layout.fillHeight: visible visible: text && (control.width > 70) horizontalAlignment: Qt.AlignLeft elide: Text.ElideRight font.pointSize: Maui.Style.fontSizes.medium color: Kirigami.Theme.textColor wrapMode: Text.NoWrap } } } } DropShadow { anchors.fill: _cover visible: !control.hovered horizontalOffset: 0 verticalOffset: 0 radius: 8.0 samples: 17 color: "#80000000" source: _cover } } diff --git a/view_models/BabeGrid/BabeGrid.qml b/view_models/BabeGrid/BabeGrid.qml index 8c4579b..ff7d75a 100644 --- a/view_models/BabeGrid/BabeGrid.qml +++ b/view_models/BabeGrid/BabeGrid.qml @@ -1,100 +1,100 @@ -import QtQuick.Controls 2.2 -import QtQuick 2.9 +import QtQuick.Controls 2.10 +import QtQuick 2.10 import ".." import org.kde.kirigami 2.7 as Kirigami import org.kde.mauikit 1.0 as Maui import AlbumsList 1.0 Maui.Page { id: gridPage property int albumCoverSize: Math.min(160, width * 0.3) property int albumCoverRadius : Maui.Style.radiusV property bool albumCardVisible : true property alias list: _albumsList property alias listModel: _albumsModel property alias grid: grid property alias holder: grid.holder property alias count: grid.count signal albumCoverClicked(string album, string artist) signal albumCoverPressed(string album, string artist) signal bgClicked() MouseArea { anchors.fill: parent onClicked: bgClicked() } Albums { id: _albumsList } Maui.BaseModel { id: _albumsModel list: _albumsList } Maui.GridView { id: grid onAreaClicked: bgClicked() adaptContent: true anchors.fill: parent topMargin: Maui.Style.space.big itemSize: albumCoverSize holder.visible: count === 0 model: _albumsModel delegate: Item { height: grid.cellHeight width: grid.cellWidth property bool isCurrentItem: GridView.isCurrentItem BabeAlbum { id: albumDelegate anchors.centerIn: parent albumRadius: albumCoverRadius albumCard: albumCardVisible padding: Maui.Style.space.small height: parent.height width: height isCurrentItem: parent.isCurrentItem label1.text: model.album ? model.album : model.artist label2.text: model.artist && model.album ? model.artist : "" image.source: model.artwork ? model.artwork : "qrc:/assets/cover.png" Connections { target: albumDelegate onClicked: { var album = _albumsList.get(index).album var artist = _albumsList.get(index).artist albumCoverClicked(album, artist) grid.currentIndex = index } onPressAndHold: { var album = grid.model.get(index).album var artist = grid.model.get(index).artist albumCoverPressed(album, artist) } } } } } } diff --git a/view_models/BabeList.qml b/view_models/BabeList.qml index 8e626eb..9d45384 100644 --- a/view_models/BabeList.qml +++ b/view_models/BabeList.qml @@ -1,32 +1,35 @@ -import QtQuick 2.12 -import QtQuick.Controls 2.12 +import QtQuick 2.10 +import QtQuick.Controls 2.10 import QtQuick.Layouts 1.3 import org.kde.kirigami 2.6 as Kirigami import org.kde.mauikit 1.0 as Maui Maui.Page { id: control property alias listView : babeList.listView property alias model : babeList.model property alias delegate : babeList.delegate property alias count : babeList.count property alias currentIndex : babeList.currentIndex property alias currentItem : babeList.currentItem property alias holder : babeList.holder property alias section : babeList.section property bool wasPulled : false signal pulled() Maui.ListBrowser { id: babeList anchors.fill: parent holder.visible: count === 0 topMargin: Maui.Style.space.medium + listView.headerPositioning: ListView.PullBackHeader + Kirigami.Theme.colorSet: Kirigami.Theme.Window + Kirigami.Theme.inherit: false } } diff --git a/view_models/BabeTable/BabeTable.qml b/view_models/BabeTable/BabeTable.qml index 1953ecb..cf98e04 100644 --- a/view_models/BabeTable/BabeTable.qml +++ b/view_models/BabeTable/BabeTable.qml @@ -1,495 +1,494 @@ import QtQuick 2.12 import QtQuick.Controls 2.12 import QtQuick.Layouts 1.3 import org.kde.kirigami 2.7 as Kirigami import org.kde.mauikit 1.0 as Maui import TracksList 1.0 import "../../utils/Player.js" as Player import "../../utils/Help.js" as H import "../../db/Queries.js" as Q import ".." BabeList { id: control // cacheBuffer : 300 property alias list : _tracksList property alias listModel : _tracksModel property alias removeDialog : _removeDialog property bool trackNumberVisible property bool coverArtVisible : false property bool allowMenu: true property bool group : false property alias contextMenu : contextMenu property alias contextMenuItems : contextMenu.contentData property alias playAllBtn : playAllBtn property alias appendBtn : appendBtn signal rowClicked(int index) signal rowDoubleClicked(int index) signal rowPressed(int index) signal quickPlayTrack(int index) signal queueTrack(int index) signal appendTrack(int index) signal artworkDoubleClicked(int index) signal playAll() signal appendAll() focus: true listView.spacing: Maui.Style.space.small * (Kirigami.Settings.isMobile ? 1.4 : 1.2) headBar.leftContent: [ ToolButton { id : playAllBtn // text: qsTr("Play all") icon.name : "media-playlist-play" onClicked: playAll() }, ToolButton { id: appendBtn // text: qsTr("Append") icon.name : "media-playlist-append"//"media-repeat-track-amarok" onClicked: appendAll() }] headBar.rightContent: [ ToolButton { icon.name: "item-select" onClicked: selectionMode = !selectionMode checkable: false checked: selectionMode }, Maui.ToolButtonMenu { id: sortBtn icon.name: "view-sort" - + visible: listView.count > 2 MenuItem { text: qsTr("Title") checkable: true checked: list.sortBy === Tracks.TITLE onTriggered: list.sortBy = Tracks.TITLE autoExclusive: true } MenuItem { text: qsTr("Track") checkable: true checked: list.sortBy === Tracks.TRACK onTriggered: list.sortBy = Tracks.TRACK autoExclusive: true } MenuItem { text: qsTr("Artist") checkable: true checked: list.sortBy === Tracks.ARTIST onTriggered: list.sortBy = Tracks.ARTIST autoExclusive: true } MenuItem { text: qsTr("Album") checkable: true checked: list.sortBy === Tracks.ALBUM onTriggered: list.sortBy = Tracks.ALBUM autoExclusive: true } MenuItem { text: qsTr("Most played") checkable: true checked: list.sortBy === Tracks.COUNT onTriggered: list.sortBy = Tracks.COUNT autoExclusive: true } MenuItem { text: qsTr("Rate") checkable: true checked: list.sortBy === Tracks.RATE onTriggered: list.sortBy = Tracks.RATE autoExclusive: true } MenuItem { text: qsTr("Favorite") checkable: true checked: list.sortBy === Tracks.FAV onTriggered: list.sortBy = Tracks.FAV autoExclusive: true } MenuItem { text: qsTr("Release date") checkable: true checked: list.sortBy === Tracks.RELEASEDATE onTriggered: list.sortBy = Tracks.RELEASEDATE autoExclusive: true } MenuItem { text: qsTr("Add date") checkable: true checked: list.sortBy === Tracks.ADDDATE onTriggered: list.sortBy = Tracks.ADDDATE autoExclusive: true } MenuSeparator{} MenuItem { text: qsTr("Group") checkable: true checked: group onTriggered: { group = !group groupBy() } } }, ToolButton { id: _filterButton icon.name: "view-filter" checkable: true + visible: listView.count > 10 } ] -// listView.headerPositioning: ListView.PullBackHeader + // listView.headerPositioning: ListView.PullBackHeader listView.header: Maui.ToolBar { + Kirigami.Theme.backgroundColor: control.Kirigami.Theme.backgroundColor visible: _filterButton.checked width: control.width position: ToolBar.Header + z: listView.z + 9 middleContent: Maui.TextField { Layout.fillWidth: true - } - } Maui.Dialog { id: _removeDialog property int index title: qsTr("Remove track") message: qsTr("You can delete the file from your computer or remove it from your collection") rejectButton.text: qsTr("Delete") acceptButton.text: qsTr("Remove") page.padding: Maui.Style.space.huge onAccepted: { list.remove(listView.currentIndex) close() } onRejected: { if(Maui.FM.removeFile(list.get(index).url)) list.remove(listView.currentIndex) close() } } TableMenu { id: contextMenu MenuSeparator {} MenuItem { text: qsTr("Go to Artist") onTriggered: goToArtist() } MenuItem { text: qsTr("Go to Album") onTriggered: goToAlbum() } onFavClicked: { list.fav(listView.currentIndex, !(list.get(listView.currentIndex).fav == "1")) } onQueueClicked: Player.queueTracks([list.get(listView.currentIndex)]) onPlayClicked: quickPlayTrack(listView.currentIndex) onAppendClicked: appendTrack(listView.currentIndex) onSaveToClicked: { playlistDialog.tracks = [list.get(listView.currentIndex).url] playlistDialog.open() } onOpenWithClicked: Maui.FM.openLocation([list.get(listView.currentIndex).url]) onRemoveClicked: { _removeDialog.index= listView.currentIndex _removeDialog.open() } onRateClicked: { list.rate(listView.currentIndex, rate); } onColorClicked: { list.color(listView.currentIndex, color); } onInfoClicked: { infoView.show(list.get(listView.currentIndex)) } onCopyToClicked: { cloudView.list.upload(listView.currentIndex) } onShareClicked: { const url = list.get(listView.currentIndex).url if(isAndroid) { Maui.Android.shareDialog(url) return } _dialogLoader.sourceComponent = _shareDialogComponent root.dialog.show([url]) } } section.criteria: ViewSection.FullString section.delegate: Maui.LabelDelegate { id: _sectionDelegate label: section isSection: true width: control.width Kirigami.Theme.backgroundColor: "#333" Kirigami.Theme.textColor: "#fafafa" background: Rectangle { color: Kirigami.Theme.backgroundColor } } - Maui.BaseModel { id: _tracksModel list: _tracksList } Tracks { id: _tracksList onSortByChanged: if(control.group) control.groupBy() } model: _tracksModel // property alias animBabe: delegate.animBabe delegate: TableDelegate { id: delegate width: listView.width number : trackNumberVisible ? true : false coverArt : coverArtVisible ? (control.width > 300) : coverArtVisible onPressAndHold: if(Kirigami.Settings.isMobile && allowMenu) openItemMenu(index) onRightClicked: if(allowMenu) openItemMenu(index) onLeftEmblemClicked: H.addToSelection(list.get(index)) isSelected: selectionBar.contains(model.url) onClicked: { currentIndex = index if(selectionMode) { H.addToSelection(list.get(listView.currentIndex)) return } if(Kirigami.Settings.isMobile) rowClicked(index) } onDoubleClicked: { currentIndex = index if(!Kirigami.Settings.isMobile) rowClicked(index) } onPlay: { currentIndex = index quickPlayTrack(index) } onAppend: { currentIndex = index appendTrack(index) } onArtworkCoverClicked: { currentIndex = index goToAlbum() } Connections { target: selectionBar onPathRemoved: { if(path === model.url) delegate.isSelected = false } onPathAdded: { if(path === model.url) delegate.isSelected = true } onCleared: delegate.isSelected = false - } } function openItemMenu(index) { currentIndex = index contextMenu.rate = list.get(currentIndex).rate contextMenu.fav = list.get(currentIndex).fav == "1" contextMenu.popup() rowPressed(index) } function saveList() { var trackList = [] if(listView.count > 0) { for(var i = 0; i < list.count; ++i) trackList.push(list.get(i).url) playlistDialog.tracks = trackList playlistDialog.open() } } function queueList() { var trackList = [] if(listView.count > 0) { for(var i = 0; i < listView.count; ++i) trackList.push(list.get(i)) Player.queueTracks(trackList) } } function goToAlbum() { swipeView.currentIndex = viewsIndex.albums const item = list.get(listView.currentIndex) - albumsView.populateTable(item.album, item.artist) + swipeView.currentItem.item.populateTable(item.album, item.artist) contextMenu.close() } function goToArtist() { swipeView.currentIndex = viewsIndex.artists const item = list.get(listView.currentIndex) - artistsView.populateTable(undefined, item.artist) + swipeView.currentItem.item.populateTable(undefined, item.artist) contextMenu.close() } function groupBy() { var prop = "undefined" if(group) switch(list.sortBy) { case Tracks.TITLE: prop = "title" break case Tracks.ARTIST: prop = "artist" break case Tracks.ALBUM: prop = "album" break case Tracks.RATE: prop = "rate" break case Tracks.FAV: prop = "fav" break case Tracks.ADDDATE: prop = "adddate" break case Tracks.RELEASEDATE: prop = "releasedate" break; case Tracks.COUNT: prop = "count" break } section.property = prop } } diff --git a/view_models/BabeTable/PlaylistDialog.qml b/view_models/BabeTable/PlaylistDialog.qml index 7ef5f47..7245dd9 100644 --- a/view_models/BabeTable/PlaylistDialog.qml +++ b/view_models/BabeTable/PlaylistDialog.qml @@ -1,106 +1,106 @@ import QtQuick 2.0 -import QtQuick.Controls 2.2 +import QtQuick.Controls 2.10 import org.kde.kirigami 2.2 as Kirigami import org.kde.mauikit 1.0 as Maui import QtQuick.Layouts 1.3 import "../../view_models" import "../../utils/Player.js" as Player import "../../db/Queries.js" as Q Maui.Dialog { title: "Add "+ tracks.length +" tracks to..." property var tracks : [] maxHeight: 400 * Maui.Style.unit page.padding: Maui.Style.space.medium ColumnLayout { anchors.fill: parent BabeList { id: playlistsList Layout.fillHeight: true Layout.fillWidth: true headBar.visible: false holder.title: qsTr("There's not playlists") holder.body: qsTr("Create a new one and start adding tracks to it") model: playlistsView.playlistModel delegate: Maui.ListDelegate { id: delegate label: model.playlist Connections { target: delegate onClicked: playlistsList.currentIndex = index onPressAndHold: { playlistsList.currentIndex = index insert() } } } } Maui.TextField { Layout.fillWidth: true id: newPlaylistField color: Kirigami.Theme.textColor placeholderText: qsTr("New playlist") onAccepted: { addPlaylist() playlistsView.playlistList.addTrack(playlistsList.listView.currentIndex, tracks) clear() } actions.data: ToolButton { icon.name: "checkbox" icon.color: Kirigami.Theme.textColor onClicked: addPlaylist() } } } onAccepted: { if(newPlaylistField.text.length) addPlaylist() insert() } function insert() { playlistsView.playlistList.addTrack(playlistsList.listView.currentIndex, tracks) close() } function addPlaylist() { if (newPlaylistField.text) { var title = newPlaylistField.text.trim() if( playlistsView.playlistList.insertAt(title, 0)) { playlistsList.listView.currentIndex = 0 playlistsList.listView.positionViewAtBeginning() } newPlaylistField.clear() } } } diff --git a/view_models/BabeTable/TableDelegate.qml b/view_models/BabeTable/TableDelegate.qml index ff32a4f..432c111 100644 --- a/view_models/BabeTable/TableDelegate.qml +++ b/view_models/BabeTable/TableDelegate.qml @@ -1,103 +1,103 @@ -import QtQuick 2.9 +import QtQuick 2.10 import QtQuick.Layouts 1.3 -import QtQuick.Controls 2.3 +import QtQuick.Controls 2.10 import QtGraphicalEffects 1.0 import org.kde.kirigami 2.7 as Kirigami import org.kde.mauikit 1.0 as Maui import "../../view_models" import "../../utils/Help.js" as H Maui.ItemDelegate { id: control isCurrentItem: ListView.isCurrentItem || isSelected property bool number : false property bool coverArt : false property bool showEmblem: true property bool keepEmblemOverlay: selectionMode property bool isSelected : false property string trackMood : model.color readonly property color bgColor : Kirigami.Theme.backgroundColor readonly property int altHeight : Maui.Style.rowHeight * 1.4 readonly property bool sameAlbum : { if(coverArt) { if(list.get(index-1)) { if(list.get(index-1).album === album && list.get(index-1).artist === artist) true else false }else false }else false } width: parent.width height: sameAlbum ? Maui.Style.rowHeight : altHeight padding: 0 rightPadding: leftPadding leftPadding: Maui.Style.space.small signal play() signal append() signal leftClicked() signal leftEmblemClicked(int index) signal artworkCoverClicked() signal artworkCoverDoubleClicked() Kirigami.Theme.backgroundColor: trackMood.length > 0 ? Qt.tint(bgColor, Qt.rgba(Qt.lighter(trackMood, 1.3).r, Qt.lighter(trackMood, 1.3).g, Qt.lighter(trackMood, 1.3).b, 0.3)): bgColor function rate(stars) { trackRating.text = stars } RowLayout { anchors.fill: parent Item { Layout.fillHeight: true Layout.preferredWidth: _leftEmblemIcon.height + Maui.Style.space.small visible: (control.keepEmblemOverlay || control.isSelected) && control.showEmblem Maui.Badge { id: _leftEmblemIcon anchors.centerIn: parent iconName: control.isSelected ? "list-remove" : "list-add" onClicked: control.leftEmblemClicked(index) size: Maui.Style.iconSizes.small } } Maui.ListItemTemplate { id: _template Layout.fillWidth: true Layout.fillHeight: true isCurrentItem: control.isCurrentItem iconSizeHint: height - Maui.Style.space.small label1.text: control.number ? model.track + ". " + model.title : model.title label2.text: model.artist + " | " + model.album label2.visible: control.coverArt ? !control.sameAlbum : true label3.text: model.fav ? (model.fav == "1" ? "\uf2D1" : "") : "" label3.font.family: "Material Design Icons" label4.font.family: "Material Design Icons" label4.text: model.rate ? H.setStars(model.rate) : "" iconVisible: !control.sameAlbum && control.coverArt imageSource: model.artwork ? model.artwork : "qrc:/assets/cover.png" } } } diff --git a/view_models/BabeTable/TableMenu.qml b/view_models/BabeTable/TableMenu.qml index 6c410f6..6b73337 100644 --- a/view_models/BabeTable/TableMenu.qml +++ b/view_models/BabeTable/TableMenu.qml @@ -1,286 +1,286 @@ import QtQuick 2.0 -import QtQuick 2.9 -import QtQuick.Controls 2.2 +import QtQuick 2.10 +import QtQuick.Controls 2.10 import QtQuick.Layouts 1.3 import "../../utils" import ".." import "../../utils/Help.js" as H import org.kde.mauikit 1.0 as Maui import org.kde.kirigami 2.6 as Kirigami Menu { id: control width: Maui.Style.unit * 200 property int rate : 0 property bool fav : false property string starColor : "#FFC107" property string starReg : Kirigami.Theme.textColor property string starIcon: "draw-star" signal removeClicked() signal favClicked() signal queueClicked() signal playClicked() signal saveToClicked() signal openWithClicked() signal editClicked() signal shareClicked() signal selectClicked() signal rateClicked(int rate) signal colorClicked(color color) signal infoClicked() signal copyToClicked() signal appendClicked() property alias menuItem : control.contentData MenuItem { text: qsTr("Select...") onTriggered: { H.addToSelection(list.get(listView.currentIndex)) if(Kirigami.Settings.isMobile) selectionMode = true contextMenu.close() } } MenuSeparator {} MenuItem { text: qsTr("Play") onTriggered: { playClicked() close() } } MenuItem { text: qsTr("Queue") onTriggered: { queueClicked() close() } } MenuItem { text: qsTr("Append") onTriggered: { appendClicked() close() } } MenuSeparator{} MenuItem { text: !fav ? qsTr("Fav it"): qsTr("UnFav it") onTriggered: { favClicked() close() } } MenuItem { text: qsTr("Add to") onTriggered: { saveToClicked() close() } } MenuSeparator {} MenuItem { text: qsTr("Share...") onTriggered: { shareClicked() close() } } // MenuItem // { // visible: Maui.App.handleAccounts // text: qsTr("Copy to cloud") // onTriggered: // { // copyToClicked() // close() // } // } MenuItem { text: qsTr("Show in folder") visible: !isAndroid onTriggered: { openWithClicked() close() } } MenuSeparator {} MenuItem { visible: false text: qsTr("Edit.") onTriggered: { editClicked() close() } } // Maui.MenuItem // { // text: qsTr("Info...") // onTriggered: // { // infoClicked() // close() // } // } MenuItem { text: qsTr("Remove") Kirigami.Theme.textColor: Kirigami.Theme.negativeTextColor onTriggered: { removeClicked() // listModel.remove(list.currentIndex) close() } } MenuSeparator {} MenuItem { id: starsRow width: parent.width height: Maui.Style.iconSizes.medium + Maui.Style.space.small RowLayout { anchors.fill: parent ToolButton { Layout.fillWidth: true Layout.fillHeight: true icon.name: starIcon icon.width: Maui.Style.iconSizes.medium icon.color: rate >= 1 ? starColor :starReg onClicked: { rate = 1 rateClicked(rate) close() } } ToolButton { Layout.fillWidth: true Layout.fillHeight: true icon.width: Maui.Style.iconSizes.medium icon.name: starIcon icon.color: rate >= 2 ? starColor :starReg onClicked: { rate = 2 rateClicked(rate) close() } } ToolButton { Layout.fillWidth: true Layout.fillHeight: true icon.width: Maui.Style.iconSizes.medium icon.name: starIcon icon.color: rate >= 3 ? starColor :starReg onClicked: { rate = 3 rateClicked(rate) close() } } ToolButton { Layout.fillWidth: true Layout.fillHeight: true icon.width: Maui.Style.iconSizes.medium icon.name: starIcon icon.color: rate >= 4 ? starColor :starReg onClicked: { rate = 4 rateClicked(rate) close() } } ToolButton { Layout.fillWidth: true Layout.fillHeight: true icon.width: Maui.Style.iconSizes.medium icon.name: starIcon icon.color: rate >= 5 ? starColor :starReg onClicked: { rate = 5 rateClicked(rate) close() } } } } MenuItem { id: colorsRow width: parent.width height: Maui.Style.iconSizes.medium + Maui.Style.space.small ColorTagsBar { anchors.fill: parent onColorClicked: { control.colorClicked(color) control.close() } } } } diff --git a/view_models/ColorTagsBar.qml b/view_models/ColorTagsBar.qml index 0b8d7fc..f5d783c 100644 --- a/view_models/ColorTagsBar.qml +++ b/view_models/ColorTagsBar.qml @@ -1,115 +1,115 @@ -import QtQuick 2.9 +import QtQuick 2.10 import QtQuick.Layouts 1.3 -import QtQuick.Controls 2.2 +import QtQuick.Controls 2.10 import org.kde.mauikit 1.0 as Maui Item { property int recSize: Maui.Style.iconSizes.small readonly property int recRadius : recSize*0.05 signal colorClicked(string color) RowLayout { width: parent.width anchors.fill: parent anchors.centerIn: parent ToolButton { Layout.fillHeight: true Layout.fillWidth: true Layout.alignment: Qt.AlignCenter flat: true Rectangle { anchors.centerIn: parent width: recSize height: recSize color: vvave.moodColor(0) radius: recRadius border.color: color border.width: 1 } onClicked: colorClicked(vvave.moodColor(0)) } ToolButton { Layout.fillHeight: true Layout.fillWidth: true Layout.alignment: Qt.AlignCenter flat: true Rectangle { anchors.centerIn: parent width: recSize height: recSize color: vvave.moodColor(1) radius: recRadius border.color: color border.width: 1 } onClicked: colorClicked(vvave.moodColor(1)) } ToolButton { Layout.fillHeight: true Layout.fillWidth: true Layout.alignment: Qt.AlignCenter flat: true Rectangle { anchors.centerIn: parent width: recSize height: recSize color: vvave.moodColor(2) radius: recRadius border.color: color border.width: 1 } onClicked: colorClicked(vvave.moodColor(2)) } ToolButton { Layout.fillHeight: true Layout.fillWidth: true Layout.alignment: Qt.AlignCenter flat: true Rectangle { anchors.centerIn: parent width: recSize height: recSize color: vvave.moodColor(3) radius: recRadius border.color: color border.width: 1 } onClicked: colorClicked(vvave.moodColor(3)) } ToolButton { Layout.fillHeight: true Layout.fillWidth: true Layout.alignment: Qt.AlignCenter flat: true Rectangle { anchors.centerIn: parent width: recSize height: recSize color: vvave.moodColor(4) radius: recRadius border.color: color border.width: 1 } onClicked: colorClicked(vvave.moodColor(4)) } } } diff --git a/widgets/AlbumsView.qml b/widgets/AlbumsView.qml index 710f06d..6ee37ce 100644 --- a/widgets/AlbumsView.qml +++ b/widgets/AlbumsView.qml @@ -1,240 +1,240 @@ -import QtQuick 2.9 -import QtQuick.Controls 2.2 +import QtQuick 2.10 +import QtQuick.Controls 2.10 import QtQuick.Layouts 1.3 import "../view_models/BabeGrid" import "../view_models/BabeTable" import "../db/Queries.js" as Q import "../utils/Help.js" as H import org.kde.kirigami 2.6 as Kirigami import org.kde.mauikit 1.0 as Maui import TracksList 1.0 import AlbumsList 1.0 BabeGrid { id: albumsViewGrid property string currentAlbum: "" property string currentArtist: "" property var tracks: [] property alias table : albumsViewTable // property alias tagBar : tagBar signal rowClicked(var track) signal playTrack(var track) signal queueTrack(var track) signal appendTrack(var track) signal appendAll(string album, string artist) signal playAll(string album, string artist) // signal albumCoverClicked(string album, string artist) signal albumCoverPressedAndHold(string album, string artist) visible: true // topPadding: Maui.Style.space.large onAlbumCoverPressed: albumCoverPressedAndHold(album, artist) headBar.visible: false // headBar.rightContent: Kirigami.ActionToolBar // { // Layout.fillWidth: true // actions: [ // Kirigami.Action // { // id: sortBtn // icon.name: "view-sort" // text: qsTr("Sort") // Kirigami.Action // { // text: qsTr("Artist") // checkable: true // checked: list.sortBy === Albums.ARTIST // onTriggered: list.sortBy = Albums.ARTIST // } // Kirigami.Action // { // text: qsTr("Album") // checkable: true // checked: list.sortBy === Albums.ALBUM // onTriggered: list.sortBy = Albums.ALBUM // } // Kirigami.Action // { // text: qsTr("Release date") // checkable: true // checked: list.sortBy === Albums.RELEASEDATE // onTriggered: list.sortBy = Albums.RELEASEDATE // } // Kirigami.Action // { // text: qsTr("Add date") // checkable: true // checked: list.sortBy === Albums.ADDDATE // onTriggered: list.sortBy = Albums.ADDDATE // } // } // ] // } // headBar.rightContent: [ // ToolButton // { // id: appendBtn // visible: headBar.visible && albumsViewGrid.count > 0 // anim : true // icon.name : "media-playlist-append"//"media-repeat-track-amarok" // onClicked: appendAll() // } // ] Maui.Dialog { id: albumDialog parent: parent maxHeight: maxWidth maxWidth: Maui.Style.unit * 600 widthHint: 0.9 heightHint: 0.9 defaultButtons: false page.padding: 0 ColumnLayout { id: albumFilter anchors.fill: parent spacing: 0 BabeTable { id: albumsViewTable Layout.fillHeight: true Layout.fillWidth: true trackNumberVisible: true headBar.visible: true coverArtVisible: true focus: true list.sortBy: Tracks.TRACK holder.emoji: "qrc:/assets/dialog-information.svg" holder.isMask: false holder.title : "Oops!" holder.body: "This list is empty" holder.emojiSize: Maui.Style.iconSizes.huge onRowClicked: { albumsViewGrid.rowClicked(list.get(index)) } onQuickPlayTrack: { albumsViewGrid.playTrack(list.get(index)) } onQueueTrack: { albumsViewGrid.queueTrack(list.get(index)) } onAppendTrack: { albumsViewGrid.appendTrack(list.get(index)) } onPlayAll: { albumDialog.close() albumsViewGrid.playAll(currentAlbum, currentArtist) } onAppendAll: { albumDialog.close() albumsViewGrid.appendAll(currentAlbum, currentArtist) } } // Maui.TagsBar // { // id: tagBar // visible:false // Layout.fillWidth: true // allowEditMode: false // onTagClicked: H.searchFor("tag:"+tag) // } } } function populateTable(album, artist) { console.log("PAPULATE ALBUMS VIEW") albumDialog.open() var query = "" var tagq = "" currentAlbum = album === undefined ? "" : album currentArtist= artist if(album && artist) { query = Q.GET.albumTracks_.arg(album) query = query.arg(artist) albumsViewTable.title = album tagq = Q.GET.albumTags_.arg(album) }else if(artist && album === undefined) { query = Q.GET.artistTracks_.arg(artist) albumsViewTable.title = artist tagq = Q.GET.artistTags_.arg(artist) } albumsViewTable.list.query = query /*dunoooo*/ // if(tracks.length > 0) // { // tagq = tagq.arg(artist) // var tags = bae.get(tagq) // console.log(tagq, "TAGS", tags) // tagBar.populate(tags) // } } function filter(tracks) { var matches = [] for(var i = 0; i 0 ListView { id: _headList anchors.fill: parent anchors.margins: Maui.Style.space.medium spacing: Maui.Style.space.medium orientation: ListView.Horizontal model: list.artists delegate: BabeAlbum { height: 120 width: height albumRadius: Maui.Style.radiusV isCurrentItem: ListView.isCurrentItem anchors.verticalCenter: parent.verticalCenter showLabels: true label1.text: modelData.album ? modelData.album : modelData.artist label2.text: modelData.artist && modelData.album ? modelData.artist : "" image.source: modelData.artwork ? modelData.artwork : "qrc:/assets/cover.png" } } } listView.headerPositioning: ListView.PullBackHeader delegate: TableDelegate { id: delegate width: parent.width number : false coverArt : false onClicked: { _listView.currentIndex = index // if(selectionMode) // { // H.addToSelection(control.list.get(_listView.currentIndex)) // return // } list.getFileUrl(index); // if(isMobile) // rowClicked(index) } // onDoubleClicked: // { // currentIndex = index // if(!isMobile) // rowClicked(index) // } // onPlay: // { // currentIndex = index // if(Maui.FM.fileExists("file://" + _cloudList.get(index).thumbnail)) // { // quickPlayTrack(index) // }else // { // _cloudList.requestFile(index) // } // } // onArtworkCoverClicked: // { // currentIndex = index // goToAlbum() // } } } } diff --git a/widgets/FloatingDisk.qml b/widgets/FloatingDisk.qml index ba9df48..f852c02 100644 --- a/widgets/FloatingDisk.qml +++ b/widgets/FloatingDisk.qml @@ -1,178 +1,178 @@ -import QtQuick 2.9 -import QtQuick.Controls 2.2 +import QtQuick 2.10 +import QtQuick.Controls 2.10 import QtQuick.Layouts 1.3 import QtGraphicalEffects 1.0 import org.kde.kirigami 2.7 as Kirigami import org.kde.mauikit 1.0 as Maui Item { id: control Kirigami.Theme.inherit: false Kirigami.Theme.colorSet: Kirigami.Theme.Complementary visible: opacity > 0.3 height: Maui.Style.iconSizes.large * 1.2 width: height x: root.footBar.x + Maui.Style.space.medium y: parent.height - height - Maui.Style.space.medium parent: ApplicationWindow.overlay z: parent.z + 1 ToolTip.delay: 1000 ToolTip.timeout: 5000 ToolTip.visible: _mouseArea.containsMouse && !Kirigami.Settings.isMobile ToolTip.text: currentTrack.title + " - " + currentTrack.artist Connections { target: mainPlaylist.table onCountChanged: { anim.run(control.y) } } NumberAnimation on y { id: anim property int startY running: false from : control.y to: control.y - 20 duration: 250 loops: 2 onStopped: { control.y = startY } function run(y) { if(y < 10) return startY = y anim.start() anim.running = true } } MouseArea { id: _mouseArea anchors.fill: parent hoverEnabled: true drag.target: parent drag.axis: Drag.XAndYAxis drag.minimumX: 0 drag.maximumX: root.width drag.minimumY: 0 drag.maximumY: root.height onClicked: _drawer.visible = true Rectangle { id: diskBg anchors.centerIn: parent height: parent.height width: height // border.color: Qt.tint(Kirigami.Theme.textColor, Qt.rgba(Kirigami.Theme.backgroundColor.r, Kirigami.Theme.backgroundColor.g, Kirigami.Theme.backgroundColor.b, 0.7)) color: "white" radius: Math.min(width, height) Image { id: miniArtwork focus: true anchors.fill: parent anchors.margins: Maui.Style.space.tiny anchors.centerIn: parent source: { if (currentArtwork) (currentArtwork.length > 0 && currentArtwork !== "NONE") ? currentArtwork: "qrc:/assets/cover.png" else "qrc:/assets/cover.png" } fillMode: Image.PreserveAspectFit cache: false antialiasing: true layer.enabled: true layer.effect: OpacityMask { maskSource: Item { width: miniArtwork.width height: miniArtwork.height Rectangle { anchors.centerIn: parent width: miniArtwork.adapt ? miniArtwork.width : Math.min( miniArtwork.width, miniArtwork.height) height: miniArtwork.adapt ? miniArtwork.height : width radius: Math.min(width, height) } } } } } DropShadow { anchors.fill: diskBg horizontalOffset: 0 verticalOffset: 0 radius: 8.0 samples: 17 color: "#80000000" source: diskBg } } RotationAnimator on rotation { from: 0 to: 360 duration: 5000 loops: Animation.Infinite running: isPlaying } // Rectangle // { // anchors.centerIn: parent // width: parent.width * 0.5 // height: width // radius: height // color: "transparent" // ShaderEffectSource // { // anchors.fill: parent // sourceItem: root // sourceRect:Qt.rect((control.x), // (control.y), // parent.width, // parent.height) // hideSource: true // } // } } diff --git a/widgets/FocusView.qml b/widgets/FocusView.qml index 6b43579..baf971f 100644 --- a/widgets/FocusView.qml +++ b/widgets/FocusView.qml @@ -1,369 +1,367 @@ import QtQuick 2.12 import QtQuick.Controls 2.12 import QtQuick.Layouts 1.3 import org.kde.kirigami 2.7 as Kirigami import org.kde.mauikit 1.0 as Maui import "../utils/Player.js" as Player import QtGraphicalEffects 1.0 Rectangle { id: control visible: focusView parent: ApplicationWindow.overlay anchors.fill: parent z: parent.z + 99999 color: Kirigami.Theme.backgroundColor Kirigami.Theme.inherit: false Kirigami.Theme.colorSet: Kirigami.Theme.View focus: true Component.onCompleted: { - _drawer.close() + _drawer.visible = false forceActiveFocus() } Keys.onBackPressed: { focusView = false event.accepted = true } Shortcut { sequence: StandardKey.Back onActivated: focusView = false } ColumnLayout { anchors.fill: parent anchors.margins: Maui.Style.space.big ListView { id: _listView Layout.fillWidth: true Layout.preferredHeight: parent.height* 0.4 orientation: ListView.Horizontal clip: true focus: true interactive: true currentIndex: currentTrackIndex spacing: Maui.Style.space.medium cacheBuffer: control.width * 1 onCurrentIndexChanged: positionViewAtIndex(currentIndex, ListView.Center) highlightFollowsCurrentItem: true highlightMoveDuration: 0 snapMode: ListView.SnapToOneItem model: mainPlaylist.listModel highlightRangeMode: ListView.StrictlyEnforceRange keyNavigationEnabled: true keyNavigationWraps : true onMovementEnded: { var index = indexAt(contentX, contentY) if(index !== currentTrackIndex) Player.playAt(index) } Rectangle { visible: (_listView.currentIndex > 0) && (_listView.count > 1) height: Maui.Style.iconSizes.small width : height radius: height color: Kirigami.Theme.textColor opacity: 0.4 anchors.left: parent.left anchors.verticalCenter: parent.verticalCenter } Rectangle { visible: (_listView.currentIndex < _listView.count - 1) && (_listView.count > 1) height: Maui.Style.iconSizes.small width : height radius: height color: Kirigami.Theme.textColor opacity: 0.4 anchors.right: parent.right anchors.verticalCenter: parent.verticalCenter } delegate: Item { id: _delegate height: _listView.height width: _listView.width Rectangle { id: _bg - width: parent.width * 0.7 + width: parent.height * 0.7 height: width anchors.centerIn: parent radius: Maui.Style.radiusV color: Kirigami.Theme.textColor } DropShadow { anchors.fill: _bg horizontalOffset: 0 verticalOffset: 0 radius: 8.0 samples: 17 color: "#80000000" source: _bg } Image { id: _image - width: parent.width * 0.7 + width: parent.height * 0.7 height: width anchors.centerIn: parent - sourceSize.width: height sourceSize.height: height - fillMode: Image.PreserveAspectFit antialiasing: false smooth: true asynchronous: true source: model.artwork ? model.artwork : "qrc:/assets/cover.png" onStatusChanged: { if (status == Image.Error) source = "qrc:/assets/cover.png"; } layer.enabled: true layer.effect: OpacityMask { maskSource: Item { width: _image.width height: _image.height Rectangle { anchors.centerIn: parent width: _image.adapt ? _image.width : Math.min(_image.width, _image.height) height: _image.adapt ? _image.height : width radius: Maui.Style.radiusV } } } } } } RowLayout { Layout.fillWidth: true Layout.preferredHeight: Maui.Style.toolBarHeight ToolButton { icon.name: "view-list-details" onClicked: focusView = false Layout.alignment: Qt.AlignCenter } ColumnLayout { Layout.fillWidth: true Layout.fillHeight: true Layout.alignment: Qt.AlignCenter spacing: 0 Label { id: _label1 visible: text.length Layout.fillWidth: true Layout.fillHeight: false verticalAlignment: Qt.AlignVCenter horizontalAlignment: Qt.AlignHCenter text: currentTrack.title elide: Text.ElideMiddle wrapMode: Text.NoWrap color: control.Kirigami.Theme.textColor font.weight: Font.Normal font.pointSize: Maui.Style.fontSizes.big } Label { id: _label2 visible: text.length Layout.fillWidth: true Layout.fillHeight: false verticalAlignment: Qt.AlignVCenter horizontalAlignment: Qt.AlignHCenter text: currentTrack.artist elide: Text.ElideMiddle wrapMode: Text.NoWrap color: control.Kirigami.Theme.textColor font.weight: Font.Normal font.pointSize: Maui.Style.fontSizes.medium opacity: 0.7 } } ToolButton { icon.name: "documentinfo" onClicked: focusView = false Layout.alignment: Qt.AlignCenter } } RowLayout { Layout.fillWidth: true Label { visible: text.length Layout.fillWidth: true Layout.fillHeight: false verticalAlignment: Qt.AlignVCenter horizontalAlignment: Qt.AlignHCenter text: progressTimeLabel elide: Text.ElideMiddle wrapMode: Text.NoWrap color: control.Kirigami.Theme.textColor font.weight: Font.Normal font.pointSize: Maui.Style.fontSizes.medium opacity: 0.7 } Slider { id: progressBar Layout.fillWidth: true padding: 0 from: 0 to: 1000 value: player.pos spacing: 0 focus: true onMoved: { player.pos = value } } Label { visible: text.length Layout.fillWidth: true Layout.fillHeight: false verticalAlignment: Qt.AlignVCenter horizontalAlignment: Qt.AlignHCenter text: player.transformTime(player.duration/1000) elide: Text.ElideMiddle wrapMode: Text.NoWrap color: control.Kirigami.Theme.textColor font.weight: Font.Normal font.pointSize: Maui.Style.fontSizes.medium opacity: 0.7 } } Maui.ToolBar { Layout.preferredHeight: Maui.Style.toolBarHeight * 2 Layout.fillWidth: true position: ToolBar.Footer background: null middleContent: [ ToolButton { id: babeBtnIcon icon.width: Maui.Style.iconSizes.big icon.height: Maui.Style.iconSizes.big icon.name: "love" enabled: currentTrackIndex >= 0 icon.color: currentBabe ? babeColor : Kirigami.Theme.textColor onClicked: if (!mainlistEmpty) { mainPlaylist.list.fav(currentTrackIndex, !(mainPlaylist.list.get(currentTrackIndex).fav == "1")) currentBabe = mainPlaylist.list.get(currentTrackIndex).fav == "1" } }, ToolButton { icon.name: "media-skip-backward" icon.color: Kirigami.Theme.textColor icon.width: Maui.Style.iconSizes.big icon.height: Maui.Style.iconSizes.big onClicked: Player.previousTrack() onPressAndHold: Player.playAt(prevTrackIndex) }, ToolButton { id: playIcon icon.width: Maui.Style.iconSizes.huge icon.height: Maui.Style.iconSizes.huge enabled: currentTrackIndex >= 0 icon.color: Kirigami.Theme.textColor icon.name: isPlaying ? "media-playback-pause" : "media-playback-start" onClicked: player.playing = !player.playing }, ToolButton { id: nextBtn icon.color: Kirigami.Theme.textColor icon.width: Maui.Style.iconSizes.big icon.height: Maui.Style.iconSizes.big icon.name: "media-skip-forward" onClicked: Player.nextTrack() onPressAndHold: Player.playAt(Player.shuffle()) }, ToolButton { id: shuffleBtn icon.width: Maui.Style.iconSizes.big icon.height: Maui.Style.iconSizes.big icon.color: babeColor icon.name: isShuffle ? "media-playlist-shuffle" : "media-playlist-normal" onClicked: { isShuffle = !isShuffle Maui.FM.saveSettings("SHUFFLE", isShuffle, "PLAYBACK") } } ] } } } diff --git a/widgets/FoldersView.qml b/widgets/FoldersView.qml index 9bb15c5..ec484c2 100644 --- a/widgets/FoldersView.qml +++ b/widgets/FoldersView.qml @@ -1,81 +1,81 @@ import QtQuick 2.0 -import QtQuick.Controls 2.2 +import QtQuick.Controls 2.10 import org.kde.mauikit 1.0 as Maui import "../view_models/BabeTable" import "../db/Queries.js" as Q Item { id: control property alias list : _filterList property var tracks : [] property string currentFolder : "" Maui.GridBrowser { id: browser anchors.margins: Maui.Style.space.big anchors.fill: parent showEmblem: false model: ListModel {} onItemClicked: { var item = browser.model.get(index) _filterList.title= item.label currentFolder = item.path filter() _listDialog.open() } } Maui.Holder { anchors.fill: parent visible: !browser.count emoji: "qrc:/assets/MusicCloud.png" isMask: false title : "No Folders!" body: "Add new music to your sources to browse by folders" emojiSize: Maui.Style.iconSizes.huge } Maui.Dialog { id: _listDialog parent: parent maxHeight: maxWidth maxWidth: Maui.Style.unit * 600 defaultButtons: false page.padding: 0 BabeTable { id: _filterList anchors.fill: parent coverArtVisible: true holder.emoji: "qrc:/assets/MusicCloud.png" holder.isMask: false holder.title : "No Tracks!" holder.body: "This source folder seems to be empty!" holder.emojiSize: Maui.Style.iconSizes.huge } } Component.onCompleted: populate() function populate() { browser.model.clear() var folders = vvave.sourceFolders(); if(folders.length > 0) for(var i in folders) browser.model.append(folders[i]) } function filter() { var where = "source = \""+currentFolder+"\"" _filterList.list.query = (Q.GET.tracksWhere_.arg(where)) } } diff --git a/widgets/InfoView/InfoView.qml b/widgets/InfoView/InfoView.qml index 8edeac1..35a46b5 100644 --- a/widgets/InfoView/InfoView.qml +++ b/widgets/InfoView/InfoView.qml @@ -1,193 +1,193 @@ -import QtQuick 2.9 -import QtQuick.Controls 2.2 +import QtQuick 2.10 +import QtQuick.Controls 2.10 import QtQuick.Layouts 1.3 import QtGraphicalEffects 1.0 import org.kde.mauikit 1.0 as Maui import org.kde.kirigami 2.7 as Kirigami import "../../view_models" Maui.Dialog { id: control defaultButtons: false property alias lyricsText : lyricsText property string wikiArtist property string wikiAlbum property string artistHead property int currentView : 0 Kirigami.Theme.backgroundColor: "#333" Kirigami.Theme.textColor: "#fafafa" clip: true SwipeView { id: infoSwipeView anchors.fill: parent currentIndex: currentView Rectangle { color: "transparent" Maui.Holder { id: lyricsHolder visible: lyricsText.text.length > 0 ? false : true message: "Couldn't find the lyrics!" } ScrollView { anchors.fill: parent clip: true contentWidth: lyricsText.width contentHeight: lyricsText.height ScrollBar.horizontal.policy: ScrollBar.AlwaysOff TextEdit { id: lyricsText text: currentTrack.lyrics width: control.width // ensure correct width height: implicitHeight readOnly: true padding: 20 color: "white" font.pointSize: Maui.Style.fontSizes.big horizontalAlignment: Qt.AlignHCenter verticalAlignment: Qt.AlignVCenter textFormat: Text.RichText wrapMode: Text.Wrap // activeFocusOnPress : true // selectByMouse : true // cursorPosition :0 // cursorVisible: true } } } Rectangle { color: "transparent" Maui.Holder { id: wikiHolder visible: wikiAlbumText.visible && wikiArtistText.visible ? false : true message: "Couldn't find the wiki!" } ColumnLayout { width:parent.width height:parent.height // Rectangle // { // width: children.width // height: children.height // anchors.horizontalCenter: parent // Image // { // id: img // width: 100 // height: 100 // fillMode: Image.PreserveAspectFit // source: (artistHead.length>0 && artistHead !== "NONE")? "file://"+encodeURIComponent(artistHead) : "qrc:/assets/cover.png" // layer.enabled: true // layer.effect: OpacityMask // { // maskSource: Item // { // width: img.width // height: img.height // Rectangle // { // anchors.centerIn: parent // width: img.adapt ? img.width : Math.min(img.width, img.height) // height: img.adapt ? img.height : width // radius: Math.min(width, height) // border.color: foregroundColor // border.width: 4 // } // } // } // } // } ScrollView { Layout.fillWidth: true Layout.fillHeight: true clip: true contentWidth: wikiAlbumText.width contentHeight: wikiAlbumText.height ScrollBar.horizontal.policy: ScrollBar.AlwaysOff Text { id: wikiAlbumText width: control.width // ensure correct width padding: 20 text: wikiAlbum visible: wikiAlbum === "NONE" || wikiAlbum.length===0 ? false : true font.pointSize: Maui.Style.fontSizes.big horizontalAlignment: Qt.AlignHCenter textFormat: Text.RichText wrapMode: Text.Wrap } } ScrollView { Layout.fillWidth: true Layout.fillHeight: true clip: true contentWidth: wikiArtistText.width contentHeight: wikiArtistText.height ScrollBar.horizontal.policy: ScrollBar.AlwaysOff Text { id: wikiArtistText width: control.width // ensure correct width padding: 20 text: wikiArtist visible: wikiArtist === "NONE" || wikiArtist.length===0 ? false : true font.pointSize: Maui.Style.fontSizes.big horizontalAlignment: Qt.AlignHCenter textFormat: Text.StyledText wrapMode: Text.Wrap } } } } } function show(track) { control.open() bae.trackLyrics(track.url) } } diff --git a/widgets/InfoView/LyricsView.qml b/widgets/InfoView/LyricsView.qml index 9697f76..3c3a118 100644 --- a/widgets/InfoView/LyricsView.qml +++ b/widgets/InfoView/LyricsView.qml @@ -1,29 +1,29 @@ -import QtQuick 2.9 -import QtQuick.Controls 2.2 +import QtQuick 2.10 +import QtQuick.Controls 2.10 import org.kde.mauikit 1.0 as Maui Item { id: infoRoot anchors.centerIn: parent property string lyrics Rectangle { anchors.fill: parent z: -999 color: backgroundColor } Text { text: lyrics || "Nothing here" color: foregroundColor font.pointSize: Maui.Style.fontSizes.big horizontalAlignment: Qt.AlignHCenter textFormat: Text.StyledText } } diff --git a/widgets/MainPlaylist/AlbumsRoll.qml b/widgets/MainPlaylist/AlbumsRoll.qml index 4da1585..953d2c2 100644 --- a/widgets/MainPlaylist/AlbumsRoll.qml +++ b/widgets/MainPlaylist/AlbumsRoll.qml @@ -1,118 +1,118 @@ -import QtQuick.Controls 2.2 -import QtQuick 2.9 +import QtQuick.Controls 2.10 +import QtQuick 2.10 import QtQuick.Layouts 1.3 import org.kde.kirigami 2.7 as Kirigami import org.kde.mauikit 1.0 as Maui import QtGraphicalEffects 1.0 import "../../view_models/BabeGrid" import "../../utils/Player.js" as Player Maui.ToolBar { id: control visible: !mainlistEmpty padding: 0 height: Maui.Style.toolBarHeight * 1.2 background: Item { Image { id: artworkBg height: parent.height width: parent.width sourceSize.width: parent.width sourceSize.height: parent.height fillMode: Image.PreserveAspectCrop antialiasing: true smooth: true asynchronous: true cache: true source: currentArtwork } FastBlur { id: fastBlur anchors.fill: parent source: artworkBg radius: 100 transparentBorder: false cached: true Rectangle { anchors.fill: parent color: Kirigami.Theme.backgroundColor opacity: 0.8 } } Kirigami.Separator { anchors.top: parent.top anchors.left: parent.left anchors.right: parent.right } } - middleContent: ListView + middleContent: ListView { id: _listView Layout.fillWidth: true Layout.preferredHeight: Maui.Style.toolBarHeight orientation: ListView.Horizontal clip: true focus: true interactive: true currentIndex: currentTrackIndex spacing: Maui.Style.space.medium cacheBuffer: control.width * 1 onCurrentIndexChanged: positionViewAtIndex(currentIndex, ListView.Center) highlightFollowsCurrentItem: true highlightMoveDuration: 0 snapMode: ListView.SnapToOneItem model: mainPlaylist.listModel highlightRangeMode: ListView.StrictlyEnforceRange keyNavigationEnabled: true keyNavigationWraps : true onMovementEnded: { var index = indexAt(contentX, contentY) if(index !== currentTrackIndex) Player.playAt(index) } delegate: Maui.ItemDelegate { id: _delegate height: _listView.height width: _listView.width padding: 0 Kirigami.Theme.inherit: true Maui.ListItemTemplate { anchors.fill: parent iconSizeHint: height - Maui.Style.space.small imageSource: model.artwork ? model.artwork : "qrc:/assets/cover.png" label1.text: model.title label2.text: model.artist + " | " + model.album } onClicked: focusView = true background: null } } } diff --git a/widgets/MainPlaylist/PlaylistMenu.qml b/widgets/MainPlaylist/PlaylistMenu.qml index 8a2474b..e265d3c 100644 --- a/widgets/MainPlaylist/PlaylistMenu.qml +++ b/widgets/MainPlaylist/PlaylistMenu.qml @@ -1,45 +1,45 @@ -import QtQuick 2.9 -import QtQuick.Controls 2.2 +import QtQuick 2.10 +import QtQuick.Controls 2.10 import org.kde.mauikit 1.0 as Maui Menu { signal clearOut() signal clean() signal callibrate() signal hideCover() signal saveToClicked() MenuItem { text: qsTr("Clear out...") onTriggered: clearOut() } MenuItem { text: qsTr("Clean...") onTriggered: clean() } MenuItem { text: qsTr("Save list to...") onTriggered: saveToClicked() } MenuItem { enabled: syncPlaylist.length > 0 text: syncPlaylist.length > 0 && sync ? qsTr("Pause syncing") : qsTr("Continue syncing") onTriggered: sync = !sync } // Maui.MenuItem // { // text: qsTr("Playlist list...") // checkable: true // checked: mainPlaylistItem.visible // onTriggered: mainPlaylistItem.visible = !mainPlaylistItem.visible // } } diff --git a/widgets/PlaylistsView/PlaylistsView.qml b/widgets/PlaylistsView/PlaylistsView.qml index b21df5e..6913f56 100644 --- a/widgets/PlaylistsView/PlaylistsView.qml +++ b/widgets/PlaylistsView/PlaylistsView.qml @@ -1,213 +1,213 @@ -import QtQuick 2.9 +import QtQuick 2.10 import QtQuick.Layouts 1.3 -import QtQuick.Controls 2.2 +import QtQuick.Controls 2.10 import org.kde.kirigami 2.7 as Kirigami import org.kde.mauikit 1.0 as Maui import "../../view_models/BabeTable" import "../../view_models" import "../../db/Queries.js" as Q import "../../utils/Help.js" as H ColumnLayout { id: control spacing: 0 property string playlistQuery property alias playlistModel : playlistViewModel.model property alias playlistList : playlistViewModel.list property alias playlistViewList : playlistViewModel signal rowClicked(var track) signal quickPlayTrack(var track) signal playAll() signal playSync(var playlist) signal appendAll() SwipeView { id: playlistSwipe Layout.fillHeight: true Layout.fillWidth: true interactive: false clip: true PlaylistsViewModel { id: playlistViewModel onPlaySync: syncAndPlay(index) } BabeList { id: playlistViewModelFilter // headBarExitIcon: "go-previous" headBar.leftContent: ToolButton { icon.name: "go-previous" onClicked: playlistSwipe.currentIndex = 0 } model : ListModel {} delegate: Maui.LabelDelegate { id: delegate label : tag Connections { target: delegate onClicked: {} } } } } ColorTagsBar { Layout.fillWidth: true height: Maui.Style.rowHeightAlt recSize: Kirigami.Settings.isMobile ? Maui.Style.iconSizes.medium : Maui.Style.iconSizes.small onColorClicked: populate(Q.GET.colorTracks_.arg(color.toLowerCase())) } Maui.Dialog { id: _filterDialog parent: parent maxHeight: maxWidth maxWidth: Maui.Style.unit * 600 defaultButtons: false page.padding: 0 BabeTable { id: filterList anchors.fill: parent clip: true coverArtVisible: true headBar.visible: !holder.visible title: playlistViewModel.list.get(playlistViewModel.currentIndex).playlist holder.emoji: "qrc:/assets/dialog-information.svg" holder.isMask: false holder.title : playlistViewModel.list.get(playlistViewModel.currentIndex).playlist holder.body: "Your playlist is empty,
start adding new music to it" holder.emojiSize: Maui.Style.iconSizes.huge contextMenuItems: MenuItem { text: qsTr("Remove from playlist") } // headerMenu.menuItem: [ // Maui.MenuItem // { // enabled: !playlistViewModel.model.get(playlistViewModel.currentIndex).playlistIcon // text: "Sync tags" // onTriggered: {} // }, // Maui.MenuItem // { // enabled: !playlistViewModel.model.get(playlistViewModel.currentIndex).playlistIcon // text: "Play-n-Sync" // onTriggered: // { // filterList.headerMenu.close() // syncAndPlay(playlistViewModel.currentIndex) // } // }, // Maui.MenuItem // { // enabled: !playlistViewModel.model.get(playlistViewModel.currentIndex).playlistIcon // text: "Remove playlist" // onTriggered: removePlaylist() // } // ] // contextMenu.menuItem: [ // MenuItem // { // text: qsTr("Remove from playlist") // onTriggered: // { // bae.removePlaylistTrack(filterList.model.get(filterList.currentIndex).url, playlistViewModel.model.get(playlistViewModel.currentIndex).playlist) // populate(playlistQuery) // } // } // ] section.criteria: ViewSection.FullString section.delegate: Maui.LabelDelegate { label: filterList.section.property === qsTr("stars") ? H.setStars(section) : section isSection: true labelTxt.font.family: "Material Design Icons" width: filterList.width } Connections { target: filterList onRowClicked: control.rowClicked(filterList.list.get(index)) onQuickPlayTrack: control.quickPlayTrack(filterList.list.get(filterList.currentIndex)) onPlayAll: playAll() onAppendAll: appendAll() onPulled: populate(playlistQuery) } Connections { target: filterList.contextMenu onRemoveClicked: { playlistList.removeTrack(playlistViewList.currentIndex, filterList.list.get(filterList.currentIndex).url) populate(playlistQuery) } } } } function populateExtra(query, title) { // playlistSwipe.currentIndex = 1 // var res = bae.get(query) // playlistViewModelFilter.clearTable() // playlistViewModelFilter.headBarTitle = title // appendToExtraList(res) } function appendToExtraList(res) { if(res.length>0) for(var i in res) playlistViewModelFilter.model.append(res[i]) } function populate(query) { playlistQuery = query filterList.list.query = playlistQuery _filterDialog.open() } function syncAndPlay(index) { if(!playlistList.get(index).playlistIcon) playSync(playlistList.get(index).playlist) } function removePlaylist() { playlistList.removePlaylist(playlistViewList.currentIndex) } } diff --git a/widgets/PlaylistsView/PlaylistsViewModel.qml b/widgets/PlaylistsView/PlaylistsViewModel.qml index eaa48d3..550210e 100644 --- a/widgets/PlaylistsView/PlaylistsViewModel.qml +++ b/widgets/PlaylistsView/PlaylistsViewModel.qml @@ -1,139 +1,139 @@ -import QtQuick 2.9 +import QtQuick 2.10 import QtQuick.Layouts 1.3 -import QtQuick.Controls 2.2 +import QtQuick.Controls 2.10 import org.kde.kirigami 2.6 as Kirigami import org.kde.mauikit 1.0 as Maui import PlaylistsList 1.0 import TracksList 1.0 import "../../utils" import "../../view_models" import "../../db/Queries.js" as Q import "../../utils/Help.js" as H BabeList { id: control property alias list: _playlistsList signal playSync(int index) topPadding: Maui.Style.contentMargins Maui.NewDialog { id: newPlaylistDialog title: qsTr("New Playlist...") onFinished: addPlaylist(text) acceptText: qsTr("Create") rejectButton.visible: false } headBar.leftContent: [ ToolButton { id : createPlaylistBtn text: qsTr("Add") icon.name : "list-add" onClicked: newPlaylistDialog.open() }, ToolButton { text: qsTr("Remove") icon.name: "list-remove" onClicked: removePlaylist() } ] Maui.BaseModel { id: _playlistsModel list: _playlistsList } Playlists { id: _playlistsList } model: _playlistsModel delegate : Maui.ListDelegate { id: delegate width: control.width label: model.playlist Connections { target : delegate onClicked : { currentIndex = index var playlist = _playlistsList.get(index).playlist filterList.group = false switch(playlist) { case "Most Played": populate(Q.GET.mostPlayedTracks); filterList.list.sortBy = Tracks.COUNT break; case "Rating": filterList.list.sortBy = Tracks.RATE filterList.group = true populate(Q.GET.favoriteTracks); break; case "Recent": populate(Q.GET.recentTracks); filterList.list.sortBy = Tracks.ADDDATE filterList.group = true break; case "Favs": populate(Q.GET.babedTracks); break; case "Online": populate(Q.GET.favoriteTracks); break; case "Tags": populateExtra(Q.GET.tags, "Tags") break; case "Relationships": populate(Q.GET.favoriteTracks); break; case "Popular": populate(Q.GET.favoriteTracks); break; case "Genres": populateExtra(Q.GET.genres, "Genres") break; default: populate(Q.GET.playlistTracks_.arg(playlist)); break; } } } } function addPlaylist(text) { var title = text.trim() if(list.insertAt(title, 0)) control.listView.positionViewAtEnd() } } diff --git a/widgets/SearchView/SearchSuggestions.qml b/widgets/SearchView/SearchSuggestions.qml index cca7726..1e0b1a5 100644 --- a/widgets/SearchView/SearchSuggestions.qml +++ b/widgets/SearchView/SearchSuggestions.qml @@ -1,101 +1,101 @@ import QtQuick 2.0 -import QtQuick.Controls 2.2 +import QtQuick.Controls 2.10 import org.kde.mauikit 1.0 as Maui import "../../view_models" import "../../db/Queries.js" as Q Maui.Popup { id: searchSuggestionsRoot property alias model : suggestionsList.model maxHeight: Maui.Style.unit * 700 heightHint: 0.5 verticalAlignment: Qt.AlignBottom BabeList { id: suggestionsList anchors.fill: parent headBar.visible: false model: ListModel {id: suggestionsModel} section.property : "type" section.delegate: Maui.LabelDelegate { label: section isSection: true width: parent.width } delegate: Maui.LabelDelegate { id: delegate label: suggestion Connections { target: delegate onClicked: { suggestionsList.currentIndex = index runSearch(suggestionsList.model.get(index).suggestion) close() } } } } // onOpened: updateSuggestions() // function updateSuggestions() // { // if(!visible) open() //// suggestionsList.clearTable() // var qq = bae.loadSetting("QUERIES", "BABE", {}) // savedQueries = qq.split(",") // if(searchInput.text.length>3 && searchInput.text.indexOf(":") < 0) // { // // var similar = bae.get('select distinct * from tracks where title LIKE "%'+searchInput.text+'%" or artist LIKE "%'+searchInput.text+'%" or album LIKE "%'+searchInput.text+'%" limit 5') // var similarArtist = bae.get('select distinct * from tracks where artist LIKE "%'+searchInput.text+'%" limit 5') // var similarAlbum= bae.get('select distinct * from tracks where album LIKE "%'+searchInput.text+'%" limit 5') // var similarTracks = bae.get('select distinct * from tracks where title LIKE "%'+searchInput.text+'%" limit 5') // var checkList = [] // for(var i in similarArtist) // if(checkList.indexOf("artist: "+similarArtist[i].artist) < 0) // { // checkList.push("artist: "+similarArtist[i].artist) // suggestionsList.model.append({suggestion: "artist: "+similarArtist[i].artist, type: "Artists"}) // } // for(i in similarAlbum) // if(checkList.indexOf("album: "+similarAlbum[i].album) < 0) // { // checkList.push("album: "+similarAlbum[i].album) // suggestionsList.model.append({suggestion: "album: "+similarAlbum[i].album, type: "Albums"}) // } // for(i in similarTracks) // if(checkList.indexOf("title: "+similarTracks[i].title) < 0) // { // checkList.push("title: "+similarTracks[i].title) // suggestionsList.model.append({suggestion: "title: "+similarTracks[i].title, type: "Tracks"}) // } // } // if(savedQueries.length>0) // for(i=0; i < 3; i++) // if(i < savedQueries.length ) // suggestionsList.model.append({suggestion: savedQueries[i], type: "Recent"}) // } } diff --git a/widgets/SearchView/SearchTable.qml b/widgets/SearchView/SearchTable.qml index 7540287..1fc3d36 100644 --- a/widgets/SearchView/SearchTable.qml +++ b/widgets/SearchView/SearchTable.qml @@ -1,122 +1,122 @@ -import QtQuick 2.9 -import QtQuick.Controls 2.2 +import QtQuick 2.10 +import QtQuick.Controls 2.10 import org.kde.kirigami 2.2 as Kirigami import org.kde.mauikit 1.0 as Maui import QtQuick.Layouts 1.3 import "../../view_models" import QtGraphicalEffects 1.0 import "../../view_models/BabeTable" import "../../db/Queries.js" as Q BabeTable { id: searchTable property alias searchInput : searchInput property var savedQueries : [] // property bool autoSuggestions : bae.loadSetting("AUTOSUGGESTIONS", "BABE", false) === "true" ? true : false property bool autoSuggestions : false trackNumberVisible: false headBar.visible: count holder.emoji: "qrc:/assets/dialog-information.svg" holder.isMask: false holder.title : "No search results!" holder.body: "Try with another query" holder.emojiSize: Maui.Style.iconSizes.huge coverArtVisible: true headBar.leftContent: ToolButton { icon.name: "edit-clear" onClicked: clearSearch() } footBar.middleContent: Maui.TextField { id: searchInput placeholderText: qsTr("Search...") Layout.fillWidth: true onAccepted: runSearch(searchInput.text) // onActiveFocusChanged: if(activeFocus && autoSuggestions) suggestionsPopup.open() onTextEdited: if(autoSuggestions) suggestionsPopup.updateSuggestions() } // footBar.leftContent: ToolButton // { // visible: true // icon.name: "view-filter" // icon.color: autoSuggestions ? babeColor : textColor // onClicked: // { // autoSuggestions = !autoSuggestions // Maui.FM.saveSettings("AUTOSUGGESTIONS", autoSuggestions, "BABE") // if(!autoSuggestions) // suggestionsPopup.close() // } // } SearchSuggestions { id: suggestionsPopup // focus: false parent: parent // modal: false // closePolicy: Popup.CloseOnPressOutsideParent } Rectangle { visible: suggestionsPopup.visible width: parent.width height: parent.height - searchInput.height color: Kirigami.Theme.backgroundColor z: 999 opacity: 0.5 } function runSearch(searchTxt) { if(searchTxt) if(searchTxt !== searchTable.title) { if(savedQueries.indexOf(searchTxt) < 0) { savedQueries.unshift(searchTxt) // suggestionsPopup.model.insert(0, {suggestion: searchInput.text}) Maui.FM.saveSettings("QUERIES", savedQueries.join(","), "BABE") } searchTable.title = searchTxt var queries = searchTxt.split(",") searchTable.list.searchQueries(queries) searchTable.forceActiveFocus() suggestionsPopup.close() } } function clearSearch() { searchInput.clear() searchTable.list.clear() searchTable.title = "" suggestionsPopup.close() } function populate(tracks) { searchTable.clearTable() for(var i in tracks) searchTable.model.append(tracks[i]) } } diff --git a/widgets/SelectionBarMenu.qml b/widgets/SelectionBarMenu.qml index dab4023..5a76ce2 100644 --- a/widgets/SelectionBarMenu.qml +++ b/widgets/SelectionBarMenu.qml @@ -1,220 +1,220 @@ import QtQuick 2.0 -import QtQuick 2.9 -import QtQuick.Controls 2.2 +import QtQuick 2.10 +import QtQuick.Controls 2.10 import QtQuick.Layouts 1.3 import "../utils" import ".." import "../utils/Help.js" as H import "../utils/Player.js" as Player import "../view_models" import org.kde.kirigami 2.7 as Kirigami import org.kde.mauikit 1.0 as Maui Menu { id: control width: Maui.Style.unit * 200 property int rate : 0 property string starColor : "#FFC107" property string starReg : Kirigami.Theme.textColor property string starIcon: "draw-star" signal rateClicked(int rate) MenuItem { text: qsTr("Play...") onTriggered: { mainPlaylist.list.clear() var tracks = _selectionBar.selectedItems for(var i in tracks) Player.appendTrack(tracks[i]) Player.playAll() } } MenuItem { text: qsTr("Append...") onTriggered: Player.appendAll(_selectionBar.selectedItems) } MenuItem { text: qsTr("Queue") onTriggered: { Player.queueTracks(_selectionBar.selectedItems) close() } } // MenuSeparator {} // MenuItem // { // text: qsTr("Fav/UnFav them") // onTriggered: // { // for(var i= 0; i < _selectionBar.count; i++) // _selectionBarModelList.fav(i, !(_selectionBarModelList.get(i).fav == "1")) // } // } MenuItem { text: qsTr("Add to...") onTriggered: { playlistDialog.tracks = _selectionBar.selectedPaths playlistDialog.open() close() } } MenuSeparator {} MenuItem { text: qsTr("Share...") onTriggered: { if(isAndroid) { Maui.Android.shareDialog(_selectionBar.selectedPaths) return } _dialogLoader.sourceComponent = _shareDialogComponent root.dialog.show(_selectionBar.selectedPaths) close() } } MenuSeparator {} MenuItem { text: qsTr("Remove") Kirigami.Theme.textColor: Kirigami.Theme.negativeTextColor onTriggered: { close() } } // MenuSeparator {} // MenuItem // { // id: starsRow // width: parent.width // height: Maui.Style.iconSizes.medium + Maui.Style.space.small // RowLayout // { // anchors.fill: parent // ToolButton // { // Layout.fillWidth: true // Layout.fillHeight: true // icon.name: starIcon // icon.width: Maui.Style.iconSizes.medium // icon.color: rate >= 1 ? starColor :starReg // onClicked: // { // rate = 1 // } // } // ToolButton // { // Layout.fillWidth: true // Layout.fillHeight: true // icon.width: Maui.Style.iconSizes.medium // icon.name: starIcon // icon.color: rate >= 2 ? starColor :starReg // onClicked: // { // rate = 2 // } // } // ToolButton // { // Layout.fillWidth: true // Layout.fillHeight: true // icon.width: Maui.Style.iconSizes.medium // icon.name: starIcon // icon.color: rate >= 3 ? starColor :starReg // onClicked: // { // rate = 3 // } // } // ToolButton // { // Layout.fillWidth: true // Layout.fillHeight: true // icon.width: Maui.Style.iconSizes.medium // icon.name: starIcon // icon.color: rate >= 4 ? starColor :starReg // onClicked: // { // rate = 4 // } // } // ToolButton // { // Layout.fillWidth: true // Layout.fillHeight: true // icon.width: Maui.Style.iconSizes.medium // icon.name: starIcon // icon.color: rate >= 5 ? starColor :starReg // onClicked: // { // rate = 5 // } // } // } // } // onRateChanged: // { // close() // for(var i= 0; i < _selectionBar.count; i++) // _selectionBarModelList.rate(i, control.rate) // } // MenuItem // { // id: colorsRow // width: parent.width // height: Maui.Style.iconSizes.medium + Maui.Style.space.small // ColorTagsBar // { // anchors.fill: parent // onColorClicked: // { // for(var i= 0; i < _selectionBar.count; i++) // _selectionBarModelList.color(i, color) // control.close() // } // } // } } diff --git a/widgets/SettingsView/SourcesDialog.qml b/widgets/SettingsView/SourcesDialog.qml index a0a84a2..43cc673 100644 --- a/widgets/SettingsView/SourcesDialog.qml +++ b/widgets/SettingsView/SourcesDialog.qml @@ -1,106 +1,106 @@ -import QtQuick 2.9 +import QtQuick 2.10 import QtQuick.Layouts 1.3 -import QtQuick.Controls 2.2 +import QtQuick.Controls 2.10 import org.kde.mauikit 1.0 as Maui import "../../view_models" import "../../utils/Help.js" as H Maui.Dialog { property string pathToRemove : "" maxWidth: Maui.Style.unit * 600 maxHeight: Maui.Style.unit * 500 defaultButtons: true acceptButton.text: qsTr("Add") rejectButton.text: qsTr("Remove") page.padding: Maui.Style.space.medium onRejected: { var index = sources.currentIndex var url = sources.model.get(index).url pathToRemove = url confirmationDialog.title = "Remove source" confirmationDialog.message = "Are you sure you want to remove the source: \n "+url confirmationDialog.open() } onAccepted: { _dialogLoader.sourceComponent = _fmDialogComponent root.dialog.settings.onlyDirs = true root.dialog.show(function(paths) { console.log("SCAN DIR <<", paths) for(var i in paths) listModel.append({url: paths[i]}) vvave.scanDir([paths]) }) getSources() } Maui.Dialog { id: confirmationDialog onAccepted: { if(pathToRemove.length>0) if(vvave.removeSource(pathToRemove)) H.refreshCollection() getSources() confirmationDialog.close() } onRejected: confirmationDialog.close() } Maui.Holder { anchors.fill: parent visible: !sources.count emoji: "qrc:/assets/MusicCloud.png" isMask: false title : "No Sources!" body: "Add new sources to organize and play your music collection" emojiSize: Maui.Style.iconSizes.huge } BabeList { id: sources anchors.fill: parent headBar.visible: false title: qsTr("Sources") Layout.fillWidth: true Layout.fillHeight: true width: parent.width ListModel { id: listModel } model: listModel delegate: Maui.ListDelegate { id: delegate label: url Connections { target: delegate onClicked: sources.currentIndex = index } } } onOpened: getSources() function getSources() { sources.model.clear() var folders = vvave.getSourceFolders() for(var i in folders) sources.model.append({url : folders[i]}) } } diff --git a/widgets/TracksView.qml b/widgets/TracksView.qml index 08dcdaa..44a6317 100644 --- a/widgets/TracksView.qml +++ b/widgets/TracksView.qml @@ -1,21 +1,22 @@ -import QtQuick 2.9 +import QtQuick 2.10 +import QtQuick.Controls 2.12 import org.kde.mauikit 1.0 as Maui import "../view_models/BabeTable" import "../view_models" import "../db/Queries.js" as Q import "../utils/Help.js" as H BabeTable { id: tracksViewTable trackNumberVisible: false headBar.visible: !holder.visible coverArtVisible: false holder.emoji: "qrc:/assets/dialog-information.svg" holder.title : qsTr("No Tracks!") holder.body: qsTr("Add new music sources") holder.emojiSize: Maui.Style.iconSizes.huge list.query: Q.GET.allTracks }