mirror of
https://github.com/hrydgard/ppsspp.git
synced 2026-11-01 03:57:17 +01:00
GameManager translated install errors when storing them, and the install screens then looked the translated text up again as a key. It now stores the category and key, and translates when asked. The raw ISO install error gets the existing "Installation failed" string. Some other errors went around as strings that were then used as keys: - A missing savestate file now has its own error code, ERROR_FILE_MISSING, instead of a key in the failure reason. - The PKG reader's reasons are technical English, so they're now shown untranslated under the translated "This PKG file isn't a PSP game update". - The netconf dialog looked up the channel number. Only "Auto" is translated now, using the WLAN Channel setting's string. - Adds the missing "Failed to read old directory" for memstick moves. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
192 lines
6.6 KiB
C++
192 lines
6.6 KiB
C++
// Copyright (c) 2026- 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 <memory>
|
|
|
|
#include "Common/Data/Text/I18n.h"
|
|
#include "Common/Data/Text/Parsers.h"
|
|
#include "Common/File/DiskFree.h"
|
|
#include "Common/File/FileUtil.h"
|
|
#include "Common/StringUtils.h"
|
|
#include "Common/System/Request.h"
|
|
#include "Common/System/System.h"
|
|
#include "Common/UI/Context.h"
|
|
#include "Common/UI/UI.h"
|
|
#include "Common/UI/View.h"
|
|
#include "Common/UI/ViewGroup.h"
|
|
|
|
#include "Core/Loaders.h"
|
|
#include "Core/System.h"
|
|
#include "Core/Util/GameManager.h"
|
|
#include "Core/Util/PathUtil.h"
|
|
|
|
#include "UI/InstallPkgScreen.h"
|
|
|
|
InstallPkgScreen::InstallPkgScreen(const Path &pkgPath)
|
|
: UITwoPaneBaseDialogScreen(Path(), TwoPaneFlags::SettingsToTheRight | TwoPaneFlags::ContentsCanScroll), pkgPath_(pkgPath) {
|
|
g_GameManager.ResetInstallError();
|
|
|
|
// Reading the package is cheap - the item table and two small PARAM.SFOs. We only keep the
|
|
// info; the install re-opens the file on its own thread.
|
|
std::unique_ptr<FileLoader> loader(ConstructFileLoader(pkgPath_));
|
|
PkgReader reader;
|
|
if (!loader || !reader.Open(loader.get(), &pkgError_)) {
|
|
return;
|
|
}
|
|
pkgInfo_ = reader.Info();
|
|
if (!pkgInfo_.isGameUpdate) {
|
|
// Everything we can read is a game update; anything else got rejected above with a reason.
|
|
return;
|
|
}
|
|
|
|
canInstall_ = true;
|
|
installSize_ = PkgInstalledSize(pkgInfo_);
|
|
destination_ = GetSysDirectory(DIRECTORY_GAME) / pkgInfo_.discId;
|
|
alreadyInstalled_ = File::Exists(destination_ / "PBOOT.PBP");
|
|
|
|
int64_t space = 0;
|
|
if (free_disk_space(GetSysDirectory(DIRECTORY_GAME), space)) {
|
|
freeSpace_ = space;
|
|
}
|
|
}
|
|
|
|
std::string_view InstallPkgScreen::GetTitle() const {
|
|
auto iz = GetI18NCategory(I18NCat::INSTALLZIP);
|
|
return iz->T("Game update");
|
|
}
|
|
|
|
void InstallPkgScreen::CreateSettingsViews(UI::ViewGroup *parent) {
|
|
using namespace UI;
|
|
|
|
auto di = GetI18NCategory(I18NCat::DIALOG);
|
|
auto iz = GetI18NCategory(I18NCat::INSTALLZIP);
|
|
|
|
installChoice_ = nullptr;
|
|
|
|
if (canInstall_) {
|
|
installChoice_ = parent->Add(new Choice(iz->T("Install"), ImageID("I_FOLDER_UPLOAD")));
|
|
installChoice_->OnClick.Handle(this, &InstallPkgScreen::OnInstall);
|
|
}
|
|
|
|
if (System_GetPropertyBool(SYSPROP_CAN_SHOW_FILE)) {
|
|
parent->Add(new Spacer(12.0f));
|
|
parent->Add(new Choice(di->T("Show in folder")))->OnClick.Add([this](UI::EventParams &) {
|
|
System_ShowFileInFolder(pkgPath_);
|
|
});
|
|
}
|
|
|
|
if (canInstall_) {
|
|
parent->Add(new Spacer(12.0f));
|
|
parent->Add(new CheckBox(&deletePkgFile_, iz->T("Delete PKG file")));
|
|
}
|
|
}
|
|
|
|
void InstallPkgScreen::CreateContentViews(UI::ViewGroup *parent) {
|
|
using namespace UI;
|
|
|
|
auto di = GetI18NCategory(I18NCat::DIALOG);
|
|
auto iz = GetI18NCategory(I18NCat::INSTALLZIP);
|
|
auto er = GetI18NCategory(I18NCat::ERRORS);
|
|
|
|
LinearLayout *leftColumn = parent->Add(new LinearLayout(ORIENT_VERTICAL, new LinearLayoutParams(FILL_PARENT, WRAP_CONTENT, Margins(8))));
|
|
|
|
if (!canInstall_) {
|
|
leftColumn->Add(new TextView(GetFriendlyPath(pkgPath_)));
|
|
leftColumn->Add(new NoticeView(NoticeLevel::ERROR, iz->T("This PKG file isn't a PSP game update"), pkgError_));
|
|
doneView_ = leftColumn->Add(new NoticeView(NoticeLevel::SUCCESS, "", ""));
|
|
doneView_->SetVisibility(Visibility::V_GONE);
|
|
return;
|
|
}
|
|
|
|
leftColumn->Add(new TextView(iz->T("Install game update?")))->SetBig(true);
|
|
leftColumn->Add(new TextView(pkgPath_.GetFilename()));
|
|
if (!pkgInfo_.title.empty()) {
|
|
leftColumn->Add(new TextView(pkgInfo_.title));
|
|
}
|
|
if (!pkgInfo_.pbootTitle.empty()) {
|
|
leftColumn->Add(new TextView(pkgInfo_.pbootTitle));
|
|
}
|
|
|
|
leftColumn->Add(new Spacer(8.0f));
|
|
|
|
// What it patches, and to what. The disc version is the one the update was built against.
|
|
leftColumn->Add(new TextView(ApplySafeSubstitutions("%1: %2 (%3)", iz->T("Game"), pkgInfo_.discId, pkgInfo_.discVersion)));
|
|
if (!pkgInfo_.appVer.empty()) {
|
|
leftColumn->Add(new TextView(ApplySafeSubstitutions("%1: %2", iz->T("Update version"), pkgInfo_.appVer)));
|
|
}
|
|
if (!pkgInfo_.systemVer.empty()) {
|
|
leftColumn->Add(new TextView(ApplySafeSubstitutions("%1: %2", iz->T("Requires firmware"), pkgInfo_.systemVer)));
|
|
}
|
|
|
|
// Package contents aren't compressed, so this is what it'll actually take up.
|
|
leftColumn->Add(new TextView(ApplySafeSubstitutions("%1: %2", iz->T("Space needed"), NiceSizeFormat(installSize_))));
|
|
if (freeSpace_ >= 0) {
|
|
leftColumn->Add(new TextView(ApplySafeSubstitutions("%1: %2", iz->T("Free space"), NiceSizeFormat((u64)freeSpace_))));
|
|
}
|
|
|
|
leftColumn->Add(new Spacer(8.0f));
|
|
leftColumn->Add(new TextView(iz->T("Install into folder")));
|
|
leftColumn->Add(new TextView(GetFriendlyPath(destination_)))->SetAlign(FLAG_WRAP_TEXT);
|
|
|
|
doneView_ = leftColumn->Add(new NoticeView(NoticeLevel::SUCCESS, "", ""));
|
|
doneView_->SetVisibility(Visibility::V_GONE);
|
|
|
|
if (freeSpace_ >= 0 && (u64)freeSpace_ < installSize_) {
|
|
leftColumn->Add(new NoticeView(NoticeLevel::ERROR, er->T("Not enough free space"), ""));
|
|
}
|
|
if (alreadyInstalled_) {
|
|
leftColumn->Add(new NoticeView(NoticeLevel::WARN, di->T("Confirm Overwrite"), iz->T("An update for this game is already installed")));
|
|
}
|
|
}
|
|
|
|
bool InstallPkgScreen::key(const KeyInput &key) {
|
|
// Ignore key presses while installing, so the user can't escape mid-write.
|
|
if (g_GameManager.GetState() == GameManagerState::IDLE) {
|
|
return UIDialogScreen::key(key);
|
|
}
|
|
return false;
|
|
}
|
|
|
|
void InstallPkgScreen::OnInstall(UI::EventParams ¶ms) {
|
|
if (!canInstall_) {
|
|
return;
|
|
}
|
|
if (g_GameManager.InstallPkgOnThread(pkgPath_, deletePkgFile_)) {
|
|
installStarted_ = true;
|
|
if (installChoice_) {
|
|
installChoice_->SetEnabled(false);
|
|
}
|
|
}
|
|
}
|
|
|
|
void InstallPkgScreen::update() {
|
|
auto iz = GetI18NCategory(I18NCat::INSTALLZIP);
|
|
|
|
using namespace UI;
|
|
if (g_GameManager.GetState() == GameManagerState::IDLE && doneView_) {
|
|
const std::string err = g_GameManager.GetInstallError();
|
|
if (!err.empty()) {
|
|
doneView_->SetLevelAndText(NoticeLevel::ERROR, err);
|
|
doneView_->SetVisibility(Visibility::V_VISIBLE);
|
|
} else if (installStarted_) {
|
|
doneView_->SetLevelAndText(NoticeLevel::SUCCESS, iz->T("Installed!"));
|
|
doneView_->SetVisibility(Visibility::V_VISIBLE);
|
|
}
|
|
}
|
|
UIBaseDialogScreen::update();
|
|
}
|