143 lines
5.0 KiB
C#
143 lines
5.0 KiB
C#
using System.ComponentModel;
|
|
using System.Windows.Data;
|
|
using System.Windows.Media;
|
|
using CommunityToolkit.Mvvm.ComponentModel;
|
|
using CursorLang.Models;
|
|
using CursorLang.Services;
|
|
|
|
namespace CursorLang.ViewModels;
|
|
|
|
/// <summary>
|
|
/// Вариант выбора в списке. Подпись меняется вместе с языком, а сам объект
|
|
/// живёт всё время работы окна: если пересоздавать элементы списка,
|
|
/// ComboBox сбрасывает выбранное значение.
|
|
/// </summary>
|
|
public sealed class EnumOption<T> : ObservableObject where T : struct, Enum
|
|
{
|
|
private string _display;
|
|
|
|
public EnumOption(T value, string display)
|
|
{
|
|
Value = value;
|
|
_display = display;
|
|
}
|
|
|
|
public T Value { get; }
|
|
|
|
public string Display
|
|
{
|
|
get => _display;
|
|
set => SetProperty(ref _display, value);
|
|
}
|
|
|
|
// Средства доступности берут имя элемента списка отсюда
|
|
public override string ToString() => Display;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Окно настроек. Значения правятся прямо в <see cref="AppSettings"/>,
|
|
/// поэтому подсказка подхватывает их сразу, без кнопки «Применить».
|
|
/// </summary>
|
|
public sealed partial class SettingsViewModel : ObservableObject, IDisposable
|
|
{
|
|
private static readonly Color[] Palette =
|
|
[
|
|
Color.FromRgb(0x20, 0x20, 0x20),
|
|
Color.FromRgb(0x00, 0x00, 0x00),
|
|
Color.FromRgb(0x1E, 0x3A, 0x8A),
|
|
Color.FromRgb(0x0F, 0x76, 0x6E),
|
|
Color.FromRgb(0x7C, 0x2D, 0x12),
|
|
Color.FromRgb(0x86, 0x19, 0x8F),
|
|
Color.FromRgb(0xB9, 0x1C, 0x1C),
|
|
Color.FromRgb(0xF5, 0xF5, 0xF5),
|
|
];
|
|
|
|
private static readonly Color[] ForegroundPalette =
|
|
[
|
|
Color.FromRgb(0xFF, 0xFF, 0xFF),
|
|
Color.FromRgb(0xD4, 0xD4, 0xD4),
|
|
Color.FromRgb(0x00, 0x00, 0x00),
|
|
Color.FromRgb(0xFA, 0xCC, 0x15),
|
|
Color.FromRgb(0x4A, 0xDE, 0x80),
|
|
Color.FromRgb(0x60, 0xA5, 0xFA),
|
|
Color.FromRgb(0xF9, 0x73, 0x16),
|
|
Color.FromRgb(0xF8, 0x71, 0x71),
|
|
];
|
|
|
|
public SettingsViewModel(AppSettings settings, ILocalizationService localization)
|
|
{
|
|
Settings = settings;
|
|
Localization = localization;
|
|
|
|
// Язык интерфейса — такая же настройка, как остальные, и хранится там же
|
|
Localization.CurrentLanguage = settings.Language;
|
|
Settings.PropertyChanged += OnSettingsChanged;
|
|
Localization.PropertyChanged += OnLocalizationChanged;
|
|
|
|
Themes = CreateOptions<AppTheme>();
|
|
PlacementModes = CreateOptions<PopupPlacementMode>();
|
|
AnchorSides = CreateOptions<AnchorSide>();
|
|
ScreenPositions = CreateOptions<ScreenPosition>();
|
|
}
|
|
|
|
public AppSettings Settings { get; }
|
|
|
|
public ILocalizationService Localization { get; }
|
|
|
|
public IReadOnlyList<Color> BackgroundPalette { get; } = Palette;
|
|
|
|
public IReadOnlyList<Color> TextPalette { get; } = ForegroundPalette;
|
|
|
|
public IReadOnlyList<EnumOption<AppTheme>> Themes { get; }
|
|
|
|
public IReadOnlyList<EnumOption<PopupPlacementMode>> PlacementModes { get; }
|
|
|
|
public IReadOnlyList<EnumOption<AnchorSide>> AnchorSides { get; }
|
|
|
|
public IReadOnlyList<EnumOption<ScreenPosition>> ScreenPositions { get; }
|
|
|
|
public void Dispose()
|
|
{
|
|
Settings.PropertyChanged -= OnSettingsChanged;
|
|
Localization.PropertyChanged -= OnLocalizationChanged;
|
|
}
|
|
|
|
private void OnSettingsChanged(object? sender, PropertyChangedEventArgs e)
|
|
{
|
|
if (e.PropertyName == nameof(AppSettings.Language))
|
|
{
|
|
Localization.CurrentLanguage = Settings.Language;
|
|
}
|
|
}
|
|
|
|
// Подписи вариантов приходят из ресурсов, поэтому при смене языка
|
|
// обновляем только текст — сами элементы списков остаются прежними
|
|
private void OnLocalizationChanged(object? sender, PropertyChangedEventArgs e)
|
|
{
|
|
if (e.PropertyName != Binding.IndexerName)
|
|
{
|
|
return;
|
|
}
|
|
|
|
Translate(Themes);
|
|
Translate(PlacementModes);
|
|
Translate(AnchorSides);
|
|
Translate(ScreenPositions);
|
|
}
|
|
|
|
private EnumOption<T>[] CreateOptions<T>() where T : struct, Enum =>
|
|
[.. Enum.GetValues<T>().Select(value => new EnumOption<T>(value, GetDisplayName(value)))];
|
|
|
|
private void Translate<T>(IReadOnlyList<EnumOption<T>> options) where T : struct, Enum
|
|
{
|
|
foreach (EnumOption<T> option in options)
|
|
{
|
|
option.Display = GetDisplayName(option.Value);
|
|
}
|
|
}
|
|
|
|
// Ключ ресурса собирается из имени типа и значения: PopupPlacementMode_AtCursor
|
|
private string GetDisplayName<T>(T value) where T : struct, Enum =>
|
|
Localization[$"{typeof(T).Name}_{value}"];
|
|
}
|