diff --git a/UI/SavedataScreen.cpp b/UI/SavedataScreen.cpp index 9e76cfda43..ee5fe99b32 100644 --- a/UI/SavedataScreen.cpp +++ b/UI/SavedataScreen.cpp @@ -67,6 +67,19 @@ static void AddFolderToZip(const Path &folder, const std::string &nameInZip, std } } +// The save folders of a game next to a save of it, without installed data. +static std::vector FindGameSaves(const Path &saveDir, std::string_view gameID) { + std::vector saves; + std::vector dirs; + File::GetFilesInDir(saveDir, &dirs); + for (const File::FileInfo &dir : dirs) { + if (dir.isDirectory && startsWith(dir.name, gameID) && File::Exists(dir.fullName / "PARAM.SFO") && !IsInstalledGameData(dir.fullName)) { + saves.push_back(dir.fullName); + } + } + return saves; +} + static void ExportAsZip(std::string_view zipName, const std::vector &entries) { if (!ShareFilesAsZip(zipName, entries)) { auto sa = GetI18NCategory(I18NCat::SAVEDATA); @@ -207,6 +220,21 @@ void SavedataPopupScreen::CreatePopupContents(UI::ViewGroup *parent) { } } + if (canExport && !isState && ginfo->Ready(GameInfoFlags::PARAM_SFO) && ginfo->id.size() >= 5) { + // The game ID starts the folder names (the same rule as GetSaveDataDirectories()). + std::vector gameSaves = FindGameSaves(savePath_.NavigateUp(), ginfo->id); + if (gameSaves.size() > 1) { + std::string zipName = ginfo->GetTitle() + " (" + ginfo->id + ")"; + content->Add(new Choice(sa->T("Export all saves for this game"), ImageID("I_SHARE"), new LinearLayoutParams(FILL_PARENT, WRAP_CONTENT)))->OnClick.Add([gameSaves, zipName](UI::EventParams &e) { + std::vector entries; + for (const Path &dir : gameSaves) { + AddFolderToZip(dir, dir.GetFilename(), &entries); + } + ExportAsZip(zipName, entries); + }); + } + } + LinearLayout *buttonRow = new LinearLayout(ORIENT_HORIZONTAL, new LinearLayoutParams(FILL_PARENT, WRAP_CONTENT)); buttonRow->SetSpacing(12); @@ -762,8 +790,6 @@ void SavedataScreen::CreateSavestateTab(UI::ViewGroup *savestate) { bool SavedataScreen::LookUpGame() { gameID_.clear(); - gameTitle_.clear(); - gameSaveDirs_.clear(); if (gamePath_.empty()) { return true; } @@ -778,13 +804,6 @@ bool SavedataScreen::LookUpGame() { return true; } gameID_ = ginfo->id; - gameTitle_ = ginfo->GetTitle(); - for (const Path &dir : ginfo->GetSaveDataDirectories()) { - // The folders the browser lists, without installed data. - if (File::Exists(dir / "PARAM.SFO") && !IsInstalledGameData(dir)) { - gameSaveDirs_.push_back(dir); - } - } return true; } @@ -814,12 +833,6 @@ void SavedataScreen::CreateTabs() { void SavedataScreen::CreateExtraButtons(UI::ViewGroup *verticalLayout, int margins) { using namespace UI; - if (!gameSaveDirs_.empty() && CanShareFiles()) { - auto sa = GetI18NCategory(I18NCat::SAVEDATA); - Choice *exportButton = verticalLayout->Add(new Choice(sa->T("Export all saves for this game"), ImageID("I_SHARE"), new LinearLayoutParams(FILL_PARENT, WRAP_CONTENT, 0.0f, Margins(0, 0, margins, margins)))); - exportButton->OnClick.Handle(this, &SavedataScreen::OnExportGameSaves); - exportButton->SetRoundCorners(); - } if (System_GetPropertyBool(SYSPROP_HAS_TEXT_INPUT_DIALOG)) { auto di = GetI18NCategory(I18NCat::DIALOG); Choice *searchButton = verticalLayout->Add(new Choice(di->T("Search"), ImageID("I_SEARCH"), new LinearLayoutParams(FILL_PARENT, WRAP_CONTENT, 0.0f, Margins(0, 0, margins, margins)))); @@ -837,14 +850,6 @@ void SavedataScreen::OnSearch(UI::EventParams &e) { } } -void SavedataScreen::OnExportGameSaves(UI::EventParams &e) { - std::vector entries; - for (const Path &dir : gameSaveDirs_) { - AddFolderToZip(dir, dir.GetFilename(), &entries); - } - ExportAsZip(gameTitle_ + " (" + gameID_ + ")", entries); -} - void SavedataScreen::OnSavedataButtonClick(UI::EventParams &e) { // the game path: e.s; std::shared_ptr ginfo = g_gameInfoCache->GetInfo(screenManager()->getDrawContext(), Path(e.s), GameInfoFlags::PARAM_SFO); diff --git a/UI/SavedataScreen.h b/UI/SavedataScreen.h index 6f777077dd..aeef0ee4d1 100644 --- a/UI/SavedataScreen.h +++ b/UI/SavedataScreen.h @@ -118,16 +118,13 @@ protected: private: void OnSavedataButtonClick(UI::EventParams &e); void OnSearch(UI::EventParams &e); - void OnExportGameSaves(UI::EventParams &e); void CreateSavedataTab(UI::ViewGroup *savedata); void CreateSavestateTab(UI::ViewGroup *savestate); - // The ID and title of the game the screen was opened for, once its PARAM.SFO is loaded. + // The ID of the game the screen was opened for (its saves are highlighted), once its PARAM.SFO is loaded. bool LookUpGame(); std::string gameID_; - std::string gameTitle_; - std::vector gameSaveDirs_; // The game's saves, without installed data. bool gameLookupPending_ = false; SavedataSortOption sortOption_ = SavedataSortOption::FILENAME; SavedataBrowser *dataBrowser_ = nullptr;