SEBWIN-141: Implemented wireless network control for action center and revised keyboard layout control for taskbar.

This commit is contained in:
dbuechel 2019-03-15 09:44:17 +01:00
parent ac2293dcb6
commit a47f68422c
29 changed files with 507 additions and 117 deletions

View file

@ -61,7 +61,7 @@ namespace SafeExamBrowser.Client.UnitTests.Operations
taskbarSettings.ShowApplicationLog = true; taskbarSettings.ShowApplicationLog = true;
taskbarSettings.ShowKeyboardLayout = true; taskbarSettings.ShowKeyboardLayout = true;
taskbarSettings.AllowWirelessNetwork = true; taskbarSettings.ShowWirelessNetwork = true;
taskbarSettings.EnableTaskbar = true; taskbarSettings.EnableTaskbar = true;
systemInfoMock.SetupGet(s => s.HasBattery).Returns(true); systemInfoMock.SetupGet(s => s.HasBattery).Returns(true);
uiFactoryMock.Setup(u => u.CreateNotificationControl(It.IsAny<INotificationInfo>(), It.IsAny<Location>())).Returns(new Mock<INotificationControl>().Object); uiFactoryMock.Setup(u => u.CreateNotificationControl(It.IsAny<INotificationInfo>(), It.IsAny<Location>())).Returns(new Mock<INotificationControl>().Object);

View file

@ -242,14 +242,20 @@ namespace SafeExamBrowser.Client.Operations
private void InitializeWirelessNetworkForActionCenter() private void InitializeWirelessNetworkForActionCenter()
{ {
// TODO if (actionCenterSettings.ShowWirelessNetwork)
{
var control = uiFactory.CreateWirelessNetworkControl(Location.ActionCenter);
wirelessNetwork.Register(control);
actionCenter.AddSystemControl(control);
}
} }
private void InitializeWirelessNetworkForTaskbar() private void InitializeWirelessNetworkForTaskbar()
{ {
if (taskbarSettings.AllowWirelessNetwork) if (taskbarSettings.ShowWirelessNetwork)
{ {
var control = uiFactory.CreateWirelessNetworkControl(); var control = uiFactory.CreateWirelessNetworkControl(Location.Taskbar);
wirelessNetwork.Register(control); wirelessNetwork.Register(control);
taskbar.AddSystemControl(control); taskbar.AddSystemControl(control);

View file

@ -40,7 +40,7 @@ namespace SafeExamBrowser.Configuration.ConfigurationData
{ {
if (value is bool enabled) if (value is bool enabled)
{ {
settings.Taskbar.AllowWirelessNetwork = enabled; settings.Taskbar.ShowWirelessNetwork = enabled;
} }
} }

View file

@ -140,13 +140,14 @@ namespace SafeExamBrowser.Configuration.ConfigurationData
settings.Taskbar.ShowApplicationLog = false; settings.Taskbar.ShowApplicationLog = false;
settings.Taskbar.ShowKeyboardLayout = true; settings.Taskbar.ShowKeyboardLayout = true;
settings.Taskbar.AllowWirelessNetwork = false; settings.Taskbar.ShowWirelessNetwork = false;
settings.Taskbar.EnableTaskbar = true; settings.Taskbar.EnableTaskbar = true;
settings.Taskbar.ShowClock = true; settings.Taskbar.ShowClock = true;
// TODO: Default values for testing of alpha version only, remove for final release! // TODO: Default values for testing of alpha version only, remove for final release!
settings.ActionCenter.ShowApplicationLog = true; settings.ActionCenter.ShowApplicationLog = true;
settings.ActionCenter.ShowKeyboardLayout = true; settings.ActionCenter.ShowKeyboardLayout = true;
settings.ActionCenter.ShowWirelessNetwork = true;
settings.Browser.AllowDeveloperConsole = true; settings.Browser.AllowDeveloperConsole = true;
settings.Browser.MainWindowSettings.AllowAddressBar = true; settings.Browser.MainWindowSettings.AllowAddressBar = true;
settings.Taskbar.ShowApplicationLog = true; settings.Taskbar.ShowApplicationLog = true;

View file

@ -30,5 +30,10 @@ namespace SafeExamBrowser.Contracts.Configuration.Settings
/// Determines whether the system control for the keyboard layout is accessible via the action center. /// Determines whether the system control for the keyboard layout is accessible via the action center.
/// </summary> /// </summary>
public bool ShowKeyboardLayout { get; set; } public bool ShowKeyboardLayout { get; set; }
/// <summary>
/// Determines whether the system control for the wireless network is accessible via the action center.
/// </summary>
public bool ShowWirelessNetwork { get; set; }
} }
} }

View file

@ -39,6 +39,6 @@ namespace SafeExamBrowser.Contracts.Configuration.Settings
/// <summary> /// <summary>
/// Determines whether the system control for the wireless network is accessible via the taskbar. /// Determines whether the system control for the wireless network is accessible via the taskbar.
/// </summary> /// </summary>
public bool AllowWirelessNetwork { get; set; } public bool ShowWirelessNetwork { get; set; }
} }
} }

View file

