mirror of
https://github.com/chylex/TweetDuck.git
synced 2025-09-14 10:32:10 +02:00
Compare commits
15 Commits
Author | SHA1 | Date | |
---|---|---|---|
a63e210b88 | |||
06bd65b7f8 | |||
b6c17eb05e | |||
a3d40fdc2b | |||
c064ef7a30 | |||
762717da1e | |||
b7d3758bea | |||
d20541fd24 | |||
2c2f860f26 | |||
d1db3aa673 | |||
cedc52cdf5 | |||
33f8eafbcf | |||
ad45cf8c72 | |||
f99d035621 | |||
f3072caea8 |
@@ -6,7 +6,6 @@ namespace TweetDuck.Configuration{
|
|||||||
// public args
|
// public args
|
||||||
public const string ArgDataFolder = "-datafolder";
|
public const string ArgDataFolder = "-datafolder";
|
||||||
public const string ArgLogging = "-log";
|
public const string ArgLogging = "-log";
|
||||||
public const string ArgDebugUpdates = "-debugupdates";
|
|
||||||
|
|
||||||
// internal args
|
// internal args
|
||||||
public const string ArgRestart = "-restart";
|
public const string ArgRestart = "-restart";
|
||||||
|
@@ -39,6 +39,7 @@ namespace TweetDuck.Core{
|
|||||||
}
|
}
|
||||||
|
|
||||||
public string UpdateInstallerPath { get; private set; }
|
public string UpdateInstallerPath { get; private set; }
|
||||||
|
private bool ignoreUpdateCheckError;
|
||||||
|
|
||||||
public AnalyticsFile AnalyticsFile => analytics?.File ?? AnalyticsFile.Dummy;
|
public AnalyticsFile AnalyticsFile => analytics?.File ?? AnalyticsFile.Dummy;
|
||||||
|
|
||||||
@@ -80,6 +81,7 @@ namespace TweetDuck.Core{
|
|||||||
Config.TrayBehaviorChanged -= Config_TrayBehaviorChanged;
|
Config.TrayBehaviorChanged -= Config_TrayBehaviorChanged;
|
||||||
|
|
||||||
browser.Dispose();
|
browser.Dispose();
|
||||||
|
updates.Dispose();
|
||||||
contextMenu.Dispose();
|
contextMenu.Dispose();
|
||||||
|
|
||||||
notificationScreenshotManager?.Dispose();
|
notificationScreenshotManager?.Dispose();
|
||||||
@@ -96,6 +98,7 @@ namespace TweetDuck.Core{
|
|||||||
UpdateTrayIcon();
|
UpdateTrayIcon();
|
||||||
|
|
||||||
this.updates = new UpdateHandler(browser, updaterSettings);
|
this.updates = new UpdateHandler(browser, updaterSettings);
|
||||||
|
this.updates.CheckFinished += updates_CheckFinished;
|
||||||
this.updates.UpdateAccepted += updates_UpdateAccepted;
|
this.updates.UpdateAccepted += updates_UpdateAccepted;
|
||||||
this.updates.UpdateDismissed += updates_UpdateDismissed;
|
this.updates.UpdateDismissed += updates_UpdateDismissed;
|
||||||
|
|
||||||
@@ -233,6 +236,28 @@ namespace TweetDuck.Core{
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void updates_CheckFinished(object sender, UpdateCheckEventArgs e){
|
||||||
|
this.InvokeAsyncSafe(() => {
|
||||||
|
e.Result.Handle(update => {
|
||||||
|
if (!update.IsUpdateDismissed){
|
||||||
|
if (update.IsUpdateNew){
|
||||||
|
browser.ShowUpdateNotification(update.VersionTag, update.ReleaseNotes);
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
updates.StartTimer();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}, ex => {
|
||||||
|
if (!ignoreUpdateCheckError){
|
||||||
|
Program.Reporter.HandleException("Update Check Error", "An error occurred while checking for updates.", true, ex);
|
||||||
|
updates.StartTimer();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
ignoreUpdateCheckError = true;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
private void updates_UpdateAccepted(object sender, UpdateEventArgs e){
|
private void updates_UpdateAccepted(object sender, UpdateEventArgs e){
|
||||||
this.InvokeAsyncSafe(() => {
|
this.InvokeAsyncSafe(() => {
|
||||||
FormManager.CloseAllDialogs();
|
FormManager.CloseAllDialogs();
|
||||||
@@ -243,11 +268,19 @@ namespace TweetDuck.Core{
|
|||||||
}
|
}
|
||||||
|
|
||||||
updates.BeginUpdateDownload(this, e.UpdateInfo, update => {
|
updates.BeginUpdateDownload(this, e.UpdateInfo, update => {
|
||||||
if (update.DownloadStatus == UpdateDownloadStatus.Done){
|
UpdateDownloadStatus status = update.DownloadStatus;
|
||||||
UpdateInstallerPath = update.InstallerPath;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
if (status == UpdateDownloadStatus.Done){
|
||||||
|
UpdateInstallerPath = update.InstallerPath;
|
||||||
ForceClose();
|
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();
|
||||||
|
}
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -302,6 +335,7 @@ namespace TweetDuck.Core{
|
|||||||
Resources.ScriptLoader.HotSwap();
|
Resources.ScriptLoader.HotSwap();
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
ignoreUpdateCheckError = false;
|
||||||
browser.ReloadToTweetDeck();
|
browser.ReloadToTweetDeck();
|
||||||
AnalyticsFile.BrowserReloads.Trigger();
|
AnalyticsFile.BrowserReloads.Trigger();
|
||||||
}
|
}
|
||||||
|
@@ -24,17 +24,24 @@ namespace TweetDuck.Core.Notification.Screenshot{
|
|||||||
browser.RegisterAsyncJsObject("$TD_NotificationScreenshot", new ScreenshotBridge(this, SetScreenshotHeight, callback));
|
browser.RegisterAsyncJsObject("$TD_NotificationScreenshot", new ScreenshotBridge(this, SetScreenshotHeight, callback));
|
||||||
|
|
||||||
browser.LoadingStateChanged += (sender, args) => {
|
browser.LoadingStateChanged += (sender, args) => {
|
||||||
if (!args.IsLoading){
|
if (args.IsLoading){
|
||||||
using(IFrame frame = args.Browser.MainFrame){
|
return;
|
||||||
if (!ScriptLoader.ExecuteFile(frame, "screenshot.js")){
|
}
|
||||||
|
|
||||||
|
string script = ScriptLoader.LoadResource("screenshot.js", true);
|
||||||
|
|
||||||
|
if (script == null){
|
||||||
this.InvokeAsyncSafe(callback);
|
this.InvokeAsyncSafe(callback);
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
using(IFrame frame = args.Browser.MainFrame){
|
||||||
|
ScriptLoader.ExecuteScript(frame, script.Replace("{width}", ClientSize.Width.ToString()), "screenshot");
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
LoadTweet(new TweetNotification(string.Empty, string.Empty, string.Empty, html, 0, string.Empty, string.Empty));
|
|
||||||
SetScreenshotHeight(1);
|
SetScreenshotHeight(1);
|
||||||
|
LoadTweet(new TweetNotification(string.Empty, string.Empty, string.Empty, html, 0, string.Empty, string.Empty));
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override string GetTweetHTML(TweetNotification tweet){
|
protected override string GetTweetHTML(TweetNotification tweet){
|
||||||
|
@@ -42,7 +42,9 @@
|
|||||||
//
|
//
|
||||||
// textBoxBrowserCSS
|
// textBoxBrowserCSS
|
||||||
//
|
//
|
||||||
this.textBoxBrowserCSS.Dock = System.Windows.Forms.DockStyle.Bottom;
|
this.textBoxBrowserCSS.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom)
|
||||||
|
| System.Windows.Forms.AnchorStyles.Left)
|
||||||
|
| System.Windows.Forms.AnchorStyles.Right)));
|
||||||
this.textBoxBrowserCSS.Font = new System.Drawing.Font("Courier New", 8.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(238)));
|
this.textBoxBrowserCSS.Font = new System.Drawing.Font("Courier New", 8.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(238)));
|
||||||
this.textBoxBrowserCSS.Location = new System.Drawing.Point(0, 16);
|
this.textBoxBrowserCSS.Location = new System.Drawing.Point(0, 16);
|
||||||
this.textBoxBrowserCSS.Margin = new System.Windows.Forms.Padding(0, 3, 0, 0);
|
this.textBoxBrowserCSS.Margin = new System.Windows.Forms.Padding(0, 3, 0, 0);
|
||||||
@@ -124,7 +126,9 @@
|
|||||||
//
|
//
|
||||||
// textBoxNotificationCSS
|
// textBoxNotificationCSS
|
||||||
//
|
//
|
||||||
this.textBoxNotificationCSS.Dock = System.Windows.Forms.DockStyle.Bottom;
|
this.textBoxNotificationCSS.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom)
|
||||||
|
| System.Windows.Forms.AnchorStyles.Left)
|
||||||
|
| System.Windows.Forms.AnchorStyles.Right)));
|
||||||
this.textBoxNotificationCSS.Font = new System.Drawing.Font("Courier New", 8.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(238)));
|
this.textBoxNotificationCSS.Font = new System.Drawing.Font("Courier New", 8.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(238)));
|
||||||
this.textBoxNotificationCSS.Location = new System.Drawing.Point(0, 16);
|
this.textBoxNotificationCSS.Location = new System.Drawing.Point(0, 16);
|
||||||
this.textBoxNotificationCSS.Margin = new System.Windows.Forms.Padding(0, 3, 0, 0);
|
this.textBoxNotificationCSS.Margin = new System.Windows.Forms.Padding(0, 3, 0, 0);
|
||||||
|
@@ -28,21 +28,22 @@
|
|||||||
this.btnRestart = new System.Windows.Forms.Button();
|
this.btnRestart = new System.Windows.Forms.Button();
|
||||||
this.cbLogging = new System.Windows.Forms.CheckBox();
|
this.cbLogging = new System.Windows.Forms.CheckBox();
|
||||||
this.toolTip = new System.Windows.Forms.ToolTip(this.components);
|
this.toolTip = new System.Windows.Forms.ToolTip(this.components);
|
||||||
this.cbDebugUpdates = new System.Windows.Forms.CheckBox();
|
|
||||||
this.tbDataFolder = new System.Windows.Forms.TextBox();
|
this.tbDataFolder = new System.Windows.Forms.TextBox();
|
||||||
this.tbShortcutTarget = new System.Windows.Forms.TextBox();
|
this.tbShortcutTarget = new System.Windows.Forms.TextBox();
|
||||||
this.labelDataFolder = new System.Windows.Forms.Label();
|
this.labelDataFolder = new System.Windows.Forms.Label();
|
||||||
this.labelShortcutTarget = new System.Windows.Forms.Label();
|
this.labelShortcutTarget = new System.Windows.Forms.Label();
|
||||||
|
this.flowPanel = new System.Windows.Forms.FlowLayoutPanel();
|
||||||
|
this.flowPanel.SuspendLayout();
|
||||||
this.SuspendLayout();
|
this.SuspendLayout();
|
||||||
//
|
//
|
||||||
// btnCancel
|
// btnCancel
|
||||||
//
|
//
|
||||||
this.btnCancel.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right)));
|
this.btnCancel.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right)));
|
||||||
this.btnCancel.Location = new System.Drawing.Point(215, 163);
|
this.btnCancel.Location = new System.Drawing.Point(215, 139);
|
||||||
this.btnCancel.Name = "btnCancel";
|
this.btnCancel.Name = "btnCancel";
|
||||||
this.btnCancel.Padding = new System.Windows.Forms.Padding(3, 0, 3, 0);
|
this.btnCancel.Padding = new System.Windows.Forms.Padding(3, 0, 3, 0);
|
||||||
this.btnCancel.Size = new System.Drawing.Size(56, 23);
|
this.btnCancel.Size = new System.Drawing.Size(56, 23);
|
||||||
this.btnCancel.TabIndex = 9;
|
this.btnCancel.TabIndex = 2;
|
||||||
this.btnCancel.Text = "Cancel";
|
this.btnCancel.Text = "Cancel";
|
||||||
this.btnCancel.UseVisualStyleBackColor = true;
|
this.btnCancel.UseVisualStyleBackColor = true;
|
||||||
this.btnCancel.Click += new System.EventHandler(this.btnCancel_Click);
|
this.btnCancel.Click += new System.EventHandler(this.btnCancel_Click);
|
||||||
@@ -50,11 +51,11 @@
|
|||||||
// btnRestart
|
// btnRestart
|
||||||
//
|
//
|
||||||
this.btnRestart.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right)));
|
this.btnRestart.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right)));
|
||||||
this.btnRestart.Location = new System.Drawing.Point(152, 163);
|
this.btnRestart.Location = new System.Drawing.Point(152, 139);
|
||||||
this.btnRestart.Name = "btnRestart";
|
this.btnRestart.Name = "btnRestart";
|
||||||
this.btnRestart.Padding = new System.Windows.Forms.Padding(3, 0, 3, 0);
|
this.btnRestart.Padding = new System.Windows.Forms.Padding(3, 0, 3, 0);
|
||||||
this.btnRestart.Size = new System.Drawing.Size(57, 23);
|
this.btnRestart.Size = new System.Drawing.Size(57, 23);
|
||||||
this.btnRestart.TabIndex = 8;
|
this.btnRestart.TabIndex = 1;
|
||||||
this.btnRestart.Text = "Restart";
|
this.btnRestart.Text = "Restart";
|
||||||
this.btnRestart.UseVisualStyleBackColor = true;
|
this.btnRestart.UseVisualStyleBackColor = true;
|
||||||
this.btnRestart.Click += new System.EventHandler(this.btnRestart_Click);
|
this.btnRestart.Click += new System.EventHandler(this.btnRestart_Click);
|
||||||
@@ -62,7 +63,7 @@
|
|||||||
// cbLogging
|
// cbLogging
|
||||||
//
|
//
|
||||||
this.cbLogging.AutoSize = true;
|
this.cbLogging.AutoSize = true;
|
||||||
this.cbLogging.Location = new System.Drawing.Point(12, 12);
|
this.cbLogging.Location = new System.Drawing.Point(3, 3);
|
||||||
this.cbLogging.Name = "cbLogging";
|
this.cbLogging.Name = "cbLogging";
|
||||||
this.cbLogging.Size = new System.Drawing.Size(64, 17);
|
this.cbLogging.Size = new System.Drawing.Size(64, 17);
|
||||||
this.cbLogging.TabIndex = 0;
|
this.cbLogging.TabIndex = 0;
|
||||||
@@ -70,25 +71,12 @@
|
|||||||
this.toolTip.SetToolTip(this.cbLogging, "Logging JavaScript output into TD_Console.txt file in the data folder.");
|
this.toolTip.SetToolTip(this.cbLogging, "Logging JavaScript output into TD_Console.txt file in the data folder.");
|
||||||
this.cbLogging.UseVisualStyleBackColor = true;
|
this.cbLogging.UseVisualStyleBackColor = true;
|
||||||
//
|
//
|
||||||
// cbDebugUpdates
|
|
||||||
//
|
|
||||||
this.cbDebugUpdates.AutoSize = true;
|
|
||||||
this.cbDebugUpdates.Location = new System.Drawing.Point(12, 35);
|
|
||||||
this.cbDebugUpdates.Name = "cbDebugUpdates";
|
|
||||||
this.cbDebugUpdates.Size = new System.Drawing.Size(127, 17);
|
|
||||||
this.cbDebugUpdates.TabIndex = 1;
|
|
||||||
this.cbDebugUpdates.Text = "Pre-Release Updates";
|
|
||||||
this.toolTip.SetToolTip(this.cbDebugUpdates, "Allows updating to pre-releases.");
|
|
||||||
this.cbDebugUpdates.UseVisualStyleBackColor = true;
|
|
||||||
//
|
|
||||||
// tbDataFolder
|
// tbDataFolder
|
||||||
//
|
//
|
||||||
this.tbDataFolder.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left)
|
this.tbDataFolder.Location = new System.Drawing.Point(3, 51);
|
||||||
| System.Windows.Forms.AnchorStyles.Right)));
|
|
||||||
this.tbDataFolder.Location = new System.Drawing.Point(15, 83);
|
|
||||||
this.tbDataFolder.Name = "tbDataFolder";
|
this.tbDataFolder.Name = "tbDataFolder";
|
||||||
this.tbDataFolder.Size = new System.Drawing.Size(257, 20);
|
this.tbDataFolder.Size = new System.Drawing.Size(260, 20);
|
||||||
this.tbDataFolder.TabIndex = 5;
|
this.tbDataFolder.TabIndex = 2;
|
||||||
this.toolTip.SetToolTip(this.tbDataFolder, "Path to the data folder. Must be either an absolute path,\r\nor a simple folder nam" +
|
this.toolTip.SetToolTip(this.tbDataFolder, "Path to the data folder. Must be either an absolute path,\r\nor a simple folder nam" +
|
||||||
"e that will be created in LocalAppData.");
|
"e that will be created in LocalAppData.");
|
||||||
//
|
//
|
||||||
@@ -97,44 +85,57 @@
|
|||||||
this.tbShortcutTarget.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left)
|
this.tbShortcutTarget.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left)
|
||||||
| System.Windows.Forms.AnchorStyles.Right)));
|
| System.Windows.Forms.AnchorStyles.Right)));
|
||||||
this.tbShortcutTarget.Cursor = System.Windows.Forms.Cursors.Hand;
|
this.tbShortcutTarget.Cursor = System.Windows.Forms.Cursors.Hand;
|
||||||
this.tbShortcutTarget.Location = new System.Drawing.Point(15, 134);
|
this.tbShortcutTarget.Location = new System.Drawing.Point(3, 102);
|
||||||
this.tbShortcutTarget.Name = "tbShortcutTarget";
|
this.tbShortcutTarget.Name = "tbShortcutTarget";
|
||||||
this.tbShortcutTarget.ReadOnly = true;
|
this.tbShortcutTarget.ReadOnly = true;
|
||||||
this.tbShortcutTarget.Size = new System.Drawing.Size(257, 20);
|
this.tbShortcutTarget.Size = new System.Drawing.Size(260, 20);
|
||||||
this.tbShortcutTarget.TabIndex = 7;
|
this.tbShortcutTarget.TabIndex = 4;
|
||||||
this.tbShortcutTarget.Click += new System.EventHandler(this.tbShortcutTarget_Click);
|
this.tbShortcutTarget.Click += new System.EventHandler(this.tbShortcutTarget_Click);
|
||||||
//
|
//
|
||||||
// labelDataFolder
|
// labelDataFolder
|
||||||
//
|
//
|
||||||
this.labelDataFolder.AutoSize = true;
|
this.labelDataFolder.AutoSize = true;
|
||||||
this.labelDataFolder.Location = new System.Drawing.Point(12, 67);
|
this.labelDataFolder.Location = new System.Drawing.Point(3, 35);
|
||||||
this.labelDataFolder.Margin = new System.Windows.Forms.Padding(3, 12, 3, 0);
|
this.labelDataFolder.Margin = new System.Windows.Forms.Padding(3, 12, 3, 0);
|
||||||
this.labelDataFolder.Name = "labelDataFolder";
|
this.labelDataFolder.Name = "labelDataFolder";
|
||||||
this.labelDataFolder.Size = new System.Drawing.Size(62, 13);
|
this.labelDataFolder.Size = new System.Drawing.Size(62, 13);
|
||||||
this.labelDataFolder.TabIndex = 4;
|
this.labelDataFolder.TabIndex = 1;
|
||||||
this.labelDataFolder.Text = "Data Folder";
|
this.labelDataFolder.Text = "Data Folder";
|
||||||
//
|
//
|
||||||
// labelShortcutTarget
|
// labelShortcutTarget
|
||||||
//
|
//
|
||||||
this.labelShortcutTarget.AutoSize = true;
|
this.labelShortcutTarget.AutoSize = true;
|
||||||
this.labelShortcutTarget.Location = new System.Drawing.Point(12, 118);
|
this.labelShortcutTarget.Location = new System.Drawing.Point(3, 86);
|
||||||
this.labelShortcutTarget.Margin = new System.Windows.Forms.Padding(3, 12, 3, 0);
|
this.labelShortcutTarget.Margin = new System.Windows.Forms.Padding(3, 12, 3, 0);
|
||||||
this.labelShortcutTarget.Name = "labelShortcutTarget";
|
this.labelShortcutTarget.Name = "labelShortcutTarget";
|
||||||
this.labelShortcutTarget.Size = new System.Drawing.Size(155, 13);
|
this.labelShortcutTarget.Size = new System.Drawing.Size(155, 13);
|
||||||
this.labelShortcutTarget.TabIndex = 6;
|
this.labelShortcutTarget.TabIndex = 3;
|
||||||
this.labelShortcutTarget.Text = "Shortcut Target (click to select)";
|
this.labelShortcutTarget.Text = "Shortcut Target (click to select)";
|
||||||
//
|
//
|
||||||
|
// flowPanel
|
||||||
|
//
|
||||||
|
this.flowPanel.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom)
|
||||||
|
| System.Windows.Forms.AnchorStyles.Left)
|
||||||
|
| System.Windows.Forms.AnchorStyles.Right)));
|
||||||
|
this.flowPanel.Controls.Add(this.cbLogging);
|
||||||
|
this.flowPanel.Controls.Add(this.labelDataFolder);
|
||||||
|
this.flowPanel.Controls.Add(this.tbDataFolder);
|
||||||
|
this.flowPanel.Controls.Add(this.labelShortcutTarget);
|
||||||
|
this.flowPanel.Controls.Add(this.tbShortcutTarget);
|
||||||
|
this.flowPanel.FlowDirection = System.Windows.Forms.FlowDirection.TopDown;
|
||||||
|
this.flowPanel.Location = new System.Drawing.Point(9, 9);
|
||||||
|
this.flowPanel.Margin = new System.Windows.Forms.Padding(0);
|
||||||
|
this.flowPanel.Name = "flowPanel";
|
||||||
|
this.flowPanel.Size = new System.Drawing.Size(266, 127);
|
||||||
|
this.flowPanel.TabIndex = 0;
|
||||||
|
this.flowPanel.WrapContents = false;
|
||||||
|
//
|
||||||
// DialogSettingsRestart
|
// DialogSettingsRestart
|
||||||
//
|
//
|
||||||
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
|
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
|
||||||
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
|
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
|
||||||
this.ClientSize = new System.Drawing.Size(284, 198);
|
this.ClientSize = new System.Drawing.Size(284, 174);
|
||||||
this.Controls.Add(this.tbShortcutTarget);
|
this.Controls.Add(this.flowPanel);
|
||||||
this.Controls.Add(this.labelShortcutTarget);
|
|
||||||
this.Controls.Add(this.tbDataFolder);
|
|
||||||
this.Controls.Add(this.labelDataFolder);
|
|
||||||
this.Controls.Add(this.cbDebugUpdates);
|
|
||||||
this.Controls.Add(this.cbLogging);
|
|
||||||
this.Controls.Add(this.btnRestart);
|
this.Controls.Add(this.btnRestart);
|
||||||
this.Controls.Add(this.btnCancel);
|
this.Controls.Add(this.btnCancel);
|
||||||
this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedSingle;
|
this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedSingle;
|
||||||
@@ -143,8 +144,9 @@
|
|||||||
this.Name = "DialogSettingsRestart";
|
this.Name = "DialogSettingsRestart";
|
||||||
this.ShowIcon = false;
|
this.ShowIcon = false;
|
||||||
this.StartPosition = System.Windows.Forms.FormStartPosition.CenterParent;
|
this.StartPosition = System.Windows.Forms.FormStartPosition.CenterParent;
|
||||||
|
this.flowPanel.ResumeLayout(false);
|
||||||
|
this.flowPanel.PerformLayout();
|
||||||
this.ResumeLayout(false);
|
this.ResumeLayout(false);
|
||||||
this.PerformLayout();
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -154,10 +156,10 @@
|
|||||||
private System.Windows.Forms.Button btnRestart;
|
private System.Windows.Forms.Button btnRestart;
|
||||||
private System.Windows.Forms.CheckBox cbLogging;
|
private System.Windows.Forms.CheckBox cbLogging;
|
||||||
private System.Windows.Forms.ToolTip toolTip;
|
private System.Windows.Forms.ToolTip toolTip;
|
||||||
private System.Windows.Forms.CheckBox cbDebugUpdates;
|
|
||||||
private System.Windows.Forms.Label labelDataFolder;
|
private System.Windows.Forms.Label labelDataFolder;
|
||||||
private System.Windows.Forms.TextBox tbDataFolder;
|
private System.Windows.Forms.TextBox tbDataFolder;
|
||||||
private System.Windows.Forms.TextBox tbShortcutTarget;
|
private System.Windows.Forms.TextBox tbShortcutTarget;
|
||||||
private System.Windows.Forms.Label labelShortcutTarget;
|
private System.Windows.Forms.Label labelShortcutTarget;
|
||||||
|
private System.Windows.Forms.FlowLayoutPanel flowPanel;
|
||||||
}
|
}
|
||||||
}
|
}
|
@@ -11,10 +11,7 @@ namespace TweetDuck.Core.Other.Settings.Dialogs{
|
|||||||
InitializeComponent();
|
InitializeComponent();
|
||||||
|
|
||||||
cbLogging.Checked = currentArgs.HasFlag(Arguments.ArgLogging);
|
cbLogging.Checked = currentArgs.HasFlag(Arguments.ArgLogging);
|
||||||
cbDebugUpdates.Checked = currentArgs.HasFlag(Arguments.ArgDebugUpdates);
|
|
||||||
|
|
||||||
cbLogging.CheckedChanged += control_Change;
|
cbLogging.CheckedChanged += control_Change;
|
||||||
cbDebugUpdates.CheckedChanged += control_Change;
|
|
||||||
|
|
||||||
if (Program.IsPortable){
|
if (Program.IsPortable){
|
||||||
tbDataFolder.Text = "Not available in portable version";
|
tbDataFolder.Text = "Not available in portable version";
|
||||||
@@ -37,10 +34,6 @@ namespace TweetDuck.Core.Other.Settings.Dialogs{
|
|||||||
Args.AddFlag(Arguments.ArgLogging);
|
Args.AddFlag(Arguments.ArgLogging);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (cbDebugUpdates.Checked){
|
|
||||||
Args.AddFlag(Arguments.ArgDebugUpdates);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!string.IsNullOrWhiteSpace(tbDataFolder.Text) && tbDataFolder.Enabled){
|
if (!string.IsNullOrWhiteSpace(tbDataFolder.Text) && tbDataFolder.Enabled){
|
||||||
Args.SetValue(Arguments.ArgDataFolder, tbDataFolder.Text);
|
Args.SetValue(Arguments.ArgDataFolder, tbDataFolder.Text);
|
||||||
}
|
}
|
||||||
|
@@ -222,9 +222,13 @@ namespace TweetDuck.Core.Other.Settings{
|
|||||||
if (e.EventId == updateCheckEventId){
|
if (e.EventId == updateCheckEventId){
|
||||||
btnCheckUpdates.Enabled = true;
|
btnCheckUpdates.Enabled = true;
|
||||||
|
|
||||||
if (!e.IsUpdateAvailable){
|
e.Result.Handle(update => {
|
||||||
|
if (!update.IsUpdateNew){
|
||||||
FormMessage.Information("No Updates Available", "Your version of TweetDuck is up to date.", FormMessage.OK);
|
FormMessage.Information("No Updates Available", "Your version of TweetDuck is up to date.", FormMessage.OK);
|
||||||
}
|
}
|
||||||
|
}, ex => {
|
||||||
|
Program.Reporter.HandleException("Update Check Error", "An error occurred while checking for updates.", true, ex);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@@ -1,5 +1,6 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Drawing;
|
using System.Drawing;
|
||||||
|
using System.Text;
|
||||||
using System.Windows.Forms;
|
using System.Windows.Forms;
|
||||||
using CefSharp;
|
using CefSharp;
|
||||||
using CefSharp.WinForms;
|
using CefSharp.WinForms;
|
||||||
@@ -145,6 +146,8 @@ namespace TweetDuck.Core{
|
|||||||
UpdateProperties();
|
UpdateProperties();
|
||||||
TweetDeckBridge.RestoreSessionData(frame);
|
TweetDeckBridge.RestoreSessionData(frame);
|
||||||
ScriptLoader.ExecuteFile(frame, "code.js", browser);
|
ScriptLoader.ExecuteFile(frame, "code.js", browser);
|
||||||
|
ScriptLoader.ExecuteFile(frame, "update.js", browser);
|
||||||
|
|
||||||
InjectBrowserCSS();
|
InjectBrowserCSS();
|
||||||
ReinjectCustomCSS(Program.UserConfig.CustomBrowserCSS);
|
ReinjectCustomCSS(Program.UserConfig.CustomBrowserCSS);
|
||||||
UserConfig_SoundNotificationInfoChanged(null, EventArgs.Empty);
|
UserConfig_SoundNotificationInfoChanged(null, EventArgs.Empty);
|
||||||
@@ -246,5 +249,9 @@ namespace TweetDuck.Core{
|
|||||||
public void ApplyROT13(){
|
public void ApplyROT13(){
|
||||||
browser.ExecuteScriptAsync("TDGF_applyROT13()");
|
browser.ExecuteScriptAsync("TDGF_applyROT13()");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void ShowUpdateNotification(string versionTag, string releaseNotes){
|
||||||
|
browser.ExecuteScriptAsync("TDUF_displayNotification", versionTag, Convert.ToBase64String(Encoding.GetEncoding("iso-8859-1").GetBytes(releaseNotes)));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
36
Data/Result.cs
Normal file
36
Data/Result.cs
Normal file
@@ -0,0 +1,36 @@
|
|||||||
|
using System;
|
||||||
|
|
||||||
|
namespace TweetDuck.Data{
|
||||||
|
sealed class Result<T>{
|
||||||
|
public bool HasValue => exception == null;
|
||||||
|
|
||||||
|
public T Value => HasValue ? value : throw new InvalidOperationException("Requested value from a failed result.");
|
||||||
|
public Exception Exception => exception ?? throw new InvalidOperationException("Requested exception from a successful result.");
|
||||||
|
|
||||||
|
private readonly T value;
|
||||||
|
private readonly Exception exception;
|
||||||
|
|
||||||
|
public Result(T value){
|
||||||
|
this.value = value;
|
||||||
|
this.exception = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Result(Exception exception){
|
||||||
|
this.value = default(T);
|
||||||
|
this.exception = exception ?? throw new ArgumentNullException(nameof(exception));
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Handle(Action<T> onSuccess, Action<Exception> onException){
|
||||||
|
if (HasValue){
|
||||||
|
onSuccess(value);
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
onException(exception);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public Result<R> Select<R>(Func<T, R> map){
|
||||||
|
return HasValue ? new Result<R>(map(value)) : new Result<R>(exception);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@@ -20,7 +20,7 @@ namespace TweetDuck{
|
|||||||
public const string BrandName = "TweetDuck";
|
public const string BrandName = "TweetDuck";
|
||||||
public const string Website = "https://tweetduck.chylex.com";
|
public const string Website = "https://tweetduck.chylex.com";
|
||||||
|
|
||||||
public const string VersionTag = "1.13.3";
|
public const string VersionTag = "1.13.4";
|
||||||
|
|
||||||
public static readonly bool IsPortable = File.Exists("makeportable");
|
public static readonly bool IsPortable = File.Exists("makeportable");
|
||||||
|
|
||||||
|
@@ -9,7 +9,7 @@ Clear columns
|
|||||||
chylex
|
chylex
|
||||||
|
|
||||||
[version]
|
[version]
|
||||||
1.1.1
|
1.2
|
||||||
|
|
||||||
[website]
|
[website]
|
||||||
https://tweetduck.chylex.com
|
https://tweetduck.chylex.com
|
||||||
|
@@ -7,12 +7,17 @@ constructor(){
|
|||||||
enabled(){
|
enabled(){
|
||||||
// prepare variables and functions
|
// prepare variables and functions
|
||||||
var clearColumn = (columnName) => {
|
var clearColumn = (columnName) => {
|
||||||
TD.controller.columnManager.get(columnName).clear();
|
let col = TD.controller.columnManager.get(columnName);
|
||||||
|
return if !col.isClearable();
|
||||||
|
|
||||||
|
col.clear();
|
||||||
TD.controller.stats.columnActionClick("clear");
|
TD.controller.stats.columnActionClick("clear");
|
||||||
};
|
};
|
||||||
|
|
||||||
var resetColumn = (columnName) => {
|
var resetColumn = (columnName) => {
|
||||||
var col = TD.controller.columnManager.get(columnName);
|
let col = TD.controller.columnManager.get(columnName);
|
||||||
|
return if !col.isClearable();
|
||||||
|
|
||||||
col.model.setClearedTimestamp(0);
|
col.model.setClearedTimestamp(0);
|
||||||
col.reloadTweets();
|
col.reloadTweets();
|
||||||
};
|
};
|
||||||
@@ -38,7 +43,7 @@ enabled(){
|
|||||||
$(document).off("mousemove", this.eventKeyUp);
|
$(document).off("mousemove", this.eventKeyUp);
|
||||||
}
|
}
|
||||||
|
|
||||||
$("#clear-columns-btn-all").text(pressed ? "Restore columns" : "Clear columns");
|
$("#clear-columns-btn-all-1,#clear-columns-btn-all-2").text(pressed ? "Restore columns" : "Clear columns");
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -81,7 +86,7 @@ enabled(){
|
|||||||
// add column buttons and keyboard shortcut info to UI
|
// add column buttons and keyboard shortcut info to UI
|
||||||
replaceMustache("column/column_header.mustache", "</header>", [
|
replaceMustache("column/column_header.mustache", "</header>", [
|
||||||
'{{^isTemporary}}',
|
'{{^isTemporary}}',
|
||||||
'<a class="column-header-link" href="#" data-action="td-clearcolumns-dosingle" style="right:34px">',
|
'<a class="column-header-link td-clear-column-shortcut" href="#" data-action="td-clearcolumns-dosingle" style="right:34px">',
|
||||||
'<i class="icon icon-clear-timeline js-show-tip" data-placement="bottom" data-original-title="Clear column (hold Shift to restore)"></i>',
|
'<i class="icon icon-clear-timeline js-show-tip" data-placement="bottom" data-original-title="Clear column (hold Shift to restore)"></i>',
|
||||||
'</a>',
|
'</a>',
|
||||||
'{{/isTemporary}}',
|
'{{/isTemporary}}',
|
||||||
@@ -98,11 +103,15 @@ enabled(){
|
|||||||
|
|
||||||
// load custom style
|
// load custom style
|
||||||
var css = window.TDPF_createCustomStyle(this);
|
var css = window.TDPF_createCustomStyle(this);
|
||||||
|
css.insert(".js-app-add-column.is-hidden + #clear-columns-btn-all-parent-1 { display: none; }");
|
||||||
|
css.insert(".column-navigator-overflow #clear-columns-btn-all-parent-2 { display: none; }");
|
||||||
css.insert(".column-title { margin-right: 60px !important; }");
|
css.insert(".column-title { margin-right: 60px !important; }");
|
||||||
css.insert(".column-type-message .column-title { margin-right: 115px !important; }");
|
|
||||||
css.insert(".mark-all-read-link { right: 59px !important; }");
|
css.insert(".mark-all-read-link { right: 59px !important; }");
|
||||||
css.insert(".open-compose-dm-link { right: 90px !important; }");
|
css.insert(".open-compose-dm-link { right: 90px !important; }");
|
||||||
css.insert("button[data-action='clear'].btn-options-tray { display: none !important; }");
|
css.insert("button[data-action='clear'].btn-options-tray { display: none !important; }");
|
||||||
|
css.insert("[data-td-icon='icon-message'] .column-title { margin-right: 115px !important; }");
|
||||||
|
css.insert("[data-td-icon='icon-schedule'] .td-clear-column-shortcut { display: none; }");
|
||||||
|
css.insert("[data-td-icon='icon-custom-timeline'] .td-clear-column-shortcut { display: none; }");
|
||||||
}
|
}
|
||||||
|
|
||||||
ready(){
|
ready(){
|
||||||
@@ -113,18 +122,22 @@ ready(){
|
|||||||
$(document).on("keyup", this.eventKeyUp);
|
$(document).on("keyup", this.eventKeyUp);
|
||||||
|
|
||||||
// add clear all button
|
// add clear all button
|
||||||
$("nav.app-navigator").first().append([
|
const generateButton = (idParent, idButton) => {
|
||||||
'<a id="clear-columns-btn-all-parent" class="js-header-action link-clean cf app-nav-link padding-h--10" data-title="Clear columns (hold Shift to restore)" data-action="td-clearcolumns-doall">',
|
return `
|
||||||
'<div class="obj-left margin-l--2"><i class="icon icon-medium icon-clear-timeline"></i></div>',
|
<a id="${idParent}" class="js-header-action link-clean cf app-nav-link padding-h--10" data-title="Clear columns (hold Shift to restore)" data-action="td-clearcolumns-doall">
|
||||||
'<div id="clear-columns-btn-all" class="nbfc padding-ts hide-condensed txt-size--16">Clear columns</div>',
|
<div class="obj-left margin-l--2"><i class="icon icon-medium icon-clear-timeline"></i></div>
|
||||||
'</a></nav>'
|
<div id="${idButton}" class="nbfc padding-ts hide-condensed txt-size--16 app-nav-link-text">Clear columns</div>
|
||||||
].join(""));
|
</a>`;
|
||||||
|
};
|
||||||
|
|
||||||
|
$(".js-app-add-column").first().after(generateButton("clear-columns-btn-all-parent-1", "clear-columns-btn-all-1"));
|
||||||
|
$(".js-column-nav-list").first().append(generateButton("clear-columns-btn-all-parent-2", "clear-columns-btn-all-2"));
|
||||||
|
|
||||||
// setup tooltip handling
|
// setup tooltip handling
|
||||||
var tooltipEvents = $._data($(".js-header-action")[0]).events;
|
var tooltipEvents = $._data($(".js-header-action")[0]).events;
|
||||||
|
|
||||||
if (tooltipEvents.mouseover && tooltipEvents.mouseover.length && tooltipEvents.mouseout && tooltipEvents.mouseout.length){
|
if (tooltipEvents.mouseover && tooltipEvents.mouseover.length && tooltipEvents.mouseout && tooltipEvents.mouseout.length){
|
||||||
$("#clear-columns-btn-all-parent").on("mouseover", tooltipEvents.mouseover[0].handler).on("mouseout", tooltipEvents.mouseout[0].handler);
|
$("#clear-columns-btn-all-parent-1,#clear-columns-btn-all-parent-2").on("mouseover", tooltipEvents.mouseover[0].handler).on("mouseout", tooltipEvents.mouseout[0].handler);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -92,63 +92,31 @@ html.dark .btn[disabled],html.dark .btn[disabled]:hover,html.dark .btn[disabled]
|
|||||||
html.dark .btn-on-dark:focus{box-shadow:0 0 0 1px #292F33,0 0 0 3px #71C9F8}
|
html.dark .btn-on-dark:focus{box-shadow:0 0 0 1px #292F33,0 0 0 3px #71C9F8}
|
||||||
html.dark .mdl-content .btn-on-dark:focus{box-shadow:0 0 0 1px #fff,0 0 0 3px #71C9F8}
|
html.dark .mdl-content .btn-on-dark:focus{box-shadow:0 0 0 1px #fff,0 0 0 3px #71C9F8}
|
||||||
html.dark .is-inverted-dark .btn:hover,html.dark .is-inverted-dark .btn:focus,html.dark .is-inverted-dark .btn:active,html.dark .is-inverted-dark .btn.is-selected{background-color:#F2F9FF}
|
html.dark .is-inverted-dark .btn:hover,html.dark .is-inverted-dark .btn:focus,html.dark .is-inverted-dark .btn:active,html.dark .is-inverted-dark .btn.is-selected{background-color:#F2F9FF}
|
||||||
html.dark .is-inverted-dark .btn-positive:hover,html.dark .is-inverted-dark .btn-positive-alt:hover,html.dark .is-inverted-dark .btn-fav.s-favorited:hover,html.dark .is-inverted-dark .s-following .follow-btn:hover,html.dark .s-following .is-inverted-dark .follow-btn:hover{background-color:#005FD1}
|
html.dark .is-inverted-dark .btn-fav.s-favorited:hover,html.dark .is-inverted-dark .s-following .follow-btn:hover,html.dark .s-following .is-inverted-dark .follow-btn:hover{background-color:#005FD1}
|
||||||
html.dark .is-inverted-dark .btn-positive:focus,html.dark .is-inverted-dark .btn-positive-alt:focus,html.dark .is-inverted-dark .btn-fav.s-favorited:focus,html.dark .is-inverted-dark .s-following .follow-btn:focus,html.dark .s-following .is-inverted-dark .follow-btn:focus{background-color:#005FD1}
|
html.dark .is-inverted-dark .btn-fav.s-favorited:focus,html.dark .is-inverted-dark .s-following .follow-btn:focus,html.dark .s-following .is-inverted-dark .follow-btn:focus{background-color:#005FD1}
|
||||||
html.dark .is-inverted-dark .btn-positive:active,html.dark .is-inverted-dark .btn-positive-alt:active,html.dark .is-inverted-dark .btn-fav.s-favorited:active,html.dark .is-inverted-dark .s-following .follow-btn:active,html.dark .s-following .is-inverted-dark .follow-btn:active,html.dark .is-inverted-dark .btn-positive.is-selected,html.dark .is-inverted-dark .is-selected.btn-positive-alt,html.dark .is-inverted-dark .is-selected.btn-fav.s-favorited,html.dark .is-inverted-dark .s-following .is-selected.follow-btn,html.dark .s-following .is-inverted-dark .is-selected.follow-btn{background-color:#005FD1}
|
html.dark .is-inverted-dark .btn-fav.s-favorited:active,html.dark .is-inverted-dark .s-following .follow-btn:active,html.dark .s-following .is-inverted-dark .follow-btn:active,html.dark .is-inverted-dark .is-selected.btn-fav.s-favorited,html.dark .is-inverted-dark .s-following .is-selected.follow-btn,html.dark .s-following .is-inverted-dark .is-selected.follow-btn{background-color:#005FD1}
|
||||||
html.dark .is-inverted-dark .btn-positive-alt:hover,html.dark .is-inverted-dark .btn-fav.s-favorited:hover,html.dark .is-inverted-dark .s-following .follow-btn:hover,html.dark .s-following .is-inverted-dark .follow-btn:hover{background-color:#A01744}
|
html.dark .is-inverted-dark .btn-fav.s-favorited:hover,html.dark .is-inverted-dark .s-following .follow-btn:hover,html.dark .s-following .is-inverted-dark .follow-btn:hover{background-color:#A01744}
|
||||||
html.dark .is-inverted-dark .btn-positive-alt:focus,html.dark .is-inverted-dark .btn-fav.s-favorited:focus,html.dark .is-inverted-dark .s-following .follow-btn:focus,html.dark .s-following .is-inverted-dark .follow-btn:focus{background-color:#A01744}
|
html.dark .is-inverted-dark .btn-fav.s-favorited:focus,html.dark .is-inverted-dark .s-following .follow-btn:focus,html.dark .s-following .is-inverted-dark .follow-btn:focus{background-color:#A01744}
|
||||||
html.dark .is-inverted-dark .btn-positive-alt:active,html.dark .is-inverted-dark .btn-fav.s-favorited:active,html.dark .is-inverted-dark .s-following .follow-btn:active,html.dark .s-following .is-inverted-dark .follow-btn:active,html.dark .is-inverted-dark .btn-positive-alt.is-selected,html.dark .is-inverted-dark .is-selected.btn-fav.s-favorited,html.dark .is-inverted-dark .s-following .is-selected.follow-btn,html.dark .s-following .is-inverted-dark .is-selected.follow-btn{background-color:#A01744}
|
html.dark .is-inverted-dark .btn-fav.s-favorited:active,html.dark .is-inverted-dark .s-following .follow-btn:active,html.dark .s-following .is-inverted-dark .follow-btn:active,html.dark .is-inverted-dark .is-selected.btn-fav.s-favorited,html.dark .is-inverted-dark .s-following .is-selected.follow-btn,html.dark .s-following .is-inverted-dark .is-selected.follow-btn{background-color:#A01744}
|
||||||
html.dark .is-inverted-dark .btn-negative:hover{background-color:#A01744}
|
html.dark .btn-fav.s-favorited,html.dark .s-following .follow-btn{color:#fff;background-color:#1DA1F2;border:1px solid #1DA1F2}
|
||||||
html.dark .is-inverted-dark .btn-negative:focus{background-color:#A01744}
|
html.dark .btn-fav.s-favorited:hover,html.dark .s-following .follow-btn:hover{color:#fff;background-color:#005FD1;border:1px solid #005FD1}
|
||||||
html.dark .is-inverted-dark .btn-negative:active,html.dark .is-inverted-dark .btn-negative.is-selected{background-color:#A01744}
|
html.dark .btn-fav.s-favorited:focus,html.dark .s-following .follow-btn:focus{color:#fff;background-color:#005FD1;border:1px solid #005FD1;box-shadow:0 0 0 1px #fff,0 0 0 3px #71C9F8}
|
||||||
html.dark .is-inverted-dark .btn-tertiary:hover{background-color:#F5F8FA}
|
html.dark .btn-fav.s-favorited:active,html.dark .s-following .follow-btn:active,html.dark .is-selected.btn-fav.s-favorited,html.dark .s-following .is-selected.follow-btn{color:#fff;background-color:#005FD1;border:1px solid #005FD1}
|
||||||
html.dark .is-inverted-dark .btn-tertiary:focus{background-color:#F5F8FA}
|
html.dark [disabled].btn-fav.s-favorited,html.dark .s-following [disabled].follow-btn,html.dark [disabled].btn-fav.s-favorited:hover,html.dark .s-following [disabled].follow-btn:hover,html.dark [disabled].btn-fav.s-favorited:active,html.dark .s-following [disabled].follow-btn:active,html.dark .is-disabled.btn-fav.s-favorited,html.dark .s-following .is-disabled.follow-btn,html.dark .is-disabled.btn-fav.s-favorited:hover,html.dark .s-following .is-disabled.follow-btn:hover,html.dark .is-disabled.btn-fav.s-favorited:focus,html.dark .s-following .is-disabled.follow-btn:focus,html.dark .is-disabled.btn-fav.s-favorited:active,html.dark .s-following .is-disabled.follow-btn:active{color:#fff;background-color:#1DA1F2;border:1px solid #1DA1F2}
|
||||||
html.dark .is-inverted-dark .btn-tertiary:active,html.dark .is-inverted-dark .btn-tertiary.is-selected{background-color:#F5F8FA}
|
html.dark .btn-fav.s-favorited:hover,html.dark .s-following .follow-btn:hover{color:#fff;background-color:#A01744;border:#A01744}
|
||||||
html.dark .btn-positive,html.dark .btn-positive-alt,html.dark .btn-fav.s-favorited,html.dark .s-following .follow-btn{color:#fff;background-color:#1DA1F2;border:1px solid #1DA1F2}
|
html.dark .btn-fav.s-favorited:active,html.dark .s-following .follow-btn:active,html.dark .is-selected.btn-fav.s-favorited,html.dark .s-following .is-selected.follow-btn{color:#fff;background-color:#A01744;border:#A01744}
|
||||||
html.dark .btn-positive:hover,html.dark .btn-positive-alt:hover,html.dark .btn-fav.s-favorited:hover,html.dark .s-following .follow-btn:hover{color:#fff;background-color:#005FD1;border:1px solid #005FD1}
|
|
||||||
html.dark .btn-positive:focus,html.dark .btn-positive-alt:focus,html.dark .btn-fav.s-favorited:focus,html.dark .s-following .follow-btn:focus{color:#fff;background-color:#005FD1;border:1px solid #005FD1;box-shadow:0 0 0 1px #fff,0 0 0 3px #71C9F8}
|
|
||||||
html.dark .btn-positive:active,html.dark .btn-positive-alt:active,html.dark .btn-fav.s-favorited:active,html.dark .s-following .follow-btn:active,html.dark .btn-positive.is-selected,html.dark .is-selected.btn-positive-alt,html.dark .is-selected.btn-fav.s-favorited,html.dark .s-following .is-selected.follow-btn{color:#fff;background-color:#005FD1;border:1px solid #005FD1}
|
|
||||||
html.dark .btn-positive[disabled],html.dark [disabled].btn-positive-alt,html.dark [disabled].btn-fav.s-favorited,html.dark .s-following [disabled].follow-btn,html.dark .btn-positive[disabled]:hover,html.dark [disabled].btn-positive-alt:hover,html.dark [disabled].btn-fav.s-favorited:hover,html.dark .s-following [disabled].follow-btn:hover,html.dark .btn-positive[disabled]:active,html.dark [disabled].btn-positive-alt:active,html.dark [disabled].btn-fav.s-favorited:active,html.dark .s-following [disabled].follow-btn:active,html.dark .btn-positive.is-disabled,html.dark .is-disabled.btn-positive-alt,html.dark .is-disabled.btn-fav.s-favorited,html.dark .s-following .is-disabled.follow-btn,html.dark .btn-positive.is-disabled:hover,html.dark .is-disabled.btn-positive-alt:hover,html.dark .is-disabled.btn-fav.s-favorited:hover,html.dark .s-following .is-disabled.follow-btn:hover,html.dark .btn-positive.is-disabled:focus,html.dark .is-disabled.btn-positive-alt:focus,html.dark .is-disabled.btn-fav.s-favorited:focus,html.dark .s-following .is-disabled.follow-btn:focus,html.dark .btn-positive.is-disabled:active,html.dark .is-disabled.btn-positive-alt:active,html.dark .is-disabled.btn-fav.s-favorited:active,html.dark .s-following .is-disabled.follow-btn:active{color:#fff;background-color:#1DA1F2;border:1px solid #1DA1F2}
|
|
||||||
html.dark .btn-compose{color:#fff;background-color:#2b7bb9}
|
|
||||||
html.dark .btn-compose:hover{color:#fff;background-color:#2b7bb9}
|
|
||||||
html.dark .btn-compose:focus{color:#fff;background-color:#2b7bb9}
|
|
||||||
html.dark .btn-compose:active,html.dark .btn-compose.is-selected{color:#fff;background-color:#2b7bb9}
|
|
||||||
html.dark .btn-positive-alt:hover,html.dark .btn-fav.s-favorited:hover,html.dark .s-following .follow-btn:hover{color:#fff;background-color:#A01744;border:#A01744}
|
|
||||||
html.dark .btn-positive-alt:active,html.dark .btn-fav.s-favorited:active,html.dark .s-following .follow-btn:active,html.dark .btn-positive-alt.is-selected,html.dark .is-selected.btn-fav.s-favorited,html.dark .s-following .is-selected.follow-btn{color:#fff;background-color:#A01744;border:#A01744}
|
|
||||||
html.dark .btn-negative{border-color:#E0245E;color:#fff;background-color:#E0245E}
|
|
||||||
html.dark .btn-negative:hover{color:#fff;background-color:#A01744;border-color:#A01744}
|
|
||||||
html.dark .btn-negative:focus{color:#fff;background-color:#A01744;border-color:#A01744;box-shadow:0 0 0 1px #fff,0 0 0 3px #F6809A}
|
|
||||||
html.dark .btn-negative:active,html.dark .btn-negative.is-selected{color:#fff;background-color:#A01744;border-color:#A01744}
|
|
||||||
html.dark .btn-negative[disabled],html.dark .btn-negative[disabled]:hover,html.dark .btn-negative[disabled]:active,html.dark .btn-negative.is-disabled,html.dark .btn-negative.is-disabled:hover,html.dark .btn-negative.is-disabled:focus,html.dark .btn-negative.is-disabled:active{border-color:#E0245E;color:#fff;background-color:#E0245E}
|
|
||||||
html.dark .btn-tertiary{border-color:#657786;color:#657786}
|
|
||||||
html.dark .btn-tertiary:hover{color:#657786;background-color:#F5F8FA;border-color:#657786}
|
|
||||||
html.dark .btn-tertiary:focus{color:#657786;background-color:#F5F8FA;border-color:#657786;box-shadow:0 0 0 1px #fff,0 0 0 3px #CCD6DD}
|
|
||||||
html.dark .btn-tertiary:active,html.dark .btn-tertiary.is-selected{color:#657786;background-color:#F5F8FA;border-color:#657786}
|
|
||||||
html.dark .btn-tertiary[disabled],html.dark .btn-tertiary[disabled]:hover,html.dark .btn-tertiary[disabled]:active,html.dark .btn-tertiary.is-disabled,html.dark .btn-tertiary.is-disabled:hover,html.dark .btn-tertiary.is-disabled:focus,html.dark .btn-tertiary.is-disabled:active{color:#AAB8C2;border-color:#e1e8ed;background-color:#eaeaea}
|
|
||||||
html.dark .btn-on-blue{color:#fff;background-color:#66757f}
|
html.dark .btn-on-blue{color:#fff;background-color:#66757f}
|
||||||
html.dark .btn-on-blue:hover{color:#fff;background-color:#66757f}
|
html.dark .btn-on-blue:hover{color:#fff;background-color:#66757f}
|
||||||
html.dark .btn-on-blue:focus{color:#fff;background-color:#66757f;box-shadow:0 0 2px 3px #50a5e6}
|
html.dark .btn-on-blue:focus{color:#fff;background-color:#66757f;box-shadow:0 0 2px 3px #50a5e6}
|
||||||
html.dark .btn-on-blue:active,html.dark .btn-on-blue.is-selected{color:#fff;background-color:#434c51}
|
html.dark .btn-on-blue:active,html.dark .btn-on-blue.is-selected{color:#fff;background-color:#434c51}
|
||||||
html.dark .btn-on-blue[disabled],html.dark .btn-on-blue[disabled]:hover,html.dark .btn-on-blue[disabled]:active,html.dark .btn-on-blue.is-disabled,html.dark .btn-on-blue.is-disabled:hover,html.dark .btn-on-blue.is-disabled:focus,html.dark .btn-on-blue.is-disabled:active{color:#fff;background-color:#66757f}
|
html.dark .btn-on-blue[disabled],html.dark .btn-on-blue[disabled]:hover,html.dark .btn-on-blue[disabled]:active,html.dark .btn-on-blue.is-disabled,html.dark .btn-on-blue.is-disabled:hover,html.dark .btn-on-blue.is-disabled:focus,html.dark .btn-on-blue.is-disabled:active{color:#fff;background-color:#66757f}
|
||||||
html.dark .btn-neutral-negative{color:#d29b9a}
|
|
||||||
html.dark .btn-neutral-negative:hover,html.dark .btn-neutral-negative:focus{color:#d29b9a}
|
|
||||||
html.dark .btn-neutral-negative[disabled],html.dark .btn-neutral-negative[disabled]:hover,html.dark .btn-neutral-negative[disabled]:active,html.dark .btn-neutral-negative.is-disabled,html.dark .btn-neutral-negative.is-disabled:hover,html.dark .btn-neutral-negative.is-disabled:focus,html.dark .btn-neutral-negative.is-disabled:active{color:#d29b9a}
|
|
||||||
html.dark .btn-neutral-positive{color:#8bd}
|
|
||||||
html.dark .btn-neutral-positive:hover,html.dark .btn-neutral-positive:focus{color:#8bd}
|
|
||||||
html.dark .btn-neutral-positive[disabled],html.dark .btn-neutral-positive[disabled]:hover,html.dark .btn-neutral-positive[disabled]:active,html.dark .btn-neutral-positive.is-disabled,html.dark .btn-neutral-positive.is-disabled:hover,html.dark .btn-neutral-positive.is-disabled:focus,html.dark .btn-neutral-positive.is-disabled:active{color:#8bd}
|
|
||||||
html.dark .btn-options-tray{color:#e1e8ed}
|
html.dark .btn-options-tray{color:#e1e8ed}
|
||||||
html.dark .btn-options-tray:hover,html.dark .btn-options-tray:focus{color:#8bd}
|
html.dark .btn-options-tray:hover,html.dark .btn-options-tray:focus{color:#8bd}
|
||||||
html.dark .btn-options-tray[disabled],html.dark .btn-options-tray[disabled]:hover,html.dark .btn-options-tray[disabled]:active,html.dark .btn-options-tray.is-disabled,html.dark .btn-options-tray.is-disabled:hover,html.dark .btn-options-tray.is-disabled:focus,html.dark .btn-options-tray.is-disabled:active{color:#8bd}
|
html.dark .btn-options-tray[disabled],html.dark .btn-options-tray[disabled]:hover,html.dark .btn-options-tray[disabled]:active,html.dark .btn-options-tray.is-disabled,html.dark .btn-options-tray.is-disabled:hover,html.dark .btn-options-tray.is-disabled:focus,html.dark .btn-options-tray.is-disabled:active{color:#8bd}
|
||||||
html.dark .btn-bg-positive{background-color:rgba(102,117,127,0.5)}
|
html.dark .btn-bg-positive{background-color:rgba(102,117,127,0.5)}
|
||||||
html.dark .btn-bg-positive:hover,html.dark .btn-bg-positive:focus{background-color:rgba(102,117,127,0.5)}
|
html.dark .btn-bg-positive:hover,html.dark .btn-bg-positive:focus{background-color:rgba(102,117,127,0.5)}
|
||||||
html.dark .btn-bg-positive[disabled],html.dark .btn-bg-positive[disabled]:hover,html.dark .btn-bg-positive[disabled]:active,html.dark .btn-bg-positive.is-disabled,html.dark .btn-bg-positive.is-disabled:hover,html.dark .btn-bg-positive.is-disabled:focus,html.dark .btn-bg-positive.is-disabled:active{background-color:rgba(102,117,127,0.5)}
|
html.dark .btn-bg-positive[disabled],html.dark .btn-bg-positive[disabled]:hover,html.dark .btn-bg-positive[disabled]:active,html.dark .btn-bg-positive.is-disabled,html.dark .btn-bg-positive.is-disabled:hover,html.dark .btn-bg-positive.is-disabled:focus,html.dark .btn-bg-positive.is-disabled:active{background-color:rgba(102,117,127,0.5)}
|
||||||
html.dark .btn-bg-negative{background-color:#5d5457}
|
|
||||||
html.dark .btn-bg-negative:hover,html.dark .btn-bg-negative:focus{background-color:#5d5457}
|
|
||||||
html.dark .btn-bg-negative[disabled],html.dark .btn-bg-negative[disabled]:hover,html.dark .btn-bg-negative[disabled]:active,html.dark .btn-bg-negative.is-disabled,html.dark .btn-bg-negative.is-disabled:hover,html.dark .btn-bg-negative.is-disabled:focus,html.dark .btn-bg-negative.is-disabled:active{background-color:#5d5457}
|
|
||||||
html.dark .btn-bg-white{background-color:#fff;color:#55acee}
|
|
||||||
html.dark .btn-bg-white:hover,html.dark .btn-bg-white:focus{background-color:#fff;color:#55acee}
|
|
||||||
html.dark .follow-btn .icon,html.dark .follow-btn .Icon{color:#1DA1F2}
|
html.dark .follow-btn .icon,html.dark .follow-btn .Icon{color:#1DA1F2}
|
||||||
html.dark .input-group-button{border:1px solid #e1e8ed}
|
|
||||||
html.dark .account-profile-header{background-color:#1DA1F2}
|
html.dark .account-profile-header{background-color:#1DA1F2}
|
||||||
html.dark .account-settings-bt{border-top:1px solid #e1e8ed}
|
html.dark .account-settings-bt{border-top:1px solid #e1e8ed}
|
||||||
html.dark .account-settings-bb{border-bottom:1px solid #e1e8ed}
|
html.dark .account-settings-bb{border-bottom:1px solid #e1e8ed}
|
||||||
@@ -440,12 +408,6 @@ html.dark .char-count:disabled{color:#777}
|
|||||||
html.dark .over-char-count:disabled{color:#be1931}
|
html.dark .over-char-count:disabled{color:#be1931}
|
||||||
html.dark .cmp-replyto{background-color:#eaeaea;border-top:1px solid #ddd}
|
html.dark .cmp-replyto{background-color:#eaeaea;border-top:1px solid #ddd}
|
||||||
html.dark .s-link-added.s-photo-added p:last-child{border-top:1px solid #ddd}
|
html.dark .s-link-added.s-photo-added p:last-child{border-top:1px solid #ddd}
|
||||||
html.dark .accs li{background:#eaeaea;border:1px solid #e1e8ed}
|
|
||||||
html.dark .accs li:hover{background:#e1e8ed}
|
|
||||||
html.dark .accs .icon,html.dark .accs .Icon{color:#999}
|
|
||||||
html.dark .accs .acc-selected{background-color:#55acee;border:1px solid #e1e8ed}
|
|
||||||
html.dark .accs .acc-selected i{color:#fff}
|
|
||||||
html.dark .accs .acc-selected:hover{border-color:#e1e8ed;background-color:#50a5e6}
|
|
||||||
html.dark .inline-reply{background-color:#485865;color:#fff}
|
html.dark .inline-reply{background-color:#485865;color:#fff}
|
||||||
html.dark .inline-reply .btn-neutral,html.dark .inline-reply .character-count{color:#fff}
|
html.dark .inline-reply .btn-neutral,html.dark .inline-reply .character-count{color:#fff}
|
||||||
html.dark .reply-triangle{border-color:transparent transparent #485865}
|
html.dark .reply-triangle{border-color:transparent transparent #485865}
|
||||||
|
@@ -8,7 +8,7 @@ Custom reply account
|
|||||||
chylex
|
chylex
|
||||||
|
|
||||||
[version]
|
[version]
|
||||||
1.2.4
|
1.3
|
||||||
|
|
||||||
[website]
|
[website]
|
||||||
https://tweetduck.chylex.com
|
https://tweetduck.chylex.com
|
||||||
|
@@ -12,10 +12,16 @@ enabled(){
|
|||||||
|
|
||||||
if (configuration.useAdvancedSelector){
|
if (configuration.useAdvancedSelector){
|
||||||
if (configuration.customSelector){
|
if (configuration.customSelector){
|
||||||
if (configuration.customSelector.toString().startsWith("function (column){")){
|
let customSelectorDef = configuration.customSelector.toString();
|
||||||
|
|
||||||
|
if (customSelectorDef.startsWith("function (column){")){
|
||||||
$TD.alert("warning", "Plugin reply-account has invalid configuration: customSelector needs to be updated due to TweetDeck changes, please read the default configuration file for the updated guide");
|
$TD.alert("warning", "Plugin reply-account has invalid configuration: customSelector needs to be updated due to TweetDeck changes, please read the default configuration file for the updated guide");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
else if (customSelectorDef.startsWith("function (type,")){
|
||||||
|
$TD.alert("warning", "Plugin reply-account has invalid configuration: the type parameter is no longer present due to TweetDeck changes, please read the default configuration file for the updated guide");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
var section = data.element.closest("section.js-column");
|
var section = data.element.closest("section.js-column");
|
||||||
|
|
||||||
@@ -35,7 +41,7 @@ enabled(){
|
|||||||
}
|
}
|
||||||
|
|
||||||
try{
|
try{
|
||||||
query = configuration.customSelector(column.getColumnType(), columnTitle, columnAccount, column, section.hasClass("column-temp"));
|
query = configuration.customSelector(columnTitle, columnAccount, column, section.hasClass("column-temp"));
|
||||||
}catch(e){
|
}catch(e){
|
||||||
$TD.alert("warning", "Plugin reply-account has invalid configuration: customSelector threw an error: "+e.message);
|
$TD.alert("warning", "Plugin reply-account has invalid configuration: customSelector threw an error: "+e.message);
|
||||||
return;
|
return;
|
||||||
|
@@ -30,14 +30,19 @@
|
|||||||
* https://tweetduck.chylex.com/guide/#dev-tools
|
* https://tweetduck.chylex.com/guide/#dev-tools
|
||||||
*
|
*
|
||||||
*
|
*
|
||||||
* The 'type' parameter is TweetDeck column type. Here is the full list of column types, note that some are
|
* In order to check the column type, use the 'column.isOfType' function. It is recommended to always put it
|
||||||
* unused and have misleading names (for example, Home columns are 'col_timeline' instead of 'col_home'):
|
* last in an 'if' statement, because it is much more demanding than checking the title/account.
|
||||||
* col_timeline, col_interactions, col_mentions, col_followers, col_search, col_list,
|
*
|
||||||
* col_customtimeline, col_messages, col_usertweets, col_favorites, col_activity,
|
* Here is the full list of column types, note that some are unused and have misleading names.
|
||||||
* col_dataminr, col_home, col_me, col_inbox, col_scheduled, col_unknown
|
* (for example, Home columns are 'col_timeline' instead of 'col_home')
|
||||||
|
*
|
||||||
|
* col_activity, col_customtimeline, col_dataminr, col_favorites, col_followers, col_home,
|
||||||
|
* col_inbox, col_interactions, col_list, col_livevideo, col_me, col_mentions,
|
||||||
|
* col_messages, col_scheduled, col_search, col_timeline, col_usertweets, col_unknown
|
||||||
*
|
*
|
||||||
* If you want to see your current column types, run this in your browser console:
|
* If you want to see your current column types, run this in your browser console:
|
||||||
* TD.controller.columnManager.getAllOrdered().map(obj => obj.getColumnType());
|
*
|
||||||
|
* (c=>c.columnManager.getAllOrdered().map(o=>Object.keys(c.stats.columnNamespaces).find(t=>o.isOfType(t))).map(t=>t==""+void 0?"col_unknown":t))(TD.controller)
|
||||||
*
|
*
|
||||||
*
|
*
|
||||||
* The 'title' parameter is the column title. Some are fixed (such as 'Home' or 'Notifications'),
|
* The 'title' parameter is the column title. Some are fixed (such as 'Home' or 'Notifications'),
|
||||||
@@ -61,16 +66,16 @@
|
|||||||
|
|
||||||
useAdvancedSelector: false,
|
useAdvancedSelector: false,
|
||||||
|
|
||||||
customSelector: function(type, title, account, column, isTemporary){
|
customSelector: function(title, account, column, isTemporary){
|
||||||
console.info(arguments); // Prints all arguments into the console
|
console.info(arguments); // Prints all arguments into the console
|
||||||
|
|
||||||
if (type === "col_search" && title === "TweetDuck"){
|
if (title === "TweetDuck" && column.isOfType("col_search")){
|
||||||
// This is a search column that looks for 'TweetDuck' in the tweets,
|
// This is a search column that looks for 'TweetDuck' in the tweets,
|
||||||
// search columns are normally linked to the preferred account
|
// search columns are normally linked to the preferred account
|
||||||
// so this forces the @TryTweetDuck account to be used instead
|
// so this forces the @TryTweetDuck account to be used instead
|
||||||
return "@TryTweetDuck";
|
return "@TryTweetDuck";
|
||||||
}
|
}
|
||||||
else if (type === "col_timeline" && account === "@chylexcz"){
|
else if (account === "@chylexcz" && column.isOfType("col_timeline")){
|
||||||
// This is a Home column of my test account @chylexcz,
|
// This is a Home column of my test account @chylexcz,
|
||||||
// but I want to reply to tweets from my official account
|
// but I want to reply to tweets from my official account
|
||||||
return "@chylexmc";
|
return "@chylexmc";
|
||||||
|
@@ -98,6 +98,13 @@
|
|||||||
return value;
|
return value;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
//
|
||||||
|
// Function: Retrieves column name
|
||||||
|
const getColumnName = function(column){
|
||||||
|
let cached = column._tduck_type || (column._tduck_type = Object.keys(columnTypes).find(type => column.isOfType(type)));
|
||||||
|
return columnTypes[cached] || "";
|
||||||
|
};
|
||||||
|
|
||||||
//
|
//
|
||||||
// Function: Event callback for a new tweet.
|
// Function: Event callback for a new tweet.
|
||||||
//
|
//
|
||||||
@@ -220,7 +227,7 @@
|
|||||||
let tweetUrl = source ? source.getChirpURL() : "";
|
let tweetUrl = source ? source.getChirpURL() : "";
|
||||||
let quoteUrl = source && source.quotedTweet ? source.quotedTweet.getChirpURL() : "";
|
let quoteUrl = source && source.quotedTweet ? source.quotedTweet.getChirpURL() : "";
|
||||||
|
|
||||||
$TD.onTweetPopup(column.model.privateState.apiid, chirpId, columnTypes[column.getColumnType()] || "", html.html(), duration, tweetUrl, quoteUrl);
|
$TD.onTweetPopup(column.model.privateState.apiid, chirpId, getColumnName(column), html.html(), duration, tweetUrl, quoteUrl);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (column.model.getHasSound()){
|
if (column.model.getHasSound()){
|
||||||
@@ -1310,6 +1317,11 @@
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// Block: Fix columns missing any identifiable attributes to allow individual styles.
|
||||||
|
//
|
||||||
|
TD.mustaches["column.mustache"] = TD.mustaches["column.mustache"].replace("{{columnclass}}\"", "{{columnclass}}\" data-td-icon=\"{{columniconclass}}\"");
|
||||||
|
|
||||||
//
|
//
|
||||||
// Block: Remove column mouse wheel handler, which allows smooth scrolling inside columns, and horizontally scrolling column container when holding Shift.
|
// Block: Remove column mouse wheel handler, which allows smooth scrolling inside columns, and horizontally scrolling column container when holding Shift.
|
||||||
//
|
//
|
||||||
|
@@ -98,7 +98,7 @@
|
|||||||
</footer>
|
</footer>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>`).appendTo(".js-app");
|
</div>`).appendTo(".js-app"); /* TODO btn-positive is removed, check all files again */
|
||||||
|
|
||||||
let tdUser = null;
|
let tdUser = null;
|
||||||
let loadTweetDuckUser = (onSuccess, onError) => {
|
let loadTweetDuckUser = (onSuccess, onError) => {
|
||||||
|
@@ -1,6 +1,6 @@
|
|||||||
(function($TD){
|
(function($TD){
|
||||||
let ele = document.getElementsByTagName("article")[0];
|
let ele = document.getElementsByTagName("article")[0];
|
||||||
ele.style.width = window.innerWidth+"px";
|
ele.style.width = "{width}px";
|
||||||
|
|
||||||
ele.style.position = "absolute";
|
ele.style.position = "absolute";
|
||||||
let contentHeight = ele.offsetHeight;
|
let contentHeight = ele.offsetHeight;
|
||||||
@@ -9,6 +9,7 @@
|
|||||||
let avatar = ele.querySelector(".tweet-avatar");
|
let avatar = ele.querySelector(".tweet-avatar");
|
||||||
let avatarBottom = avatar ? avatar.getBoundingClientRect().bottom : 0;
|
let avatarBottom = avatar ? avatar.getBoundingClientRect().bottom : 0;
|
||||||
|
|
||||||
$TD.setHeight(Math.floor(Math.max(contentHeight, avatarBottom+9)));
|
$TD.setHeight(Math.floor(Math.max(contentHeight, avatarBottom+9))).then(() => {
|
||||||
setTimeout($TD.triggerScreenshot, document.getElementsByTagName("iframe").length ? 267 : 67);
|
setTimeout($TD.triggerScreenshot, document.getElementsByTagName("iframe").length ? 267 : 67);
|
||||||
|
});
|
||||||
})($TD_NotificationScreenshot);
|
})($TD_NotificationScreenshot);
|
||||||
|
@@ -50,7 +50,7 @@ button, .btn, .mdl, .mdl-content, .popover, .lst-modal, .tooltip-inner {
|
|||||||
border-radius: 0 !important;
|
border-radius: 0 !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
.dropdown-menu, .list-item-last, .quoted-tweet, .input-group-button, input, textarea, select, .prf-header, .accs li, .accs img {
|
.dropdown-menu, .list-item-last, .quoted-tweet, input, textarea, select, .prf-header {
|
||||||
border-radius: 0 !important;
|
border-radius: 0 !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -261,11 +261,6 @@ html[data-td-font='smallest'] .tweet-detail-wrapper .badge-verified:before {
|
|||||||
background-position: -223px -97px !important;
|
background-position: -223px -97px !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
.accs-header {
|
|
||||||
/* fix retweet account selector heading */
|
|
||||||
padding-left: 0 !important;
|
|
||||||
}
|
|
||||||
|
|
||||||
.keyboard-shortcut-list {
|
.keyboard-shortcut-list {
|
||||||
/* fix keyboard navigation alignment */
|
/* fix keyboard navigation alignment */
|
||||||
vertical-align: top !important;
|
vertical-align: top !important;
|
||||||
@@ -276,12 +271,6 @@ html[data-td-font='smallest'] .tweet-detail-wrapper .badge-verified:before {
|
|||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
}
|
}
|
||||||
|
|
||||||
.inline-reply .btn-square, .rpl-actions .btn-square {
|
|
||||||
/* remove effects from buttons under reply input... this keeps happening for some stupid reason */
|
|
||||||
background: transparent !important;
|
|
||||||
box-shadow: none !important;
|
|
||||||
}
|
|
||||||
|
|
||||||
.js-add-to-customtimeline-input {
|
.js-add-to-customtimeline-input {
|
||||||
/* the custom timeline input shadow is behaving super weird when focused */
|
/* the custom timeline input shadow is behaving super weird when focused */
|
||||||
box-shadow: none !important;
|
box-shadow: none !important;
|
||||||
@@ -361,18 +350,18 @@ html[data-td-font='smallest'] .tweet-detail-wrapper .badge-verified:before {
|
|||||||
/* Fix cut off usernames in Messages column */
|
/* Fix cut off usernames in Messages column */
|
||||||
/********************************************/
|
/********************************************/
|
||||||
|
|
||||||
.column-type-message.is-shifted-1 .column-title-container {
|
[data-td-icon="icon-message"].is-shifted-1 .column-title-container {
|
||||||
height: 100%;
|
height: 100%;
|
||||||
border-bottom-color: transparent;
|
border-bottom-color: transparent;
|
||||||
}
|
}
|
||||||
|
|
||||||
#tduck .column-type-message.is-shifted-1 .column-title-items {
|
#tduck [data-td-icon="icon-message"].is-shifted-1 .column-title-items {
|
||||||
height: 100%;
|
height: 100%;
|
||||||
margin-left: 4px !important;
|
margin-left: 4px !important;
|
||||||
padding-top: 1px;
|
padding-top: 1px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.column-type-message.is-shifted-1 .username {
|
[data-td-icon="icon-message"].is-shifted-1 .username {
|
||||||
vertical-align: bottom;
|
vertical-align: bottom;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -1,33 +1,9 @@
|
|||||||
(function($, $TDU){
|
(function($, $TDU){
|
||||||
//
|
|
||||||
// Variable: Current timeout ID for update checking.
|
|
||||||
//
|
|
||||||
var updateCheckTimeoutID;
|
|
||||||
|
|
||||||
//
|
|
||||||
// Constant: Update exe file name.
|
|
||||||
//
|
|
||||||
const updateFileName = "TweetDuck.Update.exe";
|
|
||||||
|
|
||||||
//
|
|
||||||
// Constant: Url that returns JSON data about latest version.
|
|
||||||
//
|
|
||||||
const updateCheckUrlLatest = "https://api.github.com/repos/chylex/TweetDuck/releases/latest";
|
|
||||||
|
|
||||||
//
|
|
||||||
// Constant: Url that returns JSON data about all versions, including prereleases.
|
|
||||||
//
|
|
||||||
const updateCheckUrlAll = "https://api.github.com/repos/chylex/TweetDuck/releases";
|
|
||||||
|
|
||||||
//
|
|
||||||
// Constant: Fallback url in case the update installer file is missing.
|
|
||||||
//
|
|
||||||
const updateDownloadFallback = "https://tweetduck.chylex.com";
|
|
||||||
|
|
||||||
//
|
//
|
||||||
// Function: Creates the update notification element. Removes the old one if already exists.
|
// Function: Creates the update notification element. Removes the old one if already exists.
|
||||||
//
|
//
|
||||||
var displayNotification = function(version, download, changelog){
|
var displayNotification = function(version, changelog){
|
||||||
|
|
||||||
// styles
|
// styles
|
||||||
var css = $("#tweetduck-update-css");
|
var css = $("#tweetduck-update-css");
|
||||||
|
|
||||||
@@ -167,7 +143,7 @@
|
|||||||
<div id='tweetduck-changelog'>
|
<div id='tweetduck-changelog'>
|
||||||
<div id='tweetduck-changelog-box'>
|
<div id='tweetduck-changelog-box'>
|
||||||
<h2>TweetDuck Update ${version}</h2>
|
<h2>TweetDuck Update ${version}</h2>
|
||||||
${changelog}
|
${markdown(atob(changelog))}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
`).appendTo(document.body).css("display", "none");
|
`).appendTo(document.body).css("display", "none");
|
||||||
@@ -219,17 +195,11 @@
|
|||||||
|
|
||||||
buttonDiv.children(".tdu-btn-download").click(function(){
|
buttonDiv.children(".tdu-btn-download").click(function(){
|
||||||
hide();
|
hide();
|
||||||
|
|
||||||
if (download){
|
|
||||||
$TDU.onUpdateAccepted();
|
$TDU.onUpdateAccepted();
|
||||||
}
|
|
||||||
else{
|
|
||||||
$TDU.openBrowser(updateDownloadFallback);
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
|
|
||||||
buttonDiv.children(".tdu-btn-later").click(function(){
|
buttonDiv.children(".tdu-btn-later").click(function(){
|
||||||
clearTimeout(updateCheckTimeoutID);
|
$TDU.onUpdateDelayed();
|
||||||
slide();
|
slide();
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -245,15 +215,6 @@
|
|||||||
return ele;
|
return ele;
|
||||||
};
|
};
|
||||||
|
|
||||||
//
|
|
||||||
// Function: Returns milliseconds until the start of the next hour, with an extra offset in seconds that can skip an hour if the clock would roll over too soon.
|
|
||||||
//
|
|
||||||
var getTimeUntilNextHour = function(extra){
|
|
||||||
var now = new Date();
|
|
||||||
var offset = new Date(+now+extra*1000);
|
|
||||||
return new Date(offset.getFullYear(), offset.getMonth(), offset.getDate(), offset.getHours()+1, 0, 0)-now;
|
|
||||||
};
|
|
||||||
|
|
||||||
//
|
//
|
||||||
// Function: Ghetto-converts markdown to HTML.
|
// Function: Ghetto-converts markdown to HTML.
|
||||||
//
|
//
|
||||||
@@ -273,33 +234,6 @@
|
|||||||
.replace(/\n\r?\n\r?/g, "<br>");
|
.replace(/\n\r?\n\r?/g, "<br>");
|
||||||
};
|
};
|
||||||
|
|
||||||
//
|
|
||||||
// Function: Runs an update check and updates all DOM elements appropriately.
|
|
||||||
//
|
|
||||||
var runUpdateCheck = function(eventID, versionTag, dismissedVersionTag, allowPre){
|
|
||||||
clearTimeout(updateCheckTimeoutID);
|
|
||||||
updateCheckTimeoutID = setTimeout($TDU.triggerUpdateCheck, getTimeUntilNextHour(60*30)); // 30 minute offset
|
|
||||||
|
|
||||||
$.getJSON(allowPre ? updateCheckUrlAll : updateCheckUrlLatest, function(response){
|
|
||||||
var release = allowPre ? response[0] : response;
|
|
||||||
|
|
||||||
var tagName = release.tag_name;
|
|
||||||
var hasUpdate = tagName !== versionTag && tagName !== dismissedVersionTag && release.assets.length > 0;
|
|
||||||
|
|
||||||
if (hasUpdate){
|
|
||||||
var obj = release.assets.find(asset => asset.name === updateFileName) || { browser_download_url: "" };
|
|
||||||
displayNotification(tagName, obj.browser_download_url, markdown(release.body));
|
|
||||||
|
|
||||||
if (eventID){ // ignore undefined and 0
|
|
||||||
$TDU.onUpdateCheckFinished(eventID, tagName, obj.browser_download_url);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if (eventID){ // ignore undefined and 0
|
|
||||||
$TDU.onUpdateCheckFinished(eventID, null, null);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
//
|
//
|
||||||
// Block: Check updates on startup.
|
// Block: Check updates on startup.
|
||||||
//
|
//
|
||||||
@@ -310,5 +244,5 @@
|
|||||||
//
|
//
|
||||||
// Block: Setup global functions.
|
// Block: Setup global functions.
|
||||||
//
|
//
|
||||||
window.TDUF_runUpdateCheck = runUpdateCheck;
|
window.TDUF_displayNotification = displayNotification;
|
||||||
})($, $TDU);
|
})($, $TDU);
|
||||||
|
26
Resources/Utilities/CompareStylesheets.cs
Normal file
26
Resources/Utilities/CompareStylesheets.cs
Normal file
@@ -0,0 +1,26 @@
|
|||||||
|
using System.Text.RegularExpressions;
|
||||||
|
|
||||||
|
HashSet<string> ReadSelectors(string file){
|
||||||
|
return new HashSet<string>(
|
||||||
|
File.ReadAllLines(file)
|
||||||
|
.Where(line => line.Contains('{'))
|
||||||
|
.Select(line => line.Substring(0, line.IndexOf('{')).Trim())
|
||||||
|
.SelectMany(lines => lines.Split(new char[]{ ',', ' ' }, StringSplitOptions.RemoveEmptyEntries))
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
HashSet<string> ExtractClasses(HashSet<string> selectors){
|
||||||
|
return new HashSet<string>(
|
||||||
|
selectors.SelectMany(selector => Regex.Matches(selector, @"\.[a-zA-Z0-9_-]+").Cast<Match>().Select(match => match.Value))
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
void PrintAll(IEnumerable<string> data){
|
||||||
|
foreach(string line in data){
|
||||||
|
Print(line);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void PrintMissing(HashSet<string> all, HashSet<string> subset){
|
||||||
|
PrintAll(subset.Where(ele => !all.Contains(ele)));
|
||||||
|
}
|
@@ -69,6 +69,7 @@
|
|||||||
<Reference Include="System.Core" />
|
<Reference Include="System.Core" />
|
||||||
<Reference Include="System.Drawing" />
|
<Reference Include="System.Drawing" />
|
||||||
<Reference Include="System.Management" />
|
<Reference Include="System.Management" />
|
||||||
|
<Reference Include="System.Web.Extensions" />
|
||||||
<Reference Include="System.Windows.Forms" />
|
<Reference Include="System.Windows.Forms" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
@@ -259,6 +260,7 @@
|
|||||||
</Compile>
|
</Compile>
|
||||||
<Compile Include="Core\Notification\Screenshot\TweetScreenshotManager.cs" />
|
<Compile Include="Core\Notification\Screenshot\TweetScreenshotManager.cs" />
|
||||||
<Compile Include="Data\ResourceLink.cs" />
|
<Compile Include="Data\ResourceLink.cs" />
|
||||||
|
<Compile Include="Data\Result.cs" />
|
||||||
<Compile Include="Data\Serialization\FileSerializer.cs" />
|
<Compile Include="Data\Serialization\FileSerializer.cs" />
|
||||||
<Compile Include="Data\InjectedHTML.cs" />
|
<Compile Include="Data\InjectedHTML.cs" />
|
||||||
<Compile Include="Data\Serialization\ITypeConverter.cs" />
|
<Compile Include="Data\Serialization\ITypeConverter.cs" />
|
||||||
@@ -315,6 +317,7 @@
|
|||||||
<Compile Include="Core\Management\BrowserCache.cs" />
|
<Compile Include="Core\Management\BrowserCache.cs" />
|
||||||
<Compile Include="Core\Utils\BrowserUtils.cs" />
|
<Compile Include="Core\Utils\BrowserUtils.cs" />
|
||||||
<Compile Include="Core\Utils\NativeMethods.cs" />
|
<Compile Include="Core\Utils\NativeMethods.cs" />
|
||||||
|
<Compile Include="Updates\UpdateCheckClient.cs" />
|
||||||
<Compile Include="Updates\UpdateDownloadStatus.cs" />
|
<Compile Include="Updates\UpdateDownloadStatus.cs" />
|
||||||
<Compile Include="Updates\UpdateHandler.cs" />
|
<Compile Include="Updates\UpdateHandler.cs" />
|
||||||
<Compile Include="Updates\UpdateInfo.cs" />
|
<Compile Include="Updates\UpdateInfo.cs" />
|
||||||
|
@@ -1,13 +1,14 @@
|
|||||||
using System;
|
using System;
|
||||||
|
using TweetDuck.Data;
|
||||||
|
|
||||||
namespace TweetDuck.Updates.Events{
|
namespace TweetDuck.Updates.Events{
|
||||||
sealed class UpdateCheckEventArgs : EventArgs{
|
sealed class UpdateCheckEventArgs : EventArgs{
|
||||||
public int EventId { get; }
|
public int EventId { get; }
|
||||||
public bool IsUpdateAvailable { get; }
|
public Result<UpdateInfo> Result { get; }
|
||||||
|
|
||||||
public UpdateCheckEventArgs(int eventId, bool isUpdateAvailable){
|
public UpdateCheckEventArgs(int eventId, Result<UpdateInfo> result){
|
||||||
this.EventId = eventId;
|
this.EventId = eventId;
|
||||||
this.IsUpdateAvailable = isUpdateAvailable;
|
this.Result = result;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -1,7 +1,5 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Windows.Forms;
|
using System.Windows.Forms;
|
||||||
using TweetDuck.Core.Other;
|
|
||||||
using TweetDuck.Core.Utils;
|
|
||||||
|
|
||||||
namespace TweetDuck.Updates{
|
namespace TweetDuck.Updates{
|
||||||
sealed partial class FormUpdateDownload : Form{
|
sealed partial class FormUpdateDownload : Form{
|
||||||
@@ -22,21 +20,11 @@ namespace TweetDuck.Updates{
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void timerDownloadCheck_Tick(object sender, EventArgs e){
|
private void timerDownloadCheck_Tick(object sender, EventArgs e){
|
||||||
if (updateInfo.DownloadStatus == UpdateDownloadStatus.Done){
|
if (updateInfo.DownloadStatus.IsFinished()){
|
||||||
timerDownloadCheck.Stop();
|
timerDownloadCheck.Stop();
|
||||||
DialogResult = DialogResult.OK;
|
DialogResult = DialogResult.OK;
|
||||||
Close();
|
Close();
|
||||||
}
|
}
|
||||||
else if (updateInfo.DownloadStatus == UpdateDownloadStatus.Failed){
|
|
||||||
timerDownloadCheck.Stop();
|
|
||||||
|
|
||||||
if (FormMessage.Error("Update Has Failed", "Could not download the update: "+(updateInfo.DownloadError?.Message ?? "unknown error")+"\n\nDo you want to open the website and try downloading the update manually?", FormMessage.Yes, FormMessage.No)){
|
|
||||||
BrowserUtils.OpenExternalBrowser(Program.Website);
|
|
||||||
DialogResult = DialogResult.OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
Close();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
63
Updates/UpdateCheckClient.cs
Normal file
63
Updates/UpdateCheckClient.cs
Normal file
@@ -0,0 +1,63 @@
|
|||||||
|
using System;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Net;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using System.Web.Script.Serialization;
|
||||||
|
using TweetDuck.Core.Utils;
|
||||||
|
using JsonObject = System.Collections.Generic.IDictionary<string, object>;
|
||||||
|
|
||||||
|
namespace TweetDuck.Updates{
|
||||||
|
sealed class UpdateCheckClient{
|
||||||
|
private const string ApiLatestRelease = "https://api.github.com/repos/chylex/TweetDuck/releases/latest";
|
||||||
|
private const string UpdaterAssetName = "TweetDuck.Update.exe";
|
||||||
|
|
||||||
|
private readonly UpdaterSettings settings;
|
||||||
|
|
||||||
|
public UpdateCheckClient(UpdaterSettings settings){
|
||||||
|
this.settings = settings;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Task<UpdateInfo> Check(){
|
||||||
|
TaskCompletionSource<UpdateInfo> result = new TaskCompletionSource<UpdateInfo>();
|
||||||
|
|
||||||
|
WebClient client = BrowserUtils.CreateWebClient();
|
||||||
|
client.Headers[HttpRequestHeader.Accept] = "application/vnd.github.v3+json";
|
||||||
|
|
||||||
|
client.DownloadStringTaskAsync(ApiLatestRelease).ContinueWith(task => {
|
||||||
|
if (task.IsCanceled){
|
||||||
|
result.SetCanceled();
|
||||||
|
}
|
||||||
|
else if (task.IsFaulted){
|
||||||
|
result.SetException(task.Exception.InnerException);
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
try{
|
||||||
|
result.SetResult(ParseFromJson(task.Result));
|
||||||
|
}catch(Exception e){
|
||||||
|
result.SetException(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
return result.Task;
|
||||||
|
}
|
||||||
|
|
||||||
|
private UpdateInfo ParseFromJson(string json){
|
||||||
|
bool IsUpdaterAsset(JsonObject obj){
|
||||||
|
return UpdaterAssetName == (string)obj["name"];
|
||||||
|
}
|
||||||
|
|
||||||
|
string AssetDownloadUrl(JsonObject obj){
|
||||||
|
return (string)obj["browser_download_url"];
|
||||||
|
}
|
||||||
|
|
||||||
|
JsonObject root = (JsonObject)new JavaScriptSerializer().DeserializeObject(json);
|
||||||
|
|
||||||
|
string versionTag = (string)root["tag_name"];
|
||||||
|
string releaseNotes = (string)root["body"];
|
||||||
|
string downloadUrl = ((Array)root["assets"]).Cast<JsonObject>().Where(IsUpdaterAsset).Select(AssetDownloadUrl).FirstOrDefault();
|
||||||
|
|
||||||
|
return new UpdateInfo(settings, versionTag, releaseNotes, downloadUrl);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@@ -2,7 +2,15 @@
|
|||||||
public enum UpdateDownloadStatus{
|
public enum UpdateDownloadStatus{
|
||||||
None = 0,
|
None = 0,
|
||||||
InProgress,
|
InProgress,
|
||||||
Done,
|
Canceled,
|
||||||
Failed
|
AssetMissing,
|
||||||
|
Failed,
|
||||||
|
Done
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class UpdateDownloadStatusExtensions{
|
||||||
|
public static bool IsFinished(this UpdateDownloadStatus status){
|
||||||
|
return status == UpdateDownloadStatus.AssetMissing || status == UpdateDownloadStatus.Done || status == UpdateDownloadStatus.Failed;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -1,21 +1,23 @@
|
|||||||
using CefSharp;
|
using System;
|
||||||
using System;
|
using System.Threading.Tasks;
|
||||||
using System.Windows.Forms;
|
using System.Windows.Forms;
|
||||||
using TweetDuck.Core.Controls;
|
using TweetDuck.Core.Controls;
|
||||||
using TweetDuck.Core.Other.Interfaces;
|
using TweetDuck.Core.Other.Interfaces;
|
||||||
using TweetDuck.Core.Utils;
|
using TweetDuck.Data;
|
||||||
using TweetDuck.Resources;
|
|
||||||
using TweetDuck.Updates.Events;
|
using TweetDuck.Updates.Events;
|
||||||
|
|
||||||
namespace TweetDuck.Updates{
|
namespace TweetDuck.Updates{
|
||||||
sealed class UpdateHandler{
|
sealed class UpdateHandler : IDisposable{
|
||||||
public const int CheckCodeUpdatesDisabled = -1;
|
public const int CheckCodeUpdatesDisabled = -1;
|
||||||
public const int CheckCodeNotOnTweetDeck = -2;
|
public const int CheckCodeNotOnTweetDeck = -2;
|
||||||
|
|
||||||
private readonly ITweetDeckBrowser browser;
|
|
||||||
private readonly UpdaterSettings settings;
|
private readonly UpdaterSettings settings;
|
||||||
|
private readonly UpdateCheckClient client;
|
||||||
|
private readonly ITweetDeckBrowser browser;
|
||||||
|
private readonly Timer timer;
|
||||||
|
|
||||||
public event EventHandler<UpdateEventArgs> UpdateAccepted;
|
public event EventHandler<UpdateEventArgs> UpdateAccepted;
|
||||||
|
public event EventHandler<UpdateEventArgs> UpdateDelayed;
|
||||||
public event EventHandler<UpdateEventArgs> UpdateDismissed;
|
public event EventHandler<UpdateEventArgs> UpdateDismissed;
|
||||||
public event EventHandler<UpdateCheckEventArgs> CheckFinished;
|
public event EventHandler<UpdateCheckEventArgs> CheckFinished;
|
||||||
|
|
||||||
@@ -23,15 +25,43 @@ namespace TweetDuck.Updates{
|
|||||||
private UpdateInfo lastUpdateInfo;
|
private UpdateInfo lastUpdateInfo;
|
||||||
|
|
||||||
public UpdateHandler(ITweetDeckBrowser browser, UpdaterSettings settings){
|
public UpdateHandler(ITweetDeckBrowser browser, UpdaterSettings settings){
|
||||||
this.browser = browser;
|
|
||||||
this.settings = settings;
|
this.settings = settings;
|
||||||
|
this.client = new UpdateCheckClient(settings);
|
||||||
|
|
||||||
browser.OnFrameLoaded(OnFrameLoaded);
|
this.browser = browser;
|
||||||
browser.RegisterBridge("$TDU", new Bridge(this));
|
this.browser.RegisterBridge("$TDU", new Bridge(this));
|
||||||
|
|
||||||
|
this.timer = new Timer();
|
||||||
|
this.timer.Tick += timer_Tick;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void OnFrameLoaded(IFrame frame){
|
public void Dispose(){
|
||||||
ScriptLoader.ExecuteFile(frame, "update.js"); // TODO can't show error on failure
|
timer.Dispose();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void timer_Tick(object sender, EventArgs e){
|
||||||
|
timer.Stop();
|
||||||
|
Check(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void StartTimer(){
|
||||||
|
if (timer.Enabled){
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
timer.Stop();
|
||||||
|
|
||||||
|
if (Program.UserConfig.EnableUpdateCheck){
|
||||||
|
DateTime now = DateTime.Now;
|
||||||
|
TimeSpan nextHour = now.AddSeconds(60*(60-now.Minute)-now.Second)-now;
|
||||||
|
|
||||||
|
if (nextHour.TotalMinutes < 15){
|
||||||
|
nextHour = nextHour.Add(TimeSpan.FromHours(1));
|
||||||
|
}
|
||||||
|
|
||||||
|
timer.Interval = (int)Math.Ceiling(nextHour.TotalMilliseconds);
|
||||||
|
timer.Start();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public int Check(bool force){
|
public int Check(bool force){
|
||||||
@@ -44,16 +74,23 @@ namespace TweetDuck.Updates{
|
|||||||
return CheckCodeNotOnTweetDeck;
|
return CheckCodeNotOnTweetDeck;
|
||||||
}
|
}
|
||||||
|
|
||||||
browser.ExecuteFunction("TDUF_runUpdateCheck", (int)unchecked(++lastEventId), Program.VersionTag, settings.DismissedUpdate ?? string.Empty, settings.AllowPreReleases);
|
int nextEventId = unchecked(++lastEventId);
|
||||||
return lastEventId;
|
Task<UpdateInfo> checkTask = client.Check();
|
||||||
|
|
||||||
|
checkTask.ContinueWith(task => HandleUpdateCheckSuccessful(nextEventId, task.Result), TaskContinuationOptions.OnlyOnRanToCompletion);
|
||||||
|
checkTask.ContinueWith(task => HandleUpdateCheckFailed(nextEventId, task.Exception.InnerException), TaskContinuationOptions.OnlyOnFaulted);
|
||||||
|
|
||||||
|
return nextEventId;
|
||||||
}
|
}
|
||||||
|
|
||||||
return CheckCodeUpdatesDisabled;
|
return CheckCodeUpdatesDisabled;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void BeginUpdateDownload(Form ownerForm, UpdateInfo updateInfo, Action<UpdateInfo> onSuccess){
|
public void BeginUpdateDownload(Form ownerForm, UpdateInfo updateInfo, Action<UpdateInfo> onFinished){
|
||||||
if (updateInfo.DownloadStatus == UpdateDownloadStatus.Done){
|
UpdateDownloadStatus status = updateInfo.DownloadStatus;
|
||||||
onSuccess(updateInfo);
|
|
||||||
|
if (status == UpdateDownloadStatus.Done || status == UpdateDownloadStatus.AssetMissing){
|
||||||
|
onFinished(updateInfo);
|
||||||
}
|
}
|
||||||
else{
|
else{
|
||||||
FormUpdateDownload downloadForm = new FormUpdateDownload(updateInfo);
|
FormUpdateDownload downloadForm = new FormUpdateDownload(updateInfo);
|
||||||
@@ -64,14 +101,12 @@ namespace TweetDuck.Updates{
|
|||||||
};
|
};
|
||||||
|
|
||||||
downloadForm.FormClosed += (sender, args) => {
|
downloadForm.FormClosed += (sender, args) => {
|
||||||
downloadForm.Dispose();
|
if (downloadForm.DialogResult != DialogResult.OK){
|
||||||
|
updateInfo.CancelDownload();
|
||||||
|
}
|
||||||
|
|
||||||
if (downloadForm.DialogResult == DialogResult.OK){ // success or manual download
|
downloadForm.Dispose();
|
||||||
onSuccess(updateInfo);
|
onFinished(updateInfo);
|
||||||
}
|
|
||||||
else{
|
|
||||||
ownerForm.Show();
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
downloadForm.Show();
|
downloadForm.Show();
|
||||||
@@ -85,17 +120,39 @@ namespace TweetDuck.Updates{
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void TriggerUpdateAcceptedEvent(UpdateEventArgs args){
|
private void HandleUpdateCheckSuccessful(int eventId, UpdateInfo info){
|
||||||
UpdateAccepted?.Invoke(this, args);
|
if (info.IsUpdateNew && !info.IsUpdateDismissed){
|
||||||
|
CleanupDownload();
|
||||||
|
lastUpdateInfo = info;
|
||||||
|
lastUpdateInfo.BeginSilentDownload();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void TriggerUpdateDismissedEvent(UpdateEventArgs args){
|
CheckFinished?.Invoke(this, new UpdateCheckEventArgs(eventId, new Result<UpdateInfo>(info)));
|
||||||
settings.DismissedUpdate = args.UpdateInfo.VersionTag;
|
|
||||||
UpdateDismissed?.Invoke(this, args);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void TriggerCheckFinishedEvent(UpdateCheckEventArgs args){
|
private void HandleUpdateCheckFailed(int eventId, Exception exception){
|
||||||
CheckFinished?.Invoke(this, args);
|
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){
|
||||||
|
settings.DismissedUpdate = lastUpdateInfo.VersionTag;
|
||||||
|
UpdateDismissed?.Invoke(this, new UpdateEventArgs(lastUpdateInfo));
|
||||||
|
|
||||||
|
CleanupDownload();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public sealed class Bridge{
|
public sealed class Bridge{
|
||||||
@@ -109,31 +166,16 @@ namespace TweetDuck.Updates{
|
|||||||
owner.Check(false);
|
owner.Check(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void OnUpdateCheckFinished(int eventId, string versionTag, string downloadUrl){
|
|
||||||
if (versionTag != null && (owner.lastUpdateInfo == null || owner.lastUpdateInfo.VersionTag != versionTag)){
|
|
||||||
owner.CleanupDownload();
|
|
||||||
owner.lastUpdateInfo = new UpdateInfo(owner.settings, eventId, versionTag, downloadUrl);
|
|
||||||
owner.lastUpdateInfo.BeginSilentDownload();
|
|
||||||
}
|
|
||||||
|
|
||||||
owner.TriggerCheckFinishedEvent(new UpdateCheckEventArgs(eventId, owner.lastUpdateInfo != null));
|
|
||||||
}
|
|
||||||
|
|
||||||
public void OnUpdateAccepted(){
|
public void OnUpdateAccepted(){
|
||||||
if (owner.lastUpdateInfo != null){
|
owner.TriggerUpdateAcceptedEvent();
|
||||||
owner.TriggerUpdateAcceptedEvent(new UpdateEventArgs(owner.lastUpdateInfo));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void OnUpdateDelayed(){
|
||||||
|
owner.TriggerUpdateDelayedEvent();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void OnUpdateDismissed(){
|
public void OnUpdateDismissed(){
|
||||||
if (owner.lastUpdateInfo != null){
|
owner.TriggerUpdateDismissedEvent();
|
||||||
owner.TriggerUpdateDismissedEvent(new UpdateEventArgs(owner.lastUpdateInfo));
|
|
||||||
owner.CleanupDownload();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void OpenBrowser(string url){
|
|
||||||
BrowserUtils.OpenExternalBrowser(url);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -5,40 +5,43 @@ using TweetDuck.Core.Utils;
|
|||||||
|
|
||||||
namespace TweetDuck.Updates{
|
namespace TweetDuck.Updates{
|
||||||
sealed class UpdateInfo{
|
sealed class UpdateInfo{
|
||||||
public int EventId { get; }
|
|
||||||
public string VersionTag { get; }
|
public string VersionTag { get; }
|
||||||
|
public string ReleaseNotes { get; }
|
||||||
public string InstallerPath { get; }
|
public string InstallerPath { get; }
|
||||||
|
|
||||||
|
public bool IsUpdateNew => VersionTag != Program.VersionTag;
|
||||||
|
public bool IsUpdateDismissed => VersionTag == settings.DismissedUpdate;
|
||||||
|
|
||||||
public UpdateDownloadStatus DownloadStatus { get; private set; }
|
public UpdateDownloadStatus DownloadStatus { get; private set; }
|
||||||
public Exception DownloadError { get; private set; }
|
public Exception DownloadError { get; private set; }
|
||||||
|
|
||||||
private readonly string installerFolder;
|
private readonly UpdaterSettings settings;
|
||||||
private readonly string downloadUrl;
|
private readonly string downloadUrl;
|
||||||
private WebClient currentDownload;
|
private WebClient currentDownload;
|
||||||
|
|
||||||
public UpdateInfo(UpdaterSettings settings, int eventId, string versionTag, string downloadUrl){
|
public UpdateInfo(UpdaterSettings settings, string versionTag, string releaseNotes, string downloadUrl){
|
||||||
this.installerFolder = settings.InstallerDownloadFolder;
|
this.settings = settings;
|
||||||
this.downloadUrl = downloadUrl;
|
this.downloadUrl = downloadUrl;
|
||||||
|
|
||||||
this.EventId = eventId;
|
|
||||||
this.VersionTag = versionTag;
|
this.VersionTag = versionTag;
|
||||||
this.InstallerPath = Path.Combine(installerFolder, "TweetDuck."+versionTag+".exe");
|
this.ReleaseNotes = releaseNotes;
|
||||||
|
this.InstallerPath = Path.Combine(settings.InstallerDownloadFolder, "TweetDuck."+versionTag+".exe");
|
||||||
}
|
}
|
||||||
|
|
||||||
public void BeginSilentDownload(){
|
public void BeginSilentDownload(){
|
||||||
if (DownloadStatus == UpdateDownloadStatus.None || DownloadStatus == UpdateDownloadStatus.Failed){
|
if (DownloadStatus == UpdateDownloadStatus.None || DownloadStatus == UpdateDownloadStatus.Failed){
|
||||||
DownloadStatus = UpdateDownloadStatus.InProgress;
|
DownloadStatus = UpdateDownloadStatus.InProgress;
|
||||||
|
|
||||||
try{
|
if (string.IsNullOrEmpty(downloadUrl)){
|
||||||
Directory.CreateDirectory(installerFolder);
|
DownloadError = new InvalidDataException("Missing installer asset.");
|
||||||
}catch(Exception e){
|
DownloadStatus = UpdateDownloadStatus.AssetMissing;
|
||||||
DownloadError = e;
|
|
||||||
DownloadStatus = UpdateDownloadStatus.Failed;
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (string.IsNullOrEmpty(downloadUrl)){
|
try{
|
||||||
DownloadError = new UriFormatException("Could not determine URL of the update installer");
|
Directory.CreateDirectory(settings.InstallerDownloadFolder);
|
||||||
|
}catch(Exception e){
|
||||||
|
DownloadError = e;
|
||||||
DownloadStatus = UpdateDownloadStatus.Failed;
|
DownloadStatus = UpdateDownloadStatus.Failed;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -68,5 +71,18 @@ namespace TweetDuck.Updates{
|
|||||||
// rip
|
// rip
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void CancelDownload(){
|
||||||
|
DeleteInstaller();
|
||||||
|
DownloadStatus = UpdateDownloadStatus.Canceled;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override bool Equals(object obj){
|
||||||
|
return obj is UpdateInfo info && VersionTag == info.VersionTag;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override int GetHashCode(){
|
||||||
|
return VersionTag.GetHashCode();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -2,7 +2,6 @@
|
|||||||
sealed class UpdaterSettings{
|
sealed class UpdaterSettings{
|
||||||
public string InstallerDownloadFolder { get; }
|
public string InstallerDownloadFolder { get; }
|
||||||
|
|
||||||
public bool AllowPreReleases { get; set; }
|
|
||||||
public string DismissedUpdate { get; set; }
|
public string DismissedUpdate { get; set; }
|
||||||
|
|
||||||
public UpdaterSettings(string installerDownloadFolder){
|
public UpdaterSettings(string installerDownloadFolder){
|
||||||
|
@@ -4,5 +4,4 @@
|
|||||||
<package id="cef.redist.x86" version="3.3282.1731" targetFramework="net452" xmlns="" />
|
<package id="cef.redist.x86" version="3.3282.1731" targetFramework="net452" xmlns="" />
|
||||||
<package id="CefSharp.Common" version="64.0.0-CI2508" targetFramework="net452" xmlns="" />
|
<package id="CefSharp.Common" version="64.0.0-CI2508" targetFramework="net452" xmlns="" />
|
||||||
<package id="CefSharp.WinForms" version="64.0.0-CI2508" targetFramework="net452" xmlns="" />
|
<package id="CefSharp.WinForms" version="64.0.0-CI2508" targetFramework="net452" xmlns="" />
|
||||||
<package id="Microsoft.VC120.CRT.JetBrains" version="12.0.21005.2" targetFramework="net452" xmlns="" />
|
|
||||||
</packages>
|
</packages>
|
Reference in New Issue
Block a user