Skip to content

Commit

Permalink
重构桌面UI (#184)
Browse files Browse the repository at this point in the history
* 重制登录窗口

* 添加标题栏头像组件

* 重制热门和视频分区

* 完成直播分区重制

* 重制动漫及影视页面

* 重制overlay页面

* 内化部分组件

* 初步完成已有功能的UI翻新

* 支持主题切换
  • Loading branch information
Richasy authored Dec 29, 2023
1 parent 4556b7b commit bcd8eda
Show file tree
Hide file tree
Showing 340 changed files with 6,317 additions and 4,996 deletions.
166 changes: 93 additions & 73 deletions src/App/App.csproj

Large diffs are not rendered by default.

210 changes: 83 additions & 127 deletions src/App/App.xaml.cs
Original file line number Diff line number Diff line change
@@ -1,28 +1,19 @@
// Copyright (c) Bili Copilot. All rights reserved.

using System;
using System.IO;
using Bili.Copilot.App.Controls;
using Bili.Copilot.App.Forms;
using Bili.Copilot.Libs.Provider;
using Bili.Copilot.Libs.Toolkit;
using Bili.Copilot.Models.Constants.App;
using H.NotifyIcon;
using Microsoft.AppCenter;
using Microsoft.AppCenter.Analytics;
using Microsoft.AppCenter.Crashes;
using Microsoft.UI;
using Microsoft.UI.Dispatching;
using Microsoft.UI.Windowing;
using Microsoft.UI.Xaml;
using Microsoft.UI.Xaml.Controls;
using Microsoft.UI.Xaml.Input;
using Microsoft.Windows.AppLifecycle;
using NLog;
using Windows.ApplicationModel;
using Windows.ApplicationModel.Activation;
using Windows.Graphics;
using Windows.Storage;
using WinRT.Interop;

namespace Bili.Copilot.App;

Expand All @@ -45,7 +36,7 @@ public partial class App : Application
public App()
{
// 初始化 App Center.
var appCenterFilePath = Path.Combine(Package.Current.InstalledLocation.Path, "Assets/AppCenterSecret.txt");
var appCenterFilePath = Path.Combine(Windows.ApplicationModel.Package.Current.InstalledLocation.Path, "Assets/AppCenterSecret.txt");
if (File.Exists(appCenterFilePath))
{
var id = File.ReadAllText(appCenterFilePath);
Expand All @@ -56,7 +47,7 @@ public App()
}

InitializeComponent();
var mainAppInstance = Microsoft.Windows.AppLifecycle.AppInstance.FindOrRegisterForKey(Id);
var mainAppInstance = AppInstance.FindOrRegisterForKey(Id);
mainAppInstance.Activated += OnAppInstanceActivated;
UnhandledException += OnUnhandledException;
}
Expand All @@ -65,93 +56,51 @@ public App()

private bool HandleCloseEvents { get; set; }

/// <summary>
/// Try activating the window and bringing it to the foreground.
/// </summary>
public void ActivateWindow(AppActivationArguments arguments = default)
{
_dispatcherQueue.TryEnqueue(() =>
{
if (_window == null)
{
LaunchWindow();
}
else if (_window.Visible && HandleCloseEvents && arguments?.Data == null)
{
_window.Hide();
}
else
{
_window.Activate();
Windows.Win32.PInvoke.SetForegroundWindow(new Windows.Win32.Foundation.HWND(WindowNative.GetWindowHandle(_window)));
}

try
{
if (arguments?.Data is IActivatedEventArgs args)
{
MainWindow.Instance.ActivateArgumentsAsync(args);
}
}
catch (Exception)
{
}
});
}

/// <summary>
/// Invoked when the application is launched.
/// </summary>
/// <param name="args">Details about the launch request and process.</param>
protected override void OnLaunched(Microsoft.UI.Xaml.LaunchActivatedEventArgs args)
protected override async void OnLaunched(Microsoft.UI.Xaml.LaunchActivatedEventArgs args)
{
_dispatcherQueue = DispatcherQueue.GetForCurrentThread();
var rootFolder = ApplicationData.Current.LocalFolder;
var fullPath = $"{rootFolder.Path}\\Logger\\";
NLog.GlobalDiagnosticsContext.Set("LogPath", fullPath);
var instance = AppInstance.FindOrRegisterForKey(Id);
if (instance.IsCurrent)
{
_dispatcherQueue = DispatcherQueue.GetForCurrentThread();
var rootFolder = ApplicationData.Current.LocalFolder;
var fullPath = $"{rootFolder.Path}\\Logger\\";
NLog.GlobalDiagnosticsContext.Set("LogPath", fullPath);
}

var instance = Microsoft.Windows.AppLifecycle.AppInstance.FindOrRegisterForKey(Id);
var eventArgs = instance.GetActivatedEventArgs();
var data = eventArgs.Data is IActivatedEventArgs
? eventArgs.Data as IActivatedEventArgs
: args.UWPLaunchActivatedEventArgs;

LaunchWindow(data);
await LaunchWindowAsync(data);
TraceLogger.Instance.LogAppLaunched();
}

private static RectInt32 GetRenderRect(DisplayArea displayArea, IntPtr windowHandle)
/// <summary>
/// Try activating the window and bringing it to the foreground.
/// </summary>
private void ActivateWindow(AppActivationArguments arguments = default)
{
var workArea = displayArea.WorkArea;
var scaleFactor = Windows.Win32.PInvoke.GetDpiForWindow(new Windows.Win32.Foundation.HWND(windowHandle)) / 96d;
var previousWidth = SettingsToolkit.ReadLocalSetting(SettingNames.WindowWidth, 500d);
var previousHeight = SettingsToolkit.ReadLocalSetting(SettingNames.WindowHeight, 800d);
var width = Convert.ToInt32(previousWidth * scaleFactor);
var height = Convert.ToInt32(previousHeight * scaleFactor);

// Ensure the window is not larger than the work area.
if (height > workArea.Height - 20)
_ = _dispatcherQueue.TryEnqueue(async () =>
{
height = workArea.Height - 20;
}

var lastPoint = GetSavedWindowPosition();
var isZeroPoint = lastPoint.X == 0 && lastPoint.Y == 0;
var isValidPosition = lastPoint.X >= workArea.X && lastPoint.Y >= workArea.Y;
var left = isZeroPoint || !isValidPosition
? (workArea.Width - width) / 2d
: lastPoint.X - workArea.X;
var top = isZeroPoint || !isValidPosition
? (workArea.Height - height) / 2d
: lastPoint.Y - workArea.Y;
return new RectInt32(Convert.ToInt32(left), Convert.ToInt32(top), width, height);
}

private static PointInt32 GetSavedWindowPosition()
{
var left = SettingsToolkit.ReadLocalSetting(SettingNames.WindowPositionLeft, 0);
var top = SettingsToolkit.ReadLocalSetting(SettingNames.WindowPositionTop, 0);
return new PointInt32(left, top);
if (_window == null)
{
await LaunchWindowAsync();
}
else if (_window.Visible && HandleCloseEvents && arguments?.Data == null)
{
_ = _window.Hide();
}
else
{
_window.Activate();
_ = _window.SetForegroundWindow();
}
});
}

