From 78f6b1d3968a6c439cb36af74cae13c040c61af1 Mon Sep 17 00:00:00 2001
From: Jonathan Goyvaerts <jonathan.goyvaerts@gmail.com>
Date: Sun, 12 Jan 2020 04:01:04 +0100
Subject: [PATCH] Create method to LoadAndSave ApplicationMetaData and get rid
 of code duplication (#872)

---
 Ryujinx/Ui/ApplicationLibrary.cs  | 39 +++++++-----
 Ryujinx/Ui/ApplicationMetadata.cs |  2 +-
 Ryujinx/Ui/MainWindow.cs          | 99 +++++--------------------------
 3 files changed, 39 insertions(+), 101 deletions(-)

diff --git a/Ryujinx/Ui/ApplicationLibrary.cs b/Ryujinx/Ui/ApplicationLibrary.cs
index 90d333a252..2ab6107776 100644
--- a/Ryujinx/Ui/ApplicationLibrary.cs
+++ b/Ryujinx/Ui/ApplicationLibrary.cs
@@ -34,9 +34,8 @@ namespace Ryujinx.Ui
         private static readonly byte[] _nroIcon = GetResourceBytes("Ryujinx.Ui.assets.NROIcon.png");
         private static readonly byte[] _nsoIcon = GetResourceBytes("Ryujinx.Ui.assets.NSOIcon.png");
 
-        private static Keyset              _keySet;
-        private static TitleLanguage       _desiredTitleLanguage;
-        private static ApplicationMetadata _appMetadata;
+        private static Keyset        _keySet;
+        private static TitleLanguage _desiredTitleLanguage;
 
         public static void LoadApplications(List<string> appDirs, Keyset keySet, TitleLanguage desiredTitleLanguage, FileSystemClient fsClient = null, VirtualFileSystem vfs = null)
         {
@@ -339,7 +338,7 @@ namespace Ryujinx.Ui
                     }
                 }
 
