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

Compare commits

...

25 Commits
1.6.2 ... 1.6.3

Author SHA1 Message Date
92af85d3bb Release 1.6.3 2017-01-28 18:49:23 +01:00
7635af5730 Add an AppName suffix for portable and update installers 2017-01-28 18:49:14 +01:00
a838e89695 Fix custom sound notification textbox not setting color when the control is created 2017-01-28 18:12:30 +01:00
b22289a8b9 Work around Alt freezing the app since W10 Anniversary Update
Get fucked, Microsoft
2017-01-28 17:44:30 +01:00
45b3ff52c6 Tweak FormBrowser.ShowChildForm to use VisibleChanged instead of Shown event for reliability 2017-01-28 01:08:31 +01:00
4464991f4c Prevent automatic Settings tab selection from triggering autoclick in Notification tab 2017-01-28 01:07:57 +01:00
b0d2f77583 Merge pull request #101 from chylex/ipc
Replace WCF with native chromium IPC
2017-01-28 00:01:22 +01:00
b211a4405d Set CefSharpSettings.WcfEnabled to false 2017-01-27 23:59:01 +01:00
8823016d2c Make custom sound notification textbox font red when the file doesn't exist 2017-01-27 23:56:51 +01:00
859fdc7ec1 Rewrite custom sound notification to show an error message on failure instead of hiding it 2017-01-27 23:56:00 +01:00
028d5ed01f Improve debug script for easier extendibility, add sound notification simulation 2017-01-27 21:48:57 +01:00
5fd5a2a436 Use and test RegisterAsyncJsObject in FormBrowser 2017-01-27 18:51:14 +01:00
79a7e7470c Use and test RegisterAsyncJsObject in FormNotification 2017-01-27 17:00:09 +01:00
9ecef78aed Fix DismissedUpdate not being set after toggling updates 2017-01-27 16:21:36 +01:00
65a837a6e1 Move TweetDeckBridge properties to a separate JS object 2017-01-27 16:13:17 +01:00
6e4db4acea Rewrite custom CSS injection and automatically inject it while typing 2017-01-26 15:35:40 +01:00
26fb977d05 Remove unnecessary properties from TweetDeckBridge 2017-01-26 06:51:51 +01:00
b42cd1c048 Tweak screenshot notification script (minor edit) 2017-01-26 06:46:19 +01:00
467f7cd12f Rewrite update system to use RegisterAsyncJsObject 2017-01-26 06:41:20 +01:00
66699ce9df Change update progress form to show kB instead of MB 2017-01-26 06:39:46 +01:00
cf7d903932 Move updater event args to a separate namespace 2017-01-26 04:09:04 +01:00
a7ab67925c Allow moving the notification window when holding Alt in debug builds 2017-01-23 01:13:15 +01:00
a474ba4260 Fix incorrect cursor when hovering over quoted tweet in notification
Closes #97
2017-01-23 01:00:16 +01:00
09e5636e86 Remove unused 'using' statement 2017-01-23 00:59:19 +01:00
2295a875be Fix 'Copy' context menu item (separator in wrong place in browser, missing in notification) 2017-01-23 00:53:15 +01:00
29 changed files with 342 additions and 187 deletions

View File

