Skip to content
This repository has been archived by the owner on Dec 20, 2023. It is now read-only.

Commit

Permalink
支持手势操作控制音量和进度 (#544)
Browse files Browse the repository at this point in the history
  • Loading branch information
Richasy authored Oct 28, 2021
1 parent 3ff24cd commit ac190ea
Show file tree
Hide file tree
Showing 6 changed files with 252 additions and 22 deletions.
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
// Copyright (c) Richasy. All rights reserved.

using System.Collections.Generic;
using Richasy.Bili.Models.Enums.App;
using Richasy.Bili.ViewModels.Uwp;
using Richasy.Bili.ViewModels.Uwp.Common;
using Windows.Foundation;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;
using Windows.UI.Xaml.Controls.Primitives;
Expand Down Expand Up @@ -52,11 +54,14 @@ public partial class BiliPlayerTransportControls
private const string BackToDefaultButtonName = "BackToDefaultButton";
private const string ContinuePreviousViewButtonName = "ContinuePreviousViewButton";
private const string LiveRefreshButtonName = "LiveRefreshButton";
private const string TempMessageContaienrName = "TempMessageContainer";
private const string TempMessageBlockName = "TempMessageBlock";

private readonly Dictionary<int, List<DanmakuModel>> _danmakuDictionary;

private DispatcherTimer _danmakuTimer;
private DispatcherTimer _cursorTimer;
private DispatcherTimer _normalTimer;
private DanmakuView _danmakuView;
private ToggleButton _fullWindowPlayModeButton;
private ToggleButton _fullScreenPlayModeButton;
Expand All @@ -76,8 +81,20 @@ public partial class BiliPlayerTransportControls
private Button _continuePreviousViewButton;
private Button _liveRefreshButton;
private TextBlock _subtitleBlock;
private Grid _tempMessageContainer;
private TextBlock _tempMessageBlock;
private int _segmentIndex;
private double _cursorStayTime;
private double _tempMessageHoldSeconds;

private Point _manipulationStartPoint = new Point(0, 0);
private double _manipulationDeltaX = 0d;
private double _manipulationDeltaY = 0d;
private double _manipulationProgress = 0d;
private double _manipulationVolume = 0d;
private double _manipulationUnitLength = 0d;
private bool _manipulationBeforeIsPlay = false;
private PlayerManipulationType _manipulationType = PlayerManipulationType.None;

/// <summary>
/// 实例.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,13 @@
using System.Linq;
using Bilibili.Community.Service.Dm.V1;
using Richasy.Bili.App.Resources.Extension;
using Richasy.Bili.Locator.Uwp;
using Richasy.Bili.Models.BiliBili;
using Richasy.Bili.Models.Enums;
using Richasy.Bili.Models.Enums.App;
using Richasy.Bili.Toolkit.Interfaces;
using Richasy.Bili.ViewModels.Uwp;
using Windows.Foundation;
using Windows.Media.Playback;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;
Expand All @@ -36,6 +39,9 @@ public BiliPlayerTransportControls()
SizeChanged += OnSizeChanged;
InitializeDanmakuTimer();
InitializeCursorTimer();
InitializeNormalTimer();

_normalTimer.Start();
}

/// <summary>
Expand Down Expand Up @@ -75,12 +81,18 @@ protected override void OnApplyTemplate()
_continuePreviousViewButton = GetTemplateChild(ContinuePreviousViewButtonName) as Button;
_liveRefreshButton = GetTemplateChild(LiveRefreshButtonName) as Button;
_subtitleBlock = GetTemplateChild(SubtitleBlockName) as TextBlock;
_tempMessageContainer = GetTemplateChild(TempMessageContaienrName) as Grid;
_tempMessageBlock = GetTemplateChild(TempMessageBlockName) as TextBlock;

