mirror of
https://jihulab.com/DGP-Studio/Snap.Hutao.git
synced 2025-11-19 21:02:53 +08:00
implement gradient control
This commit is contained in:
64
src/Snap.Hutao/Snap.Hutao/Context/FileSystem/CacheContext.cs
Normal file
64
src/Snap.Hutao/Snap.Hutao/Context/FileSystem/CacheContext.cs
Normal file
@@ -0,0 +1,64 @@
|
||||
// Copyright (c) DGP Studio. All rights reserved.
|
||||
// Licensed under the MIT license.
|
||||
|
||||
using Snap.Hutao.Context.FileSystem.Location;
|
||||
using Windows.Storage;
|
||||
|
||||
namespace Snap.Hutao.Context.FileSystem;
|
||||
|
||||
/// <summary>
|
||||
/// 缓存目录上下文
|
||||
/// </summary>
|
||||
[Injection(InjectAs.Transient)]
|
||||
internal class CacheContext : FileSystemContext
|
||||
{
|
||||
/// <summary>
|
||||
/// 构造一个新的缓存目录上下文
|
||||
/// </summary>
|
||||
/// <param name="cache">缓存位置</param>
|
||||
public CacheContext(Cache cache)
|
||||
: base(cache)
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取缓存文件夹
|
||||
/// </summary>
|
||||
public static StorageFolder Folder
|
||||
{
|
||||
get => ApplicationData.Current.TemporaryFolder;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取缓存文件的名称
|
||||
/// </summary>
|
||||
/// <param name="uri">uri</param>
|
||||
/// <returns>缓存文件的名称</returns>
|
||||
public static string GetCacheFileName(Uri uri)
|
||||
{
|
||||
return CreateHash64(uri.ToString()).ToString();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取缓存文件的名称
|
||||
/// </summary>
|
||||
/// <param name="url">url</param>
|
||||
/// <returns>缓存文件的名称</returns>
|
||||
public static string GetCacheFileName(string url)
|
||||
{
|
||||
return CreateHash64(url).ToString();
|
||||
}
|
||||
|
||||
private static ulong CreateHash64(string str)
|
||||
{
|
||||
byte[] utf8 = System.Text.Encoding.UTF8.GetBytes(str);
|
||||
|
||||
ulong value = (ulong)utf8.Length;
|
||||
for (int n = 0; n < utf8.Length; n++)
|
||||
{
|
||||
value += (ulong)utf8[n] << ((n * 5) % 56);
|
||||
}
|
||||
|
||||
return value;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
// Copyright (c) DGP Studio. All rights reserved.
|
||||
// Licensed under the MIT license.
|
||||
|
||||
using System.IO;
|
||||
|
||||
namespace Snap.Hutao.Context.FileSystem.Location;
|
||||
|
||||
/// <summary>
|
||||
/// 缓存位置
|
||||
/// </summary>
|
||||
[Injection(InjectAs.Transient)]
|
||||
internal class Cache : IFileSystemLocation
|
||||
{
|
||||
private string? path;
|
||||
|
||||
/// <inheritdoc/>
|
||||
public string GetPath()
|
||||
{
|
||||
if (string.IsNullOrEmpty(path))
|
||||
{
|
||||
path = Windows.Storage.ApplicationData.Current.TemporaryFolder.Path;
|
||||
}
|
||||
|
||||
return path;
|
||||
}
|
||||
}
|
||||
@@ -9,7 +9,7 @@ namespace Snap.Hutao.Context.FileSystem.Location;
|
||||
/// 我的文档位置
|
||||
/// </summary>
|
||||
[Injection(InjectAs.Transient)]
|
||||
public class Metadata : IFileSystemLocation
|
||||
internal class Metadata : IFileSystemLocation
|
||||
{
|
||||
private string? path;
|
||||
|
||||
|
||||
@@ -9,7 +9,7 @@ namespace Snap.Hutao.Context.FileSystem.Location;
|
||||
/// 我的文档位置
|
||||
/// </summary>
|
||||
[Injection(InjectAs.Transient)]
|
||||
public class MyDocument : IFileSystemLocation
|
||||
internal class MyDocument : IFileSystemLocation
|
||||
{
|
||||
private string? path;
|
||||
|
||||
|
||||
@@ -16,4 +16,4 @@ internal class MetadataContext : FileSystemContext
|
||||
: base(metadata)
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
140
src/Snap.Hutao/Snap.Hutao/Control/Image/Gradient.cs
Normal file
140
src/Snap.Hutao/Snap.Hutao/Control/Image/Gradient.cs
Normal file
@@ -0,0 +1,140 @@
|
||||
// Copyright (c) DGP Studio. All rights reserved.
|
||||
// Licensed under the MIT license.
|
||||
|
||||
using CommunityToolkit.WinUI.Helpers;
|
||||
using CommunityToolkit.WinUI.UI.Animations;
|
||||
using Microsoft.UI;
|
||||
using Microsoft.UI.Composition;
|
||||
using Microsoft.UI.Xaml;
|
||||
using Microsoft.UI.Xaml.Hosting;
|
||||
using Microsoft.UI.Xaml.Media;
|
||||
using Microsoft.UI.Xaml.Media.Animation;
|
||||
using Snap.Hutao.Context.FileSystem;
|
||||
using Snap.Hutao.Core;
|
||||
using Snap.Hutao.Core.Threading;
|
||||
using Snap.Hutao.Extension;
|
||||
using System.Numerics;
|
||||
using Windows.Graphics.Imaging;
|
||||
using Windows.Storage;
|
||||
using Windows.Storage.Streams;
|
||||
|
||||
namespace Snap.Hutao.Control.Image;
|
||||
|
||||
/// <summary>
|
||||
/// 支持渐变的图像
|
||||
/// </summary>
|
||||
public class Gradient : Microsoft.UI.Xaml.Controls.Control
|
||||
{
|
||||
private static readonly DependencyProperty SourceProperty = Property<Gradient>.Depend(nameof(Source), string.Empty, OnSourceChanged);
|
||||
private static readonly ConcurrentCancellationTokenSource<Gradient> ImageLoading = new();
|
||||
private SpriteVisual? spriteVisual;
|
||||
private double imageAspectRatio;
|
||||
|
||||
/// <summary>
|
||||
/// 构造一个新的渐变图像
|
||||
/// </summary>
|
||||
public Gradient()
|
||||
{
|
||||
SizeChanged += OnSizeChanged;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 源
|
||||
/// </summary>
|
||||
public string Source
|
||||
{
|
||||
get => (string)GetValue(SourceProperty);
|
||||
set => SetValue(SourceProperty, value);
|
||||
}
|
||||
|
||||
private static async Task<StorageFile> GetCachedFileAsync(string url, CancellationToken token)
|
||||
{
|
||||
string fileName = CacheContext.GetCacheFileName(url);
|
||||
CacheContext cacheContext = Ioc.Default.GetRequiredService<CacheContext>();
|
||||
|
||||
StorageFile storageFile;
|
||||
if (!cacheContext.FileExists(fileName))
|
||||
{
|
||||
storageFile = await CacheContext.Folder.CreateFileAsync(fileName).AsTask(token);
|
||||
await StreamHelper.GetHttpStreamToStorageFileAsync(new(url), storageFile);
|
||||
}
|
||||
else
|
||||
{
|
||||
storageFile = await CacheContext.Folder.GetFileAsync(fileName).AsTask(token);
|
||||
}
|
||||
|
||||
return storageFile;
|
||||
}
|
||||
|
||||
private static void OnSourceChanged(DependencyObject sender, DependencyPropertyChangedEventArgs arg)
|
||||
{
|
||||
Gradient gradient = (Gradient)sender;
|
||||
string url = (string)arg.NewValue;
|
||||
|
||||
gradient.ApplyImageAsync(url, ImageLoading.Register(gradient)).SafeForget();
|
||||
}
|
||||
|
||||
private void OnSizeChanged(object sender, SizeChangedEventArgs e)
|
||||
{
|
||||
if (e.NewSize != e.PreviousSize && spriteVisual is not null)
|
||||
{
|
||||
UpdateVisual(spriteVisual);
|
||||
}
|
||||
}
|
||||
|
||||
private void UpdateVisual(SpriteVisual spriteVisual)
|
||||
{
|
||||
if (spriteVisual is not null)
|
||||
{
|
||||
double width = ActualWidth;
|
||||
double height = Math.Clamp(width * imageAspectRatio, 0, MaxHeight);
|
||||
|
||||
spriteVisual.Size = new Vector2((float)width, (float)height);
|
||||
Height = height;
|
||||
}
|
||||
}
|
||||
|
||||
private async Task ApplyImageAsync(string url, CancellationToken token)
|
||||
{
|
||||
await AnimationBuilder
|
||||
.Create()
|
||||
.Opacity(0, 1)
|
||||
.StartAsync(this, token);
|
||||
|
||||
StorageFile storageFile = await GetCachedFileAsync(url, token);
|
||||
|
||||
Compositor compositor = ElementCompositionPreview.GetElementVisual(this).Compositor;
|
||||
|
||||
LoadedImageSurface imageSurface = await LoadImageSurfaceAsync(storageFile, token);
|
||||
|
||||
CompositionSurfaceBrush imageSurfaceBrush = compositor.CompositeSurfaceBrush(imageSurface, stretch: CompositionStretch.UniformToFill, vRatio: 0f);
|
||||
|
||||
CompositionLinearGradientBrush backgroundBrush = compositor.CompositeLinearGradientBrush(new(1f, 0), Vector2.UnitY, new(0, Colors.White), new(1, Colors.Black));
|
||||
CompositionLinearGradientBrush foregroundBrush = compositor.CompositeLinearGradientBrush(Vector2.Zero, Vector2.UnitY, new(0, Colors.White), new(0.95f, Colors.Black));
|
||||
|
||||
CompositionEffectBrush gradientEffectBrush = compositor.CompositeBlendEffectBrush(backgroundBrush, foregroundBrush);
|
||||
CompositionEffectBrush opacityMaskEffectBrush = compositor.CompositeLuminanceToAlphaEffectBrush(gradientEffectBrush);
|
||||
CompositionEffectBrush alphaMaskEffectBrush = compositor.CompositeAlphaMaskEffectBrush(imageSurfaceBrush, opacityMaskEffectBrush);
|
||||
|
||||
spriteVisual = compositor.CompositeSpriteVisual(alphaMaskEffectBrush);
|
||||
UpdateVisual(spriteVisual);
|
||||
|
||||
ElementCompositionPreview.SetElementChildVisual(this, spriteVisual);
|
||||
|
||||
await AnimationBuilder
|
||||
.Create()
|
||||
.Opacity(1, 0)
|
||||
.StartAsync(this, token);
|
||||
}
|
||||
|
||||
private async Task<LoadedImageSurface> LoadImageSurfaceAsync(StorageFile storageFile, CancellationToken token)
|
||||
{
|
||||
using (IRandomAccessStream imageStream = await storageFile.OpenAsync(FileAccessMode.Read).AsTask(token))
|
||||
{
|
||||
BitmapDecoder decoder = await BitmapDecoder.CreateAsync(imageStream).AsTask(token);
|
||||
imageAspectRatio = (double)decoder.PixelHeight / decoder.PixelWidth;
|
||||
|
||||
return LoadedImageSurface.StartLoadFromStream(imageStream);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -22,4 +22,9 @@ internal static class EventIds
|
||||
/// Forget任务执行异常
|
||||
/// </summary>
|
||||
public static readonly EventId TaskException = new(100002, nameof(TaskException));
|
||||
|
||||
/// <summary>
|
||||
/// Forget任务执行异常
|
||||
/// </summary>
|
||||
public static readonly EventId AsyncCommandException = new(100003, nameof(AsyncCommandException));
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
// Copyright (c) DGP Studio. All rights reserved.
|
||||
// Licensed under the MIT license.
|
||||
|
||||
using System.Collections.Concurrent;
|
||||
|
||||
namespace Snap.Hutao.Core.Threading;
|
||||
|
||||
/// <summary>
|
||||
/// 并发<see cref="CancellationTokenSource"/>
|
||||
/// </summary>
|
||||
/// <typeparam name="TItem">项类型</typeparam>
|
||||
internal class ConcurrentCancellationTokenSource<TItem>
|
||||
where TItem : notnull
|
||||
{
|
||||
private readonly ConcurrentDictionary<TItem, CancellationTokenSource> waitingItems = new();
|
||||
|
||||
/// <summary>
|
||||
/// 未某个项注册取消令牌
|
||||
/// </summary>
|
||||
/// <param name="item">项</param>
|
||||
/// <returns>取消令牌</returns>
|
||||
public CancellationToken Register(TItem item)
|
||||
{
|
||||
if (waitingItems.TryRemove(item, out CancellationTokenSource? prevSource))
|
||||
{
|
||||
prevSource.Cancel();
|
||||
}
|
||||
|
||||
CancellationTokenSource current = waitingItems.GetOrAdd(item, new CancellationTokenSource());
|
||||
|
||||
return current.Token;
|
||||
}
|
||||
}
|
||||
154
src/Snap.Hutao/Snap.Hutao/Extension/CompositionExtensions.cs
Normal file
154
src/Snap.Hutao/Snap.Hutao/Extension/CompositionExtensions.cs
Normal file
@@ -0,0 +1,154 @@
|
||||
// Copyright (c) DGP Studio. All rights reserved.
|
||||
// Licensed under the MIT license.
|
||||
|
||||
using Microsoft.Graphics.Canvas.Effects;
|
||||
using Microsoft.UI.Composition;
|
||||
using System.Numerics;
|
||||
|
||||
namespace Snap.Hutao.Extension;
|
||||
|
||||
/// <summary>
|
||||
/// 合成扩展
|
||||
/// </summary>
|
||||
internal static class CompositionExtensions
|
||||
{
|
||||
/// <summary>
|
||||
/// 创建拼合图视觉对象
|
||||
/// </summary>
|
||||
/// <param name="compositor">合成器</param>
|
||||
/// <param name="brush">画刷</param>
|
||||
/// <returns>拼合图视觉对象</returns>
|
||||
public static SpriteVisual CompositeSpriteVisual(this Compositor compositor, CompositionBrush brush)
|
||||
{
|
||||
SpriteVisual spriteVisual = compositor.CreateSpriteVisual();
|
||||
spriteVisual.Brush = brush;
|
||||
return spriteVisual;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 创建混合效果画刷
|
||||
/// </summary>
|
||||
/// <param name="compositor">合成器</param>
|
||||
/// <param name="background">前景</param>
|
||||
/// <param name="foreground">背景</param>
|
||||
/// <param name="blendEffectMode">混合模式</param>
|
||||
/// <returns>合成效果画刷</returns>
|
||||
public static CompositionEffectBrush CompositeBlendEffectBrush(
|
||||
this Compositor compositor,
|
||||
CompositionBrush background,
|
||||
CompositionBrush foreground,
|
||||
BlendEffectMode blendEffectMode = BlendEffectMode.Multiply)
|
||||
{
|
||||
BlendEffect effect = new()
|
||||
{
|
||||
Background = new CompositionEffectSourceParameter("Background"),
|
||||
Foreground = new CompositionEffectSourceParameter("Foreground"),
|
||||
Mode = blendEffectMode,
|
||||
};
|
||||
|
||||
CompositionEffectBrush brush = compositor.CreateEffectFactory(effect).CreateBrush();
|
||||
|
||||
brush.SetSourceParameter("Background", background);
|
||||
brush.SetSourceParameter("Foreground", foreground);
|
||||
|
||||
return brush;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 创建亮度转不透明度效果画刷
|
||||
/// </summary>
|
||||
/// <param name="compositor">合成器</param>
|
||||
/// <param name="sourceBrush">源</param>
|
||||
/// <returns>合成效果画刷</returns>
|
||||
public static CompositionEffectBrush CompositeLuminanceToAlphaEffectBrush(this Compositor compositor, CompositionBrush sourceBrush)
|
||||
{
|
||||
LuminanceToAlphaEffect effect = new()
|
||||
{
|
||||
Source = new CompositionEffectSourceParameter("Source"),
|
||||
};
|
||||
|
||||
CompositionEffectBrush brush = compositor.CreateEffectFactory(effect).CreateBrush();
|
||||
|
||||
brush.SetSourceParameter("Source", sourceBrush);
|
||||
|
||||
return brush;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 创建不透明度蒙版效果画刷
|
||||
/// </summary>
|
||||
/// <param name="compositor">合成器</param>
|
||||
/// <param name="sourceBrush">源</param>
|
||||
/// <param name="alphaMask">不透明度蒙版</param>
|
||||
/// <returns>合成效果画刷</returns>
|
||||
public static CompositionEffectBrush CompositeAlphaMaskEffectBrush(
|
||||
this Compositor compositor,
|
||||
CompositionBrush sourceBrush,
|
||||
CompositionBrush alphaMask)
|
||||
{
|
||||
AlphaMaskEffect maskEffect = new()
|
||||
{
|
||||
AlphaMask = new CompositionEffectSourceParameter("AlphaMask"),
|
||||
Source = new CompositionEffectSourceParameter("Source"),
|
||||
};
|
||||
|
||||
CompositionEffectBrush brush = compositor.CreateEffectFactory(maskEffect).CreateBrush();
|
||||
|
||||
brush.SetSourceParameter("AlphaMask", alphaMask);
|
||||
brush.SetSourceParameter("Source", sourceBrush);
|
||||
|
||||
return brush;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 创建一个表面画刷
|
||||
/// </summary>
|
||||
/// <param name="compositor">合成器</param>
|
||||
/// <param name="surface">合成表面</param>
|
||||
/// <param name="stretch">拉伸方法</param>
|
||||
/// <param name="hRatio">水平对齐比</param>
|
||||
/// <param name="vRatio">垂直对齐比</param>
|
||||
/// <returns>合成表面画刷</returns>
|
||||
public static CompositionSurfaceBrush CompositeSurfaceBrush(
|
||||
this Compositor compositor,
|
||||
ICompositionSurface surface,
|
||||
CompositionStretch stretch = CompositionStretch.None,
|
||||
float hRatio = 0.5f,
|
||||
float vRatio = 0.5f)
|
||||
{
|
||||
CompositionSurfaceBrush brush = compositor.CreateSurfaceBrush(surface);
|
||||
brush.Stretch = stretch;
|
||||
brush.VerticalAlignmentRatio = vRatio;
|
||||
brush.HorizontalAlignmentRatio = hRatio;
|
||||
|
||||
return brush;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 创建一个线性渐变画刷
|
||||
/// </summary>
|
||||
/// <param name="compositor">合成器</param>
|
||||
/// <param name="start">起点</param>
|
||||
/// <param name="end">终点</param>
|
||||
/// <param name="stops">锚点</param>
|
||||
/// <returns>线性渐变画刷</returns>
|
||||
public static CompositionLinearGradientBrush CompositeLinearGradientBrush(
|
||||
this Compositor compositor,
|
||||
Vector2 start,
|
||||
Vector2 end,
|
||||
params GradientStop[] stops)
|
||||
{
|
||||
CompositionLinearGradientBrush brush = compositor.CreateLinearGradientBrush();
|
||||
brush.StartPoint = start;
|
||||
brush.EndPoint = end;
|
||||
|
||||
foreach (GradientStop stop in stops)
|
||||
{
|
||||
brush.ColorStops.Add(compositor.CreateColorGradientStop(stop.Offset, stop.Color));
|
||||
}
|
||||
|
||||
return brush;
|
||||
}
|
||||
|
||||
public record struct GradientStop(float Offset, Windows.UI.Color Color);
|
||||
}
|
||||
@@ -24,6 +24,9 @@ public static class TaskExtensions
|
||||
{
|
||||
await task.ConfigureAwait(continueOnCapturedContext);
|
||||
}
|
||||
catch (TaskCanceledException)
|
||||
{
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
logger?.LogError(EventIds.TaskException, e, "{caller}:{exception}", nameof(SafeForget), e.GetBaseException());
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
// Licensed under the MIT license.
|
||||
|
||||
using CommunityToolkit.Mvvm.Input;
|
||||
using Microsoft.AppCenter.Crashes;
|
||||
using Snap.Hutao.Core.Logging;
|
||||
using Snap.Hutao.Factory.Abstraction;
|
||||
|
||||
namespace Snap.Hutao.Factory;
|
||||
@@ -93,8 +93,7 @@ internal class AsyncRelayCommandFactory : IAsyncRelayCommandFactory
|
||||
if (asyncRelayCommand.ExecutionTask?.Exception is AggregateException exception)
|
||||
{
|
||||
Exception baseException = exception.GetBaseException();
|
||||
logger.LogError(baseException, "异步命令发生了错误");
|
||||
Crashes.TrackError(baseException);
|
||||
logger.LogError(EventIds.AsyncCommandException, baseException, "异步命令发生了错误");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -31,10 +31,10 @@ internal static class IocHttpClientConfiguration
|
||||
services.AddHttpClient<MetadataService>(DefaultConfiguration);
|
||||
|
||||
// normal clients
|
||||
services.AddHttpClient<HutaoClient>(DefaultConfiguration);
|
||||
services.AddHttpClient<AnnouncementClient>(DefaultConfiguration);
|
||||
services.AddHttpClient<UserGameRoleClient>(DefaultConfiguration);
|
||||
services.AddHttpClient<EnkaClient>(DefaultConfiguration);
|
||||
services.AddHttpClient<HutaoClient>(DefaultConfiguration);
|
||||
services.AddHttpClient<UserGameRoleClient>(DefaultConfiguration);
|
||||
|
||||
// x-rpc clients
|
||||
services.AddHttpClient<GameRecordClient>(XRpcConfiguration);
|
||||
|
||||
@@ -0,0 +1,33 @@
|
||||
// Copyright (c) DGP Studio. All rights reserved.
|
||||
// Licensed under the MIT license.
|
||||
|
||||
using Microsoft.UI.Xaml.Data;
|
||||
|
||||
namespace Snap.Hutao.Model.Metadata.Converter;
|
||||
|
||||
/// <summary>
|
||||
/// 角色名片转换器
|
||||
/// </summary>
|
||||
internal class AvatarNameCardPicConverter : IValueConverter
|
||||
{
|
||||
private const string BaseUrl = "https://static.snapgenshin.com/NameCardPic/UI_NameCardPic_{0}_P.png";
|
||||
|
||||
/// <inheritdoc/>
|
||||
public object Convert(object value, Type targetType, object parameter, string language)
|
||||
{
|
||||
if (value == null)
|
||||
{
|
||||
return null!;
|
||||
}
|
||||
|
||||
Avatar.Avatar avatar = (Avatar.Avatar)value;
|
||||
string avatarName = avatar.Icon[14..];
|
||||
return new Uri(string.Format(BaseUrl, avatarName));
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public object ConvertBack(object value, Type targetType, object parameter, string language)
|
||||
{
|
||||
throw Must.NeverHappen();
|
||||
}
|
||||
}
|
||||
@@ -9,7 +9,7 @@
|
||||
<Identity
|
||||
Name="7f0db578-026f-4e0b-a75b-d5d06bb0a74d"
|
||||
Publisher="CN=DGP Studio"
|
||||
Version="1.0.11.0" />
|
||||
Version="1.0.13.0" />
|
||||
|
||||
<Properties>
|
||||
<DisplayName>胡桃</DisplayName>
|
||||
|
||||
@@ -71,10 +71,9 @@
|
||||
<PackageReference Include="CommunityToolkit.WinUI.UI.Behaviors" Version="7.1.2" />
|
||||
<PackageReference Include="CommunityToolkit.WinUI.UI.Controls" Version="7.1.2" />
|
||||
<PackageReference Include="CommunityToolkit.WinUI.UI.Media" Version="7.1.2" />
|
||||
<PackageReference Include="Microsoft.AppCenter.Analytics" Version="4.5.1" />
|
||||
<PackageReference Include="Microsoft.AppCenter.Crashes" Version="4.5.1" />
|
||||
<PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite" Version="6.0.6" />
|
||||
<PackageReference Include="Microsoft.EntityFrameworkCore.Tools" Version="6.0.6" />
|
||||
<PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite" Version="6.0.7" />
|
||||
<!-- The PrivateAssets & IncludeAssets of Microsoft.EntityFrameworkCore.Tools should be remove to prevent multiple deps file-->
|
||||
<PackageReference Include="Microsoft.EntityFrameworkCore.Tools" Version="6.0.7" />
|
||||
<PackageReference Include="Microsoft.Extensions.Caching.Memory" Version="6.0.1" />
|
||||
<PackageReference Include="Microsoft.Extensions.Http" Version="6.0.0" />
|
||||
<PackageReference Include="Microsoft.Extensions.Logging.Debug" Version="6.0.0" />
|
||||
|
||||
@@ -5,7 +5,6 @@
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:cwuc="using:CommunityToolkit.WinUI.UI.Controls"
|
||||
xmlns:cwum="using:CommunityToolkit.WinUI.UI.Media"
|
||||
xmlns:mxic="using:Microsoft.Xaml.Interactions.Core"
|
||||
xmlns:mxi="using:Microsoft.Xaml.Interactivity"
|
||||
xmlns:shc="using:Snap.Hutao.Control"
|
||||
@@ -27,6 +26,7 @@
|
||||
<shmmc:AvatarSideIconConverter x:Key="AvatarSideIconConverter"/>
|
||||
<shmmc:ElementNameIconConverter x:Key="ElementNameIconConverter"/>
|
||||
<shmmc:WeaponTypeIconConverter x:Key="WeaponTypeIconConverter"/>
|
||||
<shmmc:AvatarNameCardPicConverter x:Key="AvatarNameCardPicConverter"/>
|
||||
|
||||
<shmmc:FightPropertyConverter x:Key="FightPropertyConverter"/>
|
||||
<shmmc:FightPropertyValueFormatter x:Key="FightPropertyValueFormatter"/>
|
||||
@@ -144,44 +144,48 @@
|
||||
</Expander>
|
||||
</DataTemplate>
|
||||
</Page.Resources>
|
||||
|
||||
<Grid>
|
||||
<SplitView
|
||||
IsPaneOpen="True"
|
||||
DisplayMode="Inline"
|
||||
OpenPaneLength="200">
|
||||
<SplitView.PaneBackground>
|
||||
<SolidColorBrush Color="{StaticResource CardBackgroundFillColorSecondary}"/>
|
||||
</SplitView.PaneBackground>
|
||||
<SplitView.Pane>
|
||||
<ListView
|
||||
SelectionMode="Single"
|
||||
ItemsSource="{Binding Avatars}"
|
||||
SelectedItem="{Binding Selected,Mode=TwoWay}">
|
||||
<ListView.ItemTemplate>
|
||||
<DataTemplate>
|
||||
<Grid>
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="auto"/>
|
||||
<ColumnDefinition/>
|
||||
</Grid.ColumnDefinitions>
|
||||
<shci:CachedImage
|
||||
Grid.Column="0"
|
||||
Width="48"
|
||||
Height="48"
|
||||
Margin="0,0,12,12"
|
||||
Source="{Binding SideIcon,Converter={StaticResource AvatarSideIconConverter},Mode=OneWay}"/>
|
||||
<TextBlock
|
||||
VerticalAlignment="Center"
|
||||
Grid.Column="1"
|
||||
Margin="12,0,0,0"
|
||||
Text="{Binding Name}"/>
|
||||
</Grid>
|
||||
</DataTemplate>
|
||||
</ListView.ItemTemplate>
|
||||
</ListView>
|
||||
</SplitView.Pane>
|
||||
<SplitView.Content>
|
||||
|
||||
<SplitView
|
||||
IsPaneOpen="True"
|
||||
DisplayMode="Inline"
|
||||
OpenPaneLength="200">
|
||||
<SplitView.PaneBackground>
|
||||
<SolidColorBrush Color="{StaticResource CardBackgroundFillColorSecondary}"/>
|
||||
</SplitView.PaneBackground>
|
||||
<SplitView.Pane>
|
||||
<ListView
|
||||
SelectionMode="Single"
|
||||
ItemsSource="{Binding Avatars}"
|
||||
SelectedItem="{Binding Selected,Mode=TwoWay}">
|
||||
<ListView.ItemTemplate>
|
||||
<DataTemplate>
|
||||
<Grid>
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="auto"/>
|
||||
<ColumnDefinition/>
|
||||
</Grid.ColumnDefinitions>
|
||||
<shci:CachedImage
|
||||
Grid.Column="0"
|
||||
Width="48"
|
||||
Height="48"
|
||||
Margin="0,0,12,12"
|
||||
Source="{Binding SideIcon,Converter={StaticResource AvatarSideIconConverter},Mode=OneWay}"/>
|
||||
<TextBlock
|
||||
VerticalAlignment="Center"
|
||||
Grid.Column="1"
|
||||
Margin="12,0,0,0"
|
||||
Text="{Binding Name}"/>
|
||||
</Grid>
|
||||
</DataTemplate>
|
||||
</ListView.ItemTemplate>
|
||||
</ListView>
|
||||
</SplitView.Pane>
|
||||
<SplitView.Content>
|
||||
<Grid>
|
||||
<shci:Gradient
|
||||
VerticalAlignment="Top"
|
||||
Source="{Binding Selected,Converter={StaticResource AvatarNameCardPicConverter}}">
|
||||
</shci:Gradient>
|
||||
<ScrollViewer>
|
||||
<StackPanel Margin="0,0,16,16">
|
||||
<!--简介-->
|
||||
@@ -391,7 +395,7 @@
|
||||
</ItemsControl>
|
||||
</Grid>
|
||||
</ScrollViewer>
|
||||
|
||||
|
||||
</Expander>
|
||||
<TextBlock Text="天赋" Style="{StaticResource BaseTextBlockStyle}" Margin="16,16,0,0"/>
|
||||
<ItemsControl
|
||||
@@ -407,9 +411,9 @@
|
||||
<ItemsControl
|
||||
ItemsSource="{Binding Selected.SkillDepot.Inherents}"
|
||||
ItemTemplate="{StaticResource InherentDataTemplate}"/>
|
||||
|
||||
|
||||
<TextBlock Text="命之座" Style="{StaticResource BaseTextBlockStyle}" Margin="16,16,0,0"/>
|
||||
|
||||
|
||||
<ItemsControl
|
||||
ItemsSource="{Binding Selected.SkillDepot.Talents}"
|
||||
ItemTemplate="{StaticResource InherentDataTemplate}"/>
|
||||
@@ -494,7 +498,7 @@
|
||||
</Expander>
|
||||
</StackPanel>
|
||||
</ScrollViewer>
|
||||
</SplitView.Content>
|
||||
</SplitView>
|
||||
</Grid>
|
||||
</Grid>
|
||||
</SplitView.Content>
|
||||
</SplitView>
|
||||
</Page>
|
||||
Reference in New Issue
Block a user