BililiveRecorder/BililiveRecorder.WPF/Pages/RootPage.xaml.cs

362 lines
14 KiB
C#
Raw Normal View History

2020-11-27 18:51:02 +08:00
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
2020-12-10 17:02:56 +08:00
using System.Threading.Tasks;
2020-11-27 18:51:02 +08:00
using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;
2020-12-10 17:02:56 +08:00
using System.Windows.Threading;
2020-11-27 18:51:02 +08:00
using BililiveRecorder.Core;
2021-02-23 18:03:37 +08:00
using BililiveRecorder.Core.Config;
2021-02-08 16:51:19 +08:00
using BililiveRecorder.DependencyInjection;
2020-11-27 18:51:02 +08:00
using BililiveRecorder.WPF.Controls;
using BililiveRecorder.WPF.Models;
2021-02-08 16:51:19 +08:00
using Microsoft.Extensions.DependencyInjection;
2022-04-16 01:54:43 +08:00
using ModernWpf;
2020-11-27 18:51:02 +08:00
using ModernWpf.Controls;
2020-12-10 17:02:56 +08:00
using ModernWpf.Media.Animation;
2021-02-23 18:03:37 +08:00
using Serilog;
2020-11-27 18:51:02 +08:00
using Path = System.IO.Path;
2021-02-23 18:03:37 +08:00
#nullable enable
2020-11-27 18:51:02 +08:00
namespace BililiveRecorder.WPF.Pages
{
/// <summary>
/// Interaction logic for RootPage.xaml
/// </summary>
public partial class RootPage : UserControl
{
2021-02-23 18:03:37 +08:00
private static readonly ILogger logger = Log.ForContext<RootPage>();
internal static string? CommandArgumentRecorderPath = null;
internal static bool CommandArgumentFirstRun = false; // TODO
internal static bool CommandArgumentAskPath = false;
2021-07-16 21:03:07 +08:00
internal static bool CommandArgumentHide = false;
2020-11-27 18:51:02 +08:00
private readonly Dictionary<string, Type> PageMap = new Dictionary<string, Type>();
private readonly WorkDirectoryLoader workDirectoryLoader = new WorkDirectoryLoader();
2020-12-10 17:02:56 +08:00
private readonly NavigationTransitionInfo transitionInfo = new DrillInNavigationTransitionInfo();
2020-11-27 18:51:02 +08:00
private int SettingsClickCount = 0;
internal static IServiceProvider? ServiceProvider { get; private set; }
2022-05-17 00:53:37 +08:00
private ServiceProvider serviceProvider = null!;
2020-11-27 18:51:02 +08:00
internal RootModel Model { get; private set; }
internal static Action? SwitchToSettingsPage { get; private set; }
2020-11-27 18:51:02 +08:00
public RootPage()
{
2021-01-01 14:46:27 +08:00
void AddType(Type t) => this.PageMap.Add(t.Name, t);
2020-11-27 18:51:02 +08:00
AddType(typeof(RoomListPage));
AddType(typeof(SettingsPage));
2021-05-01 00:22:27 +08:00
AddType(typeof(LogPage));
AddType(typeof(AboutPage));
2020-11-27 18:51:02 +08:00
AddType(typeof(AdvancedSettingsPage));
2020-12-11 19:22:04 +08:00
AddType(typeof(AnnouncementPage));
2021-02-23 18:03:37 +08:00
AddType(typeof(ToolboxAutoFixPage));
2021-08-10 00:49:46 +08:00
AddType(typeof(ToolboxRemuxPage));
2021-08-10 18:53:04 +08:00
AddType(typeof(ToolboxDanmakuMergerPage));
2020-11-27 18:51:02 +08:00
2021-01-01 14:46:27 +08:00
this.Model = new RootModel();
this.DataContext = this.Model;
2020-11-27 18:51:02 +08:00
2021-01-01 14:46:27 +08:00
this.InitializeComponent();
this.AdvancedSettingsPageItem.Visibility = Visibility.Hidden;
2020-11-27 18:51:02 +08:00
2021-05-01 00:22:27 +08:00
#if DEBUG
this.DebugBuildIcon.Visibility = Visibility.Visible;
#endif
2021-01-03 13:21:36 +08:00
var mw = Application.Current.MainWindow as NewMainWindow;
if (mw is not null)
mw.NativeBeforeWindowClose += this.RootPage_NativeBeforeWindowClose;
2021-02-08 16:51:19 +08:00
Loaded += this.RootPage_Loaded;
SwitchToSettingsPage = () =>
{
this.SettingsPageNavigationViewItem.IsSelected = true;
};
2020-11-27 18:51:02 +08:00
}
2020-12-03 07:01:12 +08:00
private void RootPage_NativeBeforeWindowClose(object sender, EventArgs e)
{
2021-01-01 14:46:27 +08:00
this.Model.Dispose();
2020-12-03 07:01:12 +08:00
SingleInstance.Cleanup();
}
2021-05-01 17:57:43 +08:00
#pragma warning disable VSTHRD100 // Avoid async void methods
2020-11-27 18:51:02 +08:00
private async void RootPage_Loaded(object sender, RoutedEventArgs e)
2021-05-01 17:57:43 +08:00
#pragma warning restore VSTHRD100 // Avoid async void methods
2020-11-27 18:51:02 +08:00
{
if (CommandArgumentFirstRun)
{
_ = Task.Run(async () =>
{
await Task.Delay(1000);
_ = this.Dispatcher.BeginInvoke(DispatcherPriority.Normal, (Action)(() =>
{
MessageBox.Show(Window.GetWindow(this), @"B站录播姬 安装成功!
使
BililiveRecorder Installed!
Please use the shortcut on the desktop or
in the start menu to launch.
You can uninstall me in system settings.", " Installed", MessageBoxButton.OK, MessageBoxImage.Information);
}));
});
}
// 上次选择的路径信息
var pathInfo = this.workDirectoryLoader.Read();
// 第一次尝试从命令行和配置文件自动选择路径
var first_time = true;
// 如果是从命令行参数传入的路径,则不保存选择的路径到文件
2021-02-23 18:03:37 +08:00
var from_argument = false;
// 路径选择错误
2021-01-05 22:50:10 +08:00
var error = WorkDirectorySelectorDialog.WorkDirectorySelectorDialogError.None;
// 最终选择的路径
2020-11-27 18:51:02 +08:00
string path;
2021-02-23 18:03:37 +08:00
2020-11-27 18:51:02 +08:00
while (true)
{
try
{
// 获取一个路径
if (first_time)
2020-11-27 18:51:02 +08:00
{
// while 循环第一次运行时检查命令行参数、和上次选择记住的路径
try
{
first_time = false;
2021-02-23 18:03:37 +08:00
if (!string.IsNullOrWhiteSpace(CommandArgumentRecorderPath))
{
// 如果有参数直接跳到检查路径
2021-06-17 19:15:31 +08:00
logger.Debug("Using path from command argument");
2021-02-23 18:03:37 +08:00
path = Path.GetFullPath(CommandArgumentRecorderPath);
from_argument = true; // 用于控制不写入文件保存
}
else if (pathInfo.SkipAsking && !CommandArgumentAskPath)
{
2021-06-17 19:15:31 +08:00
logger.Debug("Using path from path.json file");
// 上次选择了“不再询问”
path = pathInfo.Path;
}
else
{
// 无命令行参数 和 记住选择
continue;
}
}
catch (Exception)
{
// 出错直接重新来,不显示 error
continue;
}
2020-11-27 18:51:02 +08:00
}
else
{
// 尝试读取上次选择的路径
var lastdir = pathInfo.Path;
2020-11-27 18:51:02 +08:00
// 显示路径选择界面
var dialog = new WorkDirectorySelectorDialog
{
Error = error,
Path = lastdir,
SkipAsking = pathInfo.SkipAsking,
Owner = Application.Current.MainWindow
};
var dialogResult = await dialog.ShowAndDisableMinimizeToTrayAsync();
2021-02-23 18:03:37 +08:00
switch (dialogResult)
{
2021-02-23 18:03:37 +08:00
case ContentDialogResult.Primary:
2021-06-17 19:15:31 +08:00
logger.Debug("Confirm path selected");
2021-02-23 18:03:37 +08:00
break;
case ContentDialogResult.Secondary:
2021-06-17 19:15:31 +08:00
logger.Debug("Toolbox mode selected");
2021-02-23 18:03:37 +08:00
return;
case ContentDialogResult.None:
default:
2021-06-17 19:15:31 +08:00
logger.Debug("Exit selected");
2021-02-23 18:03:37 +08:00
(Application.Current.MainWindow as NewMainWindow)!.CloseWithoutConfirmAction();
return;
}
2020-11-27 18:51:02 +08:00
pathInfo.SkipAsking = dialog.SkipAsking;
try
{ path = Path.GetFullPath(dialog.Path); }
catch (Exception)
{
2021-01-05 22:50:10 +08:00
error = WorkDirectorySelectorDialog.WorkDirectorySelectorDialogError.PathNotSupported;
continue;
}
}
// 获取一个路径结束
2020-11-27 18:51:02 +08:00
2021-02-23 18:03:37 +08:00
var configFilePath = Path.Combine(path, "config.json");
if (!Directory.Exists(path))
2020-11-27 18:51:02 +08:00
{
2021-01-05 22:50:10 +08:00
error = WorkDirectorySelectorDialog.WorkDirectorySelectorDialogError.PathDoesNotExist;
continue;
2020-11-27 18:51:02 +08:00
}
else if (!Directory.EnumerateFiles(path).Any(x => Path.GetFileName(x) != "desktop.ini"))
2020-11-27 18:51:02 +08:00
{
// 可用的空文件夹
}
2021-02-23 18:03:37 +08:00
else if (!File.Exists(configFilePath))
{
2021-01-05 22:50:10 +08:00
error = WorkDirectorySelectorDialog.WorkDirectorySelectorDialogError.PathContainsFiles;
continue;
}
// 已经选定工作目录
// 如果不是从命令行参数传入的路径,写入 lastdir_path 记录
try
2021-02-23 18:03:37 +08:00
{
if (!from_argument)
{
pathInfo.Path = path;
this.workDirectoryLoader.Write(pathInfo);
}
2021-02-23 18:03:37 +08:00
}
catch (Exception) { }
2020-12-10 17:02:56 +08:00
2021-02-23 18:03:37 +08:00
// 加载配置文件
var config = ConfigParser.LoadFrom(path);
if (config is null)
{
2021-02-23 18:03:37 +08:00
error = WorkDirectorySelectorDialog.WorkDirectorySelectorDialogError.FailedToLoadConfig;
continue;
2020-11-27 18:51:02 +08:00
}
2021-02-23 18:03:37 +08:00
config.Global.WorkDirectory = path;
// 检查已经在同目录运行的其他进程
if (!SingleInstance.CheckMutex(path))
2020-11-27 18:51:02 +08:00
{
// 有已经在其他目录运行的进程,已经通知该进程,本进程退出
2021-02-23 18:03:37 +08:00
(Application.Current.MainWindow as NewMainWindow)!.CloseWithoutConfirmAction();
return;
2020-11-27 18:51:02 +08:00
}
2021-02-23 18:03:37 +08:00
// 无已经在同目录运行的进程
this.serviceProvider = this.BuildServiceProvider(config, logger);
ServiceProvider = this.serviceProvider;
2021-02-23 18:03:37 +08:00
var recorder = this.serviceProvider.GetRequiredService<IRecorder>();
this.Model.Recorder = recorder;
this.RoomListPageNavigationViewItem.IsEnabled = true;
this.SettingsPageNavigationViewItem.IsEnabled = true;
2021-02-27 18:14:44 +08:00
(Application.Current.MainWindow as NewMainWindow)!.HideToTray = true;
2021-12-17 19:51:48 +08:00
NetworkChangeDetector.Enable();
2021-02-23 18:03:37 +08:00
_ = Task.Run(async () =>
{
2021-04-30 19:35:15 +08:00
await Task.Delay(150);
2021-02-23 18:03:37 +08:00
_ = this.Dispatcher.BeginInvoke(DispatcherPriority.Normal, method: new Action(() =>
{
this.RoomListPageNavigationViewItem.IsSelected = true;
2021-07-16 21:03:07 +08:00
if (CommandArgumentHide)
Application.Current.MainWindow.WindowState = WindowState.Minimized;
2021-02-23 18:03:37 +08:00
}));
});
break;
2020-11-27 18:51:02 +08:00
}
catch (Exception ex)
2020-11-27 18:51:02 +08:00
{
2021-01-05 22:50:10 +08:00
error = WorkDirectorySelectorDialog.WorkDirectorySelectorDialogError.UnknownError;
2021-02-23 18:03:37 +08:00
logger.Warning(ex, "选择工作目录时发生了未知错误");
continue;
2020-11-27 18:51:02 +08:00
}
}
}
2021-12-19 21:10:34 +08:00
private ServiceProvider BuildServiceProvider(Core.Config.V3.ConfigV3 config, ILogger logger) => new ServiceCollection()
2021-02-23 18:03:37 +08:00
.AddSingleton(logger)
.AddRecorderConfig(config)
.AddFlv()
.AddRecorder()
.BuildServiceProvider();
2020-11-27 18:51:02 +08:00
private void NavigationView_SelectionChanged(NavigationView sender, NavigationViewSelectionChangedEventArgs args)
{
2021-01-01 14:46:27 +08:00
this.SettingsClickCount = 0;
2020-11-27 18:51:02 +08:00
if (args.IsSettingsSelected)
{
2021-01-01 14:46:27 +08:00
this.MainFrame.Navigate(typeof(SettingsPage), null, this.transitionInfo);
2020-11-27 18:51:02 +08:00
}
else
{
var selectedItem = (NavigationViewItem)args.SelectedItem;
var selectedItemTag = (string)selectedItem.Tag;
2020-12-11 19:22:04 +08:00
if (selectedItemTag.StartsWith("http"))
{
try
{
2021-01-01 14:46:27 +08:00
this.MainFrame.Navigate(new Uri(selectedItemTag), null, this.transitionInfo);
2020-12-11 19:22:04 +08:00
}
catch (Exception)
{
}
}
2021-01-01 14:46:27 +08:00
else if (this.PageMap.ContainsKey(selectedItemTag))
2020-11-27 18:51:02 +08:00
{
2021-01-01 14:46:27 +08:00
var pageType = this.PageMap[selectedItemTag];
this.MainFrame.Navigate(pageType, null, this.transitionInfo);
2020-11-27 18:51:02 +08:00
}
}
}
private void NavigationViewItem_MouseRightButtonUp(object sender, MouseButtonEventArgs e)
{
2021-01-08 18:54:50 +08:00
if (++this.SettingsClickCount > 1)
2020-11-27 18:51:02 +08:00
{
2021-01-01 14:46:27 +08:00
this.SettingsClickCount = 0;
this.AdvancedSettingsPageItem.Visibility = this.AdvancedSettingsPageItem.Visibility != Visibility.Visible ? Visibility.Visible : Visibility.Hidden;
2020-11-27 18:51:02 +08:00
}
}
2020-11-28 13:02:57 +08:00
2020-12-10 17:02:56 +08:00
private void MainFrame_Navigated(object sender, System.Windows.Navigation.NavigationEventArgs e)
{
try
{
if (sender is not ModernWpf.Controls.Frame frame) return;
while (frame.BackStackDepth > 0)
{
frame.RemoveBackEntry();
}
}
catch (Exception)
{
}
}
2022-04-16 01:54:43 +08:00
private void SwitchLightDarkTheme_Click(object sender, RoutedEventArgs e)
{
if (this.Dispatcher.CheckAccess())
changeTheme();
else
_ = this.Dispatcher.BeginInvoke(changeTheme);
static void changeTheme()
{
ThemeManager.Current.ApplicationTheme =
ThemeManager.Current.ActualApplicationTheme == ApplicationTheme.Dark
? ApplicationTheme.Light
: ApplicationTheme.Dark;
};
}
2020-11-27 18:51:02 +08:00
}
}