Announcement Viewer

This commit is contained in:
DismissedLight
2023-01-20 15:47:05 +08:00
parent ad440e0561
commit 06c8b347d3
7 changed files with 207 additions and 168 deletions

View File

@@ -0,0 +1,21 @@
// Copyright (c) DGP Studio. All rights reserved.
// Licensed under the MIT license.
using Microsoft.UI.Xaml;
using Microsoft.UI.Xaml.Controls.Primitives;
using Microsoft.Xaml.Interactivity;
namespace Snap.Hutao.Control.Behavior;
/// <summary>
/// 打开附着的浮出控件操作
/// </summary>
internal class OpenAttachedFlyoutAction : DependencyObject, IAction
{
/// <inheritdoc/>
public object Execute(object sender, object parameter)
{
FlyoutBase.ShowAttachedFlyout(sender as FrameworkElement);
return null!;
}
}

View File

@@ -1,21 +1,20 @@
<Page
x:Class="Snap.Hutao.View.Page.AnnouncementContentPage"
<UserControl
x:Class="Snap.Hutao.View.Control.AnnouncementContentViewer"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
ActualThemeChanged="PageActualThemeChanged"
Background="{ThemeResource ApplicationPageBackgroundThemeBrush}"
Loaded="OnLoaded"
mc:Ignorable="d">
<Page.Transitions>
<UserControl.Transitions>
<TransitionCollection>
<NavigationThemeTransition>
<DrillInNavigationTransitionInfo/>
</NavigationThemeTransition>
<EntranceThemeTransition/>
</TransitionCollection>
</Page.Transitions>
</UserControl.Transitions>
<WebView2
x:Name="WebView"
Margin="0,0,0,0"
DefaultBackgroundColor="Transparent"
IsRightTapEnabled="False"/>
</Page>
</UserControl>

View File

