diff --git a/src/Snap.Hutao/Snap.Hutao.SourceGeneration/Snap.Hutao.SourceGeneration.csproj b/src/Snap.Hutao/Snap.Hutao.SourceGeneration/Snap.Hutao.SourceGeneration.csproj index 003c57a285..d1957c5605 100644 --- a/src/Snap.Hutao/Snap.Hutao.SourceGeneration/Snap.Hutao.SourceGeneration.csproj +++ b/src/Snap.Hutao/Snap.Hutao.SourceGeneration/Snap.Hutao.SourceGeneration.csproj @@ -21,7 +21,7 @@ all runtime; build; native; contentfiles; analyzers; buildtransitive - + all runtime; build; native; contentfiles; analyzers; buildtransitive diff --git a/src/Snap.Hutao/Snap.Hutao/Context/Database/AppDbContext.cs b/src/Snap.Hutao/Snap.Hutao/Context/Database/AppDbContext.cs index c0ffb9fd8b..e090853d11 100644 --- a/src/Snap.Hutao/Snap.Hutao/Context/Database/AppDbContext.cs +++ b/src/Snap.Hutao/Snap.Hutao/Context/Database/AppDbContext.cs @@ -56,6 +56,11 @@ public AppDbContext(DbContextOptions options) /// public DbSet AvatarInfos { get; set; } = default!; + /// + /// 游戏内账号 + /// + public DbSet GameAccounts { get; set; } = default!; + /// /// 构造一个临时的应用程序数据库上下文 /// diff --git a/src/Snap.Hutao/Snap.Hutao/Core/Threading/ThreadHelper.cs b/src/Snap.Hutao/Snap.Hutao/Core/Threading/ThreadHelper.cs index 3090c0ca7f..29b38d965b 100644 --- a/src/Snap.Hutao/Snap.Hutao/Core/Threading/ThreadHelper.cs +++ b/src/Snap.Hutao/Snap.Hutao/Core/Threading/ThreadHelper.cs @@ -9,8 +9,9 @@ namespace Snap.Hutao.Core.Threading; internal static class ThreadHelper { /// - /// 异步切换到主线程 + /// 使用此静态方法以 异步切换到 主线程 /// + /// 使用 异步切换到 后台线程 /// 等待体 public static DispatherQueueSwitchOperation SwitchToMainThreadAsync() { diff --git a/src/Snap.Hutao/Snap.Hutao/Model/Binding/Gacha/HistoryWish.cs b/src/Snap.Hutao/Snap.Hutao/Model/Binding/Gacha/HistoryWish.cs index ec094ad690..2b55acd4f9 100644 --- a/src/Snap.Hutao/Snap.Hutao/Model/Binding/Gacha/HistoryWish.cs +++ b/src/Snap.Hutao/Snap.Hutao/Model/Binding/Gacha/HistoryWish.cs @@ -13,7 +13,12 @@ public class HistoryWish : WishBase /// /// 版本 /// - public string Version { get; set; } + public string Version { get; set; } = default!; + + /// + /// 卡池图片 + /// + public Uri BannerImage { get; set; } = default!; /// /// 五星Up diff --git a/src/Snap.Hutao/Snap.Hutao/Model/Binding/LaunchGame/LaunchScheme.cs b/src/Snap.Hutao/Snap.Hutao/Model/Binding/LaunchGame/LaunchScheme.cs new file mode 100644 index 0000000000..4a29e9b934 --- /dev/null +++ b/src/Snap.Hutao/Snap.Hutao/Model/Binding/LaunchGame/LaunchScheme.cs @@ -0,0 +1,42 @@ +// Copyright (c) DGP Studio. All rights reserved. +// Licensed under the MIT license. + +namespace Snap.Hutao.Model.Binding.LaunchGame; + +/// +/// 服务器方案 +/// +/// +/// 启动方案 +/// +public class LaunchScheme +{ + /// + /// 构造一个新的启动方案 + /// + /// 名称 + /// 通道 + /// 通道描述字符串 + /// 子通道 + public LaunchScheme(string name, string channel, string subChannel) + { + Name = name; + Channel = channel; + SubChannel = subChannel; + } + + /// + /// 名称 + /// + public string Name { get; set; } + + /// + /// 通道 + /// + public string Channel { get; set; } + + /// + /// 子通道 + /// + public string SubChannel { get; set; } +} \ No newline at end of file diff --git a/src/Snap.Hutao/Snap.Hutao/Model/Binding/LaunchGame/SchemeType.cs b/src/Snap.Hutao/Snap.Hutao/Model/Binding/LaunchGame/SchemeType.cs new file mode 100644 index 0000000000..8e2a66d139 --- /dev/null +++ b/src/Snap.Hutao/Snap.Hutao/Model/Binding/LaunchGame/SchemeType.cs @@ -0,0 +1,25 @@ +// Copyright (c) DGP Studio. All rights reserved. +// Licensed under the MIT license. + +namespace Snap.Hutao.Model.Binding.LaunchGame; + +/// +/// 启动类型 +/// +public enum SchemeType +{ + /// + /// 国际服 + /// + Mihoyo, + + /// + /// 国服官服 + /// + Officical, + + /// + /// 渠道服 + /// + Bilibili, +} \ No newline at end of file diff --git a/src/Snap.Hutao/Snap.Hutao/Model/Entity/GameAccount.cs b/src/Snap.Hutao/Snap.Hutao/Model/Entity/GameAccount.cs new file mode 100644 index 0000000000..97fe2ed76c --- /dev/null +++ b/src/Snap.Hutao/Snap.Hutao/Model/Entity/GameAccount.cs @@ -0,0 +1,47 @@ +// Copyright (c) DGP Studio. All rights reserved. +// Licensed under the MIT license. + +using Snap.Hutao.Core.Database; +using Snap.Hutao.Model.Binding.LaunchGame; +using Snap.Hutao.Web.Hoyolab; +using System.ComponentModel.DataAnnotations; +using System.ComponentModel.DataAnnotations.Schema; + +namespace Snap.Hutao.Model.Entity; + +/// +/// 游戏内账号 +/// +[Table("game_accounts")] +public class GameAccount : ISelectable +{ + /// + /// 内部Id + /// + [Key] + [DatabaseGenerated(DatabaseGeneratedOption.Identity)] + public Guid InnerId { get; set; } + + /// + public bool IsSelected { get; set; } + + /// + /// 对应的Uid + /// + public string? AttachUid { get; set; } + + /// + /// 服务器类型 + /// + public SchemeType Type { get; set; } + + /// + /// 名称 + /// + public string Name { get; set; } = default!; + + /// + /// MIHOYOSDK_ADL_PROD_CN_h3123967166 + /// + public string MihoyoSDK { get; set; } = default!; +} \ No newline at end of file diff --git a/src/Snap.Hutao/Snap.Hutao/Model/Entity/User.cs b/src/Snap.Hutao/Snap.Hutao/Model/Entity/User.cs index ca000fda1a..24cc09559a 100644 --- a/src/Snap.Hutao/Snap.Hutao/Model/Entity/User.cs +++ b/src/Snap.Hutao/Snap.Hutao/Model/Entity/User.cs @@ -40,4 +40,4 @@ public static User Create(Cookie cookie) { return new() { Cookie = cookie }; } -} +} \ No newline at end of file diff --git a/src/Snap.Hutao/Snap.Hutao/Model/Metadata/GachaEvent.cs b/src/Snap.Hutao/Snap.Hutao/Model/Metadata/GachaEvent.cs index 345cb15db6..3440e005bc 100644 --- a/src/Snap.Hutao/Snap.Hutao/Model/Metadata/GachaEvent.cs +++ b/src/Snap.Hutao/Snap.Hutao/Model/Metadata/GachaEvent.cs @@ -20,6 +20,11 @@ public class GachaEvent /// public string Version { get; set; } = default!; + /// + /// 卡池图 + /// + public Uri Banner { get; set; } = default!; + /// /// 开始时间 /// diff --git a/src/Snap.Hutao/Snap.Hutao/Model/NamedValue.cs b/src/Snap.Hutao/Snap.Hutao/Model/NamedValue.cs new file mode 100644 index 0000000000..490d5cb530 --- /dev/null +++ b/src/Snap.Hutao/Snap.Hutao/Model/NamedValue.cs @@ -0,0 +1,35 @@ +// Copyright (c) DGP Studio. All rights reserved. +// Licensed under the MIT license. + +using CommunityToolkit.Mvvm.ComponentModel; + +namespace Snap.Hutao.Model; + +/// +/// 封装带有名称描述的值 +/// 在绑定枚举变量时非常有用 +/// +/// 包含值的类型 +public class NamedValue +{ + /// + /// 构造一个新的命名的值 + /// + /// 命名 + /// 值 + public NamedValue(string name, T value) + { + Name = name; + Value = value; + } + + /// + /// 名称 + /// + public string Name { get; } + + /// + /// 值 + /// + public T Value { get; } +} \ No newline at end of file diff --git a/src/Snap.Hutao/Snap.Hutao/Model/Selectable.cs b/src/Snap.Hutao/Snap.Hutao/Model/Selectable.cs index a3c12bfaf6..1614749f17 100644 --- a/src/Snap.Hutao/Snap.Hutao/Model/Selectable.cs +++ b/src/Snap.Hutao/Snap.Hutao/Model/Selectable.cs @@ -46,4 +46,4 @@ public bool IsSelected /// 存放的对象 /// public T Value { get => value; set => SetProperty(ref this.value, value); } -} +} \ No newline at end of file diff --git a/src/Snap.Hutao/Snap.Hutao/Service/GachaLog/Factory/HistoryWishBuilder.cs b/src/Snap.Hutao/Snap.Hutao/Service/GachaLog/Factory/HistoryWishBuilder.cs index 2f2e51dd69..492f125c93 100644 --- a/src/Snap.Hutao/Snap.Hutao/Service/GachaLog/Factory/HistoryWishBuilder.cs +++ b/src/Snap.Hutao/Snap.Hutao/Service/GachaLog/Factory/HistoryWishBuilder.cs @@ -148,6 +148,7 @@ public HistoryWish ToHistoryWish() // fill Version = gachaEvent.Version, + BannerImage = gachaEvent.Banner, OrangeUpList = orangeUpCounter.ToStatisticsList(), PurpleUpList = purpleUpCounter.ToStatisticsList(), OrangeList = orangeCounter.ToStatisticsList(), diff --git a/src/Snap.Hutao/Snap.Hutao/Service/Game/GameService.cs b/src/Snap.Hutao/Snap.Hutao/Service/Game/GameService.cs index e5ef503f0b..722e2eb2f7 100644 --- a/src/Snap.Hutao/Snap.Hutao/Service/Game/GameService.cs +++ b/src/Snap.Hutao/Snap.Hutao/Service/Game/GameService.cs @@ -6,10 +6,12 @@ using Snap.Hutao.Context.Database; using Snap.Hutao.Core; using Snap.Hutao.Core.Database; +using Snap.Hutao.Core.IO.Ini; using Snap.Hutao.Core.Threading; using Snap.Hutao.Model.Entity; using Snap.Hutao.Service.Game.Locator; using Snap.Hutao.Service.Game.Unlocker; +using System.Collections.ObjectModel; using System.Diagnostics; using System.IO; @@ -27,6 +29,8 @@ internal class GameService : IGameService private readonly IMemoryCache memoryCache; private readonly SemaphoreSlim gameSemaphore = new(1); + private ObservableCollection? gameAccounts; + /// /// 构造一个新的游戏服务 /// @@ -129,51 +133,77 @@ public void OverwriteGamePath(string path) } /// - public async ValueTask LaunchAsync(LaunchConfiguration configuration) + public MultiChannel GetMultiChannel() { - (bool isOk, string gamePath) = await GetGamePathAsync().ConfigureAwait(false); + string gamePath = GetGamePathSkipLocator(); + string configPath = Path.Combine(gamePath, "config.ini"); - if (isOk) + using (FileStream stream = File.OpenRead(configPath)) { - if (gameSemaphore.CurrentCount == 0) - { - return; - } + List elements = IniSerializer.Deserialize(stream).ToList(); + string? channel = elements.OfType().FirstOrDefault(p => p.Key == "channel")?.Value; + string? subChannel = elements.OfType().FirstOrDefault(p => p.Key == "sub_channel")?.Value; + + return new(channel, subChannel); + } + } + + public async Task> GetGameAccountCollectionAsync() + { + if (gameAccounts == null) + { + + } + + return gameAccounts; + } + + /// + public async ValueTask LaunchAsync(LaunchConfiguration configuration) + { + if (gameSemaphore.CurrentCount == 0) + { + return; + } + + string gamePath = GetGamePathSkipLocator(); - string commandLine = new CommandLineBuilder() - .Append("-window-mode", configuration.WindowMode) - .Append("-screen-fullscreen", configuration.IsFullScreen ? 1 : 0) - .Append("-screen-width", configuration.ScreenWidth) - .Append("-screen-height", configuration.ScreenHeight) - .Append("-monitor", configuration.Monitor) - .Build(); + string commandLine = new CommandLineBuilder() + .AppendIf("-popupwindow", configuration.IsBorderless) + .Append("-screen-fullscreen", configuration.IsFullScreen ? 1 : 0) + .Append("-screen-width", configuration.ScreenWidth) + .Append("-screen-height", configuration.ScreenHeight) + .Append("-monitor", configuration.Monitor) + .Build(); - Process game = new() + Process game = new() + { + StartInfo = new() { - StartInfo = new() - { - Arguments = commandLine, - FileName = gamePath, - UseShellExecute = true, - Verb = "runas", - WorkingDirectory = Path.GetDirectoryName(gamePath), - }, - }; - - using (await gameSemaphore.EnterAsync().ConfigureAwait(false)) + Arguments = commandLine, + FileName = gamePath, + UseShellExecute = true, + Verb = "runas", + WorkingDirectory = Path.GetDirectoryName(gamePath), + }, + }; + + using (await gameSemaphore.EnterAsync().ConfigureAwait(false)) + { + if (configuration.UnlockFPS) { - if (configuration.UnlockFPS) - { - IGameFpsUnlocker unlocker = new GameFpsUnlocker(game, configuration.TargetFPS); + IGameFpsUnlocker unlocker = new GameFpsUnlocker(game, configuration.TargetFPS); - await unlocker.UnlockAsync(TimeSpan.FromMilliseconds(100), TimeSpan.FromMilliseconds(10000), TimeSpan.FromMilliseconds(2000)).ConfigureAwait(false); - } - else + TimeSpan findModuleDelay = TimeSpan.FromMilliseconds(100); + TimeSpan findModuleLimit = TimeSpan.FromMilliseconds(10000); + TimeSpan adjustFpsDelay = TimeSpan.FromMilliseconds(2000); + await unlocker.UnlockAsync(findModuleDelay, findModuleLimit, adjustFpsDelay).ConfigureAwait(false); + } + else + { + if (game.Start()) { - if (game.Start()) - { - await game.WaitForExitAsync().ConfigureAwait(false); - } + await game.WaitForExitAsync().ConfigureAwait(false); } } } diff --git a/src/Snap.Hutao/Snap.Hutao/Service/Game/IGameService.cs b/src/Snap.Hutao/Snap.Hutao/Service/Game/IGameService.cs index 966aed6c62..1302009170 100644 --- a/src/Snap.Hutao/Snap.Hutao/Service/Game/IGameService.cs +++ b/src/Snap.Hutao/Snap.Hutao/Service/Game/IGameService.cs @@ -22,6 +22,12 @@ internal interface IGameService /// 游戏路径,当路径无效时会设置并返回 string GetGamePathSkipLocator(); + /// + /// 获取多通道值 + /// + /// 多通道值 + MultiChannel GetMultiChannel(); + /// /// 异步启动 /// diff --git a/src/Snap.Hutao/Snap.Hutao/Service/Game/LaunchConfiguration.cs b/src/Snap.Hutao/Snap.Hutao/Service/Game/LaunchConfiguration.cs index d28923b1db..9c62a35945 100644 --- a/src/Snap.Hutao/Snap.Hutao/Service/Game/LaunchConfiguration.cs +++ b/src/Snap.Hutao/Snap.Hutao/Service/Game/LaunchConfiguration.cs @@ -14,9 +14,9 @@ internal struct LaunchConfiguration public bool IsFullScreen { get; set; } /// - /// Override fullscreen windowed mode. Accepted values are exclusive or borderless. + /// 是否为无边框窗口 /// - public string WindowMode { get; private set; } + public bool IsBorderless { get; private set; } /// /// 是否启用解锁帧率 diff --git a/src/Snap.Hutao/Snap.Hutao/Service/Game/MultiChannel.cs b/src/Snap.Hutao/Snap.Hutao/Service/Game/MultiChannel.cs new file mode 100644 index 0000000000..b50a2c3f29 --- /dev/null +++ b/src/Snap.Hutao/Snap.Hutao/Service/Game/MultiChannel.cs @@ -0,0 +1,31 @@ +// Copyright (c) DGP Studio. All rights reserved. +// Licensed under the MIT license. + +namespace Snap.Hutao.Service.Game; + +/// +/// 多通道 +/// +public struct MultiChannel +{ + /// + /// 通道 + /// + public string Channel; + + /// + /// 子通道 + /// + public string SubChannel; + + /// + /// 构造一个新的多通道 + /// + /// 通道 + /// 子通道 + public MultiChannel(string? channel, string? subChannel) + { + Channel = channel ?? string.Empty; + SubChannel = subChannel ?? string.Empty; + } +} \ No newline at end of file diff --git a/src/Snap.Hutao/Snap.Hutao/Service/Navigation/INavigationService.cs b/src/Snap.Hutao/Snap.Hutao/Service/Navigation/INavigationService.cs index 19ae3f5811..d61470cb21 100644 --- a/src/Snap.Hutao/Snap.Hutao/Service/Navigation/INavigationService.cs +++ b/src/Snap.Hutao/Snap.Hutao/Service/Navigation/INavigationService.cs @@ -72,4 +72,9 @@ Task NavigateAsync(INavigationAwaiter data, bool syncNa /// 同步的页面类型 /// 是否同步成功 bool SyncSelectedNavigationViewItemWith(Type pageType); + + /// + /// 尽可能尝试返回 + /// + void GoBack(); } diff --git a/src/Snap.Hutao/Snap.Hutao/Service/Navigation/NavigationService.cs b/src/Snap.Hutao/Snap.Hutao/Service/Navigation/NavigationService.cs index 906507ce77..576a43c559 100644 --- a/src/Snap.Hutao/Snap.Hutao/Service/Navigation/NavigationService.cs +++ b/src/Snap.Hutao/Snap.Hutao/Service/Navigation/NavigationService.cs @@ -178,6 +178,18 @@ public void Initialize(NavigationView navigationView, Frame frame) NavigationView.IsPaneOpen = LocalSetting.Get(SettingKeys.IsNavPaneOpen, true); } + /// + public void GoBack() + { + bool canGoBack = Frame?.CanGoBack ?? false; + + if (canGoBack) + { + Frame!.GoBack(); + SyncSelectedNavigationViewItemWith(Frame.Content.GetType()); + } + } + /// /// 遍历所有子菜单项 /// diff --git a/src/Snap.Hutao/Snap.Hutao/Service/User/UserService.cs b/src/Snap.Hutao/Snap.Hutao/Service/User/UserService.cs index 44931981ce..ac245f8924 100644 --- a/src/Snap.Hutao/Snap.Hutao/Service/User/UserService.cs +++ b/src/Snap.Hutao/Snap.Hutao/Service/User/UserService.cs @@ -2,7 +2,9 @@ // Licensed under the MIT license. using CommunityToolkit.Mvvm.Messaging; +using Microsoft.Extensions.DependencyInjection; using Snap.Hutao.Context.Database; +using Snap.Hutao.Core.Database; using Snap.Hutao.Core.Threading; using Snap.Hutao.Web.Hoyolab; using Snap.Hutao.Web.Hoyolab.Bbs.User; @@ -20,10 +22,7 @@ namespace Snap.Hutao.Service.User; [Injection(InjectAs.Singleton, typeof(IUserService))] internal class UserService : IUserService { - private readonly AppDbContext appDbContext; - private readonly UserClient userClient; - private readonly BindingClient bindingClient; - private readonly AuthClient authClient; + private readonly IServiceScopeFactory scopeFactory; private readonly IMessenger messenger; private BindingUser? currentUser; @@ -32,22 +31,11 @@ internal class UserService : IUserService /// /// 构造一个新的用户服务 /// - /// 应用程序数据库上下文 - /// 用户客户端 - /// 角色客户端 - /// 验证客户端 + /// 范围工厂 /// 消息器 - public UserService( - AppDbContext appDbContext, - UserClient userClient, - BindingClient bindingClient, - AuthClient authClient, - IMessenger messenger) + public UserService(IServiceScopeFactory scopeFactory, IMessenger messenger) { - this.appDbContext = appDbContext; - this.userClient = userClient; - this.bindingClient = bindingClient; - this.authClient = authClient; + this.scopeFactory = scopeFactory; this.messenger = messenger; } @@ -62,44 +50,54 @@ public BindingUser? Current return; } - // only update when not processing a deletion - if (value != null) + using (IServiceScope scope = scopeFactory.CreateScope()) { + AppDbContext appDbContext = scope.ServiceProvider.GetRequiredService(); + + // only update when not processing a deletion + if (value != null) + { + if (currentUser != null) + { + currentUser.IsSelected = false; + appDbContext.Users.Update(currentUser.Entity); + appDbContext.SaveChanges(); + } + } + + Message.UserChangedMessage message = new() { OldValue = currentUser, NewValue = value }; + + // 当删除到无用户时也能正常反应状态 + currentUser = value; + if (currentUser != null) { - currentUser.IsSelected = false; + currentUser.IsSelected = true; appDbContext.Users.Update(currentUser.Entity); appDbContext.SaveChanges(); } - } - Message.UserChangedMessage message = new() { OldValue = currentUser, NewValue = value }; - - // 当删除到无用户时也能正常反应状态 - currentUser = value; - - if (currentUser != null) - { - currentUser.IsSelected = true; - appDbContext.Users.Update(currentUser.Entity); - appDbContext.SaveChanges(); + messenger.Send(message); } - - messenger.Send(message); } } /// - public Task RemoveUserAsync(BindingUser user) + public async Task RemoveUserAsync(BindingUser user) { + await Task.Yield(); Must.NotNull(userCollection!); // Sync cache userCollection.Remove(user); // Sync database - appDbContext.Users.Remove(user.Entity); - return appDbContext.SaveChangesAsync(); + using (IServiceScope scope = scopeFactory.CreateScope()) + { + AppDbContext appDbContext = scope.ServiceProvider.GetRequiredService(); + + appDbContext.Users.RemoveAndSave(user.Entity); + } } /// @@ -109,21 +107,27 @@ public async Task> GetUserCollectionAsync() { List users = new(); - foreach (Model.Entity.User entity in appDbContext.Users) + using (IServiceScope scope = scopeFactory.CreateScope()) { - BindingUser? initialized = await BindingUser - .ResumeAsync(entity, userClient, bindingClient) - .ConfigureAwait(false); + AppDbContext appDbContext = scope.ServiceProvider.GetRequiredService(); + UserClient userClient = scope.ServiceProvider.GetRequiredService(); + BindingClient bindingClient = scope.ServiceProvider.GetRequiredService(); - if (initialized != null) + foreach (Model.Entity.User entity in appDbContext.Users) { - users.Add(initialized); - } - else - { - // User is unable to be initialized, remove it. - appDbContext.Users.Remove(entity); - await appDbContext.SaveChangesAsync().ConfigureAwait(false); + BindingUser? initialized = await BindingUser + .ResumeAsync(entity, userClient, bindingClient) + .ConfigureAwait(false); + + if (initialized != null) + { + users.Add(initialized); + } + else + { + // User is unable to be initialized, remove it. + appDbContext.Users.RemoveAndSave(entity); + } } } @@ -150,24 +154,27 @@ public async Task> ProcessInputCookieAsync // 检查 uid 对应用户是否存在 if (UserHelper.TryGetUserByUid(userCollection, uid, out BindingUser? userWithSameUid)) { - // 检查 stoken 是否存在 - if (cookie.ContainsSToken()) + using (IServiceScope scope = scopeFactory.CreateScope()) { - // insert stoken - userWithSameUid.UpdateSToken(uid, cookie); - appDbContext.Users.Update(userWithSameUid.Entity); - appDbContext.SaveChanges(); + AppDbContext appDbContext = scope.ServiceProvider.GetRequiredService(); - return new(UserOptionResult.Upgraded, uid); - } + // 检查 stoken 是否存在 + if (cookie.ContainsSToken()) + { + // insert stoken + userWithSameUid.UpdateSToken(uid, cookie); + appDbContext.Users.UpdateAndSave(userWithSameUid.Entity); - if (cookie.ContainsLTokenAndCookieToken()) - { - userWithSameUid.Cookie = cookie; - appDbContext.Users.Update(userWithSameUid.Entity); - appDbContext.SaveChanges(); + return new(UserOptionResult.Upgraded, uid); + } + + if (cookie.ContainsLTokenAndCookieToken()) + { + userWithSameUid.Cookie = cookie; + appDbContext.Users.UpdateAndSave(userWithSameUid.Entity); - return new(UserOptionResult.Updated, uid); + return new(UserOptionResult.Updated, uid); + } } } else if (cookie.ContainsLTokenAndCookieToken()) @@ -184,7 +191,8 @@ private async Task TryAddMultiTokenAsync(Cookie cookie, string uid) if (cookie.TryGetLoginTicket(out string? loginTicket)) { // get multitoken - Dictionary multiToken = await authClient + Dictionary multiToken = await Ioc.Default + .GetRequiredService() .GetMultiTokenByLoginTicketAsync(loginTicket, uid, default) .ConfigureAwait(false); @@ -198,22 +206,27 @@ private async Task TryAddMultiTokenAsync(Cookie cookie, string uid) private async Task> TryCreateUserAndAddAsync(ObservableCollection users, Cookie cookie) { - BindingUser? newUser = await BindingUser.CreateAsync(cookie, userClient, bindingClient).ConfigureAwait(false); - if (newUser != null) + using (IServiceScope scope = scopeFactory.CreateScope()) { - // Sync cache - await ThreadHelper.SwitchToMainThreadAsync(); - users.Add(newUser); + AppDbContext appDbContext = scope.ServiceProvider.GetRequiredService(); + UserClient userClient = scope.ServiceProvider.GetRequiredService(); + BindingClient bindingClient = scope.ServiceProvider.GetRequiredService(); - // Sync database - appDbContext.Users.Add(newUser.Entity); - await appDbContext.SaveChangesAsync().ConfigureAwait(false); + BindingUser? newUser = await BindingUser.CreateAsync(cookie, userClient, bindingClient).ConfigureAwait(false); + if (newUser != null) + { + // Sync cache + await ThreadHelper.SwitchToMainThreadAsync(); + users.Add(newUser); - return new(UserOptionResult.Added, newUser.UserInfo!.Uid); - } - else - { - return new(UserOptionResult.Invalid, null!); + // Sync database + appDbContext.Users.AddAndSave(newUser.Entity); + return new(UserOptionResult.Added, newUser.UserInfo!.Uid); + } + else + { + return new(UserOptionResult.Invalid, null!); + } } } } \ No newline at end of file diff --git a/src/Snap.Hutao/Snap.Hutao/Snap.Hutao.csproj b/src/Snap.Hutao/Snap.Hutao/Snap.Hutao.csproj index 4558210a55..05b1ee5862 100644 --- a/src/Snap.Hutao/Snap.Hutao/Snap.Hutao.csproj +++ b/src/Snap.Hutao/Snap.Hutao/Snap.Hutao.csproj @@ -70,6 +70,8 @@ + + @@ -148,6 +150,16 @@ + + + MSBuild:Compile + + + + + MSBuild:Compile + + MSBuild:Compile diff --git a/src/Snap.Hutao/Snap.Hutao/View/Control/StatisticsCard.xaml b/src/Snap.Hutao/Snap.Hutao/View/Control/StatisticsCard.xaml index 730cb2eedb..de6d74cb36 100644 --- a/src/Snap.Hutao/Snap.Hutao/View/Control/StatisticsCard.xaml +++ b/src/Snap.Hutao/Snap.Hutao/View/Control/StatisticsCard.xaml @@ -138,7 +138,8 @@ Style="{StaticResource SubtitleTextBlockStyle}"/> - diff --git a/src/Snap.Hutao/Snap.Hutao/View/Page/GachaLogPage.xaml b/src/Snap.Hutao/Snap.Hutao/View/Page/GachaLogPage.xaml index 548c31d23a..a268a9682f 100644 --- a/src/Snap.Hutao/Snap.Hutao/View/Page/GachaLogPage.xaml +++ b/src/Snap.Hutao/Snap.Hutao/View/Page/GachaLogPage.xaml @@ -241,8 +241,20 @@ + + + + + diff --git a/src/Snap.Hutao/Snap.Hutao/View/Page/LaunchGamePage.xaml b/src/Snap.Hutao/Snap.Hutao/View/Page/LaunchGamePage.xaml index 2d400f9edd..de97920b9a 100644 --- a/src/Snap.Hutao/Snap.Hutao/View/Page/LaunchGamePage.xaml +++ b/src/Snap.Hutao/Snap.Hutao/View/Page/LaunchGamePage.xaml @@ -21,7 +21,7 @@ - + @@ -37,6 +37,36 @@ + + + + + + + + + + + + +