SEBWIN-449: Extended notification mechanism to allow updating of notification icon / text and added icons for proctoring notification.

This commit is contained in:
Damian Büchel 2021-03-25 13:49:45 +01:00
parent 31a16caa87
commit ce67d4a475
22 changed files with 170 additions and 15 deletions

View file

@ -249,7 +249,7 @@ namespace SafeExamBrowser.Client
private IOperation BuildProctoringOperation()
{
var controller = new ProctoringController(context.AppConfig, new FileSystem(), ModuleLogger(nameof(ProctoringController)), uiFactory);
var controller = new ProctoringController(context.AppConfig, new FileSystem(), ModuleLogger(nameof(ProctoringController)), text, uiFactory);
var operation = new ProctoringOperation(actionCenter, context, controller, logger, controller, taskbar, uiFactory);
context.ProctoringController = controller;

View file

@ -9,6 +9,7 @@
using System;
using SafeExamBrowser.Configuration.Contracts;
using SafeExamBrowser.Core.Contracts.Notifications;
using SafeExamBrowser.Core.Contracts.Notifications.Events;
using SafeExamBrowser.Core.Contracts.Resources.Icons;
using SafeExamBrowser.I18n.Contracts;
using SafeExamBrowser.UserInterface.Contracts;
@ -27,6 +28,8 @@ namespace SafeExamBrowser.Client.Notifications
public string Tooltip { get; }
public IconResource IconResource { get; }
public event NotificationChangedEventHandler NotificationChanged { add { } remove { } }
public AboutNotification(AppConfig appConfig, IText text, IUserInterfaceFactory uiFactory)
{
this.appConfig = appConfig;

View file

@ -8,6 +8,7 @@
using System;
using SafeExamBrowser.Core.Contracts.Notifications;
using SafeExamBrowser.Core.Contracts.Notifications.Events;
using SafeExamBrowser.Core.Contracts.Resources.Icons;
using SafeExamBrowser.I18n.Contracts;
using SafeExamBrowser.Logging.Contracts;
@ -27,6 +28,8 @@ namespace SafeExamBrowser.Client.Notifications
public string Tooltip { get; }
public IconResource IconResource { get; }
public event NotificationChangedEventHandler NotificationChanged { add { } remove { } }
public LogNotification(ILogger logger, IText text, IUserInterfaceFactory uiFactory)
{
this.logger = logger;

View file

@ -53,13 +53,13 @@ namespace SafeExamBrowser.Client.Operations
logger.Info("Initializing proctoring...");
StatusChanged?.Invoke(TextKey.OperationStatus_InitializeProctoring);
var actionCenterControl = uiFactory.CreateNotificationControl(notification, Location.ActionCenter);
var taskbarControl = uiFactory.CreateNotificationControl(notification, Location.Taskbar);
controller.Initialize(Context.Settings.Proctoring);
actionCenter.AddNotificationControl(uiFactory.CreateNotificationControl(notification, Location.ActionCenter));
actionCenter.AddNotificationControl(actionCenterControl);
taskbar.AddNotificationControl(taskbarControl);
if (Context.Settings.Proctoring.ShowTaskbarNotification)
{
taskbar.AddNotificationControl(uiFactory.CreateNotificationControl(notification, Location.Taskbar));
}
}
return OperationResult.Success;

View file

@ -6,8 +6,10 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/
using System;
using System.Collections.Generic;
using SafeExamBrowser.Settings;
using SafeExamBrowser.Settings.Proctoring;
namespace SafeExamBrowser.Configuration.ConfigurationData.DataMapping
{
@ -29,9 +31,28 @@ namespace SafeExamBrowser.Configuration.ConfigurationData.DataMapping
case Keys.Proctoring.JitsiMeet.Token:
MapJitsiMeetToken(settings, value);
break;
case Keys.Proctoring.ShowTaskbarNotification:
MapShowTaskbarNotification(settings, value);
break;
case Keys.Proctoring.WindowVisibility:
MapWindowVisibility(settings, value);
break;
}
}
internal override void MapGlobal(IDictionary<string, object> rawData, AppSettings settings)
{
MapProctoringEnabled(rawData, settings);
}
private void MapProctoringEnabled(IDictionary<string, object> rawData, AppSettings settings)
{
var jitsiEnabled = rawData.TryGetValue(Keys.Proctoring.JitsiMeet.Enabled, out var v) && v is bool b && b;
var zoomEnabled = rawData.TryGetValue(Keys.Proctoring.Zoom.Enabled, out v) && v is bool b2 && b2;
settings.Proctoring.Enabled = jitsiEnabled || zoomEnabled;
}
private void MapJitsiMeetRoomName(AppSettings settings, object value)
{
if (value is string name)
@ -64,17 +85,39 @@ namespace SafeExamBrowser.Configuration.ConfigurationData.DataMapping
}
}
internal override void MapGlobal(IDictionary<string, object> rawData, AppSettings settings)
private void MapShowTaskbarNotification(AppSettings settings, object value)
{
MapProctoringEnabled(rawData, settings);
if (value is bool show)
{
settings.Proctoring.ShowTaskbarNotification = show;
}
}
private void MapProctoringEnabled(IDictionary<string, object> rawData, AppSettings settings)
private void MapWindowVisibility(AppSettings settings, object value)
{
var jitsiEnabled = rawData.TryGetValue(Keys.Proctoring.JitsiMeet.Enabled, out var v) && v is bool b && b;
var zoomEnabled = rawData.TryGetValue(Keys.Proctoring.Zoom.Enabled, out v) && v is bool b2 && b2;
const int HIDDEN = 0;
const int ALLOW_SHOW = 1;
const int ALLOW_HIDE = 2;
const int VISIBLE = 3;
settings.Proctoring.Enabled = jitsiEnabled || zoomEnabled;
if (value is int visibility)
{
switch (visibility)
{
case HIDDEN:
settings.Proctoring.WindowVisibility = WindowVisibility.Hidden;
break;
case ALLOW_SHOW:
settings.Proctoring.WindowVisibility = WindowVisibility.AllowToShow;
break;
case ALLOW_HIDE:
settings.Proctoring.WindowVisibility = WindowVisibility.AllowToHide;
break;
case VISIBLE:
settings.Proctoring.WindowVisibility = WindowVisibility.Visible;
break;
}
}
}
}
}