@@ -0,0 +1,164 @@
// Copyright (c) DGP Studio. All rights reserved.
// Licensed under the MIT license.
using Microsoft.UI.Xaml;
using Microsoft.UI.Xaml.Navigation;
using Microsoft.Web.WebView2.Core;
using Snap.Hutao.Control;
using Snap.Hutao.Core;
using Snap.Hutao.Service.Navigation;
using Snap.Hutao.Web.Hoyolab.Hk4e.Common.Announcement;
using Windows.System;
namespace Snap.Hutao.View.Control;
/// <summary>
/// 公告内容页面
/// </summary>
public sealed partial class AnnouncementContentViewer : Microsoft.UI.Xaml.Controls.UserControl
{
// apply in dark mode, Dark theme
private const string LightColor1 = "color:rgba(255,255,255,1)";
private const string LightColor2 = "color:rgba(238,238,238,1)";
private const string LightColor3 = "color:rgba(204,204,204,1)";
private const string LightColor4 = "color:rgba(198,196,191,1)";
private const string LightColor5 = "color:rgba(170,170,170,1)";
private const string LightAccentColor1 = "background-color: rgb(0,40,70)";
private const string LightAccentColor2 = "background-color: rgb(1,40,70)";
// find in content, Light theme
private const string DarkColor1 = "color:rgba(0,0,0,1)";
private const string DarkColor2 = "color:rgba(17,17,17,1)";
private const string DarkColor3 = "color:rgba(51,51,51,1)";
private const string DarkColor4 = "color:rgba(57,59,64,1)";
private const string DarkColor5 = "color:rgba(85,85,85,1)";
private const string DarkAccentColor1 = "background-color: rgb(255, 215, 185);";
private const string DarkAccentColor2 = "background-color: rgb(254, 245, 231);";
// support click open browser.
private const string MihoyoSDKDefinition = """
window.miHoYoGameJSSDK = {
openInBrowser: function(url){ window.chrome.webview.postMessage(url); },
openInWebview: function(url){ location.href = url }
}
""";
private static readonly DependencyProperty AnnouncementProperty = Property<AnnouncementContentViewer>.Depend<Announcement>(nameof(Announcement));
/// <summary>
/// 构造一个新的公告窗体
/// </summary>
public AnnouncementContentViewer()
{
InitializeComponent();
}
/// <summary>
/// 目标公告
/// </summary>
public Announcement Announcement
{
get { return (Announcement)GetValue(AnnouncementProperty); }
set { SetValue(AnnouncementProperty, value); }
}
private static string? GenerateHtml(Announcement? announcement, ElementTheme theme)
{
if (announcement == null)
{
return null;
}
string content = announcement.Content;
if (string.IsNullOrWhiteSpace(content))
{
return null;
}
content = content
.Replace(@"style=""vertical-align:middle;""", string.Empty)
.Replace(@"style=""border:none;vertical-align:middle;""", string.Empty);
bool isDarkMode = ThemeHelper.IsDarkMode(theme);
if (isDarkMode)
{
content = content
.Replace(DarkColor5, LightColor5)
.Replace(DarkColor4, LightColor4)
.Replace(DarkColor3, LightColor3)
.Replace(DarkColor2, LightColor2)
.Replace(DarkColor1, LightColor1)
.Replace(DarkAccentColor1, LightAccentColor1)
.Replace(DarkAccentColor2, LightAccentColor2);
}
string document = $$"""
<!DOCTYPE html>
<html>
<head>
<style>
body::-webkit-scrollbar {
display: none;
}
img{
border: none;
vertical-align: middle;
width: 100%;
}
</style>
</head>
<body style="{{(isDarkMode ? LightColor1 : DarkColor1)}}; background-color: transparent;">
<h3>{{announcement.Title}}</h3>
<img src="{{announcement.Banner}}" />
<br>
{{content}}
</body>
</html>
""";
return document;
}
private async Task LoadAnnouncementAsync()
{
try
{
await WebView.EnsureCoreWebView2Async();
CoreWebView2Settings settings = WebView.CoreWebView2.Settings;
settings.AreBrowserAcceleratorKeysEnabled = false;
settings.AreDefaultContextMenusEnabled = false;
settings.AreDevToolsEnabled = false;
WebView.CoreWebView2.WebMessageReceived += OnWebMessageReceived;
await WebView.CoreWebView2.AddScriptToExecuteOnDocumentCreatedAsync(MihoyoSDKDefinition);
}
catch (Exception)
{
return;
}
WebView.NavigateToString(GenerateHtml(Announcement, ActualTheme));
}
private void OnLoaded(object sender, RoutedEventArgs e)
{
LoadAnnouncementAsync().SafeForget();
}
private void OnWebMessageReceived(CoreWebView2 coreWebView2, CoreWebView2WebMessageReceivedEventArgs args)
{
string url = args.TryGetWebMessageAsString();
if (Uri.TryCreate(url, UriKind.RelativeOrAbsolute, out Uri? uri))
{
Launcher.LaunchUriAsync(uri).AsTask().SafeForget();
}
}
}

View File

