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

Compare commits

..

74 Commits
1.0 ... 1.2

Author SHA1 Message Date
15a39de939 Update version to 1.2 2016-04-26 18:51:45 +02:00
4142206b65 Fix icon in Volume Mixer
Closes #20
2016-04-26 16:04:02 +02:00
6105658602 Temporarily re-add default sound notification, but make it work with Mute function 2016-04-26 15:49:24 +02:00
a6e40be79e Fix maximization resetting restore location and size 2016-04-26 15:19:54 +02:00
95fba6a99a Fix license file copying in post build events 2016-04-26 11:59:47 +02:00
aa2e4c9845 Implement multiple tray options and refactor tray icon handling 2016-04-26 02:41:19 +02:00
f4cfc40244 Redo locations and margins in settings Form 2016-04-26 01:01:16 +02:00
6c50bdba06 Rename 'Update Notifications' setting to 'Check for Updates' 2016-04-26 00:44:49 +02:00
1f6fc491ef Add a WIP sound notification hook 2016-04-26 00:43:44 +02:00
1c3a7b6ce7 Implement holding Ctrl to open clicked links in browser 2016-04-25 18:07:54 +02:00
b04e260fb7 Fix focus stealing issues when showing or hiding the notification Form 2016-04-25 17:58:10 +02:00
4a66486e1a Rename extendFunction to appendToFunction, and add prependToFunction to code.js 2016-04-25 17:01:56 +02:00
a335aa037a Fix clicking on nested/complex links in notification.js not triggering the hooks 2016-04-25 16:17:28 +02:00
dd4c89b9dd Add notification Form title changing with enqueued tweets 2016-04-25 16:12:58 +02:00
ddbf6da061 Fix double-clicking maximizing notification Form by setting MaximizeBox to false (thanks Microsoft...) 2016-04-25 16:06:07 +02:00
f85e0030a7 Add Mute Notifications setting (required changes to notification focus handling)
Closes #13
2016-04-25 15:51:14 +02:00
c0271d273f Remove unused fontSizeClasses from code.js 2016-04-25 12:49:57 +02:00
2a1dc8beab Bypass t.co links in context menu and hide url options for # links 2016-04-24 22:13:48 +02:00
c5b3bc1a0b Fix context menu not running any actions in notification Form 2016-04-24 22:04:41 +02:00
316b1db3f6 Force word-break:break-all on expanded links 2016-04-24 20:51:30 +02:00
49fa7626b6 Expand shortened links on hover
Closes #12
2016-04-24 20:47:10 +02:00
24edcc3402 Rewrite notification system to improve reliability and future extensibility
Closes #18
2016-04-24 16:37:27 +02:00
c53a1cbd01 Fix clicking on "Followed by:" users opening the browser 2016-04-24 14:53:11 +02:00
c138b13d01 Rewrite theme change handling 2016-04-24 14:28:39 +02:00
acc9b58660 Remove getFontSizeClass from code.js 2016-04-24 14:19:20 +02:00
b94a6acee6 Add address check to notification form before running notification.js 2016-04-24 14:15:04 +02:00
b2892cc834 Rewrite font size handling 2016-04-24 14:10:29 +02:00
82a1e17b1d Add extendFunction and refactor window.TD in code.js 2016-04-24 14:04:52 +02:00
82a3cd8df2 Add a simple context menu to the tray icon (Restore, Close) 2016-04-23 20:59:23 +02:00
b39a3a05fe Move update notification code to update.js and make the notification display without needing the app div 2016-04-23 17:54:15 +02:00
f4c7eb14ec Add ScriptLoader.LoadResources with unlimited parameters 2016-04-23 17:53:01 +02:00
92ac138183 Make sure tray icon brings the window to front
Closes #14
2016-04-23 17:06:59 +02:00
b0fe8cf53e Rename TweetD*ck settings option on the website for clarity 2016-04-23 17:00:23 +02:00
016e403309 Fix LockManager to check process name before reporting, and cleanup Close/Dispose code
Closes #17
2016-04-23 16:51:11 +02:00
4cef0fb60d Fix clipboard text formatting
Closes #19
2016-04-23 16:29:51 +02:00
d53eff6043 Update version to 1.1.1 2016-04-17 17:42:14 +02:00
f064912ac9 Prevent notifications from stealing focus from the client app 2016-04-17 17:42:00 +02:00
f9f0677da3 Fix broken pop-up notifications 2016-04-17 17:41:46 +02:00
16180fd5d6 Update version to 1.1 2016-04-17 16:49:54 +02:00
462aebb115 Fix notification height and sent DMs showing up in notifications 2016-04-17 16:49:49 +02:00
0cb3bd9cc6 Add Cef.Shutdown before running the updater 2016-04-17 16:49:12 +02:00
2ef4f28740 Move Update form labels to the left 2016-04-17 16:19:15 +02:00
b02fb0934f Add version tag to About form 2016-04-17 16:10:10 +02:00
de363c982f Add update downloader and installer 2016-04-17 16:06:56 +02:00
f0132f59e5 Add ControlExtensions.MoveToCenter 2016-04-17 15:44:04 +02:00
dc32285454 Add ControlExtensions with Form.InvokeSafe and ProgressBar.SetValueInstant 2016-04-17 12:49:53 +02:00
e170172870 Add BrowserUtils.GetFileNameFromUrl and use it in ContextMenuBase 2016-04-17 01:35:27 +02:00
eba47a8196 "Fix" RichTextLabel being a fucking idiot and not working with URLs properly
Closes #10
2016-04-17 00:48:11 +02:00
907543a7cf Add WIP update notifications, currently no downloading 2016-04-16 23:22:23 +02:00
e8dea023ac Rename links and references in code to match new repository setup 2016-04-16 16:38:46 +02:00
8cfb6ab4f5 Merge branch 'master' of https://github.com/chylex/TweetDuck 2016-04-16 16:26:34 +02:00
c64d58143e Rename the project and solution to TweetDck 2016-04-16 16:20:33 +02:00
991681e186 Rename LICENSE to LICENSE.md 2016-04-16 16:16:30 +02:00
3c17c36f4f Move log file path to a separate property and make sure it always has the correct path 2016-04-16 14:39:48 +02:00
707b4b4ba2 Update the example notification (change my username) 2016-04-16 14:25:29 +02:00
413c7564aa Add VC++ 2013 redist libraries 2016-04-16 14:10:40 +02:00
453bf2dd82 Fix notifications removing DM contents 2016-04-16 13:56:29 +02:00
5597d2aed0 Ignore notifications with 0 characters 2016-04-16 03:03:48 +02:00
3c43211b25 Make sure ScriptLoader uses correct root path 2016-04-16 02:02:10 +02:00
ee87841ec2 Open browser when clicking on a "gif" (actually mp4) 2016-04-15 23:24:21 +02:00
9e5a39e9fc Add Save image as... option to context menu 2016-04-15 23:04:28 +02:00
8c21011ac7 Add BrowserUtils with header getters and OpenExternalBrowser method 2016-04-15 22:42:35 +02:00
5f5013f021 Add ContextMenuBase that handles links and media (open in browser, copy url) 2016-04-15 18:44:48 +02:00
fe093475dc Rename ContextMenuHandler to ContextMenuBrowser and add ContextMenuNotification 2016-04-15 17:30:33 +02:00
1c4e03ebea Make the notification timer config affect example notification, and fix its height 2016-04-15 16:05:09 +02:00
860b740db9 Add upgrade mechanism for config file 2016-04-15 16:02:17 +02:00
bd54da85a8 Add a Display Notification Timer option 2016-04-15 15:57:22 +02:00
86165b3529 Add Minimize to Tray option and improve window state and position saving 2016-04-15 15:06:42 +02:00
09d028a3af Fix minimizing issues again but properly 2016-04-15 14:39:38 +02:00
1cb261cb6f Merge branch 'master' of https://github.com/chylex/TweetDick 2016-04-15 14:35:14 +02:00
82934878cc Fix minimizing causing issues with saved window position 2016-04-15 14:35:10 +02:00
996c460f57 Create README.md 2016-04-15 14:05:45 +02:00
33e704f1ab Add support for loading config files across all TweetD*ck variations 2016-04-15 13:23:59 +02:00
2c3849bc43 Change namespace to TweetDck 2016-04-15 13:23:40 +02:00
48 changed files with 1661 additions and 426 deletions

View File

