Files
MaaAssistantArknights/src/MaaWpfGui/ViewModels/UI/AnnouncementViewModel.cs
uye 01504ff404 refactor: 重构公告 (#11734)
* refactor: 重构公告

* chore: 公告可数

* chore: TrimEnd -

* fix: 多余删除的 \n

* chore: 修改返回类型

* style: unused using

* chore: 标题支持多行显示

* chore: add english version of noskland

* feat: Switch image based on language

* chore: 点击 Listbox 时 ScrollViewer 滚动到最顶端

* chore: 加个预览图

* chore: 设计时预览

* fix: ---- 没移掉)

* chore: Content 也显示标题内容

* chore: 隐藏按钮

* perf: 优化分隔符删除

* chore: 压缩下图片

* feat: 调整公告关闭按钮布局

---------

Co-authored-by: Constrat <56174894+Constrat@users.noreply.github.com>
Co-authored-by: SherkeyXD <57581480+SherkeyXD@users.noreply.github.com>
2025-02-07 19:00:24 +08:00

215 lines
6.7 KiB
C#

// <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 Affero General Public License v3.0 only 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.ObjectModel;
using System.Linq;
using System.Threading.Tasks;
using System.Windows.Input;
using HandyControl.Controls;
using HandyControl.Tools.Command;
using MaaWpfGui.Configuration;
using MaaWpfGui.Constants;
using MaaWpfGui.Helper;
using Stylet;
namespace MaaWpfGui.ViewModels.UI
{
/// <summary>
/// The view model of version update.
/// </summary>
// 通过 container.Get<AnnouncementViewModel>(); 实例化或获取实例
// ReSharper disable once ClassNeverInstantiated.Global
public class AnnouncementViewModel : Screen
{
public string ImageSource { get; set; }
public class AnnouncementSection
{
public string Title { get; set; }
public string Content { get; set; }
}
public AnnouncementViewModel()
{
UpdateImageSource();
UpdateScrollStateCommand = new RelayCommand<ScrollViewer>(scrollViewer =>
{
if (scrollViewer == null)
{
return;
}
// 计算是否滚动到底部
IsScrolledToBottom |= scrollViewer.VerticalOffset >= scrollViewer.ScrollableHeight - 10;
});
ScrollToTopCommand = new RelayCommand<ScrollViewer>(scrollViewer =>
{
if (scrollViewer == null)
{
return;
}
scrollViewer.ScrollToTop();
});
AnnouncementSections = new(
ParseAnnouncementInfo(AnnouncementInfo));
SelectedAnnouncementSection = AnnouncementSections.FirstOrDefault();
}
private void UpdateImageSource()
{
ImageSource = SettingsViewModel.GuiSettings.Language switch
{
"zh-cn" or "zh-tw" => "/Res/Img/NoSkland.jpg",
_ => "/Res/Img/NoSkLandEn.jpg",
};
}
private static ObservableCollection<AnnouncementSection> ParseAnnouncementInfo(string markdown)
{
var sections = markdown.Split(["### "], StringSplitOptions.RemoveEmptyEntries)
.Select(section =>
{
var lines = section.Split('\n');
return new AnnouncementSection
{
Title = lines.FirstOrDefault(),
Content = "### " + string.Join("\n", lines).Trim([' ', '\n', '-']),
};
}).ToList();
sections.Insert(0, new()
{
Title = "ALL~ the Announcements",
Content = markdown,
});
return new(sections);
}
public ICommand UpdateScrollStateCommand { get; }
public ICommand ScrollToTopCommand { get; }
private bool _isScrolledToBottom;
public bool IsScrolledToBottom
{
get => _isScrolledToBottom;
set => SetAndNotify(ref _isScrolledToBottom, value);
}
private ObservableCollection<AnnouncementSection> _announcementSections;
public ObservableCollection<AnnouncementSection> AnnouncementSections
{
get => _announcementSections;
set => SetAndNotify(ref _announcementSections, value);
}
private AnnouncementSection _selectedAnnouncementSection;
public AnnouncementSection SelectedAnnouncementSection
{
get => _selectedAnnouncementSection;
set => SetAndNotify(ref _selectedAnnouncementSection, value);
}
private string _announcementInfo = ConfigFactory.Root.AnnouncementInfo.Info;
/// <summary>
/// Gets the announcement info.
/// </summary>
// ReSharper disable once MemberCanBePrivate.Global
public string AnnouncementInfo
{
get => _announcementInfo;
private set
{
SetAndNotify(ref _announcementInfo, value);
ConfigFactory.Root.AnnouncementInfo.Info = value;
}
}
private bool _doNotRemindThisAnnouncementAgain = ConfigFactory.Root.AnnouncementInfo.DoNotShowAgain;
public bool DoNotRemindThisAnnouncementAgain
{
get => _doNotRemindThisAnnouncementAgain;
set
{
SetAndNotify(ref _doNotRemindThisAnnouncementAgain, value);
ConfigFactory.Root.AnnouncementInfo.DoNotShowAgain = value;
}
}
private bool _doNotShowAnnouncement = ConfigFactory.Root.AnnouncementInfo.DoNotShow;
/// <summary>
/// Gets or sets a value indicating whether to show the update.
/// </summary>
public bool DoNotShowAnnouncement
{
get => _doNotShowAnnouncement;
set
{
SetAndNotify(ref _doNotShowAnnouncement, value);
ConfigFactory.Root.AnnouncementInfo.DoNotShow = value;
}
}
/// <summary>
/// 检查更新
/// </summary>
/// <returns>A <see cref="Task"/> representing the asynchronous operation.</returns>
public async Task CheckAndDownloadAnnouncement()
{
string path = "announcements/wpf";
if (SettingsViewModel.GuiSettings.Language is not ("zh-cn" or "zh-tw"))
{
path += "_en";
}
string url = MaaUrls.MaaApi + path + ".md";
using var response = await ETagCache.FetchResponseWithEtag(url, string.IsNullOrEmpty(AnnouncementInfo));
if (response == null ||
response.StatusCode == System.Net.HttpStatusCode.NotModified ||
response.StatusCode != System.Net.HttpStatusCode.OK)
{
return;
}
var body = await HttpResponseHelper.GetStringAsync(response);
if (!string.IsNullOrEmpty(body))
{
AnnouncementInfo = body;
DoNotRemindThisAnnouncementAgain = false;
}
ETagCache.Set(response);
ETagCache.Save();
}
public void Close()
{
RequestClose();
}
}
}