diff --git a/sphaira/include/app.hpp b/sphaira/include/app.hpp index 690a945..b14af12 100644 --- a/sphaira/include/app.hpp +++ b/sphaira/include/app.hpp @@ -57,6 +57,8 @@ public: static void SetTheme(u64 theme_index); static auto GetThemeIndex() -> u64; + static auto GetDefaultImage(int* w = nullptr, int* h = nullptr) -> int; + // returns argv[0] static auto GetExePath() -> fs::FsPath; // returns true if we are hbmenu. @@ -119,6 +121,7 @@ public: u64 m_start_timestamp{}; u64 m_prev_timestamp{}; fs::FsPath m_prev_last_launch{}; + int m_default_image{}; bool m_is_launched_via_sphaira_forwader{}; diff --git a/sphaira/include/nro.hpp b/sphaira/include/nro.hpp index 2de2680..5317477 100644 --- a/sphaira/include/nro.hpp +++ b/sphaira/include/nro.hpp @@ -19,7 +19,6 @@ struct NroEntry { s64 size{}; NacpStruct nacp{}; - std::vector icon{}; u64 icon_size{}; u64 icon_offset{}; diff --git a/sphaira/include/ui/menus/menu_base.hpp b/sphaira/include/ui/menus/menu_base.hpp index c1ab94d..fd23ca1 100644 --- a/sphaira/include/ui/menus/menu_base.hpp +++ b/sphaira/include/ui/menus/menu_base.hpp @@ -21,6 +21,9 @@ struct MenuBase : Widget { void SetTitleSubHeading(std::string sub_heading); void SetSubHeading(std::string sub_heading); + static auto ScrollHelperDown(u64& index, u64& start, u64 step, s64 row, s64 page, u64 size) -> bool; + static auto ScrollHelperUp(u64& index, u64& start, s64 step, s64 row, s64 page, s64 size) -> bool; + private: void UpdateVars(); diff --git a/sphaira/include/ui/types.hpp b/sphaira/include/ui/types.hpp index 9db4143..caa7cfd 100644 --- a/sphaira/include/ui/types.hpp +++ b/sphaira/include/ui/types.hpp @@ -359,7 +359,7 @@ struct Controller { m_kup = 0; } - void UpdateButtonHeld(HidNpadButton buttons) { + void UpdateButtonHeld(u64 buttons) { if (m_kdown & buttons) { m_step = 50; m_counter = 0; @@ -367,7 +367,7 @@ struct Controller { m_counter += m_step; if (m_counter >= m_MAX) { - m_kdown |= buttons; + m_kdown |= m_kheld & buttons; m_counter = 0; m_step = std::min(m_step + 50, m_MAX_STEP); } diff --git a/sphaira/source/app.cpp b/sphaira/source/app.cpp index 9631ce8..f0cbfbd 100644 --- a/sphaira/source/app.cpp +++ b/sphaira/source/app.cpp @@ -389,6 +389,10 @@ auto App::GetThemeIndex() -> u64 { return g_app->m_theme_index; } +auto App::GetDefaultImage(int* w, int* h) -> int { + return g_app->m_default_image; +} + auto App::GetExePath() -> fs::FsPath { return g_app->m_app_path; } @@ -593,24 +597,7 @@ void App::Poll() { m_controller.m_kdown = padGetButtonsDown(&m_pad); m_controller.m_kheld = padGetButtons(&m_pad); m_controller.m_kup = padGetButtonsUp(&m_pad); - - // dpad - m_controller.UpdateButtonHeld(HidNpadButton_Left); - m_controller.UpdateButtonHeld(HidNpadButton_Right); - m_controller.UpdateButtonHeld(HidNpadButton_Down); - m_controller.UpdateButtonHeld(HidNpadButton_Up); - - // ls - m_controller.UpdateButtonHeld(HidNpadButton_StickLLeft); - m_controller.UpdateButtonHeld(HidNpadButton_StickLRight); - m_controller.UpdateButtonHeld(HidNpadButton_StickLDown); - m_controller.UpdateButtonHeld(HidNpadButton_StickLUp); - - // rs - m_controller.UpdateButtonHeld(HidNpadButton_StickRLeft); - m_controller.UpdateButtonHeld(HidNpadButton_StickRRight); - m_controller.UpdateButtonHeld(HidNpadButton_StickRDown); - m_controller.UpdateButtonHeld(HidNpadButton_StickRUp); + m_controller.UpdateButtonHeld(static_cast(Button::ANY_DIRECTION)); HidTouchScreenState touch_state{}; hidGetTouchScreenStates(&touch_state, 1); @@ -1107,6 +1094,15 @@ App::App(const char* argv0) { log_write("sd_total_space: %zd\n", sd_total_space); } + // load default image + if (R_SUCCEEDED(romfsInit())) { + ON_SCOPE_EXIT(romfsExit()); + const auto image = ImageLoadFromFile("romfs:/default.png"); + if (!image.data.empty()) { + m_default_image = nvgCreateImageRGBA(vg, image.w, image.h, 0, image.data.data()); + } + } + App::Push(std::make_shared()); log_write("finished app constructor\n"); } @@ -1133,6 +1129,7 @@ App::~App() { // this has to be called before any cleanup to ensure the lifetime of // nvg is still active as some widgets may need to free images. m_widgets.clear(); + nvgDeleteImage(vg, m_default_image); appletUnhook(&m_appletHookCookie); diff --git a/sphaira/source/download.cpp b/sphaira/source/download.cpp index dcbf4fc..bf72481 100644 --- a/sphaira/source/download.cpp +++ b/sphaira/source/download.cpp @@ -93,48 +93,14 @@ struct Cache { } void get(const fs::FsPath& path, curl::Header& header) { - mutexLock(&m_mutex); - ON_SCOPE_EXIT(mutexUnlock(&m_mutex)); - - if (!fs::FsNativeSd().FileExists(path)) { - return; + const auto [etag, last_modified] = get_internal(path); + if (!etag.empty()) { + header.m_map.emplace("if-none-match", etag); } - const auto kkey = generate_key_from_path(path); - const auto it = m_cache.find(kkey); - if (it != m_cache.end()) { - return; + if (!last_modified.empty()) { + header.m_map.emplace("if-modified-since", last_modified); } - - auto hash_key = yyjson_mut_obj_getn(m_root, kkey.c_str(), kkey.length()); - if (!hash_key) { - return; - } - - auto etag_key = yyjson_mut_obj_get(hash_key, ETAG_STR); - auto last_modified_key = yyjson_mut_obj_get(hash_key, LAST_MODIFIED_STR); - - const auto etag_value = yyjson_mut_get_str(etag_key); - const auto etag_value_len = yyjson_mut_get_len(etag_key); - const auto last_modified_value = yyjson_mut_get_str(last_modified_key); - const auto last_modified_value_len = yyjson_mut_get_len(last_modified_key); - - if ((!etag_value || !etag_value_len) && (!last_modified_value || !last_modified_value_len)) { - return; - } - - std::string etag; - std::string last_modified; - if (etag_value && etag_value_len) { - etag.assign(etag_value, etag_value_len); - } - if (last_modified_value && last_modified_value_len) { - last_modified.assign(last_modified_value, last_modified_value_len); - } - - m_cache.insert_or_assign(it, kkey, Value{etag, last_modified}); - header.m_map.emplace("if-none-match", etag); - header.m_map.emplace("if-modified-since", last_modified); } void set(const fs::FsPath& path, const curl::Header& value) { @@ -157,6 +123,48 @@ struct Cache { } private: + auto get_internal(const fs::FsPath& path) -> Value { + if (!fs::FsNativeSd().FileExists(path)) { + return {}; + } + + const auto kkey = generate_key_from_path(path); + const auto it = m_cache.find(kkey); + if (it != m_cache.end()) { + return it->second; + } + + auto hash_key = yyjson_mut_obj_getn(m_root, kkey.c_str(), kkey.length()); + if (!hash_key) { + return {}; + } + + auto etag_key = yyjson_mut_obj_get(hash_key, ETAG_STR); + auto last_modified_key = yyjson_mut_obj_get(hash_key, LAST_MODIFIED_STR); + + const auto etag_value = yyjson_mut_get_str(etag_key); + const auto etag_value_len = yyjson_mut_get_len(etag_key); + const auto last_modified_value = yyjson_mut_get_str(last_modified_key); + const auto last_modified_value_len = yyjson_mut_get_len(last_modified_key); + + if ((!etag_value || !etag_value_len) && (!last_modified_value || !last_modified_value_len)) { + return {}; + } + + std::string etag; + std::string last_modified; + if (etag_value && etag_value_len) { + etag.assign(etag_value, etag_value_len); + } + if (last_modified_value && last_modified_value_len) { + last_modified.assign(last_modified_value, last_modified_value_len); + } + + const Value ret{etag, last_modified}; + m_cache.insert_or_assign(it, kkey, ret); + return ret; + } + void set_internal(const fs::FsPath& path, const Value& value) { const auto kkey = generate_key_from_path(path); @@ -536,15 +544,20 @@ auto DownloadInternal(CURL* curl, const Api& e) -> ApiResult { fsFileClose(&chunk.f); - if (res == CURLE_OK && http_code != 304) { - if (e.m_flags.m_flags & Flag_Cache) { - g_cache.set(e.m_path, header_out); - } + if (res == CURLE_OK) { + if (http_code == 304) { + log_write("cached download: %s\n", e.m_url.m_str.c_str()); + } else { + log_write("un-cached download: %s code: %u\n", e.m_url.m_str.c_str(), http_code); + if (e.m_flags.m_flags & Flag_Cache) { + g_cache.set(e.m_path, header_out); + } - fs.DeleteFile(e.m_path, true); - fs.CreateDirectoryRecursivelyWithPath(e.m_path, true); - if (R_FAILED(fs.RenameFile(tmp_buf, e.m_path, true))) { - success = false; + fs.DeleteFile(e.m_path, true); + fs.CreateDirectoryRecursivelyWithPath(e.m_path, true); + if (R_FAILED(fs.RenameFile(tmp_buf, e.m_path, true))) { + success = false; + } } } chunk.data.clear(); diff --git a/sphaira/source/ui/menus/appstore.cpp b/sphaira/source/ui/menus/appstore.cpp index 77311de..bb38d8e 100644 --- a/sphaira/source/ui/menus/appstore.cpp +++ b/sphaira/source/ui/menus/appstore.cpp @@ -290,26 +290,6 @@ void DrawIcon(NVGcontext* vg, const LazyImage& l, const LazyImage& d, Vec4 vec, DrawIcon(vg, l, d, vec.x, vec.y, vec.w, vec.h, rounded, scale); } -auto ScrollHelperDown(u64& index, u64& start, u64 step, u64 max, u64 size) -> bool { - if (size && index < (size - 1)) { - if (index < (size - step)) { - index = index + step; - App::PlaySoundEffect(SoundEffect_Scroll); - } else { - index = size - 1; - App::PlaySoundEffect(SoundEffect_Scroll); - } - if (index - start >= max) { - log_write("moved down\n"); - start += step; - } - - return true; - } - - return false; -} - auto AppDlToStr(u32 value) -> std::string { auto str = std::to_string(value); u32 inc = 3; @@ -826,6 +806,7 @@ void EntryMenu::UpdateOptions() { return InstallApp(pbox, m_entry); }, [this](bool success){ if (success) { + App::Notify("Downloaded "_i18n + m_entry.title); m_entry.status = EntryStatus::Installed; m_menu.SetDirty(); UpdateOptions(); @@ -838,6 +819,7 @@ void EntryMenu::UpdateOptions() { return UninstallApp(pbox, m_entry); }, [this](bool success){ if (success) { + App::Notify("Removed "_i18n + m_entry.title); m_entry.status = EntryStatus::Get; m_menu.SetDirty(); UpdateOptions(); @@ -930,41 +912,23 @@ Menu::Menu(const std::vector& nro_entries) : MenuBase{"AppStore"_i18n} } }}), std::make_pair(Button::DOWN, Action{[this](){ - if (ScrollHelperDown(m_index, m_start, 3, 9, m_entries_current.size())) { + if (ScrollHelperDown(m_index, m_start, 3, 3, 9, m_entries_current.size())) { SetIndex(m_index); } }}), std::make_pair(Button::UP, Action{[this](){ - if (m_entries_current.empty()) { - return; - } - - if (m_index >= 3) { - SetIndex(m_index - 3); - App::PlaySoundEffect(SoundEffect_Scroll); - if (m_index < m_start ) { - // log_write("moved up\n"); - m_start -= 3; - } - } - }}), - std::make_pair(Button::R2, Action{(u8)ActionType::HELD, [this](){ - if (ScrollHelperDown(m_index, m_start, 9, 9, m_entries_current.size())) { + if (ScrollHelperUp(m_index, m_start, 3, 3, 9, m_entries_current.size())) { SetIndex(m_index); } }}), - std::make_pair(Button::L2, Action{(u8)ActionType::HELD, [this](){ - if (m_entries.empty()) { - return; + std::make_pair(Button::R2, Action{[this](){ + if (ScrollHelperDown(m_index, m_start, 9, 3, 9, m_entries_current.size())) { + SetIndex(m_index); } - - if (m_index >= 9) { - SetIndex(m_index - 9); - App::PlaySoundEffect(SoundEffect_Scroll); - while (m_index < m_start) { - // log_write("moved up\n"); - m_start -= 3; - } + }}), + std::make_pair(Button::L2, Action{[this](){ + if (ScrollHelperUp(m_index, m_start, 9, 3, 9, m_entries_current.size())) { + SetIndex(m_index); } }}), std::make_pair(Button::A, Action{"Info"_i18n, [this](){ @@ -1027,12 +991,6 @@ Menu::Menu(const std::vector& nro_entries) : MenuBase{"AppStore"_i18n} curl::Flags{curl::Flag_Cache}, curl::OnComplete{[this](auto& result){ if (result.success) { - if (result.code == 304) { - log_write("appstore json not updated\n"); - } else { - log_write("appstore json updated\n"); - } - m_repo_download_state = ImageDownloadState::Done; if (HasFocus()) { ScanHomebrew(); @@ -1120,7 +1078,6 @@ void Menu::Draw(NVGcontext* vg, Theme* theme) { image.state = ImageDownloadState::Done; // data hasn't changed if (result.code == 304) { - log_write("downloaded appstore image, was cached\n"); image.cached = false; } } else { diff --git a/sphaira/source/ui/menus/filebrowser.cpp b/sphaira/source/ui/menus/filebrowser.cpp index 24cea17..6ec3e12 100644 --- a/sphaira/source/ui/menus/filebrowser.cpp +++ b/sphaira/source/ui/menus/filebrowser.cpp @@ -322,23 +322,23 @@ Menu::Menu(const std::vector& nro_entries) : MenuBase{"FileBrowser"_i1 } }}), std::make_pair(Button::DOWN, Action{[this](){ - if (m_index < (m_entries_current.size() - 1)) { - SetIndex(m_index + 1); - App::PlaySoundEffect(SoundEffect_Scroll); - if (m_index - m_index_offset >= 8) { - log_write("moved down\n"); - m_index_offset++; - } + if (ScrollHelperDown(m_index, m_index_offset, 1, 1, 8, m_entries_current.size())) { + SetIndex(m_index); } }}), std::make_pair(Button::UP, Action{[this](){ - if (m_index != 0) { - SetIndex(m_index - 1); - App::PlaySoundEffect(SoundEffect_Scroll); - if (m_index < m_index_offset ) { - log_write("moved up\n"); - m_index_offset--; - } + if (ScrollHelperUp(m_index, m_index_offset, 1, 1, 8, m_entries_current.size())) { + SetIndex(m_index); + } + }}), + std::make_pair(Button::DPAD_RIGHT, Action{[this](){ + if (ScrollHelperDown(m_index, m_index_offset, 8, 1, 8, m_entries_current.size())) { + SetIndex(m_index); + } + }}), + std::make_pair(Button::DPAD_LEFT, Action{[this](){ + if (ScrollHelperUp(m_index, m_index_offset, 8, 1, 8, m_entries_current.size())) { + SetIndex(m_index); } }}), std::make_pair(Button::A, Action{"Open"_i18n, [this](){ diff --git a/sphaira/source/ui/menus/ghdl.cpp b/sphaira/source/ui/menus/ghdl.cpp index 825f322..39ce115 100644 --- a/sphaira/source/ui/menus/ghdl.cpp +++ b/sphaira/source/ui/menus/ghdl.cpp @@ -233,28 +233,24 @@ Menu::Menu() : MenuBase{"GitHub"_i18n} { fs::FsNativeSd().CreateDirectoryRecursively(CACHE_PATH); this->SetActions( - std::make_pair(Button::R2, Action{[this](){ - }}), - std::make_pair(Button::DOWN, Action{[this](){ - if (m_index < (m_entries.size() - 1)) { - SetIndex(m_index + 1); - App::PlaySoundEffect(SoundEffect_Scroll); - if (m_index - m_index_offset >= 8) { - log_write("moved down\n"); - m_index_offset++; - } + if (ScrollHelperDown(m_index, m_index_offset, 1, 1, 8, m_entries.size())) { + SetIndex(m_index); } }}), - std::make_pair(Button::UP, Action{[this](){ - if (m_index != 0) { - SetIndex(m_index - 1); - App::PlaySoundEffect(SoundEffect_Scroll); - if (m_index < m_index_offset ) { - log_write("moved up\n"); - m_index_offset--; - } + if (ScrollHelperUp(m_index, m_index_offset, 1, 1, 8, m_entries.size())) { + SetIndex(m_index); + } + }}), + std::make_pair(Button::DPAD_RIGHT, Action{[this](){ + if (ScrollHelperDown(m_index, m_index_offset, 8, 1, 8, m_entries.size())) { + SetIndex(m_index); + } + }}), + std::make_pair(Button::DPAD_LEFT, Action{[this](){ + if (ScrollHelperUp(m_index, m_index_offset, 8, 1, 8, m_entries.size())) { + SetIndex(m_index); } }}), diff --git a/sphaira/source/ui/menus/homebrew.cpp b/sphaira/source/ui/menus/homebrew.cpp index e9bfbdb..1d555c4 100644 --- a/sphaira/source/ui/menus/homebrew.cpp +++ b/sphaira/source/ui/menus/homebrew.cpp @@ -43,27 +43,23 @@ Menu::Menu() : MenuBase{"Homebrew"_i18n} { } }}), std::make_pair(Button::DOWN, Action{[this](){ - if (m_index < (m_entries.size() - 1)) { - if (m_index < (m_entries.size() - 3)) { - SetIndex(m_index + 3); - } else { - SetIndex(m_entries.size() - 1); - } - App::PlaySoundEffect(SoundEffect_Scroll); - if (m_index - m_start >= 9) { - log_write("moved down\n"); - m_start += 3; - } + if (ScrollHelperDown(m_index, m_start, 3, 3, 9, m_entries.size())) { + SetIndex(m_index); } }}), std::make_pair(Button::UP, Action{[this](){ - if (m_index >= 3) { - SetIndex(m_index - 3); - App::PlaySoundEffect(SoundEffect_Scroll); - if (m_index < m_start ) { - // log_write("moved up\n"); - m_start -= 3; - } + if (ScrollHelperUp(m_index, m_start, 3, 3, 9, m_entries.size())) { + SetIndex(m_index); + } + }}), + std::make_pair(Button::R2, Action{[this](){ + if (ScrollHelperDown(m_index, m_start, 9, 3, 9, m_entries.size())) { + SetIndex(m_index); + } + }}), + std::make_pair(Button::L2, Action{[this](){ + if (ScrollHelperUp(m_index, m_start, 9, 3, 9, m_entries.size())) { + SetIndex(m_index); } }}), std::make_pair(Button::A, Action{"Launch"_i18n, [this](){ @@ -177,15 +173,26 @@ void Menu::Draw(NVGcontext* vg, Theme* theme) { gfx::drawRect(vg, SCREEN_WIDTH - 50+2, 102 + sb_h * sb_y, 10-4, sb_h + (sb_h * 2) - 4, theme->elements[ThemeEntryID_TEXT_SELECTED].colour); } + // max images per frame, in order to not hit io / gpu too hard. + const int image_load_max = 2; + int image_load_count = 0; + for (u64 i = 0, pos = SCROLL, y = 110, w = 370, h = 155; pos < nro_total && i < max_entry_display; y += h + 10) { for (u64 j = 0, x = 75; j < 3 && pos < nro_total && i < max_entry_display; j++, i++, pos++, x += w + 10) { auto& e = m_entries[pos]; // lazy load image - if (!e.image && e.icon.empty() && e.icon_size && e.icon_offset) { - e.icon = nro_get_icon(e.path, e.icon_size, e.icon_offset); - if (!e.icon.empty()) { - e.image = nvgCreateImageMem(vg, 0, e.icon.data(), e.icon.size()); + if (image_load_count < image_load_max) { + if (!e.image && e.icon_size && e.icon_offset) { + // NOTE: it seems that images can be any size. SuperTux uses a 1024x1024 + // ~300Kb image, which takes a few frames to completely load. + // really, switch-tools should handle this by resizing the image before + // adding it to the nro, as well as validate its a valid jpeg. + const auto icon = nro_get_icon(e.path, e.icon_size, e.icon_offset); + if (!icon.empty()) { + e.image = nvgCreateImageMem(vg, 0, icon.data(), icon.size()); + image_load_count++; + } } } @@ -198,7 +205,7 @@ void Menu::Draw(NVGcontext* vg, Theme* theme) { } const float image_size = 115; - gfx::drawImageRounded(vg, x + 20, y + 20, image_size, image_size, e.image); + gfx::drawImageRounded(vg, x + 20, y + 20, image_size, image_size, e.image ? e.image : App::GetDefaultImage()); nvgSave(vg); nvgScissor(vg, x, y, w - 30.f, h); // clip @@ -261,12 +268,12 @@ void Menu::SetIndex(std::size_t index) { // log_write("name: %s hbini.ts: %lu file.ts: %lu smaller: %s\n", e.GetName(), e.hbini.timestamp, e.timestamp.modified, e.hbini.timestamp < e.timestamp.modified ? "true" : "false"); SetTitleSubHeading(m_entries[m_index].path); - this->SetSubHeading(std::to_string(m_index + 1) + " / " + std::to_string(m_entries.size())); + this->SetSubHeading(std::to_string(m_index + 1) + " / " + std::to_string(m_entries.size()) + " " + std::to_string(m_start)); } void Menu::InstallHomebrew() { const auto& nro = m_entries[m_index]; - InstallHomebrew(nro.path, nro.nacp, nro.icon); + InstallHomebrew(nro.path, nro.nacp, nro_get_icon(nro.path, nro.size, nro.icon_offset)); } void Menu::ScanHomebrew() { diff --git a/sphaira/source/ui/menus/main_menu.cpp b/sphaira/source/ui/menus/main_menu.cpp index d8769f1..16e39f5 100644 --- a/sphaira/source/ui/menus/main_menu.cpp +++ b/sphaira/source/ui/menus/main_menu.cpp @@ -158,12 +158,6 @@ MainMenu::MainMenu() { return false; } - if (result.code == 304) { - log_write("data hasn't changed\n"); - } else { - log_write("etag changed\n"); - } - auto json = yyjson_read_file(CACHE_PATH, YYJSON_READ_NOFLAG, nullptr, nullptr); R_UNLESS(json, false); ON_SCOPE_EXIT(yyjson_doc_free(json)); diff --git a/sphaira/source/ui/menus/menu_base.cpp b/sphaira/source/ui/menus/menu_base.cpp index b9a1009..a9eb41e 100644 --- a/sphaira/source/ui/menus/menu_base.cpp +++ b/sphaira/source/ui/menus/menu_base.cpp @@ -103,4 +103,53 @@ void MenuBase::UpdateVars() { m_poll_timestamp.Update(); } +auto MenuBase::ScrollHelperDown(u64& index, u64& start, u64 step, s64 row, s64 page, u64 size) -> bool { + const auto old_index = index; + + if (index < (size - step)) { + index += step; + } else { + index = size - 1; + } + + if (index != old_index) { + App::PlaySoundEffect(SoundEffect_Scroll); + s64 delta = index - old_index; + + if (index - start >= page) { + do { + start += row; + delta -= row; + } while (delta > 0 && start + page < size); + } + + return true; + } + + return false; +} + +auto MenuBase::ScrollHelperUp(u64& index, u64& start, s64 step, s64 row, s64 page, s64 size) -> bool { + const auto old_index = index; + + if (index >= step) { + index -= step; + } else { + index = 0; + } + + if (index != old_index) { + App::PlaySoundEffect(SoundEffect_Scroll); + // if () + while (index < start) { + // log_write("moved up\n"); + start -= row; + } + + return true; + } + + return false; +} + } // namespace sphaira::ui::menu diff --git a/sphaira/source/ui/menus/themezer.cpp b/sphaira/source/ui/menus/themezer.cpp index 1003d3d..4647274 100644 --- a/sphaira/source/ui/menus/themezer.cpp +++ b/sphaira/source/ui/menus/themezer.cpp @@ -179,26 +179,6 @@ auto loadThemeImage(ThemeEntry& e) -> bool { } } -auto ScrollHelperDown(u64& index, u64& start, u64 step, u64 max, u64 size) -> bool { - if (size && index < (size - 1)) { - if (index < (size - step)) { - index = index + step; - App::PlaySoundEffect(SoundEffect_Scroll); - } else { - index = size - 1; - App::PlaySoundEffect(SoundEffect_Scroll); - } - if (index - start >= max) { - log_write("moved down\n"); - start += step; - } - - return true; - } - - return false; -} - void from_json(yyjson_val* json, Creator& e) { JSON_OBJ_ITR( JSON_SET_STR(id); @@ -449,7 +429,25 @@ Menu::Menu() : MenuBase{"Themezer"_i18n} { }}), std::make_pair(Button::DOWN, Action{[this](){ const auto& page = m_pages[m_page_index]; - if (ScrollHelperDown(m_index, m_start, 3, 6, page.m_packList.size())) { + if (ScrollHelperDown(m_index, m_start, 3, 3, 6, page.m_packList.size())) { + SetIndex(m_index); + } + }}), + std::make_pair(Button::UP, Action{[this](){ + const auto& page = m_pages[m_page_index]; + if (ScrollHelperUp(m_index, m_start, 3, 3, 6, page.m_packList.size())) { + SetIndex(m_index); + } + }}), + std::make_pair(Button::R2, Action{[this](){ + const auto& page = m_pages[m_page_index]; + if (ScrollHelperDown(m_index, m_start, 6, 3, 6, page.m_packList.size())) { + SetIndex(m_index); + } + }}), + std::make_pair(Button::L2, Action{[this](){ + const auto& page = m_pages[m_page_index]; + if (ScrollHelperUp(m_index, m_start, 6, 3, 6, page.m_packList.size())) { SetIndex(m_index); } }}), @@ -465,12 +463,10 @@ Menu::Menu() : MenuBase{"Themezer"_i18n} { App::Push(std::make_shared("Installing "_i18n + entry.details.name, [this, &entry](auto pbox){ return InstallTheme(pbox, entry); - }, [this](bool success){ - // if (success) { - // m_entry.status = EntryStatus::Installed; - // m_menu.SetDirty(); - // UpdateOptions(); - // } + }, [this, &entry](bool success){ + if (success) { + App::Notify("Downloaded "_i18n + entry.details.name); + } }, 2)); } } @@ -530,16 +526,6 @@ Menu::Menu() : MenuBase{"Themezer"_i18n} { } })); }}), - std::make_pair(Button::UP, Action{[this](){ - if (m_index >= 3) { - SetIndex(m_index - 3); - App::PlaySoundEffect(SoundEffect_Scroll); - if (m_index < m_start ) { - // log_write("moved up\n"); - m_start -= 3; - } - } - }}), std::make_pair(Button::R, Action{"Next Page"_i18n, [this](){ m_page_index++; if (m_page_index >= m_page_index_max) { @@ -662,10 +648,7 @@ void Menu::Draw(NVGcontext* vg, Theme* theme) { image.state = ImageDownloadState::Done; // data hasn't changed if (result.code == 304) { - log_write("downloaded themezer image, was cached\n"); image.cached = false; - } else { - log_write("downloaded new themezer image\n"); } } else { image.state = ImageDownloadState::Failed; @@ -690,9 +673,7 @@ void Menu::Draw(NVGcontext* vg, Theme* theme) { } } - if (image.image) { - gfx::drawImageRounded(vg, x + xoff, y, 320, 180, image.image); - } + gfx::drawImageRounded(vg, x + xoff, y, 320, 180, image.image ? image.image : App::GetDefaultImage()); } gfx::drawTextArgs(vg, x + xoff, y + 180 + 20, 18, NVG_ALIGN_LEFT, theme->elements[text_id].colour, "%s", e.details.name.c_str());