diff --git a/WinUIGallery/Controls/PageHeader.xaml.cs b/WinUIGallery/Controls/PageHeader.xaml.cs index dd3b6f4bf..4500d3c0d 100644 --- a/WinUIGallery/Controls/PageHeader.xaml.cs +++ b/WinUIGallery/Controls/PageHeader.xaml.cs @@ -101,7 +101,7 @@ private void UserControl_Loaded(object sender, RoutedEventArgs e) } if (Item != null) { - FavoriteButton.IsChecked = SettingsHelper.Contains(SettingsKeys.Favorites, Item.UniqueId); + FavoriteButton.IsChecked = SettingsHelper.Current.Favorites.Contains(Item.UniqueId); } } @@ -121,11 +121,11 @@ private void FavoriteButton_Click(object sender, RoutedEventArgs e) { if (toggleButton.IsChecked == true) { - SettingsHelper.TryAddItem(SettingsKeys.Favorites, Item.UniqueId, InsertPosition.Last); + SettingsHelper.Current.UpdateFavorites(items => items.AddToLast(Item.UniqueId)); } else { - SettingsHelper.TryRemoveItem(SettingsKeys.Favorites, Item.UniqueId); + SettingsHelper.Current.UpdateFavorites(items => items.Remove(Item.UniqueId)); } } } diff --git a/WinUIGallery/Helpers/NavigationOrientationHelper.cs b/WinUIGallery/Helpers/NavigationOrientationHelper.cs index 57c61db45..cb98e5726 100644 --- a/WinUIGallery/Helpers/NavigationOrientationHelper.cs +++ b/WinUIGallery/Helpers/NavigationOrientationHelper.cs @@ -2,43 +2,20 @@ // Licensed under the MIT License. using Microsoft.UI.Xaml.Controls; -using Microsoft.Windows.Storage; namespace WinUIGallery.Helpers; public static partial class NavigationOrientationHelper { - private static bool _isLeftMode = true; - private static ApplicationData appData = ApplicationData.GetDefault(); public static bool IsLeftMode() { - if (NativeMethods.IsAppPackaged) - { - var valueFromSettings = appData.LocalSettings.Values[SettingsKeys.IsLeftMode]; - if (valueFromSettings == null) - { - appData.LocalSettings.Values[SettingsKeys.IsLeftMode] = true; - valueFromSettings = true; - } - return (bool)valueFromSettings; - } - else - { - return _isLeftMode; - } + return SettingsHelper.Current.IsLeftMode; } public static void IsLeftModeForElement(bool isLeftMode) { UpdateNavigationViewForElement(isLeftMode); - if (NativeMethods.IsAppPackaged) - { - appData.LocalSettings.Values[SettingsKeys.IsLeftMode] = isLeftMode; - } - else - { - _isLeftMode = isLeftMode; - } + SettingsHelper.Current.IsLeftMode = isLeftMode; } public static void UpdateNavigationViewForElement(bool isLeftMode) diff --git a/WinUIGallery/Helpers/ProtocolActivationClipboardHelper.cs b/WinUIGallery/Helpers/ProtocolActivationClipboardHelper.cs index aa4779350..aa8763bf4 100644 --- a/WinUIGallery/Helpers/ProtocolActivationClipboardHelper.cs +++ b/WinUIGallery/Helpers/ProtocolActivationClipboardHelper.cs @@ -15,40 +15,16 @@ namespace WinUIGallery.Helpers; /// public static partial class ProtocolActivationClipboardHelper { - private static bool _showCopyLinkTeachingTip = true; - private static ApplicationData appData = ApplicationData.GetDefault(); - public static bool ShowCopyLinkTeachingTip { get { - if (NativeMethods.IsAppPackaged) - { - object valueFromSettings = appData.LocalSettings.Values[SettingsKeys.ShowCopyLinkTeachingTip]; - if (valueFromSettings == null) - { - appData.LocalSettings.Values[SettingsKeys.ShowCopyLinkTeachingTip] = true; - valueFromSettings = true; - } - return (bool)valueFromSettings; - } - else - { - return _showCopyLinkTeachingTip; - } + return SettingsHelper.Current.IsShowCopyLinkTeachingTip; } set { - if (NativeMethods.IsAppPackaged) - { - appData.LocalSettings.Values[SettingsKeys.ShowCopyLinkTeachingTip] = value; - - } - else - { - _showCopyLinkTeachingTip = value; - } + SettingsHelper.Current.IsShowCopyLinkTeachingTip = value; } } diff --git a/WinUIGallery/Helpers/SettingsHelper.cs b/WinUIGallery/Helpers/SettingsHelper.cs deleted file mode 100644 index 12be0453e..000000000 --- a/WinUIGallery/Helpers/SettingsHelper.cs +++ /dev/null @@ -1,192 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT License. - -using Microsoft.Windows.Storage; -using System; -using System.Collections.Generic; -using System.Diagnostics; -using System.Linq; - -namespace WinUIGallery.Helpers; - -/// -/// Enum to specify whether an item should be inserted at the beginning or end of the list. -/// -public enum InsertPosition -{ - /// - /// Insert at the beginning of the list. - /// - First, - - /// - /// Insert at the end of the list. - /// - Last -} - -/// -/// Provides utility methods for managing application settings, including operations for storing, retrieving, and -/// manipulating lists of strings in the application's local settings. -/// -public static partial class SettingsHelper -{ - /// - /// The maximum number of items to retain in the recently visited list. - /// - public const int MaxRecentlyVisitedSamples = 7; - - /// - /// An instance of ApplicationData for the current user. - /// - private static ApplicationData appData = ApplicationData.GetDefault(); - - /// - /// Information Separator: Represents an invisible, JSON-safe delimiter used for internal string serialization. - /// - /// This delimiter is intended for separating values in serialized strings where compatibility - /// with JSON is a concern. It is not intended for public use or modification. - private const char delimiter = '\u001f'; - - /// - /// Attempts to add an item to a list associated with the specified key, ensuring no duplicates and optionally - /// enforcing a size limit. - /// - /// The key identifying the list to which the item will be added. Cannot be null, empty, or whitespace. - /// The item to add to the list. Cannot be null, empty, or whitespace. - /// The position at which to insert the item in the list. Use to insert at the - /// beginning, or to insert at the end. - /// The maximum allowed size of the list. If greater than zero, the list will be trimmed to this size after adding - /// the item. Defaults to 0, meaning no size limit is enforced. - /// if the item was successfully added to the list and the list was saved; otherwise, . - public static bool TryAddItem(string key, string item, InsertPosition position, int maxSize = 0) - { - if (string.IsNullOrWhiteSpace(key) || string.IsNullOrWhiteSpace(item)) - return false; - - bool enforceSizeLimit = maxSize > 0; - var list = GetList(key); - - // Prevent duplicates by removing if already exists - list.Remove(item); - - // Add item at the specified position - if (position == InsertPosition.First) - list.Insert(0, item); - else - list.Add(item); - - // Trim list if needed - if (enforceSizeLimit && list.Count > maxSize) - { - int excess = list.Count - maxSize; - if (position == InsertPosition.First) - list.RemoveRange(maxSize, excess); // Remove from end - else - list.RemoveRange(0, excess); // Remove from start - } - - return TrySaveList(key, list); - } - - /// - /// Attempts to remove the specified item from the list associated with the given key. - /// - /// The key identifying the list from which the item should be removed. Cannot be null or empty. - /// The item to remove from the list. Cannot be null. - /// if the item was successfully removed and the updated list was saved; otherwise, . - public static bool TryRemoveItem(string key, string item) - { - if (!Exists(key) || !Contains(key, item)) - { - return false; - } - - var list = GetList(key); - if (list.Remove(item)) - { - return TrySaveList(key, list); - } - return false; - } - - /// - /// Retrieves a list of strings associated with the specified key from the application's local settings. - /// - /// The key used to locate the stored value in the application's local settings. Cannot be null. - /// A list of strings parsed from the stored value associated with the specified key. Returns an empty list if the - /// key does not exist or the stored value is null. - public static List GetList(string key) - { - string raw = appData.LocalSettings.Values[key] as string; - return raw != null - ? raw.Split(delimiter, StringSplitOptions.RemoveEmptyEntries).ToList() - : new List(); - } - - /// - /// Determines whether the specified item exists within the set of values associated with the given key. - /// - /// The key used to retrieve the stored set of values. Cannot be null or empty. - /// The item to search for within the set of values. Cannot be null. - /// if the item exists in the set of values associated with the key; otherwise, . - public static bool Contains(string key, string item) - { - string raw = appData.LocalSettings.Values[key] as string; - if (string.IsNullOrEmpty(raw)) - return false; - - var set = new HashSet( - raw.Split(delimiter, StringSplitOptions.RemoveEmptyEntries) - ); - - return set.Contains(item); - } - - /// - /// Deletes the specified key and its associated value from the application's local settings. - /// - /// The key of the setting to remove. Cannot be or empty. - public static void Delete(string key) - { - appData.LocalSettings.Values.Remove(key); - } - - /// - /// Determines whether a specified key exists in the application's local settings. - /// - /// The key to check for existence in the local settings. Cannot be null or empty. - /// if the specified key exists and its associated value is not null or empty; otherwise, - /// . - public static bool Exists(string key) - { - string raw = appData.LocalSettings.Values[key] as string; - return !string.IsNullOrEmpty(raw); - } - - /// - /// Attempts to save a list of strings to the application's local settings storage. - /// - /// The unique key used to store the list in local settings. Cannot be null or empty. - /// The list of strings to save. Cannot be null. - /// if the list is successfully saved; otherwise, if the total size - /// of the list exceeds the storage limit. - private static bool TrySaveList(string key, List items) - { - string joined = string.Join(delimiter, items); - int byteSize = System.Text.Encoding.Unicode.GetByteCount(joined); - - // If the size exceeds or equals 8 KB (8192 bytes), reject the save operation - if (byteSize >= 8192) - { - Debug.WriteLine($"Storage limit exceeded for key: {key}."); - return false; - } - - appData.LocalSettings.Values[key] = joined; - return true; - } -} diff --git a/WinUIGallery/Helpers/SettingsHelper/Internals/ListExtensions.cs b/WinUIGallery/Helpers/SettingsHelper/Internals/ListExtensions.cs new file mode 100644 index 000000000..904b46201 --- /dev/null +++ b/WinUIGallery/Helpers/SettingsHelper/Internals/ListExtensions.cs @@ -0,0 +1,34 @@ +using System.Collections.Generic; + +namespace WinUIGallery.Helpers; + +internal static class ListExtensions +{ + public static void AddToFirst(this List list, T item, int? maxSize = null) + { + if (item == null || (item is string data && string.IsNullOrWhiteSpace(data))) + return; + + list.Remove(item); + list.Insert(0, item); + + if (maxSize.HasValue && maxSize.Value > 0 && list.Count > maxSize.Value) + { + list.RemoveRange(maxSize.Value, list.Count - maxSize.Value); + } + } + + public static void AddToLast(this List list, T item, int? maxSize = null) + { + if (item == null || (item is string data && string.IsNullOrWhiteSpace(data))) + return; + + list.Remove(item); + list.Add(item); + + if (maxSize.HasValue && maxSize.Value > 0 && list.Count > maxSize.Value) + { + list.RemoveRange(0, list.Count - maxSize.Value); + } + } +} diff --git a/WinUIGallery/Helpers/SettingsHelper/Internals/SettingsJsonContext.cs b/WinUIGallery/Helpers/SettingsHelper/Internals/SettingsJsonContext.cs new file mode 100644 index 000000000..50105a119 --- /dev/null +++ b/WinUIGallery/Helpers/SettingsHelper/Internals/SettingsJsonContext.cs @@ -0,0 +1,11 @@ +using System.Collections.Generic; +using System.Text.Json.Serialization; + +namespace WinUIGallery.Helpers; + +[JsonSourceGenerationOptions(WriteIndented = true, GenerationMode = JsonSourceGenerationMode.Metadata)] +[JsonSerializable(typeof(Dictionary))] +[JsonSerializable(typeof(SettingsHelper))] +internal partial class SettingsJsonContext : JsonSerializerContext +{ +} \ No newline at end of file diff --git a/WinUIGallery/Helpers/SettingsHelper/ObservableSettings.cs b/WinUIGallery/Helpers/SettingsHelper/ObservableSettings.cs new file mode 100644 index 000000000..3a6af432b --- /dev/null +++ b/WinUIGallery/Helpers/SettingsHelper/ObservableSettings.cs @@ -0,0 +1,43 @@ +using System.ComponentModel; +using System.Runtime.CompilerServices; + +namespace WinUIGallery.Helpers; + +public partial class ObservableSettings : INotifyPropertyChanged +{ + private readonly ISettingsProvider provider; + + public ObservableSettings(ISettingsProvider provider) + { + this.provider = provider; + } + + public event PropertyChangedEventHandler PropertyChanged; + + protected bool Set(T value, [CallerMemberName] string propertyName = null) + { + if (provider.Contains(propertyName)) + { + var currentValue = provider.Get(propertyName); + if (Equals(currentValue, value)) + return false; + } + + provider.Set(propertyName, value); + PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName)); + return true; + } + + protected T Get([CallerMemberName] string propertyName = null) + { + return provider.Get(propertyName); + } + + protected T GetOrCreateDefault(T defaultValue, [CallerMemberName] string propertyName = null) + { + if (!provider.Contains(propertyName)) + Set(defaultValue, propertyName); + + return Get(propertyName); + } +} diff --git a/WinUIGallery/Helpers/SettingsHelper/Providers/ApplicationDataSettingsProvider.cs b/WinUIGallery/Helpers/SettingsHelper/Providers/ApplicationDataSettingsProvider.cs new file mode 100644 index 000000000..ada030c6b --- /dev/null +++ b/WinUIGallery/Helpers/SettingsHelper/Providers/ApplicationDataSettingsProvider.cs @@ -0,0 +1,84 @@ +using Microsoft.Windows.Storage; +using System; +using System.Collections.Generic; +using System.Text.Json; + +namespace WinUIGallery.Helpers; + +public partial class ApplicationDataSettingsProvider : ISettingsProvider +{ + private readonly ApplicationDataContainer container; + + public ApplicationDataSettingsProvider(ApplicationDataContainer container) + { + this.container = container ?? throw new ArgumentNullException(nameof(container)); + } + + public bool Contains(string key) => container.Values.ContainsKey(key); + + public object Get(string key) => container.Values.TryGetValue(key, out var value) ? value : null; + + public void Set(string key, object value) => container.Values[key] = value; + + public T Get(string key) + { + if (!container.Values.TryGetValue(key, out var value)) + return default; + + try + { + if (value is T t) + return t; + + if (value is string str && !IsSimpleType(typeof(T))) + { + var typeInfo = SettingsJsonContext.Default.GetTypeInfo(typeof(T)); + return (T)JsonSerializer.Deserialize(str, typeInfo); + } + + return (T)Convert.ChangeType(value, typeof(T)); + } + catch (Exception) + { + HandleCorruptedKey(key); + return default; + } + } + + private void HandleCorruptedKey(string key) + { + try + { + container.Values.Remove(key); + } + catch (Exception ex) + { + System.Diagnostics.Debug.WriteLine($"Failed to remove corrupted key '{key}': {ex}"); + } + } + + public void Set(string key, T value) + { + object storedValue = IsSimpleType(typeof(T)) + ? value + : JsonSerializer.Serialize(value, SettingsJsonContext.Default.GetTypeInfo(typeof(T))); + + container.Values[key] = storedValue; + } + + private static readonly HashSet ExtraSimpleTypes = new() + { + typeof(string), + typeof(DateTimeOffset), + typeof(TimeSpan), + typeof(Guid), + typeof(Windows.Foundation.Point), + typeof(Windows.Foundation.Size), + typeof(Windows.Foundation.Rect) + }; + + private static bool IsSimpleType(Type type) + { + return type.IsPrimitive || ExtraSimpleTypes.Contains(type); + } +} diff --git a/WinUIGallery/Helpers/SettingsHelper/Providers/ISettingsProvider.cs b/WinUIGallery/Helpers/SettingsHelper/Providers/ISettingsProvider.cs new file mode 100644 index 000000000..d02ce23b4 --- /dev/null +++ b/WinUIGallery/Helpers/SettingsHelper/Providers/ISettingsProvider.cs @@ -0,0 +1,11 @@ +namespace WinUIGallery.Helpers; + +public interface ISettingsProvider +{ + bool Contains(string key); + object Get(string key); + void Set(string key, object value); + + T Get(string key); + void Set(string key, T value); +} diff --git a/WinUIGallery/Helpers/SettingsHelper/Providers/JsonSettingsProvider.cs b/WinUIGallery/Helpers/SettingsHelper/Providers/JsonSettingsProvider.cs new file mode 100644 index 000000000..8f6e0d3b6 --- /dev/null +++ b/WinUIGallery/Helpers/SettingsHelper/Providers/JsonSettingsProvider.cs @@ -0,0 +1,101 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Text.Json; + +namespace WinUIGallery.Helpers; + +public partial class JsonSettingsProvider : ISettingsProvider +{ + private readonly string filePath; + private Dictionary values = new(); + + public JsonSettingsProvider(string filePath) + { + this.filePath = filePath; + Load(); + } + + public bool Contains(string key) => values.ContainsKey(key); + + public object Get(string key) => values.TryGetValue(key, out var value) ? value : null; + + public void Set(string key, object value) + { + var json = JsonSerializer.SerializeToElement(value, SettingsJsonContext.Default.GetTypeInfo(value.GetType())); + values[key] = json; + Save(); + } + + public T Get(string key) + { + if (!values.TryGetValue(key, out var jsonElement)) + return default; + + try + { + return (T)jsonElement.Deserialize(SettingsJsonContext.Default.GetTypeInfo(typeof(T))); + } + catch (Exception) + { + HandleCorruptedKey(key); + return default; + } + } + + + public void Set(string key, T value) + { + var json = JsonSerializer.SerializeToElement(value, SettingsJsonContext.Default.GetTypeInfo(typeof(T))); + values[key] = json; + Save(); + } + + private void Load() + { + if (!File.Exists(filePath)) + return; + + try + { + var json = File.ReadAllText(filePath); + values = JsonSerializer.Deserialize( + json, + SettingsJsonContext.Default.DictionaryStringJsonElement + ) ?? new(); + } + catch (Exception) + { + HandleCorruptedFile(); + } + } + private void HandleCorruptedFile() + { + try + { + File.Delete(filePath); + } + catch (Exception ex) + { + System.Diagnostics.Debug.WriteLine($"Failed to delete corrupted settings file '{filePath}': {ex}"); + } + + values = new(); + } + + private void HandleCorruptedKey(string key) + { + values.Remove(key); + Save(); + } + + + private void Save() + { + var json = JsonSerializer.Serialize( + values, + SettingsJsonContext.Default.DictionaryStringJsonElement + ); + File.WriteAllText(filePath, json); + } +} diff --git a/WinUIGallery/Helpers/SettingsHelper/Providers/SettingsProviderFactory.cs b/WinUIGallery/Helpers/SettingsHelper/Providers/SettingsProviderFactory.cs new file mode 100644 index 000000000..ffb4dcd88 --- /dev/null +++ b/WinUIGallery/Helpers/SettingsHelper/Providers/SettingsProviderFactory.cs @@ -0,0 +1,27 @@ +using Microsoft.Windows.Storage; +using System; +using System.IO; + +namespace WinUIGallery.Helpers; + +public static partial class SettingsProviderFactory +{ + public static ISettingsProvider CreateProvider() + { + if (NativeMethods.IsAppPackaged) + { + return new ApplicationDataSettingsProvider(ApplicationData.GetDefault().LocalSettings); + } + else + { + var folder = Path.Combine( + Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData), + ProcessInfoHelper.ProductNameAndVersion + ); + + Directory.CreateDirectory(folder); + var filePath = Path.Combine(folder, "AppConfig.json"); + return new JsonSettingsProvider(filePath); + } + } +} diff --git a/WinUIGallery/Helpers/SettingsHelper/SettingsHelper.cs b/WinUIGallery/Helpers/SettingsHelper/SettingsHelper.cs new file mode 100644 index 000000000..790268c02 --- /dev/null +++ b/WinUIGallery/Helpers/SettingsHelper/SettingsHelper.cs @@ -0,0 +1,60 @@ +using Microsoft.UI.Xaml; +using System; +using System.Collections.Generic; + +namespace WinUIGallery.Helpers; + +public partial class SettingsHelper : ObservableSettings +{ + private static readonly SettingsHelper instance = new(SettingsProviderFactory.CreateProvider()); + public static SettingsHelper Current => instance; + + private SettingsHelper(ISettingsProvider provider) + : base(provider) + { + } + public const int MaxRecentlyVisitedSamples = 7; + + public ElementTheme SelectedAppTheme + { + get => GetOrCreateDefault(ElementTheme.Default); + set => Set(value); + } + + public bool IsLeftMode + { + get => GetOrCreateDefault(true); + set => Set(value); + } + + public bool IsShowCopyLinkTeachingTip + { + get => GetOrCreateDefault(true); + set => Set(value); + } + + public List RecentlyVisited + { + get => GetOrCreateDefault>(new List()); + private set => Set(value); + } + + public List Favorites + { + get => GetOrCreateDefault>(new List()); + private set => Set(value); + } + + public void UpdateFavorites(Action> updater) + { + var list = Favorites; + updater(list); + Favorites = list; + } + public void UpdateRecentlyVisited(Action> updater) + { + var list = RecentlyVisited; + updater(list); + RecentlyVisited = list; + } +} diff --git a/WinUIGallery/Helpers/SettingsKeys.cs b/WinUIGallery/Helpers/SettingsKeys.cs deleted file mode 100644 index 3ef302c54..000000000 --- a/WinUIGallery/Helpers/SettingsKeys.cs +++ /dev/null @@ -1,34 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT License. -namespace WinUIGallery.Helpers; - -/// -/// Provides constant keys used for accessing application settings. -/// -public static partial class SettingsKeys -{ - /// - /// The key used to store or retrieve the selected application theme. - /// - public const string SelectedAppTheme = "SelectedAppTheme"; - - /// - /// Represents the key used to determine whether the navigation is in "left mode." - /// - public const string IsLeftMode = "NavigationIsOnLeftMode"; - - /// - /// Key for the list of recently visited Pages. - /// - public const string RecentlyVisited = "RecentlyVisited"; - - /// - /// Key for the list of favorited Pages. - /// - public const string Favorites = "Favorites"; - - /// - /// Represents the key used to identify the "Show Copy Link" teaching tip of the protocol activation clipboard. - /// - public const string ShowCopyLinkTeachingTip = "ShowCopyLinkTeachingTip"; -} diff --git a/WinUIGallery/Helpers/ThemeHelper.cs b/WinUIGallery/Helpers/ThemeHelper.cs index 161043dfc..ca3cd7fea 100644 --- a/WinUIGallery/Helpers/ThemeHelper.cs +++ b/WinUIGallery/Helpers/ThemeHelper.cs @@ -2,7 +2,6 @@ // Licensed under the MIT License. using Microsoft.UI.Xaml; -using Microsoft.Windows.Storage; namespace WinUIGallery.Helpers; @@ -11,8 +10,6 @@ namespace WinUIGallery.Helpers; /// public static partial class ThemeHelper { - private static ApplicationData appData = ApplicationData.GetDefault(); - /// /// Gets the current actual theme of the app based on the requested theme of the /// root element, or if that value is Default, the requested theme of the Application. @@ -63,24 +60,13 @@ public static ElementTheme RootTheme } } - if (NativeMethods.IsAppPackaged) - { - appData.LocalSettings.Values[SettingsKeys.SelectedAppTheme] = value.ToString(); - } + SettingsHelper.Current.SelectedAppTheme = value; } } public static void Initialize() { - if (NativeMethods.IsAppPackaged) - { - string savedTheme = appData.LocalSettings.Values[SettingsKeys.SelectedAppTheme]?.ToString(); - - if (savedTheme != null) - { - RootTheme = EnumHelper.GetEnum(savedTheme); - } - } + RootTheme = SettingsHelper.Current.SelectedAppTheme; } public static bool IsDarkTheme() diff --git a/WinUIGallery/MainWindow.xaml.cs b/WinUIGallery/MainWindow.xaml.cs index e2509348d..94a026ddb 100644 --- a/WinUIGallery/MainWindow.xaml.cs +++ b/WinUIGallery/MainWindow.xaml.cs @@ -50,7 +50,7 @@ private void RootGrid_Loaded(object sender, RoutedEventArgs e) private void SetWindowProperties() { -#if DEBUG +#if DEBUG || DEBUG_UNPACKAGED this.Title = "WinUI 3 Gallery Dev"; titleBar.Subtitle = "Dev"; #else @@ -120,7 +120,7 @@ public void Navigate(Type pageType, object targetPageArguments = null, Navigatio if (pageType.Equals(typeof(ItemPage)) && targetPageArguments != null) { // Mark the item sample's page visited - SettingsHelper.TryAddItem(SettingsKeys.RecentlyVisited, targetPageArguments.ToString(), InsertPosition.First, SettingsHelper.MaxRecentlyVisitedSamples); + SettingsHelper.Current.UpdateRecentlyVisited(items => items.AddToFirst(targetPageArguments.ToString(), SettingsHelper.MaxRecentlyVisitedSamples)); } } diff --git a/WinUIGallery/Pages/HomePage.xaml.cs b/WinUIGallery/Pages/HomePage.xaml.cs index 19e622252..a9d28275f 100644 --- a/WinUIGallery/Pages/HomePage.xaml.cs +++ b/WinUIGallery/Pages/HomePage.xaml.cs @@ -31,26 +31,24 @@ protected override void OnNavigatedTo(NavigationEventArgs e) .OrderBy(i => i.Title) .ToList(); - RecentlyVisitedSamplesList = GetValidItems(SettingsKeys.RecentlyVisited); + RecentlyVisitedSamplesList = GetValidItems(SettingsHelper.Current.RecentlyVisited, isFavorite: false); RecentlyAddedOrUpdatedSamplesList = Items.Where(i => i.IsNew || i.IsUpdated).ToList(); - FavoriteSamplesList = GetValidItems(SettingsKeys.Favorites); + FavoriteSamplesList = GetValidItems(SettingsHelper.Current.Favorites, isFavorite: true); VisualStateManager.GoToState(this, RecentlyVisitedSamplesList.Count > 0 ? "Recent" : "NoRecent", true); VisualStateManager.GoToState(this, FavoriteSamplesList.Count > 0 ? "Favorites" : "NoFavorites", true); } - public List GetValidItems(string settingsKey) + public List GetValidItems(List items, bool isFavorite) { - List keyList = SettingsHelper.GetList(settingsKey); - - if (keyList == null || keyList.Count == 0) + if (items == null || items.Count == 0) return new List(); Dictionary itemMap = Items.ToDictionary(i => i.UniqueId); List result = new(); - foreach (string id in keyList) + foreach (string id in items) { if (itemMap.TryGetValue(id, out var item)) { @@ -58,7 +56,14 @@ public List GetValidItems(string settingsKey) } else { - SettingsHelper.TryRemoveItem(settingsKey, id); + if (isFavorite) + { + SettingsHelper.Current.UpdateFavorites(items => items.Remove(id)); + } + else + { + SettingsHelper.Current.UpdateRecentlyVisited(items => items.Remove(id)); + } } } diff --git a/WinUIGallery/Pages/SettingsPage.xaml.cs b/WinUIGallery/Pages/SettingsPage.xaml.cs index ddba4fe0a..ebd61b5cc 100644 --- a/WinUIGallery/Pages/SettingsPage.xaml.cs +++ b/WinUIGallery/Pages/SettingsPage.xaml.cs @@ -8,7 +8,6 @@ using System; using Windows.ApplicationModel.DataTransfer; using Windows.System; -using WinUIGallery.ControlPages; using WinUIGallery.Helpers; namespace WinUIGallery.Pages; @@ -43,8 +42,8 @@ protected override void OnNavigatedTo(NavigationEventArgs e) private void CheckRecentAndFavoriteButtonStates() { - ClearRecentBtn.IsEnabled = SettingsHelper.Exists(SettingsKeys.RecentlyVisited); - UnfavoriteBtn.IsEnabled = SettingsHelper.Exists(SettingsKeys.Favorites); + ClearRecentBtn.IsEnabled = SettingsHelper.Current.RecentlyVisited.Count > 0; + UnfavoriteBtn.IsEnabled = SettingsHelper.Current.Favorites.Count > 0; } private void OnSettingsPageLoaded(object sender, RoutedEventArgs e) @@ -180,7 +179,7 @@ private async void UnfavoriteBtn_Click(object sender, RoutedEventArgs e) }; dialog.PrimaryButtonClick += (s, args) => { - SettingsHelper.Delete(SettingsKeys.Favorites); + SettingsHelper.Current.UpdateFavorites(items => items.Clear()); CheckRecentAndFavoriteButtonStates(); }; var result = await dialog.ShowAsync(); @@ -200,7 +199,7 @@ private async void ClearRecentBtn_Click(object sender, RoutedEventArgs e) }; dialog.PrimaryButtonClick += (s, args) => { - SettingsHelper.Delete(SettingsKeys.RecentlyVisited); + SettingsHelper.Current.UpdateRecentlyVisited(items => items.Clear()); CheckRecentAndFavoriteButtonStates(); }; var result = await dialog.ShowAsync(); diff --git a/WinUIGallery/Samples/ControlPages/Fundamentals/ScratchPadPage.xaml.cs b/WinUIGallery/Samples/ControlPages/Fundamentals/ScratchPadPage.xaml.cs index 80aa7c575..d883a5d6b 100644 --- a/WinUIGallery/Samples/ControlPages/Fundamentals/ScratchPadPage.xaml.cs +++ b/WinUIGallery/Samples/ControlPages/Fundamentals/ScratchPadPage.xaml.cs @@ -9,35 +9,17 @@ using Microsoft.UI.Xaml.Markup; using System; using System.Linq; -using Windows.Storage; using Windows.System; namespace WinUIGallery.ControlPages; public sealed partial class ScratchPadPage : Page { - // The name of the ApplicationData container used to store all ScratchPad-related settings. - private const string containerKey = "ScratchPad"; - - // The key under the ScratchPad container for storing the XAML composite value. - private const string xamlCompositeValueKey = "ScratchPadXAML"; - - // The key within the XAML composite value that stores the number of 4KB segments. - private const string xamlSegmentCountKey = "count"; - public ScratchPadPage() { this.InitializeComponent(); - var xamlStr = ReadScratchPadXAMLinLocalSettings(); - - // If there is no stored XAML, load the default. - if (xamlStr == null || xamlStr.Trim().Length == 0) - { - xamlStr = GetDefaultScratchXAML(); - } - - m_oldText = xamlStr; + m_oldText = GetDefaultScratchXAML(); textbox.TextDocument.SetText(TextSetOptions.None, m_oldText); var formatter = new XamlTextFormatter(textbox); formatter.ApplyColors(); @@ -69,46 +51,6 @@ private string GetDefaultScratchXAML() "; } - public string ReadScratchPadXAMLinLocalSettings() - { - var appData = Microsoft.Windows.Storage.ApplicationData.GetDefault(); - if (appData.LocalSettings.Containers.ContainsKey(containerKey)) - { - var scratchPadContainer = appData.LocalSettings.CreateContainer(containerKey, Microsoft.Windows.Storage.ApplicationDataCreateDisposition.Existing); - if (scratchPadContainer != null && scratchPadContainer.Values.ContainsKey(xamlCompositeValueKey)) - { - // String values are limited to 4K characters. Use a composite value to support a longer string. - var compositeStr = scratchPadContainer.Values[xamlCompositeValueKey] as ApplicationDataCompositeValue; - var xamlStr = ""; - int count = (int)compositeStr[xamlSegmentCountKey]; - for (int i = 0; i < count; i++) - { - xamlStr += compositeStr[i.ToString()]; - } - return xamlStr; - } - } - return null; - } - - public void SaveScratchPadXAMLinLocalSettings(string xamlStr) - { - var appData = Microsoft.Windows.Storage.ApplicationData.GetDefault(); - var scratchPadContainer = appData.LocalSettings.CreateContainer(containerKey, Microsoft.Windows.Storage.ApplicationDataCreateDisposition.Existing); - // String values are limited to 4K characters. Use a composite value to support a longer string. - var compositeStr = new ApplicationDataCompositeValue(); - int count = 0; - while (xamlStr.Length > 0) - { - var len = Math.Min(xamlStr.Length, 4000); - compositeStr[count.ToString()] = xamlStr.Substring(0, len); - count++; - xamlStr = xamlStr.Substring(len); - } - compositeStr[xamlSegmentCountKey] = count; - scratchPadContainer.Values[xamlCompositeValueKey] = compositeStr; - } - private async void ResetToDefaultClick(object sender, RoutedEventArgs e) { ContentDialog dialog = new ContentDialog(); @@ -153,8 +95,6 @@ private void LoadContent() textbox.TextDocument.GetText(TextGetOptions.None, out newText); //System.Diagnostics.Debug.WriteLine("new text: " + newText); - SaveScratchPadXAMLinLocalSettings(newText); - // TODO: Strip out x:Bind -- maybe just convert it to spaces? try {