This commit is contained in:
qhy040404
2024-02-05 21:47:52 +08:00
parent 678ec191a6
commit 95024e4107
10 changed files with 991 additions and 20 deletions

View File

@@ -0,0 +1,54 @@
// Copyright (c) DGP Studio. All rights reserved.
// Licensed under the MIT license.
namespace Snap.Hutao.Control.Collection.AdvancedCollectionView;
/// <summary>
/// A collection view implementation that supports filtering, grouping, sorting and incremental loading
/// </summary>
internal partial class AdvancedCollectionView
{
/// <summary>
/// Stops refreshing until it is disposed
/// </summary>
/// <returns>An disposable object</returns>
public IDisposable DeferRefresh()
{
return new NotificationDeferrer(this);
}
/// <summary>
/// Notification deferrer helper class
/// </summary>
#pragma warning disable CA1063 // Implement IDisposable Correctly
public class NotificationDeferrer : IDisposable
#pragma warning restore CA1063 // Implement IDisposable Correctly
{
private readonly AdvancedCollectionView _acvs;
private readonly object _currentItem;
/// <summary>
/// Initializes a new instance of the <see cref="NotificationDeferrer"/> class.
/// </summary>
/// <param name="acvs">Source ACVS</param>
public NotificationDeferrer(AdvancedCollectionView acvs)
{
_acvs = acvs;
_currentItem = _acvs.CurrentItem;
_acvs._deferCounter++;
}
/// <summary>
/// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources.
/// </summary>
/// <filterpriority>2</filterpriority>
#pragma warning disable CA1063 // Implement IDisposable Correctly
public void Dispose()
#pragma warning restore CA1063 // Implement IDisposable Correctly
{
_acvs.MoveCurrentTo(_currentItem);
_acvs._deferCounter--;
_acvs.Refresh();
}
}
}

View File

@@ -0,0 +1,61 @@
// Copyright (c) DGP Studio. All rights reserved.
// Licensed under the MIT license.
using Microsoft.UI.Xaml.Data;
using Windows.Foundation.Collections;
namespace Snap.Hutao.Control.Collection.AdvancedCollectionView;
/// <summary>
/// A collection view implementation that supports filtering, grouping, sorting and incremental loading
/// </summary>
internal partial class AdvancedCollectionView
{
/// <summary>
/// Currently selected item changing event
/// </summary>
/// <param name="e">event args</param>
private void OnCurrentChanging(CurrentChangingEventArgs e)
{
if (_deferCounter > 0)
{
return;
}
CurrentChanging?.Invoke(this, e);
}
/// <summary>
/// Currently selected item changed event
/// </summary>
/// <param name="e">event args</param>
private void OnCurrentChanged(object e)
{
if (_deferCounter > 0)
{
return;
}
CurrentChanged?.Invoke(this, e);
// ReSharper disable once ExplicitCallerInfoArgument
OnPropertyChanged(nameof(CurrentItem));
}
/// <summary>
/// Vector changed event
/// </summary>
/// <param name="e">event args</param>
private void OnVectorChanged(IVectorChangedEventArgs e)
{
if (_deferCounter > 0)
{
return;
}
VectorChanged?.Invoke(this, e);
// ReSharper disable once ExplicitCallerInfoArgument
OnPropertyChanged(nameof(Count));
}
}

View File

