make DI initialize in program

This commit is contained in:
DismissedLight
2022-08-24 22:18:57 +08:00
parent 8972914a72
commit 90caef6bdc
32 changed files with 227 additions and 146 deletions

View File

@@ -1,8 +1,6 @@
// Copyright (c) DGP Studio. All rights reserved.
// Licensed under the MIT license.
using CommunityToolkit.Mvvm.Messaging;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.UI.Xaml;
using Microsoft.Windows.AppLifecycle;
using Snap.Hutao.Core.LifeCycle;
@@ -11,57 +9,31 @@ using Snap.Hutao.Extension;
using Snap.Hutao.Service.Metadata;
using System.Diagnostics;
using Windows.Storage;
using Windows.UI.ViewManagement;
namespace Snap.Hutao;
/// <summary>
/// Provides application-specific behavior to supplement the default Application class.
/// </summary>
[Injection(InjectAs.Singleton)]
public partial class App : Application
{
private static Window? window;
private readonly ILogger<App> logger;
/// <summary>
/// Initializes the singleton application object.
/// </summary>
public App()
/// <param name="logger">日志器</param>
public App(ILogger<App> logger)
{
// load app resource
InitializeComponent();
InitializeDependencyInjection();
// Notice that we already call InitializeDependencyInjection() above
// so we can use Ioc here.
logger = Ioc.Default.GetRequiredService<ILogger<App>>();
this.logger = logger;
_ = new ExceptionRecorder(this, logger);
}
/// <summary>
/// 当前窗口
/// </summary>
public static Window? Window { get => window; set => window = value; }
/// <inheritdoc cref="Application"/>
public static new App Current
{
get => (App)Application.Current;
}
/// <inheritdoc cref="ApplicationData.Current.TemporaryFolder"/>
public static StorageFolder CacheFolder
{
get => ApplicationData.Current.TemporaryFolder;
}
/// <inheritdoc cref="ApplicationData.Current.LocalSettings"/>
public static ApplicationDataContainer Settings
{
get => ApplicationData.Current.LocalSettings;
}
/// <inheritdoc/>
[SuppressMessage("", "VSTHRD100")]
protected override async void OnLaunched(LaunchActivatedEventArgs args)
@@ -71,11 +43,11 @@ public partial class App : Application
if (firstInstance.IsCurrent)
{
// manually invoke the
// manually invoke
Activation.Activate(firstInstance, activatedEventArgs);
firstInstance.Activated += Activation.Activate;
logger.LogInformation(EventIds.CommonLog, "Cache folder : {folder}", CacheFolder.Path);
logger.LogInformation(EventIds.CommonLog, "Cache folder : {folder}", ApplicationData.Current.TemporaryFolder.Path);
Ioc.Default
.GetRequiredService<IMetadataService>()
@@ -90,29 +62,4 @@ public partial class App : Application
Process.GetCurrentProcess().Kill();
}
}
private static void InitializeDependencyInjection()
{
IServiceProvider services = new ServiceCollection()
// Microsoft extension
.AddLogging(builder => builder
.AddDebug()
.AddDatabase())
.AddMemoryCache()
// Hutao extensions
.AddJsonSerializerOptions()
.AddDatebase()
.AddInjections()
.AddHttpClients()
// Discrete services
.AddSingleton<IMessenger>(WeakReferenceMessenger.Default)
.AddSingleton(new UISettings())
.BuildServiceProvider();
Ioc.Default.ConfigureServices(services);
}
}
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 432 B

After

Width:  |  Height:  |  Size: 7.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.2 KiB

After

Width:  |  Height:  |  Size: 254 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.7 KiB

After

Width:  |  Height:  |  Size: 123 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 637 B

After

Width:  |  Height:  |  Size: 19 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 283 B

After

Width:  |  Height:  |  Size: 3.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 456 B

After

Width:  |  Height:  |  Size: 8.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.0 KiB

After

Width:  |  Height:  |  Size: 87 KiB

View File

