From 1a8619c0e9b0527d7e2d14cbeca005029572b609 Mon Sep 17 00:00:00 2001 From: Joseph Finney Date: Sun, 7 Apr 2024 14:11:10 -0500 Subject: [PATCH 01/10] inital work --- .../Extensions/SettingsStorageExtensions.cs | 108 ++++++++++++++++++ Text-Grab/Pages/GeneralSettings.xaml | 5 + Text-Grab/Pages/GeneralSettings.xaml.cs | 12 +- Text-Grab/Services/SettingsService.cs | 66 +++++++++++ Text-Grab/Utilities/Json.cs | 23 ++++ 5 files changed, 213 insertions(+), 1 deletion(-) create mode 100644 Text-Grab/Extensions/SettingsStorageExtensions.cs create mode 100644 Text-Grab/Services/SettingsService.cs create mode 100644 Text-Grab/Utilities/Json.cs diff --git a/Text-Grab/Extensions/SettingsStorageExtensions.cs b/Text-Grab/Extensions/SettingsStorageExtensions.cs new file mode 100644 index 00000000..bb873788 --- /dev/null +++ b/Text-Grab/Extensions/SettingsStorageExtensions.cs @@ -0,0 +1,108 @@ +using System; +using System.IO; +using System.Threading.Tasks; +using Windows.Storage; +using Windows.Storage.Streams; + +namespace Text_Grab.Helpers; + +// Use these extension methods to store and retrieve local and roaming app data +// More details regarding storing and retrieving app data at https://docs.microsoft.com/windows/apps/design/app-settings/store-and-retrieve-app-data +public static class SettingsStorageExtensions +{ + private const string FileExtension = ".json"; + + public static bool IsRoamingStorageAvailable(this ApplicationData appData) + { + return appData.RoamingStorageQuota == 0; + } + + public static async Task SaveAsync(this StorageFolder folder, string name, T content) + { + if (content is null) + return; + + StorageFile file = await folder.CreateFileAsync(GetFileName(name), CreationCollisionOption.ReplaceExisting); + string fileContent = await Json.StringifyAsync(content); + + await FileIO.WriteTextAsync(file, fileContent); + } + + public static async Task ReadAsync(this StorageFolder folder, string name) + { + if (!File.Exists(Path.Combine(folder.Path, GetFileName(name)))) + { + return default; + } + + StorageFile file = await folder.GetFileAsync($"{name}.json"); + string fileContent = await FileIO.ReadTextAsync(file); + + return await Json.ToObjectAsync(fileContent); + } + + public static async Task SaveAsync(this ApplicationDataContainer settings, string key, T? value) + { + if (value is null) + return; + + settings.SaveString(key, await Json.StringifyAsync(value)); + } + + public static void SaveString(this ApplicationDataContainer settings, string key, string value) + { + settings.Values[key] = value; + } + + public static async Task ReadAsync(this ApplicationDataContainer settings, string key) + { + if (settings.Values.TryGetValue(key, out object? obj)) + return await Json.ToObjectAsync((string)obj); + + return default; + } + + public static async Task SaveFileAsync(this StorageFolder folder, byte[] content, string fileName, CreationCollisionOption options = CreationCollisionOption.ReplaceExisting) + { + ArgumentNullException.ThrowIfNull(content); + + if (string.IsNullOrEmpty(fileName)) + throw new ArgumentException("File name is null or empty. Specify a valid file name", nameof(fileName)); + + StorageFile storageFile = await folder.CreateFileAsync(fileName, options); + await FileIO.WriteBytesAsync(storageFile, content); + return storageFile; + } + + public static async Task ReadFileAsync(this StorageFolder folder, string fileName) + { + IStorageItem item = await folder.TryGetItemAsync(fileName).AsTask().ConfigureAwait(false); + + if ((item != null) && item.IsOfType(StorageItemTypes.File)) + { + StorageFile storageFile = await folder.GetFileAsync(fileName); + byte[]? content = await storageFile.ReadBytesAsync(); + return content; + } + + return null; + } + + public static async Task ReadBytesAsync(this StorageFile file) + { + if (file == null) + return null; + + using IRandomAccessStream stream = await file.OpenReadAsync(); + using DataReader reader = new(stream.GetInputStreamAt(0)); + await reader.LoadAsync((uint)stream.Size); + byte[] bytes = new byte[stream.Size]; + reader.ReadBytes(bytes); + return bytes; + } + + private static string GetFileName(string name) + { + return string.Concat(name, FileExtension); + } +} diff --git a/Text-Grab/Pages/GeneralSettings.xaml b/Text-Grab/Pages/GeneralSettings.xaml index 7593e599..048c1d04 100644 --- a/Text-Grab/Pages/GeneralSettings.xaml +++ b/Text-Grab/Pages/GeneralSettings.xaml @@ -48,6 +48,11 @@ Click="AboutBTN_Click" /> + + .Instance; #endregion Fields - public GeneralSettings() { InitializeComponent(); + TestToggle.IsChecked = settings.TestSetting; if (!ImplementAppOptions.IsPackaged()) OpenExeFolderButton.Visibility = Visibility.Visible; @@ -281,4 +283,12 @@ private void ShowToastCheckBox_Unchecked(object sender, RoutedEventArgs e) { DefaultSettings.ShowToast = false; } + + private void TestToggle_Checked(object sender, RoutedEventArgs e) + { + if (sender is not ToggleSwitch toggleSwitch) + return; + + settings.TestSetting = toggleSwitch.IsChecked is true; + } } diff --git a/Text-Grab/Services/SettingsService.cs b/Text-Grab/Services/SettingsService.cs new file mode 100644 index 00000000..e2545b06 --- /dev/null +++ b/Text-Grab/Services/SettingsService.cs @@ -0,0 +1,66 @@ +using Text_Grab.Helpers; +using Windows.Storage; + +namespace Text_Grab.Services; +internal class SettingsService +{ + private ApplicationDataContainer _localSettings = ApplicationData.Current.LocalSettings; + // relevant discussion https://github.com/microsoft/WindowsAppSDK/discussions/1478 + public SettingsService() + { + if (!_localSettings.Values.ContainsKey("IsFirstRun")) + { + _localSettings.Values["IsFirstRun"] = true; + } + } + + private bool? testSetting; + + public bool TestSetting + { + get + { + testSetting ??= _localSettings.ReadAsync(nameof(TestSetting)).Result; + testSetting ??= false; + + return testSetting.Value; + } + set + { + testSetting = value; + _localSettings.SaveAsync(nameof(TestSetting), value); + } + } + + private double? testDoubleSetting; + public double? TestDoubleSetting + { + get + { + testDoubleSetting ??= _localSettings.ReadAsync(nameof(TestDoubleSetting)).Result; + testDoubleSetting ??= 2; + return testDoubleSetting; + } + set + { + testDoubleSetting = value; + _localSettings.SaveAsync(nameof(TestDoubleSetting), value); + } + } + + private string? testStringSetting; + public string? TestStringSetting + { + get + { + testStringSetting ??= _localSettings.ReadAsync(nameof(TestStringSetting)).Result; + testStringSetting ??= "Hello, World!"; + return testStringSetting; + } + set + { + testStringSetting = value; + _localSettings.SaveAsync(nameof(TestStringSetting), value); + } + } +} diff --git a/Text-Grab/Utilities/Json.cs b/Text-Grab/Utilities/Json.cs new file mode 100644 index 00000000..aba84536 --- /dev/null +++ b/Text-Grab/Utilities/Json.cs @@ -0,0 +1,23 @@ +using System.Text.Json; +using System.Threading.Tasks; + +namespace Text_Grab.Helpers; + +public static class Json +{ + public static async Task ToObjectAsync(string value) + { + return await Task.Run(() => + { + return JsonSerializer.Deserialize(value); + }); + } + + public static async Task StringifyAsync(object value) + { + return await Task.Run(() => + { + return JsonSerializer.Serialize(value); + }); + } +} \ No newline at end of file From 79363fd773c982b8f179bdf88743a9d28bd7d169 Mon Sep 17 00:00:00 2001 From: Joseph Finney Date: Sat, 13 Apr 2024 20:43:01 -0500 Subject: [PATCH 02/10] First success pass on SettingsService --- Text-Grab/Pages/GeneralSettings.xaml | 5 -- Text-Grab/Pages/GeneralSettings.xaml.cs | 26 +++---- Text-Grab/Services/SettingsService.cs | 87 +++++++++++----------- Text-Grab/Utilities/AppUtilities.cs | 19 +++++ Text-Grab/Utilities/FileUtilities.cs | 12 +-- Text-Grab/Utilities/ImplementAppOptions.cs | 18 +---- Text-Grab/Views/FirstRunWindow.xaml.cs | 2 +- 7 files changed, 82 insertions(+), 87 deletions(-) create mode 100644 Text-Grab/Utilities/AppUtilities.cs diff --git a/Text-Grab/Pages/GeneralSettings.xaml b/Text-Grab/Pages/GeneralSettings.xaml index 048c1d04..7593e599 100644 --- a/Text-Grab/Pages/GeneralSettings.xaml +++ b/Text-Grab/Pages/GeneralSettings.xaml @@ -48,11 +48,6 @@ Click="AboutBTN_Click" /> - - (nameof(DefaultSettings.ShowToast)); + RunInBackgroundChkBx.IsChecked = DefaultSettings.RunInTheBackground; ReadBarcodesBarcode.IsChecked = DefaultSettings.TryToReadBarcodes; HistorySwitch.IsChecked = DefaultSettings.UseHistory; @@ -276,19 +276,15 @@ private void TryInsertCheckbox_Unchecked(object sender, RoutedEventArgs e) private void ShowToastCheckBox_Checked(object sender, RoutedEventArgs e) { - DefaultSettings.ShowToast = true; + //DefaultSettings.ShowToast = true; + string nameOfToast = nameof(DefaultSettings.ShowToast); + Singleton.Instance.SaveSetting(nameOfToast, true); } private void ShowToastCheckBox_Unchecked(object sender, RoutedEventArgs e) { - DefaultSettings.ShowToast = false; - } - - private void TestToggle_Checked(object sender, RoutedEventArgs e) - { - if (sender is not ToggleSwitch toggleSwitch) - return; - - settings.TestSetting = toggleSwitch.IsChecked is true; + //DefaultSettings.ShowToast = false; + string nameOfToast = nameof(DefaultSettings.ShowToast); + Singleton.Instance.SaveSetting(nameOfToast, false); } } diff --git a/Text-Grab/Services/SettingsService.cs b/Text-Grab/Services/SettingsService.cs index e2545b06..3b3738e9 100644 --- a/Text-Grab/Services/SettingsService.cs +++ b/Text-Grab/Services/SettingsService.cs @@ -1,66 +1,65 @@ -using Text_Grab.Helpers; +using System; +using System.Diagnostics; +using Text_Grab.Utilities; using Windows.Storage; namespace Text_Grab.Services; + internal class SettingsService { - private ApplicationDataContainer _localSettings = ApplicationData.Current.LocalSettings; + private ApplicationDataContainer? _localSettings; // relevant discussion https://github.com/microsoft/WindowsAppSDK/discussions/1478 + + private Properties.Settings _classicSettings = Properties.Settings.Default; + public SettingsService() { - if (!_localSettings.Values.ContainsKey("IsFirstRun")) - { - _localSettings.Values["IsFirstRun"] = true; - } + if (AppUtilities.IsPackaged()) + _localSettings = ApplicationData.Current.LocalSettings; } - private bool? testSetting; - - public bool TestSetting + public T GetSetting(string name) { - get + // if running as packaged try to get from local settings + if (_localSettings is not null) { - testSetting ??= _localSettings.ReadAsync(nameof(TestSetting)).Result; - testSetting ??= false; + try + { + _localSettings.Values.TryGetValue(name, out object? obj); - return testSetting.Value; - } - set - { - testSetting = value; - _localSettings.SaveAsync(nameof(TestSetting), value); - } - } + if (obj is not null) // not saved into local settings, get default from classic settings + return (T)Convert.ChangeType(obj, typeof(T)); + } + catch (Exception ex) + { + Debug.WriteLine($"Failed to Get setting from ApplicationDataContainer {ex.Message}"); - private double? testDoubleSetting; - public double? TestDoubleSetting - { - get - { - testDoubleSetting ??= _localSettings.ReadAsync(nameof(TestDoubleSetting)).Result; - testDoubleSetting ??= 2; - return testDoubleSetting; - } - set - { - testDoubleSetting = value; - _localSettings.SaveAsync(nameof(TestDoubleSetting), value); +#if DEBUG + throw; +#endif + } } + + return _classicSettings[name] is T value ? value : default; } - private string? testStringSetting; - public string? TestStringSetting + public void SaveSetting(string name, T value) { - get - { - testStringSetting ??= _localSettings.ReadAsync(nameof(TestStringSetting)).Result; - testStringSetting ??= "Hello, World!"; - return testStringSetting; - } - set + if (_localSettings is not null) { - testStringSetting = value; - _localSettings.SaveAsync(nameof(TestStringSetting), value); + try + { + _localSettings.Values[name] = value; + } + catch (Exception ex) + { + Debug.WriteLine($"Failed to Save setting from ApplicationDataContainer {ex.Message}"); +#if DEBUG + throw; +#endif + } } + else + _classicSettings[name] = value; } } diff --git a/Text-Grab/Utilities/AppUtilities.cs b/Text-Grab/Utilities/AppUtilities.cs new file mode 100644 index 00000000..d3ea6dee --- /dev/null +++ b/Text-Grab/Utilities/AppUtilities.cs @@ -0,0 +1,19 @@ +using Windows.ApplicationModel; + +namespace Text_Grab.Utilities; +internal class AppUtilities +{ + internal static bool IsPackaged() + { + try + { + // If we have a package ID then we are running in a packaged context + PackageId dummy = Package.Current.Id; + return true; + } + catch + { + return false; + } + } +} diff --git a/Text-Grab/Utilities/FileUtilities.cs b/Text-Grab/Utilities/FileUtilities.cs index 6190625f..4bc64d0f 100644 --- a/Text-Grab/Utilities/FileUtilities.cs +++ b/Text-Grab/Utilities/FileUtilities.cs @@ -17,7 +17,7 @@ public class FileUtilities public static Task GetImageFileAsync(string fileName, FileStorageKind storageKind) { - if (ImplementAppOptions.IsPackaged()) + if (AppUtilities.IsPackaged()) return GetImageFilePackaged(fileName, storageKind); return GetImageFileUnpackaged(fileName, storageKind); @@ -75,7 +75,7 @@ public static string GetPathToLocalFile(string imageRelativePath) public async static Task GetPathToHistory() { - if (ImplementAppOptions.IsPackaged()) + if (AppUtilities.IsPackaged()) { StorageFolder historyFolder = await GetStorageFolderPackaged("", FileStorageKind.WithHistory); return historyFolder.Path; @@ -86,7 +86,7 @@ public async static Task GetPathToHistory() public static Task GetTextFileAsync(string fileName, FileStorageKind storageKind) { - if (ImplementAppOptions.IsPackaged()) + if (AppUtilities.IsPackaged()) return GetTextFilePackaged(fileName, storageKind); return GetTextFileUnpackaged(fileName, storageKind); @@ -94,7 +94,7 @@ public static Task GetTextFileAsync(string fileName, FileStorageKind sto public static Task SaveImageFile(Bitmap image, string filename, FileStorageKind storageKind) { - if (ImplementAppOptions.IsPackaged()) + if (AppUtilities.IsPackaged()) return SaveImagePackaged(image, filename, storageKind); return SaveImageFileUnpackaged(image, filename, storageKind); @@ -102,7 +102,7 @@ public static Task SaveImageFile(Bitmap image, string filename, FileStorag public static Task SaveTextFile(string textContent, string filename, FileStorageKind storageKind) { - if (ImplementAppOptions.IsPackaged()) + if (AppUtilities.IsPackaged()) return SaveTextFilePackaged(textContent, filename, storageKind); return SaveTextFileUnpackaged(textContent, filename, storageKind); @@ -294,7 +294,7 @@ private static async Task SaveTextFileUnpackaged(string textContent, strin public async static void TryDeleteHistoryDirectory() { FileStorageKind historyFolderKind = FileStorageKind.WithHistory; - if (ImplementAppOptions.IsPackaged()) + if (AppUtilities.IsPackaged()) { StorageFolder historyFolder = await GetStorageFolderPackaged("", historyFolderKind); diff --git a/Text-Grab/Utilities/ImplementAppOptions.cs b/Text-Grab/Utilities/ImplementAppOptions.cs index c530191d..ddeaa85e 100644 --- a/Text-Grab/Utilities/ImplementAppOptions.cs +++ b/Text-Grab/Utilities/ImplementAppOptions.cs @@ -33,23 +33,9 @@ public static void ImplementBackgroundOption(bool runInBackground) } } - internal static bool IsPackaged() - { - try - { - // If we have a package ID then we are running in a packaged context - var dummy = Package.Current.Id; - return true; - } - catch - { - return false; - } - } - private static async void RemoveFromStartup() { - if (IsPackaged()) + if (AppUtilities.IsPackaged()) { StartupTask startupTask = await StartupTask.GetAsync("StartTextGrab"); startupTask.Disable(); @@ -68,7 +54,7 @@ private static async void RemoveFromStartup() private static async Task SetForStartup() { - if (IsPackaged()) + if (AppUtilities.IsPackaged()) { StartupTask startupTask = await StartupTask.GetAsync("StartTextGrab"); StartupTaskState newState = await startupTask.RequestEnableAsync(); diff --git a/Text-Grab/Views/FirstRunWindow.xaml.cs b/Text-Grab/Views/FirstRunWindow.xaml.cs index 4fa673f3..67fad8b4 100644 --- a/Text-Grab/Views/FirstRunWindow.xaml.cs +++ b/Text-Grab/Views/FirstRunWindow.xaml.cs @@ -59,7 +59,7 @@ private async void FirstRun_Loaded(object sender, RoutedEventArgs e) break; } - if (ImplementAppOptions.IsPackaged()) + if (AppUtilities.IsPackaged()) { StartupTask startupTask = await StartupTask.GetAsync("StartTextGrab"); From 08747e6b9e6829411f2d41868ebe6f8aa6ffe070 Mon Sep 17 00:00:00 2001 From: Joseph Finney Date: Sat, 13 Apr 2024 21:31:47 -0500 Subject: [PATCH 03/10] Wrap Settings in new class --- Text-Grab/Pages/GeneralSettings.xaml.cs | 14 ++--- Text-Grab/Services/SettingsService.cs | 76 +++++++++++++++---------- Text-Grab/Utilities/AppUtilities.cs | 6 +- 3 files changed, 56 insertions(+), 40 deletions(-) diff --git a/Text-Grab/Pages/GeneralSettings.xaml.cs b/Text-Grab/Pages/GeneralSettings.xaml.cs index 5f6095bb..62d4c0a6 100644 --- a/Text-Grab/Pages/GeneralSettings.xaml.cs +++ b/Text-Grab/Pages/GeneralSettings.xaml.cs @@ -19,11 +19,10 @@ public partial class GeneralSettings : Page { #region Fields - private readonly Settings DefaultSettings = Settings.Default; + private readonly Settings DefaultSettings = AppUtilities.TextGrabSettings; private readonly Brush BadBrush = new SolidColorBrush(Colors.Red); private readonly Brush GoodBrush = new SolidColorBrush(Colors.Transparent); private double InsertDelaySeconds = 1.5; - private SettingsService settings = Singleton.Instance; #endregion Fields @@ -117,8 +116,7 @@ private async void Page_Loaded(object sender, RoutedEventArgs e) StartupOnLoginCheckBox.IsChecked = Settings.Default.StartupOnLogin; } - // ShowToastCheckBox.IsChecked = DefaultSettings.ShowToast; - ShowToastCheckBox.IsChecked = settings.GetSetting(nameof(DefaultSettings.ShowToast)); + ShowToastCheckBox.IsChecked = DefaultSettings.ShowToast; RunInBackgroundChkBx.IsChecked = DefaultSettings.RunInTheBackground; ReadBarcodesBarcode.IsChecked = DefaultSettings.TryToReadBarcodes; @@ -276,15 +274,11 @@ private void TryInsertCheckbox_Unchecked(object sender, RoutedEventArgs e) private void ShowToastCheckBox_Checked(object sender, RoutedEventArgs e) { - //DefaultSettings.ShowToast = true; - string nameOfToast = nameof(DefaultSettings.ShowToast); - Singleton.Instance.SaveSetting(nameOfToast, true); + DefaultSettings.ShowToast = true; } private void ShowToastCheckBox_Unchecked(object sender, RoutedEventArgs e) { - //DefaultSettings.ShowToast = false; - string nameOfToast = nameof(DefaultSettings.ShowToast); - Singleton.Instance.SaveSetting(nameOfToast, false); + DefaultSettings.ShowToast = false; } } diff --git a/Text-Grab/Services/SettingsService.cs b/Text-Grab/Services/SettingsService.cs index 3b3738e9..9a2e0ccf 100644 --- a/Text-Grab/Services/SettingsService.cs +++ b/Text-Grab/Services/SettingsService.cs @@ -1,65 +1,83 @@ using System; +using System.ComponentModel; +using System.Configuration; using System.Diagnostics; using Text_Grab.Utilities; using Windows.Storage; namespace Text_Grab.Services; -internal class SettingsService +internal class SettingsService : IDisposable { private ApplicationDataContainer? _localSettings; // relevant discussion https://github.com/microsoft/WindowsAppSDK/discussions/1478 - private Properties.Settings _classicSettings = Properties.Settings.Default; + public Properties.Settings ClassicSettings = Properties.Settings.Default; + + private static SettingsPropertyCollection settingOptions = Properties.Settings.Default.Properties; public SettingsService() { if (AppUtilities.IsPackaged()) _localSettings = ApplicationData.Current.LocalSettings; + + ClassicSettings.PropertyChanged -= ClassicSettings_PropertyChanged; + ClassicSettings.PropertyChanged += ClassicSettings_PropertyChanged; + } + + private void ClassicSettings_PropertyChanged(object? sender, PropertyChangedEventArgs e) + { + if (e.PropertyName is not string propertyName) + return; + + SaveSettingInContainer(propertyName, ClassicSettings[propertyName]); } - public T GetSetting(string name) + public void Dispose() + { + ClassicSettings.PropertyChanged -= ClassicSettings_PropertyChanged; + } + + public T? GetSettingFromContainer(string name) { // if running as packaged try to get from local settings - if (_localSettings is not null) + if (_localSettings is null) + return default; + + try { - try - { - _localSettings.Values.TryGetValue(name, out object? obj); + _localSettings.Values.TryGetValue(name, out object? obj); - if (obj is not null) // not saved into local settings, get default from classic settings - return (T)Convert.ChangeType(obj, typeof(T)); - } - catch (Exception ex) - { - Debug.WriteLine($"Failed to Get setting from ApplicationDataContainer {ex.Message}"); + if (obj is not null) // not saved into local settings, get default from classic settings + return (T)Convert.ChangeType(obj, typeof(T)); + } + catch (Exception ex) + { + Debug.WriteLine($"Failed to Get setting from ApplicationDataContainer {ex.Message}"); #if DEBUG - throw; + throw; #endif - } } - return _classicSettings[name] is T value ? value : default; + return default; } - public void SaveSetting(string name, T value) + public void SaveSettingInContainer(string name, T value) { - if (_localSettings is not null) + if (_localSettings is null) + return; + + try + { + _localSettings.Values[name] = value; + } + catch (Exception ex) { - try - { - _localSettings.Values[name] = value; - } - catch (Exception ex) - { - Debug.WriteLine($"Failed to Save setting from ApplicationDataContainer {ex.Message}"); + Debug.WriteLine($"Failed to Save setting from ApplicationDataContainer {ex.Message}"); #if DEBUG - throw; + throw; #endif - } } - else - _classicSettings[name] = value; } } diff --git a/Text-Grab/Utilities/AppUtilities.cs b/Text-Grab/Utilities/AppUtilities.cs index d3ea6dee..228e2247 100644 --- a/Text-Grab/Utilities/AppUtilities.cs +++ b/Text-Grab/Utilities/AppUtilities.cs @@ -1,4 +1,6 @@ -using Windows.ApplicationModel; +using Text_Grab.Properties; +using Text_Grab.Services; +using Windows.ApplicationModel; namespace Text_Grab.Utilities; internal class AppUtilities @@ -16,4 +18,6 @@ internal static bool IsPackaged() return false; } } + + internal static Settings TextGrabSettings => Singleton.Instance.ClassicSettings; } From 6aec0b900c86d8272d18e3423abd5e11b8713f8b Mon Sep 17 00:00:00 2001 From: Joseph Finney Date: Sat, 13 Apr 2024 21:58:07 -0500 Subject: [PATCH 04/10] Add a check and migration to ClassicSettings --- Text-Grab/Services/SettingsService.cs | 21 +++++++++++++++++++-- 1 file changed, 19 insertions(+), 2 deletions(-) diff --git a/Text-Grab/Services/SettingsService.cs b/Text-Grab/Services/SettingsService.cs index 9a2e0ccf..b9168ea4 100644 --- a/Text-Grab/Services/SettingsService.cs +++ b/Text-Grab/Services/SettingsService.cs @@ -1,4 +1,5 @@ using System; +using System.Collections.Generic; using System.ComponentModel; using System.Configuration; using System.Diagnostics; @@ -18,13 +19,29 @@ internal class SettingsService : IDisposable public SettingsService() { - if (AppUtilities.IsPackaged()) - _localSettings = ApplicationData.Current.LocalSettings; + if (!AppUtilities.IsPackaged()) + return; + + _localSettings = ApplicationData.Current.LocalSettings; + + if (ClassicSettings.FirstRun && _localSettings.Values.Count > 0) + MigrateLocalSettingsToClassic(); + // copy settings from classic to local settings + // so that when app updates they can be copied forward ClassicSettings.PropertyChanged -= ClassicSettings_PropertyChanged; ClassicSettings.PropertyChanged += ClassicSettings_PropertyChanged; } + private void MigrateLocalSettingsToClassic() + { + if (_localSettings is null) + return; + + foreach (KeyValuePair localSetting in _localSettings.Values) + ClassicSettings[localSetting.Key] = localSetting.Value; + } + private void ClassicSettings_PropertyChanged(object? sender, PropertyChangedEventArgs e) { if (e.PropertyName is not string propertyName) From fd24d3f6dff0487af58c1fdf75beada863841b11 Mon Sep 17 00:00:00 2001 From: Joseph Finney Date: Sat, 13 Apr 2024 22:07:43 -0500 Subject: [PATCH 05/10] remove unused field --- Text-Grab/Services/SettingsService.cs | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/Text-Grab/Services/SettingsService.cs b/Text-Grab/Services/SettingsService.cs index b9168ea4..777d4742 100644 --- a/Text-Grab/Services/SettingsService.cs +++ b/Text-Grab/Services/SettingsService.cs @@ -1,7 +1,6 @@ using System; using System.Collections.Generic; using System.ComponentModel; -using System.Configuration; using System.Diagnostics; using Text_Grab.Utilities; using Windows.Storage; @@ -10,13 +9,11 @@ namespace Text_Grab.Services; internal class SettingsService : IDisposable { - private ApplicationDataContainer? _localSettings; + private readonly ApplicationDataContainer? _localSettings; // relevant discussion https://github.com/microsoft/WindowsAppSDK/discussions/1478 public Properties.Settings ClassicSettings = Properties.Settings.Default; - private static SettingsPropertyCollection settingOptions = Properties.Settings.Default.Properties; - public SettingsService() { if (!AppUtilities.IsPackaged()) From b87a87fa7af99b8959a635c4a25ba63b5fa8f5a7 Mon Sep 17 00:00:00 2001 From: Joseph Finney Date: Sat, 13 Apr 2024 22:07:49 -0500 Subject: [PATCH 06/10] use new static settings --- Text-Grab/App.xaml.cs | 38 +++++++++++++++++++++----------------- 1 file changed, 21 insertions(+), 17 deletions(-) diff --git a/Text-Grab/App.xaml.cs b/Text-Grab/App.xaml.cs index 35fafd6a..57425346 100644 --- a/Text-Grab/App.xaml.cs +++ b/Text-Grab/App.xaml.cs @@ -1,6 +1,5 @@ using Microsoft.Toolkit.Uwp.Notifications; using Microsoft.Win32; -using Microsoft.Windows.Themes; using RegistryUtils; using System; using System.Collections.Generic; @@ -18,7 +17,6 @@ using Text_Grab.Views; using Wpf.Ui; using Wpf.Ui.Appearance; -using Wpf.Ui.Extensions; namespace Text_Grab; @@ -27,6 +25,12 @@ namespace Text_Grab; /// public partial class App : System.Windows.Application { + #region Fields + + readonly static Settings _defaultSettings = AppUtilities.TextGrabSettings; + + #endregion Fields + #region Properties public List HotKeyIds { get; set; } = new(); @@ -38,7 +42,7 @@ public partial class App : System.Windows.Application public static void DefaultLaunch() { - TextGrabMode defaultLaunchSetting = Enum.Parse(Settings.Default.DefaultLaunch, true); + TextGrabMode defaultLaunchSetting = Enum.Parse(_defaultSettings.DefaultLaunch, true); switch (defaultLaunchSetting) { @@ -65,7 +69,7 @@ public static void DefaultLaunch() } public static void SetTheme(object? sender = null, EventArgs? e = null) { - bool gotTheme = Enum.TryParse(Settings.Default.AppTheme.ToString(), true, out AppTheme currentAppTheme); + bool gotTheme = Enum.TryParse(_defaultSettings.AppTheme.ToString(), true, out AppTheme currentAppTheme); if (!gotTheme) return; @@ -135,8 +139,8 @@ private static async Task HandleStartupArgs(string[] args) if (arg == "--windowless") { isQuiet = true; - Settings.Default.FirstRun = false; - Settings.Default.Save(); + _defaultSettings.FirstRun = false; + _defaultSettings.Save(); } if (currentArgument.Contains("ToastActivated")) @@ -151,7 +155,7 @@ private static async Task HandleStartupArgs(string[] args) return true; } - bool isStandardMode = Enum.TryParse(currentArgument, true, out TextGrabMode launchMode); + bool isStandardMode = Enum.TryParse(currentArgument, true, out TextGrabMode launchMode); if (isStandardMode) { @@ -195,8 +199,8 @@ private static void ShowAndSetFirstRun() FirstRunWindow frw = new(); frw.Show(); - Settings.Default.FirstRun = false; - Settings.Default.Save(); + _defaultSettings.FirstRun = false; + _defaultSettings.Save(); } private static async Task TryToOpenFile(string possiblePath, bool isQuiet) @@ -253,14 +257,14 @@ async void appStartup(object sender, StartupEventArgs e) if (handledArgument) { // arguments were passed, so don't show firstRun dialog - Settings.Default.FirstRun = false; - Settings.Default.Save(); + _defaultSettings.FirstRun = false; + _defaultSettings.Save(); return; } - if (Settings.Default.FirstRun) + if (_defaultSettings.FirstRun) { - Settings.Default.CorrectToLatin = LanguageUtilities.IsCurrentLanguageLatinBased(); + _defaultSettings.CorrectToLatin = LanguageUtilities.IsCurrentLanguageLatinBased(); ShowAndSetFirstRun(); return; } @@ -277,11 +281,11 @@ private void CurrentDispatcherUnhandledException(object sender, DispatcherUnhand private bool HandleNotifyIcon() { - if (Settings.Default.RunInTheBackground && NumberOfRunningInstances < 2) + if (_defaultSettings.RunInTheBackground && NumberOfRunningInstances < 2) { NotifyIconUtilities.SetupNotifyIcon(); - if (Settings.Default.StartupOnLogin) + if (_defaultSettings.StartupOnLogin) return true; } @@ -295,11 +299,11 @@ private void LaunchFromToast(ToastNotificationActivatedEventArgsCompat toastArgs return; // Need to dispatch to UI thread if performing UI operations - Dispatcher.BeginInvoke((Action)(() => + Dispatcher.BeginInvoke(() => { EditTextWindow mtw = new(argsInvoked); mtw.Show(); - })); + }); } #endregion Methods } From 09da226d3a78195612b8fa8459281c8a483e4731 Mon Sep 17 00:00:00 2001 From: Joseph Finney Date: Sat, 13 Apr 2024 22:28:52 -0500 Subject: [PATCH 07/10] Use new wrapped settings on Settings pages --- Text-Grab/Pages/DangerSettings.xaml.cs | 4 +++- Text-Grab/Pages/KeysSettings.xaml.cs | 2 +- Text-Grab/Pages/LanguageSettings.xaml.cs | 7 ++++--- Text-Grab/Pages/TesseractSettings.xaml.cs | 2 +- 4 files changed, 9 insertions(+), 6 deletions(-) diff --git a/Text-Grab/Pages/DangerSettings.xaml.cs b/Text-Grab/Pages/DangerSettings.xaml.cs index dc35ec7f..69da416e 100644 --- a/Text-Grab/Pages/DangerSettings.xaml.cs +++ b/Text-Grab/Pages/DangerSettings.xaml.cs @@ -11,6 +11,8 @@ namespace Text_Grab.Pages; /// public partial class DangerSettings : Page { + private readonly Settings DefaultSettings = AppUtilities.TextGrabSettings; + public DangerSettings() { InitializeComponent(); @@ -23,7 +25,7 @@ private void ResetSettingsButton_Click(object sender, RoutedEventArgs e) if (areYouSure != MessageBoxResult.Yes) return; - Settings.Default.Reset(); + DefaultSettings.Reset(); Singleton.Instance.DeleteHistory(); App.Current.Shutdown(); } diff --git a/Text-Grab/Pages/KeysSettings.xaml.cs b/Text-Grab/Pages/KeysSettings.xaml.cs index 466d54b1..dee1fc70 100644 --- a/Text-Grab/Pages/KeysSettings.xaml.cs +++ b/Text-Grab/Pages/KeysSettings.xaml.cs @@ -14,7 +14,7 @@ namespace Text_Grab.Pages; /// public partial class KeysSettings : Page { - private Settings DefaultSettings = Settings.Default; + private readonly Settings DefaultSettings = AppUtilities.TextGrabSettings; public KeysSettings() { diff --git a/Text-Grab/Pages/LanguageSettings.xaml.cs b/Text-Grab/Pages/LanguageSettings.xaml.cs index 2121c94a..4fbc221a 100644 --- a/Text-Grab/Pages/LanguageSettings.xaml.cs +++ b/Text-Grab/Pages/LanguageSettings.xaml.cs @@ -22,11 +22,12 @@ namespace Text_Grab.Pages; public partial class LanguageSettings : Page { private bool usingTesseract; + private readonly Settings DefaultSettings = AppUtilities.TextGrabSettings; public LanguageSettings() { InitializeComponent(); - usingTesseract = Settings.Default.UseTesseract && TesseractHelper.CanLocateTesseractExe(); + usingTesseract = DefaultSettings.UseTesseract && TesseractHelper.CanLocateTesseractExe(); } private async void Page_Loaded(object sender, RoutedEventArgs e) @@ -78,7 +79,7 @@ private async void InstallButton_Click(object sender, RoutedEventArgs e) if (string.IsNullOrWhiteSpace(pickedLanguageFile)) return; - string tesseractPath = Path.GetDirectoryName(Settings.Default.TesseractPath) ?? "c:\\"; + string tesseractPath = Path.GetDirectoryName(DefaultSettings.TesseractPath) ?? "c:\\"; string tesseractFilePath = $"{tesseractPath}\\tessdata\\{pickedLanguageFile}"; string tempFilePath = Path.Combine(Path.GetTempPath(), pickedLanguageFile); @@ -136,7 +137,7 @@ public async Task CopyFileWithElevatedPermissions(string sourcePath, string dest private void OpenPathButton_Click(object sender, RoutedEventArgs e) { - string tesseractPath = Path.GetDirectoryName(Settings.Default.TesseractPath) ?? string.Empty; + string tesseractPath = Path.GetDirectoryName(DefaultSettings.TesseractPath) ?? string.Empty; if (string.IsNullOrWhiteSpace(tesseractPath)) return; diff --git a/Text-Grab/Pages/TesseractSettings.xaml.cs b/Text-Grab/Pages/TesseractSettings.xaml.cs index 636e2c4d..983b3602 100644 --- a/Text-Grab/Pages/TesseractSettings.xaml.cs +++ b/Text-Grab/Pages/TesseractSettings.xaml.cs @@ -15,7 +15,7 @@ namespace Text_Grab.Pages; /// public partial class TesseractSettings : Page { - private readonly Settings DefaultSettings = Settings.Default; + private readonly Settings DefaultSettings = AppUtilities.TextGrabSettings; public TesseractSettings() { From 726ef9fa96c8fac6bc5f82d2b5435c748fb8d34d Mon Sep 17 00:00:00 2001 From: Joseph Finney Date: Sat, 13 Apr 2024 22:37:58 -0500 Subject: [PATCH 08/10] Use new settings wrapper for utilities services pages models and controls --- Text-Grab/Controls/BottomBarSettings.xaml.cs | 12 ++++++----- Text-Grab/Controls/WordBorder.xaml.cs | 2 +- Text-Grab/Models/OcrOutput.cs | 2 +- Text-Grab/Pages/GeneralSettings.xaml.cs | 2 +- Text-Grab/Services/HistoryService.cs | 7 ++++--- .../Utilities/CustomBottomBarUtilities.cs | 6 +++--- Text-Grab/Utilities/LanguageUtilities.cs | 4 ++-- Text-Grab/Utilities/NotifyIconUtilities.cs | 2 +- Text-Grab/Utilities/OcrUtilities.cs | 15 ++++++------- Text-Grab/Utilities/OutputUtilities.cs | 4 ++-- Text-Grab/Utilities/ShortcutKeysUtilities.cs | 14 ++++++------- Text-Grab/Utilities/TesseractHelper.cs | 21 +++++++++++-------- Text-Grab/Utilities/WindowUtilities.cs | 10 ++++----- 13 files changed, 54 insertions(+), 47 deletions(-) diff --git a/Text-Grab/Controls/BottomBarSettings.xaml.cs b/Text-Grab/Controls/BottomBarSettings.xaml.cs index d6de7245..0121e5c3 100644 --- a/Text-Grab/Controls/BottomBarSettings.xaml.cs +++ b/Text-Grab/Controls/BottomBarSettings.xaml.cs @@ -12,6 +12,8 @@ namespace Text_Grab.Controls; public partial class BottomBarSettings : FluentWindow { + private readonly Settings DefaultSettings = AppUtilities.TextGrabSettings; + #region Constructors public BottomBarSettings() @@ -30,8 +32,8 @@ public BottomBarSettings() ButtonsInLeftList = new(allBtns); LeftListBox.ItemsSource = ButtonsInLeftList; - ShowCursorTextCheckBox.IsChecked = Settings.Default.ShowCursorText; - ShowScrollbarCheckBox.IsChecked = Settings.Default.ScrollBottomBar; + ShowCursorTextCheckBox.IsChecked = DefaultSettings.ShowCursorText; + ShowScrollbarCheckBox.IsChecked = DefaultSettings.ScrollBottomBar; } #endregion Constructors @@ -115,9 +117,9 @@ private void MoveUpButton_Click(object sender, RoutedEventArgs e) } private void SaveBTN_Click(object sender, RoutedEventArgs e) { - Settings.Default.ShowCursorText = ShowCursorTextCheckBox.IsChecked ?? true; - Settings.Default.ScrollBottomBar = ShowScrollbarCheckBox.IsChecked ?? true; - Settings.Default.Save(); + DefaultSettings.ShowCursorText = ShowCursorTextCheckBox.IsChecked ?? true; + DefaultSettings.ScrollBottomBar = ShowScrollbarCheckBox.IsChecked ?? true; + DefaultSettings.Save(); CustomBottomBarUtilities.SaveCustomBottomBarItemsSetting(ButtonsInRightList.ToList()); if (Owner is EditTextWindow etw) diff --git a/Text-Grab/Controls/WordBorder.xaml.cs b/Text-Grab/Controls/WordBorder.xaml.cs index df352f41..fe61f7fd 100644 --- a/Text-Grab/Controls/WordBorder.xaml.cs +++ b/Text-Grab/Controls/WordBorder.xaml.cs @@ -361,7 +361,7 @@ private void WordBorderControl_MouseDoubleClick(object sender, MouseButtonEventA try { Clipboard.SetDataObject(Word, true); } catch { } - if (Settings.Default.ShowToast + if (AppUtilities.TextGrabSettings.ShowToast && !IsFromEditWindow) NotificationUtilities.ShowToast(Word); diff --git a/Text-Grab/Models/OcrOutput.cs b/Text-Grab/Models/OcrOutput.cs index 602b0c0d..07677e46 100644 --- a/Text-Grab/Models/OcrOutput.cs +++ b/Text-Grab/Models/OcrOutput.cs @@ -17,7 +17,7 @@ public record OcrOutput public void CleanOutput() { - if (Settings.Default is not Settings userSettings + if (AppUtilities.TextGrabSettings is not Settings userSettings || Kind == OcrOutputKind.Barcode) return; diff --git a/Text-Grab/Pages/GeneralSettings.xaml.cs b/Text-Grab/Pages/GeneralSettings.xaml.cs index 62d4c0a6..0576f4ac 100644 --- a/Text-Grab/Pages/GeneralSettings.xaml.cs +++ b/Text-Grab/Pages/GeneralSettings.xaml.cs @@ -113,7 +113,7 @@ private async void Page_Loaded(object sender, RoutedEventArgs e) } else { - StartupOnLoginCheckBox.IsChecked = Settings.Default.StartupOnLogin; + StartupOnLoginCheckBox.IsChecked = DefaultSettings.StartupOnLogin; } ShowToastCheckBox.IsChecked = DefaultSettings.ShowToast; diff --git a/Text-Grab/Services/HistoryService.cs b/Text-Grab/Services/HistoryService.cs index a0273c0d..10bd7b77 100644 --- a/Text-Grab/Services/HistoryService.cs +++ b/Text-Grab/Services/HistoryService.cs @@ -26,6 +26,7 @@ public class HistoryService private List HistoryTextOnly = new(); private List HistoryWithImage = new(); private DispatcherTimer saveTimer = new(); + private readonly Settings DefaultSettings = AppUtilities.TextGrabSettings; #endregion Fields #region Constructors @@ -151,7 +152,7 @@ public async Task PopulateMenuItemWithRecentGrabs(MenuItem recentGrabsMenuItem) public void SaveToHistory(GrabFrame grabFrameToSave) { - if (!Settings.Default.UseHistory) + if (!DefaultSettings.UseHistory) return; HistoryInfo historyInfo = grabFrameToSave.AsHistoryItem(); @@ -186,7 +187,7 @@ public void SaveToHistory(GrabFrame grabFrameToSave) public void SaveToHistory(HistoryInfo infoFromFullscreenGrab) { - if (!Settings.Default.UseHistory || infoFromFullscreenGrab.ImageContent is null) + if (!DefaultSettings.UseHistory || infoFromFullscreenGrab.ImageContent is null) return; string imgRandomName = Guid.NewGuid().ToString(); @@ -209,7 +210,7 @@ public void SaveToHistory(HistoryInfo infoFromFullscreenGrab) public void SaveToHistory(EditTextWindow etwToSave) { - if (!Settings.Default.UseHistory) + if (!DefaultSettings.UseHistory) return; HistoryInfo historyInfo = etwToSave.AsHistoryItem(); diff --git a/Text-Grab/Utilities/CustomBottomBarUtilities.cs b/Text-Grab/Utilities/CustomBottomBarUtilities.cs index 67f2836f..6310d034 100644 --- a/Text-Grab/Utilities/CustomBottomBarUtilities.cs +++ b/Text-Grab/Utilities/CustomBottomBarUtilities.cs @@ -17,7 +17,7 @@ public class CustomBottomBarUtilities { public static List GetCustomBottomBarItemsSetting() { - string json = Settings.Default.BottomButtonsJson; + string json = AppUtilities.TextGrabSettings.BottomButtonsJson; if (string.IsNullOrWhiteSpace(json)) return ButtonInfo.DefaultButtonList; @@ -60,10 +60,10 @@ public static void SaveCustomBottomBarItemsSetting(List bottomBarBut string json = JsonSerializer.Serialize(bottomBarButtons); // save the json string to the settings - Settings.Default.BottomButtonsJson = json; + AppUtilities.TextGrabSettings.BottomButtonsJson = json; // save the settings - Settings.Default.Save(); + AppUtilities.TextGrabSettings.Save(); } public static List GetBottomBarButtons(EditTextWindow editTextWindow) diff --git a/Text-Grab/Utilities/LanguageUtilities.cs b/Text-Grab/Utilities/LanguageUtilities.cs index ace6082f..285340e5 100644 --- a/Text-Grab/Utilities/LanguageUtilities.cs +++ b/Text-Grab/Utilities/LanguageUtilities.cs @@ -21,11 +21,11 @@ public static Language GetOCRLanguage() { Language selectedLanguage = GetCurrentInputLanguage(); - if (!string.IsNullOrEmpty(Settings.Default.LastUsedLang)) + if (!string.IsNullOrEmpty(AppUtilities.TextGrabSettings.LastUsedLang)) { try { - selectedLanguage = new(Settings.Default.LastUsedLang); + selectedLanguage = new(AppUtilities.TextGrabSettings.LastUsedLang); } catch { diff --git a/Text-Grab/Utilities/NotifyIconUtilities.cs b/Text-Grab/Utilities/NotifyIconUtilities.cs index 7d5c0ff5..2e6b0bbb 100644 --- a/Text-Grab/Utilities/NotifyIconUtilities.cs +++ b/Text-Grab/Utilities/NotifyIconUtilities.cs @@ -102,7 +102,7 @@ private static void trayIcon_Disposed(object? sender, EventArgs e) static void HotKeyManager_HotKeyPressed(object? sender, HotKeyEventArgs e) { - if (!Settings.Default.GlobalHotkeysEnabled) + if (!AppUtilities.TextGrabSettings.GlobalHotkeysEnabled) return; IEnumerable shortcuts = ShortcutKeysUtilities.GetShortcutKeySetsFromSettings(); diff --git a/Text-Grab/Utilities/OcrUtilities.cs b/Text-Grab/Utilities/OcrUtilities.cs index 514622cb..2de33ef1 100644 --- a/Text-Grab/Utilities/OcrUtilities.cs +++ b/Text-Grab/Utilities/OcrUtilities.cs @@ -30,6 +30,7 @@ namespace Text_Grab.Utilities; public static class OcrUtilities { + private readonly static Settings DefaultSettings = AppUtilities.TextGrabSettings; public static void GetTextFromOcrLine(this OcrLine ocrLine, bool isSpaceJoiningOCRLang, StringBuilder text) { @@ -45,7 +46,7 @@ public static void GetTextFromOcrLine(this OcrLine ocrLine, bool isSpaceJoiningO { text.AppendLine(ocrLine.Text); - if (Settings.Default.CorrectErrors) + if (DefaultSettings.CorrectErrors) text.TryFixEveryWordLetterNumberErrors(); } else @@ -61,7 +62,7 @@ public static void GetTextFromOcrLine(this OcrLine ocrLine, bool isSpaceJoiningO bool isThisWordSpaceJoining = regexSpaceJoiningWord.IsMatch(wordString); - if (Settings.Default.CorrectErrors) + if (DefaultSettings.CorrectErrors) wordString = wordString.TryFixNumberLetterErrors(); if (isFirstWord || (!isThisWordSpaceJoining && !isPrevWordSpaceJoining)) @@ -74,7 +75,7 @@ public static void GetTextFromOcrLine(this OcrLine ocrLine, bool isSpaceJoiningO } } - if (Settings.Default.CorrectToLatin) + if (DefaultSettings.CorrectToLatin) text.ReplaceGreekOrCyrillicWithLatin(); } @@ -251,7 +252,7 @@ public async static Task> GetTextFromRandomAccessStream(IRandomA outputs.Add(paragraphsOutput); - if (Settings.Default.TryToReadBarcodes) + if (DefaultSettings.TryToReadBarcodes) { Bitmap bitmap = ImageMethods.GetBitmapFromIRandomAccessStream(randomAccessStream); OcrOutput barcodeResult = BarcodeUtilities.TryToReadBarcodes(bitmap); @@ -290,14 +291,14 @@ public async static Task> GetTextFromImageAsync(Bitmap bitmap, L { List outputs = new(); - if (Settings.Default.UseTesseract + if (DefaultSettings.UseTesseract && TesseractHelper.CanLocateTesseractExe() && !string.IsNullOrEmpty(tessTag)) { OcrOutput tesseractOutput = await TesseractHelper.GetOcrOutputFromBitmap(bitmap, language, tessTag); outputs.Add(tesseractOutput); - if (Settings.Default.TryToReadBarcodes) + if (DefaultSettings.TryToReadBarcodes) { OcrOutput barcodeResult = BarcodeUtilities.TryToReadBarcodes(bitmap); outputs.Add(barcodeResult); @@ -312,7 +313,7 @@ public async static Task> GetTextFromImageAsync(Bitmap bitmap, L OcrOutput paragraphsOutput = GetTextFromOcrResult(language, scaledBitmap, ocrResult); outputs.Add(paragraphsOutput); - if (Settings.Default.TryToReadBarcodes) + if (DefaultSettings.TryToReadBarcodes) { OcrOutput barcodeResult = BarcodeUtilities.TryToReadBarcodes(scaledBitmap); outputs.Add(barcodeResult); diff --git a/Text-Grab/Utilities/OutputUtilities.cs b/Text-Grab/Utilities/OutputUtilities.cs index 55872ed0..d6978487 100644 --- a/Text-Grab/Utilities/OutputUtilities.cs +++ b/Text-Grab/Utilities/OutputUtilities.cs @@ -22,10 +22,10 @@ public static void HandleTextFromOcr(string grabbedText, bool isSingleLine, bool return; } - if (!Settings.Default.NeverAutoUseClipboard) + if (!AppUtilities.TextGrabSettings.NeverAutoUseClipboard) try { Clipboard.SetDataObject(grabbedText, true); } catch { } - if (Settings.Default.ShowToast) + if (AppUtilities.TextGrabSettings.ShowToast) NotificationUtilities.ShowToast(grabbedText); WindowUtilities.ShouldShutDown(); diff --git a/Text-Grab/Utilities/ShortcutKeysUtilities.cs b/Text-Grab/Utilities/ShortcutKeysUtilities.cs index 0c50b157..8f5c12cd 100644 --- a/Text-Grab/Utilities/ShortcutKeysUtilities.cs +++ b/Text-Grab/Utilities/ShortcutKeysUtilities.cs @@ -15,15 +15,15 @@ public static void SaveShortcutKeySetSettings(IEnumerable shortc string json = JsonSerializer.Serialize(shortcutKeySets); // save the json string to the settings - Settings.Default.ShortcutKeySets = json; + AppUtilities.TextGrabSettings.ShortcutKeySets = json; // save the settings - Settings.Default.Save(); + AppUtilities.TextGrabSettings.Save(); } public static IEnumerable GetShortcutKeySetsFromSettings() { - string json = Settings.Default.ShortcutKeySets; + string json = AppUtilities.TextGrabSettings.ShortcutKeySets; List defaultKeys = ShortcutKeySet.DefaultShortcutKeySets; @@ -46,14 +46,14 @@ public static IEnumerable GetShortcutKeySetsFromSettings() public static IEnumerable ParseFromPreviousAndDefaultsSettings() { - string fsgKey = Settings.Default.FullscreenGrabHotKey; + string fsgKey = AppUtilities.TextGrabSettings.FullscreenGrabHotKey; if (string.IsNullOrWhiteSpace(fsgKey)) return ShortcutKeySet.DefaultShortcutKeySets; - string gfKey = Settings.Default.GrabFrameHotkey; - string etwKey = Settings.Default.EditWindowHotKey; - string qslKey = Settings.Default.LookupHotKey; + string gfKey = AppUtilities.TextGrabSettings.GrabFrameHotkey; + string etwKey = AppUtilities.TextGrabSettings.EditWindowHotKey; + string qslKey = AppUtilities.TextGrabSettings.LookupHotKey; List priorAndDefaultSettings = new(); diff --git a/Text-Grab/Utilities/TesseractHelper.cs b/Text-Grab/Utilities/TesseractHelper.cs index f6f4bff3..fa01e2ee 100644 --- a/Text-Grab/Utilities/TesseractHelper.cs +++ b/Text-Grab/Utilities/TesseractHelper.cs @@ -30,6 +30,9 @@ public static class TesseractHelper private const string rawProgramsPath = @"%LOCALAPPDATA%\Programs\Tesseract-OCR\tesseract.exe"; private const string basicPath = @"C:\Program Files\Tesseract-OCR\tesseract.exe"; + private readonly static Settings DefaultSettings = AppUtilities.TextGrabSettings; + + public static bool CanLocateTesseractExe() { string tesseractPath = string.Empty; @@ -49,31 +52,31 @@ public static bool CanLocateTesseractExe() private static string GetTesseractPath() { - if (!string.IsNullOrWhiteSpace(Settings.Default.TesseractPath) - && File.Exists(Settings.Default.TesseractPath)) - return Settings.Default.TesseractPath; + if (!string.IsNullOrWhiteSpace(DefaultSettings.TesseractPath) + && File.Exists(DefaultSettings.TesseractPath)) + return DefaultSettings.TesseractPath; string tesExePath = Environment.ExpandEnvironmentVariables(rawPath); string programsPath = Environment.ExpandEnvironmentVariables(rawProgramsPath); if (File.Exists(tesExePath)) { - Settings.Default.TesseractPath = tesExePath; - Settings.Default.Save(); + DefaultSettings.TesseractPath = tesExePath; + DefaultSettings.Save(); return tesExePath; } if (File.Exists(programsPath)) { - Settings.Default.TesseractPath = programsPath; - Settings.Default.Save(); + DefaultSettings.TesseractPath = programsPath; + DefaultSettings.Save(); return programsPath; } if (File.Exists(basicPath)) { - Settings.Default.TesseractPath = basicPath; - Settings.Default.Save(); + DefaultSettings.TesseractPath = basicPath; + DefaultSettings.Save(); return basicPath; } diff --git a/Text-Grab/Utilities/WindowUtilities.cs b/Text-Grab/Utilities/WindowUtilities.cs index 00a859dd..583d48f6 100644 --- a/Text-Grab/Utilities/WindowUtilities.cs +++ b/Text-Grab/Utilities/WindowUtilities.cs @@ -29,10 +29,10 @@ public static void SetWindowPosition(Window passedWindow) string storedPositionString = ""; if (passedWindow is EditTextWindow) - storedPositionString = Settings.Default.EditTextWindowSizeAndPosition; + storedPositionString = AppUtilities.TextGrabSettings.EditTextWindowSizeAndPosition; if (passedWindow is GrabFrame) - storedPositionString = Settings.Default.GrabFrameWindowSizeAndPosition; + storedPositionString = AppUtilities.TextGrabSettings.GrabFrameWindowSizeAndPosition; List storedPosition = new(storedPositionString.Split(',')); @@ -166,7 +166,7 @@ internal static async void CloseAllFullscreenGrabs() } } - if (Settings.Default.TryInsert + if (AppUtilities.TextGrabSettings.TryInsert && !string.IsNullOrWhiteSpace(stringFromOCR) && !isFromEditWindow) { @@ -191,7 +191,7 @@ internal static void FullscreenKeyDown(Key key, bool? isActive = null) internal static async Task TryInsertString(string stringToInsert) { - await Task.Delay(TimeSpan.FromSeconds(Settings.Default.InsertDelay)); + await Task.Delay(TimeSpan.FromSeconds(AppUtilities.TextGrabSettings.InsertDelay)); List inputs = new(); // make sure keys are up. @@ -267,7 +267,7 @@ public static void ShouldShutDown() bool shouldShutDown = false; - if (Settings.Default.RunInTheBackground) + if (AppUtilities.TextGrabSettings.RunInTheBackground) { if (App.Current is App app) { From 08366bc534eb64c97002ce278e427141ec1cd524 Mon Sep 17 00:00:00 2001 From: Joseph Finney Date: Sat, 13 Apr 2024 22:46:01 -0500 Subject: [PATCH 09/10] Swap out settings in all views --- Text-Grab/Views/EditTextWindow.xaml.cs | 73 ++++++++++++----------- Text-Grab/Views/FirstRunWindow.xaml.cs | 38 ++++++------ Text-Grab/Views/FullscreenGrab.xaml.cs | 43 ++++++------- Text-Grab/Views/GrabFrame.xaml.cs | 36 +++++------ Text-Grab/Views/QuickSimpleLookup.xaml.cs | 20 ++++--- Text-Grab/Views/SettingsWindow.xaml.cs | 2 +- 6 files changed, 111 insertions(+), 101 deletions(-) diff --git a/Text-Grab/Views/EditTextWindow.xaml.cs b/Text-Grab/Views/EditTextWindow.xaml.cs index cc163326..3699d038 100644 --- a/Text-Grab/Views/EditTextWindow.xaml.cs +++ b/Text-Grab/Views/EditTextWindow.xaml.cs @@ -57,6 +57,9 @@ public partial class EditTextWindow : Wpf.Ui.Controls.FluentWindow private WindowState? prevWindowState; private CultureInfo selectedCultureInfo = CultureInfo.CurrentCulture; + + private readonly Settings DefaultSettings = AppUtilities.TextGrabSettings; + #endregion Fields #region Constructors @@ -290,12 +293,12 @@ public void SetBottomBarButtons() List buttons = CustomBottomBarUtilities.GetBottomBarButtons(this); - if (Settings.Default.ScrollBottomBar) + if (DefaultSettings.ScrollBottomBar) BottomBarScrollViewer.HorizontalScrollBarVisibility = ScrollBarVisibility.Auto; else BottomBarScrollViewer.HorizontalScrollBarVisibility = ScrollBarVisibility.Disabled; - if (Settings.Default.ShowCursorText) + if (DefaultSettings.ShowCursorText) BottomBarText.Visibility = Visibility.Visible; else BottomBarText.Visibility = Visibility.Collapsed; @@ -517,7 +520,7 @@ private void AlwaysOnTop_Checked(object sender, RoutedEventArgs e) else Topmost = false; - Settings.Default.EditWindowIsOnTop = Topmost; + DefaultSettings.EditWindowIsOnTop = Topmost; } private void CanLaunchUriExecute(object sender, CanExecuteRoutedEventArgs e) @@ -810,13 +813,13 @@ private void FontMenuItem_Click(object sender, RoutedEventArgs e) Debug.WriteLine(fd.Font); - Settings.Default.FontFamilySetting = fd.Font.Name; - Settings.Default.FontSizeSetting = (fd.Font.Size * 96.0 / 72.0); - Settings.Default.IsFontBold = fd.Font.Bold; - Settings.Default.IsFontItalic = fd.Font.Italic; - Settings.Default.IsFontUnderline = fd.Font.Underline; - Settings.Default.IsFontStrikeout = fd.Font.Strikeout; - Settings.Default.Save(); + DefaultSettings.FontFamilySetting = fd.Font.Name; + DefaultSettings.FontSizeSetting = (fd.Font.Size * 96.0 / 72.0); + DefaultSettings.IsFontBold = fd.Font.Bold; + DefaultSettings.IsFontItalic = fd.Font.Italic; + DefaultSettings.IsFontUnderline = fd.Font.Underline; + DefaultSettings.IsFontStrikeout = fd.Font.Strikeout; + DefaultSettings.Save(); SetFontFromSettings(); } @@ -874,12 +877,12 @@ private void HideBottomBarMenuItem_Click(object sender, RoutedEventArgs e) if (sender is MenuItem bbMi && bbMi.IsChecked) { BottomBar.Visibility = Visibility.Collapsed; - Settings.Default.EditWindowBottomBarIsHidden = true; + DefaultSettings.EditWindowBottomBarIsHidden = true; } else { BottomBar.Visibility = Visibility.Visible; - Settings.Default.EditWindowBottomBarIsHidden = false; + DefaultSettings.EditWindowBottomBarIsHidden = false; } } @@ -1000,8 +1003,8 @@ private void LaunchFindAndReplace() private void LaunchFullscreenOnLoad_Click(object sender, RoutedEventArgs e) { - Settings.Default.EditWindowStartFullscreen = LaunchFullscreenOnLoad.IsChecked; - Settings.Default.Save(); + DefaultSettings.EditWindowStartFullscreen = LaunchFullscreenOnLoad.IsChecked; + DefaultSettings.Save(); } private void LaunchQuickSimpleLookup(object sender, RoutedEventArgs e) @@ -1050,8 +1053,8 @@ private async void LoadLanguageMenuItems(MenuItem captureMenuItem) // TODO Find a way to combine with the FSG language drop down bool haveSetLastLang = false; - string lastTextLang = Settings.Default.LastUsedLang; - bool usingTesseract = Settings.Default.UseTesseract && TesseractHelper.CanLocateTesseractExe(); + string lastTextLang = DefaultSettings.LastUsedLang; + bool usingTesseract = DefaultSettings.UseTesseract && TesseractHelper.CanLocateTesseractExe(); if (usingTesseract) { @@ -1194,7 +1197,7 @@ private void MarginsMenuItem_Checked(object sender, RoutedEventArgs e) if (sender is not MenuItem marginsMenuItem) return; - Settings.Default.EtwUseMargins = marginsMenuItem.IsChecked; + DefaultSettings.EtwUseMargins = marginsMenuItem.IsChecked; SetMargins(MarginsMenuItem.IsChecked); } @@ -1382,7 +1385,7 @@ private void PassedTextControl_SizeChanged(object sender, SizeChangedEventArgs e private void PassedTextControl_TextChanged(object sender, TextChangedEventArgs e) { - if (Settings.Default.EditWindowStartFullscreen && prevWindowState is not null) + if (DefaultSettings.EditWindowStartFullscreen && prevWindowState is not null) { this.WindowState = prevWindowState.Value; prevWindowState = null; @@ -1574,7 +1577,7 @@ private void RestorePositionMenuItem_Checked(object sender, RoutedEventArgs e) if (sender is not MenuItem restoreMenuItem) return; - Settings.Default.RestoreEtwPositions = restoreMenuItem.IsChecked; + DefaultSettings.RestoreEtwPositions = restoreMenuItem.IsChecked; } private void RestoreThisPosition_Click(object sender, RoutedEventArgs e) @@ -1584,7 +1587,7 @@ private void RestoreThisPosition_Click(object sender, RoutedEventArgs e) private void RestoreWindowSettings() { - if (Settings.Default.EditWindowStartFullscreen + if (DefaultSettings.EditWindowStartFullscreen && string.IsNullOrWhiteSpace(OpenedFilePath) && !LaunchedFromNotification) { @@ -1594,30 +1597,30 @@ private void RestoreWindowSettings() WindowState = WindowState.Minimized; } - if (Settings.Default.EditWindowIsOnTop) + if (DefaultSettings.EditWindowIsOnTop) { AlwaysOnTop.IsChecked = true; Topmost = true; } - RestorePositionMenuItem.IsChecked = Settings.Default.RestoreEtwPositions; + RestorePositionMenuItem.IsChecked = DefaultSettings.RestoreEtwPositions; - if (Settings.Default.RestoreEtwPositions) + if (DefaultSettings.RestoreEtwPositions) WindowUtilities.SetWindowPosition(this); - if (!Settings.Default.EditWindowIsWordWrapOn) + if (!DefaultSettings.EditWindowIsWordWrapOn) { WrapTextMenuItem.IsChecked = false; PassedTextControl.TextWrapping = TextWrapping.NoWrap; } - if (Settings.Default.EditWindowBottomBarIsHidden) + if (DefaultSettings.EditWindowBottomBarIsHidden) { HideBottomBarMenuItem.IsChecked = true; BottomBar.Visibility = Visibility.Collapsed; } - if (Settings.Default.EtwUseMargins) + if (DefaultSettings.EtwUseMargins) { MarginsMenuItem.IsChecked = true; SetMargins(true); @@ -1728,16 +1731,16 @@ private void SelectWordMenuItem_Click(object sender, RoutedEventArgs e) private void SetFontFromSettings() { - PassedTextControl.FontFamily = new System.Windows.Media.FontFamily(Settings.Default.FontFamilySetting); - PassedTextControl.FontSize = Settings.Default.FontSizeSetting; - if (Settings.Default.IsFontBold) + PassedTextControl.FontFamily = new System.Windows.Media.FontFamily(DefaultSettings.FontFamilySetting); + PassedTextControl.FontSize = DefaultSettings.FontSizeSetting; + if (DefaultSettings.IsFontBold) PassedTextControl.FontWeight = FontWeights.Bold; - if (Settings.Default.IsFontItalic) + if (DefaultSettings.IsFontItalic) PassedTextControl.FontStyle = FontStyles.Italic; TextDecorationCollection tdc = new(); - if (Settings.Default.IsFontUnderline) tdc.Add(TextDecorations.Underline); - if (Settings.Default.IsFontStrikeout) tdc.Add(TextDecorations.Strikethrough); + if (DefaultSettings.IsFontUnderline) tdc.Add(TextDecorations.Underline); + if (DefaultSettings.IsFontStrikeout) tdc.Add(TextDecorations.Strikethrough); PassedTextControl.TextDecorations = tdc; } @@ -2037,8 +2040,8 @@ private void Window_Activated(object sender, EventArgs e) private void Window_Closed(object? sender, EventArgs e) { string windowSizeAndPosition = $"{this.Left},{this.Top},{this.Width},{this.Height}"; - Settings.Default.EditTextWindowSizeAndPosition = windowSizeAndPosition; - Settings.Default.Save(); + DefaultSettings.EditTextWindowSizeAndPosition = windowSizeAndPosition; + DefaultSettings.Save(); Windows.ApplicationModel.DataTransfer.Clipboard.ContentChanged -= Clipboard_ContentChanged; @@ -2103,7 +2106,7 @@ private void WrapTextCHBOX_Checked(object sender, RoutedEventArgs e) else PassedTextControl.TextWrapping = TextWrapping.NoWrap; - Settings.Default.EditWindowIsWordWrapOn = (bool)WrapTextMenuItem.IsChecked; + DefaultSettings.EditWindowIsWordWrapOn = (bool)WrapTextMenuItem.IsChecked; } #endregion Methods } diff --git a/Text-Grab/Views/FirstRunWindow.xaml.cs b/Text-Grab/Views/FirstRunWindow.xaml.cs index 67fad8b4..6c4cf31d 100644 --- a/Text-Grab/Views/FirstRunWindow.xaml.cs +++ b/Text-Grab/Views/FirstRunWindow.xaml.cs @@ -15,6 +15,8 @@ namespace Text_Grab; /// public partial class FirstRunWindow : FluentWindow { + private readonly Settings DefaultSettings = AppUtilities.TextGrabSettings; + #region Constructors public FirstRunWindow() @@ -31,15 +33,15 @@ private void BackgroundCheckBox_Checked(object sender, RoutedEventArgs e) { if (sender is ToggleSwitch toggleSwitch && toggleSwitch.IsChecked is not null) { - Settings.Default.RunInTheBackground = (bool)toggleSwitch.IsChecked; - ImplementAppOptions.ImplementBackgroundOption(Settings.Default.RunInTheBackground); - Settings.Default.Save(); + DefaultSettings.RunInTheBackground = (bool)toggleSwitch.IsChecked; + ImplementAppOptions.ImplementBackgroundOption(DefaultSettings.RunInTheBackground); + DefaultSettings.Save(); } } private async void FirstRun_Loaded(object sender, RoutedEventArgs e) { - TextGrabMode defaultLaunchSetting = Enum.Parse(Settings.Default.DefaultLaunch, true); + TextGrabMode defaultLaunchSetting = Enum.Parse(DefaultSettings.DefaultLaunch, true); switch (defaultLaunchSetting) { case TextGrabMode.Fullscreen: @@ -84,12 +86,12 @@ private async void FirstRun_Loaded(object sender, RoutedEventArgs e) } else { - StartupCheckbox.IsChecked = Settings.Default.StartupOnLogin; + StartupCheckbox.IsChecked = DefaultSettings.StartupOnLogin; } - BackgroundCheckBox.IsChecked = Settings.Default.RunInTheBackground; + BackgroundCheckBox.IsChecked = DefaultSettings.RunInTheBackground; - NotificationsCheckBox.IsChecked = Settings.Default.ShowToast; + NotificationsCheckBox.IsChecked = DefaultSettings.ShowToast; } private void Hyperlink_RequestNavigate(object sender, System.Windows.Navigation.RequestNavigateEventArgs e) @@ -102,8 +104,8 @@ private void NotificationsCheckBox_Checked(object sender, RoutedEventArgs e) { if (sender is ToggleSwitch toggleSwitch && toggleSwitch.IsChecked is not null) { - Settings.Default.ShowToast = (bool)toggleSwitch.IsChecked; - Settings.Default.Save(); + DefaultSettings.ShowToast = (bool)toggleSwitch.IsChecked; + DefaultSettings.Save(); } } @@ -113,7 +115,7 @@ private void OkayButton_Click(object sender, RoutedEventArgs e) if (windowsCount == 2 || windowsCount == 1) { - TextGrabMode defaultLaunchSetting = Enum.Parse(Settings.Default.DefaultLaunch, true); + TextGrabMode defaultLaunchSetting = Enum.Parse(DefaultSettings.DefaultLaunch, true); switch (defaultLaunchSetting) { case TextGrabMode.Fullscreen: @@ -141,15 +143,15 @@ private void RadioButton_Checked(object sender, RoutedEventArgs e) return; if (GrabFrameRDBTN.IsChecked is bool gfOn && gfOn) - Settings.Default.DefaultLaunch = "GrabFrame"; + DefaultSettings.DefaultLaunch = "GrabFrame"; else if (FullScreenRDBTN.IsChecked is bool fsgOn && fsgOn) - Settings.Default.DefaultLaunch = "Fullscreen"; + DefaultSettings.DefaultLaunch = "Fullscreen"; else if (QuickLookupRDBTN.IsChecked is bool qslOn && qslOn) - Settings.Default.DefaultLaunch = "QuickLookup"; + DefaultSettings.DefaultLaunch = "QuickLookup"; else - Settings.Default.DefaultLaunch = "EditText"; + DefaultSettings.DefaultLaunch = "EditText"; - Settings.Default.Save(); + DefaultSettings.Save(); } private void SettingsButton_Click(object sender, RoutedEventArgs e) { @@ -162,9 +164,9 @@ private async void StartupCheckbox_Checked(object sender, RoutedEventArgs e) { if (sender is ToggleSwitch toggleSwitch && toggleSwitch.IsChecked is not null) { - Settings.Default.StartupOnLogin = (bool)toggleSwitch.IsChecked; - await ImplementAppOptions.ImplementStartupOption(Settings.Default.StartupOnLogin); - Settings.Default.Save(); + DefaultSettings.StartupOnLogin = (bool)toggleSwitch.IsChecked; + await ImplementAppOptions.ImplementStartupOption(DefaultSettings.StartupOnLogin); + DefaultSettings.Save(); } } diff --git a/Text-Grab/Views/FullscreenGrab.xaml.cs b/Text-Grab/Views/FullscreenGrab.xaml.cs index fcb3ff8c..1a37c6ca 100644 --- a/Text-Grab/Views/FullscreenGrab.xaml.cs +++ b/Text-Grab/Views/FullscreenGrab.xaml.cs @@ -38,6 +38,7 @@ public partial class FullscreenGrab : Window private double yShiftDelta; private HistoryInfo? historyInfo; bool usingTesseract; + private readonly static Settings DefaultSettings = AppUtilities.TextGrabSettings; #endregion Fields @@ -47,7 +48,7 @@ public FullscreenGrab() { InitializeComponent(); App.SetTheme(); - usingTesseract = Settings.Default.UseTesseract && TesseractHelper.CanLocateTesseractExe(); + usingTesseract = DefaultSettings.UseTesseract && TesseractHelper.CanLocateTesseractExe(); } #endregion Constructors @@ -115,8 +116,8 @@ internal void KeyPressed(Key key, bool? isActive = null) bool isSingleLineChecked = false; if (SingleLineToggleButton.IsChecked is true) isSingleLineChecked = true; - Settings.Default.FSGMakeSingleLineToggle = isSingleLineChecked; - Settings.Default.Save(); + DefaultSettings.FSGMakeSingleLineToggle = isSingleLineChecked; + DefaultSettings.Save(); break; case Key.E: if (isActive is null) @@ -127,8 +128,8 @@ internal void KeyPressed(Key key, bool? isActive = null) bool isSendToEditChecked = false; if (SendToEditTextToggleButton.IsChecked is true) isSendToEditChecked = true; - Settings.Default.FsgSendEtwToggle = isSendToEditChecked; - Settings.Default.Save(); + DefaultSettings.FsgSendEtwToggle = isSendToEditChecked; + DefaultSettings.Save(); break; case Key.F: if (isActive is null) @@ -152,8 +153,8 @@ internal void KeyPressed(Key key, bool? isActive = null) bool isNormalChecked = false; if (StandardModeToggleButton.IsChecked is true) isNormalChecked = true; - Settings.Default.FSGMakeSingleLineToggle = !isNormalChecked; - Settings.Default.Save(); + DefaultSettings.FSGMakeSingleLineToggle = !isNormalChecked; + DefaultSettings.Save(); break; case Key.T: if (TableToggleButton.Visibility == Visibility.Collapsed) @@ -272,8 +273,8 @@ private void LanguagesComboBox_PreviewMouseDown(object sender, MouseButtonEventA { if (e.MiddleButton == MouseButtonState.Pressed) { - Settings.Default.LastUsedLang = String.Empty; - Settings.Default.Save(); + DefaultSettings.LastUsedLang = String.Empty; + DefaultSettings.Save(); } } @@ -284,8 +285,8 @@ private void LanguagesComboBox_SelectionChanged(object sender, SelectionChangedE if (languageCmbBox.SelectedItem is TessLang tessLang) { - Settings.Default.LastUsedLang = tessLang.CultureDisplayName; - Settings.Default.Save(); + DefaultSettings.LastUsedLang = tessLang.CultureDisplayName; + DefaultSettings.Save(); TableMenuItem.Visibility = Visibility.Collapsed; TableToggleButton.Visibility = Visibility.Collapsed; @@ -293,8 +294,8 @@ private void LanguagesComboBox_SelectionChanged(object sender, SelectionChangedE if (languageCmbBox.SelectedItem is Language pickedLang) { - Settings.Default.LastUsedLang = pickedLang.LanguageTag; - Settings.Default.Save(); + DefaultSettings.LastUsedLang = pickedLang.LanguageTag; + DefaultSettings.Save(); TableMenuItem.Visibility = Visibility.Visible; TableToggleButton.Visibility = Visibility.Visible; @@ -345,7 +346,7 @@ private static async Task LoadOcrLanguages(ComboBox languagesComboBox, bool usin // TODO Find a way to combine with the ETW language drop down bool haveSetLastLang = false; - string lastTextLang = Settings.Default.LastUsedLang; + string lastTextLang = DefaultSettings.LastUsedLang; if (usingTesseract) { List tesseractLanguages = await TesseractHelper.TesseractLanguages(); @@ -620,7 +621,7 @@ private async void RegionClickCanvas_MouseUp(object sender, MouseButtonEventArgs else textFromOCR = await OcrUtilities.GetRegionsTextAsync(this, regionScaled, selectedOcrLang, tessTag); - if (Settings.Default.UseHistory && !isSmallClick) + if (DefaultSettings.UseHistory && !isSmallClick) { GetDpiAdjustedRegionOfSelectBorder(out DpiScale dpi, out double posLeft, out double posTop); @@ -691,8 +692,8 @@ private void SingleLineMenuItem_Click(object? sender = null, RoutedEventArgs? e bool isSingleLineChecked = false; if (SingleLineToggleButton.IsChecked is true) isSingleLineChecked = true; - Settings.Default.FSGMakeSingleLineToggle = isSingleLineChecked; - Settings.Default.Save(); + DefaultSettings.FSGMakeSingleLineToggle = isSingleLineChecked; + DefaultSettings.Save(); } } @@ -711,13 +712,13 @@ private async void Window_Loaded(object sender, RoutedEventArgs e) SetImageToBackground(); - if (Settings.Default.FSGMakeSingleLineToggle) + if (DefaultSettings.FSGMakeSingleLineToggle) { SingleLineToggleButton.IsChecked = true; SelectSingleToggleButton(SingleLineToggleButton); } - if (Settings.Default.FsgSendEtwToggle) + if (DefaultSettings.FsgSendEtwToggle) SendToEditTextToggleButton.IsChecked = true; #if DEBUG @@ -782,8 +783,8 @@ private void StandardModeToggleButton_Click(object sender, RoutedEventArgs e) if (StandardModeToggleButton.IsChecked is true) isStandardChecked = true; - Settings.Default.FSGMakeSingleLineToggle = !isStandardChecked; - Settings.Default.Save(); + DefaultSettings.FSGMakeSingleLineToggle = !isStandardChecked; + DefaultSettings.Save(); } } diff --git a/Text-Grab/Views/GrabFrame.xaml.cs b/Text-Grab/Views/GrabFrame.xaml.cs index 9a271550..2a01c823 100644 --- a/Text-Grab/Views/GrabFrame.xaml.cs +++ b/Text-Grab/Views/GrabFrame.xaml.cs @@ -73,6 +73,8 @@ public partial class GrabFrame : Window private bool wasAltHeld = false; private double windowFrameImageScale = 1; private ObservableCollection wordBorders = new(); + private readonly static Settings DefaultSettings = AppUtilities.TextGrabSettings; + #endregion Fields #region Constructors @@ -642,10 +644,10 @@ private async void AddNewWordBorder(Border selectBorder) rect = new(rect.X + 4, rect.Y, (rect.Width * dpi.DpiScaleX) + 10, rect.Height * dpi.DpiScaleY); string ocrText = await OcrUtilities.GetTextFromAbsoluteRectAsync(rect.GetScaleSizeByFraction(viewBoxZoomFactor), CurrentLanguage); - if (Settings.Default.CorrectErrors) + if (DefaultSettings.CorrectErrors) ocrText = ocrText.TryFixEveryWordLetterNumberErrors(); - if (Settings.Default.CorrectToLatin) + if (DefaultSettings.CorrectToLatin) ocrText = ocrText.ReplaceGreekOrCyrillicWithLatin(); if (frameContentImageSource is BitmapImage bmpImg) @@ -942,10 +944,10 @@ private async Task DrawRectanglesAroundWords(string searchWord = "") string ocrText = lineText.ToString(); - if (Settings.Default.CorrectErrors) + if (DefaultSettings.CorrectErrors) ocrText = ocrText.TryFixEveryWordLetterNumberErrors(); - if (Settings.Default.CorrectToLatin) + if (DefaultSettings.CorrectToLatin) ocrText = ocrText.ReplaceGreekOrCyrillicWithLatin(); WordBorder wordBorderBox = new() @@ -988,7 +990,7 @@ private async Task DrawRectanglesAroundWords(string searchWord = "") SetRotationBasedOnOcrResult(); - if (Settings.Default.TryToReadBarcodes) + if (DefaultSettings.TryToReadBarcodes) TryToReadBarcodes(dpi); if (IsWordEditMode) @@ -1197,8 +1199,8 @@ private SolidColorBrush GetBackgroundBrushFromBitmap(ref DpiScale dpi, double sc private void GetGrabFrameUserSettings() { - AutoOcrCheckBox.IsChecked = Settings.Default.GrabFrameAutoOcr; - AlwaysUpdateEtwCheckBox.IsChecked = Settings.Default.GrabFrameUpdateEtw; + AutoOcrCheckBox.IsChecked = DefaultSettings.GrabFrameAutoOcr; + AlwaysUpdateEtwCheckBox.IsChecked = DefaultSettings.GrabFrameUpdateEtw; } private void GrabBTN_Click(object sender, RoutedEventArgs e) @@ -1218,10 +1220,10 @@ private void GrabBTN_Click(object sender, RoutedEventArgs e) return; } - if (!Settings.Default.NeverAutoUseClipboard) + if (!DefaultSettings.NeverAutoUseClipboard) try { Clipboard.SetDataObject(FrameText, true); } catch { } - if (Settings.Default.ShowToast) + if (DefaultSettings.ShowToast) NotificationUtilities.ShowToast(FrameText); } @@ -1427,8 +1429,8 @@ private void LanguagesComboBox_MouseDown(object sender, MouseButtonEventArgs e) { if (e.MiddleButton == MouseButtonState.Pressed) { - Settings.Default.LastUsedLang = String.Empty; - Settings.Default.Save(); + DefaultSettings.LastUsedLang = String.Empty; + DefaultSettings.Save(); } } @@ -1442,8 +1444,8 @@ private void LanguagesComboBox_SelectionChanged(object sender, SelectionChangedE if (pickedLang != null) { currentLanguage = pickedLang; - Settings.Default.LastUsedLang = pickedLang.LanguageTag; - Settings.Default.Save(); + DefaultSettings.LastUsedLang = pickedLang.LanguageTag; + DefaultSettings.Save(); } ResetGrabFrame(); @@ -1950,10 +1952,10 @@ private void SelectAllWordBorders(object? sender = null, RoutedEventArgs? e = nu private void SetGrabFrameUserSettings() { string windowSizeAndPosition = $"{this.Left},{this.Top},{this.Width},{this.Height}"; - Settings.Default.GrabFrameWindowSizeAndPosition = windowSizeAndPosition; - Settings.Default.GrabFrameAutoOcr = AutoOcrCheckBox.IsChecked; - Settings.Default.GrabFrameUpdateEtw = AlwaysUpdateEtwCheckBox.IsChecked; - Settings.Default.Save(); + DefaultSettings.GrabFrameWindowSizeAndPosition = windowSizeAndPosition; + DefaultSettings.GrabFrameAutoOcr = AutoOcrCheckBox.IsChecked; + DefaultSettings.GrabFrameUpdateEtw = AlwaysUpdateEtwCheckBox.IsChecked; + DefaultSettings.Save(); } private void SetRefreshOrOcrFrameBtnVis() { diff --git a/Text-Grab/Views/QuickSimpleLookup.xaml.cs b/Text-Grab/Views/QuickSimpleLookup.xaml.cs index cdd54593..c5045ca7 100644 --- a/Text-Grab/Views/QuickSimpleLookup.xaml.cs +++ b/Text-Grab/Views/QuickSimpleLookup.xaml.cs @@ -30,6 +30,8 @@ public partial class QuickSimpleLookup : Wpf.Ui.Controls.FluentWindow private LookupItem? lastSelection; private int rowCount = 0; private string valueUnderEdit = string.Empty; + private readonly static Settings DefaultSettings = AppUtilities.TextGrabSettings; + #endregion Fields #region Constructors @@ -316,10 +318,10 @@ private async void PickSaveLocation_Click(object sender, RoutedEventArgs e) dlg.FileName = "QuickSimpleLookupDataFile.csv"; dlg.OverwritePrompt = false; - if (!string.IsNullOrEmpty(Settings.Default.LookupFileLocation)) + if (!string.IsNullOrEmpty(DefaultSettings.LookupFileLocation)) { - dlg.InitialDirectory = Settings.Default.LookupFileLocation; - dlg.FileName = Path.GetFileName(Settings.Default.LookupFileLocation); + dlg.InitialDirectory = DefaultSettings.LookupFileLocation; + dlg.FileName = Path.GetFileName(DefaultSettings.LookupFileLocation); } var result = dlg.ShowDialog(); @@ -327,8 +329,8 @@ private async void PickSaveLocation_Click(object sender, RoutedEventArgs e) if (result is false) return; - Settings.Default.LookupFileLocation = dlg.FileName; - Settings.Default.Save(); + DefaultSettings.LookupFileLocation = dlg.FileName; + DefaultSettings.Save(); if (File.Exists(dlg.FileName)) { @@ -691,9 +693,9 @@ private void UpdateRowCount() private async void Window_Loaded(object sender, RoutedEventArgs e) { - await ReadCsvFileIntoQuickSimpleLookup(Settings.Default.LookupFileLocation); + await ReadCsvFileIntoQuickSimpleLookup(DefaultSettings.LookupFileLocation); - if (Settings.Default.TryInsert && !IsFromETW) + if (DefaultSettings.TryInsert && !IsFromETW) PasteToggleButton.IsChecked = true; if (IsFromETW) @@ -718,10 +720,10 @@ private async Task WriteDataToCSV() try { - if (string.IsNullOrEmpty(Settings.Default.LookupFileLocation)) + if (string.IsNullOrEmpty(DefaultSettings.LookupFileLocation)) await FileUtilities.SaveTextFile(csvContents.ToString(), cacheFilename, FileStorageKind.WithExe); else - await FileUtilities.SaveTextFile(csvContents.ToString(), Settings.Default.LookupFileLocation, FileStorageKind.Absolute); + await FileUtilities.SaveTextFile(csvContents.ToString(), DefaultSettings.LookupFileLocation, FileStorageKind.Absolute); SaveBTN.Visibility = Visibility.Collapsed; } diff --git a/Text-Grab/Views/SettingsWindow.xaml.cs b/Text-Grab/Views/SettingsWindow.xaml.cs index a2c05f7a..5e753820 100644 --- a/Text-Grab/Views/SettingsWindow.xaml.cs +++ b/Text-Grab/Views/SettingsWindow.xaml.cs @@ -26,7 +26,7 @@ public SettingsWindow() private void Window_Closed(object? sender, EventArgs e) { - Settings.Default.Save(); + AppUtilities.TextGrabSettings.Save(); if (App.Current is App app) NotifyIconUtilities.RegisterHotKeys(app); From 95be674e799974fe457ae16892b292dba15dccfd Mon Sep 17 00:00:00 2001 From: Joseph Finney Date: Sun, 14 Apr 2024 15:54:05 -0500 Subject: [PATCH 10/10] Catch settings getting applied when settings pages load Save Tesseract path when setting it Fixes #448 Fixes #450 --- Text-Grab/Pages/GeneralSettings.xaml | 4 +- Text-Grab/Pages/GeneralSettings.xaml.cs | 78 ++++++++++++++++++++++- Text-Grab/Pages/KeysSettings.xaml.cs | 21 ++++++ Text-Grab/Pages/LanguageSettings.xaml.cs | 1 + Text-Grab/Pages/TesseractSettings.xaml.cs | 12 ++++ Text-Grab/Views/SettingsWindow.xaml.cs | 4 +- 6 files changed, 112 insertions(+), 8 deletions(-) diff --git a/Text-Grab/Pages/GeneralSettings.xaml b/Text-Grab/Pages/GeneralSettings.xaml index 7593e599..e112d012 100644 --- a/Text-Grab/Pages/GeneralSettings.xaml +++ b/Text-Grab/Pages/GeneralSettings.xaml @@ -8,7 +8,7 @@ xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:ui="http://schemas.lepo.co/wpfui/2022/xaml" Title="GeneralSettings" - d:DesignHeight="450" + d:DesignHeight="1450" d:DesignWidth="800" Loaded="Page_Loaded" mc:Ignorable="d"> @@ -203,7 +203,6 @@ Try to read barcodes @@ -299,7 +298,6 @@ Keep recent history of Grabs and Edit Text Windows diff --git a/Text-Grab/Pages/GeneralSettings.xaml.cs b/Text-Grab/Pages/GeneralSettings.xaml.cs index 0576f4ac..af34ace9 100644 --- a/Text-Grab/Pages/GeneralSettings.xaml.cs +++ b/Text-Grab/Pages/GeneralSettings.xaml.cs @@ -5,7 +5,6 @@ using System.Windows.Controls; using System.Windows.Media; using Text_Grab.Properties; -using Text_Grab.Services; using Text_Grab.Utilities; using Windows.ApplicationModel; using Wpf.Ui.Controls; @@ -23,6 +22,7 @@ public partial class GeneralSettings : Page private readonly Brush BadBrush = new SolidColorBrush(Colors.Red); private readonly Brush GoodBrush = new SolidColorBrush(Colors.Transparent); private double InsertDelaySeconds = 1.5; + private bool settingsSet = false; #endregion Fields @@ -127,11 +127,13 @@ private async void Page_Loaded(object sender, RoutedEventArgs e) TryInsertCheckbox.IsChecked = DefaultSettings.TryInsert; InsertDelaySeconds = DefaultSettings.InsertDelay; SecondsTextBox.Text = InsertDelaySeconds.ToString("##.#", System.Globalization.CultureInfo.InvariantCulture); + + settingsSet = true; } private void ValidateTextIsNumber(object sender, TextChangedEventArgs e) { - if (!IsLoaded) + if (!settingsSet) return; if (sender is System.Windows.Controls.TextBox numberInputBox) @@ -155,26 +157,41 @@ private void ValidateTextIsNumber(object sender, TextChangedEventArgs e) private void FullScreenRDBTN_Checked(object sender, RoutedEventArgs e) { + if (!settingsSet) + return; + DefaultSettings.DefaultLaunch = TextGrabMode.Fullscreen.ToString(); } private void GrabFrameRDBTN_Checked(object sender, RoutedEventArgs e) { + if (!settingsSet) + return; + DefaultSettings.DefaultLaunch = TextGrabMode.GrabFrame.ToString(); } private void EditTextRDBTN_Checked(object sender, RoutedEventArgs e) { + if (!settingsSet) + return; + DefaultSettings.DefaultLaunch = TextGrabMode.EditText.ToString(); } private void QuickLookupRDBTN_Checked(object sender, RoutedEventArgs e) { + if (!settingsSet) + return; + DefaultSettings.DefaultLaunch = TextGrabMode.QuickLookup.ToString(); } private void RunInBackgroundChkBx_Checked(object sender, RoutedEventArgs e) { + if (!settingsSet) + return; + if (sender is not ToggleSwitch runInBackgroundSwitch) return; @@ -184,101 +201,158 @@ private void RunInBackgroundChkBx_Checked(object sender, RoutedEventArgs e) private void SystemThemeRdBtn_Checked(object sender, RoutedEventArgs e) { + if (!settingsSet) + return; + DefaultSettings.AppTheme = AppTheme.System.ToString(); App.SetTheme(); } private void LightThemeRdBtn_Checked(object sender, RoutedEventArgs e) { + if (!settingsSet) + return; + DefaultSettings.AppTheme = AppTheme.Light.ToString(); App.SetTheme(); } private void DarkThemeRdBtn_Checked(object sender, RoutedEventArgs e) { + if (!settingsSet) + return; + DefaultSettings.AppTheme = AppTheme.Dark.ToString(); App.SetTheme(); } private void ReadBarcodesBarcode_Checked(object sender, RoutedEventArgs e) { + if (!settingsSet) + return; + DefaultSettings.TryToReadBarcodes = true; } private void ReadBarcodesBarcode_Unchecked(object sender, RoutedEventArgs e) { + if (!settingsSet) + return; + DefaultSettings.TryToReadBarcodes = false; } private void HistorySwitch_Checked(object sender, RoutedEventArgs e) { + if (!settingsSet) + return; + DefaultSettings.UseHistory = true; } private void HistorySwitch_Unchecked(object sender, RoutedEventArgs e) { + if (!settingsSet) + return; + DefaultSettings.UseHistory = false; } private void ErrorCorrectBox_Checked(object sender, RoutedEventArgs e) { + if (!settingsSet) + return; + DefaultSettings.CorrectErrors = true; } private void ErrorCorrectBox_Unchecked(object sender, RoutedEventArgs e) { + if (!settingsSet) + return; + DefaultSettings.CorrectErrors = false; } private void CorrectToLatin_Checked(object sender, RoutedEventArgs e) { + if (!settingsSet) + return; + DefaultSettings.CorrectToLatin = true; } private void CorrectToLatin_Unchecked(object sender, RoutedEventArgs e) { + if (!settingsSet) + return; + DefaultSettings.CorrectToLatin = false; } private void NeverUseClipboardChkBx_Checked(object sender, RoutedEventArgs e) { + if (!settingsSet) + return; + DefaultSettings.NeverAutoUseClipboard = true; } private void NeverUseClipboardChkBx_Unchecked(object sender, RoutedEventArgs e) { + if (!settingsSet) + return; + DefaultSettings.NeverAutoUseClipboard = false; } private async void StartupOnLoginCheckBox_Checked(object sender, RoutedEventArgs e) { + if (!settingsSet) + return; + DefaultSettings.StartupOnLogin = true; await ImplementAppOptions.ImplementStartupOption(true); } private async void StartupOnLoginCheckBox_Unchecked(object sender, RoutedEventArgs e) { + if (!settingsSet) + return; + DefaultSettings.StartupOnLogin = false; await ImplementAppOptions.ImplementStartupOption(false); } private void TryInsertCheckbox_Checked(object sender, RoutedEventArgs e) { + if (!settingsSet) + return; + DefaultSettings.TryInsert = true; } private void TryInsertCheckbox_Unchecked(object sender, RoutedEventArgs e) { + if (!settingsSet) + return; + DefaultSettings.TryInsert = false; } private void ShowToastCheckBox_Checked(object sender, RoutedEventArgs e) { + if (!settingsSet) + return; + DefaultSettings.ShowToast = true; } private void ShowToastCheckBox_Unchecked(object sender, RoutedEventArgs e) { + if (!settingsSet) + return; + DefaultSettings.ShowToast = false; } } diff --git a/Text-Grab/Pages/KeysSettings.xaml.cs b/Text-Grab/Pages/KeysSettings.xaml.cs index dee1fc70..84cbb3ac 100644 --- a/Text-Grab/Pages/KeysSettings.xaml.cs +++ b/Text-Grab/Pages/KeysSettings.xaml.cs @@ -15,6 +15,7 @@ namespace Text_Grab.Pages; public partial class KeysSettings : Page { private readonly Settings DefaultSettings = AppUtilities.TextGrabSettings; + private bool settingsSet = false; public KeysSettings() { @@ -23,6 +24,9 @@ public KeysSettings() private void ShortcutControl_Recording(object sender, EventArgs e) { + if (!settingsSet) + return; + foreach (UIElement child in ShortcutsStackPanel.Children) if (child is ShortcutControl shortcutControl && sender is ShortcutControl senderShortcut @@ -32,6 +36,9 @@ private void ShortcutControl_Recording(object sender, EventArgs e) private void ShortcutControl_KeySetChanged(object sender, EventArgs e) { + if (!settingsSet) + return; + if (HotKeysAllDifferent()) { List shortcutKeys = []; @@ -133,10 +140,15 @@ private void Page_Loaded(object sender, RoutedEventArgs e) break; } } + + settingsSet = true; } private void RunInBackgroundChkBx_Checked(object sender, RoutedEventArgs e) { + if (!settingsSet) + return; + DefaultSettings.RunInTheBackground = true; ImplementAppOptions.ImplementBackgroundOption(DefaultSettings.RunInTheBackground); DefaultSettings.Save(); @@ -144,6 +156,9 @@ private void RunInBackgroundChkBx_Checked(object sender, RoutedEventArgs e) private void RunInBackgroundChkBx_Unchecked(object sender, RoutedEventArgs e) { + if (!settingsSet) + return; + DefaultSettings.RunInTheBackground = false; ImplementAppOptions.ImplementBackgroundOption(DefaultSettings.RunInTheBackground); GlobalHotkeysCheckbox.IsChecked = false; @@ -152,11 +167,17 @@ private void RunInBackgroundChkBx_Unchecked(object sender, RoutedEventArgs e) private void GlobalHotkeysCheckbox_Checked(object sender, RoutedEventArgs e) { + if (!settingsSet) + return; + DefaultSettings.GlobalHotkeysEnabled = true; } private void GlobalHotkeysCheckbox_Unchecked(object sender, RoutedEventArgs e) { + if (!settingsSet) + return; + DefaultSettings.GlobalHotkeysEnabled = false; } } diff --git a/Text-Grab/Pages/LanguageSettings.xaml.cs b/Text-Grab/Pages/LanguageSettings.xaml.cs index 4fbc221a..ceceefe1 100644 --- a/Text-Grab/Pages/LanguageSettings.xaml.cs +++ b/Text-Grab/Pages/LanguageSettings.xaml.cs @@ -24,6 +24,7 @@ public partial class LanguageSettings : Page private bool usingTesseract; private readonly Settings DefaultSettings = AppUtilities.TextGrabSettings; + public LanguageSettings() { InitializeComponent(); diff --git a/Text-Grab/Pages/TesseractSettings.xaml.cs b/Text-Grab/Pages/TesseractSettings.xaml.cs index 983b3602..b432df6d 100644 --- a/Text-Grab/Pages/TesseractSettings.xaml.cs +++ b/Text-Grab/Pages/TesseractSettings.xaml.cs @@ -16,6 +16,8 @@ namespace Text_Grab.Pages; public partial class TesseractSettings : Page { private readonly Settings DefaultSettings = AppUtilities.TextGrabSettings; + private bool settingsSet = false; + public TesseractSettings() { @@ -24,6 +26,9 @@ public TesseractSettings() private void TesseractPathTextBox_TextChanged(object sender, TextChangedEventArgs e) { + if (!settingsSet) + return; + if (sender is not System.Windows.Controls.TextBox pathTextbox || pathTextbox.Text is not string pathText) return; @@ -31,6 +36,8 @@ private void TesseractPathTextBox_TextChanged(object sender, TextChangedEventArg UseTesseractCheckBox.IsEnabled = true; else UseTesseractCheckBox.IsEnabled = false; + + DefaultSettings.TesseractPath = pathText; } private void OpenPathButton_Click(object sender, RoutedEventArgs args) @@ -62,6 +69,9 @@ private void Hyperlink_RequestNavigate(object sender, RequestNavigateEventArgs e private void UseTesseractCheckBox_Checked(object sender, RoutedEventArgs e) { + if (!settingsSet) + return; + if (sender is not ToggleSwitch useTesseractSwitch) return; @@ -80,5 +90,7 @@ private void Page_Loaded(object sender, RoutedEventArgs e) UseTesseractCheckBox.IsChecked = false; UseTesseractCheckBox.IsEnabled = false; DefaultSettings.UseTesseract = false; + + settingsSet = true; } } diff --git a/Text-Grab/Views/SettingsWindow.xaml.cs b/Text-Grab/Views/SettingsWindow.xaml.cs index 5e753820..a7283f18 100644 --- a/Text-Grab/Views/SettingsWindow.xaml.cs +++ b/Text-Grab/Views/SettingsWindow.xaml.cs @@ -1,7 +1,6 @@ using System; using System.Windows; using Text_Grab.Pages; -using Text_Grab.Properties; using Text_Grab.Utilities; namespace Text_Grab; @@ -17,7 +16,6 @@ public SettingsWindow() { InitializeComponent(); App.SetTheme(); - } #endregion Constructors @@ -41,6 +39,6 @@ private void Window_Loaded(object sender, RoutedEventArgs e) if (App.Current is App app) NotifyIconUtilities.UnregisterHotkeys(app); } + #endregion Methods } -