1
0
mirror of https://github.com/chylex/TweetDuck.git synced 2025-09-14 19:32:10 +02:00

Compare commits

...

57 Commits
1.4 ... 1.4.2

Author SHA1 Message Date
20119db883 Release 1.4.2 2016-10-09 16:04:38 +02:00
a4006deb8c Rewrite extra mouse button handling and fix skipping 'Back to Tweet'
Closes #74
2016-10-09 15:49:08 +02:00
25fa3cefab Fix notification tweet footer displaying in some tweets (after removing it in a prev commit) 2016-10-09 15:13:01 +02:00
bb5161eb34 Fix notifications only displaying the last one when multiple were enqueued at the same time 2016-10-09 14:58:11 +02:00
1bfc403a98 Fix typos in installer script comments 2016-10-09 14:42:13 +02:00
720d10e543 Fix update installer version cleanup issue and move idpDownloadAfter to InitializeWizard 2016-10-09 13:33:38 +02:00
30c117672e Make full installer not automatically run TweetDuck when in silent mode 2016-10-09 13:32:28 +02:00
6d1b5c77d1 Fix program arguments for the full installer execution in update installer 2016-10-09 00:58:13 +02:00
d1cbf608e0 Add WIP full package download to update installation file if CEF needs updating 2016-10-09 00:54:37 +02:00
7e3014c52d Refactor installation files (move .NET Framework check to a function) 2016-10-09 00:53:59 +02:00
82beb1f5a7 Fix context menu state changing when moving mouse quickly
Closes #70
2016-10-08 17:43:55 +02:00
657dc81300 Include ISS installer scripts and resources 2016-10-08 17:36:20 +02:00
8e22192dd3 Update gitignore to include some files from 'bld' folder 2016-10-08 17:35:28 +02:00
dc0b7d58e3 Add an Open Program Folder button to Settings - Advanced 2016-10-08 16:20:52 +02:00
6919e5bdb0 Fix hardware acceleration only being partial 2016-10-08 16:13:50 +02:00
9728a62efa Remove unnecessary code from notification html builder 2016-09-30 23:56:27 +02:00
276e070759 Fix recent TweetDeck change breaking media in notifications 2016-09-30 23:43:46 +02:00
fadea54f8d Remove legacy update notification warnings 2016-09-30 15:12:18 +02:00
523d340ade Remove the disabled() event handler in timeline-polls plugin 2016-09-30 15:09:52 +02:00
96fa7efb66 Fix a crash in reply-account plugin on Popout 2016-09-27 21:30:34 +02:00
03591f8317 Release 1.4.1 2016-09-27 18:25:58 +02:00
28cc60d007 Tweak CommandLineArgsParser to slightly improve reliability with quoted strings 2016-09-27 18:11:50 +02:00
1fa69bdb3b Add invalid data folder error reporting and env variable expansion for absolute paths 2016-09-27 18:00:05 +02:00
11f5f9b72e Add Reporter.HandleEarlyFailure for non-recoverable errors before Reporter is setup 2016-09-27 17:58:13 +02:00
61f6543041 Change Source Code link to Tips & Tricks 2016-09-27 17:37:19 +02:00
0c9ab32f37 Add additional functionality to the back mouse button (inline and drawer composer, fix order) 2016-09-27 04:16:50 +02:00
fde984d02b Add a hover class to Notification body element and only display skip button when over 2016-09-27 03:48:14 +02:00
f23db31306 Increase default size of Edit CSS dialog 2016-09-26 17:20:25 +02:00
8dce99b8b3 Add support for ctrl+a shortcut in multiline textboxes 2016-09-26 17:20:10 +02:00
342ac51cda Tweak the skip button position in Notification window 2016-09-26 17:14:17 +02:00
ba31f7ae01 Update TweetDuck website to https 2016-09-26 16:31:06 +02:00
8d0fa030f8 Remove d3dcompiler_43.dll that used to be required for Win XP 2016-09-26 16:16:20 +02:00
d030a79c81 Fix Release build compliation error 2016-09-26 16:10:21 +02:00
6690efc4d9 Address code analysis issues 2016-09-26 15:53:08 +02:00
afa8098463 Add two restart buttons to Settings - Advanced 2016-09-26 14:28:14 +02:00
c064e579d2 Add Program.Restart and fix restarting causing loss of initial program arguments 2016-09-26 14:05:44 +02:00
01dc4e4714 Update CommandLineArgsParser to use CommandLineArgs 2016-09-26 13:58:59 +02:00
6fbc246b12 Use CommandLineArgs in Program and fix broken -locale parameter 2016-09-26 13:56:13 +02:00
1efe2a02f7 Add a CommandLineArgs class for easy arg management 2016-09-26 13:52:55 +02:00
ab2ab06f60 Reorganize utility classes and methods in TweetDeck Migration code 2016-09-26 04:19:50 +02:00
a71d889682 Replace FormMigrationQuestion with a custom FormMessage 2016-09-25 23:10:18 +02:00
2252d85b27 Add MessageBoxIcon.Question support to FormMessage 2016-09-25 23:09:36 +02:00
3f09100177 Update version of the design-revert plugin 2016-09-25 19:01:39 +02:00
6b79c89f42 Add a button to skip current notification 2016-09-25 16:53:00 +02:00
5f249d4603 Add a <body> td-example-notification attribute for example notifications 2016-09-25 16:52:22 +02:00
fa64309909 Hide the old TweetDeck column Clear button when clear-columns plugin is enabled 2016-09-25 15:35:15 +02:00
c46aafdab6 Add column resetting to clear-columns plugin 2016-09-25 15:31:18 +02:00
3e9c397494 Fix inconsistency with loadConfigurationFile's onFailure parameter 2016-09-25 03:21:44 +02:00
47935165db Update current plugins to use the new CSS functionality 2016-09-25 02:37:16 +02:00
be77f753e7 Add a global function to easily add custom styles in plugins 2016-09-25 02:34:19 +02:00
2c30613279 Fix reply-account plugin for docked replies 2016-09-23 22:09:06 +02:00
d83eaec987 Update reply-account plugin version 2016-09-23 21:14:53 +02:00
e6f199a224 Implement #last in reply-account and fix bugs in its code 2016-09-23 21:13:54 +02:00
6636a2aa9e Add an experimental timeline-polls plugin 2016-09-23 19:49:56 +02:00
221bdc58fe Tweak support for old configs in reply-account plugin 2016-09-23 16:05:53 +02:00
e48a068e9d Redesign reply-account plugin configuration and add WIP last account setting 2016-09-23 15:55:13 +02:00
3371c31e63 Release 1.4 2016-09-22 00:58:27 +02:00
45 changed files with 1028 additions and 436 deletions

5
.gitignore vendored
View File

