SEBWIN-104: Revived the about window and overhauled taskbar layout.

This commit is contained in:
dbuechel 2019-01-09 11:17:43 +01:00
parent d4ef20bd9f
commit 32cecbd5e2
16 changed files with 94 additions and 36 deletions

View file

@ -25,6 +25,8 @@ namespace SafeExamBrowser.Client.UnitTests.Operations
{ {
private Mock<ILogger> loggerMock; private Mock<ILogger> loggerMock;
private TaskbarSettings settings; private TaskbarSettings settings;
private Mock<INotificationInfo> aboutInfoMock;
private Mock<INotificationController> aboutControllerMock;
private Mock<INotificationInfo> logInfoMock; private Mock<INotificationInfo> logInfoMock;
private Mock<INotificationController> logControllerMock; private Mock<INotificationController> logControllerMock;
private Mock<ISystemComponent<ISystemKeyboardLayoutControl>> keyboardLayoutMock; private Mock<ISystemComponent<ISystemKeyboardLayoutControl>> keyboardLayoutMock;
@ -41,6 +43,8 @@ namespace SafeExamBrowser.Client.UnitTests.Operations
public void Initialize() public void Initialize()
{ {
loggerMock = new Mock<ILogger>(); loggerMock = new Mock<ILogger>();
aboutInfoMock = new Mock<INotificationInfo>();
aboutControllerMock = new Mock<INotificationController>();
logInfoMock = new Mock<INotificationInfo>(); logInfoMock = new Mock<INotificationInfo>();
logControllerMock = new Mock<INotificationController>(); logControllerMock = new Mock<INotificationController>();
keyboardLayoutMock = new Mock<ISystemComponent<ISystemKeyboardLayoutControl>>(); keyboardLayoutMock = new Mock<ISystemComponent<ISystemKeyboardLayoutControl>>();
@ -60,6 +64,8 @@ namespace SafeExamBrowser.Client.UnitTests.Operations
sut = new TaskbarOperation( sut = new TaskbarOperation(
loggerMock.Object, loggerMock.Object,
aboutInfoMock.Object,
aboutControllerMock.Object,
logInfoMock.Object, logInfoMock.Object,
logControllerMock.Object, logControllerMock.Object,
keyboardLayoutMock.Object, keyboardLayoutMock.Object,

View file

@ -223,12 +223,14 @@ namespace SafeExamBrowser.Client
private IOperation BuildTaskbarOperation() private IOperation BuildTaskbarOperation()
{ {
var aboutInfo = new AboutNotificationInfo(text);
var aboutController = new AboutNotificationController(configuration.AppConfig, uiFactory);
var keyboardLayout = new KeyboardLayout(new ModuleLogger(logger, nameof(KeyboardLayout)), text); var keyboardLayout = new KeyboardLayout(new ModuleLogger(logger, nameof(KeyboardLayout)), text);
var logController = new LogNotificationController(logger, uiFactory); var logController = new LogNotificationController(logger, uiFactory);
var logInfo = new LogNotificationInfo(text); var logInfo = new LogNotificationInfo(text);
var powerSupply = new PowerSupply(new ModuleLogger(logger, nameof(PowerSupply)), text); var powerSupply = new PowerSupply(new ModuleLogger(logger, nameof(PowerSupply)), text);
var wirelessNetwork = new WirelessNetwork(new ModuleLogger(logger, nameof(WirelessNetwork)), text); var wirelessNetwork = new WirelessNetwork(new ModuleLogger(logger, nameof(WirelessNetwork)), text);
var operation = new TaskbarOperation(logger, logInfo, logController, keyboardLayout, powerSupply, wirelessNetwork, systemInfo, Taskbar, configuration.Settings.Taskbar, text, uiFactory); var operation = new TaskbarOperation(logger, aboutInfo, aboutController, logInfo, logController, keyboardLayout, powerSupply, wirelessNetwork, systemInfo, Taskbar, configuration.Settings.Taskbar, text, uiFactory);
return operation; return operation;
} }

View file

@ -13,8 +13,8 @@ namespace SafeExamBrowser.Client.Notifications
{ {
internal class AboutNotificationIconResource : IIconResource internal class AboutNotificationIconResource : IIconResource
{ {
public Uri Uri => new Uri("pack://application:,,,/SafeExamBrowser;component/SafeExamBrowser.ico"); public Uri Uri => new Uri("pack://application:,,,/SafeExamBrowser.UserInterface.Classic;component/Images/AboutNotification.xaml");
public bool IsBitmapResource => true; public bool IsBitmapResource => false;
public bool IsXamlResource => false; public bool IsXamlResource => true;
} }
} }

View file

@ -22,6 +22,8 @@ namespace SafeExamBrowser.Client.Operations
internal class TaskbarOperation : IOperation internal class TaskbarOperation : IOperation
{ {
private ILogger logger; private ILogger logger;
private INotificationInfo aboutInfo;
private INotificationController aboutController;
private INotificationInfo logInfo; private INotificationInfo logInfo;
private INotificationController logController; private INotificationController logController;
private TaskbarSettings settings; private TaskbarSettings settings;
@ -38,6 +40,8 @@ namespace SafeExamBrowser.Client.Operations
public TaskbarOperation( public TaskbarOperation(
ILogger logger, ILogger logger,
INotificationInfo aboutInfo,
INotificationController aboutController,
INotificationInfo logInfo, INotificationInfo logInfo,
INotificationController logController, INotificationController logController,
ISystemComponent<ISystemKeyboardLayoutControl> keyboardLayout, ISystemComponent<ISystemKeyboardLayoutControl> keyboardLayout,
@ -49,6 +53,8 @@ namespace SafeExamBrowser.Client.Operations
IText text, IText text,
IUserInterfaceFactory uiFactory) IUserInterfaceFactory uiFactory)
{ {
this.aboutInfo = aboutInfo;
this.aboutController = aboutController;
this.logger = logger; this.logger = logger;
this.logInfo = logInfo; this.logInfo = logInfo;
this.logController = logController; this.logController = logController;
@ -67,6 +73,8 @@ namespace SafeExamBrowser.Client.Operations
logger.Info("Initializing taskbar..."); logger.Info("Initializing taskbar...");
StatusChanged?.Invoke(TextKey.OperationStatus_InitializeTaskbar); StatusChanged?.Invoke(TextKey.OperationStatus_InitializeTaskbar);
AddAboutNotification();
if (settings.AllowApplicationLog) if (settings.AllowApplicationLog)
{ {
CreateLogNotification(); CreateLogNotification();
@ -77,16 +85,16 @@ namespace SafeExamBrowser.Client.Operations
AddKeyboardLayoutControl(); AddKeyboardLayoutControl();
} }
if (systemInfo.HasBattery)
{
AddPowerSupplyControl();
}
if (settings.AllowWirelessNetwork) if (settings.AllowWirelessNetwork)
{ {
AddWirelessNetworkControl(); AddWirelessNetworkControl();
} }
if (systemInfo.HasBattery)
{
AddPowerSupplyControl();
}
return OperationResult.Success; return OperationResult.Success;
} }
@ -95,6 +103,8 @@ namespace SafeExamBrowser.Client.Operations
logger.Info("Terminating taskbar..."); logger.Info("Terminating taskbar...");
StatusChanged?.Invoke(TextKey.OperationStatus_TerminateTaskbar); StatusChanged?.Invoke(TextKey.OperationStatus_TerminateTaskbar);
aboutController.Terminate();
if (settings.AllowApplicationLog) if (settings.AllowApplicationLog)
{ {
logController.Terminate(); logController.Terminate();
@ -105,19 +115,27 @@ namespace SafeExamBrowser.Client.Operations
keyboardLayout.Terminate(); keyboardLayout.Terminate();
} }
if (systemInfo.HasBattery)
{
powerSupply.Terminate();
}
if (settings.AllowWirelessNetwork) if (settings.AllowWirelessNetwork)
{ {
wirelessNetwork.Terminate(); wirelessNetwork.Terminate();
} }
if (systemInfo.HasBattery)
{
powerSupply.Terminate();
}
return OperationResult.Success; return OperationResult.Success;
} }
private void AddAboutNotification()
{
var aboutNotification = uiFactory.CreateNotification(aboutInfo);
aboutController.RegisterNotification(aboutNotification);
taskbar.AddNotification(aboutNotification);
}
private void AddKeyboardLayoutControl() private void AddKeyboardLayoutControl()
{ {
var control = uiFactory.CreateKeyboardLayoutControl(); var control = uiFactory.CreateKeyboardLayoutControl();

View file

@ -63,7 +63,7 @@ namespace SafeExamBrowser.SystemComponents
{ {
var charge = SystemInformation.PowerStatus.BatteryLifePercent; var charge = SystemInformation.PowerStatus.BatteryLifePercent;
var percentage = Math.Round(charge * 100); var percentage = Math.Round(charge * 100);
var status = charge <= 0.35 ? (charge <= 0.2 ? BatteryChargeStatus.Critical : BatteryChargeStatus.Low) : BatteryChargeStatus.Okay; var status = charge <= 0.4 ? (charge <= 0.2 ? BatteryChargeStatus.Critical : BatteryChargeStatus.Low) : BatteryChargeStatus.Okay;
var online = SystemInformation.PowerStatus.PowerLineStatus == PowerLineStatus.Online; var online = SystemInformation.PowerStatus.PowerLineStatus == PowerLineStatus.Online;
var tooltip = string.Empty; var tooltip = string.Empty;

View file

@ -5,19 +5,19 @@
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:SafeExamBrowser.UserInterface.Classic" xmlns:local="clr-namespace:SafeExamBrowser.UserInterface.Classic"
mc:Ignorable="d" mc:Ignorable="d"
Title="About Safe Exam Browser" Background="White" Height="350" Width="450" ResizeMode="NoResize" Icon="./Images/SafeExamBrowser.ico" Title="Version &amp; License Information" Background="White" Height="325" Width="600" ResizeMode="NoResize" Icon="./Images/SafeExamBrowser.ico"
ShowInTaskbar="False" WindowStartupLocation="CenterScreen"> ShowInTaskbar="False" WindowStartupLocation="CenterScreen">
<Grid> <Grid>
<Grid.RowDefinitions> <Grid.RowDefinitions>
<RowDefinition /> <RowDefinition Height="*" />
<RowDefinition /> <RowDefinition Height="Auto" />
</Grid.RowDefinitions> </Grid.RowDefinitions>
<Grid.ColumnDefinitions> <Grid.ColumnDefinitions>
<ColumnDefinition /> <ColumnDefinition />
<ColumnDefinition /> <ColumnDefinition />
</Grid.ColumnDefinitions> </Grid.ColumnDefinitions>
<Image Grid.ColumnSpan="2" Source="pack://application:,,,/SafeExamBrowser.UserInterface.Classic;component/Images/SplashScreen.png" Margin="0,5,0,0" /> <Image Grid.ColumnSpan="2" Source="pack://application:,,,/SafeExamBrowser.UserInterface.Classic;component/Images/SplashScreen.png" Margin="0,5,0,0" />
<TextBlock x:Name="VersionInfo" Grid.Row="0" Grid.Column="1" Foreground="Gray" Margin="25,70,50,10" TextWrapping="Wrap" /> <TextBlock x:Name="VersionInfo" Grid.Row="0" Grid.Column="1" Foreground="Gray" Margin="25,75,125,10" TextWrapping="Wrap" />
<ScrollViewer Grid.Row="1" Grid.Column="0" Grid.ColumnSpan="2" VerticalScrollBarVisibility="Auto"> <ScrollViewer Grid.Row="1" Grid.Column="0" Grid.ColumnSpan="2" VerticalScrollBarVisibility="Auto">
<TextBlock x:Name="MainText" Margin="10" FontSize="10" TextWrapping="Wrap"> <TextBlock x:Name="MainText" Margin="10" FontSize="10" TextWrapping="Wrap">
This application is subject to the terms of the Mozilla Public License, v. 2.0. If a copy of the MPL was not distributed This application is subject to the terms of the Mozilla Public License, v. 2.0. If a copy of the MPL was not distributed
@ -26,7 +26,7 @@
<LineBreak /> <LineBreak />
<Bold><Underline>CefSharp (.NET bindings for the Chromium Embedded Framework)</Underline></Bold> <Bold><Underline>CefSharp (.NET bindings for the Chromium Embedded Framework)</Underline></Bold>
<LineBreak /> <LineBreak />
Copyright © 2010-2017 The CefSharp Authors. All rights reserved. Copyright © 2010-2019 The CefSharp Authors. All rights reserved.
<LineBreak /> <LineBreak />
<LineBreak /> <LineBreak />
<Bold><Underline>CEF (Chromium Embedded Framework)</Underline></Bold> <Bold><Underline>CEF (Chromium Embedded Framework)</Underline></Bold>

View file

@ -3,6 +3,7 @@
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.Classic.Controls" xmlns:local="clr-namespace:SafeExamBrowser.UserInterface.Classic.Controls"
mc:Ignorable="d" d:DesignHeight="40" d:DesignWidth="40"> mc:Ignorable="d" d:DesignHeight="40" d:DesignWidth="40">
@ -25,15 +26,23 @@
</ScrollViewer> </ScrollViewer>
</Border> </Border>
</Popup> </Popup>
<Button x:Name="Button" Background="Transparent" HorizontalContentAlignment="Stretch" Template="{StaticResource TaskbarButton}" <Button x:Name="Button" Background="Transparent" Template="{StaticResource TaskbarButton}" Padding="5" Width="40">
VerticalContentAlignment="Stretch" Width="40">
<Grid> <Grid>
<Grid.RowDefinitions> <fa:ImageAwesome Panel.ZIndex="1" Foreground="LightGray" Icon="KeyboardOutline" VerticalAlignment="Center" />
<RowDefinition Height="*" /> <Viewbox Panel.ZIndex="2" Stretch="Uniform">
<RowDefinition Height="*" /> <StackPanel Orientation="Vertical">
</Grid.RowDefinitions> <TextBlock x:Name="LayoutCultureCode" FontWeight="Bold" TextAlignment="Center" Text="ENG">
<TextBlock x:Name="LayoutCultureCode" Grid.Row="0" HorizontalAlignment="Center" VerticalAlignment="Bottom" /> <TextBlock.Effect>
<TextBlock x:Name="LayoutName" Grid.Row="1" HorizontalAlignment="Center" VerticalAlignment="Top" /> <DropShadowEffect Color="White" BlurRadius="5" Direction="0" Opacity="1" ShadowDepth="0" />
</TextBlock.Effect>
</TextBlock>
<TextBlock x:Name="LayoutName" Foreground="Gray" TextAlignment="Center" Text="SG">
<TextBlock.Effect>
<DropShadowEffect Color="White" BlurRadius="5" Direction="0" Opacity="1" ShadowDepth="0" />
</TextBlock.Effect>
</TextBlock>
</StackPanel>
</Viewbox>
</Grid> </Grid>
</Button> </Button>
</Grid> </Grid>

View file

@ -80,7 +80,7 @@ namespace SafeExamBrowser.UserInterface.Classic.Controls
private void SetCurrent(KeyboardLayoutButton button, IKeyboardLayout layout) private void SetCurrent(KeyboardLayoutButton button, IKeyboardLayout layout)
{ {
var name = layout.Name?.Length > 3 ? String.Join(string.Empty, layout.Name.Split(' ').Select(s => s.First())) : layout.Name; var name = layout.Name?.Length > 3 ? String.Join(string.Empty, layout.Name.Split(' ').Where(s => Char.IsLetter(s.First())).Select(s => s.First())) : layout.Name;
foreach (var child in LayoutsStackPanel.Children) foreach (var child in LayoutsStackPanel.Children)
{ {

View file

@ -14,6 +14,6 @@
</ResourceDictionary> </ResourceDictionary>
</UserControl.Resources> </UserControl.Resources>
<Grid> <Grid>
<Button x:Name="IconButton" Background="{StaticResource BackgroundBrush}" Click="Icon_Click" Padding="5,0" Template="{StaticResource TaskbarButton}" Width="40"/> <Button x:Name="IconButton" Background="{StaticResource BackgroundBrush}" Click="Icon_Click" Padding="7.5" Template="{StaticResource TaskbarButton}" Width="40" />
</Grid> </Grid>
</UserControl> </UserControl>

View file

@ -33,7 +33,7 @@
</Grid> </Grid>
</Border> </Border>
</Popup> </Popup>
<Button x:Name="Button" Background="Transparent" IsEnabled="False" Template="{StaticResource TaskbarButton}" ToolTipService.ShowOnDisabled="True"> <Button x:Name="Button" Background="Transparent" IsEnabled="False" Padding="5" Template="{StaticResource TaskbarButton}" ToolTipService.ShowOnDisabled="True">
<Viewbox Stretch="Uniform" Width="Auto"> <Viewbox Stretch="Uniform" Width="Auto">
<Canvas Height="40" Width="40"> <Canvas Height="40" Width="40">
<Viewbox Stretch="Uniform" Width="40" Panel.ZIndex="2"> <Viewbox Stretch="Uniform" Width="40" Panel.ZIndex="2">

View file

@ -26,7 +26,7 @@
</ScrollViewer> </ScrollViewer>
</Border> </Border>
</Popup> </Popup>
<Button x:Name="Button" Background="Transparent" HorizontalContentAlignment="Stretch" Template="{StaticResource TaskbarButton}" <Button x:Name="Button" Background="Transparent" HorizontalContentAlignment="Stretch" Padding="5" Template="{StaticResource TaskbarButton}"
ToolTipService.ShowOnDisabled="True" VerticalContentAlignment="Stretch" Width="40"> ToolTipService.ShowOnDisabled="True" VerticalContentAlignment="Stretch" Width="40">
<Grid> <Grid>
<Viewbox x:Name="SignalStrengthIcon" Stretch="Uniform" Width="Auto" /> <Viewbox x:Name="SignalStrengthIcon" Stretch="Uniform" Width="Auto" />

View file

@ -0,0 +1,8 @@
<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 Foreground="Gray" Icon="InfoCircle" Margin="10" />
</Grid>
</Viewbox>

View file

@ -222,6 +222,10 @@
<SubType>Designer</SubType> <SubType>Designer</SubType>
<Generator>MSBuild:Compile</Generator> <Generator>MSBuild:Compile</Generator>
</Page> </Page>
<Resource Include="Images\AboutNotification.xaml">
<SubType>Designer</SubType>
<Generator>MSBuild:Compile</Generator>
</Resource>
<Page Include="LogWindow.xaml"> <Page Include="LogWindow.xaml">
<SubType>Designer</SubType> <SubType>Designer</SubType>
<Generator>MSBuild:Compile</Generator> <Generator>MSBuild:Compile</Generator>

View file

@ -22,9 +22,9 @@
</ScrollViewer.Resources> </ScrollViewer.Resources>
<StackPanel x:Name="ApplicationStackPanel" Orientation="Horizontal" /> <StackPanel x:Name="ApplicationStackPanel" Orientation="Horizontal" />
</ScrollViewer> </ScrollViewer>
<local:DateTimeControl Grid.Column="1" Foreground="DimGray" /> <StackPanel Grid.Column="1" x:Name="NotificationStackPanel" Orientation="Horizontal" VerticalAlignment="Stretch" />
<StackPanel Grid.Column="2" x:Name="NotificationStackPanel" Margin="5,0,0,0" Orientation="Horizontal" VerticalAlignment="Stretch" /> <StackPanel Grid.Column="2" x:Name="SystemControlStackPanel" Orientation="Horizontal" VerticalAlignment="Stretch" />
<StackPanel Grid.Column="3" x:Name="SystemControlStackPanel" Orientation="Horizontal" VerticalAlignment="Stretch" /> <local:DateTimeControl Grid.Column="3" Foreground="DimGray" Padding="10,0,10,0" />
<local:QuitButton Grid.Column="4" x:Name="QuitButton" /> <local:QuitButton Grid.Column="4" x:Name="QuitButton" />
</Grid> </Grid>
</Window> </Window>

View file

@ -8,6 +8,8 @@
using System.Threading; using System.Threading;
using System.Windows; using System.Windows;
using System.Windows.Media;
using FontAwesome.WPF;
using SafeExamBrowser.Contracts.Configuration; using SafeExamBrowser.Contracts.Configuration;
using SafeExamBrowser.Contracts.Configuration.Settings; using SafeExamBrowser.Contracts.Configuration.Settings;
using SafeExamBrowser.Contracts.I18n; using SafeExamBrowser.Contracts.I18n;
@ -27,6 +29,8 @@ namespace SafeExamBrowser.UserInterface.Classic
public UserInterfaceFactory(IText text) public UserInterfaceFactory(IText text)
{ {
this.text = text; this.text = text;
InitializeFontAwesome();
} }
public IWindow CreateAboutWindow(AppConfig appConfig) public IWindow CreateAboutWindow(AppConfig appConfig)
@ -122,5 +126,12 @@ namespace SafeExamBrowser.UserInterface.Classic
{ {
return new WirelessNetworkControl(); return new WirelessNetworkControl();
} }
private void InitializeFontAwesome()
{
// To be able to use FontAwesome in XAML icon resources, we need to make sure that the FontAwesome.WPF assembly is loaded into
// the AppDomain before attempting to load an icon resource - thus the creation of an unused image below...
ImageAwesome.CreateImageSource(FontAwesomeIcon.FontAwesome, Brushes.Black);
}
} }
} }

View file

@ -68,7 +68,7 @@ namespace SafeExamBrowser.UserInterface.Classic.ViewModels
{ {
textBlock.Dispatcher.Invoke(() => textBlock.Dispatcher.Invoke(() =>
{ {
var date = message.DateTime.ToString("yyyy-MM-dd HH:mm:ss.fff"); var date = message.DateTime.ToString("HH:mm:ss.fff");
var severity = message.Severity.ToString().ToUpper(); var severity = message.Severity.ToString().ToUpper();
var threadId = message.ThreadInfo.Id < 10 ? $"0{message.ThreadInfo.Id}" : message.ThreadInfo.Id.ToString(); var threadId = message.ThreadInfo.Id < 10 ? $"0{message.ThreadInfo.Id}" : message.ThreadInfo.Id.ToString();
var threadName = message.ThreadInfo.HasName ? ": " + message.ThreadInfo.Name : string.Empty; var threadName = message.ThreadInfo.HasName ? ": " + message.ThreadInfo.Name : string.Empty;