@@ -67,7 +67,7 @@ namespace TweetDck.Configuration{
public string NotificationSoundPath{
get{
return !string.IsNullOrEmpty(notificationSoundPath) && File.Exists(notificationSoundPath) ? notificationSoundPath : string.Empty;
return string.IsNullOrEmpty(notificationSoundPath) ? string.Empty : notificationSoundPath;
}
set{

View File

@@ -0,0 +1,34 @@
using System;
using System.Text;
namespace TweetDck.Core.Bridge{
static class PropertyBridge{
[Flags]
public enum Properties{
ExpandLinksOnHover = 1,
MuteNotifications = 2,
HasCustomNotificationSound = 4,
All = ExpandLinksOnHover | MuteNotifications | HasCustomNotificationSound
}
public static string GenerateScript(Properties properties = Properties.All){
StringBuilder build = new StringBuilder();
build.Append("(function(c){");
if (properties.HasFlag(Properties.ExpandLinksOnHover)){
build.Append("c.expandLinksOnHover=").Append(Program.UserConfig.ExpandLinksOnHover ? "true;" : "false;");
}
if (properties.HasFlag(Properties.MuteNotifications)){
build.Append("c.muteNotifications=").Append(Program.UserConfig.MuteNotifications ? "true;" : "false;");
}
if (properties.HasFlag(Properties.HasCustomNotificationSound)){
build.Append("c.hasCustomNotificationSound=").Append(Program.UserConfig.NotificationSoundPath.Length > 0 ? "true;" : "false;");
}
build.Append("})(window.$TDX=window.$TDX||{})");
return build.ToString();
}
}
}

View File

@@ -21,48 +21,6 @@ namespace TweetDck.Core.Bridge{
private readonly FormBrowser form;
private readonly FormNotification notification;
public string BrandName{
get{
return Program.BrandName;
}
}
public string VersionTag{
get{
return Program.VersionTag;
}
}
public bool MuteNotifications{
get{
return Program.UserConfig.MuteNotifications;
}
}
public bool HasCustomNotificationSound{
get{
return !string.IsNullOrEmpty(Program.UserConfig.NotificationSoundPath);
}
}
public bool ExpandLinksOnHover{
get{
return Program.UserConfig.ExpandLinksOnHover;
}
}
public bool HasCustomBrowserCSS{
get{
return !string.IsNullOrEmpty(Program.UserConfig.CustomBrowserCSS);
}
}
public string CustomBrowserCSS{
get{
return Program.UserConfig.CustomBrowserCSS;
}
}
public TweetDeckBridge(FormBrowser form, FormNotification notification){
this.form = form;
this.notification = notification;

View File

@@ -17,6 +17,8 @@ using System.Media;
using TweetDck.Core.Bridge;
using TweetDck.Core.Notification;
using TweetDck.Core.Notification.Screenshot;
using TweetDck.Updates.Events;
using System.IO;
namespace TweetDck.Core{
sealed partial class FormBrowser : Form{
@@ -42,6 +44,7 @@ namespace TweetDck.Core{
private TweetScreenshotManager notificationScreenshotManager;
private SoundPlayer notificationSound;
private bool ignoreNotificationSoundError;
public FormBrowser(PluginManager pluginManager, UpdaterSettings updaterSettings){
InitializeComponent();
@@ -53,7 +56,11 @@ namespace TweetDck.Core{
this.plugins.PluginChangedState += plugins_PluginChangedState;
this.notification = CreateNotificationForm(NotificationFlags.AutoHide | NotificationFlags.TopMost);
#if DEBUG
this.notification.CanMoveWindow = () => (ModifierKeys & Keys.Alt) == Keys.Alt;
#else
this.notification.CanMoveWindow = () => false;
#endif
this.notification.Show();
this.browser = new ChromiumWebBrowser("https://tweetdeck.twitter.com/"){
@@ -69,11 +76,13 @@ namespace TweetDck.Core{
this.browser.LoadingStateChanged += Browser_LoadingStateChanged;
this.browser.FrameLoadEnd += Browser_FrameLoadEnd;
this.browser.RegisterJsObject("$TD", new TweetDeckBridge(this, notification));
this.browser.RegisterAsyncJsObject("$TD", new TweetDeckBridge(this, notification));
this.browser.RegisterAsyncJsObject("$TDP", plugins.Bridge);
Controls.Add(browser);
Controls.Add(new MenuStrip{ Visible = false }); // fixes Alt freezing the program in Win 10 Anniversary Update
Disposed += (sender, args) => {
browser.Dispose();
@@ -92,13 +101,16 @@ namespace TweetDck.Core{
UpdateTrayIcon();
Config.MuteToggled += Config_MuteToggled;
this.updates = new UpdateHandler(browser, this, updaterSettings);
this.updates.UpdateAccepted += updates_UpdateAccepted;
this.updates.UpdateDismissed += updates_UpdateDismissed;
}
private void ShowChildForm(Form form){
form.VisibleChanged += (sender, args) => form.MoveToCenter(this);
form.Show(this);
form.Shown += (sender, args) => form.MoveToCenter(this);
}
public void ForceClose(){
@@ -135,7 +147,9 @@ namespace TweetDck.Core{
private void Browser_FrameLoadEnd(object sender, FrameLoadEndEventArgs e){
if (e.Frame.IsMain && BrowserUtils.IsTweetDeckWebsite(e.Frame)){
UpdateProperties();
ScriptLoader.ExecuteFile(e.Frame, "code.js");
ReinjectCustomCSS(Config.CustomBrowserCSS);
#if DEBUG
ScriptLoader.ExecuteFile(e.Frame, "debug.js");
@@ -192,6 +206,10 @@ namespace TweetDck.Core{
}
}
private void Config_MuteToggled(object sender, EventArgs e){
UpdateProperties(PropertyBridge.Properties.MuteNotifications);
}
private void Config_TrayBehaviorChanged(object sender, EventArgs e){
if (!isLoaded)return;
@@ -241,6 +259,11 @@ namespace TweetDck.Core{
}
}
private void updates_UpdateDismissed(object sender, UpdateDismissedEventArgs e){
Config.DismissedUpdate = e.VersionTag;
Config.Save();
}
protected override void WndProc(ref Message m){
if (isLoaded && m.Msg == Program.WindowRestoreMessage){
trayIcon_ClickRestore(trayIcon, new EventArgs());
@@ -269,6 +292,16 @@ namespace TweetDck.Core{
notification.ResumeNotification();
}
// javascript calls
public void ReinjectCustomCSS(string css){
browser.ExecuteScriptAsync("TDGF_reinjectCustomCSS", css == null ? string.Empty : css.Replace(Environment.NewLine, " "));
}
public void UpdateProperties(PropertyBridge.Properties properties = PropertyBridge.Properties.All){
browser.ExecuteScriptAsync(PropertyBridge.GenerateScript(properties));
}
// callback handlers
public void OpenSettings(){
@@ -284,14 +317,18 @@ namespace TweetDck.Core{
currentFormSettings = null;
if (!prevEnableUpdateCheck && Config.EnableUpdateCheck){
updates.Settings.DismissedUpdate = string.Empty;
Config.DismissedUpdate = string.Empty;
Config.Save();
updates.Check(false);
}
if (!Config.EnableTrayHighlight){
trayIcon.HasNotifications = false;
}
UpdateProperties(PropertyBridge.Properties.ExpandLinksOnHover | PropertyBridge.Properties.HasCustomNotificationSound);
};
ShowChildForm(currentFormSettings);
@@ -327,19 +364,49 @@ namespace TweetDck.Core{
}
public void PlayNotificationSound(){
if (string.IsNullOrEmpty(Config.NotificationSoundPath)){
if (Config.NotificationSoundPath.Length == 0){
return;
}
if (notificationSound == null){
notificationSound = new SoundPlayer();
notificationSound = new SoundPlayer{
LoadTimeout = 5000
};
}
if (notificationSound.SoundLocation != Config.NotificationSoundPath){
notificationSound.SoundLocation = Config.NotificationSoundPath;
ignoreNotificationSoundError = false;
}
notificationSound.Play();
try{
notificationSound.Play();
}catch(FileNotFoundException e){
OnNotificationSoundError("File not found: "+e.FileName);
}catch(InvalidOperationException){
OnNotificationSoundError("File is not a valid sound file.");
}catch(TimeoutException){
OnNotificationSoundError("File took too long to load.");
}
}
private void OnNotificationSoundError(string message){
if (!ignoreNotificationSoundError){
ignoreNotificationSoundError = true;
using(FormMessage form = new FormMessage("Notification Sound Error", "Could not play custom notification sound."+Environment.NewLine+message, MessageBoxIcon.Error)){
form.AddButton("Ignore");
Button btnOpenSettings = form.AddButton("Open Settings");
btnOpenSettings.Width += 16;
btnOpenSettings.Location = new Point(btnOpenSettings.Location.X-16, btnOpenSettings.Location.Y);
if (form.ShowDialog() == DialogResult.OK && form.ClickedButton == btnOpenSettings){
OpenSettings();
currentFormSettings.SelectTab(FormSettings.TabIndexNotification);
}
}
}
}
public void OnTweetScreenshotReady(string html, int width, int height){

View File

@@ -133,7 +133,7 @@ namespace TweetDck.Core{
if (!flags.HasFlag(NotificationFlags.DisableScripts)){
notificationJS = ScriptLoader.LoadResource(NotificationScriptFile);
browser.RegisterJsObject("$TD", new TweetDeckBridge(owner, this));
browser.RegisterAsyncJsObject("$TD", new TweetDeckBridge(owner, this));
if (plugins != null){
pluginJS = ScriptLoader.LoadResource(PluginManager.PluginNotificationScriptFile);
@@ -238,6 +238,7 @@ namespace TweetDck.Core{
private void Browser_FrameLoadEnd(object sender, FrameLoadEndEventArgs e){
if (e.Frame.IsMain && notificationJS != null && browser.Address != "about:blank" && !flags.HasFlag(NotificationFlags.DisableScripts)){
e.Frame.ExecuteJavaScriptAsync(PropertyBridge.GenerateScript(PropertyBridge.Properties.ExpandLinksOnHover));
ScriptLoader.ExecuteScript(e.Frame, notificationJS, NotificationScriptIdentifier);
if (plugins != null && plugins.HasAnyPlugin(PluginEnvironment.Notification)){
@@ -435,7 +436,7 @@ namespace TweetDck.Core{
else{
Point position = PointToClient(Cursor.Position);
position.Offset(20, 5);
toolTip.Show(text, this, position);
toolTip.Show(text, this, position); // TODO figure out flickering when moving the mouse
}
}
}

View File

@@ -33,6 +33,10 @@ namespace TweetDck.Core.Handling{
model.Remove(CefMenuCommand.ViewSource);
RemoveSeparatorIfLast(model);
if (parameters.TypeFlags.HasFlag(ContextMenuType.Selection)){
model.AddSeparator();
}
base.OnBeforeContextMenu(browserControl, browser, frame, parameters, model);
lastHighlightedTweet = TweetDeckBridge.LastHighlightedTweet;
@@ -76,6 +80,8 @@ namespace TweetDck.Core.Handling{
AddDebugMenuItems(globalMenu);
#endif
}
RemoveSeparatorIfLast(model);
}
public override bool OnContextMenuCommand(IWebBrowser browserControl, IBrowser browser, IFrame frame, IContextMenuParams parameters, CefMenuCommand commandId, CefEventFlags eventFlags){

View File

@@ -1,6 +1,5 @@
using CefSharp;
using TweetDck.Core.Controls;
using TweetDck.Core.Utils;
namespace TweetDck.Core.Handling{
class ContextMenuNotification : ContextMenuBase{
@@ -19,6 +18,12 @@ namespace TweetDck.Core.Handling{
public override void OnBeforeContextMenu(IWebBrowser browserControl, IBrowser browser, IFrame frame, IContextMenuParams parameters, IMenuModel model){
model.Clear();
if (parameters.TypeFlags.HasFlag(ContextMenuType.Selection)){
model.AddItem(CefMenuCommand.Copy, "Copy");
model.AddSeparator();
}
base.OnBeforeContextMenu(browserControl, browser, frame, parameters, model);
if (enableCustomMenu){

View File

@@ -12,7 +12,7 @@ namespace TweetDck.Core.Notification.Screenshot{
browser.FrameLoadEnd += (sender, args) => {
if (args.Frame.IsMain && browser.Address != "about:blank"){
ScriptLoader.ExecuteScript(args.Frame, "window.setTimeout(() => $TD_NotificationScreenshot.trigger(), 25)", "gen:screenshot");
ScriptLoader.ExecuteScript(args.Frame, "window.setTimeout($TD_NotificationScreenshot.trigger, 25)", "gen:screenshot");
}
};

View File

@@ -9,9 +9,13 @@ using TweetDck.Updates;
namespace TweetDck.Core.Other{
sealed partial class FormSettings : Form{
public const int TabIndexNotification = 1;
private readonly FormBrowser browser;
private readonly Dictionary<Type, BaseTabSettings> tabs = new Dictionary<Type, BaseTabSettings>(4);
private bool wasTabSelectedAutomatically;
public FormSettings(FormBrowser browser, PluginManager plugins, UpdateHandler updates){
InitializeComponent();
@@ -22,12 +26,18 @@ namespace TweetDck.Core.Other{
this.tabPanel.SetupTabPanel(100);
this.tabPanel.AddButton("General", SelectTab<TabSettingsGeneral>);
this.tabPanel.AddButton("Notifications", () => SelectTab(() => new TabSettingsNotifications(browser.CreateNotificationForm(NotificationFlags.DisableContextMenu))));
this.tabPanel.AddButton("Notifications", () => SelectTab(() => new TabSettingsNotifications(browser.CreateNotificationForm(NotificationFlags.DisableContextMenu), wasTabSelectedAutomatically)));
this.tabPanel.AddButton("Updates", () => SelectTab(() => new TabSettingsUpdates(updates)));
this.tabPanel.AddButton("Advanced", () => SelectTab(() => new TabSettingsAdvanced(browser.ReloadBrowser, plugins)));
this.tabPanel.AddButton("Advanced", () => SelectTab(() => new TabSettingsAdvanced(browser.ReinjectCustomCSS, plugins)));
this.tabPanel.SelectTab(tabPanel.Buttons.First());
}
public void SelectTab(int index){
wasTabSelectedAutomatically = true;
this.tabPanel.SelectTab(tabPanel.Buttons.ElementAt(index));
wasTabSelectedAutomatically = false;
}
private void SelectTab<T>() where T : BaseTabSettings, new(){
SelectTab(() => new T());
}

View File

@@ -23,6 +23,7 @@
/// the contents of this method with the code editor.
/// </summary>
private void InitializeComponent() {
this.components = new System.ComponentModel.Container();
this.textBoxBrowserCSS = new System.Windows.Forms.TextBox();
this.btnCancel = new System.Windows.Forms.Button();
this.btnApply = new System.Windows.Forms.Button();
@@ -32,6 +33,7 @@
this.textBoxNotificationCSS = new System.Windows.Forms.TextBox();
this.labelWarning = new System.Windows.Forms.Label();
this.btnOpenWiki = new System.Windows.Forms.Button();
this.timerTestBrowser = new System.Windows.Forms.Timer(this.components);
((System.ComponentModel.ISupportInitialize)(this.splitContainer)).BeginInit();
this.splitContainer.Panel1.SuspendLayout();
this.splitContainer.Panel2.SuspendLayout();
@@ -52,6 +54,7 @@
this.textBoxBrowserCSS.Size = new System.Drawing.Size(373, 253);
this.textBoxBrowserCSS.TabIndex = 0;
this.textBoxBrowserCSS.WordWrap = false;
this.textBoxBrowserCSS.KeyUp += new System.Windows.Forms.KeyEventHandler(this.textBoxBrowserCSS_KeyUp);
//
// btnCancel
//
@@ -132,7 +135,7 @@
this.textBoxNotificationCSS.Multiline = true;
this.textBoxNotificationCSS.Name = "textBoxNotificationCSS";
this.textBoxNotificationCSS.ScrollBars = System.Windows.Forms.ScrollBars.Both;
this.textBoxNotificationCSS.Size = new System.Drawing.Size(376, 253);
this.textBoxNotificationCSS.Size = new System.Drawing.Size(373, 253);
this.textBoxNotificationCSS.TabIndex = 1;
this.textBoxNotificationCSS.WordWrap = false;
//
@@ -159,6 +162,11 @@
this.btnOpenWiki.UseVisualStyleBackColor = true;
this.btnOpenWiki.Click += new System.EventHandler(this.btnOpenWiki_Click);
//
// timerTestBrowser
//
this.timerTestBrowser.Interval = 500;
this.timerTestBrowser.Tick += new System.EventHandler(this.timerTestBrowser_Tick);
//
// DialogSettingsCSS
//
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
@@ -195,5 +203,6 @@
private System.Windows.Forms.Label labelNotification;
private System.Windows.Forms.Label labelWarning;
private System.Windows.Forms.Button btnOpenWiki;
private System.Windows.Forms.Timer timerTestBrowser;
}
}

View File

@@ -17,10 +17,14 @@ namespace TweetDck.Core.Other.Settings.Dialogs{
}
}
public DialogSettingsCSS(){
private readonly Action<string> reinjectBrowserCSS;
public DialogSettingsCSS(Action<string> reinjectBrowserCSS){
InitializeComponent();
Text = Program.BrandName+" Settings - CSS";
this.reinjectBrowserCSS = reinjectBrowserCSS;
textBoxBrowserCSS.EnableMultilineShortcuts();
textBoxBrowserCSS.Text = Program.UserConfig.CustomBrowserCSS ?? "";
@@ -29,6 +33,16 @@ namespace TweetDck.Core.Other.Settings.Dialogs{
textBoxNotificationCSS.Text = Program.UserConfig.CustomNotificationCSS ?? "";
}
private void textBoxBrowserCSS_KeyUp(object sender, KeyEventArgs e){
timerTestBrowser.Stop();
timerTestBrowser.Start();
}
private void timerTestBrowser_Tick(object sender, EventArgs e){
reinjectBrowserCSS(textBoxBrowserCSS.Text);
timerTestBrowser.Stop();
}
private void btnOpenWiki_Click(object sender, EventArgs e){
BrowserUtils.OpenExternalBrowser("https://github.com/chylex/TweetDuck/wiki");
}

View File

@@ -9,13 +9,13 @@ using TweetDck.Plugins;
namespace TweetDck.Core.Other.Settings{
partial class TabSettingsAdvanced : BaseTabSettings{
private readonly Action browserReloadAction;
private readonly Action<string> reinjectBrowserCSS;
private readonly PluginManager plugins;
public TabSettingsAdvanced(Action browserReloadAction, PluginManager plugins){
public TabSettingsAdvanced(Action<string> reinjectBrowserCSS, PluginManager plugins){
InitializeComponent();
this.browserReloadAction = browserReloadAction;
this.reinjectBrowserCSS = reinjectBrowserCSS;
this.plugins = plugins;
checkHardwareAcceleration.Checked = HardwareAcceleration.IsEnabled;
@@ -80,17 +80,13 @@ namespace TweetDck.Core.Other.Settings{
}
private void btnEditCSS_Click(object sender, EventArgs e){
using(DialogSettingsCSS form = new DialogSettingsCSS()){
using(DialogSettingsCSS form = new DialogSettingsCSS(reinjectBrowserCSS)){
if (form.ShowDialog(ParentForm) == DialogResult.OK){
bool hasChangedBrowser = form.BrowserCSS != Config.CustomBrowserCSS;
Config.CustomBrowserCSS = form.BrowserCSS;
Config.CustomNotificationCSS = form.NotificationCSS;
if (hasChangedBrowser && MessageBox.Show("The browser CSS has changed, do you want to reload it?", "Browser CSS Changed", MessageBoxButtons.YesNo, MessageBoxIcon.Question, MessageBoxDefaultButton.Button2) == DialogResult.Yes){
browserReloadAction();
}
}
reinjectBrowserCSS(Config.CustomBrowserCSS); // reinject on cancel too, because the CSS is updated while typing
}
}

View File

@@ -381,6 +381,7 @@
this.tbCustomSound.Name = "tbCustomSound";
this.tbCustomSound.Size = new System.Drawing.Size(170, 20);
this.tbCustomSound.TabIndex = 0;
this.tbCustomSound.TextChanged += new System.EventHandler(this.tbCustomSound_TextChanged);
//
// TabSettingsNotifications
//

View File

@@ -1,6 +1,7 @@
using System;
using System.Drawing;
using System.Globalization;
using System.IO;
using System.Windows.Forms;
using TweetDck.Core.Controls;
using TweetDck.Core.Notification;
@@ -11,7 +12,7 @@ namespace TweetDck.Core.Other.Settings{
private readonly FormNotification notification;
private readonly Point initCursorPosition;
public TabSettingsNotifications(FormNotification notification){
public TabSettingsNotifications(FormNotification notification, bool ignoreAutoClick){
InitializeComponent();
this.notification = notification;
@@ -30,7 +31,7 @@ namespace TweetDck.Core.Other.Settings{
this.notification.Activated += notification_Activated;
this.notification.Show(this);
initCursorPosition = Cursor.Position;
initCursorPosition = ignoreAutoClick ? ControlExtensions.InvisibleLocation : Cursor.Position;
switch(Config.NotificationPosition){
case TweetNotification.Position.TopLeft: radioLocTL.Checked = true; break;
@@ -58,7 +59,7 @@ namespace TweetDck.Core.Other.Settings{
trackBarEdgeDistance.SetValueSafe(Config.NotificationEdgeDistance);
labelEdgeDistanceValue.Text = trackBarEdgeDistance.Value.ToString(CultureInfo.InvariantCulture)+" px";
tbCustomSound.Text = Config.NotificationSoundPath ?? string.Empty;
tbCustomSound.Text = Config.NotificationSoundPath;
Disposed += (sender, args) => this.notification.Dispose();
}
@@ -77,7 +78,7 @@ namespace TweetDck.Core.Other.Settings{
}
private void notification_Activated(object sender, EventArgs e){
if (Cursor.Position == initCursorPosition){
if (Cursor.Position == initCursorPosition && initCursorPosition != ControlExtensions.InvisibleLocation){
Timer delay = WindowsUtils.CreateSingleTickTimer(1);
delay.Tick += (sender2, args2) => { // here you can see a disgusting hack to force the freshly opened notification window out of focus
@@ -167,6 +168,13 @@ namespace TweetDck.Core.Other.Settings{
notification.ShowNotificationForSettings(false);
}
private void tbCustomSound_TextChanged(object sender, EventArgs e){
// also runs when the control is created, i.e. when Ready is false
bool fileExists = string.IsNullOrEmpty(tbCustomSound.Text) || File.Exists(tbCustomSound.Text);
tbCustomSound.ForeColor = fileExists ? SystemColors.WindowText : Color.Maroon;
}
private void btnBrowseSound_Click(object sender, EventArgs e){
using(OpenFileDialog dialog = new OpenFileDialog{
AutoUpgradeEnabled = true,

View File

@@ -1,6 +1,7 @@
using System;
using System.Windows.Forms;
using TweetDck.Updates;
using TweetDck.Updates.Events;
namespace TweetDck.Core.Other.Settings{
partial class TabSettingsUpdates : BaseTabSettings{
@@ -27,12 +28,18 @@ namespace TweetDck.Core.Other.Settings{
private void btnCheckUpdates_Click(object sender, EventArgs e){
if (!Ready)return;
Config.DismissedUpdate = string.Empty;
Config.Save();
updateCheckEventId = updates.Check(true);
btnCheckUpdates.Enabled = false;
if (updateCheckEventId == -1){
MessageBox.Show("Sorry, your system is no longer supported.", "Unsupported System", MessageBoxButtons.OK, MessageBoxIcon.Warning);
}
else{
btnCheckUpdates.Enabled = false;
updates.Settings.DismissedUpdate = string.Empty;
Config.DismissedUpdate = string.Empty;
Config.Save();
}
}
private void updates_CheckFinished(object sender, UpdateCheckEventArgs e){

View File

@@ -21,8 +21,8 @@ namespace TweetDck{
public const string BrandName = "TweetDuck";
public const string Website = "https://tweetduck.chylex.com";
public const string VersionTag = "1.6.2";
public const string VersionFull = "1.6.2.0";
public const string VersionTag = "1.6.3";
public const string VersionFull = "1.6.3.0";
public static readonly Version Version = new Version(VersionTag);
@@ -125,6 +125,8 @@ namespace TweetDck{
}
BrowserCache.ClearOldCacheFiles();
CefSharpSettings.WcfEnabled = false;
CefSettings settings = new CefSettings{
AcceptLanguageList = BrowserUtils.HeaderAcceptLanguage,
@@ -155,7 +157,8 @@ namespace TweetDck{
plugins.Reload();
FormBrowser mainForm = new FormBrowser(plugins, new UpdaterSettings{
AllowPreReleases = Args.HasFlag("-debugupdates")
AllowPreReleases = Args.HasFlag("-debugupdates"),
DismissedUpdate = UserConfig.DismissedUpdate
});
Application.Run(mainForm);

View File

@@ -1,4 +1,4 @@
(function($, $TD, TD){
(function($, $TD, $TDX, TD){
//
// Variable: Current highlighted column jQuery object.
//
@@ -20,8 +20,8 @@
if (menu.length === 0)return;
menu.children(".drp-h-divider").last().after([
'<li class="is-selectable" data-std><a href="#" data-action="td-settings">'+$TD.brandName+' settings</a></li>',
'<li class="is-selectable" data-std><a href="#" data-action="td-plugins">'+$TD.brandName+' plugins</a></li>',
'<li class="is-selectable" data-std><a href="#" data-action="td-settings">TweetDuck settings</a></li>',
'<li class="is-selectable" data-std><a href="#" data-action="td-plugins">TweetDuck plugins</a></li>',
'<li class="drp-h-divider"></li>'
].join(""));
@@ -112,6 +112,7 @@
html.css("border", "0");
html.find("footer").last().remove(); // apparently withTweetActions breaks for certain tweets, nice
html.find(".js-quote-detail").removeClass("is-actionable");
var url = html.find("time").first().children("a").first().attr("href") || "";
@@ -198,7 +199,7 @@
return;
}
if ($TD.expandLinksOnHover){
if ($TDX.expandLinksOnHover){
tooltipTimer = window.setTimeout(function(){
var expanded = me.attr("data-full-url");
expanded = cutStart(expanded, "https://");
@@ -217,7 +218,7 @@
}
}
else if (e.type === "mouseleave"){
if ($TD.expandLinksOnHover){
if ($TDX.expandLinksOnHover){
var prevText = me.attr("td-prev-text");
if (prevText){
@@ -256,7 +257,7 @@
var soundEle = document.getElementById("update-sound");
soundEle.play = prependToFunction(soundEle.play, function(){
return $TD.muteNotifications || $TD.hasCustomNotificationSound;
return $TDX.muteNotifications || $TDX.hasCustomNotificationSound;
});
})();
@@ -543,12 +544,14 @@
styleOfficial.sheet.insertRule(".txt-base-smallest .badge-verified:before { height: 13px !important; }", 0); // fix cut off badge icon
styleOfficial.sheet.insertRule(".keyboard-shortcut-list { vertical-align: top; }", 0); // fix keyboard navigation alignment
if ($TD.hasCustomBrowserCSS){
var styleCustom = document.createElement("style");
styleCustom.innerHTML = $TD.customBrowserCSS;
document.head.appendChild(styleCustom);
}
TD.services.TwitterActionRetweetedRetweet.prototype.iconClass = "icon-retweet icon-retweet-color txt-base-medium"; // fix retweet icon mismatch
window.TDGF_reinjectCustomCSS = function(styles){
$("#tweetduck-custom-css").remove();
if (styles && styles.length){
$(document.head).append("<style type='text/css' id='tweetduck-custom-css'>"+styles+"</style>");
}
};
})();
})($, $TD, TD);
})($, $TD, $TDX, TD);

View File

@@ -1,19 +1,49 @@
(function($, $TD, TD){
(function($, $TD, $TDX, TD){
var isDebugging = false;
$(document).keydown(function(e){
// ==============================
// F4 key - simulate notification
// ==============================
// ==========================
// F4 key - toggle debug mode
// ==========================
if (e.keyCode === 115){
var col = TD.controller.columnManager.getAllOrdered()[0];
isDebugging = !isDebugging;
$(".app-title").first().css("background-color", isDebugging ? "#5A6B75" : "#292F33");
}
// Debug mode handling
else if (isDebugging){
e.preventDefault();
$.publish("/notifications/new",[{
column: col,
items: [
col.updateArray[Math.floor(Math.random()*col.updateArray.length)]
]
}]);
// ===================================
// N key - simulate popup notification
// ===================================
if (e.keyCode === 78){
var col = TD.controller.columnManager.getAllOrdered()[0];
$.publish("/notifications/new",[{
column: col,
items: [
col.updateArray[Math.floor(Math.random()*col.updateArray.length)]
]
}]);
}
// ===================================
// S key - simulate sound notification
// ===================================
else if (e.keyCode === 83){
if ($TDX.hasCustomNotificationSound){
$TD.onTweetSound();
}
else{
document.getElementById("update-sound").play();
}
}
}
});
})($, $TD, TD);
})($, $TD, $TDX, TD);

View File

@@ -1,4 +1,4 @@
(function($TD){
(function($TD, $TDX){
//
// Variable: Collection of all <a> tags.
//
@@ -51,7 +51,7 @@
return;
}
if ($TD.expandLinksOnHover){
if ($TDX.expandLinksOnHover){
tooltipTimer = window.setTimeout(function(){
var expanded = url;
expanded = cutStart(expanded, "https://");
@@ -73,7 +73,7 @@
addEventListener(links, "mouseleave", function(e){
if (!e.currentTarget.hasAttribute("data-full-url"))return;
if ($TD.expandLinksOnHover){
if ($TDX.expandLinksOnHover){
var prevText = e.currentTarget.getAttribute("td-prev-text");
if (prevText){
@@ -146,4 +146,4 @@
document.body.addEventListener("mouseleave", function(){
document.body.classList.remove("td-hover");
});
})($TD);
})($TD, $TDX);

View File

@@ -7,25 +7,25 @@
//
// Constant: Update exe file name.
//
const updateFileName = $TDU.brandName+".Update.exe";
const updateFileName = "TweetDuck.Update.exe";
//
// Constant: Url that returns JSON data about latest version.
//
const updateCheckUrlLatest = "https://api.github.com/repos/chylex/"+$TDU.brandName+"/releases/latest";
const updateCheckUrlLatest = "https://api.github.com/repos/chylex/TweetDuck/releases/latest";
//
// Constant: Url that returns JSON data about all versions, including prereleases.
//
const updateCheckUrlAll = "https://api.github.com/repos/chylex/"+$TDU.brandName+"/releases";
const updateCheckUrlAll = "https://api.github.com/repos/chylex/TweetDuck/releases";
//
// Function: Creates the update notification element. Removes the old one if already exists.
//
var createUpdateNotificationElement = function(version, download){
var displayNotification = function(version, download){
var outdated = version === "unsupported";
var ele = $("#tweetdck-update");
var ele = $("#tweetduck-update");
var existed = ele.length > 0;
if (existed > 0){
@@ -33,7 +33,7 @@
}
var html = outdated ? [
"<div id='tweetdck-update'>",
"<div id='tweetduck-update'>",
"<p class='tdu-title'>Unsupported System</p>",
"<p class='tdu-info'>You will not receive updates.</p>",
"<div class='tdu-buttons'>",
@@ -42,8 +42,8 @@
"</div>",
"</div>"
] : [
"<div id='tweetdck-update'>",
"<p class='tdu-title'>"+$TDU.brandName+" Update</p>",
"<div id='tweetduck-update'>",
"<p class='tdu-title'>TweetDuck Update</p>",
"<p class='tdu-info'>Version "+version+" is now available.</p>",
"<div class='tdu-buttons'>",
"<button class='btn btn-positive tdu-btn-download'><span class='label'>Download</span></button>",
@@ -54,7 +54,7 @@
$(document.body).append(html.join(""));
ele = $("#tweetdck-update");
ele = $("#tweetduck-update");
var buttonDiv = ele.children("div.tdu-buttons").first();
@@ -128,33 +128,19 @@
//
// Function: Runs an update check and updates all DOM elements appropriately.
//
var runUpdateCheck = function(force, eventID){
if (!$TDU.isSystemSupported){
if ($TDU.dismissedVersionTag !== "unsupported"){
createUpdateNotificationElement("unsupported");
}
return;
}
var runUpdateCheck = function(eventID, versionTag, dismissedVersionTag, allowPre){
clearTimeout(updateCheckTimeoutID);
updateCheckTimeoutID = setTimeout(runUpdateCheck, 1000*60*60); // 1 hour
if (!$TDU.updateCheckEnabled && !force){
return;
}
var allowPre = $TDU.allowPreReleases;
updateCheckTimeoutID = setTimeout($TDU.triggerUpdateCheck, 1000*60*60); // 1 hour
$.getJSON(allowPre ? updateCheckUrlAll : updateCheckUrlLatest, function(response){
var release = allowPre ? response[0] : response;
var tagName = release.tag_name;
var hasUpdate = tagName !== $TDU.versionTag && tagName !== $TDU.dismissedVersionTag && release.assets.length > 0;
var hasUpdate = tagName !== versionTag && tagName !== dismissedVersionTag && release.assets.length > 0;
if (hasUpdate){
var obj = release.assets.find(asset => asset.name === updateFileName) || release.assets[0];
createUpdateNotificationElement(tagName, obj.browser_download_url);
displayNotification(tagName, obj.browser_download_url);
}
if (eventID){ // ignore undefined and 0
@@ -166,6 +152,6 @@
//
// Block: Setup global functions.
//
window.TDUF_displayNotification = displayNotification;
window.TDUF_runUpdateCheck = runUpdateCheck;
runUpdateCheck();
})($, $TDU);

View File

@@ -71,6 +71,7 @@
<ItemGroup>
<Compile Include="Configuration\LockManager.cs" />
<Compile Include="Configuration\UserConfig.cs" />
<Compile Include="Core\Bridge\PropertyBridge.cs" />
<Compile Include="Core\Controls\ControlExtensions.cs" />
<Compile Include="Core\Controls\FlatButton.cs">
<SubType>Component</SubType>
@@ -222,6 +223,7 @@
<Compile Include="Plugins\PluginManager.cs" />
<Compile Include="Plugins\PluginScriptGenerator.cs" />
<Compile Include="Reporter.cs" />
<Compile Include="Updates\Events\UpdateDismissedEventArgs.cs" />
<Compile Include="Updates\FormUpdateDownload.cs">
<SubType>Form</SubType>
</Compile>
@@ -238,8 +240,8 @@
<Compile Include="Core\Utils\BrowserUtils.cs" />
<Compile Include="Core\Utils\HardwareAcceleration.cs" />
<Compile Include="Core\Utils\NativeMethods.cs" />
<Compile Include="Updates\UpdateAcceptedEventArgs.cs" />
<Compile Include="Updates\UpdateCheckEventArgs.cs" />
<Compile Include="Updates\Events\UpdateAcceptedEventArgs.cs" />
<Compile Include="Updates\Events\UpdateCheckEventArgs.cs" />
<Compile Include="Updates\UpdateHandler.cs" />
<Compile Include="Updates\UpdateInfo.cs" />
<Compile Include="Program.cs" />

View File

@@ -1,6 +1,6 @@
using System;
namespace TweetDck.Updates{
namespace TweetDck.Updates.Events{
class UpdateAcceptedEventArgs : EventArgs{
public readonly UpdateInfo UpdateInfo;

View File

@@ -1,6 +1,6 @@
using System;
namespace TweetDck.Updates{
namespace TweetDck.Updates.Events{
class UpdateCheckEventArgs : EventArgs{
public int EventId { get; private set; }
public bool UpdateAvailable { get; private set; }
@@ -12,4 +12,4 @@ namespace TweetDck.Updates{
LatestVersion = latestVersion;
}
}
}
}

View File

@@ -0,0 +1,11 @@
using System;
namespace TweetDck.Updates.Events{
class UpdateDismissedEventArgs : EventArgs{
public readonly string VersionTag;
public UpdateDismissedEventArgs(string versionTag){
this.VersionTag = versionTag;
}
}
}

View File

@@ -9,7 +9,7 @@ using TweetDck.Core.Utils;
namespace TweetDck.Updates{
sealed partial class FormUpdateDownload : Form{
private const double BytesToMB = 1024.0*1024.0;
private const double BytesToKB = 1024.0;
public string InstallerPath{
get{
@@ -69,7 +69,7 @@ namespace TweetDck.Updates{
progressDownload.SetValueInstant(1000);
}
labelStatus.Text = (e.BytesReceived/BytesToMB).ToString("0.0", CultureInfo.CurrentCulture)+" MB";
labelStatus.Text = (e.BytesReceived/BytesToKB).ToString("0.0", CultureInfo.CurrentCulture)+" kB";
}
else{
if (progressDownload.Style != ProgressBarStyle.Continuous){
@@ -77,7 +77,7 @@ namespace TweetDck.Updates{
}
progressDownload.SetValueInstant(e.ProgressPercentage*10);
labelStatus.Text = (e.BytesReceived/BytesToMB).ToString("0.0", CultureInfo.CurrentCulture)+" / "+(e.TotalBytesToReceive/BytesToMB).ToString("0.0", CultureInfo.CurrentCulture)+" MB";
labelStatus.Text = (e.BytesReceived/BytesToKB).ToString("0.0", CultureInfo.CurrentCulture)+" / "+(e.TotalBytesToReceive/BytesToKB).ToString("0.0", CultureInfo.CurrentCulture)+" kB";
}
});
}

View File

@@ -5,14 +5,28 @@ using TweetDck.Core;
using TweetDck.Core.Controls;
using TweetDck.Core.Utils;
using TweetDck.Resources;
using TweetDck.Updates.Events;
namespace TweetDck.Updates{
class UpdateHandler{
private static bool IsSystemSupported{
get{
return true; // Environment.OSVersion.Version >= new Version("6.1"); // 6.1 NT version = Windows 7
}
}
public UpdaterSettings Settings{
get{
return settings;
}
}
private readonly ChromiumWebBrowser browser;
private readonly FormBrowser form;
private readonly UpdaterSettings settings;
public event EventHandler<UpdateAcceptedEventArgs> UpdateAccepted;
public event EventHandler<UpdateDismissedEventArgs> UpdateDismissed;
public event EventHandler<UpdateCheckEventArgs> CheckFinished;
private int lastEventId;
@@ -23,18 +37,32 @@ namespace TweetDck.Updates{
this.settings = settings;
browser.FrameLoadEnd += browser_FrameLoadEnd;
browser.RegisterJsObject("$TDU", new Bridge(this));
browser.RegisterAsyncJsObject("$TDU", new Bridge(this));
}
private void browser_FrameLoadEnd(object sender, FrameLoadEndEventArgs e){
if (e.Frame.IsMain && BrowserUtils.IsTweetDeckWebsite(e.Frame)){
ScriptLoader.ExecuteFile(e.Frame, "update.js");
Check(false);
}
}
public int Check(bool force){
browser.ExecuteScriptAsync("TDUF_runUpdateCheck", force, ++lastEventId);
return lastEventId;
if (IsSystemSupported){
if (Program.UserConfig.EnableUpdateCheck || force){
string dismissedUpdate = force || settings.DismissedUpdate == null ? string.Empty : settings.DismissedUpdate;
browser.ExecuteScriptAsync("TDUF_runUpdateCheck", ++lastEventId, Program.VersionTag, dismissedUpdate, settings.AllowPreReleases);
return lastEventId;
}
return 0;
}
else if (settings.DismissedUpdate != "unsupported"){
browser.ExecuteScriptAsync("TDUF_displayNotification", "unsupported");
}
return -1;
}
private void TriggerUpdateAcceptedEvent(UpdateAcceptedEventArgs args){
@@ -43,6 +71,16 @@ namespace TweetDck.Updates{
}
}
private void TriggerUpdateDismissedEvent(UpdateDismissedEventArgs args){
form.InvokeSafe(() => {
settings.DismissedUpdate = args.VersionTag;
if (UpdateDismissed != null){
UpdateDismissed(this, args);
}
});
}
private void TriggerCheckFinishedEvent(UpdateCheckEventArgs args){
if (CheckFinished != null){
form.InvokeSafe(() => CheckFinished(this, args));
@@ -50,48 +88,16 @@ namespace TweetDck.Updates{
}
public class Bridge{
public string BrandName{
get{
return Program.BrandName;
}
}
public string VersionTag{
get{
return Program.VersionTag;
}
}
public bool UpdateCheckEnabled{
get{
return Program.UserConfig.EnableUpdateCheck;
}
}
public string DismissedVersionTag{
get{
return Program.UserConfig.DismissedUpdate ?? string.Empty;
}
}
public bool AllowPreReleases{
get{
return owner.settings.AllowPreReleases;
}
}
public bool IsSystemSupported{
get{
return true; // Environment.OSVersion.Version >= new Version("6.1"); // 6.1 NT version = Windows 7
}
}
private readonly UpdateHandler owner;
public Bridge(UpdateHandler owner){
this.owner = owner;
}
public void TriggerUpdateCheck(){
owner.Check(false);
}
public void OnUpdateCheckFinished(int eventId, bool isUpdateAvailable, string latestVersion){
owner.TriggerCheckFinishedEvent(new UpdateCheckEventArgs(eventId, isUpdateAvailable, latestVersion));
}
@@ -101,10 +107,7 @@ namespace TweetDck.Updates{
}
public void OnUpdateDismissed(string versionTag){
owner.form.InvokeSafe(() => {
Program.UserConfig.DismissedUpdate = versionTag;
Program.UserConfig.Save();
});
owner.TriggerUpdateDismissedEvent(new UpdateDismissedEventArgs(versionTag));
}
public void OpenBrowser(string url){

View File

@@ -1,5 +1,6 @@
namespace TweetDck.Updates{
class UpdaterSettings{
public bool AllowPreReleases { get; set; }
public string DismissedUpdate { get; set; }
}
}

View File

@@ -10,7 +10,7 @@
[Setup]
AppId={{8C25A716-7E11-4AAD-9992-8B5D0C78AE06}
AppName={#MyAppName}
AppName={#MyAppName} Portable
AppVersion={#MyAppVersion}
AppVerName={#MyAppName} {#MyAppVersion}
AppPublisher={#MyAppPublisher}

View File

@@ -12,7 +12,7 @@
[Setup]
AppId={{{#MyAppID}}
AppName={#MyAppName}
AppName={#MyAppName} Update
AppVersion={#MyAppVersion}
AppVerName={#MyAppName} {#MyAppVersion}
AppPublisher={#MyAppPublisher}