diff --git a/src/Snap.Hutao/Snap.Hutao/App.xaml b/src/Snap.Hutao/Snap.Hutao/App.xaml index a578a1ea..3b6babf6 100644 --- a/src/Snap.Hutao/Snap.Hutao/App.xaml +++ b/src/Snap.Hutao/Snap.Hutao/App.xaml @@ -2,7 +2,10 @@ x:Class="Snap.Hutao.App" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" - xmlns:muxc="using:Microsoft.UI.Xaml.Controls"> + xmlns:cwuc="using:CommunityToolkit.WinUI.UI.Converters" + xmlns:muxc="using:Microsoft.UI.Xaml.Controls" + xmlns:shmmc="using:Snap.Hutao.Model.Metadata.Converter" + xmlns:shvc="using:Snap.Hutao.View.Converter"> @@ -13,21 +16,36 @@ - + - + ms-appx:///Resource/Font/Segoe Fluent Icons.ttf#Segoe Fluent Icons - + 6,16,16,16 16,0,0,0 - + 16 - + 6 6,6,0,0 0,6,6,0 0,0,6,6 2 + + + + + + + + + + + + + + + diff --git a/src/Snap.Hutao/Snap.Hutao/App.xaml.cs b/src/Snap.Hutao/Snap.Hutao/App.xaml.cs index fa75ecd0..47df058f 100644 --- a/src/Snap.Hutao/Snap.Hutao/App.xaml.cs +++ b/src/Snap.Hutao/Snap.Hutao/App.xaml.cs @@ -54,13 +54,17 @@ public partial class App : Application logger.LogInformation(EventIds.CommonLog, "Snap Hutao : {version}", CoreEnvironment.Version); logger.LogInformation(EventIds.CommonLog, "Cache folder : {folder}", ApplicationData.Current.TemporaryFolder.Path); + JumpListHelper.ConfigAsync().SafeForget(logger); + Ioc.Default .GetRequiredService() .ImplictAs()? .InitializeInternalAsync() .SafeForget(logger); - Ioc.Default.GetRequiredService().Initialize(); + Ioc.Default + .GetRequiredService() + .Initialize(); } else { diff --git a/src/Snap.Hutao/Snap.Hutao/Control/Behavior/AutoHeightBehavior.cs b/src/Snap.Hutao/Snap.Hutao/Control/Behavior/AutoHeightBehavior.cs index 11d8d246..43a8b2a3 100644 --- a/src/Snap.Hutao/Snap.Hutao/Control/Behavior/AutoHeightBehavior.cs +++ b/src/Snap.Hutao/Snap.Hutao/Control/Behavior/AutoHeightBehavior.cs @@ -55,4 +55,4 @@ internal class AutoHeightBehavior : BehaviorBase { AssociatedObject.Height = (double)AssociatedObject.ActualWidth * (TargetHeight / TargetWidth); } -} \ No newline at end of file +} diff --git a/src/Snap.Hutao/Snap.Hutao/Control/Behavior/AutoWidthBehavior.cs b/src/Snap.Hutao/Snap.Hutao/Control/Behavior/AutoWidthBehavior.cs new file mode 100644 index 00000000..b033564d --- /dev/null +++ b/src/Snap.Hutao/Snap.Hutao/Control/Behavior/AutoWidthBehavior.cs @@ -0,0 +1,58 @@ +// Copyright (c) DGP Studio. All rights reserved. +// Licensed under the MIT license. + +using CommunityToolkit.WinUI.UI.Behaviors; +using Microsoft.UI.Xaml; +using Snap.Hutao.Core; + +namespace Snap.Hutao.Control.Behavior; + +/// +/// 按给定比例自动调整高度的行为 +/// +internal class AutoWidthBehavior : BehaviorBase +{ + private static readonly DependencyProperty TargetWidthProperty = Property.Depend(nameof(TargetWidth), 320D); + private static readonly DependencyProperty TargetHeightProperty = Property.Depend(nameof(TargetHeight), 1024D); + + /// + /// 目标宽度 + /// + public double TargetWidth + { + get => (double)GetValue(TargetWidthProperty); + set => SetValue(TargetWidthProperty, value); + } + + /// + /// 目标高度 + /// + public double TargetHeight + { + get => (double)GetValue(TargetHeightProperty); + set => SetValue(TargetHeightProperty, value); + } + + /// + protected override void OnAssociatedObjectLoaded() + { + UpdateElementWidth(); + AssociatedObject.SizeChanged += OnSizeChanged; + } + + /// + protected override void OnDetaching() + { + AssociatedObject.SizeChanged -= OnSizeChanged; + } + + private void OnSizeChanged(object sender, SizeChangedEventArgs e) + { + UpdateElementWidth(); + } + + private void UpdateElementWidth() + { + AssociatedObject.Width = (double)AssociatedObject.Height * (TargetWidth / TargetHeight); + } +} \ No newline at end of file diff --git a/src/Snap.Hutao/Snap.Hutao/Core/CommandLineBuilder.cs b/src/Snap.Hutao/Snap.Hutao/Core/CommandLineBuilder.cs new file mode 100644 index 00000000..0cab1bf0 --- /dev/null +++ b/src/Snap.Hutao/Snap.Hutao/Core/CommandLineBuilder.cs @@ -0,0 +1,63 @@ +// Copyright (c) DGP Studio. All rights reserved. +// Licensed under the MIT license. + +using System.Text; + +namespace Snap.Hutao.Core; + +/// +/// 命令行建造器 +/// +public class CommandLineBuilder +{ + private const char WhiteSpace = ' '; + private readonly Dictionary options = new(); + + /// + /// 当符合条件时添加参数 + /// + /// 参数名称 + /// 条件 + /// 值 + /// 命令行建造器 + public CommandLineBuilder AppendIf(string name, bool condition, object? value = null) + { + return condition ? Append(name, value) : this; + } + + /// + /// 添加参数 + /// + /// 参数名称 + /// 值 + /// 命令行建造器 + public CommandLineBuilder Append(string name, object? value = null) + { + options.Add(name, value?.ToString()); + return this; + } + + /// + public string Build() + { + return ToString(); + } + + /// + public override string ToString() + { + StringBuilder s = new(); + foreach ((string key, string? value) in options) + { + s.Append(WhiteSpace); + s.Append(key); + if (!string.IsNullOrEmpty(value)) + { + s.Append(WhiteSpace); + s.Append(value); + } + } + + return s.ToString(); + } +} \ No newline at end of file diff --git a/src/Snap.Hutao/Snap.Hutao/Core/JumpListHelper.cs b/src/Snap.Hutao/Snap.Hutao/Core/JumpListHelper.cs new file mode 100644 index 00000000..612ac475 --- /dev/null +++ b/src/Snap.Hutao/Snap.Hutao/Core/JumpListHelper.cs @@ -0,0 +1,35 @@ +// Copyright (c) DGP Studio. All rights reserved. +// Licensed under the MIT license. + +using Snap.Hutao.Core.LifeCycle; +using Windows.UI.StartScreen; + +namespace Snap.Hutao.Core; + +/// +/// 跳转列表帮助类 +/// +public static class JumpListHelper +{ + /// + /// 异步配置跳转列表 + /// + /// 任务 + public static async Task ConfigAsync() + { + if (JumpList.IsSupported()) + { + JumpList list = await JumpList.LoadCurrentAsync(); + + list.Items.Clear(); + + JumpListItem launchGameItem = JumpListItem.CreateWithArguments(Activation.LaunchGame, "启动游戏"); + launchGameItem.GroupName = "快捷操作"; + launchGameItem.Logo = new("ms-appx:///Resource/Icon/UI_GuideIcon_PlayMethod.png"); + + list.Items.Add(launchGameItem); + + await list.SaveAsync(); + } + } +} \ No newline at end of file diff --git a/src/Snap.Hutao/Snap.Hutao/Core/LifeCycle/Activation.cs b/src/Snap.Hutao/Snap.Hutao/Core/LifeCycle/Activation.cs index e48a5bfb..1eda1194 100644 --- a/src/Snap.Hutao/Snap.Hutao/Core/LifeCycle/Activation.cs +++ b/src/Snap.Hutao/Snap.Hutao/Core/LifeCycle/Activation.cs @@ -13,6 +13,11 @@ namespace Snap.Hutao.Core.LifeCycle; /// internal static class Activation { + /// + /// 启动游戏启动参数 + /// + public const string LaunchGame = "LaunchGame"; + private static readonly SemaphoreSlim ActivateSemaphore = new(1); /// @@ -44,16 +49,36 @@ internal static class Activation private static async Task HandleActivationCoreAsync(AppActivationArguments args) { - _ = Ioc.Default.GetRequiredService(); + string argument = string.Empty; - IInfoBarService infoBarService = Ioc.Default.GetRequiredService(); - await infoBarService.WaitInitializationAsync().ConfigureAwait(false); + if (args.Kind == ExtendedActivationKind.Launch) + { + if (args.TryGetLaunchActivatedArgument(out string? arguments)) + { + argument = arguments; + } + } + + switch (argument) + { + case "": + { + _ = Ioc.Default.GetRequiredService(); + await Ioc.Default.GetRequiredService().WaitInitializationAsync().ConfigureAwait(false); + break; + } + + case LaunchGame: + { + break; + } + } if (args.Kind == ExtendedActivationKind.Protocol) { if (args.TryGetProtocolActivatedUri(out Uri? uri)) { - infoBarService.Information(uri.ToString()); + Ioc.Default.GetRequiredService().Information(uri.ToString()); await HandleUrlActivationAsync(uri).ConfigureAwait(false); } } diff --git a/src/Snap.Hutao/Snap.Hutao/Core/LifeCycle/AppActivationArgumentsExtensions.cs b/src/Snap.Hutao/Snap.Hutao/Core/LifeCycle/AppActivationArgumentsExtensions.cs index cc4e416d..9ea64b70 100644 --- a/src/Snap.Hutao/Snap.Hutao/Core/LifeCycle/AppActivationArgumentsExtensions.cs +++ b/src/Snap.Hutao/Snap.Hutao/Core/LifeCycle/AppActivationArgumentsExtensions.cs @@ -28,4 +28,22 @@ public static class AppActivationArgumentsExtensions return false; } + + /// + /// 尝试获取启动的参数 + /// + /// 应用程序激活参数 + /// 参数 + /// 是否存在参数 + public static bool TryGetLaunchActivatedArgument(this AppActivationArguments activatedEventArgs, [NotNullWhen(true)] out string? arguments) + { + arguments = null; + if (activatedEventArgs.Data is ILaunchActivatedEventArgs launchArgs) + { + arguments = launchArgs.Arguments; + return true; + } + + return false; + } } diff --git a/src/Snap.Hutao/Snap.Hutao/Core/ProcessHelper.cs b/src/Snap.Hutao/Snap.Hutao/Core/ProcessHelper.cs index 87f390b5..080423a0 100644 --- a/src/Snap.Hutao/Snap.Hutao/Core/ProcessHelper.cs +++ b/src/Snap.Hutao/Snap.Hutao/Core/ProcessHelper.cs @@ -41,4 +41,4 @@ public static class ProcessHelper }; return Process.Start(processInfo); } -} +} \ No newline at end of file diff --git a/src/Snap.Hutao/Snap.Hutao/Core/Setting/LocalSetting.cs b/src/Snap.Hutao/Snap.Hutao/Core/Setting/LocalSetting.cs index f536d772..7a8f9640 100644 --- a/src/Snap.Hutao/Snap.Hutao/Core/Setting/LocalSetting.cs +++ b/src/Snap.Hutao/Snap.Hutao/Core/Setting/LocalSetting.cs @@ -10,10 +10,6 @@ namespace Snap.Hutao.Core.Setting; /// internal static class LocalSetting { - /// - /// 由于 没有 nullable context, - /// 在处理引用类型时需要格外小心 - /// private static readonly ApplicationDataContainer Container; static LocalSetting() @@ -21,6 +17,198 @@ internal static class LocalSetting Container = ApplicationData.Current.LocalSettings; } + /// + public static byte Get(string key, byte defaultValue) + { + return Get(key, defaultValue); + } + + /// + public static short Get(string key, short defaultValue) + { + return Get(key, defaultValue); + } + + /// + public static ushort Get(string key, ushort defaultValue) + { + return Get(key, defaultValue); + } + + /// + public static int Get(string key, int defaultValue) + { + return Get(key, defaultValue); + } + + /// + public static uint Get(string key, uint defaultValue) + { + return Get(key, defaultValue); + } + + /// + public static ulong Get(string key, ulong defaultValue) + { + return Get(key, defaultValue); + } + + /// + public static float Get(string key, float defaultValue) + { + return Get(key, defaultValue); + } + + /// + public static double Get(string key, double defaultValue) + { + return Get(key, defaultValue); + } + + /// + public static bool Get(string key, bool defaultValue) + { + return Get(key, defaultValue); + } + + /// + public static char Get(string key, char defaultValue) + { + return Get(key, defaultValue); + } + + /// + public static DateTimeOffset Get(string key, DateTimeOffset defaultValue) + { + return Get(key, defaultValue); + } + + /// + public static TimeSpan Get(string key, TimeSpan defaultValue) + { + return Get(key, defaultValue); + } + + /// + public static Guid Get(string key, Guid defaultValue) + { + return Get(key, defaultValue); + } + + /// + public static Windows.Foundation.Point Get(string key, Windows.Foundation.Point defaultValue) + { + return Get(key, defaultValue); + } + + /// + public static Windows.Foundation.Size Get(string key, Windows.Foundation.Size defaultValue) + { + return Get(key, defaultValue); + } + + /// + public static Windows.Foundation.Rect Get(string key, Windows.Foundation.Rect defaultValue) + { + return Get(key, defaultValue); + } + + /// + public static void Set(string key, byte value) + { + Set(key, value); + } + + /// + public static void Set(string key, short value) + { + Set(key, value); + } + + /// + public static void Set(string key, ushort value) + { + Set(key, value); + } + + /// + public static void Set(string key, int value) + { + Set(key, value); + } + + /// + public static void Set(string key, uint value) + { + Set(key, value); + } + + /// + public static void Set(string key, ulong value) + { + Set(key, value); + } + + /// + public static void Set(string key, float value) + { + Set(key, value); + } + + /// + public static void Set(string key, double value) + { + Set(key, value); + } + + /// + public static void Set(string key, bool value) + { + Set(key, value); + } + + /// + public static void Set(string key, char value) + { + Set(key, value); + } + + /// + public static void Set(string key, DateTimeOffset value) + { + Set(key, value); + } + + /// + public static void Set(string key, TimeSpan value) + { + Set(key, value); + } + + /// + public static void Set(string key, Guid value) + { + Set(key, value); + } + + /// + public static void Set(string key, Windows.Foundation.Point value) + { + Set(key, value); + } + + /// + public static void Set(string key, Windows.Foundation.Size value) + { + Set(key, value); + } + + /// + public static void Set(string key, Windows.Foundation.Rect value) + { + Set(key, value); + } + /// /// 获取设置项的值 /// @@ -28,8 +216,8 @@ internal static class LocalSetting /// 键 /// 默认值 /// 获取的值 - [return: MaybeNull] - public static T Get(string key, [AllowNull] T defaultValue = default) + private static T Get(string key, T defaultValue = default) + where T : struct { if (Container.Values.TryGetValue(key, out object? value)) { @@ -49,9 +237,9 @@ internal static class LocalSetting /// 设置项的类型 /// 键 /// 值 - /// 设置的值 - public static object? Set(string key, T value) + private static void Set(string key, T value) + where T : struct { - return Container.Values[key] = value; + Container.Values[key] = value; } } diff --git a/src/Snap.Hutao/Snap.Hutao/Core/Windowing/Persistence.cs b/src/Snap.Hutao/Snap.Hutao/Core/Windowing/Persistence.cs index 2a882ff4..431f6964 100644 --- a/src/Snap.Hutao/Snap.Hutao/Core/Windowing/Persistence.cs +++ b/src/Snap.Hutao/Snap.Hutao/Core/Windowing/Persistence.cs @@ -44,7 +44,7 @@ internal static class Persistence /// 应用窗体 public static void Save(AppWindow appWindow) { - LocalSetting.Set(SettingKeys.WindowRect, (ulong)(CompactRect)appWindow.GetRect()); + LocalSetting.Set(SettingKeys.WindowRect, (CompactRect)appWindow.GetRect()); } /// @@ -124,7 +124,7 @@ internal static class Persistence return new(rect.X, rect.Y, rect.Width, rect.Height); } - public static explicit operator ulong(CompactRect rect) + public static implicit operator ulong(CompactRect rect) { return rect.Value; } diff --git a/src/Snap.Hutao/Snap.Hutao/LaunchGameWindow.xaml b/src/Snap.Hutao/Snap.Hutao/LaunchGameWindow.xaml new file mode 100644 index 00000000..56cbbfea --- /dev/null +++ b/src/Snap.Hutao/Snap.Hutao/LaunchGameWindow.xaml @@ -0,0 +1,12 @@ + + + + + diff --git a/src/Snap.Hutao/Snap.Hutao/LaunchGameWindow.xaml.cs b/src/Snap.Hutao/Snap.Hutao/LaunchGameWindow.xaml.cs new file mode 100644 index 00000000..84f88421 --- /dev/null +++ b/src/Snap.Hutao/Snap.Hutao/LaunchGameWindow.xaml.cs @@ -0,0 +1,20 @@ +// Copyright (c) DGP Studio. All rights reserved. +// Licensed under the MIT license. + +using Microsoft.UI.Xaml; + +namespace Snap.Hutao; + +/// +/// 启动游戏窗口 +/// +public sealed partial class LaunchGameWindow : Window +{ + /// + /// 构造一个新的启动游戏窗口 + /// + public LaunchGameWindow() + { + InitializeComponent(); + } +} 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 e807f505..ec094ad6 100644 --- a/src/Snap.Hutao/Snap.Hutao/Model/Binding/Gacha/HistoryWish.cs +++ b/src/Snap.Hutao/Snap.Hutao/Model/Binding/Gacha/HistoryWish.cs @@ -10,6 +10,11 @@ namespace Snap.Hutao.Model.Binding.Gacha; /// public class HistoryWish : WishBase { + /// + /// 版本 + /// + public string Version { get; set; } + /// /// 五星Up /// diff --git a/src/Snap.Hutao/Snap.Hutao/Model/Metadata/Avatar/AvatarIds.cs b/src/Snap.Hutao/Snap.Hutao/Model/Metadata/Avatar/AvatarIds.cs deleted file mode 100644 index d7701353..00000000 --- a/src/Snap.Hutao/Snap.Hutao/Model/Metadata/Avatar/AvatarIds.cs +++ /dev/null @@ -1,76 +0,0 @@ -// Copyright (c) DGP Studio. All rights reserved. -// Licensed under the MIT license. - -namespace Snap.Hutao.Model.Metadata.Avatar; - -/// -/// 角色ID -/// -[SuppressMessage("", "SA1600")] -public static class AvatarIds -{ - public const int Ayaka = 10000002; - public const int Qin = 10000003; - - public const int Lisa = 10000006; - - public const int Barbara = 10000014; - public const int Kaeya = 10000015; - public const int Diluc = 10000016; - - public const int Razor = 10000020; - public const int Ambor = 10000021; - public const int Venti = 10000022; - public const int Xiangling = 10000023; - public const int Beidou = 10000024; - public const int Xingqiu = 10000025; - public const int Xiao = 10000026; - public const int Ningguang = 10000027; - - public const int Klee = 10000029; - public const int Zhongli = 10000030; - public const int Fischl = 10000031; - public const int Bennett = 10000032; - public const int Tartaglia = 10000033; - public const int Noel = 10000034; - public const int Qiqi = 10000035; - public const int Chongyun = 10000036; - public const int Ganyu = 10000037; - public const int Albedo = 10000038; - public const int Diona = 10000039; - - public const int Mona = 10000041; - public const int Keqing = 10000042; - public const int Sucrose = 10000043; - public const int Xinyan = 10000044; - public const int Rosaria = 10000045; - public const int Hutao = 10000046; - public const int Kazuha = 10000047; - public const int Feiyan = 10000048; - public const int Yoimiya = 10000049; - public const int Tohma = 10000050; - public const int Eula = 10000051; - public const int Shougun = 10000052; - public const int Sayu = 10000053; - public const int Kokomi = 10000054; - public const int Gorou = 10000055; - public const int Sara = 10000056; - public const int Itto = 10000057; - public const int Yae = 10000058; - public const int Heizou = 10000059; - public const int Yelan = 10000060; - - public const int Aloy = 10000062; - public const int Shenhe = 10000063; - public const int Yunjin = 10000064; - public const int Shinobu = 10000065; - public const int Ayato = 10000066; - public const int Collei = 10000067; - public const int Dori = 10000068; - public const int Tighnari = 10000069; - public const int Nilou = 10000070; - public const int Cyno = 10000071; - public const int Candace = 10000072; - public const int Nahida = 10000073; - public const int Layla = 10000074; -} \ No newline at end of file diff --git a/src/Snap.Hutao/Snap.Hutao/Model/Metadata/Avatar/CookBonus.cs b/src/Snap.Hutao/Snap.Hutao/Model/Metadata/Avatar/CookBonus.cs new file mode 100644 index 00000000..9fbdb57b --- /dev/null +++ b/src/Snap.Hutao/Snap.Hutao/Model/Metadata/Avatar/CookBonus.cs @@ -0,0 +1,57 @@ +// Copyright (c) DGP Studio. All rights reserved. +// Licensed under the MIT license. + +using Snap.Hutao.Model.Intrinsic; + +namespace Snap.Hutao.Model.Metadata.Avatar; + +/// +/// 料理奖励 +/// +public class CookBonus +{ + /// + /// 原型名称 + /// + public string OriginName { get; set; } = default!; + + /// + /// 原型描述 + /// + public string OriginDescription { get; set; } = default!; + + /// + /// 原型图标 + /// + public string OriginIcon { get; set; } = default!; + + /// + /// 名称 + /// + public string Name { get; set; } = default!; + + /// + /// 描述 + /// + public string Description { get; set; } = default!; + + /// + /// 效果描述 + /// + public string EffectDescription { get; set; } = default!; + + /// + /// 图标 + /// + public string Icon { get; set; } = default!; + + /// + /// 物品等级 + /// + public ItemQuality RankLevel { get; set; } + + /// + /// 材料列表 + /// + public List InputList { get; set; } = default!; +} \ No newline at end of file diff --git a/src/Snap.Hutao/Snap.Hutao/Model/Metadata/Avatar/FetterInfo.cs b/src/Snap.Hutao/Snap.Hutao/Model/Metadata/Avatar/FetterInfo.cs index 0656f765..d1dc472e 100644 --- a/src/Snap.Hutao/Snap.Hutao/Model/Metadata/Avatar/FetterInfo.cs +++ b/src/Snap.Hutao/Snap.Hutao/Model/Metadata/Avatar/FetterInfo.cs @@ -76,6 +76,11 @@ public class FetterInfo /// public string CvKorean { get; set; } = default!; + /// + /// 料理 + /// + public CookBonus? CookBonus { get; set; } + /// /// 好感语音 /// diff --git a/src/Snap.Hutao/Snap.Hutao/Model/Metadata/Avatar/ItemWithCount.cs b/src/Snap.Hutao/Snap.Hutao/Model/Metadata/Avatar/ItemWithCount.cs new file mode 100644 index 00000000..45b572f2 --- /dev/null +++ b/src/Snap.Hutao/Snap.Hutao/Model/Metadata/Avatar/ItemWithCount.cs @@ -0,0 +1,37 @@ +// Copyright (c) DGP Studio. All rights reserved. +// Licensed under the MIT license. + +using Snap.Hutao.Model.Intrinsic; + +namespace Snap.Hutao.Model.Metadata.Avatar; + +/// +/// 带有个数的物品 +/// +public class ItemWithCount +{ + /// + /// 物品Id + /// + public int Id { get; set; } + + /// + /// 名称 + /// + public string Name { get; set; } = default!; + + /// + /// 图标 + /// + public string Icon { get; set; } = default!; + + /// + /// 物品等级 + /// + public ItemQuality RankLevel { get; set; } + + /// + /// 数量 + /// + public int Count { get; set; } +} \ No newline at end of file diff --git a/src/Snap.Hutao/Snap.Hutao/Model/Metadata/AvatarIds.cs b/src/Snap.Hutao/Snap.Hutao/Model/Metadata/AvatarIds.cs new file mode 100644 index 00000000..aa0c305d --- /dev/null +++ b/src/Snap.Hutao/Snap.Hutao/Model/Metadata/AvatarIds.cs @@ -0,0 +1,78 @@ +// Copyright (c) DGP Studio. All rights reserved. +// Licensed under the MIT license. + +using Snap.Hutao.Model.Primitive; + +namespace Snap.Hutao.Model.Metadata; + +/// +/// 角色ID +/// +[SuppressMessage("", "SA1600")] +public static class AvatarIds +{ + public static readonly AvatarId Ayaka = 10000002; + public static readonly AvatarId Qin = 10000003; + + public static readonly AvatarId Lisa = 10000006; + + public static readonly AvatarId Barbara = 10000014; + public static readonly AvatarId Kaeya = 10000015; + public static readonly AvatarId Diluc = 10000016; + + public static readonly AvatarId Razor = 10000020; + public static readonly AvatarId Ambor = 10000021; + public static readonly AvatarId Venti = 10000022; + public static readonly AvatarId Xiangling = 10000023; + public static readonly AvatarId Beidou = 10000024; + public static readonly AvatarId Xingqiu = 10000025; + public static readonly AvatarId Xiao = 10000026; + public static readonly AvatarId Ningguang = 10000027; + + public static readonly AvatarId Klee = 10000029; + public static readonly AvatarId Zhongli = 10000030; + public static readonly AvatarId Fischl = 10000031; + public static readonly AvatarId Bennett = 10000032; + public static readonly AvatarId Tartaglia = 10000033; + public static readonly AvatarId Noel = 10000034; + public static readonly AvatarId Qiqi = 10000035; + public static readonly AvatarId Chongyun = 10000036; + public static readonly AvatarId Ganyu = 10000037; + public static readonly AvatarId Albedo = 10000038; + public static readonly AvatarId Diona = 10000039; + + public static readonly AvatarId Mona = 10000041; + public static readonly AvatarId Keqing = 10000042; + public static readonly AvatarId Sucrose = 10000043; + public static readonly AvatarId Xinyan = 10000044; + public static readonly AvatarId Rosaria = 10000045; + public static readonly AvatarId Hutao = 10000046; + public static readonly AvatarId Kazuha = 10000047; + public static readonly AvatarId Feiyan = 10000048; + public static readonly AvatarId Yoimiya = 10000049; + public static readonly AvatarId Tohma = 10000050; + public static readonly AvatarId Eula = 10000051; + public static readonly AvatarId Shougun = 10000052; + public static readonly AvatarId Sayu = 10000053; + public static readonly AvatarId Kokomi = 10000054; + public static readonly AvatarId Gorou = 10000055; + public static readonly AvatarId Sara = 10000056; + public static readonly AvatarId Itto = 10000057; + public static readonly AvatarId Yae = 10000058; + public static readonly AvatarId Heizou = 10000059; + public static readonly AvatarId Yelan = 10000060; + + public static readonly AvatarId Aloy = 10000062; + public static readonly AvatarId Shenhe = 10000063; + public static readonly AvatarId Yunjin = 10000064; + public static readonly AvatarId Shinobu = 10000065; + public static readonly AvatarId Ayato = 10000066; + public static readonly AvatarId Collei = 10000067; + public static readonly AvatarId Dori = 10000068; + public static readonly AvatarId Tighnari = 10000069; + public static readonly AvatarId Nilou = 10000070; + public static readonly AvatarId Cyno = 10000071; + public static readonly AvatarId Candace = 10000072; + public static readonly AvatarId Nahida = 10000073; + public static readonly AvatarId Layla = 10000074; +} \ No newline at end of file diff --git a/src/Snap.Hutao/Snap.Hutao/Model/Metadata/Converter/GachaAvatarIconConverter.cs b/src/Snap.Hutao/Snap.Hutao/Model/Metadata/Converter/GachaAvatarIconConverter.cs new file mode 100644 index 00000000..cc31af11 --- /dev/null +++ b/src/Snap.Hutao/Snap.Hutao/Model/Metadata/Converter/GachaAvatarIconConverter.cs @@ -0,0 +1,31 @@ +// Copyright (c) DGP Studio. All rights reserved. +// Licensed under the MIT license. + +using Snap.Hutao.Control; + +namespace Snap.Hutao.Model.Metadata.Converter; + +/// +/// 立绘图标转换器 +/// +internal class GachaAvatarIconConverter : ValueConverterBase +{ + private const string BaseUrl = "https://static.snapgenshin.com/GachaAvatarIcon/UI_Gacha_AvatarIcon_{0}.png"; + + /// + /// 名称转Uri + /// + /// 名称 + /// 链接 + public static Uri IconNameToUri(string name) + { + name = name["UI_AvatarIcon_".Length..]; + return new Uri(string.Format(BaseUrl, name)); + } + + /// + public override Uri Convert(string from) + { + return IconNameToUri(from); + } +} \ No newline at end of file diff --git a/src/Snap.Hutao/Snap.Hutao/Model/Metadata/Converter/GachaAvatarImgConverter.cs b/src/Snap.Hutao/Snap.Hutao/Model/Metadata/Converter/GachaAvatarImgConverter.cs index b0b192c5..5062adf2 100644 --- a/src/Snap.Hutao/Snap.Hutao/Model/Metadata/Converter/GachaAvatarImgConverter.cs +++ b/src/Snap.Hutao/Snap.Hutao/Model/Metadata/Converter/GachaAvatarImgConverter.cs @@ -6,7 +6,7 @@ using Snap.Hutao.Control; namespace Snap.Hutao.Model.Metadata.Converter; /// -/// 角色头像转换器 +/// 立绘转换器 /// internal class GachaAvatarImgConverter : ValueConverterBase { diff --git a/src/Snap.Hutao/Snap.Hutao/Model/Metadata/Converter/ItemIconConverter.cs b/src/Snap.Hutao/Snap.Hutao/Model/Metadata/Converter/ItemIconConverter.cs new file mode 100644 index 00000000..dd306fc7 --- /dev/null +++ b/src/Snap.Hutao/Snap.Hutao/Model/Metadata/Converter/ItemIconConverter.cs @@ -0,0 +1,30 @@ +// Copyright (c) DGP Studio. All rights reserved. +// Licensed under the MIT license. + +using Snap.Hutao.Control; + +namespace Snap.Hutao.Model.Metadata.Converter; + +/// +/// 物品图片转换器 +/// +internal class ItemIconConverter : ValueConverterBase +{ + private const string BaseUrl = "https://static.snapgenshin.com/ItemIcon/{0}.png"; + + /// + /// 名称转Uri + /// + /// 名称 + /// 链接 + public static Uri IconNameToUri(string name) + { + return new Uri(string.Format(BaseUrl, name)); + } + + /// + public override Uri Convert(string from) + { + return IconNameToUri(from); + } +} \ 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 9ca299b2..345cb15d 100644 --- a/src/Snap.Hutao/Snap.Hutao/Model/Metadata/GachaEvent.cs +++ b/src/Snap.Hutao/Snap.Hutao/Model/Metadata/GachaEvent.cs @@ -15,6 +15,11 @@ public class GachaEvent /// public string Name { get; set; } = default!; + /// + /// 版本 + /// + public string Version { get; set; } = default!; + /// /// 开始时间 /// diff --git a/src/Snap.Hutao/Snap.Hutao/Package.appxmanifest b/src/Snap.Hutao/Snap.Hutao/Package.appxmanifest index 1a04cd71..dae27fae 100644 --- a/src/Snap.Hutao/Snap.Hutao/Package.appxmanifest +++ b/src/Snap.Hutao/Snap.Hutao/Package.appxmanifest @@ -9,7 +9,7 @@ + Version="1.1.14.0" /> 胡桃 diff --git a/src/Snap.Hutao/Snap.Hutao/Program.cs b/src/Snap.Hutao/Snap.Hutao/Program.cs index aa64a0a5..546e537e 100644 --- a/src/Snap.Hutao/Snap.Hutao/Program.cs +++ b/src/Snap.Hutao/Snap.Hutao/Program.cs @@ -7,7 +7,6 @@ using Microsoft.UI.Dispatching; using Microsoft.UI.Xaml; using Snap.Hutao.Core.Logging; using System.Runtime.InteropServices; -using Windows.UI.ViewManagement; using WinRT; namespace Snap.Hutao; @@ -32,6 +31,7 @@ public static partial class Program private static void Main(string[] args) { _ = args; + XamlCheckProcessRequirements(); ComWrappersSupport.InitializeComWrappers(); @@ -75,7 +75,6 @@ public static partial class Program // Discrete services .AddSingleton(WeakReferenceMessenger.Default) - .AddSingleton(new UISettings()) .BuildServiceProvider(); diff --git a/src/Snap.Hutao/Snap.Hutao/Resource/Icon/UI_GuideIcon_PlayMethod.png b/src/Snap.Hutao/Snap.Hutao/Resource/Icon/UI_GuideIcon_PlayMethod.png new file mode 100644 index 00000000..71b3db69 Binary files /dev/null and b/src/Snap.Hutao/Snap.Hutao/Resource/Icon/UI_GuideIcon_PlayMethod.png differ diff --git a/src/Snap.Hutao/Snap.Hutao/Service/AvatarInfo/Factory/ReliquaryWeightConfiguration.cs b/src/Snap.Hutao/Snap.Hutao/Service/AvatarInfo/Factory/ReliquaryWeightConfiguration.cs index b7e69a58..b370c247 100644 --- a/src/Snap.Hutao/Snap.Hutao/Service/AvatarInfo/Factory/ReliquaryWeightConfiguration.cs +++ b/src/Snap.Hutao/Snap.Hutao/Service/AvatarInfo/Factory/ReliquaryWeightConfiguration.cs @@ -2,7 +2,7 @@ // Licensed under the MIT license. using Snap.Hutao.Model.Intrinsic; -using Snap.Hutao.Model.Metadata.Avatar; +using Snap.Hutao.Model.Metadata; namespace Snap.Hutao.Service.AvatarInfo.Factory; 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 acddb2e9..2f2e51dd 100644 --- a/src/Snap.Hutao/Snap.Hutao/Service/GachaLog/Factory/HistoryWishBuilder.cs +++ b/src/Snap.Hutao/Snap.Hutao/Service/GachaLog/Factory/HistoryWishBuilder.cs @@ -147,6 +147,7 @@ internal class HistoryWishBuilder TotalCount = totalCountTracker, // fill + Version = gachaEvent.Version, 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 4196cc51..e5ef503f 100644 --- a/src/Snap.Hutao/Snap.Hutao/Service/Game/GameService.cs +++ b/src/Snap.Hutao/Snap.Hutao/Service/Game/GameService.cs @@ -1,82 +1,181 @@ // Copyright (c) DGP Studio. All rights reserved. // Licensed under the MIT license. -using Microsoft.EntityFrameworkCore; using Microsoft.Extensions.Caching.Memory; +using Microsoft.Extensions.DependencyInjection; using Snap.Hutao.Context.Database; +using Snap.Hutao.Core; using Snap.Hutao.Core.Database; using Snap.Hutao.Core.Threading; using Snap.Hutao.Model.Entity; using Snap.Hutao.Service.Game.Locator; +using Snap.Hutao.Service.Game.Unlocker; +using System.Diagnostics; +using System.IO; namespace Snap.Hutao.Service.Game; /// /// 游戏服务 /// -[Injection(InjectAs.Transient, typeof(IGameService))] +[Injection(InjectAs.Singleton, typeof(IGameService))] internal class GameService : IGameService { - private readonly AppDbContext appDbContext; + private const string GamePathKey = $"{nameof(GameService)}.Cache.{SettingEntry.GamePath}"; + + private readonly IServiceScopeFactory scopeFactory; private readonly IMemoryCache memoryCache; - private readonly IEnumerable gameLocators; + private readonly SemaphoreSlim gameSemaphore = new(1); /// /// 构造一个新的游戏服务 /// - /// 数据库上下文 + /// 范围工厂 /// 内存缓存 /// 游戏定位器集合 - public GameService(AppDbContext appDbContext, IMemoryCache memoryCache, IEnumerable gameLocators) + public GameService(IServiceScopeFactory scopeFactory, IMemoryCache memoryCache) { - this.appDbContext = appDbContext; + this.scopeFactory = scopeFactory; this.memoryCache = memoryCache; - this.gameLocators = gameLocators; } /// public async ValueTask> GetGamePathAsync() { - string key = $"{nameof(GameService)}.Cache.{SettingEntry.GamePath}"; - - if (memoryCache.TryGetValue(key, out object? value)) + if (memoryCache.TryGetValue(GamePathKey, out object? value)) { return new(true, Must.NotNull((value as string)!)); } else { - SettingEntry entry = appDbContext.Settings.SingleOrAdd(e => e.Key == SettingEntry.GamePath, () => new(SettingEntry.GamePath, null), out bool added); - - // Cannot find in setting - if (added) + using (IServiceScope scope = scopeFactory.CreateScope()) { - // Try locate by registry - IGameLocator locator = gameLocators.Single(l => l.Name == nameof(RegistryLauncherLocator)); - ValueResult result = await locator.LocateGamePathAsync().ConfigureAwait(false); + AppDbContext appDbContext = scope.ServiceProvider.GetRequiredService(); - if (!result.IsOk) + SettingEntry entry = appDbContext.Settings.SingleOrAdd(e => e.Key == SettingEntry.GamePath, () => new(SettingEntry.GamePath, null), out bool added); + + // Cannot find in setting + if (added) { - // Try locate manually - locator = gameLocators.Single(l => l.Name == nameof(ManualGameLocator)); - result = await locator.LocateGamePathAsync().ConfigureAwait(false); + IEnumerable gameLocators = scope.ServiceProvider.GetRequiredService>(); + + // Try locate by registry + IGameLocator locator = gameLocators.Single(l => l.Name == nameof(RegistryLauncherLocator)); + ValueResult result = await locator.LocateGamePathAsync().ConfigureAwait(false); + + if (!result.IsOk) + { + // Try locate manually + locator = gameLocators.Single(l => l.Name == nameof(ManualGameLocator)); + result = await locator.LocateGamePathAsync().ConfigureAwait(false); + } + + if (result.IsOk) + { + // Save result. + entry.Value = result.Value; + appDbContext.Settings.UpdateAndSave(entry); + } + else + { + return new(false, null!); + } } - if (result.IsOk) + // Set cache and return. + string path = memoryCache.Set(GamePathKey, Must.NotNull(entry.Value!)); + return new(true, path); + } + } + } + + /// + public string GetGamePathSkipLocator() + { + if (memoryCache.TryGetValue(GamePathKey, out object? value)) + { + return (value as string)!; + } + else + { + using (IServiceScope scope = scopeFactory.CreateScope()) + { + AppDbContext appDbContext = scope.ServiceProvider.GetRequiredService(); + SettingEntry entry = appDbContext.Settings.SingleOrAdd(e => e.Key == SettingEntry.GamePath, () => new(SettingEntry.GamePath, null), out bool added); + + entry.Value ??= string.Empty; + appDbContext.Settings.UpdateAndSave(entry); + + // Set cache and return. + return memoryCache.Set(GamePathKey, entry.Value); + } + } + } + + /// + public void OverwriteGamePath(string path) + { + // sync cache + memoryCache.Set(GamePathKey, path); + + using (IServiceScope scope = scopeFactory.CreateScope()) + { + AppDbContext appDbContext = scope.ServiceProvider.GetRequiredService(); + + SettingEntry entry = appDbContext.Settings.SingleOrAdd(e => e.Key == SettingEntry.GamePath, () => new(SettingEntry.GamePath, null), out _); + entry.Value = path; + appDbContext.Settings.UpdateAndSave(entry); + } + } + + /// + public async ValueTask LaunchAsync(LaunchConfiguration configuration) + { + (bool isOk, string gamePath) = await GetGamePathAsync().ConfigureAwait(false); + + if (isOk) + { + if (gameSemaphore.CurrentCount == 0) + { + return; + } + + 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(); + + Process game = new() + { + StartInfo = new() { - // Save result. - entry.Value = result.Value; - appDbContext.Settings.Update(entry); - await appDbContext.SaveChangesAsync().ConfigureAwait(false); + Arguments = commandLine, + FileName = gamePath, + UseShellExecute = true, + Verb = "runas", + WorkingDirectory = Path.GetDirectoryName(gamePath), + }, + }; + + using (await gameSemaphore.EnterAsync().ConfigureAwait(false)) + { + if (configuration.UnlockFPS) + { + IGameFpsUnlocker unlocker = new GameFpsUnlocker(game, configuration.TargetFPS); + + await unlocker.UnlockAsync(TimeSpan.FromMilliseconds(100), TimeSpan.FromMilliseconds(10000), TimeSpan.FromMilliseconds(2000)).ConfigureAwait(false); } else { - return new(false, null!); + if (game.Start()) + { + await game.WaitForExitAsync().ConfigureAwait(false); + } } } - - // Set cache and return. - string path = memoryCache.Set(key, Must.NotNull(entry.Value!)); - return new(true, path); } } } \ No newline at end of file diff --git a/src/Snap.Hutao/Snap.Hutao/Service/Game/IGameService.cs b/src/Snap.Hutao/Snap.Hutao/Service/Game/IGameService.cs index fb9aef99..966aed6c 100644 --- a/src/Snap.Hutao/Snap.Hutao/Service/Game/IGameService.cs +++ b/src/Snap.Hutao/Snap.Hutao/Service/Game/IGameService.cs @@ -15,4 +15,23 @@ internal interface IGameService /// /// 结果 ValueTask> GetGamePathAsync(); + + /// + /// 获取游戏路径,跳过异步定位器 + /// + /// 游戏路径,当路径无效时会设置并返回 + string GetGamePathSkipLocator(); + + /// + /// 异步启动 + /// + /// 启动配置 + /// 任务 + ValueTask LaunchAsync(LaunchConfiguration configuration); + + /// + /// 重写游戏路径 + /// + /// 路径 + void OverwriteGamePath(string path); } \ No newline at end of file diff --git a/src/Snap.Hutao/Snap.Hutao/Service/Game/LaunchConfiguration.cs b/src/Snap.Hutao/Snap.Hutao/Service/Game/LaunchConfiguration.cs new file mode 100644 index 00000000..d28923b1 --- /dev/null +++ b/src/Snap.Hutao/Snap.Hutao/Service/Game/LaunchConfiguration.cs @@ -0,0 +1,45 @@ +// Copyright (c) DGP Studio. All rights reserved. +// Licensed under the MIT license. + +namespace Snap.Hutao.Service.Game; + +/// +/// 启动游戏配置 +/// +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 UnlockFPS { get; private set; } + + /// + /// 目标帧率 + /// + public int TargetFPS { get; private set; } + + /// + /// 窗口宽度 + /// + public int ScreenWidth { get; private set; } + + /// + /// 窗口高度 + /// + public int ScreenHeight { get; private set; } + + /// + /// 显示器编号 + /// + public int Monitor { get; private set; } +} \ No newline at end of file diff --git a/src/Snap.Hutao/Snap.Hutao/Service/Hutao/HutaoCache.cs b/src/Snap.Hutao/Snap.Hutao/Service/Hutao/HutaoCache.cs index 66541172..4884b33e 100644 --- a/src/Snap.Hutao/Snap.Hutao/Service/Hutao/HutaoCache.cs +++ b/src/Snap.Hutao/Snap.Hutao/Service/Hutao/HutaoCache.cs @@ -158,4 +158,4 @@ internal class HutaoCache : IHutaoCache { Overview = await hutaoService.GetOverviewAsync().ConfigureAwait(false); } -} +} \ 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 7de19a0f..4558210a 100644 --- a/src/Snap.Hutao/Snap.Hutao/Snap.Hutao.csproj +++ b/src/Snap.Hutao/Snap.Hutao/Snap.Hutao.csproj @@ -34,6 +34,7 @@ + @@ -41,6 +42,7 @@ + @@ -67,6 +69,7 @@ + @@ -93,6 +96,7 @@ + @@ -144,6 +148,16 @@ + + + MSBuild:Compile + + + + + MSBuild:Compile + + MSBuild:Compile diff --git a/src/Snap.Hutao/Snap.Hutao/View/MainView.xaml b/src/Snap.Hutao/Snap.Hutao/View/MainView.xaml index 302cefe5..9366fbd1 100644 --- a/src/Snap.Hutao/Snap.Hutao/View/MainView.xaml +++ b/src/Snap.Hutao/Snap.Hutao/View/MainView.xaml @@ -27,7 +27,12 @@ Icon="{shcm:BitmapIcon Source=ms-appx:///Resource/Icon/UI_BtnIcon_ActivityEntry.png}"/> - + + + (INavigationAwaiter.Default, true); } - - private async Task UpdateThemeAsync() - { - // It seems that UISettings.ColorValuesChanged - // event can raise up on a background thread. - await ThreadHelper.SwitchToMainThreadAsync(); - - App current = Ioc.Default.GetRequiredService(); - - if (!ThemeHelper.Equals(current.RequestedTheme, RequestedTheme)) - { - ILogger logger = Ioc.Default.GetRequiredService>(); - logger.LogInformation(EventIds.CommonLog, "Element Theme [{element}] | App Theme [{app}]", RequestedTheme, current.RequestedTheme); - - // Update controls' theme which presents in the PopupRoot - RequestedTheme = ThemeHelper.ApplicationToElement(current.RequestedTheme); - } - } } \ No newline at end of file diff --git a/src/Snap.Hutao/Snap.Hutao/View/Page/AchievementPage.xaml b/src/Snap.Hutao/Snap.Hutao/View/Page/AchievementPage.xaml index b6cfd7ee..beb0f4bb 100644 --- a/src/Snap.Hutao/Snap.Hutao/View/Page/AchievementPage.xaml +++ b/src/Snap.Hutao/Snap.Hutao/View/Page/AchievementPage.xaml @@ -4,24 +4,17 @@ xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" - xmlns:cwuc="using:CommunityToolkit.WinUI.UI.Converters" xmlns:mxic="using:Microsoft.Xaml.Interactions.Core" xmlns:mxi="using:Microsoft.Xaml.Interactivity" xmlns:shc="using:Snap.Hutao.Control" xmlns:shcb="using:Snap.Hutao.Control.Behavior" xmlns:shci="using:Snap.Hutao.Control.Image" xmlns:shcm="using:Snap.Hutao.Control.Markup" - xmlns:shmmc="using:Snap.Hutao.Model.Metadata.Converter" xmlns:shv="using:Snap.Hutao.ViewModel" mc:Ignorable="d" Background="{ThemeResource ApplicationPageBackgroundThemeBrush}" d:DataContext="{d:DesignInstance shv:AchievementViewModel}"> - - - - - diff --git a/src/Snap.Hutao/Snap.Hutao/View/Page/AnnouncementPage.xaml b/src/Snap.Hutao/Snap.Hutao/View/Page/AnnouncementPage.xaml index cbcf9f46..6da2956c 100644 --- a/src/Snap.Hutao/Snap.Hutao/View/Page/AnnouncementPage.xaml +++ b/src/Snap.Hutao/Snap.Hutao/View/Page/AnnouncementPage.xaml @@ -8,7 +8,6 @@ xmlns:cwua="using:CommunityToolkit.WinUI.UI.Animations" xmlns:cwub="using:CommunityToolkit.WinUI.UI.Behaviors" xmlns:cwucont="using:CommunityToolkit.WinUI.UI.Controls" - xmlns:cwuconv="using:CommunityToolkit.WinUI.UI.Converters" xmlns:mxic="using:Microsoft.Xaml.Interactions.Core" xmlns:mxi="using:Microsoft.Xaml.Interactivity" xmlns:shc="using:Snap.Hutao.Control" @@ -21,7 +20,6 @@ - diff --git a/src/Snap.Hutao/Snap.Hutao/View/Page/AvatarPropertyPage.xaml b/src/Snap.Hutao/Snap.Hutao/View/Page/AvatarPropertyPage.xaml index 45890b33..25028275 100644 --- a/src/Snap.Hutao/Snap.Hutao/View/Page/AvatarPropertyPage.xaml +++ b/src/Snap.Hutao/Snap.Hutao/View/Page/AvatarPropertyPage.xaml @@ -36,8 +36,6 @@ 0.5 - - diff --git a/src/Snap.Hutao/Snap.Hutao/View/Page/GachaLogPage.xaml b/src/Snap.Hutao/Snap.Hutao/View/Page/GachaLogPage.xaml index 582e8578..548c31d2 100644 --- a/src/Snap.Hutao/Snap.Hutao/View/Page/GachaLogPage.xaml +++ b/src/Snap.Hutao/Snap.Hutao/View/Page/GachaLogPage.xaml @@ -140,10 +140,17 @@ - + + + + + @@ -26,11 +28,15 @@ - - + + - - + + + + + + diff --git a/src/Snap.Hutao/Snap.Hutao/View/Page/LaunchGamePage.xaml b/src/Snap.Hutao/Snap.Hutao/View/Page/LaunchGamePage.xaml new file mode 100644 index 00000000..2d400f9e --- /dev/null +++ b/src/Snap.Hutao/Snap.Hutao/View/Page/LaunchGamePage.xaml @@ -0,0 +1,132 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +