未验证 提交 8fbd99f4 编写于 作者: M Martin Zikmund 提交者: GitHub

Merge pull request #12910 from unoplatform/dev/rlm/MediaTransportConstrols

......@@ -8,11 +8,31 @@
xmlns:valueConverters="using:UITests.ValueConverters"
mc:Ignorable="d"
Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
<StackPanel>
<MediaPlayerElement x:Name="playbaby"
Source="{x:Bind ToMediaPlaybackItem(SoundToPlay)}"
AreTransportControlsEnabled="True"
Visibility="Visible"
AutoPlay="True"/>
</StackPanel>
<ScrollViewer>
<StackPanel>
<MediaPlayerElement x:Name="MediaPlayerElementSample1"
Source="https://uno-assets.platform.uno/tests/videos/Mobile_Development_in_VS_Code_with_Uno_Platform_orDotNetMAUI.mp4"
AreTransportControlsEnabled="True"
AutoPlay="False"
MaxWidth="720">
<MediaPlayerElement.TransportControls>
<MediaTransportControls IsCompact="False"
ShowAndHideAutomatically="False"/>
</MediaPlayerElement.TransportControls>
</MediaPlayerElement>
<MediaPlayerElement x:Name="MediaPlayerElementSample2"
Source="https://uno-assets.platform.uno/tests/videos/Mobile_Development_in_VS_Code_with_Uno_Platform_orDotNetMAUI.mp4"
AreTransportControlsEnabled="True"
AutoPlay="False"
MaxWidth="720">
<MediaPlayerElement.TransportControls>
<MediaTransportControls IsCompact="True"
ShowAndHideAutomatically="False"/>
</MediaPlayerElement.TransportControls>
</MediaPlayerElement>
</StackPanel>
</ScrollViewer>
</Page>
......@@ -3,17 +3,17 @@
#pragma warning disable 114 // new keyword hiding
namespace Windows.UI.Xaml.Controls
{
#if false || false || IS_UNIT_TESTS || false || __SKIA__ || __NETSTD_REFERENCE__ || false
#if false || false || false || false || false || false || false
[global::Uno.NotImplemented("IS_UNIT_TESTS", "__SKIA__", "__NETSTD_REFERENCE__")]
#endif
public partial class MediaTransportControlsHelper
{
#if false || false || IS_UNIT_TESTS || false || __SKIA__ || __NETSTD_REFERENCE__ || false
#if false || false || false || false || false || false || false
internal MediaTransportControlsHelper()
{
}
#endif
#if false || false || IS_UNIT_TESTS || false || __SKIA__ || __NETSTD_REFERENCE__ || false
#if false || false || false || false || false || false || false
[global::Uno.NotImplemented("IS_UNIT_TESTS", "__SKIA__", "__NETSTD_REFERENCE__")]
public static global::Windows.UI.Xaml.DependencyProperty DropoutOrderProperty { get; } =
Windows.UI.Xaml.DependencyProperty.RegisterAttached(
......@@ -21,20 +21,20 @@ namespace Windows.UI.Xaml.Controls
typeof(global::Windows.UI.Xaml.Controls.MediaTransportControlsHelper),
new Windows.UI.Xaml.FrameworkPropertyMetadata(default(int?)));
#endif
// Forced skipping of method Windows.UI.Xaml.Controls.MediaTransportControlsHelper.DropoutOrderProperty.get
#if false || false || IS_UNIT_TESTS || false || __SKIA__ || __NETSTD_REFERENCE__ || false
// Forced skipping of method Windows.UI.Xaml.Controls.MediaTransportControlsHelper.DropoutOrderProperty.get
#if false || false || false || false || false || false || false
[global::Uno.NotImplemented("IS_UNIT_TESTS", "__SKIA__", "__NETSTD_REFERENCE__")]
public static int? GetDropoutOrder(global::Windows.UI.Xaml.UIElement element)
{
return (int?)element.GetValue(DropoutOrderProperty);
}
#endif
#if false || false || IS_UNIT_TESTS || false || __SKIA__ || __NETSTD_REFERENCE__ || false
#if false || false || false || false || false || false || false
[global::Uno.NotImplemented("IS_UNIT_TESTS", "__SKIA__", "__NETSTD_REFERENCE__")]
public static void SetDropoutOrder(global::Windows.UI.Xaml.UIElement element, int? value)
{
element.SetValue(DropoutOrderProperty, value);
}
#endif
}
}
}
......@@ -240,9 +240,11 @@ namespace Windows.UI.Xaml.Controls
Bind(this, x => x.PointerReleased += OnRootReleased, x => x.PointerReleased -= OnRootReleased);
Bind(this, x => x.PointerCaptureLost += OnRootCaptureLost, x => x.PointerCaptureLost -= OnRootCaptureLost);
Bind(this, x => x.PointerMoved += OnRootMoved, x => x.PointerMoved -= OnRootMoved);
Bind(this, x => x.SizeChanged += OnSizeChanged, x => x.SizeChanged -= OnSizeChanged);
BindLoaded(m_tpCommandBar, OnCommandBarLoaded, invokeHandlerIfAlreadyLoaded: true);
BindSizeChanged(m_tpControlPanelGrid, ControlPanelGridSizeChanged);
Bind(m_tpControlPanelGrid, x => x.PointerEntered += OnControlPanelEntered, x => x.PointerExited -= OnControlPanelEntered);
Bind(m_tpControlPanelGrid, x => x.PointerExited += OnControlPanelExited, x => x.PointerExited -= OnControlPanelExited);
Bind(m_tpControlPanelGrid, x => x.PointerCaptureLost += OnControlPanelCaptureLost, x => x.PointerCaptureLost -= OnControlPanelCaptureLost);
......@@ -1249,5 +1251,460 @@ namespace Windows.UI.Xaml.Controls
return false;
}
private void OnSizeChanged(object sender, SizeChangedEventArgs e) // todo: maybe adjust event source
{
if (m_transportControlsEnabled)
{
SetMeasureCommandBar();
#if !HAS_UNO
// If error is showing, may need to switch between long / short / shortest form
IFC(UpdateErrorUI());
IFC(UpdateVisualState());
#endif
}
#if !HAS_UNO
// This is arise when clicks the exit fullscreen screen on the title bar, then reset back from the full window
if (m_isFullWindow && m_isFullScreen)
{
ctl::ComPtr<wuv::IApplicationView3> spAppView3;
BOOLEAN fullscreenmode = FALSE;
IFC(GetFullScreenView(&spAppView3));
if (spAppView3)
{
IFC(spAppView3->get_IsFullScreenMode(&fullscreenmode));
}
if (!fullscreenmode)
{
if (!m_isFullScreenPending) // if true means still we are not under fullscreen, exit through titlebar doesn't occur still
{
if (!m_isMiniView)
{
IFC(OnFullWindowClick());
}
else
{
// While switching from Fullscreen to MiniView, just update the fullscren states.
IFC(UpdateFullWindowUI());
m_isFullScreen = FALSE;
}
}
}
else
{
// m_isFullScreenPending Complete.
m_isFullScreenPending = FALSE;
// Find out if the API is available (currently behind a velocity key)
ctl::ComPtr<wf::Metadata::IApiInformationStatics> apiInformationStatics;
IFC(ctl::GetActivationFactory(
wrl_wrappers::HStringReference(RuntimeClass_Windows_Foundation_Metadata_ApiInformation).Get(),
&apiInformationStatics));
// we are in full screen, so check for spanning mode
uint32_t regionCount = 0;
boolean isPresent = false;
IFC(apiInformationStatics->IsMethodPresent(
wrl_wrappers::HStringReference(L"Windows.UI.ViewManagement.ApplicationView").Get(),
wrl_wrappers::HStringReference(L"GetDisplayRegions").Get(),
&isPresent));
if (isPresent)
{
// Get regions for current view
ctl::ComPtr<wuv::IApplicationViewStatics2> applicationViewStatics;
IFC(ctl::GetActivationFactory(wrl_wrappers::HStringReference(
RuntimeClass_Windows_UI_ViewManagement_ApplicationView)
.Get(),
&applicationViewStatics));
ctl::ComPtr<wuv::IApplicationView> applicationView;
// Get Display Regions doesn't work on Win32 Apps, because there is no
// application view. For the time being, just don't return an empty vector
// when running in an unsupported mode.
if (SUCCEEDED(applicationViewStatics->GetForCurrentView(&applicationView)))
{
ctl::ComPtr<wuv::IApplicationView9> applicationView9;
IFC(applicationView.As(&applicationView9));
HRESULT hrGetForCurrentView;
ctl::ComPtr<wfc::IVectorView<wuwm::DisplayRegion*>> regions;
hrGetForCurrentView = applicationView9->GetDisplayRegions(&regions);
if (FAILED(hrGetForCurrentView))
{
// bug 14084372: APIs currently return a failure when there is only one display region.
return S_OK;
}
IFC(regions->get_Size(&regionCount));
}
}
if (regionCount > 1 &&
!m_isCompact &&
!m_isSpanningCompactEnabled)
{
put_IsCompact(true);
m_isSpanningCompactEnabled = TRUE;
}
}
}
else
{
// not fullscreen, in spanning compact mode is enabled, reset it
if (m_isSpanningCompactEnabled)
{
put_IsCompact(false);
m_isSpanningCompactEnabled = FALSE;
}
}
Cleanup:
#endif
}
private void SetMeasureCommandBar()
{
_ = this.Dispatcher.RunAsync(CoreDispatcherPriority.Normal, MeasureCommandBar);
}
/// <summary>
/// Measure CommandBar to fit the buttons in given width.
/// </summary>
private void MeasureCommandBar()
{
if (m_tpCommandBar is { })
{
ResetMargins();
var availableSize = this.ActualWidth;
m_tpCommandBar.Measure(new Size(double.PositiveInfinity, double.PositiveInfinity));
var desiredSize = m_tpCommandBar.DesiredSize;
if (availableSize < desiredSize.Width)
{
Dropout(availableSize, desiredSize);
}
else
{
Expand(availableSize, desiredSize);
AddMarginsBetweenGroups();
}
#if !HAS_UNO
// Remove this code to disable and hide only after Deliverable 19012797: Fullscreen media works in ApplicationWindow and Win32 XAML Islands is complete
// since Expand or Dropout can make the full window button visible again, this code is used to hide it again
CContentRoot* contentRoot = VisualTree::GetContentRootForElement(GetHandle());
if (contentRoot->GetType() == CContentRoot::Type::XamlIsland)
{
IFC(m_tpFullWindowButton.Cast<ButtonBase>()->put_Visibility(xaml::Visibility_Collapsed));
}
#endif
}
}
private void AddMarginsBetweenGroups()
{
var isCompact = IsCompact;
if ((m_tpLeftAppBarSeparator is { } || m_tpRightAppBarSeparator is { }) && !isCompact)
{
double leftWidth = 0;
double middleWidth = 0;
double rightWidth = 0;
bool leftComplete = false;
bool rightStart = false;
var totalWidth = this.ActualWidth;
if (m_tpCommandBar is null)
{
return;
}
var spPrimaryCommandObsVec = m_tpCommandBar.PrimaryCommands;
var spPrimaryButtons = spPrimaryCommandObsVec.ToArray();
for (int i = 0; i < spPrimaryButtons.Length; i++)
{
var spCommandElement = spPrimaryButtons[i];
if (spCommandElement as UIElement is { } spElement)
{
if (spElement.Visibility == Visibility.Visible)
{
if (spElement == m_tpLeftAppBarSeparator)
{
leftComplete = true;
continue;
}
if (spElement == m_tpRightAppBarSeparator)
{
rightStart = true;
continue;
}
}
if (spElement as FrameworkElement is { } spFrmElement)
{
var width = spFrmElement.Width;
if (!leftComplete)
{
leftWidth = leftWidth + width;
}
else if (!rightStart)
{
middleWidth = middleWidth + width;
}
else
{
rightWidth = rightWidth + width;
}
}
}
}
var cmdMargin = new Thickness(0);
// Consider control panel margin for xbox case
if (m_tpControlPanelGrid is { })
{
m_tpControlPanelGrid.Margin(cmdMargin);
}
double leftGap = (totalWidth / 2) - (cmdMargin.Left + leftWidth + (middleWidth / 2));
double rightGap = (totalWidth / 2) - (cmdMargin.Right + rightWidth + (middleWidth / 2));
// If we get negative value, means they are not in equal balance
if (leftGap < 0 || rightGap < 0)
{
leftGap = rightGap = (totalWidth - (leftWidth + middleWidth + rightWidth)) / 2;
}
if (m_tpLeftAppBarSeparator is { })
{
var extraMargin = new Thickness(leftGap / 2, 0, leftGap / 2, 0);
m_tpLeftAppBarSeparator.Margin(extraMargin);
}
if (m_tpRightAppBarSeparator is { })
{
var extraMargin = new Thickness(rightGap / 2, 0, rightGap / 2, 0);
m_tpRightAppBarSeparator.Margin(extraMargin);
}
}
}
private void ResetMargins()
{
var zeroMargin = new Thickness(0);
if (m_tpLeftAppBarSeparator is { })
{
m_tpLeftAppBarSeparator.Margin = zeroMargin;
}
if (m_tpRightAppBarSeparator is { })
{
m_tpRightAppBarSeparator.Margin = zeroMargin;
}
}
private void Dropout(double availableSize, Size desiredSize)
{
if (m_tpCommandBar is null)
{
return;
}
var spPrimaryButtons = m_tpCommandBar.PrimaryCommands.ToArray();
var buttonsCount = spPrimaryButtons.Length;
var infiniteBounds = new Size(double.PositiveInfinity, double.PositiveInfinity);
while (availableSize < desiredSize.Width)
{
var lowestVisibleOrder = int.MaxValue;
int lowestElementIndex = 0;
for (int i = 0; i < buttonsCount; i++)
{
var spCommandElement = spPrimaryButtons[i];
if (spCommandElement as UIElement is { } spElement)
{
if (spElement.Visibility == Visibility.Visible)
{
var spOrder = MediaTransportControlsHelper.GetDropoutOrder(spElement);
if (spOrder is { } order && order > 0 && lowestVisibleOrder > order)
{
lowestVisibleOrder = order;
lowestElementIndex = i;
}
}
}
}
if (lowestVisibleOrder == int.MaxValue)
{
break;
}
else
{
var spCommandElement = spPrimaryButtons[lowestElementIndex];
if (spCommandElement as UIElement is { } spElement)
{
spElement.Visibility = Visibility.Collapsed;
}
m_tpCommandBar.Measure(infiniteBounds);
desiredSize = m_tpCommandBar.DesiredSize;
}
}
}
private void Expand(double availableSize, Size desiredSize)
{
if (m_tpCommandBar is null)
{
return;
}
var spPrimaryButtons = m_tpCommandBar.PrimaryCommands.ToArray();
var buttonsCount = spPrimaryButtons.Length;
var infiniteBounds = new Size(double.PositiveInfinity, double.PositiveInfinity);
while (availableSize > desiredSize.Width)
{
var highestCollapseOrder = -1;
int highestElementIndex = 0;
for (int i = 0; i < buttonsCount; i++)
{
var spCommandElement = spPrimaryButtons[i];
if (spCommandElement as UIElement is { } spElement)
{
if (spElement.Visibility == Visibility.Collapsed && !IsButtonCollapsedbySystem(spElement))
{
var spOrder = MediaTransportControlsHelper.GetDropoutOrder(spElement);
if (spOrder is { } order && order > highestCollapseOrder)
{
highestCollapseOrder = order;
highestElementIndex = i;
}
}
}
}
if (highestCollapseOrder == -1)
{
break;
}
else
{
var spCommandElement = spPrimaryButtons[highestElementIndex];
// Make sure it should be complete space but not partial space to fit the button
if (spCommandElement as UIElement is { } spElement &&
spElement as FrameworkElement is { } frameworkElement &&
availableSize >= (desiredSize.Width + frameworkElement.Width))
{
spElement.Visibility = Visibility.Visible;
m_tpCommandBar.Measure(infiniteBounds);
desiredSize = m_tpCommandBar.DesiredSize;
}
else
{
break;
}
}
}
}
/// <summary>
/// Determine whether button collapsed by system.
/// </summary>
private bool IsButtonCollapsedbySystem(UIElement element)
{
//In case of Compact mode this button should collapse
if (element == m_tpPlayPauseButton && IsCompact)
{
return true;
}
//In case of the Missing Audio tracks this button should collapse
else if (element == m_tpTHAudioTrackSelectionButton
#if !HAS_UNO
&& IsCompact) {&& !m_hasMultipleAudioStreams
#endif
)
{
return true;
}
//In case of the Missing CC tracks this button should collapse
else if (element == m_tpCCSelectionButton
#if !HAS_UNO
&& !m_hasCCTracks
#endif
)
{
return true;
}
//Remaining check whether thru APIs Button is collapsed.
else if (element == m_tpPlaybackRateButton)
{
return !IsPlaybackRateButtonVisible;
}
else if (element == m_tpTHVolumeButton)
{
return !IsVolumeButtonVisible;
}
else if (element == m_tpFullWindowButton)
{
return !IsFullWindowButtonVisible;
}
else if (element == m_tpZoomButton)
{
return !IsZoomButtonVisible;
}
else if (element == m_tpFastForwardButton)
{
return !IsFastForwardButtonVisible;
}
else if (element == m_tpFastRewindButton)
{
return !IsFastRewindButtonVisible;
}
else if (element == m_tpStopButton)
{
return !IsStopButtonVisible;
}
// In case of the Cast doesn't supports this button should always collapse
else if (element == m_tpCastButton
#if !HAS_UNO
&& !m_isCastSupports
#endif
)
{
return true;
}
else if (element == m_tpSkipForwardButton)
{
return !IsSkipForwardButtonVisible;
}
else if (element == m_tpSkipBackwardButton)
{
return !IsSkipBackwardButtonVisible;
}
else if (element == m_tpNextTrackButton)
{
return !IsNextTrackButtonVisible;
}
else if (element == m_tpPreviousTrackButton)
{
return !IsPreviousTrackButtonVisible;
}
else if (element == m_tpRepeatButton)
{
return !IsRepeatButtonVisible;
}
else if (element == m_tpCompactOverlayButton)
{
return !IsCompactOverlayButtonVisible;
}
return false;
}
}
}
#if __ANDROID__ || __IOS__ || __MACOS__ || __WASM__
namespace Windows.UI.Xaml.Controls
{
public partial class MediaTransportControlsHelper
......@@ -21,4 +20,3 @@ namespace Windows.UI.Xaml.Controls
}
}
}
#endif
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册