SEBWIN-221: Changed IProgressIndicator implementation to automatically show busy indication after a delay. All application controllers now create new splash screens before executing an operation sequence.

This commit is contained in:
dbuechel 2018-10-04 11:24:16 +02:00
parent ed43534e5b
commit 7a57cdf93b
10 changed files with 62 additions and 76 deletions

View file

@ -110,7 +110,7 @@ namespace SafeExamBrowser.Client
if (communication.Success)
{
splashScreen.Hide();
splashScreen.Close();
logger.Info("Application successfully initialized.");
logger.Log(string.Empty);
@ -135,8 +135,8 @@ namespace SafeExamBrowser.Client
logger.Log(string.Empty);
logger.Info("Initiating shutdown procedure...");
splashScreen = uiFactory.CreateSplashScreen(appConfig);
splashScreen.Show();
splashScreen.BringToForeground();
DeregisterEvents();
@ -153,7 +153,7 @@ namespace SafeExamBrowser.Client
logger.Log(string.Empty);
}
splashScreen?.Close();
splashScreen.Close();
}
private void RegisterEvents()
@ -307,7 +307,7 @@ namespace SafeExamBrowser.Client
private void Operations_StatusChanged(TextKey status)
{
splashScreen?.UpdateText(status);
splashScreen?.UpdateStatus(status, true);
}
private void Runtime_ConnectionLost()

View file

@ -42,8 +42,7 @@ namespace SafeExamBrowser.Contracts.UserInterface
/// <summary>
/// Updates the status text. If the busy flag is set, an animation will be shown to indicate a long-running operation.
/// TODO: Automatically show busy indication in implementations after e.g. 2 seconds!
/// </summary>
void UpdateText(TextKey key, bool showBusyIndication = false);
void UpdateStatus(TextKey key, bool busyIndication = false);
}
}

View file

@ -14,7 +14,6 @@ using SafeExamBrowser.Contracts.Configuration;
using SafeExamBrowser.Contracts.Configuration.Settings;
using SafeExamBrowser.Contracts.Core.OperationModel;
using SafeExamBrowser.Contracts.Logging;
using SafeExamBrowser.Contracts.UserInterface;
using SafeExamBrowser.Runtime.Operations;
namespace SafeExamBrowser.Runtime.UnitTests.Operations
@ -27,7 +26,6 @@ namespace SafeExamBrowser.Runtime.UnitTests.Operations
private Mock<IConfigurationRepository> configuration;
private Mock<ISessionData> session;
private Settings settings;
private Mock<IProgressIndicator> progressIndicator;
private ServiceOperation sut;
[TestInitialize]
@ -38,7 +36,6 @@ namespace SafeExamBrowser.Runtime.UnitTests.Operations
configuration = new Mock<IConfigurationRepository>();
session = new Mock<ISessionData>();
settings = new Settings();
progressIndicator = new Mock<IProgressIndicator>();
configuration.SetupGet(c => c.CurrentSession).Returns(session.Object);
configuration.SetupGet(c => c.CurrentSettings).Returns(settings);

View file

@ -94,7 +94,7 @@ namespace SafeExamBrowser.Runtime
logger.Info("Application successfully initialized.");
logger.Log(string.Empty);
logger.Subscribe(runtimeWindow);
splashScreen.Hide();
splashScreen.Close();
StartSession(true);
}
@ -120,8 +120,9 @@ namespace SafeExamBrowser.Runtime
logger.Unsubscribe(runtimeWindow);
runtimeWindow?.Close();
splashScreen?.Show();
splashScreen?.BringToForeground();
splashScreen = uiFactory.CreateSplashScreen(appConfig);
splashScreen.Show();
logger.Log(string.Empty);
logger.Info("Initiating shutdown procedure...");
@ -141,7 +142,7 @@ namespace SafeExamBrowser.Runtime
messageBox.Show(TextKey.MessageBox_ShutdownError, TextKey.MessageBox_ShutdownErrorTitle, icon: MessageBoxIcon.Error, parent: splashScreen);
}
splashScreen?.Close();
splashScreen.Close();
}
private void StartSession(bool initial = false)
@ -164,7 +165,7 @@ namespace SafeExamBrowser.Runtime
logger.Info("### --- Session Running --- ###");
runtimeWindow.HideProgressBar();
runtimeWindow.UpdateText(TextKey.RuntimeWindow_ApplicationRunning);
runtimeWindow.UpdateStatus(TextKey.RuntimeWindow_ApplicationRunning);
runtimeWindow.TopMost = configuration.CurrentSettings.KioskMode != KioskMode.None;
if (configuration.CurrentSettings.KioskMode == KioskMode.DisableExplorerShell)
@ -270,7 +271,7 @@ namespace SafeExamBrowser.Runtime
private void BootstrapSequence_StatusChanged(TextKey status)
{
splashScreen?.UpdateText(status);
splashScreen?.UpdateStatus(status, true);
}
private void ClientProcess_Terminated(int exitCode)
@ -427,7 +428,7 @@ namespace SafeExamBrowser.Runtime
private void SessionSequence_StatusChanged(TextKey status)
{
runtimeWindow?.UpdateText(status);
runtimeWindow?.UpdateStatus(status, true);
}
}
}

View file

