diff --git a/Plugins/Wox.Plugin.Program/Logger/ProgramLogger.cs b/Plugins/Wox.Plugin.Program/Logger/ProgramLogger.cs index 587aba685..d9f92bca2 100644 --- a/Plugins/Wox.Plugin.Program/Logger/ProgramLogger.cs +++ b/Plugins/Wox.Plugin.Program/Logger/ProgramLogger.cs @@ -1,4 +1,4 @@ -using NLog; +using NLog; using NLog.Config; using NLog.Targets; using System; @@ -7,6 +7,7 @@ using System.Runtime.CompilerServices; using System.Security; using Wox.Infrastructure; +using Wox.Infrastructure.UserSettings; namespace Wox.Plugin.Program.Logger { @@ -21,7 +22,7 @@ internal static class ProgramLogger static ProgramLogger() { - var path = Path.Combine(Constant.DataDirectory, DirectoryName, Constant.Version); + var path = Path.Combine(DataLocation.DataDirectory(), DirectoryName, Constant.Version); if (!Directory.Exists(path)) { Directory.CreateDirectory(path); diff --git a/Wox.Core/Configuration/IPortable.cs b/Wox.Core/Configuration/IPortable.cs new file mode 100644 index 000000000..b0af43672 --- /dev/null +++ b/Wox.Core/Configuration/IPortable.cs @@ -0,0 +1,16 @@ + +namespace Wox.Core.Configuration +{ + public interface IPortable + { + void EnablePortableMode(); + void DisablePortableMode(); + void RemoveShortcuts(); + void RemoveUninstallerEntry(); + void CreateShortcuts(); + void CreateUninstallerEntry(); + void MoveUserDataFolder(string fromLocation, string toLocation); + void VerifyUserDataAfterMove(string fromLocation, string toLocation); + bool CanUpdatePortability(); + } +} \ No newline at end of file diff --git a/Wox.Core/Configuration/Portable.cs b/Wox.Core/Configuration/Portable.cs new file mode 100644 index 000000000..ee916001b --- /dev/null +++ b/Wox.Core/Configuration/Portable.cs @@ -0,0 +1,203 @@ +using Microsoft.Win32; +using Squirrel; +using System; +using System.IO; +using System.Reflection; +using System.Windows; +using Wox.Infrastructure; +using Wox.Infrastructure.Logger; +using Wox.Infrastructure.UserSettings; +using Wox.Plugin.SharedCommands; + +namespace Wox.Core.Configuration +{ + public class Portable : IPortable + { + /// + /// As at Squirrel.Windows version 1.5.2, UpdateManager needs to be disposed after finish + /// + /// + private UpdateManager NewUpdateManager() + { + return new UpdateManager(string.Empty, Constant.Wox, Constant.RootDirectory); + } + + public void DisablePortableMode() + { + try + { + MoveUserDataFolder(DataLocation.PortableDataPath, DataLocation.RoamingDataPath); +#if DEBUG + // Create shortcuts and uninstaller are not required in debug mode, + // otherwise will repoint the path of the actual installed production version to the debug version +#else + CreateShortcuts(); + CreateUninstallerEntry(); +#endif + IndicateDeletion(DataLocation.PortableDataPath); + + MessageBox.Show("Wox needs to restart to finish disabling portable mode, " + + "after the restart your portable data profile will be deleted and roaming data profile kept"); + + UpdateManager.RestartApp(); + } + catch (Exception e) + { +#if !DEBUG + Log.Exception("Portable", "Error occured while disabling portable mode", e); +#endif + throw; + } + } + + public void EnablePortableMode() + { + try + { + MoveUserDataFolder(DataLocation.RoamingDataPath, DataLocation.PortableDataPath); +#if DEBUG + // Remove shortcuts and uninstaller are not required in debug mode, + // otherwise will delete the actual installed production version +#else + RemoveShortcuts(); + RemoveUninstallerEntry(); +#endif + IndicateDeletion(DataLocation.RoamingDataPath); + + MessageBox.Show("Wox needs to restart to finish enabling portable mode, " + + "after the restart your roaming data profile will be deleted and portable data profile kept"); + + UpdateManager.RestartApp(); + } + catch (Exception e) + { +#if !DEBUG + Log.Exception("Portable", "Error occured while enabling portable mode", e); +#endif + throw; + } + } + + public void RemoveShortcuts() + { + using (var portabilityUpdater = NewUpdateManager()) + { + var exeName = Constant.Wox + ".exe"; + portabilityUpdater.RemoveShortcutsForExecutable(exeName, ShortcutLocation.StartMenu); + portabilityUpdater.RemoveShortcutsForExecutable(exeName, ShortcutLocation.Desktop); + portabilityUpdater.RemoveShortcutsForExecutable(exeName, ShortcutLocation.Startup); + } + } + + public void RemoveUninstallerEntry() + { + using (var portabilityUpdater = NewUpdateManager()) + { + portabilityUpdater.RemoveUninstallerRegistryEntry(); + } + } + + public void MoveUserDataFolder(string fromLocation, string toLocation) + { + FilesFolders.Copy(fromLocation, toLocation); + VerifyUserDataAfterMove(fromLocation, toLocation); + } + + public void VerifyUserDataAfterMove(string fromLocation, string toLocation) + { + FilesFolders.VerifyBothFolderFilesEqual(fromLocation, toLocation); + } + + public void CreateShortcuts() + { + using (var portabilityUpdater = NewUpdateManager()) + { + var exeName = Constant.Wox + ".exe"; + portabilityUpdater.CreateShortcutsForExecutable(exeName, ShortcutLocation.StartMenu, false); + portabilityUpdater.CreateShortcutsForExecutable(exeName, ShortcutLocation.Desktop, false); + portabilityUpdater.CreateShortcutsForExecutable(exeName, ShortcutLocation.Startup, false); + } + } + + public void CreateUninstallerEntry() + { + var uninstallRegSubKey = @"Software\Microsoft\Windows\CurrentVersion\Uninstall"; + // NB: Sometimes the Uninstall key doesn't exist + using (var parentKey = + RegistryKey.OpenBaseKey(RegistryHive.CurrentUser, RegistryView.Default) + .CreateSubKey("Uninstall", RegistryKeyPermissionCheck.ReadWriteSubTree)) {; } + + var key = RegistryKey.OpenBaseKey(RegistryHive.CurrentUser, RegistryView.Default) + .CreateSubKey(uninstallRegSubKey + "\\" + Constant.Wox, RegistryKeyPermissionCheck.ReadWriteSubTree); + key.SetValue("DisplayIcon", Constant.ApplicationDirectory + "\\app.ico", RegistryValueKind.String); + + using (var portabilityUpdater = NewUpdateManager()) + { + portabilityUpdater.CreateUninstallerRegistryEntry(); + } + } + + internal void IndicateDeletion(string filePathTodelete) + { + using (StreamWriter sw = File.CreateText(filePathTodelete + "\\" + DataLocation.DeletionIndicatorFile)){} + } + + /// + ///This method should be run at first before all methods during start up and should be run before determining which data location + ///will be used for Wox. + /// + public void PreStartCleanUpAfterPortabilityUpdate() + { + // Specify here so this method does not rely on other environment variables to initialise + var portableDataPath = Path.Combine(Directory.GetParent(Assembly.GetExecutingAssembly().Location.NonNull()).ToString(), "UserData"); + var roamingDataPath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData), "Wox"); + + bool DataLocationPortableDeleteRequired = false; + bool DataLocationRoamingDeleteRequired = false; + + if ((roamingDataPath + "\\" + DataLocation.DeletionIndicatorFile).FileExits()) + DataLocationRoamingDeleteRequired = true; + + if ((portableDataPath + "\\" + DataLocation.DeletionIndicatorFile).FileExits()) + DataLocationPortableDeleteRequired = true; + + if (DataLocationRoamingDeleteRequired) + { + if(roamingDataPath.LocationExists()) + MessageBox.Show("Wox detected you restarted after enabling portable mode, " + + "your roaming data profile will now be deleted"); + + FilesFolders.RemoveFolderIfExists(roamingDataPath); + + return; + } + + if(DataLocationPortableDeleteRequired) + { + MessageBox.Show("Wox detected you restarted after disabling portable mode, " + + "your portable data profile will now be deleted"); + + FilesFolders.RemoveFolderIfExists(portableDataPath); + + return; + } + } + + public bool CanUpdatePortability() + { + var roamingLocationExists = DataLocation.RoamingDataPath.LocationExists(); + var portableLocationExists = DataLocation.PortableDataPath.LocationExists(); + + if(roamingLocationExists && portableLocationExists) + { + MessageBox.Show(string.Format("Wox detected your user data exists both in {0} and " + + "{1}. {2}{2}Please delete {1} in order to proceed. No changes have occured.", + DataLocation.PortableDataPath, DataLocation.RoamingDataPath, Environment.NewLine)); + + return false; + } + + return true; + } + } +} diff --git a/Wox.Core/Plugin/PluginInstaller.cs b/Wox.Core/Plugin/PluginInstaller.cs index ffdb0aa75..a867d2e10 100644 --- a/Wox.Core/Plugin/PluginInstaller.cs +++ b/Wox.Core/Plugin/PluginInstaller.cs @@ -34,7 +34,7 @@ internal static void Install(string path) return; } - string pluginFolerPath = Infrastructure.Constant.PluginsDirectory; + string pluginFolerPath = Infrastructure.UserSettings.DataLocation.PluginsDirectory; string newPluginName = plugin.Name .Replace("/", "_") diff --git a/Wox.Core/Plugin/PluginManager.cs b/Wox.Core/Plugin/PluginManager.cs index 3d1450648..aa1065dfb 100644 --- a/Wox.Core/Plugin/PluginManager.cs +++ b/Wox.Core/Plugin/PluginManager.cs @@ -32,20 +32,20 @@ public static class PluginManager // todo happlebao, this should not be public, the indicator function should be embeded public static PluginsSettings Settings; private static List _metadatas; - private static readonly string[] Directories = { Constant.PreinstalledDirectory, Constant.PluginsDirectory }; + private static readonly string[] Directories = { Constant.PreinstalledDirectory, DataLocation.PluginsDirectory }; private static void ValidateUserDirectory() { - if (!Directory.Exists(Constant.PluginsDirectory)) + if (!Directory.Exists(DataLocation.PluginsDirectory)) { - Directory.CreateDirectory(Constant.PluginsDirectory); + Directory.CreateDirectory(DataLocation.PluginsDirectory); } } private static void DeletePythonBinding() { const string binding = "wox.py"; - var directory = Constant.PluginsDirectory; + var directory = DataLocation.PluginsDirectory; foreach (var subDirectory in Directory.GetDirectories(directory)) { var path = Path.Combine(subDirectory, binding); diff --git a/Wox.Core/Resource/Theme.cs b/Wox.Core/Resource/Theme.cs index fc5d55046..b011b4f49 100644 --- a/Wox.Core/Resource/Theme.cs +++ b/Wox.Core/Resource/Theme.cs @@ -23,7 +23,7 @@ public class Theme private const string Folder = "Themes"; private const string Extension = ".xaml"; private string DirectoryPath => Path.Combine(Constant.ProgramDirectory, Folder); - private string UserDirectoryPath => Path.Combine(Constant.DataDirectory, Folder); + private string UserDirectoryPath => Path.Combine(DataLocation.DataDirectory(), Folder); public Theme() { diff --git a/Wox.Core/Updater.cs b/Wox.Core/Updater.cs index 9262d78f4..6a04def9f 100644 --- a/Wox.Core/Updater.cs +++ b/Wox.Core/Updater.cs @@ -15,6 +15,7 @@ using Wox.Infrastructure.Http; using Wox.Infrastructure.Logger; using System.IO; +using Wox.Infrastructure.UserSettings; namespace Wox.Core { @@ -80,13 +81,13 @@ public async Task UpdateApp(bool silentIfLatestVersion = true) await updateManager.ApplyReleases(newUpdateInfo); - if (Constant.IsPortableMode) + if (DataLocation.PortableDataLocationInUse()) { - var targetDestination = updateManager.RootAppDirectory + $"\\app-{newReleaseVersion.ToString()}\\{Constant.PortableFolderName}"; - FilesFolders.Copy(Constant.PortableDataPath, targetDestination); - if (!FilesFolders.VerifyBothFolderFilesEqual(Constant.PortableDataPath, targetDestination)) + var targetDestination = updateManager.RootAppDirectory + $"\\app-{newReleaseVersion.ToString()}\\{DataLocation.PortableFolderName}"; + FilesFolders.Copy(DataLocation.PortableDataPath, targetDestination); + if (!FilesFolders.VerifyBothFolderFilesEqual(DataLocation.PortableDataPath, targetDestination)) MessageBox.Show(string.Format("Wox was not able to move your user profile data to the new update version. Please manually" + - "move your profile data folder from {0} to {1}", Constant.PortableDataPath, targetDestination)); + "move your profile data folder from {0} to {1}", DataLocation.PortableDataPath, targetDestination)); } else { diff --git a/Wox.Core/Wox.Core.csproj b/Wox.Core/Wox.Core.csproj index 7307243e6..0c5e0c178 100644 --- a/Wox.Core/Wox.Core.csproj +++ b/Wox.Core/Wox.Core.csproj @@ -51,6 +51,8 @@ Properties\SolutionAssemblyInfo.cs + + diff --git a/Wox.Infrastructure/Wox.cs b/Wox.Infrastructure/Constant.cs similarity index 60% rename from Wox.Infrastructure/Wox.cs rename to Wox.Infrastructure/Constant.cs index 16629e4fb..78a08ca69 100644 --- a/Wox.Infrastructure/Wox.cs +++ b/Wox.Infrastructure/Constant.cs @@ -1,4 +1,3 @@ -using System; using System.Diagnostics; using System.IO; using System.Reflection; @@ -13,25 +12,9 @@ public static class Constant private static readonly Assembly Assembly = Assembly.GetExecutingAssembly(); public static readonly string ProgramDirectory = Directory.GetParent(Assembly.Location.NonNull()).ToString(); public static readonly string ExecutablePath = Path.Combine(ProgramDirectory, Wox + ".exe"); - - public static bool IsPortableMode; - public const string PortableFolderName = "UserData"; - public static string PortableDataPath = Path.Combine(ProgramDirectory, PortableFolderName); - public static string DetermineDataDirectory() - { - if (Directory.Exists(PortableDataPath)) - { - IsPortableMode = true; - return PortableDataPath; - } - else - { - return Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData), Wox); - } - } - - public static readonly string DataDirectory = DetermineDataDirectory(); - public static readonly string PluginsDirectory = Path.Combine(DataDirectory, Plugins); + public static readonly string ApplicationDirectory = Directory.GetParent(ProgramDirectory).ToString(); + public static readonly string RootDirectory = Directory.GetParent(ApplicationDirectory).ToString(); + public static readonly string PreinstalledDirectory = Path.Combine(ProgramDirectory, Plugins); public const string Issue = "https://github.com/jjw24/Wox/issues/new"; public static readonly string Version = FileVersionInfo.GetVersionInfo(Assembly.Location.NonNull()).ProductVersion; diff --git a/Wox.Infrastructure/Logger/Log.cs b/Wox.Infrastructure/Logger/Log.cs index 349920076..4b7a97241 100644 --- a/Wox.Infrastructure/Logger/Log.cs +++ b/Wox.Infrastructure/Logger/Log.cs @@ -4,6 +4,7 @@ using NLog; using NLog.Config; using NLog.Targets; +using Wox.Infrastructure.UserSettings; namespace Wox.Infrastructure.Logger { @@ -15,7 +16,7 @@ public static class Log static Log() { - CurrentLogDirectory = Path.Combine(Constant.DataDirectory, DirectoryName, Constant.Version); + CurrentLogDirectory = Path.Combine(DataLocation.DataDirectory(), DirectoryName, Constant.Version); if (!Directory.Exists(CurrentLogDirectory)) { Directory.CreateDirectory(CurrentLogDirectory); diff --git a/Wox.Infrastructure/Storage/BinaryStorage.cs b/Wox.Infrastructure/Storage/BinaryStorage.cs index d2c5a2da8..6f9031dde 100644 --- a/Wox.Infrastructure/Storage/BinaryStorage.cs +++ b/Wox.Infrastructure/Storage/BinaryStorage.cs @@ -5,6 +5,7 @@ using System.Runtime.Serialization.Formatters; using System.Runtime.Serialization.Formatters.Binary; using Wox.Infrastructure.Logger; +using Wox.Infrastructure.UserSettings; namespace Wox.Infrastructure.Storage { @@ -17,7 +18,7 @@ public class BinaryStorage public BinaryStorage(string filename) { const string directoryName = "Cache"; - var directoryPath = Path.Combine(Constant.DataDirectory, directoryName); + var directoryPath = Path.Combine(DataLocation.DataDirectory(), directoryName); Helper.ValidateDirectory(directoryPath); const string fileSuffix = ".cache"; diff --git a/Wox.Infrastructure/Storage/PluginJsonStorage.cs b/Wox.Infrastructure/Storage/PluginJsonStorage.cs index 27de500c7..77dd541c3 100644 --- a/Wox.Infrastructure/Storage/PluginJsonStorage.cs +++ b/Wox.Infrastructure/Storage/PluginJsonStorage.cs @@ -1,4 +1,5 @@ using System.IO; +using Wox.Infrastructure.UserSettings; namespace Wox.Infrastructure.Storage { @@ -9,7 +10,7 @@ public PluginJsonStorage() // C# releated, add python releated below var dataType = typeof(T); var assemblyName = typeof(T).Assembly.GetName().Name; - DirectoryPath = Path.Combine(Constant.DataDirectory, DirectoryName, Constant.Plugins, assemblyName); + DirectoryPath = Path.Combine(DataLocation.DataDirectory(), DirectoryName, Constant.Plugins, assemblyName); Helper.ValidateDirectory(DirectoryPath); FilePath = Path.Combine(DirectoryPath, $"{dataType.Name}{FileSuffix}"); diff --git a/Wox.Infrastructure/Storage/WoxJsonStorage.cs b/Wox.Infrastructure/Storage/WoxJsonStorage.cs index da0dbd073..1a6b22c4b 100644 --- a/Wox.Infrastructure/Storage/WoxJsonStorage.cs +++ b/Wox.Infrastructure/Storage/WoxJsonStorage.cs @@ -4,6 +4,7 @@ using System.Linq; using System.Text; using System.Threading.Tasks; +using Wox.Infrastructure.UserSettings; namespace Wox.Infrastructure.Storage { @@ -11,7 +12,7 @@ namespace Wox.Infrastructure.Storage { public WoxJsonStorage() { - var directoryPath = Path.Combine(Constant.DataDirectory, DirectoryName); + var directoryPath = Path.Combine(DataLocation.DataDirectory(), DirectoryName); Helper.ValidateDirectory(directoryPath); var filename = typeof(T).Name; diff --git a/Wox.Infrastructure/UserSettings/DataLocation.cs b/Wox.Infrastructure/UserSettings/DataLocation.cs new file mode 100644 index 000000000..ef85341c5 --- /dev/null +++ b/Wox.Infrastructure/UserSettings/DataLocation.cs @@ -0,0 +1,34 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Wox.Infrastructure.UserSettings +{ + public static class DataLocation + { + public const string PortableFolderName = "UserData"; + public const string DeletionIndicatorFile = ".dead"; + public static string PortableDataPath = Path.Combine(Constant.ProgramDirectory, PortableFolderName); + public static string RoamingDataPath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData), Constant.Wox); + public static string DataDirectory() + { + if (PortableDataLocationInUse()) + return PortableDataPath; + + return RoamingDataPath; + } + + public static bool PortableDataLocationInUse() + { + if (Directory.Exists(PortableDataPath) && !File.Exists(DeletionIndicatorFile)) + return true; + + return false; + } + + public static readonly string PluginsDirectory = Path.Combine(DataDirectory(), Constant.Plugins); + } +} diff --git a/Wox.Infrastructure/Wox.Infrastructure.csproj b/Wox.Infrastructure/Wox.Infrastructure.csproj index fc1990da9..65bd29d49 100644 --- a/Wox.Infrastructure/Wox.Infrastructure.csproj +++ b/Wox.Infrastructure/Wox.Infrastructure.csproj @@ -77,7 +77,8 @@ - + + diff --git a/Wox.Plugin/SharedCommands/FilesFolders.cs b/Wox.Plugin/SharedCommands/FilesFolders.cs index 584a83bc6..f9eb13961 100644 --- a/Wox.Plugin/SharedCommands/FilesFolders.cs +++ b/Wox.Plugin/SharedCommands/FilesFolders.cs @@ -48,7 +48,7 @@ public static void Copy(this string sourcePath, string targetPath) throw e; #else MessageBox.Show(string.Format("Copying path {0} has failed, it will now be deleted for consistency", targetPath)); - RemoveFolder(targetPath); + RemoveFolderIfExists(targetPath); #endif } @@ -81,7 +81,7 @@ public static bool VerifyBothFolderFilesEqual(this string fromPath, string toPat } - public static void RemoveFolder(this string path) + public static void RemoveFolderIfExists(this string path) { try { @@ -97,5 +97,15 @@ public static void RemoveFolder(this string path) #endif } } + + public static bool LocationExists(this string path) + { + return Directory.Exists(path); + } + + public static bool FileExits(this string filePath) + { + return File.Exists(filePath); + } } } diff --git a/Wox/App.xaml.cs b/Wox/App.xaml.cs index 0fc1e8c95..83a0d2255 100644 --- a/Wox/App.xaml.cs +++ b/Wox/App.xaml.cs @@ -4,6 +4,7 @@ using System.Timers; using System.Windows; using Wox.Core; +using Wox.Core.Configuration; using Wox.Core.Plugin; using Wox.Core.Resource; using Wox.Helper; @@ -26,6 +27,7 @@ public partial class App : IDisposable, ISingleInstanceApp private MainViewModel _mainVM; private SettingWindowViewModel _settingsVM; private readonly Updater _updater = new Updater(Wox.Properties.Settings.Default.GithubRepo); + private readonly Portable _portable = new Portable(); private readonly Alphabet _alphabet = new Alphabet(); private StringMatcher _stringMatcher; @@ -46,6 +48,8 @@ private void OnStartup(object sender, StartupEventArgs e) { Stopwatch.Normal("|App.OnStartup|Startup cost", () => { + _portable.PreStartCleanUpAfterPortabilityUpdate(); + Log.Info("|App.OnStartup|Begin Wox startup ----------------------------------------------------"); Log.Info($"|App.OnStartup|Runtime info:{ErrorReporting.RuntimeInfo()}"); RegisterAppDomainExceptions(); @@ -53,7 +57,7 @@ private void OnStartup(object sender, StartupEventArgs e) ImageLoader.Initialize(); - _settingsVM = new SettingWindowViewModel(_updater); + _settingsVM = new SettingWindowViewModel(_updater, _portable); _settings = _settingsVM.Settings; _alphabet.Initialize(_settings); diff --git a/Wox/SettingWindow.xaml b/Wox/SettingWindow.xaml index 3c12bda6f..bbb17d506 100644 --- a/Wox/SettingWindow.xaml +++ b/Wox/SettingWindow.xaml @@ -33,6 +33,9 @@ + + + diff --git a/Wox/ViewModel/SettingWindowViewModel.cs b/Wox/ViewModel/SettingWindowViewModel.cs index f9160df9f..3f315a9e3 100644 --- a/Wox/ViewModel/SettingWindowViewModel.cs +++ b/Wox/ViewModel/SettingWindowViewModel.cs @@ -8,11 +8,11 @@ using System.Windows.Media; using System.Windows.Media.Imaging; using Wox.Core; +using Wox.Core.Configuration; using Wox.Core.Plugin; using Wox.Core.Resource; using Wox.Helper; using Wox.Infrastructure; -using Wox.Infrastructure.Http; using Wox.Infrastructure.Storage; using Wox.Infrastructure.UserSettings; using Wox.Plugin; @@ -22,11 +22,13 @@ namespace Wox.ViewModel public class SettingWindowViewModel : BaseModel { private readonly Updater _updater; + private readonly IPortable _portable; private readonly WoxJsonStorage _storage; - public SettingWindowViewModel(Updater updater) + public SettingWindowViewModel(Updater updater, IPortable portable) { _updater = updater; + _portable = portable; _storage = new WoxJsonStorage(); Settings = _storage.Load(); Settings.PropertyChanged += (s, e) => @@ -36,8 +38,6 @@ public SettingWindowViewModel(Updater updater) OnPropertyChanged(nameof(ActivatedTimes)); } }; - - } public Settings Settings { get; set; } @@ -47,6 +47,27 @@ public async void UpdateApp() await _updater.UpdateApp(false); } + // This is only required to set at startup. When portable mode enabled/disabled a restart is always required + private bool _portableMode = DataLocation.PortableDataLocationInUse(); + public bool PortableMode + { + get { return _portableMode; } + set + { + if (!_portable.CanUpdatePortability()) + return; + + if (DataLocation.PortableDataLocationInUse()) + { + _portable.DisablePortableMode(); + } + else + { + _portable.EnablePortableMode(); + } + } + } + public void Save() { _storage.Save();