private void InitializeTrayIcon()
Expand All @@ -167,28 +116,66 @@ private void InitializeTrayIcon()
var exitApplicationCommand = (XamlUICommand)Resources["QuitCommand"];
exitApplicationCommand.ExecuteRequested += OnQuitCommandExecuteRequested;

TrayIcon = (TaskbarIcon)Resources["TrayIcon"];
TrayIcon.ForceCreate();
try
{
TrayIcon = (TaskbarIcon)Resources["TrayIcon"];
TrayIcon.ForceCreate();
}
catch (Exception)
{
var logger = LogManager.GetCurrentClassLogger();
logger.Error("Failed to initialize tray icon");
}
}

private void LaunchWindow(IActivatedEventArgs args = default)
private async Task LaunchWindowAsync(IActivatedEventArgs args = default)
{
_window = new MainWindow(args);
MoveAndResize();
_window.Closed += OnMainWindowClosedAsync;

HandleCloseEvents = SettingsToolkit.ReadLocalSetting(SettingNames.HideWhenCloseWindow, true);
if (HandleCloseEvents)
if (args is IProtocolActivatedEventArgs protocolArgs
&& !string.IsNullOrEmpty(protocolArgs.Uri.Host))
{
InitializeTrayIcon();
// 处理协议启动.
}
else
{
var instance = AppInstance.FindOrRegisterForKey(Id);

// If the current instance is not the previously registered instance
if (!instance.IsCurrent)
{
var activatedArgs = AppInstance.GetCurrent().GetActivatedEventArgs();

// Redirect to the existing instance
await instance.RedirectActivationToAsync(activatedArgs);

// Kill the current instance
Current.Exit();
return;
}

_window.Activate();
var isSignedIn = await AuthorizeProvider.Instance.IsTokenValidAsync();
if (!isSignedIn)
{
var window = new SignInWindow();
window.Activate();
}
else
{
_window = new MainWindow();
_window.Closed += OnMainWindowClosedAsync;

HandleCloseEvents = SettingsToolkit.ReadLocalSetting(SettingNames.HideWhenCloseWindow, true);
if (HandleCloseEvents)
{
InitializeTrayIcon();
}

_window.Activate();
}
}
}