@@ -0,0 +1,39 @@
// Copyright (c) DGP Studio. All rights reserved.
// Licensed under the MIT license.
using Microsoft.UI.Xaml.Controls;
using Snap.Hutao.Extension;
namespace Snap.Hutao.Control.Extension;
/// <summary>
/// 对话框扩展
/// </summary>
internal static class ContentDialogExtensions
{
/// <summary>
/// 阻止用户交互
/// </summary>
/// <param name="contentDialog">对话框</param>
/// <returns>用于恢复用户交互</returns>
public static IDisposable BlockInteraction(this ContentDialog contentDialog)
{
contentDialog.ShowAsync().AsTask().SafeForget();
return new ContentDialogHider(contentDialog);
}
private struct ContentDialogHider : IDisposable
{
private readonly ContentDialog contentDialog;
public ContentDialogHider(ContentDialog contentDialog)
{
this.contentDialog = contentDialog;
}
public void Dispose()
{
contentDialog.Hide();
}
}
}

View File

@@ -8,7 +8,6 @@ using Microsoft.UI.Xaml.Hosting;
using Microsoft.UI.Xaml.Media;
using Snap.Hutao.Core;
using Snap.Hutao.Core.Caching;
using Snap.Hutao.Core.Exception;
using Snap.Hutao.Core.Threading;
using Snap.Hutao.Extension;
using Snap.Hutao.Service.Abstraction;
@@ -132,13 +131,8 @@ public abstract class CompositionImage : Microsoft.UI.Xaml.Controls.Control
{
imageSurface = await LoadImageSurfaceAsync(storageFile, token);
}
catch (COMException ex) when (ex.Is(COMError.STG_E_FILENOTFOUND))
catch (COMException)
{
// Image file not found.
}
catch (COMException ex) when (ex.Is(COMError.WINCODEC_ERR_COMPONENTNOTFOUND))
{
// Image is broken, remove it
await imageCache.RemoveAsync(uri.Enumerate());
}

View File

@@ -55,7 +55,7 @@ public class MonoChrome : CompositionImage
{
ElementTheme.Light => ApplicationTheme.Light,
ElementTheme.Dark => ApplicationTheme.Dark,
_ => App.Current.RequestedTheme,
_ => Ioc.Default.GetRequiredService<App>().RequestedTheme,
};
backgroundBrush.Color = theme switch

View File

