SEBWIN-303: Implemented audio control for action center.
This commit is contained in:
parent
758b61084a
commit
106651fc2d
13 changed files with 302 additions and 16 deletions
|
@ -289,7 +289,7 @@
|
|||
Click to mute audio
|
||||
</Entry>
|
||||
<Entry key="SystemControl_AudioDeviceNotFound">
|
||||
No audio device found
|
||||
No active audio device found
|
||||
</Entry>
|
||||
<Entry key="SystemControl_AudioDeviceUnmuteTooltip">
|
||||
Click to unmute audio
|
||||
|
|
|
@ -175,11 +175,11 @@ namespace SafeExamBrowser.SystemComponents
|
|||
{
|
||||
try
|
||||
{
|
||||
var info = BuildInfoText(audioDevice.AudioEndpointVolume.MasterVolumeLevelScalar, audioDevice.AudioEndpointVolume.Mute);
|
||||
|
||||
foreach (var control in controls)
|
||||
if (audioDevice != default(MMDevice))
|
||||
{
|
||||
if (audioDevice != default(MMDevice))
|
||||
var info = BuildInfoText(audioDevice.AudioEndpointVolume.MasterVolumeLevelScalar, audioDevice.AudioEndpointVolume.Mute);
|
||||
|
||||
foreach (var control in controls)
|
||||
{
|
||||
control.HasOutputDevice = true;
|
||||
control.OutputDeviceMuted = audioDevice.AudioEndpointVolume.Mute;
|
||||
|
@ -187,7 +187,10 @@ namespace SafeExamBrowser.SystemComponents
|
|||
control.OutputDeviceVolume = audioDevice.AudioEndpointVolume.MasterVolumeLevelScalar;
|
||||
control.SetInformation(info);
|
||||
}
|
||||
else
|
||||
}
|
||||
else
|
||||
{
|
||||
foreach (var control in controls)
|
||||
{
|
||||
control.HasOutputDevice = false;
|
||||
control.SetInformation(text.Get(TextKey.SystemControl_AudioDeviceNotFound));
|
||||
|
|
|
@ -0,0 +1,45 @@
|
|||
<UserControl x:Class="SafeExamBrowser.UserInterface.Desktop.Controls.ActionCenterAudioControl"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:local="clr-namespace:SafeExamBrowser.UserInterface.Desktop.Controls"
|
||||
mc:Ignorable="d" d:DesignHeight="100" d:DesignWidth="125">
|
||||
<UserControl.Resources>
|
||||
<ResourceDictionary>
|
||||
<ResourceDictionary.MergedDictionaries>
|
||||
<ResourceDictionary Source="../Templates/Buttons.xaml" />
|
||||
<ResourceDictionary Source="../Templates/Colors.xaml" />
|
||||
<ResourceDictionary Source="../Templates/ScrollViewers.xaml" />
|
||||
</ResourceDictionary.MergedDictionaries>
|
||||
</ResourceDictionary>
|
||||
</UserControl.Resources>
|
||||
<Grid x:Name="Grid" Background="{StaticResource ActionCenterDarkBrush}" Height="64" Margin="2">
|
||||
<Popup x:Name="Popup" IsOpen="False" Placement="Top" PlacementTarget="{Binding ElementName=Button}">
|
||||
<Border Background="Gray">
|
||||
<StackPanel Orientation="Vertical">
|
||||
<TextBlock x:Name="AudioDeviceName" Foreground="White" Margin="5" TextAlignment="Center" />
|
||||
<StackPanel Orientation="Horizontal" Height="40">
|
||||
<Button x:Name="MuteButton" Background="Transparent" Foreground="White" Padding="5" Template="{StaticResource ActionCenterButton}" Width="40">
|
||||
<ContentControl x:Name="PopupIcon" />
|
||||
</Button>
|
||||
<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" Foreground="White" Width="40" />
|
||||
</StackPanel>
|
||||
</StackPanel>
|
||||
</Border>
|
||||
</Popup>
|
||||
<Button x:Name="Button" Padding="2" Template="{StaticResource ActionCenterButton}">
|
||||
<Grid>
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="2*" />
|
||||
<RowDefinition Height="3*" />
|
||||
</Grid.RowDefinitions>
|
||||
<ContentControl x:Name="TaskbarIcon" />
|
||||
<TextBlock Grid.Row="1" x:Name="Text" FontSize="11" Foreground="White" TextAlignment="Center" TextTrimming="CharacterEllipsis" TextWrapping="Wrap" VerticalAlignment="Bottom" />
|
||||
</Grid>
|
||||
</Button>
|
||||
</Grid>
|
||||
</UserControl>
|
|
@ -0,0 +1,161 @@
|
|||
/*
|
||||
* 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/.
|
||||
*/
|
||||
|
||||
using System;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows;
|
||||
using System.Windows.Controls;
|
||||
using System.Windows.Controls.Primitives;
|
||||
using System.Windows.Media;
|
||||
using System.Windows.Threading;
|
||||
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 ActionCenterAudioControl : UserControl, ISystemAudioControl
|
||||
{
|
||||
private readonly IText text;
|
||||
private bool muted;
|
||||
private XamlIconResource MutedIcon;
|
||||
private XamlIconResource NoDeviceIcon;
|
||||
|
||||
public event AudioMuteRequestedEventHandler MuteRequested;
|
||||
public event AudioVolumeSelectedEventHandler VolumeSelected;
|
||||
|
||||
public ActionCenterAudioControl(IText text)
|
||||
{
|
||||
this.text = text;
|
||||
|
||||
InitializeComponent();
|
||||
InitializeAudioControl();
|
||||
}
|
||||
|
||||
public bool HasOutputDevice
|
||||
{
|
||||
set
|
||||
{
|
||||
Dispatcher.InvokeAsync(() =>
|
||||
{
|
||||
Button.IsEnabled = value;
|
||||
|
||||
if (!value)
|
||||
{
|
||||
TaskbarIcon.Content = IconResourceLoader.Load(NoDeviceIcon);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
public bool OutputDeviceMuted
|
||||
{
|
||||
set
|
||||
{
|
||||
Dispatcher.InvokeAsync(() =>
|
||||
{
|
||||
muted = value;
|
||||
|
||||
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);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
public string OutputDeviceName
|
||||
{
|
||||
set
|
||||
{
|
||||
Dispatcher.InvokeAsync(() => AudioDeviceName.Text = value);
|
||||
}
|
||||
}
|
||||
|
||||
public double OutputDeviceVolume
|
||||
{
|
||||
set
|
||||
{
|
||||
Dispatcher.InvokeAsync(() =>
|
||||
{
|
||||
Volume.ValueChanged -= Volume_ValueChanged;
|
||||
Volume.Value = Math.Round(value * 100);
|
||||
Volume.ValueChanged += Volume_ValueChanged;
|
||||
|
||||
if (!muted)
|
||||
{
|
||||
PopupIcon.Content = LoadIcon(value);
|
||||
TaskbarIcon.Content = LoadIcon(value);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
public void Close()
|
||||
{
|
||||
Popup.IsOpen = false;
|
||||
}
|
||||
|
||||
public void SetInformation(string text)
|
||||
{
|
||||
Dispatcher.InvokeAsync(() =>
|
||||
{
|
||||
Button.ToolTip = text;
|
||||
Text.Text = text;
|
||||
});
|
||||
}
|
||||
|
||||
private void InitializeAudioControl()
|
||||
{
|
||||
var originalBrush = Grid.Background;
|
||||
|
||||
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/Audio_Muted.xaml"));
|
||||
NoDeviceIcon = new XamlIconResource(new Uri("pack://application:,,,/SafeExamBrowser.UserInterface.Desktop;component/Images/Audio_Light_NoDevice.xaml"));
|
||||
Popup.MouseLeave += (o, args) => Task.Delay(250).ContinueWith(_ => Dispatcher.Invoke(() => Popup.IsOpen = IsMouseOver));
|
||||
Popup.Opened += (o, args) => Grid.Background = Brushes.Gray;
|
||||
Popup.Closed += (o, args) => Grid.Background = originalBrush;
|
||||
Volume.ValueChanged += Volume_ValueChanged;
|
||||
}
|
||||
|
||||
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");
|
||||
var uri = new Uri($"pack://application:,,,/SafeExamBrowser.UserInterface.Desktop;component/Images/Audio_Light_{icon}.xaml");
|
||||
var resource = new XamlIconResource(uri);
|
||||
|
||||
return IconResourceLoader.Load(resource);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -120,8 +120,8 @@ 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"));
|
||||
MutedIcon = new XamlIconResource(new Uri("pack://application:,,,/SafeExamBrowser.UserInterface.Desktop;component/Images/Audio_Muted.xaml"));
|
||||
NoDeviceIcon = new XamlIconResource(new Uri("pack://application:,,,/SafeExamBrowser.UserInterface.Desktop;component/Images/Audio_NoDevice.xaml"));
|
||||
Popup.MouseLeave += (o, args) => Task.Delay(250).ContinueWith(_ => Dispatcher.Invoke(() => Popup.IsOpen = IsMouseOver));
|
||||
Volume.ValueChanged += Volume_ValueChanged;
|
||||
|
||||
|
|
|
@ -0,0 +1,13 @@
|
|||
<Viewbox
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:fa="http://schemas.fontawesome.io/icons/"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
|
||||
<Grid>
|
||||
<fa:ImageAwesome Icon="VolumeOff" HorizontalAlignment="Left" />
|
||||
<Canvas Width="100" Height="100">
|
||||
<Path StrokeThickness="5.0" Stroke="Black" StrokeStartLineCap="Round" StrokeEndLineCap="Round" StrokeLineJoin="Round" Data="M 55,35 C 65,45 65,55 55,65"/>
|
||||
<Path StrokeThickness="5.0" Stroke="Black" StrokeStartLineCap="Round" StrokeEndLineCap="Round" StrokeLineJoin="Round" Data="M 65,25 C 80,35 80,65 65,75"/>
|
||||
<Path StrokeThickness="5.0" Stroke="Black" StrokeStartLineCap="Round" StrokeEndLineCap="Round" StrokeLineJoin="Round" Data="M 75,15 C 95,30 95,70 75,85"/>
|
||||
</Canvas>
|
||||
</Grid>
|
||||
</Viewbox>
|
|
@ -0,0 +1,13 @@
|
|||
<Viewbox
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:fa="http://schemas.fontawesome.io/icons/"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
|
||||
<Grid>
|
||||
<fa:ImageAwesome Icon="VolumeOff" HorizontalAlignment="Left" />
|
||||
<Canvas Width="100" Height="100">
|
||||
<Path StrokeThickness="5.0" Stroke="Black" StrokeStartLineCap="Round" StrokeEndLineCap="Round" StrokeLineJoin="Round" Data="M 55,35 C 65,45 65,55 55,65"/>
|
||||
<Path StrokeThickness="5.0" Stroke="#ffdddddd" StrokeStartLineCap="Round" StrokeEndLineCap="Round" StrokeLineJoin="Round" Data="M 65,25 C 80,35 80,65 65,75"/>
|
||||
<Path StrokeThickness="5.0" Stroke="#ffdddddd" StrokeStartLineCap="Round" StrokeEndLineCap="Round" StrokeLineJoin="Round" Data="M 75,15 C 95,30 95,70 75,85"/>
|
||||
</Canvas>
|
||||
</Grid>
|
||||
</Viewbox>
|
|
@ -0,0 +1,13 @@
|
|||
<Viewbox
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:fa="http://schemas.fontawesome.io/icons/"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
|
||||
<Grid>
|
||||
<fa:ImageAwesome Icon="VolumeOff" HorizontalAlignment="Left" />
|
||||
<Canvas Width="100" Height="100">
|
||||
<Path StrokeThickness="5.0" Stroke="Black" StrokeStartLineCap="Round" StrokeEndLineCap="Round" StrokeLineJoin="Round" Data="M 55,35 C 65,45 65,55 55,65"/>
|
||||
<Path StrokeThickness="5.0" Stroke="Black" StrokeStartLineCap="Round" StrokeEndLineCap="Round" StrokeLineJoin="Round" Data="M 65,25 C 80,35 80,65 65,75"/>
|
||||
<Path StrokeThickness="5.0" Stroke="#ffdddddd" StrokeStartLineCap="Round" StrokeEndLineCap="Round" StrokeLineJoin="Round" Data="M 75,15 C 95,30 95,70 75,85"/>
|
||||
</Canvas>
|
||||
</Grid>
|
||||
</Viewbox>
|
|
@ -0,0 +1,16 @@
|
|||
<Viewbox
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:fa="http://schemas.fontawesome.io/icons/"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
|
||||
<Grid Margin="1">
|
||||
<Grid Margin="5,0,0,0">
|
||||
<fa:ImageAwesome Icon="VolumeOff" Foreground="#ffdddddd" HorizontalAlignment="Left" />
|
||||
<Canvas Width="100" Height="100">
|
||||
<Path StrokeThickness="5.0" Stroke="#ffdddddd" StrokeStartLineCap="Round" StrokeEndLineCap="Round" StrokeLineJoin="Round" Data="M 55,35 C 65,45 65,55 55,65"/>
|
||||
<Path StrokeThickness="5.0" Stroke="#ffdddddd" StrokeStartLineCap="Round" StrokeEndLineCap="Round" StrokeLineJoin="Round" Data="M 65,25 C 80,35 80,65 65,75"/>
|
||||
<Path StrokeThickness="5.0" Stroke="#ffdddddd" StrokeStartLineCap="Round" StrokeEndLineCap="Round" StrokeLineJoin="Round" Data="M 75,15 C 95,30 95,70 75,85"/>
|
||||
</Canvas>
|
||||
</Grid>
|
||||
<fa:ImageAwesome Foreground="Red" Icon="Ban" Opacity="0.3" />
|
||||
</Grid>
|
||||
</Viewbox>
|
|
@ -80,6 +80,9 @@
|
|||
<Compile Include="Controls\ActionCenterApplicationButton.xaml.cs">
|
||||
<DependentUpon>ActionCenterApplicationButton.xaml</DependentUpon>
|
||||
</Compile>
|
||||
<Compile Include="Controls\ActionCenterAudioControl.xaml.cs">
|
||||
<DependentUpon>ActionCenterAudioControl.xaml</DependentUpon>
|
||||
</Compile>
|
||||
<Compile Include="Controls\ActionCenterClock.xaml.cs">
|
||||
<DependentUpon>ActionCenterClock.xaml</DependentUpon>
|
||||
</Compile>
|
||||
|
@ -175,6 +178,10 @@
|
|||
<SubType>Designer</SubType>
|
||||
<Generator>MSBuild:Compile</Generator>
|
||||
</Page>
|
||||
<Page Include="Controls\ActionCenterAudioControl.xaml">
|
||||
<SubType>Designer</SubType>
|
||||
<Generator>MSBuild:Compile</Generator>
|
||||
</Page>
|
||||
<Page Include="Controls\ActionCenterClock.xaml">
|
||||
<SubType>Designer</SubType>
|
||||
<Generator>MSBuild:Compile</Generator>
|
||||
|
@ -263,7 +270,7 @@
|
|||
<Generator>MSBuild:Compile</Generator>
|
||||
<SubType>Designer</SubType>
|
||||
</Resource>
|
||||
<Resource Include="Images\AudioNoDevice.xaml">
|
||||
<Resource Include="Images\Audio_NoDevice.xaml">
|
||||
<Generator>MSBuild:Compile</Generator>
|
||||
<SubType>Designer</SubType>
|
||||
</Resource>
|
||||
|
@ -279,7 +286,23 @@
|
|||
<Generator>MSBuild:Compile</Generator>
|
||||
<SubType>Designer</SubType>
|
||||
</Resource>
|
||||
<Resource Include="Images\AudioMuted.xaml">
|
||||
<Resource Include="Images\Audio_Muted.xaml">
|
||||
<Generator>MSBuild:Compile</Generator>
|
||||
<SubType>Designer</SubType>
|
||||
</Resource>
|
||||
<Resource Include="Images\Audio_Light_66.xaml">
|
||||
<Generator>MSBuild:Compile</Generator>
|
||||
<SubType>Designer</SubType>
|
||||
</Resource>
|
||||
<Resource Include="Images\Audio_Light_33.xaml">
|
||||
<Generator>MSBuild:Compile</Generator>
|
||||
<SubType>Designer</SubType>
|
||||
</Resource>
|
||||
<Resource Include="Images\Audio_Light_100.xaml">
|
||||
<Generator>MSBuild:Compile</Generator>
|
||||
<SubType>Designer</SubType>
|
||||
</Resource>
|
||||
<Resource Include="Images\Audio_Light_NoDevice.xaml">
|
||||
<Generator>MSBuild:Compile</Generator>
|
||||
<SubType>Designer</SubType>
|
||||
</Resource>
|
||||
|
|
|
@ -54,12 +54,11 @@ namespace SafeExamBrowser.UserInterface.Desktop
|
|||
|
||||
public ISystemAudioControl CreateAudioControl(Location location)
|
||||
{
|
||||
// TODO
|
||||
//if (location == Location.ActionCenter)
|
||||
//{
|
||||
// return new ActionCenterAudioControl();
|
||||
//}
|
||||
//else
|
||||
if (location == Location.ActionCenter)
|
||||
{
|
||||
return new ActionCenterAudioControl(text);
|
||||
}
|
||||
else
|
||||
{
|
||||
return new TaskbarAudioControl(text);
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue