feat: 公告弹窗 (#6557)

This commit is contained in:
uye
2023-09-28 09:24:29 +08:00
committed by GitHub
14 changed files with 331 additions and 111 deletions

View File

@@ -187,5 +187,8 @@ namespace MaaWpfGui.Constants
public const string ForceScheduledStart = "Timer.ForceScheduledStart";
public const string CustomConfig = "Timer.CustomConfig";
public const string AnnouncementInfo = "Announcement.AnnouncementInfo";
public const string IsFirstShowAnnouncement = "Announcement.IsFirstShowAnnouncement";
}
}

View File

@@ -62,6 +62,8 @@ namespace MaaWpfGui.Helper
public static VersionUpdateViewModel VersionUpdateViewModel { get; private set; }
public static AnnouncementViewModel AnnouncementViewModel { get; private set; }
public static AsstProxy AsstProxy { get; private set; }
public static TrayIcon TrayIcon { get; private set; }
@@ -88,6 +90,7 @@ namespace MaaWpfGui.Helper
SettingsViewModel = container.Get<SettingsViewModel>();
CopilotViewModel = container.Get<CopilotViewModel>();
VersionUpdateViewModel = container.Get<VersionUpdateViewModel>();
AnnouncementViewModel = container.Get<AnnouncementViewModel>();
// 这仨实例化时存在依赖顺序
HttpService = container.Get<HttpService>();

View File

@@ -16,6 +16,7 @@ using System.Diagnostics;
using System.IO;
using System.Runtime.InteropServices;
using System.Security.Principal;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Threading;
using GlobalHotKey;
@@ -193,6 +194,17 @@ namespace MaaWpfGui.Main
/// <inheritdoc/>
protected override void OnLaunch()
{
Task.Run(async () =>
{
if (!Instances.AnnouncementViewModel.IsFirstShowAnnouncement)
{
return;
}
await Instances.AnnouncementViewModel.CheckAndDownloadAnnouncement();
_ = Execute.OnUIThreadAsync(() => Instances.WindowManager.ShowWindow(Instances.AnnouncementViewModel));
Instances.AnnouncementViewModel.IsFirstShowAnnouncement = false;
});
Instances.VersionUpdateViewModel.ShowUpdateOrDownload();
}

View File

@@ -670,4 +670,8 @@ The video aspect ratio needs to be 16:9 without interference factors such as bla
<system:String x:Key="ExternalNotificationEmailTemplateLinkCopilotSite">MAA Copilot (Chinese)</system:String>
<system:String x:Key="ExternalNotificationEmailTemplateHello">Doctor, there's a new notification!</system:String>
<!-- External Notification -->
<!-- Announcement -->
<system:String x:Key="Announcement">Announcement</system:String>
<system:String x:Key="CheckAndDownloadAnnouncement">View Announcement</system:String>
<!-- Announcement -->
</ResourceDictionary>

View File

@@ -670,4 +670,8 @@ Bilibili: ログイン インターフェイスに表示されるアカウント
<system:String x:Key="ExternalNotificationEmailTemplateLinkOfficialSite">公式サイト</system:String>
<system:String x:Key="ExternalNotificationEmailTemplateLinkCopilotSite">Copilot中国語</system:String>
<!-- External Notification -->
<!-- Announcement -->
<system:String x:Key="Announcement">公告</system:String>
<system:String x:Key="CheckAndDownloadAnnouncement">公告を見ます</system:String>
<!-- Announcement -->
</ResourceDictionary>

View File

@@ -670,4 +670,8 @@ Bilibili: 로그인 인터페이스에 표시되는 계정 이름(예: 장산)
<system:String x:Key="ExternalNotificationEmailTemplateLinkOfficialSite">공식 홈페이지</system:String>
<system:String x:Key="ExternalNotificationEmailTemplateLinkCopilotSite">워크 스테이션</system:String>
<!-- External Notification -->
<!-- Announcement -->
<system:String x:Key="Announcement">공고패</system:String>
<system:String x:Key="CheckAndDownloadAnnouncement">공고패</system:String>
<!-- Announcement -->
</ResourceDictionary>

View File

@@ -670,4 +670,8 @@
<system:String x:Key="ExternalNotificationEmailTemplateLinkOfficialSite">官网</system:String>
<system:String x:Key="ExternalNotificationEmailTemplateLinkCopilotSite">作业站</system:String>
<!-- External Notification -->
<!-- Announcement -->
<system:String x:Key="Announcement">公告</system:String>
<system:String x:Key="CheckAndDownloadAnnouncement">查看公告</system:String>
<!-- Announcement -->
</ResourceDictionary>

View File

@@ -670,4 +670,8 @@
<system:String x:Key="ExternalNotificationEmailTemplateLinkOfficialSite">官網</system:String>
<system:String x:Key="ExternalNotificationEmailTemplateLinkCopilotSite">作業站</system:String>
<!-- External Notification -->
<!-- Announcement -->
<system:String x:Key="Announcement">公告</system:String>
<system:String x:Key="CheckAndDownloadAnnouncement">查看公告</system:String>
<!-- Announcement -->
</ResourceDictionary>

View File

@@ -0,0 +1,125 @@
// <copyright file="AnnouncementViewModel.cs" company="MaaAssistantArknights">
// MaaWpfGui - A part of the MaaCoreArknights project
// Copyright (C) 2021 MistEO and Contributors
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY
// </copyright>
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Net.Http;
using System.Threading.Tasks;
using System.Windows.Documents;
using System.Windows.Input;
using MaaWpfGui.Constants;
using MaaWpfGui.Helper;
using Markdig;
using Markdig.Wpf;
using Stylet;
namespace MaaWpfGui.ViewModels.UI
{
/// <summary>
/// The view model of version update.
/// </summary>
// 通过 container.Get<TaskQueueViewModel>(); 实例化或获取实例
// ReSharper disable once ClassNeverInstantiated.Global
public class AnnouncementViewModel : Screen
{
private string _announcementInfo = ConfigurationHelper.GetValue(ConfigurationKeys.AnnouncementInfo, string.Empty);
/// <summary>
/// Gets the announcement info.
/// </summary>
// ReSharper disable once MemberCanBePrivate.Global
public string AnnouncementInfo
{
get => _announcementInfo;
private set
{
SetAndNotify(ref _announcementInfo, value);
ConfigurationHelper.SetValue(ConfigurationKeys.AnnouncementInfo, value);
}
}
private bool _isFirstShowAnnouncement = bool.Parse(ConfigurationHelper.GetValue(ConfigurationKeys.IsFirstShowAnnouncement, true.ToString()));
public bool IsFirstShowAnnouncement
{
get => _isFirstShowAnnouncement;
set
{
SetAndNotify(ref _isFirstShowAnnouncement, value);
ConfigurationHelper.SetValue(ConfigurationKeys.IsFirstShowAnnouncement, value.ToString());
}
}
public FlowDocument AnnouncementInfoDoc => Markdig.Wpf.Markdown.ToFlowDocument(AnnouncementInfo,
new MarkdownPipelineBuilder().UseSupportedExtensions().Build());
/// <summary>
/// 检查更新
/// </summary>
public async Task CheckAndDownloadAnnouncement()
{
const string Path = "announcements/wpf.md";
const string Url = MaaUrls.MaaApi + Path;
var etag = !string.IsNullOrEmpty(AnnouncementInfo) ? ETagCache.Get(Url) : string.Empty;
Dictionary<string, string> header = new Dictionary<string, string>
{
{ "Accept", "application/octet-stream" },
};
if (!string.IsNullOrEmpty(etag))
{
header["If-None-Match"] = etag;
}
var response = await Instances.HttpService.GetAsync(new Uri(Url), header, httpCompletionOption: HttpCompletionOption.ResponseHeadersRead);
if (response == null ||
response.StatusCode == System.Net.HttpStatusCode.NotModified ||
response.StatusCode != System.Net.HttpStatusCode.OK)
{
return;
}
try
{
var body = await response.Content.ReadAsStringAsync();
if (!string.IsNullOrEmpty(body))
{
AnnouncementInfo = body;
IsFirstShowAnnouncement = true;
}
}
catch
{
return;
}
ETagCache.Set(Url, response.Headers.ETag.Tag);
ETagCache.Save();
}
/// <summary>
/// The event handler of opening hyperlink.
/// </summary>
/// <param name="sender">The sender.</param>
/// <param name="e">The event arguments.</param>
// xaml 里用到了
// ReSharper disable once UnusedMember.Global
// ReSharper disable once UnusedParameter.Global
public void OpenHyperlink(object sender, ExecutedRoutedEventArgs e)
{
Process.Start(e.Parameter.ToString());
}
}
}

