This commit is contained in:
qhy040404
2024-02-02 11:06:08 +08:00
parent 7baf125f88
commit 974afa86ee
10 changed files with 50 additions and 41 deletions

View File

@@ -2,6 +2,7 @@
// Licensed under the MIT license. // Licensed under the MIT license.
using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore;
using Snap.Hutao.Model.Entity.Database;
using System.Collections.ObjectModel; using System.Collections.ObjectModel;
using System.Collections.Specialized; using System.Collections.Specialized;
using System.Runtime.InteropServices; using System.Runtime.InteropServices;
@@ -11,13 +12,12 @@ namespace Snap.Hutao.Core.Database;
internal sealed class ObservableReorderableDbCollection<T> : ObservableCollection<T> internal sealed class ObservableReorderableDbCollection<T> : ObservableCollection<T>
where T : class, IReorderable where T : class, IReorderable
{ {
private readonly DbContext dbContext; private readonly IServiceProvider serviceProvider;
private bool previousChangeIsRemoved;
public ObservableReorderableDbCollection(List<T> items, DbContext dbContext) public ObservableReorderableDbCollection(List<T> items, IServiceProvider serviceProvider)
: base(AdjustIndex(items)) : base(AdjustIndex(items))
{ {
this.dbContext = dbContext; this.serviceProvider = serviceProvider;
} }
protected override void OnCollectionChanged(NotifyCollectionChangedEventArgs e) protected override void OnCollectionChanged(NotifyCollectionChangedEventArgs e)
@@ -27,16 +27,8 @@ internal sealed class ObservableReorderableDbCollection<T> : ObservableCollectio
switch (e.Action) switch (e.Action)
{ {
case NotifyCollectionChangedAction.Remove: case NotifyCollectionChangedAction.Remove:
previousChangeIsRemoved = true;
break;
case NotifyCollectionChangedAction.Add: case NotifyCollectionChangedAction.Add:
if (!previousChangeIsRemoved)
{
return;
}
OnReorder(); OnReorder();
previousChangeIsRemoved = false;
break; break;
} }
} }
@@ -57,10 +49,15 @@ internal sealed class ObservableReorderableDbCollection<T> : ObservableCollectio
{ {
AdjustIndex((List<T>)Items); AdjustIndex((List<T>)Items);
DbSet<T> dbSet = dbContext.Set<T>(); using (IServiceScope scope = serviceProvider.CreateScope())
foreach (ref readonly T item in CollectionsMarshal.AsSpan((List<T>)Items))
{ {
dbSet.UpdateAndSave(item); AppDbContext appDbContext = scope.ServiceProvider.GetRequiredService<AppDbContext>();
DbSet<T> dbSet = appDbContext.Set<T>();
foreach (ref readonly T item in CollectionsMarshal.AsSpan((List<T>)Items))
{
dbSet.UpdateAndSave(item);
}
} }
} }
} }

View File

@@ -1,6 +1,7 @@
// Copyright (c) DGP Studio. All rights reserved. // Copyright (c) DGP Studio. All rights reserved.
// Licensed under the MIT license. // Licensed under the MIT license.
using Snap.Hutao.Core.Database;
using System.Collections.ObjectModel; using System.Collections.ObjectModel;
using System.Runtime.CompilerServices; using System.Runtime.CompilerServices;
using System.Text; using System.Text;
@@ -113,6 +114,13 @@ internal static partial class EnumerableExtension
return new ObservableCollection<T>(source); return new ObservableCollection<T>(source);
} }
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static ObservableReorderableDbCollection<T> ToObservableReorderableDbCollection<T>(this IEnumerable<T> source, IServiceProvider serviceProvider)
where T : class, IReorderable
{
return new ObservableReorderableDbCollection<T>([.. source], serviceProvider);
}
/// <summary> /// <summary>
/// Concatenates each element from the collection into single string. /// Concatenates each element from the collection into single string.
/// </summary> /// </summary>

View File

@@ -1,6 +1,7 @@
// Copyright (c) DGP Studio. All rights reserved. // Copyright (c) DGP Studio. All rights reserved.
// Licensed under the MIT license. // Licensed under the MIT license.
using Snap.Hutao.Core.Database;
using Snap.Hutao.Core.ExceptionService; using Snap.Hutao.Core.ExceptionService;
using Snap.Hutao.Factory.ContentDialog; using Snap.Hutao.Factory.ContentDialog;
using Snap.Hutao.Model.Entity; using Snap.Hutao.Model.Entity;
@@ -18,9 +19,9 @@ internal sealed partial class GameAccountService : IGameAccountService
private readonly IGameDbService gameDbService; private readonly IGameDbService gameDbService;
private readonly ITaskContext taskContext; private readonly ITaskContext taskContext;
private ObservableCollection<GameAccount>? gameAccounts; private ObservableReorderableDbCollection<GameAccount>? gameAccounts;
public ObservableCollection<GameAccount> GameAccountCollection public ObservableReorderableDbCollection<GameAccount> GameAccountCollection
{ {
get => gameAccounts ??= gameDbService.GetGameAccountCollection(); get => gameAccounts ??= gameDbService.GetGameAccountCollection();
} }

