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
{