@ -58,6 +58,8 @@ namespace SafeExamBrowser.UserInterface.Classic
Dispatcher.Invoke(() =>
{
allowClose = true;
model.BusyIndication = false;
base.Close();
});
}
@ -69,6 +71,7 @@ namespace SafeExamBrowser.UserInterface.Classic
public void HideProgressBar()
{
model.AnimatedBorderVisibility = Visibility.Visible;
model.ProgressBarVisibility = Visibility.Hidden;
}
@ -108,18 +111,14 @@ namespace SafeExamBrowser.UserInterface.Classic
public void ShowProgressBar()
{
model.AnimatedBorderVisibility = Visibility.Hidden;
model.ProgressBarVisibility = Visibility.Visible;
}
public void UpdateText(TextKey key, bool showBusyIndication = false)
public void UpdateStatus(TextKey key, bool busyIndication = false)
{
model.StopBusyIndication();
model.Status = text.Get(key);
if (showBusyIndication)
{
model.StartBusyIndication();
}
model.BusyIndication = busyIndication;
}
public new void Show()

View file

@ -19,7 +19,7 @@
<ColumnDefinition Width="155" />
</Grid.ColumnDefinitions>
<Image Grid.Column="0" Grid.ColumnSpan="2" Source="pack://application:,,,/SafeExamBrowser.UserInterface.Classic;component/Images/SplashScreen.png" />
<TextBlock x:Name="InfoTextBlock" Grid.Column="1" Margin="10,75,10,10" TextWrapping="Wrap" />
<TextBlock x:Name="InfoTextBlock" Grid.Column="1" Foreground="Gray" Margin="10,75,10,10" TextWrapping="Wrap" />
</Grid>
<ProgressBar x:Name="ProgressBar" Grid.Row="1" Minimum="0" Maximum="{Binding Path=MaxProgress}" Value="{Binding Path=CurrentProgress}" IsIndeterminate="{Binding Path=IsIndeterminate}" BorderThickness="0" />
<TextBlock x:Name="StatusTextBlock" Grid.Row="1" Text="{Binding Path=Status}" FontSize="12" HorizontalAlignment="Center" VerticalAlignment="Center" />

View file

@ -63,6 +63,8 @@ namespace SafeExamBrowser.UserInterface.Classic
Dispatcher.Invoke(() =>
{
allowClose = true;
model.BusyIndication = false;
base.Close();
});
}
@ -102,15 +104,10 @@ namespace SafeExamBrowser.UserInterface.Classic
model.CurrentProgress = value;
}
public void UpdateText(TextKey key, bool showBusyIndication = false)
public void UpdateStatus(TextKey key, bool busyIndication = false)
{
model.StopBusyIndication();
model.Status = text.Get(key);
if (showBusyIndication)
{
model.StartBusyIndication();
}
model.BusyIndication = busyIndication;
}
private void InitializeSplashScreen()
@ -120,9 +117,6 @@ namespace SafeExamBrowser.UserInterface.Classic
StatusTextBlock.DataContext = model;
ProgressBar.DataContext = model;
// To prevent the progress bar going from max to min value at startup...
model.MaxProgress = 1;
Closing += (o, args) => args.Cancel = !allowClose;
}

View file

@ -13,14 +13,24 @@ namespace SafeExamBrowser.UserInterface.Classic.ViewModels
{
internal class ProgressIndicatorViewModel : INotifyPropertyChanged
{
private readonly object @lock = new object();
private Timer busyTimer;
private int currentProgress;
private bool isIndeterminate;
private int maxProgress;
private string status;
private Timer busyTimer;
public event PropertyChangedEventHandler PropertyChanged;
public bool BusyIndication
{
set
{
HandleBusyIndication(value);
}
}
public int CurrentProgress
{
get
@ -73,31 +83,35 @@ namespace SafeExamBrowser.UserInterface.Classic.ViewModels
}
}
public virtual void StartBusyIndication()
{
StopBusyIndication();
busyTimer = new Timer
{
AutoReset = true,
Interval = 750
};
busyTimer.Elapsed += BusyTimer_Elapsed;
busyTimer.Start();
}
public virtual void StopBusyIndication()
{
busyTimer?.Stop();
busyTimer?.Close();
}
protected void OnPropertyChanged(string propertyName)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
private void HandleBusyIndication(bool start)
{
lock (@lock)
{
if (busyTimer != null)
{
busyTimer.Elapsed -= BusyTimer_Elapsed;
busyTimer.Stop();
busyTimer.Close();
}
if (start)
{
busyTimer = new Timer
{
AutoReset = true,
Interval = 1500,
};
busyTimer.Elapsed += BusyTimer_Elapsed;
busyTimer.Start();
}
}
}
private void BusyTimer_Elapsed(object sender, ElapsedEventArgs e)
{
var next = Status ?? string.Empty;
@ -112,6 +126,7 @@ namespace SafeExamBrowser.UserInterface.Classic.ViewModels
}
Status = next;
busyTimer.Interval = 750;
}
}
}

View file

@ -66,20 +66,6 @@ namespace SafeExamBrowser.UserInterface.Classic.ViewModels
}
}
public override void StartBusyIndication()
{
base.StartBusyIndication();
AnimatedBorderVisibility = Visibility.Hidden;
}
public override void StopBusyIndication()
{
base.StopBusyIndication();
AnimatedBorderVisibility = Visibility.Visible;
}
private void AppendLogMessage(ILogMessage message)
{
var time = message.DateTime.ToString("HH:mm:ss.fff");

View file

@ -100,15 +100,10 @@ namespace SafeExamBrowser.UserInterface.Windows10
model.CurrentProgress = value;
}
public void UpdateText(TextKey key, bool showBusyIndication = false)
public void UpdateStatus(TextKey key, bool showBusyIndication = false)
{
model.StopBusyIndication();
// TODO: Handle auto-start of busy indication
model.Status = text.Get(key);
if (showBusyIndication)
{
model.StartBusyIndication();
}
}
private void InitializeSplashScreen()