@@ -216,7 +216,7 @@ public abstract class CacheBase<T>
using (await cacheFolderSemaphore.EnterAsync().ConfigureAwait(false))
{
baseFolder ??= App.CacheFolder;
baseFolder ??= ApplicationData.Current.TemporaryFolder;
if (string.IsNullOrWhiteSpace(cacheFolderName))
{

View File

@@ -23,6 +23,7 @@ internal static class Activation
/// <param name="args">激活参数</param>
public static void Activate(object? sender, AppActivationArguments args)
{
_ = sender;
HandleActivationAsync(args).SafeForget();
}
@@ -43,7 +44,7 @@ internal static class Activation
private static async Task HandleActivationCoreAsync(AppActivationArguments args)
{
App.Window = Ioc.Default.GetRequiredService<MainWindow>();
_ = Ioc.Default.GetRequiredService<MainWindow>();
IInfoBarService infoBarService = Ioc.Default.GetRequiredService<IInfoBarService>();
await infoBarService.WaitInitializationAsync().ConfigureAwait(false);

View File

@@ -18,7 +18,7 @@ internal static class LocalSetting
static LocalSetting()
{
Container = App.Settings;
Container = ApplicationData.Current.LocalSettings;
}
/// <summary>
@@ -28,7 +28,7 @@ internal static class LocalSetting
/// <param name="key">键</param>
/// <param name="defaultValue">默认值</param>
/// <returns>获取的值</returns>
[return:MaybeNull]
[return: MaybeNull]
public static T Get<T>(string key, [AllowNull] T defaultValue = default)
{
if (Container.Values.TryGetValue(key, out object? value))

View File

@@ -57,4 +57,20 @@ public static class ThemeHelper
_ => throw Must.NeverHappen(),
};
}
/// <summary>
/// 检查是否为暗黑模式
/// </summary>
/// <param name="elementTheme">当前元素主题</param>
/// <param name="applicationTheme">当前应用主题</param>
/// <returns>是否为暗黑模式</returns>
public static bool IsDarkMode(ElementTheme elementTheme, ApplicationTheme applicationTheme)
{
return elementTheme switch
{
ElementTheme.Default => applicationTheme == ApplicationTheme.Dark,
ElementTheme.Dark => true,
_ => false,
};
}
}

View File

@@ -25,7 +25,10 @@ public struct DispatherQueueSwitchOperation : IAwaitable<DispatherQueueSwitchOpe
/// <summary>
/// 是否完成
/// </summary>
public bool IsCompleted => dispatherQueue.HasThreadAccess;
public bool IsCompleted
{
get => dispatherQueue.HasThreadAccess;
}
/// <inheritdoc/>
public void OnCompleted(Action continuation)

View File

@@ -116,10 +116,12 @@ internal sealed class WindowManager : IDisposable
appTitleBar.ButtonBackgroundColor = Colors.Transparent;
appTitleBar.ButtonInactiveBackgroundColor = Colors.Transparent;
Color systemBaseLowColor = (Color)App.Current.Resources["SystemBaseLowColor"];
App app = Ioc.Default.GetRequiredService<App>();
Color systemBaseLowColor = (Color)app.Resources["SystemBaseLowColor"];
appTitleBar.ButtonHoverBackgroundColor = systemBaseLowColor;
Color systemBaseMediumLowColor = (Color)App.Current.Resources["SystemBaseMediumLowColor"];
Color systemBaseMediumLowColor = (Color)app.Resources["SystemBaseMediumLowColor"];
appTitleBar.ButtonPressedBackgroundColor = systemBaseMediumLowColor;
// The Foreground doesn't accept Alpha channel. So we translate it to gray.
@@ -127,7 +129,7 @@ internal sealed class WindowManager : IDisposable
byte result = (byte)((systemBaseMediumLowColor.A / 255.0) * light);
appTitleBar.ButtonInactiveForegroundColor = Color.FromArgb(0xFF, result, result, result);
Color systemBaseHighColor = (Color)App.Current.Resources["SystemBaseHighColor"];
Color systemBaseHighColor = (Color)app.Resources["SystemBaseHighColor"];
appTitleBar.ButtonForegroundColor = systemBaseHighColor;
appTitleBar.ButtonHoverForegroundColor = systemBaseHighColor;
appTitleBar.ButtonPressedForegroundColor = systemBaseHighColor;

View File

@@ -194,6 +194,8 @@ public enum FightProperty
/// <summary>
/// 草元素伤害加成
/// </summary>
[Description("草元素伤害加成")]
[Format(FormatMethod.Percent)]
FIGHT_PROP_GRASS_ADD_HURT = 43,
/// <summary>

View File

@@ -10,7 +10,7 @@ namespace Snap.Hutao.Model.Metadata.Converter;
/// </summary>
internal class AvatarIconConverter : IValueConverter
{
private const string BaseUrl = "https://upload-bbs.mihoyo.com/game_record/genshin/character_icon/{0}.png";
private const string BaseUrl = "https://static.snapgenshin.com/AvatarIcon/{0}.png";
/// <inheritdoc/>
public object Convert(object value, Type targetType, object parameter, string language)

View File

@@ -10,7 +10,7 @@ namespace Snap.Hutao.Model.Metadata.Converter;
/// </summary>
internal class AvatarSideIconConverter : IValueConverter
{
private const string BaseUrl = "https://upload-bbs.mihoyo.com/game_record/genshin/character_side_icon/{0}.png";
private const string BaseUrl = "https://static.snapgenshin.com/AvatarIcon/{0}.png";
/// <inheritdoc/>
public object Convert(object value, Type targetType, object parameter, string language)

View File

@@ -1,10 +1,14 @@
// Copyright (c) DGP Studio. All rights reserved.
// Licensed under the MIT license.
using CommunityToolkit.Mvvm.Messaging;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.UI.Dispatching;
using Microsoft.UI.Xaml;
using Snap.Hutao.Core.Logging;
using Snap.Hutao.Core.Threading;
using System.Runtime.InteropServices;
using Windows.UI.ViewManagement;
using WinRT;
namespace Snap.Hutao;
@@ -35,12 +39,44 @@ public static class Program
XamlCheckProcessRequirements();
ComWrappersSupport.InitializeComWrappers();
Application.Start(p =>
{
dispatcherQueue = DispatcherQueue.GetForCurrentThread();
DispatcherQueueSynchronizationContext context = new(dispatcherQueue);
SynchronizationContext.SetSynchronizationContext(context);
_ = new App();
});
InitializeDependencyInjection();
// In a Desktop app this runs a message pump internally,
// and does not return until the application shuts down.
Application.Start(InitializeApp);
}
private static void InitializeApp(ApplicationInitializationCallbackParams param)
{
dispatcherQueue = DispatcherQueue.GetForCurrentThread();
DispatcherQueueSynchronizationContext context = new(dispatcherQueue);
SynchronizationContext.SetSynchronizationContext(context);
_ = Ioc.Default.GetRequiredService<App>();
}
private static void InitializeDependencyInjection()
{
IServiceProvider services = new ServiceCollection()
// Microsoft extension
.AddLogging(builder => builder
.AddDebug()
.AddDatabase())
.AddMemoryCache()
// Hutao extensions
.AddJsonSerializerOptions()
.AddDatebase()
.AddInjections()
.AddHttpClients()
// Discrete services
.AddSingleton<IMessenger>(WeakReferenceMessenger.Default)
.AddSingleton(new UISettings())
.BuildServiceProvider();
Ioc.Default.ConfigureServices(services);
}
}

View File

@@ -151,6 +151,12 @@ internal class AchievementService : IAchievementService
}
}
/// <inheritdoc/>
public Task<ImportResult> ImportFromUIAFAsync(EntityArchive archive, List<UIAFItem> list, ImportOption option)
{
return Task.Run(() => ImportFromUIAF(archive, list, option));
}
/// <inheritdoc/>
public void SaveAchievements(EntityArchive archive, IList<BindingAchievement> achievements)
{

View File

@@ -40,9 +40,18 @@ internal interface IAchievementService
/// <param name="archive">用户</param>
/// <param name="list">UIAF数据</param>
/// <param name="option">选项</param>
/// <returns>导入</returns>
/// <returns>导入结果</returns>
ImportResult ImportFromUIAF(EntityArchive archive, List<UIAFItem> list, ImportOption option);
/// <summary>
/// 异步导入UIAF数据
/// </summary>
/// <param name="archive">用户</param>
/// <param name="list">UIAF数据</param>
/// <param name="option">选项</param>
/// <returns>导入结果</returns>
Task<ImportResult> ImportFromUIAFAsync(EntityArchive archive, List<UIAFItem> list, ImportOption option);
/// <summary>
/// 异步移除存档
/// </summary>

View File

@@ -35,4 +35,10 @@ public struct ImportResult
Update = update;
Remove = remove;
}
/// <inheritdoc/>
public override string ToString()
{
return $"新增:{Add} 个成就 | 更新:{Update} 个成就 | 删除{Remove} 个成就";
}
}

