1
0
mirror of https://github.com/chylex/TweetDuck.git synced 2025-04-11 12:15:44 +02:00

Refactor update notification into a bridge object & tweak installer pre-downloading

This commit is contained in:
chylex 2018-07-10 08:17:42 +02:00
parent 502ac4ebc1
commit db9daf2714
11 changed files with 147 additions and 164 deletions

View File

@ -0,0 +1,68 @@
using System;
using System.Windows.Forms;
using TweetDuck.Core.Controls;
using TweetDuck.Updates;
namespace TweetDuck.Core.Bridge{
class UpdateBridge{
private readonly UpdateHandler updates;
private readonly Control sync;
private UpdateInfo nextUpdate = null;
public event EventHandler<UpdateInfo> UpdateAccepted;
public event EventHandler<UpdateInfo> UpdateDelayed;
public event EventHandler<UpdateInfo> UpdateDismissed;
public UpdateBridge(UpdateHandler updates, Control sync){
this.sync = sync;
this.updates = updates;
this.updates.CheckFinished += updates_CheckFinished;
}
internal void Cleanup(){
updates.CheckFinished -= updates_CheckFinished;
nextUpdate?.DeleteInstaller();
}
private void updates_CheckFinished(object sender, UpdateCheckEventArgs e){
UpdateInfo foundUpdate = e.Result.HasValue ? e.Result.Value : null;
if (nextUpdate != null && !nextUpdate.Equals(foundUpdate)){
nextUpdate.DeleteInstaller();
}
nextUpdate = foundUpdate;
}
private void HandleInteractionEvent(EventHandler<UpdateInfo> eventHandler){
UpdateInfo tmpInfo = nextUpdate;
if (tmpInfo != null){
sync.InvokeAsyncSafe(() => eventHandler?.Invoke(this, tmpInfo));
}
}
// Bridge methods
public void TriggerUpdateCheck(){
updates.Check(false);
}
public void OnUpdateAccepted(){
HandleInteractionEvent(UpdateAccepted);
}
public void OnUpdateDelayed(){
HandleInteractionEvent(UpdateDelayed);
}
public void OnUpdateDismissed(){
HandleInteractionEvent(UpdateDismissed);
nextUpdate?.DeleteInstaller();
nextUpdate = null;
}
}
}

View File

