Files
sphaira/sphaira/include/ui/menus/appstore.hpp
2025-05-26 22:55:06 +01:00

206 lines
5.2 KiB
C++

#pragma once
#include "ui/menus/grid_menu_base.hpp"
#include "ui/scrollable_text.hpp"
#include "ui/scrolling_text.hpp"
#include "ui/list.hpp"
#include "fs.hpp"
#include "option.hpp"
#include <span>
namespace sphaira::ui::menu::appstore {
struct ManifestEntry {
char command;
fs::FsPath path;
};
using ManifestEntries = std::vector<ManifestEntry>;
enum class ImageDownloadState {
None, // not started
Progress, // Download started
Done, // finished downloading
Failed, // attempted to download but failed
};
struct LazyImage {
LazyImage() = default;
~LazyImage();
int image{};
int w{}, h{};
bool tried_cache{};
bool cached{};
ImageDownloadState state{ImageDownloadState::None};
u8 first_pixel[4]{};
};
enum class EntryStatus {
Get,
Installed,
Local,
Update,
};
struct Entry {
std::string category{}; // todo: lable
std::string binary{}; // optional, only valid for .nro
std::string updated{}; // date of update
std::string name{};
std::string license{}; // optional
std::string title{}; // same as name but with spaces
std::string url{}; // url of repo (optional?)
std::string description{};
std::string author{};
std::string changelog{}; // optional
u64 screens{}; // number of screenshots
u64 extracted{}; // extracted size in KiB
std::string version{};
u64 filesize{}; // compressed size in KiB
std::string details{};
u64 app_dls{};
std::string md5{}; // md5 of the zip
LazyImage image{};
u32 updated_num{};
EntryStatus status{EntryStatus::Get};
};
// number to index m_entries to get entry
using EntryMini = u32;
struct Menu; // fwd
struct EntryMenu final : MenuBase {
EntryMenu(Entry& entry, const LazyImage& default_icon, Menu& menu);
~EntryMenu();
auto GetShortTitle() const -> const char* override { return "Entry"; };
void Update(Controller* controller, TouchInfo* touch) override;
void Draw(NVGcontext* vg, Theme* theme) override;
// void OnFocusGained() override;
void ShowChangelogAction();
void SetIndex(s64 index);
void UpdateOptions();
private:
struct Option {
Option(const std::string& dt, const std::string& ct, std::function<void(void)> f)
: display_text{dt}, confirm_text{ct}, func{f} {}
Option(const std::string& dt, std::function<void(void)> f)
: display_text{dt}, func{f} {}
std::string display_text{};
std::string confirm_text{};
std::function<void(void)> func{};
};
Entry& m_entry;
const LazyImage& m_default_icon;
Menu& m_menu;
s64 m_index{}; // where i am in the array
std::vector<Option> m_options{};
LazyImage m_banner{};
std::unique_ptr<List> m_list{};
std::shared_ptr<ScrollableText> m_details{};
std::shared_ptr<ScrollableText> m_changelog{};
std::shared_ptr<ScrollableText> m_detail_changelog{};
bool m_show_changlog{};
};
enum Filter {
Filter_All,
Filter_Games,
Filter_Emulators,
Filter_Tools,
Filter_Advanced,
Filter_Themes,
Filter_Legacy,
Filter_Misc,
Filter_MAX,
};
enum SortType {
SortType_Updated,
SortType_Downloads,
SortType_Size,
SortType_Alphabetical,
};
enum OrderType {
OrderType_Descending,
OrderType_Ascending,
};
using LayoutType = grid::LayoutType;
struct Menu final : grid::Menu {
Menu(u32 flags);
~Menu();
auto GetShortTitle() const -> const char* override { return "Store"; };
void Update(Controller* controller, TouchInfo* touch) override;
void Draw(NVGcontext* vg, Theme* theme) override;
void OnFocusGained() override;
void SetAuthor();
auto GetEntry(s64 i) -> Entry& {
return m_entries[m_entries_current[i]];
}
auto GetEntry() -> Entry& {
return GetEntry(m_index);
}
auto SetDirty() {
m_dirty = true;
}
private:
void SetIndex(s64 index);
void ScanHomebrew();
void Sort();
void SortAndFindLastFile();
void SetFilter();
void SetSearch(const std::string& term);
void OnLayoutChange();
private:
static constexpr inline const char* INI_SECTION = "appstore";
std::vector<Entry> m_entries{};
std::vector<EntryMini> m_entries_index[Filter_MAX]{};
std::vector<EntryMini> m_entries_index_author{};
std::vector<EntryMini> m_entries_index_search{};
std::span<EntryMini> m_entries_current{};
option::OptionLong m_filter{INI_SECTION, "filter", Filter::Filter_All};
option::OptionLong m_sort{INI_SECTION, "sort", SortType::SortType_Updated};
option::OptionLong m_order{INI_SECTION, "order", OrderType::OrderType_Descending};
option::OptionLong m_layout{INI_SECTION, "layout", LayoutType::LayoutType_GridDetail};
s64 m_index{}; // where i am in the array
LazyImage m_default_image{};
LazyImage m_update{};
LazyImage m_get{};
LazyImage m_local{};
LazyImage m_installed{};
ImageDownloadState m_repo_download_state{ImageDownloadState::None};
std::unique_ptr<List> m_list{};
std::string m_search_term{};
std::string m_author_term{};
s64 m_entry_search_jump_back{};
s64 m_entry_author_jump_back{};
bool m_is_search{};
bool m_is_author{};
bool m_dirty{}; // if set, does a sort
};
} // namespace sphaira::ui::menu::appstore