View File

@@ -3727,5 +3727,13 @@ namespace MaaWpfGui.ViewModels.UI
{
(sender as ComboBox)?.MakeComboBoxSearchable();
}
// UI 绑定的方法
// ReSharper disable once UnusedMember.Global
public async Task CheckAndDownloadAnnouncement()
{
await Instances.AnnouncementViewModel.CheckAndDownloadAnnouncement();
_ = Execute.OnUIThreadAsync(() => Instances.WindowManager.ShowWindow(Instances.AnnouncementViewModel));
}
}
}

View File

@@ -395,24 +395,6 @@ namespace MaaWpfGui.ViewModels.UI
{
IsFirstBootAfterUpdate = false;
Instances.WindowManager.ShowWindow(this);
//if (false) // _curVersion == "v4.24.0"
//{
// var result = MessageBoxHelper.Show(
// LocalizationHelper.GetString("Dotnet8"),
// LocalizationHelper.GetString("Dotnet8Caption"),
// MessageBoxButton.YesNo,
// MessageBoxImage.Information);
// switch (result)
// {
// case MessageBoxResult.No:
// Instances.SettingsViewModel.AutoDownloadUpdatePackage = false;
// break;
// case MessageBoxResult.Yes:
// Process.Start("https://dotnet.microsoft.com/download/dotnet/8.0/runtime");
// break;
// }
//}
}
else
{
@@ -992,6 +974,7 @@ namespace MaaWpfGui.ViewModels.UI
/// <param name="e">The event arguments.</param>
// xaml 里用到了
// ReSharper disable once UnusedMember.Global
// ReSharper disable once UnusedParameter.Global
public void OpenHyperlink(object sender, ExecutedRoutedEventArgs e)
{
Process.Start(e.Parameter.ToString());

View File

@@ -0,0 +1,54 @@
<hc:Window
x:Class="MaaWpfGui.Views.UI.AnnouncementView"
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:hc="https://handyorg.github.io/handycontrol"
xmlns:markdig="clr-namespace:Markdig.Wpf;assembly=Markdig.Wpf"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:s="https://github.com/canton7/Stylet"
xmlns:ui="clr-namespace:MaaWpfGui.ViewModels.UI"
Title="{DynamicResource Announcement}"
Width="600"
Height="500"
d:DataContext="{d:DesignInstance {x:Type ui:AnnouncementViewModel}}"
mc:Ignorable="d">
<Grid Background="{DynamicResource VersionUpdateViewBackgroundBrush}">
<Grid.RowDefinitions>
<RowDefinition Height="*" />
<RowDefinition Height="20" />
</Grid.RowDefinitions>
<FlowDocumentScrollViewer
x:Name="UpdateInfoMarkdownDocument"
Grid.Row="0"
Margin="16,0"
Document="{Binding AnnouncementInfoDoc}"
IsSelectionEnabled="False"
Zoom="90">
<FlowDocumentScrollViewer.Template>
<ControlTemplate TargetType="FlowDocumentScrollViewer">
<Border
Margin="{TemplateBinding Padding}"
BorderBrush="{TemplateBinding BorderBrush}"
BorderThickness="{TemplateBinding BorderThickness}"
CornerRadius="{Binding Path=(hc:BorderElement.CornerRadius), RelativeSource={RelativeSource TemplatedParent}}"
Focusable="False">
<hc:ScrollViewer
x:Name="PART_ContentHost"
HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}"
VerticalAlignment="{TemplateBinding VerticalContentAlignment}"
CanContentScroll="True"
IsInertiaEnabled="True" />
</Border>
</ControlTemplate>
</FlowDocumentScrollViewer.Template>
<FlowDocumentScrollViewer.CommandBindings>
<CommandBinding Command="{x:Static markdig:Commands.Hyperlink}" Executed="{s:Action OpenHyperlink}" />
</FlowDocumentScrollViewer.CommandBindings>
</FlowDocumentScrollViewer>
</Grid>
</hc:Window>

View File

@@ -17,101 +17,115 @@
d:DataContext="{d:DesignInstance {x:Type ui:SettingsViewModel}}"
d:DesignWidth="550"
mc:Ignorable="d">
<StackPanel Margin="10" VerticalAlignment="Center">
<controls:TextBlock
Margin="5"
HorizontalAlignment="Center"
VerticalAlignment="Center">
<Hyperlink
Cursor="Hand"
NavigateUri="{Binding Source={x:Static constants:MaaUrls.MaaPlus}}"
TextDecorations="None">
<TextBlock Text="{DynamicResource Website}" />
</Hyperlink>
</controls:TextBlock>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<StackPanel Grid.Column="0">
<controls:TextBlock
Margin="5"
HorizontalAlignment="Center"
VerticalAlignment="Center">
<Hyperlink
Cursor="Hand"
NavigateUri="{Binding Source={x:Static constants:MaaUrls.MaaPlus}}"
TextDecorations="None">
<TextBlock Text="{DynamicResource Website}" />
</Hyperlink>
</controls:TextBlock>
<controls:TextBlock
Margin="5"
HorizontalAlignment="Center"
VerticalAlignment="Center">
<Hyperlink
Cursor="Hand"
NavigateUri="{Binding Source={x:Static constants:MaaUrls.Bilibili}}"
TextDecorations="None">
<TextBlock Text="bilibili" />
</Hyperlink>
</controls:TextBlock>
<controls:TextBlock
Margin="5"
HorizontalAlignment="Center"
VerticalAlignment="Center">
<Hyperlink
Cursor="Hand"
NavigateUri="{Binding Source={x:Static constants:MaaUrls.Bilibili}}"
TextDecorations="None">
<TextBlock Text="bilibili" />
</Hyperlink>
</controls:TextBlock>
<controls:TextBlock
Margin="5"
HorizontalAlignment="Center"
VerticalAlignment="Center">
<Hyperlink
Cursor="Hand"
NavigateUri="{Binding Source={x:Static constants:MaaUrls.GitHub}}"
TextDecorations="None">
<TextBlock Text="{DynamicResource Github}" />
</Hyperlink>
</controls:TextBlock>
<controls:TextBlock
Margin="5"
HorizontalAlignment="Center"
VerticalAlignment="Center">
<Hyperlink
Cursor="Hand"
NavigateUri="{Binding Source={x:Static constants:MaaUrls.GitHub}}"
TextDecorations="None">
<TextBlock Text="{DynamicResource Github}" />
</Hyperlink>
</controls:TextBlock>
<controls:TextBlock
Margin="5"
HorizontalAlignment="Center"
VerticalAlignment="Center">
<Hyperlink
Cursor="Hand"
NavigateUri="{Binding Source={x:Static constants:MaaUrls.QqGroups}}"
TextDecorations="None">
<TextBlock Text="{DynamicResource QqGroup}" />
</Hyperlink>
</controls:TextBlock>
<controls:TextBlock
Margin="5"
HorizontalAlignment="Center"
VerticalAlignment="Center">
<Hyperlink
Cursor="Hand"
NavigateUri="{Binding Source={x:Static constants:MaaUrls.QqGroups}}"
TextDecorations="None">
<TextBlock Text="{DynamicResource QqGroup}" />
</Hyperlink>
</controls:TextBlock>
<controls:TextBlock
Margin="5"
HorizontalAlignment="Center"
VerticalAlignment="Center">
<Hyperlink
Cursor="Hand"
NavigateUri="{Binding Source={x:Static constants:MaaUrls.QqChannel}}"
TextDecorations="None">
<TextBlock Text="{DynamicResource QqChannel}" />
</Hyperlink>
</controls:TextBlock>
<controls:TextBlock
Margin="5"
HorizontalAlignment="Center"
VerticalAlignment="Center">
<Hyperlink
Cursor="Hand"
NavigateUri="{Binding Source={x:Static constants:MaaUrls.QqChannel}}"
TextDecorations="None">
<TextBlock Text="{DynamicResource QqChannel}" />
</Hyperlink>
</controls:TextBlock>
</StackPanel>
<StackPanel Grid.Column="1">
<controls:TextBlock
Margin="5"
HorizontalAlignment="Center"
VerticalAlignment="Center">
<Hyperlink
Cursor="Hand"
NavigateUri="{Binding Source={x:Static constants:MaaUrls.Telegram}}"
TextDecorations="None">
<TextBlock Text="{DynamicResource Telegram}" />
</Hyperlink>
</controls:TextBlock>
<controls:TextBlock
Margin="5"
HorizontalAlignment="Center"
VerticalAlignment="Center">
<Hyperlink
Cursor="Hand"
NavigateUri="{Binding Source={x:Static constants:MaaUrls.Telegram}}"
TextDecorations="None">
<TextBlock Text="{DynamicResource Telegram}" />
</Hyperlink>
</controls:TextBlock>
<controls:TextBlock
Margin="5"
HorizontalAlignment="Center"
VerticalAlignment="Center">
<Hyperlink
Cursor="Hand"
NavigateUri="{Binding Source={x:Static constants:MaaUrls.HelpUri}}"
TextDecorations="None">
<TextBlock Text="{DynamicResource Help}" />
</Hyperlink>
</controls:TextBlock>
<controls:TextBlock
Margin="5"
HorizontalAlignment="Center"
VerticalAlignment="Center">
<Hyperlink
Cursor="Hand"
NavigateUri="{Binding Source={x:Static constants:MaaUrls.HelpUri}}"
TextDecorations="None">
<TextBlock Text="{DynamicResource Help}" />
</Hyperlink>
</controls:TextBlock>
<controls:TextBlock
Margin="5"
HorizontalAlignment="Center"
VerticalAlignment="Center">
<Hyperlink
Cursor="Hand"
NavigateUri="{Binding Source={x:Static constants:MaaUrls.GitHubIssues}}"
TextDecorations="None">
<TextBlock Text="{DynamicResource Issue}" />
</Hyperlink>
</controls:TextBlock>
<controls:TextBlock
Margin="5"
HorizontalAlignment="Center"
VerticalAlignment="Center">
<Hyperlink
Cursor="Hand"
NavigateUri="{Binding Source={x:Static constants:MaaUrls.GitHubIssues}}"
TextDecorations="None">
<TextBlock Text="{DynamicResource Issue}" />
</Hyperlink>
</controls:TextBlock>
</StackPanel>
<Button
Width="Auto"
MaxWidth="100"
Margin="5"
Command="{s:Action CheckAndDownloadAnnouncement}"
Content="{DynamicResource CheckAndDownloadAnnouncement}" />
</StackPanel>
</Grid>
</UserControl>

View File

@@ -114,9 +114,7 @@
Text="{DynamicResource RoguelikeStartWithEliteTwo}"
TextWrapping="Wrap" />
</CheckBox>
<CheckBox
Margin="0,10"
IsChecked="{Binding RoguelikeUseSupportUnit}">
<CheckBox Margin="0,10" IsChecked="{Binding RoguelikeUseSupportUnit}">
<TextBlock
Block.TextAlignment="Left"
Text="{DynamicResource RoguelikeUseSupportUnit}"