@ -17,7 +17,6 @@
using TweetDuck.Plugins.Enums;
using TweetDuck.Plugins.Events;
using TweetDuck.Updates;
using TweetDuck.Updates.Events;
namespace TweetDuck.Core{
sealed partial class FormBrowser : Form, AnalyticsFile.IProvider{
@ -50,6 +49,7 @@ public bool IsWaiting{
private readonly UpdateHandler updates;
private readonly FormNotificationTweet notification;
private readonly ContextMenu contextMenu;
private readonly UpdateBridge updateBridge;
private bool isLoaded;
private FormWindowState prevState;
@ -62,7 +62,7 @@ public FormBrowser(){
InitializeComponent();
Text = Program.BrandName;
this.plugins = new PluginManager(Program.PluginPath, Program.PluginConfigFilePath);
this.plugins.Reloaded += plugins_Reloaded;
this.plugins.Executed += plugins_Executed;
@ -71,7 +71,15 @@ public FormBrowser(){
this.notification = new FormNotificationTweet(this, plugins);
this.notification.Show();
this.browser = new TweetDeckBrowser(this, new TweetDeckBridge.Browser(this, notification));
this.updates = new UpdateHandler(Program.InstallerPath);
this.updates.CheckFinished += updates_CheckFinished;
this.updateBridge = new UpdateBridge(updates, this);
this.updateBridge.UpdateAccepted += updateBridge_UpdateAccepted;
this.updateBridge.UpdateDelayed += updateBridge_UpdateDelayed;
this.updateBridge.UpdateDismissed += updateBridge_UpdateDismissed;
this.browser = new TweetDeckBrowser(this, new TweetDeckBridge.Browser(this, notification), updateBridge);
this.contextMenu = ContextMenuBrowser.CreateMenu(this);
this.plugins.Register(browser, PluginEnvironment.Browser, this, true);
@ -103,11 +111,6 @@ public FormBrowser(){
UpdateFormIcon();
}
this.updates = new UpdateHandler(browser, Program.InstallerPath);
this.updates.CheckFinished += updates_CheckFinished;
this.updates.UpdateAccepted += updates_UpdateAccepted;
this.updates.UpdateDismissed += updates_UpdateDismissed;
if (Config.AllowDataCollection){
analytics = new AnalyticsManager(this, plugins, Program.AnalyticsFilePath);
}
@ -207,7 +210,7 @@ private void FormBrowser_FormClosing(object sender, FormClosingEventArgs e){
private void FormBrowser_FormClosed(object sender, FormClosedEventArgs e){
if (isLoaded && UpdateInstallerPath == null){
updates.CleanupDownload();
updateBridge.Cleanup();
}
}
@ -252,7 +255,7 @@ private void updates_CheckFinished(object sender, UpdateCheckEventArgs e){
string tag = update.VersionTag;
if (tag != Program.VersionTag && tag != Config.DismissedUpdate){
updates.PrepareUpdate(update);
update.BeginSilentDownload();
browser.ShowUpdateNotification(tag, update.ReleaseNotes);
}
else{
@ -268,38 +271,61 @@ private void updates_CheckFinished(object sender, UpdateCheckEventArgs e){
ignoreUpdateCheckError = true;
}
private void updates_UpdateAccepted(object sender, UpdateEventArgs e){
this.InvokeAsyncSafe(() => {
FormManager.CloseAllDialogs();
private void updateBridge_UpdateAccepted(object sender, UpdateInfo update){
FormManager.CloseAllDialogs();
if (!string.IsNullOrEmpty(Config.DismissedUpdate)){
Config.DismissedUpdate = null;
Config.Save();
if (!string.IsNullOrEmpty(Config.DismissedUpdate)){
Config.DismissedUpdate = null;
Config.Save();
}
void OnFinished(){
UpdateDownloadStatus status = update.DownloadStatus;
if (status == UpdateDownloadStatus.Done){
UpdateInstallerPath = update.InstallerPath;
ForceClose();
}
else if (status != UpdateDownloadStatus.Canceled && FormMessage.Error("Update Has Failed", "Could not automatically download the update: "+(update.DownloadError?.Message ?? "unknown error")+"\n\nWould you like to open the website and try downloading the update manually?", FormMessage.Yes, FormMessage.No)){
BrowserUtils.OpenExternalBrowser(Program.Website);
ForceClose();
}
else{
Show();
}
}
if (update.DownloadStatus.IsFinished(true)){
OnFinished();
}
else{
FormUpdateDownload downloadForm = new FormUpdateDownload(update);
updates.BeginUpdateDownload(this, e.UpdateInfo, update => {
UpdateDownloadStatus status = update.DownloadStatus;
downloadForm.VisibleChanged += (sender2, args2) => {
downloadForm.MoveToCenter(this);
Hide();
};
if (status == UpdateDownloadStatus.Done){
UpdateInstallerPath = update.InstallerPath;
ForceClose();
downloadForm.FormClosed += (sender2, args2) => {
if (downloadForm.DialogResult != DialogResult.OK){
update.CancelDownload();
}
else if (status != UpdateDownloadStatus.Canceled && FormMessage.Error("Update Has Failed", "Could not automatically download the update: "+(update.DownloadError?.Message ?? "unknown error")+"\n\nWould you like to open the website and try downloading the update manually?", FormMessage.Yes, FormMessage.No)){
BrowserUtils.OpenExternalBrowser(Program.Website);
ForceClose();
}
else{
Show();
}
});
});
downloadForm.Dispose();
OnFinished();
};
downloadForm.Show();
}
}
private void updates_UpdateDismissed(object sender, UpdateEventArgs e){
this.InvokeAsyncSafe(() => {
Config.DismissedUpdate = e.UpdateInfo.VersionTag;
Config.Save();
});
private void updateBridge_UpdateDelayed(object sender, UpdateInfo update){
// stops the timer
}
private void updateBridge_UpdateDismissed(object sender, UpdateInfo update){
Config.DismissedUpdate = update.VersionTag;
Config.Save();
}
protected override void WndProc(ref Message m){

View File

@ -7,7 +7,6 @@
using TweetDuck.Core.Other.Settings.Dialogs;
using TweetDuck.Core.Utils;
using TweetDuck.Updates;
using TweetDuck.Updates.Events;
namespace TweetDuck.Core.Other.Settings{
sealed partial class TabSettingsGeneral : BaseTabSettings{
@ -210,11 +209,6 @@ private void btnCheckUpdates_Click(object sender, EventArgs e){
btnCheckUpdates.Enabled = false;
updateCheckEventId = updates.Check(true);
if (updateCheckEventId == UpdateHandler.CheckCodeNotOnTweetDeck){
FormMessage.Error("Update Check", "Updates can only be checked once TweetDeck is fully loaded.", FormMessage.OK);
btnCheckUpdates.Enabled = true;
}
}
private void updates_CheckFinished(object sender, UpdateCheckEventArgs e){
@ -225,6 +219,8 @@ private void updates_CheckFinished(object sender, UpdateCheckEventArgs e){
if (update.VersionTag == Program.VersionTag){
FormMessage.Information("No Updates Available", "Your version of TweetDuck is up to date.", FormMessage.OK);
}
// TODO allow outside TweetDeck
}, ex => {
Program.Reporter.HandleException("Update Check Error", "An error occurred while checking for updates.", true, ex);
});

View File

@ -9,7 +9,6 @@
using TweetDuck.Core.Controls;
using TweetDuck.Core.Handling;
using TweetDuck.Core.Handling.General;
using TweetDuck.Core.Management;
using TweetDuck.Core.Notification;
using TweetDuck.Core.Other.Interfaces;
using TweetDuck.Core.Utils;
@ -40,7 +39,7 @@ public bool IsTweetDeckWebsite{
private string prevSoundNotificationPath = null;
public TweetDeckBrowser(FormBrowser owner, TweetDeckBridge bridge){
public TweetDeckBrowser(FormBrowser owner, TweetDeckBridge tdBridge, UpdateBridge updateBridge){
RequestHandlerBrowser requestHandler = new RequestHandlerBrowser();
this.browser = new ChromiumWebBrowser(TwitterUtils.TweetDeckURL){
@ -58,7 +57,8 @@ public TweetDeckBrowser(FormBrowser owner, TweetDeckBridge bridge){
this.browser.FrameLoadEnd += browser_FrameLoadEnd;
this.browser.LoadError += browser_LoadError;
this.browser.RegisterAsyncJsObject("$TD", bridge);
this.browser.RegisterAsyncJsObject("$TD", tdBridge);
this.browser.RegisterAsyncJsObject("$TDU", updateBridge);
this.browser.BrowserSettings.BackgroundColor = (uint)TwitterUtils.BackgroundColor.ToArgb();
this.browser.Dock = DockStyle.None;

View File

@ -58,6 +58,7 @@
<Compile Include="Configuration\SystemConfig.cs" />
<Compile Include="Configuration\UserConfig.cs" />
<Compile Include="Core\Bridge\PropertyBridge.cs" />
<Compile Include="Core\Bridge\UpdateBridge.cs" />
<Compile Include="Core\Controls\ControlExtensions.cs" />
<Compile Include="Core\Controls\FlatButton.cs">
<SubType>Component</SubType>
@ -283,7 +284,7 @@
<DependentUpon>Resources.resx</DependentUpon>
</Compile>
<Compile Include="Reporter.cs" />
<Compile Include="Updates\Events\UpdateCheckEventArgs.cs" />
<Compile Include="Updates\UpdateCheckEventArgs.cs" />
<Compile Include="Updates\FormUpdateDownload.cs">
<SubType>Form</SubType>
</Compile>
@ -306,7 +307,6 @@
<Compile Include="Program.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="Resources\ScriptLoader.cs" />
<Compile Include="Updates\Events\UpdateEventArgs.cs" />
</ItemGroup>
<ItemGroup>
<BootstrapperPackage Include="Microsoft.Net.Client.3.5">

View File

@ -1,11 +0,0 @@
using System;
namespace TweetDuck.Updates.Events{
sealed class UpdateEventArgs : EventArgs{
public UpdateInfo UpdateInfo { get; }
public UpdateEventArgs(UpdateInfo updateInfo){
this.UpdateInfo = updateInfo;
}
}
}

View File

@ -20,7 +20,7 @@ private void btnCancel_Click(object sender, EventArgs e){
}
private void timerDownloadCheck_Tick(object sender, EventArgs e){
if (updateInfo.DownloadStatus.IsFinished()){
if (updateInfo.DownloadStatus.IsFinished(false)){
timerDownloadCheck.Stop();
DialogResult = DialogResult.OK;
Close();

View File

@ -1,7 +1,7 @@
using System;
using TweetDuck.Data;
namespace TweetDuck.Updates.Events{
namespace TweetDuck.Updates{
sealed class UpdateCheckEventArgs : EventArgs{
public int EventId { get; }
public Result<UpdateInfo> Result { get; }

View File

@ -9,8 +9,8 @@ public enum UpdateDownloadStatus{
}
public static class UpdateDownloadStatusExtensions{
public static bool IsFinished(this UpdateDownloadStatus status){
return status == UpdateDownloadStatus.AssetMissing || status == UpdateDownloadStatus.Done || status == UpdateDownloadStatus.Failed;
public static bool IsFinished(this UpdateDownloadStatus status, bool canRetry){
return status == UpdateDownloadStatus.AssetMissing || status == UpdateDownloadStatus.Done || (status == UpdateDownloadStatus.Failed && !canRetry);
}
}
}

View File

@ -1,38 +1,24 @@
using System;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Forms;
using TweetDuck.Core.Controls;
using TweetDuck.Core.Other.Interfaces;
using TweetDuck.Data;
using TweetDuck.Updates.Events;
using Timer = System.Windows.Forms.Timer;
namespace TweetDuck.Updates{
sealed class UpdateHandler : IDisposable{
public const int CheckCodeUpdatesDisabled = -1;
public const int CheckCodeNotOnTweetDeck = -2;
private readonly UpdateCheckClient client;
private readonly TaskScheduler scheduler;
private readonly ITweetDeckBrowser browser;
private readonly Timer timer;
public event EventHandler<UpdateEventArgs> UpdateAccepted;
public event EventHandler<UpdateEventArgs> UpdateDelayed;
public event EventHandler<UpdateEventArgs> UpdateDismissed;
public event EventHandler<UpdateCheckEventArgs> CheckFinished;
private ushort lastEventId;
private UpdateInfo lastUpdateInfo;
public UpdateHandler(ITweetDeckBrowser browser, string installerFolder){
public UpdateHandler(string installerFolder){
this.client = new UpdateCheckClient(installerFolder);
this.scheduler = TaskScheduler.FromCurrentSynchronizationContext();
this.browser = browser;
this.browser.RegisterBridge("$TDU", new Bridge(this));
this.timer = new Timer();
this.timer.Tick += timer_Tick;
}
@ -68,10 +54,6 @@ public void StartTimer(){
public int Check(bool force){
if (Program.UserConfig.EnableUpdateCheck || force){
if (!browser.IsTweetDeckWebsite){
return CheckCodeNotOnTweetDeck;
}
int nextEventId = unchecked(++lastEventId);
Task<UpdateInfo> checkTask = client.Check();
@ -84,46 +66,6 @@ public int Check(bool force){
return CheckCodeUpdatesDisabled;
}
public void PrepareUpdate(UpdateInfo info){
CleanupDownload();
lastUpdateInfo = info;
lastUpdateInfo.BeginSilentDownload();
}
public void BeginUpdateDownload(Form ownerForm, UpdateInfo updateInfo, Action<UpdateInfo> onFinished){
UpdateDownloadStatus status = updateInfo.DownloadStatus;
if (status == UpdateDownloadStatus.Done || status == UpdateDownloadStatus.AssetMissing){
onFinished(updateInfo);
}
else{
FormUpdateDownload downloadForm = new FormUpdateDownload(updateInfo);
downloadForm.VisibleChanged += (sender, args) => {
downloadForm.MoveToCenter(ownerForm);
ownerForm.Hide();
};
downloadForm.FormClosed += (sender, args) => {
if (downloadForm.DialogResult != DialogResult.OK){
updateInfo.CancelDownload();
}
downloadForm.Dispose();
onFinished(updateInfo);
};
downloadForm.Show();
}
}
public void CleanupDownload(){
if (lastUpdateInfo != null){
lastUpdateInfo.DeleteInstaller();
lastUpdateInfo = null;
}
}
private void HandleUpdateCheckSuccessful(int eventId, UpdateInfo info){
CheckFinished?.Invoke(this, new UpdateCheckEventArgs(eventId, new Result<UpdateInfo>(info)));
}
@ -131,48 +73,5 @@ private void HandleUpdateCheckSuccessful(int eventId, UpdateInfo info){
private void HandleUpdateCheckFailed(int eventId, Exception exception){
CheckFinished?.Invoke(this, new UpdateCheckEventArgs(eventId, new Result<UpdateInfo>(exception)));
}
private void TriggerUpdateAcceptedEvent(){
if (lastUpdateInfo != null){
UpdateAccepted?.Invoke(this, new UpdateEventArgs(lastUpdateInfo));
}
}
private void TriggerUpdateDelayedEvent(){
if (lastUpdateInfo != null){
UpdateDelayed?.Invoke(this, new UpdateEventArgs(lastUpdateInfo));
}
}
private void TriggerUpdateDismissedEvent(){
if (lastUpdateInfo != null){
UpdateDismissed?.Invoke(this, new UpdateEventArgs(lastUpdateInfo));
CleanupDownload();
}
}
public sealed class Bridge{
private readonly UpdateHandler owner;
public Bridge(UpdateHandler owner){
this.owner = owner;
}
public void TriggerUpdateCheck(){
owner.Check(false);
}
public void OnUpdateAccepted(){
owner.TriggerUpdateAcceptedEvent();
}
public void OnUpdateDelayed(){
owner.TriggerUpdateDelayedEvent();
}
public void OnUpdateDismissed(){
owner.TriggerUpdateDismissedEvent();
}
}
}
}

View File

@ -26,6 +26,11 @@ public UpdateInfo(string versionTag, string releaseNotes, string downloadUrl, st
}
public void BeginSilentDownload(){
if (File.Exists(InstallerPath)){
DownloadStatus = UpdateDownloadStatus.Done;
return;
}
if (DownloadStatus == UpdateDownloadStatus.None || DownloadStatus == UpdateDownloadStatus.Failed){
DownloadStatus = UpdateDownloadStatus.InProgress;