This commit is contained in:
PrefacedCorg
2026-04-24 10:24:20 +08:00
parent 42854ff924
commit 5266368f79
15 changed files with 887 additions and 564 deletions
@@ -65,7 +65,7 @@
</ui:SettingsCard>
<ui:SettingsExpander Header="{i18n:I18n Key=About_DeviceInfo}"
d:IsExpanded="True">
IsExpanded="True">
<ui:SettingsExpander.HeaderIcon>
<ui:FontIcon Icon="{x:Static ui:SegoeFluentIcons.Devices}" />
</ui:SettingsExpander.HeaderIcon>
@@ -92,29 +92,6 @@
</ui:SettingsExpander.Items>
</ui:SettingsExpander>
<ui:SettingsExpander Header="{i18n:I18n Key=About_PrivacyAndTelemetry}"
d:IsExpanded="True">
<ui:SettingsExpander.HeaderIcon>
<ui:FontIcon Icon="{x:Static ui:SegoeFluentIcons.Shield}" />
</ui:SettingsExpander.HeaderIcon>
<ui:SettingsExpander.Items>
<ui:SettingsCard ContentAlignment="Left">
<CheckBox x:Name="CheckBoxTelemetryPrivacyAccepted"
Content="{i18n:I18n Key=About_PrivacyAgreement}"
Checked="CheckBoxTelemetryPrivacyAccepted_Checked"
Unchecked="CheckBoxTelemetryPrivacyAccepted_Checked" />
</ui:SettingsCard>
<ui:SettingsCard Header="{i18n:I18n Key=About_TelemetryLabel}">
<ComboBox x:Name="ComboBoxTelemetryUploadLevel"
SelectionChanged="ComboBoxTelemetryUploadLevel_SelectionChanged">
<ComboBoxItem Tag="0" Content="{i18n:I18n Key=About_Telemetry_Off}" />
<ComboBoxItem Tag="1" Content="{i18n:I18n Key=About_Telemetry_Basic}" />
<ComboBoxItem Tag="2" Content="{i18n:I18n Key=About_Telemetry_Optional}" />
</ComboBox>
</ui:SettingsCard>
</ui:SettingsExpander.Items>
</ui:SettingsExpander>
<Border Background="{DynamicResource {x:Static ui:ThemeKeys.LayerFillColorDefaultBrushKey}}"
BorderBrush="{DynamicResource {x:Static ui:ThemeKeys.CardStrokeColorDefaultBrushKey}}"
CornerRadius="4" BorderThickness="1" Padding="12,10" TextElement.FontSize="14">
@@ -1,12 +1,9 @@
using Ink_Canvas.Helpers;
using Ink_Canvas.Windows.SettingsViews.Helpers;
using System;
using System.Collections.ObjectModel;
using System.Diagnostics;
using System.IO;
using System.Reflection;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Threading;
namespace Ink_Canvas.Windows.SettingsViews.Pages
@@ -20,9 +17,6 @@ namespace Ink_Canvas.Windows.SettingsViews.Pages
public partial class AboutPage : iNKORE.UI.WPF.Modern.Controls.Page
{
private bool _isLoaded = false;
private bool _isChangingTelemetryInternally;
private bool _isChangingTelemetryPrivacyInternally;
private DispatcherTimer _usageRefreshTimer;
private long _savedTotalSeconds;
private DateTime _sessionStartTime;
@@ -69,7 +63,6 @@ namespace Ink_Canvas.Windows.SettingsViews.Pages
private void AboutPage_Loaded(object sender, RoutedEventArgs e)
{
LoadSettings();
_isLoaded = true;
if (_usageRefreshTimer == null)
{
@@ -101,43 +94,15 @@ namespace Ink_Canvas.Windows.SettingsViews.Pages
private void LoadSettings()
{
_isLoaded = false;
try
{
AppVersionTextBlock.Text = Assembly.GetExecutingAssembly().GetName().Version.ToString();
var settings = SettingsManager.Settings;
if (settings?.Startup != null)
{
int idx = 0;
switch (settings.Startup.TelemetryUploadLevel)
{
case TelemetryUploadLevel.None:
idx = 0;
break;
case TelemetryUploadLevel.Basic:
idx = 1;
break;
case TelemetryUploadLevel.Extended:
idx = 2;
break;
default:
idx = 0;
break;
}
ComboBoxTelemetryUploadLevel.SelectedIndex = idx;
CheckBoxTelemetryPrivacyAccepted.IsChecked = settings.Startup.HasAcceptedTelemetryPrivacy;
}
RefreshDeviceInfo();
}
catch (Exception ex)
{
Debug.WriteLine($"加载关于页面设置时出错: {ex.Message}");
}
_isLoaded = true;
}
private void RefreshDeviceInfo_Click(object sender, RoutedEventArgs e)
@@ -206,219 +171,5 @@ namespace Ink_Canvas.Windows.SettingsViews.Pages
TotalUsageTextBlock.Text = "获取失败";
}
}
private void ComboBoxTelemetryUploadLevel_SelectionChanged(object sender, RoutedEventArgs e)
{
if (!_isLoaded) return;
if (_isChangingTelemetryInternally) return;
var oldLevel = SettingsManager.Settings.Startup.TelemetryUploadLevel;
var item = ComboBoxTelemetryUploadLevel?.SelectedItem as ComboBoxItem;
if (item == null) return;
var tag = item.Tag?.ToString() ?? "0";
var newLevel = TelemetryUploadLevel.None;
switch (tag)
{
case "1":
newLevel = TelemetryUploadLevel.Basic;
break;
case "2":
newLevel = TelemetryUploadLevel.Extended;
break;
default:
newLevel = TelemetryUploadLevel.None;
break;
}
if (newLevel == TelemetryUploadLevel.None &&
oldLevel != TelemetryUploadLevel.None &&
SettingsManager.Settings.Startup.UpdateChannel != UpdateChannel.Release)
{
var result = MessageBox.Show(
"关闭匿名使用数据上传后,将无法继续使用预览/测试通道,系统会自动切换回正式通道(Release)。\n\n是否确认关闭?",
"确认关闭遥测",
MessageBoxButton.YesNo,
MessageBoxImage.Warning);
if (result != MessageBoxResult.Yes)
{
_isChangingTelemetryInternally = true;
try
{
int idx = 0;
switch (oldLevel)
{
case TelemetryUploadLevel.Basic:
idx = 1;
break;
case TelemetryUploadLevel.Extended:
idx = 2;
break;
default:
idx = 0;
break;
}
ComboBoxTelemetryUploadLevel.SelectedIndex = idx;
}
finally
{
_isChangingTelemetryInternally = false;
}
return;
}
SettingsManager.Settings.Startup.UpdateChannel = UpdateChannel.Release;
DeviceIdentifier.UpdateUsageChannel(UpdateChannel.Release);
}
if (newLevel != TelemetryUploadLevel.None && !SettingsManager.Settings.Startup.HasAcceptedTelemetryPrivacy)
{
MessageBox.Show(
"在开启匿名使用数据上传前,请先阅读并勾选上方的隐私说明。",
"需要同意隐私说明",
MessageBoxButton.OK,
MessageBoxImage.Warning);
_isChangingTelemetryInternally = true;
try
{
SettingsManager.Settings.Startup.TelemetryUploadLevel = TelemetryUploadLevel.None;
if (ComboBoxTelemetryUploadLevel != null)
{
ComboBoxTelemetryUploadLevel.SelectedIndex = 0;
}
}
finally
{
_isChangingTelemetryInternally = false;
}
return;
}
SettingsManager.Settings.Startup.TelemetryUploadLevel = newLevel;
SettingsManager.SaveSettingsToFile();
}
private void CheckBoxTelemetryPrivacyAccepted_Checked(object sender, RoutedEventArgs e)
{
if (!_isLoaded) return;
if (_isChangingTelemetryPrivacyInternally) return;
bool isChecked = CheckBoxTelemetryPrivacyAccepted.IsChecked == true;
if (isChecked)
{
if (!PrivacyFileExists())
{
MessageBox.Show(
"未找到隐私说明文件(privacy / privacy.txt),暂时无法启用匿名使用数据上传。",
"隐私说明缺失",
MessageBoxButton.OK,
MessageBoxImage.Warning);
_isChangingTelemetryPrivacyInternally = true;
try
{
CheckBoxTelemetryPrivacyAccepted.IsChecked = false;
}
finally
{
_isChangingTelemetryPrivacyInternally = false;
}
SettingsManager.Settings.Startup.HasAcceptedTelemetryPrivacy = false;
SettingsManager.SaveSettingsToFile();
return;
}
var privacyWindow = new PrivacyAgreementWindow();
bool? dialogResult = privacyWindow.ShowDialog();
if (dialogResult == true && privacyWindow.UserAccepted)
{
SettingsManager.Settings.Startup.HasAcceptedTelemetryPrivacy = true;
SettingsManager.SaveSettingsToFile();
}
else
{
_isChangingTelemetryPrivacyInternally = true;
try
{
CheckBoxTelemetryPrivacyAccepted.IsChecked = false;
}
finally
{
_isChangingTelemetryPrivacyInternally = false;
}
SettingsManager.Settings.Startup.HasAcceptedTelemetryPrivacy = false;
SettingsManager.SaveSettingsToFile();
}
}
else
{
var result = MessageBox.Show(
"取消同意隐私说明后,将关闭匿名使用数据上传,并切回正式通道(Release)。\n\n是否确认?",
"确认取消隐私同意",
MessageBoxButton.YesNo,
MessageBoxImage.Warning);
if (result != MessageBoxResult.Yes)
{
_isChangingTelemetryPrivacyInternally = true;
try
{
CheckBoxTelemetryPrivacyAccepted.IsChecked = true;
}
finally
{
_isChangingTelemetryPrivacyInternally = false;
}
return;
}
_isChangingTelemetryInternally = true;
try
{
SettingsManager.Settings.Startup.TelemetryUploadLevel = TelemetryUploadLevel.None;
if (ComboBoxTelemetryUploadLevel != null)
{
ComboBoxTelemetryUploadLevel.SelectedIndex = 0;
}
}
finally
{
_isChangingTelemetryInternally = false;
}
if (SettingsManager.Settings.Startup.UpdateChannel != UpdateChannel.Release)
{
SettingsManager.Settings.Startup.UpdateChannel = UpdateChannel.Release;
DeviceIdentifier.UpdateUsageChannel(UpdateChannel.Release);
}
SettingsManager.Settings.Startup.HasAcceptedTelemetryPrivacy = false;
SettingsManager.SaveSettingsToFile();
}
}
private static bool PrivacyFileExists()
{
try
{
var assembly = Assembly.GetExecutingAssembly();
var resourceName = "Ink_Canvas.privacy.txt";
using (Stream stream = assembly.GetManifestResourceStream(resourceName))
{
return stream != null;
}
}
catch
{
return false;
}
}
}
}
@@ -174,8 +174,8 @@
<ui:SettingsExpander Header="{i18n:I18n Key=Canvas_BrushAutoRestore}"
Visibility="{Binding IsOn, ElementName=CardBrushAutoRestore, Converter={StaticResource BooleanToVisibilityConverter}}"
d:Visibility="Visible"
d:IsExpanded="True">
IsExpanded="{Binding IsOn, ElementName=CardBrushAutoRestore, Mode=OneWay}"
d:Visibility="Visible">
<ui:SettingsExpander.HeaderIcon>
<ui:FontIcon Icon="{x:Static ui:SegoeFluentIcons.Settings}" />
</ui:SettingsExpander.HeaderIcon>
@@ -283,8 +283,8 @@
<ui:SettingsExpander Header="形状修正"
Visibility="{Binding IsOn, ElementName=CardEnableInkToShape, Converter={StaticResource BooleanToVisibilityConverter}}"
d:Visibility="Visible"
d:IsExpanded="True">
IsExpanded="{Binding IsOn, ElementName=CardEnableInkToShape, Mode=OneWay}"
d:Visibility="Visible">
<ui:SettingsExpander.HeaderIcon>
<ui:FontIcon Icon="{x:Static ui:SegoeFluentIcons.Settings}" />
</ui:SettingsExpander.HeaderIcon>
@@ -15,7 +15,7 @@
<ui:SettingsExpander x:Name="settingsCard" VerticalAlignment="Top"
Description="The SettingsExpander has the same properties as a Card, and you can set SettingsCard as part of the Items collection."
Header="SettingsExpander" IsEnabled="True"
d:IsExpanded="True">
IsExpanded="True">
<ui:SettingsExpander.HeaderIcon>
<ui:FontIcon Glyph="&#xE91B;"/>
@@ -0,0 +1,58 @@
<Page x:Class="Ink_Canvas.Windows.SettingsViews.Pages.MainInterfacePage"
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"
mc:Ignorable="d"
d:DesignHeight="450" d:DesignWidth="800"
Title="主界面">
<ScrollViewer Padding="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="800"
HorizontalAlignment="Stretch"
Spacing="{StaticResource SettingsCardSpacing}">
<TextBlock Style="{StaticResource SettingsSectionHeaderTextBlockStyle}"
Text="主界面" />
<ItemsControl x:Name="SubPageItems">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<ikw:SimpleStackPanel Spacing="{StaticResource SettingsCardSpacing}" />
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.ItemTemplate>
<DataTemplate>
<ui:SettingsCard
Header="{Binding Header}"
Description="{Binding Description}"
IsClickEnabled="True"
Click="SubPageCard_Click"
Tag="{Binding PageTag}">
<ui:SettingsCard.HeaderIcon>
<ui:FontIcon Glyph="{Binding IconGlyph}" />
</ui:SettingsCard.HeaderIcon>
</ui:SettingsCard>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</ikw:SimpleStackPanel>
</Grid>
</ScrollViewer>
</Page>
@@ -0,0 +1,88 @@
using iNKORE.UI.WPF.Modern.Controls;
using System.Collections.ObjectModel;
using System.Windows;
using SWC = System.Windows.Controls;
namespace Ink_Canvas.Windows.SettingsViews.Pages
{
public partial class MainInterfacePage : SWC.Page
{
private readonly ObservableCollection<SubPageNavItem> _subPageItems = new();
public MainInterfacePage()
{
InitializeComponent();
SubPageItems.ItemsSource = _subPageItems;
Loaded += MainInterfacePage_Loaded;
}
private void MainInterfacePage_Loaded(object sender, RoutedEventArgs e)
{
LoadSubPages();
}
private void LoadSubPages()
{
_subPageItems.Clear();
var settingsWindow = Window.GetWindow(this) as SettingsWindow;
if (settingsWindow == null) return;
var navView = settingsWindow.GetNavigationView();
if (navView == null) return;
foreach (var item in navView.MenuItems)
{
if (item is NavigationViewItem navItem)
{
string tag = navItem.Tag as string;
if (tag == "MainInterfacePage" && navItem.MenuItems.Count > 0)
{
foreach (var child in navItem.MenuItems)
{
if (child is NavigationViewItem childItem)
{
string childTag = childItem.Tag as string;
if (!string.IsNullOrEmpty(childTag))
{
string glyph = ExtractIconGlyph(childItem);
string description = SWC.ToolTipService.GetToolTip(childItem) as string
?? $"点击跳转到{childItem.Content}";
_subPageItems.Add(new SubPageNavItem
{
Header = childItem.Content?.ToString() ?? "",
Description = description,
PageTag = childTag,
IconGlyph = glyph
});
}
}
}
break;
}
}
}
}
private string ExtractIconGlyph(NavigationViewItem navItem)
{
if (navItem.Icon is FontIcon fontIcon)
return fontIcon.Glyph ?? "\uE737";
if (navItem.Icon is SymbolIcon symbolIcon)
return char.ConvertFromUtf32((int)symbolIcon.Symbol);
return "\uE737";
}
private void SubPageCard_Click(object sender, RoutedEventArgs e)
{
if (sender is FrameworkElement element && element.Tag is string pageTag)
{
var settingsWindow = Window.GetWindow(this) as SettingsWindow;
settingsWindow?.NavigateToPage(pageTag);
}
}
}
}
@@ -0,0 +1,64 @@
<ui:Page x:Class="Ink_Canvas.Windows.SettingsViews.Pages.PrivacyPage"
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:i18n="clr-namespace:Ink_Canvas.MarkupExtensions"
xmlns:sys="clr-namespace:System;assembly=mscorlib"
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="{i18n:I18n Key=About_PrivacyAndTelemetry}" />
<ui:SettingsExpander Header="{i18n:I18n Key=About_PrivacyAndTelemetry}"
IsExpanded="True">
<ui:SettingsExpander.HeaderIcon>
<ui:FontIcon Icon="{x:Static ui:SegoeFluentIcons.Shield}" />
</ui:SettingsExpander.HeaderIcon>
<ui:SettingsExpander.Items>
<ui:SettingsCard ContentAlignment="Left">
<CheckBox x:Name="CheckBoxTelemetryPrivacyAccepted"
Content="{i18n:I18n Key=About_PrivacyAgreement}"
Checked="CheckBoxTelemetryPrivacyAccepted_Checked"
Unchecked="CheckBoxTelemetryPrivacyAccepted_Checked" />
</ui:SettingsCard>
<ui:SettingsCard Header="{i18n:I18n Key=About_TelemetryLabel}">
<ComboBox x:Name="ComboBoxTelemetryUploadLevel"
SelectionChanged="ComboBoxTelemetryUploadLevel_SelectionChanged">
<ComboBoxItem Tag="0" Content="{i18n:I18n Key=About_Telemetry_Off}" />
<ComboBoxItem Tag="1" Content="{i18n:I18n Key=About_Telemetry_Basic}" />
<ComboBoxItem Tag="2" Content="{i18n:I18n Key=About_Telemetry_Optional}" />
</ComboBox>
</ui:SettingsCard>
</ui:SettingsExpander.Items>
</ui:SettingsExpander>
<Rectangle Height="48" />
</ikw:SimpleStackPanel>
</Grid>
</Grid>
</ScrollViewer>
</ui:Page>
@@ -0,0 +1,279 @@
using Ink_Canvas.Helpers;
using Ink_Canvas.Windows.SettingsViews.Helpers;
using System;
using System.IO;
using System.Reflection;
using System.Windows;
using System.Windows.Controls;
namespace Ink_Canvas.Windows.SettingsViews.Pages
{
public partial class PrivacyPage : iNKORE.UI.WPF.Modern.Controls.Page
{
private bool _isLoaded = false;
private bool _isChangingTelemetryInternally;
private bool _isChangingTelemetryPrivacyInternally;
public PrivacyPage()
{
InitializeComponent();
Loaded += PrivacyPage_Loaded;
}
private void PrivacyPage_Loaded(object sender, RoutedEventArgs e)
{
LoadSettings();
_isLoaded = true;
}
private void LoadSettings()
{
_isLoaded = false;
try
{
var settings = SettingsManager.Settings;
if (settings?.Startup != null)
{
int idx = 0;
switch (settings.Startup.TelemetryUploadLevel)
{
case TelemetryUploadLevel.None:
idx = 0;
break;
case TelemetryUploadLevel.Basic:
idx = 1;
break;
case TelemetryUploadLevel.Extended:
idx = 2;
break;
default:
idx = 0;
break;
}
ComboBoxTelemetryUploadLevel.SelectedIndex = idx;
CheckBoxTelemetryPrivacyAccepted.IsChecked = settings.Startup.HasAcceptedTelemetryPrivacy;
}
}
catch (Exception ex)
{
System.Diagnostics.Debug.WriteLine($"加载隐私页面设置时出错: {ex.Message}");
}
_isLoaded = true;
}
private void ComboBoxTelemetryUploadLevel_SelectionChanged(object sender, RoutedEventArgs e)
{
if (!_isLoaded) return;
if (_isChangingTelemetryInternally) return;
var oldLevel = SettingsManager.Settings.Startup.TelemetryUploadLevel;
var item = ComboBoxTelemetryUploadLevel?.SelectedItem as ComboBoxItem;
if (item == null) return;
var tag = item.Tag?.ToString() ?? "0";
var newLevel = TelemetryUploadLevel.None;
switch (tag)
{
case "1":
newLevel = TelemetryUploadLevel.Basic;
break;
case "2":
newLevel = TelemetryUploadLevel.Extended;
break;
default:
newLevel = TelemetryUploadLevel.None;
break;
}
if (newLevel == TelemetryUploadLevel.None &&
oldLevel != TelemetryUploadLevel.None &&
SettingsManager.Settings.Startup.UpdateChannel != UpdateChannel.Release)
{
var result = MessageBox.Show(
"关闭匿名使用数据上传后,将无法继续使用预览/测试通道,系统会自动切换回正式通道(Release)。\n\n是否确认关闭?",
"确认关闭遥测",
MessageBoxButton.YesNo,
MessageBoxImage.Warning);
if (result != MessageBoxResult.Yes)
{
_isChangingTelemetryInternally = true;
try
{
int idx = 0;
switch (oldLevel)
{
case TelemetryUploadLevel.Basic:
idx = 1;
break;
case TelemetryUploadLevel.Extended:
idx = 2;
break;
default:
idx = 0;
break;
}
ComboBoxTelemetryUploadLevel.SelectedIndex = idx;
}
finally
{
_isChangingTelemetryInternally = false;
}
return;
}
SettingsManager.Settings.Startup.UpdateChannel = UpdateChannel.Release;
DeviceIdentifier.UpdateUsageChannel(UpdateChannel.Release);
}
if (newLevel != TelemetryUploadLevel.None && !SettingsManager.Settings.Startup.HasAcceptedTelemetryPrivacy)
{
MessageBox.Show(
"在开启匿名使用数据上传前,请先阅读并勾选上方的隐私说明。",
"需要同意隐私说明",
MessageBoxButton.OK,
MessageBoxImage.Warning);
_isChangingTelemetryInternally = true;
try
{
SettingsManager.Settings.Startup.TelemetryUploadLevel = TelemetryUploadLevel.None;
if (ComboBoxTelemetryUploadLevel != null)
{
ComboBoxTelemetryUploadLevel.SelectedIndex = 0;
}
}
finally
{
_isChangingTelemetryInternally = false;
}
return;
}
SettingsManager.Settings.Startup.TelemetryUploadLevel = newLevel;
SettingsManager.SaveSettingsToFile();
}
private void CheckBoxTelemetryPrivacyAccepted_Checked(object sender, RoutedEventArgs e)
{
if (!_isLoaded) return;
if (_isChangingTelemetryPrivacyInternally) return;
bool isChecked = CheckBoxTelemetryPrivacyAccepted.IsChecked == true;
if (isChecked)
{
if (!PrivacyFileExists())
{
MessageBox.Show(
"未找到隐私说明文件(privacy / privacy.txt),暂时无法启用匿名使用数据上传。",
"隐私说明缺失",
MessageBoxButton.OK,
MessageBoxImage.Warning);
_isChangingTelemetryPrivacyInternally = true;
try
{
CheckBoxTelemetryPrivacyAccepted.IsChecked = false;
}
finally
{
_isChangingTelemetryPrivacyInternally = false;
}
SettingsManager.Settings.Startup.HasAcceptedTelemetryPrivacy = false;
SettingsManager.SaveSettingsToFile();
return;
}
var privacyWindow = new PrivacyAgreementWindow();
bool? dialogResult = privacyWindow.ShowDialog();
if (dialogResult == true && privacyWindow.UserAccepted)
{
SettingsManager.Settings.Startup.HasAcceptedTelemetryPrivacy = true;
SettingsManager.SaveSettingsToFile();
}
else
{
_isChangingTelemetryPrivacyInternally = true;
try
{
CheckBoxTelemetryPrivacyAccepted.IsChecked = false;
}
finally
{
_isChangingTelemetryPrivacyInternally = false;
}
SettingsManager.Settings.Startup.HasAcceptedTelemetryPrivacy = false;
SettingsManager.SaveSettingsToFile();
}
}
else
{
var result = MessageBox.Show(
"取消同意隐私说明后,将关闭匿名使用数据上传,并切回正式通道(Release)。\n\n是否确认?",
"确认取消隐私同意",
MessageBoxButton.YesNo,
MessageBoxImage.Warning);
if (result != MessageBoxResult.Yes)
{
_isChangingTelemetryPrivacyInternally = true;
try
{
CheckBoxTelemetryPrivacyAccepted.IsChecked = true;
}
finally
{
_isChangingTelemetryPrivacyInternally = false;
}
return;
}
_isChangingTelemetryInternally = true;
try
{
SettingsManager.Settings.Startup.TelemetryUploadLevel = TelemetryUploadLevel.None;
if (ComboBoxTelemetryUploadLevel != null)
{
ComboBoxTelemetryUploadLevel.SelectedIndex = 0;
}
}
finally
{
_isChangingTelemetryInternally = false;
}
if (SettingsManager.Settings.Startup.UpdateChannel != UpdateChannel.Release)
{
SettingsManager.Settings.Startup.UpdateChannel = UpdateChannel.Release;
DeviceIdentifier.UpdateUsageChannel(UpdateChannel.Release);
}
SettingsManager.Settings.Startup.HasAcceptedTelemetryPrivacy = false;
SettingsManager.SaveSettingsToFile();
}
}
private static bool PrivacyFileExists()
{
try
{
var assembly = Assembly.GetExecutingAssembly();
var resourceName = "Ink_Canvas.privacy.txt";
using (Stream stream = assembly.GetManifestResourceStream(resourceName))
{
return stream != null;
}
}
catch
{
return false;
}
}
}
}
@@ -1,25 +1,22 @@
<ui:Page x:Class="Ink_Canvas.Windows.SettingsViews.Pages.StartupPage"
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: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:helpers="clr-namespace:Ink_Canvas.Windows.SettingsViews.Helpers"
xmlns:ui="http://schemas.inkore.net/lib/ui/wpf/modern"
xmlns:ikw="http://schemas.inkore.net/lib/ui/wpf"
xmlns:i18n="clr-namespace:Ink_Canvas.MarkupExtensions"
xmlns:sys="clr-namespace:System;assembly=mscorlib"
xmlns:controls="clr-namespace:Ink_Canvas.Controls;assembly=InkCanvas.Controls"
xmlns:c="clr-namespace:Ink_Canvas.Converter"
mc:Ignorable="d"
Title="启动">
<ScrollViewer PanningMode="VerticalFirst">
<Grid Margin="59,0,59,0">
<FrameworkElement.Resources>
<sys:Double x:Key="SettingsCardSpacing">4</sys:Double>
<c:BooleanToVisibilityConverter x:Key="BooleanToVisibilityConverter" />
<Style x:Key="SettingsSectionHeaderTextBlockStyle"
BasedOn="{StaticResource BodyStrongTextBlockStyle}"
TargetType="TextBlock">
@@ -33,70 +30,6 @@
HorizontalAlignment="Stretch"
Spacing="{StaticResource SettingsCardSpacing}">
<!-- 窗口设置 -->
<TextBlock Style="{StaticResource SettingsSectionHeaderTextBlockStyle}"
Text="窗口设置" />
<!-- 窗口无焦点模式 -->
<controls:LabeledSettingsCard x:Name="CardNoFocusMode"
Header="{i18n:I18n Key=Startup_NoFocusMode}"
Description="{i18n:I18n Key=Startup_NoFocusModeHint}"
Icon="{x:Static ui:SegoeFluentIcons.View}"
SwitchName="ToggleSwitchNoFocusMode"
Toggled="ToggleSwitchNoFocusMode_Toggled" />
<!-- 窗口无边框模式 -->
<controls:LabeledSettingsCard x:Name="CardWindowMode"
Header="{i18n:I18n Key=Startup_NoBorderMode}"
Description="{i18n:I18n Key=Startup_NoBorderModeHint}"
Icon="{x:Static ui:SegoeFluentIcons.FullScreen}"
SwitchName="ToggleSwitchWindowMode"
Toggled="ToggleSwitchWindowMode_Toggled" />
<!-- 窗口置顶 -->
<ui:SettingsExpander x:Name="ExpanderAlwaysOnTop"
Header="{i18n:I18n Key=Startup_TopMost}"
Description="{i18n:I18n Key=Startup_TopMostHint}"
d:IsExpanded="True">
<ui:SettingsExpander.HeaderIcon>
<ui:FontIcon Icon="{x:Static ui:SegoeFluentIcons.Pinned}" />
</ui:SettingsExpander.HeaderIcon>
<ui:ToggleSwitch x:Name="ToggleSwitchAlwaysOnTop"
OnContent="{DynamicResource Common_On}"
OffContent="{DynamicResource Common_Off}"
Toggled="ToggleSwitchAlwaysOnTop_Toggled" />
<ui:SettingsExpander.ItemTemplate>
<helpers:TopMostModeTemplateSelector>
<helpers:TopMostModeTemplateSelector.SelectionTemplate>
<DataTemplate>
<ui:SettingsCard Header="{i18n:I18n Key=Startup_TopMostMode}">
<StackPanel Orientation="Horizontal">
<RadioButton Content="{i18n:I18n Key=Startup_TopMostMode_Normal}"
GroupName="TopMostMode"
Checked="RadioTopMostNormal_Checked"
Loaded="RadioTopMostNormal_Loaded"
Margin="0,0,16,0" />
<RadioButton Content="{i18n:I18n Key=Startup_TopMostMode_UIA}"
GroupName="TopMostMode"
Checked="RadioTopMostUIA_Checked"
Loaded="RadioTopMostUIA_Loaded" />
</StackPanel>
</ui:SettingsCard>
</DataTemplate>
</helpers:TopMostModeTemplateSelector.SelectionTemplate>
<helpers:TopMostModeTemplateSelector.ButtonTemplate>
<DataTemplate>
<ui:SettingsCard Header="{Binding ButtonHeader}">
<Button Content="{Binding ButtonContent}"
Click="BtnRestart_Click"
Tag="{Binding RestartAsAdmin}" />
</ui:SettingsCard>
</DataTemplate>
</helpers:TopMostModeTemplateSelector.ButtonTemplate>
</helpers:TopMostModeTemplateSelector>
</ui:SettingsExpander.ItemTemplate>
</ui:SettingsExpander>
<!-- 启动设置 -->
<TextBlock Style="{StaticResource SettingsSectionHeaderTextBlockStyle}"
Text="启动设置" />
@@ -1,20 +1,14 @@
using Ink_Canvas.Helpers;
using Ink_Canvas.Windows.SettingsViews.Helpers;
using System;
using System.Collections.ObjectModel;
using System.Diagnostics;
using System.Windows;
using System.Windows.Controls;
namespace Ink_Canvas.Windows.SettingsViews.Pages
{
public partial class StartupPage : iNKORE.UI.WPF.Modern.Controls.Page
{
private bool _isLoaded = false;
private bool _isAdmin = false;
private RadioButton _radioNormal;
private RadioButton _radioUIA;
private readonly ObservableCollection<object> _topMostModeItems = new();
public StartupPage()
{
@@ -31,37 +25,10 @@ namespace Ink_Canvas.Windows.SettingsViews.Pages
private void LoadSettings()
{
_isLoaded = false;
_isAdmin = AppRestartHelper.IsRunningAsAdmin();
try
{
var settings = SettingsManager.Settings;
if (settings.Advanced != null)
{
CardNoFocusMode.IsOn = settings.Advanced.IsNoFocusMode;
CardWindowMode.IsOn = settings.Advanced.WindowMode;
ToggleSwitchAlwaysOnTop.IsOn = settings.Advanced.IsAlwaysOnTop;
_topMostModeItems.Clear();
_topMostModeItems.Add(new TopMostModeSelectionItem());
var btnItem = _isAdmin
? new TopMostModeButtonItem
{
ButtonHeader = Properties.Strings.GetString("Startup_TopMostMode_RestartAsNormal"),
ButtonContent = Properties.Strings.GetString("Startup_TopMostMode_RestartAsNormal"),
RestartAsAdmin = false
}
: new TopMostModeButtonItem
{
ButtonHeader = Properties.Strings.GetString("Startup_TopMostMode_RestartAsAdmin"),
ButtonContent = Properties.Strings.GetString("Startup_TopMostMode_RestartAsAdmin"),
RestartAsAdmin = true
};
_topMostModeItems.Add(btnItem);
ExpanderAlwaysOnTop.ItemsSource = _topMostModeItems;
}
bool runAtStartup = AutoStartHelper.IsAutoStartEnabled("Ink Canvas Annotation");
CardRunAtStartup.IsOn = runAtStartup;
@@ -84,187 +51,6 @@ namespace Ink_Canvas.Windows.SettingsViews.Pages
_isLoaded = true;
}
private void UpdateRadioButtons()
{
if (_radioNormal == null || _radioUIA == null) return;
bool wasLoaded = _isLoaded;
_isLoaded = false;
_radioNormal.IsEnabled = _isAdmin;
_radioUIA.IsEnabled = _isAdmin;
if (_isAdmin && SettingsManager.Settings.Advanced.EnableUIAccessTopMost)
_radioUIA.IsChecked = true;
else
_radioNormal.IsChecked = true;
_isLoaded = wasLoaded;
}
private void RadioTopMostNormal_Loaded(object sender, RoutedEventArgs e)
{
_radioNormal = sender as RadioButton;
UpdateRadioButtons();
}
private void RadioTopMostUIA_Loaded(object sender, RoutedEventArgs e)
{
_radioUIA = sender as RadioButton;
UpdateRadioButtons();
}
#region
private void ToggleSwitchNoFocusMode_Toggled(object sender, RoutedEventArgs e)
{
if (!_isLoaded) return;
try
{
bool newState = CardNoFocusMode.IsOn;
SettingsManager.Settings.Advanced.IsNoFocusMode = newState;
SettingsManager.SaveSettingsToFile();
var window = Application.Current.MainWindow;
if (window != null)
{
WindowSettingsHelper.ApplyNoFocusMode(window);
if (SettingsManager.Settings.Advanced.IsAlwaysOnTop)
{
WindowSettingsHelper.ApplyAlwaysOnTop(window);
}
}
}
catch (Exception ex)
{
Debug.WriteLine($"设置窗口无焦点模式时出错: {ex.Message}");
}
}
private void ToggleSwitchWindowMode_Toggled(object sender, RoutedEventArgs e)
{
if (!_isLoaded) return;
try
{
bool newState = CardWindowMode.IsOn;
SettingsManager.Settings.Advanced.WindowMode = newState;
SettingsManager.SaveSettingsToFile();
var window = Application.Current.MainWindow;
if (window != null)
{
WindowSettingsHelper.SetWindowMode(window);
}
}
catch (Exception ex)
{
Debug.WriteLine($"设置窗口无边框模式时出错: {ex.Message}");
}
}
private void ToggleSwitchAlwaysOnTop_Toggled(object sender, RoutedEventArgs e)
{
if (!_isLoaded) return;
try
{
bool newState = ToggleSwitchAlwaysOnTop.IsOn;
SettingsManager.Settings.Advanced.IsAlwaysOnTop = newState;
SettingsManager.SaveSettingsToFile();
var window = Application.Current.MainWindow;
if (window != null)
{
WindowSettingsHelper.ApplyAlwaysOnTop(window);
if (!newState && SettingsManager.Settings.Advanced.EnableUIAccessTopMost)
{
SettingsManager.Settings.Advanced.EnableUIAccessTopMost = false;
App.IsUIAccessTopMostEnabled = false;
WindowSettingsHelper.ApplyUIAccessTopMost(window);
SettingsManager.SaveSettingsToFile();
if (_radioNormal != null) _radioNormal.IsChecked = true;
}
}
}
catch (Exception ex)
{
Debug.WriteLine($"设置窗口置顶时出错: {ex.Message}");
}
}
private void RadioTopMostNormal_Checked(object sender, RoutedEventArgs e)
{
if (!_isLoaded) return;
try
{
SettingsManager.Settings.Advanced.EnableUIAccessTopMost = false;
SettingsManager.SaveSettingsToFile();
App.IsUIAccessTopMostEnabled = false;
var msg = Properties.Strings.GetString("Startup_TopMostMode_Normal_RestartRequired");
var result = System.Windows.MessageBox.Show(msg, "Ink Canvas", MessageBoxButton.YesNo, MessageBoxImage.Question);
if (result == MessageBoxResult.Yes)
{
AppRestartHelper.RestartWithCurrentPrivileges();
}
}
catch (Exception ex)
{
Debug.WriteLine($"设置普通置顶模式时出错: {ex.Message}");
}
}
private void RadioTopMostUIA_Checked(object sender, RoutedEventArgs e)
{
if (!_isLoaded) return;
try
{
SettingsManager.Settings.Advanced.EnableUIAccessTopMost = true;
if (!SettingsManager.Settings.Advanced.IsAlwaysOnTop)
{
SettingsManager.Settings.Advanced.IsAlwaysOnTop = true;
ToggleSwitchAlwaysOnTop.IsOn = true;
}
SettingsManager.SaveSettingsToFile();
var msg = Properties.Strings.GetString("Startup_TopMostMode_UIA_RestartRequired");
var result = System.Windows.MessageBox.Show(msg, "Ink Canvas", MessageBoxButton.YesNo, MessageBoxImage.Question);
if (result == MessageBoxResult.Yes)
{
App.IsUIAccessTopMostEnabled = true;
AppRestartHelper.RestartAsAdmin();
}
}
catch (Exception ex)
{
Debug.WriteLine($"设置UIA置顶模式时出错: {ex.Message}");
}
}
private void BtnRestart_Click(object sender, RoutedEventArgs e)
{
if (sender is Button btn && btn.Tag is bool asAdmin)
{
AppRestartHelper.RestartApp(asAdmin);
}
}
#endregion
#region
private void ToggleSwitchRunAtStartup_Toggled(object sender, RoutedEventArgs e)
@@ -54,8 +54,8 @@
<ui:SettingsExpander x:Name="ExpanderSilentUpdateTime"
Header="{i18n:I18n Key=Startup_SilentUpdateTimePeriod}"
Visibility="{Binding IsOn, ElementName=CardSilentUpdate, Converter={StaticResource BooleanToVisibilityConverter}}"
d:Visibility="Visible"
d:IsExpanded="True">
IsExpanded="{Binding IsOn, ElementName=CardSilentUpdate, Mode=OneWay}"
d:Visibility="Visible">
<ui:SettingsExpander.HeaderIcon>
<ui:FontIcon Icon="{x:Static ui:SegoeFluentIcons.Settings}" />
</ui:SettingsExpander.HeaderIcon>
@@ -0,0 +1,102 @@
<ui:Page x:Class="Ink_Canvas.Windows.SettingsViews.Pages.WindowPage"
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:helpers="clr-namespace:Ink_Canvas.Windows.SettingsViews.Helpers"
xmlns:ui="http://schemas.inkore.net/lib/ui/wpf/modern"
xmlns:ikw="http://schemas.inkore.net/lib/ui/wpf"
xmlns:i18n="clr-namespace:Ink_Canvas.MarkupExtensions"
xmlns:sys="clr-namespace:System;assembly=mscorlib"
xmlns:controls="clr-namespace:Ink_Canvas.Controls;assembly=InkCanvas.Controls"
xmlns:c="clr-namespace:Ink_Canvas.Converter"
mc:Ignorable="d"
Title="窗口">
<ScrollViewer PanningMode="VerticalFirst">
<Grid Margin="59,0,59,0">
<FrameworkElement.Resources>
<sys:Double x:Key="SettingsCardSpacing">4</sys:Double>
<c:BooleanToVisibilityConverter x:Key="BooleanToVisibilityConverter" />
<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="窗口设置" />
<controls:LabeledSettingsCard x:Name="CardNoFocusMode"
Header="{i18n:I18n Key=Startup_NoFocusMode}"
Description="{i18n:I18n Key=Startup_NoFocusModeHint}"
Icon="{x:Static ui:SegoeFluentIcons.View}"
SwitchName="ToggleSwitchNoFocusMode"
Toggled="ToggleSwitchNoFocusMode_Toggled" />
<controls:LabeledSettingsCard x:Name="CardWindowMode"
Header="{i18n:I18n Key=Startup_NoBorderMode}"
Description="{i18n:I18n Key=Startup_NoBorderModeHint}"
Icon="{x:Static ui:SegoeFluentIcons.FullScreen}"
SwitchName="ToggleSwitchWindowMode"
Toggled="ToggleSwitchWindowMode_Toggled" />
<ui:SettingsExpander x:Name="ExpanderAlwaysOnTop"
Header="{i18n:I18n Key=Startup_TopMost}"
Description="{i18n:I18n Key=Startup_TopMostHint}"
IsExpanded="{Binding IsOn, ElementName=ToggleSwitchAlwaysOnTop, Mode=OneWay}">
<ui:SettingsExpander.HeaderIcon>
<ui:FontIcon Icon="{x:Static ui:SegoeFluentIcons.Pinned}" />
</ui:SettingsExpander.HeaderIcon>
<ui:ToggleSwitch x:Name="ToggleSwitchAlwaysOnTop"
OnContent="{DynamicResource Common_On}"
OffContent="{DynamicResource Common_Off}"
Toggled="ToggleSwitchAlwaysOnTop_Toggled" />
<ui:SettingsExpander.ItemTemplate>
<helpers:TopMostModeTemplateSelector>
<helpers:TopMostModeTemplateSelector.SelectionTemplate>
<DataTemplate>
<ui:SettingsCard Header="{i18n:I18n Key=Startup_TopMostMode}">
<StackPanel Orientation="Horizontal">
<RadioButton Content="{i18n:I18n Key=Startup_TopMostMode_Normal}"
GroupName="TopMostMode"
Checked="RadioTopMostNormal_Checked"
Loaded="RadioTopMostNormal_Loaded"
Margin="0,0,16,0" />
<RadioButton Content="{i18n:I18n Key=Startup_TopMostMode_UIA}"
GroupName="TopMostMode"
Checked="RadioTopMostUIA_Checked"
Loaded="RadioTopMostUIA_Loaded" />
</StackPanel>
</ui:SettingsCard>
</DataTemplate>
</helpers:TopMostModeTemplateSelector.SelectionTemplate>
<helpers:TopMostModeTemplateSelector.ButtonTemplate>
<DataTemplate>
<ui:SettingsCard Header="{Binding ButtonHeader}">
<Button Content="{Binding ButtonContent}"
Click="BtnRestart_Click"
Tag="{Binding RestartAsAdmin}" />
</ui:SettingsCard>
</DataTemplate>
</helpers:TopMostModeTemplateSelector.ButtonTemplate>
</helpers:TopMostModeTemplateSelector>
</ui:SettingsExpander.ItemTemplate>
</ui:SettingsExpander>
<Rectangle Height="48" />
</ikw:SimpleStackPanel>
</Grid>
</Grid>
</ScrollViewer>
</ui:Page>
@@ -0,0 +1,251 @@
using Ink_Canvas.Helpers;
using Ink_Canvas.Windows.SettingsViews.Helpers;
using System;
using System.Collections.ObjectModel;
using System.Diagnostics;
using System.Windows;
using System.Windows.Controls;
namespace Ink_Canvas.Windows.SettingsViews.Pages
{
public partial class WindowPage : iNKORE.UI.WPF.Modern.Controls.Page
{
private bool _isLoaded = false;
private bool _isAdmin = false;
private RadioButton _radioNormal;
private RadioButton _radioUIA;
private readonly ObservableCollection<object> _topMostModeItems = new();
public WindowPage()
{
InitializeComponent();
Loaded += WindowPage_Loaded;
}
private void WindowPage_Loaded(object sender, RoutedEventArgs e)
{
LoadSettings();
_isLoaded = true;
}
private void LoadSettings()
{
_isLoaded = false;
_isAdmin = AppRestartHelper.IsRunningAsAdmin();
try
{
var settings = SettingsManager.Settings;
if (settings.Advanced != null)
{
CardNoFocusMode.IsOn = settings.Advanced.IsNoFocusMode;
CardWindowMode.IsOn = settings.Advanced.WindowMode;
ToggleSwitchAlwaysOnTop.IsOn = settings.Advanced.IsAlwaysOnTop;
_topMostModeItems.Clear();
_topMostModeItems.Add(new TopMostModeSelectionItem());
var btnItem = _isAdmin
? new TopMostModeButtonItem
{
ButtonHeader = Properties.Strings.GetString("Startup_TopMostMode_RestartAsNormal"),
ButtonContent = Properties.Strings.GetString("Startup_TopMostMode_RestartAsNormal"),
RestartAsAdmin = false
}
: new TopMostModeButtonItem
{
ButtonHeader = Properties.Strings.GetString("Startup_TopMostMode_RestartAsAdmin"),
ButtonContent = Properties.Strings.GetString("Startup_TopMostMode_RestartAsAdmin"),
RestartAsAdmin = true
};
_topMostModeItems.Add(btnItem);
ExpanderAlwaysOnTop.ItemsSource = _topMostModeItems;
}
}
catch (Exception ex)
{
Debug.WriteLine($"加载窗口设置时出错: {ex.Message}");
}
_isLoaded = true;
}
private void UpdateRadioButtons()
{
if (_radioNormal == null || _radioUIA == null) return;
bool wasLoaded = _isLoaded;
_isLoaded = false;
_radioNormal.IsEnabled = _isAdmin;
_radioUIA.IsEnabled = _isAdmin;
if (_isAdmin && SettingsManager.Settings.Advanced.EnableUIAccessTopMost)
_radioUIA.IsChecked = true;
else
_radioNormal.IsChecked = true;
_isLoaded = wasLoaded;
}
private void RadioTopMostNormal_Loaded(object sender, RoutedEventArgs e)
{
_radioNormal = sender as RadioButton;
UpdateRadioButtons();
}
private void RadioTopMostUIA_Loaded(object sender, RoutedEventArgs e)
{
_radioUIA = sender as RadioButton;
UpdateRadioButtons();
}
private void ToggleSwitchNoFocusMode_Toggled(object sender, RoutedEventArgs e)
{
if (!_isLoaded) return;
try
{
bool newState = CardNoFocusMode.IsOn;
SettingsManager.Settings.Advanced.IsNoFocusMode = newState;
SettingsManager.SaveSettingsToFile();
var window = Application.Current.MainWindow;
if (window != null)
{
WindowSettingsHelper.ApplyNoFocusMode(window);
if (SettingsManager.Settings.Advanced.IsAlwaysOnTop)
{
WindowSettingsHelper.ApplyAlwaysOnTop(window);
}
}
}
catch (Exception ex)
{
Debug.WriteLine($"设置窗口无焦点模式时出错: {ex.Message}");
}
}
private void ToggleSwitchWindowMode_Toggled(object sender, RoutedEventArgs e)
{
if (!_isLoaded) return;
try
{
bool newState = CardWindowMode.IsOn;
SettingsManager.Settings.Advanced.WindowMode = newState;
SettingsManager.SaveSettingsToFile();
var window = Application.Current.MainWindow;
if (window != null)
{
WindowSettingsHelper.SetWindowMode(window);
}
}
catch (Exception ex)
{
Debug.WriteLine($"设置窗口无边框模式时出错: {ex.Message}");
}
}
private void ToggleSwitchAlwaysOnTop_Toggled(object sender, RoutedEventArgs e)
{
if (!_isLoaded) return;
try
{
bool newState = ToggleSwitchAlwaysOnTop.IsOn;
SettingsManager.Settings.Advanced.IsAlwaysOnTop = newState;
SettingsManager.SaveSettingsToFile();
var window = Application.Current.MainWindow;
if (window != null)
{
WindowSettingsHelper.ApplyAlwaysOnTop(window);
if (!newState && SettingsManager.Settings.Advanced.EnableUIAccessTopMost)
{
SettingsManager.Settings.Advanced.EnableUIAccessTopMost = false;
App.IsUIAccessTopMostEnabled = false;
WindowSettingsHelper.ApplyUIAccessTopMost(window);
SettingsManager.SaveSettingsToFile();
if (_radioNormal != null) _radioNormal.IsChecked = true;
}
}
}
catch (Exception ex)
{
Debug.WriteLine($"设置窗口置顶时出错: {ex.Message}");
}
}
private void RadioTopMostNormal_Checked(object sender, RoutedEventArgs e)
{
if (!_isLoaded) return;
try
{
SettingsManager.Settings.Advanced.EnableUIAccessTopMost = false;
SettingsManager.SaveSettingsToFile();
App.IsUIAccessTopMostEnabled = false;
var msg = Properties.Strings.GetString("Startup_TopMostMode_Normal_RestartRequired");
var result = System.Windows.MessageBox.Show(msg, "Ink Canvas", MessageBoxButton.YesNo, MessageBoxImage.Question);
if (result == MessageBoxResult.Yes)
{
AppRestartHelper.RestartWithCurrentPrivileges();
}
}
catch (Exception ex)
{
Debug.WriteLine($"设置普通置顶模式时出错: {ex.Message}");
}
}
private void RadioTopMostUIA_Checked(object sender, RoutedEventArgs e)
{
if (!_isLoaded) return;
try
{
SettingsManager.Settings.Advanced.EnableUIAccessTopMost = true;
if (!SettingsManager.Settings.Advanced.IsAlwaysOnTop)
{
SettingsManager.Settings.Advanced.IsAlwaysOnTop = true;
ToggleSwitchAlwaysOnTop.IsOn = true;
}
SettingsManager.SaveSettingsToFile();
var msg = Properties.Strings.GetString("Startup_TopMostMode_UIA_RestartRequired");
var result = System.Windows.MessageBox.Show(msg, "Ink Canvas", MessageBoxButton.YesNo, MessageBoxImage.Question);
if (result == MessageBoxResult.Yes)
{
App.IsUIAccessTopMostEnabled = true;
AppRestartHelper.RestartAsAdmin();
}
}
catch (Exception ex)
{
Debug.WriteLine($"设置UIA置顶模式时出错: {ex.Message}");
}
}
private void BtnRestart_Click(object sender, RoutedEventArgs e)
{
if (sender is Button btn && btn.Tag is bool asAdmin)
{
AppRestartHelper.RestartApp(asAdmin);
}
}
}
}
@@ -144,6 +144,37 @@
<ui:FontIcon Icon="{x:Static ui:SegoeFluentIcons.Play}"/>
</ui:NavigationViewItem.Icon>
</ui:NavigationViewItem>
<ui:NavigationViewItem
x:Name="PrivacyPageItem"
Content="隐私"
Tag="PrivacyPage"
ToolTipService.ToolTip="隐私与遥测设置">
<ui:NavigationViewItem.Icon>
<ui:FontIcon Icon="{x:Static ui:SegoeFluentIcons.Shield}"/>
</ui:NavigationViewItem.Icon>
</ui:NavigationViewItem>
</ui:NavigationViewItem.MenuItems>
</ui:NavigationViewItem>
<!-- 主界面 -->
<ui:NavigationViewItem
x:Name="MainInterfaceItem"
Content="主界面"
Tag="MainInterfacePage"
ToolTipService.ToolTip="主界面设置">
<ui:NavigationViewItem.Icon>
<ui:FontIcon Icon="{x:Static ui:FluentSystemIcons.Desktop_20_Regular}" FontSize="20" Margin="-2"/>
</ui:NavigationViewItem.Icon>
<ui:NavigationViewItem.MenuItems>
<ui:NavigationViewItem
x:Name="WindowPageItem"
Content="窗口"
Tag="WindowPage"
ToolTipService.ToolTip="窗口设置">
<ui:NavigationViewItem.Icon>
<ui:FontIcon Icon="{x:Static ui:FluentSystemIcons.Window_20_Regular}" FontSize="20" Margin="-2"/>
</ui:NavigationViewItem.Icon>
</ui:NavigationViewItem>
</ui:NavigationViewItem.MenuItems>
</ui:NavigationViewItem>
@@ -39,6 +39,9 @@ namespace Ink_Canvas.Windows.SettingsViews
{ "HomePage", typeof(HomePage) },
{ "BasicPage", typeof(BasicPage) },
{ "StartupPage", typeof(StartupPage) },
{ "PrivacyPage", typeof(PrivacyPage) },
{ "MainInterfacePage", typeof(MainInterfacePage) },
{ "WindowPage", typeof(WindowPage) },
{ "UpdatePage", typeof(UpdatePage) },
{ "CanvasPage", typeof(CanvasPage) },
{ "DebugPage", typeof(IconographyPage) },