XFE Git
XFE Studio Git
Git 首页 全局搜索
XFE 主站 文档 NuGet

XFEWarframe

【WinUI】基于Warframe游戏本体的公开服务器以及安装器

公开
关注 0 Fork 0 Star 0
UTF-8
using CommunityToolkit.WinUI.Controls;
using Microsoft.UI.Xaml;
using Microsoft.UI.Xaml.Automation;
using Microsoft.UI.Xaml.Controls;

namespace XFEWarframe.Desktop.Editing;

/// <summary>Inline setting cards grouped by purpose. Searching never replaces fields or their drafts.</summary>
public sealed class GroupedSettingsForm : StackPanel
{
    public IReadOnlyList<EditorField>? Fields
    {
        get => (IReadOnlyList<EditorField>?)GetValue(FieldsProperty);
        set => SetValue(FieldsProperty, value);
    }
    public static readonly DependencyProperty FieldsProperty = DependencyProperty.Register(nameof(Fields), typeof(IReadOnlyList<EditorField>), typeof(GroupedSettingsForm), new PropertyMetadata(null, (sender, _) => ((GroupedSettingsForm)sender).Rebuild()));
    public string Scope { get => (string)GetValue(ScopeProperty); set => SetValue(ScopeProperty, value); }
    public static readonly DependencyProperty ScopeProperty = DependencyProperty.Register(nameof(Scope), typeof(string), typeof(GroupedSettingsForm), new PropertyMetadata("account", (sender, _) => ((GroupedSettingsForm)sender).Rebuild()));
    public string Query { get => (string)GetValue(QueryProperty); set => SetValue(QueryProperty, value); }
    public static readonly DependencyProperty QueryProperty = DependencyProperty.Register(nameof(Query), typeof(string), typeof(GroupedSettingsForm), new PropertyMetadata("", (sender, _) => ((GroupedSettingsForm)sender).Filter()));
    public bool EnableSearch { get => (bool)GetValue(EnableSearchProperty); set => SetValue(EnableSearchProperty, value); }
    public static readonly DependencyProperty EnableSearchProperty = DependencyProperty.Register(nameof(EnableSearch), typeof(bool), typeof(GroupedSettingsForm), new PropertyMetadata(true, (sender, _) => ((GroupedSettingsForm)sender).Rebuild()));

    private sealed record Row(EditorField Field, SettingsCard Card);
    private sealed record Section(SettingSection Definition, SettingsExpander Expander, Row[] Rows);
    private readonly List<Section> sections = [];
    private readonly Dictionary<string, bool> expansion = [];
    private AutoSuggestBox? search;
    private readonly TextBlock empty = new() { Text = UiText.Translate("没有匹配的设置"), Opacity = .7, Margin = new Thickness(12) };
    private bool filtering;

    public GroupedSettingsForm() => Spacing = 8;
    private void Rebuild()
    {
        Children.Clear(); sections.Clear(); search = null;
        if (EnableSearch && Fields?.Count >= 8)
        {
            search = new AutoSuggestBox { DisplayMemberPath = nameof(EditorField.Label), Text = Query, PlaceholderText = UiText.Translate("搜索设置"), Margin = new Thickness(0, 0, 0, 4) };
            Suggestions.SetCandidates(search, Fields);
            search.TextChanged += (sender, _) => { if (ReferenceEquals(sender, search)) Query = search.Text; };
            Children.Add(search);
        }
        foreach (var group in (Fields ?? []).GroupBy(x => SettingSections.Find(Scope, x.Key)).OrderBy(x => x.Key.Order))
        {
            var id = Scope + ":" + group.Key.Key;
            var expander = new SettingsExpander
            {
                Header = UiText.Translate(group.Key.Title), Tag = group.Key.Key,
                IsExpanded = expansion.GetValueOrDefault(id, group.Key.Order == 0),
                HorizontalAlignment = HorizontalAlignment.Stretch
            };
            AutomationProperties.SetAutomationId(expander, "settings-group-" + group.Key.Key);
            // Save only the user's normal browsing state, not automatic search expansion.
            expander.RegisterPropertyChangedCallback(SettingsExpander.IsExpandedProperty, (_, _) =>
            { if (!filtering && string.IsNullOrWhiteSpace(Query)) expansion[id] = expander.IsExpanded; });
            var fields = group.ToArray();
            var cards = EditorForm.CreateCards(fields);
            foreach (var card in cards) expander.Items.Add(card);
            sections.Add(new(group.Key, expander, fields.Zip(cards, (field, card) => new Row(field, card)).ToArray()));
            Children.Add(expander);
        }
        Children.Add(empty); Filter();
    }
    private void Filter()
    {
        filtering = true;
        try
        {
            var query = Query.Trim();
            if (search is not null && search.Text != Query) search.Text = Query;
            var any = false;
            foreach (var section in sections)
            {
                var groupMatches = UiText.Translate(section.Definition.Title).Contains(query, StringComparison.OrdinalIgnoreCase);
                var count = 0;
                foreach (var row in section.Rows)
                {
                    var matches = groupMatches || row.Field.Label.Contains(query, StringComparison.OrdinalIgnoreCase) || row.Field.Key.Contains(query, StringComparison.OrdinalIgnoreCase);
                    row.Card.Visibility = matches ? Visibility.Visible : Visibility.Collapsed;
                    if (matches) count++;
                }
                section.Expander.Visibility = count > 0 ? Visibility.Visible : Visibility.Collapsed;
                section.Expander.Description = UiText.Format("{0} 项设置", count);
                section.Expander.IsExpanded = query.Length > 0 || expansion.GetValueOrDefault(Scope + ":" + section.Definition.Key, section.Definition.Order == 0);
                any |= count > 0;
            }
            empty.Visibility = any ? Visibility.Collapsed : Visibility.Visible;
        }
        finally { filtering = false; }
    }
}