feat: 项目初始化 + 3D方块世界原型 + AI助搭系统
CI / Go Backend (push) Canceled after 0s

初始化 monorepo: Go后端(7微服务) + Unity客户端(9模块) + 启动器

HTML5原型: Three.js 3D体素世界, Perlin噪声地形, 原版材质, 22种方块

Minecraft创造模式背包: 双栏布局, 拖拽移动物品, 方向性元件引脚

AI助搭策划文档 + 客户端/服务端骨架 + Docker Compose + CI
This commit is contained in:
xyou
2026-08-08 14:07:56 +08:00
parent 9500c4c80a
commit f70b061d1a
1972 changed files with 159760 additions and 6 deletions
@@ -0,0 +1,506 @@
<local:MyPageRight
x:Class="PCL.PageSetupAbout"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:app="clr-namespace:PCL.Core.App;assembly=PCL.Core"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:local="clr-namespace:PCL"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d"
DataContext="{Binding Source={x:Static app:Basics.Metadata}}"
PanScroll="{Binding ElementName=PanBack}"
RenderOptions.BitmapScalingMode="LowQuality">
<local:MyScrollViewer
x:Name="PanBack"
HorizontalScrollBarVisibility="Disabled"
VerticalScrollBarVisibility="Auto">
<StackPanel
x:Name="PanMain"
Margin="25,10"
Grid.IsSharedSizeScope="True">
<local:MyCard Margin="0,15" Title="{DynamicResource Setup.About.Title}">
<Grid Margin="21,40,21,16">
<Grid.RowDefinitions>
<RowDefinition Height="45" />
<RowDefinition Height="45" />
<RowDefinition Height="45" />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="40" />
<ColumnDefinition />
<ColumnDefinition Width="150" />
</Grid.ColumnDefinitions>
<local:MyListItem
Grid.Row="0"
Grid.Column="1"
Margin="-5,0,15,0"
Info="{DynamicResource Setup.About.OriginalAuthor.Info}"
IsHitTestVisible="False"
Title="{DynamicResource Setup.About.OriginalAuthor.Name}" />
<local:MyListItem
Grid.Row="1"
Grid.Column="1"
Margin="-5,0,15,0"
Info="{DynamicResource Setup.About.Community.Info}"
IsHitTestVisible="False"
Title="{DynamicResource Setup.About.Community.Name}" />
<local:MyListItem
x:Name="ItemAboutPcl"
Grid.Row="2"
Grid.Column="1"
Margin="-5,0,15,0"
Info="{DynamicResource Setup.About.Version.Info}"
IsHitTestVisible="False"
Title="{Binding Name}" />
<Image
x:Name="ImgPCLLogo"
Grid.Row="2"
Margin="3" MouseLeftButtonDown="ImgPCLLogo_Click"
Source="/Plain Craft Launcher 2;component/Images/Heads/Logo-CE.png">
<Image.Clip>
<EllipseGeometry
Center="17 17"
RadiusX="17"
RadiusY="17" />
</Image.Clip>
</Image>
<Image
Grid.Row="0"
Margin="3"
Source="/Plain Craft Launcher 2;component/Images/Heads/LTCat.jpg">
<Image.Clip>
<EllipseGeometry
Center="17 17"
RadiusX="17"
RadiusY="17" />
</Image.Clip>
</Image>
<Image
x:Name="ImgPCLCommunity"
Grid.Row="1" MouseLeftButtonDown="ImgPCLCommunity_Click"
Margin="3"
Source="/Plain Craft Launcher 2;component/Images/Heads/PCL-Community.png" />
<local:MyButton
Grid.Row="0"
Grid.Column="2"
Height="35"
local:CustomEventService.EventData="https://ifdian.net/a/LTCat"
local:CustomEventService.EventType="OpenUrl"
Text="{DynamicResource Setup.About.SponsorOriginalAuthor}" />
<local:MyButton
Grid.Row="1"
Grid.Column="2"
Height="35"
local:CustomEventService.EventData="https://github.com/PCL-Community"
local:CustomEventService.EventType="OpenUrl"
Text="{DynamicResource Setup.About.GitHubHome}" />
<local:MyButton
Grid.Row="2"
Grid.Column="2"
Height="35"
local:CustomEventService.EventData="https://github.com/PCL-Community/PCL2-CE"
local:CustomEventService.EventType="OpenUrl"
Text="{DynamicResource Setup.About.SourceCode}" />
</Grid>
</local:MyCard>
<local:MyCard Margin="0,0,0,15" Title="{DynamicResource Setup.About.SpecialThanks.Title}">
<Grid Margin="21,40,21,16">
<Grid.RowDefinitions>
<RowDefinition Height="45" />
<RowDefinition x:Name="RowMcmod" Height="45" />
<RowDefinition Height="45" />
<RowDefinition Height="45" />
<RowDefinition Height="45" />
<RowDefinition Height="45" />
<RowDefinition Height="45" />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="40" />
<ColumnDefinition />
<ColumnDefinition Width="150" />
</Grid.ColumnDefinitions>
<local:MyListItem
Grid.Row="0"
Grid.Column="1"
Margin="-5,0,15,0"
Info="{DynamicResource Setup.About.SpecialThanks.Info.Bmclapi}"
IsHitTestVisible="False"
Title="{DynamicResource Setup.About.SpecialThanks.Name.Bangbang93}" />
<local:MyButton
Grid.Row="0"
Grid.Column="2"
Height="35"
local:CustomEventService.EventData="https://afdian.com/a/bangbang93"
local:CustomEventService.EventType="OpenUrl"
Text="{DynamicResource Setup.About.SpecialThanks.SponsorMirror}" />
<local:MyListItem
x:Name="ItemMcmod"
Grid.Row="1"
Grid.Column="1"
Grid.ColumnSpan="2"
Margin="-5,0,0,0"
Info="{DynamicResource Setup.About.SpecialThanks.Info.Mcmod}"
IsHitTestVisible="False"
Title="{DynamicResource Setup.About.SpecialThanks.Name.Mcmod}" />
<local:MyButton
x:Name="BtnMcmod"
Grid.Row="1"
Grid.Column="2"
Height="35"
local:CustomEventService.EventData="https://www.mcmod.cn"
local:CustomEventService.EventType="OpenUrl"
Text="{DynamicResource Setup.About.SpecialThanks.OpenMcmod}" />
<local:MyListItem
Grid.Row="2"
Grid.Column="1"
Grid.ColumnSpan="2"
Margin="-5,0,0,0"
Info="{DynamicResource Setup.About.SpecialThanks.Info.Cloud}"
IsHitTestVisible="False"
Title="{DynamicResource Setup.About.SpecialThanks.Name.Pysio}" />
<local:MyButton
Grid.Row="2"
Grid.Column="2"
Height="35"
local:CustomEventService.EventData="https://www.pysio.online"
local:CustomEventService.EventType="OpenUrl"
Text="{DynamicResource Setup.About.SpecialThanks.GoBlog}" />
<local:MyListItem
Grid.Row="3"
Grid.Column="1"
Grid.ColumnSpan="2"
Margin="-5,0,0,0"
Info="{DynamicResource Setup.About.SpecialThanks.Info.Cloud}"
IsHitTestVisible="False"
Title="{DynamicResource Setup.About.SpecialThanks.Name.Yunmoan}" />
<local:MyButton
Grid.Row="3"
Grid.Column="2"
Height="35"
local:CustomEventService.EventData="https://www.zyghit.cn"
local:CustomEventService.EventType="OpenUrl"
Text="{DynamicResource Setup.About.SpecialThanks.OpenWebsite}" />
<local:MyListItem
Grid.Row="4"
Grid.Column="1"
Grid.ColumnSpan="2"
Margin="-5,0,0,0"
Info="{DynamicResource Setup.About.SpecialThanks.Info.LinkModule}"
IsHitTestVisible="False"
Title="{DynamicResource Setup.About.SpecialThanks.Name.EasyTier}" />
<local:MyButton
Grid.Row="4"
Grid.Column="2"
Height="35"
local:CustomEventService.EventData="https://easytier.cn"
local:CustomEventService.EventType="OpenUrl"
Text="{DynamicResource Setup.About.SpecialThanks.OpenWebsite}" />
<local:MyListItem
Grid.Row="5"
Grid.Column="1"
Grid.ColumnSpan="2"
Margin="-5,0,0,0"
Info="{DynamicResource Setup.About.SpecialThanks.Info.Mcim}"
IsHitTestVisible="False"
Title="{DynamicResource Setup.About.SpecialThanks.Name.Z0z0r4}" />
<local:MyListItem
Grid.Row="6"
Grid.Column="1"
Grid.ColumnSpan="2"
Margin="-5,0,0,0"
Info="{DynamicResource Setup.About.SpecialThanks.Info.IconDesign}"
IsHitTestVisible="False"
Title="{DynamicResource Setup.About.SpecialThanks.Name.Emperormummy}" />
<Image
Grid.Row="0"
Margin="3"
Source="/Plain Craft Launcher 2;component/Images/Heads/bangbang93.png">
<Image.Clip>
<EllipseGeometry
Center="17 17"
RadiusX="17"
RadiusY="17" />
</Image.Clip>
</Image>
<Image
x:Name="ImgMcmod"
Grid.Row="1"
Margin="3"
Source="/Plain Craft Launcher 2;component/Images/Heads/wiki.png">
<Image.Clip>
<EllipseGeometry
Center="17 17"
RadiusX="17"
RadiusY="17" />
</Image.Clip>
</Image>
<Image
Grid.Row="2"
Margin="3"
Source="/Plain Craft Launcher 2;component/Images/Heads/Pysio.jpg">
<Image.Clip>
<EllipseGeometry
Center="17 17"
RadiusX="17"
RadiusY="17" />
</Image.Clip>
</Image>
<Image
Grid.Row="3"
Margin="3"
Source="/Plain Craft Launcher 2;component/Images/Heads/Yunmoan.jpg">
<Image.Clip>
<EllipseGeometry
Center="17 17"
RadiusX="17"
RadiusY="17" />
</Image.Clip>
</Image>
<Image
Grid.Row="4"
Margin="3"
Source="/Plain Craft Launcher 2;component/Images/Heads/EasyTier.png">
<Image.Clip>
<EllipseGeometry
Center="17 17"
RadiusX="17"
RadiusY="17" />
</Image.Clip>
</Image>
<Image
Grid.Row="5"
Margin="3"
Source="/Plain Craft Launcher 2;component/Images/Heads/z0z0r4.png">
<Image.Clip>
<EllipseGeometry
Center="17 17"
RadiusX="17"
RadiusY="17" />
</Image.Clip>
</Image>
<Image
Grid.Row="6"
Margin="3"
Source="/Plain Craft Launcher 2;component/Images/Heads/Emperormummy.png">
<Image.Clip>
<EllipseGeometry
Center="17 17"
RadiusX="17"
RadiusY="17" />
</Image.Clip>
</Image>
</Grid>
</local:MyCard>
<local:MyCard
Margin="0,0,0,15"
DataContext="{Binding RelativeSource={RelativeSource AncestorType=local:PageSetupAbout}}"
Title="{DynamicResource Setup.About.Contributors.Title}">
<Grid Margin="17,42,15,20">
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="5" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<ItemsControl ItemsSource="{Binding Contributors}">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<WrapPanel Orientation="Horizontal" />
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.ItemTemplate>
<DataTemplate>
<StackPanel
Width="72"
Margin="4,8"
HorizontalAlignment="Center"
Orientation="Vertical">
<local:MyImage
Width="36"
Height="36"
CornerRadius="18"
RenderOptions.BitmapScalingMode="HighQuality"
Source="{Binding AvatarUrl}" />
<local:MyTextButton
MaxWidth="90"
Margin="0,8,0,0"
HorizontalAlignment="Center"
FontSize="14"
local:CustomEventService.EventData="{Binding HtmlUrl}"
local:CustomEventService.EventType="OpenUrl"
Text="{Binding Login}"
ToolTip="{Binding Login}" />
</StackPanel>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
<local:MyTextButton
Grid.Row="2"
HorizontalAlignment="Center"
local:CustomEventService.EventData="https://github.com/PCL-Community/PCL2-CE/graphs/contributors"
local:CustomEventService.EventType="OpenUrl"
Text="{DynamicResource Setup.About.Contributors.ViewMore}" />
</Grid>
</local:MyCard>
<local:MyCard
Margin="0,0,0,15"
CanSwap="True"
Title="{DynamicResource Setup.About.Legal.Title}">
<StackPanel Margin="25,39,23,20">
<TextBlock
Margin="0,6,0,4"
FontWeight="Bold"
Text="{DynamicResource Setup.About.Legal.PrivacyNotice}"
TextWrapping="Wrap" />
<TextBlock
Margin="0,0,0,2"
LineHeight="17"
Text="{DynamicResource Setup.About.Legal.PrivacyText}"
TextWrapping="Wrap" />
<TextBlock
Margin="0,12,0,4"
FontWeight="Bold"
Text="{DynamicResource Setup.About.Legal.OtherInfo}"
TextWrapping="Wrap" />
<TextBlock
Margin="0,0,0,2"
LineHeight="17"
Text="{DynamicResource Setup.About.Legal.CopyrightText}"
TextWrapping="Wrap" />
<StackPanel
Height="35"
Margin="0,12,0,0"
HorizontalAlignment="Left"
Orientation="Horizontal">
<local:MyButton
Margin="0,0,20,0"
ColorType="Highlight"
local:CustomEventService.EventData="https://github.com/PCL-Community/PCL2-CE"
local:CustomEventService.EventType="OpenUrl"
Padding="13,0"
Text="{DynamicResource Setup.About.Legal.CommunitySource}" />
<local:MyButton
Margin="0,0,20,0"
local:CustomEventService.EventData="https://www.pclc.cc/privacy/personal-info-brief.html"
local:CustomEventService.EventType="OpenUrl"
Padding="13,0"
Text="{DynamicResource Setup.About.Legal.CommunityLobbyPrivacy}" />
<local:MyButton
Margin="0,0,20,0"
local:CustomEventService.EventData="https://account.naids.com/policy"
local:CustomEventService.EventType="OpenUrl"
Padding="13,0"
Text="{DynamicResource Setup.About.Legal.NatayarkTerms}" />
</StackPanel>
</StackPanel>
</local:MyCard>
<local:MyCard
Margin="0,0,0,15"
CanSwap="True"
IsSwapped="True"
Title="{DynamicResource Setup.About.UpstreamLegal.Title}">
<StackPanel Margin="25,39,23,20">
<TextBlock
Margin="0,6,0,4"
FontWeight="Bold"
Text="{DynamicResource Setup.About.Legal.PrivacyNotice}"
TextWrapping="Wrap" />
<TextBlock
Margin="0,0,0,2"
LineHeight="17"
Text="{DynamicResource Setup.About.UpstreamLegal.PrivacyText}"
TextWrapping="Wrap" />
<TextBlock
Margin="0,12,0,4"
FontWeight="Bold"
Text="{DynamicResource Setup.About.Legal.OtherInfo}"
TextWrapping="Wrap" />
<TextBlock
Margin="0,0,0,2"
LineHeight="17"
Text="{DynamicResource Setup.About.UpstreamLegal.CopyrightText}"
TextWrapping="Wrap" />
<StackPanel
Height="35"
Margin="0,12,0,0"
HorizontalAlignment="Left"
Orientation="Horizontal">
<local:MyButton
Width="160"
Margin="0,0,20,0"
ColorType="Highlight"
local:CustomEventService.EventData="https://shimo.im/docs/rGrd8pY8xWkt6ryW"
local:CustomEventService.EventType="OpenUrl"
Padding="13,0"
Text="{DynamicResource Setup.About.UpstreamLegal.TermsAndDisclaimer}" />
<local:MyButton
Width="120"
Margin="0,0,20,0"
local:CustomEventService.EventData="https://github.com/Meloong-Git/PCL"
local:CustomEventService.EventType="OpenUrl"
Padding="13,0"
Text="{DynamicResource Setup.About.UpstreamLegal.OpenSource}" />
</StackPanel>
</StackPanel>
</local:MyCard>
<local:MyCard
Margin="0,0,0,15"
CanSwap="True"
IsSwapped="True"
Title="{DynamicResource Setup.About.Licenses.Title}">
<ItemsControl Margin="25,42,23,4" ItemsSource="{Binding Licenses}">
<ItemsControl.ItemTemplate>
<DataTemplate>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" SharedSizeGroup="LicenseName" />
<ColumnDefinition Width="20" />
<ColumnDefinition Width="Auto" />
<ColumnDefinition />
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="60" />
</Grid.RowDefinitions>
<TextBlock
Grid.Row="0"
Grid.Column="0"
FontWeight="Bold"
Text="{Binding Name}"
TextWrapping="Wrap" />
<TextBlock
Grid.Row="0"
Grid.Column="2"
Grid.ColumnSpan="2"
Text="{Binding Information}"
TextWrapping="Wrap" />
<local:MyButton
Grid.Row="1"
Grid.Column="2"
MinWidth="140"
Margin="0,7,20,18"
HorizontalAlignment="Left"
local:CustomEventService.EventData="{Binding WebsiteUri}"
local:CustomEventService.EventType="OpenUrl"
Padding="13,0"
Text="{DynamicResource Setup.About.Licenses.ViewWebsite}"
Visibility="{Binding WebsiteUri, Converter={StaticResource NullToVisibilityConverter}}" />
<local:MyButton
Grid.Row="1"
Grid.Column="3"
MinWidth="140"
Margin="0,7,20,18"
HorizontalAlignment="Left"
local:CustomEventService.EventData="{Binding LicenseUri}"
local:CustomEventService.EventType="OpenUrl"
Padding="13,0"
Text="{DynamicResource Setup.About.Licenses.ViewLicense}"
Visibility="{Binding LicenseUri, Converter={StaticResource NullToVisibilityConverter}}" />
</Grid>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</local:MyCard>
</StackPanel>
</local:MyScrollViewer>
</local:MyPageRight>
@@ -0,0 +1,203 @@
using System.Collections.ObjectModel;
using System.Text.Json.Serialization;
using System.Windows;
using System.Windows.Input;
using PCL.Core.App.Localization;
using PCL.Core.IO.Net.Http;
using PCL.Core.Utils;
namespace PCL;
public partial class PageSetupAbout
{
// 彩蛋
private int clickCount;
private new bool isLoaded;
public PageSetupAbout()
{
InitializeComponent();
Loaded += PageOtherAbout_Loaded;
}
public ObservableCollection<GitHubContributor> Contributors { get; set; } = new();
private void PageOtherAbout_Loaded(object sender, RoutedEventArgs e)
{
// 重复加载部分
PanBack.ScrollToHome();
// 非重复加载部分
if (isLoaded)
return;
isLoaded = true;
ItemAboutPcl.Info = ItemAboutPcl.Info.Replace("%VERSION%", ModBase.versionBaseName)
.Replace("%VERSIONCODE%", ModBase.versionCode.ToString()).Replace("%BRANCH%", ModBase.versionBranchName)
.Replace("%COMMIT_HASH%", ModBase.commitHashShort);
if (!Lang.IsChineseMainland)
{
ItemMcmod.Visibility = Visibility.Collapsed;
BtnMcmod.Visibility = Visibility.Collapsed;
ImgMcmod.Visibility = Visibility.Collapsed;
RowMcmod.Height = new GridLength(0);
}
LoadContributersAsync();
}
private async void LoadContributersAsync()
{
try
{
using (var response = await HttpRequest
.Create("https://api.github.com/repos/PCL-Community/PCL2-CE/contributors").SendAsync())
{
response.EnsureSuccessStatusCode();
var cos = await response.AsJsonAsync<List<GitHubContributor>>(JsonCompat.SerializerOptions);
Contributors.Clear();
foreach (var item in cos)
Contributors.Add((GitHubContributor)item);
}
}
catch (Exception ex)
{
ModBase.Log(ex, Lang.Text("Setup.About.Error.LoadContributorsFailed"));
}
}
private void ImgPCLCommunity_Click(object sender, MouseButtonEventArgs e)
{
ModAnimation.AniStart(new[] { ModAnimation.AaRotateTransform(sender, 360d) });
}
private void ImgPCLLogo_Click(object sender, MouseButtonEventArgs e)
{
if (clickCount < 200)
{
clickCount += 1;
switch (clickCount)
{
case 5:
{
HintService.Hint(Lang.Text("Setup.About.EasterEgg.NiceClick"));
break;
}
case 15:
{
HintService.Hint(Lang.Text("Setup.About.EasterEgg.StillClicking"));
break;
}
case 25:
{
switch (ModMain.MyMsgBox(Lang.Text("Setup.About.EasterEgg.Bored.Message"), Lang.Text("Setup.About.EasterEgg.Bored.Title"), Lang.Text("Setup.About.EasterEgg.Bored.Yes"), Lang.Text("Setup.About.EasterEgg.Bored.No")))
{
case 2:
{
HintService.Hint(Lang.Text("Setup.About.EasterEgg.Bored.Response"));
break;
}
}
break;
}
case 50:
{
HintService.Hint(Lang.Text("Setup.About.EasterEgg.Encouragement"));
break;
}
case 75:
{
HintService.Hint(Lang.Text("Setup.About.EasterEgg.HiddenTheme"));
break;
}
case 100:
{
HintService.Hint(Lang.Text("Setup.About.EasterEgg.StillStaring"));
break;
}
case 130:
{
HintService.Hint(Lang.Text("Setup.About.EasterEgg.NothingBehind"));
break;
}
case 150:
{
switch (ModMain.MyMsgBox(Lang.Text("Setup.About.EasterEgg.Tired.Message1"), Lang.Text("Setup.About.EasterEgg.Tired.Title1"), Lang.Text("Setup.About.EasterEgg.Tired.Exhausted"), Lang.Text("Setup.About.EasterEgg.Tired.NotTired")))
{
case 1:
{
HintService.Hint(Lang.Text("Setup.About.EasterEgg.Tired.StopClicking"));
break;
}
case 2:
{
switch (ModMain.MyMsgBox(Lang.Text("Setup.About.EasterEgg.Tired.Message2"), Lang.Text("Setup.About.EasterEgg.Tired.Title2"), Lang.Text("Setup.About.EasterEgg.Tired.Exhausted"), Lang.Text("Setup.About.EasterEgg.Tired.NotTired")))
{
case 1:
{
HintService.Hint(Lang.Text("Setup.About.EasterEgg.Tired.StopClicking"));
break;
}
case 2:
{
switch (ModMain.MyMsgBox(Lang.Text("Setup.About.EasterEgg.Tired.Message3"), Lang.Text("Setup.About.EasterEgg.Tired.Title3"), Lang.Text("Setup.About.EasterEgg.Tired.Exhausted"), Lang.Text("Setup.About.EasterEgg.Tired.ReallyNotTired")))
{
case 1:
{
HintService.Hint(Lang.Text("Setup.About.EasterEgg.Tired.StopClicking"));
break;
}
case 2:
{
HintService.Hint(Lang.Text("Setup.About.EasterEgg.Tired.FinallyGiveUp"));
break;
}
}
break;
}
}
break;
}
}
break;
}
case 200:
{
HintService.Hint(Lang.Text("Setup.About.EasterEgg.ClickDisabled"));
ImgPCLLogo.IsHitTestVisible = false;
return;
}
}
var rand = new Random();
var mx = rand.Next(-1, 1);
if (mx == 0)
mx = 1;
var my = rand.Next(-1, 1);
if (my == 0)
my = 1;
ModAnimation.AniStart(new[]
{
ModAnimation.AaTranslateX(sender, mx, 0), ModAnimation.AaTranslateY(sender, my, 0),
ModAnimation.AaTranslateX(sender, -mx, 0, 100), ModAnimation.AaTranslateY(sender, -my, 0, 100)
});
}
}
public class GitHubContributor
{
[JsonPropertyName("login")] public string Login { get; set; }
[JsonPropertyName("avatar_url")] public string AvatarUrl { get; set; }
[JsonPropertyName("html_url")] public string HtmlUrl { get; set; }
[JsonPropertyName("contributions")] public int Contributions { get; set; }
}
}
@@ -0,0 +1,63 @@
<local:MyPageRight x:Class="PCL.PageSetupFeedback"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:PCL"
PanScroll="{Binding ElementName=PanBack}">
<local:MyScrollViewer VerticalScrollBarVisibility="Auto" HorizontalScrollBarVisibility="Disabled" x:Name="PanBack">
<StackPanel x:Name="PanMain" Margin="25,25,25,25">
<local:MyCard Title="{DynamicResource Setup.Feedback.Submit.Title}" x:Name="PanInfo">
<StackPanel Orientation="Vertical" Margin="20,40,18,22">
<TextBlock
Text="{DynamicResource Setup.Feedback.Submit.Description}"
TextWrapping="Wrap" />
<Grid Margin="0,15,0,0" Height="35">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" SharedSizeGroup="Button" />
<ColumnDefinition Width="Auto" SharedSizeGroup="Button" />
<ColumnDefinition Width="Auto" SharedSizeGroup="Button" />
<ColumnDefinition Width="Auto" SharedSizeGroup="Button" />
</Grid.ColumnDefinitions>
<local:MyButton x:Name="BtnManageOpen" Grid.Column="0" MinWidth="140" Text="{DynamicResource Setup.Feedback.Submit.Open}"
Padding="13,0" Margin="0,0,20,0" HorizontalAlignment="Left"
ColorType="Highlight" Click="Feedback_Click" />
</Grid>
</StackPanel>
</local:MyCard>
<StackPanel x:Name="PanContent" Margin="0,15,0,0">
<local:MyCard Title="{DynamicResource Setup.Feedback.Status.Processing}" Margin="0,0,0,15" x:Name="PanContentProcessing" CanSwap="True">
<StackPanel x:Name="PanListProcessing" Orientation="Vertical" Margin="20,36,18,18" />
</local:MyCard>
<local:MyCard Title="{DynamicResource Setup.Feedback.Status.WaitingProcess}" Margin="0,0,0,15" x:Name="PanContentWaitingProcess" CanSwap="True">
<StackPanel x:Name="PanListWaitingProcess" Orientation="Vertical" Margin="20,36,18,18" />
</local:MyCard>
<local:MyCard Title="{DynamicResource Setup.Feedback.Status.Waiting}" Margin="0,0,0,15" x:Name="PanContentWait" CanSwap="True">
<StackPanel x:Name="PanListWait" Orientation="Vertical" Margin="20,36,18,18" />
</local:MyCard>
<local:MyCard Title="{DynamicResource Setup.Feedback.Status.Paused}" Margin="0,0,0,15" x:Name="PanContentPause" CanSwap="True">
<StackPanel x:Name="PanListPause" Orientation="Vertical" Margin="20,36,18,18" />
</local:MyCard>
<local:MyCard Title="{DynamicResource Setup.Feedback.Status.UpNext}" Margin="0,0,0,15" x:Name="PanContentUpnext" CanSwap="True">
<StackPanel x:Name="PanListUpnext" Orientation="Vertical" Margin="20,36,18,18" />
</local:MyCard>
<local:MyCard Title="{DynamicResource Setup.Feedback.Status.Completed}" Margin="0,0,0,15" x:Name="PanContentCompleted" CanSwap="True"
IsSwapped="True">
<StackPanel x:Name="PanListCompleted" Orientation="Vertical" Margin="20,36,18,18" />
</local:MyCard>
<local:MyCard Title="{DynamicResource Setup.Feedback.Status.Declined}" Margin="0,0,0,15" x:Name="PanContentDecline" CanSwap="True" IsSwapped="True">
<StackPanel x:Name="PanListDecline" Orientation="Vertical" Margin="20,36,18,18" />
</local:MyCard>
<local:MyCard Title="{DynamicResource Setup.Feedback.Status.Ignored}" Margin="0,0,0,15" x:Name="PanContentIgnored" CanSwap="True" IsSwapped="True">
<StackPanel x:Name="PanListIgnored" Orientation="Vertical" Margin="20,36,18,18" />
</local:MyCard>
<local:MyCard Title="{DynamicResource Setup.Feedback.Status.Duplicate}" Margin="0,0,0,15" x:Name="PanContentDuplicate" CanSwap="True" IsSwapped="True">
<StackPanel x:Name="PanListDuplicate" Orientation="Vertical" Margin="20,36,18,18" />
</local:MyCard>
</StackPanel>
<local:MyCard HorizontalAlignment="Center" VerticalAlignment="Center" SnapsToDevicePixels="True"
x:Name="PanLoad" UseAnimation="False" Margin="40,50">
<local:MyLoading Text="{DynamicResource Setup.Feedback.Loading}" Margin="20,20,20,17" x:Name="Load" HorizontalAlignment="Center"
VerticalAlignment="Center" />
</local:MyCard>
</StackPanel>
</local:MyScrollViewer>
</local:MyPageRight>
@@ -0,0 +1,196 @@
using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;
using System.Text.Json.Serialization;
using PCL.Network;
using PCL.Core.App.Localization;
namespace PCL;
public partial class PageSetupFeedback
{
public enum TagId : long
{
Processing = 6820804544L,
WaitingProcess = 6820804546L,
Completed = 6820804547L,
Decline = 6820804539L,
Ignored = 8064650117L,
Duplicate = 6820804541L,
Wait = 8743070786L,
Pause = 8558220235L,
Upnext = 8550609020L
}
private bool _isLoaded;
public ModLoader.LoaderTask<bool, List<Feedback>> Loader;
private static readonly Dictionary<string, (Func<PageSetupFeedback, StackPanel> Panel, string Icon)> TagMap = new()
{
[((long)TagId.Processing).ToString()] = (p => p.PanListProcessing, "Blocks/CommandBlock.png"),
[((long)TagId.WaitingProcess).ToString()] = (p => p.PanListWaitingProcess, "Blocks/RedstoneBlock.png"),
[((long)TagId.Wait).ToString()] = (p => p.PanListWait, "Blocks/Anvil.png"),
[((long)TagId.Pause).ToString()] = (p => p.PanListPause, "Blocks/RedstoneLampOff.png"),
[((long)TagId.Upnext).ToString()] = (p => p.PanListUpnext, "Blocks/RedstoneLampOn.png"),
[((long)TagId.Completed).ToString()] = (p => p.PanListCompleted, "Blocks/Grass.png"),
[((long)TagId.Decline).ToString()] = (p => p.PanListDecline, "Blocks/CobbleStone.png"),
[((long)TagId.Ignored).ToString()] = (p => p.PanListIgnored, "Blocks/CobbleStone.png"),
[((long)TagId.Duplicate).ToString()] = (p => p.PanListDuplicate, "Blocks/CobbleStone.png"),
};
public PageSetupFeedback()
{
InitializeComponent();
Loader = new ModLoader.LoaderTask<bool, List<Feedback>>("FeedbackList", FeedbackListGet);
Loaded += PageOtherFeedback_Loaded;
}
private void PageOtherFeedback_Loaded(object sender, RoutedEventArgs e)
{
PageLoaderInit(Load, PanLoad, PanContent, PanInfo, Loader, _ => RefreshList());
// 重复加载部分
PanBack.ScrollToHome();
// 非重复加载部分
if (_isLoaded)
return;
_isLoaded = true;
}
public void FeedbackListGet(ModLoader.LoaderTask<bool, List<Feedback>> task)
{
var list = Requester.FetchJson(
"https://api.github.com/repos/PCL-Community/PCL2-CE/issues?state=all&sort=created&per_page=200",
new RequestParam
{
Retries = 3,
UseBrowserUserAgent = true
}) as JsonArray; // 获取近期 200 条数据就够了
if (list is null)
throw new Exception(Lang.Text("Setup.Feedback.LoadFailed"));
var res = new List<Feedback>();
foreach (var i in list)
{
if (i is not JsonObject issue) continue;
var pullRequestToken = issue["pull_request"];
if (pullRequestToken is not null && pullRequestToken.GetValueKind() != JsonValueKind.Null) continue;
var item = issue.Deserialize<Feedback>()!;
item.User = issue["user"]!["login"]!.ToString();
item.Id = issue["number"]!.ToString();
var issueType = Lang.Text("Setup.Feedback.Uncategorized");
var typeToken = issue["type"];
if (typeToken is not null && typeToken.GetValueKind() == JsonValueKind.Object)
{
var typeNameToken = typeToken["name"];
if (typeNameToken is not null) issueType = typeNameToken.ToString().ToLower();
}
item.Type = issueType;
if (issue["labels"] is JsonArray thisTags)
foreach (var thisTag in thisTags)
if (thisTag is JsonObject tagObj)
item.Tags.Add(tagObj["id"]!.ToString());
res.Add(item);
}
task.output = res;
}
private MyListItem CreateFeedbackItem(Feedback item, string logo)
{
var li = new MyListItem
{
Title = item.Title,
Type = MyListItem.CheckType.Clickable,
Info = $"{item.User} | {Lang.Date(item.Time)}",
Logo = ModBase.pathImage + logo,
Tags = item.Type
};
li.Click += (_, _) => ShowFeedbackDetail(item);
return li;
}
private void ShowFeedbackDetail(Feedback item)
{
var timeSpanText = Lang.TimeSpan(item.Time - DateTime.Now);
switch (ModMain.MyMsgBoxMarkdown(
Lang.Text("Setup.Feedback.Item.Submitter", item.User, timeSpanText) + "\n" +
Lang.Text("Setup.Feedback.Item.Type", item.Type) + "\n\n" +
item.Content,
$"#{item.Id} {item.Title}", button2: Lang.Text("Setup.Feedback.Item.ViewDetail")))
{
case 2:
{
ModBase.OpenWebsite(item.Url);
break;
}
}
}
private void SetPanelVisibility(StackPanel panel, MyCard card)
{
card.Visibility = panel.Children.Count == 0 ? Visibility.Collapsed : Visibility.Visible;
}
public void RefreshList()
{
PanListProcessing.Children.Clear();
PanListWaitingProcess.Children.Clear();
PanListWait.Children.Clear();
PanListPause.Children.Clear();
PanListUpnext.Children.Clear();
PanListCompleted.Children.Clear();
PanListDecline.Children.Clear();
PanListIgnored.Children.Clear();
PanListDuplicate.Children.Clear();
foreach (var item in Loader.output)
{
var tag = item.Tags.Find(TagMap.ContainsKey);
if (tag is not null)
{
var (panel, icon) = TagMap[tag];
panel(this).Children.Add(CreateFeedbackItem(item, icon));
}
}
SetPanelVisibility(PanListProcessing, PanContentProcessing);
SetPanelVisibility(PanListWaitingProcess, PanContentWaitingProcess);
SetPanelVisibility(PanListWait, PanContentWait);
SetPanelVisibility(PanListPause, PanContentPause);
SetPanelVisibility(PanListUpnext, PanContentUpnext);
SetPanelVisibility(PanListCompleted, PanContentCompleted);
SetPanelVisibility(PanListDecline, PanContentDecline);
SetPanelVisibility(PanListIgnored, PanContentIgnored);
SetPanelVisibility(PanListDuplicate, PanContentDuplicate);
}
private void Feedback_Click(object sender, MouseButtonEventArgs e)
{
PageSetupLeft.TryFeedback();
}
public class Feedback
{
[JsonIgnore]
public string User { get; set; } = string.Empty;
[JsonPropertyName("title")]
public string Title { get; init; } = string.Empty;
[JsonPropertyName("created_at")]
public DateTime Time { get; init; }
[JsonPropertyName("body")]
public string Content { get; init; } = string.Empty;
[JsonPropertyName("html_url")]
public string Url { get; init; } = string.Empty;
[JsonIgnore]
public string Id { get; set; } = string.Empty;
public List<string> Tags { get; } = new();
public string Type { get; set; } = string.Empty;
}
}
@@ -0,0 +1,119 @@
<local:MyPageRight
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:PCL" xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d" x:Class="PCL.PageSetupGameLink"
PanScroll="{Binding ElementName=PanBack}">
<local:MyScrollViewer VerticalScrollBarVisibility="Auto" HorizontalScrollBarVisibility="Disabled" x:Name="PanBack">
<StackPanel x:Name="PanMain" Margin="25,10">
<local:MyCard Margin="0,15" Title="EasyTier">
<StackPanel Margin="25,40,25,15" Orientation="Vertical">
<local:MyHint Text="{DynamicResource Setup.GameLink.RestartRequired}" Theme="Yellow" Margin="0,0,0,10" />
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" SharedSizeGroup="TextBlock" />
<ColumnDefinition Width="8" />
<ColumnDefinition Width="1*" />
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="28" />
<RowDefinition Height="8" />
<!--<RowDefinition Height="28" />
<RowDefinition Height="8" />
<RowDefinition Height="Auto" MinHeight="28"/>
<RowDefinition Height="8" />
<RowDefinition Height="28" />
<RowDefinition Height="8" />
<RowDefinition Height="28" />
<RowDefinition Height="8" />-->
<RowDefinition Height="28" />
<RowDefinition Height="4" />
<RowDefinition Height="28" />
<RowDefinition Height="28" />
<RowDefinition Height="28" />
<RowDefinition Height="28" />
<!--<RowDefinition Height="4" />
<RowDefinition Height="35" />-->
</Grid.RowDefinitions>
<TextBlock Grid.Row="0" VerticalAlignment="Center" HorizontalAlignment="Left" Text="{DynamicResource Setup.GameLink.Username}"
Margin="0,0,25,0" />
<local:MyTextBox x:Name="TextLinkUsername" Grid.Row="0" Grid.ColumnSpan="2" Tag="LinkUsername"
Grid.Column="2" TextChanged="TextBoxChange"
ToolTip="{DynamicResource Setup.GameLink.Username.ToolTip}" />
<!--<TextBlock Grid.Row="2" VerticalAlignment="Center" HorizontalAlignment="Left" Text="自定义节点" Margin="0,0,25,0" />
<local:MyTextBox x:Name="TextLinkRelay" Grid.Row="2" Grid.ColumnSpan="2" Tag="LinkRelayServer" Grid.Column="2" HintText="一般应以 tcp:// 或 udp:// 开头;若有多个,请使用英文分号分割">
<local:MyTextBox.ValidateRules>
<local:ValidateNullable />
<local:ValidateNullOrWhiteSpace />
</local:MyTextBox.ValidateRules>
</local:MyTextBox>
<TextBlock Grid.Row="4" VerticalAlignment="Center" HorizontalAlignment="Left" Text="预设节点"/>
<TextBlock x:Name="TextRelays" Grid.Row="4" Grid.Column="2" Grid.ColumnSpan="2" VerticalAlignment="Center" HorizontalAlignment="Left" Text="正在获取..." TextWrapping="WrapWithOverflow"/>
<TextBlock Grid.Row="6" VerticalAlignment="Center" HorizontalAlignment="Left" Text="中继行为"/>
<local:MyComboBox x:Name="ComboRelayType" Tag="LinkRelayType" Grid.Row="6" Grid.Column="2">
<local:MyComboBoxItem Content="自动决定(推荐)" ToolTip="让 EasyTier 自行决定连接方式,适用于绝大多数用户。&#xa;EasyTier 将会尽可能建立 P2P 连接,仅在 P2P 连接未能建立时使用中继。"/>
<local:MyComboBoxItem Content="仅中继" ToolTip="数据将仅通过中继节点进行转发,仅推荐在完全无法连接或极端卡顿的情况下尝试。"/>
</local:MyComboBox>
<TextBlock Grid.Row="8" VerticalAlignment="Center" HorizontalAlignment="Left" Text="节点行为"/>
<local:MyComboBox x:Name="ComboServerType" Tag="LinkServerType" Grid.Row="8" Grid.Column="2">
<local:MyComboBoxItem Content="仅自有节点协助中继" ToolTip="仅通过 PCL CE 自有节点通信。&#xa;自有节点由 PCL CE 官方部署,一般情况下此选项已经足够使用。"/>
<local:MyComboBoxItem Content="自有节点 + 社区节点 协助中继" ToolTip="除自有节点外,添加由 PCL CE 挑选的部分 EasyTier 社区提供的节点。&#xa;这些节点由社区志愿者部署,可能可以提供更快的连接速度。"/>
<local:MyComboBoxItem Content="不使用预设节点中继 (谨慎选择)" ToolTip="不使用任何预设节点中继数据。&#xa;联机双方将需要添加至少一个相同的自定义节点才可以连接。&#xa;这要求你具备一定技术能力且有特殊需要,在绝大多数情况下不要选择此选项!"/>
</local:MyComboBox>-->
<TextBlock Grid.Row="2" VerticalAlignment="Center" HorizontalAlignment="Left" Text="{DynamicResource Setup.GameLink.Protocol.Preference}" />
<local:MyComboBox x:Name="ComboPreferProtocol" Tag="LinkProtocolPreference" Grid.Row="2"
SelectionChanged="LinkProtocolPerferenceChange"
Grid.Column="2">
<local:MyComboBoxItem Content="{DynamicResource Setup.GameLink.Protocol.Tcp}" ToolTip="{DynamicResource Setup.GameLink.Protocol.Tcp.ToolTip}" />
<local:MyComboBoxItem Content="{DynamicResource Setup.GameLink.Protocol.Udp}" ToolTip="{DynamicResource Setup.GameLink.Protocol.Udp.ToolTip}" />
</local:MyComboBox>
<local:MyCheckBox x:Name="CheckLatencyFirstMode" Tag="LinkLatencyFirstMode" Grid.Row="4"
Grid.ColumnSpan="3" Text="{DynamicResource Setup.GameLink.LatencyFirstMode}" Change="CheckBoxChange"
ToolTip="{DynamicResource Setup.GameLink.LatencyFirstMode.ToolTip}" />
<local:MyCheckBox x:Name="CheckTryPunchSym" Tag="LinkTryPunchSym" Grid.Row="5"
Grid.ColumnSpan="3" Text="{DynamicResource Setup.GameLink.PortGuessNat}" Change="CheckBoxChange"
ToolTip="{DynamicResource Setup.GameLink.PortGuessNat.ToolTip}" />
<local:MyCheckBox x:Name="CheckEnableIPv6" Tag="LinkEnableIPv6" Grid.Row="6"
Grid.ColumnSpan="3" Text="{DynamicResource Setup.GameLink.EnableIPv6}" Change="CheckBoxChange"
ToolTip="{DynamicResource Setup.GameLink.EnableIPv6.ToolTip}" />
<local:MyCheckBox x:Name="CheckEnableCliOutput" Tag="LinkEnableCliOutput" Grid.Row="7"
Grid.ColumnSpan="3" Text="{DynamicResource Setup.GameLink.CliDebugOutput}" Change="CheckBoxChange"
ToolTip="{DynamicResource Setup.GameLink.CliDebugOutput.ToolTip}" />
<!--<local:MyButton Grid.Row="17" HorizontalAlignment="Left" Grid.ColumnSpan="3" Width="120" Text="社区节点列表" EventType="打开网页" EventData="https://uptime.easytier.cn/" ColorType="Highlight" ToolTip="查看 EasyTier 社区提供的节点。&#xa;你也可以在此页面提交自己的节点,以帮助整个社区优化连接。"/>-->
</Grid>
</StackPanel>
</local:MyCard>
<local:MyCard Margin="10" Title="{DynamicResource Setup.GameLink.NetworkTest.Title}" Visibility="Collapsed">
<StackPanel Margin="25,40,25,15" Orientation="Vertical">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="8" />
<ColumnDefinition Width="1*" />
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="8" />
<RowDefinition Height="30" />
</Grid.RowDefinitions>
<TextBlock x:Name="TextUdpNatType"
Text="{DynamicResource Setup.GameLink.NetworkTest.UdpNatType.NotTested}"
Grid.Row="0" />
<TextBlock x:Name="TextTcpNatType"
Text="{DynamicResource Setup.GameLink.NetworkTest.TcpNatType.NotTested}"
Grid.Row="1" />
<TextBlock x:Name="TextIpv6Status"
Text="{DynamicResource Setup.GameLink.NetworkTest.Ipv6Status.NotTested}"
Grid.Row="2" />
<local:MyButton x:Name="BtnNetTest" Text="{DynamicResource Setup.GameLink.NetworkTest.Start}" Grid.Row="4" ColorType="Highlight"
Click="BtnNetTest_Click"
VerticalAlignment="Stretch" HorizontalAlignment="Stretch" />
</Grid>
</StackPanel>
</local:MyCard>
</StackPanel>
</local:MyScrollViewer>
</local:MyPageRight>
@@ -0,0 +1,176 @@
using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;
using PCL.Core.App;
using PCL.Core.App.Configuration;
using PCL.Core.App.Localization;
using PCL.Core.Link.Scaffolding.EasyTier;
namespace PCL;
public partial class PageSetupGameLink
{
private bool isFirstLoad = true;
private new bool isLoaded;
public PageSetupGameLink()
{
InitializeComponent();
TextUdpNatType.Text = Lang.Text("Setup.GameLink.NetworkTest.UdpNatType", Lang.Text("Setup.GameLink.NetworkTest.NotTested"));
TextTcpNatType.Text = Lang.Text("Setup.GameLink.NetworkTest.TcpNatType", Lang.Text("Setup.GameLink.NetworkTest.NotTested"));
TextIpv6Status.Text = Lang.Text("Setup.GameLink.NetworkTest.Ipv6Status", Lang.Text("Setup.GameLink.NetworkTest.NotTested"));
Loaded += PageSetupLink_Loaded;
Loaded += (_, _) => Reload();
}
private void PageSetupLink_Loaded(object sender, RoutedEventArgs e)
{
// 重复加载部分
PanBack.ScrollToHome();
// 非重复加载部分
if (isLoaded)
return;
isLoaded = true;
ModAnimation.AniControlEnabled += 1;
Reload();
ModAnimation.AniControlEnabled -= 1;
}
public void Reload()
{
TextLinkUsername.Text = Config.Link.Username;
// TextLinkRelay.Text = Config.Link.RelayServer
// ComboRelayType.SelectedIndex = Config.Link.RelayType
// ComboServerType.SelectedIndex = Config.Link.ServerType
CheckLatencyFirstMode.Checked = Config.Link.UseLatencyFirstMode;
ComboPreferProtocol.SelectedIndex = (int)Config.Link.ProtocolPreference;
CheckTryPunchSym.Checked = Config.Link.TryPunchSym;
CheckEnableIPv6.Checked = Config.Link.EnableIPv6;
CheckEnableCliOutput.Checked = Config.Link.EnableCliOutput;
// TextRelays.Text = "正在获取信息..."
// Do While Not (PageLinkLobby.LobbyAnnouncementLoader.State = LoadState.Finished OrElse PageLinkLobby.LobbyAnnouncementLoader.State = LoadState.Failed)
// Thread.Sleep(500)
// Loop
// If ETRelay.RelayList.Count > 0 Then
// TextRelays.Text = ""
// For Each Relay In ETRelay.RelayList
// Select Case Relay.Type
// Case ETRelayType.Community
// TextRelays.Text += "[社区] "
// Case ETRelayType.Selfhosted
// TextRelays.Text += "[自有] "
// Case Else 'ETRelayType.Custom
// TextRelays.Text += "[自定义] "
// End Select
// TextRelays.Text += Relay.Name & ""
// Next
// TextRelays.Text = TextRelays.Text.BeforeLast("")
// Else
// TextRelays.Text = "暂无,你可能需要手动添加中继服务器"
// End If
}
// 初始化
public void Reset()
{
try
{
Config.Link.Reset();
ModBase.Log("[Setup] 已初始化联机页设置");
HintService.Hint(Lang.Text("Setup.GameLink.Initialized"), HintType.Success, false);
Reload();
}
catch (Exception ex)
{
ModBase.Log(
ex,
Lang.Text("Setup.GameLink.Error.InitFailed"),
ModBase.LogLevel.Msgbox,
userSummary: Lang.Text("Setup.GameLink.Error.InitFailed"));
}
Reload();
}
// 将控件改变路由到设置改变
private void TextBoxChange(object senderRaw, TextChangedEventArgs e)
{
var sender = (MyTextBox)senderRaw;
if (ModAnimation.AniControlEnabled == 0)
SetByTag(sender.Tag?.ToString(), sender.Text);
}
private static void ComboBoxChange(MyComboBox sender, object e)
{
if (ModAnimation.AniControlEnabled == 0)
SetByTag(sender.Tag?.ToString(), sender.SelectedIndex);
}
private void CheckBoxChange(object senderRaw, bool user)
{
var sender = (MyCheckBox)senderRaw;
if (ModAnimation.AniControlEnabled == 0)
SetByTag(sender.Tag?.ToString(), sender.Checked);
}
private static void SetByTag(string tag, object value)
=> ConfigService.TrySetValue(tag, value);
private void LinkProtocolPerferenceChange(object sender, SelectionChangedEventArgs e)
{
if (ModAnimation.AniControlEnabled == 0)
try
{
var selection = (LinkProtocolPreference)((MyComboBox)sender).SelectedIndex;
Config.Link.ProtocolPreference = selection;
}
catch (Exception ex)
{
ModBase.Log(
ex,
Lang.Text("Setup.GameLink.Error.ConfigChangeFailed"),
ModBase.LogLevel.Hint,
userSummary: Lang.Text("Setup.GameLink.Error.ConfigChangeFailed"));
}
}
// 网络测试
private void BtnNetTest_Click(object sender, MouseButtonEventArgs e)
{
try
{
BtnNetTest.IsEnabled = false;
BtnNetTest.Text = Lang.Text("Setup.GameLink.NetworkTest.Testing");
ModBase.RunInNewThread(() =>
{
var status = CliNetTest.GetNetStatusAsync().GetAwaiter().GetResult();
ModBase.RunInUi(() =>
{
TextUdpNatType.Text =
Lang.Text("Setup.GameLink.NetworkTest.UdpNatType", CliNetTest.GetNatTypeString(status.UdpNatType));
TextTcpNatType.Text =
Lang.Text("Setup.GameLink.NetworkTest.TcpNatType", CliNetTest.GetNatTypeString(status.TcpNatType));
TextIpv6Status.Text = Lang.Text("Setup.GameLink.NetworkTest.Ipv6Status",
status.SupportIPv6
? Lang.Text("Setup.GameLink.NetworkTest.Supported")
: Lang.Text("Setup.GameLink.NetworkTest.Unsupported"));
BtnNetTest.IsEnabled = true;
BtnNetTest.Text = Lang.Text("Setup.GameLink.NetworkTest.Start");
});
});
}
catch (Exception ex)
{
ModBase.Log(ex,
"[Link] 获取网络测试结果失败",
ModBase.LogLevel.Hint,
userSummary: Lang.Text("Setup.GameLink.Error.NetworkTestFailed"));
BtnNetTest.IsEnabled = true;
BtnNetTest.Text = Lang.Text("Setup.GameLink.NetworkTest.Start");
}
}
}
@@ -0,0 +1,181 @@
<local:MyPageRight
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:PCL" xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d" x:Class="PCL.PageSetupGameManage"
PanScroll="{Binding ElementName=PanBack}">
<local:MyScrollViewer VerticalScrollBarVisibility="Auto" HorizontalScrollBarVisibility="Disabled" x:Name="PanBack">
<StackPanel x:Name="PanMain" Margin="25,10">
<local:MyCard Margin="0,15" Title="{DynamicResource Setup.GameManage.Source.Title}">
<StackPanel Margin="25,37,25,15">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" SharedSizeGroup="Name" />
<ColumnDefinition />
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="28" />
<RowDefinition Height="7" />
<RowDefinition Height="28" />
<RowDefinition Height="7" />
<RowDefinition Height="27" />
<RowDefinition Height="27" />
<RowDefinition Height="Auto" />
<RowDefinition Height="27" />
</Grid.RowDefinitions>
<TextBlock VerticalAlignment="Center" HorizontalAlignment="Left" Text="{DynamicResource Setup.GameManage.Source.File}" Margin="0,0,25,0" />
<local:MyComboBox x:Name="ComboDownloadSource" Grid.ColumnSpan="2" Tag="ToolDownloadSource"
Grid.Column="1" SelectionChanged="ComboChange">
<local:MyComboBoxItem Content="{DynamicResource Setup.GameManage.Source.UseMirror}" />
<local:MyComboBoxItem Content="{DynamicResource Setup.GameManage.Source.PreferOfficialThenMirror}" IsSelected="True" />
<local:MyComboBoxItem Content="{DynamicResource Setup.GameManage.Source.UseOfficial}" />
</local:MyComboBox>
<TextBlock VerticalAlignment="Center" HorizontalAlignment="Left" Text="{DynamicResource Setup.GameManage.Source.Version}" Margin="0,0,25,0"
Grid.Row="2" />
<local:MyComboBox x:Name="ComboDownloadVersion" Grid.ColumnSpan="2" Tag="ToolDownloadVersion"
Grid.Column="1" Grid.Row="2" SelectionChanged="ComboChange">
<local:MyComboBoxItem Content="{DynamicResource Setup.GameManage.Source.Version.Mirror}" />
<local:MyComboBoxItem Content="{DynamicResource Setup.GameManage.Source.PreferOfficialThenMirror}" IsSelected="True" />
<local:MyComboBoxItem Content="{DynamicResource Setup.GameManage.Source.UseOfficial}" />
</local:MyComboBox>
<TextBlock Grid.Row="4" VerticalAlignment="Center" HorizontalAlignment="Left" Text="{DynamicResource Setup.GameManage.Download.Threads}"
Margin="0,0,25,0" />
<local:MySlider x:Name="SliderDownloadThread" Grid.Row="4" Tag="ToolDownloadThread"
PreviewChange="SliderDownloadThread_PreviewChange"
MaxValue="255" Value="63" Grid.Column="1" Change="SliderChange"
ToolTip="{DynamicResource Setup.GameManage.Download.Threads.ToolTip}" />
<TextBlock VerticalAlignment="Center" Grid.Row="5" HorizontalAlignment="Left" Text="{DynamicResource Setup.GameManage.Download.SpeedLimit}"
Margin="0,0,25,0" />
<local:MySlider x:Name="SliderDownloadSpeed" Grid.Row="5" Tag="ToolDownloadSpeed" MaxValue="42"
Value="42" Grid.Column="1" Change="SliderChange"
ToolTip="{DynamicResource Setup.GameManage.Download.SpeedLimit.ToolTip}" />
<TextBlock VerticalAlignment="Top" Grid.Row="6" HorizontalAlignment="Left" Text="{DynamicResource Setup.GameManage.Download.TargetFolder}"
Margin="0,5,25,5" />
<TextBlock Margin="0,5" HorizontalAlignment="Left"
Text="{DynamicResource Setup.GameManage.Download.TargetFolder.Hint}" Grid.Row="6"
Grid.Column="1" VerticalAlignment="Center" Opacity="0.5" />
<TextBlock Margin="0,5" Grid.Row="7" Text="{DynamicResource Setup.GameManage.Download.InstallBehavior}" />
<Grid Grid.Row="7" Grid.Column="1">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<local:MyCheckBox Grid.Row="0" Grid.Column="0" Text="{DynamicResource Setup.GameManage.Download.AutoSelectInstance}"
x:Name="CheckDownloadAutoSelectVersion"
Tag="ToolDownloadAutoSelectVersion" Change="CheckBoxChange" />
<local:MyCheckBox Grid.Row="0" Grid.Column="1" Margin="0,0,0,0" Text="{DynamicResource Setup.GameManage.Download.FixAuthlib}"
x:Name="CheckFixAuthlib" Tag="ToolFixAuthlib" Change="CheckBoxChange"
ToolTip="{DynamicResource Setup.GameManage.Download.FixAuthlib.ToolTip}" />
</Grid>
</Grid>
</StackPanel>
</local:MyCard>
<local:MyCard Margin="0,0,0,15" Title="{DynamicResource Setup.GameManage.Community.Title}">
<StackPanel Margin="25,37,25,12">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" SharedSizeGroup="Name" />
<ColumnDefinition />
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="28" />
<RowDefinition Height="7" />
<RowDefinition Height="28" x:Name="RowFilenameFormat" />
<RowDefinition Height="7" x:Name="RowFilenameFormatGap" />
<RowDefinition Height="28" x:Name="RowModManageStyle" />
<RowDefinition Height="7" x:Name="RowModManageStyleGap" />
<RowDefinition Height="28" x:Name="RowQuickDownload" />
<RowDefinition Height="7" x:Name="RowQuickDownloadGap" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<TextBlock Grid.Row="0" VerticalAlignment="Center" HorizontalAlignment="Left" Text="{DynamicResource Setup.GameManage.Community.Source}"
Margin="0,0,25,0" />
<local:MyComboBox x:Name="ComboDownloadMod" Grid.Row="0" Grid.ColumnSpan="2"
Tag="ToolDownloadMod" Grid.Column="1" SelectionChanged="ComboChange">
<local:MyComboBoxItem Content="{DynamicResource Setup.GameManage.Source.UseMirror}" />
<local:MyComboBoxItem Content="{DynamicResource Setup.GameManage.Community.Source.PreferOfficialWithFallback}" IsSelected="True" />
<local:MyComboBoxItem Content="{DynamicResource Setup.GameManage.Source.UseOfficial}" />
</local:MyComboBox>
<TextBlock Grid.Row="2" x:Name="TextFilenameFormat" VerticalAlignment="Center" HorizontalAlignment="Left" Text="{DynamicResource Setup.GameManage.Community.FilenameFormat}"
Margin="0,0,25,0" />
<local:MyComboBox Grid.Row="2" x:Name="ComboDownloadTranslateV2" Grid.ColumnSpan="2"
Tag="ToolDownloadTranslateV2" Grid.Column="1" SelectionChanged="ComboChange"
ToolTip="{DynamicResource Setup.GameManage.Community.FilenameFormat.ToolTip}">
<local:MyComboBoxItem Content="{DynamicResource Setup.GameManage.Community.FilenameFormat.Style0}" />
<local:MyComboBoxItem Content="{DynamicResource Setup.GameManage.Community.FilenameFormat.Style1}" IsSelected="True" />
<local:MyComboBoxItem Content="{DynamicResource Setup.GameManage.Community.FilenameFormat.Style2}" />
<local:MyComboBoxItem Content="{DynamicResource Setup.GameManage.Community.FilenameFormat.Style3}" />
<local:MyComboBoxItem Content="{DynamicResource Setup.GameManage.Community.FilenameFormat.Style4}" />
</local:MyComboBox>
<TextBlock Grid.Row="4" x:Name="TextModManageStyle" VerticalAlignment="Center" HorizontalAlignment="Left" Text="{DynamicResource Setup.GameManage.Community.ModManageStyle}"
Margin="0,0,25,0" />
<local:MyComboBox Grid.Row="4" x:Name="ComboModLocalNameStyle" Grid.ColumnSpan="2"
Tag="ToolModLocalNameStyle" Grid.Column="1" SelectionChanged="ComboChange"
ToolTip="{DynamicResource Setup.GameManage.Community.ModManageStyle.ToolTip}">
<local:MyComboBoxItem Content="{DynamicResource Setup.GameManage.Community.ModManageStyle.TitleTranslation}" IsSelected="True" />
<local:MyComboBoxItem Content="{DynamicResource Setup.GameManage.Community.ModManageStyle.TitleFilename}" />
</local:MyComboBox>
<TextBlock Grid.Row="6" VerticalAlignment="Center" HorizontalAlignment="Left" Text="{DynamicResource Setup.GameManage.Community.QuickDownload}"
Margin="0,0,25,0" />
<local:MyComboBox Grid.Row="6" x:Name="ComboDownloadQuickBehavior" Grid.ColumnSpan="2"
Tag="ToolDownloadQuickBehavior" Grid.Column="1" SelectionChanged="ComboChange"
ToolTip="{DynamicResource Setup.GameManage.Community.QuickDownload.ToolTip}">
<local:MyComboBoxItem Content="{DynamicResource Setup.GameManage.Community.QuickDownload.AlwaysAsk}" IsSelected="True" />
<local:MyComboBoxItem Content="{DynamicResource Setup.GameManage.Community.QuickDownload.CurrentInstance}" />
<local:MyComboBoxItem Content="{DynamicResource Setup.GameManage.Community.QuickDownload.AskInstance}" />
<local:MyComboBoxItem Content="{DynamicResource Setup.GameManage.Community.QuickDownload.AskPath}" />
</local:MyComboBox>
</Grid>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<local:MyCheckBox Margin="0,2,0,4" Text="{DynamicResource Setup.GameManage.Community.HideQuilt}" ToolTip="{DynamicResource Setup.GameManage.Community.HideQuilt.ToolTip}"
Grid.Row="0" Height="22" Grid.Column="0" Change="CheckBoxChange"
x:Name="CheckDownloadIgnoreQuilt" Tag="ToolDownloadIgnoreQuilt" />
<local:MyCheckBox Margin="0,2,0,4" Text="{DynamicResource Setup.GameManage.Community.AutoInstallDependencies}" ToolTip="{DynamicResource Setup.GameManage.Community.AutoInstallDependencies.ToolTip}"
Grid.Row="1" Height="22" Grid.Column="0" Change="CheckBoxChange"
x:Name="CheckDownloadAutoInstallDependencies" Tag="ToolDownloadAutoInstallDependencies" />
</Grid>
</StackPanel>
</local:MyCard>
<local:MyCard Margin="0,0,0,15" Title="{DynamicResource Setup.GameManage.Accessibility.Title}">
<Grid Margin="25,40,25,17">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="160" />
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="22" />
<RowDefinition Height="8" />
<RowDefinition Height="22" />
<RowDefinition Height="8" />
<RowDefinition Height="22" />
<RowDefinition Height="8" />
</Grid.RowDefinitions>
<TextBlock VerticalAlignment="Center" HorizontalAlignment="Left" Text="{DynamicResource Setup.GameManage.Accessibility.GameUpdateNotice}" Margin="0,0,25,0" />
<local:MyCheckBox Text="{DynamicResource Setup.GameManage.Accessibility.ReleaseNotice}" Grid.Column="1" x:Name="CheckUpdateRelease"
Change="CheckBoxChange"
Tag="ToolUpdateRelease" ToolTip="{DynamicResource Setup.GameManage.Accessibility.ReleaseNotice.ToolTip}" />
<local:MyCheckBox Text="{DynamicResource Setup.GameManage.Accessibility.SnapshotNotice}" Grid.Column="2" Height="22" x:Name="CheckUpdateSnapshot"
Change="CheckBoxChange"
Tag="ToolUpdateSnapshot" ToolTip="{DynamicResource Setup.GameManage.Accessibility.SnapshotNotice.ToolTip}" />
<TextBlock VerticalAlignment="Center" Grid.Row="2" HorizontalAlignment="Left" Text="{DynamicResource Setup.GameManage.Accessibility.GameLanguage}"
Margin="0,0,25,0" />
<local:MyCheckBox Text="{DynamicResource Setup.GameManage.Accessibility.AutoLauncherLanguage}" Grid.Row="2" Grid.Column="1" Grid.ColumnSpan="5"
x:Name="CheckHelpLauncherLanguage" Tag="ToolHelpChinese" Change="CheckBoxChange" />
<local:MyCheckBox Text="{DynamicResource Setup.GameManage.Accessibility.ReadClipboard}" Height="22" Grid.Row="4" Grid.Column="0"
Grid.ColumnSpan="3" Change="CheckBoxChange"
x:Name="CheckDownloadClipboard" Tag="ToolDownloadClipboard"
ToolTip="{DynamicResource Setup.GameManage.Accessibility.ReadClipboard.ToolTip}" />
</Grid>
</local:MyCard>
</StackPanel>
</local:MyScrollViewer>
</local:MyPageRight>
@@ -0,0 +1,158 @@
using System.Windows;
using System.Windows.Controls;
using PCL.Core.App;
using PCL.Core.App.Configuration;
using PCL.Core.App.Localization;
using PCL.Core.Utils;
namespace PCL;
public partial class PageSetupGameManage
{
private new bool isLoaded;
public PageSetupGameManage()
{
InitializeComponent();
Loaded += PageSetupSystem_Loaded;
}
private void PageSetupSystem_Loaded(object sender, RoutedEventArgs e)
{
// 重复加载部分
PanBack.ScrollToHome();
// 非重复加载部分
if (isLoaded)
return;
isLoaded = true;
ModAnimation.AniControlEnabled += 1;
Reload();
SliderLoad();
if (!Lang.IsChineseMainland)
{
TextFilenameFormat.Visibility = Visibility.Collapsed;
ComboDownloadTranslateV2.Visibility = Visibility.Collapsed;
TextModManageStyle.Visibility = Visibility.Collapsed;
ComboModLocalNameStyle.Visibility = Visibility.Collapsed;
RowFilenameFormat.Height = new GridLength(0);
RowFilenameFormatGap.Height = new GridLength(0);
RowModManageStyle.Height = new GridLength(0);
RowModManageStyleGap.Height = new GridLength(0);
}
ModAnimation.AniControlEnabled -= 1;
}
public void Reload()
{
// 下载
SliderDownloadThread.Value = Config.Download.ThreadLimit;
SliderDownloadSpeed.Value = Config.Download.SpeedLimit;
ComboDownloadSource.SelectedIndex = Config.Download.FileSource;
ComboDownloadVersion.SelectedIndex = Config.Download.VersionListSource;
CheckDownloadAutoSelectVersion.Checked = Config.Download.AutoSelectInstance;
CheckFixAuthlib.Checked = Config.Download.FixAuthLib;
// Mod 与整合包
ComboDownloadTranslateV2.SelectedIndex = Config.Download.Comp.NameFormatV2;
ComboDownloadMod.SelectedIndex = Config.Download.Comp.CompSourceSolution;
ComboModLocalNameStyle.SelectedIndex = Config.Download.Comp.UiCompNameSolution;
ComboDownloadQuickBehavior.SelectedIndex = Config.Download.Comp.QuickDownloadBehavior;
CheckDownloadIgnoreQuilt.Checked = Config.Download.Comp.IgnoreQuilt;
CheckDownloadAutoInstallDependencies.Checked = Config.Download.Comp.AutoInstallDependencies;
CheckDownloadClipboard.Checked = Config.Download.Comp.ReadClipboard;
// Minecraft 更新提示
CheckUpdateRelease.Checked = Config.Tool.ReleaseNotification;
CheckUpdateSnapshot.Checked = Config.Tool.SnapshotNotification;
// 辅助设置
CheckHelpLauncherLanguage.Checked = Config.Tool.AutoChangeLanguage;
}
// 初始化
public void Reset()
{
try
{
Config.Download.Reset();
Config.Tool.Reset();
ModBase.Log("[Setup] 已初始化其他页设置");
HintService.Hint(Lang.Text("Setup.GameManage.Initialized"), HintType.Success, false);
}
catch (Exception ex)
{
ModBase.Log(
ex,
Lang.Text("Setup.GameManage.Error.InitFailed"),
ModBase.LogLevel.Msgbox,
userSummary: Lang.Text("Setup.GameManage.Error.InitFailed"));
}
Reload();
}
// 将控件改变路由到设置改变
private void CheckBoxChange(object senderRaw, bool user)
{
var sender = (MyCheckBox)senderRaw;
if (ModAnimation.AniControlEnabled == 0)
SetByTag(sender.Tag?.ToString(), sender.Checked);
}
private void SliderChange(object senderRaw, bool user)
{
var sender = (MySlider)senderRaw;
if (ModAnimation.AniControlEnabled == 0)
SetByTag(sender.Tag?.ToString(), sender.Value);
}
private void ComboChange(object senderRaw, SelectionChangedEventArgs e)
{
var sender = (MyComboBox)senderRaw;
if (ModAnimation.AniControlEnabled == 0)
SetByTag(sender.Tag?.ToString(), sender.SelectedIndex);
}
private static void SetByTag(string tag, object value)
=> ConfigService.TrySetValue(tag, value);
// 滑动条
private void SliderLoad()
{
SliderDownloadThread.getHintText = new Func<object, object>(v => (int)v + 1);
SliderDownloadSpeed.getHintText = new Func<object, object>(v =>
{
int value = (int)v;
switch (value)
{
case <= 14:
return Lang.Number((value + 1) * 0.1d, "N1") + " MiB/s";
case <= 31:
return Lang.Number((value - 11) * 0.5d, "N1") + " MiB/s";
case <= 41:
return Lang.Number(value - 21, "N0") + " MiB/s";
default:
return Lang.Text("Setup.GameManage.Download.Unlimited");
}
});
}
private void SliderDownloadThread_PreviewChange(object sender, ModBase.RouteEventArgs e)
{
if (SliderDownloadThread.Value < 100)
return;
if (!States.Hint.LargeDownloadThread)
{
States.Hint.LargeDownloadThread = true;
ModMain.MyMsgBox(
Lang.Text("Setup.GameManage.Download.Threads.TooManyWarning.Message"),
Lang.Text("Common.Dialog.Warning"),
Lang.Text("Setup.GameManage.Download.Threads.TooManyWarning.Confirm"), isWarn: true);
}
}
}
@@ -0,0 +1,26 @@
<local:MyPageRight
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:PCL" xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d" x:Class="PCL.PageSetupJava"
PanScroll="{Binding ElementName=PanBack}">
<local:MyScrollViewer VerticalScrollBarVisibility="Auto" HorizontalScrollBarVisibility="Disabled" x:Name="PanBack">
<Grid>
<StackPanel x:Name="PanMain" Margin="25,25,25,10">
<local:MyCard Margin="0,0,0,15">
<StackPanel Margin="8" Orientation="Horizontal">
<local:MyIconTextButton x:Name="BtnAdd" Text="{DynamicResource Setup.Java.Add}" LogoScale="0.9" Click="BtnAdd_Click"
SvgIcon="lucide/circle-plus" />
</StackPanel>
</local:MyCard>
<local:MyCard Margin="0,0,0,15">
<StackPanel Margin="15" Orientation="Vertical" x:Name="PanContent" />
</local:MyCard>
</StackPanel>
<local:MyCard x:Name="CardLoad" HorizontalAlignment="Center" VerticalAlignment="Center">
<local:MyLoading Text="{DynamicResource Setup.Java.Loading}" x:Name="PanLoad" Margin="12" />
</local:MyCard>
</Grid>
</local:MyScrollViewer>
</local:MyPageRight>
@@ -0,0 +1,220 @@
using System.IO;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Media;
using PCL.Core.App;
using PCL.Core.Minecraft;
using PCL.Core.UI;
using PCL.Core.App.Localization;
namespace PCL;
public partial class PageSetupJava
{
private bool isLoad = false;
public ModLoader.LoaderTask<bool, List<JavaEntry>> loader;
public PageSetupJava()
{
InitializeComponent();
loader = new ModLoader.LoaderTask<bool, List<JavaEntry>>("JavaPageLoader", Load_GetJavaList);
Loaded += PageSetupLaunch_Loaded;
}
private void PageSetupLaunch_Loaded(object sender, RoutedEventArgs e)
{
PageLoaderInit(PanLoad, CardLoad, PanMain, null, loader, _ => OnLoadFinished(), Load_Input);
}
private object Load_Input()
{
return false;
}
private void Load_GetJavaList(ModLoader.LoaderTask<bool, List<JavaEntry>> loader)
{
if (loader.input) JavaService.JavaManager.ScanJavaAsync().GetAwaiter().GetResult();
loader.output = ModJava.Javas.GetSortedJavaList();
}
private void OnLoadFinished()
{
PanContent.Children.Clear();
var itemAuto = new MyListItem
{
Type = MyListItem.CheckType.RadioBox,
Title = Lang.Text("Setup.Java.AutoSelect.Title"),
Info = Lang.Text("Setup.Java.AutoSelect.Info")
};
itemAuto.Check += (sender, e) => Config.Launch.SelectedJava = "";
PanContent.Children.Add(itemAuto);
var currentSetJava = Config.Launch.SelectedJava;
foreach (var entry in ModJava.Javas.GetSortedJavaList())
{
var item = ItemBuild(entry);
PanContent.Children.Add(item);
if (entry.Installation.JavaExePath == currentSetJava)
item.SetChecked(true, false, false);
}
if (string.IsNullOrEmpty(currentSetJava))
itemAuto.SetChecked(true, false, false);
}
private MyListItem ItemBuild(JavaEntry j)
{
var item = new MyListItem();
var versionTypeDesc = j.Installation.IsJre ? "JRE" : "JDK";
var versionNameDesc = j.Installation.MajorVersion.ToString();
item.Title = $"{versionTypeDesc} {versionNameDesc}";
item.Info = j.Installation.JavaFolder;
var displayTags = new List<string>();
var displayBits = j.Installation.Is64Bit ? "64 Bit" : "32 Bit";
displayTags.Add(displayBits);
var displayBrand = j.Installation.Brand.ToString();
displayTags.Add(displayBrand);
item.Tags = displayTags;
item.Type = MyListItem.CheckType.RadioBox;
item.Check += (sender, e) =>
{
if (!j.Installation.IsStillAvailable)
{
HintService.Hint(Lang.Text("Setup.Java.Unavailable"));
return;
}
if (j.IsEnabled)
Config.Launch.SelectedJava = j.Installation.JavaExePath;
else
{
HintService.Hint(Lang.Text("Setup.Java.EnableBeforeSelect"));
e.handled = true;
}
};
var btnOpenFolder = new MyIconButton();
btnOpenFolder.SvgIcon = "lucide/folder-open";
btnOpenFolder.ToolTip = Lang.Text("Common.Action.Open");
btnOpenFolder.Click += (sender, e) =>
{
if (!j.Installation.IsStillAvailable)
{
HintService.Hint(Lang.Text("Setup.Java.Unavailable"));
return;
}
ModBase.OpenExplorer(j.Installation.JavaFolder);
};
var btnInfo = new MyIconButton();
btnInfo.SvgIcon = "lucide/info";
btnInfo.ToolTip = Lang.Text("Setup.Java.Detail.ToolTip");
btnInfo.Click += (sender, e) =>
{
if (!j.Installation.IsStillAvailable)
{
HintService.Hint(Lang.Text("Setup.Java.Unavailable"));
return;
}
ModMain.MyMsgBox(
Lang.Text("Setup.Java.Info.Format",
versionTypeDesc,
j.Installation.Version.ToString(),
j.Installation.Architecture.ToString(),
displayBits,
displayBrand,
j.Installation.JavaFolder),
Lang.Text("Setup.Java.Info.Title"));
};
var btnEnableSwitch = new MyIconButton();
item.Buttons = [btnOpenFolder, btnInfo, btnEnableSwitch];
void UpdateEnableStyle(bool isCurEnable)
{
if (!j.Installation.IsStillAvailable)
{
HintService.Hint(Lang.Text("Setup.Java.Unavailable"));
return;
}
if (isCurEnable)
{
item.LabTitle.TextDecorations = null;
item.LabTitle.SetResourceReference(TextBlock.ForegroundProperty, "ColorBrush1");
btnEnableSwitch.SvgIcon = "lucide/circle-minus";
btnEnableSwitch.ToolTip = Lang.Text("Setup.Java.Disable");
}
else
{
item.LabTitle.TextDecorations = TextDecorations.Strikethrough;
item.LabTitle.SetResourceReference(TextBlock.ForegroundProperty, "ColorBrushGray4");
btnEnableSwitch.SvgIcon = "lucide/circle-check";
btnEnableSwitch.ToolTip = Lang.Text("Setup.Java.Enable");
}
}
btnEnableSwitch.Click += (_, _) =>
{
try
{
var target = ModJava.Javas.AddOrGet(j.Installation.JavaExePath);
if (target is null)
{
HintService.Hint(Lang.Text("Setup.Java.Unavailable"));
return;
}
if (target.IsEnabled && Config.Launch.SelectedJava == target.Installation.JavaExePath)
{
HintService.Hint(Lang.Text("Setup.Java.DeselectBeforeDisable"));
return;
}
target.IsEnabled = !target.IsEnabled;
UpdateEnableStyle(target.IsEnabled);
ModJava.Javas.SaveConfig();
}
catch (Exception ex)
{
ModBase.Log(
ex,
Lang.Text("Setup.Java.EnableFailed"),
ModBase.LogLevel.Hint,
userSummary: Lang.Text("Setup.Java.EnableFailed"));
}
};
UpdateEnableStyle(j.IsEnabled);
return item;
}
private void BtnAdd_Click(object sender, ModBase.RouteEventArgs e)
{
var ret = SystemDialogs.SelectFile(Lang.Text("Setup.Java.SelectFile.Filter"), Lang.Text("Setup.Java.SelectFile.Title"));
if (string.IsNullOrEmpty(ret) || !File.Exists(ret))
return;
if (ModJava.Javas.Exist(ret))
HintService.Hint(Lang.Text("Setup.Java.AlreadyExists"));
else
Dispatcher.BeginInvoke(new Action(async () =>
{
await Task.Run(() =>
{
ModJava.Javas.AddOrGet(ret);
ModJava.Javas.SaveConfig();
});
if (ModJava.Javas.Exist(ret))
{
HintService.Hint(Lang.Text("Setup.Java.Added"), HintType.Success);
loader.Start(true, true);
}
else
{
HintService.Hint(Lang.Text("Setup.Java.AddFailed"), HintType.Error);
}
}));
}
}
@@ -0,0 +1,319 @@
<local:MyPageRight
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:PCL"
xmlns:val="https://ce.pclc.cc/core/utils/validate"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:System="clr-namespace:System;assembly=mscorlib"
mc:Ignorable="d" x:Class="PCL.PageSetupLaunch"
PanScroll="{Binding ElementName=PanBack, Mode=OneWay}">
<local:MyScrollViewer VerticalScrollBarVisibility="Auto" HorizontalScrollBarVisibility="Disabled" x:Name="PanBack">
<StackPanel x:Name="PanMain" Margin="25,25,25,10">
<local:MyCard x:Name="CardArgument" Margin="0,0,0,15" Title="{DynamicResource Setup.Launch.Options.Title}">
<StackPanel Margin="25,40,25,15">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" SharedSizeGroup="Name" />
<ColumnDefinition Width="1*" />
<ColumnDefinition Width="60" />
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="28" />
<RowDefinition Height="9" />
<RowDefinition Height="28" />
<RowDefinition Height="9" />
<RowDefinition Height="28" />
<RowDefinition Height="9" />
<RowDefinition Height="28" />
<RowDefinition Height="9" />
<RowDefinition Height="28" />
<RowDefinition Height="9" />
<RowDefinition Height="28" />
<RowDefinition Height="9" />
<RowDefinition Height="28" />
<RowDefinition Height="9" />
<RowDefinition Height="28" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<TextBlock Grid.Row="0" VerticalAlignment="Center" HorizontalAlignment="Left" Text="{DynamicResource Setup.Launch.Options.InstanceIsolation.Label}"
Margin="0,0,25,0" />
<local:MyComboBox x:Name="ComboArgumentIndieV2" Grid.Row="0" Grid.ColumnSpan="2"
Tag="LaunchArgumentIndieV2" Grid.Column="1"
SelectionChanged="ComboArgumentIndie_OnSelectionChanged"
ToolTip="{DynamicResource Setup.Launch.Options.InstanceIsolation.ToolTip}">
<local:MyComboBoxItem Content="{DynamicResource Common.Action.Close}"
ToolTip="{DynamicResource Setup.Launch.Options.InstanceIsolation.None.ToolTip}" />
<local:MyComboBoxItem Content="{DynamicResource Setup.Launch.Options.InstanceIsolation.ModdedOnly}" IsSelected="True"
ToolTip="{DynamicResource Setup.Launch.Options.InstanceIsolation.ModdedOnly.ToolTip}" />
<local:MyComboBoxItem Content="{DynamicResource Setup.Launch.Options.InstanceIsolation.NonRelease}" ToolTip="{DynamicResource Setup.Launch.Options.InstanceIsolation.NonRelease.ToolTip}" />
<local:MyComboBoxItem Content="{DynamicResource Setup.Launch.Options.InstanceIsolation.ModdedAndNonRelease}" />
<local:MyComboBoxItem Content="{DynamicResource Setup.Launch.Options.InstanceIsolation.All}"
ToolTip="{DynamicResource Setup.Launch.Options.InstanceIsolation.All.ToolTip}" />
</local:MyComboBox>
<TextBlock Grid.Row="2" VerticalAlignment="Center" HorizontalAlignment="Left" Text="{DynamicResource Setup.Launch.Options.WindowTitle.Label}"
Margin="0,0,25,0" />
<local:MyComboBox x:Name="TextArgumentTitle" Grid.Row="2" Grid.ColumnSpan="2"
Tag="LaunchArgumentTitle" Grid.Column="1" IsEditable="True"
IsTextSearchEnabled="False" TextChanged="TextArgumentTitle_OnTextChanged"
ToolTip="{DynamicResource Setup.Launch.Options.WindowTitle.ToolTip}"
HintText="{DynamicResource Common.Option.Default}">
<local:MyComboBoxItem Content="{DynamicResource Setup.Launch.Options.WindowTitle.SampleFormat}" />
</local:MyComboBox>
<TextBlock Grid.Row="4" VerticalAlignment="Center" HorizontalAlignment="Left" Text="{DynamicResource Setup.Launch.Options.CustomInfo.Label}"
Margin="0,0,25,0" />
<local:MyTextBox x:Name="TextArgumentInfo" Grid.Row="4" Grid.ColumnSpan="2"
Tag="LaunchArgumentInfo" Text="PCL" Grid.Column="1"
ValidatedTextChanged="TextBoxChange"
ToolTip="{DynamicResource Setup.Launch.Options.CustomInfo.ToolTip}">
<local:MyTextBox.ValidateRules>
<val:BlacklistValidator>
<val:BlacklistValidator.Blacklist>
<System:String>"</System:String>
<System:String>“</System:String>
<System:String>”</System:String>
</val:BlacklistValidator.Blacklist>
</val:BlacklistValidator>
</local:MyTextBox.ValidateRules>
</local:MyTextBox>
<TextBlock VerticalAlignment="Center" Grid.Row="6" HorizontalAlignment="Left" Text="{DynamicResource Setup.Launch.Options.Visibility.Label}"
Margin="0,0,25,0" />
<local:MyComboBox x:Name="ComboArgumentVisibie" Grid.Row="6" Grid.ColumnSpan="2"
Tag="LaunchArgumentVisible" Grid.Column="1"
SelectionChanged="ComboArgumentVisibie_SelectionChanged">
<local:MyComboBoxItem Content="{DynamicResource Setup.Launch.Options.Visibility.CloseImmediately}" />
<local:MyComboBoxItem Content="" IsEnabled="False" Visibility="Collapsed" />
<local:MyComboBoxItem Content="{DynamicResource Setup.Launch.Options.Visibility.HideAndCloseOnExit}" />
<local:MyComboBoxItem Content="{DynamicResource Setup.Launch.Options.Visibility.HideAndReopenOnExit}" />
<local:MyComboBoxItem Content="{DynamicResource Setup.Launch.Options.Visibility.Minimize}" />
<local:MyComboBoxItem Content="{DynamicResource Setup.Launch.Options.Visibility.KeepUnchanged}" IsSelected="True" />
</local:MyComboBox>
<TextBlock VerticalAlignment="Center" Grid.Row="8" HorizontalAlignment="Left" Text="{DynamicResource Setup.Launch.Options.Priority.Label}"
Margin="0,0,25,0" />
<local:MyComboBox x:Name="ComboArgumentPriority" Grid.Row="8" Grid.ColumnSpan="2"
Tag="LaunchArgumentPriority" Grid.Column="1"
SelectionChanged="ComboChange"
SelectedValuePath="Tag">
<local:MyComboBoxItem Content="{DynamicResource Setup.Launch.Options.Priority.RealTime}" Tag="4" />
<local:MyComboBoxItem Content="{DynamicResource Setup.Launch.Options.Priority.High}" Tag="3" />
<local:MyComboBoxItem Content="{DynamicResource Setup.Launch.Options.Priority.AboveNormal}" Tag="0" />
<local:MyComboBoxItem Content="{DynamicResource Setup.Launch.Options.Priority.Normal}" IsSelected="True" Tag="1" />
<local:MyComboBoxItem Content="{DynamicResource Setup.Launch.Options.Priority.BelowNormal}" Tag="2" />
</local:MyComboBox>
<TextBlock VerticalAlignment="Center" Grid.Row="10" HorizontalAlignment="Left" Text="{DynamicResource Setup.Launch.Options.WindowSize.Label}"
Margin="0,0,25,0" />
<Grid x:Name="PanArgumentWindow" Grid.Row="10" Grid.ColumnSpan="2" Grid.Column="1">
<Grid.ColumnDefinitions>
<ColumnDefinition />
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>
<local:MyComboBox x:Name="ComboArgumentWindowType" Tag="LaunchArgumentWindowType"
SelectionChanged="ComboChange"
ToolTip="{DynamicResource Setup.Launch.Options.WindowSize.ModernUiWarning}">
<local:MyComboBoxItem Content="{DynamicResource Setup.Launch.Options.WindowSize.Fullscreen}" />
<local:MyComboBoxItem Content="{DynamicResource Common.Option.Default}" IsSelected="True" />
<local:MyComboBoxItem Content="{DynamicResource Setup.Launch.Options.WindowSize.SameAsLauncher}" />
<local:MyComboBoxItem Content="{DynamicResource Setup.Launch.Options.WindowSize.Custom}" ToolTip="{DynamicResource Setup.Launch.Options.WindowSize.CustomHeightBug.ToolTip}" />
<local:MyComboBoxItem Content="{DynamicResource Setup.Launch.Options.WindowSize.Maximized}" />
</local:MyComboBox>
<local:MyTextBox Padding="0,0,5,0" Visibility="Collapsed" Grid.Column="1" Margin="50,0,0,0"
x:Name="TextArgumentWindowWidth" Tag="LaunchArgumentWindowWidth"
Width="60" HorizontalContentAlignment="Center" Text="854"
ValidatedTextChanged="TextBoxChange">
<local:MyTextBox.ValidateRules>
<val:IntValidator Min="1" Max="9999" />
</local:MyTextBox.ValidateRules>
</local:MyTextBox>
<TextBlock x:Name="LabArgumentWindowMiddle" Visibility="Collapsed" Grid.Column="2"
Text=" × " VerticalAlignment="Center" FontSize="18" />
<local:MyTextBox Padding="0,0,5,0" Visibility="Collapsed" Grid.Column="3" Width="60"
HorizontalContentAlignment="Center" x:Name="TextArgumentWindowHeight"
Tag="LaunchArgumentWindowHeight" Text="480"
ValidatedTextChanged="TextBoxChange"
ToolTip="{DynamicResource Setup.Launch.Options.WindowSize.CustomHeightBug.ToolTip}"
ToolTipService.Placement="Right" ToolTipService.HorizontalOffset="5">
<local:MyTextBox.ValidateRules>
<val:IntValidator Min="1" Max="9999" />
</local:MyTextBox.ValidateRules>
</local:MyTextBox>
</Grid>
<TextBlock VerticalAlignment="Center" Grid.Row="12" HorizontalAlignment="Left" Text="{DynamicResource Setup.Launch.Options.MsAuth.Label}"
Margin="0,0,25,0"
ToolTip="{DynamicResource Setup.Launch.Options.MsAuth.ToolTip}" />
<local:MyComboBox x:Name="ComboMsAuthType" Grid.Row="12" Grid.ColumnSpan="2"
Tag="LoginMsAuthType" Grid.Column="1"
SelectionChanged="ComboChange"
ToolTip="{DynamicResource Setup.Launch.Options.MsAuth.ToolTip}"
IsEnabled="False">
<local:MyComboBoxItem Content="{DynamicResource Setup.Launch.Options.MsAuth.WebManager}" IsSelected="True" />
<local:MyComboBoxItem Content="{DynamicResource Setup.Launch.Options.MsAuth.DeviceCode}" />
</local:MyComboBox>
<TextBlock VerticalAlignment="Center" Grid.Row="14" HorizontalAlignment="Left" Text="{DynamicResource Setup.Launch.Options.IpStack.Label}"
Margin="0,0,25,0" />
<local:MyComboBox x:Name="ComboPreferredIpStack" Grid.Row="14" Grid.ColumnSpan="2"
Tag="LaunchPreferredIpStack" Grid.Column="1"
SelectionChanged="ComboChange"
ToolTip="{DynamicResource Setup.Launch.Options.IpStack.ToolTip}">
<local:MyComboBoxItem Content="{DynamicResource Setup.Launch.Options.IpStack.Ipv4}" IsSelected="True" />
<local:MyComboBoxItem Content="{DynamicResource Setup.Launch.Options.IpStack.JavaDefault}" />
<local:MyComboBoxItem Content="{DynamicResource Setup.Launch.Options.IpStack.Ipv6}" />
</local:MyComboBox>
</Grid>
</StackPanel>
</local:MyCard>
<local:MyCard Margin="0,0,0,15" Title="{DynamicResource Setup.Launch.Memory.Title}">
<StackPanel Margin="25,40,25,15">
<local:MyHint x:Name="LabRamWarn" Visibility="Visible"
Text="{DynamicResource Setup.Launch.Memory.Warning.Java32Bit}" Theme="Yellow" Margin="0,0,0,12" />
<local:MyHint x:Name="HintRamTooHigh" Visibility="Collapsed" Height="30" Theme="Yellow"
Text="{DynamicResource Setup.Launch.Memory.Warning.TooMuch}" Margin="0,0,0,12"
HorizontalAlignment="Stretch" VerticalAlignment="Stretch" />
<Grid Margin="0,0,0,3">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" />
<ColumnDefinition />
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="9" />
<RowDefinition Height="Auto" />
<RowDefinition Height="9" />
</Grid.RowDefinitions>
<local:MyRadioBox Text="{DynamicResource Setup.Launch.Memory.Auto}" Width="110" Checked="True" x:Name="RadioRamType0"
Tag="LaunchRamType/0" Margin="0,0,20,0" Check="RadioBoxChange"
ToolTip="{DynamicResource Setup.Launch.Memory.Auto.ToolTip}" ToolTipService.Placement="Right"
ToolTipService.HorizontalOffset="-10" ToolTipService.VerticalOffset="-3" />
<local:MyRadioBox Grid.Row="2" Text="{DynamicResource Common.Option.Customize}" x:Name="RadioRamType1" Tag="LaunchRamType/1"
Margin="0,0,20,0" Check="RadioBoxChange" />
<local:MySlider Grid.Row="2" Grid.Column="1" IsEnabled="False" x:Name="SliderRamCustom"
Tag="LaunchRamCustom" MaxValue="49" Value="13" Change="SliderChange" />
</Grid>
<Grid x:Name="PanRamDisplay" Margin="0,11,2,0" SnapsToDevicePixels="True">
<Grid.ColumnDefinitions>
<ColumnDefinition x:Name="ColumnRamUsed" Width="4.7*" />
<ColumnDefinition x:Name="ColumnRamGame" Width="2.5*" />
<ColumnDefinition x:Name="ColumnRamEmpty" Width="0.7*" />
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition />
<RowDefinition Height="4" />
<RowDefinition />
</Grid.RowDefinitions>
<Rectangle x:Name="RectRamUsed" Grid.Row="1" StrokeThickness="0">
<Rectangle.Fill>
<LinearGradientBrush EndPoint="1,0.5" StartPoint="0,0.5">
<GradientStop Color="{DynamicResource ColorObject3}" Offset="0" />
<GradientStop Color="{DynamicResource ColorObject2}" Offset="0.5" />
</LinearGradientBrush>
</Rectangle.Fill>
</Rectangle>
<Rectangle Grid.Row="1" StrokeThickness="0" Grid.Column="1"
Fill="{DynamicResource ColorBrush3}" Opacity="0.5" x:Name="RectRamGame" />
<Rectangle x:Name="RectRamEmpty" Grid.Row="1" StrokeThickness="0" Grid.Column="2"
Fill="{DynamicResource ColorBrush6}" Opacity="0.7" />
<TextBlock x:Name="LabRamUsedTitle" Text="{DynamicResource Setup.Launch.Memory.UsedTotal}" Grid.ColumnSpan="3" Opacity="0.7"
TextTrimming="None" Margin="2,0,0,5" FontSize="11" HorizontalAlignment="Left" />
<TextBlock x:Name="LabRamGameTitle" Text="{DynamicResource Setup.Launch.Memory.GameAllocation}" Opacity="0.7" Grid.ColumnSpan="3"
TextTrimming="None" Margin="2,0,0,5" FontSize="11" HorizontalAlignment="Left" />
<StackPanel Grid.Row="2" Orientation="Horizontal" Grid.ColumnSpan="3" Margin="2,3,0,0"
HorizontalAlignment="Left">
<TextBlock x:Name="LabRamUsed" Text="4.7 GiB" FontSize="16"
Foreground="{DynamicResource ColorBrushMemory}" TextTrimming="None" />
<TextBlock x:Name="LabRamTotal" Text=" / 7.9 GiB" FontSize="16"
Foreground="{DynamicResource ColorBrushMemory}" TextTrimming="None" />
</StackPanel>
<TextBlock Grid.Row="2" x:Name="LabRamGame" Text="2.5 GiB" Grid.ColumnSpan="3"
TextTrimming="None" Margin="2,3,0,0" FontSize="16"
Foreground="{DynamicResource ColorBrushMemory}" HorizontalAlignment="Left" />
</Grid>
</StackPanel>
</local:MyCard>
<local:MyCard Margin="0,0,0,15" Title="{DynamicResource Setup.Launch.Advanced.Title}" IsSwapped="True" CanSwap="True">
<Grid Margin="25,40,25,15">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="1*" />
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="28" />
<RowDefinition Height="9" />
<RowDefinition Height="Auto" />
<RowDefinition Height="9" />
<RowDefinition Height="28" />
<RowDefinition Height="9" />
<RowDefinition Height="28" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<TextBlock Grid.Row="0" VerticalAlignment="Center" HorizontalAlignment="Left" Text="{DynamicResource Setup.Launch.Advanced.Renderer.Label}"
Margin="0,0,25,0" />
<local:MyComboBox x:Name="ComboAdvanceRenderer" Grid.Row="0" Grid.Column="1" Grid.ColumnSpan="2"
Tag="LaunchAdvanceRenderer"
SelectionChanged="ComboAdvanceRenderer_OnSelectionChanged">
<local:MyComboBoxItem Content="{DynamicResource Setup.Launch.Advanced.Renderer.GameDefault}" IsSelected="True" />
<local:MyComboBoxItem Content="{DynamicResource Setup.Launch.Advanced.Renderer.Software}" />
<local:MyComboBoxItem Content="{DynamicResource Setup.Launch.Advanced.Renderer.DirectX12}" />
<local:MyComboBoxItem Content="{DynamicResource Setup.Launch.Advanced.Renderer.Vulkan}" />
</local:MyComboBox>
<StackPanel Grid.Row="2" VerticalAlignment="Center" Orientation="Horizontal"
HorizontalAlignment="Left" Margin="0,0,25,0">
<TextBlock Text="{DynamicResource Setup.Launch.Advanced.JvmHead}" VerticalAlignment="Center" />
<local:MyIconButton Height="23" Margin="0,1,0,0" x:Name="BtnAdvanceJvmReset"
VerticalAlignment="Center" Click="BtnAdvanceJvmReset_Click"
ToolTip="{DynamicResource Setup.Launch.Advanced.JvmHead.Restore}" ToolTipService.Placement="Right"
ToolTipService.InitialShowDelay="200" ToolTipService.VerticalOffset="-1"
SvgIcon="lucide/rotate-ccw"
LogoScale="0.9" />
</StackPanel>
<local:MyTextBox Grid.Row="2" x:Name="TextAdvanceJvm" Grid.ColumnSpan="2" Tag="LaunchAdvanceJvm"
TextChanged="TextAdvanceJvm_TextChanged"
Grid.Column="1" ValidatedTextChanged="TextBoxChange"
ToolTip="{DynamicResource Setup.Launch.Advanced.JvmHead.ToolTip}"
MaxLength="4000" Height="100" AcceptsReturn="True" TextWrapping="Wrap"
VerticalContentAlignment="Top" Padding="0,5" VerticalScrollBarVisibility="Auto" />
<TextBlock Grid.Row="4" VerticalAlignment="Center" HorizontalAlignment="Left" Text="{DynamicResource Setup.Launch.Advanced.GameTail}"
Margin="0,0,25,0" />
<local:MyTextBox x:Name="TextAdvanceGame" Grid.Row="4" Grid.ColumnSpan="2" Tag="LaunchAdvanceGame"
Grid.Column="1" ValidatedTextChanged="TextBoxChange"
ToolTip="{DynamicResource Setup.Launch.Advanced.GameTail.ToolTip}" />
<TextBlock Grid.Row="6" VerticalAlignment="Center" HorizontalAlignment="Left" Text="{DynamicResource Setup.Launch.Advanced.PreLaunchCommand}"
Margin="0,0,25,0" />
<local:MyTextBox x:Name="TextAdvanceRun" Grid.Row="6" Grid.ColumnSpan="2" Tag="LaunchAdvanceRun"
Grid.Column="1" HintText="" ValidatedTextChanged="TextBoxChange"
TextChanged="TextAdvanceRun_TextChanged"
ToolTip="{DynamicResource Setup.Launch.Advanced.PreLaunchCommand.ToolTip}" />
<local:MyCheckBox Grid.Row="7" Grid.Column="1" x:Name="CheckAdvanceRunWait"
Tag="LaunchAdvanceRunWait" Visibility="Collapsed"
Change="CheckBoxChange"
Text="{DynamicResource Setup.Launch.Advanced.PreLaunchCommand.Wait}" Margin="0,8,0,7" />
<StackPanel Margin="0,12,0,4" Grid.Row="8" Grid.ColumnSpan="2" HorizontalAlignment="Left">
<local:MyCheckBox Height="28" Text="{DynamicResource Setup.Launch.Advanced.DisableJlw}" x:Name="CheckAdvanceDisableJLW" Tag="LaunchAdvanceDisableJLW" Change="CheckBoxChange"
ToolTipService.Placement="Right" ToolTip="{DynamicResource Setup.Launch.Advanced.DisableJlw.ToolTip}" />
<local:MyCheckBox Height="28" Text="{DynamicResource Setup.Launch.Advanced.DisableLF}" x:Name="CheckAdvanceDisableLF" Tag="LaunchAdvanceDisableLF" Change="CheckBoxChange"
ToolTipService.Placement="Right" ToolTip="{DynamicResource Setup.Launch.Advanced.DisableLF.ToolTip}" />
<local:MyCheckBox Height="28" Text="{DynamicResource Setup.Launch.Advanced.GpuPreference}" x:Name="CheckAdvanceGraphicCard" Tag="LaunchAdvanceGraphicCard" Change="CheckBoxChange"
ToolTipService.Placement="Right" ToolTip="{DynamicResource Setup.Launch.Advanced.GpuPreference.ToolTip}" />
<local:MyCheckBox Height="28" Text="{DynamicResource Setup.Launch.Advanced.UseJavaExe}" x:Name="CheckAdvanceNoJavaw" Tag="LaunchAdvanceNoJavaw" Change="CheckBoxChange"
ToolTipService.Placement="Right" ToolTip="{DynamicResource Setup.Launch.Advanced.UseJavaExe.ToolTip}" />
<local:MyCheckBox Height="28" Text="{DynamicResource Setup.Launch.Advanced.DisableLwjglUnsafeAgent}" x:Name="CheckAdvanceDisableLwjglUnsafeAgent" Tag="LaunchAdvanceDisableLwjglUnsafeAgent" Change="CheckBoxChange"
ToolTipService.Placement="Right" ToolTip="{DynamicResource Setup.Launch.Advanced.DisableLwjglUnsafeAgent.ToolTip}" />
<local:MyCheckBox Height="28" Text="{DynamicResource Setup.Launch.Advanced.DisableCrashAnalysis}" x:Name="CheckAdvanceDisableCrashAnalysis" Tag="LaunchAdvanceDisableCrashAnalysis" Change="CheckBoxChange"
ToolTipService.Placement="Right" ToolTip="{DynamicResource Setup.Launch.Advanced.DisableCrashAnalysis.ToolTip}" />
<local:MyCheckBox Height="28" Text="{DynamicResource Setup.Launch.Advanced.LockMemory}" x:Name="CheckAdvanceLockMemory" Tag="LaunchAdvanceLockMemory" Change="CheckBoxChange"
ToolTipService.Placement="Right" ToolTip="{DynamicResource Setup.Launch.Advanced.LockMemory.ToolTip}" />
</StackPanel>
<local:MyHint Text="{DynamicResource Setup.Launch.Advanced.MoreInInstanceSetup}" Margin="0,5,0,10" Theme="Blue" Grid.Row="9"
Grid.ColumnSpan="2"
CanClose="True" RelativeSetup="HintMoreAdvancedSetup" />
</Grid>
</local:MyCard>
<local:MyExtraTextButton HorizontalAlignment="Center" Margin="0,-5,0,15"
x:Name="BtnSwitch" Text="{DynamicResource Setup.Launch.SwitchToInstanceSetup}" Click="BtnSwitch_Click"
LogoScale="0.9"
SvgIcon="lucide/arrow-right" />
</StackPanel>
</local:MyScrollViewer>
</local:MyPageRight>
@@ -0,0 +1,584 @@
using System.IO;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;
using System.Windows.Threading;
using PCL.Core.App;
using PCL.Core.App.Configuration;
using PCL.Core.Utils.OS;
using PCL.Core.App.Localization;
namespace PCL;
public partial class PageSetupLaunch
{
private bool isLoad;
public PageSetupLaunch()
{
Loaded += PageSetupLaunch_Loaded;
InitializeComponent();
}
private void PageSetupLaunch_Loaded(object sender, RoutedEventArgs e)
{
// 重复加载部分
PanBack.ScrollToHome();
RefreshRam(false);
if (ModInstanceList.McMcInstanceSelected is null)
BtnSwitch.Visibility = Visibility.Collapsed;
else
BtnSwitch.Visibility = Visibility.Visible;
// 非重复加载部分
if (isLoad)
return;
isLoad = true;
ModAnimation.AniControlEnabled += 1;
Reload();
ModAnimation.AniControlEnabled -= 1;
// 内存自动刷新
var timer = new DispatcherTimer { Interval = new TimeSpan(0, 0, 0, 1) };
timer.Tick += (_, _) => RefreshRam();
timer.Start();
RectRamGame.SizeChanged += (s, e) => RefreshRamText();
}
public void Reload()
{
try
{
// 启动参数
TextArgumentTitle.Text = Config.Launch.Title;
TextArgumentInfo.Text = Config.Launch.TypeInfo;
ComboArgumentIndieV2.SelectedIndex = Config.Launch.IndieSolutionV2;
ComboArgumentVisibie.SelectedIndex = (int)Config.Launch.LauncherVisibility;
ComboArgumentPriority.SelectedValue = ((int)Config.Launch.ProcessPriority).ToString();
ComboArgumentWindowType.SelectedIndex = (int)Config.Launch.GameWindowMode;
TextArgumentWindowWidth.Text = Config.Launch.GameWindowWidth.ToString();
TextArgumentWindowHeight.Text = Config.Launch.GameWindowHeight.ToString();
ComboMsAuthType.SelectedIndex = Config.Launch.LoginMsAuthType;
ComboPreferredIpStack.SelectedIndex = (int)Config.Launch.PreferredIpStack;
WindowTypeUIRefresh();
// 游戏内存
((MyRadioBox)FindName("RadioRamType" + Config.Launch.MemoryAllocationMode)).Checked = true;
SliderRamCustom.Value = Config.Launch.CustomMemorySize;
// 高级设置
ComboAdvanceRenderer.SelectedIndex = Config.Launch.Renderer;
TextAdvanceJvm.Text = Config.Launch.JvmArgs;
TextAdvanceGame.Text = Config.Launch.GameArgs;
TextAdvanceRun.Text = Config.Launch.PreLaunchCommand;
CheckAdvanceRunWait.Checked = Config.Launch.PreLaunchCommandWait;
CheckAdvanceDisableLF.Checked = Config.Launch.DisableLF;
CheckAdvanceGraphicCard.Checked = Config.Launch.SetGpuPreference;
CheckAdvanceNoJavaw.Checked = Config.Launch.NoJavaw;
CheckAdvanceDisableLwjglUnsafeAgent.Checked = Config.Launch.DisableLwjglUnsafeAgent;
CheckAdvanceDisableCrashAnalysis.Checked = Config.Launch.DisableCrashAnalysis;
CheckAdvanceLockMemory.Checked = Config.Launch.LockMemory;
if (SystemInfo.IsArm64System)
{
CheckAdvanceDisableJLW.Checked = true;
CheckAdvanceDisableJLW.IsEnabled = false;
CheckAdvanceDisableJLW.ToolTip = Lang.Text("Setup.Launch.Advanced.DisableJlw.Arm64Notice");
}
else
{
CheckAdvanceDisableJLW.Checked = Config.Launch.DisableJlw;
}
}
catch (NullReferenceException ex)
{
ModBase.Log(
ex,
Lang.Text("Setup.Launch.Error.ConfigReset"),
ModBase.LogLevel.Msgbox,
userSummary: Lang.Text("Setup.Launch.Error.ConfigReset"));
Reset();
}
catch (Exception ex)
{
ModBase.Log(
ex,
Lang.Text("Setup.Launch.Error.LoadFailed"),
ModBase.LogLevel.Feedback,
userSummary: Lang.Text("Setup.Launch.Error.LoadFailed"));
}
}
// 初始化
public void Reset()
{
try
{
Config.Launch.Reset();
ModBase.Log("[Setup] 已初始化启动设置");
HintService.Hint(Lang.Text("Setup.Launch.Initialized"), HintType.Success, false);
}
catch (Exception ex)
{
ModBase.Log(
ex,
Lang.Text("Setup.Launch.Error.InitFailed"),
ModBase.LogLevel.Msgbox,
userSummary: Lang.Text("Setup.Launch.Error.InitFailed"));
}
Reload();
}
// 将控件改变路由到设置改变
private void RadioBoxChange(object senderRaw, ModBase.RouteEventArgs e)
{
var sender = (MyRadioBox)senderRaw;
var gotCfg = sender.Tag?.ToString()?.Split("/") ?? Array.Empty<string>();
if (ModAnimation.AniControlEnabled == 0 && gotCfg.Length >= 2)
SetByTag(gotCfg[0], int.Parse(gotCfg[1]));
}
private void TextBoxChange(object senderRaw, RoutedEventArgs e)
{
var sender = (MyTextBox)senderRaw;
if (ModAnimation.AniControlEnabled == 0)
SetByTag(sender.Tag?.ToString(), sender.Text);
}
private void TextArgumentTitle_OnTextChanged(object senderRaw, TextChangedEventArgs e)
{
var sender = (MyTextBox)senderRaw;
if (ModAnimation.AniControlEnabled == 0)
SetByTag(sender.Tag?.ToString(), sender.Text);
}
private void SliderChange(object senderRaw, bool user)
{
var sender = (MySlider)senderRaw;
if (ModAnimation.AniControlEnabled == 0)
SetByTag(sender.Tag?.ToString(), sender.Value);
}
private void ComboChange(object senderRaw, SelectionChangedEventArgs e)
{
var sender = (MyComboBox)senderRaw;
if (ModAnimation.AniControlEnabled == 0)
{
var senderTag = sender.Tag?.ToString();
SetByTag(senderTag,
senderTag == "LaunchArgumentPriority" ? Convert.ToInt32(sender.SelectedValue) : sender.SelectedIndex);
if (senderTag == "LaunchArgumentWindowType") WindowTypeUIRefresh();
}
}
private void CheckBoxChange(object senderRaw, bool user)
{
var sender = (MyCheckBox)senderRaw;
if (ModAnimation.AniControlEnabled == 0)
SetByTag(sender.Tag?.ToString(), sender.Checked);
}
private static void SetByTag(string tag, object value)
=> ConfigService.TrySetValue(tag, value);
// 切换到实例独立设置
private void BtnSwitch_Click(object sender, MouseButtonEventArgs e)
{
ModInstanceList.McMcInstanceSelected.Load();
PageInstanceLeft.McInstance = ModInstanceList.McMcInstanceSelected;
ModMain.frmMain.PageChange(FormMain.PageType.InstanceSetup, FormMain.PageSubType.VersionSetup);
}
private void ComboAdvanceRenderer_OnSelectionChanged(object sender, SelectionChangedEventArgs e)
{
ComboChange(sender, e);
ComboAdvanceRenderer_SelectionChanged((MyComboBox)sender, e);
}
private void ComboArgumentIndie_OnSelectionChanged(object sender, SelectionChangedEventArgs e)
{
ComboChange(sender, e);
ComboArgumentIndie_SelectionChanged(sender, e);
}
#region
public void RamType(int type)
{
if (SliderRamCustom is null)
return;
SliderRamCustom.IsEnabled = type == 1;
}
/// <summary>
/// 刷新 UI 上的 RAM 显示。
/// </summary>
public void RefreshRam(bool showAnim)
{
if (LabRamGame is null || LabRamUsed is null || ModMain.frmMain.pageCurrent != FormMain.PageType.Setup ||
ModMain.frmSetupLeft.pageID != FormMain.PageSubType.SetupLaunch)
return;
// 获取内存情况
var ramGame = Math.Round(GetRam(ModInstanceList.McMcInstanceSelected, false), 5);
var phyRam = KernelInterop.GetPhysicalMemoryBytes();
var ramTotal = Math.Round((double)phyRam.Total / 1024 / 1024 / 1024, 1);
var ramAvailable = Math.Round((double)phyRam.Available / 1024 / 1024 / 1024, 1);
var ramGameActual = Math.Round(Math.Min(ramGame, ramAvailable), 5);
var ramUsed = Math.Round(ramTotal - ramAvailable, 5);
var ramEmpty = Math.Round(ModBase.MathClamp(ramTotal - ramUsed - ramGame, 0d, 1000d), 1);
// 设置最大可用内存
if (ramTotal <= 1.5d)
SliderRamCustom.MaxValue = (int)Math.Round(Math.Max(Math.Floor((ramTotal - 0.3d) / 0.1d), 1d));
else if (ramTotal <= 8d)
SliderRamCustom.MaxValue = (int)Math.Round(Math.Floor((ramTotal - 1.5d) / 0.5d) + 12d);
else if (ramTotal <= 16d)
SliderRamCustom.MaxValue = (int)Math.Round(Math.Floor((ramTotal - 8d) / 1d) + 25d);
else
SliderRamCustom.MaxValue = (int)Math.Round(Math.Floor((ramTotal - 16d) / 2d) + 33d);
// 设置文本
LabRamGame.Text = $"{Lang.Number(ramGame, "N1")} GiB{(ramGame != ramGameActual ? $" ({Lang.Text("Setup.Launch.Memory.AvailableSuffix", Lang.Number(ramGameActual, "N1"))})" : "")}";
LabRamUsed.Text = $"{Lang.Number(ramUsed, "N1")} GiB";
LabRamTotal.Text = $" / {Lang.Number(ramTotal, "N1")} GiB";
LabRamWarn.Visibility =
ramGame == 1d && !ModJava.IsGameSet64BitJava() && !SystemInfo.Is32BitSystem && ModJava.Javas.ExistAnyJava()
? Visibility.Visible
: Visibility.Collapsed;
HintRamTooHigh.Visibility = ramGame / ramTotal > 0.75d ? Visibility.Visible : Visibility.Collapsed;
if (showAnim)
{
// 宽度动画
ModAnimation.AniStart(
new[]
{
ModAnimation.AaGridLengthWidth(ColumnRamUsed, ramUsed - ColumnRamUsed.Width.Value, 800,
ease: new ModAnimation.AniEaseOutFluent(ModAnimation.AniEasePower.Strong)),
ModAnimation.AaGridLengthWidth(ColumnRamGame, ramGameActual - ColumnRamGame.Width.Value, 800,
ease: new ModAnimation.AniEaseOutFluent(ModAnimation.AniEasePower.Strong)),
ModAnimation.AaGridLengthWidth(ColumnRamEmpty, ramEmpty - ColumnRamEmpty.Width.Value, 800,
ease: new ModAnimation.AniEaseOutFluent(ModAnimation.AniEasePower.Strong))
}, "SetupLaunch Ram Grid");
}
else
{
// 宽度设置
ColumnRamUsed.Width = new GridLength(ramUsed, GridUnitType.Star);
ColumnRamGame.Width = new GridLength(ramGameActual, GridUnitType.Star);
ColumnRamEmpty.Width = new GridLength(ramEmpty, GridUnitType.Star);
}
}
private void RefreshRam()
{
RefreshRam(true);
}
private int ramTextLeft = 2;
private int ramTextRight = 1;
/// <summary>
/// 刷新 UI 上的文本位置。
/// </summary>
private void RefreshRamText()
{
// 获取宽度信息
var rectUsedWidth = RectRamUsed.ActualWidth;
var totalWidth = PanRamDisplay.ActualWidth;
var labGameWidth = LabRamGame.ActualWidth;
var labUsedWidth = LabRamUsed.ActualWidth;
var labTotalWidth = LabRamTotal.ActualWidth;
var labGameTitleWidth = LabRamGameTitle.ActualWidth;
var labUsedTitleWidth = LabRamUsedTitle.ActualWidth;
// 左侧
int left;
if (rectUsedWidth - 30d < labUsedWidth || rectUsedWidth - 30d < labUsedTitleWidth)
// 全写不下了
left = 0;
else if (rectUsedWidth - 25d < labUsedWidth + labTotalWidth)
// 显示不下完整数据
left = 1;
else
// 正常
left = 2;
if (ramTextLeft != left)
{
ramTextLeft = left;
switch (left)
{
case 0:
{
ModAnimation.AniStart(
new[]
{
ModAnimation.AaOpacity(LabRamUsed, -LabRamUsed.Opacity, 100),
ModAnimation.AaOpacity(LabRamTotal, -LabRamTotal.Opacity, 100),
ModAnimation.AaOpacity(LabRamUsedTitle, -LabRamUsedTitle.Opacity, 100)
}, "SetupLaunch Ram TextLeft");
break;
}
case 1:
{
ModAnimation.AniStart(
new[]
{
ModAnimation.AaOpacity(LabRamUsed, 1d - LabRamUsed.Opacity, 100),
ModAnimation.AaOpacity(LabRamTotal, -LabRamTotal.Opacity, 100),
ModAnimation.AaOpacity(LabRamUsedTitle, 0.7d - LabRamUsedTitle.Opacity, 100)
}, "SetupLaunch Ram TextLeft");
break;
}
case 2:
{
ModAnimation.AniStart(
new[]
{
ModAnimation.AaOpacity(LabRamUsed, 1d - LabRamUsed.Opacity, 100),
ModAnimation.AaOpacity(LabRamTotal, 1d - LabRamTotal.Opacity, 100),
ModAnimation.AaOpacity(LabRamUsedTitle, 0.7d - LabRamUsedTitle.Opacity, 100)
}, "SetupLaunch Ram TextLeft");
break;
}
}
}
// 右侧
int right;
if (totalWidth < labGameWidth + 2d + rectUsedWidth || totalWidth < labGameTitleWidth + 2d + rectUsedWidth)
// 挤到最右边
right = 0;
else
// 正常情况
right = 1;
if (right == 0)
{
if (ModAnimation.AniControlEnabled == 0 &&
(ramTextRight != right || ModAnimation.AniIsRun("SetupLaunch Ram TextRight")))
{
// 需要动画
ModAnimation.AniStart(
new[]
{
ModAnimation.AaX(LabRamGame, totalWidth - labGameWidth - LabRamGame.Margin.Left, 100,
ease: new ModAnimation.AniEaseOutFluent(ModAnimation.AniEasePower.Weak)),
ModAnimation.AaX(LabRamGameTitle, totalWidth - labGameTitleWidth - LabRamGameTitle.Margin.Left,
100, ease: new ModAnimation.AniEaseOutFluent(ModAnimation.AniEasePower.Weak))
}, "SetupLaunch Ram TextRight");
}
else
{
// 不需要动画
ModAnimation.AniStop("SetupLaunch Ram TextRight");
LabRamGame.Margin = new Thickness(totalWidth - labGameWidth, 3d, 0d, 0d);
LabRamGameTitle.Margin = new Thickness(totalWidth - labGameTitleWidth, 0d, 0d, 5d);
}
}
else if (ModAnimation.AniControlEnabled == 0 &&
(ramTextRight != right || ModAnimation.AniIsRun("SetupLaunch Ram TextRight")))
{
// 需要动画
ModAnimation.AniStart(
new[]
{
ModAnimation.AaX(LabRamGame, 2d + rectUsedWidth - LabRamGame.Margin.Left, 100,
ease: new ModAnimation.AniEaseOutFluent(ModAnimation.AniEasePower.Weak)),
ModAnimation.AaX(LabRamGameTitle, 2d + rectUsedWidth - LabRamGameTitle.Margin.Left, 100,
ease: new ModAnimation.AniEaseOutFluent(ModAnimation.AniEasePower.Weak))
}, "SetupLaunch Ram TextRight");
}
else
{
// 不需要动画
ModAnimation.AniStop("SetupLaunch Ram TextRight");
LabRamGame.Margin = new Thickness(2d + rectUsedWidth, 3d, 0d, 0d);
LabRamGameTitle.Margin = new Thickness(2d + rectUsedWidth, 0d, 0d, 5d);
}
ramTextRight = right;
}
/// <summary>
/// 获取当前设置的 RAM 值。单位为 GB。
/// </summary>
public static double GetRam(McInstance version, bool useVersionJavaSetup, bool? is32BitJava = default)
{
// ------------------------------------------
// 修改下方代码时需要一并修改 PageInstanceSetup
// ------------------------------------------
var ramGive = default(double);
if (Config.Launch.MemoryAllocationMode == 0)
{
// 自动配置
var ramAvailable =
Math.Round((double)KernelInterop.GetAvailablePhysicalMemoryBytes() / 1024 / 1024 / 1024 * 10) / 10;
// 确定需求的内存值
double ramMininum; // 无论如何也需要保证的最低限度内存
double ramTarget1; // 估计能勉强带动了的内存
double ramTarget2; // 估计没啥问题了的内存
double ramTarget3; // 放一百万个材质和 Mod 和光影需要的内存
if (version is not null && !version.IsLoaded)
version.Load();
if (version is not null && version.Modable)
{
// 可安装 Mod 的实例
var modDir = new DirectoryInfo(version.PathIndie + @"mods\");
var modCount = modDir.Exists ? modDir.GetFiles().Length : 0;
ramMininum = 0.5d + modCount / 150d;
ramTarget1 = 1.5d + modCount / 90d;
ramTarget2 = 2.7d + modCount / 50d;
ramTarget3 = 4.5d + modCount / 25d;
}
else if (version is not null && version.Info.HasOptiFine)
{
// OptiFine 实例
ramMininum = 0.5d;
ramTarget1 = 1.5d;
ramTarget2 = 3d;
ramTarget3 = 5d;
}
else
{
// 普通实例
ramMininum = 0.5d;
ramTarget1 = 1.5d;
ramTarget2 = 2.5d;
ramTarget3 = 4d;
}
var ramStages = new[]
{
(Delta: ramTarget1, Ratio: 1d),
(Delta: ramTarget2 - ramTarget1, Ratio: 0.7d),
(Delta: ramTarget3 - ramTarget2, Ratio: 0.4d),
(Delta: ramTarget3, Ratio: 0.15d)
};
foreach (var (RamDelta, RamRatio) in ramStages)
{
ramGive += Math.Min(ramAvailable * RamRatio, RamDelta);
ramAvailable -= RamDelta / RamRatio;
if (ramAvailable < 0.1d)
break;
}
// 不低于最低值
ramGive = Math.Round(Math.Max(ramGive, ramMininum), 1);
}
else
{
// 手动配置
var value = Config.Launch.CustomMemorySize;
ramGive = value switch
{
<= 12 => value * 0.1d + 0.3d,
<= 25 => (value - 12) * 0.5d + 1.5d,
<= 33 => (value - 25) * 1 + 8,
_ => (value - 33) * 2 + 16
};
}
// 若使用 32 位 Java,则限制为 1G
if (is32BitJava ?? !ModJava.IsGameSet64BitJava(useVersionJavaSetup ? version : null))
ramGive = Math.Min(1d, ramGive);
return ramGive;
}
#endregion
#region
private void WindowTypeUIRefresh()
{
if (ComboArgumentWindowType is null)
return;
if (ComboArgumentWindowType.SelectedIndex == 3 && LabArgumentWindowMiddle is not null &&
LabArgumentWindowMiddle.Visibility == Visibility.Collapsed)
{
LabArgumentWindowMiddle.Visibility = Visibility.Visible;
TextArgumentWindowHeight.Visibility = Visibility.Visible;
TextArgumentWindowWidth.Visibility = Visibility.Visible;
}
else if (ComboArgumentWindowType.SelectedIndex != 3 && LabArgumentWindowMiddle is not null &&
LabArgumentWindowMiddle.Visibility == Visibility.Visible)
{
LabArgumentWindowMiddle.Visibility = Visibility.Collapsed;
TextArgumentWindowHeight.Visibility = Visibility.Collapsed;
TextArgumentWindowWidth.Visibility = Visibility.Collapsed;
}
}
// 可见性选择直接关闭的警告
private void ComboArgumentVisibie_SelectionChanged(object sender, SelectionChangedEventArgs sizeChangedEventArgs)
{
ComboChange(sender, sizeChangedEventArgs);
if (ModAnimation.AniControlEnabled != 0)
return;
if (ComboArgumentVisibie.SelectedIndex == 0)
if (ModMain.MyMsgBox(
Lang.Text("Setup.Launch.Options.Visibility.CloseImmediately.Warning.Message"),
Lang.Text("Setup.Launch.Options.Visibility.CloseImmediately.Warning.Title"),
Lang.Text("Setup.Launch.Options.Visibility.CloseImmediately.Warning.Continue"),
Lang.Text("Common.Action.Cancel")) == 2)
ComboArgumentVisibie.SelectedItem = sizeChangedEventArgs.RemovedItems[0];
}
// 实例隔离提示
private void ComboArgumentIndie_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
if (ModAnimation.AniControlEnabled != 0)
return;
ModMain.MyMsgBox(Lang.Text("Setup.Launch.Options.InstanceIsolation.DefaultPolicyHint"));
}
#endregion
#region
private void TextAdvanceRun_TextChanged(object sender, TextChangedEventArgs e)
{
CheckAdvanceRunWait.Visibility =
string.IsNullOrEmpty(TextAdvanceRun.Text) ? Visibility.Collapsed : Visibility.Visible;
}
// JVM 参数重设
private void TextAdvanceJvm_TextChanged(object sender, TextChangedEventArgs e)
{
BtnAdvanceJvmReset.Visibility =
TextAdvanceJvm.Text == Config.Launch.JvmArgsConfig.DefaultValue
? Visibility.Hidden
: Visibility.Visible;
}
private void BtnAdvanceJvmReset_Click(object sender, EventArgs e)
{
Config.Launch.JvmArgsConfig.Reset();
Reload();
}
private void ComboAdvanceRenderer_SelectionChanged(MyComboBox sender, object e)
{
if (ModAnimation.AniControlEnabled != 0)
return;
if (!States.Hint.Renderer && ComboAdvanceRenderer.SelectedIndex != 0)
{
if (ModMain.MyMsgBox(Lang.Text("Setup.Launch.Advanced.Renderer.Warning.Message"),
Lang.Text("Common.Dialog.Warning"),
Lang.Text("Setup.Launch.Advanced.Renderer.Warning.Confirm"),
Lang.Text("Common.Action.Cancel"), isWarn: true) == 2)
{
ComboAdvanceRenderer.SelectedItem = ((SelectionChangedEventArgs)e).RemovedItems[0];
}
else
{
Config.Launch.Renderer = sender.SelectedIndex;
States.Hint.Renderer = true;
}
}
else
{
Config.Launch.Renderer = sender.SelectedIndex;
}
}
#endregion
}
@@ -0,0 +1,187 @@
<local:MyPageRight
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:PCL"
xmlns:svgIcon="clr-namespace:PCL.Core.UI.Controls.SvgIcon;assembly=PCL.Core"
xmlns:coreControls="clr-namespace:PCL.Core.UI.Controls;assembly=PCL.Core"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d"
x:Class="PCL.PageSetupLauncherLanguage"
PanScroll="{Binding ElementName=PanBack}">
<local:MyScrollViewer
x:Name="PanBack"
VerticalScrollBarVisibility="Auto"
HorizontalScrollBarVisibility="Disabled">
<StackPanel x:Name="PanMain" Margin="25,10">
<local:MyCard
Margin="0,15,0,10"
Title="{DynamicResource Setup.Language.CardTitle}">
<StackPanel Margin="25,40,25,15">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" SharedSizeGroup="Name" />
<ColumnDefinition Width="1*" />
<ColumnDefinition Width="60" />
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="28" />
<RowDefinition Height="9" />
<RowDefinition Height="28" />
</Grid.RowDefinitions>
<TextBlock
Grid.Row="0"
VerticalAlignment="Center"
HorizontalAlignment="Left"
Margin="0,0,25,0"
Text="{DynamicResource Setup.Language.UiLanguage}" />
<local:MyComboBox
x:Name="ComboUiLanguage"
Grid.Row="0"
Grid.Column="1"
Grid.ColumnSpan="2"
SelectionChanged="ComboUiLanguage_SelectionChanged" />
<TextBlock
Grid.Row="2"
VerticalAlignment="Center"
HorizontalAlignment="Left"
Margin="0,0,25,0"
Text="{DynamicResource Setup.Language.FormatCulture}" />
<local:MyComboBox
x:Name="ComboUiFormatCulture"
Grid.Row="2"
Grid.Column="1"
Grid.ColumnSpan="2"
SelectionChanged="ComboUiFormatCulture_SelectionChanged" />
</Grid>
<coreControls:BlurBorder
x:Name="BannerInternationalization"
Margin="0,10,0,0"
Padding="25"
MinHeight="230"
CornerRadius="5"
ClipToBounds="True"
Background="{DynamicResource ColorBrush7}">
<Grid>
<Canvas
Width="205"
Height="145"
HorizontalAlignment="Right"
VerticalAlignment="Top"
Margin="0,-43,-25,0"
Panel.ZIndex="0"
IsHitTestVisible="False">
<svgIcon:SvgIcon
Width="215"
Height="215"
Canvas.Left="5"
Canvas.Top="-56"
Icon="lucide/earth"
IconBrush="{DynamicResource ColorBrush5}"
StrokeThickness="2.4"
Opacity="0.62"
Stretch="Uniform" />
</Canvas>
<Grid Panel.ZIndex="1">
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<StackPanel Grid.Row="0" Margin="0,0,170,0" HorizontalAlignment="Left">
<TextBlock
FontSize="22"
FontWeight="Bold"
Foreground="{DynamicResource ColorBrush1}"
Text="{DynamicResource Setup.Language.Banner.TitlePrefix}"
TextWrapping="Wrap" />
<TextBlock
Margin="0,2,0,2"
FontFamily="Bahnschrift"
FontSize="42"
FontWeight="Bold"
Foreground="{DynamicResource ColorBrush1}"
Text="PCL CE"
TextWrapping="Wrap" />
<TextBlock
FontSize="22"
FontWeight="Bold"
Foreground="{DynamicResource ColorBrush1}"
Text="{DynamicResource Setup.Language.Banner.TitleSuffix}"
TextWrapping="Wrap" />
</StackPanel>
<StackPanel Grid.Row="1" Margin="0,20,0,0">
<TextBlock
FontSize="14"
LineHeight="23"
LineStackingStrategy="BlockLineHeight"
Foreground="{DynamicResource ColorBrush1}"
Text="{DynamicResource Setup.Language.Banner.DescriptionLine1}"
TextWrapping="Wrap" />
<TextBlock
Margin="0,5,0,0"
FontSize="14"
LineHeight="23"
LineStackingStrategy="BlockLineHeight"
Foreground="{DynamicResource ColorBrush1}"
Text="{DynamicResource Setup.Language.Banner.DescriptionLine2}"
TextWrapping="Wrap" />
<TextBlock
Margin="0,5,0,0"
FontSize="14"
LineHeight="23"
LineStackingStrategy="BlockLineHeight"
Foreground="{DynamicResource ColorBrush1}"
Text="{DynamicResource Setup.Language.Banner.DescriptionLine3}"
TextWrapping="Wrap" />
</StackPanel>
</Grid>
</Grid>
</coreControls:BlurBorder>
<StackPanel
Margin="0,10,0,0"
HorizontalAlignment="Right"
Orientation="Horizontal">
<local:MyIconTextButton
x:Name="BtnSubmitPullRequest"
Margin="0,0,7,0"
Text="{DynamicResource Setup.Language.Banner.SubmitPullRequest}"
SvgIcon="lucide/upload"
ColorType="Highlight"
ToolTip="{DynamicResource Setup.Language.Banner.SubmitPullRequest}"
local:CustomEventService.EventType="OpenUrl"
local:CustomEventService.EventData="https://github.com/PCL-Community/PCL-CE/pulls" />
<local:MyIconTextButton
x:Name="BtnViewDeveloperDocs"
Text="{DynamicResource Setup.Language.Banner.ViewDeveloperDocs}"
SvgIcon="lucide/book-marked"
ToolTip="{DynamicResource Setup.Language.Banner.ViewDeveloperDocs}"
local:CustomEventService.EventType="OpenUrl"
local:CustomEventService.EventData="https://docs.pclc.cc/ce/developers/" />
</StackPanel>
</StackPanel>
</local:MyCard>
</StackPanel>
</local:MyScrollViewer>
</local:MyPageRight>
@@ -0,0 +1,225 @@
using System.Globalization;
using System.Windows;
using System.Windows.Controls;
using PCL.Core.App;
using PCL.Core.App.Localization;
namespace PCL;
public partial class PageSetupLauncherLanguage
{
private bool _isLoaded;
public PageSetupLauncherLanguage()
{
InitializeComponent();
Loaded += PageSetupLauncherLanguage_Loaded;
}
private void PageSetupLauncherLanguage_Loaded(object sender, RoutedEventArgs e)
{
// 重复加载部分
PanBack.ScrollToHome();
// 非重复加载部分
if (_isLoaded)
return;
_isLoaded = true;
ModAnimation.AniControlEnabled += 1;
Reload();
ModAnimation.AniControlEnabled -= 1;
}
public void Reload()
{
ModAnimation.AniControlEnabled += 1;
try
{
ReloadLanguageCombo();
ReloadFormatCultureCombo();
}
finally
{
ModAnimation.AniControlEnabled -= 1;
}
}
public void Reset()
{
try
{
Config.Preference.Localization.LanguageConfig.SetDefaultValue();
Config.Preference.Localization.FormatCultureConfig.SetDefaultValue();
LocalizationService.ApplyFromConfig();
ModBase.Log("[Setup] 已初始化启动器-语言页设置");
HintService.Hint(Lang.Text("Setup.Language.Reset.Success"), HintType.Success, false);
Reload();
}
catch (Exception ex)
{
ModBase.Log(
ex,
"初始化启动器-语言页设置失败",
ModBase.LogLevel.Msgbox,
userSummary: Lang.Text("Setup.Error.OperationFailed"));
}
}
private void ReloadLanguageCombo()
{
ComboUiLanguage.Items.Clear();
var autoLanguage = LocalizationService.ResolveLanguage(LocalizationService.Auto);
ComboUiLanguage.Items.Add(CreateLanguageComboItem(
Lang.Text("Setup.Language.UiLanguage.Auto", GetLanguageDisplay(autoLanguage)),
LocalizationService.Auto,
autoLanguage));
foreach (var language in LocalizationService.SupportedLanguages)
ComboUiLanguage.Items.Add(CreateLanguageComboItem(
GetLanguageDisplay(language),
language.Code,
language));
var configValue = NormalizeConfigValue(Config.Preference.Localization.Language);
var selectedLanguageTag = LocalizationService.Auto;
if (LocalizationService.IsLanguageSupported(configValue))
selectedLanguageTag =
string.Equals(configValue, LocalizationService.Auto, StringComparison.OrdinalIgnoreCase)
? LocalizationService.Auto
: LocalizationService.ResolveLanguage(configValue).Code;
SelectComboItem(ComboUiLanguage, selectedLanguageTag);
}
private void ReloadFormatCultureCombo()
{
ComboUiFormatCulture.Items.Clear();
ComboUiFormatCulture.Items.Add(new MyComboBoxItem
{
Content = Lang.Text("Setup.Language.FormatCulture.Auto"),
Tag = LocalizationService.Auto
});
ComboUiFormatCulture.Items.Add(new MyComboBoxItem
{
Content = Lang.Text("Setup.Language.FormatCulture.FollowLanguage"),
Tag = LocalizationService.FormatCultureFollowLanguage
});
foreach (var culture in GetBuiltInFormatCultures())
ComboUiFormatCulture.Items.Add(new MyComboBoxItem
{
Content = GetCultureDisplay(culture),
Tag = culture.Name
});
var configValue = NormalizeConfigValue(Config.Preference.Localization.FormatCulture);
if (!IsFormatCultureItemExisting(configValue) && TryGetCulture(configValue, out var customCulture))
ComboUiFormatCulture.Items.Add(new MyComboBoxItem
{
Content = GetCultureDisplay(customCulture),
Tag = customCulture.Name
});
SelectComboItem(ComboUiFormatCulture,
IsFormatCultureItemExisting(configValue) ? configValue : LocalizationService.Auto);
}
private void ComboUiLanguage_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
if (ModAnimation.AniControlEnabled != 0)
return;
if (ComboUiLanguage.SelectedItem is not MyComboBoxItem item)
return;
var value = item.Tag?.ToString() ?? LocalizationService.Auto;
if (Config.Preference.Localization.Language == value)
return;
Config.Preference.Localization.Language = value;
HintService.Hint(Lang.Text("Setup.Language.Changed"), HintType.Success, false);
Reload();
}
private void ComboUiFormatCulture_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
if (ModAnimation.AniControlEnabled != 0)
return;
if (ComboUiFormatCulture.SelectedItem is not MyComboBoxItem item)
return;
var value = item.Tag?.ToString() ?? LocalizationService.Auto;
if (Config.Preference.Localization.FormatCulture == value)
return;
Config.Preference.Localization.FormatCulture = value;
HintService.Hint(Lang.Text("Setup.Language.Changed"), HintType.Success, false);
Reload();
}
private static IEnumerable<CultureInfo> GetBuiltInFormatCultures()
{
var used = new HashSet<string>(StringComparer.OrdinalIgnoreCase);
foreach (var language in LocalizationService.SupportedLanguages)
{
var culture = CultureInfo.GetCultureInfo(language.CultureName);
if (used.Add(culture.Name)) yield return culture;
}
}
private static MyComboBoxItem CreateLanguageComboItem(string content, string tag, LocalizationLanguage language)
{
return new MyComboBoxItem
{
Content = content,
Tag = tag,
FontFamily = LocalizationFontService.BuildRepresentativeFontFamily(language)
};
}
private static string GetLanguageDisplay(LocalizationLanguage language)
{
return $"{language.NativeName}";
}
private static string GetCultureDisplay(CultureInfo culture)
{
return $"{culture.NativeName}";
}
private static string NormalizeConfigValue(string? value)
{
return string.IsNullOrWhiteSpace(value) ? LocalizationService.Auto : value;
}
private static bool TryGetCulture(string value, out CultureInfo culture)
{
try
{
culture = CultureInfo.GetCultureInfo(value);
return true;
}
catch (CultureNotFoundException)
{
culture = CultureInfo.InvariantCulture;
return false;
}
}
private static void SelectComboItem(MyComboBox comboBox, string tag)
{
foreach (var item in comboBox.Items.OfType<MyComboBoxItem>())
{
if (!string.Equals(item.Tag?.ToString(), tag, StringComparison.OrdinalIgnoreCase)) continue;
comboBox.SelectedItem = item;
return;
}
comboBox.SelectedIndex = comboBox.Items.Count > 0 ? 0 : -1;
}
private bool IsFormatCultureItemExisting(string tag)
{
return ComboUiFormatCulture.Items.OfType<MyComboBoxItem>()
.Any(item => string.Equals(item.Tag?.ToString(), tag, StringComparison.OrdinalIgnoreCase));
}
}
@@ -0,0 +1,188 @@
<local:MyPageRight
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:PCL" xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d" x:Class="PCL.PageSetupLauncherMisc"
PanScroll="{Binding ElementName=PanBack}">
<local:MyScrollViewer VerticalScrollBarVisibility="Auto" HorizontalScrollBarVisibility="Disabled" x:Name="PanBack">
<StackPanel x:Name="PanMain" Margin="25,10">
<local:MyCard Margin="0,15" Title="{DynamicResource Setup.Misc.System.Title}">
<Grid Margin="25,40,25,16">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" SharedSizeGroup="Name" />
<ColumnDefinition Width="1*" />
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="28" />
<RowDefinition Height="9" />
<RowDefinition Height="28" />
<RowDefinition Height="5" />
<RowDefinition Height="28" />
<RowDefinition Height="5" />
<RowDefinition Height="20" />
<RowDefinition Height="8" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<TextBlock VerticalAlignment="Center" HorizontalAlignment="Left" Text="{DynamicResource Setup.Misc.System.Announcement}" Margin="0,0,25,0"
Grid.Row="0" />
<local:MyComboBox x:Name="ComboSystemActivity" Tag="SystemSystemActivity" Grid.Column="1"
Grid.Row="0"
SelectionChanged="ComboSystemActivity_OnSelectionChanged">
<local:MyComboBoxItem Content="{DynamicResource Setup.Misc.System.Announcement.All}" ToolTip="{DynamicResource Setup.Misc.System.Announcement.All.ToolTip}" />
<local:MyComboBoxItem Content="{DynamicResource Setup.Misc.System.Announcement.ImportantOnly}" />
<local:MyComboBoxItem Content="{DynamicResource Setup.Misc.System.Announcement.Disabled}" />
</local:MyComboBox>
<TextBlock Grid.Row="2" VerticalAlignment="Center" HorizontalAlignment="Left" Text="{DynamicResource Setup.Misc.System.MaxFps}"
Margin="0,0,25,0" />
<local:MySlider x:Name="SliderAniFPS" Grid.Row="2" Tag="UiAniFPS" MaxValue="59" Value="59"
Grid.Column="1"
ToolTip="{DynamicResource Setup.Misc.System.MaxFps.ToolTip}"
Change="SliderChange" />
<TextBlock Grid.Row="4" VerticalAlignment="Center" HorizontalAlignment="Left" Text="{DynamicResource Setup.Misc.System.MaxLogLines}"
Margin="0,0,25,0" />
<local:MySlider x:Name="SliderMaxLog" Grid.Row="4" Tag="SystemMaxLog" MaxValue="29" Value="13"
Grid.Column="1"
ToolTip="{DynamicResource Setup.Misc.System.MaxLogLines.ToolTip}"
Change="SliderChange" />
<Grid Grid.Row="6" Grid.ColumnSpan="5">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" SharedSizeGroup="CheckBox" />
<ColumnDefinition Width="Auto" SharedSizeGroup="CheckBox" />
<ColumnDefinition Width="Auto" SharedSizeGroup="CheckBox" />
<ColumnDefinition Width="Auto" SharedSizeGroup="CheckBox" />
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="20" />
</Grid.RowDefinitions>
<local:MyCheckBox Grid.Row="0" Grid.Column="0" Text="{DynamicResource Setup.Misc.System.DisableHardwareAcceleration}" x:Name="CheckSystemDisableHardwareAcceleration" Tag="SystemDisableHardwareAcceleration" Change="CheckSystemDisableHardwareAcceleration_OnChange"/>
<local:MyCheckBox Grid.Row="0" Grid.Column="1" Text="{DynamicResource Setup.Misc.System.Telemetry}" x:Name="CheckSystemTelemetry" Tag="SystemTelemetry" Change="CheckBoxChange"
ToolTip="{DynamicResource Setup.Misc.System.Telemetry.ToolTip}"/>
</Grid>
<Grid Grid.Row="8" Grid.ColumnSpan="5">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" SharedSizeGroup="Button" />
<ColumnDefinition Width="Auto" SharedSizeGroup="Button" />
<ColumnDefinition Width="Auto" SharedSizeGroup="Button" />
<ColumnDefinition Width="Auto" SharedSizeGroup="Button" />
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="35" />
</Grid.RowDefinitions>
<local:MyButton Grid.Column="0" Grid.Row="0" x:Name="BtnSystemSettingExp" MinWidth="140"
Text="{DynamicResource Setup.Misc.System.ExportSettings}" Padding="13,0" Margin="0,0,20,0"
Click="BtnSystemSettingExp_Click" />
<local:MyButton Grid.Column="1" Grid.Row="0" x:Name="BtnSystemSettingImp" MinWidth="140"
Text="{DynamicResource Setup.Misc.System.ImportSettings}" Padding="13,0" Margin="0,0,20,0"
Click="BtnSystemSettingImp_Click" />
<local:MyButton Grid.Column="2" Grid.Row="0" x:Name="BtnSystemStopUsingPclCe" MinWidth="140"
Text="{DynamicResource Setup.Misc.System.StopUsingPclCe}" Padding="13,0" Margin="0,0,20,0"
ColorType="Red" Click="BtnSystemStopUsingPclCe_Click" />
</Grid>
</Grid>
</local:MyCard>
<local:MyCard Margin="0,0,0,15" Title="{DynamicResource Setup.Misc.Network.Title}">
<Grid Margin="25,38,25,15">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" SharedSizeGroup="Name" />
<ColumnDefinition Width="1*" />
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="28" />
<RowDefinition Height="4" />
<RowDefinition Height="28" />
<RowDefinition Height="4" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<local:MyCheckBox x:Name="CheckNetDohEnable" Tag="SystemNetEnableDoH" Grid.Row="0"
Grid.ColumnSpan="2" Text="{DynamicResource Setup.Misc.Network.DoH}"
ToolTip="{DynamicResource Setup.Misc.Network.DoH.ToolTip}"
Change="CheckBoxChange" />
<TextBlock Grid.Row="2" VerticalAlignment="Center" HorizontalAlignment="Left" Text="{DynamicResource Setup.Misc.Network.HttpProxy}"
Margin="0,0,25,0" />
<Grid Grid.Row="2" Grid.Column="1">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="1*" />
<ColumnDefinition Width="1*" />
<ColumnDefinition Width="1*" />
<ColumnDefinition Width="0.2*" />
</Grid.ColumnDefinitions>
<local:MyRadioBox Text="{DynamicResource Setup.Misc.Network.Proxy.None}" x:Name="RadioHttpProxyType0" Height="22"
Tag="SystemHttpProxyType/0" Grid.Column="0"
Check="RadioBoxChange" />
<local:MyRadioBox Text="{DynamicResource Setup.Misc.Network.Proxy.System}" x:Name="RadioHttpProxyType1" Height="22"
Tag="SystemHttpProxyType/1" Grid.Column="1"
Check="RadioBoxChange" />
<local:MyRadioBox Text="{DynamicResource Setup.Misc.Network.Proxy.Custom}" x:Name="RadioHttpProxyType2" Height="22"
Tag="SystemHttpProxyType/2" Grid.Column="2"
Check="RadioBoxChange" />
</Grid>
<Grid Grid.Row="4" Grid.Column="1" x:Name="HttpProxyCustom"
Visibility="{Binding ElementName=RadioHttpProxyType2,Path=Checked,Converter={StaticResource BooleanToVisibilityConverter}}">
<Grid.RowDefinitions>
<RowDefinition Height="28" />
<RowDefinition Height="9" />
<RowDefinition Height="28" />
<RowDefinition Height="9" />
<RowDefinition Height="28" />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="1*" />
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="1*" />
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>
<local:MyHint Text="{DynamicResource Setup.Misc.Network.Proxy.UntrustedWarning}" Grid.Row="0" Grid.ColumnSpan="5" Theme="Yellow" />
<local:MyTextBox x:Name="TextSystemHttpProxy" Grid.Row="2" Grid.Column="0" Grid.ColumnSpan="5"
Tag="SystemHttpProxy" HintText="比如 http://127.0.0.1:1080/"
ToolTip="{DynamicResource Setup.Misc.Network.Proxy.InvalidWarning}" />
<TextBlock Grid.Column="0" Grid.Row="4" Text="{DynamicResource Setup.Misc.Network.Proxy.Username}" VerticalAlignment="Center"
HorizontalAlignment="Left" Margin="0,0,5,0" />
<local:MyTextBox Grid.Column="1" Grid.Row="4" HintText="{DynamicResource Setup.Misc.Network.Proxy.Optional}" Tag="SystemHttpProxyCustomUsername"
x:Name="TextSystemHttpProxyCustomUsername" Margin="0,0,5,0" />
<TextBlock Grid.Column="2" Grid.Row="4" Text="{DynamicResource Setup.Misc.Network.Proxy.Password}" VerticalAlignment="Center"
HorizontalAlignment="Left" Margin="0,0,5,0" />
<local:MyTextBox Grid.Column="3" Grid.Row="4" HintText="{DynamicResource Setup.Misc.Network.Proxy.Optional}" Tag="SystemHttpProxyCustomPassword"
x:Name="TextSystemHttpProxyCustomPassword" Margin="0,0,5,0" />
<local:MyButton Text="{DynamicResource Setup.Misc.Network.Proxy.Apply}" TextPadding="3" Grid.Row="4" Grid.Column="4"
x:Name="BtnApplyHttpProxy" Click="ApplyHttpProxyBtn_OnClicked" />
</Grid>
</Grid>
</local:MyCard>
<local:MyCard x:Name="CardDebug" Margin="0,0,0,15" Title="{DynamicResource Setup.Misc.Debug.Title}" CanSwap="True" IsSwapped="True">
<StackPanel Margin="25,40,25,15">
<Grid x:Name="PanDebugAnim" Height="22" Margin="0,0,0,10">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" SharedSizeGroup="Name" />
<ColumnDefinition />
</Grid.ColumnDefinitions>
<TextBlock VerticalAlignment="Center" HorizontalAlignment="Left" Text="{DynamicResource Setup.Misc.Debug.AnimationSpeed}" Margin="0,0,25,0" />
<local:MySlider x:Name="SliderDebugAnim" Tag="SystemDebugAnim" MaxValue="30" Grid.Column="1"
Change="SliderChange" />
</Grid>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="1.5*" />
<ColumnDefinition />
<ColumnDefinition />
</Grid.ColumnDefinitions>
<local:MyCheckBox Grid.Column="0" Text="{DynamicResource Setup.Misc.Debug.SkipCopy}" Height="22"
x:Name="CheckDebugSkipCopy" Tag="SystemDebugSkipCopy"
ToolTip="{DynamicResource Setup.Misc.Debug.SkipCopy.ToolTip}"
Change="CheckBoxChange" />
<local:MyCheckBox Grid.Column="1" Text="{DynamicResource Setup.Misc.Debug.Mode}" Height="22" x:Name="CheckDebugMode"
Tag="SystemDebugMode" ToolTip="{DynamicResource Setup.Misc.Debug.Mode.ToolTip}"
Change="CheckDebugMode_OnChange" />
<local:MyCheckBox Grid.Column="2" Text="{DynamicResource Setup.Misc.Debug.Delay}" Height="22" x:Name="CheckDebugDelay"
Tag="SystemDebugDelay"
ToolTip="{DynamicResource Setup.Misc.Debug.Delay.ToolTip}"
Change="CheckBoxChange" />
</Grid>
</StackPanel>
</local:MyCard>
</StackPanel>
</local:MyScrollViewer>
</local:MyPageRight>
@@ -0,0 +1,322 @@
using System.Diagnostics;
using System.IO;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;
using PCL.Core.App;
using PCL.Core.App.Configuration;
using PCL.Core.App.IoC;
using PCL.Core.UI;
using PCL.Core.App.Localization;
using PCL.Core.Utils.OS;
namespace PCL;
public partial class PageSetupLauncherMisc
{
private bool isFirstLoad = true;
private new bool isLoaded;
public PageSetupLauncherMisc()
{
InitializeComponent();
Loaded += PageSetupLink_Loaded;
Loaded += (_, _) => Reload();
}
private void PageSetupLink_Loaded(object sender, RoutedEventArgs e)
{
// 重复加载部分
PanBack.ScrollToHome();
// 非重复加载部分
if (isLoaded)
return;
isLoaded = true;
ModAnimation.AniControlEnabled += 1;
SliderLoad();
Reload();
ModAnimation.AniControlEnabled -= 1;
}
public void Reload()
{
// 系统设置
ComboSystemActivity.SelectedIndex = States.System.AnnounceSolution;
CheckSystemDisableHardwareAcceleration.Checked = Config.System.DisableHardwareAcceleration;
SliderAniFPS.Value = Config.System.AnimationFpsLimit;
SliderMaxLog.Value = Config.System.MaxGameLog;
CheckSystemTelemetry.Checked = Config.System.Telemetry;
// 网络
TextSystemHttpProxy.Text = Config.Network.HttpProxy.CustomAddress;
TextSystemHttpProxyCustomUsername.Text = Config.Network.HttpProxy.CustomUsername;
TextSystemHttpProxyCustomPassword.Text = Config.Network.HttpProxy.CustomPassword;
((MyRadioBox)FindName($"RadioHttpProxyType{Config.Network.HttpProxy.Type}")).SetChecked(true, false);
CheckNetDohEnable.Checked = Config.Network.EnableDoH;
// 调试选项
SliderDebugAnim.Value = Config.Debug.AnimationSpeed;
CheckDebugSkipCopy.Checked = Config.Debug.DontCopy;
CheckDebugMode.Checked = Config.Debug.Enabled;
CheckDebugDelay.Checked = Config.Debug.AddRandomDelay;
}
// 初始化
public void Reset()
{
try
{
Config.Network.Reset();
Config.Debug.Reset();
Config.System.Reset();
ModBase.Log("[Setup] 已初始化启动器-杂项页设置");
HintService.Hint(Lang.Text("Setup.Misc.Initialized"), HintType.Success, false);
Reload();
}
catch (Exception ex)
{
ModBase.Log(
ex,
Lang.Text("Setup.Misc.Error.InitFailed"),
ModBase.LogLevel.Msgbox,
userSummary: Lang.Text("Setup.Misc.Error.InitFailed"));
}
Reload();
}
// 将控件改变路由到设置改变
private void ComboChange(object senderRaw, SelectionChangedEventArgs e)
{
var sender = (MyComboBox)senderRaw;
if (ModAnimation.AniControlEnabled == 0)
SetByTag(sender.Tag?.ToString(), sender.SelectedIndex);
}
private void RadioBoxChange(object senderRaw, ModBase.RouteEventArgs e)
{
var sender = (MyRadioBox)senderRaw;
var gotCfg = sender.Tag?.ToString()?.Split("/") ?? Array.Empty<string>();
if (ModAnimation.AniControlEnabled == 0 && gotCfg.Length >= 2)
SetByTag(gotCfg[0], int.Parse(gotCfg[1]));
}
private void CheckBoxChange(object senderRaw, bool user)
{
var sender = (MyCheckBox)senderRaw;
if (ModAnimation.AniControlEnabled == 0)
SetByTag(sender.Tag?.ToString(), sender.Checked);
}
private void SliderChange(object senderRaw, bool user)
{
var sender = (MySlider)senderRaw;
if (ModAnimation.AniControlEnabled == 0)
SetByTag(sender.Tag?.ToString(), sender.Value);
}
private static void SetByTag(string tag, object value)
=> ConfigService.TrySetValue(tag, value);
// 网络
private void ApplyHttpProxyBtn_OnClicked(object sender, MouseButtonEventArgs e)
{
Config.Network.HttpProxy.CustomAddress = TextSystemHttpProxy.Text;
Config.Network.HttpProxy.CustomUsername = TextSystemHttpProxyCustomUsername.Text;
Config.Network.HttpProxy.CustomPassword = TextSystemHttpProxyCustomPassword.Text;
}
// 滑动条
private void SliderLoad()
{
SliderDebugAnim.getHintText = new Func<object, object>(v =>
(int)v > 29
? Lang.Text("Common.Action.Close")
: Lang.Number(Math.Round(Convert.ToDouble(v) / 10 + 0.1d, 1), "N1") + "x");
SliderAniFPS.getHintText = new Func<object, string>(v => Lang.Number(Convert.ToInt32(v) + 1, "N0") + " FPS");
// y = 10x + 50 (0 <= x <= 5, 50 <= y <= 100)
// y = 50x - 150 (5 < x <= 13, 100 < y <= 500)
// y = 100x - 800 (13 < x <= 28, 500 < y <= 2000)
SliderMaxLog.getHintText = new Func<object, object>(v =>
{
var val = Convert.ToInt32(v);
return val switch
{
<= 5 => val * 10 + 50,
<= 13 => val * 50 - 150,
<= 28 => val * 100 - 800,
_ => Lang.Text("Setup.Misc.System.MaxLogLines.Unlimited")
};
});
}
// 硬件加速
private void Check_DisableHardwareAcceleration(object _, bool __)
{
HintService.Hint(Lang.Text("Setup.Misc.HardwareAcceleration.RestartNotice"));
}
// 调试模式
private void CheckDebugMode_Change(object _, bool __)
{
if (ModAnimation.AniControlEnabled == 0)
HintService.Hint(Lang.Text("Setup.Misc.Debug.Mode.Hint"), log: false);
}
// 自动更新
private void ComboSystemActivity_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
if (ModAnimation.AniControlEnabled != 0)
return;
if (ComboSystemActivity.SelectedIndex != 2)
return;
if (ModMain.MyMsgBox(
Lang.Text("Setup.Misc.System.Announcement.Disabled.Warning.Message"),
Lang.Text("Common.Dialog.Warning"),
Lang.Text("Setup.Misc.System.Announcement.Disabled.Warning.Confirm"),
Lang.Text("Common.Action.Cancel"), isWarn: true) ==
2) ComboSystemActivity.SelectedItem = e.RemovedItems[0];
}
private void CheckDebugMode_OnChange(object sender, bool user)
{
CheckBoxChange(sender, user);
CheckDebugMode_Change(sender, user);
}
private void CheckSystemDisableHardwareAcceleration_OnChange(object sender, bool user)
{
CheckBoxChange(sender, user);
Check_DisableHardwareAcceleration(sender, user);
}
private void ComboSystemActivity_OnSelectionChanged(object sender, SelectionChangedEventArgs e)
{
ComboChange(sender, e);
ComboSystemActivity_SelectionChanged(sender, e);
}
#region /
private void BtnSystemSettingExp_Click(object sender, MouseButtonEventArgs e)
{
var savePath =
SystemDialogs.SelectSaveFile(Lang.Text("Setup.Misc.System.ExportSettings.SaveTitle"), "PCL 全局配置.json", Lang.Text("Setup.Misc.System.ExportSettings.Filter"), ModBase.exePath);
if (string.IsNullOrWhiteSpace(savePath))
return;
File.Copy(ConfigService.SharedConfigPath, savePath, true);
HintService.Hint(Lang.Text("Setup.Misc.System.ExportSettings.Success"), HintType.Success);
ModBase.OpenExplorer(savePath);
}
private void BtnSystemSettingImp_Click(object sender, MouseButtonEventArgs e)
{
var sourcePath = SystemDialogs.SelectFile(Lang.Text("Setup.Misc.System.ExportSettings.Filter"), Lang.Text("Setup.Misc.System.ImportSettings.SelectTitle"));
if (string.IsNullOrWhiteSpace(sourcePath))
return;
File.Copy(sourcePath, ConfigService.SharedConfigPath, true);
ModMain.MyMsgBox(Lang.Text("Setup.Misc.System.ImportSettings.Success.Message"), button1: Lang.Text("Setup.Misc.System.ImportSettings.Success.Restart"), forceWait: true);
Process.Start(new ProcessStartInfo(Basics.ExecutablePath));
FormMain.EndProgramForce();
}
#endregion
#region 使 PCL CE
private void BtnSystemStopUsingPclCe_Click(object sender, MouseButtonEventArgs e)
{
var result = ModMain.MyMsgBox(
Lang.Text("Setup.Misc.System.StopUsingPclCe.Message"),
Lang.Text("Setup.Misc.System.StopUsingPclCe.Title"),
Lang.Text("Common.Action.Continue"),
Lang.Text("Setup.Misc.System.StopUsingPclCe.ContinueAndRemove"),
Lang.Text("Common.Action.Cancel"),
isWarn: true);
if (result < 3)
{
if (ModMain.MyMsgBox(
Lang.Text("Setup.Misc.System.StopUsingPclCe.Message.Final"),
Lang.Text("Common.Dialog.Warning"),
Lang.Text("Common.Action.Continue"),
Lang.Text("Common.Action.Cancel"),
isWarn: true) == 1)
{
StopUsingPClCeCore(result == 2);
}
}
}
private void StopUsingPClCeCore(bool removeMcResources)
{
// 删除 MC 文件夹内的 PCL CE 配置
if (removeMcResources && States.Game.Folders != "")
{
foreach (var path in States.Game.Folders.Split('|'))
{
var realPath = path.Split('>')[1];
Delete([Path.Combine(realPath, "PCL.ini")]);
var versionsPath = Path.Combine(realPath, "versions");
if (!Directory.Exists(versionsPath)) continue;
Delete(
Directory.EnumerateDirectories(versionsPath)
.Select(p => Path.Combine(p, "PCL", "config.v1.yml"))
);
}
}
// 由于 CE 文件夹正在使用,使用延迟调用 CMD 的方法删除
List<string> foldersToDelete =
[
Paths.Data,
Paths.OldSharedData,
Paths.SharedData,
Paths.SharedLocalData,
Paths.Temp
];
var sb = new StringBuilder();
sb.Append("/c timeout /t 5 /nobreak >nul & ");
foreach (var folder in foldersToDelete)
{
sb.Append($"rmdir /s /q \"{folder}\" & ");
}
Process.Start(new ProcessStartInfo
{
FileName = "cmd.exe",
Arguments = sb.ToString(),
CreateNoWindow = true,
WindowStyle = ProcessWindowStyle.Hidden,
UseShellExecute = false
});
// 强制退出
KernelInterop.ExitProcess();
void Delete(IEnumerable<string> paths)
{
foreach (var path in paths)
{
try
{
if (!File.Exists(path)) continue;
File.Delete(path);
}
catch (Exception)
{
//
}
}
}
}
#endregion
}
@@ -0,0 +1,154 @@
<local:MyPageLeft
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:PCL" xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" mc:Ignorable="d" x:Class="PCL.PageSetupLeft"
d:DesignWidth="152">
<local:MyScrollViewer HorizontalScrollBarVisibility="Disabled" VerticalScrollBarVisibility="Auto"
Style="{StaticResource ScrollViewerFullMargin}">
<StackPanel Margin="0,12,0,0" x:Name="PanItem">
<TextBlock Text="{DynamicResource Setup.Left.Category.Game}" Margin="13,5,5,3" Opacity="0.6" FontSize="12" x:Name="TextGameCategory" />
<local:MyListItem x:Name="ItemLaunch" IsScaleAnimationEnabled="False" Tag="0" MinPaddingRight="35" Height="36" VerticalAlignment="Top" Title="{DynamicResource Setup.Left.Item.Launch}" Type="RadioBox" Check="PageCheck"
LogoScale="1" SvgIcon="lucide/rocket">
<local:MyListItem.Buttons>
<x:Array Type="{x:Type local:MyIconButton}">
<local:MyIconButton Tag="0" ToolTip="{DynamicResource Common.Action.Initialize}" ToolTipService.Placement="Right"
ToolTipService.InitialShowDelay="200" ToolTipService.VerticalOffset="-1"
Click="Reset"
SvgIcon="lucide/rotate-ccw"
LogoScale="0.9" />
</x:Array>
</local:MyListItem.Buttons>
</local:MyListItem>
<local:MyListItem x:Name="ItemJava" IsScaleAnimationEnabled="False" Tag="9" MinPaddingRight="35" Height="36" VerticalAlignment="Top" Title="{DynamicResource Setup.Left.Item.Java}" Type="RadioBox" Check="PageCheck"
LogoScale="1" SvgIcon="lucide/coffee">
<local:MyListItem.Buttons>
<x:Array Type="{x:Type local:MyIconButton}">
<local:MyIconButton Tag="9" ToolTip="{DynamicResource Common.Action.Refresh}" ToolTipService.Placement="Right"
ToolTipService.InitialShowDelay="200" ToolTipService.VerticalOffset="-1"
Click="Refresh" LogoScale="0.85"
SvgIcon="lucide/refresh-cw" />
</x:Array>
</local:MyListItem.Buttons>
</local:MyListItem>
<local:MyListItem x:Name="ItemGameManage" IsScaleAnimationEnabled="False" Tag="2" MinPaddingRight="35"
Check="PageCheck"
Height="36" VerticalAlignment="Top" Title="{DynamicResource Setup.Left.Item.GameManage}" Type="RadioBox"
LogoScale="0.95"
SvgIcon="lucide/book-marked">
<local:MyListItem.Buttons>
<x:Array Type="{x:Type local:MyIconButton}">
<local:MyIconButton Tag="2" ToolTip="{DynamicResource Common.Action.Initialize}" ToolTipService.Placement="Right"
ToolTipService.InitialShowDelay="200" ToolTipService.VerticalOffset="-1"
Click="Reset"
SvgIcon="lucide/rotate-ccw"
LogoScale="0.9" />
</x:Array>
</local:MyListItem.Buttons>
</local:MyListItem>
<TextBlock Text="{DynamicResource Setup.Left.Category.Tools}" Margin="13,5,5,3" Opacity="0.6" FontSize="12" x:Name="TextToolsCategory" />
<local:MyListItem x:Name="ItemGameLink" IsScaleAnimationEnabled="False" Type="RadioBox" Tag="7"
Check="PageCheck"
MinPaddingRight="35" Height="36" VerticalAlignment="Top" Title="{DynamicResource Setup.Left.Item.GameLink}"
SvgIcon="lucide/bubbles">
<local:MyListItem.Buttons>
<x:Array Type="{x:Type local:MyIconButton}">
<local:MyIconButton Tag="7" ToolTip="{DynamicResource Common.Action.Initialize}" ToolTipService.Placement="Right"
ToolTipService.InitialShowDelay="200" ToolTipService.VerticalOffset="-1"
Click="Reset"
SvgIcon="lucide/rotate-ccw"
LogoScale="0.9" />
</x:Array>
</local:MyListItem.Buttons>
</local:MyListItem>
<TextBlock Text="{DynamicResource Setup.Left.Category.Launcher}" Margin="13,5,5,3" Opacity="0.6" FontSize="12" x:Name="TextLauncherCategory" />
<local:MyListItem x:Name="ItemUI" IsScaleAnimationEnabled="False" Tag="1" MinPaddingRight="35" Height="36"
Check="PageCheck"
VerticalAlignment="Top" Title="{DynamicResource Setup.Left.Item.Ui}"
SvgIcon="lucide/palette"
Type="RadioBox">
<local:MyListItem.Buttons>
<x:Array Type="{x:Type local:MyIconButton}">
<local:MyIconButton Tag="1" ToolTip="{DynamicResource Common.Action.Initialize}" ToolTipService.Placement="Right"
ToolTipService.InitialShowDelay="200" ToolTipService.VerticalOffset="-1"
Click="Reset"
SvgIcon="lucide/rotate-ccw"
LogoScale="0.9" />
</x:Array>
</local:MyListItem.Buttons>
</local:MyListItem>
<local:MyListItem x:Name="ItemLauncherLanguage"
IsScaleAnimationEnabled="False"
Tag="11" MinPaddingRight="35"
Check="PageCheck"
Height="36" VerticalAlignment="Top"
Title="{DynamicResource Setup.Language.Title}"
Type="RadioBox"
LogoScale="0.95"
SvgIcon="lucide/earth">
<local:MyListItem.Buttons>
<x:Array Type="{x:Type local:MyIconButton}">
<local:MyIconButton Tag="11" ToolTip="{DynamicResource Common.Action.Initialize}" ToolTipService.Placement="Right"
ToolTipService.InitialShowDelay="200" ToolTipService.VerticalOffset="-1"
Click="Reset"
SvgIcon="lucide/rotate-ccw"
LogoScale="0.9" />
</x:Array>
</local:MyListItem.Buttons>
</local:MyListItem>
<local:MyListItem x:Name="ItemLauncherMisc" IsScaleAnimationEnabled="False" Tag="10" MinPaddingRight="35"
Check="PageCheck"
Height="36" VerticalAlignment="Top" Title="{DynamicResource Setup.Left.Item.Misc}" Type="RadioBox"
LogoScale="0.95"
SvgIcon="lucide/monitor-cog">
<local:MyListItem.Buttons>
<x:Array Type="{x:Type local:MyIconButton}">
<local:MyIconButton Tag="10" ToolTip="{DynamicResource Common.Action.Initialize}" ToolTipService.Placement="Right"
ToolTipService.InitialShowDelay="200" ToolTipService.VerticalOffset="-1"
Click="Reset"
SvgIcon="lucide/rotate-ccw"
LogoScale="0.9" />
</x:Array>
</local:MyListItem.Buttons>
</local:MyListItem>
<TextBlock Text="{DynamicResource Setup.Left.Category.About}" Margin="13,5,5,3" Opacity="0.6" FontSize="12" x:Name="TextAboutCategory" />
<local:MyListItem x:Name="ItemAbout" IsScaleAnimationEnabled="False" Tag="4" MinPaddingRight="35"
Check="PageCheck"
Height="36" VerticalAlignment="Top" Title="{DynamicResource Setup.Left.Item.About}" Type="RadioBox"
SvgIcon="lucide/info" />
<local:MyListItem x:Name="ItemUpdate" IsScaleAnimationEnabled="False" Tag="8" MinPaddingRight="35"
Check="PageCheck"
Height="36" VerticalAlignment="Top" Title="{DynamicResource Setup.Left.Item.Update}" Type="RadioBox"
SvgIcon="lucide/refresh-cw" />
<local:MyListItem x:Name="ItemFeedback" IsScaleAnimationEnabled="False" Type="RadioBox" Tag="6"
Check="PageCheck"
MinPaddingRight="35" Height="36" VerticalAlignment="Top" Title="{DynamicResource Setup.Left.Item.Feedback}"
LogoScale="0.9"
SvgIcon="lucide/message-circle">
<local:MyListItem.Buttons>
<x:Array Type="{x:Type local:MyIconButton}">
<local:MyIconButton Tag="6" ToolTip="{DynamicResource Common.Action.Refresh}" ToolTipService.Placement="Right"
ToolTipService.InitialShowDelay="200" ToolTipService.VerticalOffset="-1"
Click="Refresh" LogoScale="0.85"
SvgIcon="lucide/refresh-cw" />
</x:Array>
</local:MyListItem.Buttons>
</local:MyListItem>
<local:MyListItem x:Name="ItemLog" IsScaleAnimationEnabled="False" Tag="5" MinPaddingRight="35" Height="36"
Check="PageCheck"
VerticalAlignment="Top" Title="{DynamicResource Setup.Left.Item.Log}" Type="RadioBox" LogoScale="0.9"
SvgIcon="lucide/scroll-text" />
</StackPanel>
</local:MyScrollViewer>
</local:MyPageLeft>
@@ -0,0 +1,385 @@
using System.Windows;
using System.Windows.Controls;
using PCL.Core.App;
using PCL.Core.App.Localization;
namespace PCL;
public partial class PageSetupLeft
{
private bool isLoad;
private bool isPageSwitched; // 如果在 Loaded 前切换到其他页面,会导致触发 Loaded 时再次切换一次
private void PageSetupLeft_Loaded(object sender, RoutedEventArgs e)
{
// 是否处于隐藏的子页面
var isHiddenPage = false;
var hide = Config.Preference.Hide;
if (ItemLaunch.Checked && hide.SetupLaunch) isHiddenPage = true;
if (ItemJava.Checked && hide.SetupJava) isHiddenPage = true;
if (ItemGameManage.Checked && hide.SetupGameManage) isHiddenPage = true;
if (ItemGameLink.Checked && hide.SetupGameLink) isHiddenPage = true;
if (ItemUI.Checked && hide.SetupUi) isHiddenPage = true;
if (ItemLauncherLanguage.Checked && hide.SetupLauncherLanguage) isHiddenPage = true;
if (ItemLauncherMisc.Checked && hide.SetupLauncherMisc) isHiddenPage = true;
if (ItemAbout.Checked && hide.SetupAbout) isHiddenPage = true;
if (ItemUpdate.Checked && hide.SetupUpdate) isHiddenPage = true;
if (ItemFeedback.Checked && hide.SetupFeedback) isHiddenPage = true;
if (ItemLog.Checked && hide.SetupLog) isHiddenPage = true;
if (PageSetupUI.HiddenForceShow)
isHiddenPage = false;
// 若页面错误,或尚未加载,则继续
if (isLoad && !isHiddenPage)
return;
isLoad = true;
// 刷新子页面隐藏情况
PageSetupUI.HiddenRefresh();
// 选择第一个未被禁用的子页面
if (isPageSwitched)
return;
var hideCfg = Config.Preference.Hide;
if (!hideCfg.SetupLaunch)
ItemLaunch.SetChecked(true, false, false);
else if (!hideCfg.SetupJava)
ItemJava.SetChecked(true, false, false);
else if (!hideCfg.SetupGameManage)
ItemGameManage.SetChecked(true, false, false);
else if (!hideCfg.SetupGameLink)
ItemGameLink.SetChecked(true, false, false);
else if (!hideCfg.SetupUi)
ItemUI.SetChecked(true, false, false);
else if (!hideCfg.SetupLauncherLanguage)
ItemLauncherLanguage.SetChecked(true, false, false);
else if (!hideCfg.SetupLauncherMisc)
ItemLauncherMisc.SetChecked(true, false, false);
else if (!hideCfg.SetupAbout)
ItemAbout.SetChecked(true, false, false);
else if (!hideCfg.SetupUpdate)
ItemUpdate.SetChecked(true, false, false);
else if (!hideCfg.SetupFeedback)
ItemFeedback.SetChecked(true, false, false);
else if (!hideCfg.SetupLog)
ItemLog.SetChecked(true, false, false);
else
ItemLaunch.SetChecked(true, false, false);
}
private void PageOtherLeft_Unloaded(object sender, RoutedEventArgs e)
{
isPageSwitched = false;
}
public void Reset(object sender, EventArgs e)
{
switch (ModBase.Val(((MyIconButton)sender).Tag))
{
case (double)FormMain.PageSubType.SetupLaunch:
{
if (ModMain.MyMsgBox(Lang.Text("Setup.Left.Reset.Launch.Message"), Lang.Text("Setup.Left.Reset.Title"), button2: Lang.Text("Common.Action.Cancel"), isWarn: true) == 1)
{
if (ModMain.frmSetupLaunch is null)
ModMain.frmSetupLaunch = new PageSetupLaunch();
ModMain.frmSetupLaunch.Reset();
ItemLaunch.Checked = true;
}
break;
}
case (double)FormMain.PageSubType.SetupUI:
{
if (ModMain.MyMsgBox(Lang.Text("Setup.Left.Reset.Ui.Message"),
Lang.Text("Setup.Left.Reset.Title"), button2: Lang.Text("Common.Action.Cancel"), isWarn: true) == 1)
{
if (ModMain.frmSetupUI is null)
ModMain.frmSetupUI = new PageSetupUI();
ModMain.frmSetupUI.Reset();
ItemUI.Checked = true;
}
break;
}
case (double)FormMain.PageSubType.SetupGameManage:
{
if (ModMain.MyMsgBox(Lang.Text("Setup.Left.Reset.GameManage.Message"), Lang.Text("Setup.Left.Reset.Title"), button2: Lang.Text("Common.Action.Cancel"), isWarn: true) == 1)
{
if (ModMain.frmSetupGameManage is null)
ModMain.frmSetupGameManage = new PageSetupGameManage();
ModMain.frmSetupGameManage.Reset();
ItemGameManage.Checked = true;
}
break;
}
case (double)FormMain.PageSubType.SetupGameLink:
{
if (ModMain.MyMsgBox(Lang.Text("Setup.Left.Reset.GameLink.Message"), Lang.Text("Setup.Left.Reset.Title"), button2: Lang.Text("Common.Action.Cancel"), isWarn: true) == 1)
{
if (ModMain.frmSetupGameLink is null)
ModMain.frmSetupGameLink = new PageSetupGameLink();
ModMain.frmSetupGameLink.Reset();
ItemGameLink.Checked = true;
}
break;
}
case (double)FormMain.PageSubType.SetupLauncherLanguage:
{
if (ModMain.MyMsgBox(Lang.Text("Setup.Left.Reset.Language.Message"), Lang.Text("Setup.Left.Reset.Title"), button2: Lang.Text("Common.Action.Cancel"), isWarn: true) == 1)
{
if (ModMain.frmSetupLauncherLanguage is null)
ModMain.frmSetupLauncherLanguage = new PageSetupLauncherLanguage();
ModMain.frmSetupLauncherLanguage.Reset();
ItemLauncherLanguage.Checked = true;
}
break;
}
case (double)FormMain.PageSubType.SetupLauncherMisc:
{
if (ModMain.MyMsgBox(Lang.Text("Setup.Left.Reset.Misc.Message"), Lang.Text("Setup.Left.Reset.Title"), button2: Lang.Text("Common.Action.Cancel"), isWarn: true) == 1)
{
if (ModMain.frmSetupLauncherMisc is null)
ModMain.frmSetupLauncherMisc = new PageSetupLauncherMisc();
ModMain.frmSetupLauncherMisc.Reset();
ItemLauncherMisc.Checked = true;
}
break;
}
}
}
public static void TryFeedback() // Handles ItemFeedback.Click
{
ModBase.RunInNewThread(() =>
{
if (!ModBase.CanFeedback(true))
return;
switch (ModMain.MyMsgBox(Lang.Text("Setup.Left.Feedback.Message"), Lang.Text("Setup.Left.Feedback.Title"),
Lang.Text("Setup.Left.Feedback.SubmitNew"), Lang.Text("Setup.Left.Feedback.ViewList"), Lang.Text("Common.Action.Cancel")))
{
case 1:
{
ModBase.Feedback();
break;
}
case 2:
{
ModBase.OpenWebsite("https://github.com/PCL-Community/PCL2-CE/issues/");
break;
}
}
});
}
public void Refresh(object sender, EventArgs e) // 由边栏按钮匿名调用
{
switch (ModBase.Val(((MyIconButton)sender).Tag))
{
case (double)FormMain.PageSubType.SetupFeedback:
{
if (ModMain.frmSetupFeedback is not null) ModMain.frmSetupFeedback.Loader.Start(isForceRestart: true);
ItemFeedback.Checked = true;
break;
}
case (double)FormMain.PageSubType.SetupJava:
{
if (ModMain.frmSetupJava is not null) ModMain.frmSetupJava.loader.Start(isForceRestart: true);
ItemJava.Checked = true;
break;
}
}
HintService.Hint(Lang.Text("Setup.Left.Refreshing"), log: false);
}
#region
/// <summary>
/// 当前页面的编号。从左往右从 0 开始计算。
/// </summary>
public FormMain.PageSubType pageID;
public PageSetupLeft()
{
InitializeComponent();
// 选择第一个未被禁用的子页面
var hideCfg = Config.Preference.Hide;
if (!hideCfg.SetupLaunch)
pageID = FormMain.PageSubType.SetupLaunch;
else if (!hideCfg.SetupJava)
pageID = FormMain.PageSubType.SetupJava;
else if (!hideCfg.SetupGameManage)
pageID = FormMain.PageSubType.SetupGameManage;
else if (!hideCfg.SetupGameLink)
pageID = FormMain.PageSubType.SetupGameLink;
else if (!hideCfg.SetupUi)
pageID = FormMain.PageSubType.SetupUI;
else if (!hideCfg.SetupLauncherLanguage)
pageID = FormMain.PageSubType.SetupLauncherLanguage;
else if (!hideCfg.SetupLauncherMisc)
pageID = FormMain.PageSubType.SetupLauncherMisc;
else if (!hideCfg.SetupAbout)
pageID = FormMain.PageSubType.SetupAbout;
else if (!hideCfg.SetupUpdate)
pageID = FormMain.PageSubType.SetupUpdate;
else if (!hideCfg.SetupFeedback)
pageID = FormMain.PageSubType.SetupFeedback;
else if (!hideCfg.SetupLog)
pageID = FormMain.PageSubType.SetupLog;
else
pageID = FormMain.PageSubType.SetupLaunch;
AnimatedControl = PanItem;
Loaded += PageSetupLeft_Loaded;
Unloaded += PageOtherLeft_Unloaded;
}
/// <summary>
/// 勾选事件改变页面。
/// </summary>
private void PageCheck(object senderRaw, ModBase.RouteEventArgs e)
{
var sender = (MyListItem)senderRaw;
// 尚未初始化控件属性时,sender.Tag 为 Nothing,会跳过切换,且由于 PageID 默认为 0 而切换到第一个页面
// 若使用 IsLoaded,则会导致模拟点击不被执行(模拟点击切换页面时,控件的 IsLoaded 为 False
if (sender.Tag is not null)
PageChange((FormMain.PageSubType)ModBase.Val(sender.Tag));
}
/// <summary>
/// 获取当前导航指定的右页面。
/// </summary>
public object PageGet(FormMain.PageSubType? id = null)
{
var targetID = id ?? pageID;
switch (id)
{
case FormMain.PageSubType.SetupLaunch:
{
if (ModMain.frmSetupLaunch is null)
ModMain.frmSetupLaunch = new PageSetupLaunch();
return ModMain.frmSetupLaunch;
}
case FormMain.PageSubType.SetupUI:
{
if (ModMain.frmSetupUI is null)
ModMain.frmSetupUI = new PageSetupUI();
return ModMain.frmSetupUI;
}
case FormMain.PageSubType.SetupGameManage:
{
if (ModMain.frmSetupGameManage is null)
ModMain.frmSetupGameManage = new PageSetupGameManage();
return ModMain.frmSetupGameManage;
}
case FormMain.PageSubType.SetupUpdate:
{
if (ModMain.frmSetupUpdate is null)
ModMain.frmSetupUpdate = new PageSetupUpdate();
return ModMain.frmSetupUpdate;
}
case FormMain.PageSubType.SetupAbout:
{
if (ModMain.frmSetupAbout is null)
ModMain.frmSetupAbout = new PageSetupAbout();
return ModMain.frmSetupAbout;
}
case FormMain.PageSubType.SetupLog:
{
if (ModMain.frmSetupLog is null)
ModMain.frmSetupLog = new PageSetupLog();
return ModMain.frmSetupLog;
}
case FormMain.PageSubType.SetupFeedback:
{
if (ModMain.frmSetupFeedback is null)
ModMain.frmSetupFeedback = new PageSetupFeedback();
return ModMain.frmSetupFeedback;
}
case FormMain.PageSubType.SetupGameLink:
{
if (ModMain.frmSetupGameLink is null)
ModMain.frmSetupGameLink = new PageSetupGameLink();
return ModMain.frmSetupGameLink;
}
case FormMain.PageSubType.SetupLauncherLanguage:
{
if (ModMain.frmSetupLauncherLanguage is null)
ModMain.frmSetupLauncherLanguage = new PageSetupLauncherLanguage();
return ModMain.frmSetupLauncherLanguage;
}
case FormMain.PageSubType.SetupLauncherMisc:
{
if (ModMain.frmSetupLauncherMisc is null)
ModMain.frmSetupLauncherMisc = new PageSetupLauncherMisc();
return ModMain.frmSetupLauncherMisc;
}
case FormMain.PageSubType.SetupJava:
{
if (ModMain.frmSetupJava is null)
ModMain.frmSetupJava = new PageSetupJava();
return ModMain.frmSetupJava;
}
default:
{
throw new Exception("未知的设置子页面种类:" + (int)id);
}
}
}
/// <summary>
/// 切换现有页面。
/// </summary>
public void PageChange(FormMain.PageSubType id)
{
if (pageID == id)
return;
ModAnimation.AniControlEnabled += 1;
isPageSwitched = true;
try
{
PageChangeRun((MyPageRight)PageGet(id));
pageID = id;
}
catch (Exception ex)
{
ModBase.Log(
ex,
$"切换分页面失败(ID {(int)id}",
ModBase.LogLevel.Feedback,
userSummary: Lang.Text("Setup.Error.OperationFailed"));
}
finally
{
ModAnimation.AniControlEnabled -= 1;
}
}
private static void PageChangeRun(MyPageRight target)
{
ModAnimation.AniStop("FrmMain PageChangeRight"); // 停止主页面的右页面切换动画,防止它与本动画一起触发多次 PageOnEnter
if (target.Parent is not null)
target.SetValue(ContentPresenter.ContentProperty, null);
ModMain.frmMain.pageRight = target;
((MyPageRight)ModMain.frmMain.PanMainRight.Child).PageOnExit();
ModAnimation.AniStart(new[]
{
ModAnimation.AaCode(() =>
{
((MyPageRight)ModMain.frmMain.PanMainRight.Child).PageOnForceExit();
ModMain.frmMain.PanMainRight.Child = ModMain.frmMain.pageRight;
ModMain.frmMain.pageRight.Opacity = 0d;
}, 130),
ModAnimation.AaCode(() =>
{
// 延迟触发页面通用动画,以使得在 Loaded 事件中加载的控件得以处理
ModMain.frmMain.pageRight.Opacity = 1d;
ModMain.frmMain.pageRight.PageOnEnter();
}, 30, true)
}, "PageLeft PageChange");
}
#endregion
}
@@ -0,0 +1,29 @@
<local:MyPageRight x:Class="PCL.PageSetupLog"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:local="clr-namespace:PCL"
mc:Ignorable="d"
d:DesignHeight="450" d:DesignWidth="800"
PanScroll="{Binding ElementName=PanBack}" RenderOptions.BitmapScalingMode="LowQuality">
<local:MyScrollViewer VerticalScrollBarVisibility="Auto" HorizontalScrollBarVisibility="Disabled" x:Name="PanBack">
<DockPanel>
<local:MyCard DockPanel.Dock="Top" Title="{DynamicResource Setup.Log.Operations}" Margin="25,25,25,5">
<WrapPanel ItemHeight="35" Margin="25,40,20,20">
<local:MyButton MinWidth="100" Text="{DynamicResource Setup.Log.Export}" ColorType="Highlight" Margin="0,0,15,0"
Click="ButtonExport_OnClick" />
<local:MyButton MinWidth="120" Text="{DynamicResource Setup.Log.ExportAll}" ColorType="Normal" Margin="0,0,15,0"
Click="ButtonExportAll_OnClick" />
<local:MyButton MinWidth="120" Text="{DynamicResource Setup.Log.OpenDirectory}" ColorType="Normal" Margin="0,0,15,0"
Click="ButtonOpenDir_OnClick" />
<local:MyButton MinWidth="120" Text="{DynamicResource Setup.Log.ClearHistory}" ColorType="Red" Click="ButtonClean_OnClick" />
</WrapPanel>
</local:MyCard>
<local:MyCard Title="{DynamicResource Setup.Log.AllLogs}" Margin="25,10,25,25" x:Name="PanContent">
<StackPanel Name="PanList" Orientation="Vertical" Margin="20,36,18,18" />
</local:MyCard>
</DockPanel>
</local:MyScrollViewer>
</local:MyPageRight>
@@ -0,0 +1,163 @@
using System.Globalization;
using System.IO;
using System.IO.Compression;
using System.Windows;
using System.Windows.Input;
using PCL.Core.App;
using PCL.Core.Logging;
using PCL.Core.UI;
using PCL.Core.Utils;
using PCL.Core.Utils.Exts;
using PCL.Core.App.Localization;
namespace PCL;
public partial class PageSetupLog
{
public PageSetupLog()
{
InitializeComponent();
Loaded += PageOtherLog_Loaded;
}
private static string LogDirectory => LogService.Logger.Configuration.StoreFolder;
private static List<string> CurrentLogs
{
get
{
var logs = LogService.Logger.CurrentLogFiles;
return logs.Select(item => Path.GetFullPath(item)).ToList();
}
}
private void PageOtherLog_Loaded(object sender, RoutedEventArgs e)
{
// 重复加载部分
PanBack.ScrollToHome();
LoadList();
// 非重复加载部分
if (IsLoaded)
return;
}
public void LoadList()
{
PanList.Children.Clear();
var current = CurrentLogs;
var logFiles = Directory.GetFiles(LogDirectory).OrderByDescending(f => File.GetLastWriteTime(f)).ToArray();
foreach (var item in logFiles)
{
var fullPath = Path.GetFullPath(item);
var title = Path.GetFileName(item);
if (title.StartsWith("Launch"))
{
title = title.Substring(7, title.Length - 11);
DateTime dt;
var r = DateTime.TryParseExact(title, "yyyy-M-d-HHmmssfff", CultureInfo.InvariantCulture,
DateTimeStyles.None, out dt);
if (r)
title = Lang.Date(dt, "G");
if (current.Any(log => log.Equals(fullPath)))
title = Lang.Text("Setup.Log.CurrentSuffix", title);
}
else if (title.StartsWith("LastPending"))
{
title = title.Substring(11, title.Length - 15);
if (title.Length > 1)
title = Lang.Text("Setup.Log.TempStored", title.Substring(1));
else
title = Lang.Text("Setup.Log.TempUnoutput");
}
var ele = new MyListItem
{
Type = MyListItem.CheckType.Clickable,
Title = title,
Info = fullPath,
Tag = fullPath
};
ele.Click += (sender, e) =>
{
var s = (MyListItem)sender;
var file = (string)s.Tag;
Basics.OpenPath(file);
};
PanList.Children.Add(ele);
}
}
private static void ExportLog(IEnumerable<string> sourceFiles)
{
var filter = Lang.Text("Setup.Log.ExportFilter");
var desktopPath = Environment.GetFolderPath(Environment.SpecialFolder.Desktop);
var baseName = "PCL_CE_Logs_" + DateTime.Now.ToString("yyyyMMddHHmmss", CultureInfo.InvariantCulture);
var tempDirName = baseName + ".tmp";
var fileName = baseName + ".zip";
var selectedPath = SystemDialogs.SelectSaveFile(Lang.Text("Setup.Log.ExportSaveTitle"), fileName, filter, desktopPath);
if (string.IsNullOrEmpty(selectedPath))
return;
try
{
Directory.CreateDirectory(tempDirName);
if (File.Exists(selectedPath))
File.Delete(selectedPath);
using (var zip = ZipFile.Open(selectedPath, ZipArchiveMode.Create))
{
foreach (var item in sourceFiles)
{
var itemFileName = Path.GetFileName(item);
var tempPath = Path.Combine(tempDirName, itemFileName);
File.Copy(item, tempPath);
zip.CreateEntryFromFile(tempPath, itemFileName, CompressionLevel.Fastest);
File.Delete(tempPath);
}
}
HintService.Hint(Lang.Text("Setup.Log.ExportSuccess"), HintType.Success);
}
catch (Exception ex)
{
ModBase.Log(
ex,
Lang.Text("Setup.Log.ExportFailed"),
ModBase.LogLevel.Hint,
userSummary: Lang.Text("Setup.Log.ExportFailed"));
}
finally
{
if (Directory.Exists(tempDirName))
Directory.Delete(tempDirName);
}
}
private void ButtonOpenDir_OnClick(object sender, MouseButtonEventArgs e)
{
Basics.OpenPath(LogDirectory);
}
private void ButtonClean_OnClick(object sender, MouseButtonEventArgs e)
{
var r = ModMain.MyMsgBox(Lang.Text("Setup.Log.Clear.Confirm.Message"), Lang.Text("Setup.Log.Clear.Confirm.Title"), Lang.Text("Common.Action.Confirm"), Lang.Text("Common.Action.Cancel"), isWarn: true);
if (r != 1)
return;
var currentSet = new HashSet<string>(CurrentLogs);
foreach (var item in Directory.GetFiles(LogDirectory))
if (!currentSet.Contains(item))
File.Delete(item);
HintService.Hint(Lang.Text("Setup.Log.Clear.Success"), HintType.Success);
LoadList();
}
private void ButtonExportAll_OnClick(object sender, MouseButtonEventArgs e)
{
ExportLog(Directory.GetFiles(LogDirectory));
}
private void ButtonExport_OnClick(object sender, MouseButtonEventArgs e)
{
var pendingLogs = Array.FindAll(Directory.GetFiles(LogDirectory),
s => s.IsMatch(RegexPatterns.LastPendingLogPath));
ExportLog(CurrentLogs.Concat(pendingLogs));
}
}
@@ -0,0 +1,482 @@
<local:MyPageRight
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:PCL"
xmlns:val="https://ce.pclc.cc/core/utils/validate"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d" x:Class="PCL.PageSetupUI"
DataContext="{Binding RelativeSource={RelativeSource Self}}"
PanScroll="{Binding ElementName=PanBack}">
<local:MyScrollViewer VerticalScrollBarVisibility="Auto" HorizontalScrollBarVisibility="Disabled" x:Name="PanBack">
<StackPanel x:Name="PanMain" Margin="25,10">
<local:MyCard Margin="0,15" Title="{DynamicResource Setup.Ui.Basic.Title}" x:Name="CardLauncher">
<Grid Margin="25,40,25,10">
<StackPanel>
<Grid Margin="0,0,0,6">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" SharedSizeGroup="Name1" />
<ColumnDefinition Width="1*" />
<ColumnDefinition Width="30" />
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="1*" />
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<TextBlock VerticalAlignment="Center" HorizontalAlignment="Left" Text="{DynamicResource Setup.Ui.Basic.Opacity}"
Margin="0,0,20,0" />
<local:MySlider Grid.ColumnSpan="5" x:Name="SliderLauncherOpacity"
Tag="UiLauncherTransparent" MaxValue="600" ValueByKey="10" Grid.Column="1"
Change="SliderChange" />
</Grid>
<Border Background="{DynamicResource ColorBrushToolTip}" Margin="0,5,0,12" CornerRadius="4"
Name="PanLauncherHide" Visibility="Collapsed">
<StackPanel HorizontalAlignment="Center" VerticalAlignment="Center" Margin="20">
<TextBlock Text="{DynamicResource Setup.Ui.Basic.BlueHint}" FontSize="13" Margin="0,0,0,0"
TextWrapping="Wrap" />
<local:MyButton Height="35" x:Name="BtnLauncherDonate" MinWidth="140" Text="{DynamicResource Setup.Ui.Basic.GetSnapshot}"
Padding="13,0" HorizontalAlignment="Center" Margin="0,9,0,0"
ColorType="Highlight" Click="BtnLauncherDonate_Click" />
</StackPanel>
</Border>
<Grid Height="28" Margin="0,0,0,7">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" SharedSizeGroup="Name1" />
<ColumnDefinition />
<ColumnDefinition Width="92" SharedSizeGroup="SubName" />
<ColumnDefinition />
<ColumnDefinition SharedSizeGroup="SubName" />
<ColumnDefinition />
</Grid.ColumnDefinitions>
<TextBlock Grid.Column="0" VerticalAlignment="Center" HorizontalAlignment="Left" Text="{DynamicResource Setup.Ui.Theme.Title}" />
<local:MyComboBox Grid.Column="1" x:Name="ComboDarkMode" Tag="UiDarkMode"
SelectionChanged="ComboChange">
<local:MyComboBoxItem Content="{DynamicResource Setup.Ui.Theme.Light}" />
<local:MyComboBoxItem Content="{DynamicResource Setup.Ui.Theme.Dark}" />
<local:MyComboBoxItem Content="{DynamicResource Setup.Ui.Theme.FollowSystem}" /> <!-- default -->
</local:MyComboBox>
<TextBlock Grid.Column="2" VerticalAlignment="Center" HorizontalAlignment="Center" Text="{DynamicResource Setup.Ui.Theme.LightColor}"/>
<local:MyComboBox Grid.Column="3" x:Name="ComboLightColor" Tag="UiLightColor" ItemsSource="{Binding ThemeColors}" SelectionChanged="ThemeColor_Change"/>
<TextBlock Grid.Column="4" VerticalAlignment="Center" HorizontalAlignment="Center" Text="{DynamicResource Setup.Ui.Theme.DarkColor}"/>
<local:MyComboBox Grid.Column="5" x:Name="ComboDarkColor" Tag="UiDarkColor" ItemsSource="{Binding ThemeColors}" SelectionChanged="ThemeColor_Change"/>
</Grid>
<local:MyCheckBox Text="{DynamicResource Setup.Ui.Basic.ShowLogo}" Margin="-1,0,0,7" Height="22"
x:Name="CheckLauncherLogo" Tag="UiLauncherLogo" Change="CheckBoxChange" />
<local:MyCheckBox Text="{DynamicResource Setup.Ui.Basic.LockWindow}" Margin="-1,0,0,7" Height="22" x:Name="CheckLockWindowSize"
Tag="UiLockWindowSize" Change="CheckBoxChange" />
<local:MyCheckBox Text="{DynamicResource Setup.Ui.Basic.ShowTriviaHint}" Margin="-1,0,0,7" Height="22"
x:Name="CheckShowLaunchingHint" Tag="UiShowLaunchingHint"
Change="CheckBoxChange" />
<StackPanel x:Name="PanelBlur" Margin="0,0,0,10">
<local:MyCheckBox Text="{DynamicResource Setup.Ui.Basic.AdvancedMaterial}" Height="22" x:Name="CheckBlur" Tag="UiBlur"
ToolTip="{DynamicResource Setup.Ui.Basic.AdvancedMaterial.ToolTip}"
Change="CheckBoxChange" />
<Grid x:Name="PanBlurValue" Margin="0,10,0,0">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" SharedSizeGroup="Name1" />
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="Auto" SharedSizeGroup="SubName" />
<ColumnDefinition />
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition />
<RowDefinition Height="10" />
<RowDefinition />
</Grid.RowDefinitions>
<TextBlock Grid.Row="0" Grid.Column="0" VerticalAlignment="Center"
HorizontalAlignment="Left" Text="{DynamicResource Setup.Ui.Basic.BlurRadius}" />
<local:MySlider Grid.Row="0" Grid.Column="1" Grid.ColumnSpan="3"
x:Name="SliderBlurValue" Tag="UiBlurValue" MaxValue="40"
ValueByKey="10" Change="SliderChange"
ToolTip="{DynamicResource Setup.Ui.Basic.BlurRadius.ToolTip}" />
<TextBlock Grid.Row="2" Grid.Column="2" VerticalAlignment="Center"
HorizontalAlignment="Center" Text="{DynamicResource Setup.Ui.Basic.BlurSamplingRate}" />
<local:MySlider Grid.Row="2" Grid.Column="3" x:Name="SliderBlurSamplingRate"
Tag="UiBlurSamplingRate" MaxValue="100" ValueByKey="5"
Change="SliderChange"
ToolTip="{DynamicResource Setup.Ui.Basic.BlurSamplingRate.ToolTip}" />
<TextBlock Grid.Row="2" Grid.Column="0" VerticalAlignment="Center"
HorizontalAlignment="Left" Text="{DynamicResource Setup.Ui.Basic.BlurMethod}" />
<local:MyComboBox Grid.Row="2" Grid.Column="1" x:Name="ComboBlurType" Tag="UiBlurType"
Height="28" MinWidth="100" ToolTip="{DynamicResource Setup.Ui.Basic.BlurMethod.ToolTip}"
SelectionChanged="ComboChange">
<local:MyComboBoxItem Content="{DynamicResource Setup.Ui.Basic.BlurMethod.Gaussian}"
ToolTip="{DynamicResource Setup.Ui.Basic.BlurMethod.Gaussian.ToolTip}" />
<local:MyComboBoxItem Content="{DynamicResource Setup.Ui.Basic.BlurMethod.Box}"
ToolTip="{DynamicResource Setup.Ui.Basic.BlurMethod.Box.ToolTip}" />
</local:MyComboBox>
</Grid>
</StackPanel>
</StackPanel>
</Grid>
</local:MyCard>
<local:MyCard x:Name="CardFont" Margin="0,0,0,15" Title="{DynamicResource Setup.Ui.Font.Title}">
<Grid Margin="25,40,25,15">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="25" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition SharedSizeGroup="FontSelector" Height="30" />
<RowDefinition Height="10" />
<RowDefinition SharedSizeGroup="FontSelector" />
</Grid.RowDefinitions>
<TextBlock Grid.Row="0" Grid.Column="0" VerticalAlignment="Center" Text="{DynamicResource Setup.Ui.Font.Global}" />
<local:FontSelector Grid.Row="0" Grid.Column="2" x:Name="ComboUiFont" Tooltip="{DynamicResource Setup.Ui.Font.Global.ToolTip}"
SelectionChanged="ComboFontChange" />
<TextBlock Grid.Row="2" Grid.Column="0" VerticalAlignment="Center" Text="{DynamicResource Setup.Ui.Font.Motd}" />
<local:FontSelector Grid.Row="2" Grid.Column="2" x:Name="ComboUiMotdFont"
Tooltip="{DynamicResource Setup.Ui.Font.Motd.ToolTip}" SelectionChanged="ComboMotdFontChange" />
</Grid>
</local:MyCard>
<local:MyCard x:Name="CardBackground" Margin="0,0,0,15" Title="{DynamicResource Setup.Ui.Background.TitleDefault}">
<StackPanel Margin="25,40,25,20">
<Grid x:Name="PanBackgroundSuit" Height="28" Margin="0,0,0,10" Visibility="Collapsed">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" SharedSizeGroup="Name" />
<ColumnDefinition />
</Grid.ColumnDefinitions>
<TextBlock VerticalAlignment="Center" HorizontalAlignment="Left" Text="{DynamicResource Setup.Ui.Background.ContentAdapt}"
Margin="0,0,25,0" />
<local:MyComboBox x:Name="ComboBackgroundSuit" Tag="UiBackgroundSuit" Grid.Column="1"
SelectionChanged="ComboChange">
<local:MyComboBoxItem Content="{DynamicResource Setup.Ui.Background.Suit.Smart}" IsSelected="True" ToolTip="{DynamicResource Setup.Ui.Background.Suit.Smart.ToolTip}" />
<local:MyComboBoxItem Content="{DynamicResource Setup.Ui.Background.Suit.Center}" />
<local:MyComboBoxItem Content="{DynamicResource Setup.Ui.Background.Suit.Fit}" ToolTip="{DynamicResource Setup.Ui.Background.Suit.Fit.ToolTip}" />
<local:MyComboBoxItem Content="{DynamicResource Setup.Ui.Background.Suit.Stretch}" ToolTip="{DynamicResource Setup.Ui.Background.Suit.Stretch.ToolTip}" />
<local:MyComboBoxItem Content="{DynamicResource Setup.Ui.Background.Suit.Tile}" />
<local:MyComboBoxItem Content="{DynamicResource Setup.Ui.Background.Suit.TopLeft}" />
<local:MyComboBoxItem Content="{DynamicResource Setup.Ui.Background.Suit.TopRight}" />
<local:MyComboBoxItem Content="{DynamicResource Setup.Ui.Background.Suit.BottomLeft}" />
<local:MyComboBoxItem Content="{DynamicResource Setup.Ui.Background.Suit.BottomRight}" />
</local:MyComboBox>
</Grid>
<Grid x:Name="PanBackgroundOpacity" Height="22" Margin="0,0,0,7" Visibility="Collapsed">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" SharedSizeGroup="Name" />
<ColumnDefinition />
</Grid.ColumnDefinitions>
<TextBlock VerticalAlignment="Center" HorizontalAlignment="Left" Text="{DynamicResource Setup.Ui.Basic.Opacity2}" Margin="0,0,25,0" />
<local:MySlider x:Name="SliderBackgroundOpacity" Tag="UiBackgroundOpacity" MaxValue="1000"
ValueByKey="10" Grid.Column="1" Change="SliderChange" />
</Grid>
<Grid x:Name="PanBackgroundBlur" Height="22" Margin="0,0,0,10" Visibility="Collapsed">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" SharedSizeGroup="Name" />
<ColumnDefinition />
</Grid.ColumnDefinitions>
<TextBlock VerticalAlignment="Center" HorizontalAlignment="Left" Text="{DynamicResource Setup.Ui.Background.Blur}" Margin="0,0,25,0" />
<local:MySlider x:Name="SliderBackgroundBlur" Tag="UiBackgroundBlur" MaxValue="40"
Grid.Column="1" Change="SliderChange"
ToolTip="{DynamicResource Setup.Ui.Background.Blur.ToolTip}" />
</Grid>
<local:MyCheckBox Text="{DynamicResource Setup.Ui.Background.PauseVideo}" Margin="-1,0,0,8" Height="22"
x:Name="CheckAutoPauseVideo" Tag="UiAutoPauseVideo" Change="CheckBoxChange"
ToolTip="{DynamicResource Setup.Ui.Background.PauseVideo.ToolTip}" IsEnabled="True" />
<local:MyCheckBox Text="{DynamicResource Setup.Ui.Background.ColorOverlay}" Margin="-1,0,0,8" Height="22" x:Name="CheckBackgroundColorful"
Tag="UiBackgroundColorful" Change="CheckBoxChange" />
<Grid Height="35" Margin="0,2,0,0">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" SharedSizeGroup="Button" />
<ColumnDefinition Width="Auto" SharedSizeGroup="Button" />
<ColumnDefinition Width="Auto" SharedSizeGroup="Button" />
</Grid.ColumnDefinitions>
<local:MyButton x:Name="BtnBackgroundOpen" MinWidth="140" Text="{DynamicResource Common.Action.OpenFolder}" Padding="13,0"
Margin="0,0,20,0" Click="BtnUIBgOpen_Click"
ToolTip="{DynamicResource Setup.Ui.Background.OpenFolder.ToolTip}" />
<local:MyButton x:Name="BtnBackgroundRefresh" MinWidth="140" Text="{DynamicResource Setup.Ui.Background.Refresh}" Padding="13,0"
Margin="0,0,20,0" Click="BtnBackgroundRefresh_Click"
ToolTip="{DynamicResource Setup.Ui.Background.Refresh.ToolTip}"
Grid.Column="1" />
<local:MyButton x:Name="BtnBackgroundClear" MinWidth="140" Text="{DynamicResource Setup.Ui.Background.Clear}" Visibility="Collapsed"
Padding="13,0" Margin="0,0,20,0" ColorType="Red"
Click="BtnBackgroundClear_Click" Grid.Column="2" />
</Grid>
</StackPanel>
</local:MyCard>
<local:MyCard x:Name="CardMusic" Margin="0,0,0,15" Title="{DynamicResource Setup.Ui.Music.Title}">
<StackPanel Margin="25,42,25,20">
<Grid x:Name="PanMusicVolume" Visibility="Collapsed" Height="22" Margin="0,0,0,10">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" SharedSizeGroup="Name" />
<ColumnDefinition />
</Grid.ColumnDefinitions>
<TextBlock VerticalAlignment="Center" HorizontalAlignment="Left" Text="{DynamicResource Setup.Ui.Music.Volume}" Margin="0,0,25,0" />
<local:MySlider x:Name="SliderMusicVolume" Tag="UiMusicVolume" MaxValue="1000" ValueByKey="10"
Grid.Column="1" Change="SliderChange" />
</Grid>
<StackPanel x:Name="PanMusicDetail" Visibility="Collapsed" Margin="-1,0,0,3">
<local:MyCheckBox Text="{DynamicResource Setup.Ui.Music.Shuffle}" Margin="0,0,0,5" Height="22" x:Name="CheckMusicRandom"
Tag="UiMusicRandom" Change="CheckBoxChange" />
<local:MyCheckBox Text="{DynamicResource Setup.Ui.Music.AutoStart}" Margin="0,0,0,5" Height="22" x:Name="CheckMusicAuto"
Tag="UiMusicAuto" Change="CheckBoxChange" />
<local:MyCheckBox Text="{DynamicResource Setup.Ui.Music.StartInGame}" Margin="0,0,0,5" Height="22"
x:Name="CheckMusicStart" Tag="UiMusicStart" Change="CheckMusicStart_OnChange" />
<local:MyCheckBox Text="{DynamicResource Setup.Ui.Music.StopInGame}" Margin="0,0,0,5" Height="22"
x:Name="CheckMusicStop" Tag="UiMusicStop" Change="CheckMusicStop_OnChange" />
<local:MyCheckBox Text="{DynamicResource Setup.Ui.Music.Smtc}" Margin="0,0,0,5" Height="22"
x:Name="CheckMusicSMTC" Tag="UiMusicSMTC" Change="CheckBoxChange"
ToolTip="{DynamicResource Setup.Ui.Music.Smtc.ToolTip}" />
</StackPanel>
<Grid Height="35">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" SharedSizeGroup="Button" />
<ColumnDefinition Width="Auto" SharedSizeGroup="Button" />
<ColumnDefinition Width="Auto" SharedSizeGroup="Button" />
</Grid.ColumnDefinitions>
<local:MyButton x:Name="BtnMusicOpen" Text="{DynamicResource Common.Action.OpenFolder}" MinWidth="140" Padding="13,0"
Margin="0,0,20,0" Click="BtnMusicOpen_Click"
ToolTip="{DynamicResource Setup.Ui.Music.OpenFolder.ToolTip}" />
<local:MyButton x:Name="BtnMusicRefresh" Text="{DynamicResource Setup.Ui.Music.Refresh}" MinWidth="140" Padding="13,0"
Margin="0,0,20,0" Click="BtnMusicRefresh_Click"
ToolTip="{DynamicResource Setup.Ui.Music.Refresh.ToolTip}" Grid.Column="1" />
<local:MyButton x:Name="BtnMusicClear" Text="{DynamicResource Setup.Ui.Music.Clear}" MinWidth="140" Visibility="Collapsed"
Padding="13,0" Margin="0,0,20,0" ColorType="Red" Click="BtnMusicClear_Click"
Grid.Column="2" />
</Grid>
</StackPanel>
</local:MyCard>
<local:MyCard x:Name="CardLogo" Margin="0,0,0,15" Title="{DynamicResource Setup.Ui.Logo.Title}">
<StackPanel Margin="25,40,25,15">
<Grid Margin="-1,0,0,0">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="1*" />
<ColumnDefinition Width="1*" />
<ColumnDefinition Width="1*" />
<ColumnDefinition Width="1*" />
<ColumnDefinition Width="0.2*" />
</Grid.ColumnDefinitions>
<local:MyRadioBox Text="{DynamicResource Setup.Ui.Logo.None}" x:Name="RadioLogoType0" Height="22" Tag="UiLogoType/0"
Grid.Column="0" Check="RadioBoxChange" />
<local:MyRadioBox Text="{DynamicResource Common.Option.Default}" x:Name="RadioLogoType1" Height="22" Tag="UiLogoType/1"
Grid.Column="1" Check="RadioBoxChange" />
<local:MyRadioBox Text="{DynamicResource Setup.Ui.Logo.Text}" x:Name="RadioLogoType2" Height="22" Tag="UiLogoType/2"
Grid.Column="2" Check="RadioBoxChange" />
<local:MyRadioBox Text="{DynamicResource Setup.Ui.Logo.Image}" x:Name="RadioLogoType3" Height="22" Tag="UiLogoType/3"
Grid.Column="3" Check="RadioBoxChange" PreviewCheck="RadioLogoType3_Check" />
</Grid>
<local:MyCheckBox Text="{DynamicResource Setup.Ui.Logo.LeftAlign}" Margin="-1,8,0,3" Height="22" x:Name="CheckLogoLeft"
Tag="UiLogoLeft" Visibility="Collapsed" Change="CheckBoxChange" />
<Grid x:Name="PanLogoText" Margin="0,14,0,5" Visibility="Collapsed">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" SharedSizeGroup="Name" />
<ColumnDefinition />
</Grid.ColumnDefinitions>
<TextBlock VerticalAlignment="Center" HorizontalAlignment="Left" Text="{DynamicResource Setup.Ui.Logo.TextLabel}" Margin="0,0,25,0" />
<local:MyTextBox x:Name="TextLogoText" Tag="UiLogoText" Grid.Column="1" MaxLength="100"
ValidatedTextChanged="TextBoxChange" />
</Grid>
<Grid x:Name="PanLogoChange" Margin="0,14,0,5" Height="35" Visibility="Collapsed">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" SharedSizeGroup="Button" />
<ColumnDefinition Width="Auto" SharedSizeGroup="Button" />
</Grid.ColumnDefinitions>
<local:MyButton x:Name="BtnLogoChange" Text="{DynamicResource Setup.Ui.Logo.ChangeImage}" MinWidth="140" Padding="13,0"
Margin="0,0,20,0" Click="BtnLogoChange_Click" />
<local:MyButton x:Name="BtnLogoDelete" Text="{DynamicResource Setup.Ui.Logo.ClearImage}" MinWidth="140" Padding="13,0"
Margin="0,0,20,0" ColorType="Red" Click="BtnLogoDelete_Click" Grid.Column="1" />
</Grid>
</StackPanel>
</local:MyCard>
<local:MyCard Margin="0,0,0,15" Title="{DynamicResource Setup.Ui.Homepage.Title}" x:Name="CardCustom">
<StackPanel Margin="25,40,25,15">
<Grid Margin="-1,0,0,0">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="1*" />
<ColumnDefinition Width="1*" />
<ColumnDefinition Width="1*" />
<ColumnDefinition Width="1*" />
<ColumnDefinition Width="0.2*" />
</Grid.ColumnDefinitions>
<local:MyRadioBox Text="{DynamicResource Setup.Ui.Homepage.Blank}" x:Name="RadioCustomType0" Height="22" Tag="UiCustomType/0"
Grid.Column="0" Check="RadioBoxChange" />
<local:MyRadioBox Text="{DynamicResource Setup.Ui.Homepage.Preset}" x:Name="RadioCustomType3" Height="22" Tag="UiCustomType/3"
Grid.Column="1" Check="RadioBoxChange" />
<local:MyRadioBox Text="{DynamicResource Setup.Ui.Homepage.LocalFile}" x:Name="RadioCustomType1" Height="22" Tag="UiCustomType/1"
Grid.Column="2" Check="RadioBoxChange" />
<local:MyRadioBox Text="{DynamicResource Setup.Ui.Homepage.NetUpdate}" x:Name="RadioCustomType2" Height="22" Tag="UiCustomType/2"
Grid.Column="3" Check="RadioBoxChange" />
</Grid>
<local:MyHint Margin="0,15,0,-4" Text="{DynamicResource Setup.Ui.Homepage.HintReferToModSetup}" Theme="Blue" x:Name="HintCustom" />
<local:MyHint Margin="0,15,0,6" Text="{DynamicResource Setup.Ui.Homepage.NetWarning}" Theme="Yellow"
x:Name="HintCustomWarn"
CanClose="True" RelativeSetup="HintCustomWarn" />
<Grid Height="35" x:Name="PanCustomLocal" Visibility="Collapsed" Margin="0,10,0,5">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" SharedSizeGroup="Button" />
<ColumnDefinition Width="Auto" SharedSizeGroup="Button" />
<ColumnDefinition Width="Auto" SharedSizeGroup="Button" />
</Grid.ColumnDefinitions>
<local:MyButton x:Name="BtnCustomRefresh" Grid.Column="0" MinWidth="140" Text="{DynamicResource Setup.Ui.Homepage.Refresh}"
Padding="13,0" Margin="0,0,20,0" HorizontalAlignment="Left"
ColorType="Highlight" Click="BtnCustomRefresh_Click" />
<local:MyButton x:Name="BtnCustomTutorial" Grid.Column="1" MinWidth="140" Text="{DynamicResource Setup.Ui.Homepage.Tutorial}"
Padding="13,0" Margin="0,0,20,0" HorizontalAlignment="Left"
Click="BtnCustomTutorial_Click" />
</Grid>
<Grid x:Name="PanCustomNet" Visibility="Collapsed" Margin="0,10,0,5">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" SharedSizeGroup="Name" />
<ColumnDefinition />
</Grid.ColumnDefinitions>
<TextBlock VerticalAlignment="Center" HorizontalAlignment="Left" Text="{DynamicResource Setup.Ui.Homepage.DownloadUrl}" Margin="0,0,25,0" />
<local:MyTextBox x:Name="TextCustomNet" Tag="UiCustomNet" Grid.Column="1" MaxHeight="28"
ValidatedTextChanged="TextBoxChange">
<local:MyTextBox.ValidateRules>
<val:HttpValidator AllowsNullOrEmpty="True" />
</local:MyTextBox.ValidateRules>
</local:MyTextBox>
</Grid>
<Grid x:Name="PanCustomPreset" Visibility="Collapsed" Margin="0,12,10,5" Height="28">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" SharedSizeGroup="Name" />
<ColumnDefinition />
</Grid.ColumnDefinitions>
<TextBlock VerticalAlignment="Center" HorizontalAlignment="Left" Text="{DynamicResource Setup.Ui.Homepage.PresetLabel}" Margin="0,0,25,0" />
<local:MyComboBox x:Name="ComboCustomPreset" Grid.ColumnSpan="2" Tag="UiCustomPreset"
Grid.Column="1" SelectionChanged="ComboChange">
<local:MyComboBoxItem Content="{DynamicResource Setup.Ui.Homepage.Preset.Trivia}" />
<local:MyComboBoxItem Content="{DynamicResource Setup.Ui.Homepage.Preset.EchoCave}" Visibility="Collapsed" />
<local:MyComboBoxItem Content="{DynamicResource Setup.Ui.Homepage.Preset.McNews}" />
<!-- <local:MyComboBoxItem Content="{DynamicResource Setup.Ui.Homepage.Preset.SimpleHomepage}" /> -->
<local:MyComboBoxItem Content="{DynamicResource Setup.Ui.Homepage.Preset.DailyModpack}" />
<local:MyComboBoxItem Content="{DynamicResource Setup.Ui.Homepage.Preset.McSkin}" />
<local:MyComboBoxItem Content="{DynamicResource Setup.Ui.Homepage.Preset.OpenBmclapi}" />
<!-- <local:MyComboBoxItem Content="{DynamicResource Setup.Ui.Homepage.Preset.PclMarket}" /> -->
<!-- <local:MyComboBoxItem Content="{DynamicResource Setup.Ui.Homepage.Preset.PclNews}" /> -->
<local:MyComboBoxItem Content="{DynamicResource Setup.Ui.Homepage.Preset.PclManual}" />
<!-- <local:MyComboBoxItem Content="{DynamicResource Setup.Ui.Homepage.Preset.OpenMcim}" Visibility="Collapsed" /> -->
<local:MyComboBoxItem Content="{DynamicResource Setup.Ui.Homepage.Preset.Magazine}" />
<local:MyComboBoxItem Content="{DynamicResource Setup.Ui.Homepage.Preset.GitHub}" />
<local:MyComboBoxItem Content="{DynamicResource Setup.Ui.Homepage.Preset.McUpdateSummary}" />
<local:MyComboBoxItem Content="{DynamicResource Setup.Ui.Homepage.Preset.NewsToday}" />
<local:MyComboBoxItem Content="{DynamicResource Setup.Ui.Homepage.Preset.MinecraftKnowledge}" />
<local:MyComboBoxItem Content="{DynamicResource Setup.Ui.Homepage.Preset.ModpackRecommendation}" />
<local:MyComboBoxItem Content="{DynamicResource Setup.Ui.Homepage.Preset.Bangumi}" />
<local:MyComboBoxItem Content="{DynamicResource Setup.Ui.Homepage.Preset.PclAnnouncement}"/>
<local:MyComboBoxItem Content="{DynamicResource Setup.Ui.Homepage.Preset.McOfficialFeed}"/>
</local:MyComboBox>
</Grid>
</StackPanel>
</local:MyCard>
<local:MyCard x:Name="CardSwitch" Margin="0,0,0,15" Title="{DynamicResource Setup.Ui.FeatureHide.Title}">
<StackPanel Margin="25,38,15,15">
<TextBlock Margin="0,1,0,1" Text="{DynamicResource Setup.Ui.FeatureHide.Description}" TextWrapping="Wrap" />
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="18" />
<ColumnDefinition Width="0.8*" />
<ColumnDefinition Width="0.9*" />
<ColumnDefinition Width="0.8*" />
<ColumnDefinition Width="0.8*" />
<ColumnDefinition Width="1.0*" />
<ColumnDefinition Width="1.0*" />
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="4" />
<RowDefinition Height="30" />
<RowDefinition Height="30" />
<RowDefinition Height="30" />
<RowDefinition Height="30" />
<RowDefinition Height="30" />
<RowDefinition Height="30" />
<RowDefinition Height="30" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<TextBlock Grid.Row="1" VerticalAlignment="Center" HorizontalAlignment="Left" Text="{DynamicResource Setup.Ui.FeatureHide.MainPage}" />
<local:MyCheckBox Height="22" VerticalAlignment="Center" Grid.Row="1" Grid.Column="2" Text="{DynamicResource Setup.Ui.FeatureHide.Item.Download}"
x:Name="CheckHiddenPageDownload" Tag="UiHiddenPageDownload"
Change="CheckBoxChange" />
<local:MyCheckBox Height="22" VerticalAlignment="Center" Grid.Row="1" Grid.Column="3" Text="{DynamicResource Setup.Ui.FeatureHide.Item.Settings}"
x:Name="CheckHiddenPageSetup" Tag="UiHiddenPageSetup" Change="CheckBoxChange" />
<local:MyCheckBox Height="22" VerticalAlignment="Center" Grid.Row="1" Grid.Column="4" Text="{DynamicResource Setup.Ui.FeatureHide.Item.Tools}"
x:Name="CheckHiddenPageTools" Tag="UiHiddenPageTools" Change="CheckBoxChange" />
<TextBlock Grid.Row="2" VerticalAlignment="Center" HorizontalAlignment="Left" Text="{DynamicResource Setup.Ui.FeatureHide.SubSetup}" />
<local:MyCheckBox Height="22" VerticalAlignment="Center" Grid.Row="2" Grid.Column="2" Text="{DynamicResource Setup.Ui.FeatureHide.Item.Launch}"
x:Name="CheckHiddenSetupLaunch" Tag="UiHiddenSetupLaunch"
Change="CheckBoxChange" />
<local:MyCheckBox Height="22" VerticalAlignment="Center" Grid.Row="2" Grid.Column="3"
Text="Java" x:Name="CheckHiddenSetupJava" Tag="UiHiddenSetupJava"
Change="CheckBoxChange" />
<local:MyCheckBox Height="22" VerticalAlignment="Center" Grid.Row="2" Grid.Column="4" Text="{DynamicResource Setup.Ui.FeatureHide.Item.GameManage}"
x:Name="CheckHiddenSetupGameManage" Tag="UiHiddenSetupGameManage"
Change="CheckBoxChange" />
<local:MyCheckBox Height="22" VerticalAlignment="Center" Grid.Row="2" Grid.Column="5" Text="{DynamicResource Setup.Ui.FeatureHide.Item.GameLink}"
x:Name="CheckHiddenSetupGameLink" Tag="UiHiddenSetupGameLink"
Change="CheckBoxChange" />
<local:MyCheckBox Height="22" VerticalAlignment="Center" Grid.Row="2" Grid.Column="6"
Text="{DynamicResource Setup.Ui.FeatureHide.Item.Ui}" x:Name="CheckHiddenSetupUI" Tag="UiHiddenSetupUi"
Change="CheckBoxChange" />
<local:MyCheckBox Height="22" VerticalAlignment="Center" Grid.Row="3" Grid.Column="2" Text="{DynamicResource Setup.Ui.FeatureHide.Item.Language}"
x:Name="CheckHiddenSetupLauncherLanguage" Tag="UiHiddenSetupLauncherLanguage"
Change="CheckBoxChange" />
<local:MyCheckBox Height="22" VerticalAlignment="Center" Grid.Row="3" Grid.Column="3" Text="{DynamicResource Setup.Ui.FeatureHide.Item.Misc}"
x:Name="CheckHiddenLauncherMisc" Tag="UiHiddenSetupLauncherMisc"
Change="CheckBoxChange" />
<local:MyCheckBox Height="22" VerticalAlignment="Center" Grid.Row="3" Grid.Column="4"
Text="{DynamicResource Setup.Ui.FeatureHide.Item.Update}" x:Name="CheckHiddenSetupUpdate" Tag="UiHiddenSetupUpdate"
Change="CheckBoxChange" />
<local:MyCheckBox Height="22" VerticalAlignment="Center" Grid.Row="3" Grid.Column="5" Text="{DynamicResource Setup.Ui.FeatureHide.Item.About}"
x:Name="CheckHiddenSetupAbout" Tag="UiHiddenSetupAbout"
Change="CheckBoxChange" />
<local:MyCheckBox Height="22" VerticalAlignment="Center" Grid.Row="3" Grid.Column="6" Text="{DynamicResource Setup.Ui.FeatureHide.Item.Feedback}"
x:Name="CheckHiddenSetupFeedback" Tag="UiHiddenSetupFeedback"
Change="CheckBoxChange" />
<local:MyCheckBox Height="22" VerticalAlignment="Center" Grid.Row="3" Grid.Column="7"
Text="{DynamicResource Setup.Ui.FeatureHide.Item.Log}" x:Name="CheckHiddenSetupLog" Tag="UiHiddenSetupLog"
Change="CheckBoxChange" />
<TextBlock Grid.Row="4" VerticalAlignment="Center" HorizontalAlignment="Left" Text="{DynamicResource Setup.Ui.FeatureHide.SubTools}" />
<local:MyCheckBox Height="22" VerticalAlignment="Center" Grid.Row="4" Grid.Column="2" Text="{DynamicResource Setup.Ui.FeatureHide.Item.Lobby}" x:Name="CheckHiddenToolsGameLink" Tag="UiHiddenToolsGameLink" Change="CheckBoxChange"/>
<local:MyCheckBox Height="22" VerticalAlignment="Center" Grid.Row="4" Grid.Column="3" Text="{DynamicResource Setup.Ui.FeatureHide.Item.Toolbox}" x:Name="CheckHiddenToolsTest" Tag="UiHiddenToolsTest" Change="CheckBoxChange"/>
<TextBlock Grid.Row="5" VerticalAlignment="Center" HorizontalAlignment="Left" Text="{DynamicResource Setup.Ui.FeatureHide.SubInstance}" />
<local:MyCheckBox Height="22" VerticalAlignment="Center" Grid.Row="5" Grid.Column="2" Text="{DynamicResource Setup.Ui.FeatureHide.Item.Edit}"
x:Name="CheckHiddenVersionEdit" Tag="UiHiddenVersionEdit"
Change="CheckBoxChange" />
<local:MyCheckBox Height="22" VerticalAlignment="Center" Grid.Row="5" Grid.Column="3" Text="{DynamicResource Setup.Ui.FeatureHide.Item.Export}"
x:Name="CheckHiddenVersionExport" Tag="UiHiddenVersionExport"
Change="CheckBoxChange" />
<local:MyCheckBox Height="22" VerticalAlignment="Center" Grid.Row="5" Grid.Column="4" Text="{DynamicResource Setup.Ui.FeatureHide.Item.Save}"
x:Name="CheckHiddenVersionSave" Tag="UiHiddenVersionSave"
Change="CheckBoxChange" />
<local:MyCheckBox Height="22" VerticalAlignment="Center" Grid.Row="5" Grid.Column="5" Text="{DynamicResource Setup.Ui.FeatureHide.Item.Screenshot}"
x:Name="CheckHiddenVersionScreenshot" Tag="UiHiddenVersionScreenshot"
Change="CheckBoxChange" />
<local:MyCheckBox Height="22" VerticalAlignment="Center" Grid.Row="5" Grid.Column="6"
Text="Mod" x:Name="CheckHiddenVersionMod" Tag="UiHiddenVersionMod"
Change="CheckBoxChange" />
<local:MyCheckBox Height="22" VerticalAlignment="Center" Grid.Row="6" Grid.Column="2"
Text="{DynamicResource Setup.Ui.FeatureHide.Item.ResourcePack}" x:Name="CheckHiddenVersionResourcePack"
Tag="UiHiddenVersionResourcePack" Change="CheckBoxChange" />
<local:MyCheckBox Height="22" VerticalAlignment="Center" Grid.Row="6" Grid.Column="3"
Text="{DynamicResource Setup.Ui.FeatureHide.Item.Shader}" x:Name="CheckHiddenVersionShader" Tag="UiHiddenVersionShader"
Change="CheckBoxChange" />
<local:MyCheckBox Height="22" VerticalAlignment="Center" Grid.Row="6" Grid.Column="4"
Grid.ColumnSpan="2" Text="{DynamicResource Setup.Ui.FeatureHide.Item.Schematic}" x:Name="CheckHiddenVersionSchematic"
Tag="UiHiddenVersionSchematic" Change="CheckBoxChange" />
<local:MyCheckBox Height="22" VerticalAlignment="Center" Grid.Row="6" Grid.Column="6"
Text="{DynamicResource Setup.Ui.FeatureHide.Item.Server}" x:Name="CheckHiddenVersionServer" Tag="UiHiddenVersionServer"
Change="CheckBoxChange" />
<TextBlock Grid.Row="7" VerticalAlignment="Center" HorizontalAlignment="Left" Text="{DynamicResource Setup.Ui.FeatureHide.SpecificFeature}" />
<local:MyCheckBox Height="22" VerticalAlignment="Center" Grid.Row="7" Grid.Column="2"
Text="{DynamicResource Setup.Ui.FeatureHide.Item.InstanceSelect}" x:Name="CheckHiddenFunctionSelect" Tag="UiHiddenFunctionSelect"
ToolTip="{DynamicResource Setup.Ui.FeatureHide.Item.InstanceSelect.ToolTip}" Change="CheckBoxChange" />
<local:MyCheckBox Height="22" VerticalAlignment="Center" Grid.Row="7" Grid.Column="3"
Text="{DynamicResource Setup.Ui.FeatureHide.Item.ModUpdate}" x:Name="CheckHiddenFunctionModUpdate"
Tag="UiHiddenFunctionModUpdate" ToolTip="{DynamicResource Setup.Ui.FeatureHide.Item.ModUpdate.ToolTip}"
Change="CheckBoxChange" />
<local:MyCheckBox Height="22" VerticalAlignment="Center" Grid.Row="7" Grid.Column="4"
Text="{DynamicResource Setup.Ui.FeatureHide.Item.FeatureHide}" x:Name="CheckHiddenFunctionHidden" Tag="UiHiddenFunctionHidden"
ToolTip="{DynamicResource Setup.Ui.FeatureHide.Item.FeatureHide.ToolTip}"
Change="CheckBoxChange" />
</Grid>
</StackPanel>
</local:MyCard>
</StackPanel>
</local:MyScrollViewer>
</local:MyPageRight>
@@ -0,0 +1,957 @@
using System.IO;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;
using PCL.Core.App;
using PCL.Core.App.Configuration;
using PCL.Core.UI;
using PCL.Core.Utils;
using PCL.Core.App.Localization;
namespace PCL;
public partial class PageSetupUI
{
public string[] ThemeColors => Basics.IsAprilFool
? [Lang.Text("Setup.Ui.Theme.Color.SkyBlue"), Lang.Text("Setup.Ui.Theme.Color.CatBlue"), Lang.Text("Setup.Ui.Theme.Color.CrashBlue"), Lang.Text("Setup.Ui.Theme.Color.Hmcl")]
: [Lang.Text("Setup.Ui.Theme.Color.SkyBlue"), Lang.Text("Setup.Ui.Theme.Color.CatBlue"), Lang.Text("Setup.Ui.Theme.Color.CrashBlue")];
public new bool isLoaded;
public PageSetupUI()
{
InitializeComponent();
Loaded += PageSetupUI_Loaded;
Loaded += (_, _) => HiddenRefresh();
}
private void PageSetupUI_Loaded(object sender, RoutedEventArgs e)
{
// 重复加载部分
PanBack.ScrollToHome();
ModAnimation.AniControlEnabled += 1;
Reload(); // #4826,在每次进入页面时都刷新一下
ModAnimation.AniControlEnabled -= 1;
// 非重复加载部分
if (isLoaded)
return;
isLoaded = true;
SliderLoad();
PanLauncherHide.Visibility = Visibility.Visible;
}
public void Reload()
{
try
{
// 启动器
SliderLauncherOpacity.Value = Config.Preference.Theme.WindowOpacity;
CheckLauncherLogo.Checked = Config.Preference.ShowStartupLogo;
ComboDarkMode.SelectedIndex = (int)Config.Preference.Theme.ColorMode;
ComboDarkColor.SelectedIndex = (int)Config.Preference.Theme.DarkColor;
ComboLightColor.SelectedIndex = (int)Config.Preference.Theme.LightColor;
CheckShowLaunchingHint.Checked = Config.Preference.ShowLaunchingHint;
// 字体设置
ComboUiFont.SelectedFontTag = Config.Preference.Font;
ComboUiMotdFont.SelectedFontTag = Config.Preference.MotdFont;
CheckBlur.Checked = Config.Preference.Blur.IsEnabled;
SliderBlurValue.Value = Config.Preference.Blur.Radius;
SliderBlurSamplingRate.Value = Config.Preference.Blur.SamplingRate;
ComboBlurType.SelectedIndex = Config.Preference.Blur.KernelType;
PanBlurValue.Visibility = CheckBlur.Checked == true ? Visibility.Visible : Visibility.Collapsed;
CheckLockWindowSize.Checked = Config.Preference.LockWindowSize;
// 背景图片
SliderBackgroundOpacity.Value = Config.Preference.Background.WallpaperOpacity;
SliderBackgroundBlur.Value = Config.Preference.Background.WallpaperBlurRadius;
ComboBackgroundSuit.SelectedIndex = Config.Preference.Background.WallpaperSuitMode;
CheckBackgroundColorful.Checked = Config.Preference.Background.BackgroundColorful;
var autoPauseVideo = Config.Preference.Background.AutoPauseVideo;
CheckAutoPauseVideo.Checked = autoPauseVideo;
if (ModVideoBack.IsGaming)
if (autoPauseVideo)
BtnBackgroundRefresh.IsEnabled = false;
BackgroundRefresh(false, false);
// 标题栏
((MyRadioBox)FindName("RadioLogoType" + (int)Config.Preference.WindowTitleType))
.Checked = true;
CheckLogoLeft.Visibility = RadioLogoType0.Checked ? Visibility.Visible : Visibility.Collapsed;
PanLogoText.Visibility = RadioLogoType2.Checked ? Visibility.Visible : Visibility.Collapsed;
PanLogoChange.Visibility = RadioLogoType3.Checked ? Visibility.Visible : Visibility.Collapsed;
TextLogoText.Text = Config.Preference.WindowTitleCustomText;
CheckLogoLeft.Checked = Config.Preference.TopBarLeftAlign;
// 背景音乐
CheckMusicRandom.Checked = Config.Preference.Music.ShufflePlayback;
CheckMusicAuto.Checked = Config.Preference.Music.StartOnStartup;
CheckMusicStop.Checked = Config.Preference.Music.StopInGame;
CheckMusicStart.Checked = Config.Preference.Music.StartInGame;
CheckMusicSMTC.Checked = Config.Preference.Music.EnableSMTC;
SliderMusicVolume.Value = Config.Preference.Music.Volume;
MusicRefreshUI();
// 主页
try
{
ComboCustomPreset.SelectedIndex = Config.Preference.Homepage.SelectedPreset;
}
catch
{
Config.Preference.Homepage.SelectedPresetConfig.Reset();
}
((MyRadioBox)FindName("RadioCustomType" + Config.Preference.Homepage.Type)).Checked = true;
TextCustomNet.Text = Config.Preference.Homepage.CustomUrl;
ModSetup.UiCustomType(Config.Preference.Homepage.Type);
// 功能隐藏
// 获取配置组引用
var uiHidden = Config.Preference.Hide;
// 主页面
CheckHiddenPageDownload.Checked = uiHidden.PageDownload;
CheckHiddenPageSetup.Checked = uiHidden.PageSetup;
CheckHiddenPageTools.Checked = uiHidden.PageTools;
// 子页面 设置
CheckHiddenSetupLaunch.Checked = uiHidden.SetupLaunch;
CheckHiddenSetupUI.Checked = uiHidden.SetupUi;
CheckHiddenSetupLauncherLanguage.Checked = uiHidden.SetupLauncherLanguage;
CheckHiddenSetupGameManage.Checked = uiHidden.SetupGameManage;
CheckHiddenSetupJava.Checked = uiHidden.SetupJava;
CheckHiddenLauncherMisc.Checked = uiHidden.SetupLauncherMisc;
CheckHiddenSetupUpdate.Checked = uiHidden.SetupUpdate;
CheckHiddenSetupGameLink.Checked = uiHidden.SetupGameLink;
CheckHiddenSetupAbout.Checked = uiHidden.SetupAbout;
CheckHiddenSetupFeedback.Checked = uiHidden.SetupFeedback;
CheckHiddenSetupLog.Checked = uiHidden.SetupLog;
// 子页面 工具
CheckHiddenToolsGameLink.Checked = uiHidden.ToolsGameLink;
CheckHiddenToolsTest.Checked = uiHidden.ToolsTest;
// 子页面 实例设置
CheckHiddenVersionEdit.Checked = uiHidden.InstanceEdit;
CheckHiddenVersionExport.Checked = uiHidden.InstanceExport;
CheckHiddenVersionSave.Checked = uiHidden.InstanceSave;
CheckHiddenVersionScreenshot.Checked = uiHidden.InstanceScreenshot;
CheckHiddenVersionMod.Checked = uiHidden.InstanceMod;
CheckHiddenVersionResourcePack.Checked = uiHidden.InstanceResourcePack;
CheckHiddenVersionShader.Checked = uiHidden.InstanceShader;
CheckHiddenVersionSchematic.Checked = uiHidden.InstanceSchematic;
CheckHiddenVersionServer.Checked = uiHidden.InstanceServer;
// 特定功能
CheckHiddenFunctionSelect.Checked = uiHidden.FunctionSelect;
CheckHiddenFunctionModUpdate.Checked = uiHidden.FunctionModUpdate;
CheckHiddenFunctionHidden.Checked = uiHidden.FunctionHidden;
}
catch (NullReferenceException ex)
{
ModBase.Log(
ex,
Lang.Text("Setup.Ui.Error.ConfigReset"),
ModBase.LogLevel.Msgbox,
userSummary: Lang.Text("Setup.Ui.Error.ConfigReset"));
Reset();
}
catch (Exception ex)
{
ModBase.Log(
ex,
Lang.Text("Setup.Ui.Error.LoadFailed"),
ModBase.LogLevel.Feedback,
userSummary: Lang.Text("Setup.Ui.Error.LoadFailed"));
}
}
// 初始化
public void Reset()
{
try
{
Config.Preference.Reset();
ModBase.Log("[Setup] 已初始化个性化设置!");
HintService.Hint(Lang.Text("Setup.Ui.Initialized"), HintType.Success, false);
}
catch (Exception ex)
{
ModBase.Log(
ex,
Lang.Text("Setup.Ui.Error.InitFailed"),
ModBase.LogLevel.Msgbox,
userSummary: Lang.Text("Setup.Ui.Error.InitFailed"));
}
Reload();
}
// 将控件改变路由到设置改变
private void SliderChange(object senderRaw, bool user)
{
var sender = (MySlider)senderRaw;
if (ModAnimation.AniControlEnabled == 0)
SetByTag(sender.Tag?.ToString(), sender.Value);
}
private void ComboChange(object senderRaw, SelectionChangedEventArgs e)
{
var sender = (MyComboBox)senderRaw;
if (ModAnimation.AniControlEnabled == 0)
SetByTag(sender.Tag?.ToString(), sender.SelectedIndex);
}
private void CheckBoxChange(object senderRaw, bool user)
{
var sender = (MyCheckBox)senderRaw;
if (ModAnimation.AniControlEnabled == 0)
SetByTag(sender.Tag?.ToString(), sender.Checked);
}
private void TextBoxChange(object senderRaw, RoutedEventArgs e)
{
var sender = (MyTextBox)senderRaw;
if (ModAnimation.AniControlEnabled == 0)
SetByTag(sender.Tag?.ToString(), sender.Text);
}
private void RadioBoxChange(object senderRaw, ModBase.RouteEventArgs e)
{
var sender = (MyRadioBox)senderRaw;
var gotCfg = sender.Tag?.ToString()?.Split("/") ?? Array.Empty<string>();
if (ModAnimation.AniControlEnabled == 0 && gotCfg.Length >= 2)
SetByTag(gotCfg[0], int.Parse(gotCfg[1]));
}
private static void SetByTag(string tag, object value)
{
ConfigService.TrySetValue(tag, value);
}
private void ComboFontChange(object sender, SelectionChangedEventArgs e)
{
if (ModAnimation.AniControlEnabled == 0) Config.Preference.Font = ComboUiFont.SelectedFontTag;
}
private void ComboMotdFontChange(object sender, SelectionChangedEventArgs e)
{
if (ModAnimation.AniControlEnabled == 0) Config.Preference.MotdFont = ComboUiMotdFont.SelectedFontTag;
}
// 背景图片
private void BtnUIBgOpen_Click(object sender, MouseButtonEventArgs e)
{
ModBase.OpenExplorer(ModBase.exePath + @"PCL\Pictures\");
}
private void BtnBackgroundRefresh_Click(object sender, MouseButtonEventArgs e)
{
BackgroundRefresh(true, true);
}
public void BackgroundRefreshUI(bool show, int count)
{
if (PanBackgroundOpacity is null)
return;
if (show)
{
PanBackgroundOpacity.Visibility = Visibility.Visible;
PanBackgroundBlur.Visibility = Visibility.Visible;
PanBackgroundSuit.Visibility = Visibility.Visible;
BtnBackgroundClear.Visibility = Visibility.Visible;
CheckAutoPauseVideo.Visibility = Visibility.Visible;
CardBackground.Title = Lang.Text("Setup.Ui.Background.TitleWithCount", count);
}
else
{
PanBackgroundOpacity.Visibility = Visibility.Collapsed;
PanBackgroundBlur.Visibility = Visibility.Collapsed;
PanBackgroundSuit.Visibility = Visibility.Collapsed;
BtnBackgroundClear.Visibility = Visibility.Collapsed;
CheckAutoPauseVideo.Visibility = Visibility.Collapsed;
CardBackground.Title = Lang.Text("Setup.Ui.Background.TitleDefault");
}
CardBackground.TriggerForceResize();
}
private void BtnBackgroundClear_Click(object sender, MouseButtonEventArgs e)
{
if (ModMain.MyMsgBox(Lang.Text("Setup.Ui.Background.Clear.Confirm.Message"),
Lang.Text("Common.Dialog.Warning"), button2: Lang.Text("Common.Action.Cancel"),
isWarn: true) == 1)
{
ModBase.DeleteDirectory(ModBase.exePath + @"PCL\Pictures");
BackgroundRefresh(false, true);
HintService.Hint(Lang.Text("Setup.Ui.Background.Clear.Success"), HintType.Success);
}
}
/// <summary>
/// 刷新背景图片及设置页 UI。
/// </summary>
/// <param name="isHint">是否显示刷新提示。</param>
/// <param name="refresh">是否刷新图片显示。</param>
public static void BackgroundRefresh(bool isHint, bool refresh)
{
try
{
// 获取可用的图片文件
Directory.CreateDirectory(ModBase.exePath + @"PCL\Pictures\");
var pic = ModBase.EnumerateFiles(ModBase.exePath + @"PCL\Pictures\").Where(file =>
!(file.Extension.Equals(".ini", StringComparison.OrdinalIgnoreCase) ||
file.Extension.Equals(".db", StringComparison.OrdinalIgnoreCase))).Select(file => file.FullName)
.ToList();
// 视频加载异常处理
EventHandler<ExceptionRoutedEventArgs> videoHandler = (sender, e) =>
{
var videoEx = e.ErrorException;
var videoAddress = ModMain.frmMain.VideoBack.Source.ToString();
if (ModMain.frmMain.VideoBack.Source is not null)
{
ModVideoBack.VideoStop();
if (videoEx.Message.Contains("0xC00D109B"))
ModBase.Log(
$"""
刷新背景内容失败,该视频文件可能并非 H.264(AVC)格式。
你可以尝试使用视频转码工具打开视频文件并设定目标格式为 H.264(AVC),然后转码该视频。
文件:{videoAddress}
""",
ModBase.LogLevel.Msgbox,
userSummary: Lang.Text("Setup.Ui.Error.BackgroundVideoUnsupported"));
else
ModBase.Log(
videoEx,
$"刷新背景内容失败({videoAddress}",
ModBase.LogLevel.Msgbox,
userSummary: Lang.Text("Setup.Ui.Error.OperationFailed"));
}
};
ModMain.frmMain.VideoBack.MediaFailed -= videoHandler;
ModVideoBack.GamingStateChanged -= ModVideoBack.OnGamingStateChanged;
ModVideoBack.ForcePlayChanged -= ModVideoBack.OnForcePlayChanged;
ModVideoBack.GamingStateChanged += ModVideoBack.OnGamingStateChanged;
ModVideoBack.ForcePlayChanged += ModVideoBack.OnForcePlayChanged;
if (!Config.Preference.Background.AutoPauseVideo)
ModVideoBack.ForcePlay = true;
// 加载
if (pic.Count == 0)
{
if (refresh)
{
if (ModMain.frmMain.ImgBack.Visibility == Visibility.Collapsed)
{
if (isHint)
HintService.Hint(Lang.Text("Setup.Ui.Background.NoAvailableContent"), HintType.Error);
}
else
{
ModMain.frmMain.ImgBack.Visibility = Visibility.Collapsed;
if (isHint)
HintService.Hint(Lang.Text("Setup.Ui.Background.Cleared"), HintType.Success);
}
}
if (ModMain.frmSetupUI is not null)
ModMain.frmSetupUI.BackgroundRefreshUI(false, 0);
}
else
{
if (refresh)
{
var address = RandomUtils.PickRandom(pic);
try
{
ModMain.frmMain.ImgBack.Background = null;
ModVideoBack.VideoStop();
ModBase.Log("[UI] 加载背景内容:" + address);
ModMain.frmMain.ImgBack.Background = new MyBitmap(address);
_ = Config.Preference.Background.WallpaperSuitMode;
ModMain.frmMain.ImgBack.Visibility = Visibility.Visible;
if (isHint)
HintService.Hint(Lang.Text("Setup.Ui.Background.Refresh.Success", ModBase.GetFileNameFromPath(address)), HintType.Success,
false);
}
catch (Exception ex)
{
try
{
ModMain.frmMain.VideoBack.MediaFailed += videoHandler;
ModBase.Log(ex, "[UI] 加载背景图片失败" + address);
if (ModBase.modeDebug)
HintService.Hint(Lang.Text("Setup.Ui.Background.ImageLoadFailed", address));
ModMain.frmMain.ImgBack.Visibility = Visibility.Visible;
ModMain.frmMain.VideoBack.Source = new Uri(address, UriKind.Absolute);
ModVideoBack.VideoPlay();
if (isHint)
HintService.Hint(Lang.Text("Setup.Ui.Background.Refresh.Success", ModBase.GetFileNameFromPath(address)), HintType.Success,
false);
}
catch (Exception playEx)
{
ModBase.Log(playEx, "播放背景内容时出现未知错误:");
}
}
}
if (ModMain.frmSetupUI is not null)
ModMain.frmSetupUI.BackgroundRefreshUI(true, pic.Count);
}
}
catch (Exception ex)
{
ModBase.Log(
ex,
"刷新背景内容时出现未知错误",
ModBase.LogLevel.Feedback,
userSummary: Lang.Text("Setup.Ui.Error.OperationFailed"));
}
}
// 顶部栏
private void BtnLogoChange_Click(object sender, MouseButtonEventArgs e)
{
var fileName = SystemDialogs.SelectFile(
Lang.Text("Setup.Ui.ImageFile.Filter"),
Lang.Text("Setup.Ui.ImageFile.SelectTitle"));
if (string.IsNullOrEmpty(fileName))
return;
try
{
// 拷贝文件
File.Delete(ModBase.exePath + @"PCL\Logo.png");
ModBase.CopyFile(fileName, ModBase.exePath + @"PCL\Logo.png");
// 设置当前显示
ModMain.frmMain.ImageTitleLogo.Source = null; // 防止因为 Source 属性前后的值相同而不更新 (#5628)
ModMain.frmMain.ImageTitleLogo.Source = ModBase.exePath + @"PCL\Logo.png";
}
catch (Exception ex)
{
if (ex.Message.Contains("参数无效"))
ModBase.Log(
"""
使
""",
ModBase.LogLevel.Msgbox,
userSummary: Lang.Text("Setup.Ui.Error.TitleImageInvalidFormat"));
else
ModBase.Log(
ex,
"设置标题栏图片失败",
ModBase.LogLevel.Msgbox,
userSummary: Lang.Text("Setup.Ui.Error.OperationFailed"));
ModMain.frmMain.ImageTitleLogo.Source = null;
}
}
private void RadioLogoType3_Check(object sender, ModBase.RouteEventArgs e)
{
if (!(ModAnimation.AniControlEnabled == 0 && e.raiseByMouse))
return;
Refresh: ;
// 已有图片则不再选择
if (File.Exists(ModBase.exePath + @"PCL\Logo.png"))
{
try
{
ModMain.frmMain.ImageTitleLogo.Source = null; // 防止因为 Source 属性前后的值相同而不更新 (#5628)
ModMain.frmMain.ImageTitleLogo.Source = ModBase.exePath + @"PCL\Logo.png";
}
catch (Exception ex)
{
if (ex.Message.Contains("参数无效"))
ModBase.Log(
"""
使
""",
ModBase.LogLevel.Msgbox,
userSummary: Lang.Text("Setup.Ui.Error.TitleImageResizeInvalidFormat"));
else
ModBase.Log(
ex,
"调整标题栏图片失败",
ModBase.LogLevel.Msgbox,
userSummary: Lang.Text("Setup.Ui.Error.OperationFailed"));
ModMain.frmMain.ImageTitleLogo.Source = null;
e.handled = true;
try
{
File.Delete(ModBase.exePath + @"PCL\Logo.png");
}
catch (Exception exx)
{
ModBase.Log(
exx,
"清理错误的标题栏图片失败",
ModBase.LogLevel.Msgbox,
userSummary: Lang.Text("Setup.Ui.Error.OperationFailed"));
}
}
return;
}
// 没有图片则要求选择
var fileName = SystemDialogs.SelectFile(Lang.Text("Setup.Ui.ImageFile.Filter"), Lang.Text("Setup.Ui.ImageFile.SelectTitle"));
if (string.IsNullOrEmpty(fileName))
{
ModMain.frmMain.ImageTitleLogo.Source = null;
e.handled = true;
}
else
{
try
{
// 拷贝文件
File.Delete(ModBase.exePath + @"PCL\Logo.png");
ModBase.CopyFile(fileName, ModBase.exePath + @"PCL\Logo.png");
goto Refresh;
}
catch (Exception ex)
{
ModBase.Log(
ex,
"复制标题栏图片失败",
ModBase.LogLevel.Msgbox,
userSummary: Lang.Text("Setup.Ui.Error.OperationFailed"));
}
}
}
private void BtnLogoDelete_Click(object sender, MouseButtonEventArgs e)
{
try
{
File.Delete(ModBase.exePath + @"PCL\Logo.png");
RadioLogoType1.SetChecked(true, true);
HintService.Hint(Lang.Text("Setup.Ui.Logo.Clear.Success"), HintType.Success);
}
catch (Exception ex)
{
ModBase.Log(
ex,
"清空标题栏图片失败",
ModBase.LogLevel.Msgbox,
userSummary: Lang.Text("Setup.Ui.Error.OperationFailed"));
}
}
// 背景音乐
private void BtnMusicOpen_Click(object sender, MouseButtonEventArgs e)
{
ModBase.OpenExplorer(ModBase.exePath + @"PCL\Musics\");
}
private void BtnMusicRefresh_Click(object sender, MouseButtonEventArgs e)
{
ModMusic.MusicRefreshPlay(true);
}
public void MusicRefreshUI()
{
if (PanBackgroundOpacity is null)
return;
if (ModMusic.musicAllList.Any())
{
PanMusicVolume.Visibility = Visibility.Visible;
PanMusicDetail.Visibility = Visibility.Visible;
BtnMusicClear.Visibility = Visibility.Visible;
CardMusic.Title = Lang.Text("Setup.Ui.Music.TitleWithCount", ModBase.EnumerateFiles(ModBase.exePath + @"PCL\Musics\").Count());
}
else
{
PanMusicVolume.Visibility = Visibility.Collapsed;
PanMusicDetail.Visibility = Visibility.Collapsed;
BtnMusicClear.Visibility = Visibility.Collapsed;
CardMusic.Title = Lang.Text("Setup.Ui.Music.Title");
}
CardMusic.TriggerForceResize();
}
private void BtnMusicClear_Click(object sender, MouseButtonEventArgs e)
{
if (ModMain.MyMsgBox(Lang.Text("Setup.Ui.Music.Clear.Confirm.Message"),
Lang.Text("Common.Dialog.Warning"), button2: Lang.Text("Common.Action.Cancel"),
isWarn: true) == 1)
ModBase.RunInThread(() =>
{
HintService.Hint(Lang.Text("Setup.Ui.Music.Deleting"));
// 停止播放音乐
ModMusic.musicNAudio = null;
ModMusic.musicWaitingList = new List<string>();
ModMusic.musicAllList = new List<string>();
Thread.Sleep(200);
// 删除文件
try
{
ModBase.DeleteDirectory(ModBase.exePath + @"PCL\Musics");
// DisableSMTCSupport()
HintService.Hint(Lang.Text("Setup.Ui.Music.Delete.Success"), HintType.Success);
}
catch (Exception ex)
{
ModBase.Log(
ex,
"删除背景音乐失败",
ModBase.LogLevel.Msgbox,
userSummary: Lang.Text("Setup.Ui.Error.OperationFailed"));
}
try
{
Directory.CreateDirectory(ModBase.exePath + @"PCL\Musics");
ModBase.RunInUi(() => ModMusic.MusicRefreshPlay(false));
}
catch (Exception ex)
{
ModBase.Log(
ex,
"重建背景音乐文件夹失败",
ModBase.LogLevel.Msgbox,
userSummary: Lang.Text("Setup.Ui.Error.OperationFailed"));
}
});
}
private void CheckMusicStart_Change(object sender, bool user)
{
CheckBoxChange(sender, user);
if (ModAnimation.AniControlEnabled != 0)
return;
if (CheckMusicStart.Checked == true)
CheckMusicStop.Checked = false;
}
private void CheckMusicStop_Change()
{
if (ModAnimation.AniControlEnabled != 0)
return;
if (CheckMusicStop.Checked == true)
CheckMusicStart.Checked = false;
}
// 主页
private void BtnCustomRefresh_Click(object sender, MouseButtonEventArgs e)
{
ModMain.frmLaunchRight.ForceRefresh();
HintService.Hint(Lang.Text("Setup.Ui.Homepage.Refresh.Success"), HintType.Success);
}
private void BtnCustomTutorial_Click(object sender, MouseButtonEventArgs e)
{
ModBase.OpenWebsite("https://docs.pclc.cc/ce/customization/xaml-format");
}
// 主题
private void ThemeColor_Change(object senderRaw, SelectionChangedEventArgs e)
{
var sender = (MyComboBox)senderRaw;
SetByTag(sender.Tag?.ToString(), sender.SelectedIndex);
ThemeManager.ThemeRefresh();
}
// 赞助
private void BtnLauncherDonate_Click(object sender, MouseButtonEventArgs e)
{
ModBase.OpenWebsite("https://afdian.com/a/LTCat");
}
// 滑动条
private void SliderLoad()
{
SliderMusicVolume.getHintText = new Func<object, object>(v =>
Lang.Number(Math.Ceiling(Convert.ToDouble(v) * 0.1d) / 100d, "P0"));
SliderLauncherOpacity.getHintText = new Func<object, object>(v =>
Lang.Number(Math.Round(40 + Convert.ToDouble(v) * 0.1d) / 100d, "P0"));
SliderBackgroundOpacity.getHintText = new Func<object, object>(v =>
Lang.Number(Math.Round(Convert.ToDouble(v) * 0.1d) / 100d, "P0"));
SliderBackgroundBlur.getHintText = new Func<object, object>(v => Lang.Text("Setup.Ui.Slider.Pixel", Lang.Number(Convert.ToDouble(v), "N0")));
SliderBlurValue.getHintText = new Func<object, object>(v => Lang.Text("Setup.Ui.Slider.Pixel", Lang.Number(Convert.ToDouble(v), "N0")));
SliderBlurSamplingRate.getHintText = new Func<object, object>(v => Lang.Number(Convert.ToDouble(v) / 100d, "P0"));
}
private void CheckMusicStart_OnChange(object sender, bool user)
{
CheckBoxChange(sender, user);
CheckMusicStart_Change(sender, user);
}
private void CheckMusicStop_OnChange(object sender, bool user)
{
CheckBoxChange(sender, user);
CheckMusicStop_Change();
}
#region
/// <summary>
/// 是否强制显示被禁用的功能。
/// </summary>
public static bool HiddenForceShow
{
get => field;
set
{
field = value;
HiddenRefresh();
}
}
/// <summary>
/// 更新功能隐藏带来的显示变化。
/// </summary>
public static void HiddenRefresh()
{
if (ModMain.frmMain.PanTitleSelect is null || !ModMain.frmMain.PanTitleSelect.IsLoaded)
return;
try
{
// 获取配置组引用以缩短代码
var conf = Config.Preference.Hide;
// 顶部栏:下载、设置、工具
var isAllTitleHidden = !HiddenForceShow && conf.PageDownload && conf.PageSetup && conf.PageTools;
if (isAllTitleHidden)
{
ModMain.frmMain.PanTitleSelect.Visibility = Visibility.Collapsed;
}
else
{
ModMain.frmMain.PanTitleSelect.Visibility = Visibility.Visible;
ModMain.frmMain.BtnTitleSelect1.Visibility = !HiddenForceShow && conf.PageDownload
? Visibility.Collapsed
: Visibility.Visible;
ModMain.frmMain.BtnTitleSelect2.Visibility =
!HiddenForceShow && conf.PageSetup ? Visibility.Collapsed : Visibility.Visible;
ModMain.frmMain.BtnTitleSelect3.Visibility =
!HiddenForceShow && conf.PageTools ? Visibility.Collapsed : Visibility.Visible;
}
// 功能隐藏设置卡片
if (ModMain.frmSetupUI is not null)
{
ModMain.frmSetupUI.CardSwitch.Visibility = !HiddenForceShow && conf.FunctionHidden
? Visibility.Collapsed
: Visibility.Visible;
ModMain.frmSetupUI.CardSwitch.Title = HiddenForceShow ? Lang.Text("Setup.Ui.FeatureHide.TitleTemporarilyDisabled") : Lang.Text("Setup.Ui.FeatureHide.Title");
}
// 设置子页面 (FrmSetupLeft)
if (ModMain.frmSetupLeft is not null)
{
ModMain.frmSetupLeft.ItemLaunch.Visibility =
!HiddenForceShow && conf.SetupLaunch ? Visibility.Collapsed : Visibility.Visible;
ModMain.frmSetupLeft.ItemUI.Visibility =
!HiddenForceShow && conf.SetupUi ? Visibility.Collapsed : Visibility.Visible;
ModMain.frmSetupLeft.ItemLauncherLanguage.Visibility = !HiddenForceShow && conf.SetupLauncherLanguage
? Visibility.Collapsed
: Visibility.Visible;
ModMain.frmSetupLeft.ItemGameManage.Visibility = !HiddenForceShow && conf.SetupGameManage
? Visibility.Collapsed
: Visibility.Visible;
ModMain.frmSetupLeft.ItemLauncherMisc.Visibility = !HiddenForceShow && conf.SetupLauncherMisc
? Visibility.Collapsed
: Visibility.Visible;
ModMain.frmSetupLeft.ItemJava.Visibility =
!HiddenForceShow && conf.SetupJava ? Visibility.Collapsed : Visibility.Visible;
ModMain.frmSetupLeft.ItemUpdate.Visibility =
!HiddenForceShow && conf.SetupUpdate ? Visibility.Collapsed : Visibility.Visible;
ModMain.frmSetupLeft.ItemGameLink.Visibility = !HiddenForceShow && conf.SetupGameLink
? Visibility.Collapsed
: Visibility.Visible;
ModMain.frmSetupLeft.ItemAbout.Visibility =
!HiddenForceShow && conf.SetupAbout ? Visibility.Collapsed : Visibility.Visible;
ModMain.frmSetupLeft.ItemFeedback.Visibility = !HiddenForceShow && conf.SetupFeedback
? Visibility.Collapsed
: Visibility.Visible;
ModMain.frmSetupLeft.ItemLog.Visibility =
!HiddenForceShow && conf.SetupLog ? Visibility.Collapsed : Visibility.Visible;
var categories = new[]
{
(ModMain.frmSetupLeft.TextGameCategory,
!(conf.SetupLaunch && conf.SetupJava && conf.SetupGameManage)),
(ModMain.frmSetupLeft.TextToolsCategory, !conf.SetupGameLink),
(ModMain.frmSetupLeft.TextLauncherCategory, !(conf.SetupUi && conf.SetupLauncherLanguage && conf.SetupLauncherMisc)),
(ModMain.frmSetupLeft.TextAboutCategory,
!(conf.SetupAbout && conf.SetupUpdate && conf.SetupFeedback && conf.SetupLog))
};
foreach (var category in categories)
{
var isVisible = category.Item2 || HiddenForceShow;
category.Item1.Visibility = isVisible ? Visibility.Visible : Visibility.Collapsed;
if (isVisible)
category.Item1.Opacity = 0.6d;
}
// 统计设置页可用项数量
var setupCount = 0;
if (!conf.SetupLaunch)
setupCount += 1;
if (!conf.SetupUi)
setupCount += 1;
if (!conf.SetupLauncherLanguage)
setupCount += 1;
if (!conf.SetupGameManage)
setupCount += 1;
if (!conf.SetupLauncherMisc)
setupCount += 1;
if (!conf.SetupJava)
setupCount += 1;
if (!conf.SetupUpdate)
setupCount += 1;
if (!conf.SetupGameLink)
setupCount += 1;
if (!conf.SetupAbout)
setupCount += 1;
if (!conf.SetupFeedback)
setupCount += 1;
if (!conf.SetupLog)
setupCount += 1;
ModMain.frmSetupLeft.PanItem.Visibility =
setupCount < 2 && !HiddenForceShow ? Visibility.Collapsed : Visibility.Visible;
}
// 工具子页面 (FrmToolsLeft)
if (ModMain.frmToolsLeft is not null)
{
ModMain.frmToolsLeft.ItemGameLink.Visibility = !HiddenForceShow && conf.ToolsGameLink
? Visibility.Collapsed
: Visibility.Visible;
ModMain.frmToolsLeft.ItemTest.Visibility =
!HiddenForceShow && conf.ToolsTest ? Visibility.Collapsed : Visibility.Visible;
// 处理分类标题
var isGameLinkVisible = (!HiddenForceShow && !conf.ToolsGameLink) || HiddenForceShow;
ModMain.frmToolsLeft.TextGameLinkCategory.Visibility = isGameLinkVisible ? Visibility.Visible : Visibility.Collapsed;
if (isGameLinkVisible) ModMain.frmToolsLeft.TextGameLinkCategory.Opacity = 0.6;
var isToolsVisible = (!HiddenForceShow && !conf.ToolsTest) || HiddenForceShow;
ModMain.frmToolsLeft.TextToolsCategory.Visibility = isToolsVisible ? Visibility.Visible : Visibility.Collapsed;
if (isToolsVisible) ModMain.frmToolsLeft.TextToolsCategory.Opacity = 0.6;
// 统计工具页可用项数量
var toolsCount = 0;
if (!conf.ToolsGameLink)
toolsCount += 1;
if (!conf.ToolsTest)
toolsCount += 1;
ModMain.frmToolsLeft.PanItem.Visibility =
toolsCount < 2 && !HiddenForceShow ? Visibility.Collapsed : Visibility.Visible;
}
// 其他入口刷新
if (ModMain.frmMain.pageCurrent == FormMain.PageType.InstanceSelect)
ModMain.frmSelectRight.BtnEmptyDownload_Loaded();
if (ModMain.frmMain.pageCurrent == FormMain.PageType.Launch)
ModMain.frmLaunchLeft.RefreshButtonsUI();
if (ModMain.frmMain.pageCurrent == FormMain.PageType.InstanceSetup &&
ModMain.frmInstanceModDisabled is not null)
ModMain.frmInstanceModDisabled.BtnDownload_Loaded();
}
catch (Exception ex)
{
ModBase.Log(
ex,
"刷新功能隐藏项目失败",
ModBase.LogLevel.Feedback,
userSummary: Lang.Text("Setup.Ui.Error.OperationFailed"));
}
}
// ================= 设置页面协同 =================
private void HiddenSetupMain()
{
var isChecked = (bool)CheckHiddenPageSetup.Checked;
CheckHiddenSetupLaunch.Checked = isChecked;
CheckHiddenSetupUI.Checked = isChecked;
CheckHiddenSetupLauncherLanguage.Checked = isChecked;
CheckHiddenSetupGameManage.Checked = isChecked;
CheckHiddenLauncherMisc.Checked = isChecked;
CheckHiddenSetupJava.Checked = isChecked;
CheckHiddenSetupUpdate.Checked = isChecked;
CheckHiddenSetupGameLink.Checked = isChecked;
CheckHiddenSetupAbout.Checked = isChecked;
CheckHiddenSetupFeedback.Checked = isChecked;
CheckHiddenSetupLog.Checked = isChecked;
}
// ================= 设置页面协同 =================
private void HiddenSetupMain(object sender, bool user)
{
if (!user)
return; // 仅处理用户点击,防止死循环
var isChecked = (bool)CheckHiddenPageSetup.Checked;
CheckHiddenSetupLaunch.Checked = isChecked;
CheckHiddenSetupUI.Checked = isChecked;
CheckHiddenSetupLauncherLanguage.Checked = isChecked;
CheckHiddenSetupGameManage.Checked = isChecked;
CheckHiddenLauncherMisc.Checked = isChecked;
CheckHiddenSetupJava.Checked = isChecked;
CheckHiddenSetupUpdate.Checked = isChecked;
CheckHiddenSetupGameLink.Checked = isChecked;
CheckHiddenSetupAbout.Checked = isChecked;
CheckHiddenSetupFeedback.Checked = isChecked;
CheckHiddenSetupLog.Checked = isChecked;
}
private void HiddenSetupSub(object sender, bool user)
{
if (!user)
return;
var conf = Config.Preference.Hide;
// 判断是否全部勾选
var allChecked = conf.SetupLaunch && conf.SetupUi && conf.SetupLauncherLanguage && conf.SetupJava &&
conf.SetupUpdate && conf.SetupGameLink && conf.SetupAbout && conf.SetupFeedback &&
conf.SetupLog && conf.SetupLauncherMisc && conf.SetupGameManage;
CheckHiddenPageSetup.Checked = allChecked;
}
// ================= 工具页面协同 =================
private void HiddenToolsMain(object sender, bool user)
{
if (!user)
return;
var isChecked = (bool)CheckHiddenPageTools.Checked;
CheckHiddenToolsGameLink.Checked = isChecked;
CheckHiddenToolsTest.Checked = isChecked;
}
private void HiddenToolsSub(object sender, bool user)
{
if (!user)
return;
var conf = Config.Preference.Hide;
var allChecked = conf.ToolsGameLink && conf.ToolsTest;
CheckHiddenPageTools.Checked = allChecked;
}
// 警告提示
private void HiddenHint(object sender, bool user)
{
if (ModAnimation.AniControlEnabled == 0 && sender is MyCheckBox checkBox && checkBox.Checked == true)
HintService.Hint(Lang.Text("Setup.Ui.FeatureHide.TemporaryHint"));
}
#endregion
}
@@ -0,0 +1,172 @@
<local:MyPageRight
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:PCL" xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d" x:Class="PCL.PageSetupUpdate"
PanScroll="{Binding ElementName=PanBack}">
<local:MyScrollViewer VerticalScrollBarVisibility="Auto" HorizontalScrollBarVisibility="Disabled" x:Name="PanBack">
<StackPanel x:Name="PanMain" Margin="25,25,25,10">
<local:MyCard Height="Auto">
<StackPanel Margin="20,15,20,15">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" SharedSizeGroup="Name" />
<ColumnDefinition />
<ColumnDefinition Width="8" />
<ColumnDefinition Width="75" />
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="28" />
<RowDefinition Height="7" />
<RowDefinition Height="28" />
<RowDefinition Height="7" />
<RowDefinition Height="28" />
</Grid.RowDefinitions>
<TextBlock Text="{DynamicResource Setup.Update.Channel.Title}" Grid.Row="0" VerticalAlignment="Center" HorizontalAlignment="Left"
Margin="0,0,25,0" />
<local:MyComboBox x:Name="ComboSystemUpdateChannel" Tag="SystemUpdateChannel" Grid.Column="1"
Grid.ColumnSpan="3" Grid.Row="0"
SelectionChanged="ComboSystemUpdateBranch_SelectionChanged">
<local:MyComboBoxItem Content="{DynamicResource Setup.Update.Channel.Release}"
ToolTip="{DynamicResource Setup.Update.Channel.Release.ToolTip}" />
<local:MyComboBoxItem Content="{DynamicResource Setup.Update.Channel.Beta}"
ToolTip="{DynamicResource Setup.Update.Channel.Beta.ToolTip}" />
<local:MyComboBoxItem Content="{DynamicResource Setup.Update.Channel.Dev}"
ToolTip="{DynamicResource Setup.Update.Channel.Dev.ToolTip}"
Visibility="Collapsed" />
</local:MyComboBox>
<TextBlock Text="{DynamicResource Setup.Update.Auto.Title}" Grid.Row="2" VerticalAlignment="Center" HorizontalAlignment="Left"
Margin="0,0,25,0" />
<local:MyComboBox x:Name="ComboSystemUpdateMode" Tag="SystemUpdateMode" Grid.Column="1"
Grid.ColumnSpan="3" Grid.Row="2"
SelectionChanged="ComboSystemUpdateMode_SelectionChanged">
<local:MyComboBoxItem Content="{DynamicResource Setup.Update.Auto.DownloadAndInstall}" ToolTip="{DynamicResource Setup.Update.Auto.DownloadAndInstall.ToolTip}" />
<local:MyComboBoxItem Content="{DynamicResource Setup.Update.Auto.DownloadAndNotify}" ToolTip="{DynamicResource Setup.Update.Auto.DownloadAndNotify.ToolTip}" />
<local:MyComboBoxItem Content="{DynamicResource Setup.Update.Auto.NotifyOnly}" ToolTip="{DynamicResource Setup.Update.Auto.NotifyOnly.ToolTip}" />
<local:MyComboBoxItem Content="{DynamicResource Setup.Update.Auto.Disabled}" ToolTip="{DynamicResource Setup.Update.Auto.Disabled.ToolTip}" />
</local:MyComboBox>
<TextBlock Text="{DynamicResource Setup.Update.MirrorChyanCdk.Label}" Grid.Row="4" VerticalAlignment="Center"
HorizontalAlignment="Left" Margin="0,0,25,0" />
<PasswordBox x:Name="TextMirrorCDK"
ToolTip="{DynamicResource Setup.Update.MirrorChyanCdk.ToolTip}"
Grid.Row="4" Grid.Column="1"
PasswordChanged="TextMirrorCDK_PasswordChanged" />
<local:MyButton x:Name="BtnGetMirrorCDK" Text="{DynamicResource Setup.Update.MirrorChyanCdk.Get}" Grid.Column="3" Grid.Row="4"
ColorType="Highlight" Click="BtnGetMirrorCDK_Click" />
</Grid>
</StackPanel>
</local:MyCard>
<local:MyCard x:Name="CardUpdate" Margin="0,15">
<StackPanel Margin="20,20,20,20">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="50" />
<ColumnDefinition Width="10" />
<ColumnDefinition Width="1*" />
<ColumnDefinition Width="85" />
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="29" />
<RowDefinition Height="1" />
<RowDefinition Height="20" />
<RowDefinition Height="8" />
<RowDefinition Height="Auto" />
<RowDefinition Height="10" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<!-- <Image Source="/Images/Icons/Tahoe.png" Grid.Column="0" Grid.Row="0" Grid.RowSpan="3" Height="50" Width="50" HorizontalAlignment="Left" VerticalAlignment="Center" /> -->
<local:MyImage x:Name="ImgUpdateIcon" Source="https://www.pclc.cc/img/pcl-ce/icon.webp"
Grid.Column="0" Grid.Row="0" Grid.RowSpan="3" Height="50" Width="50"
HorizontalAlignment="Left" VerticalAlignment="Center" />
<TextBlock x:Name="TextUpdateName" Text="PCL CE 2.14.0" FontWeight="Bold" FontSize="20"
Grid.Row="0" Grid.Column="2" HorizontalAlignment="Left" VerticalAlignment="Bottom" />
<TextBlock x:Name="TextUpdateDesc" Text="by PCL-Community" FontSize="14" Grid.Row="2"
Grid.Column="2" HorizontalAlignment="Left" VerticalAlignment="Top" />
<local:MyButton x:Name="BtnUpdate" Text="{DynamicResource Setup.Update.Install}" ColorType="Highlight" Grid.Row="0"
Grid.RowSpan="2" Grid.Column="3" HorizontalAlignment="Center"
VerticalAlignment="Center" Width="85" Height="30"
Click="BtnUpdate_Click" />
<TextBlock x:Name="TextChangelog"
Text="{DynamicResource Setup.Update.Changelog.Placeholder}"
Grid.Row="4" Grid.Column="0" Grid.ColumnSpan="4" TextWrapping="Wrap" />
<local:MyTextButton x:Name="BtnChangelogDetail" Text="{DynamicResource Setup.Update.Changelog.MoreInfo}" FontWeight="Thin"
Grid.Row="6" Grid.Column="0" Grid.ColumnSpan="4" HorizontalAlignment="Left"
VerticalAlignment="Center" Click="BtnChangelogDetail_Click" />
</Grid>
</StackPanel>
</local:MyCard>
<local:MyCard x:Name="CardCheck" Margin="0,15" Visibility="Collapsed">
<StackPanel Margin="20,20,20,20">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="50" />
<ColumnDefinition Width="10" />
<ColumnDefinition Width="1*" />
<ColumnDefinition Width="80" />
<ColumnDefinition Width="10" />
<ColumnDefinition Width="100" />
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="29" />
<RowDefinition Height="1" />
<RowDefinition Height="20" />
</Grid.RowDefinitions>
<Image Source="pack://application:,,,/Images/icon.png" Grid.Column="0" Grid.Row="0"
Grid.RowSpan="3" Height="50" Width="50" HorizontalAlignment="Left"
VerticalAlignment="Center" />
<!-- <local:MyImage x:Name="ImgUpdateIcon" FallbackSource="pack://application:,,,/images/icon.ico" Source="https://www.pclc.cc/img/pcl-ce/icon.webp" Grid.Column="0" Grid.Row="0" Grid.RowSpan="3" Height="50" Width="50" HorizontalAlignment="Left" VerticalAlignment="Center"/> -->
<TextBlock x:Name="TextCurrentVersion" Text="PCL CE 2.13.4" FontWeight="Bold" FontSize="20"
Grid.Row="0" Grid.Column="2" HorizontalAlignment="Left" VerticalAlignment="Bottom" />
<TextBlock x:Name="TextCurrentDesc" Text="{DynamicResource Setup.Update.Latest}" FontSize="14" Grid.Row="2" Grid.Column="2"
HorizontalAlignment="Left" VerticalAlignment="Top" />
<local:MyButton x:Name="BtnCheckAgain" Text="{DynamicResource Setup.Update.CheckAgain}" ColorType="Highlight" Grid.Row="0"
Grid.RowSpan="2" Grid.Column="3" HorizontalAlignment="Stretch"
VerticalAlignment="Stretch" Click="BtnCheckAgain_OnClick" />
<local:MyButton x:Name="BtnChangelog" Text="{DynamicResource Setup.Update.Changelog.View}" ColorType="Normal" Grid.Row="0"
Grid.RowSpan="2" Grid.Column="5" HorizontalAlignment="Stretch"
VerticalAlignment="Stretch" Click="BtnChangelog_Click" />
</Grid>
</StackPanel>
</local:MyCard>
<local:MyCard x:Name="CardOtherOption" Title="{DynamicResource Setup.Update.OtherOptions.Title}" CanSwap="True" IsSwapped="True"
Visibility="Collapsed">
<StackPanel Margin="20,40,20,20">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="50" />
<ColumnDefinition Width="10" />
<ColumnDefinition Width="1*" />
<ColumnDefinition Width="85" />
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="29" />
<RowDefinition Height="1" />
<RowDefinition Height="20" />
<RowDefinition Height="8" />
<RowDefinition Height="Auto" />
<RowDefinition Height="10" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<Image Source="/Images/Icons/Tahoe.png" Grid.Column="0" Grid.Row="0" Grid.RowSpan="3"
Height="50" Width="50" HorizontalAlignment="Left" VerticalAlignment="Center" />
<!--<local:MyImage x:Name="ImgUpdateIcon" FallbackSource="pack://application:,,,/images/icon.ico" Source="https://www.pclc.cc/img/pcl-ce/icon.webp" Grid.Column="0" Grid.Row="0" Grid.RowSpan="3" Height="50" Width="50" HorizontalAlignment="Left" VerticalAlignment="Center"/>-->
<TextBlock x:Name="TextOptionalUpdateName" Text="AquaCL 3.0.0" FontWeight="Bold" FontSize="20"
Grid.Row="0" Grid.Column="2" HorizontalAlignment="Left" VerticalAlignment="Bottom" />
<TextBlock x:Name="TextOptionalUpdateDesc" Text="20.0 MiB" FontSize="14" Grid.Row="2"
Grid.Column="2" HorizontalAlignment="Left" VerticalAlignment="Top" />
<local:MyButton x:Name="BtnOptionalUpdate" Text="{DynamicResource Setup.Update.Install}" ColorType="Highlight" Grid.Row="0"
Grid.RowSpan="2" Grid.Column="3" HorizontalAlignment="Stretch"
VerticalAlignment="Stretch" />
<TextBlock x:Name="TextOptionalChangelog"
Text="{DynamicResource Setup.Update.OtherOptions.Placeholder}"
Grid.Row="4" Grid.Column="0" Grid.ColumnSpan="4" TextWrapping="Wrap" />
<local:MyTextButton x:Name="BtnOptionalChangelogDetail" Text="{DynamicResource Setup.Update.Changelog.MoreInfo}" FontWeight="Thin"
Grid.Row="6" Grid.Column="0" Grid.ColumnSpan="4" HorizontalAlignment="Left"
VerticalAlignment="Center" />
</Grid>
</StackPanel>
</local:MyCard>
</StackPanel>
</local:MyScrollViewer>
</local:MyPageRight>
@@ -0,0 +1,284 @@
using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;
using PCL.Core.App;
using PCL.Core.Utils;
using PCL.Core.App.Localization;
using PCL.Core.Utils.OS;
namespace PCL;
public partial class PageSetupUpdate
{
public VersionDataModel updateInfo;
public PageSetupUpdate()
{
InitializeComponent();
Loaded += (_, _) => Init();
}
private void Init()
{
ModAnimation.AniControlEnabled += 1;
TextMirrorCDK.Password = Config.Update.MirrorChyanKey;
ComboSystemUpdateChannel.SelectedIndex = (int)Config.Update.UpdateChannel;
ComboSystemUpdateMode.SelectedIndex = (int)Config.Update.UpdateMode;
TextCurrentVersion.Text = "PCL CE " + VersionNameFormat(ModBase.versionBaseName);
ModAnimation.AniControlEnabled -= 1;
CheckUpdate();
}
private async Task<UpdateStatus> IsLatestAsync()
{
try
{
// 修复:使用 dynamic 绕过命名空间重名导致的编译期类型冲突,
// 或者你可以尝试替换为 PCL.Core.App.SemVer.Parse(ModBase.versionBaseName)
if (await UpdateManager.remoteServer.IsLatestAsync(
UpdateManager.IsCurrentVersionBeta ? UpdateChannel.beta : UpdateChannel.stable,
SystemInfo.IsArm64System ? UpdateArch.arm64 : UpdateArch.x64,
SemVer.Parse(ModBase.versionBaseName),
ModBase.versionCode))
{
ModBase.Log("[Update] 已是最新版本");
return UpdateStatus.Latest;
}
ModBase.Log("[Update] 有可用的新版本");
return UpdateStatus.Available;
}
catch (Exception ex)
{
ModBase.Log(
ex,
Lang.Text("Setup.Update.Error.NetworkFailed"),
ModBase.LogLevel.Hint,
userSummary: Lang.Text("Setup.Update.Error.NetworkFailed"));
return UpdateStatus.Error;
}
}
public async void CheckUpdate()
{
ModBase.Log("[Update] 开始检查更新");
CardUpdate.Visibility = Visibility.Collapsed;
CardCheck.Visibility = Visibility.Visible;
TextCurrentDesc.Text = Lang.Text("Setup.Update.Checking");
BtnCheckAgain.IsEnabled = false;
switch (await IsLatestAsync())
{
case UpdateStatus.Available:
{
Exception checkUpdateEx = null;
try
{
updateInfo = UpdateManager.remoteServer.GetLatestVersion(
UpdateManager.IsCurrentVersionBeta
? UpdateChannel.beta
: UpdateChannel.stable, SystemInfo.IsArm64System ? UpdateArch.arm64 : UpdateArch.x64);
TextUpdateName.Text = "PCL CE " + VersionNameFormat(updateInfo.VersionName);
var summary = updateInfo.Changelog.Between("<summary>", "</summary>");
if (!updateInfo.Changelog.Contains("<summary>") || string.IsNullOrWhiteSpace(summary.Trim()))
TextChangelog.Text = Lang.Text("Setup.Update.Changelog.Empty");
else
TextChangelog.Text = summary;
}
catch (Exception ex)
{
checkUpdateEx = ex;
}
BtnCheckAgain.IsEnabled = true;
if (updateInfo is null)
{
TextCurrentDesc.Text = Lang.Text("Setup.Update.CheckFailed");
if (checkUpdateEx is not null)
ModBase.Log(
checkUpdateEx,
"[Update] 检查更新失败",
ModBase.LogLevel.Msgbox,
userSummary: Lang.Text("Update.Check.Failed"));
else
ModBase.Log(
"[Update] 检查更新失败",
ModBase.LogLevel.Msgbox,
userSummary: Lang.Text("Update.Check.Failed"));
return;
}
if (UpdateManager.updateLoader is not null && UpdateManager.updateLoader.State == ModBase.LoadState.Loading)
{
BtnUpdate_Timer();
BtnUpdate.IsEnabled = false;
}
else if (UpdateManager.isUpdateWaitingRestart)
{
BtnUpdate.Text = Lang.Text("Setup.Update.RestartInstall");
BtnUpdate.IsEnabled = true;
}
else
{
BtnUpdate.Text = Lang.Text("Setup.Update.Install");
BtnUpdate.IsEnabled = true;
}
CardUpdate.Visibility = Visibility.Visible;
CardCheck.Visibility = Visibility.Collapsed;
break;
}
case UpdateStatus.Latest:
{
CardUpdate.Visibility = Visibility.Collapsed;
CardCheck.Visibility = Visibility.Visible;
BtnCheckAgain.IsEnabled = true;
TextCurrentDesc.Text = Lang.Text("Setup.Update.Latest");
break;
}
case UpdateStatus.Error:
{
CardUpdate.Visibility = Visibility.Collapsed;
CardCheck.Visibility = Visibility.Visible;
BtnCheckAgain.IsEnabled = true;
TextCurrentDesc.Text = Lang.Text("Setup.Update.CheckFailed");
break;
}
}
}
public void BtnUpdate_Timer()
{
while (UpdateManager.updateLoader is not null && UpdateManager.updateLoader.State == ModBase.LoadState.Loading)
{
ModBase.RunInUi(() => BtnUpdate.Text = Lang.Number(UpdateManager.updateLoader.Progress, "P2"));
Thread.Sleep(200);
}
}
private void BtnUpdate_Click(object sender, MouseButtonEventArgs e)
{
if (UpdateManager.isUpdateWaitingRestart) UpdateManager.UpdateRestart(true);
// 开始更新流程
UpdateManager.UpdateStart(UpdateEnums.UpdateType.UpdateNow);
}
private void BtnChangelogDetail_Click(object sender, EventArgs e)
{
if (updateInfo is null)
ModMain.MyMsgBox(Lang.Text("Setup.Update.Changelog.Unavailable"), Lang.Text("Setup.Update.Changelog.Title"));
else
ModMain.MyMsgBoxMarkdown(updateInfo.Changelog, Lang.Text("Setup.Update.Changelog.Title"));
}
private void ComboSystemUpdateMode_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
if (ModAnimation.AniControlEnabled == 0)
Config.Update.UpdateMode = (LauncherAutoUpdateBehavior)ComboSystemUpdateMode.SelectedIndex;
}
private void ComboSystemUpdateBranch_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
if (ModAnimation.AniControlEnabled != 0)
return;
var isCancelled = false;
switch (ComboSystemUpdateChannel.SelectedIndex)
{
case 0:
{
break;
}
case 1:
{
if (ModMain.MyMsgBox(Lang.Text("Setup.Update.Channel.Beta.Warning.Message"),
Lang.Text("Setup.Update.Channel.Common.Warning.Title"),
Lang.Text("Setup.Update.Channel.Common.Warning.Confirm"),
Lang.Text("Common.Action.Cancel"), isWarn: true) == 2)
isCancelled = true;
else
CheckUpdate();
break;
}
case 2:
{
if (ModMain.MyMsgBox(Lang.Text("Setup.Update.Channel.Dev.Warning.Message"),
Lang.Text("Setup.Update.Channel.Common.Warning.Title"),
Lang.Text("Setup.Update.Channel.Common.Warning.Confirm"),
Lang.Text("Common.Action.Cancel"), isWarn: true) == 2)
{
isCancelled = true;
break;
}
var confirmText = Lang.Text("Setup.Update.Channel.Dev.FinalConfirm.ExpectedInput");
var ret = ModMain.MyMsgBoxInput(
Lang.Text("Setup.Update.Channel.Dev.FinalConfirm.Title"),
Lang.Text("Setup.Update.Channel.Dev.FinalConfirm.Message", confirmText),
button1: Lang.Text("Setup.Update.Channel.Dev.FinalConfirm.Submit"),
button2: Lang.Text("Common.Action.Cancel"), isWarn: true);
if (ret == confirmText)
{
CheckUpdate();
}
else
{
HintService.Hint(Lang.Text("Setup.Update.Channel.Dev.FinalConfirm.WrongInput"));
isCancelled = true;
}
break;
}
}
if (isCancelled)
{
ModAnimation.AniControlEnabled += 1;
ComboSystemUpdateChannel.SelectedItem = e.RemovedItems[0];
ModAnimation.AniControlEnabled -= 1;
}
else
{
Config.Update.UpdateChannel = (Core.App.UpdateChannel)ComboSystemUpdateChannel.SelectedIndex;
}
}
private void TextMirrorCDK_PasswordChanged(object sender, EventArgs e)
{
Config.Update.MirrorChyanKey = TextMirrorCDK.Password;
}
private void BtnGetMirrorCDK_Click(object sender, MouseButtonEventArgs e)
{
ModBase.OpenWebsite("https://mirrorchyan.com/");
}
private void BtnChangelog_Click(object sender, MouseButtonEventArgs e)
{
ModBase.OpenWebsite("https://github.com/PCL-Community/PCL2-CE/releases/v" + ModBase.versionBaseName);
}
public string VersionNameFormat(string str)
{
str = str.Replace("v", "");
if (!str.Contains("-"))
return str;
var add = str.AfterLast("-");
str = str.BeforeLast("-");
return $"{str} {add.Replace(".", " ").Replace("beta", "Beta").Replace("rc", "RC")}";
}
private void BtnCheckAgain_OnClick(object sender, MouseButtonEventArgs e)
{
CheckUpdate();
}
private enum UpdateStatus
{
Checking = 0,
Available = 1,
Error = 2,
Latest = 3
}
}