summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--src/android/app/src/main/java/org/yuzu/yuzu_emu/fragments/InstallableFragment.kt12
-rw-r--r--src/android/app/src/main/java/org/yuzu/yuzu_emu/ui/main/MainActivity.kt91
-rw-r--r--src/android/app/src/main/res/values/strings.xml2
3 files changed, 33 insertions, 72 deletions
diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/fragments/InstallableFragment.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/fragments/InstallableFragment.kt
index ec116ab62..6940fc757 100644
--- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/fragments/InstallableFragment.kt
+++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/fragments/InstallableFragment.kt
@@ -21,6 +21,8 @@ import org.yuzu.yuzu_emu.databinding.FragmentInstallablesBinding
21import org.yuzu.yuzu_emu.model.HomeViewModel 21import org.yuzu.yuzu_emu.model.HomeViewModel
22import org.yuzu.yuzu_emu.model.Installable 22import org.yuzu.yuzu_emu.model.Installable
23import org.yuzu.yuzu_emu.ui.main.MainActivity 23import org.yuzu.yuzu_emu.ui.main.MainActivity
24import java.time.LocalDateTime
25import java.time.format.DateTimeFormatter
24 26
25class InstallableFragment : Fragment() { 27class InstallableFragment : Fragment() {
26 private var _binding: FragmentInstallablesBinding? = null 28 private var _binding: FragmentInstallablesBinding? = null
@@ -78,7 +80,15 @@ class InstallableFragment : Fragment() {
78 R.string.manage_save_data, 80 R.string.manage_save_data,
79 R.string.import_export_saves_description, 81 R.string.import_export_saves_description,
80 install = { mainActivity.importSaves.launch(arrayOf("application/zip")) }, 82 install = { mainActivity.importSaves.launch(arrayOf("application/zip")) },
81 export = { mainActivity.exportSave() } 83 export = {
84 mainActivity.exportSaves.launch(
85 "yuzu saves - ${
86 LocalDateTime.now().format(
87 DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm")
88 )
89 }.zip"
90 )
91 }
82 ) 92 )
83 } else { 93 } else {
84 Installable( 94 Installable(
diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/ui/main/MainActivity.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/ui/main/MainActivity.kt
index 211b7cf69..ace5dddea 100644
--- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/ui/main/MainActivity.kt
+++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/ui/main/MainActivity.kt
@@ -6,7 +6,6 @@ package org.yuzu.yuzu_emu.ui.main
6import android.content.Intent 6import android.content.Intent
7import android.net.Uri 7import android.net.Uri
8import android.os.Bundle 8import android.os.Bundle
9import android.provider.DocumentsContract
10import android.view.View 9import android.view.View
11import android.view.ViewGroup.MarginLayoutParams 10import android.view.ViewGroup.MarginLayoutParams
12import android.view.WindowManager 11import android.view.WindowManager
@@ -20,7 +19,6 @@ import androidx.core.splashscreen.SplashScreen.Companion.installSplashScreen
20import androidx.core.view.ViewCompat 19import androidx.core.view.ViewCompat
21import androidx.core.view.WindowCompat 20import androidx.core.view.WindowCompat
22import androidx.core.view.WindowInsetsCompat 21import androidx.core.view.WindowInsetsCompat
23import androidx.documentfile.provider.DocumentFile
24import androidx.lifecycle.Lifecycle 22import androidx.lifecycle.Lifecycle
25import androidx.lifecycle.lifecycleScope 23import androidx.lifecycle.lifecycleScope
26import androidx.lifecycle.repeatOnLifecycle 24import androidx.lifecycle.repeatOnLifecycle
@@ -41,7 +39,6 @@ import org.yuzu.yuzu_emu.NativeLibrary
41import org.yuzu.yuzu_emu.R 39import org.yuzu.yuzu_emu.R
42import org.yuzu.yuzu_emu.activities.EmulationActivity 40import org.yuzu.yuzu_emu.activities.EmulationActivity
43import org.yuzu.yuzu_emu.databinding.ActivityMainBinding 41import org.yuzu.yuzu_emu.databinding.ActivityMainBinding
44import org.yuzu.yuzu_emu.features.DocumentProvider
45import org.yuzu.yuzu_emu.features.settings.model.Settings 42import org.yuzu.yuzu_emu.features.settings.model.Settings
46import org.yuzu.yuzu_emu.fragments.IndeterminateProgressDialogFragment 43import org.yuzu.yuzu_emu.fragments.IndeterminateProgressDialogFragment
47import org.yuzu.yuzu_emu.fragments.MessageDialogFragment 44import org.yuzu.yuzu_emu.fragments.MessageDialogFragment
@@ -53,9 +50,6 @@ import org.yuzu.yuzu_emu.model.TaskViewModel
53import org.yuzu.yuzu_emu.utils.* 50import org.yuzu.yuzu_emu.utils.*
54import java.io.BufferedInputStream 51import java.io.BufferedInputStream
55import java.io.BufferedOutputStream 52import java.io.BufferedOutputStream
56import java.io.FileOutputStream
57import java.time.LocalDateTime
58import java.time.format.DateTimeFormatter
59import java.util.zip.ZipEntry 53import java.util.zip.ZipEntry
60import java.util.zip.ZipInputStream 54import java.util.zip.ZipInputStream
61 55
@@ -73,7 +67,6 @@ class MainActivity : AppCompatActivity(), ThemeProvider {
73 67
74 // Get first subfolder in saves folder (should be the user folder) 68 // Get first subfolder in saves folder (should be the user folder)
75 val savesFolderRoot get() = File(savesFolder).listFiles()?.firstOrNull()?.canonicalPath ?: "" 69 val savesFolderRoot get() = File(savesFolder).listFiles()?.firstOrNull()?.canonicalPath ?: ""
76 private var lastZipCreated: File? = null
77 70
78 override fun onCreate(savedInstanceState: Bundle?) { 71 override fun onCreate(savedInstanceState: Bundle?) {
79 val splashScreen = installSplashScreen() 72 val splashScreen = installSplashScreen()
@@ -657,74 +650,30 @@ class MainActivity : AppCompatActivity(), ThemeProvider {
657 } 650 }
658 651
659 /** 652 /**
660 * Zips the save files located in the given folder path and creates a new zip file with the current date and time.
661 * @return true if the zip file is successfully created, false otherwise.
662 */
663 private fun zipSave(): Boolean {
664 try {
665 val tempFolder = File(getPublicFilesDir().canonicalPath, "temp")
666 tempFolder.mkdirs()
667 val saveFolder = File(savesFolderRoot)
668 val outputZipFile = File(
669 tempFolder,
670 "yuzu saves - ${
671 LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm"))
672 }.zip"
673 )
674 outputZipFile.createNewFile()
675 val result = FileUtil.zipFromInternalStorage(
676 saveFolder,
677 savesFolderRoot,
678 BufferedOutputStream(FileOutputStream(outputZipFile))
679 )
680 if (result == TaskState.Failed) {
681 return false
682 }
683 lastZipCreated = outputZipFile
684 } catch (e: Exception) {
685 return false
686 }
687 return true
688 }
689
690 /**
691 * Exports the save file located in the given folder path by creating a zip file and sharing it via intent. 653 * Exports the save file located in the given folder path by creating a zip file and sharing it via intent.
692 */ 654 */
693 fun exportSave() { 655 val exportSaves = registerForActivityResult(
694 CoroutineScope(Dispatchers.IO).launch { 656 ActivityResultContracts.CreateDocument("application/zip")
695 val wasZipCreated = zipSave() 657 ) { result ->
696 val lastZipFile = lastZipCreated 658 if (result == null) {
697 if (!wasZipCreated || lastZipFile == null) { 659 return@registerForActivityResult
698 withContext(Dispatchers.Main) { 660 }
699 Toast.makeText(
700 this@MainActivity,
701 getString(R.string.export_save_failed),
702 Toast.LENGTH_LONG
703 ).show()
704 }
705 return@launch
706 }
707 661
708 withContext(Dispatchers.Main) { 662 IndeterminateProgressDialogFragment.newInstance(
709 val file = DocumentFile.fromSingleUri( 663 this,
710 this@MainActivity, 664 R.string.save_files_exporting,
711 DocumentsContract.buildDocumentUri( 665 false
712 DocumentProvider.AUTHORITY, 666 ) {
713 "${DocumentProvider.ROOT_ID}/temp/${lastZipFile.name}" 667 val zipResult = FileUtil.zipFromInternalStorage(
714 ) 668 File(savesFolderRoot),
715 )!! 669 savesFolderRoot,
716 val intent = Intent(Intent.ACTION_SEND) 670 BufferedOutputStream(contentResolver.openOutputStream(result))
717 .setDataAndType(file.uri, "application/zip") 671 )
718 .addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION) 672 return@newInstance when (zipResult) {
719 .putExtra(Intent.EXTRA_STREAM, file.uri) 673 TaskState.Completed -> getString(R.string.export_success)
720 startForResultExportSave.launch( 674 TaskState.Cancelled, TaskState.Failed -> getString(R.string.export_failed)
721 Intent.createChooser(
722 intent,
723 getString(R.string.share_save_file)
724 )
725 )
726 } 675 }
727 } 676 }.show(supportFragmentManager, IndeterminateProgressDialogFragment.TAG)
728 } 677 }
729 678
730 private val startForResultExportSave = 679 private val startForResultExportSave =
diff --git a/src/android/app/src/main/res/values/strings.xml b/src/android/app/src/main/res/values/strings.xml
index 98c3f20f8..471af8795 100644
--- a/src/android/app/src/main/res/values/strings.xml
+++ b/src/android/app/src/main/res/values/strings.xml
@@ -91,6 +91,7 @@
91 <string name="manage_save_data">Manage save data</string> 91 <string name="manage_save_data">Manage save data</string>
92 <string name="manage_save_data_description">Save data found. Please select an option below.</string> 92 <string name="manage_save_data_description">Save data found. Please select an option below.</string>
93 <string name="import_export_saves_description">Import or export save files</string> 93 <string name="import_export_saves_description">Import or export save files</string>
94 <string name="save_files_exporting">Exporting save files…</string>
94 <string name="save_file_imported_success">Imported successfully</string> 95 <string name="save_file_imported_success">Imported successfully</string>
95 <string name="save_file_invalid_zip_structure">Invalid save directory structure</string> 96 <string name="save_file_invalid_zip_structure">Invalid save directory structure</string>
96 <string name="save_file_invalid_zip_structure_description">The first subfolder name must be the title ID of the game.</string> 97 <string name="save_file_invalid_zip_structure_description">The first subfolder name must be the title ID of the game.</string>
@@ -256,6 +257,7 @@
256 <string name="cancelling">Cancelling</string> 257 <string name="cancelling">Cancelling</string>
257 <string name="install">Install</string> 258 <string name="install">Install</string>
258 <string name="delete">Delete</string> 259 <string name="delete">Delete</string>
260 <string name="export_success">Exported successfully</string>
259 261
260 <!-- GPU driver installation --> 262 <!-- GPU driver installation -->
261 <string name="select_gpu_driver">Select GPU driver</string> 263 <string name="select_gpu_driver">Select GPU driver</string>