SEBWIN-303: Implemented audio control logic.

This commit is contained in:
dbuechel 2019-08-15 16:16:51 +02:00
parent cc6710cedf
commit 4381be2647
10 changed files with 107 additions and 6 deletions

View file

@ -109,7 +109,9 @@ namespace SafeExamBrowser.Contracts.I18n
Shell_QuitButton,
SystemControl_AudioDeviceInfo,
SystemControl_AudioDeviceInfoMuted,
SystemControl_AudioDeviceMuteTooltip,
SystemControl_AudioDeviceNotFound,
SystemControl_AudioDeviceUnmuteTooltip,
SystemControl_BatteryCharged,
SystemControl_BatteryCharging,
SystemControl_BatteryChargeCriticalWarning,

View file

@ -208,6 +208,8 @@
<Compile Include="UserInterface\IProgressIndicator.cs" />
<Compile Include="UserInterface\Shell\Events\ActivatorEventHandler.cs" />
<Compile Include="UserInterface\Shell\Events\ApplicationControlClickedEventHandler.cs" />
<Compile Include="UserInterface\Shell\Events\AudioMuteRequestedEventHandler.cs" />
<Compile Include="UserInterface\Shell\Events\AudioVolumeSelectedEventHandler.cs" />
<Compile Include="UserInterface\Shell\Events\KeyboardLayoutSelectedEventHandler.cs" />
<Compile Include="UserInterface\Shell\Events\NotificationControlClickedEventHandler.cs" />
<Compile Include="UserInterface\Shell\IActionCenter.cs" />

View file

