diff --git a/SafeExamBrowser.Client/Operations/ServerOperation.cs b/SafeExamBrowser.Client/Operations/ServerOperation.cs
index 69a07108..f90d6bdf 100644
--- a/SafeExamBrowser.Client/Operations/ServerOperation.cs
+++ b/SafeExamBrowser.Client/Operations/ServerOperation.cs
@@ -54,8 +54,6 @@ namespace SafeExamBrowser.Client.Operations
Context.AppConfig.ServerExamId,
Context.AppConfig.ServerOauth2Token,
Context.Settings.Server);
-
- // TODO: Add action center and taskbar notifications
}
return result;
@@ -70,8 +68,6 @@ namespace SafeExamBrowser.Client.Operations
logger.Info("Finalizing server...");
StatusChanged?.Invoke(TextKey.OperationStatus_FinalizeServer);
- // TODO: Stop action center and taskbar notifications
-
server.StopConnectivity();
}
diff --git a/SafeExamBrowser.UserInterface.Mobile/SafeExamBrowser.UserInterface.Mobile.csproj b/SafeExamBrowser.UserInterface.Mobile/SafeExamBrowser.UserInterface.Mobile.csproj
index 08067dd3..606a9ce4 100644
--- a/SafeExamBrowser.UserInterface.Mobile/SafeExamBrowser.UserInterface.Mobile.csproj
+++ b/SafeExamBrowser.UserInterface.Mobile/SafeExamBrowser.UserInterface.Mobile.csproj
@@ -149,6 +149,9 @@
WindowControl.xaml
+
+ ExamSelectionDialog.xaml
+
FileSystemDialog.xaml
@@ -172,6 +175,9 @@
RuntimeWindow.xaml
+
+ ServerFailureDialog.xaml
+
SplashScreen.xaml
@@ -374,6 +380,10 @@
MSBuild:Compile
Designer
+
+ Designer
+ MSBuild:Compile
+
Designer
MSBuild:Compile
@@ -474,6 +484,10 @@
MSBuild:Compile
Designer
+
+ Designer
+ MSBuild:Compile
+
MSBuild:Compile
Designer
diff --git a/SafeExamBrowser.UserInterface.Mobile/UserInterfaceFactory.cs b/SafeExamBrowser.UserInterface.Mobile/UserInterfaceFactory.cs
index 6c09dd43..4535b2c9 100644
--- a/SafeExamBrowser.UserInterface.Mobile/UserInterfaceFactory.cs
+++ b/SafeExamBrowser.UserInterface.Mobile/UserInterfaceFactory.cs
@@ -84,8 +84,7 @@ namespace SafeExamBrowser.UserInterface.Mobile
public IExamSelectionDialog CreateExamSelectionDialog(IEnumerable exams)
{
- // TODO
- throw new System.NotImplementedException();
+ return Application.Current.Dispatcher.Invoke(() => new ExamSelectionDialog(exams, text));
}
public ISystemControl CreateKeyboardLayoutControl(IKeyboard keyboard, Location location)
@@ -170,8 +169,7 @@ namespace SafeExamBrowser.UserInterface.Mobile
public IServerFailureDialog CreateServerFailureDialog(string info, bool showFallback)
{
- // TODO
- throw new System.NotImplementedException();
+ return Application.Current.Dispatcher.Invoke(() => new ServerFailureDialog(info, showFallback, text));
}
public ISplashScreen CreateSplashScreen(AppConfig appConfig = null)
diff --git a/SafeExamBrowser.UserInterface.Mobile/Windows/ExamSelectionDialog.xaml b/SafeExamBrowser.UserInterface.Mobile/Windows/ExamSelectionDialog.xaml
new file mode 100644
index 00000000..f0742ecd
--- /dev/null
+++ b/SafeExamBrowser.UserInterface.Mobile/Windows/ExamSelectionDialog.xaml
@@ -0,0 +1,61 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/SafeExamBrowser.UserInterface.Mobile/Windows/ExamSelectionDialog.xaml.cs b/SafeExamBrowser.UserInterface.Mobile/Windows/ExamSelectionDialog.xaml.cs
new file mode 100644
index 00000000..ded33854
--- /dev/null
+++ b/SafeExamBrowser.UserInterface.Mobile/Windows/ExamSelectionDialog.xaml.cs
@@ -0,0 +1,111 @@
+/*
+ * Copyright (c) 2020 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.Collections.Generic;
+using System.ComponentModel;
+using System.Windows;
+using System.Windows.Controls;
+using SafeExamBrowser.I18n.Contracts;
+using SafeExamBrowser.Server.Contracts.Data;
+using SafeExamBrowser.UserInterface.Contracts.Windows;
+using SafeExamBrowser.UserInterface.Contracts.Windows.Data;
+
+namespace SafeExamBrowser.UserInterface.Mobile.Windows
+{
+ public partial class ExamSelectionDialog : Window, IExamSelectionDialog
+ {
+ private readonly IText text;
+
+ public ExamSelectionDialog(IEnumerable exams, IText text)
+ {
+ this.text = text;
+
+ InitializeComponent();
+ InitializeExamSelectionDialog(exams);
+ }
+
+ public ExamSelectionDialogResult Show(IWindow parent = null)
+ {
+ return Dispatcher.Invoke(() =>
+ {
+ var result = new ExamSelectionDialogResult { Success = false };
+
+ if (parent is Window)
+ {
+ Owner = parent as Window;
+ WindowStartupLocation = WindowStartupLocation.CenterOwner;
+ }
+
+ InitializeBounds();
+
+ if (ShowDialog() is true)
+ {
+ result.SelectedExam = ExamList.SelectedItem as Exam;
+ result.Success = true;
+ }
+
+ return result;
+ });
+ }
+
+ private void InitializeBounds()
+ {
+ Left = 0;
+ Top = 0;
+ Height = SystemParameters.PrimaryScreenHeight;
+ Width = SystemParameters.PrimaryScreenWidth;
+ }
+
+ private void InitializeExamSelectionDialog(IEnumerable exams)
+ {
+ InitializeBounds();
+
+ Message.Text = text.Get(TextKey.ExamSelectionDialog_Message);
+ Title = text.Get(TextKey.ExamSelectionDialog_Title);
+ WindowStartupLocation = WindowStartupLocation.CenterScreen;
+
+ CancelButton.Content = text.Get(TextKey.ExamSelectionDialog_Cancel);
+ CancelButton.Click += CancelButton_Click;
+
+ SelectButton.Content = text.Get(TextKey.ExamSelectionDialog_Select);
+ SelectButton.Click += ConfirmButton_Click;
+
+ ExamList.ItemsSource = exams;
+ ExamList.SelectionChanged += ExamList_SelectionChanged;
+
+ Loaded += (o, args) => Activate();
+
+ SystemParameters.StaticPropertyChanged += SystemParameters_StaticPropertyChanged;
+ }
+
+ private void CancelButton_Click(object sender, RoutedEventArgs e)
+ {
+ DialogResult = false;
+ Close();
+ }
+
+ private void ConfirmButton_Click(object sender, RoutedEventArgs e)
+ {
+ DialogResult = true;
+ Close();
+ }
+
+ private void ExamList_SelectionChanged(object sender, SelectionChangedEventArgs e)
+ {
+ SelectButton.IsEnabled = ExamList.SelectedItem != null;
+ }
+
+ private void SystemParameters_StaticPropertyChanged(object sender, PropertyChangedEventArgs e)
+ {
+ if (e.PropertyName == nameof(SystemParameters.WorkArea))
+ {
+ Dispatcher.InvokeAsync(InitializeBounds);
+ }
+ }
+ }
+}
diff --git a/SafeExamBrowser.UserInterface.Mobile/Windows/ServerFailureDialog.xaml b/SafeExamBrowser.UserInterface.Mobile/Windows/ServerFailureDialog.xaml
new file mode 100644
index 00000000..77077268
--- /dev/null
+++ b/SafeExamBrowser.UserInterface.Mobile/Windows/ServerFailureDialog.xaml
@@ -0,0 +1,45 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/SafeExamBrowser.UserInterface.Mobile/Windows/ServerFailureDialog.xaml.cs b/SafeExamBrowser.UserInterface.Mobile/Windows/ServerFailureDialog.xaml.cs
new file mode 100644
index 00000000..a6b4c254
--- /dev/null
+++ b/SafeExamBrowser.UserInterface.Mobile/Windows/ServerFailureDialog.xaml.cs
@@ -0,0 +1,119 @@
+/*
+ * Copyright (c) 2020 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.ComponentModel;
+using System.Windows;
+using SafeExamBrowser.I18n.Contracts;
+using SafeExamBrowser.UserInterface.Contracts.Windows;
+using SafeExamBrowser.UserInterface.Contracts.Windows.Data;
+
+namespace SafeExamBrowser.UserInterface.Mobile.Windows
+{
+ public partial class ServerFailureDialog : Window, IServerFailureDialog
+ {
+ private readonly IText text;
+
+ public ServerFailureDialog(string info, bool showFallback, IText text)
+ {
+ this.text = text;
+
+ InitializeComponent();
+ InitializeDialog(info, showFallback);
+ }
+
+ public ServerFailureDialogResult Show(IWindow parent = null)
+ {
+ return Dispatcher.Invoke(() =>
+ {
+ var result = new ServerFailureDialogResult { Success = false };
+
+ if (parent is Window)
+ {
+ Owner = parent as Window;
+ WindowStartupLocation = WindowStartupLocation.CenterOwner;
+ }
+
+ InitializeBounds();
+
+ if (ShowDialog() is true)
+ {
+ result.Abort = Tag as string == nameof(AbortButton);
+ result.Fallback = Tag as string == nameof(FallbackButton);
+ result.Retry = Tag as string == nameof(RetryButton);
+ result.Success = true;
+ }
+ else
+ {
+ result.Abort = true;
+ }
+
+ return result;
+ });
+ }
+
+ private void InitializeBounds()
+ {
+ Left = 0;
+ Top = 0;
+ Height = SystemParameters.PrimaryScreenHeight;
+ Width = SystemParameters.PrimaryScreenWidth;
+ }
+
+ private void InitializeDialog(string info, bool showFallback)
+ {
+ InitializeBounds();
+
+ Info.Text = info;
+ Message.Text = text.Get(TextKey.ServerFailureDialog_Message);
+ Title = text.Get(TextKey.ServerFailureDialog_Title);
+
+ AbortButton.Click += AbortButton_Click;
+ AbortButton.Content = text.Get(TextKey.ServerFailureDialog_Abort);
+
+ FallbackButton.Click += FallbackButton_Click;
+ FallbackButton.Content = text.Get(TextKey.ServerFailureDialog_Fallback);
+ FallbackButton.Visibility = showFallback ? Visibility.Visible : Visibility.Collapsed;
+
+ Loaded += (o, args) => Activate();
+
+ RetryButton.Click += RetryButton_Click;
+ RetryButton.Content = text.Get(TextKey.ServerFailureDialog_Retry);
+
+ SystemParameters.StaticPropertyChanged += SystemParameters_StaticPropertyChanged;
+ }
+
+ private void AbortButton_Click(object sender, RoutedEventArgs e)
+ {
+ DialogResult = true;
+ Tag = nameof(AbortButton);
+ Close();
+ }
+
+ private void FallbackButton_Click(object sender, RoutedEventArgs e)
+ {
+ DialogResult = true;
+ Tag = nameof(FallbackButton);
+ Close();
+ }
+
+ private void RetryButton_Click(object sender, RoutedEventArgs e)
+ {
+ DialogResult = true;
+ Tag = nameof(RetryButton);
+ Close();
+ }
+
+ private void SystemParameters_StaticPropertyChanged(object sender, PropertyChangedEventArgs e)
+ {
+ if (e.PropertyName == nameof(SystemParameters.WorkArea))
+ {
+ Dispatcher.InvokeAsync(InitializeBounds);
+ }
+ }
+ }
+}