add!:安全面板

This commit is contained in:
2026-05-01 01:22:35 +08:00
parent efe0bb6ae2
commit cb6af3e21f
5 changed files with 312 additions and 0 deletions
@@ -76,6 +76,13 @@
<ui:FontIcon Icon="{x:Static ui:SegoeFluentIcons.Shield}" />
</ui:SettingsCard.HeaderIcon>
</ui:SettingsCard>
<ui:SettingsCard Header="安全" Description="安全密码与进程保护"
IsClickEnabled="True" Click="QuickNavCard_Click" Tag="SecurityPage">
<ui:SettingsCard.HeaderIcon>
<ui:FontIcon Icon="{x:Static ui:SegoeFluentIcons.Permissions}" />
</ui:SettingsCard.HeaderIcon>
</ui:SettingsCard>
<TextBlock Style="{StaticResource SettingsSectionHeaderTextBlockStyle}"
Text="主界面" />
@@ -0,0 +1,112 @@
<ui:Page x:Class="Ink_Canvas.Windows.SettingsViews.Pages.SecurityPage"
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:Ink_Canvas.Windows.SettingsViews.Pages"
xmlns:ui="http://schemas.inkore.net/lib/ui/wpf/modern"
xmlns:ikw="http://schemas.inkore.net/lib/ui/wpf"
xmlns:sys="clr-namespace:System;assembly=mscorlib"
xmlns:controls="clr-namespace:Ink_Canvas.Controls;assembly=InkCanvas.Controls"
mc:Ignorable="d"
Title="安全">
<ScrollViewer PanningMode="VerticalFirst">
<Grid Margin="59,0,59,0">
<FrameworkElement.Resources>
<sys:Double x:Key="SettingsCardSpacing">4</sys:Double>
<Style x:Key="SettingsSectionHeaderTextBlockStyle"
BasedOn="{StaticResource BodyStrongTextBlockStyle}"
TargetType="TextBlock">
<Style.Setters>
<Setter Property="Margin" Value="1,30,0,6" />
</Style.Setters>
</Style>
</FrameworkElement.Resources>
<Grid>
<ikw:SimpleStackPanel MaxWidth="1000"
HorizontalAlignment="Stretch"
Spacing="{StaticResource SettingsCardSpacing}">
<!-- 安全密码 -->
<TextBlock Style="{StaticResource SettingsSectionHeaderTextBlockStyle}"
Text="安全密码" />
<ui:InfoBar IsClosable="False"
IsOpen="True"
Severity="Informational"
Title="说明"
Message="安全密码默认关闭。开启后可用于退出软件、进入设置与重置配置等操作时的二次验证。" />
<controls:LabeledSettingsCard x:Name="CardPasswordEnabled"
Header="启用安全密码"
Description="开启后需要设置密码"
Icon="{x:Static ui:SegoeFluentIcons.Permissions}"
SwitchName="ToggleSwitchPasswordEnabled"
Toggled="ToggleSwitchPasswordEnabled_Toggled" />
<ui:SettingsCard x:Name="CardPasswordManage"
Header="密码管理"
Description="设置或修改安全密码">
<ui:SettingsCard.HeaderIcon>
<ui:FontIcon Icon="{x:Static ui:SegoeFluentIcons.Lock}" />
</ui:SettingsCard.HeaderIcon>
<Button x:Name="BtnSetOrChangePassword"
Content="设置/修改密码"
MinWidth="120"
Click="BtnSetOrChangePassword_Click" />
</ui:SettingsCard>
<controls:LabeledSettingsCard x:Name="CardRequirePasswordOnExit"
Header="退出软件需要密码"
Description="关闭 InkCanvasForClass 时进行密码验证"
Icon="{x:Static ui:SegoeFluentIcons.SignOut}"
SwitchName="ToggleSwitchRequirePasswordOnExit"
Toggled="ToggleSwitchRequirePasswordOnExit_Toggled" />
<controls:LabeledSettingsCard x:Name="CardRequirePasswordOnEnterSettings"
Header="进入设置需要密码"
Description="打开设置面板/新设置窗口时进行验证"
Icon="{x:Static ui:SegoeFluentIcons.Settings}"
SwitchName="ToggleSwitchRequirePasswordOnEnterSettings"
Toggled="ToggleSwitchRequirePasswordOnEnterSettings_Toggled" />
<controls:LabeledSettingsCard x:Name="CardRequirePasswordOnResetConfig"
Header="重置配置需要密码"
Description="重置 Settings.json 前进行二次验证"
Icon="{x:Static ui:SegoeFluentIcons.Refresh}"
SwitchName="ToggleSwitchRequirePasswordOnResetConfig"
Toggled="ToggleSwitchRequirePasswordOnResetConfig_Toggled" />
<controls:LabeledSettingsCard x:Name="CardRequirePasswordOnModifyOrClearNameList"
Header="修改/清空点名名单需要密码"
Description="对点名名单进行修改或清空前进行验证"
Icon="{x:Static ui:SegoeFluentIcons.People}"
SwitchName="ToggleSwitchRequirePasswordOnModifyOrClearNameList"
Toggled="ToggleSwitchRequirePasswordOnModifyOrClearNameList_Toggled" />
<!-- 进程保护 -->
<TextBlock Style="{StaticResource SettingsSectionHeaderTextBlockStyle}"
Text="进程保护" />
<ui:InfoBar IsClosable="False"
IsOpen="True"
Severity="Informational"
Title="说明"
Message="进程保护默认开启:运行期间保护根目录下的程序文件(exe/dll/config)不被外部修改。" />
<controls:LabeledSettingsCard x:Name="CardEnableProcessProtection"
Header="进程保护"
Description="开启后关键文件会被只读占用"
Icon="{x:Static ui:SegoeFluentIcons.Shield}"
SwitchName="ToggleSwitchEnableProcessProtection"
Toggled="ToggleSwitchEnableProcessProtection_Toggled" />
<Rectangle Height="48" />
</ikw:SimpleStackPanel>
</Grid>
</Grid>
</ScrollViewer>
</ui:Page>
@@ -0,0 +1,183 @@
using Ink_Canvas.Helpers;
using Ink_Canvas.Windows.SettingsViews.Helpers;
using System;
using System.Windows;
using Page = iNKORE.UI.WPF.Modern.Controls.Page;
namespace Ink_Canvas.Windows.SettingsViews.Pages
{
public partial class SecurityPage : Page
{
private bool _isLoaded = false;
public SecurityPage()
{
InitializeComponent();
Loaded += Page_Loaded;
Unloaded += Page_Unloaded;
}
private void Page_Loaded(object sender, RoutedEventArgs e)
{
LoadSettings();
_isLoaded = true;
}
private void Page_Unloaded(object sender, RoutedEventArgs e)
{
_isLoaded = false;
}
private void LoadSettings()
{
_isLoaded = false;
try
{
var settings = SettingsManager.Settings;
if (settings == null) return;
if (settings.Security == null) settings.Security = new Security();
var sec = settings.Security;
CardPasswordEnabled.IsOn = sec.PasswordEnabled;
CardRequirePasswordOnExit.IsOn = sec.RequirePasswordOnExit;
CardRequirePasswordOnEnterSettings.IsOn = sec.RequirePasswordOnEnterSettings;
CardRequirePasswordOnResetConfig.IsOn = sec.RequirePasswordOnResetConfig;
CardRequirePasswordOnModifyOrClearNameList.IsOn = sec.RequirePasswordOnModifyOrClearNameList;
CardEnableProcessProtection.IsOn = sec.EnableProcessProtection;
UpdatePasswordUiState();
}
catch (Exception ex)
{
System.Diagnostics.Debug.WriteLine($"加载安全页面设置时出错: {ex.Message}");
}
_isLoaded = true;
}
private void UpdatePasswordUiState()
{
var sec = SettingsManager.Settings?.Security;
var enabled = sec != null && sec.PasswordEnabled;
if (BtnSetOrChangePassword != null) BtnSetOrChangePassword.IsEnabled = enabled;
CardRequirePasswordOnExit.IsEnabled = enabled;
CardRequirePasswordOnEnterSettings.IsEnabled = enabled;
CardRequirePasswordOnResetConfig.IsEnabled = enabled;
CardRequirePasswordOnModifyOrClearNameList.IsEnabled = enabled;
}
private void SetCardIsOnSilently(Ink_Canvas.Controls.LabeledSettingsCard card, bool value)
{
var prev = _isLoaded;
_isLoaded = false;
try { card.IsOn = value; }
finally { _isLoaded = prev; }
}
private async void ToggleSwitchPasswordEnabled_Toggled(object sender, RoutedEventArgs e)
{
if (!_isLoaded) return;
var settings = SettingsManager.Settings;
if (settings == null) return;
if (settings.Security == null) settings.Security = new Security();
var sec = settings.Security;
bool newState = CardPasswordEnabled.IsOn;
var owner = Window.GetWindow(this);
if (newState)
{
var havePassword = SecurityManager.HasPasswordConfigured(settings);
if (!havePassword)
{
var pwd = await SecurityManager.PromptSetNewPasswordAsync(owner);
if (string.IsNullOrEmpty(pwd))
{
SetCardIsOnSilently(CardPasswordEnabled, false);
return;
}
SecurityManager.SetPassword(settings, pwd);
}
sec.PasswordEnabled = true;
SettingsManager.SaveSettingsToFile();
UpdatePasswordUiState();
}
else
{
if (SecurityManager.HasPasswordConfigured(settings))
{
bool ok = await SecurityManager.PromptAndVerifyAsync(settings, owner,
"关闭安全密码", "请输入当前密码以关闭安全密码功能。");
if (!ok)
{
SetCardIsOnSilently(CardPasswordEnabled, true);
return;
}
}
sec.PasswordEnabled = false;
SecurityManager.ClearPassword(settings);
SettingsManager.SaveSettingsToFile();
UpdatePasswordUiState();
}
}
private async void BtnSetOrChangePassword_Click(object sender, RoutedEventArgs e)
{
var settings = SettingsManager.Settings;
if (settings == null) return;
if (settings.Security == null) settings.Security = new Security();
var owner = Window.GetWindow(this);
var newPwd = await SecurityManager.PromptChangePasswordAsync(settings, owner);
if (!string.IsNullOrEmpty(newPwd))
{
SecurityManager.SetPassword(settings, newPwd);
settings.Security.PasswordEnabled = true;
SettingsManager.SaveSettingsToFile();
SetCardIsOnSilently(CardPasswordEnabled, true);
UpdatePasswordUiState();
}
}
private void ToggleSwitchRequirePasswordOnExit_Toggled(object sender, RoutedEventArgs e)
{
if (!_isLoaded) return;
SettingsManager.Settings.Security.RequirePasswordOnExit = CardRequirePasswordOnExit.IsOn;
SettingsManager.SaveSettingsToFile();
}
private void ToggleSwitchRequirePasswordOnEnterSettings_Toggled(object sender, RoutedEventArgs e)
{
if (!_isLoaded) return;
SettingsManager.Settings.Security.RequirePasswordOnEnterSettings = CardRequirePasswordOnEnterSettings.IsOn;
SettingsManager.SaveSettingsToFile();
}
private void ToggleSwitchRequirePasswordOnResetConfig_Toggled(object sender, RoutedEventArgs e)
{
if (!_isLoaded) return;
SettingsManager.Settings.Security.RequirePasswordOnResetConfig = CardRequirePasswordOnResetConfig.IsOn;
SettingsManager.SaveSettingsToFile();
}
private void ToggleSwitchRequirePasswordOnModifyOrClearNameList_Toggled(object sender, RoutedEventArgs e)
{
if (!_isLoaded) return;
SettingsManager.Settings.Security.RequirePasswordOnModifyOrClearNameList = CardRequirePasswordOnModifyOrClearNameList.IsOn;
SettingsManager.SaveSettingsToFile();
}
private void ToggleSwitchEnableProcessProtection_Toggled(object sender, RoutedEventArgs e)
{
if (!_isLoaded) return;
bool newState = CardEnableProcessProtection.IsOn;
SettingsManager.Settings.Security.EnableProcessProtection = newState;
SettingsManager.SaveSettingsToFile();
ProcessProtectionManager.SetEnabled(newState);
}
}
}
@@ -153,6 +153,15 @@
<ui:FontIcon Icon="{x:Static ui:SegoeFluentIcons.Shield}"/>
</ui:NavigationViewItem.Icon>
</ui:NavigationViewItem>
<ui:NavigationViewItem
x:Name="SecurityPageItem"
Content="安全"
Tag="SecurityPage"
ToolTipService.ToolTip="安全密码与进程保护">
<ui:NavigationViewItem.Icon>
<ui:FontIcon Icon="{x:Static ui:SegoeFluentIcons.Permissions}"/>
</ui:NavigationViewItem.Icon>
</ui:NavigationViewItem>
</ui:NavigationViewItem.MenuItems>
</ui:NavigationViewItem>
@@ -40,6 +40,7 @@ namespace Ink_Canvas.Windows.SettingsViews
{ "HomePage", typeof(HomePage) },
{ "StartupPage", typeof(StartupPage) },
{ "PrivacyPage", typeof(PrivacyPage) },
{ "SecurityPage", typeof(SecurityPage) },
{ "WindowPage", typeof(WindowPage) },
{ "AppearancePage", typeof(AppearancePage) },
{ "UpdatePage", typeof(UpdatePage) },