View File

@@ -50,7 +50,7 @@
<StackPanel
x:Name="InfoBarStack"
Margin="32"
Margin="32,48,32,32"
MaxWidth="640"
VerticalAlignment="Bottom">
<StackPanel.Resources>

View File

@@ -50,13 +50,15 @@ public sealed partial class MainView : UserControl
{
await Program.SwitchToMainThreadAsync();
if (!ThemeHelper.Equals(App.Current.RequestedTheme, RequestedTheme))
App current = Ioc.Default.GetRequiredService<App>();
if (!ThemeHelper.Equals(current.RequestedTheme, RequestedTheme))
{
ILogger<MainView> logger = Ioc.Default.GetRequiredService<ILogger<MainView>>();
logger.LogInformation(EventIds.CommonLog, "Element Theme [{element}] App Theme [{app}]", RequestedTheme, App.Current.RequestedTheme);
logger.LogInformation(EventIds.CommonLog, "Element Theme [{element}] App Theme [{app}]", RequestedTheme, current.RequestedTheme);
// Update controls' theme which presents in the PopupRoot
RequestedTheme = ThemeHelper.ApplicationToElement(App.Current.RequestedTheme);
RequestedTheme = ThemeHelper.ApplicationToElement(current.RequestedTheme);
}
}
}

