appstore add option to show installed files for app, add option to launch app website. slightly round scrollbar.

This commit is contained in:
ITotalJustice
2025-06-02 17:51:48 +01:00
parent f37fc13b7c
commit 298be4a344
6 changed files with 79 additions and 22 deletions

View File

@@ -108,8 +108,11 @@ private:
std::shared_ptr<ScrollableText> m_details{};
std::shared_ptr<ScrollableText> m_changelog{};
std::shared_ptr<ScrollableText> m_detail_changelog{};
std::unique_ptr<ScrollableText> m_manifest_list{};
bool m_show_changlog{};
bool m_show_file_list{};
ImageDownloadState m_file_list_state{};
};
enum Filter {

View File

@@ -332,7 +332,7 @@ struct ThreadQueue {
}
auto Add(const Api& api, bool is_upload = false) -> bool {
if (api.GetUrl().empty() || api.GetPath().empty() || !api.GetOnComplete()) {
if (api.GetUrl().empty() || !api.GetOnComplete()) {
return false;
}

View File

@@ -16,6 +16,7 @@
#include "hasher.hpp"
#include "threaded_file_transfer.hpp"
#include "nro.hpp"
#include "web.hpp"
#include <minIni.h>
#include <string>
@@ -144,6 +145,12 @@ auto BuildBannerUrl(const Entry& e) -> std::string {
return out;
}
auto BuildManifestUrl(const Entry& e) -> std::string {
char out[0x100];
std::snprintf(out, sizeof(out), "%s/packages/%s/manifest.install", URL_BASE, e.name.c_str());
return out;
}
auto BuildZipUrl(const Entry& e) -> std::string {
char out[0x100];
std::snprintf(out, sizeof(out), "%s/zips/%s.zip", URL_BASE, e.name.c_str());
@@ -634,12 +641,15 @@ EntryMenu::EntryMenu(Entry& entry, const LazyImage& default_icon, Menu& menu)
}
}}),
std::make_pair(Button::X, Action{"Options"_i18n, [this](){
auto sidebar = std::make_shared<Sidebar>("Options"_i18n, Sidebar::Side::RIGHT);
sidebar->Add(std::make_shared<SidebarEntryCallback>("More by Author"_i18n, [this](){
auto options = std::make_shared<Sidebar>("Options"_i18n, Sidebar::Side::RIGHT);
ON_SCOPE_EXIT(App::Push(options));
options->Add(std::make_shared<SidebarEntryCallback>("More by Author"_i18n, [this](){
m_menu.SetAuthor();
SetPop();
}, true));
sidebar->Add(std::make_shared<SidebarEntryCallback>("Leave Feedback"_i18n, [this](){
options->Add(std::make_shared<SidebarEntryCallback>("Leave Feedback"_i18n, [this](){
std::string out;
if (R_SUCCEEDED(swkbd::ShowText(out)) && !out.empty()) {
const auto post = "name=" "switch_user" "&package=" + m_entry.name + "&message=" + out;
@@ -660,10 +670,44 @@ EntryMenu::EntryMenu(Entry& entry, const LazyImage& default_icon, Menu& menu)
});
}
}, true));
App::Push(sidebar);
if (App::IsApplication() && !m_entry.url.empty()) {
options->Add(std::make_shared<SidebarEntryCallback>("Visit Website"_i18n, [this](){
WebShow(m_entry.url);
}));
}
}}),
std::make_pair(Button::B, Action{"Back"_i18n, [this](){
SetPop();
}}),
std::make_pair(Button::L2, Action{"Files"_i18n, [this](){
m_show_file_list ^= 1;
if (m_show_file_list && !m_manifest_list && m_file_list_state == ImageDownloadState::None) {
m_file_list_state = ImageDownloadState::Progress;
const auto path = BuildManifestCachePath(m_entry);
std::vector<u8> data;
if (R_SUCCEEDED(fs::read_entire_file(path, data))) {
m_file_list_state = ImageDownloadState::Done;
data.push_back('\0');
m_manifest_list = std::make_unique<ScrollableText>((const char*)data.data(), 0, 374, 250, 768, 18);
} else {
curl::Api().ToMemoryAsync(
curl::Url{BuildManifestUrl(m_entry)},
curl::StopToken{this->GetToken()},
curl::OnComplete{[this](auto& result){
if (result.success) {
m_file_list_state = ImageDownloadState::Done;
result.data.push_back('\0');
m_manifest_list = std::make_unique<ScrollableText>((const char*)result.data.data(), 0, 374, 250, 768, 18);
} else {
m_file_list_state = ImageDownloadState::Failed;
}
}}
);
}
}
}})
);
@@ -712,7 +756,13 @@ EntryMenu::~EntryMenu() {
void EntryMenu::Update(Controller* controller, TouchInfo* touch) {
MenuBase::Update(controller, touch);
m_detail_changelog->Update(controller, touch);
if (m_show_file_list) {
if (m_manifest_list) {
m_manifest_list->Update(controller, touch);
}
} else {
m_detail_changelog->Update(controller, touch);
}
}
void EntryMenu::Draw(NVGcontext* vg, Theme* theme) {
@@ -767,12 +817,24 @@ void EntryMenu::Draw(NVGcontext* vg, Theme* theme) {
y -= block.h + 18;
}
m_detail_changelog->Draw(vg, theme);
if (m_show_file_list) {
if (m_manifest_list) {
m_manifest_list->Draw(vg, theme);
} else if (m_file_list_state == ImageDownloadState::Progress) {
gfx::drawText(vg, 110, 374, 18, theme->GetColour(ThemeEntryID_TEXT), "Loading..."_i18n.c_str());
} else if (m_file_list_state == ImageDownloadState::Failed) {
gfx::drawText(vg, 110, 374, 18, theme->GetColour(ThemeEntryID_TEXT), "Failed to download manifest"_i18n.c_str());
}
} else {
m_detail_changelog->Draw(vg, theme);
}
}
void EntryMenu::ShowChangelogAction() {
std::function<void()> func = std::bind(&EntryMenu::ShowChangelogAction, this);
m_show_changlog ^= 1;
m_show_file_list = false;
if (m_show_changlog) {
SetAction(Button::L, Action{"Details"_i18n, func});

View File

@@ -107,7 +107,7 @@ void MenuBase::Draw(NVGcontext* vg, Theme* theme) {
gfx::drawTextArgs(vg, 80, start_y, 28.f, NVG_ALIGN_LEFT | NVG_ALIGN_BOTTOM, theme->GetColour(ThemeEntryID_TEXT), m_title.c_str());
m_scroll_title_sub_heading.Draw(vg, true, title_sub_x, start_y, text_w - title_sub_x, 16, NVG_ALIGN_LEFT | NVG_ALIGN_BOTTOM, theme->GetColour(ThemeEntryID_TEXT_INFO), m_title_sub_heading.c_str());
m_scroll_sub_heading.Draw(vg, true, 80, 685, text_w - 80, 18, NVG_ALIGN_LEFT, theme->GetColour(ThemeEntryID_TEXT), m_sub_heading.c_str());
m_scroll_sub_heading.Draw(vg, true, 80, 685, text_w - 160, 18, NVG_ALIGN_LEFT, theme->GetColour(ThemeEntryID_TEXT), m_sub_heading.c_str());
}
void MenuBase::SetTitle(std::string title) {

View File

@@ -296,8 +296,8 @@ void drawScrollbar(NVGcontext* vg, const Theme* theme, float x, float y, float h
if (entry_total > max_entry_display) {
const float sb_h = 1.f / (float)entry_total * h;
const float sb_y = SCROLL;
gfx::drawRect(vg, x, y, scc2, h, theme->GetColour(ThemeEntryID_SCROLLBAR_BACKGROUND), false);
gfx::drawRect(vg, x + scw, y + scw + sb_h * sb_y, scc2 - scw * 2, sb_h * float(max_entry_display) - scw * 2, theme->GetColour(ThemeEntryID_SCROLLBAR), false);
gfx::drawRect(vg, x, y, scc2, h, theme->GetColour(ThemeEntryID_SCROLLBAR_BACKGROUND), 5);
gfx::drawRect(vg, x + scw, y + scw + sb_h * sb_y, scc2 - scw * 2, sb_h * float(max_entry_display) - scw * 2, theme->GetColour(ThemeEntryID_SCROLLBAR), 5);
}
}
@@ -318,8 +318,8 @@ void drawScrollbar2(NVGcontext* vg, const Theme* theme, float x, float y, float
if (count > page) {
const float sb_h = 1.f / (float)count * h;
const float sb_y = index_off;
gfx::drawRect(vg, x, y, scc2, h, theme->GetColour(ThemeEntryID_SCROLLBAR_BACKGROUND), false);
gfx::drawRect(vg, x + scw, y + scw + sb_h * sb_y, scc2 - scw * 2, sb_h * float(page) - scw * 2, theme->GetColour(ThemeEntryID_SCROLLBAR), false);
gfx::drawRect(vg, x, y, scc2, h, theme->GetColour(ThemeEntryID_SCROLLBAR_BACKGROUND), 5);
gfx::drawRect(vg, x + scw, y + scw + sb_h * sb_y, scc2 - scw * 2, sb_h * float(page) - scw * 2, theme->GetColour(ThemeEntryID_SCROLLBAR), 5);
}
}

View File

@@ -87,16 +87,8 @@ void ScrollableText::Draw(NVGcontext* vg, Theme* theme) {
// const Vec4 banner_vec(70, line_vec.y + 20, 848.f, 208.f);
const Vec4 banner_vec(70, line_vec.y + 20, m_end_w + (110.0F), 208.f);
// only draw scrollbar if needed
if ((m_bounds[3] - m_bounds[1]) > m_clip_y) {
const auto scrollbar_size = m_clip_y;
const auto max_index = (m_bounds[3] - m_bounds[1]) / m_step;
const auto sb_h = 1.f / max_index * scrollbar_size;
const auto in_clip = m_clip_y / m_step - 1;
const auto sb_y = m_index;
gfx::drawRect(vg, banner_vec.w, m_y_off_base, 10, scrollbar_size, theme->GetColour(ThemeEntryID_SCROLLBAR_BACKGROUND));
gfx::drawRect(vg, banner_vec.w+2, m_y_off_base + sb_h * sb_y, 10-4, sb_h + (sb_h * in_clip) - 4, theme->GetColour(ThemeEntryID_SCROLLBAR));
}
const auto max_index = (m_bounds[3] - m_bounds[1]) / m_step;
gfx::drawScrollbar2(vg, theme, banner_vec.w + 25, m_y_off_base, m_clip_y, m_index, max_index, 1, m_clip_y / m_step - 1);
nvgSave(vg);
nvgIntersectScissor(vg, 0, m_y_off_base - m_font_size, 1280, m_clip_y + m_font_size); // clip