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

Compare commits

..

13 Commits
1.12 ... 1.12.1

24 changed files with 292 additions and 141 deletions

View File

@@ -10,7 +10,9 @@ using TweetDuck.Data.Serialization;
namespace TweetDuck.Configuration{
sealed class UserConfig{
private static readonly FileSerializer<UserConfig> Serializer = new FileSerializer<UserConfig>();
private static readonly FileSerializer<UserConfig> Serializer = new FileSerializer<UserConfig>{
HandleUnknownProperties = FileSerializer<UserConfig>.IgnoreProperties("AppLocale")
};
static UserConfig(){
Serializer.RegisterTypeConverter(typeof(WindowState), WindowState.Converter);
@@ -41,18 +43,19 @@ namespace TweetDuck.Configuration{
public WindowState BrowserWindow { get; set; } = new WindowState();
public WindowState PluginsWindow { get; set; } = new WindowState();
public bool ExpandLinksOnHover { get; set; } = true;
public bool SwitchAccountSelectors { get; set; } = true;
public bool OpenSearchInFirstColumn { get; set; } = true;
public bool BestImageQuality { get; set; } = true;
public bool EnableAnimatedImages { get; set; } = true;
public int VideoPlayerVolume { get; set; } = 50;
private int _zoomLevel = 100;
public bool ExpandLinksOnHover { get; set; } = true;
public bool SwitchAccountSelectors { get; set; } = true;
public bool OpenSearchInFirstColumn { get; set; } = true;
public bool KeepLikeFollowDialogsOpen { get; set; } = true;
public bool BestImageQuality { get; set; } = true;
public bool EnableAnimatedImages { get; set; } = true;
public int VideoPlayerVolume { get; set; } = 50;
private int _zoomLevel = 100;
private bool _muteNotifications;
public bool EnableSpellCheck { get; set; } = false;
public string AppLocale { get; set; } = "en-US";
public string TranslationTarget { get; set; } = "en";
public bool EnableSpellCheck { get; set; } = false;
public string SpellCheckLanguage { get; set; } = "en-US";
public string TranslationTarget { get; set; } = "en";
private TrayIcon.Behavior _trayBehavior = TrayIcon.Behavior.Disabled;
public bool EnableTrayHighlight { get; set; } = true;

View File

@@ -17,6 +17,7 @@ namespace TweetDuck.Core.Bridge{
if (environment == Environment.Browser){
build.Append("x.switchAccountSelectors=").Append(Bool(Program.UserConfig.SwitchAccountSelectors));
build.Append("x.openSearchInFirstColumn=").Append(Bool(Program.UserConfig.OpenSearchInFirstColumn));
build.Append("x.keepLikeFollowDialogsOpen=").Append(Bool(Program.UserConfig.KeepLikeFollowDialogsOpen));
build.Append("x.muteNotifications=").Append(Bool(Program.UserConfig.MuteNotifications));
build.Append("x.hasCustomNotificationSound=").Append(Bool(Program.UserConfig.NotificationSoundPath.Length > 0));
build.Append("x.notificationMediaPreviews=").Append(Bool(Program.UserConfig.NotificationMediaPreviews));

View File

@@ -10,7 +10,7 @@ using TweetDuck.Core.Utils;
using TweetDuck.Resources;
namespace TweetDuck.Core.Bridge{
sealed class TweetDeckBridge{
class TweetDeckBridge{
public static string FontSize { get; private set; }
public static string NotificationHeadLayout { get; private set; }
@@ -45,41 +45,77 @@ namespace TweetDuck.Core.Bridge{
private readonly FormBrowser form;
private readonly FormNotificationMain notification;
public TweetDeckBridge(FormBrowser form, FormNotificationMain notification){
protected TweetDeckBridge(FormBrowser form, FormNotificationMain notification){
this.form = form;
this.notification = notification;
}
public void OnIntroductionClosed(bool showGuide, bool allowDataCollection){
form.InvokeAsyncSafe(() => {
form.OnIntroductionClosed(showGuide, allowDataCollection);
});
// Browser only
public sealed class Browser : TweetDeckBridge{
public Browser(FormBrowser form, FormNotificationMain notification) : base(form, notification){}
public void OpenContextMenu(){
form.InvokeAsyncSafe(form.OpenContextMenu);
}
public void OnIntroductionClosed(bool showGuide, bool allowDataCollection){
form.InvokeAsyncSafe(() => {
form.OnIntroductionClosed(showGuide, allowDataCollection);
});
}
public void LoadNotificationLayout(string fontSize, string headLayout){
form.InvokeAsyncSafe(() => {
FontSize = fontSize;
NotificationHeadLayout = headLayout;
});
}
public void SetLastHighlightedTweet(string tweetUrl, string quoteUrl, string authors, string imageList){
form.InvokeAsyncSafe(() => {
LastHighlightedTweetUrl = tweetUrl;
LastHighlightedQuoteUrl = quoteUrl;
LastHighlightedTweetAuthors = authors;
LastHighlightedTweetImages = imageList;
});
}
public void DisplayTooltip(string text){
form.InvokeAsyncSafe(() => form.DisplayTooltip(text));
}
public void SetSessionData(string key, string value){
form.InvokeSafe(() => { // do not use InvokeAsyncSafe, return only after invocation
SessionData.Add(key, value);
});
}
}
public void LoadNotificationLayout(string fontSize, string headLayout){
form.InvokeAsyncSafe(() => {
FontSize = fontSize;
NotificationHeadLayout = headLayout;
});
// Notification only
public sealed class Notification : TweetDeckBridge{
public Notification(FormBrowser form, FormNotificationMain notification) : base(form, notification){}
public void DisplayTooltip(string text){
notification.InvokeAsyncSafe(() => notification.DisplayTooltip(text));
}
public void LoadNextNotification(){
notification.InvokeAsyncSafe(notification.FinishCurrentNotification);
}
public void ShowTweetDetail(){
notification.InvokeAsyncSafe(notification.ShowTweetDetail);
}
}
// Global
public void SetLastRightClickInfo(string type, string link){
form.InvokeAsyncSafe(() => ContextMenuBase.SetContextInfo(type, link));
}
public void SetLastHighlightedTweet(string tweetUrl, string quoteUrl, string authors, string imageList){
form.InvokeAsyncSafe(() => {
LastHighlightedTweetUrl = tweetUrl;
LastHighlightedQuoteUrl = quoteUrl;
LastHighlightedTweetAuthors = authors;
LastHighlightedTweetImages = imageList;
});
}
public void OpenContextMenu(){
form.InvokeAsyncSafe(form.OpenContextMenu);
}
public void OnTweetPopup(string columnId, string chirpId, string columnName, string tweetHtml, int tweetCharacters, string tweetUrl, string quoteUrl){
notification.InvokeAsyncSafe(() => {
form.OnTweetNotification();
@@ -94,25 +130,6 @@ namespace TweetDuck.Core.Bridge{
});
}
public void DisplayTooltip(string text, bool showInNotification){
if (showInNotification){
notification.InvokeAsyncSafe(() => notification.DisplayTooltip(text));
}
else{
form.InvokeAsyncSafe(() => form.DisplayTooltip(text));
}
}
public void SetSessionData(string key, string value){
form.InvokeSafe(() => { // do not use InvokeAsyncSafe, return only after invocation
SessionData.Add(key, value);
});
}
public void LoadNextNotification(){
notification.InvokeAsyncSafe(notification.FinishCurrentNotification);
}
public void ScreenshotTweet(string html, int width, int height){
form.InvokeAsyncSafe(() => form.OnTweetScreenshotReady(html, width, height));
}

View File

@@ -67,7 +67,7 @@ namespace TweetDuck.Core{
this.notification = new FormNotificationTweet(this, plugins);
this.notification.Show();
this.browser = new TweetDeckBrowser(this, plugins, new TweetDeckBridge(this, notification));
this.browser = new TweetDeckBrowser(this, plugins, new TweetDeckBridge.Browser(this, notification));
this.browser.PageLoaded += browser_PageLoaded;
this.contextMenu = ContextMenuBrowser.CreateMenu(this);

View File

@@ -11,6 +11,7 @@ namespace TweetDuck.Core.Handling.General{
private static void UpdatePrefsInternal(){
using(IRequestContext ctx = Cef.GetGlobalRequestContext()){
ctx.SetPreference("browser.enable_spellchecking", Program.UserConfig.EnableSpellCheck, out string _);
ctx.SetPreference("spellcheck.dictionary", Program.UserConfig.SpellCheckLanguage, out string _);
ctx.SetPreference("settings.a11y.animation_policy", Program.UserConfig.EnableAnimatedImages ? "allowed" : "none", out string _);
}
}

View File

@@ -1,4 +1,5 @@
using System.Windows.Forms;
using TweetDuck.Core.Controls;
using TweetDuck.Plugins;
using TweetDuck.Resources;
@@ -32,6 +33,10 @@ namespace TweetDuck.Core.Notification.Example{
exampleNotification = TweetNotification.Example(exampleTweetHTML, 95);
}
public override void HideNotification(){
Location = ControlExtensions.InvisibleLocation;
}
public void ShowExampleNotification(bool reset){
if (reset){
LoadTweet(exampleNotification);

View File

@@ -181,6 +181,8 @@ namespace TweetDuck.Core.Notification{
public virtual void HideNotification(){
browser.Load("about:blank");
DisplayTooltip(null);
Location = ControlExtensions.InvisibleLocation;
currentNotification = null;
}
@@ -206,7 +208,9 @@ namespace TweetDuck.Core.Notification{
protected virtual void LoadTweet(TweetNotification tweet){
currentNotification = tweet;
resourceHandler.SetHTML(GetTweetHTML(tweet));
browser.Load(TwitterUtils.TweetDeckURL);
DisplayTooltip(null);
}
protected virtual void SetNotificationSize(int width, int height){

View File

@@ -83,7 +83,7 @@ namespace TweetDuck.Core.Notification{
browser.KeyboardHandler = new KeyboardHandlerNotification(this);
browser.RegisterAsyncJsObject("$TD", new TweetDeckBridge(owner, this));
browser.RegisterAsyncJsObject("$TD", new TweetDeckBridge.Notification(owner, this));
browser.RegisterAsyncJsObject("$TDP", plugins.Bridge);
browser.LoadingStateChanged += Browser_LoadingStateChanged;

View File

@@ -38,12 +38,13 @@ namespace TweetDuck.Core.Other.Analytics{
0,
{ "Hardware Acceleration" , Bool(SysConfig.HardwareAcceleration) },
0,
{ "Expand Links" , Bool(UserConfig.ExpandLinksOnHover) },
{ "Switch Account Selectors" , Bool(UserConfig.SwitchAccountSelectors) },
{ "Search In First Column" , Bool(UserConfig.OpenSearchInFirstColumn) },
{ "Best Image Quality" , Bool(UserConfig.BestImageQuality) },
{ "Spell Check" , Bool(UserConfig.EnableSpellCheck) },
{ "Zoom" , Exact(UserConfig.ZoomLevel) },
{ "Expand Links" , Bool(UserConfig.ExpandLinksOnHover) },
{ "Switch Account Selectors" , Bool(UserConfig.SwitchAccountSelectors) },
{ "Search In First Column" , Bool(UserConfig.OpenSearchInFirstColumn) },
{ "Keep Like Follow Dialogs Open" , Bool(UserConfig.KeepLikeFollowDialogsOpen) },
{ "Best Image Quality" , Bool(UserConfig.BestImageQuality) },
{ "Spell Check" , Bool(UserConfig.EnableSpellCheck) },
{ "Zoom" , Exact(UserConfig.ZoomLevel) },
0,
{ "Updates" , Bool(UserConfig.EnableUpdateCheck) },
{ "Update Dismissed" , Bool(!string.IsNullOrEmpty(UserConfig.DismissedUpdate)) },

View File

@@ -9,6 +9,7 @@ using TweetDuck.Core.Handling.General;
using TweetDuck.Core.Other.Analytics;
using TweetDuck.Core.Utils;
using System.Text.RegularExpressions;
using TweetDuck.Resources;
namespace TweetDuck.Core.Other{
sealed partial class FormGuide : Form{
@@ -73,6 +74,7 @@ namespace TweetDuck.Core.Other{
browser.LoadingStateChanged += browser_LoadingStateChanged;
browser.FrameLoadStart += browser_FrameLoadStart;
browser.FrameLoadEnd += browser_FrameLoadEnd;
browser.BrowserSettings.BackgroundColor = (uint)BackColor.ToArgb();
browser.Dock = DockStyle.None;
@@ -110,6 +112,11 @@ namespace TweetDuck.Core.Other{
BrowserUtils.SetZoomLevel(browser.GetBrowser(), Program.UserConfig.ZoomLevel);
}
private void browser_FrameLoadEnd(object sender, FrameLoadEndEventArgs e){
// idiot chromium
ScriptLoader.ExecuteScript(e.Frame, "Array.prototype.forEach.call(document.getElementsByTagName('A'), ele => ele.addEventListener('click', e => { e.preventDefault(); window.open(ele.getAttribute('href')); }))", "gen:links");
}
private void Config_ZoomLevelChanged(object sender, EventArgs e){
BrowserUtils.SetZoomLevel(browser.GetBrowser(), Program.UserConfig.ZoomLevel);
}

View File

@@ -40,6 +40,7 @@
this.checkAnimatedAvatars = new System.Windows.Forms.CheckBox();
this.labelUpdates = new System.Windows.Forms.Label();
this.flowPanel = new System.Windows.Forms.FlowLayoutPanel();
this.checkKeepLikeFollowDialogsOpen = new System.Windows.Forms.CheckBox();
((System.ComponentModel.ISupportInitialize)(this.trackBarZoom)).BeginInit();
this.panelZoom.SuspendLayout();
this.flowPanel.SuspendLayout();
@@ -59,7 +60,7 @@
// checkUpdateNotifications
//
this.checkUpdateNotifications.AutoSize = true;
this.checkUpdateNotifications.Location = new System.Drawing.Point(6, 245);
this.checkUpdateNotifications.Location = new System.Drawing.Point(6, 268);
this.checkUpdateNotifications.Margin = new System.Windows.Forms.Padding(6, 6, 3, 3);
this.checkUpdateNotifications.Name = "checkUpdateNotifications";
this.checkUpdateNotifications.Size = new System.Drawing.Size(165, 17);
@@ -69,7 +70,7 @@
//
// btnCheckUpdates
//
this.btnCheckUpdates.Location = new System.Drawing.Point(5, 268);
this.btnCheckUpdates.Location = new System.Drawing.Point(5, 291);
this.btnCheckUpdates.Margin = new System.Windows.Forms.Padding(5, 3, 3, 3);
this.btnCheckUpdates.Name = "btnCheckUpdates";
this.btnCheckUpdates.Size = new System.Drawing.Size(144, 23);
@@ -102,7 +103,7 @@
// checkBestImageQuality
//
this.checkBestImageQuality.AutoSize = true;
this.checkBestImageQuality.Location = new System.Drawing.Point(6, 95);
this.checkBestImageQuality.Location = new System.Drawing.Point(6, 118);
this.checkBestImageQuality.Margin = new System.Windows.Forms.Padding(6, 3, 3, 3);
this.checkBestImageQuality.Name = "checkBestImageQuality";
this.checkBestImageQuality.Size = new System.Drawing.Size(114, 17);
@@ -139,7 +140,7 @@
// labelZoom
//
this.labelZoom.AutoSize = true;
this.labelZoom.Location = new System.Drawing.Point(3, 150);
this.labelZoom.Location = new System.Drawing.Point(3, 173);
this.labelZoom.Margin = new System.Windows.Forms.Padding(3, 12, 3, 0);
this.labelZoom.Name = "labelZoom";
this.labelZoom.Size = new System.Drawing.Size(34, 13);
@@ -167,7 +168,7 @@
this.panelZoom.Anchor = System.Windows.Forms.AnchorStyles.Top;
this.panelZoom.Controls.Add(this.trackBarZoom);
this.panelZoom.Controls.Add(this.labelZoomValue);
this.panelZoom.Location = new System.Drawing.Point(0, 163);
this.panelZoom.Location = new System.Drawing.Point(0, 186);
this.panelZoom.Margin = new System.Windows.Forms.Padding(0);
this.panelZoom.Name = "panelZoom";
this.panelZoom.Size = new System.Drawing.Size(322, 36);
@@ -176,7 +177,7 @@
// checkAnimatedAvatars
//
this.checkAnimatedAvatars.AutoSize = true;
this.checkAnimatedAvatars.Location = new System.Drawing.Point(6, 118);
this.checkAnimatedAvatars.Location = new System.Drawing.Point(6, 141);
this.checkAnimatedAvatars.Margin = new System.Windows.Forms.Padding(6, 3, 3, 3);
this.checkAnimatedAvatars.Name = "checkAnimatedAvatars";
this.checkAnimatedAvatars.Size = new System.Drawing.Size(145, 17);
@@ -188,7 +189,7 @@
//
this.labelUpdates.AutoSize = true;
this.labelUpdates.Font = new System.Drawing.Font("Microsoft Sans Serif", 12F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(238)));
this.labelUpdates.Location = new System.Drawing.Point(0, 219);
this.labelUpdates.Location = new System.Drawing.Point(0, 242);
this.labelUpdates.Margin = new System.Windows.Forms.Padding(0, 20, 0, 0);
this.labelUpdates.Name = "labelUpdates";
this.labelUpdates.Size = new System.Drawing.Size(70, 20);
@@ -204,6 +205,7 @@
this.flowPanel.Controls.Add(this.checkExpandLinks);
this.flowPanel.Controls.Add(this.checkSwitchAccountSelectors);
this.flowPanel.Controls.Add(this.checkOpenSearchInFirstColumn);
this.flowPanel.Controls.Add(this.checkKeepLikeFollowDialogsOpen);
this.flowPanel.Controls.Add(this.checkBestImageQuality);
this.flowPanel.Controls.Add(this.checkAnimatedAvatars);
this.flowPanel.Controls.Add(this.labelZoom);
@@ -214,17 +216,28 @@
this.flowPanel.FlowDirection = System.Windows.Forms.FlowDirection.TopDown;
this.flowPanel.Location = new System.Drawing.Point(9, 9);
this.flowPanel.Name = "flowPanel";
this.flowPanel.Size = new System.Drawing.Size(322, 296);
this.flowPanel.Size = new System.Drawing.Size(322, 319);
this.flowPanel.TabIndex = 4;
this.flowPanel.WrapContents = false;
//
// checkKeepLikeFollowDialogsOpen
//
this.checkKeepLikeFollowDialogsOpen.AutoSize = true;
this.checkKeepLikeFollowDialogsOpen.Location = new System.Drawing.Point(6, 95);
this.checkKeepLikeFollowDialogsOpen.Margin = new System.Windows.Forms.Padding(6, 3, 3, 3);
this.checkKeepLikeFollowDialogsOpen.Name = "checkKeepLikeFollowDialogsOpen";
this.checkKeepLikeFollowDialogsOpen.Size = new System.Drawing.Size(176, 17);
this.checkKeepLikeFollowDialogsOpen.TabIndex = 7;
this.checkKeepLikeFollowDialogsOpen.Text = "Keep Like/Follow Dialogs Open";
this.checkKeepLikeFollowDialogsOpen.UseVisualStyleBackColor = true;
//
// TabSettingsGeneral
//
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
this.Controls.Add(this.flowPanel);
this.Name = "TabSettingsGeneral";
this.Size = new System.Drawing.Size(340, 314);
this.Size = new System.Drawing.Size(340, 337);
((System.ComponentModel.ISupportInitialize)(this.trackBarZoom)).EndInit();
this.panelZoom.ResumeLayout(false);
this.flowPanel.ResumeLayout(false);
@@ -251,5 +264,6 @@
private System.Windows.Forms.CheckBox checkOpenSearchInFirstColumn;
private System.Windows.Forms.CheckBox checkAnimatedAvatars;
private System.Windows.Forms.FlowLayoutPanel flowPanel;
private System.Windows.Forms.CheckBox checkKeepLikeFollowDialogsOpen;
}
}

View File

@@ -21,6 +21,7 @@ namespace TweetDuck.Core.Other.Settings{
toolTip.SetToolTip(checkExpandLinks, "Expands links inside the tweets. If disabled,\r\nthe full links show up in a tooltip instead.");
toolTip.SetToolTip(checkSwitchAccountSelectors, "When (re)tweeting, click to select a single account or hold Shift to\r\nselect multiple accounts, instead of TweetDeck\'s default behavior.");
toolTip.SetToolTip(checkOpenSearchInFirstColumn, "By default, TweetDeck adds Search columns at the end.\r\nThis option makes them appear before the first column instead.");
toolTip.SetToolTip(checkKeepLikeFollowDialogsOpen, "Allows liking and following from multiple accounts at once,\r\ninstead of automatically closing the dialog after taking an action.");
toolTip.SetToolTip(checkBestImageQuality, "When right-clicking a tweet image, the context menu options\r\nwill use links to the original image size (:orig in the URL).");
toolTip.SetToolTip(checkAnimatedAvatars, "Some old Twitter avatars could be uploaded as animated GIFs.");
@@ -36,6 +37,7 @@ namespace TweetDuck.Core.Other.Settings{
checkExpandLinks.Checked = Config.ExpandLinksOnHover;
checkSwitchAccountSelectors.Checked = Config.SwitchAccountSelectors;
checkOpenSearchInFirstColumn.Checked = Config.OpenSearchInFirstColumn;
checkKeepLikeFollowDialogsOpen.Checked = Config.KeepLikeFollowDialogsOpen;
checkBestImageQuality.Checked = Config.BestImageQuality;
checkAnimatedAvatars.Checked = Config.EnableAnimatedImages;
@@ -46,6 +48,7 @@ namespace TweetDuck.Core.Other.Settings{
checkExpandLinks.CheckedChanged += checkExpandLinks_CheckedChanged;
checkSwitchAccountSelectors.CheckedChanged += checkSwitchAccountSelectors_CheckedChanged;
checkOpenSearchInFirstColumn.CheckedChanged += checkOpenSearchInFirstColumn_CheckedChanged;
checkKeepLikeFollowDialogsOpen.CheckedChanged += checkKeepLikeFollowDialogsOpen_CheckedChanged;
checkBestImageQuality.CheckedChanged += checkBestImageQuality_CheckedChanged;
checkAnimatedAvatars.CheckedChanged += checkAnimatedAvatars_CheckedChanged;
trackBarZoom.ValueChanged += trackBarZoom_ValueChanged;
@@ -70,6 +73,10 @@ namespace TweetDuck.Core.Other.Settings{
Config.OpenSearchInFirstColumn = checkOpenSearchInFirstColumn.Checked;
}
private void checkKeepLikeFollowDialogsOpen_CheckedChanged(object sender, EventArgs e){
Config.KeepLikeFollowDialogsOpen = checkKeepLikeFollowDialogsOpen.Checked;
}
private void checkBestImageQuality_CheckedChanged(object sender, EventArgs e){
Config.BestImageQuality = checkBestImageQuality.Checked;
}

View File

@@ -28,8 +28,8 @@
this.checkSpellCheck = new System.Windows.Forms.CheckBox();
this.labelLocales = new System.Windows.Forms.Label();
this.flowPanel = new System.Windows.Forms.FlowLayoutPanel();
this.labelAppLanguage = new System.Windows.Forms.Label();
this.comboBoxAppLocale = new System.Windows.Forms.ComboBox();
this.labelSpellCheckLanguage = new System.Windows.Forms.Label();
this.comboBoxSpellCheckLanguage = new System.Windows.Forms.ComboBox();
this.labelTranslations = new System.Windows.Forms.Label();
this.labelTranslationTarget = new System.Windows.Forms.Label();
this.comboBoxTranslationTarget = new System.Windows.Forms.ComboBox();
@@ -65,8 +65,8 @@
| System.Windows.Forms.AnchorStyles.Right)));
this.flowPanel.Controls.Add(this.labelLocales);
this.flowPanel.Controls.Add(this.checkSpellCheck);
this.flowPanel.Controls.Add(this.labelAppLanguage);
this.flowPanel.Controls.Add(this.comboBoxAppLocale);
this.flowPanel.Controls.Add(this.labelSpellCheckLanguage);
this.flowPanel.Controls.Add(this.comboBoxSpellCheckLanguage);
this.flowPanel.Controls.Add(this.labelTranslations);
this.flowPanel.Controls.Add(this.labelTranslationTarget);
this.flowPanel.Controls.Add(this.comboBoxTranslationTarget);
@@ -77,25 +77,25 @@
this.flowPanel.TabIndex = 4;
this.flowPanel.WrapContents = false;
//
// labelAppLanguage
// labelSpellCheckLanguage
//
this.labelAppLanguage.AutoSize = true;
this.labelAppLanguage.Location = new System.Drawing.Point(3, 58);
this.labelAppLanguage.Margin = new System.Windows.Forms.Padding(3, 12, 3, 0);
this.labelAppLanguage.Name = "labelAppLanguage";
this.labelAppLanguage.Size = new System.Drawing.Size(77, 13);
this.labelAppLanguage.TabIndex = 11;
this.labelAppLanguage.Text = "App Language";
this.labelSpellCheckLanguage.AutoSize = true;
this.labelSpellCheckLanguage.Location = new System.Drawing.Point(3, 58);
this.labelSpellCheckLanguage.Margin = new System.Windows.Forms.Padding(3, 12, 3, 0);
this.labelSpellCheckLanguage.Name = "labelSpellCheckLanguage";
this.labelSpellCheckLanguage.Size = new System.Drawing.Size(115, 13);
this.labelSpellCheckLanguage.TabIndex = 11;
this.labelSpellCheckLanguage.Text = "Spell Check Language";
//
// comboBoxAppLocale
// comboBoxSpellCheckLanguage
//
this.comboBoxAppLocale.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList;
this.comboBoxAppLocale.FormattingEnabled = true;
this.comboBoxAppLocale.Location = new System.Drawing.Point(5, 74);
this.comboBoxAppLocale.Margin = new System.Windows.Forms.Padding(5, 3, 3, 3);
this.comboBoxAppLocale.Name = "comboBoxAppLocale";
this.comboBoxAppLocale.Size = new System.Drawing.Size(311, 21);
this.comboBoxAppLocale.TabIndex = 9;
this.comboBoxSpellCheckLanguage.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList;
this.comboBoxSpellCheckLanguage.FormattingEnabled = true;
this.comboBoxSpellCheckLanguage.Location = new System.Drawing.Point(5, 74);
this.comboBoxSpellCheckLanguage.Margin = new System.Windows.Forms.Padding(5, 3, 3, 3);
this.comboBoxSpellCheckLanguage.Name = "comboBoxSpellCheckLanguage";
this.comboBoxSpellCheckLanguage.Size = new System.Drawing.Size(311, 21);
this.comboBoxSpellCheckLanguage.TabIndex = 9;
//
// labelTranslations
//
@@ -148,8 +148,8 @@
private System.Windows.Forms.FlowLayoutPanel flowPanel;
private System.Windows.Forms.ComboBox comboBoxTranslationTarget;
private System.Windows.Forms.Label labelTranslationTarget;
private System.Windows.Forms.ComboBox comboBoxAppLocale;
private System.Windows.Forms.ComboBox comboBoxSpellCheckLanguage;
private System.Windows.Forms.Label labelTranslations;
private System.Windows.Forms.Label labelAppLanguage;
private System.Windows.Forms.Label labelSpellCheckLanguage;
}
}

View File

@@ -8,20 +8,20 @@ namespace TweetDuck.Core.Other.Settings{
InitializeComponent();
toolTip.SetToolTip(checkSpellCheck, "Underlines words that are spelled incorrectly.");
toolTip.SetToolTip(comboBoxAppLocale, "Language used for spell check and context menu items.");
toolTip.SetToolTip(comboBoxSpellCheckLanguage, "Language used for spell check.");
toolTip.SetToolTip(comboBoxTranslationTarget, "Language tweets are translated into.");
checkSpellCheck.Checked = Config.EnableSpellCheck;
try{
foreach(LocaleUtils.Item item in LocaleUtils.ChromiumLocales){
comboBoxAppLocale.Items.Add(item);
foreach(LocaleUtils.Item item in LocaleUtils.SpellCheckLanguages){
comboBoxSpellCheckLanguage.Items.Add(item);
}
}catch{
comboBoxAppLocale.Items.Add(new LocaleUtils.Item("en-US"));
comboBoxSpellCheckLanguage.Items.Add(new LocaleUtils.Item("en-US"));
}
comboBoxAppLocale.SelectedItem = new LocaleUtils.Item(Config.AppLocale);
comboBoxSpellCheckLanguage.SelectedItem = new LocaleUtils.Item(Config.SpellCheckLanguage);
foreach(LocaleUtils.Item item in LocaleUtils.TweetDeckTranslationLocales){
comboBoxTranslationTarget.Items.Add(item);
@@ -32,7 +32,7 @@ namespace TweetDuck.Core.Other.Settings{
public override void OnReady(){
checkSpellCheck.CheckedChanged += checkSpellCheck_CheckedChanged;
comboBoxAppLocale.SelectedValueChanged += comboBoxAppLocale_SelectedValueChanged;
comboBoxSpellCheckLanguage.SelectedValueChanged += comboBoxSpellCheckLanguage_SelectedValueChanged;
comboBoxTranslationTarget.SelectedValueChanged += comboBoxTranslationTarget_SelectedValueChanged;
}
@@ -41,8 +41,8 @@ namespace TweetDuck.Core.Other.Settings{
BrowserProcessHandler.UpdatePrefs();
}
private void comboBoxAppLocale_SelectedValueChanged(object sender, EventArgs e){
Config.AppLocale = (comboBoxAppLocale.SelectedItem as LocaleUtils.Item)?.Code;
private void comboBoxSpellCheckLanguage_SelectedValueChanged(object sender, EventArgs e){
Config.SpellCheckLanguage = (comboBoxSpellCheckLanguage.SelectedItem as LocaleUtils.Item)?.Code;
PromptRestart();
}

View File

@@ -10,19 +10,7 @@ using TweetDuck.Core.Other;
namespace TweetDuck.Core.Utils{
static class BrowserUtils{
public static string HeaderAcceptLanguage{
get{
string culture = Program.UserConfig.AppLocale;
if (culture == "en"){
return "en-us,en";
}
else{
return culture.ToLower()+",en;q=0.9";
}
}
}
public static string HeaderAcceptLanguage => "en-us,en";
public static string HeaderUserAgent => Program.BrandName+" "+Application.ProductVersion;
public static void SetupCefArgs(IDictionary<string, string> args){

View File

@@ -1,17 +1,23 @@
using System;
using System.Collections.Generic;
using System.Globalization;
using System.IO;
using System.Linq;
namespace TweetDuck.Core.Utils{
static class LocaleUtils{
public static string LocaleFolder => Path.Combine(Program.ProgramPath, "locales");
public static IEnumerable<Item> ChromiumLocales => Directory
.EnumerateFiles(LocaleFolder, "*.pak", SearchOption.TopDirectoryOnly)
.Select(file => new Item(Path.GetFileNameWithoutExtension(file)))
.OrderBy(code => code);
// https://cs.chromium.org/chromium/src/third_party/hunspell_dictionaries/
public static IEnumerable<Item> SpellCheckLanguages { get; } = new List<string>{
"af-ZA", "bg-BG", "ca-ES", "cs-CZ", "da-DK", "de-DE",
"el-GR", "en-AU", "en-CA", "en-GB", "en-US", "es-ES",
"et-EE", "fa-IR", "fo-FO", "fr-FR", "he-IL", "hi-IN",
"hr-HR", "hu-HU", "id-ID", "it-IT", "ko" , "lt-LT",
"lv-LV", "nb-NO", "nl-NL", "pl-PL", "pt-BR", "pt-PT",
"ro-RO", "ru-RU", "sk-SK", "sl-SI", "sq" , "sr",
"sv-SE", "ta-IN", "tg-TG", "tr" , "uk-UA", "vi-VN"
}.Select(code => {
string lang = StringUtils.ExtractBefore(code, '-', 2);
return lang == "en" || lang == "pt" ? new Item(code) : new Item(code, lang);
}).OrderBy(code => code).ToList();
// TD.languages.getSupportedTranslationDestinationLanguages() except for "ht", "in", "iw" which are missing/duplicates
public static IEnumerable<Item> TweetDeckTranslationLocales { get; } = new List<string>{
@@ -26,9 +32,9 @@ namespace TweetDuck.Core.Utils{
public string Code { get; }
public CultureInfo Info { get; }
public Item(string code){
public Item(string code, string alt = null){
this.Code = code;
this.Info = CultureInfo.GetCultureInfo(code);
this.Info = CultureInfo.GetCultureInfo(alt ?? code);
}
public override bool Equals(object obj){

View File

@@ -20,7 +20,7 @@ namespace TweetDuck{
public const string BrandName = "TweetDuck";
public const string Website = "https://tweetduck.chylex.com";
public const string VersionTag = "1.11.2";
public const string VersionTag = "1.12";
public static readonly bool IsPortable = File.Exists("makeportable");
@@ -133,7 +133,6 @@ namespace TweetDuck{
CefSettings settings = new CefSettings{
AcceptLanguageList = BrowserUtils.HeaderAcceptLanguage,
UserAgent = BrowserUtils.HeaderUserAgent,
Locale = UserConfig.AppLocale,
BrowserSubprocessPath = BrandName+".Browser.exe",
CachePath = StoragePath,
LogFile = ConsoleLogFilePath,

View File

@@ -9,7 +9,7 @@ Emoji keyboard
chylex
[version]
1.4.1
1.4.2
[website]
https://tweetduck.chylex.com

View File

@@ -349,7 +349,7 @@ enabled(){
lastEmojiLength = foundEmoji.length;
}
}
else if (foundNames.length > 1){
else if (foundNames.length > 1 && $(".js-app-content").is(".is-open")){
e.preventDefault();
ele.val(val.substring(0, firstColon)+val.substring(ele[0].selectionStart));
ele[0].selectionEnd = ele[0].selectionStart = firstColon;
@@ -399,6 +399,7 @@ enabled(){
ready(){
this.composeDrawer = $("[data-drawer='compose']");
this.composeInput = $(".js-compose-text", ".js-docked-compose");
this.composeSelector = ".js-compose-text,.js-reply-tweetbox";
this.composePanelScroller = $(".js-compose-scroller", ".js-docked-compose").first().children().first();
this.composePanelScroller.on("scroll", this.composerScrollEvent);
@@ -407,11 +408,12 @@ ready(){
$(document).on("click", this.documentClickEvent);
$(document).on("keydown", this.documentKeyEvent);
$(document).on("uiComposeImageAdded", this.uploadFilesEvent);
this.composeInput.on("keydown", this.composeInputKeyDownEvent);
this.composeInput.on("keypress", this.composeInputKeyPressEvent);
this.composeInput.on("focus", this.composeInputFocusEvent);
this.composeDrawer.on("uiComposeTweetSending", this.composerSendingEvent);
$(document).on("keydown", this.composeSelector, this.composeInputKeyDownEvent);
$(document).on("keypress", this.composeSelector, this.composeInputKeyPressEvent);
$(document).on("focus", this.composeSelector, this.composeInputFocusEvent);
// HTML generation
var convUnicode = function(codePt){
@@ -533,10 +535,11 @@ disabled(){
$(document).off("click", this.documentClickEvent);
$(document).off("keydown", this.documentKeyEvent);
$(document).off("uiComposeImageAdded", this.uploadFilesEvent);
this.composeInput.off("keydown", this.composeInputKeyDownEvent);
this.composeInput.off("keypress", this.composeInputKeyPressEvent);
this.composeInput.off("focus", this.composeInputFocusEvent);
this.composeDrawer.off("uiComposeTweetSending", this.composerSendingEvent);
$(document).off("keydown", this.composeSelector, this.composeInputKeyDownEvent);
$(document).off("keypress", this.composeSelector, this.composeInputKeyPressEvent);
$(document).off("focus", this.composeSelector, this.composeInputFocusEvent);
TD.mustaches["compose/docked_compose.mustache"] = this.prevComposeMustache;
}

View File

@@ -182,6 +182,12 @@
this.outerHTML = this.innerHTML;
});
html.find("p.link-complex-target").filter(function(){
return $(this).text() === "Show this thread";
}).first().each(function(){
this.id = "tduck-show-thread";
});
let type = tweet.getChirpType();
if (type === "follow"){
@@ -286,6 +292,7 @@
tags.push(".tweet-context .nbfc { text-overflow: ellipsis !important; white-space: nowrap !important }"); // force ellipsis on long usernames
tags.push(".activity-header { align-items: center !important; margin-bottom: 4px !important }"); // tweak alignment of avatar and text in notifications
tags.push(".activity-header .tweet-timestamp { line-height: unset !important }"); // fix timestamp position in notifications
tags.push("#tduck-show-thread { display: inline-block !important; cursor: pointer }");
if (fontSizeName === "smallest"){
tags.push(".badge-verified:before { width: 13px !important; height: 13px !important; background-position: -223px -98px !important }"); // fix cut off badge icon
@@ -388,7 +395,7 @@
}
else{
tooltipTimer = window.setTimeout(function(){
$TD.displayTooltip(me.attr("data-full-url"), false);
$TD.displayTooltip(me.attr("data-full-url"));
tooltipDisplayed = true;
}, 400);
}
@@ -405,13 +412,13 @@
if (tooltipDisplayed){
tooltipDisplayed = false;
$TD.displayTooltip(null, false);
$TD.displayTooltip(null);
}
},
mousemove: function(e){
if (tooltipDisplayed && (prevMouseX !== e.clientX || prevMouseY !== e.clientY)){
$TD.displayTooltip($(this).attr("data-full-url"), false);
$TD.displayTooltip($(this).attr("data-full-url"));
prevMouseX = e.clientX;
prevMouseY = e.clientY;
}
@@ -1164,6 +1171,17 @@
}));
};
//
// Block: Revert Like/Follow dialogs being closed after clicking an action.
//
if (ensurePropertyExists(TD, "decider", "get")){
const prevFunc = TD.decider.get;
TD.decider.get = function(key){
return $TDX.keepLikeFollowDialogsOpen && key.startsWith("tweetdeck_subsequent_") ? false : prevFunc.apply(this, arguments);
};
}
//
// Block: Fix DM reply input box not getting focused after opening a conversation.
//

View File

@@ -62,7 +62,7 @@
}
else{
tooltipTimer = window.setTimeout(function(){
$TD.displayTooltip(url, true);
$TD.displayTooltip(url);
tooltipDisplayed = true;
}, 400);
}
@@ -83,7 +83,7 @@
if (tooltipDisplayed){
tooltipDisplayed = false;
$TD.displayTooltip(null, true);
$TD.displayTooltip(null);
}
});
@@ -92,13 +92,32 @@
var url = e.currentTarget.getAttribute("data-full-url");
return if !url;
$TD.displayTooltip(url, true);
$TD.displayTooltip(url);
prevMouseX = e.clientX;
prevMouseY = e.clientY;
}
});
})();
//
// Block: Work around clipboard HTML formatting.
//
document.addEventListener("copy", function(e){
window.setTimeout($TD.fixClipboard, 0);
});
//
// Block: Setup a handler for 'Show this thread'.
//
(function(){
var btn = document.getElementById("tduck-show-thread");
return if !btn;
btn.addEventListener("click", function(){
$TD.showNotificationTweetDetail();
});
})();
//
// Block: Setup a skip button.
//

View File

@@ -403,19 +403,25 @@ ren "$(TargetDir)LICENSE.md" "LICENSE.txt"
xcopy "$(ProjectDir)bld\Resources\CEFSHARP-LICENSE.txt" "$(TargetDir)" /Y
xcopy "$(ProjectDir)packages\Microsoft.VC120.CRT.JetBrains.12.0.21005.2\DotFiles\msvcp120.dll" "$(TargetDir)" /Y
xcopy "$(ProjectDir)packages\Microsoft.VC120.CRT.JetBrains.12.0.21005.2\DotFiles\msvcr120.dll" "$(TargetDir)" /Y
rmdir "$(TargetDir)scripts" /S /Q
mkdir "$(TargetDir)scripts"
xcopy "$(ProjectDir)Resources\Scripts\*" "$(TargetDir)scripts\" /E /Y
rmdir "$(TargetDir)plugins" /S /Q
mkdir "$(TargetDir)plugins"
mkdir "$(TargetDir)plugins\official"
mkdir "$(TargetDir)plugins\user"
xcopy "$(ProjectDir)Resources\Plugins\*" "$(TargetDir)plugins\official\" /E /Y
rmdir "$(TargetDir)plugins\official\.debug" /S /Q
del "$(TargetDir)plugins\official\emoji-keyboard\emoji-instructions.txt"
rmdir "$(ProjectDir)bin\Debug"
rmdir "$(ProjectDir)bin\Release"
rmdir "$(TargetDir)plugins\official\.debug" /S /Q
del "$(TargetDir)plugins\official\emoji-keyboard\emoji-instructions.txt"
attrib +R "$(TargetDir)locales\en-US.pak"
del /Q /A:-R "$(TargetDir)locales\*.pak"
attrib -R "$(TargetDir)locales\en-US.pak"
if $(ConfigurationName) == Debug (
rmdir "$(TargetDir)plugins\official\.debug" /S /Q

Binary file not shown.

View File

@@ -60,6 +60,58 @@ Type: filesandordirs; Name: "{localappdata}\{#MyAppName}\GPUCache"
[InstallDelete]
Type: filesandordirs; Name: "{app}\plugins\official"
Type: files; Name: "{app}\locales\am.pak"
Type: files; Name: "{app}\locales\ar.pak"
Type: files; Name: "{app}\locales\bg.pak"
Type: files; Name: "{app}\locales\bn.pak"
Type: files; Name: "{app}\locales\ca.pak"
Type: files; Name: "{app}\locales\cs.pak"
Type: files; Name: "{app}\locales\da.pak"
Type: files; Name: "{app}\locales\de.pak"
Type: files; Name: "{app}\locales\el.pak"
Type: files; Name: "{app}\locales\en-GB.pak"
Type: files; Name: "{app}\locales\es-419.pak"
Type: files; Name: "{app}\locales\es.pak"
Type: files; Name: "{app}\locales\et.pak"
Type: files; Name: "{app}\locales\fa.pak"
Type: files; Name: "{app}\locales\fi.pak"
Type: files; Name: "{app}\locales\fil.pak"
Type: files; Name: "{app}\locales\fr.pak"
Type: files; Name: "{app}\locales\gu.pak"
Type: files; Name: "{app}\locales\he.pak"
Type: files; Name: "{app}\locales\hi.pak"
Type: files; Name: "{app}\locales\hr.pak"
Type: files; Name: "{app}\locales\hu.pak"
Type: files; Name: "{app}\locales\id.pak"
Type: files; Name: "{app}\locales\it.pak"
Type: files; Name: "{app}\locales\ja.pak"
Type: files; Name: "{app}\locales\kn.pak"
Type: files; Name: "{app}\locales\ko.pak"
Type: files; Name: "{app}\locales\lt.pak"
Type: files; Name: "{app}\locales\lv.pak"
Type: files; Name: "{app}\locales\ml.pak"
Type: files; Name: "{app}\locales\mr.pak"
Type: files; Name: "{app}\locales\ms.pak"
Type: files; Name: "{app}\locales\nb.pak"
Type: files; Name: "{app}\locales\nl.pak"
Type: files; Name: "{app}\locales\pl.pak"
Type: files; Name: "{app}\locales\pt-BR.pak"
Type: files; Name: "{app}\locales\pt-PT.pak"
Type: files; Name: "{app}\locales\ro.pak"
Type: files; Name: "{app}\locales\ru.pak"
Type: files; Name: "{app}\locales\sk.pak"
Type: files; Name: "{app}\locales\sl.pak"
Type: files; Name: "{app}\locales\sr.pak"
Type: files; Name: "{app}\locales\sv.pak"
Type: files; Name: "{app}\locales\sw.pak"
Type: files; Name: "{app}\locales\ta.pak"
Type: files; Name: "{app}\locales\te.pak"
Type: files; Name: "{app}\locales\th.pak"
Type: files; Name: "{app}\locales\tr.pak"
Type: files; Name: "{app}\locales\uk.pak"
Type: files; Name: "{app}\locales\vi.pak"
Type: files; Name: "{app}\locales\zh-CN.pak"
Type: files; Name: "{app}\locales\zh-TW.pak"
[Code]
function TDIsUninstallable: Boolean; forward;