@@ -1,134 +0,0 @@
// Copyright (c) DGP Studio. All rights reserved.
// Licensed under the MIT license.
using Microsoft.UI.Xaml;
using Microsoft.UI.Xaml.Navigation;
using Microsoft.Web.WebView2.Core;
using Snap.Hutao.Core;
using Snap.Hutao.Service.Navigation;
using Windows.System;
namespace Snap.Hutao.View.Page;
/// <summary>
/// An empty page that can be used on its own or navigated to within a Frame.
/// </summary>
public sealed partial class AnnouncementContentPage : Microsoft.UI.Xaml.Controls.Page
{
// apply in dark mode
private const string LightColor1 = "color:rgba(255,255,255,1)";
private const string LightColor2 = "color:rgba(238,238,238,1)";
private const string LightColor3 = "color:rgba(204,204,204,1)";
private const string LightColor4 = "color:rgba(198,196,191,1)";
private const string LightColor5 = "color:rgba(170,170,170,1)";
private const string LightAccentColor1 = "background-color: rgb(0,40,70)";
private const string LightAccentColor2 = "background-color: rgb(1,40,70)";
// find in content
private const string DarkColor1 = "color:rgba(0,0,0,1)";
private const string DarkColor2 = "color:rgba(17,17,17,1)";
private const string DarkColor3 = "color:rgba(51,51,51,1)";
private const string DarkColor4 = "color:rgba(57,59,64,1)";
private const string DarkColor5 = "color:rgba(85,85,85,1)";
private const string DarkAccentColor1 = "background-color: rgb(255, 215, 185);";
private const string DarkAccentColor2 = "background-color: rgb(254, 245, 231);";
// support click open browser.
private const string MihoyoSDKDefinition = """
window.miHoYoGameJSSDK = {
openInBrowser: function(url){ window.chrome.webview.postMessage(url); },
openInWebview: function(url){ location.href = url }
}
""";
private string? targetContent;
/// <summary>
/// 构造一个新的公告窗体
/// </summary>
public AnnouncementContentPage()
{
InitializeComponent();
}
/// <inheritdoc/>
protected override void OnNavigatedTo(NavigationEventArgs e)
{
base.OnNavigatedTo(e);
if (e.Parameter is INavigationData extra)
{
targetContent = extra.Data as string;
LoadAnnouncementAsync(extra).SafeForget();
}
}
/// <inheritdoc/>
protected override void OnNavigatedFrom(NavigationEventArgs e)
{
base.OnNavigatedFrom(e);
// WebView.CoreWebView2.Environment.Exit();
}
private static string? ReplaceForeground(string? rawContent, ElementTheme theme)
{
if (string.IsNullOrWhiteSpace(rawContent))
{
return rawContent;
}
bool isDarkMode = ThemeHelper.IsDarkMode(theme);
if (isDarkMode)
{
rawContent = rawContent
.Replace(DarkColor5, LightColor5)
.Replace(DarkColor4, LightColor4)
.Replace(DarkColor3, LightColor3)
.Replace(DarkColor2, LightColor2)
.Replace(DarkAccentColor1, LightAccentColor1)
.Replace(DarkAccentColor2, LightAccentColor2);
}
// wrap a default color body around
return $@"<body style=""{(isDarkMode ? LightColor1 : DarkColor1)}"">{rawContent}</body>";
}
private async Task LoadAnnouncementAsync(INavigationData data)
{
try
{
await WebView.EnsureCoreWebView2Async();
WebView.CoreWebView2.Settings.AreDefaultContextMenusEnabled = false;
WebView.CoreWebView2.WebMessageReceived += OnWebMessageReceived;
await WebView.CoreWebView2.AddScriptToExecuteOnDocumentCreatedAsync(MihoyoSDKDefinition);
}
catch (Exception ex)
{
data.NotifyNavigationException(ex);
return;
}
WebView.NavigateToString(ReplaceForeground(targetContent, ActualTheme));
data.NotifyNavigationCompleted();
}
private void PageActualThemeChanged(FrameworkElement sender, object args)
{
WebView.NavigateToString(ReplaceForeground(targetContent, ActualTheme));
}
[SuppressMessage("", "VSTHRD100")]
private async void OnWebMessageReceived(CoreWebView2 coreWebView2, CoreWebView2WebMessageReceivedEventArgs args)
{
string url = args.TryGetWebMessageAsString();
if (Uri.TryCreate(url, UriKind.RelativeOrAbsolute, out Uri? uri))
{
await Launcher.LaunchUriAsync(uri).AsTask().ConfigureAwait(false);
}
}
}

View File

