diff --git a/autotests/mediaplaylisttest.h b/autotests/mediaplaylisttest.h --- a/autotests/mediaplaylisttest.h +++ b/autotests/mediaplaylisttest.h @@ -123,6 +123,8 @@ void switchToTrackTest(); + void previousAndNextTracksTest(); + void singleTrack(); void remainingTracksTest(); diff --git a/autotests/mediaplaylisttest.cpp b/autotests/mediaplaylisttest.cpp --- a/autotests/mediaplaylisttest.cpp +++ b/autotests/mediaplaylisttest.cpp @@ -6152,6 +6152,132 @@ QCOMPARE(myPlayList.currentTrack(), QPersistentModelIndex(myPlayList.index(4, 0))); } +void MediaPlayListTest::previousAndNextTracksTest() +{ + MediaPlayList myPlayList; + QAbstractItemModelTester testModel(&myPlayList); + DatabaseInterface myDatabaseContent; + TracksListener myListener(&myDatabaseContent); + + QSignalSpy previousTrackChangedSpy(&myPlayList, &MediaPlayList::previousTrackChanged); + QSignalSpy currentTrackChangedSpy(&myPlayList, &MediaPlayList::currentTrackChanged); + QSignalSpy nextTrackChangedSpy(&myPlayList, &MediaPlayList::nextTrackChanged); + QSignalSpy randomPlayChangedSpy(&myPlayList, &MediaPlayList::randomPlayChanged); + QSignalSpy repeatPlayChangedSpy(&myPlayList, &MediaPlayList::repeatPlayChanged); + QSignalSpy playListFinishedSpy(&myPlayList, &MediaPlayList::playListFinished); + + myDatabaseContent.init(QStringLiteral("testDbDirectContent")); + + connect(&myListener, &TracksListener::trackHasChanged, + &myPlayList, &MediaPlayList::trackChanged, + Qt::QueuedConnection); + connect(&myListener, &TracksListener::tracksListAdded, + &myPlayList, &MediaPlayList::tracksListAdded, + Qt::QueuedConnection); + connect(&myPlayList, &MediaPlayList::newTrackByNameInList, + &myListener, &TracksListener::trackByNameInList, + Qt::QueuedConnection); + connect(&myPlayList, &MediaPlayList::newEntryInList, + &myListener, &TracksListener::newEntryInList, + Qt::QueuedConnection); + connect(&myDatabaseContent, &DatabaseInterface::tracksAdded, + &myListener, &TracksListener::tracksAdded); + + myDatabaseContent.insertTracksList(mNewTracks, mNewCovers); + + QCOMPARE(previousTrackChangedSpy.count(), 0); + QCOMPARE(currentTrackChangedSpy.count(), 0); + QCOMPARE(nextTrackChangedSpy.count(), 0); + QCOMPARE(randomPlayChangedSpy.count(), 0); + QCOMPARE(repeatPlayChangedSpy.count(), 0); + QCOMPARE(playListFinishedSpy.count(), 0); + + myPlayList.enqueue({myDatabaseContent.trackIdFromTitleAlbumTrackDiscNumber(QStringLiteral("track1"), QStringLiteral("artist1"), QStringLiteral("album2"), 1, 1), + QStringLiteral("track1")}, + ElisaUtils::Track); + myPlayList.enqueue({myDatabaseContent.trackIdFromTitleAlbumTrackDiscNumber(QStringLiteral("track3"), QStringLiteral("artist3"), QStringLiteral("album1"), 3, 3), + QStringLiteral("track3")}, + ElisaUtils::Track); + myPlayList.enqueue({myDatabaseContent.trackIdFromTitleAlbumTrackDiscNumber(QStringLiteral("track4"), QStringLiteral("artist1"), QStringLiteral("album1"), 4, 4), + QStringLiteral("track4")}, + ElisaUtils::Track); + myPlayList.enqueue({myDatabaseContent.trackIdFromTitleAlbumTrackDiscNumber(QStringLiteral("track2"), QStringLiteral("artist1"), QStringLiteral("album1"), 2, 2), + QStringLiteral("track2")}, + ElisaUtils::Track); + myPlayList.enqueue({myDatabaseContent.trackIdFromTitleAlbumTrackDiscNumber(QStringLiteral("track1"), QStringLiteral("artist1"), QStringLiteral("album2"), 1, 1), + QStringLiteral("track1")}, + ElisaUtils::Track); + + QCOMPARE(previousTrackChangedSpy.count(), 0); + QCOMPARE(currentTrackChangedSpy.count(), 0); + QCOMPARE(nextTrackChangedSpy.count(), 0); + QCOMPARE(randomPlayChangedSpy.count(), 0); + QCOMPARE(repeatPlayChangedSpy.count(), 0); + QCOMPARE(playListFinishedSpy.count(), 0); + + QCOMPARE(currentTrackChangedSpy.wait(), true); + + QCOMPARE(previousTrackChangedSpy.count(), 0); + QCOMPARE(currentTrackChangedSpy.count(), 1); + QCOMPARE(nextTrackChangedSpy.count(), 1); + QCOMPARE(randomPlayChangedSpy.count(), 0); + QCOMPARE(repeatPlayChangedSpy.count(), 0); + QCOMPARE(playListFinishedSpy.count(), 0); + + QCOMPARE(myPlayList.previousTrack(), QPersistentModelIndex()); + QCOMPARE(myPlayList.currentTrack(), QPersistentModelIndex(myPlayList.index(0, 0))); + QCOMPARE(myPlayList.nextTrack(), QPersistentModelIndex(myPlayList.index(1, 0))); + + myPlayList.skipNextTrack(); + + QCOMPARE(previousTrackChangedSpy.count(), 1); + QCOMPARE(currentTrackChangedSpy.count(), 2); + QCOMPARE(nextTrackChangedSpy.count(), 2); + QCOMPARE(randomPlayChangedSpy.count(), 0); + QCOMPARE(repeatPlayChangedSpy.count(), 0); + QCOMPARE(playListFinishedSpy.count(), 0); + + QCOMPARE(myPlayList.previousTrack(), QPersistentModelIndex(myPlayList.index(0, 0))); + QCOMPARE(myPlayList.currentTrack(), QPersistentModelIndex(myPlayList.index(1, 0))); + QCOMPARE(myPlayList.nextTrack(), QPersistentModelIndex(myPlayList.index(2, 0))); + + myPlayList.switchTo(4); + + QCOMPARE(previousTrackChangedSpy.count(), 2); + QCOMPARE(currentTrackChangedSpy.count(), 3); + QCOMPARE(nextTrackChangedSpy.count(), 3); + + QCOMPARE(myPlayList.previousTrack(), QPersistentModelIndex(myPlayList.index(3, 0))); + QCOMPARE(myPlayList.currentTrack(), QPersistentModelIndex(myPlayList.index(4, 0))); + QCOMPARE(myPlayList.nextTrack(), QPersistentModelIndex()); + + myPlayList.setRepeatPlay(true); + + QCOMPARE(previousTrackChangedSpy.count(), 2); + QCOMPARE(currentTrackChangedSpy.count(), 3); + QCOMPARE(nextTrackChangedSpy.count(), 4); + + QCOMPARE(myPlayList.previousTrack(), QPersistentModelIndex(myPlayList.index(3, 0))); + QCOMPARE(myPlayList.currentTrack(), QPersistentModelIndex(myPlayList.index(4, 0))); + QCOMPARE(myPlayList.nextTrack(), QPersistentModelIndex(myPlayList.index(0, 0))); + + myPlayList.skipNextTrack(); + + QCOMPARE(previousTrackChangedSpy.count(), 3); + QCOMPARE(currentTrackChangedSpy.count(), 4); + QCOMPARE(nextTrackChangedSpy.count(), 5); + + QCOMPARE(myPlayList.previousTrack(), QPersistentModelIndex(myPlayList.index(4, 0))); + QCOMPARE(myPlayList.currentTrack(), QPersistentModelIndex(myPlayList.index(0, 0))); + QCOMPARE(myPlayList.nextTrack(), QPersistentModelIndex(myPlayList.index(1, 0))); + + myPlayList.setRandomPlay(true); + + QVERIFY(myPlayList.previousTrack() != QPersistentModelIndex()); + QVERIFY(myPlayList.currentTrack() != QPersistentModelIndex()); + QVERIFY(myPlayList.nextTrack() != QPersistentModelIndex()); +} + void MediaPlayListTest::singleTrack() { MediaPlayList myPlayList; diff --git a/src/mediaplaylist.h b/src/mediaplaylist.h --- a/src/mediaplaylist.h +++ b/src/mediaplaylist.h @@ -54,10 +54,18 @@ READ tracksCount NOTIFY tracksCountChanged) + Q_PROPERTY(QPersistentModelIndex previousTrack + READ previousTrack + NOTIFY previousTrackChanged) + Q_PROPERTY(QPersistentModelIndex currentTrack READ currentTrack NOTIFY currentTrackChanged) + Q_PROPERTY(QPersistentModelIndex nextTrack + READ nextTrack + NOTIFY nextTrackChanged) + Q_PROPERTY(int currentTrackRow READ currentTrackRow NOTIFY currentTrackRowChanged) @@ -168,8 +176,12 @@ int tracksCount() const; + QPersistentModelIndex previousTrack() const; + QPersistentModelIndex currentTrack() const; + QPersistentModelIndex nextTrack() const; + int currentTrackRow() const; bool randomPlay() const; @@ -195,8 +207,12 @@ void tracksCountChanged(); + void previousTrackChanged(QPersistentModelIndex previousTrack); + void currentTrackChanged(QPersistentModelIndex currentTrack); + void nextTrackChanged(QPersistentModelIndex nextTrack); + void clearPlayListPlayer(); void undoClearPlayListPlayer(); @@ -300,6 +316,8 @@ void restoreRepeatPlay(); + void notifyPreviousAndNextTracks(); + void enqueueArtist(const QString &artistName); void enqueueFilesList(const ElisaUtils::EntryDataList &newEntries); diff --git a/src/mediaplaylist.cpp b/src/mediaplaylist.cpp --- a/src/mediaplaylist.cpp +++ b/src/mediaplaylist.cpp @@ -42,8 +42,12 @@ MusicListenersManager* mMusicListenersManager = nullptr; + QPersistentModelIndex mPreviousTrack; + QPersistentModelIndex mCurrentTrack; + QPersistentModelIndex mNextTrack; + QVariantMap mPersistentState; QMediaPlaylist mLoadPlaylist; @@ -296,6 +300,9 @@ } } } + if (!d->mNextTrack.isValid() || !d->mPreviousTrack.isValid()) { + notifyPreviousAndNextTracks(); + } if (!d->mCurrentTrack.isValid() && rowCount(parent) <= row) { resetCurrentTrack(); @@ -815,11 +822,21 @@ return rowCount(); } +QPersistentModelIndex MediaPlayList::previousTrack() const +{ + return d->mPreviousTrack; +} + QPersistentModelIndex MediaPlayList::currentTrack() const { return d->mCurrentTrack; } +QPersistentModelIndex MediaPlayList::nextTrack() const +{ + return d->mNextTrack; +} + int MediaPlayList::currentTrackRow() const { return d->mCurrentTrack.row(); @@ -1026,6 +1043,8 @@ resetCurrentTrack(); } else if (i == d->mCurrentTrack.row()) { notifyCurrentTrackChanged(); + } else if (i == d->mNextTrack.row() || i == d->mPreviousTrack.row()) { + notifyPreviousAndNextTracks(); } break; @@ -1046,6 +1065,8 @@ resetCurrentTrack(); } else if (i == d->mCurrentTrack.row()) { notifyCurrentTrackChanged(); + } else if (i == d->mNextTrack.row() || i == d->mPreviousTrack.row()) { + notifyPreviousAndNextTracks(); } break; @@ -1099,6 +1120,7 @@ createRandomList(); Q_EMIT randomPlayChanged(); Q_EMIT remainingTracksChanged(); + notifyPreviousAndNextTracks(); } } @@ -1108,6 +1130,7 @@ d->mRepeatPlay = value; Q_EMIT repeatPlayChanged(); Q_EMIT remainingTracksChanged(); + notifyPreviousAndNextTracks(); } } @@ -1241,8 +1264,56 @@ } } +void MediaPlayList::notifyPreviousAndNextTracks() +{ + if (!d->mCurrentTrack.isValid()) { + d->mPreviousTrack = QPersistentModelIndex(); + d->mNextTrack = QPersistentModelIndex(); + } + auto mOldPreviousTrack = d->mPreviousTrack; + auto mOldNextTrack = d->mNextTrack; + // use random list for previous and next types + if (d->mRandomPlay) { + d->mPreviousTrack = index(d->mRandomPositions.first(), 0); + d->mNextTrack = index(d->mRandomPositions.last(), 0); + } else if (d->mRepeatPlay) { + // forward to end or begin when repeating + if (d->mCurrentTrack.row() == 0) { + d->mPreviousTrack = index(rowCount() - 1, 0); + } else { + d->mPreviousTrack = index(d->mCurrentTrack.row() - 1, 0); + } + if (d->mCurrentTrack.row() == rowCount() - 1) { + d->mNextTrack = index(0, 0); + } else { + d->mNextTrack = index(d->mCurrentTrack.row() + 1, 0); + } + } else { + // return nothing if no tracks available + if (d->mCurrentTrack.row() == 0) { + d->mPreviousTrack = QPersistentModelIndex(); + } else { + d->mPreviousTrack = index(d->mCurrentTrack.row() - 1, 0); + } + if (d->mCurrentTrack.row() == rowCount() - 1) { + d->mNextTrack = QPersistentModelIndex(); + } else { + d->mNextTrack = index(d->mCurrentTrack.row() + 1, 0); + } + } + if (d->mPreviousTrack != mOldPreviousTrack) { + Q_EMIT previousTrackChanged(d->mPreviousTrack); + } + if (d->mNextTrack != mOldNextTrack) { + Q_EMIT nextTrackChanged(d->mNextTrack); + } +} + void MediaPlayList::notifyCurrentTrackChanged() { + // determine previous and next tracks first + notifyPreviousAndNextTracks(); + Q_EMIT currentTrackChanged(d->mCurrentTrack); Q_EMIT currentTrackRowChanged(); Q_EMIT remainingTracksChanged();