mirror of
https://github.com/chylex/TweetDuck.git
synced 2025-09-14 19:32:10 +02:00
Compare commits
39 Commits
Author | SHA1 | Date | |
---|---|---|---|
92af85d3bb | |||
7635af5730 | |||
a838e89695 | |||
b22289a8b9 | |||
45b3ff52c6 | |||
4464991f4c | |||
b0d2f77583 | |||
b211a4405d | |||
8823016d2c | |||
859fdc7ec1 | |||
028d5ed01f | |||
5fd5a2a436 | |||
79a7e7470c | |||
9ecef78aed | |||
65a837a6e1 | |||
6e4db4acea | |||
26fb977d05 | |||
b42cd1c048 | |||
467f7cd12f | |||
66699ce9df | |||
cf7d903932 | |||
a7ab67925c | |||
a474ba4260 | |||
09e5636e86 | |||
2295a875be | |||
82a2455afc | |||
268de676ee | |||
8fe26c07f1 | |||
da3921b1ca | |||
4dd2e787d1 | |||
ce005ae6c2 | |||
1513f46a11 | |||
7543eeb0f4 | |||
873242120c | |||
98f8095a65 | |||
785571a550 | |||
0c4bd4044e | |||
0319543dce | |||
82d70b2d7f |
@@ -67,7 +67,7 @@ namespace TweetDck.Configuration{
|
|||||||
|
|
||||||
public string NotificationSoundPath{
|
public string NotificationSoundPath{
|
||||||
get{
|
get{
|
||||||
return !string.IsNullOrEmpty(notificationSoundPath) && File.Exists(notificationSoundPath) ? notificationSoundPath : string.Empty;
|
return string.IsNullOrEmpty(notificationSoundPath) ? string.Empty : notificationSoundPath;
|
||||||
}
|
}
|
||||||
|
|
||||||
set{
|
set{
|
||||||
|
34
Core/Bridge/PropertyBridge.cs
Normal file
34
Core/Bridge/PropertyBridge.cs
Normal 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();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@@ -21,48 +21,6 @@ namespace TweetDck.Core.Bridge{
|
|||||||
private readonly FormBrowser form;
|
private readonly FormBrowser form;
|
||||||
private readonly FormNotification notification;
|
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){
|
public TweetDeckBridge(FormBrowser form, FormNotification notification){
|
||||||
this.form = form;
|
this.form = form;
|
||||||
this.notification = notification;
|
this.notification = notification;
|
||||||
|
@@ -17,6 +17,8 @@ using System.Media;
|
|||||||
using TweetDck.Core.Bridge;
|
using TweetDck.Core.Bridge;
|
||||||
using TweetDck.Core.Notification;
|
using TweetDck.Core.Notification;
|
||||||
using TweetDck.Core.Notification.Screenshot;
|
using TweetDck.Core.Notification.Screenshot;
|
||||||
|
using TweetDck.Updates.Events;
|
||||||
|
using System.IO;
|
||||||
|
|
||||||
namespace TweetDck.Core{
|
namespace TweetDck.Core{
|
||||||
sealed partial class FormBrowser : Form{
|
sealed partial class FormBrowser : Form{
|
||||||
@@ -42,6 +44,7 @@ namespace TweetDck.Core{
|
|||||||
|
|
||||||
private TweetScreenshotManager notificationScreenshotManager;
|
private TweetScreenshotManager notificationScreenshotManager;
|
||||||
private SoundPlayer notificationSound;
|
private SoundPlayer notificationSound;
|
||||||
|
private bool ignoreNotificationSoundError;
|
||||||
|
|
||||||
public FormBrowser(PluginManager pluginManager, UpdaterSettings updaterSettings){
|
public FormBrowser(PluginManager pluginManager, UpdaterSettings updaterSettings){
|
||||||
InitializeComponent();
|
InitializeComponent();
|
||||||
@@ -53,7 +56,11 @@ namespace TweetDck.Core{
|
|||||||
this.plugins.PluginChangedState += plugins_PluginChangedState;
|
this.plugins.PluginChangedState += plugins_PluginChangedState;
|
||||||
|
|
||||||
this.notification = CreateNotificationForm(NotificationFlags.AutoHide | NotificationFlags.TopMost);
|
this.notification = CreateNotificationForm(NotificationFlags.AutoHide | NotificationFlags.TopMost);
|
||||||
|
#if DEBUG
|
||||||
|
this.notification.CanMoveWindow = () => (ModifierKeys & Keys.Alt) == Keys.Alt;
|
||||||
|
#else
|
||||||
this.notification.CanMoveWindow = () => false;
|
this.notification.CanMoveWindow = () => false;
|
||||||
|
#endif
|
||||||
this.notification.Show();
|
this.notification.Show();
|
||||||
|
|
||||||
this.browser = new ChromiumWebBrowser("https://tweetdeck.twitter.com/"){
|
this.browser = new ChromiumWebBrowser("https://tweetdeck.twitter.com/"){
|
||||||
@@ -69,11 +76,13 @@ namespace TweetDck.Core{
|
|||||||
|
|
||||||
this.browser.LoadingStateChanged += Browser_LoadingStateChanged;
|
this.browser.LoadingStateChanged += Browser_LoadingStateChanged;
|
||||||
this.browser.FrameLoadEnd += Browser_FrameLoadEnd;
|
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);
|
this.browser.RegisterAsyncJsObject("$TDP", plugins.Bridge);
|
||||||
|
|
||||||
Controls.Add(browser);
|
Controls.Add(browser);
|
||||||
|
|
||||||
|
Controls.Add(new MenuStrip{ Visible = false }); // fixes Alt freezing the program in Win 10 Anniversary Update
|
||||||
|
|
||||||
Disposed += (sender, args) => {
|
Disposed += (sender, args) => {
|
||||||
browser.Dispose();
|
browser.Dispose();
|
||||||
|
|
||||||
@@ -92,13 +101,16 @@ namespace TweetDck.Core{
|
|||||||
|
|
||||||
UpdateTrayIcon();
|
UpdateTrayIcon();
|
||||||
|
|
||||||
|
Config.MuteToggled += Config_MuteToggled;
|
||||||
|
|
||||||
this.updates = new UpdateHandler(browser, this, updaterSettings);
|
this.updates = new UpdateHandler(browser, this, updaterSettings);
|
||||||
this.updates.UpdateAccepted += updates_UpdateAccepted;
|
this.updates.UpdateAccepted += updates_UpdateAccepted;
|
||||||
|
this.updates.UpdateDismissed += updates_UpdateDismissed;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void ShowChildForm(Form form){
|
private void ShowChildForm(Form form){
|
||||||
|
form.VisibleChanged += (sender, args) => form.MoveToCenter(this);
|
||||||
form.Show(this);
|
form.Show(this);
|
||||||
form.Shown += (sender, args) => form.MoveToCenter(this);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void ForceClose(){
|
public void ForceClose(){
|
||||||
@@ -135,7 +147,9 @@ namespace TweetDck.Core{
|
|||||||
|
|
||||||
private void Browser_FrameLoadEnd(object sender, FrameLoadEndEventArgs e){
|
private void Browser_FrameLoadEnd(object sender, FrameLoadEndEventArgs e){
|
||||||
if (e.Frame.IsMain && BrowserUtils.IsTweetDeckWebsite(e.Frame)){
|
if (e.Frame.IsMain && BrowserUtils.IsTweetDeckWebsite(e.Frame)){
|
||||||
|
UpdateProperties();
|
||||||
ScriptLoader.ExecuteFile(e.Frame, "code.js");
|
ScriptLoader.ExecuteFile(e.Frame, "code.js");
|
||||||
|
ReinjectCustomCSS(Config.CustomBrowserCSS);
|
||||||
|
|
||||||
#if DEBUG
|
#if DEBUG
|
||||||
ScriptLoader.ExecuteFile(e.Frame, "debug.js");
|
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){
|
private void Config_TrayBehaviorChanged(object sender, EventArgs e){
|
||||||
if (!isLoaded)return;
|
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){
|
protected override void WndProc(ref Message m){
|
||||||
if (isLoaded && m.Msg == Program.WindowRestoreMessage){
|
if (isLoaded && m.Msg == Program.WindowRestoreMessage){
|
||||||
trayIcon_ClickRestore(trayIcon, new EventArgs());
|
trayIcon_ClickRestore(trayIcon, new EventArgs());
|
||||||
@@ -269,6 +292,16 @@ namespace TweetDck.Core{
|
|||||||
notification.ResumeNotification();
|
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
|
// callback handlers
|
||||||
|
|
||||||
public void OpenSettings(){
|
public void OpenSettings(){
|
||||||
@@ -284,14 +317,18 @@ namespace TweetDck.Core{
|
|||||||
currentFormSettings = null;
|
currentFormSettings = null;
|
||||||
|
|
||||||
if (!prevEnableUpdateCheck && Config.EnableUpdateCheck){
|
if (!prevEnableUpdateCheck && Config.EnableUpdateCheck){
|
||||||
|
updates.Settings.DismissedUpdate = string.Empty;
|
||||||
Config.DismissedUpdate = string.Empty;
|
Config.DismissedUpdate = string.Empty;
|
||||||
Config.Save();
|
Config.Save();
|
||||||
|
|
||||||
updates.Check(false);
|
updates.Check(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!Config.EnableTrayHighlight){
|
if (!Config.EnableTrayHighlight){
|
||||||
trayIcon.HasNotifications = false;
|
trayIcon.HasNotifications = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
UpdateProperties(PropertyBridge.Properties.ExpandLinksOnHover | PropertyBridge.Properties.HasCustomNotificationSound);
|
||||||
};
|
};
|
||||||
|
|
||||||
ShowChildForm(currentFormSettings);
|
ShowChildForm(currentFormSettings);
|
||||||
@@ -327,19 +364,49 @@ namespace TweetDck.Core{
|
|||||||
}
|
}
|
||||||
|
|
||||||
public void PlayNotificationSound(){
|
public void PlayNotificationSound(){
|
||||||
if (string.IsNullOrEmpty(Config.NotificationSoundPath)){
|
if (Config.NotificationSoundPath.Length == 0){
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (notificationSound == null){
|
if (notificationSound == null){
|
||||||
notificationSound = new SoundPlayer();
|
notificationSound = new SoundPlayer{
|
||||||
|
LoadTimeout = 5000
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
if (notificationSound.SoundLocation != Config.NotificationSoundPath){
|
if (notificationSound.SoundLocation != Config.NotificationSoundPath){
|
||||||
notificationSound.SoundLocation = Config.NotificationSoundPath;
|
notificationSound.SoundLocation = Config.NotificationSoundPath;
|
||||||
|
ignoreNotificationSoundError = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
try{
|
||||||
notificationSound.Play();
|
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){
|
public void OnTweetScreenshotReady(string html, int width, int height){
|
||||||
|
@@ -133,7 +133,7 @@ namespace TweetDck.Core{
|
|||||||
|
|
||||||
if (!flags.HasFlag(NotificationFlags.DisableScripts)){
|
if (!flags.HasFlag(NotificationFlags.DisableScripts)){
|
||||||
notificationJS = ScriptLoader.LoadResource(NotificationScriptFile);
|
notificationJS = ScriptLoader.LoadResource(NotificationScriptFile);
|
||||||
browser.RegisterJsObject("$TD", new TweetDeckBridge(owner, this));
|
browser.RegisterAsyncJsObject("$TD", new TweetDeckBridge(owner, this));
|
||||||
|
|
||||||
if (plugins != null){
|
if (plugins != null){
|
||||||
pluginJS = ScriptLoader.LoadResource(PluginManager.PluginNotificationScriptFile);
|
pluginJS = ScriptLoader.LoadResource(PluginManager.PluginNotificationScriptFile);
|
||||||
@@ -238,6 +238,7 @@ namespace TweetDck.Core{
|
|||||||
|
|
||||||
private void Browser_FrameLoadEnd(object sender, FrameLoadEndEventArgs e){
|
private void Browser_FrameLoadEnd(object sender, FrameLoadEndEventArgs e){
|
||||||
if (e.Frame.IsMain && notificationJS != null && browser.Address != "about:blank" && !flags.HasFlag(NotificationFlags.DisableScripts)){
|
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);
|
ScriptLoader.ExecuteScript(e.Frame, notificationJS, NotificationScriptIdentifier);
|
||||||
|
|
||||||
if (plugins != null && plugins.HasAnyPlugin(PluginEnvironment.Notification)){
|
if (plugins != null && plugins.HasAnyPlugin(PluginEnvironment.Notification)){
|
||||||
@@ -435,7 +436,7 @@ namespace TweetDck.Core{
|
|||||||
else{
|
else{
|
||||||
Point position = PointToClient(Cursor.Position);
|
Point position = PointToClient(Cursor.Position);
|
||||||
position.Offset(20, 5);
|
position.Offset(20, 5);
|
||||||
toolTip.Show(text, this, position);
|
toolTip.Show(text, this, position); // TODO figure out flickering when moving the mouse
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -3,6 +3,7 @@ using System;
|
|||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Windows.Forms;
|
using System.Windows.Forms;
|
||||||
using TweetDck.Core.Bridge;
|
using TweetDck.Core.Bridge;
|
||||||
|
using TweetDck.Core.Controls;
|
||||||
using TweetDck.Core.Utils;
|
using TweetDck.Core.Utils;
|
||||||
|
|
||||||
namespace TweetDck.Core.Handling{
|
namespace TweetDck.Core.Handling{
|
||||||
@@ -21,6 +22,12 @@ namespace TweetDck.Core.Handling{
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
private readonly Form form;
|
||||||
|
|
||||||
|
protected ContextMenuBase(Form form){
|
||||||
|
this.form = form;
|
||||||
|
}
|
||||||
|
|
||||||
public virtual void OnBeforeContextMenu(IWebBrowser browserControl, IBrowser browser, IFrame frame, IContextMenuParams parameters, IMenuModel model){
|
public virtual void OnBeforeContextMenu(IWebBrowser browserControl, IBrowser browser, IFrame frame, IContextMenuParams parameters, IMenuModel model){
|
||||||
if (parameters.TypeFlags.HasFlag(ContextMenuType.Link) && !parameters.UnfilteredLinkUrl.EndsWith("tweetdeck.twitter.com/#", StringComparison.Ordinal)){
|
if (parameters.TypeFlags.HasFlag(ContextMenuType.Link) && !parameters.UnfilteredLinkUrl.EndsWith("tweetdeck.twitter.com/#", StringComparison.Ordinal)){
|
||||||
model.AddItem((CefMenuCommand)MenuOpenLinkUrl, "Open link in browser");
|
model.AddItem((CefMenuCommand)MenuOpenLinkUrl, "Open link in browser");
|
||||||
@@ -43,7 +50,7 @@ namespace TweetDck.Core.Handling{
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case MenuCopyLinkUrl:
|
case MenuCopyLinkUrl:
|
||||||
Clipboard.SetText(string.IsNullOrEmpty(TweetDeckBridge.LastRightClickedLink) ? parameters.UnfilteredLinkUrl : TweetDeckBridge.LastRightClickedLink, TextDataFormat.UnicodeText);
|
SetClipboardText(string.IsNullOrEmpty(TweetDeckBridge.LastRightClickedLink) ? parameters.UnfilteredLinkUrl : TweetDeckBridge.LastRightClickedLink);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case MenuOpenImage:
|
case MenuOpenImage:
|
||||||
@@ -74,7 +81,7 @@ namespace TweetDck.Core.Handling{
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case MenuCopyImageUrl:
|
case MenuCopyImageUrl:
|
||||||
Clipboard.SetText(parameters.SourceUrl, TextDataFormat.UnicodeText);
|
SetClipboardText(parameters.SourceUrl);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
#if DEBUG
|
#if DEBUG
|
||||||
@@ -93,6 +100,10 @@ namespace TweetDck.Core.Handling{
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected void SetClipboardText(string text){
|
||||||
|
form.InvokeSafe(() => WindowsUtils.SetClipboard(text, TextDataFormat.UnicodeText));
|
||||||
|
}
|
||||||
|
|
||||||
protected static void RemoveSeparatorIfLast(IMenuModel model){
|
protected static void RemoveSeparatorIfLast(IMenuModel model){
|
||||||
if (model.Count > 0 && model.GetTypeAt(model.Count-1) == MenuItemType.Separator){
|
if (model.Count > 0 && model.GetTypeAt(model.Count-1) == MenuItemType.Separator){
|
||||||
model.RemoveAt(model.Count-1);
|
model.RemoveAt(model.Count-1);
|
||||||
|
@@ -1,5 +1,4 @@
|
|||||||
using CefSharp;
|
using CefSharp;
|
||||||
using System.Windows.Forms;
|
|
||||||
using TweetDck.Core.Bridge;
|
using TweetDck.Core.Bridge;
|
||||||
using TweetDck.Core.Controls;
|
using TweetDck.Core.Controls;
|
||||||
using TweetDck.Core.Utils;
|
using TweetDck.Core.Utils;
|
||||||
@@ -23,7 +22,7 @@ namespace TweetDck.Core.Handling{
|
|||||||
private string lastHighlightedTweet;
|
private string lastHighlightedTweet;
|
||||||
private string lastHighlightedQuotedTweet;
|
private string lastHighlightedQuotedTweet;
|
||||||
|
|
||||||
public ContextMenuBrowser(FormBrowser form){
|
public ContextMenuBrowser(FormBrowser form) : base(form){
|
||||||
this.form = form;
|
this.form = form;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -34,6 +33,10 @@ namespace TweetDck.Core.Handling{
|
|||||||
model.Remove(CefMenuCommand.ViewSource);
|
model.Remove(CefMenuCommand.ViewSource);
|
||||||
RemoveSeparatorIfLast(model);
|
RemoveSeparatorIfLast(model);
|
||||||
|
|
||||||
|
if (parameters.TypeFlags.HasFlag(ContextMenuType.Selection)){
|
||||||
|
model.AddSeparator();
|
||||||
|
}
|
||||||
|
|
||||||
base.OnBeforeContextMenu(browserControl, browser, frame, parameters, model);
|
base.OnBeforeContextMenu(browserControl, browser, frame, parameters, model);
|
||||||
|
|
||||||
lastHighlightedTweet = TweetDeckBridge.LastHighlightedTweet;
|
lastHighlightedTweet = TweetDeckBridge.LastHighlightedTweet;
|
||||||
@@ -77,6 +80,8 @@ namespace TweetDck.Core.Handling{
|
|||||||
AddDebugMenuItems(globalMenu);
|
AddDebugMenuItems(globalMenu);
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
RemoveSeparatorIfLast(model);
|
||||||
}
|
}
|
||||||
|
|
||||||
public override bool OnContextMenuCommand(IWebBrowser browserControl, IBrowser browser, IFrame frame, IContextMenuParams parameters, CefMenuCommand commandId, CefEventFlags eventFlags){
|
public override bool OnContextMenuCommand(IWebBrowser browserControl, IBrowser browser, IFrame frame, IContextMenuParams parameters, CefMenuCommand commandId, CefEventFlags eventFlags){
|
||||||
@@ -114,7 +119,7 @@ namespace TweetDck.Core.Handling{
|
|||||||
return true;
|
return true;
|
||||||
|
|
||||||
case MenuCopyTweetUrl:
|
case MenuCopyTweetUrl:
|
||||||
Clipboard.SetText(lastHighlightedTweet, TextDataFormat.UnicodeText);
|
SetClipboardText(lastHighlightedTweet);
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
case MenuScreenshotTweet:
|
case MenuScreenshotTweet:
|
||||||
@@ -126,7 +131,7 @@ namespace TweetDck.Core.Handling{
|
|||||||
return true;
|
return true;
|
||||||
|
|
||||||
case MenuCopyQuotedTweetUrl:
|
case MenuCopyQuotedTweetUrl:
|
||||||
Clipboard.SetText(lastHighlightedQuotedTweet, TextDataFormat.UnicodeText);
|
SetClipboardText(lastHighlightedQuotedTweet);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -1,5 +1,4 @@
|
|||||||
using System.Windows.Forms;
|
using CefSharp;
|
||||||
using CefSharp;
|
|
||||||
using TweetDck.Core.Controls;
|
using TweetDck.Core.Controls;
|
||||||
|
|
||||||
namespace TweetDck.Core.Handling{
|
namespace TweetDck.Core.Handling{
|
||||||
@@ -12,13 +11,19 @@ namespace TweetDck.Core.Handling{
|
|||||||
private readonly FormNotification form;
|
private readonly FormNotification form;
|
||||||
private readonly bool enableCustomMenu;
|
private readonly bool enableCustomMenu;
|
||||||
|
|
||||||
public ContextMenuNotification(FormNotification form, bool enableCustomMenu){
|
public ContextMenuNotification(FormNotification form, bool enableCustomMenu) : base(form){
|
||||||
this.form = form;
|
this.form = form;
|
||||||
this.enableCustomMenu = enableCustomMenu;
|
this.enableCustomMenu = enableCustomMenu;
|
||||||
}
|
}
|
||||||
|
|
||||||
public override void OnBeforeContextMenu(IWebBrowser browserControl, IBrowser browser, IFrame frame, IContextMenuParams parameters, IMenuModel model){
|
public override void OnBeforeContextMenu(IWebBrowser browserControl, IBrowser browser, IFrame frame, IContextMenuParams parameters, IMenuModel model){
|
||||||
model.Clear();
|
model.Clear();
|
||||||
|
|
||||||
|
if (parameters.TypeFlags.HasFlag(ContextMenuType.Selection)){
|
||||||
|
model.AddItem(CefMenuCommand.Copy, "Copy");
|
||||||
|
model.AddSeparator();
|
||||||
|
}
|
||||||
|
|
||||||
base.OnBeforeContextMenu(browserControl, browser, frame, parameters, model);
|
base.OnBeforeContextMenu(browserControl, browser, frame, parameters, model);
|
||||||
|
|
||||||
if (enableCustomMenu){
|
if (enableCustomMenu){
|
||||||
@@ -62,11 +67,11 @@ namespace TweetDck.Core.Handling{
|
|||||||
return true;
|
return true;
|
||||||
|
|
||||||
case MenuCopyTweetUrl:
|
case MenuCopyTweetUrl:
|
||||||
Clipboard.SetText(form.CurrentUrl, TextDataFormat.UnicodeText);
|
SetClipboardText(form.CurrentUrl);
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
case MenuCopyQuotedTweetUrl:
|
case MenuCopyQuotedTweetUrl:
|
||||||
Clipboard.SetText(form.CurrentQuotedTweetUrl, TextDataFormat.UnicodeText);
|
SetClipboardText(form.CurrentQuotedTweetUrl);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -12,7 +12,7 @@ namespace TweetDck.Core.Notification.Screenshot{
|
|||||||
|
|
||||||
browser.FrameLoadEnd += (sender, args) => {
|
browser.FrameLoadEnd += (sender, args) => {
|
||||||
if (args.Frame.IsMain && browser.Address != "about:blank"){
|
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");
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@@ -9,9 +9,13 @@ using TweetDck.Updates;
|
|||||||
|
|
||||||
namespace TweetDck.Core.Other{
|
namespace TweetDck.Core.Other{
|
||||||
sealed partial class FormSettings : Form{
|
sealed partial class FormSettings : Form{
|
||||||
|
public const int TabIndexNotification = 1;
|
||||||
|
|
||||||
private readonly FormBrowser browser;
|
private readonly FormBrowser browser;
|
||||||
private readonly Dictionary<Type, BaseTabSettings> tabs = new Dictionary<Type, BaseTabSettings>(4);
|
private readonly Dictionary<Type, BaseTabSettings> tabs = new Dictionary<Type, BaseTabSettings>(4);
|
||||||
|
|
||||||
|
private bool wasTabSelectedAutomatically;
|
||||||
|
|
||||||
public FormSettings(FormBrowser browser, PluginManager plugins, UpdateHandler updates){
|
public FormSettings(FormBrowser browser, PluginManager plugins, UpdateHandler updates){
|
||||||
InitializeComponent();
|
InitializeComponent();
|
||||||
|
|
||||||
@@ -22,12 +26,18 @@ namespace TweetDck.Core.Other{
|
|||||||
|
|
||||||
this.tabPanel.SetupTabPanel(100);
|
this.tabPanel.SetupTabPanel(100);
|
||||||
this.tabPanel.AddButton("General", SelectTab<TabSettingsGeneral>);
|
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("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());
|
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(){
|
private void SelectTab<T>() where T : BaseTabSettings, new(){
|
||||||
SelectTab(() => new T());
|
SelectTab(() => new T());
|
||||||
}
|
}
|
||||||
|
@@ -23,6 +23,7 @@
|
|||||||
/// the contents of this method with the code editor.
|
/// the contents of this method with the code editor.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
private void InitializeComponent() {
|
private void InitializeComponent() {
|
||||||
|
this.components = new System.ComponentModel.Container();
|
||||||
this.textBoxBrowserCSS = new System.Windows.Forms.TextBox();
|
this.textBoxBrowserCSS = new System.Windows.Forms.TextBox();
|
||||||
this.btnCancel = new System.Windows.Forms.Button();
|
this.btnCancel = new System.Windows.Forms.Button();
|
||||||
this.btnApply = new System.Windows.Forms.Button();
|
this.btnApply = new System.Windows.Forms.Button();
|
||||||
@@ -32,6 +33,7 @@
|
|||||||
this.textBoxNotificationCSS = new System.Windows.Forms.TextBox();
|
this.textBoxNotificationCSS = new System.Windows.Forms.TextBox();
|
||||||
this.labelWarning = new System.Windows.Forms.Label();
|
this.labelWarning = new System.Windows.Forms.Label();
|
||||||
this.btnOpenWiki = new System.Windows.Forms.Button();
|
this.btnOpenWiki = new System.Windows.Forms.Button();
|
||||||
|
this.timerTestBrowser = new System.Windows.Forms.Timer(this.components);
|
||||||
((System.ComponentModel.ISupportInitialize)(this.splitContainer)).BeginInit();
|
((System.ComponentModel.ISupportInitialize)(this.splitContainer)).BeginInit();
|
||||||
this.splitContainer.Panel1.SuspendLayout();
|
this.splitContainer.Panel1.SuspendLayout();
|
||||||
this.splitContainer.Panel2.SuspendLayout();
|
this.splitContainer.Panel2.SuspendLayout();
|
||||||
@@ -52,6 +54,7 @@
|
|||||||
this.textBoxBrowserCSS.Size = new System.Drawing.Size(373, 253);
|
this.textBoxBrowserCSS.Size = new System.Drawing.Size(373, 253);
|
||||||
this.textBoxBrowserCSS.TabIndex = 0;
|
this.textBoxBrowserCSS.TabIndex = 0;
|
||||||
this.textBoxBrowserCSS.WordWrap = false;
|
this.textBoxBrowserCSS.WordWrap = false;
|
||||||
|
this.textBoxBrowserCSS.KeyUp += new System.Windows.Forms.KeyEventHandler(this.textBoxBrowserCSS_KeyUp);
|
||||||
//
|
//
|
||||||
// btnCancel
|
// btnCancel
|
||||||
//
|
//
|
||||||
@@ -132,7 +135,7 @@
|
|||||||
this.textBoxNotificationCSS.Multiline = true;
|
this.textBoxNotificationCSS.Multiline = true;
|
||||||
this.textBoxNotificationCSS.Name = "textBoxNotificationCSS";
|
this.textBoxNotificationCSS.Name = "textBoxNotificationCSS";
|
||||||
this.textBoxNotificationCSS.ScrollBars = System.Windows.Forms.ScrollBars.Both;
|
this.textBoxNotificationCSS.ScrollBars = System.Windows.Forms.ScrollBars.Both;
|
||||||
this.textBoxNotificationCSS.Size = new System.Drawing.Size(376, 253);
|
this.textBoxNotificationCSS.Size = new System.Drawing.Size(373, 253);
|
||||||
this.textBoxNotificationCSS.TabIndex = 1;
|
this.textBoxNotificationCSS.TabIndex = 1;
|
||||||
this.textBoxNotificationCSS.WordWrap = false;
|
this.textBoxNotificationCSS.WordWrap = false;
|
||||||
//
|
//
|
||||||
@@ -159,6 +162,11 @@
|
|||||||
this.btnOpenWiki.UseVisualStyleBackColor = true;
|
this.btnOpenWiki.UseVisualStyleBackColor = true;
|
||||||
this.btnOpenWiki.Click += new System.EventHandler(this.btnOpenWiki_Click);
|
this.btnOpenWiki.Click += new System.EventHandler(this.btnOpenWiki_Click);
|
||||||
//
|
//
|
||||||
|
// timerTestBrowser
|
||||||
|
//
|
||||||
|
this.timerTestBrowser.Interval = 500;
|
||||||
|
this.timerTestBrowser.Tick += new System.EventHandler(this.timerTestBrowser_Tick);
|
||||||
|
//
|
||||||
// DialogSettingsCSS
|
// DialogSettingsCSS
|
||||||
//
|
//
|
||||||
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
|
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
|
||||||
@@ -195,5 +203,6 @@
|
|||||||
private System.Windows.Forms.Label labelNotification;
|
private System.Windows.Forms.Label labelNotification;
|
||||||
private System.Windows.Forms.Label labelWarning;
|
private System.Windows.Forms.Label labelWarning;
|
||||||
private System.Windows.Forms.Button btnOpenWiki;
|
private System.Windows.Forms.Button btnOpenWiki;
|
||||||
|
private System.Windows.Forms.Timer timerTestBrowser;
|
||||||
}
|
}
|
||||||
}
|
}
|
@@ -17,11 +17,15 @@ namespace TweetDck.Core.Other.Settings.Dialogs{
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public DialogSettingsCSS(){
|
private readonly Action<string> reinjectBrowserCSS;
|
||||||
|
|
||||||
|
public DialogSettingsCSS(Action<string> reinjectBrowserCSS){
|
||||||
InitializeComponent();
|
InitializeComponent();
|
||||||
|
|
||||||
Text = Program.BrandName+" Settings - CSS";
|
Text = Program.BrandName+" Settings - CSS";
|
||||||
|
|
||||||
|
this.reinjectBrowserCSS = reinjectBrowserCSS;
|
||||||
|
|
||||||
textBoxBrowserCSS.EnableMultilineShortcuts();
|
textBoxBrowserCSS.EnableMultilineShortcuts();
|
||||||
textBoxBrowserCSS.Text = Program.UserConfig.CustomBrowserCSS ?? "";
|
textBoxBrowserCSS.Text = Program.UserConfig.CustomBrowserCSS ?? "";
|
||||||
|
|
||||||
@@ -29,6 +33,16 @@ namespace TweetDck.Core.Other.Settings.Dialogs{
|
|||||||
textBoxNotificationCSS.Text = Program.UserConfig.CustomNotificationCSS ?? "";
|
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){
|
private void btnOpenWiki_Click(object sender, EventArgs e){
|
||||||
BrowserUtils.OpenExternalBrowser("https://github.com/chylex/TweetDuck/wiki");
|
BrowserUtils.OpenExternalBrowser("https://github.com/chylex/TweetDuck/wiki");
|
||||||
}
|
}
|
||||||
|
@@ -121,8 +121,11 @@ namespace TweetDck.Core.Other.Settings.Export{
|
|||||||
|
|
||||||
public void WriteToFile(string path, bool createDirectory){
|
public void WriteToFile(string path, bool createDirectory){
|
||||||
if (createDirectory){
|
if (createDirectory){
|
||||||
// ReSharper disable once AssignNullToNotNullAttribute
|
string dir = Path.GetDirectoryName(path);
|
||||||
Directory.CreateDirectory(Path.GetDirectoryName(path));
|
|
||||||
|
if (!string.IsNullOrEmpty(dir)){
|
||||||
|
Directory.CreateDirectory(dir);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
File.WriteAllBytes(path, contents);
|
File.WriteAllBytes(path, contents);
|
||||||
|
@@ -9,13 +9,13 @@ using TweetDck.Plugins;
|
|||||||
|
|
||||||
namespace TweetDck.Core.Other.Settings{
|
namespace TweetDck.Core.Other.Settings{
|
||||||
partial class TabSettingsAdvanced : BaseTabSettings{
|
partial class TabSettingsAdvanced : BaseTabSettings{
|
||||||
private readonly Action browserReloadAction;
|
private readonly Action<string> reinjectBrowserCSS;
|
||||||
private readonly PluginManager plugins;
|
private readonly PluginManager plugins;
|
||||||
|
|
||||||
public TabSettingsAdvanced(Action browserReloadAction, PluginManager plugins){
|
public TabSettingsAdvanced(Action<string> reinjectBrowserCSS, PluginManager plugins){
|
||||||
InitializeComponent();
|
InitializeComponent();
|
||||||
|
|
||||||
this.browserReloadAction = browserReloadAction;
|
this.reinjectBrowserCSS = reinjectBrowserCSS;
|
||||||
this.plugins = plugins;
|
this.plugins = plugins;
|
||||||
|
|
||||||
checkHardwareAcceleration.Checked = HardwareAcceleration.IsEnabled;
|
checkHardwareAcceleration.Checked = HardwareAcceleration.IsEnabled;
|
||||||
@@ -80,17 +80,13 @@ namespace TweetDck.Core.Other.Settings{
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void btnEditCSS_Click(object sender, EventArgs e){
|
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){
|
if (form.ShowDialog(ParentForm) == DialogResult.OK){
|
||||||
bool hasChangedBrowser = form.BrowserCSS != Config.CustomBrowserCSS;
|
|
||||||
|
|
||||||
Config.CustomBrowserCSS = form.BrowserCSS;
|
Config.CustomBrowserCSS = form.BrowserCSS;
|
||||||
Config.CustomNotificationCSS = form.NotificationCSS;
|
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){
|
reinjectBrowserCSS(Config.CustomBrowserCSS); // reinject on cancel too, because the CSS is updated while typing
|
||||||
browserReloadAction();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -381,6 +381,7 @@
|
|||||||
this.tbCustomSound.Name = "tbCustomSound";
|
this.tbCustomSound.Name = "tbCustomSound";
|
||||||
this.tbCustomSound.Size = new System.Drawing.Size(170, 20);
|
this.tbCustomSound.Size = new System.Drawing.Size(170, 20);
|
||||||
this.tbCustomSound.TabIndex = 0;
|
this.tbCustomSound.TabIndex = 0;
|
||||||
|
this.tbCustomSound.TextChanged += new System.EventHandler(this.tbCustomSound_TextChanged);
|
||||||
//
|
//
|
||||||
// TabSettingsNotifications
|
// TabSettingsNotifications
|
||||||
//
|
//
|
||||||
|
@@ -1,6 +1,7 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Drawing;
|
using System.Drawing;
|
||||||
using System.Globalization;
|
using System.Globalization;
|
||||||
|
using System.IO;
|
||||||
using System.Windows.Forms;
|
using System.Windows.Forms;
|
||||||
using TweetDck.Core.Controls;
|
using TweetDck.Core.Controls;
|
||||||
using TweetDck.Core.Notification;
|
using TweetDck.Core.Notification;
|
||||||
@@ -11,7 +12,7 @@ namespace TweetDck.Core.Other.Settings{
|
|||||||
private readonly FormNotification notification;
|
private readonly FormNotification notification;
|
||||||
private readonly Point initCursorPosition;
|
private readonly Point initCursorPosition;
|
||||||
|
|
||||||
public TabSettingsNotifications(FormNotification notification){
|
public TabSettingsNotifications(FormNotification notification, bool ignoreAutoClick){
|
||||||
InitializeComponent();
|
InitializeComponent();
|
||||||
|
|
||||||
this.notification = notification;
|
this.notification = notification;
|
||||||
@@ -30,7 +31,7 @@ namespace TweetDck.Core.Other.Settings{
|
|||||||
this.notification.Activated += notification_Activated;
|
this.notification.Activated += notification_Activated;
|
||||||
this.notification.Show(this);
|
this.notification.Show(this);
|
||||||
|
|
||||||
initCursorPosition = Cursor.Position;
|
initCursorPosition = ignoreAutoClick ? ControlExtensions.InvisibleLocation : Cursor.Position;
|
||||||
|
|
||||||
switch(Config.NotificationPosition){
|
switch(Config.NotificationPosition){
|
||||||
case TweetNotification.Position.TopLeft: radioLocTL.Checked = true; break;
|
case TweetNotification.Position.TopLeft: radioLocTL.Checked = true; break;
|
||||||
@@ -58,7 +59,7 @@ namespace TweetDck.Core.Other.Settings{
|
|||||||
trackBarEdgeDistance.SetValueSafe(Config.NotificationEdgeDistance);
|
trackBarEdgeDistance.SetValueSafe(Config.NotificationEdgeDistance);
|
||||||
labelEdgeDistanceValue.Text = trackBarEdgeDistance.Value.ToString(CultureInfo.InvariantCulture)+" px";
|
labelEdgeDistanceValue.Text = trackBarEdgeDistance.Value.ToString(CultureInfo.InvariantCulture)+" px";
|
||||||
|
|
||||||
tbCustomSound.Text = Config.NotificationSoundPath ?? string.Empty;
|
tbCustomSound.Text = Config.NotificationSoundPath;
|
||||||
|
|
||||||
Disposed += (sender, args) => this.notification.Dispose();
|
Disposed += (sender, args) => this.notification.Dispose();
|
||||||
}
|
}
|
||||||
@@ -77,7 +78,7 @@ namespace TweetDck.Core.Other.Settings{
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void notification_Activated(object sender, EventArgs e){
|
private void notification_Activated(object sender, EventArgs e){
|
||||||
if (Cursor.Position == initCursorPosition){
|
if (Cursor.Position == initCursorPosition && initCursorPosition != ControlExtensions.InvisibleLocation){
|
||||||
Timer delay = WindowsUtils.CreateSingleTickTimer(1);
|
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
|
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);
|
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){
|
private void btnBrowseSound_Click(object sender, EventArgs e){
|
||||||
using(OpenFileDialog dialog = new OpenFileDialog{
|
using(OpenFileDialog dialog = new OpenFileDialog{
|
||||||
AutoUpgradeEnabled = true,
|
AutoUpgradeEnabled = true,
|
||||||
|
@@ -1,6 +1,7 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Windows.Forms;
|
using System.Windows.Forms;
|
||||||
using TweetDck.Updates;
|
using TweetDck.Updates;
|
||||||
|
using TweetDck.Updates.Events;
|
||||||
|
|
||||||
namespace TweetDck.Core.Other.Settings{
|
namespace TweetDck.Core.Other.Settings{
|
||||||
partial class TabSettingsUpdates : BaseTabSettings{
|
partial class TabSettingsUpdates : BaseTabSettings{
|
||||||
@@ -27,12 +28,18 @@ namespace TweetDck.Core.Other.Settings{
|
|||||||
private void btnCheckUpdates_Click(object sender, EventArgs e){
|
private void btnCheckUpdates_Click(object sender, EventArgs e){
|
||||||
if (!Ready)return;
|
if (!Ready)return;
|
||||||
|
|
||||||
Config.DismissedUpdate = string.Empty;
|
|
||||||
Config.Save();
|
|
||||||
|
|
||||||
updateCheckEventId = updates.Check(true);
|
updateCheckEventId = updates.Check(true);
|
||||||
|
|
||||||
|
if (updateCheckEventId == -1){
|
||||||
|
MessageBox.Show("Sorry, your system is no longer supported.", "Unsupported System", MessageBoxButtons.OK, MessageBoxIcon.Warning);
|
||||||
|
}
|
||||||
|
else{
|
||||||
btnCheckUpdates.Enabled = false;
|
btnCheckUpdates.Enabled = false;
|
||||||
|
|
||||||
|
updates.Settings.DismissedUpdate = string.Empty;
|
||||||
|
Config.DismissedUpdate = string.Empty;
|
||||||
|
Config.Save();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void updates_CheckFinished(object sender, UpdateCheckEventArgs e){
|
private void updates_CheckFinished(object sender, UpdateCheckEventArgs e){
|
||||||
|
@@ -105,7 +105,7 @@ namespace TweetDck.Core.Utils{
|
|||||||
build.Append(kvp.Key).Append(" \"").Append(kvp.Value).Append("\" ");
|
build.Append(kvp.Key).Append(" \"").Append(kvp.Value).Append("\" ");
|
||||||
}
|
}
|
||||||
|
|
||||||
return build.Remove(build.Length-1, 1).ToString();
|
return build.Length == 0 ? string.Empty : build.Remove(build.Length-1, 1).ToString();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -24,13 +24,26 @@ namespace TweetDck.Core.Utils{
|
|||||||
Left, Right
|
Left, Right
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private struct LASTINPUTINFO{
|
||||||
|
public static readonly uint Size = (uint)Marshal.SizeOf(typeof(LASTINPUTINFO));
|
||||||
|
|
||||||
|
// ReSharper disable once NotAccessedField.Local
|
||||||
|
public uint cbSize;
|
||||||
|
#pragma warning disable 649
|
||||||
|
public uint dwTime;
|
||||||
|
#pragma warning restore 649
|
||||||
|
}
|
||||||
|
|
||||||
public delegate IntPtr HookProc(int nCode, IntPtr wParam, IntPtr lParam);
|
public delegate IntPtr HookProc(int nCode, IntPtr wParam, IntPtr lParam);
|
||||||
|
|
||||||
[DllImport("user32.dll", EntryPoint = "SetWindowPos")]
|
[DllImport("user32.dll", EntryPoint = "SetWindowPos")]
|
||||||
public static extern bool SetWindowPos(int hWnd, int hWndOrder, int x, int y, int width, int height, uint flags);
|
private static extern bool SetWindowPos(int hWnd, int hWndOrder, int x, int y, int width, int height, uint flags);
|
||||||
|
|
||||||
[DllImport("user32.dll")]
|
[DllImport("user32.dll")]
|
||||||
public static extern void mouse_event(int dwFlags, int dx, int dy, int cButtons, int dwExtraInfo);
|
private static extern void mouse_event(int dwFlags, int dx, int dy, int cButtons, int dwExtraInfo);
|
||||||
|
|
||||||
|
[DllImport("user32.dll")]
|
||||||
|
private static extern bool GetLastInputInfo(ref LASTINPUTINFO info);
|
||||||
|
|
||||||
[DllImport("user32.dll")]
|
[DllImport("user32.dll")]
|
||||||
public static extern IntPtr SendMessage(IntPtr hWnd, uint msg, int wParam, IntPtr lParam);
|
public static extern IntPtr SendMessage(IntPtr hWnd, uint msg, int wParam, IntPtr lParam);
|
||||||
@@ -75,5 +88,23 @@ namespace TweetDck.Core.Utils{
|
|||||||
mouse_event(flagHold, Cursor.Position.X, Cursor.Position.Y, 0, 0);
|
mouse_event(flagHold, Cursor.Position.X, Cursor.Position.Y, 0, 0);
|
||||||
mouse_event(flagRelease, Cursor.Position.X, Cursor.Position.Y, 0, 0);
|
mouse_event(flagRelease, Cursor.Position.X, Cursor.Position.Y, 0, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static int GetIdleSeconds(){
|
||||||
|
LASTINPUTINFO info = new LASTINPUTINFO();
|
||||||
|
info.cbSize = LASTINPUTINFO.Size;
|
||||||
|
|
||||||
|
if (!GetLastInputInfo(ref info)){
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint ticks;
|
||||||
|
|
||||||
|
unchecked{
|
||||||
|
ticks = (uint)Environment.TickCount;
|
||||||
|
}
|
||||||
|
|
||||||
|
int seconds = (int)Math.Floor(TimeSpan.FromMilliseconds(ticks-info.dwTime).TotalSeconds);
|
||||||
|
return Math.Max(0, seconds); // ignore rollover after several weeks of uptime
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -1,5 +1,6 @@
|
|||||||
using System.Diagnostics;
|
using System.Diagnostics;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
|
using System.Runtime.InteropServices;
|
||||||
using System.Text.RegularExpressions;
|
using System.Text.RegularExpressions;
|
||||||
using System.Windows.Forms;
|
using System.Windows.Forms;
|
||||||
|
|
||||||
@@ -49,13 +50,36 @@ namespace TweetDck.Core.Utils{
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
string original = Clipboard.GetText(TextDataFormat.Html);
|
string originalText = Clipboard.GetText(TextDataFormat.UnicodeText);
|
||||||
string updated = RegexStripHtmlStyles.Replace(original, string.Empty);
|
string originalHtml = Clipboard.GetText(TextDataFormat.Html);
|
||||||
|
|
||||||
int removed = original.Length-updated.Length;
|
string updatedHtml = RegexStripHtmlStyles.Replace(originalHtml, string.Empty);
|
||||||
updated = RegexOffsetClipboardHtml.Replace(updated, match => (int.Parse(match.Value)-removed).ToString().PadLeft(match.Value.Length, '0'));
|
|
||||||
|
|
||||||
Clipboard.SetText(updated, TextDataFormat.Html);
|
int removed = originalHtml.Length-updatedHtml.Length;
|
||||||
|
updatedHtml = RegexOffsetClipboardHtml.Replace(updatedHtml, match => (int.Parse(match.Value)-removed).ToString().PadLeft(match.Value.Length, '0'));
|
||||||
|
|
||||||
|
DataObject obj = new DataObject();
|
||||||
|
obj.SetText(originalText, TextDataFormat.UnicodeText);
|
||||||
|
obj.SetText(updatedHtml, TextDataFormat.Html);
|
||||||
|
SetClipboardData(obj);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void SetClipboard(string text, TextDataFormat format){
|
||||||
|
if (string.IsNullOrEmpty(text)){
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
DataObject obj = new DataObject();
|
||||||
|
obj.SetText(text, format);
|
||||||
|
SetClipboardData(obj);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void SetClipboardData(DataObject obj){
|
||||||
|
try{
|
||||||
|
Clipboard.SetDataObject(obj);
|
||||||
|
}catch(ExternalException e){
|
||||||
|
Program.Reporter.HandleException("Clipboard Error", Program.BrandName+" could not access the clipboard as it is currently used by another process.", true, e);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -21,8 +21,8 @@ namespace TweetDck{
|
|||||||
public const string BrandName = "TweetDuck";
|
public const string BrandName = "TweetDuck";
|
||||||
public const string Website = "https://tweetduck.chylex.com";
|
public const string Website = "https://tweetduck.chylex.com";
|
||||||
|
|
||||||
public const string VersionTag = "1.6.1";
|
public const string VersionTag = "1.6.3";
|
||||||
public const string VersionFull = "1.6.1.0";
|
public const string VersionFull = "1.6.3.0";
|
||||||
|
|
||||||
public static readonly Version Version = new Version(VersionTag);
|
public static readonly Version Version = new Version(VersionTag);
|
||||||
|
|
||||||
@@ -126,6 +126,8 @@ namespace TweetDck{
|
|||||||
|
|
||||||
BrowserCache.ClearOldCacheFiles();
|
BrowserCache.ClearOldCacheFiles();
|
||||||
|
|
||||||
|
CefSharpSettings.WcfEnabled = false;
|
||||||
|
|
||||||
CefSettings settings = new CefSettings{
|
CefSettings settings = new CefSettings{
|
||||||
AcceptLanguageList = BrowserUtils.HeaderAcceptLanguage,
|
AcceptLanguageList = BrowserUtils.HeaderAcceptLanguage,
|
||||||
UserAgent = BrowserUtils.HeaderUserAgent,
|
UserAgent = BrowserUtils.HeaderUserAgent,
|
||||||
@@ -155,7 +157,8 @@ namespace TweetDck{
|
|||||||
plugins.Reload();
|
plugins.Reload();
|
||||||
|
|
||||||
FormBrowser mainForm = new FormBrowser(plugins, new UpdaterSettings{
|
FormBrowser mainForm = new FormBrowser(plugins, new UpdaterSettings{
|
||||||
AllowPreReleases = Args.HasFlag("-debugupdates")
|
AllowPreReleases = Args.HasFlag("-debugupdates"),
|
||||||
|
DismissedUpdate = UserConfig.DismissedUpdate
|
||||||
});
|
});
|
||||||
|
|
||||||
Application.Run(mainForm);
|
Application.Run(mainForm);
|
||||||
|
@@ -37,3 +37,7 @@ using TweetDck;
|
|||||||
[assembly: AssemblyFileVersion(Program.VersionFull)]
|
[assembly: AssemblyFileVersion(Program.VersionFull)]
|
||||||
|
|
||||||
[assembly: NeutralResourcesLanguageAttribute("en")]
|
[assembly: NeutralResourcesLanguageAttribute("en")]
|
||||||
|
|
||||||
|
#if DEBUG
|
||||||
|
[assembly: System.Runtime.CompilerServices.InternalsVisibleTo("UnitTests")]
|
||||||
|
#endif
|
||||||
|
@@ -1,4 +1,4 @@
|
|||||||
(function($, $TD, TD){
|
(function($, $TD, $TDX, TD){
|
||||||
//
|
//
|
||||||
// Variable: Current highlighted column jQuery object.
|
// Variable: Current highlighted column jQuery object.
|
||||||
//
|
//
|
||||||
@@ -20,8 +20,8 @@
|
|||||||
if (menu.length === 0)return;
|
if (menu.length === 0)return;
|
||||||
|
|
||||||
menu.children(".drp-h-divider").last().after([
|
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-settings">TweetDuck 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-plugins">TweetDuck plugins</a></li>',
|
||||||
'<li class="drp-h-divider"></li>'
|
'<li class="drp-h-divider"></li>'
|
||||||
].join(""));
|
].join(""));
|
||||||
|
|
||||||
@@ -112,6 +112,7 @@
|
|||||||
|
|
||||||
html.css("border", "0");
|
html.css("border", "0");
|
||||||
html.find("footer").last().remove(); // apparently withTweetActions breaks for certain tweets, nice
|
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") || "";
|
var url = html.find("time").first().children("a").first().attr("href") || "";
|
||||||
|
|
||||||
@@ -198,7 +199,7 @@
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($TD.expandLinksOnHover){
|
if ($TDX.expandLinksOnHover){
|
||||||
tooltipTimer = window.setTimeout(function(){
|
tooltipTimer = window.setTimeout(function(){
|
||||||
var expanded = me.attr("data-full-url");
|
var expanded = me.attr("data-full-url");
|
||||||
expanded = cutStart(expanded, "https://");
|
expanded = cutStart(expanded, "https://");
|
||||||
@@ -217,7 +218,7 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (e.type === "mouseleave"){
|
else if (e.type === "mouseleave"){
|
||||||
if ($TD.expandLinksOnHover){
|
if ($TDX.expandLinksOnHover){
|
||||||
var prevText = me.attr("td-prev-text");
|
var prevText = me.attr("td-prev-text");
|
||||||
|
|
||||||
if (prevText){
|
if (prevText){
|
||||||
@@ -256,7 +257,7 @@
|
|||||||
var soundEle = document.getElementById("update-sound");
|
var soundEle = document.getElementById("update-sound");
|
||||||
|
|
||||||
soundEle.play = prependToFunction(soundEle.play, function(){
|
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(".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
|
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
|
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);
|
||||||
|
@@ -1,11 +1,27 @@
|
|||||||
(function($, $TD, TD){
|
(function($, $TD, $TDX, TD){
|
||||||
|
var isDebugging = false;
|
||||||
|
|
||||||
$(document).keydown(function(e){
|
$(document).keydown(function(e){
|
||||||
|
|
||||||
// ==============================
|
// ==========================
|
||||||
// F4 key - simulate notification
|
// F4 key - toggle debug mode
|
||||||
// ==============================
|
// ==========================
|
||||||
|
|
||||||
if (e.keyCode === 115){
|
if (e.keyCode === 115){
|
||||||
|
isDebugging = !isDebugging;
|
||||||
|
$(".app-title").first().css("background-color", isDebugging ? "#5A6B75" : "#292F33");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Debug mode handling
|
||||||
|
|
||||||
|
else if (isDebugging){
|
||||||
|
e.preventDefault();
|
||||||
|
|
||||||
|
// ===================================
|
||||||
|
// N key - simulate popup notification
|
||||||
|
// ===================================
|
||||||
|
|
||||||
|
if (e.keyCode === 78){
|
||||||
var col = TD.controller.columnManager.getAllOrdered()[0];
|
var col = TD.controller.columnManager.getAllOrdered()[0];
|
||||||
|
|
||||||
$.publish("/notifications/new",[{
|
$.publish("/notifications/new",[{
|
||||||
@@ -15,5 +31,19 @@
|
|||||||
]
|
]
|
||||||
}]);
|
}]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ===================================
|
||||||
|
// 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);
|
||||||
|
@@ -1,4 +1,4 @@
|
|||||||
(function($TD){
|
(function($TD, $TDX){
|
||||||
//
|
//
|
||||||
// Variable: Collection of all <a> tags.
|
// Variable: Collection of all <a> tags.
|
||||||
//
|
//
|
||||||
@@ -51,7 +51,7 @@
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($TD.expandLinksOnHover){
|
if ($TDX.expandLinksOnHover){
|
||||||
tooltipTimer = window.setTimeout(function(){
|
tooltipTimer = window.setTimeout(function(){
|
||||||
var expanded = url;
|
var expanded = url;
|
||||||
expanded = cutStart(expanded, "https://");
|
expanded = cutStart(expanded, "https://");
|
||||||
@@ -73,7 +73,7 @@
|
|||||||
addEventListener(links, "mouseleave", function(e){
|
addEventListener(links, "mouseleave", function(e){
|
||||||
if (!e.currentTarget.hasAttribute("data-full-url"))return;
|
if (!e.currentTarget.hasAttribute("data-full-url"))return;
|
||||||
|
|
||||||
if ($TD.expandLinksOnHover){
|
if ($TDX.expandLinksOnHover){
|
||||||
var prevText = e.currentTarget.getAttribute("td-prev-text");
|
var prevText = e.currentTarget.getAttribute("td-prev-text");
|
||||||
|
|
||||||
if (prevText){
|
if (prevText){
|
||||||
@@ -146,4 +146,4 @@
|
|||||||
document.body.addEventListener("mouseleave", function(){
|
document.body.addEventListener("mouseleave", function(){
|
||||||
document.body.classList.remove("td-hover");
|
document.body.classList.remove("td-hover");
|
||||||
});
|
});
|
||||||
})($TD);
|
})($TD, $TDX);
|
||||||
|
@@ -7,25 +7,25 @@
|
|||||||
//
|
//
|
||||||
// Constant: Update exe file name.
|
// 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.
|
// 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.
|
// 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.
|
// 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 outdated = version === "unsupported";
|
||||||
|
|
||||||
var ele = $("#tweetdck-update");
|
var ele = $("#tweetduck-update");
|
||||||
var existed = ele.length > 0;
|
var existed = ele.length > 0;
|
||||||
|
|
||||||
if (existed > 0){
|
if (existed > 0){
|
||||||
@@ -33,7 +33,7 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
var html = outdated ? [
|
var html = outdated ? [
|
||||||
"<div id='tweetdck-update'>",
|
"<div id='tweetduck-update'>",
|
||||||
"<p class='tdu-title'>Unsupported System</p>",
|
"<p class='tdu-title'>Unsupported System</p>",
|
||||||
"<p class='tdu-info'>You will not receive updates.</p>",
|
"<p class='tdu-info'>You will not receive updates.</p>",
|
||||||
"<div class='tdu-buttons'>",
|
"<div class='tdu-buttons'>",
|
||||||
@@ -42,8 +42,8 @@
|
|||||||
"</div>",
|
"</div>",
|
||||||
"</div>"
|
"</div>"
|
||||||
] : [
|
] : [
|
||||||
"<div id='tweetdck-update'>",
|
"<div id='tweetduck-update'>",
|
||||||
"<p class='tdu-title'>"+$TDU.brandName+" Update</p>",
|
"<p class='tdu-title'>TweetDuck Update</p>",
|
||||||
"<p class='tdu-info'>Version "+version+" is now available.</p>",
|
"<p class='tdu-info'>Version "+version+" is now available.</p>",
|
||||||
"<div class='tdu-buttons'>",
|
"<div class='tdu-buttons'>",
|
||||||
"<button class='btn btn-positive tdu-btn-download'><span class='label'>Download</span></button>",
|
"<button class='btn btn-positive tdu-btn-download'><span class='label'>Download</span></button>",
|
||||||
@@ -54,7 +54,7 @@
|
|||||||
|
|
||||||
$(document.body).append(html.join(""));
|
$(document.body).append(html.join(""));
|
||||||
|
|
||||||
ele = $("#tweetdck-update");
|
ele = $("#tweetduck-update");
|
||||||
|
|
||||||
var buttonDiv = ele.children("div.tdu-buttons").first();
|
var buttonDiv = ele.children("div.tdu-buttons").first();
|
||||||
|
|
||||||
@@ -128,33 +128,19 @@
|
|||||||
//
|
//
|
||||||
// Function: Runs an update check and updates all DOM elements appropriately.
|
// Function: Runs an update check and updates all DOM elements appropriately.
|
||||||
//
|
//
|
||||||
var runUpdateCheck = function(force, eventID){
|
var runUpdateCheck = function(eventID, versionTag, dismissedVersionTag, allowPre){
|
||||||
if (!$TDU.isSystemSupported){
|
|
||||||
if ($TDU.dismissedVersionTag !== "unsupported"){
|
|
||||||
createUpdateNotificationElement("unsupported");
|
|
||||||
}
|
|
||||||
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
clearTimeout(updateCheckTimeoutID);
|
clearTimeout(updateCheckTimeoutID);
|
||||||
updateCheckTimeoutID = setTimeout(runUpdateCheck, 1000*60*60); // 1 hour
|
updateCheckTimeoutID = setTimeout($TDU.triggerUpdateCheck, 1000*60*60); // 1 hour
|
||||||
|
|
||||||
if (!$TDU.updateCheckEnabled && !force){
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
var allowPre = $TDU.allowPreReleases;
|
|
||||||
|
|
||||||
$.getJSON(allowPre ? updateCheckUrlAll : updateCheckUrlLatest, function(response){
|
$.getJSON(allowPre ? updateCheckUrlAll : updateCheckUrlLatest, function(response){
|
||||||
var release = allowPre ? response[0] : response;
|
var release = allowPre ? response[0] : response;
|
||||||
|
|
||||||
var tagName = release.tag_name;
|
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){
|
if (hasUpdate){
|
||||||
var obj = release.assets.find(asset => asset.name === updateFileName) || release.assets[0];
|
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
|
if (eventID){ // ignore undefined and 0
|
||||||
@@ -166,6 +152,6 @@
|
|||||||
//
|
//
|
||||||
// Block: Setup global functions.
|
// Block: Setup global functions.
|
||||||
//
|
//
|
||||||
|
window.TDUF_displayNotification = displayNotification;
|
||||||
window.TDUF_runUpdateCheck = runUpdateCheck;
|
window.TDUF_runUpdateCheck = runUpdateCheck;
|
||||||
runUpdateCheck();
|
|
||||||
})($, $TDU);
|
})($, $TDU);
|
||||||
|
@@ -71,6 +71,7 @@
|
|||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<Compile Include="Configuration\LockManager.cs" />
|
<Compile Include="Configuration\LockManager.cs" />
|
||||||
<Compile Include="Configuration\UserConfig.cs" />
|
<Compile Include="Configuration\UserConfig.cs" />
|
||||||
|
<Compile Include="Core\Bridge\PropertyBridge.cs" />
|
||||||
<Compile Include="Core\Controls\ControlExtensions.cs" />
|
<Compile Include="Core\Controls\ControlExtensions.cs" />
|
||||||
<Compile Include="Core\Controls\FlatButton.cs">
|
<Compile Include="Core\Controls\FlatButton.cs">
|
||||||
<SubType>Component</SubType>
|
<SubType>Component</SubType>
|
||||||
@@ -222,6 +223,7 @@
|
|||||||
<Compile Include="Plugins\PluginManager.cs" />
|
<Compile Include="Plugins\PluginManager.cs" />
|
||||||
<Compile Include="Plugins\PluginScriptGenerator.cs" />
|
<Compile Include="Plugins\PluginScriptGenerator.cs" />
|
||||||
<Compile Include="Reporter.cs" />
|
<Compile Include="Reporter.cs" />
|
||||||
|
<Compile Include="Updates\Events\UpdateDismissedEventArgs.cs" />
|
||||||
<Compile Include="Updates\FormUpdateDownload.cs">
|
<Compile Include="Updates\FormUpdateDownload.cs">
|
||||||
<SubType>Form</SubType>
|
<SubType>Form</SubType>
|
||||||
</Compile>
|
</Compile>
|
||||||
@@ -238,8 +240,8 @@
|
|||||||
<Compile Include="Core\Utils\BrowserUtils.cs" />
|
<Compile Include="Core\Utils\BrowserUtils.cs" />
|
||||||
<Compile Include="Core\Utils\HardwareAcceleration.cs" />
|
<Compile Include="Core\Utils\HardwareAcceleration.cs" />
|
||||||
<Compile Include="Core\Utils\NativeMethods.cs" />
|
<Compile Include="Core\Utils\NativeMethods.cs" />
|
||||||
<Compile Include="Updates\UpdateAcceptedEventArgs.cs" />
|
<Compile Include="Updates\Events\UpdateAcceptedEventArgs.cs" />
|
||||||
<Compile Include="Updates\UpdateCheckEventArgs.cs" />
|
<Compile Include="Updates\Events\UpdateCheckEventArgs.cs" />
|
||||||
<Compile Include="Updates\UpdateHandler.cs" />
|
<Compile Include="Updates\UpdateHandler.cs" />
|
||||||
<Compile Include="Updates\UpdateInfo.cs" />
|
<Compile Include="Updates\UpdateInfo.cs" />
|
||||||
<Compile Include="Program.cs" />
|
<Compile Include="Program.cs" />
|
||||||
|
12
TweetDck.sln
12
TweetDck.sln
@@ -1,21 +1,31 @@
|
|||||||
|
|
||||||
Microsoft Visual Studio Solution File, Format Version 12.00
|
Microsoft Visual Studio Solution File, Format Version 12.00
|
||||||
# Visual Studio 2013
|
# Visual Studio 2013
|
||||||
VisualStudioVersion = 12.0.40629.0
|
VisualStudioVersion = 12.0.40629.0
|
||||||
MinimumVisualStudioVersion = 10.0.40219.1
|
MinimumVisualStudioVersion = 10.0.40219.1
|
||||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "TweetDck", "TweetDck.csproj", "{2389A7CD-E0D3-4706-8294-092929A33A2D}"
|
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "TweetDck", "TweetDck.csproj", "{2389A7CD-E0D3-4706-8294-092929A33A2D}"
|
||||||
EndProject
|
EndProject
|
||||||
|
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "UnitTests", "tests\UnitTests.csproj", "{A958FA7A-4A2C-42A7-BFA0-159343483F4E}"
|
||||||
|
EndProject
|
||||||
Global
|
Global
|
||||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||||
|
Debug|Any CPU = Debug|Any CPU
|
||||||
Debug|x86 = Debug|x86
|
Debug|x86 = Debug|x86
|
||||||
|
Release|Any CPU = Release|Any CPU
|
||||||
Release|x86 = Release|x86
|
Release|x86 = Release|x86
|
||||||
EndGlobalSection
|
EndGlobalSection
|
||||||
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
||||||
|
{2389A7CD-E0D3-4706-8294-092929A33A2D}.Debug|Any CPU.ActiveCfg = Debug|x86
|
||||||
{2389A7CD-E0D3-4706-8294-092929A33A2D}.Debug|x86.ActiveCfg = Debug|x86
|
{2389A7CD-E0D3-4706-8294-092929A33A2D}.Debug|x86.ActiveCfg = Debug|x86
|
||||||
{2389A7CD-E0D3-4706-8294-092929A33A2D}.Debug|x86.Build.0 = Debug|x86
|
{2389A7CD-E0D3-4706-8294-092929A33A2D}.Debug|x86.Build.0 = Debug|x86
|
||||||
{2389A7CD-E0D3-4706-8294-092929A33A2D}.Debug|x86.Deploy.0 = Debug|x86
|
{2389A7CD-E0D3-4706-8294-092929A33A2D}.Debug|x86.Deploy.0 = Debug|x86
|
||||||
|
{2389A7CD-E0D3-4706-8294-092929A33A2D}.Release|Any CPU.ActiveCfg = Release|x86
|
||||||
{2389A7CD-E0D3-4706-8294-092929A33A2D}.Release|x86.ActiveCfg = Release|x86
|
{2389A7CD-E0D3-4706-8294-092929A33A2D}.Release|x86.ActiveCfg = Release|x86
|
||||||
{2389A7CD-E0D3-4706-8294-092929A33A2D}.Release|x86.Build.0 = Release|x86
|
{2389A7CD-E0D3-4706-8294-092929A33A2D}.Release|x86.Build.0 = Release|x86
|
||||||
|
{A958FA7A-4A2C-42A7-BFA0-159343483F4E}.Debug|Any CPU.ActiveCfg = Debug|x86
|
||||||
|
{A958FA7A-4A2C-42A7-BFA0-159343483F4E}.Debug|x86.ActiveCfg = Debug|x86
|
||||||
|
{A958FA7A-4A2C-42A7-BFA0-159343483F4E}.Debug|x86.Build.0 = Debug|x86
|
||||||
|
{A958FA7A-4A2C-42A7-BFA0-159343483F4E}.Release|Any CPU.ActiveCfg = Release|x86
|
||||||
|
{A958FA7A-4A2C-42A7-BFA0-159343483F4E}.Release|x86.ActiveCfg = Release|x86
|
||||||
EndGlobalSection
|
EndGlobalSection
|
||||||
GlobalSection(SolutionProperties) = preSolution
|
GlobalSection(SolutionProperties) = preSolution
|
||||||
HideSolutionNode = FALSE
|
HideSolutionNode = FALSE
|
||||||
|
2
TweetDck.sln.DotSettings
Normal file
2
TweetDck.sln.DotSettings
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
<wpf:ResourceDictionary xml:space="preserve" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:s="clr-namespace:System;assembly=mscorlib" xmlns:ss="urn:shemas-jetbrains-com:settings-storage-xaml" xmlns:wpf="http://schemas.microsoft.com/winfx/2006/xaml/presentation">
|
||||||
|
<s:String x:Key="/Default/FilterSettingsManager/CoverageFilterXml/@EntryValue"><data><IncludeFilters /><ExcludeFilters><Filter ModuleMask="UnitTests" ModuleVersionMask="*" ClassMask="*" FunctionMask="*" IsEnabled="True" /></ExcludeFilters></data></s:String></wpf:ResourceDictionary>
|
@@ -1,6 +1,6 @@
|
|||||||
using System;
|
using System;
|
||||||
|
|
||||||
namespace TweetDck.Updates{
|
namespace TweetDck.Updates.Events{
|
||||||
class UpdateAcceptedEventArgs : EventArgs{
|
class UpdateAcceptedEventArgs : EventArgs{
|
||||||
public readonly UpdateInfo UpdateInfo;
|
public readonly UpdateInfo UpdateInfo;
|
||||||
|
|
@@ -1,6 +1,6 @@
|
|||||||
using System;
|
using System;
|
||||||
|
|
||||||
namespace TweetDck.Updates{
|
namespace TweetDck.Updates.Events{
|
||||||
class UpdateCheckEventArgs : EventArgs{
|
class UpdateCheckEventArgs : EventArgs{
|
||||||
public int EventId { get; private set; }
|
public int EventId { get; private set; }
|
||||||
public bool UpdateAvailable { get; private set; }
|
public bool UpdateAvailable { get; private set; }
|
11
Updates/Events/UpdateDismissedEventArgs.cs
Normal file
11
Updates/Events/UpdateDismissedEventArgs.cs
Normal 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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@@ -9,7 +9,7 @@ using TweetDck.Core.Utils;
|
|||||||
|
|
||||||
namespace TweetDck.Updates{
|
namespace TweetDck.Updates{
|
||||||
sealed partial class FormUpdateDownload : Form{
|
sealed partial class FormUpdateDownload : Form{
|
||||||
private const double BytesToMB = 1024.0*1024.0;
|
private const double BytesToKB = 1024.0;
|
||||||
|
|
||||||
public string InstallerPath{
|
public string InstallerPath{
|
||||||
get{
|
get{
|
||||||
@@ -69,7 +69,7 @@ namespace TweetDck.Updates{
|
|||||||
progressDownload.SetValueInstant(1000);
|
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{
|
else{
|
||||||
if (progressDownload.Style != ProgressBarStyle.Continuous){
|
if (progressDownload.Style != ProgressBarStyle.Continuous){
|
||||||
@@ -77,7 +77,7 @@ namespace TweetDck.Updates{
|
|||||||
}
|
}
|
||||||
|
|
||||||
progressDownload.SetValueInstant(e.ProgressPercentage*10);
|
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";
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@@ -5,14 +5,28 @@ using TweetDck.Core;
|
|||||||
using TweetDck.Core.Controls;
|
using TweetDck.Core.Controls;
|
||||||
using TweetDck.Core.Utils;
|
using TweetDck.Core.Utils;
|
||||||
using TweetDck.Resources;
|
using TweetDck.Resources;
|
||||||
|
using TweetDck.Updates.Events;
|
||||||
|
|
||||||
namespace TweetDck.Updates{
|
namespace TweetDck.Updates{
|
||||||
class UpdateHandler{
|
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 ChromiumWebBrowser browser;
|
||||||
private readonly FormBrowser form;
|
private readonly FormBrowser form;
|
||||||
private readonly UpdaterSettings settings;
|
private readonly UpdaterSettings settings;
|
||||||
|
|
||||||
public event EventHandler<UpdateAcceptedEventArgs> UpdateAccepted;
|
public event EventHandler<UpdateAcceptedEventArgs> UpdateAccepted;
|
||||||
|
public event EventHandler<UpdateDismissedEventArgs> UpdateDismissed;
|
||||||
public event EventHandler<UpdateCheckEventArgs> CheckFinished;
|
public event EventHandler<UpdateCheckEventArgs> CheckFinished;
|
||||||
|
|
||||||
private int lastEventId;
|
private int lastEventId;
|
||||||
@@ -23,26 +37,50 @@ namespace TweetDck.Updates{
|
|||||||
this.settings = settings;
|
this.settings = settings;
|
||||||
|
|
||||||
browser.FrameLoadEnd += browser_FrameLoadEnd;
|
browser.FrameLoadEnd += browser_FrameLoadEnd;
|
||||||
browser.RegisterJsObject("$TDU", new Bridge(this));
|
browser.RegisterAsyncJsObject("$TDU", new Bridge(this));
|
||||||
}
|
}
|
||||||
|
|
||||||
private void browser_FrameLoadEnd(object sender, FrameLoadEndEventArgs e){
|
private void browser_FrameLoadEnd(object sender, FrameLoadEndEventArgs e){
|
||||||
if (e.Frame.IsMain && BrowserUtils.IsTweetDeckWebsite(e.Frame)){
|
if (e.Frame.IsMain && BrowserUtils.IsTweetDeckWebsite(e.Frame)){
|
||||||
ScriptLoader.ExecuteFile(e.Frame, "update.js");
|
ScriptLoader.ExecuteFile(e.Frame, "update.js");
|
||||||
|
Check(false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public int Check(bool force){
|
public int Check(bool force){
|
||||||
browser.ExecuteScriptAsync("TDUF_runUpdateCheck", force, ++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 lastEventId;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
else if (settings.DismissedUpdate != "unsupported"){
|
||||||
|
browser.ExecuteScriptAsync("TDUF_displayNotification", "unsupported");
|
||||||
|
}
|
||||||
|
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
private void TriggerUpdateAcceptedEvent(UpdateAcceptedEventArgs args){
|
private void TriggerUpdateAcceptedEvent(UpdateAcceptedEventArgs args){
|
||||||
if (UpdateAccepted != null){
|
if (UpdateAccepted != null){
|
||||||
form.InvokeSafe(() => UpdateAccepted(this, args));
|
form.InvokeSafe(() => UpdateAccepted(this, args));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void TriggerUpdateDismissedEvent(UpdateDismissedEventArgs args){
|
||||||
|
form.InvokeSafe(() => {
|
||||||
|
settings.DismissedUpdate = args.VersionTag;
|
||||||
|
|
||||||
|
if (UpdateDismissed != null){
|
||||||
|
UpdateDismissed(this, args);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
private void TriggerCheckFinishedEvent(UpdateCheckEventArgs args){
|
private void TriggerCheckFinishedEvent(UpdateCheckEventArgs args){
|
||||||
if (CheckFinished != null){
|
if (CheckFinished != null){
|
||||||
form.InvokeSafe(() => CheckFinished(this, args));
|
form.InvokeSafe(() => CheckFinished(this, args));
|
||||||
@@ -50,48 +88,16 @@ namespace TweetDck.Updates{
|
|||||||
}
|
}
|
||||||
|
|
||||||
public class Bridge{
|
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 Environment.OSVersion.Version >= new Version("6.1"); // 6.1 NT version = Windows 7
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private readonly UpdateHandler owner;
|
private readonly UpdateHandler owner;
|
||||||
|
|
||||||
public Bridge(UpdateHandler owner){
|
public Bridge(UpdateHandler owner){
|
||||||
this.owner = owner;
|
this.owner = owner;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void TriggerUpdateCheck(){
|
||||||
|
owner.Check(false);
|
||||||
|
}
|
||||||
|
|
||||||
public void OnUpdateCheckFinished(int eventId, bool isUpdateAvailable, string latestVersion){
|
public void OnUpdateCheckFinished(int eventId, bool isUpdateAvailable, string latestVersion){
|
||||||
owner.TriggerCheckFinishedEvent(new UpdateCheckEventArgs(eventId, isUpdateAvailable, latestVersion));
|
owner.TriggerCheckFinishedEvent(new UpdateCheckEventArgs(eventId, isUpdateAvailable, latestVersion));
|
||||||
}
|
}
|
||||||
@@ -101,10 +107,7 @@ namespace TweetDck.Updates{
|
|||||||
}
|
}
|
||||||
|
|
||||||
public void OnUpdateDismissed(string versionTag){
|
public void OnUpdateDismissed(string versionTag){
|
||||||
owner.form.InvokeSafe(() => {
|
owner.TriggerUpdateDismissedEvent(new UpdateDismissedEventArgs(versionTag));
|
||||||
Program.UserConfig.DismissedUpdate = versionTag;
|
|
||||||
Program.UserConfig.Save();
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void OpenBrowser(string url){
|
public void OpenBrowser(string url){
|
||||||
|
@@ -1,5 +1,6 @@
|
|||||||
namespace TweetDck.Updates{
|
namespace TweetDck.Updates{
|
||||||
class UpdaterSettings{
|
class UpdaterSettings{
|
||||||
public bool AllowPreReleases { get; set; }
|
public bool AllowPreReleases { get; set; }
|
||||||
|
public string DismissedUpdate { get; set; }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -10,7 +10,7 @@
|
|||||||
|
|
||||||
[Setup]
|
[Setup]
|
||||||
AppId={{8C25A716-7E11-4AAD-9992-8B5D0C78AE06}
|
AppId={{8C25A716-7E11-4AAD-9992-8B5D0C78AE06}
|
||||||
AppName={#MyAppName}
|
AppName={#MyAppName} Portable
|
||||||
AppVersion={#MyAppVersion}
|
AppVersion={#MyAppVersion}
|
||||||
AppVerName={#MyAppName} {#MyAppVersion}
|
AppVerName={#MyAppName} {#MyAppVersion}
|
||||||
AppPublisher={#MyAppPublisher}
|
AppPublisher={#MyAppPublisher}
|
||||||
|
@@ -12,7 +12,7 @@
|
|||||||
|
|
||||||
[Setup]
|
[Setup]
|
||||||
AppId={{{#MyAppID}}
|
AppId={{{#MyAppID}}
|
||||||
AppName={#MyAppName}
|
AppName={#MyAppName} Update
|
||||||
AppVersion={#MyAppVersion}
|
AppVersion={#MyAppVersion}
|
||||||
AppVerName={#MyAppName} {#MyAppVersion}
|
AppVerName={#MyAppName} {#MyAppVersion}
|
||||||
AppPublisher={#MyAppPublisher}
|
AppPublisher={#MyAppPublisher}
|
||||||
|
143
tests/Core/Settings/TestCombinedFileStream.cs
Normal file
143
tests/Core/Settings/TestCombinedFileStream.cs
Normal file
@@ -0,0 +1,143 @@
|
|||||||
|
using Microsoft.VisualStudio.TestTools.UnitTesting;
|
||||||
|
using System;
|
||||||
|
using System.IO;
|
||||||
|
using TweetDck.Core.Other.Settings.Export;
|
||||||
|
|
||||||
|
namespace UnitTests.Core.Settings{
|
||||||
|
[TestClass]
|
||||||
|
public class TestCombinedFileStream{
|
||||||
|
[TestMethod]
|
||||||
|
public void TestNoFiles(){
|
||||||
|
using(CombinedFileStream cfs = new CombinedFileStream(TestUtils.WriteFile("cfs_empty"))){
|
||||||
|
cfs.Flush();
|
||||||
|
}
|
||||||
|
|
||||||
|
Assert.IsTrue(File.Exists("cfs_empty"));
|
||||||
|
|
||||||
|
using(CombinedFileStream cfs = new CombinedFileStream(TestUtils.ReadFile("cfs_empty"))){
|
||||||
|
Assert.IsNull(cfs.ReadFile());
|
||||||
|
}
|
||||||
|
|
||||||
|
using(CombinedFileStream cfs = new CombinedFileStream(TestUtils.ReadFile("cfs_empty"))){
|
||||||
|
Assert.IsNull(cfs.SkipFile());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void TestEmptyFiles(){
|
||||||
|
TestUtils.WriteText("cfs_input_empty_1", string.Empty);
|
||||||
|
TestUtils.WriteText("cfs_input_empty_2", string.Empty);
|
||||||
|
|
||||||
|
using(CombinedFileStream cfs = new CombinedFileStream(TestUtils.WriteFile("cfs_blank_files"))){
|
||||||
|
cfs.WriteFile("id1", "cfs_input_empty_1");
|
||||||
|
cfs.WriteFile("id2", "cfs_input_empty_2");
|
||||||
|
cfs.WriteFile("id2_clone", "cfs_input_empty_2");
|
||||||
|
cfs.Flush();
|
||||||
|
}
|
||||||
|
|
||||||
|
Assert.IsTrue(File.Exists("cfs_blank_files"));
|
||||||
|
|
||||||
|
using(CombinedFileStream cfs = new CombinedFileStream(TestUtils.ReadFile("cfs_blank_files"))){
|
||||||
|
CombinedFileStream.Entry entry1 = cfs.ReadFile();
|
||||||
|
string entry2key = cfs.SkipFile();
|
||||||
|
CombinedFileStream.Entry entry3 = cfs.ReadFile();
|
||||||
|
|
||||||
|
Assert.IsNull(cfs.ReadFile());
|
||||||
|
Assert.IsNull(cfs.SkipFile());
|
||||||
|
|
||||||
|
Assert.AreEqual("id1", entry1.KeyName);
|
||||||
|
Assert.AreEqual("id1", entry1.Identifier);
|
||||||
|
CollectionAssert.AreEqual(new string[0], entry1.KeyValue);
|
||||||
|
|
||||||
|
Assert.AreEqual("id2", entry2key);
|
||||||
|
|
||||||
|
Assert.AreEqual("id2_clone", entry3.KeyName);
|
||||||
|
Assert.AreEqual("id2_clone", entry3.Identifier);
|
||||||
|
CollectionAssert.AreEqual(new string[0], entry3.KeyValue);
|
||||||
|
|
||||||
|
entry1.WriteToFile("cfs_blank_file_1");
|
||||||
|
entry3.WriteToFile("cfs_blank_file_2");
|
||||||
|
TestUtils.DeleteFileOnExit("cfs_blank_file_1");
|
||||||
|
TestUtils.DeleteFileOnExit("cfs_blank_file_2");
|
||||||
|
}
|
||||||
|
|
||||||
|
Assert.IsTrue(File.Exists("cfs_blank_file_1"));
|
||||||
|
Assert.IsTrue(File.Exists("cfs_blank_file_2"));
|
||||||
|
Assert.AreEqual(string.Empty, TestUtils.ReadText("cfs_blank_file_1"));
|
||||||
|
Assert.AreEqual(string.Empty, TestUtils.ReadText("cfs_blank_file_2"));
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void TestTextFilesAndComplexKeys(){
|
||||||
|
TestUtils.WriteText("cfs_input_text_1", "Hello World!"+Environment.NewLine);
|
||||||
|
|
||||||
|
using(CombinedFileStream cfs = new CombinedFileStream(TestUtils.WriteFile("cfs_text_files"))){
|
||||||
|
cfs.WriteFile(new string[]{ "key1", "a", "bb", "ccc", "dddd" }, "cfs_input_text_1");
|
||||||
|
cfs.WriteFile(new string[]{ "key2", "a", "bb", "ccc", "dddd" }, "cfs_input_text_1");
|
||||||
|
cfs.Flush();
|
||||||
|
}
|
||||||
|
|
||||||
|
Assert.IsTrue(File.Exists("cfs_text_files"));
|
||||||
|
|
||||||
|
using(CombinedFileStream cfs = new CombinedFileStream(TestUtils.ReadFile("cfs_text_files"))){
|
||||||
|
CombinedFileStream.Entry entry = cfs.ReadFile();
|
||||||
|
|
||||||
|
Assert.AreEqual("key2", cfs.SkipFile());
|
||||||
|
Assert.IsNull(cfs.ReadFile());
|
||||||
|
Assert.IsNull(cfs.SkipFile());
|
||||||
|
|
||||||
|
Assert.AreEqual("key1|a|bb|ccc|dddd", entry.Identifier);
|
||||||
|
Assert.AreEqual("key1", entry.KeyName);
|
||||||
|
CollectionAssert.AreEqual(new string[]{ "a", "bb", "ccc", "dddd" }, entry.KeyValue);
|
||||||
|
|
||||||
|
entry.WriteToFile("cfs_text_file_1");
|
||||||
|
TestUtils.DeleteFileOnExit("cfs_text_file_1");
|
||||||
|
}
|
||||||
|
|
||||||
|
Assert.IsTrue(File.Exists("cfs_text_file_1"));
|
||||||
|
Assert.AreEqual("Hello World!"+Environment.NewLine, TestUtils.ReadText("cfs_text_file_1"));
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void TestEntryWriteWithDirectory(){
|
||||||
|
if (Directory.Exists("cfs_directory")){
|
||||||
|
Directory.Delete("cfs_directory", true);
|
||||||
|
}
|
||||||
|
|
||||||
|
TestUtils.WriteText("cfs_input_dir_1", "test");
|
||||||
|
|
||||||
|
using(CombinedFileStream cfs = new CombinedFileStream(TestUtils.WriteFile("cfs_dir_test"))){
|
||||||
|
cfs.WriteFile("key1", "cfs_input_dir_1");
|
||||||
|
cfs.WriteFile("key2", "cfs_input_dir_1");
|
||||||
|
cfs.WriteFile("key3", "cfs_input_dir_1");
|
||||||
|
cfs.WriteFile("key4", "cfs_input_dir_1");
|
||||||
|
cfs.Flush();
|
||||||
|
}
|
||||||
|
|
||||||
|
Assert.IsTrue(File.Exists("cfs_dir_test"));
|
||||||
|
|
||||||
|
using(CombinedFileStream cfs = new CombinedFileStream(TestUtils.ReadFile("cfs_dir_test"))){
|
||||||
|
try{
|
||||||
|
cfs.ReadFile().WriteToFile("cfs_directory/cfs_dir_test_file", false);
|
||||||
|
Assert.Fail("WriteToFile did not trigger an exception.");
|
||||||
|
}catch(DirectoryNotFoundException){}
|
||||||
|
|
||||||
|
cfs.ReadFile().WriteToFile("cfs_directory/cfs_dir_test_file", true);
|
||||||
|
cfs.ReadFile().WriteToFile("cfs_dir_test_file", true);
|
||||||
|
cfs.ReadFile().WriteToFile("cfs_dir_test_file.txt", true);
|
||||||
|
TestUtils.DeleteFileOnExit("cfs_dir_test_file");
|
||||||
|
TestUtils.DeleteFileOnExit("cfs_dir_test_file.txt");
|
||||||
|
}
|
||||||
|
|
||||||
|
Assert.IsTrue(Directory.Exists("cfs_directory"));
|
||||||
|
Assert.IsTrue(File.Exists("cfs_directory/cfs_dir_test_file"));
|
||||||
|
Assert.IsTrue(File.Exists("cfs_dir_test_file"));
|
||||||
|
Assert.IsTrue(File.Exists("cfs_dir_test_file.txt"));
|
||||||
|
Assert.AreEqual("test", TestUtils.ReadText("cfs_directory/cfs_dir_test_file"));
|
||||||
|
Assert.AreEqual("test", TestUtils.ReadText("cfs_dir_test_file"));
|
||||||
|
Assert.AreEqual("test", TestUtils.ReadText("cfs_dir_test_file.txt"));
|
||||||
|
|
||||||
|
Directory.Delete("cfs_directory", true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
19
tests/Core/Utils/TestBrowserUtils.cs
Normal file
19
tests/Core/Utils/TestBrowserUtils.cs
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
using Microsoft.VisualStudio.TestTools.UnitTesting;
|
||||||
|
using TweetDck.Core.Utils;
|
||||||
|
|
||||||
|
namespace UnitTests.Core.Utils{
|
||||||
|
[TestClass]
|
||||||
|
public class TestBrowserUtils{
|
||||||
|
[TestMethod]
|
||||||
|
public void TestGetFileNameFromUrl(){
|
||||||
|
Assert.AreEqual("index.html", BrowserUtils.GetFileNameFromUrl("http://test.com/index.html"));
|
||||||
|
Assert.AreEqual("index.html", BrowserUtils.GetFileNameFromUrl("http://test.com/index.html?"));
|
||||||
|
Assert.AreEqual("index.html", BrowserUtils.GetFileNameFromUrl("http://test.com/index.html?param1=abc¶m2=false"));
|
||||||
|
|
||||||
|
Assert.AreEqual("index", BrowserUtils.GetFileNameFromUrl("http://test.com/index"));
|
||||||
|
Assert.AreEqual("index.", BrowserUtils.GetFileNameFromUrl("http://test.com/index."));
|
||||||
|
|
||||||
|
Assert.IsNull(BrowserUtils.GetFileNameFromUrl("http://test.com/"));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
157
tests/Core/Utils/TestCommandLineArgs.cs
Normal file
157
tests/Core/Utils/TestCommandLineArgs.cs
Normal file
@@ -0,0 +1,157 @@
|
|||||||
|
using Microsoft.VisualStudio.TestTools.UnitTesting;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using TweetDck.Core.Utils;
|
||||||
|
|
||||||
|
namespace UnitTests.Core.Utils{
|
||||||
|
[TestClass]
|
||||||
|
public class TestCommandLineArgs{
|
||||||
|
[TestMethod]
|
||||||
|
public void TestEmpty(){
|
||||||
|
CommandLineArgs args = new CommandLineArgs();
|
||||||
|
|
||||||
|
Assert.AreEqual(0, args.Count);
|
||||||
|
Assert.AreEqual(string.Empty, args.ToString());
|
||||||
|
|
||||||
|
Assert.IsFalse(args.HasFlag("x"));
|
||||||
|
Assert.IsFalse(args.HasValue("x"));
|
||||||
|
Assert.AreEqual("default", args.GetValue("x", "default"));
|
||||||
|
|
||||||
|
args.RemoveFlag("x");
|
||||||
|
args.RemoveValue("x");
|
||||||
|
|
||||||
|
var dict = new Dictionary<string, string>();
|
||||||
|
args.ToDictionary(dict);
|
||||||
|
Assert.AreEqual(0, dict.Count);
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void TestFlags(){
|
||||||
|
CommandLineArgs args = new CommandLineArgs();
|
||||||
|
|
||||||
|
args.AddFlag("my_test_flag_1");
|
||||||
|
args.AddFlag("my_test_flag_2");
|
||||||
|
args.AddFlag("aAaAa");
|
||||||
|
|
||||||
|
Assert.IsFalse(args.HasValue("aAaAa"));
|
||||||
|
|
||||||
|
Assert.AreEqual(3, args.Count);
|
||||||
|
Assert.IsTrue(args.HasFlag("my_test_flag_1"));
|
||||||
|
Assert.IsTrue(args.HasFlag("my_test_flag_2"));
|
||||||
|
Assert.IsTrue(args.HasFlag("aaaaa"));
|
||||||
|
Assert.IsTrue(args.HasFlag("AAAAA"));
|
||||||
|
Assert.AreEqual("my_test_flag_1 my_test_flag_2 aaaaa", args.ToString());
|
||||||
|
|
||||||
|
args.RemoveFlag("Aaaaa");
|
||||||
|
|
||||||
|
Assert.AreEqual(2, args.Count);
|
||||||
|
Assert.IsTrue(args.HasFlag("my_test_flag_1"));
|
||||||
|
Assert.IsTrue(args.HasFlag("my_test_flag_2"));
|
||||||
|
Assert.IsFalse(args.HasFlag("aaaaa"));
|
||||||
|
Assert.AreEqual("my_test_flag_1 my_test_flag_2", args.ToString());
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void TestValues(){
|
||||||
|
CommandLineArgs args = new CommandLineArgs();
|
||||||
|
|
||||||
|
args.SetValue("test_value", "My Test Value");
|
||||||
|
args.SetValue("aAaAa", "aaaaa");
|
||||||
|
|
||||||
|
Assert.IsFalse(args.HasFlag("aAaAa"));
|
||||||
|
|
||||||
|
Assert.AreEqual(2, args.Count);
|
||||||
|
Assert.IsTrue(args.HasValue("test_value"));
|
||||||
|
Assert.IsTrue(args.HasValue("aaaaa"));
|
||||||
|
Assert.IsTrue(args.HasValue("AAAAA"));
|
||||||
|
Assert.AreEqual("My Test Value", args.GetValue("test_value", string.Empty));
|
||||||
|
Assert.AreEqual("aaaaa", args.GetValue("aaaaa", string.Empty));
|
||||||
|
Assert.AreEqual("test_value \"My Test Value\" aaaaa \"aaaaa\"", args.ToString());
|
||||||
|
|
||||||
|
args.RemoveValue("Aaaaa");
|
||||||
|
|
||||||
|
Assert.AreEqual(1, args.Count);
|
||||||
|
Assert.IsTrue(args.HasValue("test_value"));
|
||||||
|
Assert.IsFalse(args.HasValue("aaaaa"));
|
||||||
|
Assert.AreEqual("test_value \"My Test Value\"", args.ToString());
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void TestFlagAndValueMix(){
|
||||||
|
CommandLineArgs args = new CommandLineArgs();
|
||||||
|
|
||||||
|
args.AddFlag("my_test_flag_1");
|
||||||
|
args.AddFlag("my_test_flag_2");
|
||||||
|
args.AddFlag("aAaAa");
|
||||||
|
|
||||||
|
args.SetValue("test_value", "My Test Value");
|
||||||
|
args.SetValue("aAaAa", "aaaaa");
|
||||||
|
|
||||||
|
Assert.AreEqual(5, args.Count);
|
||||||
|
Assert.IsTrue(args.HasFlag("aaaaa"));
|
||||||
|
Assert.IsTrue(args.HasValue("aaaaa"));
|
||||||
|
Assert.AreEqual("my_test_flag_1 my_test_flag_2 aaaaa test_value \"My Test Value\" aaaaa \"aaaaa\"", args.ToString());
|
||||||
|
|
||||||
|
var dict = new Dictionary<string, string>();
|
||||||
|
args.ToDictionary(dict); // loses 'aaaaa' flag
|
||||||
|
|
||||||
|
Assert.AreEqual(4, dict.Count);
|
||||||
|
Assert.AreEqual("1", dict["my_test_flag_1"]);
|
||||||
|
Assert.AreEqual("1", dict["my_test_flag_2"]);
|
||||||
|
Assert.AreEqual("My Test Value", dict["test_value"]);
|
||||||
|
Assert.AreEqual("aaaaa", dict["aaaaa"]);
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void TestClone(){
|
||||||
|
CommandLineArgs args = new CommandLineArgs();
|
||||||
|
|
||||||
|
args.AddFlag("my_test_flag_1");
|
||||||
|
args.AddFlag("my_test_flag_2");
|
||||||
|
args.AddFlag("aAaAa");
|
||||||
|
|
||||||
|
args.SetValue("test_value", "My Test Value");
|
||||||
|
args.SetValue("aAaAa", "aaaaa");
|
||||||
|
|
||||||
|
CommandLineArgs clone = args.Clone();
|
||||||
|
args.RemoveFlag("aaaaa");
|
||||||
|
args.RemoveValue("aaaaa");
|
||||||
|
clone.RemoveFlag("my_test_flag_1");
|
||||||
|
clone.RemoveFlag("my_test_flag_2");
|
||||||
|
clone.RemoveValue("test_value");
|
||||||
|
|
||||||
|
Assert.AreEqual(3, args.Count);
|
||||||
|
Assert.AreEqual(2, clone.Count);
|
||||||
|
|
||||||
|
Assert.AreEqual("my_test_flag_1 my_test_flag_2 test_value \"My Test Value\"", args.ToString());
|
||||||
|
Assert.AreEqual("aaaaa aaaaa \"aaaaa\"", clone.ToString());
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void TestEmptyStringArray(){
|
||||||
|
CommandLineArgs args;
|
||||||
|
|
||||||
|
args = CommandLineArgs.FromStringArray('-', new string[0]);
|
||||||
|
Assert.AreEqual(0, args.Count);
|
||||||
|
|
||||||
|
args = CommandLineArgs.FromStringArray('-', new string[]{ "", "+fail", "@nope" });
|
||||||
|
Assert.AreEqual(0, args.Count);
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void TestValidStringArray(){
|
||||||
|
CommandLineArgs args;
|
||||||
|
|
||||||
|
args = CommandLineArgs.FromStringArray('-', new string[]{ "-flag1", "-flag2", "-FLAG3" });
|
||||||
|
Assert.AreEqual(3, args.Count);
|
||||||
|
Assert.IsTrue(args.HasFlag("-flag1"));
|
||||||
|
Assert.IsTrue(args.HasFlag("-flag2"));
|
||||||
|
Assert.IsTrue(args.HasFlag("-flag3"));
|
||||||
|
|
||||||
|
args = CommandLineArgs.FromStringArray('-', new string[]{ "-flag", "-value", "Here is some text!" });
|
||||||
|
Assert.AreEqual(2, args.Count);
|
||||||
|
Assert.IsTrue(args.HasFlag("-flag"));
|
||||||
|
Assert.IsTrue(args.HasValue("-value"));
|
||||||
|
Assert.AreEqual("Here is some text!", args.GetValue("-value", string.Empty));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
32
tests/Core/Utils/TestCommandLineArgsParser.cs
Normal file
32
tests/Core/Utils/TestCommandLineArgsParser.cs
Normal file
@@ -0,0 +1,32 @@
|
|||||||
|
using Microsoft.VisualStudio.TestTools.UnitTesting;
|
||||||
|
using TweetDck.Core.Utils;
|
||||||
|
|
||||||
|
namespace UnitTests.Core.Utils{
|
||||||
|
[TestClass]
|
||||||
|
public class TestCommandLineArgsParser{
|
||||||
|
[TestMethod]
|
||||||
|
public void TestEmptyString(){
|
||||||
|
Assert.AreEqual(0, CommandLineArgsParser.ReadCefArguments("").Count);
|
||||||
|
Assert.AreEqual(0, CommandLineArgsParser.ReadCefArguments(" ").Count);
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void TestValidString(){
|
||||||
|
CommandLineArgs args = CommandLineArgsParser.ReadCefArguments("--aaa --bbb --first-value=123 --SECOND-VALUE=\"a b c d e\" --ccc");
|
||||||
|
// cef has no flags, flag arguments have a value of 1
|
||||||
|
// the processing removes all dashes in front of each key
|
||||||
|
|
||||||
|
Assert.AreEqual(5, args.Count);
|
||||||
|
Assert.IsTrue(args.HasValue("aaa"));
|
||||||
|
Assert.IsTrue(args.HasValue("bbb"));
|
||||||
|
Assert.IsTrue(args.HasValue("ccc"));
|
||||||
|
Assert.IsTrue(args.HasValue("first-value"));
|
||||||
|
Assert.IsTrue(args.HasValue("second-value"));
|
||||||
|
Assert.AreEqual("1", args.GetValue("aaa", string.Empty));
|
||||||
|
Assert.AreEqual("1", args.GetValue("bbb", string.Empty));
|
||||||
|
Assert.AreEqual("1", args.GetValue("ccc", string.Empty));
|
||||||
|
Assert.AreEqual("123", args.GetValue("first-value", string.Empty));
|
||||||
|
Assert.AreEqual("a b c d e", args.GetValue("second-value", string.Empty));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
35
tests/Properties/AssemblyInfo.cs
Normal file
35
tests/Properties/AssemblyInfo.cs
Normal file
@@ -0,0 +1,35 @@
|
|||||||
|
using System.Reflection;
|
||||||
|
using System.Runtime.InteropServices;
|
||||||
|
|
||||||
|
// General Information about an assembly is controlled through the following
|
||||||
|
// set of attributes. Change these attribute values to modify the information
|
||||||
|
// associated with an assembly.
|
||||||
|
[assembly: AssemblyTitle("UnitTests")]
|
||||||
|
[assembly: AssemblyDescription("")]
|
||||||
|
[assembly: AssemblyConfiguration("")]
|
||||||
|
[assembly: AssemblyCompany("")]
|
||||||
|
[assembly: AssemblyProduct("UnitTests")]
|
||||||
|
[assembly: AssemblyCopyright("")]
|
||||||
|
[assembly: AssemblyTrademark("")]
|
||||||
|
[assembly: AssemblyCulture("")]
|
||||||
|
|
||||||
|
// Setting ComVisible to false makes the types in this assembly not visible
|
||||||
|
// to COM components. If you need to access a type in this assembly from
|
||||||
|
// COM, set the ComVisible attribute to true on that type.
|
||||||
|
[assembly: ComVisible(false)]
|
||||||
|
|
||||||
|
// The following GUID is for the ID of the typelib if this project is exposed to COM
|
||||||
|
[assembly: Guid("99036b78-aad6-4a76-8bf3-40c77eca2464")]
|
||||||
|
|
||||||
|
// Version information for an assembly consists of the following four values:
|
||||||
|
//
|
||||||
|
// Major Version
|
||||||
|
// Minor Version
|
||||||
|
// Build Number
|
||||||
|
// Revision
|
||||||
|
//
|
||||||
|
// You can specify all the values or you can default the Build and Revision Numbers
|
||||||
|
// by using the '*' as shown below:
|
||||||
|
// [assembly: AssemblyVersion("1.0.*")]
|
||||||
|
[assembly: AssemblyVersion("1.0.0.0")]
|
||||||
|
[assembly: AssemblyFileVersion("1.0.0.0")]
|
65
tests/TestUtils.cs
Normal file
65
tests/TestUtils.cs
Normal file
@@ -0,0 +1,65 @@
|
|||||||
|
using System;
|
||||||
|
using System.IO;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Text;
|
||||||
|
using System.Linq;
|
||||||
|
using Microsoft.VisualStudio.TestTools.UnitTesting;
|
||||||
|
|
||||||
|
namespace UnitTests{
|
||||||
|
public static class TestUtils{
|
||||||
|
private static readonly HashSet<string> CreatedFiles = new HashSet<string>();
|
||||||
|
|
||||||
|
public static void WriteText(string file, string text){
|
||||||
|
DeleteFileOnExit(file);
|
||||||
|
File.WriteAllText(file, text, Encoding.UTF8);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void WriteLines(string file, IEnumerable<string> lines){
|
||||||
|
DeleteFileOnExit(file);
|
||||||
|
File.WriteAllLines(file, lines, Encoding.UTF8);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static FileStream WriteFile(string file){
|
||||||
|
DeleteFileOnExit(file);
|
||||||
|
return new FileStream(file, FileMode.Create, FileAccess.Write, FileShare.None);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static string ReadText(string file){
|
||||||
|
try{
|
||||||
|
return File.ReadAllText(file, Encoding.UTF8);
|
||||||
|
}catch(Exception){
|
||||||
|
return string.Empty;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static IEnumerable<string> ReadLines(string file){
|
||||||
|
try{
|
||||||
|
return File.ReadLines(file, Encoding.UTF8);
|
||||||
|
}catch(Exception){
|
||||||
|
return Enumerable.Empty<string>();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static FileStream ReadFile(string file){
|
||||||
|
return new FileStream(file, FileMode.Open, FileAccess.Read, FileShare.None);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void DeleteFileOnExit(string file){
|
||||||
|
CreatedFiles.Add(file);
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestClass]
|
||||||
|
public static class Cleanup{
|
||||||
|
[AssemblyCleanup]
|
||||||
|
public static void DeleteFilesOnExit(){
|
||||||
|
foreach(string file in CreatedFiles){
|
||||||
|
try{
|
||||||
|
File.Delete(file);
|
||||||
|
}catch(Exception){
|
||||||
|
// ignore
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
90
tests/UnitTests.csproj
Normal file
90
tests/UnitTests.csproj
Normal file
@@ -0,0 +1,90 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<Project ToolsVersion="12.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||||
|
<PropertyGroup>
|
||||||
|
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
|
||||||
|
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
|
||||||
|
<ProjectGuid>{A958FA7A-4A2C-42A7-BFA0-159343483F4E}</ProjectGuid>
|
||||||
|
<OutputType>Library</OutputType>
|
||||||
|
<AppDesignerFolder>Properties</AppDesignerFolder>
|
||||||
|
<RootNamespace>UnitTests</RootNamespace>
|
||||||
|
<AssemblyName>UnitTests</AssemblyName>
|
||||||
|
<TargetFrameworkVersion>v4.5.2</TargetFrameworkVersion>
|
||||||
|
<FileAlignment>512</FileAlignment>
|
||||||
|
<ProjectTypeGuids>{3AC096D0-A1C2-E12C-1390-A8335801FDAB};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}</ProjectTypeGuids>
|
||||||
|
<VisualStudioVersion Condition="'$(VisualStudioVersion)' == ''">10.0</VisualStudioVersion>
|
||||||
|
<VSToolsPath Condition="'$(VSToolsPath)' == ''">$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)</VSToolsPath>
|
||||||
|
<ReferencePath>$(ProgramFiles)\Common Files\microsoft shared\VSTT\$(VisualStudioVersion)\UITestExtensionPackages</ReferencePath>
|
||||||
|
<IsCodedUITest>False</IsCodedUITest>
|
||||||
|
<TestProjectType>UnitTest</TestProjectType>
|
||||||
|
<TargetFrameworkProfile />
|
||||||
|
</PropertyGroup>
|
||||||
|
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Debug|x86'">
|
||||||
|
<PlatformTarget>x86</PlatformTarget>
|
||||||
|
<OutputPath>bin\x86\Debug\</OutputPath>
|
||||||
|
<Prefer32Bit>false</Prefer32Bit>
|
||||||
|
</PropertyGroup>
|
||||||
|
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Release|x86'">
|
||||||
|
<PlatformTarget>x86</PlatformTarget>
|
||||||
|
<OutputPath>bin\x86\Release\</OutputPath>
|
||||||
|
<Prefer32Bit>false</Prefer32Bit>
|
||||||
|
</PropertyGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<Reference Include="System" />
|
||||||
|
<Reference Include="System.Core">
|
||||||
|
<RequiredTargetFramework>3.5</RequiredTargetFramework>
|
||||||
|
</Reference>
|
||||||
|
</ItemGroup>
|
||||||
|
<Choose>
|
||||||
|
<When Condition="('$(VisualStudioVersion)' == '10.0' or '$(VisualStudioVersion)' == '') and '$(TargetFrameworkVersion)' == 'v3.5'">
|
||||||
|
<ItemGroup>
|
||||||
|
<Reference Include="Microsoft.VisualStudio.QualityTools.UnitTestFramework, Version=10.1.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL" />
|
||||||
|
</ItemGroup>
|
||||||
|
</When>
|
||||||
|
<Otherwise>
|
||||||
|
<ItemGroup>
|
||||||
|
<Reference Include="Microsoft.VisualStudio.QualityTools.UnitTestFramework" />
|
||||||
|
</ItemGroup>
|
||||||
|
</Otherwise>
|
||||||
|
</Choose>
|
||||||
|
<ItemGroup>
|
||||||
|
<Compile Include="Core\Settings\TestCombinedFileStream.cs" />
|
||||||
|
<Compile Include="Core\Utils\TestBrowserUtils.cs" />
|
||||||
|
<Compile Include="Core\Utils\TestCommandLineArgs.cs" />
|
||||||
|
<Compile Include="Core\Utils\TestCommandLineArgsParser.cs" />
|
||||||
|
<Compile Include="Properties\AssemblyInfo.cs" />
|
||||||
|
<Compile Include="TestUtils.cs" />
|
||||||
|
</ItemGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<ProjectReference Include="..\TweetDck.csproj">
|
||||||
|
<Project>{2389a7cd-e0d3-4706-8294-092929a33a2d}</Project>
|
||||||
|
<Name>TweetDck</Name>
|
||||||
|
</ProjectReference>
|
||||||
|
</ItemGroup>
|
||||||
|
<Choose>
|
||||||
|
<When Condition="'$(VisualStudioVersion)' == '10.0' And '$(IsCodedUITest)' == 'True'">
|
||||||
|
<ItemGroup>
|
||||||
|
<Reference Include="Microsoft.VisualStudio.QualityTools.CodedUITestFramework, Version=10.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
|
||||||
|
<Private>False</Private>
|
||||||
|
</Reference>
|
||||||
|
<Reference Include="Microsoft.VisualStudio.TestTools.UITest.Common, Version=10.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
|
||||||
|
<Private>False</Private>
|
||||||
|
</Reference>
|
||||||
|
<Reference Include="Microsoft.VisualStudio.TestTools.UITest.Extension, Version=10.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
|
||||||
|
<Private>False</Private>
|
||||||
|
</Reference>
|
||||||
|
<Reference Include="Microsoft.VisualStudio.TestTools.UITesting, Version=10.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
|
||||||
|
<Private>False</Private>
|
||||||
|
</Reference>
|
||||||
|
</ItemGroup>
|
||||||
|
</When>
|
||||||
|
</Choose>
|
||||||
|
<Import Project="$(VSToolsPath)\TeamTest\Microsoft.TestTools.targets" Condition="Exists('$(VSToolsPath)\TeamTest\Microsoft.TestTools.targets')" />
|
||||||
|
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
|
||||||
|
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
|
||||||
|
Other similar extension points exist, see Microsoft.Common.targets.
|
||||||
|
<Target Name="BeforeBuild">
|
||||||
|
</Target>
|
||||||
|
<Target Name="AfterBuild">
|
||||||
|
</Target>
|
||||||
|
-->
|
||||||
|
</Project>
|
Reference in New Issue
Block a user