@@ -17,9 +17,12 @@
[Rr]eleases/ [Rr]eleases/
x64/ x64/
x86/ x86/
bld/
[Bb]in/ [Bb]in/
[Oo]bj/ [Oo]bj/
bld/*
!bld/gen_full.iss
!bld/gen_upd.iss
!bld/Resources
# Visual Studio 2015 cache/options directory # Visual Studio 2015 cache/options directory
.vs/ .vs/

View File

@@ -34,5 +34,15 @@ namespace TweetDck.Core.Controls{
trackBar.Value = value; trackBar.Value = value;
} }
} }
public static void EnableMultilineShortcuts(this TextBox textBox){
textBox.KeyDown += (sender, args) => {
if (args.Control && args.KeyCode == Keys.A){
((TextBox)sender).SelectAll();
args.SuppressKeyPress = true;
args.Handled = true;
}
};
}
} }
} }

View File

@@ -225,7 +225,7 @@ namespace TweetDck.Core{
tweetQueue.Enqueue(notification); tweetQueue.Enqueue(notification);
UpdateTitle(); UpdateTitle();
if (!timerProgress.Enabled){ if (totalTime == 0){
LoadNextNotification(); LoadNextNotification();
} }
} }
@@ -248,6 +248,7 @@ namespace TweetDck.Core{
Location = new Point(-32000, -32000); Location = new Point(-32000, -32000);
progressBarTimer.Value = Program.UserConfig.NotificationTimerCountDown ? 1000 : 0; progressBarTimer.Value = Program.UserConfig.NotificationTimerCountDown ? 1000 : 0;
timerProgress.Stop(); timerProgress.Stop();
totalTime = 0;
StopMouseHook(); StopMouseHook();
} }

View File

@@ -18,6 +18,9 @@ namespace TweetDck.Core.Handling{
private readonly FormBrowser form; private readonly FormBrowser form;
private string lastHighlightedTweet;
private string lastHighlightedQuotedTweet;
public ContextMenuBrowser(FormBrowser form){ public ContextMenuBrowser(FormBrowser form){
this.form = form; this.form = form;
} }
@@ -31,11 +34,14 @@ namespace TweetDck.Core.Handling{
base.OnBeforeContextMenu(browserControl, browser, frame, parameters, model); base.OnBeforeContextMenu(browserControl, browser, frame, parameters, model);
if (!string.IsNullOrEmpty(TweetDeckBridge.LastHighlightedTweet) && (parameters.TypeFlags & (ContextMenuType.Editable | ContextMenuType.Selection)) == 0){ lastHighlightedTweet = TweetDeckBridge.LastHighlightedTweet;
lastHighlightedQuotedTweet = TweetDeckBridge.LastHighlightedQuotedTweet;
if (!string.IsNullOrEmpty(lastHighlightedTweet) && (parameters.TypeFlags & (ContextMenuType.Editable | ContextMenuType.Selection)) == 0){
model.AddItem((CefMenuCommand)MenuOpenTweetUrl, "Open tweet in browser"); model.AddItem((CefMenuCommand)MenuOpenTweetUrl, "Open tweet in browser");
model.AddItem((CefMenuCommand)MenuCopyTweetUrl, "Copy tweet address"); model.AddItem((CefMenuCommand)MenuCopyTweetUrl, "Copy tweet address");
if (!string.IsNullOrEmpty(TweetDeckBridge.LastHighlightedQuotedTweet)){ if (!string.IsNullOrEmpty(lastHighlightedQuotedTweet)){
model.AddSeparator(); model.AddSeparator();
model.AddItem((CefMenuCommand)MenuOpenQuotedTweetUrl, "Open quoted tweet in browser"); model.AddItem((CefMenuCommand)MenuOpenQuotedTweetUrl, "Open quoted tweet in browser");
model.AddItem((CefMenuCommand)MenuCopyQuotedTweetUrl, "Copy quoted tweet address"); model.AddItem((CefMenuCommand)MenuCopyQuotedTweetUrl, "Copy quoted tweet address");
@@ -91,19 +97,19 @@ namespace TweetDck.Core.Handling{
return true; return true;
case MenuOpenTweetUrl: case MenuOpenTweetUrl:
BrowserUtils.OpenExternalBrowser(TweetDeckBridge.LastHighlightedTweet); BrowserUtils.OpenExternalBrowser(lastHighlightedTweet);
return true; return true;
case MenuCopyTweetUrl: case MenuCopyTweetUrl:
Clipboard.SetText(TweetDeckBridge.LastHighlightedTweet, TextDataFormat.UnicodeText); Clipboard.SetText(lastHighlightedTweet, TextDataFormat.UnicodeText);
return true; return true;
case MenuOpenQuotedTweetUrl: case MenuOpenQuotedTweetUrl:
BrowserUtils.OpenExternalBrowser(TweetDeckBridge.LastHighlightedQuotedTweet); BrowserUtils.OpenExternalBrowser(lastHighlightedQuotedTweet);
return true; return true;
case MenuCopyQuotedTweetUrl: case MenuCopyQuotedTweetUrl:
Clipboard.SetText(TweetDeckBridge.LastHighlightedQuotedTweet, TextDataFormat.UnicodeText); Clipboard.SetText(lastHighlightedQuotedTweet, TextDataFormat.UnicodeText);
return true; return true;
} }

View File

@@ -119,6 +119,10 @@ namespace TweetDck.Core.Handling{
} }
} }
public void LoadNextNotification(){
notification.InvokeSafe(notification.FinishCurrentTweet);
}
public void TryPasteImage(){ public void TryPasteImage(){
form.InvokeSafe(() => { form.InvokeSafe(() => {
if (Clipboard.ContainsImage()){ if (Clipboard.ContainsImage()){

View File

@@ -20,7 +20,7 @@ namespace TweetDck.Core.Handling{
private static string CustomCSS{ private static string CustomCSS{
get{ get{
return @".scroll-styled-v::-webkit-scrollbar{width:8px}.scroll-styled-v::-webkit-scrollbar-thumb{border-radius:0}a[data-full-url]{word-break:break-all}"; return @".scroll-styled-v::-webkit-scrollbar{width:8px}.scroll-styled-v::-webkit-scrollbar-thumb{border-radius:0}a[data-full-url]{word-break:break-all}#td-skip{opacity:0;cursor:pointer;transition:opacity 0.15s ease}.td-hover #td-skip{opacity:0.75}#td-skip:hover{opacity:1}";
} }
} }
@@ -55,7 +55,7 @@ namespace TweetDck.Core.Handling{
build.Append(@"</div></div></article>"); build.Append(@"</div></div></article>");
return new TweetNotification(build.ToString(), "", 95); return new TweetNotification(build.ToString(), "", 95, true);
} }
} }
@@ -84,11 +84,15 @@ namespace TweetDck.Core.Handling{
private readonly string html; private readonly string html;
private readonly string url; private readonly string url;
private readonly int characters; private readonly int characters;
private readonly bool isExample;
public TweetNotification(string html, string url, int characters){ public TweetNotification(string html, string url, int characters) : this(html, url, characters, false){}
private TweetNotification(string html, string url, int characters, bool isExample){
this.html = html; this.html = html;
this.url = url; this.url = url;
this.characters = characters; this.characters = characters;
this.isExample = isExample;
} }
public int GetDisplayDuration(int value){ public int GetDisplayDuration(int value){
@@ -106,7 +110,7 @@ namespace TweetDck.Core.Handling{
} }
build.Append("</head>"); build.Append("</head>");
build.Append("<body class='hearty'><div class='app-columns-container'><div class='column scroll-styled-v' style='width:100%;overflow-y:auto'>"); build.Append("<body class='hearty'").Append(isExample ? " td-example-notification" : "").Append("><div class='app-columns-container'><div class='column scroll-styled-v' style='width:100%;overflow-y:auto'>");
build.Append(html); build.Append(html);
build.Append("</div></div></body>"); build.Append("</div></div></body>");
build.Append("</html>"); build.Append("</html>");

View File

@@ -28,7 +28,7 @@ namespace TweetDck.Core.Other {
System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(FormAbout)); System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(FormAbout));
this.pictureLogo = new System.Windows.Forms.PictureBox(); this.pictureLogo = new System.Windows.Forms.PictureBox();
this.labelDescription = new System.Windows.Forms.Label(); this.labelDescription = new System.Windows.Forms.Label();
this.labelSourceCode = new System.Windows.Forms.LinkLabel(); this.labelTips = new System.Windows.Forms.LinkLabel();
this.labelWebsite = new System.Windows.Forms.LinkLabel(); this.labelWebsite = new System.Windows.Forms.LinkLabel();
this.tablePanelLinks = new System.Windows.Forms.TableLayoutPanel(); this.tablePanelLinks = new System.Windows.Forms.TableLayoutPanel();
this.labelIssues = new System.Windows.Forms.LinkLabel(); this.labelIssues = new System.Windows.Forms.LinkLabel();
@@ -59,19 +59,19 @@ namespace TweetDck.Core.Other {
this.labelDescription.Size = new System.Drawing.Size(232, 109); this.labelDescription.Size = new System.Drawing.Size(232, 109);
this.labelDescription.TabIndex = 1; this.labelDescription.TabIndex = 1;
// //
// labelSourceCode // labelTips
// //
this.labelSourceCode.Dock = System.Windows.Forms.DockStyle.Fill; this.labelTips.Dock = System.Windows.Forms.DockStyle.Fill;
this.labelSourceCode.Font = new System.Drawing.Font("Microsoft Sans Serif", 9.75F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(238))); this.labelTips.Font = new System.Drawing.Font("Microsoft Sans Serif", 9.75F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(238)));
this.labelSourceCode.LinkArea = new System.Windows.Forms.LinkArea(0, 0); this.labelTips.LinkArea = new System.Windows.Forms.LinkArea(0, 0);
this.labelSourceCode.Location = new System.Drawing.Point(117, 0); this.labelTips.Location = new System.Drawing.Point(117, 0);
this.labelSourceCode.Margin = new System.Windows.Forms.Padding(0); this.labelTips.Margin = new System.Windows.Forms.Padding(0);
this.labelSourceCode.Name = "labelSourceCode"; this.labelTips.Name = "labelTips";
this.labelSourceCode.Size = new System.Drawing.Size(99, 16); this.labelTips.Size = new System.Drawing.Size(99, 16);
this.labelSourceCode.TabIndex = 3; this.labelTips.TabIndex = 3;
this.labelSourceCode.Text = "Source Code"; this.labelTips.Text = "Tips && Tricks";
this.labelSourceCode.TextAlign = System.Drawing.ContentAlignment.MiddleCenter; this.labelTips.TextAlign = System.Drawing.ContentAlignment.MiddleCenter;
this.labelSourceCode.LinkClicked += new System.Windows.Forms.LinkLabelLinkClickedEventHandler(this.OnLinkClicked); this.labelTips.LinkClicked += new System.Windows.Forms.LinkLabelLinkClickedEventHandler(this.OnLinkClicked);
// //
// labelWebsite // labelWebsite
// //
@@ -98,7 +98,7 @@ namespace TweetDck.Core.Other {
this.tablePanelLinks.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 35.14F)); this.tablePanelLinks.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 35.14F));
this.tablePanelLinks.Controls.Add(this.labelIssues, 2, 0); this.tablePanelLinks.Controls.Add(this.labelIssues, 2, 0);
this.tablePanelLinks.Controls.Add(this.labelWebsite, 0, 0); this.tablePanelLinks.Controls.Add(this.labelWebsite, 0, 0);
this.tablePanelLinks.Controls.Add(this.labelSourceCode, 1, 0); this.tablePanelLinks.Controls.Add(this.labelTips, 1, 0);
this.tablePanelLinks.Location = new System.Drawing.Point(12, 124); this.tablePanelLinks.Location = new System.Drawing.Point(12, 124);
this.tablePanelLinks.Name = "tablePanelLinks"; this.tablePanelLinks.Name = "tablePanelLinks";
this.tablePanelLinks.RowCount = 1; this.tablePanelLinks.RowCount = 1;
@@ -146,7 +146,7 @@ namespace TweetDck.Core.Other {
private System.Windows.Forms.PictureBox pictureLogo; private System.Windows.Forms.PictureBox pictureLogo;
private System.Windows.Forms.Label labelDescription; private System.Windows.Forms.Label labelDescription;
private System.Windows.Forms.LinkLabel labelSourceCode; private System.Windows.Forms.LinkLabel labelTips;
private System.Windows.Forms.LinkLabel labelWebsite; private System.Windows.Forms.LinkLabel labelWebsite;
private System.Windows.Forms.TableLayoutPanel tablePanelLinks; private System.Windows.Forms.TableLayoutPanel tablePanelLinks;
private System.Windows.Forms.LinkLabel labelIssues; private System.Windows.Forms.LinkLabel labelIssues;

View File

@@ -3,7 +3,7 @@ using TweetDck.Core.Utils;
namespace TweetDck.Core.Other{ namespace TweetDck.Core.Other{
sealed partial class FormAbout : Form{ sealed partial class FormAbout : Form{
private const string GitHubLink = "https://github.com/chylex/TweetDuck"; private const string TipsLink = "https://github.com/chylex/TweetDuck/wiki";
private const string IssuesLink = "https://github.com/chylex/TweetDuck/issues"; private const string IssuesLink = "https://github.com/chylex/TweetDuck/issues";
public FormAbout(){ public FormAbout(){
@@ -14,7 +14,7 @@ namespace TweetDck.Core.Other{
labelDescription.Text = Program.BrandName+" was created by chylex as a replacement to the discontinued official TweetDeck client for Windows.\n\nThe program is available for free under the open source MIT license."; labelDescription.Text = Program.BrandName+" was created by chylex as a replacement to the discontinued official TweetDeck client for Windows.\n\nThe program is available for free under the open source MIT license.";
labelWebsite.Links.Add(new LinkLabel.Link(0, labelWebsite.Text.Length, Program.Website)); labelWebsite.Links.Add(new LinkLabel.Link(0, labelWebsite.Text.Length, Program.Website));
labelSourceCode.Links.Add(new LinkLabel.Link(0, labelSourceCode.Text.Length, GitHubLink)); labelTips.Links.Add(new LinkLabel.Link(0, labelTips.Text.Length, TipsLink));
labelIssues.Links.Add(new LinkLabel.Link(0, labelIssues.Text.Length, IssuesLink)); labelIssues.Links.Add(new LinkLabel.Link(0, labelIssues.Text.Length, IssuesLink));
} }

View File

@@ -34,6 +34,10 @@ namespace TweetDck.Core.Other{
icon = SystemIcons.Error; icon = SystemIcons.Error;
break; break;
case MessageBoxIcon.Question:
icon = SystemIcons.Question;
break;
default: default:
icon = null; icon = null;
labelMessage.Location = new Point(labelMessage.Location.X-32, labelMessage.Location.Y); labelMessage.Location = new Point(labelMessage.Location.X-32, labelMessage.Location.Y);

View File

@@ -1,5 +1,4 @@
using System.Diagnostics; using System.Windows.Forms;
using System.Windows.Forms;
using TweetDck.Configuration; using TweetDck.Configuration;
namespace TweetDck.Core.Other.Settings{ namespace TweetDck.Core.Other.Settings{
@@ -18,8 +17,7 @@ namespace TweetDck.Core.Other.Settings{
protected static void PromptRestart(){ protected static void PromptRestart(){
if (MessageBox.Show("The application must restart for the setting to take place. Do you want to restart now?", Program.BrandName+" Settings", MessageBoxButtons.YesNo, MessageBoxIcon.Information) == DialogResult.Yes){ if (MessageBox.Show("The application must restart for the setting to take place. Do you want to restart now?", Program.BrandName+" Settings", MessageBoxButtons.YesNo, MessageBoxIcon.Information) == DialogResult.Yes){
Process.Start(Application.ExecutablePath, "-restart"); Program.Restart();
Application.Exit();
} }
} }
} }

View File

@@ -48,14 +48,14 @@
this.textBoxBrowserCSS.Multiline = true; this.textBoxBrowserCSS.Multiline = true;
this.textBoxBrowserCSS.Name = "textBoxBrowserCSS"; this.textBoxBrowserCSS.Name = "textBoxBrowserCSS";
this.textBoxBrowserCSS.ScrollBars = System.Windows.Forms.ScrollBars.Both; this.textBoxBrowserCSS.ScrollBars = System.Windows.Forms.ScrollBars.Both;
this.textBoxBrowserCSS.Size = new System.Drawing.Size(226, 193); this.textBoxBrowserCSS.Size = new System.Drawing.Size(373, 253);
this.textBoxBrowserCSS.TabIndex = 0; this.textBoxBrowserCSS.TabIndex = 0;
this.textBoxBrowserCSS.WordWrap = false; this.textBoxBrowserCSS.WordWrap = false;
// //
// 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(354, 227); this.btnCancel.Location = new System.Drawing.Point(654, 287);
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);
@@ -67,7 +67,7 @@
// btnApply // btnApply
// //
this.btnApply.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right))); this.btnApply.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right)));
this.btnApply.Location = new System.Drawing.Point(416, 227); this.btnApply.Location = new System.Drawing.Point(716, 287);
this.btnApply.Name = "btnApply"; this.btnApply.Name = "btnApply";
this.btnApply.Padding = new System.Windows.Forms.Padding(3, 0, 3, 0); this.btnApply.Padding = new System.Windows.Forms.Padding(3, 0, 3, 0);
this.btnApply.Size = new System.Drawing.Size(56, 23); this.btnApply.Size = new System.Drawing.Size(56, 23);
@@ -95,8 +95,8 @@
this.splitContainer.Panel2.Controls.Add(this.labelNotification); this.splitContainer.Panel2.Controls.Add(this.labelNotification);
this.splitContainer.Panel2.Controls.Add(this.textBoxNotificationCSS); this.splitContainer.Panel2.Controls.Add(this.textBoxNotificationCSS);
this.splitContainer.Panel2MinSize = 64; this.splitContainer.Panel2MinSize = 64;
this.splitContainer.Size = new System.Drawing.Size(460, 209); this.splitContainer.Size = new System.Drawing.Size(760, 269);
this.splitContainer.SplitterDistance = 226; this.splitContainer.SplitterDistance = 373;
this.splitContainer.SplitterWidth = 5; this.splitContainer.SplitterWidth = 5;
this.splitContainer.TabIndex = 5; this.splitContainer.TabIndex = 5;
// //
@@ -131,7 +131,7 @@
this.textBoxNotificationCSS.Multiline = true; this.textBoxNotificationCSS.Multiline = true;
this.textBoxNotificationCSS.Name = "textBoxNotificationCSS"; this.textBoxNotificationCSS.Name = "textBoxNotificationCSS";
this.textBoxNotificationCSS.ScrollBars = System.Windows.Forms.ScrollBars.Both; this.textBoxNotificationCSS.ScrollBars = System.Windows.Forms.ScrollBars.Both;
this.textBoxNotificationCSS.Size = new System.Drawing.Size(226, 193); this.textBoxNotificationCSS.Size = new System.Drawing.Size(378, 253);
this.textBoxNotificationCSS.TabIndex = 1; this.textBoxNotificationCSS.TabIndex = 1;
this.textBoxNotificationCSS.WordWrap = false; this.textBoxNotificationCSS.WordWrap = false;
// //
@@ -139,7 +139,7 @@
// //
this.labelWarning.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left))); this.labelWarning.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left)));
this.labelWarning.AutoSize = true; this.labelWarning.AutoSize = true;
this.labelWarning.Location = new System.Drawing.Point(9, 232); this.labelWarning.Location = new System.Drawing.Point(9, 292);
this.labelWarning.Name = "labelWarning"; this.labelWarning.Name = "labelWarning";
this.labelWarning.Size = new System.Drawing.Size(341, 13); this.labelWarning.Size = new System.Drawing.Size(341, 13);
this.labelWarning.TabIndex = 6; this.labelWarning.TabIndex = 6;
@@ -149,7 +149,7 @@
// //
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(484, 262); this.ClientSize = new System.Drawing.Size(784, 322);
this.Controls.Add(this.labelWarning); this.Controls.Add(this.labelWarning);
this.Controls.Add(this.splitContainer); this.Controls.Add(this.splitContainer);
this.Controls.Add(this.btnApply); this.Controls.Add(this.btnApply);

View File

@@ -1,5 +1,6 @@
using System; using System;
using System.Windows.Forms; using System.Windows.Forms;
using TweetDck.Core.Controls;
namespace TweetDck.Core.Other.Settings.Dialogs{ namespace TweetDck.Core.Other.Settings.Dialogs{
sealed partial class DialogSettingsCSS : Form{ sealed partial class DialogSettingsCSS : Form{
@@ -20,7 +21,10 @@ namespace TweetDck.Core.Other.Settings.Dialogs{
Text = Program.BrandName+" Settings - CSS"; Text = Program.BrandName+" Settings - CSS";
textBoxBrowserCSS.EnableMultilineShortcuts();
textBoxBrowserCSS.Text = Program.UserConfig.CustomBrowserCSS ?? ""; textBoxBrowserCSS.Text = Program.UserConfig.CustomBrowserCSS ?? "";
textBoxNotificationCSS.EnableMultilineShortcuts();
textBoxNotificationCSS.Text = Program.UserConfig.CustomNotificationCSS ?? ""; textBoxNotificationCSS.Text = Program.UserConfig.CustomNotificationCSS ?? "";
} }

View File

@@ -1,6 +1,6 @@
using System; using System;
using System.Collections.Generic;
using System.Windows.Forms; using System.Windows.Forms;
using TweetDck.Core.Controls;
using TweetDck.Core.Utils; using TweetDck.Core.Utils;
namespace TweetDck.Core.Other.Settings.Dialogs{ namespace TweetDck.Core.Other.Settings.Dialogs{
@@ -16,6 +16,7 @@ namespace TweetDck.Core.Other.Settings.Dialogs{
Text = Program.BrandName+" Settings - CEF Arguments"; Text = Program.BrandName+" Settings - CEF Arguments";
textBoxArgs.EnableMultilineShortcuts();
textBoxArgs.Text = Program.UserConfig.CustomCefArgs ?? ""; textBoxArgs.Text = Program.UserConfig.CustomCefArgs ?? "";
textBoxArgs.Select(textBoxArgs.Text.Length, 0); textBoxArgs.Select(textBoxArgs.Text.Length, 0);
} }
@@ -33,7 +34,7 @@ namespace TweetDck.Core.Other.Settings.Dialogs{
return; return;
} }
int count = CommandLineArgsParser.AddToDictionary(CefArgs, new Dictionary<string, string>()); int count = CommandLineArgsParser.ReadCefArguments(CefArgs).Count;
string prompt = count == 0 && !string.IsNullOrWhiteSpace(prevArgs) ? "All arguments will be removed from the settings. Continue?" : count+(count == 1 ? " argument" : " arguments")+" will be added to the settings. Continue?"; string prompt = count == 0 && !string.IsNullOrWhiteSpace(prevArgs) ? "All arguments will be removed from the settings. Continue?" : count+(count == 1 ? " argument" : " arguments")+" will be added to the settings. Continue?";
if (MessageBox.Show(prompt, "Confirm CEF Arguments", MessageBoxButtons.OKCancel, MessageBoxIcon.Question, MessageBoxDefaultButton.Button2) == DialogResult.OK){ if (MessageBox.Show(prompt, "Confirm CEF Arguments", MessageBoxButtons.OKCancel, MessageBoxIcon.Question, MessageBoxDefaultButton.Button2) == DialogResult.OK){

View File

@@ -1,6 +1,5 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Diagnostics;
using System.IO; using System.IO;
using System.Linq; using System.Linq;
using System.Windows.Forms; using System.Windows.Forms;
@@ -105,8 +104,7 @@ namespace TweetDck.Core.Other.Settings.Export{
// okay to and restart, 'cookies' is always the last entry // okay to and restart, 'cookies' is always the last entry
IsRestarting = true; IsRestarting = true;
Process.Start(Application.ExecutablePath, "-restart -importcookies"); Program.Restart(new string[]{ "-importcookies" });
Application.Exit();
} }
break; break;

View File

@@ -29,13 +29,18 @@
this.toolTip = new System.Windows.Forms.ToolTip(this.components); this.toolTip = new System.Windows.Forms.ToolTip(this.components);
this.btnEditCefArgs = new System.Windows.Forms.Button(); this.btnEditCefArgs = new System.Windows.Forms.Button();
this.btnEditCSS = new System.Windows.Forms.Button(); this.btnEditCSS = new System.Windows.Forms.Button();
this.btnRestartLog = new System.Windows.Forms.Button();
this.btnRestart = new System.Windows.Forms.Button();
this.btnReset = new System.Windows.Forms.Button(); this.btnReset = new System.Windows.Forms.Button();
this.btnImport = new System.Windows.Forms.Button(); this.btnImport = new System.Windows.Forms.Button();
this.btnExport = new System.Windows.Forms.Button(); this.btnExport = new System.Windows.Forms.Button();
this.groupPerformance = new System.Windows.Forms.GroupBox(); this.groupPerformance = new System.Windows.Forms.GroupBox();
this.groupConfiguration = new System.Windows.Forms.GroupBox(); this.groupConfiguration = new System.Windows.Forms.GroupBox();
this.groupApp = new System.Windows.Forms.GroupBox();
this.btnOpenAppFolder = new System.Windows.Forms.Button();
this.groupPerformance.SuspendLayout(); this.groupPerformance.SuspendLayout();
this.groupConfiguration.SuspendLayout(); this.groupConfiguration.SuspendLayout();
this.groupApp.SuspendLayout();
this.SuspendLayout(); this.SuspendLayout();
// //
// btnClearCache // btnClearCache
@@ -86,6 +91,30 @@
this.btnEditCSS.UseVisualStyleBackColor = true; this.btnEditCSS.UseVisualStyleBackColor = true;
this.btnEditCSS.Click += new System.EventHandler(this.btnEditCSS_Click); this.btnEditCSS.Click += new System.EventHandler(this.btnEditCSS_Click);
// //
// btnRestartLog
//
this.btnRestartLog.Location = new System.Drawing.Point(6, 77);
this.btnRestartLog.Name = "btnRestartLog";
this.btnRestartLog.Size = new System.Drawing.Size(171, 23);
this.btnRestartLog.TabIndex = 18;
this.btnRestartLog.Text = "Restart with Logging";
this.toolTip.SetToolTip(this.btnRestartLog, "Restarts the program and enables logging\r\ninto a debug.txt file in the installati" +
"on folder.");
this.btnRestartLog.UseVisualStyleBackColor = true;
this.btnRestartLog.Click += new System.EventHandler(this.btnRestartLog_Click);
//
// btnRestart
//
this.btnRestart.Location = new System.Drawing.Point(6, 48);
this.btnRestart.Name = "btnRestart";
this.btnRestart.Size = new System.Drawing.Size(171, 23);
this.btnRestart.TabIndex = 17;
this.btnRestart.Text = "Restart the Program";
this.toolTip.SetToolTip(this.btnRestart, "Restarts the program using the same command\r\nline arguments that were used at lau" +
"nch.");
this.btnRestart.UseVisualStyleBackColor = true;
this.btnRestart.Click += new System.EventHandler(this.btnRestart_Click);
//
// btnReset // btnReset
// //
this.btnReset.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left))); this.btnReset.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left)));
@@ -148,10 +177,34 @@
this.groupConfiguration.TabStop = false; this.groupConfiguration.TabStop = false;
this.groupConfiguration.Text = "Configuration"; this.groupConfiguration.Text = "Configuration";
// //
// groupApp
//
this.groupApp.Controls.Add(this.btnOpenAppFolder);
this.groupApp.Controls.Add(this.btnRestartLog);
this.groupApp.Controls.Add(this.btnRestart);
this.groupApp.Location = new System.Drawing.Point(198, 9);
this.groupApp.Name = "groupApp";
this.groupApp.Size = new System.Drawing.Size(183, 106);
this.groupApp.TabIndex = 20;
this.groupApp.TabStop = false;
this.groupApp.Text = "App";
//
// btnOpenAppFolder
//
this.btnOpenAppFolder.Location = new System.Drawing.Point(6, 19);
this.btnOpenAppFolder.Name = "btnOpenAppFolder";
this.btnOpenAppFolder.Size = new System.Drawing.Size(171, 23);
this.btnOpenAppFolder.TabIndex = 16;
this.btnOpenAppFolder.Text = "Open Program Folder";
this.toolTip.SetToolTip(this.btnOpenAppFolder, "Opens the folder where the app is located.");
this.btnOpenAppFolder.UseVisualStyleBackColor = true;
this.btnOpenAppFolder.Click += new System.EventHandler(this.btnOpenAppFolder_Click);
//
// TabSettingsAdvanced // TabSettingsAdvanced
// //
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.Controls.Add(this.groupApp);
this.Controls.Add(this.groupConfiguration); this.Controls.Add(this.groupConfiguration);
this.Controls.Add(this.groupPerformance); this.Controls.Add(this.groupPerformance);
this.Controls.Add(this.btnReset); this.Controls.Add(this.btnReset);
@@ -162,6 +215,7 @@
this.groupPerformance.ResumeLayout(false); this.groupPerformance.ResumeLayout(false);
this.groupPerformance.PerformLayout(); this.groupPerformance.PerformLayout();
this.groupConfiguration.ResumeLayout(false); this.groupConfiguration.ResumeLayout(false);
this.groupApp.ResumeLayout(false);
this.ResumeLayout(false); this.ResumeLayout(false);
this.PerformLayout(); this.PerformLayout();
@@ -179,5 +233,9 @@
private System.Windows.Forms.GroupBox groupConfiguration; private System.Windows.Forms.GroupBox groupConfiguration;
private System.Windows.Forms.Button btnEditCefArgs; private System.Windows.Forms.Button btnEditCefArgs;
private System.Windows.Forms.Button btnEditCSS; private System.Windows.Forms.Button btnEditCSS;
private System.Windows.Forms.GroupBox groupApp;
private System.Windows.Forms.Button btnRestartLog;
private System.Windows.Forms.Button btnRestart;
private System.Windows.Forms.Button btnOpenAppFolder;
} }
} }

View File

@@ -1,4 +1,5 @@
using System; using System;
using System.Diagnostics;
using System.Windows.Forms; using System.Windows.Forms;
using TweetDck.Core.Controls; using TweetDck.Core.Controls;
using TweetDck.Core.Other.Settings.Dialogs; using TweetDck.Core.Other.Settings.Dialogs;
@@ -70,13 +71,16 @@ namespace TweetDck.Core.Other.Settings{
if (form.ShowDialog(ParentForm) == DialogResult.OK){ if (form.ShowDialog(ParentForm) == DialogResult.OK){
Config.CustomCefArgs = form.CefArgs; Config.CustomCefArgs = form.CefArgs;
form.Dispose();
PromptRestart(); PromptRestart();
} }
else{
form.Dispose();
}
} }
private void btnEditCSS_Click(object sender, EventArgs e){ private void btnEditCSS_Click(object sender, EventArgs e){
DialogSettingsCSS form = new DialogSettingsCSS(); using(DialogSettingsCSS form = new DialogSettingsCSS()){
if (form.ShowDialog(ParentForm) == DialogResult.OK){ if (form.ShowDialog(ParentForm) == DialogResult.OK){
bool hasChangedBrowser = form.BrowserCSS != Config.CustomBrowserCSS; bool hasChangedBrowser = form.BrowserCSS != Config.CustomBrowserCSS;
@@ -88,6 +92,7 @@ namespace TweetDck.Core.Other.Settings{
} }
} }
} }
}
private void btnExport_Click(object sender, EventArgs e){ private void btnExport_Click(object sender, EventArgs e){
DialogResult resultSaveCredentials = MessageBox.Show("Do you want to include your login session? This will not save your password into the file, but it will allow anyone with the file to login into TweetDeck as you.", "Export "+Program.BrandName+" Settings", MessageBoxButtons.YesNoCancel, MessageBoxIcon.Question, MessageBoxDefaultButton.Button3); DialogResult resultSaveCredentials = MessageBox.Show("Do you want to include your login session? This will not save your password into the file, but it will allow anyone with the file to login into TweetDeck as you.", "Export "+Program.BrandName+" Settings", MessageBoxButtons.YesNoCancel, MessageBoxIcon.Question, MessageBoxDefaultButton.Button3);
@@ -151,5 +156,17 @@ namespace TweetDck.Core.Other.Settings{
((FormSettings)ParentForm).ReloadUI(); ((FormSettings)ParentForm).ReloadUI();
} }
} }
private void btnOpenAppFolder_Click(object sender, EventArgs e){
using(Process.Start("explorer.exe", "\""+Program.ProgramPath+"\"")){}
}
private void btnRestart_Click(object sender, EventArgs e){
Program.Restart();
}
private void btnRestartLog_Click(object sender, EventArgs e){
Program.Restart(new string[]{ "-log" });
}
} }
} }

View File

@@ -0,0 +1,107 @@
using System.Collections.Generic;
using System.Text;
namespace TweetDck.Core.Utils{
class CommandLineArgs{
public static CommandLineArgs FromStringArray(char entryChar, string[] array){
CommandLineArgs args = new CommandLineArgs();
ReadStringArray(entryChar, array, args);
return args;
}
public static void ReadStringArray(char entryChar, string[] array, CommandLineArgs targetArgs){
for(int index = 0; index < array.Length; index++){
string entry = array[index];
if (entry.Length > 0 && entry[0] == entryChar){
if (index < array.Length-1){
string potentialValue = array[index+1];
if (potentialValue.Length > 0 && potentialValue[0] == entryChar){
targetArgs.AddFlag(entry);
}
else{
targetArgs.SetValue(entry, potentialValue);
++index;
}
}
else{
targetArgs.AddFlag(entry);
}
}
}
}
private readonly HashSet<string> flags = new HashSet<string>();
private readonly Dictionary<string, string> values = new Dictionary<string, string>();
public int Count{
get{
return flags.Count+values.Count;
}
}
public void AddFlag(string flag){
flags.Add(flag.ToLowerInvariant());
}
public bool HasFlag(string flag){
return flags.Contains(flag.ToLowerInvariant());
}
public void RemoveFlag(string flag){
flags.Remove(flag.ToLowerInvariant());
}
public void SetValue(string key, string value){
values[key.ToLowerInvariant()] = value;
}
public string GetValue(string key, string defaultValue){
string val;
return values.TryGetValue(key.ToLowerInvariant(), out val) ? val : defaultValue;
}
public void RemoveValue(string key){
values.Remove(key.ToLowerInvariant());
}
public CommandLineArgs Clone(){
CommandLineArgs copy = new CommandLineArgs();
foreach(string flag in flags){
copy.AddFlag(flag);
}
foreach(KeyValuePair<string, string> kvp in values){
copy.SetValue(kvp.Key, kvp.Value);
}
return copy;
}
public void ToDictionary(IDictionary<string, string> target){
foreach(string flag in flags){
target[flag] = "1";
}
foreach(KeyValuePair<string, string> kvp in values){
target[kvp.Key] = kvp.Value;
}
}
public override string ToString(){
StringBuilder build = new StringBuilder();
foreach(string flag in flags){
build.Append(flag).Append(' ');
}
foreach(KeyValuePair<string, string> kvp in values){
build.Append(kvp.Key).Append(" \"").Append(kvp.Value).Append("\" ");
}
return build.Remove(build.Length-1, 1).ToString();
}
}
}

View File

@@ -1,5 +1,4 @@
using System.Collections.Generic; using System.Text.RegularExpressions;
using System.Text.RegularExpressions;
namespace TweetDck.Core.Utils{ namespace TweetDck.Core.Utils{
static class CommandLineArgsParser{ static class CommandLineArgsParser{
@@ -7,18 +6,18 @@ namespace TweetDck.Core.Utils{
private static Regex SplitRegex{ private static Regex SplitRegex{
get{ get{
return splitRegex ?? (splitRegex = new Regex(@"([^=\s]+(?:=(?:""[^""]*?""|[^ ]*))?)", RegexOptions.Compiled)); return splitRegex ?? (splitRegex = new Regex(@"([^=\s]+(?:=(?:[^ ]*""[^""]*?""[^ ]*|[^ ]*))?)", RegexOptions.Compiled));
} }
} }
public static int AddToDictionary(string args, IDictionary<string, string> dictionary){ public static CommandLineArgs ReadCefArguments(string argumentString){
if (string.IsNullOrWhiteSpace(args)){ CommandLineArgs args = new CommandLineArgs();
return 0;
if (string.IsNullOrWhiteSpace(argumentString)){
return args;
} }
int count = 0; foreach(Match match in SplitRegex.Matches(argumentString)){
foreach(Match match in SplitRegex.Matches(args)){
string matchValue = match.Value; string matchValue = match.Value;
int indexEquals = matchValue.IndexOf('='); int indexEquals = matchValue.IndexOf('=');
@@ -34,12 +33,11 @@ namespace TweetDck.Core.Utils{
} }
if (key.Length != 0){ if (key.Length != 0){
dictionary[key] = value; args.SetValue(key, value);
++count;
} }
} }
return count; return args;
} }
} }
} }

View File

@@ -1,148 +0,0 @@
using TweetDck.Core.Controls;
namespace TweetDck.Migration {
partial class FormMigrationQuestion {
/// <summary>
/// Required designer variable.
/// </summary>
private System.ComponentModel.IContainer components = null;
/// <summary>
/// Clean up any resources being used.
/// </summary>
/// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
protected override void Dispose(bool disposing) {
if (disposing && (components != null)) {
components.Dispose();
}
base.Dispose(disposing);
}
#region Windows Form Designer generated code
/// <summary>
/// Required method for Designer support - do not modify
/// the contents of this method with the code editor.
/// </summary>
private void InitializeComponent() {
this.btnIgnore = new System.Windows.Forms.Button();
this.panelButtons = new System.Windows.Forms.FlowLayoutPanel();
this.btnAskLater = new System.Windows.Forms.Button();
this.btnMigrate = new System.Windows.Forms.Button();
this.btnMigrateUninstall = new System.Windows.Forms.Button();
this.labelQuestion = new System.Windows.Forms.Label();
this.panelButtons.SuspendLayout();
this.SuspendLayout();
//
// btnIgnore
//
this.btnIgnore.AutoSize = true;
this.btnIgnore.AutoSizeMode = System.Windows.Forms.AutoSizeMode.GrowAndShrink;
this.btnIgnore.Location = new System.Drawing.Point(391, 0);
this.btnIgnore.Margin = new System.Windows.Forms.Padding(3, 0, 3, 0);
this.btnIgnore.Name = "btnIgnore";
this.btnIgnore.Padding = new System.Windows.Forms.Padding(3, 0, 3, 0);
this.btnIgnore.Size = new System.Drawing.Size(53, 23);
this.btnIgnore.TabIndex = 1;
this.btnIgnore.Text = "Ignore";
this.btnIgnore.UseVisualStyleBackColor = true;
this.btnIgnore.Click += new System.EventHandler(this.btnIgnore_Click);
//
// panelButtons
//
this.panelButtons.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left)
| System.Windows.Forms.AnchorStyles.Right)));
this.panelButtons.Controls.Add(this.btnAskLater);
this.panelButtons.Controls.Add(this.btnIgnore);
this.panelButtons.Controls.Add(this.btnMigrate);
this.panelButtons.Controls.Add(this.btnMigrateUninstall);
this.panelButtons.FlowDirection = System.Windows.Forms.FlowDirection.RightToLeft;
this.panelButtons.Location = new System.Drawing.Point(12, 67);
this.panelButtons.Name = "panelButtons";
this.panelButtons.Size = new System.Drawing.Size(518, 23);
this.panelButtons.TabIndex = 0;
//
// btnAskLater
//
this.btnAskLater.AutoSize = true;
this.btnAskLater.AutoSizeMode = System.Windows.Forms.AutoSizeMode.GrowAndShrink;
this.btnAskLater.Location = new System.Drawing.Point(450, 0);
this.btnAskLater.Margin = new System.Windows.Forms.Padding(3, 0, 0, 0);
this.btnAskLater.Name = "btnAskLater";
this.btnAskLater.Padding = new System.Windows.Forms.Padding(3, 0, 3, 0);
this.btnAskLater.Size = new System.Drawing.Size(68, 23);
this.btnAskLater.TabIndex = 0;
this.btnAskLater.Text = "Ask Later";
this.btnAskLater.UseVisualStyleBackColor = true;
this.btnAskLater.Click += new System.EventHandler(this.btnAskLater_Click);
//
// btnMigrate
//
this.btnMigrate.AutoSize = true;
this.btnMigrate.AutoSizeMode = System.Windows.Forms.AutoSizeMode.GrowAndShrink;
this.btnMigrate.Location = new System.Drawing.Point(327, 0);
this.btnMigrate.Margin = new System.Windows.Forms.Padding(3, 0, 3, 0);
this.btnMigrate.Name = "btnMigrate";
this.btnMigrate.Padding = new System.Windows.Forms.Padding(3, 0, 3, 0);
this.btnMigrate.Size = new System.Drawing.Size(58, 23);
this.btnMigrate.TabIndex = 3;
this.btnMigrate.Text = "Migrate";
this.btnMigrate.UseVisualStyleBackColor = true;
this.btnMigrate.Click += new System.EventHandler(this.btnMigrate_Click);
//
// btnMigrateUninstall
//
this.btnMigrateUninstall.AutoSize = true;
this.btnMigrateUninstall.AutoSizeMode = System.Windows.Forms.AutoSizeMode.GrowAndShrink;
this.btnMigrateUninstall.Location = new System.Drawing.Point(223, 0);
this.btnMigrateUninstall.Margin = new System.Windows.Forms.Padding(0, 0, 3, 0);
this.btnMigrateUninstall.Name = "btnMigrateUninstall";
this.btnMigrateUninstall.Padding = new System.Windows.Forms.Padding(3, 0, 3, 0);
this.btnMigrateUninstall.Size = new System.Drawing.Size(98, 23);
this.btnMigrateUninstall.TabIndex = 4;
this.btnMigrateUninstall.Text = "Migrate && Purge";
this.btnMigrateUninstall.UseVisualStyleBackColor = true;
this.btnMigrateUninstall.Click += new System.EventHandler(this.btnMigrateUninstall_Click);
//
// labelQuestion
//
this.labelQuestion.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.labelQuestion.Font = new System.Drawing.Font("Microsoft Sans Serif", 9.75F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(238)));
this.labelQuestion.Location = new System.Drawing.Point(49, 9);
this.labelQuestion.Margin = new System.Windows.Forms.Padding(40, 3, 3, 3);
this.labelQuestion.Name = "labelQuestion";
this.labelQuestion.Size = new System.Drawing.Size(481, 52);
this.labelQuestion.TabIndex = 2;
//
// FormMigrationQuestion
//
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
this.ClientSize = new System.Drawing.Size(542, 102);
this.Controls.Add(this.labelQuestion);
this.Controls.Add(this.panelButtons);
this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedDialog;
this.MaximizeBox = false;
this.MinimizeBox = false;
this.Name = "FormMigrationQuestion";
this.ShowIcon = false;
this.StartPosition = System.Windows.Forms.FormStartPosition.CenterScreen;
this.Text = "TweetDeck Migration";
this.panelButtons.ResumeLayout(false);
this.panelButtons.PerformLayout();
this.ResumeLayout(false);
}
#endregion
private System.Windows.Forms.Button btnIgnore;
private System.Windows.Forms.FlowLayoutPanel panelButtons;
private System.Windows.Forms.Button btnMigrate;
private System.Windows.Forms.Label labelQuestion;
private System.Windows.Forms.Button btnAskLater;
private System.Windows.Forms.Button btnMigrateUninstall;
}
}

View File

@@ -1,42 +0,0 @@
using System;
using System.Drawing;
using System.Windows.Forms;
namespace TweetDck.Migration{
partial class FormMigrationQuestion : Form{
public MigrationDecision Decision { get; private set; }
public FormMigrationQuestion(){
InitializeComponent();
labelQuestion.Text = "Hey there, I found some TweetDeck data! Do you want to »Migrate« it and delete the old data folder, »Ignore« the request forever, or try "+Program.BrandName+" out first?\r\nYou may also »Migrate && Purge« which uninstalls TweetDeck too!";
}
protected override void OnPaint(PaintEventArgs e){
e.Graphics.DrawIcon(SystemIcons.Question, 10, 10);
base.OnPaint(e);
}
private void btnMigrateUninstall_Click(object sender, EventArgs e){
Close(MigrationDecision.MigratePurge);
}
private void btnMigrate_Click(object sender, EventArgs e){
Close(MigrationDecision.Migrate);
}
private void btnIgnore_Click(object sender, EventArgs e){
Close(MigrationDecision.Ignore);
}
private void btnAskLater_Click(object sender, EventArgs e){
Close(MigrationDecision.AskLater);
}
private void Close(MigrationDecision decision){
Decision = decision;
DialogResult = DialogResult.OK;
Close();
}
}
}

View File

@@ -6,7 +6,8 @@ using System.Threading;
using System.Threading.Tasks; using System.Threading.Tasks;
using System.Windows.Forms; using System.Windows.Forms;
using Microsoft.Win32; using Microsoft.Win32;
using TweetDck.Migration.Helpers; using TweetDck.Core.Other;
using System.Drawing;
namespace TweetDck.Migration{ namespace TweetDck.Migration{
static class MigrationManager{ static class MigrationManager{
@@ -32,8 +33,25 @@ namespace TweetDck.Migration{
if (!Program.UserConfig.IgnoreMigration && Directory.Exists(TweetDeckPath)){ if (!Program.UserConfig.IgnoreMigration && Directory.Exists(TweetDeckPath)){
MigrationDecision decision; MigrationDecision decision;
using(FormMigrationQuestion formQuestion = new FormMigrationQuestion()){ const string prompt = "Hey there, I found some TweetDeck data! Do you want to »Migrate« it and delete the old data folder, »Ignore« the prompt, or try "+Program.BrandName+" out first? You may also »Migrate && Purge« which uninstalls TweetDeck too!";
decision = formQuestion.ShowDialog() == DialogResult.OK ? formQuestion.Decision : MigrationDecision.AskLater;
using(FormMessage formQuestion = new FormMessage("TweetDeck Migration", prompt, MessageBoxIcon.Question)){
formQuestion.AddButton("Ask Later");
Button btnIgnore = formQuestion.AddButton("Ignore");
Button btnMigrate = formQuestion.AddButton("Migrate");
Button btnMigrateAndPurge = formQuestion.AddButton("Migrate && Purge");
btnMigrateAndPurge.Location = new Point(btnMigrateAndPurge.Location.X-18, btnMigrateAndPurge.Location.Y);
btnMigrateAndPurge.Width += 18;
if (formQuestion.ShowDialog() == DialogResult.OK){
decision = formQuestion.ClickedButton == btnMigrateAndPurge ? MigrationDecision.MigratePurge :
formQuestion.ClickedButton == btnMigrate ? MigrationDecision.Migrate :
formQuestion.ClickedButton == btnIgnore ? MigrationDecision.Ignore : MigrationDecision.AskLater;
}
else{
decision = MigrationDecision.AskLater;
}
} }
switch(decision){ switch(decision){
@@ -66,10 +84,10 @@ namespace TweetDck.Migration{
} }
} }
else if (!Program.UserConfig.IgnoreUninstallCheck){ else if (!Program.UserConfig.IgnoreUninstallCheck){
string guid = ProgramRegistrySearch.FindByDisplayName("TweetDeck"); string guid = MigrationUtils.FindProgramGuidByDisplayName("TweetDeck");
if (guid != null && MessageBox.Show("TweetDeck is still installed on your computer, do you want to uninstall it?", "Uninstall TweetDeck", MessageBoxButtons.YesNo, MessageBoxIcon.Question, MessageBoxDefaultButton.Button2) == DialogResult.Yes){ if (guid != null && MessageBox.Show("TweetDeck is still installed on your computer, do you want to uninstall it?", "Uninstall TweetDeck", MessageBoxButtons.YesNo, MessageBoxIcon.Question, MessageBoxDefaultButton.Button2) == DialogResult.Yes){
RunUninstaller(guid, 0); MigrationUtils.RunUninstaller(guid, 0);
CleanupTweetDeck(); CleanupTweetDeck();
} }
@@ -135,10 +153,10 @@ namespace TweetDck.Migration{
if (decision == MigrationDecision.MigratePurge){ if (decision == MigrationDecision.MigratePurge){
// uninstall in the background // uninstall in the background
string guid = ProgramRegistrySearch.FindByDisplayName("TweetDeck"); string guid = MigrationUtils.FindProgramGuidByDisplayName("TweetDeck");
if (guid != null){ if (guid != null){
RunUninstaller(guid, 5000); MigrationUtils.RunUninstaller(guid, 5000);
} }
// registry cleanup // registry cleanup
@@ -162,18 +180,6 @@ namespace TweetDck.Migration{
} }
} }
private static void RunUninstaller(string guid, int timeout){
Process uninstaller = Process.Start("msiexec.exe", "/x "+guid+" /quiet /qn");
if (uninstaller != null){
if (timeout > 0){
uninstaller.WaitForExit(timeout); // it appears that the process is restarted or something that triggers this, but it shouldn't be a problem
}
uninstaller.Close();
}
}
private static void CleanupTweetDeck(){ private static void CleanupTweetDeck(){
try{ try{
Registry.CurrentUser.DeleteSubKeyTree(@"Software\Twitter\TweetDeck", true); Registry.CurrentUser.DeleteSubKeyTree(@"Software\Twitter\TweetDeck", true);

View File

@@ -1,10 +1,23 @@
using System; using System;
using System.Diagnostics;
using System.Linq; using System.Linq;
using Microsoft.Win32; using Microsoft.Win32;
namespace TweetDck.Migration.Helpers{ namespace TweetDck.Migration{
static class ProgramRegistrySearch{ static class MigrationUtils{
public static string FindByDisplayName(string displayName){ public static void RunUninstaller(string guid, int timeout){
Process uninstaller = Process.Start("msiexec.exe", "/x "+guid+" /quiet /qn");
if (uninstaller != null){
if (timeout > 0){
uninstaller.WaitForExit(timeout); // it appears that the process is restarted or something that triggers this, but it shouldn't be a problem
}
uninstaller.Close();
}
}
public static string FindProgramGuidByDisplayName(string displayName){
Predicate<RegistryKey> predicate = key => displayName.Equals(key.GetValue("DisplayName") as string, StringComparison.OrdinalIgnoreCase); Predicate<RegistryKey> predicate = key => displayName.Equals(key.GetValue("DisplayName") as string, StringComparison.OrdinalIgnoreCase);
string guid; string guid;

View File

@@ -24,12 +24,6 @@ namespace TweetDck.Plugins{
} }
} }
public string FolderPath{
get{
return path;
}
}
public bool HasConfig{ public bool HasConfig{
get{ get{
return ConfigFile.Length > 0 && GetFullPathIfSafe(ConfigFile).Length > 0; return ConfigFile.Length > 0 && GetFullPathIfSafe(ConfigFile).Length > 0;

View File

@@ -40,7 +40,7 @@ namespace TweetDck.Plugins{
public string ReadFile(int token, string path, bool cache){ public string ReadFile(int token, string path, bool cache){
string fullPath = GetFullPathIfSafe(token, path); string fullPath = GetFullPathIfSafe(token, path);
if (fullPath == string.Empty){ if (fullPath.Length == 0){
throw new Exception("File path has to be relative to the plugin folder."); throw new Exception("File path has to be relative to the plugin folder.");
} }

View File

@@ -19,16 +19,17 @@ using System.Security.AccessControl;
namespace TweetDck{ namespace TweetDck{
static class Program{ static class Program{
public const string BrandName = "TweetDuck"; public const string BrandName = "TweetDuck";
public const string Website = "http://tweetduck.chylex.com"; public const string Website = "https://tweetduck.chylex.com";
public const string BrowserSubprocess = BrandName+".Browser.exe"; public const string BrowserSubprocess = BrandName+".Browser.exe";
public const string VersionTag = "1.3.3"; public const string VersionTag = "1.4.2";
public const string VersionFull = "1.3.3.0"; public const string VersionFull = "1.4.2.0";
public static readonly Version Version = new Version(VersionTag); public static readonly Version Version = new Version(VersionTag);
public static readonly bool IsPortable = File.Exists("makeportable"); public static readonly bool IsPortable = File.Exists("makeportable");
private static readonly CommandLineArgs Args = CommandLineArgs.FromStringArray('-', Environment.GetCommandLineArgs());
public static readonly string ProgramPath = AppDomain.CurrentDomain.BaseDirectory; public static readonly string ProgramPath = AppDomain.CurrentDomain.BaseDirectory;
public static readonly string StoragePath = IsPortable ? Path.Combine(ProgramPath, "portable", "storage") : GetDataStoragePath(); public static readonly string StoragePath = IsPortable ? Path.Combine(ProgramPath, "portable", "storage") : GetDataStoragePath();
@@ -70,9 +71,7 @@ namespace TweetDck{
} }
}; };
string[] programArguments = Environment.GetCommandLineArgs(); if (Args.HasFlag("-restart")){
if (programArguments.Contains("-restart")){
for(int attempt = 0; attempt < 41; attempt++){ for(int attempt = 0; attempt < 41; attempt++){
if (LockManager.Lock()){ if (LockManager.Lock()){
break; break;
@@ -109,7 +108,7 @@ namespace TweetDck{
} }
} }
if (programArguments.Contains("-importcookies")){ if (Args.HasFlag("-importcookies")){
ExportManager.ImportCookies(); ExportManager.ImportCookies();
} }
@@ -118,15 +117,20 @@ namespace TweetDck{
CefSettings settings = new CefSettings{ CefSettings settings = new CefSettings{
AcceptLanguageList = BrowserUtils.HeaderAcceptLanguage, AcceptLanguageList = BrowserUtils.HeaderAcceptLanguage,
UserAgent = BrowserUtils.HeaderUserAgent, UserAgent = BrowserUtils.HeaderUserAgent,
Locale = GetCmdArgumentValue("locale") ?? "en", Locale = Args.GetValue("-locale", "en"),
CachePath = StoragePath, CachePath = StoragePath,
BrowserSubprocessPath = File.Exists(BrowserSubprocess) ? BrowserSubprocess : "CefSharp.BrowserSubprocess.exe", BrowserSubprocessPath = File.Exists(BrowserSubprocess) ? BrowserSubprocess : "CefSharp.BrowserSubprocess.exe",
#if !DEBUG #if !DEBUG
LogSeverity = programArguments.Contains("-log") ? LogSeverity.Info : LogSeverity.Disable LogSeverity = Args.HasFlag("-log") ? LogSeverity.Info : LogSeverity.Disable
#endif #endif
}; };
CommandLineArgsParser.AddToDictionary(UserConfig.CustomCefArgs, settings.CefCommandLineArgs); CommandLineArgsParser.ReadCefArguments(UserConfig.CustomCefArgs).ToDictionary(settings.CefCommandLineArgs);
if (!HardwareAcceleration.IsEnabled){
settings.CefCommandLineArgs["disable-gpu"] = "1";
settings.CefCommandLineArgs["disable-gpu-vsync"] = "1";
}
Cef.Initialize(settings, false, new BrowserProcessHandler()); Cef.Initialize(settings, false, new BrowserProcessHandler());
@@ -154,18 +158,18 @@ namespace TweetDck{
} }
} }
private static string GetCmdArgumentValue(string search){
string[] args = Environment.GetCommandLineArgs();
int index = Array.FindIndex(args, arg => arg.Equals(search, StringComparison.OrdinalIgnoreCase));
return index >= 0 && index < args.Length-1 ? args[index+1] : null;
}
private static string GetDataStoragePath(){ private static string GetDataStoragePath(){
string custom = GetCmdArgumentValue("-datafolder"); string custom = Args.GetValue("-datafolder", null);
if (custom != null && (custom.Contains(Path.DirectorySeparatorChar) || custom.Contains(Path.AltDirectorySeparatorChar))){ if (custom != null && (custom.Contains(Path.DirectorySeparatorChar) || custom.Contains(Path.AltDirectorySeparatorChar))){
return custom; if (Path.GetInvalidPathChars().Any(custom.Contains)){
Reporter.HandleEarlyFailure("Data Folder Invalid", "The data folder contains invalid characters:\n"+custom);
}
else if (!Path.IsPathRooted(custom)){
Reporter.HandleEarlyFailure("Data Folder Invalid", "The data folder has to be either a simple folder name, or a full path:\n"+custom);
}
return Environment.ExpandEnvironmentVariables(custom);
} }
else{ else{
return Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData), custom ?? BrandName); return Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData), custom ?? BrandName);
@@ -188,6 +192,21 @@ namespace TweetDck{
ReloadConfig(); ReloadConfig();
} }
public static void Restart(){
Restart(new string[0]);
}
public static void Restart(string[] extraArgs){
CommandLineArgs args = Args.Clone();
args.AddFlag("-restart");
args.RemoveFlag("-importcookies");
CommandLineArgs.ReadStringArray('-', extraArgs, args);
Process.Start(Application.ExecutablePath, args.ToString());
Application.Exit();
}
private static void ExitCleanup(){ private static void ExitCleanup(){
if (HasCleanedUp)return; if (HasCleanedUp)return;

View File

@@ -70,5 +70,20 @@ namespace TweetDck{
Environment.FailFast(message, e); Environment.FailFast(message, e);
} }
} }
public static void HandleEarlyFailure(string caption, string message){
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
FormMessage form = new FormMessage(caption, message, MessageBoxIcon.Error);
form.AddButton("Exit");
form.ShowDialog();
try{
Process.GetCurrentProcess().Kill();
}catch{
Environment.FailFast(message, new Exception(message));
}
}
} }
} }

View File

@@ -3,12 +3,16 @@ Clear columns
[description] [description]
- Adds buttons and keyboard shortcuts to quickly clear columns - Adds buttons and keyboard shortcuts to quickly clear columns
- Hold Shift when clicking or using a keyboard shortcut to reset the column instead
[author] [author]
chylex chylex
[version] [version]
1.0 1.1
[website] [website]
https://tweetduck.chylex.com https://tweetduck.chylex.com
[requires]
1.4.1

View File

@@ -11,38 +11,75 @@ enabled(){
TD.controller.stats.columnActionClick("clear"); TD.controller.stats.columnActionClick("clear");
}; };
var clearAllColumns = () => { var resetColumn = (columnName) => {
Object.keys(TD.controller.columnManager.getAll()).forEach(key => clearColumn(key)); var col = TD.controller.columnManager.get(columnName);
col.model.setClearedTimestamp(0);
col.reloadTweets();
};
var forEachColumn = (func) => {
Object.keys(TD.controller.columnManager.getAll()).forEach(func);
}; };
var replaceMustache = (key, search, replace) => { var replaceMustache = (key, search, replace) => {
TD.mustaches[key] = TD.mustaches[key].replace(search, replace); TD.mustaches[key] = TD.mustaches[key].replace(search, replace);
}; };
var wasShiftPressed = false;
var updateShiftState = (pressed) => {
if (pressed != wasShiftPressed){
wasShiftPressed = pressed;
if (pressed){
$(document).on("mousemove", this.eventKeyUp);
}
else{
$(document).off("mousemove", this.eventKeyUp);
}
$("#clear-columns-btn-all").text(pressed ? "Reset all" : "Clear all");
}
};
// prepare event handlers // prepare event handlers
this.eventClearSingle = function(){ this.eventClickSingle = function(e){
clearColumn($(this).closest(".js-column").attr("data-column")); var name = $(this).closest(".js-column").attr("data-column");
e.shiftKey ? resetColumn(name) : clearColumn(name);
}; };
this.eventClearAll = function(){ this.eventClickAll = function(e){
clearAllColumns(); forEachColumn(e.shiftKey ? resetColumn : clearColumn);
}; };
this.eventKeys = function(e){ this.eventKeyDown = function(e){
if (e.keyCode === 46 && (document.activeElement === null || document.activeElement === document.body)){ // 46 = delete if (!(document.activeElement === null || document.activeElement === document.body)){
return;
}
updateShiftState(e.shiftKey);
if (e.keyCode === 46){ // 46 = delete
if (e.altKey){ if (e.altKey){
clearAllColumns(); forEachColumn(e.shiftKey ? resetColumn : clearColumn);
} }
else{ else{
var focusedColumn = $(".js-column.is-focused"); var focusedColumn = $(".js-column.is-focused");
if (focusedColumn.length){ if (focusedColumn.length){
clearColumn(focusedColumn.attr("data-column")); var name = focusedColumn.attr("data-column");
e.shiftKey ? resetColumn(name) : clearColumn(name);
} }
} }
} }
}; };
this.eventKeyUp = function(e){
if (!e.shiftKey){
updateShiftState(false);
}
};
// 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}}',
@@ -62,27 +99,26 @@ enabled(){
].join("")); ].join(""));
// load custom style // load custom style
var style = document.createElement("style"); var css = window.TDPF_createCustomStyle(this);
document.head.appendChild(style); css.insert(".column-title { margin-right: 60px !important; }");
css.insert(".column-type-message .column-title { margin-right: 115px !important; }");
var sheet = style.sheet; css.insert(".mark-all-read-link { right: 59px !important; }");
sheet.insertRule(".column-title { margin-right: 60px !important; }", 0); css.insert(".open-compose-dm-link { right: 90px !important; }");
sheet.insertRule(".column-type-message .column-title { margin-right: 115px !important; }", 0); css.insert("button[data-action='clear'].btn-options-tray { display: none !important; }");
sheet.insertRule(".mark-all-read-link { right: 59px !important; }", 0);
sheet.insertRule(".open-compose-dm-link { right: 90px !important; }", 0);
} }
ready(){ ready(){
// setup events // setup events
$(document).on("click", "[data-action='td-clearcolumns-dosingle']", this.eventClearSingle); $(document).on("click", "[data-action='td-clearcolumns-dosingle']", this.eventClickSingle);
$(document).on("click", "[data-action='td-clearcolumns-doall']", this.eventClearAll); $(document).on("click", "[data-action='td-clearcolumns-doall']", this.eventClickAll);
$(document).on("keydown", this.eventKeys); $(document).on("keydown", this.eventKeyDown);
$(document).on("keyup", this.eventKeyUp);
// add clear all button // add clear all button
$("nav.app-navigator").first().append([ $("nav.app-navigator").first().append([
'<a class="link-clean cf app-nav-link padding-hl" data-title="Clear all" data-action="td-clearcolumns-doall">', '<a class="link-clean cf app-nav-link padding-hl" data-title="Clear all" data-action="td-clearcolumns-doall">',
'<div class="obj-left"><i class="icon icon-large icon-clear-timeline"></i></div>', '<div class="obj-left"><i class="icon icon-large icon-clear-timeline"></i></div>',
'<div class="nbfc padding-ts hide-condensed">Clear all</div>', '<div id="clear-columns-btn-all" class="nbfc padding-ts hide-condensed">Clear all</div>',
'</a></nav>' '</a></nav>'
].join("")); ].join(""));
} }

View File

@@ -9,7 +9,10 @@ Revert TweetDeck design changes
chylex chylex
[version] [version]
1.0 1.1
[website] [website]
https://tweetduck.chylex.com https://tweetduck.chylex.com
[requires]
1.4.1

View File

@@ -1,15 +1,11 @@
enabled(){ enabled(){
// add a stylesheet to change tweet actions // add a stylesheet to change tweet actions
var style = document.createElement("style"); this.css = window.TDPF_createCustomStyle(this);
style.id = "design-revert"; this.css.insert(".tweet-actions { float: right !important; width: auto !important; }");
document.head.appendChild(style); this.css.insert(".tweet-action { opacity: 0; }");
this.css.insert(".is-favorite .tweet-action, .is-retweet .tweet-action { opacity: 0.5; visibility: visible !important; }");
var sheet = style.sheet; this.css.insert(".tweet:hover .tweet-action, .is-favorite .tweet-action[rel='favorite'], .is-retweet .tweet-action[rel='retweet'] { opacity: 1; visibility: visible !important; }");
sheet.insertRule(".tweet-actions { float: right !important; width: auto !important; }", 0); this.css.insert(".tweet-actions > li:nth-child(4) { margin-right: 2px !important; }");
sheet.insertRule(".tweet-action { opacity: 0; }", 0);
sheet.insertRule(".is-favorite .tweet-action, .is-retweet .tweet-action { opacity: 0.5; visibility: visible !important; }", 0);
sheet.insertRule(".tweet:hover .tweet-action, .is-favorite .tweet-action[rel='favorite'], .is-retweet .tweet-action[rel='retweet'] { opacity: 1; visibility: visible !important; }", 0);
sheet.insertRule(".tweet-actions > li:nth-child(4) { margin-right: 2px !important; }", 0);
// revert small links around the tweet // revert small links around the tweet
this.prevFooterMustache = TD.mustaches["status/tweet_single_footer.mustache"]; this.prevFooterMustache = TD.mustaches["status/tweet_single_footer.mustache"];
@@ -31,7 +27,8 @@ ready(){
} }
disabled(){ disabled(){
$("#design-revert").remove(); this.css.remove();
$(document).off("uiShowActionsMenu", this.uiShowActionsMenuEvent); $(document).off("uiShowActionsMenu", this.uiShowActionsMenuEvent);
TD.mustaches["status/tweet_single_footer.mustache"] = this.prevFooterMustache; TD.mustaches["status/tweet_single_footer.mustache"] = this.prevFooterMustache;
} }

View File

@@ -8,7 +8,7 @@ Custom reply account
chylex chylex
[version] [version]
1.0 1.1
[website] [website]
https://tweetduck.chylex.com https://tweetduck.chylex.com

View File

@@ -1,67 +1,120 @@
enabled(){ enabled(){
var configuration = { defaultAccount: "" }; var configuration = { defaultAccount: "#preferred" };
window.TDPF_loadConfigurationFile(this, "configuration.js", "configuration.default.js", obj => configuration = obj); window.TDPF_loadConfigurationFile(this, "configuration.js", "configuration.default.js", obj => configuration = obj);
this.uiInlineComposeTweetEvent = function(e, data){ this.lastSelectedAccount = null;
var account = null;
if (configuration.useAdvancedSelector && configuration.customSelector){ this.uiComposeTweetEvent = (e, data) => {
var column = TD.controller.columnManager.get(data.element.closest("section.column").attr("data-column")); if (data.type !== "reply" || data.popFromInline || !("element" in data)){
var result = configuration.customSelector(column);
if (typeof result === "string" && result[0] === '@'){
account = result.substring(1);
}
}
if (account === null){
if (configuration.defaultAccount === false){
return; return;
} }
else if (configuration.defaultAccount !== "" && configuration.defaultAccount[0] === '@'){
account = configuration.defaultAccount.substring(1);
}
}
var identifier; var query;
if (account === null){ if (configuration.useAdvancedSelector){
identifier = TD.storage.clientController.client.getDefaultAccount(); if (configuration.customSelector){
var column = TD.controller.columnManager.get(data.element.closest("section.column").attr("data-column"));
query = configuration.customSelector(column);
} }
else{ else{
var obj = TD.storage.accountController.getAccountFromUsername(account); $TD.alert("warning", "Plugin reply-account has invalid configuration: useAdvancedSelector is true, but customSelector function is missing");
return;
}
}
else{
query = configuration.defaultAccount;
if (query === ""){
query = "#preferred";
}
else if (typeof query !== "string"){
query = "#default";
}
}
if (typeof query === "undefined"){
query = "#preferred";
}
if (typeof query !== "string"){
return;
}
else if (query.length === 0){
$TD.alert("warning", "Plugin reply-account has invalid configuration: the requested account is empty");
return;
}
else if (query[0] !== '@' && query[0] !== '#'){
$TD.alert("warning", "Plugin reply-account has invalid configuration: the requested account does not begin with @ or #: "+query);
return;
}
var identifier = null;
switch(query){
case "#preferred":
identifier = TD.storage.clientController.client.getDefaultAccount();
break;
case "#last":
if (this.lastSelectedAccount === null){
return;
}
identifier = this.lastSelectedAccount;
break;
case "#default":
return;
default:
if (query[0] === '@'){
var obj = TD.storage.accountController.getAccountFromUsername(query.substring(1));
if (obj.length === 0){ if (obj.length === 0){
$TD.alert("warning", "Plugin reply-account has invalid configuration: requested account not found: "+query);
return; return;
} }
else{ else{
identifier = obj[0].privateState.key; identifier = obj[0].privateState.key;
} }
} }
else{
$TD.alert("warning", "Plugin reply-account has invalid configuration: unknown requested account query: "+query);
return;
}
}
data.singleFrom = data.from = [ identifier ]; data.singleFrom = data.from = [ identifier ];
}; };
this.onSelectedAccountChanged = () => {
var selected = $(".js-account-item.is-selected", ".js-account-list");
this.lastSelectedAccount = selected.length === 1 ? selected.attr("data-account-key") : null;
};
} }
ready(){ ready(){
var events = $._data(document, "events"); var events = $._data(document, "events");
if ("uiInlineComposeTweet" in events){ for(var event of [ "uiInlineComposeTweet", "uiDockedComposeTweet" ]){
$(document).on("uiInlineComposeTweet", this.uiInlineComposeTweetEvent); $(document).on(event, this.uiComposeTweetEvent);
var handlers = events["uiInlineComposeTweet"]; var handlers = events[event];
var oldHandler = handlers[0]; var newHandler = handlers[handlers.length-1];
var newHandler = handlers[1];
for(var index = handlers.length-1; index > 0; index--){
handlers[index] = handlers[index-1];
}
handlers[0] = newHandler; handlers[0] = newHandler;
handlers[1] = oldHandler;
}
else{
$(document).on("uiInlineComposeTweet", this.uiInlineComposeTweetEvent);
} }
$(document).on("click", ".js-account-list .js-account-item", this.onSelectedAccountChanged);
} }
disabled(){ disabled(){
$(document).off("uiInlineComposeTweet", this.uiInlineComposeTweetEvent); $(document).off("uiInlineComposeTweet", this.uiComposeTweetEvent);
$(document).off("uiDockedComposeTweet", this.uiComposeTweetEvent);
$(document).off("click", ".js-account-list .js-account-item", this.onSelectedAccountChanged);
} }

View File

@@ -13,13 +13,14 @@
* *
* Set value of 'defaultAccount' to one of the following values: * Set value of 'defaultAccount' to one of the following values:
* *
* "" to use your preferred TweetDeck account for all replies (default) * "#preferred" to use your preferred TweetDeck account (the one used to log into TweetDeck)
* "#last" to specify the account that was selected last time (only updates if a single account is selected)
* "#default" to fall back to default TweetDeck behavior; useful for advanced configuration below, otherwise disable the plugin instead
* "@myAccount" to specify an account name to use; has to be one of your registered account names * "@myAccount" to specify an account name to use; has to be one of your registered account names
* false to fall back to default TweetDeck behavior; useful for advanced configuration below, otherwise disable the plugin instead
* *
*/ */
defaultAccount: "", defaultAccount: "#preferred",
/* /*
* Advanced way of configuring the plugin * Advanced way of configuring the plugin
@@ -30,8 +31,8 @@
* 1. Set value of 'useAdvancedSelector' to true * 1. Set value of 'useAdvancedSelector' to true
* 2. Uncomment the 'customSelector' function, and replace the example code with your desired behavior * 2. Uncomment the 'customSelector' function, and replace the example code with your desired behavior
* *
* If 'customSelector' returns a string containing a full name of one of the registered accounts (including @), that account is used. * The 'customSelector' function should return a string in one of the formats supported by 'defaultAccount'.
* If it returns anything else (for example false, undefined, or an account name that is not registered), it falls back to 'defaultAccount' behavior. * If it returns anything else (for example, false or undefined), it falls back to 'defaultAccount' behavior.
* *
* The 'column' parameter is a TweetDeck column object. If you want to see all properties of the object, open your browser, nagivate to TweetDeck, * The 'column' parameter is a TweetDeck column object. If you want to see all properties of the object, open your browser, nagivate to TweetDeck,
* log in, and run the following code in your browser console, which will return an object containing all of the column objects mapped to their IDs: * log in, and run the following code in your browser console, which will return an object containing all of the column objects mapped to their IDs:

View File

@@ -0,0 +1,18 @@
[name]
Polls in timelines
[description]
- Adds poll result display directly into timelines
- Experimental, may be buggy or break when TweetDeck updates
[author]
chylex
[version]
1.0
[website]
https://tweetduck.chylex.com
[requires]
1.4.1

View File

@@ -0,0 +1,25 @@
constructor(){
super({
requiresPageReload: true
});
}
enabled(){
// add a stylesheet
window.TDPF_createCustomStyle(this).insert(".column-detail .timeline-poll-container { display: none }");
// setup layout injecting
var injectLayout = (mustache, onlyIfNotFound, search, replace) => {
if (TD.mustaches[mustache].indexOf(onlyIfNotFound) === -1){
TD.mustaches[mustache] = TD.mustaches[mustache].replace(search, replace);
}
};
// add poll rendering to tweets
injectLayout("status/tweet_single.mustache", "status/poll", "{{/quotedTweetMissing}} {{#translation}}", "{{/quotedTweetMissing}} <div class='timeline-poll-container'>{{>duck/tweet_single/poll}}</div> {{#translation}}");
TD.mustaches["duck/tweet_single/poll.mustache"] = '<div class="js-poll margin-tl"> {{#poll}} <ul class="margin-b--12"> {{#choices}} <li class="position-rel margin-b--8 height-3"> <div class="poll-bar pin-top height-p--100 br-1 {{#isWinner}}poll-bar--winner{{/isWinner}} {{#hasTimeLeft}}br-left{{/hasTimeLeft}} width-p--{{percentage}}"/> <div class="poll-label position-rel padding-a--4"> <span class="txt-bold txt-right inline-block width-5 padding-r--4">{{percentage}}%</span> {{{label}}} {{#isSelectedChoice}} <i class="icon icon-check txt-size-variable--11"></i> {{/isSelectedChoice}} </div> </li> {{/choices}} </ul> <span class="inline-block txt-small padding-ls txt-seamful-deep-gray"> {{{prettyCount}}} &middot; {{#hasTimeLeft}} {{{prettyTimeLeft}}} {{/hasTimeLeft}} {{^hasTimeLeft}} {{_i}}Final results{{/i}} {{/hasTimeLeft}} </span> {{/poll}} </div>';
}
disabled(){
// not needed, plugin reloads the page when enabled or disabled
}

View File

@@ -104,11 +104,14 @@
var html = $(tweet.render({ var html = $(tweet.render({
withFooter: false, withFooter: false,
withTweetActions: false, withTweetActions: false,
withMediaPreview: false withMediaPreview: true,
isMediaPreviewOff: true,
isMediaPreviewSmall: false,
isMediaPreviewLarge: false
})); }));
html.css("border", "0"); html.css("border", "0");
html.find(".tweet-body").first().children("footer").remove(); html.find("footer").last().remove(); // apparently withTweetActions breaks for certain tweets, nice
var url = html.find("time").first().children("a").first().attr("href") || ""; var url = html.find("time").first().children("a").first().attr("href") || "";
@@ -376,26 +379,39 @@
// //
// Block: Support for extra mouse buttons. // Block: Support for extra mouse buttons.
// //
(function(){
var tryClickSelector = function(selector, parent){
return $(selector, parent).click().length;
};
var tryCloseModal = function(){
var modal = $("#open-modal");
return modal.is(":visible") && tryClickSelector("a[rel=dismiss]", modal);
};
var tryCloseHighlightedColumn = function(){
if (highlightedColumnEle){
var column = highlightedColumnEle.closest(".js-column");
return (column.is(".is-shifted-2") && tryClickSelector(".js-tweet-social-proof-back", column)) || (column.is(".is-shifted-1") && tryClickSelector(".js-column-back", column));
}
};
window.TDGF_onMouseClickExtra = function(button){ window.TDGF_onMouseClickExtra = function(button){
if (button === 1){ // back button if (button === 1){ // back button
var modal = $("#open-modal"); tryCloseModal() ||
tryClickSelector(".js-inline-compose-close") ||
if (highlightedColumnEle && highlightedColumnEle.closest(".js-column").is(".is-shifted-1")){ tryCloseHighlightedColumn() ||
highlightedColumnEle.find(".js-column-back").first().click(); tryClickSelector(".js-app-content.is-open .js-drawer-close:visible") ||
} tryClickSelector(".is-shifted-2 .js-tweet-social-proof-back") ||
else if (modal.is(":visible")){
modal.find("a[rel=dismiss]").click();
}
else{
$(".js-column-back").click(); $(".js-column-back").click();
} }
}
else if (button === 2){ // forward button else if (button === 2){ // forward button
if (highlightedTweetEle){ if (highlightedTweetEle){
highlightedTweetEle.children().first().click(); highlightedTweetEle.children().first().click();
} }
} }
}; };
})();
// //
// Block: Fix scheduled tweets not showing up sometimes. // Block: Fix scheduled tweets not showing up sometimes.

View File

@@ -117,6 +117,36 @@
$TD.setNotificationTweetEmbedded(account[0].getAttribute("href")+"/status/"+tweetId); $TD.setNotificationTweetEmbedded(account[0].getAttribute("href")+"/status/"+tweetId);
})(); })();
//
// Block: Setup a skip button.
//
(function(){
if (document.body.hasAttribute("td-example-notification")){
return;
}
document.body.insertAdjacentHTML("afterbegin", [
'<svg id="td-skip" xmlns="http://www.w3.org/2000/svg" width="10" height="17" viewBox="0 0 350 600" style="position:fixed;left:30px;bottom:10px;z-index:1000">',
'<path fill="#888" d="M0,151.656l102.208-102.22l247.777,247.775L102.208,544.986L0,442.758l145.546-145.547">',
'</svg>'
].join(""));
document.getElementById("td-skip").addEventListener("click", function(){
$TD.loadNextNotification();
});
})();
//
// Block: Setup a hover class on body.
//
document.body.addEventListener("mouseenter", function(){
document.body.classList.add("td-hover");
});
document.body.addEventListener("mouseleave", function(){
document.body.classList.remove("td-hover");
});
// //
// Block: Page fully loaded. // Block: Page fully loaded.
// //

View File

@@ -15,7 +15,7 @@
try{ try{
obj = eval("("+contents+")"); obj = eval("("+contents+")");
}catch(err){ }catch(err){
if (!(onFailure && onFailure(err.message))){ if (!(onFailure && onFailure(err))){
$TD.alert("warning", "Problem loading '"+fileName+"' file for '"+identifier+"' plugin, the JavaScript syntax is invalid: "+err.message); $TD.alert("warning", "Problem loading '"+fileName+"' file for '"+identifier+"' plugin, the JavaScript syntax is invalid: "+err.message);
} }
@@ -34,4 +34,21 @@
} }
}); });
}; };
//
// Block: Setup a function to add/remove custom CSS.
//
window.TDPF_createCustomStyle = function(pluginObject){
var element = document.createElement("style");
element.id = "plugin-"+pluginObject.$id+"-"+Math.random().toString(36).substring(2, 7);
document.head.appendChild(element);
var obj = {
insert: (rule) => element.sheet.insertRule(rule, 0),
remove: () => $(element).remove()
};
obj.element = element;
return obj;
};
})($TDP); })($TDP);

View File

@@ -19,7 +19,6 @@
// //
var createUpdateNotificationElement = function(version, download){ var createUpdateNotificationElement = function(version, download){
var outdated = version === "unsupported"; var outdated = version === "unsupported";
var tweetdick = version === "tweetdick";
var ele = $("#tweetdck-update"); var ele = $("#tweetdck-update");
var existed = ele.length > 0; var existed = ele.length > 0;
@@ -37,15 +36,6 @@
"<button class='btn btn-negative tdu-btn-dismiss'><span class='label'>Dismiss</span></button>", "<button class='btn btn-negative tdu-btn-dismiss'><span class='label'>Dismiss</span></button>",
"</div>", "</div>",
"</div>" "</div>"
] : tweetdick ? [
"<div id='tweetdck-update'>",
"<p class='tdu-title'>TweetDick Ending</p>",
"<p class='tdu-info'>Please, move to TweetDuck.</p>",
"<div class='tdu-buttons'>",
"<button class='btn btn-positive tdu-btn-unsupported'><span class='label'>Read More</span></button>",
"<button class='btn btn-negative tdu-btn-dismiss'><span class='label'>Dismiss</span></button>",
"</div>",
"</div>"
] : [ ] : [
"<div id='tweetdck-update'>", "<div id='tweetdck-update'>",
"<p class='tdu-title'>"+$TDU.brandName+" Update</p>", "<p class='tdu-title'>"+$TDU.brandName+" Update</p>",
@@ -118,10 +108,6 @@
$TDU.openBrowser("https://github.com/chylex/TweetDuck/wiki/Supported-Systems"); $TDU.openBrowser("https://github.com/chylex/TweetDuck/wiki/Supported-Systems");
}); });
buttonDiv.children(".tdu-btn-tweetdick").click(function(){
$TDU.openBrowser("https://github.com/chylex/TweetDick/wiki/Future-of-TweetDick");
});
buttonDiv.children(".tdu-btn-dismiss,.tdu-btn-unsupported").click(function(){ buttonDiv.children(".tdu-btn-dismiss,.tdu-btn-unsupported").click(function(){
$TDU.onUpdateDismissed(version); $TDU.onUpdateDismissed(version);
ele.slideUp(function(){ ele.remove(); }); ele.slideUp(function(){ ele.remove(); });
@@ -145,13 +131,6 @@
return; return;
} }
else if ($TDU.brandName === "TweetDick"){
if ($TDU.dismissedVersionTag !== "tweetdick"){
createUpdateNotificationElement("tweetdick");
}
return;
}
clearTimeout(updateCheckTimeoutID); clearTimeout(updateCheckTimeoutID);
updateCheckTimeoutID = setTimeout(runUpdateCheck, 1000*60*60); // 1 hour updateCheckTimeoutID = setTimeout(runUpdateCheck, 1000*60*60); // 1 hour

View File

@@ -176,6 +176,7 @@
<Compile Include="Core\Other\Settings\TabSettingsUpdates.Designer.cs"> <Compile Include="Core\Other\Settings\TabSettingsUpdates.Designer.cs">
<DependentUpon>TabSettingsUpdates.cs</DependentUpon> <DependentUpon>TabSettingsUpdates.cs</DependentUpon>
</Compile> </Compile>
<Compile Include="Core\Utils\CommandLineArgs.cs" />
<Compile Include="Core\Utils\CommandLineArgsParser.cs" /> <Compile Include="Core\Utils\CommandLineArgsParser.cs" />
<Compile Include="Core\Utils\WindowState.cs" /> <Compile Include="Core\Utils\WindowState.cs" />
<Compile Include="Core\Utils\WindowsUtils.cs" /> <Compile Include="Core\Utils\WindowsUtils.cs" />
@@ -192,6 +193,7 @@
<Compile Include="Core\Other\FormSettings.Designer.cs"> <Compile Include="Core\Other\FormSettings.Designer.cs">
<DependentUpon>FormSettings.cs</DependentUpon> <DependentUpon>FormSettings.cs</DependentUpon>
</Compile> </Compile>
<Compile Include="Migration\MigrationUtils.cs" />
<Compile Include="Plugins\Controls\PluginControl.cs"> <Compile Include="Plugins\Controls\PluginControl.cs">
<SubType>UserControl</SubType> <SubType>UserControl</SubType>
</Compile> </Compile>
@@ -234,15 +236,8 @@
<Compile Include="Updates\UpdateCheckEventArgs.cs" /> <Compile Include="Updates\UpdateCheckEventArgs.cs" />
<Compile Include="Updates\UpdateHandler.cs" /> <Compile Include="Updates\UpdateHandler.cs" />
<Compile Include="Updates\UpdateInfo.cs" /> <Compile Include="Updates\UpdateInfo.cs" />
<Compile Include="Migration\FormMigrationQuestion.cs">
<SubType>Form</SubType>
</Compile>
<Compile Include="Migration\FormMigrationQuestion.Designer.cs">
<DependentUpon>FormMigrationQuestion.cs</DependentUpon>
</Compile>
<Compile Include="Migration\MigrationDecision.cs" /> <Compile Include="Migration\MigrationDecision.cs" />
<Compile Include="Migration\MigrationManager.cs" /> <Compile Include="Migration\MigrationManager.cs" />
<Compile Include="Migration\Helpers\ProgramRegistrySearch.cs" />
<Compile Include="Program.cs" /> <Compile Include="Program.cs" />
<Compile Include="Properties\AssemblyInfo.cs" /> <Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="Properties\Resources.Designer.cs"> <Compile Include="Properties\Resources.Designer.cs">

View File

@@ -1,5 +1,6 @@
del "bin\x86\Release\*.xml" del "bin\x86\Release\*.xml"
del "bin\x86\Release\devtools_resources.pak" del "bin\x86\Release\devtools_resources.pak"
del "bin\x86\Release\d3dcompiler_43.dll"
del "bin\x86\Release\TweetDuck.Browser.exe" del "bin\x86\Release\TweetDuck.Browser.exe"
ren "bin\x86\Release\CefSharp.BrowserSubprocess.exe" "TweetDuck.Browser.exe" ren "bin\x86\Release\CefSharp.BrowserSubprocess.exe" "TweetDuck.Browser.exe"

9
bld/Resources/LICENSE Normal file
View File

@@ -0,0 +1,9 @@
The MIT License (MIT)
Copyright (c) 2016
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

BIN
bld/Resources/icon.ico Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 31 KiB

111
bld/gen_full.iss Normal file
View File

@@ -0,0 +1,111 @@
; Script generated by the Inno Script Studio Wizard.
; SEE THE DOCUMENTATION FOR DETAILS ON CREATING INNO SETUP SCRIPT FILES!
#define MyAppName "TweetDuck"
#define MyAppPublisher "chylex"
#define MyAppURL "https://tweetduck.chylex.com"
#define MyAppExeName "TweetDuck.exe"
#define MyAppVersion GetFileVersion("..\bin\x86\Release\TweetDuck.exe")
[Setup]
AppId={{8C25A716-7E11-4AAD-9992-8B5D0C78AE06}
AppName={#MyAppName}
AppVersion={#MyAppVersion}
AppVerName={#MyAppName} {#MyAppVersion}
AppPublisher={#MyAppPublisher}
AppPublisherURL={#MyAppURL}
AppSupportURL={#MyAppURL}
AppUpdatesURL={#MyAppURL}
DefaultDirName={pf}\{#MyAppName}
DefaultGroupName={#MyAppName}
OutputBaseFilename={#MyAppName}
VersionInfoVersion={#MyAppVersion}
LicenseFile=.\Resources\LICENSE
SetupIconFile=.\Resources\icon.ico
UninstallDisplayName={#MyAppName}
UninstallDisplayIcon={app}\{#MyAppExeName}
Compression=lzma
SolidCompression=yes
InternalCompressLevel=max
MinVersion=0,6.1
[Languages]
Name: "english"; MessagesFile: "compiler:Default.isl"
[Tasks]
Name: "desktopicon"; Description: "{cm:CreateDesktopIcon}"; GroupDescription: "{cm:AdditionalIcons}"; Flags: unchecked
[Files]
Source: "..\bin\x86\Release\{#MyAppExeName}"; DestDir: "{app}"; Flags: ignoreversion
Source: "..\bin\x86\Release\*"; DestDir: "{app}"; Flags: ignoreversion recursesubdirs createallsubdirs; Excludes: "*.xml,devtools_resources.pak,d3dcompiler_43.dll"
[Icons]
Name: "{group}\{#MyAppName}"; Filename: "{app}\{#MyAppExeName}"
Name: "{commondesktop}\{#MyAppName}"; Filename: "{app}\{#MyAppExeName}"; Tasks: desktopicon
[Run]
Filename: "{app}\{#MyAppExeName}"; Description: "{cm:LaunchProgram,{#StringChange(MyAppName, '&', '&&')}}"; Flags: nowait postinstall skipifsilent
[InstallDelete]
Type: files; Name: "{app}\td-log.txt"
[UninstallDelete]
Type: files; Name: "{app}\debug.log"
Type: filesandordirs; Name: "{localappdata}\{#MyAppName}\Cache"
Type: filesandordirs; Name: "{localappdata}\{#MyAppName}\GPUCache"
[Code]
function TDGetNetFrameworkVersion: Cardinal; forward;
{ Check .NET Framework version on startup, ask user if they want to proceed if older than 4.5.2. }
function InitializeSetup: Boolean;
begin
if TDGetNetFrameworkVersion() >= 379893 then
begin
Result := True;
Exit;
end;
if (MsgBox('{#MyAppName} requires .NET Framework 4.5.2 or newer,'+#13+#10+'please download it from {#MyAppURL}'+#13+#10+#13+#10'Do you want to proceed with the setup anyway?', mbCriticalError, MB_YESNO or MB_DEFBUTTON2) = IDNO) then
begin
Result := False;
Exit;
end;
Result := True;
end;
{ Ask user if they want to delete 'AppData\TweetDuck' and 'plugins' folders after uninstallation. }
procedure CurUninstallStepChanged(CurUninstallStep: TUninstallStep);
var ProfileDataFolder: String;
var PluginDataFolder: String;
begin
if CurUninstallStep = usPostUninstall then
begin
ProfileDataFolder := ExpandConstant('{localappdata}\{#MyAppName}')
PluginDataFolder := ExpandConstant('{app}\plugins')
if (DirExists(ProfileDataFolder) or DirExists(PluginDataFolder)) and (MsgBox('Do you also want to delete your {#MyAppName} profile and plugins?', mbConfirmation, MB_YESNO or MB_DEFBUTTON2) = IDYES) then
begin
DelTree(ProfileDataFolder, True, True, True);
DelTree(PluginDataFolder, True, True, True);
DelTree(ExpandConstant('{app}'), True, False, False);
end;
end;
end;
{ Return DWORD value containing the build version of .NET Framework. }
function TDGetNetFrameworkVersion: Cardinal;
var FrameworkVersion: Cardinal;
begin
if RegQueryDWordValue(HKEY_LOCAL_MACHINE, 'Software\Microsoft\NET Framework Setup\NDP\v4\Full', 'Release', FrameworkVersion) then
begin
Result := FrameworkVersion;
Exit;
end;
Result := 0;
end;

227
bld/gen_upd.iss Normal file
View File

@@ -0,0 +1,227 @@
; Script generated by the Inno Script Studio Wizard.
; SEE THE DOCUMENTATION FOR DETAILS ON CREATING INNO SETUP SCRIPT FILES!
#define MyAppName "TweetDuck"
#define MyAppPublisher "chylex"
#define MyAppURL "https://tweetduck.chylex.com"
#define MyAppExeName "TweetDuck.exe"
#define MyAppID "8C25A716-7E11-4AAD-9992-8B5D0C78AE06"
#define MyAppVersion GetFileVersion("..\bin\x86\Release\TweetDuck.exe")
#define CefVersion "3.2785.1478.0"
[Setup]
AppId={{{#MyAppID}}
AppName={#MyAppName}
AppVersion={#MyAppVersion}
AppVerName={#MyAppName} {#MyAppVersion}
AppPublisher={#MyAppPublisher}
AppPublisherURL={#MyAppURL}
AppSupportURL={#MyAppURL}
AppUpdatesURL={#MyAppURL}
DefaultDirName={pf}\{#MyAppName}
DefaultGroupName={#MyAppName}
OutputBaseFilename={#MyAppName}.Update
VersionInfoVersion={#MyAppVersion}
LicenseFile=.\Resources\LICENSE
SetupIconFile=.\Resources\icon.ico
UninstallDisplayName={#MyAppName}
UninstallDisplayIcon={app}\{#MyAppExeName}
Compression=lzma
SolidCompression=yes
InternalCompressLevel=max
MinVersion=0,6.1
#include <idp.iss>
[Languages]
Name: "english"; MessagesFile: "compiler:Default.isl"
[Files]
Source: "..\bin\x86\Release\{#MyAppExeName}"; DestDir: "{app}"; Flags: ignoreversion
Source: "..\bin\x86\Release\*"; DestDir: "{app}"; Flags: ignoreversion recursesubdirs createallsubdirs; Excludes: "*.xml,*.dll,*.pak,*.bin,*.dat"
[Icons]
Name: "{group}\{#MyAppName}"; Filename: "{app}\{#MyAppExeName}"
[Run]
Filename: "{app}\{#MyAppExeName}"; Description: "{cm:LaunchProgram,{#StringChange(MyAppName, '&', '&&')}}"; Flags: nowait postinstall
[InstallDelete]
Type: files; Name: "{app}\*.xml"
Type: files; Name: "{app}\*.js"
Type: files; Name: "{app}\d3dcompiler_43.dll"
Type: files; Name: "{app}\devtools_resources.pak"
Type: files; Name: "{app}\CefSharp.BrowserSubprocess.exe"
Type: files; Name: "{app}\td-log.txt"
[UninstallDelete]
Type: files; Name: "{app}\*.*"
Type: filesandordirs; Name: "{app}\locales"
Type: filesandordirs; Name: "{app}\scripts"
Type: filesandordirs; Name: "{localappdata}\{#MyAppName}\Cache"
Type: filesandordirs; Name: "{localappdata}\{#MyAppName}\GPUCache"
[Code]
function TDGetNetFrameworkVersion: Cardinal; forward;
function TDGetAppVersionClean: String; forward;
function TDIsMatchingCEFVersion(InstallPath: String): Boolean; forward;
function TDPrepareFullDownloadIfNeeded: Boolean; forward;
procedure TDExecuteFullDownload; forward;
{ Check .NET Framework version on startup, ask user if they want to proceed if older than 4.5.2. Prepare full download package if required. }
function InitializeSetup: Boolean;
begin
if not TDPrepareFullDownloadIfNeeded() then
begin
MsgBox('{#MyAppName} installation could not be found on your system.', mbCriticalError, MB_OK);
Result := False;
Exit;
end;
if TDGetNetFrameworkVersion() >= 379893 then
begin
Result := True;
Exit;
end;
if (MsgBox('{#MyAppName} requires .NET Framework 4.5.2 or newer,'+#13+#10+'please download it from {#MyAppURL}'+#13+#10+#13+#10'Do you want to proceed with the setup anyway?', mbCriticalError, MB_YESNO or MB_DEFBUTTON2) = IDNO) then
begin
Result := False;
Exit;
end;
Result := True;
end;
{ Prepare download plugin if there are any files to download. }
procedure InitializeWizard();
begin
if idpFilesCount <> 0 then
begin
idpDownloadAfter(wpReady);
end;
end;
{ Ask user if they want to delete 'AppData\TweetDuck' and 'plugins' folders after uninstallation. }
procedure CurUninstallStepChanged(CurUninstallStep: TUninstallStep);
var ProfileDataFolder: String;
var PluginDataFolder: String;
begin
if CurUninstallStep = usPostUninstall then
begin
ProfileDataFolder := ExpandConstant('{localappdata}\{#MyAppName}');
PluginDataFolder := ExpandConstant('{app}\plugins');
if (DirExists(ProfileDataFolder) or DirExists(PluginDataFolder)) and (MsgBox('Do you also want to delete your {#MyAppName} profile and plugins?', mbConfirmation, MB_YESNO or MB_DEFBUTTON2) = IDYES) then
begin
DelTree(ProfileDataFolder, True, True, True);
DelTree(PluginDataFolder, True, True, True);
DelTree(ExpandConstant('{app}'), True, False, False);
end;
end;
end;
{ Remove uninstallation data and application to force them to be replaced with updated ones. }
procedure CurStepChanged(CurStep: TSetupStep);
begin
if CurStep = ssInstall then
begin
DeleteFile(ExpandConstant('{app}\unins000.dat'));
DeleteFile(ExpandConstant('{app}\unins000.exe'));
TDExecuteFullDownload();
end;
end;
{ Return DWORD value containing the build version of .NET Framework. }
function TDGetNetFrameworkVersion: Cardinal;
var FrameworkVersion: Cardinal;
begin
if RegQueryDWordValue(HKEY_LOCAL_MACHINE, 'Software\Microsoft\NET Framework Setup\NDP\v4\Full', 'Release', FrameworkVersion) then
begin
Result := FrameworkVersion;
Exit;
end;
Result := 0;
end;
{ Return whether the version of the installed libcef.dll library matches internal one. }
function TDIsMatchingCEFVersion(InstallPath: String): Boolean;
var CEFVersion: String;
begin
Result := (GetVersionNumbersString(InstallPath+'\libcef.dll', CEFVersion) and (CompareStr(CEFVersion, '{#CefVersion}') = 0))
end;
{ Return a cleaned up form of the app version string (removes all .0 suffixes). }
function TDGetAppVersionClean: String;
var Substr: String;
var CleanVersion: String;
begin
CleanVersion := '{#MyAppVersion}'
while True do
begin
Substr := Copy(CleanVersion, Length(CleanVersion)-1, 2);
if (CompareStr(Substr, '.0') <> 0) then
begin
break;
end;
CleanVersion := Copy(CleanVersion, 1, Length(CleanVersion)-2);
end;
Result := CleanVersion;
end;
{ Prepare the full package installer to run if the CEF version is not matching. Return False if the app is not installed. }
function TDPrepareFullDownloadIfNeeded: Boolean;
var InstallPath: String;
begin
if not RegQueryStringValue(HKEY_LOCAL_MACHINE, 'Software\Microsoft\Windows\CurrentVersion\Uninstall\{{#MyAppID}}_is1', 'InstallLocation', InstallPath) then
begin
Result := False;
Exit;
end;
if not TDIsMatchingCEFVersion(InstallPath) then
begin
idpAddFile('https://github.com/{#MyAppPublisher}/{#MyAppName}/releases/download/'+TDGetAppVersionClean()+'/{#MyAppName}.exe', ExpandConstant('{tmp}\{#MyAppName}.Full.exe'));
end;
Result := True;
end;
{ Run the full package installer if downloaded. }
procedure TDExecuteFullDownload;
var InstallFile: String;
var ResultCode: Integer;
begin
InstallFile := ExpandConstant('{tmp}\{#MyAppName}.Full.exe')
if FileExists(InstallFile) then
begin
WizardForm.ProgressGauge.Style := npbstMarquee;
try
if not Exec(InstallFile, '/SP- /SILENT /MERGETASKS="!desktopicon"', '', SW_SHOW, ewWaitUntilTerminated, ResultCode) then begin
MsgBox('Could not run the full installer, please visit {#MyAppURL} and download the latest version manually. Error: '+SysErrorMessage(ResultCode), mbCriticalError, MB_OK);
DeleteFile(InstallFile);
Abort();
Exit;
end;
finally
WizardForm.ProgressGauge.Style := npbstNormal;
DeleteFile(InstallFile);
end;
end;
end;