mirror of
https://github.com/hrydgard/ppsspp.git
synced 2024-11-26 23:10:38 +00:00
Much more UI work on savedata import
fix
This commit is contained in:
parent
f38cc4a959
commit
8186f14a57
@ -266,11 +266,17 @@ void DetectZipFileContents(struct zip *z, ZipFileInfo *info) {
|
||||
int directoriesInRoot = 0;
|
||||
bool hasParamSFO = false;
|
||||
bool hasIcon0PNG = false;
|
||||
s64 totalFileSize = 0;
|
||||
|
||||
// TODO: It might be cleaner to write separate detection functions, but this big loop doing it all at once
|
||||
// is quite convenient and makes it easy to add shared heuristics.
|
||||
for (int i = 0; i < numFiles; i++) {
|
||||
const char *fn = zip_get_name(z, i, 0);
|
||||
|
||||
zip_stat_t stat{};
|
||||
zip_stat_index(z, i, 0, &stat);
|
||||
totalFileSize += stat.size;
|
||||
|
||||
std::string zippedName = fn;
|
||||
std::transform(zippedName.begin(), zippedName.end(), zippedName.begin(),
|
||||
[](unsigned char c) { return asciitolower(c); }); // Not using std::tolower to avoid Turkish I->ı conversion.
|
||||
@ -282,6 +288,7 @@ void DetectZipFileContents(struct zip *z, ZipFileInfo *info) {
|
||||
// A directory. Not all zips bother including these.
|
||||
continue;
|
||||
}
|
||||
|
||||
int prevSlashLocation = -1;
|
||||
int slashCount = countSlashes(zippedName, &prevSlashLocation);
|
||||
if (zippedName.find("eboot.pbp") != std::string::npos) {
|
||||
@ -318,9 +325,12 @@ void DetectZipFileContents(struct zip *z, ZipFileInfo *info) {
|
||||
ParamSFOData sfo;
|
||||
if (sfo.ReadSFO((const u8 *)paramSFOContents.data(), paramSFOContents.size())) {
|
||||
if (sfo.HasKey("TITLE")) {
|
||||
std::string title = sfo.GetValueString("TITLE") + ": " + sfo.GetValueString("SAVEDATA_TITLE");
|
||||
std::string details = sfo.GetValueString("SAVEDATA_DETAIL");
|
||||
info->contentName = title + "\n\n" + details;
|
||||
info->gameTitle = sfo.GetValueString("TITLE");
|
||||
info->savedataTitle = sfo.GetValueString("SAVEDATA_TITLE");
|
||||
char buff[20];
|
||||
strftime(buff, 20, "%Y-%m-%d %H:%M:%S", localtime(&stat.mtime));
|
||||
info->mTime = buff;
|
||||
info->savedataDetails = sfo.GetValueString("SAVEDATA_DETAIL");
|
||||
info->savedataDir = sfo.GetValueString("SAVEDATA_DIRECTORY"); // should also be parsable from the path.
|
||||
hasParamSFO = true;
|
||||
}
|
||||
@ -339,6 +349,7 @@ void DetectZipFileContents(struct zip *z, ZipFileInfo *info) {
|
||||
info->isoFileIndex = isoFileIndex;
|
||||
info->textureIniIndex = textureIniIndex;
|
||||
info->ignoreMetaFiles = false;
|
||||
info->totalFileSize = totalFileSize;
|
||||
|
||||
// Priority ordering for detecting the various kinds of zip file content.s
|
||||
if (isPSPMemstickGame) {
|
||||
@ -613,7 +624,6 @@ bool GameManager::ExtractFile(struct zip *z, int file_index, const Path &outFile
|
||||
struct zip_stat zstat;
|
||||
zip_stat_index(z, file_index, 0, &zstat);
|
||||
size_t size = zstat.size;
|
||||
|
||||
zip_file *zf = zip_fopen_index(z, file_index, 0);
|
||||
if (!zf) {
|
||||
ERROR_LOG(Log::HLE, "Failed to open file by index (%d) (%s)", file_index, outFilename.c_str());
|
||||
|
@ -50,8 +50,14 @@ struct ZipFileInfo {
|
||||
int isoFileIndex; // for ISO
|
||||
int textureIniIndex; // for textures
|
||||
bool ignoreMetaFiles;
|
||||
std::string contentName;
|
||||
std::string gameTitle; // from PARAM.SFO if available
|
||||
std::string savedataTitle;
|
||||
std::string savedataDetails;
|
||||
std::string savedataDir;
|
||||
std::string mTime;
|
||||
s64 totalFileSize;
|
||||
|
||||
std::string contentName;
|
||||
};
|
||||
|
||||
struct ZipFileTask {
|
||||
|
@ -53,7 +53,7 @@ bool CwCheatScreen::TryLoadCheatInfo() {
|
||||
if (!info->Ready(GameInfoFlags::PARAM_SFO)) {
|
||||
return false;
|
||||
}
|
||||
gameID = info->paramSFO.GetValueString("DISC_ID");
|
||||
gameID = info->GetParamSFO().GetValueString("DISC_ID");
|
||||
if ((info->id.empty() || !info->disc_total)
|
||||
&& gamePath_.FilePathContainsNoCase("PSP/GAME/")) {
|
||||
gameID = g_paramSFO.GenerateFakeID(gamePath_);
|
||||
|
@ -33,6 +33,7 @@
|
||||
#include "Core/FileSystems/ISOFileSystem.h"
|
||||
#include "Core/FileSystems/DirectoryFileSystem.h"
|
||||
#include "Core/FileSystems/VirtualDiscFileSystem.h"
|
||||
#include "Core/HLE/sceUtility.h"
|
||||
#include "Core/ELF/PBPReader.h"
|
||||
#include "Core/SaveState.h"
|
||||
#include "Core/System.h"
|
||||
@ -128,7 +129,7 @@ bool GameInfo::Delete() {
|
||||
}
|
||||
}
|
||||
|
||||
u64 GameInfo::GetGameSizeOnDiskInBytes() {
|
||||
u64 GameInfo::GetSizeOnDiskInBytes() {
|
||||
switch (fileType) {
|
||||
case IdentifiedFileType::PSP_PBP_DIRECTORY:
|
||||
case IdentifiedFileType::PSP_SAVEDATA_DIRECTORY:
|
||||
@ -140,7 +141,7 @@ u64 GameInfo::GetGameSizeOnDiskInBytes() {
|
||||
}
|
||||
}
|
||||
|
||||
u64 GameInfo::GetGameSizeUncompressedInBytes() {
|
||||
u64 GameInfo::GetSizeUncompressedInBytes() {
|
||||
switch (fileType) {
|
||||
case IdentifiedFileType::PSP_PBP_DIRECTORY:
|
||||
case IdentifiedFileType::PSP_SAVEDATA_DIRECTORY:
|
||||
@ -161,6 +162,39 @@ u64 GameInfo::GetGameSizeUncompressedInBytes() {
|
||||
}
|
||||
}
|
||||
|
||||
std::string GetFileDateAsString(const Path &filename) {
|
||||
tm time;
|
||||
if (File::GetModifTime(filename, time)) {
|
||||
char buf[256];
|
||||
switch (g_Config.iDateFormat) {
|
||||
case PSP_SYSTEMPARAM_DATE_FORMAT_YYYYMMDD:
|
||||
strftime(buf, sizeof(buf), "%Y-%m-%d %H:%M:%S", &time);
|
||||
break;
|
||||
case PSP_SYSTEMPARAM_DATE_FORMAT_MMDDYYYY:
|
||||
strftime(buf, sizeof(buf), "%m-%d-%Y %H:%M:%S", &time);
|
||||
break;
|
||||
case PSP_SYSTEMPARAM_DATE_FORMAT_DDMMYYYY:
|
||||
strftime(buf, sizeof(buf), "%d-%m-%Y %H:%M:%S", &time);
|
||||
break;
|
||||
default: // Should never happen
|
||||
return "";
|
||||
}
|
||||
return std::string(buf);
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
std::string GameInfo::GetMTime() const {
|
||||
switch (fileType) {
|
||||
case IdentifiedFileType::PSP_SAVEDATA_DIRECTORY:
|
||||
return GetFileDateAsString(GetFilePath() / "PARAM.SFO");
|
||||
case IdentifiedFileType::PSP_PBP_DIRECTORY:
|
||||
return GetFileDateAsString(GetFilePath() / "EBOOT.PBP");
|
||||
default:
|
||||
return GetFileDateAsString(GetFilePath());
|
||||
}
|
||||
}
|
||||
|
||||
// Not too meaningful if the object itself is a savedata directory...
|
||||
// Call this under lock.
|
||||
std::vector<Path> GameInfo::GetSaveDataDirectories() {
|
||||
@ -183,7 +217,7 @@ std::vector<Path> GameInfo::GetSaveDataDirectories() {
|
||||
return directories;
|
||||
}
|
||||
|
||||
u64 GameInfo::GetSaveDataSizeInBytes() {
|
||||
u64 GameInfo::GetGameSavedataSizeInBytes() {
|
||||
if (fileType == IdentifiedFileType::PSP_SAVEDATA_DIRECTORY || fileType == IdentifiedFileType::PPSSPP_SAVESTATE) {
|
||||
return 0;
|
||||
}
|
||||
@ -466,6 +500,10 @@ public:
|
||||
info_->fileType = Identify_File(info_->GetFileLoader().get(), &errorString);
|
||||
}
|
||||
|
||||
if (!info_->Ready(GameInfoFlags::FILE_TYPE) && !(flags_ & GameInfoFlags::FILE_TYPE)) {
|
||||
_dbg_assert_(false);
|
||||
}
|
||||
|
||||
switch (info_->fileType) {
|
||||
case IdentifiedFileType::PSP_PBP:
|
||||
case IdentifiedFileType::PSP_PBP_DIRECTORY:
|
||||
@ -768,12 +806,24 @@ handleELF:
|
||||
|
||||
if (flags_ & GameInfoFlags::SIZE) {
|
||||
std::lock_guard<std::mutex> lock(info_->lock);
|
||||
info_->gameSizeOnDisk = info_->GetGameSizeOnDiskInBytes();
|
||||
info_->saveDataSize = info_->GetSaveDataSizeInBytes();
|
||||
info_->gameSizeOnDisk = info_->GetSizeOnDiskInBytes();
|
||||
switch (info_->fileType) {
|
||||
case IdentifiedFileType::PSP_ISO:
|
||||
case IdentifiedFileType::PSP_ISO_NP:
|
||||
case IdentifiedFileType::PSP_DISC_DIRECTORY:
|
||||
case IdentifiedFileType::PSP_PBP:
|
||||
case IdentifiedFileType::PSP_PBP_DIRECTORY:
|
||||
info_->saveDataSize = info_->GetGameSavedataSizeInBytes();
|
||||
info_->installDataSize = info_->GetInstallDataSizeInBytes();
|
||||
break;
|
||||
default:
|
||||
info_->saveDataSize = 0;
|
||||
info_->installDataSize = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (flags_ & GameInfoFlags::UNCOMPRESSED_SIZE) {
|
||||
info_->gameSizeUncompressed = info_->GetGameSizeUncompressedInBytes();
|
||||
info_->gameSizeUncompressed = info_->GetSizeUncompressedInBytes();
|
||||
}
|
||||
|
||||
// Time to update the flags.
|
||||
@ -883,6 +933,8 @@ void GameInfoCache::PurgeType(IdentifiedFileType fileType) {
|
||||
std::shared_ptr<GameInfo> GameInfoCache::GetInfo(Draw::DrawContext *draw, const Path &gamePath, GameInfoFlags wantFlags) {
|
||||
const std::string &pathStr = gamePath.ToString();
|
||||
|
||||
// _dbg_assert_(gamePath != GetSysDirectory(DIRECTORY_SAVEDATA));
|
||||
|
||||
// This is always needed to determine the method to get the other info, so make sure it's computed first.
|
||||
wantFlags |= GameInfoFlags::FILE_TYPE;
|
||||
|
||||
|
@ -96,12 +96,20 @@ public:
|
||||
std::shared_ptr<FileLoader> GetFileLoader();
|
||||
void DisposeFileLoader();
|
||||
|
||||
u64 GetGameSizeUncompressedInBytes(); // NOTE: More expensive than GetGameSizeOnDiskInBytes().
|
||||
u64 GetGameSizeOnDiskInBytes();
|
||||
u64 GetSaveDataSizeInBytes();
|
||||
u64 GetSizeUncompressedInBytes(); // NOTE: More expensive than GetGameSizeOnDiskInBytes().
|
||||
u64 GetSizeOnDiskInBytes();
|
||||
u64 GetGameSavedataSizeInBytes(); // For games
|
||||
u64 GetInstallDataSizeInBytes();
|
||||
|
||||
// For various kinds of savedata, mainly.
|
||||
// NOTE: This one actually performs I/O directly, not cached.
|
||||
std::string GetMTime() const;
|
||||
|
||||
void ParseParamSFO();
|
||||
const ParamSFOData &GetParamSFO() const {
|
||||
_dbg_assert_(hasFlags & GameInfoFlags::PARAM_SFO);
|
||||
return paramSFO;
|
||||
}
|
||||
void FinishPendingTextureLoads(Draw::DrawContext *draw);
|
||||
|
||||
std::vector<Path> GetSaveDataDirectories();
|
||||
@ -152,7 +160,6 @@ public:
|
||||
int disc_number = 0;
|
||||
int region = -1;
|
||||
IdentifiedFileType fileType;
|
||||
ParamSFOData paramSFO;
|
||||
bool hasConfig = false;
|
||||
|
||||
// Pre read the data, create a texture the next time (GL thread..)
|
||||
@ -171,6 +178,7 @@ public:
|
||||
u64 installDataSize = 0;
|
||||
|
||||
protected:
|
||||
ParamSFOData paramSFO;
|
||||
// Note: this can change while loading, use GetTitle().
|
||||
std::string title;
|
||||
|
||||
@ -182,6 +190,7 @@ protected:
|
||||
|
||||
private:
|
||||
DISALLOW_COPY_AND_ASSIGN(GameInfo);
|
||||
friend class GameInfoWorkItem;
|
||||
};
|
||||
|
||||
class GameInfoCache {
|
||||
@ -197,6 +206,7 @@ public:
|
||||
// but filled in later asynchronously in the background. So keep calling this,
|
||||
// redrawing the UI often. Only set flags to GAMEINFO_WANTBG or WANTSND if you really want them
|
||||
// because they're big. bgTextures and sound may be discarded over time as well.
|
||||
// NOTE: This never returns null, so you don't need to check for that. Do check Ready() flags though.
|
||||
std::shared_ptr<GameInfo> GetInfo(Draw::DrawContext *draw, const Path &gamePath, GameInfoFlags wantFlags);
|
||||
void FlushBGs(); // Gets rid of all BG textures. Also gets rid of bg sounds.
|
||||
|
||||
|
@ -503,7 +503,7 @@ UI::EventReturn GameScreen::OnPlay(UI::EventParams &e) {
|
||||
UI::EventReturn GameScreen::OnGameSettings(UI::EventParams &e) {
|
||||
std::shared_ptr<GameInfo> info = g_gameInfoCache->GetInfo(NULL, gamePath_, GameInfoFlags::PARAM_SFO);
|
||||
if (info && info->Ready(GameInfoFlags::PARAM_SFO)) {
|
||||
std::string discID = info->paramSFO.GetValueString("DISC_ID");
|
||||
std::string discID = info->GetParamSFO().GetValueString("DISC_ID");
|
||||
if ((discID.empty() || !info->disc_total) && gamePath_.FilePathContainsNoCase("PSP/GAME/"))
|
||||
discID = g_paramSFO.GenerateFakeID(gamePath_);
|
||||
screenManager()->push(new GameSettingsScreen(gamePath_, discID, true));
|
||||
|
@ -21,8 +21,10 @@
|
||||
|
||||
#include "Common/StringUtils.h"
|
||||
#include "Common/Data/Text/I18n.h"
|
||||
#include "Common/Data/Text/Parsers.h"
|
||||
#include "Core/System.h"
|
||||
#include "Core/Util/GameManager.h"
|
||||
#include "Core/Loaders.h"
|
||||
#include "UI/InstallZipScreen.h"
|
||||
#include "UI/MainScreen.h"
|
||||
#include "UI/OnScreenDisplay.h"
|
||||
@ -41,6 +43,7 @@ void InstallZipScreen::CreateViews() {
|
||||
auto di = GetI18NCategory(I18NCat::DIALOG);
|
||||
auto iz = GetI18NCategory(I18NCat::INSTALLZIP);
|
||||
auto er = GetI18NCategory(I18NCat::ERRORS);
|
||||
auto ga = GetI18NCategory(I18NCat::GAME);
|
||||
|
||||
Margins actionMenuMargins(0, 100, 15, 0);
|
||||
|
||||
@ -61,7 +64,7 @@ void InstallZipScreen::CreateViews() {
|
||||
installChoice_ = nullptr;
|
||||
doneView_ = nullptr;
|
||||
installChoice_ = nullptr;
|
||||
|
||||
existingSaveView_ = nullptr;
|
||||
if (z) {
|
||||
DetectZipFileContents(z, &zipFileInfo_); // Even if this fails, it sets zipInfo->contents.
|
||||
if (zipFileInfo_.contents == ZipFileContents::ISO_FILE || zipFileInfo_.contents == ZipFileContents::PSP_GAME_DIR) {
|
||||
@ -69,6 +72,9 @@ void InstallZipScreen::CreateViews() {
|
||||
|
||||
leftColumn->Add(new TextView(question));
|
||||
leftColumn->Add(new TextView(shortFilename));
|
||||
if (!zipFileInfo_.contentName.empty()) {
|
||||
leftColumn->Add(new TextView(zipFileInfo_.contentName));
|
||||
}
|
||||
|
||||
doneView_ = leftColumn->Add(new TextView(""));
|
||||
|
||||
@ -89,15 +95,36 @@ void InstallZipScreen::CreateViews() {
|
||||
|
||||
showDeleteCheckbox = true;
|
||||
} else if (zipFileInfo_.contents == ZipFileContents::SAVE_DATA) {
|
||||
std::string_view question = iz->T("Install savedata?");
|
||||
leftColumn->Add(new TextView(question, ALIGN_LEFT, false, new AnchorLayoutParams(10, 10, NONE, NONE)));
|
||||
leftColumn->Add(new TextView(zipFileInfo_.contentName));
|
||||
std::string_view question = iz->T("Import savedata from ZIP file");
|
||||
leftColumn->Add(new TextView(question))->SetBig(true);
|
||||
leftColumn->Add(new TextView(zipFileInfo_.gameTitle + ": " + zipFileInfo_.savedataDir));
|
||||
|
||||
Path savedataDir = GetSysDirectory(DIRECTORY_SAVEDATA);
|
||||
bool overwrite = !CanExtractWithoutOverwrite(z, savedataDir, 50);
|
||||
|
||||
leftColumn->Add(new NoticeView(NoticeLevel::WARN, di->T("Confirm Overwrite"), ""));
|
||||
|
||||
int columnWidth = 300;
|
||||
|
||||
LinearLayout *compareColumns = leftColumn->Add(new LinearLayout(UI::ORIENT_HORIZONTAL, new LinearLayoutParams(FILL_PARENT, WRAP_CONTENT)));
|
||||
compareColumns->Add(new SavedataView(*screenManager()->getUIContext(), Path(), IdentifiedFileType::PSP_SAVEDATA_DIRECTORY,
|
||||
zipFileInfo_.gameTitle, zipFileInfo_.savedataTitle, zipFileInfo_.savedataDetails, NiceSizeFormat(zipFileInfo_.totalFileSize), zipFileInfo_.mTime, false, new LinearLayoutParams(columnWidth, WRAP_CONTENT)));
|
||||
|
||||
// Check for potential overwrite at destination, and ask the user if it's OK to overwrite.
|
||||
Path saveDir = GetSysDirectory(DIRECTORY_SAVEDATA);
|
||||
if (!CanExtractWithoutOverwrite(z, saveDir, 50)) {
|
||||
leftColumn->Add(new NoticeView(NoticeLevel::WARN, di->T("Confirm Overwrite"), "", new AnchorLayoutParams(10, 60, NONE, NONE)));
|
||||
leftColumn->Add(new SavedataButton(GetSysDirectory(DIRECTORY_SAVEDATA) / zipFileInfo_.savedataDir));
|
||||
if (overwrite) {
|
||||
savedataToOverwrite_ = savedataDir / zipFileInfo_.savedataDir;
|
||||
std::shared_ptr<GameInfo> ginfo = g_gameInfoCache->GetInfo(screenManager()->getDrawContext(), savedataToOverwrite_, GameInfoFlags::FILE_TYPE | GameInfoFlags::PARAM_SFO | GameInfoFlags::ICON | GameInfoFlags::SIZE);
|
||||
|
||||
LinearLayout *rightCompare = new LinearLayout(UI::ORIENT_VERTICAL);
|
||||
rightCompare->Add(new TextView(iz->T("Existing data")));
|
||||
compareColumns->Add(rightCompare);
|
||||
existingSaveView_ = rightCompare->Add(new SavedataView(*screenManager()->getUIContext(), ginfo.get(), IdentifiedFileType::PSP_SAVEDATA_DIRECTORY, false, new LinearLayoutParams(columnWidth, WRAP_CONTENT)));
|
||||
if (System_GetPropertyBool(SYSPROP_CAN_SHOW_FILE)) {
|
||||
rightCompare->Add(new Button(ga->T("Show In Folder")))->OnClick.Add([=](UI::EventParams &) {
|
||||
System_ShowFileInFolder(savedataToOverwrite_);
|
||||
return UI::EVENT_DONE;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
installChoice_ = rightColumnItems->Add(new Choice(iz->T("Install")));
|
||||
@ -166,5 +193,10 @@ void InstallZipScreen::update() {
|
||||
MainScreen::showHomebrewTab = returnToHomebrew_;
|
||||
}
|
||||
}
|
||||
|
||||
if (existingSaveView_) {
|
||||
std::shared_ptr<GameInfo> ginfo = g_gameInfoCache->GetInfo(screenManager()->getDrawContext(), savedataToOverwrite_, GameInfoFlags::FILE_TYPE | GameInfoFlags::PARAM_SFO | GameInfoFlags::ICON | GameInfoFlags::SIZE);
|
||||
existingSaveView_->Update(ginfo.get());
|
||||
}
|
||||
UIScreen::update();
|
||||
}
|
||||
|
@ -24,6 +24,8 @@
|
||||
|
||||
#include "UI/MiscScreens.h"
|
||||
|
||||
class SavedataView;
|
||||
|
||||
class InstallZipScreen : public UIDialogScreenWithBackground {
|
||||
public:
|
||||
InstallZipScreen(const Path &zipPath);
|
||||
@ -41,6 +43,8 @@ private:
|
||||
UI::Choice *installChoice_ = nullptr;
|
||||
UI::Choice *backChoice_ = nullptr;
|
||||
UI::TextView *doneView_ = nullptr;
|
||||
SavedataView *existingSaveView_ = nullptr;
|
||||
Path savedataToOverwrite_;
|
||||
Path zipPath_;
|
||||
ZipFileInfo zipFileInfo_{};
|
||||
bool returnToHomebrew_ = true;
|
||||
|
@ -1544,6 +1544,7 @@ UI::EventReturn MainScreen::OnGameHighlight(UI::EventParams &e) {
|
||||
}
|
||||
|
||||
UI::EventReturn MainScreen::OnGameSelectedInstant(UI::EventParams &e) {
|
||||
// TODO: This is really not necessary here in all cases.
|
||||
g_Config.Save("MainScreen::OnGameSelectedInstant");
|
||||
ScreenManager *screen = screenManager();
|
||||
LaunchFile(screen, Path(e.s));
|
||||
|
@ -23,6 +23,7 @@
|
||||
#include "Common/Data/Encoding/Utf8.h"
|
||||
#include "Common/Data/Text/I18n.h"
|
||||
#include "Common/Math/curves.h"
|
||||
#include "Common/Data/Text/Parsers.h"
|
||||
#include "Common/System/NativeApp.h"
|
||||
#include "Common/System/Request.h"
|
||||
#include "Common/Data/Encoding/Utf8.h"
|
||||
@ -46,85 +47,112 @@
|
||||
|
||||
class SavedataButton;
|
||||
|
||||
std::string GetFileDateAsString(const Path &filename) {
|
||||
tm time;
|
||||
if (File::GetModifTime(filename, time)) {
|
||||
char buf[256];
|
||||
switch (g_Config.iDateFormat) {
|
||||
case PSP_SYSTEMPARAM_DATE_FORMAT_YYYYMMDD:
|
||||
strftime(buf, sizeof(buf), "%Y-%m-%d %H:%M:%S", &time);
|
||||
break;
|
||||
case PSP_SYSTEMPARAM_DATE_FORMAT_MMDDYYYY:
|
||||
strftime(buf, sizeof(buf), "%m-%d-%Y %H:%M:%S", &time);
|
||||
break;
|
||||
case PSP_SYSTEMPARAM_DATE_FORMAT_DDMMYYYY:
|
||||
strftime(buf, sizeof(buf), "%d-%m-%Y %H:%M:%S", &time);
|
||||
break;
|
||||
default: // Should never happen
|
||||
return "";
|
||||
}
|
||||
return std::string(buf);
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
static std::string TrimString(const std::string &str) {
|
||||
size_t pos = str.find_last_not_of(" \r\n\t");
|
||||
if (pos != str.npos) {
|
||||
return str.substr(0, pos + 1);
|
||||
}
|
||||
return str;
|
||||
}
|
||||
|
||||
class SavedataPopupScreen : public PopupScreen {
|
||||
public:
|
||||
SavedataPopupScreen(std::string savePath, std::string title) : PopupScreen(TrimString(title)), savePath_(savePath) { }
|
||||
|
||||
const char *tag() const override { return "SavedataPopup"; }
|
||||
|
||||
void CreatePopupContents(UI::ViewGroup *parent) override {
|
||||
SavedataView::SavedataView(UIContext &dc, const Path &savePath, IdentifiedFileType type, std::string_view title, std::string_view savedataTitle, std::string_view savedataDetail, std::string_view fileSize, std::string_view mtime, bool showIcon, UI::LayoutParams *layoutParams)
|
||||
: LinearLayout(UI::ORIENT_VERTICAL, layoutParams)
|
||||
{
|
||||
using namespace UI;
|
||||
UIContext &dc = *screenManager()->getUIContext();
|
||||
|
||||
const Style &textStyle = dc.theme->popupStyle;
|
||||
|
||||
std::shared_ptr<GameInfo> ginfo = g_gameInfoCache->GetInfo(screenManager()->getDrawContext(), savePath_, GameInfoFlags::PARAM_SFO | GameInfoFlags::ICON | GameInfoFlags::SIZE);
|
||||
if (!ginfo->Ready(GameInfoFlags::PARAM_SFO))
|
||||
return;
|
||||
|
||||
ScrollView *contentScroll = new ScrollView(ORIENT_VERTICAL, new LinearLayoutParams(FILL_PARENT, WRAP_CONTENT, 1.0f, UI::Margins(0, 3)));
|
||||
LinearLayout *content = new LinearLayout(ORIENT_VERTICAL);
|
||||
parent->Add(contentScroll);
|
||||
contentScroll->Add(content);
|
||||
LinearLayout *toprow = new LinearLayout(ORIENT_HORIZONTAL, new LayoutParams(FILL_PARENT, WRAP_CONTENT));
|
||||
content->Add(toprow);
|
||||
Add(toprow);
|
||||
toprow->SetSpacing(0.0);
|
||||
|
||||
if (ginfo->fileType == IdentifiedFileType::PSP_SAVEDATA_DIRECTORY) {
|
||||
std::string savedata_detail = ginfo->paramSFO.GetValueString("SAVEDATA_DETAIL");
|
||||
std::string savedata_title = ginfo->paramSFO.GetValueString("SAVEDATA_TITLE");
|
||||
|
||||
if (ginfo->icon.texture) {
|
||||
toprow->Add(new GameIconView(savePath_, 2.0f, new LinearLayoutParams(Margins(5, 5))));
|
||||
savedataTitle_ = nullptr;
|
||||
fileSize_ = nullptr;
|
||||
mTime_ = nullptr;
|
||||
detail_ = nullptr;
|
||||
if (type == IdentifiedFileType::PSP_SAVEDATA_DIRECTORY) {
|
||||
if (showIcon) {
|
||||
toprow->Add(new GameIconView(savePath, 2.0f, new LinearLayoutParams(Margins(5, 5))));
|
||||
}
|
||||
LinearLayout *topright = new LinearLayout(ORIENT_VERTICAL, new LinearLayoutParams(WRAP_CONTENT, WRAP_CONTENT, 1.0f));
|
||||
topright->SetSpacing(1.0f);
|
||||
topright->Add(new TextView(savedata_title, ALIGN_LEFT | FLAG_WRAP_TEXT, false))->SetTextColor(textStyle.fgColor);
|
||||
topright->Add(new TextView(StringFromFormat("%lld kB", ginfo->gameSizeOnDisk / 1024), 0, true))->SetTextColor(textStyle.fgColor);
|
||||
topright->Add(new TextView(GetFileDateAsString(savePath_ / "PARAM.SFO"), 0, true))->SetTextColor(textStyle.fgColor);
|
||||
savedataTitle_ = topright->Add(new TextView(savedataTitle, ALIGN_LEFT | FLAG_WRAP_TEXT, false));
|
||||
savedataTitle_->SetTextColor(textStyle.fgColor);
|
||||
fileSize_ = topright->Add(new TextView(fileSize, 0, true));
|
||||
fileSize_->SetTextColor(textStyle.fgColor);
|
||||
mTime_ = topright->Add(new TextView(mtime, 0, true));
|
||||
mTime_->SetTextColor(textStyle.fgColor);
|
||||
toprow->Add(topright);
|
||||
content->Add(new Spacer(3.0));
|
||||
content->Add(new TextView(ReplaceAll(savedata_detail, "\r", ""), ALIGN_LEFT | FLAG_WRAP_TEXT, true, new LinearLayoutParams(Margins(10, 0))))->SetTextColor(textStyle.fgColor);
|
||||
content->Add(new Spacer(3.0));
|
||||
Add(new Spacer(3.0));
|
||||
detail_ = Add(new TextView(ReplaceAll(savedataDetail, "\r", ""), ALIGN_LEFT | FLAG_WRAP_TEXT, true, new LinearLayoutParams(Margins(10, 0))));
|
||||
detail_->SetTextColor(textStyle.fgColor);
|
||||
Add(new Spacer(3.0));
|
||||
} else {
|
||||
Path image_path = savePath_.WithReplacedExtension(".ppst", ".jpg");
|
||||
_dbg_assert_(type == IdentifiedFileType::PPSSPP_SAVESTATE);
|
||||
Path image_path = savePath.WithReplacedExtension(".ppst", ".jpg");
|
||||
if (File::Exists(image_path)) {
|
||||
toprow->Add(new AsyncImageFileView(image_path, IS_KEEP_ASPECT, new LinearLayoutParams(480, 272, Margins(10, 0))));
|
||||
} else {
|
||||
auto sa = GetI18NCategory(I18NCat::SAVEDATA);
|
||||
toprow->Add(new TextView(sa->T("No screenshot"), new LinearLayoutParams(Margins(10, 5))))->SetTextColor(textStyle.fgColor);
|
||||
}
|
||||
content->Add(new TextView(GetFileDateAsString(savePath_), 0, true, new LinearLayoutParams(Margins(10, 5))))->SetTextColor(textStyle.fgColor);
|
||||
mTime_ = Add(new TextView(mtime, 0, true, new LinearLayoutParams(Margins(10, 5))));
|
||||
mTime_->SetTextColor(textStyle.fgColor);
|
||||
}
|
||||
}
|
||||
|
||||
void SavedataView::Update(GameInfo *ginfo) {
|
||||
if (!ginfo->Ready(GameInfoFlags::PARAM_SFO | GameInfoFlags::SIZE)) {
|
||||
return;
|
||||
}
|
||||
_dbg_assert_(savedataTitle_);
|
||||
if (savedataTitle_) {
|
||||
savedataTitle_->SetText(ginfo->GetParamSFO().GetValueString("SAVEDATA_TITLE"));
|
||||
}
|
||||
if (detail_) {
|
||||
detail_->SetText(ginfo->GetParamSFO().GetValueString("SAVEDATA_DETAIL"));
|
||||
}
|
||||
if (fileSize_) {
|
||||
fileSize_->SetText(NiceSizeFormat(ginfo->gameSizeOnDisk));
|
||||
}
|
||||
if (mTime_) {
|
||||
mTime_->SetText(ginfo->GetMTime());
|
||||
}
|
||||
}
|
||||
|
||||
SavedataView::SavedataView(UIContext &dc, GameInfo *ginfo, IdentifiedFileType type, bool showIcon, UI::LayoutParams *layoutParams)
|
||||
: SavedataView(dc,
|
||||
ginfo->GetFilePath(),
|
||||
type,
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
showIcon,
|
||||
layoutParams) {}
|
||||
|
||||
class SavedataPopupScreen : public PopupScreen {
|
||||
public:
|
||||
SavedataPopupScreen(Path savePath, std::string_view title) : PopupScreen(StripSpaces(title)), savePath_(savePath) { }
|
||||
|
||||
const char *tag() const override { return "SavedataPopup"; }
|
||||
void update() override {
|
||||
std::shared_ptr<GameInfo> ginfo = g_gameInfoCache->GetInfo(screenManager()->getDrawContext(), savePath_, GameInfoFlags::PARAM_SFO | GameInfoFlags::ICON | GameInfoFlags::SIZE);
|
||||
if (!ginfo->Ready(GameInfoFlags::PARAM_SFO)) {
|
||||
// Hm, this is no good. But hopefully the previous screen loaded it.
|
||||
return;
|
||||
}
|
||||
if (savedataView_) {
|
||||
savedataView_->Update(ginfo.get());
|
||||
}
|
||||
}
|
||||
|
||||
void CreatePopupContents(UI::ViewGroup *parent) override {
|
||||
using namespace UI;
|
||||
UIContext &dc = *screenManager()->getUIContext();
|
||||
|
||||
std::shared_ptr<GameInfo> ginfo = g_gameInfoCache->GetInfo(screenManager()->getDrawContext(), savePath_, GameInfoFlags::PARAM_SFO | GameInfoFlags::ICON | GameInfoFlags::SIZE);
|
||||
if (!ginfo->Ready(GameInfoFlags::PARAM_SFO)) {
|
||||
// This is OK, handled in Update. Though most likely, the previous screen loaded it.
|
||||
}
|
||||
|
||||
ScrollView *contentScroll = new ScrollView(ORIENT_VERTICAL, new LinearLayoutParams(FILL_PARENT, WRAP_CONTENT, 1.0f, UI::Margins(0, 3)));
|
||||
parent->Add(contentScroll);
|
||||
|
||||
// TODO: If the game info wasn't already loaded, we'll get a bogus fileType here.
|
||||
savedataView_ = contentScroll->Add(new SavedataView(dc, ginfo.get(), ginfo->fileType, true));
|
||||
|
||||
auto di = GetI18NCategory(I18NCat::DIALOG);
|
||||
LinearLayout *buttons = new LinearLayout(ORIENT_HORIZONTAL, new LinearLayoutParams(FILL_PARENT, WRAP_CONTENT));
|
||||
@ -141,6 +169,7 @@ protected:
|
||||
|
||||
private:
|
||||
UI::EventReturn OnDeleteButtonClick(UI::EventParams &e);
|
||||
SavedataView *savedataView_ = nullptr;
|
||||
Path savePath_;
|
||||
};
|
||||
|
||||
@ -244,14 +273,15 @@ bool SavedataButton::UpdateText() {
|
||||
}
|
||||
|
||||
void SavedataButton::UpdateText(const std::shared_ptr<GameInfo> &ginfo) {
|
||||
_dbg_assert_(ginfo->Ready(GameInfoFlags::PARAM_SFO));
|
||||
const std::string currentTitle = ginfo->GetTitle();
|
||||
if (!currentTitle.empty()) {
|
||||
title_ = CleanSaveString(currentTitle);
|
||||
}
|
||||
if (subtitle_.empty() && ginfo->gameSizeOnDisk > 0) {
|
||||
std::string date = GetFileDateAsString(ginfo->GetFilePath() / "PARAM.SFO");
|
||||
std::string savedata_title = ginfo->paramSFO.GetValueString("SAVEDATA_TITLE");
|
||||
subtitle_ = CleanSaveString(savedata_title) + StringFromFormat(" (%lld kB, %s)", ginfo->gameSizeOnDisk / 1024, date.c_str());
|
||||
std::string date = ginfo->GetMTime();
|
||||
std::string savedata_title = ginfo->GetParamSFO().GetValueString("SAVEDATA_TITLE");
|
||||
subtitle_ = CleanSaveString(savedata_title) + " (" + NiceSizeFormat(ginfo->gameSizeOnDisk) + ", " + date.c_str() + ")";
|
||||
}
|
||||
}
|
||||
|
||||
@ -648,7 +678,7 @@ UI::EventReturn SavedataScreen::OnSavedataButtonClick(UI::EventParams &e) {
|
||||
if (!ginfo->Ready(GameInfoFlags::PARAM_SFO)) {
|
||||
return UI::EVENT_DONE;
|
||||
}
|
||||
SavedataPopupScreen *popupScreen = new SavedataPopupScreen(e.s, ginfo->GetTitle());
|
||||
SavedataPopupScreen *popupScreen = new SavedataPopupScreen(Path(e.s), ginfo->GetTitle());
|
||||
if (e.v) {
|
||||
popupScreen->SetPopupOrigin(e.v);
|
||||
}
|
||||
|
@ -145,3 +145,17 @@ private:
|
||||
bool hasDateSeconds_ = false;
|
||||
};
|
||||
|
||||
// View used for the detailed popup, and also in the import savedata comparison.
|
||||
// It doesn't do its own data loading for that reason.
|
||||
class SavedataView : public UI::LinearLayout {
|
||||
public:
|
||||
SavedataView(UIContext &dc, GameInfo *ginfo, IdentifiedFileType type, bool showIcon, UI::LayoutParams *layoutParams = nullptr);
|
||||
SavedataView(UIContext &dc, const Path &savePath, IdentifiedFileType type, std::string_view title, std::string_view savedataTitle, std::string_view savedataDetail, std::string_view fileSize, std::string_view mtime, bool showIcon, UI::LayoutParams *layoutParams = nullptr);
|
||||
|
||||
void Update(GameInfo *ginfo);
|
||||
private:
|
||||
UI::TextView *savedataTitle_ = nullptr;
|
||||
UI::TextView *detail_ = nullptr;
|
||||
UI::TextView *mTime_ = nullptr;
|
||||
UI::TextView *fileSize_ = nullptr;
|
||||
};
|
||||
|
Loading…
Reference in New Issue
Block a user