mirror of
https://github.com/hrydgard/ppsspp.git
synced 2024-10-07 19:03:29 +00:00
Initial draft of the Homebrew Store. Lets you install a few homebrew.
This commit is contained in:
parent
cd6962497a
commit
2fb2602387
@ -371,7 +371,7 @@ add_library(stb_vorbis STATIC
|
||||
native/ext/stb_vorbis/stb_vorbis.h)
|
||||
include_directories(native/ext/stb_vorbis)
|
||||
|
||||
if(ANDROID)
|
||||
# if(ANDROID)
|
||||
add_library(libzip STATIC
|
||||
native/ext/libzip/zip.h
|
||||
native/ext/libzip/mkstemp.c
|
||||
@ -431,7 +431,7 @@ if(ANDROID)
|
||||
target_link_libraries(libzip zlib)
|
||||
include_directories(native/ext/libzip)
|
||||
set(LIBZIP libzip zlib)
|
||||
endif()
|
||||
# endif()
|
||||
|
||||
set(nativeExtra)
|
||||
set(nativeExtraLibs)
|
||||
@ -532,6 +532,10 @@ add_library(native STATIC
|
||||
native/base/timeutil.h
|
||||
native/data/compression.cpp
|
||||
native/data/compression.h
|
||||
native/ext/vjson/json.cpp
|
||||
native/ext/vjson/json.h
|
||||
native/ext/vjson/block_allocator.cpp
|
||||
native/ext/vjson/block_allocator.h
|
||||
native/file/chunk_file.cpp
|
||||
native/file/chunk_file.h
|
||||
native/file/dialog.cpp
|
||||
@ -655,7 +659,7 @@ add_library(native STATIC
|
||||
native/ext/jpge/jpge.cpp
|
||||
native/ext/jpge/jpge.h)
|
||||
include_directories(native)
|
||||
target_link_libraries(native ${LIBZIP} rg_etc1 vjson stb_image stb_vorbis snappy ${GLEW_LIBRARIES})
|
||||
target_link_libraries(native ${LIBZIP} rg_etc1 vjson stb_image stb_vorbis snappy libzip ${GLEW_LIBRARIES})
|
||||
|
||||
if(ANDROID)
|
||||
target_link_libraries(native log)
|
||||
@ -972,6 +976,8 @@ add_library(${CoreLibName} ${CoreLinkType}
|
||||
Core/SaveState.h
|
||||
Core/System.cpp
|
||||
Core/System.h
|
||||
Core/Util/GameManager.cpp
|
||||
Core/Util/GameManager.h
|
||||
Core/Util/BlockAllocator.cpp
|
||||
Core/Util/BlockAllocator.h
|
||||
Core/Util/PPGeDraw.cpp
|
||||
@ -1152,6 +1158,7 @@ set(NativeAppSource
|
||||
UI/UIShader.cpp
|
||||
UI/OnScreenDisplay.cpp
|
||||
UI/ControlMappingScreen.cpp
|
||||
UI/Store.cpp
|
||||
UI/CwCheatScreen.cpp
|
||||
UI/ui_atlas.cpp)
|
||||
if(ANDROID AND ARM)
|
||||
|
103
Core/Util/GameManager.cpp
Normal file
103
Core/Util/GameManager.cpp
Normal file
@ -0,0 +1,103 @@
|
||||
// Copyright (c) 2013- PPSSPP Project.
|
||||
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, version 2.0 or later versions.
|
||||
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License 2.0 for more details.
|
||||
|
||||
// A copy of the GPL 2.0 should have been included with the program.
|
||||
// If not, see http://www.gnu.org/licenses/
|
||||
|
||||
// Official git repository and contact information can be found at
|
||||
// https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/.
|
||||
|
||||
#include "file/file_util.h"
|
||||
#include "native/ext/libzip/zip.h"
|
||||
|
||||
#include "Common/Log.h"
|
||||
#include "Common/FileUtil.h"
|
||||
#include "Core/System.h"
|
||||
#include "Core/Util/GameManager.h"
|
||||
|
||||
GameManager g_GameManager;
|
||||
|
||||
bool GameManager::IsGameInstalled(std::string name) {
|
||||
return false;
|
||||
}
|
||||
|
||||
bool GameManager::DownloadAndInstall(std::string storeZipUrl) {
|
||||
if (curDownload_.get() != 0) {
|
||||
ERROR_LOG(HLE, "Can only process one download at a time");
|
||||
return false;
|
||||
}
|
||||
|
||||
// TODO: Android-compatible temp file names
|
||||
curDownload_ = downloader_.StartDownload(storeZipUrl, "/tmp/ppsspp.dl");
|
||||
return true;
|
||||
}
|
||||
|
||||
void GameManager::Uninstall(std::string name) {
|
||||
|
||||
}
|
||||
|
||||
void GameManager::Update() {
|
||||
if (curDownload_.get() && curDownload_->Done()) {
|
||||
// Install the game!
|
||||
std::string zipName = curDownload_->outfile();
|
||||
InstallGame(zipName);
|
||||
// Doesn't matter if the install succeeds or not, we delete the temp file to not squander space.
|
||||
// TODO: Handle disk full?
|
||||
deleteFile(zipName.c_str());
|
||||
curDownload_.reset();
|
||||
}
|
||||
}
|
||||
|
||||
void GameManager::InstallGame(std::string zipfile) {
|
||||
std::string pspGame = GetSysDirectory(DIRECTORY_GAME);
|
||||
INFO_LOG(HLE, "Installing %s into %s", zipfile.c_str(), pspGame.c_str());
|
||||
|
||||
int error;
|
||||
struct zip *z = zip_open(zipfile.c_str(), 0, &error);
|
||||
if (!z) {
|
||||
ERROR_LOG(HLE, "Failed to open ZIP file %s, error code=%i", zipfile.c_str(), error);
|
||||
return;
|
||||
}
|
||||
|
||||
int numFiles = zip_get_num_files(z);
|
||||
|
||||
for (int i = 0; i < numFiles; i++) {
|
||||
const char *fn = zip_get_name(z, i, 0);
|
||||
if (strstr(fn, "/") != 0) {
|
||||
INFO_LOG(HLE, "File: %i: %s", i, fn);
|
||||
struct zip_stat zstat;
|
||||
int x = zip_stat_index(z, i, 0, &zstat);
|
||||
size_t size = zstat.size;
|
||||
u8 *buffer = new u8[size];
|
||||
zip_file *zf = zip_fopen_index(z, i, 0);
|
||||
zip_fread(zf, buffer, size);
|
||||
zip_fclose(zf);
|
||||
|
||||
std::string outFilename = pspGame + fn;
|
||||
bool isDir = outFilename.back() == '/';
|
||||
if (isDir) {
|
||||
File::CreateFullPath(outFilename.c_str());
|
||||
} else {
|
||||
INFO_LOG(HLE, "Writing %i bytes to %s", (int)size, outFilename.c_str());
|
||||
FILE *f = fopen(outFilename.c_str(), "wb");
|
||||
if (f) {
|
||||
fwrite(buffer, 1, size, f);
|
||||
fclose(f);
|
||||
} else {
|
||||
ERROR_LOG(HLE, "Failed to open file for writing");
|
||||
}
|
||||
delete [] buffer;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
zip_close(z);
|
||||
}
|
44
Core/Util/GameManager.h
Normal file
44
Core/Util/GameManager.h
Normal file
@ -0,0 +1,44 @@
|
||||
// Copyright (c) 2013- PPSSPP Project.
|
||||
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, version 2.0 or later versions.
|
||||
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License 2.0 for more details.
|
||||
|
||||
// A copy of the GPL 2.0 should have been included with the program.
|
||||
// If not, see http://www.gnu.org/licenses/
|
||||
|
||||
// Official git repository and contact information can be found at
|
||||
// https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/.
|
||||
|
||||
|
||||
// Manages the PSP/GAME directory contents.
|
||||
//
|
||||
// Not concerned with full ISOs.
|
||||
|
||||
#include "net/http_client.h"
|
||||
|
||||
class GameManager {
|
||||
public:
|
||||
bool IsGameInstalled(std::string name);
|
||||
|
||||
// This starts off a background process.
|
||||
bool DownloadAndInstall(std::string storeZipUrl);
|
||||
void Uninstall(std::string name);
|
||||
|
||||
// Call from time to time to check on completed downloads from the
|
||||
// main UI thread.
|
||||
void Update();
|
||||
|
||||
private:
|
||||
void InstallGame(std::string zipfile);
|
||||
|
||||
http::Downloader downloader_;
|
||||
std::shared_ptr<http::Download> curDownload_;
|
||||
};
|
||||
|
||||
extern GameManager g_GameManager;
|
@ -439,7 +439,7 @@ void GameInfoCache::Add(const std::string &key, GameInfo *info_) {
|
||||
// This may run off-main-thread and we thus can't use the global
|
||||
// pspFileSystem (well, we could with synchronization but there might not
|
||||
// even be a game running).
|
||||
GameInfo *GameInfoCache::GetInfo(const std::string &gamePath, bool wantBG) {
|
||||
GameInfo *GameInfoCache::GetInfo(const std::string &gamePath, bool wantBG, bool synchronous) {
|
||||
auto iter = info_.find(gamePath);
|
||||
if (iter != info_.end()) {
|
||||
GameInfo *info = iter->second;
|
||||
@ -501,6 +501,10 @@ again:
|
||||
GameInfoWorkItem *item = new GameInfoWorkItem(gamePath, info);
|
||||
gameInfoWQ_->Add(item);
|
||||
|
||||
if (synchronous) {
|
||||
gameInfoWQ_->Wait(item);
|
||||
}
|
||||
|
||||
info_[gamePath] = info;
|
||||
return info;
|
||||
}
|
||||
|
@ -27,15 +27,15 @@
|
||||
#include "Core/ELF/ParamSFO.h"
|
||||
#include "Core/Loaders.h"
|
||||
|
||||
|
||||
// A GameInfo holds information about a game, and also lets you do things that the VSH
|
||||
// does on the PSP, namely checking for and deleting savedata, and similar things.
|
||||
// Only cares about games that are installed on the current device.
|
||||
|
||||
class GameInfo {
|
||||
public:
|
||||
GameInfo()
|
||||
GameInfo()
|
||||
: fileType(FILETYPE_UNKNOWN), paramSFOLoaded(false), iconTexture(NULL), pic0Texture(NULL), pic1Texture(NULL),
|
||||
wantBG(false), gameSize(0), saveDataSize(0), installDataSize(0), disc_total(0), disc_number(0) {}
|
||||
wantBG(false), gameSize(0), saveDataSize(0), installDataSize(0), disc_total(0), disc_number(0) {}
|
||||
|
||||
bool DeleteGame(); // Better be sure what you're doing when calling this.
|
||||
bool DeleteAllSaveData();
|
||||
@ -64,7 +64,7 @@ public:
|
||||
IdentifiedFileType fileType;
|
||||
ParamSFOData paramSFO;
|
||||
bool paramSFOLoaded;
|
||||
|
||||
|
||||
// Pre read the data, create a texture the next time (GL thread..)
|
||||
std::string iconTextureData;
|
||||
Texture *iconTexture;
|
||||
@ -102,7 +102,7 @@ public:
|
||||
// but filled in later asynchronously in the background. So keep calling this,
|
||||
// redrawing the UI often. Only set wantBG if you really want it because
|
||||
// it's big. bgTextures may be discarded over time as well.
|
||||
GameInfo *GetInfo(const std::string &gamePath, bool wantBG);
|
||||
GameInfo *GetInfo(const std::string &gamePath, bool wantBG, bool synchronous = false);
|
||||
void Decimate(); // Deletes old info.
|
||||
void FlushBGs(); // Gets rid of all BG textures.
|
||||
|
||||
|
@ -40,6 +40,7 @@
|
||||
#include "UI/CwCheatScreen.h"
|
||||
#include "UI/MiscScreens.h"
|
||||
#include "UI/ControlMappingScreen.h"
|
||||
#include "UI/Store.h"
|
||||
#include "UI/ui_atlas.h"
|
||||
#include "Core/Config.h"
|
||||
#include "GPU/GPUInterface.h"
|
||||
@ -501,6 +502,7 @@ void MainScreen::CreateViews() {
|
||||
#endif
|
||||
rightColumnItems->Add(new Choice(m->T("Game Settings", "Settings")))->OnClick.Handle(this, &MainScreen::OnGameSettings);
|
||||
rightColumnItems->Add(new Choice(m->T("Credits")))->OnClick.Handle(this, &MainScreen::OnCredits);
|
||||
rightColumnItems->Add(new Choice(m->T("Homebrew Store")))->OnClick.Handle(this, &MainScreen::OnHomebrewStore);
|
||||
#ifndef __SYMBIAN32__
|
||||
rightColumnItems->Add(new Choice(m->T("www.ppsspp.org")))->OnClick.Handle(this, &MainScreen::OnPPSSPPOrg);
|
||||
#endif
|
||||
@ -648,6 +650,11 @@ UI::EventReturn MainScreen::OnCredits(UI::EventParams &e) {
|
||||
return UI::EVENT_DONE;
|
||||
}
|
||||
|
||||
UI::EventReturn MainScreen::OnHomebrewStore(UI::EventParams &e) {
|
||||
screenManager()->push(new StoreScreen());
|
||||
return UI::EVENT_DONE;
|
||||
}
|
||||
|
||||
UI::EventReturn MainScreen::OnSupport(UI::EventParams &e) {
|
||||
#ifdef ANDROID
|
||||
LaunchBrowser("market://details?id=org.ppsspp.ppssppgold");
|
||||
|
@ -51,6 +51,7 @@ private:
|
||||
UI::EventReturn OnExit(UI::EventParams &e);
|
||||
UI::EventReturn OnDownloadUpgrade(UI::EventParams &e);
|
||||
UI::EventReturn OnDismissUpgrade(UI::EventParams &e);
|
||||
UI::EventReturn OnHomebrewStore(UI::EventParams &e);
|
||||
|
||||
UI::LinearLayout *upgradeBar_;
|
||||
};
|
||||
|
@ -61,6 +61,7 @@
|
||||
#include "Core/HLE/sceCtrl.h"
|
||||
#include "Core/Host.h"
|
||||
#include "Core/SaveState.h"
|
||||
#include "Core/Util/GameManager.h"
|
||||
#include "Common/MemArena.h"
|
||||
|
||||
#include "ui_atlas.h"
|
||||
@ -566,6 +567,8 @@ void TakeScreenshot() {
|
||||
}
|
||||
|
||||
void NativeRender() {
|
||||
g_GameManager.Update();
|
||||
|
||||
glstate.depthWrite.set(GL_TRUE);
|
||||
glstate.colorMask.set(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
|
||||
|
||||
|
253
UI/Store.cpp
Normal file
253
UI/Store.cpp
Normal file
@ -0,0 +1,253 @@
|
||||
#include "native/ext/vjson/json.h"
|
||||
|
||||
#include "i18n/i18n.h"
|
||||
#include "ui/ui_context.h"
|
||||
#include "ui/viewgroup.h"
|
||||
#include "gfx_es2/draw_buffer.h"
|
||||
|
||||
#include "Common/Log.h"
|
||||
#include "Core/Config.h"
|
||||
#include "UI/Store.h"
|
||||
|
||||
const std::string storeBaseUrl = "http://store.ppsspp.org/";
|
||||
|
||||
// This is the entry in a list. Does not have install buttons and so on.
|
||||
class ProductItemView : public UI::Choice {
|
||||
public:
|
||||
ProductItemView(const StoreEntry &entry, UI::LayoutParams *layoutParams = 0)
|
||||
: entry_(entry), UI::Choice(entry.name, layoutParams) {}
|
||||
|
||||
virtual void GetContentDimensions(const UIContext &dc, float &w, float &h) const {
|
||||
w = 300;
|
||||
h = 164;
|
||||
}
|
||||
virtual void Update(const InputState &input_state);
|
||||
virtual void Draw(UIContext &dc);
|
||||
|
||||
StoreEntry GetEntry() const { return entry_; }
|
||||
|
||||
private:
|
||||
const StoreEntry &entry_;
|
||||
};
|
||||
|
||||
void ProductItemView::Draw(UIContext &dc) {
|
||||
UI::Choice::Draw(dc);
|
||||
// dc.DrawText(entry_.name.c_str(), bounds_.centerX(), bounds_.centerY(), 0xFFFFFFFF, ALIGN_CENTER);
|
||||
}
|
||||
|
||||
void ProductItemView::Update(const InputState &input_state) {
|
||||
View::Update(input_state);
|
||||
}
|
||||
|
||||
// This is a "details" view of a game. Let's you install it.
|
||||
class ProductView : public UI::LinearLayout {
|
||||
public:
|
||||
ProductView(const StoreEntry &entry) : LinearLayout(UI::ORIENT_VERTICAL), entry_(entry) {
|
||||
CreateViews();
|
||||
}
|
||||
|
||||
virtual void Update(const InputState &input_state);
|
||||
|
||||
private:
|
||||
void CreateViews();
|
||||
UI::EventReturn OnInstall(UI::EventParams &e);
|
||||
UI::EventReturn OnUninstall(UI::EventParams &e);
|
||||
|
||||
StoreEntry entry_;
|
||||
};
|
||||
|
||||
void ProductView::CreateViews() {
|
||||
using namespace UI;
|
||||
Clear();
|
||||
|
||||
Add(new TextView(entry_.name));
|
||||
Add(new TextView(entry_.author));
|
||||
|
||||
I18NCategory *s = GetI18NCategory("Store");
|
||||
if (!g_GameManager.IsGameInstalled(entry_.file)) {
|
||||
Add(new Button(s->T("Install")))->OnClick.Handle(this, &ProductView::OnInstall);
|
||||
} else {
|
||||
Add(new Button(s->T("Uninstall")))->OnClick.Handle(this, &ProductView::OnUninstall);
|
||||
}
|
||||
// Add star rating, comments etc?
|
||||
Add(new TextView(entry_.description));
|
||||
|
||||
float size = entry_.size / (1024.f * 1024.f);
|
||||
char temp[256];
|
||||
sprintf(temp, "%s: %f %s", s->T("Size"), size, s->T("MB"));
|
||||
|
||||
Add(new TextView(temp));
|
||||
}
|
||||
|
||||
void ProductView::Update(const InputState &input_state) {
|
||||
View::Update(input_state);
|
||||
// TODO: Update download progress bar, etc.
|
||||
}
|
||||
|
||||
UI::EventReturn ProductView::OnInstall(UI::EventParams &e) {
|
||||
std::string zipUrl = storeBaseUrl + "files/" + entry_.file + ".zip";
|
||||
INFO_LOG(HLE, "Triggering install of %s", zipUrl.c_str());
|
||||
g_GameManager.DownloadAndInstall(zipUrl);
|
||||
return UI::EVENT_DONE;
|
||||
}
|
||||
|
||||
UI::EventReturn ProductView::OnUninstall(UI::EventParams &e) {
|
||||
g_GameManager.Uninstall(entry_.file);
|
||||
return UI::EVENT_DONE;
|
||||
}
|
||||
|
||||
|
||||
StoreScreen::StoreScreen() : loading_(true), connectionError_(false) {
|
||||
StoreFilter noFilter;
|
||||
SetFilter(noFilter);
|
||||
lang_ = g_Config.sLanguageIni;
|
||||
loading_ = true;
|
||||
|
||||
std::string indexPath = storeBaseUrl + "index.json";
|
||||
|
||||
listing_ = downloader_.StartDownload(indexPath, "");
|
||||
}
|
||||
|
||||
StoreScreen::~StoreScreen() {
|
||||
downloader_.CancelAll();
|
||||
}
|
||||
|
||||
// Handle async download tasks
|
||||
void StoreScreen::update(InputState &input) {
|
||||
UIDialogScreenWithBackground::update(input);
|
||||
|
||||
downloader_.Update();
|
||||
|
||||
if (listing_.get() != 0 && listing_->Done()) {
|
||||
if (listing_->ResultCode() == 200) {
|
||||
std::string listingJson;
|
||||
listing_->buffer().TakeAll(&listingJson);
|
||||
printf("%s\n", listingJson.c_str());
|
||||
loading_ = false;
|
||||
|
||||
ParseListing(listingJson);
|
||||
RecreateViews();
|
||||
} else {
|
||||
// Failed to contact store. Don't do anything.
|
||||
connectionError_ = true;
|
||||
RecreateViews();
|
||||
}
|
||||
|
||||
// Forget the listing.
|
||||
listing_.reset();
|
||||
}
|
||||
}
|
||||
|
||||
void StoreScreen::ParseListing(std::string json) {
|
||||
JsonReader reader(json.c_str(), json.size());
|
||||
if (!reader.ok()) {
|
||||
ELOG("Error parsing JSON from store");
|
||||
connectionError_ = true;
|
||||
RecreateViews();
|
||||
return;
|
||||
}
|
||||
json_value *root = reader.root();
|
||||
const json_value *entries = root->getArray("entries");
|
||||
if (entries) {
|
||||
entries_.clear();
|
||||
const json_value *game = entries->first_child;
|
||||
while (game) {
|
||||
StoreEntry e;
|
||||
e.type = ENTRY_PBPZIP;
|
||||
e.name = GetTranslatedString(game, "name");
|
||||
e.description = GetTranslatedString(game, "description", "");
|
||||
e.author = game->getString("author", "?");
|
||||
e.size = game->getInt("size");
|
||||
const char *file = game->getString("file", 0);
|
||||
if (!file)
|
||||
continue;
|
||||
e.file = file;
|
||||
entries_.push_back(e);
|
||||
game = game->next_sibling;
|
||||
ILOG("%s", e.name.c_str());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void StoreScreen::CreateViews() {
|
||||
using namespace UI;
|
||||
if (connectionError_ || loading_) {
|
||||
root_ = new LinearLayout(ORIENT_VERTICAL);
|
||||
root_->Add(new TextView(loading_ ? "Loading.." : "Connection Error"));
|
||||
root_->Add(new Button("Retry"))->OnClick.Handle(this, &StoreScreen::OnRetry);
|
||||
root_->Add(new Button("Back"))->OnClick.Handle<UIScreen>(this, &UIScreen::OnBack);
|
||||
} else {
|
||||
root_ = new LinearLayout(ORIENT_HORIZONTAL);
|
||||
ScrollView *leftScroll = new ScrollView(ORIENT_VERTICAL, new LinearLayoutParams(0.5f));
|
||||
root_->Add(new Button("Back"))->OnClick.Handle<UIScreen>(this, &UIScreen::OnBack);
|
||||
root_->Add(leftScroll);
|
||||
LinearLayout *scrollItemView = new LinearLayout(ORIENT_VERTICAL);
|
||||
leftScroll->Add(scrollItemView);
|
||||
std::vector<StoreEntry> entries = FilterEntries();
|
||||
for (size_t i = 0; i < entries.size(); i++) {
|
||||
ILOG("Adding %s", entries[i].name.c_str());
|
||||
scrollItemView->Add(new ProductItemView(entries_[i]))->OnClick.Handle(this, &StoreScreen::OnGameSelected);
|
||||
}
|
||||
|
||||
// TODO: Similar apps, etc etc
|
||||
productPanel_ = new ScrollView(ORIENT_VERTICAL, new LinearLayoutParams(0.5f));
|
||||
root_->Add(productPanel_);
|
||||
}
|
||||
}
|
||||
|
||||
std::vector<StoreEntry> StoreScreen::FilterEntries() {
|
||||
std::vector<StoreEntry> filtered;
|
||||
for (size_t i = 0; i < entries_.size(); i++) {
|
||||
// TODO: Actually filter by category etc.
|
||||
filtered.push_back(entries_[i]);
|
||||
}
|
||||
return filtered;
|
||||
}
|
||||
|
||||
UI::EventReturn StoreScreen::OnGameSelected(UI::EventParams &e) {
|
||||
ProductItemView *item = static_cast<ProductItemView *>(e.v);
|
||||
if (!item)
|
||||
return UI::EVENT_DONE;
|
||||
|
||||
productPanel_->Clear();
|
||||
productPanel_->Add(new ProductView(item->GetEntry()));
|
||||
return UI::EVENT_DONE;
|
||||
}
|
||||
|
||||
void StoreScreen::SetFilter(const StoreFilter &filter) {
|
||||
filter_ = filter;
|
||||
RecreateViews();
|
||||
}
|
||||
|
||||
UI::EventReturn StoreScreen::OnRetry(UI::EventParams &e) {
|
||||
SetFilter(filter_);
|
||||
return UI::EVENT_DONE;
|
||||
}
|
||||
|
||||
std::string StoreScreen::GetStoreJsonURL(std::string storePath) const {
|
||||
std::string path = storeBaseUrl + storePath;
|
||||
if (path.back() != '/')
|
||||
path += '/';
|
||||
path += "index.json";
|
||||
return path;
|
||||
}
|
||||
|
||||
std::string StoreScreen::GetTranslatedString(const json_value *json, std::string key, const char *fallback) const {
|
||||
ILOG("getTranslatedString %s", key.c_str());
|
||||
const json_value *dict = json->getDict("en_US");
|
||||
if (dict && json->hasChild(lang_.c_str(), JSON_OBJECT)) {
|
||||
if (json->getDict(lang_.c_str())->hasChild(key.c_str(), JSON_STRING)) {
|
||||
dict = json->getDict(lang_.c_str());
|
||||
}
|
||||
}
|
||||
const char *str = 0;
|
||||
if (dict) {
|
||||
str = dict->getString(key.c_str());
|
||||
}
|
||||
if (str) {
|
||||
return std::string(str);
|
||||
} else {
|
||||
return fallback ? fallback : "(error)";
|
||||
}
|
||||
}
|
||||
|
102
UI/Store.h
Normal file
102
UI/Store.h
Normal file
@ -0,0 +1,102 @@
|
||||
// Copyright (c) 2013- PPSSPP Project.
|
||||
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, version 2.0 or later versions.
|
||||
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License 2.0 for more details.
|
||||
|
||||
// A copy of the GPL 2.0 should have been included with the program.
|
||||
// If not, see http://www.gnu.org/licenses/
|
||||
|
||||
// Official git repository and contact information can be found at
|
||||
// https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "base/functional.h"
|
||||
#include "ui/ui_screen.h"
|
||||
#include "ui/viewgroup.h"
|
||||
#include "net/http_client.h"
|
||||
|
||||
#include "Core/Util/GameManager.h"
|
||||
#include "UI/MiscScreens.h"
|
||||
|
||||
// Game screen: Allows you to start a game, delete saves, delete the game,
|
||||
// set game specific settings, etc.
|
||||
// Uses GameInfoCache heavily to implement the functionality.
|
||||
|
||||
struct json_value;
|
||||
|
||||
enum EntryType {
|
||||
ENTRY_PBPZIP,
|
||||
ENTRY_ISO,
|
||||
};
|
||||
|
||||
struct StoreCategory {
|
||||
std::string name;
|
||||
};
|
||||
|
||||
struct StoreEntry {
|
||||
EntryType type;
|
||||
std::string name;
|
||||
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 category;
|
||||
u64 size;
|
||||
};
|
||||
|
||||
struct StoreFilter {
|
||||
std::string categoryId;
|
||||
};
|
||||
|
||||
class StoreScreen : public UIDialogScreenWithBackground {
|
||||
public:
|
||||
StoreScreen();
|
||||
~StoreScreen();
|
||||
|
||||
virtual void update(InputState &input);
|
||||
|
||||
protected:
|
||||
virtual void CreateViews();
|
||||
UI::EventReturn OnGameSelected(UI::EventParams &e);
|
||||
UI::EventReturn OnCategorySelected(UI::EventParams &e);
|
||||
UI::EventReturn OnRetry(UI::EventParams &e);
|
||||
|
||||
private:
|
||||
void SetFilter(const StoreFilter &filter);
|
||||
void ParseListing(std::string json);
|
||||
std::vector<StoreEntry> FilterEntries();
|
||||
|
||||
std::string GetStoreJsonURL(std::string storePath) const;
|
||||
std::string GetTranslatedString(const json_value *json, std::string key, const char *fallback = 0) const;
|
||||
|
||||
http::Downloader downloader_;
|
||||
|
||||
std::shared_ptr<http::Download> listing_;
|
||||
std::shared_ptr<http::Download> image_;
|
||||
|
||||
// TODO: Replace with a PathBrowser or similar. Though that one only supports
|
||||
// local filesystems at the moment.
|
||||
std::string storePath_;
|
||||
|
||||
bool loading_;
|
||||
bool connectionError_;
|
||||
|
||||
std::map<std::string, StoreCategory> categories_;
|
||||
|
||||
// We download the whole store in one JSON request. Not super scalable but works fine
|
||||
// for now. entries_ contains all the products in the store.
|
||||
std::vector<StoreEntry> entries_;
|
||||
|
||||
StoreFilter filter_;
|
||||
std::string lang_;
|
||||
|
||||
UI::ViewGroup *productPanel_;
|
||||
};
|
||||
|
@ -254,6 +254,7 @@ EXEC_AND_LIB_FILES := \
|
||||
$(SRC)/Core/FileSystems/tlzrc.cpp \
|
||||
$(SRC)/Core/MIPS/JitCommon/JitCommon.cpp \
|
||||
$(SRC)/Core/MIPS/JitCommon/JitBlockCache.cpp \
|
||||
$(SRC)/Core/Util/GameManager.cpp \
|
||||
$(SRC)/Core/Util/BlockAllocator.cpp \
|
||||
$(SRC)/Core/Util/ppge_atlas.cpp \
|
||||
$(SRC)/Core/Util/PPGeDraw.cpp \
|
||||
|
Loading…
Reference in New Issue
Block a user