diff --git a/CollapseLauncher/Classes/Helper/Background/BackgroundMediaUtility.cs b/CollapseLauncher/Classes/Helper/Background/BackgroundMediaUtility.cs index e4ee99f5d..eeeb6fa6d 100644 --- a/CollapseLauncher/Classes/Helper/Background/BackgroundMediaUtility.cs +++ b/CollapseLauncher/Classes/Helper/Background/BackgroundMediaUtility.cs @@ -18,8 +18,10 @@ namespace CollapseLauncher.Helper.Background [SuppressMessage("ReSharper", "IdentifierTypo")] [SuppressMessage("ReSharper", "PossibleNullReferenceException")] [SuppressMessage("ReSharper", "AssignNullToNotNullAttribute")] - internal static class BackgroundMediaUtility + internal class BackgroundMediaUtility : IDisposable { + internal static BackgroundMediaUtility Current { get; private set; } + internal enum MediaType { Media, @@ -36,30 +38,27 @@ internal enum MediaType internal static readonly string[] SupportedMediaPlayerExt = [".mp4", ".mov", ".mkv", ".webm", ".avi", ".gif"]; - private static FrameworkElement? _parentUI; - private static ImageUI? _bgImageBackground; - private static ImageUI? _bgImageBackgroundLast; - private static MediaPlayerElement? _bgMediaPlayerBackground; + private FrameworkElement? _parentUI; + private ImageUI? _bgImageBackground; + private ImageUI? _bgImageBackgroundLast; + private MediaPlayerElement? _bgMediaPlayerBackground; - private static Grid? _bgAcrylicMask; - private static Grid? _bgOverlayTitleBar; + private Grid? _bgAcrylicMask; + private Grid? _bgOverlayTitleBar; - private static Grid? _parentBgImageBackgroundGrid; - #pragma warning disable CS0169 // Field is never used - private static Grid? _parentBgImageForegroundGrid; - #pragma warning restore CS0169 // Field is never used - private static Grid? _parentBgMediaPlayerBackgroundGrid; + private Grid? _parentBgImageBackgroundGrid; + private Grid? _parentBgMediaPlayerBackgroundGrid; - internal static MediaType CurrentAppliedMediaType = MediaType.Unknown; + internal MediaType CurrentAppliedMediaType = MediaType.Unknown; - private static CancellationTokenSourceWrapper? _cancellationToken; - private static StillImageLoader? _loaderStillImage; - private static MediaPlayerLoader? _loaderMediaPlayer; - private static IBackgroundMediaLoader? _currentMediaLoader; + private CancellationTokenSourceWrapper? _cancellationToken; + private StillImageLoader? _loaderStillImage; + private MediaPlayerLoader? _loaderMediaPlayer; + private IBackgroundMediaLoader? _currentMediaLoader; - private static bool _isCurrentDimmAnimRun; - private static bool _isCurrentUndimmAnimRun; - private static bool _isCurrentRegistered; + private bool _isCurrentDimmAnimRun; + private bool _isCurrentUndimmAnimRun; + private bool _isCurrentRegistered; private static FileStream? _alternativeFileStream; @@ -75,61 +74,76 @@ internal enum MediaType /// The parent for Background Image. /// The parent for Background Media Player internal static async Task RegisterCurrent(FrameworkElement? parentUI, Grid bgAcrylicMask, - Grid bgOverlayTitleBar, Grid bgImageGridBackground, - Grid bgMediaPlayerGrid) + Grid bgOverlayTitleBar, Grid bgImageGridBackground, + Grid bgMediaPlayerGrid) { // Set the parent UI - _parentUI = parentUI; - - // Mask stuff - _bgAcrylicMask = bgAcrylicMask; - _bgOverlayTitleBar = bgOverlayTitleBar; + FrameworkElement? ui = parentUI; // Initialize the background instances - (_bgImageBackground, _bgImageBackgroundLast) = + var (bgImageBackground, bgImageBackgroundLast) = await InitializeElementGrid(bgImageGridBackground, "ImageBackground", AssignDefaultImage); - _bgMediaPlayerBackground = + var bgMediaPlayerBackground = (await TryGetFirstGridElement(bgMediaPlayerGrid.WithOpacity(0), "MediaPlayer")) .WithHorizontalAlignment(HorizontalAlignment.Center) .WithVerticalAlignment(VerticalAlignment.Center) .WithStretch(Stretch.UniformToFill); - // Store the parent grid reference into this static variables + Current = new BackgroundMediaUtility(ui, bgAcrylicMask, bgOverlayTitleBar, + bgImageGridBackground, bgMediaPlayerGrid, bgImageBackground, + bgImageBackgroundLast, bgMediaPlayerBackground); + } + + private BackgroundMediaUtility(FrameworkElement? parentUI, Grid bgAcrylicMask, + Grid bgOverlayTitleBar, Grid bgImageGridBackground, + Grid bgMediaPlayerGrid, ImageUI? bgImageBackground, + ImageUI? bgImageBackgroundLast, MediaPlayerElement? mediaPlayerElement) + { + _parentUI = parentUI; + _bgAcrylicMask = bgAcrylicMask; + _bgOverlayTitleBar = bgOverlayTitleBar; _parentBgImageBackgroundGrid = bgImageGridBackground; _parentBgMediaPlayerBackgroundGrid = bgMediaPlayerGrid; + _bgImageBackground = bgImageBackground; + _bgImageBackgroundLast = bgImageBackgroundLast; + _bgMediaPlayerBackground = mediaPlayerElement; + // Set that the current page has been registered _isCurrentRegistered = true; } + ~BackgroundMediaUtility() => Dispose(); + /// - /// Detach the current background utility from the previously attached . + /// Detach and dispose the current background utility from the previously attached . /// - internal static void DetachCurrent() + public void Dispose() { if (_cancellationToken is { IsCancellationRequested: false }) { _cancellationToken.Cancel(); } + _cancellationToken?.Dispose(); _bgImageBackground = null; _bgImageBackgroundLast = null; _bgMediaPlayerBackground = null; - _parentBgImageBackgroundGrid?.ClearChildren(); - _parentBgMediaPlayerBackgroundGrid?.ClearChildren(); - _parentBgImageBackgroundGrid = null; _parentBgMediaPlayerBackgroundGrid = null; _bgAcrylicMask = null; _bgOverlayTitleBar = null; + _loaderMediaPlayer?.Dispose(); _loaderMediaPlayer = null; + _loaderStillImage?.Dispose(); _loaderStillImage = null; CurrentAppliedMediaType = MediaType.Unknown; _isCurrentRegistered = false; + GC.SuppressFinalize(this); } /// @@ -237,7 +251,7 @@ internal static async ValueTask AssignDefaultImage(TElement element) /// Ensure that the instance is already initialized /// /// Throw if instance is not registered - private static void EnsureCurrentImageRegistered() + private void EnsureCurrentImageRegistered() { if (_bgImageBackground == null || _bgImageBackgroundLast == null) { @@ -249,7 +263,7 @@ private static void EnsureCurrentImageRegistered() /// Ensure that the instance is already initialized /// /// Throw if instance is not registered - private static void EnsureCurrentMediaPlayerRegistered() + private void EnsureCurrentMediaPlayerRegistered() { if (_bgMediaPlayerBackground == null) { @@ -265,12 +279,12 @@ private static void EnsureCurrentMediaPlayerRegistered() /// Request a cache recreation if the background file properties have been cached /// Throws if the background file is not supported /// Throws if some instances aren't yet initialized - internal static async Task LoadBackground(string mediaPath, bool isRequestInit = false, + internal async Task LoadBackground(string mediaPath, bool isRequestInit = false, bool isForceRecreateCache = false) { while (!_isCurrentRegistered) { - await Task.Delay(250, _cancellationToken?.Token ?? default); + await Task.Delay(250, _cancellationToken?.Token ?? default); } EnsureCurrentImageRegistered(); @@ -348,7 +362,7 @@ await _currentMediaLoader.LoadAsync(mediaPath, isForceRecreateCache, isRequestIn /// /// Dimming the current loaded background /// - internal static async void Dimm() + internal async void Dimm() { while (_isCurrentDimmAnimRun || _isCurrentUndimmAnimRun) { @@ -375,7 +389,7 @@ internal static async void Dimm() /// /// Undimming the current loaded background /// - internal static async void Undimm() + internal async void Undimm() { while (_isCurrentDimmAnimRun || _isCurrentUndimmAnimRun) { @@ -402,7 +416,7 @@ internal static async void Undimm() /// /// Mute the audio of the currently loaded background /// - internal static void Mute() + internal void Mute() { _currentMediaLoader?.Mute(); } @@ -410,7 +424,7 @@ internal static void Mute() /// /// Unmute the audio of the currently loaded background /// - internal static void Unmute() + internal void Unmute() { _currentMediaLoader?.Unmute(); } @@ -418,7 +432,7 @@ internal static void Unmute() /// /// Set the volume of the audio from the currently loaded background /// - internal static void SetVolume(double value) + internal void SetVolume(double value) { _currentMediaLoader?.SetVolume(value); } @@ -426,7 +440,7 @@ internal static void SetVolume(double value) /// /// Trigger the unfocused window event to the currently loaded background /// - internal static void WindowUnfocused() + internal void WindowUnfocused() { _currentMediaLoader?.WindowUnfocused(); } @@ -434,7 +448,7 @@ internal static void WindowUnfocused() /// /// Trigger the focused window event to the currently loaded background /// - internal static void WindowFocused() + internal void WindowFocused() { _currentMediaLoader?.WindowFocused(); } @@ -442,7 +456,7 @@ internal static void WindowFocused() /// /// Play/Resume the currently loaded background /// - internal static void Play() + internal void Play() { _currentMediaLoader?.Play(); } @@ -450,7 +464,7 @@ internal static void Play() /// /// Pause the currently loaded background /// - internal static void Pause() + internal void Pause() { _currentMediaLoader?.Pause(); } @@ -467,7 +481,7 @@ public static void SetAlternativeFileStream(FileStream stream) _alternativeFileStream = stream; } - private static IBackgroundMediaLoader? GetImageLoader(MediaType mediaType) + private IBackgroundMediaLoader? GetImageLoader(MediaType mediaType) { return mediaType switch { diff --git a/CollapseLauncher/Classes/Helper/Background/Loaders/MediaPlayerLoader.cs b/CollapseLauncher/Classes/Helper/Background/Loaders/MediaPlayerLoader.cs index 398edf907..d1277790f 100644 --- a/CollapseLauncher/Classes/Helper/Background/Loaders/MediaPlayerLoader.cs +++ b/CollapseLauncher/Classes/Helper/Background/Loaders/MediaPlayerLoader.cs @@ -9,11 +9,8 @@ using Windows.Media.Playback; using Windows.Storage; using Windows.Storage.FileProperties; -using Windows.UI; using CollapseLauncher.Extension; using CollapseLauncher.Helper.Animation; -using ColorThiefDotNet; -using CommunityToolkit.WinUI; using CommunityToolkit.WinUI.Animations; using Hi3Helper; using Hi3Helper.Shared.Region; @@ -24,8 +21,6 @@ using Microsoft.UI.Xaml.Controls; using Microsoft.UI.Xaml.Media; using ImageUI = Microsoft.UI.Xaml.Controls.Image; -using Microsoft.UI; -using CollapseLauncher.Helper.Image; #nullable enable namespace CollapseLauncher.Helper.Background.Loaders @@ -33,7 +28,7 @@ namespace CollapseLauncher.Helper.Background.Loaders [SuppressMessage("ReSharper", "IdentifierTypo")] [SuppressMessage("ReSharper", "PossibleNullReferenceException")] [SuppressMessage("ReSharper", "AssignNullToNotNullAttribute")] - internal class MediaPlayerLoader : IBackgroundMediaLoader + internal class MediaPlayerLoader : IBackgroundMediaLoader, IDisposable { private FrameworkElement ParentUI { get; } private Compositor CurrentCompositor { get; } @@ -56,8 +51,12 @@ internal class MediaPlayerLoader : IBackgroundMediaLoader private SoftwareBitmap? CurrentFrameBitmap { get; set; } private CanvasImageSource? CurrentCanvasImageSource { get; set; } private CanvasDevice? CanvasDevice { get; set; } + +#if USEDYNAMICVIDEOPALETTE private CanvasBitmap? CanvasBitmap { get; set; } +#endif + internal MediaPlayerLoader( FrameworkElement parentUI, Grid acrylicMask, Grid overlayTitleBar, @@ -82,6 +81,20 @@ internal MediaPlayerLoader( IsMediaPlayerLoading = false; } + ~MediaPlayerLoader() => Dispose(); + + public void Dispose() + { + CurrentMediaPlayer?.Dispose(); + CurrentStopwatch?.Stop(); + InnerCancellationToken?.Dispose(); + CurrentFrameBitmap?.Dispose(); + CanvasDevice?.Dispose(); + CurrentMediaStream?.Dispose(); + + GC.SuppressFinalize(this); + } + public async ValueTask LoadAsync(string filePath, bool isImageLoadForFirstTime, bool isRequestInit, CancellationToken token) { diff --git a/CollapseLauncher/Classes/Helper/Background/Loaders/StillImageLoader.cs b/CollapseLauncher/Classes/Helper/Background/Loaders/StillImageLoader.cs index 620db2480..ea9260c02 100644 --- a/CollapseLauncher/Classes/Helper/Background/Loaders/StillImageLoader.cs +++ b/CollapseLauncher/Classes/Helper/Background/Loaders/StillImageLoader.cs @@ -20,7 +20,7 @@ namespace CollapseLauncher.Helper.Background.Loaders [SuppressMessage("ReSharper", "IdentifierTypo")] [SuppressMessage("ReSharper", "PossibleNullReferenceException")] [SuppressMessage("ReSharper", "AssignNullToNotNullAttribute")] - internal class StillImageLoader : IBackgroundMediaLoader + internal class StillImageLoader : IBackgroundMediaLoader, IDisposable { private FrameworkElement ParentUI { get; } private Compositor CurrentCompositor { get; } @@ -56,6 +56,13 @@ internal StillImageLoader( IsImageLoading = false; } + ~StillImageLoader() => Dispose(); + + public void Dispose() + { + GC.SuppressFinalize(this); + } + public async ValueTask LoadAsync(string filePath, bool isImageLoadForFirstTime, bool isRequestInit, CancellationToken token) { diff --git a/CollapseLauncher/Classes/Helper/WindowUtility.cs b/CollapseLauncher/Classes/Helper/WindowUtility.cs index 3eca361a7..25fe03deb 100644 --- a/CollapseLauncher/Classes/Helper/WindowUtility.cs +++ b/CollapseLauncher/Classes/Helper/WindowUtility.cs @@ -304,11 +304,11 @@ private static IntPtr WndProc(IntPtr hwnd, uint msg, UIntPtr wParam, IntPtr lPar { if (wParam == 1) { - BackgroundMediaUtility.WindowFocused(); + BackgroundMediaUtility.Current.WindowFocused(); } else { - BackgroundMediaUtility.WindowUnfocused(); + BackgroundMediaUtility.Current.WindowUnfocused(); } } break; @@ -335,7 +335,7 @@ private static IntPtr WndProc(IntPtr hwnd, uint msg, UIntPtr wParam, IntPtr lPar } case SC_MINIMIZE: { - BackgroundMediaUtility.WindowUnfocused(); + BackgroundMediaUtility.Current.WindowUnfocused(); if (LauncherConfig.GetAppConfigValue("MinimizeToTray").ToBool()) { // Carousel is handled inside WM_SHOWWINDOW message for minimize to tray @@ -352,7 +352,7 @@ private static IntPtr WndProc(IntPtr hwnd, uint msg, UIntPtr wParam, IntPtr lPar } case SC_RESTORE: { - BackgroundMediaUtility.WindowFocused(); + BackgroundMediaUtility.Current.WindowFocused(); InnerLauncherConfig.m_homePage?.CarouselRestartScroll(); break; } @@ -368,7 +368,7 @@ private static IntPtr WndProc(IntPtr hwnd, uint msg, UIntPtr wParam, IntPtr lPar } else { - BackgroundMediaUtility.WindowFocused(); + BackgroundMediaUtility.Current.WindowFocused(); InnerLauncherConfig.m_homePage?.CarouselRestartScroll(); } diff --git a/CollapseLauncher/XAMLs/MainApp/MainPage.xaml.cs b/CollapseLauncher/XAMLs/MainApp/MainPage.xaml.cs index e111fc29f..e0403d977 100644 --- a/CollapseLauncher/XAMLs/MainApp/MainPage.xaml.cs +++ b/CollapseLauncher/XAMLs/MainApp/MainPage.xaml.cs @@ -98,7 +98,6 @@ private void Page_Unloaded(object sender, RoutedEventArgs e) AppDiscordPresence.Dispose(); #endif ImageLoaderHelper.DestroyWaifu2X(); - BackgroundMediaUtility.DetachCurrent(); } private async void StartRoutine(object sender, RoutedEventArgs e) @@ -427,8 +426,8 @@ private void BackgroundImg_IsImageHideEvent(object sender, bool e) { if (IsFirstStartup) return; - if (e) BackgroundMediaUtility.Dimm(); - else BackgroundMediaUtility.Undimm(); + if (e) BackgroundMediaUtility.Current.Dimm(); + else BackgroundMediaUtility.Current.Undimm(); } private async void CustomBackgroundChanger_Event(object sender, BackgroundImgProperty e) @@ -448,7 +447,7 @@ private async void CustomBackgroundChanger_Event(object sender, BackgroundImgPro try { - await BackgroundMediaUtility.LoadBackground(regionBackgroundProp.imgLocalPath, e.IsRequestInit, e.IsForceRecreateCache); + await BackgroundMediaUtility.Current.LoadBackground(regionBackgroundProp.imgLocalPath, e.IsRequestInit, e.IsForceRecreateCache); } catch (Exception ex) { diff --git a/CollapseLauncher/XAMLs/MainApp/Pages/SettingsPage.xaml.cs b/CollapseLauncher/XAMLs/MainApp/Pages/SettingsPage.xaml.cs index 6650a9abf..c296eecfe 100644 --- a/CollapseLauncher/XAMLs/MainApp/Pages/SettingsPage.xaml.cs +++ b/CollapseLauncher/XAMLs/MainApp/Pages/SettingsPage.xaml.cs @@ -606,9 +606,9 @@ private bool IsVideoBackgroundAudioMute set { if (!value) - BackgroundMediaUtility.Mute(); + BackgroundMediaUtility.Current.Mute(); else - BackgroundMediaUtility.Unmute(); + BackgroundMediaUtility.Current.Unmute(); } } @@ -618,9 +618,9 @@ private double VideoBackgroundAudioVolume { double value = GetAppConfigValue("BackgroundAudioVolume").ToDouble(); if (value < 0) - BackgroundMediaUtility.SetVolume(0d); + BackgroundMediaUtility.Current.SetVolume(0d); if (value > 1) - BackgroundMediaUtility.SetVolume(1d); + BackgroundMediaUtility.Current.SetVolume(1d); return value * 100d; } @@ -628,7 +628,7 @@ private double VideoBackgroundAudioVolume { if (value < 0) return; double downValue = value / 100d; - BackgroundMediaUtility.SetVolume(downValue); + BackgroundMediaUtility.Current.SetVolume(downValue); } } @@ -672,7 +672,7 @@ private bool IsAcrylicEffectEnabled set { SetAndSaveConfigValue("EnableAcrylicEffect", value); - if (BackgroundMediaUtility.CurrentAppliedMediaType == MediaType.StillImage) + if (BackgroundMediaUtility.Current.CurrentAppliedMediaType == MediaType.StillImage) App.ToggleBlurBackdrop(value); } }