Added proper playlist creation and replacing.

This commit is contained in:
Casey Langen 2017-01-26 18:24:15 -08:00
parent 1f0139c5cd
commit de859a7f7a
6 changed files with 201 additions and 71 deletions

View File

@ -48,19 +48,66 @@ static std::string CREATE_PLAYLIST_QUERY =
static std::string INSERT_PLAYLIST_TRACK_QUERY =
"INSERT INTO playlist_tracks (track_id, playlist_id, sort_order) VALUES (?, ?, ?);";
static std::string DELETE_PLAYLIST_TRACKS_QUERY =
"DELETE FROM playlist_tracks WHERE playlist_id=?;";
std::shared_ptr<SavePlaylistQuery> SavePlaylistQuery::Save(
const std::string& playlistName,
std::shared_ptr<musik::core::TrackList> tracks)
{
return std::shared_ptr<SavePlaylistQuery>(
new SavePlaylistQuery(playlistName, tracks));
}
std::shared_ptr<SavePlaylistQuery> SavePlaylistQuery::Replace(
const DBID playlistId,
std::shared_ptr<musik::core::TrackList> tracks)
{
return std::shared_ptr<SavePlaylistQuery>(
new SavePlaylistQuery(playlistId, tracks));
}
SavePlaylistQuery::SavePlaylistQuery(
const std::string& playlistName,
std::shared_ptr<musik::core::TrackList> tracks)
{
this->playlistId = -1;
this->playlistName = playlistName;
this->tracks = tracks;
}
SavePlaylistQuery::~SavePlaylistQuery() {
SavePlaylistQuery::SavePlaylistQuery(
DBID playlistId,
std::shared_ptr<musik::core::TrackList> tracks)
{
this->playlistId = playlistId;
this->tracks = tracks;
}
bool SavePlaylistQuery::OnRun(musik::core::db::Connection &db) {
SavePlaylistQuery::~SavePlaylistQuery() {
}
bool SavePlaylistQuery::AddTracksToPlaylist(musik::core::db::Connection &db, DBID playlistId) {
Statement insertTrack(INSERT_PLAYLIST_TRACK_QUERY.c_str(), db);
TrackPtr track;
TrackList& tracks = *this->tracks;
for (size_t i = 0; i < tracks.Count(); i++) {
track = tracks.Get(i);
insertTrack.Reset();
insertTrack.BindInt(0, track->Id());
insertTrack.BindInt(1, playlistId);
insertTrack.BindInt(2, (int) i);
if (insertTrack.Step() == db::Error) {
return false;
}
}
return true;
}
bool SavePlaylistQuery::CreatePlaylist(musik::core::db::Connection &db) {
ScopedTransaction transaction(db);
/* create playlist */
@ -75,21 +122,39 @@ bool SavePlaylistQuery::OnRun(musik::core::db::Connection &db) {
DBID playlistId = db.LastInsertedId();
/* add tracks to playlist */
Statement insertTrack(INSERT_PLAYLIST_TRACK_QUERY.c_str(), db);
TrackList& tracks = *this->tracks;
TrackPtr track;
for (size_t i = 0; i < tracks.Count(); i++) {
track = tracks.Get(i);
insertTrack.Reset();
insertTrack.BindInt(0, track->Id());
insertTrack.BindInt(1, playlistId);
insertTrack.BindInt(2, (int) i);
if (insertTrack.Step() == db::Error) {
transaction.Cancel();
return false;
}
if (!this->AddTracksToPlaylist(db, playlistId)) {
transaction.Cancel();
return false;
}
return true;
}
bool SavePlaylistQuery::ReplacePlaylist(musik::core::db::Connection &db) {
ScopedTransaction transaction(db);
/* delete existing tracks, we'll replace 'em */
Statement createPlaylist(DELETE_PLAYLIST_TRACKS_QUERY.c_str(), db);
createPlaylist.BindInt(0, this->playlistId);
if (createPlaylist.Step() == db::Error) {
transaction.Cancel();
return false;
}
/* add tracks to playlist */
if (!this->AddTracksToPlaylist(db, playlistId)) {
transaction.Cancel();
return false;
}
return true;
}
bool SavePlaylistQuery::OnRun(musik::core::db::Connection &db) {
if (playlistId != -1) {
return this->ReplacePlaylist(db);
}
return this->CreatePlaylist(db);
}

View File

@ -43,10 +43,14 @@ namespace musik {
namespace glue {
class SavePlaylistQuery : public musik::core::query::QueryBase {
public:
SavePlaylistQuery(
static std::shared_ptr<SavePlaylistQuery> Save(
const std::string& playlistName,
std::shared_ptr<musik::core::TrackList> tracks);
static std::shared_ptr<SavePlaylistQuery> Replace(
const DBID playlistId,
std::shared_ptr<musik::core::TrackList> tracks);
virtual std::string Name() { return "SavePlaylistQuery"; }
virtual ~SavePlaylistQuery();
@ -54,7 +58,21 @@ namespace musik {
protected:
virtual bool OnRun(musik::core::db::Connection &db);
private:
SavePlaylistQuery(
const std::string& playlistName,
std::shared_ptr<musik::core::TrackList> tracks);
SavePlaylistQuery(
DBID playlistId,
std::shared_ptr<musik::core::TrackList> tracks);
bool CreatePlaylist(musik::core::db::Connection &db);
bool ReplacePlaylist(musik::core::db::Connection &db);
bool AddTracksToPlaylist(musik::core::db::Connection &db, DBID playlistId);
std::string playlistName;
DBID playlistId;
std::shared_ptr<musik::core::TrackList> tracks;
};
}

View File

@ -41,6 +41,7 @@
#include <app/util/Hotkeys.h>
#include <app/overlay/PlayQueueOverlays.h>
#include <glue/query/NowPlayingTrackListQuery.h>
#include <glue/query/GetPlaylistQuery.h>
#include <glue/util/Duration.h>
#include "NowPlayingLayout.h"
@ -67,7 +68,7 @@ NowPlayingLayout::NowPlayingLayout(
, playback(playback)
, library(library)
, reselectIndex(-1)
, lastPlaylistId(-1) {
, lastPlaylistQueryId(-1) {
this->InitializeWindows();
this->playback.Shuffled.connect(this, &NowPlayingLayout::OnPlaybackShuffled);
@ -146,9 +147,9 @@ void NowPlayingLayout::OnTrackListRequeried(musik::glue::TrackListQueryBase* que
/* if the requery just finished for a regular playlist, we need to
make sure we load it into the PlaybackService. generally we just read
FROM the playback service */
if (query && query->GetId() == this->lastPlaylistId) {
if (query && query->GetId() == this->lastPlaylistQueryId) {
this->playback.CopyFrom(*query->GetResult());
this->lastPlaylistId = -1;
this->lastPlaylistQueryId = -1;
}
if (playback.Count()) {
@ -197,8 +198,11 @@ void NowPlayingLayout::RequeryTrackList() {
new NowPlayingTrackListQuery(this->library, this->playback)));
}
void NowPlayingLayout::OnPlaylistQueryStart(std::shared_ptr<musik::glue::TrackListQueryBase> query) {
this->lastPlaylistId = query->GetId();
void NowPlayingLayout::OnPlaylistSelected(DBID playlistId) {
auto query = std::shared_ptr<GetPlaylistQuery>(
new GetPlaylistQuery(library, playlistId));
this->lastPlaylistQueryId = query->GetId();
this->trackListView->Requery(query);
}
@ -214,7 +218,7 @@ bool NowPlayingLayout::KeyPress(const std::string& key) {
PlayQueueOverlays::ShowLoadPlaylistOverlay(
this->playback,
this->library,
std::bind(&NowPlayingLayout::OnPlaylistQueryStart, this, std::placeholders::_1));
std::bind(&NowPlayingLayout::OnPlaylistSelected, this, std::placeholders::_1));
return true;
}
else if (key == "M-s") {

View File

@ -76,13 +76,13 @@ namespace musik {
void OnTrackListRequeried(musik::glue::TrackListQueryBase* query);
void OnPlaybackShuffled(bool shuffled);
int64 RowDecorator(musik::core::TrackPtr track, size_t index);
void OnPlaylistQueryStart(std::shared_ptr<musik::glue::TrackListQueryBase> query);
void OnPlaylistSelected(DBID playlistId);
musik::core::audio::PlaybackService& playback;
musik::core::ILibraryPtr library;
std::shared_ptr<TrackListView> trackListView;
int reselectIndex; /* gross... */
int lastPlaylistId;
int lastPlaylistQueryId;
};
}
}

View File

@ -67,6 +67,44 @@ static std::shared_ptr<Adapter> createAddToAdapter() {
return adapter;
}
static std::shared_ptr<CategoryListQuery> queryPlaylists(musik::core::ILibraryPtr library) {
std::shared_ptr<CategoryListQuery> query(
new CategoryListQuery(Playlists::TABLE_NAME, ""));
library->Enqueue(query, ILibrary::QuerySynchronous);
if (query->GetStatus() != IQuery::Finished) {
query.reset();
return query;
}
return query;
}
static void addPlaylistsToAdapter(
std::shared_ptr<Adapter> adapter, CategoryListQuery::ResultList result)
{
auto it = result->begin();
while (it != result->end()) {
adapter->AddEntry((*it)->displayValue);
++it;
}
}
static void showPlaylistListOverlay(
const std::string& title,
std::shared_ptr<Adapter> adapter,
ListOverlay::ItemSelectedCallback callback)
{
std::shared_ptr<ListOverlay> dialog(new ListOverlay());
dialog->SetAdapter(adapter)
.SetTitle(title)
.SetSelectedIndex(0)
.SetItemSelectedCallback(callback);
cursespp::App::Overlays().Push(dialog);
}
PlayQueueOverlays::PlayQueueOverlays() {
}
@ -161,40 +199,40 @@ void PlayQueueOverlays::ShowAddCategoryOverlay(
void PlayQueueOverlays::ShowLoadPlaylistOverlay(
musik::core::audio::PlaybackService& playback,
musik::core::ILibraryPtr library,
TrackListQueryCallback callback)
PlaylistSelectedCallback callback)
{
std::shared_ptr<CategoryListQuery> query(
new CategoryListQuery(Playlists::TABLE_NAME, ""));
library->Enqueue(query, ILibrary::QuerySynchronous);
if (query->GetStatus() != IQuery::Finished) {
return;
}
std::shared_ptr<CategoryListQuery> query = queryPlaylists(library);
auto result = query->GetResult();
std::shared_ptr<Adapter> adapter(new Adapter());
adapter->SetSelectable(true);
addPlaylistsToAdapter(adapter, result);
auto it = result->begin();
while (it != result->end()) {
adapter->AddEntry((*it)->displayValue);
++it;
}
showPlaylistListOverlay(
"load playlist",
adapter,
[library, result, callback]
(cursespp::IScrollAdapterPtr adapter, size_t index) {
if (index != ListWindow::NO_SELECTION && callback) {
DBID playlistId = (*result)[index]->id;
callback(playlistId);
}
});
}
std::shared_ptr<ListOverlay> dialog(new ListOverlay());
static void createNewPlaylist(
std::shared_ptr<TrackList> tracks,
musik::core::ILibraryPtr library)
{
std::shared_ptr<InputOverlay> dialog(new InputOverlay());
dialog->SetAdapter(adapter)
.SetTitle("load playlist")
.SetSelectedIndex(0)
.SetItemSelectedCallback(
[&playback, library, result, callback]
(cursespp::IScrollAdapterPtr adapter, size_t index) {
if (index != ListWindow::NO_SELECTION && callback) {
DBID playlistId = (*result)[index]->id;
callback(std::shared_ptr<GetPlaylistQuery>(
new GetPlaylistQuery(library, playlistId)));
dialog->SetTitle("playlist name")
.SetWidth(36)
.SetText("")
.SetInputAcceptedCallback(
[tracks, library](const std::string& name) {
if (name.size()) {
library->Enqueue(SavePlaylistQuery::Save(name, tracks));
}
});
@ -205,23 +243,29 @@ void PlayQueueOverlays::ShowSavePlaylistOverlay(
musik::core::audio::PlaybackService& playback,
musik::core::ILibraryPtr library)
{
std::shared_ptr<InputOverlay> dialog(new InputOverlay());
std::shared_ptr<CategoryListQuery> query = queryPlaylists(library);
auto result = query->GetResult();
dialog->SetTitle("playlist name")
.SetWidth(36)
.SetText("")
.SetInputAcceptedCallback(
[&playback, library](const std::string& name) {
if (name.size()) {
std::shared_ptr<TrackList> tracks(new TrackList(library));
playback.CopyTo(*tracks);
std::shared_ptr<Adapter> adapter(new Adapter());
adapter->SetSelectable(true);
adapter->AddEntry("new...");
addPlaylistsToAdapter(adapter, result);
std::shared_ptr<SavePlaylistQuery>
saveQuery(new SavePlaylistQuery(name, tracks));
showPlaylistListOverlay(
"save playlist",
adapter,
[&playback, library, result]
(cursespp::IScrollAdapterPtr adapter, size_t index) {
std::shared_ptr<TrackList> tracks(new TrackList(library));
playback.CopyTo(*tracks);
library->Enqueue(saveQuery);
}
});
cursespp::App::Overlays().Push(dialog);
if (index == 0) { /* create new */
createNewPlaylist(tracks, library);
}
else { /* replace existing */
--index;
DBID playlistId = (*result)[index]->id;
library->Enqueue(SavePlaylistQuery::Replace(playlistId, tracks));
}
});
}

View File

@ -43,8 +43,7 @@ namespace musik {
namespace box {
class PlayQueueOverlays {
public:
using TrackListQueryCallback =
std::function<void(std::shared_ptr<musik::glue::TrackListQueryBase>)>;
using PlaylistSelectedCallback = std::function<void(DBID)>;
static void ShowAddTrackOverlay(
musik::core::audio::PlaybackService& playback,
@ -59,7 +58,7 @@ namespace musik {
static void ShowLoadPlaylistOverlay(
musik::core::audio::PlaybackService& playback,
musik::core::ILibraryPtr library,
TrackListQueryCallback callback);
PlaylistSelectedCallback callback);
static void ShowSavePlaylistOverlay(
musik::core::audio::PlaybackService& playback,