@ -9,8 +9,7 @@
namespace SafeExamBrowser.Contracts.I18n namespace SafeExamBrowser.Contracts.I18n
{ {
/// <summary> /// <summary>
/// Provides access to text data. IMPORTANT: To allow for a complete internationalization of the application, all text elements which /// Provides access to text data.
/// are visible to the user must be retrieved via this module!
/// </summary> /// </summary>
public interface IText public interface IText
{ {

View file

@ -19,9 +19,7 @@ using SafeExamBrowser.Contracts.UserInterface.Windows;
namespace SafeExamBrowser.Contracts.UserInterface namespace SafeExamBrowser.Contracts.UserInterface
{ {
/// <summary> /// <summary>
/// The factory for user interface elements which cannot be instantiated at the composition root. IMPORTANT: To allow for decoupling /// The factory for user interface elements which cannot be instantiated at the composition root.
/// from the particular user interface framework in use, all dynamically generated user interface elements must be generated by this
/// factory.
/// </summary> /// </summary>
public interface IUserInterfaceFactory public interface IUserInterfaceFactory
{ {
@ -84,6 +82,6 @@ namespace SafeExamBrowser.Contracts.UserInterface
/// <summary> /// <summary>
/// Creates a system control which allows to change the wireless network connection of the computer. /// Creates a system control which allows to change the wireless network connection of the computer.
/// </summary> /// </summary>
ISystemWirelessNetworkControl CreateWirelessNetworkControl(); ISystemWirelessNetworkControl CreateWirelessNetworkControl(Location location);
} }
} }

View file

@ -6,12 +6,12 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. * file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/ */
using SafeExamBrowser.Contracts.SystemComponents; using System;
namespace SafeExamBrowser.Contracts.UserInterface.Shell.Events namespace SafeExamBrowser.Contracts.UserInterface.Shell.Events
{ {
/// <summary> /// <summary>
/// Indicates that a particular <see cref="IWirelessNetwork"/> has been selected by the user. /// Indicates that a particular wireless network has been selected by the user.
/// </summary> /// </summary>
public delegate void WirelessNetworkSelectedEventHandler(IWirelessNetwork network); public delegate void WirelessNetworkSelectedEventHandler(Guid id);
} }

View file

@ -22,11 +22,11 @@ namespace SafeExamBrowser.SystemComponents
{ {
public class WirelessNetwork : ISystemComponent<ISystemWirelessNetworkControl> public class WirelessNetwork : ISystemComponent<ISystemWirelessNetworkControl>
{ {
private const int TWO_SECONDS = 2000; private const int FIVE_SECONDS = 5000;
private readonly object @lock = new object(); private readonly object @lock = new object();
private IList<ISystemWirelessNetworkControl> controls; private List<ISystemWirelessNetworkControl> controls;
private IList<WirelessNetworkDefinition> networks; private List<WirelessNetworkDefinition> networks;
private bool hasWifiAdapter; private bool hasWifiAdapter;
private ILogger logger; private ILogger logger;
private IText text; private IText text;
@ -49,10 +49,8 @@ namespace SafeExamBrowser.SystemComponents
if (hasWifiAdapter) if (hasWifiAdapter)
{ {
timer = new Timer(TWO_SECONDS); UpdateAvailableNetworks();
timer.Elapsed += Timer_Elapsed; StartTimer();
timer.AutoReset = true;
timer.Start();
logger.Info("Started monitoring the wireless network adapter."); logger.Info("Started monitoring the wireless network adapter.");
} }
@ -97,23 +95,28 @@ namespace SafeExamBrowser.SystemComponents
} }
} }
private void Control_NetworkSelected(IWirelessNetwork network) private void Control_NetworkSelected(Guid id)
{ {
try lock (@lock)
{ {
var accessPoint = networks.First(n => n.Id == network.Id).AccessPoint; var network = networks.First(n => n.Id == id);
var authRequest = new AuthRequest(accessPoint);
accessPoint.ConnectAsync(authRequest, false, (success) => AccessPoint_OnConnectComplete(network.Name, success)); try
foreach (var control in controls)
{ {
control.IsConnecting = true; var request = new AuthRequest(network.AccessPoint);
logger.Info($"Attempting to connect to '{network.Name}'...");
network.AccessPoint.ConnectAsync(request, false, (success) => AccessPoint_OnConnectComplete(network.Name, success));
foreach (var control in controls)
{
control.IsConnecting = true;
}
}
catch (Exception e)
{
logger.Error($"Failed to connect to wireless network '{network.Name}!'", e);
} }
}
catch (Exception e)
{
logger.Error($"Failed to connect to wireless network '{network.Name}!'", e);
} }
} }
@ -133,16 +136,19 @@ namespace SafeExamBrowser.SystemComponents
control.IsConnecting = false; control.IsConnecting = false;
} }
UpdateAvailableNetworks();
UpdateControls(); UpdateControls();
} }
private void Timer_Elapsed(object sender, ElapsedEventArgs e) private void Timer_Elapsed(object sender, ElapsedEventArgs e)
{ {
UpdateAvailableNetworks();
UpdateControls(); UpdateControls();
} }
private void Wifi_ConnectionStatusChanged(object sender, WifiStatusEventArgs e) private void Wifi_ConnectionStatusChanged(object sender, WifiStatusEventArgs e)
{ {
UpdateAvailableNetworks();
UpdateControls(); UpdateControls();
} }
@ -177,22 +183,7 @@ namespace SafeExamBrowser.SystemComponents
{ {
try try
{ {
var isConnected = false; var currentNetwork = networks.FirstOrDefault(n => n.Status == WirelessNetworkStatus.Connected);
var networkName = string.Empty;
networks.Clear();
foreach (var accessPoint in wifi.GetAccessPoints())
{
// The user may only connect to an already configured wireless network!
if (accessPoint.HasProfile)
{
networkName = accessPoint.Name;
isConnected = accessPoint.IsConnected;
networks.Add(ToDefinition(accessPoint));
}
}
foreach (var control in controls) foreach (var control in controls)
{ {
@ -201,13 +192,13 @@ namespace SafeExamBrowser.SystemComponents
control.SetInformation(text.Get(TextKey.SystemControl_WirelessDisconnected)); control.SetInformation(text.Get(TextKey.SystemControl_WirelessDisconnected));
} }
if (isConnected) if (currentNetwork != null)
{ {
control.SetInformation(text.Get(TextKey.SystemControl_WirelessConnected).Replace("%%NAME%%", networkName)); control.SetInformation(text.Get(TextKey.SystemControl_WirelessConnected).Replace("%%NAME%%", currentNetwork.Name));
} }
control.NetworkStatus = ToStatus(wifi.ConnectionStatus); control.NetworkStatus = ToStatus(wifi.ConnectionStatus);
control.Update(new List<IWirelessNetwork>(networks)); control.Update(networks.ToList());
} }
} }
catch (Exception e) catch (Exception e)
@ -217,6 +208,31 @@ namespace SafeExamBrowser.SystemComponents
} }
} }
private void UpdateAvailableNetworks()
{
lock (@lock)
{
networks.Clear();
foreach (var accessPoint in wifi.GetAccessPoints())
{
// The user may only connect to an already configured wireless network!
if (accessPoint.HasProfile)
{
networks.Add(ToDefinition(accessPoint));
}
}
}
}
private void StartTimer()
{
timer = new Timer(FIVE_SECONDS);
timer.Elapsed += Timer_Elapsed;
timer.AutoReset = true;
timer.Start();
}
private WirelessNetworkDefinition ToDefinition(AccessPoint accessPoint) private WirelessNetworkDefinition ToDefinition(AccessPoint accessPoint)
{ {
return new WirelessNetworkDefinition return new WirelessNetworkDefinition

View file

@ -18,7 +18,7 @@
<Grid x:Name="Grid" Background="{StaticResource ActionCenterDarkBrush}" Height="64" Margin="2"> <Grid x:Name="Grid" Background="{StaticResource ActionCenterDarkBrush}" Height="64" Margin="2">
<Popup x:Name="Popup" IsOpen="False" Placement="Top" PlacementTarget="{Binding ElementName=Button}"> <Popup x:Name="Popup" IsOpen="False" Placement="Top" PlacementTarget="{Binding ElementName=Button}">
<Border Background="Gray"> <Border Background="Gray">
<ScrollViewer x:Name="LayoutsScrollViewer" MaxHeight="250" VerticalScrollBarVisibility="Auto" Template="{StaticResource SmallBarScrollViewer}"> <ScrollViewer MaxHeight="250" VerticalScrollBarVisibility="Auto" Template="{StaticResource SmallBarScrollViewer}">
<StackPanel x:Name="LayoutsStackPanel" /> <StackPanel x:Name="LayoutsStackPanel" />
</ScrollViewer> </ScrollViewer>
</Border> </Border>

View file

@ -0,0 +1,30 @@
<UserControl x:Class="SafeExamBrowser.UserInterface.Desktop.Controls.ActionCenterWirelessNetworkButton"
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="40" d:DesignWidth="250">
<UserControl.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="../Templates/Buttons.xaml" />
<ResourceDictionary Source="../Templates/Colors.xaml" />
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
</UserControl.Resources>
<Grid>
<Button x:Name="Button" Background="Transparent" Height="40" Padding="10,0" Template="{StaticResource ActionCenterButton}">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>
<TextBlock x:Name="IsCurrentTextBlock" Grid.Column="0" FontSize="20" HorizontalAlignment="Center" VerticalAlignment="Center" Visibility="Hidden">•</TextBlock>
<TextBlock x:Name="SignalStrengthTextBlock" Grid.Column="1" Foreground="White" HorizontalAlignment="Left" Margin="10,0,5,0" VerticalAlignment="Center" />
<TextBlock x:Name="NetworkNameTextBlock" Grid.Column="2" FontWeight="Bold" HorizontalAlignment="Left" Margin="5,0,10,0" VerticalAlignment="Center" />
</Grid>
</Button>
</Grid>
</UserControl>

View file

@ -0,0 +1,50 @@
/*
* 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.Windows;
using System.Windows.Controls;
using SafeExamBrowser.Contracts.SystemComponents;
using SafeExamBrowser.Contracts.UserInterface.Shell.Events;
namespace SafeExamBrowser.UserInterface.Desktop.Controls
{
public partial class ActionCenterWirelessNetworkButton : UserControl
{
private IWirelessNetwork network;
public bool IsCurrent
{
set { IsCurrentTextBlock.Visibility = value ? Visibility.Visible : Visibility.Hidden; }
}
public string NetworkName
{
set { NetworkNameTextBlock.Text = value; }
}
public int SignalStrength
{
set { SignalStrengthTextBlock.Text = $"{value}%"; }
}
public event WirelessNetworkSelectedEventHandler NetworkSelected;
public ActionCenterWirelessNetworkButton(IWirelessNetwork network)
{
this.network = network;
InitializeComponent();
InitializeEvents();
}
private void InitializeEvents()
{
Button.Click += (o, args) => NetworkSelected?.Invoke(network.Id);
}
}
}

View file

@ -0,0 +1,42 @@
<UserControl x:Class="SafeExamBrowser.UserInterface.Desktop.Controls.ActionCenterWirelessNetworkControl"
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:fa="http://schemas.fontawesome.io/icons/"
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">
<ScrollViewer MaxHeight="250" VerticalScrollBarVisibility="Auto" Template="{StaticResource SmallBarScrollViewer}">
<StackPanel x:Name="NetworksStackPanel" />
</ScrollViewer>
</Border>
</Popup>
<Button x:Name="Button" Padding="2" Template="{StaticResource ActionCenterButton}" ToolTipService.ShowOnDisabled="True">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="2*" />
<RowDefinition Height="3*" />
</Grid.RowDefinitions>
<Grid Grid.Row="0" HorizontalAlignment="Center" VerticalAlignment="Center">
<Viewbox x:Name="SignalStrengthIcon" Stretch="Uniform" Width="Auto" />
<fa:ImageAwesome x:Name="NoAdapterIcon" Foreground="Red" Icon="Ban" Margin="1" Opacity="0.3" Visibility="Collapsed" />
<fa:ImageAwesome x:Name="LoadingIcon" Foreground="Black" Icon="Cog" Margin="5" Spin="True" SpinDuration="2" Visibility="Collapsed" />
<Image x:Name="NetworkStatusIcon" Height="7" HorizontalAlignment="Right" Margin="-2,0" Panel.ZIndex="10" VerticalAlignment="Bottom" />
</Grid>
<TextBlock Grid.Row="1" x:Name="Text" FontSize="11" Foreground="White" TextAlignment="Center" TextTrimming="CharacterEllipsis" TextWrapping="Wrap" VerticalAlignment="Bottom" />
</Grid>
</Button>
</Grid>
</UserControl>

View file

@ -0,0 +1,139 @@
/*
* 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.Collections.Generic;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Media;
using FontAwesome.WPF;
using SafeExamBrowser.Contracts.SystemComponents;
using SafeExamBrowser.Contracts.UserInterface.Shell;
using SafeExamBrowser.Contracts.UserInterface.Shell.Events;
using SafeExamBrowser.UserInterface.Desktop.Utilities;
namespace SafeExamBrowser.UserInterface.Desktop.Controls
{
public partial class ActionCenterWirelessNetworkControl : UserControl, ISystemWirelessNetworkControl
{
public bool HasWirelessNetworkAdapter
{
set
{
Dispatcher.Invoke(() =>
{
Button.IsEnabled = value;
NoAdapterIcon.Visibility = value ? Visibility.Collapsed : Visibility.Visible;
});
}
}
public bool IsConnecting
{
set
{
Dispatcher.Invoke(() =>
{
LoadingIcon.Visibility = value ? Visibility.Visible : Visibility.Collapsed;
SignalStrengthIcon.Visibility = value ? Visibility.Collapsed : Visibility.Visible;
NetworkStatusIcon.Visibility = value ? Visibility.Collapsed : Visibility.Visible;
});
}
}
public WirelessNetworkStatus NetworkStatus
{
set
{
Dispatcher.Invoke(() =>
{
var icon = value == WirelessNetworkStatus.Connected ? FontAwesomeIcon.Check : FontAwesomeIcon.Close;
var brush = value == WirelessNetworkStatus.Connected ? Brushes.Green : Brushes.Orange;
if (value == WirelessNetworkStatus.Disconnected)
{
SignalStrengthIcon.Child = GetIcon(0);
}
NetworkStatusIcon.Source = ImageAwesome.CreateImageSource(icon, brush);
});
}
}
public event WirelessNetworkSelectedEventHandler NetworkSelected;
public ActionCenterWirelessNetworkControl()
{
InitializeComponent();
InitializeWirelessNetworkControl();
}
public void Close()
{
Dispatcher.Invoke(() => Popup.IsOpen = false);
}
public void SetInformation(string text)
{
Dispatcher.Invoke(() =>
{
Button.ToolTip = text;
Text.Text = text;
});
}
public void Update(IEnumerable<IWirelessNetwork> networks)
{
Dispatcher.Invoke(() =>
{
NetworksStackPanel.Children.Clear();
foreach (var network in networks)
{
var button = new ActionCenterWirelessNetworkButton(network);
var isCurrent = network.Status == WirelessNetworkStatus.Connected;
button.IsCurrent = isCurrent;
button.NetworkName = network.Name;
button.SignalStrength = network.SignalStrength;
button.NetworkSelected += (id) => NetworkSelected?.Invoke(id);
if (isCurrent)
{
NetworkStatus = network.Status;
SignalStrengthIcon.Child = GetIcon(network.SignalStrength);
}
NetworksStackPanel.Children.Add(button);
}
});
}
private void InitializeWirelessNetworkControl()
{
var originalBrush = Grid.Background;
SignalStrengthIcon.Child = GetIcon(0);
Button.Click += (o, args) => Popup.IsOpen = !Popup.IsOpen;
Button.MouseLeave += (o, args) => Task.Delay(250).ContinueWith(_ => Dispatcher.Invoke(() => Popup.IsOpen = Popup.IsMouseOver));
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;
}
private UIElement GetIcon(int signalStrength)
{
var icon = signalStrength > 66 ? "100" : (signalStrength > 33 ? "66" : (signalStrength > 0 ? "33" : "0"));
var uri = new Uri($"pack://application:,,,/SafeExamBrowser.UserInterface.Desktop;component/Images/WiFi_Light_{icon}.xaml");
var resource = new XamlIconResource(uri);
return IconResourceLoader.Load(resource);
}
}
}

View file

@ -3,7 +3,6 @@
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:fa="http://schemas.fontawesome.io/icons/"
xmlns:s="clr-namespace:System;assembly=mscorlib" xmlns:s="clr-namespace:System;assembly=mscorlib"
xmlns:local="clr-namespace:SafeExamBrowser.UserInterface.Desktop.Controls" xmlns:local="clr-namespace:SafeExamBrowser.UserInterface.Desktop.Controls"
mc:Ignorable="d" d:DesignHeight="40" d:DesignWidth="40"> mc:Ignorable="d" d:DesignHeight="40" d:DesignWidth="40">
@ -25,27 +24,9 @@
</Border> </Border>
</Popup> </Popup>
<Button x:Name="Button" Background="Transparent" Template="{StaticResource TaskbarButton}" Padding="5" Width="40"> <Button x:Name="Button" Background="Transparent" Template="{StaticResource TaskbarButton}" Padding="5" Width="40">
<Grid> <Viewbox Stretch="Uniform">
<fa:ImageAwesome Panel.ZIndex="1" Foreground="LightGray" Icon="KeyboardOutline" VerticalAlignment="Center"> <TextBlock x:Name="LayoutCultureCode" FontWeight="Bold" Margin="2" TextAlignment="Center" VerticalAlignment="Center" />
<fa:ImageAwesome.Effect> </Viewbox>
<DropShadowEffect Color="White" BlurRadius="5" Direction="0" Opacity="1" ShadowDepth="0" />
</fa:ImageAwesome.Effect>
</fa:ImageAwesome>
<Viewbox Panel.ZIndex="2" Stretch="Uniform">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="1*" />
<RowDefinition Height="1*" />
</Grid.RowDefinitions>
<TextBlock Grid.Row="0" x:Name="LayoutCultureCode" FontWeight="Bold" TextAlignment="Center">
<TextBlock.Effect>
<DropShadowEffect Color="White" BlurRadius="5" Direction="0" Opacity="1" ShadowDepth="0" />
</TextBlock.Effect>
</TextBlock>
<TextBlock Grid.Row="1" />
</Grid>
</Viewbox>
</Grid>
</Button> </Button>
</Grid> </Grid>
</UserControl> </UserControl>

View file

@ -1,4 +1,4 @@
<UserControl x:Class="SafeExamBrowser.UserInterface.Desktop.Controls.WirelessNetworkButton" <UserControl x:Class="SafeExamBrowser.UserInterface.Desktop.Controls.TaskbarWirelessNetworkButton"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"

View file

@ -8,12 +8,14 @@
using System.Windows; using System.Windows;
using System.Windows.Controls; using System.Windows.Controls;
using SafeExamBrowser.Contracts.SystemComponents;
using SafeExamBrowser.Contracts.UserInterface.Shell.Events;
namespace SafeExamBrowser.UserInterface.Desktop.Controls namespace SafeExamBrowser.UserInterface.Desktop.Controls
{ {
public partial class WirelessNetworkButton : UserControl public partial class TaskbarWirelessNetworkButton : UserControl
{ {
public event RoutedEventHandler Click; private readonly IWirelessNetwork network;
public bool IsCurrent public bool IsCurrent
{ {
@ -30,11 +32,19 @@ namespace SafeExamBrowser.UserInterface.Desktop.Controls
set { SignalStrengthTextBlock.Text = $"{value}%"; } set { SignalStrengthTextBlock.Text = $"{value}%"; }
} }
public WirelessNetworkButton() public event WirelessNetworkSelectedEventHandler NetworkSelected;
{
InitializeComponent();
Button.Click += (o, args) => Click?.Invoke(o, args); public TaskbarWirelessNetworkButton(IWirelessNetwork network)
{
this.network = network;
InitializeComponent();
InitializeEvents();
}
private void InitializeEvents()
{
Button.Click += (o, args) => NetworkSelected?.Invoke(network.Id);
} }
} }
} }

View file

@ -1,4 +1,4 @@
<UserControl x:Class="SafeExamBrowser.UserInterface.Desktop.Controls.WirelessNetworkControl" <UserControl x:Class="SafeExamBrowser.UserInterface.Desktop.Controls.TaskbarWirelessNetworkControl"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
@ -12,16 +12,14 @@
<ResourceDictionary.MergedDictionaries> <ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="../Templates/Buttons.xaml" /> <ResourceDictionary Source="../Templates/Buttons.xaml" />
<ResourceDictionary Source="../Templates/Colors.xaml" /> <ResourceDictionary Source="../Templates/Colors.xaml" />
<ResourceDictionary Source="../Templates/ScrollViewers.xaml" />
</ResourceDictionary.MergedDictionaries> </ResourceDictionary.MergedDictionaries>
</ResourceDictionary> </ResourceDictionary>
</UserControl.Resources> </UserControl.Resources>
<Grid> <Grid>
<Popup x:Name="Popup" IsOpen="False" Placement="Top" PlacementTarget="{Binding ElementName=Button}"> <Popup x:Name="Popup" IsOpen="False" Placement="Top" PlacementTarget="{Binding ElementName=Button}">
<Border Background="LightGray" BorderBrush="Gray" BorderThickness="0.75,0.75,0.75,0"> <Border Background="LightGray" BorderBrush="Gray" BorderThickness="0.75,0.75,0.75,0">
<ScrollViewer MaxHeight="250" VerticalScrollBarVisibility="Auto"> <ScrollViewer MaxHeight="250" VerticalScrollBarVisibility="Auto" Template="{StaticResource SmallBarScrollViewer}">
<ScrollViewer.Resources>
<s:Double x:Key="{x:Static SystemParameters.VerticalScrollBarWidthKey}">5</s:Double>
</ScrollViewer.Resources>
<StackPanel x:Name="NetworksStackPanel" /> <StackPanel x:Name="NetworksStackPanel" />
</ScrollViewer> </ScrollViewer>
</Border> </Border>
@ -29,9 +27,9 @@
<Button x:Name="Button" Background="Transparent" Padding="5" Template="{StaticResource TaskbarButton}" ToolTipService.ShowOnDisabled="True" Width="40"> <Button x:Name="Button" Background="Transparent" Padding="5" Template="{StaticResource TaskbarButton}" ToolTipService.ShowOnDisabled="True" Width="40">
<Grid HorizontalAlignment="Center" VerticalAlignment="Center"> <Grid HorizontalAlignment="Center" VerticalAlignment="Center">
<Viewbox x:Name="SignalStrengthIcon" Stretch="Uniform" Width="Auto" /> <Viewbox x:Name="SignalStrengthIcon" Stretch="Uniform" Width="Auto" />
<fa:ImageAwesome x:Name="NoAdapterIcon" Foreground="Red" Icon="Ban" Margin="1" Opacity="0.2" Visibility="Collapsed" /> <fa:ImageAwesome x:Name="NoAdapterIcon" Foreground="Red" Icon="Ban" Margin="1" Opacity="0.3" Visibility="Collapsed" />
<fa:ImageAwesome x:Name="LoadingIcon" Foreground="Gray" Icon="Cog" Margin="5" Spin="True" SpinDuration="2" Visibility="Collapsed" /> <fa:ImageAwesome x:Name="LoadingIcon" Foreground="Gray" Icon="Cog" Margin="5" Spin="True" SpinDuration="2" Visibility="Collapsed" />
<Image x:Name="NetworkStatusIcon" Height="8" HorizontalAlignment="Right" Margin="-1,2" Panel.ZIndex="10" VerticalAlignment="Bottom" /> <Image x:Name="NetworkStatusIcon" Height="7" HorizontalAlignment="Right" Margin="0,2" Panel.ZIndex="10" VerticalAlignment="Bottom" />
</Grid> </Grid>
</Button> </Button>
</Grid> </Grid>

View file

@ -20,7 +20,7 @@ using SafeExamBrowser.UserInterface.Desktop.Utilities;
namespace SafeExamBrowser.UserInterface.Desktop.Controls namespace SafeExamBrowser.UserInterface.Desktop.Controls
{ {
public partial class WirelessNetworkControl : UserControl, ISystemWirelessNetworkControl public partial class TaskbarWirelessNetworkControl : UserControl, ISystemWirelessNetworkControl
{ {
public bool HasWirelessNetworkAdapter public bool HasWirelessNetworkAdapter
{ {
@ -56,6 +56,11 @@ namespace SafeExamBrowser.UserInterface.Desktop.Controls
var icon = value == WirelessNetworkStatus.Connected ? FontAwesomeIcon.Check : FontAwesomeIcon.Close; var icon = value == WirelessNetworkStatus.Connected ? FontAwesomeIcon.Check : FontAwesomeIcon.Close;
var brush = value == WirelessNetworkStatus.Connected ? Brushes.Green : Brushes.Orange; var brush = value == WirelessNetworkStatus.Connected ? Brushes.Green : Brushes.Orange;
if (value == WirelessNetworkStatus.Disconnected)
{
SignalStrengthIcon.Child = GetIcon(0);
}
NetworkStatusIcon.Source = ImageAwesome.CreateImageSource(icon, brush); NetworkStatusIcon.Source = ImageAwesome.CreateImageSource(icon, brush);
}); });
} }
@ -63,7 +68,7 @@ namespace SafeExamBrowser.UserInterface.Desktop.Controls
public event WirelessNetworkSelectedEventHandler NetworkSelected; public event WirelessNetworkSelectedEventHandler NetworkSelected;
public WirelessNetworkControl() public TaskbarWirelessNetworkControl()
{ {
InitializeComponent(); InitializeComponent();
InitializeWirelessNetworkControl(); InitializeWirelessNetworkControl();
@ -87,16 +92,13 @@ namespace SafeExamBrowser.UserInterface.Desktop.Controls
foreach (var network in networks) foreach (var network in networks)
{ {
var button = new WirelessNetworkButton(); var button = new TaskbarWirelessNetworkButton(network);
var isCurrent = network.Status == WirelessNetworkStatus.Connected; var isCurrent = network.Status == WirelessNetworkStatus.Connected;
button.Click += (o, args) =>
{
NetworkSelected?.Invoke(network);
};
button.IsCurrent = isCurrent; button.IsCurrent = isCurrent;
button.NetworkName = network.Name; button.NetworkName = network.Name;
button.SignalStrength = network.SignalStrength; button.SignalStrength = network.SignalStrength;
button.NetworkSelected += (id) => NetworkSelected?.Invoke(id);
if (isCurrent) if (isCurrent)
{ {

View file

@ -1,8 +1,14 @@
<Viewbox <Viewbox
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 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"> xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<Grid> <Canvas Width="1024.000" Height="1024.000">
<fa:ImageAwesome Foreground="Gray" Icon="InfoCircle" Margin="10" /> <Canvas>
</Grid> <Path Data=" M 0.000,0.000 L 1024.000,0.000 L 1024.000,1024.000 L 0.000,1024.000 L 0.000,0.000 Z"/>
<Path StrokeThickness="70.0" Stroke="#ff000000" StrokeStartLineCap="Round" StrokeEndLineCap="Round" StrokeLineJoin="Round" Data=" M 117.000,512.000 C 117.000,293.840 293.840,117.000 512.000,117.000 C 730.160,117.000 907.000,293.840 907.000,512.000 C 907.000,730.160 730.160,907.000 512.000,907.000 C 293.840,907.000 117.000,730.160 117.000,512.000 Z"/>
<Path StrokeThickness="70.0" Stroke="#ff000000" StrokeStartLineCap="Round" StrokeEndLineCap="Round" StrokeLineJoin="Round" Data=" M 619.210,298.700"/>
<Path StrokeThickness="70.0" Stroke="#ff000000" StrokeStartLineCap="Round" StrokeEndLineCap="Round" StrokeLineJoin="Round" Data=" M 619.210,727.560"/>
<Path StrokeThickness="70.0" Stroke="#ff000000" StrokeStartLineCap="Round" StrokeEndLineCap="Round" StrokeLineJoin="Round" Data=" M 512.000,458.096 L 512.000,741.560"/>
<Path Fill="#ff000000" Data=" M 547.625,312.700 C 547.625,332.375 531.675,348.325 512.000,348.325 C 492.325,348.325 476.375,332.375 476.375,312.700 C 476.375,293.025 492.325,277.075 512.000,277.075 C 531.675,277.075 547.625,293.025 547.625,312.700 Z"/>
</Canvas>
</Canvas>
</Viewbox> </Viewbox>

View file

@ -0,0 +1,16 @@
<Viewbox
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<Canvas Width="1024.000" Height="1024.000">
<Canvas>
<Path Data=" M 0.000,0.000 L 1024.000,0.000 L 1024.000,1024.000 L 0.000,1024.000 L 0.000,0.000 Z"/>
<Path StrokeThickness="1.0" Stroke="#ffdddddd" StrokeStartLineCap="Round" StrokeEndLineCap="Round" StrokeLineJoin="Round" Fill="#ffdddddd" Data=" M 467.000,811.000 C 467.000,786.150 487.150,766.000 512.000,766.000 C 536.850,766.000 557.000,786.150 557.000,811.000 C 557.000,835.850 536.850,856.000 512.000,856.000 C 487.150,856.000 467.000,835.850 467.000,811.000 Z"/>
<Path StrokeThickness="35.0" Stroke="#ffdddddd" StrokeStartLineCap="Round" StrokeEndLineCap="Round" StrokeLineJoin="Round" Data=" M 82.530,352.000 C 191.500,240.330 343.650,171.000 512.000,171.000 C 680.350,171.000 832.500,240.330 941.470,352.000"/>
<Path StrokeThickness="70.0" Stroke="#ffdddddd" StrokeStartLineCap="Round" StrokeEndLineCap="Round" StrokeLineJoin="Round" Data=" M 82.530,352.000 C 191.500,240.330 343.650,171.000 512.000,171.000 C 680.350,171.000 832.500,240.330 941.470,352.000"/>
<Path StrokeThickness="35.0" Stroke="#ffdddddd" StrokeStartLineCap="Round" StrokeEndLineCap="Round" StrokeLineJoin="Round" Data=" M 346.620,660.000 C 384.600,610.220 444.550,578.100 512.000,578.100 C 579.900,578.100 640.200,610.650 678.140,661.000"/>
<Path StrokeThickness="70.0" Stroke="#ffdddddd" StrokeStartLineCap="Round" StrokeEndLineCap="Round" StrokeLineJoin="Round" Data=" M 346.620,660.000 C 384.600,610.220 444.550,578.100 512.000,578.100 C 579.900,578.100 640.200,610.650 678.140,661.000"/>
<Path StrokeThickness="35.0" Stroke="#ffdddddd" StrokeStartLineCap="Round" StrokeEndLineCap="Round" StrokeLineJoin="Round" Data=" M 213.050,505.000 C 288.650,426.810 394.650,378.200 512.000,378.200 C 629.350,378.200 735.350,426.810 810.950,505.000"/>
<Path StrokeThickness="70.0" Stroke="#ffdddddd" StrokeStartLineCap="Round" StrokeEndLineCap="Round" StrokeLineJoin="Round" Data=" M 213.050,505.000 C 288.650,426.810 394.650,378.200 512.000,378.200 C 629.350,378.200 735.350,426.810 810.950,505.000"/>
</Canvas>
</Canvas>
</Viewbox>

View file

@ -0,0 +1,16 @@
<Viewbox
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<Canvas Width="1024.000" Height="1024.000">
<Canvas>
<Path Data=" M 0.000,0.000 L 1024.000,0.000 L 1024.000,1024.000 L 0.000,1024.000 L 0.000,0.000 Z"/>
<Path StrokeThickness="1.0" Stroke="#ff000000" StrokeStartLineCap="Round" StrokeEndLineCap="Round" StrokeLineJoin="Round" Fill="#ff000000" Data=" M 467.000,811.000 C 467.000,786.150 487.150,766.000 512.000,766.000 C 536.850,766.000 557.000,786.150 557.000,811.000 C 557.000,835.850 536.850,856.000 512.000,856.000 C 487.150,856.000 467.000,835.850 467.000,811.000 Z"/>
<Path StrokeThickness="35.0" Stroke="#ff000000" StrokeStartLineCap="Round" StrokeEndLineCap="Round" StrokeLineJoin="Round" Data=" M 82.530,352.000 C 191.500,240.330 343.650,171.000 512.000,171.000 C 680.350,171.000 832.500,240.330 941.470,352.000"/>
<Path StrokeThickness="70.0" Stroke="#ff000000" StrokeStartLineCap="Round" StrokeEndLineCap="Round" StrokeLineJoin="Round" Data=" M 82.530,352.000 C 191.500,240.330 343.650,171.000 512.000,171.000 C 680.350,171.000 832.500,240.330 941.470,352.000"/>
<Path StrokeThickness="35.0" Stroke="#ff000000" StrokeStartLineCap="Round" StrokeEndLineCap="Round" StrokeLineJoin="Round" Data=" M 346.620,660.000 C 384.600,610.221 444.550,578.100 512.000,578.100 C 579.900,578.100 640.200,610.650 678.140,661.000"/>
<Path StrokeThickness="70.0" Stroke="#ff000000" StrokeStartLineCap="Round" StrokeEndLineCap="Round" StrokeLineJoin="Round" Data=" M 346.620,660.000 C 384.600,610.221 444.550,578.100 512.000,578.100 C 579.900,578.100 640.200,610.650 678.140,661.000"/>
<Path StrokeThickness="35.0" Stroke="#ff000000" StrokeStartLineCap="Round" StrokeEndLineCap="Round" StrokeLineJoin="Round" Data=" M 213.050,505.000 C 288.650,426.810 394.650,378.200 512.000,378.200 C 629.350,378.200 735.350,426.810 810.950,505.000"/>
<Path StrokeThickness="70.0" Stroke="#ff000000" StrokeStartLineCap="Round" StrokeEndLineCap="Round" StrokeLineJoin="Round" Data=" M 213.050,505.000 C 288.650,426.810 394.650,378.200 512.000,378.200 C 629.350,378.200 735.350,426.810 810.950,505.000"/>
</Canvas>
</Canvas>
</Viewbox>

View file

@ -0,0 +1,16 @@
<Viewbox
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<Canvas Width="1024.000" Height="1024.000">
<Canvas>
<Path Data=" M 0.000,0.000 L 1024.000,0.000 L 1024.000,1024.000 L 0.000,1024.000 L 0.000,0.000 Z"/>
<Path StrokeThickness="1.0" Stroke="#ff000000" StrokeStartLineCap="Round" StrokeEndLineCap="Round" StrokeLineJoin="Round" Fill="#ff000000" Data=" M 467.000,811.000 C 467.000,786.150 487.150,766.000 512.000,766.000 C 536.850,766.000 557.000,786.150 557.000,811.000 C 557.000,835.850 536.850,856.000 512.000,856.000 C 487.150,856.000 467.000,835.850 467.000,811.000 Z"/>
<Path StrokeThickness="35.0" Stroke="#ff000000" StrokeStartLineCap="Round" StrokeEndLineCap="Round" StrokeLineJoin="Round" Data=" M 82.530,352.000 C 191.500,240.330 343.650,171.000 512.000,171.000 C 680.350,171.000 832.500,240.330 941.470,352.000"/>
<Path StrokeThickness="70.0" Stroke="#ffdddddd" StrokeStartLineCap="Round" StrokeEndLineCap="Round" StrokeLineJoin="Round" Data=" M 82.530,352.000 C 191.500,240.330 343.650,171.000 512.000,171.000 C 680.350,171.000 832.500,240.330 941.470,352.000"/>
<Path StrokeThickness="35.0" Stroke="#ff000000" StrokeStartLineCap="Round" StrokeEndLineCap="Round" StrokeLineJoin="Round" Data=" M 346.620,660.000 C 384.600,610.220 444.550,578.100 512.000,578.100 C 579.900,578.100 640.200,610.650 678.140,661.000"/>
<Path StrokeThickness="70.0" Stroke="#ff000000" StrokeStartLineCap="Round" StrokeEndLineCap="Round" StrokeLineJoin="Round" Data=" M 346.620,660.000 C 384.600,610.220 444.550,578.100 512.000,578.100 C 579.900,578.100 640.200,610.650 678.140,661.000"/>
<Path StrokeThickness="35.0" Stroke="#ff000000" StrokeStartLineCap="Round" StrokeEndLineCap="Round" StrokeLineJoin="Round" Data=" M 213.050,505.000 C 288.650,426.810 394.650,378.200 512.000,378.200 C 629.350,378.200 735.350,426.810 810.950,505.000"/>
<Path StrokeThickness="70.0" Stroke="#ffdddddd" StrokeStartLineCap="Round" StrokeEndLineCap="Round" StrokeLineJoin="Round" Data=" M 213.050,505.000 C 288.650,426.810 394.650,378.200 512.000,378.200 C 629.350,378.200 735.350,426.810 810.950,505.000"/>
</Canvas>
</Canvas>
</Viewbox>

View file

@ -0,0 +1,16 @@
<Viewbox
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<Canvas Width="1024.000" Height="1024.000">
<Canvas>
<Path Data=" M 0.000,0.000 L 1024.000,0.000 L 1024.000,1024.000 L 0.000,1024.000 L 0.000,0.000 Z"/>
<Path StrokeThickness="1.0" Stroke="#ff000000" StrokeStartLineCap="Round" StrokeEndLineCap="Round" StrokeLineJoin="Round" Fill="#ff000000" Data=" M 467.000,811.000 C 467.000,786.150 487.150,766.000 512.000,766.000 C 536.850,766.000 557.000,786.150 557.000,811.000 C 557.000,835.850 536.850,856.000 512.000,856.000 C 487.150,856.000 467.000,835.850 467.000,811.000 Z"/>
<Path StrokeThickness="35.0" Stroke="#ff000000" StrokeStartLineCap="Round" StrokeEndLineCap="Round" StrokeLineJoin="Round" Data=" M 82.530,352.000 C 191.500,240.330 343.650,171.000 512.000,171.000 C 680.350,171.000 832.500,240.330 941.470,352.000"/>
<Path StrokeThickness="70.0" Stroke="#ffdddddd" StrokeStartLineCap="Round" StrokeEndLineCap="Round" StrokeLineJoin="Round" Data=" M 82.530,352.000 C 191.500,240.330 343.650,171.000 512.000,171.000 C 680.350,171.000 832.500,240.330 941.470,352.000"/>
<Path StrokeThickness="35.0" Stroke="#ff000000" StrokeStartLineCap="Round" StrokeEndLineCap="Round" StrokeLineJoin="Round" Data=" M 346.620,660.000 C 384.600,610.220 444.550,578.100 512.000,578.100 C 579.900,578.100 640.200,610.650 678.140,661.000"/>
<Path StrokeThickness="70.0" Stroke="#ff000000" StrokeStartLineCap="Round" StrokeEndLineCap="Round" StrokeLineJoin="Round" Data=" M 346.620,660.000 C 384.600,610.220 444.550,578.100 512.000,578.100 C 579.900,578.100 640.200,610.650 678.140,661.000"/>
<Path StrokeThickness="35.0" Stroke="#ff000000" StrokeStartLineCap="Round" StrokeEndLineCap="Round" StrokeLineJoin="Round" Data=" M 213.050,505.000 C 288.650,426.810 394.650,378.200 512.000,378.200 C 629.350,378.200 735.350,426.810 810.950,505.000"/>
<Path StrokeThickness="70.0" Stroke="#ff000000" StrokeStartLineCap="Round" StrokeEndLineCap="Round" StrokeLineJoin="Round" Data=" M 213.050,505.000 C 288.650,426.810 394.650,378.200 512.000,378.200 C 629.350,378.200 735.350,426.810 810.950,505.000"/>
</Canvas>
</Canvas>
</Viewbox>

View file

@ -4,11 +4,17 @@
xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:SafeExamBrowser.UserInterface.Desktop" xmlns:local="clr-namespace:SafeExamBrowser.UserInterface.Desktop"
mc:Ignorable="d" mc:Ignorable="d" Title="{Binding Path=WindowTitle}" Background="Black" Height="500" Width="1100" MinHeight="350" MinWidth="350"
Title="{Binding Path=WindowTitle}" Background="WhiteSmoke" Height="500" Width="1100" MinHeight="350" MinWidth="350"
WindowStartupLocation="CenterScreen" Icon="./Images/LogNotification.ico"> WindowStartupLocation="CenterScreen" Icon="./Images/LogNotification.ico">
<Window.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="./Templates/ScrollViewers.xaml" />
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
</Window.Resources>
<Grid> <Grid>
<ScrollViewer x:Name="ScrollViewer" HorizontalScrollBarVisibility="Auto" Padding="5,5,5,0" VerticalScrollBarVisibility="Auto"> <ScrollViewer x:Name="ScrollViewer" HorizontalScrollBarVisibility="Auto" Padding="5,5,5,0" VerticalScrollBarVisibility="Auto" Template="{StaticResource SmallBarScrollViewer}">
<TextBlock x:Name="LogContent" FontFamily="Consolas" /> <TextBlock x:Name="LogContent" FontFamily="Consolas" />
</ScrollViewer> </ScrollViewer>
</Grid> </Grid>

View file

@ -92,6 +92,12 @@
<Compile Include="Controls\ActionCenterPowerSupplyControl.xaml.cs"> <Compile Include="Controls\ActionCenterPowerSupplyControl.xaml.cs">
<DependentUpon>ActionCenterPowerSupplyControl.xaml</DependentUpon> <DependentUpon>ActionCenterPowerSupplyControl.xaml</DependentUpon>
</Compile> </Compile>
<Compile Include="Controls\ActionCenterWirelessNetworkButton.xaml.cs">
<DependentUpon>ActionCenterWirelessNetworkButton.xaml</DependentUpon>
</Compile>
<Compile Include="Controls\ActionCenterWirelessNetworkControl.xaml.cs">
<DependentUpon>ActionCenterWirelessNetworkControl.xaml</DependentUpon>
</Compile>
<Compile Include="Controls\TaskbarApplicationControl.xaml.cs"> <Compile Include="Controls\TaskbarApplicationControl.xaml.cs">
<DependentUpon>TaskbarApplicationControl.xaml</DependentUpon> <DependentUpon>TaskbarApplicationControl.xaml</DependentUpon>
</Compile> </Compile>
@ -116,11 +122,11 @@
<Compile Include="Controls\QuitButton.xaml.cs"> <Compile Include="Controls\QuitButton.xaml.cs">
<DependentUpon>QuitButton.xaml</DependentUpon> <DependentUpon>QuitButton.xaml</DependentUpon>
</Compile> </Compile>
<Compile Include="Controls\WirelessNetworkButton.xaml.cs"> <Compile Include="Controls\TaskbarWirelessNetworkButton.xaml.cs">
<DependentUpon>WirelessNetworkButton.xaml</DependentUpon> <DependentUpon>TaskbarWirelessNetworkButton.xaml</DependentUpon>
</Compile> </Compile>
<Compile Include="Controls\WirelessNetworkControl.xaml.cs"> <Compile Include="Controls\TaskbarWirelessNetworkControl.xaml.cs">
<DependentUpon>WirelessNetworkControl.xaml</DependentUpon> <DependentUpon>TaskbarWirelessNetworkControl.xaml</DependentUpon>
</Compile> </Compile>
<Compile Include="LogWindow.xaml.cs"> <Compile Include="LogWindow.xaml.cs">
<DependentUpon>LogWindow.xaml</DependentUpon> <DependentUpon>LogWindow.xaml</DependentUpon>
@ -179,6 +185,14 @@
<SubType>Designer</SubType> <SubType>Designer</SubType>
<Generator>MSBuild:Compile</Generator> <Generator>MSBuild:Compile</Generator>
</Page> </Page>
<Page Include="Controls\ActionCenterWirelessNetworkButton.xaml">
<SubType>Designer</SubType>
<Generator>MSBuild:Compile</Generator>
</Page>
<Page Include="Controls\ActionCenterWirelessNetworkControl.xaml">
<SubType>Designer</SubType>
<Generator>MSBuild:Compile</Generator>
</Page>
<Page Include="Controls\TaskbarApplicationControl.xaml"> <Page Include="Controls\TaskbarApplicationControl.xaml">
<SubType>Designer</SubType> <SubType>Designer</SubType>
<Generator>MSBuild:Compile</Generator> <Generator>MSBuild:Compile</Generator>
@ -215,6 +229,22 @@
<SubType>Designer</SubType> <SubType>Designer</SubType>
<Generator>MSBuild:Compile</Generator> <Generator>MSBuild:Compile</Generator>
</Resource> </Resource>
<Resource Include="Images\WiFi_Light_66.xaml">
<Generator>MSBuild:Compile</Generator>
<SubType>Designer</SubType>
</Resource>
<Resource Include="Images\WiFi_Light_33.xaml">
<Generator>MSBuild:Compile</Generator>
<SubType>Designer</SubType>
</Resource>
<Resource Include="Images\WiFi_Light_100.xaml">
<Generator>MSBuild:Compile</Generator>
<SubType>Designer</SubType>
</Resource>
<Resource Include="Images\WiFi_Light_0.xaml">
<Generator>MSBuild:Compile</Generator>
<SubType>Designer</SubType>
</Resource>
<Page Include="Templates\ScrollViewers.xaml"> <Page Include="Templates\ScrollViewers.xaml">
<SubType>Designer</SubType> <SubType>Designer</SubType>
<Generator>MSBuild:Compile</Generator> <Generator>MSBuild:Compile</Generator>
@ -271,11 +301,11 @@
<Generator>MSBuild:Compile</Generator> <Generator>MSBuild:Compile</Generator>
<SubType>Designer</SubType> <SubType>Designer</SubType>
</Resource> </Resource>
<Page Include="Controls\WirelessNetworkButton.xaml"> <Page Include="Controls\TaskbarWirelessNetworkButton.xaml">
<SubType>Designer</SubType> <SubType>Designer</SubType>
<Generator>MSBuild:Compile</Generator> <Generator>MSBuild:Compile</Generator>
</Page> </Page>
<Page Include="Controls\WirelessNetworkControl.xaml"> <Page Include="Controls\TaskbarWirelessNetworkControl.xaml">
<SubType>Designer</SubType> <SubType>Designer</SubType>
<Generator>MSBuild:Compile</Generator> <Generator>MSBuild:Compile</Generator>
</Page> </Page>

View file

@ -157,9 +157,16 @@ namespace SafeExamBrowser.UserInterface.Desktop
return splashScreen; return splashScreen;
} }
public ISystemWirelessNetworkControl CreateWirelessNetworkControl() public ISystemWirelessNetworkControl CreateWirelessNetworkControl(Location location)
{ {
return new WirelessNetworkControl(); if (location == Location.ActionCenter)
{
return new ActionCenterWirelessNetworkControl();
}
else
{
return new TaskbarWirelessNetworkControl();
}
} }
private void InitializeFontAwesome() private void InitializeFontAwesome()

View file

@ -54,7 +54,7 @@ namespace SafeExamBrowser.UserInterface.Desktop.ViewModels
{ {
var isHeader = logText.Text.StartsWith("/* "); var isHeader = logText.Text.StartsWith("/* ");
var isComment = logText.Text.StartsWith("# "); var isComment = logText.Text.StartsWith("# ");
var brush = isHeader || isComment ? Brushes.ForestGreen : textBlock.Foreground; var brush = isHeader || isComment ? Brushes.LimeGreen : textBlock.Foreground;
textBlock.Inlines.Add(new Run($"{logText.Text}{Environment.NewLine}") textBlock.Inlines.Add(new Run($"{logText.Text}{Environment.NewLine}")
{ {
@ -74,7 +74,7 @@ namespace SafeExamBrowser.UserInterface.Desktop.ViewModels
var threadName = message.ThreadInfo.HasName ? ": " + message.ThreadInfo.Name : string.Empty; var threadName = message.ThreadInfo.HasName ? ": " + message.ThreadInfo.Name : string.Empty;
var threadInfo = $"[{threadId}{threadName}]"; var threadInfo = $"[{threadId}{threadName}]";
var infoRun = new Run($"{date} {threadInfo} - ") { Foreground = Brushes.Gray }; var infoRun = new Run($"{date} {threadInfo} - ") { Foreground = Brushes.DarkGray };
var messageRun = new Run($"{severity}: {message.Message}{Environment.NewLine}") { Foreground = GetBrushFor(message.Severity) }; var messageRun = new Run($"{severity}: {message.Message}{Environment.NewLine}") { Foreground = GetBrushFor(message.Severity) };
textBlock.Inlines.Add(infoRun); textBlock.Inlines.Add(infoRun);
@ -87,13 +87,13 @@ namespace SafeExamBrowser.UserInterface.Desktop.ViewModels
switch (severity) switch (severity)
{ {
case LogLevel.Debug: case LogLevel.Debug:
return Brushes.Gray; return Brushes.DarkGray;
case LogLevel.Error: case LogLevel.Error:
return Brushes.Red; return Brushes.Red;
case LogLevel.Warning: case LogLevel.Warning:
return Brushes.Orange; return Brushes.Orange;
default: default:
return Brushes.Black; return Brushes.White;
} }
} }
} }