diff --git a/models/cloud/cloud.cpp b/models/cloud/cloud.cpp index bae278c..49819e1 100644 --- a/models/cloud/cloud.cpp +++ b/models/cloud/cloud.cpp @@ -1,177 +1,179 @@ #include "cloud.h" #include "abstractmusicprovider.h" #include "NextCloud/nextmusic.h" #ifdef STATIC_MAUIKIT #include "mauiaccounts.h" #else #include #endif Cloud::Cloud(QObject *parent) : MauiList (parent), provider(new NextMusic(this)) { connect(MauiAccounts::instance(), &MauiAccounts::currentAccountChanged, [this](QVariantMap account) { this->provider->setCredentials(FMH::toModel(account)); this->setList(); }); connect(provider, &AbstractMusicProvider::collectionReady, [=](FMH::MODEL_LIST data) { emit this->albumsChanged(); emit this->artistsChanged(); emit this->preListChanged(); this->list = data; this->sortList(); emit this->postListChanged(); }); connect(static_cast (provider), &NextMusic::trackPathReady, [=](QString id, QString path) { - qDebug() << "track path remot eurl is ready at "<< path << id; + auto track = static_cast (provider)->getTrackItem(id); + track[FMH::MODEL_KEY::URL] = path; + emit this->fileReady(FMH::toMap(track)); }); } void Cloud::componentComplete() { } void Cloud::setSortBy(const Cloud::SORTBY &sort) { if(this->sort == sort) return; this->sort = sort; emit this->preListChanged(); this->sortList(); emit this->postListChanged(); emit this->sortByChanged(); } Cloud::SORTBY Cloud::getSortBy() const { return this->sort; } QVariantList Cloud::getAlbums() const { return this->provider->getAlbumsList(); } QVariantList Cloud::getArtists() const { return this->provider->getArtistsList(); } FMH::MODEL_LIST Cloud::items() const { return this->list; } void Cloud::setList() { this->provider->getCollection(); } void Cloud::sortList() { if(this->sort == Cloud::SORTBY::NONE) return; const auto key = static_cast(this->sort); std::sort(this->list.begin(), this->list.end(), [key](const FMH::MODEL &e1, const FMH::MODEL &e2) -> bool { switch(key) { case FMH::MODEL_KEY::RELEASEDATE: case FMH::MODEL_KEY::RATE: case FMH::MODEL_KEY::FAV: case FMH::MODEL_KEY::COUNT: { if(e1[key].toInt() > e2[key].toInt()) return true; break; } case FMH::MODEL_KEY::TRACK: { if(e1[key].toInt() < e2[key].toInt()) return true; break; } case FMH::MODEL_KEY::ADDDATE: { auto currentTime = QDateTime::currentDateTime(); auto date1 = QDateTime::fromString(e1[key], Qt::TextDate); auto date2 = QDateTime::fromString(e2[key], Qt::TextDate); if(date1.secsTo(currentTime) < date2.secsTo(currentTime)) return true; break; } case FMH::MODEL_KEY::TITLE: case FMH::MODEL_KEY::ARTIST: case FMH::MODEL_KEY::ALBUM: case FMH::MODEL_KEY::FORMAT: { const auto str1 = QString(e1[key]).toLower(); const auto str2 = QString(e2[key]).toLower(); if(str1 < str2) return true; break; } default: if(e1[key] < e2[key]) return true; } return false; }); } QVariantMap Cloud::get(const int &index) const { if(index >= this->list.size() || index < 0) return QVariantMap(); QVariantMap res; const auto item = this->list.at(index); for(auto key : item.keys()) res.insert(FMH::MODEL_NAME[key], item[key]); return res; } QVariantList Cloud::getAll() { return QVariantList(); } void Cloud::upload(const QUrl &url) { } void Cloud::getFileUrl(const QString &id) { static_cast(this->provider)->getTrackPath(id); } void Cloud::getFileUrl(const int &index) { if(index >= this->list.size() || index < 0) return; this->getFileUrl(this->list.at(index)[FMH::MODEL_KEY::ID]); } diff --git a/models/cloud/cloud.h b/models/cloud/cloud.h index 5ce949c..ff763ef 100644 --- a/models/cloud/cloud.h +++ b/models/cloud/cloud.h @@ -1,77 +1,77 @@ #ifndef CLOUD_H #define CLOUD_H #include #ifdef STATIC_MAUIKIT #include "fmh.h" #include "mauilist.h" #else #include #include #endif class FM; class AbstractMusicProvider; class Cloud : public MauiList { Q_OBJECT Q_PROPERTY(Cloud::SORTBY sortBy READ getSortBy WRITE setSortBy NOTIFY sortByChanged) Q_PROPERTY(QVariantList artists READ getArtists NOTIFY artistsChanged) Q_PROPERTY(QVariantList albums READ getAlbums NOTIFY albumsChanged) public: enum SORTBY : uint_fast8_t { ADDDATE = FMH::MODEL_KEY::ADDDATE, RELEASEDATE = FMH::MODEL_KEY::RELEASEDATE, FORMAT = FMH::MODEL_KEY::FORMAT, ARTIST = FMH::MODEL_KEY::ARTIST, TITLE = FMH::MODEL_KEY::TITLE, ALBUM = FMH::MODEL_KEY::ALBUM, RATE = FMH::MODEL_KEY::RATE, FAV = FMH::MODEL_KEY::FAV, TRACK = FMH::MODEL_KEY::TRACK, COUNT = FMH::MODEL_KEY::COUNT, NONE }; Q_ENUM(SORTBY) explicit Cloud(QObject *parent = nullptr); void componentComplete() override final; FMH::MODEL_LIST items() const override; void setSortBy(const Cloud::SORTBY &sort); Cloud::SORTBY getSortBy() const; QVariantList getAlbums() const; QVariantList getArtists() const; private: AbstractMusicProvider *provider; FMH::MODEL_LIST list; void sortList(); void setList(); Cloud::SORTBY sort = Cloud::SORTBY::ARTIST; public slots: QVariantMap get(const int &index) const; QVariantList getAll(); void upload(const QUrl &url); void getFileUrl(const QString &id); void getFileUrl(const int &index); signals: void sortByChanged(); - void fileUrlReady(QString id, QUrl url); + void fileReady(QVariantMap track); void warning(QString error); void artistsChanged(); void albumsChanged(); }; #endif // CLOUD_H diff --git a/services/local/player.cpp b/services/local/player.cpp index 1e979c0..bb2bb11 100644 --- a/services/local/player.cpp +++ b/services/local/player.cpp @@ -1,232 +1,209 @@ #include "player.h" #include "../../utils/bae.h" +#ifdef STATIC_MAUIKIT +#include "mauiaccounts.h" +#else +#include +#endif Player::Player(QObject *parent) : QObject(parent), player(new QMediaPlayer(this)), updater(new QTimer(this)) { - this->buffer = new QBuffer(this->player); // connect(this->player, &QMediaPlayer::durationChanged, this, [&](qint64 dur) // { // emit this->durationChanged(/*BAE::transformTime(dur/1000)*/); // }); this->player->setVolume(this->volume); connect(this->updater, &QTimer::timeout, this, &Player::update); } inline QNetworkRequest getOcsRequest(const QNetworkRequest& request) { qDebug() << Q_FUNC_INFO; // Read raw headers out of the provided request QMap rawHeaders; for (const QByteArray& headerKey : request.rawHeaderList()) { rawHeaders.insert(headerKey, request.rawHeader(headerKey)); } - const QString concatenated = "mauitest:mauitest"; + const auto account = FMH::toModel(MauiAccounts::instance()->getCurrentAccount()); + + const QString concatenated = QString("%1:%2").arg(account[FMH::MODEL_KEY::USER], account[FMH::MODEL_KEY::PASSWORD]); const QByteArray data = concatenated.toLocal8Bit().toBase64(); const QString headerData = "Basic " + data; // Construct new QNetworkRequest with prepared header values QNetworkRequest newRequest(request); newRequest.setRawHeader(QString("Authorization").toLocal8Bit(), headerData.toLocal8Bit()); newRequest.setRawHeader(QByteArrayLiteral("OCS-APIREQUEST"), QByteArrayLiteral("true")); qDebug() << "headers" << newRequest.rawHeaderList() << newRequest.url(); return newRequest; } bool Player::play() const { if(this->url.isEmpty()) return false; if(!updater->isActive()) this->updater->start(500); this->player->play(); return true; } void Player::pause() const { if(this->player->isAvailable()) this->player->pause(); } void Player::stop() { if(this->player->isAvailable()) { this->player->stop(); this->url = QString(); this->player->setMedia(QMediaContent()); } this->playing = false; emit this->playingChanged(); this->updater->stop(); this->emitState(); } void Player::emitState() { switch(this->player->state()) { case QMediaPlayer::PlayingState: this->state = Player::STATE::PLAYING; break; case QMediaPlayer::PausedState: this->state = Player::STATE::PAUSED; break; case QMediaPlayer::StoppedState: this->state = Player::STATE::STOPED; break; } emit this->stateChanged(); } QString Player::transformTime(const int &pos) { return BAE::transformTime(pos); } -void Player::appendBuffe(QByteArray &array) -{ - qDebug()<<"APENDING TO BUFFER"<< array << this->array; - this->array.append(array, array.length()); - amountBuffers++; - - if(amountBuffers == 1) - playBuffer(); -} - -void Player::playRemote(const QString &url) -{ - qDebug()<<"Trying to play remote"<url = url; - this->player->setMedia(QUrl::fromUserInput(url)); - this->play(); -} - void Player::setUrl(const QUrl &value) { if(value == this->url) return; this->url = value; emit this->urlChanged(); this->pos = 0; emit this->posChanged(); const auto media = this->url.isLocalFile() ? QMediaContent(this->url) : QMediaContent(getOcsRequest(QNetworkRequest(this->url))); this->player->setMedia(media); this->emitState(); } QUrl Player::getUrl() const { return this->url; } void Player::setVolume(const int &value) { if(value == this->volume) return; this->volume = value; this->player->setVolume(volume); emit this->volumeChanged(); } int Player::getVolume() const { return this->volume; } int Player::getDuration() const { return static_cast(this->player->duration()); } Player::STATE Player::getState() const { return this->state; } void Player::setPlaying(const bool &value) { this->playing = value; if(this->playing) this->play(); else this->pause(); emit this->playingChanged(); this->emitState(); } bool Player::getPlaying() const { return this->playing; } bool Player::getFinished() { return this->finished; } void Player::setPos(const int &value) { this->pos = value; this->player->setPosition(this->player->duration() / 1000 * this->pos); this->emitState(); this->posChanged(); } int Player::getPos() const { return this->pos; } -void Player::playBuffer() -{ - buffer->setData(array); - buffer->open(QIODevice::ReadOnly); - if(!buffer->isReadable()) qDebug()<<"Cannot read buffer"; - player->setMedia(QMediaContent(),buffer); - this->url = "buffer"; - this->play(); - this->emitState(); -} - void Player::update() { if(this->player->isAvailable()) { this->pos = static_cast(static_cast(this->player->position())/this->player->duration()*1000);; emit this->posChanged(); } if(this->player->state() == QMediaPlayer::StoppedState && this->updater->isActive() && this->player->position() == this->player->duration()) { this->finished = true; emit this->finishedChanged(); } this->emitState(); } diff --git a/services/local/player.h b/services/local/player.h index 5c97c12..c6152a6 100644 --- a/services/local/player.h +++ b/services/local/player.h @@ -1,91 +1,85 @@ #ifndef PLAYER_H #define PLAYER_H #include #include #include #include class Player : public QObject { Q_OBJECT Q_PROPERTY(QUrl url READ getUrl WRITE setUrl NOTIFY urlChanged) Q_PROPERTY(int volume READ getVolume WRITE setVolume NOTIFY volumeChanged) Q_PROPERTY(Player::STATE state READ getState NOTIFY stateChanged) Q_PROPERTY(int duration READ getDuration NOTIFY durationChanged) Q_PROPERTY(bool playing READ getPlaying WRITE setPlaying NOTIFY playingChanged) Q_PROPERTY(bool finished READ getFinished NOTIFY finishedChanged) Q_PROPERTY(int pos READ getPos WRITE setPos NOTIFY posChanged) public: enum STATE : uint_fast8_t { PLAYING, PAUSED, STOPED, ERROR };Q_ENUM(STATE) explicit Player(QObject *parent = nullptr); - void playBuffer(); - Q_INVOKABLE void appendBuffe(QByteArray &array); void setUrl(const QUrl &value); QUrl getUrl() const; void setVolume(const int &value); int getVolume() const; int getDuration() const; Player::STATE getState() const; void setPlaying(const bool &value); bool getPlaying() const; bool getFinished(); int getPos() const; void setPos(const int &value); private: QMediaPlayer *player; QTimer *updater; int amountBuffers = 0; int pos = 0; int volume = 100; - QBuffer *buffer; - QByteArray array; - QUrl url; Player::STATE state = STATE::STOPED; bool playing = false; bool finished = false; bool play() const; void pause() const; void update(); void emitState(); signals: void durationChanged(); void urlChanged(); void volumeChanged(); void stateChanged(); void playingChanged(); void finishedChanged(); void posChanged(); public slots: static QString transformTime(const int &pos); - void playRemote(const QString &url); void stop(); }; #endif // PLAYER_H diff --git a/services/web/NextCloud/nextmusic.cpp b/services/web/NextCloud/nextmusic.cpp index c5d1e36..390cd33 100644 --- a/services/web/NextCloud/nextmusic.cpp +++ b/services/web/NextCloud/nextmusic.cpp @@ -1,241 +1,247 @@ #include "nextmusic.h" #include #include #include #include #include #ifdef STATIC_MAUIKIT #include "fm.h" #else #include #endif static const inline QNetworkRequest formRequest(const QUrl &url, const QString &user, const QString &password) { if(!url.isValid() && !user.isEmpty() && !password.isEmpty()) return QNetworkRequest(); const QString concatenated = QString("%1:%2").arg(user, password); const QByteArray data = concatenated.toLocal8Bit().toBase64(); const QString headerData = "Basic " + data; // Construct new QNetworkRequest with prepared header values QNetworkRequest newRequest(url); newRequest.setRawHeader(QString("Authorization").toLocal8Bit(), headerData.toLocal8Bit()); // newRequest.setRawHeader(QByteArrayLiteral("OCS-APIREQUEST"), QByteArrayLiteral("true")); qDebug() << "headers" << newRequest.rawHeaderList() << newRequest.url(); return newRequest; } const QString NextMusic::API = QStringLiteral("https://PROVIDER/index.php/apps/music/api/"); NextMusic::NextMusic(QObject *parent) : AbstractMusicProvider(parent) {} QVariantList NextMusic::getAlbumsList() const { return this->m_albums; } QVariantList NextMusic::getArtistsList() const { qDebug () << "ASKING FOR ARISTS" << this->m_artists; return this->m_artists; } FMH::MODEL_LIST NextMusic::parseCollection(const QByteArray &array) { FMH::MODEL_LIST res; // qDebug()<< "trying to parse array" << array; QJsonParseError jsonParseError; QJsonDocument jsonResponse = QJsonDocument::fromJson(static_cast(array).toUtf8(), &jsonParseError); if (jsonParseError.error != QJsonParseError::NoError) { qDebug()<< "ERROR PARSING" << array; return res; } const auto data = jsonResponse.toVariant(); if(data.isNull() || !data.isValid()) return res; const auto list = data.toList(); qDebug()<< "SOFAR GOOD PARSING"; if(!list.isEmpty()) { for(const auto &item : list) { const auto map = item.toMap(); const auto artist = map.value("name").toString(); const auto artistId = map.value("id").toString(); this->m_artists.append(QVariantMap{{"artist", artist}, {"id", artistId}}); qDebug()<< "ARTIST" << artist << artistId; const auto albumsList = map.value("albums").toList(); for(const auto &albumItem : albumsList) { const auto albumMap = albumItem.toMap(); const auto album = albumMap.value("name").toString(); const auto albumId = albumMap.value("id").toString(); const auto albumYear = albumMap.value("year").toString(); const auto albumCover = albumMap.value("cover").toString(); this->m_albums.append(QVariantMap {{"album", album}, {"artist", artist}, {"release_date", albumYear}, {"artwork", albumCover}, {"id", albumId}}); qDebug()<< "ARTIST && ALBUM" << artist << album << artistId; const auto tracksList = albumMap.value("tracks").toList(); for(const auto &trackItem : tracksList) { const auto trackMap = trackItem.toMap(); const auto title = trackMap.value("title").toString(); const auto track = trackMap.value("number").toString(); const auto id = trackMap.value("id").toString(); const auto filesMap = trackMap.value("files").toMap(); for(const auto &fileKey : filesMap.keys()) { const auto mime = fileKey; const auto url = filesMap[fileKey].toString(); - res << FMH::MODEL({ + const auto trackModel = FMH::MODEL({ {FMH::MODEL_KEY::ID, url}, {FMH::MODEL_KEY::TITLE, title}, {FMH::MODEL_KEY::TRACK, track}, {FMH::MODEL_KEY::ALBUM, album}, {FMH::MODEL_KEY::ARTIST, artist}, {FMH::MODEL_KEY::ARTWORK, albumCover}, {FMH::MODEL_KEY::RELEASEDATE, albumYear}, {FMH::MODEL_KEY::SOURCE, this->m_provider} }); + this->m_tracks.insert(url, trackModel); + res << trackModel; } } } } } qDebug()<< res; return res; } +FMH::MODEL NextMusic::getTrackItem(const QString &id) +{ + return this->m_tracks.value(id); +} + void NextMusic::getTrackPath(const QString &id) { auto url = QString(NextMusic::API+"file/%1/path").replace("PROVIDER", QUrl(this->m_provider).host()).arg(id); QString concatenated = this->m_user + ":" + this->m_password; QByteArray data = concatenated.toLocal8Bit().toBase64(); QString headerData = "Basic " + data; QMap header {{"Authorization", headerData.toLocal8Bit()}}; const auto downloader = new FMH::Downloader; connect(downloader, &FMH::Downloader::dataReady, [this, id, _downloader = std::move(downloader)](QByteArray array) { QJsonParseError jsonParseError; QJsonDocument jsonResponse = QJsonDocument::fromJson(static_cast(array).toUtf8(), &jsonParseError); if (jsonParseError.error != QJsonParseError::NoError) { qDebug()<< "ERROR PARSING"; return; } const auto data = jsonResponse.toVariant(); if(data.isNull() || !data.isValid()) return; const auto map = data.toMap(); - const auto url = this->provider() + map["path"].toString(); - - qDebug()<< "TRACK PATH...." << url; - emit this->trackPathReady(id, url); + auto path = map["path"].toString(); + const auto url = this->provider() + (path.startsWith("/") ? path.remove(0,1) : path); + emit this->trackPathReady(id, url); }); downloader->getArray(url, header); } void NextMusic::getCollection(const std::initializer_list ¶meters) { auto url = QString(NextMusic::API).replace("PROVIDER", QUrl(this->m_provider).host()).append("collection"); QString concatenated = this->m_user + ":" + this->m_password; QByteArray data = concatenated.toLocal8Bit().toBase64(); QString headerData = "Basic " + data; QMap header {{"Authorization", headerData.toLocal8Bit()}}; const auto downloader = new FMH::Downloader; connect(downloader, &FMH::Downloader::dataReady, [&, _downloader = std::move(downloader)](QByteArray array) { const auto data = this->parseCollection(array); emit this->collectionReady(data); _downloader->deleteLater(); }); downloader->getArray(url, header); } void NextMusic::getTracks() { } void NextMusic::getTrack(const QString &id) { } void NextMusic::getArtists() { } void NextMusic::getArtist(const QString &id) { } void NextMusic::getAlbums() { } void NextMusic::getAlbum(const QString &id) { } void NextMusic::getPlaylists() { } void NextMusic::getPlaylist(const QString &id) { } void NextMusic::getFolders() { } void NextMusic::getFolder(const QString &id) { } diff --git a/services/web/NextCloud/nextmusic.h b/services/web/NextCloud/nextmusic.h index 77caca3..5da7891 100644 --- a/services/web/NextCloud/nextmusic.h +++ b/services/web/NextCloud/nextmusic.h @@ -1,45 +1,48 @@ #ifndef NEXTMUSIC_H #define NEXTMUSIC_H #include #include "abstractmusicprovider.h" class NextMusic : public AbstractMusicProvider { Q_OBJECT public: explicit NextMusic(QObject *parent = nullptr); QVariantList getAlbumsList() const override final; QVariantList getArtistsList() const override final; private: const static QString API; static const QString formatUrl(const QString &user, const QString &password, const QString &provider); FMH::MODEL_LIST parseCollection(const QByteArray &array); QVariantList m_artists; QVariantList m_albums; + QHash m_tracks; //(id: trackMap) signals: public slots: // AbstractMusicProvider interface public: + + FMH::MODEL getTrackItem(const QString &id); void getTrackPath(const QString &id); void getCollection(const std::initializer_list ¶meters = {}) override final; void getTracks() override final; void getTrack(const QString &id) override final; void getArtists() override final; void getArtist(const QString &id) override final; void getAlbums() override final; void getAlbum(const QString &id) override final; void getPlaylists() override final; void getPlaylist(const QString &id) override final; void getFolders() override final; void getFolder(const QString &id) override final; }; #endif // NEXTMUSIC_H diff --git a/utils/Player.js b/utils/Player.js index 02a126c..202f5ce 100644 --- a/utils/Player.js +++ b/utils/Player.js @@ -1,219 +1,218 @@ .import org.kde.mauikit 1.0 as Maui function playTrack(index) { if((index < mainPlaylist.listView.count) && (mainPlaylist.listView.count > 0) && (index > -1)) { currentTrack = mainPlaylist.list.get(index) if(typeof(currentTrack) === "undefined") return - if(Maui.FM.fileExists(currentTrack.url)) + if(!Maui.FM.fileExists(currentTrack.url) && currentTrack.url.startsWith("file://")) { - player.url = currentTrack.url; - player.playing = true - + missingAlert(currentTrack) + return + } - if(currentTrack.artwork && currentTrack.artwork.length && currentTrack.artwork !== "NONE") - currentArtwork = currentTrack.artwork - // else bae.loadCover(currentTrack.url) + player.url = currentTrack.url; + player.playing = true + currentArtwork = currentTrack.artwork - progressBar.enabled = true - root.title = currentTrack.title + " - " +currentTrack.artist + progressBar.enabled = true + root.title = currentTrack.title + " - " +currentTrack.artist - // if(!root.active) - // bae.notifySong(currentTrack.url) + // if(!root.active) + // bae.notifySong(currentTrack.url) - // if(currentTrack.lyrics.length < 1) - // bae.trackLyrics(currentTrack.url) + // if(currentTrack.lyrics.length < 1) + // bae.trackLyrics(currentTrack.url) - // root.mainPlaylist.infoView.wikiAlbum = bae.albumWiki(root.mainPlaylist.currentTrack.album,root.mainPlaylist.currentTrack.artist) - // root.mainPlaylist.infoView.wikiArtist = bae.artistWiki(root.mainPlaylist.currentTrack.artist) - // // root.mainPlaylist.infoView.artistHead = bae.artistArt(root.mainPlaylist.currentTrack.artist) - }else missingAlert(currentTrack) + // root.mainPlaylist.infoView.wikiAlbum = bae.albumWiki(root.mainPlaylist.currentTrack.album,root.mainPlaylist.currentTrack.artist) + // root.mainPlaylist.infoView.wikiArtist = bae.artistWiki(root.mainPlaylist.currentTrack.artist) + // // root.mainPlaylist.infoView.artistHead = bae.artistArt(root.mainPlaylist.currentTrack.artist) } } function queueTracks(tracks) { if(tracks && tracks.length > 0) { appendTracksAt(tracks, currentTrackIndex+onQueue+1) onQueue++ root.notify("", "Queue", tracks.length + " tracks added put on queue") } } function setLyrics(lyrics) { currentTrack.lyrics = lyrics infoView.lyricsText.text = lyrics } function stop() { player.stop() progressBar.value = 0 progressBar.enabled = false root.title = "Babe..." } function pauseTrack() { player.playing = false } function resumeTrack() { if(!player.play() && !mainlistEmpty) playAt(0) } function nextTrack() { if(!mainlistEmpty) { var next = 0 if(isShuffle && onQueue === 0) next = shuffle() else next = currentTrackIndex+1 >= mainPlaylist.listView.count? 0 : currentTrackIndex+1 prevTrackIndex = mainPlaylist.listView.currentIndex playAt(next) if(onQueue > 0) { onQueue-- console.log(onQueue) } } } function previousTrack() { if(!mainlistEmpty) { var previous = previous = currentTrackIndex-1 >= 0 ? mainPlaylist.listView.currentIndex-1 : currentTrackIndex-1 prevTrackIndex = mainPlaylist.listView.currentIndex playAt(previous) } } function shuffle() { var pos = Math.floor(Math.random() * mainPlaylist.listView.count) return pos } function playAt(index) { if((index < mainPlaylist.listView.count) && (index > -1)) { currentTrackIndex = index mainPlaylist.listView.currentIndex = currentTrackIndex mainPlaylist.albumsRoll.positionAlbum(currentTrackIndex) playTrack(currentTrackIndex) } } function quickPlay(track) { // root.pageStack.currentIndex = 0 appendTrack(track) playAt(mainPlaylist.listView.count-1) mainPlaylist.listView.positionViewAtEnd() mainPlaylist.albumsRoll.positionViewAtEnd() } function appendTracksAt(tracks, at) { if(tracks) for(var i in tracks) mainPlaylist.list.append(tracks[i], parseInt(at)+parseInt(i)) } function appendTrack(track) { if(track) { mainPlaylist.list.append(track) if(sync === true) { infoMsgAnim() // addToPlaylist([track.url], syncPlaylist) } } } function addTrack(track) { if(track) { appendTrack(track) mainPlaylist.listView.positionViewAtEnd() } } function appendAll(tracks) { if(tracks) { for(var i in tracks) appendTrack(tracks[i]) mainPlaylist.listView.positionViewAtEnd() } } function savePlaylist() { var list = [] var n = mainPlaylist.listView.count n = n > 15 ? 15 : n for(var i=0 ; i < n; i++) { var url = mainPlaylist.list.get(i).url list.push(url) } Maui.FM.saveSettings("LASTPLAYLIST", list, "PLAYLIST"); Maui.FM.saveSettings("PLAYLIST_POS", mainPlaylist.listView.currentIndex, "MAINWINDOW") } function clearOutPlaylist() { mainPlaylist.list.clear() stop() } function cleanPlaylist() { var urls = [] for(var i = 0; i < mainPlaylist.listView.count; i++) { var url = mainPlaylist.list.get(i).url if(urls.indexOf(url)<0) urls.push(url) else mainPlaylist.list.remove(i) } } function playAll() { sync = false syncPlaylist = "" infoMsg = "" if(_drawer.modal && !_drawer.visible) _drawer.visible = true mainPlaylist.listView.positionViewAtBeginning() playAt(0) } diff --git a/widgets/CloudView/CloudView.qml b/widgets/CloudView/CloudView.qml index c271ce0..bdc6010 100644 --- a/widgets/CloudView/CloudView.qml +++ b/widgets/CloudView/CloudView.qml @@ -1,275 +1,278 @@ import QtQuick 2.9 import QtQuick.Controls 2.2 import QtQuick.Layouts 1.3 import org.kde.mauikit 1.0 as Maui import org.kde.kirigami 2.7 as Kirigami import "../../view_models/BabeTable" import "../../view_models/BabeGrid" +import "../../utils/Player.js" as Player import CloudList 1.0 Maui.Page { id: control property alias list : _cloudList Maui.BaseModel { id: _cloudModel list: _cloudList } Cloud { id: _cloudList + + onFileReady: Player.addTrack(track) } headBar.leftContent: [ ToolButton { id : playAllBtn // text: qsTr("Play all") icon.name : "media-playlist-play" // onClicked: playAll() }, ToolButton { id: appendBtn // text: qsTr("Append") icon.name : "media-playlist-append"//"media-repeat-track-amarok" // onClicked: appendAll() }] headBar.rightContent: [ ToolButton { icon.name: "item-select" onClicked: selectionMode = !selectionMode checkable: false checked: selectionMode }, Maui.ToolButtonMenu { id: sortBtn icon.name: "view-sort" MenuItem { text: qsTr("Title") checkable: true checked: list.sortBy === Cloud.TITLE onTriggered: list.sortBy = Cloud.TITLE autoExclusive: true } MenuItem { text: qsTr("Track") checkable: true checked: list.sortBy === Cloud.TRACK onTriggered: list.sortBy = Cloud.TRACK autoExclusive: true } MenuItem { text: qsTr("Artist") checkable: true checked: list.sortBy === Cloud.ARTIST onTriggered: list.sortBy = Cloud.ARTIST autoExclusive: true } MenuItem { text: qsTr("Album") checkable: true checked: list.sortBy === Cloud.ALBUM onTriggered: list.sortBy = Cloud.ALBUM autoExclusive: true } MenuItem { text: qsTr("Most played") checkable: true checked: list.sortBy === Cloud.COUNT onTriggered: list.sortBy = Cloud.COUNT autoExclusive: true } MenuItem { text: qsTr("Rate") checkable: true checked: list.sortBy === Cloud.RATE onTriggered: list.sortBy = Cloud.RATE autoExclusive: true } MenuItem { text: qsTr("Favorite") checkable: true checked: list.sortBy === Cloud.FAV onTriggered: list.sortBy = Cloud.FAV autoExclusive: true } MenuItem { text: qsTr("Release date") checkable: true checked: list.sortBy === Cloud.RELEASEDATE onTriggered: list.sortBy = Cloud.RELEASEDATE autoExclusive: true } MenuItem { text: qsTr("Add date") checkable: true checked: list.sortBy === Cloud.ADDDATE onTriggered: list.sortBy = Cloud.ADDDATE autoExclusive: true } MenuSeparator{} MenuItem { text: qsTr("Group") checkable: true checked: group onTriggered: group = !group } } ] Maui.ListBrowser { id: _listView anchors.fill: parent clip: true holder.visible: count === 0 topMargin: Maui.Style.space.medium model: _cloudModel section.property: "artist" section.criteria: ViewSection.FullString section.delegate: Maui.LabelDelegate { id: _sectionDelegate label: section isSection: true width: parent.width Kirigami.Theme.backgroundColor: "#333" Kirigami.Theme.textColor: "#fafafa" background: Rectangle { color: Kirigami.Theme.backgroundColor } } listView.header: Rectangle { Kirigami.Theme.inherit: false width: parent.width height: 150 z: _listView.listView.z+999 color: Kirigami.Theme.backgroundColor ListView { anchors.fill: parent anchors.margins: Maui.Style.space.medium spacing: Maui.Style.space.medium orientation: ListView.Horizontal model: list.artists delegate: BabeAlbum { height: 120 width: height albumRadius: Maui.Style.radiusV isCurrentItem: ListView.isCurrentItem anchors.verticalCenter: parent.verticalCenter showLabels: true label1.text: modelData.album ? modelData.album : modelData.artist label2.text: modelData.artist && modelData.album ? modelData.artist : "" image.source: modelData.artwork ? modelData.artwork : "qrc:/assets/cover.png" } } } listView.headerPositioning: ListView.PullBackHeader delegate: TableDelegate { id: delegate width: parent.width number : false quickPlay: true coverArt : false trackDurationVisible : false trackRatingVisible : false menuItem: false remoteArtwork: false playingIndicator: false // onPressAndHold: if(isMobile && allowMenu) openItemMenu(index) // onRightClicked: if(allowMenu) openItemMenu(index) onClicked: { _listView.currentIndex = index // if(selectionMode) // { // H.addToSelection(control.list.get(_listView.currentIndex)) // return // } list.getFileUrl(index); // if(isMobile) // rowClicked(index) } // onDoubleClicked: // { // currentIndex = index // if(!isMobile) // rowClicked(index) // } // onPlay: // { // currentIndex = index // if(Maui.FM.fileExists("file://" + _cloudList.get(index).thumbnail)) // { // quickPlayTrack(index) // }else // { // _cloudList.requestFile(index) // } // } // onArtworkCoverClicked: // { // currentIndex = index // goToAlbum() // } } } }