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

Compare commits

..

36 Commits
1.0 ... 1.1

Author SHA1 Message Date
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
43 changed files with 1054 additions and 206 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;

View File

@@ -3,13 +3,16 @@ 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.Handling;
using TweetDick.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
@@ -20,12 +23,18 @@ namespace TweetDick.Configuration{
public Point WindowLocation { get; set; } public Point WindowLocation { get; set; }
public Size WindowSize { get; set; } public Size WindowSize { get; set; }
public bool MinimizeToTray { 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; }
public Point CustomNotificationPosition { get; set; } public Point CustomNotificationPosition { get; set; }
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;
@@ -43,15 +52,36 @@ namespace TweetDick.Configuration{
[NonSerialized] [NonSerialized]
private string file; private string file;
private int fileVersion;
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 +119,10 @@ namespace TweetDick.Configuration{
} }
} }
if (config != null){
config.UpgradeFile();
}
break; break;
}catch(FileNotFoundException){ }catch(FileNotFoundException){
}catch(Exception e){ }catch(Exception e){
@@ -102,5 +136,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,33 @@
/// 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.components = new System.ComponentModel.Container();
this.trayIcon = new System.Windows.Forms.NotifyIcon(this.components);
this.SuspendLayout(); this.SuspendLayout();
// //
// trayIcon
//
this.trayIcon.Icon = global::TweetDck.Properties.Resources.icon;
this.trayIcon.Click += new System.EventHandler(this.trayIcon_Click);
//
// 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 = global::TweetDck.Properties.Resources.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.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 System.Windows.Forms.NotifyIcon trayIcon;
} }
} }

View File

@@ -1,15 +1,16 @@
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;
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 +18,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 +28,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 +37,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);
@@ -43,20 +48,13 @@ namespace TweetDick.Core{
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){ trayIcon.Text = Program.BrandName;
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,6 +72,7 @@ namespace TweetDick.Core{
WindowState = FormWindowState.Maximized; WindowState = FormWindowState.Maximized;
} }
prevState = WindowState;
isLoaded = true; isLoaded = true;
} }
@@ -96,30 +95,47 @@ namespace TweetDick.Core{
} }
} }
private void FormBrowser_Resize(object sender, EventArgs e){
if (!isLoaded)return;
if (WindowState != prevState){
prevState = WindowState;
if (WindowState == FormWindowState.Minimized){
if (Config.MinimizeToTray){
Hide(); // hides taskbar too?! welp that works I guess
trayIcon.Visible = true;
}
}
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;
if (Location.X != -32000){
Config.IsMaximized = WindowState == FormWindowState.Maximized;
Config.WindowLocation = Location; Config.WindowLocation = Location;
Config.WindowSize = Size; Config.WindowSize = Size;
Config.Save(); Config.Save();
} }
}
private void FormBrowser_WindowStateChanged(object sender, EventArgs e){ private void trayIcon_Click(object sender, EventArgs e){
if (!isLoaded)return; isLoaded = false;
Show();
SetupWindow();
Config.IsMaximized = WindowState != FormWindowState.Normal; trayIcon.Visible = false;
FormBrowser_ResizeEnd(sender,e);
} }
// 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 +143,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 +176,24 @@ namespace TweetDick.Core{
public void OnTweetPopup(TweetNotification tweet){ public void OnTweetPopup(TweetNotification tweet){
notification.ShowNotification(tweet); notification.ShowNotification(tweet);
} }
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 FlatProgressBar();
this.SuspendLayout(); this.SuspendLayout();
// //
// panelBrowser // panelBrowser

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;
@@ -33,7 +33,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){
@@ -111,6 +111,15 @@ namespace TweetDick.Core{
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];
} }
@@ -170,21 +179,5 @@ namespace TweetDick.Core{
e.Cancel = true; 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)){
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(parameters.UnfilteredLinkUrl,TextDataFormat.Text);
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.Text);
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

