From bba92d11c22e71cfaf58d3694b6a652d7b880a28 Mon Sep 17 00:00:00 2001 From: ne0rrmatrix Date: Fri, 24 May 2024 08:10:47 -0700 Subject: [PATCH 01/50] Add full screen state management for media elements This commit introduces full screen state management for media elements. The `CommunityToolkit.Maui.Primitives` namespace was added to several files to support this feature. A new `MediaElementScreenState` enum and `FullScreenStateChangedEventArgs` class were added to represent the full screen state and event data respectively. The `IMediaElement` and `MediaElement` interfaces were updated to include a `FullScreenState` property, a `FullScreenStateChanged` event, and a `FullScreenChanged` method. The `MediaElementPage` class now subscribes to the `FullScreenStateChanged` event and logs information when triggered. The `MauiMediaElement` classes for Android and Windows, and the `MediaManagerDelegate` class for MacOS, were updated to include a `WindowsChanged` event that triggers when the full screen state changes. The `MediaManager` classes for Android, MacOS, and Windows now subscribe to the `WindowsChanged` event and update the full screen state when triggered. The `MediaManager` class for MacOS sets the `Delegate` property of the `AVPlayerViewController` to a new instance of `MediaManagerDelegate`. --- .../MediaElement/MediaElementPage.xaml.cs | 4 +++ .../Interfaces/IMediaElement.cs | 17 +++++++++ .../MediaElement.shared.cs | 36 +++++++++++++++++++ .../FullScreenStateChangedEventArgs.cs | 28 +++++++++++++++ .../Primitives/MediaElementFullScreenState.cs | 17 +++++++++ .../Views/MauiMediaElement.android.cs | 10 ++++++ .../Views/MauiMediaElement.windows.cs | 9 +++++ .../Views/MediaManager.android.cs | 15 +++++++- .../Views/MediaManager.macios.cs | 23 +++++++++++- .../Views/MediaManager.shared.cs | 1 - .../Views/MediaManager.windows.cs | 15 +++++++- 11 files changed, 171 insertions(+), 4 deletions(-) create mode 100644 src/CommunityToolkit.Maui.MediaElement/Primitives/FullScreenStateChangedEventArgs.cs create mode 100644 src/CommunityToolkit.Maui.MediaElement/Primitives/MediaElementFullScreenState.cs diff --git a/samples/CommunityToolkit.Maui.Sample/Pages/Views/MediaElement/MediaElementPage.xaml.cs b/samples/CommunityToolkit.Maui.Sample/Pages/Views/MediaElement/MediaElementPage.xaml.cs index 0908e8bd83..9f4d30fce1 100644 --- a/samples/CommunityToolkit.Maui.Sample/Pages/Views/MediaElement/MediaElementPage.xaml.cs +++ b/samples/CommunityToolkit.Maui.Sample/Pages/Views/MediaElement/MediaElementPage.xaml.cs @@ -1,5 +1,6 @@ using System.ComponentModel; using CommunityToolkit.Maui.Core.Primitives; +using CommunityToolkit.Maui.Primitives; using CommunityToolkit.Maui.Sample.ViewModels.Views; using CommunityToolkit.Maui.Views; using Microsoft.Extensions.Logging; @@ -21,8 +22,11 @@ public MediaElementPage(MediaElementViewModel viewModel, ILogger + logger.LogInformation("FullScreen State Changed. Old State: {PreviousState}, New State: {NewState}", e.PreviousState, e.NewState); void MediaElement_PropertyChanged(object? sender, PropertyChangedEventArgs e) { if (e.PropertyName == MediaElement.DurationProperty.PropertyName) diff --git a/src/CommunityToolkit.Maui.MediaElement/Interfaces/IMediaElement.cs b/src/CommunityToolkit.Maui.MediaElement/Interfaces/IMediaElement.cs index fc621bc902..a79ffca13f 100644 --- a/src/CommunityToolkit.Maui.MediaElement/Interfaces/IMediaElement.cs +++ b/src/CommunityToolkit.Maui.MediaElement/Interfaces/IMediaElement.cs @@ -1,4 +1,5 @@ using CommunityToolkit.Maui.Core.Primitives; +using CommunityToolkit.Maui.Primitives; using CommunityToolkit.Maui.Views; namespace CommunityToolkit.Maui.Core; @@ -19,6 +20,11 @@ public interface IMediaElement : IView, IAsynchronousMediaElementHandler /// MediaElementState CurrentState { get; } + /// + /// Gets the full screen state of the media element. + /// + MediaElementScreenState FullScreenState { get;} + /// /// Gets the height (in pixels) of the loaded media in pixels. /// @@ -96,6 +102,11 @@ public interface IMediaElement : IView, IAsynchronousMediaElementHandler /// event EventHandler PositionChanged; + /// + /// Occurs when the changes. + /// + event EventHandler FullScreenStateChanged; + /// /// Occurs when the media has ended playing successfully. /// @@ -146,4 +157,10 @@ public interface IMediaElement : IView, IAsynchronousMediaElementHandler /// /// The new state the transitioned to. internal void CurrentStateChanged(MediaElementState newState); + + /// + /// Triggers a change. + /// + /// + internal void FullScreenChanged(MediaElementScreenState newState); } \ No newline at end of file diff --git a/src/CommunityToolkit.Maui.MediaElement/MediaElement.shared.cs b/src/CommunityToolkit.Maui.MediaElement/MediaElement.shared.cs index f08c4435c8..ee50eb8126 100644 --- a/src/CommunityToolkit.Maui.MediaElement/MediaElement.shared.cs +++ b/src/CommunityToolkit.Maui.MediaElement/MediaElement.shared.cs @@ -2,6 +2,7 @@ using CommunityToolkit.Maui.Converters; using CommunityToolkit.Maui.Core; using CommunityToolkit.Maui.Core.Primitives; +using CommunityToolkit.Maui.Primitives; namespace CommunityToolkit.Maui.Views; @@ -31,6 +32,14 @@ public class MediaElement : View, IMediaElement, IDisposable /// public static readonly BindableProperty DurationProperty = durationPropertyKey.BindableProperty; + /// + /// Backing store for the property. + /// + public static readonly BindableProperty FullScreenProperty = + BindableProperty.Create(nameof(FullScreenState), typeof(MediaElementScreenState), typeof(MediaElement), + MediaElementScreenState.Default, propertyChanged: OnFullScreenPropertyChanged); + + /// /// Backing store for the property. /// @@ -134,6 +143,13 @@ public event EventHandler SeekCompleted remove => eventManager.RemoveEventHandler(value); } + /// + public event EventHandler FullScreenStateChanged + { + add => eventManager.AddEventHandler(value); + remove => eventManager.RemoveEventHandler(value); + } + /// public event EventHandler StateChanged { @@ -334,6 +350,14 @@ public MediaElementState CurrentState private set => SetValue(CurrentStateProperty, value); } + /// + /// Gets the full screen state of the media element. + /// + public MediaElementScreenState FullScreenState + { + get => (MediaElementScreenState)GetValue(FullScreenProperty); + private set => SetValue(FullScreenProperty, value); + } TimeSpan IMediaElement.Position { get => (TimeSpan)GetValue(PositionProperty); @@ -459,6 +483,15 @@ static void OnSourcePropertyChanged(BindableObject bindable, object oldValue, ob static void OnSourcePropertyChanging(BindableObject bindable, object oldValue, object newValue) => ((MediaElement)bindable).OnSourcePropertyChanging((MediaSource?)oldValue); + static void OnFullScreenPropertyChanged(BindableObject bindable, object oldValue, object newValue) + { + var MediaElement = (MediaElement)bindable; + var previousState = (MediaElementScreenState)oldValue; + var newState = (MediaElementScreenState)newValue; + + MediaElement.OnFullScreenChanged(new FullScreenStateChangedEventArgs(previousState, newState)); + } + static void OnCurrentStatePropertyChanged(BindableObject bindable, object oldValue, object newValue) { var MediaElement = (MediaElement)bindable; @@ -561,6 +594,7 @@ void IMediaElement.SeekCompleted() } void IMediaElement.CurrentStateChanged(MediaElementState newState) => CurrentState = newState; + void IMediaElement.FullScreenChanged(MediaElementScreenState newState) => FullScreenState = newState; void OnPositionChanged(MediaPositionChangedEventArgs mediaPositionChangedEventArgs) => eventManager.HandleEvent(this, mediaPositionChangedEventArgs, nameof(PositionChanged)); @@ -568,6 +602,8 @@ void OnPositionChanged(MediaPositionChangedEventArgs mediaPositionChangedEventAr void OnStateChanged(MediaStateChangedEventArgs mediaStateChangedEventArgs) => eventManager.HandleEvent(this, mediaStateChangedEventArgs, nameof(StateChanged)); + void OnFullScreenChanged(FullScreenStateChangedEventArgs fullScreenStateChangedEventArgs) => + eventManager.HandleEvent(this, fullScreenStateChangedEventArgs, nameof(FullScreenStateChanged)); void OnPauseRequested() => eventManager.HandleEvent(this, EventArgs.Empty, nameof(PauseRequested)); void OnPlayRequested() => eventManager.HandleEvent(this, EventArgs.Empty, nameof(PlayRequested)); diff --git a/src/CommunityToolkit.Maui.MediaElement/Primitives/FullScreenStateChangedEventArgs.cs b/src/CommunityToolkit.Maui.MediaElement/Primitives/FullScreenStateChangedEventArgs.cs new file mode 100644 index 0000000000..3b95eb6c4d --- /dev/null +++ b/src/CommunityToolkit.Maui.MediaElement/Primitives/FullScreenStateChangedEventArgs.cs @@ -0,0 +1,28 @@ +namespace CommunityToolkit.Maui.Primitives; + +/// +/// Event data for when the full screen state of the media element has changed. +/// +public sealed class FullScreenStateChangedEventArgs +{ + /// + /// Initializes a new instance of the class. + /// + /// + /// + public FullScreenStateChangedEventArgs(MediaElementScreenState previousState, MediaElementScreenState newState) + { + PreviousState = previousState; + NewState = newState; + } + + /// + /// Gets the previous state that the instance is transitioning from. + /// + public MediaElementScreenState PreviousState { get; } + + /// + /// Gets the new state that the instance is transitioning to. + /// + public MediaElementScreenState NewState { get; } +} diff --git a/src/CommunityToolkit.Maui.MediaElement/Primitives/MediaElementFullScreenState.cs b/src/CommunityToolkit.Maui.MediaElement/Primitives/MediaElementFullScreenState.cs new file mode 100644 index 0000000000..6a82e3564b --- /dev/null +++ b/src/CommunityToolkit.Maui.MediaElement/Primitives/MediaElementFullScreenState.cs @@ -0,0 +1,17 @@ +namespace CommunityToolkit.Maui.Primitives; + +/// +/// +/// +public enum MediaElementScreenState +{ + /// + /// Full screen. + /// + FullScreen, + + /// + /// The default state. + /// + Default, +} diff --git a/src/CommunityToolkit.Maui.MediaElement/Views/MauiMediaElement.android.cs b/src/CommunityToolkit.Maui.MediaElement/Views/MauiMediaElement.android.cs index 669ff5d5b3..b210152b0f 100644 --- a/src/CommunityToolkit.Maui.MediaElement/Views/MauiMediaElement.android.cs +++ b/src/CommunityToolkit.Maui.MediaElement/Views/MauiMediaElement.android.cs @@ -9,6 +9,7 @@ using AndroidX.Core.View; using Com.Google.Android.Exoplayer2.UI; using CommunityToolkit.Maui.Views; +using CommunityToolkit.Maui.Primitives; namespace CommunityToolkit.Maui.Core.Views; @@ -17,6 +18,11 @@ namespace CommunityToolkit.Maui.Core.Views; /// public class MauiMediaElement : CoordinatorLayout { + /// + /// An event that is raised when the full screen state of the media element has changed. + /// + public static event EventHandler? WindowsChanged; + readonly StyledPlayerView playerView; int defaultSystemUiVisibility; bool isSystemBarVisible; @@ -48,6 +54,8 @@ public MauiMediaElement(Context context, StyledPlayerView playerView) : base(con AddView(playerView); } + static void OnWindowsChanged(FullScreenStateChangedEventArgs e) => WindowsChanged?.Invoke(null, e); + public override void OnDetachedFromWindow() { if (isFullScreen) @@ -146,6 +154,7 @@ void OnFullscreenButtonClick(object? sender, StyledPlayerView.FullscreenButtonCl item.Height = displayMetrics.HeightPixels; layout?.AddView(playerView, item); SetSystemBarsVisibility(); + MauiMediaElement.OnWindowsChanged(new FullScreenStateChangedEventArgs(MediaElementScreenState.Default, MediaElementScreenState.FullScreen)); } else { @@ -158,6 +167,7 @@ void OnFullscreenButtonClick(object? sender, StyledPlayerView.FullscreenButtonCl layout?.RemoveView(playerView); AddView(playerView, item); SetSystemBarsVisibility(); + MauiMediaElement.OnWindowsChanged(new FullScreenStateChangedEventArgs(MediaElementScreenState.FullScreen, MediaElementScreenState.Default)); } } diff --git a/src/CommunityToolkit.Maui.MediaElement/Views/MauiMediaElement.windows.cs b/src/CommunityToolkit.Maui.MediaElement/Views/MauiMediaElement.windows.cs index 9b830b80f5..fd57da1247 100644 --- a/src/CommunityToolkit.Maui.MediaElement/Views/MauiMediaElement.windows.cs +++ b/src/CommunityToolkit.Maui.MediaElement/Views/MauiMediaElement.windows.cs @@ -1,4 +1,5 @@ using CommunityToolkit.Maui.Extensions; +using CommunityToolkit.Maui.Primitives; using CommunityToolkit.Maui.Views; using Microsoft.UI; using Microsoft.UI.Windowing; @@ -31,6 +32,11 @@ public class MauiMediaElement : Grid, IDisposable readonly Button fullScreenButton; readonly MediaPlayerElement mediaPlayerElement; + /// + /// An event that is raised when the full screen state of the media element has changed. + /// + public static event EventHandler? WindowsChanged; + bool doesNavigationBarExistBeforeFullScreen; bool isDisposed; @@ -90,6 +96,7 @@ public void Dispose() Dispose(true); GC.SuppressFinalize(this); } + static void OnWindowsChanged(FullScreenStateChangedEventArgs e) => WindowsChanged?.Invoke(null, e); /// /// Gets the presented page. @@ -173,6 +180,7 @@ void OnFullScreenButtonClick(object sender, RoutedEventArgs e) var parent = mediaPlayerElement.Parent as FrameworkElement; mediaPlayerElement.Width = parent?.Width ?? mediaPlayerElement.Width; mediaPlayerElement.Height = parent?.Height ?? mediaPlayerElement.Height; + MauiMediaElement.OnWindowsChanged(new FullScreenStateChangedEventArgs(MediaElementScreenState.FullScreen, MediaElementScreenState.Default)); } else { @@ -200,6 +208,7 @@ void OnFullScreenButtonClick(object sender, RoutedEventArgs e) { popup.IsOpen = true; } + MauiMediaElement.OnWindowsChanged(new FullScreenStateChangedEventArgs(MediaElementScreenState.Default, MediaElementScreenState.FullScreen)); } } } \ No newline at end of file diff --git a/src/CommunityToolkit.Maui.MediaElement/Views/MediaManager.android.cs b/src/CommunityToolkit.Maui.MediaElement/Views/MediaManager.android.cs index f12b0e61a8..e96034b6c7 100644 --- a/src/CommunityToolkit.Maui.MediaElement/Views/MediaManager.android.cs +++ b/src/CommunityToolkit.Maui.MediaElement/Views/MediaManager.android.cs @@ -11,6 +11,7 @@ using CommunityToolkit.Maui.Core.Primitives; using CommunityToolkit.Maui.Views; using Microsoft.Extensions.Logging; +using CommunityToolkit.Maui.Primitives; namespace CommunityToolkit.Maui.Core.Views; @@ -46,10 +47,22 @@ public partial class MediaManager : Java.Lang.Object, IPlayer.IListener ControllerAutoShow = false, LayoutParameters = new RelativeLayout.LayoutParams(ViewGroup.LayoutParams.MatchParent, ViewGroup.LayoutParams.MatchParent) }; - + MauiMediaElement.WindowsChanged += OnWindowsChanged; return (Player, PlayerView); } + void OnWindowsChanged(object? sender, FullScreenStateChangedEventArgs e) + { + if (MediaElement is not null) + { + MediaElement.FullScreenChanged(e.NewState); + } + else + { + Logger?.LogWarning("MediaElement is null"); + } + } + /// /// Occurs when ExoPlayer changes the playback parameters. /// diff --git a/src/CommunityToolkit.Maui.MediaElement/Views/MediaManager.macios.cs b/src/CommunityToolkit.Maui.MediaElement/Views/MediaManager.macios.cs index 20c34fa971..9b567c22da 100644 --- a/src/CommunityToolkit.Maui.MediaElement/Views/MediaManager.macios.cs +++ b/src/CommunityToolkit.Maui.MediaElement/Views/MediaManager.macios.cs @@ -1,11 +1,13 @@ using AVFoundation; using AVKit; using CommunityToolkit.Maui.Core.Primitives; +using CommunityToolkit.Maui.Primitives; using CommunityToolkit.Maui.Views; using CoreFoundation; using CoreMedia; using Foundation; using Microsoft.Extensions.Logging; +using UIKit; namespace CommunityToolkit.Maui.Core.Views; @@ -90,7 +92,8 @@ public partial class MediaManager : IDisposable Player = new(); PlayerViewController = new() { - Player = Player + Player = Player, + Delegate = new MediaManagerDelegate() }; // Pre-initialize Volume and Muted properties to the player object @@ -588,4 +591,22 @@ void RateChanged(object? sender, NSNotificationEventArgs args) MediaElement.Speed = Player.Rate; } } +} + +sealed class MediaManagerDelegate : AVPlayerViewControllerDelegate +{ + /// + /// Handles the event when the windows change. + /// + public static event EventHandler? WindowsChanged; + public override void WillBeginFullScreenPresentation(AVPlayerViewController playerViewController, IUIViewControllerTransitionCoordinator coordinator) + { + MediaManagerDelegate.OnWindowsChanged(new FullScreenStateChangedEventArgs(MediaElementScreenState.Default, MediaElementScreenState.FullScreen)); + } + public override void WillEndFullScreenPresentation(AVPlayerViewController playerViewController, IUIViewControllerTransitionCoordinator coordinator) + { + MediaManagerDelegate.OnWindowsChanged(new FullScreenStateChangedEventArgs(MediaElementScreenState.FullScreen, MediaElementScreenState.Default)); + } + + static void OnWindowsChanged(FullScreenStateChangedEventArgs e) => WindowsChanged?.Invoke(null, e); } \ No newline at end of file diff --git a/src/CommunityToolkit.Maui.MediaElement/Views/MediaManager.shared.cs b/src/CommunityToolkit.Maui.MediaElement/Views/MediaManager.shared.cs index 253f5beaa8..e3dcde5f1a 100644 --- a/src/CommunityToolkit.Maui.MediaElement/Views/MediaManager.shared.cs +++ b/src/CommunityToolkit.Maui.MediaElement/Views/MediaManager.shared.cs @@ -34,7 +34,6 @@ public MediaManager(IMauiContext context, IMediaElement mediaElement, IDispatche MauiContext = context; Dispatcher = dispatcher; MediaElement = mediaElement; - Logger = MauiContext.Services.GetRequiredService().CreateLogger(nameof(MediaManager)); } diff --git a/src/CommunityToolkit.Maui.MediaElement/Views/MediaManager.windows.cs b/src/CommunityToolkit.Maui.MediaElement/Views/MediaManager.windows.cs index aba821f579..d6ca07a1ad 100644 --- a/src/CommunityToolkit.Maui.MediaElement/Views/MediaManager.windows.cs +++ b/src/CommunityToolkit.Maui.MediaElement/Views/MediaManager.windows.cs @@ -1,4 +1,5 @@ using CommunityToolkit.Maui.Core.Primitives; +using CommunityToolkit.Maui.Primitives; using CommunityToolkit.Maui.Views; using Microsoft.Extensions.Logging; using Microsoft.UI.Xaml.Controls; @@ -41,7 +42,6 @@ public PlatformMediaElement CreatePlatformView() Player = new(); WindowsMediaElement MediaElement = new(); MediaElement.MediaOpened += OnMediaElementMediaOpened; - Player.SetMediaPlayer(MediaElement); Player.MediaPlayer.PlaybackSession.PlaybackRateChanged += OnPlaybackSessionPlaybackRateChanged; @@ -52,9 +52,22 @@ public PlatformMediaElement CreatePlatformView() Player.MediaPlayer.VolumeChanged += OnMediaElementVolumeChanged; Player.MediaPlayer.IsMutedChanged += OnMediaElementIsMutedChanged; + MauiMediaElement.WindowsChanged += OnWindowsChanged; return Player; } + void OnWindowsChanged(object? sender, FullScreenStateChangedEventArgs e) + { + if(MediaElement is not null) + { + MediaElement.FullScreenChanged(e.NewState); + } + else + { + Logger?.LogWarning("MediaElement is null"); + } + } + /// /// Releases the managed and unmanaged resources used by the . /// From 6db6b06fb9652e6bb315245e2dae6590f205a3be Mon Sep 17 00:00:00 2001 From: ne0rrmatrix Date: Sun, 16 Jun 2024 15:17:38 -0700 Subject: [PATCH 02/50] fix merge bug --- .../Views/MediaManager.android.cs | 11 +---------- 1 file changed, 1 insertion(+), 10 deletions(-) diff --git a/src/CommunityToolkit.Maui.MediaElement/Views/MediaManager.android.cs b/src/CommunityToolkit.Maui.MediaElement/Views/MediaManager.android.cs index 9069680049..742b4836dd 100644 --- a/src/CommunityToolkit.Maui.MediaElement/Views/MediaManager.android.cs +++ b/src/CommunityToolkit.Maui.MediaElement/Views/MediaManager.android.cs @@ -79,15 +79,6 @@ public partial class MediaManager : Java.Lang.Object, IPlayer.IListener { return bitmap; } - PlayerView = new StyledPlayerView(MauiContext.Context) - { - Player = Player, - UseController = false, - ControllerAutoShow = false, - LayoutParameters = new RelativeLayout.LayoutParams(ViewGroup.LayoutParams.MatchParent, ViewGroup.LayoutParams.MatchParent) - }; - MauiMediaElement.WindowsChanged += OnWindowsChanged; - return (Player, PlayerView); } void OnWindowsChanged(object? sender, FullScreenStateChangedEventArgs e) @@ -220,7 +211,7 @@ or PlaybackStateCompat.StateSkippingToQueueItem ControllerAutoShow = false, LayoutParameters = new RelativeLayout.LayoutParams(ViewGroup.LayoutParams.MatchParent, ViewGroup.LayoutParams.MatchParent) }; - + MauiMediaElement.WindowsChanged += OnWindowsChanged; checkPermissionsTask = CheckAndRequestForegroundPermission(checkPermissionSourceToken.Token); return (Player, PlayerView); } From 17601c307a6c5b31ecd551f99f5d5214b8f2a304 Mon Sep 17 00:00:00 2001 From: ne0rrmatrix Date: Sun, 16 Jun 2024 15:53:02 -0700 Subject: [PATCH 03/50] Enhance fullscreen event handling - Updated MediaElementPage.xaml to include a new event handler `FullScreenStateChanged` for better responsiveness to fullscreen changes. - Removed subscription to `FullScreenStateChanged` in MediaElementPage.xaml.cs, indicating a shift in how fullscreen changes are managed. - Improved Android fullscreen support in MauiMediaElement.android.cs by invoking `OnWindowsChanged` with `FullScreenStateChangedEventArgs` to accurately track fullscreen state changes. --- .../Pages/Views/MediaElement/MediaElementPage.xaml | 3 ++- .../Pages/Views/MediaElement/MediaElementPage.xaml.cs | 1 - .../Views/MauiMediaElement.android.cs | 2 ++ 3 files changed, 4 insertions(+), 2 deletions(-) diff --git a/samples/CommunityToolkit.Maui.Sample/Pages/Views/MediaElement/MediaElementPage.xaml b/samples/CommunityToolkit.Maui.Sample/Pages/Views/MediaElement/MediaElementPage.xaml index df6de2bc37..84457ae7ab 100644 --- a/samples/CommunityToolkit.Maui.Sample/Pages/Views/MediaElement/MediaElementPage.xaml +++ b/samples/CommunityToolkit.Maui.Sample/Pages/Views/MediaElement/MediaElementPage.xaml @@ -39,7 +39,8 @@ MediaOpened="OnMediaOpened" PositionChanged="OnPositionChanged" StateChanged="OnStateChanged" - SeekCompleted="OnSeekCompleted"/> + SeekCompleted="OnSeekCompleted" + FullScreenStateChanged="MediaElement_FullScreenStateChanged"/> public class MauiMediaElement : CoordinatorLayout { - /// - /// An event that is raised when the full screen state of the media element has changed. - /// - public static event EventHandler? WindowsChanged; + readonly StyledPlayerView playerView; int defaultSystemUiVisibility; @@ -60,7 +57,6 @@ public MauiMediaElement(Context context, StyledPlayerView playerView) : base(con AddView(relativeLayout); } - static void OnWindowsChanged(FullScreenStateChangedEventArgs e) => WindowsChanged?.Invoke(null, e); public override void OnDetachedFromWindow() { @@ -123,14 +119,14 @@ void OnFullscreenButtonClick(object? sender, StyledPlayerView.FullscreenButtonCl isFullScreen = true; RemoveView(relativeLayout); layout?.AddView(relativeLayout); - OnWindowsChanged(new FullScreenStateChangedEventArgs(MediaElementScreenState.Default, MediaElementScreenState.FullScreen)); + MediaManager.FullScreenEvents.OnWindowsChanged(new FullScreenStateChangedEventArgs(MediaElementScreenState.Default, MediaElementScreenState.FullScreen)); } else { isFullScreen = false; layout?.RemoveView(relativeLayout); AddView(relativeLayout); - OnWindowsChanged(new FullScreenStateChangedEventArgs(MediaElementScreenState.FullScreen, MediaElementScreenState.Default)); + MediaManager.FullScreenEvents.OnWindowsChanged(new FullScreenStateChangedEventArgs(MediaElementScreenState.FullScreen, MediaElementScreenState.Default)); } // Hide/Show the SystemBars and Status bar SetSystemBarsVisibility(); diff --git a/src/CommunityToolkit.Maui.MediaElement/Views/MauiMediaElement.windows.cs b/src/CommunityToolkit.Maui.MediaElement/Views/MauiMediaElement.windows.cs index 516667197e..4e5b0df22c 100644 --- a/src/CommunityToolkit.Maui.MediaElement/Views/MauiMediaElement.windows.cs +++ b/src/CommunityToolkit.Maui.MediaElement/Views/MauiMediaElement.windows.cs @@ -8,13 +8,11 @@ using Microsoft.UI.Xaml.Controls.Primitives; using Microsoft.UI.Xaml.Input; using Microsoft.UI.Xaml.Media; -using Microsoft.UI.Xaml.Media.Imaging; using WinRT.Interop; using Application = Microsoft.Maui.Controls.Application; using Button = Microsoft.UI.Xaml.Controls.Button; using Colors = Microsoft.UI.Colors; using Grid = Microsoft.UI.Xaml.Controls.Grid; -using ImageSource = Microsoft.UI.Xaml.Media.ImageSource; using Page = Microsoft.Maui.Controls.Page; using SolidColorBrush = Microsoft.UI.Xaml.Media.SolidColorBrush; using Thickness = Microsoft.UI.Xaml.Thickness; @@ -36,11 +34,6 @@ public class MauiMediaElement : Grid, IDisposable readonly FontIcon fullScreenIcon = new() { Glyph = "\uE740", FontFamily = new FontFamily("Segoe Fluent Icons") }; readonly FontIcon exitFullScreenIcon = new() { Glyph = "\uE73F", FontFamily = new FontFamily("Segoe Fluent Icons") }; - /// - /// An event that is raised when the full screen state of the media element has changed. - /// - public static event EventHandler? WindowsChanged; - bool doesNavigationBarExistBeforeFullScreen; bool isDisposed; @@ -92,7 +85,6 @@ public void Dispose() Dispose(true); GC.SuppressFinalize(this); } - static void OnWindowsChanged(FullScreenStateChangedEventArgs e) => WindowsChanged?.Invoke(null, e); /// /// Gets the presented page. @@ -179,7 +171,8 @@ void OnFullScreenButtonClick(object sender, RoutedEventArgs e) var parent = mediaPlayerElement.Parent as FrameworkElement; mediaPlayerElement.Width = parent?.Width ?? mediaPlayerElement.Width; mediaPlayerElement.Height = parent?.Height ?? mediaPlayerElement.Height; - MauiMediaElement.OnWindowsChanged(new FullScreenStateChangedEventArgs(MediaElementScreenState.FullScreen, MediaElementScreenState.Default)); + + MediaManager.FullScreenEvents.OnWindowsChanged(new FullScreenStateChangedEventArgs(MediaElementScreenState.FullScreen, MediaElementScreenState.Default)); } else { @@ -208,7 +201,7 @@ void OnFullScreenButtonClick(object sender, RoutedEventArgs e) { popup.IsOpen = true; } - MauiMediaElement.OnWindowsChanged(new FullScreenStateChangedEventArgs(MediaElementScreenState.Default, MediaElementScreenState.FullScreen)); + MediaManager.FullScreenEvents.OnWindowsChanged(new FullScreenStateChangedEventArgs(MediaElementScreenState.Default, MediaElementScreenState.FullScreen)); } } } \ No newline at end of file diff --git a/src/CommunityToolkit.Maui.MediaElement/Views/MediaManager.android.cs b/src/CommunityToolkit.Maui.MediaElement/Views/MediaManager.android.cs index dbf47bce45..421a0baa0b 100644 --- a/src/CommunityToolkit.Maui.MediaElement/Views/MediaManager.android.cs +++ b/src/CommunityToolkit.Maui.MediaElement/Views/MediaManager.android.cs @@ -18,9 +18,9 @@ using CommunityToolkit.Maui.ApplicationModel.Permissions; using CommunityToolkit.Maui.Core.Primitives; using CommunityToolkit.Maui.Media.Services; +using CommunityToolkit.Maui.Primitives; using CommunityToolkit.Maui.Views; using Microsoft.Extensions.Logging; -using CommunityToolkit.Maui.Primitives; namespace CommunityToolkit.Maui.Core.Views; @@ -211,7 +211,7 @@ or PlaybackStateCompat.StateSkippingToQueueItem ControllerAutoShow = false, LayoutParameters = new RelativeLayout.LayoutParams(ViewGroup.LayoutParams.MatchParent, ViewGroup.LayoutParams.MatchParent) }; - MauiMediaElement.WindowsChanged += OnWindowsChanged; + FullScreenEvents.WindowsChanged += OnWindowsChanged; checkPermissionsTask = CheckAndRequestForegroundPermission(checkPermissionSourceToken.Token); return (Player, PlayerView); } diff --git a/src/CommunityToolkit.Maui.MediaElement/Views/MediaManager.macios.cs b/src/CommunityToolkit.Maui.MediaElement/Views/MediaManager.macios.cs index 2f318e3b62..a0b906344e 100644 --- a/src/CommunityToolkit.Maui.MediaElement/Views/MediaManager.macios.cs +++ b/src/CommunityToolkit.Maui.MediaElement/Views/MediaManager.macios.cs @@ -16,13 +16,6 @@ namespace CommunityToolkit.Maui.Core.Views; public partial class MediaManager : IDisposable { Metadata? metaData; - static event EventHandler? WindowsChanged; - - /// - /// Static event that is raised when the full screen state of the media element has changed. - /// - /// - public static void OnWindowsChanged(FullScreenStateChangedEventArgs e) => WindowsChanged?.Invoke(null, e); // Media would still start playing when Speed was set although ShouldAutoPlay=False // This field was added to overcome that. @@ -129,7 +122,7 @@ public partial class MediaManager : IDisposable AddPlayedToEndObserver(); AddErrorObservers(); - WindowsChanged += OnWindowsChanged; + MediaManager.FullScreenEvents.WindowsChanged += OnWindowsChanged; return (Player, PlayerViewController); } @@ -694,10 +687,10 @@ sealed class MediaManagerDelegate : AVPlayerViewControllerDelegate { public override void WillBeginFullScreenPresentation(AVPlayerViewController playerViewController, IUIViewControllerTransitionCoordinator coordinator) { - MediaManager.OnWindowsChanged(new FullScreenStateChangedEventArgs(MediaElementScreenState.Default, MediaElementScreenState.FullScreen)); + MediaManager.FullScreenEvents.OnWindowsChanged(new FullScreenStateChangedEventArgs(MediaElementScreenState.Default, MediaElementScreenState.FullScreen)); } public override void WillEndFullScreenPresentation(AVPlayerViewController playerViewController, IUIViewControllerTransitionCoordinator coordinator) { - MediaManager.OnWindowsChanged(new FullScreenStateChangedEventArgs(MediaElementScreenState.FullScreen, MediaElementScreenState.Default)); + MediaManager.FullScreenEvents.OnWindowsChanged(new FullScreenStateChangedEventArgs(MediaElementScreenState.FullScreen, MediaElementScreenState.Default)); } } \ No newline at end of file diff --git a/src/CommunityToolkit.Maui.MediaElement/Views/MediaManager.shared.cs b/src/CommunityToolkit.Maui.MediaElement/Views/MediaManager.shared.cs index f1530f0b63..4a7fb30c6c 100644 --- a/src/CommunityToolkit.Maui.MediaElement/Views/MediaManager.shared.cs +++ b/src/CommunityToolkit.Maui.MediaElement/Views/MediaManager.shared.cs @@ -9,7 +9,7 @@ #elif TIZEN global using PlatformMediaElement = CommunityToolkit.Maui.Core.Views.TizenPlayer; #endif - +using CommunityToolkit.Maui.Primitives; using Microsoft.Extensions.Logging; namespace CommunityToolkit.Maui.Core.Views; @@ -37,6 +37,22 @@ public MediaManager(IMauiContext context, IMediaElement mediaElement, IDispatche Logger = MauiContext.Services.GetRequiredService().CreateLogger(nameof(MediaManager)); } + /// + /// An event that is raised when the full screen state of the media element has changed. + /// + public record FullScreenEvents() + { + /// + /// An event that is raised when the full screen state of the media element has changed. + /// + public static event EventHandler? WindowsChanged; + /// + /// An event that is raised when the full screen state of the media element has changed. + /// + /// + public static void OnWindowsChanged(FullScreenStateChangedEventArgs e) => WindowsChanged?.Invoke(null, e); + } + /// /// The instance managed by this manager. /// diff --git a/src/CommunityToolkit.Maui.MediaElement/Views/MediaManager.windows.cs b/src/CommunityToolkit.Maui.MediaElement/Views/MediaManager.windows.cs index c00dd19eb8..b22c7d78a3 100644 --- a/src/CommunityToolkit.Maui.MediaElement/Views/MediaManager.windows.cs +++ b/src/CommunityToolkit.Maui.MediaElement/Views/MediaManager.windows.cs @@ -1,5 +1,4 @@ using CommunityToolkit.Maui.Core.Primitives; -using CommunityToolkit.Maui.Extensions; using CommunityToolkit.Maui.Primitives; using CommunityToolkit.Maui.Views; using Microsoft.Extensions.Logging; @@ -58,7 +57,7 @@ public PlatformMediaElement CreatePlatformView() Player.MediaPlayer.IsMutedChanged += OnMediaElementIsMutedChanged; systemMediaControls = Player.MediaPlayer.SystemMediaTransportControls; - MauiMediaElement.WindowsChanged += OnWindowsChanged; + FullScreenEvents.WindowsChanged += OnWindowsChanged; return Player; } From 570668846a3a3a3bb9638e509a079bfcf0c23544 Mon Sep 17 00:00:00 2001 From: ne0rrmatrix Date: Fri, 19 Jul 2024 04:53:02 -0700 Subject: [PATCH 09/50] fix spacing issue --- .../Views/MauiMediaElement.android.cs | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/CommunityToolkit.Maui.MediaElement/Views/MauiMediaElement.android.cs b/src/CommunityToolkit.Maui.MediaElement/Views/MauiMediaElement.android.cs index cc1bd0b894..ccdb99825b 100644 --- a/src/CommunityToolkit.Maui.MediaElement/Views/MauiMediaElement.android.cs +++ b/src/CommunityToolkit.Maui.MediaElement/Views/MauiMediaElement.android.cs @@ -16,8 +16,6 @@ namespace CommunityToolkit.Maui.Core.Views; /// public class MauiMediaElement : CoordinatorLayout { - - readonly StyledPlayerView playerView; int defaultSystemUiVisibility; bool isSystemBarVisible; From 201e54ef1f38e5fd58a474a3afb04bdbcb2b1aec Mon Sep 17 00:00:00 2001 From: ne0rrmatrix Date: Fri, 19 Jul 2024 05:40:04 -0700 Subject: [PATCH 10/50] Refactor full-screen state handling - Removed `OnWindowsChanged` from `MediaManager` in platform-specific files (Android, macOS, Windows) due to redundancy and centralized this logic by adding a new protected method `OnWindowsChanged` to the `FullScreenEvents` record in `MediaManager.shared.cs`. This change aims to reduce code duplication and improve the management of full-screen state changes across different platforms. --- .../Views/MediaManager.android.cs | 12 ------------ .../Views/MediaManager.macios.cs | 12 ------------ .../Views/MediaManager.shared.cs | 16 ++++++++++++++++ .../Views/MediaManager.windows.cs | 12 ------------ 4 files changed, 16 insertions(+), 36 deletions(-) diff --git a/src/CommunityToolkit.Maui.MediaElement/Views/MediaManager.android.cs b/src/CommunityToolkit.Maui.MediaElement/Views/MediaManager.android.cs index 421a0baa0b..61e65b6223 100644 --- a/src/CommunityToolkit.Maui.MediaElement/Views/MediaManager.android.cs +++ b/src/CommunityToolkit.Maui.MediaElement/Views/MediaManager.android.cs @@ -81,18 +81,6 @@ public partial class MediaManager : Java.Lang.Object, IPlayer.IListener } } - void OnWindowsChanged(object? sender, FullScreenStateChangedEventArgs e) - { - if (MediaElement is not null) - { - MediaElement.FullScreenChanged(e.NewState); - } - else - { - Logger?.LogWarning("MediaElement is null"); - } - } - /// /// Occurs when ExoPlayer changes the playback parameters. /// diff --git a/src/CommunityToolkit.Maui.MediaElement/Views/MediaManager.macios.cs b/src/CommunityToolkit.Maui.MediaElement/Views/MediaManager.macios.cs index a0b906344e..4bfe29ea22 100644 --- a/src/CommunityToolkit.Maui.MediaElement/Views/MediaManager.macios.cs +++ b/src/CommunityToolkit.Maui.MediaElement/Views/MediaManager.macios.cs @@ -136,18 +136,6 @@ public void Dispose() GC.SuppressFinalize(this); } - void OnWindowsChanged(object? sender, FullScreenStateChangedEventArgs e) - { - if (MediaElement is not null) - { - MediaElement.FullScreenChanged(e.NewState); - } - else - { - Logger?.LogWarning("MediaElement is null"); - } - } - protected virtual partial void PlatformPlay() { if (Player?.CurrentTime == PlayerItem?.Duration) diff --git a/src/CommunityToolkit.Maui.MediaElement/Views/MediaManager.shared.cs b/src/CommunityToolkit.Maui.MediaElement/Views/MediaManager.shared.cs index 4a7fb30c6c..059f685ea3 100644 --- a/src/CommunityToolkit.Maui.MediaElement/Views/MediaManager.shared.cs +++ b/src/CommunityToolkit.Maui.MediaElement/Views/MediaManager.shared.cs @@ -53,6 +53,22 @@ public record FullScreenEvents() public static void OnWindowsChanged(FullScreenStateChangedEventArgs e) => WindowsChanged?.Invoke(null, e); } + /// + /// + /// + /// + /// + protected void OnWindowsChanged(object? sender, FullScreenStateChangedEventArgs e) + { + if (MediaElement is not null) + { + MediaElement.FullScreenChanged(e.NewState); + } + else + { + Logger?.LogWarning("MediaElement is null"); + } + } /// /// The instance managed by this manager. /// diff --git a/src/CommunityToolkit.Maui.MediaElement/Views/MediaManager.windows.cs b/src/CommunityToolkit.Maui.MediaElement/Views/MediaManager.windows.cs index b22c7d78a3..0458dc137a 100644 --- a/src/CommunityToolkit.Maui.MediaElement/Views/MediaManager.windows.cs +++ b/src/CommunityToolkit.Maui.MediaElement/Views/MediaManager.windows.cs @@ -61,18 +61,6 @@ public PlatformMediaElement CreatePlatformView() return Player; } - void OnWindowsChanged(object? sender, FullScreenStateChangedEventArgs e) - { - if(MediaElement is not null) - { - MediaElement.FullScreenChanged(e.NewState); - } - else - { - Logger?.LogWarning("MediaElement is null"); - } - } - /// /// Releases the managed and unmanaged resources used by the . /// From 4a129069db74ca60e62c9cbb0a2f09eed51b2608 Mon Sep 17 00:00:00 2001 From: ne0rrmatrix Date: Fri, 19 Jul 2024 05:44:59 -0700 Subject: [PATCH 11/50] Centralize FullScreenEvents subscription Centralized the subscription to FullScreenEvents.WindowsChanged in the MediaManager class to improve maintainability and readability. Removed redundant event unsubscriptions in platform-specific MediaManager files, streamlining event management. --- .../Views/MediaManager.android.cs | 1 - .../Views/MediaManager.macios.cs | 2 -- .../Views/MediaManager.shared.cs | 1 + .../Views/MediaManager.windows.cs | 1 - 4 files changed, 1 insertion(+), 4 deletions(-) diff --git a/src/CommunityToolkit.Maui.MediaElement/Views/MediaManager.android.cs b/src/CommunityToolkit.Maui.MediaElement/Views/MediaManager.android.cs index 61e65b6223..b59fde2508 100644 --- a/src/CommunityToolkit.Maui.MediaElement/Views/MediaManager.android.cs +++ b/src/CommunityToolkit.Maui.MediaElement/Views/MediaManager.android.cs @@ -199,7 +199,6 @@ or PlaybackStateCompat.StateSkippingToQueueItem ControllerAutoShow = false, LayoutParameters = new RelativeLayout.LayoutParams(ViewGroup.LayoutParams.MatchParent, ViewGroup.LayoutParams.MatchParent) }; - FullScreenEvents.WindowsChanged += OnWindowsChanged; checkPermissionsTask = CheckAndRequestForegroundPermission(checkPermissionSourceToken.Token); return (Player, PlayerView); } diff --git a/src/CommunityToolkit.Maui.MediaElement/Views/MediaManager.macios.cs b/src/CommunityToolkit.Maui.MediaElement/Views/MediaManager.macios.cs index 4bfe29ea22..2d5fb5db71 100644 --- a/src/CommunityToolkit.Maui.MediaElement/Views/MediaManager.macios.cs +++ b/src/CommunityToolkit.Maui.MediaElement/Views/MediaManager.macios.cs @@ -122,8 +122,6 @@ public partial class MediaManager : IDisposable AddPlayedToEndObserver(); AddErrorObservers(); - MediaManager.FullScreenEvents.WindowsChanged += OnWindowsChanged; - return (Player, PlayerViewController); } diff --git a/src/CommunityToolkit.Maui.MediaElement/Views/MediaManager.shared.cs b/src/CommunityToolkit.Maui.MediaElement/Views/MediaManager.shared.cs index 059f685ea3..0a104ac57e 100644 --- a/src/CommunityToolkit.Maui.MediaElement/Views/MediaManager.shared.cs +++ b/src/CommunityToolkit.Maui.MediaElement/Views/MediaManager.shared.cs @@ -35,6 +35,7 @@ public MediaManager(IMauiContext context, IMediaElement mediaElement, IDispatche Dispatcher = dispatcher; MediaElement = mediaElement; Logger = MauiContext.Services.GetRequiredService().CreateLogger(nameof(MediaManager)); + FullScreenEvents.WindowsChanged += OnWindowsChanged; } /// diff --git a/src/CommunityToolkit.Maui.MediaElement/Views/MediaManager.windows.cs b/src/CommunityToolkit.Maui.MediaElement/Views/MediaManager.windows.cs index 0458dc137a..71b7097438 100644 --- a/src/CommunityToolkit.Maui.MediaElement/Views/MediaManager.windows.cs +++ b/src/CommunityToolkit.Maui.MediaElement/Views/MediaManager.windows.cs @@ -57,7 +57,6 @@ public PlatformMediaElement CreatePlatformView() Player.MediaPlayer.IsMutedChanged += OnMediaElementIsMutedChanged; systemMediaControls = Player.MediaPlayer.SystemMediaTransportControls; - FullScreenEvents.WindowsChanged += OnWindowsChanged; return Player; } From 3425c2538674c1fd8407defc5f84343064d29208 Mon Sep 17 00:00:00 2001 From: ne0rrmatrix Date: Fri, 19 Jul 2024 05:50:08 -0700 Subject: [PATCH 12/50] fix cosmetic issues --- .../Views/MediaManager.android.cs | 2 +- .../Views/MediaManager.shared.cs | 2 ++ .../Views/MediaManager.windows.cs | 3 ++- 3 files changed, 5 insertions(+), 2 deletions(-) diff --git a/src/CommunityToolkit.Maui.MediaElement/Views/MediaManager.android.cs b/src/CommunityToolkit.Maui.MediaElement/Views/MediaManager.android.cs index b59fde2508..1899767566 100644 --- a/src/CommunityToolkit.Maui.MediaElement/Views/MediaManager.android.cs +++ b/src/CommunityToolkit.Maui.MediaElement/Views/MediaManager.android.cs @@ -18,7 +18,6 @@ using CommunityToolkit.Maui.ApplicationModel.Permissions; using CommunityToolkit.Maui.Core.Primitives; using CommunityToolkit.Maui.Media.Services; -using CommunityToolkit.Maui.Primitives; using CommunityToolkit.Maui.Views; using Microsoft.Extensions.Logging; @@ -199,6 +198,7 @@ or PlaybackStateCompat.StateSkippingToQueueItem ControllerAutoShow = false, LayoutParameters = new RelativeLayout.LayoutParams(ViewGroup.LayoutParams.MatchParent, ViewGroup.LayoutParams.MatchParent) }; + checkPermissionsTask = CheckAndRequestForegroundPermission(checkPermissionSourceToken.Token); return (Player, PlayerView); } diff --git a/src/CommunityToolkit.Maui.MediaElement/Views/MediaManager.shared.cs b/src/CommunityToolkit.Maui.MediaElement/Views/MediaManager.shared.cs index 0a104ac57e..08ca12d27d 100644 --- a/src/CommunityToolkit.Maui.MediaElement/Views/MediaManager.shared.cs +++ b/src/CommunityToolkit.Maui.MediaElement/Views/MediaManager.shared.cs @@ -9,6 +9,7 @@ #elif TIZEN global using PlatformMediaElement = CommunityToolkit.Maui.Core.Views.TizenPlayer; #endif + using CommunityToolkit.Maui.Primitives; using Microsoft.Extensions.Logging; @@ -34,6 +35,7 @@ public MediaManager(IMauiContext context, IMediaElement mediaElement, IDispatche MauiContext = context; Dispatcher = dispatcher; MediaElement = mediaElement; + Logger = MauiContext.Services.GetRequiredService().CreateLogger(nameof(MediaManager)); FullScreenEvents.WindowsChanged += OnWindowsChanged; } diff --git a/src/CommunityToolkit.Maui.MediaElement/Views/MediaManager.windows.cs b/src/CommunityToolkit.Maui.MediaElement/Views/MediaManager.windows.cs index 71b7097438..6438581dc1 100644 --- a/src/CommunityToolkit.Maui.MediaElement/Views/MediaManager.windows.cs +++ b/src/CommunityToolkit.Maui.MediaElement/Views/MediaManager.windows.cs @@ -1,5 +1,5 @@ using CommunityToolkit.Maui.Core.Primitives; -using CommunityToolkit.Maui.Primitives; +using CommunityToolkit.Maui.Extensions; using CommunityToolkit.Maui.Views; using Microsoft.Extensions.Logging; using Microsoft.UI.Xaml.Controls; @@ -46,6 +46,7 @@ public PlatformMediaElement CreatePlatformView() Player = new(); WindowsMediaElement MediaElement = new(); MediaElement.MediaOpened += OnMediaElementMediaOpened; + Player.SetMediaPlayer(MediaElement); Player.MediaPlayer.PlaybackSession.NaturalVideoSizeChanged += OnNaturalVideoSizeChanged; Player.MediaPlayer.PlaybackSession.PlaybackRateChanged += OnPlaybackSessionPlaybackRateChanged; From 7f757026bbe984e6524d9b00f47fe4489009cd70 Mon Sep 17 00:00:00 2001 From: ne0rrmatrix Date: Fri, 19 Jul 2024 05:56:21 -0700 Subject: [PATCH 13/50] More Cosmetic Fixes --- src/CommunityToolkit.Maui.MediaElement/MediaElement.shared.cs | 4 +++- .../Views/MauiMediaElement.windows.cs | 2 -- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/CommunityToolkit.Maui.MediaElement/MediaElement.shared.cs b/src/CommunityToolkit.Maui.MediaElement/MediaElement.shared.cs index 58d7373aaf..ea4129d621 100644 --- a/src/CommunityToolkit.Maui.MediaElement/MediaElement.shared.cs +++ b/src/CommunityToolkit.Maui.MediaElement/MediaElement.shared.cs @@ -39,7 +39,6 @@ public class MediaElement : View, IMediaElement, IDisposable BindableProperty.Create(nameof(FullScreenState), typeof(MediaElementScreenState), typeof(MediaElement), MediaElementScreenState.Default, propertyChanged: OnFullScreenPropertyChanged); - /// /// Backing store for the property. /// @@ -401,6 +400,7 @@ public MediaElementScreenState FullScreenState get => (MediaElementScreenState)GetValue(FullScreenProperty); private set => SetValue(FullScreenProperty, value); } + TimeSpan IMediaElement.Position { get => (TimeSpan)GetValue(PositionProperty); @@ -649,6 +649,7 @@ void IMediaElement.SeekCompleted() } void IMediaElement.CurrentStateChanged(MediaElementState newState) => CurrentState = newState; + void IMediaElement.FullScreenChanged(MediaElementScreenState newState) => FullScreenState = newState; void OnPositionChanged(MediaPositionChangedEventArgs mediaPositionChangedEventArgs) => @@ -659,6 +660,7 @@ void OnStateChanged(MediaStateChangedEventArgs mediaStateChangedEventArgs) => void OnFullScreenChanged(FullScreenStateChangedEventArgs fullScreenStateChangedEventArgs) => eventManager.HandleEvent(this, fullScreenStateChangedEventArgs, nameof(FullScreenStateChanged)); + void OnPauseRequested() => eventManager.HandleEvent(this, EventArgs.Empty, nameof(PauseRequested)); void OnPlayRequested() => eventManager.HandleEvent(this, EventArgs.Empty, nameof(PlayRequested)); diff --git a/src/CommunityToolkit.Maui.MediaElement/Views/MauiMediaElement.windows.cs b/src/CommunityToolkit.Maui.MediaElement/Views/MauiMediaElement.windows.cs index 4e5b0df22c..41bac769ac 100644 --- a/src/CommunityToolkit.Maui.MediaElement/Views/MauiMediaElement.windows.cs +++ b/src/CommunityToolkit.Maui.MediaElement/Views/MauiMediaElement.windows.cs @@ -33,7 +33,6 @@ public class MauiMediaElement : Grid, IDisposable // Cannot be static readonly because we need to be able to add icon to multiple instances of the button readonly FontIcon fullScreenIcon = new() { Glyph = "\uE740", FontFamily = new FontFamily("Segoe Fluent Icons") }; readonly FontIcon exitFullScreenIcon = new() { Glyph = "\uE73F", FontFamily = new FontFamily("Segoe Fluent Icons") }; - bool doesNavigationBarExistBeforeFullScreen; bool isDisposed; @@ -171,7 +170,6 @@ void OnFullScreenButtonClick(object sender, RoutedEventArgs e) var parent = mediaPlayerElement.Parent as FrameworkElement; mediaPlayerElement.Width = parent?.Width ?? mediaPlayerElement.Width; mediaPlayerElement.Height = parent?.Height ?? mediaPlayerElement.Height; - MediaManager.FullScreenEvents.OnWindowsChanged(new FullScreenStateChangedEventArgs(MediaElementScreenState.FullScreen, MediaElementScreenState.Default)); } else From 8bfed079393a3c3ecebee6c7d3431c9914a91cc6 Mon Sep 17 00:00:00 2001 From: ne0rrmatrix Date: Fri, 19 Jul 2024 06:25:23 -0700 Subject: [PATCH 14/50] Refactor full screen event handling - Renamed `OnWindowsChanged` to `OnFullScreenStatusChanged` in `MediaManager` and `FullScreenEvents` for clarity. - Added `MediaElement` property to `FullScreenEvents` for better media element access. --- .../Views/MediaManager.shared.cs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/CommunityToolkit.Maui.MediaElement/Views/MediaManager.shared.cs b/src/CommunityToolkit.Maui.MediaElement/Views/MediaManager.shared.cs index 08ca12d27d..81cd7a16d1 100644 --- a/src/CommunityToolkit.Maui.MediaElement/Views/MediaManager.shared.cs +++ b/src/CommunityToolkit.Maui.MediaElement/Views/MediaManager.shared.cs @@ -37,7 +37,7 @@ public MediaManager(IMauiContext context, IMediaElement mediaElement, IDispatche MediaElement = mediaElement; Logger = MauiContext.Services.GetRequiredService().CreateLogger(nameof(MediaManager)); - FullScreenEvents.WindowsChanged += OnWindowsChanged; + FullScreenEvents.WindowsChanged += OnFullScreenStatusChanged; } /// @@ -61,7 +61,7 @@ public record FullScreenEvents() /// /// /// - protected void OnWindowsChanged(object? sender, FullScreenStateChangedEventArgs e) + protected void OnFullScreenStatusChanged(object? sender, FullScreenStateChangedEventArgs e) { if (MediaElement is not null) { @@ -72,6 +72,7 @@ protected void OnWindowsChanged(object? sender, FullScreenStateChangedEventArgs Logger?.LogWarning("MediaElement is null"); } } + /// /// The instance managed by this manager. /// From 58ffa61a42702572f815c2032cdd2ef864a44cc2 Mon Sep 17 00:00:00 2001 From: ne0rrmatrix Date: Fri, 19 Jul 2024 07:54:44 -0700 Subject: [PATCH 15/50] Increase accessibility and refine directives In `MauiMediaElement.android.cs`, the visibility of `CurrentPlatformContext` has been changed from `readonly` to `public readonly`, enhancing its accessibility for external use. Additionally, in `MediaManager.shared.cs`, a comment has been added to acknowledge similarities with PR #1918 on the CommunityToolkit/Maui repository. --- .../Views/MauiMediaElement.android.cs | 2 +- .../Views/MediaManager.shared.cs | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/src/CommunityToolkit.Maui.MediaElement/Views/MauiMediaElement.android.cs b/src/CommunityToolkit.Maui.MediaElement/Views/MauiMediaElement.android.cs index ccdb99825b..5c5214cbcf 100644 --- a/src/CommunityToolkit.Maui.MediaElement/Views/MauiMediaElement.android.cs +++ b/src/CommunityToolkit.Maui.MediaElement/Views/MauiMediaElement.android.cs @@ -192,7 +192,7 @@ void SetSystemBarsVisibility() } } - readonly record struct CurrentPlatformContext + public readonly record struct CurrentPlatformContext { public static Activity CurrentActivity { diff --git a/src/CommunityToolkit.Maui.MediaElement/Views/MediaManager.shared.cs b/src/CommunityToolkit.Maui.MediaElement/Views/MediaManager.shared.cs index 81cd7a16d1..440a50f76d 100644 --- a/src/CommunityToolkit.Maui.MediaElement/Views/MediaManager.shared.cs +++ b/src/CommunityToolkit.Maui.MediaElement/Views/MediaManager.shared.cs @@ -1,4 +1,5 @@ -#if !(ANDROID || IOS || WINDOWS || MACCATALYST || TIZEN) +// NOTE: PR shares code with #1918 https://github.com/CommunityToolkit/Maui/pull/1918 +#if !(ANDROID || IOS || WINDOWS || MACCATALYST || TIZEN) global using PlatformMediaElement = System.Object; #elif ANDROID global using PlatformMediaElement = Com.Google.Android.Exoplayer2.IExoPlayer; From 1e65556e37da37e9ed23b64faba8811c3631d2c9 Mon Sep 17 00:00:00 2001 From: ne0rrmatrix Date: Fri, 19 Jul 2024 08:29:11 -0700 Subject: [PATCH 16/50] Refine visibility and structure of records - Changed `CurrentPlatformContext` in `MauiMediaElement.android.cs` from `public` to `internal`, limiting its accessibility to within its assembly. - Modified `FullScreenEvents` in `MediaManager.shared.cs`: 1. Access modifier updated from `public` to `internal`. 2. Converted from a `record` to a `readonly record struct`, making it a value type and immutable. --- .../Views/MauiMediaElement.android.cs | 2 +- .../Views/MediaManager.shared.cs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/CommunityToolkit.Maui.MediaElement/Views/MauiMediaElement.android.cs b/src/CommunityToolkit.Maui.MediaElement/Views/MauiMediaElement.android.cs index 5c5214cbcf..f1d2539899 100644 --- a/src/CommunityToolkit.Maui.MediaElement/Views/MauiMediaElement.android.cs +++ b/src/CommunityToolkit.Maui.MediaElement/Views/MauiMediaElement.android.cs @@ -192,7 +192,7 @@ void SetSystemBarsVisibility() } } - public readonly record struct CurrentPlatformContext + internal readonly record struct CurrentPlatformContext { public static Activity CurrentActivity { diff --git a/src/CommunityToolkit.Maui.MediaElement/Views/MediaManager.shared.cs b/src/CommunityToolkit.Maui.MediaElement/Views/MediaManager.shared.cs index 440a50f76d..f871605d73 100644 --- a/src/CommunityToolkit.Maui.MediaElement/Views/MediaManager.shared.cs +++ b/src/CommunityToolkit.Maui.MediaElement/Views/MediaManager.shared.cs @@ -44,7 +44,7 @@ public MediaManager(IMauiContext context, IMediaElement mediaElement, IDispatche /// /// An event that is raised when the full screen state of the media element has changed. /// - public record FullScreenEvents() + internal readonly record struct FullScreenEvents() { /// /// An event that is raised when the full screen state of the media element has changed. From 94436e261f46aea2f2147d4c8507f0318152a497 Mon Sep 17 00:00:00 2001 From: James Crutchley Date: Mon, 20 Jan 2025 01:49:35 -0800 Subject: [PATCH 17/50] fix merge error --- .../Views/MauiMediaElement.android.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/CommunityToolkit.Maui.MediaElement/Views/MauiMediaElement.android.cs b/src/CommunityToolkit.Maui.MediaElement/Views/MauiMediaElement.android.cs index 3da9ec40a0..15e653c5a3 100644 --- a/src/CommunityToolkit.Maui.MediaElement/Views/MauiMediaElement.android.cs +++ b/src/CommunityToolkit.Maui.MediaElement/Views/MauiMediaElement.android.cs @@ -6,6 +6,7 @@ using AndroidX.CoordinatorLayout.Widget; using AndroidX.Core.View; using AndroidX.Media3.UI; +using CommunityToolkit.Maui.Primitives; using CommunityToolkit.Maui.Views; namespace CommunityToolkit.Maui.Core.Views; From bf5b70e7b628338f183ac37ab308ebe0a239a170 Mon Sep 17 00:00:00 2001 From: James Crutchley Date: Sun, 2 Feb 2025 17:40:56 -0800 Subject: [PATCH 18/50] Rename OnWindowsChanged to OnFullScreenStateChanged --- .../Views/MauiMediaElement.android.cs | 4 ++-- .../Views/MauiMediaElement.windows.cs | 4 ++-- .../Views/MediaManager.macios.cs | 4 ++-- .../Views/MediaManager.shared.cs | 2 +- 4 files changed, 7 insertions(+), 7 deletions(-) diff --git a/src/CommunityToolkit.Maui.MediaElement/Views/MauiMediaElement.android.cs b/src/CommunityToolkit.Maui.MediaElement/Views/MauiMediaElement.android.cs index 15e653c5a3..0ed0524630 100644 --- a/src/CommunityToolkit.Maui.MediaElement/Views/MauiMediaElement.android.cs +++ b/src/CommunityToolkit.Maui.MediaElement/Views/MauiMediaElement.android.cs @@ -121,14 +121,14 @@ void OnFullscreenButtonClick(object? sender, PlayerView.FullscreenButtonClickEve isFullScreen = true; RemoveView(relativeLayout); layout?.AddView(relativeLayout); - MediaManager.FullScreenEvents.OnWindowsChanged(new FullScreenStateChangedEventArgs(MediaElementScreenState.Default, MediaElementScreenState.FullScreen)); + MediaManager.FullScreenEvents.OnFullScreenStateChanged(new FullScreenStateChangedEventArgs(MediaElementScreenState.Default, MediaElementScreenState.FullScreen)); } else { isFullScreen = false; layout?.RemoveView(relativeLayout); AddView(relativeLayout); - MediaManager.FullScreenEvents.OnWindowsChanged(new FullScreenStateChangedEventArgs(MediaElementScreenState.FullScreen, MediaElementScreenState.Default)); + MediaManager.FullScreenEvents.OnFullScreenStateChanged(new FullScreenStateChangedEventArgs(MediaElementScreenState.FullScreen, MediaElementScreenState.Default)); } // Hide/Show the SystemBars and Status bar SetSystemBarsVisibility(); diff --git a/src/CommunityToolkit.Maui.MediaElement/Views/MauiMediaElement.windows.cs b/src/CommunityToolkit.Maui.MediaElement/Views/MauiMediaElement.windows.cs index 6485aaf026..4e04223b05 100644 --- a/src/CommunityToolkit.Maui.MediaElement/Views/MauiMediaElement.windows.cs +++ b/src/CommunityToolkit.Maui.MediaElement/Views/MauiMediaElement.windows.cs @@ -181,7 +181,7 @@ void OnFullScreenButtonClick(object sender, RoutedEventArgs e) var parent = mediaPlayerElement.Parent as FrameworkElement; mediaPlayerElement.Width = parent?.Width ?? mediaPlayerElement.Width; mediaPlayerElement.Height = parent?.Height ?? mediaPlayerElement.Height; - MediaManager.FullScreenEvents.OnWindowsChanged(new FullScreenStateChangedEventArgs(MediaElementScreenState.FullScreen, MediaElementScreenState.Default)); + MediaManager.FullScreenEvents.OnFullScreenStateChanged(new FullScreenStateChangedEventArgs(MediaElementScreenState.FullScreen, MediaElementScreenState.Default)); } else { @@ -208,7 +208,7 @@ void OnFullScreenButtonClick(object sender, RoutedEventArgs e) { popup.IsOpen = true; } - MediaManager.FullScreenEvents.OnWindowsChanged(new FullScreenStateChangedEventArgs(MediaElementScreenState.Default, MediaElementScreenState.FullScreen)); + MediaManager.FullScreenEvents.OnFullScreenStateChanged(new FullScreenStateChangedEventArgs(MediaElementScreenState.Default, MediaElementScreenState.FullScreen)); } } } \ No newline at end of file diff --git a/src/CommunityToolkit.Maui.MediaElement/Views/MediaManager.macios.cs b/src/CommunityToolkit.Maui.MediaElement/Views/MediaManager.macios.cs index c47e624fb8..cfd41b9710 100644 --- a/src/CommunityToolkit.Maui.MediaElement/Views/MediaManager.macios.cs +++ b/src/CommunityToolkit.Maui.MediaElement/Views/MediaManager.macios.cs @@ -726,10 +726,10 @@ sealed class MediaManagerDelegate : AVPlayerViewControllerDelegate { public override void WillBeginFullScreenPresentation(AVPlayerViewController playerViewController, IUIViewControllerTransitionCoordinator coordinator) { - MediaManager.FullScreenEvents.OnWindowsChanged(new FullScreenStateChangedEventArgs(MediaElementScreenState.Default, MediaElementScreenState.FullScreen)); + MediaManager.FullScreenEvents.OnFullScreenStateChanged(new FullScreenStateChangedEventArgs(MediaElementScreenState.Default, MediaElementScreenState.FullScreen)); } public override void WillEndFullScreenPresentation(AVPlayerViewController playerViewController, IUIViewControllerTransitionCoordinator coordinator) { - MediaManager.FullScreenEvents.OnWindowsChanged(new FullScreenStateChangedEventArgs(MediaElementScreenState.FullScreen, MediaElementScreenState.Default)); + MediaManager.FullScreenEvents.OnFullScreenStateChanged(new FullScreenStateChangedEventArgs(MediaElementScreenState.FullScreen, MediaElementScreenState.Default)); } } \ No newline at end of file diff --git a/src/CommunityToolkit.Maui.MediaElement/Views/MediaManager.shared.cs b/src/CommunityToolkit.Maui.MediaElement/Views/MediaManager.shared.cs index a0771b379d..c8c2f5c88a 100644 --- a/src/CommunityToolkit.Maui.MediaElement/Views/MediaManager.shared.cs +++ b/src/CommunityToolkit.Maui.MediaElement/Views/MediaManager.shared.cs @@ -54,7 +54,7 @@ internal readonly record struct FullScreenEvents() /// An event that is raised when the full screen state of the media element has changed. /// /// - public static void OnWindowsChanged(FullScreenStateChangedEventArgs e) => WindowsChanged?.Invoke(null, e); + public static void OnFullScreenStateChanged(FullScreenStateChangedEventArgs e) => WindowsChanged?.Invoke(null, e); } /// From 42b91a2ee9ada4f91aa7acfffab1db1d1605f13b Mon Sep 17 00:00:00 2001 From: James Crutchley Date: Tue, 1 Apr 2025 14:25:50 -0700 Subject: [PATCH 19/50] Refactor full-screen event handling Updated full-screen state change handling to use a new static class `FullScreenEvents` instead of `MediaManager.FullScreenEvents`. This change centralizes event management across Android, Windows, and macOS, improving code organization and maintainability while preserving existing functionality. --- .../Primitives/FullScreenEvents.cs | 14 ++++++++++++++ .../Views/MauiMediaElement.android.cs | 4 ++-- .../Views/MauiMediaElement.windows.cs | 4 ++-- .../Views/MediaManager.macios.cs | 4 ++-- .../Views/MediaManager.shared.cs | 15 --------------- 5 files changed, 20 insertions(+), 21 deletions(-) create mode 100644 src/CommunityToolkit.Maui.MediaElement/Primitives/FullScreenEvents.cs diff --git a/src/CommunityToolkit.Maui.MediaElement/Primitives/FullScreenEvents.cs b/src/CommunityToolkit.Maui.MediaElement/Primitives/FullScreenEvents.cs new file mode 100644 index 0000000000..4e4977b97c --- /dev/null +++ b/src/CommunityToolkit.Maui.MediaElement/Primitives/FullScreenEvents.cs @@ -0,0 +1,14 @@ +namespace CommunityToolkit.Maui.Primitives; + +static class FullScreenEvents +{ + /// + /// An event that is raised when the full screen state of the media element has changed. + /// + public static event EventHandler? WindowsChanged; + /// + /// An event that is raised when the full screen state of the media element has changed. + /// + /// + public static void OnFullScreenStateChanged(FullScreenStateChangedEventArgs e) => WindowsChanged?.Invoke(null, e); +} diff --git a/src/CommunityToolkit.Maui.MediaElement/Views/MauiMediaElement.android.cs b/src/CommunityToolkit.Maui.MediaElement/Views/MauiMediaElement.android.cs index fb49c1a341..3fae41dbc5 100644 --- a/src/CommunityToolkit.Maui.MediaElement/Views/MauiMediaElement.android.cs +++ b/src/CommunityToolkit.Maui.MediaElement/Views/MauiMediaElement.android.cs @@ -126,14 +126,14 @@ void OnFullscreenButtonClick(object? sender, PlayerView.FullscreenButtonClickEve isFullScreen = true; RemoveView(relativeLayout); layout?.AddView(relativeLayout); - MediaManager.FullScreenEvents.OnFullScreenStateChanged(new FullScreenStateChangedEventArgs(MediaElementScreenState.Default, MediaElementScreenState.FullScreen)); + FullScreenEvents.OnFullScreenStateChanged(new FullScreenStateChangedEventArgs(MediaElementScreenState.Default, MediaElementScreenState.FullScreen)); } else { isFullScreen = false; layout?.RemoveView(relativeLayout); AddView(relativeLayout); - MediaManager.FullScreenEvents.OnFullScreenStateChanged(new FullScreenStateChangedEventArgs(MediaElementScreenState.FullScreen, MediaElementScreenState.Default)); + FullScreenEvents.OnFullScreenStateChanged(new FullScreenStateChangedEventArgs(MediaElementScreenState.FullScreen, MediaElementScreenState.Default)); } // Hide/Show the SystemBars and Status bar SetSystemBarsVisibility(); diff --git a/src/CommunityToolkit.Maui.MediaElement/Views/MauiMediaElement.windows.cs b/src/CommunityToolkit.Maui.MediaElement/Views/MauiMediaElement.windows.cs index 4e04223b05..2e2c9ee013 100644 --- a/src/CommunityToolkit.Maui.MediaElement/Views/MauiMediaElement.windows.cs +++ b/src/CommunityToolkit.Maui.MediaElement/Views/MauiMediaElement.windows.cs @@ -181,7 +181,7 @@ void OnFullScreenButtonClick(object sender, RoutedEventArgs e) var parent = mediaPlayerElement.Parent as FrameworkElement; mediaPlayerElement.Width = parent?.Width ?? mediaPlayerElement.Width; mediaPlayerElement.Height = parent?.Height ?? mediaPlayerElement.Height; - MediaManager.FullScreenEvents.OnFullScreenStateChanged(new FullScreenStateChangedEventArgs(MediaElementScreenState.FullScreen, MediaElementScreenState.Default)); + FullScreenEvents.OnFullScreenStateChanged(new FullScreenStateChangedEventArgs(MediaElementScreenState.FullScreen, MediaElementScreenState.Default)); } else { @@ -208,7 +208,7 @@ void OnFullScreenButtonClick(object sender, RoutedEventArgs e) { popup.IsOpen = true; } - MediaManager.FullScreenEvents.OnFullScreenStateChanged(new FullScreenStateChangedEventArgs(MediaElementScreenState.Default, MediaElementScreenState.FullScreen)); + FullScreenEvents.OnFullScreenStateChanged(new FullScreenStateChangedEventArgs(MediaElementScreenState.Default, MediaElementScreenState.FullScreen)); } } } \ No newline at end of file diff --git a/src/CommunityToolkit.Maui.MediaElement/Views/MediaManager.macios.cs b/src/CommunityToolkit.Maui.MediaElement/Views/MediaManager.macios.cs index aff3f8c2a5..989ac26b1f 100644 --- a/src/CommunityToolkit.Maui.MediaElement/Views/MediaManager.macios.cs +++ b/src/CommunityToolkit.Maui.MediaElement/Views/MediaManager.macios.cs @@ -726,10 +726,10 @@ sealed class MediaManagerDelegate : AVPlayerViewControllerDelegate { public override void WillBeginFullScreenPresentation(AVPlayerViewController playerViewController, IUIViewControllerTransitionCoordinator coordinator) { - MediaManager.FullScreenEvents.OnFullScreenStateChanged(new FullScreenStateChangedEventArgs(MediaElementScreenState.Default, MediaElementScreenState.FullScreen)); + FullScreenEvents.OnFullScreenStateChanged(new FullScreenStateChangedEventArgs(MediaElementScreenState.Default, MediaElementScreenState.FullScreen)); } public override void WillEndFullScreenPresentation(AVPlayerViewController playerViewController, IUIViewControllerTransitionCoordinator coordinator) { - MediaManager.FullScreenEvents.OnFullScreenStateChanged(new FullScreenStateChangedEventArgs(MediaElementScreenState.FullScreen, MediaElementScreenState.Default)); + FullScreenEvents.OnFullScreenStateChanged(new FullScreenStateChangedEventArgs(MediaElementScreenState.FullScreen, MediaElementScreenState.Default)); } } \ No newline at end of file diff --git a/src/CommunityToolkit.Maui.MediaElement/Views/MediaManager.shared.cs b/src/CommunityToolkit.Maui.MediaElement/Views/MediaManager.shared.cs index c8c2f5c88a..aea8a4394e 100644 --- a/src/CommunityToolkit.Maui.MediaElement/Views/MediaManager.shared.cs +++ b/src/CommunityToolkit.Maui.MediaElement/Views/MediaManager.shared.cs @@ -41,21 +41,6 @@ public MediaManager(IMauiContext context, IMediaElement mediaElement, IDispatche FullScreenEvents.WindowsChanged += OnFullScreenStatusChanged; } - /// - /// An event that is raised when the full screen state of the media element has changed. - /// - internal readonly record struct FullScreenEvents() - { - /// - /// An event that is raised when the full screen state of the media element has changed. - /// - public static event EventHandler? WindowsChanged; - /// - /// An event that is raised when the full screen state of the media element has changed. - /// - /// - public static void OnFullScreenStateChanged(FullScreenStateChangedEventArgs e) => WindowsChanged?.Invoke(null, e); - } /// /// From be5d58c4cb32582c5c1db5f09df7d2886c20fe97 Mon Sep 17 00:00:00 2001 From: James Crutchley Date: Sat, 5 Apr 2025 18:26:45 -0700 Subject: [PATCH 20/50] Refactor FullScreenEvents to use instance methods Updated the FullScreenEvents class to replace static event handling with instance methods, allowing for multiple instances and improved event management. Adjusted related calls in MauiMediaElement.android.cs and MauiMediaElement.windows.cs to use the new instance methods. Added a static instance of FullScreenEvents in MediaManager for centralized event management. --- .../Primitives/FullScreenEvents.cs | 14 ++++++++++---- .../Views/MauiMediaElement.android.cs | 4 ++-- .../Views/MauiMediaElement.windows.cs | 4 ++-- .../Views/MediaManager.macios.cs | 4 ++-- .../Views/MediaManager.shared.cs | 4 ++++ 5 files changed, 20 insertions(+), 10 deletions(-) diff --git a/src/CommunityToolkit.Maui.MediaElement/Primitives/FullScreenEvents.cs b/src/CommunityToolkit.Maui.MediaElement/Primitives/FullScreenEvents.cs index 4e4977b97c..5b089cade6 100644 --- a/src/CommunityToolkit.Maui.MediaElement/Primitives/FullScreenEvents.cs +++ b/src/CommunityToolkit.Maui.MediaElement/Primitives/FullScreenEvents.cs @@ -1,14 +1,20 @@ -namespace CommunityToolkit.Maui.Primitives; +using CommunityToolkit.Maui.Views; -static class FullScreenEvents +namespace CommunityToolkit.Maui.Primitives; + +/// +/// Represents the event arguments for the event. +/// +public class FullScreenEvents { /// /// An event that is raised when the full screen state of the media element has changed. /// - public static event EventHandler? WindowsChanged; + public event EventHandler? WindowsChanged; /// /// An event that is raised when the full screen state of the media element has changed. /// + /// /// - public static void OnFullScreenStateChanged(FullScreenStateChangedEventArgs e) => WindowsChanged?.Invoke(null, e); + public void OnFullScreenStateChanged(object? sender, FullScreenStateChangedEventArgs e) => WindowsChanged?.Invoke(sender, e); } diff --git a/src/CommunityToolkit.Maui.MediaElement/Views/MauiMediaElement.android.cs b/src/CommunityToolkit.Maui.MediaElement/Views/MauiMediaElement.android.cs index 3fae41dbc5..626332453b 100644 --- a/src/CommunityToolkit.Maui.MediaElement/Views/MauiMediaElement.android.cs +++ b/src/CommunityToolkit.Maui.MediaElement/Views/MauiMediaElement.android.cs @@ -126,14 +126,14 @@ void OnFullscreenButtonClick(object? sender, PlayerView.FullscreenButtonClickEve isFullScreen = true; RemoveView(relativeLayout); layout?.AddView(relativeLayout); - FullScreenEvents.OnFullScreenStateChanged(new FullScreenStateChangedEventArgs(MediaElementScreenState.Default, MediaElementScreenState.FullScreen)); + MediaManager.FullScreenEvents.OnFullScreenStateChanged(this, new FullScreenStateChangedEventArgs(MediaElementScreenState.Default, MediaElementScreenState.FullScreen)); } else { isFullScreen = false; layout?.RemoveView(relativeLayout); AddView(relativeLayout); - FullScreenEvents.OnFullScreenStateChanged(new FullScreenStateChangedEventArgs(MediaElementScreenState.FullScreen, MediaElementScreenState.Default)); + MediaManager.FullScreenEvents.OnFullScreenStateChanged(this , new FullScreenStateChangedEventArgs(MediaElementScreenState.FullScreen, MediaElementScreenState.Default)); } // Hide/Show the SystemBars and Status bar SetSystemBarsVisibility(); diff --git a/src/CommunityToolkit.Maui.MediaElement/Views/MauiMediaElement.windows.cs b/src/CommunityToolkit.Maui.MediaElement/Views/MauiMediaElement.windows.cs index 2e2c9ee013..c3119ec61b 100644 --- a/src/CommunityToolkit.Maui.MediaElement/Views/MauiMediaElement.windows.cs +++ b/src/CommunityToolkit.Maui.MediaElement/Views/MauiMediaElement.windows.cs @@ -181,7 +181,7 @@ void OnFullScreenButtonClick(object sender, RoutedEventArgs e) var parent = mediaPlayerElement.Parent as FrameworkElement; mediaPlayerElement.Width = parent?.Width ?? mediaPlayerElement.Width; mediaPlayerElement.Height = parent?.Height ?? mediaPlayerElement.Height; - FullScreenEvents.OnFullScreenStateChanged(new FullScreenStateChangedEventArgs(MediaElementScreenState.FullScreen, MediaElementScreenState.Default)); + MediaManager.FullScreenEvents.OnFullScreenStateChanged(this, new FullScreenStateChangedEventArgs(MediaElementScreenState.FullScreen, MediaElementScreenState.Default)); } else { @@ -208,7 +208,7 @@ void OnFullScreenButtonClick(object sender, RoutedEventArgs e) { popup.IsOpen = true; } - FullScreenEvents.OnFullScreenStateChanged(new FullScreenStateChangedEventArgs(MediaElementScreenState.Default, MediaElementScreenState.FullScreen)); + MediaManager.FullScreenEvents.OnFullScreenStateChanged(this, new FullScreenStateChangedEventArgs(MediaElementScreenState.Default, MediaElementScreenState.FullScreen)); } } } \ No newline at end of file diff --git a/src/CommunityToolkit.Maui.MediaElement/Views/MediaManager.macios.cs b/src/CommunityToolkit.Maui.MediaElement/Views/MediaManager.macios.cs index 989ac26b1f..d3bdcd352c 100644 --- a/src/CommunityToolkit.Maui.MediaElement/Views/MediaManager.macios.cs +++ b/src/CommunityToolkit.Maui.MediaElement/Views/MediaManager.macios.cs @@ -726,10 +726,10 @@ sealed class MediaManagerDelegate : AVPlayerViewControllerDelegate { public override void WillBeginFullScreenPresentation(AVPlayerViewController playerViewController, IUIViewControllerTransitionCoordinator coordinator) { - FullScreenEvents.OnFullScreenStateChanged(new FullScreenStateChangedEventArgs(MediaElementScreenState.Default, MediaElementScreenState.FullScreen)); + MediaManager.FullScreenEvents.OnFullScreenStateChanged(this, new FullScreenStateChangedEventArgs(MediaElementScreenState.Default, MediaElementScreenState.FullScreen)); } public override void WillEndFullScreenPresentation(AVPlayerViewController playerViewController, IUIViewControllerTransitionCoordinator coordinator) { - FullScreenEvents.OnFullScreenStateChanged(new FullScreenStateChangedEventArgs(MediaElementScreenState.FullScreen, MediaElementScreenState.Default)); + MediaManager.FullScreenEvents.OnFullScreenStateChanged(this, new FullScreenStateChangedEventArgs(MediaElementScreenState.FullScreen, MediaElementScreenState.Default)); } } \ No newline at end of file diff --git a/src/CommunityToolkit.Maui.MediaElement/Views/MediaManager.shared.cs b/src/CommunityToolkit.Maui.MediaElement/Views/MediaManager.shared.cs index aea8a4394e..51e68f5d72 100644 --- a/src/CommunityToolkit.Maui.MediaElement/Views/MediaManager.shared.cs +++ b/src/CommunityToolkit.Maui.MediaElement/Views/MediaManager.shared.cs @@ -21,6 +21,10 @@ namespace CommunityToolkit.Maui.Core.Views; /// public partial class MediaManager { + /// + /// The instance that is managed through this class. + /// + public static readonly FullScreenEvents FullScreenEvents = new(); /// /// Initializes a new instance of the class. /// From d1a8df90d3647749df3e238eb4e0789a3c9e1b0d Mon Sep 17 00:00:00 2001 From: James Crutchley Date: Thu, 3 Jul 2025 13:25:17 -0700 Subject: [PATCH 21/50] Update comment for MediaElementScreenState enum Revised the comment above the `MediaElementScreenState` enum to clarify its purpose, changing it to "Represents the different screen states of a media element." --- .../Primitives/MediaElementFullScreenState.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/CommunityToolkit.Maui.MediaElement/Primitives/MediaElementFullScreenState.cs b/src/CommunityToolkit.Maui.MediaElement/Primitives/MediaElementFullScreenState.cs index d0ec40e7be..e20b922b75 100644 --- a/src/CommunityToolkit.Maui.MediaElement/Primitives/MediaElementFullScreenState.cs +++ b/src/CommunityToolkit.Maui.MediaElement/Primitives/MediaElementFullScreenState.cs @@ -1,7 +1,7 @@ namespace CommunityToolkit.Maui.Core; /// -/// +/// Represents the different screen states of a media element. /// public enum MediaElementScreenState { From ba9936ea6166e37dce47e428fecab3866053c240 Mon Sep 17 00:00:00 2001 From: James Crutchley Date: Thu, 3 Jul 2025 13:26:31 -0700 Subject: [PATCH 22/50] Improve comment for OnFullScreenStatusChanged method Updated the comment above the `OnFullScreenStatusChanged` method to clarify its purpose. The original comment was removed and replaced with a more descriptive statement: "Handles changes to the full screen state." --- .../Views/MediaManager.shared.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/CommunityToolkit.Maui.MediaElement/Views/MediaManager.shared.cs b/src/CommunityToolkit.Maui.MediaElement/Views/MediaManager.shared.cs index 51e68f5d72..5f3f10ad1f 100644 --- a/src/CommunityToolkit.Maui.MediaElement/Views/MediaManager.shared.cs +++ b/src/CommunityToolkit.Maui.MediaElement/Views/MediaManager.shared.cs @@ -47,7 +47,7 @@ public MediaManager(IMauiContext context, IMediaElement mediaElement, IDispatche /// - /// + /// Handles changes to the full screen state. /// /// /// From 5a5675c96c0c8f29f27129465e295d862c987dc6 Mon Sep 17 00:00:00 2001 From: James Crutchley Date: Fri, 5 Sep 2025 12:06:22 -0700 Subject: [PATCH 23/50] Fix variable case --- src/CommunityToolkit.Maui.MediaElement/MediaElement.shared.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/CommunityToolkit.Maui.MediaElement/MediaElement.shared.cs b/src/CommunityToolkit.Maui.MediaElement/MediaElement.shared.cs index 9e5c64beee..f707995af8 100644 --- a/src/CommunityToolkit.Maui.MediaElement/MediaElement.shared.cs +++ b/src/CommunityToolkit.Maui.MediaElement/MediaElement.shared.cs @@ -555,11 +555,11 @@ static void OnSourcePropertyChanging(BindableObject bindable, object oldValue, o static void OnFullScreenPropertyChanged(BindableObject bindable, object oldValue, object newValue) { - var MediaElement = (MediaElement)bindable; + var mediaElement = (MediaElement)bindable; var previousState = (MediaElementScreenState)oldValue; var newState = (MediaElementScreenState)newValue; - MediaElement.OnFullScreenChanged(new FullScreenStateChangedEventArgs(previousState, newState)); + mediaElement.OnFullScreenChanged(new FullScreenStateChangedEventArgs(previousState, newState)); } static void OnCurrentStatePropertyChanged(BindableObject bindable, object oldValue, object newValue) From 427e31f9882728f1dde7c27edc7a4132cde0c22b Mon Sep 17 00:00:00 2001 From: James Crutchley Date: Fri, 5 Sep 2025 12:51:49 -0700 Subject: [PATCH 24/50] Update FullScreenEvents to use WeakEventManager --- .../Primitives/FullScreenEvents.cs | 21 ++++++++++++------- 1 file changed, 14 insertions(+), 7 deletions(-) diff --git a/src/CommunityToolkit.Maui.MediaElement/Primitives/FullScreenEvents.cs b/src/CommunityToolkit.Maui.MediaElement/Primitives/FullScreenEvents.cs index 987577bc28..2e52cb99b9 100644 --- a/src/CommunityToolkit.Maui.MediaElement/Primitives/FullScreenEvents.cs +++ b/src/CommunityToolkit.Maui.MediaElement/Primitives/FullScreenEvents.cs @@ -1,5 +1,4 @@ using CommunityToolkit.Maui.Core; -using CommunityToolkit.Maui.Views; namespace CommunityToolkit.Maui.Primitives; @@ -8,14 +7,22 @@ namespace CommunityToolkit.Maui.Primitives; /// public class FullScreenEvents { + readonly WeakEventManager eventManager = new(); + /// - /// An event that is raised when the full screen state of the media element has changed. + /// Raised when the full screen state of the media element changes. /// - public event EventHandler? WindowsChanged; + public event EventHandler WindowsChanged + { + add => eventManager.AddEventHandler(value); + remove => eventManager.RemoveEventHandler(value); + } + /// - /// An event that is raised when the full screen state of the media element has changed. + /// Triggers the event. /// - /// - /// - public void OnFullScreenStateChanged(object? sender, FullScreenStateChangedEventArgs e) => WindowsChanged?.Invoke(sender, e); + /// Origin of the event. + /// Full screen state change arguments. + public void OnFullScreenStateChanged(object? sender, FullScreenStateChangedEventArgs e) => + eventManager.HandleEvent(sender, e, nameof(WindowsChanged)); } From eee4a1991eebe2beb8d2b3bfa33fd80d33a16382 Mon Sep 17 00:00:00 2001 From: James Crutchley Date: Fri, 5 Sep 2025 13:35:09 -0700 Subject: [PATCH 25/50] Removed public static event and FullScreenEvents. Updated with better event handling. --- .../Handlers/MediaElementHandler.android.cs | 2 +- .../Handlers/MediaElementHandler.windows.cs | 2 +- .../Primitives/FullScreenEvents.cs | 28 ------------------- .../Views/MauiMediaElement.android.cs | 10 ++++--- .../Views/MauiMediaElement.windows.cs | 9 ++++-- .../Views/MediaManager.macios.cs | 10 ++++--- .../Views/MediaManager.shared.cs | 23 +++------------ 7 files changed, 24 insertions(+), 60 deletions(-) delete mode 100644 src/CommunityToolkit.Maui.MediaElement/Primitives/FullScreenEvents.cs diff --git a/src/CommunityToolkit.Maui.MediaElement/Handlers/MediaElementHandler.android.cs b/src/CommunityToolkit.Maui.MediaElement/Handlers/MediaElementHandler.android.cs index bd1e00e6e7..1cc281b6bf 100644 --- a/src/CommunityToolkit.Maui.MediaElement/Handlers/MediaElementHandler.android.cs +++ b/src/CommunityToolkit.Maui.MediaElement/Handlers/MediaElementHandler.android.cs @@ -25,7 +25,7 @@ protected override MauiMediaElement CreatePlatformView() Dispatcher.GetForCurrentThread() ?? throw new InvalidOperationException($"{nameof(IDispatcher)} cannot be null")); var (_, playerView) = MediaManager.CreatePlatformView(VirtualView.AndroidViewType); - return new(Context, playerView); + return new(Context, playerView, MediaManager); } protected override void DisconnectHandler(MauiMediaElement platformView) diff --git a/src/CommunityToolkit.Maui.MediaElement/Handlers/MediaElementHandler.windows.cs b/src/CommunityToolkit.Maui.MediaElement/Handlers/MediaElementHandler.windows.cs index bbc29f0064..3280c612a2 100644 --- a/src/CommunityToolkit.Maui.MediaElement/Handlers/MediaElementHandler.windows.cs +++ b/src/CommunityToolkit.Maui.MediaElement/Handlers/MediaElementHandler.windows.cs @@ -25,7 +25,7 @@ protected override MauiMediaElement CreatePlatformView() Dispatcher.GetForCurrentThread() ?? throw new InvalidOperationException($"{nameof(IDispatcher)} cannot be null")); var mediaPlatform = MediaManager.CreatePlatformView(); - return new(mediaPlatform); + return new(mediaPlatform, MediaManager); } /// diff --git a/src/CommunityToolkit.Maui.MediaElement/Primitives/FullScreenEvents.cs b/src/CommunityToolkit.Maui.MediaElement/Primitives/FullScreenEvents.cs deleted file mode 100644 index 2e52cb99b9..0000000000 --- a/src/CommunityToolkit.Maui.MediaElement/Primitives/FullScreenEvents.cs +++ /dev/null @@ -1,28 +0,0 @@ -using CommunityToolkit.Maui.Core; - -namespace CommunityToolkit.Maui.Primitives; - -/// -/// Represents the event arguments for the event. -/// -public class FullScreenEvents -{ - readonly WeakEventManager eventManager = new(); - - /// - /// Raised when the full screen state of the media element changes. - /// - public event EventHandler WindowsChanged - { - add => eventManager.AddEventHandler(value); - remove => eventManager.RemoveEventHandler(value); - } - - /// - /// Triggers the event. - /// - /// Origin of the event. - /// Full screen state change arguments. - public void OnFullScreenStateChanged(object? sender, FullScreenStateChangedEventArgs e) => - eventManager.HandleEvent(sender, e, nameof(WindowsChanged)); -} diff --git a/src/CommunityToolkit.Maui.MediaElement/Views/MauiMediaElement.android.cs b/src/CommunityToolkit.Maui.MediaElement/Views/MauiMediaElement.android.cs index 80953c3479..a340a57bfd 100644 --- a/src/CommunityToolkit.Maui.MediaElement/Views/MauiMediaElement.android.cs +++ b/src/CommunityToolkit.Maui.MediaElement/Views/MauiMediaElement.android.cs @@ -6,7 +6,6 @@ using AndroidX.CoordinatorLayout.Widget; using AndroidX.Core.View; using AndroidX.Media3.UI; -using CommunityToolkit.Maui.Primitives; using CommunityToolkit.Maui.Views; [assembly: UsesPermission(Android.Manifest.Permission.ForegroundServiceMediaPlayback)] @@ -23,6 +22,7 @@ public class MauiMediaElement : CoordinatorLayout { readonly RelativeLayout relativeLayout; readonly PlayerView playerView; + readonly MediaManager mediaManager; int defaultSystemUiVisibility; bool isSystemBarVisible; @@ -42,9 +42,11 @@ public MauiMediaElement(nint ptr, JniHandleOwnership jni) : base(Platform.AppCon /// /// The application's . /// The that acts as the platform media player. - public MauiMediaElement(Context context, PlayerView playerView) : base(context) + /// The that is managing the instance. + public MauiMediaElement(Context context, PlayerView playerView, MediaManager mediaManager) : base(context) { this.playerView = playerView; + this.mediaManager = mediaManager ?? throw new ArgumentNullException(nameof(mediaManager)); this.playerView.SetBackgroundColor(Android.Graphics.Color.Black); playerView.FullscreenButtonClick += OnFullscreenButtonClick; var layout = new RelativeLayout.LayoutParams(LayoutParams.WrapContent, LayoutParams.WrapContent); @@ -126,14 +128,14 @@ void OnFullscreenButtonClick(object? sender, PlayerView.FullscreenButtonClickEve isFullScreen = true; RemoveView(relativeLayout); layout?.AddView(relativeLayout); - MediaManager.FullScreenEvents.OnFullScreenStateChanged(this, new FullScreenStateChangedEventArgs(MediaElementScreenState.Default, MediaElementScreenState.FullScreen)); + mediaManager.UpdateFullScreenState(MediaElementScreenState.FullScreen); } else { isFullScreen = false; layout?.RemoveView(relativeLayout); AddView(relativeLayout); - MediaManager.FullScreenEvents.OnFullScreenStateChanged(this , new FullScreenStateChangedEventArgs(MediaElementScreenState.FullScreen, MediaElementScreenState.Default)); + mediaManager.UpdateFullScreenState(MediaElementScreenState.Default); } // Hide/Show the SystemBars and Status bar SetSystemBarsVisibility(); diff --git a/src/CommunityToolkit.Maui.MediaElement/Views/MauiMediaElement.windows.cs b/src/CommunityToolkit.Maui.MediaElement/Views/MauiMediaElement.windows.cs index c3119ec61b..4f777d8178 100644 --- a/src/CommunityToolkit.Maui.MediaElement/Views/MauiMediaElement.windows.cs +++ b/src/CommunityToolkit.Maui.MediaElement/Views/MauiMediaElement.windows.cs @@ -24,6 +24,7 @@ public partial class MauiMediaElement : Grid, IDisposable readonly Popup popup = new(); readonly Grid fullScreenGrid = new(); readonly MediaPlayerElement mediaPlayerElement; + readonly MediaManager mediaManager; readonly CustomTransportControls? customTransportControls; bool doesNavigationBarExistBeforeFullScreen; bool isDisposed; @@ -32,9 +33,11 @@ public partial class MauiMediaElement : Grid, IDisposable /// Initializes a new instance of the class. /// /// - public MauiMediaElement(MediaPlayerElement mediaPlayerElement) + /// + public MauiMediaElement(MediaPlayerElement mediaPlayerElement, MediaManager mediaManager) { LoadResourceDictionary(); + this.mediaManager = mediaManager; this.mediaPlayerElement = mediaPlayerElement; customTransportControls = SetTransportControls(); Children.Add(this.mediaPlayerElement); @@ -181,7 +184,7 @@ void OnFullScreenButtonClick(object sender, RoutedEventArgs e) var parent = mediaPlayerElement.Parent as FrameworkElement; mediaPlayerElement.Width = parent?.Width ?? mediaPlayerElement.Width; mediaPlayerElement.Height = parent?.Height ?? mediaPlayerElement.Height; - MediaManager.FullScreenEvents.OnFullScreenStateChanged(this, new FullScreenStateChangedEventArgs(MediaElementScreenState.FullScreen, MediaElementScreenState.Default)); + mediaManager.UpdateFullScreenState(MediaElementScreenState.Default); } else { @@ -208,7 +211,7 @@ void OnFullScreenButtonClick(object sender, RoutedEventArgs e) { popup.IsOpen = true; } - MediaManager.FullScreenEvents.OnFullScreenStateChanged(this, new FullScreenStateChangedEventArgs(MediaElementScreenState.Default, MediaElementScreenState.FullScreen)); + mediaManager.UpdateFullScreenState(MediaElementScreenState.FullScreen); } } } \ No newline at end of file diff --git a/src/CommunityToolkit.Maui.MediaElement/Views/MediaManager.macios.cs b/src/CommunityToolkit.Maui.MediaElement/Views/MediaManager.macios.cs index b1167aa258..67ff64636d 100644 --- a/src/CommunityToolkit.Maui.MediaElement/Views/MediaManager.macios.cs +++ b/src/CommunityToolkit.Maui.MediaElement/Views/MediaManager.macios.cs @@ -29,7 +29,7 @@ public partial class MediaManager : IDisposable PlayerViewController = new() { Player = Player, - Delegate = new MediaManagerDelegate() + Delegate = new MediaManagerDelegate(this) }; // Pre-initialize Volume and Muted properties to the player object @@ -720,14 +720,16 @@ void RateChanged(object? sender, NSNotificationEventArgs args) } } -sealed class MediaManagerDelegate : AVPlayerViewControllerDelegate +sealed class MediaManagerDelegate(MediaManager mediaManager) : AVPlayerViewControllerDelegate { + readonly MediaManager mediaManager = mediaManager; + public override void WillBeginFullScreenPresentation(AVPlayerViewController playerViewController, IUIViewControllerTransitionCoordinator coordinator) { - MediaManager.FullScreenEvents.OnFullScreenStateChanged(this, new FullScreenStateChangedEventArgs(MediaElementScreenState.Default, MediaElementScreenState.FullScreen)); + mediaManager.UpdateFullScreenState(MediaElementScreenState.FullScreen); } public override void WillEndFullScreenPresentation(AVPlayerViewController playerViewController, IUIViewControllerTransitionCoordinator coordinator) { - MediaManager.FullScreenEvents.OnFullScreenStateChanged(this, new FullScreenStateChangedEventArgs(MediaElementScreenState.FullScreen, MediaElementScreenState.Default)); + mediaManager.UpdateFullScreenState(MediaElementScreenState.Default); } } \ No newline at end of file diff --git a/src/CommunityToolkit.Maui.MediaElement/Views/MediaManager.shared.cs b/src/CommunityToolkit.Maui.MediaElement/Views/MediaManager.shared.cs index 5f3f10ad1f..227e539385 100644 --- a/src/CommunityToolkit.Maui.MediaElement/Views/MediaManager.shared.cs +++ b/src/CommunityToolkit.Maui.MediaElement/Views/MediaManager.shared.cs @@ -11,7 +11,6 @@ global using PlatformMediaElement = CommunityToolkit.Maui.Core.Views.TizenPlayer; #endif -using CommunityToolkit.Maui.Primitives; using Microsoft.Extensions.Logging; namespace CommunityToolkit.Maui.Core.Views; @@ -21,10 +20,6 @@ namespace CommunityToolkit.Maui.Core.Views; /// public partial class MediaManager { - /// - /// The instance that is managed through this class. - /// - public static readonly FullScreenEvents FullScreenEvents = new(); /// /// Initializes a new instance of the class. /// @@ -42,25 +37,15 @@ public MediaManager(IMauiContext context, IMediaElement mediaElement, IDispatche MediaElement = mediaElement; Logger = MauiContext.Services.GetRequiredService().CreateLogger(nameof(MediaManager)); - FullScreenEvents.WindowsChanged += OnFullScreenStatusChanged; } - /// - /// Handles changes to the full screen state. + /// Update the full screen state on the associated MediaElement. /// - /// - /// - protected void OnFullScreenStatusChanged(object? sender, FullScreenStateChangedEventArgs e) + /// The new full screen state. + internal void UpdateFullScreenState(MediaElementScreenState newState) { - if (MediaElement is not null) - { - MediaElement.FullScreenChanged(e.NewState); - } - else - { - Logger?.LogWarning("MediaElement is null"); - } + MediaElement.FullScreenChanged(newState); } /// From 073a2bd4092ef302c7a78f2a171a26f12fcbf819 Mon Sep 17 00:00:00 2001 From: James Crutchley Date: Fri, 5 Sep 2025 13:41:32 -0700 Subject: [PATCH 26/50] Updated `FullScreenStateChangedEventArgs` to inherit from `EventArgs` --- .../FullScreenStateChangedEventArgs.cs | 21 +++++++------------ 1 file changed, 8 insertions(+), 13 deletions(-) diff --git a/src/CommunityToolkit.Maui.MediaElement/Primitives/FullScreenStateChangedEventArgs.cs b/src/CommunityToolkit.Maui.MediaElement/Primitives/FullScreenStateChangedEventArgs.cs index b927e8cf8b..2bd99a962b 100644 --- a/src/CommunityToolkit.Maui.MediaElement/Primitives/FullScreenStateChangedEventArgs.cs +++ b/src/CommunityToolkit.Maui.MediaElement/Primitives/FullScreenStateChangedEventArgs.cs @@ -3,26 +3,21 @@ /// /// Event data for when the full screen state of the media element has changed. /// -public sealed class FullScreenStateChangedEventArgs +/// +/// Initializes a new instance of the class. +/// +/// +/// +public sealed class FullScreenStateChangedEventArgs(MediaElementScreenState previousState, MediaElementScreenState newState) : EventArgs { - /// - /// Initializes a new instance of the class. - /// - /// - /// - public FullScreenStateChangedEventArgs(MediaElementScreenState previousState, MediaElementScreenState newState) - { - PreviousState = previousState; - NewState = newState; - } /// /// Gets the previous state that the instance is transitioning from. /// - public MediaElementScreenState PreviousState { get; } + public MediaElementScreenState PreviousState { get; } = previousState; /// /// Gets the new state that the instance is transitioning to. /// - public MediaElementScreenState NewState { get; } + public MediaElementScreenState NewState { get; } = newState; } From 089c11726deb0102feda6e0ee62e3bd5f5d89f08 Mon Sep 17 00:00:00 2001 From: James Crutchley Date: Tue, 17 Feb 2026 03:45:23 -0800 Subject: [PATCH 27/50] fix merge conflict --- .../MediaElement.shared.cs | 2 - .../Layouts/StateContainerTests.cs | 45 ++++++++++++++++++- .../StateContainer/StateContainer.shared.cs | 7 +-- .../StateContainerController.shared.cs | 27 ++++++----- .../StateContainerDefaults.shared.cs | 1 - 5 files changed, 63 insertions(+), 19 deletions(-) diff --git a/src/CommunityToolkit.Maui.MediaElement/MediaElement.shared.cs b/src/CommunityToolkit.Maui.MediaElement/MediaElement.shared.cs index f0a6925007..35bbca24ef 100644 --- a/src/CommunityToolkit.Maui.MediaElement/MediaElement.shared.cs +++ b/src/CommunityToolkit.Maui.MediaElement/MediaElement.shared.cs @@ -616,8 +616,6 @@ void OnSourceChanged(object? sender, EventArgs eventArgs) InvalidateMeasure(); } - void IMediaElement.CurrentStateChanged(MediaElementState newState) => CurrentState = newState; - void IMediaElement.FullScreenChanged(MediaElementScreenState newState) => FullScreenState = newState; void OnPositionChanged(MediaPositionChangedEventArgs mediaPositionChangedEventArgs) => diff --git a/src/CommunityToolkit.Maui.UnitTests/Layouts/StateContainerTests.cs b/src/CommunityToolkit.Maui.UnitTests/Layouts/StateContainerTests.cs index 7b40135419..5d330e8484 100644 --- a/src/CommunityToolkit.Maui.UnitTests/Layouts/StateContainerTests.cs +++ b/src/CommunityToolkit.Maui.UnitTests/Layouts/StateContainerTests.cs @@ -514,11 +514,30 @@ public void StateContainer_CreatesControllerWithLayout() } [Fact] - public void Controller_ReturnsErrorLabelOnInvalidState() + public void Controller_ThrowsStateContainerExceptionInvalidStateKey() { Assert.Throws(() => controller.SwitchToState("InvalidStateKey")); } + [Fact] + public void Controller_ThrowsStateContainerExceptionOnDuplicateStateKey() + { + // Arrange + var stackLayout = new StackLayout(); + var label = new Label(); + var button = new Button(); + + StateView.SetStateKey(label, StateKey.Anything); + StateView.SetStateKey(button, StateKey.Anything); + StateContainer.SetStateViews(stackLayout, [label, button]); + + // Assert + var exception = Assert.Throws(() => StateContainer.SetCurrentState(stackLayout, StateKey.Anything)); + Assert.IsType(exception.InnerException); + exception.Message.Should().Contain("multiple"); + exception.InnerException.Message.Should().Contain("Sequence contains more than one matching element"); + } + [Fact] public void Controller_SwitchesToStateFromContentSuccess() { @@ -594,12 +613,34 @@ public void EnsureDefaults() var stackLayout = new StackLayout(); // Act Assert - Assert.Equal(StateContainerDefaults.StateViews, StateContainer.GetStateViews(stackLayout)); + Assert.Equal([], StateContainer.GetStateViews(stackLayout)); + Assert.Empty(StateContainer.GetStateViews(stackLayout)); Assert.Equal(StateContainerDefaults.CurrentState, StateContainer.GetCurrentState(stackLayout)); Assert.Equal(StateContainerDefaults.CanStateChange, StateContainer.GetCanStateChange(stackLayout)); Assert.Equal(StateViewDefaults.StateKey, StateView.GetStateKey(stackLayout)); } + [Fact] + public void EnsureLayoutControllerIsUniquePerLayout() + { + // Arrange + var grid1 = new Grid(); + var grid2 = new Grid(); + + // Act + var grid1StateViews = StateContainer.GetStateViews(grid1); + var grid2StateViews = StateContainer.GetStateViews(grid2); + grid1StateViews.Add(new Label + { + Text = "Test", + }); + + // Assert + Assert.NotSame(grid1StateViews, grid2StateViews); + Assert.Single(grid1StateViews); + Assert.Empty(grid2StateViews); + } + sealed class ViewModel : INotifyPropertyChanged { public bool CanChangeState diff --git a/src/CommunityToolkit.Maui/Layouts/StateContainer/StateContainer.shared.cs b/src/CommunityToolkit.Maui/Layouts/StateContainer/StateContainer.shared.cs index 51f94983a9..dabce01fae 100644 --- a/src/CommunityToolkit.Maui/Layouts/StateContainer/StateContainer.shared.cs +++ b/src/CommunityToolkit.Maui/Layouts/StateContainer/StateContainer.shared.cs @@ -192,7 +192,7 @@ static void ValidateCanStateChange(in BindableObject bindable) } } - static IList CreateDefaultStateViewsProperty(BindableObject bindable) => StateContainerDefaults.StateViews; + static IList CreateDefaultStateViewsProperty(BindableObject bindable) => []; } /// @@ -201,5 +201,6 @@ static void ValidateCanStateChange(in BindableObject bindable) /// /// Constructor for /// -/// -public sealed class StateContainerException(string message) : InvalidOperationException(message); \ No newline at end of file +/// The error message that explains the reason for the exception. +/// The exception that is the cause of the current exception. If the parameter is not a null reference ( in Visual Basic), the current exception is raised in a block that handles the inner exception. +public sealed class StateContainerException(string message, Exception? innerException = null) : InvalidOperationException(message, innerException); \ No newline at end of file diff --git a/src/CommunityToolkit.Maui/Layouts/StateContainer/StateContainerController.shared.cs b/src/CommunityToolkit.Maui/Layouts/StateContainer/StateContainerController.shared.cs index ef1216e30b..6d7db2d726 100644 --- a/src/CommunityToolkit.Maui/Layouts/StateContainer/StateContainerController.shared.cs +++ b/src/CommunityToolkit.Maui/Layouts/StateContainer/StateContainerController.shared.cs @@ -3,23 +3,21 @@ /// /// StateContainer Controller /// -sealed class StateContainerController +/// +/// Initialize with a +/// +/// The layout that this controller manages. +sealed class StateContainerController(Layout layout) { - readonly WeakReference layoutWeakReference; + readonly WeakReference layoutWeakReference = new(layout); string? previousState; List originalContent = Enumerable.Empty().ToList(); - /// - /// Initialize with a - /// - /// - public StateContainerController(Layout layout) => layoutWeakReference = new WeakReference(layout); - /// /// The StateViews defined in the StateContainer. /// - public required IList StateViews { get; set; } + public required IList StateViews { get; init; } /// /// Display the default content. @@ -84,7 +82,14 @@ internal Layout GetLayout() View GetViewForState(string state) { - var view = StateViews.FirstOrDefault(x => StateView.GetStateKey(x) == state); - return view ?? throw new StateContainerException($"View for {state} not defined."); + try + { + var view = StateViews.SingleOrDefault(x => StateView.GetStateKey(x) == state); + return view ?? throw new StateContainerException($"{nameof(StateView)} for {state} not defined."); + } + catch (InvalidOperationException e) + { + throw new StateContainerException($"Unable to determine {nameof(StateView)} for State: {state}. This State has been assigned to multiple {nameof(StateView)}s. Ensure each {nameof(StateView)} has a unique StateKey", e); + } } } \ No newline at end of file diff --git a/src/CommunityToolkit.Maui/Primitives/StateContainerDefaults.shared.cs b/src/CommunityToolkit.Maui/Primitives/StateContainerDefaults.shared.cs index bb3a6ce3b4..02a82d7cc9 100644 --- a/src/CommunityToolkit.Maui/Primitives/StateContainerDefaults.shared.cs +++ b/src/CommunityToolkit.Maui/Primitives/StateContainerDefaults.shared.cs @@ -4,5 +4,4 @@ static class StateContainerDefaults { public const string? CurrentState = null; public const bool CanStateChange = true; - public static IList StateViews { get; } = []; } \ No newline at end of file From 63bfdd4bd124b935a1aa3422f763987a8c258f0d Mon Sep 17 00:00:00 2001 From: James Crutchley Date: Tue, 17 Feb 2026 04:37:17 -0800 Subject: [PATCH 28/50] Switch to using event handlers for Full Screen Events --- .../Handlers/MediaElementHandler.android.cs | 12 +++++++++ .../Handlers/MediaElementHandler.windows.cs | 23 ++++++++++++++-- .../Views/MauiMediaElement.android.cs | 13 +++++++-- .../Views/MauiMediaElement.windows.cs | 27 ++++++++++++------- .../Views/MediaManager.windows.cs | 6 +---- 5 files changed, 63 insertions(+), 18 deletions(-) diff --git a/src/CommunityToolkit.Maui.MediaElement/Handlers/MediaElementHandler.android.cs b/src/CommunityToolkit.Maui.MediaElement/Handlers/MediaElementHandler.android.cs index 9a1ed2e361..fe657cc76c 100644 --- a/src/CommunityToolkit.Maui.MediaElement/Handlers/MediaElementHandler.android.cs +++ b/src/CommunityToolkit.Maui.MediaElement/Handlers/MediaElementHandler.android.cs @@ -25,11 +25,23 @@ protected override MauiMediaElement CreatePlatformView() Dispatcher.GetForCurrentThread() ?? throw new InvalidOperationException($"{nameof(IDispatcher)} cannot be null")); var (_, playerView) = MediaManager.CreatePlatformView(VirtualView.AndroidViewType, VirtualView.IsAndroidForegroundServiceEnabled); + VirtualView.FullScreenStateChanged += HandleFullScreenButtonClicked; return new(Context, playerView); } + protected override void ConnectHandler(MauiMediaElement platformView) + { + platformView.FullScreenButtonClicked += HandleFullScreenButtonClicked; + base.ConnectHandler(platformView); + } + + void HandleFullScreenButtonClicked(object? sender, FullScreenStateChangedEventArgs e) + { + MediaManager?.UpdateFullScreenState(e.NewState); + } protected override void DisconnectHandler(MauiMediaElement platformView) { + platformView.FullScreenButtonClicked -= HandleFullScreenButtonClicked; platformView.Dispose(); Dispose(); base.DisconnectHandler(platformView); diff --git a/src/CommunityToolkit.Maui.MediaElement/Handlers/MediaElementHandler.windows.cs b/src/CommunityToolkit.Maui.MediaElement/Handlers/MediaElementHandler.windows.cs index 8b60e8c219..3a4687ab5e 100644 --- a/src/CommunityToolkit.Maui.MediaElement/Handlers/MediaElementHandler.windows.cs +++ b/src/CommunityToolkit.Maui.MediaElement/Handlers/MediaElementHandler.windows.cs @@ -26,7 +26,25 @@ protected override MauiMediaElement CreatePlatformView() Dispatcher.GetForCurrentThread() ?? throw new InvalidOperationException($"{nameof(IDispatcher)} cannot be null")); var mediaPlatform = MediaManager.CreatePlatformView(); - return new(mediaPlatform, MediaManager); + + return new(mediaPlatform); + } + + /// + /// Establishes a connection between the handler and the specified platform-specific media element view. + /// + /// Overrides the base implementation to provide custom connection logic for the media element on the + /// Windows platform. + /// The platform-specific media element view to connect to the handler. Cannot be null. + protected override void ConnectHandler(MauiMediaElement platformView) + { + platformView.FullScreenButtonClicked += HandleFullScreenButtonClicked; + base.ConnectHandler(platformView); + } + + void HandleFullScreenButtonClicked(object? sender, FullScreenStateChangedEventArgs e) + { + MediaManager?.UpdateFullScreenState(e.NewState); } /// @@ -37,11 +55,12 @@ protected override void DisconnectHandler(MauiMediaElement platformView) base.DisconnectHandler(platformView); } - static void UnloadPlatformView(MauiMediaElement platformView) + void UnloadPlatformView(MauiMediaElement platformView) { if (platformView.IsLoaded) { platformView.Unloaded += OnPlatformViewUnloaded; + platformView.FullScreenButtonClicked -= HandleFullScreenButtonClicked; } else { diff --git a/src/CommunityToolkit.Maui.MediaElement/Views/MauiMediaElement.android.cs b/src/CommunityToolkit.Maui.MediaElement/Views/MauiMediaElement.android.cs index f381d44175..fbc25860a0 100644 --- a/src/CommunityToolkit.Maui.MediaElement/Views/MauiMediaElement.android.cs +++ b/src/CommunityToolkit.Maui.MediaElement/Views/MauiMediaElement.android.cs @@ -17,6 +17,13 @@ public class MauiMediaElement : CoordinatorLayout { readonly RelativeLayout relativeLayout; readonly PlayerView playerView; + /// + /// Occurs when the full screen button is clicked, providing information about the new full screen state. + /// + /// Subscribe to this event to be notified when the user toggles the full screen mode. The event + /// provides details about the resulting state through the + /// parameter. + public event EventHandler? FullScreenButtonClicked; int defaultSystemUiVisibility; bool isSystemBarVisible; @@ -120,17 +127,19 @@ void OnFullscreenButtonClick(object? sender, PlayerView.FullscreenButtonClickEve isFullScreen = true; RemoveView(relativeLayout); layout?.AddView(relativeLayout); - mediaManager.UpdateFullScreenState(MediaElementScreenState.FullScreen); } else { isFullScreen = false; layout?.RemoveView(relativeLayout); AddView(relativeLayout); - mediaManager.UpdateFullScreenState(MediaElementScreenState.Default); } // Hide/Show the SystemBars and Status bar SetSystemBarsVisibility(); + + var newState = e.P0 ? MediaElementScreenState.FullScreen : MediaElementScreenState.Default; + var oldState = e.P0 ? MediaElementScreenState.Default : MediaElementScreenState.FullScreen; + FullScreenButtonClicked?.Invoke(this, new FullScreenStateChangedEventArgs(oldState, newState)); } void SetSystemBarsVisibility() diff --git a/src/CommunityToolkit.Maui.MediaElement/Views/MauiMediaElement.windows.cs b/src/CommunityToolkit.Maui.MediaElement/Views/MauiMediaElement.windows.cs index 85af56d05d..e73cad1a99 100644 --- a/src/CommunityToolkit.Maui.MediaElement/Views/MauiMediaElement.windows.cs +++ b/src/CommunityToolkit.Maui.MediaElement/Views/MauiMediaElement.windows.cs @@ -3,8 +3,6 @@ using CommunityToolkit.Maui.Extensions; using CommunityToolkit.Maui.Primitives; using CommunityToolkit.Maui.Views; -using Microsoft.Maui.Controls; -using Microsoft.Maui.Devices; using Microsoft.UI; using Microsoft.UI.Windowing; using Microsoft.UI.Xaml; @@ -22,6 +20,13 @@ namespace CommunityToolkit.Maui.Core.Views; /// public partial class MauiMediaElement : Grid, IDisposable { + /// + /// Occurs when the full screen button is clicked, providing information about the new full screen state. + /// + /// Subscribe to this event to be notified when the user toggles the full screen mode. The event + /// provides details about the resulting state through the + /// parameter. + public event EventHandler? FullScreenButtonClicked; [LibraryImport("user32.dll")] internal static partial IntPtr GetForegroundWindow(); @@ -36,7 +41,6 @@ public partial class MauiMediaElement : Grid, IDisposable readonly Popup popup = new(); readonly Grid fullScreenGrid = new(); readonly MediaPlayerElement mediaPlayerElement; - readonly MediaManager mediaManager; readonly CustomTransportControls? customTransportControls; bool doesNavigationBarExistBeforeFullScreen; bool isDisposed; @@ -45,11 +49,9 @@ public partial class MauiMediaElement : Grid, IDisposable /// Initializes a new instance of the class. /// /// - /// - public MauiMediaElement(MediaPlayerElement mediaPlayerElement, MediaManager mediaManager) + public MauiMediaElement(MediaPlayerElement mediaPlayerElement) { LoadResourceDictionary(); - this.mediaManager = mediaManager; this.mediaPlayerElement = mediaPlayerElement; customTransportControls = SetTransportControls(); Children.Add(this.mediaPlayerElement); @@ -181,7 +183,7 @@ void OnFullScreenButtonClick(object sender, RoutedEventArgs e) { var currentPage = CurrentPage; var appWindow = GetAppWindowForCurrentWindow(); - + MediaElementScreenState? mediaElementState = null; if (appWindow.Presenter.Kind is AppWindowPresenterKind.FullScreen) { appWindow.SetPresenter(AppWindowPresenterKind.Default); @@ -198,7 +200,7 @@ void OnFullScreenButtonClick(object sender, RoutedEventArgs e) var parent = mediaPlayerElement.Parent as FrameworkElement; mediaPlayerElement.Width = parent?.Width ?? mediaPlayerElement.Width; mediaPlayerElement.Height = parent?.Height ?? mediaPlayerElement.Height; - mediaManager.UpdateFullScreenState(MediaElementScreenState.Default); + mediaElementState = MediaElementScreenState.Default; } else { @@ -225,7 +227,14 @@ void OnFullScreenButtonClick(object sender, RoutedEventArgs e) { popup.IsOpen = true; } - mediaManager.UpdateFullScreenState(MediaElementScreenState.FullScreen); + mediaElementState = MediaElementScreenState.FullScreen; + } + if (mediaElementState is null) + { + return; } + var newState = mediaElementState.Value; + var oldState = newState == MediaElementScreenState.FullScreen ? MediaElementScreenState.Default : MediaElementScreenState.FullScreen; + FullScreenButtonClicked?.Invoke(this, new FullScreenStateChangedEventArgs(oldState, newState)); } } \ No newline at end of file diff --git a/src/CommunityToolkit.Maui.MediaElement/Views/MediaManager.windows.cs b/src/CommunityToolkit.Maui.MediaElement/Views/MediaManager.windows.cs index d12af56c84..45c87004d8 100644 --- a/src/CommunityToolkit.Maui.MediaElement/Views/MediaManager.windows.cs +++ b/src/CommunityToolkit.Maui.MediaElement/Views/MediaManager.windows.cs @@ -4,9 +4,6 @@ using CommunityToolkit.Maui.Extensions; using CommunityToolkit.Maui.Views; using Microsoft.Extensions.Logging; -using Microsoft.Maui; -using Microsoft.Maui.Controls; -using Microsoft.Maui.Dispatching; using Microsoft.UI.Xaml.Controls; using Microsoft.UI.Xaml.Media.Imaging; using Windows.Media; @@ -15,7 +12,6 @@ using Windows.System.Display; using ParentWindow = CommunityToolkit.Maui.Extensions.PageExtensions.ParentWindow; using WindowsMediaElement = Windows.Media.Playback.MediaPlayer; -using WinMediaSource = Windows.Media.Core.MediaSource; namespace CommunityToolkit.Maui.Core.Views; @@ -66,7 +62,7 @@ public PlatformMediaElement CreatePlatformView() Player.MediaPlayer.SystemMediaTransportControls.IsEnabled = false; systemMediaControls = Player.MediaPlayer.SystemMediaTransportControls; - + return Player; } From ba5d9be58e40f62965fc59191fd1afec93b17a2d Mon Sep 17 00:00:00 2001 From: James Crutchley Date: Tue, 17 Feb 2026 06:08:38 -0800 Subject: [PATCH 29/50] Refactor FullScreenButtonClicked event handling Refactor FullScreenButtonClicked to use WeakEventManager and make it internal across Android, Windows, and iOS/macOS. Update event subscription and invocation patterns for improved encapsulation and memory management. Remove unused usings and ensure proper event unsubscription to prevent leaks. --- .../Handlers/MediaElementHandler.android.cs | 8 ++--- .../Handlers/MediaElementHandler.windows.cs | 6 ++-- .../Views/MauiMediaElement.android.cs | 17 +++++----- .../Views/MauiMediaElement.windows.cs | 17 +++++----- .../Views/MediaManager.macios.cs | 33 ++++++++++++++----- .../Views/MediaManager.shared.cs | 4 --- 6 files changed, 49 insertions(+), 36 deletions(-) diff --git a/src/CommunityToolkit.Maui.MediaElement/Handlers/MediaElementHandler.android.cs b/src/CommunityToolkit.Maui.MediaElement/Handlers/MediaElementHandler.android.cs index fe657cc76c..d32147c578 100644 --- a/src/CommunityToolkit.Maui.MediaElement/Handlers/MediaElementHandler.android.cs +++ b/src/CommunityToolkit.Maui.MediaElement/Handlers/MediaElementHandler.android.cs @@ -25,23 +25,23 @@ protected override MauiMediaElement CreatePlatformView() Dispatcher.GetForCurrentThread() ?? throw new InvalidOperationException($"{nameof(IDispatcher)} cannot be null")); var (_, playerView) = MediaManager.CreatePlatformView(VirtualView.AndroidViewType, VirtualView.IsAndroidForegroundServiceEnabled); - VirtualView.FullScreenStateChanged += HandleFullScreenButtonClicked; + VirtualView.FullScreenStateChanged += OnFullScreenStateChanged; return new(Context, playerView); } protected override void ConnectHandler(MauiMediaElement platformView) { - platformView.FullScreenButtonClicked += HandleFullScreenButtonClicked; + platformView.FullScreenButtonClicked += OnFullScreenStateChanged; base.ConnectHandler(platformView); } - void HandleFullScreenButtonClicked(object? sender, FullScreenStateChangedEventArgs e) + void OnFullScreenStateChanged(object? sender, FullScreenStateChangedEventArgs e) { MediaManager?.UpdateFullScreenState(e.NewState); } protected override void DisconnectHandler(MauiMediaElement platformView) { - platformView.FullScreenButtonClicked -= HandleFullScreenButtonClicked; + platformView.FullScreenButtonClicked -= OnFullScreenStateChanged; platformView.Dispose(); Dispose(); base.DisconnectHandler(platformView); diff --git a/src/CommunityToolkit.Maui.MediaElement/Handlers/MediaElementHandler.windows.cs b/src/CommunityToolkit.Maui.MediaElement/Handlers/MediaElementHandler.windows.cs index 3a4687ab5e..cb23de6840 100644 --- a/src/CommunityToolkit.Maui.MediaElement/Handlers/MediaElementHandler.windows.cs +++ b/src/CommunityToolkit.Maui.MediaElement/Handlers/MediaElementHandler.windows.cs @@ -38,11 +38,11 @@ protected override MauiMediaElement CreatePlatformView() /// The platform-specific media element view to connect to the handler. Cannot be null. protected override void ConnectHandler(MauiMediaElement platformView) { - platformView.FullScreenButtonClicked += HandleFullScreenButtonClicked; + platformView.FullScreenButtonClicked += OnFullScreenStateChanged; base.ConnectHandler(platformView); } - void HandleFullScreenButtonClicked(object? sender, FullScreenStateChangedEventArgs e) + void OnFullScreenStateChanged(object? sender, FullScreenStateChangedEventArgs e) { MediaManager?.UpdateFullScreenState(e.NewState); } @@ -60,7 +60,7 @@ void UnloadPlatformView(MauiMediaElement platformView) if (platformView.IsLoaded) { platformView.Unloaded += OnPlatformViewUnloaded; - platformView.FullScreenButtonClicked -= HandleFullScreenButtonClicked; + platformView.FullScreenButtonClicked -= OnFullScreenStateChanged; } else { diff --git a/src/CommunityToolkit.Maui.MediaElement/Views/MauiMediaElement.android.cs b/src/CommunityToolkit.Maui.MediaElement/Views/MauiMediaElement.android.cs index fbc25860a0..38843e3789 100644 --- a/src/CommunityToolkit.Maui.MediaElement/Views/MauiMediaElement.android.cs +++ b/src/CommunityToolkit.Maui.MediaElement/Views/MauiMediaElement.android.cs @@ -17,18 +17,17 @@ public class MauiMediaElement : CoordinatorLayout { readonly RelativeLayout relativeLayout; readonly PlayerView playerView; - /// - /// Occurs when the full screen button is clicked, providing information about the new full screen state. - /// - /// Subscribe to this event to be notified when the user toggles the full screen mode. The event - /// provides details about the resulting state through the - /// parameter. - public event EventHandler? FullScreenButtonClicked; - + readonly WeakEventManager fullScreenEventManager = new(); int defaultSystemUiVisibility; bool isSystemBarVisible; bool isFullScreen; + internal event EventHandler FullScreenButtonClicked + { + add => fullScreenEventManager.AddEventHandler(value); + remove => fullScreenEventManager.RemoveEventHandler(value); + } + #pragma warning disable CS8618 // Non-nullable field is uninitialized. Consider declaring as nullable. #pragma warning disable IDE0060 // Remove unused parameter public MauiMediaElement(nint ptr, JniHandleOwnership jni) : base(Platform.AppContext) @@ -139,7 +138,7 @@ void OnFullscreenButtonClick(object? sender, PlayerView.FullscreenButtonClickEve var newState = e.P0 ? MediaElementScreenState.FullScreen : MediaElementScreenState.Default; var oldState = e.P0 ? MediaElementScreenState.Default : MediaElementScreenState.FullScreen; - FullScreenButtonClicked?.Invoke(this, new FullScreenStateChangedEventArgs(oldState, newState)); + fullScreenEventManager.HandleEvent(this, new FullScreenStateChangedEventArgs(oldState, newState), nameof(FullScreenButtonClicked)); } void SetSystemBarsVisibility() diff --git a/src/CommunityToolkit.Maui.MediaElement/Views/MauiMediaElement.windows.cs b/src/CommunityToolkit.Maui.MediaElement/Views/MauiMediaElement.windows.cs index e73cad1a99..6681243060 100644 --- a/src/CommunityToolkit.Maui.MediaElement/Views/MauiMediaElement.windows.cs +++ b/src/CommunityToolkit.Maui.MediaElement/Views/MauiMediaElement.windows.cs @@ -20,13 +20,6 @@ namespace CommunityToolkit.Maui.Core.Views; /// public partial class MauiMediaElement : Grid, IDisposable { - /// - /// Occurs when the full screen button is clicked, providing information about the new full screen state. - /// - /// Subscribe to this event to be notified when the user toggles the full screen mode. The event - /// provides details about the resulting state through the - /// parameter. - public event EventHandler? FullScreenButtonClicked; [LibraryImport("user32.dll")] internal static partial IntPtr GetForegroundWindow(); @@ -38,6 +31,8 @@ public partial class MauiMediaElement : Grid, IDisposable var hwnd = GetForegroundWindow(); return hwnd == IntPtr.Zero ? null : hwnd; } + + readonly WeakEventManager fullScreenEventManager = new(); readonly Popup popup = new(); readonly Grid fullScreenGrid = new(); readonly MediaPlayerElement mediaPlayerElement; @@ -45,6 +40,12 @@ public partial class MauiMediaElement : Grid, IDisposable bool doesNavigationBarExistBeforeFullScreen; bool isDisposed; + internal event EventHandler FullScreenButtonClicked + { + add => fullScreenEventManager.AddEventHandler(value); + remove => fullScreenEventManager.RemoveEventHandler(value); + } + /// /// Initializes a new instance of the class. /// @@ -235,6 +236,6 @@ void OnFullScreenButtonClick(object sender, RoutedEventArgs e) } var newState = mediaElementState.Value; var oldState = newState == MediaElementScreenState.FullScreen ? MediaElementScreenState.Default : MediaElementScreenState.FullScreen; - FullScreenButtonClicked?.Invoke(this, new FullScreenStateChangedEventArgs(oldState, newState)); + fullScreenEventManager.HandleEvent(this, new FullScreenStateChangedEventArgs(oldState, newState), nameof(FullScreenButtonClicked)); } } \ No newline at end of file diff --git a/src/CommunityToolkit.Maui.MediaElement/Views/MediaManager.macios.cs b/src/CommunityToolkit.Maui.MediaElement/Views/MediaManager.macios.cs index 173d69ea18..92d25ccbea 100644 --- a/src/CommunityToolkit.Maui.MediaElement/Views/MediaManager.macios.cs +++ b/src/CommunityToolkit.Maui.MediaElement/Views/MediaManager.macios.cs @@ -14,7 +14,7 @@ namespace CommunityToolkit.Maui.Core.Views; public partial class MediaManager : IDisposable { Metadata? metaData; - + MediaManagerDelegate? mDelegate; // Media would still start playing when Speed was set although ShouldAutoPlay=False // This field was added to overcome that. bool isInitialSpeedSet; @@ -26,12 +26,15 @@ public partial class MediaManager : IDisposable public (PlatformMediaElement Player, AVPlayerViewController PlayerViewController) CreatePlatformView() { Player = new(); + mDelegate = new MediaManagerDelegate(); + mDelegate.FullScreenButtonClicked += OnFullScreenStateChanged; + PlayerViewController = new() { Player = Player, - Delegate = new MediaManagerDelegate(this) + Delegate = mDelegate, }; - + // Pre-initialize Volume and Muted properties to the player object Player.Muted = MediaElement.ShouldMute; var volumeDiff = Math.Abs(Player.Volume - MediaElement.Volume); @@ -58,6 +61,11 @@ public partial class MediaManager : IDisposable return (Player, PlayerViewController); } + void OnFullScreenStateChanged(object? sender, FullScreenStateChangedEventArgs e) + { + UpdateFullScreenState(e.NewState); + } + /// /// Releases the managed and unmanaged resources used by the . /// @@ -426,7 +434,7 @@ protected virtual void Dispose(bool disposing) UIApplication.SharedApplication.IdleTimerDisabled = false; var audioSession = AVAudioSession.SharedInstance(); audioSession.SetActive(false); - + mDelegate?.FullScreenButtonClicked -= OnFullScreenStateChanged; DestroyErrorObservers(); DestroyPlayedToEndObserver(); @@ -725,16 +733,25 @@ void RateChanged(object? sender, NSNotificationEventArgs args) } } -sealed class MediaManagerDelegate(MediaManager mediaManager) : AVPlayerViewControllerDelegate +sealed class MediaManagerDelegate : AVPlayerViewControllerDelegate { - readonly MediaManager mediaManager = mediaManager; + readonly WeakEventManager fullScreenEventManager = new(); + internal event EventHandler FullScreenButtonClicked + { + add => fullScreenEventManager.AddEventHandler(value); + remove => fullScreenEventManager.RemoveEventHandler(value); + } public override void WillBeginFullScreenPresentation(AVPlayerViewController playerViewController, IUIViewControllerTransitionCoordinator coordinator) { - mediaManager.UpdateFullScreenState(MediaElementScreenState.FullScreen); + var oldState = MediaElementScreenState.Default; + var newState = MediaElementScreenState.FullScreen; + fullScreenEventManager.HandleEvent(this, new FullScreenStateChangedEventArgs(oldState, newState), nameof(FullScreenButtonClicked)); } public override void WillEndFullScreenPresentation(AVPlayerViewController playerViewController, IUIViewControllerTransitionCoordinator coordinator) { - mediaManager.UpdateFullScreenState(MediaElementScreenState.Default); + var oldState = MediaElementScreenState.FullScreen; + var newState = MediaElementScreenState.Default; + fullScreenEventManager.HandleEvent(this, new FullScreenStateChangedEventArgs(oldState, newState), nameof(FullScreenButtonClicked)); } } \ No newline at end of file diff --git a/src/CommunityToolkit.Maui.MediaElement/Views/MediaManager.shared.cs b/src/CommunityToolkit.Maui.MediaElement/Views/MediaManager.shared.cs index 3a1e53be18..16968e708b 100644 --- a/src/CommunityToolkit.Maui.MediaElement/Views/MediaManager.shared.cs +++ b/src/CommunityToolkit.Maui.MediaElement/Views/MediaManager.shared.cs @@ -12,10 +12,6 @@ #endif using Microsoft.Extensions.Logging; -using Microsoft.Maui; -using Microsoft.Maui.Dispatching; -using Microsoft.Maui.Controls; -using Microsoft.Extensions.DependencyInjection; namespace CommunityToolkit.Maui.Core.Views; From d3d8028ce7020962c79a06601be7438914b45d95 Mon Sep 17 00:00:00 2001 From: James Crutchley Date: Tue, 17 Feb 2026 06:16:23 -0800 Subject: [PATCH 30/50] Update src/CommunityToolkit.Maui.MediaElement/Handlers/MediaElementHandler.android.cs Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- .../Handlers/MediaElementHandler.android.cs | 1 - 1 file changed, 1 deletion(-) diff --git a/src/CommunityToolkit.Maui.MediaElement/Handlers/MediaElementHandler.android.cs b/src/CommunityToolkit.Maui.MediaElement/Handlers/MediaElementHandler.android.cs index d32147c578..5fc933a7e0 100644 --- a/src/CommunityToolkit.Maui.MediaElement/Handlers/MediaElementHandler.android.cs +++ b/src/CommunityToolkit.Maui.MediaElement/Handlers/MediaElementHandler.android.cs @@ -25,7 +25,6 @@ protected override MauiMediaElement CreatePlatformView() Dispatcher.GetForCurrentThread() ?? throw new InvalidOperationException($"{nameof(IDispatcher)} cannot be null")); var (_, playerView) = MediaManager.CreatePlatformView(VirtualView.AndroidViewType, VirtualView.IsAndroidForegroundServiceEnabled); - VirtualView.FullScreenStateChanged += OnFullScreenStateChanged; return new(Context, playerView); } From cbc8b71c0a43406b046025711415311052da727d Mon Sep 17 00:00:00 2001 From: James Crutchley Date: Tue, 17 Feb 2026 06:36:30 -0800 Subject: [PATCH 31/50] Update src/CommunityToolkit.Maui.MediaElement/Views/MediaManager.shared.cs Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- .../Views/MediaManager.shared.cs | 1 - 1 file changed, 1 deletion(-) diff --git a/src/CommunityToolkit.Maui.MediaElement/Views/MediaManager.shared.cs b/src/CommunityToolkit.Maui.MediaElement/Views/MediaManager.shared.cs index 16968e708b..66bc702253 100644 --- a/src/CommunityToolkit.Maui.MediaElement/Views/MediaManager.shared.cs +++ b/src/CommunityToolkit.Maui.MediaElement/Views/MediaManager.shared.cs @@ -1,4 +1,3 @@ -// NOTE: PR shares code with #1918 https://github.com/CommunityToolkit/Maui/pull/1918 #if !(ANDROID || IOS || WINDOWS || MACCATALYST || TIZEN) global using PlatformMediaElement = System.Object; #elif ANDROID From f6eab31b115541cc16b6975e68403ca1d7e67d57 Mon Sep 17 00:00:00 2001 From: James Crutchley Date: Tue, 17 Feb 2026 06:54:24 -0800 Subject: [PATCH 32/50] Fixes --- .../Handlers/MediaElementHandler.windows.cs | 2 +- .../MediaElement.shared.cs | 9 +++++---- .../Primitives/MediaElementFullScreenState.cs | 8 ++++---- 3 files changed, 10 insertions(+), 9 deletions(-) diff --git a/src/CommunityToolkit.Maui.MediaElement/Handlers/MediaElementHandler.windows.cs b/src/CommunityToolkit.Maui.MediaElement/Handlers/MediaElementHandler.windows.cs index cb23de6840..388d39d177 100644 --- a/src/CommunityToolkit.Maui.MediaElement/Handlers/MediaElementHandler.windows.cs +++ b/src/CommunityToolkit.Maui.MediaElement/Handlers/MediaElementHandler.windows.cs @@ -57,10 +57,10 @@ protected override void DisconnectHandler(MauiMediaElement platformView) void UnloadPlatformView(MauiMediaElement platformView) { + platformView.FullScreenButtonClicked -= OnFullScreenStateChanged; if (platformView.IsLoaded) { platformView.Unloaded += OnPlatformViewUnloaded; - platformView.FullScreenButtonClicked -= OnFullScreenStateChanged; } else { diff --git a/src/CommunityToolkit.Maui.MediaElement/MediaElement.shared.cs b/src/CommunityToolkit.Maui.MediaElement/MediaElement.shared.cs index 35bbca24ef..6fd4283c47 100644 --- a/src/CommunityToolkit.Maui.MediaElement/MediaElement.shared.cs +++ b/src/CommunityToolkit.Maui.MediaElement/MediaElement.shared.cs @@ -32,12 +32,13 @@ public partial class MediaElement : View, IMediaElement, IDisposable /// public static readonly BindableProperty DurationProperty = durationPropertyKey.BindableProperty; + static readonly BindablePropertyKey fullScreenPropertyKey = + BindableProperty.CreateReadOnly(nameof(FullScreenState), typeof(MediaElementScreenState), typeof(MediaElement), + MediaElementScreenState.Default, propertyChanged: OnFullScreenPropertyChanged); /// /// Backing store for the property. /// - public static readonly BindableProperty FullScreenProperty = - BindableProperty.Create(nameof(FullScreenState), typeof(MediaElementScreenState), typeof(MediaElement), - MediaElementScreenState.Default, propertyChanged: OnFullScreenPropertyChanged); + public static readonly BindableProperty FullScreenProperty = fullScreenPropertyKey.BindableProperty; /// /// Backing store for the property. @@ -391,7 +392,7 @@ public MediaElementState CurrentState public MediaElementScreenState FullScreenState { get => (MediaElementScreenState)GetValue(FullScreenProperty); - private set => SetValue(FullScreenProperty, value); + private set => SetValue(fullScreenPropertyKey, value); } /// diff --git a/src/CommunityToolkit.Maui.MediaElement/Primitives/MediaElementFullScreenState.cs b/src/CommunityToolkit.Maui.MediaElement/Primitives/MediaElementFullScreenState.cs index e20b922b75..37ce45480e 100644 --- a/src/CommunityToolkit.Maui.MediaElement/Primitives/MediaElementFullScreenState.cs +++ b/src/CommunityToolkit.Maui.MediaElement/Primitives/MediaElementFullScreenState.cs @@ -6,12 +6,12 @@ public enum MediaElementScreenState { /// - /// Full screen. + /// The default state. /// - FullScreen, + Default = 0, /// - /// The default state. + /// Full screen. /// - Default, + FullScreen = 1, } From 12bf3b3b87d0d239f4924b6aeb1653f31a268edd Mon Sep 17 00:00:00 2001 From: James Crutchley Date: Tue, 17 Feb 2026 07:01:06 -0800 Subject: [PATCH 33/50] More Fixes --- .../Handlers/MediaElementHandler.windows.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/CommunityToolkit.Maui.MediaElement/Handlers/MediaElementHandler.windows.cs b/src/CommunityToolkit.Maui.MediaElement/Handlers/MediaElementHandler.windows.cs index 388d39d177..3868885ba1 100644 --- a/src/CommunityToolkit.Maui.MediaElement/Handlers/MediaElementHandler.windows.cs +++ b/src/CommunityToolkit.Maui.MediaElement/Handlers/MediaElementHandler.windows.cs @@ -51,13 +51,13 @@ void OnFullScreenStateChanged(object? sender, FullScreenStateChangedEventArgs e) protected override void DisconnectHandler(MauiMediaElement platformView) { Dispose(); + platformView.FullScreenButtonClicked -= OnFullScreenStateChanged; UnloadPlatformView(platformView); base.DisconnectHandler(platformView); } - void UnloadPlatformView(MauiMediaElement platformView) + static void UnloadPlatformView(MauiMediaElement platformView) { - platformView.FullScreenButtonClicked -= OnFullScreenStateChanged; if (platformView.IsLoaded) { platformView.Unloaded += OnPlatformViewUnloaded; From 41a000672112b55330e3f7418f8f070d158526c5 Mon Sep 17 00:00:00 2001 From: James Crutchley Date: Tue, 17 Feb 2026 07:32:39 -0800 Subject: [PATCH 34/50] Add Tets for MediaElementScreenState --- .../Views/MediaElement/MediaElementTests.cs | 69 +++++++++++++++++++ 1 file changed, 69 insertions(+) diff --git a/src/CommunityToolkit.Maui.UnitTests/Views/MediaElement/MediaElementTests.cs b/src/CommunityToolkit.Maui.UnitTests/Views/MediaElement/MediaElementTests.cs index 93b6f2e1ff..d674199a00 100644 --- a/src/CommunityToolkit.Maui.UnitTests/Views/MediaElement/MediaElementTests.cs +++ b/src/CommunityToolkit.Maui.UnitTests/Views/MediaElement/MediaElementTests.cs @@ -2,6 +2,7 @@ using CommunityToolkit.Maui.Views; using FluentAssertions; using Xunit; +using System.Collections.Generic; namespace CommunityToolkit.Maui.UnitTests.Views; @@ -145,4 +146,72 @@ public void MediaElementVolumeShouldNotBeLessThan0() }; }); } + + [Fact] + public void FullScreenChanged_RaisesEventAndUpdatesState() + { + // Arrange + var media = new MediaElement(); + var captured = new List(); + + media.FullScreenStateChanged += (_, e) => captured.Add(e); + + var imedia = (IMediaElement)media; + + // Pre-assert default + Assert.Equal(MediaElementScreenState.Default, media.FullScreenState); + + // Act + imedia.FullScreenChanged(MediaElementScreenState.FullScreen); + + // Assert + Assert.Equal(MediaElementScreenState.FullScreen, media.FullScreenState); + Assert.Single(captured); + Assert.Equal(MediaElementScreenState.Default, captured[0].PreviousState); + Assert.Equal(MediaElementScreenState.FullScreen, captured[0].NewState); + } + + [Fact] + public void FullScreenChanged_ToggleBack_RaisesEventWithPreviousState() + { + // Arrange + var media = new MediaElement(); + var captured = new List(); + + media.FullScreenStateChanged += (_, e) => captured.Add(e); + + var imedia = (IMediaElement)media; + + // Set to full screen first + imedia.FullScreenChanged(MediaElementScreenState.FullScreen); + Assert.Equal(MediaElementScreenState.FullScreen, media.FullScreenState); + + captured.Clear(); + + // Act - toggle back to default + imedia.FullScreenChanged(MediaElementScreenState.Default); + + // Assert + Assert.Equal(MediaElementScreenState.Default, media.FullScreenState); + Assert.Single(captured); + Assert.Equal(MediaElementScreenState.FullScreen, captured[0].PreviousState); + Assert.Equal(MediaElementScreenState.Default, captured[0].NewState); + } + + [Fact] + public void SettingBindableProperty_DoesNotChangeReadOnlyState() + { + // Arrange + var media = new MediaElement(); + var captured = new List(); + + media.FullScreenStateChanged += (_, e) => captured.Add(e); + + // Act - FullScreenProperty is read-only; attempting to set via BindableProperty should not change it + media.SetValue(MediaElement.FullScreenProperty, MediaElementScreenState.FullScreen); + + // Assert - state remains default and no event was raised + Assert.Equal(MediaElementScreenState.Default, media.FullScreenState); + Assert.Empty(captured); + } } \ No newline at end of file From e1092b36383556e680b8688b0ac913f51e35da33 Mon Sep 17 00:00:00 2001 From: James Crutchley Date: Tue, 17 Feb 2026 08:46:26 -0800 Subject: [PATCH 35/50] Update src/CommunityToolkit.Maui.MediaElement/Handlers/MediaElementHandler.android.cs Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- .../Handlers/MediaElementHandler.android.cs | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/CommunityToolkit.Maui.MediaElement/Handlers/MediaElementHandler.android.cs b/src/CommunityToolkit.Maui.MediaElement/Handlers/MediaElementHandler.android.cs index 5fc933a7e0..8ee33231a9 100644 --- a/src/CommunityToolkit.Maui.MediaElement/Handlers/MediaElementHandler.android.cs +++ b/src/CommunityToolkit.Maui.MediaElement/Handlers/MediaElementHandler.android.cs @@ -38,6 +38,11 @@ void OnFullScreenStateChanged(object? sender, FullScreenStateChangedEventArgs e) { MediaManager?.UpdateFullScreenState(e.NewState); } + /// + /// Disconnects the handler from the platform-specific and + /// unsubscribes from related events, disposing the platform view and handler resources. + /// + /// The platform-specific instance to disconnect. protected override void DisconnectHandler(MauiMediaElement platformView) { platformView.FullScreenButtonClicked -= OnFullScreenStateChanged; From bca8914ea64ac764c9225c4fc12e1458bdb86278 Mon Sep 17 00:00:00 2001 From: James Crutchley Date: Tue, 17 Feb 2026 09:21:18 -0800 Subject: [PATCH 36/50] Update src/CommunityToolkit.Maui.MediaElement/Interfaces/IMediaElement.shared.cs Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- .../Interfaces/IMediaElement.shared.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/CommunityToolkit.Maui.MediaElement/Interfaces/IMediaElement.shared.cs b/src/CommunityToolkit.Maui.MediaElement/Interfaces/IMediaElement.shared.cs index ffd5381082..481f9f3599 100644 --- a/src/CommunityToolkit.Maui.MediaElement/Interfaces/IMediaElement.shared.cs +++ b/src/CommunityToolkit.Maui.MediaElement/Interfaces/IMediaElement.shared.cs @@ -32,7 +32,7 @@ public interface IMediaElement : IView, IAsynchronousMediaElementHandler /// /// Gets the full screen state of the media element. /// - MediaElementScreenState FullScreenState { get;} + MediaElementScreenState FullScreenState { get; } /// /// Gets the height (in pixels) of the loaded media in pixels. From 8b63297422758eaad721616d9a30a871b2348b70 Mon Sep 17 00:00:00 2001 From: James Crutchley Date: Tue, 17 Feb 2026 09:22:10 -0800 Subject: [PATCH 37/50] Update src/CommunityToolkit.Maui.MediaElement/Interfaces/IMediaElement.shared.cs Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- .../Interfaces/IMediaElement.shared.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/CommunityToolkit.Maui.MediaElement/Interfaces/IMediaElement.shared.cs b/src/CommunityToolkit.Maui.MediaElement/Interfaces/IMediaElement.shared.cs index 481f9f3599..b3595512a1 100644 --- a/src/CommunityToolkit.Maui.MediaElement/Interfaces/IMediaElement.shared.cs +++ b/src/CommunityToolkit.Maui.MediaElement/Interfaces/IMediaElement.shared.cs @@ -173,8 +173,8 @@ public interface IMediaElement : IView, IAsynchronousMediaElementHandler internal void CurrentStateChanged(MediaElementState newState); /// - /// Triggers a change. + /// Triggers a change. Intended to be called by platform-specific handlers or managers when the fullscreen state changes. /// - /// + /// The new fullscreen state the transitioned to. internal void FullScreenChanged(MediaElementScreenState newState); } \ No newline at end of file From 0fc8b1a924abe33c8f86b09b14d2873a0f1a3481 Mon Sep 17 00:00:00 2001 From: James Crutchley Date: Tue, 17 Feb 2026 09:40:34 -0800 Subject: [PATCH 38/50] Update tests --- ...llScreenState.cs => MediaElementScreenState.cs} | 0 .../Views/MediaElement/MediaElementTests.cs | 14 +++++++++++--- 2 files changed, 11 insertions(+), 3 deletions(-) rename src/CommunityToolkit.Maui.MediaElement/Primitives/{MediaElementFullScreenState.cs => MediaElementScreenState.cs} (100%) diff --git a/src/CommunityToolkit.Maui.MediaElement/Primitives/MediaElementFullScreenState.cs b/src/CommunityToolkit.Maui.MediaElement/Primitives/MediaElementScreenState.cs similarity index 100% rename from src/CommunityToolkit.Maui.MediaElement/Primitives/MediaElementFullScreenState.cs rename to src/CommunityToolkit.Maui.MediaElement/Primitives/MediaElementScreenState.cs diff --git a/src/CommunityToolkit.Maui.UnitTests/Views/MediaElement/MediaElementTests.cs b/src/CommunityToolkit.Maui.UnitTests/Views/MediaElement/MediaElementTests.cs index d674199a00..dbff26f21e 100644 --- a/src/CommunityToolkit.Maui.UnitTests/Views/MediaElement/MediaElementTests.cs +++ b/src/CommunityToolkit.Maui.UnitTests/Views/MediaElement/MediaElementTests.cs @@ -207,10 +207,18 @@ public void SettingBindableProperty_DoesNotChangeReadOnlyState() media.FullScreenStateChanged += (_, e) => captured.Add(e); - // Act - FullScreenProperty is read-only; attempting to set via BindableProperty should not change it - media.SetValue(MediaElement.FullScreenProperty, MediaElementScreenState.FullScreen); + // Act - FullScreenProperty is read-only; attempting to set via BindableProperty may throw + try + { + media.SetValue(MediaElement.FullScreenProperty, MediaElementScreenState.FullScreen); + } + catch (System.Exception ex) + { + // If the framework throws, ensure it's the expected type + Assert.IsType(ex); + } - // Assert - state remains default and no event was raised + // Ensure state remains unchanged and no event was raised in either case Assert.Equal(MediaElementScreenState.Default, media.FullScreenState); Assert.Empty(captured); } From aefaba3e49b4af59102597255d595d656eecfa4d Mon Sep 17 00:00:00 2001 From: James Crutchley Date: Tue, 17 Feb 2026 09:46:17 -0800 Subject: [PATCH 39/50] Standardize full-screen event to FullScreenStateChanged Renamed the FullScreenButtonClicked event to FullScreenStateChanged across Android, Windows, and iOS/macOS MediaElement implementations. Updated all event declarations, handler subscriptions, and invocations for consistency and clarity. Also renamed related variables (e.g., mDelegate to fullScreenDelegate) to match the new event naming. This change ensures the event accurately represents any full-screen state change, not just button clicks. --- .../Handlers/MediaElementHandler.android.cs | 4 ++-- .../Handlers/MediaElementHandler.windows.cs | 4 ++-- .../Views/MauiMediaElement.android.cs | 4 ++-- .../Views/MauiMediaElement.windows.cs | 4 ++-- .../Views/MediaManager.macios.cs | 16 ++++++++-------- 5 files changed, 16 insertions(+), 16 deletions(-) diff --git a/src/CommunityToolkit.Maui.MediaElement/Handlers/MediaElementHandler.android.cs b/src/CommunityToolkit.Maui.MediaElement/Handlers/MediaElementHandler.android.cs index 8ee33231a9..9649454706 100644 --- a/src/CommunityToolkit.Maui.MediaElement/Handlers/MediaElementHandler.android.cs +++ b/src/CommunityToolkit.Maui.MediaElement/Handlers/MediaElementHandler.android.cs @@ -30,7 +30,7 @@ protected override MauiMediaElement CreatePlatformView() protected override void ConnectHandler(MauiMediaElement platformView) { - platformView.FullScreenButtonClicked += OnFullScreenStateChanged; + platformView.FullScreenStateChanged += OnFullScreenStateChanged; base.ConnectHandler(platformView); } @@ -45,7 +45,7 @@ void OnFullScreenStateChanged(object? sender, FullScreenStateChangedEventArgs e) /// The platform-specific instance to disconnect. protected override void DisconnectHandler(MauiMediaElement platformView) { - platformView.FullScreenButtonClicked -= OnFullScreenStateChanged; + platformView.FullScreenStateChanged -= OnFullScreenStateChanged; platformView.Dispose(); Dispose(); base.DisconnectHandler(platformView); diff --git a/src/CommunityToolkit.Maui.MediaElement/Handlers/MediaElementHandler.windows.cs b/src/CommunityToolkit.Maui.MediaElement/Handlers/MediaElementHandler.windows.cs index 3868885ba1..7ba6c9bfa9 100644 --- a/src/CommunityToolkit.Maui.MediaElement/Handlers/MediaElementHandler.windows.cs +++ b/src/CommunityToolkit.Maui.MediaElement/Handlers/MediaElementHandler.windows.cs @@ -38,7 +38,7 @@ protected override MauiMediaElement CreatePlatformView() /// The platform-specific media element view to connect to the handler. Cannot be null. protected override void ConnectHandler(MauiMediaElement platformView) { - platformView.FullScreenButtonClicked += OnFullScreenStateChanged; + platformView.FullScreenStateChanged += OnFullScreenStateChanged; base.ConnectHandler(platformView); } @@ -51,7 +51,7 @@ void OnFullScreenStateChanged(object? sender, FullScreenStateChangedEventArgs e) protected override void DisconnectHandler(MauiMediaElement platformView) { Dispose(); - platformView.FullScreenButtonClicked -= OnFullScreenStateChanged; + platformView.FullScreenStateChanged -= OnFullScreenStateChanged; UnloadPlatformView(platformView); base.DisconnectHandler(platformView); } diff --git a/src/CommunityToolkit.Maui.MediaElement/Views/MauiMediaElement.android.cs b/src/CommunityToolkit.Maui.MediaElement/Views/MauiMediaElement.android.cs index 38843e3789..ed724f64f5 100644 --- a/src/CommunityToolkit.Maui.MediaElement/Views/MauiMediaElement.android.cs +++ b/src/CommunityToolkit.Maui.MediaElement/Views/MauiMediaElement.android.cs @@ -22,7 +22,7 @@ public class MauiMediaElement : CoordinatorLayout bool isSystemBarVisible; bool isFullScreen; - internal event EventHandler FullScreenButtonClicked + internal event EventHandler FullScreenStateChanged { add => fullScreenEventManager.AddEventHandler(value); remove => fullScreenEventManager.RemoveEventHandler(value); @@ -138,7 +138,7 @@ void OnFullscreenButtonClick(object? sender, PlayerView.FullscreenButtonClickEve var newState = e.P0 ? MediaElementScreenState.FullScreen : MediaElementScreenState.Default; var oldState = e.P0 ? MediaElementScreenState.Default : MediaElementScreenState.FullScreen; - fullScreenEventManager.HandleEvent(this, new FullScreenStateChangedEventArgs(oldState, newState), nameof(FullScreenButtonClicked)); + fullScreenEventManager.HandleEvent(this, new FullScreenStateChangedEventArgs(oldState, newState), nameof(FullScreenStateChanged)); } void SetSystemBarsVisibility() diff --git a/src/CommunityToolkit.Maui.MediaElement/Views/MauiMediaElement.windows.cs b/src/CommunityToolkit.Maui.MediaElement/Views/MauiMediaElement.windows.cs index 6681243060..56030759dc 100644 --- a/src/CommunityToolkit.Maui.MediaElement/Views/MauiMediaElement.windows.cs +++ b/src/CommunityToolkit.Maui.MediaElement/Views/MauiMediaElement.windows.cs @@ -40,7 +40,7 @@ public partial class MauiMediaElement : Grid, IDisposable bool doesNavigationBarExistBeforeFullScreen; bool isDisposed; - internal event EventHandler FullScreenButtonClicked + internal event EventHandler FullScreenStateChanged { add => fullScreenEventManager.AddEventHandler(value); remove => fullScreenEventManager.RemoveEventHandler(value); @@ -236,6 +236,6 @@ void OnFullScreenButtonClick(object sender, RoutedEventArgs e) } var newState = mediaElementState.Value; var oldState = newState == MediaElementScreenState.FullScreen ? MediaElementScreenState.Default : MediaElementScreenState.FullScreen; - fullScreenEventManager.HandleEvent(this, new FullScreenStateChangedEventArgs(oldState, newState), nameof(FullScreenButtonClicked)); + fullScreenEventManager.HandleEvent(this, new FullScreenStateChangedEventArgs(oldState, newState), nameof(FullScreenStateChanged)); } } \ No newline at end of file diff --git a/src/CommunityToolkit.Maui.MediaElement/Views/MediaManager.macios.cs b/src/CommunityToolkit.Maui.MediaElement/Views/MediaManager.macios.cs index 92d25ccbea..aef4e4f9f2 100644 --- a/src/CommunityToolkit.Maui.MediaElement/Views/MediaManager.macios.cs +++ b/src/CommunityToolkit.Maui.MediaElement/Views/MediaManager.macios.cs @@ -14,7 +14,7 @@ namespace CommunityToolkit.Maui.Core.Views; public partial class MediaManager : IDisposable { Metadata? metaData; - MediaManagerDelegate? mDelegate; + MediaManagerDelegate? fullScreenDelegate; // Media would still start playing when Speed was set although ShouldAutoPlay=False // This field was added to overcome that. bool isInitialSpeedSet; @@ -26,13 +26,13 @@ public partial class MediaManager : IDisposable public (PlatformMediaElement Player, AVPlayerViewController PlayerViewController) CreatePlatformView() { Player = new(); - mDelegate = new MediaManagerDelegate(); - mDelegate.FullScreenButtonClicked += OnFullScreenStateChanged; + fullScreenDelegate = new MediaManagerDelegate(); + fullScreenDelegate.FullScreenStateChanged += OnFullScreenStateChanged; PlayerViewController = new() { Player = Player, - Delegate = mDelegate, + Delegate = fullScreenDelegate, }; // Pre-initialize Volume and Muted properties to the player object @@ -434,7 +434,7 @@ protected virtual void Dispose(bool disposing) UIApplication.SharedApplication.IdleTimerDisabled = false; var audioSession = AVAudioSession.SharedInstance(); audioSession.SetActive(false); - mDelegate?.FullScreenButtonClicked -= OnFullScreenStateChanged; + fullScreenDelegate?.FullScreenStateChanged -= OnFullScreenStateChanged; DestroyErrorObservers(); DestroyPlayedToEndObserver(); @@ -736,7 +736,7 @@ void RateChanged(object? sender, NSNotificationEventArgs args) sealed class MediaManagerDelegate : AVPlayerViewControllerDelegate { readonly WeakEventManager fullScreenEventManager = new(); - internal event EventHandler FullScreenButtonClicked + internal event EventHandler FullScreenStateChanged { add => fullScreenEventManager.AddEventHandler(value); remove => fullScreenEventManager.RemoveEventHandler(value); @@ -746,12 +746,12 @@ public override void WillBeginFullScreenPresentation(AVPlayerViewController play { var oldState = MediaElementScreenState.Default; var newState = MediaElementScreenState.FullScreen; - fullScreenEventManager.HandleEvent(this, new FullScreenStateChangedEventArgs(oldState, newState), nameof(FullScreenButtonClicked)); + fullScreenEventManager.HandleEvent(this, new FullScreenStateChangedEventArgs(oldState, newState), nameof(FullScreenStateChanged)); } public override void WillEndFullScreenPresentation(AVPlayerViewController playerViewController, IUIViewControllerTransitionCoordinator coordinator) { var oldState = MediaElementScreenState.FullScreen; var newState = MediaElementScreenState.Default; - fullScreenEventManager.HandleEvent(this, new FullScreenStateChangedEventArgs(oldState, newState), nameof(FullScreenButtonClicked)); + fullScreenEventManager.HandleEvent(this, new FullScreenStateChangedEventArgs(oldState, newState), nameof(FullScreenStateChanged)); } } \ No newline at end of file From 85833876bbed65177f1af0ad071613296226a0dc Mon Sep 17 00:00:00 2001 From: James Crutchley Date: Tue, 17 Feb 2026 10:06:52 -0800 Subject: [PATCH 40/50] Rename FullScreenStateChanged to ScreenStateChanged Refactored all usages of FullScreenStateChanged event and related types to ScreenStateChanged for improved clarity and generalization. Replaced FullScreenStateChangedEventArgs with ScreenStateChangedEventArgs, updated property and field names, and revised event handler signatures and XAML wiring across all platforms. Updated unit tests to reflect these changes. This makes screen state transitions more semantically accurate and extensible beyond just full screen scenarios. --- .../Views/MediaElement/MediaElementPage.xaml | 2 +- .../MediaElement/MediaElementPage.xaml.cs | 2 +- .../Handlers/MediaElementHandler.android.cs | 6 +++--- .../Handlers/MediaElementHandler.windows.cs | 6 +++--- .../Interfaces/IMediaElement.shared.cs | 2 +- .../MediaElement.shared.cs | 18 +++++++++--------- ...tArgs.cs => ScreenStateChangedEventArgs.cs} | 4 ++-- .../Views/MauiMediaElement.android.cs | 4 ++-- .../Views/MauiMediaElement.windows.cs | 4 ++-- .../Views/MediaManager.macios.cs | 12 ++++++------ .../Views/MediaElement/MediaElementTests.cs | 16 ++++++++-------- 11 files changed, 38 insertions(+), 38 deletions(-) rename src/CommunityToolkit.Maui.MediaElement/Primitives/{FullScreenStateChangedEventArgs.cs => ScreenStateChangedEventArgs.cs} (74%) diff --git a/samples/CommunityToolkit.Maui.Sample/Pages/Views/MediaElement/MediaElementPage.xaml b/samples/CommunityToolkit.Maui.Sample/Pages/Views/MediaElement/MediaElementPage.xaml index e95d0ae6da..a85957bcf4 100644 --- a/samples/CommunityToolkit.Maui.Sample/Pages/Views/MediaElement/MediaElementPage.xaml +++ b/samples/CommunityToolkit.Maui.Sample/Pages/Views/MediaElement/MediaElementPage.xaml @@ -40,7 +40,7 @@ PositionChanged="OnPositionChanged" StateChanged="OnStateChanged" SeekCompleted="OnSeekCompleted" - FullScreenStateChanged="MediaElement_FullScreenStateChanged"/> + ScreenStateChanged="MediaElement_FullScreenStateChanged"/> /// -/// Initializes a new instance of the class. +/// Initializes a new instance of the class. /// /// /// -public sealed class FullScreenStateChangedEventArgs(MediaElementScreenState previousState, MediaElementScreenState newState) : EventArgs +public sealed class ScreenStateChangedEventArgs(MediaElementScreenState previousState, MediaElementScreenState newState) : EventArgs { /// diff --git a/src/CommunityToolkit.Maui.MediaElement/Views/MauiMediaElement.android.cs b/src/CommunityToolkit.Maui.MediaElement/Views/MauiMediaElement.android.cs index ed724f64f5..85fe4a377c 100644 --- a/src/CommunityToolkit.Maui.MediaElement/Views/MauiMediaElement.android.cs +++ b/src/CommunityToolkit.Maui.MediaElement/Views/MauiMediaElement.android.cs @@ -22,7 +22,7 @@ public class MauiMediaElement : CoordinatorLayout bool isSystemBarVisible; bool isFullScreen; - internal event EventHandler FullScreenStateChanged + internal event EventHandler FullScreenStateChanged { add => fullScreenEventManager.AddEventHandler(value); remove => fullScreenEventManager.RemoveEventHandler(value); @@ -138,7 +138,7 @@ void OnFullscreenButtonClick(object? sender, PlayerView.FullscreenButtonClickEve var newState = e.P0 ? MediaElementScreenState.FullScreen : MediaElementScreenState.Default; var oldState = e.P0 ? MediaElementScreenState.Default : MediaElementScreenState.FullScreen; - fullScreenEventManager.HandleEvent(this, new FullScreenStateChangedEventArgs(oldState, newState), nameof(FullScreenStateChanged)); + fullScreenEventManager.HandleEvent(this, new ScreenStateChangedEventArgs(oldState, newState), nameof(FullScreenStateChanged)); } void SetSystemBarsVisibility() diff --git a/src/CommunityToolkit.Maui.MediaElement/Views/MauiMediaElement.windows.cs b/src/CommunityToolkit.Maui.MediaElement/Views/MauiMediaElement.windows.cs index 56030759dc..a27bc5e0cc 100644 --- a/src/CommunityToolkit.Maui.MediaElement/Views/MauiMediaElement.windows.cs +++ b/src/CommunityToolkit.Maui.MediaElement/Views/MauiMediaElement.windows.cs @@ -40,7 +40,7 @@ public partial class MauiMediaElement : Grid, IDisposable bool doesNavigationBarExistBeforeFullScreen; bool isDisposed; - internal event EventHandler FullScreenStateChanged + internal event EventHandler FullScreenStateChanged { add => fullScreenEventManager.AddEventHandler(value); remove => fullScreenEventManager.RemoveEventHandler(value); @@ -236,6 +236,6 @@ void OnFullScreenButtonClick(object sender, RoutedEventArgs e) } var newState = mediaElementState.Value; var oldState = newState == MediaElementScreenState.FullScreen ? MediaElementScreenState.Default : MediaElementScreenState.FullScreen; - fullScreenEventManager.HandleEvent(this, new FullScreenStateChangedEventArgs(oldState, newState), nameof(FullScreenStateChanged)); + fullScreenEventManager.HandleEvent(this, new ScreenStateChangedEventArgs(oldState, newState), nameof(FullScreenStateChanged)); } } \ No newline at end of file diff --git a/src/CommunityToolkit.Maui.MediaElement/Views/MediaManager.macios.cs b/src/CommunityToolkit.Maui.MediaElement/Views/MediaManager.macios.cs index aef4e4f9f2..58e98c8705 100644 --- a/src/CommunityToolkit.Maui.MediaElement/Views/MediaManager.macios.cs +++ b/src/CommunityToolkit.Maui.MediaElement/Views/MediaManager.macios.cs @@ -27,7 +27,7 @@ public partial class MediaManager : IDisposable { Player = new(); fullScreenDelegate = new MediaManagerDelegate(); - fullScreenDelegate.FullScreenStateChanged += OnFullScreenStateChanged; + fullScreenDelegate.ScreenStateChanged += OnScreenStateChanged; PlayerViewController = new() { @@ -61,7 +61,7 @@ public partial class MediaManager : IDisposable return (Player, PlayerViewController); } - void OnFullScreenStateChanged(object? sender, FullScreenStateChangedEventArgs e) + void OnScreenStateChanged(object? sender, ScreenStateChangedEventArgs e) { UpdateFullScreenState(e.NewState); } @@ -434,7 +434,7 @@ protected virtual void Dispose(bool disposing) UIApplication.SharedApplication.IdleTimerDisabled = false; var audioSession = AVAudioSession.SharedInstance(); audioSession.SetActive(false); - fullScreenDelegate?.FullScreenStateChanged -= OnFullScreenStateChanged; + fullScreenDelegate?.ScreenStateChanged -= OnScreenStateChanged; DestroyErrorObservers(); DestroyPlayedToEndObserver(); @@ -736,7 +736,7 @@ void RateChanged(object? sender, NSNotificationEventArgs args) sealed class MediaManagerDelegate : AVPlayerViewControllerDelegate { readonly WeakEventManager fullScreenEventManager = new(); - internal event EventHandler FullScreenStateChanged + internal event EventHandler ScreenStateChanged { add => fullScreenEventManager.AddEventHandler(value); remove => fullScreenEventManager.RemoveEventHandler(value); @@ -746,12 +746,12 @@ public override void WillBeginFullScreenPresentation(AVPlayerViewController play { var oldState = MediaElementScreenState.Default; var newState = MediaElementScreenState.FullScreen; - fullScreenEventManager.HandleEvent(this, new FullScreenStateChangedEventArgs(oldState, newState), nameof(FullScreenStateChanged)); + fullScreenEventManager.HandleEvent(this, new ScreenStateChangedEventArgs(oldState, newState), nameof(ScreenStateChanged)); } public override void WillEndFullScreenPresentation(AVPlayerViewController playerViewController, IUIViewControllerTransitionCoordinator coordinator) { var oldState = MediaElementScreenState.FullScreen; var newState = MediaElementScreenState.Default; - fullScreenEventManager.HandleEvent(this, new FullScreenStateChangedEventArgs(oldState, newState), nameof(FullScreenStateChanged)); + fullScreenEventManager.HandleEvent(this, new ScreenStateChangedEventArgs(oldState, newState), nameof(ScreenStateChanged)); } } \ No newline at end of file diff --git a/src/CommunityToolkit.Maui.UnitTests/Views/MediaElement/MediaElementTests.cs b/src/CommunityToolkit.Maui.UnitTests/Views/MediaElement/MediaElementTests.cs index dbff26f21e..9f117b98df 100644 --- a/src/CommunityToolkit.Maui.UnitTests/Views/MediaElement/MediaElementTests.cs +++ b/src/CommunityToolkit.Maui.UnitTests/Views/MediaElement/MediaElementTests.cs @@ -152,9 +152,9 @@ public void FullScreenChanged_RaisesEventAndUpdatesState() { // Arrange var media = new MediaElement(); - var captured = new List(); + var captured = new List(); - media.FullScreenStateChanged += (_, e) => captured.Add(e); + media.ScreenStateChanged += (_, e) => captured.Add(e); var imedia = (IMediaElement)media; @@ -176,9 +176,9 @@ public void FullScreenChanged_ToggleBack_RaisesEventWithPreviousState() { // Arrange var media = new MediaElement(); - var captured = new List(); + var captured = new List(); - media.FullScreenStateChanged += (_, e) => captured.Add(e); + media.ScreenStateChanged += (_, e) => captured.Add(e); var imedia = (IMediaElement)media; @@ -203,14 +203,14 @@ public void SettingBindableProperty_DoesNotChangeReadOnlyState() { // Arrange var media = new MediaElement(); - var captured = new List(); + var captured = new List(); - media.FullScreenStateChanged += (_, e) => captured.Add(e); + media.ScreenStateChanged += (_, e) => captured.Add(e); - // Act - FullScreenProperty is read-only; attempting to set via BindableProperty may throw + // Act - ScreenStateProperty is read-only; attempting to set via BindableProperty may throw try { - media.SetValue(MediaElement.FullScreenProperty, MediaElementScreenState.FullScreen); + media.SetValue(MediaElement.ScreenStateProperty, MediaElementScreenState.FullScreen); } catch (System.Exception ex) { From 0f3a264e77826b0efac75127f82efb728892958a Mon Sep 17 00:00:00 2001 From: James Crutchley Date: Tue, 17 Feb 2026 10:21:46 -0800 Subject: [PATCH 41/50] Update src/CommunityToolkit.Maui.MediaElement/Primitives/ScreenStateChangedEventArgs.cs Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- .../Primitives/ScreenStateChangedEventArgs.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/CommunityToolkit.Maui.MediaElement/Primitives/ScreenStateChangedEventArgs.cs b/src/CommunityToolkit.Maui.MediaElement/Primitives/ScreenStateChangedEventArgs.cs index e07f474f57..7fc1210950 100644 --- a/src/CommunityToolkit.Maui.MediaElement/Primitives/ScreenStateChangedEventArgs.cs +++ b/src/CommunityToolkit.Maui.MediaElement/Primitives/ScreenStateChangedEventArgs.cs @@ -12,12 +12,12 @@ public sealed class ScreenStateChangedEventArgs(MediaElementScreenState previous { /// - /// Gets the previous state that the instance is transitioning from. + /// Gets the previous state that the instance is transitioning from. /// public MediaElementScreenState PreviousState { get; } = previousState; /// - /// Gets the new state that the instance is transitioning to. + /// Gets the new state that the instance is transitioning to. /// public MediaElementScreenState NewState { get; } = newState; } From 5c42fe21123ece25aaae31c538ae88ef58d923bf Mon Sep 17 00:00:00 2001 From: James Crutchley Date: Tue, 17 Feb 2026 18:24:58 -0800 Subject: [PATCH 42/50] Update src/CommunityToolkit.Maui.MediaElement/Views/MauiMediaElement.windows.cs Co-authored-by: Pedro Jesus --- .../Views/MauiMediaElement.windows.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/CommunityToolkit.Maui.MediaElement/Views/MauiMediaElement.windows.cs b/src/CommunityToolkit.Maui.MediaElement/Views/MauiMediaElement.windows.cs index a27bc5e0cc..ab42b7ffb5 100644 --- a/src/CommunityToolkit.Maui.MediaElement/Views/MauiMediaElement.windows.cs +++ b/src/CommunityToolkit.Maui.MediaElement/Views/MauiMediaElement.windows.cs @@ -184,7 +184,7 @@ void OnFullScreenButtonClick(object sender, RoutedEventArgs e) { var currentPage = CurrentPage; var appWindow = GetAppWindowForCurrentWindow(); - MediaElementScreenState? mediaElementState = null; + var mediaElementState = MediaElementScreenState.Default; if (appWindow.Presenter.Kind is AppWindowPresenterKind.FullScreen) { appWindow.SetPresenter(AppWindowPresenterKind.Default); From a340b3043e848b31e06d489d6ba2985adda13c3a Mon Sep 17 00:00:00 2001 From: James Crutchley Date: Tue, 17 Feb 2026 18:26:05 -0800 Subject: [PATCH 43/50] Update src/CommunityToolkit.Maui.MediaElement/Views/MediaManager.macios.cs Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- .../Views/MediaManager.macios.cs | 1 - 1 file changed, 1 deletion(-) diff --git a/src/CommunityToolkit.Maui.MediaElement/Views/MediaManager.macios.cs b/src/CommunityToolkit.Maui.MediaElement/Views/MediaManager.macios.cs index 58e98c8705..862ea90c7c 100644 --- a/src/CommunityToolkit.Maui.MediaElement/Views/MediaManager.macios.cs +++ b/src/CommunityToolkit.Maui.MediaElement/Views/MediaManager.macios.cs @@ -34,7 +34,6 @@ public partial class MediaManager : IDisposable Player = Player, Delegate = fullScreenDelegate, }; - // Pre-initialize Volume and Muted properties to the player object Player.Muted = MediaElement.ShouldMute; var volumeDiff = Math.Abs(Player.Volume - MediaElement.Volume); From 855641299db22b4c4c0510bb2d68f78c5ab625d8 Mon Sep 17 00:00:00 2001 From: James Crutchley Date: Tue, 17 Feb 2026 18:26:37 -0800 Subject: [PATCH 44/50] Update src/CommunityToolkit.Maui.MediaElement/Handlers/MediaElementHandler.windows.cs Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- .../Handlers/MediaElementHandler.windows.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/CommunityToolkit.Maui.MediaElement/Handlers/MediaElementHandler.windows.cs b/src/CommunityToolkit.Maui.MediaElement/Handlers/MediaElementHandler.windows.cs index daec8ae5f6..6a82da50e5 100644 --- a/src/CommunityToolkit.Maui.MediaElement/Handlers/MediaElementHandler.windows.cs +++ b/src/CommunityToolkit.Maui.MediaElement/Handlers/MediaElementHandler.windows.cs @@ -50,8 +50,8 @@ void OnScreenStateChanged(object? sender, ScreenStateChangedEventArgs e) /// protected override void DisconnectHandler(MauiMediaElement platformView) { - Dispose(); platformView.FullScreenStateChanged -= OnScreenStateChanged; + Dispose(); UnloadPlatformView(platformView); base.DisconnectHandler(platformView); } From ef273908c87fe970b8ce1226f03c026ba71557a8 Mon Sep 17 00:00:00 2001 From: James Crutchley Date: Tue, 17 Feb 2026 18:27:00 -0800 Subject: [PATCH 45/50] Update src/CommunityToolkit.Maui.MediaElement/Views/MediaManager.windows.cs Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- .../Views/MediaManager.windows.cs | 1 - 1 file changed, 1 deletion(-) diff --git a/src/CommunityToolkit.Maui.MediaElement/Views/MediaManager.windows.cs b/src/CommunityToolkit.Maui.MediaElement/Views/MediaManager.windows.cs index 45c87004d8..c5e2883835 100644 --- a/src/CommunityToolkit.Maui.MediaElement/Views/MediaManager.windows.cs +++ b/src/CommunityToolkit.Maui.MediaElement/Views/MediaManager.windows.cs @@ -62,7 +62,6 @@ public PlatformMediaElement CreatePlatformView() Player.MediaPlayer.SystemMediaTransportControls.IsEnabled = false; systemMediaControls = Player.MediaPlayer.SystemMediaTransportControls; - return Player; } From 27d6e99a387487b765d0f5e30c2fe5ce77ac80d7 Mon Sep 17 00:00:00 2001 From: James Crutchley Date: Tue, 17 Feb 2026 18:27:24 -0800 Subject: [PATCH 46/50] Update src/CommunityToolkit.Maui.MediaElement/Handlers/MediaElementHandler.windows.cs Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- .../Handlers/MediaElementHandler.windows.cs | 1 - 1 file changed, 1 deletion(-) diff --git a/src/CommunityToolkit.Maui.MediaElement/Handlers/MediaElementHandler.windows.cs b/src/CommunityToolkit.Maui.MediaElement/Handlers/MediaElementHandler.windows.cs index 6a82da50e5..ee5ad0cdd0 100644 --- a/src/CommunityToolkit.Maui.MediaElement/Handlers/MediaElementHandler.windows.cs +++ b/src/CommunityToolkit.Maui.MediaElement/Handlers/MediaElementHandler.windows.cs @@ -26,7 +26,6 @@ protected override MauiMediaElement CreatePlatformView() Dispatcher.GetForCurrentThread() ?? throw new InvalidOperationException($"{nameof(IDispatcher)} cannot be null")); var mediaPlatform = MediaManager.CreatePlatformView(); - return new(mediaPlatform); } From 2d3ac0c3561876c99f3aeee09c4955c042733924 Mon Sep 17 00:00:00 2001 From: James Crutchley Date: Tue, 17 Feb 2026 18:29:45 -0800 Subject: [PATCH 47/50] Update src/CommunityToolkit.Maui.UnitTests/Views/MediaElement/MediaElementTests.cs Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- .../Views/MediaElement/MediaElementTests.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/CommunityToolkit.Maui.UnitTests/Views/MediaElement/MediaElementTests.cs b/src/CommunityToolkit.Maui.UnitTests/Views/MediaElement/MediaElementTests.cs index 9f117b98df..adf424b1e3 100644 --- a/src/CommunityToolkit.Maui.UnitTests/Views/MediaElement/MediaElementTests.cs +++ b/src/CommunityToolkit.Maui.UnitTests/Views/MediaElement/MediaElementTests.cs @@ -1,8 +1,8 @@ using CommunityToolkit.Maui.Core; using CommunityToolkit.Maui.Views; using FluentAssertions; -using Xunit; using System.Collections.Generic; +using Xunit; namespace CommunityToolkit.Maui.UnitTests.Views; From 8878c83855fc598aba7e93dd0b7b6fe4ab74576b Mon Sep 17 00:00:00 2001 From: James Crutchley Date: Tue, 17 Feb 2026 18:52:42 -0800 Subject: [PATCH 48/50] Rename FullScreenState to ScreenState in MediaElement Renamed the FullScreenState property and all related references to ScreenState across the codebase. This includes property names, event documentation, method parameters, and all usages in implementation and tests. The change generalizes the state property to better reflect its purpose and potential future use cases beyond just fullscreen. --- .../Interfaces/IMediaElement.shared.cs | 6 +++--- .../MediaElement.shared.cs | 8 ++++---- .../Views/MediaElement/MediaElementTests.cs | 10 +++++----- 3 files changed, 12 insertions(+), 12 deletions(-) diff --git a/src/CommunityToolkit.Maui.MediaElement/Interfaces/IMediaElement.shared.cs b/src/CommunityToolkit.Maui.MediaElement/Interfaces/IMediaElement.shared.cs index f4f79421c7..4cab252de7 100644 --- a/src/CommunityToolkit.Maui.MediaElement/Interfaces/IMediaElement.shared.cs +++ b/src/CommunityToolkit.Maui.MediaElement/Interfaces/IMediaElement.shared.cs @@ -32,7 +32,7 @@ public interface IMediaElement : IView, IAsynchronousMediaElementHandler /// /// Gets the full screen state of the media element. /// - MediaElementScreenState FullScreenState { get; } + MediaElementScreenState ScreenState { get; } /// /// Gets the height (in pixels) of the loaded media in pixels. @@ -117,7 +117,7 @@ public interface IMediaElement : IView, IAsynchronousMediaElementHandler string MetadataArtworkUrl { get; set; } /// - /// Occurs when the changes. + /// Occurs when the changes. /// event EventHandler ScreenStateChanged; @@ -173,7 +173,7 @@ public interface IMediaElement : IView, IAsynchronousMediaElementHandler internal void CurrentStateChanged(MediaElementState newState); /// - /// Triggers a change. Intended to be called by platform-specific handlers or managers when the fullscreen state changes. + /// Triggers a change. Intended to be called by platform-specific handlers or managers when the fullscreen state changes. /// /// The new fullscreen state the transitioned to. internal void FullScreenChanged(MediaElementScreenState newState); diff --git a/src/CommunityToolkit.Maui.MediaElement/MediaElement.shared.cs b/src/CommunityToolkit.Maui.MediaElement/MediaElement.shared.cs index 956ec8f410..9645c584f2 100644 --- a/src/CommunityToolkit.Maui.MediaElement/MediaElement.shared.cs +++ b/src/CommunityToolkit.Maui.MediaElement/MediaElement.shared.cs @@ -33,10 +33,10 @@ public partial class MediaElement : View, IMediaElement, IDisposable public static readonly BindableProperty DurationProperty = durationPropertyKey.BindableProperty; static readonly BindablePropertyKey screenStatePropertyKey = - BindableProperty.CreateReadOnly(nameof(FullScreenState), typeof(MediaElementScreenState), typeof(MediaElement), + BindableProperty.CreateReadOnly(nameof(ScreenState), typeof(MediaElementScreenState), typeof(MediaElement), MediaElementScreenState.Default, propertyChanged: OnFullScreenPropertyChanged); /// - /// Backing store for the property. + /// Backing store for the property. /// public static readonly BindableProperty ScreenStateProperty = screenStatePropertyKey.BindableProperty; @@ -389,7 +389,7 @@ public MediaElementState CurrentState /// /// Gets the full screen state of the media element. /// - public MediaElementScreenState FullScreenState + public MediaElementScreenState ScreenState { get => (MediaElementScreenState)GetValue(ScreenStateProperty); private set => SetValue(screenStatePropertyKey, value); @@ -617,7 +617,7 @@ void OnSourceChanged(object? sender, EventArgs eventArgs) InvalidateMeasure(); } - void IMediaElement.FullScreenChanged(MediaElementScreenState newState) => FullScreenState = newState; + void IMediaElement.FullScreenChanged(MediaElementScreenState newState) => ScreenState = newState; void OnPositionChanged(MediaPositionChangedEventArgs mediaPositionChangedEventArgs) => eventManager.HandleEvent(this, mediaPositionChangedEventArgs, nameof(PositionChanged)); diff --git a/src/CommunityToolkit.Maui.UnitTests/Views/MediaElement/MediaElementTests.cs b/src/CommunityToolkit.Maui.UnitTests/Views/MediaElement/MediaElementTests.cs index 9f117b98df..03b6208525 100644 --- a/src/CommunityToolkit.Maui.UnitTests/Views/MediaElement/MediaElementTests.cs +++ b/src/CommunityToolkit.Maui.UnitTests/Views/MediaElement/MediaElementTests.cs @@ -159,13 +159,13 @@ public void FullScreenChanged_RaisesEventAndUpdatesState() var imedia = (IMediaElement)media; // Pre-assert default - Assert.Equal(MediaElementScreenState.Default, media.FullScreenState); + Assert.Equal(MediaElementScreenState.Default, media.ScreenState); // Act imedia.FullScreenChanged(MediaElementScreenState.FullScreen); // Assert - Assert.Equal(MediaElementScreenState.FullScreen, media.FullScreenState); + Assert.Equal(MediaElementScreenState.FullScreen, media.ScreenState); Assert.Single(captured); Assert.Equal(MediaElementScreenState.Default, captured[0].PreviousState); Assert.Equal(MediaElementScreenState.FullScreen, captured[0].NewState); @@ -184,7 +184,7 @@ public void FullScreenChanged_ToggleBack_RaisesEventWithPreviousState() // Set to full screen first imedia.FullScreenChanged(MediaElementScreenState.FullScreen); - Assert.Equal(MediaElementScreenState.FullScreen, media.FullScreenState); + Assert.Equal(MediaElementScreenState.FullScreen, media.ScreenState); captured.Clear(); @@ -192,7 +192,7 @@ public void FullScreenChanged_ToggleBack_RaisesEventWithPreviousState() imedia.FullScreenChanged(MediaElementScreenState.Default); // Assert - Assert.Equal(MediaElementScreenState.Default, media.FullScreenState); + Assert.Equal(MediaElementScreenState.Default, media.ScreenState); Assert.Single(captured); Assert.Equal(MediaElementScreenState.FullScreen, captured[0].PreviousState); Assert.Equal(MediaElementScreenState.Default, captured[0].NewState); @@ -219,7 +219,7 @@ public void SettingBindableProperty_DoesNotChangeReadOnlyState() } // Ensure state remains unchanged and no event was raised in either case - Assert.Equal(MediaElementScreenState.Default, media.FullScreenState); + Assert.Equal(MediaElementScreenState.Default, media.ScreenState); Assert.Empty(captured); } } \ No newline at end of file From 735cc47246020a27f394c5eb326a0628b368017c Mon Sep 17 00:00:00 2001 From: James Crutchley Date: Tue, 17 Feb 2026 19:25:14 -0800 Subject: [PATCH 49/50] Refactor: remove nullable checks for mediaElementState Simplified fullscreen toggle logic by removing unnecessary null checks and direct use of the nullable Value property. Assumes mediaElementState is always set, improving code clarity. --- .../Views/MauiMediaElement.windows.cs | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/src/CommunityToolkit.Maui.MediaElement/Views/MauiMediaElement.windows.cs b/src/CommunityToolkit.Maui.MediaElement/Views/MauiMediaElement.windows.cs index ab42b7ffb5..99938d57da 100644 --- a/src/CommunityToolkit.Maui.MediaElement/Views/MauiMediaElement.windows.cs +++ b/src/CommunityToolkit.Maui.MediaElement/Views/MauiMediaElement.windows.cs @@ -201,7 +201,6 @@ void OnFullScreenButtonClick(object sender, RoutedEventArgs e) var parent = mediaPlayerElement.Parent as FrameworkElement; mediaPlayerElement.Width = parent?.Width ?? mediaPlayerElement.Width; mediaPlayerElement.Height = parent?.Height ?? mediaPlayerElement.Height; - mediaElementState = MediaElementScreenState.Default; } else { @@ -230,11 +229,7 @@ void OnFullScreenButtonClick(object sender, RoutedEventArgs e) } mediaElementState = MediaElementScreenState.FullScreen; } - if (mediaElementState is null) - { - return; - } - var newState = mediaElementState.Value; + var newState = mediaElementState; var oldState = newState == MediaElementScreenState.FullScreen ? MediaElementScreenState.Default : MediaElementScreenState.FullScreen; fullScreenEventManager.HandleEvent(this, new ScreenStateChangedEventArgs(oldState, newState), nameof(FullScreenStateChanged)); } From 0e5c649d92a8eafef1c5ac176e1456b659c85881 Mon Sep 17 00:00:00 2001 From: James Crutchley Date: Sun, 24 May 2026 22:05:31 -0700 Subject: [PATCH 50/50] Second merge fix --- .../Views/MediaManager.windows.cs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/CommunityToolkit.Maui.MediaElement/Views/MediaManager.windows.cs b/src/CommunityToolkit.Maui.MediaElement/Views/MediaManager.windows.cs index c5d34a4552..6e63328fa1 100644 --- a/src/CommunityToolkit.Maui.MediaElement/Views/MediaManager.windows.cs +++ b/src/CommunityToolkit.Maui.MediaElement/Views/MediaManager.windows.cs @@ -336,7 +336,7 @@ protected virtual async partial ValueTask PlatformUpdateSource() if (streamMediaSource.Stream is not null) { var randomAccessStream = streamMediaSource.Stream.AsRandomAccessStream(); - Player.Source = WinMediaSource.CreateFromStream(randomAccessStream, streamMediaSource.Stream.GetMimeType()); + Player.Source = Windows.Media.Core.MediaSource.CreateFromStream(randomAccessStream, streamMediaSource.Stream.GetMimeType()); } } } @@ -366,7 +366,7 @@ async Task SetUriSourceWithHeaders(Uri uri, IDictionary headers) adaptiveMediaSource = adaptiveResult.MediaSource; adaptiveMediaSource.DownloadRequested += OnAdaptiveMediaSourceDownloadRequested; - var mediaSource = WinMediaSource.CreateFromAdaptiveMediaSource(adaptiveMediaSource); + var mediaSource = Windows.Media.Core.MediaSource.CreateFromAdaptiveMediaSource(adaptiveMediaSource); await Dispatcher.DispatchAsync(() => { Player.AutoPlay = MediaElement.ShouldAutoPlay; @@ -379,7 +379,7 @@ await Dispatcher.DispatchAsync(() => await Dispatcher.DispatchAsync(() => { Player.AutoPlay = MediaElement.ShouldAutoPlay; - Player.Source = WinMediaSource.CreateFromStream(stream, string.Empty); + Player.Source = Windows.Media.Core.MediaSource.CreateFromStream(stream, string.Empty); }); } }