@@ -0,0 +1,816 @@
// Copyright (c) DGP Studio. All rights reserved.
// Licensed under the MIT license.
using System.Collections;
using System.Collections.ObjectModel;
using System.Collections.Specialized;
using System.Reflection;
using System.Runtime.CompilerServices;
using CommunityToolkit.WinUI.Collections;
using CommunityToolkit.WinUI.Helpers;
using Microsoft.UI.Xaml.Data;
using Windows.Foundation;
using Windows.Foundation.Collections;
using NotifyCollectionChangedAction = global::System.Collections.Specialized.NotifyCollectionChangedAction;
namespace Snap.Hutao.Control.Collection.AdvancedCollectionView;
/// <summary>
/// A collection view implementation that supports filtering, sorting and incremental loading
/// https://github.com/CommunityToolkit/Windows/pull/309
/// </summary>
internal partial class AdvancedCollectionView : IAdvancedCollectionView, INotifyPropertyChanged, ISupportIncrementalLoading, IComparer<object>
{
private readonly List<object> _view;
private readonly ObservableCollection<SortDescription> _sortDescriptions;
private readonly Dictionary<string, PropertyInfo> _sortProperties;
private readonly bool _liveShapingEnabled;
private readonly HashSet<string> _observedFilterProperties = new HashSet<string>();
private IList _source;
private Predicate<object> _filter;
private int _deferCounter;
private WeakEventListener<AdvancedCollectionView, object, NotifyCollectionChangedEventArgs> _sourceWeakEventListener;
/// <summary>
/// Initializes a new instance of the <see cref="AdvancedCollectionView"/> class.
/// </summary>
public AdvancedCollectionView()
: this(new List<object>(0))
{
}
/// <summary>
/// Initializes a new instance of the <see cref="AdvancedCollectionView"/> class.
/// </summary>
/// <param name="source">source IEnumerable</param>
/// <param name="isLiveShaping">Denotes whether or not this ACV should re-filter/re-sort if a PropertyChanged is raised for an observed property.</param>
#pragma warning disable CS8767
#pragma warning disable CS8769
#pragma warning disable CS8622
#pragma warning disable CS8600
#pragma warning disable CS8601
#pragma warning disable CS8604
#pragma warning disable CS8603 // Possible null reference return.
#pragma warning disable CS8618 // Non-nullable field must contain a non-null value when exiting constructor. Consider declaring as nullable.
public AdvancedCollectionView(IList source, bool isLiveShaping = false)
{
_liveShapingEnabled = isLiveShaping;
_view = new List<object>();
_sortDescriptions = new ObservableCollection<SortDescription>();
_sortDescriptions.CollectionChanged += SortDescriptions_CollectionChanged;
_sortProperties = new Dictionary<string, PropertyInfo>();
Source = source;
}
/// <summary>
/// Gets or sets the source
/// </summary>
public IList Source
{
get
{
return _source;
}
set
{
// ReSharper disable once PossibleUnintendedReferenceComparison
if (_source == value)
{
return;
}
if (_source != null)
{
DetachPropertyChangedHandler(_source);
}
_source = value;
AttachPropertyChangedHandler(_source);
_sourceWeakEventListener?.Detach();
if (_source is INotifyCollectionChanged sourceNcc)
{
_sourceWeakEventListener =
new WeakEventListener<AdvancedCollectionView, object, NotifyCollectionChangedEventArgs>(this)
{
// Call the actual collection changed event
OnEventAction = (source, changed, arg3) => SourceNcc_CollectionChanged(source, arg3),
// The source doesn't exist anymore
OnDetachAction = (listener) => sourceNcc.CollectionChanged -= _sourceWeakEventListener!.OnEvent
};
sourceNcc.CollectionChanged += _sourceWeakEventListener.OnEvent;
}
HandleSourceChanged();
OnPropertyChanged();
}
}
/// <summary>
/// Manually refresh the view
/// </summary>
public void Refresh()
{
HandleSourceChanged();
}
/// <inheritdoc/>
public void RefreshFilter()
{
HandleFilterChanged();
}
/// <inheritdoc/>
public void RefreshSorting()
{
HandleSortChanged();
}
/// <inheritdoc />
public IEnumerator<object> GetEnumerator() => _view.GetEnumerator();
/// <inheritdoc />
IEnumerator IEnumerable.GetEnumerator() => _view.GetEnumerator();
/// <inheritdoc />
public void Add(object item)
{
if (IsReadOnly)
{
throw new NotSupportedException("Collection is read-only.");
}
_source.Add(item);
}
/// <inheritdoc />
public void Clear()
{
if (IsReadOnly)
{
throw new NotSupportedException("Collection is read-only.");
}
_source.Clear();
}
/// <inheritdoc />
public bool Contains(object item) => _view.Contains(item);
/// <inheritdoc />
public void CopyTo(object[] array, int arrayIndex) => _view.CopyTo(array, arrayIndex);
/// <inheritdoc />
public bool Remove(object item)
{
if (IsReadOnly)
{
throw new NotSupportedException("Collection is read-only.");
}
_source.Remove(item);
return true;
}
/// <inheritdoc />
public int Count => _view.Count;
/// <inheritdoc />
public bool IsReadOnly => _source == null || _source.IsReadOnly;
/// <inheritdoc />
public int IndexOf(object item) => _view.IndexOf(item);
/// <inheritdoc />
public void Insert(int index, object item)
{
if (IsReadOnly)
{
throw new NotSupportedException("Collection is read-only.");
}
_source.Insert(index, item);
}
/// <summary>
/// Removes the <see cref="T:System.Collections.Generic.IList`1"/> item at the specified index.
/// </summary>
/// <param name="index">The zero-based index of the item to remove.</param><exception cref="T:System.ArgumentOutOfRangeException"><paramref name="index"/> is not a valid index in the <see cref="T:System.Collections.Generic.IList`1"/>.</exception><exception cref="T:System.NotSupportedException">The <see cref="T:System.Collections.Generic.IList`1"/> is read-only.</exception>
public void RemoveAt(int index) => Remove(_view[index]);
/// <summary>
/// Gets or sets the element at the specified index.
/// </summary>
/// <returns>
/// The element at the specified index.
/// </returns>
/// <param name="index">The zero-based index of the element to get or set.</param><exception cref="T:System.ArgumentOutOfRangeException"><paramref name="index"/> is not a valid index in the <see cref="T:System.Collections.Generic.IList`1"/>.</exception><exception cref="T:System.NotSupportedException">The property is set and the <see cref="T:System.Collections.Generic.IList`1"/> is read-only.</exception>
public object this[int index]
{
get { return _view[index]; }
set { _view[index] = value; }
}
/// <summary>
/// Occurs when the vector changes.
/// </summary>
public event Windows.Foundation.Collections.VectorChangedEventHandler<object> VectorChanged;
/// <summary>
/// Move current index to item
/// </summary>
/// <param name="item">item</param>
/// <returns>success of operation</returns>
public bool MoveCurrentTo(object item) => item == CurrentItem || MoveCurrentToIndex(IndexOf(item));
/// <summary>
/// Moves selected item to position
/// </summary>
/// <param name="index">index</param>
/// <returns>success of operation</returns>
public bool MoveCurrentToPosition(int index) => MoveCurrentToIndex(index);
/// <summary>
/// Move current item to first item
/// </summary>
/// <returns>success of operation</returns>
public bool MoveCurrentToFirst() => MoveCurrentToIndex(0);
/// <summary>
/// Move current item to last item
/// </summary>
/// <returns>success of operation</returns>
public bool MoveCurrentToLast() => MoveCurrentToIndex(_view.Count - 1);
/// <summary>
/// Move current item to next item
/// </summary>
/// <returns>success of operation</returns>
public bool MoveCurrentToNext() => MoveCurrentToIndex(CurrentPosition + 1);
/// <summary>
/// Move current item to previous item
/// </summary>
/// <returns>success of operation</returns>
public bool MoveCurrentToPrevious() => MoveCurrentToIndex(CurrentPosition - 1);
/// <summary>
/// Load more items from the source
/// </summary>
/// <param name="count">number of items to load</param>
/// <returns>Async operation of LoadMoreItemsResult</returns>
/// <exception cref="NotImplementedException">Not implemented yet...</exception>
public IAsyncOperation<LoadMoreItemsResult> LoadMoreItemsAsync(uint count)
{
var sil = _source as ISupportIncrementalLoading;
return sil?.LoadMoreItemsAsync(count);
}
/// <summary>
/// Gets the groups in collection
/// </summary>
public IObservableVector<object> CollectionGroups => null;
/// <summary>
/// Gets or sets the current item
/// </summary>
public object CurrentItem
{
get { return CurrentPosition > -1 && CurrentPosition < _view.Count ? _view[CurrentPosition] : null; }
#pragma warning restore CS8603 // Possible null reference return.
set { MoveCurrentTo(value); }
}
/// <summary>
/// Gets the position of current item
/// </summary>
public int CurrentPosition { get; private set; }
/// <summary>
/// Gets a value indicating whether the source has more items
/// </summary>
public bool HasMoreItems => (_source as ISupportIncrementalLoading)?.HasMoreItems ?? false;
/// <summary>
/// Gets a value indicating whether the current item is after the last visible item
/// </summary>
public bool IsCurrentAfterLast => CurrentPosition >= _view.Count;
/// <summary>
/// Gets a value indicating whether the current item is before the first visible item
/// </summary>
public bool IsCurrentBeforeFirst => CurrentPosition < 0;
/// <summary>
/// Current item changed event handler
/// </summary>
public event EventHandler<object> CurrentChanged;
/// <summary>
/// Current item changing event handler
/// </summary>
public event CurrentChangingEventHandler CurrentChanging;
/// <summary>
/// Gets a value indicating whether this CollectionView can filter its items
/// </summary>
public bool CanFilter => true;
/// <summary>
/// Gets or sets the predicate used to filter the visible items
/// </summary>
public Predicate<object> Filter
{
get
{
return _filter;
}
set
{
if (_filter == value)
{
return;
}
_filter = value;
HandleFilterChanged();
}
}
/// <summary>
/// Gets a value indicating whether this CollectionView can sort its items
/// </summary>
public bool CanSort => true;
/// <summary>
/// Gets SortDescriptions to sort the visible items
/// </summary>
public IList<SortDescription> SortDescriptions => _sortDescriptions;
/*
/// <summary>
/// Gets a value indicating whether this CollectionView can group its items
/// </summary>
public bool CanGroup => false;
/// <summary>
/// Gets GroupDescriptions to group the visible items
/// </summary>
public IList<object> GroupDescriptions => null;
*/
/// <summary>
/// Gets the source collection
/// </summary>
public IEnumerable SourceCollection => _source;
/// <summary>
/// IComparer implementation
/// </summary>
/// <param name="x">Object A</param>
/// <param name="y">Object B</param>
/// <returns>Comparison value</returns>
#pragma warning disable CA1033 // Interface methods should be callable by child types
int IComparer<object>.Compare(object x, object y)
#pragma warning restore CA1033 // Interface methods should be callable by child types
{
if (!_sortProperties.Any())
{
var listType = _source?.GetType();
Type type;
if (listType != null && listType.IsGenericType)
{
type = listType.GetGenericArguments()[0];
}
else
{
type = x.GetType();
}
foreach (var sd in _sortDescriptions)
{
if (!string.IsNullOrEmpty(sd.PropertyName))
{
_sortProperties[sd.PropertyName] = type.GetProperty(sd.PropertyName);
}
}
}
foreach (var sd in _sortDescriptions)
{
object cx, cy;
if (string.IsNullOrEmpty(sd.PropertyName))
{
cx = x;
cy = y;
}
else
{
var pi = _sortProperties[sd.PropertyName];
cx = pi.GetValue(x!);
cy = pi.GetValue(y!);
}
var cmp = sd.Comparer.Compare(cx, cy);
if (cmp != 0)
{
return sd.Direction == SortDirection.Ascending ? +cmp : -cmp;
}
}
return 0;
}
/// <summary>
/// Occurs when a property value changes.
/// </summary>
public event PropertyChangedEventHandler? PropertyChanged;
/// <summary>
/// Property changed event invoker
/// </summary>
/// <param name="propertyName">name of the property that changed</param>
protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null!)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
/// <inheritdoc/>
public void ObserveFilterProperty(string propertyName)
{
_observedFilterProperties.Add(propertyName);
}
/// <inheritdoc/>
public void ClearObservedFilterProperties()
{
_observedFilterProperties.Clear();
}
private void ItemOnPropertyChanged(object item, PropertyChangedEventArgs e)
{
if (!_liveShapingEnabled)
{
return;
}
var filterResult = _filter?.Invoke(item);
if (filterResult.HasValue && _observedFilterProperties.Contains(e.PropertyName))
{
var viewIndex = _view.IndexOf(item);
if (viewIndex != -1 && !filterResult.Value)
{
RemoveFromView(viewIndex, item);
}
else if (viewIndex == -1 && filterResult.Value)
{
var index = _source.IndexOf(item);
HandleItemAdded(index, item);
}
}
if ((filterResult ?? true) && SortDescriptions.Any(sd => sd.PropertyName == e.PropertyName))
{
var oldIndex = _view.IndexOf(item);
// Check if item is in view:
if (oldIndex < 0)
{
return;
}
_view.RemoveAt(oldIndex);
var targetIndex = _view.BinarySearch(item, this);
if (targetIndex < 0)
{
targetIndex = ~targetIndex;
}
// Only trigger expensive UI updates if the index really changed:
if (targetIndex != oldIndex)
{
OnVectorChanged(new VectorChangedEventArgs(CollectionChange.ItemRemoved, oldIndex, item));
_view.Insert(targetIndex, item);
OnVectorChanged(new VectorChangedEventArgs(CollectionChange.ItemInserted, targetIndex, item));
}
else
{
_view.Insert(targetIndex, item);
}
}
else if (string.IsNullOrEmpty(e.PropertyName))
{
HandleSourceChanged();
}
}
private void AttachPropertyChangedHandler(IEnumerable items)
{
if (!_liveShapingEnabled || items == null)
{
return;
}
foreach (var item in items.OfType<INotifyPropertyChanged>())
{
item.PropertyChanged += ItemOnPropertyChanged;
}
}
private void DetachPropertyChangedHandler(IEnumerable items)
{
if (!_liveShapingEnabled || items == null)
{
return;
}
foreach (var item in items.OfType<INotifyPropertyChanged>())
{
item.PropertyChanged -= ItemOnPropertyChanged;
}
}
private void HandleSortChanged()
{
_sortProperties.Clear();
_view.Sort(this);
_sortProperties.Clear();
OnVectorChanged(new VectorChangedEventArgs(CollectionChange.Reset));
}
private void HandleFilterChanged()
{
if (_filter != null)
{
for (var index = 0; index < _view.Count; index++)
{
var item = _view.ElementAt(index);
if (_filter(item))
{
continue;
}
RemoveFromView(index, item);
index--;
}
}
var viewHash = new HashSet<object>(_view);
var viewIndex = 0;
for (var index = 0; index < _source.Count; index++)
{
var item = _source[index];
if (viewHash.Contains(item))
{
viewIndex++;
continue;
}
if (HandleItemAdded(index, item, viewIndex))
{
viewIndex++;
}
}
}
private void HandleSourceChanged()
{
_sortProperties.Clear();
var currentItem = CurrentItem;
_view.Clear();
foreach (var item in Source)
{
if (_filter != null && !_filter(item))
{
continue;
}
if (_sortDescriptions.Any())
{
var targetIndex = _view.BinarySearch(item, this);
if (targetIndex < 0)
{
targetIndex = ~targetIndex;
}
_view.Insert(targetIndex, item);
}
else
{
_view.Add(item);
}
}
_sortProperties.Clear();
OnVectorChanged(new VectorChangedEventArgs(CollectionChange.Reset));
MoveCurrentTo(currentItem);
}
private void SourceNcc_CollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
{
// ReSharper disable once SwitchStatementMissingSomeCases
switch (e.Action)
{
case NotifyCollectionChangedAction.Add:
AttachPropertyChangedHandler(e.NewItems);
if (_deferCounter <= 0)
{
if (e.NewItems?.Count == 1)
{
HandleItemAdded(e.NewStartingIndex, e.NewItems[0]);
}
else
{
HandleSourceChanged();
}
}
break;
case NotifyCollectionChangedAction.Remove:
DetachPropertyChangedHandler(e.OldItems);
if (_deferCounter <= 0)
{
if (e.OldItems?.Count == 1)
{
HandleItemRemoved(e.OldStartingIndex, e.OldItems[0]);
}
else
{
HandleSourceChanged();
}
}
break;
case NotifyCollectionChangedAction.Move:
case NotifyCollectionChangedAction.Replace:
case NotifyCollectionChangedAction.Reset:
if (_deferCounter <= 0)
{
HandleSourceChanged();
}
break;
}
}
private bool HandleItemAdded(int newStartingIndex, object newItem, int? viewIndex = null)
{
if (_filter != null && !_filter(newItem))
{
return false;
}
var newViewIndex = _view.Count;
if (_sortDescriptions.Any())
{
_sortProperties.Clear();
newViewIndex = _view.BinarySearch(newItem, this);
if (newViewIndex < 0)
{
newViewIndex = ~newViewIndex;
}
}
else if (_filter != null)
{
if (_source == null)
{
HandleSourceChanged();
return false;
}
if (newStartingIndex == 0 || _view.Count == 0)
{
newViewIndex = 0;
}
else if (newStartingIndex == _source.Count - 1)
{
newViewIndex = _view.Count;
}
else if (viewIndex.HasValue)
{
newViewIndex = viewIndex.Value;
}
else
{
for (int i = 0, j = 0; i < _source.Count; i++)
{
if (i == newStartingIndex)
{
newViewIndex = j;
break;
}
if (_view[j] == _source[i])
{
j++;
}
}
}
}
_view.Insert(newViewIndex, newItem);
if (newViewIndex <= CurrentPosition)
{
CurrentPosition++;
}
var e = new VectorChangedEventArgs(CollectionChange.ItemInserted, newViewIndex, newItem);
OnVectorChanged(e);
return true;
}
private void HandleItemRemoved(int oldStartingIndex, object oldItem)
{
if (_filter != null && !_filter(oldItem))
{
return;
}
if (oldStartingIndex < 0 || oldStartingIndex >= _view.Count || !Equals(_view[oldStartingIndex], oldItem))
{
oldStartingIndex = _view.IndexOf(oldItem);
}
if (oldStartingIndex < 0)
{
return;
}
RemoveFromView(oldStartingIndex, oldItem);
}
private void RemoveFromView(int itemIndex, object item)
{
_view.RemoveAt(itemIndex);
if (itemIndex <= CurrentPosition)
{
CurrentPosition--;
}
var e = new VectorChangedEventArgs(CollectionChange.ItemRemoved, itemIndex, item);
OnVectorChanged(e);
}
private void SortDescriptions_CollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
{
if (_deferCounter > 0)
{
return;
}
HandleSortChanged();
}
private bool MoveCurrentToIndex(int i)
{
if (i < -1 || i >= _view.Count)
{
return false;
}
if (i == CurrentPosition)
{
return false;
}
var e = new CurrentChangingEventArgs();
OnCurrentChanging(e);
if (e.Cancel)
{
return false;
}
CurrentPosition = i;
OnCurrentChanged(null!);
return true;
}
}
#pragma warning restore CS8767
#pragma warning restore CS8769
#pragma warning restore CS8622
#pragma warning restore CS8601
#pragma warning restore CS8600
#pragma warning restore CS8604
#pragma warning restore CS8618 // Non-nullable field must contain a non-null value when exiting constructor. Consider declaring as nullable.
#pragma warning restore CS8603 // Possible null reference return.