_fullWindowPlayModeButton.Click += OnPlayModeButtonClick;
_fullScreenPlayModeButton.Click += OnPlayModeButtonClick;
_compactOverlayPlayModeButton.Click += OnPlayModeButtonClick;
_interactionControl.ManipulationMode = ManipulationModes.TranslateX | ManipulationModes.TranslateY;
_interactionControl.Tapped += OnInteractionControlTapped;
_interactionControl.DoubleTapped += OnInteractionControlDoubleTapped;
_interactionControl.ManipulationStarted += OnInteractionControlManipulationStarted;
_interactionControl.ManipulationDelta += OnInteractionControlManipulationDelta;
_interactionControl.ManipulationCompleted += OnInteractionControlManipulationCompleted;
_backButton.Click += OnBackButtonClick;
_danmakuBarVisibilityButton.Click += OnDanmakuBarVisibilityButtonClick;
_homeButton.Click += OnHomeButtonClickAsync;
Expand Down Expand Up @@ -465,6 +477,16 @@ private void InitializeCursorTimer()
}
}

private void InitializeNormalTimer()
{
if (_normalTimer == null)
{
_normalTimer = new DispatcherTimer();
_normalTimer.Interval = TimeSpan.FromSeconds(0.5);
_normalTimer.Tick += OnNormalTimerTick;
}
}

private void InitializeDanmaku(List<DanmakuElem> elements)
{
var list = new List<DanmakuModel>();
Expand Down Expand Up @@ -663,5 +685,122 @@ private void OnCursorTimerTickAsync(object sender, object e)
_cursorStayTime = 0;
}
}

private void OnNormalTimerTick(object sender, object e)
{
if (_tempMessageHoldSeconds >= 2)
{
HideTempMessage();
}
else if (_tempMessageHoldSeconds != -1)
{
_tempMessageHoldSeconds += 0.5;
}
}

private void OnInteractionControlManipulationCompleted(object sender, ManipulationCompletedRoutedEventArgs e)
{
_manipulationVolume = 0;
_manipulationProgress = 0;
_manipulationDeltaX = 0;
_manipulationDeltaY = 0;
_manipulationStartPoint = new Point(0, 0);
_manipulationType = PlayerManipulationType.None;

if (_manipulationBeforeIsPlay)
{
ViewModel.BiliPlayer.MediaPlayer.Play();
}

_manipulationBeforeIsPlay = false;
}

private void OnInteractionControlManipulationDelta(object sender, ManipulationDeltaRoutedEventArgs e)
{
if (ViewModel.PlayerStatus != PlayerStatus.Playing && ViewModel.PlayerStatus != PlayerStatus.Pause)
{
return;
}

_manipulationDeltaX += e.Delta.Translation.X;
_manipulationDeltaY -= e.Delta.Translation.Y;
if (Math.Abs(_manipulationDeltaX) > 15 || Math.Abs(_manipulationDeltaY) > 15)
{
var resourceToolkit = ServiceLocator.Instance.GetService<IResourceToolkit>();
if (_manipulationType == PlayerManipulationType.None)
{
var isVolume = Math.Abs(_manipulationDeltaY) > Math.Abs(_manipulationDeltaX);
_manipulationType = isVolume ? PlayerManipulationType.Volume : PlayerManipulationType.Progress;
if (!isVolume)
{
ViewModel.BiliPlayer.MediaPlayer.Pause();
}
}

if (_manipulationType == PlayerManipulationType.Volume)
{
var volume = _manipulationVolume + (_manipulationDeltaY / 2.0);
if (volume > 100)
{
volume = 100;
}
else if (volume < 0)
{
volume = 0;
}

ShowTempMessage($"{resourceToolkit.GetLocaleString(LanguageNames.CurrentVolume)}: {Math.Round(volume)}");
ViewModel.BiliPlayer.MediaPlayer.Volume = volume / 100.0;
if (volume == 0)
{
ShowTempMessage(resourceToolkit.GetLocaleString(LanguageNames.Muted));
}
}
else
{
var progress = _manipulationProgress + (_manipulationDeltaX * _manipulationUnitLength);
if (progress > ViewModel.BiliPlayer.MediaPlayer.PlaybackSession.NaturalDuration.TotalSeconds)
{
progress = ViewModel.BiliPlayer.MediaPlayer.PlaybackSession.NaturalDuration.TotalSeconds;
}
else if (progress < 0)
{
progress = 0;
}

ShowTempMessage($"{resourceToolkit.GetLocaleString(LanguageNames.CurrentProgress)}: {TimeSpan.FromSeconds(progress):g}");
ViewModel.BiliPlayer.MediaPlayer.PlaybackSession.Position = TimeSpan.FromSeconds(progress);
}
}
}