-                (bool favorite, string timePlayed, string lastPlayed) = GetMetadata(titleId);
+                ApplicationMetadata appMetadata = LoadAndSaveMetaData(titleId);
 
                 if (ulong.TryParse(titleId, NumberStyles.HexNumber, CultureInfo.InvariantCulture, out ulong titleIdNum))
                 {
@@ -357,14 +356,14 @@ namespace Ryujinx.Ui
 
                 ApplicationData data = new ApplicationData()
                 {
-                    Favorite      = favorite,
+                    Favorite      = appMetadata.Favorite,
                     Icon          = applicationIcon,
                     TitleName     = titleName,
                     TitleId       = titleId,
                     Developer     = developer,
                     Version       = version,
-                    TimePlayed    = timePlayed,
-                    LastPlayed    = lastPlayed,
+                    TimePlayed    = ConvertSecondsToReadableString(appMetadata.TimePlayed),
+                    LastPlayed    = appMetadata.LastPlayed,
                     FileExtension = Path.GetExtension(applicationPath).ToUpper().Remove(0 ,1),
                     FileSize      = (fileSize < 1) ? (fileSize * 1024).ToString("0.##") + "MB" : fileSize.ToString("0.##") + "GB",
                     Path          = applicationPath,
@@ -431,34 +430,44 @@ namespace Ryujinx.Ui
             return controlNca?.OpenFileSystem(NcaSectionType.Data, IntegrityCheckLevel.None);
         }
 
-        private static (bool favorite, string timePlayed, string lastPlayed) GetMetadata(string titleId)
+        internal static ApplicationMetadata LoadAndSaveMetaData(string titleId, Action<ApplicationMetadata> modifyFunction = null)
         {
             string metadataFolder = Path.Combine(new VirtualFileSystem().GetBasePath(), "games", titleId, "gui");
-            string metadataFile   = Path.Combine(metadataFolder, "metadata.json");
+            string metadataFile = Path.Combine(metadataFolder, "metadata.json");
 
-            IJsonFormatterResolver resolver = CompositeResolver.Create(StandardResolver.AllowPrivateSnakeCase);
+            IJsonFormatterResolver resolver = CompositeResolver.Create(new[] { StandardResolver.AllowPrivateSnakeCase });
+
+            ApplicationMetadata appMetadata;
 
             if (!File.Exists(metadataFile))
             {
                 Directory.CreateDirectory(metadataFolder);
 
-                _appMetadata = new ApplicationMetadata
+                appMetadata = new ApplicationMetadata
                 {
                     Favorite   = false,
                     TimePlayed = 0,
                     LastPlayed = "Never"
                 };
 
-                byte[] saveData = JsonSerializer.Serialize(_appMetadata, resolver);
-                File.WriteAllText(metadataFile, Encoding.UTF8.GetString(saveData, 0, saveData.Length).PrettyPrintJson());
+                byte[] data = JsonSerializer.Serialize(appMetadata, resolver);
+                File.WriteAllText(metadataFile, Encoding.UTF8.GetString(data, 0, data.Length).PrettyPrintJson());
             }
 
             using (Stream stream = File.OpenRead(metadataFile))
             {
-                _appMetadata = JsonSerializer.Deserialize<ApplicationMetadata>(stream, resolver);
+                appMetadata = JsonSerializer.Deserialize<ApplicationMetadata>(stream, resolver);
             }
 
-            return (_appMetadata.Favorite, ConvertSecondsToReadableString(_appMetadata.TimePlayed), _appMetadata.LastPlayed);
+            if (modifyFunction != null)
+            {
+                modifyFunction(appMetadata);
+
+                byte[] saveData = JsonSerializer.Serialize(appMetadata, resolver);
+                File.WriteAllText(metadataFile, Encoding.UTF8.GetString(saveData, 0, saveData.Length).PrettyPrintJson());
+            }
+
+            return appMetadata;
         }
 
         private static string ConvertSecondsToReadableString(double seconds)
diff --git a/Ryujinx/Ui/ApplicationMetadata.cs b/Ryujinx/Ui/ApplicationMetadata.cs
index adc2b9df97..cdedf91b80 100644
--- a/Ryujinx/Ui/ApplicationMetadata.cs
+++ b/Ryujinx/Ui/ApplicationMetadata.cs
@@ -1,6 +1,6 @@
 namespace Ryujinx.Ui
 {
-    internal struct ApplicationMetadata
+    internal class ApplicationMetadata
     {
         public bool   Favorite   { get; set; }
         public double TimePlayed { get; set; }
diff --git a/Ryujinx/Ui/MainWindow.cs b/Ryujinx/Ui/MainWindow.cs
index 667ea5a5b9..c914a4a7a3 100644
--- a/Ryujinx/Ui/MainWindow.cs
+++ b/Ryujinx/Ui/MainWindow.cs
@@ -307,37 +307,10 @@ namespace Ryujinx.Ui
 
                 DiscordIntegrationModule.SwitchToPlayingState(_device.System.TitleId, _device.System.TitleName);
 
-                string metadataFolder = System.IO.Path.Combine(new VirtualFileSystem().GetBasePath(), "games", _device.System.TitleId, "gui");
-                string metadataFile   = System.IO.Path.Combine(metadataFolder, "metadata.json");
-
-                IJsonFormatterResolver resolver = CompositeResolver.Create(new[] { StandardResolver.AllowPrivateSnakeCase });
-
-                ApplicationMetadata appMetadata;
-
-                if (!File.Exists(metadataFile))
+                ApplicationLibrary.LoadAndSaveMetaData(_device.System.TitleId, appMetadata =>
                 {
-                    Directory.CreateDirectory(metadataFolder);
-
-                    appMetadata = new ApplicationMetadata
-                    {
-                        Favorite   = false,
-                        TimePlayed = 0,
-                        LastPlayed = "Never"
-                    };
-
-                    byte[] data = JsonSerializer.Serialize(appMetadata, resolver);
-                    File.WriteAllText(metadataFile, Encoding.UTF8.GetString(data, 0, data.Length).PrettyPrintJson());
-                }
-
-                using (Stream stream = File.OpenRead(metadataFile))
-                {
-                    appMetadata = JsonSerializer.Deserialize<ApplicationMetadata>(stream, resolver);
-                }
-
-                appMetadata.LastPlayed = DateTime.UtcNow.ToString();
-
-                byte[] saveData = JsonSerializer.Serialize(appMetadata, resolver);
-                File.WriteAllText(metadataFile, Encoding.UTF8.GetString(saveData, 0, saveData.Length).PrettyPrintJson());
+                    appMetadata.LastPlayed = DateTime.UtcNow.ToString();
+                });
             }
         }
 
