From 844e0360c78ad0eb5dd2dcad5a38667df89f921f Mon Sep 17 00:00:00 2001 From: xbzk Date: Thu, 19 Mar 2026 05:38:57 +0100 Subject: [PATCH] [addons] fixed manual installation from per-game fragment (#3743) maybe consequence of code centralization. reverted for now. -please test: install update from per-game path -install update on manage eden data path -install update when another update is already installed and check both versions Reviewed-on: https://git.eden-emu.dev/eden-emu/eden/pulls/3743 Reviewed-by: MaranBr Reviewed-by: Lizzie Reviewed-by: CamilleLaVey Co-authored-by: xbzk Co-committed-by: xbzk --- .../yuzu/yuzu_emu/fragments/AddonsFragment.kt | 20 +++++- .../ContentTypeSelectionDialogFragment.kt | 65 ++--------------- .../yuzu_emu/fragments/InstallableFragment.kt | 67 ++--------------- .../org/yuzu/yuzu_emu/ui/main/MainActivity.kt | 44 ------------ .../yuzu/yuzu_emu/utils/InstallableActions.kt | 72 +++++++++++++++++++ 5 files changed, 103 insertions(+), 165 deletions(-) diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/fragments/AddonsFragment.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/fragments/AddonsFragment.kt index b20d75ef0a..96632b4606 100644 --- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/fragments/AddonsFragment.kt +++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/fragments/AddonsFragment.kt @@ -25,6 +25,7 @@ import org.yuzu.yuzu_emu.model.AddonViewModel import org.yuzu.yuzu_emu.model.HomeViewModel import org.yuzu.yuzu_emu.utils.AddonUtil import org.yuzu.yuzu_emu.utils.FileUtil.copyFilesTo +import org.yuzu.yuzu_emu.utils.InstallableActions import org.yuzu.yuzu_emu.utils.ViewUtils.updateMargins import org.yuzu.yuzu_emu.utils.collect import java.io.File @@ -107,6 +108,12 @@ class AddonsFragment : Fragment() { ).show(parentFragmentManager, MessageDialogFragment.TAG) } } + parentFragmentManager.setFragmentResultListener( + ContentTypeSelectionDialogFragment.REQUEST_INSTALL_GAME_UPDATE, + viewLifecycleOwner + ) { _, _ -> + installGameUpdate.launch(arrayOf("*/*")) + } binding.buttonInstall.setOnClickListener { ContentTypeSelectionDialogFragment().show( @@ -130,7 +137,7 @@ class AddonsFragment : Fragment() { super.onDestroy() } - val installAddon = + private val installAddon = registerForActivityResult(ActivityResultContracts.OpenDocumentTree()) { result -> if (result == null) { return@registerForActivityResult @@ -175,6 +182,17 @@ class AddonsFragment : Fragment() { } } + private val installGameUpdate = + registerForActivityResult(ActivityResultContracts.OpenMultipleDocuments()) { documents -> + InstallableActions.verifyAndInstallContent( + activity = requireActivity(), + fragmentManager = parentFragmentManager, + addonViewModel = addonViewModel, + documents = documents, + programId = args.game.programId + ) + } + private fun setInsets() = ViewCompat.setOnApplyWindowInsetsListener( binding.root diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/fragments/ContentTypeSelectionDialogFragment.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/fragments/ContentTypeSelectionDialogFragment.kt index 880c2ff3bf..fb59a3a52c 100644 --- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/fragments/ContentTypeSelectionDialogFragment.kt +++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/fragments/ContentTypeSelectionDialogFragment.kt @@ -8,18 +8,14 @@ package org.yuzu.yuzu_emu.fragments import android.app.Dialog import android.content.DialogInterface -import android.net.Uri import android.os.Bundle -import androidx.activity.result.contract.ActivityResultContracts import androidx.fragment.app.DialogFragment import androidx.fragment.app.activityViewModels import androidx.preference.PreferenceManager import com.google.android.material.dialog.MaterialAlertDialogBuilder -import org.yuzu.yuzu_emu.NativeLibrary import org.yuzu.yuzu_emu.R import org.yuzu.yuzu_emu.YuzuApplication import org.yuzu.yuzu_emu.model.AddonViewModel -import org.yuzu.yuzu_emu.utils.InstallableActions class ContentTypeSelectionDialogFragment : DialogFragment() { private val addonViewModel: AddonViewModel by activityViewModels() @@ -29,52 +25,6 @@ class ContentTypeSelectionDialogFragment : DialogFragment() { private var selectedItem = 0 - private val installGameUpdateLauncher = - registerForActivityResult(ActivityResultContracts.OpenMultipleDocuments()) { documents -> - if (documents.isEmpty()) { - return@registerForActivityResult - } - - val game = addonViewModel.game - if (game == null) { - installContent(documents) - return@registerForActivityResult - } - - ProgressDialogFragment.newInstance( - requireActivity(), - R.string.verifying_content, - false - ) { _, _ -> - var updatesMatchProgram = true - for (document in documents) { - val valid = NativeLibrary.doesUpdateMatchProgram( - game.programId, - document.toString() - ) - if (!valid) { - updatesMatchProgram = false - break - } - } - - requireActivity().runOnUiThread { - if (updatesMatchProgram) { - installContent(documents) - } else { - MessageDialogFragment.newInstance( - requireActivity(), - titleId = R.string.content_install_notice, - descriptionId = R.string.content_install_notice_description, - positiveAction = { installContent(documents) }, - negativeAction = {} - ).show(parentFragmentManager, MessageDialogFragment.TAG) - } - } - return@newInstance Any() - }.show(parentFragmentManager, ProgressDialogFragment.TAG) - } - override fun onCreateDialog(savedInstanceState: Bundle?): Dialog { val launchOptions = arrayOf(getString(R.string.updates_and_dlc), getString(R.string.mods_and_cheats)) @@ -87,7 +37,10 @@ class ContentTypeSelectionDialogFragment : DialogFragment() { .setTitle(R.string.select_content_type) .setPositiveButton(android.R.string.ok) { _: DialogInterface, _: Int -> when (selectedItem) { - 0 -> installGameUpdateLauncher.launch(arrayOf("*/*")) + 0 -> parentFragmentManager.setFragmentResult( + REQUEST_INSTALL_GAME_UPDATE, + Bundle() + ) else -> { if (!preferences.getBoolean(MOD_NOTICE_SEEN, false)) { preferences.edit().putBoolean(MOD_NOTICE_SEEN, true).apply() @@ -112,17 +65,9 @@ class ContentTypeSelectionDialogFragment : DialogFragment() { companion object { const val TAG = "ContentTypeSelectionDialogFragment" + const val REQUEST_INSTALL_GAME_UPDATE = "RequestInstallGameUpdate" private const val SELECTED_ITEM = "SelectedItem" private const val MOD_NOTICE_SEEN = "ModNoticeSeen" } - - private fun installContent(documents: List) { - InstallableActions.installContent( - activity = requireActivity(), - fragmentManager = parentFragmentManager, - addonViewModel = addonViewModel, - documents = documents - ) - } } 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 10862c37b4..6510c069e3 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 @@ -227,66 +227,13 @@ class InstallableFragment : Fragment() { private val installGameUpdateLauncher = registerForActivityResult(ActivityResultContracts.OpenMultipleDocuments()) { documents -> - if (documents.isEmpty()) { - return@registerForActivityResult - } - - if (addonViewModel.game == null) { - InstallableActions.installContent( - activity = requireActivity(), - fragmentManager = parentFragmentManager, - addonViewModel = addonViewModel, - documents = documents - ) - return@registerForActivityResult - } - - ProgressDialogFragment.newInstance( - requireActivity(), - R.string.verifying_content, - false - ) { _, _ -> - var updatesMatchProgram = true - for (document in documents) { - val valid = NativeLibrary.doesUpdateMatchProgram( - addonViewModel.game!!.programId, - document.toString() - ) - if (!valid) { - updatesMatchProgram = false - break - } - } - - if (updatesMatchProgram) { - requireActivity().runOnUiThread { - InstallableActions.installContent( - activity = requireActivity(), - fragmentManager = parentFragmentManager, - addonViewModel = addonViewModel, - documents = documents - ) - } - } else { - requireActivity().runOnUiThread { - MessageDialogFragment.newInstance( - requireActivity(), - titleId = R.string.content_install_notice, - descriptionId = R.string.content_install_notice_description, - positiveAction = { - InstallableActions.installContent( - activity = requireActivity(), - fragmentManager = parentFragmentManager, - addonViewModel = addonViewModel, - documents = documents - ) - }, - negativeAction = {} - ).show(parentFragmentManager, MessageDialogFragment.TAG) - } - } - return@newInstance Any() - }.show(parentFragmentManager, ProgressDialogFragment.TAG) + InstallableActions.verifyAndInstallContent( + activity = requireActivity(), + fragmentManager = parentFragmentManager, + addonViewModel = addonViewModel, + documents = documents, + programId = addonViewModel.game?.programId + ) } private val importUserDataLauncher = 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 f0806df786..3a771edfcb 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 @@ -32,7 +32,6 @@ import org.yuzu.yuzu_emu.databinding.ActivityMainBinding import org.yuzu.yuzu_emu.dialogs.NetPlayDialog import org.yuzu.yuzu_emu.features.settings.model.Settings import org.yuzu.yuzu_emu.fragments.AddGameFolderDialogFragment -import org.yuzu.yuzu_emu.fragments.ProgressDialogFragment import org.yuzu.yuzu_emu.fragments.MessageDialogFragment import org.yuzu.yuzu_emu.model.AddonViewModel import org.yuzu.yuzu_emu.model.DriverViewModel @@ -479,49 +478,6 @@ class MainActivity : AppCompatActivity(), ThemeProvider { ) } - val installGameUpdate = registerForActivityResult( - ActivityResultContracts.OpenMultipleDocuments() - ) { documents: List -> - if (documents.isEmpty()) { - return@registerForActivityResult - } - - if (addonViewModel.game == null) { - installContent(documents) - return@registerForActivityResult - } - - ProgressDialogFragment.newInstance( - this@MainActivity, - R.string.verifying_content, - false - ) { _, _ -> - var updatesMatchProgram = true - for (document in documents) { - val valid = NativeLibrary.doesUpdateMatchProgram( - addonViewModel.game!!.programId, - document.toString() - ) - if (!valid) { - updatesMatchProgram = false - break - } - } - - if (updatesMatchProgram) { - homeViewModel.setContentToInstall(documents) - } else { - MessageDialogFragment.newInstance( - this@MainActivity, - titleId = R.string.content_install_notice, - descriptionId = R.string.content_install_notice_description, - positiveAction = { homeViewModel.setContentToInstall(documents) }, - negativeAction = {} - ) - } - }.show(supportFragmentManager, ProgressDialogFragment.TAG) - } - private fun installContent(documents: List) { InstallableActions.installContent( activity = this, diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/utils/InstallableActions.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/utils/InstallableActions.kt index d385e2a095..882bae965b 100644 --- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/utils/InstallableActions.kt +++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/utils/InstallableActions.kt @@ -26,6 +26,78 @@ import java.util.zip.ZipEntry import java.util.zip.ZipInputStream object InstallableActions { + private fun verifyGameContentAndInstall( + activity: FragmentActivity, + fragmentManager: FragmentManager, + documents: List, + programId: String?, + onInstallConfirmed: () -> Unit + ) { + if (documents.isEmpty()) { + return + } + + if (programId == null) { + onInstallConfirmed() + return + } + + ProgressDialogFragment.newInstance( + activity, + R.string.verifying_content, + false + ) { _, _ -> + var updatesMatchProgram = true + for (document in documents) { + val valid = NativeLibrary.doesUpdateMatchProgram( + programId, + document.toString() + ) + if (!valid) { + updatesMatchProgram = false + break + } + } + + activity.runOnUiThread { + if (updatesMatchProgram) { + onInstallConfirmed() + } else { + MessageDialogFragment.newInstance( + activity, + titleId = R.string.content_install_notice, + descriptionId = R.string.content_install_notice_description, + positiveAction = onInstallConfirmed, + negativeAction = {} + ).show(fragmentManager, MessageDialogFragment.TAG) + } + } + return@newInstance Any() + }.show(fragmentManager, ProgressDialogFragment.TAG) + } + + fun verifyAndInstallContent( + activity: FragmentActivity, + fragmentManager: FragmentManager, + addonViewModel: AddonViewModel, + documents: List, + programId: String? + ) { + verifyGameContentAndInstall( + activity = activity, + fragmentManager = fragmentManager, + documents = documents, + programId = programId + ) { + installContent( + activity = activity, + fragmentManager = fragmentManager, + addonViewModel = addonViewModel, + documents = documents + ) + } + } + fun processKey( activity: FragmentActivity, fragmentManager: FragmentManager,