private void OnInteractionControlManipulationStarted(object sender, ManipulationStartedRoutedEventArgs e)
{
var player = ViewModel.BiliPlayer.MediaPlayer;
_manipulationStartPoint = e.Position;
_manipulationProgress = player.PlaybackSession.Position.TotalSeconds;
_manipulationVolume = player.Volume * 100.0;
_manipulationBeforeIsPlay = ViewModel.PlayerStatus == PlayerStatus.Playing;
if (player.PlaybackSession != null && player.PlaybackSession.NaturalDuration.TotalSeconds > 0)
{
// 获取单位像素对应的时长
var unit = player.PlaybackSession.NaturalDuration.TotalSeconds / this.ActualWidth;
_manipulationUnitLength = unit / 1.5;
}
}

private void ShowTempMessage(string message)
{
_tempMessageContainer.Visibility = Visibility.Visible;
_tempMessageBlock.Text = message;
_tempMessageHoldSeconds = 0;
}

private void HideTempMessage()
{
_tempMessageContainer.Visibility = Visibility.Collapsed;
_tempMessageBlock.Text = string.Empty;
_tempMessageHoldSeconds = -1;
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,12 @@
From="50"
To="0.5"
Duration="0:0:0.2" />
<DoubleAnimation
Storyboard.TargetName="TempMessageVertical"
Storyboard.TargetProperty="Y"
From="50"
To="0.5"
Duration="0:0:0.2" />
<DoubleAnimation
Storyboard.TargetName="ChoiceVertical"
Storyboard.TargetProperty="Y"
Expand Down Expand Up @@ -134,6 +140,12 @@
From="0.5"
To="80"
Duration="0:0:0.4" />
<DoubleAnimation
Storyboard.TargetName="TempMessageVertical"
Storyboard.TargetProperty="Y"
From="0.5"
To="80"
Duration="0:0:0.4" />
<DoubleAnimation
Storyboard.TargetName="ChoiceVertical"
Storyboard.TargetProperty="Y"
Expand Down Expand Up @@ -345,28 +357,53 @@
<local:InteractionChoicePanel x:Name="ChoiceContainer" />
</Grid>

<Border x:Name="PreviousViewInformer_Border">
<muxc:InfoBar
x:Name="PreviousViewInformer"
HorizontalAlignment="Right"
Background="{ThemeResource MediaTransportControlsPanelBackground}"
BorderBrush="{ThemeResource MediaTransportControlsBorderBrush}"
BorderThickness="{ThemeResource MediaTransportControlsBorderThickness}"
CornerRadius="{TemplateBinding CornerRadius}"
IsClosable="True"
IsIconVisible="False"
IsOpen="{Binding RelativeSource={RelativeSource Mode=TemplatedParent}, Path=ViewModel.IsShowHistory, Mode=TwoWay}"
Message="{Binding RelativeSource={RelativeSource Mode=TemplatedParent}, Path=ViewModel.HistoryText}"
RenderTransformOrigin="0.5,0.5">
<muxc:InfoBar.ActionButton>
<Button
x:Name="ContinuePreviousViewButton"
MinWidth="120"
Click="JumpToHistoryAsync"
Content="{loc:LocaleLocator Name=ContinuePreviousView}" />
</muxc:InfoBar.ActionButton>
</muxc:InfoBar>
</Border>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>
<Grid
x:Name="TempMessageContainer"
HorizontalAlignment="Left"
Visibility="Collapsed">
<Grid.RenderTransform>
<TranslateTransform x:Name="TempMessageVertical" />
</Grid.RenderTransform>
<Grid
x:Name="TempMessageGrid"
Margin="24,0"
Padding="16,8"
Background="{ThemeResource MediaTransportControlsPanelBackground}"
CornerRadius="{StaticResource ControlCornerRadius}">
<TextBlock
x:Name="TempMessageBlock"
MaxWidth="320"
TextWrapping="Wrap" />
</Grid>
</Grid>
<Border x:Name="PreviousViewInformer_Border" Grid.Column="1">
<muxc:InfoBar
x:Name="PreviousViewInformer"
Background="{ThemeResource MediaTransportControlsPanelBackground}"
BorderBrush="{ThemeResource MediaTransportControlsBorderBrush}"
BorderThickness="{ThemeResource MediaTransportControlsBorderThickness}"
CornerRadius="{TemplateBinding CornerRadius}"
IsClosable="True"
IsIconVisible="False"
IsOpen="{Binding RelativeSource={RelativeSource Mode=TemplatedParent}, Path=ViewModel.IsShowHistory, Mode=TwoWay}"
Message="{Binding RelativeSource={RelativeSource Mode=TemplatedParent}, Path=ViewModel.HistoryText}"
RenderTransformOrigin="0.5,0.5">
<muxc:InfoBar.ActionButton>
<Button
x:Name="ContinuePreviousViewButton"
MinWidth="120"
Click="JumpToHistoryAsync"
Content="{loc:LocaleLocator Name=ContinuePreviousView}" />
</muxc:InfoBar.ActionButton>
</muxc:InfoBar>
</Border>
</Grid>


<Border x:Name="ControlPanel_ControlPanelVisibilityStates_Border" MaxWidth="820">
<Grid
Expand Down
9 changes: 9 additions & 0 deletions src/App/Resources/Strings/zh-CN/Resources.resw
Original file line number Diff line number Diff line change
Expand Up @@ -285,6 +285,12 @@
<data name="Copied" xml:space="preserve">
<value>已复制</value>
</data>
<data name="CurrentProgress" xml:space="preserve">
<value>当前进度</value>
</data>
<data name="CurrentVolume" xml:space="preserve">
<value>当前音量</value>
</data>
<data name="Danmaku" xml:space="preserve">
<value>弹幕</value>
</data>
Expand Down Expand Up @@ -632,6 +638,9 @@
<data name="MTCControlModeDescription" xml:space="preserve">
<value>选择媒体传输控件(包含播放进度的播放控制栏)显隐的方式</value>
</data>
<data name="Muted" xml:space="preserve">
<value>已静音</value>
</data>
<data name="MyFavorite" xml:space="preserve">
<value>我的收藏</value>
</data>
Expand Down
3 changes: 3 additions & 0 deletions src/Models/Models.Enums/App/LanguageNames.cs
Original file line number Diff line number Diff line change
Expand Up @@ -378,6 +378,9 @@ public enum LanguageNames
DisableP2PCdnDescription,
ContinuousPlay,
ContinuousPlayDescription,
CurrentVolume,
CurrentProgress,
Muted,
#pragma warning restore SA1602 // Enumeration items should be documented
}
}
25 changes: 25 additions & 0 deletions src/Models/Models.Enums/App/PlayerManipulationType.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
// Copyright (c) Richasy. All rights reserved.

namespace Richasy.Bili.Models.Enums.App
{
/// <summary>
/// 播放器手势操作类型.
/// </summary>
public enum PlayerManipulationType
{
/// <summary>
/// 未指定.
/// </summary>
None,

/// <summary>
/// 进度.
/// </summary>
Progress,

/// <summary>
/// 音量.
/// </summary>
Volume,
}
}

0 comments on commit ac190ea

Please sign in to comment.