Don't clear history each time individual items are added or removed.

This will prevent the playback history from vanishing unexpectedly in case a preset can't be loaded.

Also fixed a few typos in the Doxygen comments and clarified how the history is changed when changing the playlist.
This commit is contained in:
Kai Blaschke 2025-10-03 17:51:27 +02:00
parent 2da6db297e
commit 797a24251f
No known key found for this signature in database
GPG Key ID: B014B6811527389F
3 changed files with 126 additions and 9 deletions

View File

@ -65,13 +65,22 @@ bool Playlist::AddItem(const std::string& filename, uint32_t index, bool allowDu
} }
} }
m_presetHistory.clear();
if (index >= m_items.size()) if (index >= m_items.size())
{ {
m_items.emplace_back(filename); m_items.emplace_back(filename);
} }
else else
{ {
// Increment indices of items equal or grater than the newly added index.
for (auto& historyItem : m_presetHistory)
{
if (historyItem >= index)
{
historyItem++;
}
}
m_items.emplace(m_items.cbegin() + index, filename); m_items.emplace(m_items.cbegin() + index, filename);
} }
@ -83,7 +92,6 @@ auto Playlist::AddPath(const std::string& path, uint32_t index, bool recursive,
{ {
uint32_t presetsAdded{0}; uint32_t presetsAdded{0};
m_presetHistory.clear();
if (recursive) if (recursive)
{ {
try try
@ -129,6 +137,15 @@ auto Playlist::AddPath(const std::string& path, uint32_t index, bool recursive,
} }
} }
// Increment indices of items in playback history equal or grater than the newly added index.
for (auto& historyItem : m_presetHistory)
{
if (historyItem >= index)
{
historyItem += presetsAdded;
}
}
return presetsAdded; return presetsAdded;
} }
@ -140,7 +157,23 @@ auto Playlist::RemoveItem(uint32_t index) -> bool
return false; return false;
} }
m_presetHistory.clear(); // Remove item from history and decrement indices of items after the removed index.
for (auto it = begin(m_presetHistory); it != end(m_presetHistory);)
{
if (*it == index)
{
it = m_presetHistory.erase(it);
continue;
}
if (*it > index)
{
(*it)--;
}
++it;
}
m_items.erase(m_items.cbegin() + index); m_items.erase(m_items.cbegin() + index);
return true; return true;
@ -333,6 +366,15 @@ void Playlist::RemoveLastHistoryEntry()
} }
auto Playlist::HistoryItems() const -> std::vector<uint32_t>
{
std::vector<uint32_t> items;
std::copy(begin(m_presetHistory), end(m_presetHistory), std::back_inserter(items));
return items;
}
auto Playlist::Filter() -> class Filter& auto Playlist::Filter() -> class Filter&
{ {
return m_filter; return m_filter;

View File

@ -37,7 +37,7 @@ class Playlist
{ {
public: public:
/** /**
* Short-hand constant which can be used in AddItem() to add new presets at the end of the playlist. * Shorthand constant which can be used in AddItem() to add new presets at the end of the playlist.
*/ */
static constexpr auto InsertAtEnd = std::numeric_limits<uint32_t>::max(); static constexpr auto InsertAtEnd = std::numeric_limits<uint32_t>::max();
@ -89,7 +89,7 @@ public:
virtual bool Empty() const; virtual bool Empty() const;
/** /**
* @brief Clears the current playlist. * @brief Clears the current playlist and playback history.
*/ */
virtual void Clear(); virtual void Clear();
@ -97,13 +97,15 @@ public:
* @brief Returns the playlist items. * @brief Returns the playlist items.
* @return A vector with items in the current playlist. * @return A vector with items in the current playlist.
*/ */
virtual const std::vector<Item>& Items() const; virtual auto Items() const -> const std::vector<Item>&;
/** /**
* @brief Adds a preset file to the playlist. * @brief Adds a preset file to the playlist.
* *
* Use Playlist::InsertAtEnd as index to always insert an item at the end of the playlist. * Use Playlist::InsertAtEnd as index to always insert an item at the end of the playlist.
* *
* The playback history will be kept, and indices are updated accordingly.
*
* @param filename The file path and name to add. * @param filename The file path and name to add.
* @param index The index to insert the preset at. If larger than the playlist size, it's added * @param index The index to insert the preset at. If larger than the playlist size, it's added
* to the end of the playlist. * to the end of the playlist.
@ -117,7 +119,9 @@ public:
* @brief Adds presets (recursively) from the given path. * @brief Adds presets (recursively) from the given path.
* *
* The function will scan the given path (and possible subdirs) for files with a .milk extension * The function will scan the given path (and possible subdirs) for files with a .milk extension
* and and the to the playlist, starting at the given index. * and add them to the playlist, starting at the given index.
*
* The playback history will be kept, and indices are updated accordingly.
* *
* The order of the added files is unspecified. Use the Sort() method to sort the playlist or * The order of the added files is unspecified. Use the Sort() method to sort the playlist or
* the newly added range. * the newly added range.
@ -135,7 +139,8 @@ public:
bool allowDuplicates) -> uint32_t; bool allowDuplicates) -> uint32_t;
/** /**
* @brief Removed a playlist item at the given playlist index. * @brief Removes a playlist item at the given playlist index.
* The playback history will be kept, and indices are updated accordingly.
* @param index The index to remove. * @param index The index to remove.
* @return True if an item was removed, false if the index was out of bounds and no item was * @return True if an item was removed, false if the index was out of bounds and no item was
* removed.. * removed..
@ -159,6 +164,8 @@ public:
* *
* Sorting is case-sensitive. * Sorting is case-sensitive.
* *
* The playback history is cleared when calling this function.
*
* @param startIndex The index to start sorting at. If the index is larger than the last * @param startIndex The index to start sorting at. If the index is larger than the last
* item index, the playlist will remain unchanged. * item index, the playlist will remain unchanged.
* @param count The number of items to sort. If the value exceeds the playlist length, only * @param count The number of items to sort. If the value exceeds the playlist length, only
@ -226,6 +233,12 @@ public:
*/ */
virtual void RemoveLastHistoryEntry(); virtual void RemoveLastHistoryEntry();
/**
* @brief Returns a vector with the playlist indices of the current playback history.
* @return A vector of indices with the last played presets.
*/
virtual auto HistoryItems() const -> std::vector<uint32_t>;
/** /**
* @brief Returns the current playlist filter list. * @brief Returns the current playlist filter list.
* @return The filter list for the current playlist. * @return The filter list for the current playlist.

View File

@ -153,6 +153,38 @@ TEST(projectMPlaylistPlaylist, AddItemNoDuplicates)
} }
TEST(projectMPlaylistPlaylist, AddItemWithHistory)
{
Playlist playlist;
EXPECT_TRUE(playlist.AddItem("/some/file", 0, false));
EXPECT_TRUE(playlist.AddItem("/some/other/file", Playlist::InsertAtEnd, false));
EXPECT_TRUE(playlist.AddItem("/and/another/file", Playlist::InsertAtEnd, false));
ASSERT_EQ(playlist.Size(), 3);
playlist.SetPresetIndex(1);
playlist.SetPresetIndex(2);
playlist.SetPresetIndex(0);
auto historyItemsBefore = playlist.HistoryItems();
ASSERT_EQ(historyItemsBefore.size(), 3);
EXPECT_EQ(historyItemsBefore.at(0), 0); // Playback started with index 0
EXPECT_EQ(historyItemsBefore.at(1), 1);
EXPECT_EQ(historyItemsBefore.at(2), 2);
EXPECT_TRUE(playlist.AddItem("/yet/another/file", 1, false));
ASSERT_EQ(playlist.Size(), 4);
auto historyItemsAfter = playlist.HistoryItems();
ASSERT_EQ(historyItemsAfter.size(), 3);
EXPECT_EQ(historyItemsAfter.at(0), 0);
EXPECT_EQ(historyItemsAfter.at(1), 2);
EXPECT_EQ(historyItemsAfter.at(2), 3);
}
TEST(projectMPlaylistPlaylist, AddPathRecursively) TEST(projectMPlaylistPlaylist, AddPathRecursively)
{ {
Playlist playlist; Playlist playlist;
@ -218,7 +250,7 @@ TEST(projectMPlaylistPlaylist, AddPathNonRecursively)
} }
TEST(projectMPlaylistPlaylist, AddPathnonRecursivelyNoDuplicates) TEST(projectMPlaylistPlaylist, AddPathNonRecursivelyNoDuplicates)
{ {
Playlist playlist; Playlist playlist;
@ -289,6 +321,36 @@ TEST(projectMPlaylistPlaylist, RemoveItemFromMiddle)
} }
TEST(projectMPlaylistPlaylist, RemoveItemWithHistory)
{
Playlist playlist;
EXPECT_TRUE(playlist.AddItem("/some/file", Playlist::InsertAtEnd, false));
EXPECT_TRUE(playlist.AddItem("/some/other/file", Playlist::InsertAtEnd, false));
EXPECT_TRUE(playlist.AddItem("/yet/another/file", Playlist::InsertAtEnd, false));
ASSERT_EQ(playlist.Size(), 3);
playlist.SetPresetIndex(1);
playlist.SetPresetIndex(2);
playlist.SetPresetIndex(0);
auto historyItemsBefore = playlist.HistoryItems();
ASSERT_EQ(historyItemsBefore.size(), 3);
EXPECT_EQ(historyItemsBefore.at(0), 0); // Playback started with index 0
EXPECT_EQ(historyItemsBefore.at(1), 1);
EXPECT_EQ(historyItemsBefore.at(2), 2);
EXPECT_TRUE(playlist.RemoveItem(1));
ASSERT_EQ(playlist.Size(), 2);
auto historyItemsAfter = playlist.HistoryItems();
ASSERT_EQ(historyItemsAfter.size(), 2);
EXPECT_EQ(historyItemsAfter.at(0), 0);
EXPECT_EQ(historyItemsAfter.at(1), 1);
}
TEST(projectMPlaylistPlaylist, RemoveItemIndexOutOfBounds) TEST(projectMPlaylistPlaylist, RemoveItemIndexOutOfBounds)
{ {
Playlist playlist; Playlist playlist;