@ -0,0 +1,15 @@
/*
* Copyright (c) 2019 ETH Zürich, Educational Development and Technology (LET)
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/
namespace SafeExamBrowser.Contracts.UserInterface.Shell.Events
{
/// <summary>
/// Indicates that the user would like to change the audio mute status to the given value.
/// </summary>
public delegate void AudioMuteRequestedEventHandler(bool mute);
}

View file

@ -0,0 +1,16 @@
/*
* Copyright (c) 2019 ETH Zürich, Educational Development and Technology (LET)
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/
namespace SafeExamBrowser.Contracts.UserInterface.Shell.Events
{
/// <summary>
/// Indicates that the user would like to set the audio volume to the given value, where <c>0.0</c> is the lowest and <c>1.0</c> the highest
/// possible value.
/// </summary>
public delegate void AudioVolumeSelectedEventHandler(double volume);
}

View file

@ -6,6 +6,8 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/
using SafeExamBrowser.Contracts.UserInterface.Shell.Events;
namespace SafeExamBrowser.Contracts.UserInterface.Shell
{
/// <summary>
@ -32,5 +34,15 @@ namespace SafeExamBrowser.Contracts.UserInterface.Shell
/// Shows the current audio output volume, where <c>0.0</c> is the lowest and <c>1.0</c> the highest possible value.
/// </summary>
double OutputDeviceVolume { set; }
/// <summary>
/// Event fired when the user requests to mute the current output device.
/// </summary>
event AudioMuteRequestedEventHandler MuteRequested;
/// <summary>
/// Event fired when the user requests to set the volume of the current output device.
/// </summary>
event AudioVolumeSelectedEventHandler VolumeSelected;
}
}

View file

@ -285,9 +285,15 @@
<Entry key="SystemControl_AudioDeviceInfoMuted">
%%NAME%%: Muted
</Entry>
<Entry key="SystemControl_AudioDeviceMuteTooltip">
Click to mute audio
</Entry>
<Entry key="SystemControl_AudioDeviceNotFound">
No audio device found
</Entry>
<Entry key="SystemControl_AudioDeviceUnmuteTooltip">
Click to unmute audio
</Entry>
<Entry key="SystemControl_BatteryCharging">
Plugged in, charging... (%%CHARGE%%%)
</Entry>

View file

@ -49,6 +49,9 @@ namespace SafeExamBrowser.SystemComponents
public void Register(ISystemAudioControl control)
{
control.MuteRequested += Control_MuteRequested;
control.VolumeSelected += Control_VolumeSelected;
lock (@lock)
{
controls.Add(control);
@ -108,6 +111,8 @@ namespace SafeExamBrowser.SystemComponents
{
var info = BuildInfoText(data.MasterVolume, data.Muted);
logger.Debug($"Detected audio device change: Volume {data.MasterVolume * 100}, {(data.Muted ? "muted" : "unmuted")}");
foreach (var control in controls)
{
control.OutputDeviceMuted = data.Muted;
@ -117,6 +122,16 @@ namespace SafeExamBrowser.SystemComponents
}
}
private void Control_MuteRequested(bool mute)
{
audioDevice.AudioEndpointVolume.Mute = mute;
}
private void Control_VolumeSelected(double volume)
{
audioDevice.AudioEndpointVolume.MasterVolumeLevelScalar = (float) volume;
}
private void UpdateControls()
{
lock (@lock)
@ -154,7 +169,7 @@ namespace SafeExamBrowser.SystemComponents
var info = text.Get(muted ? TextKey.SystemControl_AudioDeviceInfoMuted : TextKey.SystemControl_AudioDeviceInfo);
info = info.Replace("%%NAME%%", audioDeviceShortName);
info = info.Replace("%%VOLUME%%", Convert.ToString(volume * 100));
info = info.Replace("%%VOLUME%%", Convert.ToString(Math.Round(volume * 100)));
return info;
}

View file

@ -21,11 +21,13 @@
<StackPanel Orientation="Vertical">
<TextBlock x:Name="AudioDeviceName" Margin="5" TextAlignment="Center" />
<StackPanel Orientation="Horizontal" Height="40">
<Button x:Name="Mute" Background="Transparent" Padding="5" Template="{StaticResource TaskbarButton}" Width="40">
<Button x:Name="MuteButton" Background="Transparent" Padding="5" Template="{StaticResource TaskbarButton}" Width="40">
<ContentControl x:Name="PopupIcon" />
</Button>
<Slider x:Name="Volume" Grid.Column="1" Orientation="Horizontal" TickFrequency="1" IsSnapToTickEnabled="True" Maximum="100" VerticalAlignment="Center" Width="250" />
<TextBlock Grid.Column="2" FontWeight="DemiBold" FontSize="16" Text="{Binding ElementName=Volume, Path=Value}" TextAlignment="Center" VerticalAlignment="Center" Width="40" />
<Slider x:Name="Volume" Grid.Column="1" Orientation="Horizontal" TickFrequency="1" Maximum="100" IsSnapToTickEnabled="True"
IsMoveToPointEnabled="True" VerticalAlignment="Center" Width="250" Thumb.DragStarted="Volume_DragStarted" Thumb.DragCompleted="Volume_DragCompleted" />
<TextBlock Grid.Column="2" FontWeight="DemiBold" FontSize="16" Text="{Binding ElementName=Volume, Path=Value}"
TextAlignment="Center" VerticalAlignment="Center" Width="40" />
</StackPanel>
</StackPanel>
</Border>

View file

@ -10,20 +10,29 @@ using System;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Controls.Primitives;
using System.Windows.Media;
using SafeExamBrowser.Contracts.I18n;
using SafeExamBrowser.Contracts.UserInterface.Shell;
using SafeExamBrowser.Contracts.UserInterface.Shell.Events;
using SafeExamBrowser.UserInterface.Shared.Utilities;
namespace SafeExamBrowser.UserInterface.Desktop.Controls
{
public partial class TaskbarAudioControl : UserControl, ISystemAudioControl
{
private readonly IText text;
private bool muted;
private XamlIconResource MutedIcon;
private XamlIconResource NoDeviceIcon;
public TaskbarAudioControl()
public event AudioMuteRequestedEventHandler MuteRequested;
public event AudioVolumeSelectedEventHandler VolumeSelected;
public TaskbarAudioControl(IText text)
{
this.text = text;
InitializeComponent();
InitializeAudioControl();
}
@ -54,11 +63,13 @@ namespace SafeExamBrowser.UserInterface.Desktop.Controls
if (value)
{
MuteButton.ToolTip = text.Get(TextKey.SystemControl_AudioDeviceUnmuteTooltip);
PopupIcon.Content = IconResourceLoader.Load(MutedIcon);
TaskbarIcon.Content = IconResourceLoader.Load(MutedIcon);
}
else
{
MuteButton.ToolTip = text.Get(TextKey.SystemControl_AudioDeviceMuteTooltip);
TaskbarIcon.Content = LoadIcon(Volume.Value / 100);
}
});
@ -79,7 +90,9 @@ namespace SafeExamBrowser.UserInterface.Desktop.Controls
{
Dispatcher.InvokeAsync(() =>
{
Volume.ValueChanged -= Volume_ValueChanged;
Volume.Value = Math.Round(value * 100);
Volume.ValueChanged += Volume_ValueChanged;
if (!muted)
{
@ -106,9 +119,11 @@ namespace SafeExamBrowser.UserInterface.Desktop.Controls
Button.Click += (o, args) => Popup.IsOpen = !Popup.IsOpen;
Button.MouseLeave += (o, args) => Task.Delay(250).ContinueWith(_ => Dispatcher.Invoke(() => Popup.IsOpen = Popup.IsMouseOver));
MuteButton.Click += (o, args) => MuteRequested?.Invoke(!muted);
MutedIcon = new XamlIconResource(new Uri("pack://application:,,,/SafeExamBrowser.UserInterface.Desktop;component/Images/AudioMuted.xaml"));
NoDeviceIcon = new XamlIconResource(new Uri("pack://application:,,,/SafeExamBrowser.UserInterface.Desktop;component/Images/AudioNoDevice.xaml"));
Popup.MouseLeave += (o, args) => Task.Delay(250).ContinueWith(_ => Dispatcher.Invoke(() => Popup.IsOpen = IsMouseOver));
Volume.ValueChanged += Volume_ValueChanged;
Popup.Opened += (o, args) =>
{
@ -123,6 +138,22 @@ namespace SafeExamBrowser.UserInterface.Desktop.Controls
};
}
private void Volume_DragStarted(object sender, DragStartedEventArgs e)
{
Volume.ValueChanged -= Volume_ValueChanged;
}
private void Volume_DragCompleted(object sender, DragCompletedEventArgs e)
{
VolumeSelected?.Invoke(Volume.Value / 100);
Volume.ValueChanged += Volume_ValueChanged;
}
private void Volume_ValueChanged(object sender, RoutedPropertyChangedEventArgs<double> e)
{
VolumeSelected?.Invoke(Volume.Value / 100);
}
private UIElement LoadIcon(double volume)
{
var icon = volume > 0.66 ? "100" : (volume > 0.33 ? "66" : "33");

View file

@ -61,7 +61,7 @@ namespace SafeExamBrowser.UserInterface.Desktop
//}
//else
{
return new TaskbarAudioControl();
return new TaskbarAudioControl(text);
}
}