- Fluent Design 风格 UI,深色/浅色主题切换 - 平滑过渡动画(页面切换、按钮交互、状态变化) - 五大核心功能:安装管理、墨迹管理、格式转换、触摸设置、激活管理 - 基于 dotnetCampus.EasiPlugin.Sdk v2.1.1-alpha.3 插件框架 - WPF 安装向导(欢迎页 -> 安装页 -> 完成页)
346 lines
12 KiB
C#
346 lines
12 KiB
C#
/*
|
||
* InstallPage.xaml.cs - Better-Seewo 安装向导安装页面逻辑
|
||
* 负责模拟安装过程、更新进度条和日志、管理安装步骤状态
|
||
* 作者:雾启工作室
|
||
*/
|
||
|
||
using System;
|
||
using System.IO;
|
||
using System.Threading.Tasks;
|
||
using System.Windows;
|
||
using System.Windows.Controls;
|
||
using System.Windows.Media.Animation;
|
||
|
||
namespace Better_Seewo.Installer.Pages
|
||
{
|
||
/// <summary>
|
||
/// InstallPage 的交互逻辑 - 安装向导安装页面
|
||
/// </summary>
|
||
public partial class InstallPage : Page
|
||
{
|
||
/// <summary>
|
||
/// 当前安装进度(0-100)
|
||
/// </summary>
|
||
private int _currentProgress;
|
||
|
||
/// <summary>
|
||
/// 标记安装是否已启动
|
||
/// </summary>
|
||
private bool _isStarted;
|
||
|
||
/// <summary>
|
||
/// 构造函数,初始化页面组件
|
||
/// </summary>
|
||
public InstallPage()
|
||
{
|
||
InitializeComponent();
|
||
|
||
// 设置默认安装路径
|
||
TxtInstallPath.Text = App.InstallPath;
|
||
}
|
||
|
||
/// <summary>
|
||
/// 浏览按钮点击 - 选择安装路径
|
||
/// </summary>
|
||
private void BtnBrowse_Click(object sender, RoutedEventArgs e)
|
||
{
|
||
// 如果安装已开始则不允许更改路径
|
||
if (_isStarted) return;
|
||
|
||
// 使用文件夹浏览对话框选择安装路径
|
||
var dialog = new System.Windows.Forms.FolderBrowserDialog
|
||
{
|
||
Description = "选择 Better-Seewo 安装路径",
|
||
ShowNewFolderButton = true,
|
||
SelectedPath = TxtInstallPath.Text
|
||
};
|
||
|
||
if (dialog.ShowDialog() == System.Windows.Forms.DialogResult.OK)
|
||
{
|
||
TxtInstallPath.Text = dialog.SelectedPath;
|
||
App.InstallPath = dialog.SelectedPath;
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// 开始安装过程(由主窗口调用)
|
||
/// 模拟三个安装步骤:检测EN5 -> 复制文件 -> 注册插件
|
||
/// </summary>
|
||
public async void StartInstallation()
|
||
{
|
||
if (_isStarted) return;
|
||
_isStarted = true;
|
||
|
||
try
|
||
{
|
||
// 禁用路径输入和浏览按钮
|
||
TxtInstallPath.IsReadOnly = true;
|
||
|
||
// 更新安装路径
|
||
App.InstallPath = TxtInstallPath.Text;
|
||
|
||
// ===== 步骤 1:检测 EN5 安装状态 =====
|
||
SetStepStatus(1, "running");
|
||
AppendLog($"[{DateTime.Now:HH:mm:ss}] 正在检测 EasiNote5 安装状态...");
|
||
await Task.Delay(800);
|
||
|
||
// 检查 EN5 安装目录是否存在
|
||
string en5Path = GetEn5InstallPath();
|
||
bool en5Exists = !string.IsNullOrEmpty(en5Path) && Directory.Exists(en5Path);
|
||
|
||
if (en5Exists)
|
||
{
|
||
AppendLog($"[{DateTime.Now:HH:mm:ss}] 已检测到 EasiNote5 安装路径: {en5Path}");
|
||
SetStepStatus(1, "success");
|
||
}
|
||
else
|
||
{
|
||
AppendLog($"[{DateTime.Now:HH:mm:ss}] 未检测到 EasiNote5 安装,将继续安装到指定路径");
|
||
SetStepStatus(1, "warning");
|
||
}
|
||
|
||
UpdateProgress(25);
|
||
await Task.Delay(300);
|
||
|
||
// ===== 步骤 2:复制插件文件 =====
|
||
SetStepStatus(2, "running");
|
||
AppendLog($"[{DateTime.Now:HH:mm:ss}] 正在复制插件文件...");
|
||
await Task.Delay(600);
|
||
|
||
// 创建目标目录
|
||
string installDir = App.InstallPath;
|
||
try
|
||
{
|
||
if (!Directory.Exists(installDir))
|
||
{
|
||
Directory.CreateDirectory(installDir);
|
||
AppendLog($"[{DateTime.Now:HH:mm:ss}] 已创建安装目录: {installDir}");
|
||
}
|
||
|
||
// TODO: 实际安装时,将插件文件从安装包复制到目标目录
|
||
// 以下为模拟文件复制过程
|
||
string[] mockFiles = {
|
||
"Better-EN5.dll",
|
||
"Better-EN5.pdb",
|
||
"Newtonsoft.Json.dll",
|
||
"config.json"
|
||
};
|
||
|
||
foreach (var file in mockFiles)
|
||
{
|
||
await Task.Delay(200);
|
||
AppendLog($"[{DateTime.Now:HH:mm:ss}] 正在复制: {file}");
|
||
UpdateProgress(25 + (Array.IndexOf(mockFiles, file) + 1) * 10);
|
||
}
|
||
|
||
AppendLog($"[{DateTime.Now:HH:mm:ss}] 插件文件复制完成");
|
||
SetStepStatus(2, "success");
|
||
}
|
||
catch (Exception ex)
|
||
{
|
||
AppendLog($"[{DateTime.Now:HH:mm:ss}] 复制文件失败: {ex.Message}");
|
||
SetStepStatus(2, "error");
|
||
throw;
|
||
}
|
||
|
||
await Task.Delay(300);
|
||
|
||
// ===== 步骤 3:注册插件 =====
|
||
SetStepStatus(3, "running");
|
||
AppendLog($"[{DateTime.Now:HH:mm:ss}] 正在注册插件...");
|
||
await Task.Delay(500);
|
||
|
||
try
|
||
{
|
||
// TODO: 实际安装时,写入注册表或配置文件完成插件注册
|
||
await Task.Delay(400);
|
||
AppendLog($"[{DateTime.Now:HH:mm:ss}] 正在写入插件配置...");
|
||
UpdateProgress(80);
|
||
|
||
await Task.Delay(300);
|
||
AppendLog($"[{DateTime.Now:HH:mm:ss}] 正在注册 EasiNote5 插件组件...");
|
||
UpdateProgress(90);
|
||
|
||
await Task.Delay(300);
|
||
AppendLog($"[{DateTime.Now:HH:mm:ss}] 插件注册完成");
|
||
SetStepStatus(3, "success");
|
||
}
|
||
catch (Exception ex)
|
||
{
|
||
AppendLog($"[{DateTime.Now:HH:mm:ss}] 注册插件失败: {ex.Message}");
|
||
SetStepStatus(3, "error");
|
||
throw;
|
||
}
|
||
|
||
// ===== 安装完成 =====
|
||
UpdateProgress(100);
|
||
AppendLog($"[{DateTime.Now:HH:mm:ss}] ========================================");
|
||
AppendLog($"[{DateTime.Now:HH:mm:ss}] 安装完成!Better-Seewo v{App.AppVersion} 已成功安装");
|
||
AppendLog($"[{DateTime.Now:HH:mm:ss}] 安装路径: {App.InstallPath}");
|
||
|
||
// 延迟后自动切换到完成页
|
||
await Task.Delay(1000);
|
||
|
||
// 通知主窗口安装完成
|
||
if (Window.GetWindow(this) is MainWindow mainWindow)
|
||
{
|
||
mainWindow.OnInstallCompleted();
|
||
}
|
||
}
|
||
catch (Exception ex)
|
||
{
|
||
AppendLog($"[{DateTime.Now:HH:mm:ss}] 安装过程中发生错误: {ex.Message}");
|
||
MessageBox.Show(
|
||
$"安装失败:{ex.Message}",
|
||
"Better-Seewo 安装程序",
|
||
MessageBoxButton.OK,
|
||
MessageBoxImage.Error
|
||
);
|
||
|
||
// 恢复按钮状态,允许重试
|
||
if (Window.GetWindow(this) is MainWindow mainWindow)
|
||
{
|
||
mainWindow.BtnInstall.IsEnabled = true;
|
||
mainWindow.BtnInstall.Content = "重试安装 \uE74E;";
|
||
mainWindow.BtnBack.IsEnabled = true;
|
||
}
|
||
|
||
App.IsInstalling = false;
|
||
_isStarted = false;
|
||
}
|
||
}
|
||
|
||
#region ===== 辅助方法 =====
|
||
|
||
/// <summary>
|
||
/// 获取 EasiNote5 的安装路径
|
||
/// 检查常见的 EN5 安装目录
|
||
/// </summary>
|
||
private static string GetEn5InstallPath()
|
||
{
|
||
// 常见的 EasiNote5 安装路径
|
||
string[] possiblePaths = {
|
||
@"C:\Program Files (x86)\Seewo\EasiNote5",
|
||
@"C:\Program Files\Seewo\EasiNote5",
|
||
@"D:\Program Files (x86)\Seewo\EasiNote5",
|
||
@"D:\Program Files\Seewo\EasiNote5"
|
||
};
|
||
|
||
foreach (var path in possiblePaths)
|
||
{
|
||
if (Directory.Exists(path))
|
||
{
|
||
return path;
|
||
}
|
||
}
|
||
|
||
return null;
|
||
}
|
||
|
||
/// <summary>
|
||
/// 设置安装步骤的状态图标
|
||
/// </summary>
|
||
/// <param name="step">步骤编号(1-3)</param>
|
||
/// <param name="status">状态:running/success/warning/error</param>
|
||
private void SetStepStatus(int step, string status)
|
||
{
|
||
// 确保在 UI 线程执行
|
||
Dispatcher.Invoke(() =>
|
||
{
|
||
var icon = step switch
|
||
{
|
||
1 => Step1Icon,
|
||
2 => Step2Icon,
|
||
3 => Step3Icon,
|
||
_ => Step1Icon
|
||
};
|
||
|
||
if (icon == null) return;
|
||
|
||
// 根据状态设置图标和颜色
|
||
icon.Text = status switch
|
||
{
|
||
"running" => "⏳",
|
||
"success" => "✓",
|
||
"warning" => "⚠",
|
||
"error" => "✗",
|
||
_ => "⏳"
|
||
};
|
||
|
||
icon.Foreground = status switch
|
||
{
|
||
"running" => (System.Windows.Media.Brush)FindResource("WarningBrush"),
|
||
"success" => (System.Windows.Media.Brush)FindResource("SuccessBrush"),
|
||
"warning" => (System.Windows.Media.Brush)FindResource("WarningBrush"),
|
||
"error" => (System.Windows.Media.Brush)FindResource("ErrorBrush"),
|
||
_ => (System.Windows.Media.Brush)FindResource("TextSecondaryBrush")
|
||
};
|
||
});
|
||
}
|
||
|
||
/// <summary>
|
||
/// 更新进度条和百分比文字
|
||
/// </summary>
|
||
/// <param name="progress">进度值(0-100)</param>
|
||
private void UpdateProgress(int progress)
|
||
{
|
||
_currentProgress = Math.Clamp(progress, 0, 100);
|
||
|
||
// 确保在 UI 线程执行
|
||
Dispatcher.Invoke(() =>
|
||
{
|
||
// 更新百分比文字
|
||
TxtProgress.Text = $"{_currentProgress}%";
|
||
|
||
// 更新进度条宽度(使用动画)
|
||
var widthAnimation = new DoubleAnimation
|
||
{
|
||
From = (ProgressFill.ActualWidth > 0 ? ProgressFill.ActualWidth : 0),
|
||
To = (_currentProgress / 100.0) * ProgressFill.Parent.ActualWidth,
|
||
Duration = TimeSpan.FromMilliseconds(300),
|
||
EasingFunction = new CubicEase { EasingMode = EasingMode.EaseOut }
|
||
};
|
||
|
||
// 如果父容器尚未布局完成,直接设置宽度
|
||
if (ProgressFill.Parent.ActualWidth == 0)
|
||
{
|
||
// 等待布局完成后设置
|
||
ProgressFill.Loaded += (s, e) =>
|
||
{
|
||
var loadedAnimation = new DoubleAnimation
|
||
{
|
||
From = 0,
|
||
To = (_currentProgress / 100.0) * ProgressFill.Parent.ActualWidth,
|
||
Duration = TimeSpan.FromMilliseconds(300),
|
||
EasingFunction = new CubicEase { EasingMode = EasingMode.EaseOut }
|
||
};
|
||
ProgressFill.BeginAnimation(WidthProperty, loadedAnimation);
|
||
};
|
||
}
|
||
else
|
||
{
|
||
ProgressFill.BeginAnimation(WidthProperty, widthAnimation);
|
||
}
|
||
});
|
||
}
|
||
|
||
/// <summary>
|
||
/// 向日志文本框追加一行日志
|
||
/// </summary>
|
||
/// <param name="message">日志消息</param>
|
||
private void AppendLog(string message)
|
||
{
|
||
// 确保在 UI 线程执行
|
||
Dispatcher.Invoke(() =>
|
||
{
|
||
TxtLog.Text += message + Environment.NewLine;
|
||
|
||
// 自动滚动到底部
|
||
LogScrollViewer.ScrollToEnd();
|
||
});
|
||
}
|
||
|
||
#endregion
|
||
}
|
||
}
|