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

Compare commits

...

75 Commits
1.3.2 ... 1.4

Author SHA1 Message Date
aa2c60f7e9 Move cookie import code to ExportManager 2016-09-20 17:15:34 +02:00
f7dc200684 Kill process instead of Environment.FailFast if possible 2016-09-20 17:11:36 +02:00
ad306c56c7 Move log file to storage path 2016-09-20 16:58:00 +02:00
86aba1eb52 Update all exception handlers 2016-09-20 16:55:51 +02:00
826f1aba7a Tweak exception handling in Reporter (use Environment.FailFast and change log button title) 2016-09-20 16:51:29 +02:00
8abf4364c6 Replace calls to Program.Log 2016-09-20 16:39:31 +02:00
4c45d91d4e Move logging to Reporter and make a static instance of it in Program 2016-09-20 16:38:15 +02:00
3176b6cb8f Create a Reporter class with improved HandleException code 2016-09-20 16:34:56 +02:00
27971e09cd Add new Control related functionality to FormMessage 2016-09-20 16:31:53 +02:00
bf95ae00de Tweak the message for missing write permission 2016-09-20 16:10:46 +02:00
0dbfa7e101 Improve reliability of directory write perm checking 2016-09-20 16:00:41 +02:00
85d09c4b5e Add a FormMessage class for custom message boxes 2016-09-20 07:47:16 +02:00
4f9bc40476 Update cache clearing for CEF 53 and clear old cache files on first startup 2016-09-19 14:03:37 +02:00
757ccbf9d3 Switch locale to English and add spell check setting
Closes #62
2016-09-19 13:33:44 +02:00
4cf9730130 Make sure the config is not loaded before old process exits when restarting 2016-09-19 13:24:23 +02:00
1dd0d70ab9 Reorganize Program.LogFile from property to readonly field 2016-09-19 13:08:27 +02:00
340eaece0f Update CefSharp to 53 and update the readme 2016-09-19 00:12:48 +02:00
c151e7cd37 Remove everything TweetDick related 2016-09-18 23:24:11 +02:00
ca0baae832 Release 1.3.3 2016-09-18 22:23:48 +02:00
478e6ed8df Move config loading and migration execution to an earlier point 2016-09-18 22:19:02 +02:00
7388eb07ca Increase process close timeouts to 20 seconds from 10 2016-09-18 21:49:41 +02:00
c38d507e50 Hopefully fix an occasional crash when importing session and restarting 2016-09-18 21:48:40 +02:00
5aee087a57 Add a Program Files warning if not running as administrator 2016-09-18 21:17:30 +02:00
0cda3702ea Change notification scroll trigger cursor position for windows without side borders 2016-09-18 21:08:09 +02:00
ce55226d0c Add error handling to logging 2016-09-18 20:50:43 +02:00
0bab0a9963 Update reply-account plugin metadata and default config warning 2016-09-18 20:29:49 +02:00
34955b7083 Rewrite Plugin default config handling and config error reporting 2016-09-18 20:29:31 +02:00
ba6ce072ac Add support for a -datafolder command line argument 2016-09-18 19:42:00 +02:00
f39fd00697 Add a TweetDick warning and migration prompt 2016-09-18 19:41:37 +02:00
58fc1be1d5 Add CefSharp version to NuGet instructions 2016-09-12 14:29:48 +02:00
1fdf9bffb6 Disable global context menu items when in textarea or text selection 2016-09-07 21:47:31 +02:00
2ad179ef8e Rename configuration file in reply-account plugin 2016-09-07 15:03:06 +02:00
d42cc5b762 Remove .js file block in Plugin folders 2016-09-07 15:01:08 +02:00
403658f622 Add config file to reply-account plugin metadata 2016-09-07 14:43:17 +02:00
6ca35685db Add button for easy Plugin config file access 2016-09-07 14:42:21 +02:00
bfc6822f69 Fix Plugins window title 2016-09-07 14:20:35 +02:00
b0386937d7 Remove lnk updater from the TweetDeck migration system 2016-09-05 21:25:25 +02:00
9436540b2f Add CultureInfo.CurrentCulture to time in logger 2016-09-05 20:45:39 +02:00
45b0ece342 Update Plugin sorting and design (separator, colors) 2016-09-05 20:44:58 +02:00
5c147d3648 Fix missing and unfocused scrollbar in Plugins window 2016-09-05 20:44:07 +02:00
8fa68c428f Add 'Open (quoted) tweet in browser' context menu items and move them down 2016-09-05 16:17:23 +02:00
e2be90191e Standardize context menu items using Chrome's style 2016-09-05 14:30:07 +02:00
339da2f1a9 Add unsupported system notification
Closes #58
2016-09-04 20:30:35 +02:00
b2cc5d50bd Address code analysis issues and fix unused parameter in CombinedFileStream.WriteToFile 2016-09-04 19:32:33 +02:00
f38b188046 Add a safety net to plugin file export in case the path is too long 2016-09-04 18:10:50 +02:00
9e45628e87 Rename 'Export/Import Settings' to Profile and add Plugin exporting 2016-09-04 16:58:03 +02:00
bf76398627 Optimize icon loading and size in Forms, fix Plugins Form title inconsistency 2016-09-04 15:32:00 +02:00
81d5728964 Add scrollbars to Edit CSS window 2016-09-04 13:57:38 +02:00
d76027558b Add a custom alert function with customizable icon and no text length limit 2016-09-04 13:19:52 +02:00
1450cc24a3 Reorganize global context menu items into a sub-menu 2016-09-04 13:10:32 +02:00
f41523c1b2 Remove redundant 'using' directives 2016-09-04 04:53:37 +02:00
4019463e68 Fix occasional incorrect location of child windows 2016-09-04 04:52:59 +02:00
5e2e239f5e Force Reload All button in Plugins window to trigger the event even without changes 2016-09-04 04:44:08 +02:00
bc7856b6c0 Tweak wording in reply-account configuration file 2016-09-04 04:39:19 +02:00
e2bba8d9e1 Update reply-account plugin to use default config and swap event order when enabled late 2016-09-04 04:36:01 +02:00
520db2c32e Rewrite loadConfigurationFile in plugins.js to accept default config file 2016-09-04 04:33:55 +02:00
da71f2de2b Add CheckFileExists function to PluginBridge 2016-09-04 04:33:13 +02:00
6dd2c6678b Add custom exception messages to file reading in PluginBridge 2016-09-04 04:01:40 +02:00
fb3d9e6d6b Add a reply-account plugin with config 2016-09-04 04:01:00 +02:00
36473c2df9 Add a global plugins.js file with loadConfigurationFile utility function 2016-09-04 03:59:37 +02:00
81aa30b2ec Allow custom .js files in plugin folders when prefixed by 'user.' 2016-09-04 03:50:35 +02:00
85d5160782 Add plugin identifier to the object itself 2016-09-04 03:38:42 +02:00
44bf7b870e Rewrote notification mouse hook to only be active if the window is visible
Closes #57
2016-09-04 00:59:13 +02:00
44da2e6082 Add debug example notification padding for scrollbar testing 2016-09-04 00:58:47 +02:00
d576bc3972 Work around Scheduled column update delay bug in TweetDeck
Closes #53
2016-09-03 16:15:28 +02:00
dbeb4c7205 Reorganize path constants and allow the program to be portable 2016-09-02 20:59:03 +02:00
e5223a852e Fix profile picture in example tweet 2016-09-02 20:58:18 +02:00
f3884315c0 Fix visual issues with clear-columns plugin (icon in temp columns, misaligned Messages icons) 2016-09-02 20:46:54 +02:00
53cd9dc9a6 Move script files to /scripts/ folder and exclude them from Visual Studio 2016-09-02 19:05:48 +02:00
a3666a7ab2 Fix formatting in JavaScript files 2016-09-02 17:35:21 +02:00
ca4eb17308 Add a clear-columns plugins 2016-09-02 17:28:32 +02:00
b729dca2e5 Seal PluginConfig and add a method to disable official plugins from config 2016-09-02 17:25:25 +02:00
21354e675a Fix TweetDeck keyboard shortcut list alignment 2016-09-02 17:17:08 +02:00
2085ddd347 Update website in design-revert plugin to https 2016-09-02 16:41:52 +02:00
31a475861b Reformat (missing space after comma), minor code tweaks 2016-09-02 13:34:41 +02:00
79 changed files with 1675 additions and 1519 deletions

View File

