diff --git a/Common/StringUtils.cpp b/Common/StringUtils.cpp index 7aa9c55945..63ac6413e0 100644 --- a/Common/StringUtils.cpp +++ b/Common/StringUtils.cpp @@ -171,6 +171,14 @@ std::string IndentString(const std::string &str, const std::string &sep, bool sk return output.str(); } +std::string_view StripPrefix(std::string_view prefix, std::string_view s) { + if (startsWith(s, prefix)) { + return s.substr(prefix.size(), s.size() - prefix.size()); + } else { + return s; + } +} + void SkipSpace(const char **ptr) { while (**ptr && isspace(**ptr)) { (*ptr)++; diff --git a/Common/StringUtils.h b/Common/StringUtils.h index fb80fc3558..6197877cd0 100644 --- a/Common/StringUtils.h +++ b/Common/StringUtils.h @@ -81,6 +81,8 @@ std::string StripQuotes(const std::string &s); std::string_view StripSpaces(std::string_view s); std::string_view StripQuotes(std::string_view s); +std::string_view StripPrefix(std::string_view prefix, std::string_view s); + // NOTE: str must live at least as long as all uses of output. void SplitString(std::string_view str, const char delim, std::vector &output); // Try to avoid this when possible, in favor of the string_view version. diff --git a/UI/Store.cpp b/UI/Store.cpp index 39d75fcea3..c81c2b6af4 100644 --- a/UI/Store.cpp +++ b/UI/Store.cpp @@ -233,8 +233,6 @@ void HttpImageFileView::Draw(UIContext &dc) { } } - - // This is the entry in a list. Does not have install buttons and so on. class ProductItemView : public UI::StickyChoice { public: @@ -333,6 +331,37 @@ void ProductView::CreateViews() { float size = entry_.size / (1024.f * 1024.f); Add(new TextView(StringFromFormat("%s: %.2f %s", st->T_cstr("Size"), size, st->T_cstr("MB")))); + + if (!entry_.license.empty()) { + LinearLayout *horiz = Add(new LinearLayout(ORIENT_HORIZONTAL)); + horiz->Add(new TextView(StringFromFormat("%s: %s", st->T_cstr("License"), entry_.license.c_str()))); + horiz->Add(new Button(st->T("Details")))->OnClick.Add([this](UI::EventParams) { + std::string url = StringFromFormat("https://www.ppsspp.org/docs/reference/homebrew-store-distribution/#%s", entry_.file.c_str()); + System_LaunchUrl(LaunchUrlType::BROWSER_URL, url.c_str()); + return UI::EVENT_DONE; + }); + } + if (!entry_.websiteURL.empty()) { + // Display in a few different ways depending on the URL + size_t slashes = std::count(entry_.websiteURL.begin(), entry_.websiteURL.end(), '/'); + std::string buttonText; + if (slashes == 2) { + // Just strip https and show the URL. + std::string_view name = StripPrefix("https://", entry_.websiteURL); + name = StripPrefix("http://", name); + if (name.size() < entry_.websiteURL.size()) { + buttonText = name; + } + } + if (buttonText.empty()) { + // Fall back + buttonText = st->T("Website"); + } + Add(new Button(buttonText))->OnClick.Add([this](UI::EventParams) { + System_LaunchUrl(LaunchUrlType::BROWSER_URL, entry_.websiteURL.c_str()); + return UI::EVENT_DONE; + }); + } } void ProductView::Update() { @@ -460,11 +489,13 @@ void StoreScreen::ParseListing(const std::string &json) { e.type = ENTRY_PBPZIP; e.name = GetTranslatedString(game, "name"); e.description = GetTranslatedString(game, "description", ""); - e.author = game.getStringOr("author", "?"); + e.author = ReplaceAll(game.getStringOr("author", "?"), "&&", "&"); // Can't remove && in the JSON source data due to old app versions e.size = game.getInt("size"); e.downloadURL = game.getStringOr("download-url", ""); e.iconURL = game.getStringOr("icon-url", ""); e.contentRating = game.getInt("content-rating", 0); + e.websiteURL = game.getStringOr("website-url", ""); + e.license = game.getStringOr("license", ""); #if PPSSPP_PLATFORM(IOS_APP_STORE) if (e.contentRating >= 100) { continue; diff --git a/UI/Store.h b/UI/Store.h index 6b742c12e4..1e51b6bd5f 100644 --- a/UI/Store.h +++ b/UI/Store.h @@ -50,9 +50,11 @@ struct StoreEntry { std::string description; std::string author; std::string iconURL; - std::string file; // This is the folder name of the installed one too, and hence a "unique-ish" identifier. + std::string file; // This is the folder name of the installed one too, and hence a "unique-ish" identifier. Also used as a-link on the license website, if !license.empty(). std::string category; std::string downloadURL; // Only set for games that are not hosted on store.ppsspp.org + std::string websiteURL; + std::string license; bool hidden; int contentRating; // 100 means to hide it on iOS. No other values defined yet. u64 size;