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

Compare commits

..

465 Commits
1.11 ... 1.16.1

Author SHA1 Message Date
2ea38b88ce Release 1.16.1 2018-08-28 21:11:31 +02:00
2c4f2be57d Support system font in notifications, but revert to Arial everywhere by default 2018-08-28 21:06:53 +02:00
fa4beea425 Reset script cache when holding Shift during browser reload 2018-08-24 16:34:55 +02:00
7a976edc82 Ignore cached files for updates and viewed images if their contents are empty 2018-08-23 20:08:34 +02:00
bb22c35221 Fix broken context menu options for images in DMs
Closes #238
2018-08-23 19:51:43 +02:00
ff3dc59016 Move 'View image in photo viewer' handling to TwitterUtils 2018-08-23 19:32:20 +02:00
2e4dd3df3e Fix column icon alignment & clear icon not being hidden for certain columns 2018-08-18 14:55:08 +02:00
b82e5d33f9 Add .column to data-td-icon attribute selectors (very minor optimization) 2018-08-18 14:41:30 +02:00
65d56b336b Release 1.16 2018-08-17 20:09:15 +02:00
7836d61173 Rewrite hovered column/tweet detection again to improve consistency & performance 2018-08-17 16:13:09 +02:00
898437720b Refactor and optimize the plugin configuration file 2018-08-17 11:09:07 +02:00
d9a80d1085 Make it easier to modify custom values for column width and font size 2018-08-17 08:09:28 +02:00
ab3d8b0ae2 Load edit-design plugin configuration dialog lazily 2018-08-17 07:53:43 +02:00
b865074c32 Mark DMs as read when replying to them 2018-08-17 07:02:22 +02:00
2b8ca77c0d Add a safeguard and a TODO to DM notification fix 2018-08-16 20:36:12 +02:00
fa8b4e1e7f Remove broken feature that showed missed notifications after reload 2018-08-16 20:33:31 +02:00
a310c5bcc1 Fix a broken workaround for DM notifications not showing if the convo is open 2018-08-16 19:53:48 +02:00
b5dccd6b91 Merge branch 'master' of https://github.com/chylex/TweetDuck 2018-08-15 15:55:23 +02:00
c2bcb39b38 Fix broken hover color on column filter icons 2018-08-15 15:55:02 +02:00
4515add0a0 Update README.md 2018-08-12 16:06:38 +02:00
5b6aaec48c Reorganize installer batch files 2018-08-12 15:56:14 +02:00
810e56ca31 Update CefSharp to 67 (pre01) 2018-08-12 15:36:48 +02:00
5bcc8ac2e0 Remove ITweetDeckBrowser 2018-08-10 03:18:26 +02:00
f5bfb35867 Add a notification script to the debug plugin for testing 2018-08-10 03:14:39 +02:00
9088b8cd07 Finish refactoring context menu structures & fix bugs from previous commits 2018-08-10 00:58:44 +02:00
a7d90dc708 Allow RT & Add to List/Collection dialogs to be smaller
Closes #236
2018-08-09 20:20:08 +02:00
5968b57a01 Add account context menu items to follow notifications 2018-08-09 20:07:51 +02:00
94946a9ed6 Refactor context menu link handling 2018-08-09 19:55:53 +02:00
561aec5ef0 Refactor highlighted column/tweet variables 2018-08-09 18:13:45 +02:00
e31696d843 Update README.md 2018-07-31 14:30:05 +02:00
8b33fd2002 Update README.md 2018-07-31 14:23:25 +02:00
064e43750f Rewrite PostBuild into F# with optional compilation for performance 2018-07-31 12:48:07 +02:00
29d2f4f681 Why the fuck is Copy-Item file exclusion not working 2018-07-31 03:01:15 +02:00
c11b40b94a Tweak appearance of list-related notifications 2018-07-31 02:33:51 +02:00
e874e1d798 Refactor StringBuilder usage 2018-07-30 01:58:23 +02:00
01244ec632 Replace td-example-notification attribute with .td-example body class 2018-07-30 01:49:38 +02:00
671657e2b0 Remove user & system config properties from Program class & fix field visibility 2018-07-29 10:16:29 +02:00
dff7278e2e Refactor zoom config events & fix notification zoom not updating when outside TweetDeck 2018-07-29 09:41:52 +02:00
0881328636 Release 1.15.2 2018-07-27 22:13:16 +02:00
a951c3a7c9 Tweak Options visuals (labels, spacing, colors) & fix off-by-pixel bug on high DPI 2018-07-27 19:29:21 +02:00
b25fae54fe Update PostCefUpdate script to remove x64/AnyCPU from .targets file 2018-07-27 05:59:27 +02:00
a87bc4609e Add a cue text to Sounds tab in Options 2018-07-27 05:32:17 +02:00
3e68026949 Redesign Options to reduce amount of tabs and organize code 2018-07-27 05:12:17 +02:00
78d6d285cd Remove GDI charset from fonts in designer files 2018-07-26 20:17:53 +02:00
72e3596a3c Tweak heading font in Options and fix minor issues (tab order, overflowing text) 2018-07-26 19:37:07 +02:00
643ebcaab4 Prompt restart after profile import/reset only if an updated option requires it 2018-07-25 22:01:37 +02:00
52ef6cd95a Unify configs (backups, behavior, error handling) & make future development easier 2018-07-25 17:25:20 +02:00
4aec2f3260 Refactor FileSerializer to attempt error recovery & tweak StreamWriter usage 2018-07-25 03:38:44 +02:00
73549515eb Remove old user configuration fix 2018-07-24 06:16:52 +02:00
d83d2660cf Initial Options dialog refactoring to use an event for restart requests 2018-07-24 04:04:44 +02:00
8de913172c Minor visual fixes (old column icon alignment, TweetDeck reply triangle bug) 2018-07-23 20:14:54 +02:00
4acfd64cff Update xUnit 2018-07-23 20:13:04 +02:00
b56f90ed52 Add README instructions to fix broken MSBuild task 2018-07-23 14:20:07 +02:00
1375630727 Safeguard ResponseFilterBase in case input stream is null
Closes #234 (hopefully)
2018-07-23 12:37:57 +02:00
668825bc01 Add option to toggle touch adjustment & disable it by default
Closes #230
2018-07-23 01:36:49 +02:00
90414ae579 Release 1.15.1 2018-07-13 08:28:44 +02:00
41c8caa2a4 Make avatars in DM recipient list square 2018-07-12 15:23:01 +02:00
15305ecabe Revert TweetDeck style changes to the 'Add column' dialog
Closes #233
2018-07-12 08:37:44 +02:00
50090effd4 Refactor image/video download code and fix video download error message 2018-07-10 18:31:39 +02:00
6dffdcd1ed Add update notifications outside TweetDeck, tweak changelog styling 2018-07-10 08:50:09 +02:00
db9daf2714 Refactor update notification into a bridge object & tweak installer pre-downloading 2018-07-10 08:17:42 +02:00
502ac4ebc1 Enable high DPI awareness for video player process
Closes #232
2018-07-09 18:14:58 +02:00
3f44f3bab4 Fix notification scrolling issue by disabling threaded scrolling & latching
Closes #221
2018-07-09 17:47:20 +02:00
746eba185b Release 1.15 2018-07-09 14:06:13 +02:00
82dec92510 Fix wrong screenshot width on high DPI 2018-07-09 14:06:07 +02:00
2edc93df47 Update CefSharp to the newest build 2018-07-09 13:23:13 +02:00
c5a6738199 Fix a missing 'Clear columns' button after re-enabling the clear-columns plugin 2018-07-09 13:20:58 +02:00
dfd578165b Revert custom throttling, it is not ready due to issues w/ notifications 2018-07-09 13:04:55 +02:00
285d400f69 Refactor ScriptLoader to cache files on its own & change method signatures 2018-07-09 12:22:29 +02:00
47a3444ace Remove unnecessary styles and tweak formatting in black theme CSS 2018-07-09 10:21:44 +02:00
0ec227da52 Redesign Edit CSS dialog, add 'Open Dev Tools' button and better editor 2018-07-08 12:57:22 +02:00
f9cf582306 ... 2018-07-08 10:09:44 +02:00
b0883229bf Move HasDevTools to BrowserUtils 2018-07-08 10:06:40 +02:00
31b5d9a4c0 Protect code.js from uncaught errors & add custom 'throw if' statement 2018-07-08 09:53:42 +02:00
6841a78556 Rewrite clear-columns plugin to work w/o reload & fix broken Clear icon 2018-07-08 08:09:29 +02:00
9d2089a8ce Extract markup from introduction.js into an imported file & fix import regex 2018-07-08 06:14:33 +02:00
6d6bb79199 Massive JS formatting refactoring 2018-07-08 06:09:51 +02:00
937c8e22c4 Force UTF-8 in VS Code workspace settings 2018-07-08 05:16:31 +02:00
34c8d44dfe Project tweaks (make update installer on build, stopwatch resource swap, formatting) 2018-07-08 05:03:30 +02:00
2dbf778e56 Change the new DM limit behavior b/c older DMs don't load when scrolled to bottom 2018-07-06 22:09:09 +02:00
873fe2b393 Remove legacy HW acceleration support check & update tooltip 2018-07-06 09:37:25 +02:00
0c53bc6f32 Move icons and images to a separate folder 2018-07-06 07:26:22 +02:00
fa407e150b Add a quick way to import profile from the login page
Closes #228
2018-07-06 07:03:39 +02:00
4e52102c5c Add option for browser throttling w/ default when covered by larger window 2018-07-06 06:26:50 +02:00
0355a5c646 Add VS Code workspace file & fix some warnings 2018-07-06 06:04:10 +02:00
377d9c3554 Make an interface for dialogs to avoid hard-coding them in FormManager 2018-07-06 05:30:12 +02:00
20b1b3c895 Add more safety checks to code.js 2018-07-05 09:05:20 +02:00
41bbe7c51b Decrease amount of loaded DMs to lower performance hit from re-opening DMs 2018-07-05 07:39:26 +02:00
27fa6aefd3 Improve CSS minification 2018-07-05 06:32:45 +02:00
a63c3232da Update CefSharp to 67 (early) 2018-07-05 06:30:41 +02:00
146908a115 Include files for importing in the project to let VS detect changes 2018-07-04 17:27:49 +02:00
48b0f35fee Move template plugin HTML and CSS into a separate file 2018-07-04 17:24:32 +02:00
6c435ebe26 Extract styles from update.js into an imported CSS file 2018-07-04 07:03:48 +02:00
b8d0b721a2 Extract styles from introduction.js into an imported CSS file 2018-07-04 07:00:47 +02:00
a6d5957f46 Extract styles from twitter.js into imported CSS files 2018-07-04 06:55:10 +02:00
9e5f676e23 Move imported files into structured folder for easier handling & tweak syntax 2018-07-04 06:53:31 +02:00
414f3a1f9d Import shared plugin setup code into individual environment files 2018-07-04 06:26:41 +02:00
fedf9c60ee Hack up a simple import system in the build process 2018-07-04 06:25:22 +02:00
b6385d9622 Change unit test namespaces 2018-07-04 03:07:45 +02:00
76d25a712d Move old IO test project in preparation for future refactoring 2018-07-04 03:07:15 +02:00
2c6d935273 Rewrite unit tests for CommandLineArgs into xUnit 2018-07-04 02:45:11 +02:00
830d98a101 Rewrite unit tests for TwoKeyDictionary into xUnit 2018-07-03 21:23:34 +02:00
d7378bd75a Add leading slashes to URL strings in RequestHandlerBrowser 2018-07-02 20:32:23 +02:00
0f41cb9dbc Add response filter to restore global jQuery & unfreeze TweetDeck resources 2018-07-02 20:27:54 +02:00
77bc922d93 Add base class for response filters to safely modify intercepted files 2018-07-02 19:57:24 +02:00
c91b635132 Fix TDPF_createCustomStyle's remove function depending on jQuery 2018-07-01 16:51:57 +02:00
e5521de34a Split icon design files & update 256x256 icon 2018-07-01 15:45:33 +02:00
7c0f8d0f24 Remove temporarily forced update checking 2018-07-01 03:10:47 +02:00
f60d5f650f Add new program and tray icons to show when notifications are muted 2018-06-30 21:28:41 +02:00
ca67f2fe0a Redo app icon background as vector & update all icons 2018-06-30 19:39:16 +02:00
16cce8be1d Remove unnecessary code for disabling TweetDeck update notification 2018-06-30 15:02:46 +02:00
770619d948 Make update notification work without jQuery & optimize slide animation 2018-06-30 14:30:45 +02:00
cfedb7d6b1 Improve logged error message when update checking fails 2018-06-30 13:22:37 +02:00
738557b3a2 Add exception type that adds (potentially sensitive) details to error log 2018-06-30 13:20:25 +02:00
38b01deec1 Make it easier to freeze TweetDeck resources in the future 2018-06-30 11:49:46 +02:00
1a31e69ec9 Release 1.14.4.1 2018-06-29 19:56:00 +02:00
e065983c95 Delay the apocalypse (freeze TweetDeck JS resources, force update checking) 2018-06-29 19:41:02 +02:00
30a169171a Apparently deserializing @TryMyAwesomeApp sometimes causes a hidden crash 2018-06-29 17:10:11 +02:00
8d1900362e Update PostCefUpdate script to remove invalid build configurations (x64, AnyCPU) 2018-06-29 17:05:53 +02:00
e154189de1 Cleanup TweetDuck.csproj and fix names in TestResult unit test 2018-06-28 14:06:03 +02:00
b0f147de24 Fix misaligned 'Add column' icons when using old icon design 2018-06-28 08:10:48 +02:00
979b3548db Release 1.14.4 2018-06-28 07:54:38 +02:00
05d6c578b3 Move InjectedHTML unit tests to xUnit and rename Inject method 2018-06-26 11:19:44 +02:00
a117559063 Minor formatting tweaks 2018-06-26 10:05:53 +02:00
f87c649b09 Fix Twitter experiment causing crash in notifications and subsequent render corruption 2018-06-26 09:49:37 +02:00
6504dc9184 Add unit tests for Result and a few utility methods & fix edge case in StringUtils 2018-06-24 21:41:02 +02:00
25a8ddffd4 Rewrite and tweak existing Core namespace unit tests into xUnit 2018-06-24 19:29:24 +02:00
fa0f9b89cf Remove 'Release' configuration from UnitTests project 2018-06-24 16:16:11 +02:00
4d00a67891 Add a new F# xUnit test project 2018-06-24 16:09:21 +02:00
bd2c43e1f4 Fix analytics not counting applying ROT13 on non-editable text 2018-06-19 21:35:35 +02:00
c7279eaa34 Fix bug with falsely detecting symlinks in plugins if a file/folder doesn't exist 2018-06-19 21:32:21 +02:00
fd523e552c Symlinks/junctions in plugin folders can go to hell 2018-06-13 22:20:10 +02:00
cb877b8b23 Fix broken desktop notifications for retweets with sensitive media 2018-06-10 23:53:01 +02:00
ed1bee8b89 Release 1.14.3 2018-06-10 20:13:05 +02:00
a8e1492056 Push pin icon to the repository 2018-06-08 10:16:58 +02:00
5587216c01 Fix one more case of breaking overlays (account dialog) 2018-06-07 17:48:52 +02:00
86569261ad Add a visual response when hovering filter icons under column header 2018-06-07 14:52:39 +02:00
4a9049c7aa Fix CSS change in dialog overlays breaking some cases 2018-06-07 14:09:35 +02:00
75d60a8182 Work around browser redirection when dragging links into a scrolling column 2018-06-07 13:23:19 +02:00
14d4dc2ed9 Fix more instances of cut off badges 2018-06-06 16:04:15 +02:00
fd0e1740a5 Rename SetLastRightClickInfo bridge method and make it browser-only 2018-06-06 15:11:07 +02:00
70ca890bef Fix not stripping t.co in notifications when dragging & sometimes when copying 2018-06-06 15:10:52 +02:00
b9318dfd8e Minor visual fixes (Edit List modal, set minimum column width) 2018-06-05 04:25:05 +02:00
995642a719 Add support for 1 or 2 columns on screen in edit-design plugin 2018-06-05 03:48:40 +02:00
d14de4ac9e Lower minimum width of browser window & fix modals breaking in small windows 2018-06-05 02:51:21 +02:00
b7f325a241 Minor RequestHandlerBase refactoring 2018-06-05 02:05:04 +02:00
27c55718c2 Release 1.14.2.1 2018-06-04 13:01:44 +02:00
421ff0654b Temporarily work around buggy notification scrolling 2018-06-04 12:35:34 +02:00
ed947458f9 Update fallback HTML in desktop notifications 2018-06-04 12:09:02 +02:00
9cdb20ba84 Fix several broken column types in 'Add column' modal 2018-06-04 11:02:52 +02:00
d8774b735f Release 1.14.2 2018-06-04 08:59:32 +02:00
adcb42695f Update CEF so I don't have to workaround wrong dev tools version
Closes #220
2018-06-01 22:32:44 +02:00
dd77b5bcbb Revert smooth scrolling fix and rewrite horizontal scrolling fix to avoid column jumping 2018-06-01 21:48:26 +02:00
d2445be155 Fix missing GIF previews in tweet screenshots 2018-05-31 03:07:51 +02:00
10254c8af7 Fix tweet screenshots with Aero disabled by making the window visible
Closes #223
2018-05-31 02:58:25 +02:00
d7e830badf Slightly increase default notification height for larger font sizes 2018-05-31 01:11:17 +02:00
b445a3a9b8 Fix broken reply-account advanced selector arguments after a TweetDeck update 2018-05-31 00:52:08 +02:00
97f42ead66 Make it easier to debug screenshots 2018-05-30 19:50:11 +02:00
03730fafb9 ...because I can't be bothered 2018-05-29 15:34:02 +02:00
0be9465dca Fix column icons being hidden by title with clear-columns or edit-design features on 2018-05-29 15:23:41 +02:00
d7f1df4995 Release 1.14.1 2018-05-16 13:07:47 +02:00
3cb0f90706 Prevent an unlikely crash when showing an error message in context menu 2018-05-16 13:05:59 +02:00
a3e9b15a8a Add 'Apply ROT13' to non-editable selections to allow decoding tweets 2018-05-16 12:40:49 +02:00
00bfa68a57 Fix UI issues after recent TweetDeck updates 2018-05-16 07:48:47 +02:00
c311e24f08 Make it easier to update devtools file after updating CEF 2018-05-15 12:42:57 +02:00
1cdd4e4455 Update CefSharp to 66 (early) to fix memory leak 2018-05-15 10:10:03 +02:00
8078c0081a Add a script to fix browser project references after updating CEF 2018-05-15 10:04:08 +02:00
a867e1fc40 Optimize speed and memory usage of build process for app & installers 2018-05-08 20:20:02 +02:00
61da36ac1c Update README.md 2018-05-08 19:37:06 +02:00
720ca2a018 Update README.md 2018-05-08 19:36:08 +02:00
b39c593552 Update README.md 2018-05-08 06:28:07 +02:00
c808952a45 Update README.md 2018-05-08 00:03:08 +02:00
b468d7a766 Update README.md 2018-05-07 20:03:50 +02:00
28578f60be Include plugin files in the project & update README 2018-05-07 19:35:08 +02:00
92a39e2527 Push debug configuration start arguments (-datafolder TweetDuckDebug) 2018-05-07 18:11:56 +02:00
1bce5e4342 Release 1.14 2018-05-07 17:28:34 +02:00
68f586e104 Fix wrong info in the analytics dialog 2018-05-07 15:42:41 +02:00
d27a66202e Remove "Show this thread" in quoted tweets from notifications and screenshots 2018-05-07 03:01:24 +02:00
07de2f450c Fix broken notification scrolling in CEF 65 properly 2018-05-07 02:43:40 +02:00
3c03726634 Remove old and no longer necessary code from update installer 2018-05-06 22:47:58 +02:00
6fb2643063 Slightly increase installer compression level 2018-05-06 22:24:55 +02:00
5eef6c8196 Kill stubborn app processes when installing updates 2018-05-06 21:18:23 +02:00
829c332e13 Add a global function for mustache injection & fix broken clear-columns mustache 2018-05-05 11:47:19 +02:00
47eec14bca Fix freshly broken GIF previews in notifications 2018-05-04 21:07:33 +02:00
e7ee1d6be7 Revert "Fix broken notification scrolling in CEF 65"
This reverts commit 1029ea5840.
2018-05-04 14:00:41 +02:00
e41b5e5ff7 Replace generated license files with just one and include CEF license 2018-05-04 13:30:54 +02:00
ba1bacd08c Fix minor formatting and method modifier issues 2018-05-04 13:04:23 +02:00
1029ea5840 Fix broken notification scrolling in CEF 65 2018-05-04 11:41:20 +02:00
339eaf0195 Fix button appearance in introduction dialog and some plugins 2018-05-03 16:02:44 +02:00
aa1e1549d8 Fix Twitter's broken Cancel button when logging out 2018-05-03 15:04:09 +02:00
1f8ae9ef80 Update CefSharp to 65 (pre01) and fix blank example notification
* Update CefSharp to 65 (pre01)

* Fix blank example notification on first load
2018-05-03 14:05:56 +02:00
65165de060 Release 1.13.6 2018-05-02 16:27:23 +02:00
485836d2ce Replace about:blank in FormGuide with a dummy page 2018-05-02 15:21:23 +02:00
64c07c14d9 Revert "Update to CefSharp 65 (early) (#215)"
This reverts commit b6a599f8a6.
2018-05-02 15:19:01 +02:00
b6313c2b72 Update CefSharp to 65 (pre01) 2018-05-02 00:05:08 +02:00
58124b5821 Force Chrome UA on TweetDeck and remove -chromeagent argument 2018-05-01 19:31:39 +02:00
b6a599f8a6 Update to CefSharp 65 (early) (#215) 2018-05-01 19:20:13 +02:00
19a6bc0dbd Improve performance of PostBuild.ps1 2018-05-01 16:37:06 +02:00
8cb81d44ee Fix update installer changing uninstaller name and remove /MERGETASKS parameter 2018-05-01 14:36:51 +02:00
22d0a372d8 Add dev tools to the installer as an optional component 2018-05-01 14:30:56 +02:00
988fae75c3 Add a command line argument to use Chrome user agent 2018-04-30 21:02:15 +02:00
a82b0e3622 Release 1.13.5 2018-04-29 20:55:33 +02:00
bc6cacacf9 Fix portable install not recognizing itself after importing login session 2018-04-29 19:00:17 +02:00
03ad1b3cbc Update instructions for reply-account plugin and TDPF_getColumnName 2018-04-29 14:29:33 +02:00
eac300627f Fix broken column names again and make getColumnName accessible to plugins 2018-04-29 13:17:00 +02:00
12525ac386 Fix screenshots with zoom & try to fix rendering issues 2018-04-28 20:36:49 +02:00
7558551859 Add a debug flag to generate individual screenshot frames 2018-04-28 18:15:25 +02:00
a9cce13eef Fix visual inconsistencies with new icons 2018-04-28 15:34:15 +02:00
5bb2c43dd0 Fix edit-design plugin not loading when enabled after a restart 2018-04-28 15:22:55 +02:00
5b1dcc88cc Make Plugins form always show Configure button when configurable 2018-04-28 15:19:58 +02:00
5c8fc1d136 Fix clear-columns plugin button disappearing when adding/removing columns 2018-04-27 21:13:38 +02:00
82c2ab3448 Fix broken smooth and horizontal scrolling after a TweetDeck update 2018-04-27 19:33:32 +02:00
b05c8d180f Remove UpdaterSettings and fix not restarting the timer after a dismissed update 2018-04-27 19:21:42 +02:00
87109e5d01 Fix a few visual issues with high DPI 2018-04-27 18:29:02 +02:00
be1a809098 Update all forms and dialogs to use the 'Segoe UI' font 2018-04-27 18:06:45 +02:00
ba0e3f1bd4 Continue redesign of Plugins form (tweak visuals, position, and size limits) 2018-04-27 14:59:36 +02:00
27d41e6164 Begin redesign of the Plugins form (layout reorganization, fixes, optimization) 2018-04-27 13:47:29 +02:00
1ce5ddfd98 Rewrite names and descriptions of plugins & update debug plugin 2018-04-26 21:54:40 +02:00
0096a1a4ef Move debug configuration build events to PostBuild script 2018-04-26 15:37:02 +02:00
d2a6560a90 Measure PostBuild script duration and fix formatting 2018-04-25 19:35:57 +02:00
4d7c048139 Remove versions from official plugins and make them only work on one app version 2018-04-25 19:35:04 +02:00
1d78bd2655 Release 1.13.4.1 2018-04-24 18:16:13 +02:00
9250f1907c Quick semi-temporary fix for removed column.isOfType 2018-04-24 18:10:22 +02:00
a63e210b88 Release 1.13.4 2018-04-15 19:59:35 +02:00
06bd65b7f8 Fix wrong behavior when an update is canceled during download & multiple check errors in some cases 2018-04-15 19:01:39 +02:00
b6c17eb05e Remove unused selectors and classes from styles & add a related TODO note 2018-04-15 18:08:37 +02:00
a3d40fdc2b Push a quick utility to detect unused selectors and classes 2018-04-15 18:08:03 +02:00
c064ef7a30 Improve screenshot reliability 2018-04-15 16:24:26 +02:00
762717da1e Move clear-columns plugin nav button next to 'Add column' button & add isClearable safeguard 2018-04-15 14:39:59 +02:00
b7d3758bea Add error handling when checking updates, and remove unnecessary TODO 2018-04-15 14:03:11 +02:00
d20541fd24 Fix clear-columns plugin to hide the Clear button on scheduled & collection columns 2018-04-14 20:28:48 +02:00
2c2f860f26 Fix issues caused by recent TweetDeck update (notifications, column styles, reply account)
Closes #211
2018-04-14 19:40:51 +02:00
d1db3aa673 Remove command line argument for pre-releases & reorganize restart dialog 2018-04-11 10:39:17 +02:00
cedc52cdf5 Move update notification trigger code to TweetDeckBrowser 2018-04-11 10:01:55 +02:00
33f8eafbcf Remove unused VC120 NuGet package 2018-04-11 09:59:10 +02:00
ad45cf8c72 Begin rewriting update checker to run within C# 2018-04-11 09:59:00 +02:00
f99d035621 Add a Result class that acts as an Either monad for a value or exception 2018-04-10 19:45:41 +02:00
f3072caea8 Fix broken element resizing in the Edit CSS dialog 2018-04-07 13:42:36 +02:00
1410974292 Release 1.13.3 2018-04-07 11:56:36 +02:00
44413fa96c Swap order of 'Search in' items in selection context menu 2018-04-07 11:15:14 +02:00
342a4b4067 Minor code formatting tweaks 2018-04-07 03:46:10 +02:00
4356dde92d Fix wrong c# language version setting for Release builds 2018-04-06 16:36:27 +02:00
21e64a18d8 Fix screenshots to work properly with combinations of DPI and zoom settings 2018-04-06 07:28:57 +02:00
5a305a6740 Fix wrong screenshot size when browser zoom is not 100% 2018-04-06 03:05:06 +02:00
44595bad40 Refactor plugin loading and validation 2018-04-05 21:34:35 +02:00
7fc9edc9cb Fix wrong namespace in update event classes 2018-04-05 09:58:52 +02:00
93e191f522 Reorganize hot swap code & add support for hot swapping plugins 2018-04-05 03:34:11 +02:00
8d8355e792 Rewrite PluginManager setup scripts to use a custom array-based dictionary 2018-04-05 02:09:51 +02:00
a5379d290c Add resource hotswap for easier debugging 2018-04-04 23:13:44 +02:00
caea8d4315 Move most of post build event (copying, cleanup) to PostBuild.ps1 2018-04-04 20:05:59 +02:00
24224ab4c6 Increase height of Options form to avoid scrollbars in General tab 2018-04-04 07:43:00 +02:00
4dbc02360c Add context menu options to search selected text in a column or browser
Closes #209
2018-04-04 05:22:41 +02:00
aa7a29af0c Fix combo box issues (closing while opening, minor browser selection bug) 2018-04-04 03:33:14 +02:00
296d0c6199 Fix ScriptLoader showing multiple errors at once sometimes & change error title 2018-04-03 23:46:00 +02:00
812a034e8d Include version header in ScriptLoader files to detect failed installs 2018-04-03 23:44:43 +02:00
e9de789b79 Minor refactoring, including removal of unnecessary enableCustomCSS parameter 2018-04-03 20:49:21 +02:00
cfbc1b9575 Enable custom CSS in screenshots and move styles from code.js to notification.css 2018-04-03 20:48:33 +02:00
e39e85e4dd Add 'td-notification' body class to desktop notifications & update notification.css 2018-04-03 20:26:54 +02:00
3f0b161cd0 Move screenshot height calculation to the screenshot window 2018-04-03 18:26:33 +02:00
ebe3868720 Fix ScriptLoader crash when showing error message from another thread 2018-04-03 18:19:39 +02:00
ffd0f5e986 Rewrite screenshot rendering to fix current and future visual issues 2018-04-03 02:05:22 +02:00
217535a3ba Make td-notification-padded styles available in screenshots 2018-04-03 02:02:15 +02:00
7abfbea2da Fix "Replying to" user link not using black theme in screenshots
Closes #208
2018-04-03 01:10:53 +02:00
86ffeaac9a Remove no longer supported keycap emoji from the emoji keyboard
Closes #207
2018-04-03 00:04:18 +02:00
ab915b7115 Move accounts above hashtags in search results 2018-04-02 23:26:51 +02:00
705b5d38cf Add design files for logo and video player buttons 2018-04-01 19:35:12 +02:00
fc2acb00b3 Add a batch file to build update installer only 2018-03-16 18:50:37 +01:00
5add8a1d0e Move ITweetDeckBrowser and refactor some things 2018-03-16 18:48:41 +01:00
063d3a2637 Remove unnecessary null fallback in SetClipboardText 2018-03-09 14:43:59 +01:00
f1f90a2ee3 Refactor code to avoid nulls (#206)
* Ensure potential nulls have a fallback value & add/remove null checks

* Refactor update check code to avoid nulls

* Refactor ProfileManager exception handling to avoid nulls

* Refactor a few more various classes and fix nulls in ContextInfo

* Force c#7 everywhere and revert usage of newer features from cherry-picked commits

* Remove unused #pragma declaration
2018-03-07 14:37:03 +01:00
ed317a4e46 Refactor VideoPlayer 2018-03-06 21:17:22 +01:00
cca16f3bb1 Release 1.13.2 2018-03-06 18:38:24 +01:00
aba156cb3b Fix typo from refactoring breaking context menu for some links 2018-03-02 06:00:53 +01:00
cd4e4d7095 Fix hashtags and search links being recognized as account links 2018-03-02 05:59:20 +01:00
8fbb639430 Refactor & optimize context menu, send last tweet info only on right-click 2018-03-02 05:24:45 +01:00
d5bf8ec558 Fix missing image/video context menu for tweets that have both media and a quote 2018-03-02 00:15:28 +01:00
b6cff40f1e Warn when checking updates outside TweetDeck & fix visual and unlikely issues 2018-02-28 11:03:55 +01:00
833e42f455 Add a IsTweetDeckWebsite bool to ITweetDeckBrowser 2018-02-28 07:24:40 +01:00
8134843dad Fix background color & twitter.com hooks not applying quickly enough sometimes 2018-02-28 02:34:29 +01:00
1f92d5e633 Remove 'Shift Selects Multiple Accounts' option & fix refocusing after switching account 2018-02-28 01:43:44 +01:00
dc51c0ae85 Remove unnecessary console logging in debug builds 2018-02-26 17:45:56 +01:00
45c79643d6 Why the fuck is TLS 1.2 disabled by default in .NET on some computers 2018-02-25 23:15:00 +01:00
9041bfc627 Tweak search input font size and icon position 2018-02-21 22:17:51 +01:00
0b3b3dd0be Fix a crash when downloading tweet images with no username
Happens when someone accidentally or through dev tools gets to
twitter.com and tries downloading an image.
2018-02-21 19:48:00 +01:00
89e92dab59 Fix middle-clicking on links in desktop notifications not skipping them or stripping t.co 2018-02-19 17:31:28 +01:00
8c168c9ad7 Fix emoji keyboard button size & tweak composer button layout 2018-02-17 12:21:26 +01:00
9f63357a92 Pre-check desktop icon option in installer when not updating 2018-02-17 10:52:19 +01:00
d91b4bd1f3 Release 1.13.1 2018-02-14 18:43:02 +01:00
c0c64f6d62 Remove old TweetDeck installation check from the installer & tweak formatting 2018-02-14 17:45:19 +01:00
1a5d2af779 Decrease post-update analytics report to 8h and increase startup delay to 2m 2018-02-14 17:10:24 +01:00
f40a33192b Revert and fix various changes from recent TweetDeck update 2018-02-14 15:39:27 +01:00
ca4900aff0 Fix 'Manage templates' button after a recent TweetDeck update 2018-02-14 15:17:58 +01:00
56fc9e2d40 Fix black theme issues (mismatched detection & rare bug with wrong notification background color) 2018-02-13 16:51:40 +01:00
d2174c0b69 Fix misaligned avatars in activity columns 2018-02-13 15:59:21 +01:00
9f76754ad3 Force full install from 1.13 to 1.13.0.1 2018-02-13 13:37:30 +01:00
118ceaec35 Release 1.13.0.1 2018-02-13 13:27:52 +01:00
5a57d28a7d Fix crash by checking and downloading for VC++ 2015 in the installer
Closes #205
2018-02-13 13:17:40 +01:00
07af99f862 Fix wrong background color in tweet screenshots when using black theme 2018-02-13 12:42:25 +01:00
59fba7fba0 Fix a hidden crash that prevented desktop notifications from showing 2018-02-13 12:37:11 +01:00
dd4edc4249 Update CefSharp to latest 64 and remove VC++ 2012 2018-02-13 11:28:48 +01:00
856226473a Update README.md 2018-02-13 05:52:03 +01:00
8d1c07d6b2 Release 1.13 2018-02-12 18:48:42 +01:00
c32462cc9e Update TweetDeck color selectors in CSS for black theme 2018-02-12 18:23:16 +01:00
ec94ea3273 Refactor PluginManager to use ITweetDeckBrowser & do some cleanup 2018-02-12 15:26:21 +01:00
41acd8c15b Refactor UpdateHandler to reference ITweetDeckBrowser 2018-02-12 11:35:39 +01:00
155a79f2ec Add ITweetDeckBrowser for refactoring 2018-02-12 11:34:23 +01:00
9197cb9be6 Add support for 'Configure' button to edit-design plugin 2018-02-12 11:26:50 +01:00
03d50c847b Add 'Configure' button to plugins with a configure() method & close dialog afterwards 2018-02-12 10:40:00 +01:00
bf45c40365 Make analytics debugging easier & tweak Counter serialization 2018-02-12 06:13:08 +01:00
679e126194 Reset all analytics counters 2018-02-12 05:41:03 +01:00
50e39164bd Update and add analytics data points & increase report interval to 14 days 2018-02-11 20:01:57 +01:00
cb9f75e968 Refactor AnalyticsFile events and usage 2018-02-11 16:59:02 +01:00
aa7f6cc3b1 Fix loading spinner sometimes being visible before getting replaced 2018-02-10 23:20:34 +01:00
fe601aed41 Redesign favorite/retweet notifications to be more compact and show full text 2018-02-10 13:09:09 +01:00
2282a9df28 Move 'Show this thread' in desktop notifications above media/quotes & fix hover color w/ black theme 2018-02-10 08:29:59 +01:00
2b54627750 Tweak media size and margins in desktop notifications 2018-02-10 07:54:50 +01:00
16051a0d25 Forgot this 2018-02-10 07:13:56 +01:00
66d5f0d790 Refactor IResourceHandler usage 2018-02-10 07:07:11 +01:00
07d29207f0 Restore loading background color and spinner from before the TweetDeck update 2018-02-10 06:50:52 +01:00
a60be2afcc More Visual Studio shit 2018-02-07 21:58:21 +01:00
027f3ee253 Remove recently added follow notification 2018-02-07 03:22:50 +01:00
04774815e4 Fix bad padding in introduction modal 2018-02-07 03:20:58 +01:00
61a73c055b Fix weird alignment of stuff in notification columns 2018-02-07 00:39:05 +01:00
7731534ffc Save some space in edit-design plugin 2018-02-07 00:21:57 +01:00
ed7bf99610 Prevent dev tools from leaking info in all request headers 2018-02-06 21:10:29 +01:00
cbe4272556 Hide unused items in TweetDeck Settings modal (startup notifications, gif autoplay) 2018-02-06 20:43:18 +01:00
8f5e3dfdcc Merge pull request #203 from chylex/cefsharp64
Update CefSharp to 64 & re-enable mp3s in sound notifications
2018-02-06 18:40:23 +01:00
35500c51f1 Allow export/import/restoring system options & refactor Manage Options dialog 2018-02-06 18:35:36 +01:00
629f873bb2 Add a debugger trigger shortcut to debug plugin 2018-02-06 18:25:11 +01:00
a44cb884c4 Fix a crash when restarting after importing/resetting profile & refactor 2018-02-06 17:04:32 +01:00
d5ad1d0daa Fix loading spinners, and links in notifications when using black theme
Closes #202
2018-02-06 04:38:57 +01:00
61ae7e3b6a Fix 'Show this thread' being too close to media thumbnails in notifications 2018-02-06 04:37:45 +01:00
01583e424f Re-add mp3 support in sound notifications 2018-02-06 04:10:03 +01:00
5c0aa1b3da Update CefSharp to 64 (early build) 2018-02-06 04:06:18 +01:00
07391efa70 Fix more visual issues (remove DM reply button background w/ black theme) 2018-02-02 23:13:43 +01:00
b80f1bfc7c Fix more visual issues (remove disabled button border w/ black theme) 2018-02-02 22:31:01 +01:00
ad310db86c Fix more visual issues (profile modal w/ black theme, timeline input shadow) 2018-02-02 21:57:28 +01:00
4ce0122a29 Fix hover/click effects on buttons under reply input box 2018-02-02 19:15:44 +01:00
a8894f7054 Fix visual issues with search input and buttons 2018-02-02 18:01:11 +01:00
1d1515351b Release 1.12.5.1 2018-02-02 16:57:28 +01:00
2a9ddd4468 Fix edit-design modal, black theme quote border, and dark theme scrollbar color 2018-02-02 16:56:06 +01:00
0f9a944775 Square-ify border of reply box & fix notification background 2018-02-02 15:54:22 +01:00
34ee9ebd66 Release 1.12.5 2018-02-02 15:24:19 +01:00
43f632b555 Allow detecting custom edit-design themes in analytics 2018-02-02 15:19:25 +01:00
7cf3f1d32c Add option for the old dark theme in edit-design plugin 2018-02-02 14:59:33 +01:00
e51e87647e Remove unknown property error in FileSerializer & refactor reading 2018-02-02 13:49:10 +01:00
b8aae88b11 Fix broken Shift swap when selecting accounts after a recent TweetDeck update 2018-01-31 00:28:19 +01:00
d06e29db15 Get rid of string.Split in FileSerializer
string.Split is not suitable for potentially very large strings, so this
decently improves memory usage
2018-01-30 15:45:19 +01:00
62449450f3 Release 1.12.4 2018-01-29 08:40:38 +01:00
b290c94635 Fix a video player crash caused by not handling remote commands on UI thread 2018-01-29 08:20:33 +01:00
f909b887d9 Fix screenshot issues (wrong media size and margin, hide "Show this thread") 2018-01-28 21:48:57 +01:00
5cf4843212 Fix broken screenshots of tweets with just one line of text 2018-01-28 21:40:18 +01:00
b3d1e1bfac Fix example notification timer breaking on skip (forward mouse button or Enter) 2018-01-28 20:54:49 +01:00
df47499a28 Update example notification (username, avatar, improve text) 2018-01-28 20:50:18 +01:00
421475ec87 Add a notification and way to follow the new TweetDuck account 2018-01-28 20:22:13 +01:00
29d999b8eb Remove old data collection notification that was shown after updating 2018-01-28 20:05:50 +01:00
acacd9a5e5 Fix reversed button tab order in FormMessage 2018-01-28 19:39:12 +01:00
b81c26f93f Add an option to ignore tracking URL warnings (t.co) 2018-01-28 19:38:40 +01:00
00b212944c Implement top tier account bamboozle scheme 2018-01-28 19:12:32 +01:00
70ba006e4d Reorganize logo file resources and remove about.png 2018-01-26 17:44:41 +01:00
118e0cae62 Compress the logo in the About form 2018-01-26 17:36:15 +01:00
c003bb4e71 Add a way to display the TweetDuck logo in the browser 2018-01-26 17:32:54 +01:00
e9b2fa7603 Release 1.12.3.1 2018-01-26 15:58:17 +01:00
35afaa105d Fix text alignment in the Feedback tab in Options 2018-01-26 15:49:44 +01:00
2e300a7b8f Fix broken stylesheets in notifications after a recent TweetDeck update
Closes #199
2018-01-26 15:43:52 +01:00
f3f5b88550 Refactor resource handler related extension methods 2018-01-22 14:53:38 +01:00
22f491d98a Release 1.12.3 2018-01-22 07:13:50 +01:00
7908c8ebd9 Goddammit VS 2018-01-22 06:54:58 +01:00
e114a93714 Refactor and move BrowserCache, VideoPlayer, and ExportManager 2018-01-22 06:41:20 +01:00
931761600f Move and refactor browser list options a bit more again 2018-01-22 05:17:50 +01:00
e5b4b03e1a Meh 2018-01-21 09:11:40 +01:00
f1e8b3fbf0 Move option for custom program for opening links at the end for better accessibility 2018-01-21 06:33:50 +01:00
4d64243a07 Turn WindowsUtils.Browser fields into get-only properties 2018-01-21 04:25:06 +01:00
3422b4d4d6 Fix height, tab order, and recently broken scroll focus handling in Options 2018-01-21 03:29:11 +01:00
b170d529fd Add an option to disable smooth scrolling 2018-01-21 03:11:12 +01:00
83741db5aa Fix broken smooth & horizontal scrolling with cursor above columns
Closes #192
2018-01-21 01:18:59 +01:00
c4b2b3ab25 Add verbose error logging to video player & tweak Reporter.Log 2018-01-19 23:37:45 +01:00
676df44985 Fix dialog title inconsistencies 2018-01-19 22:29:53 +01:00
037adc6b5c Add a way to select a custom program for opening links
References #185
2018-01-19 20:08:48 +01:00
186d17dd98 Add an option to select an installed browser to open links in
Closes #185
2018-01-19 19:19:40 +01:00
ab9ff980ef Fix dragging twitter links over columns from some sources or w/ url parameters not working 2018-01-19 06:05:46 +01:00
f297cb2623 Add line escaping to FileSerializer for easier manual file editing 2018-01-18 20:37:29 +01:00
b53c672768 Refactor Program.ResetConfig & Program.RestartWithArgs 2018-01-18 10:58:58 +01:00
1a2b967749 Move Chromium data from LocalAppData/CEF to TweetDuck storage folder 2018-01-18 10:47:16 +01:00
6ba30c48cf Remove BrowserUtils.HeaderAcceptLanguage and use default value instead 2018-01-18 10:37:43 +01:00
1af9ee9ced Release 1.12.2 2018-01-17 16:19:28 +01:00
e50480aa35 Fix edit-design plugin modal labels changing margins with different themes 2018-01-16 22:55:21 +01:00
6943c7813f Fix hovering scrollbars not changing their color with edit-design plugin enabled 2018-01-16 22:54:53 +01:00
7c9b4382ca Fix Follow dialog closing when clicking any but the first Follow button 2018-01-16 19:20:14 +01:00
3187f97592 Rewrite 'Keep Like/Follow dialogs open' code after TD removed the old way 2018-01-15 21:25:43 +01:00
b71a367052 Merge pull request #196 from chylex/delet_audio_lib
Remove audio library
2018-01-14 11:13:31 +01:00
2d4bbf2a6f Fix sound notification extension detection and add warning to mp3 files 2018-01-14 00:08:43 +01:00
6e59dfddcc Remove audio library 2018-01-13 23:38:30 +01:00
bd92fc6ee0 Use <audio> for custom sound notifications & allow volume control for default one
Closes #195
2018-01-13 22:59:34 +01:00
2f61de7025 Add GetHandlerFactory extension method to BrowserUtils 2018-01-13 22:37:24 +01:00
8fcec7ec7c Merge remote-tracking branch 'refs/remotes/origin/master' into delet_audio_lib 2018-01-13 19:50:13 +01:00
33d9ba3871 Refactor UserConfig event invocations into a generic method 2018-01-13 19:49:16 +01:00
4f8c778ba0 Ignore errors in automatic cache clearing
Closes #194
2018-01-13 15:35:20 +01:00
804c739038 Fix broken element dragging (timeline tweets and maybe more) 2018-01-13 15:27:07 +01:00
a0445fbb12 Release 1.12.1.1 2018-01-12 12:48:14 +01:00
7ab5d7b796 Release 1.12.1 2018-01-12 12:40:09 +01:00
7f83a7773b Fix 'Show this thread' not working >_> 2018-01-12 12:39:46 +01:00
fc9e8a808f Fix emoji inline tweak not working in DMs 2018-01-11 21:48:00 +01:00
5ab8976bc7 Fix broken links in guide because Chromium is an idiot 2018-01-11 21:06:31 +01:00
e2a28f2811 Allow typing unambiguous :emoji: in inline replies 2018-01-11 20:15:56 +01:00
137a20ed0e Fix notification tooltip not disappearing when skipping/closing without moving mouse 2018-01-11 00:06:18 +01:00
f956f696f4 Limit some $TD functions to browser/notification, change displayTooltip params 2018-01-10 23:53:37 +01:00
bb7cbde38f Make 'Show this thread' in notification open tweet detail
Closes #191
2018-01-10 22:47:50 +01:00
8c452d3fa2 Fix clipboard html styles when copying text from notifications 2018-01-10 22:47:06 +01:00
f65c33c432 Add newly added option to analytics report 2018-01-10 22:17:30 +01:00
da2758ccb1 Add option to keep Like/Follow dialogs open
Closes #193
2018-01-10 14:22:47 +01:00
de10112b7f Remove non-english locale files from the installation 2018-01-03 16:23:56 +01:00
301d4fb171 Replace app locale option with spell check language & use correct lang list 2018-01-03 16:04:11 +01:00
f0a79add14 Fix broken example notification after closing it and then changing options 2018-01-03 14:52:47 +01:00
d33bc9fe25 Release 1.12 2018-01-01 01:48:48 +01:00
a2a5dfd435 Reset the official plugins folder in the update installer 2018-01-01 01:27:58 +01:00
f3d7c8d4c3 Set language header to match app locale 2017-12-31 14:21:21 +01:00
67f60dd787 Merge pull request #190 from chylex/locale_magic
Add options for app locale (remove argument) & target translation language
2017-12-31 14:03:15 +01:00
62310ce4a4 Add an option to set target language for tweet translations 2017-12-31 13:59:19 +01:00
3a27089364 Add an option to set app locale in a new Options tab & remove locale argument 2017-12-31 13:29:38 +01:00
a05460f562 Make BrowserCache.CacheFolder a property 2017-12-31 12:14:45 +01:00
390872c305 Merge pull request #189 from chylex/settings_ui_plz 2017-12-31 10:26:23 +01:00
594d12df79 Reorganize all Options tabs into FlowLayoutPanels 2017-12-31 10:20:42 +01:00
c42c12c72b Move Options tooltips outside designer files & reorder options in code 2017-12-31 08:10:24 +01:00
c37f4fe365 Merge branch 'master' of https://github.com/chylex/TweetDuck 2017-12-31 07:02:20 +01:00
8d37d68770 Fix dragging links not stripping t.co shortener
Closes #183
2017-12-31 06:59:17 +01:00
1b3d1fb36a Tweak readme wording 2017-12-31 05:36:32 +01:00
2f352ef9bb Update CefSharp to 63-pre01 and update documentation 2017-12-31 05:34:36 +01:00
527f3cab4c Fix reinstantiating AnalyticsManager when restoring from tray & test stuff 2017-12-31 05:01:23 +01:00
f67bf27db2 Add an option to automatically clear cache after exceeding a set size
Closes #182
2017-12-30 02:06:36 +01:00
a8bb3ba349 Improve performance and safety of cache size checking & clearing 2017-12-28 04:52:53 +01:00
321ab12213 WTF is AnyCPU doing in the project files 2017-12-28 00:50:51 +01:00
4cab18e557 Merge pull request #187 from chylex/cefsharp63
Update CefSharp to 63 (early build) & delete GC reload
2017-12-28 00:39:07 +01:00
c15ea97a36 Update CEF again 2017-12-28 00:32:26 +01:00
a0cc4109df Delete GC reload in CEF 63 (#186) 2017-12-28 00:03:24 +01:00
f66ff1000a Replace AbstractRequestHandler with CefSharp's implementation 2017-12-21 22:45:29 +01:00
51a9bb6d3c Update CefSharp to 63 pre-release 2017-12-21 20:25:36 +01:00
07017bd29b Fix cut off usernames in Messages column 2017-12-21 20:15:02 +01:00
45b6f49a08 Fix middle-click and ctrl-click handling in CEF 62 2017-12-07 20:07:15 +01:00
103ad72788 Update CefSharp to 62 (early build) 2017-12-07 19:50:43 +01:00
543259f29f Release 1.11.2 2017-11-21 07:07:24 +01:00
98799734c5 Add a box shadow to main menu in the guide 2017-11-21 06:59:54 +01:00
96f491a666 Redo the introduction dialog (add main menu image & follow link, rewrite text) 2017-11-21 06:11:49 +01:00
29e541dbef Fix comment formatting in notification.css 2017-11-20 18:01:17 +01:00
1343b9c113 Fix username alignment (follow notifications & all types in desktop notifications) 2017-11-20 18:01:02 +01:00
94920fd459 Ensure only one guide window is open and fix webkit element outline 2017-11-20 17:44:28 +01:00
b2f3b245b7 Open TweetDuck guide links directly in the app 2017-11-20 17:25:25 +01:00
15bc6c1d73 Fix idiot chromium being unable to figure out window size while loading guide 2017-11-20 17:21:46 +01:00
2c175b8d3a Fix incorrect default config value for notification scroll speed 2017-11-18 15:31:36 +01:00
a48c17a769 Update analytics (fix system edition, add dev tools and other feature collection) 2017-11-18 07:15:18 +01:00
03465c4ab0 Remove dismissed update config entry after accepting an update 2017-11-18 02:53:25 +01:00
b4e936c530 Minor refactoring of notification classes & remove no longer needed CSS 2017-11-14 19:06:05 +01:00
fb1482370a Fix issues from TweetDeck updates (long usernames, badge in detail view, notification media previews) 2017-11-14 18:42:34 +01:00
e831bc2bea Fix broken compose text size in edit-design plugin after a TweetDeck update 2017-11-11 17:32:20 +01:00
c74c168c96 Release 1.11.1 2017-11-10 14:59:48 +01:00
40b53fa40c Fix broken update notification CSS after a TweetDeck update 2017-11-10 14:52:32 +01:00
3481cc0349 Fix broken CSS in browser and plugins after a TweetDeck update 2017-11-10 14:44:47 +01:00
09abd889e9 Add ID to <html> for selector priority 2017-11-10 14:14:50 +01:00
330bbfbb31 Fix broken CSS in notifications after a TweetDeck update 2017-11-10 13:35:29 +01:00
6b7b690476 Remove Log method from the bridge object 2017-11-09 21:43:22 +01:00
cea72801a7 Fix video player process sometimes taking too long to close 2017-11-09 19:29:01 +01:00
04369e22a7 Add option to disable animated avatars (general GIF toggle)
Note: this breaks when disable-extensions is used, so it was changed to
disable-pdf-extension instead
2017-11-09 18:18:22 +01:00
f1b16eab9a Add a global function (including one for plugins) to reload columns 2017-11-09 18:15:58 +01:00
13646d9c90 Increase quality of media previews in desktop notifications 2017-11-09 17:08:39 +01:00
17d762ce91 Make spell check option not require a restart 2017-11-09 16:51:40 +01:00
237 changed files with 11679 additions and 6614 deletions

View File

@@ -5,9 +5,8 @@ namespace TweetDuck.Configuration{
static class Arguments{ static class Arguments{
// public args // public args
public const string ArgDataFolder = "-datafolder"; public const string ArgDataFolder = "-datafolder";
public const string ArgLocale = "-locale";
public const string ArgLogging = "-log"; public const string ArgLogging = "-log";
public const string ArgDebugUpdates = "-debugupdates"; public const string ArgIgnoreGDPR = "-nogdpr";
// internal args // internal args
public const string ArgRestart = "-restart"; public const string ArgRestart = "-restart";

View File

@@ -0,0 +1,128 @@
using System;
using System.Collections.Generic;
using System.Drawing;
using TweetDuck.Configuration.Instance;
using TweetDuck.Core.Utils;
using TweetDuck.Data;
using TweetDuck.Data.Serialization;
namespace TweetDuck.Configuration{
sealed class ConfigManager{
public UserConfig User { get; }
public SystemConfig System { get; }
public PluginConfig Plugins { get; }
public event EventHandler ProgramRestartRequested;
private readonly FileConfigInstance<UserConfig> infoUser;
private readonly FileConfigInstance<SystemConfig> infoSystem;
private readonly PluginConfigInstance infoPlugins;
private readonly IConfigInstance<BaseConfig>[] infoList;
public ConfigManager(){
User = new UserConfig(this);
System = new SystemConfig(this);
Plugins = new PluginConfig(this);
infoList = new IConfigInstance<BaseConfig>[]{
infoUser = new FileConfigInstance<UserConfig>(Program.UserConfigFilePath, User, "program options"),
infoSystem = new FileConfigInstance<SystemConfig>(Program.SystemConfigFilePath, System, "system options"),
infoPlugins = new PluginConfigInstance(Program.PluginConfigFilePath, Plugins)
};
// TODO refactor further
infoUser.Serializer.RegisterTypeConverter(typeof(WindowState), WindowState.Converter);
infoUser.Serializer.RegisterTypeConverter(typeof(Point), new SingleTypeConverter<Point>{
ConvertToString = value => $"{value.X} {value.Y}",
ConvertToObject = value => {
int[] elements = StringUtils.ParseInts(value, ' ');
return new Point(elements[0], elements[1]);
}
});
infoUser.Serializer.RegisterTypeConverter(typeof(Size), new SingleTypeConverter<Size>{
ConvertToString = value => $"{value.Width} {value.Height}",
ConvertToObject = value => {
int[] elements = StringUtils.ParseInts(value, ' ');
return new Size(elements[0], elements[1]);
}
});
}
public void LoadAll(){
infoUser.Load();
infoSystem.Load();
infoPlugins.Load();
}
public void SaveAll(){
infoUser.Save();
infoSystem.Save();
infoPlugins.Save();
}
public void ReloadAll(){
infoUser.Reload();
infoSystem.Reload();
infoPlugins.Reload();
}
private void TriggerProgramRestartRequested(){
ProgramRestartRequested?.Invoke(this, EventArgs.Empty);
}
private IConfigInstance<BaseConfig> GetInstanceInfo(BaseConfig instance){
Type instanceType = instance.GetType();
return Array.Find(infoList, info => info.Instance.GetType() == instanceType); // TODO handle null
}
public abstract class BaseConfig{
private readonly ConfigManager configManager;
protected BaseConfig(ConfigManager configManager){
this.configManager = configManager;
}
// Management
public void Save(){
configManager.GetInstanceInfo(this).Save();
}
public void Reload(){
configManager.GetInstanceInfo(this).Reload();
}
public void Reset(){
configManager.GetInstanceInfo(this).Reset();
}
// Construction methods
public T ConstructWithDefaults<T>() where T : BaseConfig{
return ConstructWithDefaults(configManager) as T;
}
protected abstract BaseConfig ConstructWithDefaults(ConfigManager configManager);
// Utility methods
protected void UpdatePropertyWithEvent<T>(ref T field, T value, EventHandler eventHandler){
if (!EqualityComparer<T>.Default.Equals(field, value)){
field = value;
eventHandler?.Invoke(this, EventArgs.Empty);
}
}
protected void UpdatePropertyWithRestartRequest<T>(ref T field, T value){
if (!EqualityComparer<T>.Default.Equals(field, value)){
field = value;
configManager.TriggerProgramRestartRequested();
}
}
}
}
}

View File

@@ -0,0 +1,104 @@
using System;
using System.IO;
using TweetDuck.Data.Serialization;
namespace TweetDuck.Configuration.Instance{
sealed class FileConfigInstance<T> : IConfigInstance<T> where T : ConfigManager.BaseConfig{
private const string ErrorTitle = "Configuration Error";
public T Instance { get; }
public FileSerializer<T> Serializer { get; }
private readonly string filenameMain;
private readonly string filenameBackup;
private readonly string errorIdentifier;
public FileConfigInstance(string filename, T instance, string errorIdentifier){
this.filenameMain = filename;
this.filenameBackup = filename+".bak";
this.errorIdentifier = errorIdentifier;
this.Instance = instance;
this.Serializer = new FileSerializer<T>();
}
private void LoadInternal(bool backup){
Serializer.Read(backup ? filenameBackup : filenameMain, Instance);
}
public void Load(){
Exception firstException = null;
for(int attempt = 0; attempt < 2; attempt++){
try{
LoadInternal(attempt > 0);
if (firstException != null){ // silently log exception that caused a backup restore
Program.Reporter.Log(firstException.ToString());
}
return;
}catch(FileNotFoundException){
}catch(DirectoryNotFoundException){
break;
}catch(Exception e){
if (firstException == null){
firstException = e;
}
}
}
if (firstException is FormatException){
Program.Reporter.HandleException(ErrorTitle, "The configuration file for "+errorIdentifier+" is outdated or corrupted. If you continue, your "+errorIdentifier+" will be reset.", true, firstException);
}
else if (firstException is SerializationSoftException sse){
Program.Reporter.HandleException(ErrorTitle, $"{sse.Errors.Count} error{(sse.Errors.Count == 1 ? " was" : "s were")} encountered while loading the configuration file for "+errorIdentifier+". If you continue, some of your "+errorIdentifier+" will be reset.", true, firstException);
}
else if (firstException != null){
Program.Reporter.HandleException(ErrorTitle, "Could not open the configuration file for "+errorIdentifier+". If you continue, your "+errorIdentifier+" will be reset.", true, firstException);
}
}
public void Save(){
try{
if (File.Exists(filenameMain)){
File.Delete(filenameBackup);
File.Move(filenameMain, filenameBackup);
}
Serializer.Write(filenameMain, Instance);
}catch(SerializationSoftException e){
Program.Reporter.HandleException(ErrorTitle, $"{e.Errors.Count} error{(e.Errors.Count == 1 ? " was" : "s were")} encountered while saving the configuration file for "+errorIdentifier+".", true, e);
}catch(Exception e){
Program.Reporter.HandleException(ErrorTitle, "Could not save the configuration file for "+errorIdentifier+".", true, e);
}
}
public void Reload(){
try{
LoadInternal(false);
}catch(FileNotFoundException){
try{
Serializer.Write(filenameMain, Instance.ConstructWithDefaults<T>());
LoadInternal(false);
}catch(Exception e){
Program.Reporter.HandleException(ErrorTitle, "Could not regenerate the configuration file for "+errorIdentifier+".", true, e);
}
}catch(Exception e){
Program.Reporter.HandleException(ErrorTitle, "Could not reload the configuration file for "+errorIdentifier+".", true, e);
}
}
public void Reset(){
try{
File.Delete(filenameMain);
File.Delete(filenameBackup);
}catch(Exception e){
Program.Reporter.HandleException(ErrorTitle, "Could not delete configuration files to reset "+errorIdentifier+".", true, e);
return;
}
Reload();
}
}
}

View File

@@ -0,0 +1,9 @@
namespace TweetDuck.Configuration.Instance{
interface IConfigInstance<out T>{
T Instance { get; }
void Save();
void Reload();
void Reset();
}
}

View File

@@ -0,0 +1,69 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Text;
namespace TweetDuck.Configuration.Instance{
class PluginConfigInstance : IConfigInstance<PluginConfig>{
public PluginConfig Instance { get; }
private readonly string filename;
public PluginConfigInstance(string filename, PluginConfig instance){
this.filename = filename;
this.Instance = instance;
}
public void Load(){
try{
using(StreamReader reader = new StreamReader(new FileStream(filename, FileMode.Open, FileAccess.Read, FileShare.Read), Encoding.UTF8)){
string line = reader.ReadLine();
if (line == "#Disabled"){
HashSet<string> newDisabled = new HashSet<string>();
while((line = reader.ReadLine()) != null){
newDisabled.Add(line);
}
Instance.ReloadSilently(newDisabled);
}
}
}catch(FileNotFoundException){
}catch(DirectoryNotFoundException){
}catch(Exception e){
Program.Reporter.HandleException("Plugin Configuration Error", "Could not read the plugin configuration file. If you continue, the list of disabled plugins will be reset to default.", true, e);
}
}
public void Save(){
try{
using(StreamWriter writer = new StreamWriter(new FileStream(filename, FileMode.Create, FileAccess.Write, FileShare.None), Encoding.UTF8)){
writer.WriteLine("#Disabled");
foreach(string identifier in Instance.DisabledPlugins){
writer.WriteLine(identifier);
}
}
}catch(Exception e){
Program.Reporter.HandleException("Plugin Configuration Error", "Could not save the plugin configuration file.", true, e);
}
}
public void Reload(){
Load();
}
public void Reset(){
try{
File.Delete(filename);
Instance.ReloadSilently(Instance.ConstructWithDefaults<PluginConfig>().DisabledPlugins);
}catch(Exception e){
Program.Reporter.HandleException("Plugin Configuration Error", "Could not delete the plugin configuration file.", true, e);
return;
}
Reload();
}
}
}

View File

@@ -0,0 +1,45 @@
using System;
using System.Collections.Generic;
using TweetDuck.Plugins;
using TweetDuck.Plugins.Events;
namespace TweetDuck.Configuration{
sealed class PluginConfig : ConfigManager.BaseConfig, IPluginConfig{
private static readonly string[] DefaultDisabled = {
"official/clear-columns",
"official/reply-account"
};
// CONFIGURATION
public IEnumerable<string> DisabledPlugins => disabled;
public event EventHandler<PluginChangedStateEventArgs> PluginChangedState;
public void SetEnabled(Plugin plugin, bool enabled){
if ((enabled && disabled.Remove(plugin.Identifier)) || (!enabled && disabled.Add(plugin.Identifier))){
PluginChangedState?.Invoke(this, new PluginChangedStateEventArgs(plugin, enabled));
Save();
}
}
public bool IsEnabled(Plugin plugin){
return !disabled.Contains(plugin.Identifier);
}
public void ReloadSilently(IEnumerable<string> newDisabled){
disabled.Clear();
disabled.UnionWith(newDisabled);
}
private readonly HashSet<string> disabled = new HashSet<string>(DefaultDisabled);
// END OF CONFIG
public PluginConfig(ConfigManager configManager) : base(configManager){}
protected override ConfigManager.BaseConfig ConstructWithDefaults(ConfigManager configManager){
return new PluginConfig(configManager);
}
}
}

View File

@@ -1,54 +1,26 @@
using System; namespace TweetDuck.Configuration{
using System.IO; sealed class SystemConfig : ConfigManager.BaseConfig{
using TweetDuck.Data.Serialization;
namespace TweetDuck.Configuration{
sealed class SystemConfig{
private static readonly FileSerializer<SystemConfig> Serializer = new FileSerializer<SystemConfig>();
public static readonly bool IsHardwareAccelerationSupported = File.Exists(Path.Combine(Program.ProgramPath, "libEGL.dll")) &&
File.Exists(Path.Combine(Program.ProgramPath, "libGLESv2.dll"));
// CONFIGURATION DATA // CONFIGURATION DATA
private bool _hardwareAcceleration = true; public bool _hardwareAcceleration = true;
public bool EnableBrowserGCReload { get; set; } = true; public bool ClearCacheAutomatically { get; set; } = true;
public int BrowserMemoryThreshold { get; set; } = 400; public int ClearCacheThreshold { get; set; } = 250;
// SPECIAL PROPERTIES // SPECIAL PROPERTIES
public bool HardwareAcceleration{ public bool HardwareAcceleration{
get => _hardwareAcceleration && IsHardwareAccelerationSupported; get => _hardwareAcceleration;
set => _hardwareAcceleration = value; set => UpdatePropertyWithRestartRequest(ref _hardwareAcceleration, value);
} }
// END OF CONFIG // END OF CONFIG
private readonly string file; public SystemConfig(ConfigManager configManager) : base(configManager){}
private SystemConfig(string file){ protected override ConfigManager.BaseConfig ConstructWithDefaults(ConfigManager configManager){
this.file = file; return new SystemConfig(configManager);
}
public void Save(){
try{
Serializer.Write(file, this);
}catch(Exception e){
Program.Reporter.HandleException("Configuration Error", "Could not save the system configuration file.", true, e);
}
}
public static SystemConfig Load(string file){
SystemConfig config = new SystemConfig(file);
try{
Serializer.ReadIfExists(file, config);
}catch(Exception e){
Program.Reporter.HandleException("Configuration Error", "Could not open the system configuration file. If you continue, you will lose system specific configuration such as Hardware Acceleration.", true, e);
}
return config;
} }
} }
} }

View File

@@ -1,54 +1,43 @@
using System; using System;
using System.Drawing; using System.Drawing;
using System.IO;
using TweetDuck.Core.Controls; using TweetDuck.Core.Controls;
using TweetDuck.Core.Notification; using TweetDuck.Core.Notification;
using TweetDuck.Core.Other; using TweetDuck.Core.Other;
using TweetDuck.Core.Utils; using TweetDuck.Core.Utils;
using TweetDuck.Data; using TweetDuck.Data;
using TweetDuck.Data.Serialization;
namespace TweetDuck.Configuration{ namespace TweetDuck.Configuration{
sealed class UserConfig{ sealed class UserConfig : ConfigManager.BaseConfig{
private static readonly FileSerializer<UserConfig> Serializer = new FileSerializer<UserConfig>();
static UserConfig(){
Serializer.RegisterTypeConverter(typeof(WindowState), WindowState.Converter);
Serializer.RegisterTypeConverter(typeof(Point), new SingleTypeConverter<Point>{
ConvertToString = value => $"{value.X} {value.Y}",
ConvertToObject = value => {
int[] elements = StringUtils.ParseInts(value, ' ');
return new Point(elements[0], elements[1]);
}
});
Serializer.RegisterTypeConverter(typeof(Size), new SingleTypeConverter<Size>{
ConvertToString = value => $"{value.Width} {value.Height}",
ConvertToObject = value => {
int[] elements = StringUtils.ParseInts(value, ' ');
return new Size(elements[0], elements[1]);
}
});
}
// CONFIGURATION DATA // CONFIGURATION DATA
public bool FirstRun { get; set; } = true; public bool FirstRun { get; set; } = true;
public bool AllowDataCollection { get; set; } = false; public bool AllowDataCollection { get; set; } = false;
public bool ShowDataCollectionNotification { get; set; } = true;
public WindowState BrowserWindow { get; set; } = new WindowState(); public WindowState BrowserWindow { get; set; } = new WindowState();
public WindowState PluginsWindow { get; set; } = new WindowState(); public Size PluginsWindowSize { get; set; } = Size.Empty;
public bool ExpandLinksOnHover { get; set; } = true; public bool ExpandLinksOnHover { get; set; } = true;
public bool SwitchAccountSelectors { get; set; } = true;
public bool OpenSearchInFirstColumn { get; set; } = true; public bool OpenSearchInFirstColumn { get; set; } = true;
public bool KeepLikeFollowDialogsOpen { get; set; } = true;
public bool BestImageQuality { get; set; } = true; public bool BestImageQuality { get; set; } = true;
public bool EnableSpellCheck { get; set; } = false; public bool EnableAnimatedImages { get; set; } = true;
public int VideoPlayerVolume { get; set; } = 50;
private bool _enableSmoothScrolling = true;
private bool _enableTouchAdjustment = false;
private string _customCefArgs = null;
public string BrowserPath { get; set; } = null;
public bool IgnoreTrackingUrlWarning { get; set; } = false;
public string SearchEngineUrl { get; set; } = null;
private int _zoomLevel = 100; private int _zoomLevel = 100;
private bool _muteNotifications;
public int VideoPlayerVolume { get; set; } = 50;
public bool EnableSpellCheck { get; set; } = false;
private string _spellCheckLanguage = "en-US";
public string TranslationTarget { get; set; } = "en";
private TrayIcon.Behavior _trayBehavior = TrayIcon.Behavior.Disabled; private TrayIcon.Behavior _trayBehavior = TrayIcon.Behavior.Disabled;
public bool EnableTrayHighlight { get; set; } = true; public bool EnableTrayHighlight { get; set; } = true;
@@ -73,12 +62,13 @@ namespace TweetDuck.Configuration{
public TweetNotification.Size NotificationSize { get; set; } = TweetNotification.Size.Auto; public TweetNotification.Size NotificationSize { get; set; } = TweetNotification.Size.Auto;
public Size CustomNotificationSize { get; set; } = Size.Empty; public Size CustomNotificationSize { get; set; } = Size.Empty;
public int NotificationScrollSpeed { get; set; } = 10; public int NotificationScrollSpeed { get; set; } = 100;
public int NotificationSoundVolume { get; set; } = 100;
private string _notificationSoundPath; private string _notificationSoundPath;
private int _notificationSoundVolume = 100;
private bool _muteNotifications;
public string CustomCefArgs { get; set; } = null;
public string CustomBrowserCSS { get; set; } = null; public string CustomBrowserCSS { get; set; } = null;
public string CustomNotificationCSS { get; set; } = null; public string CustomNotificationCSS { get; set; } = null;
@@ -86,45 +76,53 @@ namespace TweetDuck.Configuration{
public bool IsCustomNotificationPositionSet => CustomNotificationPosition != ControlExtensions.InvisibleLocation; public bool IsCustomNotificationPositionSet => CustomNotificationPosition != ControlExtensions.InvisibleLocation;
public bool IsCustomNotificationSizeSet => CustomNotificationSize != Size.Empty; public bool IsCustomNotificationSizeSet => CustomNotificationSize != Size.Empty;
public bool IsCustomSoundNotificationSet => NotificationSoundPath != string.Empty;
public TwitterUtils.ImageQuality TwitterImageQuality => BestImageQuality ? TwitterUtils.ImageQuality.Orig : TwitterUtils.ImageQuality.Default; public TwitterUtils.ImageQuality TwitterImageQuality => BestImageQuality ? TwitterUtils.ImageQuality.Orig : TwitterUtils.ImageQuality.Default;
public string NotificationSoundPath{ public string NotificationSoundPath{
get => string.IsNullOrEmpty(_notificationSoundPath) ? string.Empty : _notificationSoundPath; get => _notificationSoundPath ?? string.Empty;
set => _notificationSoundPath = value; set => UpdatePropertyWithEvent(ref _notificationSoundPath, value, SoundNotificationChanged);
}
public int NotificationSoundVolume{
get => _notificationSoundVolume;
set => UpdatePropertyWithEvent(ref _notificationSoundVolume, value, SoundNotificationChanged);
} }
public bool MuteNotifications{ public bool MuteNotifications{
get => _muteNotifications; get => _muteNotifications;
set => UpdatePropertyWithEvent(ref _muteNotifications, value, MuteToggled);
set{
if (_muteNotifications != value){
_muteNotifications = value;
MuteToggled?.Invoke(this, EventArgs.Empty);
}
}
} }
public int ZoomLevel{ public int ZoomLevel{
get => _zoomLevel; get => _zoomLevel;
set => UpdatePropertyWithEvent(ref _zoomLevel, value, ZoomLevelChanged);
set{
if (_zoomLevel != value){
_zoomLevel = value;
ZoomLevelChanged?.Invoke(this, EventArgs.Empty);
}
}
} }
public TrayIcon.Behavior TrayBehavior{ public TrayIcon.Behavior TrayBehavior{
get => _trayBehavior; get => _trayBehavior;
set => UpdatePropertyWithEvent(ref _trayBehavior, value, TrayBehaviorChanged);
}
set{ public bool EnableSmoothScrolling{
if (_trayBehavior != value){ get => _enableSmoothScrolling;
_trayBehavior = value; set => UpdatePropertyWithRestartRequest(ref _enableSmoothScrolling, value);
TrayBehaviorChanged?.Invoke(this, EventArgs.Empty);
} }
public bool EnableTouchAdjustment{
get => _enableTouchAdjustment;
set => UpdatePropertyWithRestartRequest(ref _enableTouchAdjustment, value);
} }
public string CustomCefArgs{
get => _customCefArgs;
set => UpdatePropertyWithRestartRequest(ref _customCefArgs, value);
}
public string SpellCheckLanguage{
get => _spellCheckLanguage;
set => UpdatePropertyWithRestartRequest(ref _spellCheckLanguage, value);
} }
// EVENTS // EVENTS
@@ -132,84 +130,14 @@ namespace TweetDuck.Configuration{
public event EventHandler MuteToggled; public event EventHandler MuteToggled;
public event EventHandler ZoomLevelChanged; public event EventHandler ZoomLevelChanged;
public event EventHandler TrayBehaviorChanged; public event EventHandler TrayBehaviorChanged;
public event EventHandler SoundNotificationChanged;
// END OF CONFIG // END OF CONFIG
private readonly string file; public UserConfig(ConfigManager configManager) : base(configManager){}
private UserConfig(string file){ protected override ConfigManager.BaseConfig ConstructWithDefaults(ConfigManager configManager){
this.file = file; return new UserConfig(configManager);
}
public void Save(){
try{
if (File.Exists(file)){
string backupFile = GetBackupFile(file);
File.Delete(backupFile);
File.Move(file, backupFile);
}
Serializer.Write(file, this);
}catch(Exception e){
Program.Reporter.HandleException("Configuration Error", "Could not save the configuration file.", true, e);
}
}
public void Reload(){
try{
LoadInternal(false);
}catch(FileNotFoundException){
try{
Serializer.Write(file, new UserConfig(file));
LoadInternal(false);
}catch(Exception e){
Program.Reporter.HandleException("Configuration Error", "Could not regenerate configuration file.", true, e);
}
}catch(Exception e){
Program.Reporter.HandleException("Configuration Error", "Could not reload configuration file.", true, e);
}
}
private void LoadInternal(bool backup){
Serializer.Read(backup ? GetBackupFile(file) : file, this);
}
public static UserConfig Load(string file){
Exception firstException = null;
for(int attempt = 0; attempt < 2; attempt++){
try{
UserConfig config = new UserConfig(file);
config.LoadInternal(attempt > 0);
return config;
}catch(FileNotFoundException){
}catch(DirectoryNotFoundException){
break;
}catch(Exception e){
if (attempt == 0){
firstException = e;
Program.Reporter.Log(e.ToString());
}
else if (firstException is FormatException){
Program.Reporter.HandleException("Configuration Error", "The configuration file is outdated or corrupted. If you continue, your program options will be reset.", true, e);
return new UserConfig(file);
}
else if (firstException != null){
Program.Reporter.HandleException("Configuration Error", "Could not open the backup configuration file. If you continue, your program options will be reset.", true, e);
return new UserConfig(file);
}
}
}
if (firstException != null){
Program.Reporter.HandleException("Configuration Error", "Could not open the configuration file.", true, firstException);
}
return new UserConfig(file);
}
public static string GetBackupFile(string file){
return file+".bak";
} }
} }
} }

View File

@@ -1,19 +0,0 @@
using System;
using System.Windows.Forms;
using TweetDuck.Core.Controls;
namespace TweetDuck.Core.Bridge{
sealed class CallbackBridge{
private readonly Control owner;
private readonly Action safeCallback;
public CallbackBridge(Control owner, Action safeCallback){
this.owner = owner;
this.safeCallback = safeCallback;
}
public void Trigger(){
owner.InvokeSafe(safeCallback);
}
}
}

View File

@@ -1,4 +1,5 @@
using System.Text; using System.Text;
using TweetDuck.Configuration;
namespace TweetDuck.Core.Bridge{ namespace TweetDuck.Core.Bridge{
static class PropertyBridge{ static class PropertyBridge{
@@ -7,24 +8,24 @@ namespace TweetDuck.Core.Bridge{
} }
public static string GenerateScript(Environment environment){ public static string GenerateScript(Environment environment){
string Bool(bool value){ string Bool(bool value) => value ? "true;" : "false;";
return value ? "true;" : "false;"; string Str(string value) => '"'+value+"\";";
}
StringBuilder build = new StringBuilder().Append("(function(x){"); UserConfig config = Program.Config.User;
StringBuilder build = new StringBuilder(128).Append("(function(x){");
build.Append("x.expandLinksOnHover=").Append(Bool(Program.UserConfig.ExpandLinksOnHover)); build.Append("x.expandLinksOnHover=").Append(Bool(config.ExpandLinksOnHover));
if (environment == Environment.Browser){ if (environment == Environment.Browser){
build.Append("x.switchAccountSelectors=").Append(Bool(Program.UserConfig.SwitchAccountSelectors)); build.Append("x.openSearchInFirstColumn=").Append(Bool(config.OpenSearchInFirstColumn));
build.Append("x.openSearchInFirstColumn=").Append(Bool(Program.UserConfig.OpenSearchInFirstColumn)); build.Append("x.keepLikeFollowDialogsOpen=").Append(Bool(config.KeepLikeFollowDialogsOpen));
build.Append("x.muteNotifications=").Append(Bool(Program.UserConfig.MuteNotifications)); build.Append("x.muteNotifications=").Append(Bool(config.MuteNotifications));
build.Append("x.hasCustomNotificationSound=").Append(Bool(Program.UserConfig.NotificationSoundPath.Length > 0)); build.Append("x.notificationMediaPreviews=").Append(Bool(config.NotificationMediaPreviews));
build.Append("x.notificationMediaPreviews=").Append(Bool(Program.UserConfig.NotificationMediaPreviews)); build.Append("x.translationTarget=").Append(Str(config.TranslationTarget));
} }
if (environment == Environment.Notification){ if (environment == Environment.Notification){
build.Append("x.skipOnLinkClick=").Append(Bool(Program.UserConfig.NotificationSkipOnLinkClick)); build.Append("x.skipOnLinkClick=").Append(Bool(config.NotificationSkipOnLinkClick));
} }
return build.Append("})(window.$TDX=window.$TDX||{})").ToString(); return build.Append("})(window.$TDX=window.$TDX||{})").ToString();

View File

@@ -1,55 +1,41 @@
using System.Collections.Generic; using System.Windows.Forms;
using System.Text;
using System.Windows.Forms;
using CefSharp;
using TweetDuck.Core.Controls; using TweetDuck.Core.Controls;
using TweetDuck.Core.Handling; using TweetDuck.Core.Management;
using TweetDuck.Core.Notification; using TweetDuck.Core.Notification;
using TweetDuck.Core.Other; using TweetDuck.Core.Other;
using TweetDuck.Core.Utils; using TweetDuck.Core.Utils;
using TweetDuck.Resources;
namespace TweetDuck.Core.Bridge{ namespace TweetDuck.Core.Bridge{
sealed class TweetDeckBridge{ class TweetDeckBridge{
public static string FontSize { get; private set; } public static string FontSize { get; private set; }
public static string NotificationHeadLayout { get; private set; } public static string NotificationHeadLayout { get; private set; }
public static readonly ContextInfo ContextInfo = new ContextInfo();
public static string LastHighlightedTweetUrl = string.Empty;
public static string LastHighlightedQuoteUrl = string.Empty;
private static string LastHighlightedTweetAuthors = string.Empty;
private static string LastHighlightedTweetImages = string.Empty;
public static string[] LastHighlightedTweetAuthorsArray => LastHighlightedTweetAuthors.Split(';');
public static string[] LastHighlightedTweetImagesArray => LastHighlightedTweetImages.Split(';');
private static readonly Dictionary<string, string> SessionData = new Dictionary<string, string>(2);
public static void ResetStaticProperties(){ public static void ResetStaticProperties(){
FontSize = NotificationHeadLayout = null; FontSize = NotificationHeadLayout = null;
LastHighlightedTweetUrl = LastHighlightedQuoteUrl = LastHighlightedTweetAuthors = LastHighlightedTweetImages = string.Empty;
}
public static void RestoreSessionData(IFrame frame){
if (SessionData.Count > 0){
StringBuilder build = new StringBuilder().Append("window.TD_SESSION={");
foreach(KeyValuePair<string, string> kvp in SessionData){
build.Append(kvp.Key).Append(":'").Append(kvp.Value.Replace("'", "\\'")).Append("',");
}
ScriptLoader.ExecuteScript(frame, build.Append("}").ToString(), "gen:session");
SessionData.Clear();
}
} }
private readonly FormBrowser form; private readonly FormBrowser form;
private readonly FormNotificationMain notification; private readonly FormNotificationMain notification;
public TweetDeckBridge(FormBrowser form, FormNotificationMain notification){ protected TweetDeckBridge(FormBrowser form, FormNotificationMain notification){
this.form = form; this.form = form;
this.notification = notification; this.notification = notification;
} }
// Browser only
public sealed class Browser : TweetDeckBridge{
public Browser(FormBrowser form, FormNotificationMain notification) : base(form, notification){}
public void OpenContextMenu(){
form.InvokeAsyncSafe(form.OpenContextMenu);
}
public void OpenProfileImport(){
form.InvokeAsyncSafe(form.OpenProfileImport);
}
public void OnIntroductionClosed(bool showGuide, bool allowDataCollection){ public void OnIntroductionClosed(bool showGuide, bool allowDataCollection){
form.InvokeAsyncSafe(() => { form.InvokeAsyncSafe(() => {
form.OnIntroductionClosed(showGuide, allowDataCollection); form.OnIntroductionClosed(showGuide, allowDataCollection);
@@ -63,22 +49,38 @@ namespace TweetDuck.Core.Bridge{
}); });
} }
public void SetLastRightClickInfo(string type, string link){ public void SetRightClickedLink(string type, string url){
form.InvokeAsyncSafe(() => ContextMenuBase.SetContextInfo(type, link)); ContextInfo.SetLink(type, url);
} }
public void SetLastHighlightedTweet(string tweetUrl, string quoteUrl, string authors, string imageList){ public void SetRightClickedChirp(string tweetUrl, string quoteUrl, string chirpAuthors, string chirpImages){
form.InvokeAsyncSafe(() => { ContextInfo.SetChirp(tweetUrl, quoteUrl, chirpAuthors, chirpImages);
LastHighlightedTweetUrl = tweetUrl;
LastHighlightedQuoteUrl = quoteUrl;
LastHighlightedTweetAuthors = authors;
LastHighlightedTweetImages = imageList;
});
} }
public void OpenContextMenu(){ public void DisplayTooltip(string text){
form.InvokeAsyncSafe(form.OpenContextMenu); form.InvokeAsyncSafe(() => form.DisplayTooltip(text));
} }
}
// Notification only
public sealed class Notification : TweetDeckBridge{
public Notification(FormBrowser form, FormNotificationMain notification) : base(form, notification){}
public void DisplayTooltip(string text){
notification.InvokeAsyncSafe(() => notification.DisplayTooltip(text));
}
public void LoadNextNotification(){
notification.InvokeAsyncSafe(notification.FinishCurrentNotification);
}
public void ShowTweetDetail(){
notification.InvokeAsyncSafe(notification.ShowTweetDetail);
}
}
// Global
public void OnTweetPopup(string columnId, string chirpId, string columnName, string tweetHtml, int tweetCharacters, string tweetUrl, string quoteUrl){ public void OnTweetPopup(string columnId, string chirpId, string columnName, string tweetHtml, int tweetCharacters, string tweetUrl, string quoteUrl){
notification.InvokeAsyncSafe(() => { notification.InvokeAsyncSafe(() => {
@@ -90,31 +92,12 @@ namespace TweetDuck.Core.Bridge{
public void OnTweetSound(){ public void OnTweetSound(){
form.InvokeAsyncSafe(() => { form.InvokeAsyncSafe(() => {
form.OnTweetNotification(); form.OnTweetNotification();
form.PlayNotificationSound(); form.OnTweetSound();
}); });
} }
public void DisplayTooltip(string text, bool showInNotification){ public void ScreenshotTweet(string html, int width){
if (showInNotification){ form.InvokeAsyncSafe(() => form.OnTweetScreenshotReady(html, width));
notification.InvokeAsyncSafe(() => notification.DisplayTooltip(text));
}
else{
form.InvokeAsyncSafe(() => form.DisplayTooltip(text));
}
}
public void SetSessionData(string key, string value){
form.InvokeSafe(() => { // do not use InvokeAsyncSafe, return only after invocation
SessionData.Add(key, value);
});
}
public void LoadNextNotification(){
notification.InvokeAsyncSafe(notification.FinishCurrentNotification);
}
public void ScreenshotTweet(string html, int width, int height){
form.InvokeAsyncSafe(() => form.OnTweetScreenshotReady(html, width, height));
} }
public void PlayVideo(string url, string username){ public void PlayVideo(string url, string username){
@@ -148,13 +131,9 @@ namespace TweetDuck.Core.Bridge{
public void CrashDebug(string message){ public void CrashDebug(string message){
#if DEBUG #if DEBUG
Log(message); System.Diagnostics.Debug.WriteLine(message);
System.Diagnostics.Debugger.Break(); System.Diagnostics.Debugger.Break();
#endif #endif
} }
public void Log(string data){
System.Diagnostics.Debug.WriteLine(data);
}
} }
} }

View File

@@ -0,0 +1,68 @@
using System;
using System.Windows.Forms;
using TweetDuck.Core.Controls;
using TweetDuck.Updates;
namespace TweetDuck.Core.Bridge{
class UpdateBridge{
private readonly UpdateHandler updates;
private readonly Control sync;
private UpdateInfo nextUpdate = null;
public event EventHandler<UpdateInfo> UpdateAccepted;
public event EventHandler<UpdateInfo> UpdateDelayed;
public event EventHandler<UpdateInfo> UpdateDismissed;
public UpdateBridge(UpdateHandler updates, Control sync){
this.sync = sync;
this.updates = updates;
this.updates.CheckFinished += updates_CheckFinished;
}
internal void Cleanup(){
updates.CheckFinished -= updates_CheckFinished;
nextUpdate?.DeleteInstaller();
}
private void updates_CheckFinished(object sender, UpdateCheckEventArgs e){
UpdateInfo foundUpdate = e.Result.HasValue ? e.Result.Value : null;
if (nextUpdate != null && !nextUpdate.Equals(foundUpdate)){
nextUpdate.DeleteInstaller();
}
nextUpdate = foundUpdate;
}
private void HandleInteractionEvent(EventHandler<UpdateInfo> eventHandler){
UpdateInfo tmpInfo = nextUpdate;
if (tmpInfo != null){
sync.InvokeAsyncSafe(() => eventHandler?.Invoke(this, tmpInfo));
}
}
// Bridge methods
public void TriggerUpdateCheck(){
updates.Check(false);
}
public void OnUpdateAccepted(){
HandleInteractionEvent(UpdateAccepted);
}
public void OnUpdateDelayed(){
HandleInteractionEvent(UpdateDelayed);
}
public void OnUpdateDismissed(){
HandleInteractionEvent(UpdateDismissed);
nextUpdate?.DeleteInstaller();
nextUpdate = null;
}
}
}

View File

@@ -7,7 +7,7 @@ namespace TweetDuck.Core.Controls{
public int LineHeight { get; set; } public int LineHeight { get; set; }
protected override void OnPaint(PaintEventArgs e){ protected override void OnPaint(PaintEventArgs e){
int y = (int)Math.Floor((ClientRectangle.Height-Text.Length*LineHeight)/2F)-2; // 2 = random int y = (int)Math.Floor((ClientRectangle.Height-Text.Length*LineHeight)/2F)-1;
using(Brush brush = new SolidBrush(ForeColor)){ using(Brush brush = new SolidBrush(ForeColor)){
foreach(char chr in Text){ foreach(char chr in Text){

View File

@@ -39,17 +39,17 @@
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
this.BackColor = TweetDuck.Core.Utils.TwitterUtils.BackgroundColor; this.BackColor = TweetDuck.Core.Utils.TwitterUtils.BackgroundColor;
this.ClientSize = new System.Drawing.Size(400, 386); this.ClientSize = new System.Drawing.Size(1008, 730);
this.Icon = Properties.Resources.icon; this.Icon = Properties.Resources.icon;
this.Location = TweetDuck.Core.Controls.ControlExtensions.InvisibleLocation; this.Location = TweetDuck.Core.Controls.ControlExtensions.InvisibleLocation;
this.MinimumSize = new System.Drawing.Size(416, 424); this.MinimumSize = new System.Drawing.Size(348, 424);
this.Name = "FormBrowser"; this.Name = "FormBrowser";
this.StartPosition = System.Windows.Forms.FormStartPosition.Manual; this.StartPosition = System.Windows.Forms.FormStartPosition.Manual;
this.Activated += new System.EventHandler(this.FormBrowser_Activated); this.Activated += new System.EventHandler(this.FormBrowser_Activated);
this.FormClosing += new System.Windows.Forms.FormClosingEventHandler(this.FormBrowser_FormClosing); this.FormClosing += new System.Windows.Forms.FormClosingEventHandler(this.FormBrowser_FormClosing);
this.FormClosed += new System.Windows.Forms.FormClosedEventHandler(this.FormBrowser_FormClosed); this.FormClosed += new System.Windows.Forms.FormClosedEventHandler(this.FormBrowser_FormClosed);
this.LocationChanged += new System.EventHandler(this.FormBrowser_LocationChanged);
this.ResizeEnd += new System.EventHandler(this.FormBrowser_ResizeEnd); this.ResizeEnd += new System.EventHandler(this.FormBrowser_ResizeEnd);
this.LocationChanged += new System.EventHandler(this.FormBrowser_LocationChanged);
this.Resize += new System.EventHandler(this.FormBrowser_Resize); this.Resize += new System.EventHandler(this.FormBrowser_Resize);
this.ResumeLayout(false); this.ResumeLayout(false);

View File

@@ -5,21 +5,22 @@ using TweetDuck.Configuration;
using TweetDuck.Core.Bridge; using TweetDuck.Core.Bridge;
using TweetDuck.Core.Controls; using TweetDuck.Core.Controls;
using TweetDuck.Core.Handling; using TweetDuck.Core.Handling;
using TweetDuck.Core.Handling.General;
using TweetDuck.Core.Management;
using TweetDuck.Core.Notification; using TweetDuck.Core.Notification;
using TweetDuck.Core.Notification.Screenshot; using TweetDuck.Core.Notification.Screenshot;
using TweetDuck.Core.Other; using TweetDuck.Core.Other;
using TweetDuck.Core.Other.Analytics; using TweetDuck.Core.Other.Analytics;
using TweetDuck.Core.Other.Management; using TweetDuck.Core.Other.Settings.Dialogs;
using TweetDuck.Core.Other.Settings;
using TweetDuck.Core.Utils; using TweetDuck.Core.Utils;
using TweetDuck.Plugins; using TweetDuck.Plugins;
using TweetDuck.Plugins.Events; using TweetDuck.Plugins.Events;
using TweetDuck.Resources;
using TweetDuck.Updates; using TweetDuck.Updates;
using TweetLib.Audio;
namespace TweetDuck.Core{ namespace TweetDuck.Core{
sealed partial class FormBrowser : Form{ sealed partial class FormBrowser : Form, AnalyticsFile.IProvider{
private static UserConfig Config => Program.UserConfig; private static UserConfig Config => Program.Config.User;
public bool IsWaiting{ public bool IsWaiting{
set{ set{
@@ -39,27 +40,30 @@ namespace TweetDuck.Core{
} }
public string UpdateInstallerPath { get; private set; } public string UpdateInstallerPath { get; private set; }
private bool ignoreUpdateCheckError;
public AnalyticsFile AnalyticsFile => analytics?.File ?? AnalyticsFile.Dummy;
private readonly TweetDeckBrowser browser; private readonly TweetDeckBrowser browser;
private readonly PluginManager plugins; private readonly PluginManager plugins;
private readonly UpdateHandler updates; private readonly UpdateHandler updates;
private readonly FormNotificationTweet notification; private readonly FormNotificationTweet notification;
private readonly ContextMenu contextMenu; private readonly ContextMenu contextMenu;
private readonly UpdateBridge updateBridge;
private bool isLoaded; private bool isLoaded;
private FormWindowState prevState; private FormWindowState prevState;
private TweetScreenshotManager notificationScreenshotManager; private TweetScreenshotManager notificationScreenshotManager;
private SoundNotification soundNotification;
private VideoPlayer videoPlayer; private VideoPlayer videoPlayer;
private AnalyticsManager analytics; private AnalyticsManager analytics;
public FormBrowser(UpdaterSettings updaterSettings){ public FormBrowser(){
InitializeComponent(); InitializeComponent();
Text = Program.BrandName; Text = Program.BrandName;
this.plugins = new PluginManager(Program.PluginPath, Program.PluginConfigFilePath); this.plugins = new PluginManager(Program.Config.Plugins, Program.PluginPath);
this.plugins.Reloaded += plugins_Reloaded; this.plugins.Reloaded += plugins_Reloaded;
this.plugins.Executed += plugins_Executed; this.plugins.Executed += plugins_Executed;
this.plugins.Reload(); this.plugins.Reload();
@@ -67,32 +71,47 @@ namespace TweetDuck.Core{
this.notification = new FormNotificationTweet(this, plugins); this.notification = new FormNotificationTweet(this, plugins);
this.notification.Show(); this.notification.Show();
this.browser = new TweetDeckBrowser(this, plugins, new TweetDeckBridge(this, notification)); this.updates = new UpdateHandler(Program.InstallerPath);
this.browser.PageLoaded += browser_PageLoaded; this.updates.CheckFinished += updates_CheckFinished;
this.updateBridge = new UpdateBridge(updates, this);
this.updateBridge.UpdateAccepted += updateBridge_UpdateAccepted;
this.updateBridge.UpdateDelayed += updateBridge_UpdateDelayed;
this.updateBridge.UpdateDismissed += updateBridge_UpdateDismissed;
this.browser = new TweetDeckBrowser(this, plugins, new TweetDeckBridge.Browser(this, notification), updateBridge);
this.contextMenu = ContextMenuBrowser.CreateMenu(this); this.contextMenu = ContextMenuBrowser.CreateMenu(this);
Controls.Add(new MenuStrip{ Visible = false }); // fixes Alt freezing the program in Win 10 Anniversary Update Controls.Add(new MenuStrip{ Visible = false }); // fixes Alt freezing the program in Win 10 Anniversary Update
Disposed += (sender, args) => { Disposed += (sender, args) => {
Config.MuteToggled -= Config_MuteToggled;
Config.TrayBehaviorChanged -= Config_TrayBehaviorChanged;
browser.Dispose(); browser.Dispose();
updates.Dispose();
contextMenu.Dispose(); contextMenu.Dispose();
notificationScreenshotManager?.Dispose(); notificationScreenshotManager?.Dispose();
soundNotification?.Dispose();
videoPlayer?.Dispose(); videoPlayer?.Dispose();
analytics?.Dispose(); analytics?.Dispose();
}; };
Config.MuteToggled += Config_MuteToggled;
this.trayIcon.ClickRestore += trayIcon_ClickRestore; this.trayIcon.ClickRestore += trayIcon_ClickRestore;
this.trayIcon.ClickClose += trayIcon_ClickClose; this.trayIcon.ClickClose += trayIcon_ClickClose;
Config.TrayBehaviorChanged += Config_TrayBehaviorChanged; Config.TrayBehaviorChanged += Config_TrayBehaviorChanged;
UpdateTrayIcon(); UpdateTray();
this.updates = browser.CreateUpdateHandler(updaterSettings); if (Config.MuteNotifications){
this.updates.UpdateAccepted += updates_UpdateAccepted; UpdateFormIcon();
this.updates.UpdateDismissed += updates_UpdateDismissed; }
if (Config.AllowDataCollection){
analytics = new AnalyticsManager(this, plugins, Program.AnalyticsFilePath);
}
RestoreWindow(); RestoreWindow();
} }
@@ -113,13 +132,13 @@ namespace TweetDuck.Core{
Config.BrowserWindow.Restore(this, true); Config.BrowserWindow.Restore(this, true);
prevState = WindowState; prevState = WindowState;
isLoaded = true; isLoaded = true;
if (Config.AllowDataCollection){
analytics = new AnalyticsManager(this, plugins, Program.AnalyticsFilePath);
}
} }
private void UpdateTrayIcon(){ private void UpdateFormIcon(){ // TODO fix to show icon in taskbar too
Icon = Config.MuteNotifications ? Properties.Resources.icon_muted : Properties.Resources.icon;
}
private void UpdateTray(){
trayIcon.Visible = Config.TrayBehavior.ShouldDisplayIcon(); trayIcon.Visible = Config.TrayBehavior.ShouldDisplayIcon();
} }
@@ -189,64 +208,37 @@ namespace TweetDuck.Core{
private void FormBrowser_FormClosed(object sender, FormClosedEventArgs e){ private void FormBrowser_FormClosed(object sender, FormClosedEventArgs e){
if (isLoaded && UpdateInstallerPath == null){ if (isLoaded && UpdateInstallerPath == null){
updates.CleanupDownload(); updateBridge.Cleanup();
} }
} }
private void Config_MuteToggled(object sender, EventArgs e){
UpdateFormIcon();
AnalyticsFile.NotificationMutes.Trigger();
}
private void Config_TrayBehaviorChanged(object sender, EventArgs e){ private void Config_TrayBehaviorChanged(object sender, EventArgs e){
UpdateTrayIcon(); UpdateTray();
} }
private void trayIcon_ClickRestore(object sender, EventArgs e){ private void trayIcon_ClickRestore(object sender, EventArgs e){
Show(); Show();
RestoreWindow(); RestoreWindow();
Activate(); Activate();
UpdateTrayIcon(); UpdateTray();
} }
private void trayIcon_ClickClose(object sender, EventArgs e){ private void trayIcon_ClickClose(object sender, EventArgs e){
ForceClose(); ForceClose();
} }
private void browser_PageLoaded(object sender, EventArgs e){
if (Config.ShowDataCollectionNotification){
this.InvokeAsyncSafe(() => {
if (!Config.FirstRun && Config.AllowDataCollection){
FormMessage form = new FormMessage("Anonymous Data Update", "Hi! You can now review your anonymous data report, and opt-out if you've changed your mind. Collected data will be used to focus development on most commonly used features. If you want to opt-out but still support the project, any feedback and donations are appreciated.", MessageBoxIcon.Information);
form.AddButton("OK", ControlType.Accept | ControlType.Focused);
Button btnReviewSettings = new Button{
Anchor = AnchorStyles.Bottom | AnchorStyles.Left,
Font = SystemFonts.MessageBoxFont,
Location = new Point(9, 12),
Margin = new Padding(0, 0, 48, 0),
Size = new Size(160, 26),
Text = "Review Feedback Options",
UseVisualStyleBackColor = true
};
btnReviewSettings.Click += (sender2, args2) => {
form.Close();
OpenSettings(typeof(TabSettingsFeedback));
};
form.AddActionControl(btnReviewSettings);
ShowChildForm(form);
}
Config.ShowDataCollectionNotification = false;
Config.Save();
});
}
}
private void plugins_Reloaded(object sender, PluginErrorEventArgs e){ private void plugins_Reloaded(object sender, PluginErrorEventArgs e){
if (e.HasErrors){ if (e.HasErrors){
FormMessage.Error("Error Loading Plugins", "The following plugins will not be available until the issues are resolved:\n\n"+string.Join("\n\n", e.Errors), FormMessage.OK); FormMessage.Error("Error Loading Plugins", "The following plugins will not be available until the issues are resolved:\n\n"+string.Join("\n\n", e.Errors), FormMessage.OK);
} }
if (isLoaded){ if (isLoaded){
ReloadToTweetDeck(); browser.ReloadToTweetDeck();
} }
} }
@@ -256,62 +248,92 @@ namespace TweetDuck.Core{
} }
} }
private void updates_UpdateAccepted(object sender, UpdateEventArgs e){ private void updates_CheckFinished(object sender, UpdateCheckEventArgs e){
this.InvokeAsyncSafe(() => { e.Result.Handle(update => {
string tag = update.VersionTag;
if (tag != Program.VersionTag && tag != Config.DismissedUpdate){
update.BeginSilentDownload();
browser.ShowUpdateNotification(tag, update.ReleaseNotes);
}
else{
updates.StartTimer();
}
}, ex => {
if (!ignoreUpdateCheckError){
Program.Reporter.HandleException("Update Check Error", "An error occurred while checking for updates.", true, ex);
updates.StartTimer();
}
});
ignoreUpdateCheckError = true;
}
private void updateBridge_UpdateAccepted(object sender, UpdateInfo update){
FormManager.CloseAllDialogs(); FormManager.CloseAllDialogs();
updates.BeginUpdateDownload(this, e.UpdateInfo, update => { if (!string.IsNullOrEmpty(Config.DismissedUpdate)){
if (update.DownloadStatus == UpdateDownloadStatus.Done){ Config.DismissedUpdate = null;
UpdateInstallerPath = update.InstallerPath;
}
ForceClose();
});
});
}
private void updates_UpdateDismissed(object sender, UpdateEventArgs e){
this.InvokeAsyncSafe(() => {
Config.DismissedUpdate = e.UpdateInfo.VersionTag;
Config.Save(); Config.Save();
});
} }
private void soundNotification_PlaybackError(object sender, PlaybackErrorEventArgs e){ void OnFinished(){
e.Ignore = true; UpdateDownloadStatus status = update.DownloadStatus;
using(FormMessage form = new FormMessage("Notification Sound Error", "Could not play custom notification sound.\n"+e.Message, MessageBoxIcon.Error)){ if (status == UpdateDownloadStatus.Done){
form.AddButton(FormMessage.Ignore, ControlType.Cancel | ControlType.Focused); UpdateInstallerPath = update.InstallerPath;
ForceClose();
Button btnOpenSettings = form.AddButton("View Options"); }
btnOpenSettings.Width += 16; else if (status != UpdateDownloadStatus.Canceled && FormMessage.Error("Update Has Failed", "Could not automatically download the update: "+(update.DownloadError?.Message ?? "unknown error")+"\n\nWould you like to open the website and try downloading the update manually?", FormMessage.Yes, FormMessage.No)){
btnOpenSettings.Location = new Point(btnOpenSettings.Location.X-16, btnOpenSettings.Location.Y); BrowserUtils.OpenExternalBrowser(Program.Website);
ForceClose();
if (form.ShowDialog() == DialogResult.OK && form.ClickedButton == btnOpenSettings){ }
OpenSettings(typeof(TabSettingsSounds)); else{
Show();
} }
} }
if (update.DownloadStatus.IsFinished(true)){
OnFinished();
}
else{
FormUpdateDownload downloadForm = new FormUpdateDownload(update);
downloadForm.VisibleChanged += (sender2, args2) => {
downloadForm.MoveToCenter(this);
Hide();
};
downloadForm.FormClosed += (sender2, args2) => {
if (downloadForm.DialogResult != DialogResult.OK){
update.CancelDownload();
}
downloadForm.Dispose();
OnFinished();
};
downloadForm.Show();
}
}
private void updateBridge_UpdateDelayed(object sender, UpdateInfo update){
// stops the timer
}
private void updateBridge_UpdateDismissed(object sender, UpdateInfo update){
Config.DismissedUpdate = update.VersionTag;
Config.Save();
} }
protected override void WndProc(ref Message m){ protected override void WndProc(ref Message m){
if (isLoaded){ if (isLoaded && m.Msg == Program.WindowRestoreMessage){
if (m.Msg == Program.WindowRestoreMessage){
if (WindowsUtils.CurrentProcessID == m.WParam.ToInt32()){ if (WindowsUtils.CurrentProcessID == m.WParam.ToInt32()){
trayIcon_ClickRestore(trayIcon, EventArgs.Empty); trayIcon_ClickRestore(trayIcon, EventArgs.Empty);
} }
return; return;
} }
else if (m.Msg == Program.SubProcessMessage){
int processId = m.WParam.ToInt32();
if (WindowsUtils.IsChildProcess(processId)){ // child process is checked in two places for safety
BrowserProcesses.Link(m.LParam.ToInt32(), processId);
}
return;
}
}
if (browser.Ready && m.Msg == NativeMethods.WM_PARENTNOTIFY && (m.WParam.ToInt32() & 0xFFFF) == NativeMethods.WM_XBUTTONDOWN){ if (browser.Ready && m.Msg == NativeMethods.WM_PARENTNOTIFY && (m.WParam.ToInt32() & 0xFFFF) == NativeMethods.WM_XBUTTONDOWN){
if (videoPlayer != null && videoPlayer.Running){ if (videoPlayer != null && videoPlayer.Running){
@@ -319,7 +341,7 @@ namespace TweetDuck.Core{
} }
else{ else{
browser.OnMouseClickExtra(m.WParam); browser.OnMouseClickExtra(m.WParam);
TriggerAnalyticsEvent(AnalyticsFile.Event.BrowserExtraMouseButton); AnalyticsFile.BrowserExtraMouseButtons.Trigger();
} }
return; return;
@@ -343,19 +365,42 @@ namespace TweetDuck.Core{
} }
public void ReloadToTweetDeck(){ public void ReloadToTweetDeck(){
#if DEBUG
ScriptLoader.HotSwap();
#else
if (ModifierKeys.HasFlag(Keys.Shift)){
ScriptLoader.ClearCache();
}
#endif
ignoreUpdateCheckError = false;
browser.ReloadToTweetDeck(); browser.ReloadToTweetDeck();
AnalyticsFile.BrowserReloads.Trigger();
}
public void AddSearchColumn(string query){
browser.AddSearchColumn(query);
} }
public void TriggerTweetScreenshot(){ public void TriggerTweetScreenshot(){
browser.TriggerTweetScreenshot(); browser.TriggerTweetScreenshot();
} }
public void ApplyROT13(){ public void ReloadColumns(){
browser.ApplyROT13(); browser.ReloadColumns();
} }
public void TriggerAnalyticsEvent(AnalyticsFile.Event e){ public void PlaySoundNotification(){
analytics?.TriggerEvent(e); browser.PlaySoundNotification();
}
public void ApplyROT13(){
browser.ApplyROT13();
AnalyticsFile.UsedROT13.Trigger();
}
public void OpenDevTools(){
browser.OpenDevTools();
} }
// callback handlers // callback handlers
@@ -364,7 +409,6 @@ namespace TweetDuck.Core{
if (Config.FirstRun){ if (Config.FirstRun){
Config.FirstRun = false; Config.FirstRun = false;
Config.AllowDataCollection = allowDataCollection; Config.AllowDataCollection = allowDataCollection;
Config.ShowDataCollectionNotification = false;
Config.Save(); Config.Save();
if (allowDataCollection && analytics == null){ if (allowDataCollection && analytics == null){
@@ -373,7 +417,7 @@ namespace TweetDuck.Core{
} }
if (showGuide){ if (showGuide){
ShowChildForm(new FormGuide()); FormGuide.Show();
} }
} }
@@ -403,8 +447,6 @@ namespace TweetDuck.Core{
trayIcon.HasNotifications = false; trayIcon.HasNotifications = false;
} }
browser.RefreshMemoryTracker();
if (Config.AllowDataCollection){ if (Config.AllowDataCollection){
if (analytics == null){ if (analytics == null){
analytics = new AnalyticsManager(this, plugins, Program.AnalyticsFilePath); analytics = new AnalyticsManager(this, plugins, Program.AnalyticsFilePath);
@@ -415,6 +457,8 @@ namespace TweetDuck.Core{
analytics = null; analytics = null;
} }
BrowserCache.RefreshTimer();
if (form.ShouldReloadBrowser){ if (form.ShouldReloadBrowser){
FormManager.TryFind<FormPlugins>()?.Close(); FormManager.TryFind<FormPlugins>()?.Close();
plugins.Reload(); // also reloads the browser plugins.Reload(); // also reloads the browser
@@ -427,45 +471,45 @@ namespace TweetDuck.Core{
form.Dispose(); form.Dispose();
}; };
TriggerAnalyticsEvent(AnalyticsFile.Event.OpenOptions); AnalyticsFile.OpenOptions.Trigger();
ShowChildForm(form); ShowChildForm(form);
} }
} }
public void OpenAbout(){ public void OpenAbout(){
if (!FormManager.TryBringToFront<FormAbout>()){ if (!FormManager.TryBringToFront<FormAbout>()){
TriggerAnalyticsEvent(AnalyticsFile.Event.OpenAbout); AnalyticsFile.OpenAbout.Trigger();
ShowChildForm(new FormAbout()); ShowChildForm(new FormAbout());
} }
} }
public void OpenPlugins(){ public void OpenPlugins(){
if (!FormManager.TryBringToFront<FormPlugins>()){ if (!FormManager.TryBringToFront<FormPlugins>()){
TriggerAnalyticsEvent(AnalyticsFile.Event.OpenPlugins); AnalyticsFile.OpenPlugins.Trigger();
ShowChildForm(new FormPlugins(plugins)); ShowChildForm(new FormPlugins(plugins));
} }
} }
public void OpenProfileImport(){
FormManager.TryFind<FormSettings>()?.Close();
using(DialogSettingsManage dialog = new DialogSettingsManage(plugins, true)){
if (dialog.ShowDialog() == DialogResult.OK && !dialog.IsRestarting){
BrowserProcessHandler.UpdatePrefs();
FormManager.TryFind<FormPlugins>()?.Close();
plugins.Reload(); // also reloads the browser
}
}
}
public void OnTweetNotification(){ // may be called multiple times, once for each type of notification public void OnTweetNotification(){ // may be called multiple times, once for each type of notification
if (Config.EnableTrayHighlight && !ContainsFocus){ if (Config.EnableTrayHighlight && !ContainsFocus){
trayIcon.HasNotifications = true; trayIcon.HasNotifications = true;
} }
} }
public void PlayNotificationSound(){ public void OnTweetSound(){
if (Config.NotificationSoundPath.Length == 0){ AnalyticsFile.SoundNotifications.Trigger();
return;
}
if (soundNotification == null){
soundNotification = new SoundNotification();
soundNotification.PlaybackError += soundNotification_PlaybackError;
}
soundNotification.SetVolume(Config.NotificationSoundVolume);
soundNotification.Play(Config.NotificationSoundPath);
TriggerAnalyticsEvent(AnalyticsFile.Event.SoundNotification);
} }
public void PlayVideo(string url, string username){ public void PlayVideo(string url, string username){
@@ -483,7 +527,7 @@ namespace TweetDuck.Core{
} }
videoPlayer.Launch(url, username); videoPlayer.Launch(url, username);
TriggerAnalyticsEvent(AnalyticsFile.Event.VideoPlay); AnalyticsFile.VideoPlays.Trigger();
} }
public bool ProcessBrowserKey(Keys key){ public bool ProcessBrowserKey(Keys key){
@@ -505,16 +549,16 @@ namespace TweetDuck.Core{
notification.FinishCurrentNotification(); notification.FinishCurrentNotification();
browser.ShowTweetDetail(columnId, chirpId, fallbackUrl); browser.ShowTweetDetail(columnId, chirpId, fallbackUrl);
TriggerAnalyticsEvent(AnalyticsFile.Event.TweetDetail); AnalyticsFile.TweetDetails.Trigger();
} }
public void OnTweetScreenshotReady(string html, int width, int height){ public void OnTweetScreenshotReady(string html, int width){
if (notificationScreenshotManager == null){ if (notificationScreenshotManager == null){
notificationScreenshotManager = new TweetScreenshotManager(this, plugins); notificationScreenshotManager = new TweetScreenshotManager(this, plugins);
} }
notificationScreenshotManager.Trigger(html, width, height); notificationScreenshotManager.Trigger(html, width);
TriggerAnalyticsEvent(AnalyticsFile.Event.TweetScreenshot); AnalyticsFile.TweetScreenshots.Trigger();
} }
public void DisplayTooltip(string text){ public void DisplayTooltip(string text){

View File

@@ -1,6 +1,5 @@
using System.Linq; using System.Linq;
using System.Windows.Forms; using System.Windows.Forms;
using TweetDuck.Core.Other;
namespace TweetDuck.Core{ namespace TweetDuck.Core{
static class FormManager{ static class FormManager{
@@ -18,12 +17,14 @@ namespace TweetDuck.Core{
else return false; else return false;
} }
public static bool HasAnyDialogs => Application.OpenForms.OfType<IAppDialog>().Any();
public static void CloseAllDialogs(){ public static void CloseAllDialogs(){
foreach(Form form in Application.OpenForms.Cast<Form>().Reverse()){ foreach(IAppDialog dialog in Application.OpenForms.OfType<IAppDialog>().Reverse()){
if (form is FormSettings || form is FormPlugins || form is FormAbout || form is FormGuide){ ((Form)dialog).Close();
form.Close();
}
} }
} }
public interface IAppDialog{}
} }
} }

View File

@@ -1,33 +1,23 @@
using System; using System;
using System.IO;
using System.Text.RegularExpressions; using System.Text.RegularExpressions;
using System.Windows.Forms; using System.Windows.Forms;
using CefSharp; using CefSharp;
using TweetDuck.Core.Bridge;
using TweetDuck.Core.Controls; using TweetDuck.Core.Controls;
using TweetDuck.Core.Utils; using TweetDuck.Core.Utils;
using System.Collections.Generic;
using System.Linq; using System.Linq;
using TweetDuck.Configuration;
using TweetDuck.Core.Bridge;
using TweetDuck.Core.Management;
using TweetDuck.Core.Notification;
using TweetDuck.Core.Other; using TweetDuck.Core.Other;
using TweetDuck.Core.Other.Analytics;
using TweetDuck.Resources;
namespace TweetDuck.Core.Handling{ namespace TweetDuck.Core.Handling{
abstract class ContextMenuBase : IContextMenuHandler{ abstract class ContextMenuBase : IContextMenuHandler{
protected static readonly bool HasDevTools = File.Exists(Path.Combine(Program.ProgramPath, "devtools_resources.pak")); protected static UserConfig Config => Program.Config.User;
private static TwitterUtils.ImageQuality ImageQuality => Program.UserConfig.TwitterImageQuality; private static TwitterUtils.ImageQuality ImageQuality => Config.TwitterImageQuality;
private static KeyValuePair<string, string> ContextInfo;
private static bool IsLink => ContextInfo.Key == "link";
private static bool IsImage => ContextInfo.Key == "image";
private static bool IsVideo => ContextInfo.Key == "video";
public static void SetContextInfo(string type, string link){
ContextInfo = new KeyValuePair<string, string>(string.IsNullOrEmpty(link) ? null : type, link);
}
private static string GetMediaLink(IContextMenuParams parameters){
return IsImage || IsVideo ? ContextInfo.Value : parameters.SourceUrl;
}
private const CefMenuCommand MenuOpenLinkUrl = (CefMenuCommand)26500; private const CefMenuCommand MenuOpenLinkUrl = (CefMenuCommand)26500;
private const CefMenuCommand MenuCopyLinkUrl = (CefMenuCommand)26501; private const CefMenuCommand MenuCopyLinkUrl = (CefMenuCommand)26501;
@@ -37,31 +27,39 @@ namespace TweetDuck.Core.Handling{
private const CefMenuCommand MenuCopyMediaUrl = (CefMenuCommand)26505; private const CefMenuCommand MenuCopyMediaUrl = (CefMenuCommand)26505;
private const CefMenuCommand MenuSaveMedia = (CefMenuCommand)26506; private const CefMenuCommand MenuSaveMedia = (CefMenuCommand)26506;
private const CefMenuCommand MenuSaveTweetImages = (CefMenuCommand)26507; private const CefMenuCommand MenuSaveTweetImages = (CefMenuCommand)26507;
private const CefMenuCommand MenuSearchInBrowser = (CefMenuCommand)26508;
private const CefMenuCommand MenuReadApplyROT13 = (CefMenuCommand)26509;
private const CefMenuCommand MenuOpenDevTools = (CefMenuCommand)26599; private const CefMenuCommand MenuOpenDevTools = (CefMenuCommand)26599;
private string[] lastHighlightedTweetAuthors; protected ContextInfo.ContextData Context { get; private set; }
private string[] lastHighlightedTweetImageList;
private readonly AnalyticsFile.IProvider analytics;
protected ContextMenuBase(AnalyticsFile.IProvider analytics){
this.analytics = analytics;
}
public virtual void OnBeforeContextMenu(IWebBrowser browserControl, IBrowser browser, IFrame frame, IContextMenuParams parameters, IMenuModel model){ public virtual void OnBeforeContextMenu(IWebBrowser browserControl, IBrowser browser, IFrame frame, IContextMenuParams parameters, IMenuModel model){
if (!TwitterUtils.IsTweetDeckWebsite(frame) || browser.IsLoading){ if (!TwitterUtils.IsTweetDeckWebsite(frame) || browser.IsLoading){
lastHighlightedTweetAuthors = StringUtils.EmptyArray; Context = TweetDeckBridge.ContextInfo.Reset();
lastHighlightedTweetImageList = StringUtils.EmptyArray;
ContextInfo = default(KeyValuePair<string, string>);
} }
else{ else{
lastHighlightedTweetAuthors = TweetDeckBridge.LastHighlightedTweetAuthorsArray; Context = TweetDeckBridge.ContextInfo.Create(parameters);
lastHighlightedTweetImageList = TweetDeckBridge.LastHighlightedTweetImagesArray;
} }
bool hasTweetImage = IsImage; if (parameters.TypeFlags.HasFlag(ContextMenuType.Selection) && !parameters.TypeFlags.HasFlag(ContextMenuType.Editable)){
bool hasTweetVideo = IsVideo; model.AddItem(MenuSearchInBrowser, "Search in browser");
model.AddSeparator();
model.AddItem(MenuReadApplyROT13, "Apply ROT13");
model.AddSeparator();
}
string TextOpen(string name) => "Open "+name+" in browser"; string TextOpen(string name) => "Open "+name+" in browser";
string TextCopy(string name) => "Copy "+name+" address"; string TextCopy(string name) => "Copy "+name+" address";
string TextSave(string name) => "Save "+name+" as..."; string TextSave(string name) => "Save "+name+" as...";
if (parameters.TypeFlags.HasFlag(ContextMenuType.Link) && !parameters.UnfilteredLinkUrl.EndsWith("tweetdeck.twitter.com/#", StringComparison.Ordinal) && !hasTweetImage && !hasTweetVideo){ if (Context.Types.HasFlag(ContextInfo.ContextType.Link) && !Context.UnsafeLinkUrl.EndsWith("tweetdeck.twitter.com/#", StringComparison.Ordinal)){
if (TwitterUtils.RegexAccount.IsMatch(parameters.UnfilteredLinkUrl)){ if (TwitterUtils.RegexAccount.IsMatch(Context.UnsafeLinkUrl)){
model.AddItem(MenuOpenLinkUrl, TextOpen("account")); model.AddItem(MenuOpenLinkUrl, TextOpen("account"));
model.AddItem(MenuCopyLinkUrl, TextCopy("account")); model.AddItem(MenuCopyLinkUrl, TextCopy("account"));
model.AddItem(MenuCopyUsername, "Copy account username"); model.AddItem(MenuCopyUsername, "Copy account username");
@@ -74,19 +72,19 @@ namespace TweetDuck.Core.Handling{
model.AddSeparator(); model.AddSeparator();
} }
if (hasTweetVideo){ if (Context.Types.HasFlag(ContextInfo.ContextType.Video)){
model.AddItem(MenuOpenMediaUrl, TextOpen("video")); model.AddItem(MenuOpenMediaUrl, TextOpen("video"));
model.AddItem(MenuCopyMediaUrl, TextCopy("video")); model.AddItem(MenuCopyMediaUrl, TextCopy("video"));
model.AddItem(MenuSaveMedia, TextSave("video")); model.AddItem(MenuSaveMedia, TextSave("video"));
model.AddSeparator(); model.AddSeparator();
} }
else if ((parameters.TypeFlags.HasFlag(ContextMenuType.Media) && parameters.HasImageContents) || hasTweetImage){ else if (Context.Types.HasFlag(ContextInfo.ContextType.Image) && Context.MediaUrl != TweetNotification.AppLogo.Url){
model.AddItem(MenuViewImage, "View image in photo viewer"); model.AddItem(MenuViewImage, "View image in photo viewer");
model.AddItem(MenuOpenMediaUrl, TextOpen("image")); model.AddItem(MenuOpenMediaUrl, TextOpen("image"));
model.AddItem(MenuCopyMediaUrl, TextCopy("image")); model.AddItem(MenuCopyMediaUrl, TextCopy("image"));
model.AddItem(MenuSaveMedia, TextSave("image")); model.AddItem(MenuSaveMedia, TextSave("image"));
if (lastHighlightedTweetImageList.Length > 1){ if (Context.Chirp.Images.Length > 1){
model.AddItem(MenuSaveTweetImages, TextSave("all images")); model.AddItem(MenuSaveTweetImages, TextSave("all images"));
} }
@@ -95,66 +93,86 @@ namespace TweetDuck.Core.Handling{
} }
public virtual bool OnContextMenuCommand(IWebBrowser browserControl, IBrowser browser, IFrame frame, IContextMenuParams parameters, CefMenuCommand commandId, CefEventFlags eventFlags){ public virtual bool OnContextMenuCommand(IWebBrowser browserControl, IBrowser browser, IFrame frame, IContextMenuParams parameters, CefMenuCommand commandId, CefEventFlags eventFlags){
Control control = browserControl.AsControl();
switch(commandId){ switch(commandId){
case MenuOpenLinkUrl: case MenuOpenLinkUrl:
OpenBrowser(browserControl.AsControl(), IsLink ? ContextInfo.Value : parameters.LinkUrl); OpenBrowser(control, Context.LinkUrl);
break; break;
case MenuCopyLinkUrl: case MenuCopyLinkUrl:
SetClipboardText(browserControl.AsControl(), IsLink ? ContextInfo.Value : parameters.UnfilteredLinkUrl); SetClipboardText(control, Context.UnsafeLinkUrl);
break; break;
case MenuCopyUsername: case MenuCopyUsername: {
Match match = TwitterUtils.RegexAccount.Match(parameters.UnfilteredLinkUrl); string url = Context.UnsafeLinkUrl;
SetClipboardText(browserControl.AsControl(), match.Success ? match.Groups[1].Value : parameters.UnfilteredLinkUrl); Match match = TwitterUtils.RegexAccount.Match(url);
SetClipboardText(control, match.Success ? match.Groups[1].Value : url);
control.InvokeAsyncSafe(analytics.AnalyticsFile.CopiedUsernames.Trigger);
break; break;
}
case MenuOpenMediaUrl: case MenuOpenMediaUrl:
OpenBrowser(browserControl.AsControl(), TwitterUtils.GetMediaLink(GetMediaLink(parameters), ImageQuality)); OpenBrowser(control, TwitterUtils.GetMediaLink(Context.MediaUrl, ImageQuality));
break; break;
case MenuCopyMediaUrl: case MenuCopyMediaUrl:
SetClipboardText(browserControl.AsControl(), TwitterUtils.GetMediaLink(GetMediaLink(parameters), ImageQuality)); SetClipboardText(control, TwitterUtils.GetMediaLink(Context.MediaUrl, ImageQuality));
break; break;
case MenuViewImage: case MenuViewImage: {
string url = GetMediaLink(parameters); string url = Context.MediaUrl;
string file = Path.Combine(BrowserCache.CacheFolder, TwitterUtils.GetImageFileName(url));
void ViewFile(){ control.InvokeAsyncSafe(() => {
string ext = Path.GetExtension(file); TwitterUtils.ViewImage(url, ImageQuality);
analytics.AnalyticsFile.ViewedImages.Trigger();
if (TwitterUtils.ValidImageExtensions.Contains(ext)){
WindowsUtils.OpenAssociatedProgram(file);
}
else{
FormMessage.Error("Image Download", "Invalid file extension "+ext, FormMessage.OK);
}
}
if (File.Exists(file)){
ViewFile();
}
else{
BrowserUtils.DownloadFileAsync(TwitterUtils.GetMediaLink(url, ImageQuality), file, ViewFile, ex => {
FormMessage.Error("Image Download", "An error occurred while downloading the image: "+ex.Message, FormMessage.OK);
}); });
}
break; break;
}
case MenuSaveMedia: case MenuSaveMedia: {
if (IsVideo){ bool isVideo = Context.Types.HasFlag(ContextInfo.ContextType.Video);
TwitterUtils.DownloadVideo(GetMediaLink(parameters), lastHighlightedTweetAuthors.LastOrDefault()); string url = Context.MediaUrl;
string username = Context.Chirp.Authors.LastOrDefault();
control.InvokeAsyncSafe(() => {
if (isVideo){
TwitterUtils.DownloadVideo(url, username);
analytics.AnalyticsFile.DownloadedVideos.Trigger();
} }
else{ else{
TwitterUtils.DownloadImage(GetMediaLink(parameters), lastHighlightedTweetAuthors.LastOrDefault(), ImageQuality); TwitterUtils.DownloadImage(url, username, ImageQuality);
analytics.AnalyticsFile.DownloadedImages.Trigger();
} }
});
break; break;
}
case MenuSaveTweetImages: case MenuSaveTweetImages: {
TwitterUtils.DownloadImages(lastHighlightedTweetImageList, lastHighlightedTweetAuthors.LastOrDefault(), ImageQuality); string[] urls = Context.Chirp.Images;
string username = Context.Chirp.Authors.LastOrDefault();
control.InvokeAsyncSafe(() => {
TwitterUtils.DownloadImages(urls, username, ImageQuality);
analytics.AnalyticsFile.DownloadedImages.Trigger();
});
break;
}
case MenuReadApplyROT13:
string selection = parameters.SelectionText;
control.InvokeAsyncSafe(() => FormMessage.Information("ROT13", StringUtils.ConvertRot13(selection), FormMessage.OK));
control.InvokeAsyncSafe(analytics.AnalyticsFile.UsedROT13.Trigger);
return true;
case MenuSearchInBrowser:
string query = parameters.SelectionText;
control.InvokeAsyncSafe(() => BrowserUtils.OpenExternalSearch(query));
DeselectAll(frame);
break; break;
case MenuOpenDevTools: case MenuOpenDevTools:
@@ -166,24 +184,35 @@ namespace TweetDuck.Core.Handling{
} }
public virtual void OnContextMenuDismissed(IWebBrowser browserControl, IBrowser browser, IFrame frame){ public virtual void OnContextMenuDismissed(IWebBrowser browserControl, IBrowser browser, IFrame frame){
ContextInfo = default(KeyValuePair<string, string>); Context = TweetDeckBridge.ContextInfo.Reset();
} }
public virtual bool RunContextMenu(IWebBrowser browserControl, IBrowser browser, IFrame frame, IContextMenuParams parameters, IMenuModel model, IRunContextMenuCallback callback){ public virtual bool RunContextMenu(IWebBrowser browserControl, IBrowser browser, IFrame frame, IContextMenuParams parameters, IMenuModel model, IRunContextMenuCallback callback){
return false; return false;
} }
protected void OpenBrowser(Control control, string url){ protected static void DeselectAll(IFrame frame){
ScriptLoader.ExecuteScript(frame, "window.getSelection().removeAllRanges()", "gen:deselect");
}
protected static void OpenBrowser(Control control, string url){
control.InvokeAsyncSafe(() => BrowserUtils.OpenExternalBrowser(url)); control.InvokeAsyncSafe(() => BrowserUtils.OpenExternalBrowser(url));
} }
protected void SetClipboardText(Control control, string text){ protected static void SetClipboardText(Control control, string text){
control.InvokeAsyncSafe(() => WindowsUtils.SetClipboard(text, TextDataFormat.UnicodeText)); control.InvokeAsyncSafe(() => WindowsUtils.SetClipboard(text, TextDataFormat.UnicodeText));
} }
protected static void InsertSelectionSearchItem(IMenuModel model, CefMenuCommand insertCommand, string insertLabel){
model.InsertItemAt(model.GetIndexOf(MenuSearchInBrowser)+1, insertCommand, insertLabel);
}
protected static void AddDebugMenuItems(IMenuModel model){ protected static void AddDebugMenuItems(IMenuModel model){
if (BrowserUtils.HasDevTools){
AddSeparator(model);
model.AddItem(MenuOpenDevTools, "Open dev tools"); model.AddItem(MenuOpenDevTools, "Open dev tools");
} }
}
protected static void RemoveSeparatorIfLast(IMenuModel model){ protected static void RemoveSeparatorIfLast(IMenuModel model){
if (model.Count > 0 && model.GetTypeAt(model.Count-1) == MenuItemType.Separator){ if (model.Count > 0 && model.GetTypeAt(model.Count-1) == MenuItemType.Separator){

View File

@@ -1,8 +1,7 @@
using CefSharp; using CefSharp;
using System.Windows.Forms; using System.Windows.Forms;
using TweetDuck.Core.Bridge;
using TweetDuck.Core.Controls; using TweetDuck.Core.Controls;
using TweetDuck.Core.Other.Analytics; using TweetDuck.Core.Management;
using TweetDuck.Core.Utils; using TweetDuck.Core.Utils;
namespace TweetDuck.Core.Handling{ namespace TweetDuck.Core.Handling{
@@ -18,7 +17,8 @@ namespace TweetDuck.Core.Handling{
private const CefMenuCommand MenuOpenQuotedTweetUrl = (CefMenuCommand)26612; private const CefMenuCommand MenuOpenQuotedTweetUrl = (CefMenuCommand)26612;
private const CefMenuCommand MenuCopyQuotedTweetUrl = (CefMenuCommand)26613; private const CefMenuCommand MenuCopyQuotedTweetUrl = (CefMenuCommand)26613;
private const CefMenuCommand MenuScreenshotTweet = (CefMenuCommand)26614; private const CefMenuCommand MenuScreenshotTweet = (CefMenuCommand)26614;
private const CefMenuCommand MenuInputApplyROT13 = (CefMenuCommand)26615; private const CefMenuCommand MenuWriteApplyROT13 = (CefMenuCommand)26615;
private const CefMenuCommand MenuSearchInColumn = (CefMenuCommand)26616;
private const string TitleReloadBrowser = "Reload browser"; private const string TitleReloadBrowser = "Reload browser";
private const string TitleMuteNotifications = "Mute notifications"; private const string TitleMuteNotifications = "Mute notifications";
@@ -28,24 +28,24 @@ namespace TweetDuck.Core.Handling{
private readonly FormBrowser form; private readonly FormBrowser form;
private string lastHighlightedTweetUrl; public ContextMenuBrowser(FormBrowser form) : base(form){
private string lastHighlightedQuoteUrl;
public ContextMenuBrowser(FormBrowser form){
this.form = form; this.form = form;
} }
public override void OnBeforeContextMenu(IWebBrowser browserControl, IBrowser browser, IFrame frame, IContextMenuParams parameters, IMenuModel model){ public override void OnBeforeContextMenu(IWebBrowser browserControl, IBrowser browser, IFrame frame, IContextMenuParams parameters, IMenuModel model){
bool isSelecting = parameters.TypeFlags.HasFlag(ContextMenuType.Selection);
bool isEditing = parameters.TypeFlags.HasFlag(ContextMenuType.Editable);
model.Remove(CefMenuCommand.Back); model.Remove(CefMenuCommand.Back);
model.Remove(CefMenuCommand.Forward); model.Remove(CefMenuCommand.Forward);
model.Remove(CefMenuCommand.Print); model.Remove(CefMenuCommand.Print);
model.Remove(CefMenuCommand.ViewSource); model.Remove(CefMenuCommand.ViewSource);
RemoveSeparatorIfLast(model); RemoveSeparatorIfLast(model);
if (parameters.TypeFlags.HasFlag(ContextMenuType.Selection)){ if (isSelecting){
if (parameters.TypeFlags.HasFlag(ContextMenuType.Editable)){ if (isEditing){
model.AddSeparator(); model.AddSeparator();
model.AddItem(MenuInputApplyROT13, "Apply ROT13"); model.AddItem(MenuWriteApplyROT13, "Apply ROT13");
} }
model.AddSeparator(); model.AddSeparator();
@@ -53,20 +53,16 @@ namespace TweetDuck.Core.Handling{
base.OnBeforeContextMenu(browserControl, browser, frame, parameters, model); base.OnBeforeContextMenu(browserControl, browser, frame, parameters, model);
lastHighlightedTweetUrl = TweetDeckBridge.LastHighlightedTweetUrl; if (isSelecting && !isEditing && TwitterUtils.IsTweetDeckWebsite(frame)){
lastHighlightedQuoteUrl = TweetDeckBridge.LastHighlightedQuoteUrl; InsertSelectionSearchItem(model, MenuSearchInColumn, "Search in a column");
if (!TwitterUtils.IsTweetDeckWebsite(frame) || browser.IsLoading){
lastHighlightedTweetUrl = string.Empty;
lastHighlightedQuoteUrl = string.Empty;
} }
if (!string.IsNullOrEmpty(lastHighlightedTweetUrl) && (parameters.TypeFlags & (ContextMenuType.Editable | ContextMenuType.Selection)) == 0){ if (Context.Types.HasFlag(ContextInfo.ContextType.Chirp) && !isSelecting && !isEditing){
model.AddItem(MenuOpenTweetUrl, "Open tweet in browser"); model.AddItem(MenuOpenTweetUrl, "Open tweet in browser");
model.AddItem(MenuCopyTweetUrl, "Copy tweet address"); model.AddItem(MenuCopyTweetUrl, "Copy tweet address");
model.AddItem(MenuScreenshotTweet, "Screenshot tweet to clipboard"); model.AddItem(MenuScreenshotTweet, "Screenshot tweet to clipboard");
if (!string.IsNullOrEmpty(lastHighlightedQuoteUrl)){ if (!string.IsNullOrEmpty(Context.Chirp.QuoteUrl)){
model.AddSeparator(); model.AddSeparator();
model.AddItem(MenuOpenQuotedTweetUrl, "Open quoted tweet in browser"); model.AddItem(MenuOpenQuotedTweetUrl, "Open quoted tweet in browser");
model.AddItem(MenuCopyQuotedTweetUrl, "Copy quoted tweet address"); model.AddItem(MenuCopyQuotedTweetUrl, "Copy quoted tweet address");
@@ -75,29 +71,26 @@ namespace TweetDuck.Core.Handling{
model.AddSeparator(); model.AddSeparator();
} }
if ((parameters.TypeFlags & (ContextMenuType.Editable | ContextMenuType.Selection)) == 0){ if (!isSelecting && !isEditing){
AddSeparator(model); AddSeparator(model);
IMenuModel globalMenu = model.Count == 0 ? model : model.AddSubMenu(MenuGlobal, Program.BrandName); IMenuModel globalMenu = model.Count == 0 ? model : model.AddSubMenu(MenuGlobal, Program.BrandName);
globalMenu.AddItem(CefMenuCommand.Reload, TitleReloadBrowser); globalMenu.AddItem(CefMenuCommand.Reload, TitleReloadBrowser);
globalMenu.AddCheckItem(MenuMute, TitleMuteNotifications); globalMenu.AddCheckItem(MenuMute, TitleMuteNotifications);
globalMenu.SetChecked(MenuMute, Program.UserConfig.MuteNotifications); globalMenu.SetChecked(MenuMute, Config.MuteNotifications);
globalMenu.AddSeparator(); globalMenu.AddSeparator();
globalMenu.AddItem(MenuSettings, TitleSettings); globalMenu.AddItem(MenuSettings, TitleSettings);
globalMenu.AddItem(MenuPlugins, TitlePlugins); globalMenu.AddItem(MenuPlugins, TitlePlugins);
globalMenu.AddItem(MenuAbout, TitleAboutProgram); globalMenu.AddItem(MenuAbout, TitleAboutProgram);
if (HasDevTools){
globalMenu.AddSeparator();
AddDebugMenuItems(globalMenu); AddDebugMenuItems(globalMenu);
} }
}
RemoveSeparatorIfLast(model); RemoveSeparatorIfLast(model);
form.InvokeAsyncSafe(() => form.TriggerAnalyticsEvent(AnalyticsFile.Event.BrowserContextMenu)); form.InvokeAsyncSafe(form.AnalyticsFile.BrowserContextMenus.Trigger);
} }
public override bool OnContextMenuCommand(IWebBrowser browserControl, IBrowser browser, IFrame frame, IContextMenuParams parameters, CefMenuCommand commandId, CefEventFlags eventFlags){ public override bool OnContextMenuCommand(IWebBrowser browserControl, IBrowser browser, IFrame frame, IContextMenuParams parameters, CefMenuCommand commandId, CefEventFlags eventFlags){
@@ -127,11 +120,11 @@ namespace TweetDuck.Core.Handling{
return true; return true;
case MenuOpenTweetUrl: case MenuOpenTweetUrl:
OpenBrowser(form, lastHighlightedTweetUrl); OpenBrowser(form, Context.Chirp.TweetUrl);
return true; return true;
case MenuCopyTweetUrl: case MenuCopyTweetUrl:
SetClipboardText(form, lastHighlightedTweetUrl); SetClipboardText(form, Context.Chirp.TweetUrl);
return true; return true;
case MenuScreenshotTweet: case MenuScreenshotTweet:
@@ -139,16 +132,22 @@ namespace TweetDuck.Core.Handling{
return true; return true;
case MenuOpenQuotedTweetUrl: case MenuOpenQuotedTweetUrl:
OpenBrowser(form, lastHighlightedQuoteUrl); OpenBrowser(form, Context.Chirp.QuoteUrl);
return true; return true;
case MenuCopyQuotedTweetUrl: case MenuCopyQuotedTweetUrl:
SetClipboardText(form, lastHighlightedQuoteUrl); SetClipboardText(form, Context.Chirp.QuoteUrl);
return true; return true;
case MenuInputApplyROT13: case MenuWriteApplyROT13:
form.InvokeAsyncSafe(form.ApplyROT13); form.InvokeAsyncSafe(form.ApplyROT13);
return true; return true;
case MenuSearchInColumn:
string query = parameters.SelectionText;
form.InvokeAsyncSafe(() => form.AddSearchColumn(query));
DeselectAll(frame);
break;
} }
return false; return false;
@@ -165,16 +164,16 @@ namespace TweetDuck.Core.Handling{
menu.MenuItems.Add(TitleAboutProgram, (sender, args) => form.OpenAbout()); menu.MenuItems.Add(TitleAboutProgram, (sender, args) => form.OpenAbout());
menu.Popup += (sender, args) => { menu.Popup += (sender, args) => {
menu.MenuItems[1].Checked = Program.UserConfig.MuteNotifications; menu.MenuItems[1].Checked = Config.MuteNotifications;
form.TriggerAnalyticsEvent(AnalyticsFile.Event.BrowserContextMenu); form.AnalyticsFile.BrowserContextMenus.Trigger();
}; };
return menu; return menu;
} }
private static void ToggleMuteNotifications(){ private static void ToggleMuteNotifications(){
Program.UserConfig.MuteNotifications = !Program.UserConfig.MuteNotifications; Config.MuteNotifications = !Config.MuteNotifications;
Program.UserConfig.Save(); Config.Save();
} }
} }
} }

View File

@@ -1,15 +1,14 @@
using CefSharp; using CefSharp;
using TweetDuck.Core.Other.Analytics;
namespace TweetDuck.Core.Handling{ namespace TweetDuck.Core.Handling{
sealed class ContextMenuGuide : ContextMenuBase{ sealed class ContextMenuGuide : ContextMenuBase{
public ContextMenuGuide(AnalyticsFile.IProvider analytics) : base(analytics){}
public override void OnBeforeContextMenu(IWebBrowser browserControl, IBrowser browser, IFrame frame, IContextMenuParams parameters, IMenuModel model){ public override void OnBeforeContextMenu(IWebBrowser browserControl, IBrowser browser, IFrame frame, IContextMenuParams parameters, IMenuModel model){
model.Clear(); model.Clear();
base.OnBeforeContextMenu(browserControl, browser, frame, parameters, model); base.OnBeforeContextMenu(browserControl, browser, frame, parameters, model);
if (HasDevTools){
AddSeparator(model);
AddDebugMenuItems(model); AddDebugMenuItems(model);
} }
} }
} }
}

View File

@@ -1,7 +1,6 @@
using CefSharp; using CefSharp;
using TweetDuck.Core.Controls; using TweetDuck.Core.Controls;
using TweetDuck.Core.Notification; using TweetDuck.Core.Notification;
using TweetDuck.Core.Other.Analytics;
namespace TweetDuck.Core.Handling{ namespace TweetDuck.Core.Handling{
sealed class ContextMenuNotification : ContextMenuBase{ sealed class ContextMenuNotification : ContextMenuBase{
@@ -14,7 +13,7 @@ namespace TweetDuck.Core.Handling{
private readonly FormNotificationBase form; private readonly FormNotificationBase form;
private readonly bool enableCustomMenu; private readonly bool enableCustomMenu;
public ContextMenuNotification(FormNotificationBase form, bool enableCustomMenu){ public ContextMenuNotification(FormNotificationBase form, bool enableCustomMenu) : base(form){
this.form = form; this.form = form;
this.enableCustomMenu = enableCustomMenu; this.enableCustomMenu = enableCustomMenu;
} }
@@ -48,16 +47,12 @@ namespace TweetDuck.Core.Handling{
} }
} }
if (HasDevTools){
AddSeparator(model);
AddDebugMenuItems(model); AddDebugMenuItems(model);
}
RemoveSeparatorIfLast(model); RemoveSeparatorIfLast(model);
form.InvokeAsyncSafe(() => { form.InvokeAsyncSafe(() => {
form.ContextMenuOpen = true; form.ContextMenuOpen = true;
form.TriggerAnalyticsEvent(AnalyticsFile.Event.NotificationContextMenu); form.AnalyticsFile.NotificationContextMenus.Trigger();
}); });
} }

View File

@@ -1,13 +1,22 @@
using System.Collections.Generic; using System.Collections.Generic;
using CefSharp; using CefSharp;
using CefSharp.Enums;
namespace TweetDuck.Core.Handling{ namespace TweetDuck.Core.Handling{
sealed class DragHandlerBrowser : IDragHandler{ sealed class DragHandlerBrowser : IDragHandler{
private readonly RequestHandlerBrowser requestHandler;
public DragHandlerBrowser(RequestHandlerBrowser requestHandler){
this.requestHandler = requestHandler;
}
public bool OnDragEnter(IWebBrowser browserControl, IBrowser browser, IDragData dragData, DragOperationsMask mask){ public bool OnDragEnter(IWebBrowser browserControl, IBrowser browser, IDragData dragData, DragOperationsMask mask){
void TriggerDragStart(string type, string data = null){ void TriggerDragStart(string type, string data = null){
browserControl.ExecuteScriptAsync("window.TDGF_onGlobalDragStart", type, data); browserControl.ExecuteScriptAsync("window.TDGF_onGlobalDragStart", type, data);
} }
requestHandler.BlockNextUserNavUrl = dragData.LinkUrl; // empty if not a link
if (dragData.IsLink){ if (dragData.IsLink){
TriggerDragStart("link", dragData.LinkUrl); TriggerDragStart("link", dragData.LinkUrl);
} }

View File

@@ -0,0 +1,72 @@
using System;
using System.IO;
using System.Text;
using CefSharp;
namespace TweetDuck.Core.Handling.Filters{
abstract class ResponseFilterBase : IResponseFilter{
private enum State{
Reading, Writing, Done
}
private readonly Encoding encoding;
private byte[] responseData;
private State state;
private int offset;
protected ResponseFilterBase(int totalBytes, Encoding encoding){
this.responseData = new byte[totalBytes];
this.encoding = encoding;
this.state = State.Reading;
}
FilterStatus IResponseFilter.Filter(Stream dataIn, out long dataInRead, Stream dataOut, out long dataOutWritten){
int responseLength = responseData.Length;
if (state == State.Reading){
int bytesToRead = Math.Min(responseLength-offset, (int)Math.Min(dataIn?.Length ?? 0, int.MaxValue));
dataIn?.Read(responseData, offset, bytesToRead);
offset += bytesToRead;
dataInRead = bytesToRead;
dataOutWritten = 0;
if (offset >= responseLength){
responseData = encoding.GetBytes(ProcessResponse(encoding.GetString(responseData)));
state = State.Writing;
offset = 0;
}
return FilterStatus.NeedMoreData;
}
else if (state == State.Writing){
int bytesToWrite = Math.Min(responseLength-offset, (int)Math.Min(dataOut.Length, int.MaxValue));
if (bytesToWrite > 0){
dataOut.Write(responseData, offset, bytesToWrite);
offset += bytesToWrite;
}
dataOutWritten = bytesToWrite;
dataInRead = 0;
if (offset < responseLength){
return FilterStatus.NeedMoreData;
}
else{
state = State.Done;
return FilterStatus.Done;
}
}
else{
throw new InvalidOperationException("This resource filter cannot be reused.");
}
}
public abstract bool InitFilter();
protected abstract string ProcessResponse(string text);
public abstract void Dispose();
}
}

View File

@@ -0,0 +1,20 @@
using System.Text;
using System.Text.RegularExpressions;
namespace TweetDuck.Core.Handling.Filters{
sealed class ResponseFilterVendor : ResponseFilterBase{
private static readonly Regex RegexRestoreJQuery = new Regex(@"(\w+)\.fn=\1\.prototype", RegexOptions.Compiled);
public ResponseFilterVendor(int totalBytes) : base(totalBytes, Encoding.UTF8){}
public override bool InitFilter(){
return true;
}
protected override string ProcessResponse(string text){
return RegexRestoreJQuery.Replace(text, "window.$$=$1;$&", 1);
}
public override void Dispose(){}
}
}

View File

@@ -1,12 +1,26 @@
using System; using System;
using System.Threading.Tasks;
using CefSharp; using CefSharp;
using TweetDuck.Configuration;
namespace TweetDuck.Core.Handling.General{ namespace TweetDuck.Core.Handling.General{
sealed class BrowserProcessHandler : IBrowserProcessHandler{ sealed class BrowserProcessHandler : IBrowserProcessHandler{
void IBrowserProcessHandler.OnContextInitialized(){ public static Task UpdatePrefs(){
using(IRequestContext ctx = Cef.GetGlobalRequestContext()){ return Cef.UIThreadTaskFactory.StartNew(UpdatePrefsInternal);
ctx.SetPreference("browser.enable_spellchecking", Program.UserConfig.EnableSpellCheck, out string _);
} }
private static void UpdatePrefsInternal(){
UserConfig config = Program.Config.User;
using(IRequestContext ctx = Cef.GetGlobalRequestContext()){
ctx.SetPreference("browser.enable_spellchecking", config.EnableSpellCheck, out string _);
ctx.SetPreference("spellcheck.dictionary", config.SpellCheckLanguage, out string _);
ctx.SetPreference("settings.a11y.animation_policy", config.EnableAnimatedImages ? "allowed" : "none", out string _);
}
}
void IBrowserProcessHandler.OnContextInitialized(){
UpdatePrefsInternal();
} }
void IBrowserProcessHandler.OnScheduleMessagePumpWork(long delay){} void IBrowserProcessHandler.OnScheduleMessagePumpWork(long delay){}

View File

@@ -7,16 +7,14 @@ using CefSharp;
namespace TweetDuck.Core.Handling.General{ namespace TweetDuck.Core.Handling.General{
sealed class FileDialogHandler : IDialogHandler{ sealed class FileDialogHandler : IDialogHandler{
public bool OnFileDialog(IWebBrowser browserControl, IBrowser browser, CefFileDialogMode mode, string title, string defaultFilePath, List<string> acceptFilters, int selectedAcceptFilter, IFileDialogCallback callback){ public bool OnFileDialog(IWebBrowser browserControl, IBrowser browser, CefFileDialogMode mode, CefFileDialogFlags flags, string title, string defaultFilePath, List<string> acceptFilters, int selectedAcceptFilter, IFileDialogCallback callback){
CefFileDialogMode dialogType = mode & CefFileDialogMode.TypeMask; if (mode == CefFileDialogMode.Open || mode == CefFileDialogMode.OpenMultiple){
if (dialogType == CefFileDialogMode.Open || dialogType == CefFileDialogMode.OpenMultiple){
string allFilters = string.Join(";", acceptFilters.Select(filter => "*"+filter)); string allFilters = string.Join(";", acceptFilters.Select(filter => "*"+filter));
using(OpenFileDialog dialog = new OpenFileDialog{ using(OpenFileDialog dialog = new OpenFileDialog{
AutoUpgradeEnabled = true, AutoUpgradeEnabled = true,
DereferenceLinks = true, DereferenceLinks = true,
Multiselect = dialogType == CefFileDialogMode.OpenMultiple, Multiselect = mode == CefFileDialogMode.OpenMultiple,
Title = "Open Files", Title = "Open Files",
Filter = $"All Supported Formats ({allFilters})|{allFilters}|All Files (*.*)|*.*" Filter = $"All Supported Formats ({allFilters})|{allFilters}|All Files (*.*)|*.*"
}){ }){

View File

@@ -1,7 +1,6 @@
using System.Drawing; using System.Drawing;
using System.Windows.Forms; using System.Windows.Forms;
using CefSharp; using CefSharp;
using CefSharp.WinForms;
using TweetDuck.Core.Controls; using TweetDuck.Core.Controls;
using TweetDuck.Core.Other; using TweetDuck.Core.Other;
using TweetDuck.Core.Utils; using TweetDuck.Core.Utils;
@@ -28,7 +27,7 @@ namespace TweetDuck.Core.Handling.General{
} }
bool IJsDialogHandler.OnJSDialog(IWebBrowser browserControl, IBrowser browser, string originUrl, CefJsDialogType dialogType, string messageText, string defaultPromptText, IJsDialogCallback callback, ref bool suppressMessage){ bool IJsDialogHandler.OnJSDialog(IWebBrowser browserControl, IBrowser browser, string originUrl, CefJsDialogType dialogType, string messageText, string defaultPromptText, IJsDialogCallback callback, ref bool suppressMessage){
((ChromiumWebBrowser)browserControl).InvokeSafe(() => { browserControl.AsControl().InvokeSafe(() => {
FormMessage form; FormMessage form;
TextBox input = null; TextBox input = null;
@@ -51,8 +50,9 @@ namespace TweetDuck.Core.Handling.General{
input = new TextBox{ input = new TextBox{
Anchor = AnchorStyles.Left | AnchorStyles.Right | AnchorStyles.Bottom, Anchor = AnchorStyles.Left | AnchorStyles.Right | AnchorStyles.Bottom,
Font = SystemFonts.MessageBoxFont,
Location = new Point(BrowserUtils.Scale(22+inputPad, dpiScale), form.ActionPanelY-BrowserUtils.Scale(46, dpiScale)), Location = new Point(BrowserUtils.Scale(22+inputPad, dpiScale), form.ActionPanelY-BrowserUtils.Scale(46, dpiScale)),
Size = new Size(form.ClientSize.Width-BrowserUtils.Scale(44+inputPad, dpiScale), 20) Size = new Size(form.ClientSize.Width-BrowserUtils.Scale(44+inputPad, dpiScale), BrowserUtils.Scale(23, dpiScale))
}; };
form.Controls.Add(input); form.Controls.Add(input);

View File

@@ -4,9 +4,7 @@ using TweetDuck.Core.Utils;
namespace TweetDuck.Core.Handling.General{ namespace TweetDuck.Core.Handling.General{
sealed class LifeSpanHandler : ILifeSpanHandler{ sealed class LifeSpanHandler : ILifeSpanHandler{
public bool OnBeforePopup(IWebBrowser browserControl, IBrowser browser, IFrame frame, string targetUrl, string targetFrameName, WindowOpenDisposition targetDisposition, bool userGesture, IPopupFeatures popupFeatures, IWindowInfo windowInfo, IBrowserSettings browserSettings, ref bool noJavascriptAccess, out IWebBrowser newBrowser){ public static bool HandleLinkClick(IWebBrowser browserControl, WindowOpenDisposition targetDisposition, string targetUrl){
newBrowser = null;
switch(targetDisposition){ switch(targetDisposition){
case WindowOpenDisposition.NewBackgroundTab: case WindowOpenDisposition.NewBackgroundTab:
case WindowOpenDisposition.NewForegroundTab: case WindowOpenDisposition.NewForegroundTab:
@@ -20,6 +18,11 @@ namespace TweetDuck.Core.Handling.General{
} }
} }
public bool OnBeforePopup(IWebBrowser browserControl, IBrowser browser, IFrame frame, string targetUrl, string targetFrameName, WindowOpenDisposition targetDisposition, bool userGesture, IPopupFeatures popupFeatures, IWindowInfo windowInfo, IBrowserSettings browserSettings, ref bool noJavascriptAccess, out IWebBrowser newBrowser){
newBrowser = null;
return HandleLinkClick(browserControl, targetDisposition, targetUrl);
}
public void OnAfterCreated(IWebBrowser browserControl, IBrowser browser){} public void OnAfterCreated(IWebBrowser browserControl, IBrowser browser){}
public bool DoClose(IWebBrowser browserControl, IBrowser browser){ public bool DoClose(IWebBrowser browserControl, IBrowser browser){

View File

@@ -1,68 +0,0 @@
using System.Security.Cryptography.X509Certificates;
using CefSharp;
namespace TweetDuck.Core.Handling.General{
abstract class RequestHandlerBase : IRequestHandler{
// Browser
public virtual void OnRenderViewReady(IWebBrowser browserControl, IBrowser browser){}
public virtual void OnRenderProcessTerminated(IWebBrowser browserControl, IBrowser browser, CefTerminationStatus status){}
public virtual bool OnBeforeBrowse(IWebBrowser browserControl, IBrowser browser, IFrame frame, IRequest request, bool isRedirect){
return false;
}
public virtual bool OnOpenUrlFromTab(IWebBrowser browserControl, IBrowser browser, IFrame frame, string targetUrl, WindowOpenDisposition targetDisposition, bool userGesture){
return false;
}
public virtual bool OnProtocolExecution(IWebBrowser browserControl, IBrowser browser, string url){
return false;
}
// Resources
public virtual CefReturnValue OnBeforeResourceLoad(IWebBrowser browserControl, IBrowser browser, IFrame frame, IRequest request, IRequestCallback callback){
return CefReturnValue.Continue;
}
public virtual void OnResourceRedirect(IWebBrowser browserControl, IBrowser browser, IFrame frame, IRequest request, IResponse response, ref string newUrl){}
public virtual bool OnResourceResponse(IWebBrowser browserControl, IBrowser browser, IFrame frame, IRequest request, IResponse response){
return false;
}
public virtual IResponseFilter GetResourceResponseFilter(IWebBrowser browserControl, IBrowser browser, IFrame frame, IRequest request, IResponse response){
return null;
}
public virtual void OnResourceLoadComplete(IWebBrowser browserControl, IBrowser browser, IFrame frame, IRequest request, IResponse response, UrlRequestStatus status, long receivedContentLength){}
// JavaScript & Plugins
public virtual bool OnQuotaRequest(IWebBrowser browserControl, IBrowser browser, string originUrl, long newSize, IRequestCallback callback){
callback.Dispose();
return false;
}
public virtual void OnPluginCrashed(IWebBrowser browserControl, IBrowser browser, string pluginPath){}
// Auth
public virtual bool GetAuthCredentials(IWebBrowser browserControl, IBrowser browser, IFrame frame, bool isProxy, string host, int port, string realm, string scheme, IAuthCallback callback){
callback.Dispose();
return false;
}
public virtual bool OnSelectClientCertificate(IWebBrowser browserControl, IBrowser browser, bool isProxy, string host, int port, X509Certificate2Collection certificates, ISelectClientCertificateCallback callback){
callback.Dispose();
return false;
}
public virtual bool OnCertificateError(IWebBrowser browserControl, IBrowser browser, CefErrorCode errorCode, string requestUrl, ISslInfo sslInfo, IRequestCallback callback){
callback.Dispose();
return false;
}
}
}

View File

@@ -2,7 +2,6 @@
using System.Windows.Forms; using System.Windows.Forms;
using TweetDuck.Core.Controls; using TweetDuck.Core.Controls;
using TweetDuck.Core.Notification; using TweetDuck.Core.Notification;
using TweetDuck.Core.Other.Analytics;
namespace TweetDuck.Core.Handling { namespace TweetDuck.Core.Handling {
sealed class KeyboardHandlerNotification : IKeyboardHandler{ sealed class KeyboardHandlerNotification : IKeyboardHandler{
@@ -13,7 +12,7 @@ namespace TweetDuck.Core.Handling {
} }
private void TriggerKeyboardShortcutAnalytics(){ private void TriggerKeyboardShortcutAnalytics(){
notification.InvokeAsyncSafe(() => notification.TriggerAnalyticsEvent(AnalyticsFile.Event.NotificationKeyboardShortcut)); notification.InvokeAsyncSafe(notification.AnalyticsFile.NotificationKeyboardShortcuts.Trigger);
} }
bool IKeyboardHandler.OnPreKeyEvent(IWebBrowser browserControl, IBrowser browser, KeyType type, int windowsKeyCode, int nativeKeyCode, CefEventFlags modifiers, bool isSystemKey, ref bool isKeyboardShortcut){ bool IKeyboardHandler.OnPreKeyEvent(IWebBrowser browserControl, IBrowser browser, KeyType type, int windowsKeyCode, int nativeKeyCode, CefEventFlags modifiers, bool isSystemKey, ref bool isKeyboardShortcut){

View File

@@ -0,0 +1,35 @@
using System.Collections.Specialized;
using CefSharp;
using CefSharp.Handler;
using TweetDuck.Core.Handling.General;
using TweetDuck.Core.Utils;
namespace TweetDuck.Core.Handling{
class RequestHandlerBase : DefaultRequestHandler{
private readonly bool autoReload;
public RequestHandlerBase(bool autoReload){
this.autoReload = autoReload;
}
public override bool OnOpenUrlFromTab(IWebBrowser browserControl, IBrowser browser, IFrame frame, string targetUrl, WindowOpenDisposition targetDisposition, bool userGesture){
return LifeSpanHandler.HandleLinkClick(browserControl, targetDisposition, targetUrl);
}
public override CefReturnValue OnBeforeResourceLoad(IWebBrowser browserControl, IBrowser browser, IFrame frame, IRequest request, IRequestCallback callback){
if (BrowserUtils.HasDevTools){
NameValueCollection headers = request.Headers;
headers.Remove("x-devtools-emulate-network-conditions-client-id");
request.Headers = headers;
}
return base.OnBeforeResourceLoad(browserControl, browser, frame, request, callback);
}
public override void OnRenderProcessTerminated(IWebBrowser browserControl, IBrowser browser, CefTerminationStatus status){
if (autoReload){
browser.Reload();
}
}
}
}

View File

@@ -1,18 +1,96 @@
using CefSharp; // Uncomment to force TweetDeck to load a predefined version of the vendor/bundle scripts
using TweetDuck.Core.Handling.General; // #define FREEZE_TWEETDECK_SCRIPTS
using System.Collections.Specialized;
using CefSharp;
using TweetDuck.Core.Handling.Filters;
using TweetDuck.Core.Utils;
#if FREEZE_TWEETDECK_SCRIPTS
using System.Collections.Generic;
using System.Text.RegularExpressions;
#endif
namespace TweetDuck.Core.Handling{ namespace TweetDuck.Core.Handling{
sealed class RequestHandlerBrowser : RequestHandlerBase{ sealed class RequestHandlerBrowser : RequestHandlerBase{
public override void OnRenderProcessTerminated(IWebBrowser browserControl, IBrowser browser, CefTerminationStatus status){ public string BlockNextUserNavUrl { get; set; }
browser.Reload();
} public RequestHandlerBrowser() : base(true){}
public override CefReturnValue OnBeforeResourceLoad(IWebBrowser browserControl, IBrowser browser, IFrame frame, IRequest request, IRequestCallback callback){ public override CefReturnValue OnBeforeResourceLoad(IWebBrowser browserControl, IBrowser browser, IFrame frame, IRequest request, IRequestCallback callback){
if (request.ResourceType == ResourceType.Script && request.Url.Contains("analytics.")){ if (request.ResourceType == ResourceType.Script && request.Url.Contains("analytics.")){
callback.Dispose();
return CefReturnValue.Cancel; return CefReturnValue.Cancel;
} }
return CefReturnValue.Continue; return base.OnBeforeResourceLoad(browserControl, browser, frame, request, callback);
}
public override bool OnBeforeBrowse(IWebBrowser browserControl, IBrowser browser, IFrame frame, IRequest request, bool userGesture, bool isRedirect){
if (userGesture && request.TransitionType == TransitionType.LinkClicked){
bool block = request.Url == BlockNextUserNavUrl;
BlockNextUserNavUrl = string.Empty;
return block;
}
return base.OnBeforeBrowse(browserControl, browser, frame, request, userGesture, isRedirect);
}
#if FREEZE_TWEETDECK_SCRIPTS
private static readonly Regex TweetDeckScriptUrl = new Regex(@"/dist/(.*?)\.(.*?)\.js$", RegexOptions.Compiled);
private static readonly SortedList<string, string> TweetDeckHashes = new SortedList<string, string>(2){
{ "vendor", "942c0a20e8" },
{ "bundle", "1bd75b5854" }
};
#endif
public override bool OnResourceResponse(IWebBrowser browserControl, IBrowser browser, IFrame frame, IRequest request, IResponse response){
if (request.ResourceType == ResourceType.Image && request.Url.Contains("/backgrounds/spinner_blue")){
request.Url = TwitterUtils.LoadingSpinner.Url;
return true;
}
#if FREEZE_TWEETDECK_SCRIPTS
else if (request.ResourceType == ResourceType.Script){
Match match = TweetDeckScriptUrl.Match(request.Url);
if (match.Success && TweetDeckHashes.TryGetValue(match.Groups[1].Value, out string hash)){
if (match.Groups[2].Value == hash){
System.Diagnostics.Debug.WriteLine($"accepting {request.Url}");
}
else{
System.Diagnostics.Debug.WriteLine($"rewriting {request.Url} to {hash}");
request.Url = TweetDeckScriptUrl.Replace(request.Url, "/dist/$1."+hash+".js");
return true;
}
}
}
#endif
return base.OnResourceResponse(browserControl, browser, frame, request, response);
}
public override IResponseFilter GetResourceResponseFilter(IWebBrowser browserControl, IBrowser browser, IFrame frame, IRequest request, IResponse response){
if (request.ResourceType == ResourceType.Script && request.Url.Contains("/dist/vendor")){
NameValueCollection headers = response.ResponseHeaders;
if (int.TryParse(headers["x-ton-expected-size"], out int totalBytes)){
return new ResponseFilterVendor(totalBytes);
}
#if DEBUG
else{
System.Diagnostics.Debug.WriteLine($"Missing uncompressed size header in {request.Url}");
foreach(string key in headers){
System.Diagnostics.Debug.WriteLine($" {key}: {headers[key]}");
}
System.Diagnostics.Debugger.Break();
}
#endif
}
return base.GetResourceResponseFilter(browserControl, browser, frame, request, response);
} }
} }
} }

View File

@@ -0,0 +1,72 @@
using System;
using System.IO;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
namespace TweetDuck.Core.Management{
static class BrowserCache{
public static string CacheFolder => Path.Combine(Program.StoragePath, "Cache");
private static bool ClearOnExit;
private static Timer AutoClearTimer;
private static long CalculateCacheSize(){
return new DirectoryInfo(CacheFolder).EnumerateFiles().Select(file => {
try{
return file.Length;
}catch{
return 0L;
}
}).Sum();
}
public static void GetCacheSize(Action<Task<long>> callbackBytes){
Task<long> task = new Task<long>(CalculateCacheSize);
task.ContinueWith(callbackBytes);
task.Start();
}
public static void RefreshTimer(){
bool shouldRun = Program.Config.System.ClearCacheAutomatically && !ClearOnExit;
if (!shouldRun && AutoClearTimer != null){
AutoClearTimer.Dispose();
AutoClearTimer = null;
}
else if (shouldRun && AutoClearTimer == null){
AutoClearTimer = new Timer(state => {
if (AutoClearTimer != null){
try{
if (CalculateCacheSize() >= Program.Config.System.ClearCacheThreshold*1024L*1024L){
SetClearOnExit();
}
}catch(Exception){
// TODO should probably log errors and report them at some point
}
}
}, null, TimeSpan.FromSeconds(30), TimeSpan.FromHours(4));
}
}
public static void SetClearOnExit(){
ClearOnExit = true;
RefreshTimer();
}
public static void Exit(){
if (AutoClearTimer != null){
AutoClearTimer.Dispose();
AutoClearTimer = null;
}
if (ClearOnExit){
try{
Directory.Delete(CacheFolder, true);
}catch{
// welp, too bad
}
}
}
}
}

View File

@@ -0,0 +1,161 @@
using System;
using CefSharp;
using TweetDuck.Core.Utils;
namespace TweetDuck.Core.Management{
sealed class ContextInfo{
private LinkInfo link;
private ChirpInfo? chirp;
public ContextInfo(){
Reset();
}
public void SetLink(string type, string url){
link = string.IsNullOrEmpty(url) ? null : new LinkInfo(type, url);
}
public void SetChirp(string tweetUrl, string quoteUrl, string chirpAuthors, string chirpImages){
chirp = string.IsNullOrEmpty(tweetUrl) ? (ChirpInfo?)null : new ChirpInfo(tweetUrl, quoteUrl, chirpAuthors, chirpImages);
}
public ContextData Reset(){
link = null;
chirp = null;
return ContextData.Empty;
}
public ContextData Create(IContextMenuParams parameters){
ContextData.Builder builder = new ContextData.Builder();
builder.AddContext(parameters);
if (link != null){
builder.AddOverride(link.Type, link.Url);
}
if (chirp.HasValue){
builder.AddChirp(chirp.Value);
}
return builder.Build();
}
// Data structures
private sealed class LinkInfo{
public string Type { get; }
public string Url { get; }
public LinkInfo(string type, string url){
this.Type = type;
this.Url = url;
}
}
public struct ChirpInfo{
public string TweetUrl { get; }
public string QuoteUrl { get; }
public string[] Authors => chirpAuthors?.Split(';') ?? StringUtils.EmptyArray;
public string[] Images => chirpImages?.Split(';') ?? StringUtils.EmptyArray;
private readonly string chirpAuthors;
private readonly string chirpImages;
public ChirpInfo(string tweetUrl, string quoteUrl, string chirpAuthors, string chirpImages){
this.TweetUrl = tweetUrl;
this.QuoteUrl = quoteUrl;
this.chirpAuthors = chirpAuthors;
this.chirpImages = chirpImages;
}
}
// Constructed context
[Flags]
public enum ContextType{
Unknown = 0,
Link = 0b0001,
Image = 0b0010,
Video = 0b0100,
Chirp = 0b1000
}
public sealed class ContextData{
public static readonly ContextData Empty = new Builder().Build();
public ContextType Types { get; }
public string LinkUrl { get; }
public string UnsafeLinkUrl { get; }
public string MediaUrl { get; }
public ChirpInfo Chirp { get; }
public ContextData(ContextType types, string linkUrl, string unsafeLinkUrl, string mediaUrl, ChirpInfo chirp){
Types = types;
LinkUrl = linkUrl;
UnsafeLinkUrl = unsafeLinkUrl;
MediaUrl = mediaUrl;
Chirp = chirp;
}
public sealed class Builder{
private ContextType types = ContextType.Unknown;
private string linkUrl = string.Empty;
private string unsafeLinkUrl = string.Empty;
private string mediaUrl = string.Empty;
private ChirpInfo chirp = default(ChirpInfo);
public void AddContext(IContextMenuParams parameters){
ContextMenuType flags = parameters.TypeFlags;
if (flags.HasFlag(ContextMenuType.Media) && parameters.HasImageContents){
types |= ContextType.Image;
types &= ~ContextType.Video;
mediaUrl = parameters.SourceUrl;
}
if (flags.HasFlag(ContextMenuType.Link)){
types |= ContextType.Link;
linkUrl = parameters.LinkUrl;
unsafeLinkUrl = parameters.UnfilteredLinkUrl;
}
}
public void AddOverride(string type, string url){
switch(type){
case "link":
types |= ContextType.Link;
linkUrl = url;
unsafeLinkUrl = url;
break;
case "image":
types |= ContextType.Image;
types &= ~(ContextType.Video | ContextType.Link);
mediaUrl = url;
break;
case "video":
types |= ContextType.Video;
types &= ~(ContextType.Image | ContextType.Link);
mediaUrl = url;
break;
}
}
public void AddChirp(ChirpInfo chirp){
this.types |= ContextType.Chirp;
this.chirp = chirp;
}
public ContextData Build(){
return new ContextData(types, linkUrl, unsafeLinkUrl, mediaUrl, chirp);
}
}
}
}
}

View File

@@ -2,38 +2,46 @@
using System.Collections.Generic; using System.Collections.Generic;
using System.IO; using System.IO;
using System.Linq; using System.Linq;
using TweetDuck.Core.Other;
using TweetDuck.Data; using TweetDuck.Data;
using TweetDuck.Plugins; using TweetDuck.Plugins;
using TweetDuck.Plugins.Enums; using TweetDuck.Plugins.Enums;
namespace TweetDuck.Core.Other.Settings.Export{ namespace TweetDuck.Core.Management{
sealed class ExportManager{ sealed class ProfileManager{
private static readonly string CookiesPath = Path.Combine(Program.StoragePath, "Cookies"); private static readonly string CookiesPath = Path.Combine(Program.StoragePath, "Cookies");
private static readonly string TempCookiesPath = Path.Combine(Program.StoragePath, "CookiesTmp"); private static readonly string TempCookiesPath = Path.Combine(Program.StoragePath, "CookiesTmp");
public bool IsRestarting { get; private set; } [Flags]
public Exception LastException { get; private set; } public enum Items{
None = 0,
UserConfig = 1,
SystemConfig = 2,
Session = 4,
PluginData = 8,
All = UserConfig|SystemConfig|Session|PluginData
}
private readonly string file; private readonly string file;
private readonly PluginManager plugins; private readonly PluginManager plugins;
public ExportManager(string file, PluginManager plugins){ public ProfileManager(string file, PluginManager plugins){
this.file = file; this.file = file;
this.plugins = plugins; this.plugins = plugins;
} }
public bool Export(ExportFileFlags flags){ public bool Export(Items items){
try{ try{
using(CombinedFileStream stream = new CombinedFileStream(new FileStream(file, FileMode.Create, FileAccess.Write, FileShare.None))){ using(CombinedFileStream stream = new CombinedFileStream(new FileStream(file, FileMode.Create, FileAccess.Write, FileShare.None))){
if (flags.HasFlag(ExportFileFlags.UserConfig)){ if (items.HasFlag(Items.UserConfig)){
stream.WriteFile("config", Program.UserConfigFilePath); stream.WriteFile("config", Program.UserConfigFilePath);
} }
if (flags.HasFlag(ExportFileFlags.SystemConfig)){ if (items.HasFlag(Items.SystemConfig)){
stream.WriteFile("system", Program.SystemConfigFilePath); stream.WriteFile("system", Program.SystemConfigFilePath);
} }
if (flags.HasFlag(ExportFileFlags.PluginData)){ if (items.HasFlag(Items.PluginData)){
stream.WriteFile("plugin.config", Program.PluginConfigFilePath); stream.WriteFile("plugin.config", Program.PluginConfigFilePath);
foreach(Plugin plugin in plugins.Plugins){ foreach(Plugin plugin in plugins.Plugins){
@@ -47,7 +55,7 @@ namespace TweetDuck.Core.Other.Settings.Export{
} }
} }
if (flags.HasFlag(ExportFileFlags.Session)){ if (items.HasFlag(Items.Session)){
stream.WriteFile("cookies", CookiesPath); stream.WriteFile("cookies", CookiesPath);
} }
@@ -56,13 +64,13 @@ namespace TweetDuck.Core.Other.Settings.Export{
return true; return true;
}catch(Exception e){ }catch(Exception e){
LastException = e; Program.Reporter.HandleException("Profile Export Error", "An exception happened while exporting TweetDuck profile.", true, e);
return false; return false;
} }
} }
public ExportFileFlags GetImportFlags(){ public Items FindImportItems(){
ExportFileFlags flags = ExportFileFlags.None; Items items = Items.None;
try{ try{
using(CombinedFileStream stream = new CombinedFileStream(new FileStream(file, FileMode.Open, FileAccess.Read, FileShare.None))){ using(CombinedFileStream stream = new CombinedFileStream(new FileStream(file, FileMode.Open, FileAccess.Read, FileShare.None))){
@@ -71,33 +79,32 @@ namespace TweetDuck.Core.Other.Settings.Export{
while((key = stream.SkipFile()) != null){ while((key = stream.SkipFile()) != null){
switch(key){ switch(key){
case "config": case "config":
flags |= ExportFileFlags.UserConfig; items |= Items.UserConfig;
break; break;
case "system": case "system":
flags |= ExportFileFlags.SystemConfig; items |= Items.SystemConfig;
break; break;
case "plugin.config": case "plugin.config":
case "plugin.data": case "plugin.data":
flags |= ExportFileFlags.PluginData; items |= Items.PluginData;
break; break;
case "cookies": case "cookies":
flags |= ExportFileFlags.Session; items |= Items.Session;
break; break;
} }
} }
} }
}catch(Exception e){ }catch(Exception){
LastException = e; items = Items.None;
flags = ExportFileFlags.None;
} }
return flags; return items;
} }
public bool Import(ExportFileFlags flags){ public bool Import(Items items){
try{ try{
HashSet<string> missingPlugins = new HashSet<string>(); HashSet<string> missingPlugins = new HashSet<string>();
@@ -107,29 +114,28 @@ namespace TweetDuck.Core.Other.Settings.Export{
while((entry = stream.ReadFile()) != null){ while((entry = stream.ReadFile()) != null){
switch(entry.KeyName){ switch(entry.KeyName){
case "config": case "config":
if (flags.HasFlag(ExportFileFlags.UserConfig)){ if (items.HasFlag(Items.UserConfig)){
entry.WriteToFile(Program.UserConfigFilePath); entry.WriteToFile(Program.UserConfigFilePath);
} }
break; break;
case "system": case "system":
if (flags.HasFlag(ExportFileFlags.SystemConfig)){ if (items.HasFlag(Items.SystemConfig)){
entry.WriteToFile(Program.SystemConfigFilePath); entry.WriteToFile(Program.SystemConfigFilePath);
IsRestarting = true;
} }
break; break;
case "plugin.config": case "plugin.config":
if (flags.HasFlag(ExportFileFlags.PluginData)){ if (items.HasFlag(Items.PluginData)){
entry.WriteToFile(Program.PluginConfigFilePath); entry.WriteToFile(Program.PluginConfigFilePath);
} }
break; break;
case "plugin.data": case "plugin.data":
if (flags.HasFlag(ExportFileFlags.PluginData)){ if (items.HasFlag(Items.PluginData)){
string[] value = entry.KeyValue; string[] value = entry.KeyValue;
entry.WriteToFile(Path.Combine(Program.PluginDataPath, value[0], value[1]), true); entry.WriteToFile(Path.Combine(Program.PluginDataPath, value[0], value[1]), true);
@@ -142,9 +148,8 @@ namespace TweetDuck.Core.Other.Settings.Export{
break; break;
case "cookies": case "cookies":
if (flags.HasFlag(ExportFileFlags.Session)){ if (items.HasFlag(Items.Session)){
entry.WriteToFile(Path.Combine(Program.StoragePath, TempCookiesPath)); entry.WriteToFile(Path.Combine(Program.StoragePath, TempCookiesPath));
IsRestarting = true;
} }
break; break;
@@ -153,12 +158,12 @@ namespace TweetDuck.Core.Other.Settings.Export{
} }
if (missingPlugins.Count > 0){ if (missingPlugins.Count > 0){
FormMessage.Information("Importing TweetDuck Profile", "Detected missing plugins when importing plugin data:\n"+string.Join("\n", missingPlugins), FormMessage.OK); FormMessage.Information("Profile Import", "Detected missing plugins when importing plugin data:\n"+string.Join("\n", missingPlugins), FormMessage.OK);
} }
return true; return true;
}catch(Exception e){ }catch(Exception e){
LastException = e; Program.Reporter.HandleException("Profile Import", "An exception happened while importing TweetDuck profile.", true, e);
return false; return false;
} }
} }
@@ -188,15 +193,23 @@ namespace TweetDuck.Core.Other.Settings.Export{
} }
private static IEnumerable<PathInfo> EnumerateFilesRelative(string root){ private static IEnumerable<PathInfo> EnumerateFilesRelative(string root){
return Directory.Exists(root) ? Directory.EnumerateFiles(root, "*.*", SearchOption.AllDirectories).Select(fullPath => new PathInfo{ if (Directory.Exists(root)){
Full = fullPath, int rootLength = root.Length;
Relative = fullPath.Substring(root.Length).TrimStart(Path.DirectorySeparatorChar, Path.AltDirectorySeparatorChar) // strip leading separator character return Directory.EnumerateFiles(root, "*.*", SearchOption.AllDirectories).Select(fullPath => new PathInfo(fullPath, rootLength));
}) : Enumerable.Empty<PathInfo>(); }
else{
return Enumerable.Empty<PathInfo>();
}
} }
private sealed class PathInfo{ private sealed class PathInfo{
public string Full { get; set; } public string Full { get; }
public string Relative { get; set; } public string Relative { get; }
public PathInfo(string fullPath, int rootLength){
this.Full = fullPath;
this.Relative = fullPath.Substring(rootLength).TrimStart(Path.DirectorySeparatorChar, Path.AltDirectorySeparatorChar); // strip leading separator character
}
} }
} }
} }

View File

@@ -0,0 +1,213 @@
using System;
using System.Diagnostics;
using System.IO;
using System.Windows.Forms;
using TweetDuck.Configuration;
using TweetDuck.Core.Controls;
using TweetDuck.Core.Other;
using TweetDuck.Core.Utils;
using TweetLib.Communication;
namespace TweetDuck.Core.Management{
sealed class VideoPlayer : IDisposable{
private static UserConfig Config => Program.Config.User;
public bool Running => currentInstance != null && currentInstance.Running;
public event EventHandler ProcessExited;
private readonly FormBrowser owner;
private Instance currentInstance;
private bool isClosing;
public VideoPlayer(FormBrowser owner){
this.owner = owner;
this.owner.FormClosing += owner_FormClosing;
}
public void Launch(string url, string username){
if (Running){
Destroy();
isClosing = false;
}
try{
DuplexPipe.Server pipe = DuplexPipe.CreateServer();
pipe.DataIn += pipe_DataIn;
Process process;
if ((process = Process.Start(new ProcessStartInfo{
FileName = Path.Combine(Program.ProgramPath, "TweetDuck.Video.exe"),
Arguments = $"{owner.Handle} {Config.VideoPlayerVolume} \"{url}\" \"{pipe.GenerateToken()}\"",
UseShellExecute = false,
RedirectStandardOutput = true
})) != null){
currentInstance = new Instance(process, pipe, url, username);
process.EnableRaisingEvents = true;
process.Exited += process_Exited;
process.BeginOutputReadLine();
process.OutputDataReceived += process_OutputDataReceived;
pipe.DisposeToken();
}
else{
pipe.DataIn -= pipe_DataIn;
pipe.Dispose();
}
}catch(Exception e){
Program.Reporter.HandleException("Video Playback Error", "Error launching video player.", true, e);
}
}
public void SendKeyEvent(Keys key){
currentInstance?.Pipe.Write("key", ((int)key).ToString());
}
private void pipe_DataIn(object sender, DuplexPipe.PipeReadEventArgs e){
owner.InvokeSafe(() => {
switch(e.Key){
case "vol":
if (int.TryParse(e.Data, out int volume) && volume != Config.VideoPlayerVolume){
Config.VideoPlayerVolume = volume;
Config.Save();
}
break;
case "download":
if (currentInstance != null){
owner.AnalyticsFile.DownloadedVideos.Trigger();
TwitterUtils.DownloadVideo(currentInstance.Url, currentInstance.Username);
}
break;
case "rip":
currentInstance?.Dispose();
currentInstance = null;
isClosing = false;
TriggerProcessExitEventUnsafe();
break;
}
});
}
public void Close(){
if (currentInstance != null){
if (isClosing){
Destroy();
isClosing = false;
}
else{
isClosing = true;
currentInstance.Process.Exited -= process_Exited;
currentInstance.Pipe.Write("die");
}
}
}
public void Dispose(){
ProcessExited = null;
isClosing = true;
Destroy();
}
private void Destroy(){
if (currentInstance != null){
currentInstance.KillAndDispose();
currentInstance = null;
TriggerProcessExitEventUnsafe();
}
}
private void owner_FormClosing(object sender, FormClosingEventArgs e){
if (currentInstance != null){
currentInstance.Process.Exited -= process_Exited;
}
}
private void process_OutputDataReceived(object sender, DataReceivedEventArgs e){
if (!string.IsNullOrEmpty(e.Data)){
Program.Reporter.Log("[VideoPlayer] "+e.Data);
}
}
private void process_Exited(object sender, EventArgs e){
if (currentInstance == null){
return;
}
int exitCode = currentInstance.Process.ExitCode;
string url = currentInstance.Url;
currentInstance.Dispose();
currentInstance = null;
switch(exitCode){
case 3: // CODE_LAUNCH_FAIL
if (FormMessage.Error("Video Playback Error", "Error launching video player, this may be caused by missing Windows Media Player. Do you want to open the video in your browser?", FormMessage.Yes, FormMessage.No)){
BrowserUtils.OpenExternalBrowser(url);
}
break;
case 4: // CODE_MEDIA_ERROR
if (FormMessage.Error("Video Playback Error", "The video could not be loaded, most likely due to unknown format. Do you want to open the video in your browser?", FormMessage.Yes, FormMessage.No)){
BrowserUtils.OpenExternalBrowser(url);
}
break;
}
owner.InvokeAsyncSafe(TriggerProcessExitEventUnsafe);
}
private void TriggerProcessExitEventUnsafe(){
ProcessExited?.Invoke(this, EventArgs.Empty);
}
private sealed class Instance : IDisposable{
public bool Running{
get{
Process.Refresh();
return !Process.HasExited;
}
}
public Process Process { get; }
public DuplexPipe.Server Pipe { get; }
public string Url { get; }
public string Username { get; }
public Instance(Process process, DuplexPipe.Server pipe, string url, string username){
this.Process = process;
this.Pipe = pipe;
this.Url = url;
this.Username = username;
}
public void KillAndDispose(){
try{
Process.Kill();
}catch{
// kill me instead then
}
Dispose();
}
public void Dispose(){
Process.Dispose();
Pipe.Dispose();
}
}
}
}

View File

@@ -1,15 +1,18 @@
using System.Windows.Forms; using System;
using System.Windows.Forms;
using CefSharp;
using TweetDuck.Core.Controls;
using TweetDuck.Plugins; using TweetDuck.Plugins;
using TweetDuck.Resources; using TweetDuck.Resources;
namespace TweetDuck.Core.Notification.Example{ namespace TweetDuck.Core.Notification.Example{
sealed class FormNotificationExample : FormNotificationMain{ sealed class FormNotificationExample : FormNotificationMain{
public override bool RequiresResize => true; public override bool RequiresResize => true;
protected override bool CanDragWindow => Program.UserConfig.NotificationPosition == TweetNotification.Position.Custom; protected override bool CanDragWindow => Config.NotificationPosition == TweetNotification.Position.Custom;
protected override FormBorderStyle NotificationBorderStyle{ protected override FormBorderStyle NotificationBorderStyle{
get{ get{
if (Program.UserConfig.NotificationSize == TweetNotification.Size.Custom){ if (Config.NotificationSize == TweetNotification.Size.Custom){
switch(base.NotificationBorderStyle){ switch(base.NotificationBorderStyle){
case FormBorderStyle.FixedSingle: return FormBorderStyle.Sizable; case FormBorderStyle.FixedSingle: return FormBorderStyle.Sizable;
case FormBorderStyle.FixedToolWindow: return FormBorderStyle.SizableToolWindow; case FormBorderStyle.FixedToolWindow: return FormBorderStyle.SizableToolWindow;
@@ -20,18 +23,37 @@ namespace TweetDuck.Core.Notification.Example{
} }
} }
protected override string BodyClasses => base.BodyClasses+" td-example";
public event EventHandler Ready;
private readonly TweetNotification exampleNotification; private readonly TweetNotification exampleNotification;
public FormNotificationExample(FormBrowser owner, PluginManager pluginManager) : base(owner, pluginManager, false){ public FormNotificationExample(FormBrowser owner, PluginManager pluginManager) : base(owner, pluginManager, false){
string exampleTweetHTML = ScriptLoader.LoadResource("pages/example.html", true); browser.LoadingStateChanged += browser_LoadingStateChanged;
string exampleTweetHTML = ScriptLoader.LoadResourceSilent("pages/example.html")?.Replace("{avatar}", TweetNotification.AppLogo.Url) ?? string.Empty;
#if DEBUG #if DEBUG
exampleTweetHTML = exampleTweetHTML.Replace("</p>", @"</p><div style='margin-top:256px'>Scrollbar test padding...</div>"); exampleTweetHTML = exampleTweetHTML.Replace("</p>", @"</p><div style='margin-top:256px'>Scrollbar test padding...</div>");
#endif #endif
exampleNotification = TweetNotification.Example(exampleTweetHTML, 95); exampleNotification = new TweetNotification(string.Empty, string.Empty, "Home", exampleTweetHTML, 176, string.Empty, string.Empty);
} }
private void browser_LoadingStateChanged(object sender, LoadingStateChangedEventArgs e){
if (!e.IsLoading){
Ready?.Invoke(this, EventArgs.Empty);
browser.LoadingStateChanged -= browser_LoadingStateChanged;
}
}
public override void HideNotification(){
Location = ControlExtensions.InvisibleLocation;
}
public override void FinishCurrentNotification(){}
public void ShowExampleNotification(bool reset){ public void ShowExampleNotification(bool reset){
if (reset){ if (reset){
LoadTweet(exampleNotification); LoadTweet(exampleNotification);

View File

@@ -1,6 +1,4 @@
using CefSharp; using CefSharp.WinForms;
using CefSharp.WinForms;
using System;
using System.Drawing; using System.Drawing;
using System.Windows.Forms; using System.Windows.Forms;
using TweetDuck.Configuration; using TweetDuck.Configuration;
@@ -9,11 +7,12 @@ using TweetDuck.Core.Controls;
using TweetDuck.Core.Handling; using TweetDuck.Core.Handling;
using TweetDuck.Core.Handling.General; using TweetDuck.Core.Handling.General;
using TweetDuck.Core.Other.Analytics; using TweetDuck.Core.Other.Analytics;
using TweetDuck.Core.Other.Management;
using TweetDuck.Core.Utils; using TweetDuck.Core.Utils;
namespace TweetDuck.Core.Notification{ namespace TweetDuck.Core.Notification{
partial class FormNotificationBase : Form{ abstract partial class FormNotificationBase : Form, AnalyticsFile.IProvider{
protected static UserConfig Config => Program.Config.User;
protected static int FontSizeLevel{ protected static int FontSizeLevel{
get{ get{
switch(TweetDeckBridge.FontSize){ switch(TweetDeckBridge.FontSize){
@@ -28,19 +27,18 @@ namespace TweetDuck.Core.Notification{
protected virtual Point PrimaryLocation{ protected virtual Point PrimaryLocation{
get{ get{
UserConfig config = Program.UserConfig;
Screen screen; Screen screen;
if (config.NotificationDisplay > 0 && config.NotificationDisplay <= Screen.AllScreens.Length){ if (Config.NotificationDisplay > 0 && Config.NotificationDisplay <= Screen.AllScreens.Length){
screen = Screen.AllScreens[config.NotificationDisplay-1]; screen = Screen.AllScreens[Config.NotificationDisplay-1];
} }
else{ else{
screen = Screen.FromControl(owner); screen = Screen.FromControl(owner);
} }
int edgeDist = config.NotificationEdgeDistance; int edgeDist = Config.NotificationEdgeDistance;
switch(config.NotificationPosition){ switch(Config.NotificationPosition){
case TweetNotification.Position.TopLeft: case TweetNotification.Position.TopLeft:
return new Point(screen.WorkingArea.X+edgeDist, screen.WorkingArea.Y+edgeDist); return new Point(screen.WorkingArea.X+edgeDist, screen.WorkingArea.Y+edgeDist);
@@ -54,19 +52,19 @@ namespace TweetDuck.Core.Notification{
return new Point(screen.WorkingArea.X+screen.WorkingArea.Width-edgeDist-Width, screen.WorkingArea.Y+screen.WorkingArea.Height-edgeDist-Height); return new Point(screen.WorkingArea.X+screen.WorkingArea.Width-edgeDist-Width, screen.WorkingArea.Y+screen.WorkingArea.Height-edgeDist-Height);
case TweetNotification.Position.Custom: case TweetNotification.Position.Custom:
if (!config.IsCustomNotificationPositionSet){ 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(); Config.Save();
} }
return config.CustomNotificationPosition; return Config.CustomNotificationPosition;
} }
return Location; return Location;
} }
} }
public bool IsNotificationVisible => Location != ControlExtensions.InvisibleLocation; protected bool IsNotificationVisible => Location != ControlExtensions.InvisibleLocation;
protected virtual bool CanDragWindow => true; protected virtual bool CanDragWindow => true;
public new Point Location{ public new Point Location{
@@ -91,10 +89,12 @@ namespace TweetDuck.Core.Notification{
} }
} }
public AnalyticsFile AnalyticsFile => owner.AnalyticsFile;
protected override bool ShowWithoutActivation => true; protected override bool ShowWithoutActivation => true;
protected float DpiScale { get; } protected float DpiScale { get; }
protected double SizeScale => DpiScale*Program.UserConfig.ZoomLevel/100.0; protected double SizeScale => DpiScale*Config.ZoomLevel/100.0;
protected readonly FormBrowser owner; protected readonly FormBrowser owner;
protected readonly ChromiumWebBrowser browser; protected readonly ChromiumWebBrowser browser;
@@ -108,13 +108,13 @@ namespace TweetDuck.Core.Notification{
public string CurrentQuoteUrl => currentNotification?.QuoteUrl; public string CurrentQuoteUrl => currentNotification?.QuoteUrl;
public bool CanViewDetail => currentNotification != null && !string.IsNullOrEmpty(currentNotification.ColumnId) && !string.IsNullOrEmpty(currentNotification.ChirpId); public bool CanViewDetail => currentNotification != null && !string.IsNullOrEmpty(currentNotification.ColumnId) && !string.IsNullOrEmpty(currentNotification.ChirpId);
public bool IsPaused => pauseCounter > 0;
protected bool IsPaused => pauseCounter > 0;
protected bool IsCursorOverBrowser => browser.Bounds.Contains(PointToClient(Cursor.Position));
public bool FreezeTimer { get; set; } public bool FreezeTimer { get; set; }
public bool ContextMenuOpen { get; set; } public bool ContextMenuOpen { get; set; }
public event EventHandler Initialized;
protected FormNotificationBase(FormBrowser owner, bool enableContextMenu){ protected FormNotificationBase(FormBrowser owner, bool enableContextMenu){
InitializeComponent(); InitializeComponent();
@@ -124,21 +124,16 @@ namespace TweetDuck.Core.Notification{
this.browser = new ChromiumWebBrowser("about:blank"){ this.browser = new ChromiumWebBrowser("about:blank"){
MenuHandler = new ContextMenuNotification(this, enableContextMenu), MenuHandler = new ContextMenuNotification(this, enableContextMenu),
JsDialogHandler = new JavaScriptDialogHandler(), JsDialogHandler = new JavaScriptDialogHandler(),
LifeSpanHandler = new LifeSpanHandler() LifeSpanHandler = new LifeSpanHandler(),
RequestHandler = new RequestHandlerBase(false)
}; };
this.browser.Dock = DockStyle.None; this.browser.Dock = DockStyle.None;
this.browser.ClientSize = ClientSize; this.browser.ClientSize = ClientSize;
this.browser.IsBrowserInitializedChanged += browser_IsBrowserInitializedChanged;
#if DEBUG this.browser.SetupResourceHandler(TwitterUtils.TweetDeckURL, this.resourceHandler);
this.browser.ConsoleMessage += BrowserUtils.HandleConsoleMessage; this.browser.SetupResourceHandler(TweetNotification.AppLogo);
#endif this.browser.SetupZoomEvents();
DpiScale = this.GetDPIScale();
DefaultResourceHandlerFactory handlerFactory = (DefaultResourceHandlerFactory)browser.ResourceHandlerFactory;
handlerFactory.RegisterHandler(TwitterUtils.TweetDeckURL, this.resourceHandler);
Controls.Add(browser); Controls.Add(browser);
@@ -147,6 +142,8 @@ namespace TweetDuck.Core.Notification{
this.owner.FormClosed -= owner_FormClosed; this.owner.FormClosed -= owner_FormClosed;
}; };
DpiScale = this.GetDPIScale();
// ReSharper disable once VirtualMemberCallInContructor // ReSharper disable once VirtualMemberCallInContructor
UpdateTitle(); UpdateTitle();
} }
@@ -159,29 +156,18 @@ namespace TweetDuck.Core.Notification{
base.WndProc(ref m); base.WndProc(ref m);
} }
public void TriggerAnalyticsEvent(AnalyticsFile.Event e){
owner.TriggerAnalyticsEvent(e);
}
// event handlers // event handlers
private void owner_FormClosed(object sender, FormClosedEventArgs e){ private void owner_FormClosed(object sender, FormClosedEventArgs e){
Close(); Close();
} }
private void browser_IsBrowserInitializedChanged(object sender, IsBrowserInitializedChangedEventArgs e){
if (e.IsBrowserInitialized){
Initialized?.Invoke(this, EventArgs.Empty);
int identifier = browser.GetBrowser().Identifier;
Disposed += (sender2, args2) => BrowserProcesses.Forget(identifier);
}
}
// notification methods // notification methods
public virtual void HideNotification(){ public virtual void HideNotification(){
browser.Load("about:blank"); browser.Load("about:blank");
DisplayTooltip(null);
Location = ControlExtensions.InvisibleLocation; Location = ControlExtensions.InvisibleLocation;
currentNotification = null; currentNotification = null;
} }
@@ -200,15 +186,14 @@ namespace TweetDuck.Core.Notification{
} }
} }
protected virtual string GetTweetHTML(TweetNotification tweet){ protected abstract string GetTweetHTML(TweetNotification tweet);
string bodyClasses = browser.Bounds.Contains(PointToClient(Cursor.Position)) ? "td-hover" : string.Empty;
return tweet.GenerateHtml(bodyClasses);
}
protected virtual void LoadTweet(TweetNotification tweet){ protected virtual void LoadTweet(TweetNotification tweet){
currentNotification = tweet; currentNotification = tweet;
resourceHandler.SetHTML(GetTweetHTML(tweet)); resourceHandler.SetHTML(GetTweetHTML(tweet));
browser.Load(TwitterUtils.TweetDeckURL); browser.Load(TwitterUtils.TweetDeckURL);
DisplayTooltip(null);
} }
protected virtual void SetNotificationSize(int width, int height){ protected virtual void SetNotificationSize(int width, int height){
@@ -217,12 +202,14 @@ namespace TweetDuck.Core.Notification{
protected virtual void UpdateTitle(){ protected virtual void UpdateTitle(){
string title = currentNotification?.ColumnTitle; string title = currentNotification?.ColumnTitle;
Text = string.IsNullOrEmpty(title) || !Program.UserConfig.DisplayNotificationColumn ? Program.BrandName : Program.BrandName+" - "+title; Text = string.IsNullOrEmpty(title) || !Config.DisplayNotificationColumn ? Program.BrandName : $"{Program.BrandName} - {title}";
} }
public void ShowTweetDetail(){ public void ShowTweetDetail(){
if (currentNotification != null){
owner.ShowTweetDetail(currentNotification.ColumnId, currentNotification.ChirpId, currentNotification.TweetUrl); owner.ShowTweetDetail(currentNotification.ColumnId, currentNotification.ChirpId, currentNotification.TweetUrl);
} }
}
public void MoveToVisibleLocation(){ public void MoveToVisibleLocation(){
bool needsReactivating = Location == ControlExtensions.InvisibleLocation; bool needsReactivating = Location == ControlExtensions.InvisibleLocation;

View File

@@ -5,7 +5,6 @@ using System.Windows.Forms;
using TweetDuck.Core.Bridge; using TweetDuck.Core.Bridge;
using TweetDuck.Core.Controls; using TweetDuck.Core.Controls;
using TweetDuck.Core.Handling; using TweetDuck.Core.Handling;
using TweetDuck.Core.Other.Analytics;
using TweetDuck.Core.Utils; using TweetDuck.Core.Utils;
using TweetDuck.Data; using TweetDuck.Data;
using TweetDuck.Plugins; using TweetDuck.Plugins;
@@ -14,11 +13,6 @@ using TweetDuck.Resources;
namespace TweetDuck.Core.Notification{ namespace TweetDuck.Core.Notification{
abstract partial class FormNotificationMain : FormNotificationBase{ abstract partial class FormNotificationMain : FormNotificationBase{
private const string NotificationScriptFile = "notification.js";
private static readonly string NotificationScriptIdentifier = ScriptLoader.GetRootIdentifier(NotificationScriptFile);
private static readonly string NotificationJS = ScriptLoader.LoadResource(NotificationScriptFile);
private readonly PluginManager plugins; private readonly PluginManager plugins;
private readonly int timerBarHeight; private readonly int timerBarHeight;
@@ -34,7 +28,7 @@ namespace TweetDuck.Core.Notification{
public virtual bool RequiresResize{ public virtual bool RequiresResize{
get{ get{
return !prevDisplayTimer.HasValue || !prevFontSize.HasValue || prevDisplayTimer != Program.UserConfig.DisplayNotificationTimer || prevFontSize != FontSizeLevel; return !prevDisplayTimer.HasValue || !prevFontSize.HasValue || prevDisplayTimer != Config.DisplayNotificationTimer || prevFontSize != FontSizeLevel;
} }
set{ set{
@@ -43,7 +37,7 @@ namespace TweetDuck.Core.Notification{
prevFontSize = null; prevFontSize = null;
} }
else{ else{
prevDisplayTimer = Program.UserConfig.DisplayNotificationTimer; prevDisplayTimer = Config.DisplayNotificationTimer;
prevFontSize = FontSizeLevel; prevFontSize = FontSizeLevel;
} }
} }
@@ -51,29 +45,31 @@ namespace TweetDuck.Core.Notification{
private int BaseClientWidth{ private int BaseClientWidth{
get{ get{
switch(Program.UserConfig.NotificationSize){ switch(Config.NotificationSize){
default: default:
return BrowserUtils.Scale(284, SizeScale*(1.0+0.05*FontSizeLevel)); return BrowserUtils.Scale(284, SizeScale*(1.0+0.05*FontSizeLevel));
case TweetNotification.Size.Custom: case TweetNotification.Size.Custom:
return Program.UserConfig.CustomNotificationSize.Width; return Config.CustomNotificationSize.Width;
} }
} }
} }
private int BaseClientHeight{ private int BaseClientHeight{
get{ get{
switch(Program.UserConfig.NotificationSize){ switch(Config.NotificationSize){
default: default:
return BrowserUtils.Scale(122, SizeScale*(1.0+0.075*FontSizeLevel)); return BrowserUtils.Scale(122, SizeScale*(1.0+0.08*FontSizeLevel));
case TweetNotification.Size.Custom: case TweetNotification.Size.Custom:
return Program.UserConfig.CustomNotificationSize.Height; return Config.CustomNotificationSize.Height;
} }
} }
} }
public Size BrowserSize => Program.UserConfig.DisplayNotificationTimer ? new Size(ClientSize.Width, ClientSize.Height-timerBarHeight) : ClientSize; protected virtual string BodyClasses => IsCursorOverBrowser ? "td-notification td-hover" : "td-notification";
public Size BrowserSize => Config.DisplayNotificationTimer ? new Size(ClientSize.Width, ClientSize.Height-timerBarHeight) : ClientSize;
protected FormNotificationMain(FormBrowser owner, PluginManager pluginManager, bool enableContextMenu) : base(owner, enableContextMenu){ protected FormNotificationMain(FormBrowser owner, PluginManager pluginManager, bool enableContextMenu) : base(owner, enableContextMenu){
InitializeComponent(); InitializeComponent();
@@ -82,13 +78,13 @@ namespace TweetDuck.Core.Notification{
this.timerBarHeight = BrowserUtils.Scale(4, DpiScale); this.timerBarHeight = BrowserUtils.Scale(4, DpiScale);
browser.KeyboardHandler = new KeyboardHandlerNotification(this); browser.KeyboardHandler = new KeyboardHandlerNotification(this);
browser.RegisterAsyncJsObject("$TD", new TweetDeckBridge.Notification(owner, this));
browser.RegisterAsyncJsObject("$TD", new TweetDeckBridge(owner, this));
browser.RegisterAsyncJsObject("$TDP", plugins.Bridge);
browser.LoadingStateChanged += Browser_LoadingStateChanged; browser.LoadingStateChanged += Browser_LoadingStateChanged;
browser.FrameLoadEnd += Browser_FrameLoadEnd; browser.FrameLoadEnd += Browser_FrameLoadEnd;
plugins.Register(browser, PluginEnvironment.Notification, this);
mouseHookDelegate = MouseHookProc; mouseHookDelegate = MouseHookProc;
Disposed += (sender, args) => StopMouseHook(true); Disposed += (sender, args) => StopMouseHook(true);
} }
@@ -113,8 +109,8 @@ namespace TweetDuck.Core.Notification{
if (nCode == 0){ if (nCode == 0){
int eventType = wParam.ToInt32(); int eventType = wParam.ToInt32();
if (eventType == NativeMethods.WM_MOUSEWHEEL && browser.Bounds.Contains(PointToClient(Cursor.Position))){ if (eventType == NativeMethods.WM_MOUSEWHEEL && IsCursorOverBrowser){
browser.SendMouseWheelEvent(0, 0, 0, BrowserUtils.Scale(NativeMethods.GetMouseHookData(lParam), Program.UserConfig.NotificationScrollSpeed/100.0), CefEventFlags.None); browser.SendMouseWheelEvent(0, 0, 0, BrowserUtils.Scale(NativeMethods.GetMouseHookData(lParam), Config.NotificationScrollSpeed*0.01), CefEventFlags.None);
return NativeMethods.HOOK_HANDLED; return NativeMethods.HOOK_HANDLED;
} }
else if (eventType == NativeMethods.WM_XBUTTONDOWN && DesktopBounds.Contains(Cursor.Position)){ else if (eventType == NativeMethods.WM_XBUTTONDOWN && DesktopBounds.Contains(Cursor.Position)){
@@ -128,7 +124,7 @@ namespace TweetDuck.Core.Notification{
} }
blockXButtonUp = true; blockXButtonUp = true;
this.InvokeAsyncSafe(() => TriggerAnalyticsEvent(AnalyticsFile.Event.NotificationExtraMouseButton)); this.InvokeAsyncSafe(AnalyticsFile.NotificationExtraMouseButtons.Trigger);
return NativeMethods.HOOK_HANDLED; return NativeMethods.HOOK_HANDLED;
} }
else if (eventType == NativeMethods.WM_XBUTTONUP && blockXButtonUp){ else if (eventType == NativeMethods.WM_XBUTTONUP && blockXButtonUp){
@@ -164,10 +160,11 @@ namespace TweetDuck.Core.Notification{
} }
private void Browser_FrameLoadEnd(object sender, FrameLoadEndEventArgs e){ private void Browser_FrameLoadEnd(object sender, FrameLoadEndEventArgs e){
if (e.Frame.IsMain && NotificationJS != null && browser.Address != "about:blank"){ IFrame frame = e.Frame;
e.Frame.ExecuteJavaScriptAsync(PropertyBridge.GenerateScript(PropertyBridge.Environment.Notification));
ScriptLoader.ExecuteScript(e.Frame, NotificationJS, NotificationScriptIdentifier); if (frame.IsMain && browser.Address != "about:blank"){
plugins.ExecutePlugins(e.Frame, PluginEnvironment.Notification); frame.ExecuteJavaScriptAsync(PropertyBridge.GenerateScript(PropertyBridge.Environment.Notification));
ScriptLoader.ExecuteFile(frame, "notification.js", this);
} }
} }
@@ -184,7 +181,7 @@ namespace TweetDuck.Core.Notification{
timeLeft -= timerProgress.Interval; timeLeft -= timerProgress.Interval;
int value = BrowserUtils.Scale(progressBarTimer.Maximum+25, (totalTime-timeLeft)/(double)totalTime); int value = BrowserUtils.Scale(progressBarTimer.Maximum+25, (totalTime-timeLeft)/(double)totalTime);
progressBarTimer.SetValueInstant(Program.UserConfig.NotificationTimerCountDown ? progressBarTimer.Maximum-value : value); progressBarTimer.SetValueInstant(Config.NotificationTimerCountDown ? progressBarTimer.Maximum-value : value);
if (timeLeft <= 0){ if (timeLeft <= 0){
FinishCurrentNotification(); FinishCurrentNotification();
@@ -200,7 +197,7 @@ namespace TweetDuck.Core.Notification{
public override void HideNotification(){ public override void HideNotification(){
base.HideNotification(); base.HideNotification();
progressBarTimer.Value = Program.UserConfig.NotificationTimerCountDown ? progressBarTimer.Maximum : progressBarTimer.Minimum; progressBarTimer.Value = Config.NotificationTimerCountDown ? progressBarTimer.Maximum : progressBarTimer.Minimum;
timerProgress.Stop(); timerProgress.Stop();
totalTime = 0; totalTime = 0;
@@ -231,10 +228,10 @@ namespace TweetDuck.Core.Notification{
} }
protected override string GetTweetHTML(TweetNotification tweet){ protected override string GetTweetHTML(TweetNotification tweet){
string html = base.GetTweetHTML(tweet); string html = tweet.GenerateHtml(BodyClasses, this);
foreach(InjectedHTML injection in plugins.Bridge.NotificationInjections){ foreach(InjectedHTML injection in plugins.NotificationInjections){
html = injection.Inject(html); html = injection.InjectInto(html);
} }
return html; return html;
@@ -242,14 +239,14 @@ namespace TweetDuck.Core.Notification{
protected override void LoadTweet(TweetNotification tweet){ protected override void LoadTweet(TweetNotification tweet){
timerProgress.Stop(); timerProgress.Stop();
totalTime = timeLeft = tweet.GetDisplayDuration(Program.UserConfig.NotificationDurationValue); totalTime = timeLeft = tweet.GetDisplayDuration(Config.NotificationDurationValue);
progressBarTimer.Value = Program.UserConfig.NotificationTimerCountDown ? progressBarTimer.Maximum : progressBarTimer.Minimum; progressBarTimer.Value = Config.NotificationTimerCountDown ? progressBarTimer.Maximum : progressBarTimer.Minimum;
base.LoadTweet(tweet); base.LoadTweet(tweet);
} }
protected override void SetNotificationSize(int width, int height){ protected override void SetNotificationSize(int width, int height){
if (Program.UserConfig.DisplayNotificationTimer){ if (Config.DisplayNotificationTimer){
ClientSize = new Size(width, height+timerBarHeight); ClientSize = new Size(width, height+timerBarHeight);
progressBarTimer.Visible = true; progressBarTimer.Visible = true;
} }

View File

@@ -3,7 +3,6 @@ using System.Collections.Generic;
using System.Drawing; using System.Drawing;
using TweetDuck.Plugins; using TweetDuck.Plugins;
using System.Windows.Forms; using System.Windows.Forms;
using TweetDuck.Core.Other.Analytics;
using TweetDuck.Core.Utils; using TweetDuck.Core.Utils;
namespace TweetDuck.Core.Notification{ namespace TweetDuck.Core.Notification{
@@ -33,10 +32,10 @@ namespace TweetDuck.Core.Notification{
public FormNotificationTweet(FormBrowser owner, PluginManager pluginManager) : base(owner, pluginManager, true){ public FormNotificationTweet(FormBrowser owner, PluginManager pluginManager) : base(owner, pluginManager, true){
InitializeComponent(); InitializeComponent();
Program.UserConfig.MuteToggled += Config_MuteToggled; Config.MuteToggled += Config_MuteToggled;
Disposed += (sender, args) => Program.UserConfig.MuteToggled -= Config_MuteToggled; Disposed += (sender, args) => Config.MuteToggled -= Config_MuteToggled;
if (Program.UserConfig.MuteNotifications){ if (Config.MuteNotifications){
PauseNotification(); PauseNotification();
} }
} }
@@ -58,7 +57,7 @@ namespace TweetDuck.Core.Notification{
// event handlers // event handlers
private void Config_MuteToggled(object sender, EventArgs e){ private void Config_MuteToggled(object sender, EventArgs e){
if (Program.UserConfig.MuteNotifications){ if (Config.MuteNotifications){
PauseNotification(); PauseNotification();
} }
else{ else{
@@ -74,7 +73,7 @@ namespace TweetDuck.Core.Notification{
} }
private void timerIdlePauseCheck_Tick(object sender, EventArgs e){ private void timerIdlePauseCheck_Tick(object sender, EventArgs e){
if (NativeMethods.GetIdleSeconds() < Program.UserConfig.NotificationIdlePauseSeconds){ if (NativeMethods.GetIdleSeconds() < Config.NotificationIdlePauseSeconds){
ResumeNotification(); ResumeNotification();
timerIdlePauseCheck.Stop(); timerIdlePauseCheck.Stop();
} }
@@ -94,7 +93,7 @@ namespace TweetDuck.Core.Notification{
} }
needsTrim |= tweetQueue.Count >= TrimMinimum; needsTrim |= tweetQueue.Count >= TrimMinimum;
TriggerAnalyticsEvent(AnalyticsFile.Event.DesktopNotification); AnalyticsFile.DesktopNotifications.Trigger();
} }
public override void HideNotification(){ public override void HideNotification(){
@@ -129,7 +128,7 @@ namespace TweetDuck.Core.Notification{
private void LoadNextNotification(){ private void LoadNextNotification(){
if (!IsNotificationVisible){ if (!IsNotificationVisible){
if (Program.UserConfig.NotificationNonIntrusiveMode && IsCursorOverNotificationArea && NativeMethods.GetIdleSeconds() < NonIntrusiveIdleLimit){ if (Config.NotificationNonIntrusiveMode && IsCursorOverNotificationArea && NativeMethods.GetIdleSeconds() < NonIntrusiveIdleLimit){
if (!timerCursorCheck.Enabled){ if (!timerCursorCheck.Enabled){
PauseNotification(); PauseNotification();
timerCursorCheck.Start(); timerCursorCheck.Start();
@@ -137,7 +136,7 @@ namespace TweetDuck.Core.Notification{
return; return;
} }
else if (Program.UserConfig.NotificationIdlePauseSeconds > 0 && NativeMethods.GetIdleSeconds() >= Program.UserConfig.NotificationIdlePauseSeconds){ else if (Config.NotificationIdlePauseSeconds > 0 && NativeMethods.GetIdleSeconds() >= Config.NotificationIdlePauseSeconds){
if (!timerIdlePauseCheck.Enabled){ if (!timerIdlePauseCheck.Enabled){
PauseNotification(); PauseNotification();
timerIdlePauseCheck.Start(); timerIdlePauseCheck.Start();

View File

@@ -3,7 +3,7 @@ using System.Drawing;
using System.Drawing.Imaging; using System.Drawing.Imaging;
using System.Windows.Forms; using System.Windows.Forms;
using CefSharp; using CefSharp;
using TweetDuck.Core.Bridge; using TweetDuck.Core.Controls;
using TweetDuck.Core.Other; using TweetDuck.Core.Other;
using TweetDuck.Core.Utils; using TweetDuck.Core.Utils;
using TweetDuck.Data; using TweetDuck.Data;
@@ -15,44 +15,74 @@ namespace TweetDuck.Core.Notification.Screenshot{
protected override bool CanDragWindow => false; protected override bool CanDragWindow => false;
private readonly PluginManager plugins; private readonly PluginManager plugins;
private int height;
public FormNotificationScreenshotable(Action callback, FormBrowser owner, PluginManager pluginManager) : base(owner, false){ public FormNotificationScreenshotable(Action callback, FormBrowser owner, PluginManager pluginManager, string html, int width) : base(owner, false){
this.plugins = pluginManager; this.plugins = pluginManager;
browser.RegisterAsyncJsObject("$TD_NotificationScreenshot", new CallbackBridge(this, callback)); int realWidth = BrowserUtils.Scale(width, DpiScale);
browser.RegisterAsyncJsObject("$TD_NotificationScreenshot", new ScreenshotBridge(this, SetScreenshotHeight, callback));
browser.LoadingStateChanged += (sender, args) => { browser.LoadingStateChanged += (sender, args) => {
if (!args.IsLoading){ if (args.IsLoading){
using(IFrame frame = args.Browser.MainFrame){ return;
ScriptLoader.ExecuteScript(frame, "window.setTimeout($TD_NotificationScreenshot.trigger, document.getElementsByTagName('iframe').length ? 267 : 67)", "gen:screenshot");
} }
string script = ScriptLoader.LoadResourceSilent("screenshot.js");
if (script == null){
this.InvokeAsyncSafe(callback);
return;
}
using(IFrame frame = args.Browser.MainFrame){
ScriptLoader.ExecuteScript(frame, script.Replace("{width}", realWidth.ToString()).Replace("{frames}", TweetScreenshotManager.WaitFrames.ToString()), "gen:screenshot");
} }
}; };
SetNotificationSize(realWidth, 1024);
LoadTweet(new TweetNotification(string.Empty, string.Empty, string.Empty, html, 0, string.Empty, string.Empty));
} }
protected override string GetTweetHTML(TweetNotification tweet){ protected override string GetTweetHTML(TweetNotification tweet){
string html = tweet.GenerateHtml("td-screenshot", false); string html = tweet.GenerateHtml("td-screenshot", this);
foreach(InjectedHTML injection in plugins.Bridge.NotificationInjections){ foreach(InjectedHTML injection in plugins.NotificationInjections){
html = injection.Inject(html); html = injection.InjectInto(html);
} }
return html; return html;
} }
public void LoadNotificationForScreenshot(TweetNotification tweet, int width, int height){ private void SetScreenshotHeight(int browserHeight){
LoadTweet(tweet); this.height = BrowserUtils.Scale(browserHeight, SizeScale);
SetNotificationSize(width, height); }
public bool TakeScreenshot(bool ignoreHeightError = false){
if (!ignoreHeightError){
if (height == 0){
FormMessage.Error("Screenshot Failed", "Could not detect screenshot size.", FormMessage.OK);
return false;
}
else if (height > ClientSize.Height){
FormMessage.Error("Screenshot Failed", $"Screenshot is too large: {height}px > {ClientSize.Height}px", FormMessage.OK);
return false;
}
}
if (!WindowsUtils.IsAeroEnabled){
MoveToVisibleLocation(); // TODO make this look nicer I guess
} }
public void TakeScreenshot(){
IntPtr context = NativeMethods.GetDC(this.Handle); IntPtr context = NativeMethods.GetDC(this.Handle);
if (context == IntPtr.Zero){ if (context == IntPtr.Zero){
FormMessage.Error("Screenshot Failed", "Could not retrieve a graphics context handle for the notification window to take the screenshot.", FormMessage.OK); FormMessage.Error("Screenshot Failed", "Could not retrieve a graphics context handle for the notification window to take the screenshot.", FormMessage.OK);
return false;
} }
else{ else{
using(Bitmap bmp = new Bitmap(ClientSize.Width, ClientSize.Height, PixelFormat.Format32bppRgb)){ using(Bitmap bmp = new Bitmap(ClientSize.Width, Math.Max(1, height), PixelFormat.Format32bppRgb)){
try{ try{
NativeMethods.RenderSourceIntoBitmap(context, bmp); NativeMethods.RenderSourceIntoBitmap(context, bmp);
}finally{ }finally{
@@ -60,6 +90,7 @@ namespace TweetDuck.Core.Notification.Screenshot{
} }
Clipboard.SetImage(bmp); Clipboard.SetImage(bmp);
return true;
} }
} }
} }

View File

@@ -0,0 +1,26 @@
using System;
using System.Windows.Forms;
using TweetDuck.Core.Controls;
namespace TweetDuck.Core.Notification.Screenshot{
sealed class ScreenshotBridge{
private readonly Control owner;
private readonly Action<int> safeSetHeight;
private readonly Action safeTriggerScreenshot;
public ScreenshotBridge(Control owner, Action<int> safeSetHeight, Action safeTriggerScreenshot){
this.owner = owner;
this.safeSetHeight = safeSetHeight;
this.safeTriggerScreenshot = safeTriggerScreenshot;
}
public void SetHeight(int tweetHeight){
owner.InvokeSafe(() => safeSetHeight(tweetHeight));
}
public void TriggerScreenshot(){
owner.InvokeSafe(safeTriggerScreenshot);
}
}
}

View File

@@ -1,11 +1,22 @@
// Uncomment to keep screenshot windows visible for debugging #if DEBUG
// Uncomment to keep screenshot windows visible for debugging
// #define NO_HIDE_SCREENSHOTS // #define NO_HIDE_SCREENSHOTS
// Uncomment to generate screenshots of individual frames for at most 1 second
// #define GEN_SCREENSHOT_FRAMES
#endif
using System; using System;
using System.Windows.Forms; using System.Windows.Forms;
using TweetDuck.Core.Controls; using TweetDuck.Core.Controls;
using TweetDuck.Plugins; using TweetDuck.Plugins;
#if GEN_SCREENSHOT_FRAMES
using System.Drawing.Imaging;
using System.IO;
using TweetDuck.Core.Utils;
#endif
namespace TweetDuck.Core.Notification.Screenshot{ namespace TweetDuck.Core.Notification.Screenshot{
sealed class TweetScreenshotManager : IDisposable{ sealed class TweetScreenshotManager : IDisposable{
private readonly FormBrowser owner; private readonly FormBrowser owner;
@@ -13,6 +24,15 @@ namespace TweetDuck.Core.Notification.Screenshot{
private readonly Timer timeout; private readonly Timer timeout;
private readonly Timer disposer; private readonly Timer disposer;
#if GEN_SCREENSHOT_FRAMES
private readonly Timer debugger;
private int frameCounter;
public const int WaitFrames = 60;
#else
public const int WaitFrames = 5;
#endif
private FormNotificationScreenshotable screenshot; private FormNotificationScreenshotable screenshot;
public TweetScreenshotManager(FormBrowser owner, PluginManager pluginManager){ public TweetScreenshotManager(FormBrowser owner, PluginManager pluginManager){
@@ -24,6 +44,11 @@ namespace TweetDuck.Core.Notification.Screenshot{
this.disposer = new Timer{ Interval = 1 }; this.disposer = new Timer{ Interval = 1 };
this.disposer.Tick += disposer_Tick; this.disposer.Tick += disposer_Tick;
#if GEN_SCREENSHOT_FRAMES
this.debugger = new Timer{ Interval = 16 };
this.debugger.Tick += debugger_Tick;
#endif
} }
private void timeout_Tick(object sender, EventArgs e){ private void timeout_Tick(object sender, EventArgs e){
@@ -37,17 +62,20 @@ namespace TweetDuck.Core.Notification.Screenshot{
screenshot = null; screenshot = null;
} }
public void Trigger(string html, int width, int height){ public void Trigger(string html, int width){
if (screenshot != null){ if (screenshot != null){
return; return;
} }
screenshot = new FormNotificationScreenshotable(Callback, owner, plugins); screenshot = new FormNotificationScreenshotable(Callback, owner, plugins, html, width);
screenshot.LoadNotificationForScreenshot(new TweetNotification(string.Empty, string.Empty, string.Empty, html, 0, string.Empty, string.Empty), width, height);
screenshot.Show(); screenshot.Show();
timeout.Start(); timeout.Start();
#if !(DEBUG && NO_HIDE_SCREENSHOTS) #if GEN_SCREENSHOT_FRAMES
StartDebugger();
#endif
#if !NO_HIDE_SCREENSHOTS
owner.IsWaiting = true; owner.IsWaiting = true;
#endif #endif
} }
@@ -60,7 +88,7 @@ namespace TweetDuck.Core.Notification.Screenshot{
timeout.Stop(); timeout.Stop();
screenshot.TakeScreenshot(); screenshot.TakeScreenshot();
#if !(DEBUG && NO_HIDE_SCREENSHOTS) #if !NO_HIDE_SCREENSHOTS
OnFinished(); OnFinished();
#else #else
screenshot.MoveToVisibleLocation(); screenshot.MoveToVisibleLocation();
@@ -69,15 +97,52 @@ namespace TweetDuck.Core.Notification.Screenshot{
} }
private void OnFinished(){ private void OnFinished(){
#if GEN_SCREENSHOT_FRAMES
debugger.Stop();
#endif
screenshot.Location = ControlExtensions.InvisibleLocation; screenshot.Location = ControlExtensions.InvisibleLocation;
owner.IsWaiting = false; owner.IsWaiting = false;
disposer.Start(); disposer.Start();
} }
public void Dispose(){ public void Dispose(){
#if GEN_SCREENSHOT_FRAMES
debugger.Dispose();
#endif
timeout.Dispose(); timeout.Dispose();
disposer.Dispose(); disposer.Dispose();
screenshot?.Dispose(); screenshot?.Dispose();
} }
#if GEN_SCREENSHOT_FRAMES
private static readonly string DebugScreenshotPath = Path.Combine(Program.StoragePath, "TD_Screenshots");
private void StartDebugger(){
frameCounter = 0;
try{
Directory.Delete(DebugScreenshotPath, true);
WindowsUtils.TrySleepUntil(() => !Directory.Exists(DebugScreenshotPath), 1000, 10);
}catch(DirectoryNotFoundException){}
Directory.CreateDirectory(DebugScreenshotPath);
debugger.Start();
}
private void debugger_Tick(object sender, EventArgs e){
if (frameCounter < 63 && screenshot.TakeScreenshot(true)){
try{
Clipboard.GetImage()?.Save(Path.Combine(DebugScreenshotPath, "frame_"+(++frameCounter)+".png"), ImageFormat.Png);
}catch{
System.Diagnostics.Debug.WriteLine("Failed generating frame "+frameCounter);
}
}
else{
debugger.Stop();
}
}
#endif
} }
} }

View File

@@ -1,32 +1,50 @@
using System; using System.Drawing;
using TweetLib.Audio; using System.IO;
using System.Windows.Forms;
using CefSharp;
using TweetDuck.Core.Controls;
using TweetDuck.Core.Other;
using TweetDuck.Core.Other.Settings;
namespace TweetDuck.Core.Notification{ namespace TweetDuck.Core.Notification{
sealed class SoundNotification : IDisposable{ static class SoundNotification{
public string SupportedFormats => player.SupportedFormats; public const string SupportedFormats = "*.wav;*.ogg;*.mp3;*.flac;*.opus;*.weba;*.webm";
public event EventHandler<PlaybackErrorEventArgs> PlaybackError;
private readonly AudioPlayer player; public static IResourceHandler CreateFileHandler(string path){
string mimeType;
public SoundNotification(){ switch(Path.GetExtension(path)){
this.player = AudioPlayer.New(); case ".weba":
this.player.PlaybackError += Player_PlaybackError; case ".webm": mimeType = "audio/webm"; break;
case ".wav": mimeType = "audio/wav"; break;
case ".ogg": mimeType = "audio/ogg"; break;
case ".mp3": mimeType = "audio/mp3"; break;
case ".flac": mimeType = "audio/flac"; break;
case ".opus": mimeType = "audio/ogg; codecs=opus"; break;
default: mimeType = null; break;
} }
public void Play(string file){ try{
player.Play(file); return ResourceHandler.FromFilePath(path, mimeType);
} }catch{
FormBrowser browser = FormManager.TryFind<FormBrowser>();
public bool SetVolume(int volume){ browser?.InvokeAsyncSafe(() => {
return player.SetVolume(volume); using(FormMessage form = new FormMessage("Sound Notification Error", "Could not find custom notification sound file:\n"+path, MessageBoxIcon.Error)){
} form.AddButton(FormMessage.Ignore, ControlType.Cancel | ControlType.Focused);
private void Player_PlaybackError(object sender, PlaybackErrorEventArgs e){ Button btnViewOptions = form.AddButton("View Options");
PlaybackError?.Invoke(this, e); btnViewOptions.Width += 16;
} btnViewOptions.Location = new Point(btnViewOptions.Location.X-16, btnViewOptions.Location.Y);
public void Dispose(){ if (form.ShowDialog() == DialogResult.OK && form.ClickedButton == btnViewOptions){
player.Dispose(); browser.OpenSettings(typeof(TabSettingsSounds));
}
}
});
return null;
}
} }
} }
} }

View File

@@ -1,16 +1,15 @@
using System; using System;
using System.Text; using System.Text;
using System.Windows.Forms;
using CefSharp;
using TweetDuck.Core.Bridge; using TweetDuck.Core.Bridge;
using TweetDuck.Data;
using TweetDuck.Resources; using TweetDuck.Resources;
namespace TweetDuck.Core.Notification{ namespace TweetDuck.Core.Notification{
sealed class TweetNotification{ sealed class TweetNotification{
private const string DefaultHeadLayout = @"<html class='os-windows txt-size--14' data-td-font='medium' data-td-theme='dark'><head><meta charset='utf-8'><meta http-equiv='X-UA-Compatible' content='chrome=1'><link rel='stylesheet' href='https://ton.twimg.com/tweetdeck-web/web/css/font.5ef884f9f9.css'><link rel='stylesheet' href='https://ton.twimg.com/tweetdeck-web/web/css/app-dark.5631e0dd42.css'><style type='text/css'>body{background:#222426}</style>"; private const string DefaultHeadLayout = @"<html class=""scroll-v os-windows dark txt-size--14"" lang=""en-US"" id=""tduck"" data-td-font=""medium"" data-td-theme=""dark""><head><meta charset=""utf-8""><link href=""https://ton.twimg.com/tweetdeck-web/web/dist/bundle.4b1f87e09d.css"" rel=""stylesheet""><style type='text/css'>body { background: rgb(34, 36, 38) !important }</style>";
private static readonly string CustomCSS = ScriptLoader.LoadResource("styles/notification.css"); public static readonly ResourceLink AppLogo = new ResourceLink("https://ton.twimg.com/tduck/avatar", ResourceHandler.FromByteArray(Properties.Resources.avatar, "image/png"));
public static TweetNotification Example(string html, int characters){
return new TweetNotification(string.Empty, string.Empty, "Home", html, characters, string.Empty, string.Empty, true);
}
public enum Position{ public enum Position{
TopLeft, TopRight, BottomLeft, BottomRight, Custom TopLeft, TopRight, BottomLeft, BottomRight, Custom
@@ -29,11 +28,8 @@ namespace TweetDuck.Core.Notification{
private readonly string html; private readonly string html;
private readonly int characters; private readonly int characters;
private readonly bool isExample;
public TweetNotification(string columnId, string chirpId, string title, string html, int characters, string tweetUrl, string quoteUrl) : this(columnId, chirpId, title, html, characters, tweetUrl, quoteUrl, false){} public TweetNotification(string columnId, string chirpId, string title, string html, int characters, string tweetUrl, string quoteUrl){
private TweetNotification(string columnId, string chirpId, string title, string html, int characters, string tweetUrl, string quoteUrl, bool isExample){
this.ColumnId = columnId; this.ColumnId = columnId;
this.ChirpId = chirpId; this.ChirpId = chirpId;
@@ -43,37 +39,35 @@ namespace TweetDuck.Core.Notification{
this.html = html; this.html = html;
this.characters = characters; this.characters = characters;
this.isExample = isExample;
} }
public int GetDisplayDuration(int value){ public int GetDisplayDuration(int value){
return 2000+Math.Max(1000, value*characters); return 2000+Math.Max(1000, value*characters);
} }
public string GenerateHtml(string bodyClasses = null, bool enableCustomCSS = true){ public string GenerateHtml(string bodyClasses, Control sync){
StringBuilder build = new StringBuilder(); string headLayout = TweetDeckBridge.NotificationHeadLayout ?? DefaultHeadLayout;
string mainCSS = ScriptLoader.LoadResource("styles/notification.css", sync) ?? string.Empty;
string customCSS = Program.Config.User.CustomNotificationCSS ?? string.Empty;
StringBuilder build = new StringBuilder(320 + headLayout.Length + mainCSS.Length + customCSS.Length + html.Length);
build.Append("<!DOCTYPE html>"); build.Append("<!DOCTYPE html>");
build.Append(TweetDeckBridge.NotificationHeadLayout ?? DefaultHeadLayout); build.Append(headLayout);
build.Append("<style type='text/css'>").Append(mainCSS).Append("</style>");
if (enableCustomCSS){ if (!string.IsNullOrWhiteSpace(customCSS)){
build.Append("<style type='text/css'>").Append(CustomCSS).Append("</style>"); build.Append("<style type='text/css'>").Append(customCSS).Append("</style>");
if (!string.IsNullOrEmpty(Program.UserConfig.CustomNotificationCSS)){
build.Append("<style type='text/css'>").Append(Program.UserConfig.CustomNotificationCSS).Append("</style>");
}
} }
build.Append("</head>"); build.Append("</head><body class='scroll-styled-v system-font-stack");
build.Append("<body class='scroll-styled-v");
if (!string.IsNullOrEmpty(bodyClasses)){ if (!string.IsNullOrEmpty(bodyClasses)){
build.Append(' ').Append(bodyClasses); build.Append(' ').Append(bodyClasses);
} }
build.Append('\'').Append(isExample ? " td-example-notification" : "").Append("><div class='column' style='width:100%;height:auto;overflow:initial;'>"); build.Append("'><div class='column' style='width:100%!important;min-height:100vh!important;height:auto!important;overflow:initial!important;'>");
build.Append(html); build.Append(html);
build.Append("</div></body>"); build.Append("</div></body></html>");
build.Append("</html>");
return build.ToString(); return build.ToString();
} }
} }

View File

@@ -1,7 +1,11 @@
using System; using System;
using System.Diagnostics.CodeAnalysis;
using System.Linq;
using System.Reflection;
using TweetDuck.Data.Serialization; using TweetDuck.Data.Serialization;
namespace TweetDuck.Core.Other.Analytics{ namespace TweetDuck.Core.Other.Analytics{
[SuppressMessage("ReSharper", "AutoPropertyCanBeMadeGetOnly.Local")]
sealed class AnalyticsFile{ sealed class AnalyticsFile{
private static readonly FileSerializer<AnalyticsFile> Serializer = new FileSerializer<AnalyticsFile>(); private static readonly FileSerializer<AnalyticsFile> Serializer = new FileSerializer<AnalyticsFile>();
@@ -10,15 +14,14 @@ namespace TweetDuck.Core.Other.Analytics{
ConvertToString = value => value.ToBinary().ToString(), ConvertToString = value => value.ToBinary().ToString(),
ConvertToObject = value => DateTime.FromBinary(long.Parse(value)) ConvertToObject = value => DateTime.FromBinary(long.Parse(value))
}); });
Serializer.RegisterTypeConverter(typeof(Counter), new SingleTypeConverter<Counter>{
ConvertToString = value => value.Value.ToString(),
ConvertToObject = value => int.Parse(value)
});
} }
public enum Event{ public static readonly AnalyticsFile Dummy = new AnalyticsFile();
OpenOptions, OpenPlugins, OpenAbout, OpenGuide,
DesktopNotification, SoundNotification,
BrowserContextMenu, BrowserExtraMouseButton,
NotificationContextMenu, NotificationExtraMouseButton, NotificationKeyboardShortcut,
TweetScreenshot, TweetDetail, VideoPlay, GCReload
}
// STATE PROPERTIES // STATE PROPERTIES
@@ -28,57 +31,61 @@ namespace TweetDuck.Core.Other.Analytics{
// USAGE DATA // USAGE DATA
public int CountOpenOptions { get; private set; } = 0; public Counter OpenOptions { get; private set; } = 0;
public int CountOpenPlugins { get; private set; } = 0; public Counter OpenPlugins { get; private set; } = 0;
public int CountOpenAbout { get; private set; } = 0; public Counter OpenAbout { get; private set; } = 0;
public int CountOpenGuide { get; private set; } = 0; public Counter OpenGuide { get; private set; } = 0;
public int CountDesktopNotifications { get; private set; } = 0; public Counter DesktopNotifications { get; private set; } = 0;
public int CountSoundNotifications { get; private set; } = 0; public Counter SoundNotifications { get; private set; } = 0;
public Counter NotificationMutes { get; private set; } = 0;
public int CountBrowserContextMenus { get; private set; } = 0; public Counter BrowserContextMenus { get; private set; } = 0;
public int CountBrowserExtraMouseButtons { get; private set; } = 0; public Counter BrowserExtraMouseButtons { get; private set; } = 0;
public int CountNotificationContextMenus { get; private set; } = 0; public Counter NotificationContextMenus { get; private set; } = 0;
public int CountNotificationExtraMouseButtons { get; private set; } = 0; public Counter NotificationExtraMouseButtons { get; private set; } = 0;
public int CountNotificationKeyboardShortcuts { get; private set; } = 0; public Counter NotificationKeyboardShortcuts { get; private set; } = 0;
public int CountTweetScreenshots { get; private set; } = 0; public Counter BrowserReloads { get; private set; } = 0;
public int CountTweetDetails { get; private set; } = 0; public Counter CopiedUsernames { get; private set; } = 0;
public int CountVideoPlays { get; private set; } = 0; public Counter ViewedImages { get; private set; } = 0;
public int CountGCReloads { get; private set; } = 0; public Counter DownloadedImages { get; private set; } = 0;
public Counter DownloadedVideos { get; private set; } = 0;
public Counter UsedROT13 { get; private set; } = 0;
public Counter TweetScreenshots { get; private set; } = 0;
public Counter TweetDetails { get; private set; } = 0;
public Counter VideoPlays { get; private set; } = 0;
// END OF DATA // END OF DATA
public event EventHandler PropertyChanged;
private readonly string file; private readonly string file;
private AnalyticsFile(string file){ private AnalyticsFile(string file){
this.file = file; this.file = file;
} }
public void TriggerEvent(Event e){ private AnalyticsFile(){
switch(e){ this.file = null;
case Event.OpenOptions: ++CountOpenOptions; break;
case Event.OpenPlugins: ++CountOpenPlugins; break;
case Event.OpenAbout: ++CountOpenAbout; break;
case Event.OpenGuide: ++CountOpenGuide; break;
case Event.DesktopNotification: ++CountDesktopNotifications; break;
case Event.SoundNotification: ++CountSoundNotifications; break;
case Event.BrowserContextMenu: ++CountBrowserContextMenus; break;
case Event.BrowserExtraMouseButton: ++CountBrowserExtraMouseButtons; break;
case Event.NotificationContextMenu: ++CountNotificationContextMenus; break;
case Event.NotificationExtraMouseButton: ++CountNotificationExtraMouseButtons; break;
case Event.NotificationKeyboardShortcut: ++CountNotificationKeyboardShortcuts; break;
case Event.TweetScreenshot: ++CountTweetScreenshots; break;
case Event.TweetDetail: ++CountTweetDetails; break;
case Event.VideoPlay: ++CountVideoPlays; break;
case Event.GCReload: ++CountGCReloads; break;
} }
private void SetupProperties(){
foreach(Counter counter in GetType().GetProperties(BindingFlags.Instance | BindingFlags.Public).Where(prop => prop.PropertyType == typeof(Counter)).Select(prop => (Counter)prop.GetValue(this))){
counter.SetOwner(this);
}
}
public void OnPropertyChanged(){
PropertyChanged?.Invoke(this, EventArgs.Empty);
} }
public void Save(){ public void Save(){
if (file == null){
return;
}
try{ try{
Serializer.Write(file, this); Serializer.Write(file, this);
}catch(Exception e){ }catch(Exception e){
@@ -95,7 +102,34 @@ namespace TweetDuck.Core.Other.Analytics{
Program.Reporter.HandleException("Analytics File Error", "Could not open the analytics file.", true, e); Program.Reporter.HandleException("Analytics File Error", "Could not open the analytics file.", true, e);
} }
config.SetupProperties();
return config; return config;
} }
public interface IProvider{
AnalyticsFile AnalyticsFile { get; }
}
public sealed class Counter{
public int Value { get; private set; }
private AnalyticsFile owner;
public Counter(int value){
this.Value = value;
}
public void SetOwner(AnalyticsFile owner){
this.owner = owner;
}
public void Trigger(){
++Value;
owner?.OnPropertyChanged();
}
public static implicit operator int(Counter counter) => counter.Value;
public static implicit operator Counter(int value) => new Counter(value);
}
} }
} }

View File

@@ -1,4 +1,8 @@
using System; // Uncomment to debug reports locally
// #define ANALYTICS_LOCALHOST
// #define ANALYTICS_INSTANT
using System;
using System.Net; using System.Net;
using System.Threading.Tasks; using System.Threading.Tasks;
using System.Timers; using System.Timers;
@@ -8,8 +12,15 @@ using TweetDuck.Plugins;
namespace TweetDuck.Core.Other.Analytics{ namespace TweetDuck.Core.Other.Analytics{
sealed class AnalyticsManager : IDisposable{ sealed class AnalyticsManager : IDisposable{
private static readonly TimeSpan CollectionInterval = TimeSpan.FromDays(7); private static readonly TimeSpan CollectionInterval = TimeSpan.FromDays(14);
private static readonly Uri CollectionUrl = new Uri("https://tweetduck.chylex.com/breadcrumb/report");
private static readonly Uri CollectionUrl = new Uri(
#if (DEBUG && ANALYTICS_LOCALHOST)
"http://localhost/newhome/tweetduck/~breadcrumb/request.php?type=report"
#else
"https://tweetduck.chylex.com/breadcrumb/report"
#endif
);
public AnalyticsFile File { get; } public AnalyticsFile File { get; }
@@ -20,7 +31,9 @@ namespace TweetDuck.Core.Other.Analytics{
public AnalyticsManager(FormBrowser browser, PluginManager plugins, string file){ public AnalyticsManager(FormBrowser browser, PluginManager plugins, string file){
this.browser = browser; this.browser = browser;
this.plugins = plugins; this.plugins = plugins;
this.File = AnalyticsFile.Load(file); this.File = AnalyticsFile.Load(file);
this.File.PropertyChanged += File_PropertyChanged;
this.currentTimer = new Timer{ SynchronizingObject = browser }; this.currentTimer = new Timer{ SynchronizingObject = browser };
this.currentTimer.Elapsed += currentTimer_Elapsed; this.currentTimer.Elapsed += currentTimer_Elapsed;
@@ -29,14 +42,20 @@ namespace TweetDuck.Core.Other.Analytics{
this.saveTimer.Elapsed += saveTimer_Elapsed; this.saveTimer.Elapsed += saveTimer_Elapsed;
if (this.File.LastCollectionVersion != Program.VersionTag){ if (this.File.LastCollectionVersion != Program.VersionTag){
ScheduleReportIn(TimeSpan.FromHours(12), string.Empty); ScheduleReportIn(TimeSpan.FromHours(8), string.Empty);
} }
else{ else{
RestartTimer(); RestartTimer();
} }
#if (DEBUG && ANALYTICS_INSTANT)
SendReport();
#endif
} }
public void Dispose(){ public void Dispose(){
File.PropertyChanged -= File_PropertyChanged;
if (saveTimer.Enabled){ if (saveTimer.Enabled){
File.Save(); File.Save();
} }
@@ -45,8 +64,7 @@ namespace TweetDuck.Core.Other.Analytics{
saveTimer.Dispose(); saveTimer.Dispose();
} }
public void TriggerEvent(AnalyticsFile.Event e){ private void File_PropertyChanged(object sender, EventArgs e){
File.TriggerEvent(e);
saveTimer.Enabled = true; saveTimer.Enabled = true;
} }
@@ -72,7 +90,7 @@ namespace TweetDuck.Core.Other.Analytics{
TimeSpan diff = DateTime.Now.Subtract(File.LastDataCollection); TimeSpan diff = DateTime.Now.Subtract(File.LastDataCollection);
int minutesTillNext = (int)(CollectionInterval.TotalMinutes-Math.Floor(diff.TotalMinutes)); int minutesTillNext = (int)(CollectionInterval.TotalMinutes-Math.Floor(diff.TotalMinutes));
currentTimer.Interval = Math.Max(minutesTillNext, 1)*60000; currentTimer.Interval = Math.Max(minutesTillNext, 2)*60000;
currentTimer.Start(); currentTimer.Start();
} }
@@ -94,6 +112,11 @@ namespace TweetDuck.Core.Other.Analytics{
Task.Factory.StartNew(() => { Task.Factory.StartNew(() => {
AnalyticsReport report = AnalyticsReportGenerator.Create(File, info, plugins); AnalyticsReport report = AnalyticsReportGenerator.Create(File, info, plugins);
#if (DEBUG && !ANALYTICS_INSTANT)
System.Diagnostics.Debugger.Break();
#endif
BrowserUtils.CreateWebClient().UploadValues(CollectionUrl, "POST", report.ToNameValueCollection()); BrowserUtils.CreateWebClient().UploadValues(CollectionUrl, "POST", report.ToNameValueCollection());
}).ContinueWith(task => browser.InvokeAsyncSafe(() => { }).ContinueWith(task => browser.InvokeAsyncSafe(() => {
if (task.Status == TaskStatus.RanToCompletion){ if (task.Status == TaskStatus.RanToCompletion){
@@ -117,6 +140,14 @@ namespace TweetDuck.Core.Other.Analytics{
message = "HTTP Error "+(response != null ? $"{(int)response.StatusCode} ({response.StatusDescription})" : "(unknown code)"); message = "HTTP Error "+(response != null ? $"{(int)response.StatusCode} ({response.StatusDescription})" : "(unknown code)");
break; break;
} }
#if DEBUG
System.IO.Stream responseStream = e.Response.GetResponseStream();
if (responseStream != null){
System.Diagnostics.Debug.WriteLine(new System.IO.StreamReader(responseStream).ReadToEnd());
}
#endif
} }
ScheduleReportIn(TimeSpan.FromHours(4), message ?? "Error: "+(task.Exception.InnerException?.Message ?? task.Exception.Message)); ScheduleReportIn(TimeSpan.FromHours(4), message ?? "Error: "+(task.Exception.InnerException?.Message ?? task.Exception.Message));

View File

@@ -40,7 +40,7 @@ namespace TweetDuck.Core.Other.Analytics{
} }
public override string ToString(){ public override string ToString(){
StringBuilder build = new StringBuilder(); StringBuilder build = new StringBuilder(625);
foreach(DictionaryEntry entry in data){ foreach(DictionaryEntry entry in data){
if (entry.Value == null){ if (entry.Value == null){

View File

@@ -11,6 +11,7 @@ using System.Text.RegularExpressions;
using TweetDuck.Core.Notification; using TweetDuck.Core.Notification;
using TweetDuck.Core.Utils; using TweetDuck.Core.Utils;
using TweetDuck.Plugins; using TweetDuck.Plugins;
using TweetDuck.Plugins.Enums;
namespace TweetDuck.Core.Other.Analytics{ namespace TweetDuck.Core.Other.Analytics{
static class AnalyticsReportGenerator{ static class AnalyticsReportGenerator{
@@ -20,6 +21,7 @@ namespace TweetDuck.Core.Other.Analytics{
return new AnalyticsReport{ return new AnalyticsReport{
{ "App Version" , Program.VersionTag }, { "App Version" , Program.VersionTag },
{ "App Type" , Program.IsPortable ? "portable" : "installed" }, { "App Type" , Program.IsPortable ? "portable" : "installed" },
{ "App Dev Tools" , Bool(BrowserUtils.HasDevTools) },
0, 0,
{ "System Name" , SystemName }, { "System Name" , SystemName },
{ "System Edition" , SystemEdition }, { "System Edition" , SystemEdition },
@@ -35,16 +37,23 @@ namespace TweetDuck.Core.Other.Analytics{
{ "Screen DPI" , info.DPI != null ? Exact(info.DPI.Value) : "(unknown)" }, { "Screen DPI" , info.DPI != null ? Exact(info.DPI.Value) : "(unknown)" },
0, 0,
{ "Hardware Acceleration" , Bool(SysConfig.HardwareAcceleration) }, { "Hardware Acceleration" , Bool(SysConfig.HardwareAcceleration) },
{ "Browser GC Reload" , Bool(SysConfig.EnableBrowserGCReload) }, { "Clear Cache Automatically" , Bool(SysConfig.ClearCacheAutomatically) },
{ "Browser GC Threshold" , Exact(SysConfig.BrowserMemoryThreshold) }, { "Clear Cache Threshold" , Exact(SysConfig.ClearCacheThreshold) },
0, 0,
{ "Expand Links" , Bool(UserConfig.ExpandLinksOnHover) }, { "Expand Links" , Bool(UserConfig.ExpandLinksOnHover) },
{ "Switch Account Selectors" , Bool(UserConfig.SwitchAccountSelectors) },
{ "Search In First Column" , Bool(UserConfig.OpenSearchInFirstColumn) }, { "Search In First Column" , Bool(UserConfig.OpenSearchInFirstColumn) },
{ "Keep Like Follow Dialogs Open" , Bool(UserConfig.KeepLikeFollowDialogsOpen) },
{ "Best Image Quality" , Bool(UserConfig.BestImageQuality) }, { "Best Image Quality" , Bool(UserConfig.BestImageQuality) },
{ "Spell Check" , Bool(UserConfig.EnableSpellCheck) }, { "Animated Images" , Bool(UserConfig.EnableAnimatedImages) },
0,
{ "Smooth Scrolling" , Bool(UserConfig.EnableSmoothScrolling) },
{ "Custom Browser" , CustomBrowser },
{ "Zoom" , Exact(UserConfig.ZoomLevel) }, { "Zoom" , Exact(UserConfig.ZoomLevel) },
0, 0,
{ "Spell Check" , Bool(UserConfig.EnableSpellCheck) },
{ "Spell Check Language" , UserConfig.SpellCheckLanguage.ToLower() },
{ "Translation Target Language" , UserConfig.TranslationTarget },
0,
{ "Updates" , Bool(UserConfig.EnableUpdateCheck) }, { "Updates" , Bool(UserConfig.EnableUpdateCheck) },
{ "Update Dismissed" , Bool(!string.IsNullOrEmpty(UserConfig.DismissedUpdate)) }, { "Update Dismissed" , Bool(!string.IsNullOrEmpty(UserConfig.DismissedUpdate)) },
0, 0,
@@ -62,14 +71,15 @@ namespace TweetDuck.Core.Other.Analytics{
{ "Notification Non-Intrusive" , Bool(UserConfig.NotificationNonIntrusiveMode) }, { "Notification Non-Intrusive" , Bool(UserConfig.NotificationNonIntrusiveMode) },
{ "Notification Idle Pause" , Exact(UserConfig.NotificationIdlePauseSeconds) }, { "Notification Idle Pause" , Exact(UserConfig.NotificationIdlePauseSeconds) },
{ "Custom Sound Notification" , string.IsNullOrEmpty(UserConfig.NotificationSoundPath) ? "off" : Path.GetExtension(UserConfig.NotificationSoundPath) }, { "Custom Sound Notification" , string.IsNullOrEmpty(UserConfig.NotificationSoundPath) ? "off" : Path.GetExtension(UserConfig.NotificationSoundPath) },
{ "Custom Sound Notification Volume" , RoundUp(UserConfig.NotificationSoundVolume, 5) },
0, 0,
{ "Program Arguments" , List(ProgramArguments) }, { "Program Arguments" , List(ProgramArguments) },
{ "Custom CEF Arguments" , RoundUp((UserConfig.CustomCefArgs ?? string.Empty).Length, 10) }, { "Custom CEF Arguments" , RoundUp((UserConfig.CustomCefArgs ?? string.Empty).Length, 10) },
{ "Custom Browser CSS" , RoundUp((UserConfig.CustomBrowserCSS ?? string.Empty).Length, 50) }, { "Custom Browser CSS" , RoundUp((UserConfig.CustomBrowserCSS ?? string.Empty).Length, 50) },
{ "Custom Notification CSS" , RoundUp((UserConfig.CustomNotificationCSS ?? string.Empty).Length, 50) }, { "Custom Notification CSS" , RoundUp((UserConfig.CustomNotificationCSS ?? string.Empty).Length, 50) },
0, 0,
{ "Plugins All" , List(plugins.Plugins.Select(plugin => plugin.Identifier)) }, { "Plugins All" , List(plugins.Plugins.Select(Plugin)) },
{ "Plugins Enabled" , List(plugins.Plugins.Where(plugin => plugins.Config.IsEnabled(plugin)).Select(plugin => plugin.Identifier)) }, { "Plugins Enabled" , List(plugins.Plugins.Where(plugin => plugins.Config.IsEnabled(plugin)).Select(Plugin)) },
0, 0,
{ "Theme" , Dict(editLayoutDesign, "_theme", "light/def") }, { "Theme" , Dict(editLayoutDesign, "_theme", "light/def") },
{ "Column Width" , Dict(editLayoutDesign, "columnWidth", "310px/def") }, { "Column Width" , Dict(editLayoutDesign, "columnWidth", "310px/def") },
@@ -85,31 +95,38 @@ namespace TweetDuck.Core.Other.Analytics{
{ "Reply Account Mode" , ReplyAccountConfigFromPlugin }, { "Reply Account Mode" , ReplyAccountConfigFromPlugin },
{ "Template Count" , Exact(TemplateCountFromPlugin) }, { "Template Count" , Exact(TemplateCountFromPlugin) },
0, 0,
{ "Opened Options" , LogRound(file.CountOpenOptions, 4) }, { "Opened Options" , LogRound(file.OpenOptions, 4) },
{ "Opened Plugins" , LogRound(file.CountOpenPlugins, 4) }, { "Opened Plugins" , LogRound(file.OpenPlugins, 4) },
{ "Opened About" , LogRound(file.CountOpenAbout, 4) }, { "Opened About" , LogRound(file.OpenAbout, 4) },
{ "Opened Guide" , LogRound(file.CountOpenGuide, 4) }, { "Opened Guide" , LogRound(file.OpenGuide, 4) },
{ "Desktop Notifications" , LogRound(file.CountDesktopNotifications, 5) }, { "Desktop Notifications" , LogRound(file.DesktopNotifications, 5) },
{ "Sound Notifications" , LogRound(file.CountSoundNotifications, 5) }, { "Sound Notifications" , LogRound(file.SoundNotifications, 5) },
{ "Browser Context Menus" , LogRound(file.CountBrowserContextMenus, 2) }, { "Notification Mutes" , LogRound(file.NotificationMutes, 2) },
{ "Browser Extra Mouse Buttons" , LogRound(file.CountBrowserExtraMouseButtons, 2) }, { "Browser Context Menus" , LogRound(file.BrowserContextMenus, 2) },
{ "Notification Context Menus" , LogRound(file.CountNotificationContextMenus, 2) }, { "Browser Extra Mouse Buttons" , LogRound(file.BrowserExtraMouseButtons, 2) },
{ "Notification Extra Mouse Buttons" , LogRound(file.CountNotificationExtraMouseButtons, 2) }, { "Notification Context Menus" , LogRound(file.NotificationContextMenus, 2) },
{ "Notification Keyboard Shortcuts" , LogRound(file.CountNotificationKeyboardShortcuts, 2) }, { "Notification Extra Mouse Buttons" , LogRound(file.NotificationExtraMouseButtons, 2) },
{ "Tweet Screenshots" , LogRound(file.CountTweetScreenshots, 2) }, { "Notification Keyboard Shortcuts" , LogRound(file.NotificationKeyboardShortcuts, 2) },
{ "Tweet Details" , LogRound(file.CountTweetDetails, 2) }, { "Browser Reloads" , LogRound(file.BrowserReloads, 2) },
{ "Video Plays" , LogRound(file.CountVideoPlays, 4) }, { "Copied Usernames" , LogRound(file.CopiedUsernames, 2) },
{ "GC Reloads" , LogRound(file.CountGCReloads, 4) } { "Viewed Images" , LogRound(file.ViewedImages, 2) },
{ "Downloaded Images" , LogRound(file.DownloadedImages, 2) },
{ "Downloaded Videos" , LogRound(file.DownloadedVideos, 2) },
{ "Used ROT13" , LogRound(file.UsedROT13, 2) },
{ "Tweet Screenshots" , LogRound(file.TweetScreenshots, 2) },
{ "Tweet Details" , LogRound(file.TweetDetails, 2) },
{ "Video Plays" , LogRound(file.VideoPlays, 4) }
}.FinalizeReport(); }.FinalizeReport();
} }
private static UserConfig UserConfig => Program.UserConfig; private static UserConfig UserConfig => Program.Config.User;
private static SystemConfig SysConfig => Program.SystemConfig; private static SystemConfig SysConfig => Program.Config.System;
private static string Bool(bool value) => value ? "on" : "off"; private static string Bool(bool value) => value ? "on" : "off";
private static string Exact(int value) => value.ToString(); private static string Exact(int value) => value.ToString();
private static string RoundUp(int value, int multiple) => (multiple*(int)Math.Ceiling((double)value/multiple)).ToString(); private static string RoundUp(int value, int multiple) => (multiple*(int)Math.Ceiling((double)value/multiple)).ToString();
private static string LogRound(int value, int logBase) => (value <= 0 ? 0 : (int)Math.Pow(logBase, Math.Floor(Math.Log(value, logBase)))).ToString(); private static string LogRound(int value, int logBase) => (value <= 0 ? 0 : (int)Math.Pow(logBase, Math.Floor(Math.Log(value, logBase)))).ToString();
private static string Plugin(Plugin plugin) => plugin.Group.GetIdentifierPrefixShort()+plugin.Identifier.Substring(plugin.Group.GetIdentifierPrefix().Length);
private static string Dict(Dictionary<string, string> dict, string key, string def = "(unknown)") => dict.TryGetValue(key, out string value) ? value : def; private static string Dict(Dictionary<string, string> dict, string key, string def = "(unknown)") => dict.TryGetValue(key, out string value) ? value : def;
private static string List(IEnumerable<string> list) => string.Join("|", list.DefaultIfEmpty("(none)")); private static string List(IEnumerable<string> list) => string.Join("|", list.DefaultIfEmpty("(none)"));
@@ -127,11 +144,16 @@ namespace TweetDuck.Core.Other.Analytics{
using(RegistryKey key = Registry.LocalMachine.OpenSubKey(@"SOFTWARE\Microsoft\Windows NT\CurrentVersion", false)){ using(RegistryKey key = Registry.LocalMachine.OpenSubKey(@"SOFTWARE\Microsoft\Windows NT\CurrentVersion", false)){
// ReSharper disable once PossibleNullReferenceException // ReSharper disable once PossibleNullReferenceException
osName = key.GetValue("ProductName") as string; osName = key.GetValue("ProductName") as string;
osEdition = key.GetValue("EditionID") as string;
osBuild = key.GetValue("CurrentBuild") as string; osBuild = key.GetValue("CurrentBuild") as string;
osEdition = null;
if (osName != null && osEdition != null){ if (osName != null){
osName = osName.Replace(osEdition, "").TrimEnd(); Match match = Regex.Match(osName, @"^(.*?\d+(?:\.\d+)?) (.*)$");
if (match.Success){
osName = match.Groups[1].Value;
osEdition = match.Groups[2].Value;
}
} }
} }
}catch{ }catch{
@@ -175,6 +197,12 @@ namespace TweetDuck.Core.Other.Analytics{
ProgramArguments = args.Keys.Select(key => key.TrimStart('-')).ToArray(); ProgramArguments = args.Keys.Select(key => key.TrimStart('-')).ToArray();
} }
private static string CustomBrowser{
get{
return Path.GetFileName(UserConfig.BrowserPath) ?? string.Empty;
}
}
private static string TrayMode{ private static string TrayMode{
get{ get{
switch(UserConfig.TrayBehavior){ switch(UserConfig.TrayBehavior){
@@ -257,7 +285,7 @@ namespace TweetDuck.Core.Other.Analytics{
Match matchAdvanced = Regex.Match(data, "useAdvancedSelector:(.*?)(?:,|$)", RegexOptions.Multiline); Match matchAdvanced = Regex.Match(data, "useAdvancedSelector:(.*?)(?:,|$)", RegexOptions.Multiline);
if (!matchType.Success){ if (!matchType.Success){
return "(unknown)"; return data.Contains("defaultAccount:\"\"") ? "(legacy)" : "(unknown)";
} }
string accType = matchType.Groups[1].Value == "#" ? matchType.Groups[2].Value : "account"; string accType = matchType.Groups[1].Value == "#" ? matchType.Groups[2].Value : "account";
@@ -274,7 +302,7 @@ namespace TweetDuck.Core.Other.Analytics{
return new ExternalInfo(); return new ExternalInfo();
} }
else{ else{
Screen screen = Screen.FromControl(form); Screen screen = Screen.FromControl(form); // works on multi-monitor setups even in tray
int dpi; int dpi;
using(Graphics graphics = form.CreateGraphics()){ using(Graphics graphics = form.CreateGraphics()){

View File

@@ -23,7 +23,6 @@ namespace TweetDuck.Core.Other {
/// the contents of this method with the code editor. /// the contents of this method with the code editor.
/// </summary> /// </summary>
private void InitializeComponent() { private void InitializeComponent() {
System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(FormAbout));
this.pictureLogo = new System.Windows.Forms.PictureBox(); this.pictureLogo = new System.Windows.Forms.PictureBox();
this.labelDescription = new System.Windows.Forms.Label(); this.labelDescription = new System.Windows.Forms.Label();
this.labelTips = new System.Windows.Forms.LinkLabel(); this.labelTips = new System.Windows.Forms.LinkLabel();
@@ -38,11 +37,11 @@ namespace TweetDuck.Core.Other {
// //
this.pictureLogo.BackgroundImageLayout = System.Windows.Forms.ImageLayout.None; this.pictureLogo.BackgroundImageLayout = System.Windows.Forms.ImageLayout.None;
this.pictureLogo.ErrorImage = null; this.pictureLogo.ErrorImage = null;
this.pictureLogo.Image = ((System.Drawing.Image)(resources.GetObject("pictureLogo.Image")));
this.pictureLogo.InitialImage = null; this.pictureLogo.InitialImage = null;
this.pictureLogo.Location = new System.Drawing.Point(12, 12); this.pictureLogo.Location = new System.Drawing.Point(12, 12);
this.pictureLogo.Name = "pictureLogo"; this.pictureLogo.Name = "pictureLogo";
this.pictureLogo.Size = new System.Drawing.Size(96, 96); this.pictureLogo.Size = new System.Drawing.Size(96, 96);
this.pictureLogo.SizeMode = System.Windows.Forms.PictureBoxSizeMode.StretchImage;
this.pictureLogo.TabIndex = 0; this.pictureLogo.TabIndex = 0;
this.pictureLogo.TabStop = false; this.pictureLogo.TabStop = false;
// //
@@ -51,23 +50,22 @@ namespace TweetDuck.Core.Other {
this.labelDescription.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom) this.labelDescription.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom)
| System.Windows.Forms.AnchorStyles.Left) | System.Windows.Forms.AnchorStyles.Left)
| System.Windows.Forms.AnchorStyles.Right))); | System.Windows.Forms.AnchorStyles.Right)));
this.labelDescription.Font = new System.Drawing.Font("Microsoft Sans Serif", 9.75F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(238))); this.labelDescription.Font = new System.Drawing.Font("Segoe UI", 9.75F);
this.labelDescription.Location = new System.Drawing.Point(114, 12); this.labelDescription.Location = new System.Drawing.Point(114, 12);
this.labelDescription.Name = "labelDescription"; this.labelDescription.Name = "labelDescription";
this.labelDescription.Size = new System.Drawing.Size(232, 109); this.labelDescription.Size = new System.Drawing.Size(232, 113);
this.labelDescription.TabIndex = 0; this.labelDescription.TabIndex = 0;
// //
// labelTips // labelTips
// //
this.labelTips.Dock = System.Windows.Forms.DockStyle.Fill; this.labelTips.Dock = System.Windows.Forms.DockStyle.Fill;
this.labelTips.Font = new System.Drawing.Font("Microsoft Sans Serif", 9.75F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(238))); this.labelTips.Font = new System.Drawing.Font("Segoe UI", 9.75F, System.Drawing.FontStyle.Regular);
this.labelTips.LinkArea = new System.Windows.Forms.LinkArea(0, 0); this.labelTips.LinkArea = new System.Windows.Forms.LinkArea(0, 0);
this.labelTips.Location = new System.Drawing.Point(117, 0); this.labelTips.Location = new System.Drawing.Point(117, 0);
this.labelTips.Margin = new System.Windows.Forms.Padding(0); this.labelTips.Margin = new System.Windows.Forms.Padding(0);
this.labelTips.Name = "labelTips"; this.labelTips.Name = "labelTips";
this.labelTips.Size = new System.Drawing.Size(99, 16); this.labelTips.Size = new System.Drawing.Size(99, 18);
this.labelTips.TabIndex = 1; this.labelTips.TabIndex = 1;
this.labelTips.TabStop = true;
this.labelTips.Text = "Tips && Tricks"; this.labelTips.Text = "Tips && Tricks";
this.labelTips.TextAlign = System.Drawing.ContentAlignment.MiddleCenter; this.labelTips.TextAlign = System.Drawing.ContentAlignment.MiddleCenter;
this.labelTips.LinkClicked += new System.Windows.Forms.LinkLabelLinkClickedEventHandler(this.OnLinkClicked); this.labelTips.LinkClicked += new System.Windows.Forms.LinkLabelLinkClickedEventHandler(this.OnLinkClicked);
@@ -76,14 +74,13 @@ namespace TweetDuck.Core.Other {
// //
this.labelWebsite.AutoSize = true; this.labelWebsite.AutoSize = true;
this.labelWebsite.Dock = System.Windows.Forms.DockStyle.Fill; this.labelWebsite.Dock = System.Windows.Forms.DockStyle.Fill;
this.labelWebsite.Font = new System.Drawing.Font("Microsoft Sans Serif", 9.75F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(238))); this.labelWebsite.Font = new System.Drawing.Font("Segoe UI", 9.75F, System.Drawing.FontStyle.Regular);
this.labelWebsite.LinkArea = new System.Windows.Forms.LinkArea(0, 0); this.labelWebsite.LinkArea = new System.Windows.Forms.LinkArea(0, 0);
this.labelWebsite.Location = new System.Drawing.Point(0, 0); this.labelWebsite.Location = new System.Drawing.Point(0, 0);
this.labelWebsite.Margin = new System.Windows.Forms.Padding(0); this.labelWebsite.Margin = new System.Windows.Forms.Padding(0);
this.labelWebsite.Name = "labelWebsite"; this.labelWebsite.Name = "labelWebsite";
this.labelWebsite.Size = new System.Drawing.Size(117, 16); this.labelWebsite.Size = new System.Drawing.Size(117, 18);
this.labelWebsite.TabIndex = 0; this.labelWebsite.TabIndex = 0;
this.labelWebsite.TabStop = true;
this.labelWebsite.Text = "Official Website"; this.labelWebsite.Text = "Official Website";
this.labelWebsite.TextAlign = System.Drawing.ContentAlignment.MiddleLeft; this.labelWebsite.TextAlign = System.Drawing.ContentAlignment.MiddleLeft;
this.labelWebsite.LinkClicked += new System.Windows.Forms.LinkLabelLinkClickedEventHandler(this.OnLinkClicked); this.labelWebsite.LinkClicked += new System.Windows.Forms.LinkLabelLinkClickedEventHandler(this.OnLinkClicked);
@@ -99,24 +96,23 @@ namespace TweetDuck.Core.Other {
this.tablePanelLinks.Controls.Add(this.labelIssues, 2, 0); this.tablePanelLinks.Controls.Add(this.labelIssues, 2, 0);
this.tablePanelLinks.Controls.Add(this.labelWebsite, 0, 0); this.tablePanelLinks.Controls.Add(this.labelWebsite, 0, 0);
this.tablePanelLinks.Controls.Add(this.labelTips, 1, 0); this.tablePanelLinks.Controls.Add(this.labelTips, 1, 0);
this.tablePanelLinks.Location = new System.Drawing.Point(12, 124); this.tablePanelLinks.Location = new System.Drawing.Point(12, 128);
this.tablePanelLinks.Name = "tablePanelLinks"; this.tablePanelLinks.Name = "tablePanelLinks";
this.tablePanelLinks.RowCount = 1; this.tablePanelLinks.RowCount = 1;
this.tablePanelLinks.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 100F)); this.tablePanelLinks.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 100F));
this.tablePanelLinks.Size = new System.Drawing.Size(334, 16); this.tablePanelLinks.Size = new System.Drawing.Size(334, 18);
this.tablePanelLinks.TabIndex = 1; this.tablePanelLinks.TabIndex = 1;
// //
// labelIssues // labelIssues
// //
this.labelIssues.Dock = System.Windows.Forms.DockStyle.Fill; this.labelIssues.Dock = System.Windows.Forms.DockStyle.Fill;
this.labelIssues.Font = new System.Drawing.Font("Microsoft Sans Serif", 9.75F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(238))); this.labelIssues.Font = new System.Drawing.Font("Segoe UI", 9.75F, System.Drawing.FontStyle.Regular);
this.labelIssues.LinkArea = new System.Windows.Forms.LinkArea(0, 0); this.labelIssues.LinkArea = new System.Windows.Forms.LinkArea(0, 0);
this.labelIssues.Location = new System.Drawing.Point(216, 0); this.labelIssues.Location = new System.Drawing.Point(216, 0);
this.labelIssues.Margin = new System.Windows.Forms.Padding(0); this.labelIssues.Margin = new System.Windows.Forms.Padding(0);
this.labelIssues.Name = "labelIssues"; this.labelIssues.Name = "labelIssues";
this.labelIssues.Size = new System.Drawing.Size(118, 16); this.labelIssues.Size = new System.Drawing.Size(118, 18);
this.labelIssues.TabIndex = 2; this.labelIssues.TabIndex = 2;
this.labelIssues.TabStop = true;
this.labelIssues.Text = "Report an Issue"; this.labelIssues.Text = "Report an Issue";
this.labelIssues.TextAlign = System.Drawing.ContentAlignment.MiddleRight; this.labelIssues.TextAlign = System.Drawing.ContentAlignment.MiddleRight;
this.labelIssues.LinkClicked += new System.Windows.Forms.LinkLabelLinkClickedEventHandler(this.OnLinkClicked); this.labelIssues.LinkClicked += new System.Windows.Forms.LinkLabelLinkClickedEventHandler(this.OnLinkClicked);
@@ -126,7 +122,7 @@ namespace TweetDuck.Core.Other {
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
this.BackColor = System.Drawing.Color.White; this.BackColor = System.Drawing.Color.White;
this.ClientSize = new System.Drawing.Size(358, 152); this.ClientSize = new System.Drawing.Size(358, 156);
this.Controls.Add(this.tablePanelLinks); this.Controls.Add(this.tablePanelLinks);
this.Controls.Add(this.labelDescription); this.Controls.Add(this.labelDescription);
this.Controls.Add(this.pictureLogo); this.Controls.Add(this.pictureLogo);

View File

@@ -1,9 +1,11 @@
using System.ComponentModel; using System.ComponentModel;
using System.Drawing;
using System.IO;
using System.Windows.Forms; using System.Windows.Forms;
using TweetDuck.Core.Utils; using TweetDuck.Core.Utils;
namespace TweetDuck.Core.Other{ namespace TweetDuck.Core.Other{
sealed partial class FormAbout : Form{ sealed partial class FormAbout : Form, FormManager.IAppDialog{
private const string TipsLink = "https://github.com/chylex/TweetDuck/wiki"; private const string TipsLink = "https://github.com/chylex/TweetDuck/wiki";
private const string IssuesLink = "https://github.com/chylex/TweetDuck/issues"; private const string IssuesLink = "https://github.com/chylex/TweetDuck/issues";
@@ -17,6 +19,10 @@ namespace TweetDuck.Core.Other{
labelWebsite.Links.Add(new LinkLabel.Link(0, labelWebsite.Text.Length, Program.Website)); labelWebsite.Links.Add(new LinkLabel.Link(0, labelWebsite.Text.Length, Program.Website));
labelTips.Links.Add(new LinkLabel.Link(0, labelTips.Text.Length, TipsLink)); labelTips.Links.Add(new LinkLabel.Link(0, labelTips.Text.Length, TipsLink));
labelIssues.Links.Add(new LinkLabel.Link(0, labelIssues.Text.Length, IssuesLink)); labelIssues.Links.Add(new LinkLabel.Link(0, labelIssues.Text.Length, IssuesLink));
MemoryStream logoStream = new MemoryStream(Properties.Resources.avatar);
pictureLogo.Image = Image.FromStream(logoStream);
Disposed += (sender, args) => logoStream.Dispose();
} }
private void OnLinkClicked(object sender, LinkLabelLinkClickedEventArgs e){ private void OnLinkClicked(object sender, LinkLabelLinkClickedEventArgs e){
@@ -33,7 +39,7 @@ namespace TweetDuck.Core.Other{
} }
private void ShowGuide(){ private void ShowGuide(){
new FormGuide().Show(); FormGuide.Show();
Close(); Close();
} }
} }

View File

@@ -1,246 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<root>
<!--
Microsoft ResX Schema
Version 2.0
The primary goals of this format is to allow a simple XML format
that is mostly human readable. The generation and parsing of the
various data types are done through the TypeConverter classes
associated with the data types.
Example:
... ado.net/XML headers & schema ...
<resheader name="resmimetype">text/microsoft-resx</resheader>
<resheader name="version">2.0</resheader>
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
<value>[base64 mime encoded serialized .NET Framework object]</value>
</data>
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
<comment>This is a comment</comment>
</data>
There are any number of "resheader" rows that contain simple
name/value pairs.
Each data row contains a name, and value. The row also contains a
type or mimetype. Type corresponds to a .NET class that support
text/value conversion through the TypeConverter architecture.
Classes that don't support this are serialized and stored with the
mimetype set.
The mimetype is used for serialized objects, and tells the
ResXResourceReader how to depersist the object. This is currently not
extensible. For a given mimetype the value must be set accordingly:
Note - application/x-microsoft.net.object.binary.base64 is the format
that the ResXResourceWriter will generate, however the reader can
read any of the formats listed below.
mimetype: application/x-microsoft.net.object.binary.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.soap.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.bytearray.base64
value : The object must be serialized into a byte array
: using a System.ComponentModel.TypeConverter
: and then encoded with base64 encoding.
-->
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
<xsd:element name="root" msdata:IsDataSet="true">
<xsd:complexType>
<xsd:choice maxOccurs="unbounded">
<xsd:element name="metadata">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" />
</xsd:sequence>
<xsd:attribute name="name" use="required" type="xsd:string" />
<xsd:attribute name="type" type="xsd:string" />
<xsd:attribute name="mimetype" type="xsd:string" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="assembly">
<xsd:complexType>
<xsd:attribute name="alias" type="xsd:string" />
<xsd:attribute name="name" type="xsd:string" />
</xsd:complexType>
</xsd:element>
<xsd:element name="data">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="resheader">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" />
</xsd:complexType>
</xsd:element>
</xsd:choice>
</xsd:complexType>
</xsd:element>
</xsd:schema>
<resheader name="resmimetype">
<value>text/microsoft-resx</value>
</resheader>
<resheader name="version">
<value>2.0</value>
</resheader>
<resheader name="reader">
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<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="pictureLogo.Image" type="System.Drawing.Bitmap, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value>
iVBORw0KGgoAAAANSUhEUgAAAGAAAABgCAYAAADimHc4AAAABGdBTUEAALGOfPtRkwAAACBjSFJNAACH
DwAAjA8AAP1SAACBQAAAfXkAAOmLAAA85QAAGcxzPIV3AAAKOWlDQ1BQaG90b3Nob3AgSUNDIHByb2Zp
bGUAAEjHnZZ3VFTXFofPvXd6oc0wAlKG3rvAANJ7k15FYZgZYCgDDjM0sSGiAhFFRJoiSFDEgNFQJFZE
sRAUVLAHJAgoMRhFVCxvRtaLrqy89/Ly++Osb+2z97n77L3PWhcAkqcvl5cGSwGQyhPwgzyc6RGRUXTs
AIABHmCAKQBMVka6X7B7CBDJy82FniFyAl8EAfB6WLwCcNPQM4BOB/+fpFnpfIHomAARm7M5GSwRF4g4
JUuQLrbPipgalyxmGCVmvihBEcuJOWGRDT77LLKjmNmpPLaIxTmns1PZYu4V8bZMIUfEiK+ICzO5nCwR
3xKxRoowlSviN+LYVA4zAwAUSWwXcFiJIjYRMYkfEuQi4uUA4EgJX3HcVyzgZAvEl3JJS8/hcxMSBXQd
li7d1NqaQffkZKVwBALDACYrmcln013SUtOZvBwAFu/8WTLi2tJFRbY0tba0NDQzMv2qUP91829K3NtF
ehn4uWcQrf+L7a/80hoAYMyJarPziy2uCoDOLQDI3fti0zgAgKSobx3Xv7oPTTwviQJBuo2xcVZWlhGX
wzISF/QP/U+Hv6GvvmckPu6P8tBdOfFMYYqALq4bKy0lTcinZ6QzWRy64Z+H+B8H/nUeBkGceA6fwxNF
hImmjMtLELWbx+YKuGk8Opf3n5r4D8P+pMW5FonS+BFQY4yA1HUqQH7tBygKESDR+8Vd/6NvvvgwIH55
4SqTi3P/7zf9Z8Gl4iWDm/A5ziUohM4S8jMX98TPEqABAUgCKpAHykAd6ABDYAasgC1wBG7AG/iDEBAJ
VgMWSASpgA+yQB7YBApBMdgJ9oBqUAcaQTNoBcdBJzgFzoNL4Bq4AW6D+2AUTIBnYBa8BgsQBGEhMkSB
5CEVSBPSh8wgBmQPuUG+UBAUCcVCCRAPEkJ50GaoGCqDqqF6qBn6HjoJnYeuQIPQXWgMmoZ+h97BCEyC
qbASrAUbwwzYCfaBQ+BVcAK8Bs6FC+AdcCXcAB+FO+Dz8DX4NjwKP4PnEIAQERqiihgiDMQF8UeikHiE
j6xHipAKpAFpRbqRPuQmMorMIG9RGBQFRUcZomxRnqhQFAu1BrUeVYKqRh1GdaB6UTdRY6hZ1Ec0Ga2I
1kfboL3QEegEdBa6EF2BbkK3oy+ib6Mn0K8xGAwNo42xwnhiIjFJmLWYEsw+TBvmHGYQM46Zw2Kx8lh9
rB3WH8vECrCF2CrsUexZ7BB2AvsGR8Sp4Mxw7rgoHA+Xj6vAHcGdwQ3hJnELeCm8Jt4G749n43PwpfhG
fDf+On4Cv0CQJmgT7AghhCTCJkIloZVwkfCA8JJIJKoRrYmBRC5xI7GSeIx4mThGfEuSIemRXEjRJCFp
B+kQ6RzpLuklmUzWIjuSo8gC8g5yM/kC+RH5jQRFwkjCS4ItsUGiRqJDYkjiuSReUlPSSXK1ZK5kheQJ
yeuSM1J4KS0pFymm1HqpGqmTUiNSc9IUaVNpf+lU6RLpI9JXpKdksDJaMm4ybJkCmYMyF2TGKQhFneJC
YVE2UxopFykTVAxVm+pFTaIWU7+jDlBnZWVkl8mGyWbL1sielh2lITQtmhcthVZKO04bpr1borTEaQln
yfYlrUuGlszLLZVzlOPIFcm1yd2WeydPl3eTT5bfJd8p/1ABpaCnEKiQpbBf4aLCzFLqUtulrKVFS48v
vacIK+opBimuVTyo2K84p6Ss5KGUrlSldEFpRpmm7KicpFyufEZ5WoWiYq/CVSlXOavylC5Ld6Kn0Cvp
vfRZVUVVT1Whar3qgOqCmrZaqFq+WpvaQ3WCOkM9Xr1cvUd9VkNFw08jT6NF454mXpOhmai5V7NPc15L
Wytca6tWp9aUtpy2l3audov2Ax2yjoPOGp0GnVu6GF2GbrLuPt0berCehV6iXo3edX1Y31Kfq79Pf9AA
bWBtwDNoMBgxJBk6GWYathiOGdGMfI3yjTqNnhtrGEcZ7zLuM/5oYmGSYtJoct9UxtTbNN+02/R3Mz0z
llmN2S1zsrm7+QbzLvMXy/SXcZbtX3bHgmLhZ7HVosfig6WVJd+y1XLaSsMq1qrWaoRBZQQwShiXrdHW
ztYbrE9Zv7WxtBHYHLf5zdbQNtn2iO3Ucu3lnOWNy8ft1OyYdvV2o/Z0+1j7A/ajDqoOTIcGh8eO6o5s
xybHSSddpySno07PnU2c+c7tzvMuNi7rXM65Iq4erkWuA24ybqFu1W6P3NXcE9xb3Gc9LDzWepzzRHv6
eO7yHPFS8mJ5NXvNelt5r/Pu9SH5BPtU+zz21fPl+3b7wX7efrv9HqzQXMFb0ekP/L38d/s/DNAOWBPw
YyAmMCCwJvBJkGlQXlBfMCU4JvhI8OsQ55DSkPuhOqHC0J4wybDosOaw+XDX8LLw0QjjiHUR1yIVIrmR
XVHYqLCopqi5lW4r96yciLaILoweXqW9KnvVldUKq1NWn46RjGHGnIhFx4bHHol9z/RnNjDn4rziauNm
WS6svaxnbEd2OXuaY8cp40zG28WXxU8l2CXsTphOdEisSJzhunCruS+SPJPqkuaT/ZMPJX9KCU9pS8Wl
xqae5Mnwknm9acpp2WmD6frphemja2zW7Fkzy/fhN2VAGasyugRU0c9Uv1BHuEU4lmmfWZP5Jiss60S2
dDYvuz9HL2d7zmSue+63a1FrWWt78lTzNuWNrXNaV78eWh+3vmeD+oaCDRMbPTYe3kTYlLzpp3yT/LL8
V5vDN3cXKBVsLBjf4rGlpVCikF84stV2a9021DbutoHt5turtn8sYhddLTYprih+X8IqufqN6TeV33za
Eb9joNSydP9OzE7ezuFdDrsOl0mX5ZaN7/bb3VFOLy8qf7UnZs+VimUVdXsJe4V7Ryt9K7uqNKp2Vr2v
Tqy+XeNc01arWLu9dn4fe9/Qfsf9rXVKdcV17w5wD9yp96jvaNBqqDiIOZh58EljWGPft4xvm5sUmoqb
PhziHRo9HHS4t9mqufmI4pHSFrhF2DJ9NProje9cv+tqNWytb6O1FR8Dx4THnn4f+/3wcZ/jPScYJ1p/
0Pyhtp3SXtQBdeR0zHYmdo52RXYNnvQ+2dNt293+o9GPh06pnqo5LXu69AzhTMGZT2dzz86dSz83cz7h
/HhPTM/9CxEXbvUG9g5c9Ll4+ZL7pQt9Tn1nL9tdPnXF5srJq4yrndcsr3X0W/S3/2TxU/uA5UDHdavr
XTesb3QPLh88M+QwdP6m681Lt7xuXbu94vbgcOjwnZHokdE77DtTd1PuvriXeW/h/sYH6AdFD6UeVjxS
fNTws+7PbaOWo6fHXMf6Hwc/vj/OGn/2S8Yv7ycKnpCfVEyqTDZPmU2dmnafvvF05dOJZ+nPFmYKf5X+
tfa5zvMffnP8rX82YnbiBf/Fp99LXsq/PPRq2aueuYC5R69TXy/MF72Rf3P4LeNt37vwd5MLWe+x7ys/
6H7o/ujz8cGn1E+f/gUDmPP8usTo0wAAAAlwSFlzAAAuIgAALiIBquLdkgAAEVpJREFUeF7tXQl0VNd5
Thq3Tk7tc+qmiZMm7YmdJj1OT3Gd0kTMG3mJnZQEJzaSjXETx0lqNwt2jWscQGixBAJLSMhgA8YYbIyQ
hHYJI4lFGMwioQWxyewgMdoXtKFd4u/337lPjDRv9pk3g+A75zsMWv577/fd+9/l3Rl9johu0Y/U/OIt
6sfrLwIYT2de+SJ4F/j34LfB+8Ap4L9J8uvvgfy9b4DfBO8EPy9DBBwC3gCI93fgDHAuuA7cDVaDzWAX
OAAOgcNgP9gN8vc+A4vB9eBr4M/Be8GAMiPgDIBAXwVDwbXgEbAPJC+RDToGvgfOBr8mi/UbAsIACMFp
ZRaYC7aBWuL5gh3gdvBZ8C5ZHV3hVwPQaM7hS0ETqCWQnqwDE8Apsnq6wC8GoJEPgFtAzt9aYviTPJ9k
gkGyuj6FrgagUd8CeVIcBLUaH0gcATeD35XV9wl0MQCN4OXjn8EroFZjA5m8qooE/1o2x6vwuQGouAEs
A7UadyPxOPgj2SyvwacGoMILwRsh3ThLTksx4BdkEz2GTwxABb8C8pJSqxGTgTvAb8jmegSvG4CK/QvI
O1Wtik8mXgSnyma7Da8agAo9Auq5kfI3+Shkhmy+W/CaAajI42CvrNjNRJ7jZksZXIZXDEAFWPxA3FTp
xVHQLRM8NgAFPwTejD1/InkH/biUxWl4ZAAK5LP3mynnO+JV0KWJ2W0DUNCXwVOy4Fu8zhrQ6SWqJwbk
WxQa2Mxop6fSWyk0rYlCUhspZEs9zdxSJ8iv+WuhW5vpqYw27d93nXvB26RUduGWAQg+36KwwCULv7VF
iDx3Wx1tPNxCBy92UU17P7VdHaLWniE619JLu8900Nv7m+jFLBgCM9gs/l3NmCqlqU+nt+D/msYtk3LZ
hcsGIPB/gPaPF7jyKrW+rwNZnJCUBoraUU9H63po9No1NM8++odGac/ZDno5r45C2QitESGF59gv5dVT
clUHzc5gEyb8XOaVa6DDsyMU67wBCHg7WCULsEkezi9/jEptbfKLCdzrn0s30b5znWiS6xgeuUaby1so
NKVubDSwGZzCOG3NzTdRQXW7+NnM4+b2atUDPAPeIeXTBEK4ZMA8i+Ca5Ir+LrOOOvtHKGkfcit6kp4m
sBh/zDGRqaMfzfEMh5CuZiXXUOgWE72Ua6L1Jc10qqmXRkbNo4nT2PMw2sHcESvl0wTCOGcAAv0DyFtv
rULGyAKsO9SMUERD6EnRO+t1M4F76++zTNTUNSjK9wYutvVhzujTTGGrMG/wqNCqiwX5IsA/SxmtgDBO
G7DBIqhN8oR3suEqQpnRh7watcOcU31pAvfCWUgZ1Y3Xy/YlCk+Z28rlqrTTvkwpoxUQyrEBCPCvoONz
fVTg1xkm6hkYQajr4Mktdpd5uecrE9jg5IpWWaJvwRN1SHKtaA/PCfMLmyiq2DxPaNUN5KMKg5RzHBDO
KQNSLYLZJFfgVSz3tMBDeM0BrMNlr9H6fXfJ8V7AErK7f1iW5hsMjYxSSnkjPbnxLP1vbq2YE04399KV
vmGak9/kqF0FUs5xQFj7BuAXvwM6ddDGOfiNnQ0IYxvbTrYjVWDiwkrFW6OB83DaEd/3/obOfiq71Ekt
3YOkzgg8NUTxPOdgLpiV1TE6K7vzASnrGBDCoQF8b0cz6ESyqDG77BvAOI2VxJycy7bX2q4QJoYgDVxo
7ZPR9QVv4OzNb7OyOll8mpnWTNPXnlwnZR0DQtg2AAHuAPnCkmbwieQREFZQjzCOwfPChlJs/3mt7cFo
YAPn5NTRsFwa6on3kII05zUIjt4uXv9icx099u5pCn7rKBkSynoMC1K/LuUVQBi7BswcF9gBWYzfZ5vE
RsZZnG/powjsVsXc4IYR/DtLix2POm+C9wGrPjWfK1nWl3v6MxA+FB1xxgeX6OF3TpKSdASsIiMMMK48
TkpM4RwprwDC2TUgTw3uFFEZXgo2dA4glPNgu8pruyms0HxAJnaWThrBP7v2oHnfoQd48xWBelqmHe7t
Is2kNNJ/rj9HD648RsoKC+FVwgBj/MGDUl4BhNQ2AIH/FuTLq1aNtkfuFYWfXUEo18FGHKvrofg9DfRs
mknEcjQq2ABejeiFyEKTWXyUbU4z7fSLj0z06NpTELnKLLyl6BOZVDVgDM+8R8ps14AQy4Y6S1fmAXvg
npZ/oo0iiuro2VSYkdIgVhocX0zc0hQ2YDWWt3phIdrGp5+hW1vpZxsv0SOcZrR6uy1iFAQvLvqDlNmu
Ae9aCus0IQzn8/LL3QjnHbAZpZe6RE9fsL2O/jvTJFIdlzMz2URRhZflT/oer+fX0E/ePUXBttKMI3Ia
enNfhpRZ2wAI+XnQ4amnLXLamPdxHQ1i4+IL8AqqHvMMp6vdZ65Q8en2sXW5r/HbjZVYzVRoi+sMYZwx
saxWWbj1Swhn04B/BPkQSVNgu+TUAHKefB/LzMkE3s3PXgfxsbLRFNd5XlMWZT6AkDYN+JmVsE5QLEPz
WujXGY0iZ3N60GOHqheuDgzT4++U80SqJarz5DQUXfAcQlobACE5/fAb4jRFtkdOPatLWqmrf4RSKlvo
1fzL9MSGM7TuQJ04R7nR0dDRSw8mlGqL6gpXniDjkp2xyoKULyCslQH81MutCZgNWLz7+qaI83Jz9yAm
0A5q6/HeGb2/cPxyBxnivWEAT8T7c4Mjc+5EWCsD/gbkt4JqimyP6rGA+sRosqHgWD0Zlh/WFtUVsgHL
S44aI3O/hrBWBvCboN273cwTMJaHvEKZjEgsOkNKogcrIJViJVTeaIzefi/CWhnA7zJvGiesC+TVT85x
8wPryYYXNpl3upqiukQYsKKyR1my63sIa2UAv3WU3xelKbAj8k71lXz/nE76Em09A/Tjt5B+PF0BqUw6
MogN2RSEtjKAHz+6twdg8k6Yz4NOuXceFKgorm7yTv5XmXRkVIk78H2EtjLgfpBv+moL7AR5Mv5NRp1X
byf4GzH5n3kn/6vkkbS8dCpCWxnAnzrikQFMPiRbWFAnbkXc6OAN2BNreAPmjfwvyQbEH9I0gD/yxfM3
W/BxRFqTuBrYOzj+lsSNht0nG72bfphJVddgwL8jvJUBHk3C4yhNeCXfRJfaPL+p5i+8ln4Cq59KbSHd
ZVLloLJs7/0Ib2UAL0NbxgnpCWEC75Bnp5rog7IW6ujz7dURb+NsYxdvmswpQ0tItyiWod1KTJHmMpQ3
YvxhR9qCukiekGenN4tHjU9+VENPbzpLcbtq6GS9954X+BLLtp/y7uTLNG/EmozRBd9GEVYG8Gf37LEU
0RNy7/+o8gqdae6jQxc76eCFTqqo7aTGzsBPSRdbeuihRG/3fpANiC85qkTkaB5F8Adr8CeaaArqKsUj
yiJ9by14C2/keXnpqXIV5pTYPblB8zZ9BcVYGcDH0f9nKaJH5I1ZSgMduNCF8DcOjtS0k+L13C/JBize
EWeYn3wbihpvgHwgw+/71RbUDfIo+FNuvdWl3UAFn+a+KM59vLzyUWl+IPMbFHVd97EXZgPuAb3yKSfq
ZSUeBbFFNSgi8PHRwRrzut8Xvd/Ma8FR+XYfSf4FyJ+PoymqM1TvRIakNtP098/TQ5h4psWXUnzBaRQT
uDhZ1yknXi/uei0JHZTlpbVBr6z7IoqzNkAlRHR9Ira4E/lEcv31O5Hq9Q2Qe9bCrJPU3T+EYgILPajT
r96v8F3qYSL/G5bszuKOjiLHeP2FBETkj5G0FlmDapp5amsrzfiwhh5ZPeFOpCXxNSWxnGauKaed2OI7
8eZF3RCejXqjbj5MPWYDInJfZo1RpF0D+EOX7L4nbOzqdWqTSDN8J3Kst2sVbkF+sMGj4fmNlZR2uFas
uYflg3t/mLJy11lf530Q6/+3qoaw+vkOa4xibRvAgMj8oaYTRLe+eu3UnUgt8mhgIxLKKBhLvsdXltDc
zRV0qUXfXfKHBy7pID4ongUfKpfyOmXAf00U3ubVa0+IOCzAM+vKqOxCG6qhHzbziodvOvhq0rUk0k9Q
WPpLUl4BVMG2AbOyu+4CW1j8Jx1dvXaHLDx6/09XHabU0loaHNb32cG7n1zQT3w+fkgs75r6Pwl3S3kF
UA3bBjB+vvH8CnH1WqYLzeCukEcNVhnc459YXSaGf0evvk/O2OjovGqZdnQQn/l2NQVF5G2Qso4B1bFv
gCEs/X6kmhHNoCp5NHBDBPm1ShYbTKwQPZ1723T09tfTT4hnrL2D+h9N17Zdpd9uNI88UUet9viCGAFB
r29WpKxjQJXsG8AwLtv3sbhOpxUYjZi+5hg9s+E4zVpfRT9ZeZh+nFRKP11ZRqFry+mFD6soKreakg/V
iPzuz/V/TqVJ1E2s83UVX9yE2294baPV3y5AtRwboIRnT0OgUavAko++fZR++cFxKj7VQgPDI9Q3OCKE
HhgKjLOfc03d9ErqcX1TjiVhADLJdCnnOKB6jg1gGOP2pwsntQpAbxLzw/JSCsuqprNocCCgoaOPEgrP
0MOJJeZjZT17vUo++Vz6yU4poxVQTScNWJT5XfSefvNmQqMgJhuBhirxJTQ/4wRVXGqnUT9c0Drf3E3L
IfyPON2Ina0fer0gVoxJVcNBr31g9QZtFaiucwYwjEt2xdqcCywpRgRWOph0f7m+QuT/y+1XfbrD5Ztr
24/V05wtR8Wmzr/CS7JWscWrpHyaQNWdN0AJS7vDmFh2zmYqmkiZmnjF8WBCibhbuWbPeTqMyZiXnp4Y
wgdnfF2cl7Gc3x9Db+ccr/sEa4u87l9R3hAcnvllKZ8m0BTnDWAo4VmPGldyIXZSkRalGdwzeWTwaonP
gRZlV9O6vRcoq8JEu7E0LTnXSidMHSKNHK29Qofwf76Xw99/Dz8XiRXV7z48QjPeLkOqg+gwN2BEtyRv
WCNyQqRsNuGyAQxlya44p1KRPaqGQDxhCnrvGFlYlRZf558TcwxP+IEmuCXFI8eda6RcduGWAcaFaX9p
jD/0qdOp6GYia7K8pCp4UfqXpFx24ZYBDGVB6jeNKypMt0ywoPm8p9UYkW3zI8omwm0DGIbXN//AuKKy
VxSsVaGbiWYNhrBpdenPnHhkAAMTzUwUPnxTm6C2PWrbc1IWp+GxAQxDePavxlXkpiLazO2OKfqjlMMl
eMUABruPCt1kI4HbiuVm9PY/SRlchtcMYBjCMkJQMcwJN8HEzB0tqWrIGF3wvGy+W/CqAQwlLH2aknDY
xGthzYpPBnIHW1HRYozMeUw222143QDGtD8n3yP2CcKESZaSeAOaUFpuDM+8TzbXI/jEAIZxYepfGaIL
48yVngQpiVMO2qHEFq81Lkr32p819JkBKgyLMmeYD/Bu4NHAdU8sr1Ui85+SzfIafG4Aw7go4y5jbPEy
8TzhRpobxMitGjYu3fOOMWzrV2VzvApdDFDxw3mbpyhL92aL09RATkuibhitb35agIn2h7L6PoGuBqgw
hOc8Zow7UCQayyMiIPYOnONlmow7sEeJzPPoL+Q5C78YoAI76KBpMTtXK4nlLcZV6HVqz9MUyEfkMpkr
KnuMSz/ZpETkPCyrpwv8aoCKH8zdcPe0yG0vYum6X8wTLIivRoZczQgmVQ2izBIluvBVZeHWb8nq6IqA
MMASWDX9k+GN7X8wxO5JU5aXnjeLxoKxIVI4YYzKCQKrX7cUWpiJf/n7CWW1yrJ9WcaYwpeU8Cynj419
hYAzwBJB8zbdHhyVd78xpuA5ZfHOWEzgWeixFVgSNiBldGG0DICj4uE7PyEzvx4Q6YQ/ECm+5Cgm0jxl
8Y5lyhsfPw9zpyrzU3zyp8ndRUAbwFDrZViQdlvQ/NQ7kKPvNkYX3GuIKbpPWfrJFP7IFyXu4FQYM1V5
c//3lWV7p/A70JWobfcq4dlfN4Zn3WmYn3y7GseSgYCxulhW7Bb1p+YXb1Ev0uf+H9A3E1Z4VJUaAAAA
AElFTkSuQmCC
</value>
</data>
</root>

View File

@@ -1,59 +1,107 @@
using System; using System.Drawing;
using System.Drawing;
using System.Windows.Forms; using System.Windows.Forms;
using CefSharp; using CefSharp;
using CefSharp.WinForms; using CefSharp.WinForms;
using TweetDuck.Core.Controls; using TweetDuck.Core.Controls;
using TweetDuck.Core.Handling; using TweetDuck.Core.Handling;
using TweetDuck.Core.Handling.General; using TweetDuck.Core.Handling.General;
using TweetDuck.Core.Other.Analytics;
using TweetDuck.Core.Utils; using TweetDuck.Core.Utils;
using System.Text.RegularExpressions;
using TweetDuck.Data;
using TweetDuck.Resources;
namespace TweetDuck.Core.Other{ namespace TweetDuck.Core.Other{
sealed partial class FormGuide : Form{ sealed partial class FormGuide : Form, FormManager.IAppDialog{
private const string GuideUrl = "https://tweetduck.chylex.com/guide/v2/"; private const string GuideUrl = "https://tweetduck.chylex.com/guide/v2/";
private const string GuidePathRegex = @"^guide(?:/v\d+)?(?:/(#.*))?";
private readonly ChromiumWebBrowser browser; private static readonly ResourceLink DummyPage = new ResourceLink("http://td/dummy", ResourceHandler.FromString(""));
public FormGuide(){ public static bool CheckGuideUrl(string url, out string hash){
InitializeComponent(); if (!url.Contains("//tweetduck.chylex.com/guide")){
hash = null;
return false;
}
Text = Program.BrandName+" Guide"; string path = url.Substring(url.IndexOf("/guide")+1);
Match match = Regex.Match(path, GuidePathRegex);
if (match.Success){
hash = match.Groups[1].Value;
return true;
}
else{
hash = null;
return false;
}
}
public static void Show(string hash = null){
string url = GuideUrl+(hash ?? string.Empty);
FormGuide guide = FormManager.TryFind<FormGuide>();
if (guide == null){
FormBrowser owner = FormManager.TryFind<FormBrowser>(); FormBrowser owner = FormManager.TryFind<FormBrowser>();
if (owner != null){ if (owner != null){
owner.AnalyticsFile.OpenGuide.Trigger();
new FormGuide(url, owner).Show(owner);
}
}
else{
guide.Reload(url);
guide.Activate();
}
}
private readonly ChromiumWebBrowser browser;
private string nextUrl;
private FormGuide(string url, FormBrowser owner){
InitializeComponent();
Text = Program.BrandName+" Guide";
Size = new Size(owner.Size.Width*3/4, owner.Size.Height*3/4); Size = new Size(owner.Size.Width*3/4, owner.Size.Height*3/4);
VisibleChanged += (sender, args) => this.MoveToCenter(owner); VisibleChanged += (sender, args) => this.MoveToCenter(owner);
owner.TriggerAnalyticsEvent(AnalyticsFile.Event.OpenGuide); this.browser = new ChromiumWebBrowser(url){
} MenuHandler = new ContextMenuGuide(owner),
this.browser = new ChromiumWebBrowser(GuideUrl){
MenuHandler = new ContextMenuGuide(),
JsDialogHandler = new JavaScriptDialogHandler(), JsDialogHandler = new JavaScriptDialogHandler(),
LifeSpanHandler = new LifeSpanHandler(), LifeSpanHandler = new LifeSpanHandler(),
RequestHandler = new RequestHandlerBrowser() RequestHandler = new RequestHandlerBase(true)
}; };
browser.LoadingStateChanged += browser_LoadingStateChanged; browser.LoadingStateChanged += browser_LoadingStateChanged;
browser.FrameLoadStart += browser_FrameLoadStart; browser.FrameLoadEnd += browser_FrameLoadEnd;
browser.BrowserSettings.BackgroundColor = (uint)BackColor.ToArgb(); browser.BrowserSettings.BackgroundColor = (uint)BackColor.ToArgb();
browser.Dock = DockStyle.None; browser.Dock = DockStyle.None;
browser.Location = ControlExtensions.InvisibleLocation; browser.Location = ControlExtensions.InvisibleLocation;
browser.SetupResourceHandler(DummyPage);
browser.SetupZoomEvents();
Controls.Add(browser); Controls.Add(browser);
Disposed += (sender, args) => { Disposed += (sender, args) => {
Program.UserConfig.ZoomLevelChanged -= Config_ZoomLevelChanged;
browser.Dispose(); browser.Dispose();
}; };
}
Program.UserConfig.ZoomLevelChanged += Config_ZoomLevelChanged; private void Reload(string url){
nextUrl = url;
browser.LoadingStateChanged += browser_LoadingStateChanged;
browser.Dock = DockStyle.None;
browser.Location = ControlExtensions.InvisibleLocation;
browser.Load(DummyPage.Url);
} }
private void browser_LoadingStateChanged(object sender, LoadingStateChangedEventArgs e){ private void browser_LoadingStateChanged(object sender, LoadingStateChangedEventArgs e){
if (!e.IsLoading){ if (!e.IsLoading){
if (browser.Address == DummyPage.Url){
browser.Load(nextUrl);
}
else{
this.InvokeAsyncSafe(() => { this.InvokeAsyncSafe(() => {
browser.Location = Point.Empty; browser.Location = Point.Empty;
browser.Dock = DockStyle.Fill; browser.Dock = DockStyle.Fill;
@@ -62,13 +110,10 @@ namespace TweetDuck.Core.Other{
browser.LoadingStateChanged -= browser_LoadingStateChanged; browser.LoadingStateChanged -= browser_LoadingStateChanged;
} }
} }
private void browser_FrameLoadStart(object sender, FrameLoadStartEventArgs e){
BrowserUtils.SetZoomLevel(browser.GetBrowser(), Program.UserConfig.ZoomLevel);
} }
private void Config_ZoomLevelChanged(object sender, EventArgs e){ private void browser_FrameLoadEnd(object sender, FrameLoadEndEventArgs e){
BrowserUtils.SetZoomLevel(browser.GetBrowser(), Program.UserConfig.ZoomLevel); ScriptLoader.ExecuteScript(e.Frame, "Array.prototype.forEach.call(document.getElementsByTagName('A'), ele => ele.addEventListener('click', e => { e.preventDefault(); window.open(ele.getAttribute('href')); }))", "gen:links");
} }
} }
} }

View File

@@ -133,7 +133,7 @@ namespace TweetDuck.Core.Other{
Font = SystemFonts.MessageBoxFont, Font = SystemFonts.MessageBoxFont,
Location = new Point(0, 12), Location = new Point(0, 12),
Size = new Size(BrowserUtils.Scale(88, dpiScale), BrowserUtils.Scale(26, dpiScale)), Size = new Size(BrowserUtils.Scale(88, dpiScale), BrowserUtils.Scale(26, dpiScale)),
TabIndex = buttonCount, TabIndex = 256-buttonCount,
Text = title, Text = title,
UseVisualStyleBackColor = true UseVisualStyleBackColor = true
}; };

View File

@@ -23,20 +23,23 @@
/// the contents of this method with the code editor. /// the contents of this method with the code editor.
/// </summary> /// </summary>
private void InitializeComponent() { private void InitializeComponent() {
this.components = new System.ComponentModel.Container();
this.btnClose = new System.Windows.Forms.Button(); this.btnClose = new System.Windows.Forms.Button();
this.btnReload = new System.Windows.Forms.Button(); this.btnReload = new System.Windows.Forms.Button();
this.btnOpenFolder = new System.Windows.Forms.Button(); this.btnOpenFolder = new System.Windows.Forms.Button();
this.flowLayoutPlugins = new TweetDuck.Plugins.Controls.PluginListFlowLayout(); this.flowLayoutPlugins = new TweetDuck.Plugins.Controls.PluginListFlowLayout();
this.timerLayout = new System.Windows.Forms.Timer(this.components);
this.SuspendLayout(); this.SuspendLayout();
// //
// btnClose // btnClose
// //
this.btnClose.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right))); this.btnClose.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right)));
this.btnClose.AutoSize = true; this.btnClose.AutoSize = true;
this.btnClose.Location = new System.Drawing.Point(643, 439); this.btnClose.Font = new System.Drawing.Font("Segoe UI", 9F, System.Drawing.FontStyle.Regular);
this.btnClose.Location = new System.Drawing.Point(642, 433);
this.btnClose.Name = "btnClose"; this.btnClose.Name = "btnClose";
this.btnClose.Padding = new System.Windows.Forms.Padding(3, 0, 3, 0); this.btnClose.Padding = new System.Windows.Forms.Padding(2, 0, 2, 0);
this.btnClose.Size = new System.Drawing.Size(49, 23); this.btnClose.Size = new System.Drawing.Size(50, 25);
this.btnClose.TabIndex = 1; this.btnClose.TabIndex = 1;
this.btnClose.Text = "Close"; this.btnClose.Text = "Close";
this.btnClose.UseVisualStyleBackColor = true; this.btnClose.UseVisualStyleBackColor = true;
@@ -46,10 +49,11 @@
// //
this.btnReload.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left))); this.btnReload.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left)));
this.btnReload.AutoSize = true; this.btnReload.AutoSize = true;
this.btnReload.Location = new System.Drawing.Point(131, 439); this.btnReload.Font = new System.Drawing.Font("Segoe UI", 9F, System.Drawing.FontStyle.Regular);
this.btnReload.Location = new System.Drawing.Point(141, 433);
this.btnReload.Name = "btnReload"; this.btnReload.Name = "btnReload";
this.btnReload.Padding = new System.Windows.Forms.Padding(3, 0, 3, 0); this.btnReload.Padding = new System.Windows.Forms.Padding(2, 0, 2, 0);
this.btnReload.Size = new System.Drawing.Size(71, 23); this.btnReload.Size = new System.Drawing.Size(74, 25);
this.btnReload.TabIndex = 2; this.btnReload.TabIndex = 2;
this.btnReload.Text = "Reload All"; this.btnReload.Text = "Reload All";
this.btnReload.UseVisualStyleBackColor = true; this.btnReload.UseVisualStyleBackColor = true;
@@ -59,10 +63,11 @@
// //
this.btnOpenFolder.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left))); this.btnOpenFolder.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left)));
this.btnOpenFolder.AutoSize = true; this.btnOpenFolder.AutoSize = true;
this.btnOpenFolder.Location = new System.Drawing.Point(12, 439); this.btnOpenFolder.Font = new System.Drawing.Font("Segoe UI", 9F, System.Drawing.FontStyle.Regular);
this.btnOpenFolder.Location = new System.Drawing.Point(12, 433);
this.btnOpenFolder.Name = "btnOpenFolder"; this.btnOpenFolder.Name = "btnOpenFolder";
this.btnOpenFolder.Padding = new System.Windows.Forms.Padding(3, 0, 3, 0); this.btnOpenFolder.Padding = new System.Windows.Forms.Padding(2, 0, 2, 0);
this.btnOpenFolder.Size = new System.Drawing.Size(113, 23); this.btnOpenFolder.Size = new System.Drawing.Size(123, 25);
this.btnOpenFolder.TabIndex = 3; this.btnOpenFolder.TabIndex = 3;
this.btnOpenFolder.Text = "Open Plugin Folder"; this.btnOpenFolder.Text = "Open Plugin Folder";
this.btnOpenFolder.UseVisualStyleBackColor = true; this.btnOpenFolder.UseVisualStyleBackColor = true;
@@ -77,22 +82,29 @@
this.flowLayoutPlugins.FlowDirection = System.Windows.Forms.FlowDirection.TopDown; this.flowLayoutPlugins.FlowDirection = System.Windows.Forms.FlowDirection.TopDown;
this.flowLayoutPlugins.Location = new System.Drawing.Point(12, 12); this.flowLayoutPlugins.Location = new System.Drawing.Point(12, 12);
this.flowLayoutPlugins.Name = "flowLayoutPlugins"; this.flowLayoutPlugins.Name = "flowLayoutPlugins";
this.flowLayoutPlugins.Size = new System.Drawing.Size(680, 421); this.flowLayoutPlugins.Size = new System.Drawing.Size(680, 415);
this.flowLayoutPlugins.TabIndex = 0; this.flowLayoutPlugins.TabIndex = 0;
this.flowLayoutPlugins.WrapContents = false; this.flowLayoutPlugins.WrapContents = false;
this.flowLayoutPlugins.Resize += new System.EventHandler(this.flowLayoutPlugins_Resize); this.flowLayoutPlugins.Resize += new System.EventHandler(this.flowLayoutPlugins_Resize);
// //
// timerLayout
//
this.timerLayout.Interval = 99;
this.timerLayout.Tick += new System.EventHandler(this.timerLayout_Tick);
//
// FormPlugins // FormPlugins
// //
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
this.ClientSize = new System.Drawing.Size(704, 474); this.ClientSize = new System.Drawing.Size(704, 470);
this.Controls.Add(this.flowLayoutPlugins); this.Controls.Add(this.flowLayoutPlugins);
this.Controls.Add(this.btnOpenFolder); this.Controls.Add(this.btnOpenFolder);
this.Controls.Add(this.btnReload); this.Controls.Add(this.btnReload);
this.Controls.Add(this.btnClose); this.Controls.Add(this.btnClose);
this.Icon = global::TweetDuck.Properties.Resources.icon; this.Icon = global::TweetDuck.Properties.Resources.icon;
this.MinimumSize = new System.Drawing.Size(480, 320); this.MaximizeBox = false;
this.MinimizeBox = false;
this.MinimumSize = new System.Drawing.Size(640, 360);
this.Name = "FormPlugins"; this.Name = "FormPlugins";
this.StartPosition = System.Windows.Forms.FormStartPosition.CenterParent; this.StartPosition = System.Windows.Forms.FormStartPosition.CenterParent;
this.ResumeLayout(false); this.ResumeLayout(false);
@@ -106,5 +118,6 @@
private System.Windows.Forms.Button btnReload; private System.Windows.Forms.Button btnReload;
private System.Windows.Forms.Button btnOpenFolder; private System.Windows.Forms.Button btnOpenFolder;
private Plugins.Controls.PluginListFlowLayout flowLayoutPlugins; private Plugins.Controls.PluginListFlowLayout flowLayoutPlugins;
private System.Windows.Forms.Timer timerLayout;
} }
} }

View File

@@ -3,11 +3,14 @@ using System.Diagnostics;
using System.Drawing; using System.Drawing;
using System.Linq; using System.Linq;
using System.Windows.Forms; using System.Windows.Forms;
using TweetDuck.Configuration;
using TweetDuck.Plugins; using TweetDuck.Plugins;
using TweetDuck.Plugins.Controls; using TweetDuck.Plugins.Controls;
namespace TweetDuck.Core.Other{ namespace TweetDuck.Core.Other{
sealed partial class FormPlugins : Form{ sealed partial class FormPlugins : Form, FormManager.IAppDialog{
private static UserConfig Config => Program.Config.User;
private readonly PluginManager pluginManager; private readonly PluginManager pluginManager;
public FormPlugins(){ public FormPlugins(){
@@ -19,14 +22,22 @@ namespace TweetDuck.Core.Other{
public FormPlugins(PluginManager pluginManager) : this(){ public FormPlugins(PluginManager pluginManager) : this(){
this.pluginManager = pluginManager; this.pluginManager = pluginManager;
if (!Config.PluginsWindowSize.IsEmpty){
Size targetSize = Config.PluginsWindowSize;
Size = new Size(Math.Max(MinimumSize.Width, targetSize.Width), Math.Max(MinimumSize.Height, targetSize.Height));
}
Shown += (sender, args) => { Shown += (sender, args) => {
Program.UserConfig.PluginsWindow.Restore(this, false);
ReloadPluginList(); ReloadPluginList();
}; };
FormClosed += (sender, args) => { FormClosed += (sender, args) => {
Program.UserConfig.PluginsWindow.Save(this); Config.PluginsWindowSize = Size;
Program.UserConfig.Save(); Config.Save();
};
ResizeEnd += (sender, args) => {
timerLayout.Start();
}; };
} }
@@ -50,18 +61,26 @@ namespace TweetDuck.Core.Other{
flowLayoutPlugins.ResumeLayout(true); flowLayoutPlugins.ResumeLayout(true);
// sorry, I guess... timerLayout_Tick(null, EventArgs.Empty);
Padding = new Padding(Padding.Left, Padding.Top, Padding.Right+1, Padding.Bottom); timerLayout.Start();
Padding = new Padding(Padding.Left, Padding.Top, Padding.Right-1, Padding.Bottom);
} }
private void flowLayoutPlugins_Resize(object sender, EventArgs e){ private void timerLayout_Tick(object sender, EventArgs e){
if (flowLayoutPlugins.Controls.Count == 0){ timerLayout.Stop();
// stupid WinForms scrollbars and panels
Padding = new Padding(Padding.Left, Padding.Top, Padding.Right+1, Padding.Bottom+1);
Padding = new Padding(Padding.Left, Padding.Top, Padding.Right-1, Padding.Bottom-1);
}
public void flowLayoutPlugins_Resize(object sender, EventArgs e){
Control lastPlugin = flowLayoutPlugins.Controls.OfType<PluginControl>().LastOrDefault();
if (lastPlugin == null){
return; return;
} }
Control lastControl = flowLayoutPlugins.Controls[flowLayoutPlugins.Controls.Count-1]; bool showScrollBar = lastPlugin.Location.Y+lastPlugin.Height+1 >= flowLayoutPlugins.Height;
bool showScrollBar = lastControl.Location.Y+lastControl.Height >= flowLayoutPlugins.Height;
int horizontalOffset = showScrollBar ? SystemInformation.VerticalScrollBarWidth : 0; int horizontalOffset = showScrollBar ? SystemInformation.VerticalScrollBarWidth : 0;
flowLayoutPlugins.AutoScroll = showScrollBar; flowLayoutPlugins.AutoScroll = showScrollBar;
@@ -71,12 +90,12 @@ namespace TweetDuck.Core.Other{
control.Width = flowLayoutPlugins.Width-control.Margin.Horizontal-horizontalOffset; control.Width = flowLayoutPlugins.Width-control.Margin.Horizontal-horizontalOffset;
} }
lastControl.Visible = !showScrollBar; flowLayoutPlugins.Controls[flowLayoutPlugins.Controls.Count-1].Visible = !showScrollBar;
flowLayoutPlugins.Focus(); flowLayoutPlugins.Focus();
} }
private void btnOpenFolder_Click(object sender, EventArgs e){ 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){ private void btnReload_Click(object sender, EventArgs e){

View File

@@ -33,10 +33,11 @@
// //
this.btnClose.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right))); this.btnClose.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right)));
this.btnClose.AutoSize = true; this.btnClose.AutoSize = true;
this.btnClose.Location = new System.Drawing.Point(449, 447); this.btnClose.Font = new System.Drawing.Font("Segoe UI", 9F);
this.btnClose.Location = new System.Drawing.Point(747, 500);
this.btnClose.Name = "btnClose"; this.btnClose.Name = "btnClose";
this.btnClose.Padding = new System.Windows.Forms.Padding(3, 0, 3, 0); this.btnClose.Padding = new System.Windows.Forms.Padding(2, 0, 2, 0);
this.btnClose.Size = new System.Drawing.Size(49, 23); this.btnClose.Size = new System.Drawing.Size(50, 25);
this.btnClose.TabIndex = 3; this.btnClose.TabIndex = 3;
this.btnClose.Text = "Close"; this.btnClose.Text = "Close";
this.btnClose.UseVisualStyleBackColor = true; this.btnClose.UseVisualStyleBackColor = true;
@@ -52,7 +53,7 @@
this.panelContents.Location = new System.Drawing.Point(135, 12); this.panelContents.Location = new System.Drawing.Point(135, 12);
this.panelContents.Margin = new System.Windows.Forms.Padding(0, 3, 3, 3); this.panelContents.Margin = new System.Windows.Forms.Padding(0, 3, 3, 3);
this.panelContents.Name = "panelContents"; this.panelContents.Name = "panelContents";
this.panelContents.Size = new System.Drawing.Size(363, 429); this.panelContents.Size = new System.Drawing.Size(662, 482);
this.panelContents.TabIndex = 1; this.panelContents.TabIndex = 1;
// //
// panelButtons // panelButtons
@@ -63,17 +64,18 @@
this.panelButtons.Location = new System.Drawing.Point(12, 12); this.panelButtons.Location = new System.Drawing.Point(12, 12);
this.panelButtons.Margin = new System.Windows.Forms.Padding(3, 3, 0, 3); this.panelButtons.Margin = new System.Windows.Forms.Padding(3, 3, 0, 3);
this.panelButtons.Name = "panelButtons"; this.panelButtons.Name = "panelButtons";
this.panelButtons.Size = new System.Drawing.Size(124, 429); this.panelButtons.Size = new System.Drawing.Size(124, 482);
this.panelButtons.TabIndex = 0; this.panelButtons.TabIndex = 0;
// //
// btnManageOptions // btnManageOptions
// //
this.btnManageOptions.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left))); this.btnManageOptions.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left)));
this.btnManageOptions.AutoSize = true; this.btnManageOptions.AutoSize = true;
this.btnManageOptions.Location = new System.Drawing.Point(12, 447); this.btnManageOptions.Font = new System.Drawing.Font("Segoe UI", 9F);
this.btnManageOptions.Location = new System.Drawing.Point(12, 500);
this.btnManageOptions.Name = "btnManageOptions"; this.btnManageOptions.Name = "btnManageOptions";
this.btnManageOptions.Padding = new System.Windows.Forms.Padding(3, 0, 3, 0); this.btnManageOptions.Padding = new System.Windows.Forms.Padding(2, 0, 2, 0);
this.btnManageOptions.Size = new System.Drawing.Size(101, 23); this.btnManageOptions.Size = new System.Drawing.Size(109, 25);
this.btnManageOptions.TabIndex = 4; this.btnManageOptions.TabIndex = 4;
this.btnManageOptions.Text = "Manage Options"; this.btnManageOptions.Text = "Manage Options";
this.btnManageOptions.UseVisualStyleBackColor = true; this.btnManageOptions.UseVisualStyleBackColor = true;
@@ -83,7 +85,7 @@
// //
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
this.ClientSize = new System.Drawing.Size(510, 482); this.ClientSize = new System.Drawing.Size(809, 537);
this.Controls.Add(this.btnManageOptions); this.Controls.Add(this.btnManageOptions);
this.Controls.Add(this.panelContents); this.Controls.Add(this.panelContents);
this.Controls.Add(this.panelButtons); this.Controls.Add(this.panelButtons);

View File

@@ -3,6 +3,7 @@ using System.Collections.Generic;
using System.Drawing; using System.Drawing;
using System.Windows.Forms; using System.Windows.Forms;
using TweetDuck.Core.Controls; using TweetDuck.Core.Controls;
using TweetDuck.Core.Handling.General;
using TweetDuck.Core.Notification.Example; using TweetDuck.Core.Notification.Example;
using TweetDuck.Core.Other.Analytics; using TweetDuck.Core.Other.Analytics;
using TweetDuck.Core.Other.Settings; using TweetDuck.Core.Other.Settings;
@@ -12,17 +13,17 @@ using TweetDuck.Plugins;
using TweetDuck.Updates; using TweetDuck.Updates;
namespace TweetDuck.Core.Other{ namespace TweetDuck.Core.Other{
sealed partial class FormSettings : Form{ sealed partial class FormSettings : Form, FormManager.IAppDialog{
public bool ShouldReloadBrowser { get; private set; }
private readonly FormBrowser browser; private readonly FormBrowser browser;
private readonly PluginManager plugins; private readonly PluginManager plugins;
private readonly int buttonHeight; private readonly int buttonHeight;
private readonly Dictionary<Type, SettingsTab> tabs = new Dictionary<Type, SettingsTab>(4); private readonly Dictionary<Type, SettingsTab> tabs = new Dictionary<Type, SettingsTab>(8);
private SettingsTab currentTab; private SettingsTab currentTab;
public bool ShouldReloadBrowser { get; private set; }
public FormSettings(FormBrowser browser, PluginManager plugins, UpdateHandler updates, AnalyticsManager analytics, Type startTab){ public FormSettings(FormBrowser browser, PluginManager plugins, UpdateHandler updates, AnalyticsManager analytics, Type startTab){
InitializeComponent(); InitializeComponent();
@@ -35,43 +36,67 @@ namespace TweetDuck.Core.Other{
this.buttonHeight = BrowserUtils.Scale(39, this.GetDPIScale()) | 1; this.buttonHeight = BrowserUtils.Scale(39, this.GetDPIScale()) | 1;
AddButton("General", () => new TabSettingsGeneral(updates)); PrepareLoad();
AddButton("System Tray", () => new TabSettingsTray());
AddButton("General", () => new TabSettingsGeneral(this.browser.ReloadColumns, updates));
AddButton("Notifications", () => new TabSettingsNotifications(new FormNotificationExample(this.browser, this.plugins))); AddButton("Notifications", () => new TabSettingsNotifications(new FormNotificationExample(this.browser, this.plugins)));
AddButton("Sounds", () => new TabSettingsSounds()); AddButton("Sounds", () => new TabSettingsSounds(this.browser.PlaySoundNotification));
AddButton("Feedback", () => new TabSettingsFeedback(analytics, AnalyticsReportGenerator.ExternalInfo.From(this.browser), this.plugins)); AddButton("Feedback", () => new TabSettingsFeedback(analytics, AnalyticsReportGenerator.ExternalInfo.From(this.browser), this.plugins));
AddButton("Advanced", () => new TabSettingsAdvanced(this.browser.ReinjectCustomCSS)); AddButton("Advanced", () => new TabSettingsAdvanced(this.browser.ReinjectCustomCSS, this.browser.OpenDevTools));
SelectTab(tabs[startTab ?? typeof(TabSettingsGeneral)]); SelectTab(tabs[startTab ?? typeof(TabSettingsGeneral)]);
} }
private void FormSettings_FormClosing(object sender, FormClosingEventArgs e){ private void PrepareLoad(){
Program.Config.ProgramRestartRequested += Config_ProgramRestartRequested;
}
private void PrepareUnload(){ // TODO refactor this further later
currentTab.Control.OnClosing(); currentTab.Control.OnClosing();
Program.Config.ProgramRestartRequested -= Config_ProgramRestartRequested;
Program.Config.SaveAll();
}
private void Config_ProgramRestartRequested(object sender, EventArgs e){
if (FormMessage.Information("TweetDuck Options", "The application must restart for the option to take place. Do you want to restart now?", FormMessage.Yes, FormMessage.No)){
Program.Restart();
}
}
private void FormSettings_FormClosing(object sender, FormClosingEventArgs e){
PrepareUnload();
foreach(SettingsTab tab in tabs.Values){ foreach(SettingsTab tab in tabs.Values){
if (tab.IsInitialized){ if (tab.IsInitialized){
tab.Control.Dispose(); tab.Control.Dispose();
} }
} }
Program.UserConfig.Save();
browser.ResumeNotification(); browser.ResumeNotification();
} }
private void btnManageOptions_Click(object sender, EventArgs e){ private void btnManageOptions_Click(object sender, EventArgs e){
currentTab.Control.OnClosing(); PrepareUnload();
using(DialogSettingsManage dialog = new DialogSettingsManage(plugins)){ using(DialogSettingsManage dialog = new DialogSettingsManage(plugins)){
FormClosing -= FormSettings_FormClosing; FormClosing -= FormSettings_FormClosing;
if (dialog.ShowDialog() == DialogResult.OK){ if (dialog.ShowDialog() == DialogResult.OK){
if (!dialog.IsRestarting){
browser.ResumeNotification(); browser.ResumeNotification();
ShouldReloadBrowser = dialog.ShouldReloadBrowser; if (dialog.ShouldReloadBrowser){
BrowserProcessHandler.UpdatePrefs();
ShouldReloadBrowser = true;
}
}
Close(); Close();
} }
else{ else{
FormClosing += FormSettings_FormClosing; FormClosing += FormSettings_FormClosing;
PrepareLoad();
} }
} }
} }
@@ -84,6 +109,7 @@ namespace TweetDuck.Core.Other{
FlatButton btn = new FlatButton{ FlatButton btn = new FlatButton{
BackColor = SystemColors.Control, BackColor = SystemColors.Control,
FlatStyle = FlatStyle.Flat, FlatStyle = FlatStyle.Flat,
Font = SystemFonts.MessageBoxFont,
Location = new Point(0, (buttonHeight+1)*(panelButtons.Controls.Count/2)), Location = new Point(0, (buttonHeight+1)*(panelButtons.Controls.Count/2)),
Margin = new Padding(0), Margin = new Padding(0),
Size = new Size(panelButtons.Width, buttonHeight), Size = new Size(panelButtons.Width, buttonHeight),
@@ -131,6 +157,10 @@ namespace TweetDuck.Core.Other{
} }
} }
if (tab.Control.Height < panelContents.Height-2){
tab.Control.Height = panelContents.Height-2; // fixes off-by-pixel error on high DPI
}
tab.Control.OnReady(); tab.Control.OnReady();
} }
@@ -150,6 +180,10 @@ namespace TweetDuck.Core.Other{
} }
private void control_MouseLeave(object sender, EventArgs e){ private void control_MouseLeave(object sender, EventArgs e){
if (sender is ComboBox cb && cb.DroppedDown){
return; // prevents comboboxes from closing when MouseLeave event triggers during opening animation
}
panelContents.Focus(); panelContents.Focus();
} }

View File

@@ -1,27 +0,0 @@
using System.Collections.Generic;
using System.Diagnostics;
using CefSharp;
using TweetDuck.Core.Utils;
namespace TweetDuck.Core.Other.Management{
static class BrowserProcesses{
private static readonly Dictionary<int, int> PIDs = new Dictionary<int, int>();
public static void Link(int identifier, int pid){
PIDs[identifier] = pid;
}
public static void Forget(int identifier){
PIDs.Remove(identifier);
}
public static Process FindProcess(IBrowser browser){
if (PIDs.TryGetValue(browser.Identifier, out int pid) && WindowsUtils.IsChildProcess(pid)){ // child process is checked in two places for safety
return Process.GetProcessById(pid);
}
else{
return null;
}
}
}
}

View File

@@ -1,93 +0,0 @@
using System;
using System.Diagnostics;
using System.Timers;
using CefSharp;
using CefSharp.WinForms;
using TweetDuck.Core.Controls;
using Timer = System.Timers.Timer;
namespace TweetDuck.Core.Other.Management{
sealed class MemoryUsageTracker : IDisposable{
private const int IntervalMemoryCheck = 60000*30; // 30 minutes
private const int IntervalCleanupAttempt = 60000*5; // 5 minutes
private readonly string script;
private readonly Timer timer;
private FormBrowser owner;
private IBrowser browser;
private long threshold;
private bool needsCleanup;
public MemoryUsageTracker(string cleanupFunctionName){
this.script = $"window.{cleanupFunctionName} && window.{cleanupFunctionName}()";
this.timer = new Timer{ Interval = IntervalMemoryCheck };
this.timer.Elapsed += timer_Elapsed;
}
public void Start(ChromiumWebBrowser control, int thresholdMB){
Stop();
this.owner = (FormBrowser)control.Parent; // TODO ugly
this.browser = control.GetBrowser();
this.threshold = thresholdMB*1024L*1024L;
this.timer.SynchronizingObject = owner;
this.timer.Start();
}
public void Stop(){
timer.Stop();
timer.SynchronizingObject = null;
owner = null;
browser = null;
SetNeedsCleanup(false);
}
public void Dispose(){
timer.SynchronizingObject = null;
timer.Dispose();
owner = null;
browser = null;
}
private void SetNeedsCleanup(bool value){
if (needsCleanup != value){
needsCleanup = value;
timer.Interval = value ? IntervalCleanupAttempt : IntervalMemoryCheck; // restarts timer
}
}
private void timer_Elapsed(object sender, ElapsedEventArgs e){
if (owner == null || browser == null){
return;
}
if (needsCleanup){
if (!owner.ContainsFocus){
using(IFrame frame = browser.MainFrame){
frame.EvaluateScriptAsync(script).ContinueWith(task => {
JavascriptResponse response = task.Result;
if (response.Success && (response.Result as bool? ?? false)){
SetNeedsCleanup(false);
owner.InvokeAsyncSafe(() => owner.TriggerAnalyticsEvent(Analytics.AnalyticsFile.Event.GCReload));
}
});
}
}
}
else{
try{
using(Process process = BrowserProcesses.FindProcess(browser)){
if (process?.PrivateMemorySize64 > threshold){
SetNeedsCleanup(true);
}
}
}catch{
// ignore I guess?
}
}
}
}
}

View File

@@ -1,181 +0,0 @@
using System;
using System.Diagnostics;
using System.IO;
using System.Windows.Forms;
using TweetDuck.Core.Controls;
using TweetDuck.Core.Utils;
using TweetLib.Communication;
namespace TweetDuck.Core.Other.Management{
sealed class VideoPlayer : IDisposable{
public bool Running{
get{
if (currentProcess == null){
return false;
}
currentProcess.Refresh();
return !currentProcess.HasExited;
}
}
public event EventHandler ProcessExited;
private readonly Form owner;
private string lastUrl;
private string lastUsername;
private Process currentProcess;
private DuplexPipe.Server currentPipe;
private bool isClosing;
public VideoPlayer(Form owner){
this.owner = owner;
this.owner.FormClosing += owner_FormClosing;
}
public void Launch(string url, string username){
if (Running){
Destroy();
isClosing = false;
}
lastUrl = url;
lastUsername = username;
try{
currentPipe = DuplexPipe.CreateServer();
currentPipe.DataIn += currentPipe_DataIn;
if ((currentProcess = Process.Start(new ProcessStartInfo{
FileName = Path.Combine(Program.ProgramPath, "TweetDuck.Video.exe"),
Arguments = $"{owner.Handle} {Program.UserConfig.VideoPlayerVolume} \"{url}\" \"{currentPipe.GenerateToken()}\"",
UseShellExecute = false,
RedirectStandardOutput = true
})) != null){
currentProcess.EnableRaisingEvents = true;
currentProcess.Exited += process_Exited;
#if DEBUG
currentProcess.BeginOutputReadLine();
currentProcess.OutputDataReceived += (sender, args) => Debug.WriteLine("VideoPlayer: "+args.Data);
#endif
}
currentPipe.DisposeToken();
}catch(Exception e){
Program.Reporter.HandleException("Video Playback Error", "Error launching video player.", true, e);
}
}
public void SendKeyEvent(Keys key){
currentPipe?.Write("key", ((int)key).ToString());
}
private void currentPipe_DataIn(object sender, DuplexPipe.PipeReadEventArgs e){
owner.InvokeSafe(() => {
switch(e.Key){
case "vol":
if (int.TryParse(e.Data, out int volume) && volume != Program.UserConfig.VideoPlayerVolume){
Program.UserConfig.VideoPlayerVolume = volume;
Program.UserConfig.Save();
}
break;
case "download":
TwitterUtils.DownloadVideo(lastUrl, lastUsername);
break;
case "rip":
currentPipe.Dispose();
currentPipe = null;
currentProcess.Dispose();
currentProcess = null;
isClosing = false;
TriggerProcessExitEventUnsafe();
break;
}
});
}
public void Close(){
if (currentProcess != null){
if (isClosing){
Destroy();
isClosing = false;
}
else{
isClosing = true;
currentProcess.Exited -= process_Exited;
currentPipe.Write("die");
}
}
}
public void Dispose(){
ProcessExited = null;
isClosing = true;
Destroy();
}
private void Destroy(){
if (currentProcess != null){
try{
currentProcess.Kill();
}catch{
// kill me instead then
}
currentProcess.Dispose();
currentProcess = null;
currentPipe.Dispose();
currentPipe = null;
TriggerProcessExitEventUnsafe();
}
}
private void owner_FormClosing(object sender, FormClosingEventArgs e){
if (currentProcess != null){
currentProcess.Exited -= process_Exited;
}
}
private void process_Exited(object sender, EventArgs e){
int exitCode = currentProcess.ExitCode;
currentProcess.Dispose();
currentProcess = null;
currentPipe.Dispose();
currentPipe = null;
switch(exitCode){
case 3: // CODE_LAUNCH_FAIL
if (FormMessage.Error("Video Playback Error", "Error launching video player, this may be caused by missing Windows Media Player. Do you want to open the video in your browser?", FormMessage.Yes, FormMessage.No)){
BrowserUtils.OpenExternalBrowser(lastUrl);
}
break;
case 4: // CODE_MEDIA_ERROR
if (FormMessage.Error("Video Playback Error", "The video could not be loaded, most likely due to unknown format. Do you want to open the video in your browser?", FormMessage.Yes, FormMessage.No)){
BrowserUtils.OpenExternalBrowser(lastUrl);
}
break;
}
owner.InvokeAsyncSafe(TriggerProcessExitEventUnsafe);
}
private void TriggerProcessExitEventUnsafe(){
ProcessExited?.Invoke(this, EventArgs.Empty);
}
}
}

View File

@@ -1,20 +1,29 @@
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq;
using System.Windows.Forms; using System.Windows.Forms;
using TweetDuck.Configuration; using TweetDuck.Configuration;
namespace TweetDuck.Core.Other.Settings{ namespace TweetDuck.Core.Other.Settings{
class BaseTabSettings : UserControl{ class BaseTabSettings : UserControl{
protected static UserConfig Config => Program.UserConfig; protected static UserConfig Config => Program.Config.User;
protected static SystemConfig SysConfig => Program.Config.System;
public IEnumerable<Control> InteractiveControls{ public IEnumerable<Control> InteractiveControls{
get{ get{
foreach(Panel panel in Controls.OfType<Panel>()){ IEnumerable<Control> FindInteractiveControls(Control parent){
foreach(Control control in panel.Controls){ foreach(Control control in parent.Controls){
if (control is Panel subPanel){
foreach(Control subControl in FindInteractiveControls(subPanel)){
yield return subControl;
}
}
else{
yield return control; yield return control;
} }
} }
} }
return FindInteractiveControls(this);
}
} }
protected BaseTabSettings(){ protected BaseTabSettings(){
@@ -23,11 +32,5 @@ namespace TweetDuck.Core.Other.Settings{
public virtual void OnReady(){} public virtual void OnReady(){}
public virtual void OnClosing(){} public virtual void OnClosing(){}
protected static void PromptRestart(){
if (FormMessage.Information("TweetDuck Options", "The application must restart for the option to take place. Do you want to restart now?", FormMessage.Yes, FormMessage.No)){
Program.Restart();
}
}
} }
} }

View File

@@ -33,22 +33,24 @@
this.textBoxReport.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom) this.textBoxReport.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom)
| System.Windows.Forms.AnchorStyles.Left) | System.Windows.Forms.AnchorStyles.Left)
| System.Windows.Forms.AnchorStyles.Right))); | System.Windows.Forms.AnchorStyles.Right)));
this.textBoxReport.Font = new System.Drawing.Font("Courier New", 8.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(238))); this.textBoxReport.Font = new System.Drawing.Font("Courier New", 8.25F, System.Drawing.FontStyle.Regular);
this.textBoxReport.Location = new System.Drawing.Point(12, 41); this.textBoxReport.Location = new System.Drawing.Point(12, 45);
this.textBoxReport.Multiline = true; this.textBoxReport.Multiline = true;
this.textBoxReport.Name = "textBoxReport"; this.textBoxReport.Name = "textBoxReport";
this.textBoxReport.ReadOnly = true; this.textBoxReport.ReadOnly = true;
this.textBoxReport.ScrollBars = System.Windows.Forms.ScrollBars.Both; this.textBoxReport.ScrollBars = System.Windows.Forms.ScrollBars.Both;
this.textBoxReport.Size = new System.Drawing.Size(460, 480); this.textBoxReport.Size = new System.Drawing.Size(435, 474);
this.textBoxReport.TabIndex = 1; this.textBoxReport.TabIndex = 1;
// //
// btnClose // btnClose
// //
this.btnClose.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right))); this.btnClose.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right)));
this.btnClose.Location = new System.Drawing.Point(416, 527); this.btnClose.AutoSize = true;
this.btnClose.Font = new System.Drawing.Font("Segoe UI", 9F, System.Drawing.FontStyle.Regular);
this.btnClose.Location = new System.Drawing.Point(397, 525);
this.btnClose.Name = "btnClose"; this.btnClose.Name = "btnClose";
this.btnClose.Padding = new System.Windows.Forms.Padding(3, 0, 3, 0); this.btnClose.Padding = new System.Windows.Forms.Padding(2, 0, 2, 0);
this.btnClose.Size = new System.Drawing.Size(56, 23); this.btnClose.Size = new System.Drawing.Size(50, 25);
this.btnClose.TabIndex = 2; this.btnClose.TabIndex = 2;
this.btnClose.Text = "Close"; this.btnClose.Text = "Close";
this.btnClose.UseVisualStyleBackColor = true; this.btnClose.UseVisualStyleBackColor = true;
@@ -56,23 +58,25 @@
// //
// labelInfo // labelInfo
// //
this.labelInfo.AutoSize = true;
this.labelInfo.Font = new System.Drawing.Font("Segoe UI", 9F, System.Drawing.FontStyle.Regular);
this.labelInfo.Location = new System.Drawing.Point(12, 9); this.labelInfo.Location = new System.Drawing.Point(12, 9);
this.labelInfo.Margin = new System.Windows.Forms.Padding(3, 0, 3, 3); this.labelInfo.Margin = new System.Windows.Forms.Padding(3, 0, 3, 3);
this.labelInfo.Name = "labelInfo"; this.labelInfo.Name = "labelInfo";
this.labelInfo.Size = new System.Drawing.Size(460, 26); this.labelInfo.Size = new System.Drawing.Size(434, 30);
this.labelInfo.TabIndex = 0; this.labelInfo.TabIndex = 0;
this.labelInfo.Text = "When enabled, this data will be sent over a secure network roughly once every wee" + this.labelInfo.Text = "When enabled, this data will be sent over a secure network roughly every 14 days." +
"k.\r\nSome numbers in the report were made imprecise on purpose."; "\r\nSome numbers in the report were made imprecise on purpose.";
// //
// DialogSettingsAnalytics // DialogSettingsAnalytics
// //
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
this.ClientSize = new System.Drawing.Size(484, 562); this.ClientSize = new System.Drawing.Size(459, 562);
this.Controls.Add(this.labelInfo); this.Controls.Add(this.labelInfo);
this.Controls.Add(this.btnClose); this.Controls.Add(this.btnClose);
this.Controls.Add(this.textBoxReport); this.Controls.Add(this.textBoxReport);
this.MinimumSize = new System.Drawing.Size(450, 340); this.MinimumSize = new System.Drawing.Size(475, 340);
this.Name = "DialogSettingsAnalytics"; this.Name = "DialogSettingsAnalytics";
this.ShowIcon = false; this.ShowIcon = false;
this.StartPosition = System.Windows.Forms.FormStartPosition.CenterParent; this.StartPosition = System.Windows.Forms.FormStartPosition.CenterParent;

View File

@@ -27,40 +27,41 @@
this.textBoxBrowserCSS = new System.Windows.Forms.TextBox(); this.textBoxBrowserCSS = new System.Windows.Forms.TextBox();
this.btnCancel = new System.Windows.Forms.Button(); this.btnCancel = new System.Windows.Forms.Button();
this.btnApply = new System.Windows.Forms.Button(); this.btnApply = new System.Windows.Forms.Button();
this.splitContainer = new System.Windows.Forms.SplitContainer();
this.labelBrowser = new System.Windows.Forms.Label();
this.labelNotification = new System.Windows.Forms.Label();
this.textBoxNotificationCSS = new System.Windows.Forms.TextBox(); this.textBoxNotificationCSS = new System.Windows.Forms.TextBox();
this.labelWarning = new System.Windows.Forms.Label(); this.btnOpenDevTools = new System.Windows.Forms.Button();
this.btnOpenWiki = new System.Windows.Forms.Button();
this.timerTestBrowser = new System.Windows.Forms.Timer(this.components); this.timerTestBrowser = new System.Windows.Forms.Timer(this.components);
((System.ComponentModel.ISupportInitialize)(this.splitContainer)).BeginInit(); this.tabPanel = new System.Windows.Forms.TabControl();
this.splitContainer.Panel1.SuspendLayout(); this.tabPageBrowser = new System.Windows.Forms.TabPage();
this.splitContainer.Panel2.SuspendLayout(); this.tabPageNotification = new System.Windows.Forms.TabPage();
this.splitContainer.SuspendLayout(); this.tabPanel.SuspendLayout();
this.tabPageBrowser.SuspendLayout();
this.tabPageNotification.SuspendLayout();
this.SuspendLayout(); this.SuspendLayout();
// //
// textBoxBrowserCSS // textBoxBrowserCSS
// //
this.textBoxBrowserCSS.Dock = System.Windows.Forms.DockStyle.Bottom; this.textBoxBrowserCSS.Dock = System.Windows.Forms.DockStyle.Fill;
this.textBoxBrowserCSS.Font = new System.Drawing.Font("Courier New", 8.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(238))); this.textBoxBrowserCSS.Font = new System.Drawing.Font("Courier New", 8.25F, System.Drawing.FontStyle.Regular);
this.textBoxBrowserCSS.Location = new System.Drawing.Point(0, 16); this.textBoxBrowserCSS.Location = new System.Drawing.Point(3, 3);
this.textBoxBrowserCSS.Margin = new System.Windows.Forms.Padding(0, 3, 0, 0); this.textBoxBrowserCSS.Margin = new System.Windows.Forms.Padding(0, 3, 0, 0);
this.textBoxBrowserCSS.Multiline = true; this.textBoxBrowserCSS.Multiline = true;
this.textBoxBrowserCSS.Name = "textBoxBrowserCSS"; this.textBoxBrowserCSS.Name = "textBoxBrowserCSS";
this.textBoxBrowserCSS.ScrollBars = System.Windows.Forms.ScrollBars.Both; this.textBoxBrowserCSS.ScrollBars = System.Windows.Forms.ScrollBars.Both;
this.textBoxBrowserCSS.Size = new System.Drawing.Size(378, 253); this.textBoxBrowserCSS.Size = new System.Drawing.Size(426, 332);
this.textBoxBrowserCSS.TabIndex = 1; this.textBoxBrowserCSS.TabIndex = 0;
this.textBoxBrowserCSS.WordWrap = false; this.textBoxBrowserCSS.WordWrap = false;
this.textBoxBrowserCSS.KeyDown += new System.Windows.Forms.KeyEventHandler(this.textBoxCSS_KeyDown);
this.textBoxBrowserCSS.KeyUp += new System.Windows.Forms.KeyEventHandler(this.textBoxBrowserCSS_KeyUp); this.textBoxBrowserCSS.KeyUp += new System.Windows.Forms.KeyEventHandler(this.textBoxBrowserCSS_KeyUp);
// //
// btnCancel // btnCancel
// //
this.btnCancel.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right))); this.btnCancel.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right)));
this.btnCancel.Location = new System.Drawing.Point(654, 287); this.btnCancel.AutoSize = true;
this.btnCancel.Font = new System.Drawing.Font("Segoe UI", 9F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
this.btnCancel.Location = new System.Drawing.Point(337, 384);
this.btnCancel.Name = "btnCancel"; this.btnCancel.Name = "btnCancel";
this.btnCancel.Padding = new System.Windows.Forms.Padding(3, 0, 3, 0); this.btnCancel.Padding = new System.Windows.Forms.Padding(2, 0, 2, 0);
this.btnCancel.Size = new System.Drawing.Size(56, 23); this.btnCancel.Size = new System.Drawing.Size(57, 25);
this.btnCancel.TabIndex = 2; this.btnCancel.TabIndex = 2;
this.btnCancel.Text = "Cancel"; this.btnCancel.Text = "Cancel";
this.btnCancel.UseVisualStyleBackColor = true; this.btnCancel.UseVisualStyleBackColor = true;
@@ -69,119 +70,105 @@
// btnApply // btnApply
// //
this.btnApply.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right))); this.btnApply.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right)));
this.btnApply.Location = new System.Drawing.Point(716, 287); this.btnApply.AutoSize = true;
this.btnApply.Font = new System.Drawing.Font("Segoe UI", 9F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
this.btnApply.Location = new System.Drawing.Point(400, 384);
this.btnApply.Name = "btnApply"; this.btnApply.Name = "btnApply";
this.btnApply.Padding = new System.Windows.Forms.Padding(3, 0, 3, 0); this.btnApply.Padding = new System.Windows.Forms.Padding(2, 0, 2, 0);
this.btnApply.Size = new System.Drawing.Size(56, 23); this.btnApply.Size = new System.Drawing.Size(52, 25);
this.btnApply.TabIndex = 1; this.btnApply.TabIndex = 1;
this.btnApply.Text = "Apply"; this.btnApply.Text = "Apply";
this.btnApply.UseVisualStyleBackColor = true; this.btnApply.UseVisualStyleBackColor = true;
this.btnApply.Click += new System.EventHandler(this.btnApply_Click); this.btnApply.Click += new System.EventHandler(this.btnApply_Click);
// //
// splitContainer
//
this.splitContainer.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.splitContainer.Location = new System.Drawing.Point(12, 12);
this.splitContainer.Name = "splitContainer";
//
// splitContainer.Panel1
//
this.splitContainer.Panel1.Controls.Add(this.labelBrowser);
this.splitContainer.Panel1.Controls.Add(this.textBoxBrowserCSS);
this.splitContainer.Panel1MinSize = 64;
//
// splitContainer.Panel2
//
this.splitContainer.Panel2.Controls.Add(this.labelNotification);
this.splitContainer.Panel2.Controls.Add(this.textBoxNotificationCSS);
this.splitContainer.Panel2MinSize = 64;
this.splitContainer.Size = new System.Drawing.Size(760, 269);
this.splitContainer.SplitterDistance = 378;
this.splitContainer.SplitterWidth = 5;
this.splitContainer.TabIndex = 0;
//
// labelBrowser
//
this.labelBrowser.AutoSize = true;
this.labelBrowser.Location = new System.Drawing.Point(-3, 0);
this.labelBrowser.Margin = new System.Windows.Forms.Padding(0, 0, 3, 0);
this.labelBrowser.Name = "labelBrowser";
this.labelBrowser.Size = new System.Drawing.Size(45, 13);
this.labelBrowser.TabIndex = 0;
this.labelBrowser.Text = "Browser";
//
// labelNotification
//
this.labelNotification.AutoSize = true;
this.labelNotification.Location = new System.Drawing.Point(-3, 0);
this.labelNotification.Margin = new System.Windows.Forms.Padding(0, 0, 3, 0);
this.labelNotification.Name = "labelNotification";
this.labelNotification.Size = new System.Drawing.Size(60, 13);
this.labelNotification.TabIndex = 0;
this.labelNotification.Text = "Notification";
//
// textBoxNotificationCSS // textBoxNotificationCSS
// //
this.textBoxNotificationCSS.Dock = System.Windows.Forms.DockStyle.Bottom; this.textBoxNotificationCSS.Dock = System.Windows.Forms.DockStyle.Fill;
this.textBoxNotificationCSS.Font = new System.Drawing.Font("Courier New", 8.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(238))); this.textBoxNotificationCSS.Font = new System.Drawing.Font("Courier New", 8.25F, System.Drawing.FontStyle.Regular);
this.textBoxNotificationCSS.Location = new System.Drawing.Point(0, 16); this.textBoxNotificationCSS.Location = new System.Drawing.Point(3, 3);
this.textBoxNotificationCSS.Margin = new System.Windows.Forms.Padding(0, 3, 0, 0); this.textBoxNotificationCSS.Margin = new System.Windows.Forms.Padding(0, 3, 0, 0);
this.textBoxNotificationCSS.Multiline = true; this.textBoxNotificationCSS.Multiline = true;
this.textBoxNotificationCSS.Name = "textBoxNotificationCSS"; this.textBoxNotificationCSS.Name = "textBoxNotificationCSS";
this.textBoxNotificationCSS.ScrollBars = System.Windows.Forms.ScrollBars.Both; this.textBoxNotificationCSS.ScrollBars = System.Windows.Forms.ScrollBars.Both;
this.textBoxNotificationCSS.Size = new System.Drawing.Size(377, 253); this.textBoxNotificationCSS.Size = new System.Drawing.Size(426, 332);
this.textBoxNotificationCSS.TabIndex = 1; this.textBoxNotificationCSS.TabIndex = 0;
this.textBoxNotificationCSS.WordWrap = false; this.textBoxNotificationCSS.WordWrap = false;
this.textBoxNotificationCSS.KeyDown += new System.Windows.Forms.KeyEventHandler(this.textBoxCSS_KeyDown);
// //
// labelWarning // btnOpenDevTools
// //
this.labelWarning.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left))); this.btnOpenDevTools.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left)));
this.labelWarning.AutoSize = true; this.btnOpenDevTools.AutoSize = true;
this.labelWarning.Location = new System.Drawing.Point(91, 292); this.btnOpenDevTools.Font = new System.Drawing.Font("Segoe UI", 9F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
this.labelWarning.Name = "labelWarning"; this.btnOpenDevTools.Location = new System.Drawing.Point(12, 384);
this.labelWarning.Size = new System.Drawing.Size(341, 13); this.btnOpenDevTools.Name = "btnOpenDevTools";
this.labelWarning.TabIndex = 3; this.btnOpenDevTools.Padding = new System.Windows.Forms.Padding(2, 0, 2, 0);
this.labelWarning.Text = "The code is not validated, please make sure there are no syntax errors."; this.btnOpenDevTools.Size = new System.Drawing.Size(104, 25);
// this.btnOpenDevTools.TabIndex = 3;
// btnOpenWiki this.btnOpenDevTools.Text = "Open Dev Tools";
// this.btnOpenDevTools.UseVisualStyleBackColor = true;
this.btnOpenWiki.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left))); this.btnOpenDevTools.Click += new System.EventHandler(this.btnOpenDevTools_Click);
this.btnOpenWiki.Location = new System.Drawing.Point(12, 287);
this.btnOpenWiki.Name = "btnOpenWiki";
this.btnOpenWiki.Padding = new System.Windows.Forms.Padding(3, 0, 3, 0);
this.btnOpenWiki.Size = new System.Drawing.Size(73, 23);
this.btnOpenWiki.TabIndex = 4;
this.btnOpenWiki.Text = "Open Wiki";
this.btnOpenWiki.UseVisualStyleBackColor = true;
this.btnOpenWiki.Click += new System.EventHandler(this.btnOpenWiki_Click);
// //
// timerTestBrowser // timerTestBrowser
// //
this.timerTestBrowser.Interval = 500; this.timerTestBrowser.Interval = 400;
this.timerTestBrowser.Tick += new System.EventHandler(this.timerTestBrowser_Tick); this.timerTestBrowser.Tick += new System.EventHandler(this.timerTestBrowser_Tick);
// //
// tabPanel
//
this.tabPanel.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.tabPanel.Controls.Add(this.tabPageBrowser);
this.tabPanel.Controls.Add(this.tabPageNotification);
this.tabPanel.Font = new System.Drawing.Font("Segoe UI", 9F, System.Drawing.FontStyle.Regular);
this.tabPanel.Location = new System.Drawing.Point(12, 12);
this.tabPanel.Name = "tabPanel";
this.tabPanel.SelectedIndex = 0;
this.tabPanel.Size = new System.Drawing.Size(440, 366);
this.tabPanel.TabIndex = 0;
this.tabPanel.SelectedIndexChanged += new System.EventHandler(this.tabPanel_SelectedIndexChanged);
//
// tabPageBrowser
//
this.tabPageBrowser.Controls.Add(this.textBoxBrowserCSS);
this.tabPageBrowser.Location = new System.Drawing.Point(4, 24);
this.tabPageBrowser.Name = "tabPageBrowser";
this.tabPageBrowser.Padding = new System.Windows.Forms.Padding(3);
this.tabPageBrowser.Size = new System.Drawing.Size(432, 338);
this.tabPageBrowser.TabIndex = 0;
this.tabPageBrowser.Text = "Browser";
this.tabPageBrowser.UseVisualStyleBackColor = true;
//
// tabPageNotification
//
this.tabPageNotification.Controls.Add(this.textBoxNotificationCSS);
this.tabPageNotification.Location = new System.Drawing.Point(4, 24);
this.tabPageNotification.Name = "tabPageNotification";
this.tabPageNotification.Padding = new System.Windows.Forms.Padding(3);
this.tabPageNotification.Size = new System.Drawing.Size(432, 338);
this.tabPageNotification.TabIndex = 1;
this.tabPageNotification.Text = "Notification";
this.tabPageNotification.UseVisualStyleBackColor = true;
//
// DialogSettingsCSS // DialogSettingsCSS
// //
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
this.ClientSize = new System.Drawing.Size(784, 322); this.ClientSize = new System.Drawing.Size(464, 421);
this.Controls.Add(this.btnOpenWiki); this.Controls.Add(this.tabPanel);
this.Controls.Add(this.labelWarning); this.Controls.Add(this.btnOpenDevTools);
this.Controls.Add(this.splitContainer);
this.Controls.Add(this.btnApply); this.Controls.Add(this.btnApply);
this.Controls.Add(this.btnCancel); this.Controls.Add(this.btnCancel);
this.MinimumSize = new System.Drawing.Size(600, 160); this.MinimumSize = new System.Drawing.Size(320, 240);
this.Name = "DialogSettingsCSS"; this.Name = "DialogSettingsCSS";
this.ShowIcon = false; this.ShowIcon = false;
this.StartPosition = System.Windows.Forms.FormStartPosition.CenterParent; this.StartPosition = System.Windows.Forms.FormStartPosition.CenterParent;
this.splitContainer.Panel1.ResumeLayout(false); this.tabPanel.ResumeLayout(false);
this.splitContainer.Panel1.PerformLayout(); this.tabPageBrowser.ResumeLayout(false);
this.splitContainer.Panel2.ResumeLayout(false); this.tabPageBrowser.PerformLayout();
this.splitContainer.Panel2.PerformLayout(); this.tabPageNotification.ResumeLayout(false);
((System.ComponentModel.ISupportInitialize)(this.splitContainer)).EndInit(); this.tabPageNotification.PerformLayout();
this.splitContainer.ResumeLayout(false);
this.ResumeLayout(false); this.ResumeLayout(false);
this.PerformLayout(); this.PerformLayout();
@@ -192,12 +179,11 @@
private System.Windows.Forms.TextBox textBoxBrowserCSS; private System.Windows.Forms.TextBox textBoxBrowserCSS;
private System.Windows.Forms.Button btnCancel; private System.Windows.Forms.Button btnCancel;
private System.Windows.Forms.Button btnApply; private System.Windows.Forms.Button btnApply;
private System.Windows.Forms.SplitContainer splitContainer;
private System.Windows.Forms.TextBox textBoxNotificationCSS; private System.Windows.Forms.TextBox textBoxNotificationCSS;
private System.Windows.Forms.Label labelBrowser; private System.Windows.Forms.Button btnOpenDevTools;
private System.Windows.Forms.Label labelNotification;
private System.Windows.Forms.Label labelWarning;
private System.Windows.Forms.Button btnOpenWiki;
private System.Windows.Forms.Timer timerTestBrowser; private System.Windows.Forms.Timer timerTestBrowser;
private System.Windows.Forms.TabControl tabPanel;
private System.Windows.Forms.TabPage tabPageBrowser;
private System.Windows.Forms.TabPage tabPageNotification;
} }
} }

View File

@@ -1,4 +1,6 @@
using System; using System;
using System.Linq;
using System.Text.RegularExpressions;
using System.Windows.Forms; using System.Windows.Forms;
using TweetDuck.Core.Controls; using TweetDuck.Core.Controls;
using TweetDuck.Core.Utils; using TweetDuck.Core.Utils;
@@ -9,19 +11,108 @@ namespace TweetDuck.Core.Other.Settings.Dialogs{
public string NotificationCSS => textBoxNotificationCSS.Text; public string NotificationCSS => textBoxNotificationCSS.Text;
private readonly Action<string> reinjectBrowserCSS; private readonly Action<string> reinjectBrowserCSS;
private readonly Action openDevTools;
public DialogSettingsCSS(Action<string> reinjectBrowserCSS){ public DialogSettingsCSS(string browserCSS, string notificationCSS, Action<string> reinjectBrowserCSS, Action openDevTools){
InitializeComponent(); InitializeComponent();
Text = Program.BrandName+" Options - CSS"; Text = Program.BrandName+" Options - CSS";
this.reinjectBrowserCSS = reinjectBrowserCSS; this.reinjectBrowserCSS = reinjectBrowserCSS;
this.openDevTools = openDevTools;
textBoxBrowserCSS.EnableMultilineShortcuts(); textBoxBrowserCSS.EnableMultilineShortcuts();
textBoxBrowserCSS.Text = Program.UserConfig.CustomBrowserCSS ?? ""; textBoxBrowserCSS.Text = browserCSS ?? "";
textBoxNotificationCSS.EnableMultilineShortcuts(); textBoxNotificationCSS.EnableMultilineShortcuts();
textBoxNotificationCSS.Text = Program.UserConfig.CustomNotificationCSS ?? ""; textBoxNotificationCSS.Text = notificationCSS ?? "";
if (!BrowserUtils.HasDevTools){
btnOpenDevTools.Enabled = false;
}
ActiveControl = textBoxBrowserCSS;
textBoxBrowserCSS.Select(textBoxBrowserCSS.TextLength, 0);
}
private void tabPanel_SelectedIndexChanged(object sender, EventArgs e){
TextBox tb = tabPanel.SelectedTab.Controls.OfType<TextBox>().FirstOrDefault();
if (tb != null){
tb.Focus();
tb.Select(tb.TextLength, 0);
}
}
private void textBoxCSS_KeyDown(object sender, KeyEventArgs e){
TextBox tb = (TextBox)sender;
string text = tb.Text;
if (e.KeyCode == Keys.Back && e.Modifiers == Keys.Control){
e.SuppressKeyPress = true;
int deleteTo = tb.SelectionStart;
if (deleteTo > 0){
char initialChar = text[--deleteTo];
bool shouldDeleteAlphanumeric = char.IsLetterOrDigit(initialChar);
while(--deleteTo >= 0){
if ((shouldDeleteAlphanumeric && !char.IsLetterOrDigit(text[deleteTo])) ||
(!shouldDeleteAlphanumeric && text[deleteTo] != initialChar)){
break;
}
}
if (!(deleteTo < text.Length-1 && text[deleteTo] == '\r' && text[deleteTo+1] == '\n')){
++deleteTo;
}
tb.Select(deleteTo, tb.SelectionLength+tb.SelectionStart-deleteTo);
tb.SelectedText = string.Empty;
}
}
else if (e.KeyCode == Keys.Back && e.Modifiers == Keys.None){
int deleteTo = tb.SelectionStart;
if (deleteTo > 1 && text[deleteTo-1] == ' ' && text[deleteTo-2] == ' '){
e.SuppressKeyPress = true;
tb.Select(deleteTo-2, 2);
tb.SelectedText = string.Empty;
}
}
else if (e.KeyCode == Keys.Enter && e.Modifiers == Keys.None && tb.SelectionLength == 0){
int insertAt = tb.SelectionStart, cursorOffset = 0;
string insertText;
if (insertAt == 0){
return;
}
else if (text[insertAt-1] == '{'){
insertText = Environment.NewLine+" ";
int nextBracket = insertAt < text.Length ? text.IndexOfAny(new char[]{ '{', '}' }, insertAt+1) : -1;
if (nextBracket == -1 || text[nextBracket] == '{'){
string insertExtra = Environment.NewLine+"}";
insertText += insertExtra;
cursorOffset -= insertExtra.Length;
}
}
else{
int lineStart = text.LastIndexOf('\n', tb.SelectionStart-1);
Match match = Regex.Match(text.Substring(lineStart == -1 ? 0 : lineStart+1), "^([ \t]+)");
insertText = match.Success ? Environment.NewLine+match.Groups[1].Value : null;
}
if (!string.IsNullOrEmpty(insertText)){
e.SuppressKeyPress = true;
tb.Text = text.Insert(insertAt, insertText);
tb.SelectionStart = insertAt+cursorOffset+insertText.Length;
}
}
} }
private void textBoxBrowserCSS_KeyUp(object sender, KeyEventArgs e){ private void textBoxBrowserCSS_KeyUp(object sender, KeyEventArgs e){
@@ -34,8 +125,8 @@ namespace TweetDuck.Core.Other.Settings.Dialogs{
timerTestBrowser.Stop(); timerTestBrowser.Stop();
} }
private void btnOpenWiki_Click(object sender, EventArgs e){ private void btnOpenDevTools_Click(object sender, EventArgs e){
BrowserUtils.OpenExternalBrowser("https://github.com/chylex/TweetDuck/wiki"); openDevTools();
} }
private void btnApply_Click(object sender, EventArgs e){ private void btnApply_Click(object sender, EventArgs e){

View File

@@ -35,20 +35,22 @@
this.textBoxArgs.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom) this.textBoxArgs.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom)
| System.Windows.Forms.AnchorStyles.Left) | System.Windows.Forms.AnchorStyles.Left)
| System.Windows.Forms.AnchorStyles.Right))); | System.Windows.Forms.AnchorStyles.Right)));
this.textBoxArgs.Font = new System.Drawing.Font("Courier New", 8.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(238))); this.textBoxArgs.Font = new System.Drawing.Font("Courier New", 8.25F, System.Drawing.FontStyle.Regular);
this.textBoxArgs.Location = new System.Drawing.Point(12, 28); this.textBoxArgs.Location = new System.Drawing.Point(12, 30);
this.textBoxArgs.Multiline = true; this.textBoxArgs.Multiline = true;
this.textBoxArgs.Name = "textBoxArgs"; this.textBoxArgs.Name = "textBoxArgs";
this.textBoxArgs.Size = new System.Drawing.Size(460, 193); this.textBoxArgs.Size = new System.Drawing.Size(480, 189);
this.textBoxArgs.TabIndex = 1; this.textBoxArgs.TabIndex = 1;
// //
// btnCancel // btnCancel
// //
this.btnCancel.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right))); this.btnCancel.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right)));
this.btnCancel.Location = new System.Drawing.Point(354, 227); this.btnCancel.AutoSize = true;
this.btnCancel.Font = new System.Drawing.Font("Segoe UI", 9F, System.Drawing.FontStyle.Regular);
this.btnCancel.Location = new System.Drawing.Point(377, 225);
this.btnCancel.Name = "btnCancel"; this.btnCancel.Name = "btnCancel";
this.btnCancel.Padding = new System.Windows.Forms.Padding(3, 0, 3, 0); this.btnCancel.Padding = new System.Windows.Forms.Padding(2, 0, 2, 0);
this.btnCancel.Size = new System.Drawing.Size(56, 23); this.btnCancel.Size = new System.Drawing.Size(57, 25);
this.btnCancel.TabIndex = 3; this.btnCancel.TabIndex = 3;
this.btnCancel.Text = "Cancel"; this.btnCancel.Text = "Cancel";
this.btnCancel.UseVisualStyleBackColor = true; this.btnCancel.UseVisualStyleBackColor = true;
@@ -57,10 +59,12 @@
// btnApply // btnApply
// //
this.btnApply.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right))); this.btnApply.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right)));
this.btnApply.Location = new System.Drawing.Point(416, 227); this.btnApply.AutoSize = true;
this.btnApply.Font = new System.Drawing.Font("Segoe UI", 9F, System.Drawing.FontStyle.Regular);
this.btnApply.Location = new System.Drawing.Point(440, 225);
this.btnApply.Name = "btnApply"; this.btnApply.Name = "btnApply";
this.btnApply.Padding = new System.Windows.Forms.Padding(3, 0, 3, 0); this.btnApply.Padding = new System.Windows.Forms.Padding(2, 0, 2, 0);
this.btnApply.Size = new System.Drawing.Size(56, 23); this.btnApply.Size = new System.Drawing.Size(52, 25);
this.btnApply.TabIndex = 2; this.btnApply.TabIndex = 2;
this.btnApply.Text = "Apply"; this.btnApply.Text = "Apply";
this.btnApply.UseVisualStyleBackColor = true; this.btnApply.UseVisualStyleBackColor = true;
@@ -69,10 +73,12 @@
// btnHelp // btnHelp
// //
this.btnHelp.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left))); this.btnHelp.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left)));
this.btnHelp.Location = new System.Drawing.Point(12, 227); this.btnHelp.AutoSize = true;
this.btnHelp.Font = new System.Drawing.Font("Segoe UI", 9F, System.Drawing.FontStyle.Regular);
this.btnHelp.Location = new System.Drawing.Point(12, 225);
this.btnHelp.Name = "btnHelp"; this.btnHelp.Name = "btnHelp";
this.btnHelp.Padding = new System.Windows.Forms.Padding(3, 0, 3, 0); this.btnHelp.Padding = new System.Windows.Forms.Padding(2, 0, 2, 0);
this.btnHelp.Size = new System.Drawing.Size(124, 23); this.btnHelp.Size = new System.Drawing.Size(141, 25);
this.btnHelp.TabIndex = 4; this.btnHelp.TabIndex = 4;
this.btnHelp.Text = "List of Chromium Args"; this.btnHelp.Text = "List of Chromium Args";
this.btnHelp.UseVisualStyleBackColor = true; this.btnHelp.UseVisualStyleBackColor = true;
@@ -81,10 +87,11 @@
// labelWarning // labelWarning
// //
this.labelWarning.AutoSize = true; this.labelWarning.AutoSize = true;
this.labelWarning.Font = new System.Drawing.Font("Segoe UI", 9F, System.Drawing.FontStyle.Regular);
this.labelWarning.Location = new System.Drawing.Point(12, 9); this.labelWarning.Location = new System.Drawing.Point(12, 9);
this.labelWarning.Margin = new System.Windows.Forms.Padding(3, 0, 3, 3); this.labelWarning.Margin = new System.Windows.Forms.Padding(3, 0, 3, 3);
this.labelWarning.Name = "labelWarning"; this.labelWarning.Name = "labelWarning";
this.labelWarning.Size = new System.Drawing.Size(423, 13); this.labelWarning.Size = new System.Drawing.Size(478, 15);
this.labelWarning.TabIndex = 0; this.labelWarning.TabIndex = 0;
this.labelWarning.Text = "Warning: Some arguments may cause the program to stop working, edit at your own r" + this.labelWarning.Text = "Warning: Some arguments may cause the program to stop working, edit at your own r" +
"isk."; "isk.";
@@ -93,13 +100,13 @@
// //
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
this.ClientSize = new System.Drawing.Size(484, 262); this.ClientSize = new System.Drawing.Size(504, 262);
this.Controls.Add(this.labelWarning); this.Controls.Add(this.labelWarning);
this.Controls.Add(this.btnHelp); this.Controls.Add(this.btnHelp);
this.Controls.Add(this.btnApply); this.Controls.Add(this.btnApply);
this.Controls.Add(this.btnCancel); this.Controls.Add(this.btnCancel);
this.Controls.Add(this.textBoxArgs); this.Controls.Add(this.textBoxArgs);
this.MinimumSize = new System.Drawing.Size(500, 160); this.MinimumSize = new System.Drawing.Size(520, 160);
this.Name = "DialogSettingsCefArgs"; this.Name = "DialogSettingsCefArgs";
this.ShowIcon = false; this.ShowIcon = false;
this.StartPosition = System.Windows.Forms.FormStartPosition.CenterParent; this.StartPosition = System.Windows.Forms.FormStartPosition.CenterParent;

View File

@@ -8,13 +8,15 @@ namespace TweetDuck.Core.Other.Settings.Dialogs{
sealed partial class DialogSettingsCefArgs : Form{ sealed partial class DialogSettingsCefArgs : Form{
public string CefArgs => textBoxArgs.Text; public string CefArgs => textBoxArgs.Text;
public DialogSettingsCefArgs(){ private readonly string initialArgs;
public DialogSettingsCefArgs(string args){
InitializeComponent(); InitializeComponent();
Text = Program.BrandName+" Options - CEF Arguments"; Text = Program.BrandName+" Options - CEF Arguments";
textBoxArgs.EnableMultilineShortcuts(); textBoxArgs.EnableMultilineShortcuts();
textBoxArgs.Text = Program.UserConfig.CustomCefArgs ?? ""; textBoxArgs.Text = initialArgs = args ?? "";
textBoxArgs.Select(textBoxArgs.Text.Length, 0); textBoxArgs.Select(textBoxArgs.Text.Length, 0);
} }
@@ -23,16 +25,14 @@ namespace TweetDuck.Core.Other.Settings.Dialogs{
} }
private void btnApply_Click(object sender, EventArgs e){ private void btnApply_Click(object sender, EventArgs e){
string prevArgs = Program.UserConfig.CustomCefArgs; if (CefArgs == initialArgs){
if (CefArgs == prevArgs){
DialogResult = DialogResult.Cancel; DialogResult = DialogResult.Cancel;
Close(); Close();
return; return;
} }
int count = CommandLineArgs.ReadCefArguments(CefArgs).Count; int count = CommandLineArgs.ReadCefArguments(CefArgs).Count;
string prompt = count == 0 && !string.IsNullOrWhiteSpace(prevArgs) ? "All current arguments will be removed. Continue?" : count+(count == 1 ? " argument was" : " arguments were")+" detected. Continue?"; string prompt = count == 0 && !string.IsNullOrWhiteSpace(initialArgs) ? "All current arguments will be removed. Continue?" : count+(count == 1 ? " argument was" : " arguments were")+" detected. Continue?";
if (FormMessage.Question("Confirm CEF Arguments", prompt, FormMessage.OK, FormMessage.Cancel)){ if (FormMessage.Question("Confirm CEF Arguments", prompt, FormMessage.OK, FormMessage.Cancel)){
DialogResult = DialogResult.OK; DialogResult = DialogResult.OK;

View File

@@ -26,26 +26,29 @@
this.components = new System.ComponentModel.Container(); this.components = new System.ComponentModel.Container();
this.btnCancel = new System.Windows.Forms.Button(); this.btnCancel = new System.Windows.Forms.Button();
this.btnContinue = new System.Windows.Forms.Button(); this.btnContinue = new System.Windows.Forms.Button();
this.cbConfig = new System.Windows.Forms.CheckBox(); this.cbProgramConfig = new System.Windows.Forms.CheckBox();
this.cbSession = new System.Windows.Forms.CheckBox(); this.cbSession = new System.Windows.Forms.CheckBox();
this.cbPluginData = new System.Windows.Forms.CheckBox(); this.cbPluginData = new System.Windows.Forms.CheckBox();
this.toolTip = new System.Windows.Forms.ToolTip(this.components); this.toolTip = new System.Windows.Forms.ToolTip(this.components);
this.panelExport = new System.Windows.Forms.Panel(); this.cbSystemConfig = new System.Windows.Forms.CheckBox();
this.panelDecision = new System.Windows.Forms.Panel(); this.panelSelection = new System.Windows.Forms.FlowLayoutPanel();
this.radioReset = new System.Windows.Forms.RadioButton(); this.panelDecision = new System.Windows.Forms.FlowLayoutPanel();
this.radioExport = new System.Windows.Forms.RadioButton();
this.radioImport = new System.Windows.Forms.RadioButton(); this.radioImport = new System.Windows.Forms.RadioButton();
this.panelExport.SuspendLayout(); this.radioExport = new System.Windows.Forms.RadioButton();
this.radioReset = new System.Windows.Forms.RadioButton();
this.panelSelection.SuspendLayout();
this.panelDecision.SuspendLayout(); this.panelDecision.SuspendLayout();
this.SuspendLayout(); this.SuspendLayout();
// //
// btnCancel // btnCancel
// //
this.btnCancel.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right))); this.btnCancel.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right)));
this.btnCancel.Location = new System.Drawing.Point(176, 97); this.btnCancel.AutoSize = true;
this.btnCancel.Font = new System.Drawing.Font("Segoe UI", 9F, System.Drawing.FontStyle.Regular);
this.btnCancel.Location = new System.Drawing.Point(165, 92);
this.btnCancel.Name = "btnCancel"; this.btnCancel.Name = "btnCancel";
this.btnCancel.Padding = new System.Windows.Forms.Padding(3, 0, 3, 0); this.btnCancel.Padding = new System.Windows.Forms.Padding(2, 0, 2, 0);
this.btnCancel.Size = new System.Drawing.Size(56, 23); this.btnCancel.Size = new System.Drawing.Size(57, 25);
this.btnCancel.TabIndex = 4; this.btnCancel.TabIndex = 4;
this.btnCancel.Text = "Cancel"; this.btnCancel.Text = "Cancel";
this.btnCancel.UseVisualStyleBackColor = true; this.btnCancel.UseVisualStyleBackColor = true;
@@ -56,127 +59,163 @@
this.btnContinue.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right))); this.btnContinue.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right)));
this.btnContinue.AutoSize = true; this.btnContinue.AutoSize = true;
this.btnContinue.Enabled = false; this.btnContinue.Enabled = false;
this.btnContinue.Location = new System.Drawing.Point(125, 97); this.btnContinue.Font = new System.Drawing.Font("Segoe UI", 9F, System.Drawing.FontStyle.Regular);
this.btnContinue.Location = new System.Drawing.Point(114, 92);
this.btnContinue.Name = "btnContinue"; this.btnContinue.Name = "btnContinue";
this.btnContinue.Padding = new System.Windows.Forms.Padding(3, 0, 3, 0); this.btnContinue.Padding = new System.Windows.Forms.Padding(2, 0, 2, 0);
this.btnContinue.Size = new System.Drawing.Size(45, 23); this.btnContinue.Size = new System.Drawing.Size(45, 25);
this.btnContinue.TabIndex = 3; this.btnContinue.TabIndex = 3;
this.btnContinue.Text = "Next"; this.btnContinue.Text = "Next";
this.btnContinue.UseVisualStyleBackColor = true; this.btnContinue.UseVisualStyleBackColor = true;
this.btnContinue.Click += new System.EventHandler(this.btnContinue_Click); this.btnContinue.Click += new System.EventHandler(this.btnContinue_Click);
// //
// cbConfig // cbProgramConfig
// //
this.cbConfig.AutoSize = true; this.cbProgramConfig.AutoSize = true;
this.cbConfig.Location = new System.Drawing.Point(0, 3); this.cbProgramConfig.Font = new System.Drawing.Font("Segoe UI", 9F, System.Drawing.FontStyle.Regular);
this.cbConfig.Name = "cbConfig"; this.cbProgramConfig.Location = new System.Drawing.Point(3, 3);
this.cbConfig.Size = new System.Drawing.Size(104, 17); this.cbProgramConfig.Margin = new System.Windows.Forms.Padding(3, 3, 3, 2);
this.cbConfig.TabIndex = 0; this.cbProgramConfig.Name = "cbProgramConfig";
this.cbConfig.Text = "Program Options"; this.cbProgramConfig.Size = new System.Drawing.Size(117, 19);
this.toolTip.SetToolTip(this.cbConfig, "Interface, notification, and update options."); this.cbProgramConfig.TabIndex = 0;
this.cbConfig.UseVisualStyleBackColor = true; this.cbProgramConfig.Text = "Program Options";
this.cbConfig.CheckedChanged += new System.EventHandler(this.cbConfig_CheckedChanged); this.toolTip.SetToolTip(this.cbProgramConfig, "Interface, notification, and update options.");
this.cbProgramConfig.UseVisualStyleBackColor = true;
this.cbProgramConfig.CheckedChanged += new System.EventHandler(this.checkBoxSelection_CheckedChanged);
// //
// cbSession // cbSession
// //
this.cbSession.AutoSize = true; this.cbSession.AutoSize = true;
this.cbSession.Location = new System.Drawing.Point(0, 27); this.cbSession.Font = new System.Drawing.Font("Segoe UI", 9F, System.Drawing.FontStyle.Regular);
this.cbSession.Location = new System.Drawing.Point(3, 51);
this.cbSession.Margin = new System.Windows.Forms.Padding(3, 3, 3, 2);
this.cbSession.Name = "cbSession"; this.cbSession.Name = "cbSession";
this.cbSession.Size = new System.Drawing.Size(92, 17); this.cbSession.Size = new System.Drawing.Size(98, 19);
this.cbSession.TabIndex = 1; this.cbSession.TabIndex = 2;
this.cbSession.Text = "Login Session"; this.cbSession.Text = "Login Session";
this.toolTip.SetToolTip(this.cbSession, "A token that allows logging into the\r\ncurrent TweetDeck account."); this.toolTip.SetToolTip(this.cbSession, "A token that allows logging into the\r\ncurrent TweetDeck account.");
this.cbSession.UseVisualStyleBackColor = true; this.cbSession.UseVisualStyleBackColor = true;
this.cbSession.CheckedChanged += new System.EventHandler(this.cbSession_CheckedChanged); this.cbSession.CheckedChanged += new System.EventHandler(this.checkBoxSelection_CheckedChanged);
// //
// cbPluginData // cbPluginData
// //
this.cbPluginData.AutoSize = true; this.cbPluginData.AutoSize = true;
this.cbPluginData.Location = new System.Drawing.Point(0, 51); this.cbPluginData.Font = new System.Drawing.Font("Segoe UI", 9F, System.Drawing.FontStyle.Regular);
this.cbPluginData.Location = new System.Drawing.Point(3, 75);
this.cbPluginData.Margin = new System.Windows.Forms.Padding(3, 3, 3, 2);
this.cbPluginData.Name = "cbPluginData"; this.cbPluginData.Name = "cbPluginData";
this.cbPluginData.Size = new System.Drawing.Size(81, 17); this.cbPluginData.Size = new System.Drawing.Size(87, 19);
this.cbPluginData.TabIndex = 2; this.cbPluginData.TabIndex = 3;
this.cbPluginData.Text = "Plugin Data"; this.cbPluginData.Text = "Plugin Data";
this.toolTip.SetToolTip(this.cbPluginData, "Data files generated by plugins.\r\nDoes not include the plugins themselves."); this.toolTip.SetToolTip(this.cbPluginData, "Data files generated by plugins.\r\nDoes not include the plugins themselves.");
this.cbPluginData.UseVisualStyleBackColor = true; this.cbPluginData.UseVisualStyleBackColor = true;
this.cbPluginData.CheckedChanged += new System.EventHandler(this.cbPluginData_CheckedChanged); this.cbPluginData.CheckedChanged += new System.EventHandler(this.checkBoxSelection_CheckedChanged);
// //
// panelExport // cbSystemConfig
// //
this.panelExport.Controls.Add(this.cbConfig); this.cbSystemConfig.AutoSize = true;
this.panelExport.Controls.Add(this.cbPluginData); this.cbSystemConfig.Font = new System.Drawing.Font("Segoe UI", 9F, System.Drawing.FontStyle.Regular);
this.panelExport.Controls.Add(this.cbSession); this.cbSystemConfig.Location = new System.Drawing.Point(3, 27);
this.panelExport.Location = new System.Drawing.Point(12, 12); this.cbSystemConfig.Margin = new System.Windows.Forms.Padding(3, 3, 3, 2);
this.panelExport.Name = "panelExport"; this.cbSystemConfig.Name = "cbSystemConfig";
this.panelExport.Size = new System.Drawing.Size(220, 79); this.cbSystemConfig.Size = new System.Drawing.Size(109, 19);
this.panelExport.TabIndex = 5; this.cbSystemConfig.TabIndex = 1;
this.panelExport.Visible = false; this.cbSystemConfig.Text = "System Options";
this.toolTip.SetToolTip(this.cbSystemConfig, "Hardware acceleration and cache options.");
this.cbSystemConfig.UseVisualStyleBackColor = true;
this.cbSystemConfig.CheckedChanged += new System.EventHandler(this.checkBoxSelection_CheckedChanged);
//
// panelSelection
//
this.panelSelection.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left)
| System.Windows.Forms.AnchorStyles.Right)));
this.panelSelection.Controls.Add(this.cbProgramConfig);
this.panelSelection.Controls.Add(this.cbSystemConfig);
this.panelSelection.Controls.Add(this.cbSession);
this.panelSelection.Controls.Add(this.cbPluginData);
this.panelSelection.FlowDirection = System.Windows.Forms.FlowDirection.TopDown;
this.panelSelection.Location = new System.Drawing.Point(12, 12);
this.panelSelection.Name = "panelSelection";
this.panelSelection.Size = new System.Drawing.Size(210, 97);
this.panelSelection.TabIndex = 2;
this.panelSelection.Visible = false;
this.panelSelection.WrapContents = false;
// //
// panelDecision // panelDecision
// //
this.panelDecision.Controls.Add(this.radioReset); this.panelDecision.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left)
this.panelDecision.Controls.Add(this.radioExport); | System.Windows.Forms.AnchorStyles.Right)));
this.panelDecision.Controls.Add(this.radioImport); this.panelDecision.Controls.Add(this.radioImport);
this.panelDecision.Controls.Add(this.radioExport);
this.panelDecision.Controls.Add(this.radioReset);
this.panelDecision.FlowDirection = System.Windows.Forms.FlowDirection.TopDown;
this.panelDecision.Location = new System.Drawing.Point(12, 12); this.panelDecision.Location = new System.Drawing.Point(12, 12);
this.panelDecision.Name = "panelDecision"; this.panelDecision.Name = "panelDecision";
this.panelDecision.Size = new System.Drawing.Size(220, 79); this.panelDecision.Size = new System.Drawing.Size(210, 75);
this.panelDecision.TabIndex = 6; this.panelDecision.TabIndex = 0;
// this.panelDecision.WrapContents = false;
// radioReset
//
this.radioReset.AutoSize = true;
this.radioReset.Location = new System.Drawing.Point(3, 49);
this.radioReset.Name = "radioReset";
this.radioReset.Size = new System.Drawing.Size(104, 17);
this.radioReset.TabIndex = 2;
this.radioReset.TabStop = true;
this.radioReset.Text = "Restore Defaults";
this.radioReset.UseVisualStyleBackColor = true;
this.radioReset.CheckedChanged += new System.EventHandler(this.radioDecision_CheckedChanged);
//
// radioExport
//
this.radioExport.AutoSize = true;
this.radioExport.Location = new System.Drawing.Point(3, 26);
this.radioExport.Name = "radioExport";
this.radioExport.Size = new System.Drawing.Size(87, 17);
this.radioExport.TabIndex = 1;
this.radioExport.TabStop = true;
this.radioExport.Text = "Export Profile";
this.radioExport.UseVisualStyleBackColor = true;
this.radioExport.CheckedChanged += new System.EventHandler(this.radioDecision_CheckedChanged);
// //
// radioImport // radioImport
// //
this.radioImport.AutoSize = true; this.radioImport.AutoSize = true;
this.radioImport.Font = new System.Drawing.Font("Segoe UI", 9F, System.Drawing.FontStyle.Regular);
this.radioImport.Location = new System.Drawing.Point(3, 3); this.radioImport.Location = new System.Drawing.Point(3, 3);
this.radioImport.Margin = new System.Windows.Forms.Padding(3, 3, 3, 2);
this.radioImport.Name = "radioImport"; this.radioImport.Name = "radioImport";
this.radioImport.Size = new System.Drawing.Size(86, 17); this.radioImport.Size = new System.Drawing.Size(98, 19);
this.radioImport.TabIndex = 0; this.radioImport.TabIndex = 0;
this.radioImport.TabStop = true; this.radioImport.TabStop = true;
this.radioImport.Text = "Import Profile"; this.radioImport.Text = "Import Profile";
this.radioImport.UseVisualStyleBackColor = true; this.radioImport.UseVisualStyleBackColor = true;
this.radioImport.CheckedChanged += new System.EventHandler(this.radioDecision_CheckedChanged); this.radioImport.CheckedChanged += new System.EventHandler(this.radioDecision_CheckedChanged);
// //
// radioExport
//
this.radioExport.AutoSize = true;
this.radioExport.Font = new System.Drawing.Font("Segoe UI", 9F, System.Drawing.FontStyle.Regular);
this.radioExport.Location = new System.Drawing.Point(3, 27);
this.radioExport.Margin = new System.Windows.Forms.Padding(3, 3, 3, 2);
this.radioExport.Name = "radioExport";
this.radioExport.Size = new System.Drawing.Size(95, 19);
this.radioExport.TabIndex = 1;
this.radioExport.TabStop = true;
this.radioExport.Text = "Export Profile";
this.radioExport.UseVisualStyleBackColor = true;
this.radioExport.CheckedChanged += new System.EventHandler(this.radioDecision_CheckedChanged);
//
// radioReset
//
this.radioReset.AutoSize = true;
this.radioReset.Font = new System.Drawing.Font("Segoe UI", 9F, System.Drawing.FontStyle.Regular);
this.radioReset.Location = new System.Drawing.Point(3, 51);
this.radioReset.Margin = new System.Windows.Forms.Padding(3, 3, 3, 2);
this.radioReset.Name = "radioReset";
this.radioReset.Size = new System.Drawing.Size(110, 19);
this.radioReset.TabIndex = 2;
this.radioReset.TabStop = true;
this.radioReset.Text = "Restore Defaults";
this.radioReset.UseVisualStyleBackColor = true;
this.radioReset.CheckedChanged += new System.EventHandler(this.radioDecision_CheckedChanged);
//
// DialogSettingsManage // DialogSettingsManage
// //
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
this.ClientSize = new System.Drawing.Size(244, 132); this.ClientSize = new System.Drawing.Size(234, 129);
this.Controls.Add(this.panelDecision);
this.Controls.Add(this.panelExport);
this.Controls.Add(this.btnContinue); this.Controls.Add(this.btnContinue);
this.Controls.Add(this.btnCancel); this.Controls.Add(this.btnCancel);
this.Controls.Add(this.panelDecision);
this.Controls.Add(this.panelSelection);
this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedSingle; this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedSingle;
this.MaximizeBox = false; this.MaximizeBox = false;
this.MinimizeBox = false; this.MinimizeBox = false;
this.MinimumSize = new System.Drawing.Size(200, 170); this.MinimumSize = new System.Drawing.Size(250, 167);
this.Name = "DialogSettingsManage"; this.Name = "DialogSettingsManage";
this.ShowIcon = false; this.ShowIcon = false;
this.StartPosition = System.Windows.Forms.FormStartPosition.CenterParent; this.StartPosition = System.Windows.Forms.FormStartPosition.CenterParent;
this.Text = "Manage Options"; this.Text = "Manage Options";
this.panelExport.ResumeLayout(false); this.panelSelection.ResumeLayout(false);
this.panelExport.PerformLayout(); this.panelSelection.PerformLayout();
this.panelDecision.ResumeLayout(false); this.panelDecision.ResumeLayout(false);
this.panelDecision.PerformLayout(); this.panelDecision.PerformLayout();
this.ResumeLayout(false); this.ResumeLayout(false);
@@ -188,12 +227,13 @@
private System.Windows.Forms.Button btnCancel; private System.Windows.Forms.Button btnCancel;
private System.Windows.Forms.Button btnContinue; private System.Windows.Forms.Button btnContinue;
private System.Windows.Forms.CheckBox cbConfig; private System.Windows.Forms.CheckBox cbProgramConfig;
private System.Windows.Forms.CheckBox cbSystemConfig;
private System.Windows.Forms.CheckBox cbSession; private System.Windows.Forms.CheckBox cbSession;
private System.Windows.Forms.CheckBox cbPluginData; private System.Windows.Forms.CheckBox cbPluginData;
private System.Windows.Forms.ToolTip toolTip; private System.Windows.Forms.ToolTip toolTip;
private System.Windows.Forms.Panel panelExport; private System.Windows.Forms.FlowLayoutPanel panelSelection;
private System.Windows.Forms.Panel panelDecision; private System.Windows.Forms.FlowLayoutPanel panelDecision;
private System.Windows.Forms.RadioButton radioReset; private System.Windows.Forms.RadioButton radioReset;
private System.Windows.Forms.RadioButton radioExport; private System.Windows.Forms.RadioButton radioExport;
private System.Windows.Forms.RadioButton radioImport; private System.Windows.Forms.RadioButton radioImport;

View File

@@ -1,8 +1,10 @@
using System; using System;
using System.Collections.Generic;
using System.IO; using System.IO;
using System.Windows.Forms; using System.Windows.Forms;
using TweetDuck.Configuration; using TweetDuck.Configuration;
using TweetDuck.Core.Other.Settings.Export; using TweetDuck.Core.Management;
using TweetDuck.Core.Utils;
using TweetDuck.Plugins; using TweetDuck.Plugins;
namespace TweetDuck.Core.Other.Settings.Dialogs{ namespace TweetDuck.Core.Other.Settings.Dialogs{
@@ -11,46 +13,57 @@ namespace TweetDuck.Core.Other.Settings.Dialogs{
Deciding, Reset, Import, Export Deciding, Reset, Import, Export
} }
public ExportFileFlags Flags{ private ProfileManager.Items SelectedItems{
get => selectedFlags; get => _selectedItems;
set{ set{
// this will call events and SetFlag, which also updates the UI // this will call events and SetFlag, which also updates the UI
cbConfig.Checked = value.HasFlag(ExportFileFlags.UserConfig); foreach(KeyValuePair<CheckBox, ProfileManager.Items> kvp in checkBoxMap){
cbSession.Checked = value.HasFlag(ExportFileFlags.Session); kvp.Key.Checked = value.HasFlag(kvp.Value);
cbPluginData.Checked = value.HasFlag(ExportFileFlags.PluginData); }
} }
} }
private bool SelectedItemsForceRestart{
get => _selectedItems.HasFlag(ProfileManager.Items.Session);
}
public bool IsRestarting { get; private set; }
public bool ShouldReloadBrowser { get; private set; } public bool ShouldReloadBrowser { get; private set; }
private readonly PluginManager plugins; private readonly PluginManager plugins;
private readonly Dictionary<CheckBox, ProfileManager.Items> checkBoxMap = new Dictionary<CheckBox, ProfileManager.Items>(4);
private State currentState; private State currentState;
private ProfileManager importManager;
private bool requestedRestartFromConfig;
private ExportManager importManager; private ProfileManager.Items _selectedItems = ProfileManager.Items.None;
private ExportFileFlags selectedFlags = ExportFileFlags.None;
public DialogSettingsManage(PluginManager plugins){ public DialogSettingsManage(PluginManager plugins, bool openImportImmediately = false){
InitializeComponent(); InitializeComponent();
this.plugins = plugins; this.plugins = plugins;
this.currentState = State.Deciding; this.currentState = State.Deciding;
this.checkBoxMap[cbProgramConfig] = ProfileManager.Items.UserConfig;
this.checkBoxMap[cbSystemConfig] = ProfileManager.Items.SystemConfig;
this.checkBoxMap[cbSession] = ProfileManager.Items.Session;
this.checkBoxMap[cbPluginData] = ProfileManager.Items.PluginData;
if (openImportImmediately){
radioImport.Checked = true;
btnContinue_Click(null, EventArgs.Empty);
}
} }
private void radioDecision_CheckedChanged(object sender, EventArgs e){ private void radioDecision_CheckedChanged(object sender, EventArgs e){
btnContinue.Enabled = true; btnContinue.Enabled = true;
} }
private void cbConfig_CheckedChanged(object sender, EventArgs e){ private void checkBoxSelection_CheckedChanged(object sender, EventArgs e){
SetFlag(ExportFileFlags.UserConfig, cbConfig.Checked); CheckBox cb = (CheckBox)sender;
} SetFlag(checkBoxMap[cb], cb.Checked);
private void cbSession_CheckedChanged(object sender, EventArgs e){
SetFlag(ExportFileFlags.Session, cbSession.Checked);
}
private void cbPluginData_CheckedChanged(object sender, EventArgs e){
SetFlag(ExportFileFlags.PluginData, cbPluginData.Checked);
} }
private void btnContinue_Click(object sender, EventArgs e){ private void btnContinue_Click(object sender, EventArgs e){
@@ -63,7 +76,7 @@ namespace TweetDuck.Core.Other.Settings.Dialogs{
currentState = State.Reset; currentState = State.Reset;
Text = "Restore Defaults"; Text = "Restore Defaults";
Flags = ExportFileFlags.UserConfig; SelectedItems = ProfileManager.Items.UserConfig;
} }
// Import // Import
@@ -81,15 +94,15 @@ namespace TweetDuck.Core.Other.Settings.Dialogs{
file = dialog.FileName; file = dialog.FileName;
} }
importManager = new ExportManager(file, plugins); importManager = new ProfileManager(file, plugins);
currentState = State.Import; currentState = State.Import;
Text = "Import Profile"; Text = "Import Profile";
Flags = importManager.GetImportFlags(); SelectedItems = importManager.FindImportItems();
cbConfig.Enabled = cbConfig.Checked; foreach(CheckBox cb in checkBoxMap.Keys){
cbSession.Enabled = cbSession.Checked; cb.Enabled = cb.Checked;
cbPluginData.Enabled = cbPluginData.Checked; }
} }
// Export // Export
@@ -98,46 +111,49 @@ namespace TweetDuck.Core.Other.Settings.Dialogs{
Text = "Export Profile"; Text = "Export Profile";
btnContinue.Text = "Export Profile"; btnContinue.Text = "Export Profile";
Flags = ExportFileFlags.All & ~ExportFileFlags.Session; SelectedItems = ProfileManager.Items.UserConfig | ProfileManager.Items.PluginData;
} }
// Continue... // Continue...
panelDecision.Visible = false; panelDecision.Visible = false;
panelExport.Visible = true; panelSelection.Visible = true;
Height += panelSelection.Height-panelDecision.Height;
break; break;
case State.Reset: case State.Reset:
if (FormMessage.Warning("Reset TweetDuck Options", "This will reset the selected items. Are you sure you want to proceed?", FormMessage.Yes, FormMessage.No)){ if (FormMessage.Warning("Reset TweetDuck Options", "This will reset the selected items. Are you sure you want to proceed?", FormMessage.Yes, FormMessage.No)){
if (Flags.HasFlag(ExportFileFlags.UserConfig)){ Program.Config.ProgramRestartRequested += Config_ProgramRestartRequested;
Program.ResetConfig();
if (SelectedItems.HasFlag(ProfileManager.Items.UserConfig)){
Program.Config.User.Reset();
} }
if (Flags.HasFlag(ExportFileFlags.SystemConfig)){ if (SelectedItems.HasFlag(ProfileManager.Items.SystemConfig)){
try{ Program.Config.System.Reset();
File.Delete(Program.SystemConfigFilePath);
}catch(Exception ex){
Program.Reporter.HandleException("System Config Reset Error", "Could not delete system config.", true, ex);
}
} }
if (Flags.HasFlag(ExportFileFlags.PluginData)){ Program.Config.ProgramRestartRequested -= Config_ProgramRestartRequested;
if (SelectedItems.HasFlag(ProfileManager.Items.PluginData)){
Program.Config.Plugins.Reset();
try{ try{
File.Delete(Program.PluginConfigFilePath);
Directory.Delete(Program.PluginDataPath, true); Directory.Delete(Program.PluginDataPath, true);
}catch(Exception ex){ }catch(Exception ex){
Program.Reporter.HandleException("Plugin Data Reset Error", "Could not delete plugin data.", true, ex); Program.Reporter.HandleException("Profile Reset", "Could not delete plugin data.", true, ex);
} }
} }
if (Flags.HasFlag(ExportFileFlags.Session)){ if (SelectedItemsForceRestart){
Program.Restart(Arguments.ArgDeleteCookies); RestartProgram(SelectedItems.HasFlag(ProfileManager.Items.Session) ? new string[]{ Arguments.ArgDeleteCookies } : StringUtils.EmptyArray);
} }
else if (Flags.HasFlag(ExportFileFlags.SystemConfig)){ else if (requestedRestartFromConfig){
Program.Restart(); if (FormMessage.Information("Profile Reset", "The application must restart for some of the restored options to take place. Do you want to restart now?", FormMessage.Yes, FormMessage.No)){
RestartProgram();
} }
else{ }
ShouldReloadBrowser = true; ShouldReloadBrowser = true;
}
DialogResult = DialogResult.OK; DialogResult = DialogResult.OK;
Close(); Close();
@@ -146,24 +162,22 @@ namespace TweetDuck.Core.Other.Settings.Dialogs{
break; break;
case State.Import: case State.Import:
if (importManager.Import(Flags)){ if (importManager.Import(SelectedItems)){
Program.UserConfig.Reload(); Program.Config.ProgramRestartRequested += Config_ProgramRestartRequested;
Program.Config.ReloadAll();
Program.Config.ProgramRestartRequested -= Config_ProgramRestartRequested;
if (importManager.IsRestarting){ if (SelectedItemsForceRestart){
if (Flags.HasFlag(ExportFileFlags.Session)){ RestartProgram(SelectedItems.HasFlag(ProfileManager.Items.Session) ? new string[]{ Arguments.ArgImportCookies } : StringUtils.EmptyArray);
Program.Restart(Arguments.ArgImportCookies);
} }
else if (Flags.HasFlag(ExportFileFlags.SystemConfig)){ else if (requestedRestartFromConfig){
Program.Restart(); if (FormMessage.Information("Profile Import", "The application must restart for some of the imported options to take place. Do you want to restart now?", FormMessage.Yes, FormMessage.No)){
RestartProgram();
} }
} }
else{ }
ShouldReloadBrowser = true; ShouldReloadBrowser = true;
}
}
else{
Program.Reporter.HandleException("Profile Import Error", "An exception happened while importing TweetDuck profile.", true, importManager.LastException);
}
DialogResult = DialogResult.OK; DialogResult = DialogResult.OK;
Close(); Close();
@@ -186,14 +200,7 @@ namespace TweetDuck.Core.Other.Settings.Dialogs{
file = dialog.FileName; file = dialog.FileName;
} }
Program.UserConfig.Save(); new ProfileManager(file, plugins).Export(SelectedItems);
Program.SystemConfig.Save();
ExportManager manager = new ExportManager(file, plugins);
if (!manager.Export(Flags)){
Program.Reporter.HandleException("Profile Export Error", "An exception happened while exporting TweetDuck profile.", true, manager.LastException);
}
DialogResult = DialogResult.OK; DialogResult = DialogResult.OK;
Close(); Close();
@@ -206,16 +213,25 @@ namespace TweetDuck.Core.Other.Settings.Dialogs{
Close(); Close();
} }
private void SetFlag(ExportFileFlags flag, bool enable){ private void Config_ProgramRestartRequested(object sender, EventArgs e){
selectedFlags = enable ? selectedFlags | flag : selectedFlags & ~flag; requestedRestartFromConfig = true;
btnContinue.Enabled = selectedFlags != ExportFileFlags.None; }
private void SetFlag(ProfileManager.Items flag, bool enable){
_selectedItems = enable ? _selectedItems | flag : _selectedItems & ~flag;
btnContinue.Enabled = _selectedItems != ProfileManager.Items.None;
if (currentState == State.Import){ if (currentState == State.Import){
btnContinue.Text = selectedFlags.HasFlag(ExportFileFlags.Session) ? "Import && Restart" : "Import Profile"; btnContinue.Text = SelectedItemsForceRestart ? "Import && Restart" : "Import Profile";
} }
else if (currentState == State.Reset){ else if (currentState == State.Reset){
btnContinue.Text = selectedFlags.HasFlag(ExportFileFlags.Session) ? "Restore && Restart" : "Restore Defaults"; btnContinue.Text = SelectedItemsForceRestart ? "Restore && Restart" : "Restore Defaults";
} }
}
private void RestartProgram(params string[] extraArgs){
IsRestarting = true;
Program.Restart(extraArgs);
} }
} }
} }

View File

@@ -28,23 +28,24 @@
this.btnRestart = new System.Windows.Forms.Button(); this.btnRestart = new System.Windows.Forms.Button();
this.cbLogging = new System.Windows.Forms.CheckBox(); this.cbLogging = new System.Windows.Forms.CheckBox();
this.toolTip = new System.Windows.Forms.ToolTip(this.components); this.toolTip = new System.Windows.Forms.ToolTip(this.components);
this.cbDebugUpdates = new System.Windows.Forms.CheckBox();
this.comboLocale = new System.Windows.Forms.ComboBox();
this.tbDataFolder = new System.Windows.Forms.TextBox(); this.tbDataFolder = new System.Windows.Forms.TextBox();
this.tbShortcutTarget = new System.Windows.Forms.TextBox(); this.tbShortcutTarget = new System.Windows.Forms.TextBox();
this.labelLocale = new System.Windows.Forms.Label();
this.labelDataFolder = new System.Windows.Forms.Label(); this.labelDataFolder = new System.Windows.Forms.Label();
this.labelShortcutTarget = new System.Windows.Forms.Label(); this.labelShortcutTarget = new System.Windows.Forms.Label();
this.flowPanel = new System.Windows.Forms.FlowLayoutPanel();
this.flowPanel.SuspendLayout();
this.SuspendLayout(); this.SuspendLayout();
// //
// btnCancel // btnCancel
// //
this.btnCancel.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right))); this.btnCancel.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right)));
this.btnCancel.Location = new System.Drawing.Point(216, 217); this.btnCancel.AutoSize = true;
this.btnCancel.Font = new System.Drawing.Font("Segoe UI", 9F, System.Drawing.FontStyle.Regular);
this.btnCancel.Location = new System.Drawing.Point(215, 146);
this.btnCancel.Name = "btnCancel"; this.btnCancel.Name = "btnCancel";
this.btnCancel.Padding = new System.Windows.Forms.Padding(3, 0, 3, 0); this.btnCancel.Padding = new System.Windows.Forms.Padding(2, 0, 2, 0);
this.btnCancel.Size = new System.Drawing.Size(56, 23); this.btnCancel.Size = new System.Drawing.Size(57, 25);
this.btnCancel.TabIndex = 9; this.btnCancel.TabIndex = 2;
this.btnCancel.Text = "Cancel"; this.btnCancel.Text = "Cancel";
this.btnCancel.UseVisualStyleBackColor = true; this.btnCancel.UseVisualStyleBackColor = true;
this.btnCancel.Click += new System.EventHandler(this.btnCancel_Click); this.btnCancel.Click += new System.EventHandler(this.btnCancel_Click);
@@ -52,11 +53,13 @@
// btnRestart // btnRestart
// //
this.btnRestart.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right))); this.btnRestart.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right)));
this.btnRestart.Location = new System.Drawing.Point(153, 217); this.btnRestart.AutoSize = true;
this.btnRestart.Font = new System.Drawing.Font("Segoe UI", 9F, System.Drawing.FontStyle.Regular);
this.btnRestart.Location = new System.Drawing.Point(152, 146);
this.btnRestart.Name = "btnRestart"; this.btnRestart.Name = "btnRestart";
this.btnRestart.Padding = new System.Windows.Forms.Padding(3, 0, 3, 0); this.btnRestart.Padding = new System.Windows.Forms.Padding(2, 0, 2, 0);
this.btnRestart.Size = new System.Drawing.Size(57, 23); this.btnRestart.Size = new System.Drawing.Size(57, 25);
this.btnRestart.TabIndex = 8; this.btnRestart.TabIndex = 1;
this.btnRestart.Text = "Restart"; this.btnRestart.Text = "Restart";
this.btnRestart.UseVisualStyleBackColor = true; this.btnRestart.UseVisualStyleBackColor = true;
this.btnRestart.Click += new System.EventHandler(this.btnRestart_Click); this.btnRestart.Click += new System.EventHandler(this.btnRestart_Click);
@@ -64,102 +67,85 @@
// cbLogging // cbLogging
// //
this.cbLogging.AutoSize = true; this.cbLogging.AutoSize = true;
this.cbLogging.Location = new System.Drawing.Point(12, 12); this.cbLogging.Font = new System.Drawing.Font("Segoe UI", 9F, System.Drawing.FontStyle.Regular);
this.cbLogging.Location = new System.Drawing.Point(3, 3);
this.cbLogging.Margin = new System.Windows.Forms.Padding(3, 3, 3, 2);
this.cbLogging.Name = "cbLogging"; this.cbLogging.Name = "cbLogging";
this.cbLogging.Size = new System.Drawing.Size(64, 17); this.cbLogging.Size = new System.Drawing.Size(70, 19);
this.cbLogging.TabIndex = 0; this.cbLogging.TabIndex = 0;
this.cbLogging.Text = "Logging"; this.cbLogging.Text = "Logging";
this.toolTip.SetToolTip(this.cbLogging, "Logging JavaScript output into TD_Console.txt file in the data folder."); this.toolTip.SetToolTip(this.cbLogging, "Logs JavaScript output into TD_Console.txt file in the data folder.");
this.cbLogging.UseVisualStyleBackColor = true; this.cbLogging.UseVisualStyleBackColor = true;
// //
// cbDebugUpdates
//
this.cbDebugUpdates.AutoSize = true;
this.cbDebugUpdates.Location = new System.Drawing.Point(12, 35);
this.cbDebugUpdates.Name = "cbDebugUpdates";
this.cbDebugUpdates.Size = new System.Drawing.Size(127, 17);
this.cbDebugUpdates.TabIndex = 1;
this.cbDebugUpdates.Text = "Pre-Release Updates";
this.toolTip.SetToolTip(this.cbDebugUpdates, "Allows updating to pre-releases.");
this.cbDebugUpdates.UseVisualStyleBackColor = true;
//
// comboLocale
//
this.comboLocale.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left)
| System.Windows.Forms.AnchorStyles.Right)));
this.comboLocale.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList;
this.comboLocale.FormattingEnabled = true;
this.comboLocale.Location = new System.Drawing.Point(15, 83);
this.comboLocale.Name = "comboLocale";
this.comboLocale.Size = new System.Drawing.Size(257, 21);
this.comboLocale.TabIndex = 3;
this.toolTip.SetToolTip(this.comboLocale, "Language used for spell checking.");
//
// tbDataFolder // tbDataFolder
// //
this.tbDataFolder.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) this.tbDataFolder.Font = new System.Drawing.Font("Segoe UI", 9F, System.Drawing.FontStyle.Regular);
| System.Windows.Forms.AnchorStyles.Right))); this.tbDataFolder.Location = new System.Drawing.Point(3, 54);
this.tbDataFolder.Location = new System.Drawing.Point(15, 135);
this.tbDataFolder.Name = "tbDataFolder"; this.tbDataFolder.Name = "tbDataFolder";
this.tbDataFolder.Size = new System.Drawing.Size(257, 20); this.tbDataFolder.Size = new System.Drawing.Size(260, 23);
this.tbDataFolder.TabIndex = 5; this.tbDataFolder.TabIndex = 2;
this.toolTip.SetToolTip(this.tbDataFolder, "Path to the data folder. Must be either an absolute path,\r\nor a simple folder name that will be created in LocalAppData."); this.toolTip.SetToolTip(this.tbDataFolder, "Path to the data folder. Must be either an absolute path,\r\nor a simple folder nam" +
"e that will be created in LocalAppData.");
// //
// tbShortcutTarget // tbShortcutTarget
// //
this.tbShortcutTarget.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) this.tbShortcutTarget.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left)
| System.Windows.Forms.AnchorStyles.Right))); | System.Windows.Forms.AnchorStyles.Right)));
this.tbShortcutTarget.Cursor = System.Windows.Forms.Cursors.Hand; this.tbShortcutTarget.Cursor = System.Windows.Forms.Cursors.Hand;
this.tbShortcutTarget.Location = new System.Drawing.Point(15, 186); this.tbShortcutTarget.Font = new System.Drawing.Font("Segoe UI", 9F, System.Drawing.FontStyle.Regular);
this.tbShortcutTarget.Location = new System.Drawing.Point(3, 110);
this.tbShortcutTarget.Name = "tbShortcutTarget"; this.tbShortcutTarget.Name = "tbShortcutTarget";
this.tbShortcutTarget.ReadOnly = true; this.tbShortcutTarget.ReadOnly = true;
this.tbShortcutTarget.Size = new System.Drawing.Size(257, 20); this.tbShortcutTarget.Size = new System.Drawing.Size(260, 23);
this.tbShortcutTarget.TabIndex = 7; this.tbShortcutTarget.TabIndex = 4;
this.tbShortcutTarget.Click += new System.EventHandler(this.tbShortcutTarget_Click); this.tbShortcutTarget.Click += new System.EventHandler(this.tbShortcutTarget_Click);
// //
// labelLocale
//
this.labelLocale.AutoSize = true;
this.labelLocale.Location = new System.Drawing.Point(12, 67);
this.labelLocale.Margin = new System.Windows.Forms.Padding(3, 12, 3, 0);
this.labelLocale.Name = "labelLocale";
this.labelLocale.Size = new System.Drawing.Size(39, 13);
this.labelLocale.TabIndex = 2;
this.labelLocale.Text = "Locale";
//
// labelDataFolder // labelDataFolder
// //
this.labelDataFolder.AutoSize = true; this.labelDataFolder.AutoSize = true;
this.labelDataFolder.Location = new System.Drawing.Point(12, 119); this.labelDataFolder.Font = new System.Drawing.Font("Segoe UI", 9F, System.Drawing.FontStyle.Regular);
this.labelDataFolder.Location = new System.Drawing.Point(3, 36);
this.labelDataFolder.Margin = new System.Windows.Forms.Padding(3, 12, 3, 0); this.labelDataFolder.Margin = new System.Windows.Forms.Padding(3, 12, 3, 0);
this.labelDataFolder.Name = "labelDataFolder"; this.labelDataFolder.Name = "labelDataFolder";
this.labelDataFolder.Size = new System.Drawing.Size(62, 13); this.labelDataFolder.Size = new System.Drawing.Size(67, 15);
this.labelDataFolder.TabIndex = 4; this.labelDataFolder.TabIndex = 1;
this.labelDataFolder.Text = "Data Folder"; this.labelDataFolder.Text = "Data Folder";
// //
// labelShortcutTarget // labelShortcutTarget
// //
this.labelShortcutTarget.AutoSize = true; this.labelShortcutTarget.AutoSize = true;
this.labelShortcutTarget.Location = new System.Drawing.Point(12, 170); this.labelShortcutTarget.Font = new System.Drawing.Font("Segoe UI", 9F, System.Drawing.FontStyle.Regular);
this.labelShortcutTarget.Location = new System.Drawing.Point(3, 92);
this.labelShortcutTarget.Margin = new System.Windows.Forms.Padding(3, 12, 3, 0); this.labelShortcutTarget.Margin = new System.Windows.Forms.Padding(3, 12, 3, 0);
this.labelShortcutTarget.Name = "labelShortcutTarget"; this.labelShortcutTarget.Name = "labelShortcutTarget";
this.labelShortcutTarget.Size = new System.Drawing.Size(155, 13); this.labelShortcutTarget.Size = new System.Drawing.Size(171, 15);
this.labelShortcutTarget.TabIndex = 6; this.labelShortcutTarget.TabIndex = 3;
this.labelShortcutTarget.Text = "Shortcut Target (click to select)"; this.labelShortcutTarget.Text = "Shortcut Target (click to select)";
// //
// flowPanel
//
this.flowPanel.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.flowPanel.Controls.Add(this.cbLogging);
this.flowPanel.Controls.Add(this.labelDataFolder);
this.flowPanel.Controls.Add(this.tbDataFolder);
this.flowPanel.Controls.Add(this.labelShortcutTarget);
this.flowPanel.Controls.Add(this.tbShortcutTarget);
this.flowPanel.FlowDirection = System.Windows.Forms.FlowDirection.TopDown;
this.flowPanel.Location = new System.Drawing.Point(9, 9);
this.flowPanel.Margin = new System.Windows.Forms.Padding(0);
this.flowPanel.Name = "flowPanel";
this.flowPanel.Size = new System.Drawing.Size(266, 136);
this.flowPanel.TabIndex = 0;
this.flowPanel.WrapContents = false;
//
// DialogSettingsRestart // DialogSettingsRestart
// //
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
this.ClientSize = new System.Drawing.Size(284, 252); this.ClientSize = new System.Drawing.Size(284, 183);
this.Controls.Add(this.tbShortcutTarget); this.Controls.Add(this.flowPanel);
this.Controls.Add(this.labelShortcutTarget);
this.Controls.Add(this.tbDataFolder);
this.Controls.Add(this.labelDataFolder);
this.Controls.Add(this.comboLocale);
this.Controls.Add(this.labelLocale);
this.Controls.Add(this.cbDebugUpdates);
this.Controls.Add(this.cbLogging);
this.Controls.Add(this.btnRestart); this.Controls.Add(this.btnRestart);
this.Controls.Add(this.btnCancel); this.Controls.Add(this.btnCancel);
this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedSingle; this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedSingle;
@@ -168,6 +154,8 @@
this.Name = "DialogSettingsRestart"; this.Name = "DialogSettingsRestart";
this.ShowIcon = false; this.ShowIcon = false;
this.StartPosition = System.Windows.Forms.FormStartPosition.CenterParent; this.StartPosition = System.Windows.Forms.FormStartPosition.CenterParent;
this.flowPanel.ResumeLayout(false);
this.flowPanel.PerformLayout();
this.ResumeLayout(false); this.ResumeLayout(false);
this.PerformLayout(); this.PerformLayout();
@@ -179,12 +167,10 @@
private System.Windows.Forms.Button btnRestart; private System.Windows.Forms.Button btnRestart;
private System.Windows.Forms.CheckBox cbLogging; private System.Windows.Forms.CheckBox cbLogging;
private System.Windows.Forms.ToolTip toolTip; private System.Windows.Forms.ToolTip toolTip;
private System.Windows.Forms.CheckBox cbDebugUpdates;
private System.Windows.Forms.Label labelLocale;
private System.Windows.Forms.ComboBox comboLocale;
private System.Windows.Forms.Label labelDataFolder; private System.Windows.Forms.Label labelDataFolder;
private System.Windows.Forms.TextBox tbDataFolder; private System.Windows.Forms.TextBox tbDataFolder;
private System.Windows.Forms.TextBox tbShortcutTarget; private System.Windows.Forms.TextBox tbShortcutTarget;
private System.Windows.Forms.Label labelShortcutTarget; private System.Windows.Forms.Label labelShortcutTarget;
private System.Windows.Forms.FlowLayoutPanel flowPanel;
} }
} }

View File

@@ -1,33 +1,17 @@
using System; using System;
using System.IO;
using System.Linq;
using System.Windows.Forms; using System.Windows.Forms;
using TweetDuck.Configuration; using TweetDuck.Configuration;
using TweetDuck.Data; using TweetDuck.Data;
namespace TweetDuck.Core.Other.Settings.Dialogs{ namespace TweetDuck.Core.Other.Settings.Dialogs{
sealed partial class DialogSettingsRestart : Form{ sealed partial class DialogSettingsRestart : Form{
private const string DefaultLocale = "en-US";
public CommandLineArgs Args { get; private set; } public CommandLineArgs Args { get; private set; }
public DialogSettingsRestart(CommandLineArgs currentArgs){ public DialogSettingsRestart(CommandLineArgs currentArgs){
InitializeComponent(); InitializeComponent();
try{
object[] locales = Directory.EnumerateFiles(Path.Combine(Program.ProgramPath, "locales"), "*.pak", SearchOption.TopDirectoryOnly).Select(Path.GetFileNameWithoutExtension).ToArray<object>();
comboLocale.Items.AddRange(locales);
}catch{
comboLocale.Items.Add(DefaultLocale);
}
cbLogging.Checked = currentArgs.HasFlag(Arguments.ArgLogging); cbLogging.Checked = currentArgs.HasFlag(Arguments.ArgLogging);
cbDebugUpdates.Checked = currentArgs.HasFlag(Arguments.ArgDebugUpdates);
comboLocale.SelectedItem = currentArgs.GetValue(Arguments.ArgLocale, DefaultLocale);
cbLogging.CheckedChanged += control_Change; cbLogging.CheckedChanged += control_Change;
cbDebugUpdates.CheckedChanged += control_Change;
comboLocale.SelectedValueChanged += control_Change;
if (Program.IsPortable){ if (Program.IsPortable){
tbDataFolder.Text = "Not available in portable version"; tbDataFolder.Text = "Not available in portable version";
@@ -50,16 +34,6 @@ namespace TweetDuck.Core.Other.Settings.Dialogs{
Args.AddFlag(Arguments.ArgLogging); Args.AddFlag(Arguments.ArgLogging);
} }
if (cbDebugUpdates.Checked){
Args.AddFlag(Arguments.ArgDebugUpdates);
}
string locale = comboLocale.SelectedItem as string;
if (!string.IsNullOrWhiteSpace(locale) && locale != DefaultLocale){
Args.SetValue(Arguments.ArgLocale, locale);
}
if (!string.IsNullOrWhiteSpace(tbDataFolder.Text) && tbDataFolder.Enabled){ if (!string.IsNullOrWhiteSpace(tbDataFolder.Text) && tbDataFolder.Enabled){
Args.SetValue(Arguments.ArgDataFolder, tbDataFolder.Text); Args.SetValue(Arguments.ArgDataFolder, tbDataFolder.Text);
} }

View File

@@ -0,0 +1,109 @@
namespace TweetDuck.Core.Other.Settings.Dialogs {
partial class DialogSettingsSearchEngine {
/// <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.textBoxUrl = new System.Windows.Forms.TextBox();
this.btnCancel = new System.Windows.Forms.Button();
this.btnApply = new System.Windows.Forms.Button();
this.labelInfo = new System.Windows.Forms.Label();
this.SuspendLayout();
//
// textBoxUrl
//
this.textBoxUrl.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.textBoxUrl.Font = new System.Drawing.Font("Segoe UI", 9F, System.Drawing.FontStyle.Regular);
this.textBoxUrl.Location = new System.Drawing.Point(12, 30);
this.textBoxUrl.Name = "textBoxUrl";
this.textBoxUrl.Size = new System.Drawing.Size(310, 23);
this.textBoxUrl.TabIndex = 1;
//
// btnCancel
//
this.btnCancel.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right)));
this.btnCancel.AutoSize = true;
this.btnCancel.Font = new System.Drawing.Font("Segoe UI", 9F, System.Drawing.FontStyle.Regular);
this.btnCancel.Location = new System.Drawing.Point(207, 59);
this.btnCancel.Name = "btnCancel";
this.btnCancel.Padding = new System.Windows.Forms.Padding(2, 0, 2, 0);
this.btnCancel.Size = new System.Drawing.Size(57, 25);
this.btnCancel.TabIndex = 3;
this.btnCancel.Text = "Cancel";
this.btnCancel.UseVisualStyleBackColor = true;
this.btnCancel.Click += new System.EventHandler(this.btnCancel_Click);
//
// btnApply
//
this.btnApply.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right)));
this.btnApply.AutoSize = true;
this.btnApply.Font = new System.Drawing.Font("Segoe UI", 9F, System.Drawing.FontStyle.Regular);
this.btnApply.Location = new System.Drawing.Point(270, 59);
this.btnApply.Name = "btnApply";
this.btnApply.Padding = new System.Windows.Forms.Padding(2, 0, 2, 0);
this.btnApply.Size = new System.Drawing.Size(52, 25);
this.btnApply.TabIndex = 2;
this.btnApply.Text = "Apply";
this.btnApply.UseVisualStyleBackColor = true;
this.btnApply.Click += new System.EventHandler(this.btnApply_Click);
//
// labelInfo
//
this.labelInfo.AutoSize = true;
this.labelInfo.Font = new System.Drawing.Font("Segoe UI", 9F, System.Drawing.FontStyle.Regular);
this.labelInfo.Location = new System.Drawing.Point(12, 9);
this.labelInfo.Margin = new System.Windows.Forms.Padding(3, 0, 3, 3);
this.labelInfo.Name = "labelInfo";
this.labelInfo.Size = new System.Drawing.Size(287, 15);
this.labelInfo.TabIndex = 0;
this.labelInfo.Text = "The search query will be added at the end of the URL.";
//
// DialogSettingsSearchEngine
//
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
this.ClientSize = new System.Drawing.Size(334, 96);
this.Controls.Add(this.labelInfo);
this.Controls.Add(this.btnApply);
this.Controls.Add(this.btnCancel);
this.Controls.Add(this.textBoxUrl);
this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedSingle;
this.MaximizeBox = false;
this.MinimizeBox = false;
this.Name = "DialogSettingsSearchEngine";
this.ShowIcon = false;
this.StartPosition = System.Windows.Forms.FormStartPosition.CenterParent;
this.ResumeLayout(false);
this.PerformLayout();
}
#endregion
private System.Windows.Forms.TextBox textBoxUrl;
private System.Windows.Forms.Button btnCancel;
private System.Windows.Forms.Button btnApply;
private System.Windows.Forms.Label labelInfo;
}
}

View File

@@ -0,0 +1,27 @@
using System;
using System.Windows.Forms;
namespace TweetDuck.Core.Other.Settings.Dialogs{
sealed partial class DialogSettingsSearchEngine : Form{
public string Url => textBoxUrl.Text;
public DialogSettingsSearchEngine(){
InitializeComponent();
Text = Program.BrandName+" Options - Custom Search Engine";
textBoxUrl.Text = Program.Config.User.SearchEngineUrl ?? "";
textBoxUrl.Select(textBoxUrl.Text.Length, 0);
}
private void btnApply_Click(object sender, EventArgs e){
DialogResult = DialogResult.OK;
Close();
}
private void btnCancel_Click(object sender, EventArgs e){
DialogResult = DialogResult.Cancel;
Close();
}
}
}

View File

@@ -1,13 +0,0 @@
using System;
namespace TweetDuck.Core.Other.Settings.Export{
[Flags]
enum ExportFileFlags{
None = 0,
UserConfig = 1,
SystemConfig = 2, // TODO implement later
Session = 4,
PluginData = 8,
All = UserConfig|SystemConfig|Session|PluginData
}
}

View File

@@ -25,7 +25,6 @@
private void InitializeComponent() { private void InitializeComponent() {
this.components = new System.ComponentModel.Container(); this.components = new System.ComponentModel.Container();
this.btnClearCache = new System.Windows.Forms.Button(); this.btnClearCache = new System.Windows.Forms.Button();
this.checkHardwareAcceleration = new System.Windows.Forms.CheckBox();
this.toolTip = new System.Windows.Forms.ToolTip(this.components); this.toolTip = new System.Windows.Forms.ToolTip(this.components);
this.btnEditCefArgs = new System.Windows.Forms.Button(); this.btnEditCefArgs = new System.Windows.Forms.Button();
this.btnEditCSS = new System.Windows.Forms.Button(); this.btnEditCSS = new System.Windows.Forms.Button();
@@ -33,243 +32,242 @@
this.btnRestart = new System.Windows.Forms.Button(); this.btnRestart = new System.Windows.Forms.Button();
this.btnOpenAppFolder = new System.Windows.Forms.Button(); this.btnOpenAppFolder = new System.Windows.Forms.Button();
this.btnOpenDataFolder = new System.Windows.Forms.Button(); this.btnOpenDataFolder = new System.Windows.Forms.Button();
this.numMemoryThreshold = new TweetDuck.Core.Controls.NumericUpDownEx(); this.numClearCacheThreshold = new TweetDuck.Core.Controls.NumericUpDownEx();
this.checkBrowserGCReload = new System.Windows.Forms.CheckBox(); this.checkClearCacheAuto = new System.Windows.Forms.CheckBox();
this.labelApp = new System.Windows.Forms.Label(); this.labelApp = new System.Windows.Forms.Label();
this.panelApp = new System.Windows.Forms.Panel(); this.panelAppButtons = new System.Windows.Forms.Panel();
this.labelPerformance = new System.Windows.Forms.Label(); this.labelCache = new System.Windows.Forms.Label();
this.panelPerformance = new System.Windows.Forms.Panel(); this.panelClearCacheAuto = new System.Windows.Forms.Panel();
this.labelMemoryUsage = new System.Windows.Forms.Label();
this.panelConfiguration = new System.Windows.Forms.Panel(); this.panelConfiguration = new System.Windows.Forms.Panel();
this.labelConfiguration = new System.Windows.Forms.Label(); this.labelConfiguration = new System.Windows.Forms.Label();
((System.ComponentModel.ISupportInitialize)(this.numMemoryThreshold)).BeginInit(); this.flowPanel = new System.Windows.Forms.FlowLayoutPanel();
this.panelApp.SuspendLayout(); ((System.ComponentModel.ISupportInitialize)(this.numClearCacheThreshold)).BeginInit();
this.panelPerformance.SuspendLayout(); this.panelAppButtons.SuspendLayout();
this.panelClearCacheAuto.SuspendLayout();
this.panelConfiguration.SuspendLayout(); this.panelConfiguration.SuspendLayout();
this.flowPanel.SuspendLayout();
this.SuspendLayout(); this.SuspendLayout();
// //
// btnClearCache // btnClearCache
// //
this.btnClearCache.Location = new System.Drawing.Point(5, 28); this.btnClearCache.Font = new System.Drawing.Font("Segoe UI", 9F);
this.btnClearCache.Location = new System.Drawing.Point(5, 135);
this.btnClearCache.Margin = new System.Windows.Forms.Padding(5, 3, 3, 3); this.btnClearCache.Margin = new System.Windows.Forms.Padding(5, 3, 3, 3);
this.btnClearCache.Name = "btnClearCache"; this.btnClearCache.Name = "btnClearCache";
this.btnClearCache.Size = new System.Drawing.Size(144, 23); this.btnClearCache.Size = new System.Drawing.Size(143, 25);
this.btnClearCache.TabIndex = 1; this.btnClearCache.TabIndex = 3;
this.btnClearCache.Text = "Clear Cache (calculating)"; this.btnClearCache.Text = "Clear Cache (...)";
this.toolTip.SetToolTip(this.btnClearCache, "Clearing cache will free up space taken by downloaded images and other resources.");
this.btnClearCache.UseVisualStyleBackColor = true; this.btnClearCache.UseVisualStyleBackColor = true;
// //
// checkHardwareAcceleration
//
this.checkHardwareAcceleration.AutoSize = true;
this.checkHardwareAcceleration.Location = new System.Drawing.Point(6, 5);
this.checkHardwareAcceleration.Margin = new System.Windows.Forms.Padding(6, 5, 3, 3);
this.checkHardwareAcceleration.Name = "checkHardwareAcceleration";
this.checkHardwareAcceleration.Size = new System.Drawing.Size(134, 17);
this.checkHardwareAcceleration.TabIndex = 0;
this.checkHardwareAcceleration.Text = "Hardware Acceleration";
this.toolTip.SetToolTip(this.checkHardwareAcceleration, "Uses graphics card to improve performance. Disable if you experience\r\nvisual glitches. This option will not be exported in a profile.");
this.checkHardwareAcceleration.UseVisualStyleBackColor = true;
//
// btnEditCefArgs // btnEditCefArgs
// //
this.btnEditCefArgs.Font = new System.Drawing.Font("Segoe UI", 9F);
this.btnEditCefArgs.Location = new System.Drawing.Point(5, 3); this.btnEditCefArgs.Location = new System.Drawing.Point(5, 3);
this.btnEditCefArgs.Margin = new System.Windows.Forms.Padding(5, 3, 3, 3); this.btnEditCefArgs.Margin = new System.Windows.Forms.Padding(5, 3, 3, 3);
this.btnEditCefArgs.Name = "btnEditCefArgs"; this.btnEditCefArgs.Name = "btnEditCefArgs";
this.btnEditCefArgs.Size = new System.Drawing.Size(144, 23); this.btnEditCefArgs.Size = new System.Drawing.Size(143, 25);
this.btnEditCefArgs.TabIndex = 0; this.btnEditCefArgs.TabIndex = 0;
this.btnEditCefArgs.Text = "Edit CEF Arguments"; this.btnEditCefArgs.Text = "Edit CEF Arguments";
this.toolTip.SetToolTip(this.btnEditCefArgs, "Set custom command line arguments for Chromium Embedded Framework.");
this.btnEditCefArgs.UseVisualStyleBackColor = true; this.btnEditCefArgs.UseVisualStyleBackColor = true;
// //
// btnEditCSS // btnEditCSS
// //
this.btnEditCSS.Location = new System.Drawing.Point(155, 3); this.btnEditCSS.Font = new System.Drawing.Font("Segoe UI", 9F);
this.btnEditCSS.Location = new System.Drawing.Point(154, 3);
this.btnEditCSS.Name = "btnEditCSS"; this.btnEditCSS.Name = "btnEditCSS";
this.btnEditCSS.Size = new System.Drawing.Size(144, 23); this.btnEditCSS.Size = new System.Drawing.Size(143, 25);
this.btnEditCSS.TabIndex = 1; this.btnEditCSS.TabIndex = 1;
this.btnEditCSS.Text = "Edit CSS"; this.btnEditCSS.Text = "Edit CSS";
this.toolTip.SetToolTip(this.btnEditCSS, "Set custom CSS for browser and notification windows.");
this.btnEditCSS.UseVisualStyleBackColor = true; this.btnEditCSS.UseVisualStyleBackColor = true;
// //
// btnRestartArgs // btnRestartArgs
// //
this.btnRestartArgs.Location = new System.Drawing.Point(155, 32); this.btnRestartArgs.Font = new System.Drawing.Font("Segoe UI", 9F);
this.btnRestartArgs.Location = new System.Drawing.Point(154, 32);
this.btnRestartArgs.Name = "btnRestartArgs"; this.btnRestartArgs.Name = "btnRestartArgs";
this.btnRestartArgs.Size = new System.Drawing.Size(144, 23); this.btnRestartArgs.Size = new System.Drawing.Size(143, 25);
this.btnRestartArgs.TabIndex = 3; this.btnRestartArgs.TabIndex = 3;
this.btnRestartArgs.Text = "Restart with Arguments"; this.btnRestartArgs.Text = "Restart with Arguments";
this.toolTip.SetToolTip(this.btnRestartArgs, "Restarts the program with customizable\r\ncommand line arguments.");
this.btnRestartArgs.UseVisualStyleBackColor = true; this.btnRestartArgs.UseVisualStyleBackColor = true;
// //
// btnRestart // btnRestart
// //
this.btnRestart.Location = new System.Drawing.Point(155, 3); this.btnRestart.Font = new System.Drawing.Font("Segoe UI", 9F);
this.btnRestart.Location = new System.Drawing.Point(154, 3);
this.btnRestart.Name = "btnRestart"; this.btnRestart.Name = "btnRestart";
this.btnRestart.Size = new System.Drawing.Size(144, 23); this.btnRestart.Size = new System.Drawing.Size(143, 25);
this.btnRestart.TabIndex = 2; this.btnRestart.TabIndex = 2;
this.btnRestart.Text = "Restart the Program"; this.btnRestart.Text = "Restart the Program";
this.toolTip.SetToolTip(this.btnRestart, "Restarts the program using the same command\r\nline arguments that were used at launch.");
this.btnRestart.UseVisualStyleBackColor = true; this.btnRestart.UseVisualStyleBackColor = true;
// //
// btnOpenAppFolder // btnOpenAppFolder
// //
this.btnOpenAppFolder.Font = new System.Drawing.Font("Segoe UI", 9F);
this.btnOpenAppFolder.Location = new System.Drawing.Point(5, 3); this.btnOpenAppFolder.Location = new System.Drawing.Point(5, 3);
this.btnOpenAppFolder.Margin = new System.Windows.Forms.Padding(5, 3, 3, 3); this.btnOpenAppFolder.Margin = new System.Windows.Forms.Padding(5, 3, 3, 3);
this.btnOpenAppFolder.Name = "btnOpenAppFolder"; this.btnOpenAppFolder.Name = "btnOpenAppFolder";
this.btnOpenAppFolder.Size = new System.Drawing.Size(144, 23); this.btnOpenAppFolder.Size = new System.Drawing.Size(143, 25);
this.btnOpenAppFolder.TabIndex = 0; this.btnOpenAppFolder.TabIndex = 0;
this.btnOpenAppFolder.Text = "Open Program Folder"; this.btnOpenAppFolder.Text = "Open Program Folder";
this.toolTip.SetToolTip(this.btnOpenAppFolder, "Opens the folder where the app is located.");
this.btnOpenAppFolder.UseVisualStyleBackColor = true; this.btnOpenAppFolder.UseVisualStyleBackColor = true;
// //
// btnOpenDataFolder // btnOpenDataFolder
// //
this.btnOpenDataFolder.Font = new System.Drawing.Font("Segoe UI", 9F);
this.btnOpenDataFolder.Location = new System.Drawing.Point(5, 32); this.btnOpenDataFolder.Location = new System.Drawing.Point(5, 32);
this.btnOpenDataFolder.Margin = new System.Windows.Forms.Padding(5, 3, 3, 3); this.btnOpenDataFolder.Margin = new System.Windows.Forms.Padding(5, 3, 3, 3);
this.btnOpenDataFolder.Name = "btnOpenDataFolder"; this.btnOpenDataFolder.Name = "btnOpenDataFolder";
this.btnOpenDataFolder.Size = new System.Drawing.Size(144, 23); this.btnOpenDataFolder.Size = new System.Drawing.Size(143, 25);
this.btnOpenDataFolder.TabIndex = 1; this.btnOpenDataFolder.TabIndex = 1;
this.btnOpenDataFolder.Text = "Open Data Folder"; this.btnOpenDataFolder.Text = "Open Data Folder";
this.toolTip.SetToolTip(this.btnOpenDataFolder, "Opens the folder where your profile data is located.");
this.btnOpenDataFolder.UseVisualStyleBackColor = true; this.btnOpenDataFolder.UseVisualStyleBackColor = true;
// //
// numMemoryThreshold // numClearCacheThreshold
// //
this.numMemoryThreshold.Increment = new decimal(new int[] { this.numClearCacheThreshold.Font = new System.Drawing.Font("Segoe UI", 9F);
this.numClearCacheThreshold.Increment = new decimal(new int[] {
50, 50,
0, 0,
0, 0,
0}); 0});
this.numMemoryThreshold.Location = new System.Drawing.Point(202, 82); this.numClearCacheThreshold.Location = new System.Drawing.Point(210, 5);
this.numMemoryThreshold.Maximum = 2000; this.numClearCacheThreshold.Maximum = new decimal(new int[] {
this.numMemoryThreshold.Minimum = 200; 1000,
this.numMemoryThreshold.Name = "numMemoryThreshold"; 0,
this.numMemoryThreshold.Size = new System.Drawing.Size(97, 20); 0,
this.numMemoryThreshold.TabIndex = 4; 0});
this.numMemoryThreshold.TextSuffix = " MB"; this.numClearCacheThreshold.Minimum = new decimal(new int[] {
this.toolTip.SetToolTip(this.numMemoryThreshold, "Minimum amount of memory usage by the browser process to trigger the cleanup.\r\nThis is not a limit, the usage is allowed to exceed this value."); 100,
this.numMemoryThreshold.Value = 400; 0,
0,
0});
this.numClearCacheThreshold.Name = "numClearCacheThreshold";
this.numClearCacheThreshold.Size = new System.Drawing.Size(89, 23);
this.numClearCacheThreshold.TabIndex = 1;
this.numClearCacheThreshold.TextAlign = System.Windows.Forms.HorizontalAlignment.Right;
this.numClearCacheThreshold.TextSuffix = " MB";
this.numClearCacheThreshold.Value = new decimal(new int[] {
250,
0,
0,
0});
// //
// checkBrowserGCReload // checkClearCacheAuto
// //
this.checkBrowserGCReload.AutoSize = true; this.checkClearCacheAuto.AutoSize = true;
this.checkBrowserGCReload.Location = new System.Drawing.Point(6, 84); this.checkClearCacheAuto.Font = new System.Drawing.Font("Segoe UI", 9F);
this.checkBrowserGCReload.Margin = new System.Windows.Forms.Padding(6, 5, 3, 3); this.checkClearCacheAuto.Location = new System.Drawing.Point(6, 6);
this.checkBrowserGCReload.Name = "checkBrowserGCReload"; this.checkClearCacheAuto.Margin = new System.Windows.Forms.Padding(6, 6, 0, 2);
this.checkBrowserGCReload.Size = new System.Drawing.Size(190, 17); this.checkClearCacheAuto.Name = "checkClearCacheAuto";
this.checkBrowserGCReload.TabIndex = 3; this.checkClearCacheAuto.Size = new System.Drawing.Size(201, 19);
this.checkBrowserGCReload.Text = "Enable Browser Memory Threshold"; this.checkClearCacheAuto.TabIndex = 0;
this.toolTip.SetToolTip(this.checkBrowserGCReload, "Automatically reloads TweetDeck to save memory. This option only works if\r\nthe browser is in a \'default state\', i.e. all modals and drawers are closed, and\r\nall columns are scrolled to top. This option will not be exported in a profile."); this.checkClearCacheAuto.Text = "Clear Automatically When Above";
this.checkBrowserGCReload.UseVisualStyleBackColor = true; this.checkClearCacheAuto.UseVisualStyleBackColor = true;
// //
// labelApp // labelApp
// //
this.labelApp.AutoSize = true; this.labelApp.AutoSize = true;
this.labelApp.Font = new System.Drawing.Font("Microsoft Sans Serif", 12F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(238))); this.labelApp.Font = new System.Drawing.Font("Segoe UI Semibold", 10.5F, System.Drawing.FontStyle.Bold);
this.labelApp.Location = new System.Drawing.Point(6, 8); this.labelApp.Location = new System.Drawing.Point(0, 0);
this.labelApp.Margin = new System.Windows.Forms.Padding(0, 2, 0, 0); this.labelApp.Margin = new System.Windows.Forms.Padding(0, 0, 0, 1);
this.labelApp.Name = "labelApp"; this.labelApp.Name = "labelApp";
this.labelApp.Size = new System.Drawing.Size(38, 20); this.labelApp.Size = new System.Drawing.Size(97, 19);
this.labelApp.TabIndex = 0; this.labelApp.TabIndex = 0;
this.labelApp.Text = "App"; this.labelApp.Text = "APPLICATION";
// //
// panelApp // panelAppButtons
// //
this.panelApp.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) this.panelAppButtons.Controls.Add(this.btnOpenDataFolder);
| System.Windows.Forms.AnchorStyles.Right))); this.panelAppButtons.Controls.Add(this.btnOpenAppFolder);
this.panelApp.Controls.Add(this.btnOpenDataFolder); this.panelAppButtons.Controls.Add(this.btnRestart);
this.panelApp.Controls.Add(this.btnOpenAppFolder); this.panelAppButtons.Controls.Add(this.btnRestartArgs);
this.panelApp.Controls.Add(this.btnRestart); this.panelAppButtons.Location = new System.Drawing.Point(0, 20);
this.panelApp.Controls.Add(this.btnRestartArgs); this.panelAppButtons.Margin = new System.Windows.Forms.Padding(0);
this.panelApp.Location = new System.Drawing.Point(9, 31); this.panelAppButtons.Name = "panelAppButtons";
this.panelApp.Name = "panelApp"; this.panelAppButtons.Size = new System.Drawing.Size(300, 62);
this.panelApp.Size = new System.Drawing.Size(322, 59); this.panelAppButtons.TabIndex = 1;
this.panelApp.TabIndex = 1;
// //
// labelPerformance // labelCache
// //
this.labelPerformance.AutoSize = true; this.labelCache.AutoSize = true;
this.labelPerformance.Font = new System.Drawing.Font("Microsoft Sans Serif", 12F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(238))); this.labelCache.Font = new System.Drawing.Font("Segoe UI Semibold", 10.5F, System.Drawing.FontStyle.Bold);
this.labelPerformance.Location = new System.Drawing.Point(6, 114); this.labelCache.Location = new System.Drawing.Point(0, 112);
this.labelPerformance.Margin = new System.Windows.Forms.Padding(0, 21, 0, 0); this.labelCache.Margin = new System.Windows.Forms.Padding(0, 30, 0, 1);
this.labelPerformance.Name = "labelPerformance"; this.labelCache.Name = "labelCache";
this.labelPerformance.Size = new System.Drawing.Size(100, 20); this.labelCache.Size = new System.Drawing.Size(123, 19);
this.labelPerformance.TabIndex = 2; this.labelCache.TabIndex = 2;
this.labelPerformance.Text = "Performance"; this.labelCache.Text = "BROWSER CACHE";
// //
// panelPerformance // panelClearCacheAuto
// //
this.panelPerformance.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) this.panelClearCacheAuto.Controls.Add(this.checkClearCacheAuto);
| System.Windows.Forms.AnchorStyles.Right))); this.panelClearCacheAuto.Controls.Add(this.numClearCacheThreshold);
this.panelPerformance.Controls.Add(this.checkBrowserGCReload); this.panelClearCacheAuto.Location = new System.Drawing.Point(0, 163);
this.panelPerformance.Controls.Add(this.numMemoryThreshold); this.panelClearCacheAuto.Margin = new System.Windows.Forms.Padding(0);
this.panelPerformance.Controls.Add(this.labelMemoryUsage); this.panelClearCacheAuto.Name = "panelClearCacheAuto";
this.panelPerformance.Controls.Add(this.checkHardwareAcceleration); this.panelClearCacheAuto.Size = new System.Drawing.Size(300, 28);
this.panelPerformance.Controls.Add(this.btnClearCache); this.panelClearCacheAuto.TabIndex = 4;
this.panelPerformance.Location = new System.Drawing.Point(9, 137);
this.panelPerformance.Name = "panelPerformance";
this.panelPerformance.Size = new System.Drawing.Size(322, 105);
this.panelPerformance.TabIndex = 3;
//
// labelMemoryUsage
//
this.labelMemoryUsage.AutoSize = true;
this.labelMemoryUsage.Location = new System.Drawing.Point(3, 66);
this.labelMemoryUsage.Margin = new System.Windows.Forms.Padding(3, 12, 3, 0);
this.labelMemoryUsage.Name = "labelMemoryUsage";
this.labelMemoryUsage.Size = new System.Drawing.Size(78, 13);
this.labelMemoryUsage.TabIndex = 2;
this.labelMemoryUsage.Text = "Memory Usage";
// //
// panelConfiguration // panelConfiguration
// //
this.panelConfiguration.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left)
| System.Windows.Forms.AnchorStyles.Right)));
this.panelConfiguration.Controls.Add(this.btnEditCSS); this.panelConfiguration.Controls.Add(this.btnEditCSS);
this.panelConfiguration.Controls.Add(this.btnEditCefArgs); this.panelConfiguration.Controls.Add(this.btnEditCefArgs);
this.panelConfiguration.Location = new System.Drawing.Point(9, 289); this.panelConfiguration.Location = new System.Drawing.Point(0, 241);
this.panelConfiguration.Margin = new System.Windows.Forms.Padding(0);
this.panelConfiguration.Name = "panelConfiguration"; this.panelConfiguration.Name = "panelConfiguration";
this.panelConfiguration.Size = new System.Drawing.Size(322, 29); this.panelConfiguration.Size = new System.Drawing.Size(300, 31);
this.panelConfiguration.TabIndex = 5; this.panelConfiguration.TabIndex = 6;
// //
// labelConfiguration // labelConfiguration
// //
this.labelConfiguration.AutoSize = true; this.labelConfiguration.AutoSize = true;
this.labelConfiguration.Font = new System.Drawing.Font("Microsoft Sans Serif", 12F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(238))); this.labelConfiguration.Font = new System.Drawing.Font("Segoe UI Semibold", 10.5F, System.Drawing.FontStyle.Bold);
this.labelConfiguration.Location = new System.Drawing.Point(6, 266); this.labelConfiguration.Location = new System.Drawing.Point(0, 221);
this.labelConfiguration.Margin = new System.Windows.Forms.Padding(0, 21, 0, 0); this.labelConfiguration.Margin = new System.Windows.Forms.Padding(0, 30, 0, 1);
this.labelConfiguration.Name = "labelConfiguration"; this.labelConfiguration.Name = "labelConfiguration";
this.labelConfiguration.Size = new System.Drawing.Size(104, 20); this.labelConfiguration.Size = new System.Drawing.Size(123, 19);
this.labelConfiguration.TabIndex = 4; this.labelConfiguration.TabIndex = 5;
this.labelConfiguration.Text = "Configuration"; this.labelConfiguration.Text = "CONFIGURATION";
//
// flowPanel
//
this.flowPanel.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom)
| System.Windows.Forms.AnchorStyles.Left)));
this.flowPanel.Controls.Add(this.labelApp);
this.flowPanel.Controls.Add(this.panelAppButtons);
this.flowPanel.Controls.Add(this.labelCache);
this.flowPanel.Controls.Add(this.btnClearCache);
this.flowPanel.Controls.Add(this.panelClearCacheAuto);
this.flowPanel.Controls.Add(this.labelConfiguration);
this.flowPanel.Controls.Add(this.panelConfiguration);
this.flowPanel.FlowDirection = System.Windows.Forms.FlowDirection.TopDown;
this.flowPanel.Location = new System.Drawing.Point(9, 9);
this.flowPanel.Name = "flowPanel";
this.flowPanel.Size = new System.Drawing.Size(300, 462);
this.flowPanel.TabIndex = 0;
this.flowPanel.WrapContents = false;
// //
// TabSettingsAdvanced // TabSettingsAdvanced
// //
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
this.Controls.Add(this.labelConfiguration); this.Controls.Add(this.flowPanel);
this.Controls.Add(this.panelConfiguration);
this.Controls.Add(this.panelPerformance);
this.Controls.Add(this.labelPerformance);
this.Controls.Add(this.panelApp);
this.Controls.Add(this.labelApp);
this.Name = "TabSettingsAdvanced"; this.Name = "TabSettingsAdvanced";
this.Size = new System.Drawing.Size(340, 328); this.Size = new System.Drawing.Size(631, 480);
((System.ComponentModel.ISupportInitialize)(this.numMemoryThreshold)).EndInit(); ((System.ComponentModel.ISupportInitialize)(this.numClearCacheThreshold)).EndInit();
this.panelApp.ResumeLayout(false); this.panelAppButtons.ResumeLayout(false);
this.panelPerformance.ResumeLayout(false); this.panelClearCacheAuto.ResumeLayout(false);
this.panelPerformance.PerformLayout(); this.panelClearCacheAuto.PerformLayout();
this.panelConfiguration.ResumeLayout(false); this.panelConfiguration.ResumeLayout(false);
this.flowPanel.ResumeLayout(false);
this.flowPanel.PerformLayout();
this.ResumeLayout(false); this.ResumeLayout(false);
this.PerformLayout();
} }
#endregion #endregion
private System.Windows.Forms.Button btnClearCache; private System.Windows.Forms.Button btnClearCache;
private System.Windows.Forms.CheckBox checkHardwareAcceleration;
private System.Windows.Forms.ToolTip toolTip; private System.Windows.Forms.ToolTip toolTip;
private System.Windows.Forms.Button btnEditCefArgs; private System.Windows.Forms.Button btnEditCefArgs;
private System.Windows.Forms.Button btnEditCSS; private System.Windows.Forms.Button btnEditCSS;
@@ -278,13 +276,13 @@
private System.Windows.Forms.Button btnOpenAppFolder; private System.Windows.Forms.Button btnOpenAppFolder;
private System.Windows.Forms.Button btnOpenDataFolder; private System.Windows.Forms.Button btnOpenDataFolder;
private System.Windows.Forms.Label labelApp; private System.Windows.Forms.Label labelApp;
private System.Windows.Forms.Panel panelApp; private System.Windows.Forms.Panel panelAppButtons;
private System.Windows.Forms.Label labelPerformance; private System.Windows.Forms.Label labelCache;
private System.Windows.Forms.Panel panelPerformance; private System.Windows.Forms.Panel panelClearCacheAuto;
private System.Windows.Forms.Panel panelConfiguration; private System.Windows.Forms.Panel panelConfiguration;
private System.Windows.Forms.Label labelConfiguration; private System.Windows.Forms.Label labelConfiguration;
private System.Windows.Forms.Label labelMemoryUsage; private Controls.NumericUpDownEx numClearCacheThreshold;
private Controls.NumericUpDownEx numMemoryThreshold; private System.Windows.Forms.CheckBox checkClearCacheAuto;
private System.Windows.Forms.CheckBox checkBrowserGCReload; private System.Windows.Forms.FlowLayoutPanel flowPanel;
} }
} }

View File

@@ -1,124 +1,70 @@
using System; using System;
using System.Diagnostics; using System.Diagnostics;
using System.Threading.Tasks;
using System.Windows.Forms; using System.Windows.Forms;
using TweetDuck.Configuration; using TweetDuck.Configuration;
using TweetDuck.Core.Controls; using TweetDuck.Core.Controls;
using TweetDuck.Core.Management;
using TweetDuck.Core.Other.Settings.Dialogs; using TweetDuck.Core.Other.Settings.Dialogs;
using TweetDuck.Core.Utils; using TweetDuck.Core.Utils;
namespace TweetDuck.Core.Other.Settings{ namespace TweetDuck.Core.Other.Settings{
sealed partial class TabSettingsAdvanced : BaseTabSettings{ sealed partial class TabSettingsAdvanced : BaseTabSettings{
private static SystemConfig SysConfig => Program.SystemConfig;
private readonly Action<string> reinjectBrowserCSS; private readonly Action<string> reinjectBrowserCSS;
private readonly Action openDevTools;
public TabSettingsAdvanced(Action<string> reinjectBrowserCSS){ public TabSettingsAdvanced(Action<string> reinjectBrowserCSS, Action openDevTools){
InitializeComponent(); InitializeComponent();
this.reinjectBrowserCSS = reinjectBrowserCSS; this.reinjectBrowserCSS = reinjectBrowserCSS;
this.openDevTools = openDevTools;
if (SystemConfig.IsHardwareAccelerationSupported){ // application
checkHardwareAcceleration.Checked = SysConfig.HardwareAcceleration;
}
else{
checkHardwareAcceleration.Enabled = false;
checkHardwareAcceleration.Checked = false;
}
checkBrowserGCReload.Checked = SysConfig.EnableBrowserGCReload; toolTip.SetToolTip(btnOpenAppFolder, "Opens the folder where the app is located.");
numMemoryThreshold.Enabled = checkBrowserGCReload.Checked; toolTip.SetToolTip(btnOpenDataFolder, "Opens the folder where your profile data is located.");
numMemoryThreshold.SetValueSafe(SysConfig.BrowserMemoryThreshold); toolTip.SetToolTip(btnRestart, "Restarts the program using the same command\r\nline arguments that were used at launch.");
toolTip.SetToolTip(btnRestartArgs, "Restarts the program with customizable\r\ncommand line arguments.");
BrowserCache.CalculateCacheSize(task => { // browser cache
string text = task.IsCompleted ? (int)Math.Ceiling(task.Result/(1024.0*1024.0))+" MB" : "(unknown size)";
toolTip.SetToolTip(btnClearCache, "Clearing cache will free up space taken by downloaded images and other resources.");
toolTip.SetToolTip(checkClearCacheAuto, "Automatically clears cache when its size exceeds the set threshold. Note that cache can only be cleared when closing TweetDuck.");
checkClearCacheAuto.Checked = SysConfig.ClearCacheAutomatically;
numClearCacheThreshold.Enabled = checkClearCacheAuto.Checked;
numClearCacheThreshold.SetValueSafe(SysConfig.ClearCacheThreshold);
BrowserCache.GetCacheSize(task => {
string text = task.Status == TaskStatus.RanToCompletion ? (int)Math.Ceiling(task.Result/(1024.0*1024.0))+" MB" : "unknown";
this.InvokeSafe(() => btnClearCache.Text = $"Clear Cache ({text})"); this.InvokeSafe(() => btnClearCache.Text = $"Clear Cache ({text})");
}); });
// configuration
toolTip.SetToolTip(btnEditCefArgs, "Set custom command line arguments for Chromium Embedded Framework.");
toolTip.SetToolTip(btnEditCSS, "Set custom CSS for browser and notification windows.");
} }
public override void OnReady(){ public override void OnReady(){
btnClearCache.Click += btnClearCache_Click;
checkHardwareAcceleration.CheckedChanged += checkHardwareAcceleration_CheckedChanged;
checkBrowserGCReload.CheckedChanged += checkBrowserGCReload_CheckedChanged;
numMemoryThreshold.ValueChanged += numMemoryThreshold_ValueChanged;
btnEditCefArgs.Click += btnEditCefArgs_Click;
btnEditCSS.Click += btnEditCSS_Click;
btnOpenAppFolder.Click += btnOpenAppFolder_Click; btnOpenAppFolder.Click += btnOpenAppFolder_Click;
btnOpenDataFolder.Click += btnOpenDataFolder_Click; btnOpenDataFolder.Click += btnOpenDataFolder_Click;
btnRestart.Click += btnRestart_Click; btnRestart.Click += btnRestart_Click;
btnRestartArgs.Click += btnRestartArgs_Click; btnRestartArgs.Click += btnRestartArgs_Click;
btnClearCache.Click += btnClearCache_Click;
checkClearCacheAuto.CheckedChanged += checkClearCacheAuto_CheckedChanged;
btnEditCefArgs.Click += btnEditCefArgs_Click;
btnEditCSS.Click += btnEditCSS_Click;
} }
public override void OnClosing(){ public override void OnClosing(){
SysConfig.Save(); SysConfig.ClearCacheAutomatically = checkClearCacheAuto.Checked;
SysConfig.ClearCacheThreshold = (int)numClearCacheThreshold.Value;
} }
private void btnClearCache_Click(object sender, EventArgs e){ #region Application
btnClearCache.Enabled = false;
BrowserCache.SetClearOnExit();
FormMessage.Information("Clear Cache", "Cache will be automatically cleared when TweetDuck exits.", FormMessage.OK);
}
private void checkHardwareAcceleration_CheckedChanged(object sender, EventArgs e){
SysConfig.HardwareAcceleration = checkHardwareAcceleration.Checked;
PromptRestart(); // calls OnClosing
}
private void checkBrowserGCReload_CheckedChanged(object sender, EventArgs e){
SysConfig.EnableBrowserGCReload = checkBrowserGCReload.Checked;
numMemoryThreshold.Enabled = checkBrowserGCReload.Checked;
}
private void numMemoryThreshold_ValueChanged(object sender, EventArgs e){
SysConfig.BrowserMemoryThreshold = (int)numMemoryThreshold.Value;
}
private void btnEditCefArgs_Click(object sender, EventArgs e){
DialogSettingsCefArgs form = new DialogSettingsCefArgs();
form.VisibleChanged += (sender2, args2) => {
form.MoveToCenter(ParentForm);
};
form.FormClosed += (sender2, args2) => {
RestoreParentForm();
if (form.DialogResult == DialogResult.OK){
Config.CustomCefArgs = form.CefArgs;
PromptRestart();
form.Dispose();
}
else form.Dispose();
};
form.Show(ParentForm);
NativeMethods.SetFormDisabled(ParentForm, true);
}
private void btnEditCSS_Click(object sender, EventArgs e){
DialogSettingsCSS form = new DialogSettingsCSS(reinjectBrowserCSS);
form.VisibleChanged += (sender2, args2) => {
form.MoveToCenter(ParentForm);
};
form.FormClosed += (sender2, args2) => {
RestoreParentForm();
if (form.DialogResult == DialogResult.OK){
Config.CustomBrowserCSS = form.BrowserCSS;
Config.CustomNotificationCSS = form.NotificationCSS;
}
reinjectBrowserCSS(Config.CustomBrowserCSS); // reinject on cancel too, because the CSS is updated while typing
form.Dispose();
};
form.Show(ParentForm);
NativeMethods.SetFormDisabled(ParentForm, true);
}
private void btnOpenAppFolder_Click(object sender, EventArgs e){ private void btnOpenAppFolder_Click(object sender, EventArgs e){
using(Process.Start("explorer.exe", "\""+Program.ProgramPath+"\"")){} using(Process.Start("explorer.exe", "\""+Program.ProgramPath+"\"")){}
@@ -140,10 +86,72 @@ namespace TweetDuck.Core.Other.Settings{
} }
} }
#endregion
#region Browser Cache
private void btnClearCache_Click(object sender, EventArgs e){
btnClearCache.Enabled = false;
BrowserCache.SetClearOnExit();
FormMessage.Information("Clear Cache", "Cache will be automatically cleared when TweetDuck exits.", FormMessage.OK);
}
private void checkClearCacheAuto_CheckedChanged(object sender, EventArgs e){
numClearCacheThreshold.Enabled = checkClearCacheAuto.Checked;
}
#endregion
#region Configuration
private void btnEditCefArgs_Click(object sender, EventArgs e){
DialogSettingsCefArgs form = new DialogSettingsCefArgs(Config.CustomCefArgs);
form.VisibleChanged += (sender2, args2) => {
form.MoveToCenter(ParentForm);
};
form.FormClosed += (sender2, args2) => {
RestoreParentForm();
if (form.DialogResult == DialogResult.OK){
Config.CustomCefArgs = form.CefArgs;
}
form.Dispose();
};
form.Show(ParentForm);
NativeMethods.SetFormDisabled(ParentForm, true);
}
private void btnEditCSS_Click(object sender, EventArgs e){
DialogSettingsCSS form = new DialogSettingsCSS(Config.CustomBrowserCSS, Config.CustomNotificationCSS, reinjectBrowserCSS, openDevTools);
form.VisibleChanged += (sender2, args2) => {
form.MoveToCenter(ParentForm);
};
form.FormClosed += (sender2, args2) => {
RestoreParentForm();
if (form.DialogResult == DialogResult.OK){
Config.CustomBrowserCSS = form.BrowserCSS;
Config.CustomNotificationCSS = form.NotificationCSS;
}
reinjectBrowserCSS(Config.CustomBrowserCSS); // reinject on cancel too, because the CSS is updated while typing
form.Dispose();
};
form.Show(ParentForm);
NativeMethods.SetFormDisabled(ParentForm, true);
}
private void RestoreParentForm(){ private void RestoreParentForm(){
if (ParentForm != null){ // when the parent is closed first, ParentForm is null in FormClosed event if (ParentForm != null){ // when the parent is closed first, ParentForm is null in FormClosed event
NativeMethods.SetFormDisabled(ParentForm, false); NativeMethods.SetFormDisabled(ParentForm, false);
} }
} }
#endregion
} }
} }

View File

@@ -24,48 +24,76 @@
/// </summary> /// </summary>
private void InitializeComponent() { private void InitializeComponent() {
this.components = new System.ComponentModel.Container(); this.components = new System.ComponentModel.Container();
this.panelFeedback = new System.Windows.Forms.Panel(); this.panelDataCollection = new System.Windows.Forms.Panel();
this.labelDataCollectionLink = new System.Windows.Forms.LinkLabel();
this.checkDataCollection = new System.Windows.Forms.CheckBox();
this.labelDataCollectionMessage = new System.Windows.Forms.Label(); this.labelDataCollectionMessage = new System.Windows.Forms.Label();
this.btnViewReport = new System.Windows.Forms.Button(); this.btnViewReport = new System.Windows.Forms.Button();
this.btnSendFeedback = new System.Windows.Forms.Button(); this.btnSendFeedback = new System.Windows.Forms.Button();
this.labelDataCollectionLink = new System.Windows.Forms.LinkLabel();
this.checkDataCollection = new System.Windows.Forms.CheckBox();
this.labelDataCollection = new System.Windows.Forms.Label(); this.labelDataCollection = new System.Windows.Forms.Label();
this.labelFeedback = new System.Windows.Forms.Label(); this.labelFeedback = new System.Windows.Forms.Label();
this.toolTip = new System.Windows.Forms.ToolTip(this.components); this.toolTip = new System.Windows.Forms.ToolTip(this.components);
this.panelFeedback.SuspendLayout(); this.flowPanel = new System.Windows.Forms.FlowLayoutPanel();
this.panelDataCollection.SuspendLayout();
this.flowPanel.SuspendLayout();
this.SuspendLayout(); this.SuspendLayout();
// //
// panelFeedback // panelDataCollection
// //
this.panelFeedback.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) this.panelDataCollection.Controls.Add(this.labelDataCollectionLink);
| System.Windows.Forms.AnchorStyles.Right))); this.panelDataCollection.Controls.Add(this.checkDataCollection);
this.panelFeedback.Controls.Add(this.labelDataCollectionMessage); this.panelDataCollection.Location = new System.Drawing.Point(0, 78);
this.panelFeedback.Controls.Add(this.btnViewReport); this.panelDataCollection.Margin = new System.Windows.Forms.Padding(0);
this.panelFeedback.Controls.Add(this.btnSendFeedback); this.panelDataCollection.Name = "panelDataCollection";
this.panelFeedback.Controls.Add(this.labelDataCollectionLink); this.panelDataCollection.Size = new System.Drawing.Size(300, 28);
this.panelFeedback.Controls.Add(this.checkDataCollection); this.panelDataCollection.TabIndex = 3;
this.panelFeedback.Controls.Add(this.labelDataCollection); //
this.panelFeedback.Location = new System.Drawing.Point(9, 31); // labelDataCollectionLink
this.panelFeedback.Name = "panelFeedback"; //
this.panelFeedback.Size = new System.Drawing.Size(322, 188); this.labelDataCollectionLink.AutoSize = true;
this.panelFeedback.TabIndex = 1; this.labelDataCollectionLink.Font = new System.Drawing.Font("Segoe UI", 9F);
this.labelDataCollectionLink.LinkArea = new System.Windows.Forms.LinkArea(1, 10);
this.labelDataCollectionLink.LinkBehavior = System.Windows.Forms.LinkBehavior.HoverUnderline;
this.labelDataCollectionLink.Location = new System.Drawing.Point(153, 4);
this.labelDataCollectionLink.Margin = new System.Windows.Forms.Padding(0);
this.labelDataCollectionLink.Name = "labelDataCollectionLink";
this.labelDataCollectionLink.Size = new System.Drawing.Size(71, 21);
this.labelDataCollectionLink.TabIndex = 1;
this.labelDataCollectionLink.TabStop = true;
this.labelDataCollectionLink.Text = "(learn more)";
this.labelDataCollectionLink.TextAlign = System.Drawing.ContentAlignment.MiddleLeft;
this.labelDataCollectionLink.UseCompatibleTextRendering = true;
//
// checkDataCollection
//
this.checkDataCollection.AutoSize = true;
this.checkDataCollection.Font = new System.Drawing.Font("Segoe UI", 9F);
this.checkDataCollection.Location = new System.Drawing.Point(6, 6);
this.checkDataCollection.Margin = new System.Windows.Forms.Padding(6, 6, 0, 2);
this.checkDataCollection.Name = "checkDataCollection";
this.checkDataCollection.Size = new System.Drawing.Size(147, 19);
this.checkDataCollection.TabIndex = 0;
this.checkDataCollection.Text = "Send Anonymous Data";
this.checkDataCollection.UseVisualStyleBackColor = true;
// //
// labelDataCollectionMessage // labelDataCollectionMessage
// //
this.labelDataCollectionMessage.Location = new System.Drawing.Point(6, 114); this.labelDataCollectionMessage.Font = new System.Drawing.Font("Segoe UI", 9F);
this.labelDataCollectionMessage.Location = new System.Drawing.Point(6, 143);
this.labelDataCollectionMessage.Margin = new System.Windows.Forms.Padding(6); this.labelDataCollectionMessage.Margin = new System.Windows.Forms.Padding(6);
this.labelDataCollectionMessage.Name = "labelDataCollectionMessage"; this.labelDataCollectionMessage.Name = "labelDataCollectionMessage";
this.labelDataCollectionMessage.Size = new System.Drawing.Size(310, 67); this.labelDataCollectionMessage.Size = new System.Drawing.Size(288, 67);
this.labelDataCollectionMessage.TabIndex = 5; this.labelDataCollectionMessage.TabIndex = 5;
// //
// btnViewReport // btnViewReport
// //
this.btnViewReport.AutoSize = true; this.btnViewReport.AutoSize = true;
this.btnViewReport.Location = new System.Drawing.Point(6, 82); this.btnViewReport.Font = new System.Drawing.Font("Segoe UI", 9F);
this.btnViewReport.Location = new System.Drawing.Point(5, 109);
this.btnViewReport.Margin = new System.Windows.Forms.Padding(5, 3, 3, 3); this.btnViewReport.Margin = new System.Windows.Forms.Padding(5, 3, 3, 3);
this.btnViewReport.Name = "btnViewReport"; this.btnViewReport.Name = "btnViewReport";
this.btnViewReport.Size = new System.Drawing.Size(144, 23); this.btnViewReport.Padding = new System.Windows.Forms.Padding(2, 0, 2, 0);
this.btnViewReport.Size = new System.Drawing.Size(155, 25);
this.btnViewReport.TabIndex = 4; this.btnViewReport.TabIndex = 4;
this.btnViewReport.Text = "View My Analytics Report"; this.btnViewReport.Text = "View My Analytics Report";
this.btnViewReport.UseVisualStyleBackColor = true; this.btnViewReport.UseVisualStyleBackColor = true;
@@ -73,79 +101,74 @@
// btnSendFeedback // btnSendFeedback
// //
this.btnSendFeedback.AutoSize = true; this.btnSendFeedback.AutoSize = true;
this.btnSendFeedback.Location = new System.Drawing.Point(5, 3); this.btnSendFeedback.Font = new System.Drawing.Font("Segoe UI", 9F);
this.btnSendFeedback.Location = new System.Drawing.Point(5, 23);
this.btnSendFeedback.Margin = new System.Windows.Forms.Padding(5, 3, 3, 3); this.btnSendFeedback.Margin = new System.Windows.Forms.Padding(5, 3, 3, 3);
this.btnSendFeedback.Name = "btnSendFeedback"; this.btnSendFeedback.Name = "btnSendFeedback";
this.btnSendFeedback.Padding = new System.Windows.Forms.Padding(3, 0, 3, 0); this.btnSendFeedback.Padding = new System.Windows.Forms.Padding(2, 0, 2, 0);
this.btnSendFeedback.Size = new System.Drawing.Size(164, 23); this.btnSendFeedback.Size = new System.Drawing.Size(170, 25);
this.btnSendFeedback.TabIndex = 0; this.btnSendFeedback.TabIndex = 1;
this.btnSendFeedback.Text = "Send Feedback / Bug Report"; this.btnSendFeedback.Text = "Send Feedback / Bug Report";
this.btnSendFeedback.UseVisualStyleBackColor = true; this.btnSendFeedback.UseVisualStyleBackColor = true;
// //
// labelDataCollectionLink
//
this.labelDataCollectionLink.AutoSize = true;
this.labelDataCollectionLink.LinkArea = new System.Windows.Forms.LinkArea(1, 10);
this.labelDataCollectionLink.LinkBehavior = System.Windows.Forms.LinkBehavior.HoverUnderline;
this.labelDataCollectionLink.Location = new System.Drawing.Point(141, 60);
this.labelDataCollectionLink.Margin = new System.Windows.Forms.Padding(0, 0, 3, 0);
this.labelDataCollectionLink.Name = "labelDataCollectionLink";
this.labelDataCollectionLink.Size = new System.Drawing.Size(66, 17);
this.labelDataCollectionLink.TabIndex = 3;
this.labelDataCollectionLink.TabStop = true;
this.labelDataCollectionLink.Text = "(learn more)";
this.labelDataCollectionLink.UseCompatibleTextRendering = true;
//
// checkDataCollection
//
this.checkDataCollection.AutoSize = true;
this.checkDataCollection.Location = new System.Drawing.Point(6, 59);
this.checkDataCollection.Margin = new System.Windows.Forms.Padding(6, 5, 0, 3);
this.checkDataCollection.Name = "checkDataCollection";
this.checkDataCollection.Size = new System.Drawing.Size(135, 17);
this.checkDataCollection.TabIndex = 2;
this.checkDataCollection.Text = "Send Anonymous Data";
this.checkDataCollection.UseVisualStyleBackColor = true;
//
// labelDataCollection // labelDataCollection
// //
this.labelDataCollection.AutoSize = true; this.labelDataCollection.AutoSize = true;
this.labelDataCollection.Location = new System.Drawing.Point(3, 41); this.labelDataCollection.Font = new System.Drawing.Font("Segoe UI Semibold", 9F, System.Drawing.FontStyle.Bold);
this.labelDataCollection.Location = new System.Drawing.Point(3, 63);
this.labelDataCollection.Margin = new System.Windows.Forms.Padding(3, 12, 3, 0); this.labelDataCollection.Margin = new System.Windows.Forms.Padding(3, 12, 3, 0);
this.labelDataCollection.Name = "labelDataCollection"; this.labelDataCollection.Name = "labelDataCollection";
this.labelDataCollection.Size = new System.Drawing.Size(79, 13); this.labelDataCollection.Size = new System.Drawing.Size(88, 15);
this.labelDataCollection.TabIndex = 1; this.labelDataCollection.TabIndex = 2;
this.labelDataCollection.Text = "Data Collection"; this.labelDataCollection.Text = "Data Collection";
// //
// labelFeedback // labelFeedback
// //
this.labelFeedback.AutoSize = true; this.labelFeedback.AutoSize = true;
this.labelFeedback.Font = new System.Drawing.Font("Microsoft Sans Serif", 12F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(238))); this.labelFeedback.Font = new System.Drawing.Font("Segoe UI Semibold", 10.5F, System.Drawing.FontStyle.Bold);
this.labelFeedback.Location = new System.Drawing.Point(6, 8); this.labelFeedback.Location = new System.Drawing.Point(0, 0);
this.labelFeedback.Margin = new System.Windows.Forms.Padding(0, 2, 0, 0); this.labelFeedback.Margin = new System.Windows.Forms.Padding(0, 0, 0, 1);
this.labelFeedback.Name = "labelFeedback"; this.labelFeedback.Name = "labelFeedback";
this.labelFeedback.Size = new System.Drawing.Size(80, 20); this.labelFeedback.Size = new System.Drawing.Size(75, 19);
this.labelFeedback.TabIndex = 0; this.labelFeedback.TabIndex = 0;
this.labelFeedback.Text = "Feedback"; this.labelFeedback.Text = "FEEDBACK";
//
// flowPanel
//
this.flowPanel.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.flowPanel.Controls.Add(this.labelFeedback);
this.flowPanel.Controls.Add(this.btnSendFeedback);
this.flowPanel.Controls.Add(this.labelDataCollection);
this.flowPanel.Controls.Add(this.panelDataCollection);
this.flowPanel.Controls.Add(this.btnViewReport);
this.flowPanel.Controls.Add(this.labelDataCollectionMessage);
this.flowPanel.FlowDirection = System.Windows.Forms.FlowDirection.TopDown;
this.flowPanel.Location = new System.Drawing.Point(9, 9);
this.flowPanel.Name = "flowPanel";
this.flowPanel.Size = new System.Drawing.Size(300, 462);
this.flowPanel.TabIndex = 0;
this.flowPanel.WrapContents = false;
// //
// TabSettingsFeedback // TabSettingsFeedback
// //
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
this.Controls.Add(this.panelFeedback); this.Controls.Add(this.flowPanel);
this.Controls.Add(this.labelFeedback);
this.Name = "TabSettingsFeedback"; this.Name = "TabSettingsFeedback";
this.Size = new System.Drawing.Size(340, 230); this.Size = new System.Drawing.Size(631, 480);
this.panelFeedback.ResumeLayout(false); this.panelDataCollection.ResumeLayout(false);
this.panelFeedback.PerformLayout(); this.panelDataCollection.PerformLayout();
this.flowPanel.ResumeLayout(false);
this.flowPanel.PerformLayout();
this.ResumeLayout(false); this.ResumeLayout(false);
this.PerformLayout();
} }
#endregion #endregion
private System.Windows.Forms.Panel panelFeedback; private System.Windows.Forms.Panel panelDataCollection;
private System.Windows.Forms.CheckBox checkDataCollection; private System.Windows.Forms.CheckBox checkDataCollection;
private System.Windows.Forms.Label labelDataCollection; private System.Windows.Forms.Label labelDataCollection;
private System.Windows.Forms.Label labelFeedback; private System.Windows.Forms.Label labelFeedback;
@@ -154,5 +177,6 @@
private System.Windows.Forms.Button btnSendFeedback; private System.Windows.Forms.Button btnSendFeedback;
private System.Windows.Forms.Button btnViewReport; private System.Windows.Forms.Button btnViewReport;
private System.Windows.Forms.Label labelDataCollectionMessage; private System.Windows.Forms.Label labelDataCollectionMessage;
private System.Windows.Forms.FlowLayoutPanel flowPanel;
} }
} }

View File

@@ -18,6 +18,8 @@ namespace TweetDuck.Core.Other.Settings{
this.analyticsInfo = analyticsInfo; this.analyticsInfo = analyticsInfo;
this.plugins = plugins; this.plugins = plugins;
// feedback
checkDataCollection.Checked = Config.AllowDataCollection; checkDataCollection.Checked = Config.AllowDataCollection;
if (analytics != null){ if (analytics != null){
@@ -33,6 +35,8 @@ namespace TweetDuck.Core.Other.Settings{
btnViewReport.Click += btnViewReport_Click; btnViewReport.Click += btnViewReport_Click;
} }
#region Feedback
private void btnSendFeedback_Click(object sender, EventArgs e){ private void btnSendFeedback_Click(object sender, EventArgs e){
BrowserUtils.OpenExternalBrowser("https://github.com/chylex/TweetDuck/issues/new"); BrowserUtils.OpenExternalBrowser("https://github.com/chylex/TweetDuck/issues/new");
} }
@@ -50,5 +54,7 @@ namespace TweetDuck.Core.Other.Settings{
dialog.ShowDialog(); dialog.ShowDialog();
} }
} }
#endregion
} }
} }

View File

@@ -26,118 +26,117 @@
this.components = new System.ComponentModel.Container(); this.components = new System.ComponentModel.Container();
this.checkExpandLinks = new System.Windows.Forms.CheckBox(); this.checkExpandLinks = new System.Windows.Forms.CheckBox();
this.toolTip = new System.Windows.Forms.ToolTip(this.components); this.toolTip = new System.Windows.Forms.ToolTip(this.components);
this.checkSpellCheck = new System.Windows.Forms.CheckBox();
this.checkUpdateNotifications = new System.Windows.Forms.CheckBox(); this.checkUpdateNotifications = new System.Windows.Forms.CheckBox();
this.btnCheckUpdates = new System.Windows.Forms.Button(); this.btnCheckUpdates = new System.Windows.Forms.Button();
this.labelZoomValue = new System.Windows.Forms.Label(); this.labelZoomValue = new System.Windows.Forms.Label();
this.checkSwitchAccountSelectors = new System.Windows.Forms.CheckBox();
this.checkBestImageQuality = new System.Windows.Forms.CheckBox(); this.checkBestImageQuality = new System.Windows.Forms.CheckBox();
this.checkOpenSearchInFirstColumn = new System.Windows.Forms.CheckBox(); this.checkOpenSearchInFirstColumn = new System.Windows.Forms.CheckBox();
this.trackBarZoom = new System.Windows.Forms.TrackBar(); this.trackBarZoom = new System.Windows.Forms.TrackBar();
this.labelZoom = new System.Windows.Forms.Label(); this.labelZoom = new System.Windows.Forms.Label();
this.zoomUpdateTimer = new System.Windows.Forms.Timer(this.components); this.zoomUpdateTimer = new System.Windows.Forms.Timer(this.components);
this.labelUI = new System.Windows.Forms.Label(); this.labelUI = new System.Windows.Forms.Label();
this.panelUI = new System.Windows.Forms.Panel(); this.panelZoom = new System.Windows.Forms.Panel();
this.panelUpdates = new System.Windows.Forms.Panel(); this.checkAnimatedAvatars = new System.Windows.Forms.CheckBox();
this.labelUpdates = new System.Windows.Forms.Label(); this.labelUpdates = new System.Windows.Forms.Label();
this.flowPanelLeft = new System.Windows.Forms.FlowLayoutPanel();
this.checkKeepLikeFollowDialogsOpen = new System.Windows.Forms.CheckBox();
this.labelTray = new System.Windows.Forms.Label();
this.comboBoxTrayType = new System.Windows.Forms.ComboBox();
this.labelTrayIcon = new System.Windows.Forms.Label();
this.checkTrayHighlight = new System.Windows.Forms.CheckBox();
this.labelBrowserSettings = new System.Windows.Forms.Label();
this.checkSmoothScrolling = new System.Windows.Forms.CheckBox();
this.checkTouchAdjustment = new System.Windows.Forms.CheckBox();
this.labelBrowserPath = new System.Windows.Forms.Label();
this.comboBoxBrowserPath = new System.Windows.Forms.ComboBox();
this.labelSearchEngine = new System.Windows.Forms.Label();
this.comboBoxSearchEngine = new System.Windows.Forms.ComboBox();
this.flowPanelRight = new System.Windows.Forms.FlowLayoutPanel();
this.checkHardwareAcceleration = new System.Windows.Forms.CheckBox();
this.labelLocales = new System.Windows.Forms.Label();
this.checkSpellCheck = new System.Windows.Forms.CheckBox();
this.labelSpellCheckLanguage = new System.Windows.Forms.Label();
this.comboBoxSpellCheckLanguage = new System.Windows.Forms.ComboBox();
this.labelTranslationTarget = new System.Windows.Forms.Label();
this.comboBoxTranslationTarget = new System.Windows.Forms.ComboBox();
this.panelSeparator = new System.Windows.Forms.Panel();
((System.ComponentModel.ISupportInitialize)(this.trackBarZoom)).BeginInit(); ((System.ComponentModel.ISupportInitialize)(this.trackBarZoom)).BeginInit();
this.panelUI.SuspendLayout(); this.panelZoom.SuspendLayout();
this.panelUpdates.SuspendLayout(); this.flowPanelLeft.SuspendLayout();
this.flowPanelRight.SuspendLayout();
this.SuspendLayout(); this.SuspendLayout();
// //
// checkExpandLinks // checkExpandLinks
// //
this.checkExpandLinks.AutoSize = true; this.checkExpandLinks.AutoSize = true;
this.checkExpandLinks.Location = new System.Drawing.Point(6, 5); this.checkExpandLinks.Font = new System.Drawing.Font("Segoe UI", 9F);
this.checkExpandLinks.Margin = new System.Windows.Forms.Padding(6, 5, 3, 3); this.checkExpandLinks.Location = new System.Drawing.Point(6, 26);
this.checkExpandLinks.Margin = new System.Windows.Forms.Padding(6, 6, 3, 2);
this.checkExpandLinks.Name = "checkExpandLinks"; this.checkExpandLinks.Name = "checkExpandLinks";
this.checkExpandLinks.Size = new System.Drawing.Size(166, 17); this.checkExpandLinks.Size = new System.Drawing.Size(176, 19);
this.checkExpandLinks.TabIndex = 0; this.checkExpandLinks.TabIndex = 1;
this.checkExpandLinks.Text = "Expand Links When Hovered"; this.checkExpandLinks.Text = "Expand Links When Hovered";
this.toolTip.SetToolTip(this.checkExpandLinks, "Expands links inside the tweets. If disabled,\r\nthe full links show up in a tooltip instead.");
this.checkExpandLinks.UseVisualStyleBackColor = true; this.checkExpandLinks.UseVisualStyleBackColor = true;
// //
// checkSpellCheck
//
this.checkSpellCheck.AutoSize = true;
this.checkSpellCheck.Location = new System.Drawing.Point(6, 97);
this.checkSpellCheck.Margin = new System.Windows.Forms.Padding(6, 3, 3, 3);
this.checkSpellCheck.Name = "checkSpellCheck";
this.checkSpellCheck.Size = new System.Drawing.Size(119, 17);
this.checkSpellCheck.TabIndex = 4;
this.checkSpellCheck.Text = "Enable Spell Check";
this.toolTip.SetToolTip(this.checkSpellCheck, "Underlines words that are spelled incorrectly.");
this.checkSpellCheck.UseVisualStyleBackColor = true;
//
// checkUpdateNotifications // checkUpdateNotifications
// //
this.checkUpdateNotifications.AutoSize = true; this.checkUpdateNotifications.AutoSize = true;
this.checkUpdateNotifications.Location = new System.Drawing.Point(6, 5); this.checkUpdateNotifications.Font = new System.Drawing.Font("Segoe UI", 9F);
this.checkUpdateNotifications.Margin = new System.Windows.Forms.Padding(6, 5, 3, 3); this.checkUpdateNotifications.Location = new System.Drawing.Point(6, 393);
this.checkUpdateNotifications.Margin = new System.Windows.Forms.Padding(6, 6, 3, 2);
this.checkUpdateNotifications.Name = "checkUpdateNotifications"; this.checkUpdateNotifications.Name = "checkUpdateNotifications";
this.checkUpdateNotifications.Size = new System.Drawing.Size(165, 17); this.checkUpdateNotifications.Size = new System.Drawing.Size(182, 19);
this.checkUpdateNotifications.TabIndex = 0; this.checkUpdateNotifications.TabIndex = 13;
this.checkUpdateNotifications.Text = "Check Updates Automatically"; this.checkUpdateNotifications.Text = "Check Updates Automatically";
this.toolTip.SetToolTip(this.checkUpdateNotifications, "Checks for updates every hour.\r\nIf an update is dismissed, it will not appear again.");
this.checkUpdateNotifications.UseVisualStyleBackColor = true; this.checkUpdateNotifications.UseVisualStyleBackColor = true;
// //
// btnCheckUpdates // btnCheckUpdates
// //
this.btnCheckUpdates.Location = new System.Drawing.Point(5, 28); this.btnCheckUpdates.AutoSize = true;
this.btnCheckUpdates.Font = new System.Drawing.Font("Segoe UI", 9F);
this.btnCheckUpdates.Location = new System.Drawing.Point(5, 417);
this.btnCheckUpdates.Margin = new System.Windows.Forms.Padding(5, 3, 3, 3); this.btnCheckUpdates.Margin = new System.Windows.Forms.Padding(5, 3, 3, 3);
this.btnCheckUpdates.Name = "btnCheckUpdates"; this.btnCheckUpdates.Name = "btnCheckUpdates";
this.btnCheckUpdates.Size = new System.Drawing.Size(144, 23); this.btnCheckUpdates.Padding = new System.Windows.Forms.Padding(2, 0, 2, 0);
this.btnCheckUpdates.TabIndex = 1; this.btnCheckUpdates.Size = new System.Drawing.Size(128, 25);
this.btnCheckUpdates.TabIndex = 14;
this.btnCheckUpdates.Text = "Check Updates Now"; this.btnCheckUpdates.Text = "Check Updates Now";
this.toolTip.SetToolTip(this.btnCheckUpdates, "Forces an update check, even for updates that had been dismissed.");
this.btnCheckUpdates.UseVisualStyleBackColor = true; this.btnCheckUpdates.UseVisualStyleBackColor = true;
// //
// labelZoomValue // labelZoomValue
// //
this.labelZoomValue.BackColor = System.Drawing.Color.Transparent; this.labelZoomValue.BackColor = System.Drawing.Color.Transparent;
this.labelZoomValue.Location = new System.Drawing.Point(147, 146); this.labelZoomValue.Font = new System.Drawing.Font("Segoe UI", 9F);
this.labelZoomValue.Location = new System.Drawing.Point(147, 4);
this.labelZoomValue.Margin = new System.Windows.Forms.Padding(0, 0, 3, 0); this.labelZoomValue.Margin = new System.Windows.Forms.Padding(0, 0, 3, 0);
this.labelZoomValue.Name = "labelZoomValue"; this.labelZoomValue.Name = "labelZoomValue";
this.labelZoomValue.Size = new System.Drawing.Size(38, 13); this.labelZoomValue.Size = new System.Drawing.Size(38, 13);
this.labelZoomValue.TabIndex = 7; this.labelZoomValue.TabIndex = 1;
this.labelZoomValue.Text = "100%"; this.labelZoomValue.Text = "100%";
this.labelZoomValue.TextAlign = System.Drawing.ContentAlignment.TopRight; this.labelZoomValue.TextAlign = System.Drawing.ContentAlignment.TopRight;
this.toolTip.SetToolTip(this.labelZoomValue, "Changes the zoom level.\r\nAlso affects notifications and screenshots.");
//
// checkSwitchAccountSelectors
//
this.checkSwitchAccountSelectors.AutoSize = true;
this.checkSwitchAccountSelectors.Location = new System.Drawing.Point(6, 28);
this.checkSwitchAccountSelectors.Margin = new System.Windows.Forms.Padding(6, 3, 3, 3);
this.checkSwitchAccountSelectors.Name = "checkSwitchAccountSelectors";
this.checkSwitchAccountSelectors.Size = new System.Drawing.Size(172, 17);
this.checkSwitchAccountSelectors.TabIndex = 1;
this.checkSwitchAccountSelectors.Text = "Shift Selects Multiple Accounts";
this.toolTip.SetToolTip(this.checkSwitchAccountSelectors, "When (re)tweeting, click to select a single account or hold Shift to\r\nselect multiple accounts, instead of TweetDeck\'s default behavior.");
this.checkSwitchAccountSelectors.UseVisualStyleBackColor = true;
// //
// checkBestImageQuality // checkBestImageQuality
// //
this.checkBestImageQuality.AutoSize = true; this.checkBestImageQuality.AutoSize = true;
this.checkBestImageQuality.Location = new System.Drawing.Point(6, 74); this.checkBestImageQuality.Font = new System.Drawing.Font("Segoe UI", 9F);
this.checkBestImageQuality.Margin = new System.Windows.Forms.Padding(6, 3, 3, 3); this.checkBestImageQuality.Location = new System.Drawing.Point(6, 98);
this.checkBestImageQuality.Margin = new System.Windows.Forms.Padding(6, 3, 3, 2);
this.checkBestImageQuality.Name = "checkBestImageQuality"; this.checkBestImageQuality.Name = "checkBestImageQuality";
this.checkBestImageQuality.Size = new System.Drawing.Size(114, 17); this.checkBestImageQuality.Size = new System.Drawing.Size(125, 19);
this.checkBestImageQuality.TabIndex = 3; this.checkBestImageQuality.TabIndex = 4;
this.checkBestImageQuality.Text = "Best Image Quality"; this.checkBestImageQuality.Text = "Best Image Quality";
this.toolTip.SetToolTip(this.checkBestImageQuality, "When right-clicking a tweet image, the context menu options\r\nwill use links to the original image size (:orig in the URL).");
this.checkBestImageQuality.UseVisualStyleBackColor = true; this.checkBestImageQuality.UseVisualStyleBackColor = true;
// //
// checkOpenSearchInFirstColumn // checkOpenSearchInFirstColumn
// //
this.checkOpenSearchInFirstColumn.AutoSize = true; this.checkOpenSearchInFirstColumn.AutoSize = true;
this.checkOpenSearchInFirstColumn.Location = new System.Drawing.Point(6, 51); this.checkOpenSearchInFirstColumn.Font = new System.Drawing.Font("Segoe UI", 9F);
this.checkOpenSearchInFirstColumn.Margin = new System.Windows.Forms.Padding(6, 3, 3, 3); this.checkOpenSearchInFirstColumn.Location = new System.Drawing.Point(6, 50);
this.checkOpenSearchInFirstColumn.Margin = new System.Windows.Forms.Padding(6, 3, 3, 2);
this.checkOpenSearchInFirstColumn.Name = "checkOpenSearchInFirstColumn"; this.checkOpenSearchInFirstColumn.Name = "checkOpenSearchInFirstColumn";
this.checkOpenSearchInFirstColumn.Size = new System.Drawing.Size(219, 17); this.checkOpenSearchInFirstColumn.Size = new System.Drawing.Size(245, 19);
this.checkOpenSearchInFirstColumn.TabIndex = 2; this.checkOpenSearchInFirstColumn.TabIndex = 2;
this.checkOpenSearchInFirstColumn.Text = "Add Search Columns Before First Column"; this.checkOpenSearchInFirstColumn.Text = "Add Search Columns Before First Column";
this.toolTip.SetToolTip(this.checkOpenSearchInFirstColumn, "By default, TweetDeck adds Search columns at the end.\r\nThis option makes them appear before the first column instead.");
this.checkOpenSearchInFirstColumn.UseVisualStyleBackColor = true; this.checkOpenSearchInFirstColumn.UseVisualStyleBackColor = true;
// //
// trackBarZoom // trackBarZoom
@@ -145,24 +144,25 @@
this.trackBarZoom.AutoSize = false; this.trackBarZoom.AutoSize = false;
this.trackBarZoom.BackColor = System.Drawing.SystemColors.Control; this.trackBarZoom.BackColor = System.Drawing.SystemColors.Control;
this.trackBarZoom.LargeChange = 25; this.trackBarZoom.LargeChange = 25;
this.trackBarZoom.Location = new System.Drawing.Point(3, 145); this.trackBarZoom.Location = new System.Drawing.Point(3, 3);
this.trackBarZoom.Maximum = 200; this.trackBarZoom.Maximum = 200;
this.trackBarZoom.Minimum = 50; this.trackBarZoom.Minimum = 50;
this.trackBarZoom.Name = "trackBarZoom"; this.trackBarZoom.Name = "trackBarZoom";
this.trackBarZoom.Size = new System.Drawing.Size(148, 30); this.trackBarZoom.Size = new System.Drawing.Size(148, 30);
this.trackBarZoom.SmallChange = 5; this.trackBarZoom.SmallChange = 5;
this.trackBarZoom.TabIndex = 6; this.trackBarZoom.TabIndex = 0;
this.trackBarZoom.TickFrequency = 25; this.trackBarZoom.TickFrequency = 25;
this.trackBarZoom.Value = 100; this.trackBarZoom.Value = 100;
// //
// labelZoom // labelZoom
// //
this.labelZoom.AutoSize = true; this.labelZoom.AutoSize = true;
this.labelZoom.Location = new System.Drawing.Point(3, 129); this.labelZoom.Font = new System.Drawing.Font("Segoe UI Semibold", 9F, System.Drawing.FontStyle.Bold);
this.labelZoom.Location = new System.Drawing.Point(3, 155);
this.labelZoom.Margin = new System.Windows.Forms.Padding(3, 12, 3, 0); this.labelZoom.Margin = new System.Windows.Forms.Padding(3, 12, 3, 0);
this.labelZoom.Name = "labelZoom"; this.labelZoom.Name = "labelZoom";
this.labelZoom.Size = new System.Drawing.Size(34, 13); this.labelZoom.Size = new System.Drawing.Size(39, 15);
this.labelZoom.TabIndex = 5; this.labelZoom.TabIndex = 6;
this.labelZoom.Text = "Zoom"; this.labelZoom.Text = "Zoom";
// //
// zoomUpdateTimer // zoomUpdateTimer
@@ -173,70 +173,340 @@
// labelUI // labelUI
// //
this.labelUI.AutoSize = true; this.labelUI.AutoSize = true;
this.labelUI.Font = new System.Drawing.Font("Microsoft Sans Serif", 12F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(238))); this.labelUI.Font = new System.Drawing.Font("Segoe UI Semibold", 10.5F, System.Drawing.FontStyle.Bold);
this.labelUI.Location = new System.Drawing.Point(6, 8); this.labelUI.Location = new System.Drawing.Point(0, 0);
this.labelUI.Margin = new System.Windows.Forms.Padding(0, 2, 0, 0); this.labelUI.Margin = new System.Windows.Forms.Padding(0, 0, 0, 1);
this.labelUI.Name = "labelUI"; this.labelUI.Name = "labelUI";
this.labelUI.Size = new System.Drawing.Size(111, 20); this.labelUI.Size = new System.Drawing.Size(118, 19);
this.labelUI.TabIndex = 0; this.labelUI.TabIndex = 0;
this.labelUI.Text = "User Interface"; this.labelUI.Text = "USER INTERFACE";
// //
// panelUI // panelZoom
// //
this.panelUI.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) this.panelZoom.Controls.Add(this.trackBarZoom);
| System.Windows.Forms.AnchorStyles.Right))); this.panelZoom.Controls.Add(this.labelZoomValue);
this.panelUI.Controls.Add(this.checkOpenSearchInFirstColumn); this.panelZoom.Location = new System.Drawing.Point(0, 171);
this.panelUI.Controls.Add(this.checkBestImageQuality); this.panelZoom.Margin = new System.Windows.Forms.Padding(0, 1, 0, 0);
this.panelUI.Controls.Add(this.checkExpandLinks); this.panelZoom.Name = "panelZoom";
this.panelUI.Controls.Add(this.checkSwitchAccountSelectors); this.panelZoom.Size = new System.Drawing.Size(300, 35);
this.panelUI.Controls.Add(this.checkSpellCheck); this.panelZoom.TabIndex = 7;
this.panelUI.Controls.Add(this.labelZoom);
this.panelUI.Controls.Add(this.trackBarZoom);
this.panelUI.Controls.Add(this.labelZoomValue);
this.panelUI.Location = new System.Drawing.Point(9, 31);
this.panelUI.Name = "panelUI";
this.panelUI.Size = new System.Drawing.Size(322, 179);
this.panelUI.TabIndex = 1;
// //
// panelUpdates // checkAnimatedAvatars
// //
this.panelUpdates.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) this.checkAnimatedAvatars.AutoSize = true;
| System.Windows.Forms.AnchorStyles.Right))); this.checkAnimatedAvatars.Font = new System.Drawing.Font("Segoe UI", 9F);
this.panelUpdates.Controls.Add(this.checkUpdateNotifications); this.checkAnimatedAvatars.Location = new System.Drawing.Point(6, 122);
this.panelUpdates.Controls.Add(this.btnCheckUpdates); this.checkAnimatedAvatars.Margin = new System.Windows.Forms.Padding(6, 3, 3, 2);
this.panelUpdates.Location = new System.Drawing.Point(9, 257); this.checkAnimatedAvatars.Name = "checkAnimatedAvatars";
this.panelUpdates.Name = "panelUpdates"; this.checkAnimatedAvatars.Size = new System.Drawing.Size(158, 19);
this.panelUpdates.Size = new System.Drawing.Size(322, 55); this.checkAnimatedAvatars.TabIndex = 5;
this.panelUpdates.TabIndex = 3; this.checkAnimatedAvatars.Text = "Enable Animated Avatars";
this.checkAnimatedAvatars.UseVisualStyleBackColor = true;
// //
// labelUpdates // labelUpdates
// //
this.labelUpdates.AutoSize = true; this.labelUpdates.AutoSize = true;
this.labelUpdates.Font = new System.Drawing.Font("Microsoft Sans Serif", 12F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(238))); this.labelUpdates.Font = new System.Drawing.Font("Segoe UI Semibold", 10.5F, System.Drawing.FontStyle.Bold);
this.labelUpdates.Location = new System.Drawing.Point(6, 234); this.labelUpdates.Location = new System.Drawing.Point(0, 367);
this.labelUpdates.Margin = new System.Windows.Forms.Padding(0, 21, 0, 0); this.labelUpdates.Margin = new System.Windows.Forms.Padding(0, 30, 0, 1);
this.labelUpdates.Name = "labelUpdates"; this.labelUpdates.Name = "labelUpdates";
this.labelUpdates.Size = new System.Drawing.Size(70, 20); this.labelUpdates.Size = new System.Drawing.Size(69, 19);
this.labelUpdates.TabIndex = 2; this.labelUpdates.TabIndex = 12;
this.labelUpdates.Text = "Updates"; this.labelUpdates.Text = "UPDATES";
//
// flowPanelLeft
//
this.flowPanelLeft.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom)
| System.Windows.Forms.AnchorStyles.Left)));
this.flowPanelLeft.Controls.Add(this.labelUI);
this.flowPanelLeft.Controls.Add(this.checkExpandLinks);
this.flowPanelLeft.Controls.Add(this.checkOpenSearchInFirstColumn);
this.flowPanelLeft.Controls.Add(this.checkKeepLikeFollowDialogsOpen);
this.flowPanelLeft.Controls.Add(this.checkBestImageQuality);
this.flowPanelLeft.Controls.Add(this.checkAnimatedAvatars);
this.flowPanelLeft.Controls.Add(this.labelZoom);
this.flowPanelLeft.Controls.Add(this.panelZoom);
this.flowPanelLeft.Controls.Add(this.labelTray);
this.flowPanelLeft.Controls.Add(this.comboBoxTrayType);
this.flowPanelLeft.Controls.Add(this.labelTrayIcon);
this.flowPanelLeft.Controls.Add(this.checkTrayHighlight);
this.flowPanelLeft.Controls.Add(this.labelUpdates);
this.flowPanelLeft.Controls.Add(this.checkUpdateNotifications);
this.flowPanelLeft.Controls.Add(this.btnCheckUpdates);
this.flowPanelLeft.FlowDirection = System.Windows.Forms.FlowDirection.TopDown;
this.flowPanelLeft.Location = new System.Drawing.Point(9, 9);
this.flowPanelLeft.Name = "flowPanelLeft";
this.flowPanelLeft.Size = new System.Drawing.Size(300, 462);
this.flowPanelLeft.TabIndex = 0;
this.flowPanelLeft.WrapContents = false;
//
// checkKeepLikeFollowDialogsOpen
//
this.checkKeepLikeFollowDialogsOpen.AutoSize = true;
this.checkKeepLikeFollowDialogsOpen.Font = new System.Drawing.Font("Segoe UI", 9F);
this.checkKeepLikeFollowDialogsOpen.Location = new System.Drawing.Point(6, 74);
this.checkKeepLikeFollowDialogsOpen.Margin = new System.Windows.Forms.Padding(6, 3, 3, 2);
this.checkKeepLikeFollowDialogsOpen.Name = "checkKeepLikeFollowDialogsOpen";
this.checkKeepLikeFollowDialogsOpen.Size = new System.Drawing.Size(190, 19);
this.checkKeepLikeFollowDialogsOpen.TabIndex = 3;
this.checkKeepLikeFollowDialogsOpen.Text = "Keep Like/Follow Dialogs Open";
this.checkKeepLikeFollowDialogsOpen.UseVisualStyleBackColor = true;
//
// labelTray
//
this.labelTray.AutoSize = true;
this.labelTray.Font = new System.Drawing.Font("Segoe UI Semibold", 10.5F, System.Drawing.FontStyle.Bold);
this.labelTray.Location = new System.Drawing.Point(0, 236);
this.labelTray.Margin = new System.Windows.Forms.Padding(0, 30, 0, 1);
this.labelTray.Name = "labelTray";
this.labelTray.Size = new System.Drawing.Size(99, 19);
this.labelTray.TabIndex = 8;
this.labelTray.Text = "SYSTEM TRAY";
//
// comboBoxTrayType
//
this.comboBoxTrayType.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList;
this.comboBoxTrayType.Font = new System.Drawing.Font("Segoe UI", 9F);
this.comboBoxTrayType.FormattingEnabled = true;
this.comboBoxTrayType.Location = new System.Drawing.Point(5, 260);
this.comboBoxTrayType.Margin = new System.Windows.Forms.Padding(5, 4, 3, 3);
this.comboBoxTrayType.Name = "comboBoxTrayType";
this.comboBoxTrayType.Size = new System.Drawing.Size(144, 23);
this.comboBoxTrayType.TabIndex = 9;
//
// labelTrayIcon
//
this.labelTrayIcon.AutoSize = true;
this.labelTrayIcon.Font = new System.Drawing.Font("Segoe UI Semibold", 9F, System.Drawing.FontStyle.Bold);
this.labelTrayIcon.Location = new System.Drawing.Point(3, 295);
this.labelTrayIcon.Margin = new System.Windows.Forms.Padding(3, 9, 3, 0);
this.labelTrayIcon.Name = "labelTrayIcon";
this.labelTrayIcon.Size = new System.Drawing.Size(56, 15);
this.labelTrayIcon.TabIndex = 10;
this.labelTrayIcon.Text = "Tray Icon";
//
// checkTrayHighlight
//
this.checkTrayHighlight.AutoSize = true;
this.checkTrayHighlight.Font = new System.Drawing.Font("Segoe UI", 9F);
this.checkTrayHighlight.Location = new System.Drawing.Point(6, 316);
this.checkTrayHighlight.Margin = new System.Windows.Forms.Padding(6, 6, 3, 2);
this.checkTrayHighlight.Name = "checkTrayHighlight";
this.checkTrayHighlight.Size = new System.Drawing.Size(114, 19);
this.checkTrayHighlight.TabIndex = 11;
this.checkTrayHighlight.Text = "Enable Highlight";
this.checkTrayHighlight.UseVisualStyleBackColor = true;
//
// labelBrowserSettings
//
this.labelBrowserSettings.AutoSize = true;
this.labelBrowserSettings.Font = new System.Drawing.Font("Segoe UI Semibold", 10.5F, System.Drawing.FontStyle.Bold);
this.labelBrowserSettings.Location = new System.Drawing.Point(0, 0);
this.labelBrowserSettings.Margin = new System.Windows.Forms.Padding(0, 0, 0, 1);
this.labelBrowserSettings.Name = "labelBrowserSettings";
this.labelBrowserSettings.Size = new System.Drawing.Size(143, 19);
this.labelBrowserSettings.TabIndex = 0;
this.labelBrowserSettings.Text = "BROWSER SETTINGS";
//
// checkSmoothScrolling
//
this.checkSmoothScrolling.AutoSize = true;
this.checkSmoothScrolling.Font = new System.Drawing.Font("Segoe UI", 9F);
this.checkSmoothScrolling.Location = new System.Drawing.Point(6, 26);
this.checkSmoothScrolling.Margin = new System.Windows.Forms.Padding(6, 6, 3, 2);
this.checkSmoothScrolling.Name = "checkSmoothScrolling";
this.checkSmoothScrolling.Size = new System.Drawing.Size(117, 19);
this.checkSmoothScrolling.TabIndex = 1;
this.checkSmoothScrolling.Text = "Smooth Scrolling";
this.checkSmoothScrolling.UseVisualStyleBackColor = true;
//
// checkTouchAdjustment
//
this.checkTouchAdjustment.AutoSize = true;
this.checkTouchAdjustment.Font = new System.Drawing.Font("Segoe UI", 9F);
this.checkTouchAdjustment.Location = new System.Drawing.Point(6, 50);
this.checkTouchAdjustment.Margin = new System.Windows.Forms.Padding(6, 3, 3, 2);
this.checkTouchAdjustment.Name = "checkTouchAdjustment";
this.checkTouchAdjustment.Size = new System.Drawing.Size(163, 19);
this.checkTouchAdjustment.TabIndex = 2;
this.checkTouchAdjustment.Text = "Touch Screen Adjustment";
this.checkTouchAdjustment.UseVisualStyleBackColor = true;
//
// labelBrowserPath
//
this.labelBrowserPath.AutoSize = true;
this.labelBrowserPath.Font = new System.Drawing.Font("Segoe UI Semibold", 9F, System.Drawing.FontStyle.Bold);
this.labelBrowserPath.Location = new System.Drawing.Point(3, 107);
this.labelBrowserPath.Margin = new System.Windows.Forms.Padding(3, 12, 3, 0);
this.labelBrowserPath.Name = "labelBrowserPath";
this.labelBrowserPath.Size = new System.Drawing.Size(104, 15);
this.labelBrowserPath.TabIndex = 4;
this.labelBrowserPath.Text = "Open Links With...";
//
// comboBoxBrowserPath
//
this.comboBoxBrowserPath.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList;
this.comboBoxBrowserPath.Font = new System.Drawing.Font("Segoe UI", 9F);
this.comboBoxBrowserPath.FormattingEnabled = true;
this.comboBoxBrowserPath.Location = new System.Drawing.Point(5, 126);
this.comboBoxBrowserPath.Margin = new System.Windows.Forms.Padding(5, 4, 3, 3);
this.comboBoxBrowserPath.Name = "comboBoxBrowserPath";
this.comboBoxBrowserPath.Size = new System.Drawing.Size(173, 23);
this.comboBoxBrowserPath.TabIndex = 5;
//
// labelSearchEngine
//
this.labelSearchEngine.AutoSize = true;
this.labelSearchEngine.Font = new System.Drawing.Font("Segoe UI Semibold", 9F, System.Drawing.FontStyle.Bold);
this.labelSearchEngine.Location = new System.Drawing.Point(3, 164);
this.labelSearchEngine.Margin = new System.Windows.Forms.Padding(3, 12, 3, 0);
this.labelSearchEngine.Name = "labelSearchEngine";
this.labelSearchEngine.Size = new System.Drawing.Size(82, 15);
this.labelSearchEngine.TabIndex = 6;
this.labelSearchEngine.Text = "Search Engine";
//
// comboBoxSearchEngine
//
this.comboBoxSearchEngine.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList;
this.comboBoxSearchEngine.Font = new System.Drawing.Font("Segoe UI", 9F);
this.comboBoxSearchEngine.FormattingEnabled = true;
this.comboBoxSearchEngine.Location = new System.Drawing.Point(5, 183);
this.comboBoxSearchEngine.Margin = new System.Windows.Forms.Padding(5, 4, 3, 3);
this.comboBoxSearchEngine.Name = "comboBoxSearchEngine";
this.comboBoxSearchEngine.Size = new System.Drawing.Size(173, 23);
this.comboBoxSearchEngine.TabIndex = 7;
//
// flowPanelRight
//
this.flowPanelRight.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom)
| System.Windows.Forms.AnchorStyles.Left)));
this.flowPanelRight.Controls.Add(this.labelBrowserSettings);
this.flowPanelRight.Controls.Add(this.checkSmoothScrolling);
this.flowPanelRight.Controls.Add(this.checkTouchAdjustment);
this.flowPanelRight.Controls.Add(this.checkHardwareAcceleration);
this.flowPanelRight.Controls.Add(this.labelBrowserPath);
this.flowPanelRight.Controls.Add(this.comboBoxBrowserPath);
this.flowPanelRight.Controls.Add(this.labelSearchEngine);
this.flowPanelRight.Controls.Add(this.comboBoxSearchEngine);
this.flowPanelRight.Controls.Add(this.labelLocales);
this.flowPanelRight.Controls.Add(this.checkSpellCheck);
this.flowPanelRight.Controls.Add(this.labelSpellCheckLanguage);
this.flowPanelRight.Controls.Add(this.comboBoxSpellCheckLanguage);
this.flowPanelRight.Controls.Add(this.labelTranslationTarget);
this.flowPanelRight.Controls.Add(this.comboBoxTranslationTarget);
this.flowPanelRight.FlowDirection = System.Windows.Forms.FlowDirection.TopDown;
this.flowPanelRight.Location = new System.Drawing.Point(322, 9);
this.flowPanelRight.Name = "flowPanelRight";
this.flowPanelRight.Size = new System.Drawing.Size(300, 462);
this.flowPanelRight.TabIndex = 1;
this.flowPanelRight.WrapContents = false;
//
// checkHardwareAcceleration
//
this.checkHardwareAcceleration.AutoSize = true;
this.checkHardwareAcceleration.Font = new System.Drawing.Font("Segoe UI", 9F);
this.checkHardwareAcceleration.Location = new System.Drawing.Point(6, 74);
this.checkHardwareAcceleration.Margin = new System.Windows.Forms.Padding(6, 3, 3, 2);
this.checkHardwareAcceleration.Name = "checkHardwareAcceleration";
this.checkHardwareAcceleration.Size = new System.Drawing.Size(146, 19);
this.checkHardwareAcceleration.TabIndex = 3;
this.checkHardwareAcceleration.Text = "Hardware Acceleration";
this.checkHardwareAcceleration.UseVisualStyleBackColor = true;
//
// labelLocales
//
this.labelLocales.AutoSize = true;
this.labelLocales.Font = new System.Drawing.Font("Segoe UI Semibold", 10.5F, System.Drawing.FontStyle.Bold);
this.labelLocales.Location = new System.Drawing.Point(0, 236);
this.labelLocales.Margin = new System.Windows.Forms.Padding(0, 27, 0, 1);
this.labelLocales.Name = "labelLocales";
this.labelLocales.Size = new System.Drawing.Size(67, 19);
this.labelLocales.TabIndex = 8;
this.labelLocales.Text = "LOCALES";
//
// checkSpellCheck
//
this.checkSpellCheck.AutoSize = true;
this.checkSpellCheck.Font = new System.Drawing.Font("Segoe UI", 9F);
this.checkSpellCheck.Location = new System.Drawing.Point(6, 262);
this.checkSpellCheck.Margin = new System.Windows.Forms.Padding(6, 6, 3, 2);
this.checkSpellCheck.Name = "checkSpellCheck";
this.checkSpellCheck.Size = new System.Drawing.Size(125, 19);
this.checkSpellCheck.TabIndex = 9;
this.checkSpellCheck.Text = "Enable Spell Check";
this.checkSpellCheck.UseVisualStyleBackColor = true;
//
// labelSpellCheckLanguage
//
this.labelSpellCheckLanguage.AutoSize = true;
this.labelSpellCheckLanguage.Font = new System.Drawing.Font("Segoe UI Semibold", 9F, System.Drawing.FontStyle.Bold);
this.labelSpellCheckLanguage.Location = new System.Drawing.Point(3, 295);
this.labelSpellCheckLanguage.Margin = new System.Windows.Forms.Padding(3, 12, 3, 0);
this.labelSpellCheckLanguage.Name = "labelSpellCheckLanguage";
this.labelSpellCheckLanguage.Size = new System.Drawing.Size(123, 15);
this.labelSpellCheckLanguage.TabIndex = 10;
this.labelSpellCheckLanguage.Text = "Spell Check Language";
//
// comboBoxSpellCheckLanguage
//
this.comboBoxSpellCheckLanguage.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList;
this.comboBoxSpellCheckLanguage.Font = new System.Drawing.Font("Segoe UI", 9F);
this.comboBoxSpellCheckLanguage.FormattingEnabled = true;
this.comboBoxSpellCheckLanguage.Location = new System.Drawing.Point(5, 314);
this.comboBoxSpellCheckLanguage.Margin = new System.Windows.Forms.Padding(5, 4, 3, 3);
this.comboBoxSpellCheckLanguage.Name = "comboBoxSpellCheckLanguage";
this.comboBoxSpellCheckLanguage.Size = new System.Drawing.Size(290, 23);
this.comboBoxSpellCheckLanguage.TabIndex = 11;
//
// labelTranslationTarget
//
this.labelTranslationTarget.AutoSize = true;
this.labelTranslationTarget.Font = new System.Drawing.Font("Segoe UI Semibold", 9F, System.Drawing.FontStyle.Bold);
this.labelTranslationTarget.Location = new System.Drawing.Point(3, 352);
this.labelTranslationTarget.Margin = new System.Windows.Forms.Padding(3, 12, 3, 0);
this.labelTranslationTarget.Name = "labelTranslationTarget";
this.labelTranslationTarget.Size = new System.Drawing.Size(142, 15);
this.labelTranslationTarget.TabIndex = 12;
this.labelTranslationTarget.Text = "Bing Translator Language";
//
// comboBoxTranslationTarget
//
this.comboBoxTranslationTarget.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList;
this.comboBoxTranslationTarget.Font = new System.Drawing.Font("Segoe UI", 9F);
this.comboBoxTranslationTarget.FormattingEnabled = true;
this.comboBoxTranslationTarget.Location = new System.Drawing.Point(5, 371);
this.comboBoxTranslationTarget.Margin = new System.Windows.Forms.Padding(5, 4, 3, 3);
this.comboBoxTranslationTarget.Name = "comboBoxTranslationTarget";
this.comboBoxTranslationTarget.Size = new System.Drawing.Size(290, 23);
this.comboBoxTranslationTarget.TabIndex = 13;
//
// panelSeparator
//
this.panelSeparator.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom)
| System.Windows.Forms.AnchorStyles.Left)));
this.panelSeparator.BackColor = System.Drawing.Color.FromArgb(((int)(((byte)(200)))), ((int)(((byte)(200)))), ((int)(((byte)(200)))));
this.panelSeparator.Location = new System.Drawing.Point(312, 0);
this.panelSeparator.Margin = new System.Windows.Forms.Padding(0, 0, 6, 0);
this.panelSeparator.Name = "panelSeparator";
this.panelSeparator.Size = new System.Drawing.Size(1, 480);
this.panelSeparator.TabIndex = 2;
// //
// TabSettingsGeneral // TabSettingsGeneral
// //
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
this.Controls.Add(this.labelUpdates); this.Controls.Add(this.panelSeparator);
this.Controls.Add(this.panelUpdates); this.Controls.Add(this.flowPanelRight);
this.Controls.Add(this.panelUI); this.Controls.Add(this.flowPanelLeft);
this.Controls.Add(this.labelUI);
this.Name = "TabSettingsGeneral"; this.Name = "TabSettingsGeneral";
this.Size = new System.Drawing.Size(340, 322); this.Size = new System.Drawing.Size(631, 480);
((System.ComponentModel.ISupportInitialize)(this.trackBarZoom)).EndInit(); ((System.ComponentModel.ISupportInitialize)(this.trackBarZoom)).EndInit();
this.panelUI.ResumeLayout(false); this.panelZoom.ResumeLayout(false);
this.panelUI.PerformLayout(); this.flowPanelLeft.ResumeLayout(false);
this.panelUpdates.ResumeLayout(false); this.flowPanelLeft.PerformLayout();
this.panelUpdates.PerformLayout(); this.flowPanelRight.ResumeLayout(false);
this.flowPanelRight.PerformLayout();
this.ResumeLayout(false); this.ResumeLayout(false);
this.PerformLayout();
} }
@@ -244,19 +514,39 @@
private System.Windows.Forms.CheckBox checkExpandLinks; private System.Windows.Forms.CheckBox checkExpandLinks;
private System.Windows.Forms.ToolTip toolTip; private System.Windows.Forms.ToolTip toolTip;
private System.Windows.Forms.CheckBox checkSpellCheck;
private System.Windows.Forms.CheckBox checkUpdateNotifications; private System.Windows.Forms.CheckBox checkUpdateNotifications;
private System.Windows.Forms.Button btnCheckUpdates; private System.Windows.Forms.Button btnCheckUpdates;
private System.Windows.Forms.Label labelZoom; private System.Windows.Forms.Label labelZoom;
private System.Windows.Forms.Label labelZoomValue; private System.Windows.Forms.Label labelZoomValue;
private System.Windows.Forms.TrackBar trackBarZoom; private System.Windows.Forms.TrackBar trackBarZoom;
private System.Windows.Forms.Timer zoomUpdateTimer; private System.Windows.Forms.Timer zoomUpdateTimer;
private System.Windows.Forms.CheckBox checkSwitchAccountSelectors;
private System.Windows.Forms.Label labelUI; private System.Windows.Forms.Label labelUI;
private System.Windows.Forms.Panel panelUI; private System.Windows.Forms.Panel panelZoom;
private System.Windows.Forms.Panel panelUpdates;
private System.Windows.Forms.Label labelUpdates; private System.Windows.Forms.Label labelUpdates;
private System.Windows.Forms.CheckBox checkBestImageQuality; private System.Windows.Forms.CheckBox checkBestImageQuality;
private System.Windows.Forms.CheckBox checkOpenSearchInFirstColumn; private System.Windows.Forms.CheckBox checkOpenSearchInFirstColumn;
private System.Windows.Forms.CheckBox checkAnimatedAvatars;
private System.Windows.Forms.FlowLayoutPanel flowPanelLeft;
private System.Windows.Forms.CheckBox checkKeepLikeFollowDialogsOpen;
private System.Windows.Forms.Label labelBrowserPath;
private System.Windows.Forms.ComboBox comboBoxBrowserPath;
private System.Windows.Forms.Label labelBrowserSettings;
private System.Windows.Forms.CheckBox checkSmoothScrolling;
private System.Windows.Forms.Label labelSearchEngine;
private System.Windows.Forms.ComboBox comboBoxSearchEngine;
private System.Windows.Forms.CheckBox checkTouchAdjustment;
private System.Windows.Forms.FlowLayoutPanel flowPanelRight;
private System.Windows.Forms.Panel panelSeparator;
private System.Windows.Forms.Label labelTray;
private System.Windows.Forms.ComboBox comboBoxTrayType;
private System.Windows.Forms.Label labelTrayIcon;
private System.Windows.Forms.CheckBox checkTrayHighlight;
private System.Windows.Forms.Label labelLocales;
private System.Windows.Forms.CheckBox checkSpellCheck;
private System.Windows.Forms.Label labelSpellCheckLanguage;
private System.Windows.Forms.ComboBox comboBoxSpellCheckLanguage;
private System.Windows.Forms.Label labelTranslationTarget;
private System.Windows.Forms.ComboBox comboBoxTranslationTarget;
private System.Windows.Forms.CheckBox checkHardwareAcceleration;
} }
} }

View File

@@ -1,67 +1,180 @@
using System; using System;
using System.IO;
using System.Linq;
using System.Windows.Forms;
using TweetDuck.Core.Controls; using TweetDuck.Core.Controls;
using TweetDuck.Core.Handling.General;
using TweetDuck.Core.Other.Settings.Dialogs;
using TweetDuck.Core.Utils;
using TweetDuck.Updates; using TweetDuck.Updates;
namespace TweetDuck.Core.Other.Settings{ namespace TweetDuck.Core.Other.Settings{
sealed partial class TabSettingsGeneral : BaseTabSettings{ sealed partial class TabSettingsGeneral : BaseTabSettings{
private readonly Action reloadColumns;
private readonly UpdateHandler updates; private readonly UpdateHandler updates;
private int updateCheckEventId = -1; private int updateCheckEventId = -1;
public TabSettingsGeneral(UpdateHandler updates){ private readonly int browserListIndexDefault;
private readonly int browserListIndexCustom;
private readonly int searchEngineIndexDefault;
private readonly int searchEngineIndexCustom;
public TabSettingsGeneral(Action reloadColumns, UpdateHandler updates){
InitializeComponent(); InitializeComponent();
this.reloadColumns = reloadColumns;
this.updates = updates; this.updates = updates;
this.updates.CheckFinished += updates_CheckFinished; this.updates.CheckFinished += updates_CheckFinished;
Disposed += (sender, args) => this.updates.CheckFinished -= updates_CheckFinished; Disposed += (sender, args) => this.updates.CheckFinished -= updates_CheckFinished;
// user interface
toolTip.SetToolTip(checkExpandLinks, "Expands links inside the tweets. If disabled,\r\nthe full links show up in a tooltip instead.");
toolTip.SetToolTip(checkOpenSearchInFirstColumn, "By default, TweetDeck adds Search columns at the end.\r\nThis option makes them appear before the first column instead.");
toolTip.SetToolTip(checkKeepLikeFollowDialogsOpen, "Allows liking and following from multiple accounts at once,\r\ninstead of automatically closing the dialog after taking an action.");
toolTip.SetToolTip(checkBestImageQuality, "When right-clicking a tweet image, the context menu options\r\nwill use links to the original image size (:orig in the URL).");
toolTip.SetToolTip(checkAnimatedAvatars, "Some old Twitter avatars could be uploaded as animated GIFs.");
toolTip.SetToolTip(labelZoomValue, "Changes the zoom level.\r\nAlso affects notifications and screenshots.");
toolTip.SetToolTip(trackBarZoom, toolTip.GetToolTip(labelZoomValue)); toolTip.SetToolTip(trackBarZoom, toolTip.GetToolTip(labelZoomValue));
checkExpandLinks.Checked = Config.ExpandLinksOnHover;
checkOpenSearchInFirstColumn.Checked = Config.OpenSearchInFirstColumn;
checkKeepLikeFollowDialogsOpen.Checked = Config.KeepLikeFollowDialogsOpen;
checkBestImageQuality.Checked = Config.BestImageQuality;
checkAnimatedAvatars.Checked = Config.EnableAnimatedImages;
trackBarZoom.SetValueSafe(Config.ZoomLevel); trackBarZoom.SetValueSafe(Config.ZoomLevel);
labelZoomValue.Text = trackBarZoom.Value+"%"; labelZoomValue.Text = trackBarZoom.Value+"%";
checkExpandLinks.Checked = Config.ExpandLinksOnHover; // system tray
checkSwitchAccountSelectors.Checked = Config.SwitchAccountSelectors;
checkOpenSearchInFirstColumn.Checked = Config.OpenSearchInFirstColumn; toolTip.SetToolTip(comboBoxTrayType, "Changes behavior of the Tray icon.\r\nRight-click the icon for an action menu.");
checkBestImageQuality.Checked = Config.BestImageQuality; toolTip.SetToolTip(checkTrayHighlight, "Highlights the tray icon if there are new tweets.\r\nOnly works for columns with popup or audio notifications.\r\nThe icon resets when the main window is restored.");
checkSpellCheck.Checked = Config.EnableSpellCheck;
comboBoxTrayType.Items.Add("Disabled");
comboBoxTrayType.Items.Add("Display Icon Only");
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);
checkTrayHighlight.Enabled = Config.TrayBehavior.ShouldDisplayIcon();
checkTrayHighlight.Checked = Config.EnableTrayHighlight;
// updates
toolTip.SetToolTip(checkUpdateNotifications, "Checks for updates every hour.\r\nIf an update is dismissed, it will not appear again.");
toolTip.SetToolTip(btnCheckUpdates, "Forces an update check, even for updates that had been dismissed.");
checkUpdateNotifications.Checked = Config.EnableUpdateCheck; checkUpdateNotifications.Checked = Config.EnableUpdateCheck;
// browser settings
toolTip.SetToolTip(checkSmoothScrolling, "Toggles smooth mouse wheel scrolling.");
toolTip.SetToolTip(checkTouchAdjustment, "Toggles Chromium touch screen adjustment.\r\nDisabled by default, because it is very imprecise with TweetDeck.");
toolTip.SetToolTip(checkHardwareAcceleration, "Uses graphics card to improve performance.\r\nDisable if you experience visual glitches, or to save a small amount of RAM.");
toolTip.SetToolTip(comboBoxBrowserPath, "Sets the default browser for opening links.");
toolTip.SetToolTip(comboBoxSearchEngine, "Sets the default website for opening searches.");
checkSmoothScrolling.Checked = Config.EnableSmoothScrolling;
checkTouchAdjustment.Checked = Config.EnableTouchAdjustment;
checkHardwareAcceleration.Checked = SysConfig.HardwareAcceleration;
foreach(WindowsUtils.Browser browserInfo in WindowsUtils.FindInstalledBrowsers()){
comboBoxBrowserPath.Items.Add(browserInfo);
}
browserListIndexDefault = comboBoxBrowserPath.Items.Add("(default browser)");
browserListIndexCustom = comboBoxBrowserPath.Items.Add("(custom program...)");
UpdateBrowserPathSelection();
comboBoxSearchEngine.Items.Add(new SearchEngine("DuckDuckGo", "https://duckduckgo.com/?q="));
comboBoxSearchEngine.Items.Add(new SearchEngine("Google", "https://www.google.com/search?q="));
comboBoxSearchEngine.Items.Add(new SearchEngine("Bing", "https://www.bing.com/search?q="));
comboBoxSearchEngine.Items.Add(new SearchEngine("Yahoo", "https://search.yahoo.com/search?p="));
searchEngineIndexDefault = comboBoxSearchEngine.Items.Add("(no engine set)");
searchEngineIndexCustom = comboBoxSearchEngine.Items.Add("(custom url...)");
UpdateSearchEngineSelection();
// locales
toolTip.SetToolTip(checkSpellCheck, "Underlines words that are spelled incorrectly.");
toolTip.SetToolTip(comboBoxSpellCheckLanguage, "Language used for spell check.");
toolTip.SetToolTip(comboBoxTranslationTarget, "Language tweets are translated into.");
checkSpellCheck.Checked = Config.EnableSpellCheck;
try{
foreach(LocaleUtils.Item item in LocaleUtils.SpellCheckLanguages){
comboBoxSpellCheckLanguage.Items.Add(item);
}
}catch{
comboBoxSpellCheckLanguage.Items.Add(new LocaleUtils.Item("en-US"));
}
comboBoxSpellCheckLanguage.SelectedItem = new LocaleUtils.Item(Config.SpellCheckLanguage);
foreach(LocaleUtils.Item item in LocaleUtils.TweetDeckTranslationLocales){
comboBoxTranslationTarget.Items.Add(item);
}
comboBoxTranslationTarget.SelectedItem = new LocaleUtils.Item(Config.TranslationTarget);
} }
public override void OnReady(){ public override void OnReady(){
checkExpandLinks.CheckedChanged += checkExpandLinks_CheckedChanged; checkExpandLinks.CheckedChanged += checkExpandLinks_CheckedChanged;
checkSwitchAccountSelectors.CheckedChanged += checkSwitchAccountSelectors_CheckedChanged;
checkOpenSearchInFirstColumn.CheckedChanged += checkOpenSearchInFirstColumn_CheckedChanged; checkOpenSearchInFirstColumn.CheckedChanged += checkOpenSearchInFirstColumn_CheckedChanged;
checkKeepLikeFollowDialogsOpen.CheckedChanged += checkKeepLikeFollowDialogsOpen_CheckedChanged;
checkBestImageQuality.CheckedChanged += checkBestImageQuality_CheckedChanged; checkBestImageQuality.CheckedChanged += checkBestImageQuality_CheckedChanged;
checkSpellCheck.CheckedChanged += checkSpellCheck_CheckedChanged; checkAnimatedAvatars.CheckedChanged += checkAnimatedAvatars_CheckedChanged;
trackBarZoom.ValueChanged += trackBarZoom_ValueChanged; trackBarZoom.ValueChanged += trackBarZoom_ValueChanged;
comboBoxTrayType.SelectedIndexChanged += comboBoxTrayType_SelectedIndexChanged;
checkTrayHighlight.CheckedChanged += checkTrayHighlight_CheckedChanged;
checkUpdateNotifications.CheckedChanged += checkUpdateNotifications_CheckedChanged; checkUpdateNotifications.CheckedChanged += checkUpdateNotifications_CheckedChanged;
btnCheckUpdates.Click += btnCheckUpdates_Click; btnCheckUpdates.Click += btnCheckUpdates_Click;
checkSmoothScrolling.CheckedChanged += checkSmoothScrolling_CheckedChanged;
checkTouchAdjustment.CheckedChanged += checkTouchAdjustment_CheckedChanged;
checkHardwareAcceleration.CheckedChanged += checkHardwareAcceleration_CheckedChanged;
comboBoxBrowserPath.SelectedIndexChanged += comboBoxBrowserPath_SelectedIndexChanged;
comboBoxSearchEngine.SelectedIndexChanged += comboBoxSearchEngine_SelectedIndexChanged;
checkSpellCheck.CheckedChanged += checkSpellCheck_CheckedChanged;
comboBoxSpellCheckLanguage.SelectedValueChanged += comboBoxSpellCheckLanguage_SelectedValueChanged;
comboBoxTranslationTarget.SelectedValueChanged += comboBoxTranslationTarget_SelectedValueChanged;
} }
public override void OnClosing(){ public override void OnClosing(){
Config.ZoomLevel = trackBarZoom.Value; Config.ZoomLevel = trackBarZoom.Value;
} }
#region User Interface
private void checkExpandLinks_CheckedChanged(object sender, EventArgs e){ private void checkExpandLinks_CheckedChanged(object sender, EventArgs e){
Config.ExpandLinksOnHover = checkExpandLinks.Checked; Config.ExpandLinksOnHover = checkExpandLinks.Checked;
} }
private void checkSwitchAccountSelectors_CheckedChanged(object sender, EventArgs e){
Config.SwitchAccountSelectors = checkSwitchAccountSelectors.Checked;
}
private void checkOpenSearchInFirstColumn_CheckedChanged(object sender, EventArgs e){ private void checkOpenSearchInFirstColumn_CheckedChanged(object sender, EventArgs e){
Config.OpenSearchInFirstColumn = checkOpenSearchInFirstColumn.Checked; Config.OpenSearchInFirstColumn = checkOpenSearchInFirstColumn.Checked;
} }
private void checkKeepLikeFollowDialogsOpen_CheckedChanged(object sender, EventArgs e){
Config.KeepLikeFollowDialogsOpen = checkKeepLikeFollowDialogsOpen.Checked;
}
private void checkBestImageQuality_CheckedChanged(object sender, EventArgs e){ private void checkBestImageQuality_CheckedChanged(object sender, EventArgs e){
Config.BestImageQuality = checkBestImageQuality.Checked; Config.BestImageQuality = checkBestImageQuality.Checked;
} }
private void checkSpellCheck_CheckedChanged(object sender, EventArgs e){ private void checkAnimatedAvatars_CheckedChanged(object sender, EventArgs e){
Config.EnableSpellCheck = checkSpellCheck.Checked; Config.EnableAnimatedImages = checkAnimatedAvatars.Checked;
PromptRestart(); BrowserProcessHandler.UpdatePrefs().ContinueWith(task => reloadColumns());
} }
private void trackBarZoom_ValueChanged(object sender, EventArgs e){ private void trackBarZoom_ValueChanged(object sender, EventArgs e){
@@ -72,6 +185,26 @@ namespace TweetDuck.Core.Other.Settings{
} }
} }
private void zoomUpdateTimer_Tick(object sender, EventArgs e){
Config.ZoomLevel = trackBarZoom.Value;
zoomUpdateTimer.Stop();
}
#endregion
#region System Tray
private void comboBoxTrayType_SelectedIndexChanged(object sender, EventArgs e){
Config.TrayBehavior = (TrayIcon.Behavior)comboBoxTrayType.SelectedIndex;
checkTrayHighlight.Enabled = Config.TrayBehavior.ShouldDisplayIcon();
}
private void checkTrayHighlight_CheckedChanged(object sender, EventArgs e){
Config.EnableTrayHighlight = checkTrayHighlight.Checked;
}
#endregion
#region Updates
private void checkUpdateNotifications_CheckedChanged(object sender, EventArgs e){ private void checkUpdateNotifications_CheckedChanged(object sender, EventArgs e){
Config.EnableUpdateCheck = checkUpdateNotifications.Checked; Config.EnableUpdateCheck = checkUpdateNotifications.Checked;
} }
@@ -83,21 +216,137 @@ namespace TweetDuck.Core.Other.Settings{
updateCheckEventId = updates.Check(true); updateCheckEventId = updates.Check(true);
} }
private void updates_CheckFinished(object sender, UpdateEventArgs e){ private void updates_CheckFinished(object sender, UpdateCheckEventArgs e){
this.InvokeAsyncSafe(() => {
if (e.EventId == updateCheckEventId){ if (e.EventId == updateCheckEventId){
btnCheckUpdates.Enabled = true; btnCheckUpdates.Enabled = true;
if (!e.IsUpdateAvailable){ e.Result.Handle(update => {
if (update.VersionTag == Program.VersionTag){
FormMessage.Information("No Updates Available", "Your version of TweetDuck is up to date.", FormMessage.OK); FormMessage.Information("No Updates Available", "Your version of TweetDuck is up to date.", FormMessage.OK);
} }
} }, ex => {
Program.Reporter.HandleException("Update Check Error", "An error occurred while checking for updates.", true, ex);
}); });
} }
}
private void zoomUpdateTimer_Tick(object sender, EventArgs e){ #endregion
Config.ZoomLevel = trackBarZoom.Value; #region Browser Settings
zoomUpdateTimer.Stop();
private void checkSmoothScrolling_CheckedChanged(object sender, EventArgs e){
Config.EnableSmoothScrolling = checkSmoothScrolling.Checked;
}
private void checkTouchAdjustment_CheckedChanged(object sender, EventArgs e){
Config.EnableTouchAdjustment = checkTouchAdjustment.Checked;
}
private void checkHardwareAcceleration_CheckedChanged(object sender, EventArgs e){
SysConfig.HardwareAcceleration = checkHardwareAcceleration.Checked;
}
private void UpdateBrowserPathSelection(){
if (string.IsNullOrEmpty(Config.BrowserPath) || !File.Exists(Config.BrowserPath)){
comboBoxBrowserPath.SelectedIndex = browserListIndexDefault;
}
else{
WindowsUtils.Browser browserInfo = comboBoxBrowserPath.Items.OfType<WindowsUtils.Browser>().FirstOrDefault(browser => browser.Path == Config.BrowserPath);
if (browserInfo == null){
comboBoxBrowserPath.SelectedIndex = browserListIndexCustom;
}
else{
comboBoxBrowserPath.SelectedItem = browserInfo;
} }
} }
} }
private void comboBoxBrowserPath_SelectedIndexChanged(object sender, EventArgs e){
if (comboBoxBrowserPath.SelectedIndex == browserListIndexCustom){
using(OpenFileDialog dialog = new OpenFileDialog{
AutoUpgradeEnabled = true,
DereferenceLinks = true,
InitialDirectory = Path.GetDirectoryName(Config.BrowserPath), // returns null if argument is null
Title = "Open Links With...",
Filter = "Executables (*.exe;*.bat;*.cmd)|*.exe;*.bat;*.cmd|All Files (*.*)|*.*"
}){
if (dialog.ShowDialog() == DialogResult.OK){
Config.BrowserPath = dialog.FileName;
}
}
comboBoxBrowserPath.SelectedIndexChanged -= comboBoxBrowserPath_SelectedIndexChanged;
UpdateBrowserPathSelection();
comboBoxBrowserPath.SelectedIndexChanged += comboBoxBrowserPath_SelectedIndexChanged;
}
else{
Config.BrowserPath = (comboBoxBrowserPath.SelectedItem as WindowsUtils.Browser)?.Path; // default browser item is a string and casts to null
}
}
private void comboBoxSearchEngine_SelectedIndexChanged(object sender, EventArgs e){
if (comboBoxSearchEngine.SelectedIndex == searchEngineIndexCustom){
using(DialogSettingsSearchEngine dialog = new DialogSettingsSearchEngine()){
if (dialog.ShowDialog() == DialogResult.OK){
Config.SearchEngineUrl = dialog.Url.Trim();
}
}
comboBoxSearchEngine.SelectedIndexChanged -= comboBoxSearchEngine_SelectedIndexChanged;
UpdateSearchEngineSelection();
comboBoxSearchEngine.SelectedIndexChanged += comboBoxSearchEngine_SelectedIndexChanged;
}
else{
Config.SearchEngineUrl = (comboBoxSearchEngine.SelectedItem as SearchEngine)?.Url; // default search engine item is a string and casts to null
}
}
private void UpdateSearchEngineSelection(){
if (string.IsNullOrEmpty(Config.SearchEngineUrl)){
comboBoxSearchEngine.SelectedIndex = searchEngineIndexDefault;
}
else{
SearchEngine engineInfo = comboBoxSearchEngine.Items.OfType<SearchEngine>().FirstOrDefault(engine => engine.Url == Config.SearchEngineUrl);
if (engineInfo == null){
comboBoxSearchEngine.SelectedIndex = searchEngineIndexCustom;
}
else{
comboBoxSearchEngine.SelectedItem = engineInfo;
}
}
}
private sealed class SearchEngine{
private string Name { get; }
public string Url { get; }
public SearchEngine(string name, string url){
Name = name;
Url = url;
}
public override int GetHashCode() => Name.GetHashCode();
public override bool Equals(object obj) => obj is SearchEngine other && Name == other.Name;
public override string ToString() => Name;
}
#endregion
#region Locales
private void checkSpellCheck_CheckedChanged(object sender, EventArgs e){
Config.EnableSpellCheck = checkSpellCheck.Checked;
BrowserProcessHandler.UpdatePrefs();
}
private void comboBoxSpellCheckLanguage_SelectedValueChanged(object sender, EventArgs e){
Config.SpellCheckLanguage = (comboBoxSpellCheckLanguage.SelectedItem as LocaleUtils.Item)?.Code ?? "en-US";
}
private void comboBoxTranslationTarget_SelectedValueChanged(object sender, EventArgs e){
Config.TranslationTarget = (comboBoxTranslationTarget.SelectedItem as LocaleUtils.Item)?.Code ?? "en";
}
#endregion
}
}

View File

@@ -51,7 +51,8 @@
this.radioSizeAuto = new System.Windows.Forms.RadioButton(); this.radioSizeAuto = new System.Windows.Forms.RadioButton();
this.radioSizeCustom = new System.Windows.Forms.RadioButton(); this.radioSizeCustom = new System.Windows.Forms.RadioButton();
this.labelGeneral = new System.Windows.Forms.Label(); this.labelGeneral = new System.Windows.Forms.Label();
this.panelGeneral = new System.Windows.Forms.Panel(); this.panelEdgeDistance = new System.Windows.Forms.Panel();
this.checkMediaPreviews = new System.Windows.Forms.CheckBox();
this.labelScrollSpeedValue = new System.Windows.Forms.Label(); this.labelScrollSpeedValue = new System.Windows.Forms.Label();
this.trackBarScrollSpeed = new System.Windows.Forms.TrackBar(); this.trackBarScrollSpeed = new System.Windows.Forms.TrackBar();
this.labelScrollSpeed = new System.Windows.Forms.Label(); this.labelScrollSpeed = new System.Windows.Forms.Label();
@@ -61,79 +62,88 @@
this.labelDuration = new System.Windows.Forms.Label(); this.labelDuration = new System.Windows.Forms.Label();
this.labelTimer = new System.Windows.Forms.Label(); this.labelTimer = new System.Windows.Forms.Label();
this.labelSize = new System.Windows.Forms.Label(); this.labelSize = new System.Windows.Forms.Label();
this.panelMiscellaneous = new System.Windows.Forms.Panel(); this.panelSize = new System.Windows.Forms.Panel();
this.durationUpdateTimer = new System.Windows.Forms.Timer(this.components); this.durationUpdateTimer = new System.Windows.Forms.Timer(this.components);
this.checkMediaPreviews = new System.Windows.Forms.CheckBox(); this.flowPanelLeft = new System.Windows.Forms.FlowLayoutPanel();
this.panelScrollSpeed = new System.Windows.Forms.Panel();
this.flowPanelRight = new System.Windows.Forms.FlowLayoutPanel();
this.panelSeparator = new System.Windows.Forms.Panel();
((System.ComponentModel.ISupportInitialize)(this.trackBarEdgeDistance)).BeginInit(); ((System.ComponentModel.ISupportInitialize)(this.trackBarEdgeDistance)).BeginInit();
this.tableLayoutDurationButtons.SuspendLayout(); this.tableLayoutDurationButtons.SuspendLayout();
((System.ComponentModel.ISupportInitialize)(this.trackBarDuration)).BeginInit(); ((System.ComponentModel.ISupportInitialize)(this.trackBarDuration)).BeginInit();
this.panelGeneral.SuspendLayout(); this.panelEdgeDistance.SuspendLayout();
((System.ComponentModel.ISupportInitialize)(this.trackBarScrollSpeed)).BeginInit(); ((System.ComponentModel.ISupportInitialize)(this.trackBarScrollSpeed)).BeginInit();
this.panelLocation.SuspendLayout(); this.panelLocation.SuspendLayout();
this.panelTimer.SuspendLayout(); this.panelTimer.SuspendLayout();
this.panelMiscellaneous.SuspendLayout(); this.panelSize.SuspendLayout();
this.flowPanelLeft.SuspendLayout();
this.panelScrollSpeed.SuspendLayout();
this.flowPanelRight.SuspendLayout();
this.SuspendLayout(); this.SuspendLayout();
// //
// labelEdgeDistanceValue // labelEdgeDistanceValue
// //
this.labelEdgeDistanceValue.Location = new System.Drawing.Point(147, 129); this.labelEdgeDistanceValue.Font = new System.Drawing.Font("Segoe UI", 9F);
this.labelEdgeDistanceValue.Location = new System.Drawing.Point(145, 4);
this.labelEdgeDistanceValue.Margin = new System.Windows.Forms.Padding(0, 0, 3, 0); this.labelEdgeDistanceValue.Margin = new System.Windows.Forms.Padding(0, 0, 3, 0);
this.labelEdgeDistanceValue.Name = "labelEdgeDistanceValue"; this.labelEdgeDistanceValue.Name = "labelEdgeDistanceValue";
this.labelEdgeDistanceValue.Size = new System.Drawing.Size(40, 13); this.labelEdgeDistanceValue.Size = new System.Drawing.Size(40, 15);
this.labelEdgeDistanceValue.TabIndex = 9; this.labelEdgeDistanceValue.TabIndex = 1;
this.labelEdgeDistanceValue.Text = "0 px"; this.labelEdgeDistanceValue.Text = "0 px";
this.labelEdgeDistanceValue.TextAlign = System.Drawing.ContentAlignment.TopRight; this.labelEdgeDistanceValue.TextAlign = System.Drawing.ContentAlignment.TopRight;
// //
// labelDisplay // labelDisplay
// //
this.labelDisplay.AutoSize = true; this.labelDisplay.AutoSize = true;
this.labelDisplay.Location = new System.Drawing.Point(3, 60); this.labelDisplay.Font = new System.Drawing.Font("Segoe UI Semibold", 9F, System.Drawing.FontStyle.Bold);
this.labelDisplay.Location = new System.Drawing.Point(3, 83);
this.labelDisplay.Margin = new System.Windows.Forms.Padding(3, 12, 3, 0); this.labelDisplay.Margin = new System.Windows.Forms.Padding(3, 12, 3, 0);
this.labelDisplay.Name = "labelDisplay"; this.labelDisplay.Name = "labelDisplay";
this.labelDisplay.Size = new System.Drawing.Size(41, 13); this.labelDisplay.Size = new System.Drawing.Size(46, 15);
this.labelDisplay.TabIndex = 5; this.labelDisplay.TabIndex = 2;
this.labelDisplay.Text = "Display"; this.labelDisplay.Text = "Display";
// //
// comboBoxDisplay // comboBoxDisplay
// //
this.comboBoxDisplay.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left)
| System.Windows.Forms.AnchorStyles.Right)));
this.comboBoxDisplay.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList; this.comboBoxDisplay.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList;
this.comboBoxDisplay.Font = new System.Drawing.Font("Segoe UI", 9F);
this.comboBoxDisplay.FormattingEnabled = true; this.comboBoxDisplay.FormattingEnabled = true;
this.comboBoxDisplay.Location = new System.Drawing.Point(5, 76); this.comboBoxDisplay.Location = new System.Drawing.Point(5, 102);
this.comboBoxDisplay.Margin = new System.Windows.Forms.Padding(5, 3, 3, 3); this.comboBoxDisplay.Margin = new System.Windows.Forms.Padding(5, 4, 3, 3);
this.comboBoxDisplay.Name = "comboBoxDisplay"; this.comboBoxDisplay.Name = "comboBoxDisplay";
this.comboBoxDisplay.Size = new System.Drawing.Size(144, 21); this.comboBoxDisplay.Size = new System.Drawing.Size(144, 23);
this.comboBoxDisplay.TabIndex = 6; this.comboBoxDisplay.TabIndex = 3;
// //
// labelEdgeDistance // labelEdgeDistance
// //
this.labelEdgeDistance.AutoSize = true; this.labelEdgeDistance.AutoSize = true;
this.labelEdgeDistance.Location = new System.Drawing.Point(3, 112); this.labelEdgeDistance.Font = new System.Drawing.Font("Segoe UI Semibold", 9F, System.Drawing.FontStyle.Bold);
this.labelEdgeDistance.Location = new System.Drawing.Point(3, 140);
this.labelEdgeDistance.Margin = new System.Windows.Forms.Padding(3, 12, 3, 0); this.labelEdgeDistance.Margin = new System.Windows.Forms.Padding(3, 12, 3, 0);
this.labelEdgeDistance.Name = "labelEdgeDistance"; this.labelEdgeDistance.Name = "labelEdgeDistance";
this.labelEdgeDistance.Size = new System.Drawing.Size(103, 13); this.labelEdgeDistance.Size = new System.Drawing.Size(113, 15);
this.labelEdgeDistance.TabIndex = 7; this.labelEdgeDistance.TabIndex = 4;
this.labelEdgeDistance.Text = "Distance From Edge"; this.labelEdgeDistance.Text = "Distance From Edge";
// //
// radioLocCustom // radioLocCustom
// //
this.radioLocCustom.Location = new System.Drawing.Point(205, 4); this.radioLocCustom.Font = new System.Drawing.Font("Segoe UI", 9F);
this.radioLocCustom.Margin = new System.Windows.Forms.Padding(5, 4, 3, 3); this.radioLocCustom.Location = new System.Drawing.Point(218, 4);
this.radioLocCustom.Margin = new System.Windows.Forms.Padding(10, 4, 3, 3);
this.radioLocCustom.Name = "radioLocCustom"; this.radioLocCustom.Name = "radioLocCustom";
this.radioLocCustom.Size = new System.Drawing.Size(65, 41); this.radioLocCustom.Size = new System.Drawing.Size(70, 43);
this.radioLocCustom.TabIndex = 4; this.radioLocCustom.TabIndex = 4;
this.radioLocCustom.TabStop = true; this.radioLocCustom.TabStop = true;
this.radioLocCustom.Text = "Custom"; this.radioLocCustom.Text = "Custom";
this.toolTip.SetToolTip(this.radioLocCustom, "Drag the example notification window to the desired location.");
this.radioLocCustom.UseVisualStyleBackColor = true; this.radioLocCustom.UseVisualStyleBackColor = true;
// //
// radioLocBR // radioLocBR
// //
this.radioLocBR.Location = new System.Drawing.Point(105, 28); this.radioLocBR.Font = new System.Drawing.Font("Segoe UI", 9F);
this.radioLocBR.Location = new System.Drawing.Point(109, 28);
this.radioLocBR.Margin = new System.Windows.Forms.Padding(5, 4, 3, 3); this.radioLocBR.Margin = new System.Windows.Forms.Padding(5, 4, 3, 3);
this.radioLocBR.Name = "radioLocBR"; this.radioLocBR.Name = "radioLocBR";
this.radioLocBR.Size = new System.Drawing.Size(92, 17); this.radioLocBR.Size = new System.Drawing.Size(96, 19);
this.radioLocBR.TabIndex = 3; this.radioLocBR.TabIndex = 3;
this.radioLocBR.TabStop = true; this.radioLocBR.TabStop = true;
this.radioLocBR.Text = "Bottom Right"; this.radioLocBR.Text = "Bottom Right";
@@ -141,10 +151,11 @@
// //
// radioLocBL // radioLocBL
// //
this.radioLocBL.Font = new System.Drawing.Font("Segoe UI", 9F);
this.radioLocBL.Location = new System.Drawing.Point(5, 28); this.radioLocBL.Location = new System.Drawing.Point(5, 28);
this.radioLocBL.Margin = new System.Windows.Forms.Padding(5, 4, 3, 3); this.radioLocBL.Margin = new System.Windows.Forms.Padding(5, 4, 3, 3);
this.radioLocBL.Name = "radioLocBL"; this.radioLocBL.Name = "radioLocBL";
this.radioLocBL.Size = new System.Drawing.Size(92, 17); this.radioLocBL.Size = new System.Drawing.Size(96, 19);
this.radioLocBL.TabIndex = 2; this.radioLocBL.TabIndex = 2;
this.radioLocBL.TabStop = true; this.radioLocBL.TabStop = true;
this.radioLocBL.Text = "Bottom Left"; this.radioLocBL.Text = "Bottom Left";
@@ -152,10 +163,11 @@
// //
// radioLocTR // radioLocTR
// //
this.radioLocTR.Location = new System.Drawing.Point(105, 4); this.radioLocTR.Font = new System.Drawing.Font("Segoe UI", 9F);
this.radioLocTR.Location = new System.Drawing.Point(109, 4);
this.radioLocTR.Margin = new System.Windows.Forms.Padding(5, 4, 3, 3); this.radioLocTR.Margin = new System.Windows.Forms.Padding(5, 4, 3, 3);
this.radioLocTR.Name = "radioLocTR"; this.radioLocTR.Name = "radioLocTR";
this.radioLocTR.Size = new System.Drawing.Size(92, 17); this.radioLocTR.Size = new System.Drawing.Size(96, 19);
this.radioLocTR.TabIndex = 1; this.radioLocTR.TabIndex = 1;
this.radioLocTR.TabStop = true; this.radioLocTR.TabStop = true;
this.radioLocTR.Text = "Top Right"; this.radioLocTR.Text = "Top Right";
@@ -163,10 +175,11 @@
// //
// radioLocTL // radioLocTL
// //
this.radioLocTL.Font = new System.Drawing.Font("Segoe UI", 9F);
this.radioLocTL.Location = new System.Drawing.Point(5, 4); this.radioLocTL.Location = new System.Drawing.Point(5, 4);
this.radioLocTL.Margin = new System.Windows.Forms.Padding(5, 4, 3, 3); this.radioLocTL.Margin = new System.Windows.Forms.Padding(5, 4, 3, 3);
this.radioLocTL.Name = "radioLocTL"; this.radioLocTL.Name = "radioLocTL";
this.radioLocTL.Size = new System.Drawing.Size(92, 17); this.radioLocTL.Size = new System.Drawing.Size(96, 19);
this.radioLocTL.TabIndex = 0; this.radioLocTL.TabIndex = 0;
this.radioLocTL.TabStop = true; this.radioLocTL.TabStop = true;
this.radioLocTL.Text = "Top Left"; this.radioLocTL.Text = "Top Left";
@@ -176,13 +189,13 @@
// //
this.trackBarEdgeDistance.AutoSize = false; this.trackBarEdgeDistance.AutoSize = false;
this.trackBarEdgeDistance.LargeChange = 8; this.trackBarEdgeDistance.LargeChange = 8;
this.trackBarEdgeDistance.Location = new System.Drawing.Point(5, 128); this.trackBarEdgeDistance.Location = new System.Drawing.Point(3, 3);
this.trackBarEdgeDistance.Maximum = 40; this.trackBarEdgeDistance.Maximum = 40;
this.trackBarEdgeDistance.Minimum = 8; this.trackBarEdgeDistance.Minimum = 8;
this.trackBarEdgeDistance.Name = "trackBarEdgeDistance"; this.trackBarEdgeDistance.Name = "trackBarEdgeDistance";
this.trackBarEdgeDistance.Size = new System.Drawing.Size(148, 30); this.trackBarEdgeDistance.Size = new System.Drawing.Size(148, 30);
this.trackBarEdgeDistance.SmallChange = 2; this.trackBarEdgeDistance.SmallChange = 2;
this.trackBarEdgeDistance.TabIndex = 8; this.trackBarEdgeDistance.TabIndex = 0;
this.trackBarEdgeDistance.TickFrequency = 4; this.trackBarEdgeDistance.TickFrequency = 4;
this.trackBarEdgeDistance.Value = 8; this.trackBarEdgeDistance.Value = 8;
// //
@@ -195,12 +208,12 @@
this.tableLayoutDurationButtons.Controls.Add(this.btnDurationMedium, 0, 0); this.tableLayoutDurationButtons.Controls.Add(this.btnDurationMedium, 0, 0);
this.tableLayoutDurationButtons.Controls.Add(this.btnDurationLong, 1, 0); this.tableLayoutDurationButtons.Controls.Add(this.btnDurationLong, 1, 0);
this.tableLayoutDurationButtons.Controls.Add(this.btnDurationShort, 0, 0); this.tableLayoutDurationButtons.Controls.Add(this.btnDurationShort, 0, 0);
this.tableLayoutDurationButtons.Location = new System.Drawing.Point(3, 113); this.tableLayoutDurationButtons.Location = new System.Drawing.Point(3, 353);
this.tableLayoutDurationButtons.Name = "tableLayoutDurationButtons"; this.tableLayoutDurationButtons.Name = "tableLayoutDurationButtons";
this.tableLayoutDurationButtons.RowCount = 1; this.tableLayoutDurationButtons.RowCount = 1;
this.tableLayoutDurationButtons.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 100F)); this.tableLayoutDurationButtons.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 100F));
this.tableLayoutDurationButtons.Size = new System.Drawing.Size(171, 27); this.tableLayoutDurationButtons.Size = new System.Drawing.Size(180, 27);
this.tableLayoutDurationButtons.TabIndex = 5; this.tableLayoutDurationButtons.TabIndex = 12;
// //
// btnDurationMedium // btnDurationMedium
// //
@@ -209,10 +222,11 @@
this.btnDurationMedium.FlatAppearance.MouseDownBackColor = System.Drawing.SystemColors.ControlLight; this.btnDurationMedium.FlatAppearance.MouseDownBackColor = System.Drawing.SystemColors.ControlLight;
this.btnDurationMedium.FlatAppearance.MouseOverBackColor = System.Drawing.Color.White; this.btnDurationMedium.FlatAppearance.MouseOverBackColor = System.Drawing.Color.White;
this.btnDurationMedium.FlatStyle = System.Windows.Forms.FlatStyle.Flat; this.btnDurationMedium.FlatStyle = System.Windows.Forms.FlatStyle.Flat;
this.btnDurationMedium.Location = new System.Drawing.Point(55, 1); this.btnDurationMedium.Font = new System.Drawing.Font("Segoe UI", 9F);
this.btnDurationMedium.Location = new System.Drawing.Point(58, 1);
this.btnDurationMedium.Margin = new System.Windows.Forms.Padding(1); this.btnDurationMedium.Margin = new System.Windows.Forms.Padding(1);
this.btnDurationMedium.Name = "btnDurationMedium"; this.btnDurationMedium.Name = "btnDurationMedium";
this.btnDurationMedium.Size = new System.Drawing.Size(59, 25); this.btnDurationMedium.Size = new System.Drawing.Size(62, 25);
this.btnDurationMedium.TabIndex = 1; this.btnDurationMedium.TabIndex = 1;
this.btnDurationMedium.Text = "Medium"; this.btnDurationMedium.Text = "Medium";
this.btnDurationMedium.UseVisualStyleBackColor = true; this.btnDurationMedium.UseVisualStyleBackColor = true;
@@ -224,10 +238,11 @@
this.btnDurationLong.FlatAppearance.MouseDownBackColor = System.Drawing.SystemColors.ControlLight; this.btnDurationLong.FlatAppearance.MouseDownBackColor = System.Drawing.SystemColors.ControlLight;
this.btnDurationLong.FlatAppearance.MouseOverBackColor = System.Drawing.Color.White; this.btnDurationLong.FlatAppearance.MouseOverBackColor = System.Drawing.Color.White;
this.btnDurationLong.FlatStyle = System.Windows.Forms.FlatStyle.Flat; this.btnDurationLong.FlatStyle = System.Windows.Forms.FlatStyle.Flat;
this.btnDurationLong.Location = new System.Drawing.Point(116, 1); this.btnDurationLong.Font = new System.Drawing.Font("Segoe UI", 9F);
this.btnDurationLong.Location = new System.Drawing.Point(122, 1);
this.btnDurationLong.Margin = new System.Windows.Forms.Padding(1); this.btnDurationLong.Margin = new System.Windows.Forms.Padding(1);
this.btnDurationLong.Name = "btnDurationLong"; this.btnDurationLong.Name = "btnDurationLong";
this.btnDurationLong.Size = new System.Drawing.Size(54, 25); this.btnDurationLong.Size = new System.Drawing.Size(57, 25);
this.btnDurationLong.TabIndex = 2; this.btnDurationLong.TabIndex = 2;
this.btnDurationLong.Text = "Long"; this.btnDurationLong.Text = "Long";
this.btnDurationLong.UseVisualStyleBackColor = true; this.btnDurationLong.UseVisualStyleBackColor = true;
@@ -239,10 +254,11 @@
this.btnDurationShort.FlatAppearance.MouseDownBackColor = System.Drawing.SystemColors.ControlLight; this.btnDurationShort.FlatAppearance.MouseDownBackColor = System.Drawing.SystemColors.ControlLight;
this.btnDurationShort.FlatAppearance.MouseOverBackColor = System.Drawing.Color.White; this.btnDurationShort.FlatAppearance.MouseOverBackColor = System.Drawing.Color.White;
this.btnDurationShort.FlatStyle = System.Windows.Forms.FlatStyle.Flat; this.btnDurationShort.FlatStyle = System.Windows.Forms.FlatStyle.Flat;
this.btnDurationShort.Font = new System.Drawing.Font("Segoe UI", 9F);
this.btnDurationShort.Location = new System.Drawing.Point(1, 1); this.btnDurationShort.Location = new System.Drawing.Point(1, 1);
this.btnDurationShort.Margin = new System.Windows.Forms.Padding(1); this.btnDurationShort.Margin = new System.Windows.Forms.Padding(1);
this.btnDurationShort.Name = "btnDurationShort"; this.btnDurationShort.Name = "btnDurationShort";
this.btnDurationShort.Size = new System.Drawing.Size(52, 25); this.btnDurationShort.Size = new System.Drawing.Size(55, 25);
this.btnDurationShort.TabIndex = 0; this.btnDurationShort.TabIndex = 0;
this.btnDurationShort.Text = "Short"; this.btnDurationShort.Text = "Short";
this.btnDurationShort.UseVisualStyleBackColor = true; this.btnDurationShort.UseVisualStyleBackColor = true;
@@ -250,164 +266,174 @@
// labelDurationValue // labelDurationValue
// //
this.labelDurationValue.BackColor = System.Drawing.Color.Transparent; this.labelDurationValue.BackColor = System.Drawing.Color.Transparent;
this.labelDurationValue.Location = new System.Drawing.Point(147, 77); this.labelDurationValue.Font = new System.Drawing.Font("Segoe UI", 9F);
this.labelDurationValue.Location = new System.Drawing.Point(147, 4);
this.labelDurationValue.Margin = new System.Windows.Forms.Padding(0, 0, 3, 0); this.labelDurationValue.Margin = new System.Windows.Forms.Padding(0, 0, 3, 0);
this.labelDurationValue.Name = "labelDurationValue"; this.labelDurationValue.Name = "labelDurationValue";
this.labelDurationValue.Size = new System.Drawing.Size(52, 13); this.labelDurationValue.Size = new System.Drawing.Size(52, 15);
this.labelDurationValue.TabIndex = 4; this.labelDurationValue.TabIndex = 1;
this.labelDurationValue.Text = "0 ms/c"; this.labelDurationValue.Text = "0 ms/c";
this.labelDurationValue.TextAlign = System.Drawing.ContentAlignment.TopRight; this.labelDurationValue.TextAlign = System.Drawing.ContentAlignment.TopRight;
this.toolTip.SetToolTip(this.labelDurationValue, "Milliseconds per character.");
// //
// trackBarDuration // trackBarDuration
// //
this.trackBarDuration.AutoSize = false; this.trackBarDuration.AutoSize = false;
this.trackBarDuration.Location = new System.Drawing.Point(3, 76); this.trackBarDuration.Location = new System.Drawing.Point(3, 3);
this.trackBarDuration.Maximum = 60; this.trackBarDuration.Maximum = 60;
this.trackBarDuration.Minimum = 10; this.trackBarDuration.Minimum = 10;
this.trackBarDuration.Name = "trackBarDuration"; this.trackBarDuration.Name = "trackBarDuration";
this.trackBarDuration.Size = new System.Drawing.Size(148, 30); this.trackBarDuration.Size = new System.Drawing.Size(148, 30);
this.trackBarDuration.TabIndex = 3; this.trackBarDuration.TabIndex = 0;
this.trackBarDuration.TickFrequency = 5; this.trackBarDuration.TickFrequency = 5;
this.trackBarDuration.Value = 25; this.trackBarDuration.Value = 25;
// //
// checkSkipOnLinkClick // checkSkipOnLinkClick
// //
this.checkSkipOnLinkClick.AutoSize = true; this.checkSkipOnLinkClick.AutoSize = true;
this.checkSkipOnLinkClick.Location = new System.Drawing.Point(6, 51); this.checkSkipOnLinkClick.Font = new System.Drawing.Font("Segoe UI", 9F);
this.checkSkipOnLinkClick.Margin = new System.Windows.Forms.Padding(6, 3, 3, 3); this.checkSkipOnLinkClick.Location = new System.Drawing.Point(6, 74);
this.checkSkipOnLinkClick.Margin = new System.Windows.Forms.Padding(6, 3, 3, 2);
this.checkSkipOnLinkClick.Name = "checkSkipOnLinkClick"; this.checkSkipOnLinkClick.Name = "checkSkipOnLinkClick";
this.checkSkipOnLinkClick.Size = new System.Drawing.Size(113, 17); this.checkSkipOnLinkClick.Size = new System.Drawing.Size(121, 19);
this.checkSkipOnLinkClick.TabIndex = 2; this.checkSkipOnLinkClick.TabIndex = 3;
this.checkSkipOnLinkClick.Text = "Skip On Link Click"; this.checkSkipOnLinkClick.Text = "Skip On Link Click";
this.toolTip.SetToolTip(this.checkSkipOnLinkClick, "Skips current notification when a link\r\ninside the notification is clicked.");
this.checkSkipOnLinkClick.UseVisualStyleBackColor = true; this.checkSkipOnLinkClick.UseVisualStyleBackColor = true;
// //
// checkColumnName // checkColumnName
// //
this.checkColumnName.AutoSize = true; this.checkColumnName.AutoSize = true;
this.checkColumnName.Location = new System.Drawing.Point(6, 5); this.checkColumnName.Font = new System.Drawing.Font("Segoe UI", 9F);
this.checkColumnName.Margin = new System.Windows.Forms.Padding(6, 5, 3, 3); this.checkColumnName.Location = new System.Drawing.Point(6, 26);
this.checkColumnName.Margin = new System.Windows.Forms.Padding(6, 6, 3, 2);
this.checkColumnName.Name = "checkColumnName"; this.checkColumnName.Name = "checkColumnName";
this.checkColumnName.Size = new System.Drawing.Size(129, 17); this.checkColumnName.Size = new System.Drawing.Size(145, 19);
this.checkColumnName.TabIndex = 0; this.checkColumnName.TabIndex = 1;
this.checkColumnName.Text = "Display Column Name"; this.checkColumnName.Text = "Display Column Name";
this.toolTip.SetToolTip(this.checkColumnName, "Shows column name each notification originated\r\nfrom in the notification window title.");
this.checkColumnName.UseVisualStyleBackColor = true; this.checkColumnName.UseVisualStyleBackColor = true;
// //
// labelIdlePause // labelIdlePause
// //
this.labelIdlePause.AutoSize = true; this.labelIdlePause.AutoSize = true;
this.labelIdlePause.Location = new System.Drawing.Point(3, 106); this.labelIdlePause.Font = new System.Drawing.Font("Segoe UI Semibold", 9F, System.Drawing.FontStyle.Bold);
this.labelIdlePause.Location = new System.Drawing.Point(3, 131);
this.labelIdlePause.Margin = new System.Windows.Forms.Padding(3, 12, 3, 0); this.labelIdlePause.Margin = new System.Windows.Forms.Padding(3, 12, 3, 0);
this.labelIdlePause.Name = "labelIdlePause"; this.labelIdlePause.Name = "labelIdlePause";
this.labelIdlePause.Size = new System.Drawing.Size(89, 13); this.labelIdlePause.Size = new System.Drawing.Size(95, 15);
this.labelIdlePause.TabIndex = 4; this.labelIdlePause.TabIndex = 5;
this.labelIdlePause.Text = "Pause When Idle"; this.labelIdlePause.Text = "Pause When Idle";
// //
// comboBoxIdlePause // comboBoxIdlePause
// //
this.comboBoxIdlePause.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList; this.comboBoxIdlePause.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList;
this.comboBoxIdlePause.Font = new System.Drawing.Font("Segoe UI", 9F);
this.comboBoxIdlePause.FormattingEnabled = true; this.comboBoxIdlePause.FormattingEnabled = true;
this.comboBoxIdlePause.Location = new System.Drawing.Point(5, 122); this.comboBoxIdlePause.Location = new System.Drawing.Point(5, 150);
this.comboBoxIdlePause.Margin = new System.Windows.Forms.Padding(5, 3, 3, 3); this.comboBoxIdlePause.Margin = new System.Windows.Forms.Padding(5, 4, 3, 3);
this.comboBoxIdlePause.Name = "comboBoxIdlePause"; this.comboBoxIdlePause.Name = "comboBoxIdlePause";
this.comboBoxIdlePause.Size = new System.Drawing.Size(144, 21); this.comboBoxIdlePause.Size = new System.Drawing.Size(144, 23);
this.comboBoxIdlePause.TabIndex = 5; this.comboBoxIdlePause.TabIndex = 6;
this.toolTip.SetToolTip(this.comboBoxIdlePause, "Pauses new notifications after going idle for a set amount of time.");
// //
// checkNonIntrusive // checkNonIntrusive
// //
this.checkNonIntrusive.AutoSize = true; this.checkNonIntrusive.AutoSize = true;
this.checkNonIntrusive.Location = new System.Drawing.Point(6, 74); this.checkNonIntrusive.Font = new System.Drawing.Font("Segoe UI", 9F);
this.checkNonIntrusive.Margin = new System.Windows.Forms.Padding(6, 3, 3, 3); this.checkNonIntrusive.Location = new System.Drawing.Point(6, 98);
this.checkNonIntrusive.Margin = new System.Windows.Forms.Padding(6, 3, 3, 2);
this.checkNonIntrusive.Name = "checkNonIntrusive"; this.checkNonIntrusive.Name = "checkNonIntrusive";
this.checkNonIntrusive.Size = new System.Drawing.Size(128, 17); this.checkNonIntrusive.Size = new System.Drawing.Size(142, 19);
this.checkNonIntrusive.TabIndex = 3; this.checkNonIntrusive.TabIndex = 4;
this.checkNonIntrusive.Text = "Non-Intrusive Popups"; this.checkNonIntrusive.Text = "Non-Intrusive Popups";
this.toolTip.SetToolTip(this.checkNonIntrusive, "When not idle and the cursor is within the notification window area,\r\nit will be delayed until the cursor moves away to prevent accidental clicks.");
this.checkNonIntrusive.UseVisualStyleBackColor = true; this.checkNonIntrusive.UseVisualStyleBackColor = true;
// //
// checkTimerCountDown // checkTimerCountDown
// //
this.checkTimerCountDown.AutoSize = true; this.checkTimerCountDown.AutoSize = true;
this.checkTimerCountDown.Location = new System.Drawing.Point(6, 28); this.checkTimerCountDown.Font = new System.Drawing.Font("Segoe UI", 9F);
this.checkTimerCountDown.Margin = new System.Windows.Forms.Padding(6, 3, 3, 3); this.checkTimerCountDown.Location = new System.Drawing.Point(6, 266);
this.checkTimerCountDown.Margin = new System.Windows.Forms.Padding(6, 3, 3, 2);
this.checkTimerCountDown.Name = "checkTimerCountDown"; this.checkTimerCountDown.Name = "checkTimerCountDown";
this.checkTimerCountDown.Size = new System.Drawing.Size(119, 17); this.checkTimerCountDown.Size = new System.Drawing.Size(132, 19);
this.checkTimerCountDown.TabIndex = 1; this.checkTimerCountDown.TabIndex = 9;
this.checkTimerCountDown.Text = "Timer Counts Down"; this.checkTimerCountDown.Text = "Timer Counts Down";
this.toolTip.SetToolTip(this.checkTimerCountDown, "The notification timer counts down instead of up.");
this.checkTimerCountDown.UseVisualStyleBackColor = true; this.checkTimerCountDown.UseVisualStyleBackColor = true;
// //
// checkNotificationTimer // checkNotificationTimer
// //
this.checkNotificationTimer.AutoSize = true; this.checkNotificationTimer.AutoSize = true;
this.checkNotificationTimer.Location = new System.Drawing.Point(6, 5); this.checkNotificationTimer.Font = new System.Drawing.Font("Segoe UI", 9F);
this.checkNotificationTimer.Margin = new System.Windows.Forms.Padding(6, 5, 3, 3); this.checkNotificationTimer.Location = new System.Drawing.Point(6, 242);
this.checkNotificationTimer.Margin = new System.Windows.Forms.Padding(6, 6, 3, 2);
this.checkNotificationTimer.Name = "checkNotificationTimer"; this.checkNotificationTimer.Name = "checkNotificationTimer";
this.checkNotificationTimer.Size = new System.Drawing.Size(145, 17); this.checkNotificationTimer.Size = new System.Drawing.Size(164, 19);
this.checkNotificationTimer.TabIndex = 0; this.checkNotificationTimer.TabIndex = 8;
this.checkNotificationTimer.Text = "Display Notification Timer"; this.checkNotificationTimer.Text = "Display Notification Timer";
this.checkNotificationTimer.UseVisualStyleBackColor = true; this.checkNotificationTimer.UseVisualStyleBackColor = true;
// //
// radioSizeAuto // radioSizeAuto
// //
this.radioSizeAuto.Location = new System.Drawing.Point(6, 4); this.radioSizeAuto.Font = new System.Drawing.Font("Segoe UI", 9F);
this.radioSizeAuto.Location = new System.Drawing.Point(5, 4);
this.radioSizeAuto.Margin = new System.Windows.Forms.Padding(5, 4, 3, 3); this.radioSizeAuto.Margin = new System.Windows.Forms.Padding(5, 4, 3, 3);
this.radioSizeAuto.Name = "radioSizeAuto"; this.radioSizeAuto.Name = "radioSizeAuto";
this.radioSizeAuto.Size = new System.Drawing.Size(92, 17); this.radioSizeAuto.Size = new System.Drawing.Size(92, 19);
this.radioSizeAuto.TabIndex = 0; this.radioSizeAuto.TabIndex = 0;
this.radioSizeAuto.TabStop = true; this.radioSizeAuto.TabStop = true;
this.radioSizeAuto.Text = "Auto"; this.radioSizeAuto.Text = "Auto";
this.toolTip.SetToolTip(this.radioSizeAuto, "Notification size is based on the font size and browser zoom level.");
this.radioSizeAuto.UseVisualStyleBackColor = true; this.radioSizeAuto.UseVisualStyleBackColor = true;
// //
// radioSizeCustom // radioSizeCustom
// //
this.radioSizeCustom.Location = new System.Drawing.Point(106, 4); this.radioSizeCustom.Font = new System.Drawing.Font("Segoe UI", 9F);
this.radioSizeCustom.Location = new System.Drawing.Point(105, 4);
this.radioSizeCustom.Margin = new System.Windows.Forms.Padding(5, 4, 3, 3); this.radioSizeCustom.Margin = new System.Windows.Forms.Padding(5, 4, 3, 3);
this.radioSizeCustom.Name = "radioSizeCustom"; this.radioSizeCustom.Name = "radioSizeCustom";
this.radioSizeCustom.Size = new System.Drawing.Size(92, 17); this.radioSizeCustom.Size = new System.Drawing.Size(92, 19);
this.radioSizeCustom.TabIndex = 1; this.radioSizeCustom.TabIndex = 1;
this.radioSizeCustom.TabStop = true; this.radioSizeCustom.TabStop = true;
this.radioSizeCustom.Text = "Custom"; this.radioSizeCustom.Text = "Custom";
this.toolTip.SetToolTip(this.radioSizeCustom, "Resize the example notification window to the desired size.");
this.radioSizeCustom.UseVisualStyleBackColor = true; this.radioSizeCustom.UseVisualStyleBackColor = true;
// //
// labelGeneral // labelGeneral
// //
this.labelGeneral.AutoSize = true; this.labelGeneral.AutoSize = true;
this.labelGeneral.Font = new System.Drawing.Font("Microsoft Sans Serif", 12F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(238))); this.labelGeneral.Font = new System.Drawing.Font("Segoe UI Semibold", 10.5F, System.Drawing.FontStyle.Bold);
this.labelGeneral.Location = new System.Drawing.Point(6, 8); this.labelGeneral.Location = new System.Drawing.Point(0, 0);
this.labelGeneral.Margin = new System.Windows.Forms.Padding(0, 2, 0, 0); this.labelGeneral.Margin = new System.Windows.Forms.Padding(0, 0, 0, 1);
this.labelGeneral.Name = "labelGeneral"; this.labelGeneral.Name = "labelGeneral";
this.labelGeneral.Size = new System.Drawing.Size(66, 20); this.labelGeneral.Size = new System.Drawing.Size(69, 19);
this.labelGeneral.TabIndex = 0; this.labelGeneral.TabIndex = 0;
this.labelGeneral.Text = "General"; this.labelGeneral.Text = "GENERAL";
// //
// panelGeneral // panelEdgeDistance
// //
this.panelGeneral.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) this.panelEdgeDistance.Controls.Add(this.trackBarEdgeDistance);
| System.Windows.Forms.AnchorStyles.Right))); this.panelEdgeDistance.Controls.Add(this.labelEdgeDistanceValue);
this.panelGeneral.Controls.Add(this.checkMediaPreviews); this.panelEdgeDistance.Location = new System.Drawing.Point(0, 156);
this.panelGeneral.Controls.Add(this.checkColumnName); this.panelEdgeDistance.Margin = new System.Windows.Forms.Padding(0, 1, 0, 0);
this.panelGeneral.Controls.Add(this.checkSkipOnLinkClick); this.panelEdgeDistance.Name = "panelEdgeDistance";
this.panelGeneral.Controls.Add(this.checkNonIntrusive); this.panelEdgeDistance.Size = new System.Drawing.Size(300, 35);
this.panelGeneral.Controls.Add(this.labelIdlePause); this.panelEdgeDistance.TabIndex = 5;
this.panelGeneral.Controls.Add(this.comboBoxIdlePause); //
this.panelGeneral.Location = new System.Drawing.Point(9, 31); // checkMediaPreviews
this.panelGeneral.Name = "panelGeneral"; //
this.panelGeneral.Size = new System.Drawing.Size(322, 149); this.checkMediaPreviews.AutoSize = true;
this.panelGeneral.TabIndex = 1; this.checkMediaPreviews.Font = new System.Drawing.Font("Segoe UI", 9F);
this.checkMediaPreviews.Location = new System.Drawing.Point(6, 50);
this.checkMediaPreviews.Margin = new System.Windows.Forms.Padding(6, 3, 3, 2);
this.checkMediaPreviews.Name = "checkMediaPreviews";
this.checkMediaPreviews.Size = new System.Drawing.Size(140, 19);
this.checkMediaPreviews.TabIndex = 2;
this.checkMediaPreviews.Text = "Show Media Previews";
this.checkMediaPreviews.UseVisualStyleBackColor = true;
// //
// labelScrollSpeedValue // labelScrollSpeedValue
// //
this.labelScrollSpeedValue.Location = new System.Drawing.Point(147, 53); this.labelScrollSpeedValue.Font = new System.Drawing.Font("Segoe UI", 9F);
this.labelScrollSpeedValue.Location = new System.Drawing.Point(145, 4);
this.labelScrollSpeedValue.Margin = new System.Windows.Forms.Padding(0, 0, 3, 0); this.labelScrollSpeedValue.Margin = new System.Windows.Forms.Padding(0, 0, 3, 0);
this.labelScrollSpeedValue.Name = "labelScrollSpeedValue"; this.labelScrollSpeedValue.Name = "labelScrollSpeedValue";
this.labelScrollSpeedValue.Size = new System.Drawing.Size(38, 13); this.labelScrollSpeedValue.Size = new System.Drawing.Size(38, 15);
this.labelScrollSpeedValue.TabIndex = 4; this.labelScrollSpeedValue.TabIndex = 1;
this.labelScrollSpeedValue.Text = "100%"; this.labelScrollSpeedValue.Text = "100%";
this.labelScrollSpeedValue.TextAlign = System.Drawing.ContentAlignment.TopRight; this.labelScrollSpeedValue.TextAlign = System.Drawing.ContentAlignment.TopRight;
// //
@@ -415,163 +441,199 @@
// //
this.trackBarScrollSpeed.AutoSize = false; this.trackBarScrollSpeed.AutoSize = false;
this.trackBarScrollSpeed.LargeChange = 25; this.trackBarScrollSpeed.LargeChange = 25;
this.trackBarScrollSpeed.Location = new System.Drawing.Point(5, 52); this.trackBarScrollSpeed.Location = new System.Drawing.Point(3, 3);
this.trackBarScrollSpeed.Maximum = 200; this.trackBarScrollSpeed.Maximum = 200;
this.trackBarScrollSpeed.Minimum = 25; this.trackBarScrollSpeed.Minimum = 25;
this.trackBarScrollSpeed.Name = "trackBarScrollSpeed"; this.trackBarScrollSpeed.Name = "trackBarScrollSpeed";
this.trackBarScrollSpeed.Size = new System.Drawing.Size(148, 30); this.trackBarScrollSpeed.Size = new System.Drawing.Size(148, 30);
this.trackBarScrollSpeed.SmallChange = 5; this.trackBarScrollSpeed.SmallChange = 5;
this.trackBarScrollSpeed.TabIndex = 3; this.trackBarScrollSpeed.TabIndex = 0;
this.trackBarScrollSpeed.TickFrequency = 25; this.trackBarScrollSpeed.TickFrequency = 25;
this.trackBarScrollSpeed.Value = 100; this.trackBarScrollSpeed.Value = 100;
// //
// labelScrollSpeed // labelScrollSpeed
// //
this.labelScrollSpeed.AutoSize = true; this.labelScrollSpeed.AutoSize = true;
this.labelScrollSpeed.Location = new System.Drawing.Point(3, 36); this.labelScrollSpeed.Font = new System.Drawing.Font("Segoe UI Semibold", 9F, System.Drawing.FontStyle.Bold);
this.labelScrollSpeed.Location = new System.Drawing.Point(3, 275);
this.labelScrollSpeed.Margin = new System.Windows.Forms.Padding(3, 12, 3, 0); this.labelScrollSpeed.Margin = new System.Windows.Forms.Padding(3, 12, 3, 0);
this.labelScrollSpeed.Name = "labelScrollSpeed"; this.labelScrollSpeed.Name = "labelScrollSpeed";
this.labelScrollSpeed.Size = new System.Drawing.Size(67, 13); this.labelScrollSpeed.Size = new System.Drawing.Size(73, 15);
this.labelScrollSpeed.TabIndex = 2; this.labelScrollSpeed.TabIndex = 8;
this.labelScrollSpeed.Text = "Scroll Speed"; this.labelScrollSpeed.Text = "Scroll Speed";
// //
// labelLocation // labelLocation
// //
this.labelLocation.AutoSize = true; this.labelLocation.AutoSize = true;
this.labelLocation.Font = new System.Drawing.Font("Microsoft Sans Serif", 12F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(238))); this.labelLocation.Font = new System.Drawing.Font("Segoe UI Semibold", 10.5F, System.Drawing.FontStyle.Bold);
this.labelLocation.Location = new System.Drawing.Point(6, 395); this.labelLocation.Location = new System.Drawing.Point(0, 0);
this.labelLocation.Margin = new System.Windows.Forms.Padding(0, 21, 0, 0); this.labelLocation.Margin = new System.Windows.Forms.Padding(0, 0, 0, 1);
this.labelLocation.Name = "labelLocation"; this.labelLocation.Name = "labelLocation";
this.labelLocation.Size = new System.Drawing.Size(70, 20); this.labelLocation.Size = new System.Drawing.Size(79, 19);
this.labelLocation.TabIndex = 4; this.labelLocation.TabIndex = 0;
this.labelLocation.Text = "Location"; this.labelLocation.Text = "LOCATION";
// //
// panelLocation // panelLocation
// //
this.panelLocation.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left)
| System.Windows.Forms.AnchorStyles.Right)));
this.panelLocation.Controls.Add(this.radioLocTL); this.panelLocation.Controls.Add(this.radioLocTL);
this.panelLocation.Controls.Add(this.labelDisplay);
this.panelLocation.Controls.Add(this.trackBarEdgeDistance);
this.panelLocation.Controls.Add(this.comboBoxDisplay);
this.panelLocation.Controls.Add(this.radioLocTR); this.panelLocation.Controls.Add(this.radioLocTR);
this.panelLocation.Controls.Add(this.labelEdgeDistance);
this.panelLocation.Controls.Add(this.radioLocBL); this.panelLocation.Controls.Add(this.radioLocBL);
this.panelLocation.Controls.Add(this.radioLocCustom); this.panelLocation.Controls.Add(this.radioLocCustom);
this.panelLocation.Controls.Add(this.radioLocBR); this.panelLocation.Controls.Add(this.radioLocBR);
this.panelLocation.Controls.Add(this.labelEdgeDistanceValue); this.panelLocation.Location = new System.Drawing.Point(0, 20);
this.panelLocation.Location = new System.Drawing.Point(9, 418); this.panelLocation.Margin = new System.Windows.Forms.Padding(0);
this.panelLocation.Name = "panelLocation"; this.panelLocation.Name = "panelLocation";
this.panelLocation.Size = new System.Drawing.Size(322, 165); this.panelLocation.Size = new System.Drawing.Size(300, 51);
this.panelLocation.TabIndex = 5; this.panelLocation.TabIndex = 1;
// //
// panelTimer // panelTimer
// //
this.panelTimer.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left)
| System.Windows.Forms.AnchorStyles.Right)));
this.panelTimer.Controls.Add(this.labelDuration);
this.panelTimer.Controls.Add(this.checkNotificationTimer);
this.panelTimer.Controls.Add(this.tableLayoutDurationButtons);
this.panelTimer.Controls.Add(this.checkTimerCountDown);
this.panelTimer.Controls.Add(this.labelDurationValue); this.panelTimer.Controls.Add(this.labelDurationValue);
this.panelTimer.Controls.Add(this.trackBarDuration); this.panelTimer.Controls.Add(this.trackBarDuration);
this.panelTimer.Location = new System.Drawing.Point(9, 227); this.panelTimer.Location = new System.Drawing.Point(0, 315);
this.panelTimer.Margin = new System.Windows.Forms.Padding(0, 1, 0, 0);
this.panelTimer.Name = "panelTimer"; this.panelTimer.Name = "panelTimer";
this.panelTimer.Size = new System.Drawing.Size(322, 144); this.panelTimer.Size = new System.Drawing.Size(300, 35);
this.panelTimer.TabIndex = 3; this.panelTimer.TabIndex = 11;
// //
// labelDuration // labelDuration
// //
this.labelDuration.AutoSize = true; this.labelDuration.AutoSize = true;
this.labelDuration.Location = new System.Drawing.Point(3, 60); this.labelDuration.Font = new System.Drawing.Font("Segoe UI Semibold", 9F, System.Drawing.FontStyle.Bold);
this.labelDuration.Location = new System.Drawing.Point(3, 299);
this.labelDuration.Margin = new System.Windows.Forms.Padding(3, 12, 3, 0); this.labelDuration.Margin = new System.Windows.Forms.Padding(3, 12, 3, 0);
this.labelDuration.Name = "labelDuration"; this.labelDuration.Name = "labelDuration";
this.labelDuration.Size = new System.Drawing.Size(47, 13); this.labelDuration.Size = new System.Drawing.Size(54, 15);
this.labelDuration.TabIndex = 2; this.labelDuration.TabIndex = 10;
this.labelDuration.Text = "Duration"; this.labelDuration.Text = "Duration";
// //
// labelTimer // labelTimer
// //
this.labelTimer.AutoSize = true; this.labelTimer.AutoSize = true;
this.labelTimer.Font = new System.Drawing.Font("Microsoft Sans Serif", 12F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(238))); this.labelTimer.Font = new System.Drawing.Font("Segoe UI Semibold", 10.5F, System.Drawing.FontStyle.Bold);
this.labelTimer.Location = new System.Drawing.Point(6, 204); this.labelTimer.Location = new System.Drawing.Point(0, 216);
this.labelTimer.Margin = new System.Windows.Forms.Padding(0, 21, 0, 0); this.labelTimer.Margin = new System.Windows.Forms.Padding(0, 40, 0, 1);
this.labelTimer.Name = "labelTimer"; this.labelTimer.Name = "labelTimer";
this.labelTimer.Size = new System.Drawing.Size(48, 20); this.labelTimer.Size = new System.Drawing.Size(50, 19);
this.labelTimer.TabIndex = 2; this.labelTimer.TabIndex = 7;
this.labelTimer.Text = "Timer"; this.labelTimer.Text = "TIMER";
// //
// labelSize // labelSize
// //
this.labelSize.AutoSize = true; this.labelSize.AutoSize = true;
this.labelSize.Font = new System.Drawing.Font("Microsoft Sans Serif", 12F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(238))); this.labelSize.Font = new System.Drawing.Font("Segoe UI Semibold", 10.5F, System.Drawing.FontStyle.Bold);
this.labelSize.Location = new System.Drawing.Point(6, 607); this.labelSize.Location = new System.Drawing.Point(0, 216);
this.labelSize.Margin = new System.Windows.Forms.Padding(0, 21, 0, 0); this.labelSize.Margin = new System.Windows.Forms.Padding(0, 25, 0, 1);
this.labelSize.Name = "labelSize"; this.labelSize.Name = "labelSize";
this.labelSize.Size = new System.Drawing.Size(40, 20); this.labelSize.Size = new System.Drawing.Size(36, 19);
this.labelSize.TabIndex = 6; this.labelSize.TabIndex = 6;
this.labelSize.Text = "Size"; this.labelSize.Text = "SIZE";
// //
// panelMiscellaneous // panelSize
// //
this.panelMiscellaneous.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) this.panelSize.Controls.Add(this.radioSizeCustom);
| System.Windows.Forms.AnchorStyles.Right))); this.panelSize.Controls.Add(this.radioSizeAuto);
this.panelMiscellaneous.Controls.Add(this.radioSizeCustom); this.panelSize.Location = new System.Drawing.Point(0, 236);
this.panelMiscellaneous.Controls.Add(this.radioSizeAuto); this.panelSize.Margin = new System.Windows.Forms.Padding(0);
this.panelMiscellaneous.Controls.Add(this.labelScrollSpeedValue); this.panelSize.Name = "panelSize";
this.panelMiscellaneous.Controls.Add(this.trackBarScrollSpeed); this.panelSize.Size = new System.Drawing.Size(300, 27);
this.panelMiscellaneous.Controls.Add(this.labelScrollSpeed); this.panelSize.TabIndex = 7;
this.panelMiscellaneous.Location = new System.Drawing.Point(9, 630);
this.panelMiscellaneous.Name = "panelMiscellaneous";
this.panelMiscellaneous.Size = new System.Drawing.Size(322, 92);
this.panelMiscellaneous.TabIndex = 7;
// //
// durationUpdateTimer // durationUpdateTimer
// //
this.durationUpdateTimer.Interval = 200; this.durationUpdateTimer.Interval = 200;
this.durationUpdateTimer.Tick += new System.EventHandler(this.durationUpdateTimer_Tick); this.durationUpdateTimer.Tick += new System.EventHandler(this.durationUpdateTimer_Tick);
// //
// checkMediaPreviews // flowPanelLeft
// //
this.checkMediaPreviews.AutoSize = true; this.flowPanelLeft.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom)
this.checkMediaPreviews.Location = new System.Drawing.Point(6, 28); | System.Windows.Forms.AnchorStyles.Left)));
this.checkMediaPreviews.Margin = new System.Windows.Forms.Padding(6, 3, 3, 3); this.flowPanelLeft.Controls.Add(this.labelGeneral);
this.checkMediaPreviews.Name = "checkMediaPreviews"; this.flowPanelLeft.Controls.Add(this.checkColumnName);
this.checkMediaPreviews.Size = new System.Drawing.Size(131, 17); this.flowPanelLeft.Controls.Add(this.checkMediaPreviews);
this.checkMediaPreviews.TabIndex = 1; this.flowPanelLeft.Controls.Add(this.checkSkipOnLinkClick);
this.checkMediaPreviews.Text = "Show Media Previews"; this.flowPanelLeft.Controls.Add(this.checkNonIntrusive);
this.toolTip.SetToolTip(this.checkMediaPreviews, "Shows image and video thumbnails in the notification window."); this.flowPanelLeft.Controls.Add(this.labelIdlePause);
this.checkMediaPreviews.UseVisualStyleBackColor = true; this.flowPanelLeft.Controls.Add(this.comboBoxIdlePause);
this.flowPanelLeft.Controls.Add(this.labelTimer);
this.flowPanelLeft.Controls.Add(this.checkNotificationTimer);
this.flowPanelLeft.Controls.Add(this.checkTimerCountDown);
this.flowPanelLeft.Controls.Add(this.labelDuration);
this.flowPanelLeft.Controls.Add(this.panelTimer);
this.flowPanelLeft.Controls.Add(this.tableLayoutDurationButtons);
this.flowPanelLeft.FlowDirection = System.Windows.Forms.FlowDirection.TopDown;
this.flowPanelLeft.Location = new System.Drawing.Point(9, 9);
this.flowPanelLeft.Name = "flowPanelLeft";
this.flowPanelLeft.Size = new System.Drawing.Size(300, 461);
this.flowPanelLeft.TabIndex = 0;
this.flowPanelLeft.WrapContents = false;
//
// panelScrollSpeed
//
this.panelScrollSpeed.Controls.Add(this.trackBarScrollSpeed);
this.panelScrollSpeed.Controls.Add(this.labelScrollSpeedValue);
this.panelScrollSpeed.Location = new System.Drawing.Point(0, 291);
this.panelScrollSpeed.Margin = new System.Windows.Forms.Padding(0, 1, 0, 0);
this.panelScrollSpeed.Name = "panelScrollSpeed";
this.panelScrollSpeed.Size = new System.Drawing.Size(300, 35);
this.panelScrollSpeed.TabIndex = 9;
//
// flowPanelRight
//
this.flowPanelRight.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom)
| System.Windows.Forms.AnchorStyles.Left)));
this.flowPanelRight.Controls.Add(this.labelLocation);
this.flowPanelRight.Controls.Add(this.panelLocation);
this.flowPanelRight.Controls.Add(this.labelDisplay);
this.flowPanelRight.Controls.Add(this.comboBoxDisplay);
this.flowPanelRight.Controls.Add(this.labelEdgeDistance);
this.flowPanelRight.Controls.Add(this.panelEdgeDistance);
this.flowPanelRight.Controls.Add(this.labelSize);
this.flowPanelRight.Controls.Add(this.panelSize);
this.flowPanelRight.Controls.Add(this.labelScrollSpeed);
this.flowPanelRight.Controls.Add(this.panelScrollSpeed);
this.flowPanelRight.FlowDirection = System.Windows.Forms.FlowDirection.TopDown;
this.flowPanelRight.Location = new System.Drawing.Point(322, 9);
this.flowPanelRight.Name = "flowPanelRight";
this.flowPanelRight.Size = new System.Drawing.Size(300, 461);
this.flowPanelRight.TabIndex = 1;
this.flowPanelRight.WrapContents = false;
//
// panelSeparator
//
this.panelSeparator.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom)
| System.Windows.Forms.AnchorStyles.Left)));
this.panelSeparator.BackColor = System.Drawing.Color.FromArgb(((int)(((byte)(200)))), ((int)(((byte)(200)))), ((int)(((byte)(200)))));
this.panelSeparator.Location = new System.Drawing.Point(312, 0);
this.panelSeparator.Margin = new System.Windows.Forms.Padding(0, 0, 6, 0);
this.panelSeparator.Name = "panelSeparator";
this.panelSeparator.Size = new System.Drawing.Size(1, 480);
this.panelSeparator.TabIndex = 2;
// //
// TabSettingsNotifications // TabSettingsNotifications
// //
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
this.Controls.Add(this.panelMiscellaneous); this.Controls.Add(this.flowPanelRight);
this.Controls.Add(this.labelSize); this.Controls.Add(this.flowPanelLeft);
this.Controls.Add(this.labelTimer); this.Controls.Add(this.panelSeparator);
this.Controls.Add(this.panelLocation);
this.Controls.Add(this.labelLocation);
this.Controls.Add(this.panelGeneral);
this.Controls.Add(this.labelGeneral);
this.Controls.Add(this.panelTimer);
this.Name = "TabSettingsNotifications"; this.Name = "TabSettingsNotifications";
this.Size = new System.Drawing.Size(340, 731); this.Size = new System.Drawing.Size(631, 480);
this.ParentChanged += new System.EventHandler(this.TabSettingsNotifications_ParentChanged); this.ParentChanged += new System.EventHandler(this.TabSettingsNotifications_ParentChanged);
((System.ComponentModel.ISupportInitialize)(this.trackBarEdgeDistance)).EndInit(); ((System.ComponentModel.ISupportInitialize)(this.trackBarEdgeDistance)).EndInit();
this.tableLayoutDurationButtons.ResumeLayout(false); this.tableLayoutDurationButtons.ResumeLayout(false);
((System.ComponentModel.ISupportInitialize)(this.trackBarDuration)).EndInit(); ((System.ComponentModel.ISupportInitialize)(this.trackBarDuration)).EndInit();
this.panelGeneral.ResumeLayout(false); this.panelEdgeDistance.ResumeLayout(false);
this.panelGeneral.PerformLayout();
((System.ComponentModel.ISupportInitialize)(this.trackBarScrollSpeed)).EndInit(); ((System.ComponentModel.ISupportInitialize)(this.trackBarScrollSpeed)).EndInit();
this.panelLocation.ResumeLayout(false); this.panelLocation.ResumeLayout(false);
this.panelLocation.PerformLayout();
this.panelTimer.ResumeLayout(false); this.panelTimer.ResumeLayout(false);
this.panelTimer.PerformLayout(); this.panelSize.ResumeLayout(false);
this.panelMiscellaneous.ResumeLayout(false); this.flowPanelLeft.ResumeLayout(false);
this.panelMiscellaneous.PerformLayout(); this.flowPanelLeft.PerformLayout();
this.panelScrollSpeed.ResumeLayout(false);
this.flowPanelRight.ResumeLayout(false);
this.flowPanelRight.PerformLayout();
this.ResumeLayout(false); this.ResumeLayout(false);
this.PerformLayout();
} }
@@ -601,7 +663,7 @@
private System.Windows.Forms.CheckBox checkTimerCountDown; private System.Windows.Forms.CheckBox checkTimerCountDown;
private System.Windows.Forms.CheckBox checkNotificationTimer; private System.Windows.Forms.CheckBox checkNotificationTimer;
private System.Windows.Forms.Label labelGeneral; private System.Windows.Forms.Label labelGeneral;
private System.Windows.Forms.Panel panelGeneral; private System.Windows.Forms.Panel panelEdgeDistance;
private System.Windows.Forms.Label labelLocation; private System.Windows.Forms.Label labelLocation;
private System.Windows.Forms.Panel panelLocation; private System.Windows.Forms.Panel panelLocation;
private System.Windows.Forms.Panel panelTimer; private System.Windows.Forms.Panel panelTimer;
@@ -610,11 +672,15 @@
private System.Windows.Forms.TrackBar trackBarScrollSpeed; private System.Windows.Forms.TrackBar trackBarScrollSpeed;
private System.Windows.Forms.Label labelScrollSpeed; private System.Windows.Forms.Label labelScrollSpeed;
private System.Windows.Forms.Label labelSize; private System.Windows.Forms.Label labelSize;
private System.Windows.Forms.Panel panelMiscellaneous; private System.Windows.Forms.Panel panelSize;
private System.Windows.Forms.Label labelDuration; private System.Windows.Forms.Label labelDuration;
private System.Windows.Forms.Timer durationUpdateTimer; private System.Windows.Forms.Timer durationUpdateTimer;
private System.Windows.Forms.RadioButton radioSizeCustom; private System.Windows.Forms.RadioButton radioSizeCustom;
private System.Windows.Forms.RadioButton radioSizeAuto; private System.Windows.Forms.RadioButton radioSizeAuto;
private System.Windows.Forms.CheckBox checkMediaPreviews; private System.Windows.Forms.CheckBox checkMediaPreviews;
private System.Windows.Forms.FlowLayoutPanel flowPanelLeft;
private System.Windows.Forms.Panel panelScrollSpeed;
private System.Windows.Forms.FlowLayoutPanel flowPanelRight;
private System.Windows.Forms.Panel panelSeparator;
} }
} }

View File

@@ -15,7 +15,7 @@ namespace TweetDuck.Core.Other.Settings{
this.notification = notification; this.notification = notification;
this.notification.Initialized += (sender, args) => { this.notification.Ready += (sender, args) => {
this.InvokeAsyncSafe(() => { this.InvokeAsyncSafe(() => {
this.notification.ShowExampleNotification(true); this.notification.ShowExampleNotification(true);
this.notification.Move += notification_Move; this.notification.Move += notification_Move;
@@ -26,6 +26,45 @@ namespace TweetDuck.Core.Other.Settings{
this.notification.Activated += notification_Activated; this.notification.Activated += notification_Activated;
this.notification.Show(); this.notification.Show();
Disposed += (sender, args) => this.notification.Dispose();
// general
toolTip.SetToolTip(checkColumnName, "Shows column name each notification originated\r\nfrom in the notification window title.");
toolTip.SetToolTip(checkMediaPreviews, "Shows image and video thumbnails in the notification window.");
toolTip.SetToolTip(checkSkipOnLinkClick, "Skips current notification when a link\r\ninside the notification is clicked.");
toolTip.SetToolTip(checkNonIntrusive, "When not idle and the cursor is within the notification window area,\r\nit will be delayed until the cursor moves away to prevent accidental clicks.");
toolTip.SetToolTip(comboBoxIdlePause, "Pauses new notifications after going idle for a set amount of time.");
checkColumnName.Checked = Config.DisplayNotificationColumn;
checkMediaPreviews.Checked = Config.NotificationMediaPreviews;
checkSkipOnLinkClick.Checked = Config.NotificationSkipOnLinkClick;
checkNonIntrusive.Checked = Config.NotificationNonIntrusiveMode;
comboBoxIdlePause.Items.Add("Disabled");
comboBoxIdlePause.Items.Add("30 seconds");
comboBoxIdlePause.Items.Add("1 minute");
comboBoxIdlePause.Items.Add("2 minutes");
comboBoxIdlePause.Items.Add("5 minutes");
comboBoxIdlePause.SelectedIndex = Math.Max(0, Array.FindIndex(IdlePauseSeconds, val => val == Config.NotificationIdlePauseSeconds));
// timer
toolTip.SetToolTip(checkTimerCountDown, "The notification timer counts down instead of up.");
toolTip.SetToolTip(labelDurationValue, "Milliseconds per character.");
toolTip.SetToolTip(trackBarDuration, toolTip.GetToolTip(labelDurationValue));
checkNotificationTimer.Checked = Config.DisplayNotificationTimer;
checkTimerCountDown.Enabled = checkNotificationTimer.Checked;
checkTimerCountDown.Checked = Config.NotificationTimerCountDown;
trackBarDuration.SetValueSafe(Config.NotificationDurationValue);
labelDurationValue.Text = Config.NotificationDurationValue+" ms/c";
// location
toolTip.SetToolTip(radioLocCustom, "Drag the example notification window to the desired location.");
switch(Config.NotificationPosition){ switch(Config.NotificationPosition){
case TweetNotification.Position.TopLeft: radioLocTL.Checked = true; break; case TweetNotification.Position.TopLeft: radioLocTL.Checked = true; break;
case TweetNotification.Position.TopRight: radioLocTR.Checked = true; break; case TweetNotification.Position.TopRight: radioLocTR.Checked = true; break;
@@ -35,23 +74,6 @@ namespace TweetDuck.Core.Other.Settings{
} }
comboBoxDisplay.Enabled = trackBarEdgeDistance.Enabled = !radioLocCustom.Checked; comboBoxDisplay.Enabled = trackBarEdgeDistance.Enabled = !radioLocCustom.Checked;
switch(Config.NotificationSize){
case TweetNotification.Size.Auto: radioSizeAuto.Checked = true; break;
case TweetNotification.Size.Custom: radioSizeCustom.Checked = true; break;
}
toolTip.SetToolTip(trackBarDuration, toolTip.GetToolTip(labelDurationValue));
trackBarDuration.SetValueSafe(Config.NotificationDurationValue);
labelDurationValue.Text = Config.NotificationDurationValue+" ms/c";
comboBoxIdlePause.Items.Add("Disabled");
comboBoxIdlePause.Items.Add("30 seconds");
comboBoxIdlePause.Items.Add("1 minute");
comboBoxIdlePause.Items.Add("2 minutes");
comboBoxIdlePause.Items.Add("5 minutes");
comboBoxIdlePause.SelectedIndex = Math.Max(0, Array.FindIndex(IdlePauseSeconds, val => val == Config.NotificationIdlePauseSeconds));
comboBoxDisplay.Items.Add("(Same as TweetDuck)"); comboBoxDisplay.Items.Add("(Same as TweetDuck)");
foreach(Screen screen in Screen.AllScreens){ foreach(Screen screen in Screen.AllScreens){
@@ -60,50 +82,48 @@ namespace TweetDuck.Core.Other.Settings{
comboBoxDisplay.SelectedIndex = Math.Min(comboBoxDisplay.Items.Count-1, Config.NotificationDisplay); comboBoxDisplay.SelectedIndex = Math.Min(comboBoxDisplay.Items.Count-1, Config.NotificationDisplay);
checkColumnName.Checked = Config.DisplayNotificationColumn;
checkNotificationTimer.Checked = Config.DisplayNotificationTimer;
checkTimerCountDown.Enabled = checkNotificationTimer.Checked;
checkTimerCountDown.Checked = Config.NotificationTimerCountDown;
checkMediaPreviews.Checked = Config.NotificationMediaPreviews;
checkSkipOnLinkClick.Checked = Config.NotificationSkipOnLinkClick;
checkNonIntrusive.Checked = Config.NotificationNonIntrusiveMode;
trackBarScrollSpeed.SetValueSafe(Config.NotificationScrollSpeed);
labelScrollSpeedValue.Text = trackBarScrollSpeed.Value+"%";
trackBarEdgeDistance.SetValueSafe(Config.NotificationEdgeDistance); trackBarEdgeDistance.SetValueSafe(Config.NotificationEdgeDistance);
labelEdgeDistanceValue.Text = trackBarEdgeDistance.Value+" px"; labelEdgeDistanceValue.Text = trackBarEdgeDistance.Value+" px";
Disposed += (sender, args) => this.notification.Dispose(); // size
toolTip.SetToolTip(radioSizeAuto, "Notification size is based on the font size and browser zoom level.");
toolTip.SetToolTip(radioSizeCustom, "Resize the example notification window to the desired size.");
switch(Config.NotificationSize){
case TweetNotification.Size.Auto: radioSizeAuto.Checked = true; break;
case TweetNotification.Size.Custom: radioSizeCustom.Checked = true; break;
}
trackBarScrollSpeed.SetValueSafe(Config.NotificationScrollSpeed);
labelScrollSpeedValue.Text = trackBarScrollSpeed.Value+"%";
} }
public override void OnReady(){ public override void OnReady(){
radioLocTL.CheckedChanged += radioLoc_CheckedChanged; checkColumnName.CheckedChanged += checkColumnName_CheckedChanged;
radioLocTR.CheckedChanged += radioLoc_CheckedChanged; checkMediaPreviews.CheckedChanged += checkMediaPreviews_CheckedChanged;
radioLocBL.CheckedChanged += radioLoc_CheckedChanged; checkSkipOnLinkClick.CheckedChanged += checkSkipOnLinkClick_CheckedChanged;
radioLocBR.CheckedChanged += radioLoc_CheckedChanged; checkNonIntrusive.CheckedChanged += checkNonIntrusive_CheckedChanged;
radioLocCustom.Click += radioLocCustom_Click; comboBoxIdlePause.SelectedValueChanged += comboBoxIdlePause_SelectedValueChanged;
radioSizeAuto.CheckedChanged += radioSize_CheckedChanged;
radioSizeCustom.Click += radioSizeCustom_Click;
checkNotificationTimer.CheckedChanged += checkNotificationTimer_CheckedChanged;
checkTimerCountDown.CheckedChanged += checkTimerCountDown_CheckedChanged;
trackBarDuration.ValueChanged += trackBarDuration_ValueChanged; trackBarDuration.ValueChanged += trackBarDuration_ValueChanged;
btnDurationShort.Click += btnDurationShort_Click; btnDurationShort.Click += btnDurationShort_Click;
btnDurationMedium.Click += btnDurationMedium_Click; btnDurationMedium.Click += btnDurationMedium_Click;
btnDurationLong.Click += btnDurationLong_Click; btnDurationLong.Click += btnDurationLong_Click;
checkColumnName.CheckedChanged += checkColumnName_CheckedChanged; radioLocTL.CheckedChanged += radioLoc_CheckedChanged;
checkNotificationTimer.CheckedChanged += checkNotificationTimer_CheckedChanged; radioLocTR.CheckedChanged += radioLoc_CheckedChanged;
checkTimerCountDown.CheckedChanged += checkTimerCountDown_CheckedChanged; radioLocBL.CheckedChanged += radioLoc_CheckedChanged;
checkMediaPreviews.CheckedChanged += checkMediaPreviews_CheckedChanged; radioLocBR.CheckedChanged += radioLoc_CheckedChanged;
checkSkipOnLinkClick.CheckedChanged += checkSkipOnLinkClick_CheckedChanged; radioLocCustom.Click += radioLocCustom_Click;
checkNonIntrusive.CheckedChanged += checkNonIntrusive_CheckedChanged;
comboBoxIdlePause.SelectedValueChanged += comboBoxIdlePause_SelectedValueChanged;
trackBarScrollSpeed.ValueChanged += trackBarScrollSpeed_ValueChanged;
comboBoxDisplay.SelectedValueChanged += comboBoxDisplay_SelectedValueChanged; comboBoxDisplay.SelectedValueChanged += comboBoxDisplay_SelectedValueChanged;
trackBarEdgeDistance.ValueChanged += trackBarEdgeDistance_ValueChanged; trackBarEdgeDistance.ValueChanged += trackBarEdgeDistance_ValueChanged;
radioSizeAuto.CheckedChanged += radioSize_CheckedChanged;
radioSizeCustom.Click += radioSizeCustom_Click;
trackBarScrollSpeed.ValueChanged += trackBarScrollSpeed_ValueChanged;
} }
private void TabSettingsNotifications_ParentChanged(object sender, EventArgs e){ private void TabSettingsNotifications_ParentChanged(object sender, EventArgs e){
@@ -133,52 +153,41 @@ namespace TweetDuck.Core.Other.Settings{
} }
} }
private void radioLoc_CheckedChanged(object sender, EventArgs e){ #region General
if (radioLocTL.Checked)Config.NotificationPosition = TweetNotification.Position.TopLeft;
else if (radioLocTR.Checked)Config.NotificationPosition = TweetNotification.Position.TopRight;
else if (radioLocBL.Checked)Config.NotificationPosition = TweetNotification.Position.BottomLeft;
else if (radioLocBR.Checked)Config.NotificationPosition = TweetNotification.Position.BottomRight;
comboBoxDisplay.Enabled = trackBarEdgeDistance.Enabled = true; private void checkColumnName_CheckedChanged(object sender, EventArgs e){
Config.DisplayNotificationColumn = checkColumnName.Checked;
notification.ShowExampleNotification(false); notification.ShowExampleNotification(false);
} }
private void radioLocCustom_Click(object sender, EventArgs e){ private void checkMediaPreviews_CheckedChanged(object sender, EventArgs e){
if (!Config.IsCustomNotificationPositionSet){ Config.NotificationMediaPreviews = checkMediaPreviews.Checked;
Config.CustomNotificationPosition = notification.Location;
} }
Config.NotificationPosition = TweetNotification.Position.Custom; private void checkSkipOnLinkClick_CheckedChanged(object sender, EventArgs e){
Config.NotificationSkipOnLinkClick = checkSkipOnLinkClick.Checked;
comboBoxDisplay.Enabled = trackBarEdgeDistance.Enabled = false;
notification.ShowExampleNotification(false);
if (notification.IsFullyOutsideView() && FormMessage.Question("Notification is outside view", "The notification seems to be outside of view, would you like to reset its position?", FormMessage.Yes, FormMessage.No)){
Config.NotificationPosition = TweetNotification.Position.TopRight;
notification.MoveToVisibleLocation();
Config.CustomNotificationPosition = notification.Location;
Config.NotificationPosition = TweetNotification.Position.Custom;
notification.MoveToVisibleLocation();
}
} }
private void radioSize_CheckedChanged(object sender, EventArgs e){ private void checkNonIntrusive_CheckedChanged(object sender, EventArgs e){
if (radioSizeAuto.Checked){ Config.NotificationNonIntrusiveMode = checkNonIntrusive.Checked;
Config.NotificationSize = TweetNotification.Size.Auto;
} }
notification.ShowExampleNotification(false); private void comboBoxIdlePause_SelectedValueChanged(object sender, EventArgs e){
Config.NotificationIdlePauseSeconds = IdlePauseSeconds[comboBoxIdlePause.SelectedIndex];
} }
private void radioSizeCustom_Click(object sender, EventArgs e){ #endregion
if (!Config.IsCustomNotificationSizeSet){ #region Timer
Config.CustomNotificationSize = notification.BrowserSize;
private void checkNotificationTimer_CheckedChanged(object sender, EventArgs e){
Config.DisplayNotificationTimer = checkNotificationTimer.Checked;
checkTimerCountDown.Enabled = checkNotificationTimer.Checked;
notification.ShowExampleNotification(true);
} }
Config.NotificationSize = TweetNotification.Size.Custom; private void checkTimerCountDown_CheckedChanged(object sender, EventArgs e){
notification.ShowExampleNotification(false); Config.NotificationTimerCountDown = checkTimerCountDown.Checked;
notification.ShowExampleNotification(true);
} }
private void trackBarDuration_ValueChanged(object sender, EventArgs e){ private void trackBarDuration_ValueChanged(object sender, EventArgs e){
@@ -201,42 +210,42 @@ namespace TweetDuck.Core.Other.Settings{
trackBarDuration.Value = 35; trackBarDuration.Value = 35;
} }
private void checkColumnName_CheckedChanged(object sender, EventArgs e){ private void durationUpdateTimer_Tick(object sender, EventArgs e){
Config.DisplayNotificationColumn = checkColumnName.Checked; notification.ShowExampleNotification(true);
durationUpdateTimer.Stop();
}
#endregion
#region Location
private void radioLoc_CheckedChanged(object sender, EventArgs e){
if (radioLocTL.Checked)Config.NotificationPosition = TweetNotification.Position.TopLeft;
else if (radioLocTR.Checked)Config.NotificationPosition = TweetNotification.Position.TopRight;
else if (radioLocBL.Checked)Config.NotificationPosition = TweetNotification.Position.BottomLeft;
else if (radioLocBR.Checked)Config.NotificationPosition = TweetNotification.Position.BottomRight;
comboBoxDisplay.Enabled = trackBarEdgeDistance.Enabled = true;
notification.ShowExampleNotification(false); notification.ShowExampleNotification(false);
} }
private void checkNotificationTimer_CheckedChanged(object sender, EventArgs e){ private void radioLocCustom_Click(object sender, EventArgs e){
Config.DisplayNotificationTimer = checkNotificationTimer.Checked; if (!Config.IsCustomNotificationPositionSet){
checkTimerCountDown.Enabled = checkNotificationTimer.Checked; Config.CustomNotificationPosition = notification.Location;
notification.ShowExampleNotification(true);
} }
private void checkTimerCountDown_CheckedChanged(object sender, EventArgs e){ Config.NotificationPosition = TweetNotification.Position.Custom;
Config.NotificationTimerCountDown = checkTimerCountDown.Checked;
notification.ShowExampleNotification(true);
}
private void checkMediaPreviews_CheckedChanged(object sender, EventArgs e){ comboBoxDisplay.Enabled = trackBarEdgeDistance.Enabled = false;
Config.NotificationMediaPreviews = checkMediaPreviews.Checked; notification.ShowExampleNotification(false);
}
private void checkSkipOnLinkClick_CheckedChanged(object sender, EventArgs e){ if (notification.IsFullyOutsideView() && FormMessage.Question("Notification is Outside View", "The notification seems to be outside of view, would you like to reset its position?", FormMessage.Yes, FormMessage.No)){
Config.NotificationSkipOnLinkClick = checkSkipOnLinkClick.Checked; Config.NotificationPosition = TweetNotification.Position.TopRight;
} notification.MoveToVisibleLocation();
private void checkNonIntrusive_CheckedChanged(object sender, EventArgs e){ Config.CustomNotificationPosition = notification.Location;
Config.NotificationNonIntrusiveMode = checkNonIntrusive.Checked;
}
private void comboBoxIdlePause_SelectedValueChanged(object sender, EventArgs e){ Config.NotificationPosition = TweetNotification.Position.Custom;
Config.NotificationIdlePauseSeconds = IdlePauseSeconds[comboBoxIdlePause.SelectedIndex]; notification.MoveToVisibleLocation();
}
private void trackBarScrollSpeed_ValueChanged(object sender, EventArgs e){
if (trackBarScrollSpeed.AlignValueToTick()){
labelScrollSpeedValue.Text = trackBarScrollSpeed.Value+"%";
Config.NotificationScrollSpeed = trackBarScrollSpeed.Value;
} }
} }
@@ -251,9 +260,33 @@ namespace TweetDuck.Core.Other.Settings{
notification.ShowExampleNotification(false); notification.ShowExampleNotification(false);
} }
private void durationUpdateTimer_Tick(object sender, EventArgs e){ #endregion
notification.ShowExampleNotification(true); #region Size
durationUpdateTimer.Stop();
private void radioSize_CheckedChanged(object sender, EventArgs e){
if (radioSizeAuto.Checked){
Config.NotificationSize = TweetNotification.Size.Auto;
}
notification.ShowExampleNotification(false);
}
private void radioSizeCustom_Click(object sender, EventArgs e){
if (!Config.IsCustomNotificationSizeSet){
Config.CustomNotificationSize = notification.BrowserSize;
}
Config.NotificationSize = TweetNotification.Size.Custom;
notification.ShowExampleNotification(false);
}
private void trackBarScrollSpeed_ValueChanged(object sender, EventArgs e){
if (trackBarScrollSpeed.AlignValueToTick()){
labelScrollSpeedValue.Text = trackBarScrollSpeed.Value+"%";
Config.NotificationScrollSpeed = trackBarScrollSpeed.Value;
} }
} }
#endregion
}
} }

View File

@@ -34,28 +34,34 @@
this.panelSoundNotification = new System.Windows.Forms.Panel(); this.panelSoundNotification = new System.Windows.Forms.Panel();
this.labelVolume = new System.Windows.Forms.Label(); this.labelVolume = new System.Windows.Forms.Label();
this.trackBarVolume = new System.Windows.Forms.TrackBar(); this.trackBarVolume = new System.Windows.Forms.TrackBar();
this.flowPanel = new System.Windows.Forms.FlowLayoutPanel();
this.panelVolume = new System.Windows.Forms.Panel();
this.volumeUpdateTimer = new System.Windows.Forms.Timer(this.components);
this.panelSoundNotification.SuspendLayout(); this.panelSoundNotification.SuspendLayout();
((System.ComponentModel.ISupportInitialize)(this.trackBarVolume)).BeginInit(); ((System.ComponentModel.ISupportInitialize)(this.trackBarVolume)).BeginInit();
this.flowPanel.SuspendLayout();
this.panelVolume.SuspendLayout();
this.SuspendLayout(); this.SuspendLayout();
// //
// tbCustomSound // tbCustomSound
// //
this.tbCustomSound.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) this.tbCustomSound.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left)
| System.Windows.Forms.AnchorStyles.Right))); | System.Windows.Forms.AnchorStyles.Right)));
this.tbCustomSound.Font = new System.Drawing.Font("Segoe UI", 9F);
this.tbCustomSound.Location = new System.Drawing.Point(3, 3); this.tbCustomSound.Location = new System.Drawing.Point(3, 3);
this.tbCustomSound.Name = "tbCustomSound"; this.tbCustomSound.Name = "tbCustomSound";
this.tbCustomSound.Size = new System.Drawing.Size(316, 20); this.tbCustomSound.Size = new System.Drawing.Size(316, 23);
this.tbCustomSound.TabIndex = 0; this.tbCustomSound.TabIndex = 0;
this.toolTip.SetToolTip(this.tbCustomSound, "When empty, the default TweetDeck sound notification is used.");
// //
// labelVolumeValue // labelVolumeValue
// //
this.labelVolumeValue.BackColor = System.Drawing.Color.Transparent; this.labelVolumeValue.BackColor = System.Drawing.Color.Transparent;
this.labelVolumeValue.Location = new System.Drawing.Point(147, 84); this.labelVolumeValue.Font = new System.Drawing.Font("Segoe UI", 9F);
this.labelVolumeValue.Location = new System.Drawing.Point(147, 4);
this.labelVolumeValue.Margin = new System.Windows.Forms.Padding(0, 0, 3, 0); this.labelVolumeValue.Margin = new System.Windows.Forms.Padding(0, 0, 3, 0);
this.labelVolumeValue.Name = "labelVolumeValue"; this.labelVolumeValue.Name = "labelVolumeValue";
this.labelVolumeValue.Size = new System.Drawing.Size(38, 13); this.labelVolumeValue.Size = new System.Drawing.Size(38, 15);
this.labelVolumeValue.TabIndex = 6; this.labelVolumeValue.TabIndex = 1;
this.labelVolumeValue.Text = "100%"; this.labelVolumeValue.Text = "100%";
this.labelVolumeValue.TextAlign = System.Drawing.ContentAlignment.TopRight; this.labelVolumeValue.TextAlign = System.Drawing.ContentAlignment.TopRight;
// //
@@ -63,10 +69,11 @@
// //
this.btnPlaySound.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right))); this.btnPlaySound.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right)));
this.btnPlaySound.AutoSize = true; this.btnPlaySound.AutoSize = true;
this.btnPlaySound.Location = new System.Drawing.Point(203, 29); this.btnPlaySound.Font = new System.Drawing.Font("Segoe UI", 9F);
this.btnPlaySound.Location = new System.Drawing.Point(202, 32);
this.btnPlaySound.Name = "btnPlaySound"; this.btnPlaySound.Name = "btnPlaySound";
this.btnPlaySound.Padding = new System.Windows.Forms.Padding(3, 0, 3, 0); this.btnPlaySound.Padding = new System.Windows.Forms.Padding(2, 0, 2, 0);
this.btnPlaySound.Size = new System.Drawing.Size(43, 23); this.btnPlaySound.Size = new System.Drawing.Size(43, 25);
this.btnPlaySound.TabIndex = 2; this.btnPlaySound.TabIndex = 2;
this.btnPlaySound.Text = "Play"; this.btnPlaySound.Text = "Play";
this.btnPlaySound.UseVisualStyleBackColor = true; this.btnPlaySound.UseVisualStyleBackColor = true;
@@ -74,10 +81,11 @@
// btnResetSound // btnResetSound
// //
this.btnResetSound.AutoSize = true; this.btnResetSound.AutoSize = true;
this.btnResetSound.Location = new System.Drawing.Point(3, 29); this.btnResetSound.Font = new System.Drawing.Font("Segoe UI", 9F);
this.btnResetSound.Location = new System.Drawing.Point(3, 32);
this.btnResetSound.Name = "btnResetSound"; this.btnResetSound.Name = "btnResetSound";
this.btnResetSound.Padding = new System.Windows.Forms.Padding(3, 0, 3, 0); this.btnResetSound.Padding = new System.Windows.Forms.Padding(2, 0, 2, 0);
this.btnResetSound.Size = new System.Drawing.Size(51, 23); this.btnResetSound.Size = new System.Drawing.Size(49, 25);
this.btnResetSound.TabIndex = 3; this.btnResetSound.TabIndex = 3;
this.btnResetSound.Text = "Reset"; this.btnResetSound.Text = "Reset";
this.btnResetSound.UseVisualStyleBackColor = true; this.btnResetSound.UseVisualStyleBackColor = true;
@@ -86,10 +94,11 @@
// //
this.btnBrowseSound.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right))); this.btnBrowseSound.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right)));
this.btnBrowseSound.AutoSize = true; this.btnBrowseSound.AutoSize = true;
this.btnBrowseSound.Location = new System.Drawing.Point(252, 29); this.btnBrowseSound.Font = new System.Drawing.Font("Segoe UI", 9F);
this.btnBrowseSound.Location = new System.Drawing.Point(251, 32);
this.btnBrowseSound.Name = "btnBrowseSound"; this.btnBrowseSound.Name = "btnBrowseSound";
this.btnBrowseSound.Padding = new System.Windows.Forms.Padding(3, 0, 3, 0); this.btnBrowseSound.Padding = new System.Windows.Forms.Padding(2, 0, 2, 0);
this.btnBrowseSound.Size = new System.Drawing.Size(67, 23); this.btnBrowseSound.Size = new System.Drawing.Size(68, 25);
this.btnBrowseSound.TabIndex = 1; this.btnBrowseSound.TabIndex = 1;
this.btnBrowseSound.Text = "Browse..."; this.btnBrowseSound.Text = "Browse...";
this.btnBrowseSound.UseVisualStyleBackColor = true; this.btnBrowseSound.UseVisualStyleBackColor = true;
@@ -97,67 +106,94 @@
// labelSoundNotification // labelSoundNotification
// //
this.labelSoundNotification.AutoSize = true; this.labelSoundNotification.AutoSize = true;
this.labelSoundNotification.Font = new System.Drawing.Font("Microsoft Sans Serif", 12F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(238))); this.labelSoundNotification.Font = new System.Drawing.Font("Segoe UI Semibold", 10.5F, System.Drawing.FontStyle.Bold);
this.labelSoundNotification.Location = new System.Drawing.Point(6, 8); this.labelSoundNotification.Location = new System.Drawing.Point(0, 0);
this.labelSoundNotification.Margin = new System.Windows.Forms.Padding(0, 2, 0, 0); this.labelSoundNotification.Margin = new System.Windows.Forms.Padding(0, 0, 0, 1);
this.labelSoundNotification.Name = "labelSoundNotification"; this.labelSoundNotification.Name = "labelSoundNotification";
this.labelSoundNotification.Size = new System.Drawing.Size(198, 20); this.labelSoundNotification.Size = new System.Drawing.Size(160, 19);
this.labelSoundNotification.TabIndex = 1; this.labelSoundNotification.TabIndex = 0;
this.labelSoundNotification.Text = "Custom Sound Notification"; this.labelSoundNotification.Text = "SOUND NOTIFICATION";
// //
// panelSoundNotification // panelSoundNotification
// //
this.panelSoundNotification.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left)
| System.Windows.Forms.AnchorStyles.Right)));
this.panelSoundNotification.Controls.Add(this.labelVolume);
this.panelSoundNotification.Controls.Add(this.trackBarVolume);
this.panelSoundNotification.Controls.Add(this.btnPlaySound); this.panelSoundNotification.Controls.Add(this.btnPlaySound);
this.panelSoundNotification.Controls.Add(this.tbCustomSound); this.panelSoundNotification.Controls.Add(this.tbCustomSound);
this.panelSoundNotification.Controls.Add(this.btnResetSound); this.panelSoundNotification.Controls.Add(this.btnResetSound);
this.panelSoundNotification.Controls.Add(this.btnBrowseSound); this.panelSoundNotification.Controls.Add(this.btnBrowseSound);
this.panelSoundNotification.Controls.Add(this.labelVolumeValue); this.panelSoundNotification.Location = new System.Drawing.Point(0, 20);
this.panelSoundNotification.Location = new System.Drawing.Point(9, 31); this.panelSoundNotification.Margin = new System.Windows.Forms.Padding(0);
this.panelSoundNotification.Name = "panelSoundNotification"; this.panelSoundNotification.Name = "panelSoundNotification";
this.panelSoundNotification.Size = new System.Drawing.Size(322, 119); this.panelSoundNotification.Size = new System.Drawing.Size(322, 59);
this.panelSoundNotification.TabIndex = 2; this.panelSoundNotification.TabIndex = 1;
// //
// labelVolume // labelVolume
// //
this.labelVolume.AutoSize = true; this.labelVolume.AutoSize = true;
this.labelVolume.Location = new System.Drawing.Point(3, 67); this.labelVolume.Font = new System.Drawing.Font("Segoe UI Semibold", 9F, System.Drawing.FontStyle.Bold);
this.labelVolume.Location = new System.Drawing.Point(3, 91);
this.labelVolume.Margin = new System.Windows.Forms.Padding(3, 12, 3, 0); this.labelVolume.Margin = new System.Windows.Forms.Padding(3, 12, 3, 0);
this.labelVolume.Name = "labelVolume"; this.labelVolume.Name = "labelVolume";
this.labelVolume.Size = new System.Drawing.Size(42, 13); this.labelVolume.Size = new System.Drawing.Size(49, 15);
this.labelVolume.TabIndex = 4; this.labelVolume.TabIndex = 2;
this.labelVolume.Text = "Volume"; this.labelVolume.Text = "Volume";
// //
// trackBarVolume // trackBarVolume
// //
this.trackBarVolume.AutoSize = false; this.trackBarVolume.AutoSize = false;
this.trackBarVolume.BackColor = System.Drawing.SystemColors.Control; this.trackBarVolume.BackColor = System.Drawing.SystemColors.Control;
this.trackBarVolume.Location = new System.Drawing.Point(3, 83); this.trackBarVolume.Location = new System.Drawing.Point(3, 3);
this.trackBarVolume.Maximum = 100; this.trackBarVolume.Maximum = 100;
this.trackBarVolume.Name = "trackBarVolume"; this.trackBarVolume.Name = "trackBarVolume";
this.trackBarVolume.Size = new System.Drawing.Size(148, 30); this.trackBarVolume.Size = new System.Drawing.Size(148, 30);
this.trackBarVolume.SmallChange = 1; this.trackBarVolume.TabIndex = 0;
this.trackBarVolume.TabIndex = 5;
this.trackBarVolume.TickFrequency = 10; this.trackBarVolume.TickFrequency = 10;
this.trackBarVolume.Value = 100; this.trackBarVolume.Value = 100;
this.trackBarVolume.ValueChanged += new System.EventHandler(this.trackBarVolume_ValueChanged); this.trackBarVolume.ValueChanged += new System.EventHandler(this.trackBarVolume_ValueChanged);
// //
// flowPanel
//
this.flowPanel.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom)
| System.Windows.Forms.AnchorStyles.Left)));
this.flowPanel.Controls.Add(this.labelSoundNotification);
this.flowPanel.Controls.Add(this.panelSoundNotification);
this.flowPanel.Controls.Add(this.labelVolume);
this.flowPanel.Controls.Add(this.panelVolume);
this.flowPanel.FlowDirection = System.Windows.Forms.FlowDirection.TopDown;
this.flowPanel.Location = new System.Drawing.Point(9, 9);
this.flowPanel.Name = "flowPanel";
this.flowPanel.Size = new System.Drawing.Size(322, 462);
this.flowPanel.TabIndex = 0;
this.flowPanel.WrapContents = false;
//
// panelVolume
//
this.panelVolume.Controls.Add(this.trackBarVolume);
this.panelVolume.Controls.Add(this.labelVolumeValue);
this.panelVolume.Location = new System.Drawing.Point(0, 107);
this.panelVolume.Margin = new System.Windows.Forms.Padding(0, 1, 0, 0);
this.panelVolume.Name = "panelVolume";
this.panelVolume.Size = new System.Drawing.Size(322, 36);
this.panelVolume.TabIndex = 3;
//
// volumeUpdateTimer
//
this.volumeUpdateTimer.Interval = 250;
this.volumeUpdateTimer.Tick += new System.EventHandler(this.volumeUpdateTimer_Tick);
//
// TabSettingsSounds // TabSettingsSounds
// //
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
this.Controls.Add(this.panelSoundNotification); this.Controls.Add(this.flowPanel);
this.Controls.Add(this.labelSoundNotification);
this.Name = "TabSettingsSounds"; this.Name = "TabSettingsSounds";
this.Size = new System.Drawing.Size(340, 160); this.Size = new System.Drawing.Size(631, 480);
this.panelSoundNotification.ResumeLayout(false); this.panelSoundNotification.ResumeLayout(false);
this.panelSoundNotification.PerformLayout(); this.panelSoundNotification.PerformLayout();
((System.ComponentModel.ISupportInitialize)(this.trackBarVolume)).EndInit(); ((System.ComponentModel.ISupportInitialize)(this.trackBarVolume)).EndInit();
this.flowPanel.ResumeLayout(false);
this.flowPanel.PerformLayout();
this.panelVolume.ResumeLayout(false);
this.ResumeLayout(false); this.ResumeLayout(false);
this.PerformLayout();
} }
@@ -173,5 +209,8 @@
private System.Windows.Forms.Label labelVolume; private System.Windows.Forms.Label labelVolume;
private System.Windows.Forms.Label labelVolumeValue; private System.Windows.Forms.Label labelVolumeValue;
private System.Windows.Forms.TrackBar trackBarVolume; private System.Windows.Forms.TrackBar trackBarVolume;
private System.Windows.Forms.FlowLayoutPanel flowPanel;
private System.Windows.Forms.Panel panelVolume;
private System.Windows.Forms.Timer volumeUpdateTimer;
} }
} }

View File

@@ -4,29 +4,27 @@ using System.IO;
using System.Windows.Forms; using System.Windows.Forms;
using TweetDuck.Core.Controls; using TweetDuck.Core.Controls;
using TweetDuck.Core.Notification; using TweetDuck.Core.Notification;
using TweetLib.Audio; using TweetDuck.Core.Utils;
namespace TweetDuck.Core.Other.Settings{ namespace TweetDuck.Core.Other.Settings{
sealed partial class TabSettingsSounds : BaseTabSettings{ sealed partial class TabSettingsSounds : BaseTabSettings{
private readonly SoundNotification soundNotification; private readonly Action playSoundNotification;
private readonly bool supportsChangingVolume;
public TabSettingsSounds(){ public TabSettingsSounds(Action playSoundNotification){
InitializeComponent(); InitializeComponent();
soundNotification = new SoundNotification(); this.playSoundNotification = playSoundNotification;
soundNotification.PlaybackError += sound_PlaybackError;
supportsChangingVolume = soundNotification.SetVolume(Config.NotificationSoundVolume); // sound notification
toolTip.SetToolTip(tbCustomSound, "When empty, the default TweetDeck sound notification is used.");
trackBarVolume.Enabled = supportsChangingVolume && !string.IsNullOrEmpty(Config.NotificationSoundPath);
trackBarVolume.SetValueSafe(Config.NotificationSoundVolume); trackBarVolume.SetValueSafe(Config.NotificationSoundVolume);
labelVolumeValue.Text = trackBarVolume.Value+"%"; labelVolumeValue.Text = trackBarVolume.Value+"%";
tbCustomSound.Text = Config.NotificationSoundPath; tbCustomSound.Text = Config.NotificationSoundPath;
tbCustomSound_TextChanged(tbCustomSound, EventArgs.Empty); tbCustomSound_TextChanged(tbCustomSound, EventArgs.Empty);
NativeMethods.SendMessage(tbCustomSound.Handle, NativeMethods.EM_SETCUEBANNER, 0, "(default TweetDeck sound)");
Disposed += (sender, args) => soundNotification.Dispose();
} }
public override void OnReady(){ public override void OnReady(){
@@ -38,22 +36,31 @@ namespace TweetDuck.Core.Other.Settings{
public override void OnClosing(){ public override void OnClosing(){
Config.NotificationSoundPath = tbCustomSound.Text; Config.NotificationSoundPath = tbCustomSound.Text;
Config.NotificationSoundVolume = trackBarVolume.Value;
}
#region Sound Notification
private bool RefreshCanPlay(){
bool isEmpty = string.IsNullOrEmpty(tbCustomSound.Text);
bool canPlay = isEmpty || File.Exists(tbCustomSound.Text);
tbCustomSound.ForeColor = canPlay ? SystemColors.WindowText : Color.Red;
btnPlaySound.Enabled = canPlay;
btnResetSound.Enabled = !isEmpty;
return canPlay;
} }
private void tbCustomSound_TextChanged(object sender, EventArgs e){ private void tbCustomSound_TextChanged(object sender, EventArgs e){
bool isEmpty = string.IsNullOrEmpty(tbCustomSound.Text); RefreshCanPlay();
tbCustomSound.ForeColor = isEmpty || File.Exists(tbCustomSound.Text) ? SystemColors.WindowText : Color.Red;
btnPlaySound.Enabled = !isEmpty;
btnResetSound.Enabled = !isEmpty;
trackBarVolume.Enabled = supportsChangingVolume && !isEmpty;
} }
private void btnPlaySound_Click(object sender, EventArgs e){ private void btnPlaySound_Click(object sender, EventArgs e){
soundNotification.Play(tbCustomSound.Text); if (RefreshCanPlay()){
Config.NotificationSoundPath = tbCustomSound.Text;
Config.NotificationSoundVolume = trackBarVolume.Value;
playSoundNotification();
} }
private void sound_PlaybackError(object sender, PlaybackErrorEventArgs e){
FormMessage.Error("Notification Sound Error", "Could not play custom notification sound.\n"+e.Message, FormMessage.OK);
} }
private void btnBrowseSound_Click(object sender, EventArgs e){ private void btnBrowseSound_Click(object sender, EventArgs e){
@@ -61,7 +68,7 @@ namespace TweetDuck.Core.Other.Settings{
AutoUpgradeEnabled = true, AutoUpgradeEnabled = true,
DereferenceLinks = true, DereferenceLinks = true,
Title = "Custom Notification Sound", Title = "Custom Notification Sound",
Filter = "Sound file ("+soundNotification.SupportedFormats+")|"+soundNotification.SupportedFormats+"|All files (*.*)|*.*" Filter = $"Sound file ({SoundNotification.SupportedFormats})|{SoundNotification.SupportedFormats}|All files (*.*)|*.*"
}){ }){
if (dialog.ShowDialog() == DialogResult.OK){ if (dialog.ShowDialog() == DialogResult.OK){
tbCustomSound.Text = dialog.FileName; tbCustomSound.Text = dialog.FileName;
@@ -74,9 +81,16 @@ namespace TweetDuck.Core.Other.Settings{
} }
private void trackBarVolume_ValueChanged(object sender, EventArgs e){ private void trackBarVolume_ValueChanged(object sender, EventArgs e){
volumeUpdateTimer.Stop();
volumeUpdateTimer.Start();
labelVolumeValue.Text = trackBarVolume.Value+"%";
}
private void volumeUpdateTimer_Tick(object sender, EventArgs e){
Config.NotificationSoundVolume = trackBarVolume.Value; Config.NotificationSoundVolume = trackBarVolume.Value;
soundNotification.SetVolume(Config.NotificationSoundVolume); volumeUpdateTimer.Stop();
labelVolumeValue.Text = Config.NotificationSoundVolume+"%"; }
}
#endregion
} }
} }

View File

@@ -1,116 +0,0 @@
namespace TweetDuck.Core.Other.Settings {
partial class TabSettingsTray {
/// <summary>
/// Required designer variable.
/// </summary>
private System.ComponentModel.IContainer components = null;
/// <summary>
/// Clean up any resources being used.
/// </summary>
/// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
protected override void Dispose(bool disposing) {
if (disposing && (components != null)) {
components.Dispose();
}
base.Dispose(disposing);
}
#region Component Designer generated code
/// <summary>
/// Required method for Designer support - do not modify
/// the contents of this method with the code editor.
/// </summary>
private void InitializeComponent() {
this.components = new System.ComponentModel.Container();
this.panelTray = new System.Windows.Forms.Panel();
this.checkTrayHighlight = new System.Windows.Forms.CheckBox();
this.comboBoxTrayType = new System.Windows.Forms.ComboBox();
this.labelTrayIcon = new System.Windows.Forms.Label();
this.labelTray = new System.Windows.Forms.Label();
this.toolTip = new System.Windows.Forms.ToolTip(this.components);
this.panelTray.SuspendLayout();
this.SuspendLayout();
//
// panelTray
//
this.panelTray.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left)
| System.Windows.Forms.AnchorStyles.Right)));
this.panelTray.Controls.Add(this.checkTrayHighlight);
this.panelTray.Controls.Add(this.comboBoxTrayType);
this.panelTray.Controls.Add(this.labelTrayIcon);
this.panelTray.Location = new System.Drawing.Point(9, 31);
this.panelTray.Name = "panelTray";
this.panelTray.Size = new System.Drawing.Size(322, 76);
this.panelTray.TabIndex = 1;
//
// checkTrayHighlight
//
this.checkTrayHighlight.AutoSize = true;
this.checkTrayHighlight.Location = new System.Drawing.Point(6, 56);
this.checkTrayHighlight.Margin = new System.Windows.Forms.Padding(6, 5, 3, 3);
this.checkTrayHighlight.Name = "checkTrayHighlight";
this.checkTrayHighlight.Size = new System.Drawing.Size(103, 17);
this.checkTrayHighlight.TabIndex = 2;
this.checkTrayHighlight.Text = "Enable Highlight";
this.toolTip.SetToolTip(this.checkTrayHighlight, "Highlights the tray icon if there are new tweets.\r\nOnly works for columns with popup or audio notifications.\r\nThe icon resets when the main window is restored.");
this.checkTrayHighlight.UseVisualStyleBackColor = true;
//
// comboBoxTrayType
//
this.comboBoxTrayType.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList;
this.comboBoxTrayType.FormattingEnabled = true;
this.comboBoxTrayType.Location = new System.Drawing.Point(5, 5);
this.comboBoxTrayType.Margin = new System.Windows.Forms.Padding(5, 5, 3, 3);
this.comboBoxTrayType.Name = "comboBoxTrayType";
this.comboBoxTrayType.Size = new System.Drawing.Size(144, 21);
this.comboBoxTrayType.TabIndex = 0;
this.toolTip.SetToolTip(this.comboBoxTrayType, "Changes behavior of the Tray icon.\r\nRight-click the icon for an action menu.");
//
// labelTrayIcon
//
this.labelTrayIcon.AutoSize = true;
this.labelTrayIcon.Location = new System.Drawing.Point(3, 38);
this.labelTrayIcon.Margin = new System.Windows.Forms.Padding(3, 9, 3, 0);
this.labelTrayIcon.Name = "labelTrayIcon";
this.labelTrayIcon.Size = new System.Drawing.Size(52, 13);
this.labelTrayIcon.TabIndex = 1;
this.labelTrayIcon.Text = "Tray Icon";
//
// labelTray
//
this.labelTray.AutoSize = true;
this.labelTray.Font = new System.Drawing.Font("Microsoft Sans Serif", 12F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(238)));
this.labelTray.Location = new System.Drawing.Point(6, 8);
this.labelTray.Margin = new System.Windows.Forms.Padding(0, 2, 0, 0);
this.labelTray.Name = "labelTray";
this.labelTray.Size = new System.Drawing.Size(96, 20);
this.labelTray.TabIndex = 0;
this.labelTray.Text = "System Tray";
//
// TabSettingsTray
//
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
this.Controls.Add(this.panelTray);
this.Controls.Add(this.labelTray);
this.Name = "TabSettingsTray";
this.Size = new System.Drawing.Size(340, 119);
this.panelTray.ResumeLayout(false);
this.panelTray.PerformLayout();
this.ResumeLayout(false);
this.PerformLayout();
}
#endregion
private System.Windows.Forms.Panel panelTray;
private System.Windows.Forms.CheckBox checkTrayHighlight;
private System.Windows.Forms.ComboBox comboBoxTrayType;
private System.Windows.Forms.Label labelTrayIcon;
private System.Windows.Forms.Label labelTray;
private System.Windows.Forms.ToolTip toolTip;
}
}

View File

@@ -1,33 +0,0 @@
using System;
namespace TweetDuck.Core.Other.Settings{
sealed partial class TabSettingsTray : BaseTabSettings{
public TabSettingsTray(){
InitializeComponent();
comboBoxTrayType.Items.Add("Disabled");
comboBoxTrayType.Items.Add("Display Icon Only");
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);
checkTrayHighlight.Enabled = Config.TrayBehavior.ShouldDisplayIcon();
checkTrayHighlight.Checked = Config.EnableTrayHighlight;
}
public override void OnReady(){
comboBoxTrayType.SelectedIndexChanged += comboBoxTrayType_SelectedIndexChanged;
checkTrayHighlight.CheckedChanged += checkTrayHighlight_CheckedChanged;
}
private void comboBoxTrayType_SelectedIndexChanged(object sender, EventArgs e){
Config.TrayBehavior = (TrayIcon.Behavior)comboBoxTrayType.SelectedIndex;
checkTrayHighlight.Enabled = Config.TrayBehavior.ShouldDisplayIcon();
}
private void checkTrayHighlight_CheckedChanged(object sender, EventArgs e){
Config.EnableTrayHighlight = checkTrayHighlight.Checked;
}
}
}

View File

@@ -1,6 +1,8 @@
using System; using System;
using System.ComponentModel; using System.ComponentModel;
using System.Windows.Forms; using System.Windows.Forms;
using TweetDuck.Configuration;
using Res = TweetDuck.Properties.Resources;
namespace TweetDuck.Core.Other{ namespace TweetDuck.Core.Other{
sealed partial class TrayIcon : Component{ sealed partial class TrayIcon : Component{
@@ -8,6 +10,8 @@ namespace TweetDuck.Core.Other{
Disabled, DisplayOnly, MinimizeToTray, CloseToTray, Combined Disabled, DisplayOnly, MinimizeToTray, CloseToTray, Combined
} }
private static UserConfig Config => Program.Config.User;
public event EventHandler ClickRestore; public event EventHandler ClickRestore;
public event EventHandler ClickClose; public event EventHandler ClickClose;
@@ -17,12 +21,9 @@ namespace TweetDuck.Core.Other{
} }
set{ set{
if (value){
notifyIcon.Icon = Properties.Resources.icon_tray;
}
notifyIcon.Visible = value; notifyIcon.Visible = value;
hasNotifications = false; hasNotifications = false;
UpdateIcon();
} }
} }
@@ -32,9 +33,9 @@ namespace TweetDuck.Core.Other{
} }
set{ set{
if (hasNotifications != value && Visible){ if (hasNotifications != value){
notifyIcon.Icon = value ? Properties.Resources.icon_tray_new : Properties.Resources.icon_tray;
hasNotifications = value; hasNotifications = value;
UpdateIcon();
} }
} }
} }
@@ -53,14 +54,27 @@ namespace TweetDuck.Core.Other{
this.notifyIcon.ContextMenu = contextMenu; this.notifyIcon.ContextMenu = contextMenu;
this.notifyIcon.Text = Program.BrandName; this.notifyIcon.Text = Program.BrandName;
Config.MuteToggled += Config_MuteToggled;
Disposed += (sender, args) => Config.MuteToggled -= Config_MuteToggled;
} }
public TrayIcon(IContainer container) : this(){ public TrayIcon(IContainer container) : this(){
container.Add(this); container.Add(this);
} }
private void UpdateIcon(){
if (Visible){
notifyIcon.Icon = hasNotifications ? Res.icon_tray_new : Config.MuteNotifications ? Res.icon_tray_muted : Res.icon_tray;
}
}
// event handlers // event handlers
private void Config_MuteToggled(object sender, EventArgs e){
UpdateIcon();
}
private void trayIcon_MouseClick(object sender, MouseEventArgs e){ private void trayIcon_MouseClick(object sender, MouseEventArgs e){
if (e.Button == MouseButtons.Left){ if (e.Button == MouseButtons.Left){
menuItemRestore_Click(sender, e); menuItemRestore_Click(sender, e);
@@ -68,7 +82,7 @@ namespace TweetDuck.Core.Other{
} }
private void contextMenu_Popup(object sender, EventArgs e){ private void contextMenu_Popup(object sender, EventArgs e){
contextMenu.MenuItems[1].Checked = Program.UserConfig.MuteNotifications; contextMenu.MenuItems[1].Checked = Config.MuteNotifications;
} }
private void menuItemRestore_Click(object sender, EventArgs e){ private void menuItemRestore_Click(object sender, EventArgs e){
@@ -76,8 +90,8 @@ namespace TweetDuck.Core.Other{
} }
private void menuItemMuteNotifications_Click(object sender, EventArgs e){ private void menuItemMuteNotifications_Click(object sender, EventArgs e){
Program.UserConfig.MuteNotifications = !contextMenu.MenuItems[1].Checked; Config.MuteNotifications = !contextMenu.MenuItems[1].Checked;
Program.UserConfig.Save(); Config.Save();
} }
private void menuItemClose_Click(object sender, EventArgs e){ private void menuItemClose_Click(object sender, EventArgs e){

View File

@@ -1,22 +1,24 @@
using System; using System;
using System.Drawing; using System.Drawing;
using System.Text;
using System.Windows.Forms; using System.Windows.Forms;
using CefSharp; using CefSharp;
using CefSharp.WinForms; using CefSharp.WinForms;
using TweetDuck.Configuration;
using TweetDuck.Core.Bridge; using TweetDuck.Core.Bridge;
using TweetDuck.Core.Controls; using TweetDuck.Core.Controls;
using TweetDuck.Core.Handling; using TweetDuck.Core.Handling;
using TweetDuck.Core.Handling.General; using TweetDuck.Core.Handling.General;
using TweetDuck.Core.Other.Management; using TweetDuck.Core.Notification;
using TweetDuck.Core.Utils; using TweetDuck.Core.Utils;
using TweetDuck.Plugins; using TweetDuck.Plugins;
using TweetDuck.Plugins.Enums; using TweetDuck.Plugins.Enums;
using TweetDuck.Plugins.Events;
using TweetDuck.Resources; using TweetDuck.Resources;
using TweetDuck.Updates;
namespace TweetDuck.Core{ namespace TweetDuck.Core{
sealed class TweetDeckBrowser : IDisposable{ sealed class TweetDeckBrowser : IDisposable{
private static UserConfig Config => Program.Config.User;
public bool Ready { get; private set; } public bool Ready { get; private set; }
public bool Enabled{ public bool Enabled{
@@ -26,54 +28,54 @@ namespace TweetDuck.Core{
public bool IsTweetDeckWebsite{ public bool IsTweetDeckWebsite{
get{ get{
if (!Ready){
return false;
}
using(IFrame frame = browser.GetBrowser().MainFrame){ using(IFrame frame = browser.GetBrowser().MainFrame){
return TwitterUtils.IsTweetDeckWebsite(frame); return TwitterUtils.IsTweetDeckWebsite(frame);
} }
} }
} }
public event EventHandler PageLoaded;
private readonly ChromiumWebBrowser browser; private readonly ChromiumWebBrowser browser;
private readonly PluginManager plugins;
private readonly MemoryUsageTracker memoryUsageTracker;
public TweetDeckBrowser(FormBrowser owner, PluginManager plugins, TweetDeckBridge bridge){ private string prevSoundNotificationPath = null;
public TweetDeckBrowser(FormBrowser owner, PluginManager plugins, TweetDeckBridge tdBridge, UpdateBridge updateBridge){
RequestHandlerBrowser requestHandler = new RequestHandlerBrowser();
this.browser = new ChromiumWebBrowser(TwitterUtils.TweetDeckURL){ this.browser = new ChromiumWebBrowser(TwitterUtils.TweetDeckURL){
DialogHandler = new FileDialogHandler(), DialogHandler = new FileDialogHandler(),
DragHandler = new DragHandlerBrowser(), DragHandler = new DragHandlerBrowser(requestHandler),
MenuHandler = new ContextMenuBrowser(owner), MenuHandler = new ContextMenuBrowser(owner),
JsDialogHandler = new JavaScriptDialogHandler(), JsDialogHandler = new JavaScriptDialogHandler(),
KeyboardHandler = new KeyboardHandlerBrowser(owner), KeyboardHandler = new KeyboardHandlerBrowser(owner),
LifeSpanHandler = new LifeSpanHandler(), LifeSpanHandler = new LifeSpanHandler(),
RequestHandler = new RequestHandlerBrowser() RequestHandler = requestHandler
}; };
#if DEBUG
this.browser.ConsoleMessage += BrowserUtils.HandleConsoleMessage;
#endif
this.browser.LoadingStateChanged += browser_LoadingStateChanged; this.browser.LoadingStateChanged += browser_LoadingStateChanged;
this.browser.FrameLoadStart += browser_FrameLoadStart; this.browser.FrameLoadStart += browser_FrameLoadStart;
this.browser.FrameLoadEnd += browser_FrameLoadEnd; this.browser.FrameLoadEnd += browser_FrameLoadEnd;
this.browser.LoadError += browser_LoadError; this.browser.LoadError += browser_LoadError;
this.browser.RegisterAsyncJsObject("$TD", bridge); this.browser.RegisterAsyncJsObject("$TD", tdBridge);
this.browser.RegisterAsyncJsObject("$TDP", plugins.Bridge); this.browser.RegisterAsyncJsObject("$TDU", updateBridge);
this.browser.BrowserSettings.BackgroundColor = (uint)TwitterUtils.BackgroundColor.ToArgb(); this.browser.BrowserSettings.BackgroundColor = (uint)TwitterUtils.BackgroundColor.ToArgb();
this.browser.Dock = DockStyle.None; this.browser.Dock = DockStyle.None;
this.browser.Location = ControlExtensions.InvisibleLocation; this.browser.Location = ControlExtensions.InvisibleLocation;
this.browser.SetupResourceHandler(TweetNotification.AppLogo);
this.browser.SetupResourceHandler(TwitterUtils.LoadingSpinner);
this.browser.SetupZoomEvents();
owner.Controls.Add(browser); owner.Controls.Add(browser);
plugins.Register(browser, PluginEnvironment.Browser, owner, true);
this.plugins = plugins; Config.MuteToggled += Config_MuteToggled;
this.plugins.PluginChangedState += plugins_PluginChangedState; Config.SoundNotificationChanged += Config_SoundNotificationInfoChanged;
this.memoryUsageTracker = new MemoryUsageTracker("TDGF_tryRunCleanup");
Program.UserConfig.MuteToggled += UserConfig_MuteToggled;
Program.UserConfig.ZoomLevelChanged += UserConfig_ZoomLevelChanged;
} }
// setup and management // setup and management
@@ -91,12 +93,9 @@ namespace TweetDuck.Core{
} }
public void Dispose(){ public void Dispose(){
plugins.PluginChangedState -= plugins_PluginChangedState; Config.MuteToggled -= Config_MuteToggled;
Config.SoundNotificationChanged -= Config_SoundNotificationInfoChanged;
Program.UserConfig.MuteToggled -= UserConfig_MuteToggled;
Program.UserConfig.ZoomLevelChanged -= UserConfig_ZoomLevelChanged;
memoryUsageTracker.Dispose();
browser.Dispose(); browser.Dispose();
} }
@@ -114,41 +113,41 @@ namespace TweetDuck.Core{
} }
private void browser_FrameLoadStart(object sender, FrameLoadStartEventArgs e){ private void browser_FrameLoadStart(object sender, FrameLoadStartEventArgs e){
if (e.Frame.IsMain){ IFrame frame = e.Frame;
memoryUsageTracker.Stop();
if (Program.UserConfig.ZoomLevel != 100){ if (frame.IsMain){
BrowserUtils.SetZoomLevel(browser.GetBrowser(), Program.UserConfig.ZoomLevel); if (TwitterUtils.IsTwitterWebsite(frame)){
ScriptLoader.ExecuteFile(frame, "twitter.js", browser);
} }
if (TwitterUtils.IsTwitterWebsite(e.Frame)){ frame.ExecuteJavaScriptAsync(TwitterUtils.BackgroundColorOverride);
ScriptLoader.ExecuteFile(e.Frame, "twitter.js");
}
} }
} }
private void browser_FrameLoadEnd(object sender, FrameLoadEndEventArgs e){ private void browser_FrameLoadEnd(object sender, FrameLoadEndEventArgs e){
if (e.Frame.IsMain && TwitterUtils.IsTweetDeckWebsite(e.Frame)){ IFrame frame = e.Frame;
e.Frame.ExecuteJavaScriptAsync(TwitterUtils.BackgroundColorFix);
if (frame.IsMain){
if (TwitterUtils.IsTweetDeckWebsite(frame)){
UpdateProperties(); UpdateProperties();
TweetDeckBridge.RestoreSessionData(e.Frame); ScriptLoader.ExecuteFile(frame, "code.js", browser);
ScriptLoader.ExecuteFile(e.Frame, "code.js");
InjectBrowserCSS(); InjectBrowserCSS();
ReinjectCustomCSS(Program.UserConfig.CustomBrowserCSS); ReinjectCustomCSS(Config.CustomBrowserCSS);
plugins.ExecutePlugins(e.Frame, PluginEnvironment.Browser); Config_SoundNotificationInfoChanged(null, EventArgs.Empty);
TweetDeckBridge.ResetStaticProperties(); TweetDeckBridge.ResetStaticProperties();
if (Program.SystemConfig.EnableBrowserGCReload){ if (Arguments.HasFlag(Arguments.ArgIgnoreGDPR)){
memoryUsageTracker.Start(browser, Program.SystemConfig.BrowserMemoryThreshold); ScriptLoader.ExecuteScript(frame, "TD.storage.Account.prototype.requiresConsent = function(){ return false; }", "gen:gdpr");
} }
if (Program.UserConfig.FirstRun){ if (Config.FirstRun){
ScriptLoader.ExecuteFile(e.Frame, "introduction.js"); ScriptLoader.ExecuteFile(frame, "introduction.js", browser);
}
} }
PageLoaded?.Invoke(this, EventArgs.Empty); ScriptLoader.ExecuteFile(frame, "update.js", browser);
} }
} }
@@ -158,7 +157,7 @@ namespace TweetDuck.Core{
} }
if (!e.FailedUrl.StartsWith("http://td/", StringComparison.Ordinal)){ if (!e.FailedUrl.StartsWith("http://td/", StringComparison.Ordinal)){
string errorPage = ScriptLoader.LoadResource("pages/error.html", true); string errorPage = ScriptLoader.LoadResourceSilent("pages/error.html");
if (errorPage != null){ if (errorPage != null){
browser.LoadHtml(errorPage.Replace("{err}", BrowserUtils.GetErrorName(e.ErrorCode)), "http://td/error"); browser.LoadHtml(errorPage.Replace("{err}", BrowserUtils.GetErrorName(e.ErrorCode)), "http://td/error");
@@ -166,33 +165,26 @@ namespace TweetDuck.Core{
} }
} }
private void plugins_PluginChangedState(object sender, PluginChangedStateEventArgs e){ private void Config_MuteToggled(object sender, EventArgs e){
browser.ExecuteScriptAsync("TDPF_setPluginState", e.Plugin, e.IsEnabled);
}
private void UserConfig_MuteToggled(object sender, EventArgs e){
UpdateProperties(); UpdateProperties();
} }
private void UserConfig_ZoomLevelChanged(object sender, EventArgs e){ private void Config_SoundNotificationInfoChanged(object sender, EventArgs e){
BrowserUtils.SetZoomLevel(browser.GetBrowser(), Program.UserConfig.ZoomLevel); const string soundUrl = "https://ton.twimg.com/tduck/updatesnd";
bool hasCustomSound = Config.IsCustomSoundNotificationSet;
string newNotificationPath = Config.NotificationSoundPath;
if (prevSoundNotificationPath != newNotificationPath){
browser.SetupResourceHandler(soundUrl, hasCustomSound ? SoundNotification.CreateFileHandler(newNotificationPath) : null);
prevSoundNotificationPath = newNotificationPath;
}
browser.ExecuteScriptAsync("TDGF_setSoundNotificationData", hasCustomSound, Config.NotificationSoundVolume);
} }
// external handling // external handling
public UpdateHandler CreateUpdateHandler(UpdaterSettings settings){
return new UpdateHandler(browser, settings);
}
public void RefreshMemoryTracker(){
if (Program.SystemConfig.EnableBrowserGCReload){
memoryUsageTracker.Start(browser, Program.SystemConfig.BrowserMemoryThreshold);
}
else{
memoryUsageTracker.Stop();
}
}
public void HideVideoOverlay(bool focus){ public void HideVideoOverlay(bool focus){
if (focus){ if (focus){
browser.GetBrowser().GetHost().SendFocusEvent(true); browser.GetBrowser().GetHost().SendFocusEvent(true);
@@ -212,7 +204,7 @@ namespace TweetDuck.Core{
} }
public void InjectBrowserCSS(){ public void InjectBrowserCSS(){
browser.ExecuteScriptAsync("TDGF_injectBrowserCSS", ScriptLoader.LoadResource("styles/browser.css").TrimEnd()); browser.ExecuteScriptAsync("TDGF_injectBrowserCSS", ScriptLoader.LoadResource("styles/browser.css", browser)?.TrimEnd() ?? string.Empty);
} }
public void ReinjectCustomCSS(string css){ public void ReinjectCustomCSS(string css){
@@ -227,12 +219,32 @@ namespace TweetDuck.Core{
browser.ExecuteScriptAsync("TDGF_showTweetDetail", columnId, chirpId, fallbackUrl); browser.ExecuteScriptAsync("TDGF_showTweetDetail", columnId, chirpId, fallbackUrl);
} }
public void AddSearchColumn(string query){
browser.ExecuteScriptAsync("TDGF_performSearch", query);
}
public void TriggerTweetScreenshot(){ public void TriggerTweetScreenshot(){
browser.ExecuteScriptAsync("TDGF_triggerScreenshot()"); browser.ExecuteScriptAsync("TDGF_triggerScreenshot()");
} }
public void ReloadColumns(){
browser.ExecuteScriptAsync("TDGF_reloadColumns()");
}
public void PlaySoundNotification(){
browser.ExecuteScriptAsync("TDGF_playSoundNotification()");
}
public void ApplyROT13(){ public void ApplyROT13(){
browser.ExecuteScriptAsync("TDGF_applyROT13()"); browser.ExecuteScriptAsync("TDGF_applyROT13()");
} }
public void ShowUpdateNotification(string versionTag, string releaseNotes){
browser.ExecuteScriptAsync("TDUF_displayNotification", versionTag, Convert.ToBase64String(Encoding.GetEncoding("iso-8859-1").GetBytes(releaseNotes)));
}
public void OpenDevTools(){
browser.ShowDevTools();
}
} }
} }

View File

@@ -1,45 +0,0 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Threading.Tasks;
using System.Linq;
namespace TweetDuck.Core.Utils{
static class BrowserCache{
private static bool ClearOnExit { get; set; }
public static readonly string CacheFolder = Path.Combine(Program.StoragePath, "Cache");
private static IEnumerable<string> CacheFiles => Directory.EnumerateFiles(CacheFolder);
public static void CalculateCacheSize(Action<Task<long>> callbackBytes){
Task<long> task = new Task<long>(() => {
return CacheFiles.Select(file => {
try{
return new FileInfo(file).Length;
}catch{
return 0L;
}
}).Sum();
});
task.ContinueWith(callbackBytes);
task.Start();
}
public static void SetClearOnExit(){
ClearOnExit = true;
}
public static void Exit(){
if (ClearOnExit){
foreach(string file in CacheFiles){
try{
File.Delete(file);
}catch{
// welp, too bad
}
}
}
}
}
}

View File

@@ -6,32 +6,45 @@ using System.IO;
using System.Net; using System.Net;
using System.Windows.Forms; using System.Windows.Forms;
using CefSharp.WinForms; using CefSharp.WinForms;
using TweetDuck.Configuration;
using TweetDuck.Core.Other; using TweetDuck.Core.Other;
using TweetDuck.Data;
namespace TweetDuck.Core.Utils{ namespace TweetDuck.Core.Utils{
static class BrowserUtils{ static class BrowserUtils{
public static string HeaderAcceptLanguage{ public static string UserAgentVanilla => Program.BrandName+" "+Application.ProductVersion;
get{ public static string UserAgentChrome => "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/"+Cef.ChromiumVersion+" Safari/537.36";
string culture = Program.Culture.Name;
if (culture == "en"){ public static readonly bool HasDevTools = File.Exists(Path.Combine(Program.ProgramPath, "devtools_resources.pak"));
return "en-us,en";
}
else{
return culture.ToLower()+",en;q=0.9";
}
}
}
public static string HeaderUserAgent => Program.BrandName+" "+Application.ProductVersion; private static UserConfig Config => Program.Config.User;
private static SystemConfig SysConfig => Program.Config.System;
public static void SetupCefArgs(IDictionary<string, string> args){ public static void SetupCefArgs(IDictionary<string, string> args){
if (!Program.SystemConfig.HardwareAcceleration){ if (!SysConfig.HardwareAcceleration){
args["disable-gpu"] = "1"; args["disable-gpu"] = "1";
args["disable-gpu-vsync"] = "1"; args["disable-gpu-vsync"] = "1";
} }
args["disable-extensions"] = "1"; if (Config.EnableSmoothScrolling){
args["disable-threaded-scrolling"] = "1";
if (args.TryGetValue("disable-features", out string disabledFeatures)){
args["disable-features"] = "TouchpadAndWheelScrollLatching,"+disabledFeatures;
}
else{
args["disable-features"] = "TouchpadAndWheelScrollLatching";
}
}
else{
args["disable-smooth-scrolling"] = "1";
}
if (!Config.EnableTouchAdjustment){
args["disable-touch-adjustment"] = "1";
}
args["disable-pdf-extension"] = "1";
args["disable-plugins-discovery"] = "1"; args["disable-plugins-discovery"] = "1";
args["enable-system-flash"] = "0"; args["enable-system-flash"] = "0";
@@ -47,6 +60,36 @@ namespace TweetDuck.Core.Utils{
return (ChromiumWebBrowser)browserControl; return (ChromiumWebBrowser)browserControl;
} }
public static void SetupResourceHandler(this ChromiumWebBrowser browser, string url, IResourceHandler handler){
DefaultResourceHandlerFactory factory = (DefaultResourceHandlerFactory)browser.ResourceHandlerFactory;
if (handler == null){
factory.UnregisterHandler(url);
}
else{
factory.RegisterHandler(url, handler);
}
}
public static void SetupResourceHandler(this ChromiumWebBrowser browser, ResourceLink resource){
browser.SetupResourceHandler(resource.Url, resource.Handler);
}
public static void SetupZoomEvents(this ChromiumWebBrowser browser){
void UpdateZoomLevel(object sender, EventArgs args){
SetZoomLevel(browser.GetBrowser(), Config.ZoomLevel);
}
Config.ZoomLevelChanged += UpdateZoomLevel;
browser.Disposed += (sender, args) => Config.ZoomLevelChanged -= UpdateZoomLevel;
browser.FrameLoadStart += (sender, args) => {
if (args.Frame.IsMain && Config.ZoomLevel != 100){
SetZoomLevel(args.Browser, Config.ZoomLevel);
}
};
}
private const string TwitterTrackingUrl = "t.co"; private const string TwitterTrackingUrl = "t.co";
public enum UrlCheckResult{ public enum UrlCheckResult{
@@ -70,12 +113,46 @@ namespace TweetDuck.Core.Utils{
switch(CheckUrl(url)){ switch(CheckUrl(url)){
case UrlCheckResult.Fine: case UrlCheckResult.Fine:
if (FormGuide.CheckGuideUrl(url, out string hash)){
FormGuide.Show(hash);
}
else{
string browserPath = Config.BrowserPath;
if (browserPath == null || !File.Exists(browserPath)){
WindowsUtils.OpenAssociatedProgram(url); WindowsUtils.OpenAssociatedProgram(url);
}
else{
try{
using(Process.Start(browserPath, url)){}
}catch(Exception e){
Program.Reporter.HandleException("Error Opening Browser", "Could not open the browser.", true, e);
}
}
}
break; break;
case UrlCheckResult.Tracking: case UrlCheckResult.Tracking:
if (FormMessage.Warning("Blocked URL", "TweetDuck has blocked a tracking url due to privacy concerns. Do you want to visit it anyway?\n"+url, FormMessage.Yes, FormMessage.No)){ if (Config.IgnoreTrackingUrlWarning){
WindowsUtils.OpenAssociatedProgram(url); goto case UrlCheckResult.Fine;
}
using(FormMessage form = new FormMessage("Blocked URL", "TweetDuck has blocked a tracking url due to privacy concerns. Do you want to visit it anyway?\n"+url, MessageBoxIcon.Warning)){
form.AddButton(FormMessage.No, DialogResult.No, ControlType.Cancel | ControlType.Focused);
form.AddButton(FormMessage.Yes, DialogResult.Yes, ControlType.Accept);
form.AddButton("Always Visit", DialogResult.Ignore);
DialogResult result = form.ShowDialog();
if (result == DialogResult.Ignore){
Config.IgnoreTrackingUrlWarning = true;
Config.Save();
}
if (result == DialogResult.Ignore || result == DialogResult.Yes){
goto case UrlCheckResult.Fine;
}
} }
break; break;
@@ -86,6 +163,33 @@ namespace TweetDuck.Core.Utils{
} }
} }
public static void OpenExternalSearch(string query){
if (string.IsNullOrWhiteSpace(query))return;
string searchUrl = Config.SearchEngineUrl;
if (string.IsNullOrEmpty(searchUrl)){
if (FormMessage.Question("Search Options", "You have not configured a default search engine yet, would you like to do it now?", FormMessage.Yes, FormMessage.No)){
bool wereSettingsOpen = FormManager.TryFind<FormSettings>() != null;
FormManager.TryFind<FormBrowser>()?.OpenSettings();
if (wereSettingsOpen)return;
FormSettings settings = FormManager.TryFind<FormSettings>();
if (settings == null)return;
settings.FormClosed += (sender, args) => {
if (args.CloseReason == CloseReason.UserClosing && Config.SearchEngineUrl != searchUrl){
OpenExternalSearch(query);
}
};
}
}
else{
OpenExternalBrowser(searchUrl+Uri.EscapeUriString(query));
}
}
public static string GetFileNameFromUrl(string url){ public static string GetFileNameFromUrl(string url){
string file = Path.GetFileName(new Uri(url).AbsolutePath); string file = Path.GetFileName(new Uri(url).AbsolutePath);
return string.IsNullOrEmpty(file) ? null : file; return string.IsNullOrEmpty(file) ? null : file;
@@ -96,14 +200,20 @@ namespace TweetDuck.Core.Utils{
} }
public static WebClient CreateWebClient(){ public static WebClient CreateWebClient(){
WindowsUtils.EnsureTLS12();
WebClient client = new WebClient{ Proxy = null }; WebClient client = new WebClient{ Proxy = null };
client.Headers[HttpRequestHeader.UserAgent] = HeaderUserAgent; client.Headers[HttpRequestHeader.UserAgent] = UserAgentVanilla;
return client; return client;
} }
public static WebClient DownloadFileAsync(string url, string target, Action onSuccess, Action<Exception> onFailure){ public static WebClient DownloadFileAsync(string url, string target, string cookie, Action onSuccess, Action<Exception> onFailure){
WebClient client = CreateWebClient(); WebClient client = CreateWebClient();
if (cookie != null){
client.Headers[HttpRequestHeader.Cookie] = cookie;
}
client.DownloadFileCompleted += (sender, args) => { client.DownloadFileCompleted += (sender, args) => {
if (args.Cancelled){ if (args.Cancelled){
try{ try{
@@ -131,11 +241,5 @@ namespace TweetDuck.Core.Utils{
public static void SetZoomLevel(IBrowser browser, int percentage){ public static void SetZoomLevel(IBrowser browser, int percentage){
browser.GetHost().SetZoomLevel(Math.Log(percentage/100.0, 1.2)); browser.GetHost().SetZoomLevel(Math.Log(percentage/100.0, 1.2));
} }
#if DEBUG
public static void HandleConsoleMessage(object sender, ConsoleMessageEventArgs e){
Debug.WriteLine("[Console] {0} ({1}:{2})", e.Message, e.Source, e.Line);
}
#endif
} }
} }

58
Core/Utils/LocaleUtils.cs Normal file
View File

@@ -0,0 +1,58 @@
using System;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
namespace TweetDuck.Core.Utils{
static class LocaleUtils{
// https://cs.chromium.org/chromium/src/third_party/hunspell_dictionaries/
public static IEnumerable<Item> SpellCheckLanguages { get; } = new List<string>{
"af-ZA", "bg-BG", "ca-ES", "cs-CZ", "da-DK", "de-DE",
"el-GR", "en-AU", "en-CA", "en-GB", "en-US", "es-ES",
"et-EE", "fa-IR", "fo-FO", "fr-FR", "he-IL", "hi-IN",
"hr-HR", "hu-HU", "id-ID", "it-IT", "ko" , "lt-LT",
"lv-LV", "nb-NO", "nl-NL", "pl-PL", "pt-BR", "pt-PT",
"ro-RO", "ru-RU", "sk-SK", "sl-SI", "sq" , "sr",
"sv-SE", "ta-IN", "tg-TG", "tr" , "uk-UA", "vi-VN"
}.Select(code => {
string lang = StringUtils.ExtractBefore(code, '-', 2);
return lang == "en" || lang == "pt" ? new Item(code) : new Item(code, lang);
}).OrderBy(code => code).ToList();
// TD.languages.getSupportedTranslationDestinationLanguages() except for "ht", "in", "iw" which are missing/duplicates
public static IEnumerable<Item> TweetDeckTranslationLocales { get; } = new List<string>{
"bg", "ca", "zh-cn", "zh-tw", "cs", "da", "nl",
"en", "et", "fi", "fr", "de", "el", "he", "hi",
"hu", "id", "it", "ja", "ko", "lv", "lt", "no",
"pl", "pt", "ro", "ru", "sk", "sl", "es", "sv",
"th", "tr", "uk", "vi", "ar", "fa"
}.Select(code => new Item(code)).OrderBy(code => code).ToList();
public sealed class Item : IComparable<Item>{
public string Code { get; }
public CultureInfo Info { get; }
public Item(string code, string alt = null){
this.Code = code;
this.Info = CultureInfo.GetCultureInfo(alt ?? code);
}
public override bool Equals(object obj){
return obj is Item other && Code.Equals(other.Code, StringComparison.OrdinalIgnoreCase);
}
public override int GetHashCode(){
return Code.GetHashCode();
}
public override string ToString(){
string capitalizedName = Info.TextInfo.ToTitleCase(Info.NativeName);
return Info.DisplayName == Info.NativeName ? capitalizedName : $"{capitalizedName}, {Info.DisplayName}";
}
public int CompareTo(Item other){
return string.Compare(Info.NativeName, other.Info.NativeName, false, CultureInfo.InvariantCulture);
}
}
}
}

View File

@@ -17,6 +17,7 @@ namespace TweetDuck.Core.Utils{
public const int GWL_STYLE = -16; public const int GWL_STYLE = -16;
public const int SB_HORZ = 0; public const int SB_HORZ = 0;
public const int EM_SETCUEBANNER = 0x1501;
public const int WM_MOUSE_LL = 14; public const int WM_MOUSE_LL = 14;
public const int WM_MOUSEWHEEL = 0x020A; public const int WM_MOUSEWHEEL = 0x020A;
@@ -52,6 +53,9 @@ namespace TweetDuck.Core.Utils{
[DllImport("user32.dll", EntryPoint = "SetWindowPos")] [DllImport("user32.dll", EntryPoint = "SetWindowPos")]
private static extern bool SetWindowPos(int hWnd, int hWndOrder, int x, int y, int width, int height, uint flags); private static extern bool SetWindowPos(int hWnd, int hWndOrder, int x, int y, int width, int height, uint flags);
[DllImport("user32.dll")]
public static extern bool SendMessage(IntPtr hWnd, int msg, int wParam, [MarshalAs(UnmanagedType.LPWStr)] string lParam);
[DllImport("user32.dll")] [DllImport("user32.dll")]
public static extern bool PostMessage(IntPtr hWnd, uint msg, UIntPtr wParam, IntPtr lParam); public static extern bool PostMessage(IntPtr hWnd, uint msg, UIntPtr wParam, IntPtr lParam);
@@ -71,6 +75,9 @@ namespace TweetDuck.Core.Utils{
[return: MarshalAs(UnmanagedType.Bool)] [return: MarshalAs(UnmanagedType.Bool)]
private static extern bool BitBlt(IntPtr hdc, int nXDest, int nYDest, int nWidth, int nHeight, IntPtr hdcSrc, int nXSrc, int nYSrc, uint dwRop); private static extern bool BitBlt(IntPtr hdc, int nXDest, int nYDest, int nWidth, int nHeight, IntPtr hdcSrc, int nXSrc, int nYSrc, uint dwRop);
[DllImport("dwmapi.dll")]
public static extern int DwmIsCompositionEnabled(out bool enabled);
[DllImport("user32.dll")] [DllImport("user32.dll")]
[return: MarshalAs(UnmanagedType.Bool)] [return: MarshalAs(UnmanagedType.Bool)]
public static extern bool ShowScrollBar(IntPtr hWnd, int wBar, bool bShow); public static extern bool ShowScrollBar(IntPtr hWnd, int wBar, bool bShow);

View File

@@ -19,11 +19,23 @@ namespace TweetDuck.Core.Utils{
return Regex.Replace(str, @"(\p{Ll})(\P{Ll})|(\P{Ll})(\P{Ll}\p{Ll})", "$1$3_$2$4").ToUpper(); return Regex.Replace(str, @"(\p{Ll})(\P{Ll})|(\P{Ll})(\P{Ll}\p{Ll})", "$1$3_$2$4").ToUpper();
} }
public static string ConvertRot13(string str){
return Regex.Replace(str, @"[a-zA-Z]", match => {
int code = match.Value[0];
int start = code <= 90 ? 65 : 97;
return ((char)(start+(code-start+13)%26)).ToString();
});
}
public static int CountOccurrences(string source, string substring){ public static int CountOccurrences(string source, string substring){
int count = 0, index = 0; if (substring.Length == 0){
throw new ArgumentOutOfRangeException(nameof(substring), "Searched substring must not be empty.");
}
int count = 0, index = 0, length = substring.Length;
while((index = source.IndexOf(substring, index)) != -1){ while((index = source.IndexOf(substring, index)) != -1){
index += substring.Length; index += length;
++count; ++count;
} }

View File

@@ -2,19 +2,25 @@
using CefSharp; using CefSharp;
using System.Drawing; using System.Drawing;
using System.IO; using System.IO;
using System.Linq;
using System.Text.RegularExpressions; using System.Text.RegularExpressions;
using System.Windows.Forms; using System.Windows.Forms;
using TweetDuck.Core.Management;
using TweetDuck.Core.Other; using TweetDuck.Core.Other;
using TweetDuck.Data;
using System.Linq;
using System.Threading.Tasks;
using Cookie = CefSharp.Cookie;
namespace TweetDuck.Core.Utils{ namespace TweetDuck.Core.Utils{
static class TwitterUtils{ static class TwitterUtils{
public const string TweetDeckURL = "https://tweetdeck.twitter.com"; public const string TweetDeckURL = "https://tweetdeck.twitter.com";
public static readonly Color BackgroundColor = Color.FromArgb(28, 99, 153); public static readonly Color BackgroundColor = Color.FromArgb(28, 99, 153);
public const string BackgroundColorFix = "let e=document.createElement('style');document.head.appendChild(e);e.innerHTML='body::before{background:#1c6399!important}'"; public const string BackgroundColorOverride = "setTimeout(function f(){let h=document.head;if(!h){setTimeout(f,5);return;}let e=document.createElement('style');e.innerHTML='body,body::before{background:#1c6399!important}';h.appendChild(e);},1)";
private static readonly Lazy<Regex> RegexAccountLazy = new Lazy<Regex>(() => new Regex(@"^https?://twitter\.com/(?!signup$|tos$|privacy$)([^/]+)/?$", RegexOptions.Compiled), false); public static readonly ResourceLink LoadingSpinner = new ResourceLink("https://ton.twimg.com/tduck/spinner", ResourceHandler.FromByteArray(Properties.Resources.spinner, "image/apng"));
private static readonly Lazy<Regex> RegexAccountLazy = new Lazy<Regex>(() => new Regex(@"^https?://twitter\.com/(?!signup$|tos$|privacy$|search$|search-)([^/?]+)/?$", RegexOptions.Compiled), false);
public static Regex RegexAccount => RegexAccountLazy.Value; public static Regex RegexAccount => RegexAccountLazy.Value;
public static readonly string[] DictionaryWords = { public static readonly string[] DictionaryWords = {
@@ -38,15 +44,18 @@ namespace TweetDuck.Core.Utils{
} }
private static string ExtractMediaBaseLink(string url){ private static string ExtractMediaBaseLink(string url){
int dot = url.LastIndexOf('/'); int slash = url.LastIndexOf('/');
return dot == -1 ? url : StringUtils.ExtractBefore(url, ':', dot); return slash == -1 ? url : StringUtils.ExtractBefore(url, ':', slash);
} }
public static string GetMediaLink(string url, ImageQuality quality){ public static string GetMediaLink(string url, ImageQuality quality){
if (quality == ImageQuality.Orig){ if (quality == ImageQuality.Orig){
string result = ExtractMediaBaseLink(url); string result = ExtractMediaBaseLink(url);
if (result != url || url.Contains("//pbs.twimg.com/media/")){ if (url.Contains("//ton.twitter.com/") && url.Contains("/ton/data/dm/")){
result += ":large";
}
else if (result != url || url.Contains("//pbs.twimg.com/media/")){
result += ":orig"; result += ":orig";
} }
@@ -61,6 +70,32 @@ namespace TweetDuck.Core.Utils{
return BrowserUtils.GetFileNameFromUrl(ExtractMediaBaseLink(url)); return BrowserUtils.GetFileNameFromUrl(ExtractMediaBaseLink(url));
} }
public static void ViewImage(string url, ImageQuality quality){
void ViewImageInternal(string path){
string ext = Path.GetExtension(path);
if (ValidImageExtensions.Contains(ext)){
WindowsUtils.OpenAssociatedProgram(path);
}
else{
FormMessage.Error("Image Download", "Invalid file extension "+ext, FormMessage.OK);
}
}
string file = Path.Combine(BrowserCache.CacheFolder, GetImageFileName(url) ?? Path.GetRandomFileName());
if (WindowsUtils.FileExistsAndNotEmpty(file)){
ViewImageInternal(file);
}
else{
DownloadFileAuth(GetMediaLink(url, quality), file, () => {
ViewImageInternal(file);
}, ex => {
FormMessage.Error("Image Download", "An error occurred while downloading the image: "+ex.Message, FormMessage.OK);
});
}
}
public static void DownloadImage(string url, string username, ImageQuality quality){ public static void DownloadImage(string url, string username, ImageQuality quality){
DownloadImages(new string[]{ url }, username, quality); DownloadImages(new string[]{ url }, username, quality);
} }
@@ -73,22 +108,14 @@ namespace TweetDuck.Core.Utils{
string firstImageLink = GetMediaLink(urls[0], quality); string firstImageLink = GetMediaLink(urls[0], quality);
int qualityIndex = firstImageLink.IndexOf(':', firstImageLink.LastIndexOf('/')); int qualityIndex = firstImageLink.IndexOf(':', firstImageLink.LastIndexOf('/'));
string file = GetImageFileName(firstImageLink); string filename = GetImageFileName(firstImageLink);
string ext = Path.GetExtension(file); // includes dot string ext = Path.GetExtension(filename); // includes dot
string[] fileNameParts = qualityIndex == -1 ? new string[]{
Path.ChangeExtension(file, null)
} : new string[]{
username,
Path.ChangeExtension(file, null),
firstImageLink.Substring(qualityIndex+1)
};
using(SaveFileDialog dialog = new SaveFileDialog{ using(SaveFileDialog dialog = new SaveFileDialog{
AutoUpgradeEnabled = true, AutoUpgradeEnabled = true,
OverwritePrompt = urls.Length == 1, OverwritePrompt = urls.Length == 1,
Title = "Save image", Title = "Save Image",
FileName = $"{string.Join(" ", fileNameParts.Where(part => part.Length > 0))}{ext}", FileName = qualityIndex == -1 ? filename : $"{username} {Path.ChangeExtension(filename, null)} {firstImageLink.Substring(qualityIndex+1)}".Trim()+ext,
Filter = (urls.Length == 1 ? "Image" : "Images")+(string.IsNullOrEmpty(ext) ? " (unknown)|*.*" : $" (*{ext})|*{ext}") Filter = (urls.Length == 1 ? "Image" : "Images")+(string.IsNullOrEmpty(ext) ? " (unknown)|*.*" : $" (*{ext})|*{ext}")
}){ }){
if (dialog.ShowDialog() == DialogResult.OK){ if (dialog.ShowDialog() == DialogResult.OK){
@@ -97,14 +124,14 @@ namespace TweetDuck.Core.Utils{
} }
if (urls.Length == 1){ if (urls.Length == 1){
BrowserUtils.DownloadFileAsync(firstImageLink, dialog.FileName, null, OnFailure); DownloadFileAuth(firstImageLink, dialog.FileName, null, OnFailure);
} }
else{ else{
string pathBase = Path.ChangeExtension(dialog.FileName, null); string pathBase = Path.ChangeExtension(dialog.FileName, null);
string pathExt = Path.GetExtension(dialog.FileName); string pathExt = Path.GetExtension(dialog.FileName);
for(int index = 0; index < urls.Length; index++){ for(int index = 0; index < urls.Length; index++){
BrowserUtils.DownloadFileAsync(GetMediaLink(urls[index], quality), $"{pathBase} {index+1}{pathExt}", null, OnFailure); DownloadFileAuth(GetMediaLink(urls[index], quality), $"{pathBase} {index+1}{pathExt}", null, OnFailure);
} }
} }
} }
@@ -118,16 +145,38 @@ namespace TweetDuck.Core.Utils{
using(SaveFileDialog dialog = new SaveFileDialog{ using(SaveFileDialog dialog = new SaveFileDialog{
AutoUpgradeEnabled = true, AutoUpgradeEnabled = true,
OverwritePrompt = true, OverwritePrompt = true,
Title = "Save video", Title = "Save Video",
FileName = string.IsNullOrEmpty(username) ? filename : $"{username} {filename}", FileName = string.IsNullOrEmpty(username) ? filename : $"{username} {filename}".TrimStart(),
Filter = "Video"+(string.IsNullOrEmpty(ext) ? " (unknown)|*.*" : $" (*{ext})|*{ext}") Filter = "Video"+(string.IsNullOrEmpty(ext) ? " (unknown)|*.*" : $" (*{ext})|*{ext}")
}){ }){
if (dialog.ShowDialog() == DialogResult.OK){ if (dialog.ShowDialog() == DialogResult.OK){
BrowserUtils.DownloadFileAsync(url, dialog.FileName, null, ex => { DownloadFileAuth(url, dialog.FileName, null, ex => {
FormMessage.Error("Image Download", "An error occurred while downloading the image: "+ex.Message, FormMessage.OK); FormMessage.Error("Video Download", "An error occurred while downloading the video: "+ex.Message, FormMessage.OK);
}); });
} }
} }
} }
private static void DownloadFileAuth(string url, string target, Action onSuccess, Action<Exception> onFailure){
const string AuthCookieName = "auth_token";
TaskScheduler scheduler = TaskScheduler.FromCurrentSynchronizationContext();
using(ICookieManager cookies = Cef.GetGlobalCookieManager()){
cookies.VisitUrlCookiesAsync(url, true).ContinueWith(task => {
string cookieStr = null;
if (task.Status == TaskStatus.RanToCompletion){
Cookie found = task.Result?.Find(cookie => cookie.Name == AuthCookieName); // the list may be null
if (found != null){
cookieStr = $"{found.Name}={found.Value}";
}
}
BrowserUtils.DownloadFileAsync(url, target, cookieStr, onSuccess, onFailure);
}, scheduler);
}
}
} }
} }

View File

@@ -1,20 +1,26 @@
using System; using System;
using System.Collections.Generic;
using System.ComponentModel; using System.ComponentModel;
using System.Diagnostics; using System.Diagnostics;
using System.IO; using System.IO;
using System.Management; using System.Net;
using System.Runtime.InteropServices; using System.Runtime.InteropServices;
using System.Text.RegularExpressions; using System.Text.RegularExpressions;
using System.Threading; using System.Threading;
using System.Windows.Forms; using System.Windows.Forms;
using Microsoft.Win32;
namespace TweetDuck.Core.Utils{ namespace TweetDuck.Core.Utils{
static class WindowsUtils{ static class WindowsUtils{
private static readonly Lazy<Regex> RegexStripHtmlStyles = new Lazy<Regex>(() => new Regex(@"\s?(?:style|class)="".*?"""), false); private static readonly Lazy<Regex> RegexStripHtmlStyles = new Lazy<Regex>(() => new Regex(@"\s?(?:style|class)="".*?"""), false);
private static readonly Lazy<Regex> RegexOffsetClipboardHtml = new Lazy<Regex>(() => new Regex(@"(?<=EndHTML:|EndFragment:)(\d+)"), false); private static readonly Lazy<Regex> RegexOffsetClipboardHtml = new Lazy<Regex>(() => new Regex(@"(?<=EndHTML:|EndFragment:)(\d+)"), false);
private static readonly bool IsWindows8OrNewer;
private static bool HasMicrosoftBeenBroughtTo2008Yet;
public static int CurrentProcessID { get; } public static int CurrentProcessID { get; }
public static bool ShouldAvoidToolWindow { get; } public static bool ShouldAvoidToolWindow { get; }
public static bool IsAeroEnabled => IsWindows8OrNewer || (NativeMethods.DwmIsCompositionEnabled(out bool isCompositionEnabled) == 0 && isCompositionEnabled);
static WindowsUtils(){ static WindowsUtils(){
using(Process me = Process.GetCurrentProcess()){ using(Process me = Process.GetCurrentProcess()){
@@ -22,7 +28,17 @@ namespace TweetDuck.Core.Utils{
} }
Version ver = Environment.OSVersion.Version; Version ver = Environment.OSVersion.Version;
ShouldAvoidToolWindow = ver.Major == 6 && ver.Minor == 2; // windows 8/10 IsWindows8OrNewer = ver.Major == 6 && ver.Minor == 2; // windows 8/10
ShouldAvoidToolWindow = IsWindows8OrNewer;
}
public static void EnsureTLS12(){
if (!HasMicrosoftBeenBroughtTo2008Yet){
ServicePointManager.SecurityProtocol |= SecurityProtocolType.Tls12;
ServicePointManager.SecurityProtocol &= ~(SecurityProtocolType.Ssl3 | SecurityProtocolType.Tls | SecurityProtocolType.Tls11);
HasMicrosoftBeenBroughtTo2008Yet = true;
}
} }
public static void CreateDirectoryForFile(string file){ public static void CreateDirectoryForFile(string file){
@@ -50,6 +66,14 @@ namespace TweetDuck.Core.Utils{
} }
} }
public static bool FileExistsAndNotEmpty(string path){
try{
return new FileInfo(path).Length > 0;
}catch{
return false;
}
}
public static bool OpenAssociatedProgram(string file, string arguments = "", bool runElevated = false){ public static bool OpenAssociatedProgram(string file, string arguments = "", bool runElevated = false){
try{ try{
using(Process.Start(new ProcessStartInfo{ using(Process.Start(new ProcessStartInfo{
@@ -63,7 +87,7 @@ namespace TweetDuck.Core.Utils{
}catch(Win32Exception e) when (e.NativeErrorCode == 0x000004C7){ // operation canceled by the user }catch(Win32Exception e) when (e.NativeErrorCode == 0x000004C7){ // operation canceled by the user
return false; return false;
}catch(Exception e){ }catch(Exception e){
Program.Reporter.HandleException("Error opening file", e.Message, true, e); Program.Reporter.HandleException("Error Opening Program", "Could not open the associated program for "+file, true, e);
return false; return false;
} }
} }
@@ -95,20 +119,6 @@ namespace TweetDuck.Core.Utils{
}).Start(); }).Start();
} }
public static bool IsChildProcess(int pid){
try{
using(ManagementObjectSearcher searcher = new ManagementObjectSearcher("SELECT ParentProcessId FROM Win32_Process WHERE ProcessId = "+pid)){
foreach(ManagementBaseObject obj in searcher.Get()){
return (uint)obj["ParentProcessId"] == CurrentProcessID;
}
}
return false;
}catch{
return false;
}
}
public static void ClipboardStripHtmlStyles(){ public static void ClipboardStripHtmlStyles(){
if (!Clipboard.ContainsText(TextDataFormat.Html) || !Clipboard.ContainsText(TextDataFormat.UnicodeText)){ if (!Clipboard.ContainsText(TextDataFormat.Html) || !Clipboard.ContainsText(TextDataFormat.UnicodeText)){
return; return;
@@ -145,5 +155,63 @@ namespace TweetDuck.Core.Utils{
Program.Reporter.HandleException("Clipboard Error", "TweetDuck could not access the clipboard as it is currently used by another process.", true, e); Program.Reporter.HandleException("Clipboard Error", "TweetDuck could not access the clipboard as it is currently used by another process.", true, e);
} }
} }
public static IEnumerable<Browser> FindInstalledBrowsers(){
IEnumerable<Browser> ReadBrowsersFromKey(RegistryHive hive){
using(RegistryKey root = RegistryKey.OpenBaseKey(hive, RegistryView.Default))
using(RegistryKey browserList = root.OpenSubKey(@"SOFTWARE\Clients\StartMenuInternet", false)){
if (browserList == null){
yield break;
}
foreach(string sub in browserList.GetSubKeyNames()){
using(RegistryKey browserKey = browserList.OpenSubKey(sub, false))
using(RegistryKey shellKey = browserKey?.OpenSubKey(@"shell\open\command")){
if (shellKey == null){
continue;
}
string browserName = browserKey.GetValue(null) as string;
string browserPath = shellKey.GetValue(null) as string;
if (string.IsNullOrEmpty(browserName) || string.IsNullOrEmpty(browserPath)){
continue;
}
if (browserPath[0] == '"' && browserPath[browserPath.Length-1] == '"'){
browserPath = browserPath.Substring(1, browserPath.Length-2);
}
yield return new Browser(browserName, browserPath);
}
}
}
}
HashSet<Browser> browsers = new HashSet<Browser>();
try{
browsers.UnionWith(ReadBrowsersFromKey(RegistryHive.CurrentUser));
browsers.UnionWith(ReadBrowsersFromKey(RegistryHive.LocalMachine));
}catch{
// oops I guess
}
return browsers;
}
public sealed class Browser{
public string Name { get; }
public string Path { get; }
public Browser(string name, string path){
this.Name = name;
this.Path = path;
}
public override int GetHashCode() => Name.GetHashCode();
public override bool Equals(object obj) => obj is Browser other && Name == other.Name;
public override string ToString() => Name;
}
} }
} }

View File

@@ -16,7 +16,7 @@ namespace TweetDuck.Data{
this.html = html; this.html = html;
} }
public string Inject(string targetHTML){ public string InjectInto(string targetHTML){
int index = targetHTML.IndexOf(search, StringComparison.Ordinal); int index = targetHTML.IndexOf(search, StringComparison.Ordinal);
if (index == -1){ if (index == -1){

13
Data/ResourceLink.cs Normal file
View File

@@ -0,0 +1,13 @@
using CefSharp;
namespace TweetDuck.Data{
sealed class ResourceLink{
public string Url { get; }
public IResourceHandler Handler { get; }
public ResourceLink(string url, IResourceHandler handler){
this.Url = url;
this.Handler = handler;
}
}
}

36
Data/Result.cs Normal file
View File

@@ -0,0 +1,36 @@
using System;
namespace TweetDuck.Data{
sealed class Result<T>{
public bool HasValue => exception == null;
public T Value => HasValue ? value : throw new InvalidOperationException("Requested value from a failed result.");
public Exception Exception => exception ?? throw new InvalidOperationException("Requested exception from a successful result.");
private readonly T value;
private readonly Exception exception;
public Result(T value){
this.value = value;
this.exception = null;
}
public Result(Exception exception){
this.value = default(T);
this.exception = exception ?? throw new ArgumentNullException(nameof(exception));
}
public void Handle(Action<T> onSuccess, Action<Exception> onException){
if (HasValue){
onSuccess(value);
}
else{
onException(exception);
}
}
public Result<R> Select<R>(Func<T, R> map){
return HasValue ? new Result<R>(map(value)) : new Result<R>(exception);
}
}
}

View File

@@ -3,7 +3,7 @@ using System.Collections.Generic;
using System.IO; using System.IO;
using System.Linq; using System.Linq;
using System.Reflection; using System.Reflection;
using System.Runtime.Serialization; using System.Text;
using TweetDuck.Core.Utils; using TweetDuck.Core.Utils;
namespace TweetDuck.Data.Serialization{ namespace TweetDuck.Data.Serialization{
@@ -11,10 +11,45 @@ namespace TweetDuck.Data.Serialization{
private const string NewLineReal = "\r\n"; private const string NewLineReal = "\r\n";
private const string NewLineCustom = "\r~\n"; private const string NewLineCustom = "\r~\n";
private static readonly ITypeConverter BasicSerializerObj = new BasicTypeConverter(); private static string EscapeLine(string input) => input.Replace("\\", "\\\\").Replace(Environment.NewLine, "\\\r\n");
private static string UnescapeLine(string input) => input.Replace(NewLineCustom, Environment.NewLine);
public delegate void HandleUnknownPropertiesHandler(T obj, Dictionary<string, string> data); private static string UnescapeStream(StreamReader reader){
public HandleUnknownPropertiesHandler HandleUnknownProperties { get; set; } string data = reader.ReadToEnd();
StringBuilder build = new StringBuilder(data.Length);
int index = 0;
while(true){
int nextIndex = data.IndexOf('\\', index);
if (nextIndex == -1 || nextIndex+1 >= data.Length){
break;
}
else{
build.Append(data.Substring(index, nextIndex-index));
char next = data[nextIndex+1];
if (next == '\\'){ // convert double backslash to single backslash
build.Append('\\');
index = nextIndex+2;
}
else if (next == '\r' && nextIndex+2 < data.Length && data[nextIndex+2] == '\n'){ // convert backslash followed by CRLF to custom new line
build.Append(NewLineCustom);
index = nextIndex+3;
}
else{ // single backslash
build.Append('\\');
index = nextIndex+1;
}
}
}
return build.Append(data.Substring(index)).ToString();
}
private static readonly ITypeConverter BasicSerializerObj = new BasicTypeConverter();
private readonly Dictionary<string, PropertyInfo> props; private readonly Dictionary<string, PropertyInfo> props;
private readonly Dictionary<Type, ITypeConverter> converters; private readonly Dictionary<Type, ITypeConverter> converters;
@@ -29,6 +64,8 @@ namespace TweetDuck.Data.Serialization{
} }
public void Write(string file, T obj){ public void Write(string file, T obj){
LinkedList<string> errors = new LinkedList<string>();
WindowsUtils.CreateDirectoryForFile(file); WindowsUtils.CreateDirectoryForFile(file);
using(StreamWriter writer = new StreamWriter(new FileStream(file, FileMode.Create, FileAccess.Write, FileShare.None))){ using(StreamWriter writer = new StreamWriter(new FileStream(file, FileMode.Create, FileAccess.Write, FileShare.None))){
@@ -42,38 +79,66 @@ namespace TweetDuck.Data.Serialization{
if (serializer.TryWriteType(type, value, out string converted)){ if (serializer.TryWriteType(type, value, out string converted)){
if (converted != null){ if (converted != null){
writer.Write($"{prop.Key} {converted.Replace(Environment.NewLine, NewLineCustom)}"); writer.Write(prop.Key);
writer.Write(' ');
writer.Write(EscapeLine(converted));
writer.Write(NewLineReal); writer.Write(NewLineReal);
} }
} }
else{ else{
throw new SerializationException($"Invalid serialization type, conversion failed for: {type}"); errors.AddLast($"Missing converter for type: {type}");
} }
} }
} }
if (errors.First != null){
throw new SerializationSoftException(errors.ToArray());
}
} }
public void Read(string file, T obj){ public void Read(string file, T obj){
Dictionary<string, string> unknownProperties = new Dictionary<string, string>(4); string contents;
using(StreamReader reader = new StreamReader(new FileStream(file, FileMode.Open, FileAccess.Read, FileShare.Read))){ using(StreamReader reader = new StreamReader(new FileStream(file, FileMode.Open, FileAccess.Read, FileShare.Read))){
switch(reader.Peek()){ contents = UnescapeStream(reader);
case -1: }
if (string.IsNullOrWhiteSpace(contents)){
throw new FormatException("File is empty."); throw new FormatException("File is empty.");
case 0: }
case 1: else if (contents[0] <= (char)1){
throw new FormatException("Input appears to be a binary file."); throw new FormatException("Input appears to be a binary file.");
} }
foreach(string line in reader.ReadToEnd().Split(new string[]{ NewLineReal }, StringSplitOptions.RemoveEmptyEntries)){ LinkedList<string> errors = new LinkedList<string>();
int currentPos = 0;
do{
string line;
int nextPos = contents.IndexOf(NewLineReal, currentPos);
if (nextPos == -1){
line = contents.Substring(currentPos);
currentPos = -1;
if (string.IsNullOrEmpty(line)){
break;
}
}
else{
line = contents.Substring(currentPos, nextPos-currentPos);
currentPos = nextPos+NewLineReal.Length;
}
int space = line.IndexOf(' '); int space = line.IndexOf(' ');
if (space == -1){ if (space == -1){
throw new SerializationException($"Invalid file format, missing separator: {line}"); errors.AddLast($"Missing separator on line: {line}");
continue;
} }
string property = line.Substring(0, space); string property = line.Substring(0, space);
string value = line.Substring(space+1).Replace(NewLineCustom, Environment.NewLine); string value = UnescapeLine(line.Substring(space+1));
if (props.TryGetValue(property, out PropertyInfo info)){ if (props.TryGetValue(property, out PropertyInfo info)){
if (!converters.TryGetValue(info.PropertyType, out ITypeConverter serializer)){ if (!converters.TryGetValue(info.PropertyType, out ITypeConverter serializer)){
@@ -84,21 +149,13 @@ namespace TweetDuck.Data.Serialization{
info.SetValue(obj, converted); info.SetValue(obj, converted);
} }
else{ else{
throw new SerializationException($"Invalid file format, cannot convert value: {value} (property: {property})"); errors.AddLast($"Failed reading property {property} with value: {value}");
}
}
else{
unknownProperties[property] = value;
}
} }
} }
}while(currentPos != -1);
if (unknownProperties.Count > 0){ if (errors.First != null){
HandleUnknownProperties?.Invoke(obj, unknownProperties); throw new SerializationSoftException(errors.ToArray());
if (unknownProperties.Count > 0){
throw new SerializationException($"Invalid file format, unknown properties: {string.Join(", ", unknownProperties.Keys)}");
}
} }
} }

View File

@@ -0,0 +1,12 @@
using System;
using System.Collections.Generic;
namespace TweetDuck.Data.Serialization{
sealed class SerializationSoftException : Exception{
public IList<string> Errors { get; }
public SerializationSoftException(IList<string> errors) : base(string.Join(Environment.NewLine, errors)){
this.Errors = errors;
}
}
}

View File

@@ -62,8 +62,7 @@ namespace TweetDuck.Data{
} }
public bool Contains(K1 outerKey, K2 innerKey){ public bool Contains(K1 outerKey, K2 innerKey){
Dictionary<K2, V> innerDict; return dict.TryGetValue(outerKey, out Dictionary<K2, V> innerDict) && innerDict.ContainsKey(innerKey);
return dict.TryGetValue(outerKey, out innerDict) && innerDict.ContainsKey(innerKey);
} }
public int Count(){ public int Count(){

Some files were not shown because too many files have changed in this diff Show More