@@ -4,7 +4,7 @@ using System.IO;
using System.Threading;
namespace TweetDck.Configuration{
class LockManager{
sealed class LockManager{
public Process LockingProcess { get; private set; }
private readonly string file;
@@ -20,10 +20,10 @@ namespace TweetDck.Configuration{
}
try{
lockStream = new FileStream(file,FileMode.Create,FileAccess.Write,FileShare.Read);
lockStream = new FileStream(file, FileMode.Create, FileAccess.Write, FileShare.Read);
byte[] id = BitConverter.GetBytes(Process.GetCurrentProcess().Id);
lockStream.Write(id,0,id.Length);
lockStream.Write(id, 0, id.Length);
lockStream.Flush();
if (LockingProcess != null){
@@ -48,11 +48,11 @@ namespace TweetDck.Configuration{
try{
byte[] bytes = new byte[4];
using(FileStream fileStream = new FileStream(file,FileMode.Open,FileAccess.Read,FileShare.ReadWrite)){
fileStream.Read(bytes,0,4);
using(FileStream fileStream = new FileStream(file, FileMode.Open, FileAccess.Read, FileShare.ReadWrite)){
fileStream.Read(bytes, 0, 4);
}
int pid = BitConverter.ToInt32(bytes,0);
int pid = BitConverter.ToInt32(bytes, 0);
try{
Process foundProcess = Process.GetProcessById(pid);
@@ -90,7 +90,7 @@ namespace TweetDck.Configuration{
try{
File.Delete(file);
}catch(Exception e){
Program.Log(e.ToString());
Program.Reporter.Log(e.ToString());
result = false;
}

View File

@@ -16,7 +16,7 @@ namespace TweetDck.Configuration{
Binder = new SerializationCompatibilityHandler()
};
private const int CurrentFileVersion = 4;
private const int CurrentFileVersion = 5;
// START OF CONFIGURATION
@@ -35,6 +35,7 @@ namespace TweetDck.Configuration{
public int NotificationDurationValue { get; set; }
public bool NotificationLegacyLoad { get; set; }
public bool EnableSpellCheck { get; set; }
public bool ExpandLinksOnHover { get; set; }
public bool EnableTrayHighlight { get; set; }
@@ -65,7 +66,7 @@ namespace TweetDck.Configuration{
muteNotifications = value;
if (MuteToggled != null){
MuteToggled(this,new EventArgs());
MuteToggled(this, new EventArgs());
}
}
}
@@ -81,7 +82,7 @@ namespace TweetDck.Configuration{
trayBehavior = value;
if (TrayBehaviorChanged != null){
TrayBehaviorChanged(this,new EventArgs());
TrayBehaviorChanged(this, new EventArgs());
}
}
}
@@ -108,7 +109,7 @@ namespace TweetDck.Configuration{
DisplayNotificationTimer = true;
NotificationDuration = TweetNotification.Duration.Medium;
NotificationPosition = TweetNotification.Position.TopRight;
CustomNotificationPosition = new Point(-32000,-32000);
CustomNotificationPosition = new Point(-32000, -32000);
NotificationEdgeDistance = 8;
NotificationDurationValue = 25;
EnableUpdateCheck = true;
@@ -116,6 +117,9 @@ namespace TweetDck.Configuration{
EnableTrayHighlight = true;
Plugins = new PluginConfig();
PluginsWindow = new WindowState();
Plugins.DisableOfficialFromConfig("clear-columns");
Plugins.DisableOfficialFromConfig("reply-account");
}
private void UpgradeFile(){
@@ -155,6 +159,12 @@ namespace TweetDck.Configuration{
++fileVersion;
}
if (fileVersion == 4){
Plugins.DisableOfficialFromConfig("clear-columns");
Plugins.DisableOfficialFromConfig("reply-account");
++fileVersion;
}
// update the version
fileVersion = CurrentFileVersion;
Save();
@@ -170,26 +180,27 @@ namespace TweetDck.Configuration{
if (File.Exists(file)){
string backupFile = GetBackupFile(file);
File.Delete(backupFile);
File.Move(file,backupFile);
File.Move(file, backupFile);
}
using(Stream stream = new FileStream(file,FileMode.Create,FileAccess.Write,FileShare.None)){
Formatter.Serialize(stream,this);
using(Stream stream = new FileStream(file, FileMode.Create, FileAccess.Write, FileShare.None)){
Formatter.Serialize(stream, this);
}
return true;
}catch(Exception e){
Program.HandleException("Could not save the configuration file.",e);
Program.Reporter.HandleException("Configuration Error", "Could not save the configuration file.", true, e);
return false;
}
}
public static UserConfig Load(string file){
UserConfig config = null;
Exception firstException = null;
for(int attempt = 0; attempt < 2; attempt++){
try{
using(Stream stream = new FileStream(attempt == 0 ? file : GetBackupFile(file),FileMode.Open,FileAccess.Read,FileShare.Read)){
using(Stream stream = new FileStream(attempt == 0 ? file : GetBackupFile(file), FileMode.Open, FileAccess.Read, FileShare.Read)){
if ((config = Formatter.Deserialize(stream) as UserConfig) != null){
config.file = file;
}
@@ -201,11 +212,23 @@ namespace TweetDck.Configuration{
break;
}catch(FileNotFoundException){
}catch(DirectoryNotFoundException){
break;
}catch(Exception e){
Program.HandleException("Could not open the configuration file.",e);
if (attempt == 0){
firstException = e;
Program.Reporter.Log(e.ToString());
}
else if (firstException != null){
Program.Reporter.HandleException("Configuration Error", "Could not open the backup configuration file. If you continue, you may lose your settings and list of enabled plugins.", true, e);
}
}
}
if (firstException != null && config == null){
Program.Reporter.HandleException("Configuration Error", "Could not open the configuration file.", true, firstException);
}
return config ?? new UserConfig(file);
}
@@ -215,14 +238,9 @@ namespace TweetDck.Configuration{
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(CultureInfo.CurrentCulture,"{0}, {1}",typeName,assemblyName));
assemblyName = assemblyName.Replace("TweetDick", "TweetDuck");
typeName = typeName.Replace("TweetDick", "TweetDck");
return Type.GetType(string.Format(CultureInfo.CurrentCulture, "{0}, {1}", typeName, assemblyName));
}
}
}

View File

@@ -1,3 +1,3 @@
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<startup><supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.0,Profile=Client"/></startup></configuration>
<startup><supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.5.2"/></startup></configuration>

View File

@@ -1,8 +1,8 @@
<?xml version="1.0" encoding="utf-8"?>
<packages xmlns="http://schemas.microsoft.com/packaging/2010/07/nuspec.xsd">
<package id="cef.redist.x64" 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.WinForms" version="49.0.0-pre02" targetFramework="net40-Client" />
<package id="Microsoft.VC120.CRT.JetBrains" version="12.0.21005.2" targetFramework="net40-Client" />
<package id="cef.redist.x64" version="3.2785.1478" targetFramework="net452" />
<package id="cef.redist.x86" version="3.2785.1478" targetFramework="net452" />
<package id="CefSharp.Common" version="53.0.0-pre01" targetFramework="net452" />
<package id="CefSharp.WinForms" version="53.0.0-pre01" targetFramework="net452" />
<package id="Microsoft.VC120.CRT.JetBrains" version="12.0.21005.2" targetFramework="net452" />
</packages>

View File

@@ -14,7 +14,7 @@ namespace TweetDck.Core.Controls{
}
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);
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){

View File

@@ -2,18 +2,18 @@
using System.Windows.Forms;
namespace TweetDck.Core.Controls{
public partial class FlatProgressBar : ProgressBar{
sealed partial class FlatProgressBar : ProgressBar{
private readonly SolidBrush brush;
public FlatProgressBar(){
brush = new SolidBrush(Color.White);
SetStyle(ControlStyles.UserPaint,true);
SetStyle(ControlStyles.OptimizedDoubleBuffer,true);
SetStyle(ControlStyles.UserPaint, true);
SetStyle(ControlStyles.OptimizedDoubleBuffer, true);
}
public void SetValueInstant(int value){
ControlExtensions.SetValueInstant(this,value);
ControlExtensions.SetValueInstant(this, value);
}
protected override void OnPaint(PaintEventArgs e){

View File

@@ -14,9 +14,9 @@ namespace TweetDck.Core.Controls{
FlatAppearance.MouseDownBackColor = Color.White;
FlatAppearance.MouseOverBackColor = Color.White;
FlatStyle = FlatStyle.Flat;
Location = new Point(locationX,0);
Location = new Point(locationX, 0);
Margin = new Padding(0);
Size = new Size(sizeWidth,30);
Size = new Size(sizeWidth, 30);
Text = title;
UseVisualStyleBackColor = true;
ResumeLayout(true);

View File

@@ -33,7 +33,7 @@ namespace TweetDck.Core.Controls{
public TabButton AddButton(string title, Action callback){
TabButton button = new TabButton();
button.SetupButton((btnWidth-1)*panelButtons.Controls.Count,btnWidth,title,callback);
button.SetupButton((btnWidth-1)*panelButtons.Controls.Count, btnWidth, title, callback);
button.Click += (sender, args) => SelectTab((TabButton)sender);
panelButtons.Controls.Add(button);

View File

@@ -24,7 +24,6 @@
/// </summary>
private void InitializeComponent() {
this.components = new System.ComponentModel.Container();
System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(FormBrowser));
this.trayIcon = new TweetDck.Core.TrayIcon();
this.toolTip = new System.Windows.Forms.ToolTip(this.components);
this.SuspendLayout();
@@ -38,7 +37,7 @@
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
this.ClientSize = new System.Drawing.Size(324, 386);
this.Icon = ((System.Drawing.Icon)(resources.GetObject("$this.Icon")));
this.Icon = Properties.Resources.icon;
this.Location = new System.Drawing.Point(-32000, -32000);
this.MinimumSize = new System.Drawing.Size(340, 424);
this.Name = "FormBrowser";

View File

@@ -54,8 +54,8 @@ namespace TweetDck.Core{
this.browser.LoadingStateChanged += Browser_LoadingStateChanged;
this.browser.FrameLoadEnd += Browser_FrameLoadEnd;
this.browser.RegisterJsObject("$TD",new TweetDeckBridge(this,notification));
this.browser.RegisterAsyncJsObject("$TDP",plugins.Bridge);
this.browser.RegisterJsObject("$TD", new TweetDeckBridge(this, notification));
this.browser.RegisterAsyncJsObject("$TDP", plugins.Bridge);
Controls.Add(browser);
@@ -67,13 +67,13 @@ namespace TweetDck.Core{
UpdateTrayIcon();
this.updates = new UpdateHandler(browser,this);
this.updates = new UpdateHandler(browser, this);
this.updates.UpdateAccepted += updates_UpdateAccepted;
}
private void ShowChildForm(Form form){
form.Show(this);
form.MoveToCenter(this);
form.Shown += (sender, args) => form.MoveToCenter(this);
}
private void ForceClose(){
@@ -82,13 +82,13 @@ namespace TweetDck.Core{
}
public FormNotification CreateNotificationForm(bool autoHide){
return new FormNotification(this,plugins,autoHide);
return new FormNotification(this, plugins, autoHide);
}
// window setup
private void SetupWindow(){
Config.BrowserWindow.Restore(this,true);
Config.BrowserWindow.Restore(this, true);
prevState = WindowState;
isLoaded = true;
}
@@ -101,6 +101,12 @@ namespace TweetDck.Core{
private void Browser_LoadingStateChanged(object sender, LoadingStateChangedEventArgs e){
if (!e.IsLoading){
browser.AddWordToDictionary("tweetdeck");
browser.AddWordToDictionary("TweetDeck");
browser.AddWordToDictionary("tweetduck");
browser.AddWordToDictionary("TweetDuck");
browser.AddWordToDictionary("TD");
Invoke(new Action(SetupWindow));
browser.LoadingStateChanged -= Browser_LoadingStateChanged;
}
@@ -108,11 +114,12 @@ namespace TweetDck.Core{
private void Browser_FrameLoadEnd(object sender, FrameLoadEndEventArgs e){
if (e.Frame.IsMain){
ScriptLoader.ExecuteFile(e.Frame,"code.js");
ScriptLoader.ExecuteFile(e.Frame, "code.js");
if (plugins.HasAnyPlugin(PluginEnvironment.Browser)){
ScriptLoader.ExecuteFile(e.Frame,PluginManager.PluginBrowserScriptFile);
plugins.ExecutePlugins(e.Frame,PluginEnvironment.Browser,true);
ScriptLoader.ExecuteFile(e.Frame, PluginManager.PluginBrowserScriptFile);
ScriptLoader.ExecuteFile(e.Frame, PluginManager.PluginGlobalScriptFile);
plugins.ExecutePlugins(e.Frame, PluginEnvironment.Browser, true);
}
}
}
@@ -135,7 +142,7 @@ namespace TweetDck.Core{
}
}
else{
FormBrowser_ResizeEnd(sender,e);
FormBrowser_ResizeEnd(sender, e);
}
}
}
@@ -185,7 +192,7 @@ namespace TweetDck.Core{
}
private void plugins_PluginChangedState(object sender, PluginChangedStateEventArgs e){
browser.ExecuteScriptAsync("window.TDPF_setPluginState",e.Plugin,e.IsEnabled ? 1 : 0); // ExecuteScriptAsync cannot handle boolean values as of yet
browser.ExecuteScriptAsync("window.TDPF_setPluginState", e.Plugin, e.IsEnabled ? 1 : 0); // ExecuteScriptAsync cannot handle boolean values as of yet
}
private void updates_UpdateAccepted(object sender, UpdateAcceptedEventArgs e){
@@ -209,12 +216,12 @@ namespace TweetDck.Core{
protected override void WndProc(ref Message m){
if (isLoaded && m.Msg == Program.WindowRestoreMessage){
trayIcon_ClickRestore(trayIcon,new EventArgs());
trayIcon_ClickRestore(trayIcon, new EventArgs());
return;
}
if (isLoaded && m.Msg == 0x210 && (m.WParam.ToInt32() & 0xFFFF) == 0x020B){ // WM_PARENTNOTIFY, WM_XBUTTONDOWN
browser.ExecuteScriptAsync("TDGF_onMouseClickExtra",(m.WParam.ToInt32() >> 16) & 0xFFFF);
browser.ExecuteScriptAsync("TDGF_onMouseClickExtra", (m.WParam.ToInt32() >> 16) & 0xFFFF);
return;
}
@@ -230,7 +237,7 @@ namespace TweetDck.Core{
else{
bool prevEnableUpdateCheck = Config.EnableUpdateCheck;
currentFormSettings = new FormSettings(this,updates);
currentFormSettings = new FormSettings(this, plugins, updates);
currentFormSettings.FormClosed += (sender, args) => {
currentFormSettings = null;
@@ -284,17 +291,17 @@ namespace TweetDck.Core{
}
else{
Point position = PointToClient(Cursor.Position);
position.Offset(20,10);
toolTip.Show(text,this,position);
position.Offset(20, 10);
toolTip.Show(text, this, position);
}
}
public void OnImagePasted(){
browser.ExecuteScriptAsync("TDGF_tryPasteImage",new object[0]);
browser.ExecuteScriptAsync("TDGF_tryPasteImage", new object[0]);
}
public void OnImagePastedFinish(){
browser.ExecuteScriptAsync("TDGF_tryPasteImageFinish",new object[0]);
browser.ExecuteScriptAsync("TDGF_tryPasteImageFinish", new object[0]);
}
public void ReloadBrowser(){

View File

@@ -117,267 +117,11 @@
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<metadata name="trayIcon.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
<value>17, 17</value>
</metadata>
<metadata name="toolTip.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
<value>112, 17</value>
</metadata>
<assembly alias="System.Drawing" name="System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" />
<data name="$this.Icon" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value>
AAABAAMAMDAAAAEAIACoJQAANgAAACAgAAABACAAqBAAAN4lAAAQEAAAAQAgAGgEAACGNgAAKAAAADAA
AABgAAAAAQAgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAqHg5IrF+OlS+hjyMw4g7tcmM
PM/MjTzezY485s2OPObMjjzfyIw80MOJPLe8hDyNs387WKx8OyQAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAApHU4FrB8OGXGijzAzo889dKR
PP/SkTz/0pE8/9GRPP/RkDz/0JA8/9CQPP/RkDz/0ZE8/9KRPP/TkTz/0pE8/86PPPbGijzCt4E8bKp6
OxoAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAKN1OB+9hTuLzI486NOR
PP/SkTz/0ZA8/9CQPP/QkDz/0JA8/9CQPP/QkDz/0JA8/9CQPP/QkDz/0JA8/9CQPP/QkDz/0JA8/9GQ
PP/SkTz/0pE8/82OPOu9hTuOq3w8IgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACidTkFuoM8csyN
POrTkjz/0ZE8/9CQPP/QkDz/0JA8/9CQPP/QkDz/0JA8/9CQPP/QkDz/0JA8/9CQPP/QkDz/0JA8/9CQ
PP/QkDz/0JA8/9CQPP/QkDz/0JA8/9GRPP/Tkjz/zY887bqEPHimeDsHAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAKp6
OynDiDvA05I8/9GRPP/QkDz/0JA8/9CQPP/QkDz/0JA8/9CQPP/QkDz/0JA8/9CQPP/QkDz/0JA8/9CQ
PP/QkDz/0JA8/9CQPP/QkDz/0JA8/9CQPP/QkDz/0JA8/9CQPP/QkDz/0ZA8/9ORPP/GijzFr308LgAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAArXw7UM2OPOvTkTz/0JA8/9CQPP/QkDz/0JA8/9CQPP/QkDz/0JA8/9CQPP/QkDz/0JA8/9CQ
PP/QkDz/0JA8/9CQPP/QkDz/0JA8/9CQPP/QkDz/0JA8/9CQPP/QkDz/0JA8/9CQPP/QkDz/0JA8/9CQ
PP/SkTz/zo887rOAPFYAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAACxfjxm0ZA8/NGRPP/QkDz/0JA8/9CQPP/QkDz/0JA8/9CQPP/QkDz/0JA8/9CQ
PP/QkDz/0JA8/9CQPP/QkDz/0JA8/9CQPP/QkDz/0JA8/9CQPP/QkDz/0JA8/9CQPP/QkDz/0JA8/9CQ
PP/QkDz/0JA8/9CQPP/QkDz/0ZE8/9GQPP64gjxtAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAALaBPGXRkTz/0ZE8/9CQPP/QkDz/0JA8/9CQPP/QkDz/0JA8/9CQ
PP/QkDz/0JA8/9CQPP/QkDz/0JA8/9CQPP/QkDz/0JA8/9CQPP/QkDz/0JA8/9CQPP/QkDz/0JA8/9CQ
PP/QkDz/0JA8/9CQPP/QkDz/0JA8/9CQPP/QkDz/0JA8/9GQPP/SkTz/uIM8bAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAqnk6TtCQPPzRkTz/0JA8/9CQPP/QkDz/0JA8/9CQ
PP/QkDz/0JA8/9CQPP/QkDz/0JA8/9CQPP/QkDz/0JA8/9CQPP/QkDz/0JA8/9CQPP/QkDz/0JA8/9CQ
PP/QkDz/0JA8/9CQPP/QkDz/0JA8/9CQPP/QkDz/0JA8/9CQPP/QkDz/0JA8/9CQPP/RkDz/0ZA8/rSA
PFUAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACtfDwmzo887dKRPP/QkDz/0JA8/9CQ
PP/QkDz/0JA8/9CQPP/QkDz/0JA8/9CQPP/QkDz/0JA8/9CQPP/QkDz/0JA8/9CQPP/QkDz/0JA8/9CQ
PP/QkDz/0JA8/9CQPP/QkDz/0JA8/9CQPP/QkDz/0JA8/9CQPP/QkDz/0JA8/9CQPP/QkDz/0JA8/9CQ
PP/QkDz/0ZE8/86PPPGtfDwrAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAKZ4PAXFijzC0pE8/9CQ
PP/QkDz/0JA8/9CQPP/QkDz/0JA8/9CURf/TpGT/2baJ/9/GpP/l0bf/59W//+fVvf/kz7P/3sOg/9mz
hP/ToWH/0JND/9CQPP/QkDz/0JA8/9CQPP/QkDz/0JA8/9CQPP/QkDz/0JA8/9CQPP/QkDz/0JA8/9CQ
PP/QkDz/0JA8/9CQPP/QkDz/0JA8/9KRPP/EiTvJo3Y7CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAALiC
PG/Tkjz/0JA8/9CQPP/QkDz/0JA8/9CSQf/Vq3P/5tO7//j07v//////////////////////////////
////////////////////////9vHq/+TQtf/UqG7/0JA+/9CQPP/QkDz/0JA8/9CQPP/QkDz/0JA8/9CQ
PP/QkDz/0JA8/9CQPP/QkDz/0JA8/9CQPP/QkDz/0JA8/9CQPP/Tkjz/uYM8dgAAAAAAAAAAAAAAAAAA
AAAAAAAArXw8Gc2OPOzRkTz/0JA8/9CQPP/QlEX/27qP//fz7P//////////////////////////////
////////////////////////////////////////////////////////8ObZ/9auev/QkDz/0JA8/9CQ
PP/QkDz/0JA8/9CQPP/QkDz/0JA8/9CQPP/QkDz/0JA8/9CQPP/QkDz/0JA8/9CQPP/RkTz/zI488J1x
OB8AAAAAAAAAAAAAAAAAAAAAuoM7h9OSPP/QkDz/0JA8/9GXTf/TpGb/27uS/9u6kP/ewZz/59W9//Xv
5///////////////////////////////////////////////////////////////////////////////
///r3cr/0ZxV/9CQPP/QkDz/0JA8/9CQPP/QkDz/0JA8/9CQPP/QkDz/0JA8/9CQPP/QkDz/0JA8/9CQ
PP/QkDz/1JI8/7mDO5AAAAAAAAAAAAAAAADFj0cR0pNB6s+PO//Ojjv/0JA8/9CQPP/QkDz/0JA8/9CQ
PP/QkDz/0JA8/9CRQP/TpGf/5NC2//38+v//////////////////////////////////////////////
////////////////////////+vf0/9auev/QkDz/0JA8/9CQPP/QkDz/0JA8/9CQPP/QkDz/0JA8/9CQ
PP/QkDz/0JA8/9CQPP/QkDz/0ZE8/8uOPO6SajYVAAAAAAAAAADzr1df7qxV/+WkT//ZmUT/0JA9/86O
O//Pjzv/0JA8/9CQPP/QkDz/0JA8/9CQPP/QkDz/0JA8/9GaUv/l07r/////////////////////////
///////////////////////////////////////////////////buo//0JA8/9CQPP/QkDz/0JA8/9CQ
PP/QkDz/0JA8/9CQPP/QkDz/0JA8/9CQPP/QkDz/0JA8/9OSPP+ldjdoAAAAAAAAAADurFW67qxV//Ct
Vv/vrVb/6adR/92dSP/Skz//zo47/8+PO//QkDz/0JA8/9CQPP/QkDz/0JJB/9Smaf/dv5j/+fXw////
////////////////////////////////////////////////////////////////////////2riM/9CQ
PP/QkDz/0JA8/9CQPP/QkDz/0JA8/9CQPP/QkDz/0JA8/9CQPP/QkDz/0JA8/9KRPP/FiTzGoHQ6Ae6s
VRrurFXz7qxV/+6sVf/urFX/761W//CuVv/sqlT/4qFM/9aVQv/Pjzv/zo47/9CQPP/VqnH/8+vh////
////////////////////////////////////////////////////////////////////////////////
/////////////9aueP/QkDz/0JA8/9CQPP/QkDz/0JA8/9CQPP/QkDz/0JA8/9CQPP/QkDz/0JA8/9GQ
PP/Ojzz4oHM5Iu6sVU3urFX/7qxV/+6sVf/urFX/7qxV/+6sVf/vrVX/8K5W/+6sVf/mpU//2plF/9q6
j///////////////////////////////////////////////////////////////////////////////
//////////////////////////////n18P/Rm1P/0JA8/9CQPP/QkDz/0JA8/9CQPP/QkDz/0JA8/9CQ
PP/QkDz/0JA8/9CQPP/SkTz/rXs6Vu6sVYPurFX/7qxV/+6sVf/urFX/7qxV/+6sVf/urFX/7qxV/+6s
Vf/wrVb/6r2B////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////o18L/0JA8/9CQPP/QkDz/0JA8/9CQ
PP/QkDz/0JA8/9CQPP/QkDz/0JA8/9CQPP/SkTz/v4Y8j+6sVa3urFX/7qxV/+6sVf/urFX/7qxV/+6s
Vf/urFX/7qxV/+6sVf/urFb/9Onb///////+/v3/////////////////////////////////////////
////////////////////////////////////////////////////////////////////////1qx2/9CQ
PP/QkDz/0JA8/9CQPP/QkDz/0JA8/9CQPP/QkDz/0JA8/9CQPP/SkTz/wYc7uO6sVcrurFX/7qxV/+6s
Vf/urFX/7qxV/+6sVf/urFX/7qxV/+6sVf/trlr/67Zy/+m+h//y5NP/////////////////////////
////////////////////////////////////////////////////////////////////////////////
////////7+TW/9CQPf/QkDz/0JA8/9CQPP/QkDz/0JA8/9CQPP/QkDz/0JA8/9CQPP/RkTz/yYw80e6s
VdvurFX/7qxV/+6sVf/urFX/7qxV/+6sVf/urFX/7qxV/+6sVf/urFX/6sme//v49P//////////////
////////////////////////////////////////////////////////////////////////////////
/////////////////////////////9arc//QkDz/0JA8/9CQPP/QkDz/0JA8/9CQPP/QkDz/0JA8/9CQ
PP/RkDz/zI083+6sVeLurFX/7qxV/+6sVf/urFX/7qxV/+6sVf/urFX/7qxV/+6sVf/u2b3/////////
////////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////+fVvv/QkDz/0JA8/9CQPP/QkDz/0JA8/9CQ
PP/QkDz/0JA8/9CQPP/QkDz/zo885u6sVeLurFX/7qxV/+6sVf/urFX/7qxV/+6sVf/urFX/7qxV/+vL
of//////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////r28v/Rl0r/0JA8/9CQ
PP/QkDz/0JA8/9CQPP/QkDz/0JA8/9CQPP/QkDz/zo885u6sVdrurFX/7qxV/+6sVf/urFX/7qxV/+6s
Vf/urFX/7LBj//r28f//////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
///Vq3P/0JA8/9CQPP/QkDz/0JA8/9CQPP/QkDz/0JA8/9CQPP/RkDz/zI083+6sVcrurFX/7qxV/+6s
Vf/urFX/7qxV/+6sVf/urFX/6cKO////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
///////////////////ewp7/0JA8/9CQPP/QkDz/0JA8/9CQPP/QkDz/0JA8/9CQPP/RkTz/yYw80O6s
VazurFX/7qxV/+6sVf/urFX/7qxV/+6sVf/urFX/7NOy//z59v/u2b7/+fPr////////////////////
////////////////////////////////////////////////////////////////////////////////
///////////////////////////////////n1sD/0JA8/9CQPP/QkDz/0JA8/9CQPP/QkDz/0JA8/9CQ
PP/SkTz/xIo8uO6sVYHurFX/7qxV/+6sVf/urFX/7qxV/+6sVf/urFX/67Zx/+2uWf/qy6H/////////
////////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////v5dj/0JA8/9CQPP/QkDz/0JA8/9CQ
PP/QkDz/0JA8/9CQPP/SkTz/vYU8je6sVUvurFX/7qxV/+6sVf/urFX/7qxV/+6sVf/urFX/7qxV/+nC
kP///////////////////////////////////////////////////////fz6//fu5P/w4Mv/793F//7+
/v/////////////////////////////////////////////////////////////////17eT/0JA//86O
Ov/Pjzv/0JA8/9CQPP/QkDz/0JA8/9CQPP/SkTz/tYA8Vu6sVRnurFXy7qxV/+6sVf/urFX/7qxV/+6s
Vf/urFX/7a5b//fw5///////////////////////////////////////+/jz/+7av//pwIr/67Jn/+6t
Vv/urFX/6rd1////////////////////////////////////////////////////////////////////
///48ej/6KhU/92cR//Tkj7/zo47/8+PO//QkDz/0JA8/9GQPP/Pjzz3rXw8IAAAAADurFW37qxV/+6s
Vf/urFX/7qxV/+6sVf/urFX/6b2D//////////////////////////////////nz6//qyZ3/7K9h/+6s
Vf/urFX/7qxV/+6sVf/urFX/6rl6////////////////////////////////////////////////////
///////////////////9/Pr/6r6C//CuV//sqlT/4aBL/9aWQv/Pjzv/zo47/9GRPP/GijzCp3g8AQAA
AADurFVb7qxV/+6sVf/urFX/7qxV/+6sVf/urFX/68yk///////////////////////+/fz/68+q/+2v
XP/urFX/7qxV/+6sVf/urFX/7qxV/+6sVf/urFX/6rNr//7+/f//////////////////////////////
/////////////////////////////////////////////+nEk//vrVX/8K5W/+6sVf/lpE//2ZlF/9KR
Pf+zfzpoAAAAAAAAAADurFUP7qxV5u6sVf/urFX/7qxV/+6sVf/urFX/7NGu//////////////////fu
5P/quHb/7qxV/+6sVf/urFX/7qxV/+6sVf/urFX/7qxV/+6sVf/urFX/7qxW//Xr3///////////////
///////////////////////////////////////////////////7+PP/+vXu///////pxJL/7qxV/+6s
Vf/wrVb/8K1W/+mnUevUmUsUAAAAAAAAAAAAAAAA7qxVgO6sVf/urFX/7qxV/+6sVf/urFX/6sqg////
////////8eLO/+yvX//urFX/7qxV/+6sVf/urFX/7qxV/+6sVf/urFX/7qxV/+6sVf/urFX/7qxV/+nF
lf/////////////////////////////////////////////////////////////////8+vf/6cWV/+q5
ev/s07H/6rd1/+6sVf/urFX/7qxV/++tVogAAAAAAAAAAAAAAAAAAAAA7qxVFe6sVejurFX/7qxV/+6s
Vf/urFX/6bp8///////w4Mn/7a1Z/+6sVf/urFX/7qxV/+6sVf/urFX/7qxV/+6sVf/urFX/7qxV/+6s
Vf/urFX/7qxV/+6sVf/x4cz////////////////////////////////////////////////////+//7+
/v/////////+/+m8gP/urFX/7a1Y/+6sVf/urFX/7qxV7O6sVRoAAAAAAAAAAAAAAAAAAAAAAAAAAO6s
VWburFX/7qxV/+6sVf/urFX/7a5b/+zTs//sr1//7qxV/+6sVf/urFX/7qxV/+6sVf/urFX/7qxV/+6s
Vf/urFX/7qxV/+6sVf/urFX/7qxV/+6sVf/sr1//8uPQ////////////////////////////////////
////////6suj/+qzav/pxpj/9Onb//n07f/rr2D/7qxV/+6sVf/urFX/7qxVbwAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAO6sVQPurFW67qxV/+6sVf/urFX/7qxV/+6sVv/urFX/7qxV/+6sVf/urFX/7qxV/+6s
Vf/urFX/7qxV/+6sVf/urFX/7qxV/+6sVf/urFX/7qxV/+6sVf/urFX/7axY/+nGl//27uP/////////
/////////fz6//Lj0P/qunv/7qxV/+6sVf/urFX/7qxV/+m9gv/qt3X/7qxV/+6sVf/urFXB7qxVBQAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADurFUg7qxV6O6sVf/urFX/7qxV/+6sVf/urFX/7qxV/+6s
Vf/urFX/7qxV/+6sVf/urFX/7qxV/+6sVf/urFX/7qxV/+6sVf/urFX/7qxV/+6sVf/urFX/7qxV/+6s
Vf/qtnP/6sqg/+3WuP/s07P/6cSS/+uyZf/urFX/7qxV/+6sVf/urFX/7qxV/+6sVv/trVr/7qxV/+6s
VezurFUlAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA7qxVRu6sVfjurFX/7qxV/+6s
Vf/urFX/7qxV/+6sVf/urFX/7qxV/+6sVf/urFX/7qxV/+6sVf/urFX/7qxV/+6sVf/urFX/7qxV/+6s
Vf/urFX/7qxV/+6sVf/urFX/7qxV/+6sVf/urFX/7qxV/+6sVf/urFX/7qxV/+6sVf/urFX/7qxV/+6s
Vf/urFX/7qxV++6sVUwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAO6s
VVzurFX97qxV/+6sVf/urFX/7qxV/+6sVf/urFX/7qxV/+6sVf/urFX/7qxV/+6sVf/urFX/7qxV/+6s
Vf/urFX/7qxV/+6sVf/urFX/7qxV/+6sVf/urFX/7qxV/+6sVf/urFX/7qxV/+6sVf/urFX/7qxV/+6s
Vf/urFX/7qxV/+6sVf/urFX/7qxVYwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAADurFVd7qxV+O6sVf/urFX/7qxV/+6sVf/urFX/7qxV/+6sVf/urFX/7qxV/+6s
Vf/urFX/7qxV/+6sVf/urFX/7qxV/+6sVf/urFX/7qxV/+6sVf/urFX/7qxV/+6sVf/urFX/7qxV/+6s
Vf/urFX/7qxV/+6sVf/urFX/7qxV/+6sVfvurFVjAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA7qxVR+6sVeXurFX/7qxV/+6sVf/urFX/7qxV/+6s
Vf/urFX/7qxV/+6sVf/urFX/7qxV/+6sVf/urFX/7qxV/+6sVf/urFX/7qxV/+6sVf/urFX/7qxV/+6s
Vf/urFX/7qxV/+6sVf/urFX/7qxV/+6sVf/urFX/7qxV6O6sVU0AAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAO6sVSPurFW37qxV/+6s
Vf/urFX/7qxV/+6sVf/urFX/7qxV/+6sVf/urFX/7qxV/+6sVf/urFX/7qxV/+6sVf/urFX/7qxV/+6s
Vf/urFX/7qxV/+6sVf/urFX/7qxV/+6sVf/urFX/7qxV/+6sVf/urFW77qxVJgAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AADurFUB7qxVae6sVeTurFX/7qxV/+6sVf/urFX/7qxV/+6sVf/urFX/7qxV/+6sVf/urFX/7qxV/+6s
Vf/urFX/7qxV/+6sVf/urFX/7qxV/+6sVf/urFX/7qxV/+6sVf/urFX/7qxV5+6sVW3urFUDAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAO6sVRjurFWA7qxV4u6sVf/urFX/7qxV/+6sVf/urFX/7qxV/+6s
Vf/urFX/7qxV/+6sVf/urFX/7qxV/+6sVf/urFX/7qxV/+6sVf/urFX/7qxV/+6sVeTurFWE7qxVGwAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA7qxVEu6sVV7urFW17qxV7+6s
Vf/urFX/7qxV/+6sVf/urFX/7qxV/+6sVf/urFX/7qxV/+6sVf/urFX/7qxV/+6sVfDurFW47qxVX+6s
VRMAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAA7qxVG+6sVUzurFWA7qxVrO6sVcnurFXa7qxV4u6sVeLurFXa7qxVye6sVa3urFWC7qxVTe6s
VR0AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAP//gAH//6gr//wAAD//qCv/8AAAD/+oK//AAAAD/6gr/4AAAAH/qCv/AAAAAP+oK/4A
AAAAf6gr/AAAAAA/qCv4AAAAAB+oK/AAAAAAD6gr4AAAAAAHqCvgAAAAAAeoK8AAAAAAA6grwAAAAAAD
qCuAAAAAAAGoK4AAAAAAAagrgAAAAAAAqCsAAAAAAACoKwAAAAAAAKgrAAAAAAAAqCsAAAAAAACoKwAA
AAAAAKgrAAAAAAAAqCsAAAAAAACoKwAAAAAAAKgrAAAAAAAAqCsAAAAAAACoKwAAAAAAAKgrAAAAAAAA
qCsAAAAAAACoKwAAAAAAAKgrgAAAAAAAqCuAAAAAAAGoK4AAAAAAAagrwAAAAAADqCvAAAAAAAOoK+AA
AAAAB6gr4AAAAAAHqCvwAAAAAA+oK/gAAAAAH6gr/AAAAAA/qCv+AAAAAH+oK/8AAAAA/6gr/4AAAAH/
qCv/wAAAA/+oK//wAAAP/6gr//wAAD//qCv//4AB//+oKygAAAAgAAAAQAAAAAEAIAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAApHY4FrR/
Ole+hjuVxos7w8uNPNvOjzznzo8858uNPNzGijzEvoU7l7WBO1mpejsYAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAqHg5Kr6F
O5XLjTvo0pE8/9ORPP/SkTz/0ZE8/9CQPP/QkDz/0ZE8/9KRPP/TkTz/0pE8/82OPOq/hjyZrXw7LAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAo3U6CbuE
O4bPjzz005I8/9GRPP/QkDz/0JA8/9CQPP/QkDz/0JA8/9CQPP/QkDz/0JA8/9CQPP/QkDz/0ZE8/9OS
PP/PkDz1vYU8iah6PAsAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAKR3
OibGizvG05E8/9GQPP/QkDz/0JA8/9CQPP/QkDz/0JA8/9CQPP/QkDz/0JA8/9CQPP/QkDz/0JA8/9CQ
PP/QkDz/0JA8/9GQPP/TkTz/yIs8yqx8PCkAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AACsezsxy40849KRPP/QkDz/0JA8/9CQPP/QkDz/0JA8/9CQPP/QkDz/0JA8/9CQPP/QkDz/0JA8/9CQ
PP/QkDz/0JA8/9CQPP/QkDz/0JA8/9CQPP/SkTz/zI485rKAPTUAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAApXc6JMuNPOTSkTz/0JA8/9CQPP/QkDz/0JA8/9CQPP/QkDz/0JA8/9CQPP/QkDz/0JA8/9CQ
PP/QkDz/0JA8/9CQPP/QkDz/0JA8/9CQPP/QkDz/0JA8/9CQPP/SkTz/zI485659PCcAAAAAAAAAAAAA
AAAAAAAAAAAAAKd4OwnHizzJ0pE8/9CQPP/QkDz/0JA9/9OgYP/YtIX/38Sh/+LMr//iy67/3sOf/9iy
gv/Tn13/0JA8/9CQPP/QkDz/0JA8/9CQPP/QkDz/0JA8/9CQPP/QkDz/0JA8/9CQPP/SkTz/x4s8zaV4
OwsAAAAAAAAAAAAAAAAAAAAAu4Q8hNOSPP/QkDz/0JA8/9GXS//YtIX/6NfC//Xv5//8+vj/////////
///8+vf/9O3k/+fVvv/YsYH/0JRF/9CQPP/QkDz/0JA8/9CQPP/QkDz/0JA8/9CQPP/QkDz/0JA8/9CQ
PP/Tkjz/u4Q7iQAAAAAAAAAAAAAAAKx7OyTPjzz10ZA8/9GXS//Ztoj/8une////////////////////
///////////////////////////////////38uz/3L2V/9CRP//QkDz/0JA8/9CQPP/QkDz/0JA8/9CQ
PP/QkDz/0JA8/9GRPP/Ojzz3onU5KQAAAAAAAAAAxo1BlNGQO//Ojjv/0JNC/9GWSP/QlET/0ZpR/9au
eP/n1b3//v79////////////////////////////////////////////7+TV/9GdWP/QkDz/0JA8/9CQ
PP/QkDz/0JA8/9CQPP/QkDz/0JA8/9SSPP+4gjqaAAAAAPGuVhHvrVXq5qRO/9qZRP/QkT3/zo46/8+P
O//QkDz/0JA8/9CQPP/To2P/8+vh////////////////////////////////////////////+fXw/9Oh
Yf/QkDz/0JA8/9CQPP/QkDz/0JA8/9CQPP/QkDz/0pE8/8qMO+2WbTYV7qxVUe6sVf/wrVb/761W/+mo
Uv/enUj/05M//86PO//PkD7/3cCZ//Lp3v/7+PT/////////////////////////////////////////
////////+PTv/9GcVf/QkDz/0JA8/9CQPP/QkDz/0JA8/9CQPP/QkDz/05I8/699OljurFWR7qxV/+6s
Vf/urFX/761W//CuV//sqlT/4qJQ/+zdyf//////////////////////////////////////////////
////////////////////////7+TV/9CRP//QkDz/0JA8/9CQPP/QkDz/0JA8/9CQPP/Tkjz/vIQ7mO6s
Vb/urFX/7qxV/+6sVf/urFX/7qxV/++tVf/ry5///v79//7+/f//////////////////////////////
////////////////////////////////////////2rqO/9CQPP/QkDz/0JA8/9CQPP/QkDz/0JA8/9KR
PP/GijvF7qxV2u6sVf/urFX/7qxV/+6sVf/urFX/7qxV/+u1bv/t1bb//fv4////////////////////
///////////////////////////////////////////////////48+3/0ZRG/9CQPP/QkDz/0JA8/9CQ
PP/QkDz/0ZA8/8uNPNzurFXl7qxV/+6sVf/urFX/7qxV/+6sVf/rsWP/9OjZ////////////////////
///////////////////////////////////////////////////////////////////YtIX/0JA8/9CQ
PP/QkDz/0JA8/9CQPP/QkDz/zo886O6sVeXurFX/7qxV/+6sVf/urFX/7qxW//Hiz///////////////
/////////////////////////////////////////////////////////////////////////////+rb
yP/QkDz/0JA8/9CQPP/QkDz/0JA8/9CQPP/Ojzzo7qxV2e6sVf/urFX/7qxV/+6sVf/quHb/////////
////////////////////////////////////////////////////////////////////////////////
////////+fXw/9CURf/QkDz/0JA8/9CQPP/QkDz/0ZA8/8yOPNzurFW/7qxV/+6sVf/urFX/7qxV/+nA
if/s1LT/9Onb////////////////////////////////////////////////////////////////////
////////////////////////0Z5b/9CQPP/QkDz/0JA8/9CQPP/SkTz/x4s8xe6sVY/urFX/7qxV/+6s
Vf/urFX/7qxV/+nEk//+/fz////////////////////////////+/v3/+PHo//To2f/+/v7/////////
///////////////////////////////////VqGz/zo46/8+PO//QkDz/0JA8/9KRPP+/hjyX7qxVUO6s
Vf/urFX/7qxV/+6sVf/ssGH//Pr2///////////////////////y49D/6cOR/+qyaf/urVb/6rJp////
/////////////////////////////////////////////+e7f//goEr/1ZVB/8+PO//Ojzv/0pE8/7WB
PFfurFUQ7qxV6O6sVf/urFX/7qxV/+m+hv/////////////////z5tX/6rl6/+6sVf/urFX/7qxV/+6s
Vf/qs2r////+////////////////////////////////////////////+PLp/+y4c//urFX/5aRO/9qZ
RP/Mjjztp3g6FQAAAADurFWQ7qxV/+6sVf/urFX/6cKP////////////682m/+6sVf/urFX/7qxV/+6s
Vf/urFX/7qxV/+2sV//17N////////////////////////////////////////7+/v/06Nn/8uTT/+qz
a//wrVb/761W/+alUZYAAAAAAAAAAO6sVSHurFX07qxV/+6sVf/quXj//////+nDkf/urFX/7qxV/+6s
Vf/urFX/7qxV/+6sVf/urFX/7qxV/+m+hP////////////////////////////////////////////jy
6v/qtnH/67Fj/+6sVf/urFX2761WJQAAAAAAAAAAAAAAAO6sVX7urFX/7qxV/+2vW//pvID/7qxV/+6s
Vf/urFX/7qxV/+6sVf/urFX/7qxV/+6sVf/urFX/7qxV/+nEkv/7+PT//////////////////fz6/+rJ
n//rtW7/682n/+zTs//urFb/7qxV/+6sVYQAAAAAAAAAAAAAAAAAAAAA7qxVB+6sVcTurFX/7qxV/+6s
Vf/urFX/7qxV/+6sVf/urFX/7qxV/+6sVf/urFX/7qxV/+6sVf/urFX/7qxV/+u0bP/qy6H/7da4/+vN
pv/qtnP/7qxV/+6sVf/urFX/7K9f/+2sWP/urFXI7qxVCQAAAAAAAAAAAAAAAAAAAAAAAAAA7qxVIO6s
VeDurFX/7qxV/+6sVf/urFX/7qxV/+6sVf/urFX/7qxV/+6sVf/urFX/7qxV/+6sVf/urFX/7qxV/+6s
Vf/urFX/7qxV/+6sVf/urFX/7qxV/+6sVf/urFX/7qxV4+6sVSMAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAA7qxVLO6sVd/urFX/7qxV/+6sVf/urFX/7qxV/+6sVf/urFX/7qxV/+6sVf/urFX/7qxV/+6s
Vf/urFX/7qxV/+6sVf/urFX/7qxV/+6sVf/urFX/7qxV/+6sVeLurFUwAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAA7qxVIu6sVcHurFX/7qxV/+6sVf/urFX/7qxV/+6sVf/urFX/7qxV/+6s
Vf/urFX/7qxV/+6sVf/urFX/7qxV/+6sVf/urFX/7qxV/+6sVf/urFXE7qxVJAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA7qxVBu6sVX/urFXw7qxV/+6sVf/urFX/7qxV/+6s
Vf/urFX/7qxV/+6sVf/urFX/7qxV/+6sVf/urFX/7qxV/+6sVf/urFXy7qxVgu6sVQgAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAO6sVSXurFWP7qxV5e6s
Vf/urFX/7qxV/+6sVf/urFX/7qxV/+6sVf/urFX/7qxV/+6sVf/urFXl7qxVke6sVScAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AADurFUS7qxVUO6sVY7urFW97qxV2O6sVeXurFXl7qxV2O6sVb7urFWP7qxVUu6sVRMAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA/8AD//8AAP/8AAA/+AAAH/AAAA/gAAAHwAAAA8AA
AAOAAAABgAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIAA
AAGAAAABwAAAA8AAAAPgAAAH8AAAD/gAAB/8AAA//wAA///AA/8oAAAAEAAAACAAAAABACAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAKx7Oja9hTqTyYw8zs6PPOfOjzznyYw8zr6G
PJSvfjw3AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAo3Y7CbyEO5PRkDz805I8/9GRPP/QkDz/0JA8/9GR
PP/TkTz/0ZA8/b+GPJWrfDwKAAAAAAAAAAAAAAAAp3g8CcSJPLfTkjz/0ZA8/9CQPP/QkDz/0JA8/9CQ
PP/QkDz/0JA8/9CQPP/Tkjz/xoo8uqx8PQoAAAAAAAAAAL2FPJPUk0D/06Rm/92/mf/izK//4sut/9u6
j//Snlr/0JA8/9CQPP/QkDz/0JA8/9OSPP+9hTyWAAAAALiEQDLQkDz90JpS/93Amf/u4tP/////////
/////////fv5/+DIqP/QkkH/0JA8/9CQPP/RkDz/0JA8/qN1OTTtq1WS56VP/9qaRf/RkT3/0JdO/+rc
yP//////////////////////693L/9CSQf/QkDz/0JA8/9SSPP+3gTqW761Vz++tVv/wrVb/6K5h//fy
6v/////////////////////////////////gx6b/0JA8/9CQPP/RkTz/yYw80e6sVefurFX/7qxV/+q+
hP/69vD//////////////////////////////////fz7/9GbU//QkDz/0JA8/8+PPOnurFXn7qxV/+yw
Y//79/P////////////////////////////////////////////ZuIz/0JA8/9CQPP/Pjzzp7qxVz+6s
Vf/sr2H/8eLO/////////////v7+//n07f/+/v7/////////////////48yu/8+PO//Qjzv/yYs80e6s
VZLurFX/67Jm//7+/f/8+fb/68yl/+qza//rsmf//v37//////////////////Pn2P/ip1n/2phC/8CH
PJXurFUw7qxV/eq2c//169//6rNr/+6sVf/urFX/7q1W//Pm1f/////////////////8+fX/67+G/++t
Vf3lpVEyAAAAAO6sVZHtrVr/7a9c/+6sVf/urFX/7qxV/+6sVf/rsWP/7de5//Lj0P/pxJL/67Zy/+qz
av/urFWTAAAAAAAAAADurFUI7qxVtO6sVf/urFX/7qxV/+6sVf/urFX/7qxV/+6sVf/urFX/7qxV/+6s
Vf/urFW37qxVCQAAAAAAAAAAAAAAAO6sVQjurFWQ7qxV++6sVf/urFX/7qxV/+6sVf/urFX/7qxV/+6s
VfvurFWS7qxVCQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAO6sVTPurFWQ7qxVzO6sVeburFXm7qxVzO6s
VZDurFU0AAAAAAAAAAAAAAAAAAAAAPAPrEHAA6xBgAGsQYABrEEAAKxBAACsQQAArEEAAKxBAACsQQAA
rEEAAKxBAACsQYABrEGAAaxBwAOsQfAPrEE=
</value>
<data name="trayIcon.TrayLocation" type="System.Drawing.Point, System.Drawing">
<value>17, 17</value>
</data>
<data name="toolTip.TrayLocation" type="System.Drawing.Point, System.Drawing">
<value>112, 17</value>
</data>
</root>

View File

@@ -95,14 +95,14 @@ namespace TweetDck.Core{
pluginJS = ScriptLoader.LoadResource(PluginManager.PluginNotificationScriptFile);
browser = new ChromiumWebBrowser("about:blank"){
MenuHandler = new ContextMenuNotification(this,autoHide),
MenuHandler = new ContextMenuNotification(this, autoHide),
LifeSpanHandler = new LifeSpanHandler()
};
browser.IsBrowserInitializedChanged += Browser_IsBrowserInitializedChanged;
browser.FrameLoadEnd += Browser_FrameLoadEnd;
browser.RegisterJsObject("$TD",new TweetDeckBridge(owner,this));
browser.RegisterAsyncJsObject("$TDP",plugins.Bridge);
browser.RegisterJsObject("$TD", new TweetDeckBridge(owner, this));
browser.RegisterAsyncJsObject("$TDP", plugins.Bridge);
panelBrowser.Controls.Add(browser);
@@ -112,7 +112,6 @@ namespace TweetDck.Core{
}
mouseHookDelegate = MouseHookProc;
mouseHook = NativeMethods.SetWindowsHookEx(NativeMethods.WH_MOUSE_LL,mouseHookDelegate,IntPtr.Zero,0);
Disposed += FormNotification_Disposed;
}
@@ -125,16 +124,31 @@ namespace TweetDck.Core{
base.WndProc(ref m);
}
// mouse wheel hook
private void StartMouseHook(){
if (mouseHook == IntPtr.Zero){
mouseHook = NativeMethods.SetWindowsHookEx(NativeMethods.WH_MOUSE_LL, mouseHookDelegate, IntPtr.Zero, 0);
}
}
private void StopMouseHook(){
if (mouseHook != IntPtr.Zero){
NativeMethods.UnhookWindowsHookEx(mouseHook);
mouseHook = IntPtr.Zero;
}
}
private IntPtr MouseHookProc(int nCode, IntPtr wParam, IntPtr lParam){
if (!ContainsFocus && wParam.ToInt32() == NativeMethods.WH_MOUSEWHEEL && browser.Bounds.Contains(PointToClient(Cursor.Position))){
// fuck it, Activate() doesn't work with this
Point prevPos = Cursor.Position;
Cursor.Position = PointToScreen(new Point(-1,-1));
Cursor.Position = PointToScreen(new Point(0, -1));
NativeMethods.SimulateMouseClick(NativeMethods.MouseButton.Left);
Cursor.Position = prevPos;
}
return NativeMethods.CallNextHookEx(mouseHook,nCode,wParam,lParam);
return NativeMethods.CallNextHookEx(mouseHook, nCode, wParam, lParam);
}
// event handlers
@@ -145,7 +159,7 @@ namespace TweetDck.Core{
timeLeft -= timerProgress.Interval;
int value = (int)Math.Round(1025.0*(totalTime-timeLeft)/totalTime);
progressBarTimer.SetValueInstant(Math.Min(1000,Math.Max(0,Program.UserConfig.NotificationTimerCountDown ? 1000-value : value)));
progressBarTimer.SetValueInstant(Math.Min(1000, Math.Max(0, Program.UserConfig.NotificationTimerCountDown ? 1000-value : value)));
if (timeLeft <= 0){
FinishCurrentTweet();
@@ -163,7 +177,7 @@ namespace TweetDck.Core{
private void Browser_IsBrowserInitializedChanged(object sender, IsBrowserInitializedChangedEventArgs e){
if (e.IsBrowserInitialized && Initialized != null){
Initialized(this,new EventArgs());
Initialized(this, new EventArgs());
}
}
@@ -174,15 +188,16 @@ namespace TweetDck.Core{
isInitialized = true;
if (Initialized != null){
Initialized(this,new EventArgs());
Initialized(this, new EventArgs());
}
}
else if (notificationJS != null && browser.Address != "about:blank"){
ScriptLoader.ExecuteScript(e.Frame,notificationJS,NotificationScriptIdentifier);
ScriptLoader.ExecuteScript(e.Frame, notificationJS, NotificationScriptIdentifier);
if (plugins.HasAnyPlugin(PluginEnvironment.Notification)){
ScriptLoader.ExecuteScript(e.Frame,pluginJS,PluginScriptIdentifier);
plugins.ExecutePlugins(e.Frame,PluginEnvironment.Notification,false);
ScriptLoader.ExecuteScript(e.Frame, pluginJS, PluginScriptIdentifier);
ScriptLoader.ExecuteFile(e.Frame, PluginManager.PluginGlobalScriptFile);
plugins.ExecutePlugins(e.Frame, PluginEnvironment.Notification, false);
}
}
}
@@ -197,11 +212,7 @@ namespace TweetDck.Core{
private void FormNotification_Disposed(object sender, EventArgs e){
browser.Dispose();
if (mouseHook != IntPtr.Zero){
NativeMethods.UnhookWindowsHookEx(mouseHook);
mouseHook = IntPtr.Zero;
}
StopMouseHook();
}
// notification methods
@@ -231,12 +242,14 @@ namespace TweetDck.Core{
public void HideNotification(bool loadBlank){
if (loadBlank || Program.UserConfig.NotificationLegacyLoad){
browser.LoadHtml("","about:blank");
browser.LoadHtml("", "about:blank");
}
Location = new Point(-32000,-32000);
Location = new Point(-32000, -32000);
progressBarTimer.Value = Program.UserConfig.NotificationTimerCountDown ? 1000 : 0;
timerProgress.Stop();
StopMouseHook();
}
public void OnNotificationReady(){
@@ -268,7 +281,7 @@ namespace TweetDck.Core{
totalTime = timeLeft = tweet.GetDisplayDuration(Program.UserConfig.NotificationDurationValue);
progressBarTimer.Value = Program.UserConfig.NotificationTimerCountDown ? 1000 : 0;
browser.LoadHtml(tweet.GenerateHtml(),"http://tweetdeck.twitter.com/?"+DateTime.Now.Ticks);
browser.LoadHtml(tweet.GenerateHtml(), "http://tweetdeck.twitter.com/?"+DateTime.Now.Ticks);
if (Program.UserConfig.NotificationLegacyLoad){
OnNotificationReady();
@@ -282,11 +295,11 @@ namespace TweetDck.Core{
RequiresResize = false;
if (config.DisplayNotificationTimer){
ClientSize = new Size(BaseClientWidth,BaseClientHeight+4);
ClientSize = new Size(BaseClientWidth, BaseClientHeight+4);
progressBarTimer.Visible = true;
}
else{
ClientSize = new Size(BaseClientWidth,BaseClientHeight);
ClientSize = new Size(BaseClientWidth, BaseClientHeight);
progressBarTimer.Visible = false;
}
@@ -304,24 +317,24 @@ namespace TweetDck.Core{
switch(config.NotificationPosition){
case TweetNotification.Position.TopLeft:
Location = new Point(screen.WorkingArea.X+edgeDist,screen.WorkingArea.Y+edgeDist);
Location = new Point(screen.WorkingArea.X+edgeDist, screen.WorkingArea.Y+edgeDist);
break;
case TweetNotification.Position.TopRight:
Location = new Point(screen.WorkingArea.X+screen.WorkingArea.Width-edgeDist-Width,screen.WorkingArea.Y+edgeDist);
Location = new Point(screen.WorkingArea.X+screen.WorkingArea.Width-edgeDist-Width, screen.WorkingArea.Y+edgeDist);
break;
case TweetNotification.Position.BottomLeft:
Location = new Point(screen.WorkingArea.X+edgeDist,screen.WorkingArea.Y+screen.WorkingArea.Height-edgeDist-Height);
Location = new Point(screen.WorkingArea.X+edgeDist, screen.WorkingArea.Y+screen.WorkingArea.Height-edgeDist-Height);
break;
case TweetNotification.Position.BottomRight:
Location = new Point(screen.WorkingArea.X+screen.WorkingArea.Width-edgeDist-Width,screen.WorkingArea.Y+screen.WorkingArea.Height-edgeDist-Height);
Location = new Point(screen.WorkingArea.X+screen.WorkingArea.Width-edgeDist-Width, screen.WorkingArea.Y+screen.WorkingArea.Height-edgeDist-Height);
break;
case TweetNotification.Position.Custom:
if (!config.IsCustomNotificationPositionSet){
config.CustomNotificationPosition = new Point(screen.WorkingArea.X+screen.WorkingArea.Width-edgeDist-Width,screen.WorkingArea.Y+edgeDist);
config.CustomNotificationPosition = new Point(screen.WorkingArea.X+screen.WorkingArea.Width-edgeDist-Width, screen.WorkingArea.Y+edgeDist);
config.Save();
}
@@ -330,8 +343,10 @@ namespace TweetDck.Core{
}
if (needsReactivating){
NativeMethods.SetFormPos(this,NativeMethods.HWND_TOPMOST,NativeMethods.SWP_NOACTIVATE);
NativeMethods.SetFormPos(this, NativeMethods.HWND_TOPMOST, NativeMethods.SWP_NOACTIVATE);
}
StartMouseHook();
}
private void UpdateTitle(){
@@ -344,8 +359,8 @@ namespace TweetDck.Core{
}
else{
Point position = PointToClient(Cursor.Position);
position.Offset(20,5);
toolTip.Show(text,this,position);
position.Offset(20, 5);
toolTip.Show(text, this, position);
}
}
}

View File

@@ -0,0 +1,16 @@
using CefSharp;
using System;
namespace TweetDck.Core.Handling{
class BrowserProcessHandler : IBrowserProcessHandler{
void IBrowserProcessHandler.OnContextInitialized(){
using(IRequestContext ctx = Cef.GetGlobalRequestContext()){
string err;
ctx.SetPreference("browser.enable_spellchecking", Program.UserConfig.EnableSpellCheck, out err);
}
}
void IBrowserProcessHandler.OnScheduleMessagePumpWork(long delay){}
void IDisposable.Dispose(){}
}
}

View File

@@ -6,38 +6,38 @@ 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 MenuOpenLinkUrl = 26500;
private const int MenuCopyLinkUrl = 26501;
private const int MenuOpenImage = 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){
if (parameters.TypeFlags.HasFlag(ContextMenuType.Link) && !parameters.UnfilteredLinkUrl.EndsWith("tweetdeck.twitter.com/#",StringComparison.Ordinal)){
model.AddItem((CefMenuCommand)MenuOpenUrlInBrowser,"Open in browser");
model.AddItem((CefMenuCommand)MenuCopyUrl,"Copy link address");
if (parameters.TypeFlags.HasFlag(ContextMenuType.Link) && !parameters.UnfilteredLinkUrl.EndsWith("tweetdeck.twitter.com/#", StringComparison.Ordinal)){
model.AddItem((CefMenuCommand)MenuOpenLinkUrl, "Open link in browser");
model.AddItem((CefMenuCommand)MenuCopyLinkUrl, "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.AddItem((CefMenuCommand)MenuOpenImage, "Open image in browser");
model.AddItem((CefMenuCommand)MenuSaveImage, "Save image as...");
model.AddItem((CefMenuCommand)MenuCopyImageUrl, "Copy image address");
model.AddSeparator();
}
}
public virtual bool OnContextMenuCommand(IWebBrowser browserControl, IBrowser browser, IFrame frame, IContextMenuParams parameters, CefMenuCommand commandId, CefEventFlags eventFlags){
switch((int)commandId){
case MenuOpenUrlInBrowser:
case MenuOpenLinkUrl:
BrowserUtils.OpenExternalBrowser(parameters.LinkUrl);
break;
case MenuCopyUrl:
Clipboard.SetText(string.IsNullOrEmpty(TweetDeckBridge.LastRightClickedLink) ? parameters.UnfilteredLinkUrl : TweetDeckBridge.LastRightClickedLink,TextDataFormat.UnicodeText);
case MenuCopyLinkUrl:
Clipboard.SetText(string.IsNullOrEmpty(TweetDeckBridge.LastRightClickedLink) ? parameters.UnfilteredLinkUrl : TweetDeckBridge.LastRightClickedLink, TextDataFormat.UnicodeText);
break;
case MenuOpenImageInBrowser:
case MenuOpenImage:
BrowserUtils.OpenExternalBrowser(parameters.SourceUrl);
break;
@@ -57,15 +57,15 @@ namespace TweetDck.Core.Handling{
}
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);
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);
Clipboard.SetText(parameters.SourceUrl, TextDataFormat.UnicodeText);
break;
}
@@ -84,15 +84,21 @@ namespace TweetDck.Core.Handling{
}
}
protected static void AddSeparator(IMenuModel model){
if (model.Count > 0 && model.GetTypeAt(model.Count-1) != MenuItemType.Separator){ // do not add separators if there is nothing to separate
model.AddSeparator();
}
}
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);
int colon = url.IndexOf(':', dot);
if (colon != -1){
url = url.Substring(0,colon);
url = url.Substring(0, colon);
}
}

View File

@@ -1,15 +1,20 @@
using CefSharp;
using System.Windows.Forms;
using TweetDck.Core.Controls;
using TweetDck.Core.Utils;
namespace TweetDck.Core.Handling{
class ContextMenuBrowser : ContextMenuBase{
private const int MenuSettings = 26600;
private const int MenuPlugins = 26005;
private const int MenuAbout = 26601;
private const int MenuMute = 26602;
private const int MenuCopyTweetUrl = 26603;
private const int MenuCopyTweetEmbeddedUrl = 26604;
private const int MenuGlobal = 26600;
private const int MenuMute = 26601;
private const int MenuSettings = 26602;
private const int MenuPlugins = 26003;
private const int MenuAbout = 26604;
private const int MenuOpenTweetUrl = 26610;
private const int MenuCopyTweetUrl = 26611;
private const int MenuOpenQuotedTweetUrl = 26612;
private const int MenuCopyQuotedTweetUrl = 26613;
private readonly FormBrowser form;
@@ -24,35 +29,39 @@ namespace TweetDck.Core.Handling{
model.Remove(CefMenuCommand.ViewSource);
RemoveSeparatorIfLast(model);
if (!string.IsNullOrEmpty(TweetDeckBridge.LastHighlightedTweet)){
model.AddItem((CefMenuCommand)MenuCopyTweetUrl,"Copy tweet address");
base.OnBeforeContextMenu(browserControl, browser, frame, parameters, model);
if (!string.IsNullOrEmpty(TweetDeckBridge.LastHighlightedTweetEmbedded)){
model.AddItem((CefMenuCommand)MenuCopyTweetEmbeddedUrl,"Copy quoted tweet address");
if (!string.IsNullOrEmpty(TweetDeckBridge.LastHighlightedTweet) && (parameters.TypeFlags & (ContextMenuType.Editable | ContextMenuType.Selection)) == 0){
model.AddItem((CefMenuCommand)MenuOpenTweetUrl, "Open tweet in browser");
model.AddItem((CefMenuCommand)MenuCopyTweetUrl, "Copy tweet address");
if (!string.IsNullOrEmpty(TweetDeckBridge.LastHighlightedQuotedTweet)){
model.AddSeparator();
model.AddItem((CefMenuCommand)MenuOpenQuotedTweetUrl, "Open quoted tweet in browser");
model.AddItem((CefMenuCommand)MenuCopyQuotedTweetUrl, "Copy quoted tweet address");
}
model.AddSeparator();
}
base.OnBeforeContextMenu(browserControl,browser,frame,parameters,model);
if ((parameters.TypeFlags & (ContextMenuType.Editable | ContextMenuType.Selection)) == 0){
AddSeparator(model);
if (model.Count > 0){
RemoveSeparatorIfLast(model);
model.AddSeparator();
IMenuModel globalMenu = model.Count == 0 ? model : model.AddSubMenu((CefMenuCommand)MenuGlobal, Program.BrandName);
globalMenu.AddItem(CefMenuCommand.Reload, "Reload browser");
globalMenu.AddCheckItem((CefMenuCommand)MenuMute, "Mute notifications");
globalMenu.SetChecked((CefMenuCommand)MenuMute, Program.UserConfig.MuteNotifications);
globalMenu.AddSeparator();
globalMenu.AddItem((CefMenuCommand)MenuSettings, "Settings");
globalMenu.AddItem((CefMenuCommand)MenuPlugins, "Plugins");
globalMenu.AddItem((CefMenuCommand)MenuAbout, "About "+Program.BrandName);
}
model.AddItem(CefMenuCommand.Reload,"Reload");
model.AddCheckItem((CefMenuCommand)MenuMute,"Mute notifications");
model.SetChecked((CefMenuCommand)MenuMute,Program.UserConfig.MuteNotifications);
model.AddSeparator();
model.AddItem((CefMenuCommand)MenuSettings,"Settings");
model.AddItem((CefMenuCommand)MenuPlugins,"Plugins");
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)){
if (base.OnContextMenuCommand(browserControl, browser, frame, parameters, commandId, eventFlags)){
return true;
}
@@ -81,12 +90,20 @@ namespace TweetDck.Core.Handling{
return true;
case MenuCopyTweetUrl:
Clipboard.SetText(TweetDeckBridge.LastHighlightedTweet,TextDataFormat.UnicodeText);
case MenuOpenTweetUrl:
BrowserUtils.OpenExternalBrowser(TweetDeckBridge.LastHighlightedTweet);
return true;
case MenuCopyTweetEmbeddedUrl:
Clipboard.SetText(TweetDeckBridge.LastHighlightedTweetEmbedded,TextDataFormat.UnicodeText);
case MenuCopyTweetUrl:
Clipboard.SetText(TweetDeckBridge.LastHighlightedTweet, TextDataFormat.UnicodeText);
return true;
case MenuOpenQuotedTweetUrl:
BrowserUtils.OpenExternalBrowser(TweetDeckBridge.LastHighlightedQuotedTweet);
return true;
case MenuCopyQuotedTweetUrl:
Clipboard.SetText(TweetDeckBridge.LastHighlightedQuotedTweet, TextDataFormat.UnicodeText);
return true;
}

View File

@@ -21,30 +21,30 @@ namespace TweetDck.Core.Handling{
model.Clear();
if (enableCustomMenu){
model.AddItem((CefMenuCommand)MenuSkipTweet,"Skip tweet");
model.AddCheckItem((CefMenuCommand)MenuFreeze,"Freeze");
model.SetChecked((CefMenuCommand)MenuFreeze,form.FreezeTimer);
model.AddItem((CefMenuCommand)MenuSkipTweet, "Skip tweet");
model.AddCheckItem((CefMenuCommand)MenuFreeze, "Freeze");
model.SetChecked((CefMenuCommand)MenuFreeze, form.FreezeTimer);
model.AddSeparator();
if (!string.IsNullOrEmpty(form.CurrentUrl)){
model.AddItem((CefMenuCommand)MenuCopyTweetUrl,"Copy tweet address");
model.AddItem((CefMenuCommand)MenuCopyTweetUrl, "Copy tweet address");
if (!string.IsNullOrEmpty(TweetDeckBridge.NotificationTweetEmbedded)){
model.AddItem((CefMenuCommand)MenuCopyTweetEmbeddedUrl,"Copy quoted tweet address");
model.AddItem((CefMenuCommand)MenuCopyTweetEmbeddedUrl, "Copy quoted tweet address");
}
model.AddSeparator();
}
}
base.OnBeforeContextMenu(browserControl,browser,frame,parameters,model);
base.OnBeforeContextMenu(browserControl, browser, frame, parameters, model);
RemoveSeparatorIfLast(model);
form.InvokeSafe(() => form.ContextMenuOpen = true);
}
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)){
if (base.OnContextMenuCommand(browserControl, browser, frame, parameters, commandId, eventFlags)){
return true;
}
@@ -58,11 +58,11 @@ namespace TweetDck.Core.Handling{
return true;
case MenuCopyTweetUrl:
Clipboard.SetText(form.CurrentUrl,TextDataFormat.UnicodeText);
Clipboard.SetText(form.CurrentUrl, TextDataFormat.UnicodeText);
return true;
case MenuCopyTweetEmbeddedUrl:
Clipboard.SetText(TweetDeckBridge.NotificationTweetEmbedded,TextDataFormat.UnicodeText);
Clipboard.SetText(TweetDeckBridge.NotificationTweetEmbedded, TextDataFormat.UnicodeText);
return true;
}
@@ -70,7 +70,7 @@ namespace TweetDck.Core.Handling{
}
public override void OnContextMenuDismissed(IWebBrowser browserControl, IBrowser browser, IFrame frame){
base.OnContextMenuDismissed(browserControl,browser,frame);
base.OnContextMenuDismissed(browserControl, browser, frame);
form.InvokeSafe(() => form.ContextMenuOpen = false);
}
}

View File

@@ -12,7 +12,7 @@ namespace TweetDck.Core.Handling{
public bool OnFileDialog(IWebBrowser browserControl, IBrowser browser, CefFileDialogMode mode, string title, string defaultFilePath, List<string> acceptFilters, int selectedAcceptFilter, IFileDialogCallback callback){
if (!string.IsNullOrEmpty(TweetDeckBridge.ClipboardImagePath)){
callback.Continue(selectedAcceptFilter,new List<string>{ TweetDeckBridge.ClipboardImagePath });
callback.Continue(selectedAcceptFilter, new List<string>{ TweetDeckBridge.ClipboardImagePath });
form.InvokeSafe(() => {
TweetDeckBridge.ClipboardImagePath = string.Empty;

View File

@@ -10,7 +10,7 @@ namespace TweetDck.Core.Handling{
class TweetDeckBridge{
public static string LastRightClickedLink = string.Empty;
public static string LastHighlightedTweet = string.Empty;
public static string LastHighlightedTweetEmbedded = string.Empty;
public static string LastHighlightedQuotedTweet = string.Empty;
public static string NotificationTweetEmbedded = string.Empty;
public static string ClipboardImagePath = string.Empty;
@@ -74,10 +74,10 @@ namespace TweetDck.Core.Handling{
form.InvokeSafe(() => LastRightClickedLink = link);
}
public void SetLastHighlightedTweet(string link, string embeddedLink){
public void SetLastHighlightedTweet(string link, string quotedLink){
form.InvokeSafe(() => {
LastHighlightedTweet = link;
LastHighlightedTweetEmbedded = embeddedLink;
LastHighlightedQuotedTweet = quotedLink;
});
}
@@ -96,7 +96,7 @@ namespace TweetDck.Core.Handling{
public void OnTweetPopup(string tweetHtml, string tweetUrl, int tweetCharacters){
notification.InvokeSafe(() => {
form.OnTweetNotification();
notification.ShowNotification(new TweetNotification(tweetHtml,tweetUrl,tweetCharacters));
notification.ShowNotification(new TweetNotification(tweetHtml, tweetUrl, tweetCharacters));
});
}
@@ -128,12 +128,12 @@ namespace TweetDck.Core.Handling{
try{
Directory.CreateDirectory(Program.TemporaryPath);
ClipboardImagePath = Path.Combine(Program.TemporaryPath,"TD-Img-"+DateTime.Now.Ticks+".png");
img.Save(ClipboardImagePath,ImageFormat.Png);
ClipboardImagePath = Path.Combine(Program.TemporaryPath, "TD-Img-"+DateTime.Now.Ticks+".png");
img.Save(ClipboardImagePath, ImageFormat.Png);
form.OnImagePasted();
}catch(Exception e){
Program.HandleException("Could not paste image from clipboard.",e);
Program.Reporter.HandleException("Clipboard Image Error", "Could not paste image from clipboard.", true, e);
}
}
});
@@ -143,7 +143,7 @@ namespace TweetDck.Core.Handling{
form.InvokeSafe(() => {
Point prevPos = Cursor.Position;
Cursor.Position = form.PointToScreen(new Point(offsetX,offsetY));
Cursor.Position = form.PointToScreen(new Point(offsetX, offsetY));
NativeMethods.SimulateMouseClick(NativeMethods.MouseButton.Left);
Cursor.Position = prevPos;
@@ -155,6 +155,19 @@ namespace TweetDck.Core.Handling{
BrowserUtils.OpenExternalBrowser(url);
}
public void Alert(string type, string contents){
MessageBoxIcon icon;
switch(type){
case "error": icon = MessageBoxIcon.Error; break;
case "warning": icon = MessageBoxIcon.Warning; break;
case "info": icon = MessageBoxIcon.Information; break;
default: icon = MessageBoxIcon.None; break;
}
MessageBox.Show(contents, Program.BrandName+" Browser Message", MessageBoxButtons.OK, icon);
}
public void Log(string data){
System.Diagnostics.Debug.WriteLine(data);
}

View File

@@ -43,14 +43,19 @@ namespace TweetDck.Core.Handling{
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(@"<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/765161905312980992/AhDP9iY-_normal.jpg' 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(@"</a>");
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>");
#if DEBUG
build.Append(@"<div style='margin-top:64px'>Scrollbar test padding...</div>");
#endif
build.Append(@"</div></div></article>");
return new TweetNotification(build.ToString(),"",95);
return new TweetNotification(build.ToString(), "", 95);
}
}
@@ -87,7 +92,7 @@ namespace TweetDck.Core.Handling{
}
public int GetDisplayDuration(int value){
return 2000+Math.Max(1000,value*characters);
return 2000+Math.Max(1000, value*characters);
}
public string GenerateHtml(){

View File

@@ -13,9 +13,9 @@ namespace TweetDck.Core.Other{
labelDescription.Text = Program.BrandName+" was created by chylex as a replacement to the discontinued official TweetDeck client for Windows.\n\nThe program is available for free under the open source MIT license.";
labelWebsite.Links.Add(new LinkLabel.Link(0,labelWebsite.Text.Length,Program.Website));
labelSourceCode.Links.Add(new LinkLabel.Link(0,labelSourceCode.Text.Length,GitHubLink));
labelIssues.Links.Add(new LinkLabel.Link(0,labelIssues.Text.Length,IssuesLink));
labelWebsite.Links.Add(new LinkLabel.Link(0, labelWebsite.Text.Length, Program.Website));
labelSourceCode.Links.Add(new LinkLabel.Link(0, labelSourceCode.Text.Length, GitHubLink));
labelIssues.Links.Add(new LinkLabel.Link(0, labelIssues.Text.Length, IssuesLink));
}
private void OnLinkClicked(object sender, LinkLabelLinkClickedEventArgs e){

79
Core/Other/FormMessage.Designer.cs generated Normal file
View File

@@ -0,0 +1,79 @@
namespace TweetDck.Core.Other {
partial class FormMessage {
/// <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.panelActions = new System.Windows.Forms.Panel();
this.labelMessage = new System.Windows.Forms.Label();
this.SuspendLayout();
//
// panelActions
//
this.panelActions.BackColor = System.Drawing.SystemColors.Control;
this.panelActions.Dock = System.Windows.Forms.DockStyle.Bottom;
this.panelActions.Location = new System.Drawing.Point(0, 84);
this.panelActions.Name = "panelActions";
this.panelActions.Size = new System.Drawing.Size(233, 49);
this.panelActions.TabIndex = 0;
//
// labelMessage
//
this.labelMessage.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom)
| System.Windows.Forms.AnchorStyles.Left)
| System.Windows.Forms.AnchorStyles.Right)));
this.labelMessage.AutoSize = true;
this.labelMessage.Font = new System.Drawing.Font("Microsoft Sans Serif", 9F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(238)));
this.labelMessage.Location = new System.Drawing.Point(62, 33);
this.labelMessage.Margin = new System.Windows.Forms.Padding(53, 24, 27, 24);
this.labelMessage.MaximumSize = new System.Drawing.Size(600, 0);
this.labelMessage.MinimumSize = new System.Drawing.Size(0, 24);
this.labelMessage.Name = "labelMessage";
this.labelMessage.Size = new System.Drawing.Size(0, 24);
this.labelMessage.TabIndex = 1;
this.labelMessage.SizeChanged += new System.EventHandler(this.labelMessage_SizeChanged);
//
// FormMessage
//
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
this.BackColor = System.Drawing.Color.White;
this.ClientSize = new System.Drawing.Size(98, 133);
this.Controls.Add(this.labelMessage);
this.Controls.Add(this.panelActions);
this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedSingle;
this.MaximizeBox = false;
this.MinimizeBox = false;
this.Name = "FormMessage";
this.ShowIcon = false;
this.StartPosition = System.Windows.Forms.FormStartPosition.CenterScreen;
this.ResumeLayout(false);
this.PerformLayout();
}
#endregion
private System.Windows.Forms.Panel panelActions;
private System.Windows.Forms.Label labelMessage;
}
}

114
Core/Other/FormMessage.cs Normal file
View File

@@ -0,0 +1,114 @@
using System;
using System.Drawing;
using System.Windows.Forms;
namespace TweetDck.Core.Other{
sealed partial class FormMessage : Form{
public Button ClickedButton { get; private set; }
private readonly Icon icon;
private readonly bool isReady;
private int realFormWidth, minFormWidth;
private int buttonCount;
private int prevLabelWidth, prevLabelHeight;
private bool wasLabelMultiline;
public FormMessage(string caption, string text, MessageBoxIcon messageIcon){
InitializeComponent();
this.prevLabelWidth = labelMessage.Width;
this.prevLabelHeight = labelMessage.Height;
this.minFormWidth = 18;
switch(messageIcon){
case MessageBoxIcon.Information:
icon = SystemIcons.Information;
break;
case MessageBoxIcon.Warning:
icon = SystemIcons.Warning;
break;
case MessageBoxIcon.Error:
icon = SystemIcons.Error;
break;
default:
icon = null;
labelMessage.Location = new Point(labelMessage.Location.X-32, labelMessage.Location.Y);
break;
}
this.isReady = true;
this.Text = caption;
this.labelMessage.Text = text;
}
public Button AddButton(string title){
Button button = new Button{
Anchor = AnchorStyles.Bottom | AnchorStyles.Right,
Location = new Point(Width-112-buttonCount*96, 12),
Size = new Size(88, 26),
TabIndex = buttonCount,
Text = title,
UseVisualStyleBackColor = true
};
button.Click += (sender, args) => {
ClickedButton = (Button)sender;
DialogResult = DialogResult.OK;
Close();
};
panelActions.Controls.Add(button);
minFormWidth += 96;
Width = Math.Max(realFormWidth, minFormWidth);
++buttonCount;
return button;
}
public void AddActionControl(Control control){
panelActions.Controls.Add(control);
minFormWidth += control.Width+control.Margin.Horizontal;
Width = Math.Max(realFormWidth, minFormWidth);
}
private void labelMessage_SizeChanged(object sender, EventArgs e){
if (!isReady){
return;
}
bool isMultiline = labelMessage.Height > labelMessage.MinimumSize.Height;
if (isMultiline && !wasLabelMultiline){
labelMessage.Location = new Point(labelMessage.Location.X, labelMessage.Location.Y-8);
prevLabelHeight += 8;
}
else if (!isMultiline && wasLabelMultiline){
labelMessage.Location = new Point(labelMessage.Location.X, labelMessage.Location.Y+8);
prevLabelHeight -= 8;
}
realFormWidth = Width-(icon == null ? 32+35+(labelMessage.Margin.Left-labelMessage.Margin.Right) : 0)+labelMessage.Margin.Right+labelMessage.Width-prevLabelWidth;
Width = Math.Max(realFormWidth, minFormWidth);
Height += labelMessage.Height-prevLabelHeight;
prevLabelWidth = labelMessage.Width;
prevLabelHeight = labelMessage.Height;
wasLabelMultiline = isMultiline;
}
protected override void OnPaint(PaintEventArgs e){
if (icon != null){
e.Graphics.DrawIcon(icon, 25, 26);
}
base.OnPaint(e);
}
}
}

View File

@@ -23,7 +23,6 @@
/// the contents of this method with the code editor.
/// </summary>
private void InitializeComponent() {
System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(FormPlugins));
this.btnClose = new System.Windows.Forms.Button();
this.btnReload = new System.Windows.Forms.Button();
this.btnOpenFolder = new System.Windows.Forms.Button();
@@ -69,7 +68,7 @@
this.btnOpenFolder.UseVisualStyleBackColor = true;
this.btnOpenFolder.Click += new System.EventHandler(this.btnOpenFolder_Click);
//
// pluginList
// tabPanelPlugins
//
this.tabPanelPlugins.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom)
| System.Windows.Forms.AnchorStyles.Left)
@@ -88,11 +87,10 @@
this.Controls.Add(this.btnOpenFolder);
this.Controls.Add(this.btnReload);
this.Controls.Add(this.btnClose);
this.Icon = ((System.Drawing.Icon)(resources.GetObject("$this.Icon")));
this.Icon = global::TweetDck.Properties.Resources.icon;
this.MinimumSize = new System.Drawing.Size(480, 320);
this.Name = "FormPlugins";
this.StartPosition = System.Windows.Forms.FormStartPosition.CenterParent;
this.Text = "Plugins";
this.ResumeLayout(false);
this.PerformLayout();

View File

@@ -1,5 +1,7 @@
using System;
using System.Diagnostics;
using System.Drawing;
using System.Linq;
using System.Windows.Forms;
using TweetDck.Core.Controls;
using TweetDck.Plugins;
@@ -7,7 +9,7 @@ using TweetDck.Plugins.Controls;
using TweetDck.Plugins.Events;
namespace TweetDck.Core.Other{
partial class FormPlugins : Form{
sealed partial class FormPlugins : Form{
private readonly PluginManager pluginManager;
private readonly TabButton tabBtnOfficial, tabBtnCustom;
private readonly PluginListFlowLayout flowLayoutPlugins;
@@ -16,6 +18,8 @@ namespace TweetDck.Core.Other{
public FormPlugins(){
InitializeComponent();
Text = Program.BrandName+" Plugins";
}
public FormPlugins(PluginManager pluginManager) : this(){
@@ -28,14 +32,14 @@ namespace TweetDck.Core.Other{
this.tabPanelPlugins.SetupTabPanel(90);
this.tabPanelPlugins.ReplaceContent(flowLayoutPlugins);
this.tabBtnOfficial = tabPanelPlugins.AddButton("",() => SelectGroup(PluginGroup.Official));
this.tabBtnCustom = tabPanelPlugins.AddButton("",() => SelectGroup(PluginGroup.Custom));
this.tabBtnOfficial = tabPanelPlugins.AddButton("", () => SelectGroup(PluginGroup.Official));
this.tabBtnCustom = tabPanelPlugins.AddButton("", () => SelectGroup(PluginGroup.Custom));
this.tabPanelPlugins.SelectTab(tabBtnOfficial);
this.pluginManager_Reloaded(pluginManager,null);
this.pluginManager_Reloaded(pluginManager, null);
Shown += (sender, args) => {
Program.UserConfig.PluginsWindow.Restore(this,false);
Program.UserConfig.PluginsWindow.Restore(this, false);
};
FormClosed += (sender, args) => {
@@ -58,11 +62,20 @@ namespace TweetDck.Core.Other{
flowLayoutPlugins.SuspendLayout();
flowLayoutPlugins.Controls.Clear();
foreach(Plugin plugin in pluginManager.GetPluginsByGroup(selectedGroup.Value)){
flowLayoutPlugins.Controls.Add(new PluginControl(pluginManager,plugin));
Plugin[] plugins = pluginManager.GetPluginsByGroup(selectedGroup.Value).OrderBy(plugin => !plugin.CanRun ? 0 : pluginManager.Config.IsEnabled(plugin) ? 1 : 2).ThenBy(plugin => plugin.Name).ToArray();
for(int index = 0; index < plugins.Length; index++){
flowLayoutPlugins.Controls.Add(new PluginControl(pluginManager, plugins[index]));
if (index < plugins.Length-1){
flowLayoutPlugins.Controls.Add(new Panel{
BackColor = Color.DimGray,
Size = new Size(1, 1)
});
}
}
flowLayoutPlugins_Resize(flowLayoutPlugins,new EventArgs());
flowLayoutPlugins_Resize(flowLayoutPlugins, new EventArgs());
flowLayoutPlugins.ResumeLayout(true);
}
@@ -72,20 +85,33 @@ namespace TweetDck.Core.Other{
}
private void flowLayoutPlugins_Resize(object sender, EventArgs e){
int horizontalOffset = 8+(flowLayoutPlugins.VerticalScroll.Visible ? SystemInformation.VerticalScrollBarWidth : 0);
if (flowLayoutPlugins.Controls.Count == 0){
return;
}
Control lastControl = flowLayoutPlugins.Controls[flowLayoutPlugins.Controls.Count-1];
bool showScrollBar = lastControl.Location.Y+lastControl.Height >= flowLayoutPlugins.Height;
int horizontalOffset = showScrollBar ? SystemInformation.VerticalScrollBarWidth : 0;
flowLayoutPlugins.AutoScroll = showScrollBar;
flowLayoutPlugins.VerticalScroll.Visible = showScrollBar;
foreach(Control control in flowLayoutPlugins.Controls){
control.Width = flowLayoutPlugins.Width-control.Margin.Horizontal-horizontalOffset;
}
flowLayoutPlugins.Focus();
}
private void btnOpenFolder_Click(object sender, EventArgs e){
using(Process.Start("explorer.exe","\""+pluginManager.PathCustomPlugins+"\"")){}
using(Process.Start("explorer.exe", "\""+pluginManager.PathCustomPlugins+"\"")){}
}
private void btnReload_Click(object sender, EventArgs e){
pluginManager.Reload();
ReloadPluginTab();
if (MessageBox.Show("This will also reload the browser window. Do you want to proceed?", "Reloading Plugins", MessageBoxButtons.YesNo, MessageBoxIcon.Warning, MessageBoxDefaultButton.Button2) == DialogResult.Yes){
pluginManager.Reload();
ReloadPluginTab();
}
}
private void btnClose_Click(object sender, EventArgs e){

View File

@@ -117,261 +117,4 @@
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<assembly alias="System.Drawing" name="System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" />
<data name="$this.Icon" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value>
AAABAAMAMDAAAAEAIACoJQAANgAAACAgAAABACAAqBAAAN4lAAAQEAAAAQAgAGgEAACGNgAAKAAAADAA
AABgAAAAAQAgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAqHg5IrF+OlS+hjyMw4g7tcmM
PM/MjTzezY485s2OPObMjjzfyIw80MOJPLe8hDyNs387WKx8OyQAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAApHU4FrB8OGXGijzAzo889dKR
PP/SkTz/0pE8/9GRPP/RkDz/0JA8/9CQPP/RkDz/0ZE8/9KRPP/TkTz/0pE8/86PPPbGijzCt4E8bKp6
OxoAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAKN1OB+9hTuLzI486NOR
PP/SkTz/0ZA8/9CQPP/QkDz/0JA8/9CQPP/QkDz/0JA8/9CQPP/QkDz/0JA8/9CQPP/QkDz/0JA8/9GQ
PP/SkTz/0pE8/82OPOu9hTuOq3w8IgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACidTkFuoM8csyN
POrTkjz/0ZE8/9CQPP/QkDz/0JA8/9CQPP/QkDz/0JA8/9CQPP/QkDz/0JA8/9CQPP/QkDz/0JA8/9CQ
PP/QkDz/0JA8/9CQPP/QkDz/0JA8/9GRPP/Tkjz/zY887bqEPHimeDsHAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAKp6
OynDiDvA05I8/9GRPP/QkDz/0JA8/9CQPP/QkDz/0JA8/9CQPP/QkDz/0JA8/9CQPP/QkDz/0JA8/9CQ
PP/QkDz/0JA8/9CQPP/QkDz/0JA8/9CQPP/QkDz/0JA8/9CQPP/QkDz/0ZA8/9ORPP/GijzFr308LgAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAArXw7UM2OPOvTkTz/0JA8/9CQPP/QkDz/0JA8/9CQPP/QkDz/0JA8/9CQPP/QkDz/0JA8/9CQ
PP/QkDz/0JA8/9CQPP/QkDz/0JA8/9CQPP/QkDz/0JA8/9CQPP/QkDz/0JA8/9CQPP/QkDz/0JA8/9CQ
PP/SkTz/zo887rOAPFYAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAACxfjxm0ZA8/NGRPP/QkDz/0JA8/9CQPP/QkDz/0JA8/9CQPP/QkDz/0JA8/9CQ
PP/QkDz/0JA8/9CQPP/QkDz/0JA8/9CQPP/QkDz/0JA8/9CQPP/QkDz/0JA8/9CQPP/QkDz/0JA8/9CQ
PP/QkDz/0JA8/9CQPP/QkDz/0ZE8/9GQPP64gjxtAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAALaBPGXRkTz/0ZE8/9CQPP/QkDz/0JA8/9CQPP/QkDz/0JA8/9CQ
PP/QkDz/0JA8/9CQPP/QkDz/0JA8/9CQPP/QkDz/0JA8/9CQPP/QkDz/0JA8/9CQPP/QkDz/0JA8/9CQ
PP/QkDz/0JA8/9CQPP/QkDz/0JA8/9CQPP/QkDz/0JA8/9GQPP/SkTz/uIM8bAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAqnk6TtCQPPzRkTz/0JA8/9CQPP/QkDz/0JA8/9CQ
PP/QkDz/0JA8/9CQPP/QkDz/0JA8/9CQPP/QkDz/0JA8/9CQPP/QkDz/0JA8/9CQPP/QkDz/0JA8/9CQ
PP/QkDz/0JA8/9CQPP/QkDz/0JA8/9CQPP/QkDz/0JA8/9CQPP/QkDz/0JA8/9CQPP/RkDz/0ZA8/rSA
PFUAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACtfDwmzo887dKRPP/QkDz/0JA8/9CQ
PP/QkDz/0JA8/9CQPP/QkDz/0JA8/9CQPP/QkDz/0JA8/9CQPP/QkDz/0JA8/9CQPP/QkDz/0JA8/9CQ
PP/QkDz/0JA8/9CQPP/QkDz/0JA8/9CQPP/QkDz/0JA8/9CQPP/QkDz/0JA8/9CQPP/QkDz/0JA8/9CQ
PP/QkDz/0ZE8/86PPPGtfDwrAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAKZ4PAXFijzC0pE8/9CQ
PP/QkDz/0JA8/9CQPP/QkDz/0JA8/9CURf/TpGT/2baJ/9/GpP/l0bf/59W//+fVvf/kz7P/3sOg/9mz
hP/ToWH/0JND/9CQPP/QkDz/0JA8/9CQPP/QkDz/0JA8/9CQPP/QkDz/0JA8/9CQPP/QkDz/0JA8/9CQ
PP/QkDz/0JA8/9CQPP/QkDz/0JA8/9KRPP/EiTvJo3Y7CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAALiC
PG/Tkjz/0JA8/9CQPP/QkDz/0JA8/9CSQf/Vq3P/5tO7//j07v//////////////////////////////
////////////////////////9vHq/+TQtf/UqG7/0JA+/9CQPP/QkDz/0JA8/9CQPP/QkDz/0JA8/9CQ
PP/QkDz/0JA8/9CQPP/QkDz/0JA8/9CQPP/QkDz/0JA8/9CQPP/Tkjz/uYM8dgAAAAAAAAAAAAAAAAAA
AAAAAAAArXw8Gc2OPOzRkTz/0JA8/9CQPP/QlEX/27qP//fz7P//////////////////////////////
////////////////////////////////////////////////////////8ObZ/9auev/QkDz/0JA8/9CQ
PP/QkDz/0JA8/9CQPP/QkDz/0JA8/9CQPP/QkDz/0JA8/9CQPP/QkDz/0JA8/9CQPP/RkTz/zI488J1x
OB8AAAAAAAAAAAAAAAAAAAAAuoM7h9OSPP/QkDz/0JA8/9GXTf/TpGb/27uS/9u6kP/ewZz/59W9//Xv
5///////////////////////////////////////////////////////////////////////////////
///r3cr/0ZxV/9CQPP/QkDz/0JA8/9CQPP/QkDz/0JA8/9CQPP/QkDz/0JA8/9CQPP/QkDz/0JA8/9CQ
PP/QkDz/1JI8/7mDO5AAAAAAAAAAAAAAAADFj0cR0pNB6s+PO//Ojjv/0JA8/9CQPP/QkDz/0JA8/9CQ
PP/QkDz/0JA8/9CRQP/TpGf/5NC2//38+v//////////////////////////////////////////////
////////////////////////+vf0/9auev/QkDz/0JA8/9CQPP/QkDz/0JA8/9CQPP/QkDz/0JA8/9CQ
PP/QkDz/0JA8/9CQPP/QkDz/0ZE8/8uOPO6SajYVAAAAAAAAAADzr1df7qxV/+WkT//ZmUT/0JA9/86O
O//Pjzv/0JA8/9CQPP/QkDz/0JA8/9CQPP/QkDz/0JA8/9GaUv/l07r/////////////////////////
///////////////////////////////////////////////////buo//0JA8/9CQPP/QkDz/0JA8/9CQ
PP/QkDz/0JA8/9CQPP/QkDz/0JA8/9CQPP/QkDz/0JA8/9OSPP+ldjdoAAAAAAAAAADurFW67qxV//Ct
Vv/vrVb/6adR/92dSP/Skz//zo47/8+PO//QkDz/0JA8/9CQPP/QkDz/0JJB/9Smaf/dv5j/+fXw////
////////////////////////////////////////////////////////////////////////2riM/9CQ
PP/QkDz/0JA8/9CQPP/QkDz/0JA8/9CQPP/QkDz/0JA8/9CQPP/QkDz/0JA8/9KRPP/FiTzGoHQ6Ae6s
VRrurFXz7qxV/+6sVf/urFX/761W//CuVv/sqlT/4qFM/9aVQv/Pjzv/zo47/9CQPP/VqnH/8+vh////
////////////////////////////////////////////////////////////////////////////////
/////////////9aueP/QkDz/0JA8/9CQPP/QkDz/0JA8/9CQPP/QkDz/0JA8/9CQPP/QkDz/0JA8/9GQ
PP/Ojzz4oHM5Iu6sVU3urFX/7qxV/+6sVf/urFX/7qxV/+6sVf/vrVX/8K5W/+6sVf/mpU//2plF/9q6
j///////////////////////////////////////////////////////////////////////////////
//////////////////////////////n18P/Rm1P/0JA8/9CQPP/QkDz/0JA8/9CQPP/QkDz/0JA8/9CQ
PP/QkDz/0JA8/9CQPP/SkTz/rXs6Vu6sVYPurFX/7qxV/+6sVf/urFX/7qxV/+6sVf/urFX/7qxV/+6s
Vf/wrVb/6r2B////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////o18L/0JA8/9CQPP/QkDz/0JA8/9CQ
PP/QkDz/0JA8/9CQPP/QkDz/0JA8/9CQPP/SkTz/v4Y8j+6sVa3urFX/7qxV/+6sVf/urFX/7qxV/+6s
Vf/urFX/7qxV/+6sVf/urFb/9Onb///////+/v3/////////////////////////////////////////
////////////////////////////////////////////////////////////////////////1qx2/9CQ
PP/QkDz/0JA8/9CQPP/QkDz/0JA8/9CQPP/QkDz/0JA8/9CQPP/SkTz/wYc7uO6sVcrurFX/7qxV/+6s
Vf/urFX/7qxV/+6sVf/urFX/7qxV/+6sVf/trlr/67Zy/+m+h//y5NP/////////////////////////
////////////////////////////////////////////////////////////////////////////////
////////7+TW/9CQPf/QkDz/0JA8/9CQPP/QkDz/0JA8/9CQPP/QkDz/0JA8/9CQPP/RkTz/yYw80e6s
VdvurFX/7qxV/+6sVf/urFX/7qxV/+6sVf/urFX/7qxV/+6sVf/urFX/6sme//v49P//////////////
////////////////////////////////////////////////////////////////////////////////
/////////////////////////////9arc//QkDz/0JA8/9CQPP/QkDz/0JA8/9CQPP/QkDz/0JA8/9CQ
PP/RkDz/zI083+6sVeLurFX/7qxV/+6sVf/urFX/7qxV/+6sVf/urFX/7qxV/+6sVf/u2b3/////////
////////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////+fVvv/QkDz/0JA8/9CQPP/QkDz/0JA8/9CQ
PP/QkDz/0JA8/9CQPP/QkDz/zo885u6sVeLurFX/7qxV/+6sVf/urFX/7qxV/+6sVf/urFX/7qxV/+vL
of//////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////r28v/Rl0r/0JA8/9CQ
PP/QkDz/0JA8/9CQPP/QkDz/0JA8/9CQPP/QkDz/zo885u6sVdrurFX/7qxV/+6sVf/urFX/7qxV/+6s
Vf/urFX/7LBj//r28f//////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
///Vq3P/0JA8/9CQPP/QkDz/0JA8/9CQPP/QkDz/0JA8/9CQPP/RkDz/zI083+6sVcrurFX/7qxV/+6s
Vf/urFX/7qxV/+6sVf/urFX/6cKO////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
///////////////////ewp7/0JA8/9CQPP/QkDz/0JA8/9CQPP/QkDz/0JA8/9CQPP/RkTz/yYw80O6s
VazurFX/7qxV/+6sVf/urFX/7qxV/+6sVf/urFX/7NOy//z59v/u2b7/+fPr////////////////////
////////////////////////////////////////////////////////////////////////////////
///////////////////////////////////n1sD/0JA8/9CQPP/QkDz/0JA8/9CQPP/QkDz/0JA8/9CQ
PP/SkTz/xIo8uO6sVYHurFX/7qxV/+6sVf/urFX/7qxV/+6sVf/urFX/67Zx/+2uWf/qy6H/////////
////////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////v5dj/0JA8/9CQPP/QkDz/0JA8/9CQ
PP/QkDz/0JA8/9CQPP/SkTz/vYU8je6sVUvurFX/7qxV/+6sVf/urFX/7qxV/+6sVf/urFX/7qxV/+nC
kP///////////////////////////////////////////////////////fz6//fu5P/w4Mv/793F//7+
/v/////////////////////////////////////////////////////////////////17eT/0JA//86O
Ov/Pjzv/0JA8/9CQPP/QkDz/0JA8/9CQPP/SkTz/tYA8Vu6sVRnurFXy7qxV/+6sVf/urFX/7qxV/+6s
Vf/urFX/7a5b//fw5///////////////////////////////////////+/jz/+7av//pwIr/67Jn/+6t
Vv/urFX/6rd1////////////////////////////////////////////////////////////////////
///48ej/6KhU/92cR//Tkj7/zo47/8+PO//QkDz/0JA8/9GQPP/Pjzz3rXw8IAAAAADurFW37qxV/+6s
Vf/urFX/7qxV/+6sVf/urFX/6b2D//////////////////////////////////nz6//qyZ3/7K9h/+6s
Vf/urFX/7qxV/+6sVf/urFX/6rl6////////////////////////////////////////////////////
///////////////////9/Pr/6r6C//CuV//sqlT/4aBL/9aWQv/Pjzv/zo47/9GRPP/GijzCp3g8AQAA
AADurFVb7qxV/+6sVf/urFX/7qxV/+6sVf/urFX/68yk///////////////////////+/fz/68+q/+2v
XP/urFX/7qxV/+6sVf/urFX/7qxV/+6sVf/urFX/6rNr//7+/f//////////////////////////////
/////////////////////////////////////////////+nEk//vrVX/8K5W/+6sVf/lpE//2ZlF/9KR
Pf+zfzpoAAAAAAAAAADurFUP7qxV5u6sVf/urFX/7qxV/+6sVf/urFX/7NGu//////////////////fu
5P/quHb/7qxV/+6sVf/urFX/7qxV/+6sVf/urFX/7qxV/+6sVf/urFX/7qxW//Xr3///////////////
///////////////////////////////////////////////////7+PP/+vXu///////pxJL/7qxV/+6s
Vf/wrVb/8K1W/+mnUevUmUsUAAAAAAAAAAAAAAAA7qxVgO6sVf/urFX/7qxV/+6sVf/urFX/6sqg////
////////8eLO/+yvX//urFX/7qxV/+6sVf/urFX/7qxV/+6sVf/urFX/7qxV/+6sVf/urFX/7qxV/+nF
lf/////////////////////////////////////////////////////////////////8+vf/6cWV/+q5
ev/s07H/6rd1/+6sVf/urFX/7qxV/++tVogAAAAAAAAAAAAAAAAAAAAA7qxVFe6sVejurFX/7qxV/+6s
Vf/urFX/6bp8///////w4Mn/7a1Z/+6sVf/urFX/7qxV/+6sVf/urFX/7qxV/+6sVf/urFX/7qxV/+6s
Vf/urFX/7qxV/+6sVf/x4cz////////////////////////////////////////////////////+//7+
/v/////////+/+m8gP/urFX/7a1Y/+6sVf/urFX/7qxV7O6sVRoAAAAAAAAAAAAAAAAAAAAAAAAAAO6s
VWburFX/7qxV/+6sVf/urFX/7a5b/+zTs//sr1//7qxV/+6sVf/urFX/7qxV/+6sVf/urFX/7qxV/+6s
Vf/urFX/7qxV/+6sVf/urFX/7qxV/+6sVf/sr1//8uPQ////////////////////////////////////
////////6suj/+qzav/pxpj/9Onb//n07f/rr2D/7qxV/+6sVf/urFX/7qxVbwAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAO6sVQPurFW67qxV/+6sVf/urFX/7qxV/+6sVv/urFX/7qxV/+6sVf/urFX/7qxV/+6s
Vf/urFX/7qxV/+6sVf/urFX/7qxV/+6sVf/urFX/7qxV/+6sVf/urFX/7axY/+nGl//27uP/////////
/////////fz6//Lj0P/qunv/7qxV/+6sVf/urFX/7qxV/+m9gv/qt3X/7qxV/+6sVf/urFXB7qxVBQAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADurFUg7qxV6O6sVf/urFX/7qxV/+6sVf/urFX/7qxV/+6s
Vf/urFX/7qxV/+6sVf/urFX/7qxV/+6sVf/urFX/7qxV/+6sVf/urFX/7qxV/+6sVf/urFX/7qxV/+6s
Vf/qtnP/6sqg/+3WuP/s07P/6cSS/+uyZf/urFX/7qxV/+6sVf/urFX/7qxV/+6sVv/trVr/7qxV/+6s
VezurFUlAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA7qxVRu6sVfjurFX/7qxV/+6s
Vf/urFX/7qxV/+6sVf/urFX/7qxV/+6sVf/urFX/7qxV/+6sVf/urFX/7qxV/+6sVf/urFX/7qxV/+6s
Vf/urFX/7qxV/+6sVf/urFX/7qxV/+6sVf/urFX/7qxV/+6sVf/urFX/7qxV/+6sVf/urFX/7qxV/+6s
Vf/urFX/7qxV++6sVUwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAO6s
VVzurFX97qxV/+6sVf/urFX/7qxV/+6sVf/urFX/7qxV/+6sVf/urFX/7qxV/+6sVf/urFX/7qxV/+6s
Vf/urFX/7qxV/+6sVf/urFX/7qxV/+6sVf/urFX/7qxV/+6sVf/urFX/7qxV/+6sVf/urFX/7qxV/+6s
Vf/urFX/7qxV/+6sVf/urFX/7qxVYwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAADurFVd7qxV+O6sVf/urFX/7qxV/+6sVf/urFX/7qxV/+6sVf/urFX/7qxV/+6s
Vf/urFX/7qxV/+6sVf/urFX/7qxV/+6sVf/urFX/7qxV/+6sVf/urFX/7qxV/+6sVf/urFX/7qxV/+6s
Vf/urFX/7qxV/+6sVf/urFX/7qxV/+6sVfvurFVjAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA7qxVR+6sVeXurFX/7qxV/+6sVf/urFX/7qxV/+6s
Vf/urFX/7qxV/+6sVf/urFX/7qxV/+6sVf/urFX/7qxV/+6sVf/urFX/7qxV/+6sVf/urFX/7qxV/+6s
Vf/urFX/7qxV/+6sVf/urFX/7qxV/+6sVf/urFX/7qxV6O6sVU0AAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAO6sVSPurFW37qxV/+6s
Vf/urFX/7qxV/+6sVf/urFX/7qxV/+6sVf/urFX/7qxV/+6sVf/urFX/7qxV/+6sVf/urFX/7qxV/+6s
Vf/urFX/7qxV/+6sVf/urFX/7qxV/+6sVf/urFX/7qxV/+6sVf/urFW77qxVJgAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AADurFUB7qxVae6sVeTurFX/7qxV/+6sVf/urFX/7qxV/+6sVf/urFX/7qxV/+6sVf/urFX/7qxV/+6s
Vf/urFX/7qxV/+6sVf/urFX/7qxV/+6sVf/urFX/7qxV/+6sVf/urFX/7qxV5+6sVW3urFUDAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAO6sVRjurFWA7qxV4u6sVf/urFX/7qxV/+6sVf/urFX/7qxV/+6s
Vf/urFX/7qxV/+6sVf/urFX/7qxV/+6sVf/urFX/7qxV/+6sVf/urFX/7qxV/+6sVeTurFWE7qxVGwAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA7qxVEu6sVV7urFW17qxV7+6s
Vf/urFX/7qxV/+6sVf/urFX/7qxV/+6sVf/urFX/7qxV/+6sVf/urFX/7qxV/+6sVfDurFW47qxVX+6s
VRMAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAA7qxVG+6sVUzurFWA7qxVrO6sVcnurFXa7qxV4u6sVeLurFXa7qxVye6sVa3urFWC7qxVTe6s
VR0AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAP//gAH//6gr//wAAD//qCv/8AAAD/+oK//AAAAD/6gr/4AAAAH/qCv/AAAAAP+oK/4A
AAAAf6gr/AAAAAA/qCv4AAAAAB+oK/AAAAAAD6gr4AAAAAAHqCvgAAAAAAeoK8AAAAAAA6grwAAAAAAD
qCuAAAAAAAGoK4AAAAAAAagrgAAAAAAAqCsAAAAAAACoKwAAAAAAAKgrAAAAAAAAqCsAAAAAAACoKwAA
AAAAAKgrAAAAAAAAqCsAAAAAAACoKwAAAAAAAKgrAAAAAAAAqCsAAAAAAACoKwAAAAAAAKgrAAAAAAAA
qCsAAAAAAACoKwAAAAAAAKgrgAAAAAAAqCuAAAAAAAGoK4AAAAAAAagrwAAAAAADqCvAAAAAAAOoK+AA
AAAAB6gr4AAAAAAHqCvwAAAAAA+oK/gAAAAAH6gr/AAAAAA/qCv+AAAAAH+oK/8AAAAA/6gr/4AAAAH/
qCv/wAAAA/+oK//wAAAP/6gr//wAAD//qCv//4AB//+oKygAAAAgAAAAQAAAAAEAIAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAApHY4FrR/
Ole+hjuVxos7w8uNPNvOjzznzo8858uNPNzGijzEvoU7l7WBO1mpejsYAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAqHg5Kr6F
O5XLjTvo0pE8/9ORPP/SkTz/0ZE8/9CQPP/QkDz/0ZE8/9KRPP/TkTz/0pE8/82OPOq/hjyZrXw7LAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAo3U6CbuE
O4bPjzz005I8/9GRPP/QkDz/0JA8/9CQPP/QkDz/0JA8/9CQPP/QkDz/0JA8/9CQPP/QkDz/0ZE8/9OS
PP/PkDz1vYU8iah6PAsAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAKR3
OibGizvG05E8/9GQPP/QkDz/0JA8/9CQPP/QkDz/0JA8/9CQPP/QkDz/0JA8/9CQPP/QkDz/0JA8/9CQ
PP/QkDz/0JA8/9GQPP/TkTz/yIs8yqx8PCkAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AACsezsxy40849KRPP/QkDz/0JA8/9CQPP/QkDz/0JA8/9CQPP/QkDz/0JA8/9CQPP/QkDz/0JA8/9CQ
PP/QkDz/0JA8/9CQPP/QkDz/0JA8/9CQPP/SkTz/zI485rKAPTUAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAApXc6JMuNPOTSkTz/0JA8/9CQPP/QkDz/0JA8/9CQPP/QkDz/0JA8/9CQPP/QkDz/0JA8/9CQ
PP/QkDz/0JA8/9CQPP/QkDz/0JA8/9CQPP/QkDz/0JA8/9CQPP/SkTz/zI485659PCcAAAAAAAAAAAAA
AAAAAAAAAAAAAKd4OwnHizzJ0pE8/9CQPP/QkDz/0JA9/9OgYP/YtIX/38Sh/+LMr//iy67/3sOf/9iy
gv/Tn13/0JA8/9CQPP/QkDz/0JA8/9CQPP/QkDz/0JA8/9CQPP/QkDz/0JA8/9CQPP/SkTz/x4s8zaV4
OwsAAAAAAAAAAAAAAAAAAAAAu4Q8hNOSPP/QkDz/0JA8/9GXS//YtIX/6NfC//Xv5//8+vj/////////
///8+vf/9O3k/+fVvv/YsYH/0JRF/9CQPP/QkDz/0JA8/9CQPP/QkDz/0JA8/9CQPP/QkDz/0JA8/9CQ
PP/Tkjz/u4Q7iQAAAAAAAAAAAAAAAKx7OyTPjzz10ZA8/9GXS//Ztoj/8une////////////////////
///////////////////////////////////38uz/3L2V/9CRP//QkDz/0JA8/9CQPP/QkDz/0JA8/9CQ
PP/QkDz/0JA8/9GRPP/Ojzz3onU5KQAAAAAAAAAAxo1BlNGQO//Ojjv/0JNC/9GWSP/QlET/0ZpR/9au
eP/n1b3//v79////////////////////////////////////////////7+TV/9GdWP/QkDz/0JA8/9CQ
PP/QkDz/0JA8/9CQPP/QkDz/0JA8/9SSPP+4gjqaAAAAAPGuVhHvrVXq5qRO/9qZRP/QkT3/zo46/8+P
O//QkDz/0JA8/9CQPP/To2P/8+vh////////////////////////////////////////////+fXw/9Oh
Yf/QkDz/0JA8/9CQPP/QkDz/0JA8/9CQPP/QkDz/0pE8/8qMO+2WbTYV7qxVUe6sVf/wrVb/761W/+mo
Uv/enUj/05M//86PO//PkD7/3cCZ//Lp3v/7+PT/////////////////////////////////////////
////////+PTv/9GcVf/QkDz/0JA8/9CQPP/QkDz/0JA8/9CQPP/QkDz/05I8/699OljurFWR7qxV/+6s
Vf/urFX/761W//CuV//sqlT/4qJQ/+zdyf//////////////////////////////////////////////
////////////////////////7+TV/9CRP//QkDz/0JA8/9CQPP/QkDz/0JA8/9CQPP/Tkjz/vIQ7mO6s
Vb/urFX/7qxV/+6sVf/urFX/7qxV/++tVf/ry5///v79//7+/f//////////////////////////////
////////////////////////////////////////2rqO/9CQPP/QkDz/0JA8/9CQPP/QkDz/0JA8/9KR
PP/GijvF7qxV2u6sVf/urFX/7qxV/+6sVf/urFX/7qxV/+u1bv/t1bb//fv4////////////////////
///////////////////////////////////////////////////48+3/0ZRG/9CQPP/QkDz/0JA8/9CQ
PP/QkDz/0ZA8/8uNPNzurFXl7qxV/+6sVf/urFX/7qxV/+6sVf/rsWP/9OjZ////////////////////
///////////////////////////////////////////////////////////////////YtIX/0JA8/9CQ
PP/QkDz/0JA8/9CQPP/QkDz/zo886O6sVeXurFX/7qxV/+6sVf/urFX/7qxW//Hiz///////////////
/////////////////////////////////////////////////////////////////////////////+rb
yP/QkDz/0JA8/9CQPP/QkDz/0JA8/9CQPP/Ojzzo7qxV2e6sVf/urFX/7qxV/+6sVf/quHb/////////
////////////////////////////////////////////////////////////////////////////////
////////+fXw/9CURf/QkDz/0JA8/9CQPP/QkDz/0ZA8/8yOPNzurFW/7qxV/+6sVf/urFX/7qxV/+nA
if/s1LT/9Onb////////////////////////////////////////////////////////////////////
////////////////////////0Z5b/9CQPP/QkDz/0JA8/9CQPP/SkTz/x4s8xe6sVY/urFX/7qxV/+6s
Vf/urFX/7qxV/+nEk//+/fz////////////////////////////+/v3/+PHo//To2f/+/v7/////////
///////////////////////////////////VqGz/zo46/8+PO//QkDz/0JA8/9KRPP+/hjyX7qxVUO6s
Vf/urFX/7qxV/+6sVf/ssGH//Pr2///////////////////////y49D/6cOR/+qyaf/urVb/6rJp////
/////////////////////////////////////////////+e7f//goEr/1ZVB/8+PO//Ojzv/0pE8/7WB
PFfurFUQ7qxV6O6sVf/urFX/7qxV/+m+hv/////////////////z5tX/6rl6/+6sVf/urFX/7qxV/+6s
Vf/qs2r////+////////////////////////////////////////////+PLp/+y4c//urFX/5aRO/9qZ
RP/Mjjztp3g6FQAAAADurFWQ7qxV/+6sVf/urFX/6cKP////////////682m/+6sVf/urFX/7qxV/+6s
Vf/urFX/7qxV/+2sV//17N////////////////////////////////////////7+/v/06Nn/8uTT/+qz
a//wrVb/761W/+alUZYAAAAAAAAAAO6sVSHurFX07qxV/+6sVf/quXj//////+nDkf/urFX/7qxV/+6s
Vf/urFX/7qxV/+6sVf/urFX/7qxV/+m+hP////////////////////////////////////////////jy
6v/qtnH/67Fj/+6sVf/urFX2761WJQAAAAAAAAAAAAAAAO6sVX7urFX/7qxV/+2vW//pvID/7qxV/+6s
Vf/urFX/7qxV/+6sVf/urFX/7qxV/+6sVf/urFX/7qxV/+nEkv/7+PT//////////////////fz6/+rJ
n//rtW7/682n/+zTs//urFb/7qxV/+6sVYQAAAAAAAAAAAAAAAAAAAAA7qxVB+6sVcTurFX/7qxV/+6s
Vf/urFX/7qxV/+6sVf/urFX/7qxV/+6sVf/urFX/7qxV/+6sVf/urFX/7qxV/+u0bP/qy6H/7da4/+vN
pv/qtnP/7qxV/+6sVf/urFX/7K9f/+2sWP/urFXI7qxVCQAAAAAAAAAAAAAAAAAAAAAAAAAA7qxVIO6s
VeDurFX/7qxV/+6sVf/urFX/7qxV/+6sVf/urFX/7qxV/+6sVf/urFX/7qxV/+6sVf/urFX/7qxV/+6s
Vf/urFX/7qxV/+6sVf/urFX/7qxV/+6sVf/urFX/7qxV4+6sVSMAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAA7qxVLO6sVd/urFX/7qxV/+6sVf/urFX/7qxV/+6sVf/urFX/7qxV/+6sVf/urFX/7qxV/+6s
Vf/urFX/7qxV/+6sVf/urFX/7qxV/+6sVf/urFX/7qxV/+6sVeLurFUwAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAA7qxVIu6sVcHurFX/7qxV/+6sVf/urFX/7qxV/+6sVf/urFX/7qxV/+6s
Vf/urFX/7qxV/+6sVf/urFX/7qxV/+6sVf/urFX/7qxV/+6sVf/urFXE7qxVJAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA7qxVBu6sVX/urFXw7qxV/+6sVf/urFX/7qxV/+6s
Vf/urFX/7qxV/+6sVf/urFX/7qxV/+6sVf/urFX/7qxV/+6sVf/urFXy7qxVgu6sVQgAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAO6sVSXurFWP7qxV5e6s
Vf/urFX/7qxV/+6sVf/urFX/7qxV/+6sVf/urFX/7qxV/+6sVf/urFXl7qxVke6sVScAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AADurFUS7qxVUO6sVY7urFW97qxV2O6sVeXurFXl7qxV2O6sVb7urFWP7qxVUu6sVRMAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA/8AD//8AAP/8AAA/+AAAH/AAAA/gAAAHwAAAA8AA
AAOAAAABgAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIAA
AAGAAAABwAAAA8AAAAPgAAAH8AAAD/gAAB/8AAA//wAA///AA/8oAAAAEAAAACAAAAABACAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAKx7Oja9hTqTyYw8zs6PPOfOjzznyYw8zr6G
PJSvfjw3AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAo3Y7CbyEO5PRkDz805I8/9GRPP/QkDz/0JA8/9GR
PP/TkTz/0ZA8/b+GPJWrfDwKAAAAAAAAAAAAAAAAp3g8CcSJPLfTkjz/0ZA8/9CQPP/QkDz/0JA8/9CQ
PP/QkDz/0JA8/9CQPP/Tkjz/xoo8uqx8PQoAAAAAAAAAAL2FPJPUk0D/06Rm/92/mf/izK//4sut/9u6
j//Snlr/0JA8/9CQPP/QkDz/0JA8/9OSPP+9hTyWAAAAALiEQDLQkDz90JpS/93Amf/u4tP/////////
/////////fv5/+DIqP/QkkH/0JA8/9CQPP/RkDz/0JA8/qN1OTTtq1WS56VP/9qaRf/RkT3/0JdO/+rc
yP//////////////////////693L/9CSQf/QkDz/0JA8/9SSPP+3gTqW761Vz++tVv/wrVb/6K5h//fy
6v/////////////////////////////////gx6b/0JA8/9CQPP/RkTz/yYw80e6sVefurFX/7qxV/+q+
hP/69vD//////////////////////////////////fz7/9GbU//QkDz/0JA8/8+PPOnurFXn7qxV/+yw
Y//79/P////////////////////////////////////////////ZuIz/0JA8/9CQPP/Pjzzp7qxVz+6s
Vf/sr2H/8eLO/////////////v7+//n07f/+/v7/////////////////48yu/8+PO//Qjzv/yYs80e6s
VZLurFX/67Jm//7+/f/8+fb/68yl/+qza//rsmf//v37//////////////////Pn2P/ip1n/2phC/8CH
PJXurFUw7qxV/eq2c//169//6rNr/+6sVf/urFX/7q1W//Pm1f/////////////////8+fX/67+G/++t
Vf3lpVEyAAAAAO6sVZHtrVr/7a9c/+6sVf/urFX/7qxV/+6sVf/rsWP/7de5//Lj0P/pxJL/67Zy/+qz
av/urFWTAAAAAAAAAADurFUI7qxVtO6sVf/urFX/7qxV/+6sVf/urFX/7qxV/+6sVf/urFX/7qxV/+6s
Vf/urFW37qxVCQAAAAAAAAAAAAAAAO6sVQjurFWQ7qxV++6sVf/urFX/7qxV/+6sVf/urFX/7qxV/+6s
VfvurFWS7qxVCQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAO6sVTPurFWQ7qxVzO6sVeburFXm7qxVzO6s
VZDurFU0AAAAAAAAAAAAAAAAAAAAAPAPrEHAA6xBgAGsQYABrEEAAKxBAACsQQAArEEAAKxBAACsQQAA
rEEAAKxBAACsQYABrEGAAaxBwAOsQfAPrEE=
</value>
</data>
</root>

View File

@@ -23,7 +23,6 @@
/// the contents of this method with the code editor.
/// </summary>
private void InitializeComponent() {
System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(FormSettings));
this.btnClose = new System.Windows.Forms.Button();
this.labelTip = new System.Windows.Forms.Label();
this.tabPanel = new TweetDck.Core.Controls.TabPanel();
@@ -70,7 +69,7 @@
this.Controls.Add(this.btnClose);
this.Controls.Add(this.tabPanel);
this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedSingle;
this.Icon = ((System.Drawing.Icon)(resources.GetObject("$this.Icon")));
this.Icon = Properties.Resources.icon;
this.MaximizeBox = false;
this.MinimizeBox = false;
this.Name = "FormSettings";

View File

@@ -3,23 +3,23 @@ using System.Collections.Generic;
using System.Linq;
using System.Windows.Forms;
using TweetDck.Core.Other.Settings;
using TweetDck.Core.Other.Settings.Export;
using TweetDck.Plugins;
using TweetDck.Updates;
namespace TweetDck.Core.Other{
sealed partial class FormSettings : Form{
private readonly Dictionary<Type,BaseTabSettings> tabs = new Dictionary<Type,BaseTabSettings>(4);
private readonly Dictionary<Type, BaseTabSettings> tabs = new Dictionary<Type, BaseTabSettings>(4);
public FormSettings(FormBrowser browserForm, UpdateHandler updates){
public FormSettings(FormBrowser browserForm, PluginManager plugins, UpdateHandler updates){
InitializeComponent();
Text = Program.BrandName+" Settings";
this.tabPanel.SetupTabPanel(100);
this.tabPanel.AddButton("General",SelectTab<TabSettingsGeneral>);
this.tabPanel.AddButton("Notifications",() => SelectTab(() => new TabSettingsNotifications(browserForm.CreateNotificationForm(false))));
this.tabPanel.AddButton("Updates",() => SelectTab(() => new TabSettingsUpdates(updates)));
this.tabPanel.AddButton("Advanced",() => SelectTab(() => new TabSettingsAdvanced(browserForm.ReloadBrowser)));
this.tabPanel.AddButton("General", SelectTab<TabSettingsGeneral>);
this.tabPanel.AddButton("Notifications", () => SelectTab(() => new TabSettingsNotifications(browserForm.CreateNotificationForm(false))));
this.tabPanel.AddButton("Updates", () => SelectTab(() => new TabSettingsUpdates(updates)));
this.tabPanel.AddButton("Advanced", () => SelectTab(() => new TabSettingsAdvanced(browserForm.ReloadBrowser, plugins)));
this.tabPanel.SelectTab(tabPanel.Buttons.First());
}
@@ -30,7 +30,7 @@ namespace TweetDck.Core.Other{
private void SelectTab<T>(Func<T> constructor) where T : BaseTabSettings{
BaseTabSettings control;
if (tabs.TryGetValue(typeof(T),out control)){
if (tabs.TryGetValue(typeof(T), out control)){
tabPanel.ReplaceContent(control);
}
else{

View File

@@ -117,261 +117,4 @@
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<assembly alias="System.Drawing" name="System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" />
<data name="$this.Icon" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value>
AAABAAMAMDAAAAEAIACoJQAANgAAACAgAAABACAAqBAAAN4lAAAQEAAAAQAgAGgEAACGNgAAKAAAADAA
AABgAAAAAQAgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAqHg5IrF+OlS+hjyMw4g7tcmM
PM/MjTzezY485s2OPObMjjzfyIw80MOJPLe8hDyNs387WKx8OyQAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAApHU4FrB8OGXGijzAzo889dKR
PP/SkTz/0pE8/9GRPP/RkDz/0JA8/9CQPP/RkDz/0ZE8/9KRPP/TkTz/0pE8/86PPPbGijzCt4E8bKp6
OxoAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAKN1OB+9hTuLzI486NOR
PP/SkTz/0ZA8/9CQPP/QkDz/0JA8/9CQPP/QkDz/0JA8/9CQPP/QkDz/0JA8/9CQPP/QkDz/0JA8/9GQ
PP/SkTz/0pE8/82OPOu9hTuOq3w8IgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACidTkFuoM8csyN
POrTkjz/0ZE8/9CQPP/QkDz/0JA8/9CQPP/QkDz/0JA8/9CQPP/QkDz/0JA8/9CQPP/QkDz/0JA8/9CQ
PP/QkDz/0JA8/9CQPP/QkDz/0JA8/9GRPP/Tkjz/zY887bqEPHimeDsHAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAKp6
OynDiDvA05I8/9GRPP/QkDz/0JA8/9CQPP/QkDz/0JA8/9CQPP/QkDz/0JA8/9CQPP/QkDz/0JA8/9CQ
PP/QkDz/0JA8/9CQPP/QkDz/0JA8/9CQPP/QkDz/0JA8/9CQPP/QkDz/0ZA8/9ORPP/GijzFr308LgAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAArXw7UM2OPOvTkTz/0JA8/9CQPP/QkDz/0JA8/9CQPP/QkDz/0JA8/9CQPP/QkDz/0JA8/9CQ
PP/QkDz/0JA8/9CQPP/QkDz/0JA8/9CQPP/QkDz/0JA8/9CQPP/QkDz/0JA8/9CQPP/QkDz/0JA8/9CQ
PP/SkTz/zo887rOAPFYAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAACxfjxm0ZA8/NGRPP/QkDz/0JA8/9CQPP/QkDz/0JA8/9CQPP/QkDz/0JA8/9CQ
PP/QkDz/0JA8/9CQPP/QkDz/0JA8/9CQPP/QkDz/0JA8/9CQPP/QkDz/0JA8/9CQPP/QkDz/0JA8/9CQ
PP/QkDz/0JA8/9CQPP/QkDz/0ZE8/9GQPP64gjxtAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAALaBPGXRkTz/0ZE8/9CQPP/QkDz/0JA8/9CQPP/QkDz/0JA8/9CQ
PP/QkDz/0JA8/9CQPP/QkDz/0JA8/9CQPP/QkDz/0JA8/9CQPP/QkDz/0JA8/9CQPP/QkDz/0JA8/9CQ
PP/QkDz/0JA8/9CQPP/QkDz/0JA8/9CQPP/QkDz/0JA8/9GQPP/SkTz/uIM8bAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAqnk6TtCQPPzRkTz/0JA8/9CQPP/QkDz/0JA8/9CQ
PP/QkDz/0JA8/9CQPP/QkDz/0JA8/9CQPP/QkDz/0JA8/9CQPP/QkDz/0JA8/9CQPP/QkDz/0JA8/9CQ
PP/QkDz/0JA8/9CQPP/QkDz/0JA8/9CQPP/QkDz/0JA8/9CQPP/QkDz/0JA8/9CQPP/RkDz/0ZA8/rSA
PFUAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACtfDwmzo887dKRPP/QkDz/0JA8/9CQ
PP/QkDz/0JA8/9CQPP/QkDz/0JA8/9CQPP/QkDz/0JA8/9CQPP/QkDz/0JA8/9CQPP/QkDz/0JA8/9CQ
PP/QkDz/0JA8/9CQPP/QkDz/0JA8/9CQPP/QkDz/0JA8/9CQPP/QkDz/0JA8/9CQPP/QkDz/0JA8/9CQ
PP/QkDz/0ZE8/86PPPGtfDwrAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAKZ4PAXFijzC0pE8/9CQ
PP/QkDz/0JA8/9CQPP/QkDz/0JA8/9CURf/TpGT/2baJ/9/GpP/l0bf/59W//+fVvf/kz7P/3sOg/9mz
hP/ToWH/0JND/9CQPP/QkDz/0JA8/9CQPP/QkDz/0JA8/9CQPP/QkDz/0JA8/9CQPP/QkDz/0JA8/9CQ
PP/QkDz/0JA8/9CQPP/QkDz/0JA8/9KRPP/EiTvJo3Y7CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAALiC
PG/Tkjz/0JA8/9CQPP/QkDz/0JA8/9CSQf/Vq3P/5tO7//j07v//////////////////////////////
////////////////////////9vHq/+TQtf/UqG7/0JA+/9CQPP/QkDz/0JA8/9CQPP/QkDz/0JA8/9CQ
PP/QkDz/0JA8/9CQPP/QkDz/0JA8/9CQPP/QkDz/0JA8/9CQPP/Tkjz/uYM8dgAAAAAAAAAAAAAAAAAA
AAAAAAAArXw8Gc2OPOzRkTz/0JA8/9CQPP/QlEX/27qP//fz7P//////////////////////////////
////////////////////////////////////////////////////////8ObZ/9auev/QkDz/0JA8/9CQ
PP/QkDz/0JA8/9CQPP/QkDz/0JA8/9CQPP/QkDz/0JA8/9CQPP/QkDz/0JA8/9CQPP/RkTz/zI488J1x
OB8AAAAAAAAAAAAAAAAAAAAAuoM7h9OSPP/QkDz/0JA8/9GXTf/TpGb/27uS/9u6kP/ewZz/59W9//Xv
5///////////////////////////////////////////////////////////////////////////////
///r3cr/0ZxV/9CQPP/QkDz/0JA8/9CQPP/QkDz/0JA8/9CQPP/QkDz/0JA8/9CQPP/QkDz/0JA8/9CQ
PP/QkDz/1JI8/7mDO5AAAAAAAAAAAAAAAADFj0cR0pNB6s+PO//Ojjv/0JA8/9CQPP/QkDz/0JA8/9CQ
PP/QkDz/0JA8/9CRQP/TpGf/5NC2//38+v//////////////////////////////////////////////
////////////////////////+vf0/9auev/QkDz/0JA8/9CQPP/QkDz/0JA8/9CQPP/QkDz/0JA8/9CQ
PP/QkDz/0JA8/9CQPP/QkDz/0ZE8/8uOPO6SajYVAAAAAAAAAADzr1df7qxV/+WkT//ZmUT/0JA9/86O
O//Pjzv/0JA8/9CQPP/QkDz/0JA8/9CQPP/QkDz/0JA8/9GaUv/l07r/////////////////////////
///////////////////////////////////////////////////buo//0JA8/9CQPP/QkDz/0JA8/9CQ
PP/QkDz/0JA8/9CQPP/QkDz/0JA8/9CQPP/QkDz/0JA8/9OSPP+ldjdoAAAAAAAAAADurFW67qxV//Ct
Vv/vrVb/6adR/92dSP/Skz//zo47/8+PO//QkDz/0JA8/9CQPP/QkDz/0JJB/9Smaf/dv5j/+fXw////
////////////////////////////////////////////////////////////////////////2riM/9CQ
PP/QkDz/0JA8/9CQPP/QkDz/0JA8/9CQPP/QkDz/0JA8/9CQPP/QkDz/0JA8/9KRPP/FiTzGoHQ6Ae6s
VRrurFXz7qxV/+6sVf/urFX/761W//CuVv/sqlT/4qFM/9aVQv/Pjzv/zo47/9CQPP/VqnH/8+vh////
////////////////////////////////////////////////////////////////////////////////
/////////////9aueP/QkDz/0JA8/9CQPP/QkDz/0JA8/9CQPP/QkDz/0JA8/9CQPP/QkDz/0JA8/9GQ
PP/Ojzz4oHM5Iu6sVU3urFX/7qxV/+6sVf/urFX/7qxV/+6sVf/vrVX/8K5W/+6sVf/mpU//2plF/9q6
j///////////////////////////////////////////////////////////////////////////////
//////////////////////////////n18P/Rm1P/0JA8/9CQPP/QkDz/0JA8/9CQPP/QkDz/0JA8/9CQ
PP/QkDz/0JA8/9CQPP/SkTz/rXs6Vu6sVYPurFX/7qxV/+6sVf/urFX/7qxV/+6sVf/urFX/7qxV/+6s
Vf/wrVb/6r2B////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////o18L/0JA8/9CQPP/QkDz/0JA8/9CQ
PP/QkDz/0JA8/9CQPP/QkDz/0JA8/9CQPP/SkTz/v4Y8j+6sVa3urFX/7qxV/+6sVf/urFX/7qxV/+6s
Vf/urFX/7qxV/+6sVf/urFb/9Onb///////+/v3/////////////////////////////////////////
////////////////////////////////////////////////////////////////////////1qx2/9CQ
PP/QkDz/0JA8/9CQPP/QkDz/0JA8/9CQPP/QkDz/0JA8/9CQPP/SkTz/wYc7uO6sVcrurFX/7qxV/+6s
Vf/urFX/7qxV/+6sVf/urFX/7qxV/+6sVf/trlr/67Zy/+m+h//y5NP/////////////////////////
////////////////////////////////////////////////////////////////////////////////
////////7+TW/9CQPf/QkDz/0JA8/9CQPP/QkDz/0JA8/9CQPP/QkDz/0JA8/9CQPP/RkTz/yYw80e6s
VdvurFX/7qxV/+6sVf/urFX/7qxV/+6sVf/urFX/7qxV/+6sVf/urFX/6sme//v49P//////////////
////////////////////////////////////////////////////////////////////////////////
/////////////////////////////9arc//QkDz/0JA8/9CQPP/QkDz/0JA8/9CQPP/QkDz/0JA8/9CQ
PP/RkDz/zI083+6sVeLurFX/7qxV/+6sVf/urFX/7qxV/+6sVf/urFX/7qxV/+6sVf/u2b3/////////
////////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////+fVvv/QkDz/0JA8/9CQPP/QkDz/0JA8/9CQ
PP/QkDz/0JA8/9CQPP/QkDz/zo885u6sVeLurFX/7qxV/+6sVf/urFX/7qxV/+6sVf/urFX/7qxV/+vL
of//////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////r28v/Rl0r/0JA8/9CQ
PP/QkDz/0JA8/9CQPP/QkDz/0JA8/9CQPP/QkDz/zo885u6sVdrurFX/7qxV/+6sVf/urFX/7qxV/+6s
Vf/urFX/7LBj//r28f//////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
///Vq3P/0JA8/9CQPP/QkDz/0JA8/9CQPP/QkDz/0JA8/9CQPP/RkDz/zI083+6sVcrurFX/7qxV/+6s
Vf/urFX/7qxV/+6sVf/urFX/6cKO////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
///////////////////ewp7/0JA8/9CQPP/QkDz/0JA8/9CQPP/QkDz/0JA8/9CQPP/RkTz/yYw80O6s
VazurFX/7qxV/+6sVf/urFX/7qxV/+6sVf/urFX/7NOy//z59v/u2b7/+fPr////////////////////
////////////////////////////////////////////////////////////////////////////////
///////////////////////////////////n1sD/0JA8/9CQPP/QkDz/0JA8/9CQPP/QkDz/0JA8/9CQ
PP/SkTz/xIo8uO6sVYHurFX/7qxV/+6sVf/urFX/7qxV/+6sVf/urFX/67Zx/+2uWf/qy6H/////////
////////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////v5dj/0JA8/9CQPP/QkDz/0JA8/9CQ
PP/QkDz/0JA8/9CQPP/SkTz/vYU8je6sVUvurFX/7qxV/+6sVf/urFX/7qxV/+6sVf/urFX/7qxV/+nC
kP///////////////////////////////////////////////////////fz6//fu5P/w4Mv/793F//7+
/v/////////////////////////////////////////////////////////////////17eT/0JA//86O
Ov/Pjzv/0JA8/9CQPP/QkDz/0JA8/9CQPP/SkTz/tYA8Vu6sVRnurFXy7qxV/+6sVf/urFX/7qxV/+6s
Vf/urFX/7a5b//fw5///////////////////////////////////////+/jz/+7av//pwIr/67Jn/+6t
Vv/urFX/6rd1////////////////////////////////////////////////////////////////////
///48ej/6KhU/92cR//Tkj7/zo47/8+PO//QkDz/0JA8/9GQPP/Pjzz3rXw8IAAAAADurFW37qxV/+6s
Vf/urFX/7qxV/+6sVf/urFX/6b2D//////////////////////////////////nz6//qyZ3/7K9h/+6s
Vf/urFX/7qxV/+6sVf/urFX/6rl6////////////////////////////////////////////////////
///////////////////9/Pr/6r6C//CuV//sqlT/4aBL/9aWQv/Pjzv/zo47/9GRPP/GijzCp3g8AQAA
AADurFVb7qxV/+6sVf/urFX/7qxV/+6sVf/urFX/68yk///////////////////////+/fz/68+q/+2v
XP/urFX/7qxV/+6sVf/urFX/7qxV/+6sVf/urFX/6rNr//7+/f//////////////////////////////
/////////////////////////////////////////////+nEk//vrVX/8K5W/+6sVf/lpE//2ZlF/9KR
Pf+zfzpoAAAAAAAAAADurFUP7qxV5u6sVf/urFX/7qxV/+6sVf/urFX/7NGu//////////////////fu
5P/quHb/7qxV/+6sVf/urFX/7qxV/+6sVf/urFX/7qxV/+6sVf/urFX/7qxW//Xr3///////////////
///////////////////////////////////////////////////7+PP/+vXu///////pxJL/7qxV/+6s
Vf/wrVb/8K1W/+mnUevUmUsUAAAAAAAAAAAAAAAA7qxVgO6sVf/urFX/7qxV/+6sVf/urFX/6sqg////
////////8eLO/+yvX//urFX/7qxV/+6sVf/urFX/7qxV/+6sVf/urFX/7qxV/+6sVf/urFX/7qxV/+nF
lf/////////////////////////////////////////////////////////////////8+vf/6cWV/+q5
ev/s07H/6rd1/+6sVf/urFX/7qxV/++tVogAAAAAAAAAAAAAAAAAAAAA7qxVFe6sVejurFX/7qxV/+6s
Vf/urFX/6bp8///////w4Mn/7a1Z/+6sVf/urFX/7qxV/+6sVf/urFX/7qxV/+6sVf/urFX/7qxV/+6s
Vf/urFX/7qxV/+6sVf/x4cz////////////////////////////////////////////////////+//7+
/v/////////+/+m8gP/urFX/7a1Y/+6sVf/urFX/7qxV7O6sVRoAAAAAAAAAAAAAAAAAAAAAAAAAAO6s
VWburFX/7qxV/+6sVf/urFX/7a5b/+zTs//sr1//7qxV/+6sVf/urFX/7qxV/+6sVf/urFX/7qxV/+6s
Vf/urFX/7qxV/+6sVf/urFX/7qxV/+6sVf/sr1//8uPQ////////////////////////////////////
////////6suj/+qzav/pxpj/9Onb//n07f/rr2D/7qxV/+6sVf/urFX/7qxVbwAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAO6sVQPurFW67qxV/+6sVf/urFX/7qxV/+6sVv/urFX/7qxV/+6sVf/urFX/7qxV/+6s
Vf/urFX/7qxV/+6sVf/urFX/7qxV/+6sVf/urFX/7qxV/+6sVf/urFX/7axY/+nGl//27uP/////////
/////////fz6//Lj0P/qunv/7qxV/+6sVf/urFX/7qxV/+m9gv/qt3X/7qxV/+6sVf/urFXB7qxVBQAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADurFUg7qxV6O6sVf/urFX/7qxV/+6sVf/urFX/7qxV/+6s
Vf/urFX/7qxV/+6sVf/urFX/7qxV/+6sVf/urFX/7qxV/+6sVf/urFX/7qxV/+6sVf/urFX/7qxV/+6s
Vf/qtnP/6sqg/+3WuP/s07P/6cSS/+uyZf/urFX/7qxV/+6sVf/urFX/7qxV/+6sVv/trVr/7qxV/+6s
VezurFUlAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA7qxVRu6sVfjurFX/7qxV/+6s
Vf/urFX/7qxV/+6sVf/urFX/7qxV/+6sVf/urFX/7qxV/+6sVf/urFX/7qxV/+6sVf/urFX/7qxV/+6s
Vf/urFX/7qxV/+6sVf/urFX/7qxV/+6sVf/urFX/7qxV/+6sVf/urFX/7qxV/+6sVf/urFX/7qxV/+6s
Vf/urFX/7qxV++6sVUwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAO6s
VVzurFX97qxV/+6sVf/urFX/7qxV/+6sVf/urFX/7qxV/+6sVf/urFX/7qxV/+6sVf/urFX/7qxV/+6s
Vf/urFX/7qxV/+6sVf/urFX/7qxV/+6sVf/urFX/7qxV/+6sVf/urFX/7qxV/+6sVf/urFX/7qxV/+6s
Vf/urFX/7qxV/+6sVf/urFX/7qxVYwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAADurFVd7qxV+O6sVf/urFX/7qxV/+6sVf/urFX/7qxV/+6sVf/urFX/7qxV/+6s
Vf/urFX/7qxV/+6sVf/urFX/7qxV/+6sVf/urFX/7qxV/+6sVf/urFX/7qxV/+6sVf/urFX/7qxV/+6s
Vf/urFX/7qxV/+6sVf/urFX/7qxV/+6sVfvurFVjAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA7qxVR+6sVeXurFX/7qxV/+6sVf/urFX/7qxV/+6s
Vf/urFX/7qxV/+6sVf/urFX/7qxV/+6sVf/urFX/7qxV/+6sVf/urFX/7qxV/+6sVf/urFX/7qxV/+6s
Vf/urFX/7qxV/+6sVf/urFX/7qxV/+6sVf/urFX/7qxV6O6sVU0AAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAO6sVSPurFW37qxV/+6s
Vf/urFX/7qxV/+6sVf/urFX/7qxV/+6sVf/urFX/7qxV/+6sVf/urFX/7qxV/+6sVf/urFX/7qxV/+6s
Vf/urFX/7qxV/+6sVf/urFX/7qxV/+6sVf/urFX/7qxV/+6sVf/urFW77qxVJgAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AADurFUB7qxVae6sVeTurFX/7qxV/+6sVf/urFX/7qxV/+6sVf/urFX/7qxV/+6sVf/urFX/7qxV/+6s
Vf/urFX/7qxV/+6sVf/urFX/7qxV/+6sVf/urFX/7qxV/+6sVf/urFX/7qxV5+6sVW3urFUDAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAO6sVRjurFWA7qxV4u6sVf/urFX/7qxV/+6sVf/urFX/7qxV/+6s
Vf/urFX/7qxV/+6sVf/urFX/7qxV/+6sVf/urFX/7qxV/+6sVf/urFX/7qxV/+6sVeTurFWE7qxVGwAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA7qxVEu6sVV7urFW17qxV7+6s
Vf/urFX/7qxV/+6sVf/urFX/7qxV/+6sVf/urFX/7qxV/+6sVf/urFX/7qxV/+6sVfDurFW47qxVX+6s
VRMAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAA7qxVG+6sVUzurFWA7qxVrO6sVcnurFXa7qxV4u6sVeLurFXa7qxVye6sVa3urFWC7qxVTe6s
VR0AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAP//gAH//6gr//wAAD//qCv/8AAAD/+oK//AAAAD/6gr/4AAAAH/qCv/AAAAAP+oK/4A
AAAAf6gr/AAAAAA/qCv4AAAAAB+oK/AAAAAAD6gr4AAAAAAHqCvgAAAAAAeoK8AAAAAAA6grwAAAAAAD
qCuAAAAAAAGoK4AAAAAAAagrgAAAAAAAqCsAAAAAAACoKwAAAAAAAKgrAAAAAAAAqCsAAAAAAACoKwAA
AAAAAKgrAAAAAAAAqCsAAAAAAACoKwAAAAAAAKgrAAAAAAAAqCsAAAAAAACoKwAAAAAAAKgrAAAAAAAA
qCsAAAAAAACoKwAAAAAAAKgrgAAAAAAAqCuAAAAAAAGoK4AAAAAAAagrwAAAAAADqCvAAAAAAAOoK+AA
AAAAB6gr4AAAAAAHqCvwAAAAAA+oK/gAAAAAH6gr/AAAAAA/qCv+AAAAAH+oK/8AAAAA/6gr/4AAAAH/
qCv/wAAAA/+oK//wAAAP/6gr//wAAD//qCv//4AB//+oKygAAAAgAAAAQAAAAAEAIAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAApHY4FrR/
Ole+hjuVxos7w8uNPNvOjzznzo8858uNPNzGijzEvoU7l7WBO1mpejsYAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAqHg5Kr6F
O5XLjTvo0pE8/9ORPP/SkTz/0ZE8/9CQPP/QkDz/0ZE8/9KRPP/TkTz/0pE8/82OPOq/hjyZrXw7LAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAo3U6CbuE
O4bPjzz005I8/9GRPP/QkDz/0JA8/9CQPP/QkDz/0JA8/9CQPP/QkDz/0JA8/9CQPP/QkDz/0ZE8/9OS
PP/PkDz1vYU8iah6PAsAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAKR3
OibGizvG05E8/9GQPP/QkDz/0JA8/9CQPP/QkDz/0JA8/9CQPP/QkDz/0JA8/9CQPP/QkDz/0JA8/9CQ
PP/QkDz/0JA8/9GQPP/TkTz/yIs8yqx8PCkAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AACsezsxy40849KRPP/QkDz/0JA8/9CQPP/QkDz/0JA8/9CQPP/QkDz/0JA8/9CQPP/QkDz/0JA8/9CQ
PP/QkDz/0JA8/9CQPP/QkDz/0JA8/9CQPP/SkTz/zI485rKAPTUAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAApXc6JMuNPOTSkTz/0JA8/9CQPP/QkDz/0JA8/9CQPP/QkDz/0JA8/9CQPP/QkDz/0JA8/9CQ
PP/QkDz/0JA8/9CQPP/QkDz/0JA8/9CQPP/QkDz/0JA8/9CQPP/SkTz/zI485659PCcAAAAAAAAAAAAA
AAAAAAAAAAAAAKd4OwnHizzJ0pE8/9CQPP/QkDz/0JA9/9OgYP/YtIX/38Sh/+LMr//iy67/3sOf/9iy
gv/Tn13/0JA8/9CQPP/QkDz/0JA8/9CQPP/QkDz/0JA8/9CQPP/QkDz/0JA8/9CQPP/SkTz/x4s8zaV4
OwsAAAAAAAAAAAAAAAAAAAAAu4Q8hNOSPP/QkDz/0JA8/9GXS//YtIX/6NfC//Xv5//8+vj/////////
///8+vf/9O3k/+fVvv/YsYH/0JRF/9CQPP/QkDz/0JA8/9CQPP/QkDz/0JA8/9CQPP/QkDz/0JA8/9CQ
PP/Tkjz/u4Q7iQAAAAAAAAAAAAAAAKx7OyTPjzz10ZA8/9GXS//Ztoj/8une////////////////////
///////////////////////////////////38uz/3L2V/9CRP//QkDz/0JA8/9CQPP/QkDz/0JA8/9CQ
PP/QkDz/0JA8/9GRPP/Ojzz3onU5KQAAAAAAAAAAxo1BlNGQO//Ojjv/0JNC/9GWSP/QlET/0ZpR/9au
eP/n1b3//v79////////////////////////////////////////////7+TV/9GdWP/QkDz/0JA8/9CQ
PP/QkDz/0JA8/9CQPP/QkDz/0JA8/9SSPP+4gjqaAAAAAPGuVhHvrVXq5qRO/9qZRP/QkT3/zo46/8+P
O//QkDz/0JA8/9CQPP/To2P/8+vh////////////////////////////////////////////+fXw/9Oh
Yf/QkDz/0JA8/9CQPP/QkDz/0JA8/9CQPP/QkDz/0pE8/8qMO+2WbTYV7qxVUe6sVf/wrVb/761W/+mo
Uv/enUj/05M//86PO//PkD7/3cCZ//Lp3v/7+PT/////////////////////////////////////////
////////+PTv/9GcVf/QkDz/0JA8/9CQPP/QkDz/0JA8/9CQPP/QkDz/05I8/699OljurFWR7qxV/+6s
Vf/urFX/761W//CuV//sqlT/4qJQ/+zdyf//////////////////////////////////////////////
////////////////////////7+TV/9CRP//QkDz/0JA8/9CQPP/QkDz/0JA8/9CQPP/Tkjz/vIQ7mO6s
Vb/urFX/7qxV/+6sVf/urFX/7qxV/++tVf/ry5///v79//7+/f//////////////////////////////
////////////////////////////////////////2rqO/9CQPP/QkDz/0JA8/9CQPP/QkDz/0JA8/9KR
PP/GijvF7qxV2u6sVf/urFX/7qxV/+6sVf/urFX/7qxV/+u1bv/t1bb//fv4////////////////////
///////////////////////////////////////////////////48+3/0ZRG/9CQPP/QkDz/0JA8/9CQ
PP/QkDz/0ZA8/8uNPNzurFXl7qxV/+6sVf/urFX/7qxV/+6sVf/rsWP/9OjZ////////////////////
///////////////////////////////////////////////////////////////////YtIX/0JA8/9CQ
PP/QkDz/0JA8/9CQPP/QkDz/zo886O6sVeXurFX/7qxV/+6sVf/urFX/7qxW//Hiz///////////////
/////////////////////////////////////////////////////////////////////////////+rb
yP/QkDz/0JA8/9CQPP/QkDz/0JA8/9CQPP/Ojzzo7qxV2e6sVf/urFX/7qxV/+6sVf/quHb/////////
////////////////////////////////////////////////////////////////////////////////
////////+fXw/9CURf/QkDz/0JA8/9CQPP/QkDz/0ZA8/8yOPNzurFW/7qxV/+6sVf/urFX/7qxV/+nA
if/s1LT/9Onb////////////////////////////////////////////////////////////////////
////////////////////////0Z5b/9CQPP/QkDz/0JA8/9CQPP/SkTz/x4s8xe6sVY/urFX/7qxV/+6s
Vf/urFX/7qxV/+nEk//+/fz////////////////////////////+/v3/+PHo//To2f/+/v7/////////
///////////////////////////////////VqGz/zo46/8+PO//QkDz/0JA8/9KRPP+/hjyX7qxVUO6s
Vf/urFX/7qxV/+6sVf/ssGH//Pr2///////////////////////y49D/6cOR/+qyaf/urVb/6rJp////
/////////////////////////////////////////////+e7f//goEr/1ZVB/8+PO//Ojzv/0pE8/7WB
PFfurFUQ7qxV6O6sVf/urFX/7qxV/+m+hv/////////////////z5tX/6rl6/+6sVf/urFX/7qxV/+6s
Vf/qs2r////+////////////////////////////////////////////+PLp/+y4c//urFX/5aRO/9qZ
RP/Mjjztp3g6FQAAAADurFWQ7qxV/+6sVf/urFX/6cKP////////////682m/+6sVf/urFX/7qxV/+6s
Vf/urFX/7qxV/+2sV//17N////////////////////////////////////////7+/v/06Nn/8uTT/+qz
a//wrVb/761W/+alUZYAAAAAAAAAAO6sVSHurFX07qxV/+6sVf/quXj//////+nDkf/urFX/7qxV/+6s
Vf/urFX/7qxV/+6sVf/urFX/7qxV/+m+hP////////////////////////////////////////////jy
6v/qtnH/67Fj/+6sVf/urFX2761WJQAAAAAAAAAAAAAAAO6sVX7urFX/7qxV/+2vW//pvID/7qxV/+6s
Vf/urFX/7qxV/+6sVf/urFX/7qxV/+6sVf/urFX/7qxV/+nEkv/7+PT//////////////////fz6/+rJ
n//rtW7/682n/+zTs//urFb/7qxV/+6sVYQAAAAAAAAAAAAAAAAAAAAA7qxVB+6sVcTurFX/7qxV/+6s
Vf/urFX/7qxV/+6sVf/urFX/7qxV/+6sVf/urFX/7qxV/+6sVf/urFX/7qxV/+u0bP/qy6H/7da4/+vN
pv/qtnP/7qxV/+6sVf/urFX/7K9f/+2sWP/urFXI7qxVCQAAAAAAAAAAAAAAAAAAAAAAAAAA7qxVIO6s
VeDurFX/7qxV/+6sVf/urFX/7qxV/+6sVf/urFX/7qxV/+6sVf/urFX/7qxV/+6sVf/urFX/7qxV/+6s
Vf/urFX/7qxV/+6sVf/urFX/7qxV/+6sVf/urFX/7qxV4+6sVSMAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAA7qxVLO6sVd/urFX/7qxV/+6sVf/urFX/7qxV/+6sVf/urFX/7qxV/+6sVf/urFX/7qxV/+6s
Vf/urFX/7qxV/+6sVf/urFX/7qxV/+6sVf/urFX/7qxV/+6sVeLurFUwAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAA7qxVIu6sVcHurFX/7qxV/+6sVf/urFX/7qxV/+6sVf/urFX/7qxV/+6s
Vf/urFX/7qxV/+6sVf/urFX/7qxV/+6sVf/urFX/7qxV/+6sVf/urFXE7qxVJAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA7qxVBu6sVX/urFXw7qxV/+6sVf/urFX/7qxV/+6s
Vf/urFX/7qxV/+6sVf/urFX/7qxV/+6sVf/urFX/7qxV/+6sVf/urFXy7qxVgu6sVQgAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAO6sVSXurFWP7qxV5e6s
Vf/urFX/7qxV/+6sVf/urFX/7qxV/+6sVf/urFX/7qxV/+6sVf/urFXl7qxVke6sVScAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AADurFUS7qxVUO6sVY7urFW97qxV2O6sVeXurFXl7qxV2O6sVb7urFWP7qxVUu6sVRMAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA/8AD//8AAP/8AAA/+AAAH/AAAA/gAAAHwAAAA8AA
AAOAAAABgAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIAA
AAGAAAABwAAAA8AAAAPgAAAH8AAAD/gAAB/8AAA//wAA///AA/8oAAAAEAAAACAAAAABACAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAKx7Oja9hTqTyYw8zs6PPOfOjzznyYw8zr6G
PJSvfjw3AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAo3Y7CbyEO5PRkDz805I8/9GRPP/QkDz/0JA8/9GR
PP/TkTz/0ZA8/b+GPJWrfDwKAAAAAAAAAAAAAAAAp3g8CcSJPLfTkjz/0ZA8/9CQPP/QkDz/0JA8/9CQ
PP/QkDz/0JA8/9CQPP/Tkjz/xoo8uqx8PQoAAAAAAAAAAL2FPJPUk0D/06Rm/92/mf/izK//4sut/9u6
j//Snlr/0JA8/9CQPP/QkDz/0JA8/9OSPP+9hTyWAAAAALiEQDLQkDz90JpS/93Amf/u4tP/////////
/////////fv5/+DIqP/QkkH/0JA8/9CQPP/RkDz/0JA8/qN1OTTtq1WS56VP/9qaRf/RkT3/0JdO/+rc
yP//////////////////////693L/9CSQf/QkDz/0JA8/9SSPP+3gTqW761Vz++tVv/wrVb/6K5h//fy
6v/////////////////////////////////gx6b/0JA8/9CQPP/RkTz/yYw80e6sVefurFX/7qxV/+q+
hP/69vD//////////////////////////////////fz7/9GbU//QkDz/0JA8/8+PPOnurFXn7qxV/+yw
Y//79/P////////////////////////////////////////////ZuIz/0JA8/9CQPP/Pjzzp7qxVz+6s
Vf/sr2H/8eLO/////////////v7+//n07f/+/v7/////////////////48yu/8+PO//Qjzv/yYs80e6s
VZLurFX/67Jm//7+/f/8+fb/68yl/+qza//rsmf//v37//////////////////Pn2P/ip1n/2phC/8CH
PJXurFUw7qxV/eq2c//169//6rNr/+6sVf/urFX/7q1W//Pm1f/////////////////8+fX/67+G/++t
Vf3lpVEyAAAAAO6sVZHtrVr/7a9c/+6sVf/urFX/7qxV/+6sVf/rsWP/7de5//Lj0P/pxJL/67Zy/+qz
av/urFWTAAAAAAAAAADurFUI7qxVtO6sVf/urFX/7qxV/+6sVf/urFX/7qxV/+6sVf/urFX/7qxV/+6s
Vf/urFW37qxVCQAAAAAAAAAAAAAAAO6sVQjurFWQ7qxV++6sVf/urFX/7qxV/+6sVf/urFX/7qxV/+6s
VfvurFWS7qxVCQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAO6sVTPurFWQ7qxVzO6sVeburFXm7qxVzO6s
VZDurFU0AAAAAAAAAAAAAAAAAAAAAPAPrEHAA6xBgAGsQYABrEEAAKxBAACsQQAArEEAAKxBAACsQQAA
rEEAAKxBAACsQYABrEGAAaxBwAOsQfAPrEE=
</value>
</data>
</root>

View File

@@ -1,4 +1,5 @@
using System.Windows.Forms;
using System.Diagnostics;
using System.Windows.Forms;
using TweetDck.Configuration;
namespace TweetDck.Core.Other.Settings{
@@ -12,7 +13,14 @@ namespace TweetDck.Core.Other.Settings{
public bool Ready { get; set; }
public BaseTabSettings(){
Padding = new Padding(6,6,6,6);
Padding = new Padding(6);
}
protected static void PromptRestart(){
if (MessageBox.Show("The application must restart for the setting to take place. Do you want to restart now?", Program.BrandName+" Settings", MessageBoxButtons.YesNo, MessageBoxIcon.Information) == DialogResult.Yes){
Process.Start(Application.ExecutablePath, "-restart");
Application.Exit();
}
}
}
}

View File

@@ -47,6 +47,7 @@
this.textBoxBrowserCSS.Margin = new System.Windows.Forms.Padding(0, 3, 0, 0);
this.textBoxBrowserCSS.Multiline = true;
this.textBoxBrowserCSS.Name = "textBoxBrowserCSS";
this.textBoxBrowserCSS.ScrollBars = System.Windows.Forms.ScrollBars.Both;
this.textBoxBrowserCSS.Size = new System.Drawing.Size(226, 193);
this.textBoxBrowserCSS.TabIndex = 0;
this.textBoxBrowserCSS.WordWrap = false;
@@ -129,7 +130,8 @@
this.textBoxNotificationCSS.Margin = new System.Windows.Forms.Padding(0, 3, 0, 0);
this.textBoxNotificationCSS.Multiline = true;
this.textBoxNotificationCSS.Name = "textBoxNotificationCSS";
this.textBoxNotificationCSS.Size = new System.Drawing.Size(227, 193);
this.textBoxNotificationCSS.ScrollBars = System.Windows.Forms.ScrollBars.Both;
this.textBoxNotificationCSS.Size = new System.Drawing.Size(226, 193);
this.textBoxNotificationCSS.TabIndex = 1;
this.textBoxNotificationCSS.WordWrap = false;
//

View File

@@ -17,7 +17,7 @@ namespace TweetDck.Core.Other.Settings.Dialogs{
Text = Program.BrandName+" Settings - CEF Arguments";
textBoxArgs.Text = Program.UserConfig.CustomCefArgs ?? "";
textBoxArgs.Select(textBoxArgs.Text.Length,0);
textBoxArgs.Select(textBoxArgs.Text.Length, 0);
}
private void btnHelp_Click(object sender, EventArgs e){
@@ -33,10 +33,10 @@ namespace TweetDck.Core.Other.Settings.Dialogs{
return;
}
int count = CommandLineArgsParser.AddToDictionary(CefArgs,new Dictionary<string,string>());
int count = CommandLineArgsParser.AddToDictionary(CefArgs, new Dictionary<string, string>());
string prompt = count == 0 && !string.IsNullOrWhiteSpace(prevArgs) ? "All arguments will be removed from the settings. Continue?" : count+(count == 1 ? " argument" : " arguments")+" will be added to the settings. Continue?";
if (MessageBox.Show(prompt,"Confirm CEF Arguments",MessageBoxButtons.OKCancel,MessageBoxIcon.Question,MessageBoxDefaultButton.Button2) == DialogResult.OK){
if (MessageBox.Show(prompt, "Confirm CEF Arguments", MessageBoxButtons.OKCancel, MessageBoxIcon.Question, MessageBoxDefaultButton.Button2) == DialogResult.OK){
DialogResult = DialogResult.OK;
Close();
}

View File

@@ -4,6 +4,8 @@ using System.Text;
namespace TweetDck.Core.Other.Settings.Export{
class CombinedFileStream : IDisposable{
public const char KeySeparator = '/';
private readonly Stream stream;
public CombinedFileStream(Stream stream){
@@ -11,28 +13,31 @@ namespace TweetDck.Core.Other.Settings.Export{
}
public void WriteFile(string identifier, string path){
byte[] name = Encoding.UTF8.GetBytes(identifier);
if (name.Length > 255){
throw new ArgumentOutOfRangeException("Identifier cannot be 256 or more characters long: "+identifier);
}
byte[] contents;
using(FileStream fileStream = new FileStream(path,FileMode.Open,FileAccess.Read,FileShare.ReadWrite)){
using(FileStream fileStream = new FileStream(path, FileMode.Open, FileAccess.Read, FileShare.ReadWrite)){
int index = 0;
int left = (int)fileStream.Length;
contents = new byte[left];
while(left > 0){
int read = fileStream.Read(contents,index,left);
int read = fileStream.Read(contents, index, left);
index += read;
left -= read;
}
}
byte[] name = Encoding.UTF8.GetBytes(identifier);
byte[] contentsLength = BitConverter.GetBytes(contents.Length);
stream.WriteByte((byte)name.Length);
stream.Write(name,0,name.Length);
stream.Write(contentsLength,0,4);
stream.Write(contents,0,contents.Length);
stream.Write(name, 0, name.Length);
stream.Write(BitConverter.GetBytes(contents.Length), 0, 4);
stream.Write(contents, 0, contents.Length);
}
public Entry ReadFile(){
@@ -43,15 +48,15 @@ namespace TweetDck.Core.Other.Settings.Export{
}
byte[] name = new byte[nameLength];
stream.Read(name,0,nameLength);
stream.Read(name, 0, nameLength);
byte[] contentLength = new byte[4];
stream.Read(contentLength,0,4);
stream.Read(contentLength, 0, 4);
byte[] contents = new byte[BitConverter.ToInt32(contentLength,0)];
stream.Read(contents,0,contents.Length);
byte[] contents = new byte[BitConverter.ToInt32(contentLength, 0)];
stream.Read(contents, 0, contents.Length);
return new Entry(Encoding.UTF8.GetString(name),contents);
return new Entry(Encoding.UTF8.GetString(name), contents);
}
public void Flush(){
@@ -65,6 +70,13 @@ namespace TweetDck.Core.Other.Settings.Export{
public class Entry{
public string Identifier { get; private set; }
public string KeyName{
get{
int index = Identifier.IndexOf(KeySeparator);
return index == -1 ? Identifier : Identifier.Substring(0, index);
}
}
private readonly byte[] contents;
public Entry(string identifier, byte[] contents){
@@ -73,7 +85,16 @@ namespace TweetDck.Core.Other.Settings.Export{
}
public void WriteToFile(string path){
File.WriteAllBytes(path,contents);
File.WriteAllBytes(path, contents);
}
public void WriteToFile(string path, bool createDirectory){
if (createDirectory){
// ReSharper disable once AssignNullToNotNullAttribute
Directory.CreateDirectory(Path.GetDirectoryName(path));
}
File.WriteAllBytes(path, contents);
}
}
}

View File

@@ -1,28 +1,63 @@
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Windows.Forms;
using TweetDck.Plugins;
namespace TweetDck.Core.Other.Settings.Export{
sealed class ExportManager{
public static readonly string CookiesPath = Path.Combine(Program.StoragePath,"Cookies");
public static readonly string TempCookiesPath = Path.Combine(Program.StoragePath,"CookiesTmp");
private static readonly string CookiesPath = Path.Combine(Program.StoragePath, "Cookies");
private static readonly string TempCookiesPath = Path.Combine(Program.StoragePath, "CookiesTmp");
public bool IsRestarting { get; private set; }
public Exception LastException { get; private set; }
private readonly string file;
private readonly PluginManager plugins;
public ExportManager(string file){
public ExportManager(string file, PluginManager plugins){
this.file = file;
this.plugins = plugins;
}
public bool Export(bool includeSession){
try{
using(CombinedFileStream stream = new CombinedFileStream(new FileStream(file,FileMode.Create,FileAccess.Write,FileShare.None))){
stream.WriteFile("config",Program.ConfigFilePath);
using(CombinedFileStream stream = new CombinedFileStream(new FileStream(file, FileMode.Create, FileAccess.Write, FileShare.None))){
stream.WriteFile("config", Program.ConfigFilePath);
foreach(PathInfo path in EnumerateFilesRelative(plugins.PathOfficialPlugins)){
string[] split = path.Relative.Split(CombinedFileStream.KeySeparator);
if (split.Length < 3){
continue;
}
else if (split.Length == 3){
if (split[2].Equals(".meta", StringComparison.OrdinalIgnoreCase) ||
split[2].Equals("browser.js", StringComparison.OrdinalIgnoreCase) ||
split[2].Equals("notification.js", StringComparison.OrdinalIgnoreCase)){
continue;
}
}
try{
stream.WriteFile("plugin.off"+path.Relative, path.Full);
}catch(ArgumentOutOfRangeException e){
MessageBox.Show("Could not include a file in the export. "+e.Message, "Export Profile", MessageBoxButtons.OK, MessageBoxIcon.Warning);
}
}
foreach(PathInfo path in EnumerateFilesRelative(plugins.PathCustomPlugins)){
try{
stream.WriteFile("plugin.usr"+path.Relative, path.Full);
}catch(ArgumentOutOfRangeException e){
MessageBox.Show("Could not include a file in the export. "+e.Message, "Export Profile", MessageBoxButtons.OK, MessageBoxIcon.Warning);
}
}
if (includeSession){
stream.WriteFile("cookies",CookiesPath);
stream.WriteFile("cookies", CookiesPath);
}
stream.Flush();
@@ -37,22 +72,40 @@ namespace TweetDck.Core.Other.Settings.Export{
public bool Import(){
try{
using(CombinedFileStream stream = new CombinedFileStream(new FileStream(file,FileMode.Open,FileAccess.Read,FileShare.None))){
bool updatedPlugins = false;
using(CombinedFileStream stream = new CombinedFileStream(new FileStream(file, FileMode.Open, FileAccess.Read, FileShare.None))){
CombinedFileStream.Entry entry;
while((entry = stream.ReadFile()) != null){
switch(entry.Identifier){
switch(entry.KeyName){
case "config":
entry.WriteToFile(Program.ConfigFilePath);
Program.ReloadConfig();
break;
case "plugin.off":
string root = Path.Combine(plugins.PathOfficialPlugins, entry.Identifier.Split(CombinedFileStream.KeySeparator)[1]);
if (Directory.Exists(root)){
entry.WriteToFile(Path.Combine(plugins.PathOfficialPlugins, entry.Identifier.Substring(entry.KeyName.Length+1)), true);
updatedPlugins = true;
}
break;
case "plugin.usr":
entry.WriteToFile(Path.Combine(plugins.PathCustomPlugins, entry.Identifier.Substring(entry.KeyName.Length+1)), true);
updatedPlugins = true;
break;
case "cookies":
if (MessageBox.Show("Do you want to import the login session? This will restart "+Program.BrandName+".","Importing "+Program.BrandName+" Settings",MessageBoxButtons.YesNo,MessageBoxIcon.Question,MessageBoxDefaultButton.Button2) == DialogResult.Yes){
entry.WriteToFile(Path.Combine(Program.StoragePath,TempCookiesPath));
if (MessageBox.Show("Do you want to import the login session? This will restart "+Program.BrandName+".", "Importing "+Program.BrandName+" Settings", MessageBoxButtons.YesNo, MessageBoxIcon.Question, MessageBoxDefaultButton.Button2) == DialogResult.Yes){
entry.WriteToFile(Path.Combine(Program.StoragePath, TempCookiesPath));
// okay to and restart, 'cookies' is always the last entry
Process.Start(Application.ExecutablePath,"-restart -importcookies");
IsRestarting = true;
Process.Start(Application.ExecutablePath, "-restart -importcookies");
Application.Exit();
}
@@ -61,11 +114,41 @@ namespace TweetDck.Core.Other.Settings.Export{
}
}
if (updatedPlugins){
plugins.Reload();
}
return true;
}catch(Exception e){
LastException = e;
return false;
}
}
public static void ImportCookies(){
if (File.Exists(TempCookiesPath)){
try{
if (File.Exists(CookiesPath)){
File.Delete(CookiesPath);
}
File.Move(TempCookiesPath, CookiesPath);
}catch(Exception e){
Program.Reporter.HandleException("Profile Import Error", "Could not import the cookie file to restore login session.", true, e);
}
}
}
private static IEnumerable<PathInfo> EnumerateFilesRelative(string root){
return Directory.EnumerateFiles(root, "*.*", SearchOption.AllDirectories).Select(fullPath => new PathInfo{
Full = fullPath,
Relative = fullPath.Substring(root.Length).Replace(Path.DirectorySeparatorChar, CombinedFileStream.KeySeparator) // includes leading separator character
});
}
private class PathInfo{
public string Full { get; set; }
public string Relative { get; set; }
}
}
}

View File

@@ -28,12 +28,12 @@
this.checkHardwareAcceleration = new System.Windows.Forms.CheckBox();
this.toolTip = new System.Windows.Forms.ToolTip(this.components);
this.btnEditCefArgs = new System.Windows.Forms.Button();
this.btnEditCSS = new System.Windows.Forms.Button();
this.btnReset = new System.Windows.Forms.Button();
this.btnImport = new System.Windows.Forms.Button();
this.btnExport = new System.Windows.Forms.Button();
this.groupPerformance = new System.Windows.Forms.GroupBox();
this.groupConfiguration = new System.Windows.Forms.GroupBox();
this.btnEditCSS = new System.Windows.Forms.Button();
this.groupPerformance.SuspendLayout();
this.groupConfiguration.SuspendLayout();
this.SuspendLayout();
@@ -75,11 +75,22 @@
this.btnEditCefArgs.UseVisualStyleBackColor = true;
this.btnEditCefArgs.Click += new System.EventHandler(this.btnEditCefArgs_Click);
//
// btnEditCSS
//
this.btnEditCSS.Location = new System.Drawing.Point(6, 48);
this.btnEditCSS.Name = "btnEditCSS";
this.btnEditCSS.Size = new System.Drawing.Size(171, 23);
this.btnEditCSS.TabIndex = 16;
this.btnEditCSS.Text = "Edit CSS";
this.toolTip.SetToolTip(this.btnEditCSS, "Set custom CSS for browser and notification windows.");
this.btnEditCSS.UseVisualStyleBackColor = true;
this.btnEditCSS.Click += new System.EventHandler(this.btnEditCSS_Click);
//
// btnReset
//
this.btnReset.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left)));
this.btnReset.AutoSize = true;
this.btnReset.Location = new System.Drawing.Point(209, 250);
this.btnReset.Location = new System.Drawing.Point(190, 250);
this.btnReset.Name = "btnReset";
this.btnReset.Padding = new System.Windows.Forms.Padding(3, 0, 3, 0);
this.btnReset.Size = new System.Drawing.Size(102, 23);
@@ -92,12 +103,12 @@
//
this.btnImport.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left)));
this.btnImport.AutoSize = true;
this.btnImport.Location = new System.Drawing.Point(109, 250);
this.btnImport.Location = new System.Drawing.Point(100, 250);
this.btnImport.Name = "btnImport";
this.btnImport.Padding = new System.Windows.Forms.Padding(3, 0, 3, 0);
this.btnImport.Size = new System.Drawing.Size(94, 23);
this.btnImport.Size = new System.Drawing.Size(84, 23);
this.btnImport.TabIndex = 16;
this.btnImport.Text = "Import Settings";
this.btnImport.Text = "Import Profile";
this.btnImport.UseVisualStyleBackColor = true;
this.btnImport.Click += new System.EventHandler(this.btnImport_Click);
//
@@ -105,12 +116,13 @@
//
this.btnExport.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left)));
this.btnExport.AutoSize = true;
this.btnExport.AutoSizeMode = System.Windows.Forms.AutoSizeMode.GrowAndShrink;
this.btnExport.Location = new System.Drawing.Point(9, 250);
this.btnExport.Name = "btnExport";
this.btnExport.Padding = new System.Windows.Forms.Padding(3, 0, 3, 0);
this.btnExport.Size = new System.Drawing.Size(94, 23);
this.btnExport.Size = new System.Drawing.Size(85, 23);
this.btnExport.TabIndex = 15;
this.btnExport.Text = "Export Settings";
this.btnExport.Text = "Export Profile";
this.btnExport.UseVisualStyleBackColor = true;
this.btnExport.Click += new System.EventHandler(this.btnExport_Click);
//
@@ -136,17 +148,6 @@
this.groupConfiguration.TabStop = false;
this.groupConfiguration.Text = "Configuration";
//
// btnEditCSS
//
this.btnEditCSS.Location = new System.Drawing.Point(6, 48);
this.btnEditCSS.Name = "btnEditCSS";
this.btnEditCSS.Size = new System.Drawing.Size(171, 23);
this.btnEditCSS.TabIndex = 16;
this.btnEditCSS.Text = "Edit CSS";
this.toolTip.SetToolTip(this.btnEditCSS, "Set custom CSS for browser and notification windows.");
this.btnEditCSS.UseVisualStyleBackColor = true;
this.btnEditCSS.Click += new System.EventHandler(this.btnEditCSS_Click);
//
// TabSettingsAdvanced
//
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);

View File

@@ -1,19 +1,21 @@
using System;
using System.Diagnostics;
using System.Windows.Forms;
using TweetDck.Core.Controls;
using TweetDck.Core.Other.Settings.Dialogs;
using TweetDck.Core.Other.Settings.Export;
using TweetDck.Core.Utils;
using TweetDck.Plugins;
namespace TweetDck.Core.Other.Settings{
partial class TabSettingsAdvanced : BaseTabSettings{
private readonly Action browserReloadAction;
private readonly PluginManager plugins;
public TabSettingsAdvanced(Action browserReloadAction){
public TabSettingsAdvanced(Action browserReloadAction, PluginManager plugins){
InitializeComponent();
this.browserReloadAction = browserReloadAction;
this.plugins = plugins;
checkHardwareAcceleration.Checked = HardwareAcceleration.IsEnabled;
@@ -33,7 +35,7 @@ namespace TweetDck.Core.Other.Settings{
btnClearCache.Enabled = false;
BrowserCache.SetClearOnExit();
MessageBox.Show("Cache will be automatically cleared when "+Program.BrandName+" exits.","Clear Cache",MessageBoxButtons.OK,MessageBoxIcon.Information);
MessageBox.Show("Cache will be automatically cleared when "+Program.BrandName+" exits.", "Clear Cache", MessageBoxButtons.OK, MessageBoxIcon.Information);
}
private void checkHardwareAcceleration_CheckedChanged(object sender, EventArgs e){
@@ -46,7 +48,7 @@ namespace TweetDck.Core.Other.Settings{
succeeded = HardwareAcceleration.Enable();
}
else{
MessageBox.Show("Cannot enable hardware acceleration, the libraries libEGL.dll and libGLESv2.dll could not be restored.",Program.BrandName+" Settings",MessageBoxButtons.OK,MessageBoxIcon.Error);
MessageBox.Show("Cannot enable hardware acceleration, the libraries libEGL.dll and libGLESv2.dll could not be restored.", Program.BrandName+" Settings", MessageBoxButtons.OK, MessageBoxIcon.Error);
}
}
else{
@@ -81,14 +83,14 @@ namespace TweetDck.Core.Other.Settings{
Config.CustomBrowserCSS = form.BrowserCSS;
Config.CustomNotificationCSS = form.NotificationCSS;
if (hasChangedBrowser && MessageBox.Show("The browser CSS has changed, do you want to reload it?","Browser CSS Changed",MessageBoxButtons.YesNo,MessageBoxIcon.Question,MessageBoxDefaultButton.Button2) == DialogResult.Yes){
if (hasChangedBrowser && MessageBox.Show("The browser CSS has changed, do you want to reload it?", "Browser CSS Changed", MessageBoxButtons.YesNo, MessageBoxIcon.Question, MessageBoxDefaultButton.Button2) == DialogResult.Yes){
browserReloadAction();
}
}
}
private void btnExport_Click(object sender, EventArgs e){
DialogResult resultSaveCredentials = MessageBox.Show("Do you want to include your login session? This will not save your password into the file, but it will allow anyone with the file to login into TweetDeck as you.","Export "+Program.BrandName+" Settings",MessageBoxButtons.YesNoCancel,MessageBoxIcon.Question,MessageBoxDefaultButton.Button3);
DialogResult resultSaveCredentials = MessageBox.Show("Do you want to include your login session? This will not save your password into the file, but it will allow anyone with the file to login into TweetDeck as you.", "Export "+Program.BrandName+" Settings", MessageBoxButtons.YesNoCancel, MessageBoxIcon.Question, MessageBoxDefaultButton.Button3);
if (resultSaveCredentials == DialogResult.Cancel)return;
bool saveCredentials = resultSaveCredentials == DialogResult.Yes;
@@ -109,10 +111,10 @@ namespace TweetDck.Core.Other.Settings{
if (file != null){
Program.UserConfig.Save();
ExportManager manager = new ExportManager(file);
ExportManager manager = new ExportManager(file, plugins);
if (!manager.Export(saveCredentials)){
Program.HandleException("An exception happened while exporting "+Program.BrandName+" settings.",manager.LastException);
Program.Reporter.HandleException("Profile Export Error", "An exception happened while exporting "+Program.BrandName+" settings.", true, manager.LastException);
}
}
}
@@ -130,29 +132,24 @@ namespace TweetDck.Core.Other.Settings{
}
if (file != null){
ExportManager manager = new ExportManager(file);
ExportManager manager = new ExportManager(file, plugins);
if (manager.Import()){
((FormSettings)ParentForm).ReloadUI();
if (!manager.IsRestarting){
((FormSettings)ParentForm).ReloadUI();
}
}
else{
Program.HandleException("An exception happened while importing "+Program.BrandName+" settings.",manager.LastException);
Program.Reporter.HandleException("Profile Import Error", "An exception happened while importing "+Program.BrandName+" settings.", true, manager.LastException);
}
}
}
private void btnReset_Click(object sender, EventArgs e){
if (MessageBox.Show("This will reset all of your settings, including disabled plugins. Do you want to proceed?","Reset "+Program.BrandName+" Settings",MessageBoxButtons.YesNo,MessageBoxIcon.Warning,MessageBoxDefaultButton.Button2) == DialogResult.Yes){
if (MessageBox.Show("This will reset all of your settings, including disabled plugins. Do you want to proceed?", "Reset "+Program.BrandName+" Settings", MessageBoxButtons.YesNo, MessageBoxIcon.Warning, MessageBoxDefaultButton.Button2) == DialogResult.Yes){
Program.ResetConfig();
((FormSettings)ParentForm).ReloadUI();
}
}
private static void PromptRestart(){
if (MessageBox.Show("The application must restart for the setting to take place. Do you want to restart now?",Program.BrandName+" Settings",MessageBoxButtons.YesNo,MessageBoxIcon.Information) == DialogResult.Yes){
Process.Start(Application.ExecutablePath,"-restart");
Application.Exit();
}
}
}
}

View File

@@ -28,6 +28,7 @@
this.comboBoxTrayType = new System.Windows.Forms.ComboBox();
this.toolTip = new System.Windows.Forms.ToolTip(this.components);
this.checkTrayHighlight = new System.Windows.Forms.CheckBox();
this.checkSpellCheck = new System.Windows.Forms.CheckBox();
this.groupTray = new System.Windows.Forms.GroupBox();
this.labelTrayIcon = new System.Windows.Forms.Label();
this.groupInterface = new System.Windows.Forms.GroupBox();
@@ -74,12 +75,24 @@
this.checkTrayHighlight.UseVisualStyleBackColor = true;
this.checkTrayHighlight.CheckedChanged += new System.EventHandler(this.checkTrayHighlight_CheckedChanged);
//
// checkSpellCheck
//
this.checkSpellCheck.AutoSize = true;
this.checkSpellCheck.Location = new System.Drawing.Point(9, 44);
this.checkSpellCheck.Name = "checkSpellCheck";
this.checkSpellCheck.Size = new System.Drawing.Size(119, 17);
this.checkSpellCheck.TabIndex = 15;
this.checkSpellCheck.Text = "Enable Spell Check";
this.toolTip.SetToolTip(this.checkSpellCheck, "Underlines words that are spelled incorrectly.");
this.checkSpellCheck.UseVisualStyleBackColor = true;
this.checkSpellCheck.CheckedChanged += new System.EventHandler(this.checkSpellCheck_CheckedChanged);
//
// groupTray
//
this.groupTray.Controls.Add(this.checkTrayHighlight);
this.groupTray.Controls.Add(this.labelTrayIcon);
this.groupTray.Controls.Add(this.comboBoxTrayType);
this.groupTray.Location = new System.Drawing.Point(9, 63);
this.groupTray.Location = new System.Drawing.Point(9, 86);
this.groupTray.Name = "groupTray";
this.groupTray.Size = new System.Drawing.Size(183, 93);
this.groupTray.TabIndex = 15;
@@ -98,10 +111,11 @@
//
// groupInterface
//
this.groupInterface.Controls.Add(this.checkSpellCheck);
this.groupInterface.Controls.Add(this.checkExpandLinks);
this.groupInterface.Location = new System.Drawing.Point(9, 9);
this.groupInterface.Name = "groupInterface";
this.groupInterface.Size = new System.Drawing.Size(183, 48);
this.groupInterface.Size = new System.Drawing.Size(183, 71);
this.groupInterface.TabIndex = 16;
this.groupInterface.TabStop = false;
this.groupInterface.Text = "User Interface";
@@ -131,5 +145,6 @@
private System.Windows.Forms.GroupBox groupInterface;
private System.Windows.Forms.Label labelTrayIcon;
private System.Windows.Forms.CheckBox checkTrayHighlight;
private System.Windows.Forms.CheckBox checkSpellCheck;
}
}

View File

@@ -10,10 +10,11 @@ namespace TweetDck.Core.Other.Settings{
comboBoxTrayType.Items.Add("Minimize to Tray");
comboBoxTrayType.Items.Add("Close to Tray");
comboBoxTrayType.Items.Add("Combined");
comboBoxTrayType.SelectedIndex = Math.Min(Math.Max((int)Config.TrayBehavior,0),comboBoxTrayType.Items.Count-1);
comboBoxTrayType.SelectedIndex = Math.Min(Math.Max((int)Config.TrayBehavior, 0), comboBoxTrayType.Items.Count-1);
checkExpandLinks.Checked = Program.UserConfig.ExpandLinksOnHover;
checkTrayHighlight.Checked = Program.UserConfig.EnableTrayHighlight;
checkExpandLinks.Checked = Config.ExpandLinksOnHover;
checkSpellCheck.Checked = Config.EnableSpellCheck;
checkTrayHighlight.Checked = Config.EnableTrayHighlight;
}
private void checkExpandLinks_CheckedChanged(object sender, EventArgs e){
@@ -22,6 +23,13 @@ namespace TweetDck.Core.Other.Settings{
Config.ExpandLinksOnHover = checkExpandLinks.Checked;
}
private void checkSpellCheck_CheckedChanged(object sender, EventArgs e){
if (!Ready)return;
Config.EnableSpellCheck = checkSpellCheck.Checked;
PromptRestart();
}
private void comboBoxTrayType_SelectedIndexChanged(object sender, EventArgs e){
if (!Ready)return;

View File

@@ -43,7 +43,7 @@ namespace TweetDck.Core.Other.Settings{
comboBoxDisplay.Items.Add(screen.DeviceName+" ("+screen.Bounds.Width+"x"+screen.Bounds.Height+")");
}
comboBoxDisplay.SelectedIndex = Math.Min(comboBoxDisplay.Items.Count-1,Config.NotificationDisplay);
comboBoxDisplay.SelectedIndex = Math.Min(comboBoxDisplay.Items.Count-1, Config.NotificationDisplay);
checkNotificationTimer.Checked = Config.DisplayNotificationTimer;
checkTimerCountDown.Enabled = checkNotificationTimer.Checked;

View File

@@ -40,7 +40,7 @@ namespace TweetDck.Core.Other.Settings{
btnCheckUpdates.Enabled = true;
if (!e.UpdateAvailable){
MessageBox.Show("Your version of "+Program.BrandName+" is up to date.","No Updates Available",MessageBoxButtons.OK,MessageBoxIcon.Information);
MessageBox.Show("Your version of "+Program.BrandName+" is up to date.", "No Updates Available", MessageBoxButtons.OK, MessageBoxIcon.Information);
}
}
}

View File

@@ -45,7 +45,7 @@ namespace TweetDck.Core{
private void trayIcon_MouseClick(object sender, MouseEventArgs e){
if (e.Button == MouseButtons.Left){
restoreToolStripMenuItem_Click(sender,e);
restoreToolStripMenuItem_Click(sender, e);
}
}
@@ -60,7 +60,7 @@ namespace TweetDck.Core{
private void restoreToolStripMenuItem_Click(object sender, EventArgs e){
if (ClickRestore != null){
ClickRestore(this,e);
ClickRestore(this, e);
}
}
@@ -71,7 +71,7 @@ namespace TweetDck.Core{
private void closeToolStripMenuItem_Click(object sender, EventArgs e){
if (ClickClose != null){
ClickClose(this,e);
ClickClose(this, e);
}
}
}

View File

@@ -8,14 +8,11 @@ namespace TweetDck.Core.Utils{
static class BrowserCache{
private static bool ClearOnExit { get; set; }
private static readonly string IndexFile = Path.Combine(Program.StoragePath,"index");
private static readonly string CacheFolder = Path.Combine(Program.StoragePath, "Cache");
private static IEnumerable<string> CacheFiles{
get{
return Directory.EnumerateFiles(Program.StoragePath).Where(path => {
string file = Path.GetFileName(path);
return file != null && (file.StartsWith("data_",StringComparison.Ordinal) || file.StartsWith("f_",StringComparison.Ordinal));
}).Concat(new[]{ IndexFile });
return Directory.EnumerateFiles(CacheFolder);
}
}
@@ -30,10 +27,25 @@ namespace TweetDck.Core.Utils{
}).Sum();
});
task.ContinueWith(originalTask => callbackBytes(originalTask.Exception == null ? originalTask.Result : -1L),TaskContinuationOptions.ExecuteSynchronously);
task.ContinueWith(originalTask => callbackBytes(originalTask.Exception == null ? originalTask.Result : -1L), TaskContinuationOptions.ExecuteSynchronously);
task.Start();
}
public static void ClearOldCacheFiles(){
if (!Directory.Exists(CacheFolder)){
foreach(string file in Directory.EnumerateFiles(Program.StoragePath).Where(path => {
string file = Path.GetFileName(path);
return file != null && (file.StartsWith("data_", StringComparison.Ordinal) || file.StartsWith("f_", StringComparison.Ordinal));
}).Concat(new[]{ Path.Combine(Program.StoragePath, "index") })){
try{
File.Delete(file);
}catch{
// welp, too bad
}
}
}
}
public static void SetClearOnExit(){
ClearOnExit = true;
}

View File

@@ -45,7 +45,7 @@ namespace TweetDck.Core.Utils{
}
};
client.DownloadFileAsync(new Uri(url),target);
client.DownloadFileAsync(new Uri(url), target);
}
}
}

View File

@@ -7,11 +7,11 @@ namespace TweetDck.Core.Utils{
private static Regex SplitRegex{
get{
return splitRegex ?? (splitRegex = new Regex(@"([^=\s]+(?:=(?:""[^""]*?""|[^ ]*))?)",RegexOptions.Compiled));
return splitRegex ?? (splitRegex = new Regex(@"([^=\s]+(?:=(?:""[^""]*?""|[^ ]*))?)", RegexOptions.Compiled));
}
}
public static int AddToDictionary(string args, IDictionary<string,string> dictionary){
public static int AddToDictionary(string args, IDictionary<string, string> dictionary){
if (string.IsNullOrWhiteSpace(args)){
return 0;
}
@@ -29,11 +29,11 @@ namespace TweetDck.Core.Utils{
value = "1";
}
else{
key = matchValue.Substring(0,indexEquals).TrimStart('-');
key = matchValue.Substring(0, indexEquals).TrimStart('-');
value = matchValue.Substring(indexEquals+1).Trim('"');
}
if (key != string.Empty){
if (key.Length != 0){
dictionary[key] = value;
++count;
}

View File

@@ -3,8 +3,8 @@ using System.IO;
namespace TweetDck.Core.Utils{
static class HardwareAcceleration{
private static readonly string LibEGL = Path.Combine(AppDomain.CurrentDomain.BaseDirectory,"libEGL.dll");
private static readonly string LibGLES = Path.Combine(AppDomain.CurrentDomain.BaseDirectory,"libGLESv2.dll");
private static readonly string LibEGL = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "libEGL.dll");
private static readonly string LibGLES = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "libGLESv2.dll");
private static readonly string DisabledLibEGL = LibEGL+".bak";
private static readonly string DisabledLibGLES = LibGLES+".bak";
@@ -25,8 +25,8 @@ namespace TweetDck.Core.Utils{
if (IsEnabled)return false;
try{
File.Move(DisabledLibEGL,LibEGL);
File.Move(DisabledLibGLES,LibGLES);
File.Move(DisabledLibEGL, LibEGL);
File.Move(DisabledLibGLES, LibGLES);
return true;
}catch{
return false;
@@ -49,8 +49,8 @@ namespace TweetDck.Core.Utils{
}
try{
File.Move(LibEGL,DisabledLibEGL);
File.Move(LibGLES,DisabledLibGLES);
File.Move(LibEGL, DisabledLibEGL);
File.Move(LibGLES, DisabledLibGLES);
return true;
}catch{
return false;

View File

@@ -25,9 +25,6 @@ namespace TweetDck.Core.Utils{
public delegate IntPtr HookProc(int nCode, IntPtr wParam, IntPtr lParam);
[DllImport("Shell32.dll")]
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);
@@ -54,7 +51,7 @@ namespace TweetDck.Core.Utils{
public static extern IntPtr CallNextHookEx(IntPtr idHook, int nCode, IntPtr wParam, IntPtr lParam);
public static void SetFormPos(Form form, int hWndOrder, uint flags){
SetWindowPos(form.Handle.ToInt32(),hWndOrder,form.Left,form.Top,form.Width,form.Height,flags);
SetWindowPos(form.Handle.ToInt32(), hWndOrder, form.Left, form.Top, form.Width, form.Height, flags);
}
public static void SimulateMouseClick(MouseButton button){
@@ -74,8 +71,8 @@ namespace TweetDck.Core.Utils{
default: return;
}
mouse_event(flagHold,Cursor.Position.X,Cursor.Position.Y,0,0);
mouse_event(flagRelease,Cursor.Position.X,Cursor.Position.Y,0,0);
mouse_event(flagHold, Cursor.Position.X, Cursor.Position.Y, 0, 0);
mouse_event(flagRelease, Cursor.Position.X, Cursor.Position.Y, 0, 0);
}
}
}

View File

@@ -0,0 +1,33 @@
using System.IO;
using System.Linq;
using System.Security.AccessControl;
using System.Security.Principal;
namespace TweetDck.Core.Utils{
static class WindowsUtils{
public static bool CheckFolderPermission(string path, FileSystemRights right){
try{
AuthorizationRuleCollection rules = Directory.GetAccessControl(path).GetAccessRules(true, true, typeof(SecurityIdentifier));
WindowsIdentity identity = WindowsIdentity.GetCurrent();
if (identity == null || identity.Groups == null){
return false;
}
bool accessAllow = false, accessDeny = false;
foreach(FileSystemAccessRule rule in rules.Cast<FileSystemAccessRule>().Where(rule => identity.Groups.Contains(rule.IdentityReference) && (right & rule.FileSystemRights) == right)){
switch(rule.AccessControlType){
case AccessControlType.Allow: accessAllow = true; break;
case AccessControlType.Deny: accessDeny = true; break;
}
}
return accessAllow && !accessDeny;
}
catch{
return false;
}
}
}
}

View File

@@ -13,7 +13,7 @@ namespace TweetDck.Migration{
}
protected override void OnPaint(PaintEventArgs e){
e.Graphics.DrawIcon(SystemIcons.Question,10,10);
e.Graphics.DrawIcon(SystemIcons.Question, 10, 10);
base.OnPaint(e);
}

View File

@@ -1,42 +0,0 @@
using System;
using System.IO;
using Shell32;
namespace TweetDck.Migration.Helpers{
sealed class LnkEditor{
private readonly ShellLinkObject obj;
public LnkEditor(string file){
try{
Shell shell = new Shell();
Folder folder = shell.NameSpace(Path.GetDirectoryName(file));
FolderItem item = folder.Items().Item(Path.GetFileName(file));
obj = item.GetLink as ShellLinkObject;
}catch(Exception){
obj = null;
}
}
public void SetComment(string newComment){
if (obj == null)return;
obj.Description = newComment;
}
public void SetPath(string newPath){
if (obj == null)return;
obj.Path = newPath;
obj.SetIconLocation(newPath,0);
}
public void SetWorkingDirectory(string newWorkingDirectory){
if (obj == null)return;
obj.WorkingDirectory = newWorkingDirectory;
}
public void Save(){
if (obj == null)return;
obj.Save();
}
}
}

View File

@@ -5,12 +5,12 @@ using Microsoft.Win32;
namespace TweetDck.Migration.Helpers{
static class ProgramRegistrySearch{
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);
string guid;
return FindMatchingSubKey(Registry.LocalMachine,@"SOFTWARE\Wow6432Node\Microsoft\Windows\CurrentVersion\Uninstall",predicate,out guid) ||
FindMatchingSubKey(Registry.LocalMachine,@"SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall",predicate,out guid) ||
FindMatchingSubKey(Registry.CurrentUser,@"SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall",predicate,out guid)
return FindMatchingSubKey(Registry.LocalMachine, @"SOFTWARE\Wow6432Node\Microsoft\Windows\CurrentVersion\Uninstall", predicate, out guid) ||
FindMatchingSubKey(Registry.LocalMachine, @"SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall", predicate, out guid) ||
FindMatchingSubKey(Registry.CurrentUser, @"SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall", predicate, out guid)
? guid : null;
}
@@ -18,10 +18,10 @@ namespace TweetDck.Migration.Helpers{
string outputId = null;
try{
RegistryKey parentKey = keyHandle.OpenSubKey(path,false);
RegistryKey parentKey = keyHandle.OpenSubKey(path, false);
if (parentKey == null)throw new InvalidOperationException();
foreach(RegistryKey subKey in parentKey.GetSubKeyNames().Select(subName => parentKey.OpenSubKey(subName,false)).Where(subKey => subKey != null)){
foreach(RegistryKey subKey in parentKey.GetSubKeyNames().Select(subName => parentKey.OpenSubKey(subName, false)).Where(subKey => subKey != null)){
if (predicate(subKey)){
outputId = subKey.Name.Substring(subKey.Name.LastIndexOf('\\')+1);
subKey.Close();

View File

@@ -1,5 +1,4 @@
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
@@ -8,14 +7,28 @@ using System.Threading.Tasks;
using System.Windows.Forms;
using Microsoft.Win32;
using TweetDck.Migration.Helpers;
using TweetDck.Core.Utils;
namespace TweetDck.Migration{
static class MigrationManager{
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 TweetDeckPathParent = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData), "twitter");
private static readonly string TweetDeckPath = Path.Combine(TweetDeckPathParent, "TweetDeck");
private static readonly string TweetDickStorage = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData), "TweetDick");
public static void Run(){
if (!Program.IsPortable && Directory.Exists(TweetDickStorage) && !Directory.Exists(Program.StoragePath)){
if (MessageBox.Show("Welcome to TweetDuck! Would you like to move your old TweetDick configuration and login data?", "TweetDick Migration", MessageBoxButtons.YesNo, MessageBoxIcon.Question) == DialogResult.Yes){
try{
Directory.Move(TweetDickStorage, Program.StoragePath);
MessageBox.Show("All done! You can now uninstall TweetDick.", "TweetDick Migration", MessageBoxButtons.OK, MessageBoxIcon.Information);
}catch(Exception ex){
Program.Reporter.HandleException("Migration Error", "An unexpected error occurred during the migration process.", true, ex);
}
}
return;
}
if (!Program.UserConfig.IgnoreMigration && Directory.Exists(TweetDeckPath)){
MigrationDecision decision;
@@ -29,11 +42,11 @@ namespace TweetDck.Migration{
FormBackgroundWork formWait = new FormBackgroundWork();
formWait.ShowWorkDialog(() => {
if (!BeginMigration(decision,ex => formWait.Invoke(new Action(() => {
if (!BeginMigration(decision, ex => formWait.Invoke(new Action(() => {
formWait.Close();
if (ex != null){
Program.HandleException("An unexpected exception has occurred during the migration process.",ex);
Program.Reporter.HandleException("Migration Error", "An unexpected error occurred during the migration process.", true, ex);
return;
}
@@ -55,8 +68,8 @@ namespace TweetDck.Migration{
else if (!Program.UserConfig.IgnoreUninstallCheck){
string guid = ProgramRegistrySearch.FindByDisplayName("TweetDeck");
if (guid != null && MessageBox.Show("TweetDeck is still installed on your computer, do you want to uninstall it?","Uninstall TweetDeck",MessageBoxButtons.YesNo,MessageBoxIcon.Question,MessageBoxDefaultButton.Button2) == DialogResult.Yes){
RunUninstaller(guid,0);
if (guid != null && MessageBox.Show("TweetDeck is still installed on your computer, do you want to uninstall it?", "Uninstall TweetDeck", MessageBoxButtons.YesNo, MessageBoxIcon.Question, MessageBoxDefaultButton.Button2) == DialogResult.Yes){
RunUninstaller(guid, 0);
CleanupTweetDeck();
}
@@ -72,8 +85,8 @@ namespace TweetDck.Migration{
Task task = new Task(() => {
Directory.CreateDirectory(Program.StoragePath);
Directory.CreateDirectory(Path.Combine(Program.StoragePath,"localStorage"));
Directory.CreateDirectory(Path.Combine(Program.StoragePath,"Local Storage"));
Directory.CreateDirectory(Path.Combine(Program.StoragePath, "localStorage"));
Directory.CreateDirectory(Path.Combine(Program.StoragePath, "Local Storage"));
CopyFile("Cookies");
CopyFile("Cookies-journal");
@@ -105,7 +118,7 @@ namespace TweetDck.Migration{
// delete folders
for(int wait = 0; wait < 50; wait++){
try{
Directory.Delete(TweetDeckPath,true);
Directory.Delete(TweetDeckPath, true);
break;
}catch(Exception){
// browser subprocess not ended yet, wait
@@ -114,48 +127,18 @@ namespace TweetDck.Migration{
}
try{
Directory.Delete(TweetDeckPathParent,false);
Directory.Delete(TweetDeckPathParent, false);
}catch(IOException){
// most likely not empty, ignore
}
}
if (decision == MigrationDecision.MigratePurge){
// update the lnk files wherever possible (desktop icons, pinned taskbar, start menu)
foreach(string location in GetLnkDirectories()){
if (string.IsNullOrEmpty(location))continue;
string linkFile = Path.Combine(location,"TweetDeck.lnk");
if (File.Exists(linkFile)){
LnkEditor lnk = new LnkEditor(linkFile);
lnk.SetPath(Application.ExecutablePath);
lnk.SetWorkingDirectory(Environment.CurrentDirectory);
lnk.SetComment(Program.BrandName+" client for Windows");
lnk.Save();
string renamed = Path.Combine(location,Program.BrandName+".lnk");
try{
if (!File.Exists(renamed)){
File.Move(linkFile,renamed);
}
else{
File.Delete(linkFile);
}
}catch{
// eh, too bad
}
}
}
NativeMethods.SHChangeNotify(0x8000000,0x1000,IntPtr.Zero,IntPtr.Zero); // refreshes desktop
// uninstall in the background
string guid = ProgramRegistrySearch.FindByDisplayName("TweetDeck");
if (guid != null){
RunUninstaller(guid,5000);
RunUninstaller(guid, 5000);
}
// registry cleanup
@@ -165,7 +148,7 @@ namespace TweetDck.Migration{
}
});
task.ContinueWith(originalTask => onFinished(originalTask.Exception),TaskContinuationOptions.ExecuteSynchronously);
task.ContinueWith(originalTask => onFinished(originalTask.Exception), TaskContinuationOptions.ExecuteSynchronously);
task.Start();
return true;
@@ -173,20 +156,14 @@ namespace TweetDck.Migration{
private static void CopyFile(string relativePath){
try{
File.Copy(Path.Combine(TweetDeckPath,relativePath),Path.Combine(Program.StoragePath,relativePath),true);
File.Copy(Path.Combine(TweetDeckPath, relativePath), Path.Combine(Program.StoragePath, relativePath), true);
}catch(FileNotFoundException){
}catch(DirectoryNotFoundException){
}
}
private static IEnumerable<string> GetLnkDirectories(){
yield return Environment.GetFolderPath(Environment.SpecialFolder.DesktopDirectory);
yield return Environment.GetFolderPath(Environment.SpecialFolder.CommonDesktopDirectory);
yield return Environment.ExpandEnvironmentVariables(@"%APPDATA%\Microsoft\Internet Explorer\Quick Launch\User Pinned\TaskBar");
}
private static void RunUninstaller(string guid, int timeout){
Process uninstaller = Process.Start("msiexec.exe","/x "+guid+" /quiet /qn");
Process uninstaller = Process.Start("msiexec.exe", "/x "+guid+" /quiet /qn");
if (uninstaller != null){
if (timeout > 0){
@@ -199,7 +176,7 @@ namespace TweetDck.Migration{
private static void CleanupTweetDeck(){
try{
Registry.CurrentUser.DeleteSubKeyTree(@"Software\Twitter\TweetDeck",true);
Registry.CurrentUser.DeleteSubKeyTree(@"Software\Twitter\TweetDeck", true);
Registry.CurrentUser.DeleteSubKey(@"Software\Twitter"); // only if empty
}catch(Exception){
// not found or too bad

View File

@@ -31,6 +31,7 @@
this.flowLayoutInfo = new System.Windows.Forms.FlowLayoutPanel();
this.labelWebsite = new System.Windows.Forms.Label();
this.labelVersion = new System.Windows.Forms.Label();
this.btnOpenConfig = new System.Windows.Forms.Button();
this.panelDescription.SuspendLayout();
this.flowLayoutInfo.SuspendLayout();
this.SuspendLayout();
@@ -38,9 +39,9 @@
// btnToggleState
//
this.btnToggleState.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right)));
this.btnToggleState.Location = new System.Drawing.Point(449, 80);
this.btnToggleState.Location = new System.Drawing.Point(459, 80);
this.btnToggleState.Name = "btnToggleState";
this.btnToggleState.Size = new System.Drawing.Size(75, 23);
this.btnToggleState.Size = new System.Drawing.Size(65, 23);
this.btnToggleState.TabIndex = 0;
this.btnToggleState.Text = "Disable";
this.btnToggleState.UseVisualStyleBackColor = true;
@@ -99,7 +100,7 @@
this.flowLayoutInfo.Controls.Add(this.labelWebsite);
this.flowLayoutInfo.Location = new System.Drawing.Point(11, 85);
this.flowLayoutInfo.Name = "flowLayoutInfo";
this.flowLayoutInfo.Size = new System.Drawing.Size(432, 18);
this.flowLayoutInfo.Size = new System.Drawing.Size(368, 18);
this.flowLayoutInfo.TabIndex = 4;
this.flowLayoutInfo.WrapContents = false;
//
@@ -128,10 +129,22 @@
this.labelVersion.Text = "Version";
this.labelVersion.TextAlign = System.Drawing.ContentAlignment.TopRight;
//
// btnOpenConfig
//
this.btnOpenConfig.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right)));
this.btnOpenConfig.Location = new System.Drawing.Point(385, 80);
this.btnOpenConfig.Name = "btnOpenConfig";
this.btnOpenConfig.Size = new System.Drawing.Size(68, 23);
this.btnOpenConfig.TabIndex = 6;
this.btnOpenConfig.Text = "Configure";
this.btnOpenConfig.UseVisualStyleBackColor = true;
this.btnOpenConfig.Click += new System.EventHandler(this.btnOpenConfig_Click);
//
// PluginControl
//
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
this.Controls.Add(this.btnOpenConfig);
this.Controls.Add(this.flowLayoutInfo);
this.Controls.Add(this.panelDescription);
this.Controls.Add(this.labelName);
@@ -161,5 +174,6 @@
private System.Windows.Forms.FlowLayoutPanel flowLayoutInfo;
private System.Windows.Forms.Label labelWebsite;
private System.Windows.Forms.Label labelVersion;
private System.Windows.Forms.Button btnOpenConfig;
}
}

View File

@@ -1,5 +1,7 @@
using System;
using System.Diagnostics;
using System.Drawing;
using System.IO;
using System.Windows.Forms;
using TweetDck.Core.Utils;
@@ -21,26 +23,23 @@ namespace TweetDck.Plugins.Controls{
this.labelVersion.Text = plugin.Version;
this.labelAuthor.Text = plugin.Author;
this.labelWebsite.Text = plugin.Website;
this.btnToggleState.Text = pluginManager.Config.IsEnabled(plugin) ? "Disable" : "Enable";
if (!plugin.CanRun){
this.labelName.ForeColor = Color.DarkRed;
this.btnToggleState.Enabled = false;
}
else if (labelDescription.Text == string.Empty){
UpdatePluginState();
if (labelDescription.Text.Length == 0){
labelDescription.Visible = false;
}
panelDescription_Resize(panelDescription,new EventArgs());
panelDescription_Resize(panelDescription, new EventArgs());
}
private void panelDescription_Resize(object sender, EventArgs e){
if (labelDescription.Text == string.Empty){
if (labelDescription.Text.Length == 0){
Height = MinimumSize.Height;
}
else{
labelDescription.MaximumSize = new Size(panelDescription.Width-SystemInformation.VerticalScrollBarWidth,0);
Height = Math.Min(MinimumSize.Height+9+labelDescription.Height,MaximumSize.Height);
labelDescription.MaximumSize = new Size(panelDescription.Width-SystemInformation.VerticalScrollBarWidth, 0);
Height = Math.Min(MinimumSize.Height+9+labelDescription.Height, MaximumSize.Height);
}
}
@@ -50,11 +49,38 @@ namespace TweetDck.Plugins.Controls{
}
}
private void btnOpenConfig_Click(object sender, EventArgs e){
using(Process.Start("explorer.exe", "/select,\""+plugin.ConfigPath+"\"")){}
}
private void btnToggleState_Click(object sender, EventArgs e){
bool newState = !pluginManager.Config.IsEnabled(plugin);
pluginManager.Config.SetEnabled(plugin,newState);
pluginManager.Config.SetEnabled(plugin, newState);
btnToggleState.Text = newState ? "Disable" : "Enable";
UpdatePluginState();
}
private void UpdatePluginState(){
bool isEnabled = plugin.CanRun && pluginManager.Config.IsEnabled(plugin);
Color textColor = isEnabled ? Color.Black : Color.FromArgb(90, 90, 90);
labelVersion.ForeColor = textColor;
labelAuthor.ForeColor = textColor;
labelWebsite.ForeColor = isEnabled ? Color.Blue : Color.FromArgb(90, 90, 249);
if (plugin.CanRun){
labelName.ForeColor = textColor;
labelDescription.ForeColor = textColor;
btnToggleState.Text = isEnabled ? "Disable" : "Enable";
btnOpenConfig.Visible = plugin.HasConfig;
btnOpenConfig.Enabled = btnOpenConfig.Visible && File.Exists(plugin.ConfigPath);
}
else{
labelName.ForeColor = Color.DarkRed;
labelDescription.ForeColor = Color.DarkRed;
btnToggleState.Visible = false;
btnOpenConfig.Visible = false;
}
}
}
}

View File

@@ -3,8 +3,13 @@ using TweetDck.Core.Utils;
namespace TweetDck.Plugins.Controls{
sealed partial class PluginListFlowLayout : FlowLayoutPanel{
public PluginListFlowLayout(){
FlowDirection = FlowDirection.TopDown;
WrapContents = false;
}
protected override void WndProc(ref Message m){
NativeMethods.ShowScrollBar(Handle,NativeMethods.SB_HORZ,false); // basically fuck the horizontal scrollbar very much
NativeMethods.ShowScrollBar(Handle, NativeMethods.SB_HORZ, false); // basically fuck the horizontal scrollbar very much
base.WndProc(ref m);
}
}

View File

@@ -12,6 +12,8 @@ namespace TweetDck.Plugins{
public string Author { get { return metadata["AUTHOR"]; } }
public string Version { get { return metadata["VERSION"]; } }
public string Website { get { return metadata["WEBSITE"]; } }
public string ConfigFile { get { return metadata["CONFIGFILE"]; } }
public string ConfigDefault { get { return metadata["CONFIGDEFAULT"]; } }
public string RequiredVersion { get { return metadata["REQUIRES"]; } }
public PluginGroup Group { get; private set; }
public PluginEnvironment Environments { get; private set; }
@@ -28,14 +30,40 @@ namespace TweetDck.Plugins{
}
}
public bool HasConfig{
get{
return ConfigFile.Length > 0 && GetFullPathIfSafe(ConfigFile).Length > 0;
}
}
public string ConfigPath{
get{
return HasConfig ? Path.Combine(path, ConfigFile) : string.Empty;
}
}
public bool HasDefaultConfig{
get{
return ConfigDefault.Length > 0 && GetFullPathIfSafe(ConfigDefault).Length > 0;
}
}
public string DefaultConfigPath{
get{
return HasDefaultConfig ? Path.Combine(path, ConfigDefault) : string.Empty;
}
}
private readonly string path;
private readonly string identifier;
private readonly Dictionary<string,string> metadata = new Dictionary<string,string>(4){
private readonly Dictionary<string, string> metadata = new Dictionary<string, string>(4){
{ "NAME", "" },
{ "DESCRIPTION", "" },
{ "AUTHOR", "(anonymous)" },
{ "VERSION", "(unknown)" },
{ "WEBSITE", "" },
{ "CONFIGFILE", "" },
{ "CONFIGDEFAULT", "" },
{ "REQUIRES", "*" }
};
@@ -48,16 +76,50 @@ namespace TweetDck.Plugins{
this.Environments = PluginEnvironment.None;
}
private void OnMetadataLoaded(){
string configPath = ConfigPath, defaultConfigPath = DefaultConfigPath;
if (configPath.Length > 0 && defaultConfigPath.Length > 0 && !File.Exists(configPath) && File.Exists(defaultConfigPath)){
try{
File.Copy(defaultConfigPath, configPath, false);
}catch(Exception e){
Program.Reporter.HandleException("Plugin Loading Error", "Could not generate a configuration file for '"+identifier+"' plugin.", true, e);
}
}
}
public string GetScriptPath(PluginEnvironment environment){
if (Environments.HasFlag(environment)){
string file = environment.GetScriptFile();
return file != null ? Path.Combine(path,file) : string.Empty;
return file != null ? Path.Combine(path, file) : string.Empty;
}
else{
return string.Empty;
}
}
public string GetFullPathIfSafe(string relativePath){
string fullPath = Path.Combine(path, relativePath);
try{
string folderPathName = new DirectoryInfo(path).FullName;
DirectoryInfo currentInfo = new DirectoryInfo(fullPath);
while(currentInfo.Parent != null){
if (currentInfo.Parent.FullName == folderPathName){
return fullPath;
}
currentInfo = currentInfo.Parent;
}
}
catch{
// ignore
}
return string.Empty;
}
public override string ToString(){
return Identifier;
}
@@ -72,13 +134,13 @@ namespace TweetDck.Plugins{
}
public static Plugin CreateFromFolder(string path, PluginGroup group, out string error){
Plugin plugin = new Plugin(path,group);
Plugin plugin = new Plugin(path, group);
if (!LoadMetadata(path,plugin,out error)){
if (!LoadMetadata(path, plugin, out error)){
return null;
}
if (!LoadEnvironments(path,plugin,out error)){
if (!LoadEnvironments(path, plugin, out error)){
return null;
}
@@ -87,16 +149,8 @@ namespace TweetDck.Plugins{
}
private static bool LoadEnvironments(string path, Plugin plugin, out string error){
foreach(string file in Directory.EnumerateFiles(path,"*.js",SearchOption.TopDirectoryOnly).Select(Path.GetFileName)){
PluginEnvironment environment = PluginEnvironmentExtensions.Values.FirstOrDefault(env => file.Equals(env.GetScriptFile(),StringComparison.Ordinal));
if (environment != PluginEnvironment.None){
plugin.Environments |= environment;
}
else{
error = "Unknown script file: "+file;
return false;
}
foreach(string file in Directory.EnumerateFiles(path, "*.js", SearchOption.TopDirectoryOnly).Select(Path.GetFileName)){
plugin.Environments |= PluginEnvironmentExtensions.Values.FirstOrDefault(env => file.Equals(env.GetScriptFile(), StringComparison.Ordinal));
}
if (plugin.Environments == PluginEnvironment.None){
@@ -111,14 +165,14 @@ namespace TweetDck.Plugins{
private static readonly string[] endTag = { "[END]" };
private static bool LoadMetadata(string path, Plugin plugin, out string error){
string metaFile = Path.Combine(path,".meta");
string metaFile = Path.Combine(path, ".meta");
if (!File.Exists(metaFile)){
error = "Missing .meta file.";
return false;
}
string[] lines = File.ReadAllLines(metaFile,Encoding.UTF8);
string[] lines = File.ReadAllLines(metaFile, Encoding.UTF8);
string currentTag = null, currentContents = "";
foreach(string line in lines.Concat(endTag).Select(line => line.TrimEnd()).Where(line => line.Length > 0)){
@@ -127,7 +181,7 @@ namespace TweetDck.Plugins{
plugin.metadata[currentTag] = currentContents;
}
currentTag = line.Substring(1,line.Length-2).ToUpperInvariant();
currentTag = line.Substring(1, line.Length-2).ToUpperInvariant();
currentContents = "";
if (line.Equals(endTag[0])){
@@ -155,17 +209,19 @@ namespace TweetDck.Plugins{
Version ver;
if (plugin.RequiredVersion.Length == 0 || !(plugin.RequiredVersion.Equals("*") || System.Version.TryParse(plugin.RequiredVersion,out ver))){
if (plugin.RequiredVersion.Length == 0 || !(plugin.RequiredVersion.Equals("*") || System.Version.TryParse(plugin.RequiredVersion, out ver))){
error = "Plugin contains invalid version: "+plugin.RequiredVersion;
return false;
}
plugin.OnMetadataLoaded();
error = string.Empty;
return true;
}
private static bool CheckRequiredVersion(string requires){
return requires.Equals("*",StringComparison.Ordinal) || Program.Version >= new Version(requires);
return requires.Equals("*", StringComparison.Ordinal) || Program.Version >= new Version(requires);
}
}
}

View File

@@ -7,7 +7,7 @@ using TweetDck.Plugins.Events;
namespace TweetDck.Plugins{
class PluginBridge{
private readonly PluginManager manager;
private readonly Dictionary<string,string> fileCache = new Dictionary<string,string>(2);
private readonly Dictionary<string, string> fileCache = new Dictionary<string, string>(2);
public PluginBridge(PluginManager manager){
this.manager = manager;
@@ -20,34 +20,11 @@ namespace TweetDck.Plugins{
private string GetFullPathIfSafe(int token, string path){
Plugin plugin = manager.GetPluginFromToken(token);
if (plugin == null){
return string.Empty;
}
string fullPath = Path.Combine(plugin.FolderPath,path);
try{
string folderPathName = new DirectoryInfo(plugin.FolderPath).FullName;
DirectoryInfo currentInfo = new DirectoryInfo(fullPath);
while(currentInfo.Parent != null){
if (currentInfo.Parent.FullName == folderPathName){
return fullPath;
}
currentInfo = currentInfo.Parent;
}
}
catch{
// ignore
}
return string.Empty;
return plugin == null ? string.Empty : plugin.GetFullPathIfSafe(path);
}
public void WriteFile(int token, string path, string contents){
string fullPath = GetFullPathIfSafe(token,path);
string fullPath = GetFullPathIfSafe(token, path);
if (fullPath == string.Empty){
throw new Exception("File path has to be relative to the plugin folder.");
@@ -56,12 +33,12 @@ namespace TweetDck.Plugins{
// ReSharper disable once AssignNullToNotNullAttribute
Directory.CreateDirectory(Path.GetDirectoryName(fullPath));
File.WriteAllText(fullPath,contents,Encoding.UTF8);
File.WriteAllText(fullPath, contents, Encoding.UTF8);
fileCache[fullPath] = contents;
}
public string ReadFile(int token, string path, bool cache){
string fullPath = GetFullPathIfSafe(token,path);
string fullPath = GetFullPathIfSafe(token, path);
if (fullPath == string.Empty){
throw new Exception("File path has to be relative to the plugin folder.");
@@ -69,22 +46,38 @@ namespace TweetDck.Plugins{
string cachedContents;
if (cache && fileCache.TryGetValue(fullPath,out cachedContents)){
if (cache && fileCache.TryGetValue(fullPath, out cachedContents)){
return cachedContents;
}
return fileCache[fullPath] = File.ReadAllText(fullPath,Encoding.UTF8);
try{
return fileCache[fullPath] = File.ReadAllText(fullPath, Encoding.UTF8);
}catch(FileNotFoundException){
throw new Exception("File not found.");
}catch(DirectoryNotFoundException){
throw new Exception("Directory not found.");
}
}
public void DeleteFile(int token, string path){
string fullPath = GetFullPathIfSafe(token,path);
string fullPath = GetFullPathIfSafe(token, path);
if (fullPath == string.Empty){
if (fullPath.Length == 0){
throw new Exception("File path has to be relative to the plugin folder.");
}
fileCache.Remove(fullPath);
File.Delete(fullPath);
}
public bool CheckFileExists(int token, string path){
string fullPath = GetFullPathIfSafe(token, path);
if (fullPath.Length == 0){
throw new Exception("File path has to be relative to the plugin folder.");
}
return File.Exists(fullPath);
}
}
}

View File

@@ -4,7 +4,7 @@ using TweetDck.Plugins.Events;
namespace TweetDck.Plugins{
[Serializable]
class PluginConfig{
sealed class PluginConfig{
[field:NonSerialized]
public event EventHandler<PluginChangedStateEventArgs> PluginChangedState;
@@ -25,7 +25,7 @@ namespace TweetDck.Plugins{
public void SetEnabled(Plugin plugin, bool enabled){
if ((enabled && Disabled.Remove(plugin.Identifier)) || (!enabled && Disabled.Add(plugin.Identifier))){
if (PluginChangedState != null){
PluginChangedState(this,new PluginChangedStateEventArgs(plugin,enabled));
PluginChangedState(this, new PluginChangedStateEventArgs(plugin, enabled));
}
}
}
@@ -33,5 +33,9 @@ namespace TweetDck.Plugins{
public bool IsEnabled(Plugin plugin){
return !Disabled.Contains(plugin.Identifier) && plugin.CanRun;
}
public void DisableOfficialFromConfig(string pluginName){
Disabled.Add("official/"+pluginName);
}
}
}

View File

@@ -10,9 +10,10 @@ namespace TweetDck.Plugins{
class PluginManager{
public const string PluginBrowserScriptFile = "plugins.browser.js";
public const string PluginNotificationScriptFile = "plugins.notification.js";
public const string PluginGlobalScriptFile = "plugins.js";
public string PathOfficialPlugins { get { return Path.Combine(rootPath,"official"); } }
public string PathCustomPlugins { get { return Path.Combine(rootPath,"user"); } }
public string PathOfficialPlugins { get { return Path.Combine(rootPath, "official"); } }
public string PathCustomPlugins { get { return Path.Combine(rootPath, "user"); } }
public IEnumerable<Plugin> Plugins { get { return plugins; } }
public PluginConfig Config { get; private set; }
@@ -22,7 +23,7 @@ namespace TweetDck.Plugins{
private readonly string rootPath;
private readonly HashSet<Plugin> plugins = new HashSet<Plugin>();
private readonly Dictionary<int,Plugin> tokens = new Dictionary<int,Plugin>();
private readonly Dictionary<int, Plugin> tokens = new Dictionary<int, Plugin>();
private readonly Random rand = new Random();
private List<string> loadErrors;
@@ -47,32 +48,31 @@ namespace TweetDck.Plugins{
public Plugin GetPluginFromToken(int token){
Plugin plugin;
return tokens.TryGetValue(token,out plugin) ? plugin : null;
return tokens.TryGetValue(token, out plugin) ? plugin : null;
}
public void Reload(){
HashSet<Plugin> prevPlugins = new HashSet<Plugin>(plugins);
plugins.Clear();
tokens.Clear();
loadErrors = new List<string>(2);
foreach(Plugin plugin in LoadPluginsFrom(PathOfficialPlugins,PluginGroup.Official)){
foreach(Plugin plugin in LoadPluginsFrom(PathOfficialPlugins, PluginGroup.Official)){
plugins.Add(plugin);
}
foreach(Plugin plugin in LoadPluginsFrom(PathCustomPlugins,PluginGroup.Custom)){
foreach(Plugin plugin in LoadPluginsFrom(PathCustomPlugins, PluginGroup.Custom)){
plugins.Add(plugin);
}
if (Reloaded != null && (loadErrors.Count > 0 || !prevPlugins.SetEquals(plugins))){
Reloaded(this,new PluginLoadEventArgs(loadErrors));
if (Reloaded != null){
Reloaded(this, new PluginLoadEventArgs(loadErrors));
}
}
public void ExecutePlugins(IFrame frame, PluginEnvironment environment, bool includeDisabled){
if (includeDisabled){
ScriptLoader.ExecuteScript(frame,PluginScriptGenerator.GenerateConfig(Config),"gen:pluginconfig");
ScriptLoader.ExecuteScript(frame, PluginScriptGenerator.GenerateConfig(Config), "gen:pluginconfig");
}
foreach(Plugin plugin in Plugins){
@@ -98,14 +98,14 @@ namespace TweetDck.Plugins{
tokens[token] = plugin;
}
ScriptLoader.ExecuteScript(frame,PluginScriptGenerator.GeneratePlugin(plugin.Identifier,script,token,environment),"plugin:"+plugin);
ScriptLoader.ExecuteScript(frame, PluginScriptGenerator.GeneratePlugin(plugin.Identifier, script, token, environment), "plugin:"+plugin);
}
}
private IEnumerable<Plugin> LoadPluginsFrom(string path, PluginGroup group){
foreach(string fullDir in Directory.EnumerateDirectories(path,"*",SearchOption.TopDirectoryOnly)){
foreach(string fullDir in Directory.EnumerateDirectories(path, "*", SearchOption.TopDirectoryOnly)){
string error;
Plugin plugin = Plugin.CreateFromFolder(fullDir,group,out error);
Plugin plugin = Plugin.CreateFromFolder(fullDir, group, out error);
if (plugin == null){
loadErrors.Add(group.GetIdentifierPrefix()+Path.GetFileName(fullDir)+": "+error);

View File

@@ -3,11 +3,11 @@
namespace TweetDck.Plugins{
static class PluginScriptGenerator{
public static string GenerateConfig(PluginConfig config){
return config.AnyDisabled ? "window.TD_PLUGINS.disabled = [\""+string.Join("\",\"",config.DisabledPlugins)+"\"];" : string.Empty;
return config.AnyDisabled ? "window.TD_PLUGINS.disabled = [\""+string.Join("\",\"", config.DisabledPlugins)+"\"];" : string.Empty;
}
public static string GeneratePlugin(string pluginIdentifier, string pluginContents, int pluginToken, PluginEnvironment environment){
StringBuilder build = new StringBuilder(pluginIdentifier.Length+pluginContents.Length+150);
StringBuilder build = new StringBuilder(2*pluginIdentifier.Length+pluginContents.Length+165);
build.Append("(function(").Append(environment.GetScriptVariables()).Append("){");
@@ -16,6 +16,7 @@ namespace TweetDck.Plugins{
build.Append("obj:new class extends PluginBase{").Append(pluginContents).Append("}");
build.Append("};");
build.Append("tmp.obj.$id=\"").Append(pluginIdentifier).Append("\";");
build.Append("tmp.obj.$token=").Append(pluginToken).Append(";");
build.Append("window.TD_PLUGINS.install(tmp);");

View File

@@ -1,8 +1,6 @@
using System;
using System.Diagnostics;
using System.Globalization;
using System.IO;
using System.Text;
using System.Windows.Forms;
using CefSharp;
using TweetDck.Configuration;
@@ -14,42 +12,41 @@ using System.Threading;
using TweetDck.Plugins;
using TweetDck.Plugins.Events;
using TweetDck.Core.Other.Settings.Export;
using TweetDck.Core.Handling;
using System.Security.AccessControl;
[assembly: CLSCompliant(true)]
namespace TweetDck{
static class Program{
#if DUCK
public const string BrandName = "TweetDuck";
public const string Website = "http://tweetduck.chylex.com";
#else
public const string BrandName = "TweetDick";
public const string Website = "http://tweetdick.chylex.com";
#endif
public const string BrowserSubprocess = BrandName+".Browser.exe";
public const string VersionTag = "1.3.2";
public const string VersionFull = "1.3.2.0";
public const string VersionTag = "1.3.3";
public const string VersionFull = "1.3.3.0";
public static readonly Version Version = new Version(VersionTag);
public static readonly string StoragePath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData),BrandName);
public static readonly string PluginPath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory,"plugins");
public static readonly string TemporaryPath = Path.Combine(Path.GetTempPath(),BrandName);
public static readonly string ConfigFilePath = Path.Combine(StoragePath,"TD_UserConfig.cfg");
public static readonly bool IsPortable = File.Exists("makeportable");
public static readonly string ProgramPath = AppDomain.CurrentDomain.BaseDirectory;
public static readonly string StoragePath = IsPortable ? Path.Combine(ProgramPath, "portable", "storage") : GetDataStoragePath();
public static readonly string TemporaryPath = IsPortable ? Path.Combine(ProgramPath, "portable", "tmp") : Path.Combine(Path.GetTempPath(), BrandName+'_'+Path.GetRandomFileName().Substring(0, 6));
public static readonly string ConfigFilePath = Path.Combine(StoragePath, "TD_UserConfig.cfg");
private static readonly string LogFilePath = Path.Combine(StoragePath, "TD_Log.txt");
public static readonly string ScriptPath = Path.Combine(ProgramPath, "scripts");
public static readonly string PluginPath = Path.Combine(ProgramPath, "plugins");
public static uint WindowRestoreMessage;
private static readonly LockManager LockManager = new LockManager(Path.Combine(StoragePath,".lock"));
private static readonly LockManager LockManager = new LockManager(Path.Combine(StoragePath, ".lock"));
private static bool HasCleanedUp;
public static UserConfig UserConfig { get; private set; }
public static string LogFile{
get{
return Path.Combine(AppDomain.CurrentDomain.BaseDirectory,"td-log.txt");
}
}
public static Reporter Reporter { get; private set; }
[STAThread]
private static void Main(){
@@ -58,31 +55,51 @@ namespace TweetDck{
WindowRestoreMessage = NativeMethods.RegisterWindowMessage("TweetDuckRestore");
if (!WindowsUtils.CheckFolderPermission(ProgramPath, FileSystemRights.WriteData)){
MessageBox.Show(BrandName+" does not have write permissions to the program folder. If it is installed in Program Files, please run it as Administrator.", "Administrator Required", MessageBoxButtons.OK, MessageBoxIcon.Warning);
return;
}
Reporter = new Reporter(LogFilePath);
AppDomain.CurrentDomain.UnhandledException += (sender, args) => {
Exception ex = args.ExceptionObject as Exception;
if (ex != null){
Reporter.HandleException(BrandName+" Has Failed :(", "An unhandled exception has occurred.", false, ex);
}
};
string[] programArguments = Environment.GetCommandLineArgs();
if (programArguments.Contains("-restart")){
for(int attempt = 0; attempt < 21; attempt++){
for(int attempt = 0; attempt < 41; attempt++){
if (LockManager.Lock()){
break;
}
else if (attempt == 20){
MessageBox.Show(BrandName+" is taking too long to close, please wait and then start the application again manually.",BrandName+" Cannot Restart",MessageBoxButtons.OK,MessageBoxIcon.Error);
else if (attempt == 40){
MessageBox.Show(BrandName+" is taking too long to close, please wait and then start the application again manually.", BrandName+" Cannot Restart", MessageBoxButtons.OK, MessageBoxIcon.Error);
return;
}
else{
Thread.Sleep(500);
}
}
ReloadConfig();
}
else{
ReloadConfig();
MigrationManager.Run();
if (!LockManager.Lock()){
if (LockManager.LockingProcess.MainWindowHandle == IntPtr.Zero && LockManager.LockingProcess.Responding){ // restore if the original process is in tray
NativeMethods.SendMessage(NativeMethods.HWND_BROADCAST,WindowRestoreMessage,0,IntPtr.Zero);
NativeMethods.SendMessage(NativeMethods.HWND_BROADCAST, WindowRestoreMessage, 0, IntPtr.Zero);
return;
}
else if (MessageBox.Show("Another instance of "+BrandName+" is already running.\r\nDo you want to close it?",BrandName+" is Already Running",MessageBoxButtons.YesNo,MessageBoxIcon.Error,MessageBoxDefaultButton.Button2) == DialogResult.Yes){
if (!LockManager.CloseLockingProcess(10000)){
MessageBox.Show("Could not close the other process.",BrandName+" Has Failed :(",MessageBoxButtons.OK,MessageBoxIcon.Error);
else if (MessageBox.Show("Another instance of "+BrandName+" is already running.\r\nDo you want to close it?", BrandName+" is Already Running", MessageBoxButtons.YesNo, MessageBoxIcon.Error, MessageBoxDefaultButton.Button2) == DialogResult.Yes){
if (!LockManager.CloseLockingProcess(20000)){
MessageBox.Show("Could not close the other process.", BrandName+" Has Failed :(", MessageBoxButtons.OK, MessageBoxIcon.Error);
return;
}
@@ -92,33 +109,16 @@ namespace TweetDck{
}
}
if (programArguments.Contains("-importcookies") && File.Exists(ExportManager.TempCookiesPath)){
try{
if (File.Exists(ExportManager.CookiesPath)){
File.Delete(ExportManager.CookiesPath);
}
File.Move(ExportManager.TempCookiesPath,ExportManager.CookiesPath);
}catch(Exception e){
HandleException("Could not import the cookie file to restore login session.",e);
}
if (programArguments.Contains("-importcookies")){
ExportManager.ImportCookies();
}
ReloadConfig();
MigrationManager.Run();
Cef.OnContextInitialized = () => {
using(IRequestContext ctx = Cef.GetGlobalRequestContext()){
string err;
ctx.SetPreference("browser.enable_spellchecking",false,out err);
}
};
BrowserCache.ClearOldCacheFiles();
CefSettings settings = new CefSettings{
AcceptLanguageList = BrowserUtils.HeaderAcceptLanguage,
UserAgent = BrowserUtils.HeaderUserAgent,
Locale = CultureInfo.CurrentCulture.TwoLetterISOLanguageName,
Locale = GetCmdArgumentValue("locale") ?? "en",
CachePath = StoragePath,
BrowserSubprocessPath = File.Exists(BrowserSubprocess) ? BrowserSubprocess : "CefSharp.BrowserSubprocess.exe",
#if !DEBUG
@@ -126,21 +126,13 @@ namespace TweetDck{
#endif
};
CommandLineArgsParser.AddToDictionary(UserConfig.CustomCefArgs,settings.CefCommandLineArgs);
CommandLineArgsParser.AddToDictionary(UserConfig.CustomCefArgs, settings.CefCommandLineArgs);
Cef.Initialize(settings);
AppDomain.CurrentDomain.UnhandledException += (sender, args) => {
Exception ex = args.ExceptionObject as Exception;
if (ex != null){
HandleException("An unhandled exception has occurred.",ex);
}
};
Cef.Initialize(settings, false, new BrowserProcessHandler());
Application.ApplicationExit += (sender, args) => ExitCleanup();
PluginManager plugins = new PluginManager(PluginPath,UserConfig.Plugins);
PluginManager plugins = new PluginManager(PluginPath, UserConfig.Plugins);
plugins.Reloaded += plugins_Reloaded;
plugins.Config.PluginChangedState += (sender, args) => UserConfig.Save();
plugins.Reload();
@@ -151,39 +143,32 @@ namespace TweetDck{
if (mainForm.UpdateInstallerPath != null){
ExitCleanup();
Process.Start(mainForm.UpdateInstallerPath,"/SP- /SILENT /NOICONS /CLOSEAPPLICATIONS");
Process.Start(mainForm.UpdateInstallerPath, "/SP- /SILENT /NOICONS /CLOSEAPPLICATIONS");
Application.Exit();
}
}
private static void plugins_Reloaded(object sender, PluginLoadEventArgs e){
if (!e.Success){
MessageBox.Show("The following plugins will not be available until the issues are resolved:\n"+string.Join("\n",e.Errors),"Error Loading Plugins",MessageBoxButtons.OK,MessageBoxIcon.Warning);
MessageBox.Show("The following plugins will not be available until the issues are resolved:\n"+string.Join("\n", e.Errors), "Error Loading Plugins", MessageBoxButtons.OK, MessageBoxIcon.Warning);
}
}
public static void HandleException(string message, Exception e){
Log(e.ToString());
private static string GetCmdArgumentValue(string search){
string[] args = Environment.GetCommandLineArgs();
int index = Array.FindIndex(args, arg => arg.Equals(search, StringComparison.OrdinalIgnoreCase));
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(LogFile);
}
return index >= 0 && index < args.Length-1 ? args[index+1] : null;
}
public static void Log(string data){
StringBuilder build = new StringBuilder();
private static string GetDataStoragePath(){
string custom = GetCmdArgumentValue("-datafolder");
if (!File.Exists(LogFile)){
build.Append("Please, report all issues to: https://github.com/chylex/TweetDuck/issues\r\n\r\n");
if (custom != null && (custom.Contains(Path.DirectorySeparatorChar) || custom.Contains(Path.AltDirectorySeparatorChar))){
return custom;
}
build.Append("[").Append(DateTime.Now.ToString("G")).Append("]\r\n");
build.Append(data).Append("\r\n\r\n");
try{
File.AppendAllText(LogFile,build.ToString(),Encoding.UTF8);
}catch{
// oops
else{
return Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData), custom ?? BrandName);
}
}
@@ -196,7 +181,7 @@ namespace TweetDck{
File.Delete(ConfigFilePath);
File.Delete(UserConfig.GetBackupFile(ConfigFilePath));
}catch(Exception e){
HandleException("Could not delete configuration files to reset the settings.",e);
Reporter.HandleException("Configuration Reset Error", "Could not delete configuration files to reset the settings.", true, e);
return;
}
@@ -209,7 +194,7 @@ namespace TweetDck{
UserConfig.Save();
try{
Directory.Delete(TemporaryPath,true);
Directory.Delete(TemporaryPath, true);
}catch(DirectoryNotFoundException){
}catch(Exception e){
// welp, too bad

View File

@@ -1,13 +1,11 @@
# 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.
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 53 or newer currently available as a pre-release.
```
PM> Install-Package CefSharp.WinForms -Pre
PM> Install-Package CefSharp.WinForms -Pre -Version 53.0.0-pre01
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**.

74
Reporter.cs Normal file
View File

@@ -0,0 +1,74 @@
using System;
using System.Diagnostics;
using System.Drawing;
using System.Globalization;
using System.IO;
using System.Text;
using System.Windows.Forms;
using TweetDck.Core.Other;
namespace TweetDck{
class Reporter{
private readonly string logFile;
public Reporter(string logFile){
this.logFile = logFile;
}
public bool Log(string data){
StringBuilder build = new StringBuilder();
if (!File.Exists(logFile)){
build.Append("Please, report all issues to: https://github.com/chylex/TweetDuck/issues\r\n\r\n");
}
build.Append("[").Append(DateTime.Now.ToString("G", CultureInfo.CurrentCulture)).Append("]\r\n");
build.Append(data).Append("\r\n\r\n");
try{
File.AppendAllText(logFile, build.ToString(), Encoding.UTF8);
return true;
}catch{
return false;
}
}
public void HandleException(string caption, string message, bool canIgnore, Exception e){
Log(e.ToString());
FormMessage form = new FormMessage(caption, message+"\r\nError: "+e.Message, canIgnore ? MessageBoxIcon.Warning : MessageBoxIcon.Error);
form.AddButton("Exit");
Button btnIgnore = form.AddButton("Ignore");
Button btnOpenLog = new Button{
Anchor = AnchorStyles.Bottom | AnchorStyles.Left,
Location = new Point(12, 12),
Margin = new Padding(0, 0, 48, 0),
Size = new Size(88, 26),
Text = "Show Error Log",
UseVisualStyleBackColor = true
};
btnOpenLog.Click += (sender, args) => Process.Start(logFile);
form.AddActionControl(btnOpenLog);
if (!canIgnore){
btnIgnore.Enabled = false;
}
if (form.ShowDialog() == DialogResult.OK){
if (form.ClickedButton == btnIgnore){
return;
}
}
try{
Process.GetCurrentProcess().Kill();
}catch{
Environment.FailFast(message, e);
}
}
}
}

View File

@@ -0,0 +1,14 @@
[name]
Clear columns
[description]
- Adds buttons and keyboard shortcuts to quickly clear columns
[author]
chylex
[version]
1.0
[website]
https://tweetduck.chylex.com

View File

@@ -0,0 +1,92 @@
constructor(){
super({
requiresPageReload: true
});
}
enabled(){
// prepare variables and functions
var clearColumn = (columnName) => {
TD.controller.columnManager.get(columnName).clear();
TD.controller.stats.columnActionClick("clear");
};
var clearAllColumns = () => {
Object.keys(TD.controller.columnManager.getAll()).forEach(key => clearColumn(key));
};
var replaceMustache = (key, search, replace) => {
TD.mustaches[key] = TD.mustaches[key].replace(search, replace);
};
// prepare event handlers
this.eventClearSingle = function(){
clearColumn($(this).closest(".js-column").attr("data-column"));
};
this.eventClearAll = function(){
clearAllColumns();
};
this.eventKeys = function(e){
if (e.keyCode === 46 && (document.activeElement === null || document.activeElement === document.body)){ // 46 = delete
if (e.altKey){
clearAllColumns();
}
else{
var focusedColumn = $(".js-column.is-focused");
if (focusedColumn.length){
clearColumn(focusedColumn.attr("data-column"));
}
}
}
};
// add column buttons and keyboard shortcut info to UI
replaceMustache("column/column_header.mustache", "</header>", [
'{{^isTemporary}}',
'<a class="column-header-link" href="#" data-action="td-clearcolumns-dosingle" style="right:34px">',
'<i class="icon icon-clear-timeline"></i>',
'</a>',
'{{/isTemporary}}',
'</header>'
].join(""));
replaceMustache("keyboard_shortcut_list.mustache", "</dl> <dl", [
'<dd class="keyboard-shortcut-definition" style="white-space:nowrap">',
'<span class="text-like-keyboard-key">1</span> … <span class="text-like-keyboard-key">9</span> + <span class="text-like-keyboard-key">Del</span> Clear column 19',
'</dd><dd class="keyboard-shortcut-definition">',
'<span class="text-like-keyboard-key">Alt</span> + <span class="text-like-keyboard-key">Del</span> Clear all',
'</dd></dl><dl'
].join(""));
// load custom style
var style = document.createElement("style");
document.head.appendChild(style);
var sheet = style.sheet;
sheet.insertRule(".column-title { margin-right: 60px !important; }", 0);
sheet.insertRule(".column-type-message .column-title { margin-right: 115px !important; }", 0);
sheet.insertRule(".mark-all-read-link { right: 59px !important; }", 0);
sheet.insertRule(".open-compose-dm-link { right: 90px !important; }", 0);
}
ready(){
// setup events
$(document).on("click", "[data-action='td-clearcolumns-dosingle']", this.eventClearSingle);
$(document).on("click", "[data-action='td-clearcolumns-doall']", this.eventClearAll);
$(document).on("keydown", this.eventKeys);
// add clear all button
$("nav.app-navigator").first().append([
'<a class="link-clean cf app-nav-link padding-hl" data-title="Clear all" data-action="td-clearcolumns-doall">',
'<div class="obj-left"><i class="icon icon-large icon-clear-timeline"></i></div>',
'<div class="nbfc padding-ts hide-condensed">Clear all</div>',
'</a></nav>'
].join(""));
}
disabled(){
// not needed, plugin reloads the page when enabled or disabled
}

View File

@@ -12,4 +12,4 @@ chylex
1.0
[website]
http://tweetduck.chylex.com
https://tweetduck.chylex.com

View File

@@ -5,19 +5,19 @@ enabled(){
document.head.appendChild(style);
var sheet = style.sheet;
sheet.insertRule(".tweet-actions { float: right !important; width: auto !important; }",0);
sheet.insertRule(".tweet-action { opacity: 0; }",0);
sheet.insertRule(".is-favorite .tweet-action, .is-retweet .tweet-action { opacity: 0.5; visibility: visible !important; }",0);
sheet.insertRule(".tweet:hover .tweet-action, .is-favorite .tweet-action[rel='favorite'], .is-retweet .tweet-action[rel='retweet'] { opacity: 1; visibility: visible !important; }",0);
sheet.insertRule(".tweet-actions > li:nth-child(4) { margin-right: 2px !important; }",0);
sheet.insertRule(".tweet-actions { float: right !important; width: auto !important; }", 0);
sheet.insertRule(".tweet-action { opacity: 0; }", 0);
sheet.insertRule(".is-favorite .tweet-action, .is-retweet .tweet-action { opacity: 0.5; visibility: visible !important; }", 0);
sheet.insertRule(".tweet:hover .tweet-action, .is-favorite .tweet-action[rel='favorite'], .is-retweet .tweet-action[rel='retweet'] { opacity: 1; visibility: visible !important; }", 0);
sheet.insertRule(".tweet-actions > li:nth-child(4) { margin-right: 2px !important; }", 0);
// revert small links around the tweet
this.prevFooterMustache = TD.mustaches["status/tweet_single_footer.mustache"];
var footerLayout = TD.mustaches["status/tweet_single_footer.mustache"];
footerLayout = footerLayout.replace('txt-mute txt-size--12','txt-mute txt-small');
footerLayout = footerLayout.replace('{{#inReplyToID}}','{{^inReplyToID}} <a class="pull-left margin-txs txt-mute txt-small is-vishidden-narrow" href="#" rel="viewDetails">{{_i}}Details{{/i}}</a> <a class="pull-left margin-txs txt-mute txt-small is-vishidden is-visshown-narrow" href="#" rel="viewDetails">{{_i}}Open{{/i}}</a> {{/inReplyToID}} {{#inReplyToID}}');
footerLayout = footerLayout.replace('<span class="link-complex-target"> {{_i}}View Conversation{{/i}}','<i class="icon icon-conversation icon-small-context"></i> <span class="link-complex-target"> <span class="is-vishidden-wide is-vishidden-narrow">{{_i}}View{{/i}}</span> <span class="is-vishidden is-visshown-wide">{{_i}}Conversation{{/i}}</span>');
footerLayout = footerLayout.replace('txt-mute txt-size--12', 'txt-mute txt-small');
footerLayout = footerLayout.replace('{{#inReplyToID}}', '{{^inReplyToID}} <a class="pull-left margin-txs txt-mute txt-small is-vishidden-narrow" href="#" rel="viewDetails">{{_i}}Details{{/i}}</a> <a class="pull-left margin-txs txt-mute txt-small is-vishidden is-visshown-narrow" href="#" rel="viewDetails">{{_i}}Open{{/i}}</a> {{/inReplyToID}} {{#inReplyToID}}');
footerLayout = footerLayout.replace('<span class="link-complex-target"> {{_i}}View Conversation{{/i}}', '<i class="icon icon-conversation icon-small-context"></i> <span class="link-complex-target"> <span class="is-vishidden-wide is-vishidden-narrow">{{_i}}View{{/i}}</span> <span class="is-vishidden is-visshown-wide">{{_i}}Conversation{{/i}}</span>');
TD.mustaches["status/tweet_single_footer.mustache"] = footerLayout;
// fix layout for right-aligned actions menu
@@ -27,11 +27,11 @@ enabled(){
}
ready(){
$(document).on("uiShowActionsMenu",this.uiShowActionsMenuEvent);
$(document).on("uiShowActionsMenu", this.uiShowActionsMenuEvent);
}
disabled(){
$("#design-revert").remove();
$(document).off("uiShowActionsMenu",this.uiShowActionsMenuEvent);
$(document).off("uiShowActionsMenu", this.uiShowActionsMenuEvent);
TD.mustaches["status/tweet_single_footer.mustache"] = this.prevFooterMustache;
}

View File

@@ -0,0 +1,23 @@
[name]
Custom reply account
[description]
- Allows customizing the automatically selected reply account per column
[author]
chylex
[version]
1.0
[website]
https://tweetduck.chylex.com
[configfile]
configuration.js
[configdefault]
configuration.default.js
[requires]
1.3.3

View File

@@ -0,0 +1,67 @@
enabled(){
var configuration = { defaultAccount: "" };
window.TDPF_loadConfigurationFile(this, "configuration.js", "configuration.default.js", obj => configuration = obj);
this.uiInlineComposeTweetEvent = function(e, data){
var account = null;
if (configuration.useAdvancedSelector && configuration.customSelector){
var column = TD.controller.columnManager.get(data.element.closest("section.column").attr("data-column"));
var result = configuration.customSelector(column);
if (typeof result === "string" && result[0] === '@'){
account = result.substring(1);
}
}
if (account === null){
if (configuration.defaultAccount === false){
return;
}
else if (configuration.defaultAccount !== "" && configuration.defaultAccount[0] === '@'){
account = configuration.defaultAccount.substring(1);
}
}
var identifier;
if (account === null){
identifier = TD.storage.clientController.client.getDefaultAccount();
}
else{
var obj = TD.storage.accountController.getAccountFromUsername(account);
if (obj.length === 0){
return;
}
else{
identifier = obj[0].privateState.key;
}
}
data.singleFrom = data.from = [ identifier ];
};
}
ready(){
var events = $._data(document, "events");
if ("uiInlineComposeTweet" in events){
$(document).on("uiInlineComposeTweet", this.uiInlineComposeTweetEvent);
var handlers = events["uiInlineComposeTweet"];
var oldHandler = handlers[0];
var newHandler = handlers[1];
handlers[0] = newHandler;
handlers[1] = oldHandler;
}
else{
$(document).on("uiInlineComposeTweet", this.uiInlineComposeTweetEvent);
}
}
disabled(){
$(document).off("uiInlineComposeTweet", this.uiInlineComposeTweetEvent);
}

View File

@@ -0,0 +1,79 @@
{
/*
* WARNING
* -------
*
* Make sure you are editing 'configuration.js' and not the default configuration file, as the default one will be replaced with each update.
*
*/
/*
* Simple way of configuring the plugin
* ------------------------------------
*
* Set value of 'defaultAccount' to one of the following values:
*
* "" to use your preferred TweetDeck account for all replies (default)
* "@myAccount" to specify an account name to use; has to be one of your registered account names
* false to fall back to default TweetDeck behavior; useful for advanced configuration below, otherwise disable the plugin instead
*
*/
defaultAccount: "",
/*
* Advanced way of configuring the plugin
* --------------------------------------
*
* This assumes a basic knowledge of JavaScript and jQuery.
*
* 1. Set value of 'useAdvancedSelector' to true
* 2. Uncomment the 'customSelector' function, and replace the example code with your desired behavior
*
* If 'customSelector' returns a string containing a full name of one of the registered accounts (including @), that account is used.
* If it returns anything else (for example false, undefined, or an account name that is not registered), it falls back to 'defaultAccount' behavior.
*
* The 'column' parameter is a TweetDeck column object. If you want to see all properties of the object, open your browser, nagivate to TweetDeck,
* log in, and run the following code in your browser console, which will return an object containing all of the column objects mapped to their IDs:
* TD.controller.columnManager.getAll()
*
* The example below shows how to extract the column type, title, and account from the object.
* Column type is prefixed with col_, and may be one of the following:
*
* col_timeline, col_interactions, col_mentions, col_followers, col_search, col_list,
* col_customtimeline, col_messages, col_usertweets, col_favorites, col_activity,
* col_dataminr, col_home, col_me, col_inbox, col_scheduled, col_unknown
*
* Some of these appear to be unused (for example, Home columns are 'col_timeline' instead of 'col_home').
*
* If you want to see your column types, run this in your browser console:
* Object.values(TD.controller.columnManager.getAll()).forEach(obj => console.log(obj.getColumnType()));
*
* You can also get the jQuery column object using: $("section.column[data-column='"+column.ui.state.columnKey+"']")
*
*/
useAdvancedSelector: false,
/*customSelector: function(column){
var titleObj = $(column.getTitleHTML());
var columnType = column.getColumnType(); // col_timeline
var columnTitle = titleObj.siblings(".column-head-title").text(); // Home
var columnAccount = titleObj.siblings(".attribution").text(); // @chylexmc
if (columnType === "col_search" && columnTitle === "TweetDuck"){
// This is a search column that looks for 'TweetDuck' in the tweets,
// search columns are normally linked to the preferred account
// so this forces the @TryTweetDuck account to be used instead.
return "@TryTweetDuck";
}
else if (columnType === "col_timeline" && columnAccount === "@chylexcz"){
// This is a Home column of my test account @chylexcz,
// but I want to reply to tweets from my official account.
return "@chylexmc";
}
// otherwise returns 'undefined' which falls back to 'defaultAccount' behavior
}*/
}

View File

@@ -11,33 +11,33 @@ namespace TweetDck.Resources{
public static string LoadResource(string name){
try{
return File.ReadAllText(Path.Combine(AppDomain.CurrentDomain.BaseDirectory,name),Encoding.UTF8);
return File.ReadAllText(Path.Combine(Program.ScriptPath, name), Encoding.UTF8);
}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;
}
}
public static void ExecuteFile(ChromiumWebBrowser browser, string file){
ExecuteScript(browser,LoadResource(file),GetRootIdentifier(file));
ExecuteScript(browser, LoadResource(file), GetRootIdentifier(file));
}
public static void ExecuteFile(IFrame frame, string file){
ExecuteScript(frame,LoadResource(file),GetRootIdentifier(file));
ExecuteScript(frame, LoadResource(file), GetRootIdentifier(file));
}
public static void ExecuteScript(ChromiumWebBrowser browser, string script, string identifier){
if (script == null)return;
using(IFrame frame = browser.GetMainFrame()){
frame.ExecuteJavaScriptAsync(script,UrlPrefix+identifier,1);
frame.ExecuteJavaScriptAsync(script, UrlPrefix+identifier, 1);
}
}
public static void ExecuteScript(IFrame frame, string script, string identifier){
if (script == null)return;
frame.ExecuteJavaScriptAsync(script,UrlPrefix+identifier,1);
frame.ExecuteJavaScriptAsync(script, UrlPrefix+identifier, 1);
}
public static string GetRootIdentifier(string file){

View File

@@ -1,4 +1,4 @@
(function($,$TD,TD){
(function($, $TD, TD){
//
// Variable: Current highlighted column jQuery object.
//
@@ -27,7 +27,7 @@
var buttons = menu.children("[data-std]");
buttons.on("click","a",function(){
buttons.on("click", "a", function(){
var action = $(this).attr("data-action");
if (action === "td-settings"){
@@ -40,16 +40,16 @@
buttons.hover(function(){
$(this).addClass("is-selected");
},function(){
}, function(){
$(this).removeClass("is-selected");
});
},0);
}, 0);
});
// Notification handling
$.subscribe("/notifications/new",function(obj){
$.subscribe("/notifications/new", function(obj){
for(let index = obj.items.length-1; index >= 0; index--){
onNewTweet(obj.column,obj.items[index]);
onNewTweet(obj.column, obj.items[index]);
}
});
@@ -59,8 +59,8 @@
$(this).parent().replaceWith("<a href='"+$(this).attr("src")+"' rel='url' target='_blank' style='display:block; border:1px solid #555; padding:3px 6px'>&#9658; Open video in browser</a>");
});
$("a[rel='user']").attr("target","_blank");
}).observe($(".js-app-columns")[0],{
$("a[rel='user']").attr("target", "_blank");
}).observe($(".js-app-columns")[0], {
childList: true,
subtree: true
});
@@ -81,7 +81,7 @@
//
var prependToFunction = function(func, extension){
return function(){
return extension.apply(this,arguments) === true ? undefined : func.apply(this,arguments);
return extension.apply(this, arguments) === true ? undefined : func.apply(this, arguments);
};
};
@@ -90,8 +90,8 @@
//
var appendToFunction = function(func, extension){
return function(){
var res = func.apply(this,arguments);
extension.apply(this,arguments);
var res = func.apply(this, arguments);
extension.apply(this, arguments);
return res;
};
};
@@ -107,12 +107,12 @@
withMediaPreview: false
}));
html.css("border","0");
html.css("border", "0");
html.find(".tweet-body").first().children("footer").remove();
var url = html.find("time").first().children("a").first().attr("href") || "";
$TD.onTweetPopup(html.html(),url,tweet.text.length); // TODO column
$TD.onTweetPopup(html.html(), url, tweet.text.length); // TODO column
}
else if (column.model.getHasSound()){
$TD.onTweetSound(); // TODO disable original
@@ -144,7 +144,7 @@
else if (!window.TD_APP_READY && !app.hasClass("is-hidden")){
initializeTweetDck();
}
}).observe(app[0],{
}).observe(app[0], {
attributes: true,
attributeFilter: [ "class" ]
});
@@ -152,14 +152,14 @@
//
// Block: Hook into settings object to detect when the settings change.
//
TD.settings.setFontSize = appendToFunction(TD.settings.setFontSize,function(name){
TD.settings.setFontSize = appendToFunction(TD.settings.setFontSize, function(name){
$TD.loadFontSizeClass(name);
});
TD.settings.setTheme = appendToFunction(TD.settings.setTheme,function(){
TD.settings.setTheme = appendToFunction(TD.settings.setTheme, function(){
setTimeout(function(){
$TD.loadNotificationHeadContents(getNotificationHeadContents());
},0);
}, 0);
});
//
@@ -184,7 +184,7 @@
var prevMouseX = -1, prevMouseY = -1;
var tooltipTimer, tooltipDisplayed;
$(document.body).delegate("a[data-full-url]","mouseenter mouseleave mousemove",function(e){
$(document.body).delegate("a[data-full-url]", "mouseenter mouseleave mousemove", function(e){
var me = $(this);
if (e.type === "mouseenter"){
@@ -197,19 +197,19 @@
if ($TD.expandLinksOnHover){
tooltipTimer = window.setTimeout(function(){
var expanded = me.attr("data-full-url");
expanded = cutStart(expanded,"https://");
expanded = cutStart(expanded,"http://");
expanded = cutStart(expanded,"www.");
expanded = cutStart(expanded, "https://");
expanded = cutStart(expanded, "http://");
expanded = cutStart(expanded, "www.");
me.attr("td-prev-text",text);
me.attr("td-prev-text", text);
me.text(expanded);
},200);
}, 200);
}
else{
tooltipTimer = window.setTimeout(function(){
$TD.displayTooltip(me.attr("data-full-url"),false);
$TD.displayTooltip(me.attr("data-full-url"), false);
tooltipDisplayed = true;
},400);
}, 400);
}
}
else if (e.type === "mouseleave"){
@@ -225,12 +225,12 @@
if (tooltipDisplayed){
tooltipDisplayed = false;
$TD.displayTooltip(null,false);
$TD.displayTooltip(null, false);
}
}
else if (e.type === "mousemove"){
if (tooltipDisplayed && (prevMouseX !== e.clientX || prevMouseY !== e.clientY)){
$TD.displayTooltip(me.attr("data-full-url"),false);
$TD.displayTooltip(me.attr("data-full-url"), false);
prevMouseX = e.clientX;
prevMouseY = e.clientY;
}
@@ -241,7 +241,7 @@
//
// Block: Allow bypassing of t.co in context menus.
//
$(document.body).delegate("a","contextmenu",function(){
$(document.body).delegate("a", "contextmenu", function(){
$TD.setLastRightClickedLink($(this).attr("data-full-url") || "");
});
@@ -251,7 +251,7 @@
(function(){
var soundEle = document.getElementById("update-sound");
soundEle.play = prependToFunction(soundEle.play,function(){
soundEle.play = prependToFunction(soundEle.play, function(){
return $TD.muteNotifications;
});
})();
@@ -263,7 +263,7 @@
//
// Block: Update highlighted column.
//
app.delegate("section","mouseenter mouseleave",function(e){
app.delegate("section", "mouseenter mouseleave", function(e){
if (e.type === "mouseenter"){
highlightedColumnEle = $(this);
}
@@ -280,23 +280,23 @@
var updateHighlightedTweet = function(link, embeddedLink){
if (lastTweet !== link){
$TD.setLastHighlightedTweet(link,embeddedLink);
$TD.setLastHighlightedTweet(link, embeddedLink);
lastTweet = link;
}
};
app.delegate("article.js-stream-item","mouseenter mouseleave",function(e){
app.delegate("article.js-stream-item", "mouseenter mouseleave", function(e){
if (e.type === "mouseenter"){
highlightedTweetEle = $(this);
var link = $(this).find("time").first().children("a").first();
var embedded = $(this).find(".quoted-tweet[data-tweet-id]").first();
updateHighlightedTweet(link.length > 0 ? link.attr("href") : "",embedded.length > 0 ? embedded.find(".account-link").first().attr("href")+"/status/"+embedded.attr("data-tweet-id") : "");
updateHighlightedTweet(link.length > 0 ? link.attr("href") : "", embedded.length > 0 ? embedded.find(".account-link").first().attr("href")+"/status/"+embedded.attr("data-tweet-id") : "");
}
else if (e.type === "mouseleave"){
highlightedTweetEle = null;
updateHighlightedTweet("","");
updateHighlightedTweet("", "");
}
});
})();
@@ -322,10 +322,10 @@
scroller.scrollTop(button.offset().top); // scrolls the button into view
var buttonPos = button.children().first().offset(); // finds the camera icon offset
$TD.clickUploadImage(Math.floor(buttonPos.left),Math.floor(buttonPos.top));
$TD.clickUploadImage(Math.floor(buttonPos.left), Math.floor(buttonPos.top));
};
$(".js-app").delegate(".js-compose-text,.js-reply-tweetbox","paste",function(){
$(".js-app").delegate(".js-compose-text,.js-reply-tweetbox", "paste", function(){
lastPasteElement = $(this);
$TD.tryPasteImage();
});
@@ -355,7 +355,7 @@
else if (++counter >= 10){
clearInterval(interval);
}
},51);
}, 51);
}
else{
clickUpload();
@@ -369,7 +369,7 @@
setTimeout(function(){
getScroller().scrollTop(prevScrollTop);
$(".js-drawer").find(".js-compose-text").first()[0].focus();
},10);
}, 10);
};
})();
@@ -397,6 +397,21 @@
}
};
//
// Block: Fix scheduled tweets not showing up sometimes.
//
$(document).on("dataTweetSent", function(e, data){
if (data.response.state && data.response.state === "scheduled"){
var column = Object.values(TD.controller.columnManager.getAll()).find(column => column.model.state.type === "scheduled");
if (column){
setTimeout(function(){
column.reloadTweets();
}, 1000);
}
}
});
//
// Block: Inject custom CSS and layout into the page.
//
@@ -404,9 +419,10 @@
var styleOfficial = document.createElement("style");
document.head.appendChild(styleOfficial);
styleOfficial.sheet.insertRule("a[data-full-url] { word-break: break-all; }",0); // break long urls
styleOfficial.sheet.insertRule(".column-nav-link .attribution { position: absolute; }",0); // fix cut off account names
styleOfficial.sheet.insertRule(".txt-base-smallest .badge-verified:before { height: 13px !important; }",0); // fix cut off badge icon
styleOfficial.sheet.insertRule("a[data-full-url] { word-break: break-all; }", 0); // break long urls
styleOfficial.sheet.insertRule(".column-nav-link .attribution { position: absolute; }", 0); // fix cut off account names
styleOfficial.sheet.insertRule(".txt-base-smallest .badge-verified:before { height: 13px !important; }", 0); // fix cut off badge icon
styleOfficial.sheet.insertRule(".keyboard-shortcut-list { vertical-align: top; }", 0); // fix keyboard navigation alignment
if ($TD.hasCustomBrowserCSS){
var styleCustom = document.createElement("style");
@@ -414,4 +430,4 @@
document.head.appendChild(styleCustom);
}
})();
})($,$TD,TD);
})($, $TD, TD);

View File

@@ -9,14 +9,14 @@
//
var addEventListener = function(collection, type, listener){
for(let index = 0; index < collection.length; index++){
collection[index].addEventListener(type,listener);
collection[index].addEventListener(type, listener);
}
};
//
// Block: Hook into links to bypass default open function.
//
addEventListener(links,"click",function(e){
addEventListener(links, "click", function(e){
$TD.openBrowser(e.currentTarget.getAttribute("href"));
e.preventDefault();
});
@@ -24,7 +24,7 @@
//
// Block: Allow bypassing of t.co in context menus.
//
addEventListener(links,"contextmenu",function(e){
addEventListener(links, "contextmenu", function(e){
$TD.setLastRightClickedLink(e.currentTarget.getAttribute("data-full-url") || "");
});
@@ -39,7 +39,7 @@
var prevMouseX = -1, prevMouseY = -1;
var tooltipTimer, tooltipDisplayed;
addEventListener(links,"mouseenter",function(e){
addEventListener(links, "mouseenter", function(e){
var me = e.currentTarget;
var url = me.getAttribute("data-full-url");
@@ -54,23 +54,23 @@
if ($TD.expandLinksOnHover){
tooltipTimer = window.setTimeout(function(){
var expanded = url;
expanded = cutStart(expanded,"https://");
expanded = cutStart(expanded,"http://");
expanded = cutStart(expanded,"www.");
expanded = cutStart(expanded, "https://");
expanded = cutStart(expanded, "http://");
expanded = cutStart(expanded, "www.");
me.setAttribute("td-prev-text",text);
me.setAttribute("td-prev-text", text);
me.innerHTML = expanded;
},200);
}, 200);
}
else{
tooltipTimer = window.setTimeout(function(){
$TD.displayTooltip(url,true);
$TD.displayTooltip(url, true);
tooltipDisplayed = true;
},400);
}, 400);
}
});
addEventListener(links,"mouseleave",function(e){
addEventListener(links, "mouseleave", function(e){
if (!e.currentTarget.hasAttribute("data-full-url"))return;
if ($TD.expandLinksOnHover){
@@ -85,16 +85,16 @@
if (tooltipDisplayed){
tooltipDisplayed = false;
$TD.displayTooltip(null,true);
$TD.displayTooltip(null, true);
}
});
addEventListener(links,"mousemove",function(e){
addEventListener(links, "mousemove", function(e){
if (tooltipDisplayed && (prevMouseX !== e.clientX || prevMouseY !== e.clientY)){
var url = e.currentTarget.getAttribute("data-full-url");
if (!url)return;
$TD.displayTooltip(url,true);
$TD.displayTooltip(url, true);
prevMouseX = e.clientX;
prevMouseY = e.clientY;
}

View File

@@ -50,7 +50,7 @@
setState(plugin, enable){
if (enable && this.isDisabled(plugin)){
this.disabled.splice(this.disabled.indexOf(plugin.id),1);
this.disabled.splice(this.disabled.indexOf(plugin.id), 1);
plugin.obj.enabled();
this.runWhenReady(plugin);
}
@@ -75,6 +75,6 @@
// Block: Setup global function to change plugin state.
//
window.TDPF_setPluginState = function(identifier, enable){
window.TD_PLUGINS.setState(window.TD_PLUGINS.findObject(identifier),enable);
window.TD_PLUGINS.setState(window.TD_PLUGINS.findObject(identifier), enable);
};
})();

View File

@@ -0,0 +1,37 @@
(function($TDP){
//
// Block: Setup a simple JavaScript object configuration loader.
//
window.TDPF_loadConfigurationFile = function(pluginObject, fileNameUser, fileNameDefault, onSuccess, onFailure){
var identifier = pluginObject.$id;
var token = pluginObject.$token;
$TDP.checkFileExists(token, fileNameUser).then(exists => {
var fileName = exists ? fileNameUser : fileNameDefault;
$TDP.readFile(token, fileName, true).then(contents => {
var obj;
try{
obj = eval("("+contents+")");
}catch(err){
if (!(onFailure && onFailure(err.message))){
$TD.alert("warning", "Problem loading '"+fileName+"' file for '"+identifier+"' plugin, the JavaScript syntax is invalid: "+err.message);
}
return;
}
onSuccess && onSuccess(obj);
}).catch(err => {
if (!(onFailure && onFailure(err))){
$TD.alert("warning", "Problem loading '"+fileName+"' file for '"+identifier+"' plugin: "+err.message);
}
});
}).catch(err => {
if (!(onFailure && onFailure(err))){
$TD.alert("warning", "Problem checking '"+fileNameUser+"' file for '"+identifier+"' plugin: "+err.message);
}
});
};
})($TDP);

View File

@@ -1,4 +1,4 @@
(function($,$TDU){
(function($, $TDU){
//
// Variable: Current timeout ID for update checking.
//
@@ -18,6 +18,9 @@
// Function: Creates the update notification element. Removes the old one if already exists.
//
var createUpdateNotificationElement = function(version, download){
var outdated = version === "unsupported";
var tweetdick = version === "tweetdick";
var ele = $("#tweetdck-update");
var existed = ele.length > 0;
@@ -25,13 +28,31 @@
ele.remove();
}
var html = [
var html = outdated ? [
"<div id='tweetdck-update'>",
"<p class='tdu-title'>Unsupported System</p>",
"<p class='tdu-info'>You will not receive updates.</p>",
"<div class='tdu-buttons'>",
"<button class='btn btn-positive tdu-btn-unsupported'><span class='label'>Read More</span></button>",
"<button class='btn btn-negative tdu-btn-dismiss'><span class='label'>Dismiss</span></button>",
"</div>",
"</div>"
] : tweetdick ? [
"<div id='tweetdck-update'>",
"<p class='tdu-title'>TweetDick Ending</p>",
"<p class='tdu-info'>Please, move to TweetDuck.</p>",
"<div class='tdu-buttons'>",
"<button class='btn btn-positive tdu-btn-unsupported'><span class='label'>Read More</span></button>",
"<button class='btn btn-negative tdu-btn-dismiss'><span class='label'>Dismiss</span></button>",
"</div>",
"</div>"
] : [
"<div id='tweetdck-update'>",
"<p class='tdu-title'>"+$TDU.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>",
"<button class='btn btn-positive tdu-btn-download'><span class='label'>Download</span></button>",
"<button class='btn btn-negative tdu-btn-dismiss'><span class='label'>Dismiss</span></button>",
"</div>",
"</div>"
];
@@ -60,7 +81,7 @@
fontWeight: "bold",
textAlign: "center",
letterSpacing: "0.2px",
margin: "4px auto 2px"
margin: "5px auto 2px"
});
ele.children("p.tdu-info").first().css({
@@ -90,10 +111,18 @@
buttonDiv.children(".tdu-btn-download").click(function(){
ele.remove();
$TDU.onUpdateAccepted(version,download);
$TDU.onUpdateAccepted(version, download);
});
buttonDiv.children(".tdu-btn-dismiss").click(function(){
buttonDiv.children(".tdu-btn-unsupported").click(function(){
$TDU.openBrowser("https://github.com/chylex/TweetDuck/wiki/Supported-Systems");
});
buttonDiv.children(".tdu-btn-tweetdick").click(function(){
$TDU.openBrowser("https://github.com/chylex/TweetDick/wiki/Future-of-TweetDick");
});
buttonDiv.children(".tdu-btn-dismiss,.tdu-btn-unsupported").click(function(){
$TDU.onUpdateDismissed(version);
ele.slideUp(function(){ ele.remove(); });
});
@@ -109,22 +138,37 @@
// Function: Runs an update check and updates all DOM elements appropriately.
//
var runUpdateCheck = function(force, eventID){
if (!$TDU.isSystemSupported){
if ($TDU.dismissedVersionTag !== "unsupported"){
createUpdateNotificationElement("unsupported");
}
return;
}
else if ($TDU.brandName === "TweetDick"){
if ($TDU.dismissedVersionTag !== "tweetdick"){
createUpdateNotificationElement("tweetdick");
}
return;
}
clearTimeout(updateCheckTimeoutID);
updateCheckTimeoutID = setTimeout(runUpdateCheck,1000*60*60); // 1 hour
updateCheckTimeoutID = setTimeout(runUpdateCheck, 1000*60*60); // 1 hour
if (!$TDU.updateCheckEnabled && !force)return;
$.getJSON(updateCheckUrl,function(response){
$.getJSON(updateCheckUrl, function(response){
var tagName = response.tag_name;
var hasUpdate = tagName !== $TDU.versionTag && tagName !== $TDU.dismissedVersionTag && response.assets.length > 0;
if (hasUpdate){
var obj = response.assets.find(asset => asset.name === updateFileName) || response.assets[0];
createUpdateNotificationElement(tagName,obj.browser_download_url);
createUpdateNotificationElement(tagName, obj.browser_download_url);
}
if (eventID !== 0){
$TDU.onUpdateCheckFinished(eventID,hasUpdate,tagName);
$TDU.onUpdateCheckFinished(eventID, hasUpdate, tagName);
}
});
};
@@ -134,4 +178,4 @@
//
window.TDUF_runUpdateCheck = runUpdateCheck;
runUpdateCheck();
})($,$TDU);
})($, $TDU);

View File

@@ -1,5 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="12.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Import Project="packages\CefSharp.WinForms.53.0.0-pre01\build\CefSharp.WinForms.props" Condition="Exists('packages\CefSharp.WinForms.53.0.0-pre01\build\CefSharp.WinForms.props')" />
<Import Project="packages\CefSharp.Common.53.0.0-pre01\build\CefSharp.Common.props" Condition="Exists('packages\CefSharp.Common.53.0.0-pre01\build\CefSharp.Common.props')" />
<Import Project="packages\CefSharp.WinForms.49.0.0-pre02\build\CefSharp.WinForms.props" Condition="Exists('packages\CefSharp.WinForms.49.0.0-pre02\build\CefSharp.WinForms.props')" />
<Import Project="packages\CefSharp.Common.49.0.0-pre02\build\CefSharp.Common.props" Condition="Exists('packages\CefSharp.Common.49.0.0-pre02\build\CefSharp.Common.props')" />
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
@@ -11,12 +13,12 @@
<AppDesignerFolder>Properties</AppDesignerFolder>
<RootNamespace>TweetDck</RootNamespace>
<AssemblyName Condition=" '$(Configuration)' == 'Debug' ">TweetDick</AssemblyName>
<AssemblyName Condition=" '$(Configuration)' == 'Release Dick' ">TweetDick</AssemblyName>
<AssemblyName Condition=" '$(Configuration)' == 'Release Duck' ">TweetDuck</AssemblyName>
<TargetFrameworkVersion>v4.0</TargetFrameworkVersion>
<AssemblyName Condition=" '$(Configuration)' == 'Release' ">TweetDuck</AssemblyName>
<TargetFrameworkVersion>v4.5.2</TargetFrameworkVersion>
<FileAlignment>512</FileAlignment>
<NuGetPackageImportStamp>ff8ce4f3</NuGetPackageImportStamp>
<TargetFrameworkProfile>Client</TargetFrameworkProfile>
<NuGetPackageImportStamp>e83161d1</NuGetPackageImportStamp>
<TargetFrameworkProfile>
</TargetFrameworkProfile>
<PublishUrl>publish\</PublishUrl>
<Install>true</Install>
<InstallFrom>Disk</InstallFrom>
@@ -41,24 +43,13 @@
<PlatformTarget>x86</PlatformTarget>
<ErrorReport>prompt</ErrorReport>
<CodeAnalysisRuleSet>AllRules.ruleset</CodeAnalysisRuleSet>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release Dick|x86' ">
<OutputPath>bin\x86\Release Dick\</OutputPath>
<DefineConstants>
</DefineConstants>
<Optimize>true</Optimize>
<DebugType>none</DebugType>
<PlatformTarget>x86</PlatformTarget>
<ErrorReport>prompt</ErrorReport>
<CodeAnalysisRuleSet>MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet>
<GenerateSerializationAssemblies>Off</GenerateSerializationAssemblies>
<UseVSHostingProcess>false</UseVSHostingProcess>
<Prefer32Bit>false</Prefer32Bit>
</PropertyGroup>
<PropertyGroup>
<ApplicationIcon>Resources\icon.ico</ApplicationIcon>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release Duck|x86' ">
<OutputPath>bin\x86\Release Duck\</OutputPath>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|x86' ">
<OutputPath>bin\x86\Release\</OutputPath>
<Optimize>true</Optimize>
<PlatformTarget>x86</PlatformTarget>
<UseVSHostingProcess>false</UseVSHostingProcess>
@@ -66,7 +57,12 @@
<UseVSHostingProcess>false</UseVSHostingProcess>
<ErrorReport>prompt</ErrorReport>
<CodeAnalysisRuleSet>MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet>
<DefineConstants>DUCK</DefineConstants>
<DefineConstants>
</DefineConstants>
<Prefer32Bit>false</Prefer32Bit>
</PropertyGroup>
<PropertyGroup>
<AssemblyName>TweetDuck</AssemblyName>
</PropertyGroup>
<ItemGroup>
<Reference Include="System" />
@@ -99,6 +95,7 @@
<Compile Include="Core\Controls\TabPanel.Designer.cs">
<DependentUpon>TabPanel.cs</DependentUpon>
</Compile>
<Compile Include="Core\Handling\BrowserProcessHandler.cs" />
<Compile Include="Core\Handling\ContextMenuBase.cs" />
<Compile Include="Core\Handling\ContextMenuBrowser.cs" />
<Compile Include="Core\FormBrowser.cs">
@@ -123,6 +120,12 @@
<Compile Include="Core\Other\FormAbout.Designer.cs">
<DependentUpon>FormAbout.cs</DependentUpon>
</Compile>
<Compile Include="Core\Other\FormMessage.cs">
<SubType>Form</SubType>
</Compile>
<Compile Include="Core\Other\FormMessage.Designer.cs">
<DependentUpon>FormMessage.cs</DependentUpon>
</Compile>
<Compile Include="Core\Other\FormPlugins.cs">
<SubType>Form</SubType>
</Compile>
@@ -175,6 +178,7 @@
</Compile>
<Compile Include="Core\Utils\CommandLineArgsParser.cs" />
<Compile Include="Core\Utils\WindowState.cs" />
<Compile Include="Core\Utils\WindowsUtils.cs" />
<Compile Include="Migration\FormBackgroundWork.cs">
<SubType>Form</SubType>
</Compile>
@@ -209,6 +213,7 @@
<Compile Include="Plugins\Events\PluginLoadEventArgs.cs" />
<Compile Include="Plugins\PluginManager.cs" />
<Compile Include="Plugins\PluginScriptGenerator.cs" />
<Compile Include="Reporter.cs" />
<Compile Include="Updates\FormUpdateDownload.cs">
<SubType>Form</SubType>
</Compile>
@@ -235,7 +240,6 @@
<Compile Include="Migration\FormMigrationQuestion.Designer.cs">
<DependentUpon>FormMigrationQuestion.cs</DependentUpon>
</Compile>
<Compile Include="Migration\Helpers\LnkEditor.cs" />
<Compile Include="Migration\MigrationDecision.cs" />
<Compile Include="Migration\MigrationManager.cs" />
<Compile Include="Migration\Helpers\ProgramRegistrySearch.cs" />
@@ -272,17 +276,6 @@
<Install>true</Install>
</BootstrapperPackage>
</ItemGroup>
<ItemGroup>
<COMReference Include="Shell32">
<Guid>{50A7E9B0-70EF-11D1-B75A-00A0C90564FE}</Guid>
<VersionMajor>1</VersionMajor>
<VersionMinor>0</VersionMinor>
<Lcid>0</Lcid>
<WrapperTool>tlbimp</WrapperTool>
<Isolated>False</Isolated>
<EmbedInteropTypes>True</EmbedInteropTypes>
</COMReference>
</ItemGroup>
<ItemGroup>
<EmbeddedResource Include="Core\FormBrowser.resx">
<DependentUpon>FormBrowser.cs</DependentUpon>
@@ -310,36 +303,6 @@
<TargetPath>icon.ico</TargetPath>
</ContentWithTargetPath>
</ItemGroup>
<ItemGroup>
<ContentWithTargetPath Include="Resources\Scripts\code.js">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
<TargetPath>code.js</TargetPath>
</ContentWithTargetPath>
</ItemGroup>
<ItemGroup>
<ContentWithTargetPath Include="Resources\Scripts\notification.js">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
<TargetPath>notification.js</TargetPath>
</ContentWithTargetPath>
</ItemGroup>
<ItemGroup>
<ContentWithTargetPath Include="Resources\Scripts\plugins.browser.js">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
<TargetPath>plugins.browser.js</TargetPath>
</ContentWithTargetPath>
</ItemGroup>
<ItemGroup>
<ContentWithTargetPath Include="Resources\Scripts\plugins.notification.js">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
<TargetPath>plugins.notification.js</TargetPath>
</ContentWithTargetPath>
</ItemGroup>
<ItemGroup>
<ContentWithTargetPath Include="Resources\Scripts\update.js">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
<TargetPath>update.js</TargetPath>
</ContentWithTargetPath>
</ItemGroup>
<ItemGroup>
<None Include="Resources\icon-small.ico" />
<None Include="Resources\icon-tray-new.ico" />
@@ -347,21 +310,20 @@
</ItemGroup>
<ItemGroup>
<Folder Include="Resources\Plugins\" />
<Folder Include="Resources\Scripts\" />
</ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
<Target Name="EnsureNuGetPackageBuildImports" BeforeTargets="PrepareForBuild">
<PropertyGroup>
<ErrorText>This project references NuGet package(s) that are missing on this computer. Enable NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}.</ErrorText>
</PropertyGroup>
<Error Condition="!Exists('packages\cef.redist.x86.3.2623.1396\build\cef.redist.x86.targets')" Text="$([System.String]::Format('$(ErrorText)', 'packages\cef.redist.x86.3.2623.1396\build\cef.redist.x86.targets'))" />
<Error Condition="!Exists('packages\cef.redist.x64.3.2623.1396\build\cef.redist.x64.targets')" Text="$([System.String]::Format('$(ErrorText)', 'packages\cef.redist.x64.3.2623.1396\build\cef.redist.x64.targets'))" />
<Error Condition="!Exists('packages\CefSharp.Common.49.0.0-pre02\build\CefSharp.Common.props')" Text="$([System.String]::Format('$(ErrorText)', 'packages\CefSharp.Common.49.0.0-pre02\build\CefSharp.Common.props'))" />
<Error Condition="!Exists('packages\CefSharp.Common.49.0.0-pre02\build\CefSharp.Common.targets')" Text="$([System.String]::Format('$(ErrorText)', 'packages\CefSharp.Common.49.0.0-pre02\build\CefSharp.Common.targets'))" />
<Error Condition="!Exists('packages\CefSharp.WinForms.49.0.0-pre02\build\CefSharp.WinForms.props')" Text="$([System.String]::Format('$(ErrorText)', 'packages\CefSharp.WinForms.49.0.0-pre02\build\CefSharp.WinForms.props'))" />
<Error Condition="!Exists('packages\cef.redist.x86.3.2785.1478\build\cef.redist.x86.targets')" Text="$([System.String]::Format('$(ErrorText)', 'packages\cef.redist.x86.3.2785.1478\build\cef.redist.x86.targets'))" />
<Error Condition="!Exists('packages\cef.redist.x64.3.2785.1478\build\cef.redist.x64.targets')" Text="$([System.String]::Format('$(ErrorText)', 'packages\cef.redist.x64.3.2785.1478\build\cef.redist.x64.targets'))" />
<Error Condition="!Exists('packages\CefSharp.Common.53.0.0-pre01\build\CefSharp.Common.props')" Text="$([System.String]::Format('$(ErrorText)', 'packages\CefSharp.Common.53.0.0-pre01\build\CefSharp.Common.props'))" />
<Error Condition="!Exists('packages\CefSharp.Common.53.0.0-pre01\build\CefSharp.Common.targets')" Text="$([System.String]::Format('$(ErrorText)', 'packages\CefSharp.Common.53.0.0-pre01\build\CefSharp.Common.targets'))" />
<Error Condition="!Exists('packages\CefSharp.WinForms.53.0.0-pre01\build\CefSharp.WinForms.props')" Text="$([System.String]::Format('$(ErrorText)', 'packages\CefSharp.WinForms.53.0.0-pre01\build\CefSharp.WinForms.props'))" />
<Error Condition="!Exists('packages\CefSharp.WinForms.53.0.0-pre01\build\CefSharp.WinForms.targets')" Text="$([System.String]::Format('$(ErrorText)', 'packages\CefSharp.WinForms.53.0.0-pre01\build\CefSharp.WinForms.targets'))" />
</Target>
<Import Project="packages\cef.redist.x86.3.2623.1396\build\cef.redist.x86.targets" Condition="Exists('packages\cef.redist.x86.3.2623.1396\build\cef.redist.x86.targets')" />
<Import Project="packages\cef.redist.x64.3.2623.1396\build\cef.redist.x64.targets" Condition="Exists('packages\cef.redist.x64.3.2623.1396\build\cef.redist.x64.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>
<PostBuildEvent>del "$(TargetPath).config"
xcopy "$(ProjectDir)LICENSE.md" "$(TargetDir)" /Y
@@ -370,6 +332,10 @@ ren "$(TargetDir)LICENSE.md" "LICENSE.txt"
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
rmdir "$(TargetDir)scripts"
mkdir "$(TargetDir)scripts"
xcopy "$(ProjectDir)Resources\Scripts\*" "$(TargetDir)scripts\" /E /Y
rmdir "$(TargetDir)plugins"
mkdir "$(TargetDir)plugins"
mkdir "$(TargetDir)plugins\official"
mkdir "$(TargetDir)plugins\user"
@@ -377,6 +343,10 @@ xcopy "$(ProjectDir)Resources\Plugins\*" "$(TargetDir)plugins\official\" /E /Y
rmdir "$(ProjectDir)\bin\Debug"
rmdir "$(ProjectDir)\bin\Release"</PostBuildEvent>
</PropertyGroup>
<Import Project="packages\cef.redist.x86.3.2785.1478\build\cef.redist.x86.targets" Condition="Exists('packages\cef.redist.x86.3.2785.1478\build\cef.redist.x86.targets')" />
<Import Project="packages\cef.redist.x64.3.2785.1478\build\cef.redist.x64.targets" Condition="Exists('packages\cef.redist.x64.3.2785.1478\build\cef.redist.x64.targets')" />
<Import Project="packages\CefSharp.Common.53.0.0-pre01\build\CefSharp.Common.targets" Condition="Exists('packages\CefSharp.Common.53.0.0-pre01\build\CefSharp.Common.targets')" />
<Import Project="packages\CefSharp.WinForms.53.0.0-pre01\build\CefSharp.WinForms.targets" Condition="Exists('packages\CefSharp.WinForms.53.0.0-pre01\build\CefSharp.WinForms.targets')" />
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
Other similar extension points exist, see Microsoft.Common.targets.
<Target Name="BeforeBuild">

View File

@@ -1,4 +1,4 @@

Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio 2013
VisualStudioVersion = 12.0.40629.0
@@ -8,17 +8,14 @@ EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|x86 = Debug|x86
Release Dick|x86 = Release Dick|x86
Release Duck|x86 = Release Duck|x86
Release|x86 = Release|x86
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{2389A7CD-E0D3-4706-8294-092929A33A2D}.Debug|x86.ActiveCfg = Debug|x86
{2389A7CD-E0D3-4706-8294-092929A33A2D}.Debug|x86.Build.0 = Debug|x86
{2389A7CD-E0D3-4706-8294-092929A33A2D}.Debug|x86.Deploy.0 = Debug|x86
{2389A7CD-E0D3-4706-8294-092929A33A2D}.Release Dick|x86.ActiveCfg = Release Dick|x86
{2389A7CD-E0D3-4706-8294-092929A33A2D}.Release Dick|x86.Build.0 = Release Dick|x86
{2389A7CD-E0D3-4706-8294-092929A33A2D}.Release Duck|x86.ActiveCfg = Release Duck|x86
{2389A7CD-E0D3-4706-8294-092929A33A2D}.Release Duck|x86.Build.0 = Release Duck|x86
{2389A7CD-E0D3-4706-8294-092929A33A2D}.Release|x86.ActiveCfg = Release|x86
{2389A7CD-E0D3-4706-8294-092929A33A2D}.Release|x86.Build.0 = Release|x86
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE

View File

@@ -13,7 +13,7 @@ namespace TweetDck.Updates{
public string InstallerPath{
get{
return Path.Combine(Path.GetTempPath(),updateInfo.FileName);
return Path.Combine(Path.GetTempPath(), updateInfo.FileName);
}
}
@@ -45,7 +45,7 @@ namespace TweetDck.Updates{
}
private void FormUpdateDownload_Shown(object sender, EventArgs e){
webClient.DownloadFileAsync(new Uri(updateInfo.DownloadUrl),InstallerPath);
webClient.DownloadFileAsync(new Uri(updateInfo.DownloadUrl), InstallerPath);
}
private void btnCancel_Click(object sender, EventArgs e){
@@ -69,7 +69,7 @@ namespace TweetDck.Updates{
progressDownload.SetValueInstant(1000);
}
labelStatus.Text = (e.BytesReceived/BytesToMB).ToString("0.0",CultureInfo.CurrentCulture)+" MB";
labelStatus.Text = (e.BytesReceived/BytesToMB).ToString("0.0", CultureInfo.CurrentCulture)+" MB";
}
else{
if (progressDownload.Style != ProgressBarStyle.Continuous){
@@ -77,7 +77,7 @@ namespace TweetDck.Updates{
}
progressDownload.SetValueInstant(e.ProgressPercentage*10);
labelStatus.Text = (e.BytesReceived/BytesToMB).ToString("0.0",CultureInfo.CurrentCulture)+" / "+(e.TotalBytesToReceive/BytesToMB).ToString("0.0",CultureInfo.CurrentCulture)+" MB";
labelStatus.Text = (e.BytesReceived/BytesToMB).ToString("0.0", CultureInfo.CurrentCulture)+" / "+(e.TotalBytesToReceive/BytesToMB).ToString("0.0", CultureInfo.CurrentCulture)+" MB";
}
});
}
@@ -90,9 +90,9 @@ namespace TweetDck.Updates{
}
}
else if (e.Error != null){
Program.Log(e.Error.ToString());
Program.Reporter.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){
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;
}

View File

@@ -3,6 +3,7 @@ using CefSharp;
using CefSharp.WinForms;
using TweetDck.Core;
using TweetDck.Core.Controls;
using TweetDck.Core.Utils;
using TweetDck.Resources;
namespace TweetDck.Updates{
@@ -19,29 +20,29 @@ namespace TweetDck.Updates{
this.browser = browser;
this.form = form;
browser.FrameLoadEnd += browser_FrameLoadEnd;
browser.RegisterJsObject("$TDU",new Bridge(this));
browser.RegisterJsObject("$TDU", new Bridge(this));
}
private void browser_FrameLoadEnd(object sender, FrameLoadEndEventArgs e){
if (e.Frame.IsMain){
ScriptLoader.ExecuteFile(e.Frame,"update.js");
ScriptLoader.ExecuteFile(e.Frame, "update.js");
}
}
public int Check(bool force){
browser.ExecuteScriptAsync("TDUF_runUpdateCheck",force,++lastEventId);
browser.ExecuteScriptAsync("TDUF_runUpdateCheck", force, ++lastEventId);
return lastEventId;
}
private void TriggerUpdateAcceptedEvent(UpdateAcceptedEventArgs args){
if (UpdateAccepted != null){
form.InvokeSafe(() => UpdateAccepted(this,args));
form.InvokeSafe(() => UpdateAccepted(this, args));
}
}
private void TriggerCheckFinishedEvent(UpdateCheckEventArgs args){
if (CheckFinished != null){
form.InvokeSafe(() => CheckFinished(this,args));
form.InvokeSafe(() => CheckFinished(this, args));
}
}
@@ -70,6 +71,12 @@ namespace TweetDck.Updates{
}
}
public bool IsSystemSupported{
get{
return Environment.OSVersion.Version >= new Version("6.1"); // 6.1 NT version = Windows 7
}
}
private readonly UpdateHandler owner;
public Bridge(UpdateHandler owner){
@@ -77,11 +84,11 @@ namespace TweetDck.Updates{
}
public void OnUpdateCheckFinished(int eventId, bool isUpdateAvailable, string latestVersion){
owner.TriggerCheckFinishedEvent(new UpdateCheckEventArgs(eventId,isUpdateAvailable,latestVersion));
owner.TriggerCheckFinishedEvent(new UpdateCheckEventArgs(eventId, isUpdateAvailable, latestVersion));
}
public void OnUpdateAccepted(string versionTag, string downloadUrl){
owner.TriggerUpdateAcceptedEvent(new UpdateAcceptedEventArgs(new UpdateInfo(versionTag,downloadUrl)));
owner.TriggerUpdateAcceptedEvent(new UpdateAcceptedEventArgs(new UpdateInfo(versionTag, downloadUrl)));
}
public void OnUpdateDismissed(string versionTag){
@@ -90,6 +97,10 @@ namespace TweetDck.Updates{
Program.UserConfig.Save();
});
}
public void OpenBrowser(string url){
BrowserUtils.OpenExternalBrowser(url);
}
}
}
}

View File

@@ -1,9 +1,5 @@
del "bin\x86\Release Dick\*.xml"
del "bin\x86\Release Dick\devtools_resources.pak"
del "bin\x86\Release Duck\*.xml"
del "bin\x86\Release Duck\devtools_resources.pak"
del "bin\x86\Release\*.xml"
del "bin\x86\Release\devtools_resources.pak"
del "bin\x86\Release Dick\TweetDick.Browser.exe"
ren "bin\x86\Release Dick\CefSharp.BrowserSubprocess.exe" "TweetDick.Browser.exe"
del "bin\x86\Release Duck\TweetDuck.Browser.exe"
ren "bin\x86\Release Duck\CefSharp.BrowserSubprocess.exe" "TweetDuck.Browser.exe"
del "bin\x86\Release\TweetDuck.Browser.exe"
ren "bin\x86\Release\CefSharp.BrowserSubprocess.exe" "TweetDuck.Browser.exe"