diff options
| author | Avi Levkovich <avi@twine-s.com> | 2018-02-26 16:30:42 +0200 |
|---|---|---|
| committer | Avi Levkovich <avi@twine-s.com> | 2018-02-26 16:30:42 +0200 |
| commit | 5942bb7a13e5ad26c720a1b95ae4ea766eeeda25 (patch) | |
| tree | 2a855ce1065c875e615f5b040f984cb3fb84e518 /Software/Visual_Studio/MachineStudio/Tango.MachineStudio.UI/ViewModels | |
| parent | 4c052df707280abd208b03aa88cf904e0eb6b9bf (diff) | |
| parent | 6549d8672a93893599e921d9f1938af7dcabb8bf (diff) | |
| download | Tango-5942bb7a13e5ad26c720a1b95ae4ea766eeeda25.tar.gz Tango-5942bb7a13e5ad26c720a1b95ae4ea766eeeda25.zip | |
MERGE!
Diffstat (limited to 'Software/Visual_Studio/MachineStudio/Tango.MachineStudio.UI/ViewModels')
4 files changed, 496 insertions, 1 deletions
diff --git a/Software/Visual_Studio/MachineStudio/Tango.MachineStudio.UI/ViewModels/LoadingViewVM.cs b/Software/Visual_Studio/MachineStudio/Tango.MachineStudio.UI/ViewModels/LoadingViewVM.cs index 55a54e8aa..9acf26afd 100644 --- a/Software/Visual_Studio/MachineStudio/Tango.MachineStudio.UI/ViewModels/LoadingViewVM.cs +++ b/Software/Visual_Studio/MachineStudio/Tango.MachineStudio.UI/ViewModels/LoadingViewVM.cs @@ -6,9 +6,11 @@ using System.Threading; using System.Threading.Tasks; using Tango.Core.Helpers; using Tango.Integration.Observables; +using Tango.Logging; using Tango.MachineStudio.Common.Modules; using Tango.MachineStudio.Common.Navigation; using Tango.MachineStudio.Common.Notifications; +using Tango.MachineStudio.Common.StudioApplication; using Tango.SharedUI; namespace Tango.MachineStudio.UI.ViewModels @@ -23,14 +25,17 @@ namespace Tango.MachineStudio.UI.ViewModels private INavigationManager _navigationManager; private IStudioModuleLoader _studioModuleLoader; + public IStudioApplicationManager ApplicationManager { get; set; } + /// <summary> /// Initializes a new instance of the <see cref="LoadingViewVM"/> class. /// </summary> /// <param name="navigationManager">The navigation manager.</param> /// <param name="studioModuleLoader">The studio module loader.</param> /// <param name="notificationProvider">The notification provider.</param> - public LoadingViewVM(INavigationManager navigationManager, IStudioModuleLoader studioModuleLoader, INotificationProvider notificationProvider) + public LoadingViewVM(IStudioApplicationManager applicationManager, INavigationManager navigationManager, IStudioModuleLoader studioModuleLoader, INotificationProvider notificationProvider) { + ApplicationManager = applicationManager; _navigationManager = navigationManager; _studioModuleLoader = studioModuleLoader; _notificationProvider = notificationProvider; @@ -55,6 +60,8 @@ namespace Tango.MachineStudio.UI.ViewModels } catch (Exception ex) { + LogManager.Log(ex); + InvokeUINow(() => { if (_notificationProvider.ShowQuestion("An error occurred while trying to connect to Twine database." + Environment.NewLine + "Would you like to try again?")) diff --git a/Software/Visual_Studio/MachineStudio/Tango.MachineStudio.UI/ViewModels/MainViewVM.cs b/Software/Visual_Studio/MachineStudio/Tango.MachineStudio.UI/ViewModels/MainViewVM.cs index 679ba5ff3..fb2cd5c82 100644 --- a/Software/Visual_Studio/MachineStudio/Tango.MachineStudio.UI/ViewModels/MainViewVM.cs +++ b/Software/Visual_Studio/MachineStudio/Tango.MachineStudio.UI/ViewModels/MainViewVM.cs @@ -6,7 +6,11 @@ using System.IO; using System.Linq; using System.Reflection; using System.Text; +using System.Threading; using System.Threading.Tasks; +using System.Windows; +using System.Windows.Controls; +using System.Windows.Media; using Tango.Core.Commands; using Tango.Integration.Services; using Tango.Logging; @@ -16,10 +20,14 @@ using Tango.MachineStudio.Common.Modules; using Tango.MachineStudio.Common.Navigation; using Tango.MachineStudio.Common.Notifications; using Tango.MachineStudio.Common.StudioApplication; +using Tango.MachineStudio.Common.Update; +using Tango.MachineStudio.UI.StudioApplication; using Tango.MachineStudio.UI.SupervisingController; using Tango.MachineStudio.UI.Views; +using Tango.MachineStudio.UI.Windows; using Tango.PMR.Stubs; using Tango.SharedUI; +using Tango.SharedUI.Helpers; using Tango.Transport.Adapters; namespace Tango.MachineStudio.UI.ViewModels @@ -33,6 +41,7 @@ namespace Tango.MachineStudio.UI.ViewModels private IStudioModule _currentModule; private INavigationManager _navigation; private bool _isDisconnecting; + private Thread _updateCheckThread; /// <summary> /// Gets or sets the current loaded module. @@ -69,6 +78,11 @@ namespace Tango.MachineStudio.UI.ViewModels public RelayCommand<IStudioModule> StartModuleCommand { get; set; } /// <summary> + /// Gets or sets the open module in window command. + /// </summary> + public RelayCommand<IStudioModule> OpenModuleInWindowCommand { get; set; } + + /// <summary> /// Gets or sets the home command. /// </summary> public RelayCommand HomeCommand { get; set; } @@ -88,6 +102,16 @@ namespace Tango.MachineStudio.UI.ViewModels /// </summary> public RelayCommand SignoutCommand { get; set; } + /// <summary> + /// Gets or sets the exit command. + /// </summary> + public RelayCommand ExitCommand { get; set; } + + /// <summary> + /// Gets or sets the update center command. + /// </summary> + public RelayCommand UpdateCenterCommand { get; set; } + private IAuthenticationProvider _authenticationProvider; /// <summary> /// Gets or sets the authentication provider. @@ -128,6 +152,38 @@ namespace Tango.MachineStudio.UI.ViewModels set { _applicationManager = value; RaisePropertyChangedAuto(); } } + private bool _isUpdateAvailable; + /// <summary> + /// Gets or sets a value indicating whether a new version update is available. + /// </summary> + public bool IsUpdateAvailable + { + get { return _isUpdateAvailable; } + set { _isUpdateAvailable = value; RaisePropertyChangedAuto(); } + } + + private String _latestVersion; + /// <summary> + /// Gets or sets the latest version. + /// </summary> + public String LatestVersion + { + get { return _latestVersion; } + set { _latestVersion = value; RaisePropertyChangedAuto(); } + } + + + private bool _disableCheckForUpdates; + /// <summary> + /// Gets or sets a value indicating whether [disable check for updates]. + /// </summary> + public bool DisableCheckForUpdates + { + get { return _disableCheckForUpdates; } + set { _disableCheckForUpdates = value; RaisePropertyChangedAuto(); } + } + + /// <summary> /// Initializes a new instance of the <see cref="MainViewVM"/> class. /// </summary> @@ -157,6 +213,46 @@ namespace Tango.MachineStudio.UI.ViewModels ConnectCommand = new RelayCommand(ConnectToMachine); SignoutCommand = new RelayCommand(SignOut); DisconnectCommand = new RelayCommand(DisconnectFromMachine, (x) => ApplicationManager.IsMachineConnected && !_isDisconnecting); + OpenModuleInWindowCommand = new RelayCommand<IStudioModule>(OpenModuleInWindow); + ExitCommand = new RelayCommand(ExitApplication); + UpdateCenterCommand = new RelayCommand(NavigateToUpdateCenter); + + _updateCheckThread = new Thread(UpdateCheckThreadMethod); + _updateCheckThread.IsBackground = true; + _updateCheckThread.Start(); + } + + private void UpdateCheckThreadMethod() + { + while (!DisableCheckForUpdates) + { + Thread.Sleep(TimeSpan.FromMinutes(1)); + + try + { + if (_authenticationProvider.CurrentUser != null) + { + var service = UpdateServiceHelper.GetUpdateServiceChannel(); + var client = service.CreateChannel(); + + CheckForUpdatesResponse response = client.CheckForUpdates(new CheckForUpdatesRequest() + { + Email = _authenticationProvider.CurrentUser.Email, + Password = _authenticationProvider.CurrentUser.Password, + Version = _applicationManager.Version, + }); + + IsUpdateAvailable = response.IsUpdateAvailable; + LatestVersion = response.Version; + } + } + catch (Exception ex) + { + LogManager.Log(ex, "Error in version update periodic check..."); + } + + Thread.Sleep(TimeSpan.FromMinutes(4)); + } } /// <summary> @@ -302,5 +398,62 @@ namespace Tango.MachineStudio.UI.ViewModels { base.OnViewAttached(); } + + /// <summary> + /// Opens the module in a new window. + /// </summary> + /// <param name="module">The module.</param> + private void OpenModuleInWindow(IStudioModule module) + { + if (module == null) return; + + try + { + StartModule(null); + + module.InNewWindow = true; + + var parent = (MainView.Self as MainView).TransitionControl.Controls.SingleOrDefault(x => x.Tag.ToString() == module.Name).Content as Grid; + + var view = parent.Children[0] as FrameworkElement; + parent.Children.Remove(view); + + ModuleWindowVM vm = new ModuleWindowVM(module, parent); + ModuleWindow window = new ModuleWindow(this, vm, view); + + window.Closing += (x, y) => + { + window.grid.Children.Remove(view); + parent.Children.Add(view); + module.InNewWindow = false; + }; + + window.Owner = MainWindow.Instance; + window.Show(); + + (_applicationManager as DefaultStudioApplicationManager).RegisterOpenedWindow(window); + } + catch (Exception ex) + { + LogManager.Log(ex, "Error popping out module " + module.Name); + _notificationProvider.ShowError("Error popping out module " + module.Name); + } + } + + /// <summary> + /// Navigates to update center. + /// </summary> + private void NavigateToUpdateCenter() + { + _navigation.NavigateTo(NavigationView.UpdateView); + } + + /// <summary> + /// Exits the application. + /// </summary> + private void ExitApplication() + { + _applicationManager.ShutDown(); + } } } diff --git a/Software/Visual_Studio/MachineStudio/Tango.MachineStudio.UI/ViewModels/ModuleWindowVM.cs b/Software/Visual_Studio/MachineStudio/Tango.MachineStudio.UI/ViewModels/ModuleWindowVM.cs new file mode 100644 index 000000000..a5b737b59 --- /dev/null +++ b/Software/Visual_Studio/MachineStudio/Tango.MachineStudio.UI/ViewModels/ModuleWindowVM.cs @@ -0,0 +1,30 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.Windows.Controls; +using Tango.MachineStudio.Common; +using Tango.SharedUI; + +namespace Tango.MachineStudio.UI.ViewModels +{ + public class ModuleWindowVM : ViewModel + { + private IStudioModule _module; + + public IStudioModule Module + { + get { return _module; } + set { _module = value; RaisePropertyChangedAuto(); } + } + + public Grid Parent { get; set; } + + public ModuleWindowVM(IStudioModule module, Grid parent) + { + Parent = parent; + Module = module; + } + } +} diff --git a/Software/Visual_Studio/MachineStudio/Tango.MachineStudio.UI/ViewModels/UpdateViewVM.cs b/Software/Visual_Studio/MachineStudio/Tango.MachineStudio.UI/ViewModels/UpdateViewVM.cs new file mode 100644 index 000000000..6be4ba4ca --- /dev/null +++ b/Software/Visual_Studio/MachineStudio/Tango.MachineStudio.UI/ViewModels/UpdateViewVM.cs @@ -0,0 +1,305 @@ +using FluentFTP; +using Ionic.Zip; +using Microsoft.Practices.ServiceLocation; +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.IO; +using System.Linq; +using System.Runtime.CompilerServices; +using System.ServiceModel; +using System.Text; +using System.Threading; +using System.Threading.Tasks; +using Tango.Core.Commands; +using Tango.Core.Helpers; +using Tango.Logging; +using Tango.MachineStudio.Common.Authentication; +using Tango.MachineStudio.Common.Navigation; +using Tango.MachineStudio.Common.Notifications; +using Tango.MachineStudio.Common.StudioApplication; +using Tango.MachineStudio.Common.Update; +using Tango.SharedUI; + +namespace Tango.MachineStudio.UI.ViewModels +{ + public enum UpdateStatus + { + None, + CheckingForUpdate, + UpToDate, + UpdateAvailable, + Downloading, + Updating, + UpdateCompleted, + Error, + } + + public class UpdateViewVM : ViewModel + { + private String _appPath = AppDomain.CurrentDomain.BaseDirectory; + + private INotificationProvider _notification; + private INavigationManager _navigation; + private IStudioApplicationManager _application; + private IAuthenticationProvider _authentication; + private CheckForUpdatesResponse _updateInfo; + private String _newPackageTempFolder; + + private UpdateStatus _status; + public UpdateStatus Status + { + get { return _status; } + set { _status = value; RaisePropertyChangedAuto(); } + } + + private String _latestVersion; + public String LatestVersion + { + get { return _latestVersion; } + set { _latestVersion = value; RaisePropertyChangedAuto(); } + } + + private double _downloadProgress; + + public double DownloadProgress + { + get { return _downloadProgress; } + set { _downloadProgress = value; RaisePropertyChangedAuto(); } + } + + private double _updateProgress; + + public double UpdateProgress + { + get { return _updateProgress; } + set { _updateProgress = value; RaisePropertyChangedAuto(); } + } + + private String _currentUpdateFile; + + public String CurrentUpdateFile + { + get { return _currentUpdateFile; } + set { _currentUpdateFile = value; RaisePropertyChanged(nameof(CurrentUpdateFile)); } + } + + public RelayCommand UpdateCommand { get; set; } + + public RelayCommand BackCommand { get; set; } + + public RelayCommand RestartCommand { get; set; } + + public RelayCommand TryAgainCommand { get; set; } + + public UpdateViewVM(INotificationProvider notification, IAuthenticationProvider authentication, INavigationManager navigation, IStudioApplicationManager application) + { + _notification = notification; + _navigation = navigation; + _application = application; + _authentication = authentication; + + LatestVersion = "1.0.0.2"; + Status = UpdateStatus.CheckingForUpdate; + UpdateCommand = new RelayCommand(StartUpdate, () => Status == UpdateStatus.UpdateAvailable); + BackCommand = new RelayCommand(BackToApplication, () => Status != UpdateStatus.Updating); + RestartCommand = new RelayCommand(RestartApplication, () => Status == UpdateStatus.UpdateCompleted); + TryAgainCommand = new RelayCommand(TryAgain, () => Status == UpdateStatus.Error); + } + + public void OnNavigatedInto() + { + CheckForUpdates(); + } + + private void CheckForUpdates() + { + Status = UpdateStatus.CheckingForUpdate; + + ChannelFactory<IMachineStudioUpdateService> service = null; + + Task.Factory.StartNew(() => + { + try + { + Thread.Sleep(2000); + + service = UpdateServiceHelper.GetUpdateServiceChannel(); + var client = service.CreateChannel(); + + CheckForUpdatesResponse response = client.CheckForUpdates(new CheckForUpdatesRequest() + { + Email = _authentication.CurrentUser.Email, + Password = _authentication.CurrentUser.Password, + Version = _application.Version, + }); + + if (response.IsUpdateAvailable) + { + _updateInfo = response; + Status = UpdateStatus.UpdateAvailable; + LatestVersion = response.Version; + } + else + { + Status = UpdateStatus.UpToDate; + } + } + catch (Exception ex) + { + LogManager.Log(ex, "Error while checking for version update!"); + Status = UpdateStatus.Error; + } + finally + { + if (service != null) + { + service.Close(); + } + } + }); + } + + private void BackToApplication() + { + if (Status == UpdateStatus.Downloading) + { + if (!_notification.ShowQuestion("This will abort all update operations. Are you sure?")) + { + return; + } + } + + _navigation.NavigateTo(NavigationView.MainView); + Status = UpdateStatus.None; + } + + private void StartUpdate() + { + DownloadProgress = 0; + UpdateProgress = 0; + + Status = UpdateStatus.Downloading; + + Task.Factory.StartNew(() => + { + var tempFile = PathHelper.GetTempFilePath() + ".zip"; + + try + { + LogManager.Log("Creating temporary file " + tempFile); + + int fileSize = 0; + + using (FileStreamWrapper fs = new FileStreamWrapper(tempFile, FileMode.Create, (current) => + { + InvokeUINow(() => + { + Thread.Sleep(10); + DownloadProgress = ((double)current / (double)fileSize) * 100d; + }); + })) + { + using (FtpClient ftp = new FtpClient(_updateInfo.FtpHost, _updateInfo.UserName, _updateInfo.Password)) + { + LogManager.Log("Connecting to FTP site: " + _updateInfo.FtpHost); + ftp.ConnectAsync().Wait(); + LogManager.Log("Retrieving download size..."); + fileSize = (int)ftp.GetFileSize(_updateInfo.FilePath); + LogManager.Log("Download size: " + fileSize + " bytes."); + LogManager.Log("Starting download..."); + ftp.DownloadAsync(fs, _updateInfo.FilePath).Wait(); + } + } + + + Status = UpdateStatus.Updating; + + _newPackageTempFolder = PathHelper.GetTempFolderPath(); + + using (ZipFile zip = ZipFile.Read(tempFile)) + { + int currentEntry = 0; + + zip.ExtractProgress += (x, args) => + { + if (args.EventType == ZipProgressEventType.Extracting_AfterExtractEntry) + { + LogManager.Log("Extracting " + Path.GetFileName(args.CurrentEntry.FileName)); + UpdateProgress = ((double)(currentEntry++) / (double)zip.Entries.Count) * 100d; + } + }; + + foreach (ZipEntry entry in zip) + { + Thread.Sleep(10); + + string newPath = Path.Combine(_newPackageTempFolder, entry.FileName); + + try + { + if (entry.IsDirectory) + { + Directory.CreateDirectory(newPath); + } + else + { + CurrentUpdateFile = Path.GetFileName(entry.FileName); + entry.Extract(_newPackageTempFolder, ExtractExistingFileAction.OverwriteSilently); + } + } + catch + { + LogManager.Log("Could not extract file " + entry.FileName); + } + } + } + + ServiceLocator.Current.GetInstance<MainViewVM>().DisableCheckForUpdates = true; + Status = UpdateStatus.UpdateCompleted; + } + catch (Exception ex) + { + LogManager.Log(ex, "Error while extracting update package."); + Status = UpdateStatus.Error; + } + finally + { + PathHelper.TryDeleteFile(tempFile); + } + }); + } + + private void TryAgain() + { + CheckForUpdates(); + } + + private void RestartApplication() + { + try + { + Process p = new Process(); + p.StartInfo.FileName = _appPath + "\\Tango.MachineStudio.Updater.exe"; + p.StartInfo.UseShellExecute = true; + p.StartInfo.Arguments = _newPackageTempFolder; + p.Start(); + } + catch (Exception ex) + { + if (ex.Message == "The operation was canceled by the user") + { + _notification.ShowWarning("It seems like you refused to invoke our update utility. This prevents Machine Studio from completing the update process!"); + return; + } + } + Environment.Exit(0); + } + + protected override void RaisePropertyChangedAuto([CallerMemberName] string caller = null) + { + base.RaisePropertyChangedAuto(caller); + InvalidateRelayCommands(); + } + } +} |