View File

@@ -4,6 +4,7 @@
using Microsoft.UI.Xaml;
using Microsoft.UI.Xaml.Navigation;
using Microsoft.Web.WebView2.Core;
using Snap.Hutao.Core;
using Snap.Hutao.Extension;
using Snap.Hutao.Service.Navigation;
using Windows.System;
@@ -21,7 +22,8 @@ public sealed partial class AnnouncementContentPage : Microsoft.UI.Xaml.Controls
private const string LightColor3 = "color:rgba(204,204,204,1)";
private const string LightColor4 = "color:rgba(198,196,191,1)";
private const string LightColor5 = "color:rgba(170,170,170,1)";
private const string LightAccentColor = "background-color: rgb(0,40,70)";
private const string LightAccentColor1 = "background-color: rgb(0,40,70)";
private const string LightAccentColor2 = "background-color: rgb(1,40,70)";
// find in content
private const string DarkColor1 = "color:rgba(0,0,0,1)";
@@ -30,6 +32,7 @@ public sealed partial class AnnouncementContentPage : Microsoft.UI.Xaml.Controls
private const string DarkColor4 = "color:rgba(57,59,64,1)";
private const string DarkColor5 = "color:rgba(85,85,85,1)";
private const string DarkAccentColor1 = "background-color: rgb(255, 215, 185);";
private const string DarkAccentColor2 = "background-color: rgb(254, 245, 231);";
// support click open browser.
private const string MihoyoSDKDefinition =
@@ -66,25 +69,19 @@ openInWebview: function(url){ location.href = url }}";
return rawContent;
}
bool isDarkMode = theme switch
{
ElementTheme.Default => App.Current.RequestedTheme == ApplicationTheme.Dark,
ElementTheme.Dark => true,
_ => false,
};
if (isDarkMode)
if (ThemeHelper.IsDarkMode(theme, Ioc.Default.GetRequiredService<App>().RequestedTheme))
{
rawContent = rawContent
.Replace(DarkColor5, LightColor5)
.Replace(DarkColor4, LightColor4)
.Replace(DarkColor3, LightColor3)
.Replace(DarkColor2, LightColor2)
.Replace(DarkAccentColor1, LightAccentColor);
.Replace(DarkAccentColor1, LightAccentColor1)
.Replace(DarkAccentColor2, LightAccentColor2);
}
// wrap a default color body around
return $@"<body style=""{(isDarkMode ? LightColor1 : DarkColor1)}"">{rawContent}</body>";
return $@"<body style=""{(ThemeHelper.IsDarkMode(theme, Ioc.Default.GetRequiredService<App>().RequestedTheme) ? LightColor1 : DarkColor1)}"">{rawContent}</body>";
}
private async Task LoadAnnouncementAsync(INavigationData data)

View File

