Files
ppsspp/UI/AdhocServerScreen.cpp
T
2026-02-26 17:17:42 +01:00

165 lines
4.6 KiB
C++

#include "AdhocServerScreen.h"
#include "Common/Net/Resolve.h"
#include "Common/UI/Root.h"
#include "Common/StringUtils.h"
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) {
thiz->ResolverThread();
}, this);
editValue_ = *value;
auto list_to_use = defaultProAdhocServerList;
downloadedProAdhocServerListMutex.lock();
if (downloadedProAdhocServerList.size() != 0) {
list_to_use = downloadedProAdhocServerList;
}
downloadedProAdhocServerListMutex.unlock();
listItems_ = list_to_use;
}
AdhocServerScreen::~AdhocServerScreen() {
{
std::unique_lock<std::mutex> guard(resolverLock_);
resolverState_ = ResolverState::QUIT;
resolverCond_.notify_one();
}
resolver_.join();
}
void AdhocServerScreen::CreatePopupContents(UI::ViewGroup *parent) {
using namespace UI;
auto sy = GetI18NCategory(I18NCat::SYSTEM);
auto di = GetI18NCategory(I18NCat::DIALOG);
auto n = GetI18NCategory(I18NCat::NETWORKING);
PopupTextInputChoice *textInputChoice = parent->Add(new PopupTextInputChoice(GetRequesterToken(), &editValue_, n->T("Hostname"), "", 256, screenManager()));
std::vector<std::string> listIP;
for (const auto &item : listItems_) {
listIP.push_back(item.hostname);
}
// Add non-editable items
listIP.push_back("localhost");
parent->Add(new Spacer(5.0f));
net::GetLocalIP4List(listIP);
ScrollView *scrollView = new ScrollView(ORIENT_VERTICAL, new LinearLayoutParams(1.0f));
LinearLayout *innerView = new LinearLayout(ORIENT_VERTICAL, new LinearLayoutParams(FILL_PARENT, WRAP_CONTENT));
innerView->SetSpacing(5.0f);
if (listIP.size() > 0) {
for (const auto& label : listIP) {
// Filter out IP prefixed with "127." and "169.254." also "0." since they can be redundant or unusable
if (label.find("127.") != 0 && label.find("169.254.") != 0 && label.find("0.") != 0) {
auto button = innerView->Add(new Button(label, new LinearLayoutParams(FILL_PARENT, WRAP_CONTENT)));
button->OnClick.Add([this](UI::EventParams &e) {
std::string value = e.v->Tag();
if (!value.empty()) {
editValue_ = value;
// TODO: Let's change this to an actual button later.
System_CopyStringToClipboard(value);
}
});
button->SetTag(label);
}
}
}
scrollView->Add(innerView);
parent->Add(scrollView);
listIP.clear(); listIP.shrink_to_fit();
progressView_ = parent->Add(new NoticeView(NoticeLevel::INFO, n->T("Validating address..."), "", new LinearLayoutParams(Margins(0, 5, 0, 0))));
progressView_->SetVisibility(UI::V_GONE);
}
void AdhocServerScreen::ResolverThread() {
std::unique_lock<std::mutex> guard(resolverLock_);
while (resolverState_ != ResolverState::QUIT) {
resolverCond_.wait(guard);
if (resolverState_ == ResolverState::QUEUED) {
resolverState_ = ResolverState::PROGRESS;
addrinfo *resolved = nullptr;
std::string err;
toResolveResult_ = net::DNSResolve(toResolve_, "80", &resolved, err);
if (resolved)
net::DNSResolveFree(resolved);
resolverState_ = ResolverState::READY;
}
}
}
bool AdhocServerScreen::CanComplete(DialogResult result) {
auto n = GetI18NCategory(I18NCat::NETWORKING);
if (result != DR_OK)
return true;
std::string value = editValue_;
if (lastResolved_ == value) {
return true;
}
// Currently running.
if (resolverState_ == ResolverState::PROGRESS)
return false;
std::lock_guard<std::mutex> guard(resolverLock_);
switch (resolverState_) {
case ResolverState::PROGRESS:
case ResolverState::QUIT:
return false;
case ResolverState::QUEUED:
case ResolverState::WAITING:
break;
case ResolverState::READY:
if (toResolve_ == value) {
// Reset the state, nothing there now.
resolverState_ = ResolverState::WAITING;
toResolve_.clear();
lastResolved_ = value;
lastResolvedResult_ = toResolveResult_;
if (lastResolvedResult_) {
progressView_->SetVisibility(UI::V_GONE);
} else {
progressView_->SetText(n->T("Invalid IP or hostname"));
progressView_->SetLevel(NoticeLevel::ERROR);
progressView_->SetVisibility(UI::V_VISIBLE);
}
return true;
}
// Throw away that last result, it was for a different value.
break;
}
resolverState_ = ResolverState::QUEUED;
toResolve_ = value;
resolverCond_.notify_one();
progressView_->SetText(n->T("Validating address..."));
progressView_->SetLevel(NoticeLevel::INFO);
progressView_->SetVisibility(UI::V_VISIBLE);
return false;
}
void AdhocServerScreen::OnCompleted(DialogResult result) {
if (result == DR_OK) {
*value_ = StripSpaces(editValue_);
}
}