@@ -1,38 +1,41 @@
using CefSharp; using CefSharp;
namespace TweetDick.Core.Handling{ namespace TweetDck.Core.Handling{
class ContextMenuHandler : IContextMenuHandler{ class ContextMenuBrowser : ContextMenuBase{
private const int MenuSettings = 26500; private const int MenuSettings = 26600;
private const int MenuAbout = 26501; private const int MenuAbout = 26601;
private readonly FormBrowser form; private readonly FormBrowser form;
public ContextMenuHandler(FormBrowser form){ public ContextMenuBrowser(FormBrowser form){
this.form = form; this.form = form;
} }
public void OnBeforeContextMenu(IWebBrowser browserControl, IBrowser browser, IFrame frame, IContextMenuParams parameters, IMenuModel model){ public override void OnBeforeContextMenu(IWebBrowser browserControl, IBrowser browser, IFrame frame, IContextMenuParams parameters, IMenuModel model){
model.Remove(CefMenuCommand.Back); model.Remove(CefMenuCommand.Back);
model.Remove(CefMenuCommand.Forward); model.Remove(CefMenuCommand.Forward);
model.Remove(CefMenuCommand.Print); model.Remove(CefMenuCommand.Print);
model.Remove(CefMenuCommand.ViewSource); model.Remove(CefMenuCommand.ViewSource);
if (model.Count > 0 && model.GetTypeAt(model.Count-1) == MenuItemType.Separator){ RemoveSeparatorIfFirst(model);
model.RemoveAt(model.Count-1);
} base.OnBeforeContextMenu(browserControl,browser,frame,parameters,model);
model.AddItem(CefMenuCommand.Reload,"Reload"); model.AddItem(CefMenuCommand.Reload,"Reload");
model.AddSeparator(); model.AddSeparator();
if (TweetNotification.IsReady){ if (TweetNotification.IsReady){
model.AddItem((CefMenuCommand)MenuSettings,"Settings"); model.AddItem((CefMenuCommand)MenuSettings,"Settings");
model.AddSeparator();
} }
model.AddItem((CefMenuCommand)MenuAbout,"About "+Program.BrandName); model.AddItem((CefMenuCommand)MenuAbout,"About "+Program.BrandName);
} }
public bool OnContextMenuCommand(IWebBrowser browserControl, IBrowser browser, IFrame frame, IContextMenuParams parameters, CefMenuCommand commandId, CefEventFlags eventFlags){ public override bool OnContextMenuCommand(IWebBrowser browserControl, IBrowser browser, IFrame frame, IContextMenuParams parameters, CefMenuCommand commandId, CefEventFlags eventFlags){
if (base.OnContextMenuCommand(browserControl,browser,frame,parameters,commandId,eventFlags)){
return true;
}
switch((int)commandId){ switch((int)commandId){
case MenuSettings: case MenuSettings:
form.InvokeSafe(() => { form.InvokeSafe(() => {
@@ -51,11 +54,5 @@ namespace TweetDick.Core.Handling{
return false; 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,16 @@
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);
}
public override bool OnContextMenuCommand(IWebBrowser browserControl, IBrowser browser, IFrame frame, IContextMenuParams parameters, CefMenuCommand commandId, CefEventFlags eventFlags){
return false;
}
}
}

View File

@@ -1,6 +1,6 @@
using System.Diagnostics; using TweetDck.Core.Utils;
namespace TweetDick.Core.Handling{ namespace TweetDck.Core.Handling{
class TweetDeckBridge{ class TweetDeckBridge{
private readonly FormBrowser form; private readonly FormBrowser form;
@@ -10,6 +10,24 @@ namespace TweetDick.Core.Handling{
} }
} }
public string VersionTag{
get{
return Program.VersionTag;
}
}
public bool UpdateCheckEnabled{
get{
return Program.UserConfig.EnableUpdateCheck;
}
}
public string DismissedVersionTag{
get{
return Program.UserConfig.DismissedUpdate ?? string.Empty;
}
}
public TweetDeckBridge(FormBrowser form){ public TweetDeckBridge(FormBrowser form){
this.form = form; this.form = form;
} }
@@ -38,12 +56,25 @@ namespace TweetDick.Core.Handling{
}); });
} }
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>");

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,23 @@
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.checkNotificationTimer = new System.Windows.Forms.CheckBox();
this.checkMinimizeTray = 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.checkUpdateNotifications = new System.Windows.Forms.CheckBox();
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
@@ -181,6 +187,70 @@
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.checkUpdateNotifications);
this.groupUserInterface.Controls.Add(this.checkNotificationTimer);
this.groupUserInterface.Controls.Add(this.checkMinimizeTray);
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";
//
// checkNotificationTimer
//
this.checkNotificationTimer.AutoSize = true;
this.checkNotificationTimer.Location = new System.Drawing.Point(6, 43);
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);
//
// checkMinimizeTray
//
this.checkMinimizeTray.AutoSize = true;
this.checkMinimizeTray.Location = new System.Drawing.Point(6, 20);
this.checkMinimizeTray.Name = "checkMinimizeTray";
this.checkMinimizeTray.Size = new System.Drawing.Size(102, 17);
this.checkMinimizeTray.TabIndex = 0;
this.checkMinimizeTray.Text = "Minimize to Tray";
this.checkMinimizeTray.UseVisualStyleBackColor = true;
this.checkMinimizeTray.CheckedChanged += new System.EventHandler(this.checkMinimizeTray_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 +259,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,22 +318,16 @@
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 // checkUpdateNotifications
// //
this.tableLayout.ColumnCount = 2; this.checkUpdateNotifications.AutoSize = true;
this.tableLayout.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 50F)); this.checkUpdateNotifications.Location = new System.Drawing.Point(6, 67);
this.tableLayout.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 50F)); this.checkUpdateNotifications.Name = "checkUpdateNotifications";
this.tableLayout.Controls.Add(this.groupNotificationLocation, 0, 0); this.checkUpdateNotifications.Size = new System.Drawing.Size(122, 17);
this.tableLayout.Controls.Add(this.groupNotificationDuration, 1, 0); this.checkUpdateNotifications.TabIndex = 5;
this.tableLayout.Dock = System.Windows.Forms.DockStyle.Fill; this.checkUpdateNotifications.Text = "Update Notifications";
this.tableLayout.GrowStyle = System.Windows.Forms.TableLayoutPanelGrowStyle.FixedSize; this.checkUpdateNotifications.UseVisualStyleBackColor = true;
this.tableLayout.Location = new System.Drawing.Point(0, 0); this.checkUpdateNotifications.CheckedChanged += new System.EventHandler(this.checkUpdateNotifications_CheckedChanged);
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
// //
@@ -272,7 +336,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 = global::TweetDck.Properties.Resources.icon;
this.MaximizeBox = false; this.MaximizeBox = false;
this.MinimizeBox = false; this.MinimizeBox = false;
this.Name = "FormSettings"; this.Name = "FormSettings";
@@ -281,9 +345,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 +365,18 @@
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 checkMinimizeTray;
private System.Windows.Forms.ComboBox comboBoxDisplay; private System.Windows.Forms.CheckBox checkNotificationTimer;
private System.Windows.Forms.TableLayoutPanel tableLayout; private System.Windows.Forms.CheckBox checkUpdateNotifications;
} }
} }

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{
@@ -54,6 +54,9 @@ namespace TweetDick.Core.Other{
comboBoxDisplay.SelectedIndex = Math.Min(comboBoxDisplay.Items.Count-1,Config.NotificationDisplay); comboBoxDisplay.SelectedIndex = Math.Min(comboBoxDisplay.Items.Count-1,Config.NotificationDisplay);
trackBarEdgeDistance.Value = Config.NotificationEdgeDistance; trackBarEdgeDistance.Value = Config.NotificationEdgeDistance;
checkMinimizeTray.Checked = Config.MinimizeToTray;
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 +118,24 @@ namespace TweetDick.Core.Other{
notification.ShowNotificationForSettings(true); notification.ShowNotificationForSettings(true);
} }
private void checkMinimizeTray_CheckedChanged(object sender, EventArgs e){
if (!isLoaded)return;
Config.MinimizeToTray = checkMinimizeTray.Checked;
}
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 = global::TweetDck.Properties.Resources.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();
});
}
}
}

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,16 @@ 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.1";
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";
}
} }
} }
@@ -72,8 +68,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 +91,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("1.1.0.0")]
[assembly: AssemblyFileVersion("1.0.0.0")] [assembly: AssemblyFileVersion("1.1.0.0")]
[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

@@ -3,11 +3,11 @@ using System.IO;
using System.Text; using System.Text;
using System.Windows.Forms; using System.Windows.Forms;
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;

View File

@@ -5,7 +5,7 @@
var fontSizeClasses = [ "txt-base-smallest", "txt-base-small", "txt-base-medium", "txt-base-large", "txt-base-largest" ]; var fontSizeClasses = [ "txt-base-smallest", "txt-base-small", "txt-base-medium", "txt-base-large", "txt-base-largest" ];
// //
// Variable: Says whether TweetDick events was initialized. // Variable: Says whether TweetD*ck events was initialized.
// //
var isInitialized = false; var isInitialized = false;
@@ -15,9 +15,14 @@
var prevFontSizeClass; var prevFontSizeClass;
// //
// Function: Initializes TweetDick events. Called after the website app is loaded. // Variable: Current timeout ID for update checking.
// //
var initializeTweetDick = function(){ var updateCheckTimeoutID;
//
// Function: Initializes TweetD*ck events. Called after the website app is loaded.
//
var initializeTweetDck = function(){
// Settings button hook // Settings button hook
$("[data-action='settings-menu']").click(function(){ $("[data-action='settings-menu']").click(function(){
setTimeout(function(){ setTimeout(function(){
@@ -26,13 +31,13 @@
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+'</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");
@@ -57,7 +62,7 @@
refreshColumnObservers(); refreshColumnObservers();
})(); })();
// Popup notifications // Force popup notification settings
window.TD.controller.notifications.hasNotifications = function(){ window.TD.controller.notifications.hasNotifications = function(){
return true; return true;
}; };
@@ -66,6 +71,9 @@
return true; return true;
}; };
// Run update check
runUpdateCheck();
// Finish init // Finish init
isInitialized = true; isInitialized = true;
}; };
@@ -119,13 +127,20 @@
var html = $(tweet.outerHTML); var html = $(tweet.outerHTML);
var body = html.find(".tweet-body").first(); var body = html.find(".tweet-body").first();
if (html.find(".icon-reply").length > 0){
return; // ignore sent messages
}
body.children("div.js-quote-detail").each(function(){ body.children("div.js-quote-detail").each(function(){
$(this).html("(quoted tweet)"); $(this).html("(quoted tweet)");
}); });
body.children().not("p,div.js-quote-detail").remove(); body.children().not("p,span,div.js-quote-detail").remove();
$TD.onTweetPopup(html.html(),html.find(".js-tweet-text:first").text().length); // TODO column & remove pic links from text() var characters = html.find(".js-tweet-text:first").text().length;
if (characters == 0)return;
$TD.onTweetPopup(html.html(),characters); // TODO column & remove pic links from text()
}; };
// //
@@ -155,7 +170,115 @@
}; };
// //
// Block: Observe the app <div> element and initialize TweetDick whenever possible. // 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>"
];
$("h1.app-title").after(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"
});
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: 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 +287,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,
@@ -230,4 +353,21 @@
onUrlOpened(); onUrlOpened();
}; };
})(); })();
//
// 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();
}
});
//
// Block: Setup global functions.
//
window.TDGF_runUpdateCheck = runUpdateCheck;
})($,$TD); })($,$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,14 @@
<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\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>
@@ -220,7 +231,9 @@
xcopy "$(ProjectDir)LICENSE" "$(TargetDir)" /Y xcopy "$(ProjectDir)LICENSE" "$(TargetDir)" /Y
del "$(TargetDir)LICENSE.txt" del "$(TargetDir)LICENSE.txt"
ren "$(TargetDir)LICENSE" "LICENSE.txt" ren "$(TargetDir)LICENSE" "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