Added favorites playlist support for menus and merged/sub collections.

Improved sorting algorithm for playlists. The order now follows the order of the complete lis
t.
Added favorites playlist display to Aeon Nox theme.
Added favorites common artwork.
Added reloadableMedia support for playlist display.
This commit is contained in:
Pieter Hulshoff 2016-09-16 09:45:22 +02:00
parent 596c636eda
commit 304154a4c4
13 changed files with 289 additions and 55 deletions

Binary file not shown.

After

Width:  |  Height:  |  Size: 118 KiB

View File

@ -1970,4 +1970,46 @@
</reloadableVideo>
<!----------------------------------------------------------------------------------------------------------------------------------->
<!-- Playlist -->
<!----------------------------------------------------------------------------------------------------------------------------------->
<reloadableImage type="playlist" mode="common" alpha="0" x="1100" y="430" xOrigin="center" yOrigin="top" maxHeight="40" layer="19">
<onEnter>
<set duration=".8">
<animate type="nop"/>
</set>
</onEnter>
<onExit>
<set duration=".25">
<animate type="alpha" to="0" algorithm="easeinquadratic"/>
</set>
</onExit>
<onMenuEnter menuIndex="0">
<set duration=".8">
<animate type="y" to="430" algorithm="easeinquadratic"/>
</set>
</onMenuEnter>
<onMenuEnter menuIndex="1">
<set duration=".25">
<animate type="y" from="-50" to="2" algorithm="easeinquadratic"/>
</set>
</onMenuEnter>
<onMenuExit>
<set duration=".25">
<animate type="alpha" to="0" algorithm="easeinquadratic"/>
</set>
</onMenuExit>
<onIdle>
<set duration="1">
<animate type="alpha" to="0.5" algorithm="easeinquadratic"/>
</set>
<set duration="1">
<animate type="alpha" to="1" algorithm="easeinquadratic"/>
</set>
</onIdle>
</reloadableImage>
</layout>

View File

@ -1970,4 +1970,46 @@
</reloadableVideo>
<!----------------------------------------------------------------------------------------------------------------------------------->
<!-- Playlist -->
<!----------------------------------------------------------------------------------------------------------------------------------->
<reloadableImage type="playlist" mode="common" alpha="0" x="940" y="505" xOrigin="center" yOrigin="top" maxHeight="40" layer="19">
<onEnter>
<set duration=".8">
<animate type="nop"/>
</set>
</onEnter>
<onExit>
<set duration=".25">
<animate type="alpha" to="0" algorithm="easeinquadratic"/>
</set>
</onExit>
<onMenuEnter menuIndex="0">
<set duration=".8">
<animate type="y" to="505" algorithm="easeinquadratic"/>
</set>
</onMenuEnter>
<onMenuEnter menuIndex="1">
<set duration=".25">
<animate type="y" from="-50" to="2" algorithm="easeinquadratic"/>
</set>
</onMenuEnter>
<onMenuExit>
<set duration=".25">
<animate type="alpha" to="0" algorithm="easeinquadratic"/>
</set>
</onMenuExit>
<onIdle>
<set duration="1">
<animate type="alpha" to="0.5" algorithm="easeinquadratic"/>
</set>
<set duration="1">
<animate type="alpha" to="1" algorithm="easeinquadratic"/>
</set>
</onIdle>
</reloadableImage>
</layout>

View File

@ -1970,4 +1970,46 @@
</reloadableVideo>
<!----------------------------------------------------------------------------------------------------------------------------------->
<!-- Playlist -->
<!----------------------------------------------------------------------------------------------------------------------------------->
<reloadableImage type="playlist" mode="common" alpha="0" x="1100" y="430" xOrigin="center" yOrigin="top" maxHeight="40" layer="19">
<onEnter>
<set duration=".8">
<animate type="nop"/>
</set>
</onEnter>
<onExit>
<set duration=".25">
<animate type="alpha" to="0" algorithm="easeinquadratic"/>
</set>
</onExit>
<onMenuEnter menuIndex="0">
<set duration=".8">
<animate type="y" to="430" algorithm="easeinquadratic"/>
</set>
</onMenuEnter>
<onMenuEnter menuIndex="1">
<set duration=".25">
<animate type="y" from="-50" to="2" algorithm="easeinquadratic"/>
</set>
</onMenuEnter>
<onMenuExit>
<set duration=".25">
<animate type="alpha" to="0" algorithm="easeinquadratic"/>
</set>
</onMenuExit>
<onIdle>
<set duration="1">
<animate type="alpha" to="0.5" algorithm="easeinquadratic"/>
</set>
<set duration="1">
<animate type="alpha" to="1" algorithm="easeinquadratic"/>
</set>
</onIdle>
</reloadableImage>
</layout>

