Skip to content

Commit

Permalink
UI: Handle remote browsing asynchronously.
Browse files Browse the repository at this point in the history
  • Loading branch information
unknownbrackets committed Oct 6, 2019
1 parent 8d3da2c commit e5eb849
Show file tree
Hide file tree
Showing 5 changed files with 156 additions and 34 deletions.
21 changes: 17 additions & 4 deletions UI/MainScreen.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -441,7 +441,7 @@ void DirButton::Draw(UIContext &dc) {
}

GameBrowser::GameBrowser(std::string path, bool allowBrowsing, bool *gridStyle, std::string lastText, std::string lastLink, int flags, UI::LayoutParams *layoutParams)
: LinearLayout(UI::ORIENT_VERTICAL, layoutParams), gameList_(0), path_(path), gridStyle_(gridStyle), allowBrowsing_(allowBrowsing), lastText_(lastText), lastLink_(lastLink), flags_(flags) {
: LinearLayout(UI::ORIENT_VERTICAL, layoutParams), path_(path), gridStyle_(gridStyle), allowBrowsing_(allowBrowsing), lastText_(lastText), lastLink_(lastLink), flags_(flags) {
using namespace UI;
Refresh();
}
Expand Down Expand Up @@ -510,10 +510,17 @@ bool GameBrowser::HasSpecialFiles(std::vector<std::string> &filenames) {
return false;
}

void GameBrowser::Update() {
LinearLayout::Update();
if (listingPending_ && path_.IsListingReady()) {
Refresh();
}
}

void GameBrowser::Refresh() {
using namespace UI;

homebrewStoreButton_ = 0;
homebrewStoreButton_ = nullptr;
// Kill all the contents
Clear();

Expand Down Expand Up @@ -556,12 +563,14 @@ void GameBrowser::Refresh() {
std::vector<DirButton *> dirButtons;
std::vector<GameButton *> gameButtons;

listingPending_ = !path_.IsListingReady();

std::vector<std::string> filenames;
if (HasSpecialFiles(filenames)) {
for (size_t i = 0; i < filenames.size(); i++) {
gameButtons.push_back(new GameButton(filenames[i], *gridStyle_, new UI::LinearLayoutParams(*gridStyle_ == true ? UI::WRAP_CONTENT : UI::FILL_PARENT, UI::WRAP_CONTENT)));
}
} else {
} else if (!listingPending_) {
std::vector<FileInfo> fileInfo;
path_.GetListing(fileInfo, "iso:cso:pbp:elf:prx:ppdmp:");
for (size_t i = 0; i < fileInfo.size(); i++) {
Expand Down Expand Up @@ -616,6 +625,10 @@ void GameBrowser::Refresh() {
}
}

if (listingPending_) {
gameList_->Add(new UI::TextView(mm->T("Loading..."), ALIGN_CENTER, false, new UI::LinearLayoutParams(UI::FILL_PARENT, UI::FILL_PARENT)));
}

for (size_t i = 0; i < dirButtons.size(); i++) {
gameList_->Add(dirButtons[i])->OnClick.Handle(this, &GameBrowser::NavigateClick);
}
Expand Down Expand Up @@ -645,7 +658,7 @@ void GameBrowser::Refresh() {
Add(new Spacer());
homebrewStoreButton_ = Add(new Choice(mm->T("DownloadFromStore", "Download from the PPSSPP Homebrew Store"), new UI::LinearLayoutParams(UI::WRAP_CONTENT, UI::WRAP_CONTENT)));
} else {
homebrewStoreButton_ = 0;
homebrewStoreButton_ = nullptr;
}

if (!lastText_.empty() && gameButtons.empty()) {
Expand Down
9 changes: 6 additions & 3 deletions UI/MainScreen.h
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@

class GameBrowser : public UI::LinearLayout {
public:
GameBrowser(std::string path, bool allowBrowsing, bool *gridStyle_, std::string lastText, std::string lastLink, int flags = 0, UI::LayoutParams *layoutParams = 0);
GameBrowser(std::string path, bool allowBrowsing, bool *gridStyle, std::string lastText, std::string lastLink, int flags = 0, UI::LayoutParams *layoutParams = nullptr);

UI::Event OnChoice;
UI::Event OnHoldChoice;
Expand All @@ -37,6 +37,8 @@ class GameBrowser : public UI::LinearLayout {
void FocusGame(const std::string &gamePath);
void SetPath(const std::string &path);

void Update() override;

protected:
virtual bool DisplayTopBar();
virtual bool HasSpecialFiles(std::vector<std::string> &filenames);
Expand All @@ -57,15 +59,16 @@ class GameBrowser : public UI::LinearLayout {
UI::EventReturn HomeClick(UI::EventParams &e);
UI::EventReturn PinToggleClick(UI::EventParams &e);

UI::ViewGroup *gameList_;
UI::ViewGroup *gameList_ = nullptr;
PathBrowser path_;
bool *gridStyle_;
bool allowBrowsing_;
std::string lastText_;
std::string lastLink_;
int flags_;
UI::Choice *homebrewStoreButton_;
UI::Choice *homebrewStoreButton_ = nullptr;
std::string focusGamePath_;
bool listingPending_ = false;
};

class RemoteISOBrowseScreen;
Expand Down
4 changes: 3 additions & 1 deletion UI/RemoteISOScreen.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -160,7 +160,9 @@ static bool LoadGameList(const std::string &host, int port, std::vector<std::str
return false;
}
for (auto &file : files) {
games.push_back(file.fullName);
if (RemoteISOFileSupported(file.name)) {
games.push_back(file.fullName);
}
}

// Save for next time unless manual is true
Expand Down
140 changes: 114 additions & 26 deletions ext/native/file/path.cpp
Original file line number Diff line number Diff line change
@@ -1,11 +1,13 @@
#include <algorithm>
#include <set>
#include "base/stringutil.h"
#include "base/timeutil.h"
#include "file/path.h"
#include "net/http_client.h"
#include "net/url.h"
#include "thread/threadutil.h"

bool LoadRemoteFileList(const std::string &url, bool *cancel, std::vector<FileInfo> &files, const char *filter) {
bool LoadRemoteFileList(const std::string &url, bool *cancel, std::vector<FileInfo> &files) {
http::Client http;
Buffer result;
int code = 500;
Expand Down Expand Up @@ -58,21 +60,6 @@ bool LoadRemoteFileList(const std::string &url, bool *cancel, std::vector<FileIn
return false;
}

std::set<std::string> filters;
if (filter) {
std::string tmp;
while (*filter) {
if (*filter == ':') {
filters.insert(std::move(tmp));
} else {
tmp.push_back(*filter);
}
filter++;
}
if (!tmp.empty())
filters.insert(std::move(tmp));
}

for (std::string item : items) {
// Apply some workarounds.
if (item.empty())
Expand All @@ -87,26 +74,56 @@ bool LoadRemoteFileList(const std::string &url, bool *cancel, std::vector<FileIn
info.exists = true;
info.size = 0;
info.isWritable = false;
if (!info.isDirectory) {
std::string ext = getFileExtension(info.fullName);
if (filter) {
if (filters.find(ext) == filters.end())
continue;
}
}

files.push_back(info);
}


std::sort(files.begin(), files.end());
return !files.empty();
}

std::vector<FileInfo> ApplyFilter(std::vector<FileInfo> files, const char *filter) {
std::set<std::string> filters;
if (filter) {
std::string tmp;
while (*filter) {
if (*filter == ':') {
filters.insert(std::move(tmp));
} else {
tmp.push_back(*filter);
}
filter++;
}
if (!tmp.empty())
filters.insert(std::move(tmp));
}

auto pred = [&](const FileInfo &info) {
if (info.isDirectory || !filter)
return false;
std::string ext = getFileExtension(info.fullName);
return filters.find(ext) == filters.end();
};
files.erase(std::remove_if(files.begin(), files.end(), pred), files.end());
return files;
}

PathBrowser::~PathBrowser() {
std::unique_lock<std::mutex> guard(pendingLock_);
pendingCancel_ = true;
pendingStop_ = true;
pendingCond_.notify_all();
guard.unlock();

if (pendingThread_.joinable()) {
pendingThread_.join();
}
}

// Normalize slashes.
void PathBrowser::SetPath(const std::string &path) {
if (path[0] == '!') {
path_ = path;
HandlePath();
return;
}
path_ = path;
Expand All @@ -115,9 +132,78 @@ void PathBrowser::SetPath(const std::string &path) {
}
if (!path_.size() || (path_[path_.size() - 1] != '/'))
path_ += "/";
HandlePath();
}

void PathBrowser::HandlePath() {
std::lock_guard<std::mutex> guard(pendingLock_);

if (!path_.empty() && path_[0] == '!') {
ready_ = true;
pendingCancel_ = true;
pendingPath_.clear();
return;
}
if (!startsWith(path_, "http://") && !startsWith(path_, "https://")) {
ready_ = true;
pendingCancel_ = true;
pendingPath_.clear();
return;
}

ready_ = false;
pendingCancel_ = false;
pendingFiles_.clear();
pendingPath_ = path_;
pendingCond_.notify_all();

if (pendingThread_.joinable())
return;

pendingThread_ = std::thread([&] {
setCurrentThreadName("PathBrowser");

std::unique_lock<std::mutex> guard(pendingLock_);
std::vector<FileInfo> results;
std::string lastPath;
while (!pendingStop_) {
while (lastPath == pendingPath_ && !pendingCancel_) {
pendingCond_.wait(guard);
}
lastPath = pendingPath_;
bool success = false;
if (!lastPath.empty()) {
guard.unlock();
results.clear();
success = LoadRemoteFileList(lastPath, &pendingCancel_, results);
guard.lock();
}

if (pendingPath_ == lastPath) {
if (success && !pendingCancel_) {
pendingFiles_ = results;
}
pendingPath_.clear();
lastPath.clear();
ready_ = true;
}
}
});
}

bool PathBrowser::IsListingReady() {
return ready_;
}

bool PathBrowser::GetListing(std::vector<FileInfo> &fileInfo, const char *filter, bool *cancel) {
std::unique_lock<std::mutex> guard(pendingLock_);
while (!IsListingReady() && (!cancel || !*cancel)) {
// In case cancel changes, just sleep.
guard.unlock();
sleep_ms(100);
guard.lock();
}

#ifdef _WIN32
if (path_ == "/") {
// Special path that means root of file system.
Expand All @@ -138,7 +224,8 @@ bool PathBrowser::GetListing(std::vector<FileInfo> &fileInfo, const char *filter
#endif

if (startsWith(path_, "http://") || startsWith(path_, "https://")) {
return LoadRemoteFileList(path_, cancel, fileInfo, filter);
fileInfo = ApplyFilter(pendingFiles_, filter);
return true;
} else {
getFilesInDir(path_.c_str(), &fileInfo, filter);
return true;
Expand Down Expand Up @@ -167,4 +254,5 @@ void PathBrowser::Navigate(const std::string &path) {
if (path_[path_.size() - 1] != '/')
path_ += "/";
}
HandlePath();
}
16 changes: 16 additions & 0 deletions ext/native/file/path.h
Original file line number Diff line number Diff line change
@@ -1,7 +1,10 @@
#pragma once

#include <condition_variable>
#include <mutex>
#include <string>
#include <string.h>
#include <thread>
#include <vector>
#include <stdlib.h>

Expand All @@ -14,8 +17,10 @@ class PathBrowser {
public:
PathBrowser() {}
PathBrowser(std::string path) { SetPath(path); }
~PathBrowser();

void SetPath(const std::string &path);
bool IsListingReady();
bool GetListing(std::vector<FileInfo> &fileInfo, const char *filter = nullptr, bool *cancel = nullptr);
void Navigate(const std::string &path);

Expand All @@ -39,6 +44,17 @@ class PathBrowser {
return str;
}

private:
void HandlePath();

std::string path_;
std::string pendingPath_;
std::vector<FileInfo> pendingFiles_;
std::condition_variable pendingCond_;
std::mutex pendingLock_;
std::thread pendingThread_;
bool pendingCancel_ = false;
bool pendingStop_ = false;
bool ready_ = false;
};

0 comments on commit e5eb849

Please sign in to comment.