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

Compare commits

...

42 Commits
1.14 ... 1.14.3

Author SHA1 Message Date
ed1bee8b89 Release 1.14.3 2018-06-10 20:13:05 +02:00
a8e1492056 Push pin icon to the repository 2018-06-08 10:16:58 +02:00
5587216c01 Fix one more case of breaking overlays (account dialog) 2018-06-07 17:48:52 +02:00
86569261ad Add a visual response when hovering filter icons under column header 2018-06-07 14:52:39 +02:00
4a9049c7aa Fix CSS change in dialog overlays breaking some cases 2018-06-07 14:09:35 +02:00
75d60a8182 Work around browser redirection when dragging links into a scrolling column 2018-06-07 13:23:19 +02:00
14d4dc2ed9 Fix more instances of cut off badges 2018-06-06 16:04:15 +02:00
fd0e1740a5 Rename SetLastRightClickInfo bridge method and make it browser-only 2018-06-06 15:11:07 +02:00
70ca890bef Fix not stripping t.co in notifications when dragging & sometimes when copying 2018-06-06 15:10:52 +02:00
b9318dfd8e Minor visual fixes (Edit List modal, set minimum column width) 2018-06-05 04:25:05 +02:00
995642a719 Add support for 1 or 2 columns on screen in edit-design plugin 2018-06-05 03:48:40 +02:00
d14de4ac9e Lower minimum width of browser window & fix modals breaking in small windows 2018-06-05 02:51:21 +02:00
b7f325a241 Minor RequestHandlerBase refactoring 2018-06-05 02:05:04 +02:00
27c55718c2 Release 1.14.2.1 2018-06-04 13:01:44 +02:00
421ff0654b Temporarily work around buggy notification scrolling 2018-06-04 12:35:34 +02:00
ed947458f9 Update fallback HTML in desktop notifications 2018-06-04 12:09:02 +02:00
9cdb20ba84 Fix several broken column types in 'Add column' modal 2018-06-04 11:02:52 +02:00
d8774b735f Release 1.14.2 2018-06-04 08:59:32 +02:00
adcb42695f Update CEF so I don't have to workaround wrong dev tools version
Closes #220
2018-06-01 22:32:44 +02:00
dd77b5bcbb Revert smooth scrolling fix and rewrite horizontal scrolling fix to avoid column jumping 2018-06-01 21:48:26 +02:00
d2445be155 Fix missing GIF previews in tweet screenshots 2018-05-31 03:07:51 +02:00
10254c8af7 Fix tweet screenshots with Aero disabled by making the window visible
Closes #223
2018-05-31 02:58:25 +02:00
d7e830badf Slightly increase default notification height for larger font sizes 2018-05-31 01:11:17 +02:00
b445a3a9b8 Fix broken reply-account advanced selector arguments after a TweetDeck update 2018-05-31 00:52:08 +02:00
97f42ead66 Make it easier to debug screenshots 2018-05-30 19:50:11 +02:00
03730fafb9 ...because I can't be bothered 2018-05-29 15:34:02 +02:00
0be9465dca Fix column icons being hidden by title with clear-columns or edit-design features on 2018-05-29 15:23:41 +02:00
d7f1df4995 Release 1.14.1 2018-05-16 13:07:47 +02:00
3cb0f90706 Prevent an unlikely crash when showing an error message in context menu 2018-05-16 13:05:59 +02:00
a3e9b15a8a Add 'Apply ROT13' to non-editable selections to allow decoding tweets 2018-05-16 12:40:49 +02:00
00bfa68a57 Fix UI issues after recent TweetDeck updates 2018-05-16 07:48:47 +02:00
c311e24f08 Make it easier to update devtools file after updating CEF 2018-05-15 12:42:57 +02:00
1cdd4e4455 Update CefSharp to 66 (early) to fix memory leak 2018-05-15 10:10:03 +02:00
8078c0081a Add a script to fix browser project references after updating CEF 2018-05-15 10:04:08 +02:00
a867e1fc40 Optimize speed and memory usage of build process for app & installers 2018-05-08 20:20:02 +02:00
61da36ac1c Update README.md 2018-05-08 19:37:06 +02:00
720ca2a018 Update README.md 2018-05-08 19:36:08 +02:00
b39c593552 Update README.md 2018-05-08 06:28:07 +02:00
c808952a45 Update README.md 2018-05-08 00:03:08 +02:00
b468d7a766 Update README.md 2018-05-07 20:03:50 +02:00
28578f60be Include plugin files in the project & update README 2018-05-07 19:35:08 +02:00
92a39e2527 Push debug configuration start arguments (-datafolder TweetDuckDebug) 2018-05-07 18:11:56 +02:00
41 changed files with 442 additions and 211 deletions

View File

