diff --git a/main.qml b/main.qml index 9810096..3c86492 100644 --- a/main.qml +++ b/main.qml @@ -1,781 +1,781 @@ 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 import org.kde.mauikit 1.1 as MauiLab import org.maui.vvave 1.0 as Vvave import Player 1.0 import AlbumsList 1.0 import TracksList 1.0 import PlaylistsList 1.0 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 "view_models/BabeGrid" import "widgets/InfoView" import "db/Queries.js" as Q import "utils/Help.js" as H import "utils/Player.js" as Player Maui.ApplicationWindow { id: root title: currentTrack ? currentTrack.title + " - " + currentTrack.artist + " | " + currentTrack.album : "" /***************************************************/ /******************** 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 ") Maui.App.enableCSD: true background.opacity: translucency ? 0.5 : 1 // floatingHeader: swipeView.currentIndex === viewsIndex.albums || swipeView.currentIndex === viewsIndex.artists // autoHideHeader: true /***************************************************/ /******************** PLAYBACK ********************/ /*************************************************/ property bool isShuffle: Maui.FM.loadSettings("SHUFFLE","PLAYBACK", false) property var currentTrack: mainPlaylist.listView.itemAtIndex(currentTrackIndex) property int currentTrackIndex: -1 property int prevTrackIndex: 0 readonly property string currentArtwork: currentTrack ? currentTrack.artwork : "" 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, albums: 1, artists: 2, playlists: 3, cloud: 4, folders: 5, youtube: 6}) property string syncPlaylist: "" property bool sync: false property bool focusView : false property bool selectionMode : false /***************************************************/ /******************** UI COLORS *******************/ /*************************************************/ readonly property color babeColor: "#f84172" property bool translucency : Maui.Handy.isLinux /*SIGNALS*/ signal missingAlert(var track) // flickable: swipeView.currentItem.flickable || swipeView.currentItem.item.flickable footerPositioning: ListView.InlineFooter /*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 && currentTrack.url) mainPlaylist.list.countUp(currentTrackIndex) Player.nextTrack() } } headBar.visible: !focusView headBar.rightContent: ToolButton { visible: Maui.Handy.isTouch icon.name: "item-select" onClicked: selectionMode = !selectionMode checkable: false checked: selectionMode } Loader { id: _dialogLoader } InfoView { id: infoView maxWidth: parent.width * 0.8 maxHeight: parent.height * 0.9 } Loader { id: _focusViewLoader anchors.fill: parent active: focusView source: "widgets/FocusView.qml" } Component { id: _shareDialogComponent MauiLab.ShareDialog {} } Component { id: _fmDialogComponent Maui.FileDialog {} } Component { id: _settingsDialogComponent SettingsDialog {} } SourcesDialog { id: sourcesDialog } FloatingDisk { id: _floatingDisk } mainMenu: [ MenuSeparator{}, MenuItem { text: qsTr("Settings") icon.name: "settings-configure" onTriggered: { _dialogLoader.sourceComponent = _settingsDialogComponent dialog.open() } }, MenuItem { text: qsTr("Sources") icon.name: "folder-add" onTriggered: sourcesDialog.open() }, MenuSeparator{}, MenuItem { text: qsTr("Open") icon.name: "folder-add" onTriggered: { _dialogLoader.sourceComponent = _fmDialogComponent root.dialog.settings.onlyDirs = false root.dialog.settings.filterType = Maui.FMList.AUDIO root.dialog.show(function(paths) { Vvave.Vvave.openUrls(paths) root.dialog.close() }) } } ] Playlists { id: playlistsList } PlaylistDialog { id: playlistDialog } sideBar: Maui.AbstractSideBar { id: _drawer width: visible ? Math.min(Kirigami.Units.gridUnit * 16, root.width) : 0 collapsed: !isWide collapsible: true dragMargin: Maui.Style.space.big overlay.visible: collapsed && position > 0 && visible Connections { target: _drawer.overlay onClicked: _drawer.close() } background: Rectangle { color: Kirigami.Theme.backgroundColor opacity: translucency ? 0.5 : 1 } MainPlaylist { id: mainPlaylist anchors.fill: parent Connections { target: mainPlaylist onCoverPressed: Player.appendAll(tracks) onCoverDoubleClicked: Player.playAll(tracks) } } } // autoHideFooter: true // autoHideFooterMargins: root.height * 0.2 // autoHideFooterDelay: 5000 footer: ColumnLayout { visible: !focusView width: parent.width spacing: 0 height: visible ? implicitHeight : 0 Maui.ToolBar { Layout.fillWidth: true preferredHeight: Maui.Style.toolBarHeightAlt * 0.8 position: ToolBar.Footer visible: isPlaying leftContent: Label { id: _label1 visible: text.length verticalAlignment: Qt.AlignVCenter horizontalAlignment: Qt.AlignHCenter text: progressTimeLabel elide: Text.ElideMiddle wrapMode: Text.NoWrap color: Kirigami.Theme.textColor font.weight: Font.Normal font.pointSize: Maui.Style.fontSizes.default } middleContent: Item { Layout.fillHeight: true Layout.fillWidth: true Label { anchors.fill: parent visible: text.length verticalAlignment: Qt.AlignVCenter horizontalAlignment: Qt.AlignHCenter text: root.title elide: Text.ElideMiddle wrapMode: Text.NoWrap color: Kirigami.Theme.textColor font.weight: Font.Normal font.pointSize: Maui.Style.fontSizes.default } } rightContent: Label { id: _label2 visible: text.length verticalAlignment: Qt.AlignVCenter horizontalAlignment: Qt.AlignHCenter text: player.transformTime(player.duration/1000) elide: Text.ElideMiddle wrapMode: Text.NoWrap color: Kirigami.Theme.textColor font.weight: Font.Normal font.pointSize: Maui.Style.fontSizes.default opacity: 0.7 } background: Slider { id: progressBar padding: 0 from: 0 to: 1000 value: player.pos spacing: 0 focus: true onMoved: player.pos = value enabled: player.playing Kirigami.Separator { anchors.top: parent.top anchors.left: parent.left anchors.right: parent.right } background: Rectangle { implicitWidth: progressBar.width implicitHeight: progressBar.height width: progressBar.availableWidth height: implicitHeight color: "transparent" opacity: 0.4 Rectangle { width: progressBar.visualPosition * parent.width height: progressBar.height color: Kirigami.Theme.highlightColor } } handle: Rectangle { x: progressBar.leftPadding + progressBar.visualPosition * (progressBar.availableWidth - width) y: 0 implicitWidth: Maui.Style.iconSizes.medium implicitHeight: progressBar.height color: progressBar.pressed ? Qt.lighter(Kirigami.Theme.highlightColor, 1.2) : "transparent" } } } Maui.ToolBar { Layout.fillWidth: true Layout.preferredHeight: Maui.Style.toolBarHeight position: ToolBar.Footer background: Item { Image { id: artworkBg height: parent.height width: parent.width sourceSize.width: 500 sourceSize.height: 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 } } rightContent: ToolButton { icon.name: _volumeSlider.value === 0 ? "player-volume-muted" : "player-volume" onPressAndHold : { player.volume = player.volume === 0 ? 100 : 0 } onClicked: { _sliderPopup.visible ? _sliderPopup.close() : _sliderPopup.open() } Popup { id: _sliderPopup height: 150 width: parent.width y: -150 x: 0 // closePolicy: Popup.CloseOnEscape | Popup.CloseOnPress Slider { id: _volumeSlider visible: true height: parent.height width: 20 anchors.horizontalCenter: parent.horizontalCenter from: 0 to: 100 value: player.volume orientation: Qt.Vertical onMoved: { player.volume = value } } } } middleContent: [ ToolButton { id: babeBtnIcon icon.name: "love" enabled: currentTrackIndex >= 0 checked: currentTrack ? Maui.FM.isFav(currentTrack.url) : false icon.color: checked ? babeColor : Kirigami.Theme.textColor onClicked: if (!mainlistEmpty) { mainPlaylist.list.fav(currentTrackIndex, !Maui.FM.isFav(currentTrack.url)) } }, Maui.ToolActions { expanded: true autoExclusive: false checkable: false Action { icon.name: "media-skip-backward" onTriggered: Player.previousTrack() // onPressAndHold: Player.playAt(prevTrackIndex) } //ambulatorios1@clinicaantioquia.com.co, copago martha hilda restrepo, cc 22146440 eps salud total, consulta expecialista urologo, hora 3:40 pm Action { id: playIcon text: qsTr("Play and pause") enabled: currentTrackIndex >= 0 icon.name: isPlaying ? "media-playback-pause" : "media-playback-start" onTriggered: player.playing = !player.playing } Action { text: qsTr("Next") icon.name: "media-skip-forward" onTriggered: 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 + Maui.Page { anchors.fill: parent visible: !focusView + flickable: swipeView.currentItem.item.flickable MauiLab.AppViews { id: swipeView - Layout.fillHeight: true - Layout.fillWidth: true + anchors.fill: parent MauiLab.AppViewLoader { MauiLab.AppView.title: qsTr("Tracks") MauiLab.AppView.iconName: "view-media-track" TracksView { id: tracksView onRowClicked: Player.quickPlay(tracksView.listModel.get(index)) onQuickPlayTrack: Player.quickPlay(tracksView.listModel.get(index)) onAppendTrack: Player.addTrack(tracksView.listModel.get(index)) onPlayAll: Player.playAll( tracksView.listModel.getAll()) onAppendAll: Player.appendAll( tracksView.listModel.getAll()) onQueueTrack: Player.queueTracks([tracksView.listModel.get(index)], index) Connections { target: Vvave.Vvave onRefreshTables: tracksView.list.refresh() } } } MauiLab.AppViewLoader { MauiLab.AppView.title: qsTr("Albums") MauiLab.AppView.iconName: "view-media-album-cover" AlbumsView { id: albumsView holder.emoji: "qrc:/assets/dialog-information.svg" holder.isMask: false holder.title : qsTr("No Albums!") holder.body: qsTr("Add new music sources") holder.emojiSize: Maui.Style.iconSizes.huge list.query: Albums.ALBUMS list.sortBy: Albums.ALBUM 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.playAt(0) } onPlayAll: Player.playAll(albumsView.listModel.getAll()) onAppendAll: Player.appendAll(albumsView.listModel.getAll()) Connections { target: Vvave.Vvave onRefreshTables: albumsView.list.refresh() } } } MauiLab.AppViewLoader { MauiLab.AppView.title: qsTr("Artists") MauiLab.AppView.iconName: "view-media-artist" AlbumsView { id: artistsView holder.emoji: "qrc:/assets/dialog-information.svg" holder.isMask: false holder.title : qsTr("No Artists!") holder.body: qsTr("Add new music sources") holder.emojiSize: Maui.Style.iconSizes.huge list.query: Albums.ARTISTS list.sortBy: Albums.ARTIST table.list.sortBy: Tracks.NONE 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.playAt(0) } onPlayAll: Player.playAll(artistsView.listModel.getAll()) onAppendAll: Player.appendAll(artistsView.listModel.getAll()) Connections { target: Vvave.Vvave onRefreshTables: artistsView.list.refresh() } } } MauiLab.AppViewLoader { MauiLab.AppView.title: qsTr("Playlists") MauiLab.AppView.iconName: "view-media-playlist" PlaylistsView { id: playlistsView onRowClicked: Player.quickPlay(track) onAppendTrack: Player.addTrack(track) onPlayTrack: Player.quickPlay(track) onAppendAll: Player.appendAll(playlistsView.listModel.getAll()) onSyncAndPlay: { Player.playAll(playlistsView.listModel.getAll()) root.sync = true root.syncPlaylist = playlist } onPlayAll: Player.playAll(playlistsView.listModel.getAll()) } } MauiLab.AppViewLoader { MauiLab.AppView.title: qsTr("Cloud") MauiLab.AppView.iconName: "folder-cloud" CloudView { id: cloudView } } MauiLab.AppViewLoader { MauiLab.AppView.title: qsTr("Folders") MauiLab.AppView.iconName: "folder" FoldersView { id: foldersView Connections { target: Vvave.Vvave onRefreshTables: foldersView.populate() } Connections { target: foldersView.list onRowClicked: Player.quickPlay(foldersView.list.model.get(index)) onQuickPlayTrack: Player.quickPlay(foldersView.list.model.get(index)) onAppendTrack: Player.addTrack(foldersView.listModel.get(index)) onPlayAll: Player.playAll(foldersView.listModel.getAll()) onAppendAll: Player.appendAll(foldersView.listModel.getAll()) onQueueTrack: Player.queueTracks([foldersView.list.model.get(index)], index) } } } MauiLab.AppViewLoader { MauiLab.AppView.title: qsTr("YouTube") MauiLab.AppView.iconName: "internet-services" YouTube { id: youtubeView } } } - SelectionBar + footer: SelectionBar { id: _selectionBar property alias listView: _selectionBar.selectionList - Layout.alignment: Qt.AlignHCenter - Layout.preferredWidth: Math.min(parent.width-(Maui.Style.space.medium*2), implicitWidth) - Layout.margins: Maui.Style.space.medium + anchors.horizontalCenter: parent.horizontalCenter + width: Math.min(parent.width-(Maui.Style.space.medium*2), implicitWidth) + padding: Maui.Style.space.big maxListHeight: swipeView.height - Maui.Style.space.medium onExitClicked: { root.selectionMode = false clear() } } } /*CONNECTIONS*/ Connections { target: Vvave.Vvave onRefreshTables: { if(size>0) root.notify("emblem-info", "Collection updated", size+" new tracks added...") } 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/widgets/AlbumsView.qml b/widgets/AlbumsView.qml index b8139a6..05c78d9 100644 --- a/widgets/AlbumsView.qml +++ b/widgets/AlbumsView.qml @@ -1,161 +1,161 @@ 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.7 as Kirigami import org.kde.mauikit 1.0 as Maui import TracksList 1.0 import AlbumsList 1.0 -Kirigami.PageRow +StackView { id: control clip: true - defaultColumnWidth: Kirigami.Units.gridUnit * 44 property string currentAlbum: "" property string currentArtist: "" property var tracks: [] property alias table : _tracksTable property alias listModel : _tracksTable.listModel property alias holder: albumsViewGrid.holder property alias list : albumsViewGrid.list 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) + property Flickable flickable : currentItem.flickable - initialPage: BabeGrid + initialItem: BabeGrid { id: albumsViewGrid onAlbumCoverPressed: control.albumCoverPressedAndHold(album, artist) onAlbumCoverClicked: control.albumCoverClicked(album, artist) headBar.visible: false } BabeTable { id: _tracksTable showTitle: false trackNumberVisible: true coverArtVisible: true focus: true list.sortBy: Tracks.TRACK holder.emoji: "qrc:/assets/dialog-information.svg" holder.isMask: false holder.title : "Oops!" holder.body: qsTr("This list is empty") holder.emojiSize: Maui.Style.iconSizes.huge headBar.visible: true headBar.farLeftContent: ToolButton { icon.name: "go-previous" - onClicked: control.removePage(_tracksTable) + onClicked: control.pop() } onRowClicked: { control.rowClicked(listModel.get(index)) } onQuickPlayTrack: { control.playTrack(listModel.get(index)) } onQueueTrack: { control.queueTrack(listModel.get(index)) } onAppendTrack: { control.appendTrack(listModel.get(index)) } onPlayAll: { - control.removePage(_tracksTable) + control.pop() control.playAll(currentAlbum, currentArtist) } onAppendAll: { - control.removePage(_tracksTable) + control.pop() control.appendAll(currentAlbum, currentArtist) } } function populateTable(album, artist) { console.log("PAPULATE ALBUMS VIEW") control.push(_tracksTable) _tracksTable.listModel.filter = "" var query = "" var tagq = "" currentAlbum = album === undefined ? "" : album currentArtist= artist if(album && artist) { query = Q.GET.albumTracks_.arg(album) query = query.arg(artist) _tracksTable.title = album tagq = Q.GET.albumTags_.arg(album) }else if(artist && album === undefined) { query = Q.GET.artistTracks_.arg(artist) _tracksTable.title = artist tagq = Q.GET.artistTags_.arg(artist) } _tracksTable.list.query = query } function filter(tracks) { var matches = [] for(var i = 0; istart adding new music to it" holder.emojiSize: Maui.Style.iconSizes.huge headBar.visible: true headBar.farLeftContent: ToolButton { icon.name: "go-previous" - onClicked: control.removePage(filterList) + onClicked: control.pop() } contextMenuItems: MenuItem { text: qsTr("Remove from playlist") } onRowClicked: control.rowClicked(filterList.listModel.get(index)) onQuickPlayTrack: control.playTrack(filterList.listModel.get(filterList.currentIndex)) onAppendTrack: control.appendTrack(filterList.listModel.get(filterList.currentIndex)) onPlayAll: { if(filterList.isPublic) control.syncAndPlay(control.currentPlaylist) else control.playAll() - control.removePage(filterList) + control.pop() } onAppendAll: appendAll() onPulled: 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.contextMenu onRemoveClicked: { playlistsList.removeTrack(playlistViewList.currentIndex, filterList.listModel.get(filterList.currentIndex).url) populate(playlistQuery) } } } function appendToExtraList(res) { if(res.length>0) for(var i in res) playlistViewModelFilter.model.append(res[i]) } function populate(query, isPublic) { playlistQuery = query filterList.isPublic = isPublic filterList.list.query = playlistQuery filterList.listModel.filter = "" control.push(filterList) } function removePlaylist() { playlistsList.removePlaylist(playlistViewList.currentIndex) } function addPlaylist(text) { var title = text.trim() if(playlistsList.insert(title)) control.listView.positionViewAtEnd() } }