HashCalculator.GUI/ViewModel.cs

336 lines
10 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Diagnostics.CodeAnalysis;
using System.IO;
using System.Linq;
using System.Runtime.CompilerServices;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Windows;
using Microsoft.Win32;
using TechnologyAssembler.Core.IO;
namespace HashCalculator.GUI
{
internal abstract class NotifyPropertyChanged : INotifyPropertyChanged
{
#region INotifyPropertyChanged
public event PropertyChangedEventHandler? PropertyChanged;
protected void Notify(string name)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(name));
}
protected void SetField<X>(ref X field, X value, [CallerMemberName] string? propertyName = null)
{
if (propertyName == null)
{
throw new InvalidOperationException();
}
if (EqualityComparer<X>.Default.Equals(field, value))
{
return;
}
field = value;
Notify(propertyName);
}
#endregion
}
[SuppressMessage("Microsoft.Performance", "CA1812")]
internal class ViewModel : NotifyPropertyChanged
{
private static readonly Random _random = new Random();
public MainInputViewModel MainInput { get; }
public BigInputViewModel BigEntryInput { get; }
private ObservableCollection<DisplayAssetEntry> _entries = new ObservableCollection<DisplayAssetEntry>();
public ObservableCollection<DisplayAssetEntry> Entries
{
get => _entries;
set => SetField(ref _entries, value);
}
private string _statusText = SuggestionString("不知道该显示些什么呢……");
public string StatusText
{
get => _statusText;
set => SetField(ref _statusText, value);
}
private string _traceText = string.Empty;
public string TraceText
{
get => _traceText;
set => SetField(ref _traceText, value);
}
public ViewModel()
{
var controller = new Controller(this);
MainInput = new MainInputViewModel(controller);
BigEntryInput = new BigInputViewModel(controller);
}
public static string SuggestionString(string original)
{
var generated = $"{_random.NextDouble()}";
System.Diagnostics.Debug.WriteLine(generated);
if (generated.Contains("38") || generated.Contains("16"))
{
return "你们都是喂鱼的马甲!(";
}
if (generated.IndexOf('2') == 2)
{
return "本来以为两小时就能写完这个小工具没想到写了两个星期开始怀疑自己的智商orz";
}
return original;
}
}
internal class InputBarViewModel : NotifyPropertyChanged
{
private IEnumerable<InputEntry>? _items;
public virtual IEnumerable<InputEntry>? Items
{
get => _items;
set => SetField(ref _items, value);
}
private InputEntry? _selectedItem;
public virtual InputEntry? SelectedItem
{
get => _selectedItem;
set => SetField(ref _selectedItem, value);
}
private int _selectedIndex;
public virtual int SelectedIndex
{
get => _selectedIndex;
set => SetField(ref _selectedIndex, value);
}
private string? _text;
public virtual string? Text
{
get => _text;
set => SetField(ref _text, value);
}
}
internal class MainInputViewModel : InputBarViewModel
{
private readonly FileSystemSuggestions _suggestions = new FileSystemSuggestions();
public override int SelectedIndex
{
get => base.SelectedIndex;
set
{
if (value == 0)
{
if (Items.Count() <= 1)
{
value = -1;
}
else
{
value = base.SelectedIndex < value ? 1 : -1;
}
}
base.SelectedIndex = value;
}
}
public override string? Text
{
get => base.Text;
set
{
base.Text = value;
if (value != SelectedItem?.ToString())
{
UpdateList(value);
}
}
}
public Command<MainWindow> BrowseCommand { get; }
public Command<ViewModel> SelectCommand { get; }
public MainInputViewModel(Controller controller)
{
Items = Enumerable.Empty<InputEntry>();
BrowseCommand = new Command<MainWindow>(window =>
{
var dialog = new OpenFileDialog
{
Multiselect = false,
ValidateNames = true
};
if (dialog.ShowDialog(window) == true)
{
Text = dialog.FileName;
}
return Task.CompletedTask;
});
SelectCommand = new Command<ViewModel>(async viewModel =>
{
if (SelectedItem?.IsValid != true)
{
return;
}
try
{
BrowseCommand.CanExecuteValue = false;
SelectCommand.CanExecuteValue = false;
await controller.OnMainInputDecided(SelectedItem).ConfigureAwait(true);
}
finally
{
BrowseCommand.CanExecuteValue = true;
SelectCommand.CanExecuteValue = true;
SelectedIndex = -1;
}
});
}
private void UpdateList(string? path)
{
bool candidateFound = false;
var result = _suggestions.ProvideFileSystemSuggestions(path);
InputEntry? first = result.FirstOrDefault();
if (first != null)
{
if (new FileInfo(path!).FullName == new FileInfo(first.Value).FullName)
{
candidateFound = true;
}
}
if (!string.IsNullOrEmpty(path))
{
result = result.Prepend(new InputEntry(InputEntryType.Text, path!, path!));
}
Items = result;
if (candidateFound)
{
SelectedIndex = 1;
}
}
}
internal class BigInputViewModel : InputBarViewModel
{
public override IEnumerable<InputEntry>? Items
{
get => base.Items;
set => base.Items = value;
}
public override InputEntry? SelectedItem
{
get => base.SelectedItem;
set
{
base.SelectedItem = value;
SelectCommand.CanExecuteValue = value != null;
}
}
public override string? Text
{
get => base.Text;
set
{
base.Text = value;
if (value != SelectedItem?.ToString())
{
UpdateList(value);
}
}
}
private InputEntry? _lastProcessedManifest;
public InputEntry? LastProcessedManifest
{
get => _lastProcessedManifest;
set => SetField(ref _lastProcessedManifest, value);
}
private IEnumerable<InputEntry>? _allManifests;
public IEnumerable<InputEntry>? AllManifests
{
get => _allManifests;
set
{
SetField(ref _allManifests, value);
Items = value;
LastProcessedManifest = null;
Text = null;
}
}
public Command<ViewModel> SelectCommand { get; }
[SuppressMessage("Design", "CA1031:不捕获常规异常类型", Justification = "<挂起>")]
public BigInputViewModel(Controller controller)
{
SelectCommand = new Command<ViewModel>(async viewModel =>
{
var mainInput = viewModel.MainInput;
try
{
SelectCommand.CanExecuteValue = false;
mainInput.BrowseCommand.CanExecuteValue = false;
mainInput.SelectCommand.CanExecuteValue = false;
LastProcessedManifest = SelectedItem;
await controller.ProcessManifest(SelectedItem!.Value).ConfigureAwait(true);
}
catch (Exception exception)
{
CopyableBox.ShowDialog(_ =>
{
return Task.FromResult($"在加载 manifest 时发生错误:{exception}");
});
}
finally
{
SelectCommand.CanExecuteValue = true;
mainInput.BrowseCommand.CanExecuteValue = true;
mainInput.SelectCommand.CanExecuteValue = true;
}
})
{
CanExecuteValue = false
};
}
private void UpdateList(string? input)
{
input ??= string.Empty;
input = input.Replace(VirtualFileSystem.AltDirectorySeparatorChar, VirtualFileSystem.DirectorySeparatorChar);
var filtered = from manifest in AllManifests
where manifest.Value.IndexOf(input, StringComparison.OrdinalIgnoreCase) != -1
select manifest;
Items = filtered;
if (Items.FirstOrDefault()?.Value.Equals(input, StringComparison.OrdinalIgnoreCase) == true)
{
SelectedIndex = 0;
}
}
}
}