private async void OnMainWindowClosedAsync(object sender, WindowEventArgs args)
{
SaveCurrentWindowStats();
HandleCloseEvents = SettingsToolkit.ReadLocalSetting(SettingNames.HideWhenCloseWindow, true);
if (HandleCloseEvents)
{
Expand Down Expand Up @@ -225,41 +212,10 @@ private async void OnMainWindowClosedAsync(object sender, WindowEventArgs args)
}

InitializeTrayIcon();
_window.Hide();
_ = _window.Hide();
}
}

private void MoveAndResize()
{
var hwnd = WindowNative.GetWindowHandle(_window);
var windowId = Win32Interop.GetWindowIdFromWindow(hwnd);
var lastPoint = GetSavedWindowPosition();
var displayArea = lastPoint.X == 0 && lastPoint.Y == 0
? DisplayArea.GetFromWindowId(windowId, DisplayAreaFallback.Nearest)
: DisplayArea.GetFromPoint(lastPoint, DisplayAreaFallback.Nearest);
if (displayArea != null)
{
var rect = GetRenderRect(displayArea, hwnd);
var scaleFactor = Windows.Win32.PInvoke.GetDpiForWindow(new Windows.Win32.Foundation.HWND(hwnd)) / 96d;
_window.MinWidth = 500;
_window.MinHeight = 400;

var maxHeight = (displayArea.WorkArea.Height / scaleFactor) + 16;
_window.MaxHeight = maxHeight < 400 ? 400 : maxHeight;
_window.AppWindow.MoveAndResize(rect);
}
}

private void SaveCurrentWindowStats()
{
var left = _window.AppWindow.Position.X;
var top = _window.AppWindow.Position.Y;
SettingsToolkit.WriteLocalSetting(SettingNames.WindowPositionLeft, left);
SettingsToolkit.WriteLocalSetting(SettingNames.WindowPositionTop, top);
SettingsToolkit.WriteLocalSetting(SettingNames.WindowHeight, _window.Height > 400 ? _window.Height : 800);
SettingsToolkit.WriteLocalSetting(SettingNames.WindowWidth, _window.Width > 500 ? _window.Width : 500);
}

private void ExitApp()
{
HandleCloseEvents = false;
Expand Down
2 changes: 2 additions & 0 deletions src/App/Assets/ReaderClean.js
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,8 @@ function setAppearance() {
body {
background: $body-background$ !important;
margin-top: 20px !important;
margin-left: 16px !important;
}
`;

Expand Down
66 changes: 0 additions & 66 deletions src/App/Controls/AIFeatureDialog.xaml

This file was deleted.

Loading

0 comments on commit bcd8eda

Please sign in to comment.