SEBWIN-312: Implemented task view for mobile UI.
This commit is contained in:
parent
fbe03b86ea
commit
5ccbd2aae4
12 changed files with 308 additions and 13 deletions
|
@ -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();
|
||||
}
|
||||
|
|
|
@ -12,7 +12,7 @@
|
|||
</ResourceDictionary>
|
||||
</UserControl.Resources>
|
||||
<Grid Margin="5" Height="150" Width="250">
|
||||
<Border Name="Border" Background="{StaticResource BackgroundTransparentEmphasisBrush}" BorderBrush="DarkGray" BorderThickness="2" Visibility="Hidden" />
|
||||
<Border Name="Indicator" Background="{StaticResource BackgroundTransparentEmphasisBrush}" BorderThickness="0" Visibility="Hidden" />
|
||||
<StackPanel HorizontalAlignment="Center" Orientation="Vertical" VerticalAlignment="Center">
|
||||
<ContentControl Name="Icon" MaxWidth="40" />
|
||||
<TextBlock Name="Title" Margin="10" Foreground="{StaticResource PrimaryTextBrush}" TextTrimming="CharacterEllipsis" />
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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">
|
||||
<Window.Resources>
|
||||
<ResourceDictionary>
|
||||
<ResourceDictionary.MergedDictionaries>
|
||||
<ResourceDictionary Source="./Templates/Colors.xaml" />
|
||||
<ResourceDictionary Source="./Templates/ScrollViewers.xaml" />
|
||||
</ResourceDictionary.MergedDictionaries>
|
||||
</ResourceDictionary>
|
||||
|
|
|
@ -20,8 +20,8 @@
|
|||
<RowDefinition Height="*" />
|
||||
<RowDefinition Height="*" />
|
||||
</Grid.RowDefinitions>
|
||||
<TextBlock Grid.Row="0" x:Name="ApplicationName" Background="#99D3D3D3" FontWeight="Bold" Padding="5" TextAlignment="Center" />
|
||||
<TextBlock Grid.Row="0" x:Name="ApplicationName" Background="{StaticResource BackgroundTransparentEmphasisBrush}" FontWeight="Bold" Padding="5" TextAlignment="Center" />
|
||||
<ContentControl Grid.Row="1" x:Name="ApplicationButton" FontWeight="Bold" />
|
||||
<StackPanel Grid.Row="2" x:Name="InstancePanel" Background="#99D3D3D3" Orientation="Vertical" />
|
||||
<StackPanel Grid.Row="2" x:Name="InstancePanel" Background="{StaticResource BackgroundTransparentEmphasisBrush}" Orientation="Vertical" />
|
||||
</Grid>
|
||||
</UserControl>
|
||||
|
|
|
@ -0,0 +1,21 @@
|
|||
<UserControl x:Class="SafeExamBrowser.UserInterface.Mobile.Controls.TaskViewInstanceControl"
|
||||
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.Mobile.Controls">
|
||||
<UserControl.Resources>
|
||||
<ResourceDictionary>
|
||||
<ResourceDictionary.MergedDictionaries>
|
||||
<ResourceDictionary Source="../Templates/Colors.xaml" />
|
||||
</ResourceDictionary.MergedDictionaries>
|
||||
</ResourceDictionary>
|
||||
</UserControl.Resources>
|
||||
<Grid Margin="5" Height="150" Width="250">
|
||||
<Border Name="Indicator" Background="{StaticResource BackgroundTransparentEmphasisBrush}" BorderThickness="0" Visibility="Hidden" />
|
||||
<StackPanel HorizontalAlignment="Center" Orientation="Vertical" VerticalAlignment="Center">
|
||||
<ContentControl Name="Icon" MaxWidth="40" />
|
||||
<TextBlock Name="Title" Margin="10" Foreground="{StaticResource PrimaryTextBrush}" TextTrimming="CharacterEllipsis" />
|
||||
</StackPanel>
|
||||
</Grid>
|
||||
</UserControl>
|
|
@ -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));
|
||||
}
|
||||
}
|
||||
}
|
|
@ -143,6 +143,9 @@
|
|||
<Compile Include="Controls\TaskbarWirelessNetworkControl.xaml.cs">
|
||||
<DependentUpon>TaskbarWirelessNetworkControl.xaml</DependentUpon>
|
||||
</Compile>
|
||||
<Compile Include="Controls\TaskViewInstanceControl.xaml.cs">
|
||||
<DependentUpon>TaskViewInstanceControl.xaml</DependentUpon>
|
||||
</Compile>
|
||||
<Compile Include="LockScreen.xaml.cs">
|
||||
<DependentUpon>LockScreen.xaml</DependentUpon>
|
||||
</Compile>
|
||||
|
@ -168,6 +171,9 @@
|
|||
<Compile Include="Taskbar.xaml.cs">
|
||||
<DependentUpon>Taskbar.xaml</DependentUpon>
|
||||
</Compile>
|
||||
<Compile Include="TaskView.xaml.cs">
|
||||
<DependentUpon>TaskView.xaml</DependentUpon>
|
||||
</Compile>
|
||||
<Compile Include="UserInterfaceFactory.cs" />
|
||||
<Compile Include="ViewModels\DateTimeViewModel.cs" />
|
||||
<Compile Include="ViewModels\LogViewModel.cs" />
|
||||
|
@ -353,6 +359,10 @@
|
|||
<Generator>MSBuild:Compile</Generator>
|
||||
<SubType>Designer</SubType>
|
||||
</Resource>
|
||||
<Page Include="Controls\TaskViewInstanceControl.xaml">
|
||||
<Generator>MSBuild:Compile</Generator>
|
||||
<SubType>Designer</SubType>
|
||||
</Page>
|
||||
<Page Include="Images\ZoomPageOut.xaml">
|
||||
<Generator>MSBuild:Compile</Generator>
|
||||
<SubType>Designer</SubType>
|
||||
|
@ -457,6 +467,10 @@
|
|||
<Generator>MSBuild:Compile</Generator>
|
||||
<SubType>Designer</SubType>
|
||||
</Page>
|
||||
<Page Include="TaskView.xaml">
|
||||
<Generator>MSBuild:Compile</Generator>
|
||||
<SubType>Designer</SubType>
|
||||
</Page>
|
||||
<Page Include="Templates\Buttons.xaml">
|
||||
<SubType>Designer</SubType>
|
||||
<Generator>MSBuild:Compile</Generator>
|
||||
|
|
19
SafeExamBrowser.UserInterface.Mobile/TaskView.xaml
Normal file
19
SafeExamBrowser.UserInterface.Mobile/TaskView.xaml
Normal file
|
@ -0,0 +1,19 @@
|
|||
<Window x:Class="SafeExamBrowser.UserInterface.Mobile.TaskView"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
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"
|
||||
mc:Ignorable="d" AllowsTransparency="True" Background="{DynamicResource BackgroundTransparentBrush}" BorderBrush="DodgerBlue" BorderThickness="1"
|
||||
Title="TaskView" Topmost="True" Height="450" SizeToContent="WidthAndHeight" Width="800" WindowStartupLocation="CenterScreen" WindowStyle="None">
|
||||
<Window.Resources>
|
||||
<ResourceDictionary>
|
||||
<ResourceDictionary.MergedDictionaries>
|
||||
<ResourceDictionary Source="./Templates/Colors.xaml" />
|
||||
</ResourceDictionary.MergedDictionaries>
|
||||
</ResourceDictionary>
|
||||
</Window.Resources>
|
||||
<Grid>
|
||||
<StackPanel Name="Rows" Margin="10" Orientation="Vertical" />
|
||||
</Grid>
|
||||
</Window>
|
167
SafeExamBrowser.UserInterface.Mobile/TaskView.xaml.cs
Normal file
167
SafeExamBrowser.UserInterface.Mobile/TaskView.xaml.cs
Normal file
|
@ -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<TaskViewInstanceControl> current;
|
||||
private LinkedList<TaskViewInstanceControl> controls;
|
||||
private List<IApplicationInstance> instances;
|
||||
|
||||
public TaskView()
|
||||
{
|
||||
controls = new LinkedList<TaskViewInstanceControl>();
|
||||
instances = new List<IApplicationInstance>();
|
||||
|
||||
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<IApplicationInstance>(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();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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">
|
||||
<Window.Resources>
|
||||
<ResourceDictionary>
|
||||
<ResourceDictionary.MergedDictionaries>
|
||||
<ResourceDictionary Source="./Templates/Colors.xaml" />
|
||||
<ResourceDictionary Source="./Templates/ScrollViewers.xaml" />
|
||||
</ResourceDictionary.MergedDictionaries>
|
||||
</ResourceDictionary>
|
||||
|
@ -27,7 +28,7 @@
|
|||
</ScrollViewer>
|
||||
<StackPanel Grid.Column="1" x:Name="NotificationStackPanel" Orientation="Horizontal" VerticalAlignment="Stretch" />
|
||||
<StackPanel Grid.Column="2" x:Name="SystemControlStackPanel" Orientation="Horizontal" VerticalAlignment="Stretch" />
|
||||
<local:TaskbarClock Grid.Column="3" x:Name="Clock" Foreground="DimGray" Padding="10,0,10,0" />
|
||||
<local:TaskbarClock Grid.Column="3" x:Name="Clock" Foreground="{StaticResource SecondaryTextBrush}" Padding="10,0,10,0" />
|
||||
<local:TaskbarQuitButton Grid.Column="4" x:Name="QuitButton" />
|
||||
</Grid>
|
||||
</Window>
|
||||
|
|
|
@ -1,5 +1,9 @@
|
|||
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
|
||||
<SolidColorBrush x:Key="BackgroundBrush">#FFF0F0F0</SolidColorBrush>
|
||||
<SolidColorBrush x:Key="ActionCenterDarkBrush">#AA808080</SolidColorBrush>
|
||||
<SolidColorBrush x:Key="BackgroundBrush">#FFF0F0F0</SolidColorBrush>
|
||||
<SolidColorBrush x:Key="BackgroundTransparentBrush">#EEF0F0F0</SolidColorBrush>
|
||||
<SolidColorBrush x:Key="BackgroundTransparentEmphasisBrush">#99D3D3D3</SolidColorBrush>
|
||||
<SolidColorBrush x:Key="PrimaryTextBrush">Black</SolidColorBrush>
|
||||
<SolidColorBrush x:Key="SecondaryTextBrush">DimGray</SolidColorBrush>
|
||||
</ResourceDictionary>
|
Loading…
Reference in a new issue