View File

@ -51,16 +51,6 @@ CollectionInfo::CollectionInfo(std::string name,
CollectionInfo::~CollectionInfo()
{
// remove items from the subcollections so their destructors do not
// delete the items since the parent collection will delete them.
std::vector<CollectionInfo *>::iterator subit;
for (subit = subcollections_.begin(); subit != subcollections_.end(); subit++)
{
CollectionInfo *info = *subit;
info->items.clear();
}
Playlists_T::iterator pit = playlists.begin();
while(pit != playlists.end())
@ -129,7 +119,14 @@ bool CollectionInfo::Save()
std::vector<Item *> *saveitems = playlists["favorites"];
for(std::vector<Item *>::iterator it = saveitems->begin(); it != saveitems->end(); it++)
{
filestream << (*it)->name << std::endl;
if ((*it)->collectionInfo->name == name)
{
filestream << (*it)->name << std::endl;
}
else
{
filestream << "_" << (*it)->collectionInfo->name << ":" << (*it)->name << std::endl;
}
}
filestream.close();
@ -163,16 +160,9 @@ void CollectionInfo::extensionList(std::vector<std::string> &extensionlist)
void CollectionInfo::addSubcollection(CollectionInfo *newinfo)
{
subcollections_.push_back(newinfo);
items.insert(items.begin(), newinfo->items.begin(), newinfo->items.end());
}
bool CollectionInfo::hasSubcollections()
{
return (subcollections_.size() > 0);
}
bool CollectionInfo::itemIsLess(Item *lhs, Item *rhs)
{
if(lhs->leaf && !rhs->leaf) return true;
@ -189,3 +179,28 @@ void CollectionInfo::sortItems()
std::sort(it->second->begin(), it->second->end(), itemIsLess);
}
}
void CollectionInfo::sortFavoriteItems()
{
std::vector<Item *> *allItems = playlists["all"];
std::vector<Item *> favItems;
for(std::vector <Item *>::iterator itFav = playlists["favorites"]->begin(); itFav != playlists["favorites"]->end(); itFav++)
{
favItems.push_back((*itFav));
}
playlists["favorites"]->clear();
for(std::vector <Item *>::iterator itAll = allItems->begin(); itAll != allItems->end(); itAll++)
{
for(std::vector <Item *>::iterator itFav = favItems.begin(); itFav != favItems.end(); itFav++)
{
if ((*itAll) == (*itFav))
{
playlists["favorites"]->push_back((*itAll));
}
}
}
}

View File

@ -29,8 +29,8 @@ public:
std::string settingsPath() const;
bool Save();
void sortItems();
void sortFavoriteItems();
void addSubcollection(CollectionInfo *info);
bool hasSubcollections();
void extensionList(std::vector<std::string> &extensions);
std::string name;
std::string listpath;
@ -44,7 +44,6 @@ public:
bool menusort;
private:
std::vector<CollectionInfo *> subcollections_;
std::string metadataPath_;
std::string extensions_;
static bool itemIsLess(Item *lhs, Item *rhs);

View File

@ -232,12 +232,9 @@ bool CollectionInfoBuilder::ImportDirectory(CollectionInfo *info, std::string me
DIR *dp;
struct dirent *dirp;
std::string path = info->listpath;
std::map<std::string, Item *> allMap;
std::map<std::string, Item *> includeFilter;
std::map<std::string, Item *> favoritesFilter;
std::map<std::string, Item *> excludeFilter;
std::string includeFile = Utils::combinePath(Configuration::absolutePath, "collections", info->name, "include.txt");
std::string favoritesFile = Utils::combinePath(Configuration::absolutePath, "collections", info->name, "playlists/favorites.txt");
std::string excludeFile = Utils::combinePath(Configuration::absolutePath, "collections", info->name, "exclude.txt");
std::string launcher;
@ -344,28 +341,52 @@ bool CollectionInfoBuilder::ImportDirectory(CollectionInfo *info, std::string me
excludeFilter.erase(it);
}
for(std::vector<Item *>::iterator it = info->items.begin(); it != info->items.end(); it++) {
allMap[(*it)->fullTitle] = *it;
}
ImportBasicList(info, favoritesFile, favoritesFilter);
info->playlists["all"] = &info->items;
return true;
}
void CollectionInfoBuilder::addFavorites(CollectionInfo *info)
{
std::map<std::string, Item *> favoritesFilter;
std::string favoritesFile = Utils::combinePath(Configuration::absolutePath, "collections", info->name, "playlists/favorites.txt");
ImportBasicList(info, favoritesFile, favoritesFilter);
info->playlists["favorites"] = new std::vector<Item *>();
// add the favorites list
for(std::map<std::string, Item *>::iterator it = favoritesFilter.begin(); it != favoritesFilter.end(); it++)
{
std::map<std::string, Item *>::iterator itemit = allMap.find(it->first);
if(itemit != allMap.end())
std::string collectionName = info->name;
std::string itemName = it->first;
if (itemName.at(0) == '_') // name consists of _<collectionName>:<itemName>
{
info->playlists["favorites"]->push_back(itemit->second);
itemName.erase(0, 1); // Remove _
size_t position = itemName.find(":");
if (position != std::string::npos )
{
collectionName = itemName.substr(0, position);
itemName = itemName.erase(0, position+1);
}
}
for(std::vector<Item *>::iterator it = info->items.begin(); it != info->items.end(); it++)
{
if( (*it)->name == itemName && (*it)->collectionInfo->name == collectionName)
{
info->playlists["favorites"]->push_back((*it));
}
}
}
metaDB_.injectMetadata(info);
return true;
return;
}
void CollectionInfoBuilder::injectMetadata(CollectionInfo *info)
{
metaDB_.injectMetadata(info);
return;
}

View File

@ -31,6 +31,8 @@ public:
virtual ~CollectionInfoBuilder();
CollectionInfo *buildCollection(std::string collectionName);
CollectionInfo *buildCollection(std::string collectionName, std::string mergedCollectionName);
void addFavorites(CollectionInfo *info);
void injectMetadata(CollectionInfo *info);
static bool createCollectionDirectory(std::string collectionName);
private:

View File

@ -276,6 +276,10 @@ void ReloadableMedia::reloadTexture()
{
basename = selectedItem->score;
}
else if(typeLC == "playlist")
{
basename = page.getPlaylistName();
}
Utils::replaceSlashesWithUnderscores(basename);

View File

@ -700,7 +700,6 @@ void Page::draw()
void Page::removePlaylist()
{
if(!selectedItem_) return;
if(!selectedItem_->leaf) return;
MenuInfo_S &info = collections_.back();
CollectionInfo *collection = info.collection;
@ -711,14 +710,15 @@ void Page::removePlaylist()
if(it != items->end())
{
items->erase(it);
collection->sortFavoriteItems();
collection->saveRequest = true;
}
collection->Save();
}
void Page::addPlaylist()
{
if(!selectedItem_) return;
if(!selectedItem_->leaf) return;
MenuInfo_S &info = collections_.back();
CollectionInfo *collection = info.collection;
@ -727,9 +727,10 @@ void Page::addPlaylist()
if(playlist_->first != "favorites" && std::find(items->begin(), items->end(), selectedItem_) == items->end())
{
items->push_back(selectedItem_);
collection->sortItems();
collection->sortFavoriteItems();
collection->saveRequest = true;
}
collection->Save();
}
std::string Page::getCollectionName()

View File

@ -321,17 +321,21 @@ void RetroFE::run()
if(currentPage_)
{
std::string firstCollection = "Main";
bool menuSort = true;
config_.getProperty("firstCollection", firstCollection);
config_.getProperty("collections." + firstCollection + ".list.menuSort", menuSort);
config_.setProperty("currentCollection", firstCollection);
CollectionInfo *info = getCollection(firstCollection);
MenuParser mp;
mp.buildMenuItems(info, menuSort);
currentPage_->pushCollection(info);
bool autoFavorites = true;
config_.getProperty("autoFavorites", autoFavorites);
if (autoFavorites)
{
currentPage_->selectPlaylist("favorites"); // Switch to favorites playlist
}
currentPage_->onNewItemSelected();
currentPage_->reallocateMenuSpritePoints();
@ -344,6 +348,36 @@ void RetroFE::run()
}
break;
case RETROFE_PLAYLIST_REQUEST:
currentPage_->highlightExit();
currentPage_->setScrolling(Page::ScrollDirectionIdle);
state = RETROFE_PLAYLIST_EXIT;
break;
case RETROFE_PLAYLIST_EXIT:
if (currentPage_->isIdle())
{
currentPage_->onNewItemSelected();
state = RETROFE_PLAYLIST_LOAD_ART;
}
break;
case RETROFE_PLAYLIST_LOAD_ART:
if (currentPage_->isIdle())
{
currentPage_->reallocateMenuSpritePoints();
currentPage_->highlightEnter();
state = RETROFE_PLAYLIST_ENTER;
}
break;
case RETROFE_PLAYLIST_ENTER:
if (currentPage_->isIdle())
{
state = RETROFE_IDLE;
}
break;
case RETROFE_HIGHLIGHT_REQUEST:
currentPage_->highlightExit();
currentPage_->setScrolling(Page::ScrollDirectionIdle);
@ -395,6 +429,8 @@ void RetroFE::run()
case RETROFE_NEXT_PAGE_MENU_EXIT:
if(currentPage_->isIdle())
{
lastMenuOffsets_[currentPage_->getCollectionName()] = currentPage_->getScrollOffsetIndex();
lastMenuPlaylists_[currentPage_->getCollectionName()] = currentPage_->getPlaylistName();
// Load new layout if available
std::string layoutName;
config_.getProperty("layout", layoutName);
@ -408,14 +444,10 @@ void RetroFE::run()
currentPage_ = page;
}
bool menuSort = true;
config_.setProperty("currentCollection", nextPageName);
config_.getProperty("collections." + nextPageName + ".list.menuSort", menuSort);
CollectionInfo *info = getCollection(nextPageName);
MenuParser mp;
mp.buildMenuItems(info, menuSort);
currentPage_->pushCollection(info);
bool rememberMenu = false;
@ -502,6 +534,26 @@ void RetroFE::run()
currentPage_->popCollection();
}
config_.setProperty("currentCollection", currentPage_->getCollectionName());
bool rememberMenu = false;
config_.getProperty("rememberMenu", rememberMenu);
bool autoFavorites = true;
config_.getProperty("autoFavorites", autoFavorites);
if (rememberMenu && lastMenuPlaylists_.find(currentPage_->getCollectionName()) != lastMenuPlaylists_.end())
{
currentPage_->selectPlaylist(lastMenuPlaylists_[currentPage_->getCollectionName()]); // Switch to last playlist
}
else if (autoFavorites)
{
currentPage_->selectPlaylist("favorites"); // Switch to favorites playlist
}
if(rememberMenu && lastMenuOffsets_.find(currentPage_->getCollectionName()) != lastMenuOffsets_.end())
{
currentPage_->setScrollOffsetIndex(lastMenuOffsets_[currentPage_->getCollectionName()]);
}
currentPage_->onNewItemSelected();
currentPage_->reallocateMenuSpritePoints();
state = RETROFE_BACK_MENU_LOAD_ART;
@ -671,19 +723,17 @@ RetroFE::RETROFE_STATE RetroFE::processUserInput(Page *page)
if(input_.newKeyPressed(UserInput::KeyCodeNextPlaylist))
{
page->nextPlaylist();
page->reallocateMenuSpritePoints();
state = RETROFE_HIGHLIGHT_REQUEST;
state = RETROFE_PLAYLIST_REQUEST;
}
if(input_.newKeyPressed(UserInput::KeyCodeRemovePlaylist))
{
page->removePlaylist();
page->onNewItemSelected();
page->reallocateMenuSpritePoints();
state = RETROFE_PLAYLIST_REQUEST;
}
if(input_.newKeyPressed(UserInput::KeyCodeAddPlaylist))
{
page->addPlaylist();
page->reallocateMenuSpritePoints();
state = RETROFE_PLAYLIST_REQUEST;
}
if(input_.keystate(UserInput::KeyCodeRandom))
{
@ -779,6 +829,8 @@ CollectionInfo *RetroFE::getCollection(std::string collectionName)
CollectionInfoBuilder cib(config_, *metadb_);
CollectionInfo *collection = cib.buildCollection(collectionName);
cib.injectMetadata(collection);
DIR *dp;
struct dirent *dirp;
@ -803,11 +855,21 @@ CollectionInfo *RetroFE::getCollection(std::string collectionName)
CollectionInfo *subcollection = cib.buildCollection(basename, collectionName);
collection->addSubcollection(subcollection);
cib.injectMetadata(subcollection);
}
}
}
collection->sortItems();
bool menuSort = true;
config_.getProperty("collections." + collectionName + ".list.menuSort", menuSort);
MenuParser mp;
mp.buildMenuItems(collection, menuSort);
cib.addFavorites(collection);
collection->sortFavoriteItems();
return collection;
}

View File

@ -55,6 +55,10 @@ private:
RETROFE_LOAD_ART,
RETROFE_ENTER,
RETROFE_SPLASH_EXIT,
RETROFE_PLAYLIST_REQUEST,
RETROFE_PLAYLIST_EXIT,
RETROFE_PLAYLIST_LOAD_ART,
RETROFE_PLAYLIST_ENTER,
RETROFE_HIGHLIGHT_REQUEST,
RETROFE_HIGHLIGHT_EXIT,
RETROFE_HIGHLIGHT_LOAD_ART,

View File

@ -20,7 +20,7 @@
std::string retrofe_version_major = "0";
std::string retrofe_version_minor = "7";
std::string retrofe_version_build = "15";
std::string retrofe_version_build = "16";
std::string Version::getString()