@@ -15,6 +15,7 @@
xmlns:shcb="using:Snap.Hutao.Control.Behavior"
xmlns:shci="using:Snap.Hutao.Control.Image"
xmlns:shv="using:Snap.Hutao.ViewModel"
xmlns:shvc="using:Snap.Hutao.View.Control"
d:DataContext="{d:DesignInstance shv:AnnouncementViewModel}"
Background="{ThemeResource ApplicationPageBackgroundThemeBrush}"
mc:Ignorable="d">
@@ -122,9 +123,21 @@
</StackPanel>
</Border>
</Grid>
<FlyoutBase.AttachedFlyout>
<Flyout LightDismissOverlayMode="On" Placement="Full">
<Flyout.FlyoutPresenterStyle>
<Style BasedOn="{StaticResource DefaultFlyoutPresenterStyle}" TargetType="FlyoutPresenter">
<Setter Property="Padding" Value="0"/>
<Setter Property="CornerRadius" Value="0"/>
<Setter Property="MaxWidth" Value="560"/>
</Style>
</Flyout.FlyoutPresenterStyle>
<shvc:AnnouncementContentViewer Announcement="{Binding}"/>
</Flyout>
</FlyoutBase.AttachedFlyout>
<mxi:Interaction.Behaviors>
<mxic:EventTriggerBehavior EventName="Tapped">
<mxic:InvokeCommandAction Command="{Binding DataContext.OpenAnnouncementUICommand, Source={StaticResource BindingProxy}}" CommandParameter="{Binding Content}"/>
<shcb:OpenAttachedFlyoutAction/>
</mxic:EventTriggerBehavior>
<mxic:EventTriggerBehavior EventName="PointerEntered">
<cwub:StartAnimationAction Animation="{Binding ElementName=ImageZoomInAnimation}"/>

View File

@@ -58,7 +58,6 @@
<Flyout.FlyoutPresenterStyle>
<Style BasedOn="{StaticResource DefaultFlyoutPresenterStyle}" TargetType="FlyoutPresenter">
<Setter Property="Padding" Value="0,2,0,2"/>
<Setter Property="Background" Value="{ThemeResource FlyoutPresenterBackground}"/>
</Style>
</Flyout.FlyoutPresenterStyle>
<StackPanel>

View File

@@ -2,10 +2,7 @@
// Licensed under the MIT license.
using CommunityToolkit.Mvvm.Input;
using Snap.Hutao.Core;
using Snap.Hutao.Service.Abstraction;
using Snap.Hutao.Service.Navigation;
using Snap.Hutao.View.Page;
using Snap.Hutao.Web.Hoyolab.Hk4e.Common.Announcement;
namespace Snap.Hutao.ViewModel;
@@ -29,7 +26,6 @@ internal class AnnouncementViewModel : Abstraction.ViewModel
this.announcementService = announcementService;
OpenUICommand = new AsyncRelayCommand(OpenUIAsync);
OpenAnnouncementUICommand = new RelayCommand<string>(OpenAnnouncementUI);
}
/// <summary>
@@ -46,11 +42,6 @@ internal class AnnouncementViewModel : Abstraction.ViewModel
/// </summary>
public ICommand OpenUICommand { get; }
/// <summary>
/// 打开公告UI触发的命令
/// </summary>
public ICommand OpenAnnouncementUICommand { get; }
private async Task OpenUIAsync()
{
try
@@ -61,18 +52,4 @@ internal class AnnouncementViewModel : Abstraction.ViewModel
{
}
}
private void OpenAnnouncementUI(string? content)
{
if (WebView2Helper.IsSupported)
{
INavigationService navigationService = Ioc.Default.GetRequiredService<INavigationService>();
navigationService.Navigate<AnnouncementContentPage>(data: new NavigationExtra(content));
}
else
{
IInfoBarService infoBarService = Ioc.Default.GetRequiredService<IInfoBarService>();
infoBarService.Warning("尚未安装 WebView2 Runtime");
}
}
}