View File

@@ -0,0 +1,40 @@
// Copyright (c) DGP Studio. All rights reserved.
// Licensed under the MIT license.
using Windows.Foundation.Collections;
namespace Snap.Hutao.Control.Collection.AdvancedCollectionView;
/// <summary>
/// Vector changed EventArgs
/// </summary>
internal class VectorChangedEventArgs : IVectorChangedEventArgs
{
/// <summary>
/// Initializes a new instance of the <see cref="VectorChangedEventArgs"/> class.
/// </summary>
/// <param name="cc">collection change type</param>
/// <param name="index">index of item changed</param>
/// <param name="item">item changed</param>
public VectorChangedEventArgs(CollectionChange cc, int index = -1, object item = null!)
{
CollectionChange = cc;
Index = (uint)index;
}
/// <summary>
/// Gets the type of change that occurred in the vector.
/// </summary>
/// <returns>
/// The type of change in the vector.
/// </returns>
public CollectionChange CollectionChange { get; }
/// <summary>
/// Gets the position where the change occurred in the vector.
/// </summary>
/// <returns>
/// The zero-based position where the change occurred in the vector, if applicable.
/// </returns>
public uint Index { get; }
}

View File

@@ -1,8 +1,8 @@
// Copyright (c) DGP Studio. All rights reserved.
// Licensed under the MIT license.
using CommunityToolkit.WinUI.Collections;
using Microsoft.UI.Xaml.Controls;
using Snap.Hutao.Control.Collection.AdvancedCollectionView;
using Snap.Hutao.Core.IO;
using Snap.Hutao.Core.LifeCycle;
using Snap.Hutao.Factory.ContentDialog;
@@ -18,6 +18,8 @@ using System.Text.RegularExpressions;
using EntityAchievementArchive = Snap.Hutao.Model.Entity.AchievementArchive;
using MetadataAchievement = Snap.Hutao.Model.Metadata.Achievement.Achievement;
using MetadataAchievementGoal = Snap.Hutao.Model.Metadata.Achievement.AchievementGoal;
using SortDescription = CommunityToolkit.WinUI.Collections.SortDescription;
using SortDirection = CommunityToolkit.WinUI.Collections.SortDirection;
namespace Snap.Hutao.ViewModel.Achievement;

