refactor: config

Signed-off-by: Cryolitia <cryolitia@gmail.com>
This commit is contained in:
Cryolitia
2023-09-27 03:37:51 +08:00
parent 3337e2ffac
commit 07e4cfbbf9
10 changed files with 293 additions and 44 deletions

View File

@@ -0,0 +1,169 @@
using System;
using System.Collections.Generic;
using System.Collections.Specialized;
using System.ComponentModel;
using System.IO;
using System.Text.Json;
using System.Text.Json.Serialization;
using System.Threading.Tasks;
using MaaWpfGui.Helper;
using ObservableCollections;
using Serilog;
[assembly: PropertyChanged.FilterType("MaaWpfGui.Configuration.")]
namespace MaaWpfGui.Configuration
{
public class ConfigFactory
{
// TODO: delete test in main branch
private static readonly string _configurationFile = Path.Combine(Environment.CurrentDirectory, "config/gui.test.json");
// TODO: write backup method
private static readonly string _configurationBakFile = Path.Combine(Environment.CurrentDirectory, "config/gui.test.json.bak");
private static readonly ILogger _logger = Log.ForContext<ConfigurationHelper>();
private static readonly object _lock = new object();
public delegate void ConfigurationUpdateEventHandler(string key, object oldValue, object newValue);
public static event ConfigurationUpdateEventHandler ConfigurationUpdateEvent;
private static readonly JsonSerializerOptions _options = new JsonSerializerOptions {WriteIndented = true, Converters = {new JsonStringEnumConverter()}};
private static readonly Lazy<RootConfig> _rootConfig = new Lazy<RootConfig>(() =>
{
lock (_lock)
{
if (Directory.Exists("config") is false)
{
Directory.CreateDirectory("config");
}
RootConfig parsed = null;
if (File.Exists(_configurationFile))
{
try
{
parsed = JsonSerializer.Deserialize<RootConfig>(File.ReadAllText(_configurationFile), _options);
}
catch (Exception e)
{
_logger.Information("Failed to parse configuration file: " + e);
}
}
if (parsed is null)
{
_logger.Information("Failed to load configuration file, creating a new one");
parsed = new RootConfig();
}
if (parsed.CurrentConfig is null)
{
parsed.CurrentConfig = new SpecificConfig();
}
parsed.PropertyChanged += OnPropertyChangedFactory("Configurations.");
parsed.Configurations.CollectionChanged += (in NotifyCollectionChangedEventArgs<KeyValuePair<string, SpecificConfig>> args) =>
{
switch (args.Action)
{
case NotifyCollectionChangedAction.Add:
case NotifyCollectionChangedAction.Replace:
if (args.IsSingleItem)
{
args.NewItem.Value.GuiConfig.PropertyChanged += OnPropertyChangedFactory("Configurations." + args.NewItem.Key, JsonSerializer.Serialize(args.NewItem.Value, _options), null);
}
else
{
foreach (var value in args.NewItems)
{
value.Value.GuiConfig.PropertyChanged += OnPropertyChangedFactory("Configurations." + value.Key, JsonSerializer.Serialize(value.Value, _options), null);
}
}
break;
}
OnPropertyChangedFactory("Configurations");
};
foreach (var keyValue in parsed.Configurations)
{
keyValue.Value.GuiConfig.PropertyChanged += OnPropertyChangedFactory("Configurations." + keyValue.Key + ".GUIConfig.");
}
return parsed;
}
});
private static PropertyChangedEventHandler OnPropertyChangedFactory(string key, object oldValue, object newValue)
{
return (o, args) =>
{
var after = newValue;
if (after == null && args is PropertyChangedEventDetailArgs)
{
after = (args as PropertyChangedEventDetailArgs).NewValue;
}
OnPropertyChanged(key + args.PropertyName, oldValue, after);
};
}
private static PropertyChangedEventHandler OnPropertyChangedFactory(string key)
{
return (o, args) =>
{
object after = null;
if (args is PropertyChangedEventDetailArgs)
{
after = (args as PropertyChangedEventDetailArgs).NewValue;
}
OnPropertyChanged(key + args.PropertyName, null, after);
};
}
public static RootConfig RootConfig => _rootConfig.Value;
public static readonly SpecificConfig CurrentConfig = RootConfig.CurrentConfig;
public static async void OnPropertyChanged(string key, object oldValue, object newValue)
{
var result = await Save();
if (result)
{
ConfigurationUpdateEvent?.Invoke(key, oldValue, newValue);
_logger.Debug("Configuration {Key} has been set to {Value}", key, newValue);
}
else
{
_logger.Warning("Failed to save configuration {Key} to {Value}", key, newValue);
}
}
private static async Task<bool> Save(string file = null)
{
return await Task.Run(() =>
{
lock (_lock)
{
try
{
File.WriteAllText(file ?? _configurationFile, JsonSerializer.Serialize(RootConfig, _options));
}
catch (Exception e)
{
_logger.Error(e, "Failed to save configuration file.");
return false;
}
return true;
}
});
}
}
}

