123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353 |
- #include <cmath>
- #include <TweenEngine/Tween.h>
- #include <cpp3ds/System/Lock.hpp>
- #include "InstalledList.hpp"
- #include "AppList.hpp"
- #include "TitleKeys.hpp"
- namespace FreeShop {
- InstalledList::InstalledList()
- : m_scrollPos(0.f)
- , m_size(320.f, 0.f)
- , m_expandedItem(nullptr)
- , m_isUpdatingList(false)
- , m_gameCount(0)
- {
- // Make install options initially transparent for fade in
- TweenEngine::Tween::set(m_options, InstalledOptions::ALPHA)
- .target(0.f).start(m_tweenManager);
- }
- InstalledList &InstalledList::getInstance()
- {
- static InstalledList installedList;
- return installedList;
- }
- void InstalledList::refresh()
- {
- cpp3ds::Lock lock(m_mutexRefresh);
- cpp3ds::Uint64 relatedTitleId;
- std::vector<cpp3ds::Uint64> installedTitleIds;
- m_isUpdatingList = true;
- m_installedTitleIds.clear();
- m_installedItems.clear();
- m_expandedItem = nullptr;
- TweenEngine::Tween::set(m_options, InstalledOptions::ALPHA).target(0.f).start(m_tweenManager);
- #ifdef EMULATION
- // some hardcoded title IDs for testing
- installedTitleIds.emplace_back(0x00040000000edf00); // [US] Super Smash Bros.
- installedTitleIds.emplace_back(0x0004000e000edf00); // [US] Super Smash Bros. [UPDATE]
- installedTitleIds.emplace_back(0x00040002000edf01); // [US] Super Smash Bros. [DEMO]
- installedTitleIds.emplace_back(0x0004001000021800); // [US] StreetPass Mii Plaza
- installedTitleIds.emplace_back(0x0004000000030800); // [US] Mario Kart 7
- installedTitleIds.emplace_back(0x0004000000041700); // [US] Kirby's Dream Land
- installedTitleIds.emplace_back(0x0004008000008f00); // [US] Home Menu
- installedTitleIds.emplace_back(0x0004000000162000); // [EU] Project X Zone 2
- installedTitleIds.emplace_back(0x000400000017a400); // [EU] Fire Emblem Fates
- #else
- u32 titleCount;
- AM_GetTitleCount(MEDIATYPE_SD, &titleCount);
- installedTitleIds.resize(titleCount);
- AM_GetTitleList(nullptr, MEDIATYPE_SD, titleCount, &installedTitleIds[0]);
- AM_GetTitleCount(MEDIATYPE_NAND, &titleCount);
- installedTitleIds.resize(titleCount + installedTitleIds.size());
- AM_GetTitleList(nullptr, MEDIATYPE_NAND, titleCount, &installedTitleIds[installedTitleIds.size() - titleCount]);
- FS_CardType type;
- bool cardInserted;
- m_cardInserted = (R_SUCCEEDED(FSUSER_CardSlotIsInserted(&cardInserted)) && cardInserted && R_SUCCEEDED(FSUSER_GetCardType(&type)) && type == CARD_CTR);
- if (m_cardInserted)
- {
- // Retry a bunch of times. When the card is newly inserted,
- // it sometimes takes a short while before title can be read.
- int retryCount = 100;
- u64 cardTitleId;
- while (retryCount-- > 0)
- if (R_SUCCEEDED(AM_GetTitleList(nullptr, MEDIATYPE_GAME_CARD, 1, &cardTitleId)))
- {
- try
- {
- std::unique_ptr<InstalledItem> item(new InstalledItem(cardTitleId));
- m_installedItems.emplace_back(std::move(item));
- }
- catch (int e)
- {
- //
- }
- break;
- }
- else
- cpp3ds::sleep(cpp3ds::milliseconds(5));
- }
- #endif
- for (auto& titleId : installedTitleIds)
- {
- size_t titleType = titleId >> 32;
- if (titleType == TitleKeys::Game || titleType == TitleKeys::Update ||
- titleType == TitleKeys::DLC || titleType == TitleKeys::Demo || titleType == TitleKeys::DSiWare ||
- titleType == TitleKeys::SystemApplet || titleType == TitleKeys::SystemApplication)
- m_installedTitleIds.push_back(titleId);
- }
- // Add all primary game titles first
- for (auto& titleId : installedTitleIds)
- {
- TitleKeys::TitleType titleType = static_cast<TitleKeys::TitleType>(titleId >> 32);
- if (titleType == TitleKeys::Game || titleType == TitleKeys::DSiWare || titleType == TitleKeys::SystemApplication || titleType == TitleKeys::SystemApplet)
- try
- {
- std::unique_ptr<InstalledItem> item(new InstalledItem(titleId));
- m_installedItems.emplace_back(std::move(item));
- }
- catch (int e)
- {
- //std::cout << "Error while adding: " << titleId << std::endl;
- }
- }
- // Add updates that have not yet been installed for which we have a titlekey
- for (auto& titleId : TitleKeys::getIds())
- {
- size_t titleType = titleId >> 32;
- if (titleType == TitleKeys::Update || titleType == TitleKeys::DLC)
- {
- size_t titleLower = (titleId & 0xFFFFFFFF) >> 8;
- for (auto& installedItem : m_installedItems)
- {
- if (titleLower == (installedItem->getTitleId() & 0xFFFFFFFF) >> 8)
- {
- if (titleType == TitleKeys::Update)
- installedItem->setUpdateStatus(titleId, false);
- else
- installedItem->setDLCStatus(titleId, false);
- }
- }
- }
- }
- // Add all installed updates/DLC to the above titles added.
- // If not found, attempt to fetch parent title info from system.
- for (auto& titleId : installedTitleIds)
- {
- TitleKeys::TitleType titleType = static_cast<TitleKeys::TitleType>(titleId >> 32);
- if (titleType == TitleKeys::Update || titleType == TitleKeys::DLC)
- {
- cpp3ds::Uint32 titleLower = (titleId & 0xFFFFFFFF) >> 8;
- for (auto& installedItem : m_installedItems)
- {
- if (titleLower == (installedItem->getTitleId() & 0xFFFFFFFF) >> 8)
- {
- if (titleType == TitleKeys::Update)
- installedItem->setUpdateStatus(titleId, true);
- else
- installedItem->setDLCStatus(titleId, true);
- break;
- }
- }
- }
- }
- // Remove all system titles that have no Update or DLC
- for (auto it = m_installedItems.begin(); it != m_installedItems.end();)
- {
- size_t titleType = (*it)->getTitleId() >> 32;
- if ((titleType != TitleKeys::SystemApplication && titleType != TitleKeys::SystemApplet) ||
- ((*it)->hasDLC() || (*it)->hasDLC()))
- it++;
- else
- it = m_installedItems.erase(it);
- }
- // Sort alphabetically
- std::sort(m_installedItems.begin(), m_installedItems.end(), [=](const std::unique_ptr<InstalledItem>& a, const std::unique_ptr<InstalledItem>& b)
- {
- return a->getAppItem()->getNormalizedTitle() < b->getAppItem()->getNormalizedTitle();
- });
- repositionItems();
- m_isUpdatingList = false;
- }
- void InstalledList::draw(cpp3ds::RenderTarget &target, cpp3ds::RenderStates states) const
- {
- states.transform *= getTransform();
- states.scissor = cpp3ds::UintRect(0, 30, 320, 210);
- for (auto& item : m_installedItems)
- {
- float posY = item->getPosition().y;
- if (posY > -10.f && posY < 240.f)
- target.draw(*item, states);
- }
- if (m_expandedItem)
- target.draw(m_options, states);
- }
- void InstalledList::update(float delta)
- {
- #ifdef _3DS
- FS_CardType type;
- bool cardInserted;
- if (m_cardInserted != (R_SUCCEEDED(FSUSER_CardSlotIsInserted(&cardInserted)) && cardInserted && R_SUCCEEDED(FSUSER_GetCardType(&type)) && type == CARD_CTR))
- refresh();
- #endif
- m_tweenManager.update(delta);
- }
- bool InstalledList::processEvent(const cpp3ds::Event &event)
- {
- if (m_tweenManager.getRunningTweensCount() > 0)
- return false;
- if (event.type == cpp3ds::Event::TouchEnded)
- {
- if (event.touch.y < 30)
- return false;
- for (auto &item : m_installedItems)
- {
- float posY = getPosition().y + item->getPosition().y;
- if (event.touch.y > posY && event.touch.y < posY + item->getHeight())
- {
- if (item.get() == m_expandedItem)
- {
- if (event.touch.y < posY + 16.f)
- expandItem(nullptr);
- else
- m_options.processTouchEvent(event);
- }
- else
- expandItem(item.get());
- break;
- }
- }
- }
- return false;
- }
- void InstalledList::setScroll(float position)
- {
- m_scrollPos = std::round(position);
- repositionItems();
- }
- float InstalledList::getScroll()
- {
- return m_scrollPos;
- }
- void InstalledList::repositionItems()
- {
- float posY = 30.f + m_scrollPos;
- for (auto& item : m_installedItems)
- {
- if (item.get() == m_expandedItem)
- m_options.setPosition(0.f, posY + 20.f);
- item->setPosition(0.f, posY);
- posY += item->getHeight();
- }
- m_size.y = posY - 6.f - m_scrollPos;
- if (m_expandedItem)
- m_size.y -= 24.f;
- updateScrollSize();
- }
- const cpp3ds::Vector2f &InstalledList::getScrollSize()
- {
- return m_size;
- }
- void InstalledList::expandItem(InstalledItem *item)
- {
- if (item == m_expandedItem)
- return;
- const float optionsFadeDelay = 0.15f;
- const float expandDuration = 0.2f;
- // Expand animation
- if (m_expandedItem)
- {
- TweenEngine::Tween::to(*m_expandedItem, InstalledItem::HEIGHT, expandDuration)
- .target(16.f)
- .setCallback(TweenEngine::TweenCallback::COMPLETE, [=](TweenEngine::BaseTween* source) {
- m_expandedItem = item;
- repositionItems();
- })
- .delay(optionsFadeDelay)
- .start(m_tweenManager);
- TweenEngine::Tween::to(m_options, InstalledOptions::ALPHA, optionsFadeDelay + 0.05f)
- .target(0.f)
- .start(m_tweenManager);
- }
- if (item)
- {
- TweenEngine::Tween::to(*item, InstalledItem::HEIGHT, expandDuration)
- .target(40.f)
- .setCallback(TweenEngine::TweenCallback::COMPLETE, [=](TweenEngine::BaseTween* source) {
- m_expandedItem = item;
- m_options.setInstalledItem(item);
- repositionItems();
- })
- .delay(m_expandedItem ? optionsFadeDelay : 0.f)
- .start(m_tweenManager);
- TweenEngine::Tween::to(m_options, InstalledOptions::ALPHA, expandDuration)
- .target(255.f)
- .delay(m_expandedItem ? expandDuration + optionsFadeDelay : optionsFadeDelay)
- .start(m_tweenManager);
- }
- // Move animation for items in between expanded items
- bool foundItem = false;
- bool foundExpanded = false;
- for (auto &itemToMove : m_installedItems)
- {
- if (foundItem && !foundExpanded)
- {
- TweenEngine::Tween::to(*itemToMove, InstalledItem::POSITION_Y, expandDuration)
- .targetRelative(24.f)
- .delay(m_expandedItem ? optionsFadeDelay : 0.f)
- .start(m_tweenManager);
- }
- else if (foundExpanded && !foundItem)
- {
- TweenEngine::Tween::to(*itemToMove, InstalledItem::POSITION_Y, expandDuration)
- .targetRelative(-24.f)
- .delay(m_expandedItem ? optionsFadeDelay : 0.f)
- .start(m_tweenManager);
- }
- if (itemToMove.get() == m_expandedItem)
- foundExpanded = true;
- else if (itemToMove.get() == item)
- {
- foundItem = true;
- }
- if (foundExpanded && foundItem)
- break;
- }
- }
- bool InstalledList::isInstalled(cpp3ds::Uint64 titleId)
- {
- auto &v = getInstance().m_installedTitleIds;
- return std::find(v.begin(), v.end(), titleId) != v.end();
- }
- int InstalledList::getGameCount()
- {
- if (!m_isUpdatingList)
- m_gameCount = m_installedItems.size();
- return m_gameCount;
- }
- } // namespace FreeShop
|