@@ -25,9 +25,7 @@
<sc:Setting
Icon="&#xE117;"
Header="检查更新"
Description="根本没有检查更新选项">
</sc:Setting>
Description="根本没有检查更新选项"/>
</sc:SettingExpander.Header>
<InfoBar
IsClosable="False"
@@ -60,7 +58,7 @@
<sc:Setting
Icon="&#xE73A;"
Header="米游社签到"
Description="所有账号的所有角色都会签到,每次间隔 15s">
Description="所有账号的所有角色都会签到,每次间隔 5-15s">
<sc:Setting.ActionContent>
<Button Content="签到" Command="{Binding Experimental.SignAllUserGameRolesCommand}"/>
</sc:Setting.ActionContent>

View File

@@ -7,6 +7,7 @@ using CommunityToolkit.WinUI.UI;
using Microsoft.UI.Xaml.Controls;
using Snap.Hutao.Control;
using Snap.Hutao.Control.Cancellable;
using Snap.Hutao.Control.Extension;
using Snap.Hutao.Extension;
using Snap.Hutao.Factory.Abstraction;
using Snap.Hutao.Message;
@@ -21,6 +22,7 @@ using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.IO;
using System.Linq;
using System.Runtime.InteropServices;
using Windows.ApplicationModel.DataTransfer;
using Windows.Storage;
using Windows.Storage.Pickers;
@@ -211,7 +213,7 @@ internal class AchievementViewModel
private static Task<ContentDialogResult> ShowImportFailDialogAsync(string message)
{
return new ContentDialog2(App.Window!)
return new ContentDialog2(Ioc.Default.GetRequiredService<MainWindow>())
{
Title = "导入失败",
Content = message,
@@ -239,7 +241,8 @@ internal class AchievementViewModel
if (metaInitialized)
{
AchievementGoals = await metadataService.GetAchievementGoalsAsync(CancellationToken);
List<AchievementGoal> goals = await metadataService.GetAchievementGoalsAsync(CancellationToken);
AchievementGoals = goals.OrderBy(goal => goal.Order).ToList();
Archives = achievementService.GetArchiveCollection();
@@ -265,7 +268,8 @@ internal class AchievementViewModel
private async Task AddArchiveAsync()
{
(bool isOk, string name) = await new AchievementArchiveCreateDialog(App.Window!).GetInputAsync();
MainWindow mainWindow = Ioc.Default.GetRequiredService<MainWindow>();
(bool isOk, string name) = await new AchievementArchiveCreateDialog(mainWindow).GetInputAsync();
if (isOk)
{
@@ -292,7 +296,8 @@ internal class AchievementViewModel
{
if (Archives != null && SelectedArchive != null)
{
ContentDialogResult result = await new ContentDialog2(App.Window!)
MainWindow mainWindow = Ioc.Default.GetRequiredService<MainWindow>();
ContentDialogResult result = await new ContentDialog2(mainWindow)
{
Title = $"确定要删除存档 {SelectedArchive.Name} 吗?",
Content = "该操作是不可逆的,该存档和其内的所有成就状态会丢失。",
@@ -321,25 +326,9 @@ internal class AchievementViewModel
return;
}
string json = await Clipboard.GetContent().GetTextAsync();
if (GetUIAFFromString(json) is UIAF uiaf)
if (await GetUIAFFromClipboardAsync() is UIAF uiaf)
{
if (uiaf.IsCurrentVersionSupported())
{
(bool isOk, ImportOption option) = await new AchievementImportDialog(App.Window!, uiaf).GetImportOptionAsync();
if (isOk)
{
ImportResult result = achievementService.ImportFromUIAF(achievementService.CurrentArchive, uiaf.List, option);
infoBarService!.Success($"新增:{result.Add} 个成就 | 更新:{result.Update} 个成就 | 删除{result.Remove} 个成就");
await UpdateAchievementsAsync(achievementService.CurrentArchive);
}
}
else
{
await ShowImportFailDialogAsync("数据的 UIAF 版本过低,无法导入");
}
await TryImportUIAFInternalAsync(achievementService.CurrentArchive, uiaf);
}
else
{
@@ -363,21 +352,7 @@ internal class AchievementViewModel
{
if (await GetUIAFFromFileAsync(file) is UIAF uiaf)
{
if (uiaf.IsCurrentVersionSupported())
{
(bool isOk, ImportOption option) = await new AchievementImportDialog(App.Window!, uiaf).GetImportOptionAsync();
if (isOk)
{
ImportResult result = achievementService.ImportFromUIAF(achievementService.CurrentArchive, uiaf.List, option);
infoBarService!.Success($"新增:{result.Add} 个成就 | 更新:{result.Update} 个成就 | 删除{result.Remove} 个成就");
await UpdateAchievementsAsync(achievementService.CurrentArchive);
}
}
else
{
await ShowImportFailDialogAsync("数据的 UIAF 版本过低,无法导入");
}
await TryImportUIAFInternalAsync(achievementService.CurrentArchive, uiaf);
}
else
{
@@ -386,9 +361,20 @@ internal class AchievementViewModel
}
}
private UIAF? GetUIAFFromString(string json)
private async Task<UIAF?> GetUIAFFromClipboardAsync()
{
UIAF? uiaf = null;
string json;
try
{
json = await Clipboard.GetContent().GetTextAsync();
}
catch (COMException ex)
{
infoBarService?.Error(ex);
return null;
}
try
{
uiaf = JsonSerializer.Deserialize<UIAF>(json, options);
@@ -422,6 +408,41 @@ internal class AchievementViewModel
return uiaf;
}
private async Task<bool> TryImportUIAFInternalAsync(Model.Entity.AchievementArchive archive, UIAF uiaf)
{
if (uiaf.IsCurrentVersionSupported())
{
MainWindow mainWindow = Ioc.Default.GetRequiredService<MainWindow>();
(bool isOk, ImportOption option) = await new AchievementImportDialog(mainWindow, uiaf).GetImportOptionAsync();
if (isOk)
{
ContentDialog2 importingDialog = new(Ioc.Default.GetRequiredService<MainWindow>())
{
Title = "导入成就中",
Content = new ProgressBar() { IsIndeterminate = true },
DefaultButton = ContentDialogButton.Primary,
};
ImportResult result;
using (importingDialog.BlockInteraction())
{
result = await achievementService.ImportFromUIAFAsync(archive, uiaf.List, option);
}
infoBarService.Success(result.ToString());
await UpdateAchievementsAsync(archive);
return true;
}
}
else
{
await ShowImportFailDialogAsync("数据的 UIAF 版本过低,无法导入");
}
return false;
}
private void UpdateAchievementFilter(AchievementGoal? goal)
{
if (Achievements != null)

View File

@@ -7,6 +7,7 @@ using Snap.Hutao.Factory.Abstraction;
using Snap.Hutao.Service.Abstraction;
using Snap.Hutao.Service.Sign;
using System.Text;
using Windows.Storage;
using Windows.System;
namespace Snap.Hutao.ViewModel;
@@ -60,7 +61,7 @@ internal class ExperimentalFeaturesViewModel : ObservableObject
private Task OpenCacheFolderAsync()
{
return Launcher.LaunchFolderAsync(App.CacheFolder).AsTask();
return Launcher.LaunchFolderAsync(ApplicationData.Current.TemporaryFolder).AsTask();
}
private Task OpenDataFolderAsync()

View File

@@ -121,7 +121,8 @@ internal class UserViewModel : ObservableObject
private async Task AddUserAsync()
{
// Get cookie from user input
(bool isOk, string cookie) = await new UserDialog(App.Window!).GetInputCookieAsync();
MainWindow mainWindow = Ioc.Default.GetRequiredService<MainWindow>();
(bool isOk, string cookie) = await new UserDialog(mainWindow).GetInputCookieAsync();
// User confirms the input
if (isOk)

View File

@@ -161,7 +161,7 @@ public class Announcement : AnnouncementContent
/// 提醒版本
/// </summary>
[JsonPropertyName("remind_ver")]
public int RemindVer { get; set; }
public int RemindVersion { get; set; }
/// <summary>
/// 是否含有内容