mirror of
https://github.com/chylex/TweetDuck.git
synced 2025-09-14 10:32:10 +02:00
Compare commits
32 Commits
Author | SHA1 | Date | |
---|---|---|---|
327ef1cbee | |||
15eb823c7f | |||
54613e5242 | |||
df1352cbe3 | |||
0559afd972 | |||
afffca020e | |||
d663cc3f64 | |||
110d41e393 | |||
1a8823f592 | |||
6374a852b0 | |||
a10c7dd7c3 | |||
547c7ea417 | |||
760607995a | |||
4704197c09 | |||
093ac1ac40 | |||
9ed8b0d904 | |||
7346ce370d | |||
adefdadc19 | |||
703bce2d00 | |||
97928ecd84 | |||
be9ea7f64a | |||
ec2aaa8789 | |||
ab14b72526 | |||
d8e304f3c1 | |||
ea53ce361f | |||
2fce80b347 | |||
373c0b1cc3 | |||
e5e1b7e608 | |||
7e9221c9e0 | |||
6b849f854e | |||
831f6bc744 | |||
d282a7a537 |
5
.gitattributes
vendored
Normal file
5
.gitattributes
vendored
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
# Auto detect text files and perform LF normalization
|
||||||
|
* text=auto
|
||||||
|
|
||||||
|
*.txt text eof=lf
|
||||||
|
*.cs diff=csharp
|
@@ -11,8 +11,8 @@ using TweetDuck.Resources;
|
|||||||
|
|
||||||
namespace TweetDuck.Core.Bridge{
|
namespace TweetDuck.Core.Bridge{
|
||||||
sealed class TweetDeckBridge{
|
sealed class TweetDeckBridge{
|
||||||
public static string FontSizeClass;
|
public static string FontSize { get; private set; }
|
||||||
public static string NotificationHeadContents;
|
public static string NotificationHeadLayout { get; private set; }
|
||||||
|
|
||||||
public static string LastHighlightedTweetUrl = string.Empty;
|
public static string LastHighlightedTweetUrl = string.Empty;
|
||||||
public static string LastHighlightedQuoteUrl = string.Empty;
|
public static string LastHighlightedQuoteUrl = string.Empty;
|
||||||
@@ -25,7 +25,7 @@ namespace TweetDuck.Core.Bridge{
|
|||||||
private static readonly Dictionary<string, string> SessionData = new Dictionary<string, string>(2);
|
private static readonly Dictionary<string, string> SessionData = new Dictionary<string, string>(2);
|
||||||
|
|
||||||
public static void ResetStaticProperties(){
|
public static void ResetStaticProperties(){
|
||||||
FontSizeClass = NotificationHeadContents = null;
|
FontSize = NotificationHeadLayout = null;
|
||||||
LastHighlightedTweetUrl = LastHighlightedQuoteUrl = LastHighlightedTweetAuthors = LastHighlightedTweetImages = string.Empty;
|
LastHighlightedTweetUrl = LastHighlightedQuoteUrl = LastHighlightedTweetAuthors = LastHighlightedTweetImages = string.Empty;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -56,12 +56,11 @@ namespace TweetDuck.Core.Bridge{
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
public void LoadFontSizeClass(string fsClass){
|
public void LoadNotificationLayout(string fontSize, string headLayout){
|
||||||
form.InvokeAsyncSafe(() => FontSizeClass = fsClass);
|
form.InvokeAsyncSafe(() => {
|
||||||
}
|
FontSize = fontSize;
|
||||||
|
NotificationHeadLayout = headLayout;
|
||||||
public void LoadNotificationHeadContents(string headContents){
|
});
|
||||||
form.InvokeAsyncSafe(() => NotificationHeadContents = headContents);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void SetLastRightClickInfo(string type, string link){
|
public void SetLastRightClickInfo(string type, string link){
|
||||||
@@ -118,8 +117,8 @@ namespace TweetDuck.Core.Bridge{
|
|||||||
form.InvokeAsyncSafe(() => form.OnTweetScreenshotReady(html, width, height));
|
form.InvokeAsyncSafe(() => form.OnTweetScreenshotReady(html, width, height));
|
||||||
}
|
}
|
||||||
|
|
||||||
public void PlayVideo(string url){
|
public void PlayVideo(string url, string username){
|
||||||
form.InvokeAsyncSafe(() => form.PlayVideo(url));
|
form.InvokeAsyncSafe(() => form.PlayVideo(url, username));
|
||||||
}
|
}
|
||||||
|
|
||||||
public void FixClipboard(){
|
public void FixClipboard(){
|
||||||
|
@@ -541,7 +541,7 @@ namespace TweetDuck.Core{
|
|||||||
soundNotification.Play(Config.NotificationSoundPath);
|
soundNotification.Play(Config.NotificationSoundPath);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void PlayVideo(string url){
|
public void PlayVideo(string url, string username){
|
||||||
if (string.IsNullOrEmpty(url)){
|
if (string.IsNullOrEmpty(url)){
|
||||||
videoPlayer?.Close();
|
videoPlayer?.Close();
|
||||||
return;
|
return;
|
||||||
@@ -556,7 +556,7 @@ namespace TweetDuck.Core{
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
videoPlayer.Launch(url);
|
videoPlayer.Launch(url, username);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void HideVideoOverlay(){
|
public void HideVideoOverlay(){
|
||||||
|
@@ -7,7 +7,9 @@ using TweetDuck.Core.Bridge;
|
|||||||
using TweetDuck.Core.Controls;
|
using TweetDuck.Core.Controls;
|
||||||
using TweetDuck.Core.Utils;
|
using TweetDuck.Core.Utils;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
using System.Diagnostics;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
|
using TweetDuck.Core.Other;
|
||||||
|
|
||||||
namespace TweetDuck.Core.Handling{
|
namespace TweetDuck.Core.Handling{
|
||||||
abstract class ContextMenuBase : IContextMenuHandler{
|
abstract class ContextMenuBase : IContextMenuHandler{
|
||||||
@@ -31,10 +33,11 @@ namespace TweetDuck.Core.Handling{
|
|||||||
private const CefMenuCommand MenuOpenLinkUrl = (CefMenuCommand)26500;
|
private const CefMenuCommand MenuOpenLinkUrl = (CefMenuCommand)26500;
|
||||||
private const CefMenuCommand MenuCopyLinkUrl = (CefMenuCommand)26501;
|
private const CefMenuCommand MenuCopyLinkUrl = (CefMenuCommand)26501;
|
||||||
private const CefMenuCommand MenuCopyUsername = (CefMenuCommand)26502;
|
private const CefMenuCommand MenuCopyUsername = (CefMenuCommand)26502;
|
||||||
private const CefMenuCommand MenuOpenMediaUrl = (CefMenuCommand)26503;
|
private const CefMenuCommand MenuViewImage = (CefMenuCommand)26503;
|
||||||
private const CefMenuCommand MenuCopyMediaUrl = (CefMenuCommand)26504;
|
private const CefMenuCommand MenuOpenMediaUrl = (CefMenuCommand)26504;
|
||||||
private const CefMenuCommand MenuSaveMedia = (CefMenuCommand)26505;
|
private const CefMenuCommand MenuCopyMediaUrl = (CefMenuCommand)26505;
|
||||||
private const CefMenuCommand MenuSaveTweetImages = (CefMenuCommand)26506;
|
private const CefMenuCommand MenuSaveMedia = (CefMenuCommand)26506;
|
||||||
|
private const CefMenuCommand MenuSaveTweetImages = (CefMenuCommand)26507;
|
||||||
private const CefMenuCommand MenuOpenDevTools = (CefMenuCommand)26599;
|
private const CefMenuCommand MenuOpenDevTools = (CefMenuCommand)26599;
|
||||||
|
|
||||||
private string[] lastHighlightedTweetAuthors;
|
private string[] lastHighlightedTweetAuthors;
|
||||||
@@ -79,6 +82,7 @@ namespace TweetDuck.Core.Handling{
|
|||||||
model.AddSeparator();
|
model.AddSeparator();
|
||||||
}
|
}
|
||||||
else if ((parameters.TypeFlags.HasFlag(ContextMenuType.Media) && parameters.HasImageContents) || hasTweetImage){
|
else if ((parameters.TypeFlags.HasFlag(ContextMenuType.Media) && parameters.HasImageContents) || hasTweetImage){
|
||||||
|
model.AddItem(MenuViewImage, "View image in photo viewer");
|
||||||
model.AddItem(MenuOpenMediaUrl, TextOpen("image"));
|
model.AddItem(MenuOpenMediaUrl, TextOpen("image"));
|
||||||
model.AddItem(MenuCopyMediaUrl, TextCopy("image"));
|
model.AddItem(MenuCopyMediaUrl, TextCopy("image"));
|
||||||
model.AddItem(MenuSaveMedia, TextSave("image"));
|
model.AddItem(MenuSaveMedia, TextSave("image"));
|
||||||
@@ -114,9 +118,35 @@ namespace TweetDuck.Core.Handling{
|
|||||||
SetClipboardText(browserControl.AsControl(), TwitterUtils.GetMediaLink(GetMediaLink(parameters), ImageQuality));
|
SetClipboardText(browserControl.AsControl(), TwitterUtils.GetMediaLink(GetMediaLink(parameters), ImageQuality));
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case MenuViewImage:
|
||||||
|
string url = GetMediaLink(parameters);
|
||||||
|
string file = Path.Combine(BrowserCache.CacheFolder, TwitterUtils.GetImageFileName(url));
|
||||||
|
|
||||||
|
void ViewFile(){
|
||||||
|
string ext = Path.GetExtension(file);
|
||||||
|
|
||||||
|
if (TwitterUtils.ValidImageExtensions.Contains(ext)){
|
||||||
|
WindowsUtils.OpenAssociatedProgram(file);
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
FormMessage.Error("Image Download", "Invalid file extension "+ext, FormMessage.OK);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (File.Exists(file)){
|
||||||
|
ViewFile();
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
BrowserUtils.DownloadFileAsync(TwitterUtils.GetMediaLink(url, ImageQuality), file, ViewFile, ex => {
|
||||||
|
FormMessage.Error("Image Download", "An error occurred while downloading the image: "+ex.Message, FormMessage.OK);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
|
||||||
case MenuSaveMedia:
|
case MenuSaveMedia:
|
||||||
if (IsVideo){
|
if (IsVideo){
|
||||||
TwitterUtils.DownloadVideo(GetMediaLink(parameters));
|
TwitterUtils.DownloadVideo(GetMediaLink(parameters), lastHighlightedTweetAuthors.LastOrDefault());
|
||||||
}
|
}
|
||||||
else{
|
else{
|
||||||
TwitterUtils.DownloadImage(GetMediaLink(parameters), lastHighlightedTweetAuthors.LastOrDefault(), ImageQuality);
|
TwitterUtils.DownloadImage(GetMediaLink(parameters), lastHighlightedTweetAuthors.LastOrDefault(), ImageQuality);
|
||||||
|
@@ -48,7 +48,7 @@ namespace TweetDuck.Core.Handling{
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (HasDevTools){
|
if (HasDevTools){
|
||||||
model.AddSeparator();
|
AddSeparator(model);
|
||||||
AddDebugMenuItems(model);
|
AddDebugMenuItems(model);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -15,7 +15,7 @@ namespace TweetDuck.Core.Notification{
|
|||||||
partial class FormNotificationBase : Form{
|
partial class FormNotificationBase : Form{
|
||||||
protected static int FontSizeLevel{
|
protected static int FontSizeLevel{
|
||||||
get{
|
get{
|
||||||
switch(TweetDeckBridge.FontSizeClass){
|
switch(TweetDeckBridge.FontSize){
|
||||||
case "largest": return 4;
|
case "largest": return 4;
|
||||||
case "large": return 3;
|
case "large": return 3;
|
||||||
case "small": return 1;
|
case "small": return 1;
|
||||||
|
@@ -5,9 +5,7 @@ using TweetDuck.Resources;
|
|||||||
|
|
||||||
namespace TweetDuck.Core.Notification{
|
namespace TweetDuck.Core.Notification{
|
||||||
sealed class TweetNotification{
|
sealed class TweetNotification{
|
||||||
private const string DefaultFontSizeClass = "medium";
|
private const string DefaultHeadLayout = @"<html class='os-windows txt-size--14' data-td-font='medium' data-td-theme='dark'><head><meta charset='utf-8'><meta http-equiv='X-UA-Compatible' content='chrome=1'><link rel='stylesheet' href='https://ton.twimg.com/tweetdeck-web/web/css/font.5ef884f9f9.css'><link rel='stylesheet' href='https://ton.twimg.com/tweetdeck-web/web/css/app-dark.5631e0dd42.css'><style type='text/css'>body{background:#222426}</style>";
|
||||||
private const string DefaultHeadContents = @"<meta charset='utf-8'><meta http-equiv='X-UA-Compatible' content='chrome=1'><link rel='stylesheet' href='https://ton.twimg.com/tweetdeck-web/web/css/font.5ef884f9f9.css'><link rel='stylesheet' href='https://ton.twimg.com/tweetdeck-web/web/css/app-dark.5631e0dd42.css'><style type='text/css'>body{background:#222426}</style>";
|
|
||||||
|
|
||||||
private static readonly string CustomCSS = ScriptLoader.LoadResource("styles/notification.css");
|
private static readonly string CustomCSS = ScriptLoader.LoadResource("styles/notification.css");
|
||||||
|
|
||||||
private static string ExampleTweetHTML;
|
private static string ExampleTweetHTML;
|
||||||
@@ -67,8 +65,7 @@ namespace TweetDuck.Core.Notification{
|
|||||||
public string GenerateHtml(string bodyClasses = null, bool enableCustomCSS = true){
|
public string GenerateHtml(string bodyClasses = null, bool enableCustomCSS = true){
|
||||||
StringBuilder build = new StringBuilder();
|
StringBuilder build = new StringBuilder();
|
||||||
build.Append("<!DOCTYPE html>");
|
build.Append("<!DOCTYPE html>");
|
||||||
build.Append("<html class='os-windows txt-base-").Append(TweetDeckBridge.FontSizeClass ?? DefaultFontSizeClass).Append("'>");
|
build.Append(TweetDeckBridge.NotificationHeadLayout ?? DefaultHeadLayout);
|
||||||
build.Append("<head>").Append(TweetDeckBridge.NotificationHeadContents ?? DefaultHeadContents);
|
|
||||||
|
|
||||||
if (enableCustomCSS){
|
if (enableCustomCSS){
|
||||||
build.Append("<style type='text/css'>").Append(CustomCSS).Append("</style>");
|
build.Append("<style type='text/css'>").Append(CustomCSS).Append("</style>");
|
||||||
|
@@ -21,7 +21,7 @@ namespace TweetDuck.Core.Other{
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void OnLinkClicked(object sender, LinkLabelLinkClickedEventArgs e){
|
private void OnLinkClicked(object sender, LinkLabelLinkClickedEventArgs e){
|
||||||
BrowserUtils.OpenExternalBrowserUnsafe(e.Link.LinkData as string);
|
BrowserUtils.OpenExternalBrowser(e.Link.LinkData as string);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void FormAbout_HelpRequested(object sender, HelpEventArgs hlpevent){
|
private void FormAbout_HelpRequested(object sender, HelpEventArgs hlpevent){
|
||||||
|
@@ -25,6 +25,7 @@ namespace TweetDuck.Core.Other.Management{
|
|||||||
|
|
||||||
private readonly Form owner;
|
private readonly Form owner;
|
||||||
private string lastUrl;
|
private string lastUrl;
|
||||||
|
private string lastUsername;
|
||||||
|
|
||||||
private Process currentProcess;
|
private Process currentProcess;
|
||||||
private DuplexPipe.Server currentPipe;
|
private DuplexPipe.Server currentPipe;
|
||||||
@@ -35,13 +36,14 @@ namespace TweetDuck.Core.Other.Management{
|
|||||||
this.owner.FormClosing += owner_FormClosing;
|
this.owner.FormClosing += owner_FormClosing;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Launch(string url){
|
public void Launch(string url, string username){
|
||||||
if (Running){
|
if (Running){
|
||||||
Destroy();
|
Destroy();
|
||||||
isClosing = false;
|
isClosing = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
lastUrl = url;
|
lastUrl = url;
|
||||||
|
lastUsername = username;
|
||||||
|
|
||||||
try{
|
try{
|
||||||
currentPipe = DuplexPipe.CreateServer();
|
currentPipe = DuplexPipe.CreateServer();
|
||||||
@@ -84,7 +86,7 @@ namespace TweetDuck.Core.Other.Management{
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case "download":
|
case "download":
|
||||||
TwitterUtils.DownloadVideo(lastUrl);
|
TwitterUtils.DownloadVideo(lastUrl, lastUsername);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case "rip":
|
case "rip":
|
||||||
@@ -157,14 +159,14 @@ namespace TweetDuck.Core.Other.Management{
|
|||||||
|
|
||||||
switch(exitCode){
|
switch(exitCode){
|
||||||
case 3: // CODE_LAUNCH_FAIL
|
case 3: // CODE_LAUNCH_FAIL
|
||||||
if (FormMessage.Error("Video Playback Error", "Error launching video player, this may be caused by missing Windows Media Player. Do you want to open the video in a browser?", FormMessage.Yes, FormMessage.No)){
|
if (FormMessage.Error("Video Playback Error", "Error launching video player, this may be caused by missing Windows Media Player. Do you want to open the video in your browser?", FormMessage.Yes, FormMessage.No)){
|
||||||
BrowserUtils.OpenExternalBrowser(lastUrl);
|
BrowserUtils.OpenExternalBrowser(lastUrl);
|
||||||
}
|
}
|
||||||
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 4: // CODE_MEDIA_ERROR
|
case 4: // CODE_MEDIA_ERROR
|
||||||
if (FormMessage.Error("Video Playback Error", "The video could not be loaded, most likely due to unknown format. Do you want to open the video in a browser?", FormMessage.Yes, FormMessage.No)){
|
if (FormMessage.Error("Video Playback Error", "The video could not be loaded, most likely due to unknown format. Do you want to open the video in your browser?", FormMessage.Yes, FormMessage.No)){
|
||||||
BrowserUtils.OpenExternalBrowser(lastUrl);
|
BrowserUtils.OpenExternalBrowser(lastUrl);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -35,7 +35,7 @@ namespace TweetDuck.Core.Other.Settings.Dialogs{
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void btnOpenWiki_Click(object sender, EventArgs e){
|
private void btnOpenWiki_Click(object sender, EventArgs e){
|
||||||
BrowserUtils.OpenExternalBrowserUnsafe("https://github.com/chylex/TweetDuck/wiki");
|
BrowserUtils.OpenExternalBrowser("https://github.com/chylex/TweetDuck/wiki");
|
||||||
}
|
}
|
||||||
|
|
||||||
private void btnApply_Click(object sender, EventArgs e){
|
private void btnApply_Click(object sender, EventArgs e){
|
||||||
|
@@ -19,7 +19,7 @@ namespace TweetDuck.Core.Other.Settings.Dialogs{
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void btnHelp_Click(object sender, EventArgs e){
|
private void btnHelp_Click(object sender, EventArgs e){
|
||||||
BrowserUtils.OpenExternalBrowserUnsafe("http://peter.sh/experiments/chromium-command-line-switches/");
|
BrowserUtils.OpenExternalBrowser("http://peter.sh/experiments/chromium-command-line-switches/");
|
||||||
}
|
}
|
||||||
|
|
||||||
private void btnApply_Click(object sender, EventArgs e){
|
private void btnApply_Click(object sender, EventArgs e){
|
||||||
|
@@ -16,7 +16,7 @@ namespace TweetDuck.Core.Other.Settings{
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void btnSendFeedback_Click(object sender, EventArgs e){
|
private void btnSendFeedback_Click(object sender, EventArgs e){
|
||||||
BrowserUtils.OpenExternalBrowserUnsafe("https://github.com/chylex/TweetDuck/issues/new");
|
BrowserUtils.OpenExternalBrowser("https://github.com/chylex/TweetDuck/issues/new");
|
||||||
}
|
}
|
||||||
|
|
||||||
private void checkDataCollection_CheckedChanged(object sender, EventArgs e){
|
private void checkDataCollection_CheckedChanged(object sender, EventArgs e){
|
||||||
@@ -24,7 +24,7 @@ namespace TweetDuck.Core.Other.Settings{
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void labelDataCollectionLink_LinkClicked(object sender, LinkLabelLinkClickedEventArgs e){
|
private void labelDataCollectionLink_LinkClicked(object sender, LinkLabelLinkClickedEventArgs e){
|
||||||
BrowserUtils.OpenExternalBrowserUnsafe("https://github.com/chylex/TweetDuck/wiki/Send-anonymous-data");
|
BrowserUtils.OpenExternalBrowser("https://github.com/chylex/TweetDuck/wiki/Send-anonymous-data");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -8,7 +8,7 @@ namespace TweetDuck.Core.Utils{
|
|||||||
static class BrowserCache{
|
static class BrowserCache{
|
||||||
private static bool ClearOnExit { get; set; }
|
private static bool ClearOnExit { get; set; }
|
||||||
|
|
||||||
private static readonly string CacheFolder = Path.Combine(Program.StoragePath, "Cache");
|
public static readonly string CacheFolder = Path.Combine(Program.StoragePath, "Cache");
|
||||||
|
|
||||||
private static IEnumerable<string> CacheFiles{
|
private static IEnumerable<string> CacheFiles{
|
||||||
get{
|
get{
|
||||||
|
@@ -70,12 +70,12 @@ namespace TweetDuck.Core.Utils{
|
|||||||
|
|
||||||
switch(CheckUrl(url)){
|
switch(CheckUrl(url)){
|
||||||
case UrlCheckResult.Fine:
|
case UrlCheckResult.Fine:
|
||||||
OpenExternalBrowserUnsafe(url);
|
WindowsUtils.OpenAssociatedProgram(url);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case UrlCheckResult.Tracking:
|
case UrlCheckResult.Tracking:
|
||||||
if (FormMessage.Warning("Blocked URL", "TweetDuck has blocked a tracking url due to privacy concerns. Do you want to visit it anyway?\n"+url, FormMessage.Yes, FormMessage.No)){
|
if (FormMessage.Warning("Blocked URL", "TweetDuck has blocked a tracking url due to privacy concerns. Do you want to visit it anyway?\n"+url, FormMessage.Yes, FormMessage.No)){
|
||||||
OpenExternalBrowserUnsafe(url);
|
WindowsUtils.OpenAssociatedProgram(url);
|
||||||
}
|
}
|
||||||
|
|
||||||
break;
|
break;
|
||||||
@@ -86,10 +86,6 @@ namespace TweetDuck.Core.Utils{
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void OpenExternalBrowserUnsafe(string url){
|
|
||||||
using(Process.Start(url)){}
|
|
||||||
}
|
|
||||||
|
|
||||||
public static string GetFileNameFromUrl(string url){
|
public static string GetFileNameFromUrl(string url){
|
||||||
string file = Path.GetFileName(new Uri(url).AbsolutePath);
|
string file = Path.GetFileName(new Uri(url).AbsolutePath);
|
||||||
return string.IsNullOrEmpty(file) ? null : file;
|
return string.IsNullOrEmpty(file) ? null : file;
|
||||||
|
@@ -21,6 +21,10 @@ namespace TweetDuck.Core.Utils{
|
|||||||
"tweetdeck", "TweetDeck", "tweetduck", "TweetDuck", "TD"
|
"tweetdeck", "TweetDeck", "tweetduck", "TweetDuck", "TD"
|
||||||
};
|
};
|
||||||
|
|
||||||
|
public static readonly string[] ValidImageExtensions = {
|
||||||
|
".jpg", ".jpeg", ".png", ".gif"
|
||||||
|
};
|
||||||
|
|
||||||
public enum ImageQuality{
|
public enum ImageQuality{
|
||||||
Default, Orig
|
Default, Orig
|
||||||
}
|
}
|
||||||
@@ -53,6 +57,10 @@ namespace TweetDuck.Core.Utils{
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static string GetImageFileName(string url){
|
||||||
|
return BrowserUtils.GetFileNameFromUrl(ExtractMediaBaseLink(url));
|
||||||
|
}
|
||||||
|
|
||||||
public static void DownloadImage(string url, string username, ImageQuality quality){
|
public static void DownloadImage(string url, string username, ImageQuality quality){
|
||||||
DownloadImages(new string[]{ url }, username, quality);
|
DownloadImages(new string[]{ url }, username, quality);
|
||||||
}
|
}
|
||||||
@@ -65,7 +73,7 @@ namespace TweetDuck.Core.Utils{
|
|||||||
string firstImageLink = GetMediaLink(urls[0], quality);
|
string firstImageLink = GetMediaLink(urls[0], quality);
|
||||||
int qualityIndex = firstImageLink.IndexOf(':', firstImageLink.LastIndexOf('/'));
|
int qualityIndex = firstImageLink.IndexOf(':', firstImageLink.LastIndexOf('/'));
|
||||||
|
|
||||||
string file = BrowserUtils.GetFileNameFromUrl(ExtractMediaBaseLink(firstImageLink));
|
string file = GetImageFileName(firstImageLink);
|
||||||
string ext = Path.GetExtension(file); // includes dot
|
string ext = Path.GetExtension(file); // includes dot
|
||||||
|
|
||||||
string[] fileNameParts = qualityIndex == -1 ? new string[]{
|
string[] fileNameParts = qualityIndex == -1 ? new string[]{
|
||||||
@@ -103,7 +111,7 @@ namespace TweetDuck.Core.Utils{
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void DownloadVideo(string url){
|
public static void DownloadVideo(string url, string username){
|
||||||
string filename = BrowserUtils.GetFileNameFromUrl(url);
|
string filename = BrowserUtils.GetFileNameFromUrl(url);
|
||||||
string ext = Path.GetExtension(filename);
|
string ext = Path.GetExtension(filename);
|
||||||
|
|
||||||
@@ -111,7 +119,7 @@ namespace TweetDuck.Core.Utils{
|
|||||||
AutoUpgradeEnabled = true,
|
AutoUpgradeEnabled = true,
|
||||||
OverwritePrompt = true,
|
OverwritePrompt = true,
|
||||||
Title = "Save video",
|
Title = "Save video",
|
||||||
FileName = filename,
|
FileName = string.IsNullOrEmpty(username) ? filename : $"{username} {filename}",
|
||||||
Filter = "Video"+(string.IsNullOrEmpty(ext) ? " (unknown)|*.*" : $" (*{ext})|*{ext}")
|
Filter = "Video"+(string.IsNullOrEmpty(ext) ? " (unknown)|*.*" : $" (*{ext})|*{ext}")
|
||||||
}){
|
}){
|
||||||
if (dialog.ShowDialog() == DialogResult.OK){
|
if (dialog.ShowDialog() == DialogResult.OK){
|
||||||
|
@@ -1,4 +1,5 @@
|
|||||||
using System;
|
using System;
|
||||||
|
using System.ComponentModel;
|
||||||
using System.Diagnostics;
|
using System.Diagnostics;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Management;
|
using System.Management;
|
||||||
@@ -49,17 +50,22 @@ namespace TweetDuck.Core.Utils{
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Process StartProcess(string file, string arguments, bool runElevated){
|
public static bool OpenAssociatedProgram(string file, string arguments = "", bool runElevated = false){
|
||||||
ProcessStartInfo processInfo = new ProcessStartInfo{
|
try{
|
||||||
FileName = file,
|
using(Process.Start(new ProcessStartInfo{
|
||||||
Arguments = arguments
|
FileName = file,
|
||||||
};
|
Arguments = arguments,
|
||||||
|
Verb = runElevated ? "runas" : string.Empty,
|
||||||
if (runElevated){
|
ErrorDialog = true
|
||||||
processInfo.Verb = "runas";
|
})){
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}catch(Win32Exception e) when (e.NativeErrorCode == 0x000004C7){ // operation canceled by the user
|
||||||
|
return false;
|
||||||
|
}catch(Exception e){
|
||||||
|
Program.Reporter.HandleException("Error opening file", e.Message, true, e);
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
return Process.Start(processInfo);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static bool TrySleepUntil(Func<bool> test, int timeoutMillis, int timeStepMillis){
|
public static bool TrySleepUntil(Func<bool> test, int timeoutMillis, int timeStepMillis){
|
||||||
@@ -104,7 +110,7 @@ namespace TweetDuck.Core.Utils{
|
|||||||
}
|
}
|
||||||
|
|
||||||
public static void ClipboardStripHtmlStyles(){
|
public static void ClipboardStripHtmlStyles(){
|
||||||
if (!Clipboard.ContainsText(TextDataFormat.Html)){
|
if (!Clipboard.ContainsText(TextDataFormat.Html) || !Clipboard.ContainsText(TextDataFormat.UnicodeText)){
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
19
Program.cs
19
Program.cs
@@ -21,7 +21,7 @@ namespace TweetDuck{
|
|||||||
public const string BrandName = "TweetDuck";
|
public const string BrandName = "TweetDuck";
|
||||||
public const string Website = "https://tweetduck.chylex.com";
|
public const string Website = "https://tweetduck.chylex.com";
|
||||||
|
|
||||||
public const string VersionTag = "1.10.1";
|
public const string VersionTag = "1.10.2";
|
||||||
|
|
||||||
public static readonly bool IsPortable = File.Exists("makeportable");
|
public static readonly bool IsPortable = File.Exists("makeportable");
|
||||||
|
|
||||||
@@ -166,8 +166,12 @@ namespace TweetDuck{
|
|||||||
string updaterArgs = "/SP- /SILENT /CLOSEAPPLICATIONS /UPDATEPATH=\""+ProgramPath+"\" /RUNARGS=\""+Arguments.GetCurrentForInstallerCmd()+"\""+(IsPortable ? " /PORTABLE=1" : "");
|
string updaterArgs = "/SP- /SILENT /CLOSEAPPLICATIONS /UPDATEPATH=\""+ProgramPath+"\" /RUNARGS=\""+Arguments.GetCurrentForInstallerCmd()+"\""+(IsPortable ? " /PORTABLE=1" : "");
|
||||||
bool runElevated = !IsPortable || !WindowsUtils.CheckFolderWritePermission(ProgramPath);
|
bool runElevated = !IsPortable || !WindowsUtils.CheckFolderWritePermission(ProgramPath);
|
||||||
|
|
||||||
WindowsUtils.StartProcess(mainForm.UpdateInstallerPath, updaterArgs, runElevated);
|
if (WindowsUtils.OpenAssociatedProgram(mainForm.UpdateInstallerPath, updaterArgs, runElevated)){
|
||||||
Application.Exit();
|
Application.Exit();
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
RestartWithArgsInternal(Arguments.GetCurrentClean());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -211,11 +215,14 @@ namespace TweetDuck{
|
|||||||
FormBrowser browserForm = Application.OpenForms.OfType<FormBrowser>().FirstOrDefault();
|
FormBrowser browserForm = Application.OpenForms.OfType<FormBrowser>().FirstOrDefault();
|
||||||
if (browserForm == null)return;
|
if (browserForm == null)return;
|
||||||
|
|
||||||
args.AddFlag(Arguments.ArgRestart);
|
|
||||||
|
|
||||||
browserForm.ForceClose();
|
browserForm.ForceClose();
|
||||||
ExitCleanup();
|
|
||||||
|
|
||||||
|
ExitCleanup();
|
||||||
|
RestartWithArgsInternal(args);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void RestartWithArgsInternal(CommandLineArgs args){
|
||||||
|
args.AddFlag(Arguments.ArgRestart);
|
||||||
Process.Start(Application.ExecutablePath, args.ToString());
|
Process.Start(Application.ExecutablePath, args.ToString());
|
||||||
Application.Exit();
|
Application.Exit();
|
||||||
}
|
}
|
||||||
|
25
README.md
25
README.md
@@ -1,3 +1,7 @@
|
|||||||
|
# Support
|
||||||
|
|
||||||
|
[Follow TweetDuck on Twitter](https://twitter.com/TryTweetDuck) | [Support via PayPal](https://paypal.me/chylex) | [Support via Patreon](https://www.patreon.com/chylex)
|
||||||
|
|
||||||
# Build Instructions
|
# Build Instructions
|
||||||
|
|
||||||
### Setup
|
### Setup
|
||||||
@@ -25,21 +29,34 @@ To do that, open **TweetDuck Properties**, click the **Debug** tab, make sure yo
|
|||||||
|
|
||||||
### Build
|
### Build
|
||||||
|
|
||||||
To make a release build of TweetDuck, open **Batch Build**, tick all `Release` configurations except for the `UnitTest` project (otherwise the build will fail), and click **Rebuild**. Check the status bar to make sure it says **Rebuild All succeeded**; if not, open the **Output** view and see which part of the build failed.
|
To make a release build of TweetDuck, open **Batch Build**, tick all `Release` configurations except for the `UnitTest` project (otherwise the build will fail), and click **Rebuild**. Check the status bar to make sure it says **Rebuild All succeeded**; if not, see the [Troubleshooting](#troubleshooting) section.
|
||||||
|
|
||||||
After the build succeeds, the **bin/x86/Release** folder will contain files intended for distribution (no debug symbols or other unnecessary files). You may package these files yourself, or see the [Installers](#Installers) section for automated installer generation.
|
After the build succeeds, the `bin/x86/Release` folder will contain files intended for distribution (no debug symbols or other unnecessary files). You may package these files yourself, or see the [Installers](#installers) section for automated installer generation.
|
||||||
|
|
||||||
If you decide to release a custom version publicly, please make it clear that it is not an official release of TweetDuck.
|
If you decide to release a custom version publicly, please make it clear that it is not an official release of TweetDuck.
|
||||||
|
|
||||||
|
### Troubleshooting
|
||||||
|
|
||||||
|
There are a few quirks in the build process that may catch you off guard:
|
||||||
|
|
||||||
|
- **Plugin files are not updated automatically**
|
||||||
|
- Since official plugins (`Resources/Plugins`) are not included in the project, Visual Studio will not automatically detect changes in the files
|
||||||
|
- To ensure plugins are updated when testing the app, click **Rebuild Solution** before clicking **Start**
|
||||||
|
- **Error: The command (...) exited with code 1**
|
||||||
|
- If the post-build event fails, open the **Output** tab and look for the cause
|
||||||
|
- Determine if there was an IO error while copying files or modifying folders, or whether the final .ps1 script failed (`Encountered an error while running PostBuild.ps1 on line xyz`)
|
||||||
|
- Some files are checked for invalid characters:
|
||||||
|
- `Resources/Plugins/emoji-keyboard/emoji-ordering.txt` line endings must be LF (line feed); any CR (carriage return) in the file will cause a failed build, and you will need to ensure correct line endings in your text editor
|
||||||
|
|
||||||
### Installers
|
### Installers
|
||||||
|
|
||||||
TweetDuck uses **Inno Setup** to automate the creation of installers. First, download and install [InnoSetup QuickStart Pack](http://www.jrsoftware.org/isdl.php) (non-unicode; editor and encryption support not required) and the [Inno Download Plugin](https://code.google.com/archive/p/inno-download-plugin).
|
TweetDuck uses **Inno Setup** to automate the creation of installers. First, download and install [InnoSetup QuickStart Pack](http://www.jrsoftware.org/isdl.php) (non-unicode; editor and encryption support not required) and the [Inno Download Plugin](https://code.google.com/archive/p/inno-download-plugin).
|
||||||
|
|
||||||
Next, add the Inno Setup installation folder (usually `C:\Program Files (x86)\Inno Setup 5`) into your **PATH** environment variable. You may need to restart File Explorer for the change to take place.
|
Next, add the Inno Setup installation folder (usually `C:\Program Files (x86)\Inno Setup 5`) into your **PATH** environment variable. You may need to restart File Explorer for the change to take place.
|
||||||
|
|
||||||
Now you can generate installers after a build by running **bld/RUN BUILD.bat**. Note that despite the name, this will only package the files, you still need to run the [build](#Build) in Visual Studio!
|
Now you can generate installers after a build by running `bld/RUN BUILD.bat`. Note that despite the name, this will only package the files, you still need to run the [build](#build) in Visual Studio!
|
||||||
|
|
||||||
After the window closes, three installers will be generated inside the **bld/Output** folder:
|
After the window closes, three installers will be generated inside the `bld/Output` folder:
|
||||||
* **TweetDuck.exe**
|
* **TweetDuck.exe**
|
||||||
* This is the main installer that creates entries in the Start Menu & Programs and Features, and an optional desktop icon
|
* This is the main installer that creates entries in the Start Menu & Programs and Features, and an optional desktop icon
|
||||||
* **TweetDuck.Update.exe**
|
* **TweetDuck.Update.exe**
|
||||||
|
@@ -8,10 +8,10 @@ Edit layout & design
|
|||||||
chylex
|
chylex
|
||||||
|
|
||||||
[version]
|
[version]
|
||||||
1.1.3
|
1.1.5
|
||||||
|
|
||||||
[website]
|
[website]
|
||||||
https://tweetduck.chylex.com
|
https://tweetduck.chylex.com
|
||||||
|
|
||||||
[requires]
|
[requires]
|
||||||
1.7
|
1.10.2
|
@@ -12,6 +12,7 @@ enabled(){
|
|||||||
moveTweetActionsToRight: true,
|
moveTweetActionsToRight: true,
|
||||||
themeColorTweaks: true,
|
themeColorTweaks: true,
|
||||||
revertIcons: true,
|
revertIcons: true,
|
||||||
|
increaseQuoteTextSize: false,
|
||||||
smallComposeTextSize: false,
|
smallComposeTextSize: false,
|
||||||
optimizeAnimations: true,
|
optimizeAnimations: true,
|
||||||
avatarRadius: 2
|
avatarRadius: 2
|
||||||
@@ -331,7 +332,7 @@ enabled(){
|
|||||||
this.css.insert("#general_settings .cf { display: none !important }");
|
this.css.insert("#general_settings .cf { display: none !important }");
|
||||||
this.css.insert("#settings-modal .js-setting-list li:nth-child(3) { border-bottom: 1px solid #ccd6dd }");
|
this.css.insert("#settings-modal .js-setting-list li:nth-child(3) { border-bottom: 1px solid #ccd6dd }");
|
||||||
|
|
||||||
this.css.insert(".txt-base-smallest:not(.icon), .txt-base-largest:not(.icon) { font-size: "+this.config.fontSize+" !important }");
|
this.css.insert("html[data-td-font] { font-size: "+this.config.fontSize+" !important }");
|
||||||
this.css.insert(".avatar { border-radius: "+this.config.avatarRadius+"% !important }");
|
this.css.insert(".avatar { border-radius: "+this.config.avatarRadius+"% !important }");
|
||||||
|
|
||||||
let notificationScrollbarColor = null;
|
let notificationScrollbarColor = null;
|
||||||
@@ -366,6 +367,10 @@ enabled(){
|
|||||||
this.css.insert(".tweet-actions > li:nth-child(4) { margin-right: 2px !important }");
|
this.css.insert(".tweet-actions > li:nth-child(4) { margin-right: 2px !important }");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (this.config.increaseQuoteTextSize){
|
||||||
|
this.css.insert(".quoted-tweet { font-size: 1em !important }");
|
||||||
|
}
|
||||||
|
|
||||||
if (this.config.smallComposeTextSize){
|
if (this.config.smallComposeTextSize){
|
||||||
this.css.insert(".compose-text { font-size: 12px !important; height: 120px !important }");
|
this.css.insert(".compose-text { font-size: 12px !important; height: 120px !important }");
|
||||||
}
|
}
|
||||||
@@ -507,9 +512,13 @@ enabled(){
|
|||||||
|
|
||||||
$TDP.injectIntoNotificationsBefore(this.$token, "css", "</head>", `
|
$TDP.injectIntoNotificationsBefore(this.$token, "css", "</head>", `
|
||||||
<style type='text/css'>
|
<style type='text/css'>
|
||||||
.txt-base-smallest:not(.icon), .txt-base-largest:not(.icon) { font-size: ${this.config.fontSize} !important }
|
html[data-td-font] { font-size: ${this.config.fontSize} !important }
|
||||||
.avatar { border-radius: ${this.config.avatarRadius}% !important }
|
.avatar { border-radius: ${this.config.avatarRadius}% !important }
|
||||||
|
|
||||||
|
${this.config.increaseQuoteTextSize ? `
|
||||||
|
.quoted-tweet { font-size: 1em !important }
|
||||||
|
` : ``}
|
||||||
|
|
||||||
${this.config.revertIcons ? `
|
${this.config.revertIcons ? `
|
||||||
@font-face { font-family: 'tweetdeckold'; src: url(\"https://ton.twimg.com/tweetdeck-web/web/assets/fonts/tweetdeck-regular-webfont.5f4ea87976.woff\") format(\"woff\"); font-weight: normal; font-style: normal }
|
@font-face { font-family: 'tweetdeckold'; src: url(\"https://ton.twimg.com/tweetdeck-web/web/assets/fonts/tweetdeck-regular-webfont.5f4ea87976.woff\") format(\"woff\"); font-weight: normal; font-style: normal }
|
||||||
.icon-reply:before{content:"\\f006";font-family:tweetdeckold}
|
.icon-reply:before{content:"\\f006";font-family:tweetdeckold}
|
||||||
|
@@ -61,15 +61,13 @@
|
|||||||
<option value="16px">Largest (16px)</option>
|
<option value="16px">Largest (16px)</option>
|
||||||
<option value="custom">Custom</option>
|
<option value="custom">Custom</option>
|
||||||
</select>
|
</select>
|
||||||
|
<label class="checkbox">
|
||||||
<!-- ADVANCED -->
|
<input data-td-key="increaseQuoteTextSize" class="js-theme-checkbox touch-larger-label" type="checkbox">
|
||||||
|
Increase quoted tweet font size
|
||||||
<label class="txt-uppercase touch-larger-label">
|
|
||||||
<b>Advanced</b>
|
|
||||||
</label>
|
</label>
|
||||||
<label class="checkbox">
|
<label class="checkbox">
|
||||||
<input data-td-key="optimizeAnimations" class="js-theme-checkbox touch-larger-label" type="checkbox">
|
<input data-td-key="smallComposeTextSize" class="js-theme-checkbox touch-larger-label" type="checkbox">
|
||||||
Use more memory for smoother animations
|
Small tweet input font size
|
||||||
</label>
|
</label>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@@ -102,9 +100,15 @@
|
|||||||
<input data-td-key="revertIcons" class="js-theme-checkbox touch-larger-label" type="checkbox">
|
<input data-td-key="revertIcons" class="js-theme-checkbox touch-larger-label" type="checkbox">
|
||||||
Revert icon design
|
Revert icon design
|
||||||
</label>
|
</label>
|
||||||
|
|
||||||
|
<!-- ADVANCED -->
|
||||||
|
|
||||||
|
<label class="txt-uppercase touch-larger-label">
|
||||||
|
<b>Advanced</b>
|
||||||
|
</label>
|
||||||
<label class="checkbox">
|
<label class="checkbox">
|
||||||
<input data-td-key="smallComposeTextSize" class="js-theme-checkbox touch-larger-label" type="checkbox">
|
<input data-td-key="optimizeAnimations" class="js-theme-checkbox touch-larger-label" type="checkbox">
|
||||||
Small compose tweet font size
|
Use more memory for smoother animations
|
||||||
</label>
|
</label>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@@ -163,11 +167,12 @@
|
|||||||
.td-modal-inner-cols .l-column {
|
.td-modal-inner-cols .l-column {
|
||||||
padding: 15px 9px;
|
padding: 15px 9px;
|
||||||
box-sizing: border-box;
|
box-sizing: border-box;
|
||||||
|
width: 225px;
|
||||||
font-size: 0; /* fix custom font size breaking the modal layout */
|
font-size: 0; /* fix custom font size breaking the modal layout */
|
||||||
}
|
}
|
||||||
|
|
||||||
.td-modal-inner-cols .l-column:nth-child(2) {
|
.td-modal-inner-cols .l-column:nth-child(3) {
|
||||||
width: 250px;
|
width: 200px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.td-modal-inner-full {
|
.td-modal-inner-full {
|
||||||
@@ -199,6 +204,14 @@
|
|||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.td-modal-content select + label.checkbox {
|
||||||
|
margin-top: 9px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.td-modal-content input.js-theme-checkbox, .td-modal-content input.js-theme-radio {
|
||||||
|
margin-top: 1px;
|
||||||
|
}
|
||||||
|
|
||||||
/* Avatar shape */
|
/* Avatar shape */
|
||||||
|
|
||||||
.td-avatar-shape-container {
|
.td-avatar-shape-container {
|
||||||
|
@@ -9,7 +9,7 @@ Emoji keyboard
|
|||||||
chylex
|
chylex
|
||||||
|
|
||||||
[version]
|
[version]
|
||||||
1.4
|
1.4.1
|
||||||
|
|
||||||
[website]
|
[website]
|
||||||
https://tweetduck.chylex.com
|
https://tweetduck.chylex.com
|
||||||
|
@@ -303,23 +303,26 @@ enabled(){
|
|||||||
let firstColon = val.lastIndexOf(':', ele[0].selectionStart);
|
let firstColon = val.lastIndexOf(':', ele[0].selectionStart);
|
||||||
return if firstColon === -1;
|
return if firstColon === -1;
|
||||||
|
|
||||||
let search = val.substring(firstColon+1, ele[0].selectionStart);
|
let search = val.substring(firstColon+1, ele[0].selectionStart).toLowerCase();
|
||||||
return if !/^[a-z_]+$/i.test(search);
|
return if !/^[a-z_]+$/.test(search);
|
||||||
|
|
||||||
let keywords = search.split("_").filter(kw => kw.length > 0).map(kw => kw.toLowerCase());
|
let keywords = search.split("_").filter(kw => kw.length > 0).map(kw => kw.toLowerCase());
|
||||||
return if keywords.length === 0;
|
return if keywords.length === 0;
|
||||||
|
|
||||||
let foundName = me.emojiNames.filter(name => keywords.every(kw => name.includes(kw)));
|
let foundNames = me.emojiNames.filter(name => keywords.every(kw => name.includes(kw)));
|
||||||
|
|
||||||
if (foundName.length === 0){
|
if (foundNames.length === 0){
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
else if (foundNames.length > 1 && foundNames.includes(search)){
|
||||||
|
foundNames = [ search ];
|
||||||
|
}
|
||||||
|
|
||||||
lastEmojiKeyword = `:${search}:`;
|
lastEmojiKeyword = `:${search}:`;
|
||||||
lastEmojiPosition = lastEmojiLength = 0;
|
lastEmojiPosition = lastEmojiLength = 0;
|
||||||
|
|
||||||
if (foundName.length === 1){
|
if (foundNames.length === 1){
|
||||||
let foundIndex = me.emojiNames.indexOf(foundName[0]);
|
let foundIndex = me.emojiNames.indexOf(foundNames[0]);
|
||||||
let foundEmoji;
|
let foundEmoji;
|
||||||
|
|
||||||
for(let array of [ me.emojiData1, me.emojiData2[me.selectedSkinTone], me.emojiData3 ]){
|
for(let array of [ me.emojiData1, me.emojiData2[me.selectedSkinTone], me.emojiData3 ]){
|
||||||
@@ -346,7 +349,7 @@ enabled(){
|
|||||||
lastEmojiLength = foundEmoji.length;
|
lastEmojiLength = foundEmoji.length;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (foundName.length > 1){
|
else if (foundNames.length > 1){
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
ele.val(val.substring(0, firstColon)+val.substring(ele[0].selectionStart));
|
ele.val(val.substring(0, firstColon)+val.substring(ele[0].selectionStart));
|
||||||
ele[0].selectionEnd = ele[0].selectionStart = firstColon;
|
ele[0].selectionEnd = ele[0].selectionStart = firstColon;
|
||||||
|
@@ -8,7 +8,7 @@ Custom reply account
|
|||||||
chylex
|
chylex
|
||||||
|
|
||||||
[version]
|
[version]
|
||||||
1.2.3
|
1.2.4
|
||||||
|
|
||||||
[website]
|
[website]
|
||||||
https://tweetduck.chylex.com
|
https://tweetduck.chylex.com
|
||||||
@@ -20,4 +20,4 @@ configuration.js
|
|||||||
configuration.default.js
|
configuration.default.js
|
||||||
|
|
||||||
[requires]
|
[requires]
|
||||||
1.8
|
1.10.3
|
@@ -6,7 +6,7 @@ enabled(){
|
|||||||
this.lastSelectedAccount = null;
|
this.lastSelectedAccount = null;
|
||||||
|
|
||||||
this.uiComposeTweetEvent = (e, data) => {
|
this.uiComposeTweetEvent = (e, data) => {
|
||||||
return if data.type !== "reply" || data.popFromInline || !("element" in data);
|
return if !(data.type === "reply" || (data.type === "tweet" && "quotedTweet" in data)) || data.popFromInline || !("element" in data);
|
||||||
|
|
||||||
var query;
|
var query;
|
||||||
|
|
||||||
|
@@ -3,6 +3,18 @@ $ErrorActionPreference = "Stop"
|
|||||||
|
|
||||||
Set-Location $dir
|
Set-Location $dir
|
||||||
|
|
||||||
|
function Check-Carriage-Return{
|
||||||
|
Param([Parameter(Mandatory = $True, Position = 1)] $fname)
|
||||||
|
|
||||||
|
$file = @(Get-ChildItem -Include $fname -Recurse)[0]
|
||||||
|
|
||||||
|
if ((Get-Content -Path $file.FullName -Raw).Contains("`r")){
|
||||||
|
Throw "$fname cannot contain carriage return"
|
||||||
|
}
|
||||||
|
|
||||||
|
Write-Host "Verified" $file.FullName.Substring($dir.Length)
|
||||||
|
}
|
||||||
|
|
||||||
function Rewrite-File{
|
function Rewrite-File{
|
||||||
[CmdletBinding()]
|
[CmdletBinding()]
|
||||||
Param([Parameter(Mandatory = $True, ValueFromPipeline = $True)][array] $lines, [Parameter(Mandatory = $True, Position = 1)] $file)
|
Param([Parameter(Mandatory = $True, ValueFromPipeline = $True)][array] $lines, [Parameter(Mandatory = $True, Position = 1)] $file)
|
||||||
@@ -11,23 +23,31 @@ function Rewrite-File{
|
|||||||
Write-Host "Processed" $file.FullName.Substring($dir.Length)
|
Write-Host "Processed" $file.FullName.Substring($dir.Length)
|
||||||
}
|
}
|
||||||
|
|
||||||
ForEach($file in Get-ChildItem -Include *.js -Exclude configuration.default.js -Recurse){
|
try{
|
||||||
$lines = Get-Content -Path $file.FullName
|
Check-Carriage-Return("emoji-ordering.txt")
|
||||||
$lines = $lines | % { $_.TrimStart() }
|
|
||||||
$lines = $lines -Replace '^(.*?)((?<=^|[;{}()])\s?//(?:\s.*|$))?$', '$1'
|
|
||||||
$lines = $lines -Replace '(?<!\w)return(\s.*?)? if (.*?);', 'if ($2)return$1;'
|
|
||||||
,$lines | Rewrite-File $file
|
|
||||||
}
|
|
||||||
|
|
||||||
ForEach($file in Get-ChildItem -Include *.css -Recurse){
|
ForEach($file in Get-ChildItem -Filter *.js -Exclude configuration.default.js -Recurse){
|
||||||
$lines = Get-Content -Path $file.FullName
|
$lines = Get-Content -Path $file.FullName
|
||||||
$lines = $lines -Replace '\s*/\*.*?\*/', ''
|
$lines = $lines | % { $_.TrimStart() }
|
||||||
$lines = $lines -Replace '^\s+(.+):\s?(.+?)(?:\s?(!important))?;$', '$1:$2$3;'
|
$lines = $lines -Replace '^(.*?)((?<=^|[;{}()])\s?//(?:\s.*|$))?$', '$1'
|
||||||
$lines = $lines -Replace '^(\S.*?) {$', '$1{'
|
$lines = $lines -Replace '(?<!\w)return(\s.*?)? if (.*?);', 'if ($2)return$1;'
|
||||||
@(($lines | Where { $_ -ne '' }) -Join ' ') | Rewrite-File $file
|
,$lines | Rewrite-File $file
|
||||||
}
|
}
|
||||||
|
|
||||||
ForEach($file in Get-ChildItem -Include *.html -Recurse){
|
ForEach($file in Get-ChildItem -Filter *.css -Recurse){
|
||||||
$lines = Get-Content -Path $file.FullName
|
$lines = Get-Content -Path $file.FullName
|
||||||
,($lines | % { $_.TrimStart() }) | Rewrite-File $file
|
$lines = $lines -Replace '\s*/\*.*?\*/', ''
|
||||||
|
$lines = $lines -Replace '^\s+(.+):\s?(.+?)(?:\s?(!important))?;$', '$1:$2$3;'
|
||||||
|
$lines = $lines -Replace '^(\S.*?) {$', '$1{'
|
||||||
|
@(($lines | Where { $_ -ne '' }) -Join ' ') | Rewrite-File $file
|
||||||
|
}
|
||||||
|
|
||||||
|
ForEach($file in Get-ChildItem -Filter *.html -Recurse){
|
||||||
|
$lines = Get-Content -Path $file.FullName
|
||||||
|
,($lines | % { $_.TrimStart() }) | Rewrite-File $file
|
||||||
|
}
|
||||||
|
}catch{
|
||||||
|
Write-Host "Encountered an error while running PostBuild.ps1 on line" $_.InvocationInfo.ScriptLineNumber
|
||||||
|
Write-Host $_
|
||||||
|
Exit 1
|
||||||
}
|
}
|
||||||
|
@@ -14,6 +14,11 @@
|
|||||||
//
|
//
|
||||||
var onAppReady = [];
|
var onAppReady = [];
|
||||||
|
|
||||||
|
//
|
||||||
|
// Variable: DOM HTML element.
|
||||||
|
//
|
||||||
|
var doc = document.documentElement;
|
||||||
|
|
||||||
//
|
//
|
||||||
// Variable: DOM object containing the main app element.
|
// Variable: DOM object containing the main app element.
|
||||||
//
|
//
|
||||||
@@ -258,49 +263,62 @@
|
|||||||
})();
|
})();
|
||||||
|
|
||||||
//
|
//
|
||||||
// Function: Retrieves the tags to be put into <head> for notification HTML code.
|
// Block: Hook into settings object to detect when the settings change, and update html attributes and notification layout.
|
||||||
//
|
//
|
||||||
var getNotificationHeadContents = function(){
|
(function(){
|
||||||
let tags = [];
|
let refreshSettings = function(){
|
||||||
|
let fontSizeName = TD.settings.getFontSize();
|
||||||
|
let themeName = TD.settings.getTheme();
|
||||||
|
|
||||||
$(document.head).children("link[rel='stylesheet']:not([title]),link[title='"+TD.settings.getTheme()+"'],meta[charset],meta[http-equiv]").each(function(){
|
let tags = [
|
||||||
tags.push($(this)[0].outerHTML);
|
`<html class='os-windows ${(doc.getAttribute("class").match(/txt-\S+/) || [ "txt-size--14" ])[0]}' data-td-font='${fontSizeName}' data-td-theme='${themeName}'><head>`
|
||||||
|
];
|
||||||
|
|
||||||
|
$(document.head).children("link[rel='stylesheet']:not([title]),link[title='"+themeName+"'],meta[charset],meta[http-equiv]").each(function(){
|
||||||
|
tags.push($(this)[0].outerHTML);
|
||||||
|
});
|
||||||
|
|
||||||
|
tags.push("<style type='text/css'>");
|
||||||
|
tags.push("body { background: "+getClassStyleProperty("column", "background-color")+" }"); // set background color
|
||||||
|
tags.push("a[data-full-url] { word-break: break-all }"); // break long urls
|
||||||
|
tags.push(".media-item, .media-preview { border-radius: 1px !important }"); // square-ify media
|
||||||
|
tags.push(".quoted-tweet { border-radius: 0 !important }"); // square-ify quoted tweets
|
||||||
|
tags.push(".activity-header { align-items: center !important; margin-bottom: 4px }"); // tweak alignment of avatar and text in notifications
|
||||||
|
tags.push(".activity-header .tweet-timestamp { line-height: unset }"); // fix timestamp position in notifications
|
||||||
|
|
||||||
|
if (fontSizeName === "smallest"){
|
||||||
|
tags.push(".badge-verified:before { width: 13px !important; height: 13px !important; background-position: -223px -98px !important }"); // fix cut off badge icon
|
||||||
|
}
|
||||||
|
|
||||||
|
tags.push("</style>");
|
||||||
|
|
||||||
|
doc.setAttribute("data-td-font", fontSizeName);
|
||||||
|
doc.setAttribute("data-td-theme", themeName);
|
||||||
|
$TD.loadNotificationLayout(fontSizeName, tags.join(""));
|
||||||
|
};
|
||||||
|
|
||||||
|
TD.settings.setFontSize = appendToFunction(TD.settings.setFontSize, function(name){
|
||||||
|
setTimeout(refreshSettings, 0);
|
||||||
});
|
});
|
||||||
|
|
||||||
tags.push("<style type='text/css'>");
|
TD.settings.setTheme = appendToFunction(TD.settings.setTheme, function(name){
|
||||||
tags.push("body { background: "+getClassStyleProperty("column", "background-color")+" }"); // set background color
|
setTimeout(refreshSettings, 0);
|
||||||
tags.push("a[data-full-url] { word-break: break-all }"); // break long urls
|
});
|
||||||
tags.push(".txt-base-smallest .badge-verified:before { width: 13px !important; height: 13px !important; background-position: -223px -98px !important }"); // fix cut off badge icon
|
|
||||||
tags.push(".media-item, .media-preview { border-radius: 1px !important }"); // square-ify media
|
|
||||||
tags.push(".quoted-tweet { border-radius: 0 !important }"); // square-ify quoted tweets
|
|
||||||
tags.push(".activity-header { align-items: center !important; margin-bottom: 4px }"); // tweak alignment of avatar and text in notifications
|
|
||||||
tags.push(".activity-header .tweet-timestamp { line-height: unset }"); // fix timestamp position in notifications
|
|
||||||
tags.push("</style>");
|
|
||||||
|
|
||||||
return tags.join("");
|
onAppReady.push(refreshSettings);
|
||||||
};
|
})();
|
||||||
|
|
||||||
//
|
//
|
||||||
// Block: Hook into settings object to detect when the settings change.
|
// Block: Fix OS name.
|
||||||
//
|
//
|
||||||
TD.settings.setFontSize = appendToFunction(TD.settings.setFontSize, function(name){
|
if (ensurePropertyExists(TD, "util", "getOSName")){
|
||||||
$TD.loadFontSizeClass(name);
|
TD.util.getOSName = function(){
|
||||||
});
|
return "windows";
|
||||||
|
};
|
||||||
|
|
||||||
TD.settings.setTheme = appendToFunction(TD.settings.setTheme, function(name){
|
doc.classList.remove("os-");
|
||||||
document.documentElement.setAttribute("data-td-theme", name);
|
doc.classList.add("os-windows");
|
||||||
|
}
|
||||||
setTimeout(function(){
|
|
||||||
$TD.loadNotificationHeadContents(getNotificationHeadContents());
|
|
||||||
}, 0);
|
|
||||||
});
|
|
||||||
|
|
||||||
onAppReady.push(function(){
|
|
||||||
document.documentElement.setAttribute("data-td-theme", TD.settings.getTheme());
|
|
||||||
|
|
||||||
$TD.loadFontSizeClass(TD.settings.getFontSize());
|
|
||||||
$TD.loadNotificationHeadContents(getNotificationHeadContents());
|
|
||||||
});
|
|
||||||
|
|
||||||
//
|
//
|
||||||
// Block: Enable popup notifications.
|
// Block: Enable popup notifications.
|
||||||
@@ -796,25 +814,63 @@
|
|||||||
});
|
});
|
||||||
|
|
||||||
//
|
//
|
||||||
// Block: Make middle click on tweet reply icon open the compose drawer. Only works for non-temporary columns.
|
// Block: Make middle click on tweet reply icon open the compose drawer, retweet icon trigger a quote, and favorite icon open a 'Like from accounts...' modal.
|
||||||
//
|
//
|
||||||
app.delegate(".js-reply-action", "auxclick", function(e){
|
app.delegate(".tweet-action,.tweet-detail-action", "auxclick", function(e){
|
||||||
if (e.which === 2){
|
return if e.which !== 2;
|
||||||
let column = $(this).closest(".js-column");
|
|
||||||
|
|
||||||
if (column && column.hasClass("column") && $("[data-drawer='compose']").hasClass("is-hidden")){
|
let column = TD.controller.columnManager.get($(this).closest("section.js-column").attr("data-column"));
|
||||||
$(document).trigger("uiDrawerShowDrawer", {
|
return if !column;
|
||||||
drawer: "compose",
|
|
||||||
withAnimation: true
|
let ele = $(this).closest("article");
|
||||||
|
let tweet = column.findChirp(ele.attr("data-tweet-id")) || column.findChirp(ele.attr("data-key"));
|
||||||
|
return if !tweet;
|
||||||
|
|
||||||
|
switch($(this).attr("rel")){
|
||||||
|
case "reply":
|
||||||
|
let main = tweet.getMainTweet();
|
||||||
|
|
||||||
|
$(document).trigger("uiDockedComposeTweet", {
|
||||||
|
type: "reply",
|
||||||
|
from: [ tweet.account.getKey() ],
|
||||||
|
inReplyTo: {
|
||||||
|
id: tweet.id,
|
||||||
|
htmlText: main.htmlText,
|
||||||
|
user: {
|
||||||
|
screenName: main.user.screenName,
|
||||||
|
name: main.user.name,
|
||||||
|
profileImageURL: main.user.profileImageURL
|
||||||
|
}
|
||||||
|
},
|
||||||
|
mentions: tweet.getReplyUsers(),
|
||||||
|
element: ele
|
||||||
});
|
});
|
||||||
|
|
||||||
window.setTimeout(() => $(this).trigger("click"), 1);
|
break;
|
||||||
}
|
|
||||||
|
|
||||||
e.preventDefault();
|
case "favorite":
|
||||||
e.stopPropagation();
|
$(document).trigger("uiShowFavoriteFromOptions", { tweet });
|
||||||
e.stopImmediatePropagation();
|
break;
|
||||||
|
|
||||||
|
case "retweet":
|
||||||
|
TD.controller.stats.quoteTweet();
|
||||||
|
|
||||||
|
$(document).trigger("uiComposeTweet", {
|
||||||
|
type: "tweet",
|
||||||
|
from: [ tweet.account.getKey() ],
|
||||||
|
quotedTweet: tweet.getMainTweet(),
|
||||||
|
element: ele // triggers reply-account plugin
|
||||||
|
});
|
||||||
|
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
e.preventDefault();
|
||||||
|
e.stopPropagation();
|
||||||
|
e.stopImmediatePropagation();
|
||||||
});
|
});
|
||||||
|
|
||||||
//
|
//
|
||||||
@@ -872,12 +928,12 @@
|
|||||||
// Block: Setup video player hooks.
|
// Block: Setup video player hooks.
|
||||||
//
|
//
|
||||||
(function(){
|
(function(){
|
||||||
var playVideo = function(url){
|
window.TDGF_playVideo = function(url, username){
|
||||||
$('<div id="td-video-player-overlay" class="ovl" style="display:block"></div>').on("click contextmenu", function(){
|
$('<div id="td-video-player-overlay" class="ovl" style="display:block"></div>').on("click contextmenu", function(){
|
||||||
$TD.playVideo(null);
|
$TD.playVideo(null, null);
|
||||||
}).appendTo(app);
|
}).appendTo(app);
|
||||||
|
|
||||||
$TD.playVideo(url);
|
$TD.playVideo(url, username || null);
|
||||||
};
|
};
|
||||||
|
|
||||||
var getVideoTweetLink = function(obj){
|
var getVideoTweetLink = function(obj){
|
||||||
@@ -886,12 +942,16 @@
|
|||||||
return link.attr("href");
|
return link.attr("href");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var getUsername = function(tweet){
|
||||||
|
return tweet && (tweet.quotedTweet || tweet).getMainUser().screenName;
|
||||||
|
}
|
||||||
|
|
||||||
app.delegate(".js-gif-play", {
|
app.delegate(".js-gif-play", {
|
||||||
click: function(e){
|
click: function(e){
|
||||||
let src = !e.ctrlKey && $(this).closest(".js-media-gif-container").find("video").attr("src");
|
let src = !e.ctrlKey && $(this).closest(".js-media-gif-container").find("video").attr("src");
|
||||||
|
|
||||||
if (src){
|
if (src){
|
||||||
playVideo(src);
|
window.TDGF_playVideo(src, getUsername(highlightedTweetObj));
|
||||||
}
|
}
|
||||||
else{
|
else{
|
||||||
$TD.openBrowser(getVideoTweetLink($(this)));
|
$TD.openBrowser(getVideoTweetLink($(this)));
|
||||||
@@ -927,7 +987,7 @@
|
|||||||
let media = this.chirp.getMedia().find(media => media.mediaId === this.clickedMediaEntityId);
|
let media = this.chirp.getMedia().find(media => media.mediaId === this.clickedMediaEntityId);
|
||||||
|
|
||||||
if (media && media.isVideo && media.service === "twitter"){
|
if (media && media.isVideo && media.service === "twitter"){
|
||||||
playVideo(media.chooseVideoVariant().url);
|
window.TDGF_playVideo(media.chooseVideoVariant().url, getUsername(this.chirp));
|
||||||
cancelModal = true;
|
cancelModal = true;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
@@ -3,7 +3,7 @@
|
|||||||
<div class="js-tweet tweet">
|
<div class="js-tweet tweet">
|
||||||
<header class="tweet-header">
|
<header class="tweet-header">
|
||||||
<time class="tweet-timestamp js-timestamp pull-right txt-mute">
|
<time class="tweet-timestamp js-timestamp pull-right txt-mute">
|
||||||
<a target="_blank" rel="url" href="https://twitter.com/chylexmc" class="txt-small">0s</a>
|
<a target="_blank" rel="url" href="https://twitter.com/chylexmc" class="txt-size-variable--12">0s</a>
|
||||||
</time>
|
</time>
|
||||||
<a target="_blank" rel="user" href="https://twitter.com/chylexmc" class="account-link link-complex block">
|
<a target="_blank" rel="user" href="https://twitter.com/chylexmc" class="account-link link-complex block">
|
||||||
<div class="obj-left item-img tweet-img">
|
<div class="obj-left item-img tweet-img">
|
||||||
|
@@ -87,14 +87,14 @@
|
|||||||
};
|
};
|
||||||
|
|
||||||
//
|
//
|
||||||
// Block: Setup global function to change plugin state.
|
// Block: Setup a function to change plugin state.
|
||||||
//
|
//
|
||||||
window.TDPF_setPluginState = function(identifier, enable){
|
window.TDPF_setPluginState = function(identifier, enable){
|
||||||
window.TD_PLUGINS.setState(window.TD_PLUGINS.findObject(identifier), enable);
|
window.TD_PLUGINS.setState(window.TD_PLUGINS.findObject(identifier), enable);
|
||||||
};
|
};
|
||||||
|
|
||||||
//
|
//
|
||||||
// Block: Setup global function to reload the page.
|
// Block: Setup a function to reload the page.
|
||||||
//
|
//
|
||||||
window.TDPF_requestReload = function(){
|
window.TDPF_requestReload = function(){
|
||||||
if (!isReloading){
|
if (!isReloading){
|
||||||
@@ -102,4 +102,9 @@
|
|||||||
isReloading = true;
|
isReloading = true;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
//
|
||||||
|
// Block: Setup a function to allow plugins to play video.
|
||||||
|
//
|
||||||
|
window.TDPF_playVideo = window.TDGF_playVideo;
|
||||||
})();
|
})();
|
||||||
|
@@ -38,11 +38,15 @@
|
|||||||
/* Square-ify stuff */
|
/* Square-ify stuff */
|
||||||
/********************/
|
/********************/
|
||||||
|
|
||||||
.btn, .mdl, .mdl-content, .app-search-fake, .app-search-input, .popover, .lst-modal, .media-item, .media-preview, .tooltip-inner {
|
.btn, .mdl, .mdl-content, .app-search-fake, .app-search-input, .popover, .lst-modal, .tooltip-inner {
|
||||||
border-radius: 1px !important;
|
border-radius: 1px !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
.compose-text-container, .compose-reply-tweet, .compose-message-recipient-input-container, .compose-message-recipient {
|
.media-item, .media-preview, .media-image, .js-media-added .br--4 {
|
||||||
|
border-radius: 1px !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.compose-text-container, .compose-reply-tweet, .compose-message-recipient-input-container, .compose-message-recipient, .compose-media-bar-holder, .media-grid-container, .js-quote-tweet-holder {
|
||||||
border-radius: 0 !important;
|
border-radius: 0 !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -164,14 +168,14 @@ a[data-full-url] {
|
|||||||
vertical-align: 10%;
|
vertical-align: 10%;
|
||||||
}
|
}
|
||||||
|
|
||||||
.txt-base-smallest .sprite-verified-mini {
|
html[data-td-font='smallest'] .sprite-verified-mini {
|
||||||
/* fix cut off badge when zoomed in */
|
/* fix cut off badge when zoomed in */
|
||||||
width: 13px !important;
|
width: 13px !important;
|
||||||
height: 13px !important;
|
height: 13px !important;
|
||||||
background-position: -223px -99px !important;
|
background-position: -223px -99px !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
.txt-base-smallest .badge-verified:before {
|
html[data-td-font='smallest'] .badge-verified:before {
|
||||||
/* fix cut off badge in notifications */
|
/* fix cut off badge in notifications */
|
||||||
width: 13px !important;
|
width: 13px !important;
|
||||||
height: 13px !important;
|
height: 13px !important;
|
||||||
|
@@ -31,7 +31,7 @@ namespace TweetDuck.Updates{
|
|||||||
timerDownloadCheck.Stop();
|
timerDownloadCheck.Stop();
|
||||||
|
|
||||||
if (FormMessage.Error("Update Has Failed", "Could not download the update: "+(updateInfo.DownloadError?.Message ?? "unknown error")+"\n\nDo you want to open the website and try downloading the update manually?", FormMessage.Yes, FormMessage.No)){
|
if (FormMessage.Error("Update Has Failed", "Could not download the update: "+(updateInfo.DownloadError?.Message ?? "unknown error")+"\n\nDo you want to open the website and try downloading the update manually?", FormMessage.Yes, FormMessage.No)){
|
||||||
BrowserUtils.OpenExternalBrowserUnsafe(Program.Website);
|
BrowserUtils.OpenExternalBrowser(Program.Website);
|
||||||
DialogResult = DialogResult.OK;
|
DialogResult = DialogResult.OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user