@@ -6,6 +6,8 @@ namespace TweetDuck.Configuration{
// public args
public const string ArgDataFolder = "-datafolder";
public const string ArgLogging = "-log";
public const string ArgIgnoreGDPR = "-nogdpr";
public const string ArgNotificationScrollWA = "-nscrollwa";
// internal args
public const string ArgRestart = "-restart";

View File

@@ -64,6 +64,10 @@ namespace TweetDuck.Core.Bridge{
});
}
public void SetRightClickedLink(string type, string url){
ContextInfo.SetLink(type, url);
}
public void SetRightClickedChirp(string tweetUrl, string quoteUrl, string chirpAuthors, string chirpImages){
ContextInfo.SetChirp(tweetUrl, quoteUrl, chirpAuthors, chirpImages);
}
@@ -99,10 +103,6 @@ namespace TweetDuck.Core.Bridge{
// Global
public void SetLastRightClickInfo(string type, string url){
ContextInfo.SetLink(type, url);
}
public void OnTweetPopup(string columnId, string chirpId, string columnName, string tweetHtml, int tweetCharacters, string tweetUrl, string quoteUrl){
notification.InvokeAsyncSafe(() => {
form.OnTweetNotification();

View File

@@ -39,17 +39,17 @@
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
this.BackColor = TweetDuck.Core.Utils.TwitterUtils.BackgroundColor;
this.ClientSize = new System.Drawing.Size(400, 386);
this.ClientSize = new System.Drawing.Size(1008, 730);
this.Icon = Properties.Resources.icon;
this.Location = TweetDuck.Core.Controls.ControlExtensions.InvisibleLocation;
this.MinimumSize = new System.Drawing.Size(416, 424);
this.MinimumSize = new System.Drawing.Size(348, 424);
this.Name = "FormBrowser";
this.StartPosition = System.Windows.Forms.FormStartPosition.Manual;
this.Activated += new System.EventHandler(this.FormBrowser_Activated);
this.FormClosing += new System.Windows.Forms.FormClosingEventHandler(this.FormBrowser_FormClosing);
this.FormClosed += new System.Windows.Forms.FormClosedEventHandler(this.FormBrowser_FormClosed);
this.LocationChanged += new System.EventHandler(this.FormBrowser_LocationChanged);
this.ResizeEnd += new System.EventHandler(this.FormBrowser_ResizeEnd);
this.LocationChanged += new System.EventHandler(this.FormBrowser_LocationChanged);
this.Resize += new System.EventHandler(this.FormBrowser_Resize);
this.ResumeLayout(false);

View File

@@ -28,6 +28,7 @@ namespace TweetDuck.Core.Handling{
private const CefMenuCommand MenuSaveMedia = (CefMenuCommand)26506;
private const CefMenuCommand MenuSaveTweetImages = (CefMenuCommand)26507;
private const CefMenuCommand MenuSearchInBrowser = (CefMenuCommand)26508;
private const CefMenuCommand MenuReadApplyROT13 = (CefMenuCommand)26509;
private const CefMenuCommand MenuOpenDevTools = (CefMenuCommand)26599;
protected ContextInfo.LinkInfo LastLink { get; private set; }
@@ -57,6 +58,8 @@ namespace TweetDuck.Core.Handling{
if (parameters.TypeFlags.HasFlag(ContextMenuType.Selection) && !parameters.TypeFlags.HasFlag(ContextMenuType.Editable)){
model.AddItem(MenuSearchInBrowser, "Search in browser");
model.AddSeparator();
model.AddItem(MenuReadApplyROT13, "Apply ROT13");
model.AddSeparator();
}
bool hasTweetImage = LastLink.IsImage;
@@ -126,7 +129,7 @@ namespace TweetDuck.Core.Handling{
SetClipboardText(control, TwitterUtils.GetMediaLink(LastLink.GetMediaSource(parameters), ImageQuality));
break;
case MenuViewImage:
case MenuViewImage: {
void ViewImage(string path){
string ext = Path.GetExtension(path);
@@ -141,37 +144,59 @@ namespace TweetDuck.Core.Handling{
string url = LastLink.GetMediaSource(parameters);
string file = Path.Combine(BrowserCache.CacheFolder, TwitterUtils.GetImageFileName(url) ?? Path.GetRandomFileName());
if (File.Exists(file)){
ViewImage(file);
}
else{
control.InvokeAsyncSafe(analytics.AnalyticsFile.ViewedImages.Trigger);
BrowserUtils.DownloadFileAsync(TwitterUtils.GetMediaLink(url, ImageQuality), file, () => {
control.InvokeAsyncSafe(() => {
if (File.Exists(file)){
ViewImage(file);
}, ex => {
FormMessage.Error("Image Download", "An error occurred while downloading the image: "+ex.Message, FormMessage.OK);
});
}
}
else{
analytics.AnalyticsFile.ViewedImages.Trigger();
BrowserUtils.DownloadFileAsync(TwitterUtils.GetMediaLink(url, ImageQuality), file, () => {
ViewImage(file);
}, ex => {
FormMessage.Error("Image Download", "An error occurred while downloading the image: "+ex.Message, FormMessage.OK);
});
}
});
break;
}
case MenuSaveMedia: {
bool isVideo = LastLink.IsVideo;
string url = LastLink.GetMediaSource(parameters);
string username = LastChirp.Authors.LastOrDefault();
control.InvokeAsyncSafe(() => {
if (isVideo){
TwitterUtils.DownloadVideo(url, username);
analytics.AnalyticsFile.DownloadedVideos.Trigger();
}
else{
TwitterUtils.DownloadImage(url, username, ImageQuality);
analytics.AnalyticsFile.DownloadedImages.Trigger();
}
});
break;
}
case MenuSaveMedia:
if (LastLink.IsVideo){
control.InvokeAsyncSafe(analytics.AnalyticsFile.DownloadedVideos.Trigger);
TwitterUtils.DownloadVideo(LastLink.GetMediaSource(parameters), LastChirp.Authors.LastOrDefault());
}
else{
control.InvokeAsyncSafe(analytics.AnalyticsFile.DownloadedImages.Trigger);
TwitterUtils.DownloadImage(LastLink.GetMediaSource(parameters), LastChirp.Authors.LastOrDefault(), ImageQuality);
}
case MenuSaveTweetImages: {
string[] urls = LastChirp.Images;
string username = LastChirp.Authors.LastOrDefault();
control.InvokeAsyncSafe(() => {
TwitterUtils.DownloadImages(urls, username, ImageQuality);
analytics.AnalyticsFile.DownloadedImages.Trigger();
});
break;
}
case MenuSaveTweetImages:
control.InvokeAsyncSafe(analytics.AnalyticsFile.DownloadedImages.Trigger);
TwitterUtils.DownloadImages(LastChirp.Images, LastChirp.Authors.LastOrDefault(), ImageQuality);
break;
case MenuReadApplyROT13:
string selection = parameters.SelectionText;
control.InvokeAsyncSafe(() => FormMessage.Information("ROT13", StringUtils.ConvertRot13(selection), FormMessage.OK));
return true;
case MenuSearchInBrowser:
string query = parameters.SelectionText;

View File

@@ -16,7 +16,7 @@ namespace TweetDuck.Core.Handling{
private const CefMenuCommand MenuOpenQuotedTweetUrl = (CefMenuCommand)26612;
private const CefMenuCommand MenuCopyQuotedTweetUrl = (CefMenuCommand)26613;
private const CefMenuCommand MenuScreenshotTweet = (CefMenuCommand)26614;
private const CefMenuCommand MenuInputApplyROT13 = (CefMenuCommand)26615;
private const CefMenuCommand MenuWriteApplyROT13 = (CefMenuCommand)26615;
private const CefMenuCommand MenuSearchInColumn = (CefMenuCommand)26616;
private const string TitleReloadBrowser = "Reload browser";
@@ -44,7 +44,7 @@ namespace TweetDuck.Core.Handling{
if (isSelecting){
if (isEditing){
model.AddSeparator();
model.AddItem(MenuInputApplyROT13, "Apply ROT13");
model.AddItem(MenuWriteApplyROT13, "Apply ROT13");
}
model.AddSeparator();
@@ -141,7 +141,7 @@ namespace TweetDuck.Core.Handling{
SetClipboardText(form, LastChirp.QuoteUrl);
return true;
case MenuInputApplyROT13:
case MenuWriteApplyROT13:
form.InvokeAsyncSafe(form.ApplyROT13);
return true;

View File

@@ -4,10 +4,18 @@ using CefSharp.Enums;
namespace TweetDuck.Core.Handling{
sealed class DragHandlerBrowser : IDragHandler{
private readonly RequestHandlerBrowser requestHandler;
public DragHandlerBrowser(RequestHandlerBrowser requestHandler){
this.requestHandler = requestHandler;
}
public bool OnDragEnter(IWebBrowser browserControl, IBrowser browser, IDragData dragData, DragOperationsMask mask){
void TriggerDragStart(string type, string data = null){
browserControl.ExecuteScriptAsync("window.TDGF_onGlobalDragStart", type, data);
}
requestHandler.BlockNextUserNavUrl = dragData.LinkUrl; // empty if not a link
if (dragData.IsLink){
TriggerDragStart("link", dragData.LinkUrl);

View File

@@ -5,6 +5,12 @@ using TweetDuck.Core.Handling.General;
namespace TweetDuck.Core.Handling{
class RequestHandlerBase : DefaultRequestHandler{
private readonly bool autoReload;
public RequestHandlerBase(bool autoReload){
this.autoReload = autoReload;
}
public override bool OnOpenUrlFromTab(IWebBrowser browserControl, IBrowser browser, IFrame frame, string targetUrl, WindowOpenDisposition targetDisposition, bool userGesture){
return LifeSpanHandler.HandleLinkClick(browserControl, targetDisposition, targetUrl);
}
@@ -18,5 +24,11 @@ namespace TweetDuck.Core.Handling{
return base.OnBeforeResourceLoad(browserControl, browser, frame, request, callback);
}
public override void OnRenderProcessTerminated(IWebBrowser browserControl, IBrowser browser, CefTerminationStatus status){
if (autoReload){
browser.Reload();
}
}
}
}

View File

@@ -3,9 +3,9 @@ using TweetDuck.Core.Utils;
namespace TweetDuck.Core.Handling{
sealed class RequestHandlerBrowser : RequestHandlerBase{
public override void OnRenderProcessTerminated(IWebBrowser browserControl, IBrowser browser, CefTerminationStatus status){
browser.Reload();
}
public string BlockNextUserNavUrl { get; set; }
public RequestHandlerBrowser() : base(true){}
public override CefReturnValue OnBeforeResourceLoad(IWebBrowser browserControl, IBrowser browser, IFrame frame, IRequest request, IRequestCallback callback){
if (request.ResourceType == ResourceType.Script && request.Url.Contains("analytics.")){
@@ -16,6 +16,16 @@ namespace TweetDuck.Core.Handling{
return base.OnBeforeResourceLoad(browserControl, browser, frame, request, callback);
}
public override bool OnBeforeBrowse(IWebBrowser browserControl, IBrowser browser, IFrame frame, IRequest request, bool userGesture, bool isRedirect){
if (userGesture && request.TransitionType == TransitionType.LinkClicked){
bool block = request.Url == BlockNextUserNavUrl;
BlockNextUserNavUrl = string.Empty;
return block;
}
return base.OnBeforeBrowse(browserControl, browser, frame, request, userGesture, isRedirect);
}
public override bool OnResourceResponse(IWebBrowser browserControl, IBrowser browser, IFrame frame, IRequest request, IResponse response){
if (request.ResourceType == ResourceType.Image && request.Url.Contains("backgrounds/spinner_blue")){
request.Url = TwitterUtils.LoadingSpinner.Url;

View File

@@ -124,7 +124,7 @@ namespace TweetDuck.Core.Notification{
MenuHandler = new ContextMenuNotification(this, enableContextMenu),
JsDialogHandler = new JavaScriptDialogHandler(),
LifeSpanHandler = new LifeSpanHandler(),
RequestHandler = new RequestHandlerBase()
RequestHandler = new RequestHandlerBase(false)
};
this.browser.Dock = DockStyle.None;

View File

@@ -2,6 +2,7 @@
using System;
using System.Drawing;
using System.Windows.Forms;
using TweetDuck.Configuration;
using TweetDuck.Core.Bridge;
using TweetDuck.Core.Controls;
using TweetDuck.Core.Handling;
@@ -65,7 +66,7 @@ namespace TweetDuck.Core.Notification{
get{
switch(Program.UserConfig.NotificationSize){
default:
return BrowserUtils.Scale(122, SizeScale*(1.0+0.075*FontSizeLevel));
return BrowserUtils.Scale(122, SizeScale*(1.0+0.08*FontSizeLevel));
case TweetNotification.Size.Custom:
return Program.UserConfig.CustomNotificationSize.Height;
@@ -136,7 +137,14 @@ namespace TweetDuck.Core.Notification{
int eventType = wParam.ToInt32();
if (eventType == NativeMethods.WM_MOUSEWHEEL && IsCursorOverBrowser){
browser.SendMouseWheelEvent(0, 0, 0, BrowserUtils.Scale(NativeMethods.GetMouseHookData(lParam), Program.UserConfig.NotificationScrollSpeed*0.01), CefEventFlags.None);
if (Arguments.HasFlag(Arguments.ArgNotificationScrollWA)){
int delta = BrowserUtils.Scale(NativeMethods.GetMouseHookData(lParam), Program.UserConfig.NotificationScrollSpeed*0.01);
browser.ExecuteScriptAsync("window.scrollBy", 0, -Math.Round(delta/0.72));
}
else{
browser.SendMouseWheelEvent(0, 0, 0, BrowserUtils.Scale(NativeMethods.GetMouseHookData(lParam), Program.UserConfig.NotificationScrollSpeed*0.01), CefEventFlags.None);
}
return NativeMethods.HOOK_HANDLED;
}
else if (eventType == NativeMethods.WM_XBUTTONDOWN && DesktopBounds.Contains(Cursor.Position)){

View File

@@ -35,7 +35,7 @@ namespace TweetDuck.Core.Notification.Screenshot{
}
using(IFrame frame = args.Browser.MainFrame){
ScriptLoader.ExecuteScript(frame, script.Replace("{width}", BrowserUtils.Scale(width, DpiScale).ToString()), "screenshot");
ScriptLoader.ExecuteScript(frame, script.Replace("{width}", BrowserUtils.Scale(width, DpiScale).ToString()).Replace("{frames}", TweetScreenshotManager.WaitFrames.ToString()), "gen:screenshot");
}
};
@@ -68,6 +68,10 @@ namespace TweetDuck.Core.Notification.Screenshot{
return false;
}
}
if (!WindowsUtils.IsAeroEnabled){
MoveToVisibleLocation(); // TODO make this look nicer I guess
}
IntPtr context = NativeMethods.GetDC(this.Handle);

View File

@@ -27,6 +27,10 @@ namespace TweetDuck.Core.Notification.Screenshot{
#if GEN_SCREENSHOT_FRAMES
private readonly Timer debugger;
private int frameCounter;
public const int WaitFrames = 60;
#else
public const int WaitFrames = 5;
#endif
private FormNotificationScreenshotable screenshot;

View File

@@ -7,7 +7,7 @@ using TweetDuck.Resources;
namespace TweetDuck.Core.Notification{
sealed class TweetNotification{
private const string DefaultHeadLayout = @"<html id='tduck' 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 DefaultHeadLayout = @"<html class=""scroll-v os-windows dark txt-size--14"" lang=""en-US"" id=""tduck"" data-td-font=""medium"" data-td-theme=""dark""><head><meta charset=""utf-8""><link href=""https://ton.twimg.com/tweetdeck-web/web/dist/bundle.4b1f87e09d.css"" rel=""stylesheet""><style type='text/css'>body { background: rgb(34, 36, 38) !important }</style>";
private static readonly string CustomCSS = ScriptLoader.LoadResource("styles/notification.css") ?? string.Empty;
public static readonly ResourceLink AppLogo = new ResourceLink("https://ton.twimg.com/tduck/avatar", ResourceHandler.FromByteArray(Properties.Resources.avatar, "image/png"));

View File

@@ -69,7 +69,7 @@ namespace TweetDuck.Core.Other{
MenuHandler = new ContextMenuGuide(owner),
JsDialogHandler = new JavaScriptDialogHandler(),
LifeSpanHandler = new LifeSpanHandler(),
RequestHandler = new RequestHandlerBrowser()
RequestHandler = new RequestHandlerBase(true)
};
browser.LoadingStateChanged += browser_LoadingStateChanged;

View File

@@ -4,6 +4,7 @@ using System.Text;
using System.Windows.Forms;
using CefSharp;
using CefSharp.WinForms;
using TweetDuck.Configuration;
using TweetDuck.Core.Bridge;
using TweetDuck.Core.Controls;
using TweetDuck.Core.Handling;
@@ -39,14 +40,16 @@ namespace TweetDuck.Core{
private string prevSoundNotificationPath = null;
public TweetDeckBrowser(FormBrowser owner, TweetDeckBridge bridge){
RequestHandlerBrowser requestHandler = new RequestHandlerBrowser();
this.browser = new ChromiumWebBrowser(TwitterUtils.TweetDeckURL){
DialogHandler = new FileDialogHandler(),
DragHandler = new DragHandlerBrowser(),
DragHandler = new DragHandlerBrowser(requestHandler),
MenuHandler = new ContextMenuBrowser(owner),
JsDialogHandler = new JavaScriptDialogHandler(),
KeyboardHandler = new KeyboardHandlerBrowser(owner),
LifeSpanHandler = new LifeSpanHandler(),
RequestHandler = new RequestHandlerBrowser()
RequestHandler = requestHandler
};
this.browser.LoadingStateChanged += browser_LoadingStateChanged;
@@ -154,6 +157,10 @@ namespace TweetDuck.Core{
TweetDeckBridge.ResetStaticProperties();
if (Arguments.HasFlag(Arguments.ArgIgnoreGDPR)){
ScriptLoader.ExecuteScript(frame, @"TD.storage.Account.prototype.requiresConsent = function(){ return false; }", "gen:gdpr");
}
if (Program.UserConfig.FirstRun){
ScriptLoader.ExecuteFile(frame, "introduction.js", browser);
}

View File

@@ -71,6 +71,9 @@ namespace TweetDuck.Core.Utils{
[return: MarshalAs(UnmanagedType.Bool)]
private static extern bool BitBlt(IntPtr hdc, int nXDest, int nYDest, int nWidth, int nHeight, IntPtr hdcSrc, int nXSrc, int nYSrc, uint dwRop);
[DllImport("dwmapi.dll")]
public static extern int DwmIsCompositionEnabled(out bool enabled);
[DllImport("user32.dll")]
[return: MarshalAs(UnmanagedType.Bool)]
public static extern bool ShowScrollBar(IntPtr hWnd, int wBar, bool bShow);

View File

@@ -19,6 +19,14 @@ namespace TweetDuck.Core.Utils{
return Regex.Replace(str, @"(\p{Ll})(\P{Ll})|(\P{Ll})(\P{Ll}\p{Ll})", "$1$3_$2$4").ToUpper();
}
public static string ConvertRot13(string str){
return Regex.Replace(str, @"[a-zA-Z]", match => {
int code = match.Value[0];
int start = code <= 90 ? 65 : 97;
return ((char)(start+(code-start+13)%26)).ToString();
});
}
public static int CountOccurrences(string source, string substring){
int count = 0, index = 0;

View File

@@ -15,10 +15,12 @@ namespace TweetDuck.Core.Utils{
private static readonly Lazy<Regex> RegexStripHtmlStyles = new Lazy<Regex>(() => new Regex(@"\s?(?:style|class)="".*?"""), false);
private static readonly Lazy<Regex> RegexOffsetClipboardHtml = new Lazy<Regex>(() => new Regex(@"(?<=EndHTML:|EndFragment:)(\d+)"), false);
private static readonly bool IsWindows8OrNewer;
private static bool HasMicrosoftBeenBroughtTo2008Yet;
public static int CurrentProcessID { get; }
public static bool ShouldAvoidToolWindow { get; }
private static bool HasMicrosoftBeenBroughtTo2008Yet;
public static bool IsAeroEnabled => IsWindows8OrNewer || (NativeMethods.DwmIsCompositionEnabled(out bool isCompositionEnabled) == 0 && isCompositionEnabled);
static WindowsUtils(){
using(Process me = Process.GetCurrentProcess()){
@@ -26,7 +28,9 @@ namespace TweetDuck.Core.Utils{
}
Version ver = Environment.OSVersion.Version;
ShouldAvoidToolWindow = ver.Major == 6 && ver.Minor == 2; // windows 8/10
IsWindows8OrNewer = ver.Major == 6 && ver.Minor == 2; // windows 8/10
ShouldAvoidToolWindow = IsWindows8OrNewer;
}
public static void EnsureTLS12(){

View File

@@ -19,7 +19,7 @@ namespace TweetDuck{
public const string BrandName = "TweetDuck";
public const string Website = "https://tweetduck.chylex.com";
public const string VersionTag = "1.14";
public const string VersionTag = "1.14.3";
public static readonly string ProgramPath = AppDomain.CurrentDomain.BaseDirectory;
public static readonly bool IsPortable = File.Exists(Path.Combine(ProgramPath, "makeportable"));

View File

@@ -12,50 +12,44 @@ The program was built using Visual Studio 2017. Before opening the solution, ple
* **Desktop development with C++**
* VC++ 2017 v141 toolset
After opening the solution, download the following NuGet packages by right-clicking on the solution and selecting **Restore NuGet Packages**, or manually running this command in the **Package Manager Console**:
After opening the solution, right-click the solution and select **Restore NuGet Packages**, or manually run this command in the **Package Manager Console**:
```
PM> Install-Package CefSharp.WinForms -Version 65.0.0-pre01
PM> Install-Package CefSharp.WinForms -Version 66.0.0-CI2629 -Source https://www.myget.org/F/cefsharp/api/v3/index.json
```
Note that some pre-release builds of CefSharp are not available on NuGet. To correctly restore packages in that case, open **Package Manager Settings**, and add `https://www.myget.org/F/cefsharp/api/v3/index.json` to the list of package sources.
### Debug
It is recommended to create a separate data folder for debugging, otherwise you will not be able to run TweetDuck while debugging the solution.
The `Debug` configuration uses a separate data folder by default (`%LOCALAPPDATA%\TweetDuckDebug`) to avoid affecting an existing installation of TweetDuck. You can modify this by opening **TweetDuck Properties** in Visual Studio, clicking the **Debug** tab, and changing the **Command line arguments** field.
To do that, open **TweetDuck Properties**, click the **Debug** tab, make sure your **Configuration** is set to `Active (Debug)` (or just `Debug`), and insert this into the **Command line arguments** field:
```
-datafolder TweetDuckDebug
```
While debugging, opening the main menu and clicking **Reload browser** automatically rebuilds all resources in the `Resources/Scripts` and `Resources/Plugins` folders. This allows editing HTML/CSS/JS files and applying the changes without restarting the program, but it will cause a short delay between browser reloads.
### Build
### Release
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.
Open **Batch Build**, tick all `Release` configurations with `x86` platform except for the `UnitTest` project, 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.
If you decide to release a custom version publicly, please make it clear that it is not an official release of TweetDuck.
The `Release` configuration omits debug symbols and other unnecessary files. You can modify this behavior by opening `TweetDuck.csproj`, and editing the `<Target Name="AfterBuild" Condition="$(ConfigurationName) == Release">` section.
If you decide to publicly release a custom version, please make it clear that it is not an official release of TweetDuck. There are many references to the official website and this repository, especially in the update system, so search for `chylex.com` and `github.com` in all files and replace them appropriately.
### 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
#### Error: The command (...) exited with code 1
- This indicates a failed post-build event, open the **Output** tab for logs
- Determine if there was an IO error from the `rmdir` commands, or whether the error was in the **PostBuild.ps1** script (`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
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** for installers and updates. 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.
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 this will only package the files, you still need to run the [release build](#release) in Visual Studio!
After the window closes, three installers will be generated inside the `bld/Output` folder:
* **TweetDuck.exe**
@@ -67,8 +61,8 @@ After the window closes, three installers will be generated inside the `bld/Outp
* This is a portable installer that does not need administrator privileges
* It automatically creates a `makeportable` file in the program folder, which forces TweetDuck to run in portable mode
Note: There is a small chance you will see a resource error when running `RUN BUILD.bat`. If that happens, close the console window (which will terminate all Inno Setup processes and leave corrupted installer files in the output folder), and run it again.
#### Notes
### Code Notes
> There is a small chance running `RUN BUILD.bat` immediately shows a resource error. If that happens, close the console window (which terminates all Inno Setup processes and leaves corrupted installers in the output folder), and run it again.
There are many references to the official TweetDuck website and this repository in the code and installers, so if you plan to release your own version, make sure to search for `tweetduck.chylex.com` and `github.com` in the whole repository and replace them appropriately.
> Running `RUN BUILD.bat` uses about 400 MB of RAM due to high compression. You can lower this to about 140 MB by opening `gen_full.iss` and `gen_port.iss`, and changing `LZMADictionarySize=15360` to `LZMADictionarySize=4096`.

Binary file not shown.

View File

@@ -82,12 +82,10 @@ enabled(){
</a>`;
// add column buttons and keyboard shortcut info to UI
window.TDPF_injectMustache("column/column_header.mustache", "prepend", "</header>", `
{{^isTemporary}}
<a class="column-header-link td-clear-column-shortcut" href="#" data-action="td-clearcolumns-dosingle" style="right:34px">
<i class="icon icon-clear-timeline js-show-tip" data-placement="bottom" data-original-title="Clear column (hold Shift to restore)"></i>
</a>
{{/isTemporary}}`);
window.TDPF_injectMustache("column/column_header.mustache", "prepend", "<a data-testid=\"optionsToggle\"", `
<a class="js-action-header-button column-header-link" href="#" data-action="td-clearcolumns-dosingle">
<i class="icon icon-clear-timeline js-show-tip" data-placement="bottom" data-original-title="Clear column (hold Shift to restore)"></i>
</a>`);
window.TDPF_injectMustache("keyboard_shortcut_list.mustache", "prepend", "</dl> <dl", `
<dd class="keyboard-shortcut-definition" style="white-space:nowrap">
@@ -101,13 +99,12 @@ enabled(){
// load custom style
var css = window.TDPF_createCustomStyle(this);
css.insert(".js-app-add-column.is-hidden + .clear-columns-btn-all-parent { display: none; }");
css.insert(".column-header-links { min-width: 51px !important; }");
css.insert("[data-td-icon='icon-message'] .column-header-links { min-width: 110px !important; }");
css.insert(".column-navigator-overflow .clear-columns-btn-all-parent { display: none !important; }");
css.insert(".column-navigator-overflow { bottom: 224px !important; }");
css.insert(".column-title { margin-right: 60px !important; }");
css.insert(".mark-all-read-link { right: 59px !important; }");
css.insert(".open-compose-dm-link { right: 90px !important; }");
css.insert("button[data-action='clear'].btn-options-tray { display: none !important; }");
css.insert("[data-td-icon='icon-message'] .column-title { margin-right: 115px !important; }");
css.insert("[data-action='td-clearcolumns-dosingle'] { padding: 3px 0 !important; }");
css.insert("[data-action='clear'].btn-options-tray { display: none !important; }");
css.insert("[data-td-icon='icon-schedule'] .td-clear-column-shortcut { display: none; }");
css.insert("[data-td-icon='icon-custom-timeline'] .td-clear-column-shortcut { display: none; }");
}

View File

@@ -396,8 +396,10 @@ enabled(){
switch(currentTheme){
case "black":
this.css.insert(".app-content, .app-columns-container { background-color: #444448 !important }");
this.css.insert(".column-header-temp { background-color: transparent !important }");
this.css.insert(".column-drag-handle { opacity: 0.5 !important }");
this.css.insert(".column-drag-handle:hover { opacity: 1 !important }");
this.css.insert(".column-message.is-actionable span:hover > .icon-small-valigned { filter: saturate(20) }");
this.css.insert(".scroll-styled-v:not(.scroll-alt)::-webkit-scrollbar-thumb:not(:hover), .scroll-styled-h:not(.scroll-alt)::-webkit-scrollbar-thumb:not(:hover) { background-color: #666 !important }");
notificationScrollbarColor = "666";
break;
@@ -539,8 +541,8 @@ ${iconData.map(entry => `#tduck .icon-${entry[0]}:before{content:\"\\f0${entry[1
#tduck .js-docked-compose .js-drawer-close { margin: 20px 0 0 !important }
#tduck .search-input-control .icon { font-size: 20px !important; top: -4px !important }
.column-header .column-type-icon { bottom: 26px !important }
.is-options-open .column-type-icon { bottom: 25px !important }
.column-type-icon { margin-top: -1px !important }
.inline-reply .pull-left .Button--link { margin-top: 3px !important }
.tweet-action-item .icon-favorite-toggle { font-size: 16px !important; }
.tweet-action-item .heartsprite { top: -260% !important; left: -260% !important; transform: scale(0.4, 0.39) translateY(0.5px) !important; }
@@ -561,7 +563,7 @@ ${iconData.map(entry => `#tduck .icon-${entry[0]}:before{content:\"\\f0${entry[1
if (this.config.columnWidth[0] === '/'){
let cols = this.config.columnWidth.slice(1);
this.css.insert(".column { width: calc((100vw - 205px) / "+cols+" - 6px) !important }");
this.css.insert(".column { width: calc((100vw - 205px) / "+cols+" - 6px) !important; min-width: 160px }");
this.css.insert(".is-condensed .column { width: calc((100vw - 55px) / "+cols+" - 6px) !important }");
}
else{

View File

@@ -44,6 +44,8 @@
</optgroup>
<option disabled></option>
<optgroup label="Dynamic width">
<option value="/1">1 column on screen</option>
<option value="/2">2 columns on screen</option>
<option value="/3">3 columns on screen</option>
<option value="/4">4 columns on screen</option>
<option value="/5">5 columns on screen</option>

View File

@@ -23,25 +23,34 @@ enabled(){
return;
}
var section = data.element.closest("section.js-column");
let section = data.element.closest("section.js-column");
let column = TD.controller.columnManager.get(section.attr("data-column"));
var column = TD.controller.columnManager.get(section.attr("data-column"));
var header = $(".column-title", section);
var title = header.children(".column-head-title");
let feeds = column.getFeeds();
let accountText = "";
var columnTitle, columnAccount;
if (title.length){
columnTitle = title.text();
columnAccount = header.children(".attribution").text();
}
else{
columnTitle = header.children(".column-title-edit-box").val();
columnAccount = "";
if (feeds.length === 1){
let metadata = feeds[0].getMetadata();
let id = metadata.ownerId || metadata.id;
if (id){
accountText = TD.cache.names.getScreenName(id);
}
else{
let account = TD.storage.accountController.get(feeds[0].getAccountKey());
if (account){
accountText = "@"+account.getUsername();
}
}
}
let header = $(".column-header-title", section);
let title = header.children(".column-heading");
let titleText = title.length ? title.text() : header.children(".column-title-edit-box").val();
try{
query = configuration.customSelector(columnTitle, columnAccount, column, section.hasClass("column-temp"));
query = configuration.customSelector(titleText, accountText, column, section.hasClass("column-temp"));
}catch(e){
$TD.alert("warning", "Plugin reply-account has invalid configuration: customSelector threw an error: "+e.message);
return;

View File

@@ -51,7 +51,7 @@ enabled(){
this.css.insert(".manage-templates-btn.active { color: #fff; box-shadow: 0 0 2px 3px #50a5e6; outline: 0; }");
this.css.insert("#templates-modal-wrap { width: 100%; height: 100%; padding: 49px; position: absolute; z-index: 999; box-sizing: border-box; background-color: rgba(0, 0, 0, 0.5); }");
this.css.insert("#templates-modal { width: 100%; height: 100%; background-color: #fff; display: flex; }");
this.css.insert("#templates-modal { width: 100%; height: 100%; min-width: 500px; background-color: #fff; display: flex; }");
this.css.insert("#templates-modal > div { display: flex; flex-direction: column; }");
this.css.insert(".templates-modal-bottom { flex: 0 0 auto; padding: 16px; }");
@@ -68,7 +68,7 @@ enabled(){
this.css.insert("#template-list li .icon:hover { opacity: 1; }");
this.css.insert("#template-list li .template-actions { float: right; }");
this.css.insert("#template-editor { height: 100%; flex: 0 0 auto; width: 25vw; min-width: 150px; max-width: 400px; background-color: #485865; }");
this.css.insert("#template-editor { height: 100%; flex: 0 0 auto; width: 25vw; min-width: 225px; max-width: 400px; background-color: #485865; }");
this.css.insert(".template-editor-form { flex: 1 1 auto; padding: 12px 16px; font-size: 14px; overflow-y: auto; }");
this.css.insert(".template-editor-form .compose-text-title { margin: 24px 0 9px; }");
this.css.insert(".template-editor-form .compose-text-title:first-child { margin-top: 0; }");
@@ -261,7 +261,7 @@ enabled(){
$(".manage-templates-btn").addClass("active");
let html = `
<div id="templates-modal-wrap">
<div id="templates-modal-wrap" class="scroll-v scroll-styled-v">
<div id="templates-modal">
<div id="template-list">
<ul></ul>

View File

@@ -44,42 +44,48 @@ try{
# Helper functions
function Remove-Empty-Lines{
Param([Parameter(Mandatory = $True, Position = 1)] $lines)
ForEach($line in $lines){
if ($line -ne ''){
$line
}
}
}
function Check-Carriage-Return{
Param(
[Parameter(Mandatory = $True, Position = 1)] $fname
)
Param([Parameter(Mandatory = $True, Position = 1)] $file)
$file = @(Get-ChildItem -Path $targetDir -Include $fname -Recurse)[0]
if ((Get-Content -Path $file.FullName -Raw).Contains("`r")){
Throw "$fname cannot contain carriage return"
if (!(Test-Path $file)){
Throw "$file does not exist"
}
Write-Host "Verified" $file.FullName.Substring($targetDir.Length)
if ((Get-Content -Path $file -Raw).Contains("`r")){
Throw "$file cannot contain carriage return"
}
Write-Host "Verified" $file.Substring($targetDir.Length)
}
function Rewrite-File{
[CmdletBinding()]
Param(
[Parameter(Mandatory = $True, Position = 1)] $file,
[Parameter(Mandatory = $True, Position = 2)] $lines
)
Param([Parameter(Mandatory = $True, Position = 1)] $file,
[Parameter(Mandatory = $True, Position = 2)] $lines)
$lines = Remove-Empty-Lines($lines)
$relativePath = $file.FullName.Substring($targetDir.Length)
if ($relativePath.StartsWith("scripts\")){
$lines = (,("#" + $version) + $lines)
}
$lines = $lines | Where { $_ -ne '' }
[IO.File]::WriteAllLines($file.FullName, $lines)
Write-Host "Processed" $relativePath
}
# Post processing
Check-Carriage-Return("emoji-ordering.txt")
Check-Carriage-Return(Join-Path $targetDir "plugins\official\emoji-keyboard\emoji-ordering.txt")
ForEach($file in Get-ChildItem -Path $targetDir -Filter "*.js" -Exclude "configuration.default.js" -Recurse){
$lines = [IO.File]::ReadLines($file.FullName)
@@ -92,9 +98,9 @@ try{
ForEach($file in Get-ChildItem -Path $targetDir -Filter "*.css" -Recurse){
$lines = [IO.File]::ReadLines($file.FullName)
$lines = $lines -Replace '\s*/\*.*?\*/', ''
$lines = $lines -Replace '^\s+(.+):\s?(.+?)(?:\s?(!important))?;$', '$1:$2$3;'
$lines = $lines -Replace '^(\S.*?) {$', '$1{'
$lines = @(($lines | Where { $_ -ne '' }) -Join ' ')
$lines = $lines -Replace '^(\S.*) {$', '$1{'
$lines = $lines -Replace '^\s+(.+?):\s*(.+?)(?:\s*(!important))?;$', '$1:$2$3;'
$lines = @((Remove-Empty-Lines($lines)) -Join ' ')
Rewrite-File $file $lines
}

View File

@@ -0,0 +1,18 @@
$ErrorActionPreference = "Stop"
$MainProj = "..\TweetDuck.csproj"
$BrowserProj = "..\subprocess\TweetDuck.Browser.csproj"
$Match = Select-String -Path $MainProj '<Import Project="packages\\cef\.redist\.x86\.(.*?)\\'
$Version = $Match.Matches[0].Groups[1].Value
Copy-Item "..\packages\cef.redist.x86.${Version}\CEF\devtools_resources.pak" -Destination "..\bld\Resources\" -Force
$Match = Select-String -Path $MainProj '<Import Project="packages\\CefSharp\.Common\.(.*?)\\'
$Version = $Match.Matches[0].Groups[1].Value
$Contents = [IO.File]::ReadAllText($BrowserProj)
$Contents = $Contents -Replace '(?<=<HintPath>\.\.\\packages\\CefSharp\.Common\.)(.*?)(?=\\)', $Version
$Contents = $Contents -Replace '(?<=<Reference Include="CefSharp\.BrowserSubprocess\.Core, Version=)(\d+)', $Version.Split(".")[0]
[IO.File]::WriteAllText($BrowserProj, $Contents)

View File

@@ -197,6 +197,10 @@
html.find(".js-media").remove();
}
html.find("a[data-full-url]").each(function(){ // bypass t.co on all links
this.href = this.getAttribute("data-full-url");
});
html.find("a[href='#']").each(function(){ // remove <a> tags around links that don't lead anywhere (such as account names the tweet replied to)
this.outerHTML = this.innerHTML;
});
@@ -558,17 +562,17 @@
let media = tweet.getMedia().find(media => media.mediaId === me.getAttribute("data-media-entity-id"));
if ((media.isVideo && media.service === "twitter") || media.isAnimatedGif){
$TD.setLastRightClickInfo("video", media.chooseVideoVariant().url);
$TD.setRightClickedLink("video", media.chooseVideoVariant().url);
}
else{
$TD.setLastRightClickInfo("image", media.large());
$TD.setRightClickedLink("image", media.large());
}
}
else if (me.classList.contains("js-gif-play")){
$TD.setLastRightClickInfo("video", $(this).closest(".js-media-gif-container").find("video").attr("src"));
$TD.setRightClickedLink("video", $(this).closest(".js-media-gif-container").find("video").attr("src"));
}
else{
$TD.setLastRightClickInfo("link", me.getAttribute("data-full-url"));
$TD.setRightClickedLink("link", me.getAttribute("data-full-url"));
}
});
@@ -707,6 +711,12 @@
}
}
let gif = html.find(".js-media-gif-container");
if (gif.length){
gif.css("background-image", 'url("'+chirp.getMedia()[0].small()+'")');
}
let type = chirp.getChirpType();
if ((type.startsWith("favorite") || type.startsWith("retweet")) && chirp.isAboutYou()){
@@ -1368,11 +1378,20 @@
}
//
// Block: Remove column mouse wheel handler, which allows smooth scrolling inside columns, and horizontally scrolling column container when holding Shift.
// Block: Fix broken horizontal scrolling of column container when holding Shift. TODO Fix broken smooth scrolling.
//
if (ensurePropertyExists(TD, "ui", "columns", "setupColumnScrollListeners")){
TD.ui.columns.setupColumnScrollListeners = appendToFunction(TD.ui.columns.setupColumnScrollListeners, function(e){
$(".js-column[data-column='"+e.model.getKey()+"']").off("mousewheel onmousewheel");
TD.ui.columns.setupColumnScrollListeners = appendToFunction(TD.ui.columns.setupColumnScrollListeners, function(column){
let ele = $(".js-column[data-column='"+column.model.getKey()+"']");
return if !ele.length;
ele.off("onmousewheel").on("mousewheel", ".scroll-v", function(e){
if (e.shiftKey){
e.stopImmediatePropagation();
}
});
window.TDGF_prioritizeNewestEvent(ele[0], "mousewheel");
});
}

View File

@@ -3,12 +3,13 @@
let css = $(`
<style>
#td-introduction-modal {
display: block;
display: flex;
}
#td-introduction-modal .mdl {
width: 90%;
max-width: 830px;
min-width: 515px;
max-width: 835px;
height: 328px;
}
@@ -73,7 +74,7 @@
</style>`).appendTo(document.head);
let ele = $(`
<div id="td-introduction-modal" class="ovl">
<div id="td-introduction-modal" class="ovl scroll-v scroll-styled-v">
<div class="mdl is-inverted-dark">
<header class="mdl-header">
<h3 class="mdl-header-title">Welcome to TweetDuck</h3>

View File

@@ -14,14 +14,14 @@
};
//
// Block: Hook into links to bypass default open function and t.co, and handle skipping notification when opening links.
// Block: Hook into links to bypass default open function, and handle skipping notification when opening links.
//
(function(){
const onLinkClick = function(e){
if (e.button === 0 || e.button === 1){
let ele = e.currentTarget;
$TD.openBrowser(ele.hasAttribute("data-full-url") ? ele.getAttribute("data-full-url") : ele.getAttribute("href"));
$TD.openBrowser(ele.href);
e.preventDefault();
if ($TDX.skipOnLinkClick){
@@ -38,13 +38,6 @@
addEventListener(links, "auxclick", onLinkClick);
})();
//
// Block: Allow bypassing of t.co in context menus.
//
addEventListener(links, "contextmenu", function(e){
$TD.setLastRightClickInfo("link", e.currentTarget.getAttribute("data-full-url"));
});
//
// Block: Expand shortened links on hover or display tooltip.
//

View File

@@ -10,7 +10,7 @@
let avatarBottom = avatar ? avatar.getBoundingClientRect().bottom : 0;
$TD.setHeight(Math.floor(Math.max(contentHeight, avatarBottom+9))).then(() => {
let framesLeft = 5; // basic render is done in 1 frame, large media take longer
let framesLeft = {frames}; // basic render is done in 1 frame, large media take longer
let onNextFrame = function(){
if (--framesLeft < 0){

View File

@@ -150,6 +150,7 @@ button {
.activity-header .icon-user-filled {
vertical-align: sub !important;
margin-right: 4px !important;
}
html[data-td-theme='light'] .stream-item:not(:hover) .js-user-actions-menu {
@@ -220,6 +221,50 @@ a[data-full-url] {
bottom: 0 !important;
}
/**********************************************************/
/* Prevent column icons from being hidden by column title */
/**********************************************************/
.column-header-title {
overflow: hidden !important;
}
.column-heading {
max-width: 100%;
overflow: hidden;
white-space: nowrap;
text-overflow: ellipsis;
}
.column-header-links {
max-width: 100% !important;
}
[data-td-icon="icon-message"] .column-header-links {
min-width: 86px;
}
/************************************************************/
/* Fix modal dialogs breaking when window size is too small */
/************************************************************/
.ovl:before, .overlay:before {
display: none !important;
}
.ovl, .overlay {
flex-direction: column;
justify-content: center;
}
.ovl[style="display: block;"] {
display: flex !important;
}
#tduck .overlay {
display: flex;
}
/*******************************************/
/* Fix general visual issues or annoyances */
/*******************************************/
@@ -234,6 +279,37 @@ a[data-full-url] {
vertical-align: -10% !important;
}
.column-title {
/* fix alignment of everything in column headers */
padding-top: 1px !important;
}
.column-title .attribution {
/* fix alignment of usernames in column headers */
margin: 0 0 0 6px !important;
}
.app-navigator .tooltip {
/* fix tooltips in navigation */
display: none !important;
}
.column-header-links .icon {
/* fix tooltips in column headers */
height: calc(1em + 8px) !important;
}
.column-header-temp:not(.js-column-header) {
/* fix missing column header padding in Edit List dialog */
padding-left: 10px;
padding-right: 10px;
}
.js-column-options .btn-options-tray {
/* fix underline on buttons in column options */
text-decoration: none !important;
}
#tduck .nav-user-info .hide-condensed {
/* move login account info */
margin: 0px !important;
@@ -241,7 +317,7 @@ a[data-full-url] {
}
html[data-td-font='smallest'] .sprite-verified-mini {
/* fix cut off badge when zoomed in */
/* fix cut off badge in timelines */
width: 13px !important;
height: 13px !important;
background-position: -223px -99px !important;
@@ -261,11 +337,21 @@ html[data-td-font='smallest'] .tweet-detail-wrapper .badge-verified:before {
background-position: -223px -97px !important;
}
html[data-td-font='smallest'] .fullname-badged:before, html[data-td-font='small'] .fullname-badged:before {
/* fix cut off badge in follow chirps */
margin-top: -7px !important;
}
.keyboard-shortcut-list {
/* fix keyboard navigation alignment */
vertical-align: top !important;
}
.column-message.is-actionable span:hover > .icon-small-valigned {
/* add a visual response when hovering individual filter icons; black theme uses a value of 20 */
filter: saturate(10);
}
.tweet-detail-wrapper .js-media-gif-container {
/* GIFs in detail view don't trigger the pointer cursor */
cursor: pointer;
@@ -290,9 +376,9 @@ html[data-td-font='smallest'] .tweet-detail-wrapper .badge-verified:before {
/* Fix glaring visual issues that twitter hasn't fixed yet smh */
/***************************************************************/
.column-nav-link .attribution {
.js-column-nav-list .attribution {
/* fix cut off account names */
position: absolute !important;
line-height: 1.1 !important;
}
#tduck .js-docked-compose .js-drawer-close {
@@ -311,25 +397,6 @@ html[data-td-font='smallest'] .tweet-detail-wrapper .badge-verified:before {
vertical-align: -15% !important;
}
/************************************************/
/* Fix tooltips in navigation and column header */
/************************************************/
.app-navigator .tooltip {
display: none !important;
}
.js-column-header .column-header-link {
padding: 0 !important;
}
.js-column-header .column-header-link .icon {
width: calc(1em + 8px);
height: 100%;
padding: 9px 4px;
box-sizing: border-box;
}
/*******************************************/
/* Fix one pixel space below column header */
/*******************************************/
@@ -342,10 +409,6 @@ html[data-td-font='smallest'] .tweet-detail-wrapper .badge-verified:before {
border-bottom: none !important;
}
.is-options-open .column-type-icon {
bottom: 27px !important;
}
/********************************************/
/* Fix cut off usernames in Messages column */
/********************************************/

View File

@@ -61,13 +61,25 @@ a[data-full-url] {
/* Fix general visual issues or annoyances */
/*******************************************/
html[data-td-font='smallest'] .sprite-verified-mini {
/* fix cut off badge in timelines */
width: 13px !important;
height: 13px !important;
background-position: -223px -99px !important;
}
html[data-td-font='smallest'] .badge-verified:before {
/* fix cut off badge icon */
/* fix cut off badge in notifications */
width: 13px !important;
height: 13px !important;
background-position: -223px -98px !important;
}
html[data-td-font='smallest'] .fullname-badged:before, html[data-td-font='small'] .fullname-badged:before {
/* fix cut off badge in follow chirps */
margin-top: -7px !important;
}
.account-inline .username {
vertical-align: 10% !important;
}
@@ -90,6 +102,7 @@ html[data-td-font='smallest'] .badge-verified:before {
.activity-header .icon-user-filled {
vertical-align: sub !important;
margin-right: 4px !important;
}
.td-notification-padded .item-img {

View File

@@ -1,9 +1,9 @@
<?xml version="1.0" encoding="utf-8"?>
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="12.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Import Project="packages\CefSharp.WinForms.65.0.0-pre01\build\CefSharp.WinForms.props" Condition="Exists('packages\CefSharp.WinForms.65.0.0-pre01\build\CefSharp.WinForms.props')" />
<Import Project="packages\CefSharp.Common.65.0.0-pre01\build\CefSharp.Common.props" Condition="Exists('packages\CefSharp.Common.65.0.0-pre01\build\CefSharp.Common.props')" />
<Import Project="packages\cef.redist.x86.3.3325.1758\build\cef.redist.x86.props" Condition="Exists('packages\cef.redist.x86.3.3325.1758\build\cef.redist.x86.props')" />
<Import Project="packages\cef.redist.x64.3.3325.1758\build\cef.redist.x64.props" Condition="Exists('packages\cef.redist.x64.3.3325.1758\build\cef.redist.x64.props')" />
<Import Project="packages\CefSharp.WinForms.66.0.0-CI2629\build\CefSharp.WinForms.props" Condition="Exists('packages\CefSharp.WinForms.66.0.0-CI2629\build\CefSharp.WinForms.props')" />
<Import Project="packages\CefSharp.Common.66.0.0-CI2629\build\CefSharp.Common.props" Condition="Exists('packages\CefSharp.Common.66.0.0-CI2629\build\CefSharp.Common.props')" />
<Import Project="packages\cef.redist.x86.3.3359.1772\build\cef.redist.x86.props" Condition="Exists('packages\cef.redist.x86.3.3359.1772\build\cef.redist.x86.props')" />
<Import Project="packages\cef.redist.x64.3.3359.1772\build\cef.redist.x64.props" Condition="Exists('packages\cef.redist.x64.3.3359.1772\build\cef.redist.x64.props')" />
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
<PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
@@ -35,6 +35,9 @@
<UseApplicationTrust>false</UseApplicationTrust>
<BootstrapperEnabled>true</BootstrapperEnabled>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)' == 'Debug'">
<StartArguments>-datafolder TweetDuckDebug</StartArguments>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Debug|x86'">
<DebugSymbols>true</DebugSymbols>
<OutputPath>bin\x86\Debug\</OutputPath>
@@ -365,30 +368,45 @@
</ContentWithTargetPath>
</ItemGroup>
<ItemGroup>
<Content Include="Resources\avatar.png" />
<None Include="packages.config" />
<None Include="Resources\icon-small.ico" />
<None Include="Resources\icon-tray-new.ico" />
<None Include="Resources\icon-tray.ico" />
<None Include="Resources\PostBuild.ps1" />
<None Include="Resources\spinner.apng" />
</ItemGroup>
<ItemGroup>
<Folder Include="Resources\Plugins\" />
</ItemGroup>
<ItemGroup>
<Content Include="Resources\avatar.png" />
<Content Include="Resources\Scripts\code.js" />
<Content Include="Resources\Scripts\introduction.js" />
<Content Include="Resources\Scripts\notification.js" />
<Content Include="Resources\Scripts\pages\error.html" />
<Content Include="Resources\Scripts\pages\example.html" />
<Content Include="Resources\Scripts\plugins.browser.js" />
<Content Include="Resources\Scripts\plugins.js" />
<Content Include="Resources\Scripts\plugins.notification.js" />
<Content Include="Resources\Scripts\styles\browser.css" />
<Content Include="Resources\Scripts\styles\notification.css" />
<Content Include="Resources\Scripts\twitter.js" />
<Content Include="Resources\Scripts\update.js" />
<None Include="Resources\PostBuild.ps1" />
<None Include="Resources\Plugins\.debug\.meta" />
<None Include="Resources\Plugins\.debug\browser.js" />
<None Include="Resources\Plugins\clear-columns\.meta" />
<None Include="Resources\Plugins\clear-columns\browser.js" />
<None Include="Resources\Plugins\edit-design\.meta" />
<None Include="Resources\Plugins\edit-design\browser.js" />
<None Include="Resources\Plugins\edit-design\modal.html" />
<None Include="Resources\Plugins\edit-design\theme.black.css" />
<None Include="Resources\Plugins\emoji-keyboard\.meta" />
<None Include="Resources\Plugins\emoji-keyboard\browser.js" />
<None Include="Resources\Plugins\emoji-keyboard\emoji-instructions.txt" />
<None Include="Resources\Plugins\emoji-keyboard\emoji-ordering.txt" />
<None Include="Resources\Plugins\reply-account\.meta" />
<None Include="Resources\Plugins\reply-account\browser.js" />
<None Include="Resources\Plugins\reply-account\configuration.default.js" />
<None Include="Resources\Plugins\templates\.meta" />
<None Include="Resources\Plugins\templates\browser.js" />
<None Include="Resources\Plugins\timeline-polls\.meta" />
<None Include="Resources\Plugins\timeline-polls\browser.js" />
<None Include="Resources\Scripts\code.js" />
<None Include="Resources\Scripts\introduction.js" />
<None Include="Resources\Scripts\notification.js" />
<None Include="Resources\Scripts\pages\error.html" />
<None Include="Resources\Scripts\pages\example.html" />
<None Include="Resources\Scripts\plugins.browser.js" />
<None Include="Resources\Scripts\plugins.js" />
<None Include="Resources\Scripts\plugins.notification.js" />
<None Include="Resources\Scripts\screenshot.js" />
<None Include="Resources\Scripts\styles\browser.css" />
<None Include="Resources\Scripts\styles\notification.css" />
<None Include="Resources\Scripts\twitter.js" />
<None Include="Resources\Scripts\update.js" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="subprocess\TweetDuck.Browser.csproj">
@@ -428,13 +446,11 @@ powershell -ExecutionPolicy Unrestricted -File "$(ProjectDir)Resources\PostBuild
<PropertyGroup>
<ErrorText>This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}.</ErrorText>
</PropertyGroup>
<Error Condition="!Exists('packages\cef.redist.x64.3.3325.1758\build\cef.redist.x64.props')" Text="$([System.String]::Format('$(ErrorText)', 'packages\cef.redist.x64.3.3325.1758\build\cef.redist.x64.props'))" />
<Error Condition="!Exists('packages\cef.redist.x86.3.3325.1758\build\cef.redist.x86.props')" Text="$([System.String]::Format('$(ErrorText)', 'packages\cef.redist.x86.3.3325.1758\build\cef.redist.x86.props'))" />
<Error Condition="!Exists('packages\CefSharp.Common.65.0.0-pre01\build\CefSharp.Common.props')" Text="$([System.String]::Format('$(ErrorText)', 'packages\CefSharp.Common.65.0.0-pre01\build\CefSharp.Common.props'))" />
<Error Condition="!Exists('packages\CefSharp.Common.65.0.0-pre01\build\CefSharp.Common.targets')" Text="$([System.String]::Format('$(ErrorText)', 'packages\CefSharp.Common.65.0.0-pre01\build\CefSharp.Common.targets'))" />
<Error Condition="!Exists('packages\CefSharp.WinForms.65.0.0-pre01\build\CefSharp.WinForms.props')" Text="$([System.String]::Format('$(ErrorText)', 'packages\CefSharp.WinForms.65.0.0-pre01\build\CefSharp.WinForms.props'))" />
<Error Condition="!Exists('packages\CefSharp.WinForms.65.0.0-pre01\build\CefSharp.WinForms.targets')" Text="$([System.String]::Format('$(ErrorText)', 'packages\CefSharp.WinForms.65.0.0-pre01\build\CefSharp.WinForms.targets'))" />
<Error Condition="!Exists('packages\cef.redist.x64.3.3359.1772\build\cef.redist.x64.props')" Text="$([System.String]::Format('$(ErrorText)', 'packages\cef.redist.x64.3.3359.1772\build\cef.redist.x64.props'))" />
<Error Condition="!Exists('packages\cef.redist.x86.3.3359.1772\build\cef.redist.x86.props')" Text="$([System.String]::Format('$(ErrorText)', 'packages\cef.redist.x86.3.3359.1772\build\cef.redist.x86.props'))" />
<Error Condition="!Exists('packages\CefSharp.Common.66.0.0-CI2629\build\CefSharp.Common.props')" Text="$([System.String]::Format('$(ErrorText)', 'packages\CefSharp.Common.66.0.0-CI2629\build\CefSharp.Common.props'))" />
<Error Condition="!Exists('packages\CefSharp.Common.66.0.0-CI2629\build\CefSharp.Common.targets')" Text="$([System.String]::Format('$(ErrorText)', 'packages\CefSharp.Common.66.0.0-CI2629\build\CefSharp.Common.targets'))" />
<Error Condition="!Exists('packages\CefSharp.WinForms.66.0.0-CI2629\build\CefSharp.WinForms.props')" Text="$([System.String]::Format('$(ErrorText)', 'packages\CefSharp.WinForms.66.0.0-CI2629\build\CefSharp.WinForms.props'))" />
</Target>
<Import Project="packages\CefSharp.Common.65.0.0-pre01\build\CefSharp.Common.targets" Condition="Exists('packages\CefSharp.Common.65.0.0-pre01\build\CefSharp.Common.targets')" />
<Import Project="packages\CefSharp.WinForms.65.0.0-pre01\build\CefSharp.WinForms.targets" Condition="Exists('packages\CefSharp.WinForms.65.0.0-pre01\build\CefSharp.WinForms.targets')" />
<Import Project="packages\CefSharp.Common.66.0.0-CI2629\build\CefSharp.Common.targets" Condition="Exists('packages\CefSharp.Common.66.0.0-CI2629\build\CefSharp.Common.targets')" />
</Project>

Binary file not shown.

View File

@@ -30,6 +30,7 @@ Uninstallable=TDIsUninstallable
UninstallDisplayName={#MyAppName}
UninstallDisplayIcon={app}\{#MyAppExeName}
Compression=lzma2/ultra
LZMADictionarySize=15360
SolidCompression=yes
InternalCompressLevel=normal
MinVersion=0,6.1

View File

@@ -30,6 +30,7 @@ Uninstallable=no
UsePreviousAppDir=no
PrivilegesRequired=lowest
Compression=lzma2/ultra
LZMADictionarySize=15360
SolidCompression=yes
InternalCompressLevel=normal
MinVersion=0,6.1

View File

@@ -32,6 +32,7 @@ UninstallDisplayName={#MyAppName}
UninstallDisplayIcon={app}\{#MyAppExeName}
PrivilegesRequired=lowest
Compression=lzma/normal
LZMADictionarySize=512
SolidCompression=True
InternalCompressLevel=normal
MinVersion=0,6.1

View File

@@ -1,7 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<packages>
<package id="cef.redist.x64" version="3.3325.1758" targetFramework="net452" />
<package id="cef.redist.x86" version="3.3325.1758" targetFramework="net452" />
<package id="CefSharp.Common" version="65.0.0-pre01" targetFramework="net452" />
<package id="CefSharp.WinForms" version="65.0.0-pre01" targetFramework="net452" />
<package id="cef.redist.x64" version="3.3359.1772" targetFramework="net452" />
<package id="cef.redist.x86" version="3.3359.1772" targetFramework="net452" />
<package id="CefSharp.Common" version="66.0.0-CI2629" targetFramework="net452" />
<package id="CefSharp.WinForms" version="66.0.0-CI2629" targetFramework="net452" />
</packages>

View File

@@ -1,4 +1,4 @@
<?xml version="1.0" encoding="utf-8"?>
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
<PropertyGroup>
@@ -26,9 +26,9 @@
<StartupObject />
</PropertyGroup>
<ItemGroup>
<Reference Include="CefSharp.BrowserSubprocess.Core, Version=65.0.0.0, Culture=neutral, PublicKeyToken=40c4b6fc221f4138, processorArchitecture=x86">
<Reference Include="CefSharp.BrowserSubprocess.Core, Version=66.0.0.0, Culture=neutral, PublicKeyToken=40c4b6fc221f4138, processorArchitecture=x86">
<SpecificVersion>False</SpecificVersion>
<HintPath>..\packages\CefSharp.Common.65.0.0-pre01\CefSharp\x86\CefSharp.BrowserSubprocess.Core.dll</HintPath>
<HintPath>..\packages\CefSharp.Common.66.0.0-CI2629\CefSharp\x86\CefSharp.BrowserSubprocess.Core.dll</HintPath>
</Reference>
<Reference Include="System" />
</ItemGroup>