Compare commits

..

15 Commits

Author SHA1 Message Date
qhy040404
402bb17507 impl #1434 2024-03-05 22:41:08 +08:00
DismissedLight
dcac7ac792 Merge pull request #1431 from DGP-Studio/fix/minor 2024-03-05 21:45:00 +08:00
qhy040404
d157476a9a minor fix 2024-03-03 21:37:44 +08:00
Lightczx
506d198167 update to was 1.5 2024-03-01 09:30:43 +08:00
DismissedLight
9c2131cb9d Merge pull request #1426 from DGP-Studio/dependabot/nuget/src/Snap.Hutao/develop/packages-dcc47c4d6c 2024-02-27 09:21:58 +08:00
DismissedLight
896e3d49f2 Merge branch 'develop' into dependabot/nuget/src/Snap.Hutao/develop/packages-dcc47c4d6c 2024-02-27 09:21:30 +08:00
DismissedLight
7da24790c4 Merge pull request #1423 from Masterain98/main 2024-02-26 17:02:25 +08:00
DismissedLight
ebf163f200 Merge branch 'develop' into dependabot/nuget/src/Snap.Hutao/develop/packages-dcc47c4d6c 2024-02-26 16:59:23 +08:00
Lightczx
26043a6a73 Add furniture data struct 2024-02-26 16:35:36 +08:00
Masterain
ad67001556 Update LaunchGame.png 2024-02-26 15:28:25 +08:00
dependabot[bot]
428cd35a7f Bump the packages group in /src/Snap.Hutao with 3 updates
Bumps the packages group in /src/Snap.Hutao with 3 updates: [MSTest.TestAdapter](https://github.com/microsoft/testfx), [MSTest.TestFramework](https://github.com/microsoft/testfx) and [coverlet.collector](https://github.com/coverlet-coverage/coverlet).


Updates `MSTest.TestAdapter` from 3.2.1 to 3.2.2
- [Release notes](https://github.com/microsoft/testfx/releases)
- [Changelog](https://github.com/microsoft/testfx/blob/main/docs/Changelog.md)
- [Commits](https://github.com/microsoft/testfx/compare/v3.2.1...v3.2.2)

Updates `MSTest.TestFramework` from 3.2.1 to 3.2.2
- [Release notes](https://github.com/microsoft/testfx/releases)
- [Changelog](https://github.com/microsoft/testfx/blob/main/docs/Changelog.md)
- [Commits](https://github.com/microsoft/testfx/compare/v3.2.1...v3.2.2)

Updates `coverlet.collector` from 6.0.0 to 6.0.1
- [Release notes](https://github.com/coverlet-coverage/coverlet/releases)
- [Commits](https://github.com/coverlet-coverage/coverlet/compare/v6.0.0...v6.0.1)

---
updated-dependencies:
- dependency-name: MSTest.TestAdapter
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: packages
- dependency-name: MSTest.TestFramework
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: packages
- dependency-name: coverlet.collector
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: packages
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-02-26 07:16:52 +00:00
qhy040404
1cf3450264 fix static resource download 2024-02-25 23:29:45 +08:00
DismissedLight
1849ac16da adjust regex 2024-02-25 16:23:45 +08:00
DismissedLight
4e9d87af50 fix ja-jp announcement 2024-02-25 15:53:09 +08:00
DismissedLight
eb125e547f add mask when no backdrop 2024-02-24 20:24:46 +08:00
43 changed files with 502 additions and 303 deletions

View File

@@ -15,7 +15,7 @@
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.9.0" />
<PackageReference Include="MSTest.TestAdapter" Version="3.2.1" />
<PackageReference Include="MSTest.TestFramework" Version="3.2.1" />
<PackageReference Include="coverlet.collector" Version="6.0.0">
<PackageReference Include="coverlet.collector" Version="6.0.1">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>

View File

@@ -41,14 +41,12 @@ internal class ScopedPage : Page
/// 应当在 InitializeComponent() 前调用
/// </summary>
/// <typeparam name="TViewModel">视图模型类型</typeparam>
protected TViewModel InitializeWith<TViewModel>()
protected void InitializeWith<TViewModel>()
where TViewModel : class, IViewModel
{
IViewModel viewModel = currentScope.ServiceProvider.GetRequiredService<TViewModel>();
viewModel.CancellationToken = viewCancellationTokenSource.Token;
DataContext = viewModel;
return (TViewModel)viewModel;
}
/// <inheritdoc/>

View File

@@ -25,6 +25,7 @@ internal static partial class IocHttpClientConfiguration
.ConfigurePrimaryHttpMessageHandler((handler, provider) =>
{
HttpClientHandler clientHandler = (HttpClientHandler)handler;
clientHandler.AllowAutoRedirect = true;
clientHandler.UseProxy = true;
clientHandler.Proxy = provider.GetRequiredService<DynamicHttpProxy>();
});

View File

@@ -23,8 +23,16 @@ internal sealed partial class ExceptionRecorder
public void Record(Application app)
{
app.UnhandledException += OnAppUnhandledException;
app.DebugSettings.FailFastOnErrors = false;
app.DebugSettings.IsBindingTracingEnabled = true;
app.DebugSettings.BindingFailed += OnXamlBindingFailed;
app.DebugSettings.IsXamlResourceReferenceTracingEnabled = true;
app.DebugSettings.XamlResourceReferenceFailed += OnXamlResourceReferenceFailed;
app.DebugSettings.LayoutCycleTracingLevel = LayoutCycleTracingLevel.High;
app.DebugSettings.LayoutCycleDebugBreakLevel = LayoutCycleDebugBreakLevel.High;
}
[SuppressMessage("", "CA2012")]

View File

@@ -0,0 +1,17 @@
// Copyright (c) DGP Studio. All rights reserved.
// Licensed under the MIT license.
namespace Snap.Hutao.Core.Windowing;
[Localization]
internal enum Theme
{
[LocalizationKey(nameof(SH.CoreWindowThemeLight))]
Light,
[LocalizationKey(nameof(SH.CoreWindowThemeDark))]
Dark,
[LocalizationKey(nameof(SH.CoreWindowThemeSystem))]
System,
}

View File

@@ -129,6 +129,13 @@ internal sealed class WindowController
UpdateSystemBackdrop(options.BackdropType);
}
}
else if (e.PropertyName is nameof(AppOptions.Theme))
{
if (sender is AppOptions options)
{
UpdateTheme(options.Theme);
}
}
}
private void OnWindowClosed(object sender, WindowEventArgs args)
@@ -170,6 +177,16 @@ internal sealed class WindowController
};
}
private void UpdateTheme(Theme theme)
{
((FrameworkElement)window.Content).RequestedTheme = theme switch
{
Theme.Light => ElementTheme.Light,
Theme.Dark => ElementTheme.Dark,
_ => ElementTheme.Default,
};
}
private void UpdateTitleButtonColor()
{
AppWindowTitleBar appTitleBar = window.AppWindow.TitleBar;

View File

@@ -41,6 +41,30 @@
"Equatable": true,
"EqualityOperators": true
},
{
"Name": "FurnitureId",
"Documentation": "家具 Id",
"Equatable": true,
"EqualityOperators": true
},
{
"Name": "FurnitureMakeId",
"Documentation": "家具配方 Id",
"Equatable": true,
"EqualityOperators": true
},
{
"Name": "FurnitureSuiteId",
"Documentation": "家具套装 Id",
"Equatable": true,
"EqualityOperators": true
},
{
"Name": "FurnitureTypeId",
"Documentation": "家具分类 Id",
"Equatable": true,
"EqualityOperators": true
},
{
"Name": "Level",
"Documentation": "等级 1 - 90",

View File

@@ -13,6 +13,7 @@ internal sealed partial class SettingEntry
public const string Culture = "Culture";
public const string SystemBackdropType = "SystemBackdropType";
public const string Theme = "Theme";
public const string BackgroundImageType = "BackgroundImageType";
public const string AnnouncementRegion = "AnnouncementRegion";

View File

@@ -0,0 +1,25 @@
// Copyright (c) DGP Studio. All rights reserved.
// Licensed under the MIT license.
namespace Snap.Hutao.Model.Intrinsic;
internal enum FurnitureDeploySurfaceType
{
Ground = 0,
Wall = 1,
Ceil = 2,
StackObjPlane = 3,
Door = 4,
Chandelier = 5,
Floor = 6,
WallBody = 7,
Carpet = 8,
LegoRockery = 9,
Stair = 10,
NPC = 11,
Animal = 12,
Apartment = 13,
FurnitureSuite = 14,
Road = 15,
Terrain = 16,
}

View File

@@ -0,0 +1,13 @@
// Copyright (c) DGP Studio. All rights reserved.
// Licensed under the MIT license.
namespace Snap.Hutao.Model.Intrinsic;
internal enum FurnitureDeployType
{
Interior,
Exterior,
InteriorRoom,
InteriorHall,
Skybox,
}

View File

@@ -0,0 +1,14 @@
// Copyright (c) DGP Studio. All rights reserved.
// Licensed under the MIT license.
namespace Snap.Hutao.Model.Intrinsic;
internal enum GroupRecordType
{
None,
Racing,
Balloon,
Stake,
Seek,
Explosion,
}

View File

@@ -0,0 +1,26 @@
// Copyright (c) DGP Studio. All rights reserved.
// Licensed under the MIT license.
namespace Snap.Hutao.Model.Intrinsic;
internal enum SpecialFurnitureType
{
NormalFurniture,
BlockDependent,
FarmField,
TeleportPoint,
Fishpond,
Npc,
Apartment,
FurnitureSuite,
Paimon,
Fish,
CustomBaseFurniture,
CustomNodeFurniture,
VirtualFurniture,
GroupFurniture,
CoopPictureFrame,
ChangeBgmFurniture,
ServerGadget,
Fishtank,
}

View File

@@ -8,15 +8,4 @@ namespace Snap.Hutao.Model.Metadata.Achievement;
/// <summary>
/// 奖励
/// </summary>
internal sealed class Reward
{
/// <summary>
/// Id
/// </summary>
public MaterialId Id { get; set; }
/// <summary>
/// 数量
/// </summary>
public uint Count { get; set; }
}
internal sealed class Reward : IdCount;

View File

@@ -0,0 +1,50 @@
// Copyright (c) DGP Studio. All rights reserved.
// Licensed under the MIT license.
using Snap.Hutao.Model.Intrinsic;
using Snap.Hutao.Model.Primitive;
namespace Snap.Hutao.Model.Metadata.Furniture;
internal sealed class Furniture
{
public List<FurnitureTypeId> Types { get; set; } = default!;
public FurnitureDeploySurfaceType SurfaceType { get; set; }
public bool IsSpecial { get; set; }
public SpecialFurnitureType SpecialType { get; set; }
public uint Comfort { get; set; }
public uint Cost { get; set; }
public uint DiscountCost { get; set; }
public bool CanFloat { get; set; }
public bool IsUnique { get; set; }
public string? ItemIcon { get; set; }
public string? EffectIcon { get; set; }
public QualityType RankLevel { get; set; }
public List<FurnitureId> GruopUnits { get; set; } = default!;
public GroupRecordType GroupRecordType { get; set; }
public List<string> SourceTexts { get; set; } = default!;
public FurnitureId Id { get; set; }
public string Name { get; set; } = default!;
public string Description { get; set; } = default!;
public string? Icon { get; set; }
public uint Rank { get; set; }
}

View File

@@ -0,0 +1,18 @@
// Copyright (c) DGP Studio. All rights reserved.
// Licensed under the MIT license.
using Snap.Hutao.Model.Intrinsic;
using Snap.Hutao.Model.Primitive;
namespace Snap.Hutao.Model.Metadata.Furniture;
internal sealed class FurnitureMake
{
public FurnitureMakeId Id { get; set; }
public FurnitureId ItemId { get; set; }
public uint Experience { get; set; }
public List<IdCount> Materials { get; set; } = default!;
}

View File

@@ -0,0 +1,26 @@
// Copyright (c) DGP Studio. All rights reserved.
// Licensed under the MIT license.
using Snap.Hutao.Model.Intrinsic;
using Snap.Hutao.Model.Primitive;
namespace Snap.Hutao.Model.Metadata.Furniture;
internal sealed class FurnitureSuite
{
public FurnitureSuiteId Id { get; set; }
public List<FurnitureTypeId> Types { get; set; } = default!;
public string Name { get; set; } = default!;
public string Description { get; set; } = default!;
public string ItemIcon { get; set; } = default!;
public string? MapIcon { get; set; }
public List<AvatarId>? FavoriteNpcs { get; set; }
public List<FurnitureId> Units { get; set; } = default!;
}

View File

@@ -0,0 +1,28 @@
// Copyright (c) DGP Studio. All rights reserved.
// Licensed under the MIT license.
using Snap.Hutao.Model.Intrinsic;
using Snap.Hutao.Model.Primitive;
namespace Snap.Hutao.Model.Metadata.Furniture;
internal sealed class FurnitureType
{
public FurnitureTypeId Id { get; set; }
public uint Category { get; set; }
public string Name { get; set; } = default!;
public string Name2 { get; set; } = default!;
public string TabIcon { get; set; } = default!;
public FurnitureDeployType SceneType { get; set; }
public bool BagPageOnly { get; set; }
public bool IsShowInBag { get; set; }
public uint Sort { get; set; }
}

View File

@@ -0,0 +1,20 @@
// Copyright (c) DGP Studio. All rights reserved.
// Licensed under the MIT license.
using Snap.Hutao.Model.Intrinsic;
using Snap.Hutao.Model.Primitive;
namespace Snap.Hutao.Model.Metadata;
internal class IdCount
{
/// <summary>
/// Id
/// </summary>
public MaterialId Id { get; set; }
/// <summary>
/// 数量
/// </summary>
public uint Count { get; set; }
}

View File

@@ -60,45 +60,45 @@
: and then encoded with base64 encoding.
-->
<xsd:schema xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata" id="root">
<xsd:import namespace="http://www.w3.org/XML/1998/namespace"/>
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
<xsd:element name="root" msdata:IsDataSet="true">
<xsd:complexType>
<xsd:choice maxOccurs="unbounded">
<xsd:element name="metadata">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0"/>
<xsd:element name="value" type="xsd:string" minOccurs="0" />
</xsd:sequence>
<xsd:attribute name="name" use="required" type="xsd:string"/>
<xsd:attribute name="type" type="xsd:string"/>
<xsd:attribute name="mimetype" type="xsd:string"/>
<xsd:attribute ref="xml:space"/>
<xsd:attribute name="name" use="required" type="xsd:string" />
<xsd:attribute name="type" type="xsd:string" />
<xsd:attribute name="mimetype" type="xsd:string" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="assembly">
<xsd:complexType>
<xsd:attribute name="alias" type="xsd:string"/>
<xsd:attribute name="name" type="xsd:string"/>
<xsd:attribute name="alias" type="xsd:string" />
<xsd:attribute name="name" type="xsd:string" />
</xsd:complexType>
</xsd:element>
<xsd:element name="data">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1"/>
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2"/>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1"/>
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3"/>
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4"/>
<xsd:attribute ref="xml:space"/>
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="resheader">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1"/>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required"/>
<xsd:attribute name="name" type="xsd:string" use="required" />
</xsd:complexType>
</xsd:element>
</xsd:choice>
@@ -186,6 +186,15 @@
<data name="CoreWebView2HelperVersionUndetected" xml:space="preserve">
<value>No WebView2 Runtime detected</value>
</data>
<data name="CoreWindowThemeDark" xml:space="preserve">
<value>Dark</value>
</data>
<data name="CoreWindowThemeLight" xml:space="preserve">
<value>Light</value>
</data>
<data name="CoreWindowThemeSystem" xml:space="preserve">
<value>System</value>
</data>
<data name="FilePickerExportCommit" xml:space="preserve">
<value>Export</value>
</data>

View File

@@ -189,6 +189,15 @@
<data name="CoreWindowHotkeyCombinationRegisterFailed" xml:space="preserve">
<value>[{0}] 热键 [{1}] 注册失败</value>
</data>
<data name="CoreWindowThemeDark" xml:space="preserve">
<value>深色</value>
</data>
<data name="CoreWindowThemeLight" xml:space="preserve">
<value>浅色</value>
</data>
<data name="CoreWindowThemeSystem" xml:space="preserve">
<value>跟随系统</value>
</data>
<data name="FilePickerExportCommit" xml:space="preserve">
<value>导出</value>
</data>
@@ -2624,6 +2633,12 @@
<data name="ViewPageSettingStoreReviewNavigate" xml:space="preserve">
<value>评价软件</value>
</data>
<data name="ViewPageSettingThemeDescription" xml:space="preserve">
<value>更改窗体的颜色主题</value>
</data>
<data name="ViewPageSettingThemeHeader" xml:space="preserve">
<value>颜色主题</value>
</data>
<data name="ViewPageSettingTranslateNavigate" xml:space="preserve">
<value>贡献翻译</value>
</data>
@@ -2895,7 +2910,7 @@
<value>〓活动时间〓.*?\d\.\d版本期间持续开放</value>
</data>
<data name="WebAnnouncementMatchTransientActivityTime" xml:space="preserve">
<value>(?:〓活动时间〓|祈愿时间|【上架时间】).*?(\d\.\d版本更新后).*?~.*?&amp;lt;t class="t_(?:gl|lc)".*?&amp;gt;(.*?)&amp;lt;/t&amp;gt;</value>
<value>(?:〓活动时间〓|祈愿时间|【上架时间】|〓折扣时间〓).*?(\d\.\d版本更新后).*?~.*?&amp;lt;t class="t_(?:gl|lc)".*?&amp;gt;(.*?)&amp;lt;/t&amp;gt;</value>
</data>
<data name="WebAnnouncementMatchVersionUpdateTime" xml:space="preserve">
<value>〓更新时间〓.+?&amp;lt;t class=\"t_(?:gl|lc)\".*?&amp;gt;(.*?)&amp;lt;/t&amp;gt;</value>

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.5 KiB

After

Width:  |  Height:  |  Size: 8.0 KiB

View File

@@ -85,8 +85,13 @@ internal sealed partial class AnnouncementService : IAnnouncementService
{
foreach (ref readonly Announcement item in CollectionsMarshal.AsSpan(listWrapper.List))
{
item.Subtitle = new StringBuilder(item.Subtitle).Replace("\r<br>", string.Empty).ToString();
item.Content = AnnouncementRegex.XmlTimeTagRegex().Replace(item.Content, x => x.Groups[1].Value);
item.Subtitle = new StringBuilder(item.Subtitle)
.Replace("\r<br>", string.Empty)
.Replace("<br />", string.Empty)
.ToString();
item.Content = AnnouncementRegex
.XmlTimeTagRegex()
.Replace(item.Content, x => x.Groups[1].Value);
}
}
}

View File

@@ -16,6 +16,7 @@ internal sealed partial class AppOptions : DbStoreOptions
{
private bool? isEmptyHistoryWishVisible;
private BackdropType? backdropType;
private Theme? theme;
private BackgroundImageType? backgroundImageType;
private Region? region;
private string? geetestCustomCompositeUrl;
@@ -34,6 +35,14 @@ internal sealed partial class AppOptions : DbStoreOptions
set => SetOption(ref backdropType, SettingEntry.SystemBackdropType, value, EnumToStringOrEmpty);
}
public List<NameValue<Theme>> Themes { get; } = CollectionsNameValue.FromEnum<Theme>(theme => theme.GetLocalizedDescription());
public Theme Theme
{
get => GetOption(ref theme, SettingEntry.Theme, EnumParse<Theme>, Theme.System).Value;
set => SetOption(ref theme, SettingEntry.Theme, value, EnumToStringOrEmpty);
}
public List<NameValue<BackgroundImageType>> BackgroundImageTypes { get; } = CollectionsNameValue.FromEnum<BackgroundImageType>(type => type.GetLocalizedDescription());
public BackgroundImageType BackgroundImageType

View File

@@ -28,13 +28,13 @@ internal sealed partial class BackgroundImageService : IBackgroundImageService
private HashSet<string> currentBackgroundPathSet;
public async ValueTask<ValueResult<bool, BackgroundImage>> GetNextBackgroundImageAsync(BackgroundImage? previous)
public async ValueTask<ValueResult<bool, BackgroundImage?>> GetNextBackgroundImageAsync(BackgroundImage? previous)
{
HashSet<string> backgroundSet = await SkipOrInitBackgroundAsync().ConfigureAwait(false);
if (backgroundSet.Count <= 0)
{
return new(false, default!);
return new(true, default!);
}
string path = System.Random.Shared.GetItems([..backgroundSet], 1)[0];
@@ -109,6 +109,9 @@ internal sealed partial class BackgroundImageService : IBackgroundImageService
case BackgroundImageType.HutaoOfficialLauncher:
await SetCurrentBackgroundPathSetAsync(client => client.GetLauncherWallpaperAsync()).ConfigureAwait(false);
break;
default:
currentBackgroundPathSet = [];
break;
}
currentBackgroundPathSet ??= [];

View File

@@ -5,5 +5,5 @@ namespace Snap.Hutao.Service.BackgroundImage;
internal interface IBackgroundImageService
{
ValueTask<ValueResult<bool, BackgroundImage>> GetNextBackgroundImageAsync(BackgroundImage? previous);
ValueTask<ValueResult<bool, BackgroundImage?>> GetNextBackgroundImageAsync(BackgroundImage? previous);
}

View File

@@ -41,39 +41,33 @@ internal sealed partial class DiscordService : IDiscordService, IDisposable
private bool IsSupported()
{
try
{
// Actually requires a discord client to be running on Windows platform.
// If not, discord core creation code will throw.
Process[] discordProcesses = Process.GetProcessesByName("Discord");
// Actually requires a discord client to be running on Windows platform.
// If not, discord core creation code will throw.
Process[] discordProcesses = Process.GetProcessesByName("Discord");
if (discordProcesses.Length <= 0)
if (discordProcesses.Length <= 0)
{
return false;
}
foreach (Process process in discordProcesses)
{
try
{
_ = process.Handle;
}
catch (Exception)
{
if (!isInitialized)
{
isInitialized = true;
infoBarService.Warning(SH.ServiceDiscordActivityElevationRequiredHint);
}
return false;
}
foreach (Process process in discordProcesses)
{
try
{
_ = process.Handle;
}
catch (Exception)
{
if (!isInitialized)
{
infoBarService.Warning(SH.ServiceDiscordActivityElevationRequiredHint);
}
return false;
}
}
return true;
}
finally
{
isInitialized = true;
}
return true;
}
}

View File

@@ -23,8 +23,15 @@ internal sealed class LaunchExecutionBetterGenshinImpactAutomationHandlder : ILa
Uri betterGenshinImpactUri = "bettergi://start".ToUri();
if (await Launcher.QueryUriSupportAsync(betterGenshinImpactUri, LaunchQuerySupportType.Uri) is LaunchQuerySupportStatus.Available)
{
context.Logger.LogInformation("Waiting game window to be ready");
context.Process.WaitForInputIdle();
try
{
context.Logger.LogInformation("Waiting game window to be ready");
context.Process.WaitForInputIdle();
}
catch (InvalidOperationException)
{
return;
}
context.Logger.LogInformation("Launching BetterGI");
await Launcher.LaunchUriAsync(betterGenshinImpactUri);

View File

@@ -298,7 +298,6 @@
<PackageReference Include="CommunityToolkit.WinUI.Controls.Primitives" Version="8.0.240109" />
<PackageReference Include="CommunityToolkit.WinUI.Controls.Segmented" Version="8.0.240109" />
<PackageReference Include="CommunityToolkit.WinUI.Controls.SettingsControls" Version="8.0.240109" />
<PackageReference Include="CommunityToolkit.WinUI.Controls.TokenizingTextBox" Version="8.0.240109" />
<PackageReference Include="CommunityToolkit.WinUI.Media" Version="8.0.240109" />
<PackageReference Include="CommunityToolkit.WinUI.Notifications" Version="7.1.2" />
<PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite" Version="8.0.2" />
@@ -316,8 +315,8 @@
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
<PackageReference Include="Microsoft.VisualStudio.Validation" Version="17.8.8" />
<PackageReference Include="Microsoft.Windows.SDK.BuildTools" Version="10.0.22621.2428" />
<PackageReference Include="Microsoft.WindowsAppSDK" Version="1.4.240211001" />
<PackageReference Include="Microsoft.Windows.SDK.BuildTools" Version="10.0.22621.3233" />
<PackageReference Include="Microsoft.WindowsAppSDK" Version="1.5.240227000" />
<PackageReference Include="QRCoder" Version="1.4.3" />
<PackageReference Include="Snap.Discord.GameSDK" Version="1.6.0" />
<PackageReference Include="Snap.Hutao.Deployment.Runtime" Version="1.15.3">

View File

@@ -0,0 +1,15 @@
// Copyright (c) DGP Studio. All rights reserved.
// Licensed under the MIT license.
using Snap.Hutao.Control;
using Snap.Hutao.Core.Windowing;
namespace Snap.Hutao.View.Converter.Specialized;
internal sealed class BackdropTypeToOpacityConverter : ValueConverter<BackdropType, double>
{
public override double Convert(BackdropType from)
{
return from is BackdropType.None ? 1 : 0;
}
}

View File

@@ -9,6 +9,7 @@
xmlns:shch="using:Snap.Hutao.Control.Helper"
xmlns:shcm="using:Snap.Hutao.Control.Markup"
xmlns:shv="using:Snap.Hutao.View"
xmlns:shvcs="using:Snap.Hutao.View.Converter.Specialized"
xmlns:shvh="using:Snap.Hutao.View.Helper"
xmlns:shvm="using:Snap.Hutao.ViewModel"
xmlns:shvp="using:Snap.Hutao.View.Page"
@@ -27,9 +28,16 @@
<Thickness x:Key="NavigationViewContentGridBorderThickness">0,1,0,0</Thickness>
<x:Double x:Key="NavigationViewItemOnLeftIconBoxHeight">24</x:Double>
<SolidColorBrush x:Key="NavigationViewExpandedPaneBackground" Color="Transparent"/>
<shvcs:BackdropTypeToOpacityConverter x:Key="BackdropTypeToOpacityConverter"/>
</UserControl.Resources>
<!-- Background="{ThemeResource SolidBackgroundFillColorBaseBrush}" -->
<Grid Transitions="{ThemeResource EntranceThemeTransitions}">
<Border Background="{ThemeResource SolidBackgroundFillColorBaseBrush}" Opacity="{Binding AppOptions.BackdropType, Converter={StaticResource BackdropTypeToOpacityConverter}, Mode=OneWay}">
<Border.OpacityTransition>
<ScalarTransition Duration="0:0:1"/>
</Border.OpacityTransition>
</Border>
<Image
x:Name="BackgroundImagePresenter"
HorizontalAlignment="Center"

View File

@@ -1,13 +1,7 @@
// Copyright (c) DGP Studio. All rights reserved.
// Licensed under the MIT license.
using CommunityToolkit.WinUI.Animations;
using Microsoft.UI.Xaml;
using Microsoft.UI.Xaml.Controls;
using Microsoft.UI.Xaml.Media.Animation;
using Snap.Hutao.Control.Animation;
using Snap.Hutao.Control.Theme;
using Snap.Hutao.Service.BackgroundImage;
using Snap.Hutao.Service.Navigation;
using Snap.Hutao.View.Page;
using Snap.Hutao.ViewModel;

View File

@@ -314,6 +314,17 @@
SelectedItem="{Binding SelectedBackdropType, Mode=TwoWay}"/>
</shc:SizeRestrictedContentControl>
</cwc:SettingsCard>
<cwc:SettingsCard
Description="{shcm:ResourceString Name=ViewPageSettingThemeDescription}"
Header="{shcm:ResourceString Name=ViewPageSettingThemeHeader}"
HeaderIcon="{shcm:FontIcon Glyph=&#xE790;}">
<shc:SizeRestrictedContentControl>
<ComboBox
DisplayMemberPath="Name"
ItemsSource="{Binding AppOptions.Themes}"
SelectedItem="{Binding SelectedTheme, Mode=TwoWay}"/>
</shc:SizeRestrictedContentControl>
</cwc:SettingsCard>
<cwc:SettingsExpander
Description="{shcm:ResourceString Name=ViewPageSettingBackgroundImageDescription}"
Header="{shcm:ResourceString Name=ViewPageSettingBackgroundImageHeader}"

View File

@@ -7,6 +7,7 @@
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:mxi="using:Microsoft.Xaml.Interactivity"
xmlns:mxic="using:Microsoft.Xaml.Interactions.Core"
xmlns:shc="using:Snap.Hutao.Control"
xmlns:shcb="using:Snap.Hutao.Control.Behavior"
xmlns:shci="using:Snap.Hutao.Control.Image"
@@ -72,10 +73,6 @@
</shct:DescriptionTextBlock>
</DataTemplate>
<DataTemplate x:Key="SuggestionTemplate">
<TextBlock VerticalAlignment="Center" Text="{Binding}"/>
</DataTemplate>
<DataTemplate x:Key="AvatarListTemplate">
<Grid>
<Grid.ColumnDefinitions>
@@ -268,20 +265,22 @@
</CommandBar.Content>
<!--<AppBarButton Icon="{shcm:FontIcon Glyph=&#xE946;}" Label="搜索提示"/>-->
<AppBarElementContainer>
<cwc:TokenizingTextBox
x:Name="AvatarSuggestBox"
Width="520"
Margin="6,0,6,0"
<AutoSuggestBox
Width="240"
Height="36"
Margin="6,6,6,0"
HorizontalAlignment="Stretch"
VerticalContentAlignment="Center"
ItemsSource="{Binding FilterTokens, Mode=TwoWay}"
MaximumTokens="5"
PlaceholderText="{shcm:ResourceString Name=ViewPageWiKiAvatarAutoSuggestBoxPlaceHolder}"
QueryIcon="{cw:FontIconSource Glyph=&#xE721;}"
SuggestedItemTemplate="{StaticResource SuggestionTemplate}"
SuggestedItemsSource="{Binding AvailableQueries}"
Text="{Binding FilterToken, Mode=TwoWay}"
TokenItemTemplate="{StaticResource SuggestionTemplate}"/>
QueryIcon="{shcm:FontIcon Glyph=&#xE721;}"
Style="{StaticResource DefaultAutoSuggestBoxStyle}"
Text="{Binding FilterText, Mode=TwoWay}">
<mxi:Interaction.Behaviors>
<mxic:EventTriggerBehavior EventName="QuerySubmitted">
<mxic:InvokeCommandAction Command="{Binding FilterCommand}" CommandParameter="{Binding FilterText}"/>
</mxic:EventTriggerBehavior>
</mxi:Interaction.Behaviors>
</AutoSuggestBox>
</AppBarElementContainer>
<AppBarButton
Command="{Binding CultivateCommand}"

View File

@@ -1,8 +1,6 @@
// Copyright (c) DGP Studio. All rights reserved.
// Licensed under the MIT license.
using CommunityToolkit.WinUI.Controls;
using Microsoft.UI.Xaml.Controls;
using Snap.Hutao.Control;
using Snap.Hutao.ViewModel.Wiki;
@@ -19,19 +17,7 @@ internal sealed partial class WikiAvatarPage : ScopedPage
/// </summary>
public WikiAvatarPage()
{
WikiAvatarViewModel viewModel = InitializeWith<WikiAvatarViewModel>();
InitializeWith<WikiAvatarViewModel>();
InitializeComponent();
viewModel.Initialize(new TokenizingTextBoxAccessor(AvatarSuggestBox));
}
private class TokenizingTextBoxAccessor : ITokenizingTextBoxAccessor
{
public TokenizingTextBoxAccessor(TokenizingTextBox tokenizingTextBox)
{
TokenizingTextBox = tokenizingTextBox;
}
public TokenizingTextBox TokenizingTextBox { get; private set; }
}
}

View File

@@ -32,10 +32,6 @@
Source="{Binding Converter={StaticResource PropertyDescriptor}}"/>
</DataTemplate>
<DataTemplate x:Key="SuggestionTemplate">
<TextBlock VerticalAlignment="Center" Text="{Binding}"/>
</DataTemplate>
<DataTemplate x:Key="WeaponListTemplate">
<Grid>
<Grid.ColumnDefinitions>
@@ -135,21 +131,21 @@
LocalSettingKeySuffixForCurrent="WikiWeaponPage.Weapons"/>
</CommandBar.Content>
<AppBarElementContainer>
<cwc:TokenizingTextBox
x:Name="WeaponSuggestBox"
Width="520"
Margin="16,0,6,0"
<AutoSuggestBox
Width="240"
Height="36"
Margin="16,6,6,0"
HorizontalAlignment="Stretch"
VerticalContentAlignment="Center"
ItemTemplate="{StaticResource SuggestionTemplate}"
ItemsSource="{Binding FilterTokens, Mode=TwoWay}"
MaximumTokens="5"
PlaceholderText="{shcm:ResourceString Name=ViewPageWiKiWeaponAutoSuggestBoxPlaceHolder}"
QueryIcon="{cw:FontIconSource Glyph=&#xE721;}"
SuggestedItemTemplate="{StaticResource SuggestionTemplate}"
SuggestedItemsSource="{Binding AvailableQueries}"
Text="{Binding FilterToken, Mode=TwoWay}"
TokenItemTemplate="{StaticResource SuggestionTemplate}"/>
QueryIcon="{shcm:FontIcon Glyph=&#xE721;}"
Text="{Binding FilterText, Mode=TwoWay}">
<mxi:Interaction.Behaviors>
<mxic:EventTriggerBehavior EventName="QuerySubmitted">
<mxic:InvokeCommandAction Command="{Binding FilterCommand}" CommandParameter="{Binding FilterText}"/>
</mxic:EventTriggerBehavior>
</mxi:Interaction.Behaviors>
</AutoSuggestBox>
</AppBarElementContainer>
<AppBarButton
Command="{Binding CultivateCommand}"

View File

@@ -1,7 +1,6 @@
// Copyright (c) DGP Studio. All rights reserved.
// Licensed under the MIT license.
using CommunityToolkit.WinUI.Controls;
using Snap.Hutao.Control;
using Snap.Hutao.ViewModel.Wiki;
@@ -18,19 +17,7 @@ internal sealed partial class WikiWeaponPage : ScopedPage
/// </summary>
public WikiWeaponPage()
{
WikiWeaponViewModel viewModel = InitializeWith<WikiWeaponViewModel>();
InitializeWith<WikiWeaponViewModel>();
InitializeComponent();
viewModel.Initialize(new TokenizingTextBoxAccessor(WeaponSuggestBox));
}
private class TokenizingTextBoxAccessor : ITokenizingTextBoxAccessor
{
public TokenizingTextBoxAccessor(TokenizingTextBox tokenizingTextBox)
{
TokenizingTextBox = tokenizingTextBox;
}
public TokenizingTextBox TokenizingTextBox { get; private set; }
}
}

View File

@@ -76,9 +76,10 @@ internal sealed class DownloadSummary : ObservableObject
{
HttpResponseMessage response = await httpClient.GetAsync(fileUrl, HttpCompletionOption.ResponseHeadersRead).ConfigureAwait(false);
if (response.Content.Headers.ContentType?.MediaType is not "application/octet-stream")
if (response.Content.Headers.ContentType?.MediaType is not ("application/octet-stream" or "application/zip"))
{
logger.LogWarning("Download Static Zip failed, Content-Type is {Type}", response.Content.Headers.ContentType);
await taskContext.SwitchToMainThreadAsync();
Description = SH.ViewModelWelcomeDownloadSummaryContentTypeNotMatch;
return false;
}

View File

@@ -8,7 +8,9 @@ using Microsoft.UI.Xaml.Media.Animation;
using Snap.Hutao.Control.Animation;
using Snap.Hutao.Control.Theme;
using Snap.Hutao.Message;
using Snap.Hutao.Service;
using Snap.Hutao.Service.BackgroundImage;
using System.Globalization;
namespace Snap.Hutao.ViewModel;
@@ -17,11 +19,15 @@ namespace Snap.Hutao.ViewModel;
internal sealed partial class MainViewModel : Abstraction.ViewModel, IMainViewModelInitialization, IRecipient<BackgroundImageTypeChangedMessage>
{
private readonly IBackgroundImageService backgroundImageService;
private readonly ILogger<MainViewModel> logger;
private readonly ITaskContext taskContext;
private readonly AppOptions appOptions;
private BackgroundImage? previousBackgroundImage;
private Image? backgroundImagePresenter;
public AppOptions AppOptions { get => appOptions; }
public void Initialize(IBackgroundImagePresenterAccessor accessor)
{
backgroundImagePresenter = accessor.BackgroundImagePresenter;
@@ -40,9 +46,9 @@ internal sealed partial class MainViewModel : Abstraction.ViewModel, IMainViewMo
return;
}
(bool isOk, BackgroundImage backgroundImage) = await backgroundImageService.GetNextBackgroundImageAsync(previousBackgroundImage).ConfigureAwait(false);
(bool shouldRefresh, BackgroundImage? backgroundImage) = await backgroundImageService.GetNextBackgroundImageAsync(previousBackgroundImage).ConfigureAwait(false);
if (isOk)
if (shouldRefresh)
{
previousBackgroundImage = backgroundImage;
await taskContext.SwitchToMainThreadAsync();
@@ -57,8 +63,18 @@ internal sealed partial class MainViewModel : Abstraction.ViewModel, IMainViewMo
.StartAsync(backgroundImagePresenter)
.ConfigureAwait(true);
backgroundImagePresenter.Source = backgroundImage.ImageSource;
double targetOpacity = ThemeHelper.IsDarkMode(backgroundImagePresenter.ActualTheme) ? 1 - backgroundImage.Luminance : backgroundImage.Luminance;
backgroundImagePresenter.Source = backgroundImage?.ImageSource;
double targetOpacity = backgroundImage is not null
? ThemeHelper.IsDarkMode(backgroundImagePresenter.ActualTheme)
? 1 - backgroundImage.Luminance
: backgroundImage.Luminance
: 0;
logger.LogInformation(
"Background image: [Accent color: {AccentColor}] [Luminance: {Luminance}] [Opacity: {TargetOpacity}]",
backgroundImage?.AccentColor.ToString(CultureInfo.CurrentCulture),
backgroundImage?.Luminance,
targetOpacity);
await AnimationBuilder
.Create()

View File

@@ -58,6 +58,7 @@ internal sealed partial class SettingViewModel : Abstraction.ViewModel
private readonly IMessenger messenger;
private NameValue<BackdropType>? selectedBackdropType;
private NameValue<Theme>? selectedTheme;
private NameValue<BackgroundImageType>? selectedBackgroundImageType;
private NameValue<CultureInfo>? selectedCulture;
private NameValue<Region>? selectedRegion;
@@ -94,6 +95,18 @@ internal sealed partial class SettingViewModel : Abstraction.ViewModel
}
}
public NameValue<Theme>? SelectedTheme
{
get => selectedTheme ??= AppOptions.Themes.Single(t => t.Value == AppOptions.Theme);
set
{
if (SetProperty(ref selectedTheme, value) && value is not null)
{
AppOptions.Theme = value.Value;
}
}
}
public NameValue<BackgroundImageType>? SelectedBackgroundImageType
{
get => selectedBackgroundImageType ??= AppOptions.BackgroundImageTypes.Single(t => t.Value == AppOptions.BackgroundImageType);

View File

@@ -1,12 +0,0 @@
// Copyright (c) DGP Studio. All rights reserved.
// Licensed under the MIT license.
using CommunityToolkit.WinUI.Controls;
using Snap.Hutao.Control;
namespace Snap.Hutao.ViewModel.Wiki;
internal interface ITokenizingTextBoxAccessor : IXamlElementAccessor
{
TokenizingTextBox TokenizingTextBox { get; }
}

View File

@@ -1,9 +0,0 @@
// Copyright (c) DGP Studio. All rights reserved.
// Licensed under the MIT license.
namespace Snap.Hutao.ViewModel.Wiki;
internal interface IWikiViewModelInitialization
{
void Initialize(ITokenizingTextBoxAccessor accessor);
}

View File

@@ -1,14 +1,11 @@
// Copyright (c) DGP Studio. All rights reserved.
// Licensed under the MIT license.
using CommunityToolkit.WinUI.Controls;
using Microsoft.UI.Xaml.Controls;
using Snap.Hutao.Control.Collection.AdvancedCollectionView;
using Snap.Hutao.Factory.ContentDialog;
using Snap.Hutao.Model.Calculable;
using Snap.Hutao.Model.Entity.Primitive;
using Snap.Hutao.Model.Intrinsic;
using Snap.Hutao.Model.Intrinsic.Frozen;
using Snap.Hutao.Model.Metadata;
using Snap.Hutao.Model.Metadata.Avatar;
using Snap.Hutao.Model.Metadata.Item;
@@ -20,8 +17,6 @@ using Snap.Hutao.Service.Notification;
using Snap.Hutao.Service.User;
using Snap.Hutao.View.Dialog;
using Snap.Hutao.Web.Response;
using System.Collections.Frozen;
using System.Collections.ObjectModel;
using System.Runtime.InteropServices;
using CalculateAvatarPromotionDelta = Snap.Hutao.Web.Hoyolab.Takumi.Event.Calculate.AvatarPromotionDelta;
using CalculateClient = Snap.Hutao.Web.Hoyolab.Takumi.Event.Calculate.CalculateClient;
@@ -37,7 +32,7 @@ namespace Snap.Hutao.ViewModel.Wiki;
[HighQuality]
[ConstructorGenerated]
[Injection(InjectAs.Scoped)]
internal sealed partial class WikiAvatarViewModel : Abstraction.ViewModel, IWikiViewModelInitialization
internal sealed partial class WikiAvatarViewModel : Abstraction.ViewModel
{
private readonly IContentDialogFactory contentDialogFactory;
private readonly ICultivationService cultivationService;
@@ -50,12 +45,10 @@ internal sealed partial class WikiAvatarViewModel : Abstraction.ViewModel, IWiki
private AdvancedCollectionView<Avatar>? avatars;
private Avatar? selected;
private ObservableCollection<string>? filterTokens;
private string? filterToken;
private string? filterText;
private BaseValueInfo? baseValueInfo;
private Dictionary<Level, Dictionary<GrowCurveType, float>>? levelAvatarCurveMap;
private List<Promote>? promotes;
private FrozenSet<string> availableQueries;
/// <summary>
/// 角色列表
@@ -82,21 +75,9 @@ internal sealed partial class WikiAvatarViewModel : Abstraction.ViewModel, IWiki
public BaseValueInfo? BaseValueInfo { get => baseValueInfo; set => SetProperty(ref baseValueInfo, value); }
/// <summary>
/// 保存的筛选标志
/// 筛选文本
/// </summary>
public ObservableCollection<string>? FilterTokens { get => filterTokens; set => SetProperty(ref filterTokens, value); }
public string? FilterToken { get => filterToken; set => SetProperty(ref filterToken, value); }
public FrozenSet<string>? AvailableQueries { get => availableQueries; }
public void Initialize(ITokenizingTextBoxAccessor accessor)
{
accessor.TokenizingTextBox.TextChanged += OnFilterSuggestionRequested;
accessor.TokenizingTextBox.QuerySubmitted += OnQuerySubmitted;
accessor.TokenizingTextBox.TokenItemAdded += OnTokenItemModified;
accessor.TokenizingTextBox.TokenItemRemoved += OnTokenItemModified;
}
public string? FilterText { get => filterText; set => SetProperty(ref filterText, value); }
protected override async ValueTask<bool> InitializeUIAsync()
{
@@ -120,18 +101,6 @@ internal sealed partial class WikiAvatarViewModel : Abstraction.ViewModel, IWiki
await taskContext.SwitchToMainThreadAsync();
Avatars = new(list, true);
Selected = Avatars.View.ElementAtOrDefault(0);
FilterTokens = [];
availableQueries = FrozenSet.ToFrozenSet<string>(
[
.. avatars.Select(a => a.Name),
.. IntrinsicFrozen.AssociationTypes,
.. IntrinsicFrozen.BodyTypes,
.. IntrinsicFrozen.ElementNames,
.. IntrinsicFrozen.ItemQualities,
.. IntrinsicFrozen.WeaponTypes,
]);
return true;
}
@@ -233,53 +202,21 @@ internal sealed partial class WikiAvatarViewModel : Abstraction.ViewModel, IWiki
BaseValueInfo = new(avatar.MaxLevel, propertyCurveValues, levelAvatarCurveMap, avatarPromoteMap);
}
private void OnFilterSuggestionRequested(AutoSuggestBox sender, AutoSuggestBoxTextChangedEventArgs args)
[Command("FilterCommand")]
private void ApplyFilter(string? input)
{
if (Avatars is null)
{
return;
}
if (string.IsNullOrWhiteSpace(FilterToken))
{
return;
}
if (args.Reason == AutoSuggestionBoxTextChangeReason.UserInput)
{
sender.ItemsSource = availableQueries.Where(q => q.Contains(FilterToken, StringComparison.OrdinalIgnoreCase));
}
}
private void OnQuerySubmitted(AutoSuggestBox sender, AutoSuggestBoxQuerySubmittedEventArgs args)
{
if (args.ChosenSuggestion is not null)
{
return;
}
ApplyFilter();
}
private void OnTokenItemModified(TokenizingTextBox sender, object args)
{
ApplyFilter();
}
private void ApplyFilter()
{
if (Avatars is null)
{
return;
}
if (FilterTokens.IsNullOrEmpty())
if (string.IsNullOrWhiteSpace(input))
{
Avatars.Filter = default!;
return;
}
Avatars.Filter = AvatarFilter.Compile(string.Join(' ', FilterTokens));
Avatars.Filter = AvatarFilter.Compile(input);
if (Selected is not null && Avatars.Contains(Selected))
{

View File

@@ -1,14 +1,11 @@
// Copyright (c) DGP Studio. All rights reserved.
// Licensed under the MIT license.
using CommunityToolkit.WinUI.Controls;
using Microsoft.UI.Xaml.Controls;
using Snap.Hutao.Control.Collection.AdvancedCollectionView;
using Snap.Hutao.Factory.ContentDialog;
using Snap.Hutao.Model.Calculable;
using Snap.Hutao.Model.Entity.Primitive;
using Snap.Hutao.Model.Intrinsic;
using Snap.Hutao.Model.Intrinsic.Frozen;
using Snap.Hutao.Model.Metadata;
using Snap.Hutao.Model.Metadata.Item;
using Snap.Hutao.Model.Metadata.Weapon;
@@ -20,7 +17,6 @@ using Snap.Hutao.Service.Notification;
using Snap.Hutao.Service.User;
using Snap.Hutao.View.Dialog;
using Snap.Hutao.Web.Response;
using System.Collections.Frozen;
using System.Runtime.InteropServices;
using CalculateAvatarPromotionDelta = Snap.Hutao.Web.Hoyolab.Takumi.Event.Calculate.AvatarPromotionDelta;
using CalculateClient = Snap.Hutao.Web.Hoyolab.Takumi.Event.Calculate.CalculateClient;
@@ -33,7 +29,7 @@ namespace Snap.Hutao.ViewModel.Wiki;
/// </summary>
[ConstructorGenerated]
[Injection(InjectAs.Scoped)]
internal sealed partial class WikiWeaponViewModel : Abstraction.ViewModel, IWikiViewModelInitialization
internal sealed partial class WikiWeaponViewModel : Abstraction.ViewModel
{
private readonly IContentDialogFactory contentDialogFactory;
private readonly CalculateClient calculateClient;
@@ -46,12 +42,10 @@ internal sealed partial class WikiWeaponViewModel : Abstraction.ViewModel, IWiki
private AdvancedCollectionView<Weapon>? weapons;
private Weapon? selected;
private List<string>? filterTokens;
private string? filterToken;
private string? filterText;
private BaseValueInfo? baseValueInfo;
private Dictionary<Level, Dictionary<GrowCurveType, float>>? levelWeaponCurveMap;
private List<Promote>? promotes;
private FrozenSet<string> availableQueries;
/// <summary>
/// 角色列表
@@ -78,21 +72,9 @@ internal sealed partial class WikiWeaponViewModel : Abstraction.ViewModel, IWiki
public BaseValueInfo? BaseValueInfo { get => baseValueInfo; set => SetProperty(ref baseValueInfo, value); }
/// <summary>
/// 保存的筛选标志
/// 筛选文本
/// </summary>
public List<string>? FilterTokens { get => filterTokens; set => SetProperty(ref filterTokens, value); }
public string? FilterToken { get => filterToken; set => SetProperty(ref filterToken, value); }
public FrozenSet<string> AvailableQueries { get => availableQueries; }
public void Initialize(ITokenizingTextBoxAccessor accessor)
{
accessor.TokenizingTextBox.TextChanged += OnFilterSuggestionRequested;
accessor.TokenizingTextBox.QuerySubmitted += OnQuerySubmitted;
accessor.TokenizingTextBox.TokenItemAdded += OnTokenItemModified;
accessor.TokenizingTextBox.TokenItemRemoved += OnTokenItemModified;
}
public string? FilterText { get => filterText; set => SetProperty(ref filterText, value); }
/// <inheritdoc/>
protected override async Task OpenUIAsync()
@@ -116,15 +98,6 @@ internal sealed partial class WikiWeaponViewModel : Abstraction.ViewModel, IWiki
Weapons = new(list, true);
Selected = Weapons.View.ElementAtOrDefault(0);
FilterTokens = [];
availableQueries = FrozenSet.ToFrozenSet(
[
.. weapons.Select(w => w.Name),
.. IntrinsicFrozen.ItemQualities,
.. IntrinsicFrozen.FightProperties,
.. IntrinsicFrozen.WeaponTypes,
]);
}
}
@@ -214,53 +187,21 @@ internal sealed partial class WikiWeaponViewModel : Abstraction.ViewModel, IWiki
BaseValueInfo = new(weapon.MaxLevel, propertyCurveValues, levelWeaponCurveMap, weaponPromoteMap);
}
private void OnFilterSuggestionRequested(AutoSuggestBox sender, AutoSuggestBoxTextChangedEventArgs args)
[Command("FilterCommand")]
private void ApplyFilter(string? input)
{
if (Weapons is null)
{
return;
}
if (string.IsNullOrWhiteSpace(FilterToken))
{
return;
}
if (args.Reason == AutoSuggestionBoxTextChangeReason.UserInput)
{
sender.ItemsSource = availableQueries.Where(q => q.Contains(FilterToken, StringComparison.OrdinalIgnoreCase));
}
}
private void OnQuerySubmitted(AutoSuggestBox sender, AutoSuggestBoxQuerySubmittedEventArgs args)
{
if (args.ChosenSuggestion is not null)
{
return;
}
ApplyFilter();
}
private void OnTokenItemModified(TokenizingTextBox sender, object args)
{
ApplyFilter();
}
private void ApplyFilter()
{
if (Weapons is null)
{
return;
}
if (FilterTokens.IsNullOrEmpty())
if (string.IsNullOrWhiteSpace(input))
{
Weapons.Filter = default!;
return;
}
Weapons.Filter = WeaponFilter.Compile(string.Join(' ', FilterTokens));
Weapons.Filter = WeaponFilter.Compile(input);
if (Selected is not null && Weapons.Contains(Selected))
{