This commit is contained in:
DismissedLight
2022-08-18 16:53:31 +08:00
parent 641a731a4d
commit 9c70105c61
25 changed files with 374 additions and 169 deletions

View File

@@ -1,4 +1,16 @@
# Snap.Hutao
唷,找本堂主有何贵干呀?
> 唷,找本堂主有何贵干呀?
![Alt](https://repobeats.axiom.co/api/embed/f029553fbe0c60689b1710476ec8512452163fc9.svg "Repobeats analytics image")
## 感谢以下项目或人员的帮助
* [CommunityToolkit/dotnet](https://github.com/CommunityToolkit/dotnet)
* [CommunityToolkit/WindowsCommunityToolkit](https://github.com/CommunityToolkit/WindowsCommunityToolkit)
* [dotnet/efcore](https://github.com/dotnet/efcore)
* [dotnet/runtime](https://github.com/dotnet/runtime)
* [DotNetAnalyzers/StyleCopAnalyzers](https://github.com/DotNetAnalyzers/StyleCopAnalyzers)
* [microsoft/vs-threading](https://github.com/microsoft/vs-threading)
* [microsoft/vs-validation](https://github.com/microsoft/vs-validation)
* [microsoft/WindowsAppSDK](https://github.com/microsoft/WindowsAppSDK)
* [microsoft/microsoft-ui-xaml](https://github.com/microsoft/microsoft-ui-xaml)

View File

@@ -8,7 +8,6 @@ using Microsoft.Windows.AppLifecycle;
using Snap.Hutao.Core.LifeCycle;
using Snap.Hutao.Core.Logging;
using Snap.Hutao.Extension;
using Snap.Hutao.Service.Abstraction;
using Snap.Hutao.Service.Metadata;
using System.Diagnostics;
using Windows.Storage;
@@ -23,7 +22,6 @@ public partial class App : Application
{
private static Window? window;
private readonly ILogger<App> logger;
private readonly ExceptionRecorder exceptionRecorder;
/// <summary>
/// Initializes the singleton application object.
@@ -38,7 +36,7 @@ public partial class App : Application
// so we can use Ioc here.
logger = Ioc.Default.GetRequiredService<ILogger<App>>();
exceptionRecorder = new(this, logger);
_ = new ExceptionRecorder(this, logger);
}
/// <summary>
@@ -73,8 +71,8 @@ public partial class App : Application
if (firstInstance.IsCurrent)
{
OnActivated(firstInstance, activatedEventArgs);
firstInstance.Activated += OnActivated;
Activation.Activate(firstInstance, activatedEventArgs);
firstInstance.Activated += Activation.Activate;
logger.LogInformation(EventIds.CommonLog, "Cache folder : {folder}", CacheFolder.Path);
@@ -116,21 +114,4 @@ public partial class App : Application
Ioc.Default.ConfigureServices(services);
}
[SuppressMessage("", "VSTHRD100")]
private async void OnActivated(object? sender, AppActivationArguments args)
{
Window = Ioc.Default.GetRequiredService<MainWindow>();
IInfoBarService infoBarService = Ioc.Default.GetRequiredService<IInfoBarService>();
await infoBarService.WaitInitializationAsync();
if (args.Kind == ExtendedActivationKind.Protocol)
{
if (args.TryGetProtocolActivatedUri(out Uri? uri))
{
infoBarService.Information(uri.ToString());
}
}
}
}

View File

@@ -1,8 +1,6 @@
// Copyright (c) DGP Studio. All rights reserved.
// Licensed under the MIT license.
using Microsoft.Win32;
using Snap.Hutao.Core.Convert;
using Snap.Hutao.Extension;
using Windows.ApplicationModel;
@@ -39,35 +37,17 @@ internal static class CoreEnvironment
/// </summary>
public static readonly Version Version;
/// <summary>
/// 设备Id
/// </summary>
public static readonly string DeviceId;
/// <summary>
/// 米游社设备Id
/// </summary>
public static readonly string HoyolabDeviceId;
private const string CryptographyKey = @"HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Cryptography";
private const string MachineGuidValue = "MachineGuid";
static CoreEnvironment()
{
Version = Package.Current.Id.Version.ToVersion();
CommonUA = $"Snap Hutao/{Version}";
DeviceId = GetDeviceId();
// simply assign a random guid
HoyolabDeviceId = Guid.NewGuid().ToString();
}
/// <summary>
/// 获取设备的UUID
/// </summary>
/// <returns>设备的UUID</returns>
private static string GetDeviceId()
{
string userName = Environment.UserName;
object? machineGuid = Registry.GetValue(CryptographyKey, MachineGuidValue, userName);
return Md5Convert.ToHexString($"{userName}{machineGuid}");
}
}

View File

@@ -0,0 +1,75 @@
// Copyright (c) DGP Studio. All rights reserved.
// Licensed under the MIT license.
using CommunityToolkit.Mvvm.Messaging;
using Microsoft.EntityFrameworkCore;
namespace Snap.Hutao.Core.Database;
/// <summary>
/// 数据库当前项
/// </summary>
/// <typeparam name="TEntity">实体的类型</typeparam>
/// <typeparam name="TMessage">消息的类型</typeparam>
internal class DbCurrent<TEntity, TMessage>
where TEntity : class, ISelectable
where TMessage : Message.ValueChangedMessage<TEntity>
{
private readonly DbContext dbContext;
private readonly DbSet<TEntity> dbSet;
private readonly IMessenger messenger;
private TEntity? current;
/// <summary>
/// 构造一个新的数据库当前项
/// </summary>
/// <param name="dbContext">数据库上下文</param>
/// <param name="dbSet">数据集</param>
/// <param name="messenger">消息器</param>
public DbCurrent(DbContext dbContext, DbSet<TEntity> dbSet, IMessenger messenger)
{
this.dbContext = dbContext;
this.dbSet = dbSet;
this.messenger = messenger;
}
/// <summary>
/// 当前项
/// </summary>
public TEntity? Current
{
get => current;
set
{
// prevent useless sets
if (current == value)
{
return;
}
// only update when not processing a deletion
if (value != null)
{
if (current != null)
{
current.IsSelected = false;
dbSet.Update(current);
dbContext.SaveChanges();
}
}
TMessage message = (TMessage)Activator.CreateInstance(typeof(TMessage), current, value)!;
current = value;
if (current != null)
{
current.IsSelected = true;
dbSet.Update(current);
dbContext.SaveChanges();
}
messenger.Send(message);
}
}
}

View File

@@ -0,0 +1,15 @@
// Copyright (c) DGP Studio. All rights reserved.
// Licensed under the MIT license.
namespace Snap.Hutao.Core.Database;
/// <summary>
/// 可选择的项
/// </summary>
public interface ISelectable
{
/// <summary>
/// 获取或设置当前项的选中状态
/// </summary>
bool IsSelected { get; set; }
}

View File

@@ -2,15 +2,6 @@
// Licensed under the MIT license.
using Microsoft.Extensions.DependencyInjection;
using Snap.Hutao.Core.Caching;
using Snap.Hutao.Service.Metadata;
using Snap.Hutao.Web.Enka;
using Snap.Hutao.Web.Hoyolab.Bbs.User;
using Snap.Hutao.Web.Hoyolab.Hk4e.Common.Announcement;
using Snap.Hutao.Web.Hoyolab.Takumi.Binding;
using Snap.Hutao.Web.Hoyolab.Takumi.Event.BbsSignReward;
using Snap.Hutao.Web.Hoyolab.Takumi.GameRecord;
using Snap.Hutao.Web.Hutao;
using System.Net.Http;
namespace Snap.Hutao.Core.DependencyInjection;

View File

@@ -0,0 +1,108 @@
// Copyright (c) DGP Studio. All rights reserved.
// Licensed under the MIT license.
using CommunityToolkit.WinUI;
using Microsoft.Windows.AppLifecycle;
using Snap.Hutao.Extension;
using Snap.Hutao.Service.Abstraction;
using Snap.Hutao.Service.Navigation;
namespace Snap.Hutao.Core.LifeCycle;
/// <summary>
/// 激活处理器
/// </summary>
internal static class Activation
{
public static volatile bool isActivating = false;
public static object activationLock = new object();
/// <summary>
/// 响应激活事件
/// </summary>
/// <param name="sender">发送方</param>
/// <param name="args">激活参数</param>
public static void Activate(object? sender, AppActivationArguments args)
{
HandleActivationAsync(args).SafeForget();
}
/// <summary>
/// 异步响应激活事件
/// </summary>
/// <returns>任务</returns>
private static async Task HandleActivationAsync(AppActivationArguments args)
{
if (isActivating)
{
lock (activationLock)
{
if (isActivating)
{
return;
}
}
}
lock (activationLock)
{
isActivating = true;
}
App.Window = Ioc.Default.GetRequiredService<MainWindow>();
IInfoBarService infoBarService = Ioc.Default.GetRequiredService<IInfoBarService>();
await infoBarService.WaitInitializationAsync();
if (args.Kind == ExtendedActivationKind.Protocol)
{
if (args.TryGetProtocolActivatedUri(out Uri? uri))
{
infoBarService.Information(uri.ToString());
await HandleUrlActivationAsync(uri);
}
}
lock (activationLock)
{
isActivating = false;
}
}
private static async Task HandleUrlActivationAsync(Uri uri)
{
UriBuilder builder = new(uri);
Requires.Argument(builder.Scheme == "hutao", nameof(uri), "uri 的协议不正确");
string category = builder.Host.ToLowerInvariant();
string action = builder.Path.ToLowerInvariant();
string rawParameter = builder.Query;
switch (category)
{
case "achievement":
{
await HandleAchievementActionAsync(action, rawParameter);
break;
}
}
}
private static async Task HandleAchievementActionAsync(string action, string parameter)
{
switch (action)
{
case "/import":
{
await Program.UIDispatcherQueue.EnqueueAsync(async () =>
{
INavigationAwaiter navigationAwaiter = new NavigationExtra("InvokeByUri");
await Ioc.Default
.GetRequiredService<INavigationService>()
.NavigateAsync<View.Page.AchievementPage>(navigationAwaiter, true);
});
break;
}
}
}
}

View File

@@ -23,7 +23,6 @@ internal static class EventIds
/// <summary>
/// 异步命令执行异常
/// </summary>
[Obsolete("异步命令不再通过Factory记录异常")]
public static readonly EventId AsyncCommandException = 100002;
/// <summary>

View File

@@ -56,5 +56,5 @@ public static class ThemeHelper
ElementTheme.Dark => SystemBackdropTheme.Dark,
_ => throw Must.NeverHappen(),
};
}
}
}

View File

@@ -11,7 +11,7 @@ namespace Snap.Hutao.Core;
/// 检测 WebView2运行时 是否存在
/// 不再使用注册表检查方式
/// </summary>
internal abstract class WebView2Helper
internal static class WebView2Helper
{
private static bool hasEverDetected = false;
private static bool isSupported = false;

View File

@@ -2,6 +2,7 @@
// Licensed under the MIT license.
using CommunityToolkit.Mvvm.Input;
using Snap.Hutao.Core.Logging;
using Snap.Hutao.Factory.Abstraction;
namespace Snap.Hutao.Factory;
@@ -10,51 +11,92 @@ namespace Snap.Hutao.Factory;
[Injection(InjectAs.Transient, typeof(IAsyncRelayCommandFactory))]
internal class AsyncRelayCommandFactory : IAsyncRelayCommandFactory
{
private readonly ILogger logger;
/// <summary>
/// 构造一个新的异步命令工厂
/// </summary>
/// <param name="logger">日志器</param>
public AsyncRelayCommandFactory(ILogger<AsyncRelayCommandFactory> logger)
{
this.logger = logger;
}
/// <inheritdoc/>
public AsyncRelayCommand<T> Create<T>(Func<T?, Task> execute)
{
return new AsyncRelayCommand<T>(execute, AsyncRelayCommandOptions.FlowExceptionsToTaskScheduler);
return Register(new AsyncRelayCommand<T>(execute));
}
/// <inheritdoc/>
public AsyncRelayCommand<T> Create<T>(Func<T?, CancellationToken, Task> cancelableExecute)
{
return new AsyncRelayCommand<T>(cancelableExecute, AsyncRelayCommandOptions.FlowExceptionsToTaskScheduler);
return Register(new AsyncRelayCommand<T>(cancelableExecute));
}
/// <inheritdoc/>
public AsyncRelayCommand<T> Create<T>(Func<T?, Task> execute, Predicate<T?> canExecute)
{
return new AsyncRelayCommand<T>(execute, canExecute, AsyncRelayCommandOptions.FlowExceptionsToTaskScheduler);
return Register(new AsyncRelayCommand<T>(execute, canExecute));
}
/// <inheritdoc/>
public AsyncRelayCommand<T> Create<T>(Func<T?, CancellationToken, Task> cancelableExecute, Predicate<T?> canExecute)
{
return new AsyncRelayCommand<T>(cancelableExecute, canExecute, AsyncRelayCommandOptions.FlowExceptionsToTaskScheduler);
return Register(new AsyncRelayCommand<T>(cancelableExecute, canExecute));
}
/// <inheritdoc/>
public AsyncRelayCommand Create(Func<Task> execute)
{
return new AsyncRelayCommand(execute, AsyncRelayCommandOptions.FlowExceptionsToTaskScheduler);
return Register(new AsyncRelayCommand(execute));
}
/// <inheritdoc/>
public AsyncRelayCommand Create(Func<CancellationToken, Task> cancelableExecute)
{
return new AsyncRelayCommand(cancelableExecute, AsyncRelayCommandOptions.FlowExceptionsToTaskScheduler);
return Register(new AsyncRelayCommand(cancelableExecute));
}
/// <inheritdoc/>
public AsyncRelayCommand Create(Func<Task> execute, Func<bool> canExecute)
{
return new AsyncRelayCommand(execute, canExecute, AsyncRelayCommandOptions.FlowExceptionsToTaskScheduler);
return Register(new AsyncRelayCommand(execute, canExecute));
}
/// <inheritdoc/>
public AsyncRelayCommand Create(Func<CancellationToken, Task> cancelableExecute, Func<bool> canExecute)
{
return new AsyncRelayCommand(cancelableExecute, canExecute, AsyncRelayCommandOptions.FlowExceptionsToTaskScheduler);
return Register(new AsyncRelayCommand(cancelableExecute, canExecute));
}
private AsyncRelayCommand Register(AsyncRelayCommand command)
{
ReportException(command);
return command;
}
private AsyncRelayCommand<T> Register<T>(AsyncRelayCommand<T> command)
{
ReportException(command);
return command;
}
private void ReportException(IAsyncRelayCommand command)
{
command.PropertyChanged += (sender, args) =>
{
if (sender is IAsyncRelayCommand asyncRelayCommand)
{
if (args.PropertyName == nameof(AsyncRelayCommand.ExecutionTask))
{
if (asyncRelayCommand.ExecutionTask?.Exception is AggregateException exception)
{
Exception baseException = exception.GetBaseException();
logger.LogError(EventIds.AsyncCommandException, baseException, "{name} Exception", nameof(asyncRelayCommand));
}
}
}
};
}
}

View File

@@ -1,8 +1,6 @@
// Copyright (c) DGP Studio. All rights reserved.
// Licensed under the MIT license.
using Snap.Hutao.Model.Binding;
namespace Snap.Hutao.Message;
/// <summary>

View File

@@ -1,6 +1,7 @@
// Copyright (c) DGP Studio. All rights reserved.
// Licensed under the MIT license.
using Snap.Hutao.Core.Database;
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
@@ -10,7 +11,7 @@ namespace Snap.Hutao.Model.Entity;
/// 成就存档
/// </summary>
[Table("achievement_archives")]
public class AchievementArchive
public class AchievementArchive : ISelectable
{
/// <summary>
/// 内部Id

View File

@@ -1,6 +1,7 @@
// Copyright (c) DGP Studio. All rights reserved.
// Licensed under the MIT license.
using Snap.Hutao.Core.Database;
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
@@ -10,7 +11,7 @@ namespace Snap.Hutao.Model.Entity;
/// 用户
/// </summary>
[Table("users")]
public class User
public class User : ISelectable
{
/// <summary>
/// 内部Id

View File

@@ -9,7 +9,7 @@
<Identity
Name="7f0db578-026f-4e0b-a75b-d5d06bb0a74d"
Publisher="CN=DGP Studio"
Version="1.0.28.0" />
Version="1.0.29.0" />
<Properties>
<DisplayName>胡桃</DisplayName>

View File

@@ -3,6 +3,7 @@
using CommunityToolkit.Mvvm.Messaging;
using Snap.Hutao.Context.Database;
using Snap.Hutao.Core.Database;
using Snap.Hutao.Core.Diagnostics;
using Snap.Hutao.Core.Logging;
using Snap.Hutao.Model.InterChange.Achievement;
@@ -24,9 +25,8 @@ internal class AchievementService : IAchievementService
{
private readonly AppDbContext appDbContext;
private readonly ILogger<AchievementService> logger;
private readonly IMessenger messenger;
private readonly DbCurrent<EntityArchive, Message.AchievementArchiveChangedMessage> dbCurrent;
private EntityArchive? currentArchive;
private ObservableCollection<EntityArchive>? archiveCollection;
/// <summary>
@@ -39,44 +39,15 @@ internal class AchievementService : IAchievementService
{
this.appDbContext = appDbContext;
this.logger = logger;
this.messenger = messenger;
dbCurrent = new(appDbContext, appDbContext.AchievementArchives, messenger);
}
/// <inheritdoc/>
public EntityArchive? CurrentArchive
{
get => currentArchive;
set
{
if (currentArchive == value)
{
return;
}
// only update when not processing a deletion
if (value != null)
{
if (currentArchive != null)
{
currentArchive.IsSelected = false;
appDbContext.AchievementArchives.Update(currentArchive);
appDbContext.SaveChanges();
}
}
Message.AchievementArchiveChangedMessage message = new(currentArchive, value);
currentArchive = value;
if (currentArchive != null)
{
currentArchive.IsSelected = true;
appDbContext.AchievementArchives.Update(currentArchive);
appDbContext.SaveChanges();
}
messenger.Send(message);
}
get => dbCurrent.Current;
set => dbCurrent.Current = value;
}
/// <inheritdoc/>
@@ -85,6 +56,47 @@ internal class AchievementService : IAchievementService
return archiveCollection ??= new(appDbContext.AchievementArchives.ToList());
}
/// <inheritdoc/>
public Task RemoveArchiveAsync(EntityArchive archive)
{
Must.NotNull(archiveCollection!);
// Sync cache
archiveCollection.Remove(archive);
// Sync database
appDbContext.AchievementArchives.Remove(archive);
return appDbContext.SaveChangesAsync();
}
/// <inheritdoc/>
public async Task<ArchiveAddResult> TryAddArchiveAsync(EntityArchive newArchive)
{
if (string.IsNullOrEmpty(newArchive.Name))
{
return ArchiveAddResult.InvalidName;
}
Must.NotNull(archiveCollection!);
// 查找是否有相同的名称
if (archiveCollection.SingleOrDefault(a => a.Name == newArchive.Name) is EntityArchive userWithSameUid)
{
return ArchiveAddResult.AlreadyExists;
}
else
{
// Sync cache
archiveCollection.Add(newArchive);
// Sync database
appDbContext.AchievementArchives.Add(newArchive);
await appDbContext.SaveChangesAsync().ConfigureAwait(false);
return ArchiveAddResult.Added;
}
}
/// <inheritdoc/>
public List<BindingAchievement> GetAchievements(EntityArchive archive, IList<MetadataAchievement> metadata)
{
@@ -139,19 +151,6 @@ internal class AchievementService : IAchievementService
}
}
/// <inheritdoc/>
public Task RemoveArchiveAsync(EntityArchive archive)
{
Must.NotNull(archiveCollection!);
// Sync cache
archiveCollection.Remove(archive);
// Sync database
appDbContext.AchievementArchives.Remove(archive);
return appDbContext.SaveChangesAsync();
}
/// <inheritdoc/>
public void SaveAchievements(EntityArchive archive, IList<BindingAchievement> achievements)
{
@@ -170,34 +169,6 @@ internal class AchievementService : IAchievementService
logger.LogInformation(EventIds.Achievement, "Save achievements for [{name}] completed in {time}ms", name, time);
}
/// <inheritdoc/>
public async Task<ArchiveAddResult> TryAddArchiveAsync(EntityArchive newArchive)
{
if (string.IsNullOrEmpty(newArchive.Name))
{
return ArchiveAddResult.InvalidName;
}
Must.NotNull(archiveCollection!);
// 查找是否有相同的名称
if (archiveCollection.SingleOrDefault(a => a.Name == newArchive.Name) is EntityArchive userWithSameUid)
{
return ArchiveAddResult.AlreadyExists;
}
else
{
// Sync cache
archiveCollection.Add(newArchive);
// Sync database
appDbContext.AchievementArchives.Add(newArchive);
await appDbContext.SaveChangesAsync().ConfigureAwait(false);
return ArchiveAddResult.Added;
}
}
private ImportResult MergeAchievements(Guid archiveId, IOrderedEnumerable<UIAFItem> orederedUIAF, bool aggressive)
{
IOrderedQueryable<EntityAchievement> oldData = appDbContext.Achievements

View File

@@ -1,8 +1,6 @@
// Copyright (c) DGP Studio. All rights reserved.
// Licensed under the MIT license.
using Snap.Hutao.Core.Abstraction;
namespace Snap.Hutao.Service.Metadata;
/// <summary>

View File

@@ -0,0 +1,17 @@
// Copyright (c) DGP Studio. All rights reserved.
// Licensed under the MIT license.
namespace Snap.Hutao.Service.Navigation;
/// <summary>
/// 导航消息接收器
/// </summary>
public interface INavigationRecipient
{
/// <summary>
/// 异步接收消息
/// </summary>
/// <param name="data">导航数据</param>
/// <returns>接收处理结果是否成功</returns>
Task<bool> ReceiveAsync(INavigationData data);
}

View File

@@ -34,8 +34,8 @@ public sealed partial class AchievementImportDialog : ContentDialog
/// </summary>
public UIAF UIAF
{
get { return (UIAF)GetValue(UIAFProperty); }
set { SetValue(UIAFProperty, value); }
get => (UIAF)GetValue(UIAFProperty);
set => SetValue(UIAFProperty, value);
}
/// <summary>

View File

@@ -1,7 +1,6 @@
// Copyright (c) DGP Studio. All rights reserved.
// Licensed under the MIT license.
using Microsoft.UI.Xaml;
using Microsoft.UI.Xaml.Controls;
using Snap.Hutao.Core;
using Snap.Hutao.Core.Logging;

View File

@@ -1,7 +1,6 @@
// Copyright (c) DGP Studio. All rights reserved.
// Licensed under the MIT license.
using CommunityToolkit.Mvvm.Messaging;
using Microsoft.UI.Xaml.Navigation;
using Snap.Hutao.Control.Cancellable;
using Snap.Hutao.Service.Navigation;
@@ -24,12 +23,18 @@ public sealed partial class AchievementPage : CancellablePage
}
/// <inheritdoc/>
protected override void OnNavigatedTo(NavigationEventArgs e)
[SuppressMessage("", "VSTHRD100")]
protected override async void OnNavigatedTo(NavigationEventArgs e)
{
base.OnNavigatedTo(e);
if (e.Parameter is INavigationData extra)
{
if (extra.Data != null)
{
await ((INavigationRecipient)DataContext).ReceiveAsync(extra);
}
extra.NotifyNavigationCompleted();
}
}

View File

@@ -1,9 +1,7 @@
// Copyright (c) DGP Studio. All rights reserved.
// Licensed under the MIT license.
using Microsoft.UI.Xaml;
using Microsoft.UI.Xaml.Controls;
using Snap.Hutao.Core;
using Snap.Hutao.ViewModel;
namespace Snap.Hutao.View;

View File

@@ -15,6 +15,7 @@ using Snap.Hutao.Model.Metadata.Achievement;
using Snap.Hutao.Service.Abstraction;
using Snap.Hutao.Service.Achievement;
using Snap.Hutao.Service.Metadata;
using Snap.Hutao.Service.Navigation;
using Snap.Hutao.View.Dialog;
using System.Collections.Generic;
using System.Collections.ObjectModel;
@@ -34,6 +35,7 @@ namespace Snap.Hutao.ViewModel;
internal class AchievementViewModel
: ObservableObject,
ISupportCancellation,
INavigationRecipient,
IRecipient<AchievementArchiveChangedMessage>,
IRecipient<MainWindowClosedMessage>
{
@@ -43,6 +45,8 @@ internal class AchievementViewModel
private readonly JsonSerializerOptions options;
private readonly IPickerFactory pickerFactory;
private readonly TaskCompletionSource<bool> openUICompletionSource = new();
private AdvancedCollectionView? achievements;
private IList<AchievementGoal>? achievementGoals;
private AchievementGoal? selectedAchievementGoal;
@@ -190,6 +194,21 @@ internal class AchievementViewModel
}
}
/// <inheritdoc/>
public async Task<bool> ReceiveAsync(INavigationData data)
{
if (await openUICompletionSource.Task)
{
if (data.Data is "InvokeByUri")
{
await ImportUIAFFromClipboardAsync();
return true;
}
}
return false;
}
private async Task HandleArchiveChangeAsync(Model.Entity.AchievementArchive? oldArchieve, Model.Entity.AchievementArchive? newArchieve)
{
if (oldArchieve != null && Achievements != null)
@@ -209,7 +228,8 @@ internal class AchievementViewModel
private async Task OpenUIAsync()
{
if (await metadataService.InitializeAsync(CancellationToken))
bool metaInitialized = await metadataService.InitializeAsync(CancellationToken);
if (metaInitialized)
{
AchievementGoals = await metadataService.GetAchievementGoalsAsync(CancellationToken);
@@ -222,6 +242,8 @@ internal class AchievementViewModel
infoBarService.Warning("请创建或选择一个成就存档");
}
}
openUICompletionSource.TrySetResult(metaInitialized);
}
private async Task UpdateAchievementsAsync(Model.Entity.AchievementArchive archive)
@@ -291,8 +313,7 @@ internal class AchievementViewModel
return;
}
DataPackageView view = Clipboard.GetContent();
string json = await view.GetTextAsync();
string json = await Clipboard.GetContent().GetTextAsync();
UIAF? uiaf = null;
try
@@ -321,7 +342,7 @@ internal class AchievementViewModel
await new ContentDialog2(App.Window!)
{
Title = "导入失败",
Content = "剪贴板中的内容格式不正确",
Content = "数据格式不正确",
PrimaryButtonText = "确认",
DefaultButton = ContentDialogButton.Primary,
}
@@ -375,7 +396,7 @@ internal class AchievementViewModel
await new ContentDialog2(App.Window!)
{
Title = "导入失败",
Content = "文件中的内容格式不正确",
Content = "数据格式不正确",
PrimaryButtonText = "确认",
DefaultButton = ContentDialogButton.Primary,
}

View File

@@ -3,8 +3,6 @@
using CommunityToolkit.Mvvm.ComponentModel;
using CommunityToolkit.Mvvm.Input;
using Microsoft.UI.Xaml;
using Snap.Hutao.Core.Threading;
using Snap.Hutao.Factory.Abstraction;
using Snap.Hutao.Model.Binding;
using Snap.Hutao.Service.Abstraction;

View File

@@ -27,11 +27,6 @@ public class Response : ISupportValidation
{
Ioc.Default.GetRequiredService<IInfoBarService>().Error(ToString());
}
if (ReturnCode != 0)
{
Ioc.Default.GetRequiredService<IInfoBarService>().Warning(ToString());
}
}
/// <summary>