diff --git a/main.qml b/main.qml index 6702f9a..00bbe28 100644 --- a/main.qml +++ b/main.qml @@ -1,1068 +1,1066 @@ import QtQuick 2.9 import QtQuick.Controls 2.3 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.6 as Kirigami import org.kde.mauikit 1.0 as Maui import Player 1.0 import AlbumsList 1.0 import TracksList 1.0 import BaseModel 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 about.appIcon: "qrc:/assets/vvave.svg" about.appDescription: qsTr("VVAVE will handle your whole music collection by retreaving semantic information from the web. Just relax, enjoy and discover your new music ") showAccounts: false /***************************************************/ /******************** 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.position/1000) property alias isPlaying: player.playing property int onQueue: 0 property bool mainlistEmpty: !mainPlaylist.table.count > 0 /***************************************************/ /******************** HANDLERS ********************/ /*************************************************/ property int currentView: viewsIndex.tracks readonly property var viewsIndex: ({ tracks: 0, albums: 1, artists: 2, playlists: 3, search: 4, folders: 5, // cloud: 6, // vvave: 7, // linking: 8, youtube: 6, // spotify: 10 }) property string syncPlaylist: "" property bool sync: false property string infoMsg: "" property bool infoLabels: Maui.FM.loadSettings("LABELS", "PLAYBACK", false) == "true" ? true : false // property bool isLinked: false // property bool isServing: false // property bool focusMode : 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 = track.title + " by " + track.artist + " is missing" var messageBody = "Do you want to remove it from your collection?" notify("alert", message, messageBody, function () { // bae.removeTrack(currentTrack.url) //todo mainPlaylist.table.model.remove(mainPlaylist.table.currentIndex) }) } /*COMPONENTS*/ Player { id: player volume: 100 onFinishedChanged: if (!mainlistEmpty) { if (currentTrack.url) mainPlaylist.list.countUp(currentTrackIndex) Player.nextTrack() } } // BabeNotify // { // id: babeNotify //todo // } /* UI */ - altToolBars: false accentColor: babeColor // headBarFGColor: altColorText // headBarBGColor: "#212121" // altColorText: darkTextColor - floatingBar: false - headBar.spacing: space.big headBar.middleContent : Kirigami.ActionToolBar { // display: isWide ? ToolButton.TextBesideIcon : ToolButton.TextUnderIcon position: Controls.ToolBar.Header Layout.fillWidth: false hiddenActions: [ Kirigami.Action { text: qsTr("Folders") icon.name: "folder" checked: currentView === viewsIndex.folders checkable: false onTriggered: currentView = viewsIndex.folders }, Kirigami.Action { text: qsTr("YouTube") checkable: false icon.name: "internet-services" checked: currentView === viewsIndex.youtube onTriggered: currentView = viewsIndex.youtube } ] actions: [ Kirigami.Action { icon.name: "view-media-track" checked: currentView === viewsIndex.tracks // showIndicator: true // icon.color: active ? babeColor : altColorText onTriggered: currentView = viewsIndex.tracks text: qsTr("Tracks") checkable: false // colorScheme.highlightColor: babeColor // spacing: 0 }, Kirigami.Action { text: qsTr("Albums") checkable: false checked: currentView === viewsIndex.albums icon.name: /*"album"*/ "view-media-album-cover" // icon.color: currentView === viewsIndex.albums ? babeColor : altColorText onTriggered: currentView = viewsIndex.albums // colorScheme.highlightColor: babeColor // showIndicator: true }, Kirigami.Action { Layout.fillWidth: true text: qsTr("Artists") checkable: false checked: currentView === viewsIndex.artists icon.name: "view-media-artist" Kirigami.Theme.textColor: currentView === viewsIndex.artists ? babeColor : altColorText onTriggered: currentView = viewsIndex.artists // colorScheme.highlightColor: babeColor // showIndicator: true }, Kirigami.Action { Layout.fillWidth: true text: qsTr("Playlists") checkable: false checked: currentView === viewsIndex.playlists icon.name: "view-media-playlist" // icon.color: currentView === viewsIndex.playlists ? babeColor : altColorText onTriggered: currentView = viewsIndex.playlists // colorScheme.highlightColor: babeColor // showIndicator: true } ] } footBar.visible: !mainlistEmpty footBar.implicitHeight: footBar.visible ? toolBarHeight * 1.2 : 0 - page.footBarItem: ColumnLayout + page.footer: ColumnLayout { id: _footerLayout height: footBar.height width: root.width spacing: 0 Slider { id: progressBar Layout.preferredHeight: unit * (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: babeColor } } handle: Rectangle { x: progressBar.leftPadding + progressBar.visualPosition * (progressBar.availableWidth - width) y: -(progressBar.height * 0.8) implicitWidth: progressBar.pressed ? iconSizes.medium : 0 implicitHeight: progressBar.pressed ? iconSizes.medium : 0 radius: progressBar.pressed ? iconSizes.medium : 0 color: babeColor } } Kirigami.Separator { Layout.fillWidth: true color: borderColor } Maui.ToolBar { Layout.fillHeight: true Layout.fillWidth: true leftContent: ToolButton { icon.name: "headphones" visible: _drawer.modal + checked: _drawer.visible icon.color: _drawer.visible ? babeColor : textColor onClicked: _drawer.visible = !_drawer.visible Kirigami.Theme.highlightColor: babeColor // text: qsTr("Now") } middleContent: [ ToolButton { id: babeBtnIcon icon.name: "love" enabled: currentTrackIndex >= 0 icon.color: currentBabe ? babeColor : 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: textColor onClicked: Player.previousTrack() onPressAndHold: Player.playAt(prevTrackIndex) }, ToolButton { id: playIcon enabled: currentTrackIndex >= 0 icon.color: textColor icon.name: isPlaying ? "media-playback-pause" : "media-playback-start" onClicked: player.playing = !player.playing }, ToolButton { id: nextBtn icon.color: 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") } } ] } } // leftIcon.icon.color: currentView === viewsIndex.search ? babeColor : altColorText onSearchButtonClicked: { currentView = viewsIndex.search searchView.searchInput.forceActiveFocus() } InfoView { id: infoView maxWidth: parent.width * 0.8 maxHeight: parent.height * 0.9 } Maui.ShareDialog { id: shareDialog } Maui.FileDialog { id: fmDialog } 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: { fmDialog.onlyDirs = false fmDialog.filterType = Maui.FMList.AUDIO fmDialog.show(function(paths) { vvave.openUrls(paths) }) } }/*, 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: iconSize z: 999 Rectangle { id: infoBg anchors.fill: parent z: -999 color: altColor 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: altColor duration: 500 } } } Label { id: infoTxt anchors.centerIn: parent anchors.fill: parent height: parent.height width: parent.width font.pointSize: fontSizes.medium text: infoMsg horizontalAlignment: Qt.AlignHCenter verticalAlignment: Qt.AlignVCenter color: 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: textColor duration: 500 } } } } PlaylistDialog { id: playlistDialog } globalDrawer: Maui.GlobalDrawer { id: _drawer - width: Kirigami.Units.gridUnit * 18 + width: Math.min(Kirigami.Units.gridUnit * 18, root.width) height: root.height - root.headBar.implicitHeight - root.footBar.implicitHeight modal: !isWide handleVisible: false closePolicy: Popup.NoAutoClose contentItem: MainPlaylist { id: mainPlaylist z: 999 Connections { target: mainPlaylist onCoverPressed: Player.appendAll(tracks) onCoverDoubleClicked: Player.playAll(tracks) } } } ColumnLayout { anchors.fill: parent SwipeView { id: swipeView Layout.fillHeight: true Layout.fillWidth: true interactive: isMobile currentIndex: currentView onCurrentItemChanged: currentItem.forceActiveFocus() onCurrentIndexChanged: { currentView = currentIndex // if (!babeitView.isConnected && currentIndex === viewsIndex.vvave) // babeitView.logginDialog.open() } TracksView { id: tracksView Connections { target: tracksView onRowClicked: Player.addTrack(tracksView.list.get(index)) onQuickPlayTrack: Player.quickPlay(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) } } AlbumsView { id: albumsView holder.emoji: "qrc:/assets/MusicBox.png" holder.isMask: false holder.title : "No Albums!" holder.body: "Add new music sources" holder.emojiSize: iconSizes.huge - headBarTitle: count + qsTr(" albums") + title: count + qsTr(" albums") list.query: Albums.ALBUMS list.sortBy: Albums.ALBUM Connections { target: albumsView onRowClicked: 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 { 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: iconSizes.huge - headBarTitle: count + qsTr(" artists") + title: count + qsTr(" artists") list.query: Albums.ARTISTS list.sortBy: Albums.ARTIST table.list.sortBy: Tracks.NONE Connections { target: artistsView onRowClicked: 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 { id: playlistsView Connections { target: playlistsView onRowClicked: Player.addTrack(track) onQuickPlayTrack: 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 } } } SearchTable { id: searchView Connections { target: searchView onRowClicked: Player.addTrack(searchView.list.get(index)) onQuickPlayTrack: Player.quickPlay(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.searchTable.model.get( index).album) query = query.arg(searchView.searchTable.model.get( index).artist) mainPlaylist.list.clear() mainPlaylist.list.sortBy = Tracks.NONE mainPlaylist.list.query = query Player.playAll() } } } FoldersView { id: foldersView Connections { target: foldersView.list onRowClicked: Player.addTrack(foldersView.list.model.get(index)) onQuickPlayTrack: Player.quickPlay(foldersView.list.model.get(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) } } // CloudView // { // id: cloudView // onQuickPlayTrack: Player.quickPlay(cloudView.list.get(index)) // } // BabeitView // { // id: babeitView // } // LinkingView // { // id: linkingView // } YouTube { id: youtubeView } // Spotify // { // id: spotifyView // } } Maui.SelectionBar { id: _selectionBar property alias listView: _selectionBar.selectionList Layout.fillWidth: true Layout.margins: space.big Layout.topMargin: space.small Layout.bottomMargin: space.big onIconClicked: _contextMenu.popup() onExitClicked: clear() colorScheme.backgroundColor: "#212121" model: BaseModel { list: _selectionBarModelList } Tracks { id: _selectionBarModelList } SelectionBarMenu { id: _contextMenu } function append(item) { if(selectedPaths.indexOf(item.path) < 0) { selectedItems.push(item) selectedPaths.push(item.path) // for(var i = 0; i < selectionList.count ; i++ ) // if(selectionList.model.get(i).path === item.path) // { // selectionList.model.remove(i) // return // } selectionList.model.list.append(item) selectionList.positionViewAtEnd() if(position === Qt.Vertical) return if(typeof(riseContent) === "undefined") return riseContent() } } } } /*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() +// 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) } } } diff --git a/models/basemodel.cpp b/models/basemodel.cpp index 690dfe1..e819c41 100644 --- a/models/basemodel.cpp +++ b/models/basemodel.cpp @@ -1,123 +1,126 @@ #include "basemodel.h" #include "baselist.h" BaseModel::BaseModel(QObject *parent) : QAbstractListModel(parent), mList(nullptr) {} int BaseModel::rowCount(const QModelIndex &parent) const { if (parent.isValid() || !mList) return 0; return mList->items().size(); } QVariant BaseModel::data(const QModelIndex &index, int role) const { if (!index.isValid() || !mList) return QVariant(); return mList->items().at(index.row())[static_cast(role)]; } bool BaseModel::setData(const QModelIndex &index, const QVariant &value, int role) { if (!mList) return false; if (mList->update(index.row(), value, role)) { emit dataChanged(index, index, QVector() << role); return true; } return false; } Qt::ItemFlags BaseModel::flags(const QModelIndex &index) const { if (!index.isValid()) return Qt::NoItemFlags; return Qt::ItemIsEditable; // FIXME: Implement me! } QHash BaseModel::roleNames() const { QHash names; for(auto key : FMH::MODEL_NAME.keys()) names[key] = QString(FMH::MODEL_NAME[key]).toUtf8(); return names; } BaseList *BaseModel::getList() const { return this->mList; } void BaseModel::setList(BaseList *value) { beginResetModel(); if(mList) mList->disconnect(this); mList = value; if(mList) { connect(this->mList, &BaseList::preItemAppended, this, [=]() { const int index = mList->items().size(); beginInsertRows(QModelIndex(), index, index); }); connect(this->mList, &BaseList::postItemAppended, this, [=]() { endInsertRows(); }); connect(this->mList, &BaseList::preItemAppendedAt, this, [=](int index) { beginInsertRows(QModelIndex(), index, index); }); connect(this->mList, &BaseList::preItemRemoved, this, [=](int index) { beginRemoveRows(QModelIndex(), index, index); }); connect(this->mList, &BaseList::postItemRemoved, this, [=]() { endRemoveRows(); }); connect(this->mList, &BaseList::updateModel, this, [=](int index, QVector roles) { emit this->dataChanged(this->index(index), this->index(index), roles); }); connect(this->mList, &BaseList::preListChanged, this, [=]() { beginResetModel(); }); connect(this->mList, &BaseList::postListChanged, this, [=]() { endResetModel(); }); } endResetModel(); } QVariantMap BaseModel::get(const int &index) const { + if(this->mList) return this->mList->get(index); + + return QVariantMap(); } void BaseModel::clear() { this->mList->clear(); } diff --git a/models/playlists/playlistsmodel.cpp b/models/playlists/playlistsmodel.cpp index 0ec5776..eec3c06 100644 --- a/models/playlists/playlistsmodel.cpp +++ b/models/playlists/playlistsmodel.cpp @@ -1,257 +1,259 @@ #include "playlistsmodel.h" #include "db/collectionDB.h" PlaylistsModel::PlaylistsModel(QObject *parent) : BaseList(parent), db(CollectionDB::getInstance()) { this->setList(); } FMH::MODEL_LIST PlaylistsModel::items() const { return this->list; } void PlaylistsModel::setSortBy(const SORTBY &sort) { if(this->sort == sort) return; this->sort = sort; this->preListChanged(); this->sortList(); this->postListChanged(); emit this->sortByChanged(); } PlaylistsModel::SORTBY PlaylistsModel::getSortBy() const { return this->sort; } void PlaylistsModel::sortList() { const auto key = static_cast(this->sort); qDebug()<< "SORTING LIST BY"<< this->sort; qSort(this->list.begin() + this->defaultPlaylists().size(), this->list.end(), [key](const FMH::MODEL &e1, const FMH::MODEL &e2) -> bool { auto role = key; switch(role) { case FMH::MODEL_KEY::ADDDATE: { auto currentTime = QDateTime::currentDateTime(); auto date1 = QDateTime::fromString(e1[role], Qt::TextDate); auto date2 = QDateTime::fromString(e2[role], Qt::TextDate); if(date1.secsTo(currentTime) < date2.secsTo(currentTime)) return true; break; } case FMH::MODEL_KEY::TITLE: { 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 PlaylistsModel::setList() { qDebug()<< "trying to set playlists list"; emit this->preListChanged(); this->list << this->db->getPlaylists(); this->list << this->defaultPlaylists(); + qDebug()<< this->list; + // this->sortList(); emit this->postListChanged(); } FMH::MODEL PlaylistsModel::packPlaylist(const QString &playlist) { return FMH::MODEL { {FMH::MODEL_KEY::PLAYLIST, playlist}, {FMH::MODEL_KEY::ADDDATE, QDateTime::currentDateTime().toString(Qt::DateFormat::TextDate)} // {FMH::MODEL_KEY::ICON, "view-media-playlist"} }; } FMH::MODEL_LIST PlaylistsModel::defaultPlaylists() { return FMH::MODEL_LIST { { {FMH::MODEL_KEY::PLAYLIST, "Most Played"}, {FMH::MODEL_KEY::ICON, "view-media-playcount"}, {FMH::MODEL_KEY::ADDDATE,QDateTime::currentDateTime().toString(Qt::DateFormat::TextDate)} }, { {FMH::MODEL_KEY::PLAYLIST, "Rating"}, {FMH::MODEL_KEY::ICON, "view-media-favorite"}, {FMH::MODEL_KEY::ADDDATE,QDateTime::currentDateTime().toString(Qt::DateFormat::TextDate)} }, { {FMH::MODEL_KEY::PLAYLIST, "Recent"}, {FMH::MODEL_KEY::ICON, "view-media-recent"}, {FMH::MODEL_KEY::ADDDATE,QDateTime::currentDateTime().toString(Qt::DateFormat::TextDate)} }, { {FMH::MODEL_KEY::PLAYLIST, "Favs"}, {FMH::MODEL_KEY::ICON, "love"}, {FMH::MODEL_KEY::ADDDATE,QDateTime::currentDateTime().toString(Qt::DateFormat::TextDate)} }, { {FMH::MODEL_KEY::PLAYLIST, "Online"}, {FMH::MODEL_KEY::ICON, "internet-services"}, {FMH::MODEL_KEY::ADDDATE,QDateTime::currentDateTime().toString(Qt::DateFormat::TextDate)} }, // { // {FMH::MODEL_KEY::PLAYLIST, "Tags"}, // {FMH::MODEL_KEY::ICON, "tag"}, // {FMH::MODEL_KEY::ADDDATE,QDateTime::currentDateTime().toString(Qt::DateFormat::TextDate)} // }, // { // {FMH::MODEL_KEY::PLAYLIST, "Relationships"}, // {FMH::MODEL_KEY::ICON, "view-media-similarartists"}, // {FMH::MODEL_KEY::ADDDATE,QDateTime::currentDateTime().toString(Qt::DateFormat::TextDate)} // }, // { // {FMH::MODEL_KEY::PLAYLIST, "Popular"}, // {FMH::MODEL_KEY::ICON, "view-media-chart"}, // {FMH::MODEL_KEY::ADDDATE,QDateTime::currentDateTime().toString(Qt::DateFormat::TextDate)} // }, // { // {FMH::MODEL_KEY::PLAYLIST, "Genres"}, // {FMH::MODEL_KEY::ICON, "view-media-genre"}, // {FMH::MODEL_KEY::ADDDATE,QDateTime::currentDateTime().toString(Qt::DateFormat::TextDate)} // } }; } QVariantMap PlaylistsModel::get(const int &index) const { if(index >= this->list.size() || index < 0) return QVariantMap(); return FM::toMap(this->list.at(index)); } void PlaylistsModel::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 PlaylistsModel::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 PlaylistsModel::insert(const QString &playlist) { if(playlist.isEmpty()) return; emit this->preItemAppended(); this->list << this->packPlaylist(playlist); emit this->postItemAppended(); } void PlaylistsModel::insertAt(const QString &playlist, const int &at) { if(playlist.isEmpty()) return; if(at > this->list.size() || at < 0) return; emit this->preItemAppendedAt(at); if(this->db->addPlaylist(playlist)) this->list.insert(at, this->packPlaylist(playlist)); emit this->postItemAppended(); } void PlaylistsModel::addTrack(const int &index, const QStringList &urls) { if(index >= this->list.size() || index < 0) return; for(auto url : urls) this->db->trackPlaylist(url, this->list[index][FMH::MODEL_KEY::PLAYLIST]); } void PlaylistsModel::removeTrack(const int &index, const QString &url) { if(index >= this->list.size() || index < 0) return; this->db->removePlaylistTrack(url, this->list.at(index)[FMH::MODEL_KEY::PLAYLIST]); } void PlaylistsModel::removePlaylist(const int &index) { if(index >= this->list.size() || index < 0) return; if(this->db->removePlaylist(this->list.at(index)[FMH::MODEL_KEY::PLAYLIST])) { emit this->preItemRemoved(index); this->list.removeAt(index); emit this->postItemRemoved(); } } diff --git a/services/web/YouTube.qml b/services/web/YouTube.qml index 207c5c7..7a3345a 100644 --- a/services/web/YouTube.qml +++ b/services/web/YouTube.qml @@ -1,286 +1,292 @@ import QtQuick 2.9 import QtQuick.Controls 2.2 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 - margins: 0 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.Popup { id: configPopup parent: parent margins: contentMargins GridLayout { anchors.centerIn: parent width: parent.width*0.8 height: parent.height*0.9 columns: 1 rows: 6 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: 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: 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: true - headBarExit: true - headBarExitIcon: "edit-clear" - headBarTitle: "YouTube" holder.emoji: "qrc:/assets/Astronaut.png" holder.isMask: false holder.title : "No Results!" holder.body: "Try with another query" holder.emojiSize: iconSizes.huge coverArtVisible: true trackDuration: true trackRating: true - onExit: clearSearch() isArtworkRemote: true allowMenu: false model: ListModel{} // appendBtn.visible: false // playAllBtn.visible: false + headBar.leftContent: ToolButton + { + icon.name: "edit-clear" + onClicked: clearSearch() + } + + headBar.middleContent: Label + { + text: "YouTube" + } + headBar.rightContent: ToolButton { id: menuBtn icon.name: "application-menu" onClicked: configPopup.open() } onRowClicked: { watchVideo(youtubeTable.model.get(index)) } onQuickPlayTrack: { playTrack(youtubeTable.model.get(index).url) } } YoutubeViewer { id: youtubeViewer } } 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.headBarTitle) { youtubeTable.headBarTitle = searchTxt youtube.getQuery(searchTxt, Maui.FM.loadSettings("YOUTUBELIMIT", "BABE", 25)) } } function clearSearch() { searchInput.clear() youtubeTable.clearTable() youtubeTable.headBarTitle = "" searchRes = [] } function populate(tracks) { youtubeTable.model.clear() for(var i in tracks) youtubeTable.model.append(tracks[i]) } } diff --git a/services/web/YoutubeViewer.qml b/services/web/YoutubeViewer.qml index 38fd20a..c6a7442 100644 --- a/services/web/YoutubeViewer.qml +++ b/services/web/YoutubeViewer.qml @@ -1,45 +1,48 @@ import QtQuick 2.9 import QtQuick.Controls 2.2 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 : ({}) - margins: 0 - headBarExitIcon: "go-previous" - onExit: stackView.pop(youtubeTable) - headBarTitle: currentYt ? currentYt.title : "YouTube" + 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/view_models/BabeGrid/BabeGrid.qml b/view_models/BabeGrid/BabeGrid.qml index 0668a3b..72db18d 100644 --- a/view_models/BabeGrid/BabeGrid.qml +++ b/view_models/BabeGrid/BabeGrid.qml @@ -1,105 +1,105 @@ import QtQuick.Controls 2.2 import QtQuick 2.9 import ".." import org.kde.kirigami 2.0 as Kirigami import org.kde.mauikit 1.0 as Maui import BaseModel 1.0 import AlbumsList 1.0 Maui.Page { id: gridPage // readonly property int screenSize : bae.screenGeometry("width")*bae.screenGeometry("height"); // property int hintSize : Math.sqrt(root.width*root.height)*0.3 property int albumCoverSize: Math.min(iconSizes.enormous, width * 0.3) readonly property int albumSpacing: albumCoverSize * 0.3 + space.small property int albumCoverRadius : radiusV property bool albumCardVisible : true property alias list: _albumsList property alias listModel: _albumsModel property alias grid: grid property alias holder: holder property alias count: grid.count signal albumCoverClicked(string album, string artist) signal albumCoverPressed(string album, string artist) signal bgClicked() - margins: space.medium - topMargin: space.big +// margins: space.medium +// topMargin: space.big MouseArea { anchors.fill: parent onClicked: bgClicked() } Maui.Holder { id: holder visible: grid.count === 0 } Albums { id: _albumsList } BaseModel { id: _albumsModel list: _albumsList } Maui.GridView { id: grid onAreaClicked: bgClicked() adaptContent: true - width: parent.width - height: parent.height + anchors.fill: parent + anchors.topMargin: space.big itemSize: albumCoverSize spacing: albumSpacing cellWidth: albumCoverSize + spacing cellHeight: albumCoverSize + spacing*2 model: _albumsModel delegate: BabeAlbum { id: albumDelegate albumSize : grid.itemSize albumRadius: albumCoverRadius albumCard: albumCardVisible height: grid.cellHeight width: grid.cellWidth 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 f689bfd..66e56b0 100644 --- a/view_models/BabeList.qml +++ b/view_models/BabeList.qml @@ -1,87 +1,84 @@ import QtQuick 2.9 import QtQuick.Controls 2.2 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 : holder property alias section : babeList.section property bool wasPulled : false signal pulled() focus: true - margins: 0 Maui.Holder { id: holder visible: babeList.count === 0 focus: true } - - Maui.ListBrowser { id: babeList anchors.fill: parent clip: true // listView.highlight: Rectangle // { // width: babeList.width // height: babeList.currentItem.height // color: highlightColor // } // Keys.onUpPressed: decrementCurrentIndex() // Keys.onDownPressed: incrementCurrentIndex() // Keys.onReturnPressed: rowClicked(currentIndex) // Keys.onEnterPressed: quickPlayTrack(currentIndex) // boundsBehavior: !isMobile? Flickable.StopAtBounds : Flickable.OvershootBounds // flickableDirection: Flickable.AutoFlickDirection // snapMode: isMobile? ListView.SnapToItem : ListView.NoSnap // addDisplaced: Transition // { // NumberAnimation { properties: "x,y"; duration: 100 } // } // ScrollBar.vertical:BabeScrollBar { visible: !isMobile} // onContentYChanged: // { // if(contentY < -120) // wasPulled = true // if(contentY == 0 && wasPulled) // { pulled(); wasPulled = false} // } // Scroll is too fast on desktop, see QTBUG-56075 // https://bugreports.qt.io/browse/QTBUG-56075 // ScrollHelper // { // enabled: !isMobile // id: scrollHelper // flickable: babeList // anchors.fill: babeList // } } } diff --git a/view_models/BabeTable/BabeTable.qml b/view_models/BabeTable/BabeTable.qml index 8c8fcfe..b57f7e2 100644 --- a/view_models/BabeTable/BabeTable.qml +++ b/view_models/BabeTable/BabeTable.qml @@ -1,447 +1,446 @@ import QtQuick 2.9 import QtQuick.Controls 2.2 import QtQuick.Layouts 1.3 import org.kde.kirigami 2.6 as Kirigami import org.kde.mauikit 1.0 as Maui import BaseModel 1.0 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: babeTableRoot // cacheBuffer : 300 property alias list : _tracksList property alias listModel : _tracksModel property alias removeDialog : _removeDialog property bool trackNumberVisible property bool quickPlayVisible : true property bool coverArtVisible : false property bool menuItemVisible : isMobile property bool trackDuration property bool trackRating property bool allowMenu: true property bool isArtworkRemote : false property bool showIndicator : false 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 rowPressed(int index) signal quickPlayTrack(int index) signal queueTrack(int index) signal artworkDoubleClicked(int index) signal playAll() signal appendAll() // altToolBars: true onGroupChanged: groupBy() focus: true //headBar.middleStrech: false headBar.leftSretch: false - headBar.rightContent: Kirigami.ActionToolBar { position: Controls.ToolBar.Header Layout.fillWidth: true actions: [ Kirigami.Action { id : playAllBtn text: qsTr("Play all") icon.name : "media-playlist-play" onTriggered: playAll() }, Kirigami.Action { id: appendBtn text: qsTr("Append") icon.name : "media-playlist-append"//"media-repeat-track-amarok" onTriggered: appendAll() }, Kirigami.Action { id: sortBtn text: qsTr("Sort") icon.name: "view-sort" Kirigami.Action { text: qsTr("Title") checkable: true checked: list.sortBy === Tracks.TITLE onTriggered: list.sortBy = Tracks.TITLE } -// Kirigami.Action -// { -// text: qsTr("Track") -// checkable: true -// checked: list.sortBy === Tracks.TRACK -// onTriggered: list.sortBy = Tracks.TRACK -// } - -// Kirigami.Action -// { -// text: qsTr("Artist") -// checkable: true -// checked: list.sortBy === Tracks.ARTIST -// onTriggered: list.sortBy = Tracks.ARTIST -// } - -// Kirigami.Action -// { -// text: qsTr("Album") -// checkable: true -// checked: list.sortBy === Tracks.ALBUM -// onTriggered: list.sortBy = Tracks.ALBUM -// } - -// Kirigami.Action -// { -// text: qsTr("Most played") -// checkable: true -// checked: list.sortBy === Tracks.COUNT -// onTriggered: list.sortBy = Tracks.COUNT -// } - -// Kirigami.Action -// { -// text: qsTr("Rate") -// checkable: true -// checked: list.sortBy === Tracks.RATE -// onTriggered: list.sortBy = Tracks.RATE -// } - -// Kirigami.Action -// { -// text: qsTr("Fav") -// checkable: true -// checked: list.sortBy === Tracks.FAV -// onTriggered: list.sortBy = Tracks.FAV -// } - -// Kirigami.Action -// { -// text: qsTr("Release date") -// checkable: true -// checked: list.sortBy === Tracks.RELEASEDATE -// onTriggered: list.sortBy = Tracks.RELEASEDATE -// } - -// Kirigami.Action -// { -// text: qsTr("Add date") -// checkable: true -// checked: list.sortBy === Tracks.ADDDATE -// onTriggered: list.sortBy = Tracks.ADDDATE -// } - - -// Kirigami.Action -// { -// text: qsTr("Group") -// checkable: true -// checked: group -// onTriggered: group = !group -// } + Kirigami.Action + { + text: qsTr("Track") + checkable: true + checked: list.sortBy === Tracks.TRACK + onTriggered: list.sortBy = Tracks.TRACK + } + + Kirigami.Action + { + text: qsTr("Artist") + checkable: true + checked: list.sortBy === Tracks.ARTIST + onTriggered: list.sortBy = Tracks.ARTIST + } + + Kirigami.Action + { + text: qsTr("Album") + checkable: true + checked: list.sortBy === Tracks.ALBUM + onTriggered: list.sortBy = Tracks.ALBUM + } + + Kirigami.Action + { + text: qsTr("Most played") + checkable: true + checked: list.sortBy === Tracks.COUNT + onTriggered: list.sortBy = Tracks.COUNT + } + + Kirigami.Action + { + text: qsTr("Rate") + checkable: true + checked: list.sortBy === Tracks.RATE + onTriggered: list.sortBy = Tracks.RATE + } + + Kirigami.Action + { + text: qsTr("Fav") + checkable: true + checked: list.sortBy === Tracks.FAV + onTriggered: list.sortBy = Tracks.FAV + } + + Kirigami.Action + { + text: qsTr("Release date") + checkable: true + checked: list.sortBy === Tracks.RELEASEDATE + onTriggered: list.sortBy = Tracks.RELEASEDATE + } + + Kirigami.Action + { + text: qsTr("Add date") + checkable: true + checked: list.sortBy === Tracks.ADDDATE + onTriggered: list.sortBy = Tracks.ADDDATE + } + + + Kirigami.Action + { + text: qsTr("Group") + checkable: true + checked: group + onTriggered: group = !group + } }, Kirigami.Action { text: qsTr("Select") icon.name: "item-select" onTriggered: selectionMode = !selectionMode checkable: false checked: selectionMode } ] } 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") // rejectButton.icon.name: "archive-remove" acceptButton.text: qsTr("Remove") 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)]) 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: { isAndroid ? Maui.Android.shareDialog(list.get(listView.currentIndex)) : shareDialog.show([list.get(listView.currentIndex).url]) } } section.criteria: ViewSection.FullString section.delegate: Maui.LabelDelegate { id: _sectionDelegate label: section isSection: true boldLabel: true colorScheme.backgroundColor: "#333" colorScheme.textColor: "#fafafa" background: Rectangle { color: colorScheme.backgroundColor } } BaseModel { id: _tracksModel list: _tracksList } Tracks { id: _tracksList onSortByChanged: if(babeTableRoot.group) babeTableRoot.groupBy() } model: _tracksModel // property alias animBabe: delegate.animBabe delegate: TableDelegate { id: delegate width: listView.width number : trackNumberVisible ? true : false quickPlay: quickPlayVisible coverArt : coverArtVisible ? (babeTableRoot.width > 300) : coverArtVisible trackDurationVisible : trackDuration trackRatingVisible : trackRating menuItem: menuItemVisible remoteArtwork: isArtworkRemote playingIndicator: showIndicator onPressAndHold: if(isMobile && allowMenu) openItemMenu(index) onRightClicked: if(allowMenu) openItemMenu(index) onClicked: { currentIndex = index if(selectionMode) { H.addToSelection(listView.model.get(listView.currentIndex)) return } if(isMobile) rowClicked(index) } onDoubleClicked: { currentIndex = index if(!isMobile) rowClicked(index) } onPlay: { currentIndex = index quickPlayTrack(index) } onArtworkCoverClicked: { currentIndex = index goToAlbum() } } function openItemMenu(index) { currentIndex = index contextMenu.rate = list.get(currentIndex).rate contextMenu.fav = list.get(currentIndex).fav == "1" contextMenu.popup() rowPressed(index) console.log(list.get(currentIndex).fav) } function saveList() { var trackList = [] if(model.count > 0) { for(var i = 0; i < model.count; ++i) trackList.push(model.get(i).url) playlistDialog.tracks = trackList playlistDialog.open() } } function queueList() { var trackList = [] if(model.count > 0) { for(var i = 0; i < model.count; ++i) trackList.push(model.get(i)) Player.queueTracks(trackList) } } function goToAlbum() { root.currentView = viewsIndex.albums var item = listView.model.get(listView.currentIndex) albumsView.populateTable(item.album, item.artist) contextMenu.close() } function goToArtist() { root.currentView = viewsIndex.artists var item = listView.model.get(listView.currentIndex) artistsView.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 f9e7ede..dc513b6 100644 --- a/view_models/BabeTable/PlaylistDialog.qml +++ b/view_models/BabeTable/PlaylistDialog.qml @@ -1,111 +1,112 @@ import QtQuick 2.0 import QtQuick.Controls 2.2 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 * unit + page.padding: 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.LabelDelegate { id: delegate label: model.playlist Connections { target: delegate onClicked: playlistsList.currentIndex = index onPressAndHold: { playlistsList.currentIndex = index insert() } } } } RowLayout { Layout.fillWidth: true Maui.TextField { Layout.fillWidth: true id: newPlaylistField color: textColor placeholderText: qsTr("New playlist") onAccepted: { addPlaylist() playlistsView.playlistList.addTrack(playlistsList.listView.currentIndex, tracks) clear() } } ToolButton { icon.name: "checkbox" icon.color: 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/widgets/AlbumsView.qml b/widgets/AlbumsView.qml index fe7e439..f0714aa 100644 --- a/widgets/AlbumsView.qml +++ b/widgets/AlbumsView.qml @@ -1,244 +1,240 @@ import QtQuick 2.9 import QtQuick.Controls 2.2 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 +// property alias tagBar : tagBar signal rowClicked(var track) signal playTrack(var track) signal queueTrack(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: space.large onAlbumCoverPressed: albumCoverPressedAndHold(album, artist) headBar.visible: false - headBarExit: 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: unit * 600 + widthHint: 1 + heightHint: 1 defaultButtons: false - page.margins: 0 + page.padding: 0 // verticalAlignment: Qt.AlignBottom ColumnLayout { id: albumFilter anchors.fill: parent spacing: 0 BabeTable { id: albumsViewTable Layout.fillHeight: true Layout.fillWidth: true trackNumberVisible: true trackRating: true headBar.visible: true - headBarExit: false coverArtVisible: true quickPlayVisible: true focus: true list.sortBy: Tracks.TRACK headBar.plegable: false - holder.emoji: "qrc:/assets/ElectricPlug.png" holder.isMask: false holder.title : "Oops!" holder.body: "This list is empty" holder.emojiSize: iconSizes.huge onRowClicked: { albumsViewGrid.rowClicked(model.get(index)) } onQuickPlayTrack: { albumsViewGrid.playTrack(model.get(index)) } onQueueTrack: { albumsViewGrid.queueTrack(model.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) - } +// 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) - albumsView.table.headBarTitle = album + albumsView.table.title = album tagq = Q.GET.albumTags_.arg(album) }else if(artist && album === undefined) { query = Q.GET.artistTracks_.arg(artist) - artistsView.table.headBarTitle = artist + artistsView.table.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) 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/MainPlaylist/AlbumsRoll.qml b/widgets/MainPlaylist/AlbumsRoll.qml index b2182ad..de152cf 100644 --- a/widgets/MainPlaylist/AlbumsRoll.qml +++ b/widgets/MainPlaylist/AlbumsRoll.qml @@ -1,130 +1,130 @@ import QtQuick.Controls 2.2 import QtQuick 2.9 import QtQuick.Layouts 1.3 import "../../view_models/BabeGrid" import org.kde.kirigami 2.0 as Kirigami import "../../utils/Player.js" as Player ListView { id: albumsRollRoot orientation: ListView.Horizontal clip: true focus: true interactive: true currentIndex: currentTrackIndex 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) // positionViewAtIndex(index, ListView.Center) } // onCurrentIndexChanged: Player.playAt(currentIndex) delegate: GridLayout { height: albumsRollRoot.height width: albumsRollRoot.width clip: true columns: 2 rows: 2 rowSpacing: space.tiny columnSpacing: space.big BabeAlbum { id: delegate Layout.row: 1 Layout.rowSpan: 2 Layout.column: 1 Layout.preferredWidth: iconSizes.big + space.big Layout.fillHeight: true albumSize : iconSizes.big + space.big albumRadius : radiusV showLabels: false showIndicator: false hideRepeated: false // increaseCurrentItem : true Connections { target: delegate onClicked: { albumsRollRoot.currentIndex = index play(index) } } } Label { Layout.row: 1 Layout.column: 2 Layout.fillWidth: true Layout.fillHeight: true text: model.title color: textColor font.pointSize: fontSizes.default verticalAlignment: Qt.AlignBottom clip: true wrapMode: Text.WrapAtWordBoundaryOrAnywhere elide: Text.ElideRight } Label { Layout.row: 2 Layout.column: 2 Layout.fillWidth: true Layout.fillHeight: true text: model.artist + " | " + model.album font.pointSize: fontSizes.small verticalAlignment: Qt.AlignTop clip: true color: textColor elide: Text.ElideRight wrapMode: Text.WrapAtWordBoundaryOrAnywhere } } MouseArea { anchors.fill : parent preventStealing: true - parent: applicationWindow().overlay.parent +// parent: applicationWindow().overlay.parent onPressed: { console.log("albumsroll clicked") mouse.accepted = false } onReleased: { mouse.accepted = true } } function positionAlbum(index) { albumsRollRoot.currentIndex = index positionViewAtIndex(index, ListView.Center) } } diff --git a/widgets/MainPlaylist/MainPlaylist.qml b/widgets/MainPlaylist/MainPlaylist.qml index 2bf4aef..4aa3f01 100644 --- a/widgets/MainPlaylist/MainPlaylist.qml +++ b/widgets/MainPlaylist/MainPlaylist.qml @@ -1,214 +1,205 @@ import QtQuick 2.9 import QtQuick.Controls 2.2 import QtQuick.Layouts 1.3 import QtGraphicalEffects 1.0 import org.kde.kirigami 2.2 as Kirigami import org.kde.mauikit 1.0 as Maui import "../../utils/Player.js" as Player import "../../db/Queries.js" as Q import "../../utils" import "../../widgets" import "../../view_models" import "../../view_models/BabeTable" Maui.Page { id: mainPlaylistRoot property alias albumsRoll : albumsRoll property alias list : table.list property alias listModel: table.listModel property alias listView : table.listView property alias table: table property alias menu : playlistMenu property alias contextMenu: table.contextMenu signal coverDoubleClicked(var tracks) signal coverPressed(var tracks) focus: true - - margins: 0 headBar.visible: false PlaylistMenu { id: playlistMenu onClearOut: Player.clearOutPlaylist() // onHideCover: cover.visible = !cover.visible onClean: Player.cleanPlaylist() onSaveToClicked: table.saveList() } footBar.visible: !mainlistEmpty footBar.implicitHeight: toolBarHeight * 1.3 - footBarItem: AlbumsRoll + footBar.middleContent: AlbumsRoll { - anchors.fill : parent - anchors.leftMargin: space.small - anchors.rightMargin: space.small +// height: toolBarHeight * 1.3 + Layout.fillWidth: true + Layout.fillHeight: true id: albumsRoll } - footBar.background: Rectangle + footBar.background: Item { id: footerBg clip : true height: footBar.implicitHeight - color: "transparent" Image { id: artworkBg height: parent.height width: parent.width sourceSize.width: parent.width sourceSize.height: parent.height fillMode: Image.PreserveAspectCrop cache: true antialiasing: true smooth: true asynchronous: true source: "file://"+encodeURIComponent(currentArtwork) } FastBlur { id: fastBlur anchors.fill: parent y:1 source: artworkBg radius: 100 transparentBorder: false cached: true z:1 clip: true Rectangle { anchors.fill: parent color: viewBackgroundColor opacity: 0.85 } } } ColumnLayout { id: playlistLayout anchors.fill: parent width: parent.width spacing: 0 // anchors.bottom: mainPlaylistRoot.searchBox BabeTable { id: table Layout.fillWidth: true Layout.fillHeight: true Layout.alignment: Qt.AlignBottom | Qt.AlignTop focus: true headBar.visible: false footBar.visible: false quickPlayVisible: false coverArtVisible: true trackRating: true showIndicator : true menuItemVisible: false holder.emoji: "qrc:/assets/Radio.png" holder.isMask: false holder.title : "Meh!" holder.body: "Start putting together your playlist!" holder.emojiSize: iconSizes.huge onRowClicked: play(index) onArtworkDoubleClicked: contextMenu.babeIt(index) Component.onCompleted: { var lastplaylist = Maui.FM.loadSettings("LASTPLAYLIST", "PLAYLIST", []) var n = lastplaylist.length if(n>0) { for(var i = 0; i < n; i++) { var where = "url = \""+lastplaylist[i]+"\"" var query = Q.GET.tracksWhere_.arg(where) table.list.appendQuery(query); } }else { where = "fav = 1" query = Q.GET.tracksWhere_.arg(where) table.list.appendQuery(query); } // if(autoplay) // Player.playAt(0) } - } - - Kirigami.Separator - { - Layout.fillWidth: true - color: borderColor - } + } } // function goFocusMode() // { // if(focusMode) // { // if(isMobile) // { // root.width = screenWidth // root.height= screenHeight // }else // { // cover.y = 0 // root.maximumWidth = screenWidth // root.minimumWidth = columnWidth // root.maximumHeight = screenHeight // root.minimumHeight = columnWidth // root.width = columnWidth // root.height = 700 // } // }else // { // if(isMobile) // { // }else // { // root.maximumWidth = columnWidth // root.minimumWidth = columnWidth // root.maximumHeight = columnWidth // root.minimumHeight = columnWidth // // root.footer.visible = false // // mainlistContext.visible = false // } // } // focusMode = !focusMode // } function play(index) { prevTrackIndex = currentTrackIndex Player.playAt(index) } } diff --git a/widgets/PlaylistsView/PlaylistsView.qml b/widgets/PlaylistsView/PlaylistsView.qml index f3f068b..318f401 100644 --- a/widgets/PlaylistsView/PlaylistsView.qml +++ b/widgets/PlaylistsView/PlaylistsView.qml @@ -1,229 +1,218 @@ import QtQuick 2.9 import QtQuick.Layouts 1.3 import QtQuick.Controls 2.2 import org.kde.kirigami 2.6 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 clip: true 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" +// 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: {} } } - - onExit: playlistSwipe.currentIndex = 0 } - } ColorTagsBar { Layout.fillWidth: true height: rowHeightAlt recSize: isMobile ? iconSize : 16 - onColorClicked: populate(Q.GET.colorTracks_.arg(color.toLowerCase())) - } Maui.Dialog { id: _filterDialog parent: parent maxHeight: maxWidth maxWidth: unit * 600 defaultButtons: false - page.margins: 0 BabeTable { id: filterList anchors.fill: parent clip: true quickPlayVisible: true coverArtVisible: true trackRating: true trackDuration: false headBar.visible: !holder.visible - headBarExit: false - headBarTitle: playlistViewModel.list.get(playlistViewModel.currentIndex).playlist - - + title: playlistViewModel.list.get(playlistViewModel.currentIndex).playlist holder.emoji: "qrc:/assets/Electricity.png" holder.isMask: false holder.title : playlistViewModel.model.get(playlistViewModel.currentIndex).playlist holder.body: "Your playlist is empty,
start adding new music to it" holder.emojiSize: 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 boldLabel: true labelTxt.font.family: "Material Design Icons" } Connections { target: filterList onRowClicked: control.rowClicked(filterList.model.get(index)) onQuickPlayTrack: control.quickPlayTrack(filterList.model.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) filterList.clearTable() } } diff --git a/widgets/PlaylistsView/PlaylistsViewModel.qml b/widgets/PlaylistsView/PlaylistsViewModel.qml index 1123d3e..e40e28c 100644 --- a/widgets/PlaylistsView/PlaylistsViewModel.qml +++ b/widgets/PlaylistsView/PlaylistsViewModel.qml @@ -1,150 +1,147 @@ import QtQuick 2.9 import QtQuick.Layouts 1.3 import QtQuick.Controls 2.2 import org.kde.kirigami 2.6 as Kirigami import org.kde.mauikit 1.0 as Maui import PlaylistsList 1.0 import BaseModel 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) - headBarExit: false - headBarTitle: "Playlists" + title: "Playlists" Maui.NewDialog { id: newPlaylistDialog title: qsTr("New Playlist...") onFinished: addPlaylist(text) acceptText: qsTr("Create") rejectButton.visible: false } - signal playSync(int index) - headBar.plegable: false - headBar.rightContent: Kirigami.ActionToolBar { Layout.fillWidth: true actions: [ Kirigami.Action { text: qsTr("Remove") icon.name: "list-remove" onTriggered: removePlaylist() }, Kirigami.Action { id : createPlaylistBtn text: qsTr("Add") icon.name : "list-add" onTriggered : newPlaylistDialog.open() } ] } 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/SearchTable.qml b/widgets/SearchView/SearchTable.qml index d266a50..3a4c941 100644 --- a/widgets/SearchView/SearchTable.qml +++ b/widgets/SearchView/SearchTable.qml @@ -1,122 +1,125 @@ import QtQuick 2.9 import QtQuick.Controls 2.2 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 - headBarExit: true - headBarExitIcon: "edit-clear" holder.emoji: "qrc:/assets/BugSearch.png" holder.isMask: false holder.title : "No search results!" holder.body: "Try with another query" holder.emojiSize: iconSizes.huge coverArtVisible: true trackDuration: true trackRating: true - onExit: clearSearch() + + headBar.leftContent: ToolButton + { + icon.name: "edit-clear" + onClicked: clearSearch() + } footBar.drawBorder: false 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: darkDarkColor z: 999 opacity: 0.5 } function runSearch(searchTxt) { if(searchTxt) if(searchTxt !== searchTable.headBarTitle) { if(savedQueries.indexOf(searchTxt) < 0) { savedQueries.unshift(searchTxt) // suggestionsPopup.model.insert(0, {suggestion: searchInput.text}) Maui.FM.saveSettings("QUERIES", savedQueries.join(","), "BABE") } searchTable.headBarTitle = searchTxt var queries = searchTxt.split(",") searchTable.list.searchQueries(queries) searchTable.forceActiveFocus() suggestionsPopup.close() } } function clearSearch() { searchInput.clear() searchTable.list.clear() searchTable.headBarTitle = "" suggestionsPopup.close() } function populate(tracks) { searchTable.clearTable() for(var i in tracks) searchTable.model.append(tracks[i]) } } diff --git a/widgets/SettingsView/SourcesDialog.qml b/widgets/SettingsView/SourcesDialog.qml index 99ffa96..4b68e57 100644 --- a/widgets/SettingsView/SourcesDialog.qml +++ b/widgets/SettingsView/SourcesDialog.qml @@ -1,108 +1,104 @@ import QtQuick 2.9 import QtQuick.Layouts 1.3 import QtQuick.Controls 2.2 import org.kde.mauikit 1.0 as Maui import "../../view_models" import "../../utils/Help.js" as H Maui.Dialog { property string pathToRemove : "" maxWidth: unit * 600 maxHeight: unit * 500 - page.margins: 0 defaultButtons: true acceptButton.text: qsTr("Add") rejectButton.text: qsTr("Remove") 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: { fmDialog.onlyDirs = true fmDialog.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: iconSizes.huge } BabeList { id: sources anchors.fill: parent headBar.visible: false - headBarExit: false - headBarTitle: qsTr("Sources") + title: qsTr("Sources") Layout.fillWidth: true Layout.fillHeight: true width: parent.width - onExit: close() - ListModel { id: listModel } model: listModel delegate: Maui.LabelDelegate { 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 1d45f9e..5b51dad 100644 --- a/widgets/TracksView.qml +++ b/widgets/TracksView.qml @@ -1,27 +1,24 @@ import QtQuick 2.9 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 trackDuration: true trackRating: true headBar.visible: !holder.visible -// headBarTitle: count + " tracks" - headBarExit: false coverArtVisible: false holder.emoji: "qrc:/assets/MusicCloud.png" holder.isMask: false holder.title : "No Tracks!" holder.body: "Add new music sources" holder.emojiSize: iconSizes.huge - list.query: Q.GET.allTracks }