fix monochrome #1784

This commit is contained in:
DismissedLight
2024-07-05 11:54:45 +08:00
parent eeee9af09d
commit 52949e3431
12 changed files with 79 additions and 114 deletions

View File

@@ -20,7 +20,6 @@ using System.Diagnostics;
using System.IO;
using System.Net;
using System.Net.Http;
using Windows.ApplicationModel.Appointments;
using Windows.Foundation;
using Windows.Graphics.Imaging;
using WinRT;
@@ -58,7 +57,10 @@ internal sealed partial class ImageCache : IImageCache, IImageCacheFilePathOpera
{
get => LazyInitializer.EnsureInitialized(ref cacheFolder, () =>
{
return serviceProvider.GetRequiredService<RuntimeOptions>().GetLocalCacheImageCacheFolder();
string folder = serviceProvider.GetRequiredService<RuntimeOptions>().GetLocalCacheImageCacheFolder();
Directory.CreateDirectory(Path.Combine(folder, "Light"));
Directory.CreateDirectory(Path.Combine(folder, "Dark"));
return folder;
});
}
@@ -102,13 +104,13 @@ internal sealed partial class ImageCache : IImageCache, IImageCacheFilePathOpera
using (ScopedTaskCompletionSource themeFileScope = new())
{
ElementThemeValueFile key = new(fileName, theme);
string defaultFilePath = Path.Combine(CacheFolder, fileName);
string themeOrDefaultFilePath = theme is ElementTheme.Dark or ElementTheme.Light ? Path.Combine(CacheFolder, $"{theme}", fileName) : defaultFilePath;
if (themefileTasks.TryAdd(key, themeFileScope.Task))
{
try
{
string defaultFilePath = Path.Combine(CacheFolder, fileName);
string themeOrDefaultFilePath = theme is ElementTheme.Dark or ElementTheme.Light ? Path.Combine(CacheFolder, $"{theme}", fileName) : defaultFilePath;
if (!IsFileInvalid(themeOrDefaultFilePath))
{
return themeOrDefaultFilePath;
@@ -157,7 +159,7 @@ internal sealed partial class ImageCache : IImageCache, IImageCacheFilePathOpera
else if (themefileTasks.TryGetValue(key, out Task? task))
{
await task.ConfigureAwait(false);
return key.File;
return themeOrDefaultFilePath;
}
}
@@ -224,7 +226,7 @@ internal sealed partial class ImageCache : IImageCache, IImageCacheFilePathOpera
byteAccess.GetBuffer(out Span<Rgba32> span);
foreach (ref Rgba32 pixel in span)
{
pixel.A = (byte)(pixel.Luminance * 255);
pixel.A = (byte)pixel.Luminance255;
pixel.R = pixel.G = pixel.B = background;
}
}

View File

@@ -39,6 +39,8 @@ internal struct Rgba32
public readonly double Luminance { get => ((0.299 * R) + (0.587 * G) + (0.114 * B)) / 255; }
public readonly double Luminance255 { get => (0.299 * R) + (0.587 * G) + (0.114 * B); }
public static unsafe implicit operator Color(Rgba32 rgba32)
{
return ColorHelper.ToColor(rgba32);

View File

@@ -9,6 +9,8 @@ using Microsoft.UI.Xaml.Media.Imaging;
using Snap.Hutao.Core.Caching;
using Snap.Hutao.Core.DataTransfer;
using Snap.Hutao.Core.ExceptionService;
using Snap.Hutao.UI.Xaml.Control.Theme;
using System.Diagnostics;
using System.IO;
using System.Runtime.InteropServices;
using Windows.Graphics.Imaging;
@@ -32,7 +34,8 @@ namespace Snap.Hutao.UI.Xaml.Control.Image;
[DependencyProperty("PlaceholderSource", typeof(object), default(object))]
[DependencyProperty("PlaceholderStretch", typeof(Stretch), Stretch.Uniform)]
[DependencyProperty("PlaceholderMargin", typeof(Thickness))]
[DependencyProperty("Source", typeof(object), default(object), nameof(SourceChanged))]
[DependencyProperty("Source", typeof(object), default(object), nameof(OnSourceChanged))]
[DependencyProperty("ShowAsMonoChrome", typeof(bool), false)]
internal sealed partial class CachedImage : Microsoft.UI.Xaml.Controls.Control, IAlphaMaskProvider
{
private const string PartImage = "Image";
@@ -48,6 +51,7 @@ internal sealed partial class CachedImage : Microsoft.UI.Xaml.Controls.Control,
public CachedImage()
{
DefaultStyleKey = typeof(CachedImage);
ActualThemeChanged += OnActualThemeChanged;
}
public bool IsInitialized { get; private set; }
@@ -146,7 +150,7 @@ internal sealed partial class CachedImage : Microsoft.UI.Xaml.Controls.Control,
}
}
private static void SourceChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
private static void OnSourceChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
if (d is not CachedImage control)
{
@@ -171,10 +175,12 @@ internal sealed partial class CachedImage : Microsoft.UI.Xaml.Controls.Control,
SourceName = Path.GetFileName(imageUri.ToString());
IImageCache imageCache = this.ServiceProvider().GetRequiredService<IImageCache>();
string file = default;
try
{
HutaoException.ThrowIf(string.IsNullOrEmpty(imageUri.Host), SH.ControlImageCachedImageInvalidResourceUri);
string file = await imageCache.GetFileFromCacheAsync(imageUri).ConfigureAwait(true); // BitmapImage need to be created by main thread.
ElementTheme theme = ShowAsMonoChrome ? ThemeHelper.ApplicationToElement(ThemeHelper.ElementToApplication(ActualTheme)) : ElementTheme.Default;
file = await imageCache.GetFileFromCacheAsync(imageUri, theme).ConfigureAwait(true); // BitmapImage need to be created by main thread.
CachedName = Path.GetFileName(file);
token.ThrowIfCancellationRequested(); // check token state to determine whether the operation should be canceled.
return file.ToUri();
@@ -185,6 +191,17 @@ internal sealed partial class CachedImage : Microsoft.UI.Xaml.Controls.Control,
imageCache.Remove(imageUri);
return default;
}
catch (Exception ex)
{
Debug.WriteLine(file);
Debug.WriteLine(ex);
return default;
}
}
private void OnActualThemeChanged(FrameworkElement sender, object args)
{
SetSource(Source);
}
private void OnImageOpened(object sender, RoutedEventArgs e)

View File

@@ -1,57 +0,0 @@
// Copyright (c) DGP Studio. All rights reserved.
// Licensed under the MIT license.
using Microsoft.Graphics.Canvas.Effects;
using Microsoft.UI;
using Microsoft.UI.Composition;
using Microsoft.UI.Xaml;
using Microsoft.UI.Xaml.Media;
using Snap.Hutao.UI.Composition;
using Snap.Hutao.UI.Xaml.Control.Theme;
using Windows.Foundation;
namespace Snap.Hutao.UI.Xaml.Control.Image;
internal sealed class MonoChrome : CompositionImage
{
private CompositionColorBrush? backgroundBrush;
public MonoChrome()
{
ActualThemeChanged += OnActualThemeChanged;
}
protected override SpriteVisual CompositeSpriteVisual(Compositor compositor, LoadedImageSurface imageSurface)
{
CompositionColorBrush blackLayerBrush = compositor.CreateColorBrush(Colors.Black);
CompositionSurfaceBrush imageSurfaceBrush = compositor.CompositeSurfaceBrush(imageSurface, stretch: CompositionStretch.Uniform, vRatio: 0f);
CompositionEffectBrush overlayBrush = compositor.CompositeBlendEffectBrush(blackLayerBrush, imageSurfaceBrush, BlendEffectMode.Overlay);
CompositionEffectBrush opacityBrush = compositor.CompositeLuminanceToAlphaEffectBrush(overlayBrush);
backgroundBrush = compositor.CreateColorBrush();
SetBackgroundColor(backgroundBrush);
CompositionEffectBrush alphaMaskEffectBrush = compositor.CompositeAlphaMaskEffectBrush(backgroundBrush, opacityBrush);
return compositor.CompositeSpriteVisual(alphaMaskEffectBrush);
}
private void OnActualThemeChanged(FrameworkElement sender, object args)
{
if (backgroundBrush is not null)
{
SetBackgroundColor(backgroundBrush);
}
}
private void SetBackgroundColor(CompositionColorBrush backgroundBrush)
{
ApplicationTheme theme = ThemeHelper.ElementToApplication(ActualTheme);
backgroundBrush.Color = theme switch
{
ApplicationTheme.Light => Colors.Black,
ApplicationTheme.Dark => Colors.White,
_ => Colors.Transparent,
};
}
}

View File

@@ -5,17 +5,8 @@ using Microsoft.UI.Xaml;
namespace Snap.Hutao.UI.Xaml.Control.Theme;
/// <summary>
/// 主题帮助工具类
/// </summary>
[HighQuality]
internal static class ThemeHelper
{
/// <summary>
/// 从 <see cref="ElementTheme"/> 转换到 <see cref="ApplicationTheme"/>
/// </summary>
/// <param name="applicationTheme">元素主题</param>
/// <returns>应用主题</returns>
public static ApplicationTheme ElementToApplication(ElementTheme applicationTheme)
{
return applicationTheme switch
@@ -26,23 +17,22 @@ internal static class ThemeHelper
};
}
/// <summary>
/// 检查是否为暗黑模式
/// </summary>
/// <param name="elementTheme">当前元素主题</param>
/// <returns>是否为暗黑模式</returns>
public static ElementTheme ApplicationToElement(ApplicationTheme applicationTheme)
{
return applicationTheme switch
{
ApplicationTheme.Light => ElementTheme.Light,
ApplicationTheme.Dark => ElementTheme.Dark,
_ => ElementTheme.Default,
};
}
public static bool IsDarkMode(ElementTheme elementTheme)
{
ApplicationTheme appTheme = Ioc.Default.GetRequiredService<App>().RequestedTheme;
return IsDarkMode(elementTheme, appTheme);
}
/// <summary>
/// 检查是否为暗黑模式
/// </summary>
/// <param name="elementTheme">当前元素主题</param>
/// <param name="applicationTheme">当前应用主题</param>
/// <returns>是否为暗黑模式</returns>
public static bool IsDarkMode(ElementTheme elementTheme, ApplicationTheme applicationTheme)
{
return elementTheme switch

View File

@@ -27,10 +27,11 @@
<ColumnDefinition Width="auto"/>
<ColumnDefinition/>
</Grid.ColumnDefinitions>
<shuxci:MonoChrome
<shuxci:CachedImage
Grid.Column="0"
Width="36"
Height="36"
ShowAsMonoChrome="True"
Source="{Binding Icon}"/>
<TextBlock
Grid.Column="1"

View File

@@ -55,12 +55,12 @@
<DataTemplate x:Key="AvatarGridViewSkillTemplate">
<shuxcc:VerticalCard>
<shuxcc:VerticalCard.Top>
<shuxci:MonoChrome
<shuxci:CachedImage
Width="40"
Height="40"
Margin="12"
HorizontalAlignment="Center"
EnableShowHideAnimation="False"
ShowAsMonoChrome="True"
Source="{Binding Icon}"/>
</shuxcc:VerticalCard.Top>
<shuxcc:VerticalCard.Bottom>
@@ -319,9 +319,10 @@
<RowDefinition/>
<RowDefinition Height="auto"/>
</Grid.RowDefinitions>
<shuxci:MonoChrome
<shuxci:CachedImage
Width="16"
Height="16"
ShowAsMonoChrome="True"
Source="{Binding Icon}"/>
<TextBlock
Grid.Row="0"

View File

@@ -90,11 +90,12 @@
<SolidColorBrush Color="{Binding Quality}"/>
</Ellipse.Fill>
</Ellipse>
<shuxci:MonoChrome
<shuxci:CachedImage
Grid.Column="0"
Width="20"
Height="20"
Margin="-3,2,7,0"
ShowAsMonoChrome="True"
Source="{Binding IconUri, Mode=OneWay}"
Visibility="{Binding IconUri, Converter={StaticResource EmptyObjectToVisibilityConverter}}"/>
<shuxci:CachedImage
@@ -408,16 +409,18 @@
<ColumnDefinition Width="auto"/>
<ColumnDefinition Width="auto"/>
</Grid.ColumnDefinitions>
<shuxci:MonoChrome
<shuxci:CachedImage
Grid.Column="0"
Width="32"
Height="32"
HorizontalAlignment="Left"
ShowAsMonoChrome="True"
Source="{Binding Selected.FetterInfo.VisionBefore, Converter={StaticResource ElementNameIconConverter}}"/>
<shuxci:MonoChrome
<shuxci:CachedImage
Grid.Column="1"
Width="32"
Height="32"
ShowAsMonoChrome="True"
Source="{Binding Selected.Weapon, Converter={StaticResource WeaponTypeIconConverter}}"/>
</Grid>
<Border Style="{ThemeResource BorderCardStyle}">

View File

@@ -49,11 +49,12 @@
<SolidColorBrush Color="{Binding Quality}"/>
</Ellipse.Fill>
</Ellipse>
<shuxci:MonoChrome
<shuxci:CachedImage
Grid.Column="0"
Width="20"
Height="20"
Margin="-5,2,9,0"
ShowAsMonoChrome="True"
Source="{Binding IconUri, Mode=OneWay}"
Visibility="{Binding IconUri, Converter={StaticResource EmptyObjectToVisibilityConverter}}"/>
<shuxci:CachedImage

View File

@@ -19,7 +19,10 @@
<DataTemplate x:Key="SkillHeaderTemplate">
<StackPanel Background="Transparent" ToolTipService.ToolTip="{Binding Name}">
<shuxci:MonoChrome shux:FrameworkElementHelper.SquareLength="36" Source="{Binding Icon, Converter={StaticResource SkillIconConverter}}"/>
<shuxci:CachedImage
shux:FrameworkElementHelper.SquareLength="36"
ShowAsMonoChrome="True"
Source="{Binding Icon, Converter={StaticResource SkillIconConverter}}"/>
</StackPanel>
</DataTemplate>
</UserControl.Resources>

View File

@@ -358,21 +358,7 @@
CommandParameter="{Binding ElementName=SignInRewardButton}"
Icon="{shuxm:FontIcon Glyph={StaticResource FontIconContentGiftboxOpen}}"
Label="{shuxm:ResourceString Name=ViewUserCookieOperationSignInRewardAction}"
Style="{StaticResource DefaultAppBarButtonStyle}">
<mxi:Interaction.Behaviors>
<mxic:EventTriggerBehavior EventName="Click">
<shuxba:ShowWebView2WindowAction>
<shuxba:ShowWebView2WindowAction.ContentProvider>
<shuxvww:MiHoYoJSBridgeWebView2ContentProvider>
<shuxvww:MiHoYoJSBridgeWebView2ContentProvider.SourceProvider>
<shvu:SignInJSBridgeUriSourceProvider/>
</shuxvww:MiHoYoJSBridgeWebView2ContentProvider.SourceProvider>
</shuxvww:MiHoYoJSBridgeWebView2ContentProvider>
</shuxba:ShowWebView2WindowAction.ContentProvider>
</shuxba:ShowWebView2WindowAction>
</mxic:EventTriggerBehavior>
</mxi:Interaction.Behaviors>
</AppBarButton>
Style="{StaticResource DefaultAppBarButtonStyle}"/>
<AppBarButton
Width="{StaticResource LargeAppBarButtonWidth}"
MaxWidth="{StaticResource LargeAppBarButtonWidth}"

View File

@@ -3,7 +3,6 @@
using CommunityToolkit.Mvvm.ComponentModel;
using Microsoft.UI.Xaml.Controls;
using Microsoft.UI.Xaml.Controls.Primitives;
using Snap.Hutao.Core;
using Snap.Hutao.Core.Database;
using Snap.Hutao.Core.DataTransfer;
@@ -13,8 +12,10 @@ using Snap.Hutao.Service.Navigation;
using Snap.Hutao.Service.Notification;
using Snap.Hutao.Service.SignIn;
using Snap.Hutao.Service.User;
using Snap.Hutao.UI.Xaml.Behavior.Action;
using Snap.Hutao.UI.Xaml.View.Dialog;
using Snap.Hutao.UI.Xaml.View.Page;
using Snap.Hutao.UI.Xaml.View.Window.WebView2;
using Snap.Hutao.Web.Hoyolab;
using Snap.Hutao.Web.Hoyolab.Passport;
using Snap.Hutao.Web.Response;
@@ -244,9 +245,24 @@ internal sealed partial class UserViewModel : ObservableObject
return;
}
infoBarService.Warning(message);
if (appBarButton is null)
{
return;
}
// Manual webview
await taskContext.SwitchToMainThreadAsync();
FlyoutBase.ShowAttachedFlyout(appBarButton);
infoBarService.Warning(message);
ShowWebView2WindowAction action = new()
{
ContentProvider = new MiHoYoJSBridgeWebView2ContentProvider()
{
SourceProvider = new SignInJSBridgeUriSourceProvider(),
},
};
action.Execute(appBarButton, default!);
}
}