Skip to content

Commit

Permalink
Added liked column, fixes #138
Browse files Browse the repository at this point in the history
  • Loading branch information
kraxarn committed Jan 27, 2023
1 parent c6bf220 commit 7c74d40
Show file tree
Hide file tree
Showing 6 changed files with 146 additions and 9 deletions.
1 change: 1 addition & 0 deletions src/enum/column.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -8,4 +8,5 @@ enum class Column: int
Album = 3,
Length = 4,
Added = 5,
Liked = 6,
};
1 change: 1 addition & 0 deletions src/enum/datarole.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -11,4 +11,5 @@ enum class DataRole: int
Length = 0x106, // 262
DefaultIndex = 0x107, // 263
ShowId = 0x108, // 264
Liked = 0x109, // 265
};
127 changes: 121 additions & 6 deletions src/list/tracks.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -28,8 +28,15 @@ List::Tracks::Tracks(lib::spt::api &spotify, lib::settings &settings, lib::cache
setAllColumnsShowFocus(true);
setColumnCount(columnCount);
setHeaderLabels({
settings.general.track_numbers == lib::spotify_context::all ? "#" : "",
"Title", "Artist", "Album", "Length", "Added"
settings.general.track_numbers == lib::spotify_context::all
? QStringLiteral("#")
: QString(),
QStringLiteral("Title"),
QStringLiteral("Artist"),
QStringLiteral("Album"),
QStringLiteral("Length"),
QStringLiteral("Added"),
QStringLiteral("Liked"),
});
header()->setSectionsMovable(false);
header()->setSortIndicator(settings.general.song_header_sort_by + 1, Qt::AscendingOrder);
Expand All @@ -42,6 +49,10 @@ List::Tracks::Tracks(lib::spt::api &spotify, lib::settings &settings, lib::cache
header()->setSectionHidden(value + 1, true);
}

// Clicking icons
QTreeWidget::connect(this, &QTreeWidget::itemClicked,
this, &List::Tracks::onItemClicked);

// Play tracks on click or enter/special key
QTreeWidget::connect(this, &QTreeWidget::itemDoubleClicked,
this, &List::Tracks::onDoubleClicked);
Expand All @@ -56,6 +67,10 @@ List::Tracks::Tracks(lib::spt::api &spotify, lib::settings &settings, lib::cache
QLabel::connect(header(), &QWidget::customContextMenuRequested,
this, &List::Tracks::onHeaderMenu);

// Selecting track
QTreeWidget::connect(this, &QTreeWidget::currentItemChanged,
this, &List::Tracks::onCurrentItemChanged);

QShortcut::connect(new QShortcut(Shortcut::newPlaylist(), this),
&QShortcut::activated, this, &List::Tracks::onNewPlaylist);

Expand Down Expand Up @@ -102,6 +117,38 @@ void List::Tracks::onMenu(const QPoint &pos)
songMenu->popup(mapToGlobal(pos));
}

void List::Tracks::onItemClicked(QTreeWidgetItem *item, int column)
{
if (column == static_cast<int>(Column::Liked))
{
const auto &trackData = item->data(0, static_cast<int>(DataRole::Track));
const auto &track = trackData.value<lib::spt::track>();

const auto &likedData = item->data(0, static_cast<int>(DataRole::Liked));
const auto &isLiked = likedData.toBool();

const auto callback = [item, isLiked, column](const std::string &response)
{
if (response.empty())
{
item->setData(0, static_cast<int>(DataRole::Liked), !isLiked);
item->setIcon(column, Icon::get(isLiked
? QStringLiteral("non-starred-symbolic")
: QStringLiteral("starred-symbolic")));
}
};

if (isLiked)
{
spotify.remove_saved_tracks({track.id}, callback);
}
else
{
spotify.add_saved_tracks({track.id}, callback);
}
}
}

void List::Tracks::onDoubleClicked(QTreeWidgetItem *item, int /*column*/)
{
if (item->isDisabled())
Expand Down Expand Up @@ -151,8 +198,13 @@ void List::Tracks::onHeaderMenu(const QPoint &pos)
auto *menu = new QMenu(header());
auto *showHeaders = menu->addMenu(Icon::get("visibility"), "Columns to show");
auto *sortBy = menu->addMenu(Icon::get("view-sort-ascending"), "Default sorting");
QStringList headerTitles({
"Title", "Artist", "Album", "Length", "Added"
const QStringList headerTitles({
QStringLiteral("Title"),
QStringLiteral("Artist"),
QStringLiteral("Album"),
QStringLiteral("Length"),
QStringLiteral("Added"),
QStringLiteral("Liked"),
});
const auto &headers = this->settings.general.hidden_song_headers;

Expand Down Expand Up @@ -205,6 +257,31 @@ void List::Tracks::onHeaderMenuTriggered(QAction *action)
settings.save();
}

void List::Tracks::onCurrentItemChanged(QTreeWidgetItem *current, QTreeWidgetItem *previous)
{
if (previous != nullptr)
{
const auto &likedData = previous->data(0, static_cast<int>(DataRole::Liked));
const auto isLiked = likedData.toBool();
if (!isLiked)
{
previous->setIcon(static_cast<int>(Column::Liked), QIcon());
}
}

if (current == nullptr)
{
return;
}

const auto &likedData = current->data(0, static_cast<int>(DataRole::Liked));
const auto isLiked = likedData.toBool();

current->setIcon(static_cast<int>(Column::Liked), isLiked
? Icon::get(QStringLiteral("starred-symbolic"))
: Icon::get(QStringLiteral("non-starred-symbolic")));
}

void List::Tracks::onNewPlaylist()
{
const auto trackIds = getSelectedTrackIds();
Expand Down Expand Up @@ -300,8 +377,9 @@ void List::Tracks::resizeHeaders(const QSize &newSize)
constexpr int addedSize = 140;
constexpr int minSize = 60;
constexpr int columnCount = 7;
constexpr int likedSize = 40;

auto size = (newSize.width() - indexSize - lengthSize - addedSize) / columnCount;
auto size = (newSize.width() - indexSize - lengthSize - addedSize - likedSize) / columnCount;

if (size < minSize)
{
Expand All @@ -314,6 +392,7 @@ void List::Tracks::resizeHeaders(const QSize &newSize)
header()->resizeSection(static_cast<int>(Column::Album), size * 2);
header()->resizeSection(static_cast<int>(Column::Length), lengthSize);
header()->resizeSection(static_cast<int>(Column::Added), addedSize);
header()->resizeSection(static_cast<int>(Column::Liked), likedSize);
}

void List::Tracks::updateResizeMode(lib::resize_mode mode)
Expand Down Expand Up @@ -414,7 +493,7 @@ void List::Tracks::load(const std::vector<lib::spt::track> &tracks,
QString::fromStdString(track.album.name),
QString::fromStdString(lib::format::time(track.duration)),
getAddedText(added),
}, track, emptyIcon, index, QString::fromStdString(addedAt));
}, track, emptyIcon, index, QString::fromStdString(addedAt), false);

if (!anyHasDate && !added.empty())
{
Expand All @@ -440,6 +519,26 @@ void List::Tracks::load(const std::vector<lib::spt::track> &tracks,
header()->setSectionHidden(static_cast<int>(Column::Added), !anyHasDate
|| lib::set::contains(settings.general.hidden_song_headers,
static_cast<int>(Column::Added)));

getLikedTracks([this](const std::vector<lib::spt::track> &likedTracks)
{
for (const auto &likedTrack: likedTracks)
{
auto trackItem = trackItems.find(likedTrack.id);
if (trackItem == trackItems.end())
{
continue;
}

auto *item = dynamic_cast<ListItem::Track *>(trackItem->second);
if (item == nullptr)
{
continue;
}

item->setLiked(true);
}
});
}

void List::Tracks::load(const std::vector<lib::spt::track> &tracks)
Expand Down Expand Up @@ -571,3 +670,19 @@ auto List::Tracks::getCurrent() -> const spt::Current &
auto *mainWindow = MainWindow::find(parentWidget());
return mainWindow->getCurrent();
}

void List::Tracks::getLikedTracks(const std::function<void(const std::vector<lib::spt::track> &)> &callback)
{
const auto cachedTracks = cache.get_tracks("liked_tracks");
if (!cachedTracks.empty())
{
callback(cachedTracks);
return;
}

spotify.saved_tracks([this, callback](const std::vector<lib::spt::track> &tracks)
{
callback(tracks);
cache.set_tracks("liked_tracks", tracks);
});
}
5 changes: 5 additions & 0 deletions src/list/tracks.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -78,11 +78,16 @@ namespace List
auto getSelectedTrackIds() const -> std::vector<std::string>;
void resizeHeaders(const QSize &newSize);

void getLikedTracks(const std::function<void(const std::vector<lib::spt::track> &)> &callback);

void onMenu(const QPoint &pos);
void onItemClicked(QTreeWidgetItem *item, int column);
void onDoubleClicked(QTreeWidgetItem *item, int column);
void onHeaderMenu(const QPoint &pos);
void onHeaderMenuTriggered(QAction *action);

static void onCurrentItemChanged(QTreeWidgetItem *current, QTreeWidgetItem *previous);

void onNewPlaylist();
void onDelete();
void onPlaySelectedRow();
Expand Down
17 changes: 15 additions & 2 deletions src/listitem/track.cpp
Original file line number Diff line number Diff line change
@@ -1,13 +1,14 @@
#include "listitem/track.hpp"
#include "util/icon.hpp"

ListItem::Track::Track(const QStringList &strings, const lib::spt::track &track,
const QIcon &icon, int index)
: Track(strings, track, icon, index, {})
: Track(strings, track, icon, index, {}, false)
{
}

ListItem::Track::Track(const QStringList &strings, const lib::spt::track &track,
const QIcon &icon, int index, const QString &addedAt)
const QIcon &icon, int index, const QString &addedAt, bool isLiked)
: QTreeWidgetItem(strings)
{
setIcon(0, icon);
Expand All @@ -22,6 +23,8 @@ ListItem::Track::Track(const QStringList &strings, const lib::spt::track &track,
setData(0, static_cast<int>(DataRole::AddedDate), addedDate);
setData(0, static_cast<int>(DataRole::Length), track.duration);

setLiked(isLiked);

if (track.is_local || !track.is_playable)
{
setDisabled(true);
Expand Down Expand Up @@ -97,3 +100,13 @@ auto ListItem::Track::removePrefix(const QString &str) -> QString
? str.right(str.length() - 4)
: str;
}

void ListItem::Track::setLiked(bool isLiked)
{
const auto icon = isLiked
? Icon::get(QStringLiteral("starred-symbolic"))
: QIcon();

setIcon(static_cast<int>(Column::Liked), icon);
setData(0, static_cast<int>(DataRole::Liked), isLiked);
}
4 changes: 3 additions & 1 deletion src/listitem/track.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,9 @@ namespace ListItem
const QIcon &icon, int index);

Track(const QStringList &strings, const lib::spt::track &track,
const QIcon &icon, int index, const QString &addedAt);
const QIcon &icon, int index, const QString &addedAt, bool isLiked);

void setLiked(bool isLiked);

private:
auto operator<(const QTreeWidgetItem &item) const -> bool override;
Expand Down

0 comments on commit 7c74d40

Please sign in to comment.