mirror of
https://jihulab.com/DGP-Studio/Snap.Hutao.git
synced 2025-11-19 21:02:53 +08:00
fix monochrome #1784
This commit is contained in:
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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,
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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}">
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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}"
|
||||
|
||||
@@ -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!);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user