View file

@ -22,6 +22,7 @@ namespace SafeExamBrowser.Configuration.ConfigurationData
AllowBrowserToolbarForReloading(rawData, settings);
CalculateConfigurationKey(rawData, settings);
HandleBrowserHomeFunctionality(settings);
InitializeProctoringSettings(settings);
RemoveLegacyBrowsers(settings);
}
@ -64,6 +65,11 @@ namespace SafeExamBrowser.Configuration.ConfigurationData
settings.Browser.HomePasswordHash = settings.Security.QuitPasswordHash;
}
private void InitializeProctoringSettings(AppSettings settings)
{
settings.Proctoring.Enabled = settings.Proctoring.JitsiMeet.Enabled || settings.Proctoring.Zoom.Enabled;
}
private void RemoveLegacyBrowsers(AppSettings settings)
{
var legacyBrowsers = new List<WhitelistApplication>();

View file

@ -176,6 +176,7 @@ namespace SafeExamBrowser.Configuration.ConfigurationData
settings.Mouse.AllowRightButton = true;
settings.Proctoring.Enabled = false;
settings.Proctoring.ShowTaskbarNotification = true;
settings.Proctoring.WindowVisibility = WindowVisibility.Hidden;
settings.Security.AllowApplicationLogAccess = false;

View file

@ -216,6 +216,7 @@ namespace SafeExamBrowser.Configuration.ConfigurationData
internal static class Proctoring
{
internal const string ShowTaskbarNotification = "showProctoringViewButton";
internal const string WindowVisibility = "remoteProctoringViewShow";
internal static class JitsiMeet

View file

@ -0,0 +1,15 @@
/*
* Copyright (c) 2021 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.Core.Contracts.Notifications.Events
{
/// <summary>
/// Indicates that a notification has changed.
/// </summary>
public delegate void NotificationChangedEventHandler();
}

View file

@ -6,6 +6,7 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/
using SafeExamBrowser.Core.Contracts.Notifications.Events;
using SafeExamBrowser.Core.Contracts.Resources.Icons;
namespace SafeExamBrowser.Core.Contracts.Notifications
@ -25,6 +26,11 @@ namespace SafeExamBrowser.Core.Contracts.Notifications
/// </summary>
IconResource IconResource { get; }
/// <summary>
/// Event fired when the notification has changed.
/// </summary>
event NotificationChangedEventHandler NotificationChanged;
/// <summary>
/// Executes the notification functionality.
/// </summary>

View file

@ -54,6 +54,7 @@
<Reference Include="Microsoft.CSharp" />
</ItemGroup>
<ItemGroup>
<Compile Include="Notifications\Events\NotificationChangedEventHandler.cs" />
<Compile Include="Notifications\INotification.cs" />
<Compile Include="OperationModel\Events\ActionRequiredEventArgs.cs" />
<Compile Include="OperationModel\Events\ActionRequiredEventHandler.cs" />

View file

@ -129,6 +129,8 @@ namespace SafeExamBrowser.I18n.Contracts
MessageBox_YesButton,
Notification_AboutTooltip,
Notification_LogTooltip,
// TODO
Notification_ProctoringTooltip,
OperationStatus_CloseRuntimeConnection,
OperationStatus_EmptyClipboard,
OperationStatus_FinalizeApplications,

View file

@ -11,7 +11,9 @@ using System.IO;
using System.Reflection;
using SafeExamBrowser.Configuration.Contracts;
using SafeExamBrowser.Core.Contracts.Notifications;
using SafeExamBrowser.Core.Contracts.Notifications.Events;
using SafeExamBrowser.Core.Contracts.Resources.Icons;
using SafeExamBrowser.I18n.Contracts;
using SafeExamBrowser.Logging.Contracts;
using SafeExamBrowser.Proctoring.Contracts;
using SafeExamBrowser.Settings.Proctoring;
@ -26,21 +28,28 @@ namespace SafeExamBrowser.Proctoring
private readonly AppConfig appConfig;
private readonly IFileSystem fileSystem;
private readonly IModuleLogger logger;
private readonly IText text;
private readonly IUserInterfaceFactory uiFactory;
private string filePath;
private IProctoringWindow window;
private ProctoringSettings settings;
public string Tooltip => "TODO!!!";
public IconResource IconResource => new XamlIconResource();
public string Tooltip { get; }
public IconResource IconResource { get; set; }
public ProctoringController(AppConfig appConfig, IFileSystem fileSystem, IModuleLogger logger, IUserInterfaceFactory uiFactory)
public event NotificationChangedEventHandler NotificationChanged;
public ProctoringController(AppConfig appConfig, IFileSystem fileSystem, IModuleLogger logger, IText text, IUserInterfaceFactory uiFactory)
{
this.appConfig = appConfig;
this.fileSystem = fileSystem;
this.logger = logger;
this.text = text;
this.uiFactory = uiFactory;
IconResource = new XamlIconResource { Uri = new Uri("pack://application:,,,/SafeExamBrowser.UserInterface.Desktop;component/Images/ProctoringNotification_Inactive.xaml") };
Tooltip = text.Get(TextKey.Notification_ProctoringTooltip);
}
public void Activate()
@ -81,6 +90,9 @@ namespace SafeExamBrowser.Proctoring
}
logger.Info($"Initialized proctoring with {(settings.JitsiMeet.Enabled ? "Jitsi Meet" : "Zoom")}.");
IconResource = new XamlIconResource { Uri = new Uri("pack://application:,,,/SafeExamBrowser.UserInterface.Desktop;component/Images/ProctoringNotification_Active.xaml") };
NotificationChanged?.Invoke();
}
else
{

View file

@ -82,6 +82,10 @@
<Project>{fe0e1224-b447-4b14-81e7-ed7d84822aa0}</Project>
<Name>SafeExamBrowser.Core.Contracts</Name>
</ProjectReference>
<ProjectReference Include="..\SafeExamBrowser.I18n.Contracts\SafeExamBrowser.I18n.Contracts.csproj">
<Project>{1858ddf3-bc2a-4bff-b663-4ce2ffeb8b7d}</Project>
<Name>SafeExamBrowser.I18n.Contracts</Name>
</ProjectReference>
<ProjectReference Include="..\SafeExamBrowser.Logging.Contracts\SafeExamBrowser.Logging.Contracts.csproj">
<Project>{64ea30fb-11d4-436a-9c2b-88566285363e}</Project>
<Name>SafeExamBrowser.Logging.Contracts</Name>

View file

@ -26,6 +26,11 @@ namespace SafeExamBrowser.Settings.Proctoring
/// </summary>
public JitsiMeetSettings JitsiMeet { get; set; }
/// <summary>
/// Determines whether the proctoring notification will be shown in the taskbar.
/// </summary>
public bool ShowTaskbarNotification { get; set; }
/// <summary>
/// Determines the visibility of the proctoring window.
/// </summary>

View file

@ -24,6 +24,7 @@ namespace SafeExamBrowser.UserInterface.Desktop.Controls.ActionCenter
InitializeComponent();
InitializeNotification();
UpdateNotification();
}
private void IconButton_Click(object sender, RoutedEventArgs e)
@ -32,6 +33,11 @@ namespace SafeExamBrowser.UserInterface.Desktop.Controls.ActionCenter
}
private void InitializeNotification()
{
notification.NotificationChanged += () => Dispatcher.Invoke(UpdateNotification);
}
private void UpdateNotification()
{
Icon.Content = IconResourceLoader.Load(notification.IconResource);
IconButton.ToolTip = notification.Tooltip;

View file

@ -24,6 +24,7 @@ namespace SafeExamBrowser.UserInterface.Desktop.Controls.Taskbar
InitializeComponent();
InitializeNotification();
UpdateNotification();
}
private void IconButton_Click(object sender, RoutedEventArgs e)
@ -32,6 +33,11 @@ namespace SafeExamBrowser.UserInterface.Desktop.Controls.Taskbar
}
private void InitializeNotification()
{
notification.NotificationChanged += () => Dispatcher.Invoke(UpdateNotification);
}
private void UpdateNotification()
{
IconButton.ToolTip = notification.Tooltip;
IconButton.Content = IconResourceLoader.Load(notification.IconResource);

View file

@ -0,0 +1,12 @@
<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 Fill="Green" Data="F1 M 556.000,505.189 C 645.504,506.389 716.387,430.101 716.387,329.785 C 716.387,235.474 645.504,157.984 556.000,157.984 C 466.496,157.984 395.614,235.474 396.215,329.785 C 396.816,430.101 466.496,503.987 556.000,505.189 Z"/>
<Path Fill="Green" Data="F1 M 842.535,0.000 L 269.467,0.000 C 174.557,0.000 126.501,47.455 126.501,141.765 L 126.501,533.171 C 133.375,529.423 140.444,525.997 147.700,522.909 C 162.465,516.624 177.660,511.878 193.178,508.681 L 193.178,145.369 C 193.178,93.709 220.810,66.677 270.669,66.677 L 841.333,66.677 C 890.590,66.677 918.823,93.709 918.823,145.369 L 918.823,714.232 C 918.823,741.263 911.014,761.086 896.597,774.302 C 844.336,663.173 728.401,583.880 556.000,583.880 C 511.826,583.880 471.014,589.399 433.878,599.528 C 446.051,615.497 456.175,632.869 464.091,651.466 C 476.793,681.309 483.234,712.908 483.234,745.383 C 483.234,777.859 476.793,809.457 464.091,839.300 C 461.226,846.031 458.062,852.597 454.628,859.000 L 842.535,859.000 C 938.045,859.000 985.500,811.545 985.500,717.835 L 985.500,141.765 C 985.500,48.057 938.045,0.000 842.535,0.000 Z"/>
<Path StrokeThickness="60.0" Stroke="Green" StrokeMiterLimit="1.0" Fill="#00000000" Data="F1 M 219.477,857.005 C 212.097,857.005 203.333,854.238 197.799,848.241 L 129.072,773.058 C 125.383,769.367 123.076,761.988 123.076,755.530 C 123.076,738.926 135.530,727.855 150.290,727.855 C 159.053,727.855 165.972,731.084 170.585,736.619 L 218.093,788.279 L 309.882,660.513 C 314.955,653.594 323.258,648.521 332.944,648.521 C 347.704,648.521 360.158,660.513 360.158,675.734 C 360.158,680.347 358.313,686.343 354.623,691.417 L 242.079,846.858 C 237.466,852.854 228.702,857.005 219.477,857.005 Z M 241.617,933.573 C 344.937,933.573 429.806,848.703 429.806,745.383 C 429.806,642.063 344.937,557.193 241.617,557.193 C 138.298,557.193 53.427,642.063 53.427,745.383 C 53.427,848.703 138.298,933.573 241.617,933.573 Z"/>
<Path Data="F1 M 241.617,503.766 C 209.141,503.766 177.543,510.206 147.700,522.909 C 118.995,535.127 93.189,552.574 70.998,574.764 C 48.808,596.955 31.361,622.761 19.143,651.466 C 6.441,681.309 0.000,712.907 0.000,745.383 C 0.000,777.859 6.441,809.457 19.143,839.300 C 31.361,868.005 48.808,893.811 70.999,916.002 C 93.189,938.192 118.995,955.639 147.700,967.857 C 177.543,980.559 209.141,987.000 241.617,987.000 C 274.092,987.000 305.691,980.559 335.534,967.857 C 364.239,955.639 390.045,938.192 412.236,916.002 C 434.426,893.811 451.873,868.005 464.091,839.300 C 476.793,809.457 483.234,777.859 483.234,745.383 C 483.234,712.908 476.793,681.309 464.091,651.466 C 451.873,622.761 434.427,596.955 412.236,574.764 C 390.045,552.574 364.239,535.127 335.534,522.909 C 305.691,510.206 274.092,503.766 241.617,503.766 L 241.617,503.766 Z M 218.093,788.279 L 170.585,736.619 C 165.972,731.084 159.053,727.855 150.290,727.855 C 135.530,727.855 123.076,738.925 123.076,755.530 C 123.076,761.988 125.383,769.367 129.072,773.058 L 197.799,848.241 C 203.333,854.238 212.097,857.005 219.477,857.005 C 228.702,857.005 237.466,852.854 242.079,846.858 L 354.623,691.417 C 358.314,686.343 360.158,680.347 360.158,675.734 C 360.158,660.513 347.704,648.521 332.944,648.521 C 323.258,648.521 314.955,653.594 309.882,660.513 L 218.093,788.279 M 241.617,557.193 C 344.937,557.193 429.807,642.063 429.807,745.383 C 429.807,848.703 344.937,933.573 241.617,933.573 C 138.298,933.573 53.427,848.703 53.427,745.383 C 53.427,642.063 138.298,557.193 241.617,557.193"/>
</Canvas>
</Canvas>
</Viewbox>

View file

@ -0,0 +1,9 @@
<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 Fill="#ff000000" Data="F1 M 511.000,587.189 C 600.504,588.389 671.387,512.101 671.387,411.785 C 671.387,317.474 600.504,239.984 511.000,239.984 C 421.496,239.984 350.614,317.474 351.215,411.785 C 351.816,512.101 421.496,585.987 511.000,587.189 Z M 511.000,665.880 C 342.805,665.880 223.266,745.773 170.404,856.302 C 155.987,843.687 148.178,823.263 148.178,796.232 L 148.178,227.369 C 148.178,175.709 175.810,148.677 225.669,148.677 L 796.333,148.677 C 845.590,148.677 873.823,175.709 873.823,227.369 L 873.823,796.232 C 873.823,823.263 866.014,843.086 851.597,856.302 C 799.336,745.173 683.401,665.880 511.000,665.880 Z M 224.467,941.000 L 797.535,941.000 C 893.045,941.000 940.500,893.545 940.500,799.835 L 940.500,223.765 C 940.500,130.057 893.045,82.000 797.535,82.000 L 224.467,82.000 C 129.557,82.000 81.501,129.455 81.501,223.765 L 81.501,799.835 C 81.501,893.545 129.557,941.000 224.467,941.000 Z"/>
</Canvas>
</Canvas>
</Viewbox>

View file

@ -185,6 +185,14 @@
<Compile Include="ViewModels\LogViewModel.cs" />
<Compile Include="ViewModels\ProgressIndicatorViewModel.cs" />
<Compile Include="ViewModels\RuntimeWindowViewModel.cs" />
<Resource Include="Images\ProctoringNotification_Inactive.xaml">
<SubType>Designer</SubType>
<Generator>MSBuild:Compile</Generator>
</Resource>
<Resource Include="Images\ProctoringNotification_Active.xaml">
<Generator>MSBuild:Compile</Generator>
<SubType>Designer</SubType>
</Resource>
<Page Include="Windows\AboutWindow.xaml">
<SubType>Designer</SubType>
<Generator>MSBuild:Compile</Generator>

View file

@ -24,6 +24,7 @@ namespace SafeExamBrowser.UserInterface.Mobile.Controls.ActionCenter
InitializeComponent();
InitializeNotification();
UpdateNotification();
}
private void IconButton_Click(object sender, RoutedEventArgs e)
@ -32,6 +33,11 @@ namespace SafeExamBrowser.UserInterface.Mobile.Controls.ActionCenter
}
private void InitializeNotification()
{
notification.NotificationChanged += () => Dispatcher.Invoke(UpdateNotification);
}
private void UpdateNotification()
{
Icon.Content = IconResourceLoader.Load(notification.IconResource);
IconButton.ToolTip = notification.Tooltip;

View file

@ -24,6 +24,7 @@ namespace SafeExamBrowser.UserInterface.Mobile.Controls.Taskbar
InitializeComponent();
InitializeNotification();
UpdateNotification();
}
private void IconButton_Click(object sender, RoutedEventArgs e)
@ -32,6 +33,11 @@ namespace SafeExamBrowser.UserInterface.Mobile.Controls.Taskbar
}
private void InitializeNotification()
{
notification.NotificationChanged += () => Dispatcher.Invoke(UpdateNotification);
}
private void UpdateNotification()
{
IconButton.ToolTip = notification.Tooltip;
IconButton.Content = IconResourceLoader.Load(notification.IconResource);