From a620cbcc9050d7d3b0932d97db87628dd4e97b0a Mon Sep 17 00:00:00 2001
From: Isaac Marovitz <42140194+IsaacMarovitz@users.noreply.github.com>
Date: Fri, 26 Jan 2024 14:25:48 +0000
Subject: Ava UI: Mod Manager Fixes (#6179)

* Fix string format + Crash

* Better Logging

* Properly Delete Mods

Rename

* Catch when trying to access bad directory
---
 src/Ryujinx.Ava/Assets/Locales/en_US.json          |  2 +
 .../UI/ViewModels/ModManagerViewModel.cs           | 70 ++++++++++++++++++++--
 src/Ryujinx.HLE/HOS/ModLoader.cs                   |  2 +-
 3 files changed, 69 insertions(+), 5 deletions(-)

(limited to 'src')

diff --git a/src/Ryujinx.Ava/Assets/Locales/en_US.json b/src/Ryujinx.Ava/Assets/Locales/en_US.json
index 79692a08..8b38490f 100644
--- a/src/Ryujinx.Ava/Assets/Locales/en_US.json
+++ b/src/Ryujinx.Ava/Assets/Locales/en_US.json
@@ -383,6 +383,8 @@
   "DialogControllerSettingsModifiedConfirmSubMessage": "Do you want to save?",
   "DialogLoadFileErrorMessage": "{0}. Errored File: {1}",
   "DialogModAlreadyExistsMessage": "Mod already exists",
+  "DialogModInvalidMessage": "The specified directory does not contain a mod!",
+  "DialogModDeleteNoParentMessage": "Failed to Delete: Could not find the parent directory for mod \"{0}\"!",
   "DialogDlcNoDlcErrorMessage": "The specified file does not contain a DLC for the selected title!",
   "DialogPerformanceCheckLoggingEnabledMessage": "You have trace logging enabled, which is designed to be used by developers only.",
   "DialogPerformanceCheckLoggingEnabledConfirmMessage": "For optimal performance, it's recommended to disable trace logging. Would you like to disable trace logging now?",
diff --git a/src/Ryujinx.Ava/UI/ViewModels/ModManagerViewModel.cs b/src/Ryujinx.Ava/UI/ViewModels/ModManagerViewModel.cs
index 7340873a..2c29660b 100644
--- a/src/Ryujinx.Ava/UI/ViewModels/ModManagerViewModel.cs
+++ b/src/Ryujinx.Ava/UI/ViewModels/ModManagerViewModel.cs
@@ -8,8 +8,10 @@ using Ryujinx.Ava.Common.Locale;
 using Ryujinx.Ava.UI.Helpers;
 using Ryujinx.Ava.UI.Models;
 using Ryujinx.Common.Configuration;
+using Ryujinx.Common.Logging;
 using Ryujinx.Common.Utilities;
 using Ryujinx.HLE.HOS;
+using System;
 using System.IO;
 using System.Linq;
 
@@ -181,7 +183,30 @@ namespace Ryujinx.Ava.UI.ViewModels
 
         public void Delete(ModModel model)
         {
-            Directory.Delete(model.Path, true);
+            var modsDir = ModLoader.GetApplicationDir(ModLoader.GetSdModsBasePath(), _applicationId.ToString("x16"));
+            var parentDir = String.Empty;
+
+            foreach (var dir in Directory.GetDirectories(modsDir, "*", SearchOption.TopDirectoryOnly))
+            {
+                if (Directory.GetDirectories(dir, "*", SearchOption.AllDirectories).Contains(model.Path))
+                {
+                    parentDir = dir;
+                }
+            }
+
+            if (parentDir == String.Empty)
+            {
+                Dispatcher.UIThread.Post(async () =>
+                {
+                    await ContentDialogHelper.CreateErrorDialog(LocaleManager.Instance.UpdateAndGetDynamicValue(
+                        LocaleKeys.DialogModDeleteNoParentMessage,
+                        parentDir));
+                });
+                return;
+            }
+
+            Logger.Info?.Print(LogClass.Application, $"Deleting mod at \"{model.Path}\"");
+            Directory.Delete(parentDir, true);
 
             Mods.Remove(model);
             OnPropertyChanged(nameof(ModCount));
@@ -190,9 +215,43 @@ namespace Ryujinx.Ava.UI.ViewModels
 
         private void AddMod(DirectoryInfo directory)
         {
-            var directories = Directory.GetDirectories(directory.ToString(), "*", SearchOption.AllDirectories);
+            string[] directories;
+
+            try
+            {
+                directories = Directory.GetDirectories(directory.ToString(), "*", SearchOption.AllDirectories);
+            }
+            catch (Exception exception)
+            {
+                Dispatcher.UIThread.Post(async () =>
+                {
+                    await ContentDialogHelper.CreateErrorDialog(LocaleManager.Instance.UpdateAndGetDynamicValue(
+                        LocaleKeys.DialogLoadFileErrorMessage,
+                        exception.ToString(),
+                        directory));
+                });
+                return;
+            }
+
             var destinationDir = ModLoader.GetApplicationDir(ModLoader.GetSdModsBasePath(), _applicationId.ToString("x16"));
 
+            // TODO: More robust checking for valid mod folders
+            var isDirectoryValid = true;
+
+            if (directories.Length == 0)
+            {
+                isDirectoryValid = false;
+            }
+
+            if (!isDirectoryValid)
+            {
+                Dispatcher.UIThread.Post(async () =>
+                {
+                    await ContentDialogHelper.CreateErrorDialog(LocaleManager.Instance[LocaleKeys.DialogModInvalidMessage]);
+                });
+                return;
+            }
+
             foreach (var dir in directories)
             {
                 string dirToCreate = dir.Replace(directory.Parent.ToString(), destinationDir);
@@ -202,7 +261,10 @@ namespace Ryujinx.Ava.UI.ViewModels
                 {
                     Dispatcher.UIThread.Post(async () =>
                     {
-                        await ContentDialogHelper.CreateErrorDialog(LocaleManager.Instance.UpdateAndGetDynamicValue(LocaleKeys.DialogLoadFileErrorMessage, LocaleKeys.DialogModAlreadyExistsMessage, dirToCreate));
+                        await ContentDialogHelper.CreateErrorDialog(LocaleManager.Instance.UpdateAndGetDynamicValue(
+                            LocaleKeys.DialogLoadFileErrorMessage,
+                            LocaleManager.Instance[LocaleKeys.DialogModAlreadyExistsMessage],
+                            dirToCreate));
                     });
 
                     return;
@@ -239,7 +301,7 @@ namespace Ryujinx.Ava.UI.ViewModels
         {
             foreach (var mod in Mods)
             {
-                Directory.Delete(mod.Path, true);
+                Delete(mod);
             }
 
             Mods.Clear();
diff --git a/src/Ryujinx.HLE/HOS/ModLoader.cs b/src/Ryujinx.HLE/HOS/ModLoader.cs
index 669c775b..322c8afd 100644
--- a/src/Ryujinx.HLE/HOS/ModLoader.cs
+++ b/src/Ryujinx.HLE/HOS/ModLoader.cs
@@ -324,7 +324,7 @@ namespace Ryujinx.HLE.HOS
                 return;
             }
 
-            Logger.Info?.Print(LogClass.ModLoader, $"Searching mods for {((applicationId & 0x1000) != 0 ? "DLC" : "Application")} {applicationId:X16}");
+            Logger.Info?.Print(LogClass.ModLoader, $"Searching mods for {((applicationId & 0x1000) != 0 ? "DLC" : "Application")} {applicationId:X16} in \"{contentsDir.FullName}\"");
 
             var applicationDir = FindApplicationDir(contentsDir, $"{applicationId:x16}");
 
-- 
cgit v1.2.3-70-g09d2