fix QA issue

This commit is contained in:
DismissedLight
2024-07-01 23:17:50 +08:00
parent a2f9ff95a4
commit fe05c8dd04
9 changed files with 146 additions and 135 deletions

View File

@@ -10,6 +10,7 @@ using Snap.Hutao.Core.Caching;
using Snap.Hutao.Core.Graphics;
using Snap.Hutao.Service.Notification;
using Snap.Hutao.UI.Xaml.Media.Animation;
using System.Diagnostics;
using System.IO;
using System.Net.Http;
using System.Runtime.InteropServices;
@@ -17,11 +18,6 @@ using Windows.Foundation;
namespace Snap.Hutao.UI.Xaml.Control.Image;
/// <summary>
/// 合成图像控件
/// 为其他图像类控件提供基类
/// </summary>
[HighQuality]
[DependencyProperty("EnableShowHideAnimation", typeof(bool), true)]
[DependencyProperty("Source", typeof(Uri), default!, nameof(OnSourceChanged))]
internal abstract partial class CompositionImage : Microsoft.UI.Xaml.Controls.Control
@@ -30,48 +26,38 @@ internal abstract partial class CompositionImage : Microsoft.UI.Xaml.Controls.Co
private readonly IServiceProvider serviceProvider;
private readonly SizeChangedEventHandler sizeChangedEventHandler;
private readonly TypedEventHandler<LoadedImageSurface, LoadedImageSourceLoadCompletedEventArgs> loadedImageSourceLoadCompletedEventHandler;
private TaskCompletionSource? surfaceLoadTaskCompletionSource;
private SpriteVisual? spriteVisual;
private bool isShow = true;
/// <summary>
/// 构造一个新的单色图像
/// </summary>
protected CompositionImage()
{
serviceProvider = this.ServiceProvider();
this.DisableInteraction();
sizeChangedEventHandler = OnSizeChanged;
SizeChanged += sizeChangedEventHandler;
loadedImageSourceLoadCompletedEventHandler = OnLoadImageSurfaceLoadCompleted;
SizeChanged += OnSizeChanged;
}
/// <summary>
/// 合成组合视觉
/// </summary>
/// <param name="compositor">合成器</param>
/// <param name="imageSurface">图像表面</param>
/// <returns>拼合视觉</returns>
protected abstract SpriteVisual CompositeSpriteVisual(Compositor compositor, LoadedImageSurface imageSurface);
protected virtual void LoadImageSurfaceCompleted(LoadedImageSurface surface)
{
}
/// <summary>
/// 更新视觉对象
/// </summary>
/// <param name="spriteVisual">拼合视觉</param>
protected virtual void UpdateVisual(SpriteVisual spriteVisual)
{
spriteVisual.Size = ActualSize;
}
protected override void OnApplyTemplate()
{
base.OnApplyTemplate();
if (!string.IsNullOrEmpty(Source.OriginalString))
{
OnSourceChangedCore(Source);
}
}
private static void OnSourceChanged(DependencyObject sender, DependencyPropertyChangedEventArgs arg)
{
CompositionImage image = (CompositionImage)sender;
@@ -87,9 +73,7 @@ internal abstract partial class CompositionImage : Microsoft.UI.Xaml.Controls.Co
// value is different from old one
if (inner != (arg.OldValue as Uri))
{
image
.ApplyImageAsync(inner, token)
.SafeForget(logger, ex => OnApplyImageFailed(serviceProvider, inner, ex));
image.OnSourceChangedCore(inner);
}
}
else
@@ -101,6 +85,7 @@ internal abstract partial class CompositionImage : Microsoft.UI.Xaml.Controls.Co
private static void OnApplyImageFailed(IServiceProvider serviceProvider, Uri? uri, Exception exception)
{
Debugger.Break();
IInfoBarService infoBarService = serviceProvider.GetRequiredService<IInfoBarService>();
if (exception is HttpRequestException httpRequestException)
@@ -117,6 +102,13 @@ internal abstract partial class CompositionImage : Microsoft.UI.Xaml.Controls.Co
}
}
private void OnSourceChangedCore(Uri? uri)
{
CancellationToken token = loadingTokenSource.Register();
ILogger<CompositionImage> logger = serviceProvider.GetRequiredService<ILogger<CompositionImage>>();
ApplyImageAsync(uri, token).SafeForget(logger, ex => OnApplyImageFailed(serviceProvider, uri, ex));
}
private async ValueTask ApplyImageAsync(Uri? uri, CancellationToken token)
{
await HideAsync(token).ConfigureAwait(true);
@@ -154,21 +146,28 @@ internal abstract partial class CompositionImage : Microsoft.UI.Xaml.Controls.Co
await ShowAsync(token).ConfigureAwait(true);
}
}
else
{
Debugger.Break();
}
}
}
private async ValueTask<LoadedImageSurface> LoadImageSurfaceAsync(string file, CancellationToken token)
{
token.ThrowIfCancellationRequested();
TaskCompletionSource cancelTcs = new();
CancellationTokenRegistration registration = token.Register(() => cancelTcs.TrySetResult(), false);
surfaceLoadTaskCompletionSource = new();
LoadedImageSurface? surface = default;
try
{
surface = LoadedImageSurface.StartLoadFromUri(file.ToUri());
surface.LoadCompleted += loadedImageSourceLoadCompletedEventHandler;
surface.LoadCompleted += OnLoadImageSurfaceLoadCompleted;
if (surface.DecodedPhysicalSize.Size() <= 0D)
{
await Task.WhenAny(surfaceLoadTaskCompletionSource.Task, Task.Delay(5000, token)).ConfigureAwait(true);
await Task.Delay(50, token).ConfigureAwait(true);
await Task.WhenAny(surfaceLoadTaskCompletionSource.Task, cancelTcs.Task).ConfigureAwait(true);
}
LoadImageSurfaceCompleted(surface);
@@ -178,8 +177,10 @@ internal abstract partial class CompositionImage : Microsoft.UI.Xaml.Controls.Co
{
if (surface is not null)
{
surface.LoadCompleted -= loadedImageSourceLoadCompletedEventHandler;
surface.LoadCompleted -= OnLoadImageSurfaceLoadCompleted;
}
registration.Dispose();
}
}

View File

@@ -12,26 +12,15 @@ using Windows.Foundation;
namespace Snap.Hutao.UI.Xaml.Control.Image;
/// <summary>
/// 支持单色的图像
/// </summary>
[HighQuality]
internal sealed class MonoChrome : CompositionImage
{
private readonly TypedEventHandler<FrameworkElement, object> actualThemeChangedEventHandler;
private CompositionColorBrush? backgroundBrush;
/// <summary>
/// 构造一个新的单色图像
/// </summary>
public MonoChrome()
{
actualThemeChangedEventHandler = OnActualThemeChanged;
ActualThemeChanged += actualThemeChangedEventHandler;
ActualThemeChanged += OnActualThemeChanged;
}
/// <inheritdoc/>
protected override SpriteVisual CompositeSpriteVisual(Compositor compositor, LoadedImageSurface imageSurface)
{
CompositionColorBrush blackLayerBrush = compositor.CreateColorBrush(Colors.Black);

View File

@@ -188,6 +188,7 @@ internal sealed partial class UniformStaggeredLayout : VirtualizingLayout
}
UniformStaggeredLayoutState state = (UniformStaggeredLayoutState)context.LayoutState;
int virtualColumnCount = (int)(finalSize.Width / state.ColumnWidth);
// Cycle through each column and arrange the items that are within the realization bounds
for (int columnIndex = 0; columnIndex < state.NumberOfColumns; columnIndex++)
@@ -204,9 +205,9 @@ internal sealed partial class UniformStaggeredLayout : VirtualizingLayout
// Partial or fully in the view
if (item.Top <= context.RealizationRect.Bottom)
{
double itemHorizontalOffset = (state.ColumnWidth * columnIndex) + (MinColumnSpacing * columnIndex);
double itemHorizontalOffset = (state.ColumnWidth + MinColumnSpacing) * columnIndex;
double width = columnIndex == state.NumberOfColumns - 1
double width = columnIndex == virtualColumnCount - 1
? finalSize.Width - itemHorizontalOffset
: state.ColumnWidth;

View File

@@ -20,9 +20,20 @@ internal sealed partial class SizeRestrictedContentControl : ContentControl
{
element.Measure(availableSize);
Size contentDesiredSize = element.DesiredSize;
Size contentActualOrDesiredSize = new(
Math.Min(Math.Max(element.ActualWidth, contentDesiredSize.Width), availableSize.Width),
Math.Min(Math.Max(element.ActualHeight, contentDesiredSize.Height), availableSize.Height));
Math.Clamp(element.ActualWidth, contentDesiredSize.Width, availableSize.Width),
Math.Clamp(element.ActualHeight, contentDesiredSize.Height, availableSize.Height));
if (minContentWidth > availableSize.Width)
{
minContentWidth = 0;
}
if (minContentHeight > availableSize.Height)
{
minContentHeight = 0;
}
if (IsWidthRestricted)
{

View File

@@ -154,7 +154,7 @@
ItemsSource="{Binding List}">
<ItemsRepeater.Layout>
<UniformGridLayout
ItemsJustification="SpaceBetween"
ItemsJustification="Start"
ItemsStretch="Fill"
MinColumnSpacing="12"
MinItemWidth="300"

View File

@@ -484,7 +484,10 @@
ItemsSource="{Binding DailyNoteOptions.RefreshTimes}"
SelectedItem="{Binding DailyNoteOptions.SelectedRefreshTime, Mode=TwoWay}">
<RadioButtons.Header>
<TextBlock Style="{StaticResource BaseTextBlockStyle}" Text="{shuxm:ResourceString Name=ViewPageDailyNoteRefreshTime}"/>
<TextBlock
Margin="1,0,0,0"
Style="{StaticResource BaseTextBlockStyle}"
Text="{shuxm:ResourceString Name=ViewPageDailyNoteRefreshTime}"/>
</RadioButtons.Header>
<RadioButtons.ItemTemplate>
<DataTemplate>
@@ -547,7 +550,7 @@
ItemsSource="{Binding DailyNoteEntries}">
<ItemsRepeater.Layout>
<UniformGridLayout
ItemsJustification="SpaceBetween"
ItemsJustification="Start"
ItemsStretch="Fill"
MinColumnSpacing="12"
MinItemWidth="300"

View File

@@ -426,11 +426,14 @@
Height="32"
Source="{Binding Selected.Weapon, Converter={StaticResource WeaponTypeIconConverter}}"/>
</Grid>
<shuxc:ItemIcon
Width="128"
Height="128"
Icon="{Binding Selected.Icon, Converter={StaticResource AvatarIconConverter}, Mode=OneWay}"
Quality="{Binding Selected.Quality, Mode=OneWay}"/>
<Border Style="{ThemeResource BorderCardStyle}">
<shuxc:ItemIcon
Width="128"
Height="128"
Icon="{Binding Selected.Icon, Converter={StaticResource AvatarIconConverter}, Mode=OneWay}"
Quality="{Binding Selected.Quality, Mode=OneWay}"/>
</Border>
</StackPanel>
<StackPanel Grid.Column="1" Margin="16">
@@ -524,19 +527,21 @@
</StackPanel>
<StackPanel Grid.Row="1" Grid.ColumnSpan="2">
<ItemsControl
Margin="16,0,16,16"
ItemTemplate="{StaticResource CultivationItemTemplate}"
ItemsSource="{Binding Selected.CultivationItemsView}">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<cwc:UniformGrid
ColumnSpacing="8"
Columns="3"
RowSpacing="8"/>
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
</ItemsControl>
<ScrollViewer>
<ItemsRepeater
Margin="16,0,16,16"
ItemTemplate="{StaticResource CultivationItemTemplate}"
ItemsSource="{Binding Selected.CultivationItemsView}">
<ItemsRepeater.Layout>
<UniformGridLayout
ItemsJustification="Start"
ItemsStretch="Fill"
MaximumRowsOrColumns="3"
MinColumnSpacing="8"
MinRowSpacing="8"/>
</ItemsRepeater.Layout>
</ItemsRepeater>
</ScrollViewer>
</StackPanel>
</Grid>

View File

@@ -91,7 +91,7 @@
</Grid>
</DataTemplate>
<DataTemplate x:Key="CultivateItemTemplate">
<DataTemplate x:Key="CultivationItemTemplate">
<shuxcc:HorizontalCard>
<shuxcc:HorizontalCard.Left>
<shuxc:ItemIcon
@@ -257,63 +257,61 @@
</StackPanel>
<ScrollViewer Visibility="{Binding Weapons.Count, Converter={StaticResource Int32ToVisibilityConverter}}">
<StackPanel Padding="16" Spacing="16">
<Border cw:Effects.Shadow="{ThemeResource CompatCardShadow}">
<Border Style="{ThemeResource AcrylicBorderCardStyle}">
<Border.Background>
<ImageBrush ImageSource="ms-appx:///Resource/Icon/UI_GachaShowPanel_Bg_Weapon.png"/>
</Border.Background>
<cwc:ConstrainedBox AspectRatio="2048:1024">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="auto"/>
<ColumnDefinition/>
</Grid.ColumnDefinitions>
<Border Grid.ColumnSpan="2" Background="{ThemeResource DarkOnlyOverlayMaskColorBrush}"/>
<Border Style="{ThemeResource BorderCardStyle}">
<Border.Background>
<ImageBrush ImageSource="ms-appx:///Resource/Icon/UI_GachaShowPanel_Bg_Weapon.png"/>
</Border.Background>
<cwc:ConstrainedBox AspectRatio="2048:1024">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="auto"/>
<ColumnDefinition/>
</Grid.ColumnDefinitions>
<Border Grid.ColumnSpan="2" Background="{ThemeResource DarkOnlyOverlayMaskColorBrush}"/>
<Grid Grid.ColumnSpan="2">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="176*"/>
<ColumnDefinition Width="848*"/>
</Grid.ColumnDefinitions>
<shuxci:CachedImage
Grid.Column="1"
HorizontalAlignment="Center"
VerticalAlignment="Stretch"
Source="{Binding Selected.Icon, Converter={StaticResource GachaEquipIconConverter}}"/>
</Grid>
<ScrollViewer
Grid.Column="0"
Margin="16"
VerticalScrollBarVisibility="Hidden">
<StackPanel Spacing="16">
<shuxcc:VerticalCard MaxWidth="80">
<shuxcc:VerticalCard.Top>
<shuxc:ItemIcon Icon="{Binding Selected.Icon, Converter={StaticResource EquipIconConverter}}" Quality="{Binding Selected.RankLevel}"/>
</shuxcc:VerticalCard.Top>
<shuxcc:VerticalCard.Bottom>
<TextBlock Text="{shuxm:ResourceString Name=ViewPageWiKiWeaponBeforeAscensionTitle}"/>
</shuxcc:VerticalCard.Bottom>
</shuxcc:VerticalCard>
<shuxcc:VerticalCard MaxWidth="80">
<shuxcc:VerticalCard.Top>
<shuxc:ItemIcon Icon="{Binding Selected.AwakenIcon, Converter={StaticResource EquipIconConverter}}" Quality="{Binding Selected.RankLevel}"/>
</shuxcc:VerticalCard.Top>
<shuxcc:VerticalCard.Bottom>
<TextBlock Text="{shuxm:ResourceString Name=ViewPageWiKiWeaponAfterAscensionTitle}"/>
</shuxcc:VerticalCard.Bottom>
</shuxcc:VerticalCard>
</StackPanel>
</ScrollViewer>
<TextBlock
<Grid Grid.ColumnSpan="2">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="176*"/>
<ColumnDefinition Width="848*"/>
</Grid.ColumnDefinitions>
<shuxci:CachedImage
Grid.Column="1"
Margin="16"
HorizontalAlignment="Right"
VerticalAlignment="Bottom"
Style="{StaticResource SubtitleTextBlockStyle}"
Text="{Binding Selected.Name}"/>
HorizontalAlignment="Center"
VerticalAlignment="Stretch"
Source="{Binding Selected.Icon, Converter={StaticResource GachaEquipIconConverter}}"/>
</Grid>
</cwc:ConstrainedBox>
</Border>
<ScrollViewer
Grid.Column="0"
Margin="16"
VerticalScrollBarVisibility="Hidden">
<StackPanel Spacing="16">
<shuxcc:VerticalCard MaxWidth="80">
<shuxcc:VerticalCard.Top>
<shuxc:ItemIcon Icon="{Binding Selected.Icon, Converter={StaticResource EquipIconConverter}}" Quality="{Binding Selected.RankLevel}"/>
</shuxcc:VerticalCard.Top>
<shuxcc:VerticalCard.Bottom>
<TextBlock Text="{shuxm:ResourceString Name=ViewPageWiKiWeaponBeforeAscensionTitle}"/>
</shuxcc:VerticalCard.Bottom>
</shuxcc:VerticalCard>
<shuxcc:VerticalCard MaxWidth="80">
<shuxcc:VerticalCard.Top>
<shuxc:ItemIcon Icon="{Binding Selected.AwakenIcon, Converter={StaticResource EquipIconConverter}}" Quality="{Binding Selected.RankLevel}"/>
</shuxcc:VerticalCard.Top>
<shuxcc:VerticalCard.Bottom>
<TextBlock Text="{shuxm:ResourceString Name=ViewPageWiKiWeaponAfterAscensionTitle}"/>
</shuxcc:VerticalCard.Bottom>
</shuxcc:VerticalCard>
</StackPanel>
</ScrollViewer>
<TextBlock
Grid.Column="1"
Margin="16"
HorizontalAlignment="Right"
VerticalAlignment="Bottom"
Style="{StaticResource SubtitleTextBlockStyle}"
Text="{Binding Selected.Name}"/>
</Grid>
</cwc:ConstrainedBox>
</Border>
<TextBlock
@@ -332,16 +330,18 @@
Margin="0,0,0,0"
Style="{StaticResource BaseTextBlockStyle}"
Text="{shuxm:ResourceString Name=ViewPageWiKiAvatarAscensionMaterialsHeader}"/>
<ItemsControl ItemTemplate="{StaticResource CultivateItemTemplate}" ItemsSource="{Binding Selected.CultivationItemsView}">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<cwc:UniformGrid
ColumnSpacing="8"
Columns="3"
RowSpacing="8"/>
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
</ItemsControl>
<ScrollViewer>
<ItemsRepeater ItemTemplate="{StaticResource CultivationItemTemplate}" ItemsSource="{Binding Selected.CultivationItemsView}">
<ItemsRepeater.Layout>
<UniformGridLayout
ItemsJustification="Start"
ItemsStretch="Fill"
MaximumRowsOrColumns="3"
MinColumnSpacing="8"
MinRowSpacing="8"/>
</ItemsRepeater.Layout>
</ItemsRepeater>
</ScrollViewer>
</StackPanel>
</Border>

View File

@@ -104,9 +104,10 @@ internal sealed class UserInfo
{
get
{
string source = AvatarUrl.OriginalString;
string? source = AvatarUrl?.OriginalString;
if (!string.IsNullOrEmpty(source))
{
ArgumentNullException.ThrowIfNull(AvatarUrl);
return AvatarUrl;
}