using System; using System.Collections.Generic; using System.Diagnostics; using System.Linq; using System.Text; using System.Threading.Tasks; using System.Timers; using Tango.Core.DI; using Tango.Core.ExtensionMethods; using Tango.FSE.BL.Web; using Tango.FSE.Common; using Tango.FSE.Common.Authentication; using Tango.FSE.Common.Build; using Tango.FSE.Common.DemoMode; using Tango.FSE.Common.FSEApplication; using Tango.FSE.Common.Notifications; using Tango.FSE.Common.Threading; using Tango.FSE.Common.Updates; using Tango.FSE.UI.Dialogs; using Tango.FSE.Web.Messages; namespace Tango.FSE.UI.Updates { /// /// Represents the default implementation. /// /// [TangoCreateWhenRegistered] public class DefaultUpdatesManager : FSEExtendedObject, IUpdatesManager { private Timer _autoUpdateCheckTimer; private const double AUTO_UPDATE_CHECK_INTERVAL_MINUTES = 30; private bool _performedFirstCheck; [TangoInject] private FSEWebClient WebClient { get; set; } [TangoInject] private IFSEApplicationManager ApplicationManager { get; set; } [TangoInject] private INotificationProvider NotificationProvider { get; set; } [TangoInject] private IDispatcherProvider DispatcherProvider { get; set; } [TangoInject] private IAuthenticationProvider AuthenticationProvider { get; set; } [TangoInject(TangoInjectMode.WhenAvailable)] private IDemoModeManager DemoModeManager { get; set; } [TangoInject] private IBuildProvider BuildProvider { get; set; } /// /// Gets or sets a value indicating whether to perform an automatic update checks. /// public bool AutoCheckForUpdates { get; set; } /// /// Gets or sets the automatic update check interval. /// public TimeSpan AutoUpdateCheckInterval { get; set; } /// /// Initializes a new instance of the class. /// public DefaultUpdatesManager() { _autoUpdateCheckTimer = new Timer(TimeSpan.FromMinutes(AUTO_UPDATE_CHECK_INTERVAL_MINUTES).TotalMilliseconds); _autoUpdateCheckTimer.Elapsed += _autoUpdateCheckTimer_Elapsed; _autoUpdateCheckTimer.Stop(); } /// /// Checks for updates and returns a response containing the relevant blob/cdn addresses. /// /// public async Task CheckForUpdates() { try { LogManager.Log("Checking for updates..."); var appVersion = ApplicationManager.Version; var response = await WebClient.CheckForUpdates(new CheckForUpdatesRequest() { Version = appVersion.ToString(), Build = Tango.FSE.BL.BuildProvider.Build }); LogManager.Log($"Update check response received:\n{response.ToJsonString()}"); return response; } catch (Exception ex) { throw LogManager.Log(ex, "Error checking for updates."); } } /// /// Called when is ready and user is logged-in. (happens every time a user logs-in) /// public async void OnApplicationReady(IFSEApplicationManager applicationManager) { if (!_performedFirstCheck) { _performedFirstCheck = true; if (!applicationManager.DemoMode) { try { await Task.Delay(3000); LogManager.Log("Performing first application update check..."); var response = await CheckForUpdates(); if (response.IsUpdateAvailable) { LogManager.Log("Update is available. Invoking application update dialog..."); DisplayApplicationUpdateDialog(response); } } catch { LogManager.Log("First application run update check failed."); } } } _autoUpdateCheckTimer.Start(); if (applicationManager.DemoMode) { DemoModeManager.InsertCommand(async () => { await CheckForUpdatesWithDialog(); }, "Emulate Application Update", "Emulates an application update snackbar notification."); } } private async void _autoUpdateCheckTimer_Elapsed(object sender, ElapsedEventArgs e) { _autoUpdateCheckTimer.Stop(); if (Settings.AutoCheckForUpdates) { await CheckForUpdatesWithDialog(); } _autoUpdateCheckTimer.Start(); } private async Task CheckForUpdatesWithDialog() { try { LogManager.Log("Performing automatic update check..."); var response = await CheckForUpdates(); if (response.IsUpdateAvailable) { LogManager.Log("Application update is available. Pushing snackbar item..."); DispatcherProvider.Invoke(() => { NotificationProvider.PushSnackbarItem( MessageType.ApplicationUpdate, "Application Update", true, $"New version of {BuildProvider.BuildName} is available\nTap to see more details.", TimeSpan.FromMinutes(5), null, () => { LogManager.Log("Application update snackbar item pressed. Invoking application update dialog..."); DisplayApplicationUpdateDialog(response); }); }); } } catch { LogManager.Log("Automatic update check failed."); } } private void DisplayApplicationUpdateDialog(CheckForUpdatesResponse response) { DispatcherProvider.Invoke(async () => { var vm = await NotificationProvider.ShowDialog(new ApplicationUpdateViewVM() { Version = Version.Parse(response.Version).ToString(3), Comments = response.Comments }); if (vm.DialogResult) { Process.Start(AuthenticationProvider.CurrentEnvironment.MachineServiceAddress + $"/fse?buildVariant={(int)BuildProvider.CurrentBuild}"); } }); } } }