View File

@@ -1,9 +1,9 @@
// Copyright (c) DGP Studio. All rights reserved.
// Licensed under the MIT license.
using CommunityToolkit.WinUI.Collections;
using Microsoft.Extensions.Caching.Memory;
using Microsoft.UI.Windowing;
using Snap.Hutao.Control.Collection.AdvancedCollectionView;
using Snap.Hutao.Core;
using Snap.Hutao.Core.Database;
using Snap.Hutao.Core.Diagnostics.CodeAnalysis;
@@ -241,8 +241,6 @@ internal sealed partial class LaunchGameViewModel : Abstraction.ViewModel, IView
{
await taskContext.SwitchToMainThreadAsync();
SelectedGameAccount = account;
await UpdateGameAccountsViewAsync().ConfigureAwait(false);
}
}
catch (UserdataCorruptedException ex)
@@ -328,6 +326,18 @@ internal sealed partial class LaunchGameViewModel : Abstraction.ViewModel, IView
GameResource = response.Data;
}
}
async ValueTask UpdateGameAccountsViewAsync()
{
gameAccountFilter = new(SelectedScheme?.GetSchemeType());
ObservableReorderableDbCollection<GameAccount> accounts = gameService.GameAccountCollection;
await taskContext.SwitchToMainThreadAsync();
GameAccountsView = new(accounts, true)
{
Filter = gameAccountFilter.Filter,
};
}
}
[Command("IdentifyMonitorsCommand")]
@@ -353,16 +363,4 @@ internal sealed partial class LaunchGameViewModel : Abstraction.ViewModel, IView
window.Close();
}
}
private async ValueTask UpdateGameAccountsViewAsync()
{
gameAccountFilter = new(SelectedScheme?.GetSchemeType());
ObservableReorderableDbCollection<GameAccount> accounts = gameService.GameAccountCollection;
await taskContext.SwitchToMainThreadAsync();
GameAccountsView = new(accounts, true)
{
Filter = gameAccountFilter.Filter,
};
}
}

