mirror of
https://jihulab.com/DGP-Studio/Snap.Hutao.git
synced 2025-11-19 21:02:53 +08:00
impl #1334
This commit is contained in:
@@ -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);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -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>
|
||||||
|
|||||||
@@ -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();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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);
|
||||||
|
|
||||||
|
|||||||
@@ -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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -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;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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);
|
||||||
|
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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}"/>
|
||||||
|
|||||||
@@ -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,
|
||||||
|
};
|
||||||
|
}
|
||||||
}
|
}
|
||||||
Reference in New Issue
Block a user