mirror of
https://github.com/hrydgard/ppsspp.git
synced 2025-04-02 11:01:50 -04:00
When changing the PSP folder, move the files in a nice background process, showing progress.
Not everything is properly refreshed after the move though - for example the main screen needs a refresh.
This commit is contained in:
parent
80fc09a222
commit
4aef413c13
2 changed files with 173 additions and 69 deletions
|
@ -36,6 +36,8 @@
|
|||
#include "Common/File/Path.h"
|
||||
#include "Common/File/DiskFree.h"
|
||||
|
||||
#include "Common/Thread/ThreadManager.h"
|
||||
|
||||
#include "Core/Util/GameManager.h"
|
||||
#include "Core/System.h"
|
||||
#include "Core/Config.h"
|
||||
|
@ -236,6 +238,14 @@ ConfirmMemstickMoveScreen::ConfirmMemstickMoveScreen(Path newMemstickFolder, boo
|
|||
}
|
||||
}
|
||||
|
||||
ConfirmMemstickMoveScreen::~ConfirmMemstickMoveScreen() {
|
||||
if (moveDataTask_) {
|
||||
INFO_LOG(SYSTEM, "Move Data task still running, blocking on it");
|
||||
moveDataTask_->BlockUntilReady();
|
||||
delete moveDataTask_;
|
||||
}
|
||||
}
|
||||
|
||||
void ConfirmMemstickMoveScreen::CreateViews() {
|
||||
using namespace UI;
|
||||
auto di = GetI18NCategory("Dialog");
|
||||
|
@ -276,14 +286,50 @@ void ConfirmMemstickMoveScreen::CreateViews() {
|
|||
rightColumn->Add(new TextView(oldFreeSpaceText, ALIGN_LEFT, false));
|
||||
}
|
||||
|
||||
if (!initialSetup_) {
|
||||
leftColumn->Add(new CheckBox(&moveData_, iz->T("Move Data")));
|
||||
if (moveDataTask_) {
|
||||
progressView_ = leftColumn->Add(new TextView(progressReporter_.Get()));
|
||||
} else {
|
||||
progressView_ = nullptr;
|
||||
}
|
||||
|
||||
leftColumn->Add(new Choice(di->T("OK")))->OnClick.Handle(this, &ConfirmMemstickMoveScreen::OnConfirm);
|
||||
leftColumn->Add(new Choice(di->T("Back")))->OnClick.Handle<UIScreen>(this, &UIScreen::OnBack);
|
||||
if (!moveDataTask_) {
|
||||
if (!initialSetup_) {
|
||||
leftColumn->Add(new CheckBox(&moveData_, iz->T("Move Data")));
|
||||
}
|
||||
|
||||
leftColumn->Add(new Choice(di->T("OK")))->OnClick.Handle(this, &ConfirmMemstickMoveScreen::OnConfirm);
|
||||
leftColumn->Add(new Choice(di->T("Back")))->OnClick.Handle<UIScreen>(this, &UIScreen::OnBack);
|
||||
}
|
||||
}
|
||||
|
||||
void ConfirmMemstickMoveScreen::update() {
|
||||
UIDialogScreenWithBackground::update();
|
||||
|
||||
if (moveDataTask_) {
|
||||
if (progressView_) {
|
||||
progressView_->SetText(progressReporter_.Get());
|
||||
}
|
||||
|
||||
bool *result = moveDataTask_->Poll();
|
||||
|
||||
if (result) {
|
||||
if (*result) {
|
||||
progressReporter_.Set("Done!");
|
||||
INFO_LOG(SYSTEM, "Move data task finished successfully!");
|
||||
// Succeeded!
|
||||
FinishFolderMove();
|
||||
} else {
|
||||
INFO_LOG(SYSTEM, "Move data task failed!");
|
||||
// What do we do here? We might be in the middle of a move... Bad.
|
||||
RecreateViews();
|
||||
}
|
||||
delete moveDataTask_;
|
||||
moveDataTask_ = nullptr;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
UI::EventReturn ConfirmMemstickMoveScreen::OnConfirm(UI::EventParams ¶ms) {
|
||||
auto sy = GetI18NCategory("System");
|
||||
auto iz = GetI18NCategory("MemStick");
|
||||
|
@ -294,81 +340,113 @@ UI::EventReturn ConfirmMemstickMoveScreen::OnConfirm(UI::EventParams ¶ms) {
|
|||
// If the directory itself is called PSP, don't go below.
|
||||
|
||||
if (moveData_) {
|
||||
Path moveSrc = g_Config.memStickDirectory;
|
||||
Path moveDest = newMemstickFolder_;
|
||||
if (moveSrc.GetFilename() != "PSP") {
|
||||
moveSrc = moveSrc / "PSP";
|
||||
}
|
||||
if (moveDest.GetFilename() != "PSP") {
|
||||
moveDest = moveDest / "PSP";
|
||||
File::CreateDir(moveDest);
|
||||
}
|
||||
progressReporter_.Set("Starting move...");
|
||||
|
||||
INFO_LOG(SYSTEM, "About to move PSP data from '%s' to '%s'", moveSrc.c_str(), moveDest.c_str());
|
||||
|
||||
// Search through recursively, listing the files to move and also summing their sizes.
|
||||
std::vector<std::string> fileSuffixesToMove;
|
||||
std::vector<std::string> directorySuffixesToCreate;
|
||||
|
||||
// NOTE: It's correct to pass moveSrc twice here, it's to keep the root in the recursion.
|
||||
if (!ListFileSuffixesRecursively(moveSrc, moveSrc, directorySuffixesToCreate, fileSuffixesToMove)) {
|
||||
// TODO: Handle failure listing files.
|
||||
error_ = "Failed to read old directory";
|
||||
INFO_LOG(SYSTEM, "%s", error_.c_str());
|
||||
return UI::EVENT_DONE;
|
||||
}
|
||||
|
||||
bool dryRun = false; // Useful for debugging.
|
||||
|
||||
size_t moveFailures = 0;
|
||||
|
||||
if (!moveSrc.empty()) {
|
||||
// Better not interrupt the app while this is happening!
|
||||
|
||||
// Create all the necessary directories.
|
||||
for (auto &dirSuffix : directorySuffixesToCreate) {
|
||||
Path dir = moveDest / dirSuffix;
|
||||
if (dryRun) {
|
||||
INFO_LOG(SYSTEM, "dry run: Would have created dir '%s'", dir.c_str());
|
||||
} else {
|
||||
INFO_LOG(SYSTEM, "Creating dir '%s'", dir.c_str());
|
||||
if (!File::Exists(dir)) {
|
||||
File::CreateDir(dir);
|
||||
}
|
||||
}
|
||||
moveDataTask_ = Promise<bool>::Spawn(&g_threadManager, [&]() -> bool * {
|
||||
Path moveSrc = g_Config.memStickDirectory;
|
||||
Path moveDest = newMemstickFolder_;
|
||||
if (moveSrc.GetFilename() != "PSP") {
|
||||
moveSrc = moveSrc / "PSP";
|
||||
}
|
||||
if (moveDest.GetFilename() != "PSP") {
|
||||
moveDest = moveDest / "PSP";
|
||||
File::CreateDir(moveDest);
|
||||
}
|
||||
|
||||
for (auto &fileSuffix : fileSuffixesToMove) {
|
||||
Path from = moveSrc / fileSuffix;
|
||||
Path to = moveDest / fileSuffix;
|
||||
if (dryRun) {
|
||||
INFO_LOG(SYSTEM, "dry run: Would have moved '%s' to '%s'", from.c_str(), to.c_str());
|
||||
} else {
|
||||
// Remove the "from" prefix from the path.
|
||||
// We have to drop down to string operations for this.
|
||||
if (!File::Move(from, to)) {
|
||||
ERROR_LOG(SYSTEM, "Failed to move file '%s' to '%s'", from.c_str(), to.c_str());
|
||||
moveFailures++;
|
||||
// Should probably just bail?
|
||||
INFO_LOG(SYSTEM, "About to move PSP data from '%s' to '%s'", moveSrc.c_str(), moveDest.c_str());
|
||||
|
||||
// Search through recursively, listing the files to move and also summing their sizes.
|
||||
std::vector<std::string> fileSuffixesToMove;
|
||||
std::vector<std::string> directorySuffixesToCreate;
|
||||
|
||||
// NOTE: It's correct to pass moveSrc twice here, it's to keep the root in the recursion.
|
||||
if (!ListFileSuffixesRecursively(moveSrc, moveSrc, directorySuffixesToCreate, fileSuffixesToMove)) {
|
||||
// TODO: Handle failure listing files.
|
||||
std::string error = "Failed to read old directory";
|
||||
INFO_LOG(SYSTEM, "%s", error.c_str());
|
||||
progressReporter_.Set(error);
|
||||
return new bool(false);
|
||||
}
|
||||
|
||||
bool dryRun = false; // Useful for debugging.
|
||||
|
||||
size_t moveFailures = 0;
|
||||
|
||||
if (!moveSrc.empty()) {
|
||||
// Better not interrupt the app while this is happening!
|
||||
|
||||
// Create all the necessary directories.
|
||||
for (auto &dirSuffix : directorySuffixesToCreate) {
|
||||
Path dir = moveDest / dirSuffix;
|
||||
if (dryRun) {
|
||||
INFO_LOG(SYSTEM, "dry run: Would have created dir '%s'", dir.c_str());
|
||||
} else {
|
||||
INFO_LOG(SYSTEM, "Moved file '%s' to '%s'", from.c_str(), to.c_str());
|
||||
INFO_LOG(SYSTEM, "Creating dir '%s'", dir.c_str());
|
||||
if (!File::Exists(dir)) {
|
||||
File::CreateDir(dir);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (auto &fileSuffix : fileSuffixesToMove) {
|
||||
progressReporter_.Set(fileSuffix);
|
||||
|
||||
Path from = moveSrc / fileSuffix;
|
||||
Path to = moveDest / fileSuffix;
|
||||
if (dryRun) {
|
||||
INFO_LOG(SYSTEM, "dry run: Would have moved '%s' to '%s'", from.c_str(), to.c_str());
|
||||
} else {
|
||||
// Remove the "from" prefix from the path.
|
||||
// We have to drop down to string operations for this.
|
||||
if (!File::Move(from, to)) {
|
||||
ERROR_LOG(SYSTEM, "Failed to move file '%s' to '%s'", from.c_str(), to.c_str());
|
||||
moveFailures++;
|
||||
// Should probably just bail?
|
||||
} else {
|
||||
INFO_LOG(SYSTEM, "Moved file '%s' to '%s'", from.c_str(), to.c_str());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Delete all the old, now hopefully empty, directories.
|
||||
for (auto &dirSuffix : directorySuffixesToCreate) {
|
||||
Path dir = moveSrc / dirSuffix;
|
||||
if (dryRun) {
|
||||
INFO_LOG(SYSTEM, "dry run: Would have deleted dir '%s'", dir.c_str());
|
||||
} else {
|
||||
INFO_LOG(SYSTEM, "Deleting dir '%s'", dir.c_str());
|
||||
if (!File::Exists(dir)) {
|
||||
File::DeleteDir(dir);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (moveFailures > 0) {
|
||||
error_ = "Failed to move some files!";
|
||||
RecreateViews();
|
||||
return UI::EVENT_DONE;
|
||||
}
|
||||
if (moveFailures > 0) {
|
||||
std::string error = "Failed to move some files!";
|
||||
progressReporter_.Set(error);
|
||||
return new bool(false);
|
||||
}
|
||||
|
||||
return new bool(true);
|
||||
}, TaskType::IO_BLOCKING);
|
||||
|
||||
RecreateViews();
|
||||
} else {
|
||||
FinishFolderMove();
|
||||
}
|
||||
|
||||
return UI::EVENT_DONE;
|
||||
}
|
||||
|
||||
void ConfirmMemstickMoveScreen::FinishFolderMove() {
|
||||
auto iz = GetI18NCategory("MemStick");
|
||||
|
||||
// Successful so far, switch the memstick folder.
|
||||
if (!SwitchMemstickFolderTo(newMemstickFolder_)) {
|
||||
// TODO: More precise errors.
|
||||
error_ = iz->T("That folder doesn't work as a memstick folder.");
|
||||
return UI::EVENT_DONE;
|
||||
return;
|
||||
}
|
||||
|
||||
// If the chosen folder already had a config, reload it!
|
||||
|
@ -380,6 +458,4 @@ UI::EventReturn ConfirmMemstickMoveScreen::OnConfirm(UI::EventParams ¶ms) {
|
|||
error_ = iz->T("Failed to save config");
|
||||
RecreateViews();
|
||||
}
|
||||
|
||||
return UI::EVENT_DONE;
|
||||
}
|
||||
|
|
|
@ -19,12 +19,15 @@
|
|||
|
||||
#include <functional>
|
||||
#include <string>
|
||||
#include <atomic>
|
||||
|
||||
#include "ppsspp_config.h"
|
||||
|
||||
#include "Common/File/Path.h"
|
||||
#include "UI/MiscScreens.h"
|
||||
#include "Common/UI/UIScreen.h"
|
||||
#include "Common/Thread/Promise.h"
|
||||
|
||||
#include "UI/MiscScreens.h"
|
||||
|
||||
// MemStickScreen - let's you configure your memory stick directory.
|
||||
// Currently only useful for Android.
|
||||
|
@ -64,14 +67,34 @@ private:
|
|||
bool done_ = false;
|
||||
};
|
||||
|
||||
class ProgressReporter {
|
||||
public:
|
||||
void Set(std::string value) {
|
||||
std::lock_guard<std::mutex> guard(mutex_);
|
||||
progress_ = value;
|
||||
}
|
||||
|
||||
std::string Get() {
|
||||
std::lock_guard<std::mutex> guard(mutex_);
|
||||
return progress_;
|
||||
}
|
||||
|
||||
private:
|
||||
std::string progress_;
|
||||
std::mutex mutex_;
|
||||
};
|
||||
|
||||
class ConfirmMemstickMoveScreen : public UIDialogScreenWithBackground {
|
||||
public:
|
||||
ConfirmMemstickMoveScreen(Path newMemstickFolder, bool initialSetup);
|
||||
|
||||
~ConfirmMemstickMoveScreen();
|
||||
protected:
|
||||
void update() override;
|
||||
void CreateViews() override;
|
||||
|
||||
private:
|
||||
void FinishFolderMove();
|
||||
|
||||
UI::EventReturn OnConfirm(UI::EventParams ¶ms);
|
||||
|
||||
Path newMemstickFolder_;
|
||||
|
@ -79,5 +102,10 @@ private:
|
|||
bool moveData_ = true;
|
||||
bool initialSetup_;
|
||||
|
||||
ProgressReporter progressReporter_;
|
||||
UI::TextView *progressView_ = nullptr;
|
||||
|
||||
Promise<bool> *moveDataTask_ = nullptr;
|
||||
|
||||
std::string error_;
|
||||
};
|
||||
|
|
Loading…
Add table
Reference in a new issue