View File

@@ -1,7 +1,7 @@
// Copyright (c) DGP Studio. All rights reserved.
// Licensed under the MIT license.
using CommunityToolkit.WinUI.Collections;
using Snap.Hutao.Control.Collection.AdvancedCollectionView;
using Snap.Hutao.Core.ExceptionService;
using Snap.Hutao.Model.Entity;
using Snap.Hutao.Service.Game;

View File

@@ -1,7 +1,7 @@
// Copyright (c) DGP Studio. All rights reserved.
// Licensed under the MIT license.
using CommunityToolkit.WinUI.Collections;
using Snap.Hutao.Control.Collection.AdvancedCollectionView;
using Snap.Hutao.Factory.ContentDialog;
using Snap.Hutao.Model.Calculable;
using Snap.Hutao.Model.Entity.Primitive;

View File

@@ -1,7 +1,7 @@
// Copyright (c) DGP Studio. All rights reserved.
// Licensed under the MIT license.
using CommunityToolkit.WinUI.Collections;
using Snap.Hutao.Control.Collection.AdvancedCollectionView;
using Snap.Hutao.Model.Intrinsic;
using Snap.Hutao.Model.Metadata.Item;
using Snap.Hutao.Model.Metadata.Monster;

View File

@@ -1,7 +1,7 @@
// Copyright (c) DGP Studio. All rights reserved.
// Licensed under the MIT license.
using CommunityToolkit.WinUI.Collections;
using Snap.Hutao.Control.Collection.AdvancedCollectionView;
using Snap.Hutao.Factory.ContentDialog;
using Snap.Hutao.Model.Calculable;
using Snap.Hutao.Model.Entity.Primitive;