View File

@@ -0,0 +1,41 @@
using System.Collections.Generic;
using System.ComponentModel;
using System.Runtime.CompilerServices;
namespace MaaWpfGui.Configuration
{
public class GUIConfig : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
public DarkModeType DarkMode { get; set; } = DarkModeType.SyncWithOS;
public bool UseNotify { get; set; } = true;
public void OnPropertyChanged(string propertyName, object before, object after)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventDetailArgs(propertyName, before, after));
}
}
/// <summary>
/// 表示深色模式的类型。
/// </summary>
public enum DarkModeType
{
/// <summary>
/// 明亮的主题。
/// </summary>
Light,
/// <summary>
/// 暗黑的主题。
/// </summary>
Dark,
/// <summary>
/// 与操作系统的深色模式同步。
/// </summary>
SyncWithOS
}
}

View File

@@ -0,0 +1,19 @@
using System.ComponentModel;
namespace MaaWpfGui.Configuration
{
// https://github.com/dotnet/runtime/issues/27252
public class PropertyChangedEventDetailArgs : PropertyChangedEventArgs
{
public PropertyChangedEventDetailArgs(string propertyName, object oldValue, object newValue)
: base(propertyName)
{
OldValue = oldValue;
NewValue = newValue;
}
public object OldValue { get; private set; }
public object NewValue { get; private set; }
}
}

View File

@@ -0,0 +1,35 @@
using System;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Text.Json.Serialization;
using ObservableCollections;
namespace MaaWpfGui.Configuration
{
public class RootConfig : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
public ObservableDictionary<string, SpecificConfig> Configurations { get; set; } = new ObservableDictionary<string, SpecificConfig>();
public string Current { get; set; } = "Default";
[JsonIgnore]
public SpecificConfig CurrentConfig
{
get
{
SpecificConfig result = null;
Configurations.TryGetValue(Current, out result);
return result;
}
set => Configurations[Current] = value;
}
public void OnPropertyChanged(string propertyName, object before, object after)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventDetailArgs(propertyName, before, after));
}
}
}

View File

@@ -0,0 +1,11 @@
using System.Collections.Generic;
using System.ComponentModel;
using System.Runtime.CompilerServices;
namespace MaaWpfGui.Configuration
{
public class SpecificConfig
{
public GUIConfig GuiConfig { get; set; } = new GUIConfig();
}
}

View File

@@ -28,7 +28,6 @@ namespace MaaWpfGui.Constants
public const string Localization = "GUI.Localization";
public const string MinimizeToTray = "GUI.MinimizeToTray";
public const string HideCloseButton = "GUI.HideCloseButton";
public const string UseNotify = "GUI.UseNotify";
public const string UseLogItemDateFormat = "GUI.UseLogItemDateFormat";
public const string LogItemDateFormat = "GUI.LogItemDateFormatString";
public const string WindowPlacement = "GUI.Placement";
@@ -39,7 +38,6 @@ namespace MaaWpfGui.Constants
public const string CustomStageCode = "GUI.CustomStageCode";
public const string InverseClearMode = "GUI.InverseClearMode";
public const string WindowTitlePrefix = "GUI.WindowTitlePrefix";
public const string DarkMode = "GUI.DarkMode";
public const string AddressHistory = "Connect.AddressHistory";
public const string AutoDetect = "Connect.AutoDetect";

View File

@@ -1,3 +1,3 @@
<Weavers xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="FodyWeavers.xsd">
<Costura />
</Weavers>
<PropertyChanged />
</Weavers>