@@ -364,40 +337,13 @@ namespace Ryujinx.Ui
 
             if (_gameLoaded)
             {
-                string metadataFolder = System.IO.Path.Combine(new VirtualFileSystem().GetBasePath(), "games", _device.System.TitleId, "gui");
-                string metadataFile   = System.IO.Path.Combine(metadataFolder, "metadata.json");
-
-                IJsonFormatterResolver resolver = CompositeResolver.Create(new[] { StandardResolver.AllowPrivateSnakeCase });
-
-                ApplicationMetadata appMetadata;
-
-                if (!File.Exists(metadataFile))
+                ApplicationLibrary.LoadAndSaveMetaData(_device.System.TitleId, appMetadata =>
                 {
-                    Directory.CreateDirectory(metadataFolder);
+                    DateTime lastPlayedDateTime = DateTime.Parse(appMetadata.LastPlayed);
+                    double sessionTimePlayed = DateTime.UtcNow.Subtract(lastPlayedDateTime).TotalSeconds;
 
-                    appMetadata = new ApplicationMetadata
-                    {
-                        Favorite   = false,
-                        TimePlayed = 0,
-                        LastPlayed = "Never"
-                    };
-
-                    byte[] data = JsonSerializer.Serialize(appMetadata, resolver);
-                    File.WriteAllText(metadataFile, Encoding.UTF8.GetString(data, 0, data.Length).PrettyPrintJson());
-                }
-
-                using (Stream stream = File.OpenRead(metadataFile))
-                {
-                    appMetadata = JsonSerializer.Deserialize<ApplicationMetadata>(stream, resolver);
-                }
-
-                DateTime lastPlayedDateTime = DateTime.Parse(appMetadata.LastPlayed);
-                double   sessionTimePlayed  = DateTime.UtcNow.Subtract(lastPlayedDateTime).TotalSeconds;
-
-                appMetadata.TimePlayed += Math.Round(sessionTimePlayed, MidpointRounding.AwayFromZero);
-
-                byte[] saveData = JsonSerializer.Serialize(appMetadata, resolver);
-                File.WriteAllText(metadataFile, Encoding.UTF8.GetString(saveData, 0, saveData.Length).PrettyPrintJson());
+                    appMetadata.TimePlayed += Math.Round(sessionTimePlayed, MidpointRounding.AwayFromZero);
+                });
             }
 
             Profile.FinishProfiling();
@@ -453,33 +399,16 @@ namespace Ryujinx.Ui
         {
             _tableStore.GetIter(out TreeIter treeIter, new TreePath(args.Path));
 
-            string titleId      = _tableStore.GetValue(treeIter, 2).ToString().Split("\n")[1].ToLower();
-            string metadataPath = System.IO.Path.Combine(new VirtualFileSystem().GetBasePath(), "games", titleId, "gui", "metadata.json");
+            string titleId = _tableStore.GetValue(treeIter, 2).ToString().Split("\n")[1].ToLower();
 
-            IJsonFormatterResolver resolver = CompositeResolver.Create(new[] { StandardResolver.AllowPrivateSnakeCase });
+            bool newToggleValue = !(bool)_tableStore.GetValue(treeIter, 0);
 
-            ApplicationMetadata appMetadata;
+            _tableStore.SetValue(treeIter, 0, newToggleValue);
 
-            using (Stream stream = File.OpenRead(metadataPath))
+            ApplicationLibrary.LoadAndSaveMetaData(titleId, appMetadata =>
             {
-                appMetadata = JsonSerializer.Deserialize<ApplicationMetadata>(stream, resolver);
-            }
-
-            if ((bool)_tableStore.GetValue(treeIter, 0))
-            {
-                _tableStore.SetValue(treeIter, 0, false);
-
-                appMetadata.Favorite = false;
-            }
-            else
-            {
-                _tableStore.SetValue(treeIter, 0, true);
-
-                appMetadata.Favorite = true;
-            }
-
-            byte[] saveData = JsonSerializer.Serialize(appMetadata, resolver);
-            File.WriteAllText(metadataPath, Encoding.UTF8.GetString(saveData, 0, saveData.Length).PrettyPrintJson());
+                appMetadata.Favorite = newToggleValue;
+            });
         }
 
         private void Row_Activated(object sender, RowActivatedArgs args)