From 97f3fb4a02b1ddac00de4e56ba7856c7ad6f8371 Mon Sep 17 00:00:00 2001 From: dbuechel Date: Wed, 22 Jan 2020 15:16:11 +0100 Subject: [PATCH] SEBWIN-308: Implemented basic download overview for browser. --- SafeExamBrowser.Browser/BrowserApplication.cs | 6 +- .../BrowserApplicationInstance.cs | 14 ++++- .../Events/DownloadUpdatedEventHandler.cs | 14 +++++ .../Handlers/DownloadHandler.cs | 32 +++++++++-- .../SafeExamBrowser.Browser.csproj | 1 + SafeExamBrowser.Client/CompositionRoot.cs | 15 ++++- SafeExamBrowser.I18n.Contracts/TextKey.cs | 3 + SafeExamBrowser.I18n/Text.xml | 9 +++ .../Browser/Data/DownloadItemState.cs | 53 ++++++++++++++++++ .../Browser/IBrowserWindow.cs | 6 ++ .../FileSystemDialog/IFileSystemDialog.cs | 4 +- .../IUserInterfaceFactory.cs | 6 -- ...ExamBrowser.UserInterface.Contracts.csproj | 1 + .../BrowserWindow.xaml | 11 +++- .../BrowserWindow.xaml.cs | 49 +++++++++++++--- .../Controls/Browser/DownloadItemControl.xaml | 22 ++++++++ .../Browser/DownloadItemControl.xaml.cs | 56 +++++++++++++++++++ .../FileSystemDialog.xaml | 2 +- .../FileSystemDialog.xaml.cs | 36 ++++++------ .../FileSystemDialogFactory.cs | 37 ++++++++++++ ...feExamBrowser.UserInterface.Desktop.csproj | 8 +++ .../UserInterfaceFactory.cs | 55 ++++++++---------- .../BrowserWindow.xaml | 11 +++- .../BrowserWindow.xaml.cs | 50 ++++++++++++++--- .../Controls/Browser/DownloadItemControl.xaml | 22 ++++++++ .../Browser/DownloadItemControl.xaml.cs | 56 +++++++++++++++++++ .../FileSystemDialog.xaml.cs | 36 ++++++------ .../FileSystemDialogFactory.cs | 37 ++++++++++++ ...afeExamBrowser.UserInterface.Mobile.csproj | 8 +++ .../UserInterfaceFactory.cs | 55 ++++++++---------- 30 files changed, 582 insertions(+), 133 deletions(-) create mode 100644 SafeExamBrowser.Browser/Events/DownloadUpdatedEventHandler.cs create mode 100644 SafeExamBrowser.UserInterface.Contracts/Browser/Data/DownloadItemState.cs create mode 100644 SafeExamBrowser.UserInterface.Desktop/Controls/Browser/DownloadItemControl.xaml create mode 100644 SafeExamBrowser.UserInterface.Desktop/Controls/Browser/DownloadItemControl.xaml.cs create mode 100644 SafeExamBrowser.UserInterface.Desktop/FileSystemDialogFactory.cs create mode 100644 SafeExamBrowser.UserInterface.Mobile/Controls/Browser/DownloadItemControl.xaml create mode 100644 SafeExamBrowser.UserInterface.Mobile/Controls/Browser/DownloadItemControl.xaml.cs create mode 100644 SafeExamBrowser.UserInterface.Mobile/FileSystemDialogFactory.cs diff --git a/SafeExamBrowser.Browser/BrowserApplication.cs b/SafeExamBrowser.Browser/BrowserApplication.cs index eee3daf1..51c0589c 100644 --- a/SafeExamBrowser.Browser/BrowserApplication.cs +++ b/SafeExamBrowser.Browser/BrowserApplication.cs @@ -23,6 +23,7 @@ using SafeExamBrowser.Logging.Contracts; using SafeExamBrowser.Settings.Browser.Proxy; using SafeExamBrowser.Settings.Logging; using SafeExamBrowser.UserInterface.Contracts; +using SafeExamBrowser.UserInterface.Contracts.FileSystemDialog; using SafeExamBrowser.UserInterface.Contracts.MessageBox; using BrowserSettings = SafeExamBrowser.Settings.Browser.BrowserSettings; @@ -34,6 +35,7 @@ namespace SafeExamBrowser.Browser private AppConfig appConfig; private List instances; + private IFileSystemDialog fileSystemDialog; private IMessageBox messageBox; private IModuleLogger logger; private BrowserSettings settings; @@ -53,12 +55,14 @@ namespace SafeExamBrowser.Browser public BrowserApplication( AppConfig appConfig, BrowserSettings settings, + IFileSystemDialog fileSystemDialog, IMessageBox messageBox, IModuleLogger logger, IText text, IUserInterfaceFactory uiFactory) { this.appConfig = appConfig; + this.fileSystemDialog = fileSystemDialog; this.instances = new List(); this.logger = logger; this.messageBox = messageBox; @@ -122,7 +126,7 @@ namespace SafeExamBrowser.Browser var isMainInstance = instances.Count == 0; var instanceLogger = logger.CloneFor($"Browser Instance #{id}"); var startUrl = url ?? settings.StartUrl; - var instance = new BrowserApplicationInstance(appConfig, settings, id, isMainInstance, messageBox, instanceLogger, text, uiFactory, startUrl); + var instance = new BrowserApplicationInstance(appConfig, settings, id, isMainInstance, fileSystemDialog, messageBox, instanceLogger, text, uiFactory, startUrl); instance.ConfigurationDownloadRequested += (fileName, args) => ConfigurationDownloadRequested?.Invoke(fileName, args); instance.PopupRequested += Instance_PopupRequested; diff --git a/SafeExamBrowser.Browser/BrowserApplicationInstance.cs b/SafeExamBrowser.Browser/BrowserApplicationInstance.cs index ddea35c5..e9acd50e 100644 --- a/SafeExamBrowser.Browser/BrowserApplicationInstance.cs +++ b/SafeExamBrowser.Browser/BrowserApplicationInstance.cs @@ -24,6 +24,8 @@ using SafeExamBrowser.Settings.Browser; using SafeExamBrowser.Settings.Browser.Filter; using SafeExamBrowser.UserInterface.Contracts; using SafeExamBrowser.UserInterface.Contracts.Browser; +using SafeExamBrowser.UserInterface.Contracts.Browser.Data; +using SafeExamBrowser.UserInterface.Contracts.FileSystemDialog; using SafeExamBrowser.UserInterface.Contracts.MessageBox; namespace SafeExamBrowser.Browser @@ -37,6 +39,7 @@ namespace SafeExamBrowser.Browser private IBrowserWindow window; private HttpClient httpClient; private bool isMainInstance; + private IFileSystemDialog fileSystemDialog; private IMessageBox messageBox; private IModuleLogger logger; private BrowserSettings settings; @@ -69,6 +72,7 @@ namespace SafeExamBrowser.Browser BrowserSettings settings, int id, bool isMainInstance, + IFileSystemDialog fileSystemDialog, IMessageBox messageBox, IModuleLogger logger, IText text, @@ -79,6 +83,7 @@ namespace SafeExamBrowser.Browser this.Id = id; this.httpClient = new HttpClient(); this.isMainInstance = isMainInstance; + this.fileSystemDialog = fileSystemDialog; this.messageBox = messageBox; this.logger = logger; this.settings = settings; @@ -122,6 +127,7 @@ namespace SafeExamBrowser.Browser displayHandler.FaviconChanged += DisplayHandler_FaviconChanged; displayHandler.ProgressChanged += DisplayHandler_ProgressChanged; downloadHandler.ConfigurationDownloadRequested += DownloadHandler_ConfigurationDownloadRequested; + downloadHandler.DownloadUpdated += DownloadHandler_DownloadUpdated; keyboardHandler.ReloadRequested += ReloadRequested; keyboardHandler.ZoomInRequested += ZoomInRequested; keyboardHandler.ZoomOutRequested += ZoomOutRequested; @@ -211,8 +217,7 @@ namespace SafeExamBrowser.Browser private void DialogHandler_DialogRequested(DialogRequestedEventArgs args) { - var dialog = uiFactory.CreateFileSystemDialog(args.Element, args.InitialPath, args.Operation, title: args.Title); - var result = dialog.Show(window); + var result = fileSystemDialog.Show(args.Element, args.InitialPath, args.Operation, title: args.Title, owner: window); if (result.Success) { @@ -269,6 +274,11 @@ namespace SafeExamBrowser.Browser } } + private void DownloadHandler_DownloadUpdated(DownloadItemState state) + { + window.UpdateDownloadState(state); + } + private void LifeSpanHandler_PopupRequested(PopupRequestedEventArgs args) { var validCurrentUri = Uri.TryCreate(control.Address, UriKind.Absolute, out var currentUri); diff --git a/SafeExamBrowser.Browser/Events/DownloadUpdatedEventHandler.cs b/SafeExamBrowser.Browser/Events/DownloadUpdatedEventHandler.cs new file mode 100644 index 00000000..415a67b9 --- /dev/null +++ b/SafeExamBrowser.Browser/Events/DownloadUpdatedEventHandler.cs @@ -0,0 +1,14 @@ +/* + * 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 SafeExamBrowser.UserInterface.Contracts.Browser.Data; + +namespace SafeExamBrowser.Browser.Events +{ + internal delegate void DownloadUpdatedEventHandler(DownloadItemState state); +} diff --git a/SafeExamBrowser.Browser/Handlers/DownloadHandler.cs b/SafeExamBrowser.Browser/Handlers/DownloadHandler.cs index ceef04f2..6f843ec8 100644 --- a/SafeExamBrowser.Browser/Handlers/DownloadHandler.cs +++ b/SafeExamBrowser.Browser/Handlers/DownloadHandler.cs @@ -12,8 +12,10 @@ using System.IO; using System.Threading.Tasks; using CefSharp; using SafeExamBrowser.Browser.Contracts.Events; +using SafeExamBrowser.Browser.Events; using SafeExamBrowser.Configuration.Contracts; using SafeExamBrowser.Logging.Contracts; +using SafeExamBrowser.UserInterface.Contracts.Browser.Data; using Syroot.Windows.IO; using BrowserSettings = SafeExamBrowser.Settings.Browser.BrowserSettings; @@ -24,14 +26,17 @@ namespace SafeExamBrowser.Browser.Handlers private AppConfig appConfig; private BrowserSettings settings; private ConcurrentDictionary callbacks; + private ConcurrentDictionary downloads; private ILogger logger; internal event DownloadRequestedEventHandler ConfigurationDownloadRequested; + internal event DownloadUpdatedEventHandler DownloadUpdated; internal DownloadHandler(AppConfig appConfig, BrowserSettings settings, ILogger logger) { this.appConfig = appConfig; this.callbacks = new ConcurrentDictionary(); + this.downloads = new ConcurrentDictionary(); this.logger = logger; this.settings = settings; } @@ -60,18 +65,35 @@ namespace SafeExamBrowser.Browser.Handlers public void OnDownloadUpdated(IWebBrowser webBrowser, IBrowser browser, DownloadItem downloadItem, IDownloadItemCallback callback) { - // TODO: Show download progress in respective window -> event for BrowserApplicationInstance! + var hasId = downloads.TryGetValue(downloadItem.Id, out var id); + + if (hasId) + { + var state = new DownloadItemState(id) + { + Completion = downloadItem.PercentComplete / 100.0, + FullPath = downloadItem.FullPath, + IsCancelled = downloadItem.IsCancelled, + IsComplete = downloadItem.IsComplete, + Url = downloadItem.Url + }; + + Task.Run(() => DownloadUpdated?.Invoke(state)); + } if (downloadItem.IsComplete || downloadItem.IsCancelled) { + logger.Debug($"Download of '{downloadItem.Url}' {(downloadItem.IsComplete ? "is complete" : "was cancelled")}."); + if (callbacks.TryRemove(downloadItem.Id, out DownloadFinishedCallback finished) && finished != null) { Task.Run(() => finished.Invoke(downloadItem.IsComplete, downloadItem.FullPath)); } - logger.Debug($"Download of '{downloadItem.Url}' {(downloadItem.IsComplete ? "is complete" : "was cancelled")}."); - - // TODO: Show success message or download icon like Firefox in respective window! + if (hasId) + { + downloads.TryRemove(downloadItem.Id, out _); + } } } @@ -100,6 +122,8 @@ namespace SafeExamBrowser.Browser.Handlers logger.Debug($"Automatically downloading file as '{filePath}'."); } + downloads[downloadItem.Id] = Guid.NewGuid(); + using (callback) { callback.Continue(filePath, showDialog); diff --git a/SafeExamBrowser.Browser/SafeExamBrowser.Browser.csproj b/SafeExamBrowser.Browser/SafeExamBrowser.Browser.csproj index a5f87f95..67eb5ce4 100644 --- a/SafeExamBrowser.Browser/SafeExamBrowser.Browser.csproj +++ b/SafeExamBrowser.Browser/SafeExamBrowser.Browser.csproj @@ -68,6 +68,7 @@ + diff --git a/SafeExamBrowser.Client/CompositionRoot.cs b/SafeExamBrowser.Client/CompositionRoot.cs index 430be05c..fe344f0e 100644 --- a/SafeExamBrowser.Client/CompositionRoot.cs +++ b/SafeExamBrowser.Client/CompositionRoot.cs @@ -42,6 +42,7 @@ using SafeExamBrowser.SystemComponents.Keyboard; using SafeExamBrowser.SystemComponents.PowerSupply; using SafeExamBrowser.SystemComponents.WirelessNetwork; using SafeExamBrowser.UserInterface.Contracts; +using SafeExamBrowser.UserInterface.Contracts.FileSystemDialog; using SafeExamBrowser.UserInterface.Contracts.MessageBox; using SafeExamBrowser.UserInterface.Contracts.Shell; using SafeExamBrowser.UserInterface.Shared.Activators; @@ -197,8 +198,9 @@ namespace SafeExamBrowser.Client private IOperation BuildBrowserOperation() { + var fileSystemDialog = BuildFileSystemDialog(); var moduleLogger = ModuleLogger(nameof(BrowserApplication)); - var browser = new BrowserApplication(context.AppConfig, context.Settings.Browser, messageBox, moduleLogger, text, uiFactory); + var browser = new BrowserApplication(context.AppConfig, context.Settings.Browser, fileSystemDialog, messageBox, moduleLogger, text, uiFactory); var operation = new BrowserOperation(actionCenter, context, logger, taskbar, taskview, uiFactory); context.Browser = browser; @@ -282,6 +284,17 @@ namespace SafeExamBrowser.Client } } + private IFileSystemDialog BuildFileSystemDialog() + { + switch (uiMode) + { + case UserInterfaceMode.Mobile: + return new Mobile.FileSystemDialogFactory(text); + default: + return new Desktop.FileSystemDialogFactory(text); + } + } + private IMessageBox BuildMessageBox() { switch (uiMode) diff --git a/SafeExamBrowser.I18n.Contracts/TextKey.cs b/SafeExamBrowser.I18n.Contracts/TextKey.cs index 76756748..776d52d2 100644 --- a/SafeExamBrowser.I18n.Contracts/TextKey.cs +++ b/SafeExamBrowser.I18n.Contracts/TextKey.cs @@ -22,6 +22,9 @@ namespace SafeExamBrowser.I18n.Contracts Browser_Name, Browser_Tooltip, BrowserWindow_DeveloperConsoleMenuItem, + BrowserWindow_Downloading, + BrowserWindow_DownloadCancelled, + BrowserWindow_DownloadComplete, BrowserWindow_ZoomMenuItem, Build, FileSystemDialog_Cancel, diff --git a/SafeExamBrowser.I18n/Text.xml b/SafeExamBrowser.I18n/Text.xml index e772b0db..6c4056c8 100644 --- a/SafeExamBrowser.I18n/Text.xml +++ b/SafeExamBrowser.I18n/Text.xml @@ -24,6 +24,15 @@ Developer Console + + Downloading... + + + Cancelled. + + + Downloaded. + Page Zoom diff --git a/SafeExamBrowser.UserInterface.Contracts/Browser/Data/DownloadItemState.cs b/SafeExamBrowser.UserInterface.Contracts/Browser/Data/DownloadItemState.cs new file mode 100644 index 00000000..4b1264eb --- /dev/null +++ b/SafeExamBrowser.UserInterface.Contracts/Browser/Data/DownloadItemState.cs @@ -0,0 +1,53 @@ +/* + * 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; + +namespace SafeExamBrowser.UserInterface.Contracts.Browser.Data +{ + /// + /// Defines the state of a download item. + /// + public class DownloadItemState + { + /// + /// The current completion of the item, as percentage value from 0.0 to 1.0. + /// + public double Completion { get; set; } + + /// + /// The full path of the download location for the item. + /// + public string FullPath { get; set; } + + /// + /// The unique identifier of the item. + /// + public Guid Id { get; set; } + + /// + /// Indicates that the download was cancelled. + /// + public bool IsCancelled { get; set; } + + /// + /// Indicates that the download was completed. + /// + public bool IsComplete { get; set; } + + /// + /// The download URL of the item. + /// + public string Url { get; set; } + + public DownloadItemState(Guid id) + { + Id = id; + } + } +} diff --git a/SafeExamBrowser.UserInterface.Contracts/Browser/IBrowserWindow.cs b/SafeExamBrowser.UserInterface.Contracts/Browser/IBrowserWindow.cs index c5e4be3d..478b2cdf 100644 --- a/SafeExamBrowser.UserInterface.Contracts/Browser/IBrowserWindow.cs +++ b/SafeExamBrowser.UserInterface.Contracts/Browser/IBrowserWindow.cs @@ -8,6 +8,7 @@ using System; using SafeExamBrowser.Applications.Contracts.Resources.Icons; +using SafeExamBrowser.UserInterface.Contracts.Browser.Data; using SafeExamBrowser.UserInterface.Contracts.Browser.Events; using SafeExamBrowser.UserInterface.Contracts.Windows; @@ -83,6 +84,11 @@ namespace SafeExamBrowser.UserInterface.Contracts.Browser /// void UpdateIcon(IconResource icon); + /// + /// Updates the download state for the given item. + /// + void UpdateDownloadState(DownloadItemState state); + /// /// Updates the loading state according to the given value. /// diff --git a/SafeExamBrowser.UserInterface.Contracts/FileSystemDialog/IFileSystemDialog.cs b/SafeExamBrowser.UserInterface.Contracts/FileSystemDialog/IFileSystemDialog.cs index 48976d4e..6ca62704 100644 --- a/SafeExamBrowser.UserInterface.Contracts/FileSystemDialog/IFileSystemDialog.cs +++ b/SafeExamBrowser.UserInterface.Contracts/FileSystemDialog/IFileSystemDialog.cs @@ -13,8 +13,8 @@ namespace SafeExamBrowser.UserInterface.Contracts.FileSystemDialog public interface IFileSystemDialog { /// - /// Shows the dialog to the user. If a parent window is specified, the dialog is rendered modally for the given parent. + /// Creates a dialog according to the given parameters and shows it to the user. /// - FileSystemDialogResult Show(IWindow parent = null); + FileSystemDialogResult Show(FileSystemElement element, string initialPath, FileSystemOperation operation, string message = default(string), string title = default(string), IWindow owner = default(IWindow)); } } diff --git a/SafeExamBrowser.UserInterface.Contracts/IUserInterfaceFactory.cs b/SafeExamBrowser.UserInterface.Contracts/IUserInterfaceFactory.cs index 5747f115..9f1c92c4 100644 --- a/SafeExamBrowser.UserInterface.Contracts/IUserInterfaceFactory.cs +++ b/SafeExamBrowser.UserInterface.Contracts/IUserInterfaceFactory.cs @@ -18,7 +18,6 @@ using SafeExamBrowser.SystemComponents.Contracts.Keyboard; using SafeExamBrowser.SystemComponents.Contracts.PowerSupply; using SafeExamBrowser.SystemComponents.Contracts.WirelessNetwork; using SafeExamBrowser.UserInterface.Contracts.Browser; -using SafeExamBrowser.UserInterface.Contracts.FileSystemDialog; using SafeExamBrowser.UserInterface.Contracts.Shell; using SafeExamBrowser.UserInterface.Contracts.Windows; using SafeExamBrowser.UserInterface.Contracts.Windows.Data; @@ -50,11 +49,6 @@ namespace SafeExamBrowser.UserInterface.Contracts /// IBrowserWindow CreateBrowserWindow(IBrowserControl control, BrowserSettings settings, bool isMainWindow); - /// - /// Creates a file system dialog according to the given parameters. - /// - IFileSystemDialog CreateFileSystemDialog(FileSystemElement element, string initialPath, FileSystemOperation operation, string message = default(string), string title = default(string)); - /// /// Creates a folder dialog with the given message. /// diff --git a/SafeExamBrowser.UserInterface.Contracts/SafeExamBrowser.UserInterface.Contracts.csproj b/SafeExamBrowser.UserInterface.Contracts/SafeExamBrowser.UserInterface.Contracts.csproj index 12351f12..4a19d963 100644 --- a/SafeExamBrowser.UserInterface.Contracts/SafeExamBrowser.UserInterface.Contracts.csproj +++ b/SafeExamBrowser.UserInterface.Contracts/SafeExamBrowser.UserInterface.Contracts.csproj @@ -54,6 +54,7 @@ + diff --git a/SafeExamBrowser.UserInterface.Desktop/BrowserWindow.xaml b/SafeExamBrowser.UserInterface.Desktop/BrowserWindow.xaml index 82642240..d7cdbe8b 100644 --- a/SafeExamBrowser.UserInterface.Desktop/BrowserWindow.xaml +++ b/SafeExamBrowser.UserInterface.Desktop/BrowserWindow.xaml @@ -33,12 +33,21 @@ + + + + + + + + + + + + +