2021-06-05 14:59:38 +00:00
// 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 "ppsspp_config.h"
# include "android/jni/app-android.h"
# include "Common/Log.h"
# include "Common/UI/UI.h"
# include "Common/UI/View.h"
# include "Common/UI/ViewGroup.h"
# include "Common/StringUtils.h"
# include "Common/System/System.h"
2023-03-22 11:26:14 +00:00
# include "Common/System/Request.h"
2021-06-05 14:59:38 +00:00
# include "Common/System/NativeApp.h"
# include "Common/System/Display.h"
2023-07-12 09:29:24 +00:00
# include "Common/System/OSD.h"
2021-07-25 13:33:11 +00:00
# include "Common/Data/Text/I18n.h"
2021-07-26 20:11:07 +00:00
# include "Common/Data/Text/Parsers.h"
2021-07-25 13:33:11 +00:00
# include "Common/File/AndroidStorage.h"
# include "Common/File/FileUtil.h"
# include "Common/File/Path.h"
2021-07-24 22:16:30 +00:00
# include "Common/File/DiskFree.h"
2021-06-05 14:59:38 +00:00
2021-07-29 21:03:43 +00:00
# include "Common/Thread/ThreadManager.h"
2021-07-25 13:33:11 +00:00
# include "Core/Config.h"
2021-09-20 14:20:58 +00:00
# include "Core/Reporting.h"
# include "Core/System.h"
# include "Core/Util/GameManager.h"
2021-06-05 14:59:38 +00:00
# include "UI/MemStickScreen.h"
# include "UI/MainScreen.h"
# include "UI/MiscScreens.h"
2023-07-15 10:22:00 +00:00
# include "UI/OnScreenDisplay.h"
2021-06-05 14:59:38 +00:00
2023-12-14 11:23:31 +00:00
static bool FolderSeemsToBeUsed ( const Path & newMemstickFolder ) {
2021-09-18 17:08:41 +00:00
// Inspect the potential new folder, quickly.
2021-08-05 19:53:08 +00:00
if ( File : : Exists ( newMemstickFolder / " PSP/SAVEDATA " ) | | File : : Exists ( newMemstickFolder / " SAVEDATA " ) ) {
// Does seem likely. We could add more criteria like checking for actual savegames or something.
2021-07-24 22:16:30 +00:00
return true ;
} else {
return false ;
}
}
static bool SwitchMemstickFolderTo ( Path newMemstickFolder ) {
// Doesn't already exist, create.
// Should this ever happen?
if ( newMemstickFolder . Type ( ) = = PathType : : NATIVE ) {
if ( ! File : : Exists ( newMemstickFolder ) ) {
File : : CreateFullPath ( newMemstickFolder ) ;
}
2023-12-20 09:35:02 +00:00
Path testWriteFile = newMemstickFolder / " .write_verify_file " ;
2021-07-24 22:16:30 +00:00
if ( ! File : : WriteDataToFile ( true , " 1 " , 1 , testWriteFile ) ) {
2021-07-26 20:15:34 +00:00
return false ;
2021-07-24 22:16:30 +00:00
}
File : : Delete ( testWriteFile ) ;
} else {
// TODO: Do the same but with scoped storage? Not really necessary, right? If it came from a browse
// for folder, we can assume it exists and is writable, barring wacky race conditions like the user
// being connected by USB and deleting it.
}
Path memStickDirFile = g_Config . internalDataDirectory / " memstick_dir.txt " ;
2023-05-01 20:09:22 +00:00
# if PPSSPP_PLATFORM(UWP)
2023-04-28 19:22:17 +00:00
File : : Delete ( memStickDirFile ) ;
2023-05-01 20:09:22 +00:00
if ( newMemstickFolder ! = g_Config . internalDataDirectory ) {
2023-04-28 19:22:17 +00:00
# endif
2021-07-24 22:16:30 +00:00
std : : string str = newMemstickFolder . ToString ( ) ;
if ( ! File : : WriteDataToFile ( true , str . c_str ( ) , ( unsigned int ) str . size ( ) , memStickDirFile ) ) {
ERROR_LOG ( SYSTEM , " Failed to write memstick path '%s' to '%s' " , newMemstickFolder . c_str ( ) , memStickDirFile . c_str ( ) ) ;
2021-09-20 14:20:58 +00:00
// Not sure what to do if this file can't be written. Disk full?
2021-07-24 22:16:30 +00:00
}
2023-05-01 20:09:22 +00:00
# if PPSSPP_PLATFORM(UWP)
2023-04-28 19:22:17 +00:00
}
# endif
2021-07-24 22:16:30 +00:00
// Save so the settings, at least, are transferred.
g_Config . memStickDirectory = newMemstickFolder ;
g_Config . SetSearchPath ( GetSysDirectory ( DIRECTORY_SYSTEM ) ) ;
g_Config . UpdateIniLocation ( ) ;
return true ;
}
static std : : string FormatSpaceString ( int64_t space ) {
if ( space > = 0 ) {
2021-07-26 20:11:07 +00:00
char buffer [ 50 ] ;
NiceSizeFormat ( space , buffer , sizeof ( buffer ) ) ;
return buffer ;
2021-07-24 22:16:30 +00:00
} else {
return " N/A " ;
}
}
MemStickScreen : : MemStickScreen ( bool initialSetup )
: initialSetup_ ( initialSetup ) {
2021-09-19 13:54:01 +00:00
# if PPSSPP_PLATFORM(ANDROID)
// Let's only offer the browse-for-folder choice on Android 10 or later.
// Earlier versions often don't really have working folder browsers.
storageBrowserWorking_ = System_GetPropertyInt ( SYSPROP_SYSTEMVERSION ) > = 29 ;
# else
// For testing UI only
storageBrowserWorking_ = true ;
# endif
if ( initialSetup_ ) {
// Preselect current choice.
if ( System_GetPropertyBool ( SYSPROP_ANDROID_SCOPED_STORAGE ) ) {
choice_ = CHOICE_BROWSE_FOLDER ;
} else {
2021-09-20 14:20:58 +00:00
WARN_LOG_REPORT ( SYSTEM , " Scoped storage not enabled - shouldn't be in MemStickScreen at initial setup " ) ;
2021-09-19 13:54:01 +00:00
choice_ = CHOICE_STORAGE_ROOT ;
// Shouldn't really be here in initial setup.
}
} else {
// Detect the current choice, so it's preselected in the UI.
2023-05-01 20:09:22 +00:00
# if PPSSPP_PLATFORM(UWP)
if ( g_Config . memStickDirectory = = g_Config . internalDataDirectory ) {
2023-04-28 19:22:17 +00:00
# else
2021-09-19 13:54:01 +00:00
if ( g_Config . memStickDirectory = = Path ( g_extFilesDir ) ) {
2023-04-28 19:22:17 +00:00
# endif
2021-09-19 13:54:01 +00:00
choice_ = CHOICE_PRIVATE_DIRECTORY ;
} else if ( g_Config . memStickDirectory = = Path ( g_externalDir ) ) {
choice_ = CHOICE_STORAGE_ROOT ;
} else if ( storageBrowserWorking_ ) {
choice_ = CHOICE_BROWSE_FOLDER ;
} else {
choice_ = CHOICE_SET_MANUAL ;
}
}
2021-07-25 13:33:11 +00:00
}
2021-06-05 14:59:38 +00:00
2021-09-19 16:32:10 +00:00
static void AddExplanation ( UI : : ViewGroup * viewGroup , MemStickScreen : : Choice choice , UI : : View * extraView = nullptr ) {
2023-04-05 22:34:50 +00:00
auto iz = GetI18NCategory ( I18NCat : : MEMSTICK ) ;
2021-09-19 16:32:10 +00:00
using namespace UI ;
int flags = FLAG_WRAP_TEXT ;
UI : : ViewGroup * holder = new UI : : LinearLayout ( ORIENT_VERTICAL ) ;
UI : : ViewGroup * indentHolder = new UI : : LinearLayout ( ORIENT_HORIZONTAL ) ;
indentHolder - > Add ( new Spacer ( 20.0 ) ) ;
indentHolder - > Add ( holder ) ;
viewGroup - > Add ( indentHolder ) ;
if ( extraView ) {
holder - > Add ( extraView ) ;
}
switch ( choice ) {
case MemStickScreen : : CHOICE_STORAGE_ROOT :
// Old school choice
2021-09-20 06:34:58 +00:00
holder - > Add ( new TextView ( iz - > T ( " DataWillStay " , " Data will stay even if you uninstall PPSSPP " ) , flags , false ) ) - > SetBullet ( true ) ;
holder - > Add ( new TextView ( iz - > T ( " DataCanBeShared " , " Data can be shared between PPSSPP regular/Gold " ) , flags , false ) ) - > SetBullet ( true ) ;
2021-09-19 16:32:10 +00:00
holder - > Add ( new TextView ( iz - > T ( " EasyUSBAccess " , " Easy USB access " ) , flags , false ) ) - > SetBullet ( true ) ;
break ;
case MemStickScreen : : CHOICE_BROWSE_FOLDER :
2021-09-20 06:34:58 +00:00
holder - > Add ( new TextView ( iz - > T ( " DataWillStay " , " Data will stay even if you uninstall PPSSPP " ) , flags , false ) ) - > SetBullet ( true ) ;
holder - > Add ( new TextView ( iz - > T ( " DataCanBeShared " , " Data can be shared between PPSSPP regular/Gold " ) , flags , false ) ) - > SetBullet ( true ) ;
2023-04-28 19:22:17 +00:00
# if !PPSSPP_PLATFORM(UWP)
2021-09-19 16:32:10 +00:00
holder - > Add ( new TextView ( iz - > T ( " EasyUSBAccess " , " Easy USB access " ) , flags , false ) ) - > SetBullet ( true ) ;
2023-04-28 19:22:17 +00:00
# endif
2021-09-19 16:32:10 +00:00
break ;
case MemStickScreen : : CHOICE_PRIVATE_DIRECTORY :
// Consider https://www.compart.com/en/unicode/U+26A0 (unicode warning sign?)? or a graphic?
holder - > Add ( new TextView ( iz - > T ( " DataWillBeLostOnUninstall " , " Warning! Data will be lost when you uninstall PPSSPP! " ) , flags , false ) ) - > SetBullet ( true ) ;
holder - > Add ( new TextView ( iz - > T ( " DataCannotBeShared " , " Data CANNOT be shared between PPSSPP regular/Gold! " ) , flags , false ) ) - > SetBullet ( true ) ;
2023-04-28 19:22:17 +00:00
# if !PPSSPP_PLATFORM(UWP)
2021-09-19 16:32:10 +00:00
# if GOLD
holder - > Add ( new TextView ( iz - > T ( " USBAccessThroughGold " , " USB access through Android/data/org.ppsspp.ppssppgold/files " ) , flags , false ) ) - > SetBullet ( true ) ;
# else
holder - > Add ( new TextView ( iz - > T ( " USBAccessThrough " , " USB access through Android/data/org.ppsspp.ppsspp/files " ) , flags , false ) ) - > SetBullet ( true ) ;
2023-04-28 19:22:17 +00:00
# endif
2021-09-19 16:32:10 +00:00
# endif
break ;
case MemStickScreen : : CHOICE_SET_MANUAL :
default :
holder - > Add ( new TextView ( iz - > T ( " EasyUSBAccess " , " Easy USB access " ) , flags , false ) ) - > SetBullet ( true ) ;
// What more?
// Should we have a special text here? It'll popup a text window for editing.
break ;
}
}
2021-06-05 14:59:38 +00:00
void MemStickScreen : : CreateViews ( ) {
using namespace UI ;
2023-04-05 22:34:50 +00:00
auto di = GetI18NCategory ( I18NCat : : DIALOG ) ;
auto iz = GetI18NCategory ( I18NCat : : MEMSTICK ) ;
2021-06-05 14:59:38 +00:00
2021-09-19 18:24:28 +00:00
Margins actionMenuMargins ( 15 , 0 , 15 , 0 ) ;
2021-06-05 14:59:38 +00:00
2021-07-24 22:16:30 +00:00
root_ = new LinearLayout ( ORIENT_HORIZONTAL ) ;
2021-06-05 14:59:38 +00:00
2021-07-25 13:33:11 +00:00
Spacer * spacerColumn = new Spacer ( new LinearLayoutParams ( 20.0 , FILL_PARENT , 0.0f ) ) ;
2021-09-19 18:24:28 +00:00
ScrollView * mainColumnScroll = new ScrollView ( ORIENT_VERTICAL , new LinearLayoutParams ( 1.0 ) ) ;
2021-08-05 19:53:08 +00:00
2021-09-19 18:24:28 +00:00
ViewGroup * mainColumn = new LinearLayoutList ( ORIENT_VERTICAL ) ;
mainColumnScroll - > Add ( mainColumn ) ;
2021-07-25 13:33:11 +00:00
2021-09-19 18:24:28 +00:00
root_ - > Add ( spacerColumn ) ;
root_ - > Add ( mainColumnScroll ) ;
2021-08-05 19:53:08 +00:00
2021-07-25 13:33:11 +00:00
if ( initialSetup_ ) {
2021-09-19 18:24:28 +00:00
mainColumn - > Add ( new Spacer ( new LinearLayoutParams ( FILL_PARENT , 12.0f , 0.0f ) ) ) ;
mainColumn - > Add ( new TextView ( iz - > T ( " Welcome to PPSSPP! " ) , ALIGN_LEFT , false ) ) ;
2021-07-25 13:33:11 +00:00
}
2021-09-19 18:24:28 +00:00
mainColumn - > Add ( new Spacer ( new LinearLayoutParams ( FILL_PARENT , 18.0f , 0.0f ) ) ) ;
mainColumn - > Add ( new TextView ( iz - > T ( " MemoryStickDescription " , " Choose where to keep PSP data (Memory Stick) " ) , ALIGN_LEFT , false ) ) ;
mainColumn - > Add ( new Spacer ( new LinearLayoutParams ( FILL_PARENT , 18.0f , 0.0f ) ) ) ;
2021-09-18 21:40:43 +00:00
2021-09-19 18:24:28 +00:00
ViewGroup * subColumns = new LinearLayoutList ( ORIENT_HORIZONTAL ) ;
mainColumn - > Add ( subColumns ) ;
ViewGroup * leftColumn = new LinearLayoutList ( ORIENT_VERTICAL , new LinearLayoutParams ( 1.0 ) ) ;
subColumns - > Add ( leftColumn ) ;
ViewGroup * rightColumnItems = new LinearLayout ( ORIENT_VERTICAL , new LinearLayoutParams ( 220 , FILL_PARENT , actionMenuMargins ) ) ;
subColumns - > Add ( rightColumnItems ) ;
2021-07-25 13:33:11 +00:00
2021-08-04 21:21:28 +00:00
// For legacy Android systems, so you can switch back to the old ways if you move to SD or something.
2021-09-19 16:32:10 +00:00
// Trying to avoid needing a scroll view, so only showing the explanation for one option at a time.
2023-08-14 05:27:51 +00:00
# if !PPSSPP_PLATFORM(UWP)
2021-08-04 21:21:28 +00:00
if ( ! System_GetPropertyBool ( SYSPROP_ANDROID_SCOPED_STORAGE ) ) {
2021-09-19 13:54:01 +00:00
leftColumn - > Add ( new RadioButton ( & choice_ , CHOICE_STORAGE_ROOT , iz - > T ( " Use PSP folder at root of storage " ) ) ) - > OnClick . Handle ( this , & MemStickScreen : : OnChoiceClick ) ;
2021-09-19 16:32:10 +00:00
if ( choice_ = = CHOICE_STORAGE_ROOT ) {
AddExplanation ( leftColumn , ( MemStickScreen : : Choice ) choice_ ) ;
}
2021-09-19 13:54:01 +00:00
}
2023-08-14 05:27:51 +00:00
# endif
2021-09-19 13:54:01 +00:00
if ( storageBrowserWorking_ ) {
leftColumn - > Add ( new RadioButton ( & choice_ , CHOICE_BROWSE_FOLDER , iz - > T ( " Create or Choose a PSP folder " ) ) ) - > OnClick . Handle ( this , & MemStickScreen : : OnChoiceClick ) ;
2021-09-19 16:32:10 +00:00
2021-09-19 13:54:01 +00:00
// TODO: Show current folder here if we have one set.
} else {
leftColumn - > Add ( new RadioButton ( & choice_ , CHOICE_SET_MANUAL , iz - > T ( " Manually specify PSP folder " ) ) ) - > OnClick . Handle ( this , & MemStickScreen : : OnChoiceClick ) ;
2021-08-06 20:32:43 +00:00
leftColumn - > Add ( new TextView ( iz - > T ( " DataWillStay " , " Data will stay even if you uninstall PPSSPP. " ) ) ) - > SetBullet ( true ) ;
leftColumn - > Add ( new TextView ( iz - > T ( " DataCanBeShared " , " Data can be shared between PPSSPP regular/Gold. " ) ) ) - > SetBullet ( true ) ;
2021-09-19 13:54:01 +00:00
// TODO: Show current folder here if we have one set.
}
2023-07-15 10:22:00 +00:00
errorNoticeView_ = leftColumn - > Add ( new NoticeView ( NoticeLevel : : WARN , iz - > T ( " Cancelled - try again " ) , " " ) ) ;
errorNoticeView_ - > SetVisibility ( UI : : V_GONE ) ;
2021-09-19 16:32:10 +00:00
if ( choice_ = = CHOICE_BROWSE_FOLDER | | choice_ = = CHOICE_SET_MANUAL ) {
UI : : View * extraView = nullptr ;
if ( ! g_Config . memStickDirectory . empty ( ) ) {
2023-05-04 08:03:14 +00:00
extraView = new TextView ( StringFromFormat ( " %s: %s " , iz - > T ( " Current " ) , g_Config . memStickDirectory . ToVisualString ( ) . c_str ( ) ) , ALIGN_LEFT , false ) ;
2021-09-19 16:32:10 +00:00
}
AddExplanation ( leftColumn , ( MemStickScreen : : Choice ) choice_ , extraView ) ;
2021-08-04 21:21:28 +00:00
}
2023-05-01 20:09:22 +00:00
2021-09-19 17:35:28 +00:00
std : : string privateString = iz - > T ( " Use App Private Data " ) ;
2023-05-01 20:09:22 +00:00
2021-09-19 16:32:10 +00:00
if ( initialSetup_ ) {
privateString = StringFromFormat ( " %s (%s) " , iz - > T ( " Skip for now " ) , privateString . c_str ( ) ) ;
}
2022-09-30 09:31:32 +00:00
leftColumn - > Add ( new RadioButton ( & choice_ , CHOICE_PRIVATE_DIRECTORY , privateString ) ) - > OnClick . Handle ( this , & MemStickScreen : : OnChoiceClick ) ;
2021-09-19 16:32:10 +00:00
if ( choice_ = = CHOICE_PRIVATE_DIRECTORY ) {
AddExplanation ( leftColumn , ( MemStickScreen : : Choice ) choice_ ) ;
}
2021-09-10 21:42:21 +00:00
2021-09-19 13:54:01 +00:00
leftColumn - > Add ( new Spacer ( new LinearLayoutParams ( FILL_PARENT , 12.0f , 0.0f ) ) ) ;
const char * confirmButtonText = nullptr ;
ImageID confirmButtonImage = ImageID : : invalid ( ) ;
switch ( choice_ ) {
case CHOICE_BROWSE_FOLDER :
2021-09-19 18:24:28 +00:00
confirmButtonText = di - > T ( " OK " ) ;
2021-09-19 13:54:01 +00:00
confirmButtonImage = ImageID ( " I_FOLDER_OPEN " ) ;
break ;
case CHOICE_PRIVATE_DIRECTORY :
2021-09-19 17:10:55 +00:00
if ( initialSetup_ ) {
confirmButtonText = di - > T ( " Skip " ) ;
confirmButtonImage = ImageID ( " I_WARNING " ) ;
} else {
2021-09-20 14:13:37 +00:00
confirmButtonText = di - > T ( " OK " ) ;
2021-09-19 17:10:55 +00:00
}
2021-09-19 13:54:01 +00:00
break ;
2021-09-19 16:32:10 +00:00
case CHOICE_STORAGE_ROOT :
2021-09-19 13:54:01 +00:00
case CHOICE_SET_MANUAL :
default :
2021-09-20 14:13:37 +00:00
confirmButtonText = di - > T ( " OK " ) ;
2021-09-19 13:54:01 +00:00
break ;
}
2021-09-19 16:45:15 +00:00
rightColumnItems - > Add ( new UI : : Choice ( confirmButtonText , confirmButtonImage ) ) - > OnClick . Handle < MemStickScreen > ( this , & MemStickScreen : : OnConfirmClick ) ;
2021-09-19 13:54:01 +00:00
rightColumnItems - > Add ( new Spacer ( new LinearLayoutParams ( FILL_PARENT , 12.0f , 0.0f ) ) ) ;
2021-06-05 14:59:38 +00:00
2021-07-25 13:33:11 +00:00
if ( ! initialSetup_ ) {
2021-09-19 16:32:10 +00:00
rightColumnItems - > Add ( new UI : : Choice ( di - > T ( " Back " ) ) ) - > OnClick . Handle < UIScreen > ( this , & UIScreen : : OnBack ) ;
2021-06-05 14:59:38 +00:00
}
2021-10-05 09:30:50 +00:00
if ( System_GetPropertyInt ( SYSPROP_DEVICE_TYPE ) ! = DEVICE_TYPE_TV ) {
rightColumnItems - > Add ( new UI : : Choice ( iz - > T ( " WhatsThis " , " What's this? " ) ) ) - > OnClick . Handle < MemStickScreen > ( this , & MemStickScreen : : OnHelp ) ;
}
2021-06-05 14:59:38 +00:00
2021-07-25 13:33:11 +00:00
INFO_LOG ( SYSTEM , " MemStickScreen: initialSetup=%d " , ( int ) initialSetup_ ) ;
}
2021-06-05 14:59:38 +00:00
2021-09-15 20:46:52 +00:00
UI : : EventReturn MemStickScreen : : OnHelp ( UI : : EventParams & params ) {
2023-01-28 23:25:00 +00:00
// I'm letting the old redirect handle this one, as the target is within /docs on the website,
// and that structure may change a bit.
2023-03-21 09:42:23 +00:00
System_LaunchUrl ( LaunchUrlType : : BROWSER_URL , " https://www.ppsspp.org/guide_storage.html " ) ;
2021-09-15 20:46:52 +00:00
return UI : : EVENT_DONE ;
}
2021-09-19 13:54:01 +00:00
UI : : EventReturn MemStickScreen : : OnChoiceClick ( UI : : EventParams & params ) {
// Change the confirm button to match the choice,
// and change the text that we show.
RecreateViews ( ) ;
return UI : : EVENT_DONE ;
}
UI : : EventReturn MemStickScreen : : OnConfirmClick ( UI : : EventParams & params ) {
switch ( choice_ ) {
case CHOICE_SET_MANUAL :
return SetFolderManually ( params ) ;
case CHOICE_STORAGE_ROOT :
return UseStorageRoot ( params ) ;
case CHOICE_PRIVATE_DIRECTORY :
return UseInternalStorage ( params ) ;
case CHOICE_BROWSE_FOLDER :
return Browse ( params ) ;
}
return UI : : EVENT_DONE ;
}
UI : : EventReturn MemStickScreen : : SetFolderManually ( UI : : EventParams & params ) {
2021-09-10 21:59:54 +00:00
// The old way, from before scoped storage.
2023-06-21 22:47:00 +00:00
# if PPSSPP_PLATFORM(ANDROID) || PPSSPP_PLATFORM(SWITCH)
2023-04-05 22:34:50 +00:00
auto sy = GetI18NCategory ( I18NCat : : SYSTEM ) ;
2023-03-22 11:26:14 +00:00
System_InputBoxGetString ( sy - > T ( " Memory Stick Folder " ) , g_Config . memStickDirectory . ToString ( ) , [ & ] ( const std : : string & value , int ) {
2023-04-05 22:34:50 +00:00
auto sy = GetI18NCategory ( I18NCat : : SYSTEM ) ;
auto di = GetI18NCategory ( I18NCat : : DIALOG ) ;
2021-09-10 21:59:54 +00:00
2023-03-25 17:51:06 +00:00
std : : string newPath = value ;
size_t pos = newPath . find_last_not_of ( " / " ) ;
// Gotta have at least something but a /, and also needs to start with a /.
if ( newPath . empty ( ) | | pos = = newPath . npos | | newPath [ 0 ] ! = ' / ' ) {
settingInfo_ - > Show ( sy - > T ( " ChangingMemstickPathInvalid " , " That path couldn't be used to save Memory Stick files. " ) , nullptr ) ;
return ;
}
if ( pos ! = newPath . size ( ) - 1 ) {
newPath = newPath . substr ( 0 , pos + 1 ) ;
}
if ( newPath . empty ( ) ) {
// Reuse below message instead of adding yet another string.
System_Toast ( sy - > T ( " Path does not exist! " ) ) ;
return ;
}
Path pendingMemStickFolder ( newPath ) ;
if ( ! File : : Exists ( pendingMemStickFolder ) ) {
// Try to fix the path string, apparently some users got used to leaving out the /.
if ( newPath [ 0 ] ! = ' / ' ) {
newPath = " / " + newPath ;
}
pendingMemStickFolder = Path ( newPath ) ;
}
if ( ! File : : Exists ( pendingMemStickFolder ) & & pendingMemStickFolder . Type ( ) = = PathType : : NATIVE ) {
// Still no path? Try to automatically fix the case.
std : : string oldNewPath = newPath ;
FixPathCase ( Path ( " " ) , newPath , FixPathCaseBehavior : : FPC_FILE_MUST_EXIST ) ;
if ( oldNewPath ! = newPath ) {
NOTICE_LOG ( IO , " Fixed path case: %s -> %s " , oldNewPath . c_str ( ) , newPath . c_str ( ) ) ;
pendingMemStickFolder = Path ( newPath ) ;
} else {
NOTICE_LOG ( IO , " Failed to fix case of path %s (result: %s) " , newPath . c_str ( ) , oldNewPath . c_str ( ) ) ;
}
}
if ( pendingMemStickFolder = = g_Config . memStickDirectory ) {
// Same directory as before - all good. Nothing to do.
TriggerFinish ( DialogResult : : DR_OK ) ;
return ;
}
if ( ! File : : Exists ( pendingMemStickFolder ) ) {
System_Toast ( sy - > T ( " Path does not exist! " ) ) ;
return ;
}
screenManager ( ) - > push ( new ConfirmMemstickMoveScreen ( pendingMemStickFolder , false ) ) ;
2021-09-10 21:59:54 +00:00
} ) ;
2021-09-11 02:01:56 +00:00
# endif
2021-09-10 21:59:54 +00:00
return UI : : EVENT_DONE ;
}
2021-09-19 13:54:01 +00:00
UI : : EventReturn MemStickScreen : : UseInternalStorage ( UI : : EventParams & params ) {
2023-05-01 20:09:22 +00:00
# if PPSSPP_PLATFORM(UWP)
Path pendingMemStickFolder = g_Config . internalDataDirectory ;
2023-04-28 19:22:17 +00:00
# else
2021-08-04 21:21:28 +00:00
Path pendingMemStickFolder = Path ( g_extFilesDir ) ;
2023-04-28 19:22:17 +00:00
# endif
2021-08-04 21:21:28 +00:00
if ( initialSetup_ ) {
// There's not gonna be any files here in this case since it's a fresh install.
// Let's just accept it and move on. No need to move files either.
if ( SwitchMemstickFolderTo ( pendingMemStickFolder ) ) {
TriggerFinish ( DialogResult : : DR_OK ) ;
} else {
// This can't really happen?? Not worth making an error message.
2021-09-20 14:20:58 +00:00
ERROR_LOG_REPORT ( SYSTEM , " Could not switch memstick path in setup (internal) " ) ;
2021-08-04 21:21:28 +00:00
}
2022-04-17 21:02:17 +00:00
// Don't have a confirmation dialog that would otherwise do it for us, need to just switch directly to the main screen.
screenManager ( ) - > switchScreen ( new MainScreen ( ) ) ;
2021-09-10 20:52:49 +00:00
} else if ( pendingMemStickFolder ! = g_Config . memStickDirectory ) {
2021-08-04 21:21:28 +00:00
// Always ask for confirmation when called from the UI. Likely there's already some data.
screenManager ( ) - > push ( new ConfirmMemstickMoveScreen ( pendingMemStickFolder , false ) ) ;
2021-09-10 20:52:49 +00:00
} else {
// User chose the same directory it's already in. Let's just bail.
TriggerFinish ( DialogResult : : DR_OK ) ;
2021-08-04 21:21:28 +00:00
}
return UI : : EVENT_DONE ;
}
2021-09-19 13:54:01 +00:00
UI : : EventReturn MemStickScreen : : UseStorageRoot ( UI : : EventParams & params ) {
2021-08-04 21:21:28 +00:00
Path pendingMemStickFolder = Path ( g_externalDir ) ;
2021-07-24 22:16:30 +00:00
if ( initialSetup_ ) {
// There's not gonna be any files here in this case since it's a fresh install.
// Let's just accept it and move on. No need to move files either.
2021-08-04 21:21:28 +00:00
if ( SwitchMemstickFolderTo ( pendingMemStickFolder ) ) {
2021-07-26 20:15:34 +00:00
TriggerFinish ( DialogResult : : DR_OK ) ;
} else {
// This can't really happen?? Not worth making an error message.
2021-09-20 14:20:58 +00:00
ERROR_LOG_REPORT ( SYSTEM , " Could not switch memstick path in setup " ) ;
2021-07-26 20:15:34 +00:00
}
2021-09-10 20:52:49 +00:00
} else if ( pendingMemStickFolder ! = g_Config . memStickDirectory ) {
2021-07-24 22:16:30 +00:00
// Always ask for confirmation when called from the UI. Likely there's already some data.
2021-08-04 21:21:28 +00:00
screenManager ( ) - > push ( new ConfirmMemstickMoveScreen ( pendingMemStickFolder , false ) ) ;
2021-09-10 20:52:49 +00:00
} else {
// User chose the same directory it's already in. Let's just bail.
TriggerFinish ( DialogResult : : DR_OK ) ;
2021-07-24 22:16:30 +00:00
}
2021-07-25 13:33:11 +00:00
return UI : : EVENT_DONE ;
2021-06-05 14:59:38 +00:00
}
2021-09-19 13:54:01 +00:00
UI : : EventReturn MemStickScreen : : Browse ( UI : : EventParams & params ) {
2023-04-05 22:34:50 +00:00
auto mm = GetI18NCategory ( I18NCat : : MAINMENU ) ;
2023-03-22 15:09:33 +00:00
System_BrowseForFolder ( mm - > T ( " Choose folder " ) , [ = ] ( const std : : string & value , int ) {
2023-07-12 09:29:24 +00:00
Path pendingMemStickFolder = Path ( value ) ;
INFO_LOG ( SYSTEM , " Got folder: '%s' " , pendingMemStickFolder . c_str ( ) ) ;
2023-03-22 15:09:33 +00:00
// Browse finished. Let's pop up the confirmation dialog.
2023-07-12 09:29:24 +00:00
if ( ! pendingMemStickFolder . empty ( ) & & pendingMemStickFolder = = g_Config . memStickDirectory & & File : : IsDirectory ( pendingMemStickFolder ) ) {
2023-04-05 22:34:50 +00:00
auto iz = GetI18NCategory ( I18NCat : : MEMSTICK ) ;
2023-07-12 09:29:24 +00:00
// Not sure how this could happen, but let's go with it.
g_OSD . Show ( OSDType : : MESSAGE_SUCCESS , iz - > T ( " Done! " ) ) ;
done_ = true ;
2023-03-22 15:09:33 +00:00
return ;
2021-06-05 14:59:38 +00:00
}
2023-07-15 10:22:00 +00:00
errorNoticeView_ - > SetVisibility ( UI : : V_GONE ) ;
2023-03-22 15:09:33 +00:00
screenManager ( ) - > push ( new ConfirmMemstickMoveScreen ( pendingMemStickFolder , initialSetup_ ) ) ;
2023-07-15 10:22:00 +00:00
} , [ = ] ( ) {
errorNoticeView_ - > SetVisibility ( UI : : V_VISIBLE ) ;
2023-03-22 15:09:33 +00:00
} ) ;
return UI : : EVENT_DONE ;
2021-06-05 14:59:38 +00:00
}
2021-07-24 22:16:30 +00:00
void MemStickScreen : : dialogFinished ( const Screen * dialog , DialogResult result ) {
if ( result = = DialogResult : : DR_OK ) {
INFO_LOG ( SYSTEM , " Confirmation screen done - moving on. " ) ;
// There's a screen manager bug if we call TriggerFinish directly.
// Can't be bothered right now, so we pick this up in update().
done_ = true ;
}
// otherwise, we just keep going.
}
void MemStickScreen : : update ( ) {
UIDialogScreenWithBackground : : update ( ) ;
if ( done_ ) {
TriggerFinish ( DialogResult : : DR_OK ) ;
done_ = false ;
}
}
2021-09-18 13:10:31 +00:00
// Keep the size with the file, so we can skip overly large ones in the move.
// The user will have to take care of them afterwards, it'll just take too long probably.
struct FileSuffix {
std : : string suffix ;
u64 fileSize ;
} ;
2023-12-14 11:23:31 +00:00
static bool ListFileSuffixesRecursively ( const Path & root , const Path & folder , std : : vector < std : : string > & dirSuffixes , std : : vector < FileSuffix > & fileSuffixes ) {
2021-07-24 22:16:30 +00:00
std : : vector < File : : FileInfo > files ;
if ( ! File : : GetFilesInDir ( folder , & files ) ) {
return false ;
}
for ( auto & file : files ) {
if ( file . isDirectory ) {
2021-07-24 22:54:41 +00:00
std : : string dirSuffix ;
if ( root . ComputePathTo ( file . fullName , dirSuffix ) ) {
2023-01-02 21:07:14 +00:00
if ( ! dirSuffix . empty ( ) ) {
dirSuffixes . push_back ( dirSuffix ) ;
ListFileSuffixesRecursively ( root , folder / file . name , dirSuffixes , fileSuffixes ) ;
}
2021-07-24 22:54:41 +00:00
} else {
2021-09-20 14:20:58 +00:00
ERROR_LOG_REPORT ( SYSTEM , " Failed to compute PathTo from '%s' to '%s' " , root . c_str ( ) , folder . c_str ( ) ) ;
2021-07-24 22:54:41 +00:00
}
2021-07-24 22:16:30 +00:00
} else {
2021-07-24 22:54:41 +00:00
std : : string fileSuffix ;
if ( root . ComputePathTo ( file . fullName , fileSuffix ) ) {
2023-01-02 21:07:14 +00:00
if ( ! fileSuffix . empty ( ) ) {
fileSuffixes . push_back ( FileSuffix { fileSuffix , file . size } ) ;
}
2021-07-24 22:54:41 +00:00
}
2021-07-24 22:16:30 +00:00
}
}
return true ;
}
ConfirmMemstickMoveScreen : : ConfirmMemstickMoveScreen ( Path newMemstickFolder , bool initialSetup )
: newMemstickFolder_ ( newMemstickFolder ) , initialSetup_ ( initialSetup ) {
existingFilesInNewFolder_ = FolderSeemsToBeUsed ( newMemstickFolder ) ;
if ( initialSetup_ ) {
moveData_ = false ;
}
}
2021-07-29 21:03:43 +00:00
ConfirmMemstickMoveScreen : : ~ ConfirmMemstickMoveScreen ( ) {
if ( moveDataTask_ ) {
INFO_LOG ( SYSTEM , " Move Data task still running, blocking on it " ) ;
moveDataTask_ - > BlockUntilReady ( ) ;
delete moveDataTask_ ;
}
}
2021-07-24 22:16:30 +00:00
void ConfirmMemstickMoveScreen : : CreateViews ( ) {
using namespace UI ;
2023-04-05 22:34:50 +00:00
auto sy = GetI18NCategory ( I18NCat : : SYSTEM ) ;
auto iz = GetI18NCategory ( I18NCat : : MEMSTICK ) ;
2021-06-05 14:59:38 +00:00
2021-07-24 22:16:30 +00:00
root_ = new LinearLayout ( ORIENT_HORIZONTAL ) ;
2021-06-05 14:59:38 +00:00
2021-07-24 22:16:30 +00:00
Path oldMemstickFolder = g_Config . memStickDirectory ;
Spacer * spacerColumn = new Spacer ( new LinearLayoutParams ( 20.0 , FILL_PARENT , 0.0f ) ) ;
ViewGroup * leftColumn = new LinearLayout ( ORIENT_VERTICAL , new LinearLayoutParams ( 1.0 ) ) ;
ViewGroup * rightColumn = new LinearLayout ( ORIENT_VERTICAL , new LinearLayoutParams ( 1.0 ) ) ;
root_ - > Add ( spacerColumn ) ;
root_ - > Add ( leftColumn ) ;
root_ - > Add ( rightColumn ) ;
int64_t freeSpaceNew ;
int64_t freeSpaceOld ;
free_disk_space ( newMemstickFolder_ , freeSpaceNew ) ;
free_disk_space ( oldMemstickFolder , freeSpaceOld ) ;
2021-09-18 17:08:41 +00:00
leftColumn - > Add ( new TextView ( iz - > T ( " Selected PSP Data Folder " ) , ALIGN_LEFT , false ) ) ;
2021-08-05 19:53:08 +00:00
if ( ! initialSetup_ ) {
2023-07-15 10:22:00 +00:00
leftColumn - > Add ( new NoticeView ( NoticeLevel : : WARN , iz - > T ( " PPSSPP will restart after the change " ) , " " ) ) ;
2021-08-05 19:53:08 +00:00
}
2023-05-04 08:03:14 +00:00
leftColumn - > Add ( new TextView ( newMemstickFolder_ . ToVisualString ( ) , ALIGN_LEFT , false ) ) ;
2021-07-24 22:16:30 +00:00
std : : string newFreeSpaceText = std : : string ( iz - > T ( " Free space " ) ) + " : " + FormatSpaceString ( freeSpaceNew ) ;
leftColumn - > Add ( new TextView ( newFreeSpaceText , ALIGN_LEFT , false ) ) ;
if ( existingFilesInNewFolder_ ) {
2023-07-15 10:22:00 +00:00
leftColumn - > Add ( new NoticeView ( NoticeLevel : : SUCCESS , iz - > T ( " Already contains PSP data " ) , " " ) ) ;
2021-08-05 19:53:08 +00:00
if ( ! moveData_ ) {
2023-07-15 10:22:00 +00:00
leftColumn - > Add ( new NoticeView ( NoticeLevel : : INFO , iz - > T ( " No data will be changed " ) , " " ) ) ;
2021-08-05 19:53:08 +00:00
}
2021-07-24 22:16:30 +00:00
}
if ( ! error_ . empty ( ) ) {
leftColumn - > Add ( new TextView ( error_ , ALIGN_LEFT , false ) ) ;
}
if ( ! oldMemstickFolder . empty ( ) ) {
std : : string oldFreeSpaceText = std : : string ( iz - > T ( " Free space " ) ) + " : " + FormatSpaceString ( freeSpaceOld ) ;
2023-04-28 19:22:17 +00:00
2021-09-19 16:32:10 +00:00
rightColumn - > Add ( new TextView ( std : : string ( iz - > T ( " Current " ) ) + " : " , ALIGN_LEFT , false ) ) ;
2023-05-04 08:03:14 +00:00
rightColumn - > Add ( new TextView ( oldMemstickFolder . ToVisualString ( ) , ALIGN_LEFT , false ) ) ;
2021-07-24 22:16:30 +00:00
rightColumn - > Add ( new TextView ( oldFreeSpaceText , ALIGN_LEFT , false ) ) ;
}
2021-07-29 21:03:43 +00:00
if ( moveDataTask_ ) {
progressView_ = leftColumn - > Add ( new TextView ( progressReporter_ . Get ( ) ) ) ;
} else {
progressView_ = nullptr ;
2021-07-24 22:16:30 +00:00
}
2021-07-29 21:03:43 +00:00
if ( ! moveDataTask_ ) {
if ( ! initialSetup_ ) {
2021-08-05 19:53:08 +00:00
leftColumn - > Add ( new CheckBox ( & moveData_ , iz - > T ( " Move Data " ) ) ) - > OnClick . Handle ( this , & ConfirmMemstickMoveScreen : : OnMoveDataClick ) ;
2021-07-29 21:03:43 +00:00
}
2023-12-20 09:35:02 +00:00
auto di = GetI18NCategory ( I18NCat : : DIALOG ) ;
2021-07-29 21:03:43 +00:00
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 ) ;
}
2021-07-24 22:16:30 +00:00
}
2021-08-05 19:53:08 +00:00
UI : : EventReturn ConfirmMemstickMoveScreen : : OnMoveDataClick ( UI : : EventParams & params ) {
RecreateViews ( ) ;
return UI : : EVENT_DONE ;
}
2021-07-29 21:03:43 +00:00
void ConfirmMemstickMoveScreen : : update ( ) {
UIDialogScreenWithBackground : : update ( ) ;
2023-04-05 22:34:50 +00:00
auto iz = GetI18NCategory ( I18NCat : : MEMSTICK ) ;
2021-07-29 21:03:43 +00:00
if ( moveDataTask_ ) {
if ( progressView_ ) {
progressView_ - > SetText ( progressReporter_ . Get ( ) ) ;
}
2021-09-18 13:10:31 +00:00
MoveResult * result = moveDataTask_ - > Poll ( ) ;
2021-07-29 21:03:43 +00:00
if ( result ) {
2021-09-18 13:10:31 +00:00
if ( result - > success ) {
2021-08-09 09:24:29 +00:00
progressReporter_ . Set ( iz - > T ( " Done! " ) ) ;
2021-07-29 21:03:43 +00:00
INFO_LOG ( SYSTEM , " Move data task finished successfully! " ) ;
// Succeeded!
FinishFolderMove ( ) ;
} else {
2021-09-18 13:10:31 +00:00
progressReporter_ . Set ( iz - > T ( " Failed to move some files! " ) ) ;
2021-07-29 21:03:43 +00:00
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 ;
}
}
}
2021-07-24 22:16:30 +00:00
UI : : EventReturn ConfirmMemstickMoveScreen : : OnConfirm ( UI : : EventParams & params ) {
// Transfer all the files in /PSP from the original directory.
// Should probably be done on a background thread so we can show some UI.
// So we probably need another screen for this with a progress bar..
// If the directory itself is called PSP, don't go below.
if ( moveData_ ) {
2023-05-01 20:09:22 +00:00
progressReporter_ . Set ( T ( I18NCat : : MEMSTICK , " Starting move... " ) ) ;
2021-07-29 21:03:43 +00:00
2021-11-20 21:40:10 +00:00
moveDataTask_ = Promise < MoveResult * > : : Spawn ( & g_threadManager , [ & ] ( ) - > MoveResult * {
2023-05-01 20:09:22 +00:00
auto ms = GetI18NCategory ( I18NCat : : MEMSTICK ) ;
2021-07-29 21:03:43 +00:00
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 ) ;
}
2021-07-24 22:16:30 +00:00
2021-07-29 21:03:43 +00:00
INFO_LOG ( SYSTEM , " About to move PSP data from '%s' to '%s' " , moveSrc . c_str ( ) , moveDest . c_str ( ) ) ;
2021-07-24 22:16:30 +00:00
2021-07-29 21:03:43 +00:00
// Search through recursively, listing the files to move and also summing their sizes.
2021-09-18 13:10:31 +00:00
std : : vector < FileSuffix > fileSuffixesToMove ;
2021-07-29 21:03:43 +00:00
std : : vector < std : : string > directorySuffixesToCreate ;
2021-07-24 22:16:30 +00:00
2021-07-29 21:03:43 +00:00
// 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 ( ) ) ;
2023-05-01 20:09:22 +00:00
progressReporter_ . Set ( ms - > T ( error . c_str ( ) ) ) ;
2021-09-18 13:10:31 +00:00
return new MoveResult { false , error } ;
2021-07-29 21:03:43 +00:00
}
2021-06-05 14:59:38 +00:00
2021-07-29 21:03:43 +00:00
bool dryRun = false ; // Useful for debugging.
2021-07-24 22:16:30 +00:00
2021-09-18 13:10:31 +00:00
size_t failedFiles = 0 ;
size_t skippedFiles = 0 ;
// We're not moving huge files like ISOs during this process, unless
// they can be directly moved, without rewriting the file.
const uint64_t BIG_FILE_THRESHOLD = 24 * 1024 * 1024 ;
2021-07-24 22:16:30 +00:00
2021-07-29 21:03:43 +00:00
if ( ! moveSrc . empty ( ) ) {
// Better not interrupt the app while this is happening!
2021-07-24 22:16:30 +00:00
2021-07-29 21:03:43 +00:00
// 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 ( ) ) ;
2021-10-04 21:47:39 +00:00
progressReporter_ . Set ( dirSuffix ) ;
2021-09-18 13:10:31 +00:00
// Just ignore already-exists errors.
File : : CreateDir ( dir ) ;
2021-07-24 22:16:30 +00:00
}
}
2021-07-24 22:54:41 +00:00
2021-07-29 21:03:43 +00:00
for ( auto & fileSuffix : fileSuffixesToMove ) {
2021-09-18 13:10:31 +00:00
progressReporter_ . Set ( StringFromFormat ( " %s (%s) " , fileSuffix . suffix . c_str ( ) , NiceSizeFormat ( fileSuffix . fileSize ) . c_str ( ) ) ) ;
2021-07-29 21:03:43 +00:00
2021-09-18 13:10:31 +00:00
Path from = moveSrc / fileSuffix . suffix ;
Path to = moveDest / fileSuffix . suffix ;
if ( fileSuffix . fileSize > BIG_FILE_THRESHOLD ) {
// We only move big files if it's fast to do so.
if ( dryRun ) {
INFO_LOG ( SYSTEM , " dry run: Would have moved '%s' to '%s' (%d bytes) if fast " , from . c_str ( ) , to . c_str ( ) , ( int ) fileSuffix . fileSize ) ;
} else {
if ( ! File : : MoveIfFast ( from , to ) ) {
INFO_LOG ( SYSTEM , " Skipped moving file '%s' to '%s' (%s) " , from . c_str ( ) , to . c_str ( ) , NiceSizeFormat ( fileSuffix . fileSize ) . c_str ( ) ) ;
skippedFiles + + ;
} else {
INFO_LOG ( SYSTEM , " Moved file '%s' to '%s' " , from . c_str ( ) , to . c_str ( ) ) ;
}
}
2021-07-24 22:54:41 +00:00
} else {
2021-09-18 13:10:31 +00:00
if ( dryRun ) {
INFO_LOG ( SYSTEM , " dry run: Would have moved '%s' to '%s' (%d bytes) " , from . c_str ( ) , to . c_str ( ) , ( int ) fileSuffix . fileSize ) ;
2021-07-29 21:03:43 +00:00
} else {
2021-09-18 13:10:31 +00:00
// 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 ( ) ) ;
failedFiles + + ;
// Should probably just bail?
} else {
INFO_LOG ( SYSTEM , " Moved file '%s' to '%s' " , from . c_str ( ) , to . c_str ( ) ) ;
}
2021-07-29 21:03:43 +00:00
}
}
}
// 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 ( ) ) ;
2021-10-04 21:47:39 +00:00
progressReporter_ . Set ( dirSuffix ) ;
if ( File : : Exists ( dir ) ) {
2021-07-29 21:03:43 +00:00
File : : DeleteDir ( dir ) ;
}
2021-07-24 22:16:30 +00:00
}
}
}
2021-09-18 13:10:31 +00:00
return new MoveResult { true , " " , failedFiles } ;
2023-01-15 15:55:07 +00:00
} , TaskType : : IO_BLOCKING , TaskPriority : : HIGH ) ;
2021-07-29 21:03:43 +00:00
RecreateViews ( ) ;
} else {
FinishFolderMove ( ) ;
2021-07-25 13:33:11 +00:00
}
2021-06-05 14:59:38 +00:00
2021-07-29 21:03:43 +00:00
return UI : : EVENT_DONE ;
}
void ConfirmMemstickMoveScreen : : FinishFolderMove ( ) {
2023-05-01 20:09:22 +00:00
auto ms = GetI18NCategory ( I18NCat : : MEMSTICK ) ;
2021-07-29 21:03:43 +00:00
2021-07-24 22:16:30 +00:00
// Successful so far, switch the memstick folder.
2021-07-26 20:15:34 +00:00
if ( ! SwitchMemstickFolderTo ( newMemstickFolder_ ) ) {
// TODO: More precise errors.
2023-05-01 20:09:22 +00:00
error_ = ms - > T ( " That folder doesn't work as a memstick folder. " ) ;
2021-07-29 21:03:43 +00:00
return ;
2021-07-26 20:15:34 +00:00
}
2021-07-24 22:16:30 +00:00
// If the chosen folder already had a config, reload it!
g_Config . Load ( ) ;
2023-08-18 13:51:16 +00:00
PostLoadConfig ( ) ;
2021-07-24 22:16:30 +00:00
2021-08-05 19:53:08 +00:00
if ( ! initialSetup_ ) {
// We restart the app here, to get the new settings.
2023-03-22 21:17:53 +00:00
System_RestartApp ( " " ) ;
2021-07-25 13:33:11 +00:00
} else {
2021-09-18 14:06:11 +00:00
// This is initial setup, we now switch to the main screen, if we were successful
// (which we better have been...)
if ( g_Config . Save ( " MemstickPathChanged " ) ) {
// TriggerFinish(DialogResult::DR_OK);
screenManager ( ) - > switchScreen ( new MainScreen ( ) ) ;
} else {
2023-05-01 20:09:22 +00:00
error_ = ms - > T ( " Failed to save config " ) ;
2021-09-18 14:06:11 +00:00
RecreateViews ( ) ;
}
2021-06-05 14:59:38 +00:00
}
}