From a0e51d976ef156775abf13ec5987028d2de90cd1 Mon Sep 17 00:00:00 2001 From: Zhe Fang Date: Fri, 6 Jun 2025 22:03:28 -0400 Subject: [PATCH] add: user can now change title bar size; support full screen mode; some other user interface adjustment (still in testing) --- .../BetterLyrics.WinUI3/App.xaml | 28 ++ .../BetterLyrics.WinUI3/App.xaml.cs | 15 +- .../BetterLyrics.WinUI3.csproj | 3 +- .../BetterLyrics.WinUI3/MainWindow.xaml.cs | 178 ------------- .../Models/TitleBarType.cs | 14 + .../Settings/SettingsDefaultValues.cs | 3 + .../Services/Settings/SettingsKey.cs | 3 + .../Services/Settings/SettingsService.cs | 32 +-- .../Strings/en-US/Resources.resw | 52 ++-- .../Strings/zh-CN/Resources.resw | 50 ++-- .../Strings/zh-TW/Resources.resw | 50 ++-- .../ViewModels/BaseWindowModel.cs | 15 ++ .../ViewModels/SettingsViewModel.cs | 4 +- .../BaseWindow.xaml} | 163 ++++++------ .../Views/BaseWindow.xaml.cs | 244 ++++++++++++++++++ .../BetterLyrics.WinUI3/Views/MainPage.xaml | 109 +++----- .../Views/MainPage.xaml.cs | 87 +++---- .../Views/SettingsPage.xaml | 16 ++ 18 files changed, 583 insertions(+), 483 deletions(-) delete mode 100644 BetterLyrics.WinUI3/BetterLyrics.WinUI3/MainWindow.xaml.cs create mode 100644 BetterLyrics.WinUI3/BetterLyrics.WinUI3/Models/TitleBarType.cs create mode 100644 BetterLyrics.WinUI3/BetterLyrics.WinUI3/ViewModels/BaseWindowModel.cs rename BetterLyrics.WinUI3/BetterLyrics.WinUI3/{MainWindow.xaml => Views/BaseWindow.xaml} (54%) create mode 100644 BetterLyrics.WinUI3/BetterLyrics.WinUI3/Views/BaseWindow.xaml.cs diff --git a/BetterLyrics.WinUI3/BetterLyrics.WinUI3/App.xaml b/BetterLyrics.WinUI3/BetterLyrics.WinUI3/App.xaml index e9d4b64..89e4738 100644 --- a/BetterLyrics.WinUI3/BetterLyrics.WinUI3/App.xaml +++ b/BetterLyrics.WinUI3/BetterLyrics.WinUI3/App.xaml @@ -57,6 +57,34 @@ + + + + + + diff --git a/BetterLyrics.WinUI3/BetterLyrics.WinUI3/App.xaml.cs b/BetterLyrics.WinUI3/BetterLyrics.WinUI3/App.xaml.cs index 9dc4393..622a353 100644 --- a/BetterLyrics.WinUI3/BetterLyrics.WinUI3/App.xaml.cs +++ b/BetterLyrics.WinUI3/BetterLyrics.WinUI3/App.xaml.cs @@ -32,12 +32,13 @@ namespace BetterLyrics.WinUI3 private readonly ILogger _logger; public static new App Current => (App)Application.Current; - public MainWindow? MainWindow { get; private set; } - public MainWindow? SettingsWindow { get; set; } + public BaseWindow? MainWindow { get; private set; } + public BaseWindow? SettingsWindow { get; set; } public static ResourceLoader? ResourceLoader { get; private set; } - public static DispatcherQueue DispatcherQueue => DispatcherQueue.GetForCurrentThread(); + public static DispatcherQueue? DispatcherQueue { get; private set; } + public static DispatcherQueueTimer? DispatcherQueueTimer { get; private set; } /// /// Initializes the singleton application object. This is the first line of authored code @@ -47,7 +48,9 @@ namespace BetterLyrics.WinUI3 { this.InitializeComponent(); - App.ResourceLoader = new ResourceLoader(); + DispatcherQueue = DispatcherQueue.GetForCurrentThread(); + DispatcherQueueTimer = DispatcherQueue.CreateTimer(); + ResourceLoader = new ResourceLoader(); Helper.AppInfo.EnsureDirectories(); ConfigureServices(); @@ -67,7 +70,6 @@ namespace BetterLyrics.WinUI3 // Register services Ioc.Default.ConfigureServices( new ServiceCollection() - .AddSingleton(DispatcherQueue.GetForCurrentThread()) .AddLogging(loggingBuilder => { loggingBuilder.ClearProviders(); @@ -77,6 +79,7 @@ namespace BetterLyrics.WinUI3 .AddSingleton() .AddSingleton() // ViewModels + .AddSingleton() .AddSingleton() .AddSingleton() .BuildServiceProvider() @@ -101,7 +104,7 @@ namespace BetterLyrics.WinUI3 Encoding.RegisterProvider(CodePagesEncodingProvider.Instance); // Activate the window - MainWindow = new MainWindow(); + MainWindow = new BaseWindow(); MainWindow!.Navigate(typeof(MainPage)); MainWindow.Activate(); } diff --git a/BetterLyrics.WinUI3/BetterLyrics.WinUI3/BetterLyrics.WinUI3.csproj b/BetterLyrics.WinUI3/BetterLyrics.WinUI3/BetterLyrics.WinUI3.csproj index 065135b..8ef85ec 100644 --- a/BetterLyrics.WinUI3/BetterLyrics.WinUI3/BetterLyrics.WinUI3.csproj +++ b/BetterLyrics.WinUI3/BetterLyrics.WinUI3/BetterLyrics.WinUI3.csproj @@ -31,7 +31,8 @@ - + + diff --git a/BetterLyrics.WinUI3/BetterLyrics.WinUI3/MainWindow.xaml.cs b/BetterLyrics.WinUI3/BetterLyrics.WinUI3/MainWindow.xaml.cs deleted file mode 100644 index 6735171..0000000 --- a/BetterLyrics.WinUI3/BetterLyrics.WinUI3/MainWindow.xaml.cs +++ /dev/null @@ -1,178 +0,0 @@ -using System; -using BetterLyrics.WinUI3.Helper; -using BetterLyrics.WinUI3.Messages; -using BetterLyrics.WinUI3.Services.Settings; -using BetterLyrics.WinUI3.Views; -using CommunityToolkit.Mvvm.DependencyInjection; -using CommunityToolkit.Mvvm.Messaging; -using CommunityToolkit.WinUI.Behaviors; -using DevWinUI; -using Microsoft.Graphics.Canvas.UI.Xaml; -using Microsoft.UI.Windowing; -using Microsoft.UI.Xaml; -using Microsoft.UI.Xaml.Controls; -using Microsoft.UI.Xaml.Media.Animation; -using Microsoft.UI.Xaml.Navigation; - -// To learn more about WinUI, the WinUI project structure, -// and more about our project templates, see: http://aka.ms/winui-project-info. - -namespace BetterLyrics.WinUI3 -{ - /// - /// An empty window that can be used on its own or navigated to within a Frame. - /// - public sealed partial class MainWindow : Window - { - private readonly OverlappedPresenter _presenter; - - private readonly SettingsService _settingsService; - - public static StackedNotificationsBehavior? StackedNotificationsBehavior - { - get; - private set; - } - - public MainWindow() - { - this.InitializeComponent(); - - _settingsService = Ioc.Default.GetService()!; - - RootGrid.RequestedTheme = (ElementTheme)_settingsService.Theme; - SystemBackdrop = SystemBackdropHelper.CreateSystemBackdrop( - (BackdropType)_settingsService.BackdropType - ); - - WeakReferenceMessenger.Default.Register( - this, - (r, m) => - { - RootGrid.RequestedTheme = m.Value; - } - ); - - WeakReferenceMessenger.Default.Register( - this, - (r, m) => - { - SystemBackdrop = null; - SystemBackdrop = SystemBackdropHelper.CreateSystemBackdrop(m.Value); - } - ); - - // AppWindow.SetIcon("white_round.ico"); - StackedNotificationsBehavior = NotificationQueue; - - _presenter = (OverlappedPresenter)AppWindow.Presenter; - - ExtendsContentIntoTitleBar = true; - AppWindow.TitleBar.PreferredHeightOption = TitleBarHeightOption.Collapsed; - SetTitleBar(TopCommandGrid); - } - - public void Navigate(Type type) - { - RootFrame.Navigate(type); - } - - private void RootFrame_NavigationFailed(object sender, NavigationFailedEventArgs e) - { - throw new Exception("Failed to load Page " + e.SourcePageType.FullName); - } - - private void CloseButton_Click(object sender, RoutedEventArgs e) - { - if (RootFrame.CurrentSourcePageType == typeof(MainPage)) - { - ( - (RootFrame.Content as MainPage)!.FindChild("LyricsCanvas") - as CanvasAnimatedControl - )!.Paused = true; - App.Current.Exit(); - } - else if (RootFrame.CurrentSourcePageType == typeof(SettingsPage)) - { - App.Current.SettingsWindow!.AppWindow.Hide(); - } - } - - private void MaximiseButton_Click(object sender, RoutedEventArgs e) - { - _presenter.Maximize(); - //MaximiseButton.Visibility = Visibility.Collapsed; - //RestoreButton.Visibility = Visibility.Visible; - } - - private void MinimiseButton_Click(object sender, RoutedEventArgs e) - { - _presenter.Minimize(); - } - - private void RestoreButton_Click(object sender, RoutedEventArgs e) - { - _presenter.Restore(); - //MaximiseButton.Visibility = Visibility.Visible; - //RestoreButton.Visibility = Visibility.Collapsed; - } - - private void Window_SizeChanged(object sender, WindowSizeChangedEventArgs args) - { - if (_presenter.State == OverlappedPresenterState.Maximized) - { - MaximiseButton.Visibility = Visibility.Collapsed; - RestoreButton.Visibility = Visibility.Visible; - } - else if (_presenter.State == OverlappedPresenterState.Restored) - { - MaximiseButton.Visibility = Visibility.Visible; - RestoreButton.Visibility = Visibility.Collapsed; - } - } - - private void MiniButton_Click(object sender, RoutedEventArgs e) - { - AppWindow.Resize(new Windows.Graphics.SizeInt32(144, 48)); - MiniButton.Visibility = Visibility.Collapsed; - UnminiButton.Visibility = Visibility.Visible; - MinimiseButton.Visibility = Visibility.Collapsed; - MaximiseButton.Visibility = Visibility.Collapsed; - RestoreButton.Visibility = Visibility.Collapsed; - CloseButton.Visibility = Visibility.Collapsed; - } - - private void UnminiButton_Click(object sender, RoutedEventArgs e) - { - AppWindow.Resize(new Windows.Graphics.SizeInt32(800, 600)); - MiniButton.Visibility = Visibility.Visible; - UnminiButton.Visibility = Visibility.Collapsed; - MinimiseButton.Visibility = Visibility.Visible; - MaximiseButton.Visibility = Visibility.Visible; - RestoreButton.Visibility = Visibility.Collapsed; - CloseButton.Visibility = Visibility.Visible; - } - - private void RootFrame_Navigated(object sender, NavigationEventArgs e) - { - AppWindow.Title = Title = App.ResourceLoader!.GetString( - $"{e.SourcePageType.Name}Title" - ); - } - - private void AOTButton_Click(object sender, RoutedEventArgs e) - { - _presenter.IsAlwaysOnTop = !_presenter.IsAlwaysOnTop; - string prefix; - if (_presenter.IsAlwaysOnTop) - { - prefix = "Show"; - } - else - { - prefix = "Hide"; - } - (PinnedFontIcon.Resources[$"{prefix}PinnedFontIconStoryboard"] as Storyboard)!.Begin(); - } - } -} diff --git a/BetterLyrics.WinUI3/BetterLyrics.WinUI3/Models/TitleBarType.cs b/BetterLyrics.WinUI3/BetterLyrics.WinUI3/Models/TitleBarType.cs new file mode 100644 index 0000000..59926c7 --- /dev/null +++ b/BetterLyrics.WinUI3/BetterLyrics.WinUI3/Models/TitleBarType.cs @@ -0,0 +1,14 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace BetterLyrics.WinUI3.Models +{ + public enum TitleBarType + { + Compact, + Extended, + } +} diff --git a/BetterLyrics.WinUI3/BetterLyrics.WinUI3/Services/Settings/SettingsDefaultValues.cs b/BetterLyrics.WinUI3/BetterLyrics.WinUI3/Services/Settings/SettingsDefaultValues.cs index e4b3929..9cf6bca 100644 --- a/BetterLyrics.WinUI3/BetterLyrics.WinUI3/Services/Settings/SettingsDefaultValues.cs +++ b/BetterLyrics.WinUI3/BetterLyrics.WinUI3/Services/Settings/SettingsDefaultValues.cs @@ -27,6 +27,9 @@ namespace BetterLyrics.WinUI3.Services.Settings public const int CoverOverlayOpacity = 100; // 1.0 public const int CoverOverlayBlurAmount = 200; + // Title bar + public const int TitleBarType = 0; + // Album art public const int CoverImageRadius = 24; diff --git a/BetterLyrics.WinUI3/BetterLyrics.WinUI3/Services/Settings/SettingsKey.cs b/BetterLyrics.WinUI3/BetterLyrics.WinUI3/Services/Settings/SettingsKey.cs index 6117a88..f14ded0 100644 --- a/BetterLyrics.WinUI3/BetterLyrics.WinUI3/Services/Settings/SettingsKey.cs +++ b/BetterLyrics.WinUI3/BetterLyrics.WinUI3/Services/Settings/SettingsKey.cs @@ -26,6 +26,9 @@ namespace BetterLyrics.WinUI3.Services.Settings public const string CoverOverlayOpacity = "CoverOverlayOpacity"; public const string CoverOverlayBlurAmount = "CoverOverlayBlurAmount"; + // Title bar + public const string TitleBarType = "TitleBarType"; + // Album art public const string CoverImageRadius = "CoverImageRadius"; diff --git a/BetterLyrics.WinUI3/BetterLyrics.WinUI3/Services/Settings/SettingsService.cs b/BetterLyrics.WinUI3/BetterLyrics.WinUI3/Services/Settings/SettingsService.cs index 9908541..f954eae 100644 --- a/BetterLyrics.WinUI3/BetterLyrics.WinUI3/Services/Settings/SettingsService.cs +++ b/BetterLyrics.WinUI3/BetterLyrics.WinUI3/Services/Settings/SettingsService.cs @@ -33,28 +33,6 @@ namespace BetterLyrics.WinUI3.Services.Settings _musicLibraries.CollectionChanged += (_, _) => SaveMusicLibraries(); } - private void WatchMultipleDirectories(IEnumerable directories) - { - foreach (var dir in directories) - { - if (!Directory.Exists(dir)) - continue; - - var watcher = new FileSystemWatcher - { - Path = dir, - Filter = "*.*", - NotifyFilter = NotifyFilters.FileName | NotifyFilters.LastWrite, - EnableRaisingEvents = true, - }; - } - } - - private void OnFileCreated(object sender, FileSystemEventArgs e) - { - App.DispatcherQueue.TryEnqueue(() => { }); - } - public bool IsFirstRun { get => Get(SettingsKeys.IsFirstRun, SettingsDefaultValues.IsFirstRun); @@ -64,6 +42,9 @@ namespace BetterLyrics.WinUI3.Services.Settings [ObservableProperty] private bool _isRebuildingLyricsIndexDatabase = false; + [ObservableProperty] + private bool _isImmersiveMode = false; + // Theme public int Theme { @@ -172,6 +153,13 @@ namespace BetterLyrics.WinUI3.Services.Settings set => Set(SettingsKeys.CoverOverlayBlurAmount, value); } + // Title bar + public int TitleBarType + { + get => Get(SettingsKeys.TitleBarType, SettingsDefaultValues.TitleBarType); + set => Set(SettingsKeys.TitleBarType, value); + } + // Album art public int CoverImageRadius { diff --git a/BetterLyrics.WinUI3/BetterLyrics.WinUI3/Strings/en-US/Resources.resw b/BetterLyrics.WinUI3/BetterLyrics.WinUI3/Strings/en-US/Resources.resw index 02afdd6..7e3c40a 100644 --- a/BetterLyrics.WinUI3/BetterLyrics.WinUI3/Strings/en-US/Resources.resw +++ b/BetterLyrics.WinUI3/BetterLyrics.WinUI3/Strings/en-US/Resources.resw @@ -276,6 +276,9 @@ Show lyrics only + + Immersive mode + Lyrics effect @@ -309,35 +312,11 @@ Rebuilding the database, please wait... - - Let's get started now - Welcome to BetterLyrics - - The top area is the title bar - - - Hover on the top area to show it - - - Setup lyrics database now - - - Hover on the bottom left corner and then click to open settings page - - - Hover on the bottom area to show it - - - The bottom area is the command area - - - Toggle "show lyrics only" here - - - When lyrics exist, you can switch them in the lower right corner + + Let's setup lyrics database now No music playing now @@ -369,4 +348,25 @@ Corner radius + + Title bar size + + + Compact + + + Extended + + + Always on top + + + Full screen + + + Press Esc to exit full screen mode + + + Hover back again to show the toggle button + \ No newline at end of file diff --git a/BetterLyrics.WinUI3/BetterLyrics.WinUI3/Strings/zh-CN/Resources.resw b/BetterLyrics.WinUI3/BetterLyrics.WinUI3/Strings/zh-CN/Resources.resw index e303bb2..194691e 100644 --- a/BetterLyrics.WinUI3/BetterLyrics.WinUI3/Strings/zh-CN/Resources.resw +++ b/BetterLyrics.WinUI3/BetterLyrics.WinUI3/Strings/zh-CN/Resources.resw @@ -276,6 +276,9 @@ 仅展示歌词 + + 沉浸模式 + 歌词效果 @@ -309,36 +312,12 @@ 重构数据库中,请稍候... - - 来看看怎么使用这款应用吧 - 欢迎使用 BetterLyrics - - 顶部区域是标题栏 - - - 悬停在顶部区域以显示 - - + 现在就来初始化歌词数据库吧 - - 悬停在左下角后单击以进入设置页面 - - - 悬停在底部区域以显示 - - - 底部区域是命令栏 - - - 在此处切换“仅展示歌词” - - - 当歌词存在时可在右下角进行切换 - 当前没有正在播放的音乐 @@ -369,4 +348,25 @@ 圆角半径 + + 标题栏大小 + + + 紧凑 + + + 扩展 + + + 将应用置于顶层 + + + 全屏 + + + 按 Esc 退出全屏模式 + + + 再次悬停以显示切换按钮 + \ No newline at end of file diff --git a/BetterLyrics.WinUI3/BetterLyrics.WinUI3/Strings/zh-TW/Resources.resw b/BetterLyrics.WinUI3/BetterLyrics.WinUI3/Strings/zh-TW/Resources.resw index f24bac3..3e5d2cf 100644 --- a/BetterLyrics.WinUI3/BetterLyrics.WinUI3/Strings/zh-TW/Resources.resw +++ b/BetterLyrics.WinUI3/BetterLyrics.WinUI3/Strings/zh-TW/Resources.resw @@ -276,6 +276,9 @@ 僅展示歌詞 + + 沉浸模式 + 歌詞效果 @@ -309,36 +312,12 @@ 重構資料庫中,請稍候... - - 來看看怎麼使用這款應用程式吧 - 歡迎使用 BetterLyrics - - 頂部區域是標題欄 - - - 懸停在頂部區域以顯示 - - + 現在就來初始化歌詞資料庫吧 - - 懸停在左下角後點擊以進入設定頁面 - - - 懸停在底部區域以顯示 - - - 底部區域是命令列 - - - 在此切換“僅展示歌詞” - - - 當歌詞存在時可在右下角進行切換 - 目前沒有正在播放的音樂 @@ -369,4 +348,25 @@ 圓角半徑 + + 標題列大小 + + + 緊湊 + + + 擴充 + + + 將應用置於頂層 + + + 全螢幕 + + + 按 Esc 退出全螢幕模式 + + + 再次懸停以顯示切換按鈕 + \ No newline at end of file diff --git a/BetterLyrics.WinUI3/BetterLyrics.WinUI3/ViewModels/BaseWindowModel.cs b/BetterLyrics.WinUI3/BetterLyrics.WinUI3/ViewModels/BaseWindowModel.cs new file mode 100644 index 0000000..7a08c21 --- /dev/null +++ b/BetterLyrics.WinUI3/BetterLyrics.WinUI3/ViewModels/BaseWindowModel.cs @@ -0,0 +1,15 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using CommunityToolkit.Mvvm.ComponentModel; + +namespace BetterLyrics.WinUI3.ViewModels +{ + public partial class BaseWindowModel : ObservableObject + { + [ObservableProperty] + private int _titleBarFontSize = 11; + } +} diff --git a/BetterLyrics.WinUI3/BetterLyrics.WinUI3/ViewModels/SettingsViewModel.cs b/BetterLyrics.WinUI3/BetterLyrics.WinUI3/ViewModels/SettingsViewModel.cs index 5dc5448..9632f2f 100644 --- a/BetterLyrics.WinUI3/BetterLyrics.WinUI3/ViewModels/SettingsViewModel.cs +++ b/BetterLyrics.WinUI3/BetterLyrics.WinUI3/ViewModels/SettingsViewModel.cs @@ -1,10 +1,12 @@ using System; using System.Diagnostics; using System.Linq; +using System.Text.RegularExpressions; using System.Threading.Tasks; using BetterLyrics.WinUI3.Models; using BetterLyrics.WinUI3.Services.Database; using BetterLyrics.WinUI3.Services.Settings; +using BetterLyrics.WinUI3.Views; using CommunityToolkit.Mvvm.ComponentModel; using CommunityToolkit.Mvvm.Input; using Windows.ApplicationModel.Core; @@ -73,7 +75,7 @@ namespace BetterLyrics.WinUI3.ViewModels bool existed = SettingsService.MusicLibraries.Any((x) => x == path); if (existed) { - MainWindow.StackedNotificationsBehavior?.Show( + BaseWindow.StackedNotificationsBehavior?.Show( App.ResourceLoader!.GetString("SettingsPagePathExistedInfo"), Helper.AnimationHelper.StackedNotificationsShowingDuration ); diff --git a/BetterLyrics.WinUI3/BetterLyrics.WinUI3/MainWindow.xaml b/BetterLyrics.WinUI3/BetterLyrics.WinUI3/Views/BaseWindow.xaml similarity index 54% rename from BetterLyrics.WinUI3/BetterLyrics.WinUI3/MainWindow.xaml rename to BetterLyrics.WinUI3/BetterLyrics.WinUI3/Views/BaseWindow.xaml index 3902f9c..2f79a6b 100644 --- a/BetterLyrics.WinUI3/BetterLyrics.WinUI3/MainWindow.xaml +++ b/BetterLyrics.WinUI3/BetterLyrics.WinUI3/Views/BaseWindow.xaml @@ -1,18 +1,17 @@ - + + Background="Transparent"> - + - - + + - + - + + FontSize="{x:Bind WindowModel.TitleBarFontSize, Mode=OneWay}" + FontWeight="SemiBold" + Opacity=".5" + Text="{x:Bind Title, Mode=OneWay}" /> - - - - - - - - - - - - - - - - - + + + - - - - - - - - - - - + Style="{StaticResource TitleBarButtonStyle}"> + + - - - + Style="{StaticResource TitleBarButtonStyle}"> + + - - - + + - - - + Style="{StaticResource TitleBarButtonStyle}"> + + + + Opacity="0" + Severity="Informational"> diff --git a/BetterLyrics.WinUI3/BetterLyrics.WinUI3/Views/BaseWindow.xaml.cs b/BetterLyrics.WinUI3/BetterLyrics.WinUI3/Views/BaseWindow.xaml.cs new file mode 100644 index 0000000..3a4be15 --- /dev/null +++ b/BetterLyrics.WinUI3/BetterLyrics.WinUI3/Views/BaseWindow.xaml.cs @@ -0,0 +1,244 @@ +using System; +using System.ComponentModel.Design; +using System.Diagnostics; +using BetterLyrics.WinUI3.Helper; +using BetterLyrics.WinUI3.Messages; +using BetterLyrics.WinUI3.Models; +using BetterLyrics.WinUI3.Services.Settings; +using BetterLyrics.WinUI3.ViewModels; +using BetterLyrics.WinUI3.Views; +using CommunityToolkit.Mvvm.DependencyInjection; +using CommunityToolkit.Mvvm.Messaging; +using CommunityToolkit.WinUI; +using CommunityToolkit.WinUI.Behaviors; +using DevWinUI; +using Microsoft.Graphics.Canvas.UI.Xaml; +using Microsoft.UI.Windowing; +using Microsoft.UI.Xaml; +using Microsoft.UI.Xaml.Controls; +using Microsoft.UI.Xaml.Controls.Primitives; +using Microsoft.UI.Xaml.Input; +using Microsoft.UI.Xaml.Media.Animation; +using Microsoft.UI.Xaml.Navigation; +using Windows.UI.Input; + +// To learn more about WinUI, the WinUI project structure, +// and more about our project templates, see: http://aka.ms/winui-project-info. + +namespace BetterLyrics.WinUI3.Views +{ + /// + /// An empty window that can be used on its own or navigated to within a Frame. + /// + public sealed partial class BaseWindow : Window + { + public BaseWindowModel WindowModel { get; set; } + + private SettingsService SettingsService { get; set; } + + public static StackedNotificationsBehavior? StackedNotificationsBehavior + { + get; + private set; + } + + public BaseWindow() + { + this.InitializeComponent(); + + StackedNotificationsBehavior = NotificationQueue; + + WindowModel = Ioc.Default.GetService()!; + + SettingsService = Ioc.Default.GetService()!; + SettingsService.PropertyChanged += SettingsService_PropertyChanged; + + SettingsService_PropertyChanged( + null, + new System.ComponentModel.PropertyChangedEventArgs(nameof(SettingsService.Theme)) + ); + SettingsService_PropertyChanged( + null, + new System.ComponentModel.PropertyChangedEventArgs( + nameof(SettingsService.BackdropType) + ) + ); + SettingsService_PropertyChanged( + null, + new System.ComponentModel.PropertyChangedEventArgs( + nameof(SettingsService.TitleBarType) + ) + ); + + ExtendsContentIntoTitleBar = true; + AppWindow.TitleBar.PreferredHeightOption = TitleBarHeightOption.Collapsed; + SetTitleBar(TopCommandGrid); + } + + private void SettingsService_PropertyChanged( + object? sender, + System.ComponentModel.PropertyChangedEventArgs e + ) + { + switch (e.PropertyName) + { + case nameof(Services.Settings.SettingsService.Theme): + RootGrid.RequestedTheme = (ElementTheme)SettingsService.Theme; + break; + case nameof(Services.Settings.SettingsService.BackdropType): + SystemBackdrop = null; + SystemBackdrop = SystemBackdropHelper.CreateSystemBackdrop( + (BackdropType)SettingsService.BackdropType + ); + break; + case nameof(Services.Settings.SettingsService.TitleBarType): + switch ((TitleBarType)SettingsService.TitleBarType) + { + case TitleBarType.Compact: + TopCommandGrid.Height = (double) + App.Current.Resources["TitleBarCompactHeight"]; + AppLogoImageIcon.Height = 18; + WindowModel.TitleBarFontSize = 11; + break; + case TitleBarType.Extended: + TopCommandGrid.Height = (double) + App.Current.Resources["TitleBarExpandedHeight"]; + AppLogoImageIcon.Height = 20; + WindowModel.TitleBarFontSize = 14; + break; + default: + break; + } + break; + default: + break; + } + } + + public void Navigate(Type type) + { + RootFrame.Navigate(type); + } + + private void RootFrame_NavigationFailed(object sender, NavigationFailedEventArgs e) + { + throw new Exception("Failed to load Page " + e.SourcePageType.FullName); + } + + private void CloseButton_Click(object sender, RoutedEventArgs e) + { + if (RootFrame.CurrentSourcePageType == typeof(MainPage)) + { + App.Current.Exit(); + } + else if (RootFrame.CurrentSourcePageType == typeof(SettingsPage)) + { + App.Current.SettingsWindow!.AppWindow.Hide(); + } + } + + private void MaximiseButton_Click(object sender, RoutedEventArgs e) + { + if (AppWindow.Presenter is OverlappedPresenter presenter) + { + presenter.Maximize(); + UpdateTitleBarWindowButtonsVisibility(); + } + } + + private void MinimiseButton_Click(object sender, RoutedEventArgs e) + { + if (AppWindow.Presenter is OverlappedPresenter presenter) + { + presenter.Minimize(); + UpdateTitleBarWindowButtonsVisibility(); + } + } + + private void RestoreButton_Click(object sender, RoutedEventArgs e) + { + if (AppWindow.Presenter is OverlappedPresenter presenter) + { + presenter.Restore(); + UpdateTitleBarWindowButtonsVisibility(); + } + } + + private void UpdateTitleBarWindowButtonsVisibility() + { + if (AppWindow.Presenter is OverlappedPresenter overlappedPresenter) + { + MinimiseButton.Visibility = AOTFlyoutItem.Visibility = Visibility.Visible; + + if (overlappedPresenter.State == OverlappedPresenterState.Maximized) + { + MaximiseButton.Visibility = Visibility.Collapsed; + RestoreButton.Visibility = Visibility.Visible; + } + else if (overlappedPresenter.State == OverlappedPresenterState.Restored) + { + MaximiseButton.Visibility = Visibility.Visible; + RestoreButton.Visibility = Visibility.Collapsed; + } + } + else if (AppWindow.Presenter is FullScreenPresenter) + { + MinimiseButton.Visibility = + MaximiseButton.Visibility = + RestoreButton.Visibility = + AOTFlyoutItem.Visibility = + Visibility.Collapsed; + } + } + + private void RootFrame_Navigated(object sender, NavigationEventArgs e) + { + AppWindow.Title = Title = App.ResourceLoader!.GetString( + $"{e.SourcePageType.Name}Title" + ); + } + + private void AOTFlyoutItem_Click(object sender, RoutedEventArgs e) + { + if (AppWindow.Presenter is OverlappedPresenter presenter) + AOTFlyoutItem.IsChecked = presenter.IsAlwaysOnTop = !presenter.IsAlwaysOnTop; + } + + private void FullScreenFlyoutItem_Click(object sender, RoutedEventArgs e) + { + switch (AppWindow.Presenter.Kind) + { + case AppWindowPresenterKind.Default: + break; + case AppWindowPresenterKind.CompactOverlay: + break; + case AppWindowPresenterKind.FullScreen: + AppWindow.SetPresenter(AppWindowPresenterKind.Overlapped); + break; + case AppWindowPresenterKind.Overlapped: + AppWindow.SetPresenter(AppWindowPresenterKind.FullScreen); + StackedNotificationsBehavior?.Show( + App.ResourceLoader!.GetString("BaseWindowEnterFullScreenHint"), + AnimationHelper.StackedNotificationsShowingDuration + ); + break; + default: + break; + } + + UpdateTitleBarWindowButtonsVisibility(); + + FullScreenFlyoutItem.IsChecked = + AppWindow.Presenter.Kind == AppWindowPresenterKind.FullScreen; + } + + private void RootGrid_KeyDown(object sender, KeyRoutedEventArgs e) + { + if ( + AppWindow.Presenter is FullScreenPresenter + && e.Key == Windows.System.VirtualKey.Escape + ) + AppWindow.SetPresenter(AppWindowPresenterKind.Overlapped); + } + } +} diff --git a/BetterLyrics.WinUI3/BetterLyrics.WinUI3/Views/MainPage.xaml b/BetterLyrics.WinUI3/BetterLyrics.WinUI3/Views/MainPage.xaml index 6bcedc7..8a6acc9 100644 --- a/BetterLyrics.WinUI3/BetterLyrics.WinUI3/Views/MainPage.xaml +++ b/BetterLyrics.WinUI3/BetterLyrics.WinUI3/Views/MainPage.xaml @@ -3,6 +3,7 @@ x:Class="BetterLyrics.WinUI3.Views.MainPage" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" + xmlns:animatedvisuals="using:Microsoft.UI.Xaml.Controls.AnimatedVisuals" xmlns:canvas="using:Microsoft.Graphics.Canvas.UI.Xaml" xmlns:controls="using:CommunityToolkit.WinUI.Controls" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" @@ -349,10 +350,13 @@ + Opacity=".5" + PointerEntered="BottomCommandGrid_PointerEntered" + PointerExited="BottomCommandGrid_PointerExited"> @@ -360,10 +364,10 @@ - + - + - - + + - + - - - - - + - - + + + + + + + + - - @@ -412,55 +429,7 @@ x:Uid="MainPageWelcomeTeachingTip" Closed="WelcomeTeachingTip_Closed" IsOpen="False" - Target="{x:Bind RootGrid}"> - - - - - - - - - - - - - - - - - - - - - - - - - - - - + Target="{x:Bind SettingsButton}" /> diff --git a/BetterLyrics.WinUI3/BetterLyrics.WinUI3/Views/MainPage.xaml.cs b/BetterLyrics.WinUI3/BetterLyrics.WinUI3/Views/MainPage.xaml.cs index 8f2655d..716bbe4 100644 --- a/BetterLyrics.WinUI3/BetterLyrics.WinUI3/Views/MainPage.xaml.cs +++ b/BetterLyrics.WinUI3/BetterLyrics.WinUI3/Views/MainPage.xaml.cs @@ -10,6 +10,7 @@ using BetterLyrics.WinUI3.Services.Settings; using BetterLyrics.WinUI3.ViewModels; using CommunityToolkit.Mvvm.DependencyInjection; using CommunityToolkit.WinUI; +using DevWinUI; using Microsoft.Extensions.Logging; using Microsoft.Graphics.Canvas; using Microsoft.Graphics.Canvas.Brushes; @@ -23,6 +24,7 @@ using Microsoft.UI.Windowing; using Microsoft.UI.Xaml; using Microsoft.UI.Xaml.Controls; using Microsoft.UI.Xaml.Media; +using Microsoft.UI.Xaml.Media.Animation; using Windows.Foundation; using Windows.Graphics.Imaging; using Windows.Media; @@ -40,7 +42,7 @@ namespace BetterLyrics.WinUI3.Views public sealed partial class MainPage : Page { public MainViewModel ViewModel => (MainViewModel)DataContext; - public SettingsService SettingsService { get; set; } + private SettingsService SettingsService { get; set; } private List _lyricsLines = []; @@ -59,8 +61,6 @@ namespace BetterLyrics.WinUI3.Views private readonly float _lyricsGlowEffectMinBlurAmount = 0f; private readonly float _lyricsGlowEffectMaxBlurAmount = 6f; - private readonly DispatcherQueueTimer _queueTimer; - private TimeSpan _currentTime = TimeSpan.Zero; private readonly float _defaultOpacity = 0.3f; @@ -88,8 +88,6 @@ namespace BetterLyrics.WinUI3.Views private bool _forceToScroll = false; - private readonly DispatcherQueue _dispatcherQueue = DispatcherQueue.GetForCurrentThread(); - private GlobalSystemMediaTransportControlsSessionManager? _sessionManager = null; private GlobalSystemMediaTransportControlsSession? _currentSession = null; @@ -101,8 +99,6 @@ namespace BetterLyrics.WinUI3.Views { this.InitializeComponent(); - _queueTimer = _dispatcherQueue.CreateTimer(); - _logger = Ioc.Default.GetService>()!; SettingsService = Ioc.Default.GetService()!; DataContext = Ioc.Default.GetService(); @@ -154,6 +150,13 @@ namespace BetterLyrics.WinUI3.Views SettingsService.CoverImageRadius / 100f * (CoverImageGrid.ActualHeight / 2) ); break; + case nameof(SettingsService.IsImmersiveMode): + if (SettingsService.IsImmersiveMode) + BaseWindow.StackedNotificationsBehavior?.Show( + App.ResourceLoader!.GetString("MainPageEnterImmersiveModeHint"), + AnimationHelper.StackedNotificationsShowingDuration + ); + break; default: break; } @@ -231,7 +234,7 @@ namespace BetterLyrics.WinUI3.Views PlaybackInfoChangedEventArgs? args ) { - _dispatcherQueue.TryEnqueue( + App.DispatcherQueue!.TryEnqueue( DispatcherQueuePriority.Normal, () => { @@ -242,7 +245,7 @@ namespace BetterLyrics.WinUI3.Views } var playbackState = sender.GetPlaybackInfo().PlaybackStatus; - _logger.LogDebug(playbackState.ToString()); + // _logger.LogDebug(playbackState.ToString()); switch (playbackState) { @@ -276,7 +279,7 @@ namespace BetterLyrics.WinUI3.Views SessionsChangedEventArgs? args ) { - _logger.LogDebug("SessionManager_SessionsChanged"); + // _logger.LogDebug("SessionManager_SessionsChanged"); } private void SessionManager_CurrentSessionChanged( @@ -284,7 +287,7 @@ namespace BetterLyrics.WinUI3.Views CurrentSessionChangedEventArgs? args ) { - _logger.LogDebug("SessionManager_CurrentSessionChanged"); + // _logger.LogDebug("SessionManager_CurrentSessionChanged"); // Unregister events associated with the previous session if (_currentSession != null) { @@ -318,11 +321,11 @@ namespace BetterLyrics.WinUI3.Views MediaPropertiesChangedEventArgs? args ) { - _queueTimer.Debounce( + App.DispatcherQueueTimer!.Debounce( () => { - _logger.LogDebug("CurrentSession_MediaPropertiesChanged"); - _dispatcherQueue.TryEnqueue( + // _logger.LogDebug("CurrentSession_MediaPropertiesChanged"); + App.DispatcherQueue!.TryEnqueue( DispatcherQueuePriority.High, async () => { @@ -998,7 +1001,7 @@ namespace BetterLyrics.WinUI3.Views { if (App.Current.SettingsWindow is null) { - var settingsWindow = new MainWindow(); + var settingsWindow = new BaseWindow(); settingsWindow.Navigate(typeof(SettingsPage)); App.Current.SettingsWindow = settingsWindow; } @@ -1015,38 +1018,6 @@ namespace BetterLyrics.WinUI3.Views } private void WelcomeTeachingTip_Closed(TeachingTip sender, TeachingTipClosedEventArgs args) - { - TopCommandTeachingTip.IsOpen = true; - } - - private void TopCommandTeachingTip_Closed( - TeachingTip sender, - TeachingTipClosedEventArgs args - ) - { - BottomCommandTeachingTip.IsOpen = true; - } - - private void BottomCommandTeachingTip_Closed( - TeachingTip sender, - TeachingTipClosedEventArgs args - ) - { - LyricsOnlyTeachingTip.IsOpen = true; - } - - private void LyricsOnlyTeachingTip_Closed( - TeachingTip sender, - TeachingTipClosedEventArgs args - ) - { - InitDatabaseTeachingTip.IsOpen = true; - } - - private void InitDatabaseTeachingTip_Closed( - TeachingTip sender, - TeachingTipClosedEventArgs args - ) { SettingsService.IsFirstRun = false; } @@ -1058,5 +1029,27 @@ namespace BetterLyrics.WinUI3.Views CoverArea.ActualHeight ); } + + private void BottomCommandGrid_PointerEntered( + object sender, + Microsoft.UI.Xaml.Input.PointerRoutedEventArgs e + ) + { + if (SettingsService.IsImmersiveMode) + ( + (Storyboard)BottomCommandGrid.Resources["BottomCommandGridFadeInStoryboard"] + ).Begin(); + } + + private void BottomCommandGrid_PointerExited( + object sender, + Microsoft.UI.Xaml.Input.PointerRoutedEventArgs e + ) + { + if (SettingsService.IsImmersiveMode) + ( + (Storyboard)BottomCommandGrid.Resources["BottomCommandGridFadeOutStoryboard"] + ).Begin(); + } } } diff --git a/BetterLyrics.WinUI3/BetterLyrics.WinUI3/Views/SettingsPage.xaml b/BetterLyrics.WinUI3/BetterLyrics.WinUI3/Views/SettingsPage.xaml index 0bbed26..d4eb4a1 100644 --- a/BetterLyrics.WinUI3/BetterLyrics.WinUI3/Views/SettingsPage.xaml +++ b/BetterLyrics.WinUI3/BetterLyrics.WinUI3/Views/SettingsPage.xaml @@ -23,6 +23,8 @@ + + + + @@ -121,6 +125,13 @@ + + + + + + + + + + + +