@@ -3,7 +3,7 @@ using System.Diagnostics;
using System.IO; using System.IO;
using System.Threading; using System.Threading;
namespace TweetDick.Configuration{ namespace TweetDck.Configuration{
class LockManager{ class LockManager{
private readonly string file; private readonly string file;
private FileStream lockStream; private FileStream lockStream;
@@ -54,7 +54,15 @@ namespace TweetDick.Configuration{
int pid = BitConverter.ToInt32(bytes,0); int pid = BitConverter.ToInt32(bytes,0);
try{ try{
lockingProcess = Process.GetProcessById(pid); Process foundProcess = Process.GetProcessById(pid);
using(Process currentProcess = Process.GetCurrentProcess()){
if (foundProcess.ProcessName == currentProcess.ProcessName){
lockingProcess = foundProcess;
}
currentProcess.Close();
}
}catch(ArgumentException){} }catch(ArgumentException){}
return lockingProcess == null && CreateLockFile(); return lockingProcess == null && CreateLockFile();
@@ -76,7 +84,6 @@ namespace TweetDick.Configuration{
public void Unlock(){ public void Unlock(){
if (lockStream != null){ if (lockStream != null){
lockStream.Close();
lockStream.Dispose(); lockStream.Dispose();
File.Delete(file); File.Delete(file);
@@ -96,7 +103,7 @@ namespace TweetDick.Configuration{
} }
if (lockingProcess.HasExited){ if (lockingProcess.HasExited){
lockingProcess.Close(); lockingProcess.Dispose();
lockingProcess = null; lockingProcess = null;
return true; return true;
} }

View File

@@ -3,13 +3,17 @@ using System.Drawing;
using System.IO; using System.IO;
using System.Runtime.Serialization; using System.Runtime.Serialization;
using System.Runtime.Serialization.Formatters.Binary; using System.Runtime.Serialization.Formatters.Binary;
using System.Windows.Forms; using TweetDck.Core;
using TweetDick.Core.Handling; using TweetDck.Core.Handling;
namespace TweetDick.Configuration{ namespace TweetDck.Configuration{
[Serializable] [Serializable]
sealed class UserConfig{ sealed class UserConfig{
private static readonly IFormatter Formatter = new BinaryFormatter(); private static readonly IFormatter Formatter = new BinaryFormatter(){
Binder = new SerializationCompatibilityHandler()
};
private const int CurrentFileVersion = 1;
// START OF CONFIGURATION // START OF CONFIGURATION
@@ -19,6 +23,7 @@ namespace TweetDick.Configuration{
public bool IsMaximized { get; set; } public bool IsMaximized { get; set; }
public Point WindowLocation { get; set; } public Point WindowLocation { get; set; }
public Size WindowSize { get; set; } public Size WindowSize { get; set; }
public bool DisplayNotificationTimer { get; set; }
public TweetNotification.Duration NotificationDuration { get; set; } public TweetNotification.Duration NotificationDuration { get; set; }
public TweetNotification.Position NotificationPosition { get; set; } public TweetNotification.Position NotificationPosition { get; set; }
@@ -26,6 +31,9 @@ namespace TweetDick.Configuration{
public int NotificationEdgeDistance { get; set; } public int NotificationEdgeDistance { get; set; }
public int NotificationDisplay { get; set; } public int NotificationDisplay { get; set; }
public bool EnableUpdateCheck { get; set; }
public string DismissedUpdate { get; set; }
public bool IsCustomWindowLocationSet{ public bool IsCustomWindowLocationSet{
get{ get{
return WindowLocation.X != -32000 && WindowLocation.X != 32000; return WindowLocation.X != -32000 && WindowLocation.X != 32000;
@@ -37,21 +45,82 @@ namespace TweetDick.Configuration{
return CustomNotificationPosition.X != -32000 && CustomNotificationPosition.X != 32000; return CustomNotificationPosition.X != -32000 && CustomNotificationPosition.X != 32000;
} }
} }
public bool MuteNotifications{
get{
return muteNotifications;
}
set{
if (muteNotifications == value)return;
muteNotifications = value;
if (MuteToggled != null){
MuteToggled(this,new EventArgs());
}
}
}
public TrayIcon.Behavior TrayBehavior{
get{
return trayBehavior;
}
set{
if (trayBehavior == value)return;
trayBehavior = value;
if (TrayBehaviorChanged != null){
TrayBehaviorChanged(this,new EventArgs());
}
}
}
// END OF CONFIGURATION // END OF CONFIGURATION
[field:NonSerialized]
public event EventHandler MuteToggled;
[field:NonSerialized]
public event EventHandler TrayBehaviorChanged;
[NonSerialized] [NonSerialized]
private string file; private string file;
private int fileVersion;
private bool muteNotifications;
private TrayIcon.Behavior trayBehavior;
private UserConfig(string file){ private UserConfig(string file){
this.file = file; this.file = file;
IsMaximized = true; IsMaximized = true;
DisplayNotificationTimer = true;
WindowLocation = new Point(-32000,-32000); WindowLocation = new Point(-32000,-32000);
NotificationDuration = TweetNotification.Duration.Medium; NotificationDuration = TweetNotification.Duration.Medium;
NotificationPosition = TweetNotification.Position.TopRight; NotificationPosition = TweetNotification.Position.TopRight;
CustomNotificationPosition = new Point(-32000,-32000); CustomNotificationPosition = new Point(-32000,-32000);
NotificationEdgeDistance = 8; NotificationEdgeDistance = 8;
EnableUpdateCheck = true;
}
private void UpgradeFile(){
if (fileVersion == CurrentFileVersion){
return;
}
// if outdated, cycle through all versions
if (fileVersion == 0){
DisplayNotificationTimer = true;
EnableUpdateCheck = true;
++fileVersion;
}
// update the version
fileVersion = CurrentFileVersion;
Save();
} }
public bool Save(){ public bool Save(){
@@ -89,6 +158,10 @@ namespace TweetDick.Configuration{
} }
} }
if (config != null){
config.UpgradeFile();
}
break; break;
}catch(FileNotFoundException){ }catch(FileNotFoundException){
}catch(Exception e){ }catch(Exception e){
@@ -102,5 +175,18 @@ namespace TweetDick.Configuration{
private static string GetBackupFile(string file){ private static string GetBackupFile(string file){
return file+".bak"; return file+".bak";
} }
private class SerializationCompatibilityHandler : SerializationBinder{
public override Type BindToType(string assemblyName, string typeName){
#if DUCK
assemblyName = assemblyName.Replace("TweetDick","TweetDuck");
#else
assemblyName = assemblyName.Replace("TweetDuck","TweetDick");
#endif
typeName = typeName.Replace("TweetDick","TweetDck");
return Type.GetType(string.Format("{0}, {1}",typeName,assemblyName));
}
}
} }
} }

View File

@@ -4,4 +4,5 @@
<package id="cef.redist.x86" version="3.2623.1396" targetFramework="net40-Client" /> <package id="cef.redist.x86" version="3.2623.1396" targetFramework="net40-Client" />
<package id="CefSharp.Common" version="49.0.0-pre02" targetFramework="net40-Client" /> <package id="CefSharp.Common" version="49.0.0-pre02" targetFramework="net40-Client" />
<package id="CefSharp.WinForms" version="49.0.0-pre02" targetFramework="net40-Client" /> <package id="CefSharp.WinForms" version="49.0.0-pre02" targetFramework="net40-Client" />
<package id="Microsoft.VC120.CRT.JetBrains" version="12.0.21005.2" targetFramework="net40-Client" />
</packages> </packages>

View File

@@ -0,0 +1,32 @@
using System;
using System.Drawing;
using System.Windows.Forms;
namespace TweetDck.Core.Controls{
static class ControlExtensions{
public static void InvokeSafe(this Form form, Action func){
if (form.InvokeRequired){
form.Invoke(func);
}
else{
func();
}
}
public static void MoveToCenter(this Form targetForm, Form parentForm){
targetForm.Location = new Point(parentForm.Location.X+parentForm.Width/2-targetForm.Width/2,parentForm.Location.Y+parentForm.Height/2-targetForm.Height/2);
}
public static void SetValueInstant(this ProgressBar bar, int value){
if (value == bar.Maximum){
bar.Value = value;
bar.Value = value-1;
bar.Value = value;
}
else{
bar.Value = value+1;
bar.Value = value;
}
}
}
}

View File

@@ -1,4 +1,4 @@
namespace TweetDick.Core.Controls { namespace TweetDck.Core.Controls {
partial class FlatProgressBar { partial class FlatProgressBar {
/// <summary> /// <summary>
/// Required designer variable. /// Required designer variable.

View File

@@ -1,7 +1,7 @@
using System.Drawing; using System.Drawing;
using System.Windows.Forms; using System.Windows.Forms;
namespace TweetDick.Core.Controls{ namespace TweetDck.Core.Controls{
public partial class FlatProgressBar : ProgressBar{ public partial class FlatProgressBar : ProgressBar{
private SolidBrush brush; private SolidBrush brush;
@@ -11,15 +11,7 @@ namespace TweetDick.Core.Controls{
} }
public void SetValueInstant(int value){ public void SetValueInstant(int value){
if (value == Maximum){ ControlExtensions.SetValueInstant(this,value);
Value = value;
Value = value-1;
Value = value;
}
else{
Value = value+1;
Value = value;
}
} }
protected override void OnPaint(PaintEventArgs e){ protected override void OnPaint(PaintEventArgs e){

View File

@@ -1,4 +1,4 @@
namespace TweetDick.Core.Controls { namespace TweetDck.Core.Controls {
partial class RichTextLabel { partial class RichTextLabel {
/// <summary> /// <summary>
/// Required designer variable. /// Required designer variable.

View File

@@ -1,7 +1,7 @@
using System; using System;
using System.Windows.Forms; using System.Windows.Forms;
namespace TweetDick.Core.Controls{ namespace TweetDck.Core.Controls{
public partial class RichTextLabel : RichTextBox{ public partial class RichTextLabel : RichTextBox{
/// <summary> /// <summary>
/// Wraps the body of a RTF formatted string with default tags and formatting. /// Wraps the body of a RTF formatted string with default tags and formatting.

View File

@@ -1,4 +1,4 @@
namespace TweetDick.Core { namespace TweetDck.Core {
sealed partial class FormBrowser { sealed partial class FormBrowser {
/// <summary> /// <summary>
/// Required designer variable. /// Required designer variable.
@@ -23,23 +23,32 @@
/// 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() {
System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(FormBrowser)); this.trayIcon = new TweetDck.Core.TrayIcon();
this.SuspendLayout(); this.SuspendLayout();
// //
// trayIcon
//
this.trayIcon.Visible = false;
//
// FormBrowser // FormBrowser
// //
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
this.Icon = TweetDick.Properties.Resources.icon; this.ClientSize = new System.Drawing.Size(284, 262);
this.Icon = ((System.Drawing.Icon)(TweetDck.Properties.Resources.ResourceManager.GetObject("icon")));
this.Location = new System.Drawing.Point(-32000, -32000); this.Location = new System.Drawing.Point(-32000, -32000);
this.Name = "FormBrowser"; this.Name = "FormBrowser";
this.StartPosition = System.Windows.Forms.FormStartPosition.Manual; this.StartPosition = System.Windows.Forms.FormStartPosition.Manual;
this.FormClosing += new System.Windows.Forms.FormClosingEventHandler(this.FormBrowser_FormClosing);
this.ResizeEnd += new System.EventHandler(this.FormBrowser_ResizeEnd); this.ResizeEnd += new System.EventHandler(this.FormBrowser_ResizeEnd);
this.Resize += new System.EventHandler(this.FormBrowser_Resize);
this.ResumeLayout(false); this.ResumeLayout(false);
} }
#endregion #endregion
private TrayIcon trayIcon;
} }
} }

View File

@@ -1,15 +1,17 @@
using System.Windows.Forms; using System;
using CefSharp.WinForms;
using System;
using System.Linq; using System.Linq;
using TweetDick.Configuration; using System.Windows.Forms;
using CefSharp; using CefSharp;
using TweetDick.Core.Handling; using CefSharp.WinForms;
using TweetDick.Core.Other; using TweetDck.Configuration;
using System.Drawing; using TweetDck.Core.Handling;
using TweetDick.Resources; using TweetDck.Core.Other;
using TweetDck.Resources;
using TweetDck.Core.Utils;
using TweetDck.Core.Controls;
using System.ComponentModel;
namespace TweetDick.Core{ namespace TweetDck.Core{
sealed partial class FormBrowser : Form{ sealed partial class FormBrowser : Form{
private static UserConfig Config{ private static UserConfig Config{
get{ get{
@@ -17,6 +19,8 @@ namespace TweetDick.Core{
} }
} }
public string UpdateInstallerPath { get; private set; }
private readonly ChromiumWebBrowser browser; private readonly ChromiumWebBrowser browser;
private readonly TweetDeckBridge bridge; private readonly TweetDeckBridge bridge;
private readonly FormNotification notification; private readonly FormNotification notification;
@@ -25,6 +29,8 @@ namespace TweetDick.Core{
private FormAbout currentFormAbout; private FormAbout currentFormAbout;
private bool isLoaded; private bool isLoaded;
private FormWindowState prevState;
public FormBrowser(){ public FormBrowser(){
InitializeComponent(); InitializeComponent();
@@ -32,7 +38,7 @@ namespace TweetDick.Core{
bridge = new TweetDeckBridge(this); bridge = new TweetDeckBridge(this);
browser = new ChromiumWebBrowser("https://tweetdeck.twitter.com/"){ MenuHandler = new ContextMenuHandler(this) }; browser = new ChromiumWebBrowser("https://tweetdeck.twitter.com/"){ MenuHandler = new ContextMenuBrowser(this) };
browser.LoadingStateChanged += Browser_LoadingStateChanged; browser.LoadingStateChanged += Browser_LoadingStateChanged;
browser.FrameLoadEnd += Browser_FrameLoadEnd; browser.FrameLoadEnd += Browser_FrameLoadEnd;
browser.RegisterJsObject("$TD",bridge); browser.RegisterJsObject("$TD",bridge);
@@ -41,22 +47,19 @@ namespace TweetDick.Core{
Disposed += (sender, args) => browser.Dispose(); Disposed += (sender, args) => browser.Dispose();
trayIcon.ClickRestore += trayIcon_ClickRestore;
trayIcon.ClickClose += trayIcon_ClickClose;
Config.TrayBehaviorChanged += Config_TrayBehaviorChanged;
UpdateTrayIcon();
notification = new FormNotification(this,bridge,true){ CanMoveWindow = () => false }; notification = new FormNotification(this,bridge,true){ CanMoveWindow = () => false };
notification.Show(); notification.Show();
} }
protected override void WndProc(ref Message m){
FormWindowState prevState = WindowState;
base.WndProc(ref m);
if (prevState != WindowState && m.Msg == 0x0014){ // WM_ERASEBKGND
FormBrowser_WindowStateChanged(this,new EventArgs());
}
}
private void ShowChildForm(Form form){ private void ShowChildForm(Form form){
form.Show(this); form.Show(this);
form.Location = new Point(Location.X+Width/2-form.Width/2,Location.Y+Height/2-form.Height/2); form.MoveToCenter(this);
} }
// window setup // window setup
@@ -74,9 +77,14 @@ namespace TweetDick.Core{
WindowState = FormWindowState.Maximized; WindowState = FormWindowState.Maximized;
} }
prevState = WindowState;
isLoaded = true; isLoaded = true;
} }
private void UpdateTrayIcon(){
trayIcon.Visible = Config.TrayBehavior != TrayIcon.Behavior.Disabled;
}
// active event handlers // active event handlers
private void Browser_LoadingStateChanged(object sender, LoadingStateChangedEventArgs e){ private void Browser_LoadingStateChanged(object sender, LoadingStateChangedEventArgs e){
@@ -88,38 +96,80 @@ namespace TweetDick.Core{
private void Browser_FrameLoadEnd(object sender, FrameLoadEndEventArgs e){ private void Browser_FrameLoadEnd(object sender, FrameLoadEndEventArgs e){
if (e.Frame.IsMain){ if (e.Frame.IsMain){
string js = ScriptLoader.LoadResource("code.js"); foreach(string js in ScriptLoader.LoadResources("code.js","update.js").Where(js => js != null)){
if (js != null){
browser.ExecuteScriptAsync(js); browser.ExecuteScriptAsync(js);
} }
} }
} }
private void FormBrowser_Resize(object sender, EventArgs e){
if (!isLoaded)return;
if (WindowState != prevState){
prevState = WindowState;
if (WindowState == FormWindowState.Minimized){
if (Config.TrayBehavior == TrayIcon.Behavior.MinimizeToTray){
Hide(); // hides taskbar too?! welp that works I guess
}
}
else{
FormBrowser_ResizeEnd(sender,e);
}
}
}
private void FormBrowser_ResizeEnd(object sender, EventArgs e){ // also triggers when the window moves private void FormBrowser_ResizeEnd(object sender, EventArgs e){ // also triggers when the window moves
if (!isLoaded)return; if (!isLoaded)return;
Config.WindowLocation = Location; if (Location.X != -32000){
Config.WindowSize = Size; Config.IsMaximized = WindowState == FormWindowState.Maximized;
Config.Save();
if (WindowState == FormWindowState.Normal){
Config.WindowLocation = Location;
Config.WindowSize = Size;
}
Config.Save();
}
} }
private void FormBrowser_WindowStateChanged(object sender, EventArgs e){ private void FormBrowser_FormClosing(object sender, FormClosingEventArgs e){
if (!isLoaded)return; if (!isLoaded)return;
Config.IsMaximized = WindowState != FormWindowState.Normal; if (Config.TrayBehavior == TrayIcon.Behavior.CloseToTray && trayIcon.Visible && e.CloseReason == CloseReason.UserClosing){
FormBrowser_ResizeEnd(sender,e); Hide(); // hides taskbar too?! welp that works I guess
e.Cancel = true;
}
}
private void Config_TrayBehaviorChanged(object sender, EventArgs e){
if (!isLoaded)return;
UpdateTrayIcon();
}
private void trayIcon_ClickRestore(object sender, EventArgs e){
if (!isLoaded)return;
isLoaded = false;
Show();
SetupWindow();
Activate();
UpdateTrayIcon();
}
private void trayIcon_ClickClose(object sender, EventArgs e){
if (!isLoaded)return;
trayIcon.Visible = false; // checked in FormClosing event
Close();
} }
// callback handlers // callback handlers
public void InvokeSafe(Action func){ public void InvokeSafe(Action func){
if (InvokeRequired){ ControlExtensions.InvokeSafe(this,func);
Invoke(func);
}
else{
func();
}
} }
public void OpenSettings(){ public void OpenSettings(){
@@ -127,8 +177,21 @@ namespace TweetDick.Core{
currentFormSettings.BringToFront(); currentFormSettings.BringToFront();
} }
else{ else{
bool prevEnableUpdateCheck = Config.EnableUpdateCheck;
currentFormSettings = new FormSettings(this); currentFormSettings = new FormSettings(this);
currentFormSettings.FormClosed += (sender, args) => currentFormSettings = null;
currentFormSettings.FormClosed += (sender, args) => {
currentFormSettings = null;
if (!prevEnableUpdateCheck && Config.EnableUpdateCheck){
Config.DismissedUpdate = string.Empty;
Config.Save();
browser.ExecuteScriptAsync("TDGF_runUpdateCheck",new object[0]);
}
};
ShowChildForm(currentFormSettings); ShowChildForm(currentFormSettings);
} }
} }
@@ -147,5 +210,28 @@ namespace TweetDick.Core{
public void OnTweetPopup(TweetNotification tweet){ public void OnTweetPopup(TweetNotification tweet){
notification.ShowNotification(tweet); notification.ShowNotification(tweet);
} }
public void OnTweetSound(){
}
public void BeginUpdateProcess(string versionTag, string downloadUrl){
Hide();
FormUpdateDownload downloadForm = new FormUpdateDownload(new UpdateInfo(versionTag,downloadUrl));
downloadForm.MoveToCenter(this);
downloadForm.ShowDialog();
if (downloadForm.UpdateStatus == FormUpdateDownload.Status.Succeeded){
UpdateInstallerPath = downloadForm.InstallerPath;
Close();
}
else if (downloadForm.UpdateStatus == FormUpdateDownload.Status.Manual){
Close();
}
else{
Show();
}
}
} }
} }

View File

@@ -1,4 +1,6 @@
namespace TweetDick.Core { using TweetDck.Core.Controls;
namespace TweetDck.Core {
sealed partial class FormNotification { sealed partial class FormNotification {
/// <summary> /// <summary>
/// Required designer variable. /// Required designer variable.
@@ -26,7 +28,7 @@
this.components = new System.ComponentModel.Container(); this.components = new System.ComponentModel.Container();
this.panelBrowser = new System.Windows.Forms.Panel(); this.panelBrowser = new System.Windows.Forms.Panel();
this.timerProgress = new System.Windows.Forms.Timer(this.components); this.timerProgress = new System.Windows.Forms.Timer(this.components);
this.progressBarTimer = new TweetDick.Core.Controls.FlatProgressBar(); this.progressBarTimer = new TweetDck.Core.Controls.FlatProgressBar();
this.SuspendLayout(); this.SuspendLayout();
// //
// panelBrowser // panelBrowser
@@ -66,6 +68,8 @@
this.Controls.Add(this.panelBrowser); this.Controls.Add(this.panelBrowser);
this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedToolWindow; this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedToolWindow;
this.Location = new System.Drawing.Point(-32000, -32000); this.Location = new System.Drawing.Point(-32000, -32000);
this.MaximizeBox = false;
this.MinimizeBox = false;
this.Name = "FormNotification"; this.Name = "FormNotification";
this.ShowInTaskbar = false; this.ShowInTaskbar = false;
this.StartPosition = System.Windows.Forms.FormStartPosition.Manual; this.StartPosition = System.Windows.Forms.FormStartPosition.Manual;

View File

@@ -1,14 +1,14 @@
using System.Windows.Forms; using System;
using System.Collections.Generic;
using System.Drawing;
using System.Windows.Forms;
using CefSharp; using CefSharp;
using CefSharp.WinForms; using CefSharp.WinForms;
using System.Drawing; using TweetDck.Configuration;
using System; using TweetDck.Core.Handling;
using System.Collections.Generic; using TweetDck.Resources;
using TweetDick.Core.Handling;
using TweetDick.Configuration;
using TweetDick.Resources;
namespace TweetDick.Core{ namespace TweetDck.Core{
sealed partial class FormNotification : Form{ sealed partial class FormNotification : Form{
public Func<bool> CanMoveWindow = () => true; public Func<bool> CanMoveWindow = () => true;
@@ -21,6 +21,12 @@ namespace TweetDick.Core{
private readonly string notificationJS; private readonly string notificationJS;
protected override bool ShowWithoutActivation{
get{
return true;
}
}
public FormNotification(Form owner, TweetDeckBridge bridge, bool autoHide){ public FormNotification(Form owner, TweetDeckBridge bridge, bool autoHide){
InitializeComponent(); InitializeComponent();
@@ -33,7 +39,7 @@ namespace TweetDick.Core{
notificationJS = ScriptLoader.LoadResource("notification.js"); notificationJS = ScriptLoader.LoadResource("notification.js");
browser = new ChromiumWebBrowser("about:blank"){ MenuHandler = new MenuHandlerEmpty() }; browser = new ChromiumWebBrowser("about:blank"){ MenuHandler = new ContextMenuNotification() };
browser.FrameLoadEnd += Browser_FrameLoadEnd; browser.FrameLoadEnd += Browser_FrameLoadEnd;
if (bridge != null){ if (bridge != null){
@@ -42,17 +48,16 @@ namespace TweetDick.Core{
panelBrowser.Controls.Add(browser); panelBrowser.Controls.Add(browser);
if (autoHide){
Program.UserConfig.MuteToggled += Config_MuteToggled;
Disposed += (sender, args) => Program.UserConfig.MuteToggled -= Config_MuteToggled;
}
Disposed += (sender, args) => browser.Dispose(); Disposed += (sender, args) => browser.Dispose();
} }
public FormNotification(Form owner, bool autoHide) : this(owner,null,autoHide){} public FormNotification(Form owner, bool autoHide) : this(owner,null,autoHide){}
private void Browser_FrameLoadEnd(object sender, FrameLoadEndEventArgs e){
if (e.Frame.IsMain && notificationJS != null){
browser.ExecuteScriptAsync(notificationJS);
}
}
protected override void WndProc(ref Message m){ protected override void WndProc(ref Message m){
if (m.Msg == 0x0112 && (m.WParam.ToInt32() & 0xFFF0) == 0xF010 && !CanMoveWindow()){ // WM_SYSCOMMAND, SC_MOVE if (m.Msg == 0x0112 && (m.WParam.ToInt32() & 0xFFF0) == 0xF010 && !CanMoveWindow()){ // WM_SYSCOMMAND, SC_MOVE
return; return;
@@ -61,24 +66,77 @@ namespace TweetDick.Core{
base.WndProc(ref m); base.WndProc(ref m);
} }
public void ShowNotification(TweetNotification notification){ // event handlers
MoveToVisibleLocation();
tweetQueue.Enqueue(notification); private void timerHideProgress_Tick(object sender, EventArgs e){
if (Bounds.Contains(Cursor.Position))return;
if (!timerProgress.Enabled){ timeLeft -= timerProgress.Interval;
LoadNextNotification(); progressBarTimer.SetValueInstant((int)Math.Min(1000,Math.Round(1050.0*(totalTime-timeLeft)/totalTime)));
if (timeLeft <= 0){
if (tweetQueue.Count > 0){
LoadNextNotification();
}
else if (autoHide){
HideNotification();
}
} }
} }
public void ShowNotificationForSettings(bool resetAnimation){ private void Config_MuteToggled(object sender, EventArgs e){
if (Program.UserConfig.MuteNotifications){
HideNotification();
}
else{
if (tweetQueue.Count > 0){
MoveToVisibleLocation();
LoadNextNotification();
}
}
}
private void Browser_FrameLoadEnd(object sender, FrameLoadEndEventArgs e){
if (e.Frame.IsMain && notificationJS != null && browser.Address != "about:blank"){
browser.ExecuteScriptAsync(notificationJS);
}
}
private void FormNotification_FormClosing(object sender, FormClosingEventArgs e){
if (e.CloseReason == CloseReason.UserClosing){
HideNotification();
tweetQueue.Clear();
e.Cancel = true;
}
}
// notification methods
public void ShowNotification(TweetNotification notification){
if (Program.UserConfig.MuteNotifications){
tweetQueue.Enqueue(notification);
}
else{
MoveToVisibleLocation();
tweetQueue.Enqueue(notification);
UpdateTitle();
if (!timerProgress.Enabled){
LoadNextNotification();
}
}
}
public void ShowNotificationForSettings(bool reset){
if (browser.Address == "about:blank"){ if (browser.Address == "about:blank"){
browser.Load("about:blank"); // required, otherwise shit breaks browser.Load("about:blank"); // required, otherwise shit breaks
browser.LoadHtml(TweetNotification.ExampleTweet.GenerateHtml(),"http://tweetdeck.twitter.com/"); reset = true;
resetAnimation = true;
} }
if (reset){
browser.LoadHtml(TweetNotification.ExampleTweet.GenerateHtml(),"http://tweetdeck.twitter.com/");
if (resetAnimation){
totalTime = timeLeft = TweetNotification.ExampleTweet.GetDisplayDuration(Program.UserConfig.NotificationDuration); totalTime = timeLeft = TweetNotification.ExampleTweet.GetDisplayDuration(Program.UserConfig.NotificationDuration);
timerProgress.Start(); timerProgress.Start();
} }
@@ -89,7 +147,6 @@ namespace TweetDick.Core{
public void HideNotification(){ public void HideNotification(){
browser.LoadHtml("","about:blank"); browser.LoadHtml("","about:blank");
Location = new Point(-32000,-32000); Location = new Point(-32000,-32000);
TopMost = false;
timerProgress.Stop(); timerProgress.Stop();
} }
@@ -105,12 +162,25 @@ namespace TweetDick.Core{
totalTime = timeLeft = tweet.GetDisplayDuration(Program.UserConfig.NotificationDuration); totalTime = timeLeft = tweet.GetDisplayDuration(Program.UserConfig.NotificationDuration);
timerProgress.Stop(); timerProgress.Stop();
timerProgress.Start(); timerProgress.Start();
UpdateTitle();
} }
private void MoveToVisibleLocation(){ private void MoveToVisibleLocation(){
bool needsReactivating = Location.X == -32000;
UserConfig config = Program.UserConfig; UserConfig config = Program.UserConfig;
Screen screen = Screen.FromControl(owner); Screen screen = Screen.FromControl(owner);
if (config.DisplayNotificationTimer){
ClientSize = new Size(ClientSize.Width,122);
progressBarTimer.Visible = true;
}
else{
ClientSize = new Size(ClientSize.Width,118);
progressBarTimer.Visible = false;
}
if (config.NotificationDisplay > 0 && config.NotificationDisplay <= Screen.AllScreens.Length){ if (config.NotificationDisplay > 0 && config.NotificationDisplay <= Screen.AllScreens.Length){
screen = Screen.AllScreens[config.NotificationDisplay-1]; screen = Screen.AllScreens[config.NotificationDisplay-1];
} }
@@ -144,47 +214,13 @@ namespace TweetDick.Core{
break; break;
} }
TopMost = true; if (needsReactivating){
} Program.SetWindowPos(Handle.ToInt32(),-1,Left,Top,Width,Height,0x0010); // HWND_TOPMOST, SWP_NOACTIVATE
private void timerHideProgress_Tick(object sender, EventArgs e){
if (Bounds.Contains(Cursor.Position))return;
timeLeft -= timerProgress.Interval;
progressBarTimer.SetValueInstant((int)Math.Min(1000,Math.Round(1050.0*(totalTime-timeLeft)/totalTime)));
if (timeLeft <= 0){
if (tweetQueue.Count > 0){
LoadNextNotification();
}
else if (autoHide){
HideNotification();
}
} }
} }
private void FormNotification_FormClosing(object sender, FormClosingEventArgs e){ private void UpdateTitle(){
if (e.CloseReason == CloseReason.UserClosing){ Text = tweetQueue.Count > 0 ? Program.BrandName+" ("+tweetQueue.Count+" more left)" : Program.BrandName;
HideNotification();
tweetQueue.Clear();
e.Cancel = true;
}
}
private class MenuHandlerEmpty : IContextMenuHandler{
public void OnBeforeContextMenu(IWebBrowser browserControl, IBrowser browser, IFrame frame, IContextMenuParams parameters, IMenuModel model){
model.Clear();
}
public bool OnContextMenuCommand(IWebBrowser browserControl, IBrowser browser, IFrame frame, IContextMenuParams parameters, CefMenuCommand commandId, CefEventFlags eventFlags){
return false;
}
public void OnContextMenuDismissed(IWebBrowser browserControl, IBrowser browser, IFrame frame){}
public bool RunContextMenu(IWebBrowser browserControl, IBrowser browser, IFrame frame, IContextMenuParams parameters, IMenuModel model, IRunContextMenuCallback callback){
return false;
}
} }
} }
} }

View File

@@ -0,0 +1,110 @@
using CefSharp;
using System.IO;
using System.Windows.Forms;
using TweetDck.Core.Utils;
namespace TweetDck.Core.Handling{
abstract class ContextMenuBase : IContextMenuHandler{
private const int MenuOpenUrlInBrowser = 26500;
private const int MenuCopyUrl = 26501;
private const int MenuOpenImageInBrowser = 26502;
private const int MenuSaveImage = 26503;
private const int MenuCopyImageUrl = 26504;
public virtual void OnBeforeContextMenu(IWebBrowser browserControl, IBrowser browser, IFrame frame, IContextMenuParams parameters, IMenuModel model){
RemoveSeparatorIfLast(model);
if (parameters.TypeFlags.HasFlag(ContextMenuType.Link) && !parameters.UnfilteredLinkUrl.EndsWith("tweetdeck.twitter.com/#")){
model.AddItem((CefMenuCommand)MenuOpenUrlInBrowser,"Open in browser");
model.AddItem((CefMenuCommand)MenuCopyUrl,"Copy link address");
model.AddSeparator();
}
if (parameters.TypeFlags.HasFlag(ContextMenuType.Media) && parameters.HasImageContents){
model.AddItem((CefMenuCommand)MenuOpenImageInBrowser,"Open image in browser");
model.AddItem((CefMenuCommand)MenuSaveImage,"Save image as...");
model.AddItem((CefMenuCommand)MenuCopyImageUrl,"Copy image URL");
model.AddSeparator();
}
}
public virtual bool OnContextMenuCommand(IWebBrowser browserControl, IBrowser browser, IFrame frame, IContextMenuParams parameters, CefMenuCommand commandId, CefEventFlags eventFlags){
switch((int)commandId){
case MenuOpenUrlInBrowser:
BrowserUtils.OpenExternalBrowser(parameters.LinkUrl);
break;
case MenuCopyUrl:
Clipboard.SetText(string.IsNullOrEmpty(TweetDeckBridge.LastRightClickedLink) ? parameters.UnfilteredLinkUrl : TweetDeckBridge.LastRightClickedLink,TextDataFormat.UnicodeText);
break;
case MenuOpenImageInBrowser:
BrowserUtils.OpenExternalBrowser(parameters.SourceUrl);
break;
case MenuSaveImage:
string fileName = GetImageFileName(parameters.SourceUrl);
string extension = Path.GetExtension(fileName);
string saveTarget;
using(SaveFileDialog dialog = new SaveFileDialog{
AutoUpgradeEnabled = true,
OverwritePrompt = true,
Title = "Save image",
FileName = fileName,
Filter = "Image ("+(string.IsNullOrEmpty(extension) ? "unknown" : extension)+")|*.*"
}){
saveTarget = dialog.ShowDialog() == DialogResult.OK ? dialog.FileName : null;
}
if (saveTarget != null){
BrowserUtils.DownloadFileAsync(parameters.SourceUrl,saveTarget,ex => {
MessageBox.Show("An error occurred while downloading the image: "+ex.Message,Program.BrandName+" Has Failed :(",MessageBoxButtons.OK,MessageBoxIcon.Error);
});
}
break;
case MenuCopyImageUrl:
Clipboard.SetText(parameters.SourceUrl,TextDataFormat.UnicodeText);
break;
}
return false;
}
public virtual void OnContextMenuDismissed(IWebBrowser browserControl, IBrowser browser, IFrame frame){}
public virtual bool RunContextMenu(IWebBrowser browserControl, IBrowser browser, IFrame frame, IContextMenuParams parameters, IMenuModel model, IRunContextMenuCallback callback){
return false;
}
protected void RemoveSeparatorIfFirst(IMenuModel model){
if (model.Count > 0 && model.GetTypeAt(model.Count-1) == MenuItemType.Separator){
model.RemoveAt(model.Count-1);
}
}
protected void RemoveSeparatorIfLast(IMenuModel model){
if (model.Count > 0 && model.GetTypeAt(model.Count-1) == MenuItemType.Separator){
model.RemoveAt(model.Count-1);
}
}
private static string GetImageFileName(string url){
// twimg adds a colon after file extension
int dot = url.LastIndexOf('.');
if (dot != -1){
int colon = url.IndexOf(':',dot);
if (colon != -1){
url = url.Substring(0,colon);
}
}
// return file name
return BrowserUtils.GetFileNameFromUrl(url) ?? "unknown";
}
}
}

View File

@@ -0,0 +1,69 @@
using CefSharp;
namespace TweetDck.Core.Handling{
class ContextMenuBrowser : ContextMenuBase{
private const int MenuSettings = 26600;
private const int MenuAbout = 26601;
private const int MenuMute = 26602;
private readonly FormBrowser form;
public ContextMenuBrowser(FormBrowser form){
this.form = form;
}
public override void OnBeforeContextMenu(IWebBrowser browserControl, IBrowser browser, IFrame frame, IContextMenuParams parameters, IMenuModel model){
model.Remove(CefMenuCommand.Back);
model.Remove(CefMenuCommand.Forward);
model.Remove(CefMenuCommand.Print);
model.Remove(CefMenuCommand.ViewSource);
RemoveSeparatorIfFirst(model);
base.OnBeforeContextMenu(browserControl,browser,frame,parameters,model);
model.AddItem(CefMenuCommand.Reload,"Reload");
model.AddCheckItem((CefMenuCommand)MenuMute,"Mute Notifications");
model.SetChecked((CefMenuCommand)MenuMute,Program.UserConfig.MuteNotifications);
model.AddSeparator();
if (TweetNotification.IsReady){
model.AddItem((CefMenuCommand)MenuSettings,"Settings");
}
model.AddItem((CefMenuCommand)MenuAbout,"About "+Program.BrandName);
}
public override bool OnContextMenuCommand(IWebBrowser browserControl, IBrowser browser, IFrame frame, IContextMenuParams parameters, CefMenuCommand commandId, CefEventFlags eventFlags){
if (base.OnContextMenuCommand(browserControl,browser,frame,parameters,commandId,eventFlags)){
return true;
}
switch((int)commandId){
case MenuSettings:
form.InvokeSafe(() => {
form.OpenSettings();
});
return true;
case MenuAbout:
form.InvokeSafe(() => {
form.OpenAbout();
});
return true;
case MenuMute:
form.InvokeSafe(() => {
Program.UserConfig.MuteNotifications = !Program.UserConfig.MuteNotifications;
Program.UserConfig.Save();
});
return true;
}
return false;
}
}
}

View File

@@ -1,61 +0,0 @@
using CefSharp;
namespace TweetDick.Core.Handling{
class ContextMenuHandler : IContextMenuHandler{
private const int MenuSettings = 26500;
private const int MenuAbout = 26501;
private readonly FormBrowser form;
public ContextMenuHandler(FormBrowser form){
this.form = form;
}
public void OnBeforeContextMenu(IWebBrowser browserControl, IBrowser browser, IFrame frame, IContextMenuParams parameters, IMenuModel model){
model.Remove(CefMenuCommand.Back);
model.Remove(CefMenuCommand.Forward);
model.Remove(CefMenuCommand.Print);
model.Remove(CefMenuCommand.ViewSource);
if (model.Count > 0 && model.GetTypeAt(model.Count-1) == MenuItemType.Separator){
model.RemoveAt(model.Count-1);
}
model.AddItem(CefMenuCommand.Reload,"Reload");
model.AddSeparator();
if (TweetNotification.IsReady){
model.AddItem((CefMenuCommand)MenuSettings,"Settings");
model.AddSeparator();
}
model.AddItem((CefMenuCommand)MenuAbout,"About "+Program.BrandName);
}
public bool OnContextMenuCommand(IWebBrowser browserControl, IBrowser browser, IFrame frame, IContextMenuParams parameters, CefMenuCommand commandId, CefEventFlags eventFlags){
switch((int)commandId){
case MenuSettings:
form.InvokeSafe(() => {
form.OpenSettings();
});
return true;
case MenuAbout:
form.InvokeSafe(() => {
form.OpenAbout();
});
return true;
}
return false;
}
public void OnContextMenuDismissed(IWebBrowser browserControl, IBrowser browser, IFrame frame){}
public bool RunContextMenu(IWebBrowser browserControl, IBrowser browser, IFrame frame, IContextMenuParams parameters, IMenuModel model, IRunContextMenuCallback callback){
return false;
}
}
}

View File

@@ -0,0 +1,12 @@
using CefSharp;
namespace TweetDck.Core.Handling{
class ContextMenuNotification : ContextMenuBase{
public override void OnBeforeContextMenu(IWebBrowser browserControl, IBrowser browser, IFrame frame, IContextMenuParams parameters, IMenuModel model){
model.Clear();
base.OnBeforeContextMenu(browserControl,browser,frame,parameters,model);
RemoveSeparatorIfLast(model);
}
}
}

View File

@@ -1,7 +1,9 @@
using System.Diagnostics; using TweetDck.Core.Utils;
namespace TweetDick.Core.Handling{ namespace TweetDck.Core.Handling{
class TweetDeckBridge{ class TweetDeckBridge{
public static string LastRightClickedLink = string.Empty;
private readonly FormBrowser form; private readonly FormBrowser form;
public string BrandName{ public string BrandName{
@@ -10,6 +12,30 @@ namespace TweetDick.Core.Handling{
} }
} }
public string VersionTag{
get{
return Program.VersionTag;
}
}
public bool MuteNotifications{
get{
return Program.UserConfig.MuteNotifications;
}
}
public bool UpdateCheckEnabled{
get{
return Program.UserConfig.EnableUpdateCheck;
}
}
public string DismissedVersionTag{
get{
return Program.UserConfig.DismissedUpdate ?? string.Empty;
}
}
public TweetDeckBridge(FormBrowser form){ public TweetDeckBridge(FormBrowser form){
this.form = form; this.form = form;
} }
@@ -26,6 +52,12 @@ namespace TweetDick.Core.Handling{
}); });
} }
public void SetLastRightClickedLink(string link){
form.InvokeSafe(() => {
LastRightClickedLink = link;
});
}
public void OpenSettingsMenu(){ public void OpenSettingsMenu(){
form.InvokeSafe(() => { form.InvokeSafe(() => {
form.OpenSettings(); form.OpenSettings();
@@ -38,12 +70,31 @@ namespace TweetDick.Core.Handling{
}); });
} }
public void OnTweetSound(){
form.InvokeSafe(() => {
form.OnTweetSound();
});
}
public void OnUpdateAccepted(string versionTag, string downloadUrl){
form.InvokeSafe(() => {
form.BeginUpdateProcess(versionTag,downloadUrl);
});
}
public void OnUpdateDismissed(string versionTag){
form.InvokeSafe(() => {
Program.UserConfig.DismissedUpdate = versionTag;
Program.UserConfig.Save();
});
}
public void OpenBrowser(string url){ public void OpenBrowser(string url){
Process.Start(url); BrowserUtils.OpenExternalBrowser(url);
} }
public void Log(string data){ public void Log(string data){
Debug.WriteLine(data); System.Diagnostics.Debug.WriteLine(data);
} }
} }
} }

View File

@@ -1,7 +1,7 @@
using System; using System;
using System.Text; using System.Text;
namespace TweetDick.Core.Handling{ namespace TweetDck.Core.Handling{
sealed class TweetNotification{ sealed class TweetNotification{
private static string FontSizeClass { get; set; } private static string FontSizeClass { get; set; }
private static string HeadTag { get; set; } private static string HeadTag { get; set; }
@@ -17,10 +17,10 @@ namespace TweetDick.Core.Handling{
StringBuilder build = new StringBuilder(); StringBuilder build = new StringBuilder();
build.Append(@"<article><div class='js-stream-item-content item-box js-show-detail'><div class='js-tweet tweet'>"); build.Append(@"<article><div class='js-stream-item-content item-box js-show-detail'><div class='js-tweet tweet'>");
build.Append(@"<header class='tweet-header'>"); build.Append(@"<header class='tweet-header'>");
build.Append(@"<time class='tweet-timestamp js-timestamp pull-right txt-mute'><a target='_blank' rel='url' href='https://twitter.com/chylexMC' class='txt-small'>0s</a></time>"); build.Append(@"<time class='tweet-timestamp js-timestamp pull-right txt-mute'><a target='_blank' rel='url' href='https://twitter.com/chylexmc' class='txt-small'>0s</a></time>");
build.Append(@"<a target='_blank' rel='user' href='https://twitter.com/chylexMC' class='account-link link-complex block'>"); build.Append(@"<a target='_blank' rel='user' href='https://twitter.com/chylexmc' class='account-link link-complex block'>");
build.Append(@"<div class='obj-left item-img tweet-img'><img width='48' height='48' alt='chylexMC's avatar' src='https://pbs.twimg.com/profile_images/645532929930608642/J56NBJVY_normal.png' class='tweet-avatar avatar pull-right'></div>"); build.Append(@"<div class='obj-left item-img tweet-img'><img width='48' height='48' alt='chylexmc's avatar' src='https://pbs.twimg.com/profile_images/645532929930608642/J56NBJVY_normal.png' class='tweet-avatar avatar pull-right'></div>");
build.Append(@"<div class='nbfc'><span class='account-inline txt-ellipsis'><b class='fullname link-complex-target'>chylex</b> <span class='username txt-mute'>@chylexMC</span></span></div>"); build.Append(@"<div class='nbfc'><span class='account-inline txt-ellipsis'><b class='fullname link-complex-target'>chylex</b> <span class='username txt-mute'>@chylexmc</span></span></div>");
build.Append(@"</a>"); build.Append(@"</a>");
build.Append(@"</header>"); build.Append(@"</header>");
build.Append(@"<div class='tweet-body'><p class='js-tweet-text tweet-text with-linebreaks'>This is an example tweet, which lets you test the location and duration of popup notifications.</p></div>"); build.Append(@"<div class='tweet-body'><p class='js-tweet-text tweet-text with-linebreaks'>This is an example tweet, which lets you test the location and duration of popup notifications.</p></div>");
@@ -70,7 +70,7 @@ namespace TweetDick.Core.Handling{
public string GenerateHtml(){ public string GenerateHtml(){
StringBuilder build = new StringBuilder(); StringBuilder build = new StringBuilder();
build.Append("<!DOCTYPE html>"); build.Append("<!DOCTYPE html>");
build.Append("<html class='os-windows ").Append(FontSizeClass).Append("'>"); build.Append("<html class='os-windows txt-base-").Append(FontSizeClass).Append("'>");
build.Append("<head>").Append(HeadTag).Append("</head>"); build.Append("<head>").Append(HeadTag).Append("</head>");
build.Append("<body class='hearty'><div class='app-columns-container'><div class='column' style='width:100%'>"); build.Append("<body class='hearty'><div class='app-columns-container'><div class='column' style='width:100%'>");
build.Append(html); build.Append(html);

View File

@@ -1,4 +1,6 @@
namespace TweetDick.Core.Other { using TweetDck.Core.Controls;
namespace TweetDck.Core.Other {
sealed partial class FormAbout { sealed partial class FormAbout {
/// <summary> /// <summary>
/// Required designer variable. /// Required designer variable.
@@ -23,7 +25,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.labelAbout = new TweetDick.Core.Controls.RichTextLabel(); this.labelAbout = new TweetDck.Core.Controls.RichTextLabel();
this.SuspendLayout(); this.SuspendLayout();
// //
// labelAbout // labelAbout
@@ -41,6 +43,7 @@
this.labelAbout.TabIndex = 0; this.labelAbout.TabIndex = 0;
this.labelAbout.TabStop = false; this.labelAbout.TabStop = false;
this.labelAbout.Text = ""; this.labelAbout.Text = "";
this.labelAbout.Click += new System.EventHandler(this.labelAbout_Click);
// //
// FormAbout // FormAbout
// //

View File

@@ -1,20 +1,43 @@
using System.Text; using System;
using System.Text;
using System.Windows.Forms; using System.Windows.Forms;
using TweetDick.Core.Controls; using TweetDck.Core.Controls;
using TweetDck.Core.Utils;
namespace TweetDick.Core.Other{ namespace TweetDck.Core.Other{
sealed partial class FormAbout : Form{ sealed partial class FormAbout : Form{
private const string GitHubLink = "https://github.com/chylex/TweetDuck";
public FormAbout(){ public FormAbout(){
InitializeComponent(); InitializeComponent();
Text = "About "+Program.BrandName; Text = "About "+Program.BrandName+" "+Program.VersionTag;
StringBuilder build = new StringBuilder(); StringBuilder build = new StringBuilder();
build.Append(@"\fs22").Append(Program.BrandName).Append(@" was created by chylex as a replacement to the discontinued TweetDeck client for Windows, and is released under the MIT license.\par "); build.Append(@"\fs22").Append(Program.BrandName).Append(@" was created by chylex as a replacement to the discontinued TweetDeck client for Windows, and is released under the MIT license.\par ");
build.Append(@"Official Website: ").Append(RichTextLabel.AddLink(Program.Website)).Append(@"\line "); build.Append(@"Official Website: ").Append(RichTextLabel.AddLink(Program.Website)).Append(@"\line ");
build.Append(@"Source Code: ").Append(RichTextLabel.AddLink("https://github.com/chylex/TweetDick")); build.Append(@"Source Code: ").Append(RichTextLabel.AddLink(GitHubLink));
labelAbout.Rtf = RichTextLabel.Wrap(build.ToString()); labelAbout.Rtf = RichTextLabel.Wrap(build.ToString());
} }
private void labelAbout_Click(object sender, EventArgs e){ // LinkClicked isn't working so fuck that
if (Cursor.Current != Cursors.Hand)return;
// I don't even give a fuck, someone else PR a proper fix please
int index = labelAbout.GetCharIndexFromPosition(((MouseEventArgs)e).Location);
if (IsClickingOn(index,Program.Website)){
BrowserUtils.OpenExternalBrowser(Program.Website);
}
else if (IsClickingOn(index,GitHubLink)){
BrowserUtils.OpenExternalBrowser(GitHubLink);
}
}
private bool IsClickingOn(int index, string substringSearch){
int substringIndex = labelAbout.Text.IndexOf(substringSearch,StringComparison.Ordinal);
return index >= substringIndex && index <= substringIndex+substringSearch.Length;
}
} }
} }

View File

@@ -1,6 +1,6 @@
using TweetDick.Core.Controls; using TweetDck.Core.Controls;
namespace TweetDick.Core.Other { namespace TweetDck.Core.Other {
partial class FormBackgroundWork { partial class FormBackgroundWork {
/// <summary> /// <summary>
/// Required designer variable. /// Required designer variable.

View File

@@ -1,8 +1,8 @@
using System; using System;
using System.Windows.Forms; using System.Windows.Forms;
using TweetDick.Core.Controls; using TweetDck.Core.Controls;
namespace TweetDick.Core.Other{ namespace TweetDck.Core.Other{
partial class FormBackgroundWork : Form{ partial class FormBackgroundWork : Form{
public FormBackgroundWork(){ public FormBackgroundWork(){
InitializeComponent(); InitializeComponent();

View File

@@ -1,4 +1,4 @@
namespace TweetDick.Core.Other { namespace TweetDck.Core.Other {
sealed partial class FormSettings { sealed partial class FormSettings {
/// <summary> /// <summary>
/// Required designer variable. /// Required designer variable.
@@ -23,7 +23,6 @@
/// 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() {
System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(FormSettings));
this.groupNotificationLocation = new System.Windows.Forms.GroupBox(); this.groupNotificationLocation = new System.Windows.Forms.GroupBox();
this.labelDisplay = new System.Windows.Forms.Label(); this.labelDisplay = new System.Windows.Forms.Label();
this.comboBoxDisplay = new System.Windows.Forms.ComboBox(); this.comboBoxDisplay = new System.Windows.Forms.ComboBox();
@@ -34,16 +33,24 @@
this.radioLocBL = new System.Windows.Forms.RadioButton(); this.radioLocBL = new System.Windows.Forms.RadioButton();
this.radioLocTR = new System.Windows.Forms.RadioButton(); this.radioLocTR = new System.Windows.Forms.RadioButton();
this.radioLocTL = new System.Windows.Forms.RadioButton(); this.radioLocTL = new System.Windows.Forms.RadioButton();
this.tableLayout = new System.Windows.Forms.TableLayoutPanel();
this.tableColumn2Panel = new System.Windows.Forms.Panel();
this.groupUserInterface = new System.Windows.Forms.GroupBox();
this.comboBoxTrayType = new System.Windows.Forms.ComboBox();
this.labelTrayType = new System.Windows.Forms.Label();
this.checkUpdateNotifications = new System.Windows.Forms.CheckBox();
this.checkNotificationTimer = new System.Windows.Forms.CheckBox();
this.groupNotificationDuration = new System.Windows.Forms.GroupBox(); this.groupNotificationDuration = new System.Windows.Forms.GroupBox();
this.radioDurVeryLong = new System.Windows.Forms.RadioButton(); this.radioDurVeryLong = new System.Windows.Forms.RadioButton();
this.radioDurLong = new System.Windows.Forms.RadioButton(); this.radioDurLong = new System.Windows.Forms.RadioButton();
this.radioDurMedium = new System.Windows.Forms.RadioButton(); this.radioDurMedium = new System.Windows.Forms.RadioButton();
this.radioDurShort = new System.Windows.Forms.RadioButton(); this.radioDurShort = new System.Windows.Forms.RadioButton();
this.tableLayout = new System.Windows.Forms.TableLayoutPanel();
this.groupNotificationLocation.SuspendLayout(); this.groupNotificationLocation.SuspendLayout();
((System.ComponentModel.ISupportInitialize)(this.trackBarEdgeDistance)).BeginInit(); ((System.ComponentModel.ISupportInitialize)(this.trackBarEdgeDistance)).BeginInit();
this.groupNotificationDuration.SuspendLayout();
this.tableLayout.SuspendLayout(); this.tableLayout.SuspendLayout();
this.tableColumn2Panel.SuspendLayout();
this.groupUserInterface.SuspendLayout();
this.groupNotificationDuration.SuspendLayout();
this.SuspendLayout(); this.SuspendLayout();
// //
// groupNotificationLocation // groupNotificationLocation
@@ -69,9 +76,9 @@
// //
// labelDisplay // labelDisplay
// //
this.labelDisplay.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left)));
this.labelDisplay.AutoSize = true; this.labelDisplay.AutoSize = true;
this.labelDisplay.Location = new System.Drawing.Point(6, 154); this.labelDisplay.Location = new System.Drawing.Point(6, 148);
this.labelDisplay.Margin = new System.Windows.Forms.Padding(3, 12, 3, 0);
this.labelDisplay.Name = "labelDisplay"; this.labelDisplay.Name = "labelDisplay";
this.labelDisplay.Size = new System.Drawing.Size(41, 13); this.labelDisplay.Size = new System.Drawing.Size(41, 13);
this.labelDisplay.TabIndex = 8; this.labelDisplay.TabIndex = 8;
@@ -83,8 +90,7 @@
| System.Windows.Forms.AnchorStyles.Right))); | System.Windows.Forms.AnchorStyles.Right)));
this.comboBoxDisplay.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList; this.comboBoxDisplay.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList;
this.comboBoxDisplay.FormattingEnabled = true; this.comboBoxDisplay.FormattingEnabled = true;
this.comboBoxDisplay.Location = new System.Drawing.Point(9, 170); this.comboBoxDisplay.Location = new System.Drawing.Point(9, 164);
this.comboBoxDisplay.Margin = new System.Windows.Forms.Padding(3, 3, 3, 12);
this.comboBoxDisplay.Name = "comboBoxDisplay"; this.comboBoxDisplay.Name = "comboBoxDisplay";
this.comboBoxDisplay.Size = new System.Drawing.Size(168, 21); this.comboBoxDisplay.Size = new System.Drawing.Size(168, 21);
this.comboBoxDisplay.TabIndex = 7; this.comboBoxDisplay.TabIndex = 7;
@@ -92,9 +98,9 @@
// //
// labelEdgeDistance // labelEdgeDistance
// //
this.labelEdgeDistance.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left)));
this.labelEdgeDistance.AutoSize = true; this.labelEdgeDistance.AutoSize = true;
this.labelEdgeDistance.Location = new System.Drawing.Point(6, 203); this.labelEdgeDistance.Location = new System.Drawing.Point(6, 197);
this.labelEdgeDistance.Margin = new System.Windows.Forms.Padding(3, 9, 3, 0);
this.labelEdgeDistance.Name = "labelEdgeDistance"; this.labelEdgeDistance.Name = "labelEdgeDistance";
this.labelEdgeDistance.Size = new System.Drawing.Size(103, 13); this.labelEdgeDistance.Size = new System.Drawing.Size(103, 13);
this.labelEdgeDistance.TabIndex = 6; this.labelEdgeDistance.TabIndex = 6;
@@ -102,10 +108,10 @@
// //
// trackBarEdgeDistance // trackBarEdgeDistance
// //
this.trackBarEdgeDistance.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left) this.trackBarEdgeDistance.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left)
| System.Windows.Forms.AnchorStyles.Right))); | System.Windows.Forms.AnchorStyles.Right)));
this.trackBarEdgeDistance.LargeChange = 8; this.trackBarEdgeDistance.LargeChange = 8;
this.trackBarEdgeDistance.Location = new System.Drawing.Point(6, 219); this.trackBarEdgeDistance.Location = new System.Drawing.Point(6, 213);
this.trackBarEdgeDistance.Maximum = 40; this.trackBarEdgeDistance.Maximum = 40;
this.trackBarEdgeDistance.Minimum = 8; this.trackBarEdgeDistance.Minimum = 8;
this.trackBarEdgeDistance.Name = "trackBarEdgeDistance"; this.trackBarEdgeDistance.Name = "trackBarEdgeDistance";
@@ -181,6 +187,97 @@
this.radioLocTL.CheckedChanged += new System.EventHandler(this.radioLoc_CheckedChanged); this.radioLocTL.CheckedChanged += new System.EventHandler(this.radioLoc_CheckedChanged);
this.radioLocTL.Click += new System.EventHandler(this.radioLoc_Click); this.radioLocTL.Click += new System.EventHandler(this.radioLoc_Click);
// //
// tableLayout
//
this.tableLayout.ColumnCount = 2;
this.tableLayout.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 50F));
this.tableLayout.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 50F));
this.tableLayout.Controls.Add(this.tableColumn2Panel, 1, 0);
this.tableLayout.Controls.Add(this.groupNotificationLocation, 0, 0);
this.tableLayout.Dock = System.Windows.Forms.DockStyle.Fill;
this.tableLayout.GrowStyle = System.Windows.Forms.TableLayoutPanelGrowStyle.FixedSize;
this.tableLayout.Location = new System.Drawing.Point(0, 0);
this.tableLayout.Name = "tableLayout";
this.tableLayout.Padding = new System.Windows.Forms.Padding(3);
this.tableLayout.RowCount = 1;
this.tableLayout.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 100F));
this.tableLayout.Size = new System.Drawing.Size(384, 282);
this.tableLayout.TabIndex = 2;
//
// tableColumn2Panel
//
this.tableColumn2Panel.Controls.Add(this.groupUserInterface);
this.tableColumn2Panel.Controls.Add(this.groupNotificationDuration);
this.tableColumn2Panel.Dock = System.Windows.Forms.DockStyle.Fill;
this.tableColumn2Panel.Location = new System.Drawing.Point(192, 3);
this.tableColumn2Panel.Margin = new System.Windows.Forms.Padding(0);
this.tableColumn2Panel.Name = "tableColumn2Panel";
this.tableColumn2Panel.Size = new System.Drawing.Size(189, 276);
this.tableColumn2Panel.TabIndex = 3;
//
// groupUserInterface
//
this.groupUserInterface.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left)
| System.Windows.Forms.AnchorStyles.Right)));
this.groupUserInterface.Controls.Add(this.comboBoxTrayType);
this.groupUserInterface.Controls.Add(this.labelTrayType);
this.groupUserInterface.Controls.Add(this.checkUpdateNotifications);
this.groupUserInterface.Controls.Add(this.checkNotificationTimer);
this.groupUserInterface.Location = new System.Drawing.Point(3, 128);
this.groupUserInterface.Name = "groupUserInterface";
this.groupUserInterface.Size = new System.Drawing.Size(183, 145);
this.groupUserInterface.TabIndex = 3;
this.groupUserInterface.TabStop = false;
this.groupUserInterface.Text = "User Interface";
//
// comboBoxTrayType
//
this.comboBoxTrayType.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left)
| System.Windows.Forms.AnchorStyles.Right)));
this.comboBoxTrayType.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList;
this.comboBoxTrayType.FormattingEnabled = true;
this.comboBoxTrayType.Location = new System.Drawing.Point(9, 93);
this.comboBoxTrayType.Margin = new System.Windows.Forms.Padding(3, 3, 3, 12);
this.comboBoxTrayType.Name = "comboBoxTrayType";
this.comboBoxTrayType.Size = new System.Drawing.Size(168, 21);
this.comboBoxTrayType.TabIndex = 10;
this.comboBoxTrayType.SelectedIndexChanged += new System.EventHandler(this.comboBoxTrayType_SelectedIndexChanged);
//
// labelTrayType
//
this.labelTrayType.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left)));
this.labelTrayType.AutoSize = true;
this.labelTrayType.Location = new System.Drawing.Point(6, 77);
this.labelTrayType.Margin = new System.Windows.Forms.Padding(3, 12, 3, 0);
this.labelTrayType.Name = "labelTrayType";
this.labelTrayType.Size = new System.Drawing.Size(52, 13);
this.labelTrayType.TabIndex = 9;
this.labelTrayType.Text = "Tray Icon";
//
// checkUpdateNotifications
//
this.checkUpdateNotifications.AutoSize = true;
this.checkUpdateNotifications.Location = new System.Drawing.Point(6, 45);
this.checkUpdateNotifications.Margin = new System.Windows.Forms.Padding(3, 4, 3, 3);
this.checkUpdateNotifications.Name = "checkUpdateNotifications";
this.checkUpdateNotifications.Size = new System.Drawing.Size(115, 17);
this.checkUpdateNotifications.TabIndex = 5;
this.checkUpdateNotifications.Text = "Check for Updates";
this.checkUpdateNotifications.UseVisualStyleBackColor = true;
this.checkUpdateNotifications.CheckedChanged += new System.EventHandler(this.checkUpdateNotifications_CheckedChanged);
//
// checkNotificationTimer
//
this.checkNotificationTimer.AutoSize = true;
this.checkNotificationTimer.Location = new System.Drawing.Point(6, 21);
this.checkNotificationTimer.Margin = new System.Windows.Forms.Padding(3, 5, 3, 3);
this.checkNotificationTimer.Name = "checkNotificationTimer";
this.checkNotificationTimer.Size = new System.Drawing.Size(145, 17);
this.checkNotificationTimer.TabIndex = 4;
this.checkNotificationTimer.Text = "Display Notification Timer";
this.checkNotificationTimer.UseVisualStyleBackColor = true;
this.checkNotificationTimer.CheckedChanged += new System.EventHandler(this.checkNotificationTimer_CheckedChanged);
//
// groupNotificationDuration // groupNotificationDuration
// //
this.groupNotificationDuration.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) this.groupNotificationDuration.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left)
@@ -189,10 +286,10 @@
this.groupNotificationDuration.Controls.Add(this.radioDurLong); this.groupNotificationDuration.Controls.Add(this.radioDurLong);
this.groupNotificationDuration.Controls.Add(this.radioDurMedium); this.groupNotificationDuration.Controls.Add(this.radioDurMedium);
this.groupNotificationDuration.Controls.Add(this.radioDurShort); this.groupNotificationDuration.Controls.Add(this.radioDurShort);
this.groupNotificationDuration.Location = new System.Drawing.Point(195, 6); this.groupNotificationDuration.Location = new System.Drawing.Point(3, 3);
this.groupNotificationDuration.Name = "groupNotificationDuration"; this.groupNotificationDuration.Name = "groupNotificationDuration";
this.groupNotificationDuration.Size = new System.Drawing.Size(183, 118); this.groupNotificationDuration.Size = new System.Drawing.Size(183, 119);
this.groupNotificationDuration.TabIndex = 1; this.groupNotificationDuration.TabIndex = 2;
this.groupNotificationDuration.TabStop = false; this.groupNotificationDuration.TabStop = false;
this.groupNotificationDuration.Text = "Notification Duration"; this.groupNotificationDuration.Text = "Notification Duration";
// //
@@ -248,23 +345,6 @@
this.radioDurShort.CheckedChanged += new System.EventHandler(this.radioDur_CheckedChanged); this.radioDurShort.CheckedChanged += new System.EventHandler(this.radioDur_CheckedChanged);
this.radioDurShort.Click += new System.EventHandler(this.radioDur_Click); this.radioDurShort.Click += new System.EventHandler(this.radioDur_Click);
// //
// tableLayout
//
this.tableLayout.ColumnCount = 2;
this.tableLayout.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 50F));
this.tableLayout.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 50F));
this.tableLayout.Controls.Add(this.groupNotificationLocation, 0, 0);
this.tableLayout.Controls.Add(this.groupNotificationDuration, 1, 0);
this.tableLayout.Dock = System.Windows.Forms.DockStyle.Fill;
this.tableLayout.GrowStyle = System.Windows.Forms.TableLayoutPanelGrowStyle.FixedSize;
this.tableLayout.Location = new System.Drawing.Point(0, 0);
this.tableLayout.Name = "tableLayout";
this.tableLayout.Padding = new System.Windows.Forms.Padding(3);
this.tableLayout.RowCount = 1;
this.tableLayout.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 100F));
this.tableLayout.Size = new System.Drawing.Size(384, 282);
this.tableLayout.TabIndex = 2;
//
// FormSettings // FormSettings
// //
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
@@ -272,7 +352,7 @@
this.ClientSize = new System.Drawing.Size(384, 282); this.ClientSize = new System.Drawing.Size(384, 282);
this.Controls.Add(this.tableLayout); this.Controls.Add(this.tableLayout);
this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedSingle; this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedSingle;
this.Icon = TweetDick.Properties.Resources.icon; this.Icon = ((System.Drawing.Icon)(TweetDck.Properties.Resources.ResourceManager.GetObject("icon")));
this.MaximizeBox = false; this.MaximizeBox = false;
this.MinimizeBox = false; this.MinimizeBox = false;
this.Name = "FormSettings"; this.Name = "FormSettings";
@@ -281,9 +361,12 @@
this.groupNotificationLocation.ResumeLayout(false); this.groupNotificationLocation.ResumeLayout(false);
this.groupNotificationLocation.PerformLayout(); this.groupNotificationLocation.PerformLayout();
((System.ComponentModel.ISupportInitialize)(this.trackBarEdgeDistance)).EndInit(); ((System.ComponentModel.ISupportInitialize)(this.trackBarEdgeDistance)).EndInit();
this.tableLayout.ResumeLayout(false);
this.tableColumn2Panel.ResumeLayout(false);
this.groupUserInterface.ResumeLayout(false);
this.groupUserInterface.PerformLayout();
this.groupNotificationDuration.ResumeLayout(false); this.groupNotificationDuration.ResumeLayout(false);
this.groupNotificationDuration.PerformLayout(); this.groupNotificationDuration.PerformLayout();
this.tableLayout.ResumeLayout(false);
this.ResumeLayout(false); this.ResumeLayout(false);
} }
@@ -298,13 +381,19 @@
private System.Windows.Forms.RadioButton radioLocTL; private System.Windows.Forms.RadioButton radioLocTL;
private System.Windows.Forms.Label labelEdgeDistance; private System.Windows.Forms.Label labelEdgeDistance;
private System.Windows.Forms.TrackBar trackBarEdgeDistance; private System.Windows.Forms.TrackBar trackBarEdgeDistance;
private System.Windows.Forms.Label labelDisplay;
private System.Windows.Forms.ComboBox comboBoxDisplay;
private System.Windows.Forms.TableLayoutPanel tableLayout;
private System.Windows.Forms.Panel tableColumn2Panel;
private System.Windows.Forms.GroupBox groupUserInterface;
private System.Windows.Forms.GroupBox groupNotificationDuration; private System.Windows.Forms.GroupBox groupNotificationDuration;
private System.Windows.Forms.RadioButton radioDurVeryLong; private System.Windows.Forms.RadioButton radioDurVeryLong;
private System.Windows.Forms.RadioButton radioDurLong; private System.Windows.Forms.RadioButton radioDurLong;
private System.Windows.Forms.RadioButton radioDurMedium; private System.Windows.Forms.RadioButton radioDurMedium;
private System.Windows.Forms.RadioButton radioDurShort; private System.Windows.Forms.RadioButton radioDurShort;
private System.Windows.Forms.Label labelDisplay; private System.Windows.Forms.CheckBox checkNotificationTimer;
private System.Windows.Forms.ComboBox comboBoxDisplay; private System.Windows.Forms.CheckBox checkUpdateNotifications;
private System.Windows.Forms.TableLayoutPanel tableLayout; private System.Windows.Forms.ComboBox comboBoxTrayType;
private System.Windows.Forms.Label labelTrayType;
} }
} }

View File

@@ -1,9 +1,9 @@
using System; using System;
using System.Windows.Forms; using System.Windows.Forms;
using TweetDick.Configuration; using TweetDck.Configuration;
using TweetDick.Core.Handling; using TweetDck.Core.Handling;
namespace TweetDick.Core.Other{ namespace TweetDck.Core.Other{
sealed partial class FormSettings : Form{ sealed partial class FormSettings : Form{
private static UserConfig Config{ private static UserConfig Config{
get{ get{
@@ -53,7 +53,15 @@ namespace TweetDick.Core.Other{
comboBoxDisplay.SelectedIndex = Math.Min(comboBoxDisplay.Items.Count-1,Config.NotificationDisplay); comboBoxDisplay.SelectedIndex = Math.Min(comboBoxDisplay.Items.Count-1,Config.NotificationDisplay);
comboBoxTrayType.Items.Add("Disabled");
comboBoxTrayType.Items.Add("Display Icon Only");
comboBoxTrayType.Items.Add("Minimize to Tray");
comboBoxTrayType.Items.Add("Close to Tray");
comboBoxTrayType.SelectedIndex = Math.Min(Math.Max((int)Config.TrayBehavior,0),comboBoxTrayType.Items.Count-1);
trackBarEdgeDistance.Value = Config.NotificationEdgeDistance; trackBarEdgeDistance.Value = Config.NotificationEdgeDistance;
checkNotificationTimer.Checked = Config.DisplayNotificationTimer;
checkUpdateNotifications.Checked = Config.EnableUpdateCheck;
} }
private void FormSettings_FormClosing(object sender, FormClosingEventArgs e){ private void FormSettings_FormClosing(object sender, FormClosingEventArgs e){
@@ -115,5 +123,24 @@ namespace TweetDick.Core.Other{
notification.ShowNotificationForSettings(true); notification.ShowNotificationForSettings(true);
} }
private void comboBoxTrayType_SelectedIndexChanged(object sender, EventArgs e){
if (!isLoaded)return;
Config.TrayBehavior = (TrayIcon.Behavior)comboBoxTrayType.SelectedIndex;
}
private void checkNotificationTimer_CheckedChanged(object sender, EventArgs e){
if (!isLoaded)return;
Config.DisplayNotificationTimer = checkNotificationTimer.Checked;
notification.ShowNotificationForSettings(true);
}
private void checkUpdateNotifications_CheckedChanged(object sender, EventArgs e){
if (!isLoaded)return;
Config.EnableUpdateCheck = checkUpdateNotifications.Checked;
}
} }
} }

103
Core/Other/FormUpdateDownload.Designer.cs generated Normal file
View File

@@ -0,0 +1,103 @@
namespace TweetDck.Core.Other {
partial class FormUpdateDownload {
/// <summary>
/// Required designer variable.
/// </summary>
private System.ComponentModel.IContainer components = null;
/// <summary>
/// Clean up any resources being used.
/// </summary>
/// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
protected override void Dispose(bool disposing) {
if (disposing && (components != null)) {
components.Dispose();
}
base.Dispose(disposing);
}
#region Windows Form Designer generated code
/// <summary>
/// Required method for Designer support - do not modify
/// the contents of this method with the code editor.
/// </summary>
private void InitializeComponent() {
this.progressDownload = new System.Windows.Forms.ProgressBar();
this.btnCancel = new System.Windows.Forms.Button();
this.labelDescription = new System.Windows.Forms.Label();
this.labelStatus = new System.Windows.Forms.Label();
this.SuspendLayout();
//
// progressDownload
//
this.progressDownload.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left)
| System.Windows.Forms.AnchorStyles.Right)));
this.progressDownload.Location = new System.Drawing.Point(12, 32);
this.progressDownload.MarqueeAnimationSpeed = 40;
this.progressDownload.Maximum = 1000;
this.progressDownload.Name = "progressDownload";
this.progressDownload.Size = new System.Drawing.Size(361, 23);
this.progressDownload.Style = System.Windows.Forms.ProgressBarStyle.Marquee;
this.progressDownload.TabIndex = 0;
//
// btnCancel
//
this.btnCancel.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right)));
this.btnCancel.AutoSize = true;
this.btnCancel.AutoSizeMode = System.Windows.Forms.AutoSizeMode.GrowAndShrink;
this.btnCancel.Location = new System.Drawing.Point(317, 61);
this.btnCancel.Name = "btnCancel";
this.btnCancel.Padding = new System.Windows.Forms.Padding(3, 0, 3, 0);
this.btnCancel.Size = new System.Drawing.Size(56, 23);
this.btnCancel.TabIndex = 1;
this.btnCancel.Text = "Cancel";
this.btnCancel.UseVisualStyleBackColor = true;
this.btnCancel.Click += new System.EventHandler(this.btnCancel_Click);
//
// labelDescription
//
this.labelDescription.AutoSize = true;
this.labelDescription.Location = new System.Drawing.Point(9, 13);
this.labelDescription.Margin = new System.Windows.Forms.Padding(3, 0, 3, 3);
this.labelDescription.Name = "labelDescription";
this.labelDescription.Size = new System.Drawing.Size(0, 13);
this.labelDescription.TabIndex = 2;
//
// labelStatus
//
this.labelStatus.AutoSize = true;
this.labelStatus.Location = new System.Drawing.Point(9, 62);
this.labelStatus.Name = "labelStatus";
this.labelStatus.Size = new System.Drawing.Size(0, 13);
this.labelStatus.TabIndex = 3;
//
// FormUpdateDownload
//
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
this.ClientSize = new System.Drawing.Size(385, 96);
this.Controls.Add(this.labelStatus);
this.Controls.Add(this.labelDescription);
this.Controls.Add(this.btnCancel);
this.Controls.Add(this.progressDownload);
this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedSingle;
this.Icon = ((System.Drawing.Icon)(TweetDck.Properties.Resources.ResourceManager.GetObject("icon")));
this.MaximizeBox = false;
this.Name = "FormUpdateDownload";
this.StartPosition = System.Windows.Forms.FormStartPosition.Manual;
this.FormClosing += new System.Windows.Forms.FormClosingEventHandler(this.FormUpdateDownload_FormClosing);
this.Shown += new System.EventHandler(this.FormUpdateDownload_Shown);
this.ResumeLayout(false);
this.PerformLayout();
}
#endregion
private System.Windows.Forms.ProgressBar progressDownload;
private System.Windows.Forms.Button btnCancel;
private System.Windows.Forms.Label labelDescription;
private System.Windows.Forms.Label labelStatus;
}
}

View File

@@ -0,0 +1,108 @@
using System;
using System.ComponentModel;
using System.IO;
using System.Net;
using System.Windows.Forms;
using TweetDck.Core.Controls;
using TweetDck.Core.Utils;
namespace TweetDck.Core.Other{
sealed partial class FormUpdateDownload : Form{
public string InstallerPath{
get{
return Path.Combine(Path.GetTempPath(),updateInfo.FileName);
}
}
public enum Status{
Waiting, Failed, Cancelled, Manual, Succeeded
}
public Status UpdateStatus { get; private set; }
private readonly WebClient webClient;
private readonly UpdateInfo updateInfo;
public FormUpdateDownload(UpdateInfo info){
InitializeComponent();
this.webClient = new WebClient{ Proxy = null };
this.webClient.Headers[HttpRequestHeader.UserAgent] = BrowserUtils.HeaderUserAgent;
this.updateInfo = info;
this.UpdateStatus = Status.Waiting;
Disposed += (sender, args) => webClient.Dispose();
webClient.DownloadProgressChanged += webClient_DownloadProgressChanged;
webClient.DownloadFileCompleted += webClient_DownloadFileCompleted;
Text = "Updating "+Program.BrandName;
labelDescription.Text = "Downloading version "+info.VersionTag+"...";
}
private void FormUpdateDownload_Shown(object sender, EventArgs e){
webClient.DownloadFileAsync(new Uri(updateInfo.DownloadUrl),InstallerPath);
}
private void btnCancel_Click(object sender, EventArgs e){
webClient.CancelAsync();
btnCancel.Enabled = false;
}
private void FormUpdateDownload_FormClosing(object sender, FormClosingEventArgs e){
if (UpdateStatus == Status.Waiting){
e.Cancel = true;
webClient.CancelAsync();
UpdateStatus = e.CloseReason == CloseReason.UserClosing ? Status.Cancelled : Status.Manual; // manual will exit the app
}
}
private void webClient_DownloadProgressChanged(object sender, DownloadProgressChangedEventArgs e){
this.InvokeSafe(() => {
if (e.TotalBytesToReceive == -1){
if (progressDownload.Style != ProgressBarStyle.Marquee){
progressDownload.Style = ProgressBarStyle.Continuous;
progressDownload.SetValueInstant(1000);
}
labelStatus.Text = (e.BytesReceived/(1024.0*1024.0)).ToString("0.0")+" MB";
}
else{
if (progressDownload.Style != ProgressBarStyle.Continuous){
progressDownload.Style = ProgressBarStyle.Continuous;
}
progressDownload.SetValueInstant(e.ProgressPercentage*10);
labelStatus.Text = (e.BytesReceived/(1024.0*1024.0)).ToString("0.0")+" / "+(e.TotalBytesToReceive/(1024.0*1024.0)).ToString("0.0")+" MB";
}
});
}
private void webClient_DownloadFileCompleted(object sender, AsyncCompletedEventArgs e){
this.InvokeSafe(() => {
if (e.Cancelled){
if (UpdateStatus == Status.Waiting){
UpdateStatus = Status.Cancelled;
}
}
else if (e.Error != null){
Program.Log(e.Error.ToString());
if (MessageBox.Show("Could not download the update: "+e.Error.Message+"\r\n\r\nDo you want to open the website and try downloading the update manually?","Update Has Failed",MessageBoxButtons.YesNo,MessageBoxIcon.Error,MessageBoxDefaultButton.Button1) == DialogResult.Yes){
BrowserUtils.OpenExternalBrowser(Program.Website);
UpdateStatus = Status.Manual;
}
else{
UpdateStatus = Status.Failed;
}
}
else{
UpdateStatus = Status.Succeeded;
}
Close();
});
}
}
}

89
Core/TrayIcon.Designer.cs generated Normal file
View File

@@ -0,0 +1,89 @@
namespace TweetDck.Core {
partial class TrayIcon {
/// <summary>
/// Required designer variable.
/// </summary>
private System.ComponentModel.IContainer components = null;
/// <summary>
/// Clean up any resources being used.
/// </summary>
/// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
protected override void Dispose(bool disposing) {
if (disposing && (components != null)) {
components.Dispose();
}
base.Dispose(disposing);
}
#region Component Designer generated code
/// <summary>
/// Required method for Designer support - do not modify
/// the contents of this method with the code editor.
/// </summary>
private void InitializeComponent() {
this.components = new System.ComponentModel.Container();
this.notifyIcon = new System.Windows.Forms.NotifyIcon(this.components);
this.contextMenu = new System.Windows.Forms.ContextMenuStrip(this.components);
this.restoreToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
this.muteNotificationsToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
this.closeToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
this.contextMenu.SuspendLayout();
//
// trayIcon
//
this.notifyIcon.ContextMenuStrip = this.contextMenu;
this.notifyIcon.Icon = global::TweetDck.Properties.Resources.icon;
this.notifyIcon.MouseClick += new System.Windows.Forms.MouseEventHandler(this.trayIcon_MouseClick);
//
// contextMenuTray
//
this.contextMenu.Items.AddRange(new System.Windows.Forms.ToolStripItem[] {
this.restoreToolStripMenuItem,
this.muteNotificationsToolStripMenuItem,
this.closeToolStripMenuItem});
this.contextMenu.Name = "contextMenuTray";
this.contextMenu.ShowCheckMargin = true;
this.contextMenu.ShowImageMargin = false;
this.contextMenu.ShowItemToolTips = false;
this.contextMenu.Size = new System.Drawing.Size(174, 92);
this.contextMenu.Opening += new System.ComponentModel.CancelEventHandler(this.contextMenuTray_Opening);
this.contextMenu.Opened += new System.EventHandler(this.contextMenuTray_Opened);
//
// restoreToolStripMenuItem
//
this.restoreToolStripMenuItem.Name = "restoreToolStripMenuItem";
this.restoreToolStripMenuItem.Size = new System.Drawing.Size(173, 22);
this.restoreToolStripMenuItem.Text = "Restore";
this.restoreToolStripMenuItem.Click += new System.EventHandler(this.restoreToolStripMenuItem_Click);
//
// muteNotificationsToolStripMenuItem
//
this.muteNotificationsToolStripMenuItem.CheckOnClick = true;
this.muteNotificationsToolStripMenuItem.Name = "muteNotificationsToolStripMenuItem";
this.muteNotificationsToolStripMenuItem.Size = new System.Drawing.Size(173, 22);
this.muteNotificationsToolStripMenuItem.Text = "Mute Notifications";
this.muteNotificationsToolStripMenuItem.CheckedChanged += new System.EventHandler(this.muteNotificationsToolStripMenuItem_CheckedChanged);
//
// closeToolStripMenuItem
//
this.closeToolStripMenuItem.Name = "closeToolStripMenuItem";
this.closeToolStripMenuItem.Size = new System.Drawing.Size(173, 22);
this.closeToolStripMenuItem.Text = "Close";
this.closeToolStripMenuItem.Click += new System.EventHandler(this.closeToolStripMenuItem_Click);
//
// TrayIcon
//
this.contextMenu.ResumeLayout(false);
}
#endregion
private System.Windows.Forms.NotifyIcon notifyIcon;
private System.Windows.Forms.ContextMenuStrip contextMenu;
private System.Windows.Forms.ToolStripMenuItem restoreToolStripMenuItem;
private System.Windows.Forms.ToolStripMenuItem closeToolStripMenuItem;
private System.Windows.Forms.ToolStripMenuItem muteNotificationsToolStripMenuItem;
}
}

63
Core/TrayIcon.cs Normal file
View File

@@ -0,0 +1,63 @@
using System;
using System.ComponentModel;
using System.Windows.Forms;
namespace TweetDck.Core{
partial class TrayIcon : Component{
public enum Behavior{ // keep order
Disabled, DisplayOnly, MinimizeToTray, CloseToTray
}
public event EventHandler ClickRestore;
public event EventHandler ClickClose;
public bool Visible{
get{
return notifyIcon.Visible;
}
set{
notifyIcon.Visible = value;
}
}
public TrayIcon(){
InitializeComponent();
notifyIcon.Text = Program.BrandName;
}
// event handlers
private void trayIcon_MouseClick(object sender, MouseEventArgs e){
if (e.Button == MouseButtons.Left){
restoreToolStripMenuItem_Click(sender,e);
}
}
private void contextMenuTray_Opening(object sender, CancelEventArgs e){
muteNotificationsToolStripMenuItem.CheckedChanged -= muteNotificationsToolStripMenuItem_CheckedChanged;
muteNotificationsToolStripMenuItem.Checked = Program.UserConfig.MuteNotifications;
}
private void contextMenuTray_Opened(object sender, EventArgs e){
muteNotificationsToolStripMenuItem.CheckedChanged += muteNotificationsToolStripMenuItem_CheckedChanged;
}
private void restoreToolStripMenuItem_Click(object sender, EventArgs e){
if (ClickRestore != null){
ClickRestore(this,e);
}
}
private void muteNotificationsToolStripMenuItem_CheckedChanged(object sender, EventArgs e){
Program.UserConfig.MuteNotifications = muteNotificationsToolStripMenuItem.Checked;
Program.UserConfig.Save();
}
private void closeToolStripMenuItem_Click(object sender, EventArgs e){
if (ClickClose != null){
ClickClose(this,e);
}
}
}
}

View File

@@ -0,0 +1,51 @@
using System;
using System.Diagnostics;
using System.Globalization;
using System.IO;
using System.Net;
using System.Windows.Forms;
namespace TweetDck.Core.Utils{
static class BrowserUtils{
public static string HeaderAcceptLanguage{
get{
string culture = CultureInfo.CurrentCulture.Name;
if (culture == "en"){
return "en-us,en";
}
else{
return culture.ToLowerInvariant()+",en;q=0.9";
}
}
}
public static string HeaderUserAgent{
get{
return Program.BrandName+" "+Application.ProductVersion;
}
}
public static void OpenExternalBrowser(string url){ // TODO implement mailto
Process.Start(url);
}
public static string GetFileNameFromUrl(string url){
string file = Path.GetFileName(new Uri(url).AbsolutePath);
return string.IsNullOrEmpty(file) ? null : file;
}
public static void DownloadFileAsync(string url, string target, Action<Exception> onFailure){
WebClient client = new WebClient{ Proxy = null };
client.Headers[HttpRequestHeader.UserAgent] = HeaderUserAgent;
client.DownloadFileCompleted += (sender, args) => {
if (args.Error != null){
onFailure(args.Error);
}
};
client.DownloadFileAsync(new Uri(url),target);
}
}
}

17
Core/Utils/UpdateInfo.cs Normal file
View File

@@ -0,0 +1,17 @@
namespace TweetDck.Core.Utils{
class UpdateInfo{
public readonly string VersionTag;
public readonly string DownloadUrl;
public string FileName{
get{
return BrowserUtils.GetFileNameFromUrl(DownloadUrl) ?? Program.BrandName+".Update.exe";
}
}
public UpdateInfo(string versionTag, string downloadUrl){
this.VersionTag = versionTag;
this.DownloadUrl = downloadUrl;
}
}
}

View File

View File

@@ -1,6 +1,6 @@
using TweetDick.Core.Controls; using TweetDck.Core.Controls;
namespace TweetDick.Migration { namespace TweetDck.Migration {
partial class FormMigrationQuestion { partial class FormMigrationQuestion {
/// <summary> /// <summary>
/// Required designer variable. /// Required designer variable.

View File

@@ -1,9 +1,9 @@
using System; using System;
using System.Drawing; using System.Drawing;
using System.Windows.Forms; using System.Windows.Forms;
using TweetDick.Core.Controls; using TweetDck.Core.Controls;
namespace TweetDick.Migration{ namespace TweetDck.Migration{
partial class FormMigrationQuestion : Form{ partial class FormMigrationQuestion : Form{
public MigrationDecision Decision { get; private set; } public MigrationDecision Decision { get; private set; }

View File

@@ -1,8 +1,8 @@
using System; using System;
using Shell32;
using System.IO; using System.IO;
using Shell32;
namespace TweetDick.Migration.Helpers{ namespace TweetDck.Migration.Helpers{
sealed class LnkEditor{ sealed class LnkEditor{
private readonly ShellLinkObject obj; private readonly ShellLinkObject obj;

View File

@@ -2,7 +2,7 @@
using System.Diagnostics; using System.Diagnostics;
using System.Linq; using System.Linq;
namespace TweetDick.Migration.Helpers{ namespace TweetDck.Migration.Helpers{
static class ProgramProcessSearch{ static class ProgramProcessSearch{
public static Process FindProcessWithWindowByName(string name){ public static Process FindProcessWithWindowByName(string name){
try{ try{

View File

@@ -2,7 +2,7 @@
using System.Linq; using System.Linq;
using Microsoft.Win32; using Microsoft.Win32;
namespace TweetDick.Migration.Helpers{ namespace TweetDck.Migration.Helpers{
static class ProgramRegistrySearch{ static class ProgramRegistrySearch{
public static string FindByDisplayName(string displayName){ public static string FindByDisplayName(string displayName){
Predicate<RegistryKey> predicate = key => displayName.Equals(key.GetValue("DisplayName") as string,StringComparison.OrdinalIgnoreCase); Predicate<RegistryKey> predicate = key => displayName.Equals(key.GetValue("DisplayName") as string,StringComparison.OrdinalIgnoreCase);

View File

@@ -1,4 +1,4 @@
namespace TweetDick.Migration{ namespace TweetDck.Migration{
enum MigrationDecision{ enum MigrationDecision{
/// <summary> /// <summary>
/// Copies the important files and then deletes the TweetDeck folder. /// Copies the important files and then deletes the TweetDeck folder.

View File

@@ -1,15 +1,15 @@
using Microsoft.Win32; using System;
using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Diagnostics; using System.Diagnostics;
using System.IO; using System.IO;
using System.Threading; using System.Threading;
using System.Threading.Tasks; using System.Threading.Tasks;
using System.Windows.Forms; using System.Windows.Forms;
using TweetDick.Core.Other; using Microsoft.Win32;
using TweetDick.Migration.Helpers; using TweetDck.Core.Other;
using TweetDck.Migration.Helpers;
namespace TweetDick.Migration{ namespace TweetDck.Migration{
static class MigrationManager{ static class MigrationManager{
private static readonly string TweetDeckPathParent = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData),"twitter"); private static readonly string TweetDeckPathParent = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData),"twitter");
private static readonly string TweetDeckPath = Path.Combine(TweetDeckPathParent,"TweetDeck"); private static readonly string TweetDeckPath = Path.Combine(TweetDeckPathParent,"TweetDeck");

View File

@@ -1,17 +1,18 @@
using CefSharp; using System;
using System;
using System.Diagnostics; using System.Diagnostics;
using System.Globalization; using System.Globalization;
using System.IO; using System.IO;
using System.Runtime.InteropServices; using System.Runtime.InteropServices;
using System.Text; using System.Text;
using System.Windows.Forms; using System.Windows.Forms;
using TweetDick.Configuration; using CefSharp;
using TweetDick.Core; using TweetDck.Configuration;
using TweetDick.Migration; using TweetDck.Core;
using TweetDck.Migration;
using TweetDck.Core.Utils;
[assembly: CLSCompliant(true)] [assembly: CLSCompliant(true)]
namespace TweetDick{ namespace TweetDck{
static class Program{ static class Program{
#if DUCK #if DUCK
public const string BrandName = "TweetDuck"; public const string BrandName = "TweetDuck";
@@ -21,21 +22,17 @@ namespace TweetDick{
public const string Website = "http://tweetdick.chylex.com"; public const string Website = "http://tweetdick.chylex.com";
#endif #endif
public const string VersionTag = "1.2";
public const string VersionFull = "1.2.0.0";
public static readonly string StoragePath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData),BrandName); public static readonly string StoragePath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData),BrandName);
private static readonly LockManager LockManager = new LockManager(Path.Combine(StoragePath,".lock")); private static readonly LockManager LockManager = new LockManager(Path.Combine(StoragePath,".lock"));
public static UserConfig UserConfig { get; private set; } public static UserConfig UserConfig { get; private set; }
private static string HeaderAcceptLanguage{ public static string LogFile{
get{ get{
string culture = CultureInfo.CurrentCulture.Name; return Path.Combine(AppDomain.CurrentDomain.BaseDirectory,"td-log.txt");
if (culture == "en"){
return "en-us,en";
}
else{
return culture.ToLowerInvariant()+",en;q=0.9";
}
} }
} }
@@ -45,6 +42,9 @@ namespace TweetDick{
[DllImport("Shell32.dll")] [DllImport("Shell32.dll")]
public static extern int SHChangeNotify(int eventId, int flags, IntPtr item1, IntPtr item2); public static extern int SHChangeNotify(int eventId, int flags, IntPtr item1, IntPtr item2);
[DllImport("user32.dll", EntryPoint = "SetWindowPos")]
public static extern bool SetWindowPos(int hWnd, int hWndOrder, int x, int y, int width, int height, uint flags);
[STAThread] [STAThread]
private static void Main(){ private static void Main(){
Application.EnableVisualStyles(); Application.EnableVisualStyles();
@@ -72,8 +72,8 @@ namespace TweetDick{
}; };
Cef.Initialize(new CefSettings{ Cef.Initialize(new CefSettings{
AcceptLanguageList = HeaderAcceptLanguage, AcceptLanguageList = BrowserUtils.HeaderAcceptLanguage,
UserAgent = BrandName+" "+Application.ProductVersion, UserAgent = BrowserUtils.HeaderUserAgent,
Locale = CultureInfo.CurrentCulture.TwoLetterISOLanguageName, Locale = CultureInfo.CurrentCulture.TwoLetterISOLanguageName,
CachePath = StoragePath, CachePath = StoragePath,
#if !DEBUG #if !DEBUG
@@ -95,29 +95,37 @@ namespace TweetDick{
Cef.Shutdown(); Cef.Shutdown();
}; };
Application.Run(new FormBrowser()); FormBrowser mainForm = new FormBrowser();
Application.Run(mainForm);
if (mainForm.UpdateInstallerPath != null){
Cef.Shutdown();
Process.Start(mainForm.UpdateInstallerPath,"/SP- /SILENT /NOICONS /CLOSEAPPLICATIONS");
Application.Exit();
}
} }
public static void HandleException(string message, Exception e){ public static void HandleException(string message, Exception e){
Log(e.ToString()); Log(e.ToString());
if (MessageBox.Show(message+"\r\nDo you want to open the log file to report the issue?",BrandName+" Has Failed :(",MessageBoxButtons.YesNo,MessageBoxIcon.Error,MessageBoxDefaultButton.Button2) == DialogResult.Yes){ if (MessageBox.Show(message+"\r\nDo you want to open the log file to report the issue?",BrandName+" Has Failed :(",MessageBoxButtons.YesNo,MessageBoxIcon.Error,MessageBoxDefaultButton.Button2) == DialogResult.Yes){
Process.Start(Path.Combine(AppDomain.CurrentDomain.BaseDirectory,"td-log.txt")); Process.Start(LogFile);
} }
} }
public static void Log(string data){ public static void Log(string data){
StringBuilder build = new StringBuilder(); StringBuilder build = new StringBuilder();
if (!File.Exists("td-log.txt")){ if (!File.Exists(LogFile)){
build.Append("Please, report all issues to: https://github.com/chylex/TweetDick/issues\r\n\r\n"); build.Append("Please, report all issues to: https://github.com/chylex/TweetDuck/issues\r\n\r\n");
} }
build.Append("[").Append(DateTime.Now.ToString("G")).Append("]\r\n"); build.Append("[").Append(DateTime.Now.ToString("G")).Append("]\r\n");
build.Append(data).Append("\r\n\r\n"); build.Append(data).Append("\r\n\r\n");
try{ try{
File.AppendAllText("td-log.txt",build.ToString(),Encoding.UTF8); File.AppendAllText(LogFile,build.ToString(),Encoding.UTF8);
}catch{ }catch{
// oops // oops
} }

View File

@@ -1,7 +1,7 @@
using System.Reflection; using System.Reflection;
using System.Runtime.InteropServices; using System.Runtime.InteropServices;
using TweetDick;
using System.Resources; using System.Resources;
using TweetDck;
// General Information about an assembly is controlled through the following // General Information about an assembly is controlled through the following
// set of attributes. Change these attribute values to modify the information // set of attributes. Change these attribute values to modify the information
@@ -33,7 +33,7 @@ using System.Resources;
// You can specify all the values or you can default the Build and Revision Numbers // You can specify all the values or you can default the Build and Revision Numbers
// by using the '*' as shown below: // by using the '*' as shown below:
// [assembly: AssemblyVersion("1.0.*")] // [assembly: AssemblyVersion("1.0.*")]
[assembly: AssemblyVersion("1.0.0.0")] [assembly: AssemblyVersion(Program.VersionFull)]
[assembly: AssemblyFileVersion("1.0.0.0")] [assembly: AssemblyFileVersion(Program.VersionFull)]
[assembly: NeutralResourcesLanguageAttribute("en")] [assembly: NeutralResourcesLanguageAttribute("en")]

View File

@@ -8,7 +8,7 @@
// </auto-generated> // </auto-generated>
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
namespace TweetDick.Properties { namespace TweetDck.Properties {
using System; using System;
@@ -39,7 +39,7 @@ namespace TweetDick.Properties {
internal static global::System.Resources.ResourceManager ResourceManager { internal static global::System.Resources.ResourceManager ResourceManager {
get { get {
if (object.ReferenceEquals(resourceMan, null)) { if (object.ReferenceEquals(resourceMan, null)) {
global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("TweetDick.Properties.Resources", typeof(Resources).Assembly); global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("TweetDck.Properties.Resources", typeof(Resources).Assembly);
resourceMan = temp; resourceMan = temp;
} }
return resourceMan; return resourceMan;

13
README.md Normal file
View File

@@ -0,0 +1,13 @@
# Build Instructions
The program was build using Visual Studio 2013. After opening the solution, make sure you have **CefSharp.WinForms** and **Microsoft.VC120.CRT.JetBrains** included - if not, download them using NuGet. For **CefSharp**, you will need version 49 or newer currently available as a pre-release.
```
PM> Install-Package CefSharp.WinForms -Pre
PM> Install-Package Microsoft.VC120.CRT.JetBrains
```
TweetD\*ck comes in two variants - TweetDick and TweetDuck. The solution includes both configurations under the names **Release Dick** and **Release Duck**, so make sure to select the correct one, or build both using Batch Build.
After building, run **_postbuild.bat** which deletes unnecessary files that CefSharp adds after post-build events >_>
Built files are then available in **bin/x86** and/or **bin/x64**.

View File

@@ -1,17 +1,23 @@
using System; using System;
using System.Collections.Generic;
using System.IO; using System.IO;
using System.Text; using System.Text;
using System.Windows.Forms; using System.Windows.Forms;
using System.Linq;
namespace TweetDick.Resources{ namespace TweetDck.Resources{
static class ScriptLoader{ static class ScriptLoader{
public static string LoadResource(string name){ public static string LoadResource(string name){
try{ try{
return File.ReadAllText(name,Encoding.UTF8); return File.ReadAllText(Path.Combine(AppDomain.CurrentDomain.BaseDirectory,name),Encoding.UTF8);
}catch(Exception ex){ }catch(Exception ex){
MessageBox.Show("Unfortunately, "+Program.BrandName+" could not load the "+name+" file. The program will continue running with limited functionality.\r\n\r\n"+ex.Message,Program.BrandName+" Has Failed :(",MessageBoxButtons.OK,MessageBoxIcon.Error); MessageBox.Show("Unfortunately, "+Program.BrandName+" could not load the "+name+" file. The program will continue running with limited functionality.\r\n\r\n"+ex.Message,Program.BrandName+" Has Failed :(",MessageBoxButtons.OK,MessageBoxIcon.Error);
return null; return null;
} }
} }
public static IList<string> LoadResources(params string[] names){
return names.Select(LoadResource).ToList();
}
} }
} }

View File

@@ -1,38 +1,28 @@
(function($,$TD){ (function($,$TD,TD){
// //
// Constant: List of valid font size classes. // Variable: Says whether TweetD*ck events was initialized.
//
var fontSizeClasses = [ "txt-base-smallest", "txt-base-small", "txt-base-medium", "txt-base-large", "txt-base-largest" ];
//
// Variable: Says whether TweetDick events was initialized.
// //
var isInitialized = false; var isInitialized = false;
// //
// Variable: Previous font size class in the <html> tag. // Function: Initializes TweetD*ck events. Called after the website app is loaded.
// //
var prevFontSizeClass; var initializeTweetDck = function(){
//
// Function: Initializes TweetDick events. Called after the website app is loaded.
//
var initializeTweetDick = function(){
// Settings button hook // Settings button hook
$("[data-action='settings-menu']").click(function(){ $("[data-action='settings-menu']").click(function(){
setTimeout(function(){ setTimeout(function(){
var menu = $(".js-dropdown-content").children("ul").first(); var menu = $(".js-dropdown-content").children("ul").first();
if (menu.length === 0)return; if (menu.length === 0)return;
menu.children(".drp-h-divider").last().after('<li class="is-selectable" data-std><a href="#" data-action>'+$TD.brandName+'</a></li><li class="drp-h-divider"></li>'); menu.children(".drp-h-divider").last().after('<li class="is-selectable" data-std><a href="#" data-action>'+$TD.brandName+' settings</a></li><li class="drp-h-divider"></li>');
var tweetDickBtn = menu.children("[data-std]").first(); var tweetDckBtn = menu.children("[data-std]").first();
tweetDickBtn.on("click","a",function(){ tweetDckBtn.on("click","a",function(){
$TD.openSettingsMenu(); $TD.openSettingsMenu();
}); });
tweetDickBtn.hover(function(){ tweetDckBtn.hover(function(){
$(this).addClass("is-selected"); $(this).addClass("is-selected");
},function(){ },function(){
$(this).removeClass("is-selected"); $(this).removeClass("is-selected");
@@ -40,105 +30,68 @@
},0); },0);
}); });
// Tweet notifications // Notification handling
(function(){ $.subscribe("/notifications/new",function(obj){
var columns = $(".js-app-columns").first(); for(var item of obj.items){
onNewTweet(obj.column,item);
var refreshColumnObservers = function(){ }
columns.children().each(function(){ });
registerTweetObserverForColumn($(this));
});
};
new MutationObserver(refreshColumnObservers).observe(columns[0],{
childList: true
});
refreshColumnObservers();
})();
// Popup notifications
window.TD.controller.notifications.hasNotifications = function(){
return true;
};
window.TD.controller.notifications.isPermissionGranted = function(){
return true;
};
// Finish init // Finish init
$TD.loadFontSizeClass(TD.settings.getFontSize());
$TD.loadNotificationHeadContents(getNotificationHeadContents());
isInitialized = true; isInitialized = true;
}; };
// //
// Function: Registers an observer to a TweetDeck column, which reports new tweets. // Function: Prepends code at the beginning of a function. If the prepended function returns true, execution of the original function is cancelled.
// //
var registerTweetObserverForColumn = function(column){ var prependToFunction = function(func, extension){
if (column[0].hasAttribute("data-std-observed"))return; return function(){
return extension.apply(this,arguments) === true ? undefined : func.apply(this,arguments);
var mid = column; };
mid = mid.children().first(); };
mid = mid.children().first();
mid = mid.children(".js-column-content").first(); //
mid = mid.children(".js-column-scroller").first(); // Function: Appends code at the end of a function.
//
var container = mid.children(".js-chirp-container").first(); var appendToFunction = function(func, extension){
if (container.length === 0)return; return function(){
var res = func.apply(this,arguments);
var scroller = container.parent(); extension.apply(this,arguments);
return res;
new MutationObserver(function(mutations){ };
if (!container[0].hasAttribute("data-std-loaded")){
container[0].setAttribute("data-std-loaded","");
return;
}
var data = TD.controller.columnManager.get(column.attr("data-column"));
if (!data.model.getHasNotification())return;
if (scroller.scrollTop() != 0)return;
Array.prototype.forEach.call(mutations,function(mutation){
Array.prototype.forEach.call(mutation.addedNodes,function(node){
if (node.tagName !== "ARTICLE")return;
onNewTweet(column,node);
});
});
}).observe(container[0],{
childList: true
});
column[0].setAttribute("data-std-observed","");
}; };
// //
// Function: Event callback for a new tweet. // Function: Event callback for a new tweet.
// //
var onNewTweet = function(column, tweet){ var onNewTweet = function(column, tweet){
var html = $(tweet.outerHTML); if (column.model.getHasNotification()){
var body = html.find(".tweet-body").first(); var html = $(tweet.render({
withFooter: false,
body.children("div.js-quote-detail").each(function(){ withTweetActions: false,
$(this).html("(quoted tweet)"); withMediaPreview: false
}); }));
body.children().not("p,div.js-quote-detail").remove(); html.css("border","0");
$TD.onTweetPopup(html.html(),html.find(".js-tweet-text:first").text().length); // TODO column & remove pic links from text() var body = html.find(".tweet-body").first();
};
body.children("div.js-quote-detail").each(function(){
// $(this).html("(quoted tweet)");
// Function: Retrieves the font size using <html> class attribute. $(this).removeClass("padding-al");
// $(this).css("padding","6px");
var getFontSizeClass = function(){ });
for(var index = 0; index < fontSizeClasses.length; index++){
if (document.documentElement.classList.contains(fontSizeClasses[index])){ body.children("footer").remove();
return fontSizeClasses[index];
} $TD.onTweetPopup(html.html(),tweet.fullLength); // TODO column
}
else if (column.model.getHasSound()){
$TD.onTweetSound(); // TODO disable original
} }
return fontSizeClasses[0];
}; };
// //
@@ -155,7 +108,7 @@
}; };
// //
// Block: Observe the app <div> element and initialize TweetDick whenever possible. // Block: Observe the app <div> element and initialize TweetD*ck whenever possible.
// //
var app = $("body").children(".js-app"); var app = $("body").children(".js-app");
@@ -164,7 +117,7 @@
isInitialized = false; isInitialized = false;
} }
else if (!isInitialized && !app.hasClass("is-hidden")){ else if (!isInitialized && !app.hasClass("is-hidden")){
initializeTweetDick(); initializeTweetDck();
} }
}).observe(app[0],{ }).observe(app[0],{
attributes: true, attributes: true,
@@ -172,31 +125,28 @@
}); });
// //
// Block: Observe changes in <html> class to update font size. // Block: Hook into settings object to detect when the settings change.
// //
new MutationObserver(function(mutations){ TD.settings.setFontSize = appendToFunction(TD.settings.setFontSize,function(name){
var fsClass = getFontSizeClass(); $TD.loadFontSizeClass(name);
});
if (fsClass != prevFontSizeClass){
prevFontSizeClass = fsClass; TD.settings.setTheme = appendToFunction(TD.settings.setTheme,function(){
$TD.loadFontSizeClass(fsClass); setTimeout(function(){
} $TD.loadNotificationHeadContents(getNotificationHeadContents());
}).observe(document.documentElement,{ },0);
attributes: true,
attributeFilter: [ "class" ]
}); });
// //
// Block: Observe stylesheet swapping. // Block: Force popup notification settings
// //
new MutationObserver(function(mutations){ TD.controller.notifications.hasNotifications = function(){
$TD.loadNotificationHeadContents(getNotificationHeadContents()); return true;
}).observe(document.head.querySelector("[http-equiv='Default-Style']"),{ };
attributes: true,
attributeFilter: [ "content" ] TD.controller.notifications.isPermissionGranted = function(){
}); return true;
};
$TD.loadNotificationHeadContents(getNotificationHeadContents());
// //
// Block: Hook into links to bypass default open function // Block: Hook into links to bypass default open function
@@ -215,7 +165,7 @@
var me = $(this); var me = $(this);
var rel = me.attr("rel"); var rel = me.attr("rel");
if (!me.is(".link-complex") && !(rel === "mediaPreview" && me.closest("#open-modal").length === 0) && rel !== "list"){ if (!me.is(".link-complex") && !(rel === "mediaPreview" && me.closest("#open-modal").length === 0) && rel !== "list" && rel !== "user"){
$TD.openBrowser(me.attr("href")); $TD.openBrowser(me.attr("href"));
} }
@@ -230,4 +180,85 @@
onUrlOpened(); onUrlOpened();
}; };
})(); })();
})($,$TD);
TD.util.maybeOpenClickExternally = prependToFunction(TD.util.maybeOpenClickExternally,function(e){
if (e.ctrlKey){
$TD.openBrowser(e.currentTarget.getAttribute("href"));
e.preventDefault();
e.stopPropagation();
e.stopImmediatePropagation();
return true;
}
});
//
// Block: Expand shortened links on hover.
//
(function(){
var cutStart = function(str, search){
return _.startsWith(str,search) ? str.substr(search.length) : str;
};
$(document.body).delegate("a[data-full-url]","mouseenter mouseleave",function(e){
var me = $(this);
if (e.type === "mouseenter"){
var text = me.text();
if (text.charCodeAt(text.length-1) !== 8230){ // horizontal ellipsis
return;
}
var expanded = me.attr("data-full-url");
expanded = cutStart(expanded,"https://");
expanded = cutStart(expanded,"http://");
expanded = cutStart(expanded,"www.");
me.css("word-break","break-all");
me.attr("td-prev-text",text);
me.text(expanded);
}
else if (e.type === "mouseleave"){
var prevText = me.attr("td-prev-text");
if (prevText){
me.text(prevText);
}
}
});
})();
//
// Block: Allow bypassing of t.co in context menus.
//
$(document.body).delegate("a","contextmenu",function(){
$TD.setLastRightClickedLink($(this).attr("data-full-url") || "");
});
//
// Block: Hook into the notification sound effect.
//
(function(){
var soundEle = document.getElementById("update-sound");
soundEle.play = prependToFunction(soundEle.play,function(){
return $TD.muteNotifications;
});
})();
/* TODO document.getElementById("update-sound").play = function(){
$TD.onTweetSound();
};*/
//
// Block: Hook into mp4 video element clicking
//
$(document.body).delegate("video.js-media-gif","click",function(e){
var src = $(this).attr("src");
if (src.endsWith(".mp4")){
$TD.openBrowser(src);
e.preventDefault();
}
});
})($,$TD,TD);

View File

@@ -1,11 +1,35 @@
(function($TD){ (function($TD){
// //
// Block: Hook into links to bypass default open function // Function: Bubbles up the parents until it hits an element with the specified tag (includes the first element), and returns true if the search was successful.
//
var bubbleParents = function(element, tag, callback){
do{
if (element.tagName == "A"){
callback(element);
return true;
}
}while((element = element.parentElement) != null);
return false;
};
//
// Block: Hook into links to bypass default open function.
// //
document.body.addEventListener("click",function(e){ document.body.addEventListener("click",function(e){
if (e.target.tagName == "A"){ if (bubbleParents(e.target,"A",function(ele){
$TD.openBrowser(e.target.getAttribute("href")); $TD.openBrowser(ele.getAttribute("href"));
})){
e.preventDefault(); e.preventDefault();
} }
}); });
//
// Block: Allow bypassing of t.co in context menus.
//
document.body.addEventListener("contextmenu",function(e){
bubbleParents(e.target,"A",function(ele){
$TD.setLastRightClickedLink(element.getAttribute("data-full-url") || "");
});
});
})($TD); })($TD);

121
Resources/update.js Normal file
View File

@@ -0,0 +1,121 @@
(function($,$TD){
//
// Variable: Current timeout ID for update checking.
//
var updateCheckTimeoutID;
//
// Function: Creates the update notification element. Removes the old one if already exists.
//
var createUpdateNotificationElement = function(version, download){
var ele = $("#tweetdck-update");
var existed = ele.length > 0;
if (existed > 0){
ele.remove();
}
var html = [
"<div id='tweetdck-update'>",
"<p class='tdu-title'>"+$TD.brandName+" Update</p>",
"<p class='tdu-info'>Version "+version+" is now available.</p>",
"<div class='tdu-buttons'>",
"<button class='btn btn-positive tdu-btn-download'><span class='label'>Download</button>",
"<button class='btn btn-negative tdu-btn-dismiss'><span class='label'>Dismiss</button>",
"</div>",
"</div>"
];
$(document.body).append(html.join(""));
ele = $("#tweetdck-update");
var buttonDiv = ele.children("div.tdu-buttons").first();
ele.css({
color: "#fff",
backgroundColor: "rgb(32,94,138)",
position: "absolute",
left: "4px",
bottom: "4px",
width: "192px",
height: "86px",
display: existed ? "block" : "none",
borderRadius: "2px",
zIndex: 9999
});
ele.children("p.tdu-title").first().css({
fontSize: "17px",
fontWeight: "bold",
textAlign: "center",
letterSpacing: "0.2px",
margin: "4px auto 2px"
});
ele.children("p.tdu-info").first().css({
fontSize: "12px",
textAlign: "center",
margin: "2px auto 6px"
});
buttonDiv.css({
textAlign: "center"
});
buttonDiv.children().css({
margin: "0 4px",
minHeight: "25px",
boxShadow: "1px 1px 1px rgba(17,17,17,0.5)"
});
buttonDiv.find("span").css({
verticalAlign: "baseline"
});
ele.find("span.tdu-data-tag").first().css({
cursor: "pointer",
textDecoration: "underline"
});
buttonDiv.children(".tdu-btn-download").click(function(){
ele.remove();
$TD.onUpdateAccepted(version,download);
});
buttonDiv.children(".tdu-btn-dismiss").click(function(){
$TD.onUpdateDismissed(version);
ele.slideUp(function(){ ele.remove(); });
});
if (!existed){
ele.slideDown();
}
return ele;
};
//
// Function: Runs an update check and updates all DOM elements appropriately
//
var runUpdateCheck = function(){
clearTimeout(updateCheckTimeoutID);
updateCheckTimeoutID = setTimeout(runUpdateCheck,1000*60*60); // 1 hour
if (!$TD.updateCheckEnabled)return;
$.getJSON("https://api.github.com/repos/chylex/"+$TD.brandName+"/releases/latest",function(response){
var tagName = response.tag_name;
if (tagName != $TD.versionTag && tagName != $TD.dismissedVersionTag && response.assets.length > 0){
createUpdateNotificationElement(tagName,response.assets[0].browser_download_url);
}
});
};
//
// Block: Setup global functions.
//
window.TDGF_runUpdateCheck = runUpdateCheck;
runUpdateCheck();
})($,$TD);

View File

@@ -9,7 +9,7 @@
<ProjectGuid>{2389A7CD-E0D3-4706-8294-092929A33A2D}</ProjectGuid> <ProjectGuid>{2389A7CD-E0D3-4706-8294-092929A33A2D}</ProjectGuid>
<OutputType>WinExe</OutputType> <OutputType>WinExe</OutputType>
<AppDesignerFolder>Properties</AppDesignerFolder> <AppDesignerFolder>Properties</AppDesignerFolder>
<RootNamespace>TweetDick</RootNamespace> <RootNamespace>TweetDck</RootNamespace>
<AssemblyName Condition=" '$(Configuration)' == 'Debug' ">TweetDick</AssemblyName> <AssemblyName Condition=" '$(Configuration)' == 'Debug' ">TweetDick</AssemblyName>
<AssemblyName Condition=" '$(Configuration)' == 'Release Dick' ">TweetDick</AssemblyName> <AssemblyName Condition=" '$(Configuration)' == 'Release Dick' ">TweetDick</AssemblyName>
<AssemblyName Condition=" '$(Configuration)' == 'Release Duck' ">TweetDuck</AssemblyName> <AssemblyName Condition=" '$(Configuration)' == 'Release Duck' ">TweetDuck</AssemblyName>
@@ -77,13 +77,15 @@
<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\Controls\ControlExtensions.cs" />
<Compile Include="Core\Controls\FlatProgressBar.cs"> <Compile Include="Core\Controls\FlatProgressBar.cs">
<SubType>Component</SubType> <SubType>Component</SubType>
</Compile> </Compile>
<Compile Include="Core\Controls\FlatProgressBar.Designer.cs"> <Compile Include="Core\Controls\FlatProgressBar.Designer.cs">
<DependentUpon>FlatProgressBar.cs</DependentUpon> <DependentUpon>FlatProgressBar.cs</DependentUpon>
</Compile> </Compile>
<Compile Include="Core\Handling\ContextMenuHandler.cs" /> <Compile Include="Core\Handling\ContextMenuBase.cs" />
<Compile Include="Core\Handling\ContextMenuBrowser.cs" />
<Compile Include="Core\FormBrowser.cs"> <Compile Include="Core\FormBrowser.cs">
<SubType>Form</SubType> <SubType>Form</SubType>
</Compile> </Compile>
@@ -96,6 +98,7 @@
<Compile Include="Core\FormNotification.Designer.cs"> <Compile Include="Core\FormNotification.Designer.cs">
<DependentUpon>FormNotification.cs</DependentUpon> <DependentUpon>FormNotification.cs</DependentUpon>
</Compile> </Compile>
<Compile Include="Core\Handling\ContextMenuNotification.cs" />
<Compile Include="Core\Handling\TweetNotification.cs" /> <Compile Include="Core\Handling\TweetNotification.cs" />
<Compile Include="Core\Controls\RichTextLabel.cs"> <Compile Include="Core\Controls\RichTextLabel.cs">
<SubType>Component</SubType> <SubType>Component</SubType>
@@ -122,6 +125,20 @@
<Compile Include="Core\Other\FormSettings.Designer.cs"> <Compile Include="Core\Other\FormSettings.Designer.cs">
<DependentUpon>FormSettings.cs</DependentUpon> <DependentUpon>FormSettings.cs</DependentUpon>
</Compile> </Compile>
<Compile Include="Core\Other\FormUpdateDownload.cs">
<SubType>Form</SubType>
</Compile>
<Compile Include="Core\Other\FormUpdateDownload.Designer.cs">
<DependentUpon>FormUpdateDownload.cs</DependentUpon>
</Compile>
<Compile Include="Core\TrayIcon.cs">
<SubType>Component</SubType>
</Compile>
<Compile Include="Core\TrayIcon.Designer.cs">
<DependentUpon>TrayIcon.cs</DependentUpon>
</Compile>
<Compile Include="Core\Utils\BrowserUtils.cs" />
<Compile Include="Core\Utils\UpdateInfo.cs" />
<Compile Include="Migration\FormMigrationQuestion.cs"> <Compile Include="Migration\FormMigrationQuestion.cs">
<SubType>Form</SubType> <SubType>Form</SubType>
</Compile> </Compile>
@@ -201,6 +218,12 @@
<TargetPath>notification.js</TargetPath> <TargetPath>notification.js</TargetPath>
</ContentWithTargetPath> </ContentWithTargetPath>
</ItemGroup> </ItemGroup>
<ItemGroup>
<ContentWithTargetPath Include="Resources\update.js">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
<TargetPath>update.js</TargetPath>
</ContentWithTargetPath>
</ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" /> <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
<Target Name="EnsureNuGetPackageBuildImports" BeforeTargets="PrepareForBuild"> <Target Name="EnsureNuGetPackageBuildImports" BeforeTargets="PrepareForBuild">
<PropertyGroup> <PropertyGroup>
@@ -217,10 +240,12 @@
<Import Project="packages\CefSharp.Common.49.0.0-pre02\build\CefSharp.Common.targets" Condition="Exists('packages\CefSharp.Common.49.0.0-pre02\build\CefSharp.Common.targets')" /> <Import Project="packages\CefSharp.Common.49.0.0-pre02\build\CefSharp.Common.targets" Condition="Exists('packages\CefSharp.Common.49.0.0-pre02\build\CefSharp.Common.targets')" />
<PropertyGroup> <PropertyGroup>
<PostBuildEvent>del "$(TargetPath).config" <PostBuildEvent>del "$(TargetPath).config"
xcopy "$(ProjectDir)LICENSE" "$(TargetDir)" /Y xcopy "$(ProjectDir)LICENSE.md" "$(TargetDir)" /Y
del "$(TargetDir)LICENSE.txt" del "$(TargetDir)LICENSE.txt"
ren "$(TargetDir)LICENSE" "LICENSE.txt" ren "$(TargetDir)LICENSE.md" "LICENSE.txt"
xcopy "$(ProjectDir)Libraries\CEFSHARP-LICENSE.txt" "$(TargetDir)" /Y</PostBuildEvent> xcopy "$(ProjectDir)Libraries\CEFSHARP-LICENSE.txt" "$(TargetDir)" /Y
xcopy "$(ProjectDir)packages\Microsoft.VC120.CRT.JetBrains.12.0.21005.2\DotFiles\msvcp120.dll" "$(TargetDir)" /Y
xcopy "$(ProjectDir)packages\Microsoft.VC120.CRT.JetBrains.12.0.21005.2\DotFiles\msvcr120.dll" "$(TargetDir)" /Y</PostBuildEvent>
</PropertyGroup> </PropertyGroup>
<!-- To modify your build process, add your task inside one of the targets below and uncomment it. <!-- 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. Other similar extension points exist, see Microsoft.Common.targets.

View File

@@ -3,7 +3,7 @@ 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}") = "TweetDick", "TweetDick.csproj", "{2389A7CD-E0D3-4706-8294-092929A33A2D}" Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "TweetDck", "TweetDck.csproj", "{2389A7CD-E0D3-4706-8294-092929A33A2D}"
EndProject EndProject
Global Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution GlobalSection(SolutionConfigurationPlatforms) = preSolution