View File

@@ -1,15 +1,15 @@
// Copyright (c) DGP Studio. All rights reserved. // Copyright (c) DGP Studio. All rights reserved.
// Licensed under the MIT license. // Licensed under the MIT license.
using Snap.Hutao.Core.Database;
using Snap.Hutao.Model.Entity; using Snap.Hutao.Model.Entity;
using Snap.Hutao.Model.Entity.Primitive; using Snap.Hutao.Model.Entity.Primitive;
using System.Collections.ObjectModel;
namespace Snap.Hutao.Service.Game.Account; namespace Snap.Hutao.Service.Game.Account;
internal interface IGameAccountService internal interface IGameAccountService
{ {
ObservableCollection<GameAccount> GameAccountCollection { get; } ObservableReorderableDbCollection<GameAccount> GameAccountCollection { get; }
void AttachGameAccountToUid(GameAccount gameAccount, string uid); void AttachGameAccountToUid(GameAccount gameAccount, string uid);

View File

@@ -5,7 +5,6 @@ using Microsoft.EntityFrameworkCore;
using Snap.Hutao.Core.Database; using Snap.Hutao.Core.Database;
using Snap.Hutao.Model.Entity; using Snap.Hutao.Model.Entity;
using Snap.Hutao.Model.Entity.Database; using Snap.Hutao.Model.Entity.Database;
using System.Collections.ObjectModel;
namespace Snap.Hutao.Service.Game; namespace Snap.Hutao.Service.Game;
@@ -15,12 +14,12 @@ internal sealed partial class GameDbService : IGameDbService
{ {
private readonly IServiceProvider serviceProvider; private readonly IServiceProvider serviceProvider;
public ObservableCollection<GameAccount> GetGameAccountCollection() public ObservableReorderableDbCollection<GameAccount> GetGameAccountCollection()
{ {
using (IServiceScope scope = serviceProvider.CreateScope()) using (IServiceScope scope = serviceProvider.CreateScope())
{ {
AppDbContext appDbContext = scope.ServiceProvider.GetRequiredService<AppDbContext>(); AppDbContext appDbContext = scope.ServiceProvider.GetRequiredService<AppDbContext>();
return appDbContext.GameAccounts.AsNoTracking().ToObservableCollection(); return appDbContext.GameAccounts.AsNoTracking().OrderBy(account => account.Index).ToObservableReorderableDbCollection(serviceProvider);
} }
} }

View File

@@ -1,13 +1,13 @@
// Copyright (c) DGP Studio. All rights reserved. // Copyright (c) DGP Studio. All rights reserved.
// Licensed under the MIT license. // Licensed under the MIT license.
using Snap.Hutao.Core.Database;
using Snap.Hutao.Model.Entity; using Snap.Hutao.Model.Entity;
using Snap.Hutao.Model.Entity.Primitive; using Snap.Hutao.Model.Entity.Primitive;
using Snap.Hutao.Service.Game.Account; using Snap.Hutao.Service.Game.Account;
using Snap.Hutao.Service.Game.Configuration; using Snap.Hutao.Service.Game.Configuration;
using Snap.Hutao.Service.Game.Launching.Handler; using Snap.Hutao.Service.Game.Launching.Handler;
using Snap.Hutao.Service.Game.PathAbstraction; using Snap.Hutao.Service.Game.PathAbstraction;
using System.Collections.ObjectModel;
namespace Snap.Hutao.Service.Game; namespace Snap.Hutao.Service.Game;
@@ -24,7 +24,7 @@ internal sealed partial class GameServiceFacade : IGameServiceFacade
private readonly IGamePathService gamePathService; private readonly IGamePathService gamePathService;
/// <inheritdoc/> /// <inheritdoc/>
public ObservableCollection<GameAccount> GameAccountCollection public ObservableReorderableDbCollection<GameAccount> GameAccountCollection
{ {
get => gameAccountService.GameAccountCollection; get => gameAccountService.GameAccountCollection;
} }

View File

@@ -1,8 +1,8 @@
// Copyright (c) DGP Studio. All rights reserved. // Copyright (c) DGP Studio. All rights reserved.
// Licensed under the MIT license. // Licensed under the MIT license.
using Snap.Hutao.Core.Database;
using Snap.Hutao.Model.Entity; using Snap.Hutao.Model.Entity;
using System.Collections.ObjectModel;
namespace Snap.Hutao.Service.Game; namespace Snap.Hutao.Service.Game;
@@ -12,7 +12,7 @@ internal interface IGameDbService
ValueTask RemoveGameAccountByIdAsync(Guid id); ValueTask RemoveGameAccountByIdAsync(Guid id);
ObservableCollection<GameAccount> GetGameAccountCollection(); ObservableReorderableDbCollection<GameAccount> GetGameAccountCollection();
void UpdateGameAccount(GameAccount gameAccount); void UpdateGameAccount(GameAccount gameAccount);

View File

@@ -1,10 +1,10 @@
// Copyright (c) DGP Studio. All rights reserved. // Copyright (c) DGP Studio. All rights reserved.
// Licensed under the MIT license. // Licensed under the MIT license.
using Snap.Hutao.Core.Database;
using Snap.Hutao.Model.Entity; using Snap.Hutao.Model.Entity;
using Snap.Hutao.Model.Entity.Primitive; using Snap.Hutao.Model.Entity.Primitive;
using Snap.Hutao.Service.Game.Configuration; using Snap.Hutao.Service.Game.Configuration;
using System.Collections.ObjectModel;
namespace Snap.Hutao.Service.Game; namespace Snap.Hutao.Service.Game;
@@ -17,7 +17,7 @@ internal interface IGameServiceFacade
/// <summary> /// <summary>
/// 游戏内账号集合 /// 游戏内账号集合
/// </summary> /// </summary>
ObservableCollection<GameAccount> GameAccountCollection { get; } ObservableReorderableDbCollection<GameAccount> GameAccountCollection { get; }
/// <summary> /// <summary>
/// 将账号绑定到对应的Uid /// 将账号绑定到对应的Uid

View File

@@ -202,6 +202,8 @@
IsClickEnabled="True"/> IsClickEnabled="True"/>
<Border Padding="0,1" Style="{StaticResource BorderCardStyle}"> <Border Padding="0,1" Style="{StaticResource BorderCardStyle}">
<ListView <ListView
AllowDrop="True"
CanReorderItems="True"
ItemTemplate="{StaticResource GameAccountListTemplate}" ItemTemplate="{StaticResource GameAccountListTemplate}"
ItemsSource="{Binding GameAccountsView}" ItemsSource="{Binding GameAccountsView}"
SelectedItem="{Binding SelectedGameAccount, Mode=TwoWay}"/> SelectedItem="{Binding SelectedGameAccount, Mode=TwoWay}"/>

View File

@@ -5,6 +5,7 @@ using CommunityToolkit.WinUI.Collections;
using Microsoft.Extensions.Caching.Memory; using Microsoft.Extensions.Caching.Memory;
using Microsoft.UI.Windowing; using Microsoft.UI.Windowing;
using Snap.Hutao.Core; using Snap.Hutao.Core;
using Snap.Hutao.Core.Database;
using Snap.Hutao.Core.Diagnostics.CodeAnalysis; using Snap.Hutao.Core.Diagnostics.CodeAnalysis;
using Snap.Hutao.Core.ExceptionService; using Snap.Hutao.Core.ExceptionService;
using Snap.Hutao.Model.Entity; using Snap.Hutao.Model.Entity;
@@ -18,7 +19,6 @@ using Snap.Hutao.Service.Notification;
using Snap.Hutao.Service.User; using Snap.Hutao.Service.User;
using Snap.Hutao.Web.Hoyolab.SdkStatic.Hk4e.Launcher; using Snap.Hutao.Web.Hoyolab.SdkStatic.Hk4e.Launcher;
using System.Collections.Immutable; using System.Collections.Immutable;
using System.Collections.ObjectModel;
using System.IO; using System.IO;
namespace Snap.Hutao.ViewModel.Game; namespace Snap.Hutao.ViewModel.Game;
@@ -241,6 +241,8 @@ internal sealed partial class LaunchGameViewModel : Abstraction.ViewModel, IView
{ {
await taskContext.SwitchToMainThreadAsync(); await taskContext.SwitchToMainThreadAsync();
SelectedGameAccount = account; SelectedGameAccount = account;
await UpdateGameAccountsViewAsync().ConfigureAwait(false);
} }
} }
catch (UserdataCorruptedException ex) catch (UserdataCorruptedException ex)
@@ -326,18 +328,6 @@ internal sealed partial class LaunchGameViewModel : Abstraction.ViewModel, IView
GameResource = response.Data; GameResource = response.Data;
} }
} }
async ValueTask UpdateGameAccountsViewAsync()
{
gameAccountFilter = new(SelectedScheme?.GetSchemeType());
ObservableCollection<GameAccount> accounts = gameService.GameAccountCollection;
await taskContext.SwitchToMainThreadAsync();
GameAccountsView = new(accounts, true)
{
Filter = gameAccountFilter.Filter,
};
}
} }
[Command("IdentifyMonitorsCommand")] [Command("IdentifyMonitorsCommand")]
@@ -363,4 +353,16 @@ internal sealed partial class LaunchGameViewModel : Abstraction.ViewModel, IView
window.Close(); 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,
};
}
} }