refactor:迁移设置

This commit is contained in:
PrefacedCorg
2026-04-19 14:42:11 +08:00
parent 12c7fb1713
commit a5d6135f0c
17 changed files with 2089 additions and 2686 deletions
@@ -1,17 +1,194 @@
<ui:Page
x:Class="Ink_Canvas.Windows.SettingsViews.Pages.AboutPage"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:ui="http://schemas.inkore.net/lib/ui/wpf/modern"
xmlns:ikw="http://schemas.inkore.net/lib/ui/wpf"
Title="关于"
mc:Ignorable="d">
<Grid>
<StackPanel Margin="24">
<TextBlock Text="关于 InkCanvasForClass" Style="{DynamicResource TitleTextBlockStyle}" Margin="0,0,0,16" />
<TextBlock Text="这里是关于页面" Style="{DynamicResource BodyTextBlockStyle}" />
</StackPanel>
</Grid>
</ui:Page>
<ui:Page x:Class="Ink_Canvas.Windows.SettingsViews.Pages.AboutPage"
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>
<DataTemplate x:Key="DeveloperAvatarTemplate">
<ikw:SimpleStackPanel Orientation="Vertical" HorizontalAlignment="Center">
<Image Source="{Binding AvatarPath}"
VerticalAlignment="Center" HorizontalAlignment="Center"
RenderOptions.BitmapScalingMode="HighQuality" Width="96" Height="96" Margin="0,0,0,6">
<Image.Clip>
<EllipseGeometry Center="48,48" RadiusX="48" RadiusY="48" />
</Image.Clip>
</Image>
<TextBlock Text="{Binding Name}" HorizontalAlignment="Center" FontSize="18" FontWeight="Bold" Foreground="#fde047" />
<TextBlock Text="{Binding Role}" HorizontalAlignment="Center" FontSize="12" Foreground="White" />
</ikw:SimpleStackPanel>
</DataTemplate>
<DataTemplate x:Key="ContributorAvatarTemplate">
<ikw:SimpleStackPanel Orientation="Vertical" HorizontalAlignment="Center">
<Image Source="{Binding AvatarPath}"
VerticalAlignment="Center" HorizontalAlignment="Center"
RenderOptions.BitmapScalingMode="HighQuality" Width="48" Height="48" Margin="0,0,0,4">
<Image.Clip>
<EllipseGeometry Center="24,24" RadiusX="24" RadiusY="24" />
</Image.Clip>
</Image>
<TextBlock Text="{Binding Name}" HorizontalAlignment="Center" FontSize="12" Foreground="White" />
</ikw:SimpleStackPanel>
</DataTemplate>
</FrameworkElement.Resources>
<Grid>
<ikw:SimpleStackPanel MaxWidth="1000"
HorizontalAlignment="Stretch"
Spacing="{StaticResource SettingsCardSpacing}">
<TextBlock Style="{StaticResource SettingsSectionHeaderTextBlockStyle}"
Text="{i18n:I18n Key=About_Title}" />
<ui:SettingsCard Header="{i18n:I18n Key=About_VersionLabel}">
<ui:SettingsCard.HeaderIcon>
<ui:FontIcon Icon="{x:Static ui:SegoeFluentIcons.Info}" />
</ui:SettingsCard.HeaderIcon>
<TextBlock x:Name="AppVersionTextBlock" Text="1.X.X.X" FontWeight="Bold" VerticalAlignment="Center" />
</ui:SettingsCard>
<ui:SettingsExpander Header="{i18n:I18n Key=About_DeviceInfo}">
<ui:SettingsExpander.HeaderIcon>
<ui:FontIcon Icon="{x:Static ui:SegoeFluentIcons.Devices}" />
</ui:SettingsExpander.HeaderIcon>
<ui:SettingsExpander.Items>
<ui:SettingsCard Header="{i18n:I18n Key=About_DeviceIdLabel}">
<TextBlock x:Name="DeviceIdTextBlock" Text="{i18n:I18n Key=About_DeviceInfo_Loading}" />
</ui:SettingsCard>
<ui:SettingsCard Header="{i18n:I18n Key=About_UsageFrequencyLabel}">
<TextBlock x:Name="UsageFrequencyTextBlock" Text="{i18n:I18n Key=About_DeviceInfo_Loading}" />
</ui:SettingsCard>
<ui:SettingsCard Header="{i18n:I18n Key=About_UpdatePriorityLabel}">
<TextBlock x:Name="UpdatePriorityTextBlock" Text="{i18n:I18n Key=About_DeviceInfo_Loading}" />
</ui:SettingsCard>
<ui:SettingsCard Header="{i18n:I18n Key=About_LaunchCountLabel}">
<TextBlock x:Name="LaunchCountTextBlock" Text="{i18n:I18n Key=About_DeviceInfo_Loading}" />
</ui:SettingsCard>
<ui:SettingsCard Header="{i18n:I18n Key=About_TotalUsageLabel}">
<TextBlock x:Name="TotalUsageTextBlock" Text="{i18n:I18n Key=About_DeviceInfo_Loading}" />
</ui:SettingsCard>
<ui:SettingsCard Header="">
<Button x:Name="RefreshDeviceInfoButton" Content="{i18n:I18n Key=About_RefreshDeviceInfo}"
Click="RefreshDeviceInfo_Click" />
</ui:SettingsCard>
</ui:SettingsExpander.Items>
</ui:SettingsExpander>
<ui:SettingsExpander Header="{i18n:I18n Key=About_PrivacyAndTelemetry}">
<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">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<ikw:SimpleStackPanel Orientation="Horizontal" Spacing="8"
TextElement.Foreground="{DynamicResource {x:Static ui:ThemeKeys.AccentTextFillColorPrimaryBrushKey}}"
Margin="0,3,0,0">
<ui:FontIcon Icon="{x:Static ui:SegoeFluentIcons.Info}" FontSize="24"/>
<TextBlock FontSize="16" VerticalAlignment="Center" FontWeight="SemiBold"
Text="{i18n:I18n Key=About_LicenseTitle}" />
</ikw:SimpleStackPanel>
<ikw:SimpleStackPanel Orientation="Vertical" Spacing="12" Grid.Row="1" Margin="5,10">
<FrameworkElement.Resources>
<Style TargetType="TextBlock">
<Setter Property="LineHeight" Value="21"/>
<Setter Property="TextWrapping" Value="Wrap"/>
</Style>
</FrameworkElement.Resources>
<TextBlock Text="GNU General Public License v3.0" FontSize="20" FontWeight="Bold"/>
<TextBlock Text="{i18n:I18n Key=About_LicenseBody}" FontSize="11"
Foreground="{DynamicResource TextFillColorSecondaryBrush}" />
<Separator Opacity="0.2"/>
</ikw:SimpleStackPanel>
<ikw:SimpleStackPanel Grid.Row="2" Orientation="Horizontal" Spacing="10">
<ui:HyperlinkButton Content="ICC CE" NavigateUri="https://github.com/InkCanvasForClass/community/"/>
<ui:HyperlinkButton Content="ICA" NavigateUri="https://github.com/ChangSakura/Ink-Canvas"/>
<ui:HyperlinkButton Content="Ink Canvas" NavigateUri="https://github.com/WXRIW/Ink-Canvas"/>
</ikw:SimpleStackPanel>
</Grid>
</Border>
<TextBlock Style="{StaticResource SettingsSectionHeaderTextBlockStyle}"
Text="{i18n:I18n Key=About_DevelopersLabel}" />
<ItemsControl x:Name="DeveloperItemsControl"
ItemTemplate="{StaticResource DeveloperAvatarTemplate}">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<WrapPanel Orientation="Horizontal" ItemWidth="130" Margin="0,0,0,8" />
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
</ItemsControl>
<Separator Margin="0,8" />
<TextBlock Style="{StaticResource SettingsSectionHeaderTextBlockStyle}"
Text="{i18n:I18n Key=About_ThanksContributors}" />
<ItemsControl x:Name="ContributorItemsControl"
ItemTemplate="{StaticResource ContributorAvatarTemplate}">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<WrapPanel Orientation="Horizontal" ItemWidth="96" Margin="0,0,0,8" />
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
</ItemsControl>
<Separator Margin="0,8" />
<ikw:SimpleStackPanel Spacing="3" Orientation="Vertical" Margin="0,0,0,24">
<TextBlock Text="{i18n:I18n Key=About_Copyright}" FontWeight="Bold" TextWrapping="Wrap" />
<TextBlock Text="{i18n:I18n Key=About_OpenSourceSlogan}" FontWeight="Bold"
TextWrapping="Wrap" Foreground="{DynamicResource TextFillColorSecondaryBrush}" />
</ikw:SimpleStackPanel>
</ikw:SimpleStackPanel>
</Grid>
</Grid>
</ScrollViewer>
</ui:Page>
@@ -1,12 +1,424 @@
using iNKORE.UI.WPF.Modern.Controls;
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
{
public partial class AboutPage : Page
public class AvatarItem
{
public string AvatarPath { get; set; }
public string Name { get; set; }
public string Role { get; set; }
}
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;
public AboutPage()
{
InitializeComponent();
Loaded += AboutPage_Loaded;
Unloaded += AboutPage_Unloaded;
InitializeAvatarData();
}
private void InitializeAvatarData()
{
var developers = new ObservableCollection<AvatarItem>
{
new AvatarItem { AvatarPath = "/Resources/DeveloperAvatars/CJKmkp.jpg", Name = "CJK_mkp", Role = LocalizationHelper.GetString("About_Dev_ICCCE") },
new AvatarItem { AvatarPath = "/Resources/DeveloperAvatars/dubi906w.jpg", Name = "Dubi906w", Role = LocalizationHelper.GetString("About_Dev_ICC") },
new AvatarItem { AvatarPath = "/Resources/DeveloperAvatars/ChangSakura.png", Name = "ChangSakura", Role = LocalizationHelper.GetString("About_Dev_ICA") },
new AvatarItem { AvatarPath = "/Resources/DeveloperAvatars/WXRIW.png", Name = "WXRIW", Role = LocalizationHelper.GetString("About_Dev_InkCanvas") }
};
var contributors = new ObservableCollection<AvatarItem>
{
new AvatarItem { AvatarPath = "/Resources/DeveloperAvatars/RaspberryKan.jpg", Name = "Raspberry Kan" },
new AvatarItem { AvatarPath = "/Resources/DeveloperAvatars/kengwang.png", Name = "Kengwang" },
new AvatarItem { AvatarPath = "/Resources/DeveloperAvatars/jiajiaxd.jpg", Name = "Charles Jia" },
new AvatarItem { AvatarPath = "/Resources/DeveloperAvatars/clover-yan.png", Name = "clover_yan" },
new AvatarItem { AvatarPath = "/Resources/DeveloperAvatars/NetheriteBowl.png", Name = "Netherite_Bowl" },
new AvatarItem { AvatarPath = "/Resources/DeveloperAvatars/NotYoojun.png", Name = "Yoojun Zhou" },
new AvatarItem { AvatarPath = "/Resources/DeveloperAvatars/yuwenhui2020.png", Name = "YuWenHui2020" },
new AvatarItem { AvatarPath = "/Resources/DeveloperAvatars/STBBRD.png", Name = "ZongziTEK" },
new AvatarItem { AvatarPath = "/Resources/DeveloperAvatars/aaaaaaccd.jpg", Name = "Aesthed" },
new AvatarItem { AvatarPath = "/Resources/DeveloperAvatars/wwei.png", Name = "Wei" },
new AvatarItem { AvatarPath = "/Resources/DeveloperAvatars/Alan-CRL.png", Name = "Alan-CRL" },
new AvatarItem { AvatarPath = "/Resources/DeveloperAvatars/PrefacedCorg.jpg", Name = "PrefacedCorg" },
new AvatarItem { AvatarPath = "/Resources/DeveloperAvatars/PANDA-JSR.jpg", Name = "PANDA-JSR" }
};
DeveloperItemsControl.ItemsSource = developers;
ContributorItemsControl.ItemsSource = contributors;
}
private void AboutPage_Loaded(object sender, RoutedEventArgs e)
{
LoadSettings();
_isLoaded = true;
if (_usageRefreshTimer == null)
{
_usageRefreshTimer = new DispatcherTimer { Interval = TimeSpan.FromSeconds(1) };
_usageRefreshTimer.Tick += UsageRefreshTimer_Tick;
}
_usageRefreshTimer.Start();
}
private void AboutPage_Unloaded(object sender, RoutedEventArgs e)
{
if (_usageRefreshTimer != null)
{
_usageRefreshTimer.Stop();
_usageRefreshTimer.Tick -= UsageRefreshTimer_Tick;
_usageRefreshTimer = null;
}
}
private void UsageRefreshTimer_Tick(object sender, EventArgs e)
{
try
{
long currentSessionSeconds = (long)(DateTime.Now - _sessionStartTime).TotalSeconds;
TotalUsageTextBlock.Text = DeviceIdentifier.FormatDuration(_savedTotalSeconds + currentSessionSeconds);
}
catch { }
}
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)
{
RefreshDeviceInfo();
}
private void RefreshDeviceInfo()
{
try
{
string deviceId = DeviceIdentifier.GetDeviceId();
DeviceIdTextBlock.Text = deviceId;
var usageFrequency = DeviceIdentifier.GetUsageFrequency();
string frequencyText;
switch (usageFrequency)
{
case DeviceIdentifier.UsageFrequency.High:
frequencyText = "高频用户";
break;
case DeviceIdentifier.UsageFrequency.Medium:
frequencyText = "中频用户";
break;
case DeviceIdentifier.UsageFrequency.Low:
frequencyText = "低频用户";
break;
default:
frequencyText = "未知";
break;
}
UsageFrequencyTextBlock.Text = frequencyText;
var updatePriority = DeviceIdentifier.GetUpdatePriority();
string priorityText;
switch (updatePriority)
{
case DeviceIdentifier.UpdatePriority.High:
priorityText = "高优先级(优先推送更新)";
break;
case DeviceIdentifier.UpdatePriority.Medium:
priorityText = "中优先级(正常推送更新)";
break;
case DeviceIdentifier.UpdatePriority.Low:
priorityText = "低优先级(延迟推送更新)";
break;
default:
priorityText = "未知";
break;
}
UpdatePriorityTextBlock.Text = priorityText;
var (launchCount, totalSeconds, avgSessionSeconds, _) = DeviceIdentifier.GetUsageStats();
_savedTotalSeconds = totalSeconds;
_sessionStartTime = DateTime.Now;
LaunchCountTextBlock.Text = launchCount.ToString();
TotalUsageTextBlock.Text = DeviceIdentifier.FormatDuration(totalSeconds);
}
catch (Exception ex)
{
LogHelper.WriteLogToFile($"刷新设备信息失败: {ex.Message}", LogHelper.LogType.Error);
DeviceIdTextBlock.Text = "获取失败";
UsageFrequencyTextBlock.Text = "获取失败";
UpdatePriorityTextBlock.Text = "获取失败";
LaunchCountTextBlock.Text = "获取失败";
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;
}
}
}
}
}
@@ -0,0 +1,361 @@
<ui:Page x:Class="Ink_Canvas.Windows.SettingsViews.Pages.CanvasPage"
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"
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="{i18n:I18n Key=Canvas_GroupTitle}" />
<controls:LabeledSettingsCard x:Name="CardShowCursor"
Header="{i18n:I18n Key=Canvas_ShowCursor}"
Icon="{x:Static ui:SegoeFluentIcons.PointerHand}"
SwitchName="ToggleSwitchShowCursor"
Toggled="ToggleSwitchShowCursor_Toggled" />
<controls:LabeledSettingsCard x:Name="CardEnablePressureTouchMode"
Header="{i18n:I18n Key=Canvas_EnablePressureTouch}"
Description="{i18n:I18n Key=Canvas_EnablePressureTouchHint}"
Icon="{x:Static ui:SegoeFluentIcons.Touch}"
SwitchName="ToggleSwitchEnablePressureTouchMode"
Toggled="ToggleSwitchEnablePressureTouchMode_Toggled" />
<controls:LabeledSettingsCard x:Name="CardDisablePressure"
Header="{i18n:I18n Key=Canvas_DisablePressure}"
Description="{i18n:I18n Key=Canvas_DisablePressureHint}"
Icon="{x:Static ui:SegoeFluentIcons.TouchPointer}"
SwitchName="ToggleSwitchDisablePressure"
Toggled="ToggleSwitchDisablePressure_Toggled" />
<ui:SettingsCard Header="{i18n:I18n Key=Canvas_EraserSize}"
Description="{i18n:I18n Key=Canvas_EraserSizeHint}">
<ui:SettingsCard.HeaderIcon>
<ui:FontIcon Icon="{x:Static ui:SegoeFluentIcons.EraseTool}" />
</ui:SettingsCard.HeaderIcon>
<ComboBox x:Name="ComboBoxEraserSize" Width="160"
SelectedIndex="2"
SelectionChanged="ComboBoxEraserSize_SelectionChanged">
<ComboBoxItem Content="{i18n:I18n Key=Canvas_EraserSize_VerySmall}" />
<ComboBoxItem Content="{i18n:I18n Key=Canvas_EraserSize_Small}" />
<ComboBoxItem Content="{i18n:I18n Key=Canvas_EraserSize_Medium}" />
<ComboBoxItem Content="{i18n:I18n Key=Canvas_EraserSize_Large}" />
<ComboBoxItem Content="{i18n:I18n Key=Canvas_EraserSize_VeryLarge}" />
</ComboBox>
</ui:SettingsCard>
<controls:LabeledSettingsCard x:Name="CardHideStrokeWhenSelecting"
Header="{i18n:I18n Key=Canvas_HideStrokeWhenSelecting}"
Description="{i18n:I18n Key=Canvas_HideStrokeWhenSelectingHint}"
Icon="{x:Static ui:SegoeFluentIcons.Hide}"
SwitchName="ToggleSwitchHideStrokeWhenSelecting"
Toggled="ToggleSwitchHideStrokeWhenSelecting_Toggled" />
<controls:LabeledSettingsCard x:Name="CardClearCanvasAndClearTimeMachine"
Header="{i18n:I18n Key=Canvas_ClearInkAlsoClearHistory}"
Icon="{x:Static ui:SegoeFluentIcons.Delete}"
SwitchName="ToggleSwitchClearCanvasAndClearTimeMachine"
Toggled="ToggleSwitchClearCanvasAndClearTimeMachine_Toggled" />
<controls:LabeledSettingsCard x:Name="CardClearCanvasAlsoClearImages"
Header="{i18n:I18n Key=Canvas_ClearCanvasAlsoClearImages}"
Icon="{x:Static ui:SegoeFluentIcons.Photo}"
SwitchName="ToggleSwitchClearCanvasAlsoClearImages"
Toggled="ToggleSwitchClearCanvasAlsoClearImages_Toggled" />
<controls:LabeledSettingsCard x:Name="CardCompressPicturesUploaded"
Header="{i18n:I18n Key=Canvas_CompressPicturesUploaded}"
Icon="{x:Static ui:SegoeFluentIcons.Clear}"
SwitchName="ToggleSwitchCompressPicturesUploaded"
Toggled="ToggleSwitchCompressPicturesUploaded_Toggled" />
<controls:LabeledSettingsCard x:Name="CardLaunchSeewoVideoShowcaseForWhiteboardBooth"
Header="{i18n:I18n Key=Canvas_LaunchSeewoVideoShowcaseForWhiteboardBooth}"
Description="{i18n:I18n Key=Canvas_LaunchSeewoVideoShowcaseForWhiteboardBoothHint}"
Icon="{x:Static ui:SegoeFluentIcons.Video}"
SwitchName="ToggleSwitchLaunchSeewoVideoShowcaseForWhiteboardBooth"
Toggled="ToggleSwitchLaunchSeewoVideoShowcaseForWhiteboardBooth_Toggled" />
<ui:SettingsCard Header="{i18n:I18n Key=Canvas_KeepHyperbolaAsymptote}"
Description="{i18n:I18n Key=Canvas_HyperbolaAsymptoteHint}">
<ui:SettingsCard.HeaderIcon>
<ui:FontIcon Icon="{x:Static ui:SegoeFluentIcons.AreaChart}" />
</ui:SettingsCard.HeaderIcon>
<ComboBox x:Name="ComboBoxHyperbolaAsymptoteOption" Width="160"
SelectedIndex="0"
SelectionChanged="ComboBoxHyperbolaAsymptoteOption_SelectionChanged">
<ComboBoxItem Content="{i18n:I18n Key=Canvas_Yes}" />
<ComboBoxItem Content="{i18n:I18n Key=Canvas_No}" />
<ComboBoxItem Content="{i18n:I18n Key=Canvas_AskEachTime}" />
</ComboBox>
</ui:SettingsCard>
<controls:LabeledSettingsCard x:Name="CardShowCircleCenter"
Header="{i18n:I18n Key=Canvas_ShowCircleCenter}"
Icon="{x:Static ui:SegoeFluentIcons.CircleRing}"
SwitchName="ToggleSwitchShowCircleCenter"
Toggled="ToggleSwitchShowCircleCenter_Toggled" />
<controls:LabeledSettingsCard x:Name="CardFitToCurve"
Header="{i18n:I18n Key=Canvas_WPFBezierSmoothing}"
Icon="{x:Static ui:SegoeFluentIcons.InkingTool}"
SwitchName="ToggleSwitchFitToCurve"
Toggled="ToggleSwitchFitToCurve_Toggled" />
<controls:LabeledSettingsCard x:Name="CardAdvancedBezierSmoothing"
Header="{i18n:I18n Key=Canvas_AdvancedBezierSmoothing}"
Icon="{x:Static ui:SegoeFluentIcons.InkingTool}"
SwitchName="ToggleSwitchAdvancedBezierSmoothing"
Toggled="ToggleSwitchAdvancedBezierSmoothing_Toggled" />
<controls:LabeledSettingsCard x:Name="CardEnableInkFade"
Header="{i18n:I18n Key=Canvas_EnableInkFade}"
Description="{i18n:I18n Key=Canvas_EnableInkFadeHint}"
Icon="{x:Static ui:SegoeFluentIcons.Color}"
SwitchName="ToggleSwitchEnableInkFade"
Toggled="ToggleSwitchEnableInkFade_Toggled" />
<ui:SettingsCard Header="{i18n:I18n Key=Canvas_InkFadeTime}"
Visibility="{Binding IsOn, ElementName=CardEnableInkFade, Converter={StaticResource BooleanToVisibilityConverter}}">
<ui:SettingsCard.HeaderIcon>
<ui:FontIcon Icon="{x:Static ui:SegoeFluentIcons.Stopwatch}" />
</ui:SettingsCard.HeaderIcon>
<ikw:SimpleStackPanel Orientation="Horizontal" Spacing="12">
<Slider x:Name="InkFadeTimeSlider" Width="150" Minimum="1000" Maximum="10000"
Value="3000" TickFrequency="1000" IsSnapToTickEnabled="True"
ValueChanged="InkFadeTimeSlider_ValueChanged" />
<TextBlock Text="{Binding Value, ElementName=InkFadeTimeSlider, StringFormat={}{0:0}ms}"
VerticalAlignment="Center" FontSize="14" />
</ikw:SimpleStackPanel>
</ui:SettingsCard>
<controls:LabeledSettingsCard x:Name="CardHideInkFadeControlInPenMenu"
Header="{i18n:I18n Key=Canvas_HideInkFadeInPenMenu}"
Description="{i18n:I18n Key=Canvas_HideInkFadeInPenMenuHint}"
Icon="{x:Static ui:SegoeFluentIcons.Hide}"
SwitchName="ToggleSwitchHideInkFadeControlInPenMenu"
Toggled="ToggleSwitchHideInkFadeControlInPenMenu_Toggled" />
<controls:LabeledSettingsCard x:Name="CardBrushAutoRestore"
Header="{i18n:I18n Key=Canvas_BrushAutoRestore}"
Description="{i18n:I18n Key=Canvas_BrushAutoRestoreHint}"
Icon="{x:Static ui:SegoeFluentIcons.Refresh}"
SwitchName="ToggleSwitchBrushAutoRestore"
Toggled="ToggleSwitchBrushAutoRestore_Toggled" />
<ui:SettingsExpander Header="{i18n:I18n Key=Canvas_BrushAutoRestore}"
Visibility="{Binding IsOn, ElementName=CardBrushAutoRestore, Converter={StaticResource BooleanToVisibilityConverter}}">
<ui:SettingsExpander.HeaderIcon>
<ui:FontIcon Icon="{x:Static ui:SegoeFluentIcons.Settings}" />
</ui:SettingsExpander.HeaderIcon>
<ui:SettingsExpander.Items>
<ui:SettingsCard Header="{i18n:I18n Key=Canvas_AutoRestoreTimePoints}">
<TextBox x:Name="BrushAutoRestoreTimesTextBox" Width="260"
TextChanged="BrushAutoRestoreTimesTextBox_TextChanged" />
</ui:SettingsCard>
<ui:SettingsCard Header="{i18n:I18n Key=Canvas_RestoreColor}">
<ComboBox x:Name="ComboBoxBrushAutoRestoreColor" Width="200"
SelectionChanged="ComboBoxBrushAutoRestoreColor_SelectionChanged">
<ComboBoxItem Content="{i18n:I18n Key=Canvas_Color_Default}" Tag="#FFFF0000" />
<ComboBoxItem Content="{i18n:I18n Key=Canvas_Color_Black}" Tag="#FF000000" />
<ComboBoxItem Content="{i18n:I18n Key=Canvas_Color_White}" Tag="#FFFFFFFF" />
<ComboBoxItem Content="{i18n:I18n Key=Canvas_Color_Red}" Tag="#FFFF0000" />
<ComboBoxItem Content="{i18n:I18n Key=Canvas_Color_Yellow}" Tag="#FFFFFF00" />
<ComboBoxItem Content="{i18n:I18n Key=Canvas_Color_Blue}" Tag="#FF2563EB" />
<ComboBoxItem Content="{i18n:I18n Key=Canvas_Color_Green}" Tag="#FF16A34A" />
<ComboBoxItem Content="{i18n:I18n Key=Canvas_Color_Orange}" Tag="#FFFB9650" />
<ComboBoxItem Content="{i18n:I18n Key=Canvas_Color_Purple}" Tag="#FF9333EA" />
</ComboBox>
</ui:SettingsCard>
<ui:SettingsCard Header="{i18n:I18n Key=Canvas_RestoreWidth}">
<ikw:SimpleStackPanel Orientation="Horizontal" Spacing="12">
<Slider x:Name="BrushAutoRestoreWidthSlider" Width="200" Minimum="1" Maximum="20"
TickFrequency="1" IsSnapToTickEnabled="True" Value="5"
ValueChanged="BrushAutoRestoreWidthSlider_ValueChanged" />
<TextBlock Text="{Binding Value, ElementName=BrushAutoRestoreWidthSlider, StringFormat={}{0:0}px}"
FontSize="12" VerticalAlignment="Center" />
</ikw:SimpleStackPanel>
</ui:SettingsCard>
<ui:SettingsCard Header="{i18n:I18n Key=Canvas_RestoreOpacity}">
<ikw:SimpleStackPanel Orientation="Horizontal" Spacing="12">
<Slider x:Name="BrushAutoRestoreAlphaSlider" Width="200" Minimum="0" Maximum="255"
TickFrequency="5" IsSnapToTickEnabled="True"
ValueChanged="BrushAutoRestoreAlphaSlider_ValueChanged" />
<TextBlock Text="{Binding Value, ElementName=BrushAutoRestoreAlphaSlider, StringFormat={}{0:0}}"
FontSize="12" VerticalAlignment="Center" />
</ikw:SimpleStackPanel>
</ui:SettingsCard>
</ui:SettingsExpander.Items>
</ui:SettingsExpander>
<controls:LabeledSettingsCard x:Name="CardEnableEraserAutoSwitchBack"
Header="{i18n:I18n Key=Canvas_SwitchBackAfterEraser}"
Description="{i18n:I18n Key=Canvas_SwitchBackAfterEraserHint}"
Icon="{x:Static ui:SegoeFluentIcons.Switch}"
SwitchName="ToggleSwitchEnableEraserAutoSwitchBack"
Toggled="ToggleSwitchEnableEraserAutoSwitchBack_Toggled" />
<ui:SettingsCard Header="{i18n:I18n Key=Canvas_SwitchBackDelay}"
Description="{i18n:I18n Key=Canvas_SwitchBackDelayHint}"
Visibility="{Binding IsOn, ElementName=CardEnableEraserAutoSwitchBack, Converter={StaticResource BooleanToVisibilityConverter}}">
<ikw:SimpleStackPanel Orientation="Horizontal" Spacing="12">
<Slider x:Name="EraserAutoSwitchBackDelaySlider" Width="150" Minimum="1" Maximum="60"
Value="10" TickFrequency="1" IsSnapToTickEnabled="True"
ValueChanged="EraserAutoSwitchBackDelaySlider_ValueChanged" />
<TextBlock Text="{Binding Value, ElementName=EraserAutoSwitchBackDelaySlider, StringFormat={}{0:0}秒}"
VerticalAlignment="Center" FontSize="14" />
</ikw:SimpleStackPanel>
</ui:SettingsCard>
<TextBlock Style="{StaticResource SettingsSectionHeaderTextBlockStyle}"
Text="{i18n:I18n Key=InkRecog_Title}" />
<controls:LabeledSettingsCard x:Name="CardEnableInkToShape"
Header="{i18n:I18n Key=InkRecog_EnableInkRecognition}"
Icon="{x:Static ui:SegoeFluentIcons.Draw}"
SwitchName="ToggleSwitchEnableInkToShape"
Toggled="ToggleSwitchEnableInkToShape_Toggled" />
<ui:SettingsCard Header="{i18n:I18n Key=InkRecog_ShapeEngine}"
Description="{i18n:I18n Key=InkRecog_ShapeEngineHint}">
<ComboBox x:Name="ComboBoxShapeRecognitionEngine" Width="160"
SelectionChanged="ComboBoxShapeRecognitionEngine_SelectionChanged">
<ComboBoxItem Content="{i18n:I18n Key=InkRecog_ShapeEngineAuto}" />
<ComboBoxItem Content="{i18n:I18n Key=InkRecog_ShapeEngineIACore}" />
<ComboBoxItem Content="{i18n:I18n Key=InkRecog_ShapeEngineWinRT}" />
</ComboBox>
</ui:SettingsCard>
<controls:LabeledSettingsCard x:Name="CardEnableWinRtHandwritingStrokeBeautify"
Header="{i18n:I18n Key=InkRecog_HandwritingBeautify}"
Description="{i18n:I18n Key=InkRecog_HandwritingBeautifyHint}"
Icon="{x:Static ui:SegoeFluentIcons.PenWorkspace}"
SwitchName="ToggleSwitchEnableWinRtHandwritingStrokeBeautify"
Toggled="ToggleSwitchEnableWinRtHandwritingStrokeBeautify_Toggled" />
<controls:LabeledSettingsCard x:Name="CardEnableInkToShapeNoFakePressureRectangle"
Header="{i18n:I18n Key=InkRecog_BlockRectFakePressure}"
ShowWhen="{Binding IsOn, ElementName=CardEnableInkToShape}"
Icon="{x:Static ui:SegoeFluentIcons.RectangularClipping}"
SwitchName="ToggleSwitchEnableInkToShapeNoFakePressureRectangle"
Toggled="ToggleSwitchEnableInkToShapeNoFakePressureRectangle_Toggled" />
<controls:LabeledSettingsCard x:Name="CardEnableInkToShapeNoFakePressureTriangle"
Header="{i18n:I18n Key=InkRecog_BlockTriFakePressure}"
ShowWhen="{Binding IsOn, ElementName=CardEnableInkToShape}"
Icon="{x:Static ui:SegoeFluentIcons.IncidentTriangle}"
SwitchName="ToggleSwitchEnableInkToShapeNoFakePressureTriangle"
Toggled="ToggleSwitchEnableInkToShapeNoFakePressureTriangle_Toggled" />
<ui:SettingsExpander Header="形状修正"
Visibility="{Binding IsOn, ElementName=CardEnableInkToShape, Converter={StaticResource BooleanToVisibilityConverter}}">
<ui:SettingsExpander.HeaderIcon>
<ui:FontIcon Icon="{x:Static ui:SegoeFluentIcons.Settings}" />
</ui:SettingsExpander.HeaderIcon>
<ui:SettingsExpander.Items>
<ui:SettingsCard Header="{i18n:I18n Key=InkRecog_FixTriangle}">
<CheckBox x:Name="ToggleCheckboxEnableInkToShapeTriangle" IsChecked="True"
Checked="ToggleCheckboxEnableInkToShapeTriangle_CheckedChanged"
Unchecked="ToggleCheckboxEnableInkToShapeTriangle_CheckedChanged" />
</ui:SettingsCard>
<ui:SettingsCard Header="{i18n:I18n Key=InkRecog_FixRectangle}">
<CheckBox x:Name="ToggleCheckboxEnableInkToShapeRectangle" IsChecked="True"
Checked="ToggleCheckboxEnableInkToShapeRectangle_CheckedChanged"
Unchecked="ToggleCheckboxEnableInkToShapeRectangle_CheckedChanged" />
</ui:SettingsCard>
<ui:SettingsCard Header="{i18n:I18n Key=InkRecog_FixEllipse}">
<CheckBox x:Name="ToggleCheckboxEnableInkToShapeRounded" IsChecked="True"
Checked="ToggleCheckboxEnableInkToShapeRounded_CheckedChanged"
Unchecked="ToggleCheckboxEnableInkToShapeRounded_CheckedChanged" />
</ui:SettingsCard>
</ui:SettingsExpander.Items>
</ui:SettingsExpander>
<controls:LabeledSettingsCard x:Name="CardAutoStraightenLine"
Header="{i18n:I18n Key=InkRecog_AutoStraightLine}"
Icon="{x:Static ui:SegoeFluentIcons.LineDisplay}"
SwitchName="ToggleSwitchAutoStraightenLine"
Toggled="ToggleSwitchAutoStraightenLine_Toggled" />
<ui:SettingsCard Header="{i18n:I18n Key=InkRecog_LengthThreshold}"
Visibility="{Binding IsOn, ElementName=CardAutoStraightenLine, Converter={StaticResource BooleanToVisibilityConverter}}">
<ikw:SimpleStackPanel Orientation="Horizontal" Spacing="12">
<Slider x:Name="AutoStraightenLineThresholdSlider" Width="150" Minimum="30" Maximum="300"
Value="80" TickFrequency="30" IsSnapToTickEnabled="True"
ValueChanged="AutoStraightenLineThresholdSlider_ValueChanged" />
<TextBlock Text="{Binding Value, ElementName=AutoStraightenLineThresholdSlider, StringFormat={}{0:0}}"
VerticalAlignment="Center" FontSize="14" />
</ikw:SimpleStackPanel>
</ui:SettingsCard>
<ui:SettingsCard Header="{i18n:I18n Key=InkRecog_Sensitivity}"
Visibility="{Binding IsOn, ElementName=CardAutoStraightenLine, Converter={StaticResource BooleanToVisibilityConverter}}">
<ikw:SimpleStackPanel Orientation="Horizontal" Spacing="12">
<Slider x:Name="LineStraightenSensitivitySlider" Width="150" Minimum="0.05" Maximum="2.0"
Value="0.20" TickFrequency="0.05" IsSnapToTickEnabled="True"
ValueChanged="LineStraightenSensitivitySlider_ValueChanged" />
<TextBlock Text="{Binding Value, ElementName=LineStraightenSensitivitySlider, StringFormat={}{0:F2}}"
VerticalAlignment="Center" FontSize="14" />
</ikw:SimpleStackPanel>
</ui:SettingsCard>
<controls:LabeledSettingsCard x:Name="CardHighPrecisionLineStraighten"
Header="{i18n:I18n Key=InkRecog_HighPrecisionStraighten}"
Description="{i18n:I18n Key=InkRecog_HighPrecisionHint}"
ShowWhen="{Binding IsOn, ElementName=CardAutoStraightenLine}"
Icon="{x:Static ui:SegoeFluentIcons.Bullseye}"
SwitchName="ToggleSwitchHighPrecisionLineStraighten"
Toggled="ToggleSwitchHighPrecisionLineStraighten_Toggled" />
<controls:LabeledSettingsCard x:Name="CardLineEndpointSnapping"
Header="{i18n:I18n Key=InkRecog_LineEndpointSnapping}"
Icon="{x:Static ui:SegoeFluentIcons.Link}"
SwitchName="ToggleSwitchLineEndpointSnapping"
Toggled="ToggleSwitchLineEndpointSnapping_Toggled" />
<ui:SettingsCard Header="{i18n:I18n Key=InkRecog_SnappingDistance}"
Description="{i18n:I18n Key=InkRecog_LineEndpointSnappingHint}"
Visibility="{Binding IsOn, ElementName=CardLineEndpointSnapping, Converter={StaticResource BooleanToVisibilityConverter}}">
<ikw:SimpleStackPanel Orientation="Horizontal" Spacing="12">
<Slider x:Name="LineEndpointSnappingThresholdSlider" Width="150" Minimum="5" Maximum="50"
Value="15" TickFrequency="5" IsSnapToTickEnabled="True"
ValueChanged="LineEndpointSnappingThresholdSlider_ValueChanged" />
<TextBlock Text="{Binding Value, ElementName=LineEndpointSnappingThresholdSlider, StringFormat={}{0:0}}"
VerticalAlignment="Center" FontSize="14" />
</ikw:SimpleStackPanel>
</ui:SettingsCard>
<Rectangle Height="48" />
</ikw:SimpleStackPanel>
</Grid>
</Grid>
</ScrollViewer>
</ui:Page>
@@ -0,0 +1,403 @@
using Ink_Canvas.Helpers;
using Ink_Canvas.Windows.SettingsViews.Helpers;
using System;
using System.Diagnostics;
using System.Windows;
using System.Windows.Controls;
namespace Ink_Canvas.Windows.SettingsViews.Pages
{
public partial class CanvasPage : iNKORE.UI.WPF.Modern.Controls.Page
{
private bool _isLoaded = false;
public CanvasPage()
{
InitializeComponent();
Loaded += CanvasPage_Loaded;
}
private void CanvasPage_Loaded(object sender, RoutedEventArgs e)
{
LoadSettings();
_isLoaded = true;
}
private void LoadSettings()
{
_isLoaded = false;
try
{
var settings = SettingsManager.Settings;
if (settings.Canvas != null)
{
CardShowCursor.IsOn = settings.Canvas.IsShowCursor;
CardEnablePressureTouchMode.IsOn = settings.Canvas.EnablePressureTouchMode;
CardDisablePressure.IsOn = settings.Canvas.DisablePressure;
ComboBoxEraserSize.SelectedIndex = settings.Canvas.EraserSize;
CardHideStrokeWhenSelecting.IsOn = settings.Canvas.HideStrokeWhenSelecting;
CardClearCanvasAndClearTimeMachine.IsOn = settings.Canvas.ClearCanvasAndClearTimeMachine;
CardClearCanvasAlsoClearImages.IsOn = settings.Canvas.ClearCanvasAlsoClearImages;
CardCompressPicturesUploaded.IsOn = settings.Canvas.IsCompressPicturesUploaded;
CardLaunchSeewoVideoShowcaseForWhiteboardBooth.IsOn = settings.Canvas.LaunchSeewoVideoShowcaseForWhiteboardBooth;
ComboBoxHyperbolaAsymptoteOption.SelectedIndex = (int)settings.Canvas.HyperbolaAsymptoteOption;
CardShowCircleCenter.IsOn = settings.Canvas.ShowCircleCenter;
CardFitToCurve.IsOn = settings.Canvas.FitToCurve;
CardAdvancedBezierSmoothing.IsOn = settings.Canvas.UseAdvancedBezierSmoothing;
CardEnableInkFade.IsOn = settings.Canvas.EnableInkFade;
InkFadeTimeSlider.Value = settings.Canvas.InkFadeTime;
CardHideInkFadeControlInPenMenu.IsOn = settings.Canvas.HideInkFadeControlInPenMenu;
CardBrushAutoRestore.IsOn = settings.Canvas.EnableBrushAutoRestore;
BrushAutoRestoreTimesTextBox.Text = settings.Canvas.BrushAutoRestoreTimes ?? string.Empty;
LoadBrushAutoRestoreColor(settings.Canvas.BrushAutoRestoreColor);
BrushAutoRestoreWidthSlider.Value = settings.Canvas.BrushAutoRestoreWidth > 0 ? settings.Canvas.BrushAutoRestoreWidth : 5;
BrushAutoRestoreAlphaSlider.Value = settings.Canvas.BrushAutoRestoreAlpha;
CardEnableEraserAutoSwitchBack.IsOn = settings.Canvas.EnableEraserAutoSwitchBack;
EraserAutoSwitchBackDelaySlider.Value = settings.Canvas.EraserAutoSwitchBackDelaySeconds;
CardAutoStraightenLine.IsOn = settings.Canvas.AutoStraightenLine;
AutoStraightenLineThresholdSlider.Value = settings.Canvas.AutoStraightenLineThreshold;
CardHighPrecisionLineStraighten.IsOn = settings.Canvas.HighPrecisionLineStraighten;
CardLineEndpointSnapping.IsOn = settings.Canvas.LineEndpointSnapping;
}
if (settings.InkToShape != null)
{
CardEnableInkToShape.IsOn = settings.InkToShape.IsInkToShapeEnabled;
int eng = settings.InkToShape.ShapeRecognitionEngine;
if (eng < 0) eng = 0;
if (eng > 2) eng = 2;
ComboBoxShapeRecognitionEngine.SelectedIndex = eng;
CardEnableWinRtHandwritingStrokeBeautify.IsOn = settings.InkToShape.EnableWinRtHandwritingStrokeBeautify;
CardEnableInkToShapeNoFakePressureRectangle.IsOn = settings.InkToShape.IsInkToShapeNoFakePressureRectangle;
CardEnableInkToShapeNoFakePressureTriangle.IsOn = settings.InkToShape.IsInkToShapeNoFakePressureTriangle;
ToggleCheckboxEnableInkToShapeTriangle.IsChecked = settings.InkToShape.IsInkToShapeTriangle;
ToggleCheckboxEnableInkToShapeRectangle.IsChecked = settings.InkToShape.IsInkToShapeRectangle;
ToggleCheckboxEnableInkToShapeRounded.IsChecked = settings.InkToShape.IsInkToShapeRounded;
LineStraightenSensitivitySlider.Value = settings.InkToShape.LineStraightenSensitivity;
}
}
catch (Exception ex)
{
Debug.WriteLine($"加载画板设置时出错: {ex.Message}");
}
_isLoaded = true;
}
private void LoadBrushAutoRestoreColor(string hex)
{
try
{
foreach (var item in ComboBoxBrushAutoRestoreColor.Items)
{
if (item is ComboBoxItem cbi && cbi.Tag != null &&
string.Equals(cbi.Tag.ToString(), hex, StringComparison.OrdinalIgnoreCase))
{
ComboBoxBrushAutoRestoreColor.SelectedItem = cbi;
return;
}
}
ComboBoxBrushAutoRestoreColor.SelectedIndex = 0;
}
catch (Exception ex)
{
Debug.WriteLine($"加载画笔恢复颜色时出错: {ex.Message}");
}
}
#region
private void ToggleSwitchShowCursor_Toggled(object sender, RoutedEventArgs e)
{
if (!_isLoaded) return;
SettingsManager.Settings.Canvas.IsShowCursor = CardShowCursor.IsOn;
SettingsManager.SaveSettingsToFile();
}
private void ToggleSwitchEnablePressureTouchMode_Toggled(object sender, RoutedEventArgs e)
{
if (!_isLoaded) return;
SettingsManager.Settings.Canvas.EnablePressureTouchMode = CardEnablePressureTouchMode.IsOn;
if (SettingsManager.Settings.Canvas.EnablePressureTouchMode && SettingsManager.Settings.Canvas.DisablePressure)
{
SettingsManager.Settings.Canvas.DisablePressure = false;
CardDisablePressure.IsOn = false;
}
SettingsManager.SaveSettingsToFile();
}
private void ToggleSwitchDisablePressure_Toggled(object sender, RoutedEventArgs e)
{
if (!_isLoaded) return;
SettingsManager.Settings.Canvas.DisablePressure = CardDisablePressure.IsOn;
if (SettingsManager.Settings.Canvas.DisablePressure && SettingsManager.Settings.Canvas.EnablePressureTouchMode)
{
SettingsManager.Settings.Canvas.EnablePressureTouchMode = false;
CardEnablePressureTouchMode.IsOn = false;
}
SettingsManager.SaveSettingsToFile();
}
private void ComboBoxEraserSize_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
if (!_isLoaded) return;
SettingsManager.Settings.Canvas.EraserSize = ComboBoxEraserSize.SelectedIndex;
SettingsManager.SaveSettingsToFile();
}
private void ToggleSwitchHideStrokeWhenSelecting_Toggled(object sender, RoutedEventArgs e)
{
if (!_isLoaded) return;
SettingsManager.Settings.Canvas.HideStrokeWhenSelecting = CardHideStrokeWhenSelecting.IsOn;
SettingsManager.SaveSettingsToFile();
}
private void ToggleSwitchClearCanvasAndClearTimeMachine_Toggled(object sender, RoutedEventArgs e)
{
if (!_isLoaded) return;
SettingsManager.Settings.Canvas.ClearCanvasAndClearTimeMachine = CardClearCanvasAndClearTimeMachine.IsOn;
SettingsManager.SaveSettingsToFile();
}
private void ToggleSwitchClearCanvasAlsoClearImages_Toggled(object sender, RoutedEventArgs e)
{
if (!_isLoaded) return;
SettingsManager.Settings.Canvas.ClearCanvasAlsoClearImages = CardClearCanvasAlsoClearImages.IsOn;
SettingsManager.SaveSettingsToFile();
}
private void ToggleSwitchCompressPicturesUploaded_Toggled(object sender, RoutedEventArgs e)
{
if (!_isLoaded) return;
SettingsManager.Settings.Canvas.IsCompressPicturesUploaded = CardCompressPicturesUploaded.IsOn;
SettingsManager.SaveSettingsToFile();
}
private void ToggleSwitchLaunchSeewoVideoShowcaseForWhiteboardBooth_Toggled(object sender, RoutedEventArgs e)
{
if (!_isLoaded) return;
SettingsManager.Settings.Canvas.LaunchSeewoVideoShowcaseForWhiteboardBooth = CardLaunchSeewoVideoShowcaseForWhiteboardBooth.IsOn;
SettingsManager.SaveSettingsToFile();
}
private void ComboBoxHyperbolaAsymptoteOption_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
if (!_isLoaded) return;
SettingsManager.Settings.Canvas.HyperbolaAsymptoteOption = (OptionalOperation)ComboBoxHyperbolaAsymptoteOption.SelectedIndex;
SettingsManager.SaveSettingsToFile();
}
private void ToggleSwitchShowCircleCenter_Toggled(object sender, RoutedEventArgs e)
{
if (!_isLoaded) return;
SettingsManager.Settings.Canvas.ShowCircleCenter = CardShowCircleCenter.IsOn;
SettingsManager.SaveSettingsToFile();
}
private void ToggleSwitchFitToCurve_Toggled(object sender, RoutedEventArgs e)
{
if (!_isLoaded) return;
SettingsManager.Settings.Canvas.FitToCurve = CardFitToCurve.IsOn;
if (CardFitToCurve.IsOn)
{
SettingsManager.Settings.Canvas.UseAdvancedBezierSmoothing = false;
CardAdvancedBezierSmoothing.IsOn = false;
}
SettingsManager.SaveSettingsToFile();
}
private void ToggleSwitchAdvancedBezierSmoothing_Toggled(object sender, RoutedEventArgs e)
{
if (!_isLoaded) return;
SettingsManager.Settings.Canvas.UseAdvancedBezierSmoothing = CardAdvancedBezierSmoothing.IsOn;
if (CardAdvancedBezierSmoothing.IsOn)
{
SettingsManager.Settings.Canvas.FitToCurve = false;
CardFitToCurve.IsOn = false;
}
SettingsManager.SaveSettingsToFile();
}
private void ToggleSwitchEnableInkFade_Toggled(object sender, RoutedEventArgs e)
{
if (!_isLoaded) return;
SettingsManager.Settings.Canvas.EnableInkFade = CardEnableInkFade.IsOn;
SettingsManager.SaveSettingsToFile();
}
private void InkFadeTimeSlider_ValueChanged(object sender, RoutedPropertyChangedEventArgs<double> e)
{
if (!_isLoaded) return;
SettingsManager.Settings.Canvas.InkFadeTime = (int)e.NewValue;
SettingsManager.SaveSettingsToFile();
}
private void ToggleSwitchHideInkFadeControlInPenMenu_Toggled(object sender, RoutedEventArgs e)
{
if (!_isLoaded) return;
SettingsManager.Settings.Canvas.HideInkFadeControlInPenMenu = CardHideInkFadeControlInPenMenu.IsOn;
SettingsManager.SaveSettingsToFile();
}
private void ToggleSwitchBrushAutoRestore_Toggled(object sender, RoutedEventArgs e)
{
if (!_isLoaded) return;
SettingsManager.Settings.Canvas.EnableBrushAutoRestore = CardBrushAutoRestore.IsOn;
SettingsManager.SaveSettingsToFile();
}
private void BrushAutoRestoreTimesTextBox_TextChanged(object sender, TextChangedEventArgs e)
{
if (!_isLoaded) return;
SettingsManager.Settings.Canvas.BrushAutoRestoreTimes = BrushAutoRestoreTimesTextBox.Text ?? string.Empty;
SettingsManager.SaveSettingsToFile();
}
private void ComboBoxBrushAutoRestoreColor_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
if (!_isLoaded) return;
if (ComboBoxBrushAutoRestoreColor.SelectedItem is ComboBoxItem item)
{
string hex = item.Tag as string ?? string.Empty;
SettingsManager.Settings.Canvas.BrushAutoRestoreColor = hex;
SettingsManager.SaveSettingsToFile();
}
}
private void BrushAutoRestoreWidthSlider_ValueChanged(object sender, RoutedPropertyChangedEventArgs<double> e)
{
if (!_isLoaded) return;
SettingsManager.Settings.Canvas.BrushAutoRestoreWidth = e.NewValue;
SettingsManager.SaveSettingsToFile();
}
private void BrushAutoRestoreAlphaSlider_ValueChanged(object sender, RoutedPropertyChangedEventArgs<double> e)
{
if (!_isLoaded) return;
SettingsManager.Settings.Canvas.BrushAutoRestoreAlpha = (int)e.NewValue;
SettingsManager.SaveSettingsToFile();
}
private void ToggleSwitchEnableEraserAutoSwitchBack_Toggled(object sender, RoutedEventArgs e)
{
if (!_isLoaded) return;
SettingsManager.Settings.Canvas.EnableEraserAutoSwitchBack = CardEnableEraserAutoSwitchBack.IsOn;
SettingsManager.SaveSettingsToFile();
}
private void EraserAutoSwitchBackDelaySlider_ValueChanged(object sender, RoutedPropertyChangedEventArgs<double> e)
{
if (!_isLoaded) return;
SettingsManager.Settings.Canvas.EraserAutoSwitchBackDelaySeconds = (int)e.NewValue;
SettingsManager.SaveSettingsToFile();
}
#endregion
#region
private void ToggleSwitchEnableInkToShape_Toggled(object sender, RoutedEventArgs e)
{
if (!_isLoaded) return;
SettingsManager.Settings.InkToShape.IsInkToShapeEnabled = CardEnableInkToShape.IsOn;
SettingsManager.SaveSettingsToFile();
}
private void ComboBoxShapeRecognitionEngine_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
if (!_isLoaded || ComboBoxShapeRecognitionEngine == null) return;
int idx = ComboBoxShapeRecognitionEngine.SelectedIndex;
if (idx < 0) idx = 0;
if (idx > 2) idx = 2;
SettingsManager.Settings.InkToShape.ShapeRecognitionEngine = idx;
SettingsManager.SaveSettingsToFile();
}
private void ToggleSwitchEnableWinRtHandwritingStrokeBeautify_Toggled(object sender, RoutedEventArgs e)
{
if (!_isLoaded) return;
SettingsManager.Settings.InkToShape.EnableWinRtHandwritingStrokeBeautify = CardEnableWinRtHandwritingStrokeBeautify.IsOn;
SettingsManager.SaveSettingsToFile();
}
private void ToggleSwitchEnableInkToShapeNoFakePressureRectangle_Toggled(object sender, RoutedEventArgs e)
{
if (!_isLoaded) return;
SettingsManager.Settings.InkToShape.IsInkToShapeNoFakePressureRectangle = CardEnableInkToShapeNoFakePressureRectangle.IsOn;
SettingsManager.SaveSettingsToFile();
}
private void ToggleSwitchEnableInkToShapeNoFakePressureTriangle_Toggled(object sender, RoutedEventArgs e)
{
if (!_isLoaded) return;
SettingsManager.Settings.InkToShape.IsInkToShapeNoFakePressureTriangle = CardEnableInkToShapeNoFakePressureTriangle.IsOn;
SettingsManager.SaveSettingsToFile();
}
private void ToggleCheckboxEnableInkToShapeTriangle_CheckedChanged(object sender, RoutedEventArgs e)
{
if (!_isLoaded) return;
SettingsManager.Settings.InkToShape.IsInkToShapeTriangle = (bool)ToggleCheckboxEnableInkToShapeTriangle.IsChecked;
SettingsManager.SaveSettingsToFile();
}
private void ToggleCheckboxEnableInkToShapeRectangle_CheckedChanged(object sender, RoutedEventArgs e)
{
if (!_isLoaded) return;
SettingsManager.Settings.InkToShape.IsInkToShapeRectangle = (bool)ToggleCheckboxEnableInkToShapeRectangle.IsChecked;
SettingsManager.SaveSettingsToFile();
}
private void ToggleCheckboxEnableInkToShapeRounded_CheckedChanged(object sender, RoutedEventArgs e)
{
if (!_isLoaded) return;
SettingsManager.Settings.InkToShape.IsInkToShapeRounded = (bool)ToggleCheckboxEnableInkToShapeRounded.IsChecked;
SettingsManager.SaveSettingsToFile();
}
private void ToggleSwitchAutoStraightenLine_Toggled(object sender, RoutedEventArgs e)
{
if (!_isLoaded) return;
SettingsManager.Settings.Canvas.AutoStraightenLine = CardAutoStraightenLine.IsOn;
SettingsManager.SaveSettingsToFile();
}
private void AutoStraightenLineThresholdSlider_ValueChanged(object sender, RoutedPropertyChangedEventArgs<double> e)
{
if (!_isLoaded) return;
SettingsManager.Settings.Canvas.AutoStraightenLineThreshold = (int)e.NewValue;
SettingsManager.SaveSettingsToFile();
}
private void LineStraightenSensitivitySlider_ValueChanged(object sender, RoutedPropertyChangedEventArgs<double> e)
{
if (!_isLoaded) return;
SettingsManager.Settings.InkToShape.LineStraightenSensitivity = e.NewValue;
SettingsManager.SaveSettingsToFile();
}
private void ToggleSwitchHighPrecisionLineStraighten_Toggled(object sender, RoutedEventArgs e)
{
if (!_isLoaded) return;
SettingsManager.Settings.Canvas.HighPrecisionLineStraighten = CardHighPrecisionLineStraighten.IsOn;
SettingsManager.SaveSettingsToFile();
}
private void ToggleSwitchLineEndpointSnapping_Toggled(object sender, RoutedEventArgs e)
{
if (!_isLoaded) return;
SettingsManager.Settings.Canvas.LineEndpointSnapping = CardLineEndpointSnapping.IsOn;
SettingsManager.SaveSettingsToFile();
}
private void LineEndpointSnappingThresholdSlider_ValueChanged(object sender, RoutedPropertyChangedEventArgs<double> e)
{
if (!_isLoaded) return;
SettingsManager.Settings.Canvas.LineEndpointSnappingThreshold = (int)e.NewValue;
SettingsManager.SaveSettingsToFile();
}
#endregion
}
}
@@ -10,7 +10,8 @@
xmlns:i18n="clr-namespace:Ink_Canvas.MarkupExtensions"
xmlns:sys="clr-namespace:System;assembly=mscorlib"
xmlns:controls="clr-namespace:Ink_Canvas.Controls;assembly=InkCanvas.Controls"
mc:Ignorable="d"
xmlns:c="clr-namespace:Ink_Canvas.Converter"
mc:Ignorable="d"
Title="启动">
@@ -18,6 +19,7 @@
<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">
@@ -113,22 +115,17 @@
Icon="{x:Static ui:SegoeFluentIcons.ChevronLeft}"
SwitchName="ToggleSwitchFoldAtStartup"
Toggled="ToggleSwitchFoldAtStartup_Toggled" />
<!-- 模式设置 -->
<TextBlock Style="{StaticResource SettingsSectionHeaderTextBlockStyle}"
Text="模式设置" />
<ui:SettingsExpander Description="{i18n:I18n Key=Settings_ModeDesc}"
Header="{i18n:I18n Key=Settings_ModeDesc_1}">
<ui:SettingsExpander.HeaderIcon>
<ui:FontIcon Icon="{x:Static ui:SegoeFluentIcons.Settings}" />
</ui:SettingsExpander.HeaderIcon>
<ui:SettingsExpander.Items>
<ui:SettingsCard Header="仅PPT模式">
<ui:ToggleSwitch Name="ToggleSwitchPPTOnlyMode" OnContent="{i18n:I18n Key=Common_On}" OffContent="{i18n:I18n Key=Common_Off}" Toggled="ToggleSwitchPPTOnlyMode_Toggled" />
</ui:SettingsCard>
</ui:SettingsExpander.Items>
</ui:SettingsExpander>
<!-- 运行模式 -->
<TextBlock Style="{StaticResource SettingsSectionHeaderTextBlockStyle}"
Text="{i18n:I18n Key=Settings_ModeDesc_1}" />
<controls:LabeledSettingsCard x:Name="CardPPTOnlyMode"
Header="{i18n:I18n Key=Mode_PPTOnly}"
Description="{i18n:I18n Key=Settings_ModeDesc}"
Icon="{x:Static ui:SegoeFluentIcons.Settings}"
SwitchName="ToggleSwitchPPTOnlyMode"
Toggled="ToggleSwitchPPTOnlyMode_Toggled" />
<!-- 底部空白 -->
<Rectangle Height="48" />
@@ -115,7 +115,7 @@ namespace Ink_Canvas.Windows.SettingsViews.Pages
if (settings.ModeSettings != null)
{
ToggleSwitchPPTOnlyMode.IsOn = settings.ModeSettings.IsPPTOnlyMode;
CardPPTOnlyMode.IsOn = settings.ModeSettings.IsPPTOnlyMode;
}
}
catch (Exception ex)
@@ -361,7 +361,7 @@ namespace Ink_Canvas.Windows.SettingsViews.Pages
try
{
bool newState = ToggleSwitchPPTOnlyMode.IsOn;
bool newState = CardPPTOnlyMode.IsOn;
var window = Application.Current.MainWindow;
if (window != null)
@@ -0,0 +1,146 @@
<ui:Page x:Class="Ink_Canvas.Windows.SettingsViews.Pages.UpdatePage"
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"
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="CardAutoUpdate"
Header="{i18n:I18n Key=Header_AutoUpdate}"
Description="{i18n:I18n Key=Startup_AutoUpdateHint}"
Icon="{x:Static ui:SegoeFluentIcons.Sync}"
SwitchName="ToggleSwitchIsAutoUpdate"
Toggled="ToggleSwitchIsAutoUpdate_Toggled" />
<controls:LabeledSettingsCard x:Name="CardSilentUpdate"
Header="{i18n:I18n Key=Header_SilentUpdate}"
Description="{i18n:I18n Key=Startup_SilentUpdateHint}"
Icon="{x:Static ui:SegoeFluentIcons.QuietHours}"
SwitchName="ToggleSwitchIsAutoUpdateWithSilence"
ShowWhen="{Binding IsOn, ElementName=CardAutoUpdate}"
Toggled="ToggleSwitchIsAutoUpdateWithSilence_Toggled" />
<ui:SettingsExpander x:Name="ExpanderSilentUpdateTime"
Header="{i18n:I18n Key=Startup_SilentUpdateTimePeriod}"
Visibility="{Binding IsOn, ElementName=CardSilentUpdate, Converter={StaticResource BooleanToVisibilityConverter}}">
<ui:SettingsExpander.HeaderIcon>
<ui:FontIcon Icon="{x:Static ui:SegoeFluentIcons.Settings}" />
</ui:SettingsExpander.HeaderIcon>
<ui:SettingsExpander.Items>
<ui:SettingsCard Header="{i18n:I18n Key=Startup_SilentUpdateFullHint}">
<ui:SettingsCard.Content>
<ikw:SimpleStackPanel Orientation="Horizontal" Spacing="12">
<ikw:SimpleStackPanel Orientation="Horizontal">
<TextBlock Margin="0,0,10,0" VerticalAlignment="Center"
Text="{i18n:I18n Key=Startup_StartTime}" FontSize="14" />
<ComboBox x:Name="AutoUpdateWithSilenceStartTimeComboBox" Width="90"
SelectionChanged="AutoUpdateWithSilenceStartTimeComboBox_SelectionChanged" />
</ikw:SimpleStackPanel>
<ikw:SimpleStackPanel Orientation="Horizontal">
<TextBlock Margin="0,0,10,0" VerticalAlignment="Center"
Text="{i18n:I18n Key=Startup_EndTime}" FontSize="14" />
<ComboBox x:Name="AutoUpdateWithSilenceEndTimeComboBox" Width="90"
SelectionChanged="AutoUpdateWithSilenceEndTimeComboBox_SelectionChanged" />
</ikw:SimpleStackPanel>
</ikw:SimpleStackPanel>
</ui:SettingsCard.Content>
</ui:SettingsCard>
<ui:SettingsCard Header="{i18n:I18n Key=Startup_TimePeriodHint}" />
</ui:SettingsExpander.Items>
</ui:SettingsExpander>
<TextBlock Style="{StaticResource SettingsSectionHeaderTextBlockStyle}"
Text="更新通道" />
<ui:SettingsCard Header="{i18n:I18n Key=Startup_UpdateChannel}"
Description="{i18n:I18n Key=Startup_UpdateChannelHint}">
<ui:SettingsCard.HeaderIcon>
<ui:FontIcon Icon="{x:Static ui:SegoeFluentIcons.SyncFolder}" />
</ui:SettingsCard.HeaderIcon>
<ComboBox x:Name="UpdateChannelSelector" Width="160"
SelectionChanged="UpdateChannelSelector_SelectionChanged">
<ComboBoxItem Content="{i18n:I18n Key=Update_Release}" Tag="Release" />
<ComboBoxItem Content="{i18n:I18n Key=Update_Preview}" Tag="Preview" />
<ComboBoxItem Content="{i18n:I18n Key=Update_Beta}" Tag="Beta" />
</ComboBox>
</ui:SettingsCard>
<ui:SettingsCard Header="{i18n:I18n Key=Startup_UpdatePackageArchitecture}"
Description="{i18n:I18n Key=Startup_UpdatePackageArchitectureHint}">
<ui:SettingsCard.HeaderIcon>
<ui:FontIcon Icon="{x:Static ui:SegoeFluentIcons.DeveloperTools}" />
</ui:SettingsCard.HeaderIcon>
<ComboBox x:Name="UpdatePackageArchitectureSelector" Width="160"
SelectionChanged="UpdatePackageArchitectureSelector_SelectionChanged">
<ComboBoxItem Content="{i18n:I18n Key=Update_PackageArch_X86}" Tag="X86" />
<ComboBoxItem Content="{i18n:I18n Key=Update_PackageArch_X64}" Tag="X64" />
</ComboBox>
</ui:SettingsCard>
<TextBlock Style="{StaticResource SettingsSectionHeaderTextBlockStyle}"
Text="手动操作" />
<ui:SettingsCard Header="{i18n:I18n Key=Btn_ManualUpdate}"
Description="{i18n:I18n Key=Startup_ManualUpdateHint}">
<ui:SettingsCard.HeaderIcon>
<ui:FontIcon Icon="{x:Static ui:SegoeFluentIcons.Search}" />
</ui:SettingsCard.HeaderIcon>
<Button x:Name="ManualUpdateButton" Content="{i18n:I18n Key=Btn_ManualUpdate}"
Click="ManualUpdateButton_Click" />
</ui:SettingsCard>
<ui:SettingsCard Header="{i18n:I18n Key=Btn_FixVersion}"
Description="{i18n:I18n Key=Startup_FixVersionHint}">
<ui:SettingsCard.HeaderIcon>
<ui:FontIcon Icon="{x:Static ui:SegoeFluentIcons.Repair}" />
</ui:SettingsCard.HeaderIcon>
<Button x:Name="FixVersionButton" Content="{i18n:I18n Key=Btn_FixVersion}"
Click="FixVersionButton_Click" />
</ui:SettingsCard>
<ui:SettingsCard Header="{i18n:I18n Key=Btn_HistoryRollback}"
Description="{i18n:I18n Key=Startup_HistoryRollbackHint}">
<ui:SettingsCard.HeaderIcon>
<ui:FontIcon Icon="{x:Static ui:SegoeFluentIcons.History}" />
</ui:SettingsCard.HeaderIcon>
<Button Content="{i18n:I18n Key=Btn_HistoryRollback}"
Click="HistoryRollbackButton_Click" />
</ui:SettingsCard>
<Rectangle Height="48" />
</ikw:SimpleStackPanel>
</Grid>
</Grid>
</ScrollViewer>
</ui:Page>
@@ -0,0 +1,468 @@
using Ink_Canvas.Helpers;
using Ink_Canvas.Windows.SettingsViews.Helpers;
using System;
using System.Diagnostics;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Threading;
namespace Ink_Canvas.Windows.SettingsViews.Pages
{
public partial class UpdatePage : iNKORE.UI.WPF.Modern.Controls.Page
{
private bool _isLoaded = false;
private bool _isChangingUpdateChannelInternally = false;
private bool _isChangingUpdatePackageArchInternally = false;
public UpdatePage()
{
InitializeComponent();
Loaded += UpdatePage_Loaded;
}
private void UpdatePage_Loaded(object sender, RoutedEventArgs e)
{
LoadSettings();
_isLoaded = true;
}
private void LoadSettings()
{
_isLoaded = false;
try
{
var settings = SettingsManager.Settings;
if (settings.Startup != null)
{
CardAutoUpdate.IsOn = settings.Startup.IsAutoUpdate;
CardSilentUpdate.IsOn = settings.Startup.IsAutoUpdateWithSilence;
AutoUpdateWithSilenceTimeComboBox.InitializeAutoUpdateWithSilenceTimeComboBoxOptions(
AutoUpdateWithSilenceStartTimeComboBox, AutoUpdateWithSilenceEndTimeComboBox);
AutoUpdateWithSilenceStartTimeComboBox.SelectedItem = settings.Startup.AutoUpdateWithSilenceStartTime;
AutoUpdateWithSilenceEndTimeComboBox.SelectedItem = settings.Startup.AutoUpdateWithSilenceEndTime;
foreach (var item in UpdateChannelSelector.Items)
{
if (item is ComboBoxItem cbi && cbi.Tag != null &&
string.Equals(cbi.Tag.ToString(), settings.Startup.UpdateChannel.ToString(), StringComparison.OrdinalIgnoreCase))
{
UpdateChannelSelector.SelectedItem = cbi;
break;
}
}
_isChangingUpdatePackageArchInternally = true;
try
{
string wantTag = settings.Startup.UpdatePackageArchitecture == UpdatePackageArchitecture.X64 ? "X64" : "X86";
foreach (var item in UpdatePackageArchitectureSelector.Items)
{
if (item is ComboBoxItem cbi && cbi.Tag != null &&
string.Equals(cbi.Tag.ToString(), wantTag, StringComparison.OrdinalIgnoreCase))
{
UpdatePackageArchitectureSelector.SelectedItem = cbi;
break;
}
}
}
finally
{
_isChangingUpdatePackageArchInternally = false;
}
}
}
catch (Exception ex)
{
Debug.WriteLine($"加载更新设置时出错: {ex.Message}");
}
_isLoaded = true;
}
#region
private void ToggleSwitchIsAutoUpdate_Toggled(object sender, RoutedEventArgs e)
{
if (!_isLoaded) return;
try
{
bool newState = CardAutoUpdate.IsOn;
SettingsManager.Settings.Startup.IsAutoUpdate = newState;
if (!newState)
{
SettingsManager.Settings.Startup.IsAutoUpdateWithSilence = false;
CardSilentUpdate.IsOn = false;
}
SettingsManager.SaveSettingsToFile();
}
catch (Exception ex)
{
Debug.WriteLine($"设置自动更新时出错: {ex.Message}");
}
}
private void ToggleSwitchIsAutoUpdateWithSilence_Toggled(object sender, RoutedEventArgs e)
{
if (!_isLoaded) return;
try
{
bool newState = CardSilentUpdate.IsOn;
SettingsManager.Settings.Startup.IsAutoUpdateWithSilence = newState;
SettingsManager.SaveSettingsToFile();
}
catch (Exception ex)
{
Debug.WriteLine($"设置静默更新时出错: {ex.Message}");
}
}
private void AutoUpdateWithSilenceStartTimeComboBox_SelectionChanged(object sender, RoutedEventArgs e)
{
if (!_isLoaded) return;
try
{
SettingsManager.Settings.Startup.AutoUpdateWithSilenceStartTime =
(string)AutoUpdateWithSilenceStartTimeComboBox.SelectedItem;
SettingsManager.SaveSettingsToFile();
}
catch (Exception ex)
{
Debug.WriteLine($"设置静默更新开始时间时出错: {ex.Message}");
}
}
private void AutoUpdateWithSilenceEndTimeComboBox_SelectionChanged(object sender, RoutedEventArgs e)
{
if (!_isLoaded) return;
try
{
SettingsManager.Settings.Startup.AutoUpdateWithSilenceEndTime =
(string)AutoUpdateWithSilenceEndTimeComboBox.SelectedItem;
SettingsManager.SaveSettingsToFile();
}
catch (Exception ex)
{
Debug.WriteLine($"设置静默更新结束时间时出错: {ex.Message}");
}
}
#endregion
#region
private void UpdatePackageArchitectureSelector_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
if (!_isLoaded) return;
if (_isChangingUpdatePackageArchInternally) return;
if (!(UpdatePackageArchitectureSelector.SelectedItem is ComboBoxItem cbi) || cbi.Tag == null) return;
var newArch = string.Equals(cbi.Tag.ToString(), "X64", StringComparison.OrdinalIgnoreCase)
? UpdatePackageArchitecture.X64
: UpdatePackageArchitecture.X86;
if (SettingsManager.Settings.Startup.UpdatePackageArchitecture == newArch)
return;
SettingsManager.Settings.Startup.UpdatePackageArchitecture = newArch;
SettingsManager.SaveSettingsToFile();
LogHelper.WriteLogToFile($"Settings | Update package architecture: {newArch}");
}
private async void UpdateChannelSelector_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
if (!_isLoaded) return;
if (_isChangingUpdateChannelInternally) return;
if (!(UpdateChannelSelector.SelectedItem is ComboBoxItem cbi) || cbi.Tag == null) return;
var oldChannel = SettingsManager.Settings.Startup.UpdateChannel;
string channel = cbi.Tag.ToString();
UpdateChannel newChannel = channel == "Beta" ? UpdateChannel.Beta
: channel == "Preview" ? UpdateChannel.Preview
: UpdateChannel.Release;
if (SettingsManager.Settings.Startup.UpdateChannel == newChannel)
return;
bool isTestChannel = newChannel == UpdateChannel.Preview || newChannel == UpdateChannel.Beta;
if (isTestChannel && !SettingsManager.Settings.Startup.HasAcceptedTelemetryPrivacy)
{
MessageBox.Show(
"加入预览 / 测试通道前,请先在关于页面勾选\u201C我已阅读并同意 privacy 中的隐私说明\u201D。",
"需要同意隐私说明",
MessageBoxButton.OK,
MessageBoxImage.Warning);
SettingsManager.Settings.Startup.UpdateChannel = oldChannel;
RevertChannelSelection(oldChannel);
SettingsManager.SaveSettingsToFile();
LogHelper.WriteLogToFile("Settings | User not accepted privacy, reverted update channel");
return;
}
if (isTestChannel && SettingsManager.Settings.Startup.TelemetryUploadLevel == TelemetryUploadLevel.None)
{
var result = MessageBox.Show(
"加入预览 / 测试通道需要开启匿名基础数据上传。\n\n是否立即开启匿名基础数据上传?",
"需要开启匿名使用数据上传",
MessageBoxButton.YesNo,
MessageBoxImage.Warning);
if (result == MessageBoxResult.Yes)
{
SettingsManager.Settings.Startup.TelemetryUploadLevel = TelemetryUploadLevel.Basic;
SettingsManager.SaveSettingsToFile();
LogHelper.WriteLogToFile("Settings | Telemetry enabled (Basic) for preview/beta update channel");
}
else
{
SettingsManager.Settings.Startup.UpdateChannel = oldChannel;
RevertChannelSelection(oldChannel);
SettingsManager.SaveSettingsToFile();
LogHelper.WriteLogToFile("Settings | User declined telemetry, reverted update channel");
return;
}
}
SettingsManager.Settings.Startup.UpdateChannel = newChannel;
DeviceIdentifier.UpdateUsageChannel(newChannel);
LogHelper.WriteLogToFile($"Settings | Update channel changed to {SettingsManager.Settings.Startup.UpdateChannel}");
SettingsManager.SaveSettingsToFile();
if (SettingsManager.Settings.Startup.IsAutoUpdate)
{
LogHelper.WriteLogToFile($"AutoUpdate | Channel changed to {newChannel}, performing immediate update check");
var mainWindow = Application.Current.MainWindow as MainWindow;
if (mainWindow != null)
{
mainWindow.ResetUpdateCheckRetry();
await System.Threading.Tasks.Task.Run(async () =>
{
try
{
Dispatcher.Invoke(() =>
{
mainWindow.AutoUpdate();
});
}
catch (Exception ex)
{
LogHelper.WriteLogToFile($"AutoUpdate | Error during channel switch update check: {ex.Message}", LogHelper.LogType.Error);
}
});
}
}
else
{
LogHelper.WriteLogToFile($"AutoUpdate | Channel changed to {newChannel}, but auto-update is disabled");
}
}
private void RevertChannelSelection(UpdateChannel targetChannel)
{
Dispatcher.BeginInvoke(new Action(() =>
{
_isChangingUpdateChannelInternally = true;
try
{
string targetTag = targetChannel.ToString();
foreach (var item in UpdateChannelSelector.Items)
{
if (item is ComboBoxItem cbi && cbi.Tag != null &&
string.Equals(cbi.Tag.ToString(), targetTag, StringComparison.OrdinalIgnoreCase))
{
UpdateChannelSelector.SelectedItem = cbi;
break;
}
}
}
finally
{
_isChangingUpdateChannelInternally = false;
}
}), DispatcherPriority.Normal);
}
#endregion
#region
private async void ManualUpdateButton_Click(object sender, RoutedEventArgs e)
{
ManualUpdateButton.IsEnabled = false;
ManualUpdateButton.Content = "正在检查更新...";
try
{
LogHelper.WriteLogToFile("ManualUpdate | Manual update button clicked");
var (remoteVersion, lineGroup, apiReleaseNotes) = await AutoUpdateHelper.CheckForUpdates(SettingsManager.Settings.Startup.UpdateChannel, true, false);
if (remoteVersion != null)
{
LogHelper.WriteLogToFile($"ManualUpdate | Found new version: {remoteVersion}");
string currentVersion = System.Reflection.Assembly.GetExecutingAssembly().GetName().Version.ToString();
HasNewUpdateWindow updateWindow = new HasNewUpdateWindow(currentVersion, remoteVersion, "", apiReleaseNotes);
updateWindow.Owner = Application.Current.MainWindow;
bool? dialogResult = updateWindow.ShowDialog();
if (dialogResult != true)
{
LogHelper.WriteLogToFile("ManualUpdate | Update dialog closed without selection");
return;
}
var mainWindow = Application.Current.MainWindow as MainWindow;
switch (updateWindow.Result)
{
case HasNewUpdateWindow.UpdateResult.UpdateNow:
LogHelper.WriteLogToFile("ManualUpdate | User chose to update now");
MessageBox.Show("开始下载更新,请稍候...", "正在更新", MessageBoxButton.OK, MessageBoxImage.Information);
bool isDownloadSuccessful = mainWindow != null
&& await mainWindow.DownloadUpdateWithFallback(remoteVersion, lineGroup, SettingsManager.Settings.Startup.UpdateChannel);
if (isDownloadSuccessful)
{
MessageBoxResult result = MessageBox.Show("更新已下载完成,点击确定后将关闭软件并安装新版本!", "安装更新", MessageBoxButton.OKCancel, MessageBoxImage.Information);
if (result == MessageBoxResult.OK)
{
App.IsAppExitByUser = true;
AutoUpdateHelper.InstallNewVersionApp(remoteVersion, true);
Application.Current.Shutdown();
}
else
{
LogHelper.WriteLogToFile("ManualUpdate | User cancelled update installation");
}
}
else
{
MessageBox.Show("更新下载失败,请检查网络连接后重试。", "下载失败", MessageBoxButton.OK, MessageBoxImage.Error);
}
break;
case HasNewUpdateWindow.UpdateResult.UpdateLater:
LogHelper.WriteLogToFile("ManualUpdate | User chose to update later");
isDownloadSuccessful = mainWindow != null
&& await mainWindow.DownloadUpdateWithFallback(remoteVersion, lineGroup, SettingsManager.Settings.Startup.UpdateChannel);
if (isDownloadSuccessful)
{
LogHelper.WriteLogToFile("ManualUpdate | Update downloaded successfully, will install when application closes");
SettingsManager.Settings.Startup.IsAutoUpdate = true;
SettingsManager.Settings.Startup.IsAutoUpdateWithSilence = true;
if (mainWindow != null)
mainWindow.StartSilentUpdateTimer();
MessageBox.Show("更新已下载完成,将在软件关闭时自动安装。", "更新已准备就绪", MessageBoxButton.OK, MessageBoxImage.Information);
}
else
{
LogHelper.WriteLogToFile("ManualUpdate | Update download failed", LogHelper.LogType.Error);
MessageBox.Show("更新下载失败,请检查网络连接后重试。", "下载失败", MessageBoxButton.OK, MessageBoxImage.Error);
}
break;
case HasNewUpdateWindow.UpdateResult.SkipVersion:
LogHelper.WriteLogToFile($"ManualUpdate | User chose to skip version {remoteVersion}");
SettingsManager.Settings.Startup.SkippedVersion = remoteVersion;
SettingsManager.SaveSettingsToFile();
MessageBox.Show($"已设置跳过版本 {remoteVersion},在下次发布新版本之前不会再提示更新。",
"已跳过此版本",
MessageBoxButton.OK,
MessageBoxImage.Information);
break;
}
}
else
{
LogHelper.WriteLogToFile("ManualUpdate | No updates available");
MessageBox.Show("当前已是最新版本!", "无可用更新", MessageBoxButton.OK, MessageBoxImage.Information);
}
}
catch (Exception ex)
{
LogHelper.WriteLogToFile($"Error in ManualUpdateButton_Click: {ex.Message}", LogHelper.LogType.Error);
MessageBox.Show(
$"手动更新过程中发生错误: {ex.Message}",
"更新错误",
MessageBoxButton.OK,
MessageBoxImage.Error);
}
finally
{
ManualUpdateButton.IsEnabled = true;
ManualUpdateButton.Content = "手动更新";
}
}
private async void FixVersionButton_Click(object sender, RoutedEventArgs e)
{
var confirm = MessageBox.Show(
"此操作将下载当前选择通道的最新版本并安装,软件将自动关闭并更新。\n\n确定要执行版本修复吗?",
"版本修复确认",
MessageBoxButton.YesNo,
MessageBoxImage.Question);
if (confirm == MessageBoxResult.Yes)
{
FixVersionButton.IsEnabled = false;
FixVersionButton.Content = "正在修复...";
try
{
bool result = await AutoUpdateHelper.FixVersion(SettingsManager.Settings.Startup.UpdateChannel);
if (!result)
{
MessageBox.Show(
"版本修复失败,可能是网络问题或当前已是最新版本。",
"修复失败",
MessageBoxButton.OK,
MessageBoxImage.Error);
FixVersionButton.IsEnabled = true;
FixVersionButton.Content = "版本修复";
}
}
catch (Exception ex)
{
LogHelper.WriteLogToFile($"Error in FixVersionButton_Click: {ex.Message}", LogHelper.LogType.Error);
MessageBox.Show(
$"版本修复过程中发生错误: {ex.Message}",
"修复错误",
MessageBoxButton.OK,
MessageBoxImage.Error);
FixVersionButton.IsEnabled = true;
FixVersionButton.Content = "版本修复";
}
}
}
private void HistoryRollbackButton_Click(object sender, RoutedEventArgs e)
{
var win = new HistoryRollbackWindow(SettingsManager.Settings.Startup.UpdateChannel);
win.Owner = Application.Current.MainWindow;
win.ShowDialog();
}
#endregion
}
}
@@ -147,86 +147,39 @@
</ui:NavigationViewItem.MenuItems>
</ui:NavigationViewItem>
<!-- 页面2 -->
<!-- 更新设置 -->
<ui:NavigationViewItem
x:Name="Page2Item"
Content="页面 2"
Tag="Page2Page">
x:Name="UpdatePageItem"
Content="更新"
Tag="UpdatePage"
ToolTipService.ToolTip="更新设置">
<ui:NavigationViewItem.Icon>
<ui:SymbolIcon Symbol="Document" />
<ui:FontIcon Icon="{x:Static ui:SegoeFluentIcons.Sync}"/>
</ui:NavigationViewItem.Icon>
</ui:NavigationViewItem>
<!-- 设计设置 -->
<!-- 画板设置 -->
<ui:NavigationViewItem
x:Name="DesignItem"
Content="设计"
Tag="DesignPage"
SelectsOnInvoked="True">
x:Name="CanvasPageItem"
Content="画板"
Tag="CanvasPage"
ToolTipService.ToolTip="画板与墨迹设置">
<ui:NavigationViewItem.Icon>
<ui:FontIcon Icon="{x:Static ui:SegoeFluentIcons.Design}"/>
<ui:FontIcon Icon="{x:Static ui:SegoeFluentIcons.Edit}"/>
</ui:NavigationViewItem.Icon>
<ui:NavigationViewItem.MenuItems>
<ui:NavigationViewItem
x:Name="IconographyItem"
Content="图标"
Tag="IconographyPage"
ToolTipService.ToolTip="图标设置">
<ui:NavigationViewItem.Icon>
<ui:FontIcon Icon="{x:Static ui:SegoeFluentIcons.AllApps}"/>
</ui:NavigationViewItem.Icon>
</ui:NavigationViewItem>
<ui:NavigationViewItem
x:Name="TypographyItem"
Content="排版"
Tag="TypographyPage"
ToolTipService.ToolTip="排版设置">
<ui:NavigationViewItem.Icon>
<ui:FontIcon Icon="{x:Static ui:SegoeFluentIcons.Font}"/>
</ui:NavigationViewItem.Icon>
</ui:NavigationViewItem>
</ui:NavigationViewItem.MenuItems>
</ui:NavigationViewItem>
<!-- 外观设置 -->
<!-- Debug -->
<ui:NavigationViewItem
x:Name="AppearanceItem"
Content="外观"
Tag="AppearancePage"
SelectsOnInvoked="True">
x:Name="DebugPageItem"
Content="Debug"
Tag="DebugPage"
ToolTipService.ToolTip="Debug">
<ui:NavigationViewItem.Icon>
<ui:FontIcon Icon="{x:Static ui:SegoeFluentIcons.Color}"/>
<ui:FontIcon Icon="{x:Static ui:SegoeFluentIcons.DeveloperTools}"/>
</ui:NavigationViewItem.Icon>
<ui:NavigationViewItem.MenuItems>
<ui:NavigationViewItem
x:Name="ThemeItem"
Content="主题"
Tag="ThemePage"
ToolTipService.ToolTip="主题设置">
<ui:NavigationViewItem.Icon>
<ui:FontIcon Icon="{x:Static ui:FluentSystemIcons.DarkTheme_24_Regular}"/>
</ui:NavigationViewItem.Icon>
</ui:NavigationViewItem>
<ui:NavigationViewItem
x:Name="ColorsItem"
Content="颜色"
Tag="ColorsPage"
ToolTipService.ToolTip="颜色设置">
<ui:NavigationViewItem.Icon>
<ui:FontIcon Icon="{x:Static ui:SegoeFluentIcons.Highlight}"/>
</ui:NavigationViewItem.Icon>
</ui:NavigationViewItem>
<ui:NavigationViewItem
x:Name="FontsItem"
Content="字体"
Tag="FontsPage"
ToolTipService.ToolTip="字体设置">
<ui:NavigationViewItem.Icon>
<ui:FontIcon Icon="{x:Static ui:SegoeFluentIcons.Font}"/>
</ui:NavigationViewItem.Icon>
</ui:NavigationViewItem>
</ui:NavigationViewItem.MenuItems>
</ui:NavigationViewItem>
<ui:NavigationViewItemHeader Content="插件设置"/>
<ui:NavigationViewItem
x:Name="PluginItem"
@@ -36,15 +36,10 @@ namespace Ink_Canvas.Windows.SettingsViews
{
{ "HomePage", typeof(HomePage) },
{ "BasicPage", typeof(BasicPage) },
{ "Page2Page", typeof(Page2Page) },
{ "DesignPage", typeof(DesignPage) },
{ "AppearancePage", typeof(AppearancePage) },
{ "IconographyPage", typeof(IconographyPage) },
{ "TypographyPage", typeof(TypographyPage) },
{ "ThemePage", typeof(ThemePage) },
{ "ColorsPage", typeof(ColorsPage) },
{ "FontsPage", typeof(FontsPage) },
{ "StartupPage", typeof(StartupPage) },
{ "UpdatePage", typeof(UpdatePage) },
{ "CanvasPage", typeof(CanvasPage) },
{ "DebugPage", typeof(IconographyPage) },
{ "AboutPage", typeof(AboutPage) },
{ "Settings", typeof(SettingsPage) },
{ "PluginPage", typeof(PluginPage) },