View File

@@ -22,6 +22,7 @@ using System.Windows;
using System.Windows.Interop;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using MaaWpfGui.Configuration;
using MaaWpfGui.Constants;
using Microsoft.Toolkit.Uwp.Notifications;
using Microsoft.Win32;
@@ -394,7 +395,7 @@ namespace MaaWpfGui.Helper
NotificationSounds sound = NotificationSounds.Notification,
NotificationContent notificationContent = null)
{
if (!Convert.ToBoolean(ConfigurationHelper.GetValue(ConfigurationKeys.UseNotify, bool.TrueString)))
if (!ConfigFactory.CurrentConfig.GuiConfig.UseNotify)
{
return;
}

View File

@@ -108,6 +108,12 @@
<PackageReference Include="Notification.Wpf">
<Version>6.1.0.5</Version>
</PackageReference>
<PackageReference Include="ObservableCollections">
<Version>1.1.3</Version>
</PackageReference>
<PackageReference Include="PropertyChanged.Fody">
<Version>4.1.0</Version>
</PackageReference>
<PackageReference Include="Semver">
<Version>2.2.0</Version>
</PackageReference>

View File

@@ -29,6 +29,7 @@ using System.Threading.Tasks;
using System.Windows;
using HandyControl.Controls;
using HandyControl.Data;
using MaaWpfGui.Configuration;
using MaaWpfGui.Constants;
using MaaWpfGui.Extensions;
using MaaWpfGui.Helper;
@@ -3130,18 +3131,16 @@ namespace MaaWpfGui.ViewModels.UI
}
}
private bool _useNotify = Convert.ToBoolean(ConfigurationHelper.GetValue(ConfigurationKeys.UseNotify, bool.TrueString));
/// <summary>
/// Gets or sets a value indicating whether to use notification.
/// </summary>
public bool UseNotify
{
get => _useNotify;
get => ConfigFactory.CurrentConfig.GuiConfig.UseNotify;
set
{
SetAndNotify(ref _useNotify, value);
ConfigurationHelper.SetValue(ConfigurationKeys.UseNotify, value.ToString());
ConfigFactory.CurrentConfig.GuiConfig.UseNotify = value;
NotifyOfPropertyChange();
if (value)
{
Execute.OnUIThread(() =>
@@ -3271,39 +3270,12 @@ namespace MaaWpfGui.ViewModels.UI
}
}
/// <summary>
/// 表示深色模式的类型。
/// </summary>
public enum DarkModeType
{
/// <summary>
/// 明亮的主题。
/// </summary>
Light,
/// <summary>
/// 暗黑的主题。
/// </summary>
Dark,
/// <summary>
/// 与操作系统的深色模式同步。
/// </summary>
SyncWithOS,
}
private DarkModeType _darkModeType =
Enum.TryParse(ConfigurationHelper.GetValue(ConfigurationKeys.DarkMode, DarkModeType.Light.ToString()),
out DarkModeType temp)
? temp
: DarkModeType.Light;
/// <summary>
/// Gets or sets the dark mode.
/// </summary>
public string DarkMode
{
get => _darkModeType.ToString();
get => ConfigFactory.CurrentConfig.GuiConfig.DarkMode.ToString();
set
{
if (!Enum.TryParse(value, out DarkModeType tempEnumValue))
@@ -3311,8 +3283,8 @@ namespace MaaWpfGui.ViewModels.UI
return;
}
SetAndNotify(ref _darkModeType, tempEnumValue);
ConfigurationHelper.SetValue(ConfigurationKeys.DarkMode, value);
ConfigFactory.CurrentConfig.GuiConfig.DarkMode = tempEnumValue;
NotifyOfPropertyChange();
SwitchDarkMode();
/*
@@ -3331,10 +3303,7 @@ namespace MaaWpfGui.ViewModels.UI
public void SwitchDarkMode()
{
DarkModeType darkModeType =
Enum.TryParse(ConfigurationHelper.GetValue(ConfigurationKeys.DarkMode, DarkModeType.Light.ToString()),
out DarkModeType temp)
? temp : DarkModeType.Light;
DarkModeType darkModeType = ConfigFactory.CurrentConfig.GuiConfig.DarkMode;
switch (darkModeType)
{
case DarkModeType.Light: