mirror of
https://github.com/hrydgard/ppsspp.git
synced 2026-07-11 01:25:07 +02:00
Merge pull request #21326 from hrydgard/adhoc-view
Adhoc server list: Show metadata
This commit is contained in:
@@ -49,6 +49,7 @@ enum class LaunchUrlType {
|
||||
EMAIL_ADDRESS,
|
||||
LOCAL_FILE,
|
||||
LOCAL_FOLDER, // Shows the folder. Not supported on all systems of course.
|
||||
AUTO,
|
||||
};
|
||||
|
||||
void System_Vibrate(int length_ms);
|
||||
|
||||
@@ -24,6 +24,9 @@ PopupScreen::PopupScreen(std::string_view title, std::string_view button1, std::
|
||||
if (button1 == di->T("Delete") || button1 == di->T("Move to trash")) {
|
||||
button1Image_ = ImageID("I_TRASHCAN");
|
||||
}
|
||||
if (button1 == di->T("Back")) {
|
||||
button1Image_ = ImageID("I_NAVIGATE_BACK");
|
||||
}
|
||||
|
||||
alpha_ = 0.0f; // inherited
|
||||
ignoreInsets_ = true; // for layout purposes.
|
||||
|
||||
@@ -1085,6 +1085,10 @@ void TextView::GetContentDimensionsBySpec(const UIContext &dc, MeasureSpec horiz
|
||||
}
|
||||
}
|
||||
|
||||
TextView *TextView::SetWordWrap() {
|
||||
textAlign_ |= FLAG_WRAP_TEXT; return this;
|
||||
}
|
||||
|
||||
void TextView::Draw(UIContext &dc) {
|
||||
uint32_t textColor = hasTextColor_ ? textColor_ : (popupStyle_ ? dc.GetTheme().popupStyle.fgColor : dc.GetTheme().infoStyle.fgColor);
|
||||
if (!(textColor & 0xFF000000))
|
||||
|
||||
+2
-1
@@ -1052,7 +1052,7 @@ public:
|
||||
std::string DescribeText() const override { return GetText(); }
|
||||
void SetSmall(bool small) { textSize_ = TextSize::Small; }
|
||||
void SetBig(bool big) { textSize_ = TextSize::Big; }
|
||||
void SetTextSize(TextSize size) { textSize_ = size; }
|
||||
TextView *SetTextSize(TextSize size) { textSize_ = size; return this; }
|
||||
void SetTextColor(uint32_t color) { textColor_ = color; hasTextColor_ = true; }
|
||||
void SetShadow(bool shadow) { shadow_ = shadow; }
|
||||
void SetFocusable(bool focusable) { focusable_ = focusable; }
|
||||
@@ -1060,6 +1060,7 @@ public:
|
||||
void SetBullet(bool bullet) { bullet_ = bullet; }
|
||||
void SetPadding(Margins padding) { pad_ = padding; }
|
||||
void SetAlign(int align) { textAlign_ = align; }
|
||||
TextView *SetWordWrap();
|
||||
|
||||
bool CanBeFocused() const override { return focusable_; }
|
||||
|
||||
|
||||
@@ -143,6 +143,7 @@ bool ParseServerListEntriesJSON(std::string_view json) {
|
||||
entry.discord = server.getStringOr("discord", "");
|
||||
entry.host = server.getStringOr("host", "");
|
||||
entry.web = server.getStringOr("web", "");
|
||||
entry.ip = server.getStringOr("ip", "");
|
||||
entry.location = server.getStringOr("location", "");
|
||||
entry.description = server.getStringOr("description", "");
|
||||
entry.mode = equals(server.getStringOr("data_mode", ""), "AemuPostoffice") ? AdhocDataMode::AemuPostoffice : AdhocDataMode::P2P;
|
||||
|
||||
@@ -107,6 +107,7 @@ struct AdhocServerListEntry {
|
||||
std::string name;
|
||||
std::string host;
|
||||
std::string web;
|
||||
std::string ip; // could be used as a fallback if DNS resolution fails. Currently unused.
|
||||
std::string discord;
|
||||
std::string location;
|
||||
std::string description;
|
||||
|
||||
@@ -42,7 +42,7 @@ What's new in 1.20
|
||||
- Soundtrack is working again in Tony Hawk's Project 8 ([#20775])
|
||||
- Fix crash in StormBasic homebrew apps ([#20715])
|
||||
- Built-in songs in Beats work again ([#20662])
|
||||
- Fix adhoc in Syphon Filter games ([#20642])
|
||||
- Fix adhoc in Syphon Filter games ([#20642])
|
||||
- Fix strange cutscene speedups in Power Stone 2 (Power Stone Collection) ([#2124])
|
||||
- Work around game bug to help more custom songs play again in GTA LCS ([#20692])
|
||||
|
||||
|
||||
+154
-7
@@ -5,6 +5,153 @@
|
||||
#include "Common/StringUtils.h"
|
||||
#include "Core/HLE/sceNetAdhoc.h"
|
||||
|
||||
static UI::View *CreateLinkButton(std::string url) {
|
||||
using namespace UI;
|
||||
|
||||
// steal strings from all over the place
|
||||
auto cr = GetI18NCategory(I18NCat::PSPCREDITS);
|
||||
auto st = GetI18NCategory(I18NCat::STORE);
|
||||
|
||||
ImageID icon = ImageID("I_LINK_OUT_QUESTION");
|
||||
std::string title;
|
||||
|
||||
if (startsWith(url, "https://discord")) {
|
||||
icon = ImageID("I_LOGO_DISCORD");
|
||||
title = cr->T("Discord");
|
||||
} else {
|
||||
icon = ImageID("I_WEB_BROWSER");
|
||||
title = st->T("Website");
|
||||
}
|
||||
|
||||
Choice *choice = new Choice(title, icon, new LinearLayoutParams(WRAP_CONTENT, WRAP_CONTENT, Margins(12, 0)));
|
||||
choice->OnClick.Add([url](UI::EventParams &) {
|
||||
System_LaunchUrl(LaunchUrlType::BROWSER_URL, url);
|
||||
});
|
||||
return choice;
|
||||
}
|
||||
|
||||
// Later, this might also show games-in-progress.
|
||||
// For now, it's just a simple metadata viewer.
|
||||
class AdhocServerInfoScreen : public UI::PopupScreen {
|
||||
public:
|
||||
AdhocServerInfoScreen(const AdhocServerListEntry &entry)
|
||||
: PopupScreen(entry.name, T(I18NCat::DIALOG, "Back")), entry_(entry) {
|
||||
} // PopupScreen will translate Back on its own
|
||||
|
||||
const char *tag() const override { return "AdhocServerInfo"; }
|
||||
|
||||
protected:
|
||||
bool FillVertical() const override { return false; }
|
||||
UI::Size PopupWidth() const override { return 500; }
|
||||
bool ShowButtons() const override { return true; }
|
||||
|
||||
void CreatePopupContents(UI::ViewGroup *parent) override {
|
||||
using namespace UI;
|
||||
auto pa = GetI18NCategory(I18NCat::PAUSE);
|
||||
auto di = GetI18NCategory(I18NCat::DIALOG);
|
||||
auto ni = GetI18NCategory(I18NCat::NETWORKING);
|
||||
|
||||
ScrollView *scroll = new ScrollView(ORIENT_VERTICAL, new LinearLayoutParams(FILL_PARENT, WRAP_CONTENT, 1.0f));
|
||||
LinearLayout *content = new LinearLayout(ORIENT_VERTICAL);
|
||||
Margins contentMargins(10, 0);
|
||||
|
||||
content->Add(new InfoItem(entry_.host, ""));
|
||||
if (!entry_.ip.empty()) {
|
||||
content->Add(new InfoItem(entry_.ip, ""));
|
||||
}
|
||||
content->Add(new InfoItem(entry_.location, ""));
|
||||
content->Add(new InfoItem(ni->T("Relay server mode"), entry_.mode == AdhocDataMode::AemuPostoffice ? di->T("Yes") : di->T("No")));
|
||||
TextView *desc = content->Add(new TextView(entry_.description, new LinearLayoutParams(FILL_PARENT, WRAP_CONTENT, Margins(10))));
|
||||
desc->SetTextSize(TextSize::Small);
|
||||
desc->SetWordWrap();
|
||||
if (!entry_.web.empty()) {
|
||||
content->Add(CreateLinkButton(entry_.web));
|
||||
}
|
||||
if (!entry_.discord.empty()) {
|
||||
content->Add(CreateLinkButton(entry_.discord));
|
||||
}
|
||||
scroll->Add(content);
|
||||
parent->Add(scroll);
|
||||
}
|
||||
private:
|
||||
AdhocServerListEntry entry_;
|
||||
};
|
||||
|
||||
class AdhocServerRow : public UI::LinearLayout {
|
||||
public:
|
||||
AdhocServerRow(std::string *value, const AdhocServerListEntry &entry, ScreenManager *screenManager, UI::LayoutParams *layoutParams = nullptr);
|
||||
|
||||
void GetContentDimensions(const UIContext &dc, float &w, float &h) const override {
|
||||
w = 500; h = 90;
|
||||
}
|
||||
|
||||
void Draw(UIContext &dc) override {
|
||||
dc.FillRect(dc.GetTheme().itemStyle.background, bounds_);
|
||||
if (*value_ == entry_.host) {
|
||||
// TODO: Make this highlight themable
|
||||
dc.FillRect(UI::Drawable(0x30FFFFFF), GetBounds());
|
||||
}
|
||||
LinearLayout::Draw(dc);
|
||||
}
|
||||
|
||||
bool Touch(const TouchInput &input) override {
|
||||
using namespace UI;
|
||||
if (UI::LinearLayout::Touch(input)) {
|
||||
return true;
|
||||
}
|
||||
if (input.flags & TouchInputFlags::DOWN) {
|
||||
if (bounds_.Contains(input.x, input.y)) {
|
||||
dragging_ = true;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
if (dragging_ && (input.flags & TouchInputFlags::UP)) {
|
||||
dragging_ = false;
|
||||
if (!(input.flags & TouchInputFlags::CANCEL) && bounds_.Contains(input.x, input.y)) {
|
||||
EventParams e;
|
||||
e.v = this;
|
||||
OnSelected.Trigger(e);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
UI::Event OnSelected;
|
||||
|
||||
private:
|
||||
bool dragging_ = false;
|
||||
std::string *value_;
|
||||
AdhocServerListEntry entry_;
|
||||
};
|
||||
|
||||
AdhocServerRow::AdhocServerRow(std::string *value, const AdhocServerListEntry &entry, ScreenManager *screenManager, UI::LayoutParams *layoutParams)
|
||||
: UI::LinearLayout(ORIENT_HORIZONTAL, new UI::LinearLayoutParams(UI::FILL_PARENT, UI::WRAP_CONTENT, UI::Margins(5.0f, 0.0f))), value_(value), entry_(entry) {
|
||||
using namespace UI;
|
||||
|
||||
int number = 0;
|
||||
|
||||
LinearLayout *lines = Add(new LinearLayout(ORIENT_VERTICAL, new LinearLayoutParams(Margins(5, 5))));
|
||||
lines->SetSpacing(0.0f);
|
||||
lines->Add(new TextView(entry.name));
|
||||
lines->Add(new TextView(entry.host))->SetTextSize(TextSize::Small)->SetWordWrap();
|
||||
|
||||
Add(new Spacer(0.0f, new LinearLayoutParams(1.0f, Margins(0.0f, 5.0f))));
|
||||
|
||||
if (entry.mode == AdhocDataMode::AemuPostoffice) {
|
||||
TextView *relay = Add(new TextView("Relay", new LinearLayoutParams(WRAP_CONTENT, WRAP_CONTENT, Gravity::G_VCENTER, Margins(10.0))));
|
||||
}
|
||||
|
||||
if (!entry.description.empty()) {
|
||||
Choice *infoButton = Add(new Choice(ImageID("I_INFO"), new LinearLayoutParams(WRAP_CONTENT, WRAP_CONTENT, Gravity::G_VCENTER, Margins(0, 0, 10, 0))));
|
||||
AdhocServerListEntry copy = entry;
|
||||
infoButton->OnClick.Add([this, copy, screenManager](UI::EventParams &e) {
|
||||
e.v = this;
|
||||
screenManager->push(new AdhocServerInfoScreen(copy));
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
AdhocServerScreen::AdhocServerScreen(std::string *value, std::string_view title)
|
||||
: UI::PopupScreen(title, T(I18NCat::DIALOG, "OK"), T(I18NCat::DIALOG, "Cancel")), value_(value) {
|
||||
resolver_ = std::thread([](AdhocServerScreen *thiz) {
|
||||
@@ -37,7 +184,7 @@ void AdhocServerScreen::CreatePopupContents(UI::ViewGroup *parent) {
|
||||
|
||||
auto listItems = AdhocGetServerList();
|
||||
|
||||
PopupTextInputChoice *textInputChoice = parent->Add(new PopupTextInputChoice(GetRequesterToken(), &editValue_, n->T("Hostname"), "", 256, screenManager()));
|
||||
PopupTextInputChoice *textInputChoice = parent->Add(new PopupTextInputChoice(GetRequesterToken(), &editValue_, n->T("Hostname"), "", 450, screenManager()));
|
||||
parent->Add(new Spacer(5.0f));
|
||||
|
||||
// editValue_ has the currently selected server. On closing the dialog, we copy that to settings.
|
||||
@@ -79,7 +226,7 @@ void AdhocServerScreen::CreatePopupContents(UI::ViewGroup *parent) {
|
||||
|
||||
for (const auto &host : g_Config.vCustomAdhocServerListWithRelay) {
|
||||
// If the host is already in the public list, skip it. We don't want duplicates.
|
||||
if (hostInEntries(host)) {
|
||||
if (hostInEntries(host) || host.empty()) {
|
||||
continue;
|
||||
}
|
||||
AdhocServerListEntry entry;
|
||||
@@ -91,7 +238,7 @@ void AdhocServerScreen::CreatePopupContents(UI::ViewGroup *parent) {
|
||||
|
||||
for (const auto &host : g_Config.vCustomAdhocServerList) {
|
||||
// If the host is already in the public list, skip it. We don't want duplicates.
|
||||
if (hostInEntries(host)) {
|
||||
if (hostInEntries(host) || host.empty()) {
|
||||
continue;
|
||||
}
|
||||
AdhocServerListEntry entry;
|
||||
@@ -106,9 +253,9 @@ void AdhocServerScreen::CreatePopupContents(UI::ViewGroup *parent) {
|
||||
innerView->SetSpacing(5.0f);
|
||||
|
||||
auto AddButtonFromEntry = [this](UI::ViewGroup *parent, const AdhocServerListEntry &entry) {
|
||||
// Filter out IP prefixed with "127." and "169.254." also "0." since they can be redundant or unusable
|
||||
auto button = parent->Add(new Button(entry.host, new LinearLayoutParams(FILL_PARENT, WRAP_CONTENT)));
|
||||
button->OnClick.Add([this](UI::EventParams &e) {
|
||||
AdhocServerRow *row = new AdhocServerRow(&editValue_, entry, screenManager());
|
||||
parent->Add(row);
|
||||
row->OnSelected.Add([this](UI::EventParams &e) {
|
||||
std::string value = e.v->Tag();
|
||||
if (!value.empty()) {
|
||||
editValue_ = value;
|
||||
@@ -116,7 +263,7 @@ void AdhocServerScreen::CreatePopupContents(UI::ViewGroup *parent) {
|
||||
System_CopyStringToClipboard(value);
|
||||
}
|
||||
});
|
||||
button->SetTag(entry.host);
|
||||
row->SetTag(entry.host);
|
||||
};
|
||||
|
||||
if (!customEntries.empty()) {
|
||||
|
||||
@@ -22,6 +22,7 @@ public:
|
||||
protected:
|
||||
void OnCompleted(DialogResult result) override;
|
||||
bool CanComplete(DialogResult result) override;
|
||||
virtual UI::Size PopupWidth() const { return 650; }
|
||||
|
||||
void sendMessage(UIMessage message, const char *value) override;
|
||||
|
||||
|
||||
+8
-1
@@ -1424,6 +1424,12 @@ ULES00928 = true
|
||||
ULUS10312 = true
|
||||
ULKS46154 = true
|
||||
|
||||
# Gripshift (see #21367)
|
||||
ULUS10040 = true
|
||||
ULES00177 = true
|
||||
ULKS46040 = true
|
||||
ULJM05089 = true
|
||||
|
||||
[FramebufferAllowLargeVerticalOffset]
|
||||
# Tokimeki Memorial 4 (see #6379)
|
||||
NPJH50127 = true
|
||||
@@ -1438,7 +1444,8 @@ ULJM05224 = true
|
||||
NPJH50214 = true
|
||||
|
||||
[AtracLoopHack]
|
||||
#Atrac looped incorrectly see #7601 #13773 #11586 #10139 #12083
|
||||
# Atrac looped incorrectly see #7601 #13773 #11586 #10139 #12083
|
||||
# NOTE: This is no longer relevant after the Atrac3 rewrite, except for old savestates.
|
||||
|
||||
#Coded Arms: Contagion
|
||||
ULUS10184 = true
|
||||
|
||||
Reference in New Issue
Block a user