diff --git a/SafeExamBrowser.Client/CompositionRoot.cs b/SafeExamBrowser.Client/CompositionRoot.cs
index 953f1630..a11ee56b 100644
--- a/SafeExamBrowser.Client/CompositionRoot.cs
+++ b/SafeExamBrowser.Client/CompositionRoot.cs
@@ -309,8 +309,7 @@ namespace SafeExamBrowser.Client
switch (uiMode)
{
case UserInterfaceMode.Mobile:
- // TODO
- throw new NotImplementedException();
+ return new Mobile.TaskView();
default:
return new Desktop.TaskView();
}
diff --git a/SafeExamBrowser.UserInterface.Desktop/Controls/TaskViewInstanceControl.xaml b/SafeExamBrowser.UserInterface.Desktop/Controls/TaskViewInstanceControl.xaml
index 1af0d30e..ebccd149 100644
--- a/SafeExamBrowser.UserInterface.Desktop/Controls/TaskViewInstanceControl.xaml
+++ b/SafeExamBrowser.UserInterface.Desktop/Controls/TaskViewInstanceControl.xaml
@@ -12,7 +12,7 @@
-
+
diff --git a/SafeExamBrowser.UserInterface.Desktop/Controls/TaskViewInstanceControl.xaml.cs b/SafeExamBrowser.UserInterface.Desktop/Controls/TaskViewInstanceControl.xaml.cs
index f1997763..34647b3e 100644
--- a/SafeExamBrowser.UserInterface.Desktop/Controls/TaskViewInstanceControl.xaml.cs
+++ b/SafeExamBrowser.UserInterface.Desktop/Controls/TaskViewInstanceControl.xaml.cs
@@ -35,15 +35,15 @@ namespace SafeExamBrowser.UserInterface.Desktop.Controls
internal void Deselect()
{
- Border.Visibility = Visibility.Hidden;
Icon.MaxWidth = 40;
+ Indicator.Visibility = Visibility.Hidden;
Title.FontWeight = FontWeights.Normal;
}
internal void Select()
{
- Border.Visibility = Visibility.Visible;
Icon.MaxWidth = 50;
+ Indicator.Visibility = Visibility.Visible;
Title.FontWeight = FontWeights.SemiBold;
}
diff --git a/SafeExamBrowser.UserInterface.Mobile/ActionCenter.xaml b/SafeExamBrowser.UserInterface.Mobile/ActionCenter.xaml
index 83088909..84ce5ea4 100644
--- a/SafeExamBrowser.UserInterface.Mobile/ActionCenter.xaml
+++ b/SafeExamBrowser.UserInterface.Mobile/ActionCenter.xaml
@@ -4,11 +4,12 @@
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:SafeExamBrowser.UserInterface.Mobile.Controls"
- mc:Ignorable="d" Title="ActionCenter" Height="1000" Width="400" Background="#EEF0F0F0" AllowsTransparency="True" FontSize="16"
- WindowStyle="None" Topmost="True" ResizeMode="NoResize">
+ mc:Ignorable="d" Title="ActionCenter" Height="1000" Width="400" Background="{DynamicResource BackgroundTransparentBrush}"
+ AllowsTransparency="True" FontSize="16" WindowStyle="None" Topmost="True" ResizeMode="NoResize">
+
diff --git a/SafeExamBrowser.UserInterface.Mobile/Controls/ActionCenterApplicationControl.xaml b/SafeExamBrowser.UserInterface.Mobile/Controls/ActionCenterApplicationControl.xaml
index ec278dbd..1172d550 100644
--- a/SafeExamBrowser.UserInterface.Mobile/Controls/ActionCenterApplicationControl.xaml
+++ b/SafeExamBrowser.UserInterface.Mobile/Controls/ActionCenterApplicationControl.xaml
@@ -20,8 +20,8 @@
-
+
-
+
diff --git a/SafeExamBrowser.UserInterface.Mobile/Controls/TaskViewInstanceControl.xaml b/SafeExamBrowser.UserInterface.Mobile/Controls/TaskViewInstanceControl.xaml
new file mode 100644
index 00000000..d0f8a794
--- /dev/null
+++ b/SafeExamBrowser.UserInterface.Mobile/Controls/TaskViewInstanceControl.xaml
@@ -0,0 +1,21 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/SafeExamBrowser.UserInterface.Mobile/Controls/TaskViewInstanceControl.xaml.cs b/SafeExamBrowser.UserInterface.Mobile/Controls/TaskViewInstanceControl.xaml.cs
new file mode 100644
index 00000000..fd143e76
--- /dev/null
+++ b/SafeExamBrowser.UserInterface.Mobile/Controls/TaskViewInstanceControl.xaml.cs
@@ -0,0 +1,69 @@
+/*
+ * 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.Applications.Contracts;
+using SafeExamBrowser.Core.Contracts;
+using SafeExamBrowser.UserInterface.Shared.Utilities;
+
+namespace SafeExamBrowser.UserInterface.Mobile.Controls
+{
+ public partial class TaskViewInstanceControl : UserControl
+ {
+ private IApplicationInstance instance;
+
+ internal InstanceIdentifier Id => instance.Id;
+
+ public TaskViewInstanceControl(IApplicationInstance instance)
+ {
+ this.instance = instance;
+
+ InitializeComponent();
+ InitializeControl();
+ }
+
+ internal void Activate()
+ {
+ instance.Activate();
+ }
+
+ internal void Deselect()
+ {
+ Icon.MaxWidth = 40;
+ Indicator.Visibility = Visibility.Hidden;
+ Title.FontWeight = FontWeights.Normal;
+ }
+
+ internal void Select()
+ {
+ Icon.MaxWidth = 50;
+ Indicator.Visibility = Visibility.Visible;
+ Title.FontWeight = FontWeights.SemiBold;
+ }
+
+ private void InitializeControl()
+ {
+ Icon.Content = IconResourceLoader.Load(instance.Icon);
+ Title.Text = instance.Name;
+
+ instance.IconChanged += Instance_IconChanged;
+ instance.NameChanged += Instance_NameChanged;
+ }
+
+ private void Instance_NameChanged(string name)
+ {
+ Dispatcher.InvokeAsync(() => Title.Text = name);
+ }
+
+ private void Instance_IconChanged(IconResource icon)
+ {
+ Dispatcher.InvokeAsync(() => Icon.Content = IconResourceLoader.Load(instance.Icon));
+ }
+ }
+}
diff --git a/SafeExamBrowser.UserInterface.Mobile/SafeExamBrowser.UserInterface.Mobile.csproj b/SafeExamBrowser.UserInterface.Mobile/SafeExamBrowser.UserInterface.Mobile.csproj
index b2daab1e..75a7d088 100644
--- a/SafeExamBrowser.UserInterface.Mobile/SafeExamBrowser.UserInterface.Mobile.csproj
+++ b/SafeExamBrowser.UserInterface.Mobile/SafeExamBrowser.UserInterface.Mobile.csproj
@@ -143,6 +143,9 @@
TaskbarWirelessNetworkControl.xaml
+
+ TaskViewInstanceControl.xaml
+
LockScreen.xaml
@@ -168,6 +171,9 @@
Taskbar.xaml
+
+ TaskView.xaml
+
@@ -353,6 +359,10 @@
MSBuild:Compile
Designer
+
+ MSBuild:Compile
+ Designer
+
MSBuild:Compile
Designer
@@ -457,6 +467,10 @@
MSBuild:Compile
Designer
+
+ MSBuild:Compile
+ Designer
+
Designer
MSBuild:Compile
diff --git a/SafeExamBrowser.UserInterface.Mobile/TaskView.xaml b/SafeExamBrowser.UserInterface.Mobile/TaskView.xaml
new file mode 100644
index 00000000..5663312c
--- /dev/null
+++ b/SafeExamBrowser.UserInterface.Mobile/TaskView.xaml
@@ -0,0 +1,19 @@
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/SafeExamBrowser.UserInterface.Mobile/TaskView.xaml.cs b/SafeExamBrowser.UserInterface.Mobile/TaskView.xaml.cs
new file mode 100644
index 00000000..d577e7ea
--- /dev/null
+++ b/SafeExamBrowser.UserInterface.Mobile/TaskView.xaml.cs
@@ -0,0 +1,167 @@
+/*
+ * 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.Linq;
+using System.Windows;
+using System.Windows.Controls;
+using SafeExamBrowser.Applications.Contracts;
+using SafeExamBrowser.UserInterface.Contracts.Shell;
+using SafeExamBrowser.UserInterface.Mobile.Controls;
+
+namespace SafeExamBrowser.UserInterface.Mobile
+{
+ public partial class TaskView : Window, ITaskView
+ {
+ private LinkedListNode current;
+ private LinkedList controls;
+ private List instances;
+
+ public TaskView()
+ {
+ controls = new LinkedList();
+ instances = new List();
+
+ InitializeComponent();
+ }
+
+ public void Add(IApplication application)
+ {
+ application.InstanceStarted += Application_InstanceStarted;
+ }
+
+ public void Register(ITaskViewActivator activator)
+ {
+ activator.Deactivated += Activator_Deactivated;
+ activator.NextActivated += Activator_Next;
+ activator.PreviousActivated += Activator_Previous;
+ }
+
+ private void Application_InstanceStarted(IApplicationInstance instance)
+ {
+ Dispatcher.InvokeAsync(() => Add(instance));
+ }
+
+ private void Activator_Deactivated()
+ {
+ Dispatcher.InvokeAsync(ActivateAndHide);
+ }
+
+ private void Activator_Next()
+ {
+ Dispatcher.InvokeAsync(SelectNext);
+ }
+
+ private void Activator_Previous()
+ {
+ Dispatcher.InvokeAsync(SelectPrevious);
+ }
+
+ private void Instance_Terminated(InstanceIdentifier id)
+ {
+ Dispatcher.InvokeAsync(() => Remove(id));
+ }
+
+ private void ActivateAndHide()
+ {
+ Activate();
+ current?.Value.Activate();
+ Hide();
+ }
+
+ private void Add(IApplicationInstance instance)
+ {
+ instance.Terminated += Instance_Terminated;
+ instances.Add(instance);
+ Update();
+ }
+
+ private void Remove(InstanceIdentifier id)
+ {
+ var instance = instances.FirstOrDefault(i => i.Id == id);
+
+ if (instance != default(IApplicationInstance))
+ {
+ instances.Remove(instance);
+ Update();
+ }
+ }
+
+ private void SelectNext()
+ {
+ ShowConditional();
+
+ if (current != null)
+ {
+ current.Value.Deselect();
+ current = current.Next ?? controls.First;
+ current.Value.Select();
+ }
+ }
+
+ private void SelectPrevious()
+ {
+ ShowConditional();
+
+ if (current != null)
+ {
+ current.Value.Deselect();
+ current = current.Previous ?? controls.Last;
+ current.Value.Select();
+ }
+ }
+
+ private void ShowConditional()
+ {
+ if (instances.Any() && Visibility != Visibility.Visible)
+ {
+ Show();
+ Activate();
+ }
+ }
+
+ private void Update()
+ {
+ var max = Math.Ceiling(Math.Sqrt(instances.Count));
+ var stack = new Stack(instances);
+
+ controls.Clear();
+ Rows.Children.Clear();
+
+ for (var rowCount = 0; rowCount < max && stack.Any(); rowCount++)
+ {
+ var row = new StackPanel { Orientation = Orientation.Horizontal, HorizontalAlignment = HorizontalAlignment.Center };
+
+ Rows.Children.Add(row);
+
+ for (var columnIndex = 0; columnIndex < max && stack.Any(); columnIndex++)
+ {
+ var instance = stack.Pop();
+ var control = new TaskViewInstanceControl(instance);
+
+ controls.AddLast(control);
+ row.Children.Add(control);
+ }
+ }
+
+ current = controls.First;
+ current?.Value.Select();
+
+ UpdateLayout();
+
+ Left = (SystemParameters.WorkArea.Width - Width) / 2 + SystemParameters.WorkArea.Left;
+ Top = (SystemParameters.WorkArea.Height - Height) / 2 + SystemParameters.WorkArea.Top;
+
+ if (!instances.Any())
+ {
+ Hide();
+ }
+ }
+ }
+}
diff --git a/SafeExamBrowser.UserInterface.Mobile/Taskbar.xaml b/SafeExamBrowser.UserInterface.Mobile/Taskbar.xaml
index e86741c6..a0b40401 100644
--- a/SafeExamBrowser.UserInterface.Mobile/Taskbar.xaml
+++ b/SafeExamBrowser.UserInterface.Mobile/Taskbar.xaml
@@ -5,11 +5,12 @@
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:SafeExamBrowser.UserInterface.Mobile.Controls"
xmlns:s="clr-namespace:System;assembly=mscorlib"
- mc:Ignorable="d" Title="Taskbar" Background="#FFF0F0F0" Height="60" FontSize="16" Width="750" WindowStyle="None" Topmost="True"
- ResizeMode="NoResize" Icon="./Images/SafeExamBrowser.ico">
+ mc:Ignorable="d" Title="Taskbar" Background="{DynamicResource BackgroundBrush}" Height="60" FontSize="16" Width="750" WindowStyle="None"
+ Topmost="True" ResizeMode="NoResize" Icon="./Images/SafeExamBrowser.ico">
+
@@ -27,7 +28,7 @@
-
+
diff --git a/SafeExamBrowser.UserInterface.Mobile/Templates/Colors.xaml b/SafeExamBrowser.UserInterface.Mobile/Templates/Colors.xaml
index 468c0504..6a558e71 100644
--- a/SafeExamBrowser.UserInterface.Mobile/Templates/Colors.xaml
+++ b/SafeExamBrowser.UserInterface.Mobile/Templates/Colors.xaml
@@ -1,5 +1,9 @@
- #FFF0F0F0
#AA808080
+ #FFF0F0F0
+ #EEF0F0F0
+ #99D3D3D3
+ Black
+ DimGray
\ No newline at end of file