mirror of
https://github.com/chylex/TweetDuck.git
synced 2026-02-18 17:46:36 +01:00
Compare commits
122 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
6040337bb4
|
|||
|
1ced72388b
|
|||
|
4751a948e7
|
|||
|
3939c2263a
|
|||
|
b0ba4595ae
|
|||
|
38b1057a4c
|
|||
|
af5d785ff2
|
|||
|
655d334714
|
|||
|
eee72959e6
|
|||
|
89b8977f7d
|
|||
|
9ede2e1ccc
|
|||
|
03d1bc0f4c
|
|||
|
cde9f66111
|
|||
|
8149ed50e1
|
|||
|
24f5075116
|
|||
|
2a636245b4
|
|||
|
3f4844f6f6
|
|||
|
29308de3ee
|
|||
|
0d3d744d94
|
|||
|
d38e525fed
|
|||
|
e2ac38ed0b
|
|||
|
fa534f9eb3
|
|||
|
ec7827df24
|
|||
|
b915488651
|
|||
|
bf9a0226be
|
|||
|
68582f6973
|
|||
|
03f3d4d450
|
|||
|
115428ec50
|
|||
|
5f60852fbb
|
|||
|
a7a5723c4b
|
|||
|
17e42df42d
|
|||
|
7e692460d8
|
|||
|
f41a5946e4
|
|||
|
29fee155d7
|
|||
|
32728fc20a
|
|||
|
394cb80022
|
|||
|
21e49505d1
|
|||
|
e0025e02d1
|
|||
|
4a9590c1d9
|
|||
|
7de0c50387
|
|||
|
ccb87351c1
|
|||
|
273e7266eb
|
|||
|
427975e5ce
|
|||
|
adb304b6a2
|
|||
|
3a89a28f8b
|
|||
|
cff93dcc97
|
|||
|
dfde38ea3b
|
|||
|
a8e7f065cf
|
|||
|
5ebfc67e48
|
|||
|
57b03baad9
|
|||
|
c91f1d0e5e
|
|||
|
6a421292b3
|
|||
|
ceae748503
|
|||
|
008de87e55
|
|||
|
e7479ef9e3
|
|||
|
13f8f12ac8
|
|||
|
fd634379d7
|
|||
|
e854315a81
|
|||
|
86136d7692
|
|||
|
db251bfdfd
|
|||
|
9d39f26d54
|
|||
|
9cd813c02c
|
|||
|
8e1f87e062
|
|||
|
dda954285c
|
|||
|
ed4f7b6b72
|
|||
|
7239dcf4d2
|
|||
|
901cca268e
|
|||
|
b909341988
|
|||
|
3e607ae0fe
|
|||
|
587060f73c
|
|||
|
3ea6f6ac18
|
|||
|
c162761464
|
|||
|
994f9635ef
|
|||
|
ab8752845d
|
|||
|
a94ee2fe4b
|
|||
|
763c999b09
|
|||
|
b18cd2658c
|
|||
|
d9782f554f
|
|||
|
f1d9663709
|
|||
|
bcf77052a5
|
|||
| 85d15b32e9 | |||
| 3d3b695c85 | |||
| 88b7cac298 | |||
| c7efa631e1 | |||
| aeb90cbb1a | |||
| ae1c59847f | |||
| 651d9be57c | |||
| eeb32db6fb | |||
| daa0780644 | |||
| 8502f9105f | |||
| 16ced3d827 | |||
| 1c16187346 | |||
| 2fe058d9cb | |||
| cefdadd53a | |||
| c21c10df63 | |||
| b4d359d30c | |||
| 1e8c62ac25 | |||
| c578f36644 | |||
| c973d0cff4 | |||
| 0c3d9ae46a | |||
| a834e8b6a2 | |||
| 9f5580d983 | |||
| e94e3cecf8 | |||
| 1991f7f50f | |||
| 9eb4e623e7 | |||
| ad28d2279f | |||
| 1e3de31fc3 | |||
| f85bd41b96 | |||
| 563124b68c | |||
| 63de08c635 | |||
| 8a0a215443 | |||
| f1b7cd633e | |||
| 458eeeccda | |||
| 464e758b94 | |||
| 4c61047e9b | |||
| 1bf9e7fb56 | |||
| ca69554f37 | |||
| cf7029037e | |||
| 418388b0ab | |||
| a0f8689d4f | |||
| 95007bdd26 | |||
| ab91540deb |
4
.gitattributes
vendored
4
.gitattributes
vendored
@@ -1,5 +1,3 @@
|
|||||||
# Auto detect text files and perform LF normalization
|
# Auto detect text files and perform LF normalization
|
||||||
* text=auto
|
* text=auto eof=lf
|
||||||
|
|
||||||
*.txt text eof=lf
|
|
||||||
*.cs diff=csharp
|
*.cs diff=csharp
|
||||||
|
|||||||
3
.github/FUNDING.yml
vendored
3
.github/FUNDING.yml
vendored
@@ -1,4 +1,3 @@
|
|||||||
# These are supported funding model platforms
|
github: chylex
|
||||||
|
|
||||||
patreon: chylex
|
patreon: chylex
|
||||||
ko_fi: chylex
|
ko_fi: chylex
|
||||||
|
|||||||
7
.gitignore
vendored
7
.gitignore
vendored
@@ -5,8 +5,14 @@
|
|||||||
bld/*
|
bld/*
|
||||||
!bld/*.iss
|
!bld/*.iss
|
||||||
!bld/*.bat
|
!bld/*.bat
|
||||||
|
!bld/*.ps1
|
||||||
|
!bld/Redist
|
||||||
!bld/Resources
|
!bld/Resources
|
||||||
|
|
||||||
|
# Rider
|
||||||
|
.idea/.idea.TweetDuck/.idea/dictionaries
|
||||||
|
.idea/.idea.TweetDuck/.idea/misc.xml
|
||||||
|
|
||||||
# User-specific files
|
# User-specific files
|
||||||
*.suo
|
*.suo
|
||||||
*.user
|
*.user
|
||||||
@@ -140,4 +146,3 @@ _UpgradeReport_Files/
|
|||||||
Backup*/
|
Backup*/
|
||||||
UpgradeLog*.XML
|
UpgradeLog*.XML
|
||||||
UpgradeLog*.htm
|
UpgradeLog*.htm
|
||||||
|
|
||||||
|
|||||||
8
.idea/.idea.TweetDuck/.idea/.gitignore
generated
vendored
Normal file
8
.idea/.idea.TweetDuck/.idea/.gitignore
generated
vendored
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
# Default ignored files
|
||||||
|
/shelf/
|
||||||
|
/workspace.xml
|
||||||
|
# Rider ignored files
|
||||||
|
/projectSettingsUpdater.xml
|
||||||
|
/modules.xml
|
||||||
|
/contentModel.xml
|
||||||
|
/.idea.TweetDuck.iml
|
||||||
450
.idea/.idea.TweetDuck/.idea/codeStyles/Project.xml
generated
Normal file
450
.idea/.idea.TweetDuck/.idea/codeStyles/Project.xml
generated
Normal file
@@ -0,0 +1,450 @@
|
|||||||
|
<component name="ProjectCodeStyleConfiguration">
|
||||||
|
<code_scheme name="Project" version="173">
|
||||||
|
<option name="AUTODETECT_INDENTS" value="false" />
|
||||||
|
<option name="OTHER_INDENT_OPTIONS">
|
||||||
|
<value>
|
||||||
|
<option name="INDENT_SIZE" value="2" />
|
||||||
|
<option name="TAB_SIZE" value="2" />
|
||||||
|
</value>
|
||||||
|
</option>
|
||||||
|
<option name="LINE_SEPARATOR" value=" " />
|
||||||
|
<option name="RIGHT_MARGIN" value="999" />
|
||||||
|
<option name="FORMATTER_TAGS_ENABLED" value="true" />
|
||||||
|
<CssCodeStyleSettings>
|
||||||
|
<option name="HEX_COLOR_LOWER_CASE" value="true" />
|
||||||
|
</CssCodeStyleSettings>
|
||||||
|
<DB2CodeStyleSettings version="6">
|
||||||
|
<option name="USE_GENERIC_STYLE" value="true" />
|
||||||
|
</DB2CodeStyleSettings>
|
||||||
|
<DerbyCodeStyleSettings version="6">
|
||||||
|
<option name="USE_GENERIC_STYLE" value="true" />
|
||||||
|
</DerbyCodeStyleSettings>
|
||||||
|
<GoCodeStyleSettings>
|
||||||
|
<option name="MOVE_ALL_STDLIB_IMPORTS_IN_ONE_GROUP" value="true" />
|
||||||
|
<option name="GROUP_STDLIB_IMPORTS" value="true" />
|
||||||
|
<option name="WRAP_COMP_LIT" value="5" />
|
||||||
|
<option name="WRAP_FUNC_PARAMS" value="5" />
|
||||||
|
<option name="WRAP_FUNC_RESULT" value="5" />
|
||||||
|
</GoCodeStyleSettings>
|
||||||
|
<H2CodeStyleSettings version="6">
|
||||||
|
<option name="USE_GENERIC_STYLE" value="true" />
|
||||||
|
</H2CodeStyleSettings>
|
||||||
|
<H2CodeStyleSettings version="6">
|
||||||
|
<option name="USE_GENERIC_STYLE" value="true" />
|
||||||
|
</H2CodeStyleSettings>
|
||||||
|
<HSQLCodeStyleSettings version="6">
|
||||||
|
<option name="USE_GENERIC_STYLE" value="true" />
|
||||||
|
</HSQLCodeStyleSettings>
|
||||||
|
<HTMLCodeStyleSettings>
|
||||||
|
<option name="HTML_ALIGN_TEXT" value="true" />
|
||||||
|
<option name="HTML_SPACE_INSIDE_EMPTY_TAG" value="true" />
|
||||||
|
<option name="HTML_ELEMENTS_TO_REMOVE_NEW_LINE_BEFORE" value="" />
|
||||||
|
<option name="HTML_DO_NOT_INDENT_CHILDREN_OF" value="" />
|
||||||
|
</HTMLCodeStyleSettings>
|
||||||
|
<JSCodeStyleSettings version="0">
|
||||||
|
<option name="FORCE_SEMICOLON_STYLE" value="true" />
|
||||||
|
<option name="SPACE_WITHIN_ARRAY_INITIALIZER_BRACKETS" value="true" />
|
||||||
|
<option name="SPACE_BEFORE_FUNCTION_LEFT_PARENTH" value="false" />
|
||||||
|
<option name="FORCE_QUOTE_STYlE" value="true" />
|
||||||
|
<option name="USE_EXPLICIT_JS_EXTENSION" value="TRUE" />
|
||||||
|
<option name="SPACES_WITHIN_OBJECT_LITERAL_BRACES" value="true" />
|
||||||
|
<option name="SPACES_WITHIN_IMPORTS" value="true" />
|
||||||
|
<option name="USE_CHAINED_CALLS_GROUP_INDENTS" value="true" />
|
||||||
|
<option name="SPACE_BEFORE_ASYNC_ARROW_LPAREN" value="false" />
|
||||||
|
<option name="IMPORT_SORT_MODULE_NAME" value="true" />
|
||||||
|
</JSCodeStyleSettings>
|
||||||
|
<JSON>
|
||||||
|
<option name="OBJECT_WRAPPING" value="5" />
|
||||||
|
<option name="ARRAY_WRAPPING" value="5" />
|
||||||
|
</JSON>
|
||||||
|
<JavaCodeStyleSettings>
|
||||||
|
<option name="INSERT_INNER_CLASS_IMPORTS" value="true" />
|
||||||
|
<option name="CLASS_COUNT_TO_USE_IMPORT_ON_DEMAND" value="99" />
|
||||||
|
<option name="NAMES_COUNT_TO_USE_IMPORT_ON_DEMAND" value="99" />
|
||||||
|
<option name="PACKAGES_TO_USE_IMPORT_ON_DEMAND">
|
||||||
|
<value />
|
||||||
|
</option>
|
||||||
|
<option name="IMPORT_LAYOUT_TABLE">
|
||||||
|
<value>
|
||||||
|
<package name="" withSubpackages="true" static="false" />
|
||||||
|
<package name="javax" withSubpackages="true" static="false" />
|
||||||
|
<package name="java" withSubpackages="true" static="false" />
|
||||||
|
<package name="" withSubpackages="true" static="true" />
|
||||||
|
</value>
|
||||||
|
</option>
|
||||||
|
</JavaCodeStyleSettings>
|
||||||
|
<JetCodeStyleSettings>
|
||||||
|
<option name="PACKAGES_TO_USE_STAR_IMPORTS">
|
||||||
|
<value>
|
||||||
|
<package name="kotlinx.android.synthetic" alias="false" withSubpackages="true" />
|
||||||
|
</value>
|
||||||
|
</option>
|
||||||
|
<option name="ALIGN_IN_COLUMNS_CASE_BRANCH" value="true" />
|
||||||
|
<option name="NAME_COUNT_TO_USE_STAR_IMPORT" value="2147483647" />
|
||||||
|
<option name="NAME_COUNT_TO_USE_STAR_IMPORT_FOR_MEMBERS" value="2147483647" />
|
||||||
|
<option name="IMPORT_NESTED_CLASSES" value="true" />
|
||||||
|
<option name="WRAP_ELVIS_EXPRESSIONS" value="0" />
|
||||||
|
<option name="ALLOW_TRAILING_COMMA" value="true" />
|
||||||
|
<option name="CODE_STYLE_DEFAULTS" value="KOTLIN_OFFICIAL" />
|
||||||
|
</JetCodeStyleSettings>
|
||||||
|
<LessCodeStyleSettings>
|
||||||
|
<option name="HEX_COLOR_LOWER_CASE" value="true" />
|
||||||
|
</LessCodeStyleSettings>
|
||||||
|
<MSSQLCodeStyleSettings version="6">
|
||||||
|
<option name="USE_GENERIC_STYLE" value="true" />
|
||||||
|
</MSSQLCodeStyleSettings>
|
||||||
|
<MySQLCodeStyleSettings version="6">
|
||||||
|
<option name="USE_GENERIC_STYLE" value="true" />
|
||||||
|
</MySQLCodeStyleSettings>
|
||||||
|
<Objective-C>
|
||||||
|
<option name="INDENT_DIRECTIVE_AS_CODE" value="true" />
|
||||||
|
<option name="KEEP_STRUCTURES_IN_ONE_LINE" value="true" />
|
||||||
|
<option name="KEEP_CASE_EXPRESSIONS_IN_ONE_LINE" value="true" />
|
||||||
|
<option name="SPACE_BEFORE_INIT_LIST" value="true" />
|
||||||
|
<option name="SPACE_AFTER_DICTIONARY_LITERAL_COLON" value="false" />
|
||||||
|
</Objective-C>
|
||||||
|
<OracleCodeStyleSettings version="6">
|
||||||
|
<option name="USE_GENERIC_STYLE" value="true" />
|
||||||
|
</OracleCodeStyleSettings>
|
||||||
|
<PHPCodeStyleSettings>
|
||||||
|
<option name="ALIGN_KEY_VALUE_PAIRS" value="true" />
|
||||||
|
<option name="CONCAT_SPACES" value="false" />
|
||||||
|
<option name="COMMA_AFTER_LAST_ARRAY_ELEMENT" value="true" />
|
||||||
|
<option name="PHPDOC_BLANK_LINE_BEFORE_TAGS" value="true" />
|
||||||
|
<option name="LOWER_CASE_BOOLEAN_CONST" value="true" />
|
||||||
|
<option name="LOWER_CASE_NULL_CONST" value="true" />
|
||||||
|
<option name="ELSE_IF_STYLE" value="COMBINE" />
|
||||||
|
<option name="VARIABLE_NAMING_STYLE" value="SNAKE_CASE" />
|
||||||
|
<option name="KEEP_BLANK_LINES_AFTER_LBRACE" value="0" />
|
||||||
|
<option name="SPACE_BEFORE_CLOSURE_LEFT_PARENTHESIS" value="false" />
|
||||||
|
<option name="FORCE_SHORT_DECLARATION_ARRAY_STYLE" value="true" />
|
||||||
|
<option name="NEW_LINE_AFTER_PHP_OPENING_TAG" value="true" />
|
||||||
|
<option name="SPACE_AROUND_ASSIGNMENT_IN_DECLARE" value="true" />
|
||||||
|
</PHPCodeStyleSettings>
|
||||||
|
<PostgresCodeStyleSettings version="6">
|
||||||
|
<option name="USE_GENERIC_STYLE" value="true" />
|
||||||
|
</PostgresCodeStyleSettings>
|
||||||
|
<Properties>
|
||||||
|
<option name="KEEP_BLANK_LINES" value="true" />
|
||||||
|
</Properties>
|
||||||
|
<Python>
|
||||||
|
<option name="SPACE_AROUND_EQ_IN_NAMED_PARAMETER" value="true" />
|
||||||
|
<option name="SPACE_AROUND_EQ_IN_KEYWORD_ARGUMENT" value="true" />
|
||||||
|
<option name="NEW_LINE_AFTER_COLON" value="true" />
|
||||||
|
<option name="DICT_WRAPPING" value="5" />
|
||||||
|
<option name="DICT_NEW_LINE_AFTER_LEFT_BRACE" value="true" />
|
||||||
|
<option name="DICT_NEW_LINE_BEFORE_RIGHT_BRACE" value="true" />
|
||||||
|
</Python>
|
||||||
|
<RsCodeStyleSettings>
|
||||||
|
<option name="ALIGN_RET_TYPE" value="false" />
|
||||||
|
<option name="ALIGN_TYPE_PARAMS" value="true" />
|
||||||
|
<option name="ALLOW_ONE_LINE_MATCH" value="true" />
|
||||||
|
<option name="SPACE_AROUND_ASSOC_TYPE_BINDING" value="true" />
|
||||||
|
</RsCodeStyleSettings>
|
||||||
|
<Ruby>
|
||||||
|
<option name="INDENT_PRIVATE_METHODS" value="true" />
|
||||||
|
<option name="INDENT_PROTECTED_METHODS" value="true" />
|
||||||
|
<option name="INDENT_PUBLIC_METHODS" value="true" />
|
||||||
|
<option name="INDENT_WHEN_CASES" value="true" />
|
||||||
|
<option name="CHAIN_CALLS_ALIGNMENT" value="2" />
|
||||||
|
</Ruby>
|
||||||
|
<SQLiteCodeStyleSettings version="6">
|
||||||
|
<option name="USE_GENERIC_STYLE" value="true" />
|
||||||
|
</SQLiteCodeStyleSettings>
|
||||||
|
<ScssCodeStyleSettings>
|
||||||
|
<option name="HEX_COLOR_LOWER_CASE" value="true" />
|
||||||
|
</ScssCodeStyleSettings>
|
||||||
|
<SqlCodeStyleSettings version="6">
|
||||||
|
<option name="KEYWORD_CASE" value="2" />
|
||||||
|
<option name="TYPE_CASE" value="2" />
|
||||||
|
<option name="CUSTOM_TYPE_CASE" value="2" />
|
||||||
|
<option name="SUBQUERY_CONTENT" value="1" />
|
||||||
|
<option name="SUBQUERY_CLOSING" value="1" />
|
||||||
|
<option name="INSERT_TABLE_EL_LINE" value="0" />
|
||||||
|
<option name="INSERT_EL_WRAP" value="2" />
|
||||||
|
<option name="SET_EL_WRAP" value="2" />
|
||||||
|
<option name="SET_ALIGN_EQUAL_SIGN" value="false" />
|
||||||
|
<option name="FROM_EL_WRAP" value="2" />
|
||||||
|
<option name="FROM_ALIGN_JOIN_TABLES" value="true" />
|
||||||
|
<option name="FROM_INDENT_JOIN" value="false" />
|
||||||
|
<option name="FROM_ONLY_JOIN_INDENT" value="2" />
|
||||||
|
<option name="WHERE_EL_WRAP" value="2" />
|
||||||
|
<option name="TABLE_OPENING" value="1" />
|
||||||
|
<option name="TABLE_CONTENT" value="2" />
|
||||||
|
<option name="TABLE_CLOSING" value="3" />
|
||||||
|
<option name="TABLE_DEFAULTS_ALIGN" value="false" />
|
||||||
|
<option name="TABLE_NULLABILITIES_ALIGN" value="false" />
|
||||||
|
<option name="CONSTRAINT_WRAP_1" value="false" />
|
||||||
|
<option name="CONSTRAINT_WRAP_3" value="true" />
|
||||||
|
<option name="CONSTRAINT_WRAP_4" value="true" />
|
||||||
|
<option name="VIEW_INDENT_QUERY" value="true" />
|
||||||
|
<option name="EXPR_CASE_WHEN_WRAP" value="false" />
|
||||||
|
</SqlCodeStyleSettings>
|
||||||
|
<SybaseCodeStyleSettings version="6">
|
||||||
|
<option name="USE_GENERIC_STYLE" value="true" />
|
||||||
|
</SybaseCodeStyleSettings>
|
||||||
|
<TypeScriptCodeStyleSettings version="0">
|
||||||
|
<option name="SPACE_BEFORE_FUNCTION_LEFT_PARENTH" value="false" />
|
||||||
|
<option name="ENFORCE_TRAILING_COMMA" value="WhenMultiline" />
|
||||||
|
<option name="SPACES_WITHIN_IMPORTS" value="true" />
|
||||||
|
<option name="USE_CHAINED_CALLS_GROUP_INDENTS" value="true" />
|
||||||
|
<option name="SPACE_BEFORE_ASYNC_ARROW_LPAREN" value="false" />
|
||||||
|
</TypeScriptCodeStyleSettings>
|
||||||
|
<XML>
|
||||||
|
<option name="XML_SPACE_INSIDE_EMPTY_TAG" value="true" />
|
||||||
|
</XML>
|
||||||
|
<codeStyleSettings language="CMake">
|
||||||
|
<indentOptions>
|
||||||
|
<option name="CONTINUATION_INDENT_SIZE" value="4" />
|
||||||
|
<option name="USE_TAB_CHARACTER" value="true" />
|
||||||
|
<option name="SMART_TABS" value="true" />
|
||||||
|
<option name="KEEP_INDENTS_ON_EMPTY_LINES" value="true" />
|
||||||
|
</indentOptions>
|
||||||
|
</codeStyleSettings>
|
||||||
|
<codeStyleSettings language="CSS">
|
||||||
|
<indentOptions>
|
||||||
|
<option name="INDENT_SIZE" value="2" />
|
||||||
|
<option name="TAB_SIZE" value="2" />
|
||||||
|
<option name="KEEP_INDENTS_ON_EMPTY_LINES" value="true" />
|
||||||
|
</indentOptions>
|
||||||
|
</codeStyleSettings>
|
||||||
|
<codeStyleSettings language="Groovy">
|
||||||
|
<option name="ELSE_ON_NEW_LINE" value="true" />
|
||||||
|
<option name="SPACE_WITHIN_ARRAY_INITIALIZER_BRACES" value="true" />
|
||||||
|
<option name="IF_BRACE_FORCE" value="3" />
|
||||||
|
<option name="DOWHILE_BRACE_FORCE" value="3" />
|
||||||
|
<option name="WHILE_BRACE_FORCE" value="3" />
|
||||||
|
<option name="FOR_BRACE_FORCE" value="3" />
|
||||||
|
<indentOptions>
|
||||||
|
<option name="CONTINUATION_INDENT_SIZE" value="4" />
|
||||||
|
<option name="USE_TAB_CHARACTER" value="true" />
|
||||||
|
<option name="SMART_TABS" value="true" />
|
||||||
|
<option name="KEEP_INDENTS_ON_EMPTY_LINES" value="true" />
|
||||||
|
</indentOptions>
|
||||||
|
</codeStyleSettings>
|
||||||
|
<codeStyleSettings language="HTML">
|
||||||
|
<option name="LINE_COMMENT_AT_FIRST_COLUMN" value="false" />
|
||||||
|
<option name="BLOCK_COMMENT_AT_FIRST_COLUMN" value="false" />
|
||||||
|
<indentOptions>
|
||||||
|
<option name="INDENT_SIZE" value="2" />
|
||||||
|
<option name="TAB_SIZE" value="2" />
|
||||||
|
<option name="KEEP_INDENTS_ON_EMPTY_LINES" value="true" />
|
||||||
|
</indentOptions>
|
||||||
|
</codeStyleSettings>
|
||||||
|
<codeStyleSettings language="JAVA">
|
||||||
|
<option name="RIGHT_MARGIN" value="999" />
|
||||||
|
<option name="BLANK_LINES_AFTER_PACKAGE" value="0" />
|
||||||
|
<option name="BLANK_LINES_BEFORE_IMPORTS" value="0" />
|
||||||
|
<option name="ELSE_ON_NEW_LINE" value="true" />
|
||||||
|
<option name="SPACE_WITHIN_ARRAY_INITIALIZER_BRACES" value="true" />
|
||||||
|
<option name="SPACE_AFTER_TYPE_CAST" value="false" />
|
||||||
|
<option name="SPACE_BEFORE_SYNCHRONIZED_PARENTHESES" value="false" />
|
||||||
|
<option name="KEEP_SIMPLE_METHODS_IN_ONE_LINE" value="true" />
|
||||||
|
<option name="KEEP_SIMPLE_LAMBDAS_IN_ONE_LINE" value="true" />
|
||||||
|
<option name="KEEP_SIMPLE_CLASSES_IN_ONE_LINE" value="true" />
|
||||||
|
<option name="IF_BRACE_FORCE" value="3" />
|
||||||
|
<option name="DOWHILE_BRACE_FORCE" value="3" />
|
||||||
|
<option name="WHILE_BRACE_FORCE" value="3" />
|
||||||
|
<option name="FOR_BRACE_FORCE" value="3" />
|
||||||
|
<indentOptions>
|
||||||
|
<option name="CONTINUATION_INDENT_SIZE" value="4" />
|
||||||
|
<option name="USE_TAB_CHARACTER" value="true" />
|
||||||
|
<option name="SMART_TABS" value="true" />
|
||||||
|
<option name="KEEP_INDENTS_ON_EMPTY_LINES" value="true" />
|
||||||
|
</indentOptions>
|
||||||
|
</codeStyleSettings>
|
||||||
|
<codeStyleSettings language="JSON">
|
||||||
|
<option name="KEEP_BLANK_LINES_IN_CODE" value="1" />
|
||||||
|
<option name="SPACE_WITHIN_BRACKETS" value="true" />
|
||||||
|
<option name="SPACE_WITHIN_BRACES" value="true" />
|
||||||
|
<indentOptions>
|
||||||
|
<option name="KEEP_INDENTS_ON_EMPTY_LINES" value="true" />
|
||||||
|
</indentOptions>
|
||||||
|
</codeStyleSettings>
|
||||||
|
<codeStyleSettings language="JavaScript">
|
||||||
|
<option name="ELSE_ON_NEW_LINE" value="true" />
|
||||||
|
<option name="ALIGN_MULTILINE_TERNARY_OPERATION" value="true" />
|
||||||
|
<option name="ALIGN_MULTILINE_ARRAY_INITIALIZER_EXPRESSION" value="true" />
|
||||||
|
<option name="IF_BRACE_FORCE" value="3" />
|
||||||
|
<option name="DOWHILE_BRACE_FORCE" value="3" />
|
||||||
|
<option name="WHILE_BRACE_FORCE" value="3" />
|
||||||
|
<option name="FOR_BRACE_FORCE" value="3" />
|
||||||
|
<indentOptions>
|
||||||
|
<option name="USE_TAB_CHARACTER" value="true" />
|
||||||
|
<option name="SMART_TABS" value="true" />
|
||||||
|
<option name="KEEP_INDENTS_ON_EMPTY_LINES" value="true" />
|
||||||
|
</indentOptions>
|
||||||
|
</codeStyleSettings>
|
||||||
|
<codeStyleSettings language="LESS">
|
||||||
|
<indentOptions>
|
||||||
|
<option name="KEEP_INDENTS_ON_EMPTY_LINES" value="true" />
|
||||||
|
</indentOptions>
|
||||||
|
</codeStyleSettings>
|
||||||
|
<codeStyleSettings language="Lua">
|
||||||
|
<indentOptions>
|
||||||
|
<option name="INDENT_SIZE" value="2" />
|
||||||
|
<option name="TAB_SIZE" value="2" />
|
||||||
|
<option name="KEEP_INDENTS_ON_EMPTY_LINES" value="true" />
|
||||||
|
</indentOptions>
|
||||||
|
</codeStyleSettings>
|
||||||
|
<codeStyleSettings language="ObjectiveC">
|
||||||
|
<option name="LINE_COMMENT_AT_FIRST_COLUMN" value="false" />
|
||||||
|
<option name="BLOCK_COMMENT_AT_FIRST_COLUMN" value="false" />
|
||||||
|
<option name="LINE_COMMENT_ADD_SPACE" value="true" />
|
||||||
|
<option name="ELSE_ON_NEW_LINE" value="true" />
|
||||||
|
<option name="SPACE_WITHIN_ARRAY_INITIALIZER_BRACES" value="true" />
|
||||||
|
<option name="IF_BRACE_FORCE" value="3" />
|
||||||
|
<option name="DOWHILE_BRACE_FORCE" value="3" />
|
||||||
|
<option name="WHILE_BRACE_FORCE" value="3" />
|
||||||
|
<option name="FOR_BRACE_FORCE" value="3" />
|
||||||
|
<indentOptions>
|
||||||
|
<option name="CONTINUATION_INDENT_SIZE" value="4" />
|
||||||
|
<option name="USE_TAB_CHARACTER" value="true" />
|
||||||
|
<option name="SMART_TABS" value="true" />
|
||||||
|
<option name="KEEP_INDENTS_ON_EMPTY_LINES" value="true" />
|
||||||
|
</indentOptions>
|
||||||
|
</codeStyleSettings>
|
||||||
|
<codeStyleSettings language="PHP">
|
||||||
|
<option name="LINE_COMMENT_AT_FIRST_COLUMN" value="false" />
|
||||||
|
<option name="KEEP_FIRST_COLUMN_COMMENT" value="false" />
|
||||||
|
<option name="KEEP_CONTROL_STATEMENT_IN_ONE_LINE" value="false" />
|
||||||
|
<option name="KEEP_BLANK_LINES_IN_DECLARATIONS" value="1" />
|
||||||
|
<option name="KEEP_BLANK_LINES_IN_CODE" value="1" />
|
||||||
|
<option name="KEEP_BLANK_LINES_BEFORE_RBRACE" value="0" />
|
||||||
|
<option name="CLASS_BRACE_STYLE" value="1" />
|
||||||
|
<option name="METHOD_BRACE_STYLE" value="1" />
|
||||||
|
<option name="ELSE_ON_NEW_LINE" value="true" />
|
||||||
|
<option name="SPECIAL_ELSE_IF_TREATMENT" value="true" />
|
||||||
|
<option name="ALIGN_MULTILINE_CHAINED_METHODS" value="true" />
|
||||||
|
<option name="ALIGN_MULTILINE_PARAMETERS_IN_CALLS" value="true" />
|
||||||
|
<option name="ALIGN_MULTILINE_ARRAY_INITIALIZER_EXPRESSION" value="true" />
|
||||||
|
<option name="SPACE_BEFORE_ARRAY_INITIALIZER_LBRACE" value="true" />
|
||||||
|
<option name="KEEP_SIMPLE_METHODS_IN_ONE_LINE" value="true" />
|
||||||
|
<option name="KEEP_SIMPLE_CLASSES_IN_ONE_LINE" value="true" />
|
||||||
|
<option name="IF_BRACE_FORCE" value="3" />
|
||||||
|
<option name="DOWHILE_BRACE_FORCE" value="3" />
|
||||||
|
<option name="WHILE_BRACE_FORCE" value="3" />
|
||||||
|
<option name="FOR_BRACE_FORCE" value="3" />
|
||||||
|
<indentOptions>
|
||||||
|
<option name="INDENT_SIZE" value="2" />
|
||||||
|
<option name="TAB_SIZE" value="2" />
|
||||||
|
<option name="KEEP_INDENTS_ON_EMPTY_LINES" value="true" />
|
||||||
|
</indentOptions>
|
||||||
|
</codeStyleSettings>
|
||||||
|
<codeStyleSettings language="Puppet">
|
||||||
|
<indentOptions>
|
||||||
|
<option name="KEEP_INDENTS_ON_EMPTY_LINES" value="true" />
|
||||||
|
</indentOptions>
|
||||||
|
</codeStyleSettings>
|
||||||
|
<codeStyleSettings language="Python">
|
||||||
|
<indentOptions>
|
||||||
|
<option name="KEEP_INDENTS_ON_EMPTY_LINES" value="true" />
|
||||||
|
</indentOptions>
|
||||||
|
</codeStyleSettings>
|
||||||
|
<codeStyleSettings language="RHTML">
|
||||||
|
<indentOptions>
|
||||||
|
<option name="KEEP_INDENTS_ON_EMPTY_LINES" value="true" />
|
||||||
|
</indentOptions>
|
||||||
|
</codeStyleSettings>
|
||||||
|
<codeStyleSettings language="Rust">
|
||||||
|
<option name="RIGHT_MARGIN" value="140" />
|
||||||
|
<option name="ALIGN_MULTILINE_CHAINED_METHODS" value="true" />
|
||||||
|
<indentOptions>
|
||||||
|
<option name="USE_TAB_CHARACTER" value="true" />
|
||||||
|
<option name="SMART_TABS" value="true" />
|
||||||
|
<option name="KEEP_INDENTS_ON_EMPTY_LINES" value="true" />
|
||||||
|
</indentOptions>
|
||||||
|
</codeStyleSettings>
|
||||||
|
<codeStyleSettings language="SASS">
|
||||||
|
<indentOptions>
|
||||||
|
<option name="KEEP_INDENTS_ON_EMPTY_LINES" value="true" />
|
||||||
|
</indentOptions>
|
||||||
|
</codeStyleSettings>
|
||||||
|
<codeStyleSettings language="SCSS">
|
||||||
|
<indentOptions>
|
||||||
|
<option name="KEEP_INDENTS_ON_EMPTY_LINES" value="true" />
|
||||||
|
</indentOptions>
|
||||||
|
</codeStyleSettings>
|
||||||
|
<codeStyleSettings language="SQL">
|
||||||
|
<indentOptions>
|
||||||
|
<option name="USE_TAB_CHARACTER" value="true" />
|
||||||
|
<option name="SMART_TABS" value="true" />
|
||||||
|
<option name="KEEP_INDENTS_ON_EMPTY_LINES" value="true" />
|
||||||
|
</indentOptions>
|
||||||
|
</codeStyleSettings>
|
||||||
|
<codeStyleSettings language="Shell Script">
|
||||||
|
<indentOptions>
|
||||||
|
<option name="INDENT_SIZE" value="4" />
|
||||||
|
<option name="TAB_SIZE" value="4" />
|
||||||
|
<option name="USE_TAB_CHARACTER" value="true" />
|
||||||
|
</indentOptions>
|
||||||
|
</codeStyleSettings>
|
||||||
|
<codeStyleSettings language="TOML">
|
||||||
|
<indentOptions>
|
||||||
|
<option name="CONTINUATION_INDENT_SIZE" value="4" />
|
||||||
|
<option name="KEEP_INDENTS_ON_EMPTY_LINES" value="true" />
|
||||||
|
</indentOptions>
|
||||||
|
</codeStyleSettings>
|
||||||
|
<codeStyleSettings language="TypeScript">
|
||||||
|
<option name="ELSE_ON_NEW_LINE" value="true" />
|
||||||
|
<option name="ALIGN_MULTILINE_TERNARY_OPERATION" value="true" />
|
||||||
|
<option name="ALIGN_MULTILINE_ARRAY_INITIALIZER_EXPRESSION" value="true" />
|
||||||
|
<option name="IF_BRACE_FORCE" value="3" />
|
||||||
|
<option name="DOWHILE_BRACE_FORCE" value="3" />
|
||||||
|
<option name="WHILE_BRACE_FORCE" value="3" />
|
||||||
|
<option name="FOR_BRACE_FORCE" value="3" />
|
||||||
|
<indentOptions>
|
||||||
|
<option name="USE_TAB_CHARACTER" value="true" />
|
||||||
|
<option name="SMART_TABS" value="true" />
|
||||||
|
<option name="KEEP_INDENTS_ON_EMPTY_LINES" value="true" />
|
||||||
|
</indentOptions>
|
||||||
|
</codeStyleSettings>
|
||||||
|
<codeStyleSettings language="XML">
|
||||||
|
<indentOptions>
|
||||||
|
<option name="INDENT_SIZE" value="2" />
|
||||||
|
<option name="TAB_SIZE" value="2" />
|
||||||
|
<option name="SMART_TABS" value="true" />
|
||||||
|
<option name="KEEP_INDENTS_ON_EMPTY_LINES" value="true" />
|
||||||
|
</indentOptions>
|
||||||
|
</codeStyleSettings>
|
||||||
|
<codeStyleSettings language="go">
|
||||||
|
<option name="CALL_PARAMETERS_WRAP" value="5" />
|
||||||
|
<indentOptions>
|
||||||
|
<option name="SMART_TABS" value="true" />
|
||||||
|
<option name="KEEP_INDENTS_ON_EMPTY_LINES" value="true" />
|
||||||
|
</indentOptions>
|
||||||
|
</codeStyleSettings>
|
||||||
|
<codeStyleSettings language="kotlin">
|
||||||
|
<option name="CODE_STYLE_DEFAULTS" value="KOTLIN_OFFICIAL" />
|
||||||
|
<option name="LINE_COMMENT_AT_FIRST_COLUMN" value="false" />
|
||||||
|
<option name="BLOCK_COMMENT_AT_FIRST_COLUMN" value="false" />
|
||||||
|
<option name="LINE_COMMENT_ADD_SPACE" value="true" />
|
||||||
|
<option name="ELSE_ON_NEW_LINE" value="true" />
|
||||||
|
<option name="METHOD_ANNOTATION_WRAP" value="0" />
|
||||||
|
<option name="CLASS_ANNOTATION_WRAP" value="0" />
|
||||||
|
<option name="FIELD_ANNOTATION_WRAP" value="0" />
|
||||||
|
<indentOptions>
|
||||||
|
<option name="CONTINUATION_INDENT_SIZE" value="4" />
|
||||||
|
<option name="USE_TAB_CHARACTER" value="true" />
|
||||||
|
<option name="SMART_TABS" value="true" />
|
||||||
|
<option name="KEEP_INDENTS_ON_EMPTY_LINES" value="true" />
|
||||||
|
</indentOptions>
|
||||||
|
</codeStyleSettings>
|
||||||
|
<codeStyleSettings language="liquid">
|
||||||
|
<indentOptions>
|
||||||
|
<option name="KEEP_INDENTS_ON_EMPTY_LINES" value="true" />
|
||||||
|
</indentOptions>
|
||||||
|
</codeStyleSettings>
|
||||||
|
<codeStyleSettings language="ruby">
|
||||||
|
<option name="SPACE_WITHIN_BRACES" value="true" />
|
||||||
|
<indentOptions>
|
||||||
|
<option name="KEEP_INDENTS_ON_EMPTY_LINES" value="true" />
|
||||||
|
</indentOptions>
|
||||||
|
</codeStyleSettings>
|
||||||
|
<codeStyleSettings language="yaml">
|
||||||
|
<indentOptions>
|
||||||
|
<option name="KEEP_INDENTS_ON_EMPTY_LINES" value="true" />
|
||||||
|
</indentOptions>
|
||||||
|
</codeStyleSettings>
|
||||||
|
</code_scheme>
|
||||||
|
</component>
|
||||||
5
.idea/.idea.TweetDuck/.idea/codeStyles/codeStyleConfig.xml
generated
Normal file
5
.idea/.idea.TweetDuck/.idea/codeStyles/codeStyleConfig.xml
generated
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
<component name="ProjectCodeStyleConfiguration">
|
||||||
|
<state>
|
||||||
|
<option name="USE_PER_PROJECT_SETTINGS" value="true" />
|
||||||
|
</state>
|
||||||
|
</component>
|
||||||
6
.idea/.idea.TweetDuck/.idea/encodings.xml
generated
Normal file
6
.idea/.idea.TweetDuck/.idea/encodings.xml
generated
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project version="4">
|
||||||
|
<component name="Encoding" defaultCharsetForPropertiesFiles="UTF-8">
|
||||||
|
<file url="PROJECT" charset="UTF-8" />
|
||||||
|
</component>
|
||||||
|
</project>
|
||||||
8
.idea/.idea.TweetDuck/.idea/indexLayout.xml
generated
Normal file
8
.idea/.idea.TweetDuck/.idea/indexLayout.xml
generated
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project version="4">
|
||||||
|
<component name="UserContentModel">
|
||||||
|
<attachedFolders />
|
||||||
|
<explicitIncludes />
|
||||||
|
<explicitExcludes />
|
||||||
|
</component>
|
||||||
|
</project>
|
||||||
770
.idea/.idea.TweetDuck/.idea/inspectionProfiles/Project.xml
generated
Normal file
770
.idea/.idea.TweetDuck/.idea/inspectionProfiles/Project.xml
generated
Normal file
@@ -0,0 +1,770 @@
|
|||||||
|
<component name="InspectionProjectProfileManager">
|
||||||
|
<profile version="1.0">
|
||||||
|
<option name="myName" value="Project" />
|
||||||
|
<inspection_tool class="AccessToNonThreadSafeStaticFieldFromInstance" enabled="true" level="WARNING" enabled_by_default="true">
|
||||||
|
<option name="nonThreadSafeClasses">
|
||||||
|
<value />
|
||||||
|
</option>
|
||||||
|
<option name="nonThreadSafeTypes" value="" />
|
||||||
|
</inspection_tool>
|
||||||
|
<inspection_tool class="AccessToStaticFieldLockedOnInstance" enabled="true" level="WARNING" enabled_by_default="true" />
|
||||||
|
<inspection_tool class="AddOperatorModifier" enabled="true" level="WEAK WARNING" enabled_by_default="true" />
|
||||||
|
<inspection_tool class="AmbiguousFieldAccess" enabled="true" level="WARNING" enabled_by_default="true" />
|
||||||
|
<inspection_tool class="AmbiguousMethodCall" enabled="true" level="WARNING" enabled_by_default="true" />
|
||||||
|
<inspection_tool class="AnonymousInnerClassMayBeStatic" enabled="true" level="WARNING" enabled_by_default="true" />
|
||||||
|
<inspection_tool class="ArrayEquality" enabled="true" level="WARNING" enabled_by_default="true" />
|
||||||
|
<inspection_tool class="AssertEqualsCalledOnArray" enabled="true" level="WARNING" enabled_by_default="true" />
|
||||||
|
<inspection_tool class="AssertsWithoutMessagesTestNG" enabled="true" level="WARNING" enabled_by_default="true" />
|
||||||
|
<inspection_tool class="AssignmentOrReturnOfFieldWithMutableType" enabled="true" level="WARNING" enabled_by_default="true" />
|
||||||
|
<inspection_tool class="AssignmentToCatchBlockParameter" enabled="true" level="WARNING" enabled_by_default="true" />
|
||||||
|
<inspection_tool class="AssignmentToLambdaParameter" enabled="true" level="WARNING" enabled_by_default="true" />
|
||||||
|
<inspection_tool class="AssignmentToMethodParameter" enabled="true" level="WARNING" enabled_by_default="true">
|
||||||
|
<option name="ignoreTransformationOfOriginalParameter" value="true" />
|
||||||
|
</inspection_tool>
|
||||||
|
<inspection_tool class="AssignmentToStaticFieldFromInstanceMethod" enabled="true" level="WARNING" enabled_by_default="true" />
|
||||||
|
<inspection_tool class="AssignmentUsedAsCondition" enabled="true" level="WARNING" enabled_by_default="true" />
|
||||||
|
<inspection_tool class="AutoBoxing" enabled="true" level="WARNING" enabled_by_default="true">
|
||||||
|
<option name="ignoreAddedToCollection" value="false" />
|
||||||
|
</inspection_tool>
|
||||||
|
<inspection_tool class="AutoCloseableResource" enabled="true" level="WARNING" enabled_by_default="true">
|
||||||
|
<option name="ignoredTypes" value="java.util.stream.Stream,java.util.stream.IntStream,java.util.stream.LongStream,java.util.stream.DoubleStream,net.minecraft.client.Minecraft,net.minecraft.client.MainWindow" />
|
||||||
|
<option name="METHOD_MATCHER_CONFIG" value="java.util.Formatter,format,java.io.Writer,append,com.google.common.base.Preconditions,checkNotNull,org.hibernate.Session,close,java.io.PrintWriter,printf,net.minecraft.client.MinecraftClient,getInstance|getWindow" />
|
||||||
|
</inspection_tool>
|
||||||
|
<inspection_tool class="AutoUnboxing" enabled="true" level="WARNING" enabled_by_default="true" />
|
||||||
|
<inspection_tool class="AwaitNotInLoop" enabled="true" level="WARNING" enabled_by_default="true" />
|
||||||
|
<inspection_tool class="AwaitWithoutCorrespondingSignal" enabled="true" level="WARNING" enabled_by_default="true" />
|
||||||
|
<inspection_tool class="BadOddness" enabled="true" level="WARNING" enabled_by_default="true" />
|
||||||
|
<inspection_tool class="BigDecimalEquals" enabled="true" level="WARNING" enabled_by_default="true" />
|
||||||
|
<inspection_tool class="BigDecimalLegacyMethod" enabled="true" level="WARNING" enabled_by_default="true" />
|
||||||
|
<inspection_tool class="BooleanExpressionMayBeConditional" enabled="true" level="WARNING" enabled_by_default="true" />
|
||||||
|
<inspection_tool class="CallToNativeMethodWhileLocked" enabled="true" level="WARNING" enabled_by_default="true" />
|
||||||
|
<inspection_tool class="CallableParameterUseCaseInTypeContextInspection" enabled="false" level="WARNING" enabled_by_default="false" />
|
||||||
|
<inspection_tool class="CascadeStringReplacementInspection" enabled="true" level="WARNING" enabled_by_default="true">
|
||||||
|
<option name="USE_SHORT_ARRAYS_SYNTAX" value="true" />
|
||||||
|
</inspection_tool>
|
||||||
|
<inspection_tool class="CastConflictsWithInstanceof" enabled="true" level="WARNING" enabled_by_default="true" />
|
||||||
|
<inspection_tool class="CastToIncompatibleInterface" enabled="true" level="WARNING" enabled_by_default="true" />
|
||||||
|
<inspection_tool class="ChainedEquality" enabled="true" level="WARNING" enabled_by_default="true" />
|
||||||
|
<inspection_tool class="ChannelResource" enabled="true" level="WARNING" enabled_by_default="true">
|
||||||
|
<option name="insideTryAllowed" value="false" />
|
||||||
|
</inspection_tool>
|
||||||
|
<inspection_tool class="ClassIndependentOfModule" enabled="true" level="WARNING" enabled_by_default="true" />
|
||||||
|
<inspection_tool class="ClassLoaderInstantiation" enabled="true" level="WARNING" enabled_by_default="true" />
|
||||||
|
<inspection_tool class="ClassMayBeInterface" enabled="true" level="WEAK WARNING" enabled_by_default="true">
|
||||||
|
<option name="reportClassesWithNonAbstractMethods" value="true" />
|
||||||
|
</inspection_tool>
|
||||||
|
<inspection_tool class="ClassMethodNameMatchesFieldNameInspection" enabled="false" level="WEAK WARNING" enabled_by_default="false" />
|
||||||
|
<inspection_tool class="ClassNameDiffersFromFileName" enabled="true" level="WARNING" enabled_by_default="true" />
|
||||||
|
<inspection_tool class="ClassNewInstance" enabled="true" level="WARNING" enabled_by_default="true" />
|
||||||
|
<inspection_tool class="ClassOnlyUsedInOneModule" enabled="true" level="WARNING" enabled_by_default="true" />
|
||||||
|
<inspection_tool class="ClassOnlyUsedInOnePackage" enabled="true" level="WARNING" enabled_by_default="true" />
|
||||||
|
<inspection_tool class="ClassOverridesFieldOfSuperClassInspection" enabled="true" level="WARNING" enabled_by_default="true">
|
||||||
|
<option name="REPORT_PRIVATE_REDEFINITION" value="false" />
|
||||||
|
</inspection_tool>
|
||||||
|
<inspection_tool class="ClassUnconnectedToPackage" enabled="true" level="WARNING" enabled_by_default="true" />
|
||||||
|
<inspection_tool class="ClassWithOnlyPrivateConstructors" enabled="true" level="WARNING" enabled_by_default="true" />
|
||||||
|
<inspection_tool class="CloneableClassInSecureContext" enabled="true" level="WARNING" enabled_by_default="true" />
|
||||||
|
<inspection_tool class="CollectionContainsUrl" enabled="true" level="WARNING" enabled_by_default="true" />
|
||||||
|
<inspection_tool class="CollectionsFieldAccessReplaceableByMethodCall" enabled="true" level="WARNING" enabled_by_default="true" />
|
||||||
|
<inspection_tool class="ComparableImplementedButEqualsNotOverridden" enabled="true" level="WARNING" enabled_by_default="true" />
|
||||||
|
<inspection_tool class="ComparatorNotSerializable" enabled="true" level="WARNING" enabled_by_default="true" />
|
||||||
|
<inspection_tool class="CompareToUsesNonFinalVariable" enabled="true" level="WARNING" enabled_by_default="true" />
|
||||||
|
<inspection_tool class="ComposeMissingKeys" enabled="true" level="ERROR" enabled_by_default="true" />
|
||||||
|
<inspection_tool class="ConditionSignal" enabled="true" level="WARNING" enabled_by_default="true" />
|
||||||
|
<inspection_tool class="ConditionalExpression" enabled="true" level="INFORMATION" enabled_by_default="true">
|
||||||
|
<option name="ignoreSimpleAssignmentsAndReturns" value="true" />
|
||||||
|
</inspection_tool>
|
||||||
|
<inspection_tool class="ConditionalExpressionWithIdenticalBranchesJS" enabled="true" level="WARNING" enabled_by_default="true" />
|
||||||
|
<inspection_tool class="ConfusingElse" enabled="false" level="WEAK WARNING" enabled_by_default="false">
|
||||||
|
<option name="reportWhenNoStatementFollow" value="true" />
|
||||||
|
</inspection_tool>
|
||||||
|
<inspection_tool class="ConfusingMainMethod" enabled="true" level="WARNING" enabled_by_default="true" />
|
||||||
|
<inspection_tool class="ConfusingOctalEscape" enabled="true" level="WARNING" enabled_by_default="true" />
|
||||||
|
<inspection_tool class="ConfusingPlusesOrMinusesJS" enabled="true" level="WARNING" enabled_by_default="true" />
|
||||||
|
<inspection_tool class="ConstantJUnitAssertArgument" enabled="true" level="WARNING" enabled_by_default="true" />
|
||||||
|
<inspection_tool class="ConstantMathCall" enabled="true" level="WARNING" enabled_by_default="true" />
|
||||||
|
<inspection_tool class="ConstantTestNGAssertArgument" enabled="true" level="WARNING" enabled_by_default="true" />
|
||||||
|
<inspection_tool class="ControlFlowStatementWithoutBraces" enabled="true" level="WEAK WARNING" enabled_by_default="true" />
|
||||||
|
<inspection_tool class="ConvertJavadoc" enabled="true" level="WARNING" enabled_by_default="true" />
|
||||||
|
<inspection_tool class="ConvertLambdaToReference" enabled="true" level="WEAK WARNING" enabled_by_default="true" />
|
||||||
|
<inspection_tool class="ConvertOldAnnotations" enabled="true" level="WARNING" enabled_by_default="true" />
|
||||||
|
<inspection_tool class="CssConvertColorToHexInspection" enabled="true" level="WEAK WARNING" enabled_by_default="true" />
|
||||||
|
<inspection_tool class="CssConvertColorToRgbInspection" enabled="true" level="INFORMATION" enabled_by_default="true" />
|
||||||
|
<inspection_tool class="CssMissingSemicolon" enabled="true" level="WARNING" enabled_by_default="true" />
|
||||||
|
<inspection_tool class="CssReplaceWithShorthandUnsafely" enabled="true" level="WEAK WARNING" enabled_by_default="true" />
|
||||||
|
<inspection_tool class="CustomClassloader" enabled="true" level="WARNING" enabled_by_default="true" />
|
||||||
|
<inspection_tool class="CustomSecurityManager" enabled="true" level="WARNING" enabled_by_default="true" />
|
||||||
|
<inspection_tool class="CyclicClassDependency" enabled="true" level="WARNING" enabled_by_default="true" />
|
||||||
|
<inspection_tool class="CyclicPackageDependency" enabled="true" level="WARNING" enabled_by_default="true" />
|
||||||
|
<inspection_tool class="DateToString" enabled="true" level="WARNING" enabled_by_default="true" />
|
||||||
|
<inspection_tool class="DefaultNotLastCaseInSwitch" enabled="true" level="WARNING" enabled_by_default="true" />
|
||||||
|
<inspection_tool class="DisallowWritingIntoStaticPropertiesInspection" enabled="true" level="WEAK WARNING" enabled_by_default="true" />
|
||||||
|
<inspection_tool class="DisconnectedForeachInstructionInspection" enabled="false" level="WEAK WARNING" enabled_by_default="false" />
|
||||||
|
<inspection_tool class="DisjointPackage" enabled="true" level="WARNING" enabled_by_default="true" />
|
||||||
|
<inspection_tool class="DivideByZeroJS" enabled="true" level="WARNING" enabled_by_default="true" />
|
||||||
|
<inspection_tool class="DocumentWriteJS" enabled="true" level="WARNING" enabled_by_default="true" />
|
||||||
|
<inspection_tool class="DoubleBraceInitialization" enabled="true" level="WARNING" enabled_by_default="true" />
|
||||||
|
<inspection_tool class="DoubleCheckedLocking" enabled="true" level="WARNING" enabled_by_default="true">
|
||||||
|
<option name="ignoreOnVolatileVariables" value="false" />
|
||||||
|
</inspection_tool>
|
||||||
|
<inspection_tool class="DriverManagerGetConnection" enabled="true" level="WARNING" enabled_by_default="true" />
|
||||||
|
<inspection_tool class="DuplicateBooleanBranch" enabled="true" level="WARNING" enabled_by_default="true" />
|
||||||
|
<inspection_tool class="DuplicateConditionJS" enabled="true" level="WARNING" enabled_by_default="true" />
|
||||||
|
<inspection_tool class="DynamicallyGeneratedCodeJS" enabled="true" level="WARNING" enabled_by_default="true" />
|
||||||
|
<inspection_tool class="ES6ConvertIndexedForToForOf" enabled="true" level="WEAK WARNING" enabled_by_default="true" />
|
||||||
|
<inspection_tool class="ES6ConvertLetToConst" enabled="true" level="WEAK WARNING" enabled_by_default="true" />
|
||||||
|
<inspection_tool class="ES6ConvertToForOf" enabled="true" level="WEAK WARNING" enabled_by_default="true" />
|
||||||
|
<inspection_tool class="ES6ShorthandObjectProperty" enabled="true" level="WEAK WARNING" enabled_by_default="true" />
|
||||||
|
<inspection_tool class="ES6TopLevelAwaitExpression" enabled="true" level="ERROR" enabled_by_default="true" />
|
||||||
|
<inspection_tool class="EmptyDirectory" enabled="true" level="WARNING" enabled_by_default="true" />
|
||||||
|
<inspection_tool class="EmptyStatementBody" enabled="true" level="WARNING" enabled_by_default="true">
|
||||||
|
<option name="m_reportEmptyBlocks" value="true" />
|
||||||
|
<option name="commentsAreContent" value="true" />
|
||||||
|
</inspection_tool>
|
||||||
|
<inspection_tool class="EmptySynchronizedStatement" enabled="true" level="WARNING" enabled_by_default="true" />
|
||||||
|
<inspection_tool class="EnumSwitchStatementWhichMissesCases" enabled="true" level="WEAK WARNING" enabled_by_default="true">
|
||||||
|
<option name="ignoreSwitchStatementsWithDefault" value="true" />
|
||||||
|
</inspection_tool>
|
||||||
|
<inspection_tool class="EqualsCalledOnEnumConstant" enabled="true" level="WARNING" enabled_by_default="true" />
|
||||||
|
<inspection_tool class="EqualsHashCodeCalledOnUrl" enabled="true" level="WARNING" enabled_by_default="true" />
|
||||||
|
<inspection_tool class="EqualsUsesNonFinalVariable" enabled="true" level="WARNING" enabled_by_default="true" />
|
||||||
|
<inspection_tool class="ErrorRethrown" enabled="true" level="WARNING" enabled_by_default="true" />
|
||||||
|
<inspection_tool class="ExceptionNameDoesntEndWithException" enabled="true" level="WARNING" enabled_by_default="true" />
|
||||||
|
<inspection_tool class="ExceptionPackage" enabled="true" level="WARNING" enabled_by_default="true" />
|
||||||
|
<inspection_tool class="ExpectedExceptionNeverThrownTestNG" enabled="true" level="WARNING" enabled_by_default="true" />
|
||||||
|
<inspection_tool class="ExplicitArgumentCanBeLambda" enabled="true" level="WEAK WARNING" enabled_by_default="true" />
|
||||||
|
<inspection_tool class="ExtendsThread" enabled="true" level="WARNING" enabled_by_default="true" />
|
||||||
|
<inspection_tool class="ExtendsThrowable" enabled="true" level="WARNING" enabled_by_default="true" />
|
||||||
|
<inspection_tool class="ExternalizableWithSerializationMethods" enabled="true" level="WARNING" enabled_by_default="true" />
|
||||||
|
<inspection_tool class="FallthruInSwitchStatement" enabled="true" level="WARNING" enabled_by_default="true" />
|
||||||
|
<inspection_tool class="FieldAccessedSynchronizedAndUnsynchronized" enabled="true" level="WARNING" enabled_by_default="true">
|
||||||
|
<option name="countGettersAndSetters" value="false" />
|
||||||
|
</inspection_tool>
|
||||||
|
<inspection_tool class="FieldDeclarationSideOnly" enabled="true" level="ERROR" enabled_by_default="true" />
|
||||||
|
<inspection_tool class="FieldHidesSuperclassField" enabled="true" level="WARNING" enabled_by_default="true">
|
||||||
|
<option name="m_ignoreInvisibleFields" value="false" />
|
||||||
|
<option name="ignoreStaticFields" value="false" />
|
||||||
|
</inspection_tool>
|
||||||
|
<inspection_tool class="FieldMayBeStatic" enabled="true" level="WARNING" enabled_by_default="true" />
|
||||||
|
<inspection_tool class="Finalize" enabled="true" level="WARNING" enabled_by_default="true">
|
||||||
|
<option name="ignoreTrivialFinalizers" value="true" />
|
||||||
|
</inspection_tool>
|
||||||
|
<inspection_tool class="FinalizeNotProtected" enabled="true" level="WARNING" enabled_by_default="true" />
|
||||||
|
<inspection_tool class="FixedTimeStartWithInspection" enabled="true" level="WARNING" enabled_by_default="true" />
|
||||||
|
<inspection_tool class="FloatingPointEquality" enabled="true" level="WARNING" enabled_by_default="true" />
|
||||||
|
<inspection_tool class="FoldInitializerAndIfToElvis" enabled="false" level="INFO" enabled_by_default="false" />
|
||||||
|
<inspection_tool class="ForLoopThatDoesntUseLoopVariableJS" enabled="true" level="WARNING" enabled_by_default="true" />
|
||||||
|
<inspection_tool class="ForgottenDebugOutputInspection" enabled="true" level="WEAK WARNING" enabled_by_default="true">
|
||||||
|
<option name="configuration">
|
||||||
|
<list>
|
||||||
|
<option value="\Codeception\Util\Debug::debug" />
|
||||||
|
<option value="\Codeception\Util\Debug::pause" />
|
||||||
|
<option value="\Doctrine\Common\Util\Debug::dump" />
|
||||||
|
<option value="\Doctrine\Common\Util\Debug::export" />
|
||||||
|
<option value="\Illuminate\Support\Debug\Dumper::dump" />
|
||||||
|
<option value="\Symfony\Component\Debug\Debug::enable" />
|
||||||
|
<option value="\Symfony\Component\Debug\DebugClassLoader::enable" />
|
||||||
|
<option value="\Symfony\Component\Debug\ErrorHandler::register" />
|
||||||
|
<option value="\Symfony\Component\Debug\ExceptionHandler::register" />
|
||||||
|
<option value="\TYPO3\CMS\Core\Utility\DebugUtility::debug" />
|
||||||
|
<option value="\Zend\Debug\Debug::dump" />
|
||||||
|
<option value="\Zend\Di\Display\Console::export" />
|
||||||
|
<option value="dd" />
|
||||||
|
<option value="debug_print_backtrace" />
|
||||||
|
<option value="debug_zval_dump" />
|
||||||
|
<option value="dpm" />
|
||||||
|
<option value="dpq" />
|
||||||
|
<option value="dsm" />
|
||||||
|
<option value="dump" />
|
||||||
|
<option value="dvm" />
|
||||||
|
<option value="error_log" />
|
||||||
|
<option value="kpr" />
|
||||||
|
<option value="phpinfo" />
|
||||||
|
<option value="print_r" />
|
||||||
|
<option value="var_dump" />
|
||||||
|
<option value="var_export" />
|
||||||
|
<option value="wp_die" />
|
||||||
|
<option value="xdebug_break" />
|
||||||
|
<option value="xdebug_call_class" />
|
||||||
|
<option value="xdebug_call_file" />
|
||||||
|
<option value="xdebug_call_function" />
|
||||||
|
<option value="xdebug_call_line" />
|
||||||
|
<option value="xdebug_code_coverage_started" />
|
||||||
|
<option value="xdebug_debug_zval" />
|
||||||
|
<option value="xdebug_debug_zval_stdout" />
|
||||||
|
<option value="xdebug_dump_superglobals" />
|
||||||
|
<option value="xdebug_enable" />
|
||||||
|
<option value="xdebug_get_code_coverage" />
|
||||||
|
<option value="xdebug_get_collected_errors" />
|
||||||
|
<option value="xdebug_get_declared_vars" />
|
||||||
|
<option value="xdebug_get_function_stack" />
|
||||||
|
<option value="xdebug_get_headers" />
|
||||||
|
<option value="xdebug_get_monitored_functions" />
|
||||||
|
<option value="xdebug_get_profiler_filename" />
|
||||||
|
<option value="xdebug_get_stack_depth" />
|
||||||
|
<option value="xdebug_get_tracefile_name" />
|
||||||
|
<option value="xdebug_is_enabled" />
|
||||||
|
<option value="xdebug_memory_usage" />
|
||||||
|
<option value="xdebug_peak_memory_usage" />
|
||||||
|
<option value="xdebug_print_function_stack" />
|
||||||
|
<option value="xdebug_start_code_coverage" />
|
||||||
|
<option value="xdebug_start_error_collection" />
|
||||||
|
<option value="xdebug_start_function_monitor" />
|
||||||
|
<option value="xdebug_start_trace" />
|
||||||
|
<option value="xdebug_stop_code_coverage" />
|
||||||
|
<option value="xdebug_stop_error_collection" />
|
||||||
|
<option value="xdebug_stop_function_monitor" />
|
||||||
|
<option value="xdebug_stop_trace" />
|
||||||
|
<option value="xdebug_time_index" />
|
||||||
|
<option value="xdebug_var_dump" />
|
||||||
|
</list>
|
||||||
|
</option>
|
||||||
|
<option name="migratedIntoUserSpace" value="true" />
|
||||||
|
</inspection_tool>
|
||||||
|
<inspection_tool class="FunctionNamingConventionJS" enabled="true" level="WARNING" enabled_by_default="true">
|
||||||
|
<option name="m_regex" value="[a-z][A-Za-z]*" />
|
||||||
|
<option name="m_minLength" value="0" />
|
||||||
|
<option name="m_maxLength" value="99" />
|
||||||
|
</inspection_tool>
|
||||||
|
<inspection_tool class="FunctionWithInconsistentReturnsJS" enabled="true" level="WARNING" enabled_by_default="true" />
|
||||||
|
<inspection_tool class="HashCodeUsesNonFinalVariable" enabled="true" level="WARNING" enabled_by_default="true" />
|
||||||
|
<inspection_tool class="HibernateResource" enabled="true" level="WARNING" enabled_by_default="true">
|
||||||
|
<option name="insideTryAllowed" value="false" />
|
||||||
|
</inspection_tool>
|
||||||
|
<inspection_tool class="HtmlMissingClosingTag" enabled="true" level="WEAK WARNING" enabled_by_default="true" />
|
||||||
|
<inspection_tool class="HtmlPresentationalElement" enabled="true" level="WEAK WARNING" enabled_by_default="true" />
|
||||||
|
<inspection_tool class="HtmlRequiredTitleAttribute" enabled="true" level="INFORMATION" enabled_by_default="true" />
|
||||||
|
<inspection_tool class="IOResource" enabled="true" level="WARNING" enabled_by_default="true">
|
||||||
|
<option name="ignoredTypesString" value="java.io.ByteArrayOutputStream,java.io.ByteArrayInputStream,java.io.StringBufferInputStream,java.io.CharArrayWriter,java.io.CharArrayReader,java.io.StringWriter,java.io.StringReader" />
|
||||||
|
<option name="insideTryAllowed" value="false" />
|
||||||
|
</inspection_tool>
|
||||||
|
<inspection_tool class="IfStatementWithIdenticalBranchesJS" enabled="true" level="WARNING" enabled_by_default="true" />
|
||||||
|
<inspection_tool class="ImplicitDefaultCharsetUsage" enabled="true" level="WARNING" enabled_by_default="true" />
|
||||||
|
<inspection_tool class="InconsistentLanguageLevel" enabled="true" level="WARNING" enabled_by_default="true" />
|
||||||
|
<inspection_tool class="InconsistentLineSeparators" enabled="true" level="WARNING" enabled_by_default="true" />
|
||||||
|
<inspection_tool class="IncrementDecrementOperationEquivalentInspection" enabled="false" level="WEAK WARNING" enabled_by_default="false" />
|
||||||
|
<inspection_tool class="InnerClassOnInterface" enabled="true" level="WARNING" enabled_by_default="true">
|
||||||
|
<option name="m_ignoreInnerInterfaces" value="true" />
|
||||||
|
</inspection_tool>
|
||||||
|
<inspection_tool class="InnerClassReferencedViaSubclass" enabled="true" level="WARNING" enabled_by_default="true" />
|
||||||
|
<inspection_tool class="InnerClassVariableHidesOuterClassVariable" enabled="true" level="WARNING" enabled_by_default="true">
|
||||||
|
<option name="m_ignoreInvisibleFields" value="false" />
|
||||||
|
</inspection_tool>
|
||||||
|
<inspection_tool class="InsertLiteralUnderscores" enabled="true" level="WEAK WARNING" enabled_by_default="true" />
|
||||||
|
<inspection_tool class="InstanceofCatchParameter" enabled="true" level="WARNING" enabled_by_default="true" />
|
||||||
|
<inspection_tool class="InstanceofIncompatibleInterface" enabled="true" level="WARNING" enabled_by_default="true" />
|
||||||
|
<inspection_tool class="InstanceofThis" enabled="true" level="WARNING" enabled_by_default="true" />
|
||||||
|
<inspection_tool class="InterfaceMayBeAnnotatedFunctional" enabled="true" level="WARNING" enabled_by_default="true" />
|
||||||
|
<inspection_tool class="IsEmptyFunctionUsageInspection" enabled="false" level="WARNING" enabled_by_default="false">
|
||||||
|
<option name="SUGGEST_TO_USE_COUNT_CHECK" value="true" />
|
||||||
|
</inspection_tool>
|
||||||
|
<inspection_tool class="IsNullFunctionUsageInspection" enabled="true" level="WARNING" enabled_by_default="true" />
|
||||||
|
<inspection_tool class="IteratorNextDoesNotThrowNoSuchElementException" enabled="true" level="WARNING" enabled_by_default="true" />
|
||||||
|
<inspection_tool class="JDBCExecuteWithNonConstantString" enabled="true" level="WARNING" enabled_by_default="true" />
|
||||||
|
<inspection_tool class="JDBCPrepareStatementWithNonConstantString" enabled="true" level="WARNING" enabled_by_default="true" />
|
||||||
|
<inspection_tool class="JDBCResource" enabled="true" level="WARNING" enabled_by_default="true">
|
||||||
|
<option name="insideTryAllowed" value="false" />
|
||||||
|
</inspection_tool>
|
||||||
|
<inspection_tool class="JNDIResource" enabled="true" level="WARNING" enabled_by_default="true">
|
||||||
|
<option name="insideTryAllowed" value="false" />
|
||||||
|
</inspection_tool>
|
||||||
|
<inspection_tool class="JSArrowFunctionBracesCanBeRemoved" enabled="true" level="WEAK WARNING" enabled_by_default="true" />
|
||||||
|
<inspection_tool class="JSClassNamingConvention" enabled="true" level="WARNING" enabled_by_default="true">
|
||||||
|
<option name="m_minLength" value="0" />
|
||||||
|
<option name="m_maxLength" value="99" />
|
||||||
|
</inspection_tool>
|
||||||
|
<inspection_tool class="JSConstructorReturnsPrimitive" enabled="true" level="WARNING" enabled_by_default="true" />
|
||||||
|
<inspection_tool class="JSEqualityComparisonWithCoercion.TS" enabled="true" level="WARNING" enabled_by_default="true">
|
||||||
|
<option name="mySeverity" value="Always" />
|
||||||
|
</inspection_tool>
|
||||||
|
<inspection_tool class="JSJoinVariableDeclarationAndAssignment" enabled="true" level="WEAK WARNING" enabled_by_default="true" />
|
||||||
|
<inspection_tool class="JSMissingSwitchBranches" enabled="true" level="WEAK WARNING" enabled_by_default="true" />
|
||||||
|
<inspection_tool class="JSNonASCIINames" enabled="true" level="WARNING" enabled_by_default="true">
|
||||||
|
<option name="myAllowOnlyAscii" value="true" />
|
||||||
|
</inspection_tool>
|
||||||
|
<inspection_tool class="JSNonStrictModeUsed" enabled="true" level="WARNING" enabled_by_default="true" />
|
||||||
|
<inspection_tool class="JSOctalInteger" enabled="true" level="ERROR" enabled_by_default="true">
|
||||||
|
<option name="myReportNonStrictEs5" value="true" />
|
||||||
|
</inspection_tool>
|
||||||
|
<inspection_tool class="JSUndeclaredVariable" enabled="true" level="WEAK WARNING" enabled_by_default="true">
|
||||||
|
<option name="myCheckGlobalDefinitions" value="true" />
|
||||||
|
</inspection_tool>
|
||||||
|
<inspection_tool class="JSUnusedGlobalSymbols" enabled="true" level="WARNING" enabled_by_default="true">
|
||||||
|
<option name="myReportUnusedDefinitions" value="true" />
|
||||||
|
<option name="myReportUnusedProperties" value="true" />
|
||||||
|
</inspection_tool>
|
||||||
|
<inspection_tool class="JUnitDatapoint" enabled="true" level="WARNING" enabled_by_default="true" />
|
||||||
|
<inspection_tool class="JUnitRule" enabled="true" level="WARNING" enabled_by_default="true" />
|
||||||
|
<inspection_tool class="JUnitTestNG" enabled="true" level="WARNING" enabled_by_default="true" />
|
||||||
|
<inspection_tool class="JavadocHtmlLint" enabled="true" level="ERROR" enabled_by_default="true" />
|
||||||
|
<inspection_tool class="JoinDeclarationAndAssignmentJava" enabled="true" level="WEAK WARNING" enabled_by_default="true" />
|
||||||
|
<inspection_tool class="LambdaCanBeMethodCall" enabled="true" level="WEAK WARNING" enabled_by_default="true" />
|
||||||
|
<inspection_tool class="LengthOneStringInIndexOf" enabled="true" level="WARNING" enabled_by_default="true" />
|
||||||
|
<inspection_tool class="LengthOneStringsInConcatenation" enabled="true" level="WEAK WARNING" enabled_by_default="true" />
|
||||||
|
<inspection_tool class="LoadLibraryWithNonConstantString" enabled="true" level="WARNING" enabled_by_default="true" />
|
||||||
|
<inspection_tool class="LocalCanBeFinal" enabled="true" level="WARNING" enabled_by_default="true">
|
||||||
|
<option name="REPORT_VARIABLES" value="true" />
|
||||||
|
<option name="REPORT_PARAMETERS" value="true" />
|
||||||
|
</inspection_tool>
|
||||||
|
<inspection_tool class="LocalVariableDeclarationSideOnly" enabled="true" level="ERROR" enabled_by_default="true" />
|
||||||
|
<inspection_tool class="LocalVariableNamingConventionJS" enabled="true" level="WARNING" enabled_by_default="true">
|
||||||
|
<option name="m_regex" value="[a-z][A-Za-z]*" />
|
||||||
|
<option name="m_minLength" value="0" />
|
||||||
|
<option name="m_maxLength" value="99" />
|
||||||
|
</inspection_tool>
|
||||||
|
<inspection_tool class="MalformedSetUpTearDown" enabled="true" level="WARNING" enabled_by_default="true" />
|
||||||
|
<inspection_tool class="MapReplaceableByEnumMap" enabled="true" level="WARNING" enabled_by_default="true" />
|
||||||
|
<inspection_tool class="MethodCallSideOnly" enabled="true" level="ERROR" enabled_by_default="true" />
|
||||||
|
<inspection_tool class="MethodMayBeStatic" enabled="true" level="WARNING" enabled_by_default="true">
|
||||||
|
<option name="m_onlyPrivateOrFinal" value="false" />
|
||||||
|
<option name="m_ignoreEmptyMethods" value="true" />
|
||||||
|
</inspection_tool>
|
||||||
|
<inspection_tool class="MethodMayBeSynchronized" enabled="true" level="WARNING" enabled_by_default="true" />
|
||||||
|
<inspection_tool class="MethodOverloadsParentMethod" enabled="true" level="WARNING" enabled_by_default="true">
|
||||||
|
<option name="reportIncompatibleParameters" value="true" />
|
||||||
|
</inspection_tool>
|
||||||
|
<inspection_tool class="MethodOverridesInaccessibleMethodOfSuper" enabled="true" level="WARNING" enabled_by_default="true" />
|
||||||
|
<inspection_tool class="MethodOverridesStaticMethod" enabled="true" level="WARNING" enabled_by_default="true" />
|
||||||
|
<inspection_tool class="MethodSideOnly" enabled="true" level="ERROR" enabled_by_default="true" />
|
||||||
|
<inspection_tool class="MisorderedAssertEqualsArgumentsTestNG" enabled="true" level="WARNING" enabled_by_default="true" />
|
||||||
|
<inspection_tool class="MisorderedAssertEqualsParameters" enabled="true" level="WARNING" enabled_by_default="true" />
|
||||||
|
<inspection_tool class="MisorderedModifiersInspection" enabled="false" level="WEAK WARNING" enabled_by_default="false" />
|
||||||
|
<inspection_tool class="MissingOverrideAnnotation" enabled="true" level="WARNING" enabled_by_default="true">
|
||||||
|
<option name="ignoreObjectMethods" value="false" />
|
||||||
|
<option name="ignoreAnonymousClassMethods" value="false" />
|
||||||
|
</inspection_tool>
|
||||||
|
<inspection_tool class="MissortedModifiers" enabled="true" level="WARNING" enabled_by_default="true">
|
||||||
|
<option name="m_requireAnnotationsFirst" value="true" />
|
||||||
|
</inspection_tool>
|
||||||
|
<inspection_tool class="MultipleTopLevelClassesInFile" enabled="true" level="WARNING" enabled_by_default="true" />
|
||||||
|
<inspection_tool class="NakedNotify" enabled="true" level="WARNING" enabled_by_default="true" />
|
||||||
|
<inspection_tool class="NegatedConditional" enabled="true" level="WARNING" enabled_by_default="true">
|
||||||
|
<option name="m_ignoreNegatedNullComparison" value="true" />
|
||||||
|
</inspection_tool>
|
||||||
|
<inspection_tool class="NestedAssignment" enabled="true" level="WARNING" enabled_by_default="true" />
|
||||||
|
<inspection_tool class="NestedClassSideOnly" enabled="true" level="ERROR" enabled_by_default="true" />
|
||||||
|
<inspection_tool class="NestedConditionalExpressionJS" enabled="true" level="WARNING" enabled_by_default="true" />
|
||||||
|
<inspection_tool class="NestedSwitchStatement" enabled="true" level="WARNING" enabled_by_default="true" />
|
||||||
|
<inspection_tool class="NestedSynchronizedStatement" enabled="true" level="WARNING" enabled_by_default="true" />
|
||||||
|
<inspection_tool class="NestedTernaryOperatorInspection" enabled="false" level="WARNING" enabled_by_default="false" />
|
||||||
|
<inspection_tool class="NewExpressionSideOnly" enabled="true" level="ERROR" enabled_by_default="true" />
|
||||||
|
<inspection_tool class="NonBlockStatementBodyJS" enabled="true" level="WARNING" enabled_by_default="true" />
|
||||||
|
<inspection_tool class="NonExceptionNameEndsWithException" enabled="true" level="WARNING" enabled_by_default="true" />
|
||||||
|
<inspection_tool class="NonFinalClone" enabled="true" level="WARNING" enabled_by_default="true" />
|
||||||
|
<inspection_tool class="NonFinalFieldInEnum" enabled="true" level="WARNING" enabled_by_default="true" />
|
||||||
|
<inspection_tool class="NonFinalFieldOfException" enabled="true" level="WARNING" enabled_by_default="true" />
|
||||||
|
<inspection_tool class="NonFinalUtilityClass" enabled="true" level="WARNING" enabled_by_default="true" />
|
||||||
|
<inspection_tool class="NonReproducibleMathCall" enabled="true" level="WARNING" enabled_by_default="true" />
|
||||||
|
<inspection_tool class="NonSerializableFieldInSerializableClass" enabled="true" level="WARNING" enabled_by_default="true">
|
||||||
|
<option name="ignorableAnnotations">
|
||||||
|
<value />
|
||||||
|
</option>
|
||||||
|
<option name="ignoreAnonymousInnerClasses" value="false" />
|
||||||
|
<option name="superClassString" value="java.awt.Component" />
|
||||||
|
</inspection_tool>
|
||||||
|
<inspection_tool class="NonSerializableObjectBoundToHttpSession" enabled="true" level="WARNING" enabled_by_default="true" />
|
||||||
|
<inspection_tool class="NonSerializableObjectPassedToObjectStream" enabled="true" level="WARNING" enabled_by_default="true" />
|
||||||
|
<inspection_tool class="NonSerializableWithSerialVersionUIDField" enabled="true" level="WARNING" enabled_by_default="true" />
|
||||||
|
<inspection_tool class="NonSerializableWithSerializationMethods" enabled="true" level="WARNING" enabled_by_default="true" />
|
||||||
|
<inspection_tool class="NonShortCircuitBoolean" enabled="true" level="WARNING" enabled_by_default="true" />
|
||||||
|
<inspection_tool class="NonSynchronizedMethodOverridesSynchronizedMethod" enabled="true" level="WARNING" enabled_by_default="true" />
|
||||||
|
<inspection_tool class="NonThreadSafeLazyInitialization" enabled="true" level="WARNING" enabled_by_default="true" />
|
||||||
|
<inspection_tool class="NotOptimalIfConditionsInspection" enabled="true" level="WARNING" enabled_by_default="true">
|
||||||
|
<option name="REPORT_DUPLICATE_CONDITIONS" value="false" />
|
||||||
|
<option name="SUGGEST_OPTIMIZING_CONDITIONS" value="false" />
|
||||||
|
</inspection_tool>
|
||||||
|
<inspection_tool class="NotifyCalledOnCondition" enabled="true" level="WARNING" enabled_by_default="true" />
|
||||||
|
<inspection_tool class="NotifyWithoutCorrespondingWait" enabled="true" level="WARNING" enabled_by_default="true" />
|
||||||
|
<inspection_tool class="NullThrown" enabled="true" level="WARNING" enabled_by_default="true" />
|
||||||
|
<inspection_tool class="NumericToString" enabled="true" level="WARNING" enabled_by_default="true" />
|
||||||
|
<inspection_tool class="OCInconsistentNaming" enabled="true" level="WEAK WARNING" enabled_by_default="true" />
|
||||||
|
<inspection_tool class="ObjectAllocationIgnoredJS" enabled="true" level="WARNING" enabled_by_default="true" />
|
||||||
|
<inspection_tool class="ObjectInstantiationInEqualsHashCode" enabled="true" level="WARNING" enabled_by_default="true" />
|
||||||
|
<inspection_tool class="ObjectNotify" enabled="true" level="WARNING" enabled_by_default="true" />
|
||||||
|
<inspection_tool class="ObjectToString" enabled="true" level="WARNING" enabled_by_default="true" />
|
||||||
|
<inspection_tool class="ObsoleteCollection" enabled="true" level="WARNING" enabled_by_default="true">
|
||||||
|
<option name="ignoreRequiredObsoleteCollectionTypes" value="true" />
|
||||||
|
</inspection_tool>
|
||||||
|
<inspection_tool class="OctalAndDecimalIntegersMixed" enabled="true" level="WARNING" enabled_by_default="true" />
|
||||||
|
<inspection_tool class="OffsetOperationsInspection" enabled="true" level="ERROR" enabled_by_default="true" />
|
||||||
|
<inspection_tool class="OneTimeUseVariablesInspection" enabled="true" level="WARNING" enabled_by_default="true">
|
||||||
|
<option name="ALLOW_LONG_STATEMENTS" value="true" />
|
||||||
|
</inspection_tool>
|
||||||
|
<inspection_tool class="OverloadedVarargsMethod" enabled="true" level="WARNING" enabled_by_default="true" />
|
||||||
|
<inspection_tool class="PackageInMultipleModules" enabled="true" level="WARNING" enabled_by_default="true" />
|
||||||
|
<inspection_tool class="ParameterHidingMemberVariable" enabled="true" level="WARNING" enabled_by_default="true">
|
||||||
|
<option name="m_ignoreInvisibleFields" value="true" />
|
||||||
|
<option name="m_ignoreStaticMethodParametersHidingInstanceFields" value="true" />
|
||||||
|
<option name="m_ignoreForConstructors" value="true" />
|
||||||
|
<option name="m_ignoreForPropertySetters" value="true" />
|
||||||
|
<option name="m_ignoreForAbstractMethods" value="false" />
|
||||||
|
</inspection_tool>
|
||||||
|
<inspection_tool class="ParameterNamingConventionJS" enabled="true" level="WARNING" enabled_by_default="true">
|
||||||
|
<option name="m_regex" value="[a-z][A-Za-z]*" />
|
||||||
|
<option name="m_minLength" value="0" />
|
||||||
|
<option name="m_maxLength" value="99" />
|
||||||
|
</inspection_tool>
|
||||||
|
<inspection_tool class="ParameterizedParametersStaticCollection" enabled="true" level="WARNING" enabled_by_default="true" />
|
||||||
|
<inspection_tool class="PhpAssignmentInConditionInspection" enabled="true" level="WEAK WARNING" enabled_by_default="true" />
|
||||||
|
<inspection_tool class="PhpAssignmentReplaceableWithOperatorAssignmentInspection" enabled="true" level="WEAK WARNING" enabled_by_default="true" />
|
||||||
|
<inspection_tool class="PhpAssignmentReplaceableWithPrefixExpressionInspection" enabled="true" level="WEAK WARNING" enabled_by_default="true" />
|
||||||
|
<inspection_tool class="PhpCSValidationInspection" enabled="false" level="WEAK WARNING" enabled_by_default="false">
|
||||||
|
<option name="EXTENSIONS" value="php,js,css,inc" />
|
||||||
|
</inspection_tool>
|
||||||
|
<inspection_tool class="PhpClassNamingConventionInspection" enabled="true" level="WARNING" enabled_by_default="true">
|
||||||
|
<option name="m_minLength" value="0" />
|
||||||
|
<option name="m_maxLength" value="0" />
|
||||||
|
</inspection_tool>
|
||||||
|
<inspection_tool class="PhpClosureCanBeConvertedToShortArrowFunctionInspection" enabled="true" level="WEAK WARNING" enabled_by_default="true" />
|
||||||
|
<inspection_tool class="PhpCompoundNamespaceDepthInspection" enabled="true" level="WEAK WARNING" enabled_by_default="true" />
|
||||||
|
<inspection_tool class="PhpConstantNamingConventionInspection" enabled="true" level="WARNING" enabled_by_default="true">
|
||||||
|
<option name="m_minLength" value="0" />
|
||||||
|
<option name="m_maxLength" value="0" />
|
||||||
|
</inspection_tool>
|
||||||
|
<inspection_tool class="PhpConstantReassignmentInspection" enabled="true" level="ERROR" enabled_by_default="true" />
|
||||||
|
<inspection_tool class="PhpDivisionByZeroInspection" enabled="true" level="WARNING" enabled_by_default="true" />
|
||||||
|
<inspection_tool class="PhpDocMissingThrowsInspection" enabled="true" level="WEAK WARNING" enabled_by_default="true">
|
||||||
|
<option name="SKIP_ON_EMPTY_PHPDOC" value="false" />
|
||||||
|
</inspection_tool>
|
||||||
|
<inspection_tool class="PhpFunctionNamingConventionInspection" enabled="true" level="WARNING" enabled_by_default="true">
|
||||||
|
<option name="m_minLength" value="0" />
|
||||||
|
<option name="m_maxLength" value="0" />
|
||||||
|
</inspection_tool>
|
||||||
|
<inspection_tool class="PhpInconsistentReturnPointsInspection" enabled="true" level="WARNING" enabled_by_default="true">
|
||||||
|
<option name="ALLOW_RETURN_NULL_IN_VOID" value="false" />
|
||||||
|
</inspection_tool>
|
||||||
|
<inspection_tool class="PhpLongTypeFormInspection" enabled="true" level="WEAK WARNING" enabled_by_default="true" />
|
||||||
|
<inspection_tool class="PhpLoopCanBeConvertedToArrayFillInspection" enabled="true" level="WEAK WARNING" enabled_by_default="true" />
|
||||||
|
<inspection_tool class="PhpLoopCanBeConvertedToArrayFilterInspection" enabled="true" level="WEAK WARNING" enabled_by_default="true" />
|
||||||
|
<inspection_tool class="PhpLoopCanBeConvertedToArrayMapInspection" enabled="true" level="WEAK WARNING" enabled_by_default="true" />
|
||||||
|
<inspection_tool class="PhpMethodNamingConventionInspection" enabled="true" level="WARNING" enabled_by_default="true">
|
||||||
|
<option name="m_minLength" value="0" />
|
||||||
|
<option name="m_maxLength" value="0" />
|
||||||
|
</inspection_tool>
|
||||||
|
<inspection_tool class="PhpMethodOrClassCallIsNotCaseSensitiveInspection" enabled="true" level="WARNING" enabled_by_default="true" />
|
||||||
|
<inspection_tool class="PhpMissingParentCallMagicInspection" enabled="true" level="WARNING" enabled_by_default="true" />
|
||||||
|
<inspection_tool class="PhpMissingReturnTypeInspection" enabled="true" level="WEAK WARNING" enabled_by_default="true" />
|
||||||
|
<inspection_tool class="PhpMissingStrictTypesDeclarationInspection" enabled="true" level="WARNING" enabled_by_default="true" />
|
||||||
|
<inspection_tool class="PhpMissingVisibilityInspection" enabled="true" level="WEAK WARNING" enabled_by_default="true" />
|
||||||
|
<inspection_tool class="PhpNewClassMissingParameterListInspection" enabled="true" level="WEAK WARNING" enabled_by_default="true" />
|
||||||
|
<inspection_tool class="PhpNonCanonicalElementsOrderInspection" enabled="true" level="WEAK WARNING" enabled_by_default="true" />
|
||||||
|
<inspection_tool class="PhpOverridingMethodVisibilityInspection" enabled="true" level="WEAK WARNING" enabled_by_default="true" />
|
||||||
|
<inspection_tool class="PhpPropertyNamingConventionInspection" enabled="true" level="WARNING" enabled_by_default="true">
|
||||||
|
<option name="m_regex" value="[a-z][_a-z\d]*" />
|
||||||
|
<option name="m_minLength" value="0" />
|
||||||
|
<option name="m_maxLength" value="0" />
|
||||||
|
</inspection_tool>
|
||||||
|
<inspection_tool class="PhpRedundantClosingTagInspection" enabled="false" level="WEAK WARNING" enabled_by_default="false" />
|
||||||
|
<inspection_tool class="PhpSeparateElseIfInspection" enabled="true" level="WEAK WARNING" enabled_by_default="true" />
|
||||||
|
<inspection_tool class="PhpShortOpenTagInspection" enabled="true" level="WEAK WARNING" enabled_by_default="true" />
|
||||||
|
<inspection_tool class="PhpSingleStatementWithBracesInspection" enabled="false" level="INFORMATION" enabled_by_default="false" />
|
||||||
|
<inspection_tool class="PhpStatementHasEmptyBodyInspection" enabled="true" level="WARNING" enabled_by_default="true">
|
||||||
|
<option name="myCommentsCountAsContent" value="true" />
|
||||||
|
</inspection_tool>
|
||||||
|
<inspection_tool class="PhpStatementWithoutBracesInspection" enabled="true" level="WEAK WARNING" enabled_by_default="true" />
|
||||||
|
<inspection_tool class="PhpStaticAsDynamicMethodCallInspection" enabled="true" level="WEAK WARNING" enabled_by_default="true">
|
||||||
|
<option name="SHOW_FOR_MAGIC" value="false" />
|
||||||
|
</inspection_tool>
|
||||||
|
<inspection_tool class="PhpTraditionalSyntaxArrayLiteralInspection" enabled="true" level="WEAK WARNING" enabled_by_default="true" />
|
||||||
|
<inspection_tool class="PhpTraitsUseListInspection" enabled="true" level="WEAK WARNING" enabled_by_default="true" />
|
||||||
|
<inspection_tool class="PhpUndefinedCallbackInspection" enabled="true" level="WARNING" enabled_by_default="true" />
|
||||||
|
<inspection_tool class="PhpUndefinedClassConstantInspection" enabled="true" level="WARNING" enabled_by_default="true">
|
||||||
|
<option name="DOWNGRADE_SEVERITY" value="true" />
|
||||||
|
</inspection_tool>
|
||||||
|
<inspection_tool class="PhpUndefinedMethodInspection" enabled="true" level="WARNING" enabled_by_default="true">
|
||||||
|
<option name="DOWNGRADE_SEVERITY" value="true" />
|
||||||
|
</inspection_tool>
|
||||||
|
<inspection_tool class="PhpUnused" enabled="true" level="WEAK WARNING" enabled_by_default="true">
|
||||||
|
<option name="SHOW_UNUSED_BY_ENTRIES" value="false" />
|
||||||
|
</inspection_tool>
|
||||||
|
<inspection_tool class="PhpUnusedParameterInspection" enabled="true" level="WARNING" enabled_by_default="true">
|
||||||
|
<option name="DONT_REPORT_ANONYMOUS" value="true" />
|
||||||
|
</inspection_tool>
|
||||||
|
<inspection_tool class="PhpVarUsageInspection" enabled="true" level="WEAK WARNING" enabled_by_default="true" />
|
||||||
|
<inspection_tool class="PhpVariableNamingConventionInspection" enabled="true" level="WARNING" enabled_by_default="true">
|
||||||
|
<option name="m_minLength" value="0" />
|
||||||
|
<option name="m_maxLength" value="0" />
|
||||||
|
</inspection_tool>
|
||||||
|
<inspection_tool class="PhpVariableVariableInspection" enabled="true" level="WEAK WARNING" enabled_by_default="true" />
|
||||||
|
<inspection_tool class="PointlessBitwiseExpressionJS" enabled="true" level="WARNING" enabled_by_default="true">
|
||||||
|
<option name="m_ignoreExpressionsContainingConstants" value="false" />
|
||||||
|
</inspection_tool>
|
||||||
|
<inspection_tool class="ProblematicVarargsMethodOverride" enabled="true" level="WARNING" enabled_by_default="true" />
|
||||||
|
<inspection_tool class="ProblematicWhitespace" enabled="true" level="WARNING" enabled_by_default="true" />
|
||||||
|
<inspection_tool class="PropertyCanBeStaticInspection" enabled="true" level="WEAK WARNING" enabled_by_default="true" />
|
||||||
|
<inspection_tool class="ProtectedMemberInFinalClass" enabled="true" level="WARNING" enabled_by_default="true" />
|
||||||
|
<inspection_tool class="PublicFieldAccessedInSynchronizedContext" enabled="true" level="WARNING" enabled_by_default="true" />
|
||||||
|
<inspection_tool class="PublicStaticArrayField" enabled="true" level="WARNING" enabled_by_default="true" />
|
||||||
|
<inspection_tool class="PublicStaticCollectionField" enabled="true" level="WARNING" enabled_by_default="true" />
|
||||||
|
<inspection_tool class="PyAugmentAssignmentInspection" enabled="true" level="WEAK WARNING" enabled_by_default="true" />
|
||||||
|
<inspection_tool class="PyClassicStyleClassInspection" enabled="true" level="WARNING" enabled_by_default="true" />
|
||||||
|
<inspection_tool class="PyMissingTypeHintsInspection" enabled="true" level="WEAK WARNING" enabled_by_default="true">
|
||||||
|
<option name="m_onlyWhenTypesAreKnown" value="false" />
|
||||||
|
</inspection_tool>
|
||||||
|
<inspection_tool class="RawTypeCanBeGeneric" enabled="true" level="WEAK WARNING" enabled_by_default="true" />
|
||||||
|
<inspection_tool class="ReadObjectAndWriteObjectPrivate" enabled="true" level="WARNING" enabled_by_default="true" />
|
||||||
|
<inspection_tool class="ReadObjectInitialization" enabled="true" level="WARNING" enabled_by_default="true" />
|
||||||
|
<inspection_tool class="ReadResolveAndWriteReplaceProtected" enabled="true" level="WARNING" enabled_by_default="true" />
|
||||||
|
<inspection_tool class="RedundantElseClauseInspection" enabled="false" level="WARNING" enabled_by_default="false" />
|
||||||
|
<inspection_tool class="RedundantImplements" enabled="true" level="WARNING" enabled_by_default="true">
|
||||||
|
<option name="ignoreSerializable" value="true" />
|
||||||
|
<option name="ignoreCloneable" value="true" />
|
||||||
|
</inspection_tool>
|
||||||
|
<inspection_tool class="RedundantObjectTypeCheck" enabled="true" level="WEAK WARNING" enabled_by_default="true" />
|
||||||
|
<inspection_tool class="RedundantSuppression" enabled="true" level="WARNING" enabled_by_default="true">
|
||||||
|
<option name="IGNORE_ALL" value="true" />
|
||||||
|
</inspection_tool>
|
||||||
|
<inspection_tool class="ReferencingObjectsInspection" enabled="false" level="WARNING" enabled_by_default="false" />
|
||||||
|
<inspection_tool class="RegExpOctalEscape" enabled="true" level="WEAK WARNING" enabled_by_default="true" />
|
||||||
|
<inspection_tool class="ReplaceAssignmentWithOperatorAssignment" enabled="true" level="WARNING" enabled_by_default="true">
|
||||||
|
<option name="ignoreLazyOperators" value="true" />
|
||||||
|
<option name="ignoreObscureOperators" value="true" />
|
||||||
|
</inspection_tool>
|
||||||
|
<inspection_tool class="ReplaceAssignmentWithOperatorAssignmentJS" enabled="true" level="WEAK WARNING" enabled_by_default="true" />
|
||||||
|
<inspection_tool class="ReplaceCollectionCountWithSize" enabled="true" level="WEAK WARNING" enabled_by_default="true" />
|
||||||
|
<inspection_tool class="ReplaceGuardClauseWithFunctionCall" enabled="true" level="WEAK WARNING" enabled_by_default="true" />
|
||||||
|
<inspection_tool class="ReplaceStringFormatWithLiteral" enabled="true" level="WEAK WARNING" enabled_by_default="true" />
|
||||||
|
<inspection_tool class="ReplaceSubstringWithDropLast" enabled="true" level="WEAK WARNING" enabled_by_default="true" />
|
||||||
|
<inspection_tool class="ReplaceSubstringWithIndexingOperation" enabled="true" level="WEAK WARNING" enabled_by_default="true" />
|
||||||
|
<inspection_tool class="ReplaceSubstringWithSubstringAfter" enabled="true" level="WEAK WARNING" enabled_by_default="true" />
|
||||||
|
<inspection_tool class="ReplaceSubstringWithSubstringBefore" enabled="true" level="WEAK WARNING" enabled_by_default="true" />
|
||||||
|
<inspection_tool class="ReplaceSubstringWithTake" enabled="true" level="WEAK WARNING" enabled_by_default="true" />
|
||||||
|
<inspection_tool class="ResultOfObjectAllocationIgnored" enabled="true" level="WARNING" enabled_by_default="true" />
|
||||||
|
<inspection_tool class="ResultSetIndexZero" enabled="true" level="WARNING" enabled_by_default="true" />
|
||||||
|
<inspection_tool class="ReturnOfInnerClass" enabled="true" level="WARNING" enabled_by_default="true" />
|
||||||
|
<inspection_tool class="RsSimplifyBooleanExpression" enabled="true" level="WARNING" enabled_by_default="true" />
|
||||||
|
<inspection_tool class="RuntimeExec" enabled="true" level="WARNING" enabled_by_default="true" />
|
||||||
|
<inspection_tool class="RuntimeExecWithNonConstantString" enabled="true" level="WARNING" enabled_by_default="true" />
|
||||||
|
<inspection_tool class="SafeLock" enabled="true" level="WARNING" enabled_by_default="true" />
|
||||||
|
<inspection_tool class="SecurityAdvisoriesInspection" enabled="true" level="WARNING" enabled_by_default="true">
|
||||||
|
<option name="optionConfiguration">
|
||||||
|
<list>
|
||||||
|
<option value="barryvdh/laravel-debugbar" />
|
||||||
|
<option value="behat/behat" />
|
||||||
|
<option value="brianium/paratest" />
|
||||||
|
<option value="codeception/codeception" />
|
||||||
|
<option value="codedungeon/phpunit-result-printer" />
|
||||||
|
<option value="composer/composer" />
|
||||||
|
<option value="doctrine/coding-standard" />
|
||||||
|
<option value="filp/whoops" />
|
||||||
|
<option value="friendsofphp/php-cs-fixer" />
|
||||||
|
<option value="humbug/humbug" />
|
||||||
|
<option value="infection/infection" />
|
||||||
|
<option value="jakub-onderka/php-parallel-lint" />
|
||||||
|
<option value="johnkary/phpunit-speedtrap" />
|
||||||
|
<option value="kalessil/production-dependencies-guard" />
|
||||||
|
<option value="mikey179/vfsStream" />
|
||||||
|
<option value="mockery/mockery" />
|
||||||
|
<option value="mybuilder/phpunit-accelerator" />
|
||||||
|
<option value="orchestra/testbench" />
|
||||||
|
<option value="pdepend/pdepend" />
|
||||||
|
<option value="phan/phan" />
|
||||||
|
<option value="phing/phing" />
|
||||||
|
<option value="phpcompatibility/php-compatibility" />
|
||||||
|
<option value="phpmd/phpmd" />
|
||||||
|
<option value="phpro/grumphp" />
|
||||||
|
<option value="phpspec/phpspec" />
|
||||||
|
<option value="phpspec/prophecy" />
|
||||||
|
<option value="phpstan/phpstan" />
|
||||||
|
<option value="phpunit/phpunit" />
|
||||||
|
<option value="povils/phpmnd" />
|
||||||
|
<option value="roave/security-advisories" />
|
||||||
|
<option value="satooshi/php-coveralls" />
|
||||||
|
<option value="sebastian/phpcpd" />
|
||||||
|
<option value="slevomat/coding-standard" />
|
||||||
|
<option value="spatie/phpunit-watcher" />
|
||||||
|
<option value="squizlabs/php_codesniffer" />
|
||||||
|
<option value="sstalle/php7cc" />
|
||||||
|
<option value="symfony/debug" />
|
||||||
|
<option value="symfony/maker-bundle" />
|
||||||
|
<option value="symfony/phpunit-bridge" />
|
||||||
|
<option value="symfony/var-dumper" />
|
||||||
|
<option value="vimeo/psalm" />
|
||||||
|
<option value="wimg/php-compatibility" />
|
||||||
|
<option value="wp-coding-standards/wpcs" />
|
||||||
|
<option value="yiisoft/yii2-coding-standards" />
|
||||||
|
<option value="yiisoft/yii2-debug" />
|
||||||
|
<option value="yiisoft/yii2-gii" />
|
||||||
|
<option value="zendframework/zend-coding-standard" />
|
||||||
|
<option value="zendframework/zend-debug" />
|
||||||
|
<option value="zendframework/zend-test" />
|
||||||
|
</list>
|
||||||
|
</option>
|
||||||
|
</inspection_tool>
|
||||||
|
<inspection_tool class="SerialPersistentFieldsWithWrongSignature" enabled="true" level="WARNING" enabled_by_default="true" />
|
||||||
|
<inspection_tool class="SerialVersionUIDNotStaticFinal" enabled="true" level="WARNING" enabled_by_default="true" />
|
||||||
|
<inspection_tool class="SerializableHasSerialVersionUIDField" enabled="true" level="WARNING" enabled_by_default="true">
|
||||||
|
<option name="ignoreAnonymousInnerClasses" value="false" />
|
||||||
|
<option name="superClassString" value="java.awt.Component" />
|
||||||
|
</inspection_tool>
|
||||||
|
<inspection_tool class="SerializableHasSerializationMethods" enabled="true" level="WARNING" enabled_by_default="true">
|
||||||
|
<option name="ignoreAnonymousInnerClasses" value="false" />
|
||||||
|
<option name="superClassString" value="java.awt.Component" />
|
||||||
|
</inspection_tool>
|
||||||
|
<inspection_tool class="SerializableInnerClassHasSerialVersionUIDField" enabled="true" level="WARNING" enabled_by_default="true">
|
||||||
|
<option name="ignoreAnonymousInnerClasses" value="false" />
|
||||||
|
<option name="superClassString" value="java.awt.Component" />
|
||||||
|
</inspection_tool>
|
||||||
|
<inspection_tool class="SerializableInnerClassWithNonSerializableOuterClass" enabled="true" level="WARNING" enabled_by_default="true">
|
||||||
|
<option name="ignoreAnonymousInnerClasses" value="false" />
|
||||||
|
<option name="superClassString" value="java.awt.Component" />
|
||||||
|
</inspection_tool>
|
||||||
|
<inspection_tool class="SerializableStoresNonSerializable" enabled="true" level="WARNING" enabled_by_default="true" />
|
||||||
|
<inspection_tool class="SerializableWithUnconstructableAncestor" enabled="true" level="WARNING" enabled_by_default="true" />
|
||||||
|
<inspection_tool class="SetReplaceableByEnumSet" enabled="true" level="WARNING" enabled_by_default="true" />
|
||||||
|
<inspection_tool class="SeveralTargetsMessage" enabled="true" level="WARNING" enabled_by_default="true" />
|
||||||
|
<inspection_tool class="SharedThreadLocalRandom" enabled="true" level="WARNING" enabled_by_default="true" />
|
||||||
|
<inspection_tool class="ShortEchoTagCanBeUsedInspection" enabled="true" level="WEAK WARNING" enabled_by_default="true" />
|
||||||
|
<inspection_tool class="SignalWithoutCorrespondingAwait" enabled="true" level="WARNING" enabled_by_default="true" />
|
||||||
|
<inspection_tool class="SimpleDateFormatWithoutLocale" enabled="true" level="WARNING" enabled_by_default="true" />
|
||||||
|
<inspection_tool class="SimplifiableAnnotation" enabled="true" level="WARNING" enabled_by_default="true" />
|
||||||
|
<inspection_tool class="SimplifiableIfStatement" enabled="true" level="WEAK WARNING" enabled_by_default="true" />
|
||||||
|
<inspection_tool class="SingleStatementInBlock" enabled="false" level="INFORMATION" enabled_by_default="false" />
|
||||||
|
<inspection_tool class="SizeReplaceableByIsEmpty" enabled="true" level="WARNING" enabled_by_default="true" />
|
||||||
|
<inspection_tool class="SleepWhileHoldingLock" enabled="true" level="WARNING" enabled_by_default="true" />
|
||||||
|
<inspection_tool class="SocketResource" enabled="true" level="WARNING" enabled_by_default="true">
|
||||||
|
<option name="insideTryAllowed" value="false" />
|
||||||
|
</inspection_tool>
|
||||||
|
<inspection_tool class="SpellCheckingInspection" enabled="false" level="TYPO" enabled_by_default="false">
|
||||||
|
<option name="processCode" value="true" />
|
||||||
|
<option name="processLiterals" value="true" />
|
||||||
|
<option name="processComments" value="true" />
|
||||||
|
</inspection_tool>
|
||||||
|
<inspection_tool class="SqlGotoInspection" enabled="true" level="WARNING" enabled_by_default="true" />
|
||||||
|
<inspection_tool class="SqlRedundantOrderingDirectionInspection" enabled="false" level="WARNING" enabled_by_default="false" />
|
||||||
|
<inspection_tool class="SqlWithoutWhereInspection" enabled="true" level="WARNING" enabled_by_default="true">
|
||||||
|
<option name="myDontWarnForLimit" value="false" />
|
||||||
|
</inspection_tool>
|
||||||
|
<inspection_tool class="StrTrUsageAsStrReplaceInspection" enabled="false" level="WEAK WARNING" enabled_by_default="false" />
|
||||||
|
<inspection_tool class="StringBufferToStringInConcatenation" enabled="true" level="WARNING" enabled_by_default="true" />
|
||||||
|
<inspection_tool class="StringConcatenationInFormatCall" enabled="true" level="WARNING" enabled_by_default="true" />
|
||||||
|
<inspection_tool class="StringConcatenationInMessageFormatCall" enabled="true" level="WARNING" enabled_by_default="true" />
|
||||||
|
<inspection_tool class="StringConcatenationMissingWhitespace" enabled="true" level="WARNING" enabled_by_default="true" />
|
||||||
|
<inspection_tool class="StringEqualsEmptyString" enabled="true" level="WARNING" enabled_by_default="true">
|
||||||
|
<option name="SUPPRESS_FOR_VALUES_WHICH_COULD_BE_NULL" value="true" />
|
||||||
|
</inspection_tool>
|
||||||
|
<inspection_tool class="StringReplaceableByStringBuffer" enabled="true" level="WARNING" enabled_by_default="true">
|
||||||
|
<option name="onlyWarnOnLoop" value="true" />
|
||||||
|
</inspection_tool>
|
||||||
|
<inspection_tool class="StringToUpperWithoutLocale" enabled="true" level="WARNING" enabled_by_default="true" />
|
||||||
|
<inspection_tool class="SubStrUsedAsStrPosInspection" enabled="false" level="WEAK WARNING" enabled_by_default="false" />
|
||||||
|
<inspection_tool class="SubtractionInCompareTo" enabled="true" level="WARNING" enabled_by_default="true" />
|
||||||
|
<inspection_tool class="SuspiciousArrayCast" enabled="true" level="WARNING" enabled_by_default="true" />
|
||||||
|
<inspection_tool class="SuspiciousIndentAfterControlStatement" enabled="true" level="WARNING" enabled_by_default="true" />
|
||||||
|
<inspection_tool class="SuspiciousLiteralUnderscore" enabled="true" level="WARNING" enabled_by_default="true" />
|
||||||
|
<inspection_tool class="SwitchStatementWithConfusingDeclaration" enabled="true" level="WARNING" enabled_by_default="true" />
|
||||||
|
<inspection_tool class="SynchronizationOnStaticField" enabled="true" level="WARNING" enabled_by_default="true" />
|
||||||
|
<inspection_tool class="SynchronizeOnLock" enabled="true" level="WARNING" enabled_by_default="true" />
|
||||||
|
<inspection_tool class="SynchronizeOnThis" enabled="true" level="WARNING" enabled_by_default="true" />
|
||||||
|
<inspection_tool class="SynchronizedMethod" enabled="true" level="WARNING" enabled_by_default="true">
|
||||||
|
<option name="m_includeNativeMethods" value="true" />
|
||||||
|
<option name="ignoreSynchronizedSuperMethods" value="true" />
|
||||||
|
</inspection_tool>
|
||||||
|
<inspection_tool class="SynchronizedOnLiteralObject" enabled="true" level="WARNING" enabled_by_default="true" />
|
||||||
|
<inspection_tool class="SystemGC" enabled="true" level="WARNING" enabled_by_default="true" />
|
||||||
|
<inspection_tool class="SystemGetenv" enabled="true" level="WARNING" enabled_by_default="true" />
|
||||||
|
<inspection_tool class="SystemProperties" enabled="true" level="WARNING" enabled_by_default="true" />
|
||||||
|
<inspection_tool class="SystemRunFinalizersOnExit" enabled="true" level="WARNING" enabled_by_default="true" />
|
||||||
|
<inspection_tool class="SystemSetSecurityManager" enabled="true" level="WARNING" enabled_by_default="true" />
|
||||||
|
<inspection_tool class="TestCaseInProductCode" enabled="true" level="WARNING" enabled_by_default="true" />
|
||||||
|
<inspection_tool class="TestCaseWithConstructor" enabled="true" level="WARNING" enabled_by_default="true" />
|
||||||
|
<inspection_tool class="TestCaseWithNoTestMethods" enabled="true" level="WARNING" enabled_by_default="true">
|
||||||
|
<option name="ignoreSupers" value="true" />
|
||||||
|
</inspection_tool>
|
||||||
|
<inspection_tool class="TestMethodInProductCode" enabled="true" level="WARNING" enabled_by_default="true" />
|
||||||
|
<inspection_tool class="TestMethodWithoutAssertion" enabled="true" level="WARNING" enabled_by_default="true" />
|
||||||
|
<inspection_tool class="TextLabelInSwitchStatementJS" enabled="true" level="WARNING" enabled_by_default="true" />
|
||||||
|
<inspection_tool class="ThreadLocalNotStaticFinal" enabled="true" level="WARNING" enabled_by_default="true" />
|
||||||
|
<inspection_tool class="ThreadPriority" enabled="true" level="WARNING" enabled_by_default="true" />
|
||||||
|
<inspection_tool class="ThreadStartInConstruction" enabled="true" level="WARNING" enabled_by_default="true" />
|
||||||
|
<inspection_tool class="ThreadStopSuspendResume" enabled="true" level="WARNING" enabled_by_default="true" />
|
||||||
|
<inspection_tool class="ThreadYield" enabled="true" level="WARNING" enabled_by_default="true" />
|
||||||
|
<inspection_tool class="ThrowCaughtLocally" enabled="true" level="WARNING" enabled_by_default="true">
|
||||||
|
<option name="ignoreRethrownExceptions" value="true" />
|
||||||
|
</inspection_tool>
|
||||||
|
<inspection_tool class="ThrowRawExceptionInspection" enabled="false" level="WEAK WARNING" enabled_by_default="false" />
|
||||||
|
<inspection_tool class="TimeToString" enabled="true" level="WARNING" enabled_by_default="true" />
|
||||||
|
<inspection_tool class="TooBroadScope" enabled="true" level="WEAK WARNING" enabled_by_default="true">
|
||||||
|
<option name="m_allowConstructorAsInitializer" value="false" />
|
||||||
|
<option name="m_onlyLookAtBlocks" value="true" />
|
||||||
|
</inspection_tool>
|
||||||
|
<inspection_tool class="TransientFieldInNonSerializableClass" enabled="true" level="WARNING" enabled_by_default="true" />
|
||||||
|
<inspection_tool class="TransientFieldNotInitialized" enabled="true" level="WARNING" enabled_by_default="true" />
|
||||||
|
<inspection_tool class="TrivialStringConcatenation" enabled="true" level="WARNING" enabled_by_default="true" />
|
||||||
|
<inspection_tool class="UnNecessaryDoubleQuotesInspection" enabled="true" level="WEAK WARNING" enabled_by_default="true" />
|
||||||
|
<inspection_tool class="UnaryPlus" enabled="true" level="WARNING" enabled_by_default="true" />
|
||||||
|
<inspection_tool class="UnclearBinaryExpression" enabled="false" level="WEAK WARNING" enabled_by_default="false" />
|
||||||
|
<inspection_tool class="UnconditionalWait" enabled="true" level="WARNING" enabled_by_default="true" />
|
||||||
|
<inspection_tool class="UnconstrainedVariableType" enabled="true" level="WARNING" enabled_by_default="true" />
|
||||||
|
<inspection_tool class="UndeclaredTests" enabled="true" level="WARNING" enabled_by_default="true" />
|
||||||
|
<inspection_tool class="UnknownInspectionInspection" enabled="false" level="WEAK WARNING" enabled_by_default="false" />
|
||||||
|
<inspection_tool class="UnnecessarilyQualifiedStaticUsage" enabled="true" level="WARNING" enabled_by_default="true">
|
||||||
|
<option name="m_ignoreStaticFieldAccesses" value="false" />
|
||||||
|
<option name="m_ignoreStaticMethodCalls" value="false" />
|
||||||
|
<option name="m_ignoreStaticAccessFromStaticContext" value="false" />
|
||||||
|
</inspection_tool>
|
||||||
|
<inspection_tool class="UnnecessarilyQualifiedStaticallyImportedElement" enabled="true" level="WARNING" enabled_by_default="true" />
|
||||||
|
<inspection_tool class="UnnecessaryBoxing" enabled="true" level="WARNING" enabled_by_default="true">
|
||||||
|
<option name="onlyReportSuperfluouslyBoxed" value="true" />
|
||||||
|
</inspection_tool>
|
||||||
|
<inspection_tool class="UnnecessaryConstantArrayCreationExpression" enabled="true" level="WARNING" enabled_by_default="true" />
|
||||||
|
<inspection_tool class="UnnecessaryConstructor" enabled="true" level="WARNING" enabled_by_default="true">
|
||||||
|
<option name="ignoreAnnotations" value="true" />
|
||||||
|
</inspection_tool>
|
||||||
|
<inspection_tool class="UnnecessaryLocalVariable" enabled="true" level="WARNING" enabled_by_default="true">
|
||||||
|
<option name="m_ignoreImmediatelyReturnedVariables" value="true" />
|
||||||
|
<option name="m_ignoreAnnotatedVariables" value="false" />
|
||||||
|
</inspection_tool>
|
||||||
|
<inspection_tool class="UnnecessaryLocalVariableJS" enabled="true" level="WARNING" enabled_by_default="true">
|
||||||
|
<option name="m_ignoreImmediatelyReturnedVariables" value="true" />
|
||||||
|
<option name="m_ignoreAnnotatedVariables" value="false" />
|
||||||
|
</inspection_tool>
|
||||||
|
<inspection_tool class="UnnecessaryParentheses" enabled="true" level="INFORMATION" enabled_by_default="true">
|
||||||
|
<option name="ignoreClarifyingParentheses" value="true" />
|
||||||
|
<option name="ignoreParenthesesOnConditionals" value="false" />
|
||||||
|
<option name="ignoreParenthesesOnLambdaParameter" value="false" />
|
||||||
|
</inspection_tool>
|
||||||
|
<inspection_tool class="UnnecessaryToStringCall" enabled="true" level="WARNING" enabled_by_default="true" />
|
||||||
|
<inspection_tool class="UnnecessaryUnaryMinus" enabled="true" level="WARNING" enabled_by_default="true" />
|
||||||
|
<inspection_tool class="UnnecessaryUnboxing" enabled="true" level="WARNING" enabled_by_default="true">
|
||||||
|
<option name="onlyReportSuperfluouslyUnboxed" value="true" />
|
||||||
|
</inspection_tool>
|
||||||
|
<inspection_tool class="UnsetConstructsCanBeMergedInspection" enabled="false" level="WEAK WARNING" enabled_by_default="false" />
|
||||||
|
<inspection_tool class="UnterminatedStatementJS" enabled="true" level="WARNING" enabled_by_default="true">
|
||||||
|
<option name="ignoreSemicolonAtEndOfBlock" value="false" />
|
||||||
|
</inspection_tool>
|
||||||
|
<inspection_tool class="UnusedCatchParameterJS" enabled="true" level="WARNING" enabled_by_default="true">
|
||||||
|
<option name="m_ignoreCatchBlocksWithComments" value="true" />
|
||||||
|
</inspection_tool>
|
||||||
|
<inspection_tool class="UnusedProperty" enabled="false" level="WARNING" enabled_by_default="false" />
|
||||||
|
<inspection_tool class="UseOfAWTPeerClass" enabled="true" level="WARNING" enabled_by_default="true" />
|
||||||
|
<inspection_tool class="UseOfJDBCDriverClass" enabled="true" level="WARNING" enabled_by_default="true" />
|
||||||
|
<inspection_tool class="UseOfObsoleteAssert" enabled="true" level="WARNING" enabled_by_default="true" />
|
||||||
|
<inspection_tool class="UseOfObsoleteDateTimeApi" enabled="true" level="WARNING" enabled_by_default="true" />
|
||||||
|
<inspection_tool class="UseOfProcessBuilder" enabled="true" level="WARNING" enabled_by_default="true" />
|
||||||
|
<inspection_tool class="UseOfPropertiesAsHashtable" enabled="true" level="WARNING" enabled_by_default="true" />
|
||||||
|
<inspection_tool class="UseOfSunClasses" enabled="true" level="WARNING" enabled_by_default="true" />
|
||||||
|
<inspection_tool class="UsingInclusionReturnValueInspection" enabled="true" level="WEAK WARNING" enabled_by_default="true" />
|
||||||
|
<inspection_tool class="UtilityClassWithPublicConstructor" enabled="true" level="WARNING" enabled_by_default="true" />
|
||||||
|
<inspection_tool class="UtilityClassWithoutPrivateConstructor" enabled="true" level="WARNING" enabled_by_default="true">
|
||||||
|
<option name="ignorableAnnotations">
|
||||||
|
<value />
|
||||||
|
</option>
|
||||||
|
<option name="ignoreClassesWithOnlyMain" value="true" />
|
||||||
|
</inspection_tool>
|
||||||
|
<inspection_tool class="VariableNotUsedInsideIf" enabled="true" level="WARNING" enabled_by_default="true" />
|
||||||
|
<inspection_tool class="VariableUseSideOnly" enabled="true" level="ERROR" enabled_by_default="true" />
|
||||||
|
<inspection_tool class="VoidExpressionJS" enabled="true" level="WARNING" enabled_by_default="true" />
|
||||||
|
<inspection_tool class="VolatileArrayField" enabled="true" level="WARNING" enabled_by_default="true" />
|
||||||
|
<inspection_tool class="WaitCalledOnCondition" enabled="true" level="WARNING" enabled_by_default="true" />
|
||||||
|
<inspection_tool class="WaitNotInLoop" enabled="true" level="WARNING" enabled_by_default="true" />
|
||||||
|
<inspection_tool class="WaitNotifyNotInSynchronizedContext" enabled="true" level="WARNING" enabled_by_default="true" />
|
||||||
|
<inspection_tool class="WaitOrAwaitWithoutTimeout" enabled="true" level="WARNING" enabled_by_default="true" />
|
||||||
|
<inspection_tool class="WaitWhileHoldingTwoLocks" enabled="true" level="WARNING" enabled_by_default="true" />
|
||||||
|
<inspection_tool class="WaitWithoutCorrespondingNotify" enabled="true" level="WARNING" enabled_by_default="true" />
|
||||||
|
<inspection_tool class="WhileLoopSpinsOnField" enabled="true" level="WARNING" enabled_by_default="true">
|
||||||
|
<option name="ignoreNonEmtpyLoops" value="false" />
|
||||||
|
</inspection_tool>
|
||||||
|
<inspection_tool class="ZeroLengthArrayInitialization" enabled="true" level="WARNING" enabled_by_default="true" />
|
||||||
|
</profile>
|
||||||
|
</component>
|
||||||
6
.idea/.idea.TweetDuck/.idea/inspectionProfiles/profiles_settings.xml
generated
Normal file
6
.idea/.idea.TweetDuck/.idea/inspectionProfiles/profiles_settings.xml
generated
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
<component name="InspectionProjectProfileManager">
|
||||||
|
<settings>
|
||||||
|
<option name="PROJECT_PROFILE" value="Project" />
|
||||||
|
<version value="1.0" />
|
||||||
|
</settings>
|
||||||
|
</component>
|
||||||
6
.idea/.idea.TweetDuck/.idea/jsLibraryMappings.xml
generated
Normal file
6
.idea/.idea.TweetDuck/.idea/jsLibraryMappings.xml
generated
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project version="4">
|
||||||
|
<component name="JavaScriptLibraryMappings">
|
||||||
|
<file url="PROJECT" libraries="{@types/jquery}" />
|
||||||
|
</component>
|
||||||
|
</project>
|
||||||
20
.idea/.idea.TweetDuck/.idea/runConfigurations/TweetDuck.xml
generated
Normal file
20
.idea/.idea.TweetDuck/.idea/runConfigurations/TweetDuck.xml
generated
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
<component name="ProjectRunConfigurationManager">
|
||||||
|
<configuration default="false" name="TweetDuck" type="DotNetProject" factoryName=".NET Project">
|
||||||
|
<option name="EXE_PATH" value="$PROJECT_DIR$/bin/x86/Debug/TweetDuck.exe" />
|
||||||
|
<option name="PROGRAM_PARAMETERS" value="-datafolder TweetDuckDebug -nogdpr" />
|
||||||
|
<option name="WORKING_DIRECTORY" value="$PROJECT_DIR$/bin/x86/Debug" />
|
||||||
|
<option name="PASS_PARENT_ENVS" value="1" />
|
||||||
|
<option name="USE_EXTERNAL_CONSOLE" value="0" />
|
||||||
|
<option name="USE_MONO" value="0" />
|
||||||
|
<option name="RUNTIME_ARGUMENTS" value="" />
|
||||||
|
<option name="PROJECT_PATH" value="$PROJECT_DIR$/TweetDuck.csproj" />
|
||||||
|
<option name="PROJECT_EXE_PATH_TRACKING" value="1" />
|
||||||
|
<option name="PROJECT_ARGUMENTS_TRACKING" value="1" />
|
||||||
|
<option name="PROJECT_WORKING_DIRECTORY_TRACKING" value="1" />
|
||||||
|
<option name="PROJECT_KIND" value="Console" />
|
||||||
|
<option name="PROJECT_TFM" value=".NETFramework,Version=v4.7.2" />
|
||||||
|
<method v="2">
|
||||||
|
<option name="Build" />
|
||||||
|
</method>
|
||||||
|
</configuration>
|
||||||
|
</component>
|
||||||
11
.idea/.idea.TweetDuck/.idea/vcs.xml
generated
Normal file
11
.idea/.idea.TweetDuck/.idea/vcs.xml
generated
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project version="4">
|
||||||
|
<component name="GitSharedSettings">
|
||||||
|
<option name="FORCE_PUSH_PROHIBITED_PATTERNS">
|
||||||
|
<list />
|
||||||
|
</option>
|
||||||
|
</component>
|
||||||
|
<component name="VcsDirectoryMappings">
|
||||||
|
<mapping directory="$PROJECT_DIR$" vcs="Git" />
|
||||||
|
</component>
|
||||||
|
</project>
|
||||||
43
Application/FileDialogs.cs
Normal file
43
Application/FileDialogs.cs
Normal file
@@ -0,0 +1,43 @@
|
|||||||
|
using System;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Windows.Forms;
|
||||||
|
using TweetDuck.Management;
|
||||||
|
using TweetLib.Core.Application;
|
||||||
|
using TweetLib.Core.Systems.Dialogs;
|
||||||
|
|
||||||
|
namespace TweetDuck.Application {
|
||||||
|
sealed class FileDialogs : IAppFileDialogs {
|
||||||
|
public void SaveFile(SaveFileDialogSettings settings, Action<string> onAccepted) {
|
||||||
|
static string FormatFilter(FileDialogFilter filter) {
|
||||||
|
var builder = new StringBuilder();
|
||||||
|
builder.Append(filter.Name);
|
||||||
|
|
||||||
|
var extensions = string.Join(";", filter.Extensions.Select(ext => "*" + ext));
|
||||||
|
if (extensions.Length > 0) {
|
||||||
|
builder.Append(" (");
|
||||||
|
builder.Append(extensions);
|
||||||
|
builder.Append(")");
|
||||||
|
}
|
||||||
|
|
||||||
|
builder.Append('|');
|
||||||
|
builder.Append(extensions.Length == 0 ? "*.*" : extensions);
|
||||||
|
return builder.ToString();
|
||||||
|
}
|
||||||
|
|
||||||
|
FormManager.RunOnUIThreadAsync(() => {
|
||||||
|
using SaveFileDialog dialog = new SaveFileDialog {
|
||||||
|
AutoUpgradeEnabled = true,
|
||||||
|
OverwritePrompt = settings.OverwritePrompt,
|
||||||
|
Title = settings.DialogTitle,
|
||||||
|
FileName = settings.FileName,
|
||||||
|
Filter = settings.Filters == null ? null : string.Join("|", settings.Filters.Select(FormatFilter))
|
||||||
|
};
|
||||||
|
|
||||||
|
if (dialog.ShowDialog() == DialogResult.OK) {
|
||||||
|
onAccepted(dialog.FileName);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,58 +0,0 @@
|
|||||||
using System;
|
|
||||||
using System.ComponentModel;
|
|
||||||
using System.Diagnostics;
|
|
||||||
using TweetDuck.Utils;
|
|
||||||
using TweetLib.Core.Application;
|
|
||||||
|
|
||||||
namespace TweetDuck.Application{
|
|
||||||
class LockHandler : IAppLockHandler{
|
|
||||||
private const int WaitRetryDelay = 250;
|
|
||||||
private const int RestoreFailTimeout = 2000;
|
|
||||||
private const int CloseNaturallyTimeout = 10000;
|
|
||||||
private const int CloseKillTimeout = 5000;
|
|
||||||
|
|
||||||
bool IAppLockHandler.RestoreProcess(Process process){
|
|
||||||
if (process.MainWindowHandle == IntPtr.Zero){ // restore if the original process is in tray
|
|
||||||
NativeMethods.BroadcastMessage(Program.WindowRestoreMessage, (uint)process.Id, 0);
|
|
||||||
|
|
||||||
if (WindowsUtils.TrySleepUntil(() => CheckProcessExited(process) || (process.MainWindowHandle != IntPtr.Zero && process.Responding), RestoreFailTimeout, WaitRetryDelay)){
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool IAppLockHandler.CloseProcess(Process process){
|
|
||||||
try{
|
|
||||||
if (process.CloseMainWindow()){
|
|
||||||
// ReSharper disable once AccessToDisposedClosure
|
|
||||||
WindowsUtils.TrySleepUntil(() => CheckProcessExited(process), CloseNaturallyTimeout, WaitRetryDelay);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!process.HasExited){
|
|
||||||
process.Kill();
|
|
||||||
// ReSharper disable once AccessToDisposedClosure
|
|
||||||
WindowsUtils.TrySleepUntil(() => CheckProcessExited(process), CloseKillTimeout, WaitRetryDelay);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (process.HasExited){
|
|
||||||
process.Dispose();
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
else{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}catch(Exception ex) when (ex is InvalidOperationException || ex is Win32Exception){
|
|
||||||
bool hasExited = CheckProcessExited(process);
|
|
||||||
process.Dispose();
|
|
||||||
return hasExited;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private static bool CheckProcessExited(Process process){
|
|
||||||
process.Refresh();
|
|
||||||
return process.HasExited;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
15
Application/MessageDialogs.cs
Normal file
15
Application/MessageDialogs.cs
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
using TweetDuck.Dialogs;
|
||||||
|
using TweetDuck.Management;
|
||||||
|
using TweetLib.Core.Application;
|
||||||
|
|
||||||
|
namespace TweetDuck.Application {
|
||||||
|
sealed class MessageDialogs : IAppMessageDialogs {
|
||||||
|
public void Information(string caption, string text, string buttonAccept) {
|
||||||
|
FormManager.RunOnUIThreadAsync(() => FormMessage.Information(caption, text, buttonAccept));
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Error(string caption, string text, string buttonAccept) {
|
||||||
|
FormManager.RunOnUIThreadAsync(() => FormMessage.Error(caption, text, buttonAccept));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,16 +1,155 @@
|
|||||||
using System.Diagnostics;
|
using System;
|
||||||
|
using System.Diagnostics;
|
||||||
|
using System.Drawing;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
|
using System.Windows.Forms;
|
||||||
|
using TweetDuck.Browser;
|
||||||
|
using TweetDuck.Dialogs;
|
||||||
|
using TweetDuck.Management;
|
||||||
|
using TweetLib.Core;
|
||||||
using TweetLib.Core.Application;
|
using TweetLib.Core.Application;
|
||||||
|
using TweetLib.Core.Features.Twitter;
|
||||||
|
using TweetLib.Core.Systems.Configuration;
|
||||||
|
|
||||||
namespace TweetDuck.Application{
|
namespace TweetDuck.Application {
|
||||||
class SystemHandler : IAppSystemHandler{
|
sealed class SystemHandler : IAppSystemHandler {
|
||||||
void IAppSystemHandler.OpenFileExplorer(string path){
|
public void OpenBrowser(string url) {
|
||||||
if (File.Exists(path)){
|
if (string.IsNullOrWhiteSpace(url)) {
|
||||||
using(Process.Start("explorer.exe", "/select,\"" + path.Replace('/', '\\') + "\"")){}
|
return;
|
||||||
}
|
}
|
||||||
else if (Directory.Exists(path)){
|
|
||||||
using(Process.Start("explorer.exe", '"' + path.Replace('/', '\\') + '"')){}
|
FormManager.RunOnUIThreadAsync(() => {
|
||||||
}
|
var config = Program.Config.User;
|
||||||
}
|
|
||||||
}
|
switch (TwitterUrls.Check(url)) {
|
||||||
|
case TwitterUrls.UrlType.Fine:
|
||||||
|
string browserPath = config.BrowserPath;
|
||||||
|
|
||||||
|
if (browserPath == null || !File.Exists(browserPath)) {
|
||||||
|
OpenAssociatedProgram(url);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
string quotedUrl = '"' + url + '"';
|
||||||
|
string browserArgs = config.BrowserPathArgs == null ? quotedUrl : config.BrowserPathArgs + ' ' + quotedUrl;
|
||||||
|
|
||||||
|
try {
|
||||||
|
using (Process.Start(browserPath, browserArgs)) {}
|
||||||
|
} catch (Exception e) {
|
||||||
|
App.ErrorHandler.HandleException("Error Opening Browser", "Could not open the browser.", true, e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
|
||||||
|
case TwitterUrls.UrlType.Tracking:
|
||||||
|
if (config.IgnoreTrackingUrlWarning) {
|
||||||
|
goto case TwitterUrls.UrlType.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 TwitterUrls.UrlType.Fine;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
|
||||||
|
case TwitterUrls.UrlType.Invalid:
|
||||||
|
FormMessage.Warning("Blocked URL", "A potentially malicious or invalid URL was blocked from opening:\n" + url, FormMessage.OK);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
public void OpenFileExplorer(string path) {
|
||||||
|
if (File.Exists(path)) {
|
||||||
|
using (Process.Start("explorer.exe", "/select,\"" + path.Replace('/', '\\') + "\"")) {}
|
||||||
|
}
|
||||||
|
else if (Directory.Exists(path)) {
|
||||||
|
using (Process.Start("explorer.exe", '"' + path.Replace('/', '\\') + '"')) {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public IAppSystemHandler.OpenAssociatedProgramFunc OpenAssociatedProgram { get; } = path => {
|
||||||
|
try {
|
||||||
|
using (Process.Start(new ProcessStartInfo {
|
||||||
|
FileName = path,
|
||||||
|
ErrorDialog = true
|
||||||
|
})) {}
|
||||||
|
} catch (Exception e) {
|
||||||
|
App.ErrorHandler.HandleException("Error Opening Program", "Could not open the associated program for " + path, true, e);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
public IAppSystemHandler.CopyImageFromFileFunc CopyImageFromFile { get; } = path => {
|
||||||
|
FormManager.RunOnUIThreadAsync(() => {
|
||||||
|
Image image;
|
||||||
|
|
||||||
|
try {
|
||||||
|
image = Image.FromFile(path);
|
||||||
|
} catch (Exception ex) {
|
||||||
|
FormMessage.Error("Copy Image", "An error occurred while copying the image: " + ex.Message, FormMessage.OK);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
ClipboardManager.SetImage(image);
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
public IAppSystemHandler.CopyTextFunc CopyText { get; } = text => {
|
||||||
|
FormManager.RunOnUIThreadAsync(() => ClipboardManager.SetText(text, TextDataFormat.UnicodeText));
|
||||||
|
};
|
||||||
|
|
||||||
|
public IAppSystemHandler.SearchTextFunc SearchText { get; } = text => {
|
||||||
|
if (string.IsNullOrWhiteSpace(text)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
void PerformSearch() {
|
||||||
|
var config = Program.Config.User;
|
||||||
|
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) {
|
||||||
|
PerformSearch();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
App.SystemHandler.OpenBrowser(searchUrl + Uri.EscapeUriString(text));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
FormManager.RunOnUIThreadAsync(PerformSearch);
|
||||||
|
};
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
125
Browser/Adapters/CefBrowserComponent.cs
Normal file
125
Browser/Adapters/CefBrowserComponent.cs
Normal file
@@ -0,0 +1,125 @@
|
|||||||
|
using System;
|
||||||
|
using System.IO;
|
||||||
|
using CefSharp;
|
||||||
|
using CefSharp.WinForms;
|
||||||
|
using TweetDuck.Browser.Handling;
|
||||||
|
using TweetDuck.Management;
|
||||||
|
using TweetDuck.Utils;
|
||||||
|
using TweetLib.Browser.Base;
|
||||||
|
using TweetLib.Browser.Events;
|
||||||
|
using TweetLib.Browser.Interfaces;
|
||||||
|
using TweetLib.Utils.Static;
|
||||||
|
using IContextMenuHandler = TweetLib.Browser.Interfaces.IContextMenuHandler;
|
||||||
|
using IResourceRequestHandler = TweetLib.Browser.Interfaces.IResourceRequestHandler;
|
||||||
|
|
||||||
|
namespace TweetDuck.Browser.Adapters {
|
||||||
|
abstract class CefBrowserComponent : IBrowserComponent {
|
||||||
|
public bool Ready { get; private set; }
|
||||||
|
|
||||||
|
public string Url => browser.Address;
|
||||||
|
public string CacheFolder => BrowserCache.CacheFolder;
|
||||||
|
|
||||||
|
public event EventHandler<BrowserLoadedEventArgs> BrowserLoaded;
|
||||||
|
public event EventHandler<PageLoadEventArgs> PageLoadStart;
|
||||||
|
public event EventHandler<PageLoadEventArgs> PageLoadEnd;
|
||||||
|
|
||||||
|
private readonly ChromiumWebBrowser browser;
|
||||||
|
|
||||||
|
protected CefBrowserComponent(ChromiumWebBrowser browser) {
|
||||||
|
this.browser = browser;
|
||||||
|
this.browser.JsDialogHandler = new JavaScriptDialogHandler();
|
||||||
|
this.browser.LifeSpanHandler = new CustomLifeSpanHandler();
|
||||||
|
this.browser.LoadingStateChanged += OnLoadingStateChanged;
|
||||||
|
this.browser.LoadError += OnLoadError;
|
||||||
|
this.browser.FrameLoadStart += OnFrameLoadStart;
|
||||||
|
this.browser.FrameLoadEnd += OnFrameLoadEnd;
|
||||||
|
this.browser.SetupZoomEvents();
|
||||||
|
}
|
||||||
|
|
||||||
|
void IBrowserComponent.Setup(BrowserSetup setup) {
|
||||||
|
browser.MenuHandler = SetupContextMenu(setup.ContextMenuHandler);
|
||||||
|
browser.ResourceRequestHandlerFactory = SetupResourceHandlerFactory(setup.ResourceRequestHandler);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected abstract ContextMenuBase SetupContextMenu(IContextMenuHandler handler);
|
||||||
|
|
||||||
|
protected abstract CefResourceHandlerFactory SetupResourceHandlerFactory(IResourceRequestHandler handler);
|
||||||
|
|
||||||
|
private void OnLoadingStateChanged(object sender, LoadingStateChangedEventArgs e) {
|
||||||
|
if (!e.IsLoading) {
|
||||||
|
Ready = true;
|
||||||
|
browser.LoadingStateChanged -= OnLoadingStateChanged;
|
||||||
|
BrowserLoaded?.Invoke(this, new BrowserLoadedEventArgsImpl(browser));
|
||||||
|
BrowserLoaded = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private sealed class BrowserLoadedEventArgsImpl : BrowserLoadedEventArgs {
|
||||||
|
private readonly IWebBrowser browser;
|
||||||
|
|
||||||
|
public BrowserLoadedEventArgsImpl(IWebBrowser browser) {
|
||||||
|
this.browser = browser;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void AddDictionaryWords(params string[] words) {
|
||||||
|
foreach (string word in words) {
|
||||||
|
browser.AddWordToDictionary(word);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OnLoadError(object sender, LoadErrorEventArgs e) {
|
||||||
|
if (e.ErrorCode == CefErrorCode.Aborted) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!e.FailedUrl.StartsWithOrdinal("td://resources/error/")) {
|
||||||
|
string errorName = Enum.GetName(typeof(CefErrorCode), e.ErrorCode);
|
||||||
|
string errorTitle = StringUtils.ConvertPascalCaseToScreamingSnakeCase(errorName ?? string.Empty);
|
||||||
|
browser.Load("td://resources/error/error.html#" + Uri.EscapeDataString(errorTitle));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OnFrameLoadStart(object sender, FrameLoadStartEventArgs e) {
|
||||||
|
if (e.Frame.IsMain) {
|
||||||
|
PageLoadStart?.Invoke(this, new PageLoadEventArgs(e.Url));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OnFrameLoadEnd(object sender, FrameLoadEndEventArgs e) {
|
||||||
|
if (e.Frame.IsMain) {
|
||||||
|
PageLoadEnd?.Invoke(this, new PageLoadEventArgs(e.Url));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void AttachBridgeObject(string name, object bridge) {
|
||||||
|
browser.JavascriptObjectRepository.Settings.LegacyBindingEnabled = true;
|
||||||
|
browser.JavascriptObjectRepository.Register(name, bridge, isAsync: true, BindingOptions.DefaultBinder);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void RunScript(string identifier, string script) {
|
||||||
|
using IFrame frame = browser.GetMainFrame();
|
||||||
|
frame.ExecuteJavaScriptAsync(script, identifier, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void DownloadFile(string url, string path, Action onSuccess, Action<Exception> onError) {
|
||||||
|
Cef.UIThreadTaskFactory.StartNew(() => {
|
||||||
|
try {
|
||||||
|
using IFrame frame = browser.GetMainFrame();
|
||||||
|
var request = frame.CreateRequest(false);
|
||||||
|
|
||||||
|
request.Method = "GET";
|
||||||
|
request.Url = url;
|
||||||
|
request.Flags = UrlRequestFlags.AllowStoredCredentials;
|
||||||
|
request.SetReferrer(Url, ReferrerPolicy.Default);
|
||||||
|
|
||||||
|
var fileStream = new FileStream(path, FileMode.Create, FileAccess.Write, FileShare.Read);
|
||||||
|
var client = new DownloadRequestClient(fileStream, onSuccess, onError);
|
||||||
|
frame.CreateUrlRequest(request, client);
|
||||||
|
} catch (Exception e) {
|
||||||
|
onError?.Invoke(e);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
28
Browser/Adapters/CefContextMenuActionRegistry.cs
Normal file
28
Browser/Adapters/CefContextMenuActionRegistry.cs
Normal file
@@ -0,0 +1,28 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using CefSharp;
|
||||||
|
|
||||||
|
namespace TweetDuck.Browser.Adapters {
|
||||||
|
sealed class CefContextMenuActionRegistry {
|
||||||
|
private readonly Dictionary<CefMenuCommand, Action> actions = new Dictionary<CefMenuCommand, Action>();
|
||||||
|
|
||||||
|
public CefMenuCommand AddAction(Action action) {
|
||||||
|
CefMenuCommand id = CefMenuCommand.UserFirst + 500 + actions.Count;
|
||||||
|
actions[id] = action;
|
||||||
|
return id;
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool Execute(CefMenuCommand id) {
|
||||||
|
if (actions.TryGetValue(id, out var action)) {
|
||||||
|
action();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Clear() {
|
||||||
|
actions.Clear();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
80
Browser/Adapters/CefContextMenuModel.cs
Normal file
80
Browser/Adapters/CefContextMenuModel.cs
Normal file
@@ -0,0 +1,80 @@
|
|||||||
|
using System;
|
||||||
|
using CefSharp;
|
||||||
|
using TweetLib.Browser.Contexts;
|
||||||
|
using TweetLib.Browser.Interfaces;
|
||||||
|
using TweetLib.Core.Features.TweetDeck;
|
||||||
|
using TweetLib.Core.Features.Twitter;
|
||||||
|
|
||||||
|
namespace TweetDuck.Browser.Adapters {
|
||||||
|
sealed class CefContextMenuModel : IContextMenuBuilder {
|
||||||
|
private readonly IMenuModel model;
|
||||||
|
private readonly CefContextMenuActionRegistry actionRegistry;
|
||||||
|
|
||||||
|
public CefContextMenuModel(IMenuModel model, CefContextMenuActionRegistry actionRegistry) {
|
||||||
|
this.model = model;
|
||||||
|
this.actionRegistry = actionRegistry;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void AddAction(string name, Action action) {
|
||||||
|
var id = actionRegistry.AddAction(action);
|
||||||
|
model.AddItem(id, name);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void AddActionWithCheck(string name, bool isChecked, Action action) {
|
||||||
|
var id = actionRegistry.AddAction(action);
|
||||||
|
model.AddCheckItem(id, name);
|
||||||
|
model.SetChecked(id, isChecked);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void AddSeparator() {
|
||||||
|
if (model.Count > 0 && model.GetTypeAt(model.Count - 1) != MenuItemType.Separator) { // do not add separators if there is nothing to separate
|
||||||
|
model.AddSeparator();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Context CreateContext(IContextMenuParams parameters, TweetDeckExtraContext extraContext, ImageQuality imageQuality) {
|
||||||
|
var context = new Context();
|
||||||
|
var flags = parameters.TypeFlags;
|
||||||
|
|
||||||
|
var tweet = extraContext?.Tweet;
|
||||||
|
if (tweet != null && !flags.HasFlag(ContextMenuType.Editable)) {
|
||||||
|
context.Tweet = tweet;
|
||||||
|
}
|
||||||
|
|
||||||
|
context.Link = GetLink(parameters, extraContext);
|
||||||
|
context.Media = GetMedia(parameters, extraContext, imageQuality);
|
||||||
|
|
||||||
|
if (flags.HasFlag(ContextMenuType.Selection)) {
|
||||||
|
context.Selection = new Selection(parameters.SelectionText, flags.HasFlag(ContextMenuType.Editable));
|
||||||
|
}
|
||||||
|
|
||||||
|
return context;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static Link? GetLink(IContextMenuParams parameters, TweetDeckExtraContext extraContext) {
|
||||||
|
var link = extraContext?.Link;
|
||||||
|
if (link != null) {
|
||||||
|
return link;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (parameters.TypeFlags.HasFlag(ContextMenuType.Link) && extraContext?.Media == null) {
|
||||||
|
return new Link(parameters.LinkUrl, parameters.UnfilteredLinkUrl);
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static Media? GetMedia(IContextMenuParams parameters, TweetDeckExtraContext extraContext, ImageQuality imageQuality) {
|
||||||
|
var media = extraContext?.Media;
|
||||||
|
if (media != null) {
|
||||||
|
return media;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (parameters.TypeFlags.HasFlag(ContextMenuType.Media) && parameters.HasImageContents) {
|
||||||
|
return new Media(Media.Type.Image, TwitterUrls.GetMediaLink(parameters.SourceUrl, imageQuality));
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
23
Browser/Adapters/CefResourceHandlerFactory.cs
Normal file
23
Browser/Adapters/CefResourceHandlerFactory.cs
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
using System.Diagnostics.CodeAnalysis;
|
||||||
|
using CefSharp;
|
||||||
|
using IResourceRequestHandler = TweetLib.Browser.Interfaces.IResourceRequestHandler;
|
||||||
|
|
||||||
|
namespace TweetDuck.Browser.Adapters {
|
||||||
|
sealed class CefResourceHandlerFactory : IResourceRequestHandlerFactory {
|
||||||
|
bool IResourceRequestHandlerFactory.HasHandlers => registry != null;
|
||||||
|
|
||||||
|
private readonly CefResourceRequestHandler resourceRequestHandler;
|
||||||
|
private readonly CefResourceHandlerRegistry registry;
|
||||||
|
|
||||||
|
public CefResourceHandlerFactory(IResourceRequestHandler resourceRequestHandler, CefResourceHandlerRegistry registry) {
|
||||||
|
this.resourceRequestHandler = new CefResourceRequestHandler(registry, resourceRequestHandler);
|
||||||
|
this.registry = registry;
|
||||||
|
}
|
||||||
|
|
||||||
|
[SuppressMessage("ReSharper", "RedundantAssignment")]
|
||||||
|
CefSharp.IResourceRequestHandler IResourceRequestHandlerFactory.GetResourceRequestHandler(IWebBrowser chromiumWebBrowser, IBrowser browser, IFrame frame, IRequest request, bool isNavigation, bool isDownload, string requestInitiator, ref bool disableDefaultHandling) {
|
||||||
|
disableDefaultHandling = registry != null && registry.HasHandler(request.Url);
|
||||||
|
return resourceRequestHandler;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
42
Browser/Adapters/CefResourceHandlerRegistry.cs
Normal file
42
Browser/Adapters/CefResourceHandlerRegistry.cs
Normal file
@@ -0,0 +1,42 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Concurrent;
|
||||||
|
using System.Text;
|
||||||
|
using CefSharp;
|
||||||
|
|
||||||
|
namespace TweetDuck.Browser.Adapters {
|
||||||
|
sealed class CefResourceHandlerRegistry {
|
||||||
|
private readonly ConcurrentDictionary<string, Func<IResourceHandler>> resourceHandlers = new ConcurrentDictionary<string, Func<IResourceHandler>>(StringComparer.OrdinalIgnoreCase);
|
||||||
|
|
||||||
|
public bool HasHandler(string url) {
|
||||||
|
return resourceHandlers.ContainsKey(url);
|
||||||
|
}
|
||||||
|
|
||||||
|
public IResourceHandler GetHandler(string url) {
|
||||||
|
return resourceHandlers.TryGetValue(url, out var handler) ? handler() : null;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void Register(string url, Func<IResourceHandler> factory) {
|
||||||
|
if (!Uri.TryCreate(url, UriKind.Absolute, out Uri uri)) {
|
||||||
|
throw new ArgumentException("Resource handler URL must be absolute!");
|
||||||
|
}
|
||||||
|
|
||||||
|
resourceHandlers.AddOrUpdate(uri.AbsoluteUri, factory, (key, prev) => factory);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void RegisterStatic(string url, byte[] staticData, string mimeType = ResourceHandler.DefaultMimeType) {
|
||||||
|
Register(url, () => ResourceHandler.FromByteArray(staticData, mimeType));
|
||||||
|
}
|
||||||
|
|
||||||
|
public void RegisterStatic(string url, string staticData, string mimeType = ResourceHandler.DefaultMimeType) {
|
||||||
|
Register(url, () => ResourceHandler.FromString(staticData, Encoding.UTF8, mimeType: mimeType));
|
||||||
|
}
|
||||||
|
|
||||||
|
public void RegisterDynamic(string url, IResourceHandler handler) {
|
||||||
|
Register(url, () => handler);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Unregister(string url) {
|
||||||
|
resourceHandlers.TryRemove(url, out _);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
77
Browser/Adapters/CefResourceRequestHandler.cs
Normal file
77
Browser/Adapters/CefResourceRequestHandler.cs
Normal file
@@ -0,0 +1,77 @@
|
|||||||
|
using System.Collections.Generic;
|
||||||
|
using CefSharp;
|
||||||
|
using CefSharp.Handler;
|
||||||
|
using TweetDuck.Browser.Handling;
|
||||||
|
using TweetLib.Browser.Interfaces;
|
||||||
|
using TweetLib.Browser.Request;
|
||||||
|
using IResourceRequestHandler = TweetLib.Browser.Interfaces.IResourceRequestHandler;
|
||||||
|
using ResourceType = TweetLib.Browser.Request.ResourceType;
|
||||||
|
|
||||||
|
namespace TweetDuck.Browser.Adapters {
|
||||||
|
sealed class CefResourceRequestHandler : ResourceRequestHandler {
|
||||||
|
private readonly CefResourceHandlerRegistry resourceHandlerRegistry;
|
||||||
|
private readonly IResourceRequestHandler resourceRequestHandler;
|
||||||
|
private readonly Dictionary<ulong, IResponseProcessor> responseProcessors = new Dictionary<ulong, IResponseProcessor>();
|
||||||
|
|
||||||
|
public CefResourceRequestHandler(CefResourceHandlerRegistry resourceHandlerRegistry, IResourceRequestHandler resourceRequestHandler) {
|
||||||
|
this.resourceHandlerRegistry = resourceHandlerRegistry;
|
||||||
|
this.resourceRequestHandler = resourceRequestHandler;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override CefReturnValue OnBeforeResourceLoad(IWebBrowser chromiumWebBrowser, IBrowser browser, IFrame frame, IRequest request, IRequestCallback callback) {
|
||||||
|
if (request.ResourceType == CefSharp.ResourceType.CspReport) {
|
||||||
|
callback.Dispose();
|
||||||
|
return CefReturnValue.Cancel;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (resourceRequestHandler != null) {
|
||||||
|
var result = resourceRequestHandler.Handle(request.Url, TranslateResourceType(request.ResourceType));
|
||||||
|
|
||||||
|
switch (result) {
|
||||||
|
case RequestHandleResult.Redirect redirect:
|
||||||
|
request.Url = redirect.Url;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case RequestHandleResult.Process process:
|
||||||
|
request.SetHeaderByName("Accept-Encoding", "identity", overwrite: true);
|
||||||
|
responseProcessors[request.Identifier] = process.Processor;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case RequestHandleResult.Cancel _:
|
||||||
|
callback.Dispose();
|
||||||
|
return CefReturnValue.Cancel;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return base.OnBeforeResourceLoad(chromiumWebBrowser, browser, frame, request, callback);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override IResourceHandler GetResourceHandler(IWebBrowser browserControl, IBrowser browser, IFrame frame, IRequest request) {
|
||||||
|
return resourceHandlerRegistry?.GetHandler(request.Url);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override IResponseFilter GetResourceResponseFilter(IWebBrowser browserControl, IBrowser browser, IFrame frame, IRequest request, IResponse response) {
|
||||||
|
if (responseProcessors.TryGetValue(request.Identifier, out var processor) && int.TryParse(response.Headers["Content-Length"], out int totalBytes)) {
|
||||||
|
return new ResponseFilter(processor, totalBytes);
|
||||||
|
}
|
||||||
|
|
||||||
|
return base.GetResourceResponseFilter(browserControl, browser, frame, request, response);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void OnResourceLoadComplete(IWebBrowser chromiumWebBrowser, IBrowser browser, IFrame frame, IRequest request, IResponse response, UrlRequestStatus status, long receivedContentLength) {
|
||||||
|
responseProcessors.Remove(request.Identifier);
|
||||||
|
base.OnResourceLoadComplete(chromiumWebBrowser, browser, frame, request, response, status, receivedContentLength);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static ResourceType TranslateResourceType(CefSharp.ResourceType resourceType) {
|
||||||
|
return resourceType switch {
|
||||||
|
CefSharp.ResourceType.MainFrame => ResourceType.MainFrame,
|
||||||
|
CefSharp.ResourceType.Script => ResourceType.Script,
|
||||||
|
CefSharp.ResourceType.Stylesheet => ResourceType.Stylesheet,
|
||||||
|
CefSharp.ResourceType.Xhr => ResourceType.Xhr,
|
||||||
|
CefSharp.ResourceType.Image => ResourceType.Image,
|
||||||
|
_ => ResourceType.Unknown
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
29
Browser/Adapters/CefSchemeHandlerFactory.cs
Normal file
29
Browser/Adapters/CefSchemeHandlerFactory.cs
Normal file
@@ -0,0 +1,29 @@
|
|||||||
|
using System;
|
||||||
|
using CefSharp;
|
||||||
|
using CefSharp.WinForms;
|
||||||
|
using TweetLib.Browser.Interfaces;
|
||||||
|
|
||||||
|
namespace TweetDuck.Browser.Adapters {
|
||||||
|
sealed class CefSchemeHandlerFactory : ISchemeHandlerFactory {
|
||||||
|
public static void Register(CefSettings settings, ICustomSchemeHandler handler) {
|
||||||
|
settings.RegisterScheme(new CefCustomScheme {
|
||||||
|
SchemeName = handler.Protocol,
|
||||||
|
IsStandard = false,
|
||||||
|
IsSecure = true,
|
||||||
|
IsCorsEnabled = true,
|
||||||
|
IsCSPBypassing = true,
|
||||||
|
SchemeHandlerFactory = new CefSchemeHandlerFactory(handler)
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private readonly ICustomSchemeHandler handler;
|
||||||
|
|
||||||
|
private CefSchemeHandlerFactory(ICustomSchemeHandler handler) {
|
||||||
|
this.handler = handler;
|
||||||
|
}
|
||||||
|
|
||||||
|
public IResourceHandler Create(IBrowser browser, IFrame frame, string schemeName, IRequest request) {
|
||||||
|
return Uri.TryCreate(request.Url, UriKind.Absolute, out var uri) ? handler.Resolve(uri)?.Visit(CefSchemeResourceVisitor.Instance) : null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
38
Browser/Adapters/CefSchemeResourceVisitor.cs
Normal file
38
Browser/Adapters/CefSchemeResourceVisitor.cs
Normal file
@@ -0,0 +1,38 @@
|
|||||||
|
using System;
|
||||||
|
using System.IO;
|
||||||
|
using System.Net;
|
||||||
|
using CefSharp;
|
||||||
|
using TweetLib.Browser.Interfaces;
|
||||||
|
using TweetLib.Browser.Request;
|
||||||
|
|
||||||
|
namespace TweetDuck.Browser.Adapters {
|
||||||
|
sealed class CefSchemeResourceVisitor : ISchemeResourceVisitor<IResourceHandler> {
|
||||||
|
public static CefSchemeResourceVisitor Instance { get; } = new CefSchemeResourceVisitor();
|
||||||
|
|
||||||
|
private static readonly SchemeResource.Status FileIsEmpty = new SchemeResource.Status(HttpStatusCode.NoContent, "File is empty.");
|
||||||
|
|
||||||
|
private CefSchemeResourceVisitor() {}
|
||||||
|
|
||||||
|
public IResourceHandler Status(SchemeResource.Status status) {
|
||||||
|
var handler = CreateHandler(Array.Empty<byte>());
|
||||||
|
handler.StatusCode = (int) status.Code;
|
||||||
|
handler.StatusText = status.Message;
|
||||||
|
return handler;
|
||||||
|
}
|
||||||
|
|
||||||
|
public IResourceHandler File(SchemeResource.File file) {
|
||||||
|
byte[] contents = file.Contents;
|
||||||
|
if (contents.Length == 0) {
|
||||||
|
return Status(FileIsEmpty); // FromByteArray crashes CEF internals with no contents
|
||||||
|
}
|
||||||
|
|
||||||
|
var handler = CreateHandler(contents);
|
||||||
|
handler.MimeType = Cef.GetMimeType(file.Extension);
|
||||||
|
return handler;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static ResourceHandler CreateHandler(byte[] bytes) {
|
||||||
|
return ResourceHandler.FromStream(new MemoryStream(bytes), autoDisposeStream: true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,41 +0,0 @@
|
|||||||
using System.IO;
|
|
||||||
using CefSharp;
|
|
||||||
using TweetLib.Core.Browser;
|
|
||||||
|
|
||||||
namespace TweetDuck.Browser.Adapters{
|
|
||||||
sealed class CefScriptExecutor : IScriptExecutor{
|
|
||||||
private readonly IWebBrowser browser;
|
|
||||||
|
|
||||||
public CefScriptExecutor(IWebBrowser browser){
|
|
||||||
this.browser = browser;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void RunFunction(string name, params object[] args){
|
|
||||||
browser.ExecuteScriptAsync(name, args);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void RunScript(string identifier, string script){
|
|
||||||
using IFrame frame = browser.GetMainFrame();
|
|
||||||
RunScript(frame, script, identifier);
|
|
||||||
}
|
|
||||||
|
|
||||||
public bool RunFile(string file){
|
|
||||||
using IFrame frame = browser.GetMainFrame();
|
|
||||||
return RunFile(frame, file);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Helpers
|
|
||||||
|
|
||||||
public static void RunScript(IFrame frame, string script, string identifier){
|
|
||||||
if (script != null){
|
|
||||||
frame.ExecuteJavaScriptAsync(script, identifier, 1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public static bool RunFile(IFrame frame, string file){
|
|
||||||
string script = Program.Resources.Load(file);
|
|
||||||
RunScript(frame, script, "root:" + Path.GetFileNameWithoutExtension(file));
|
|
||||||
return script != null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,38 +0,0 @@
|
|||||||
using System.Text;
|
|
||||||
using TweetDuck.Configuration;
|
|
||||||
using TweetLib.Core;
|
|
||||||
using TweetLib.Core.Utils;
|
|
||||||
|
|
||||||
namespace TweetDuck.Browser.Bridge{
|
|
||||||
static class PropertyBridge{
|
|
||||||
public enum Environment{
|
|
||||||
Browser, Notification
|
|
||||||
}
|
|
||||||
|
|
||||||
public static string GenerateScript(Environment environment){
|
|
||||||
static string Bool(bool value) => value ? "true;" : "false;";
|
|
||||||
static string Str(string value) => $"\"{value}\";";
|
|
||||||
|
|
||||||
UserConfig config = Program.Config.User;
|
|
||||||
StringBuilder build = new StringBuilder(384).Append("(function(x){");
|
|
||||||
|
|
||||||
build.Append("x.expandLinksOnHover=").Append(Bool(config.ExpandLinksOnHover));
|
|
||||||
|
|
||||||
if (environment == Environment.Browser){
|
|
||||||
build.Append("x.focusDmInput=").Append(Bool(config.FocusDmInput));
|
|
||||||
build.Append("x.openSearchInFirstColumn=").Append(Bool(config.OpenSearchInFirstColumn));
|
|
||||||
build.Append("x.keepLikeFollowDialogsOpen=").Append(Bool(config.KeepLikeFollowDialogsOpen));
|
|
||||||
build.Append("x.muteNotifications=").Append(Bool(config.MuteNotifications));
|
|
||||||
build.Append("x.notificationMediaPreviews=").Append(Bool(config.NotificationMediaPreviews));
|
|
||||||
build.Append("x.translationTarget=").Append(Str(config.TranslationTarget));
|
|
||||||
build.Append("x.firstDayOfWeek=").Append(config.CalendarFirstDay == -1 ? LocaleUtils.GetJQueryDayOfWeek(Lib.Culture.DateTimeFormat.FirstDayOfWeek) : config.CalendarFirstDay);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (environment == Environment.Notification){
|
|
||||||
build.Append("x.skipOnLinkClick=").Append(Bool(config.NotificationSkipOnLinkClick));
|
|
||||||
}
|
|
||||||
|
|
||||||
return build.Append("})(window.$TDX=window.$TDX||{});if(window.TDGF_onPropertiesUpdated)window.TDGF_onPropertiesUpdated()").ToString();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,161 +0,0 @@
|
|||||||
using System;
|
|
||||||
using System.Diagnostics.CodeAnalysis;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
using System.Windows.Forms;
|
|
||||||
using CefSharp;
|
|
||||||
using TweetDuck.Browser.Handling;
|
|
||||||
using TweetDuck.Browser.Notification;
|
|
||||||
using TweetDuck.Controls;
|
|
||||||
using TweetDuck.Dialogs;
|
|
||||||
using TweetDuck.Management;
|
|
||||||
using TweetDuck.Utils;
|
|
||||||
using TweetLib.Core.Features.Notifications;
|
|
||||||
using TweetLib.Core.Utils;
|
|
||||||
|
|
||||||
namespace TweetDuck.Browser.Bridge{
|
|
||||||
[SuppressMessage("ReSharper", "UnusedMember.Global")]
|
|
||||||
class TweetDeckBridge{
|
|
||||||
public static void ResetStaticProperties(){
|
|
||||||
FormNotificationBase.FontSize = null;
|
|
||||||
FormNotificationBase.HeadLayout = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
private readonly FormBrowser form;
|
|
||||||
private readonly FormNotificationMain notification;
|
|
||||||
|
|
||||||
protected TweetDeckBridge(FormBrowser form, FormNotificationMain notification){
|
|
||||||
this.form = form;
|
|
||||||
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){
|
|
||||||
form.InvokeAsyncSafe(() => form.OnIntroductionClosed(showGuide, allowDataCollection));
|
|
||||||
}
|
|
||||||
|
|
||||||
public void LoadNotificationLayout(string fontSize, string headLayout){
|
|
||||||
form.InvokeAsyncSafe(() => {
|
|
||||||
FormNotificationBase.FontSize = fontSize;
|
|
||||||
FormNotificationBase.HeadLayout = headLayout;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
public void SetRightClickedLink(string type, string url){
|
|
||||||
ContextMenuBase.CurrentInfo.SetLink(type, url);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void SetRightClickedChirp(string tweetUrl, string quoteUrl, string chirpAuthors, string chirpImages){
|
|
||||||
ContextMenuBase.CurrentInfo.SetChirp(tweetUrl, quoteUrl, chirpAuthors, chirpImages);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void DisplayTooltip(string text){
|
|
||||||
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){
|
|
||||||
notification.InvokeAsyncSafe(() => {
|
|
||||||
form.OnTweetNotification();
|
|
||||||
notification.ShowNotification(new DesktopNotification(columnId, chirpId, columnName, tweetHtml, tweetCharacters, tweetUrl, quoteUrl));
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
public void OnTweetSound(){
|
|
||||||
form.InvokeAsyncSafe(() => {
|
|
||||||
form.OnTweetNotification();
|
|
||||||
form.OnTweetSound();
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
public void ScreenshotTweet(string html, int width){
|
|
||||||
form.InvokeAsyncSafe(() => form.OnTweetScreenshotReady(html, width));
|
|
||||||
}
|
|
||||||
|
|
||||||
public void PlayVideo(string videoUrl, string tweetUrl, string username, IJavascriptCallback callShowOverlay){
|
|
||||||
form.InvokeAsyncSafe(() => form.PlayVideo(videoUrl, tweetUrl, username, callShowOverlay));
|
|
||||||
}
|
|
||||||
|
|
||||||
public void StopVideo(){
|
|
||||||
form.InvokeAsyncSafe(form.StopVideo);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void FixClipboard(){
|
|
||||||
form.InvokeAsyncSafe(ClipboardManager.StripHtmlStyles);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void OpenBrowser(string url){
|
|
||||||
form.InvokeAsyncSafe(() => BrowserUtils.OpenExternalBrowser(url));
|
|
||||||
}
|
|
||||||
|
|
||||||
public void MakeGetRequest(string url, IJavascriptCallback onSuccess, IJavascriptCallback onError){
|
|
||||||
Task.Run(async () => {
|
|
||||||
var client = WebUtils.NewClient(BrowserUtils.UserAgentVanilla);
|
|
||||||
|
|
||||||
try{
|
|
||||||
var result = await client.DownloadStringTaskAsync(url);
|
|
||||||
await onSuccess.ExecuteAsync(result);
|
|
||||||
}catch(Exception e){
|
|
||||||
await onError.ExecuteAsync(e.Message);
|
|
||||||
}finally{
|
|
||||||
onSuccess.Dispose();
|
|
||||||
onError.Dispose();
|
|
||||||
client.Dispose();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
public int GetIdleSeconds(){
|
|
||||||
return NativeMethods.GetIdleSeconds();
|
|
||||||
}
|
|
||||||
|
|
||||||
public void Alert(string type, string contents){
|
|
||||||
MessageBoxIcon icon = type switch{
|
|
||||||
"error" => MessageBoxIcon.Error,
|
|
||||||
"warning" => MessageBoxIcon.Warning,
|
|
||||||
"info" => MessageBoxIcon.Information,
|
|
||||||
_ => MessageBoxIcon.None
|
|
||||||
};
|
|
||||||
|
|
||||||
FormMessage.Show("TweetDuck Browser Message", contents, icon, FormMessage.OK);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void CrashDebug(string message){
|
|
||||||
#if DEBUG
|
|
||||||
System.Diagnostics.Debug.WriteLine(message);
|
|
||||||
System.Diagnostics.Debugger.Break();
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,65 +0,0 @@
|
|||||||
using System;
|
|
||||||
using System.Diagnostics.CodeAnalysis;
|
|
||||||
using System.Windows.Forms;
|
|
||||||
using TweetDuck.Controls;
|
|
||||||
using TweetLib.Core.Features.Updates;
|
|
||||||
|
|
||||||
namespace TweetDuck.Browser.Bridge{
|
|
||||||
[SuppressMessage("ReSharper", "UnusedMember.Global")]
|
|
||||||
class UpdateBridge{
|
|
||||||
private readonly UpdateHandler updates;
|
|
||||||
private readonly Control sync;
|
|
||||||
|
|
||||||
private UpdateInfo nextUpdate = null;
|
|
||||||
|
|
||||||
public event EventHandler<UpdateInfo> UpdateAccepted;
|
|
||||||
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 OnUpdateDismissed(){
|
|
||||||
HandleInteractionEvent(UpdateDismissed);
|
|
||||||
|
|
||||||
nextUpdate?.DeleteInstaller();
|
|
||||||
nextUpdate = null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,161 +0,0 @@
|
|||||||
using System;
|
|
||||||
using CefSharp;
|
|
||||||
using TweetLib.Core.Utils;
|
|
||||||
|
|
||||||
namespace TweetDuck.Browser.Data{
|
|
||||||
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;
|
|
||||||
|
|
||||||
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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,13 +0,0 @@
|
|||||||
using CefSharp;
|
|
||||||
|
|
||||||
namespace TweetDuck.Browser.Data{
|
|
||||||
sealed class ResourceLink{
|
|
||||||
public string Url { get; }
|
|
||||||
public IResourceHandler Handler { get; }
|
|
||||||
|
|
||||||
public ResourceLink(string url, IResourceHandler handler){
|
|
||||||
this.Url = url;
|
|
||||||
this.Handler = handler;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,42 +0,0 @@
|
|||||||
using System.Drawing;
|
|
||||||
using System.Windows.Forms;
|
|
||||||
using TweetDuck.Controls;
|
|
||||||
using TweetLib.Core.Serialization.Converters;
|
|
||||||
using TweetLib.Core.Utils;
|
|
||||||
|
|
||||||
namespace TweetDuck.Browser.Data{
|
|
||||||
sealed class WindowState{
|
|
||||||
private Rectangle rect;
|
|
||||||
private bool isMaximized;
|
|
||||||
|
|
||||||
public void Save(Form form){
|
|
||||||
rect = form.WindowState == FormWindowState.Normal ? form.DesktopBounds : form.RestoreBounds;
|
|
||||||
isMaximized = form.WindowState == FormWindowState.Maximized;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void Restore(Form form, bool firstTimeFullscreen){
|
|
||||||
if (rect != Rectangle.Empty){
|
|
||||||
form.DesktopBounds = rect;
|
|
||||||
form.WindowState = isMaximized ? FormWindowState.Maximized : FormWindowState.Normal;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ((rect == Rectangle.Empty && firstTimeFullscreen) || form.IsFullyOutsideView()){
|
|
||||||
form.DesktopBounds = Screen.PrimaryScreen.WorkingArea;
|
|
||||||
form.WindowState = FormWindowState.Maximized;
|
|
||||||
Save(form);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public static readonly SingleTypeConverter<WindowState> Converter = new SingleTypeConverter<WindowState>{
|
|
||||||
ConvertToString = value => $"{(value.isMaximized ? 'M' : '_')}{value.rect.X} {value.rect.Y} {value.rect.Width} {value.rect.Height}",
|
|
||||||
ConvertToObject = value => {
|
|
||||||
int[] elements = StringUtils.ParseInts(value.Substring(1), ' ');
|
|
||||||
|
|
||||||
return new WindowState{
|
|
||||||
rect = new Rectangle(elements[0], elements[1], elements[2], elements[3]),
|
|
||||||
isMaximized = value[0] == 'M'
|
|
||||||
};
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
2
Browser/FormBrowser.Designer.cs
generated
2
Browser/FormBrowser.Designer.cs
generated
@@ -27,7 +27,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.BackColor = TweetDuck.Utils.TwitterUtils.BackgroundColor;
|
this.BackColor = TweetDuck.Browser.TweetDeckBrowser.BackgroundColor;
|
||||||
this.ClientSize = new System.Drawing.Size(1008, 730);
|
this.ClientSize = new System.Drawing.Size(1008, 730);
|
||||||
this.Icon = Properties.Resources.icon;
|
this.Icon = Properties.Resources.icon;
|
||||||
this.Location = TweetDuck.Controls.ControlExtensions.InvisibleLocation;
|
this.Location = TweetDuck.Controls.ControlExtensions.InvisibleLocation;
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
28
Browser/Handling/BrowserProcessHandler.cs
Normal file
28
Browser/Handling/BrowserProcessHandler.cs
Normal file
@@ -0,0 +1,28 @@
|
|||||||
|
using System;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using CefSharp;
|
||||||
|
using TweetDuck.Configuration;
|
||||||
|
|
||||||
|
namespace TweetDuck.Browser.Handling {
|
||||||
|
sealed class BrowserProcessHandler : IBrowserProcessHandler {
|
||||||
|
public static Task UpdatePrefs() {
|
||||||
|
return Cef.UIThreadTaskFactory.StartNew(UpdatePrefsInternal);
|
||||||
|
}
|
||||||
|
|
||||||
|
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 IDisposable.Dispose() {}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,244 +1,109 @@
|
|||||||
using System;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Drawing;
|
||||||
using System.Text.RegularExpressions;
|
|
||||||
using System.Windows.Forms;
|
|
||||||
using CefSharp;
|
using CefSharp;
|
||||||
using TweetDuck.Browser.Adapters;
|
using TweetDuck.Browser.Adapters;
|
||||||
using TweetDuck.Browser.Data;
|
|
||||||
using TweetDuck.Browser.Notification;
|
|
||||||
using TweetDuck.Configuration;
|
using TweetDuck.Configuration;
|
||||||
using TweetDuck.Controls;
|
|
||||||
using TweetDuck.Dialogs;
|
|
||||||
using TweetDuck.Management;
|
|
||||||
using TweetDuck.Management.Analytics;
|
|
||||||
using TweetDuck.Utils;
|
using TweetDuck.Utils;
|
||||||
using TweetLib.Core.Features.Twitter;
|
using TweetLib.Browser.Contexts;
|
||||||
using TweetLib.Core.Utils;
|
|
||||||
|
|
||||||
namespace TweetDuck.Browser.Handling{
|
namespace TweetDuck.Browser.Handling {
|
||||||
abstract class ContextMenuBase : IContextMenuHandler{
|
abstract class ContextMenuBase : IContextMenuHandler {
|
||||||
public static ContextInfo CurrentInfo { get; } = new ContextInfo();
|
private const CefMenuCommand MenuOpenDevTools = (CefMenuCommand) 26500;
|
||||||
|
|
||||||
protected static UserConfig Config => Program.Config.User;
|
private static readonly HashSet<CefMenuCommand> AllowedCefCommands = new HashSet<CefMenuCommand> {
|
||||||
private static ImageQuality ImageQuality => Config.TwitterImageQuality;
|
CefMenuCommand.NotFound,
|
||||||
|
CefMenuCommand.Undo,
|
||||||
private const CefMenuCommand MenuOpenLinkUrl = (CefMenuCommand)26500;
|
CefMenuCommand.Redo,
|
||||||
private const CefMenuCommand MenuCopyLinkUrl = (CefMenuCommand)26501;
|
CefMenuCommand.Cut,
|
||||||
private const CefMenuCommand MenuCopyUsername = (CefMenuCommand)26502;
|
CefMenuCommand.Copy,
|
||||||
private const CefMenuCommand MenuViewImage = (CefMenuCommand)26503;
|
CefMenuCommand.Paste,
|
||||||
private const CefMenuCommand MenuOpenMediaUrl = (CefMenuCommand)26504;
|
CefMenuCommand.Delete,
|
||||||
private const CefMenuCommand MenuCopyMediaUrl = (CefMenuCommand)26505;
|
CefMenuCommand.SelectAll,
|
||||||
private const CefMenuCommand MenuCopyImage = (CefMenuCommand)26506;
|
CefMenuCommand.SpellCheckSuggestion0,
|
||||||
private const CefMenuCommand MenuSaveMedia = (CefMenuCommand)26507;
|
CefMenuCommand.SpellCheckSuggestion1,
|
||||||
private const CefMenuCommand MenuSaveTweetImages = (CefMenuCommand)26508;
|
CefMenuCommand.SpellCheckSuggestion2,
|
||||||
private const CefMenuCommand MenuSearchInBrowser = (CefMenuCommand)26509;
|
CefMenuCommand.SpellCheckSuggestion3,
|
||||||
private const CefMenuCommand MenuReadApplyROT13 = (CefMenuCommand)26510;
|
CefMenuCommand.SpellCheckSuggestion4,
|
||||||
private const CefMenuCommand MenuOpenDevTools = (CefMenuCommand)26599;
|
CefMenuCommand.SpellCheckNoSuggestions,
|
||||||
|
CefMenuCommand.AddToDictionary
|
||||||
protected ContextInfo.ContextData Context { get; private set; }
|
};
|
||||||
|
|
||||||
private readonly AnalyticsFile.IProvider analytics;
|
protected static UserConfig Config => Program.Config.User;
|
||||||
|
|
||||||
protected ContextMenuBase(AnalyticsFile.IProvider analytics){
|
private readonly TweetLib.Browser.Interfaces.IContextMenuHandler handler;
|
||||||
this.analytics = analytics;
|
private readonly CefContextMenuActionRegistry actionRegistry;
|
||||||
}
|
|
||||||
|
|
||||||
public virtual void OnBeforeContextMenu(IWebBrowser browserControl, IBrowser browser, IFrame frame, IContextMenuParams parameters, IMenuModel model){
|
protected ContextMenuBase(TweetLib.Browser.Interfaces.IContextMenuHandler handler) {
|
||||||
if (!TwitterUrls.IsTweetDeck(frame.Url) || browser.IsLoading){
|
this.handler = handler;
|
||||||
Context = CurrentInfo.Reset();
|
this.actionRegistry = new CefContextMenuActionRegistry();
|
||||||
}
|
}
|
||||||
else{
|
|
||||||
Context = CurrentInfo.Create(parameters);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (parameters.TypeFlags.HasFlag(ContextMenuType.Selection) && !parameters.TypeFlags.HasFlag(ContextMenuType.Editable)){
|
|
||||||
model.AddItem(MenuSearchInBrowser, "Search in browser");
|
|
||||||
model.AddSeparator();
|
|
||||||
model.AddItem(MenuReadApplyROT13, "Apply ROT13");
|
|
||||||
model.AddSeparator();
|
|
||||||
}
|
|
||||||
|
|
||||||
static string TextOpen(string name) => "Open " + name + " in browser";
|
protected virtual Context CreateContext(IContextMenuParams parameters) {
|
||||||
static string TextCopy(string name) => "Copy " + name + " address";
|
return CefContextMenuModel.CreateContext(parameters, null, Config.TwitterImageQuality);
|
||||||
static string TextSave(string name) => "Save " + name + " as...";
|
}
|
||||||
|
|
||||||
if (Context.Types.HasFlag(ContextInfo.ContextType.Link) && !Context.UnsafeLinkUrl.EndsWith("tweetdeck.twitter.com/#", StringComparison.Ordinal)){
|
|
||||||
if (TwitterUrls.RegexAccount.IsMatch(Context.UnsafeLinkUrl)){
|
|
||||||
model.AddItem(MenuOpenLinkUrl, TextOpen("account"));
|
|
||||||
model.AddItem(MenuCopyLinkUrl, TextCopy("account"));
|
|
||||||
model.AddItem(MenuCopyUsername, "Copy account username");
|
|
||||||
}
|
|
||||||
else{
|
|
||||||
model.AddItem(MenuOpenLinkUrl, TextOpen("link"));
|
|
||||||
model.AddItem(MenuCopyLinkUrl, TextCopy("link"));
|
|
||||||
}
|
|
||||||
|
|
||||||
model.AddSeparator();
|
public virtual void OnBeforeContextMenu(IWebBrowser browserControl, IBrowser browser, IFrame frame, IContextMenuParams parameters, IMenuModel model) {
|
||||||
}
|
for (int i = model.Count - 1; i >= 0; i--) {
|
||||||
|
CefMenuCommand command = model.GetCommandIdAt(i);
|
||||||
|
|
||||||
if (Context.Types.HasFlag(ContextInfo.ContextType.Video)){
|
if (!AllowedCefCommands.Contains(command) && !(command >= CefMenuCommand.CustomFirst && command <= CefMenuCommand.CustomLast)) {
|
||||||
model.AddItem(MenuOpenMediaUrl, TextOpen("video"));
|
model.RemoveAt(i);
|
||||||
model.AddItem(MenuCopyMediaUrl, TextCopy("video"));
|
}
|
||||||
model.AddItem(MenuSaveMedia, TextSave("video"));
|
}
|
||||||
model.AddSeparator();
|
|
||||||
}
|
|
||||||
else if (Context.Types.HasFlag(ContextInfo.ContextType.Image) && Context.MediaUrl != FormNotificationBase.AppLogo.Url){
|
|
||||||
model.AddItem(MenuViewImage, "View image in photo viewer");
|
|
||||||
model.AddItem(MenuOpenMediaUrl, TextOpen("image"));
|
|
||||||
model.AddItem(MenuCopyMediaUrl, TextCopy("image"));
|
|
||||||
model.AddItem(MenuCopyImage, "Copy image");
|
|
||||||
model.AddItem(MenuSaveMedia, TextSave("image"));
|
|
||||||
|
|
||||||
if (Context.Chirp.Images.Length > 1){
|
for (int i = model.Count - 2; i >= 0; i--) {
|
||||||
model.AddItem(MenuSaveTweetImages, TextSave("all images"));
|
if (model.GetTypeAt(i) == MenuItemType.Separator && model.GetTypeAt(i + 1) == MenuItemType.Separator) {
|
||||||
}
|
model.RemoveAt(i);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
model.AddSeparator();
|
if (model.Count > 0 && model.GetTypeAt(0) == MenuItemType.Separator) {
|
||||||
}
|
model.RemoveAt(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
public virtual bool OnContextMenuCommand(IWebBrowser browserControl, IBrowser browser, IFrame frame, IContextMenuParams parameters, CefMenuCommand commandId, CefEventFlags eventFlags){
|
AddSeparator(model);
|
||||||
Control control = browserControl.AsControl();
|
handler.Show(new CefContextMenuModel(model, actionRegistry), CreateContext(parameters));
|
||||||
|
RemoveSeparatorIfLast(model);
|
||||||
|
}
|
||||||
|
|
||||||
switch(commandId){
|
public virtual bool OnContextMenuCommand(IWebBrowser browserControl, IBrowser browser, IFrame frame, IContextMenuParams parameters, CefMenuCommand commandId, CefEventFlags eventFlags) {
|
||||||
case MenuOpenLinkUrl:
|
if (actionRegistry.Execute(commandId)) {
|
||||||
OpenBrowser(control, Context.LinkUrl);
|
return true;
|
||||||
break;
|
}
|
||||||
|
|
||||||
case MenuCopyLinkUrl:
|
if (commandId == MenuOpenDevTools) {
|
||||||
SetClipboardText(control, Context.UnsafeLinkUrl);
|
browserControl.OpenDevToolsCustom(new Point(parameters.XCoord, parameters.YCoord));
|
||||||
break;
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
case MenuCopyUsername: {
|
return false;
|
||||||
string url = Context.UnsafeLinkUrl;
|
}
|
||||||
Match match = TwitterUrls.RegexAccount.Match(url);
|
|
||||||
|
|
||||||
SetClipboardText(control, match.Success ? match.Groups[1].Value : url);
|
public virtual void OnContextMenuDismissed(IWebBrowser browserControl, IBrowser browser, IFrame frame) {
|
||||||
control.InvokeAsyncSafe(analytics.AnalyticsFile.CopiedUsernames.Trigger);
|
actionRegistry.Clear();
|
||||||
break;
|
}
|
||||||
}
|
|
||||||
|
|
||||||
case MenuOpenMediaUrl:
|
public virtual bool RunContextMenu(IWebBrowser browserControl, IBrowser browser, IFrame frame, IContextMenuParams parameters, IMenuModel model, IRunContextMenuCallback callback) {
|
||||||
OpenBrowser(control, TwitterUrls.GetMediaLink(Context.MediaUrl, ImageQuality));
|
return false;
|
||||||
break;
|
}
|
||||||
|
|
||||||
case MenuCopyMediaUrl:
|
protected static void AddDebugMenuItems(IMenuModel model) {
|
||||||
SetClipboardText(control, TwitterUrls.GetMediaLink(Context.MediaUrl, ImageQuality));
|
if (Config.DevToolsInContextMenu) {
|
||||||
break;
|
AddSeparator(model);
|
||||||
|
model.AddItem(MenuOpenDevTools, "Open dev tools");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
case MenuCopyImage: {
|
protected static void RemoveSeparatorIfLast(IMenuModel model) {
|
||||||
string url = Context.MediaUrl;
|
if (model.Count > 0 && model.GetTypeAt(model.Count - 1) == MenuItemType.Separator) {
|
||||||
|
model.RemoveAt(model.Count - 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
control.InvokeAsyncSafe(() => {
|
protected static void AddSeparator(IMenuModel model) {
|
||||||
TwitterUtils.CopyImage(url, ImageQuality);
|
if (model.Count > 0 && model.GetTypeAt(model.Count - 1) != MenuItemType.Separator) { // do not add separators if there is nothing to separate
|
||||||
});
|
model.AddSeparator();
|
||||||
|
}
|
||||||
break;
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
case MenuViewImage: {
|
|
||||||
string url = Context.MediaUrl;
|
|
||||||
|
|
||||||
control.InvokeAsyncSafe(() => {
|
|
||||||
TwitterUtils.ViewImage(url, ImageQuality);
|
|
||||||
analytics.AnalyticsFile.ViewedImages.Trigger();
|
|
||||||
});
|
|
||||||
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
case MenuSaveMedia: {
|
|
||||||
bool isVideo = Context.Types.HasFlag(ContextInfo.ContextType.Video);
|
|
||||||
string url = Context.MediaUrl;
|
|
||||||
string username = Context.Chirp.Authors.LastOrDefault();
|
|
||||||
|
|
||||||
control.InvokeAsyncSafe(() => {
|
|
||||||
if (isVideo){
|
|
||||||
TwitterUtils.DownloadVideo(url, username);
|
|
||||||
analytics.AnalyticsFile.DownloadedVideos.Trigger();
|
|
||||||
}
|
|
||||||
else{
|
|
||||||
TwitterUtils.DownloadImage(url, username, ImageQuality);
|
|
||||||
analytics.AnalyticsFile.DownloadedImages.Trigger();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
case MenuSaveTweetImages: {
|
|
||||||
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;
|
|
||||||
|
|
||||||
case MenuOpenDevTools:
|
|
||||||
browserControl.OpenDevToolsCustom();
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
public virtual void OnContextMenuDismissed(IWebBrowser browserControl, IBrowser browser, IFrame frame){
|
|
||||||
Context = CurrentInfo.Reset();
|
|
||||||
}
|
|
||||||
|
|
||||||
public virtual bool RunContextMenu(IWebBrowser browserControl, IBrowser browser, IFrame frame, IContextMenuParams parameters, IMenuModel model, IRunContextMenuCallback callback){
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected static void DeselectAll(IFrame frame){
|
|
||||||
CefScriptExecutor.RunScript(frame, "window.getSelection().removeAllRanges()", "gen:deselect");
|
|
||||||
}
|
|
||||||
|
|
||||||
protected static void OpenBrowser(Control control, string url){
|
|
||||||
control.InvokeAsyncSafe(() => BrowserUtils.OpenExternalBrowser(url));
|
|
||||||
}
|
|
||||||
|
|
||||||
protected static void SetClipboardText(Control control, string text){
|
|
||||||
control.InvokeAsyncSafe(() => ClipboardManager.SetText(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){
|
|
||||||
if (BrowserUtils.HasDevTools){
|
|
||||||
AddSeparator(model);
|
|
||||||
model.AddItem(MenuOpenDevTools, "Open dev tools");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
protected static void RemoveSeparatorIfLast(IMenuModel model){
|
|
||||||
if (model.Count > 0 && model.GetTypeAt(model.Count - 1) == MenuItemType.Separator){
|
|
||||||
model.RemoveAt(model.Count - 1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
protected static void AddSeparator(IMenuModel model){
|
|
||||||
if (model.Count > 0 && model.GetTypeAt(model.Count - 1) != MenuItemType.Separator){ // do not add separators if there is nothing to separate
|
|
||||||
model.AddSeparator();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,179 +1,123 @@
|
|||||||
using System.Windows.Forms;
|
using System.Windows.Forms;
|
||||||
using CefSharp;
|
using CefSharp;
|
||||||
using TweetDuck.Browser.Data;
|
using TweetDuck.Browser.Adapters;
|
||||||
using TweetDuck.Controls;
|
using TweetDuck.Controls;
|
||||||
|
using TweetLib.Browser.Contexts;
|
||||||
|
using TweetLib.Core.Features.TweetDeck;
|
||||||
using TweetLib.Core.Features.Twitter;
|
using TweetLib.Core.Features.Twitter;
|
||||||
|
using TweetLib.Core.Systems.Configuration;
|
||||||
|
using IContextMenuHandler = TweetLib.Browser.Interfaces.IContextMenuHandler;
|
||||||
|
|
||||||
namespace TweetDuck.Browser.Handling{
|
namespace TweetDuck.Browser.Handling {
|
||||||
sealed class ContextMenuBrowser : ContextMenuBase{
|
sealed class ContextMenuBrowser : ContextMenuBase {
|
||||||
private const CefMenuCommand MenuGlobal = (CefMenuCommand)26600;
|
private const CefMenuCommand MenuGlobal = (CefMenuCommand) 26600;
|
||||||
private const CefMenuCommand MenuMute = (CefMenuCommand)26601;
|
private const CefMenuCommand MenuMute = (CefMenuCommand) 26601;
|
||||||
private const CefMenuCommand MenuSettings = (CefMenuCommand)26602;
|
private const CefMenuCommand MenuSettings = (CefMenuCommand) 26602;
|
||||||
private const CefMenuCommand MenuPlugins = (CefMenuCommand)26003;
|
private const CefMenuCommand MenuPlugins = (CefMenuCommand) 26003;
|
||||||
private const CefMenuCommand MenuAbout = (CefMenuCommand)26604;
|
private const CefMenuCommand MenuAbout = (CefMenuCommand) 26604;
|
||||||
|
|
||||||
private const CefMenuCommand MenuOpenTweetUrl = (CefMenuCommand)26610;
|
|
||||||
private const CefMenuCommand MenuCopyTweetUrl = (CefMenuCommand)26611;
|
|
||||||
private const CefMenuCommand MenuOpenQuotedTweetUrl = (CefMenuCommand)26612;
|
|
||||||
private const CefMenuCommand MenuCopyQuotedTweetUrl = (CefMenuCommand)26613;
|
|
||||||
private const CefMenuCommand MenuScreenshotTweet = (CefMenuCommand)26614;
|
|
||||||
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";
|
||||||
private const string TitleSettings = "Options";
|
private const string TitleSettings = "Options";
|
||||||
private const string TitlePlugins = "Plugins";
|
private const string TitlePlugins = "Plugins";
|
||||||
private const string TitleAboutProgram = "About " + Program.BrandName;
|
private const string TitleAboutProgram = "About " + Program.BrandName;
|
||||||
|
|
||||||
private readonly FormBrowser form;
|
private readonly FormBrowser form;
|
||||||
|
private readonly TweetDeckExtraContext extraContext;
|
||||||
public ContextMenuBrowser(FormBrowser form) : base(form){
|
|
||||||
this.form = form;
|
|
||||||
}
|
|
||||||
|
|
||||||
public override void OnBeforeContextMenu(IWebBrowser browserControl, IBrowser browser, IFrame frame, IContextMenuParams parameters, IMenuModel model){
|
public ContextMenuBrowser(FormBrowser form, IContextMenuHandler handler, TweetDeckExtraContext extraContext) : base(handler) {
|
||||||
bool isSelecting = parameters.TypeFlags.HasFlag(ContextMenuType.Selection);
|
this.form = form;
|
||||||
bool isEditing = parameters.TypeFlags.HasFlag(ContextMenuType.Editable);
|
this.extraContext = extraContext;
|
||||||
|
}
|
||||||
|
|
||||||
model.Remove(CefMenuCommand.Back);
|
protected override Context CreateContext(IContextMenuParams parameters) {
|
||||||
model.Remove(CefMenuCommand.Forward);
|
return CefContextMenuModel.CreateContext(parameters, extraContext, Config.TwitterImageQuality);
|
||||||
model.Remove(CefMenuCommand.Print);
|
}
|
||||||
model.Remove(CefMenuCommand.ViewSource);
|
|
||||||
RemoveSeparatorIfLast(model);
|
|
||||||
|
|
||||||
if (isSelecting){
|
public override void OnBeforeContextMenu(IWebBrowser browserControl, IBrowser browser, IFrame frame, IContextMenuParams parameters, IMenuModel model) {
|
||||||
if (isEditing){
|
if (!TwitterUrls.IsTweetDeck(frame.Url) || browser.IsLoading) {
|
||||||
model.AddSeparator();
|
extraContext.Reset();
|
||||||
model.AddItem(MenuWriteApplyROT13, "Apply ROT13");
|
}
|
||||||
}
|
|
||||||
|
|
||||||
model.AddSeparator();
|
base.OnBeforeContextMenu(browserControl, browser, frame, parameters, model);
|
||||||
}
|
|
||||||
|
|
||||||
base.OnBeforeContextMenu(browserControl, browser, frame, parameters, model);
|
bool isSelecting = parameters.TypeFlags.HasFlag(ContextMenuType.Selection);
|
||||||
|
bool isEditing = parameters.TypeFlags.HasFlag(ContextMenuType.Editable);
|
||||||
|
|
||||||
if (isSelecting && !isEditing && TwitterUrls.IsTweetDeck(frame.Url)){
|
if (!isSelecting && !isEditing) {
|
||||||
InsertSelectionSearchItem(model, MenuSearchInColumn, "Search in a column");
|
AddSeparator(model);
|
||||||
}
|
|
||||||
|
|
||||||
if (Context.Types.HasFlag(ContextInfo.ContextType.Chirp) && !isSelecting && !isEditing){
|
IMenuModel globalMenu = model.Count == 0 ? model : model.AddSubMenu(MenuGlobal, Program.BrandName);
|
||||||
model.AddItem(MenuOpenTweetUrl, "Open tweet in browser");
|
|
||||||
model.AddItem(MenuCopyTweetUrl, "Copy tweet address");
|
|
||||||
model.AddItem(MenuScreenshotTweet, "Screenshot tweet to clipboard");
|
|
||||||
|
|
||||||
if (!string.IsNullOrEmpty(Context.Chirp.QuoteUrl)){
|
globalMenu.AddItem(CefMenuCommand.Reload, TitleReloadBrowser);
|
||||||
model.AddSeparator();
|
globalMenu.AddCheckItem(MenuMute, TitleMuteNotifications);
|
||||||
model.AddItem(MenuOpenQuotedTweetUrl, "Open quoted tweet in browser");
|
globalMenu.SetChecked(MenuMute, Config.MuteNotifications);
|
||||||
model.AddItem(MenuCopyQuotedTweetUrl, "Copy quoted tweet address");
|
globalMenu.AddSeparator();
|
||||||
}
|
|
||||||
|
|
||||||
model.AddSeparator();
|
globalMenu.AddItem(MenuSettings, TitleSettings);
|
||||||
}
|
globalMenu.AddItem(MenuPlugins, TitlePlugins);
|
||||||
|
globalMenu.AddItem(MenuAbout, TitleAboutProgram);
|
||||||
|
|
||||||
if (!isSelecting && !isEditing){
|
AddDebugMenuItems(globalMenu);
|
||||||
AddSeparator(model);
|
}
|
||||||
|
}
|
||||||
|
|
||||||
IMenuModel globalMenu = model.Count == 0 ? model : model.AddSubMenu(MenuGlobal, Program.BrandName);
|
public override bool OnContextMenuCommand(IWebBrowser browserControl, IBrowser browser, IFrame frame, IContextMenuParams parameters, CefMenuCommand commandId, CefEventFlags eventFlags) {
|
||||||
|
if (base.OnContextMenuCommand(browserControl, browser, frame, parameters, commandId, eventFlags)) {
|
||||||
globalMenu.AddItem(CefMenuCommand.Reload, TitleReloadBrowser);
|
return true;
|
||||||
globalMenu.AddCheckItem(MenuMute, TitleMuteNotifications);
|
}
|
||||||
globalMenu.SetChecked(MenuMute, Config.MuteNotifications);
|
|
||||||
globalMenu.AddSeparator();
|
|
||||||
|
|
||||||
globalMenu.AddItem(MenuSettings, TitleSettings);
|
switch (commandId) {
|
||||||
globalMenu.AddItem(MenuPlugins, TitlePlugins);
|
case CefMenuCommand.Reload:
|
||||||
globalMenu.AddItem(MenuAbout, TitleAboutProgram);
|
form.InvokeAsyncSafe(form.ReloadToTweetDeck);
|
||||||
|
return true;
|
||||||
AddDebugMenuItems(globalMenu);
|
|
||||||
}
|
|
||||||
|
|
||||||
RemoveSeparatorIfLast(model);
|
case MenuSettings:
|
||||||
|
form.InvokeAsyncSafe(form.OpenSettings);
|
||||||
form.InvokeAsyncSafe(form.AnalyticsFile.BrowserContextMenus.Trigger);
|
return true;
|
||||||
}
|
|
||||||
|
|
||||||
public override bool OnContextMenuCommand(IWebBrowser browserControl, IBrowser browser, IFrame frame, IContextMenuParams parameters, CefMenuCommand commandId, CefEventFlags eventFlags){
|
case MenuAbout:
|
||||||
if (base.OnContextMenuCommand(browserControl, browser, frame, parameters, commandId, eventFlags)){
|
form.InvokeAsyncSafe(form.OpenAbout);
|
||||||
return true;
|
return true;
|
||||||
}
|
|
||||||
|
|
||||||
switch(commandId){
|
case MenuPlugins:
|
||||||
case CefMenuCommand.Reload:
|
form.InvokeAsyncSafe(form.OpenPlugins);
|
||||||
form.InvokeAsyncSafe(form.ReloadToTweetDeck);
|
return true;
|
||||||
return true;
|
|
||||||
|
|
||||||
case MenuSettings:
|
case MenuMute:
|
||||||
form.InvokeAsyncSafe(form.OpenSettings);
|
form.InvokeAsyncSafe(ToggleMuteNotifications);
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
case MenuAbout:
|
default:
|
||||||
form.InvokeAsyncSafe(form.OpenAbout);
|
return false;
|
||||||
return true;
|
}
|
||||||
|
}
|
||||||
|
|
||||||
case MenuPlugins:
|
public override void OnContextMenuDismissed(IWebBrowser browserControl, IBrowser browser, IFrame frame) {
|
||||||
form.InvokeAsyncSafe(form.OpenPlugins);
|
base.OnContextMenuDismissed(browserControl, browser, frame);
|
||||||
return true;
|
extraContext.Reset();
|
||||||
|
}
|
||||||
|
|
||||||
case MenuMute:
|
public static ContextMenu CreateMenu(FormBrowser form) {
|
||||||
form.InvokeAsyncSafe(ToggleMuteNotifications);
|
ContextMenu menu = new ContextMenu();
|
||||||
return true;
|
|
||||||
|
|
||||||
case MenuOpenTweetUrl:
|
menu.MenuItems.Add(TitleReloadBrowser, (sender, args) => form.ReloadToTweetDeck());
|
||||||
OpenBrowser(form, Context.Chirp.TweetUrl);
|
menu.MenuItems.Add(TitleMuteNotifications, (sender, args) => ToggleMuteNotifications());
|
||||||
return true;
|
menu.MenuItems.Add("-");
|
||||||
|
menu.MenuItems.Add(TitleSettings, (sender, args) => form.OpenSettings());
|
||||||
|
menu.MenuItems.Add(TitlePlugins, (sender, args) => form.OpenPlugins());
|
||||||
|
menu.MenuItems.Add(TitleAboutProgram, (sender, args) => form.OpenAbout());
|
||||||
|
|
||||||
case MenuCopyTweetUrl:
|
menu.Popup += (sender, args) => {
|
||||||
SetClipboardText(form, Context.Chirp.TweetUrl);
|
menu.MenuItems[1].Checked = Config.MuteNotifications;
|
||||||
return true;
|
};
|
||||||
|
|
||||||
case MenuScreenshotTweet:
|
return menu;
|
||||||
form.InvokeAsyncSafe(form.TriggerTweetScreenshot);
|
}
|
||||||
return true;
|
|
||||||
|
|
||||||
case MenuOpenQuotedTweetUrl:
|
private static void ToggleMuteNotifications() {
|
||||||
OpenBrowser(form, Context.Chirp.QuoteUrl);
|
Config.MuteNotifications = !Config.MuteNotifications;
|
||||||
return true;
|
Config.Save();
|
||||||
|
}
|
||||||
case MenuCopyQuotedTweetUrl:
|
}
|
||||||
SetClipboardText(form, Context.Chirp.QuoteUrl);
|
|
||||||
return true;
|
|
||||||
|
|
||||||
case MenuWriteApplyROT13:
|
|
||||||
form.InvokeAsyncSafe(form.ApplyROT13);
|
|
||||||
return true;
|
|
||||||
|
|
||||||
case MenuSearchInColumn:
|
|
||||||
string query = parameters.SelectionText;
|
|
||||||
form.InvokeAsyncSafe(() => form.AddSearchColumn(query));
|
|
||||||
DeselectAll(frame);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static ContextMenu CreateMenu(FormBrowser form){
|
|
||||||
ContextMenu menu = new ContextMenu();
|
|
||||||
|
|
||||||
menu.MenuItems.Add(TitleReloadBrowser, (sender, args) => form.ReloadToTweetDeck());
|
|
||||||
menu.MenuItems.Add(TitleMuteNotifications, (sender, args) => ToggleMuteNotifications());
|
|
||||||
menu.MenuItems.Add("-");
|
|
||||||
menu.MenuItems.Add(TitleSettings, (sender, args) => form.OpenSettings());
|
|
||||||
menu.MenuItems.Add(TitlePlugins, (sender, args) => form.OpenPlugins());
|
|
||||||
menu.MenuItems.Add(TitleAboutProgram, (sender, args) => form.OpenAbout());
|
|
||||||
|
|
||||||
menu.Popup += (sender, args) => {
|
|
||||||
menu.MenuItems[1].Checked = Config.MuteNotifications;
|
|
||||||
form.AnalyticsFile.BrowserContextMenus.Trigger();
|
|
||||||
};
|
|
||||||
|
|
||||||
return menu;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static void ToggleMuteNotifications(){
|
|
||||||
Config.MuteNotifications = !Config.MuteNotifications;
|
|
||||||
Config.Save();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,14 +1,13 @@
|
|||||||
using CefSharp;
|
using CefSharp;
|
||||||
using TweetDuck.Management.Analytics;
|
using IContextMenuHandler = TweetLib.Browser.Interfaces.IContextMenuHandler;
|
||||||
|
|
||||||
namespace TweetDuck.Browser.Handling{
|
namespace TweetDuck.Browser.Handling {
|
||||||
sealed class ContextMenuGuide : ContextMenuBase{
|
sealed class ContextMenuGuide : ContextMenuBase {
|
||||||
public ContextMenuGuide(AnalyticsFile.IProvider analytics) : base(analytics){}
|
public ContextMenuGuide(IContextMenuHandler handler) : base(handler) {}
|
||||||
|
|
||||||
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();
|
base.OnBeforeContextMenu(browserControl, browser, frame, parameters, model);
|
||||||
base.OnBeforeContextMenu(browserControl, browser, frame, parameters, model);
|
AddDebugMenuItems(model);
|
||||||
AddDebugMenuItems(model);
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,94 +1,32 @@
|
|||||||
using CefSharp;
|
using CefSharp;
|
||||||
using TweetDuck.Browser.Notification;
|
using TweetDuck.Browser.Notification;
|
||||||
using TweetDuck.Controls;
|
using TweetDuck.Controls;
|
||||||
|
using TweetLib.Browser.Contexts;
|
||||||
|
using IContextMenuHandler = TweetLib.Browser.Interfaces.IContextMenuHandler;
|
||||||
|
|
||||||
namespace TweetDuck.Browser.Handling{
|
namespace TweetDuck.Browser.Handling {
|
||||||
sealed class ContextMenuNotification : ContextMenuBase{
|
sealed class ContextMenuNotification : ContextMenuBase {
|
||||||
private const CefMenuCommand MenuViewDetail = (CefMenuCommand)26600;
|
private readonly FormNotificationBase form;
|
||||||
private const CefMenuCommand MenuSkipTweet = (CefMenuCommand)26601;
|
|
||||||
private const CefMenuCommand MenuFreeze = (CefMenuCommand)26602;
|
|
||||||
private const CefMenuCommand MenuCopyTweetUrl = (CefMenuCommand)26603;
|
|
||||||
private const CefMenuCommand MenuCopyQuotedTweetUrl = (CefMenuCommand)26604;
|
|
||||||
|
|
||||||
private readonly FormNotificationBase form;
|
public ContextMenuNotification(FormNotificationBase form, IContextMenuHandler handler) : base(handler) {
|
||||||
private readonly bool enableCustomMenu;
|
this.form = form;
|
||||||
|
}
|
||||||
|
|
||||||
public ContextMenuNotification(FormNotificationBase form, bool enableCustomMenu) : base(form){
|
protected override Context CreateContext(IContextMenuParams parameters) {
|
||||||
this.form = form;
|
Context context = base.CreateContext(parameters);
|
||||||
this.enableCustomMenu = enableCustomMenu;
|
context.Notification = new TweetLib.Browser.Contexts.Notification(form.CurrentTweetUrl, form.CurrentQuoteUrl);
|
||||||
}
|
return context;
|
||||||
|
}
|
||||||
|
|
||||||
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();
|
base.OnBeforeContextMenu(browserControl, browser, frame, parameters, model);
|
||||||
|
AddDebugMenuItems(model);
|
||||||
|
form.InvokeAsyncSafe(() => form.ContextMenuOpen = true);
|
||||||
|
}
|
||||||
|
|
||||||
if (parameters.TypeFlags.HasFlag(ContextMenuType.Selection)){
|
public override void OnContextMenuDismissed(IWebBrowser browserControl, IBrowser browser, IFrame frame) {
|
||||||
model.AddItem(CefMenuCommand.Copy, "Copy");
|
base.OnContextMenuDismissed(browserControl, browser, frame);
|
||||||
model.AddSeparator();
|
form.InvokeAsyncSafe(() => form.ContextMenuOpen = false);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
base.OnBeforeContextMenu(browserControl, browser, frame, parameters, model);
|
|
||||||
|
|
||||||
if (enableCustomMenu){
|
|
||||||
if (form.CanViewDetail){
|
|
||||||
model.AddItem(MenuViewDetail, "View detail");
|
|
||||||
}
|
|
||||||
|
|
||||||
model.AddItem(MenuSkipTweet, "Skip tweet");
|
|
||||||
model.AddCheckItem(MenuFreeze, "Freeze");
|
|
||||||
model.SetChecked(MenuFreeze, form.FreezeTimer);
|
|
||||||
|
|
||||||
if (!string.IsNullOrEmpty(form.CurrentTweetUrl)){
|
|
||||||
model.AddSeparator();
|
|
||||||
model.AddItem(MenuCopyTweetUrl, "Copy tweet address");
|
|
||||||
|
|
||||||
if (!string.IsNullOrEmpty(form.CurrentQuoteUrl)){
|
|
||||||
model.AddItem(MenuCopyQuotedTweetUrl, "Copy quoted tweet address");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
AddDebugMenuItems(model);
|
|
||||||
RemoveSeparatorIfLast(model);
|
|
||||||
|
|
||||||
form.InvokeAsyncSafe(() => {
|
|
||||||
form.ContextMenuOpen = true;
|
|
||||||
form.AnalyticsFile.NotificationContextMenus.Trigger();
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
public override bool OnContextMenuCommand(IWebBrowser browserControl, IBrowser browser, IFrame frame, IContextMenuParams parameters, CefMenuCommand commandId, CefEventFlags eventFlags){
|
|
||||||
if (base.OnContextMenuCommand(browserControl, browser, frame, parameters, commandId, eventFlags)){
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
switch(commandId){
|
|
||||||
case MenuSkipTweet:
|
|
||||||
form.InvokeAsyncSafe(form.FinishCurrentNotification);
|
|
||||||
return true;
|
|
||||||
|
|
||||||
case MenuFreeze:
|
|
||||||
form.InvokeAsyncSafe(() => form.FreezeTimer = !form.FreezeTimer);
|
|
||||||
return true;
|
|
||||||
|
|
||||||
case MenuViewDetail:
|
|
||||||
form.InvokeSafe(form.ShowTweetDetail);
|
|
||||||
return true;
|
|
||||||
|
|
||||||
case MenuCopyTweetUrl:
|
|
||||||
SetClipboardText(form, form.CurrentTweetUrl);
|
|
||||||
return true;
|
|
||||||
|
|
||||||
case MenuCopyQuotedTweetUrl:
|
|
||||||
SetClipboardText(form, form.CurrentQuoteUrl);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
public override void OnContextMenuDismissed(IWebBrowser browserControl, IBrowser browser, IFrame frame){
|
|
||||||
base.OnContextMenuDismissed(browserControl, browser, frame);
|
|
||||||
form.InvokeAsyncSafe(() => form.ContextMenuOpen = false);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
43
Browser/Handling/CustomKeyboardHandler.cs
Normal file
43
Browser/Handling/CustomKeyboardHandler.cs
Normal file
@@ -0,0 +1,43 @@
|
|||||||
|
using System.Windows.Forms;
|
||||||
|
using CefSharp;
|
||||||
|
using TweetDuck.Utils;
|
||||||
|
using TweetLib.Utils.Static;
|
||||||
|
|
||||||
|
namespace TweetDuck.Browser.Handling {
|
||||||
|
sealed class CustomKeyboardHandler : IKeyboardHandler {
|
||||||
|
private readonly IBrowserKeyHandler handler;
|
||||||
|
|
||||||
|
public CustomKeyboardHandler(IBrowserKeyHandler handler) {
|
||||||
|
this.handler = handler;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool IKeyboardHandler.OnPreKeyEvent(IWebBrowser browserControl, IBrowser browser, KeyType type, int windowsKeyCode, int nativeKeyCode, CefEventFlags modifiers, bool isSystemKey, ref bool isKeyboardShortcut) {
|
||||||
|
if (type != KeyType.RawKeyDown) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
using (var frame = browser.FocusedFrame) {
|
||||||
|
if (frame.Url.StartsWithOrdinal("devtools://")) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Keys key = (Keys) windowsKeyCode;
|
||||||
|
|
||||||
|
if (modifiers == (CefEventFlags.ControlDown | CefEventFlags.ShiftDown) && key == Keys.I) {
|
||||||
|
browserControl.OpenDevToolsCustom();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return handler != null && handler.HandleBrowserKey(key);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool IKeyboardHandler.OnKeyEvent(IWebBrowser browserControl, IBrowser browser, KeyType type, int windowsKeyCode, int nativeKeyCode, CefEventFlags modifiers, bool isSystemKey) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public interface IBrowserKeyHandler {
|
||||||
|
bool HandleBrowserKey(Keys key);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
37
Browser/Handling/CustomLifeSpanHandler.cs
Normal file
37
Browser/Handling/CustomLifeSpanHandler.cs
Normal file
@@ -0,0 +1,37 @@
|
|||||||
|
using CefSharp;
|
||||||
|
using CefSharp.Handler;
|
||||||
|
using TweetLib.Core;
|
||||||
|
using TweetLib.Utils.Static;
|
||||||
|
|
||||||
|
namespace TweetDuck.Browser.Handling {
|
||||||
|
sealed class CustomLifeSpanHandler : LifeSpanHandler {
|
||||||
|
private static bool IsPopupAllowed(string url) {
|
||||||
|
return url.StartsWithOrdinal("https://twitter.com/teams/authorize?") ||
|
||||||
|
url.StartsWithOrdinal("https://accounts.google.com/") ||
|
||||||
|
url.StartsWithOrdinal("https://appleid.apple.com/");
|
||||||
|
}
|
||||||
|
|
||||||
|
public static bool HandleLinkClick(WindowOpenDisposition targetDisposition, string targetUrl) {
|
||||||
|
switch (targetDisposition) {
|
||||||
|
case WindowOpenDisposition.NewBackgroundTab:
|
||||||
|
case WindowOpenDisposition.NewForegroundTab:
|
||||||
|
case WindowOpenDisposition.NewPopup when !IsPopupAllowed(targetUrl):
|
||||||
|
case WindowOpenDisposition.NewWindow:
|
||||||
|
App.SystemHandler.OpenBrowser(targetUrl);
|
||||||
|
return true;
|
||||||
|
|
||||||
|
default:
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override 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(targetDisposition, targetUrl);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override bool DoClose(IWebBrowser browserControl, IBrowser browser) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
62
Browser/Handling/DownloadRequestClient.cs
Normal file
62
Browser/Handling/DownloadRequestClient.cs
Normal file
@@ -0,0 +1,62 @@
|
|||||||
|
using System;
|
||||||
|
using System.IO;
|
||||||
|
using CefSharp;
|
||||||
|
|
||||||
|
namespace TweetDuck.Browser.Handling {
|
||||||
|
sealed class DownloadRequestClient : UrlRequestClient {
|
||||||
|
private readonly FileStream fileStream;
|
||||||
|
private readonly Action onSuccess;
|
||||||
|
private readonly Action<Exception> onError;
|
||||||
|
|
||||||
|
private bool hasFailed;
|
||||||
|
|
||||||
|
public DownloadRequestClient(FileStream fileStream, Action onSuccess, Action<Exception> onError) {
|
||||||
|
this.fileStream = fileStream;
|
||||||
|
this.onSuccess = onSuccess;
|
||||||
|
this.onError = onError;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override bool GetAuthCredentials(bool isProxy, string host, int port, string realm, string scheme, IAuthCallback callback) {
|
||||||
|
onError?.Invoke(new Exception("This URL requires authentication."));
|
||||||
|
fileStream.Dispose();
|
||||||
|
hasFailed = true;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void OnDownloadData(IUrlRequest request, Stream data) {
|
||||||
|
if (hasFailed) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
data.CopyTo(fileStream);
|
||||||
|
} catch (Exception e) {
|
||||||
|
fileStream.Dispose();
|
||||||
|
onError?.Invoke(e);
|
||||||
|
hasFailed = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void OnRequestComplete(IUrlRequest request) {
|
||||||
|
if (hasFailed) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool isEmpty = fileStream.Position == 0;
|
||||||
|
fileStream.Dispose();
|
||||||
|
|
||||||
|
var status = request.RequestStatus;
|
||||||
|
if (status == UrlRequestStatus.Failed) {
|
||||||
|
onError?.Invoke(new Exception("Unknown error."));
|
||||||
|
}
|
||||||
|
else if (status == UrlRequestStatus.Success) {
|
||||||
|
if (isEmpty) {
|
||||||
|
onError?.Invoke(new Exception("File is empty."));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
onSuccess?.Invoke();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -2,34 +2,34 @@
|
|||||||
using CefSharp;
|
using CefSharp;
|
||||||
using CefSharp.Enums;
|
using CefSharp.Enums;
|
||||||
|
|
||||||
namespace TweetDuck.Browser.Handling{
|
namespace TweetDuck.Browser.Handling {
|
||||||
sealed class DragHandlerBrowser : IDragHandler{
|
sealed class DragHandlerBrowser : IDragHandler {
|
||||||
private readonly RequestHandlerBrowser requestHandler;
|
private readonly RequestHandlerBrowser requestHandler;
|
||||||
|
|
||||||
public DragHandlerBrowser(RequestHandlerBrowser requestHandler){
|
public DragHandlerBrowser(RequestHandlerBrowser requestHandler) {
|
||||||
this.requestHandler = requestHandler;
|
this.requestHandler = requestHandler;
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool OnDragEnter(IWebBrowser browserControl, IBrowser browser, IDragData dragData, DragOperationsMask mask){
|
|
||||||
void TriggerDragStart(string type, string data = null){
|
|
||||||
browserControl.ExecuteScriptAsync("window.TDGF_onGlobalDragStart", type, data);
|
|
||||||
}
|
|
||||||
|
|
||||||
requestHandler.BlockNextUserNavUrl = dragData.LinkUrl; // empty if not a link
|
|
||||||
|
|
||||||
if (dragData.IsLink){
|
public bool OnDragEnter(IWebBrowser browserControl, IBrowser browser, IDragData dragData, DragOperationsMask mask) {
|
||||||
TriggerDragStart("link", dragData.LinkUrl);
|
void TriggerDragStart(string type, string data = null) {
|
||||||
}
|
browserControl.BrowserCore.ExecuteScriptAsync("window.TDGF_onGlobalDragStart", type, data);
|
||||||
else if (dragData.IsFragment){
|
}
|
||||||
TriggerDragStart("text", dragData.FragmentText.Trim());
|
|
||||||
}
|
|
||||||
else{
|
|
||||||
TriggerDragStart("unknown");
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
requestHandler.BlockNextUserNavUrl = dragData.LinkUrl; // empty if not a link
|
||||||
}
|
|
||||||
|
|
||||||
public void OnDraggableRegionsChanged(IWebBrowser browserControl, IBrowser browser, IList<DraggableRegion> regions){}
|
if (dragData.IsLink) {
|
||||||
}
|
TriggerDragStart("link", dragData.LinkUrl);
|
||||||
|
}
|
||||||
|
else if (dragData.IsFragment) {
|
||||||
|
TriggerDragStart("text", dragData.FragmentText.Trim());
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
TriggerDragStart("unknown");
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void OnDraggableRegionsChanged(IWebBrowser browserControl, IBrowser browser, IFrame frame, IList<DraggableRegion> regions) {}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
68
Browser/Handling/FileDialogHandler.cs
Normal file
68
Browser/Handling/FileDialogHandler.cs
Normal file
@@ -0,0 +1,68 @@
|
|||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Diagnostics;
|
||||||
|
using System.IO;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Windows.Forms;
|
||||||
|
using CefSharp;
|
||||||
|
using TweetLib.Core;
|
||||||
|
using TweetLib.Utils.Static;
|
||||||
|
|
||||||
|
namespace TweetDuck.Browser.Handling {
|
||||||
|
sealed class FileDialogHandler : IDialogHandler {
|
||||||
|
public bool OnFileDialog(IWebBrowser browserControl, IBrowser browser, CefFileDialogMode mode, CefFileDialogFlags flags, string title, string defaultFilePath, List<string> acceptFilters, int selectedAcceptFilter, IFileDialogCallback callback) {
|
||||||
|
if (mode == CefFileDialogMode.Open || mode == CefFileDialogMode.OpenMultiple) {
|
||||||
|
string allFilters = string.Join(";", acceptFilters.SelectMany(ParseFileType).Where(filter => !string.IsNullOrEmpty(filter)).Select(filter => "*" + filter));
|
||||||
|
|
||||||
|
using OpenFileDialog dialog = new OpenFileDialog {
|
||||||
|
AutoUpgradeEnabled = true,
|
||||||
|
DereferenceLinks = true,
|
||||||
|
Multiselect = mode == CefFileDialogMode.OpenMultiple,
|
||||||
|
Title = "Open Files",
|
||||||
|
Filter = $"All Supported Formats ({allFilters})|{allFilters}|All Files (*.*)|*.*"
|
||||||
|
};
|
||||||
|
|
||||||
|
if (dialog.ShowDialog() == DialogResult.OK) {
|
||||||
|
string ext = Path.GetExtension(dialog.FileName)?.ToLower();
|
||||||
|
callback.Continue(acceptFilters.FindIndex(filter => ParseFileType(filter).Contains(ext)), dialog.FileNames.ToList());
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
callback.Cancel();
|
||||||
|
}
|
||||||
|
|
||||||
|
callback.Dispose();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
callback.Dispose();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static IEnumerable<string> ParseFileType(string type) {
|
||||||
|
if (string.IsNullOrEmpty(type)) {
|
||||||
|
return StringUtils.EmptyArray;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (type[0] == '.') {
|
||||||
|
return new string[] { type };
|
||||||
|
}
|
||||||
|
|
||||||
|
string[] extensions = type switch {
|
||||||
|
"image/jpeg" => new string[] { ".jpg", ".jpeg" },
|
||||||
|
"image/png" => new string[] { ".png" },
|
||||||
|
"image/gif" => new string[] { ".gif" },
|
||||||
|
"image/webp" => new string[] { ".webp" },
|
||||||
|
"video/mp4" => new string[] { ".mp4" },
|
||||||
|
"video/quicktime" => new string[] { ".mov", ".qt" },
|
||||||
|
_ => StringUtils.EmptyArray
|
||||||
|
};
|
||||||
|
|
||||||
|
if (extensions.Length == 0) {
|
||||||
|
App.Logger.Warn("Unknown file type: " + type);
|
||||||
|
Debugger.Break();
|
||||||
|
}
|
||||||
|
|
||||||
|
return extensions;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,72 +0,0 @@
|
|||||||
using System;
|
|
||||||
using System.IO;
|
|
||||||
using System.Text;
|
|
||||||
using CefSharp;
|
|
||||||
|
|
||||||
namespace TweetDuck.Browser.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();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,20 +0,0 @@
|
|||||||
using System.Text;
|
|
||||||
using System.Text.RegularExpressions;
|
|
||||||
|
|
||||||
namespace TweetDuck.Browser.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(){}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,28 +0,0 @@
|
|||||||
using System;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
using CefSharp;
|
|
||||||
using TweetDuck.Configuration;
|
|
||||||
|
|
||||||
namespace TweetDuck.Browser.Handling.General{
|
|
||||||
sealed class BrowserProcessHandler : IBrowserProcessHandler{
|
|
||||||
public static Task UpdatePrefs(){
|
|
||||||
return Cef.UIThreadTaskFactory.StartNew(UpdatePrefsInternal);
|
|
||||||
}
|
|
||||||
|
|
||||||
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 IDisposable.Dispose(){}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,61 +0,0 @@
|
|||||||
using System.Collections.Generic;
|
|
||||||
using System.IO;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Windows.Forms;
|
|
||||||
using CefSharp;
|
|
||||||
|
|
||||||
namespace TweetDuck.Browser.Handling.General{
|
|
||||||
sealed class FileDialogHandler : IDialogHandler{
|
|
||||||
public bool OnFileDialog(IWebBrowser browserControl, IBrowser browser, CefFileDialogMode mode, CefFileDialogFlags flags, string title, string defaultFilePath, List<string> acceptFilters, int selectedAcceptFilter, IFileDialogCallback callback){
|
|
||||||
if (mode == CefFileDialogMode.Open || mode == CefFileDialogMode.OpenMultiple){
|
|
||||||
string allFilters = string.Join(";", acceptFilters.SelectMany(ParseFileType).Where(filter => !string.IsNullOrEmpty(filter)).Select(filter => "*" + filter));
|
|
||||||
|
|
||||||
using(OpenFileDialog dialog = new OpenFileDialog{
|
|
||||||
AutoUpgradeEnabled = true,
|
|
||||||
DereferenceLinks = true,
|
|
||||||
Multiselect = mode == CefFileDialogMode.OpenMultiple,
|
|
||||||
Title = "Open Files",
|
|
||||||
Filter = $"All Supported Formats ({allFilters})|{allFilters}|All Files (*.*)|*.*"
|
|
||||||
}){
|
|
||||||
if (dialog.ShowDialog() == DialogResult.OK){
|
|
||||||
string ext = Path.GetExtension(dialog.FileName)?.ToLower();
|
|
||||||
callback.Continue(acceptFilters.FindIndex(filter => ParseFileType(filter).Contains(ext)), dialog.FileNames.ToList());
|
|
||||||
}
|
|
||||||
else{
|
|
||||||
callback.Cancel();
|
|
||||||
}
|
|
||||||
|
|
||||||
callback.Dispose();
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
else{
|
|
||||||
callback.Dispose();
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private static IEnumerable<string> ParseFileType(string type){
|
|
||||||
if (string.IsNullOrEmpty(type)){
|
|
||||||
return new string[0];
|
|
||||||
}
|
|
||||||
|
|
||||||
if (type[0] == '.'){
|
|
||||||
return new string[]{ type };
|
|
||||||
}
|
|
||||||
|
|
||||||
switch(type){
|
|
||||||
case "image/jpeg": return new string[]{ ".jpg", ".jpeg" };
|
|
||||||
case "image/png": return new string[]{ ".png" };
|
|
||||||
case "image/gif": return new string[]{ ".gif" };
|
|
||||||
case "image/webp": return new string[]{ ".webp" };
|
|
||||||
case "video/mp4": return new string[]{ ".mp4" };
|
|
||||||
case "video/quicktime": return new string[]{ ".mov", ".qt" };
|
|
||||||
}
|
|
||||||
|
|
||||||
System.Diagnostics.Debugger.Break();
|
|
||||||
return new string[0];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,92 +0,0 @@
|
|||||||
using System.Drawing;
|
|
||||||
using System.Windows.Forms;
|
|
||||||
using CefSharp;
|
|
||||||
using TweetDuck.Controls;
|
|
||||||
using TweetDuck.Dialogs;
|
|
||||||
using TweetDuck.Utils;
|
|
||||||
|
|
||||||
namespace TweetDuck.Browser.Handling.General{
|
|
||||||
sealed class JavaScriptDialogHandler : IJsDialogHandler{
|
|
||||||
private static FormMessage CreateMessageForm(string caption, string text){
|
|
||||||
MessageBoxIcon icon = MessageBoxIcon.None;
|
|
||||||
int pipe = text.IndexOf('|');
|
|
||||||
|
|
||||||
if (pipe != -1){
|
|
||||||
icon = text.Substring(0, pipe) switch{
|
|
||||||
"error" => MessageBoxIcon.Error,
|
|
||||||
"warning" => MessageBoxIcon.Warning,
|
|
||||||
"info" => MessageBoxIcon.Information,
|
|
||||||
"question" => MessageBoxIcon.Question,
|
|
||||||
_ => MessageBoxIcon.None
|
|
||||||
};
|
|
||||||
|
|
||||||
if (icon != MessageBoxIcon.None){
|
|
||||||
text = text.Substring(pipe + 1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return new FormMessage(caption, text, icon);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool IJsDialogHandler.OnJSDialog(IWebBrowser browserControl, IBrowser browser, string originUrl, CefJsDialogType dialogType, string messageText, string defaultPromptText, IJsDialogCallback callback, ref bool suppressMessage){
|
|
||||||
browserControl.AsControl().InvokeSafe(() => {
|
|
||||||
FormMessage form;
|
|
||||||
TextBox input = null;
|
|
||||||
|
|
||||||
if (dialogType == CefJsDialogType.Alert){
|
|
||||||
form = CreateMessageForm("Browser Message", messageText);
|
|
||||||
form.AddButton(FormMessage.OK, ControlType.Accept | ControlType.Focused);
|
|
||||||
}
|
|
||||||
else if (dialogType == CefJsDialogType.Confirm){
|
|
||||||
form = CreateMessageForm("Browser Confirmation", messageText);
|
|
||||||
form.AddButton(FormMessage.No, DialogResult.No, ControlType.Cancel);
|
|
||||||
form.AddButton(FormMessage.Yes, ControlType.Focused);
|
|
||||||
}
|
|
||||||
else if (dialogType == CefJsDialogType.Prompt){
|
|
||||||
form = CreateMessageForm("Browser Prompt", messageText);
|
|
||||||
form.AddButton(FormMessage.Cancel, DialogResult.Cancel, ControlType.Cancel);
|
|
||||||
form.AddButton(FormMessage.OK, ControlType.Accept | ControlType.Focused);
|
|
||||||
|
|
||||||
float dpiScale = form.GetDPIScale();
|
|
||||||
int inputPad = form.HasIcon ? 43 : 0;
|
|
||||||
|
|
||||||
input = new TextBox{
|
|
||||||
Anchor = AnchorStyles.Left | AnchorStyles.Right | AnchorStyles.Bottom,
|
|
||||||
Font = SystemFonts.MessageBoxFont,
|
|
||||||
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), BrowserUtils.Scale(23, dpiScale))
|
|
||||||
};
|
|
||||||
|
|
||||||
form.Controls.Add(input);
|
|
||||||
form.ActiveControl = input;
|
|
||||||
form.Height += input.Size.Height + input.Margin.Vertical;
|
|
||||||
}
|
|
||||||
else{
|
|
||||||
callback.Continue(false);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool success = form.ShowDialog() == DialogResult.OK;
|
|
||||||
|
|
||||||
if (input == null){
|
|
||||||
callback.Continue(success);
|
|
||||||
}
|
|
||||||
else{
|
|
||||||
callback.Continue(success, input.Text);
|
|
||||||
input.Dispose();
|
|
||||||
}
|
|
||||||
|
|
||||||
form.Dispose();
|
|
||||||
});
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool IJsDialogHandler.OnJSBeforeUnload(IWebBrowser browserControl, IBrowser browser, string message, bool isReload, IJsDialogCallback callback){
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
void IJsDialogHandler.OnResetDialogState(IWebBrowser browserControl, IBrowser browser){}
|
|
||||||
void IJsDialogHandler.OnDialogClosed(IWebBrowser browserControl, IBrowser browser){}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,38 +0,0 @@
|
|||||||
using CefSharp;
|
|
||||||
using TweetDuck.Controls;
|
|
||||||
using TweetDuck.Utils;
|
|
||||||
|
|
||||||
namespace TweetDuck.Browser.Handling.General{
|
|
||||||
sealed class LifeSpanHandler : ILifeSpanHandler{
|
|
||||||
private static bool IsPopupAllowed(string url){
|
|
||||||
return url.StartsWith("https://twitter.com/teams/authorize?");
|
|
||||||
}
|
|
||||||
|
|
||||||
public static bool HandleLinkClick(IWebBrowser browserControl, WindowOpenDisposition targetDisposition, string targetUrl){
|
|
||||||
switch(targetDisposition){
|
|
||||||
case WindowOpenDisposition.NewBackgroundTab:
|
|
||||||
case WindowOpenDisposition.NewForegroundTab:
|
|
||||||
case WindowOpenDisposition.NewPopup when !IsPopupAllowed(targetUrl):
|
|
||||||
case WindowOpenDisposition.NewWindow:
|
|
||||||
browserControl.AsControl().InvokeAsyncSafe(() => BrowserUtils.OpenExternalBrowser(targetUrl));
|
|
||||||
return true;
|
|
||||||
|
|
||||||
default:
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
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 bool DoClose(IWebBrowser browserControl, IBrowser browser){
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void OnBeforeClose(IWebBrowser browserControl, IBrowser browser){}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
96
Browser/Handling/JavaScriptDialogHandler.cs
Normal file
96
Browser/Handling/JavaScriptDialogHandler.cs
Normal file
@@ -0,0 +1,96 @@
|
|||||||
|
using System.Drawing;
|
||||||
|
using System.Windows.Forms;
|
||||||
|
using CefSharp;
|
||||||
|
using CefSharp.WinForms;
|
||||||
|
using TweetDuck.Controls;
|
||||||
|
using TweetDuck.Dialogs;
|
||||||
|
using TweetDuck.Utils;
|
||||||
|
|
||||||
|
namespace TweetDuck.Browser.Handling {
|
||||||
|
sealed class JavaScriptDialogHandler : IJsDialogHandler {
|
||||||
|
private static FormMessage CreateMessageForm(string caption, string text) {
|
||||||
|
MessageBoxIcon icon = MessageBoxIcon.None;
|
||||||
|
int pipe = text.IndexOf('|');
|
||||||
|
|
||||||
|
if (pipe != -1) {
|
||||||
|
icon = text.Substring(0, pipe) switch {
|
||||||
|
"error" => MessageBoxIcon.Error,
|
||||||
|
"warning" => MessageBoxIcon.Warning,
|
||||||
|
"info" => MessageBoxIcon.Information,
|
||||||
|
"question" => MessageBoxIcon.Question,
|
||||||
|
_ => MessageBoxIcon.None
|
||||||
|
};
|
||||||
|
|
||||||
|
if (icon != MessageBoxIcon.None) {
|
||||||
|
text = text.Substring(pipe + 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return new FormMessage(caption, text, icon);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool IJsDialogHandler.OnJSDialog(IWebBrowser browserControl, IBrowser browser, string originUrl, CefJsDialogType dialogType, string messageText, string defaultPromptText, IJsDialogCallback callback, ref bool suppressMessage) {
|
||||||
|
var control = (ChromiumWebBrowser) browserControl;
|
||||||
|
|
||||||
|
control.InvokeSafe(() => {
|
||||||
|
FormMessage form;
|
||||||
|
TextBox input = null;
|
||||||
|
|
||||||
|
if (dialogType == CefJsDialogType.Alert) {
|
||||||
|
form = CreateMessageForm("Browser Message", messageText);
|
||||||
|
form.AddButton(FormMessage.OK, ControlType.Accept | ControlType.Focused);
|
||||||
|
}
|
||||||
|
else if (dialogType == CefJsDialogType.Confirm) {
|
||||||
|
form = CreateMessageForm("Browser Confirmation", messageText);
|
||||||
|
form.AddButton(FormMessage.No, DialogResult.No, ControlType.Cancel);
|
||||||
|
form.AddButton(FormMessage.Yes, ControlType.Focused);
|
||||||
|
}
|
||||||
|
else if (dialogType == CefJsDialogType.Prompt) {
|
||||||
|
form = CreateMessageForm("Browser Prompt", messageText);
|
||||||
|
form.AddButton(FormMessage.Cancel, DialogResult.Cancel, ControlType.Cancel);
|
||||||
|
form.AddButton(FormMessage.OK, ControlType.Accept | ControlType.Focused);
|
||||||
|
|
||||||
|
float dpiScale = form.GetDPIScale();
|
||||||
|
int inputPad = form.HasIcon ? 43 : 0;
|
||||||
|
|
||||||
|
input = new TextBox {
|
||||||
|
Anchor = AnchorStyles.Left | AnchorStyles.Right | AnchorStyles.Bottom,
|
||||||
|
Font = SystemFonts.MessageBoxFont,
|
||||||
|
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), BrowserUtils.Scale(23, dpiScale))
|
||||||
|
};
|
||||||
|
|
||||||
|
form.Controls.Add(input);
|
||||||
|
form.ActiveControl = input;
|
||||||
|
form.Height += input.Size.Height + input.Margin.Vertical;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
callback.Continue(false);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool success = form.ShowDialog() == DialogResult.OK;
|
||||||
|
|
||||||
|
if (input == null) {
|
||||||
|
callback.Continue(success);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
callback.Continue(success, input.Text);
|
||||||
|
input.Dispose();
|
||||||
|
}
|
||||||
|
|
||||||
|
form.Dispose();
|
||||||
|
});
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool IJsDialogHandler.OnBeforeUnloadDialog(IWebBrowser browserControl, IBrowser browser, string messageText, bool isReload, IJsDialogCallback callback) {
|
||||||
|
callback.Dispose();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void IJsDialogHandler.OnResetDialogState(IWebBrowser browserControl, IBrowser browser) {}
|
||||||
|
void IJsDialogHandler.OnDialogClosed(IWebBrowser browserControl, IBrowser browser) {}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,47 +0,0 @@
|
|||||||
using System.Windows.Forms;
|
|
||||||
using CefSharp;
|
|
||||||
using TweetDuck.Controls;
|
|
||||||
using TweetDuck.Dialogs;
|
|
||||||
using TweetDuck.Utils;
|
|
||||||
|
|
||||||
namespace TweetDuck.Browser.Handling{
|
|
||||||
class KeyboardHandlerBase : IKeyboardHandler{
|
|
||||||
protected virtual bool HandleRawKey(IWebBrowser browserControl, IBrowser browser, Keys key, CefEventFlags modifiers){
|
|
||||||
if (modifiers == (CefEventFlags.ControlDown | CefEventFlags.ShiftDown) && key == Keys.I){
|
|
||||||
if (BrowserUtils.HasDevTools){
|
|
||||||
browserControl.OpenDevToolsCustom();
|
|
||||||
}
|
|
||||||
else{
|
|
||||||
browserControl.AsControl().InvokeSafe(() => {
|
|
||||||
string extraMessage;
|
|
||||||
|
|
||||||
if (Program.IsPortable){
|
|
||||||
extraMessage = "Please download the portable installer, select the folder with your current installation of TweetDuck Portable, and tick 'Install dev tools' during the installation process.";
|
|
||||||
}
|
|
||||||
else{
|
|
||||||
extraMessage = "Please download the installer, and tick 'Install dev tools' during the installation process. The installer will automatically find and update your current installation of TweetDuck.";
|
|
||||||
}
|
|
||||||
|
|
||||||
FormMessage.Information("Dev Tools", "You do not have dev tools installed. " + extraMessage, FormMessage.OK);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool IKeyboardHandler.OnPreKeyEvent(IWebBrowser browserControl, IBrowser browser, KeyType type, int windowsKeyCode, int nativeKeyCode, CefEventFlags modifiers, bool isSystemKey, ref bool isKeyboardShortcut){
|
|
||||||
if (type == KeyType.RawKeyDown && !browser.FocusedFrame.Url.StartsWith("chrome-devtools://")){
|
|
||||||
return HandleRawKey(browserControl, browser, (Keys)windowsKeyCode, modifiers);
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool IKeyboardHandler.OnKeyEvent(IWebBrowser browserControl, IBrowser browser, KeyType type, int windowsKeyCode, int nativeKeyCode, CefEventFlags modifiers, bool isSystemKey){
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,20 +0,0 @@
|
|||||||
using System.Windows.Forms;
|
|
||||||
using CefSharp;
|
|
||||||
|
|
||||||
namespace TweetDuck.Browser.Handling{
|
|
||||||
sealed class KeyboardHandlerBrowser : KeyboardHandlerBase{
|
|
||||||
private readonly FormBrowser form;
|
|
||||||
|
|
||||||
public KeyboardHandlerBrowser(FormBrowser form){
|
|
||||||
this.form = form;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected override bool HandleRawKey(IWebBrowser browserControl, IBrowser browser, Keys key, CefEventFlags modifiers){
|
|
||||||
if (base.HandleRawKey(browserControl, browser, key, modifiers)){
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
return form.ProcessBrowserKey(key);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,44 +0,0 @@
|
|||||||
using System.Windows.Forms;
|
|
||||||
using CefSharp;
|
|
||||||
using TweetDuck.Browser.Notification;
|
|
||||||
using TweetDuck.Controls;
|
|
||||||
|
|
||||||
namespace TweetDuck.Browser.Handling{
|
|
||||||
sealed class KeyboardHandlerNotification : KeyboardHandlerBase{
|
|
||||||
private readonly FormNotificationBase notification;
|
|
||||||
|
|
||||||
public KeyboardHandlerNotification(FormNotificationBase notification){
|
|
||||||
this.notification = notification;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void TriggerKeyboardShortcutAnalytics(){
|
|
||||||
notification.InvokeAsyncSafe(notification.AnalyticsFile.NotificationKeyboardShortcuts.Trigger);
|
|
||||||
}
|
|
||||||
|
|
||||||
protected override bool HandleRawKey(IWebBrowser browserControl, IBrowser browser, Keys key, CefEventFlags modifiers){
|
|
||||||
if (base.HandleRawKey(browserControl, browser, key, modifiers)){
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
switch(key){
|
|
||||||
case Keys.Enter:
|
|
||||||
notification.InvokeAsyncSafe(notification.FinishCurrentNotification);
|
|
||||||
TriggerKeyboardShortcutAnalytics();
|
|
||||||
return true;
|
|
||||||
|
|
||||||
case Keys.Escape:
|
|
||||||
notification.InvokeAsyncSafe(notification.HideNotification);
|
|
||||||
TriggerKeyboardShortcutAnalytics();
|
|
||||||
return true;
|
|
||||||
|
|
||||||
case Keys.Space:
|
|
||||||
notification.InvokeAsyncSafe(() => notification.FreezeTimer = !notification.FreezeTimer);
|
|
||||||
TriggerKeyboardShortcutAnalytics();
|
|
||||||
return true;
|
|
||||||
|
|
||||||
default:
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,82 +1,22 @@
|
|||||||
using System;
|
using CefSharp;
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Collections.Specialized;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Text.RegularExpressions;
|
|
||||||
using CefSharp;
|
|
||||||
using CefSharp.Handler;
|
using CefSharp.Handler;
|
||||||
using TweetDuck.Browser.Handling.General;
|
|
||||||
using TweetDuck.Utils;
|
|
||||||
using TweetLib.Core.Utils;
|
|
||||||
|
|
||||||
namespace TweetDuck.Browser.Handling{
|
namespace TweetDuck.Browser.Handling {
|
||||||
class RequestHandlerBase : DefaultRequestHandler{
|
class RequestHandlerBase : RequestHandler {
|
||||||
private static readonly Regex TweetDeckResourceUrl = new Regex(@"/dist/(.*?)\.(.*?)\.(css|js)$");
|
private readonly bool autoReload;
|
||||||
private static readonly SortedList<string, string> TweetDeckHashes = new SortedList<string, string>(4);
|
|
||||||
|
|
||||||
public static void LoadResourceRewriteRules(string rules){
|
public RequestHandlerBase(bool autoReload) {
|
||||||
if (string.IsNullOrEmpty(rules)){
|
this.autoReload = autoReload;
|
||||||
return;
|
}
|
||||||
}
|
|
||||||
|
|
||||||
TweetDeckHashes.Clear();
|
protected override bool OnOpenUrlFromTab(IWebBrowser browserControl, IBrowser browser, IFrame frame, string targetUrl, WindowOpenDisposition targetDisposition, bool userGesture) {
|
||||||
|
return CustomLifeSpanHandler.HandleLinkClick(targetDisposition, targetUrl);
|
||||||
|
}
|
||||||
|
|
||||||
foreach(string rule in rules.Replace(" ", "").ToLower().Split(',')){
|
protected override void OnRenderProcessTerminated(IWebBrowser browserControl, IBrowser browser, CefTerminationStatus status) {
|
||||||
var (key, hash) = StringUtils.SplitInTwo(rule, '=') ?? throw new ArgumentException("A rule must have one '=' character: " + rule);
|
if (autoReload) {
|
||||||
|
browser.Reload();
|
||||||
if (hash.All(chr => char.IsDigit(chr) || (chr >= 'a' && chr <= 'f'))){
|
}
|
||||||
TweetDeckHashes.Add(key, hash);
|
}
|
||||||
}
|
}
|
||||||
else{
|
|
||||||
throw new ArgumentException("Invalid hash characters: " + rule);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
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 bool OnResourceResponse(IWebBrowser browserControl, IBrowser browser, IFrame frame, IRequest request, IResponse response){
|
|
||||||
if ((request.ResourceType == ResourceType.Script || request.ResourceType == ResourceType.Stylesheet) && TweetDeckHashes.Count > 0){
|
|
||||||
string url = request.Url;
|
|
||||||
Match match = TweetDeckResourceUrl.Match(url);
|
|
||||||
|
|
||||||
if (match.Success && TweetDeckHashes.TryGetValue($"{match.Groups[1]}.{match.Groups[3]}", out string hash)){
|
|
||||||
if (match.Groups[2].Value == hash){
|
|
||||||
Program.Reporter.LogVerbose("[RequestHandlerBase] Accepting " + url);
|
|
||||||
}
|
|
||||||
else{
|
|
||||||
Program.Reporter.LogVerbose("[RequestHandlerBase] Replacing " + url + " hash with " + hash);
|
|
||||||
request.Url = TweetDeckResourceUrl.Replace(url, $"/dist/$1.{hash}.$3");
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return base.OnResourceResponse(browserControl, browser, frame, request, response);
|
|
||||||
}
|
|
||||||
|
|
||||||
public override void OnRenderProcessTerminated(IWebBrowser browserControl, IBrowser browser, CefTerminationStatus status){
|
|
||||||
if (autoReload){
|
|
||||||
browser.Reload();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,69 +1,23 @@
|
|||||||
using System.Collections.Specialized;
|
using CefSharp;
|
||||||
using CefSharp;
|
|
||||||
using TweetDuck.Browser.Handling.Filters;
|
|
||||||
using TweetDuck.Utils;
|
|
||||||
using TweetLib.Core.Features.Twitter;
|
using TweetLib.Core.Features.Twitter;
|
||||||
|
|
||||||
namespace TweetDuck.Browser.Handling{
|
namespace TweetDuck.Browser.Handling {
|
||||||
sealed class RequestHandlerBrowser : RequestHandlerBase{
|
sealed class RequestHandlerBrowser : RequestHandlerBase {
|
||||||
private const string UrlVendorResource = "/dist/vendor";
|
public string BlockNextUserNavUrl { get; set; }
|
||||||
private const string UrlLoadingSpinner = "/backgrounds/spinner_blue";
|
|
||||||
|
|
||||||
public string BlockNextUserNavUrl { get; set; }
|
public RequestHandlerBrowser() : base(true) {}
|
||||||
|
|
||||||
public RequestHandlerBrowser() : base(true){}
|
protected 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;
|
||||||
|
}
|
||||||
|
else if (request.TransitionType.HasFlag(TransitionType.ForwardBack) && TwitterUrls.IsTweetDeck(frame.Url)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
public override CefReturnValue OnBeforeResourceLoad(IWebBrowser browserControl, IBrowser browser, IFrame frame, IRequest request, IRequestCallback callback){
|
return base.OnBeforeBrowse(browserControl, browser, frame, request, userGesture, isRedirect);
|
||||||
if (request.ResourceType == ResourceType.MainFrame){
|
}
|
||||||
if (request.Url.EndsWith("//twitter.com/")){
|
}
|
||||||
request.Url = TwitterUrls.TweetDeck; // redirect plain twitter.com requests, fixes bugs with login 2FA
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if (request.ResourceType == ResourceType.Script){
|
|
||||||
string url = request.Url;
|
|
||||||
|
|
||||||
if (url.Contains("analytics.")){
|
|
||||||
callback.Dispose();
|
|
||||||
return CefReturnValue.Cancel;
|
|
||||||
}
|
|
||||||
else if (url.Contains(UrlVendorResource)){
|
|
||||||
NameValueCollection headers = request.Headers;
|
|
||||||
headers["Accept-Encoding"] = "identity";
|
|
||||||
request.Headers = headers;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
else if (request.TransitionType.HasFlag(TransitionType.ForwardBack) && TwitterUrls.IsTweetDeck(frame.Url)){
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
return base.OnBeforeBrowse(browserControl, browser, frame, request, userGesture, isRedirect);
|
|
||||||
}
|
|
||||||
|
|
||||||
public override bool OnResourceResponse(IWebBrowser browserControl, IBrowser browser, IFrame frame, IRequest request, IResponse response){
|
|
||||||
if (request.ResourceType == ResourceType.Image && request.Url.Contains(UrlLoadingSpinner)){
|
|
||||||
request.Url = TwitterUtils.LoadingSpinner.Url;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
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(UrlVendorResource) && int.TryParse(response.ResponseHeaders["Content-Length"], out int totalBytes)){
|
|
||||||
return new ResponseFilterVendor(totalBytes);
|
|
||||||
}
|
|
||||||
|
|
||||||
return base.GetResourceResponseFilter(browserControl, browser, frame, request, response);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,43 +0,0 @@
|
|||||||
using System;
|
|
||||||
using System.Collections.Concurrent;
|
|
||||||
using CefSharp;
|
|
||||||
using TweetDuck.Browser.Data;
|
|
||||||
|
|
||||||
namespace TweetDuck.Browser.Handling{
|
|
||||||
sealed class ResourceHandlerFactory : IResourceHandlerFactory{
|
|
||||||
public bool HasHandlers => !handlers.IsEmpty;
|
|
||||||
|
|
||||||
private readonly ConcurrentDictionary<string, IResourceHandler> handlers = new ConcurrentDictionary<string, IResourceHandler>(StringComparer.OrdinalIgnoreCase);
|
|
||||||
|
|
||||||
public IResourceHandler GetResourceHandler(IWebBrowser browserControl, IBrowser browser, IFrame frame, IRequest request){
|
|
||||||
try{
|
|
||||||
return handlers.TryGetValue(request.Url, out IResourceHandler handler) ? handler : null;
|
|
||||||
}finally{
|
|
||||||
request.Dispose();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// registration
|
|
||||||
|
|
||||||
public bool RegisterHandler(string url, IResourceHandler handler){
|
|
||||||
if (Uri.TryCreate(url, UriKind.Absolute, out Uri uri)){
|
|
||||||
handlers.AddOrUpdate(uri.AbsoluteUri, handler, (key, prev) => handler);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
public bool RegisterHandler(ResourceLink link){
|
|
||||||
return RegisterHandler(link.Url, link.Handler);
|
|
||||||
}
|
|
||||||
|
|
||||||
public bool UnregisterHandler(string url){
|
|
||||||
return handlers.TryRemove(url, out IResourceHandler _);
|
|
||||||
}
|
|
||||||
|
|
||||||
public bool UnregisterHandler(ResourceLink link){
|
|
||||||
return UnregisterHandler(link.Url);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,63 +1,79 @@
|
|||||||
using System.Collections.Specialized;
|
using System;
|
||||||
|
using System.Collections.Specialized;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
using CefSharp;
|
using CefSharp;
|
||||||
|
using CefSharp.Callback;
|
||||||
|
|
||||||
namespace TweetDuck.Browser.Handling{
|
namespace TweetDuck.Browser.Handling {
|
||||||
sealed class ResourceHandlerNotification : IResourceHandler{
|
sealed class ResourceHandlerNotification : IResourceHandler {
|
||||||
private readonly NameValueCollection headers = new NameValueCollection(0);
|
private readonly NameValueCollection headers = new NameValueCollection(0);
|
||||||
private MemoryStream dataIn;
|
private MemoryStream dataIn;
|
||||||
|
|
||||||
public void SetHTML(string html){
|
public void SetHTML(string html) {
|
||||||
dataIn?.Dispose();
|
dataIn?.Dispose();
|
||||||
dataIn = ResourceHandler.GetMemoryStream(html, Encoding.UTF8);
|
dataIn = ResourceHandler.GetMemoryStream(html, Encoding.UTF8);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Dispose(){
|
public void Dispose() {
|
||||||
if (dataIn != null){
|
if (dataIn != null) {
|
||||||
dataIn.Dispose();
|
dataIn.Dispose();
|
||||||
dataIn = null;
|
dataIn = null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool IResourceHandler.ProcessRequest(IRequest request, ICallback callback){
|
bool IResourceHandler.Open(IRequest request, out bool handleRequest, ICallback callback) {
|
||||||
callback.Continue();
|
callback.Dispose();
|
||||||
return true;
|
handleRequest = true;
|
||||||
}
|
|
||||||
|
|
||||||
void IResourceHandler.GetResponseHeaders(IResponse response, out long responseLength, out string redirectUrl){
|
if (dataIn != null) {
|
||||||
redirectUrl = null;
|
dataIn.Position = 0;
|
||||||
|
}
|
||||||
|
|
||||||
response.MimeType = "text/html";
|
return true;
|
||||||
response.StatusCode = 200;
|
}
|
||||||
response.StatusText = "OK";
|
|
||||||
response.ResponseHeaders = headers;
|
|
||||||
responseLength = dataIn?.Length ?? -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool IResourceHandler.ReadResponse(Stream dataOut, out int bytesRead, ICallback callback){
|
void IResourceHandler.GetResponseHeaders(IResponse response, out long responseLength, out string redirectUrl) {
|
||||||
callback.Dispose();
|
redirectUrl = null;
|
||||||
|
|
||||||
try{
|
response.MimeType = "text/html";
|
||||||
int length = (int)dataIn.Length;
|
response.StatusCode = 200;
|
||||||
|
response.StatusText = "OK";
|
||||||
|
response.Headers = headers;
|
||||||
|
responseLength = dataIn?.Length ?? 0;
|
||||||
|
}
|
||||||
|
|
||||||
dataIn.CopyTo(dataOut, length);
|
bool IResourceHandler.Read(Stream dataOut, out int bytesRead, IResourceReadCallback callback) {
|
||||||
bytesRead = length;
|
callback?.Dispose(); // TODO unnecessary null check once ReadResponse is removed
|
||||||
return true;
|
|
||||||
}catch{ // catch IOException, possibly NullReferenceException if dataIn is null
|
|
||||||
bytesRead = 0;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
bool IResourceHandler.CanGetCookie(Cookie cookie){
|
try {
|
||||||
return true;
|
byte[] buffer = new byte[Math.Min(dataIn.Length - dataIn.Position, dataOut.Length)];
|
||||||
}
|
int length = buffer.Length;
|
||||||
|
|
||||||
bool IResourceHandler.CanSetCookie(Cookie cookie){
|
dataIn.Read(buffer, 0, length);
|
||||||
return true;
|
dataOut.Write(buffer, 0, length);
|
||||||
}
|
bytesRead = length;
|
||||||
|
} catch { // catch IOException, possibly NullReferenceException if dataIn is null
|
||||||
|
bytesRead = 0;
|
||||||
|
}
|
||||||
|
|
||||||
void IResourceHandler.Cancel(){}
|
return bytesRead > 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool IResourceHandler.Skip(long bytesToSkip, out long bytesSkipped, IResourceSkipCallback callback) {
|
||||||
|
bytesSkipped = -2; // ERR_FAILED
|
||||||
|
callback.Dispose();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool IResourceHandler.ProcessRequest(IRequest request, ICallback callback) {
|
||||||
|
return ((IResourceHandler) this).Open(request, out bool _, callback);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool IResourceHandler.ReadResponse(Stream dataOut, out int bytesRead, ICallback callback) {
|
||||||
|
return ((IResourceHandler) this).Read(dataOut, out bytesRead, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
void IResourceHandler.Cancel() {}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
76
Browser/Handling/ResponseFilter.cs
Normal file
76
Browser/Handling/ResponseFilter.cs
Normal file
@@ -0,0 +1,76 @@
|
|||||||
|
using System;
|
||||||
|
using System.IO;
|
||||||
|
using CefSharp;
|
||||||
|
using TweetLib.Browser.Interfaces;
|
||||||
|
|
||||||
|
namespace TweetDuck.Browser.Handling {
|
||||||
|
sealed class ResponseFilter : IResponseFilter {
|
||||||
|
private enum State {
|
||||||
|
Reading,
|
||||||
|
Writing,
|
||||||
|
Done
|
||||||
|
}
|
||||||
|
|
||||||
|
private readonly IResponseProcessor processor;
|
||||||
|
private byte[] responseData;
|
||||||
|
|
||||||
|
private State state;
|
||||||
|
private int offset;
|
||||||
|
|
||||||
|
public ResponseFilter(IResponseProcessor processor, int totalBytes) {
|
||||||
|
this.processor = processor;
|
||||||
|
this.responseData = new byte[totalBytes];
|
||||||
|
this.state = State.Reading;
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool InitFilter() {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
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 = processor.Process(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 void Dispose() {}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,68 +0,0 @@
|
|||||||
using System;
|
|
||||||
using System.Windows.Forms;
|
|
||||||
using CefSharp;
|
|
||||||
using TweetDuck.Controls;
|
|
||||||
using TweetLib.Core.Features.Notifications;
|
|
||||||
using TweetLib.Core.Features.Plugins;
|
|
||||||
|
|
||||||
namespace TweetDuck.Browser.Notification.Example{
|
|
||||||
sealed class FormNotificationExample : FormNotificationMain{
|
|
||||||
public override bool RequiresResize => true;
|
|
||||||
protected override bool CanDragWindow => Config.NotificationPosition == DesktopNotification.Position.Custom;
|
|
||||||
|
|
||||||
protected override FormBorderStyle NotificationBorderStyle{
|
|
||||||
get{
|
|
||||||
if (Config.NotificationSize == DesktopNotification.Size.Custom){
|
|
||||||
switch(base.NotificationBorderStyle){
|
|
||||||
case FormBorderStyle.FixedSingle: return FormBorderStyle.Sizable;
|
|
||||||
case FormBorderStyle.FixedToolWindow: return FormBorderStyle.SizableToolWindow;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return base.NotificationBorderStyle;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
protected override string BodyClasses => base.BodyClasses + " td-example";
|
|
||||||
|
|
||||||
public event EventHandler Ready;
|
|
||||||
|
|
||||||
private readonly DesktopNotification exampleNotification;
|
|
||||||
|
|
||||||
public FormNotificationExample(FormBrowser owner, PluginManager pluginManager) : base(owner, pluginManager, false){
|
|
||||||
browser.LoadingStateChanged += browser_LoadingStateChanged;
|
|
||||||
|
|
||||||
string exampleTweetHTML = Program.Resources.LoadSilent("pages/example.html")?.Replace("{avatar}", AppLogo.Url) ?? string.Empty;
|
|
||||||
|
|
||||||
#if DEBUG
|
|
||||||
exampleTweetHTML = exampleTweetHTML.Replace("</p>", @"</p><div style='margin-top:256px'>Scrollbar test padding...</div>");
|
|
||||||
#endif
|
|
||||||
|
|
||||||
exampleNotification = new DesktopNotification(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){
|
|
||||||
if (reset){
|
|
||||||
LoadTweet(exampleNotification);
|
|
||||||
}
|
|
||||||
else{
|
|
||||||
PrepareAndDisplayWindow();
|
|
||||||
}
|
|
||||||
|
|
||||||
UpdateTitle();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,254 +1,251 @@
|
|||||||
using System.Drawing;
|
using System.Drawing;
|
||||||
using System.Windows.Forms;
|
using System.Windows.Forms;
|
||||||
using CefSharp;
|
|
||||||
using CefSharp.WinForms;
|
using CefSharp.WinForms;
|
||||||
using TweetDuck.Browser.Data;
|
using TweetDuck.Browser.Adapters;
|
||||||
using TweetDuck.Browser.Handling;
|
using TweetDuck.Browser.Handling;
|
||||||
using TweetDuck.Browser.Handling.General;
|
|
||||||
using TweetDuck.Configuration;
|
using TweetDuck.Configuration;
|
||||||
using TweetDuck.Controls;
|
using TweetDuck.Controls;
|
||||||
using TweetDuck.Management.Analytics;
|
|
||||||
using TweetDuck.Utils;
|
using TweetDuck.Utils;
|
||||||
|
using TweetLib.Browser.Interfaces;
|
||||||
using TweetLib.Core.Features.Notifications;
|
using TweetLib.Core.Features.Notifications;
|
||||||
using TweetLib.Core.Features.Twitter;
|
using TweetLib.Core.Features.Twitter;
|
||||||
|
using TweetLib.Core.Systems.Configuration;
|
||||||
|
|
||||||
namespace TweetDuck.Browser.Notification{
|
namespace TweetDuck.Browser.Notification {
|
||||||
abstract partial class FormNotificationBase : Form, AnalyticsFile.IProvider{
|
abstract partial class FormNotificationBase : Form {
|
||||||
public static readonly ResourceLink AppLogo = new ResourceLink("https://ton.twimg.com/tduck/avatar", ResourceHandler.FromByteArray(Properties.Resources.avatar, "image/png"));
|
protected static UserConfig Config => Program.Config.User;
|
||||||
|
|
||||||
public static string FontSize = null;
|
protected delegate NotificationBrowser CreateBrowserImplFunc(FormNotificationBase form, IBrowserComponent browserComponent);
|
||||||
public static string HeadLayout = null;
|
|
||||||
|
|
||||||
protected static UserConfig Config => Program.Config.User;
|
protected virtual Point PrimaryLocation {
|
||||||
|
get {
|
||||||
protected static int FontSizeLevel{
|
Screen screen;
|
||||||
get => FontSize switch{
|
|
||||||
"largest" => 4,
|
|
||||||
"large" => 3,
|
|
||||||
"small" => 1,
|
|
||||||
"smallest" => 0,
|
|
||||||
_ => 2
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
protected virtual Point PrimaryLocation{
|
if (Config.NotificationDisplay > 0 && Config.NotificationDisplay <= Screen.AllScreens.Length) {
|
||||||
get{
|
screen = Screen.AllScreens[Config.NotificationDisplay - 1];
|
||||||
Screen screen;
|
}
|
||||||
|
else {
|
||||||
|
screen = Screen.FromControl(owner);
|
||||||
|
}
|
||||||
|
|
||||||
if (Config.NotificationDisplay > 0 && Config.NotificationDisplay <= Screen.AllScreens.Length){
|
int edgeDist = Config.NotificationEdgeDistance;
|
||||||
screen = Screen.AllScreens[Config.NotificationDisplay - 1];
|
|
||||||
}
|
|
||||||
else{
|
|
||||||
screen = Screen.FromControl(owner);
|
|
||||||
}
|
|
||||||
|
|
||||||
int edgeDist = Config.NotificationEdgeDistance;
|
|
||||||
|
|
||||||
switch(Config.NotificationPosition){
|
switch (Config.NotificationPosition) {
|
||||||
case DesktopNotification.Position.TopLeft:
|
case DesktopNotification.Position.TopLeft:
|
||||||
return new Point(screen.WorkingArea.X + edgeDist, screen.WorkingArea.Y + edgeDist);
|
return new Point(screen.WorkingArea.X + edgeDist, screen.WorkingArea.Y + edgeDist);
|
||||||
|
|
||||||
case DesktopNotification.Position.TopRight:
|
case DesktopNotification.Position.TopRight:
|
||||||
return new Point(screen.WorkingArea.X + screen.WorkingArea.Width - edgeDist - Width, screen.WorkingArea.Y + edgeDist);
|
return new Point(screen.WorkingArea.X + screen.WorkingArea.Width - edgeDist - Width, screen.WorkingArea.Y + edgeDist);
|
||||||
|
|
||||||
case DesktopNotification.Position.BottomLeft:
|
case DesktopNotification.Position.BottomLeft:
|
||||||
return new Point(screen.WorkingArea.X + edgeDist, screen.WorkingArea.Y + screen.WorkingArea.Height - edgeDist - Height);
|
return new Point(screen.WorkingArea.X + edgeDist, screen.WorkingArea.Y + screen.WorkingArea.Height - edgeDist - Height);
|
||||||
|
|
||||||
case DesktopNotification.Position.BottomRight:
|
case DesktopNotification.Position.BottomRight:
|
||||||
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 DesktopNotification.Position.Custom:
|
case DesktopNotification.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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
protected 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 {
|
||||||
get{
|
get {
|
||||||
return base.Location;
|
return base.Location;
|
||||||
}
|
}
|
||||||
|
|
||||||
set{
|
set {
|
||||||
Visible = (base.Location = value) != ControlExtensions.InvisibleLocation;
|
Visible = (base.Location = value) != ControlExtensions.InvisibleLocation;
|
||||||
FormBorderStyle = NotificationBorderStyle;
|
FormBorderStyle = NotificationBorderStyle;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
protected virtual FormBorderStyle NotificationBorderStyle{
|
protected virtual FormBorderStyle NotificationBorderStyle {
|
||||||
get{
|
get {
|
||||||
if (WindowsUtils.ShouldAvoidToolWindow && Visible){ // Visible = workaround for alt+tab
|
if (WindowsUtils.ShouldAvoidToolWindow && Visible) { // Visible = workaround for alt+tab
|
||||||
return FormBorderStyle.FixedSingle;
|
return FormBorderStyle.FixedSingle;
|
||||||
}
|
}
|
||||||
else{
|
else {
|
||||||
return FormBorderStyle.FixedToolWindow;
|
return FormBorderStyle.FixedToolWindow;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public AnalyticsFile AnalyticsFile => owner.AnalyticsFile;
|
protected override bool ShowWithoutActivation => true;
|
||||||
|
|
||||||
protected override bool ShowWithoutActivation => true;
|
|
||||||
|
|
||||||
protected float DpiScale { get; }
|
|
||||||
protected double SizeScale => DpiScale * Config.ZoomLevel / 100.0;
|
|
||||||
|
|
||||||
protected readonly FormBrowser owner;
|
protected float DpiScale { get; }
|
||||||
|
protected double SizeScale => DpiScale * Config.ZoomLevel / 100.0;
|
||||||
|
|
||||||
#pragma warning disable IDE0069 // Disposable fields should be disposed
|
private readonly FormBrowser owner;
|
||||||
protected readonly ChromiumWebBrowser browser;
|
|
||||||
#pragma warning restore IDE0069 // Disposable fields should be disposed
|
|
||||||
|
|
||||||
private readonly ResourceHandlerNotification resourceHandler = new ResourceHandlerNotification();
|
protected readonly IBrowserComponent browserComponent;
|
||||||
|
private readonly NotificationBrowser browserImpl;
|
||||||
|
|
||||||
private DesktopNotification currentNotification;
|
#pragma warning disable IDE0069 // Disposable fields should be disposed
|
||||||
private int pauseCounter;
|
protected readonly ChromiumWebBrowser browser;
|
||||||
|
#pragma warning restore IDE0069 // Disposable fields should be disposed
|
||||||
public string CurrentTweetUrl => currentNotification?.TweetUrl;
|
|
||||||
public string CurrentQuoteUrl => currentNotification?.QuoteUrl;
|
|
||||||
|
|
||||||
public bool CanViewDetail => currentNotification != null && !string.IsNullOrEmpty(currentNotification.ColumnId) && !string.IsNullOrEmpty(currentNotification.ChirpId);
|
private readonly ResourceHandlerNotification resourceHandler = new ResourceHandlerNotification();
|
||||||
|
|
||||||
protected bool IsPaused => pauseCounter > 0;
|
private DesktopNotification currentNotification;
|
||||||
protected bool IsCursorOverBrowser => browser.Bounds.Contains(PointToClient(Cursor.Position));
|
private int pauseCounter;
|
||||||
|
|
||||||
public bool FreezeTimer { get; set; }
|
|
||||||
public bool ContextMenuOpen { get; set; }
|
|
||||||
|
|
||||||
protected FormNotificationBase(FormBrowser owner, bool enableContextMenu){
|
public string CurrentTweetUrl => currentNotification?.TweetUrl;
|
||||||
InitializeComponent();
|
public string CurrentQuoteUrl => currentNotification?.QuoteUrl;
|
||||||
|
|
||||||
this.owner = owner;
|
protected bool IsPaused => pauseCounter > 0;
|
||||||
this.owner.FormClosed += owner_FormClosed;
|
protected internal bool IsCursorOverBrowser => browser.Bounds.Contains(PointToClient(Cursor.Position));
|
||||||
|
|
||||||
ResourceHandlerFactory resourceHandlerFactory = new ResourceHandlerFactory();
|
public bool FreezeTimer { get; set; }
|
||||||
resourceHandlerFactory.RegisterHandler(TwitterUrls.TweetDeck, this.resourceHandler);
|
public bool ContextMenuOpen { get; set; }
|
||||||
resourceHandlerFactory.RegisterHandler(AppLogo);
|
|
||||||
|
|
||||||
this.browser = new ChromiumWebBrowser("about:blank"){
|
protected FormNotificationBase(FormBrowser owner, CreateBrowserImplFunc createBrowserImpl) {
|
||||||
MenuHandler = new ContextMenuNotification(this, enableContextMenu),
|
InitializeComponent();
|
||||||
JsDialogHandler = new JavaScriptDialogHandler(),
|
|
||||||
LifeSpanHandler = new LifeSpanHandler(),
|
|
||||||
RequestHandler = new RequestHandlerBase(false),
|
|
||||||
ResourceHandlerFactory = resourceHandlerFactory
|
|
||||||
};
|
|
||||||
|
|
||||||
this.browser.Dock = DockStyle.None;
|
this.owner = owner;
|
||||||
this.browser.ClientSize = ClientSize;
|
this.owner.FormClosed += owner_FormClosed;
|
||||||
this.browser.SetupZoomEvents();
|
|
||||||
|
|
||||||
Controls.Add(browser);
|
this.browser = new ChromiumWebBrowser(NotificationBrowser.BlankURL) {
|
||||||
|
RequestHandler = new RequestHandlerBase(false)
|
||||||
|
};
|
||||||
|
|
||||||
Disposed += (sender, args) => {
|
this.browserComponent = new ComponentImpl(browser, this);
|
||||||
this.owner.FormClosed -= owner_FormClosed;
|
this.browserImpl = createBrowserImpl(this, browserComponent);
|
||||||
this.browser.Dispose();
|
|
||||||
};
|
|
||||||
|
|
||||||
DpiScale = this.GetDPIScale();
|
this.browser.Dock = DockStyle.None;
|
||||||
|
this.browser.ClientSize = ClientSize;
|
||||||
|
|
||||||
// ReSharper disable once VirtualMemberCallInContructor
|
Controls.Add(browser);
|
||||||
UpdateTitle();
|
|
||||||
}
|
|
||||||
|
|
||||||
protected override void Dispose(bool disposing){
|
Disposed += (sender, args) => {
|
||||||
if (disposing){
|
this.owner.FormClosed -= owner_FormClosed;
|
||||||
components?.Dispose();
|
this.browserImpl.Dispose();
|
||||||
resourceHandler.Dispose();
|
this.browser.Dispose();
|
||||||
}
|
};
|
||||||
|
|
||||||
base.Dispose(disposing);
|
DpiScale = this.GetDPIScale();
|
||||||
}
|
|
||||||
|
|
||||||
protected override void WndProc(ref Message m){
|
// ReSharper disable once VirtualMemberCallInContructor
|
||||||
if (m.Msg == 0x0112 && (m.WParam.ToInt32() & 0xFFF0) == 0xF010 && !CanDragWindow){ // WM_SYSCOMMAND, SC_MOVE
|
UpdateTitle();
|
||||||
return;
|
}
|
||||||
}
|
|
||||||
|
|
||||||
base.WndProc(ref m);
|
protected sealed class ComponentImpl : CefBrowserComponent {
|
||||||
}
|
private readonly FormNotificationBase owner;
|
||||||
|
|
||||||
// event handlers
|
public ComponentImpl(ChromiumWebBrowser browser, FormNotificationBase owner) : base(browser) {
|
||||||
|
this.owner = owner;
|
||||||
|
}
|
||||||
|
|
||||||
private void owner_FormClosed(object sender, FormClosedEventArgs e){
|
protected override ContextMenuBase SetupContextMenu(IContextMenuHandler handler) {
|
||||||
Close();
|
return new ContextMenuNotification(owner, handler);
|
||||||
}
|
}
|
||||||
|
|
||||||
// notification methods
|
protected override CefResourceHandlerFactory SetupResourceHandlerFactory(IResourceRequestHandler handler) {
|
||||||
|
var registry = new CefResourceHandlerRegistry();
|
||||||
|
registry.RegisterStatic(NotificationBrowser.BlankURL, string.Empty);
|
||||||
|
registry.RegisterDynamic(TwitterUrls.TweetDeck, owner.resourceHandler);
|
||||||
|
return new CefResourceHandlerFactory(handler, registry);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public virtual void HideNotification(){
|
protected override void Dispose(bool disposing) {
|
||||||
browser.Load("about:blank");
|
if (disposing) {
|
||||||
DisplayTooltip(null);
|
components?.Dispose();
|
||||||
|
resourceHandler.Dispose();
|
||||||
|
}
|
||||||
|
|
||||||
Location = ControlExtensions.InvisibleLocation;
|
base.Dispose(disposing);
|
||||||
currentNotification = null;
|
}
|
||||||
}
|
|
||||||
|
|
||||||
public virtual void FinishCurrentNotification(){}
|
protected override void WndProc(ref Message m) {
|
||||||
|
if (m.Msg == 0x0112 && (m.WParam.ToInt32() & 0xFFF0) == 0xF010 && !CanDragWindow) { // WM_SYSCOMMAND, SC_MOVE
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
public virtual void PauseNotification(){
|
base.WndProc(ref m);
|
||||||
if (pauseCounter++ == 0 && IsNotificationVisible){
|
}
|
||||||
Location = ControlExtensions.InvisibleLocation;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public virtual void ResumeNotification(){
|
// event handlers
|
||||||
if (pauseCounter > 0){
|
|
||||||
--pauseCounter;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
protected abstract string GetTweetHTML(DesktopNotification tweet);
|
private void owner_FormClosed(object sender, FormClosedEventArgs e) {
|
||||||
|
Close();
|
||||||
|
}
|
||||||
|
|
||||||
protected virtual void LoadTweet(DesktopNotification tweet){
|
// notification methods
|
||||||
currentNotification = tweet;
|
|
||||||
resourceHandler.SetHTML(GetTweetHTML(tweet));
|
|
||||||
|
|
||||||
browser.Load(TwitterUrls.TweetDeck);
|
public virtual void HideNotification() {
|
||||||
DisplayTooltip(null);
|
browser.Load(NotificationBrowser.BlankURL);
|
||||||
}
|
DisplayTooltip(null);
|
||||||
|
|
||||||
protected virtual void SetNotificationSize(int width, int height){
|
Location = ControlExtensions.InvisibleLocation;
|
||||||
browser.ClientSize = ClientSize = new Size(BrowserUtils.Scale(width, SizeScale), BrowserUtils.Scale(height, SizeScale));
|
currentNotification = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected virtual void UpdateTitle(){
|
public virtual void FinishCurrentNotification() {}
|
||||||
string title = currentNotification?.ColumnTitle;
|
|
||||||
Text = string.IsNullOrEmpty(title) || !Config.DisplayNotificationColumn ? Program.BrandName : $"{Program.BrandName} - {title}";
|
|
||||||
}
|
|
||||||
|
|
||||||
public void ShowTweetDetail(){
|
public virtual void PauseNotification() {
|
||||||
if (currentNotification != null){
|
if (pauseCounter++ == 0 && IsNotificationVisible) {
|
||||||
owner.ShowTweetDetail(currentNotification.ColumnId, currentNotification.ChirpId, currentNotification.TweetUrl);
|
Location = ControlExtensions.InvisibleLocation;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void MoveToVisibleLocation(){
|
public virtual void ResumeNotification() {
|
||||||
bool needsReactivating = Location == ControlExtensions.InvisibleLocation;
|
if (pauseCounter > 0) {
|
||||||
Location = PrimaryLocation;
|
--pauseCounter;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (needsReactivating){
|
protected virtual void LoadTweet(DesktopNotification tweet) {
|
||||||
NativeMethods.SetFormPos(this, NativeMethods.HWND_TOPMOST, NativeMethods.SWP_NOACTIVATE);
|
currentNotification = tweet;
|
||||||
}
|
resourceHandler.SetHTML(browserImpl.GetTweetHTML(tweet));
|
||||||
}
|
|
||||||
|
|
||||||
public void DisplayTooltip(string text){
|
browser.Load(TwitterUrls.TweetDeck);
|
||||||
if (string.IsNullOrEmpty(text)){
|
DisplayTooltip(null);
|
||||||
toolTip.Hide(this);
|
}
|
||||||
}
|
|
||||||
else{
|
protected virtual void SetNotificationSize(int width, int height) {
|
||||||
Point position = PointToClient(Cursor.Position);
|
browser.ClientSize = ClientSize = new Size(BrowserUtils.Scale(width, SizeScale), BrowserUtils.Scale(height, SizeScale));
|
||||||
position.Offset(20, 5);
|
}
|
||||||
toolTip.Show(text, this, position);
|
|
||||||
}
|
protected virtual void UpdateTitle() {
|
||||||
}
|
string title = currentNotification?.ColumnTitle;
|
||||||
}
|
Text = string.IsNullOrEmpty(title) || !Config.DisplayNotificationColumn ? Program.BrandName : $"{Program.BrandName} - {title}";
|
||||||
|
}
|
||||||
|
|
||||||
|
public void ShowTweetDetail() {
|
||||||
|
if (currentNotification != null && owner.ShowTweetDetail(currentNotification.ColumnId, currentNotification.ChirpId, currentNotification.TweetUrl)) {
|
||||||
|
FinishCurrentNotification();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void MoveToVisibleLocation() {
|
||||||
|
bool needsReactivating = Location == ControlExtensions.InvisibleLocation;
|
||||||
|
Location = PrimaryLocation;
|
||||||
|
|
||||||
|
if (needsReactivating) {
|
||||||
|
NativeMethods.SetFormPos(this, NativeMethods.HWND_TOPMOST, NativeMethods.SWP_NOACTIVATE);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void DisplayTooltip(string text) {
|
||||||
|
if (string.IsNullOrEmpty(text)) {
|
||||||
|
toolTip.Hide(this);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
Point position = PointToClient(Cursor.Position);
|
||||||
|
position.Offset(20, 5);
|
||||||
|
toolTip.Show(text, this, position);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
62
Browser/Notification/FormNotificationExample.cs
Normal file
62
Browser/Notification/FormNotificationExample.cs
Normal file
@@ -0,0 +1,62 @@
|
|||||||
|
using System;
|
||||||
|
using System.Windows.Forms;
|
||||||
|
using TweetDuck.Controls;
|
||||||
|
using TweetLib.Browser.Interfaces;
|
||||||
|
using TweetLib.Core.Features.Notifications;
|
||||||
|
using TweetLib.Core.Features.Plugins;
|
||||||
|
using TweetLib.Core.Features.TweetDeck;
|
||||||
|
using TweetLib.Core.Resources;
|
||||||
|
|
||||||
|
namespace TweetDuck.Browser.Notification {
|
||||||
|
sealed class FormNotificationExample : FormNotificationMain {
|
||||||
|
private static NotificationBrowser CreateBrowserImpl(IBrowserComponent browserComponent, INotificationInterface notificationInterface, ITweetDeckInterface tweetDeckInterface, PluginManager pluginManager) {
|
||||||
|
return new NotificationBrowser.Example(browserComponent, notificationInterface, tweetDeckInterface, pluginManager);
|
||||||
|
}
|
||||||
|
|
||||||
|
public override bool RequiresResize => true;
|
||||||
|
protected override bool CanDragWindow => Config.NotificationPosition == DesktopNotification.Position.Custom;
|
||||||
|
|
||||||
|
protected override FormBorderStyle NotificationBorderStyle {
|
||||||
|
get {
|
||||||
|
if (Config.NotificationSize == DesktopNotification.Size.Custom) {
|
||||||
|
switch (base.NotificationBorderStyle) {
|
||||||
|
case FormBorderStyle.FixedSingle: return FormBorderStyle.Sizable;
|
||||||
|
case FormBorderStyle.FixedToolWindow: return FormBorderStyle.SizableToolWindow;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return base.NotificationBorderStyle;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public event EventHandler Ready;
|
||||||
|
|
||||||
|
private readonly DesktopNotification exampleNotification;
|
||||||
|
|
||||||
|
public FormNotificationExample(FormBrowser owner, ITweetDeckInterface tweetDeckInterface, PluginManager pluginManager) : base(owner, (form, browserComponent) => CreateBrowserImpl(browserComponent, new NotificationInterfaceImpl(form), tweetDeckInterface, pluginManager)) {
|
||||||
|
browserComponent.BrowserLoaded += (sender, args) => {
|
||||||
|
Ready?.Invoke(this, EventArgs.Empty);
|
||||||
|
};
|
||||||
|
|
||||||
|
string exampleTweetHTML = ResourceUtils.ReadFileOrNull("notification/example/example.html") ?? string.Empty;
|
||||||
|
exampleNotification = new DesktopNotification(string.Empty, string.Empty, "Home", exampleTweetHTML, 176, string.Empty, string.Empty);
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void HideNotification() {
|
||||||
|
Location = ControlExtensions.InvisibleLocation;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void FinishCurrentNotification() {}
|
||||||
|
|
||||||
|
public void ShowExampleNotification(bool reset) {
|
||||||
|
if (reset) {
|
||||||
|
LoadTweet(exampleNotification);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
PrepareAndDisplayWindow();
|
||||||
|
}
|
||||||
|
|
||||||
|
UpdateTitle();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -2,289 +2,317 @@
|
|||||||
using System.Drawing;
|
using System.Drawing;
|
||||||
using System.Windows.Forms;
|
using System.Windows.Forms;
|
||||||
using CefSharp;
|
using CefSharp;
|
||||||
using TweetDuck.Browser.Adapters;
|
|
||||||
using TweetDuck.Browser.Bridge;
|
|
||||||
using TweetDuck.Browser.Handling;
|
using TweetDuck.Browser.Handling;
|
||||||
using TweetDuck.Controls;
|
using TweetDuck.Controls;
|
||||||
using TweetDuck.Plugins;
|
|
||||||
using TweetDuck.Utils;
|
using TweetDuck.Utils;
|
||||||
using TweetLib.Core.Data;
|
|
||||||
using TweetLib.Core.Features.Notifications;
|
using TweetLib.Core.Features.Notifications;
|
||||||
using TweetLib.Core.Features.Plugins;
|
|
||||||
using TweetLib.Core.Features.Plugins.Enums;
|
|
||||||
|
|
||||||
namespace TweetDuck.Browser.Notification{
|
namespace TweetDuck.Browser.Notification {
|
||||||
abstract partial class FormNotificationMain : FormNotificationBase{
|
abstract partial class FormNotificationMain : FormNotificationBase, CustomKeyboardHandler.IBrowserKeyHandler {
|
||||||
private readonly PluginManager plugins;
|
protected sealed class NotificationInterfaceImpl : INotificationInterface {
|
||||||
private readonly int timerBarHeight;
|
public bool FreezeTimer {
|
||||||
|
get => notification.FreezeTimer;
|
||||||
|
set => notification.FreezeTimer = value;
|
||||||
|
}
|
||||||
|
|
||||||
protected int timeLeft, totalTime;
|
public bool IsHovered => notification.IsCursorOverBrowser;
|
||||||
protected bool pausedDuringNotification;
|
|
||||||
|
|
||||||
private readonly NativeMethods.HookProc mouseHookDelegate;
|
|
||||||
private IntPtr mouseHook;
|
|
||||||
private bool blockXButtonUp;
|
|
||||||
|
|
||||||
private int currentOpacity;
|
private readonly FormNotificationBase notification;
|
||||||
|
|
||||||
private bool? prevDisplayTimer;
|
public NotificationInterfaceImpl(FormNotificationBase notification) {
|
||||||
private int? prevFontSize;
|
this.notification = notification;
|
||||||
|
}
|
||||||
|
|
||||||
public virtual bool RequiresResize{
|
public void DisplayTooltip(string text) {
|
||||||
get{
|
notification.InvokeAsyncSafe(() => notification.DisplayTooltip(text));
|
||||||
return !prevDisplayTimer.HasValue || !prevFontSize.HasValue || prevDisplayTimer != Config.DisplayNotificationTimer || prevFontSize != FontSizeLevel;
|
}
|
||||||
}
|
|
||||||
|
|
||||||
set{
|
public void FinishCurrentNotification() {
|
||||||
if (value){
|
notification.InvokeAsyncSafe(notification.FinishCurrentNotification);
|
||||||
prevDisplayTimer = null;
|
}
|
||||||
prevFontSize = null;
|
|
||||||
}
|
|
||||||
else{
|
|
||||||
prevDisplayTimer = Config.DisplayNotificationTimer;
|
|
||||||
prevFontSize = FontSizeLevel;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private int BaseClientWidth{
|
public void ShowTweetDetail() {
|
||||||
get => Config.NotificationSize switch{
|
notification.InvokeAsyncSafe(notification.ShowTweetDetail);
|
||||||
DesktopNotification.Size.Custom => Config.CustomNotificationSize.Width,
|
}
|
||||||
_ => BrowserUtils.Scale(284, SizeScale * (1.0 + 0.05 * FontSizeLevel))
|
}
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
private int BaseClientHeight{
|
private static int FontSizeLevel {
|
||||||
get => Config.NotificationSize switch{
|
get => NotificationBrowser.FontSize switch {
|
||||||
DesktopNotification.Size.Custom => Config.CustomNotificationSize.Height,
|
"largest" => 4,
|
||||||
_ => BrowserUtils.Scale(122, SizeScale * (1.0 + 0.08 * FontSizeLevel))
|
"large" => 3,
|
||||||
};
|
"small" => 1,
|
||||||
}
|
"smallest" => 0,
|
||||||
|
_ => 2
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
protected virtual string BodyClasses => IsCursorOverBrowser ? "td-notification td-hover" : "td-notification";
|
private readonly int timerBarHeight;
|
||||||
|
|
||||||
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 int timeLeft, totalTime;
|
||||||
InitializeComponent();
|
protected bool pausedDuringNotification;
|
||||||
|
|
||||||
this.plugins = pluginManager;
|
private readonly NativeMethods.HookProc mouseHookDelegate;
|
||||||
this.timerBarHeight = BrowserUtils.Scale(4, DpiScale);
|
private IntPtr mouseHook;
|
||||||
|
private bool blockXButtonUp;
|
||||||
browser.KeyboardHandler = new KeyboardHandlerNotification(this);
|
|
||||||
browser.RegisterAsyncJsObject("$TD", new TweetDeckBridge.Notification(owner, this));
|
|
||||||
|
|
||||||
browser.LoadingStateChanged += Browser_LoadingStateChanged;
|
private int currentOpacity;
|
||||||
browser.FrameLoadEnd += Browser_FrameLoadEnd;
|
|
||||||
|
|
||||||
plugins.Register(PluginEnvironment.Notification, new PluginDispatcher(browser));
|
private bool? prevDisplayTimer;
|
||||||
|
private int? prevFontSize;
|
||||||
|
|
||||||
mouseHookDelegate = MouseHookProc;
|
public virtual bool RequiresResize {
|
||||||
Disposed += (sender, args) => StopMouseHook(true);
|
get {
|
||||||
}
|
return !prevDisplayTimer.HasValue || !prevFontSize.HasValue || prevDisplayTimer != Config.DisplayNotificationTimer || prevFontSize != FontSizeLevel;
|
||||||
|
}
|
||||||
|
|
||||||
// helpers
|
set {
|
||||||
|
if (value) {
|
||||||
|
prevDisplayTimer = null;
|
||||||
|
prevFontSize = null;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
prevDisplayTimer = Config.DisplayNotificationTimer;
|
||||||
|
prevFontSize = FontSizeLevel;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private void SetOpacity(int opacity){
|
private int BaseClientWidth {
|
||||||
if (currentOpacity != opacity){
|
get => Config.NotificationSize switch {
|
||||||
currentOpacity = opacity;
|
DesktopNotification.Size.Custom => Config.CustomNotificationSize.Width,
|
||||||
Opacity = opacity / 100.0;
|
_ => BrowserUtils.Scale(284, SizeScale * (1.0 + 0.05 * FontSizeLevel))
|
||||||
}
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
// mouse wheel hook
|
private int BaseClientHeight {
|
||||||
|
get => Config.NotificationSize switch {
|
||||||
|
DesktopNotification.Size.Custom => Config.CustomNotificationSize.Height,
|
||||||
|
_ => BrowserUtils.Scale(122, SizeScale * (1.0 + 0.08 * FontSizeLevel))
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
private void StartMouseHook(){
|
public Size BrowserSize => Config.DisplayNotificationTimer ? new Size(ClientSize.Width, ClientSize.Height - timerBarHeight) : ClientSize;
|
||||||
if (mouseHook == IntPtr.Zero){
|
|
||||||
mouseHook = NativeMethods.SetWindowsHookEx(NativeMethods.WM_MOUSE_LL, mouseHookDelegate, IntPtr.Zero, 0);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void StopMouseHook(bool force){
|
protected FormNotificationMain(FormBrowser owner, CreateBrowserImplFunc createBrowserImpl) : base(owner, createBrowserImpl) {
|
||||||
if (mouseHook != IntPtr.Zero && (force || !blockXButtonUp)){
|
InitializeComponent();
|
||||||
NativeMethods.UnhookWindowsHookEx(mouseHook);
|
|
||||||
mouseHook = IntPtr.Zero;
|
|
||||||
blockXButtonUp = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private IntPtr MouseHookProc(int nCode, IntPtr wParam, IntPtr lParam){
|
this.timerBarHeight = BrowserUtils.Scale(4, DpiScale);
|
||||||
if (nCode == 0){
|
|
||||||
int eventType = wParam.ToInt32();
|
|
||||||
|
|
||||||
if (eventType == NativeMethods.WM_MOUSEWHEEL && IsCursorOverBrowser){
|
browser.KeyboardHandler = new CustomKeyboardHandler(this);
|
||||||
browser.SendMouseWheelEvent(0, 0, 0, BrowserUtils.Scale(NativeMethods.GetMouseHookData(lParam), Config.NotificationScrollSpeed * 0.01), CefEventFlags.None);
|
|
||||||
return NativeMethods.HOOK_HANDLED;
|
|
||||||
}
|
|
||||||
else if (eventType == NativeMethods.WM_XBUTTONDOWN && DesktopBounds.Contains(Cursor.Position)){
|
|
||||||
int extraButton = NativeMethods.GetMouseHookData(lParam);
|
|
||||||
|
|
||||||
if (extraButton == 2){ // forward button
|
browser.LoadingStateChanged += Browser_LoadingStateChanged;
|
||||||
this.InvokeAsyncSafe(FinishCurrentNotification);
|
|
||||||
}
|
|
||||||
else if (extraButton == 1){ // back button
|
|
||||||
this.InvokeAsyncSafe(Close);
|
|
||||||
}
|
|
||||||
|
|
||||||
blockXButtonUp = true;
|
|
||||||
this.InvokeAsyncSafe(AnalyticsFile.NotificationExtraMouseButtons.Trigger);
|
|
||||||
return NativeMethods.HOOK_HANDLED;
|
|
||||||
}
|
|
||||||
else if (eventType == NativeMethods.WM_XBUTTONUP && blockXButtonUp){
|
|
||||||
blockXButtonUp = false;
|
|
||||||
|
|
||||||
if (!Visible){
|
mouseHookDelegate = MouseHookProc;
|
||||||
StopMouseHook(false);
|
Disposed += (sender, args) => StopMouseHook(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
return NativeMethods.HOOK_HANDLED;
|
private void SetOpacity(int opacity) {
|
||||||
}
|
if (currentOpacity != opacity) {
|
||||||
}
|
currentOpacity = opacity;
|
||||||
|
Opacity = opacity / 100.0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return NativeMethods.CallNextHookEx(mouseHook, nCode, wParam, lParam);
|
// mouse wheel hook
|
||||||
}
|
|
||||||
|
|
||||||
// event handlers
|
private void StartMouseHook() {
|
||||||
|
if (mouseHook == IntPtr.Zero) {
|
||||||
|
mouseHook = NativeMethods.SetWindowsHookEx(NativeMethods.WM_MOUSE_LL, mouseHookDelegate, IntPtr.Zero, 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private void FormNotification_FormClosing(object sender, FormClosingEventArgs e){
|
private void StopMouseHook(bool force) {
|
||||||
if (e.CloseReason == CloseReason.UserClosing){
|
if (mouseHook != IntPtr.Zero && (force || !blockXButtonUp)) {
|
||||||
HideNotification();
|
NativeMethods.UnhookWindowsHookEx(mouseHook);
|
||||||
e.Cancel = true;
|
mouseHook = IntPtr.Zero;
|
||||||
}
|
blockXButtonUp = false;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private void Browser_LoadingStateChanged(object sender, LoadingStateChangedEventArgs e){
|
private IntPtr MouseHookProc(int nCode, IntPtr wParam, IntPtr lParam) {
|
||||||
if (!e.IsLoading && browser.Address != "about:blank"){
|
if (nCode == 0) {
|
||||||
this.InvokeSafe(() => {
|
int eventType = wParam.ToInt32();
|
||||||
Visible = true; // ensures repaint before moving the window to a visible location
|
|
||||||
timerDisplayDelay.Start();
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void Browser_FrameLoadEnd(object sender, FrameLoadEndEventArgs e){
|
if (eventType == NativeMethods.WM_MOUSEWHEEL && IsCursorOverBrowser) {
|
||||||
IFrame frame = e.Frame;
|
int delta = BrowserUtils.Scale(NativeMethods.GetMouseHookData(lParam), Config.NotificationScrollSpeed * 0.01);
|
||||||
|
|
||||||
if (frame.IsMain && browser.Address != "about:blank"){
|
if (Config.EnableSmoothScrolling) {
|
||||||
frame.ExecuteJavaScriptAsync(PropertyBridge.GenerateScript(PropertyBridge.Environment.Notification));
|
browser.BrowserCore.ExecuteScriptAsync("window.TDGF_scrollSmoothly", (int) Math.Round(-delta / 0.6));
|
||||||
CefScriptExecutor.RunFile(frame, "notification.js");
|
}
|
||||||
}
|
else {
|
||||||
}
|
browser.SendMouseWheelEvent(0, 0, 0, delta, CefEventFlags.None);
|
||||||
|
}
|
||||||
|
|
||||||
private void timerDisplayDelay_Tick(object sender, EventArgs e){
|
return NativeMethods.HOOK_HANDLED;
|
||||||
OnNotificationReady();
|
}
|
||||||
timerDisplayDelay.Stop();
|
else if (eventType == NativeMethods.WM_XBUTTONDOWN && DesktopBounds.Contains(Cursor.Position)) {
|
||||||
}
|
int extraButton = NativeMethods.GetMouseHookData(lParam);
|
||||||
|
|
||||||
private void timerHideProgress_Tick(object sender, EventArgs e){
|
if (extraButton == 2) { // forward button
|
||||||
bool isCursorInside = Bounds.Contains(Cursor.Position);
|
this.InvokeAsyncSafe(FinishCurrentNotification);
|
||||||
|
}
|
||||||
|
else if (extraButton == 1) { // back button
|
||||||
|
this.InvokeAsyncSafe(Close);
|
||||||
|
}
|
||||||
|
|
||||||
if (isCursorInside){
|
blockXButtonUp = true;
|
||||||
StartMouseHook();
|
return NativeMethods.HOOK_HANDLED;
|
||||||
SetOpacity(100);
|
}
|
||||||
}
|
else if (eventType == NativeMethods.WM_XBUTTONUP && blockXButtonUp) {
|
||||||
else{
|
blockXButtonUp = false;
|
||||||
StopMouseHook(false);
|
|
||||||
SetOpacity(Config.NotificationWindowOpacity);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (isCursorInside || FreezeTimer || ContextMenuOpen){
|
if (!Visible) {
|
||||||
return;
|
StopMouseHook(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
timeLeft -= timerProgress.Interval;
|
return NativeMethods.HOOK_HANDLED;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
int value = BrowserUtils.Scale(progressBarTimer.Maximum + 25, (totalTime - timeLeft) / (double)totalTime);
|
return NativeMethods.CallNextHookEx(mouseHook, nCode, wParam, lParam);
|
||||||
progressBarTimer.SetValueInstant(Config.NotificationTimerCountDown ? progressBarTimer.Maximum - value : value);
|
}
|
||||||
|
|
||||||
if (timeLeft <= 0){
|
// event handlers
|
||||||
FinishCurrentNotification();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// notification methods
|
private void FormNotification_FormClosing(object sender, FormClosingEventArgs e) {
|
||||||
|
if (e.CloseReason == CloseReason.UserClosing) {
|
||||||
|
HideNotification();
|
||||||
|
e.Cancel = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public virtual void ShowNotification(DesktopNotification notification){
|
private void Browser_LoadingStateChanged(object sender, LoadingStateChangedEventArgs e) {
|
||||||
LoadTweet(notification);
|
if (!e.IsLoading && browser.Address != NotificationBrowser.BlankURL) {
|
||||||
}
|
this.InvokeSafe(() => {
|
||||||
|
Visible = true; // ensures repaint before moving the window to a visible location
|
||||||
|
timerDisplayDelay.Start();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public override void HideNotification(){
|
private void timerDisplayDelay_Tick(object sender, EventArgs e) {
|
||||||
base.HideNotification();
|
OnNotificationReady();
|
||||||
|
timerDisplayDelay.Stop();
|
||||||
progressBarTimer.Value = Config.NotificationTimerCountDown ? progressBarTimer.Maximum : progressBarTimer.Minimum;
|
}
|
||||||
timerProgress.Stop();
|
|
||||||
totalTime = 0;
|
|
||||||
|
|
||||||
StopMouseHook(false);
|
private void timerHideProgress_Tick(object sender, EventArgs e) {
|
||||||
}
|
bool isCursorInside = Bounds.Contains(Cursor.Position);
|
||||||
|
|
||||||
public override void FinishCurrentNotification(){
|
if (isCursorInside) {
|
||||||
timerProgress.Stop();
|
StartMouseHook();
|
||||||
}
|
SetOpacity(100);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
StopMouseHook(false);
|
||||||
|
SetOpacity(Config.NotificationWindowOpacity);
|
||||||
|
}
|
||||||
|
|
||||||
public override void PauseNotification(){
|
if (isCursorInside || FreezeTimer || ContextMenuOpen) {
|
||||||
if (!IsPaused){
|
return;
|
||||||
pausedDuringNotification = IsNotificationVisible;
|
}
|
||||||
timerProgress.Stop();
|
|
||||||
StopMouseHook(true);
|
|
||||||
}
|
|
||||||
|
|
||||||
base.PauseNotification();
|
timeLeft -= timerProgress.Interval;
|
||||||
}
|
|
||||||
|
|
||||||
public override void ResumeNotification(){
|
int value = BrowserUtils.Scale(progressBarTimer.Maximum + 25, (totalTime - timeLeft) / (double) totalTime);
|
||||||
bool wasPaused = IsPaused;
|
progressBarTimer.SetValueInstant(Config.NotificationTimerCountDown ? progressBarTimer.Maximum - value : value);
|
||||||
base.ResumeNotification();
|
|
||||||
|
|
||||||
if (wasPaused && !IsPaused && pausedDuringNotification){
|
if (timeLeft <= 0) {
|
||||||
OnNotificationReady();
|
FinishCurrentNotification();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override string GetTweetHTML(DesktopNotification tweet){
|
// notification methods
|
||||||
string html = tweet.GenerateHtml(BodyClasses, HeadLayout, Config.CustomNotificationCSS);
|
|
||||||
|
|
||||||
foreach(InjectedHTML injection in plugins.NotificationInjections){
|
public virtual void ShowNotification(DesktopNotification notification) {
|
||||||
html = injection.InjectInto(html);
|
LoadTweet(notification);
|
||||||
}
|
}
|
||||||
|
|
||||||
return html;
|
public override void HideNotification() {
|
||||||
}
|
base.HideNotification();
|
||||||
|
|
||||||
protected override void LoadTweet(DesktopNotification tweet){
|
progressBarTimer.Value = Config.NotificationTimerCountDown ? progressBarTimer.Maximum : progressBarTimer.Minimum;
|
||||||
timerProgress.Stop();
|
timerProgress.Stop();
|
||||||
totalTime = timeLeft = tweet.GetDisplayDuration(Config.NotificationDurationValue);
|
totalTime = 0;
|
||||||
progressBarTimer.Value = Config.NotificationTimerCountDown ? progressBarTimer.Maximum : progressBarTimer.Minimum;
|
|
||||||
|
|
||||||
base.LoadTweet(tweet);
|
StopMouseHook(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void SetNotificationSize(int width, int height){
|
public override void FinishCurrentNotification() {
|
||||||
if (Config.DisplayNotificationTimer){
|
timerProgress.Stop();
|
||||||
ClientSize = new Size(width, height + timerBarHeight);
|
}
|
||||||
progressBarTimer.Visible = true;
|
|
||||||
}
|
|
||||||
else{
|
|
||||||
ClientSize = new Size(width, height);
|
|
||||||
progressBarTimer.Visible = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
browser.ClientSize = new Size(width, height);
|
public override void PauseNotification() {
|
||||||
}
|
if (!IsPaused) {
|
||||||
|
pausedDuringNotification = IsNotificationVisible;
|
||||||
protected void PrepareAndDisplayWindow(){
|
timerProgress.Stop();
|
||||||
if (RequiresResize){
|
StopMouseHook(true);
|
||||||
RequiresResize = false;
|
}
|
||||||
SetNotificationSize(BaseClientWidth, BaseClientHeight);
|
|
||||||
}
|
|
||||||
|
|
||||||
SetOpacity(IsCursorOverBrowser ? 100 : Config.NotificationWindowOpacity);
|
base.PauseNotification();
|
||||||
MoveToVisibleLocation();
|
}
|
||||||
}
|
|
||||||
|
|
||||||
protected virtual void OnNotificationReady(){
|
public override void ResumeNotification() {
|
||||||
PrepareAndDisplayWindow();
|
bool wasPaused = IsPaused;
|
||||||
timerProgress.Start();
|
base.ResumeNotification();
|
||||||
}
|
|
||||||
}
|
if (wasPaused && !IsPaused && pausedDuringNotification) {
|
||||||
|
OnNotificationReady();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void LoadTweet(DesktopNotification tweet) {
|
||||||
|
timerProgress.Stop();
|
||||||
|
totalTime = timeLeft = tweet.GetDisplayDuration(Config.NotificationDurationValue);
|
||||||
|
progressBarTimer.Value = Config.NotificationTimerCountDown ? progressBarTimer.Maximum : progressBarTimer.Minimum;
|
||||||
|
|
||||||
|
base.LoadTweet(tweet);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void SetNotificationSize(int width, int height) {
|
||||||
|
if (Config.DisplayNotificationTimer) {
|
||||||
|
ClientSize = new Size(width, height + timerBarHeight);
|
||||||
|
progressBarTimer.Visible = true;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
ClientSize = new Size(width, height);
|
||||||
|
progressBarTimer.Visible = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
browser.ClientSize = new Size(width, height);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void PrepareAndDisplayWindow() {
|
||||||
|
if (RequiresResize) {
|
||||||
|
RequiresResize = false;
|
||||||
|
SetNotificationSize(BaseClientWidth, BaseClientHeight);
|
||||||
|
}
|
||||||
|
|
||||||
|
SetOpacity(IsCursorOverBrowser ? 100 : Config.NotificationWindowOpacity);
|
||||||
|
MoveToVisibleLocation();
|
||||||
|
}
|
||||||
|
|
||||||
|
protected virtual void OnNotificationReady() {
|
||||||
|
PrepareAndDisplayWindow();
|
||||||
|
timerProgress.Start();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool CustomKeyboardHandler.IBrowserKeyHandler.HandleBrowserKey(Keys key) {
|
||||||
|
switch (key) {
|
||||||
|
case Keys.Enter:
|
||||||
|
this.InvokeAsyncSafe(FinishCurrentNotification);
|
||||||
|
return true;
|
||||||
|
|
||||||
|
case Keys.Escape:
|
||||||
|
this.InvokeAsyncSafe(HideNotification);
|
||||||
|
return true;
|
||||||
|
|
||||||
|
case Keys.Space:
|
||||||
|
this.InvokeAsyncSafe(() => FreezeTimer = !FreezeTimer);
|
||||||
|
return true;
|
||||||
|
|
||||||
|
default:
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,164 +3,169 @@ using System.Collections.Generic;
|
|||||||
using System.Drawing;
|
using System.Drawing;
|
||||||
using System.Windows.Forms;
|
using System.Windows.Forms;
|
||||||
using TweetDuck.Utils;
|
using TweetDuck.Utils;
|
||||||
|
using TweetLib.Browser.Interfaces;
|
||||||
using TweetLib.Core.Features.Notifications;
|
using TweetLib.Core.Features.Notifications;
|
||||||
using TweetLib.Core.Features.Plugins;
|
using TweetLib.Core.Features.Plugins;
|
||||||
|
using TweetLib.Core.Features.TweetDeck;
|
||||||
|
|
||||||
namespace TweetDuck.Browser.Notification{
|
namespace TweetDuck.Browser.Notification {
|
||||||
sealed partial class FormNotificationTweet : FormNotificationMain{
|
sealed partial class FormNotificationTweet : FormNotificationMain {
|
||||||
private const int NonIntrusiveIdleLimit = 30;
|
private static NotificationBrowser CreateBrowserImpl(IBrowserComponent browserComponent, INotificationInterface notificationInterface, ITweetDeckInterface tweetDeckInterface, PluginManager pluginManager) {
|
||||||
private const int TrimMinimum = 32;
|
return new NotificationBrowser.Tweet(browserComponent, notificationInterface, tweetDeckInterface, pluginManager);
|
||||||
|
}
|
||||||
|
|
||||||
protected override Point PrimaryLocation => hasTemporarilyMoved && IsNotificationVisible ? Location : base.PrimaryLocation;
|
private const int NonIntrusiveIdleLimit = 30;
|
||||||
private bool IsCursorOverNotificationArea => new Rectangle(PrimaryLocation, Size).Contains(Cursor.Position);
|
private const int TrimMinimum = 32;
|
||||||
|
|
||||||
protected override bool CanDragWindow{
|
protected override Point PrimaryLocation => hasTemporarilyMoved && IsNotificationVisible ? Location : base.PrimaryLocation;
|
||||||
get{
|
private bool IsCursorOverNotificationArea => new Rectangle(PrimaryLocation, Size).Contains(Cursor.Position);
|
||||||
if (ModifierKeys.HasFlag(Keys.Alt)){
|
|
||||||
hasTemporarilyMoved = true;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
else{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private readonly Queue<DesktopNotification> tweetQueue = new Queue<DesktopNotification>(4);
|
protected override bool CanDragWindow {
|
||||||
private bool needsTrim;
|
get {
|
||||||
private bool hasTemporarilyMoved;
|
if (ModifierKeys.HasFlag(Keys.Alt)) {
|
||||||
|
hasTemporarilyMoved = true;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public FormNotificationTweet(FormBrowser owner, PluginManager pluginManager) : base(owner, pluginManager, true){
|
private readonly Queue<DesktopNotification> tweetQueue = new Queue<DesktopNotification>(4);
|
||||||
InitializeComponent();
|
private bool needsTrim;
|
||||||
|
private bool hasTemporarilyMoved;
|
||||||
|
|
||||||
Config.MuteToggled += Config_MuteToggled;
|
public FormNotificationTweet(FormBrowser owner, ITweetDeckInterface tweetDeckInterface, PluginManager pluginManager) : base(owner, (form, browserComponent) => CreateBrowserImpl(browserComponent, new NotificationInterfaceImpl(form), tweetDeckInterface, pluginManager)) {
|
||||||
Disposed += (sender, args) => Config.MuteToggled -= Config_MuteToggled;
|
InitializeComponent();
|
||||||
|
|
||||||
if (Config.MuteNotifications){
|
Config.MuteToggled += Config_MuteToggled;
|
||||||
PauseNotification();
|
Disposed += (sender, args) => Config.MuteToggled -= Config_MuteToggled;
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
protected override void WndProc(ref Message m){
|
if (Config.MuteNotifications) {
|
||||||
if (m.Msg == 0x00A7){ // WM_NCMBUTTONDOWN
|
PauseNotification();
|
||||||
int hitTest = m.WParam.ToInt32();
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (hitTest == 2 || hitTest == 20){ // HTCAPTION, HTCLOSE
|
protected override void WndProc(ref Message m) {
|
||||||
hasTemporarilyMoved = false;
|
if (m.Msg == 0x00A7) { // WM_NCMBUTTONDOWN
|
||||||
MoveToVisibleLocation();
|
int hitTest = m.WParam.ToInt32();
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
base.WndProc(ref m);
|
if (hitTest == 2 || hitTest == 20) { // HTCAPTION, HTCLOSE
|
||||||
}
|
hasTemporarilyMoved = false;
|
||||||
|
MoveToVisibleLocation();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// event handlers
|
base.WndProc(ref m);
|
||||||
|
}
|
||||||
|
|
||||||
private void Config_MuteToggled(object sender, EventArgs e){
|
// event handlers
|
||||||
if (Config.MuteNotifications){
|
|
||||||
PauseNotification();
|
|
||||||
}
|
|
||||||
else{
|
|
||||||
ResumeNotification();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void timerCursorCheck_Tick(object sender, EventArgs e){
|
private void Config_MuteToggled(object sender, EventArgs e) {
|
||||||
if (!IsCursorOverNotificationArea){
|
if (Config.MuteNotifications) {
|
||||||
ResumeNotification();
|
PauseNotification();
|
||||||
timerCursorCheck.Stop();
|
}
|
||||||
}
|
else {
|
||||||
}
|
ResumeNotification();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private void timerIdlePauseCheck_Tick(object sender, EventArgs e){
|
private void timerCursorCheck_Tick(object sender, EventArgs e) {
|
||||||
if (NativeMethods.GetIdleSeconds() < Config.NotificationIdlePauseSeconds){
|
if (!IsCursorOverNotificationArea) {
|
||||||
ResumeNotification();
|
ResumeNotification();
|
||||||
timerIdlePauseCheck.Stop();
|
timerCursorCheck.Stop();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// notification methods
|
private void timerIdlePauseCheck_Tick(object sender, EventArgs e) {
|
||||||
|
if (NativeMethods.GetIdleSeconds() < Config.NotificationIdlePauseSeconds) {
|
||||||
|
ResumeNotification();
|
||||||
|
timerIdlePauseCheck.Stop();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public override void ShowNotification(DesktopNotification notification){
|
// notification methods
|
||||||
tweetQueue.Enqueue(notification);
|
|
||||||
|
|
||||||
if (!IsPaused){
|
|
||||||
UpdateTitle();
|
|
||||||
|
|
||||||
if (totalTime == 0){
|
public override void ShowNotification(DesktopNotification notification) {
|
||||||
LoadNextNotification();
|
tweetQueue.Enqueue(notification);
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
needsTrim |= tweetQueue.Count >= TrimMinimum;
|
if (!IsPaused) {
|
||||||
AnalyticsFile.DesktopNotifications.Trigger();
|
UpdateTitle();
|
||||||
}
|
|
||||||
|
|
||||||
public override void HideNotification(){
|
if (totalTime == 0) {
|
||||||
base.HideNotification();
|
LoadNextNotification();
|
||||||
tweetQueue.Clear();
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (needsTrim){
|
needsTrim |= tweetQueue.Count >= TrimMinimum;
|
||||||
tweetQueue.TrimExcess();
|
}
|
||||||
needsTrim = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
hasTemporarilyMoved = false;
|
public override void HideNotification() {
|
||||||
}
|
base.HideNotification();
|
||||||
|
tweetQueue.Clear();
|
||||||
|
|
||||||
public override void FinishCurrentNotification(){
|
if (needsTrim) {
|
||||||
if (tweetQueue.Count > 0){
|
tweetQueue.TrimExcess();
|
||||||
LoadNextNotification();
|
needsTrim = false;
|
||||||
}
|
}
|
||||||
else{
|
|
||||||
HideNotification();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public override void ResumeNotification(){
|
hasTemporarilyMoved = false;
|
||||||
bool wasPaused = IsPaused;
|
}
|
||||||
base.ResumeNotification();
|
|
||||||
|
|
||||||
if (wasPaused && !IsPaused && !pausedDuringNotification && tweetQueue.Count > 0){
|
public override void FinishCurrentNotification() {
|
||||||
LoadNextNotification();
|
if (tweetQueue.Count > 0) {
|
||||||
}
|
LoadNextNotification();
|
||||||
}
|
}
|
||||||
|
else {
|
||||||
|
HideNotification();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private void LoadNextNotification(){
|
public override void ResumeNotification() {
|
||||||
if (!IsNotificationVisible){
|
bool wasPaused = IsPaused;
|
||||||
if (Config.NotificationNonIntrusiveMode && IsCursorOverNotificationArea && NativeMethods.GetIdleSeconds() < NonIntrusiveIdleLimit){
|
base.ResumeNotification();
|
||||||
if (!timerCursorCheck.Enabled){
|
|
||||||
PauseNotification();
|
|
||||||
timerCursorCheck.Start();
|
|
||||||
}
|
|
||||||
|
|
||||||
return;
|
if (wasPaused && !IsPaused && !pausedDuringNotification && tweetQueue.Count > 0) {
|
||||||
}
|
LoadNextNotification();
|
||||||
else if (Config.NotificationIdlePauseSeconds > 0 && NativeMethods.GetIdleSeconds() >= Config.NotificationIdlePauseSeconds){
|
}
|
||||||
if (!timerIdlePauseCheck.Enabled){
|
}
|
||||||
PauseNotification();
|
|
||||||
timerIdlePauseCheck.Start();
|
|
||||||
}
|
|
||||||
|
|
||||||
return;
|
private void LoadNextNotification() {
|
||||||
}
|
if (!IsNotificationVisible) {
|
||||||
}
|
if (Config.NotificationNonIntrusiveMode && IsCursorOverNotificationArea && NativeMethods.GetIdleSeconds() < NonIntrusiveIdleLimit) {
|
||||||
|
if (!timerCursorCheck.Enabled) {
|
||||||
LoadTweet(tweetQueue.Dequeue());
|
PauseNotification();
|
||||||
}
|
timerCursorCheck.Start();
|
||||||
|
}
|
||||||
|
|
||||||
protected override void UpdateTitle(){
|
return;
|
||||||
base.UpdateTitle();
|
}
|
||||||
|
else if (Config.NotificationIdlePauseSeconds > 0 && NativeMethods.GetIdleSeconds() >= Config.NotificationIdlePauseSeconds) {
|
||||||
|
if (!timerIdlePauseCheck.Enabled) {
|
||||||
|
PauseNotification();
|
||||||
|
timerIdlePauseCheck.Start();
|
||||||
|
}
|
||||||
|
|
||||||
if (tweetQueue.Count > 0){
|
return;
|
||||||
Text = Text + " (" + tweetQueue.Count + " more left)";
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
protected override void OnNotificationReady(){
|
LoadTweet(tweetQueue.Dequeue());
|
||||||
UpdateTitle();
|
}
|
||||||
base.OnNotificationReady();
|
|
||||||
}
|
protected override void UpdateTitle() {
|
||||||
}
|
base.UpdateTitle();
|
||||||
|
|
||||||
|
if (tweetQueue.Count > 0) {
|
||||||
|
Text = Text + " (" + tweetQueue.Count + " more left)";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void OnNotificationReady() {
|
||||||
|
UpdateTitle();
|
||||||
|
base.OnNotificationReady();
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,98 +1,84 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Drawing;
|
using System.Drawing;
|
||||||
using System.Drawing.Imaging;
|
using System.IO;
|
||||||
using System.Windows.Forms;
|
using System.Threading.Tasks;
|
||||||
using CefSharp;
|
using CefSharp;
|
||||||
using TweetDuck.Browser.Adapters;
|
using CefSharp.DevTools.Page;
|
||||||
using TweetDuck.Controls;
|
using TweetDuck.Controls;
|
||||||
using TweetDuck.Dialogs;
|
using TweetDuck.Dialogs;
|
||||||
using TweetDuck.Utils;
|
using TweetDuck.Utils;
|
||||||
using TweetLib.Core.Data;
|
using TweetLib.Browser.Interfaces;
|
||||||
using TweetLib.Core.Features.Notifications;
|
using TweetLib.Core.Features.Notifications;
|
||||||
using TweetLib.Core.Features.Plugins;
|
using TweetLib.Core.Features.Plugins;
|
||||||
|
using TweetLib.Core.Resources;
|
||||||
|
|
||||||
namespace TweetDuck.Browser.Notification.Screenshot{
|
namespace TweetDuck.Browser.Notification.Screenshot {
|
||||||
sealed class FormNotificationScreenshotable : FormNotificationBase{
|
sealed class FormNotificationScreenshotable : FormNotificationBase {
|
||||||
protected override bool CanDragWindow => false;
|
private static NotificationBrowser CreateBrowserImpl( IBrowserComponent browserComponent, PluginManager pluginManager) {
|
||||||
|
return new NotificationBrowser.Screenshot(browserComponent, pluginManager.NotificationInjections);
|
||||||
|
}
|
||||||
|
|
||||||
private readonly PluginManager plugins;
|
protected override bool CanDragWindow => false;
|
||||||
private int height;
|
|
||||||
|
|
||||||
public FormNotificationScreenshotable(Action callback, FormBrowser owner, PluginManager pluginManager, string html, int width) : base(owner, false){
|
private int height;
|
||||||
this.plugins = pluginManager;
|
|
||||||
|
|
||||||
int realWidth = BrowserUtils.Scale(width, DpiScale);
|
public FormNotificationScreenshotable(Action callback, FormBrowser owner, PluginManager pluginManager, string html, int width) : base(owner, (_, browserComponent) => CreateBrowserImpl(browserComponent, pluginManager)) {
|
||||||
|
int realWidth = BrowserUtils.Scale(width, DpiScale);
|
||||||
|
|
||||||
browser.RegisterAsyncJsObject("$TD_NotificationScreenshot", new ScreenshotBridge(this, SetScreenshotHeight, callback));
|
browserComponent.AttachBridgeObject("$TD_NotificationScreenshot", new ScreenshotBridge(this, SetScreenshotHeight, callback));
|
||||||
|
|
||||||
browser.LoadingStateChanged += (sender, args) => {
|
browserComponent.BrowserLoaded += (sender, args) => {
|
||||||
if (args.IsLoading){
|
string script = ResourceUtils.ReadFileOrNull("notification/screenshot/screenshot.js");
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
string script = Program.Resources.LoadSilent("screenshot.js");
|
if (script == null) {
|
||||||
|
this.InvokeAsyncSafe(callback);
|
||||||
if (script == null){
|
return;
|
||||||
this.InvokeAsyncSafe(callback);
|
}
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
using IFrame frame = args.Browser.MainFrame;
|
string substituted = script.Replace("{width}", realWidth.ToString()).Replace("1/*FRAMES*/", TweetScreenshotManager.WaitFrames.ToString());
|
||||||
CefScriptExecutor.RunScript(frame, script.Replace("{width}", realWidth.ToString()).Replace("{frames}", TweetScreenshotManager.WaitFrames.ToString()), "gen:screenshot");
|
browserComponent.RunScript("gen:screenshot", substituted);
|
||||||
};
|
};
|
||||||
|
|
||||||
SetNotificationSize(realWidth, 1024);
|
|
||||||
LoadTweet(new DesktopNotification(string.Empty, string.Empty, string.Empty, html, 0, string.Empty, string.Empty));
|
|
||||||
}
|
|
||||||
|
|
||||||
protected override string GetTweetHTML(DesktopNotification tweet){
|
SetNotificationSize(realWidth, 1024);
|
||||||
string html = tweet.GenerateHtml("td-screenshot", HeadLayout, Config.CustomNotificationCSS);
|
LoadTweet(new DesktopNotification(string.Empty, string.Empty, string.Empty, html, 0, string.Empty, string.Empty));
|
||||||
|
}
|
||||||
|
|
||||||
foreach(InjectedHTML injection in plugins.NotificationInjections){
|
private void SetScreenshotHeight(int browserHeight) {
|
||||||
html = injection.InjectInto(html);
|
this.height = BrowserUtils.Scale(browserHeight, SizeScale);
|
||||||
}
|
}
|
||||||
|
|
||||||
return html;
|
public Task<Image> TakeScreenshot(bool ignoreHeightError = false) {
|
||||||
}
|
if (!ignoreHeightError) {
|
||||||
|
if (height == 0) {
|
||||||
|
FormMessage.Error("Screenshot Failed", "Could not detect screenshot size.", FormMessage.OK);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
else if (height > ClientSize.Height) {
|
||||||
|
FormMessage.Error("Screenshot Failed", $"Screenshot is too large: {height}px > {ClientSize.Height}px", FormMessage.OK);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private void SetScreenshotHeight(int browserHeight){
|
return Task.Run(TakeScreenshotImpl);
|
||||||
this.height = BrowserUtils.Scale(browserHeight, SizeScale);
|
}
|
||||||
}
|
|
||||||
|
|
||||||
public bool TakeScreenshot(bool ignoreHeightError = false){
|
private async Task<Image> TakeScreenshotImpl() {
|
||||||
if (!ignoreHeightError){
|
if (this.height == 0) {
|
||||||
if (height == 0){
|
return null;
|
||||||
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){
|
Viewport viewport = new Viewport {
|
||||||
MoveToVisibleLocation(); // TODO make this look nicer I guess
|
Width = this.ClientSize.Width,
|
||||||
}
|
Height = this.height,
|
||||||
|
Scale = 1
|
||||||
IntPtr context = NativeMethods.GetDC(this.Handle);
|
};
|
||||||
|
|
||||||
if (context == IntPtr.Zero){
|
byte[] data;
|
||||||
FormMessage.Error("Screenshot Failed", "Could not retrieve a graphics context handle for the notification window to take the screenshot.", FormMessage.OK);
|
using (var devToolsClient = browser.GetDevToolsClient()) {
|
||||||
return false;
|
data = (await devToolsClient.Page.CaptureScreenshotAsync(CaptureScreenshotFormat.Png, clip: viewport)).Data;
|
||||||
}
|
}
|
||||||
else{
|
|
||||||
using Bitmap bmp = new Bitmap(ClientSize.Width, Math.Max(1, height), PixelFormat.Format32bppRgb);
|
|
||||||
|
|
||||||
try{
|
return Image.FromStream(new MemoryStream(data));
|
||||||
NativeMethods.RenderSourceIntoBitmap(context, bmp);
|
}
|
||||||
}finally{
|
}
|
||||||
NativeMethods.ReleaseDC(this.Handle, context);
|
|
||||||
}
|
|
||||||
|
|
||||||
Clipboard.SetImage(bmp);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,26 +3,26 @@ using System.Diagnostics.CodeAnalysis;
|
|||||||
using System.Windows.Forms;
|
using System.Windows.Forms;
|
||||||
using TweetDuck.Controls;
|
using TweetDuck.Controls;
|
||||||
|
|
||||||
namespace TweetDuck.Browser.Notification.Screenshot{
|
namespace TweetDuck.Browser.Notification.Screenshot {
|
||||||
[SuppressMessage("ReSharper", "UnusedMember.Global")]
|
[SuppressMessage("ReSharper", "UnusedMember.Global")]
|
||||||
sealed class ScreenshotBridge{
|
sealed class ScreenshotBridge {
|
||||||
private readonly Control owner;
|
private readonly Control owner;
|
||||||
|
|
||||||
private readonly Action<int> safeSetHeight;
|
private readonly Action<int> safeSetHeight;
|
||||||
private readonly Action safeTriggerScreenshot;
|
private readonly Action safeTriggerScreenshot;
|
||||||
|
|
||||||
public ScreenshotBridge(Control owner, Action<int> safeSetHeight, Action safeTriggerScreenshot){
|
public ScreenshotBridge(Control owner, Action<int> safeSetHeight, Action safeTriggerScreenshot) {
|
||||||
this.owner = owner;
|
this.owner = owner;
|
||||||
this.safeSetHeight = safeSetHeight;
|
this.safeSetHeight = safeSetHeight;
|
||||||
this.safeTriggerScreenshot = safeTriggerScreenshot;
|
this.safeTriggerScreenshot = safeTriggerScreenshot;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void SetHeight(int tweetHeight){
|
public void SetHeight(int tweetHeight) {
|
||||||
owner.InvokeSafe(() => safeSetHeight(tweetHeight));
|
owner.InvokeSafe(() => safeSetHeight(tweetHeight));
|
||||||
}
|
}
|
||||||
|
|
||||||
public void TriggerScreenshot(){
|
public void TriggerScreenshot() {
|
||||||
owner.InvokeSafe(safeTriggerScreenshot);
|
owner.InvokeSafe(safeTriggerScreenshot);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,142 +7,158 @@
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
using System;
|
using System;
|
||||||
|
using System.Drawing;
|
||||||
|
using System.Threading.Tasks;
|
||||||
using System.Windows.Forms;
|
using System.Windows.Forms;
|
||||||
using TweetDuck.Controls;
|
using TweetDuck.Controls;
|
||||||
|
using TweetLib.Core;
|
||||||
using TweetLib.Core.Features.Plugins;
|
using TweetLib.Core.Features.Plugins;
|
||||||
|
|
||||||
#if GEN_SCREENSHOT_FRAMES
|
#if GEN_SCREENSHOT_FRAMES
|
||||||
using System.Drawing.Imaging;
|
using System.Drawing.Imaging;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using TweetDuck.Core.Utils;
|
using TweetDuck.Utils;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
namespace TweetDuck.Browser.Notification.Screenshot{
|
namespace TweetDuck.Browser.Notification.Screenshot {
|
||||||
sealed class TweetScreenshotManager : IDisposable{
|
sealed class TweetScreenshotManager : IDisposable {
|
||||||
private readonly FormBrowser owner;
|
private readonly FormBrowser owner;
|
||||||
private readonly PluginManager plugins;
|
private readonly PluginManager plugins;
|
||||||
private readonly Timer timeout;
|
private readonly Timer timeout;
|
||||||
private readonly Timer disposer;
|
private readonly Timer disposer;
|
||||||
|
|
||||||
#if GEN_SCREENSHOT_FRAMES
|
#if GEN_SCREENSHOT_FRAMES
|
||||||
private readonly Timer debugger;
|
private readonly Timer debugger;
|
||||||
private int frameCounter;
|
private int frameCounter;
|
||||||
|
|
||||||
public const int WaitFrames = 60;
|
public const int WaitFrames = 60;
|
||||||
#else
|
#else
|
||||||
public const int WaitFrames = 5;
|
public const int WaitFrames = 5;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
private FormNotificationScreenshotable screenshot;
|
|
||||||
|
|
||||||
public TweetScreenshotManager(FormBrowser owner, PluginManager pluginManager){
|
private FormNotificationScreenshotable screenshot;
|
||||||
this.owner = owner;
|
|
||||||
this.plugins = pluginManager;
|
|
||||||
|
|
||||||
this.timeout = new Timer{ Interval = 8000 };
|
public TweetScreenshotManager(FormBrowser owner, PluginManager pluginManager) {
|
||||||
this.timeout.Tick += timeout_Tick;
|
this.owner = owner;
|
||||||
|
this.plugins = pluginManager;
|
||||||
|
|
||||||
this.disposer = new Timer{ Interval = 1 };
|
this.timeout = new Timer { Interval = 8000 };
|
||||||
this.disposer.Tick += disposer_Tick;
|
this.timeout.Tick += timeout_Tick;
|
||||||
|
|
||||||
#if GEN_SCREENSHOT_FRAMES
|
this.disposer = new Timer { Interval = 1 };
|
||||||
this.debugger = new Timer{ Interval = 16 };
|
this.disposer.Tick += disposer_Tick;
|
||||||
this.debugger.Tick += debugger_Tick;
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
private void timeout_Tick(object sender, EventArgs e){
|
#if GEN_SCREENSHOT_FRAMES
|
||||||
timeout.Stop();
|
this.debugger = new Timer { Interval = 16 };
|
||||||
OnFinished();
|
this.debugger.Tick += debugger_Tick;
|
||||||
}
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
private void disposer_Tick(object sender, EventArgs e){
|
private void timeout_Tick(object sender, EventArgs e) {
|
||||||
disposer.Stop();
|
timeout.Stop();
|
||||||
screenshot.Dispose();
|
OnFinished();
|
||||||
screenshot = null;
|
}
|
||||||
}
|
|
||||||
|
|
||||||
public void Trigger(string html, int width){
|
private void disposer_Tick(object sender, EventArgs e) {
|
||||||
if (screenshot != null){
|
disposer.Stop();
|
||||||
return;
|
screenshot.Dispose();
|
||||||
}
|
screenshot = null;
|
||||||
|
}
|
||||||
|
|
||||||
screenshot = new FormNotificationScreenshotable(Callback, owner, plugins, html, width);
|
public void Trigger(string html, int width) {
|
||||||
screenshot.Show();
|
if (screenshot != null) {
|
||||||
timeout.Start();
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
#if GEN_SCREENSHOT_FRAMES
|
screenshot = new FormNotificationScreenshotable(Callback, owner, plugins, html, width);
|
||||||
StartDebugger();
|
screenshot.Show();
|
||||||
#endif
|
timeout.Start();
|
||||||
|
|
||||||
#if !NO_HIDE_SCREENSHOTS
|
#if GEN_SCREENSHOT_FRAMES
|
||||||
owner.IsWaiting = true;
|
StartDebugger();
|
||||||
#endif
|
#endif
|
||||||
}
|
|
||||||
|
|
||||||
private void Callback(){
|
#if !NO_HIDE_SCREENSHOTS
|
||||||
if (!timeout.Enabled){
|
owner.IsWaiting = true;
|
||||||
return;
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
timeout.Stop();
|
private void Callback() {
|
||||||
screenshot.TakeScreenshot();
|
if (!timeout.Enabled) {
|
||||||
|
return;
|
||||||
#if !NO_HIDE_SCREENSHOTS
|
}
|
||||||
OnFinished();
|
|
||||||
#else
|
|
||||||
screenshot.MoveToVisibleLocation();
|
|
||||||
screenshot.FormClosed += (sender, args) => disposer.Start();
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
private void OnFinished(){
|
timeout.Stop();
|
||||||
#if GEN_SCREENSHOT_FRAMES
|
screenshot.TakeScreenshot().ContinueWith(HandleResult, TaskScheduler.FromCurrentSynchronizationContext());
|
||||||
debugger.Stop();
|
}
|
||||||
#endif
|
|
||||||
|
|
||||||
screenshot.Location = ControlExtensions.InvisibleLocation;
|
private void HandleResult(Task<Image> task) {
|
||||||
owner.IsWaiting = false;
|
if (task.IsFaulted) {
|
||||||
disposer.Start();
|
App.ErrorHandler.HandleException("Screenshot Failed", "An error occurred while taking a screenshot.", true, task.Exception!.InnerException);
|
||||||
}
|
}
|
||||||
|
else if (task.IsCompleted) {
|
||||||
|
Clipboard.SetImage(task.Result);
|
||||||
|
#if !NO_HIDE_SCREENSHOTS
|
||||||
|
OnFinished();
|
||||||
|
#else
|
||||||
|
screenshot.MoveToVisibleLocation();
|
||||||
|
screenshot.FormClosed += (sender, args) => disposer.Start();
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public void Dispose(){
|
private void OnFinished() {
|
||||||
#if GEN_SCREENSHOT_FRAMES
|
#if GEN_SCREENSHOT_FRAMES
|
||||||
debugger.Dispose();
|
debugger.Stop();
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
timeout.Dispose();
|
screenshot.Location = ControlExtensions.InvisibleLocation;
|
||||||
disposer.Dispose();
|
owner.IsWaiting = false;
|
||||||
screenshot?.Dispose();
|
disposer.Start();
|
||||||
}
|
}
|
||||||
|
|
||||||
#if GEN_SCREENSHOT_FRAMES
|
public void Dispose() {
|
||||||
private static readonly string DebugScreenshotPath = Path.Combine(Program.StoragePath, "TD_Screenshots");
|
#if GEN_SCREENSHOT_FRAMES
|
||||||
|
debugger.Dispose();
|
||||||
|
#endif
|
||||||
|
|
||||||
private void StartDebugger(){
|
timeout.Dispose();
|
||||||
frameCounter = 0;
|
disposer.Dispose();
|
||||||
|
screenshot?.Dispose();
|
||||||
|
}
|
||||||
|
|
||||||
try{
|
#if GEN_SCREENSHOT_FRAMES
|
||||||
Directory.Delete(DebugScreenshotPath, true);
|
private static readonly string DebugScreenshotPath = Path.Combine(Program.StoragePath, "TD_Screenshots");
|
||||||
WindowsUtils.TrySleepUntil(() => !Directory.Exists(DebugScreenshotPath), 1000, 10);
|
|
||||||
}catch(DirectoryNotFoundException){}
|
|
||||||
|
|
||||||
Directory.CreateDirectory(DebugScreenshotPath);
|
|
||||||
debugger.Start();
|
|
||||||
}
|
|
||||||
|
|
||||||
private void debugger_Tick(object sender, EventArgs e){
|
private void StartDebugger() {
|
||||||
if (frameCounter < 63 && screenshot.TakeScreenshot(true)){
|
frameCounter = 0;
|
||||||
try{
|
|
||||||
Clipboard.GetImage()?.Save(Path.Combine(DebugScreenshotPath, "frame_" + (++frameCounter) + ".png"), ImageFormat.Png);
|
try {
|
||||||
}catch{
|
Directory.Delete(DebugScreenshotPath, true);
|
||||||
System.Diagnostics.Debug.WriteLine("Failed generating frame " + frameCounter);
|
WindowsUtils.TrySleepUntil(() => !Directory.Exists(DebugScreenshotPath), 1000, 10);
|
||||||
}
|
} catch (DirectoryNotFoundException) {}
|
||||||
}
|
|
||||||
else{
|
Directory.CreateDirectory(DebugScreenshotPath);
|
||||||
debugger.Stop();
|
debugger.Start();
|
||||||
}
|
}
|
||||||
}
|
|
||||||
#endif
|
private void debugger_Tick(object sender, EventArgs e) {
|
||||||
}
|
if (frameCounter < 63) {
|
||||||
|
int frame = ++frameCounter;
|
||||||
|
screenshot.TakeScreenshot(true).ContinueWith(task => SaveDebugFrame(task, frame), TaskScheduler.FromCurrentSynchronizationContext());
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
debugger.Stop();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void SaveDebugFrame(Task<Image> task, int frame) {
|
||||||
|
if (task.IsFaulted) {
|
||||||
|
System.Diagnostics.Debug.WriteLine("Failed generating frame " + frame + ": " + task.Exception!.InnerException);
|
||||||
|
}
|
||||||
|
else if (task.IsCompleted) {
|
||||||
|
task.Result?.Save(Path.Combine(DebugScreenshotPath, "frame_" + (++frame) + ".png"), ImageFormat.Png);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,48 +1,67 @@
|
|||||||
using System.Drawing;
|
using System.Drawing;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Windows.Forms;
|
using System.Windows.Forms;
|
||||||
using CefSharp;
|
using TweetDuck.Browser.Adapters;
|
||||||
using TweetDuck.Controls;
|
using TweetDuck.Controls;
|
||||||
using TweetDuck.Dialogs;
|
using TweetDuck.Dialogs;
|
||||||
using TweetDuck.Dialogs.Settings;
|
using TweetDuck.Dialogs.Settings;
|
||||||
using TweetDuck.Management;
|
using TweetDuck.Management;
|
||||||
|
using TweetLib.Core.Features.TweetDeck;
|
||||||
|
|
||||||
namespace TweetDuck.Browser.Notification{
|
namespace TweetDuck.Browser.Notification {
|
||||||
static class SoundNotification{
|
sealed class SoundNotification : ISoundNotificationHandler {
|
||||||
public const string SupportedFormats = "*.wav;*.ogg;*.mp3;*.flac;*.opus;*.weba;*.webm";
|
public const string SupportedFormats = "*.wav;*.ogg;*.mp3;*.flac;*.opus;*.weba;*.webm";
|
||||||
|
|
||||||
public static IResourceHandler CreateFileHandler(string path){
|
|
||||||
string mimeType = Path.GetExtension(path) switch{
|
|
||||||
".weba" => "audio/webm",
|
|
||||||
".webm" => "audio/webm",
|
|
||||||
".wav" => "audio/wav",
|
|
||||||
".ogg" => "audio/ogg",
|
|
||||||
".mp3" => "audio/mp3",
|
|
||||||
".flac" => "audio/flac",
|
|
||||||
".opus" => "audio/ogg; codecs=opus",
|
|
||||||
_ => null
|
|
||||||
};
|
|
||||||
|
|
||||||
try{
|
private readonly CefResourceHandlerRegistry registry;
|
||||||
return ResourceHandler.FromFilePath(path, mimeType);
|
|
||||||
}catch{
|
|
||||||
FormBrowser browser = FormManager.TryFind<FormBrowser>();
|
|
||||||
|
|
||||||
browser?.InvokeAsyncSafe(() => {
|
public SoundNotification(CefResourceHandlerRegistry registry) {
|
||||||
using FormMessage form = new FormMessage("Sound Notification Error", "Could not find custom notification sound file:\n" + path, MessageBoxIcon.Error);
|
this.registry = registry;
|
||||||
form.AddButton(FormMessage.Ignore, ControlType.Cancel | ControlType.Focused);
|
}
|
||||||
|
|
||||||
Button btnViewOptions = form.AddButton("View Options");
|
|
||||||
btnViewOptions.Width += 16;
|
|
||||||
btnViewOptions.Location = new Point(btnViewOptions.Location.X - 16, btnViewOptions.Location.Y);
|
|
||||||
|
|
||||||
if (form.ShowDialog() == DialogResult.OK && form.ClickedButton == btnViewOptions){
|
public void Unregister(string url) {
|
||||||
browser.OpenSettings(typeof(TabSettingsSounds));
|
registry.Unregister(url);
|
||||||
}
|
}
|
||||||
});
|
|
||||||
|
public void Register(string url, string path) {
|
||||||
return null;
|
var fileHandler = CreateFileHandler(path);
|
||||||
}
|
if (fileHandler.HasValue) {
|
||||||
}
|
var (data, mimeType) = fileHandler.Value;
|
||||||
}
|
registry.RegisterStatic(url, data, mimeType);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static (byte[] data, string mimeType)? CreateFileHandler(string path) {
|
||||||
|
string mimeType = Path.GetExtension(path) switch {
|
||||||
|
".weba" => "audio/webm",
|
||||||
|
".webm" => "audio/webm",
|
||||||
|
".wav" => "audio/wav",
|
||||||
|
".ogg" => "audio/ogg",
|
||||||
|
".mp3" => "audio/mp3",
|
||||||
|
".flac" => "audio/flac",
|
||||||
|
".opus" => "audio/ogg; codecs=opus",
|
||||||
|
_ => null
|
||||||
|
};
|
||||||
|
|
||||||
|
try {
|
||||||
|
return (File.ReadAllBytes(path), mimeType);
|
||||||
|
} catch {
|
||||||
|
FormBrowser browser = FormManager.TryFind<FormBrowser>();
|
||||||
|
|
||||||
|
browser?.InvokeAsyncSafe(() => {
|
||||||
|
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);
|
||||||
|
|
||||||
|
Button btnViewOptions = form.AddButton("View Options");
|
||||||
|
btnViewOptions.Width += 16;
|
||||||
|
btnViewOptions.Location = new Point(btnViewOptions.Location.X - 16, btnViewOptions.Location.Y);
|
||||||
|
|
||||||
|
if (form.ShowDialog() == DialogResult.OK && form.ClickedButton == btnViewOptions) {
|
||||||
|
browser.OpenSettings(typeof(TabSettingsSounds));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,123 +2,128 @@
|
|||||||
using System.ComponentModel;
|
using System.ComponentModel;
|
||||||
using System.Windows.Forms;
|
using System.Windows.Forms;
|
||||||
using TweetDuck.Configuration;
|
using TweetDuck.Configuration;
|
||||||
|
using TweetLib.Core.Systems.Configuration;
|
||||||
using Res = TweetDuck.Properties.Resources;
|
using Res = TweetDuck.Properties.Resources;
|
||||||
|
|
||||||
namespace TweetDuck.Browser{
|
namespace TweetDuck.Browser {
|
||||||
sealed partial class TrayIcon : Component{
|
sealed partial class TrayIcon : Component {
|
||||||
public enum Behavior{ // keep order
|
public enum Behavior { // keep order
|
||||||
Disabled, DisplayOnly, MinimizeToTray, CloseToTray, Combined
|
Disabled,
|
||||||
}
|
DisplayOnly,
|
||||||
|
MinimizeToTray,
|
||||||
|
CloseToTray,
|
||||||
|
Combined
|
||||||
|
}
|
||||||
|
|
||||||
private static UserConfig Config => Program.Config.User;
|
private static UserConfig Config => Program.Config.User;
|
||||||
|
|
||||||
public event EventHandler ClickRestore;
|
public event EventHandler ClickRestore;
|
||||||
public event EventHandler ClickClose;
|
public event EventHandler ClickClose;
|
||||||
|
|
||||||
public bool Visible{
|
public bool Visible {
|
||||||
get{
|
get {
|
||||||
return notifyIcon.Visible;
|
return notifyIcon.Visible;
|
||||||
}
|
}
|
||||||
|
|
||||||
set{
|
set {
|
||||||
notifyIcon.Visible = value;
|
notifyIcon.Visible = value;
|
||||||
hasNotifications = false;
|
hasNotifications = false;
|
||||||
UpdateIcon();
|
UpdateIcon();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool HasNotifications{
|
public bool HasNotifications {
|
||||||
get{
|
get {
|
||||||
return hasNotifications;
|
return hasNotifications;
|
||||||
}
|
}
|
||||||
|
|
||||||
set{
|
set {
|
||||||
if (hasNotifications != value){
|
if (hasNotifications != value) {
|
||||||
hasNotifications = value;
|
hasNotifications = value;
|
||||||
UpdateIcon();
|
UpdateIcon();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private readonly ContextMenu contextMenu;
|
private readonly ContextMenu contextMenu;
|
||||||
private bool hasNotifications;
|
private bool hasNotifications;
|
||||||
|
|
||||||
public TrayIcon(){
|
public TrayIcon() {
|
||||||
InitializeComponent();
|
InitializeComponent();
|
||||||
|
|
||||||
this.contextMenu = new ContextMenu();
|
this.contextMenu = new ContextMenu();
|
||||||
this.contextMenu.MenuItems.Add("Restore", menuItemRestore_Click);
|
this.contextMenu.MenuItems.Add("Restore", menuItemRestore_Click);
|
||||||
this.contextMenu.MenuItems.Add("Mute notifications", menuItemMuteNotifications_Click);
|
this.contextMenu.MenuItems.Add("Mute notifications", menuItemMuteNotifications_Click);
|
||||||
this.contextMenu.MenuItems.Add("Close", menuItemClose_Click);
|
this.contextMenu.MenuItems.Add("Close", menuItemClose_Click);
|
||||||
this.contextMenu.Popup += contextMenu_Popup;
|
this.contextMenu.Popup += contextMenu_Popup;
|
||||||
|
|
||||||
this.notifyIcon.ContextMenu = contextMenu;
|
|
||||||
this.notifyIcon.Text = Program.BrandName;
|
|
||||||
|
|
||||||
Config.MuteToggled += Config_MuteToggled;
|
this.notifyIcon.ContextMenu = contextMenu;
|
||||||
Disposed += (sender, args) => Config.MuteToggled -= Config_MuteToggled;
|
this.notifyIcon.Text = Program.BrandName;
|
||||||
}
|
|
||||||
|
|
||||||
public TrayIcon(IContainer container) : this(){
|
Config.MuteToggled += Config_MuteToggled;
|
||||||
container.Add(this);
|
Disposed += (sender, args) => Config.MuteToggled -= Config_MuteToggled;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void Dispose(bool disposing){
|
public TrayIcon(IContainer container) : this() {
|
||||||
if (disposing){
|
container.Add(this);
|
||||||
components?.Dispose();
|
}
|
||||||
contextMenu.Dispose();
|
|
||||||
}
|
|
||||||
|
|
||||||
base.Dispose(disposing);
|
protected override void Dispose(bool disposing) {
|
||||||
}
|
if (disposing) {
|
||||||
|
components?.Dispose();
|
||||||
|
contextMenu.Dispose();
|
||||||
|
}
|
||||||
|
|
||||||
private void UpdateIcon(){
|
base.Dispose(disposing);
|
||||||
if (Visible){
|
}
|
||||||
notifyIcon.Icon = hasNotifications ? Res.icon_tray_new : Config.MuteNotifications ? Res.icon_tray_muted : Res.icon_tray;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// event handlers
|
private void UpdateIcon() {
|
||||||
|
if (Visible) {
|
||||||
|
notifyIcon.Icon = HasNotifications ? Res.icon_tray_new : Config.MuteNotifications ? Res.icon_tray_muted : Res.icon_tray;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private void Config_MuteToggled(object sender, EventArgs e){
|
// event handlers
|
||||||
UpdateIcon();
|
|
||||||
}
|
|
||||||
|
|
||||||
private void trayIcon_MouseClick(object sender, MouseEventArgs e){
|
private void Config_MuteToggled(object sender, EventArgs e) {
|
||||||
if (e.Button == MouseButtons.Left){
|
UpdateIcon();
|
||||||
menuItemRestore_Click(sender, e);
|
}
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void contextMenu_Popup(object sender, EventArgs e){
|
private void trayIcon_MouseClick(object sender, MouseEventArgs e) {
|
||||||
contextMenu.MenuItems[1].Checked = Config.MuteNotifications;
|
if (e.Button == MouseButtons.Left) {
|
||||||
}
|
menuItemRestore_Click(sender, e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private void menuItemRestore_Click(object sender, EventArgs e){
|
private void contextMenu_Popup(object sender, EventArgs e) {
|
||||||
ClickRestore?.Invoke(this, e);
|
contextMenu.MenuItems[1].Checked = Config.MuteNotifications;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void menuItemMuteNotifications_Click(object sender, EventArgs e){
|
private void menuItemRestore_Click(object sender, EventArgs e) {
|
||||||
Config.MuteNotifications = !contextMenu.MenuItems[1].Checked;
|
ClickRestore?.Invoke(this, e);
|
||||||
Config.Save();
|
}
|
||||||
}
|
|
||||||
|
|
||||||
private void menuItemClose_Click(object sender, EventArgs e){
|
private void menuItemMuteNotifications_Click(object sender, EventArgs e) {
|
||||||
ClickClose?.Invoke(this, e);
|
Config.MuteNotifications = !contextMenu.MenuItems[1].Checked;
|
||||||
}
|
Config.Save();
|
||||||
}
|
}
|
||||||
|
|
||||||
static class BehaviorExtensions{
|
private void menuItemClose_Click(object sender, EventArgs e) {
|
||||||
public static bool ShouldDisplayIcon(this TrayIcon.Behavior behavior){
|
ClickClose?.Invoke(this, e);
|
||||||
return behavior != TrayIcon.Behavior.Disabled;
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static bool ShouldHideOnMinimize(this TrayIcon.Behavior behavior){
|
static class BehaviorExtensions {
|
||||||
return behavior == TrayIcon.Behavior.MinimizeToTray || behavior == TrayIcon.Behavior.Combined;
|
public static bool ShouldDisplayIcon(this TrayIcon.Behavior behavior) {
|
||||||
}
|
return behavior != TrayIcon.Behavior.Disabled;
|
||||||
|
}
|
||||||
|
|
||||||
public static bool ShouldHideOnClose(this TrayIcon.Behavior behavior){
|
public static bool ShouldHideOnMinimize(this TrayIcon.Behavior behavior) {
|
||||||
return behavior == TrayIcon.Behavior.CloseToTray || behavior == TrayIcon.Behavior.Combined;
|
return behavior == TrayIcon.Behavior.MinimizeToTray || behavior == TrayIcon.Behavior.Combined;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
public static bool ShouldHideOnClose(this TrayIcon.Behavior behavior) {
|
||||||
|
return behavior == TrayIcon.Behavior.CloseToTray || behavior == TrayIcon.Behavior.Combined;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,279 +1,132 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Drawing;
|
using System.Drawing;
|
||||||
using System.Text;
|
|
||||||
using System.Windows.Forms;
|
|
||||||
using CefSharp;
|
using CefSharp;
|
||||||
using CefSharp.WinForms;
|
using CefSharp.WinForms;
|
||||||
using TweetDuck.Browser.Adapters;
|
using TweetDuck.Browser.Adapters;
|
||||||
using TweetDuck.Browser.Bridge;
|
|
||||||
using TweetDuck.Browser.Handling;
|
using TweetDuck.Browser.Handling;
|
||||||
using TweetDuck.Browser.Handling.General;
|
|
||||||
using TweetDuck.Browser.Notification;
|
using TweetDuck.Browser.Notification;
|
||||||
using TweetDuck.Configuration;
|
using TweetDuck.Configuration;
|
||||||
using TweetDuck.Controls;
|
|
||||||
using TweetDuck.Plugins;
|
|
||||||
using TweetDuck.Utils;
|
using TweetDuck.Utils;
|
||||||
using TweetLib.Core.Features.Plugins;
|
using TweetLib.Core.Features.Plugins;
|
||||||
using TweetLib.Core.Features.Plugins.Enums;
|
using TweetLib.Core.Features.TweetDeck;
|
||||||
using TweetLib.Core.Features.Twitter;
|
using TweetLib.Core.Features.Twitter;
|
||||||
using TweetLib.Core.Utils;
|
using TweetLib.Core.Systems.Updates;
|
||||||
|
using IContextMenuHandler = TweetLib.Browser.Interfaces.IContextMenuHandler;
|
||||||
|
using IResourceRequestHandler = TweetLib.Browser.Interfaces.IResourceRequestHandler;
|
||||||
|
using TweetDeckBrowserImpl = TweetLib.Core.Features.TweetDeck.TweetDeckBrowser;
|
||||||
|
|
||||||
namespace TweetDuck.Browser{
|
namespace TweetDuck.Browser {
|
||||||
sealed class TweetDeckBrowser : IDisposable{
|
sealed class TweetDeckBrowser : IDisposable {
|
||||||
private static UserConfig Config => Program.Config.User;
|
public static readonly Color BackgroundColor = Color.FromArgb(28, 99, 153);
|
||||||
|
|
||||||
private const string ErrorUrl = "http://td/error";
|
public bool Ready => browserComponent.Ready;
|
||||||
private const string TwitterStyleUrl = "https://abs.twimg.com/tduck/css";
|
|
||||||
|
|
||||||
public bool Ready { get; private set; }
|
public bool Enabled {
|
||||||
|
get => browser.Enabled;
|
||||||
|
set => browser.Enabled = value;
|
||||||
|
}
|
||||||
|
|
||||||
public bool Enabled{
|
public bool IsTweetDeckWebsite {
|
||||||
get => browser.Enabled;
|
get {
|
||||||
set => browser.Enabled = value;
|
if (!Ready) {
|
||||||
}
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
public bool IsTweetDeckWebsite{
|
using IFrame frame = browser.GetBrowser().MainFrame;
|
||||||
get{
|
return TwitterUrls.IsTweetDeck(frame.Url);
|
||||||
if (!Ready){
|
}
|
||||||
return false;
|
}
|
||||||
}
|
|
||||||
|
|
||||||
using IFrame frame = browser.GetBrowser().MainFrame;
|
public TweetDeckFunctions Functions => browserImpl.Functions;
|
||||||
return TwitterUrls.IsTweetDeck(frame.Url);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private readonly ChromiumWebBrowser browser;
|
|
||||||
private readonly ResourceHandlerFactory resourceHandlerFactory = new ResourceHandlerFactory();
|
|
||||||
|
|
||||||
private string prevSoundNotificationPath = null;
|
private readonly CefBrowserComponent browserComponent;
|
||||||
|
private readonly TweetDeckBrowserImpl browserImpl;
|
||||||
|
private readonly ChromiumWebBrowser browser;
|
||||||
|
|
||||||
public TweetDeckBrowser(FormBrowser owner, PluginManager plugins, TweetDeckBridge tdBridge, UpdateBridge updateBridge){
|
public TweetDeckBrowser(FormBrowser owner, PluginManager pluginManager, ITweetDeckInterface tweetDeckInterface, UpdateChecker updateChecker) {
|
||||||
resourceHandlerFactory.RegisterHandler(FormNotificationBase.AppLogo);
|
RequestHandlerBrowser requestHandler = new RequestHandlerBrowser();
|
||||||
resourceHandlerFactory.RegisterHandler(TwitterUtils.LoadingSpinner);
|
|
||||||
|
|
||||||
RequestHandlerBrowser requestHandler = new RequestHandlerBrowser();
|
this.browser = new ChromiumWebBrowser(TwitterUrls.TweetDeck) {
|
||||||
|
DialogHandler = new FileDialogHandler(),
|
||||||
this.browser = new ChromiumWebBrowser(TwitterUrls.TweetDeck){
|
DragHandler = new DragHandlerBrowser(requestHandler),
|
||||||
DialogHandler = new FileDialogHandler(),
|
KeyboardHandler = new CustomKeyboardHandler(owner),
|
||||||
DragHandler = new DragHandlerBrowser(requestHandler),
|
RequestHandler = requestHandler
|
||||||
MenuHandler = new ContextMenuBrowser(owner),
|
};
|
||||||
JsDialogHandler = new JavaScriptDialogHandler(),
|
|
||||||
KeyboardHandler = new KeyboardHandlerBrowser(owner),
|
|
||||||
LifeSpanHandler = new LifeSpanHandler(),
|
|
||||||
RequestHandler = requestHandler,
|
|
||||||
ResourceHandlerFactory = resourceHandlerFactory
|
|
||||||
};
|
|
||||||
|
|
||||||
this.browser.LoadingStateChanged += browser_LoadingStateChanged;
|
// ReSharper disable once PossiblyImpureMethodCallOnReadonlyVariable
|
||||||
this.browser.FrameLoadStart += browser_FrameLoadStart;
|
this.browser.BrowserSettings.BackgroundColor = (uint) BackgroundColor.ToArgb();
|
||||||
this.browser.FrameLoadEnd += browser_FrameLoadEnd;
|
|
||||||
this.browser.LoadError += browser_LoadError;
|
|
||||||
|
|
||||||
this.browser.RegisterAsyncJsObject("$TD", tdBridge);
|
var extraContext = new TweetDeckExtraContext();
|
||||||
this.browser.RegisterAsyncJsObject("$TDU", updateBridge);
|
var resourceHandlerRegistry = new CefResourceHandlerRegistry();
|
||||||
|
var soundNotificationHandler = new SoundNotification(resourceHandlerRegistry);
|
||||||
this.browser.BrowserSettings.BackgroundColor = (uint)TwitterUtils.BackgroundColor.ToArgb();
|
|
||||||
this.browser.Dock = DockStyle.None;
|
|
||||||
this.browser.Location = ControlExtensions.InvisibleLocation;
|
|
||||||
this.browser.SetupZoomEvents();
|
|
||||||
|
|
||||||
owner.Controls.Add(browser);
|
|
||||||
plugins.Register(PluginEnvironment.Browser, new PluginDispatcher(browser));
|
|
||||||
|
|
||||||
Config.MuteToggled += Config_MuteToggled;
|
|
||||||
Config.SoundNotificationChanged += Config_SoundNotificationInfoChanged;
|
|
||||||
}
|
|
||||||
|
|
||||||
// setup and management
|
this.browserComponent = new ComponentImpl(browser, owner, extraContext, resourceHandlerRegistry);
|
||||||
|
this.browserImpl = new TweetDeckBrowserImpl(browserComponent, tweetDeckInterface, extraContext, soundNotificationHandler, pluginManager, updateChecker);
|
||||||
|
|
||||||
private void OnBrowserReady(){
|
if (Arguments.HasFlag(Arguments.ArgIgnoreGDPR)) {
|
||||||
if (!Ready){
|
browserComponent.PageLoadEnd += (sender, args) => {
|
||||||
browser.Location = Point.Empty;
|
if (TwitterUrls.IsTweetDeck(args.Url)) {
|
||||||
browser.Dock = DockStyle.Fill;
|
browserComponent.RunScript("gen:gdpr", "TD.storage.Account.prototype.requiresConsent = function() { return false; }");
|
||||||
Ready = true;
|
}
|
||||||
}
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Focus(){
|
owner.Controls.Add(browser);
|
||||||
browser.Focus();
|
}
|
||||||
}
|
|
||||||
|
|
||||||
public void Dispose(){
|
private sealed class ComponentImpl : CefBrowserComponent {
|
||||||
Config.MuteToggled -= Config_MuteToggled;
|
private readonly FormBrowser owner;
|
||||||
Config.SoundNotificationChanged -= Config_SoundNotificationInfoChanged;
|
private readonly TweetDeckExtraContext extraContext;
|
||||||
|
private readonly CefResourceHandlerRegistry registry;
|
||||||
browser.Dispose();
|
|
||||||
}
|
|
||||||
|
|
||||||
// event handlers
|
public ComponentImpl(ChromiumWebBrowser browser, FormBrowser owner, TweetDeckExtraContext extraContext, CefResourceHandlerRegistry registry) : base(browser) {
|
||||||
|
this.owner = owner;
|
||||||
|
this.extraContext = extraContext;
|
||||||
|
this.registry = registry;
|
||||||
|
}
|
||||||
|
|
||||||
private void browser_LoadingStateChanged(object sender, LoadingStateChangedEventArgs e){
|
protected override ContextMenuBase SetupContextMenu(IContextMenuHandler handler) {
|
||||||
if (!e.IsLoading){
|
return new ContextMenuBrowser(owner, handler, extraContext);
|
||||||
foreach(string word in TwitterUtils.DictionaryWords){
|
}
|
||||||
browser.AddWordToDictionary(word);
|
|
||||||
}
|
|
||||||
|
|
||||||
browser.BeginInvoke(new Action(OnBrowserReady));
|
protected override CefResourceHandlerFactory SetupResourceHandlerFactory(IResourceRequestHandler handler) {
|
||||||
browser.LoadingStateChanged -= browser_LoadingStateChanged;
|
return new CefResourceHandlerFactory(handler, registry);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void browser_FrameLoadStart(object sender, FrameLoadStartEventArgs e){
|
public void PrepareSize(Size size) {
|
||||||
IFrame frame = e.Frame;
|
if (!Ready) {
|
||||||
|
browser.Size = size;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (frame.IsMain){
|
public void Dispose() {
|
||||||
string url = frame.Url;
|
browserImpl.Dispose();
|
||||||
|
browser.Dispose();
|
||||||
|
}
|
||||||
|
|
||||||
if (TwitterUrls.IsTwitter(url)){
|
public void Focus() {
|
||||||
string css = Program.Resources.Load("styles/twitter.css");
|
browser.Focus();
|
||||||
resourceHandlerFactory.RegisterHandler(TwitterStyleUrl, ResourceHandler.FromString(css, mimeType: "text/css"));
|
}
|
||||||
|
|
||||||
CefScriptExecutor.RunFile(frame, "twitter.js");
|
public void OpenDevTools() {
|
||||||
}
|
browser.OpenDevToolsCustom();
|
||||||
|
}
|
||||||
if (!TwitterUrls.IsTwitterLogin2Factor(url)){
|
|
||||||
frame.ExecuteJavaScriptAsync(TwitterUtils.BackgroundColorOverride);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void browser_FrameLoadEnd(object sender, FrameLoadEndEventArgs e){
|
public void ReloadToTweetDeck() {
|
||||||
IFrame frame = e.Frame;
|
browserImpl.ReloadToTweetDeck();
|
||||||
string url = frame.Url;
|
}
|
||||||
|
|
||||||
if (frame.IsMain){
|
public void SaveVideo(string url, string username) {
|
||||||
if (TwitterUrls.IsTweetDeck(url)){
|
browserImpl.FileDownloadManager.SaveVideo(url, username);
|
||||||
UpdateProperties();
|
}
|
||||||
CefScriptExecutor.RunFile(frame, "code.js");
|
|
||||||
|
|
||||||
InjectBrowserCSS();
|
public void HideVideoOverlay(bool focus) {
|
||||||
ReinjectCustomCSS(Config.CustomBrowserCSS);
|
if (focus) {
|
||||||
Config_SoundNotificationInfoChanged(null, EventArgs.Empty);
|
browser.GetBrowser().GetHost().SendFocusEvent(true);
|
||||||
|
}
|
||||||
|
|
||||||
TweetDeckBridge.ResetStaticProperties();
|
browserComponent.RunScript("gen:hidevideo", "$('#td-video-player-overlay').remove()");
|
||||||
|
}
|
||||||
if (Arguments.HasFlag(Arguments.ArgIgnoreGDPR)){
|
}
|
||||||
CefScriptExecutor.RunScript(frame, "TD.storage.Account.prototype.requiresConsent = function(){ return false; }", "gen:gdpr");
|
|
||||||
}
|
|
||||||
|
|
||||||
if (Config.FirstRun){
|
|
||||||
CefScriptExecutor.RunFile(frame, "introduction.js");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
CefScriptExecutor.RunFile(frame, "update.js");
|
|
||||||
}
|
|
||||||
|
|
||||||
if (url == ErrorUrl){
|
|
||||||
resourceHandlerFactory.UnregisterHandler(ErrorUrl);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void browser_LoadError(object sender, LoadErrorEventArgs e){
|
|
||||||
if (e.ErrorCode == CefErrorCode.Aborted){
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!e.FailedUrl.StartsWith("http://td/", StringComparison.Ordinal)){
|
|
||||||
string errorPage = Program.Resources.LoadSilent("pages/error.html");
|
|
||||||
|
|
||||||
if (errorPage != null){
|
|
||||||
string errorName = Enum.GetName(typeof(CefErrorCode), e.ErrorCode);
|
|
||||||
string errorTitle = StringUtils.ConvertPascalCaseToScreamingSnakeCase(errorName ?? string.Empty);
|
|
||||||
|
|
||||||
resourceHandlerFactory.RegisterHandler(ErrorUrl, ResourceHandler.FromString(errorPage.Replace("{err}", errorTitle)));
|
|
||||||
browser.Load(ErrorUrl);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void Config_MuteToggled(object sender, EventArgs e){
|
|
||||||
UpdateProperties();
|
|
||||||
}
|
|
||||||
|
|
||||||
private void Config_SoundNotificationInfoChanged(object sender, EventArgs e){
|
|
||||||
const string soundUrl = "https://ton.twimg.com/tduck/updatesnd";
|
|
||||||
|
|
||||||
bool hasCustomSound = Config.IsCustomSoundNotificationSet;
|
|
||||||
string newNotificationPath = Config.NotificationSoundPath;
|
|
||||||
|
|
||||||
if (prevSoundNotificationPath != newNotificationPath){
|
|
||||||
prevSoundNotificationPath = newNotificationPath;
|
|
||||||
|
|
||||||
if (hasCustomSound){
|
|
||||||
resourceHandlerFactory.RegisterHandler(soundUrl, SoundNotification.CreateFileHandler(newNotificationPath));
|
|
||||||
}
|
|
||||||
else{
|
|
||||||
resourceHandlerFactory.UnregisterHandler(soundUrl);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
browser.ExecuteScriptAsync("TDGF_setSoundNotificationData", hasCustomSound, Config.NotificationSoundVolume);
|
|
||||||
}
|
|
||||||
|
|
||||||
// external handling
|
|
||||||
|
|
||||||
public void HideVideoOverlay(bool focus){
|
|
||||||
if (focus){
|
|
||||||
browser.GetBrowser().GetHost().SendFocusEvent(true);
|
|
||||||
}
|
|
||||||
|
|
||||||
browser.ExecuteScriptAsync("$('#td-video-player-overlay').remove()");
|
|
||||||
}
|
|
||||||
|
|
||||||
// javascript calls
|
|
||||||
|
|
||||||
public void ReloadToTweetDeck(){
|
|
||||||
browser.ExecuteScriptAsync($"if(window.TDGF_reload)window.TDGF_reload();else window.location.href='{TwitterUrls.TweetDeck}'");
|
|
||||||
}
|
|
||||||
|
|
||||||
public void UpdateProperties(){
|
|
||||||
browser.ExecuteScriptAsync(PropertyBridge.GenerateScript(PropertyBridge.Environment.Browser));
|
|
||||||
}
|
|
||||||
|
|
||||||
public void InjectBrowserCSS(){
|
|
||||||
browser.ExecuteScriptAsync("TDGF_injectBrowserCSS", Program.Resources.Load("styles/browser.css")?.TrimEnd() ?? string.Empty);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void ReinjectCustomCSS(string css){
|
|
||||||
browser.ExecuteScriptAsync("TDGF_reinjectCustomCSS", css?.Replace(Environment.NewLine, " ") ?? string.Empty);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void OnMouseClickExtra(IntPtr param){
|
|
||||||
browser.ExecuteScriptAsync("TDGF_onMouseClickExtra", (param.ToInt32() >> 16) & 0xFFFF);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void ShowTweetDetail(string columnId, string chirpId, string fallbackUrl){
|
|
||||||
browser.ExecuteScriptAsync("TDGF_showTweetDetail", columnId, chirpId, fallbackUrl);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void AddSearchColumn(string query){
|
|
||||||
browser.ExecuteScriptAsync("TDGF_performSearch", query);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void TriggerTweetScreenshot(){
|
|
||||||
browser.ExecuteScriptAsync("TDGF_triggerScreenshot()");
|
|
||||||
}
|
|
||||||
|
|
||||||
public void ReloadColumns(){
|
|
||||||
browser.ExecuteScriptAsync("TDGF_reloadColumns()");
|
|
||||||
}
|
|
||||||
|
|
||||||
public void PlaySoundNotification(){
|
|
||||||
browser.ExecuteScriptAsync("TDGF_playSoundNotification()");
|
|
||||||
}
|
|
||||||
|
|
||||||
public void 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.OpenDevToolsCustom();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,48 +1,45 @@
|
|||||||
using System;
|
using System;
|
||||||
using TweetLib.Core.Collections;
|
using TweetLib.Utils.Collections;
|
||||||
|
|
||||||
namespace TweetDuck.Configuration{
|
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 ArgLogging = "-log";
|
public const string ArgLogging = "-log";
|
||||||
public const string ArgIgnoreGDPR = "-nogdpr";
|
public const string ArgIgnoreGDPR = "-nogdpr";
|
||||||
public const string ArgFreeze = "-freeze";
|
public const string ArgHttpVideo = "-httpvideo";
|
||||||
|
public const string ArgFreeze = "-freeze";
|
||||||
|
|
||||||
// internal args
|
// internal args
|
||||||
public const string ArgRestart = "-restart";
|
public const string ArgRestart = "-restart";
|
||||||
public const string ArgImportCookies = "-importcookies";
|
public const string ArgUpdated = "-updated";
|
||||||
public const string ArgDeleteCookies = "-deletecookies";
|
|
||||||
public const string ArgUpdated = "-updated";
|
|
||||||
|
|
||||||
// class data and methods
|
// class data and methods
|
||||||
private static readonly CommandLineArgs Current = CommandLineArgs.FromStringArray('-', Environment.GetCommandLineArgs());
|
private static readonly CommandLineArgs Current = CommandLineArgs.FromStringArray('-', Environment.GetCommandLineArgs());
|
||||||
|
|
||||||
public static bool HasFlag(string flag){
|
public static bool HasFlag(string flag) {
|
||||||
return Current.HasFlag(flag);
|
return Current.HasFlag(flag);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static string GetValue(string key){
|
public static string GetValue(string key) {
|
||||||
return Current.GetValue(key);
|
return Current.GetValue(key);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static CommandLineArgs GetCurrentClean(){
|
public static CommandLineArgs GetCurrentClean() {
|
||||||
CommandLineArgs args = Current.Clone();
|
CommandLineArgs args = Current.Clone();
|
||||||
args.RemoveFlag(ArgRestart);
|
args.RemoveFlag(ArgRestart);
|
||||||
args.RemoveFlag(ArgImportCookies);
|
args.RemoveFlag(ArgUpdated);
|
||||||
args.RemoveFlag(ArgDeleteCookies);
|
return args;
|
||||||
args.RemoveFlag(ArgUpdated);
|
}
|
||||||
return args;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static CommandLineArgs GetCurrentForInstaller(){
|
public static CommandLineArgs GetCurrentForInstaller() {
|
||||||
CommandLineArgs args = GetCurrentClean();
|
CommandLineArgs args = GetCurrentClean();
|
||||||
args.AddFlag(ArgUpdated);
|
args.AddFlag(ArgUpdated);
|
||||||
return args;
|
return args;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static string GetCurrentForInstallerCmd(){
|
public static string GetCurrentForInstallerCmd() {
|
||||||
return GetCurrentForInstaller().ToString().Replace("\"", "::");
|
return GetCurrentForInstaller().ToString().Replace("\"", "::");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,82 +0,0 @@
|
|||||||
using System;
|
|
||||||
using System.Drawing;
|
|
||||||
using TweetDuck.Browser.Data;
|
|
||||||
using TweetLib.Core.Features.Configuration;
|
|
||||||
using TweetLib.Core.Features.Plugins.Config;
|
|
||||||
using TweetLib.Core.Serialization.Converters;
|
|
||||||
using TweetLib.Core.Utils;
|
|
||||||
|
|
||||||
namespace TweetDuck.Configuration{
|
|
||||||
sealed class ConfigManager : IConfigManager{
|
|
||||||
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<PluginConfig> 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<PluginConfig>(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();
|
|
||||||
}
|
|
||||||
|
|
||||||
void IConfigManager.TriggerProgramRestartRequested(){
|
|
||||||
ProgramRestartRequested?.Invoke(this, EventArgs.Empty);
|
|
||||||
}
|
|
||||||
|
|
||||||
IConfigInstance<BaseConfig> IConfigManager.GetInstanceInfo(BaseConfig instance){
|
|
||||||
Type instanceType = instance.GetType();
|
|
||||||
return Array.Find(infoList, info => info.Instance.GetType() == instanceType); // TODO handle null
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,51 +0,0 @@
|
|||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using TweetLib.Core.Features.Configuration;
|
|
||||||
using TweetLib.Core.Features.Plugins;
|
|
||||||
using TweetLib.Core.Features.Plugins.Config;
|
|
||||||
using TweetLib.Core.Features.Plugins.Events;
|
|
||||||
|
|
||||||
namespace TweetDuck.Configuration{
|
|
||||||
sealed class PluginConfig : BaseConfig, IPluginConfig{
|
|
||||||
private static readonly string[] DefaultDisabled = {
|
|
||||||
"official/clear-columns",
|
|
||||||
"official/reply-account"
|
|
||||||
};
|
|
||||||
|
|
||||||
// CONFIGURATION DATA
|
|
||||||
|
|
||||||
private readonly HashSet<string> disabled = new HashSet<string>(DefaultDisabled);
|
|
||||||
|
|
||||||
// EVENTS
|
|
||||||
|
|
||||||
public event EventHandler<PluginChangedStateEventArgs> PluginChangedState;
|
|
||||||
|
|
||||||
// END OF CONFIG
|
|
||||||
|
|
||||||
public PluginConfig(IConfigManager configManager) : base(configManager){}
|
|
||||||
|
|
||||||
protected override BaseConfig ConstructWithDefaults(IConfigManager configManager){
|
|
||||||
return new PluginConfig(configManager);
|
|
||||||
}
|
|
||||||
|
|
||||||
// INTERFACE IMPLEMENTATION
|
|
||||||
|
|
||||||
IEnumerable<string> IPluginConfig.DisabledPlugins => disabled;
|
|
||||||
|
|
||||||
void IPluginConfig.Reset(IEnumerable<string> newDisabledPlugins){
|
|
||||||
disabled.Clear();
|
|
||||||
disabled.UnionWith(newDisabledPlugins);
|
|
||||||
}
|
|
||||||
|
|
||||||
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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,28 +1,69 @@
|
|||||||
using TweetLib.Core.Features.Configuration;
|
using System.Diagnostics.CodeAnalysis;
|
||||||
|
using TweetLib.Core;
|
||||||
|
using TweetLib.Core.Application;
|
||||||
|
using TweetLib.Core.Systems.Configuration;
|
||||||
|
|
||||||
namespace TweetDuck.Configuration{
|
namespace TweetDuck.Configuration {
|
||||||
sealed class SystemConfig : BaseConfig{
|
sealed class SystemConfig : BaseConfig<SystemConfig>, IAppSystemConfiguration {
|
||||||
|
[SuppressMessage("ReSharper", "MemberCanBePrivate.Global")]
|
||||||
|
public int MigrationVersion { get; set; } = 0;
|
||||||
|
|
||||||
// CONFIGURATION DATA
|
private bool _hardwareAcceleration = true;
|
||||||
|
private bool _enableTouchAdjustment = false;
|
||||||
public bool _hardwareAcceleration = true;
|
private bool _enableColorProfileDetection = false;
|
||||||
|
private bool _useSystemProxyForAllConnections = false;
|
||||||
public bool ClearCacheAutomatically { get; set; } = true;
|
|
||||||
public int ClearCacheThreshold { get; set; } = 250;
|
|
||||||
|
|
||||||
// SPECIAL PROPERTIES
|
public bool ClearCacheAutomatically { get; set; } = true;
|
||||||
|
public int ClearCacheThreshold { get; set; } = 250;
|
||||||
public bool HardwareAcceleration{
|
|
||||||
get => _hardwareAcceleration;
|
|
||||||
set => UpdatePropertyWithRestartRequest(ref _hardwareAcceleration, value);
|
|
||||||
}
|
|
||||||
|
|
||||||
// END OF CONFIG
|
|
||||||
|
|
||||||
public SystemConfig(IConfigManager configManager) : base(configManager){}
|
// SPECIAL PROPERTIES
|
||||||
|
|
||||||
protected override BaseConfig ConstructWithDefaults(IConfigManager configManager){
|
public bool HardwareAcceleration {
|
||||||
return new SystemConfig(configManager);
|
get => _hardwareAcceleration;
|
||||||
}
|
set => UpdatePropertyWithCallback(ref _hardwareAcceleration, value, App.ConfigManager.TriggerProgramRestartRequested);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public bool EnableTouchAdjustment {
|
||||||
|
get => _enableTouchAdjustment;
|
||||||
|
set => UpdatePropertyWithCallback(ref _enableTouchAdjustment, value, App.ConfigManager.TriggerProgramRestartRequested);
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool EnableColorProfileDetection {
|
||||||
|
get => _enableColorProfileDetection;
|
||||||
|
set => UpdatePropertyWithCallback(ref _enableColorProfileDetection, value, App.ConfigManager.TriggerProgramRestartRequested);
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool UseSystemProxyForAllConnections {
|
||||||
|
get => _useSystemProxyForAllConnections;
|
||||||
|
set => UpdatePropertyWithCallback(ref _useSystemProxyForAllConnections, value, App.ConfigManager.TriggerProgramRestartRequested);
|
||||||
|
}
|
||||||
|
|
||||||
|
// END OF CONFIG
|
||||||
|
|
||||||
|
#pragma warning disable CS0618
|
||||||
|
|
||||||
|
public bool Migrate() {
|
||||||
|
bool hasChanged = false;
|
||||||
|
|
||||||
|
if (MigrationVersion < 1) {
|
||||||
|
MigrationVersion = 1;
|
||||||
|
hasChanged = true;
|
||||||
|
|
||||||
|
var userConfig = Program.Config.User;
|
||||||
|
_enableTouchAdjustment = userConfig.EnableTouchAdjustment;
|
||||||
|
_enableColorProfileDetection = userConfig.EnableColorProfileDetection;
|
||||||
|
_useSystemProxyForAllConnections = userConfig.UseSystemProxyForAllConnections;
|
||||||
|
}
|
||||||
|
|
||||||
|
return hasChanged;
|
||||||
|
}
|
||||||
|
|
||||||
|
#pragma warning restore CS0618
|
||||||
|
|
||||||
|
public override SystemConfig ConstructWithDefaults() {
|
||||||
|
return new SystemConfig {
|
||||||
|
MigrationVersion = 1
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,152 +1,167 @@
|
|||||||
using System;
|
using System;
|
||||||
|
using System.Diagnostics.CodeAnalysis;
|
||||||
using System.Drawing;
|
using System.Drawing;
|
||||||
using TweetDuck.Browser;
|
using TweetDuck.Browser;
|
||||||
using TweetDuck.Browser.Data;
|
|
||||||
using TweetDuck.Controls;
|
using TweetDuck.Controls;
|
||||||
using TweetLib.Core.Features.Configuration;
|
using TweetLib.Core;
|
||||||
|
using TweetLib.Core.Application;
|
||||||
using TweetLib.Core.Features.Notifications;
|
using TweetLib.Core.Features.Notifications;
|
||||||
using TweetLib.Core.Features.Twitter;
|
using TweetLib.Core.Features.Twitter;
|
||||||
|
using TweetLib.Core.Systems.Configuration;
|
||||||
|
using TweetLib.Utils.Data;
|
||||||
|
|
||||||
namespace TweetDuck.Configuration{
|
namespace TweetDuck.Configuration {
|
||||||
sealed class UserConfig : BaseConfig{
|
sealed class UserConfig : BaseConfig<UserConfig>, IAppUserConfiguration {
|
||||||
|
public bool FirstRun { get; set; } = true;
|
||||||
// CONFIGURATION DATA
|
|
||||||
|
|
||||||
public bool FirstRun { get; set; } = true;
|
[SuppressMessage("ReSharper", "UnusedMember.Global")]
|
||||||
public bool AllowDataCollection { get; set; } = false;
|
public bool AllowDataCollection { get; set; } = false;
|
||||||
|
|
||||||
public WindowState BrowserWindow { get; set; } = new WindowState();
|
public WindowState BrowserWindow { get; set; } = new WindowState();
|
||||||
public Size PluginsWindowSize { get; set; } = Size.Empty;
|
public Size PluginsWindowSize { get; set; } = Size.Empty;
|
||||||
|
|
||||||
public bool ExpandLinksOnHover { get; set; } = true;
|
public bool ExpandLinksOnHover { get; set; } = true;
|
||||||
public bool FocusDmInput { get; set; } = true;
|
public bool FocusDmInput { get; set; } = true;
|
||||||
public bool OpenSearchInFirstColumn { get; set; } = true;
|
public bool OpenSearchInFirstColumn { get; set; } = true;
|
||||||
public bool KeepLikeFollowDialogsOpen { get; set; } = true;
|
public bool KeepLikeFollowDialogsOpen { get; set; } = true;
|
||||||
public bool BestImageQuality { get; set; } = true;
|
public bool BestImageQuality { get; set; } = true;
|
||||||
public bool EnableAnimatedImages { get; set; } = true;
|
public bool EnableAnimatedImages { get; set; } = true;
|
||||||
|
public bool HideTweetsByNftUsers { get; set; } = false;
|
||||||
|
|
||||||
private bool _enableSmoothScrolling = true;
|
private bool _enableSmoothScrolling = true;
|
||||||
private bool _enableTouchAdjustment = false;
|
private string _customCefArgs = null;
|
||||||
private string _customCefArgs = null;
|
|
||||||
|
|
||||||
public string BrowserPath { get; set; } = null;
|
public string BrowserPath { get; set; } = null;
|
||||||
public string BrowserPathArgs { get; set; } = null;
|
public string BrowserPathArgs { get; set; } = null;
|
||||||
public bool IgnoreTrackingUrlWarning { get; set; } = false;
|
public bool IgnoreTrackingUrlWarning { get; set; } = false;
|
||||||
public string SearchEngineUrl { get; set; } = null;
|
public string SearchEngineUrl { get; set; } = null;
|
||||||
private int _zoomLevel = 100;
|
private int _zoomLevel = 100;
|
||||||
|
|
||||||
public string VideoPlayerPath { get; set; } = null;
|
|
||||||
public string VideoPlayerPathArgs { get; set; } = null;
|
|
||||||
public int VideoPlayerVolume { get; set; } = 50;
|
|
||||||
|
|
||||||
public bool EnableSpellCheck { get; set; } = false;
|
|
||||||
private string _spellCheckLanguage = "en-US";
|
|
||||||
|
|
||||||
public string TranslationTarget { get; set; } = "en";
|
public string VideoPlayerPath { get; set; } = null;
|
||||||
public int CalendarFirstDay { get; set; } = -1;
|
public string VideoPlayerPathArgs { get; set; } = null;
|
||||||
|
public int VideoPlayerVolume { get; set; } = 50;
|
||||||
private TrayIcon.Behavior _trayBehavior = TrayIcon.Behavior.Disabled;
|
|
||||||
public bool EnableTrayHighlight { get; set; } = true;
|
|
||||||
|
|
||||||
public bool EnableUpdateCheck { get; set; } = true;
|
public bool EnableSpellCheck { get; set; } = false;
|
||||||
public string DismissedUpdate { get; set; } = null;
|
private string _spellCheckLanguage = "en-US";
|
||||||
|
|
||||||
public bool DisplayNotificationColumn { get; set; } = false;
|
public string TranslationTarget { get; set; } = "en";
|
||||||
public bool NotificationMediaPreviews { get; set; } = true;
|
public int CalendarFirstDay { get; set; } = -1;
|
||||||
public bool NotificationSkipOnLinkClick { get; set; } = false;
|
|
||||||
public bool NotificationNonIntrusiveMode { get; set; } = true;
|
|
||||||
public int NotificationIdlePauseSeconds { get; set; } = 0;
|
|
||||||
|
|
||||||
public bool DisplayNotificationTimer { get; set; } = true;
|
private TrayIcon.Behavior _trayBehavior = TrayIcon.Behavior.Disabled;
|
||||||
public bool NotificationTimerCountDown { get; set; } = false;
|
public bool EnableTrayHighlight { get; set; } = true;
|
||||||
public int NotificationDurationValue { get; set; } = 25;
|
|
||||||
|
|
||||||
public DesktopNotification.Position NotificationPosition { get; set; } = DesktopNotification.Position.TopRight;
|
public bool EnableUpdateCheck { get; set; } = true;
|
||||||
public Point CustomNotificationPosition { get; set; } = ControlExtensions.InvisibleLocation;
|
public string DismissedUpdate { get; set; } = null;
|
||||||
public int NotificationDisplay { get; set; } = 0;
|
|
||||||
public int NotificationEdgeDistance { get; set; } = 8;
|
|
||||||
public int NotificationWindowOpacity { get; set; } = 100;
|
|
||||||
|
|
||||||
public DesktopNotification.Size NotificationSize { get; set; } = DesktopNotification.Size.Auto;
|
public bool DisplayNotificationColumn { get; set; } = false;
|
||||||
public Size CustomNotificationSize { get; set; } = Size.Empty;
|
public bool NotificationMediaPreviews { get; set; } = true;
|
||||||
public int NotificationScrollSpeed { get; set; } = 100;
|
public bool NotificationSkipOnLinkClick { get; set; } = false;
|
||||||
|
public bool NotificationNonIntrusiveMode { get; set; } = true;
|
||||||
private string _notificationSoundPath;
|
public int NotificationIdlePauseSeconds { get; set; } = 0;
|
||||||
private int _notificationSoundVolume = 100;
|
|
||||||
|
|
||||||
private bool _muteNotifications;
|
public bool DisplayNotificationTimer { get; set; } = true;
|
||||||
|
public bool NotificationTimerCountDown { get; set; } = false;
|
||||||
|
public int NotificationDurationValue { get; set; } = 25;
|
||||||
|
|
||||||
public string CustomBrowserCSS { get; set; } = null;
|
public DesktopNotification.Position NotificationPosition { get; set; } = DesktopNotification.Position.TopRight;
|
||||||
public string CustomNotificationCSS { get; set; } = null;
|
public Point CustomNotificationPosition { get; set; } = ControlExtensions.InvisibleLocation;
|
||||||
|
public int NotificationDisplay { get; set; } = 0;
|
||||||
|
public int NotificationEdgeDistance { get; set; } = 8;
|
||||||
|
public int NotificationWindowOpacity { get; set; } = 100;
|
||||||
|
|
||||||
public bool DevToolsWindowOnTop { get; set; } = true;
|
public DesktopNotification.Size NotificationSize { get; set; } = DesktopNotification.Size.Auto;
|
||||||
|
public Size CustomNotificationSize { get; set; } = Size.Empty;
|
||||||
// SPECIAL PROPERTIES
|
public int NotificationScrollSpeed { get; set; } = 100;
|
||||||
|
|
||||||
public bool IsCustomNotificationPositionSet => CustomNotificationPosition != ControlExtensions.InvisibleLocation;
|
private string _notificationSoundPath;
|
||||||
public bool IsCustomNotificationSizeSet => CustomNotificationSize != Size.Empty;
|
private int _notificationSoundVolume = 100;
|
||||||
public bool IsCustomSoundNotificationSet => NotificationSoundPath != string.Empty;
|
|
||||||
|
|
||||||
public ImageQuality TwitterImageQuality => BestImageQuality ? ImageQuality.Best : ImageQuality.Default;
|
private bool _muteNotifications;
|
||||||
|
|
||||||
public string NotificationSoundPath{
|
|
||||||
get => _notificationSoundPath ?? string.Empty;
|
|
||||||
set => UpdatePropertyWithEvent(ref _notificationSoundPath, value, SoundNotificationChanged);
|
|
||||||
}
|
|
||||||
|
|
||||||
public int NotificationSoundVolume{
|
|
||||||
get => _notificationSoundVolume;
|
|
||||||
set => UpdatePropertyWithEvent(ref _notificationSoundVolume, value, SoundNotificationChanged);
|
|
||||||
}
|
|
||||||
|
|
||||||
public bool MuteNotifications{
|
public string CustomBrowserCSS { get; set; } = null;
|
||||||
get => _muteNotifications;
|
public string CustomNotificationCSS { get; set; } = null;
|
||||||
set => UpdatePropertyWithEvent(ref _muteNotifications, value, MuteToggled);
|
|
||||||
}
|
|
||||||
|
|
||||||
public int ZoomLevel{
|
public bool DevToolsInContextMenu { get; set; } = false;
|
||||||
get => _zoomLevel;
|
public bool DevToolsWindowOnTop { get; set; } = true;
|
||||||
set => UpdatePropertyWithEvent(ref _zoomLevel, value, ZoomLevelChanged);
|
|
||||||
}
|
|
||||||
|
|
||||||
public TrayIcon.Behavior TrayBehavior{
|
|
||||||
get => _trayBehavior;
|
|
||||||
set => UpdatePropertyWithEvent(ref _trayBehavior, value, TrayBehaviorChanged);
|
|
||||||
}
|
|
||||||
|
|
||||||
public bool EnableSmoothScrolling{
|
|
||||||
get => _enableSmoothScrolling;
|
|
||||||
set => UpdatePropertyWithRestartRequest(ref _enableSmoothScrolling, value);
|
|
||||||
}
|
|
||||||
|
|
||||||
public bool EnableTouchAdjustment{
|
// SPECIAL PROPERTIES
|
||||||
get => _enableTouchAdjustment;
|
|
||||||
set => UpdatePropertyWithRestartRequest(ref _enableTouchAdjustment, value);
|
|
||||||
}
|
|
||||||
|
|
||||||
public string CustomCefArgs{
|
public bool IsCustomNotificationPositionSet => CustomNotificationPosition != ControlExtensions.InvisibleLocation;
|
||||||
get => _customCefArgs;
|
public bool IsCustomNotificationSizeSet => CustomNotificationSize != Size.Empty;
|
||||||
set => UpdatePropertyWithRestartRequest(ref _customCefArgs, value);
|
public bool IsCustomSoundNotificationSet => NotificationSoundPath != string.Empty;
|
||||||
}
|
|
||||||
|
|
||||||
public string SpellCheckLanguage{
|
public ImageQuality TwitterImageQuality => BestImageQuality ? ImageQuality.Best : ImageQuality.Default;
|
||||||
get => _spellCheckLanguage;
|
|
||||||
set => UpdatePropertyWithRestartRequest(ref _spellCheckLanguage, value);
|
|
||||||
}
|
|
||||||
|
|
||||||
// EVENTS
|
public string NotificationSoundPath {
|
||||||
|
get => _notificationSoundPath ?? string.Empty;
|
||||||
public event EventHandler MuteToggled;
|
set => UpdatePropertyWithEvent(ref _notificationSoundPath, value, SoundNotificationChanged);
|
||||||
public event EventHandler ZoomLevelChanged;
|
}
|
||||||
public event EventHandler TrayBehaviorChanged;
|
|
||||||
public event EventHandler SoundNotificationChanged;
|
|
||||||
|
|
||||||
// END OF CONFIG
|
public int NotificationSoundVolume {
|
||||||
|
get => _notificationSoundVolume;
|
||||||
public UserConfig(IConfigManager configManager) : base(configManager){}
|
set => UpdatePropertyWithEvent(ref _notificationSoundVolume, value, SoundNotificationChanged);
|
||||||
|
}
|
||||||
|
|
||||||
protected override BaseConfig ConstructWithDefaults(IConfigManager configManager){
|
public bool MuteNotifications {
|
||||||
return new UserConfig(configManager);
|
get => _muteNotifications;
|
||||||
}
|
set => UpdatePropertyWithEvent(ref _muteNotifications, value, MuteToggled);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public int ZoomLevel {
|
||||||
|
get => _zoomLevel;
|
||||||
|
set => UpdatePropertyWithEvent(ref _zoomLevel, value, ZoomLevelChanged);
|
||||||
|
}
|
||||||
|
|
||||||
|
public TrayIcon.Behavior TrayBehavior {
|
||||||
|
get => _trayBehavior;
|
||||||
|
set => UpdatePropertyWithEvent(ref _trayBehavior, value, TrayBehaviorChanged);
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool EnableSmoothScrolling {
|
||||||
|
get => _enableSmoothScrolling;
|
||||||
|
set => UpdatePropertyWithCallback(ref _enableSmoothScrolling, value, App.ConfigManager.TriggerProgramRestartRequested);
|
||||||
|
}
|
||||||
|
|
||||||
|
public string CustomCefArgs {
|
||||||
|
get => _customCefArgs;
|
||||||
|
set => UpdatePropertyWithCallback(ref _customCefArgs, value, App.ConfigManager.TriggerProgramRestartRequested);
|
||||||
|
}
|
||||||
|
|
||||||
|
public string SpellCheckLanguage {
|
||||||
|
get => _spellCheckLanguage;
|
||||||
|
set => UpdatePropertyWithCallback(ref _spellCheckLanguage, value, App.ConfigManager.TriggerProgramRestartRequested);
|
||||||
|
}
|
||||||
|
|
||||||
|
// DEPRECATED
|
||||||
|
|
||||||
|
[Obsolete("Moved to SystemConfig")]
|
||||||
|
[SuppressMessage("ReSharper", "UnusedAutoPropertyAccessor.Global")]
|
||||||
|
public bool EnableTouchAdjustment { get; set; }
|
||||||
|
|
||||||
|
[Obsolete("Moved to SystemConfig")]
|
||||||
|
[SuppressMessage("ReSharper", "UnusedAutoPropertyAccessor.Global")]
|
||||||
|
public bool EnableColorProfileDetection { get; set; }
|
||||||
|
|
||||||
|
[Obsolete("Moved to SystemConfig")]
|
||||||
|
[SuppressMessage("ReSharper", "UnusedAutoPropertyAccessor.Global")]
|
||||||
|
public bool UseSystemProxyForAllConnections { get; set; }
|
||||||
|
|
||||||
|
// EVENTS
|
||||||
|
|
||||||
|
public event EventHandler MuteToggled;
|
||||||
|
public event EventHandler ZoomLevelChanged;
|
||||||
|
public event EventHandler TrayBehaviorChanged;
|
||||||
|
public event EventHandler SoundNotificationChanged;
|
||||||
|
public event EventHandler OptionsDialogClosed;
|
||||||
|
|
||||||
|
public void TriggerOptionsDialogClosed() {
|
||||||
|
OptionsDialogClosed?.Invoke(this, EventArgs.Empty);
|
||||||
|
}
|
||||||
|
|
||||||
|
// END OF CONFIG
|
||||||
|
|
||||||
|
public override UserConfig ConstructWithDefaults() {
|
||||||
|
return new UserConfig();
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,78 +2,102 @@ using System;
|
|||||||
using System.Drawing;
|
using System.Drawing;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Windows.Forms;
|
using System.Windows.Forms;
|
||||||
|
using TweetLib.Utils.Data;
|
||||||
|
|
||||||
namespace TweetDuck.Controls{
|
namespace TweetDuck.Controls {
|
||||||
static class ControlExtensions{
|
static class ControlExtensions {
|
||||||
public static readonly Point InvisibleLocation = new Point(-32000, -32000);
|
public static readonly Point InvisibleLocation = new Point(-32000, -32000);
|
||||||
|
|
||||||
public static void InvokeSafe(this Control control, Action func){
|
public static void InvokeSafe(this Control control, Action func) {
|
||||||
if (control.InvokeRequired){
|
if (control.InvokeRequired) {
|
||||||
control.Invoke(func);
|
control.Invoke(func);
|
||||||
}
|
}
|
||||||
else{
|
else {
|
||||||
func();
|
func();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void InvokeAsyncSafe(this Control control, Action func){
|
public static void InvokeAsyncSafe(this Control control, Action func) {
|
||||||
control.BeginInvoke(func);
|
if (control.InvokeRequired) {
|
||||||
}
|
control.BeginInvoke(func);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
func();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public static float GetDPIScale(this Control control){
|
public static float GetDPIScale(this Control control) {
|
||||||
using Graphics graphics = control.CreateGraphics();
|
using Graphics graphics = control.CreateGraphics();
|
||||||
return graphics.DpiY / 96F;
|
return graphics.DpiY / 96F;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static bool IsFullyOutsideView(this Form form){
|
public static bool IsFullyOutsideView(this Form form) {
|
||||||
return !Screen.AllScreens.Any(screen => screen.WorkingArea.IntersectsWith(form.Bounds));
|
return !Screen.AllScreens.Any(screen => screen.WorkingArea.IntersectsWith(form.Bounds));
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void MoveToCenter(this Form targetForm, Form parentForm){
|
public static void MoveToCenter(this Form targetForm, Form parentForm) {
|
||||||
targetForm.Location = new Point(parentForm.Location.X + (parentForm.Width / 2) - (targetForm.Width / 2), parentForm.Location.Y + (parentForm.Height / 2) - (targetForm.Height / 2));
|
targetForm.Location = new Point(parentForm.Location.X + (parentForm.Width / 2) - (targetForm.Width / 2), parentForm.Location.Y + (parentForm.Height / 2) - (targetForm.Height / 2));
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void SetValueInstant(this ProgressBar bar, int value){
|
public static void SetValueInstant(this ProgressBar bar, int value) {
|
||||||
if (value == bar.Maximum){
|
if (value == bar.Maximum) {
|
||||||
bar.Value = value;
|
bar.Value = value;
|
||||||
bar.Value = value - 1;
|
bar.Value = value - 1;
|
||||||
bar.Value = value;
|
bar.Value = value;
|
||||||
}
|
}
|
||||||
else{
|
else {
|
||||||
bar.Value = value + 1;
|
bar.Value = value + 1;
|
||||||
bar.Value = value;
|
bar.Value = value;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void SetValueSafe(this NumericUpDown numUpDown, int value){
|
public static void SetValueSafe(this NumericUpDown numUpDown, int value) {
|
||||||
if (value >= numUpDown.Minimum && value <= numUpDown.Maximum){
|
if (value >= numUpDown.Minimum && value <= numUpDown.Maximum) {
|
||||||
numUpDown.Value = value;
|
numUpDown.Value = value;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void SetValueSafe(this TrackBar trackBar, int value){
|
public static void SetValueSafe(this TrackBar trackBar, int value) {
|
||||||
if (value >= trackBar.Minimum && value <= trackBar.Maximum){
|
if (value >= trackBar.Minimum && value <= trackBar.Maximum) {
|
||||||
trackBar.Value = value;
|
trackBar.Value = value;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static bool AlignValueToTick(this TrackBar trackBar){
|
public static bool AlignValueToTick(this TrackBar trackBar) {
|
||||||
if (trackBar.Value % trackBar.SmallChange != 0){
|
if (trackBar.Value % trackBar.SmallChange != 0) {
|
||||||
trackBar.Value = trackBar.SmallChange * (int)Math.Floor(((double)trackBar.Value / trackBar.SmallChange) + 0.5);
|
trackBar.Value = trackBar.SmallChange * (int) Math.Floor(((double) trackBar.Value / trackBar.SmallChange) + 0.5);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void EnableMultilineShortcuts(this TextBox textBox){
|
public static void EnableMultilineShortcuts(this TextBox textBox) {
|
||||||
textBox.KeyDown += (sender, args) => {
|
textBox.KeyDown += (sender, args) => {
|
||||||
if (args.Control && args.KeyCode == Keys.A){
|
if (args.Control && args.KeyCode == Keys.A) {
|
||||||
((TextBox)sender).SelectAll();
|
((TextBox) sender).SelectAll();
|
||||||
args.SuppressKeyPress = true;
|
args.SuppressKeyPress = true;
|
||||||
args.Handled = true;
|
args.Handled = true;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
public static void Save(this WindowState state, Form form) {
|
||||||
|
state.Bounds = form.WindowState == FormWindowState.Normal ? form.DesktopBounds : form.RestoreBounds;
|
||||||
|
state.IsMaximized = form.WindowState == FormWindowState.Maximized;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void Restore(this WindowState state, Form form, bool firstTimeFullscreen) {
|
||||||
|
if (state.Bounds != Rectangle.Empty) {
|
||||||
|
form.DesktopBounds = state.Bounds;
|
||||||
|
form.WindowState = state.IsMaximized ? FormWindowState.Maximized : FormWindowState.Normal;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((state.Bounds == Rectangle.Empty && firstTimeFullscreen) || form.IsFullyOutsideView()) {
|
||||||
|
form.DesktopBounds = Screen.PrimaryScreen.WorkingArea;
|
||||||
|
form.WindowState = FormWindowState.Maximized;
|
||||||
|
state.Save(form);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,16 +1,16 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Windows.Forms;
|
using System.Windows.Forms;
|
||||||
|
|
||||||
namespace TweetDuck.Controls{
|
namespace TweetDuck.Controls {
|
||||||
sealed class FlatButton : Button{
|
sealed class FlatButton : Button {
|
||||||
protected override bool ShowFocusCues => false;
|
protected override bool ShowFocusCues => false;
|
||||||
|
|
||||||
public FlatButton(){
|
public FlatButton() {
|
||||||
GotFocus += FlatButton_GotFocus;
|
GotFocus += FlatButton_GotFocus;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void FlatButton_GotFocus(object sender, EventArgs e){ // removes extra border when focused
|
private void FlatButton_GotFocus(object sender, EventArgs e) { // removes extra border when focused
|
||||||
NotifyDefault(false);
|
NotifyDefault(false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,37 +2,37 @@
|
|||||||
using System.Drawing;
|
using System.Drawing;
|
||||||
using System.Windows.Forms;
|
using System.Windows.Forms;
|
||||||
|
|
||||||
namespace TweetDuck.Controls{
|
namespace TweetDuck.Controls {
|
||||||
sealed class FlatProgressBar : ProgressBar{
|
sealed class FlatProgressBar : ProgressBar {
|
||||||
private readonly SolidBrush brush;
|
private readonly SolidBrush brush;
|
||||||
|
|
||||||
public FlatProgressBar(){
|
public FlatProgressBar() {
|
||||||
brush = new SolidBrush(Color.White);
|
brush = new SolidBrush(Color.White);
|
||||||
|
|
||||||
SetStyle(ControlStyles.UserPaint, true);
|
SetStyle(ControlStyles.UserPaint, true);
|
||||||
SetStyle(ControlStyles.OptimizedDoubleBuffer, true);
|
SetStyle(ControlStyles.OptimizedDoubleBuffer, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void SetValueInstant(int value){
|
public void SetValueInstant(int value) {
|
||||||
ControlExtensions.SetValueInstant(this, Math.Max(Minimum, Math.Min(Maximum, value)));
|
ControlExtensions.SetValueInstant(this, Math.Max(Minimum, Math.Min(Maximum, value)));
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void OnPaint(PaintEventArgs e){
|
protected override void OnPaint(PaintEventArgs e) {
|
||||||
if (brush.Color != ForeColor){
|
if (brush.Color != ForeColor) {
|
||||||
brush.Color = ForeColor;
|
brush.Color = ForeColor;
|
||||||
}
|
}
|
||||||
|
|
||||||
Rectangle rect = e.ClipRectangle;
|
Rectangle rect = e.ClipRectangle;
|
||||||
rect.Width = (int)(rect.Width * ((double)Value / Maximum));
|
rect.Width = (int) (rect.Width * ((double) Value / Maximum));
|
||||||
e.Graphics.FillRectangle(brush, rect);
|
e.Graphics.FillRectangle(brush, rect);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void Dispose(bool disposing){
|
protected override void Dispose(bool disposing) {
|
||||||
base.Dispose(disposing);
|
base.Dispose(disposing);
|
||||||
|
|
||||||
if (disposing){
|
if (disposing) {
|
||||||
brush.Dispose();
|
brush.Dispose();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,14 +1,14 @@
|
|||||||
using System.Windows.Forms;
|
using System.Windows.Forms;
|
||||||
using TweetDuck.Utils;
|
using TweetDuck.Utils;
|
||||||
|
|
||||||
namespace TweetDuck.Controls{
|
namespace TweetDuck.Controls {
|
||||||
sealed class FlowLayoutPanelNoHScroll : FlowLayoutPanel{
|
sealed class FlowLayoutPanelNoHScroll : FlowLayoutPanel {
|
||||||
protected override void WndProc(ref Message m){
|
protected override void WndProc(ref Message m) {
|
||||||
if (m.Msg == 0x85){ // WM_NCPAINT
|
if (m.Msg == 0x85) { // WM_NCPAINT
|
||||||
NativeMethods.ShowScrollBar(Handle, NativeMethods.SB_HORZ, false); // basically fuck the horizontal scrollbar very much
|
NativeMethods.ShowScrollBar(Handle, NativeMethods.SB_HORZ, false); // basically fuck the horizontal scrollbar very much
|
||||||
}
|
}
|
||||||
|
|
||||||
base.WndProc(ref m);
|
base.WndProc(ref m);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,21 +2,21 @@
|
|||||||
using System.Drawing;
|
using System.Drawing;
|
||||||
using System.Windows.Forms;
|
using System.Windows.Forms;
|
||||||
|
|
||||||
namespace TweetDuck.Controls{
|
namespace TweetDuck.Controls {
|
||||||
sealed class LabelVertical : Label{
|
sealed class LabelVertical : Label {
|
||||||
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) - 1;
|
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) {
|
||||||
string str = chr.ToString();
|
string str = chr.ToString();
|
||||||
float x = (ClientRectangle.Width - e.Graphics.MeasureString(str, Font).Width) / 2F;
|
float x = (ClientRectangle.Width - e.Graphics.MeasureString(str, Font).Width) / 2F;
|
||||||
|
|
||||||
e.Graphics.DrawString(str, Font, brush, x, y);
|
e.Graphics.DrawString(str, Font, brush, x, y);
|
||||||
y += LineHeight;
|
y += LineHeight;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,18 +1,18 @@
|
|||||||
using System.ComponentModel;
|
using System.ComponentModel;
|
||||||
using System.Windows.Forms;
|
using System.Windows.Forms;
|
||||||
|
|
||||||
namespace TweetDuck.Controls{
|
namespace TweetDuck.Controls {
|
||||||
sealed class NumericUpDownEx : NumericUpDown{
|
sealed class NumericUpDownEx : NumericUpDown {
|
||||||
public string TextSuffix { get; set ; }
|
public string TextSuffix { get; set ; }
|
||||||
|
|
||||||
protected override void UpdateEditText(){
|
protected override void UpdateEditText() {
|
||||||
base.UpdateEditText();
|
base.UpdateEditText();
|
||||||
|
|
||||||
if (LicenseManager.UsageMode != LicenseUsageMode.Designtime){
|
if (LicenseManager.UsageMode != LicenseUsageMode.Designtime) {
|
||||||
ChangingText = true;
|
ChangingText = true;
|
||||||
Text += TextSuffix;
|
Text += TextSuffix;
|
||||||
ChangingText = false;
|
ChangingText = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,47 +1,49 @@
|
|||||||
using System.ComponentModel;
|
using System;
|
||||||
|
using System.ComponentModel;
|
||||||
using System.Drawing;
|
using System.Drawing;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Windows.Forms;
|
using System.Windows.Forms;
|
||||||
using TweetDuck.Management;
|
using TweetDuck.Management;
|
||||||
using TweetDuck.Utils;
|
using TweetLib.Core;
|
||||||
|
|
||||||
namespace TweetDuck.Dialogs{
|
namespace TweetDuck.Dialogs {
|
||||||
sealed partial class FormAbout : Form, FormManager.IAppDialog{
|
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";
|
|
||||||
|
|
||||||
public FormAbout(){
|
public FormAbout() {
|
||||||
InitializeComponent();
|
InitializeComponent();
|
||||||
|
|
||||||
Text = "About " + Program.BrandName + " " + Program.VersionTag;
|
Text = "About " + Program.BrandName + " " + Program.VersionTag;
|
||||||
|
|
||||||
labelDescription.Text = "TweetDuck was created by chylex as a replacement to the discontinued official TweetDeck client for Windows.\n\nThe program is available for free under the open source MIT license.";
|
labelDescription.Text = "TweetDuck was created by chylex as a replacement to the discontinued official TweetDeck client for Windows.\n\nThe program is available for free under the open source MIT license.";
|
||||||
|
|
||||||
labelWebsite.Links.Add(new LinkLabel.Link(0, labelWebsite.Text.Length, Program.Website));
|
|
||||||
labelTips.Links.Add(new LinkLabel.Link(0, labelTips.Text.Length, TipsLink));
|
|
||||||
labelIssues.Links.Add(new LinkLabel.Link(0, labelIssues.Text.Length, IssuesLink));
|
|
||||||
|
|
||||||
MemoryStream logoStream = new MemoryStream(Properties.Resources.avatar);
|
labelWebsite.Links.Add(new LinkLabel.Link(0, labelWebsite.Text.Length, Program.Website));
|
||||||
pictureLogo.Image = Image.FromStream(logoStream);
|
labelTips.Links.Add(new LinkLabel.Link(0, labelTips.Text.Length, TipsLink));
|
||||||
Disposed += (sender, args) => logoStream.Dispose();
|
labelIssues.Links.Add(new LinkLabel.Link(0, labelIssues.Text.Length, Lib.IssueTrackerUrl));
|
||||||
}
|
|
||||||
|
|
||||||
private void OnLinkClicked(object sender, LinkLabelLinkClickedEventArgs e){
|
try {
|
||||||
BrowserUtils.OpenExternalBrowser(e.Link.LinkData as string);
|
pictureLogo.Image = Image.FromFile(Path.Combine(App.ResourcesPath, "images/logo.png"));
|
||||||
}
|
} catch (Exception) {
|
||||||
|
// ignore
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private void FormAbout_HelpRequested(object sender, HelpEventArgs hlpevent){
|
private void OnLinkClicked(object sender, LinkLabelLinkClickedEventArgs e) {
|
||||||
ShowGuide();
|
App.SystemHandler.OpenBrowser(e.Link.LinkData as string);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void FormAbout_HelpButtonClicked(object sender, CancelEventArgs e){
|
private void FormAbout_HelpRequested(object sender, HelpEventArgs hlpevent) {
|
||||||
e.Cancel = true;
|
ShowGuide();
|
||||||
ShowGuide();
|
}
|
||||||
}
|
|
||||||
|
|
||||||
private void ShowGuide(){
|
private void FormAbout_HelpButtonClicked(object sender, CancelEventArgs e) {
|
||||||
FormGuide.Show();
|
e.Cancel = true;
|
||||||
Close();
|
ShowGuide();
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
private void ShowGuide() {
|
||||||
|
FormGuide.Show();
|
||||||
|
Close();
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,132 +1,89 @@
|
|||||||
using System.Drawing;
|
using System.Drawing;
|
||||||
using System.Text.RegularExpressions;
|
|
||||||
using System.Windows.Forms;
|
using System.Windows.Forms;
|
||||||
using CefSharp;
|
|
||||||
using CefSharp.WinForms;
|
using CefSharp.WinForms;
|
||||||
using TweetDuck.Browser;
|
using TweetDuck.Browser;
|
||||||
using TweetDuck.Browser.Adapters;
|
using TweetDuck.Browser.Adapters;
|
||||||
using TweetDuck.Browser.Data;
|
|
||||||
using TweetDuck.Browser.Handling;
|
using TweetDuck.Browser.Handling;
|
||||||
using TweetDuck.Browser.Handling.General;
|
|
||||||
using TweetDuck.Controls;
|
using TweetDuck.Controls;
|
||||||
using TweetDuck.Management;
|
using TweetDuck.Management;
|
||||||
using TweetDuck.Utils;
|
using TweetDuck.Utils;
|
||||||
|
using TweetLib.Browser.Interfaces;
|
||||||
|
using TweetLib.Core.Features;
|
||||||
|
|
||||||
namespace TweetDuck.Dialogs{
|
namespace TweetDuck.Dialogs {
|
||||||
sealed partial class FormGuide : Form, FormManager.IAppDialog{
|
sealed partial class FormGuide : Form, FormManager.IAppDialog {
|
||||||
private const string GuideUrl = "https://tweetduck.chylex.com/guide/v2/";
|
private const string GuideUrl = "td://guide/index.html";
|
||||||
private const string GuidePathRegex = @"^guide(?:/v\d+)?(?:/(#.*))?";
|
|
||||||
|
|
||||||
private static readonly ResourceLink DummyPage = new ResourceLink("http://td/dummy", ResourceHandler.FromString(""));
|
|
||||||
|
|
||||||
public static bool CheckGuideUrl(string url, out string hash){
|
public static void Show(string hash = null) {
|
||||||
if (!url.Contains("//tweetduck.chylex.com/guide")){
|
string url = GuideUrl + (string.IsNullOrEmpty(hash) ? string.Empty : "#" + hash);
|
||||||
hash = null;
|
FormGuide guide = FormManager.TryFind<FormGuide>();
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
string path = url.Substring(url.IndexOf("/guide")+1);
|
if (guide == null) {
|
||||||
Match match = Regex.Match(path, GuidePathRegex);
|
FormBrowser owner = FormManager.TryFind<FormBrowser>();
|
||||||
|
|
||||||
if (match.Success){
|
if (owner != null) {
|
||||||
hash = match.Groups[1].Value;
|
new FormGuide(url, owner).Show(owner);
|
||||||
return true;
|
}
|
||||||
}
|
}
|
||||||
else{
|
else {
|
||||||
hash = null;
|
guide.Reload(url);
|
||||||
return false;
|
guide.Activate();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void Show(string hash = null){
|
#pragma warning disable IDE0069 // Disposable fields should be disposed
|
||||||
string url = GuideUrl + (hash ?? string.Empty);
|
private readonly ChromiumWebBrowser browser;
|
||||||
FormGuide guide = FormManager.TryFind<FormGuide>();
|
#pragma warning restore IDE0069 // Disposable fields should be disposed
|
||||||
|
|
||||||
if (guide == null){
|
|
||||||
FormBrowser owner = FormManager.TryFind<FormBrowser>();
|
|
||||||
|
|
||||||
if (owner != null){
|
private FormGuide(string url, Form owner) {
|
||||||
owner.AnalyticsFile.OpenGuide.Trigger();
|
InitializeComponent();
|
||||||
new FormGuide(url, owner).Show(owner);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else{
|
|
||||||
guide.Reload(url);
|
|
||||||
guide.Activate();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#pragma warning disable IDE0069 // Disposable fields should be disposed
|
Text = Program.BrandName + " Guide";
|
||||||
private readonly ChromiumWebBrowser browser;
|
Size = new Size(owner.Size.Width * 3 / 4, owner.Size.Height * 3 / 4);
|
||||||
#pragma warning restore IDE0069 // Disposable fields should be disposed
|
VisibleChanged += (sender, args) => this.MoveToCenter(owner);
|
||||||
|
|
||||||
private string nextUrl;
|
browser = new ChromiumWebBrowser(url) {
|
||||||
|
KeyboardHandler = new CustomKeyboardHandler(null),
|
||||||
|
RequestHandler = new RequestHandlerBase(true)
|
||||||
|
};
|
||||||
|
|
||||||
private FormGuide(string url, FormBrowser owner){
|
browser.BrowserSettings.BackgroundColor = (uint) BackColor.ToArgb();
|
||||||
InitializeComponent();
|
|
||||||
|
|
||||||
Text = Program.BrandName + " Guide";
|
var browserComponent = new ComponentImpl(browser);
|
||||||
Size = new Size(owner.Size.Width * 3 / 4, owner.Size.Height * 3 / 4);
|
var browserImpl = new BaseBrowser(browserComponent);
|
||||||
VisibleChanged += (sender, args) => this.MoveToCenter(owner);
|
|
||||||
|
|
||||||
ResourceHandlerFactory resourceHandlerFactory = new ResourceHandlerFactory();
|
BrowserUtils.SetupDockOnLoad(browserComponent, browser);
|
||||||
resourceHandlerFactory.RegisterHandler(DummyPage);
|
|
||||||
|
|
||||||
this.browser = new ChromiumWebBrowser(url){
|
|
||||||
MenuHandler = new ContextMenuGuide(owner),
|
|
||||||
JsDialogHandler = new JavaScriptDialogHandler(),
|
|
||||||
KeyboardHandler = new KeyboardHandlerBase(),
|
|
||||||
LifeSpanHandler = new LifeSpanHandler(),
|
|
||||||
RequestHandler = new RequestHandlerBase(true),
|
|
||||||
ResourceHandlerFactory = resourceHandlerFactory
|
|
||||||
};
|
|
||||||
|
|
||||||
browser.LoadingStateChanged += browser_LoadingStateChanged;
|
Controls.Add(browser);
|
||||||
browser.FrameLoadEnd += browser_FrameLoadEnd;
|
|
||||||
|
|
||||||
browser.BrowserSettings.BackgroundColor = (uint)BackColor.ToArgb();
|
|
||||||
browser.Dock = DockStyle.None;
|
|
||||||
browser.Location = ControlExtensions.InvisibleLocation;
|
|
||||||
browser.SetupZoomEvents();
|
|
||||||
|
|
||||||
Controls.Add(browser);
|
Disposed += (sender, args) => {
|
||||||
Disposed += (sender, args) => browser.Dispose();
|
browserImpl.Dispose();
|
||||||
}
|
browser.Dispose();
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
protected override void Dispose(bool disposing){
|
private sealed class ComponentImpl : CefBrowserComponent {
|
||||||
if (disposing){
|
public ComponentImpl(ChromiumWebBrowser browser) : base(browser) {}
|
||||||
components?.Dispose();
|
|
||||||
}
|
|
||||||
|
|
||||||
base.Dispose(disposing);
|
protected override ContextMenuBase SetupContextMenu(IContextMenuHandler handler) {
|
||||||
}
|
return new ContextMenuGuide(handler);
|
||||||
|
}
|
||||||
|
|
||||||
private void Reload(string url){
|
protected override CefResourceHandlerFactory SetupResourceHandlerFactory(IResourceRequestHandler handler) {
|
||||||
nextUrl = url;
|
return new CefResourceHandlerFactory(handler, null);
|
||||||
browser.LoadingStateChanged += browser_LoadingStateChanged;
|
}
|
||||||
browser.Dock = DockStyle.None;
|
}
|
||||||
browser.Location = ControlExtensions.InvisibleLocation;
|
|
||||||
browser.Load(DummyPage.Url);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void browser_LoadingStateChanged(object sender, LoadingStateChangedEventArgs e){
|
protected override void Dispose(bool disposing) {
|
||||||
if (!e.IsLoading){
|
if (disposing) {
|
||||||
if (browser.Address == DummyPage.Url){
|
components?.Dispose();
|
||||||
browser.Load(nextUrl);
|
}
|
||||||
}
|
|
||||||
else{
|
|
||||||
this.InvokeAsyncSafe(() => {
|
|
||||||
browser.Location = Point.Empty;
|
|
||||||
browser.Dock = DockStyle.Fill;
|
|
||||||
});
|
|
||||||
|
|
||||||
browser.LoadingStateChanged -= browser_LoadingStateChanged;
|
base.Dispose(disposing);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void browser_FrameLoadEnd(object sender, FrameLoadEndEventArgs e){
|
private void Reload(string url) {
|
||||||
CefScriptExecutor.RunScript(e.Frame, "Array.prototype.forEach.call(document.getElementsByTagName('A'), ele => ele.addEventListener('click', e => { e.preventDefault(); window.open(ele.getAttribute('href')); }))", "gen:links");
|
browser.Load(url);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,219 +4,215 @@ using System.Windows.Forms;
|
|||||||
using TweetDuck.Controls;
|
using TweetDuck.Controls;
|
||||||
using TweetDuck.Utils;
|
using TweetDuck.Utils;
|
||||||
|
|
||||||
namespace TweetDuck.Dialogs{
|
namespace TweetDuck.Dialogs {
|
||||||
[Flags]
|
[Flags]
|
||||||
enum ControlType{
|
enum ControlType {
|
||||||
None = 0,
|
None = 0,
|
||||||
Accept = 1, // triggered by pressing enter when a non-button is focused
|
Accept = 1, // triggered by pressing enter when a non-button is focused
|
||||||
Cancel = 2, // triggered by closing the dialog without pressing a button
|
Cancel = 2, // triggered by closing the dialog without pressing a button
|
||||||
Focused = 4 // active control after the dialog is showed
|
Focused = 4 // active control after the dialog is showed
|
||||||
}
|
}
|
||||||
|
|
||||||
sealed partial class FormMessage : Form{
|
sealed partial class FormMessage : Form {
|
||||||
public const string OK = "OK";
|
public const string OK = "OK";
|
||||||
public const string Yes = "Yes";
|
public const string Yes = "Yes";
|
||||||
public const string No = "No";
|
public const string No = "No";
|
||||||
public const string Cancel = "Cancel";
|
public const string Cancel = "Cancel";
|
||||||
public const string Retry = "Retry";
|
public const string Retry = "Retry";
|
||||||
public const string Ignore = "Ignore";
|
public const string Ignore = "Ignore";
|
||||||
public const string Exit = "Exit";
|
public const string Exit = "Exit";
|
||||||
|
|
||||||
public static bool Information(string caption, string text, string buttonAccept, string buttonCancel = null){
|
public static bool Information(string caption, string text, string buttonAccept, string buttonCancel = null) {
|
||||||
return Show(caption, text, MessageBoxIcon.Information, buttonAccept, buttonCancel);
|
return Show(caption, text, MessageBoxIcon.Information, buttonAccept, buttonCancel);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static bool Warning(string caption, string text, string buttonAccept, string buttonCancel = null){
|
public static bool Warning(string caption, string text, string buttonAccept, string buttonCancel = null) {
|
||||||
return Show(caption, text, MessageBoxIcon.Warning, buttonAccept, buttonCancel);
|
return Show(caption, text, MessageBoxIcon.Warning, buttonAccept, buttonCancel);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static bool Error(string caption, string text, string buttonAccept, string buttonCancel = null){
|
public static bool Error(string caption, string text, string buttonAccept, string buttonCancel = null) {
|
||||||
return Show(caption, text, MessageBoxIcon.Error, buttonAccept, buttonCancel);
|
return Show(caption, text, MessageBoxIcon.Error, buttonAccept, buttonCancel);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static bool Question(string caption, string text, string buttonAccept, string buttonCancel = null){
|
public static bool Question(string caption, string text, string buttonAccept, string buttonCancel = null) {
|
||||||
return Show(caption, text, MessageBoxIcon.Question, buttonAccept, buttonCancel);
|
return Show(caption, text, MessageBoxIcon.Question, buttonAccept, buttonCancel);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static bool Show(string caption, string text, MessageBoxIcon icon, string button){
|
public static bool Show(string caption, string text, MessageBoxIcon icon, string buttonAccept, string buttonCancel = null) {
|
||||||
return Show(caption, text, icon, button, null);
|
using FormMessage message = new FormMessage(caption, text, icon);
|
||||||
}
|
|
||||||
|
|
||||||
public static bool Show(string caption, string text, MessageBoxIcon icon, string buttonAccept, string buttonCancel){
|
if (buttonCancel == null) {
|
||||||
using FormMessage message = new FormMessage(caption, text, icon);
|
message.AddButton(buttonAccept, DialogResult.OK, ControlType.Cancel | ControlType.Focused);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
message.AddButton(buttonCancel, DialogResult.Cancel, ControlType.Cancel);
|
||||||
|
message.AddButton(buttonAccept, DialogResult.OK, ControlType.Accept | ControlType.Focused);
|
||||||
|
}
|
||||||
|
|
||||||
if (buttonCancel == null){
|
return message.ShowDialog() == DialogResult.OK;
|
||||||
message.AddButton(buttonAccept, DialogResult.OK, ControlType.Cancel | ControlType.Focused);
|
}
|
||||||
}
|
|
||||||
else{
|
|
||||||
message.AddButton(buttonCancel, DialogResult.Cancel, ControlType.Cancel);
|
|
||||||
message.AddButton(buttonAccept, DialogResult.OK, ControlType.Accept | ControlType.Focused);
|
|
||||||
}
|
|
||||||
|
|
||||||
return message.ShowDialog() == DialogResult.OK;
|
// Instance
|
||||||
}
|
|
||||||
|
|
||||||
// Instance
|
public Button ClickedButton { get; private set; }
|
||||||
|
|
||||||
public Button ClickedButton { get; private set; }
|
public bool HasIcon => icon != null;
|
||||||
|
public int ActionPanelY => panelActions.Location.Y;
|
||||||
|
|
||||||
public bool HasIcon => icon != null;
|
private int ClientWidth {
|
||||||
public int ActionPanelY => panelActions.Location.Y;
|
get => ClientSize.Width;
|
||||||
|
set => ClientSize = new Size(value, ClientSize.Height);
|
||||||
|
}
|
||||||
|
|
||||||
private int ClientWidth{
|
private int ButtonDistance {
|
||||||
get => ClientSize.Width;
|
get => BrowserUtils.Scale(96, dpiScale);
|
||||||
set => ClientSize = new Size(value, ClientSize.Height);
|
}
|
||||||
}
|
|
||||||
|
|
||||||
private int ButtonDistance{
|
private readonly Icon icon;
|
||||||
get => BrowserUtils.Scale(96, dpiScale);
|
private readonly bool isReady;
|
||||||
}
|
private readonly float dpiScale;
|
||||||
|
|
||||||
private readonly Icon icon;
|
private int realFormWidth, minFormWidth;
|
||||||
private readonly bool isReady;
|
private int buttonCount;
|
||||||
private readonly float dpiScale;
|
private int prevLabelWidth, prevLabelHeight;
|
||||||
|
private bool wasLabelMultiline;
|
||||||
|
|
||||||
private int realFormWidth, minFormWidth;
|
public FormMessage(string caption, string text, MessageBoxIcon messageIcon) {
|
||||||
private int buttonCount;
|
InitializeComponent();
|
||||||
private int prevLabelWidth, prevLabelHeight;
|
|
||||||
private bool wasLabelMultiline;
|
|
||||||
|
|
||||||
public FormMessage(string caption, string text, MessageBoxIcon messageIcon){
|
this.dpiScale = this.GetDPIScale();
|
||||||
InitializeComponent();
|
|
||||||
|
|
||||||
this.dpiScale = this.GetDPIScale();
|
this.prevLabelWidth = labelMessage.Width;
|
||||||
|
this.prevLabelHeight = labelMessage.Height;
|
||||||
|
this.minFormWidth = BrowserUtils.Scale(42, dpiScale);
|
||||||
|
|
||||||
this.prevLabelWidth = labelMessage.Width;
|
switch (messageIcon) {
|
||||||
this.prevLabelHeight = labelMessage.Height;
|
case MessageBoxIcon.Information:
|
||||||
this.minFormWidth = BrowserUtils.Scale(42, dpiScale);
|
icon = SystemIcons.Information;
|
||||||
|
break;
|
||||||
|
|
||||||
switch(messageIcon){
|
case MessageBoxIcon.Warning:
|
||||||
case MessageBoxIcon.Information:
|
icon = SystemIcons.Warning;
|
||||||
icon = SystemIcons.Information;
|
break;
|
||||||
break;
|
|
||||||
|
|
||||||
case MessageBoxIcon.Warning:
|
case MessageBoxIcon.Error:
|
||||||
icon = SystemIcons.Warning;
|
icon = SystemIcons.Error;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case MessageBoxIcon.Error:
|
|
||||||
icon = SystemIcons.Error;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case MessageBoxIcon.Question:
|
case MessageBoxIcon.Question:
|
||||||
icon = SystemIcons.Question;
|
icon = SystemIcons.Question;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
icon = null;
|
icon = null;
|
||||||
labelMessage.Location = new Point(BrowserUtils.Scale(19, dpiScale), labelMessage.Location.Y); // 19 instead of 9 due to larger height
|
labelMessage.Location = new Point(BrowserUtils.Scale(19, dpiScale), labelMessage.Location.Y); // 19 instead of 9 due to larger height
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
this.isReady = true;
|
this.isReady = true;
|
||||||
|
|
||||||
this.Text = caption;
|
this.Text = caption;
|
||||||
this.labelMessage.Text = text.Replace("\r", "").Replace("\n", Environment.NewLine);
|
this.labelMessage.Text = text.Replace("\r", "").Replace("\n", Environment.NewLine);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void FormMessage_SizeChanged(object sender, EventArgs e){
|
private void FormMessage_SizeChanged(object sender, EventArgs e) {
|
||||||
RecalculateButtonLocation();
|
RecalculateButtonLocation();
|
||||||
}
|
}
|
||||||
|
|
||||||
public Button AddButton(string title, ControlType type){
|
public Button AddButton(string title, ControlType type) {
|
||||||
return AddButton(title, DialogResult.OK, type);
|
return AddButton(title, DialogResult.OK, type);
|
||||||
}
|
}
|
||||||
|
|
||||||
public Button AddButton(string title, DialogResult result = DialogResult.OK, ControlType type = ControlType.None){
|
public Button AddButton(string title, DialogResult result = DialogResult.OK, ControlType type = ControlType.None) {
|
||||||
Button button = new Button{
|
Button button = new Button {
|
||||||
Anchor = AnchorStyles.Bottom,
|
Anchor = AnchorStyles.Bottom,
|
||||||
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 = 256 - buttonCount,
|
TabIndex = 256 - buttonCount,
|
||||||
Text = title,
|
Text = title,
|
||||||
UseVisualStyleBackColor = true
|
UseVisualStyleBackColor = true
|
||||||
};
|
};
|
||||||
|
|
||||||
button.Click += (sender, args) => {
|
button.Click += (sender, args) => {
|
||||||
ClickedButton = (Button)sender;
|
ClickedButton = (Button) sender;
|
||||||
DialogResult = result;
|
DialogResult = result;
|
||||||
Close();
|
Close();
|
||||||
};
|
};
|
||||||
|
|
||||||
panelActions.Controls.Add(button);
|
panelActions.Controls.Add(button);
|
||||||
++buttonCount;
|
++buttonCount;
|
||||||
|
|
||||||
minFormWidth += ButtonDistance;
|
minFormWidth += ButtonDistance;
|
||||||
ClientWidth = Math.Max(realFormWidth, minFormWidth);
|
ClientWidth = Math.Max(realFormWidth, minFormWidth);
|
||||||
RecalculateButtonLocation();
|
RecalculateButtonLocation();
|
||||||
|
|
||||||
if (type.HasFlag(ControlType.Accept)){
|
if (type.HasFlag(ControlType.Accept)) {
|
||||||
AcceptButton = button;
|
AcceptButton = button;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (type.HasFlag(ControlType.Cancel)){
|
if (type.HasFlag(ControlType.Cancel)) {
|
||||||
CancelButton = button;
|
CancelButton = button;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (type.HasFlag(ControlType.Focused)){
|
if (type.HasFlag(ControlType.Focused)) {
|
||||||
ActiveControl = button;
|
ActiveControl = button;
|
||||||
}
|
}
|
||||||
|
|
||||||
return button;
|
return button;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void AddActionControl(Control control){
|
public void AddActionControl(Control control) {
|
||||||
panelActions.Controls.Add(control);
|
panelActions.Controls.Add(control);
|
||||||
|
|
||||||
control.Size = new Size(BrowserUtils.Scale(control.Width, dpiScale), BrowserUtils.Scale(control.Height, dpiScale));
|
|
||||||
|
|
||||||
minFormWidth += control.Width + control.Margin.Horizontal;
|
control.Size = new Size(BrowserUtils.Scale(control.Width, dpiScale), BrowserUtils.Scale(control.Height, dpiScale));
|
||||||
ClientWidth = Math.Max(realFormWidth, minFormWidth);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void RecalculateButtonLocation(){
|
|
||||||
int dist = ButtonDistance;
|
|
||||||
int start = ClientWidth - dist;
|
|
||||||
|
|
||||||
for(int index = 0; index < buttonCount; index++){
|
minFormWidth += control.Width + control.Margin.Horizontal;
|
||||||
Control control = panelActions.Controls[index];
|
ClientWidth = Math.Max(realFormWidth, minFormWidth);
|
||||||
control.Location = new Point(start - index * dist, control.Location.Y);
|
}
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void labelMessage_SizeChanged(object sender, EventArgs e){
|
private void RecalculateButtonLocation() {
|
||||||
if (!isReady){
|
int dist = ButtonDistance;
|
||||||
return;
|
int start = ClientWidth - dist;
|
||||||
}
|
|
||||||
|
|
||||||
bool isMultiline = labelMessage.Height > labelMessage.MinimumSize.Height;
|
for (int index = 0; index < buttonCount; index++) {
|
||||||
int labelOffset = BrowserUtils.Scale(8, dpiScale);
|
Control control = panelActions.Controls[index];
|
||||||
|
control.Location = new Point(start - index * dist, control.Location.Y);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (isMultiline && !wasLabelMultiline){
|
private void labelMessage_SizeChanged(object sender, EventArgs e) {
|
||||||
labelMessage.Location = new Point(labelMessage.Location.X, labelMessage.Location.Y - labelOffset);
|
if (!isReady) {
|
||||||
prevLabelHeight += labelOffset;
|
return;
|
||||||
}
|
}
|
||||||
else if (!isMultiline && wasLabelMultiline){
|
|
||||||
labelMessage.Location = new Point(labelMessage.Location.X, labelMessage.Location.Y + labelOffset);
|
|
||||||
prevLabelHeight -= labelOffset;
|
|
||||||
}
|
|
||||||
|
|
||||||
realFormWidth = ClientWidth - (icon == null ? BrowserUtils.Scale(50, dpiScale) : 0) + labelMessage.Width - prevLabelWidth;
|
bool isMultiline = labelMessage.Height > labelMessage.MinimumSize.Height;
|
||||||
ClientWidth = Math.Max(realFormWidth, minFormWidth);
|
int labelOffset = BrowserUtils.Scale(8, dpiScale);
|
||||||
Height += labelMessage.Height - prevLabelHeight;
|
|
||||||
|
|
||||||
prevLabelWidth = labelMessage.Width;
|
if (isMultiline && !wasLabelMultiline) {
|
||||||
prevLabelHeight = labelMessage.Height;
|
labelMessage.Location = new Point(labelMessage.Location.X, labelMessage.Location.Y - labelOffset);
|
||||||
wasLabelMultiline = isMultiline;
|
prevLabelHeight += labelOffset;
|
||||||
}
|
}
|
||||||
|
else if (!isMultiline && wasLabelMultiline) {
|
||||||
|
labelMessage.Location = new Point(labelMessage.Location.X, labelMessage.Location.Y + labelOffset);
|
||||||
|
prevLabelHeight -= labelOffset;
|
||||||
|
}
|
||||||
|
|
||||||
protected override void OnPaint(PaintEventArgs e){
|
realFormWidth = ClientWidth - (icon == null ? BrowserUtils.Scale(50, dpiScale) : 0) + labelMessage.Width - prevLabelWidth;
|
||||||
if (icon != null){
|
ClientWidth = Math.Max(realFormWidth, minFormWidth);
|
||||||
e.Graphics.DrawIcon(icon, BrowserUtils.Scale(25, dpiScale), 1 + BrowserUtils.Scale(25, dpiScale));
|
Height += labelMessage.Height - prevLabelHeight;
|
||||||
}
|
|
||||||
|
|
||||||
base.OnPaint(e);
|
prevLabelWidth = labelMessage.Width;
|
||||||
}
|
prevLabelHeight = labelMessage.Height;
|
||||||
}
|
wasLabelMultiline = isMultiline;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void OnPaint(PaintEventArgs e) {
|
||||||
|
if (icon != null) {
|
||||||
|
e.Graphics.DrawIcon(icon, BrowserUtils.Scale(25, dpiScale), 1 + BrowserUtils.Scale(25, dpiScale));
|
||||||
|
}
|
||||||
|
|
||||||
|
base.OnPaint(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,107 +7,109 @@ using TweetDuck.Management;
|
|||||||
using TweetDuck.Plugins;
|
using TweetDuck.Plugins;
|
||||||
using TweetLib.Core;
|
using TweetLib.Core;
|
||||||
using TweetLib.Core.Features.Plugins;
|
using TweetLib.Core.Features.Plugins;
|
||||||
|
using TweetLib.Core.Features.Plugins.Enums;
|
||||||
|
using TweetLib.Core.Systems.Configuration;
|
||||||
|
|
||||||
namespace TweetDuck.Dialogs{
|
namespace TweetDuck.Dialogs {
|
||||||
sealed partial class FormPlugins : Form, FormManager.IAppDialog{
|
sealed partial class FormPlugins : Form, FormManager.IAppDialog {
|
||||||
private static UserConfig Config => Program.Config.User;
|
private static UserConfig Config => Program.Config.User;
|
||||||
|
|
||||||
private readonly PluginManager pluginManager;
|
private readonly PluginManager pluginManager;
|
||||||
|
|
||||||
public FormPlugins(){
|
|
||||||
InitializeComponent();
|
|
||||||
|
|
||||||
Text = Program.BrandName + " Plugins";
|
public FormPlugins() {
|
||||||
}
|
InitializeComponent();
|
||||||
|
|
||||||
public FormPlugins(PluginManager pluginManager) : this(){
|
Text = Program.BrandName + " Plugins";
|
||||||
this.pluginManager = pluginManager;
|
}
|
||||||
|
|
||||||
if (!Config.PluginsWindowSize.IsEmpty){
|
public FormPlugins(PluginManager pluginManager) : this() {
|
||||||
Size targetSize = Config.PluginsWindowSize;
|
this.pluginManager = pluginManager;
|
||||||
Size = new Size(Math.Max(MinimumSize.Width, targetSize.Width), Math.Max(MinimumSize.Height, targetSize.Height));
|
|
||||||
}
|
|
||||||
|
|
||||||
Shown += (sender, args) => {
|
|
||||||
ReloadPluginList();
|
|
||||||
};
|
|
||||||
|
|
||||||
FormClosed += (sender, args) => {
|
if (!Config.PluginsWindowSize.IsEmpty) {
|
||||||
Config.PluginsWindowSize = Size;
|
Size targetSize = Config.PluginsWindowSize;
|
||||||
Config.Save();
|
Size = new Size(Math.Max(MinimumSize.Width, targetSize.Width), Math.Max(MinimumSize.Height, targetSize.Height));
|
||||||
};
|
}
|
||||||
|
|
||||||
ResizeEnd += (sender, args) => {
|
Shown += (sender, args) => {
|
||||||
timerLayout.Start();
|
ReloadPluginList();
|
||||||
};
|
};
|
||||||
}
|
|
||||||
|
|
||||||
private int GetPluginOrderIndex(Plugin plugin){
|
FormClosed += (sender, args) => {
|
||||||
return !plugin.CanRun ? 0 : pluginManager.Config.IsEnabled(plugin) ? 1 : 2;
|
Config.PluginsWindowSize = Size;
|
||||||
}
|
Config.Save();
|
||||||
|
};
|
||||||
|
|
||||||
private void ReloadPluginList(){
|
ResizeEnd += (sender, args) => {
|
||||||
flowLayoutPlugins.Controls.Clear();
|
timerLayout.Start();
|
||||||
flowLayoutPlugins.SuspendLayout();
|
};
|
||||||
|
}
|
||||||
|
|
||||||
foreach(Plugin plugin in pluginManager.Plugins.OrderBy(GetPluginOrderIndex).ThenBy(plugin => plugin.Name)){
|
private int GetPluginOrderIndex(Plugin plugin) {
|
||||||
flowLayoutPlugins.Controls.Add(new PluginControl(pluginManager, plugin));
|
return !plugin.CanRun ? 0 : pluginManager.Config.IsEnabled(plugin) ? 1 : 2;
|
||||||
|
}
|
||||||
|
|
||||||
flowLayoutPlugins.Controls.Add(new Panel{
|
private void ReloadPluginList() {
|
||||||
BackColor = Color.DimGray,
|
flowLayoutPlugins.Controls.Clear();
|
||||||
Margin = new Padding(0),
|
flowLayoutPlugins.SuspendLayout();
|
||||||
Size = new Size(1, 1)
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
flowLayoutPlugins.ResumeLayout(true);
|
foreach (Plugin plugin in pluginManager.Plugins.OrderBy(GetPluginOrderIndex).ThenBy(plugin => plugin.Name)) {
|
||||||
|
flowLayoutPlugins.Controls.Add(new PluginControl(pluginManager, plugin));
|
||||||
timerLayout_Tick(null, EventArgs.Empty);
|
|
||||||
timerLayout.Start();
|
|
||||||
}
|
|
||||||
|
|
||||||
private void timerLayout_Tick(object sender, EventArgs e){
|
flowLayoutPlugins.Controls.Add(new Panel {
|
||||||
timerLayout.Stop();
|
BackColor = Color.DimGray,
|
||||||
|
Margin = new Padding(0),
|
||||||
// stupid WinForms scrollbars and panels
|
Size = new Size(1, 1)
|
||||||
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){
|
flowLayoutPlugins.ResumeLayout(true);
|
||||||
Control lastPlugin = flowLayoutPlugins.Controls.OfType<PluginControl>().LastOrDefault();
|
|
||||||
|
|
||||||
if (lastPlugin == null){
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool showScrollBar = lastPlugin.Location.Y + lastPlugin.Height + 1 >= flowLayoutPlugins.Height;
|
timerLayout_Tick(null, EventArgs.Empty);
|
||||||
int horizontalOffset = showScrollBar ? SystemInformation.VerticalScrollBarWidth : 0;
|
timerLayout.Start();
|
||||||
|
}
|
||||||
flowLayoutPlugins.AutoScroll = showScrollBar;
|
|
||||||
flowLayoutPlugins.VerticalScroll.Visible = showScrollBar;
|
|
||||||
|
|
||||||
foreach(Control control in flowLayoutPlugins.Controls){
|
private void timerLayout_Tick(object sender, EventArgs e) {
|
||||||
control.Width = flowLayoutPlugins.Width - control.Margin.Horizontal - horizontalOffset;
|
timerLayout.Stop();
|
||||||
}
|
|
||||||
|
|
||||||
flowLayoutPlugins.Controls[flowLayoutPlugins.Controls.Count - 1].Visible = !showScrollBar;
|
|
||||||
flowLayoutPlugins.Focus();
|
|
||||||
}
|
|
||||||
|
|
||||||
private void btnOpenFolder_Click(object sender, EventArgs e){
|
// stupid WinForms scrollbars and panels
|
||||||
App.SystemHandler.OpenFileExplorer(pluginManager.PathCustomPlugins);
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
private void btnReload_Click(object sender, EventArgs e){
|
private void flowLayoutPlugins_Resize(object sender, EventArgs e) {
|
||||||
if (FormMessage.Warning("Reloading Plugins", "This will also reload the browser window. Do you want to proceed?", FormMessage.Yes, FormMessage.No)){
|
Control lastPlugin = flowLayoutPlugins.Controls.OfType<PluginControl>().LastOrDefault();
|
||||||
pluginManager.Reload();
|
|
||||||
ReloadPluginList();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void btnClose_Click(object sender, EventArgs e){
|
if (lastPlugin == null) {
|
||||||
Close();
|
return;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
bool showScrollBar = lastPlugin.Location.Y + lastPlugin.Height + 1 >= flowLayoutPlugins.Height;
|
||||||
|
int horizontalOffset = showScrollBar ? SystemInformation.VerticalScrollBarWidth : 0;
|
||||||
|
|
||||||
|
flowLayoutPlugins.AutoScroll = showScrollBar;
|
||||||
|
flowLayoutPlugins.VerticalScroll.Visible = showScrollBar;
|
||||||
|
|
||||||
|
foreach (Control control in flowLayoutPlugins.Controls) {
|
||||||
|
control.Width = flowLayoutPlugins.Width - control.Margin.Horizontal - horizontalOffset;
|
||||||
|
}
|
||||||
|
|
||||||
|
flowLayoutPlugins.Controls[flowLayoutPlugins.Controls.Count - 1].Visible = !showScrollBar;
|
||||||
|
flowLayoutPlugins.Focus();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void btnOpenFolder_Click(object sender, EventArgs e) {
|
||||||
|
App.SystemHandler.OpenFileExplorer(pluginManager.GetPluginFolder(PluginGroup.Custom));
|
||||||
|
}
|
||||||
|
|
||||||
|
private void btnReload_Click(object sender, EventArgs e) {
|
||||||
|
if (FormMessage.Warning("Reloading Plugins", "This will also reload the browser window. Do you want to proceed?", FormMessage.Yes, FormMessage.No)) {
|
||||||
|
pluginManager.Reload();
|
||||||
|
ReloadPluginList();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void btnClose_Click(object sender, EventArgs e) {
|
||||||
|
Close();
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,241 +3,241 @@ using System.Collections.Generic;
|
|||||||
using System.Drawing;
|
using System.Drawing;
|
||||||
using System.Windows.Forms;
|
using System.Windows.Forms;
|
||||||
using TweetDuck.Browser;
|
using TweetDuck.Browser;
|
||||||
using TweetDuck.Browser.Handling.General;
|
using TweetDuck.Browser.Handling;
|
||||||
using TweetDuck.Browser.Notification.Example;
|
|
||||||
using TweetDuck.Configuration;
|
using TweetDuck.Configuration;
|
||||||
using TweetDuck.Controls;
|
using TweetDuck.Controls;
|
||||||
using TweetDuck.Dialogs.Settings;
|
using TweetDuck.Dialogs.Settings;
|
||||||
using TweetDuck.Management;
|
using TweetDuck.Management;
|
||||||
using TweetDuck.Management.Analytics;
|
|
||||||
using TweetDuck.Utils;
|
using TweetDuck.Utils;
|
||||||
|
using TweetLib.Core;
|
||||||
using TweetLib.Core.Features.Plugins;
|
using TweetLib.Core.Features.Plugins;
|
||||||
using TweetLib.Core.Features.Updates;
|
using TweetLib.Core.Features.TweetDeck;
|
||||||
|
using TweetLib.Core.Systems.Updates;
|
||||||
|
|
||||||
namespace TweetDuck.Dialogs{
|
namespace TweetDuck.Dialogs {
|
||||||
sealed partial class FormSettings : Form, FormManager.IAppDialog{
|
sealed partial class FormSettings : Form, FormManager.IAppDialog {
|
||||||
public bool ShouldReloadBrowser { get; private set; }
|
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>(8);
|
private readonly Dictionary<Type, SettingsTab> tabs = new Dictionary<Type, SettingsTab>(8);
|
||||||
private SettingsTab currentTab;
|
private SettingsTab currentTab;
|
||||||
|
|
||||||
public FormSettings(FormBrowser browser, PluginManager plugins, UpdateHandler updates, AnalyticsManager analytics, Type startTab){
|
public FormSettings(FormBrowser browser, PluginManager plugins, UpdateChecker updates, TweetDeckFunctions tweetDeckFunctions, Type startTab) {
|
||||||
InitializeComponent();
|
InitializeComponent();
|
||||||
|
|
||||||
Text = Program.BrandName + " Options";
|
Text = Program.BrandName + " Options";
|
||||||
|
|
||||||
this.browser = browser;
|
this.browser = browser;
|
||||||
this.browser.PauseNotification();
|
this.browser.PauseNotification();
|
||||||
|
|
||||||
this.plugins = plugins;
|
this.plugins = plugins;
|
||||||
|
|
||||||
this.buttonHeight = BrowserUtils.Scale(39, this.GetDPIScale()) | 1;
|
|
||||||
|
|
||||||
PrepareLoad();
|
this.buttonHeight = BrowserUtils.Scale(39, this.GetDPIScale()) | 1;
|
||||||
|
|
||||||
AddButton("General", () => new TabSettingsGeneral(this.browser.ReloadColumns, updates));
|
PrepareLoad();
|
||||||
AddButton("Notifications", () => new TabSettingsNotifications(new FormNotificationExample(this.browser, this.plugins)));
|
|
||||||
AddButton("Sounds", () => new TabSettingsSounds(this.browser.PlaySoundNotification));
|
|
||||||
AddButton("Tray", () => new TabSettingsTray());
|
|
||||||
AddButton("Feedback", () => new TabSettingsFeedback(analytics, AnalyticsReportGenerator.ExternalInfo.From(this.browser), this.plugins));
|
|
||||||
AddButton("Advanced", () => new TabSettingsAdvanced(this.browser.ReinjectCustomCSS, this.browser.OpenDevTools));
|
|
||||||
|
|
||||||
SelectTab(tabs[startTab ?? typeof(TabSettingsGeneral)]);
|
AddButton("General", () => new TabSettingsGeneral(this.browser.ReloadToTweetDeck, tweetDeckFunctions.ReloadColumns, updates));
|
||||||
}
|
AddButton("Notifications", () => new TabSettingsNotifications(this.browser.CreateExampleNotification()));
|
||||||
|
AddButton("Sounds", () => new TabSettingsSounds(() => tweetDeckFunctions.PlaySoundNotification(true)));
|
||||||
|
AddButton("Tray", () => new TabSettingsTray());
|
||||||
|
AddButton("Feedback", () => new TabSettingsFeedback());
|
||||||
|
AddButton("Advanced", () => new TabSettingsAdvanced(tweetDeckFunctions.ReinjectCustomCSS, this.browser.OpenDevTools));
|
||||||
|
|
||||||
private void PrepareLoad(){
|
SelectTab(tabs[startTab ?? typeof(TabSettingsGeneral)]);
|
||||||
Program.Config.ProgramRestartRequested += Config_ProgramRestartRequested;
|
}
|
||||||
}
|
|
||||||
|
|
||||||
private void PrepareUnload(){ // TODO refactor this further later
|
private void PrepareLoad() {
|
||||||
currentTab.Control.OnClosing();
|
App.ConfigManager.ProgramRestartRequested += Config_ProgramRestartRequested;
|
||||||
|
}
|
||||||
Program.Config.ProgramRestartRequested -= Config_ProgramRestartRequested;
|
|
||||||
Program.Config.SaveAll();
|
|
||||||
}
|
|
||||||
|
|
||||||
private void Config_ProgramRestartRequested(object sender, EventArgs e){
|
private void PrepareUnload() { // TODO refactor this further later
|
||||||
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)){
|
currentTab.Control.OnClosing();
|
||||||
Program.Restart();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void FormSettings_FormClosing(object sender, FormClosingEventArgs e){
|
App.ConfigManager.ProgramRestartRequested -= Config_ProgramRestartRequested;
|
||||||
PrepareUnload();
|
App.ConfigManager.SaveAll();
|
||||||
|
}
|
||||||
|
|
||||||
foreach(SettingsTab tab in tabs.Values){
|
private void Config_ProgramRestartRequested(object sender, EventArgs e) {
|
||||||
if (tab.IsInitialized){
|
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)) {
|
||||||
tab.Control.Dispose();
|
Program.Restart();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
browser.ResumeNotification();
|
|
||||||
}
|
|
||||||
|
|
||||||
private void btnManageOptions_Click(object sender, EventArgs e){
|
private void FormSettings_FormClosing(object sender, FormClosingEventArgs e) {
|
||||||
PrepareUnload();
|
PrepareUnload();
|
||||||
|
|
||||||
using DialogSettingsManage dialog = new DialogSettingsManage(plugins);
|
foreach (SettingsTab tab in tabs.Values) {
|
||||||
FormClosing -= FormSettings_FormClosing;
|
if (tab.IsInitialized) {
|
||||||
|
tab.Control.Dispose();
|
||||||
if (dialog.ShowDialog() == DialogResult.OK){
|
}
|
||||||
if (!dialog.IsRestarting){
|
}
|
||||||
browser.ResumeNotification();
|
|
||||||
|
|
||||||
if (dialog.ShouldReloadBrowser){
|
browser.ResumeNotification();
|
||||||
BrowserProcessHandler.UpdatePrefs();
|
}
|
||||||
ShouldReloadBrowser = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Close();
|
private void btnManageOptions_Click(object sender, EventArgs e) {
|
||||||
}
|
PrepareUnload();
|
||||||
else{
|
|
||||||
FormClosing += FormSettings_FormClosing;
|
|
||||||
PrepareLoad();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void btnClose_Click(object sender, EventArgs e){
|
using DialogSettingsManage dialog = new DialogSettingsManage(plugins);
|
||||||
Close();
|
FormClosing -= FormSettings_FormClosing;
|
||||||
}
|
|
||||||
|
|
||||||
private void AddButton<T>(string title, Func<T> constructor) where T : BaseTab{
|
if (dialog.ShowDialog() == DialogResult.OK) {
|
||||||
FlatButton btn = new FlatButton{
|
if (!dialog.IsRestarting) {
|
||||||
BackColor = SystemColors.Control,
|
browser.ResumeNotification();
|
||||||
FlatStyle = FlatStyle.Flat,
|
|
||||||
Font = SystemFonts.MessageBoxFont,
|
|
||||||
Location = new Point(0, (buttonHeight + 1) * (panelButtons.Controls.Count / 2)),
|
|
||||||
Margin = new Padding(0),
|
|
||||||
Size = new Size(panelButtons.Width, buttonHeight),
|
|
||||||
Text = title,
|
|
||||||
UseVisualStyleBackColor = true
|
|
||||||
};
|
|
||||||
|
|
||||||
btn.FlatAppearance.BorderSize = 0;
|
if (dialog.ShouldReloadBrowser) {
|
||||||
btn.FlatAppearance.MouseDownBackColor = Color.FromArgb(179, 213, 232);
|
BrowserProcessHandler.UpdatePrefs();
|
||||||
btn.FlatAppearance.MouseOverBackColor = Color.FromArgb(216, 230, 237);
|
ShouldReloadBrowser = true;
|
||||||
|
}
|
||||||
panelButtons.Controls.Add(btn);
|
}
|
||||||
|
|
||||||
panelButtons.Controls.Add(new Panel{
|
Close();
|
||||||
BackColor = Color.DimGray,
|
}
|
||||||
Location = new Point(0, panelButtons.Controls[panelButtons.Controls.Count - 1].Location.Y + buttonHeight),
|
else {
|
||||||
Margin = new Padding(0),
|
FormClosing += FormSettings_FormClosing;
|
||||||
Size = new Size(panelButtons.Width, 1)
|
PrepareLoad();
|
||||||
});
|
}
|
||||||
|
}
|
||||||
|
|
||||||
tabs.Add(typeof(T), new SettingsTab(btn, constructor));
|
private void btnClose_Click(object sender, EventArgs e) {
|
||||||
|
Close();
|
||||||
|
}
|
||||||
|
|
||||||
btn.Click += (sender, args) => SelectTab<T>();
|
private void AddButton<T>(string title, Func<T> constructor) where T : BaseTab {
|
||||||
}
|
FlatButton btn = new FlatButton {
|
||||||
|
BackColor = SystemColors.Control,
|
||||||
|
FlatStyle = FlatStyle.Flat,
|
||||||
|
Font = SystemFonts.MessageBoxFont,
|
||||||
|
Location = new Point(0, (buttonHeight + 1) * (panelButtons.Controls.Count / 2)),
|
||||||
|
Margin = new Padding(0),
|
||||||
|
Size = new Size(panelButtons.Width, buttonHeight),
|
||||||
|
Text = title,
|
||||||
|
UseVisualStyleBackColor = true
|
||||||
|
};
|
||||||
|
|
||||||
private void SelectTab<T>() where T : BaseTab{
|
btn.FlatAppearance.BorderSize = 0;
|
||||||
SelectTab(tabs[typeof(T)]);
|
btn.FlatAppearance.MouseDownBackColor = Color.FromArgb(179, 213, 232);
|
||||||
}
|
btn.FlatAppearance.MouseOverBackColor = Color.FromArgb(216, 230, 237);
|
||||||
|
|
||||||
private void SelectTab(SettingsTab tab){
|
panelButtons.Controls.Add(btn);
|
||||||
if (currentTab != null){
|
|
||||||
currentTab.Button.BackColor = SystemColors.Control;
|
|
||||||
currentTab.Control.OnClosing();
|
|
||||||
}
|
|
||||||
|
|
||||||
tab.Button.BackColor = tab.Button.FlatAppearance.MouseDownBackColor;
|
|
||||||
|
|
||||||
if (!tab.IsInitialized){
|
panelButtons.Controls.Add(new Panel {
|
||||||
foreach(Control control in tab.Control.InteractiveControls){
|
BackColor = Color.DimGray,
|
||||||
if (control is ComboBox){
|
Location = new Point(0, panelButtons.Controls[panelButtons.Controls.Count - 1].Location.Y + buttonHeight),
|
||||||
control.MouseLeave += control_MouseLeave;
|
Margin = new Padding(0),
|
||||||
}
|
Size = new Size(panelButtons.Width, 1)
|
||||||
else if (control is TrackBar){
|
});
|
||||||
control.MouseWheel += control_MouseWheel;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (tab.Control.Height < panelContents.Height - 2){
|
tabs.Add(typeof(T), new SettingsTab(btn, constructor));
|
||||||
tab.Control.Height = panelContents.Height - 2; // fixes off-by-pixel error on high DPI
|
|
||||||
}
|
|
||||||
|
|
||||||
tab.Control.OnReady();
|
btn.Click += (sender, args) => SelectTab<T>();
|
||||||
}
|
}
|
||||||
|
|
||||||
panelContents.VerticalScroll.Enabled = false; // required to stop animation that would otherwise break everything
|
|
||||||
panelContents.PerformLayout();
|
|
||||||
|
|
||||||
panelContents.SuspendLayout();
|
private void SelectTab<T>() where T : BaseTab {
|
||||||
panelContents.VerticalScroll.Value = 0; // https://gfycat.com/GrotesqueTastyAstarte
|
SelectTab(tabs[typeof(T)]);
|
||||||
panelContents.Controls.Clear();
|
}
|
||||||
panelContents.Controls.Add(tab.Control);
|
|
||||||
panelContents.ResumeLayout(true);
|
|
||||||
|
|
||||||
panelContents.VerticalScroll.Enabled = true;
|
private void SelectTab(SettingsTab tab) {
|
||||||
panelContents.Focus();
|
if (currentTab != null) {
|
||||||
|
currentTab.Button.BackColor = SystemColors.Control;
|
||||||
|
currentTab.Control.OnClosing();
|
||||||
|
}
|
||||||
|
|
||||||
currentTab = tab;
|
tab.Button.BackColor = tab.Button.FlatAppearance.MouseDownBackColor;
|
||||||
}
|
|
||||||
|
|
||||||
private void control_MouseLeave(object sender, EventArgs e){
|
if (!tab.IsInitialized) {
|
||||||
if (sender is ComboBox cb && cb.DroppedDown){
|
foreach (Control control in tab.Control.InteractiveControls) {
|
||||||
return; // prevents comboboxes from closing when MouseLeave event triggers during opening animation
|
if (control is ComboBox) {
|
||||||
}
|
control.MouseLeave += control_MouseLeave;
|
||||||
|
}
|
||||||
|
else if (control is TrackBar) {
|
||||||
|
control.MouseWheel += control_MouseWheel;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
panelContents.Focus();
|
if (tab.Control.Height < panelContents.Height - 2) {
|
||||||
}
|
tab.Control.Height = panelContents.Height - 2; // fixes off-by-pixel error on high DPI
|
||||||
|
}
|
||||||
|
|
||||||
private void control_MouseWheel(object sender, MouseEventArgs e){
|
tab.Control.OnReady();
|
||||||
((HandledMouseEventArgs)e).Handled = true;
|
}
|
||||||
panelContents.Focus();
|
|
||||||
}
|
|
||||||
|
|
||||||
private sealed class SettingsTab{
|
panelContents.VerticalScroll.Enabled = false; // required to stop animation that would otherwise break everything
|
||||||
public Button Button { get; }
|
panelContents.PerformLayout();
|
||||||
|
|
||||||
public BaseTab Control => control ??= constructor();
|
panelContents.SuspendLayout();
|
||||||
public bool IsInitialized => control != null;
|
panelContents.VerticalScroll.Value = 0; // https://gfycat.com/GrotesqueTastyAstarte
|
||||||
|
panelContents.Controls.Clear();
|
||||||
|
panelContents.Controls.Add(tab.Control);
|
||||||
|
panelContents.ResumeLayout(true);
|
||||||
|
|
||||||
private readonly Func<BaseTab> constructor;
|
panelContents.VerticalScroll.Enabled = true;
|
||||||
private BaseTab control;
|
panelContents.Focus();
|
||||||
|
|
||||||
public SettingsTab(Button button, Func<BaseTab> constructor){
|
currentTab = tab;
|
||||||
this.Button = button;
|
}
|
||||||
this.constructor = constructor;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
internal abstract class BaseTab : UserControl{
|
private void control_MouseLeave(object sender, EventArgs e) {
|
||||||
protected static UserConfig Config => Program.Config.User;
|
if (sender is ComboBox { DroppedDown: true } ) {
|
||||||
protected static SystemConfig SysConfig => Program.Config.System;
|
return; // prevents comboboxes from closing when MouseLeave event triggers during opening animation
|
||||||
|
}
|
||||||
|
|
||||||
public IEnumerable<Control> InteractiveControls{
|
panelContents.Focus();
|
||||||
get{
|
}
|
||||||
static IEnumerable<Control> FindInteractiveControls(Control parent){
|
|
||||||
foreach(Control control in parent.Controls){
|
|
||||||
if (control is Panel subPanel){
|
|
||||||
foreach(Control subControl in FindInteractiveControls(subPanel)){
|
|
||||||
yield return subControl;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else{
|
|
||||||
yield return control;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return FindInteractiveControls(this);
|
private void control_MouseWheel(object sender, MouseEventArgs e) {
|
||||||
}
|
((HandledMouseEventArgs) e).Handled = true;
|
||||||
}
|
panelContents.Focus();
|
||||||
|
}
|
||||||
|
|
||||||
protected BaseTab(){
|
private sealed class SettingsTab {
|
||||||
Padding = new Padding(6);
|
public Button Button { get; }
|
||||||
}
|
|
||||||
|
|
||||||
public virtual void OnReady(){}
|
public BaseTab Control => control ??= constructor();
|
||||||
public virtual void OnClosing(){}
|
public bool IsInitialized => control != null;
|
||||||
}
|
|
||||||
}
|
private readonly Func<BaseTab> constructor;
|
||||||
|
private BaseTab control;
|
||||||
|
|
||||||
|
public SettingsTab(Button button, Func<BaseTab> constructor) {
|
||||||
|
this.Button = button;
|
||||||
|
this.constructor = constructor;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
internal class BaseTab : UserControl {
|
||||||
|
protected static UserConfig Config => Program.Config.User;
|
||||||
|
protected static SystemConfig SysConfig => Program.Config.System;
|
||||||
|
|
||||||
|
public IEnumerable<Control> InteractiveControls {
|
||||||
|
get {
|
||||||
|
static IEnumerable<Control> FindInteractiveControls(Control parent) {
|
||||||
|
foreach (Control control in parent.Controls) {
|
||||||
|
if (control is Panel subPanel) {
|
||||||
|
foreach (Control subControl in FindInteractiveControls(subPanel)) {
|
||||||
|
yield return subControl;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
yield return control;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return FindInteractiveControls(this);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected BaseTab() {
|
||||||
|
Padding = new Padding(6);
|
||||||
|
}
|
||||||
|
|
||||||
|
public virtual void OnReady() {}
|
||||||
|
public virtual void OnClosing() {}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
94
Dialogs/Settings/DialogSettingsAnalytics.Designer.cs
generated
94
Dialogs/Settings/DialogSettingsAnalytics.Designer.cs
generated
@@ -1,94 +0,0 @@
|
|||||||
namespace TweetDuck.Dialogs.Settings {
|
|
||||||
partial class DialogSettingsAnalytics {
|
|
||||||
/// <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.textBoxReport = new System.Windows.Forms.TextBox();
|
|
||||||
this.btnClose = new System.Windows.Forms.Button();
|
|
||||||
this.labelInfo = new System.Windows.Forms.Label();
|
|
||||||
this.SuspendLayout();
|
|
||||||
//
|
|
||||||
// textBoxReport
|
|
||||||
//
|
|
||||||
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.Right)));
|
|
||||||
this.textBoxReport.Font = new System.Drawing.Font("Courier New", 8.25F, System.Drawing.FontStyle.Regular);
|
|
||||||
this.textBoxReport.Location = new System.Drawing.Point(12, 45);
|
|
||||||
this.textBoxReport.Multiline = true;
|
|
||||||
this.textBoxReport.Name = "textBoxReport";
|
|
||||||
this.textBoxReport.ReadOnly = true;
|
|
||||||
this.textBoxReport.ScrollBars = System.Windows.Forms.ScrollBars.Both;
|
|
||||||
this.textBoxReport.Size = new System.Drawing.Size(435, 474);
|
|
||||||
this.textBoxReport.TabIndex = 1;
|
|
||||||
//
|
|
||||||
// btnClose
|
|
||||||
//
|
|
||||||
this.btnClose.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right)));
|
|
||||||
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.Padding = new System.Windows.Forms.Padding(2, 0, 2, 0);
|
|
||||||
this.btnClose.Size = new System.Drawing.Size(50, 25);
|
|
||||||
this.btnClose.TabIndex = 2;
|
|
||||||
this.btnClose.Text = "Close";
|
|
||||||
this.btnClose.UseVisualStyleBackColor = true;
|
|
||||||
this.btnClose.Click += new System.EventHandler(this.btnClose_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(434, 30);
|
|
||||||
this.labelInfo.TabIndex = 0;
|
|
||||||
this.labelInfo.Text = "When enabled, this data will be sent over a secure network roughly every 14 days." +
|
|
||||||
"\r\nSome numbers in the report were made imprecise on purpose.";
|
|
||||||
//
|
|
||||||
// DialogSettingsAnalytics
|
|
||||||
//
|
|
||||||
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
|
|
||||||
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
|
|
||||||
this.ClientSize = new System.Drawing.Size(459, 562);
|
|
||||||
this.Controls.Add(this.labelInfo);
|
|
||||||
this.Controls.Add(this.btnClose);
|
|
||||||
this.Controls.Add(this.textBoxReport);
|
|
||||||
this.MinimumSize = new System.Drawing.Size(475, 340);
|
|
||||||
this.Name = "DialogSettingsAnalytics";
|
|
||||||
this.ShowIcon = false;
|
|
||||||
this.StartPosition = System.Windows.Forms.FormStartPosition.CenterParent;
|
|
||||||
this.ResumeLayout(false);
|
|
||||||
this.PerformLayout();
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
#endregion
|
|
||||||
|
|
||||||
private System.Windows.Forms.TextBox textBoxReport;
|
|
||||||
private System.Windows.Forms.Button btnClose;
|
|
||||||
private System.Windows.Forms.Label labelInfo;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,22 +0,0 @@
|
|||||||
using System;
|
|
||||||
using System.Windows.Forms;
|
|
||||||
using TweetDuck.Controls;
|
|
||||||
using TweetDuck.Management.Analytics;
|
|
||||||
|
|
||||||
namespace TweetDuck.Dialogs.Settings{
|
|
||||||
sealed partial class DialogSettingsAnalytics : Form{
|
|
||||||
public DialogSettingsAnalytics(AnalyticsReport report){
|
|
||||||
InitializeComponent();
|
|
||||||
|
|
||||||
Text = Program.BrandName + " Options - Analytics Report";
|
|
||||||
|
|
||||||
textBoxReport.EnableMultilineShortcuts();
|
|
||||||
textBoxReport.Text = report.ToString().TrimEnd();
|
|
||||||
textBoxReport.Select(0, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void btnClose_Click(object sender, EventArgs e){
|
|
||||||
Close();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -3,140 +3,135 @@ using System.Linq;
|
|||||||
using System.Text.RegularExpressions;
|
using System.Text.RegularExpressions;
|
||||||
using System.Windows.Forms;
|
using System.Windows.Forms;
|
||||||
using TweetDuck.Controls;
|
using TweetDuck.Controls;
|
||||||
using TweetDuck.Utils;
|
|
||||||
|
|
||||||
namespace TweetDuck.Dialogs.Settings{
|
namespace TweetDuck.Dialogs.Settings {
|
||||||
sealed partial class DialogSettingsCSS : Form{
|
sealed partial class DialogSettingsCSS : Form {
|
||||||
public string BrowserCSS => textBoxBrowserCSS.Text;
|
public string BrowserCSS => textBoxBrowserCSS.Text;
|
||||||
public string NotificationCSS => textBoxNotificationCSS.Text;
|
public string NotificationCSS => textBoxNotificationCSS.Text;
|
||||||
|
|
||||||
private readonly Action<string> reinjectBrowserCSS;
|
private readonly Action<string> reinjectBrowserCSS;
|
||||||
private readonly Action openDevTools;
|
private readonly Action openDevTools;
|
||||||
|
|
||||||
public DialogSettingsCSS(string browserCSS, string notificationCSS, Action<string> reinjectBrowserCSS, Action openDevTools){
|
public DialogSettingsCSS(string browserCSS, string notificationCSS, Action<string> reinjectBrowserCSS, Action openDevTools) {
|
||||||
InitializeComponent();
|
InitializeComponent();
|
||||||
|
|
||||||
Text = Program.BrandName + " Options - CSS";
|
|
||||||
|
|
||||||
this.reinjectBrowserCSS = reinjectBrowserCSS;
|
Text = Program.BrandName + " Options - CSS";
|
||||||
this.openDevTools = openDevTools;
|
|
||||||
|
|
||||||
textBoxBrowserCSS.EnableMultilineShortcuts();
|
|
||||||
textBoxBrowserCSS.Text = browserCSS ?? "";
|
|
||||||
|
|
||||||
textBoxNotificationCSS.EnableMultilineShortcuts();
|
this.reinjectBrowserCSS = reinjectBrowserCSS;
|
||||||
textBoxNotificationCSS.Text = notificationCSS ?? "";
|
this.openDevTools = openDevTools;
|
||||||
|
|
||||||
if (!BrowserUtils.HasDevTools){
|
textBoxBrowserCSS.EnableMultilineShortcuts();
|
||||||
btnOpenDevTools.Enabled = false;
|
textBoxBrowserCSS.Text = browserCSS ?? "";
|
||||||
}
|
|
||||||
|
|
||||||
ActiveControl = textBoxBrowserCSS;
|
textBoxNotificationCSS.EnableMultilineShortcuts();
|
||||||
textBoxBrowserCSS.Select(textBoxBrowserCSS.TextLength, 0);
|
textBoxNotificationCSS.Text = notificationCSS ?? "";
|
||||||
}
|
|
||||||
|
|
||||||
private void tabPanel_SelectedIndexChanged(object sender, EventArgs e){
|
ActiveControl = textBoxBrowserCSS;
|
||||||
TextBox tb = tabPanel.SelectedTab.Controls.OfType<TextBox>().FirstOrDefault();
|
textBoxBrowserCSS.Select(textBoxBrowserCSS.TextLength, 0);
|
||||||
|
}
|
||||||
|
|
||||||
if (tb != null){
|
private void tabPanel_SelectedIndexChanged(object sender, EventArgs e) {
|
||||||
tb.Focus();
|
TextBox tb = tabPanel.SelectedTab.Controls.OfType<TextBox>().FirstOrDefault();
|
||||||
tb.Select(tb.TextLength, 0);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void textBoxCSS_KeyDown(object sender, KeyEventArgs e){
|
if (tb != null) {
|
||||||
TextBox tb = (TextBox)sender;
|
tb.Focus();
|
||||||
string text = tb.Text;
|
tb.Select(tb.TextLength, 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (e.KeyCode == Keys.Back && e.Modifiers == Keys.Control){
|
private void textBoxCSS_KeyDown(object sender, KeyEventArgs e) {
|
||||||
e.SuppressKeyPress = true;
|
TextBox tb = (TextBox) sender;
|
||||||
|
string text = tb.Text;
|
||||||
|
|
||||||
int deleteTo = tb.SelectionStart;
|
if (e.KeyCode == Keys.Back && e.Modifiers == Keys.Control) {
|
||||||
|
e.SuppressKeyPress = true;
|
||||||
|
|
||||||
if (deleteTo > 0){
|
int deleteTo = tb.SelectionStart;
|
||||||
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);
|
if (deleteTo > 0) {
|
||||||
tb.SelectedText = string.Empty;
|
char initialChar = text[--deleteTo];
|
||||||
}
|
bool shouldDeleteAlphanumeric = char.IsLetterOrDigit(initialChar);
|
||||||
}
|
|
||||||
else if (e.KeyCode == Keys.Back && e.Modifiers == Keys.None){
|
|
||||||
int deleteTo = tb.SelectionStart;
|
|
||||||
|
|
||||||
if (deleteTo > 1 && text[deleteTo - 1] == ' ' && text[deleteTo - 2] == ' '){
|
while (--deleteTo >= 0) {
|
||||||
e.SuppressKeyPress = true;
|
if ((shouldDeleteAlphanumeric && !char.IsLetterOrDigit(text[deleteTo])) ||
|
||||||
|
(!shouldDeleteAlphanumeric && text[deleteTo] != initialChar)) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
tb.Select(deleteTo - 2, 2);
|
if (!(deleteTo < text.Length - 1 && text[deleteTo] == '\r' && text[deleteTo + 1] == '\n')) {
|
||||||
tb.SelectedText = string.Empty;
|
++deleteTo;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
else if (e.KeyCode == Keys.Enter && e.Modifiers == Keys.None && tb.SelectionLength == 0){
|
|
||||||
int insertAt = tb.SelectionStart, cursorOffset = 0;
|
|
||||||
string insertText;
|
|
||||||
|
|
||||||
if (insertAt == 0){
|
tb.Select(deleteTo, tb.SelectionLength + tb.SelectionStart - deleteTo);
|
||||||
return;
|
tb.SelectedText = string.Empty;
|
||||||
}
|
}
|
||||||
else if (text[insertAt - 1] == '{'){
|
}
|
||||||
insertText = Environment.NewLine + " ";
|
else if (e.KeyCode == Keys.Back && e.Modifiers == Keys.None) {
|
||||||
|
int deleteTo = tb.SelectionStart;
|
||||||
|
|
||||||
int nextBracket = insertAt < text.Length ? text.IndexOfAny(new char[]{ '{', '}' }, insertAt + 1) : -1;
|
if (deleteTo > 1 && text[deleteTo - 1] == ' ' && text[deleteTo - 2] == ' ') {
|
||||||
|
e.SuppressKeyPress = true;
|
||||||
|
|
||||||
if (nextBracket == -1 || text[nextBracket] == '{'){
|
tb.Select(deleteTo - 2, 2);
|
||||||
string insertExtra = Environment.NewLine + "}";
|
tb.SelectedText = string.Empty;
|
||||||
insertText += insertExtra;
|
}
|
||||||
cursorOffset -= insertExtra.Length;
|
}
|
||||||
}
|
else if (e.KeyCode == Keys.Enter && e.Modifiers == Keys.None && tb.SelectionLength == 0) {
|
||||||
}
|
int insertAt = tb.SelectionStart, cursorOffset = 0;
|
||||||
else{
|
string insertText;
|
||||||
int lineStart = text.LastIndexOf('\n', tb.SelectionStart - 1);
|
|
||||||
|
|
||||||
Match match = Regex.Match(text.Substring(lineStart == -1 ? 0 : lineStart + 1), "^([ \t]+)");
|
if (insertAt == 0) {
|
||||||
insertText = match.Success ? Environment.NewLine + match.Groups[1].Value : null;
|
return;
|
||||||
}
|
}
|
||||||
|
else if (text[insertAt - 1] == '{') {
|
||||||
|
insertText = Environment.NewLine + " ";
|
||||||
|
|
||||||
if (!string.IsNullOrEmpty(insertText)){
|
int nextBracket = insertAt < text.Length ? text.IndexOfAny(new char[] { '{', '}' }, insertAt + 1) : -1;
|
||||||
e.SuppressKeyPress = true;
|
|
||||||
tb.Text = text.Insert(insertAt, insertText);
|
|
||||||
tb.SelectionStart = insertAt + cursorOffset + insertText.Length;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void textBoxBrowserCSS_KeyUp(object sender, KeyEventArgs e){
|
if (nextBracket == -1 || text[nextBracket] == '{') {
|
||||||
timerTestBrowser.Stop();
|
string insertExtra = Environment.NewLine + "}";
|
||||||
timerTestBrowser.Start();
|
insertText += insertExtra;
|
||||||
}
|
cursorOffset -= insertExtra.Length;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
int lineStart = text.LastIndexOf('\n', tb.SelectionStart - 1);
|
||||||
|
|
||||||
private void timerTestBrowser_Tick(object sender, EventArgs e){
|
Match match = Regex.Match(text.Substring(lineStart == -1 ? 0 : lineStart + 1), "^([ \t]+)");
|
||||||
reinjectBrowserCSS(textBoxBrowserCSS.Text);
|
insertText = match.Success ? Environment.NewLine + match.Groups[1].Value : null;
|
||||||
timerTestBrowser.Stop();
|
}
|
||||||
}
|
|
||||||
|
|
||||||
private void btnOpenDevTools_Click(object sender, EventArgs e){
|
if (!string.IsNullOrEmpty(insertText)) {
|
||||||
openDevTools();
|
e.SuppressKeyPress = true;
|
||||||
}
|
tb.Text = text.Insert(insertAt, insertText);
|
||||||
|
tb.SelectionStart = insertAt + cursorOffset + insertText.Length;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private void btnApply_Click(object sender, EventArgs e){
|
private void textBoxBrowserCSS_KeyUp(object sender, KeyEventArgs e) {
|
||||||
DialogResult = DialogResult.OK;
|
timerTestBrowser.Stop();
|
||||||
Close();
|
timerTestBrowser.Start();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void btnCancel_Click(object sender, EventArgs e){
|
private void timerTestBrowser_Tick(object sender, EventArgs e) {
|
||||||
DialogResult = DialogResult.Cancel;
|
reinjectBrowserCSS(textBoxBrowserCSS.Text);
|
||||||
Close();
|
timerTestBrowser.Stop();
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
private void btnOpenDevTools_Click(object sender, EventArgs e) {
|
||||||
|
openDevTools();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void btnApply_Click(object sender, EventArgs e) {
|
||||||
|
DialogResult = DialogResult.OK;
|
||||||
|
Close();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void btnCancel_Click(object sender, EventArgs e) {
|
||||||
|
DialogResult = DialogResult.Cancel;
|
||||||
|
Close();
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,48 +1,48 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Windows.Forms;
|
using System.Windows.Forms;
|
||||||
using TweetDuck.Controls;
|
using TweetDuck.Controls;
|
||||||
using TweetDuck.Utils;
|
using TweetLib.Core;
|
||||||
using TweetLib.Core.Collections;
|
using TweetLib.Core.Features.Chromium;
|
||||||
|
|
||||||
namespace TweetDuck.Dialogs.Settings{
|
namespace TweetDuck.Dialogs.Settings {
|
||||||
sealed partial class DialogSettingsCefArgs : Form{
|
sealed partial class DialogSettingsCefArgs : Form {
|
||||||
public string CefArgs => textBoxArgs.Text;
|
public string CefArgs => textBoxArgs.Text;
|
||||||
|
|
||||||
private readonly string initialArgs;
|
private readonly string initialArgs;
|
||||||
|
|
||||||
public DialogSettingsCefArgs(string args){
|
public DialogSettingsCefArgs(string args) {
|
||||||
InitializeComponent();
|
InitializeComponent();
|
||||||
|
|
||||||
Text = Program.BrandName + " Options - CEF Arguments";
|
|
||||||
|
|
||||||
textBoxArgs.EnableMultilineShortcuts();
|
|
||||||
textBoxArgs.Text = initialArgs = args ?? "";
|
|
||||||
textBoxArgs.Select(textBoxArgs.Text.Length, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void btnHelp_Click(object sender, EventArgs e){
|
Text = Program.BrandName + " Options - CEF Arguments";
|
||||||
BrowserUtils.OpenExternalBrowser("http://peter.sh/experiments/chromium-command-line-switches/");
|
|
||||||
}
|
|
||||||
|
|
||||||
private void btnApply_Click(object sender, EventArgs e){
|
textBoxArgs.EnableMultilineShortcuts();
|
||||||
if (CefArgs == initialArgs){
|
textBoxArgs.Text = initialArgs = args ?? "";
|
||||||
DialogResult = DialogResult.Cancel;
|
textBoxArgs.Select(textBoxArgs.Text.Length, 0);
|
||||||
Close();
|
}
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
int count = CommandLineArgs.ReadCefArguments(CefArgs).Count;
|
private void btnHelp_Click(object sender, EventArgs e) {
|
||||||
string prompt = count == 0 && !string.IsNullOrWhiteSpace(initialArgs) ? "All current arguments will be removed. Continue?" : count + (count == 1 ? " argument was" : " arguments were") + " detected. Continue?";
|
App.SystemHandler.OpenBrowser("http://peter.sh/experiments/chromium-command-line-switches/");
|
||||||
|
}
|
||||||
|
|
||||||
if (FormMessage.Question("Confirm CEF Arguments", prompt, FormMessage.OK, FormMessage.Cancel)){
|
private void btnApply_Click(object sender, EventArgs e) {
|
||||||
DialogResult = DialogResult.OK;
|
if (CefArgs == initialArgs) {
|
||||||
Close();
|
DialogResult = DialogResult.Cancel;
|
||||||
}
|
Close();
|
||||||
}
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
private void btnCancel_Click(object sender, EventArgs e){
|
int count = CefUtils.ParseCommandLineArguments(CefArgs).Count;
|
||||||
DialogResult = DialogResult.Cancel;
|
string prompt = count == 0 && !string.IsNullOrWhiteSpace(initialArgs) ? "All current arguments will be removed. Continue?" : count + (count == 1 ? " argument was" : " arguments were") + " detected. Continue?";
|
||||||
Close();
|
|
||||||
}
|
if (FormMessage.Question("Confirm CEF Arguments", prompt, FormMessage.OK, FormMessage.Cancel)) {
|
||||||
}
|
DialogResult = DialogResult.OK;
|
||||||
|
Close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void btnCancel_Click(object sender, EventArgs e) {
|
||||||
|
DialogResult = DialogResult.Cancel;
|
||||||
|
Close();
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,55 +1,55 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Windows.Forms;
|
using System.Windows.Forms;
|
||||||
using TweetLib.Core.Utils;
|
using TweetLib.Utils.Static;
|
||||||
using IOPath = System.IO.Path;
|
using IOPath = System.IO.Path;
|
||||||
|
|
||||||
namespace TweetDuck.Dialogs.Settings{
|
namespace TweetDuck.Dialogs.Settings {
|
||||||
sealed partial class DialogSettingsExternalProgram : Form{
|
sealed partial class DialogSettingsExternalProgram : Form {
|
||||||
public string Path{
|
public string Path {
|
||||||
get => StringUtils.NullIfEmpty(textBoxPath.Text);
|
get => StringUtils.NullIfEmpty(textBoxPath.Text);
|
||||||
set => textBoxPath.Text = value ?? string.Empty;
|
set => textBoxPath.Text = value ?? string.Empty;
|
||||||
}
|
}
|
||||||
|
|
||||||
public string Args{
|
public string Args {
|
||||||
get => StringUtils.NullIfEmpty(textBoxArgs.Text);
|
get => StringUtils.NullIfEmpty(textBoxArgs.Text);
|
||||||
set => textBoxArgs.Text = value ?? string.Empty;
|
set => textBoxArgs.Text = value ?? string.Empty;
|
||||||
}
|
}
|
||||||
|
|
||||||
private readonly string fileDialogTitle;
|
private readonly string fileDialogTitle;
|
||||||
|
|
||||||
public DialogSettingsExternalProgram(string windowTitle, string fileDialogTitle){
|
public DialogSettingsExternalProgram(string windowTitle, string fileDialogTitle) {
|
||||||
InitializeComponent();
|
InitializeComponent();
|
||||||
|
|
||||||
Text = Program.BrandName + " Options - " + windowTitle;
|
|
||||||
AcceptButton = btnApply;
|
|
||||||
CancelButton = btnCancel;
|
|
||||||
|
|
||||||
this.fileDialogTitle = fileDialogTitle;
|
Text = Program.BrandName + " Options - " + windowTitle;
|
||||||
}
|
AcceptButton = btnApply;
|
||||||
|
CancelButton = btnCancel;
|
||||||
|
|
||||||
private void btnBrowse_Click(object sender, EventArgs e){
|
this.fileDialogTitle = fileDialogTitle;
|
||||||
using OpenFileDialog dialog = new OpenFileDialog{
|
}
|
||||||
AutoUpgradeEnabled = true,
|
|
||||||
DereferenceLinks = true,
|
|
||||||
InitialDirectory = IOPath.GetDirectoryName(Path), // returns null if argument is null
|
|
||||||
Title = fileDialogTitle,
|
|
||||||
Filter = "Executables (*.exe;*.bat;*.cmd)|*.exe;*.bat;*.cmd|All Files (*.*)|*.*"
|
|
||||||
};
|
|
||||||
|
|
||||||
if (dialog.ShowDialog() == DialogResult.OK && Path != dialog.FileName){
|
private void btnBrowse_Click(object sender, EventArgs e) {
|
||||||
Path = dialog.FileName;
|
using OpenFileDialog dialog = new OpenFileDialog {
|
||||||
Args = string.Empty;
|
AutoUpgradeEnabled = true,
|
||||||
}
|
DereferenceLinks = true,
|
||||||
}
|
InitialDirectory = IOPath.GetDirectoryName(Path), // returns null if argument is null
|
||||||
|
Title = fileDialogTitle,
|
||||||
private void btnApply_Click(object sender, EventArgs e){
|
Filter = "Executables (*.exe;*.bat;*.cmd)|*.exe;*.bat;*.cmd|All Files (*.*)|*.*"
|
||||||
DialogResult = DialogResult.OK;
|
};
|
||||||
Close();
|
|
||||||
}
|
|
||||||
|
|
||||||
private void btnCancel_Click(object sender, EventArgs e){
|
if (dialog.ShowDialog() == DialogResult.OK && Path != dialog.FileName) {
|
||||||
DialogResult = DialogResult.Cancel;
|
Path = dialog.FileName;
|
||||||
Close();
|
Args = string.Empty;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void btnApply_Click(object sender, EventArgs e) {
|
||||||
|
DialogResult = DialogResult.OK;
|
||||||
|
Close();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void btnCancel_Click(object sender, EventArgs e) {
|
||||||
|
DialogResult = DialogResult.Cancel;
|
||||||
|
Close();
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -121,7 +121,7 @@
|
|||||||
this.cbSystemConfig.Size = new System.Drawing.Size(109, 19);
|
this.cbSystemConfig.Size = new System.Drawing.Size(109, 19);
|
||||||
this.cbSystemConfig.TabIndex = 1;
|
this.cbSystemConfig.TabIndex = 1;
|
||||||
this.cbSystemConfig.Text = "System Options";
|
this.cbSystemConfig.Text = "System Options";
|
||||||
this.toolTip.SetToolTip(this.cbSystemConfig, "Hardware acceleration and cache options.");
|
this.toolTip.SetToolTip(this.cbSystemConfig, "Options related to the current system and hardware,\r\nsuch as hardware acceleration, proxy, and cache settings.");
|
||||||
this.cbSystemConfig.UseVisualStyleBackColor = true;
|
this.cbSystemConfig.UseVisualStyleBackColor = true;
|
||||||
this.cbSystemConfig.CheckedChanged += new System.EventHandler(this.checkBoxSelection_CheckedChanged);
|
this.cbSystemConfig.CheckedChanged += new System.EventHandler(this.checkBoxSelection_CheckedChanged);
|
||||||
//
|
//
|
||||||
|
|||||||
@@ -2,243 +2,237 @@
|
|||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Windows.Forms;
|
using System.Windows.Forms;
|
||||||
using TweetDuck.Configuration;
|
|
||||||
using TweetDuck.Management;
|
using TweetDuck.Management;
|
||||||
|
using TweetLib.Core;
|
||||||
using TweetLib.Core.Features.Plugins;
|
using TweetLib.Core.Features.Plugins;
|
||||||
using TweetLib.Core.Utils;
|
using TweetLib.Core.Systems.Configuration;
|
||||||
|
|
||||||
namespace TweetDuck.Dialogs.Settings{
|
namespace TweetDuck.Dialogs.Settings {
|
||||||
sealed partial class DialogSettingsManage : Form{
|
sealed partial class DialogSettingsManage : Form {
|
||||||
private enum State{
|
private enum State {
|
||||||
Deciding, Reset, Import, Export
|
Deciding,
|
||||||
}
|
Reset,
|
||||||
|
Import,
|
||||||
|
Export
|
||||||
|
}
|
||||||
|
|
||||||
private ProfileManager.Items SelectedItems{
|
private ProfileManager.Items SelectedItems {
|
||||||
get => _selectedItems;
|
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
|
||||||
foreach(KeyValuePair<CheckBox, ProfileManager.Items> kvp in checkBoxMap){
|
foreach (KeyValuePair<CheckBox, ProfileManager.Items> kvp in checkBoxMap) {
|
||||||
kvp.Key.Checked = value.HasFlag(kvp.Value);
|
kvp.Key.Checked = value.HasFlag(kvp.Value);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private bool SelectedItemsForceRestart{
|
public bool IsRestarting { get; private set; }
|
||||||
get => _selectedItems.HasFlag(ProfileManager.Items.Session);
|
public bool ShouldReloadBrowser { get; private set; }
|
||||||
}
|
|
||||||
|
|
||||||
public bool IsRestarting { get; private set; }
|
|
||||||
public bool ShouldReloadBrowser { get; private set; }
|
|
||||||
|
|
||||||
private readonly PluginManager plugins;
|
|
||||||
private readonly Dictionary<CheckBox, ProfileManager.Items> checkBoxMap = new Dictionary<CheckBox, ProfileManager.Items>(4);
|
|
||||||
private readonly bool openImportImmediately;
|
|
||||||
|
|
||||||
private State currentState;
|
private readonly PluginManager plugins;
|
||||||
private ProfileManager importManager;
|
private readonly Dictionary<CheckBox, ProfileManager.Items> checkBoxMap = new Dictionary<CheckBox, ProfileManager.Items>(4);
|
||||||
private bool requestedRestartFromConfig;
|
private readonly bool openImportImmediately;
|
||||||
|
|
||||||
private ProfileManager.Items _selectedItems = ProfileManager.Items.None;
|
private State currentState;
|
||||||
|
private ProfileManager importManager;
|
||||||
|
private bool requestedRestartFromConfig;
|
||||||
|
|
||||||
public DialogSettingsManage(PluginManager plugins, bool openImportImmediately = false){
|
private ProfileManager.Items _selectedItems = ProfileManager.Items.None;
|
||||||
InitializeComponent();
|
|
||||||
|
|
||||||
this.plugins = plugins;
|
public DialogSettingsManage(PluginManager plugins, bool openImportImmediately = false) {
|
||||||
this.currentState = State.Deciding;
|
InitializeComponent();
|
||||||
|
|
||||||
this.checkBoxMap[cbProgramConfig] = ProfileManager.Items.UserConfig;
|
this.plugins = plugins;
|
||||||
this.checkBoxMap[cbSystemConfig] = ProfileManager.Items.SystemConfig;
|
this.currentState = State.Deciding;
|
||||||
this.checkBoxMap[cbSession] = ProfileManager.Items.Session;
|
|
||||||
this.checkBoxMap[cbPluginData] = ProfileManager.Items.PluginData;
|
|
||||||
|
|
||||||
this.openImportImmediately = openImportImmediately;
|
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){
|
this.openImportImmediately = openImportImmediately;
|
||||||
radioImport.Checked = true;
|
|
||||||
btnContinue_Click(null, EventArgs.Empty);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void radioDecision_CheckedChanged(object sender, EventArgs e){
|
if (openImportImmediately) {
|
||||||
btnContinue.Enabled = true;
|
radioImport.Checked = true;
|
||||||
}
|
btnContinue_Click(null, EventArgs.Empty);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private void checkBoxSelection_CheckedChanged(object sender, EventArgs e){
|
private void radioDecision_CheckedChanged(object sender, EventArgs e) {
|
||||||
CheckBox cb = (CheckBox)sender;
|
btnContinue.Enabled = true;
|
||||||
SetFlag(checkBoxMap[cb], cb.Checked);
|
}
|
||||||
}
|
|
||||||
|
|
||||||
private void btnContinue_Click(object sender, EventArgs e){
|
private void checkBoxSelection_CheckedChanged(object sender, EventArgs e) {
|
||||||
string file;
|
CheckBox cb = (CheckBox) sender;
|
||||||
|
SetFlag(checkBoxMap[cb], cb.Checked);
|
||||||
|
}
|
||||||
|
|
||||||
switch(currentState){
|
private void btnContinue_Click(object sender, EventArgs e) {
|
||||||
case State.Deciding:
|
string file;
|
||||||
// Reset
|
|
||||||
if (radioReset.Checked){
|
|
||||||
currentState = State.Reset;
|
|
||||||
|
|
||||||
Text = "Restore Defaults";
|
switch (currentState) {
|
||||||
SelectedItems = ProfileManager.Items.UserConfig;
|
case State.Deciding:
|
||||||
}
|
// Reset
|
||||||
|
if (radioReset.Checked) {
|
||||||
|
currentState = State.Reset;
|
||||||
|
|
||||||
// Import
|
Text = "Restore Defaults";
|
||||||
else if (radioImport.Checked){
|
SelectedItems = ProfileManager.Items.UserConfig;
|
||||||
using(OpenFileDialog dialog = new OpenFileDialog{
|
}
|
||||||
AutoUpgradeEnabled = true,
|
|
||||||
DereferenceLinks = true,
|
|
||||||
Title = "Import TweetDuck Profile",
|
|
||||||
Filter = "TweetDuck Profile (*.tdsettings)|*.tdsettings"
|
|
||||||
}){
|
|
||||||
if (dialog.ShowDialog() != DialogResult.OK){
|
|
||||||
if (openImportImmediately){
|
|
||||||
Close();
|
|
||||||
}
|
|
||||||
|
|
||||||
return;
|
// Import
|
||||||
}
|
else if (radioImport.Checked) {
|
||||||
|
using (OpenFileDialog dialog = new OpenFileDialog {
|
||||||
|
AutoUpgradeEnabled = true,
|
||||||
|
DereferenceLinks = true,
|
||||||
|
Title = "Import TweetDuck Profile",
|
||||||
|
Filter = "TweetDuck Profile (*.tdsettings)|*.tdsettings"
|
||||||
|
}) {
|
||||||
|
if (dialog.ShowDialog() != DialogResult.OK) {
|
||||||
|
if (openImportImmediately) {
|
||||||
|
Close();
|
||||||
|
}
|
||||||
|
|
||||||
file = dialog.FileName;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
importManager = new ProfileManager(file, plugins);
|
file = dialog.FileName;
|
||||||
currentState = State.Import;
|
}
|
||||||
|
|
||||||
Text = "Import Profile";
|
importManager = new ProfileManager(file, plugins);
|
||||||
SelectedItems = importManager.FindImportItems();
|
currentState = State.Import;
|
||||||
|
|
||||||
foreach(CheckBox cb in checkBoxMap.Keys){
|
Text = "Import Profile";
|
||||||
cb.Enabled = cb.Checked;
|
SelectedItems = importManager.FindImportItems();
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Export
|
foreach (CheckBox cb in checkBoxMap.Keys) {
|
||||||
else if (radioExport.Checked){
|
cb.Enabled = cb.Checked;
|
||||||
currentState = State.Export;
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Text = "Export Profile";
|
// Export
|
||||||
btnContinue.Text = "Export Profile";
|
else if (radioExport.Checked) {
|
||||||
SelectedItems = ProfileManager.Items.UserConfig | ProfileManager.Items.PluginData;
|
currentState = State.Export;
|
||||||
}
|
|
||||||
|
|
||||||
// Continue...
|
|
||||||
panelDecision.Visible = false;
|
|
||||||
panelSelection.Visible = true;
|
|
||||||
Height += panelSelection.Height - panelDecision.Height;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case State.Reset:
|
Text = "Export Profile";
|
||||||
if (FormMessage.Warning("Reset TweetDuck Options", "This will reset the selected items. Are you sure you want to proceed?", FormMessage.Yes, FormMessage.No)){
|
btnContinue.Text = "Export Profile";
|
||||||
Program.Config.ProgramRestartRequested += Config_ProgramRestartRequested;
|
SelectedItems = ProfileManager.Items.UserConfig | ProfileManager.Items.PluginData;
|
||||||
|
}
|
||||||
|
|
||||||
if (SelectedItems.HasFlag(ProfileManager.Items.UserConfig)){
|
// Continue...
|
||||||
Program.Config.User.Reset();
|
panelDecision.Visible = false;
|
||||||
}
|
panelSelection.Visible = true;
|
||||||
|
Height += panelSelection.Height - panelDecision.Height;
|
||||||
|
break;
|
||||||
|
|
||||||
if (SelectedItems.HasFlag(ProfileManager.Items.SystemConfig)){
|
case State.Reset:
|
||||||
Program.Config.System.Reset();
|
if (FormMessage.Warning("Reset TweetDuck Options", "This will reset the selected items. Are you sure you want to proceed?", FormMessage.Yes, FormMessage.No)) {
|
||||||
}
|
App.ConfigManager.ProgramRestartRequested += Config_ProgramRestartRequested;
|
||||||
|
|
||||||
Program.Config.ProgramRestartRequested -= Config_ProgramRestartRequested;
|
if (SelectedItems.HasFlag(ProfileManager.Items.UserConfig)) {
|
||||||
|
Program.Config.User.Reset();
|
||||||
|
}
|
||||||
|
|
||||||
if (SelectedItems.HasFlag(ProfileManager.Items.PluginData)){
|
if (SelectedItems.HasFlag(ProfileManager.Items.SystemConfig)) {
|
||||||
Program.Config.Plugins.Reset();
|
Program.Config.System.Reset();
|
||||||
|
}
|
||||||
|
|
||||||
try{
|
App.ConfigManager.ProgramRestartRequested -= Config_ProgramRestartRequested;
|
||||||
Directory.Delete(Program.PluginDataPath, true);
|
|
||||||
}catch(Exception ex){
|
|
||||||
Program.Reporter.HandleException("Profile Reset", "Could not delete plugin data.", true, ex);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (SelectedItemsForceRestart){
|
if (SelectedItems.HasFlag(ProfileManager.Items.Session)) {
|
||||||
RestartProgram(SelectedItems.HasFlag(ProfileManager.Items.Session) ? new string[]{ Arguments.ArgDeleteCookies } : StringUtils.EmptyArray);
|
ProfileManager.DeleteAuthCookie();
|
||||||
}
|
}
|
||||||
else if (requestedRestartFromConfig){
|
|
||||||
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();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
ShouldReloadBrowser = true;
|
if (SelectedItems.HasFlag(ProfileManager.Items.PluginData)) {
|
||||||
|
Program.Config.Plugins.Reset();
|
||||||
|
|
||||||
DialogResult = DialogResult.OK;
|
try {
|
||||||
Close();
|
Directory.Delete(plugins.PluginDataFolder, true);
|
||||||
}
|
} catch (Exception ex) {
|
||||||
|
App.ErrorHandler.HandleException("Profile Reset", "Could not delete plugin data.", true, ex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
break;
|
if (requestedRestartFromConfig && 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();
|
||||||
|
}
|
||||||
|
|
||||||
case State.Import:
|
ShouldReloadBrowser = true;
|
||||||
if (importManager.Import(SelectedItems)){
|
|
||||||
Program.Config.ProgramRestartRequested += Config_ProgramRestartRequested;
|
|
||||||
Program.Config.ReloadAll();
|
|
||||||
Program.Config.ProgramRestartRequested -= Config_ProgramRestartRequested;
|
|
||||||
|
|
||||||
if (SelectedItemsForceRestart){
|
|
||||||
RestartProgram(SelectedItems.HasFlag(ProfileManager.Items.Session) ? new string[]{ Arguments.ArgImportCookies } : StringUtils.EmptyArray);
|
|
||||||
}
|
|
||||||
else if (requestedRestartFromConfig){
|
|
||||||
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();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
ShouldReloadBrowser = true;
|
|
||||||
|
|
||||||
DialogResult = DialogResult.OK;
|
DialogResult = DialogResult.OK;
|
||||||
Close();
|
Close();
|
||||||
break;
|
}
|
||||||
|
|
||||||
case State.Export:
|
break;
|
||||||
using(SaveFileDialog dialog = new SaveFileDialog{
|
|
||||||
AddExtension = true,
|
|
||||||
AutoUpgradeEnabled = true,
|
|
||||||
OverwritePrompt = true,
|
|
||||||
DefaultExt = "tdsettings",
|
|
||||||
FileName = "TweetDuck.tdsettings",
|
|
||||||
Title = "Export TweetDuck Profile",
|
|
||||||
Filter = "TweetDuck Profile (*.tdsettings)|*.tdsettings"
|
|
||||||
}){
|
|
||||||
if (dialog.ShowDialog() != DialogResult.OK){
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
file = dialog.FileName;
|
case State.Import:
|
||||||
}
|
if (importManager.Import(SelectedItems)) {
|
||||||
|
App.ConfigManager.ProgramRestartRequested += Config_ProgramRestartRequested;
|
||||||
new ProfileManager(file, plugins).Export(SelectedItems);
|
App.ConfigManager.ReloadAll();
|
||||||
|
App.ConfigManager.SaveAll();
|
||||||
|
App.ConfigManager.ProgramRestartRequested -= Config_ProgramRestartRequested;
|
||||||
|
|
||||||
DialogResult = DialogResult.OK;
|
if (requestedRestartFromConfig && 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)) {
|
||||||
Close();
|
RestartProgram();
|
||||||
break;
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
private void btnCancel_Click(object sender, EventArgs e){
|
ShouldReloadBrowser = true;
|
||||||
DialogResult = DialogResult.Cancel;
|
|
||||||
Close();
|
|
||||||
}
|
|
||||||
|
|
||||||
private void Config_ProgramRestartRequested(object sender, EventArgs e){
|
DialogResult = DialogResult.OK;
|
||||||
requestedRestartFromConfig = true;
|
Close();
|
||||||
}
|
break;
|
||||||
|
|
||||||
private void SetFlag(ProfileManager.Items flag, bool enable){
|
case State.Export:
|
||||||
_selectedItems = enable ? _selectedItems | flag : _selectedItems & ~flag;
|
using (SaveFileDialog dialog = new SaveFileDialog {
|
||||||
btnContinue.Enabled = _selectedItems != ProfileManager.Items.None;
|
AddExtension = true,
|
||||||
|
AutoUpgradeEnabled = true,
|
||||||
if (currentState == State.Import){
|
OverwritePrompt = true,
|
||||||
btnContinue.Text = SelectedItemsForceRestart ? "Import && Restart" : "Import Profile";
|
DefaultExt = "tdsettings",
|
||||||
}
|
FileName = "TweetDuck.tdsettings",
|
||||||
else if (currentState == State.Reset){
|
Title = "Export TweetDuck Profile",
|
||||||
btnContinue.Text = SelectedItemsForceRestart ? "Restore && Restart" : "Restore Defaults";
|
Filter = "TweetDuck Profile (*.tdsettings)|*.tdsettings"
|
||||||
}
|
}) {
|
||||||
}
|
if (dialog.ShowDialog() != DialogResult.OK) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
private void RestartProgram(params string[] extraArgs){
|
file = dialog.FileName;
|
||||||
IsRestarting = true;
|
}
|
||||||
Program.Restart(extraArgs);
|
|
||||||
}
|
new ProfileManager(file, plugins).Export(SelectedItems);
|
||||||
}
|
|
||||||
|
DialogResult = DialogResult.OK;
|
||||||
|
Close();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void btnCancel_Click(object sender, EventArgs e) {
|
||||||
|
DialogResult = DialogResult.Cancel;
|
||||||
|
Close();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void Config_ProgramRestartRequested(object sender, EventArgs e) {
|
||||||
|
requestedRestartFromConfig = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void SetFlag(ProfileManager.Items flag, bool enable) {
|
||||||
|
_selectedItems = enable ? _selectedItems | flag : _selectedItems & ~flag;
|
||||||
|
btnContinue.Enabled = _selectedItems != ProfileManager.Items.None;
|
||||||
|
|
||||||
|
if (currentState == State.Import) {
|
||||||
|
btnContinue.Text = "Import Profile";
|
||||||
|
}
|
||||||
|
else if (currentState == State.Reset) {
|
||||||
|
btnContinue.Text = "Restore Defaults";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void RestartProgram() {
|
||||||
|
IsRestarting = true;
|
||||||
|
Program.Restart();
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,61 +1,62 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Windows.Forms;
|
using System.Windows.Forms;
|
||||||
using TweetDuck.Configuration;
|
using TweetDuck.Configuration;
|
||||||
using TweetLib.Core.Collections;
|
using TweetLib.Core;
|
||||||
|
using TweetLib.Utils.Collections;
|
||||||
|
|
||||||
namespace TweetDuck.Dialogs.Settings{
|
namespace TweetDuck.Dialogs.Settings {
|
||||||
sealed partial class DialogSettingsRestart : Form{
|
sealed partial class DialogSettingsRestart : Form {
|
||||||
public CommandLineArgs Args { get; private set; }
|
public CommandLineArgs Args { get; private set; }
|
||||||
|
|
||||||
public DialogSettingsRestart(CommandLineArgs currentArgs){
|
public DialogSettingsRestart(CommandLineArgs currentArgs) {
|
||||||
InitializeComponent();
|
InitializeComponent();
|
||||||
|
|
||||||
cbLogging.Checked = currentArgs.HasFlag(Arguments.ArgLogging);
|
cbLogging.Checked = currentArgs.HasFlag(Arguments.ArgLogging);
|
||||||
cbLogging.CheckedChanged += control_Change;
|
cbLogging.CheckedChanged += control_Change;
|
||||||
|
|
||||||
if (Program.IsPortable){
|
|
||||||
tbDataFolder.Text = "Not available in portable version";
|
|
||||||
tbDataFolder.Enabled = false;
|
|
||||||
}
|
|
||||||
else{
|
|
||||||
tbDataFolder.Text = currentArgs.GetValue(Arguments.ArgDataFolder) ?? string.Empty;
|
|
||||||
tbDataFolder.TextChanged += control_Change;
|
|
||||||
}
|
|
||||||
|
|
||||||
control_Change(this, EventArgs.Empty);
|
if (App.IsPortable) {
|
||||||
|
tbDataFolder.Text = "Not available in portable version";
|
||||||
|
tbDataFolder.Enabled = false;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
tbDataFolder.Text = currentArgs.GetValue(Arguments.ArgDataFolder) ?? string.Empty;
|
||||||
|
tbDataFolder.TextChanged += control_Change;
|
||||||
|
}
|
||||||
|
|
||||||
Text = Program.BrandName + " Arguments";
|
control_Change(this, EventArgs.Empty);
|
||||||
}
|
|
||||||
|
|
||||||
private void control_Change(object sender, EventArgs e){
|
Text = Program.BrandName + " Arguments";
|
||||||
Args = new CommandLineArgs();
|
}
|
||||||
|
|
||||||
if (cbLogging.Checked){
|
|
||||||
Args.AddFlag(Arguments.ArgLogging);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!string.IsNullOrWhiteSpace(tbDataFolder.Text) && tbDataFolder.Enabled){
|
|
||||||
Args.SetValue(Arguments.ArgDataFolder, tbDataFolder.Text);
|
|
||||||
}
|
|
||||||
|
|
||||||
tbShortcutTarget.Text = $@"""{Program.ExecutablePath}""{(Args.Count > 0 ? " " : "")}{Args}";
|
private void control_Change(object sender, EventArgs e) {
|
||||||
tbShortcutTarget.Select(tbShortcutTarget.Text.Length, 0);
|
Args = new CommandLineArgs();
|
||||||
}
|
|
||||||
|
|
||||||
private void tbShortcutTarget_Click(object sender, EventArgs e){
|
if (cbLogging.Checked) {
|
||||||
if (tbShortcutTarget.SelectionLength == 0){
|
Args.AddFlag(Arguments.ArgLogging);
|
||||||
tbShortcutTarget.SelectAll();
|
}
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void btnRestart_Click(object sender, EventArgs e){
|
if (!string.IsNullOrWhiteSpace(tbDataFolder.Text) && tbDataFolder.Enabled) {
|
||||||
DialogResult = DialogResult.OK;
|
Args.SetValue(Arguments.ArgDataFolder, tbDataFolder.Text);
|
||||||
Close();
|
}
|
||||||
}
|
|
||||||
|
|
||||||
private void btnCancel_Click(object sender, EventArgs e){
|
tbShortcutTarget.Text = $@"""{Program.ExecutablePath}""{(Args.Count > 0 ? " " : "")}{Args}";
|
||||||
DialogResult = DialogResult.Cancel;
|
tbShortcutTarget.Select(tbShortcutTarget.Text.Length, 0);
|
||||||
Close();
|
}
|
||||||
}
|
|
||||||
}
|
private void tbShortcutTarget_Click(object sender, EventArgs e) {
|
||||||
|
if (tbShortcutTarget.SelectionLength == 0) {
|
||||||
|
tbShortcutTarget.SelectAll();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void btnRestart_Click(object sender, EventArgs e) {
|
||||||
|
DialogResult = DialogResult.OK;
|
||||||
|
Close();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void btnCancel_Click(object sender, EventArgs e) {
|
||||||
|
DialogResult = DialogResult.Cancel;
|
||||||
|
Close();
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,27 +1,27 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Windows.Forms;
|
using System.Windows.Forms;
|
||||||
|
|
||||||
namespace TweetDuck.Dialogs.Settings{
|
namespace TweetDuck.Dialogs.Settings {
|
||||||
sealed partial class DialogSettingsSearchEngine : Form{
|
sealed partial class DialogSettingsSearchEngine : Form {
|
||||||
public string Url => textBoxUrl.Text;
|
public string Url => textBoxUrl.Text;
|
||||||
|
|
||||||
public DialogSettingsSearchEngine(){
|
public DialogSettingsSearchEngine() {
|
||||||
InitializeComponent();
|
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){
|
Text = Program.BrandName + " Options - Custom Search Engine";
|
||||||
DialogResult = DialogResult.Cancel;
|
|
||||||
Close();
|
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();
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
220
Dialogs/Settings/TabSettingsAdvanced.Designer.cs
generated
220
Dialogs/Settings/TabSettingsAdvanced.Designer.cs
generated
@@ -1,11 +1,11 @@
|
|||||||
namespace TweetDuck.Dialogs.Settings {
|
namespace TweetDuck.Dialogs.Settings {
|
||||||
partial class TabSettingsAdvanced {
|
partial class TabSettingsAdvanced {
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Required designer variable.
|
/// Required designer variable.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
private System.ComponentModel.IContainer components = null;
|
private System.ComponentModel.IContainer components = null;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Clean up any resources being used.
|
/// Clean up any resources being used.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
|
/// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
|
||||||
@@ -18,8 +18,8 @@
|
|||||||
|
|
||||||
#region Component Designer generated code
|
#region Component Designer generated code
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Required method for Designer support - do not modify
|
/// Required method for Designer support - do not modify
|
||||||
/// 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() {
|
||||||
@@ -40,24 +40,34 @@
|
|||||||
this.panelClearCacheAuto = new System.Windows.Forms.Panel();
|
this.panelClearCacheAuto = new System.Windows.Forms.Panel();
|
||||||
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();
|
||||||
this.flowPanel = new System.Windows.Forms.FlowLayoutPanel();
|
this.flowPanelLeft = new System.Windows.Forms.FlowLayoutPanel();
|
||||||
|
this.labelBrowserSettings = new System.Windows.Forms.Label();
|
||||||
|
this.checkHardwareAcceleration = new System.Windows.Forms.CheckBox();
|
||||||
|
this.checkAutomaticallyDetectColorProfile = new System.Windows.Forms.CheckBox();
|
||||||
|
this.checkTouchAdjustment = new System.Windows.Forms.CheckBox();
|
||||||
|
this.labelProxy = new System.Windows.Forms.Label();
|
||||||
|
this.checkUseSystemProxyForAllConnections = new System.Windows.Forms.CheckBox();
|
||||||
this.labelDevTools = new System.Windows.Forms.Label();
|
this.labelDevTools = new System.Windows.Forms.Label();
|
||||||
|
this.checkDevToolsInContextMenu = new System.Windows.Forms.CheckBox();
|
||||||
this.checkDevToolsWindowOnTop = new System.Windows.Forms.CheckBox();
|
this.checkDevToolsWindowOnTop = new System.Windows.Forms.CheckBox();
|
||||||
|
this.flowPanelRight = new System.Windows.Forms.FlowLayoutPanel();
|
||||||
|
this.panelSeparator = new System.Windows.Forms.Panel();
|
||||||
((System.ComponentModel.ISupportInitialize)(this.numClearCacheThreshold)).BeginInit();
|
((System.ComponentModel.ISupportInitialize)(this.numClearCacheThreshold)).BeginInit();
|
||||||
this.panelAppButtons.SuspendLayout();
|
this.panelAppButtons.SuspendLayout();
|
||||||
this.panelClearCacheAuto.SuspendLayout();
|
this.panelClearCacheAuto.SuspendLayout();
|
||||||
this.panelConfiguration.SuspendLayout();
|
this.panelConfiguration.SuspendLayout();
|
||||||
this.flowPanel.SuspendLayout();
|
this.flowPanelLeft.SuspendLayout();
|
||||||
|
this.flowPanelRight.SuspendLayout();
|
||||||
this.SuspendLayout();
|
this.SuspendLayout();
|
||||||
//
|
//
|
||||||
// btnClearCache
|
// btnClearCache
|
||||||
//
|
//
|
||||||
this.btnClearCache.Font = new System.Drawing.Font("Segoe UI", 9F);
|
this.btnClearCache.Font = new System.Drawing.Font("Segoe UI", 9F);
|
||||||
this.btnClearCache.Location = new System.Drawing.Point(5, 135);
|
this.btnClearCache.Location = new System.Drawing.Point(5, 145);
|
||||||
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(143, 25);
|
this.btnClearCache.Size = new System.Drawing.Size(143, 25);
|
||||||
this.btnClearCache.TabIndex = 3;
|
this.btnClearCache.TabIndex = 5;
|
||||||
this.btnClearCache.Text = "Clear Cache (...)";
|
this.btnClearCache.Text = "Clear Cache (...)";
|
||||||
this.btnClearCache.UseVisualStyleBackColor = true;
|
this.btnClearCache.UseVisualStyleBackColor = true;
|
||||||
//
|
//
|
||||||
@@ -144,7 +154,7 @@
|
|||||||
0,
|
0,
|
||||||
0});
|
0});
|
||||||
this.numClearCacheThreshold.Name = "numClearCacheThreshold";
|
this.numClearCacheThreshold.Name = "numClearCacheThreshold";
|
||||||
this.numClearCacheThreshold.Size = new System.Drawing.Size(89, 23);
|
this.numClearCacheThreshold.Size = new System.Drawing.Size(80, 23);
|
||||||
this.numClearCacheThreshold.TabIndex = 1;
|
this.numClearCacheThreshold.TabIndex = 1;
|
||||||
this.numClearCacheThreshold.TextAlign = System.Windows.Forms.HorizontalAlignment.Right;
|
this.numClearCacheThreshold.TextAlign = System.Windows.Forms.HorizontalAlignment.Right;
|
||||||
this.numClearCacheThreshold.TextSuffix = " MB";
|
this.numClearCacheThreshold.TextSuffix = " MB";
|
||||||
@@ -193,92 +203,205 @@
|
|||||||
//
|
//
|
||||||
this.labelCache.AutoSize = true;
|
this.labelCache.AutoSize = true;
|
||||||
this.labelCache.Font = new System.Drawing.Font("Segoe UI Semibold", 10.5F, System.Drawing.FontStyle.Bold);
|
this.labelCache.Font = new System.Drawing.Font("Segoe UI Semibold", 10.5F, System.Drawing.FontStyle.Bold);
|
||||||
this.labelCache.Location = new System.Drawing.Point(0, 112);
|
this.labelCache.Location = new System.Drawing.Point(0, 122);
|
||||||
this.labelCache.Margin = new System.Windows.Forms.Padding(0, 30, 0, 1);
|
this.labelCache.Margin = new System.Windows.Forms.Padding(0, 30, 0, 1);
|
||||||
this.labelCache.Name = "labelCache";
|
this.labelCache.Name = "labelCache";
|
||||||
this.labelCache.Size = new System.Drawing.Size(123, 19);
|
this.labelCache.Size = new System.Drawing.Size(123, 19);
|
||||||
this.labelCache.TabIndex = 2;
|
this.labelCache.TabIndex = 4;
|
||||||
this.labelCache.Text = "BROWSER CACHE";
|
this.labelCache.Text = "BROWSER CACHE";
|
||||||
//
|
//
|
||||||
// panelClearCacheAuto
|
// panelClearCacheAuto
|
||||||
//
|
//
|
||||||
this.panelClearCacheAuto.Controls.Add(this.checkClearCacheAuto);
|
this.panelClearCacheAuto.Controls.Add(this.checkClearCacheAuto);
|
||||||
this.panelClearCacheAuto.Controls.Add(this.numClearCacheThreshold);
|
this.panelClearCacheAuto.Controls.Add(this.numClearCacheThreshold);
|
||||||
this.panelClearCacheAuto.Location = new System.Drawing.Point(0, 163);
|
this.panelClearCacheAuto.Location = new System.Drawing.Point(0, 173);
|
||||||
this.panelClearCacheAuto.Margin = new System.Windows.Forms.Padding(0);
|
this.panelClearCacheAuto.Margin = new System.Windows.Forms.Padding(0);
|
||||||
this.panelClearCacheAuto.Name = "panelClearCacheAuto";
|
this.panelClearCacheAuto.Name = "panelClearCacheAuto";
|
||||||
this.panelClearCacheAuto.Size = new System.Drawing.Size(300, 28);
|
this.panelClearCacheAuto.Size = new System.Drawing.Size(300, 28);
|
||||||
this.panelClearCacheAuto.TabIndex = 4;
|
this.panelClearCacheAuto.TabIndex = 6;
|
||||||
//
|
//
|
||||||
// panelConfiguration
|
// panelConfiguration
|
||||||
//
|
//
|
||||||
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(0, 241);
|
this.panelConfiguration.Location = new System.Drawing.Point(0, 132);
|
||||||
this.panelConfiguration.Margin = new System.Windows.Forms.Padding(0);
|
this.panelConfiguration.Margin = new System.Windows.Forms.Padding(0);
|
||||||
this.panelConfiguration.Name = "panelConfiguration";
|
this.panelConfiguration.Name = "panelConfiguration";
|
||||||
this.panelConfiguration.Size = new System.Drawing.Size(300, 31);
|
this.panelConfiguration.Size = new System.Drawing.Size(300, 31);
|
||||||
this.panelConfiguration.TabIndex = 6;
|
this.panelConfiguration.TabIndex = 3;
|
||||||
//
|
//
|
||||||
// labelConfiguration
|
// labelConfiguration
|
||||||
//
|
//
|
||||||
this.labelConfiguration.AutoSize = true;
|
this.labelConfiguration.AutoSize = true;
|
||||||
this.labelConfiguration.Font = new System.Drawing.Font("Segoe UI Semibold", 10.5F, System.Drawing.FontStyle.Bold);
|
this.labelConfiguration.Font = new System.Drawing.Font("Segoe UI Semibold", 10.5F, System.Drawing.FontStyle.Bold);
|
||||||
this.labelConfiguration.Location = new System.Drawing.Point(0, 221);
|
this.labelConfiguration.Location = new System.Drawing.Point(0, 112);
|
||||||
this.labelConfiguration.Margin = new System.Windows.Forms.Padding(0, 30, 0, 1);
|
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(123, 19);
|
this.labelConfiguration.Size = new System.Drawing.Size(123, 19);
|
||||||
this.labelConfiguration.TabIndex = 5;
|
this.labelConfiguration.TabIndex = 2;
|
||||||
this.labelConfiguration.Text = "CONFIGURATION";
|
this.labelConfiguration.Text = "CONFIGURATION";
|
||||||
//
|
//
|
||||||
// flowPanel
|
// flowPanelLeft
|
||||||
//
|
//
|
||||||
this.flowPanel.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom)
|
this.flowPanelLeft.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)));
|
||||||
this.flowPanel.Controls.Add(this.labelApp);
|
this.flowPanelLeft.Controls.Add(this.labelBrowserSettings);
|
||||||
this.flowPanel.Controls.Add(this.panelAppButtons);
|
this.flowPanelLeft.Controls.Add(this.checkHardwareAcceleration);
|
||||||
this.flowPanel.Controls.Add(this.labelCache);
|
this.flowPanelLeft.Controls.Add(this.checkAutomaticallyDetectColorProfile);
|
||||||
this.flowPanel.Controls.Add(this.btnClearCache);
|
this.flowPanelLeft.Controls.Add(this.checkTouchAdjustment);
|
||||||
this.flowPanel.Controls.Add(this.panelClearCacheAuto);
|
this.flowPanelLeft.Controls.Add(this.labelCache);
|
||||||
this.flowPanel.Controls.Add(this.labelConfiguration);
|
this.flowPanelLeft.Controls.Add(this.btnClearCache);
|
||||||
this.flowPanel.Controls.Add(this.panelConfiguration);
|
this.flowPanelLeft.Controls.Add(this.panelClearCacheAuto);
|
||||||
this.flowPanel.Controls.Add(this.labelDevTools);
|
this.flowPanelLeft.Controls.Add(this.labelProxy);
|
||||||
this.flowPanel.Controls.Add(this.checkDevToolsWindowOnTop);
|
this.flowPanelLeft.Controls.Add(this.checkUseSystemProxyForAllConnections);
|
||||||
this.flowPanel.FlowDirection = System.Windows.Forms.FlowDirection.TopDown;
|
this.flowPanelLeft.Controls.Add(this.labelDevTools);
|
||||||
this.flowPanel.Location = new System.Drawing.Point(9, 9);
|
this.flowPanelLeft.Controls.Add(this.checkDevToolsInContextMenu);
|
||||||
this.flowPanel.Name = "flowPanel";
|
this.flowPanelLeft.Controls.Add(this.checkDevToolsWindowOnTop);
|
||||||
this.flowPanel.Size = new System.Drawing.Size(300, 462);
|
this.flowPanelLeft.FlowDirection = System.Windows.Forms.FlowDirection.TopDown;
|
||||||
this.flowPanel.TabIndex = 0;
|
this.flowPanelLeft.Location = new System.Drawing.Point(9, 9);
|
||||||
this.flowPanel.WrapContents = false;
|
this.flowPanelLeft.Name = "flowPanelLeft";
|
||||||
|
this.flowPanelLeft.Size = new System.Drawing.Size(300, 462);
|
||||||
|
this.flowPanelLeft.TabIndex = 0;
|
||||||
|
this.flowPanelLeft.WrapContents = false;
|
||||||
|
//
|
||||||
|
// 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";
|
||||||
|
//
|
||||||
|
// checkHardwareAcceleration
|
||||||
|
//
|
||||||
|
this.checkHardwareAcceleration.AutoSize = true;
|
||||||
|
this.checkHardwareAcceleration.Font = new System.Drawing.Font("Segoe UI", 9F);
|
||||||
|
this.checkHardwareAcceleration.Location = new System.Drawing.Point(6, 23);
|
||||||
|
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 = 1;
|
||||||
|
this.checkHardwareAcceleration.Text = "Hardware Acceleration";
|
||||||
|
this.checkHardwareAcceleration.UseVisualStyleBackColor = true;
|
||||||
|
//
|
||||||
|
// checkAutomaticallyDetectColorProfile
|
||||||
|
//
|
||||||
|
this.checkAutomaticallyDetectColorProfile.AutoSize = true;
|
||||||
|
this.checkAutomaticallyDetectColorProfile.Font = new System.Drawing.Font("Segoe UI", 9F);
|
||||||
|
this.checkAutomaticallyDetectColorProfile.Location = new System.Drawing.Point(6, 47);
|
||||||
|
this.checkAutomaticallyDetectColorProfile.Margin = new System.Windows.Forms.Padding(6, 3, 3, 2);
|
||||||
|
this.checkAutomaticallyDetectColorProfile.Name = "checkAutomaticallyDetectColorProfile";
|
||||||
|
this.checkAutomaticallyDetectColorProfile.Size = new System.Drawing.Size(206, 19);
|
||||||
|
this.checkAutomaticallyDetectColorProfile.TabIndex = 2;
|
||||||
|
this.checkAutomaticallyDetectColorProfile.Text = "Automatically Detect Color Profile";
|
||||||
|
this.checkAutomaticallyDetectColorProfile.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, 71);
|
||||||
|
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 = 3;
|
||||||
|
this.checkTouchAdjustment.Text = "Touch Screen Adjustment";
|
||||||
|
this.checkTouchAdjustment.UseVisualStyleBackColor = true;
|
||||||
|
//
|
||||||
|
// labelProxy
|
||||||
|
//
|
||||||
|
this.labelProxy.AutoSize = true;
|
||||||
|
this.labelProxy.Font = new System.Drawing.Font("Segoe UI Semibold", 10.5F, System.Drawing.FontStyle.Bold);
|
||||||
|
this.labelProxy.Location = new System.Drawing.Point(0, 231);
|
||||||
|
this.labelProxy.Margin = new System.Windows.Forms.Padding(0, 30, 0, 1);
|
||||||
|
this.labelProxy.Name = "labelProxy";
|
||||||
|
this.labelProxy.Size = new System.Drawing.Size(54, 19);
|
||||||
|
this.labelProxy.TabIndex = 7;
|
||||||
|
this.labelProxy.Text = "PROXY";
|
||||||
|
//
|
||||||
|
// checkUseSystemProxyForAllConnections
|
||||||
|
//
|
||||||
|
this.checkUseSystemProxyForAllConnections.AutoSize = true;
|
||||||
|
this.checkUseSystemProxyForAllConnections.Font = new System.Drawing.Font("Segoe UI", 9F);
|
||||||
|
this.checkUseSystemProxyForAllConnections.Location = new System.Drawing.Point(6, 257);
|
||||||
|
this.checkUseSystemProxyForAllConnections.Margin = new System.Windows.Forms.Padding(6, 6, 3, 2);
|
||||||
|
this.checkUseSystemProxyForAllConnections.Name = "checkUseSystemProxyForAllConnections";
|
||||||
|
this.checkUseSystemProxyForAllConnections.Size = new System.Drawing.Size(223, 19);
|
||||||
|
this.checkUseSystemProxyForAllConnections.TabIndex = 8;
|
||||||
|
this.checkUseSystemProxyForAllConnections.Text = "Use System Proxy for All Connections";
|
||||||
|
this.checkUseSystemProxyForAllConnections.UseVisualStyleBackColor = true;
|
||||||
//
|
//
|
||||||
// labelDevTools
|
// labelDevTools
|
||||||
//
|
//
|
||||||
this.labelDevTools.AutoSize = true;
|
this.labelDevTools.AutoSize = true;
|
||||||
this.labelDevTools.Font = new System.Drawing.Font("Segoe UI Semibold", 10.5F, System.Drawing.FontStyle.Bold);
|
this.labelDevTools.Font = new System.Drawing.Font("Segoe UI Semibold", 10.5F, System.Drawing.FontStyle.Bold);
|
||||||
this.labelDevTools.Location = new System.Drawing.Point(0, 302);
|
this.labelDevTools.Location = new System.Drawing.Point(0, 308);
|
||||||
this.labelDevTools.Margin = new System.Windows.Forms.Padding(0, 30, 0, 1);
|
this.labelDevTools.Margin = new System.Windows.Forms.Padding(0, 30, 0, 1);
|
||||||
this.labelDevTools.Name = "labelDevTools";
|
this.labelDevTools.Name = "labelDevTools";
|
||||||
this.labelDevTools.Size = new System.Drawing.Size(156, 19);
|
this.labelDevTools.Size = new System.Drawing.Size(156, 19);
|
||||||
this.labelDevTools.TabIndex = 7;
|
this.labelDevTools.TabIndex = 9;
|
||||||
this.labelDevTools.Text = "DEVELOPMENT TOOLS";
|
this.labelDevTools.Text = "DEVELOPMENT TOOLS";
|
||||||
//
|
//
|
||||||
|
// checkDevToolsInContextMenu
|
||||||
|
//
|
||||||
|
this.checkDevToolsInContextMenu.AutoSize = true;
|
||||||
|
this.checkDevToolsInContextMenu.Font = new System.Drawing.Font("Segoe UI", 9F);
|
||||||
|
this.checkDevToolsInContextMenu.Location = new System.Drawing.Point(6, 334);
|
||||||
|
this.checkDevToolsInContextMenu.Margin = new System.Windows.Forms.Padding(6, 6, 3, 2);
|
||||||
|
this.checkDevToolsInContextMenu.Name = "checkDevToolsInContextMenu";
|
||||||
|
this.checkDevToolsInContextMenu.Size = new System.Drawing.Size(201, 19);
|
||||||
|
this.checkDevToolsInContextMenu.TabIndex = 10;
|
||||||
|
this.checkDevToolsInContextMenu.Text = "Show Dev Tools in Context Menu";
|
||||||
|
this.checkDevToolsInContextMenu.UseVisualStyleBackColor = true;
|
||||||
|
//
|
||||||
// checkDevToolsWindowOnTop
|
// checkDevToolsWindowOnTop
|
||||||
//
|
//
|
||||||
this.checkDevToolsWindowOnTop.AutoSize = true;
|
this.checkDevToolsWindowOnTop.AutoSize = true;
|
||||||
this.checkDevToolsWindowOnTop.Font = new System.Drawing.Font("Segoe UI", 9F);
|
this.checkDevToolsWindowOnTop.Font = new System.Drawing.Font("Segoe UI", 9F);
|
||||||
this.checkDevToolsWindowOnTop.Location = new System.Drawing.Point(6, 328);
|
this.checkDevToolsWindowOnTop.Location = new System.Drawing.Point(6, 358);
|
||||||
this.checkDevToolsWindowOnTop.Margin = new System.Windows.Forms.Padding(6, 6, 0, 2);
|
this.checkDevToolsWindowOnTop.Margin = new System.Windows.Forms.Padding(6, 3, 3, 2);
|
||||||
this.checkDevToolsWindowOnTop.Name = "checkDevToolsWindowOnTop";
|
this.checkDevToolsWindowOnTop.Name = "checkDevToolsWindowOnTop";
|
||||||
this.checkDevToolsWindowOnTop.Size = new System.Drawing.Size(168, 19);
|
this.checkDevToolsWindowOnTop.Size = new System.Drawing.Size(168, 19);
|
||||||
this.checkDevToolsWindowOnTop.TabIndex = 8;
|
this.checkDevToolsWindowOnTop.TabIndex = 11;
|
||||||
this.checkDevToolsWindowOnTop.Text = "Dev Tools Window On Top";
|
this.checkDevToolsWindowOnTop.Text = "Dev Tools Window On Top";
|
||||||
this.checkDevToolsWindowOnTop.UseVisualStyleBackColor = true;
|
this.checkDevToolsWindowOnTop.UseVisualStyleBackColor = true;
|
||||||
//
|
//
|
||||||
|
// 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.labelApp);
|
||||||
|
this.flowPanelRight.Controls.Add(this.panelAppButtons);
|
||||||
|
this.flowPanelRight.Controls.Add(this.labelConfiguration);
|
||||||
|
this.flowPanelRight.Controls.Add(this.panelConfiguration);
|
||||||
|
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;
|
||||||
|
//
|
||||||
|
// 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 = 3;
|
||||||
|
//
|
||||||
// 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.flowPanel);
|
this.Controls.Add(this.panelSeparator);
|
||||||
|
this.Controls.Add(this.flowPanelRight);
|
||||||
|
this.Controls.Add(this.flowPanelLeft);
|
||||||
this.Name = "TabSettingsAdvanced";
|
this.Name = "TabSettingsAdvanced";
|
||||||
this.Size = new System.Drawing.Size(631, 480);
|
this.Size = new System.Drawing.Size(631, 480);
|
||||||
((System.ComponentModel.ISupportInitialize)(this.numClearCacheThreshold)).EndInit();
|
((System.ComponentModel.ISupportInitialize)(this.numClearCacheThreshold)).EndInit();
|
||||||
@@ -286,8 +409,10 @@
|
|||||||
this.panelClearCacheAuto.ResumeLayout(false);
|
this.panelClearCacheAuto.ResumeLayout(false);
|
||||||
this.panelClearCacheAuto.PerformLayout();
|
this.panelClearCacheAuto.PerformLayout();
|
||||||
this.panelConfiguration.ResumeLayout(false);
|
this.panelConfiguration.ResumeLayout(false);
|
||||||
this.flowPanel.ResumeLayout(false);
|
this.flowPanelLeft.ResumeLayout(false);
|
||||||
this.flowPanel.PerformLayout();
|
this.flowPanelLeft.PerformLayout();
|
||||||
|
this.flowPanelRight.ResumeLayout(false);
|
||||||
|
this.flowPanelRight.PerformLayout();
|
||||||
this.ResumeLayout(false);
|
this.ResumeLayout(false);
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -310,8 +435,17 @@
|
|||||||
private System.Windows.Forms.Label labelConfiguration;
|
private System.Windows.Forms.Label labelConfiguration;
|
||||||
private Controls.NumericUpDownEx numClearCacheThreshold;
|
private Controls.NumericUpDownEx numClearCacheThreshold;
|
||||||
private System.Windows.Forms.CheckBox checkClearCacheAuto;
|
private System.Windows.Forms.CheckBox checkClearCacheAuto;
|
||||||
private System.Windows.Forms.FlowLayoutPanel flowPanel;
|
private System.Windows.Forms.FlowLayoutPanel flowPanelLeft;
|
||||||
private System.Windows.Forms.Label labelDevTools;
|
private System.Windows.Forms.Label labelDevTools;
|
||||||
|
private System.Windows.Forms.CheckBox checkDevToolsInContextMenu;
|
||||||
private System.Windows.Forms.CheckBox checkDevToolsWindowOnTop;
|
private System.Windows.Forms.CheckBox checkDevToolsWindowOnTop;
|
||||||
|
private System.Windows.Forms.Label labelProxy;
|
||||||
|
private System.Windows.Forms.CheckBox checkUseSystemProxyForAllConnections;
|
||||||
|
private System.Windows.Forms.FlowLayoutPanel flowPanelRight;
|
||||||
|
private System.Windows.Forms.Label labelBrowserSettings;
|
||||||
|
private System.Windows.Forms.CheckBox checkTouchAdjustment;
|
||||||
|
private System.Windows.Forms.CheckBox checkAutomaticallyDetectColorProfile;
|
||||||
|
private System.Windows.Forms.CheckBox checkHardwareAcceleration;
|
||||||
|
private System.Windows.Forms.Panel panelSeparator;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,169 +7,221 @@ using TweetDuck.Management;
|
|||||||
using TweetDuck.Utils;
|
using TweetDuck.Utils;
|
||||||
using TweetLib.Core;
|
using TweetLib.Core;
|
||||||
|
|
||||||
namespace TweetDuck.Dialogs.Settings{
|
namespace TweetDuck.Dialogs.Settings {
|
||||||
sealed partial class TabSettingsAdvanced : FormSettings.BaseTab{
|
sealed partial class TabSettingsAdvanced : FormSettings.BaseTab {
|
||||||
private readonly Action<string> reinjectBrowserCSS;
|
private readonly Action<string> reinjectBrowserCSS;
|
||||||
private readonly Action openDevTools;
|
private readonly Action openDevTools;
|
||||||
|
|
||||||
public TabSettingsAdvanced(Action<string> reinjectBrowserCSS, Action openDevTools){
|
public TabSettingsAdvanced(Action<string> reinjectBrowserCSS, Action openDevTools) {
|
||||||
InitializeComponent();
|
InitializeComponent();
|
||||||
|
|
||||||
this.reinjectBrowserCSS = reinjectBrowserCSS;
|
this.reinjectBrowserCSS = reinjectBrowserCSS;
|
||||||
this.openDevTools = openDevTools;
|
this.openDevTools = openDevTools;
|
||||||
|
|
||||||
// application
|
// application
|
||||||
|
|
||||||
toolTip.SetToolTip(btnOpenAppFolder, "Opens the folder where the app is located.");
|
|
||||||
toolTip.SetToolTip(btnOpenDataFolder, "Opens the folder where your profile data is located.");
|
|
||||||
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.");
|
|
||||||
|
|
||||||
// browser cache
|
toolTip.SetToolTip(btnOpenAppFolder, "Opens the folder where the app is located.");
|
||||||
|
toolTip.SetToolTip(btnOpenDataFolder, "Opens the folder where your profile data is located.");
|
||||||
|
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.");
|
||||||
|
|
||||||
toolTip.SetToolTip(btnClearCache, "Clearing cache will free up space taken by downloaded images and other resources.");
|
// browser settings
|
||||||
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;
|
toolTip.SetToolTip(checkTouchAdjustment, "Toggles Chromium touch screen adjustment.\r\nDisabled by default, because it is very imprecise with TweetDeck.");
|
||||||
numClearCacheThreshold.Enabled = checkClearCacheAuto.Checked;
|
toolTip.SetToolTip(checkAutomaticallyDetectColorProfile, "Automatically detects the color profile of your system.\r\nUses the sRGB profile if disabled.");
|
||||||
numClearCacheThreshold.SetValueSafe(SysConfig.ClearCacheThreshold);
|
toolTip.SetToolTip(checkHardwareAcceleration, "Uses graphics card to improve performance.\r\nDisable if you experience visual glitches, or to save a small amount of RAM.");
|
||||||
|
|
||||||
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})");
|
|
||||||
});
|
|
||||||
|
|
||||||
// configuration
|
checkTouchAdjustment.Checked = SysConfig.EnableTouchAdjustment;
|
||||||
|
checkAutomaticallyDetectColorProfile.Checked = SysConfig.EnableColorProfileDetection;
|
||||||
|
checkHardwareAcceleration.Checked = SysConfig.HardwareAcceleration;
|
||||||
|
|
||||||
toolTip.SetToolTip(btnEditCefArgs, "Set custom command line arguments for Chromium Embedded Framework.");
|
// browser cache
|
||||||
toolTip.SetToolTip(btnEditCSS, "Set custom CSS for browser and notification windows.");
|
|
||||||
|
|
||||||
// development tools
|
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.");
|
||||||
|
|
||||||
toolTip.SetToolTip(checkDevToolsWindowOnTop, "Sets whether dev tool windows appears on top of other windows.");
|
checkClearCacheAuto.Checked = SysConfig.ClearCacheAutomatically;
|
||||||
|
numClearCacheThreshold.Enabled = checkClearCacheAuto.Checked;
|
||||||
|
numClearCacheThreshold.SetValueSafe(SysConfig.ClearCacheThreshold);
|
||||||
|
|
||||||
checkDevToolsWindowOnTop.Checked = Config.DevToolsWindowOnTop;
|
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})");
|
||||||
|
});
|
||||||
|
|
||||||
if (!BrowserUtils.HasDevTools){
|
// configuration
|
||||||
checkDevToolsWindowOnTop.Enabled = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public override void OnReady(){
|
toolTip.SetToolTip(btnEditCefArgs, "Set custom command line arguments for Chromium Embedded Framework.");
|
||||||
btnOpenAppFolder.Click += btnOpenAppFolder_Click;
|
toolTip.SetToolTip(btnEditCSS, "Set custom CSS for browser and notification windows.");
|
||||||
btnOpenDataFolder.Click += btnOpenDataFolder_Click;
|
|
||||||
btnRestart.Click += btnRestart_Click;
|
|
||||||
btnRestartArgs.Click += btnRestartArgs_Click;
|
|
||||||
|
|
||||||
btnClearCache.Click += btnClearCache_Click;
|
// proxy
|
||||||
checkClearCacheAuto.CheckedChanged += checkClearCacheAuto_CheckedChanged;
|
|
||||||
|
|
||||||
btnEditCefArgs.Click += btnEditCefArgs_Click;
|
|
||||||
btnEditCSS.Click += btnEditCSS_Click;
|
|
||||||
|
|
||||||
checkDevToolsWindowOnTop.CheckedChanged += checkDevToolsWindowOnTop_CheckedChanged;
|
toolTip.SetToolTip(checkUseSystemProxyForAllConnections, "Sets whether all connections should automatically detect and use the system proxy.\r\nBy default, only the browser component uses the system proxy, while other parts (such as update checks) ignore it.\r\nDisabled by default because Windows' proxy detection can be really slow.");
|
||||||
}
|
|
||||||
|
|
||||||
public override void OnClosing(){
|
checkUseSystemProxyForAllConnections.Checked = SysConfig.UseSystemProxyForAllConnections;
|
||||||
SysConfig.ClearCacheAutomatically = checkClearCacheAuto.Checked;
|
|
||||||
SysConfig.ClearCacheThreshold = (int)numClearCacheThreshold.Value;
|
|
||||||
}
|
|
||||||
|
|
||||||
#region Application
|
// development tools
|
||||||
|
|
||||||
private void btnOpenAppFolder_Click(object sender, EventArgs e){
|
|
||||||
App.SystemHandler.OpenFileExplorer(Program.ProgramPath);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void btnOpenDataFolder_Click(object sender, EventArgs e){
|
toolTip.SetToolTip(checkDevToolsInContextMenu, "Sets whether all context menus include an option to open dev tools.");
|
||||||
App.SystemHandler.OpenFileExplorer(Program.StoragePath);
|
toolTip.SetToolTip(checkDevToolsWindowOnTop, "Sets whether dev tool windows appears on top of other windows.");
|
||||||
}
|
|
||||||
|
|
||||||
private void btnRestart_Click(object sender, EventArgs e){
|
checkDevToolsInContextMenu.Checked = Config.DevToolsInContextMenu;
|
||||||
Program.Restart();
|
checkDevToolsWindowOnTop.Checked = Config.DevToolsWindowOnTop;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void btnRestartArgs_Click(object sender, EventArgs e){
|
public override void OnReady() {
|
||||||
using DialogSettingsRestart dialog = new DialogSettingsRestart(Arguments.GetCurrentClean());
|
btnOpenAppFolder.Click += btnOpenAppFolder_Click;
|
||||||
|
btnOpenDataFolder.Click += btnOpenDataFolder_Click;
|
||||||
|
btnRestart.Click += btnRestart_Click;
|
||||||
|
btnRestartArgs.Click += btnRestartArgs_Click;
|
||||||
|
|
||||||
if (dialog.ShowDialog() == DialogResult.OK){
|
checkTouchAdjustment.CheckedChanged += checkTouchAdjustment_CheckedChanged;
|
||||||
Program.RestartWithArgs(dialog.Args);
|
checkAutomaticallyDetectColorProfile.CheckedChanged += checkAutomaticallyDetectColorProfile_CheckedChanged;
|
||||||
}
|
checkHardwareAcceleration.CheckedChanged += checkHardwareAcceleration_CheckedChanged;
|
||||||
}
|
|
||||||
|
|
||||||
#endregion
|
btnClearCache.Click += btnClearCache_Click;
|
||||||
#region Browser Cache
|
checkClearCacheAuto.CheckedChanged += checkClearCacheAuto_CheckedChanged;
|
||||||
|
|
||||||
private void btnClearCache_Click(object sender, EventArgs e){
|
btnEditCefArgs.Click += btnEditCefArgs_Click;
|
||||||
btnClearCache.Enabled = false;
|
btnEditCSS.Click += btnEditCSS_Click;
|
||||||
BrowserCache.SetClearOnExit();
|
|
||||||
FormMessage.Information("Clear Cache", "Cache will be automatically cleared when TweetDuck exits.", FormMessage.OK);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void checkClearCacheAuto_CheckedChanged(object sender, EventArgs e){
|
checkUseSystemProxyForAllConnections.CheckedChanged += checkUseSystemProxyForAllConnections_CheckedChanged;
|
||||||
numClearCacheThreshold.Enabled = checkClearCacheAuto.Checked;
|
|
||||||
}
|
|
||||||
|
|
||||||
#endregion
|
checkDevToolsWindowOnTop.CheckedChanged += checkDevToolsWindowOnTop_CheckedChanged;
|
||||||
#region Configuration
|
checkDevToolsInContextMenu.CheckedChanged += checkDevToolsInContextMenuOnCheckedChanged;
|
||||||
|
}
|
||||||
|
|
||||||
private void btnEditCefArgs_Click(object sender, EventArgs e){
|
public override void OnClosing() {
|
||||||
DialogSettingsCefArgs form = new DialogSettingsCefArgs(Config.CustomCefArgs);
|
SysConfig.ClearCacheAutomatically = checkClearCacheAuto.Checked;
|
||||||
|
SysConfig.ClearCacheThreshold = (int) numClearCacheThreshold.Value;
|
||||||
|
}
|
||||||
|
|
||||||
form.VisibleChanged += (sender2, args2) => {
|
#region Application
|
||||||
form.MoveToCenter(ParentForm);
|
|
||||||
};
|
|
||||||
|
|
||||||
form.FormClosed += (sender2, args2) => {
|
private void btnOpenAppFolder_Click(object sender, EventArgs e) {
|
||||||
RestoreParentForm();
|
App.SystemHandler.OpenFileExplorer(App.ProgramPath);
|
||||||
|
}
|
||||||
|
|
||||||
if (form.DialogResult == DialogResult.OK){
|
private void btnOpenDataFolder_Click(object sender, EventArgs e) {
|
||||||
Config.CustomCefArgs = form.CefArgs;
|
App.SystemHandler.OpenFileExplorer(App.StoragePath);
|
||||||
}
|
}
|
||||||
|
|
||||||
form.Dispose();
|
private void btnRestart_Click(object sender, EventArgs e) {
|
||||||
};
|
Program.Restart();
|
||||||
|
}
|
||||||
form.Show(ParentForm);
|
|
||||||
NativeMethods.SetFormDisabled(ParentForm, true);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void btnEditCSS_Click(object sender, EventArgs e){
|
private void btnRestartArgs_Click(object sender, EventArgs e) {
|
||||||
DialogSettingsCSS form = new DialogSettingsCSS(Config.CustomBrowserCSS, Config.CustomNotificationCSS, reinjectBrowserCSS, openDevTools);
|
using DialogSettingsRestart dialog = new DialogSettingsRestart(Arguments.GetCurrentClean());
|
||||||
|
|
||||||
form.VisibleChanged += (sender2, args2) => {
|
if (dialog.ShowDialog() == DialogResult.OK) {
|
||||||
form.MoveToCenter(ParentForm);
|
Program.RestartWithArgs(dialog.Args);
|
||||||
};
|
}
|
||||||
|
}
|
||||||
|
|
||||||
form.FormClosed += (sender2, args2) => {
|
#endregion
|
||||||
RestoreParentForm();
|
|
||||||
|
|
||||||
if (form.DialogResult == DialogResult.OK){
|
#region Browser Settings
|
||||||
Config.CustomBrowserCSS = form.BrowserCSS;
|
|
||||||
Config.CustomNotificationCSS = form.NotificationCSS;
|
|
||||||
}
|
|
||||||
|
|
||||||
reinjectBrowserCSS(Config.CustomBrowserCSS); // reinject on cancel too, because the CSS is updated while typing
|
private void checkTouchAdjustment_CheckedChanged(object sender, EventArgs e) {
|
||||||
form.Dispose();
|
SysConfig.EnableTouchAdjustment = checkTouchAdjustment.Checked;
|
||||||
};
|
}
|
||||||
|
|
||||||
form.Show(ParentForm);
|
|
||||||
NativeMethods.SetFormDisabled(ParentForm, true);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void RestoreParentForm(){
|
private void checkAutomaticallyDetectColorProfile_CheckedChanged(object sender, EventArgs e) {
|
||||||
if (ParentForm != null){ // when the parent is closed first, ParentForm is null in FormClosed event
|
SysConfig.EnableColorProfileDetection = checkAutomaticallyDetectColorProfile.Checked;
|
||||||
NativeMethods.SetFormDisabled(ParentForm, false);
|
}
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#endregion
|
private void checkHardwareAcceleration_CheckedChanged(object sender, EventArgs e) {
|
||||||
#region Development Tools
|
SysConfig.HardwareAcceleration = checkHardwareAcceleration.Checked;
|
||||||
|
}
|
||||||
|
|
||||||
private void checkDevToolsWindowOnTop_CheckedChanged(object sender, EventArgs e){
|
#endregion
|
||||||
Config.DevToolsWindowOnTop = checkDevToolsWindowOnTop.Checked;
|
|
||||||
}
|
|
||||||
|
|
||||||
#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() {
|
||||||
|
if (ParentForm != null) { // when the parent is closed first, ParentForm is null in FormClosed event
|
||||||
|
NativeMethods.SetFormDisabled(ParentForm, false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region Proxy
|
||||||
|
|
||||||
|
private void checkUseSystemProxyForAllConnections_CheckedChanged(object sender, EventArgs e) {
|
||||||
|
SysConfig.UseSystemProxyForAllConnections = checkUseSystemProxyForAllConnections.Checked;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region Development Tools
|
||||||
|
|
||||||
|
private void checkDevToolsInContextMenuOnCheckedChanged(object sender, EventArgs e) {
|
||||||
|
Config.DevToolsInContextMenu = checkDevToolsInContextMenu.Checked;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void checkDevToolsWindowOnTop_CheckedChanged(object sender, EventArgs e) {
|
||||||
|
Config.DevToolsWindowOnTop = checkDevToolsWindowOnTop.Checked;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
215
Dialogs/Settings/TabSettingsFeedback.Designer.cs
generated
215
Dialogs/Settings/TabSettingsFeedback.Designer.cs
generated
@@ -1,11 +1,11 @@
|
|||||||
namespace TweetDuck.Dialogs.Settings {
|
namespace TweetDuck.Dialogs.Settings {
|
||||||
partial class TabSettingsFeedback {
|
partial class TabSettingsFeedback {
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Required designer variable.
|
/// Required designer variable.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
private System.ComponentModel.IContainer components = null;
|
private System.ComponentModel.IContainer components = null;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Clean up any resources being used.
|
/// Clean up any resources being used.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
|
/// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
|
||||||
@@ -18,165 +18,72 @@
|
|||||||
|
|
||||||
#region Component Designer generated code
|
#region Component Designer generated code
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Required method for Designer support - do not modify
|
/// Required method for Designer support - do not modify
|
||||||
/// 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.components = new System.ComponentModel.Container();
|
||||||
this.panelDataCollection = new System.Windows.Forms.Panel();
|
this.btnSendFeedback = new System.Windows.Forms.Button();
|
||||||
this.labelDataCollectionLink = new System.Windows.Forms.LinkLabel();
|
this.toolTip = new System.Windows.Forms.ToolTip(this.components);
|
||||||
this.checkDataCollection = new System.Windows.Forms.CheckBox();
|
this.flowPanel = new System.Windows.Forms.FlowLayoutPanel();
|
||||||
this.labelDataCollectionMessage = new System.Windows.Forms.Label();
|
this.labelFeedback = new System.Windows.Forms.Label();
|
||||||
this.btnViewReport = new System.Windows.Forms.Button();
|
this.flowPanel.SuspendLayout();
|
||||||
this.btnSendFeedback = new System.Windows.Forms.Button();
|
this.SuspendLayout();
|
||||||
this.labelDataCollection = new System.Windows.Forms.Label();
|
//
|
||||||
this.labelFeedback = new System.Windows.Forms.Label();
|
// btnSendFeedback
|
||||||
this.toolTip = new System.Windows.Forms.ToolTip(this.components);
|
//
|
||||||
this.flowPanel = new System.Windows.Forms.FlowLayoutPanel();
|
this.btnSendFeedback.AutoSize = true;
|
||||||
this.panelDataCollection.SuspendLayout();
|
this.btnSendFeedback.Font = new System.Drawing.Font("Segoe UI", 9F);
|
||||||
this.flowPanel.SuspendLayout();
|
this.btnSendFeedback.Location = new System.Drawing.Point(5, 23);
|
||||||
this.SuspendLayout();
|
this.btnSendFeedback.Margin = new System.Windows.Forms.Padding(5, 3, 3, 3);
|
||||||
//
|
this.btnSendFeedback.Name = "btnSendFeedback";
|
||||||
// panelDataCollection
|
this.btnSendFeedback.Padding = new System.Windows.Forms.Padding(2, 0, 2, 0);
|
||||||
//
|
this.btnSendFeedback.Size = new System.Drawing.Size(170, 25);
|
||||||
this.panelDataCollection.Controls.Add(this.labelDataCollectionLink);
|
this.btnSendFeedback.TabIndex = 1;
|
||||||
this.panelDataCollection.Controls.Add(this.checkDataCollection);
|
this.btnSendFeedback.Text = "Send Feedback / Bug Report";
|
||||||
this.panelDataCollection.Location = new System.Drawing.Point(0, 78);
|
this.btnSendFeedback.UseVisualStyleBackColor = true;
|
||||||
this.panelDataCollection.Margin = new System.Windows.Forms.Padding(0);
|
//
|
||||||
this.panelDataCollection.Name = "panelDataCollection";
|
// flowPanel
|
||||||
this.panelDataCollection.Size = new System.Drawing.Size(300, 28);
|
//
|
||||||
this.panelDataCollection.TabIndex = 3;
|
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);
|
||||||
// labelDataCollectionLink
|
this.flowPanel.Controls.Add(this.btnSendFeedback);
|
||||||
//
|
this.flowPanel.FlowDirection = System.Windows.Forms.FlowDirection.TopDown;
|
||||||
this.labelDataCollectionLink.AutoSize = true;
|
this.flowPanel.Location = new System.Drawing.Point(9, 9);
|
||||||
this.labelDataCollectionLink.Font = new System.Drawing.Font("Segoe UI", 9F);
|
this.flowPanel.Name = "flowPanel";
|
||||||
this.labelDataCollectionLink.LinkArea = new System.Windows.Forms.LinkArea(1, 10);
|
this.flowPanel.Size = new System.Drawing.Size(300, 462);
|
||||||
this.labelDataCollectionLink.LinkBehavior = System.Windows.Forms.LinkBehavior.HoverUnderline;
|
this.flowPanel.TabIndex = 0;
|
||||||
this.labelDataCollectionLink.Location = new System.Drawing.Point(153, 4);
|
this.flowPanel.WrapContents = false;
|
||||||
this.labelDataCollectionLink.Margin = new System.Windows.Forms.Padding(0);
|
//
|
||||||
this.labelDataCollectionLink.Name = "labelDataCollectionLink";
|
// labelFeedback
|
||||||
this.labelDataCollectionLink.Size = new System.Drawing.Size(71, 21);
|
//
|
||||||
this.labelDataCollectionLink.TabIndex = 1;
|
this.labelFeedback.AutoSize = true;
|
||||||
this.labelDataCollectionLink.TabStop = true;
|
this.labelFeedback.Font = new System.Drawing.Font("Segoe UI Semibold", 10.5F, System.Drawing.FontStyle.Bold);
|
||||||
this.labelDataCollectionLink.Text = "(learn more)";
|
this.labelFeedback.Location = new System.Drawing.Point(0, 0);
|
||||||
this.labelDataCollectionLink.TextAlign = System.Drawing.ContentAlignment.MiddleLeft;
|
this.labelFeedback.Margin = new System.Windows.Forms.Padding(0, 0, 0, 1);
|
||||||
this.labelDataCollectionLink.UseCompatibleTextRendering = true;
|
this.labelFeedback.Name = "labelFeedback";
|
||||||
//
|
this.labelFeedback.Size = new System.Drawing.Size(75, 19);
|
||||||
// checkDataCollection
|
this.labelFeedback.TabIndex = 0;
|
||||||
//
|
this.labelFeedback.Text = "FEEDBACK";
|
||||||
this.checkDataCollection.AutoSize = true;
|
//
|
||||||
this.checkDataCollection.Font = new System.Drawing.Font("Segoe UI", 9F);
|
// TabSettingsFeedback
|
||||||
this.checkDataCollection.Location = new System.Drawing.Point(6, 6);
|
//
|
||||||
this.checkDataCollection.Margin = new System.Windows.Forms.Padding(6, 6, 0, 2);
|
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
|
||||||
this.checkDataCollection.Name = "checkDataCollection";
|
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
|
||||||
this.checkDataCollection.Size = new System.Drawing.Size(147, 19);
|
this.Controls.Add(this.flowPanel);
|
||||||
this.checkDataCollection.TabIndex = 0;
|
this.Name = "TabSettingsFeedback";
|
||||||
this.checkDataCollection.Text = "Send Anonymous Data";
|
this.Size = new System.Drawing.Size(631, 480);
|
||||||
this.checkDataCollection.UseVisualStyleBackColor = true;
|
this.flowPanel.ResumeLayout(false);
|
||||||
//
|
this.flowPanel.PerformLayout();
|
||||||
// labelDataCollectionMessage
|
this.ResumeLayout(false);
|
||||||
//
|
|
||||||
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.Name = "labelDataCollectionMessage";
|
|
||||||
this.labelDataCollectionMessage.Size = new System.Drawing.Size(288, 67);
|
|
||||||
this.labelDataCollectionMessage.TabIndex = 5;
|
|
||||||
//
|
|
||||||
// btnViewReport
|
|
||||||
//
|
|
||||||
this.btnViewReport.AutoSize = true;
|
|
||||||
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.Name = "btnViewReport";
|
|
||||||
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.Text = "View My Analytics Report";
|
|
||||||
this.btnViewReport.UseVisualStyleBackColor = true;
|
|
||||||
//
|
|
||||||
// btnSendFeedback
|
|
||||||
//
|
|
||||||
this.btnSendFeedback.AutoSize = true;
|
|
||||||
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.Name = "btnSendFeedback";
|
|
||||||
this.btnSendFeedback.Padding = new System.Windows.Forms.Padding(2, 0, 2, 0);
|
|
||||||
this.btnSendFeedback.Size = new System.Drawing.Size(170, 25);
|
|
||||||
this.btnSendFeedback.TabIndex = 1;
|
|
||||||
this.btnSendFeedback.Text = "Send Feedback / Bug Report";
|
|
||||||
this.btnSendFeedback.UseVisualStyleBackColor = true;
|
|
||||||
//
|
|
||||||
// labelDataCollection
|
|
||||||
//
|
|
||||||
this.labelDataCollection.AutoSize = true;
|
|
||||||
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.Name = "labelDataCollection";
|
|
||||||
this.labelDataCollection.Size = new System.Drawing.Size(88, 15);
|
|
||||||
this.labelDataCollection.TabIndex = 2;
|
|
||||||
this.labelDataCollection.Text = "Data Collection";
|
|
||||||
//
|
|
||||||
// labelFeedback
|
|
||||||
//
|
|
||||||
this.labelFeedback.AutoSize = true;
|
|
||||||
this.labelFeedback.Font = new System.Drawing.Font("Segoe UI Semibold", 10.5F, System.Drawing.FontStyle.Bold);
|
|
||||||
this.labelFeedback.Location = new System.Drawing.Point(0, 0);
|
|
||||||
this.labelFeedback.Margin = new System.Windows.Forms.Padding(0, 0, 0, 1);
|
|
||||||
this.labelFeedback.Name = "labelFeedback";
|
|
||||||
this.labelFeedback.Size = new System.Drawing.Size(75, 19);
|
|
||||||
this.labelFeedback.TabIndex = 0;
|
|
||||||
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
|
|
||||||
//
|
|
||||||
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
|
|
||||||
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
|
|
||||||
this.Controls.Add(this.flowPanel);
|
|
||||||
this.Name = "TabSettingsFeedback";
|
|
||||||
this.Size = new System.Drawing.Size(631, 480);
|
|
||||||
this.panelDataCollection.ResumeLayout(false);
|
|
||||||
this.panelDataCollection.PerformLayout();
|
|
||||||
this.flowPanel.ResumeLayout(false);
|
|
||||||
this.flowPanel.PerformLayout();
|
|
||||||
this.ResumeLayout(false);
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#endregion
|
|
||||||
|
|
||||||
private System.Windows.Forms.Panel panelDataCollection;
|
|
||||||
private System.Windows.Forms.CheckBox checkDataCollection;
|
|
||||||
private System.Windows.Forms.Label labelDataCollection;
|
|
||||||
private System.Windows.Forms.Label labelFeedback;
|
|
||||||
private System.Windows.Forms.ToolTip toolTip;
|
private System.Windows.Forms.ToolTip toolTip;
|
||||||
private System.Windows.Forms.LinkLabel labelDataCollectionLink;
|
|
||||||
private System.Windows.Forms.Button btnSendFeedback;
|
private System.Windows.Forms.Button btnSendFeedback;
|
||||||
private System.Windows.Forms.Button btnViewReport;
|
|
||||||
private System.Windows.Forms.Label labelDataCollectionMessage;
|
|
||||||
private System.Windows.Forms.FlowLayoutPanel flowPanel;
|
private System.Windows.Forms.FlowLayoutPanel flowPanel;
|
||||||
|
private System.Windows.Forms.Label labelFeedback;
|
||||||
|
|
||||||
|
#endregion
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,58 +1,22 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Windows.Forms;
|
using TweetLib.Core;
|
||||||
using TweetDuck.Management.Analytics;
|
|
||||||
using TweetDuck.Utils;
|
|
||||||
using TweetLib.Core.Features.Plugins;
|
|
||||||
|
|
||||||
namespace TweetDuck.Dialogs.Settings{
|
namespace TweetDuck.Dialogs.Settings {
|
||||||
sealed partial class TabSettingsFeedback : FormSettings.BaseTab{
|
sealed partial class TabSettingsFeedback : FormSettings.BaseTab {
|
||||||
private readonly AnalyticsFile analyticsFile;
|
public TabSettingsFeedback() {
|
||||||
private readonly AnalyticsReportGenerator.ExternalInfo analyticsInfo;
|
InitializeComponent();
|
||||||
private readonly PluginManager plugins;
|
}
|
||||||
|
|
||||||
public TabSettingsFeedback(AnalyticsManager analytics, AnalyticsReportGenerator.ExternalInfo analyticsInfo, PluginManager plugins){
|
public override void OnReady() {
|
||||||
InitializeComponent();
|
btnSendFeedback.Click += btnSendFeedback_Click;
|
||||||
|
}
|
||||||
this.analyticsFile = analytics?.File ?? AnalyticsFile.Load(Program.AnalyticsFilePath);
|
|
||||||
this.analyticsInfo = analyticsInfo;
|
|
||||||
this.plugins = plugins;
|
|
||||||
|
|
||||||
// feedback
|
#region Feedback
|
||||||
|
|
||||||
checkDataCollection.Checked = Config.AllowDataCollection;
|
private void btnSendFeedback_Click(object sender, EventArgs e) {
|
||||||
|
App.SystemHandler.OpenBrowser(Lib.IssueTrackerUrl + "/new");
|
||||||
|
}
|
||||||
|
|
||||||
if (analytics != null){
|
#endregion
|
||||||
string collectionTime = analyticsFile.LastCollectionMessage;
|
}
|
||||||
labelDataCollectionMessage.Text = string.IsNullOrEmpty(collectionTime) ? "No collection yet" : "Last collection: " + collectionTime;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public override void OnReady(){
|
|
||||||
btnSendFeedback.Click += btnSendFeedback_Click;
|
|
||||||
checkDataCollection.CheckedChanged += checkDataCollection_CheckedChanged;
|
|
||||||
labelDataCollectionLink.LinkClicked += labelDataCollectionLink_LinkClicked;
|
|
||||||
btnViewReport.Click += btnViewReport_Click;
|
|
||||||
}
|
|
||||||
|
|
||||||
#region Feedback
|
|
||||||
|
|
||||||
private void btnSendFeedback_Click(object sender, EventArgs e){
|
|
||||||
BrowserUtils.OpenExternalBrowser("https://github.com/chylex/TweetDuck/issues/new");
|
|
||||||
}
|
|
||||||
|
|
||||||
private void checkDataCollection_CheckedChanged(object sender, EventArgs e){
|
|
||||||
Config.AllowDataCollection = checkDataCollection.Checked;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void labelDataCollectionLink_LinkClicked(object sender, LinkLabelLinkClickedEventArgs e){
|
|
||||||
BrowserUtils.OpenExternalBrowser("https://github.com/chylex/TweetDuck/wiki/Send-anonymous-data");
|
|
||||||
}
|
|
||||||
|
|
||||||
private void btnViewReport_Click(object sender, EventArgs e){
|
|
||||||
using DialogSettingsAnalytics dialog = new DialogSettingsAnalytics(AnalyticsReportGenerator.Create(analyticsFile, analyticsInfo, plugins));
|
|
||||||
dialog.ShowDialog();
|
|
||||||
}
|
|
||||||
|
|
||||||
#endregion
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
147
Dialogs/Settings/TabSettingsGeneral.Designer.cs
generated
147
Dialogs/Settings/TabSettingsGeneral.Designer.cs
generated
@@ -1,11 +1,11 @@
|
|||||||
namespace TweetDuck.Dialogs.Settings {
|
namespace TweetDuck.Dialogs.Settings {
|
||||||
partial class TabSettingsGeneral {
|
partial class TabSettingsGeneral {
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Required designer variable.
|
/// Required designer variable.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
private System.ComponentModel.IContainer components = null;
|
private System.ComponentModel.IContainer components = null;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Clean up any resources being used.
|
/// Clean up any resources being used.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
|
/// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
|
||||||
@@ -18,8 +18,8 @@
|
|||||||
|
|
||||||
#region Component Designer generated code
|
#region Component Designer generated code
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Required method for Designer support - do not modify
|
/// Required method for Designer support - do not modify
|
||||||
/// 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() {
|
||||||
@@ -34,17 +34,16 @@
|
|||||||
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.panelZoom = new System.Windows.Forms.Panel();
|
this.panelZoom = new System.Windows.Forms.Panel();
|
||||||
this.checkAnimatedAvatars = new System.Windows.Forms.CheckBox();
|
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.flowPanelLeft = new System.Windows.Forms.FlowLayoutPanel();
|
||||||
|
this.labelUI = new System.Windows.Forms.Label();
|
||||||
this.checkFocusDmInput = new System.Windows.Forms.CheckBox();
|
this.checkFocusDmInput = new System.Windows.Forms.CheckBox();
|
||||||
this.checkKeepLikeFollowDialogsOpen = new System.Windows.Forms.CheckBox();
|
this.checkKeepLikeFollowDialogsOpen = new System.Windows.Forms.CheckBox();
|
||||||
this.labelBrowserSettings = new System.Windows.Forms.Label();
|
|
||||||
this.checkSmoothScrolling = new System.Windows.Forms.CheckBox();
|
this.checkSmoothScrolling = new System.Windows.Forms.CheckBox();
|
||||||
this.checkTouchAdjustment = new System.Windows.Forms.CheckBox();
|
this.labelTweetDeckSettings = new System.Windows.Forms.Label();
|
||||||
this.checkHardwareAcceleration = new System.Windows.Forms.CheckBox();
|
this.checkHideTweetsByNftUsers = new System.Windows.Forms.CheckBox();
|
||||||
this.labelBrowserPath = new System.Windows.Forms.Label();
|
this.labelBrowserPath = new System.Windows.Forms.Label();
|
||||||
this.comboBoxCustomBrowser = new System.Windows.Forms.ComboBox();
|
this.comboBoxCustomBrowser = new System.Windows.Forms.ComboBox();
|
||||||
this.labelSearchEngine = new System.Windows.Forms.Label();
|
this.labelSearchEngine = new System.Windows.Forms.Label();
|
||||||
@@ -90,11 +89,11 @@
|
|||||||
//
|
//
|
||||||
this.checkUpdateNotifications.AutoSize = true;
|
this.checkUpdateNotifications.AutoSize = true;
|
||||||
this.checkUpdateNotifications.Font = new System.Drawing.Font("Segoe UI", 9F);
|
this.checkUpdateNotifications.Font = new System.Drawing.Font("Segoe UI", 9F);
|
||||||
this.checkUpdateNotifications.Location = new System.Drawing.Point(6, 403);
|
this.checkUpdateNotifications.Location = new System.Drawing.Point(6, 381);
|
||||||
this.checkUpdateNotifications.Margin = new System.Windows.Forms.Padding(6, 6, 3, 2);
|
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(182, 19);
|
this.checkUpdateNotifications.Size = new System.Drawing.Size(182, 19);
|
||||||
this.checkUpdateNotifications.TabIndex = 14;
|
this.checkUpdateNotifications.TabIndex = 13;
|
||||||
this.checkUpdateNotifications.Text = "Check Updates Automatically";
|
this.checkUpdateNotifications.Text = "Check Updates Automatically";
|
||||||
this.checkUpdateNotifications.UseVisualStyleBackColor = true;
|
this.checkUpdateNotifications.UseVisualStyleBackColor = true;
|
||||||
//
|
//
|
||||||
@@ -102,12 +101,12 @@
|
|||||||
//
|
//
|
||||||
this.btnCheckUpdates.AutoSize = true;
|
this.btnCheckUpdates.AutoSize = true;
|
||||||
this.btnCheckUpdates.Font = new System.Drawing.Font("Segoe UI", 9F);
|
this.btnCheckUpdates.Font = new System.Drawing.Font("Segoe UI", 9F);
|
||||||
this.btnCheckUpdates.Location = new System.Drawing.Point(5, 427);
|
this.btnCheckUpdates.Location = new System.Drawing.Point(5, 405);
|
||||||
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.Padding = new System.Windows.Forms.Padding(2, 0, 2, 0);
|
this.btnCheckUpdates.Padding = new System.Windows.Forms.Padding(2, 0, 2, 0);
|
||||||
this.btnCheckUpdates.Size = new System.Drawing.Size(128, 25);
|
this.btnCheckUpdates.Size = new System.Drawing.Size(128, 25);
|
||||||
this.btnCheckUpdates.TabIndex = 15;
|
this.btnCheckUpdates.TabIndex = 14;
|
||||||
this.btnCheckUpdates.Text = "Check Updates Now";
|
this.btnCheckUpdates.Text = "Check Updates Now";
|
||||||
this.btnCheckUpdates.UseVisualStyleBackColor = true;
|
this.btnCheckUpdates.UseVisualStyleBackColor = true;
|
||||||
//
|
//
|
||||||
@@ -127,12 +126,12 @@
|
|||||||
//
|
//
|
||||||
this.checkBestImageQuality.AutoSize = true;
|
this.checkBestImageQuality.AutoSize = true;
|
||||||
this.checkBestImageQuality.Font = new System.Drawing.Font("Segoe UI", 9F);
|
this.checkBestImageQuality.Font = new System.Drawing.Font("Segoe UI", 9F);
|
||||||
this.checkBestImageQuality.Location = new System.Drawing.Point(6, 122);
|
this.checkBestImageQuality.Location = new System.Drawing.Point(6, 259);
|
||||||
this.checkBestImageQuality.Margin = new System.Windows.Forms.Padding(6, 3, 3, 2);
|
this.checkBestImageQuality.Margin = new System.Windows.Forms.Padding(6, 6, 3, 2);
|
||||||
this.checkBestImageQuality.Name = "checkBestImageQuality";
|
this.checkBestImageQuality.Name = "checkBestImageQuality";
|
||||||
this.checkBestImageQuality.Size = new System.Drawing.Size(125, 19);
|
this.checkBestImageQuality.Size = new System.Drawing.Size(182, 19);
|
||||||
this.checkBestImageQuality.TabIndex = 5;
|
this.checkBestImageQuality.TabIndex = 9;
|
||||||
this.checkBestImageQuality.Text = "Best Image Quality";
|
this.checkBestImageQuality.Text = "Download Best Image Quality";
|
||||||
this.checkBestImageQuality.UseVisualStyleBackColor = true;
|
this.checkBestImageQuality.UseVisualStyleBackColor = true;
|
||||||
//
|
//
|
||||||
// checkOpenSearchInFirstColumn
|
// checkOpenSearchInFirstColumn
|
||||||
@@ -166,11 +165,11 @@
|
|||||||
//
|
//
|
||||||
this.labelZoom.AutoSize = true;
|
this.labelZoom.AutoSize = true;
|
||||||
this.labelZoom.Font = new System.Drawing.Font("Segoe UI Semibold", 9F, System.Drawing.FontStyle.Bold);
|
this.labelZoom.Font = new System.Drawing.Font("Segoe UI Semibold", 9F, System.Drawing.FontStyle.Bold);
|
||||||
this.labelZoom.Location = new System.Drawing.Point(3, 299);
|
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(39, 15);
|
this.labelZoom.Size = new System.Drawing.Size(39, 15);
|
||||||
this.labelZoom.TabIndex = 11;
|
this.labelZoom.TabIndex = 6;
|
||||||
this.labelZoom.Text = "Zoom";
|
this.labelZoom.Text = "Zoom";
|
||||||
//
|
//
|
||||||
// zoomUpdateTimer
|
// zoomUpdateTimer
|
||||||
@@ -178,36 +177,25 @@
|
|||||||
this.zoomUpdateTimer.Interval = 250;
|
this.zoomUpdateTimer.Interval = 250;
|
||||||
this.zoomUpdateTimer.Tick += new System.EventHandler(this.zoomUpdateTimer_Tick);
|
this.zoomUpdateTimer.Tick += new System.EventHandler(this.zoomUpdateTimer_Tick);
|
||||||
//
|
//
|
||||||
// labelUI
|
|
||||||
//
|
|
||||||
this.labelUI.AutoSize = true;
|
|
||||||
this.labelUI.Font = new System.Drawing.Font("Segoe UI Semibold", 10.5F, System.Drawing.FontStyle.Bold);
|
|
||||||
this.labelUI.Location = new System.Drawing.Point(0, 0);
|
|
||||||
this.labelUI.Margin = new System.Windows.Forms.Padding(0, 0, 0, 1);
|
|
||||||
this.labelUI.Name = "labelUI";
|
|
||||||
this.labelUI.Size = new System.Drawing.Size(118, 19);
|
|
||||||
this.labelUI.TabIndex = 0;
|
|
||||||
this.labelUI.Text = "USER INTERFACE";
|
|
||||||
//
|
|
||||||
// panelZoom
|
// panelZoom
|
||||||
//
|
//
|
||||||
this.panelZoom.Controls.Add(this.trackBarZoom);
|
this.panelZoom.Controls.Add(this.trackBarZoom);
|
||||||
this.panelZoom.Controls.Add(this.labelZoomValue);
|
this.panelZoom.Controls.Add(this.labelZoomValue);
|
||||||
this.panelZoom.Location = new System.Drawing.Point(0, 315);
|
this.panelZoom.Location = new System.Drawing.Point(0, 171);
|
||||||
this.panelZoom.Margin = new System.Windows.Forms.Padding(0, 1, 0, 0);
|
this.panelZoom.Margin = new System.Windows.Forms.Padding(0, 1, 0, 0);
|
||||||
this.panelZoom.Name = "panelZoom";
|
this.panelZoom.Name = "panelZoom";
|
||||||
this.panelZoom.Size = new System.Drawing.Size(300, 35);
|
this.panelZoom.Size = new System.Drawing.Size(300, 35);
|
||||||
this.panelZoom.TabIndex = 12;
|
this.panelZoom.TabIndex = 7;
|
||||||
//
|
//
|
||||||
// checkAnimatedAvatars
|
// checkAnimatedAvatars
|
||||||
//
|
//
|
||||||
this.checkAnimatedAvatars.AutoSize = true;
|
this.checkAnimatedAvatars.AutoSize = true;
|
||||||
this.checkAnimatedAvatars.Font = new System.Drawing.Font("Segoe UI", 9F);
|
this.checkAnimatedAvatars.Font = new System.Drawing.Font("Segoe UI", 9F);
|
||||||
this.checkAnimatedAvatars.Location = new System.Drawing.Point(6, 146);
|
this.checkAnimatedAvatars.Location = new System.Drawing.Point(6, 307);
|
||||||
this.checkAnimatedAvatars.Margin = new System.Windows.Forms.Padding(6, 3, 3, 2);
|
this.checkAnimatedAvatars.Margin = new System.Windows.Forms.Padding(6, 3, 3, 2);
|
||||||
this.checkAnimatedAvatars.Name = "checkAnimatedAvatars";
|
this.checkAnimatedAvatars.Name = "checkAnimatedAvatars";
|
||||||
this.checkAnimatedAvatars.Size = new System.Drawing.Size(158, 19);
|
this.checkAnimatedAvatars.Size = new System.Drawing.Size(158, 19);
|
||||||
this.checkAnimatedAvatars.TabIndex = 6;
|
this.checkAnimatedAvatars.TabIndex = 11;
|
||||||
this.checkAnimatedAvatars.Text = "Enable Animated Avatars";
|
this.checkAnimatedAvatars.Text = "Enable Animated Avatars";
|
||||||
this.checkAnimatedAvatars.UseVisualStyleBackColor = true;
|
this.checkAnimatedAvatars.UseVisualStyleBackColor = true;
|
||||||
//
|
//
|
||||||
@@ -215,11 +203,11 @@
|
|||||||
//
|
//
|
||||||
this.labelUpdates.AutoSize = true;
|
this.labelUpdates.AutoSize = true;
|
||||||
this.labelUpdates.Font = new System.Drawing.Font("Segoe UI Semibold", 10.5F, System.Drawing.FontStyle.Bold);
|
this.labelUpdates.Font = new System.Drawing.Font("Segoe UI Semibold", 10.5F, System.Drawing.FontStyle.Bold);
|
||||||
this.labelUpdates.Location = new System.Drawing.Point(0, 377);
|
this.labelUpdates.Location = new System.Drawing.Point(0, 355);
|
||||||
this.labelUpdates.Margin = new System.Windows.Forms.Padding(0, 27, 0, 1);
|
this.labelUpdates.Margin = new System.Windows.Forms.Padding(0, 27, 0, 1);
|
||||||
this.labelUpdates.Name = "labelUpdates";
|
this.labelUpdates.Name = "labelUpdates";
|
||||||
this.labelUpdates.Size = new System.Drawing.Size(69, 19);
|
this.labelUpdates.Size = new System.Drawing.Size(69, 19);
|
||||||
this.labelUpdates.TabIndex = 13;
|
this.labelUpdates.TabIndex = 12;
|
||||||
this.labelUpdates.Text = "UPDATES";
|
this.labelUpdates.Text = "UPDATES";
|
||||||
//
|
//
|
||||||
// flowPanelLeft
|
// flowPanelLeft
|
||||||
@@ -231,14 +219,13 @@
|
|||||||
this.flowPanelLeft.Controls.Add(this.checkFocusDmInput);
|
this.flowPanelLeft.Controls.Add(this.checkFocusDmInput);
|
||||||
this.flowPanelLeft.Controls.Add(this.checkOpenSearchInFirstColumn);
|
this.flowPanelLeft.Controls.Add(this.checkOpenSearchInFirstColumn);
|
||||||
this.flowPanelLeft.Controls.Add(this.checkKeepLikeFollowDialogsOpen);
|
this.flowPanelLeft.Controls.Add(this.checkKeepLikeFollowDialogsOpen);
|
||||||
this.flowPanelLeft.Controls.Add(this.checkBestImageQuality);
|
|
||||||
this.flowPanelLeft.Controls.Add(this.checkAnimatedAvatars);
|
|
||||||
this.flowPanelLeft.Controls.Add(this.labelBrowserSettings);
|
|
||||||
this.flowPanelLeft.Controls.Add(this.checkSmoothScrolling);
|
this.flowPanelLeft.Controls.Add(this.checkSmoothScrolling);
|
||||||
this.flowPanelLeft.Controls.Add(this.checkTouchAdjustment);
|
|
||||||
this.flowPanelLeft.Controls.Add(this.checkHardwareAcceleration);
|
|
||||||
this.flowPanelLeft.Controls.Add(this.labelZoom);
|
this.flowPanelLeft.Controls.Add(this.labelZoom);
|
||||||
this.flowPanelLeft.Controls.Add(this.panelZoom);
|
this.flowPanelLeft.Controls.Add(this.panelZoom);
|
||||||
|
this.flowPanelLeft.Controls.Add(this.labelTweetDeckSettings);
|
||||||
|
this.flowPanelLeft.Controls.Add(this.checkBestImageQuality);
|
||||||
|
this.flowPanelLeft.Controls.Add(this.checkHideTweetsByNftUsers);
|
||||||
|
this.flowPanelLeft.Controls.Add(this.checkAnimatedAvatars);
|
||||||
this.flowPanelLeft.Controls.Add(this.labelUpdates);
|
this.flowPanelLeft.Controls.Add(this.labelUpdates);
|
||||||
this.flowPanelLeft.Controls.Add(this.checkUpdateNotifications);
|
this.flowPanelLeft.Controls.Add(this.checkUpdateNotifications);
|
||||||
this.flowPanelLeft.Controls.Add(this.btnCheckUpdates);
|
this.flowPanelLeft.Controls.Add(this.btnCheckUpdates);
|
||||||
@@ -249,6 +236,17 @@
|
|||||||
this.flowPanelLeft.TabIndex = 0;
|
this.flowPanelLeft.TabIndex = 0;
|
||||||
this.flowPanelLeft.WrapContents = false;
|
this.flowPanelLeft.WrapContents = false;
|
||||||
//
|
//
|
||||||
|
// labelUI
|
||||||
|
//
|
||||||
|
this.labelUI.AutoSize = true;
|
||||||
|
this.labelUI.Font = new System.Drawing.Font("Segoe UI Semibold", 10.5F, System.Drawing.FontStyle.Bold);
|
||||||
|
this.labelUI.Location = new System.Drawing.Point(0, 0);
|
||||||
|
this.labelUI.Margin = new System.Windows.Forms.Padding(0, 0, 0, 1);
|
||||||
|
this.labelUI.Name = "labelUI";
|
||||||
|
this.labelUI.Size = new System.Drawing.Size(118, 19);
|
||||||
|
this.labelUI.TabIndex = 0;
|
||||||
|
this.labelUI.Text = "USER INTERFACE";
|
||||||
|
//
|
||||||
// checkFocusDmInput
|
// checkFocusDmInput
|
||||||
//
|
//
|
||||||
this.checkFocusDmInput.AutoSize = true;
|
this.checkFocusDmInput.AutoSize = true;
|
||||||
@@ -273,52 +271,40 @@
|
|||||||
this.checkKeepLikeFollowDialogsOpen.Text = "Keep Like/Follow Dialogs Open";
|
this.checkKeepLikeFollowDialogsOpen.Text = "Keep Like/Follow Dialogs Open";
|
||||||
this.checkKeepLikeFollowDialogsOpen.UseVisualStyleBackColor = true;
|
this.checkKeepLikeFollowDialogsOpen.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, 192);
|
|
||||||
this.labelBrowserSettings.Margin = new System.Windows.Forms.Padding(0, 25, 0, 1);
|
|
||||||
this.labelBrowserSettings.Name = "labelBrowserSettings";
|
|
||||||
this.labelBrowserSettings.Size = new System.Drawing.Size(143, 19);
|
|
||||||
this.labelBrowserSettings.TabIndex = 7;
|
|
||||||
this.labelBrowserSettings.Text = "BROWSER SETTINGS";
|
|
||||||
//
|
|
||||||
// checkSmoothScrolling
|
// checkSmoothScrolling
|
||||||
//
|
//
|
||||||
this.checkSmoothScrolling.AutoSize = true;
|
this.checkSmoothScrolling.AutoSize = true;
|
||||||
this.checkSmoothScrolling.Font = new System.Drawing.Font("Segoe UI", 9F);
|
this.checkSmoothScrolling.Font = new System.Drawing.Font("Segoe UI", 9F);
|
||||||
this.checkSmoothScrolling.Location = new System.Drawing.Point(6, 218);
|
this.checkSmoothScrolling.Location = new System.Drawing.Point(6, 122);
|
||||||
this.checkSmoothScrolling.Margin = new System.Windows.Forms.Padding(6, 6, 3, 2);
|
this.checkSmoothScrolling.Margin = new System.Windows.Forms.Padding(6, 3, 3, 2);
|
||||||
this.checkSmoothScrolling.Name = "checkSmoothScrolling";
|
this.checkSmoothScrolling.Name = "checkSmoothScrolling";
|
||||||
this.checkSmoothScrolling.Size = new System.Drawing.Size(117, 19);
|
this.checkSmoothScrolling.Size = new System.Drawing.Size(117, 19);
|
||||||
this.checkSmoothScrolling.TabIndex = 8;
|
this.checkSmoothScrolling.TabIndex = 5;
|
||||||
this.checkSmoothScrolling.Text = "Smooth Scrolling";
|
this.checkSmoothScrolling.Text = "Smooth Scrolling";
|
||||||
this.checkSmoothScrolling.UseVisualStyleBackColor = true;
|
this.checkSmoothScrolling.UseVisualStyleBackColor = true;
|
||||||
//
|
//
|
||||||
// checkTouchAdjustment
|
// labelTweetDeckSettings
|
||||||
//
|
//
|
||||||
this.checkTouchAdjustment.AutoSize = true;
|
this.labelTweetDeckSettings.AutoSize = true;
|
||||||
this.checkTouchAdjustment.Font = new System.Drawing.Font("Segoe UI", 9F);
|
this.labelTweetDeckSettings.Font = new System.Drawing.Font("Segoe UI Semibold", 10.5F, System.Drawing.FontStyle.Bold);
|
||||||
this.checkTouchAdjustment.Location = new System.Drawing.Point(6, 242);
|
this.labelTweetDeckSettings.Location = new System.Drawing.Point(0, 233);
|
||||||
this.checkTouchAdjustment.Margin = new System.Windows.Forms.Padding(6, 3, 3, 2);
|
this.labelTweetDeckSettings.Margin = new System.Windows.Forms.Padding(0, 27, 0, 1);
|
||||||
this.checkTouchAdjustment.Name = "checkTouchAdjustment";
|
this.labelTweetDeckSettings.Name = "labelTweetDeckSettings";
|
||||||
this.checkTouchAdjustment.Size = new System.Drawing.Size(163, 19);
|
this.labelTweetDeckSettings.Size = new System.Drawing.Size(67, 19);
|
||||||
this.checkTouchAdjustment.TabIndex = 9;
|
this.labelTweetDeckSettings.TabIndex = 8;
|
||||||
this.checkTouchAdjustment.Text = "Touch Screen Adjustment";
|
this.labelTweetDeckSettings.Text = "TWITTER";
|
||||||
this.checkTouchAdjustment.UseVisualStyleBackColor = true;
|
|
||||||
//
|
//
|
||||||
// checkHardwareAcceleration
|
// checkHideTweetsByNftUsers
|
||||||
//
|
//
|
||||||
this.checkHardwareAcceleration.AutoSize = true;
|
this.checkHideTweetsByNftUsers.AutoSize = true;
|
||||||
this.checkHardwareAcceleration.Font = new System.Drawing.Font("Segoe UI", 9F);
|
this.checkHideTweetsByNftUsers.Font = new System.Drawing.Font("Segoe UI", 9F);
|
||||||
this.checkHardwareAcceleration.Location = new System.Drawing.Point(6, 266);
|
this.checkHideTweetsByNftUsers.Location = new System.Drawing.Point(6, 283);
|
||||||
this.checkHardwareAcceleration.Margin = new System.Windows.Forms.Padding(6, 3, 3, 2);
|
this.checkHideTweetsByNftUsers.Margin = new System.Windows.Forms.Padding(6, 3, 3, 2);
|
||||||
this.checkHardwareAcceleration.Name = "checkHardwareAcceleration";
|
this.checkHideTweetsByNftUsers.Name = "checkHideTweetsByNftUsers";
|
||||||
this.checkHardwareAcceleration.Size = new System.Drawing.Size(146, 19);
|
this.checkHideTweetsByNftUsers.Size = new System.Drawing.Size(231, 19);
|
||||||
this.checkHardwareAcceleration.TabIndex = 10;
|
this.checkHideTweetsByNftUsers.TabIndex = 10;
|
||||||
this.checkHardwareAcceleration.Text = "Hardware Acceleration";
|
this.checkHideTweetsByNftUsers.Text = "Hide Tweets by Users with NFT Avatars";
|
||||||
this.checkHardwareAcceleration.UseVisualStyleBackColor = true;
|
this.checkHideTweetsByNftUsers.UseVisualStyleBackColor = true;
|
||||||
//
|
//
|
||||||
// labelBrowserPath
|
// labelBrowserPath
|
||||||
//
|
//
|
||||||
@@ -387,7 +373,7 @@
|
|||||||
this.flowPanelRight.Location = new System.Drawing.Point(322, 9);
|
this.flowPanelRight.Location = new System.Drawing.Point(322, 9);
|
||||||
this.flowPanelRight.Name = "flowPanelRight";
|
this.flowPanelRight.Name = "flowPanelRight";
|
||||||
this.flowPanelRight.Size = new System.Drawing.Size(300, 462);
|
this.flowPanelRight.Size = new System.Drawing.Size(300, 462);
|
||||||
this.flowPanelRight.TabIndex = 1;
|
this.flowPanelRight.TabIndex = 2;
|
||||||
this.flowPanelRight.WrapContents = false;
|
this.flowPanelRight.WrapContents = false;
|
||||||
//
|
//
|
||||||
// labelLocales
|
// labelLocales
|
||||||
@@ -569,7 +555,7 @@
|
|||||||
this.panelSeparator.Margin = new System.Windows.Forms.Padding(0, 0, 6, 0);
|
this.panelSeparator.Margin = new System.Windows.Forms.Padding(0, 0, 6, 0);
|
||||||
this.panelSeparator.Name = "panelSeparator";
|
this.panelSeparator.Name = "panelSeparator";
|
||||||
this.panelSeparator.Size = new System.Drawing.Size(1, 480);
|
this.panelSeparator.Size = new System.Drawing.Size(1, 480);
|
||||||
this.panelSeparator.TabIndex = 2;
|
this.panelSeparator.TabIndex = 1;
|
||||||
//
|
//
|
||||||
// TabSettingsGeneral
|
// TabSettingsGeneral
|
||||||
//
|
//
|
||||||
@@ -604,7 +590,6 @@
|
|||||||
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.Label labelUI;
|
|
||||||
private System.Windows.Forms.Panel panelZoom;
|
private System.Windows.Forms.Panel panelZoom;
|
||||||
private System.Windows.Forms.Label labelUpdates;
|
private System.Windows.Forms.Label labelUpdates;
|
||||||
private System.Windows.Forms.CheckBox checkBestImageQuality;
|
private System.Windows.Forms.CheckBox checkBestImageQuality;
|
||||||
@@ -614,11 +599,9 @@
|
|||||||
private System.Windows.Forms.CheckBox checkKeepLikeFollowDialogsOpen;
|
private System.Windows.Forms.CheckBox checkKeepLikeFollowDialogsOpen;
|
||||||
private System.Windows.Forms.Label labelBrowserPath;
|
private System.Windows.Forms.Label labelBrowserPath;
|
||||||
private System.Windows.Forms.ComboBox comboBoxCustomBrowser;
|
private System.Windows.Forms.ComboBox comboBoxCustomBrowser;
|
||||||
private System.Windows.Forms.Label labelBrowserSettings;
|
|
||||||
private System.Windows.Forms.CheckBox checkSmoothScrolling;
|
private System.Windows.Forms.CheckBox checkSmoothScrolling;
|
||||||
private System.Windows.Forms.Label labelSearchEngine;
|
private System.Windows.Forms.Label labelSearchEngine;
|
||||||
private System.Windows.Forms.ComboBox comboBoxSearchEngine;
|
private System.Windows.Forms.ComboBox comboBoxSearchEngine;
|
||||||
private System.Windows.Forms.CheckBox checkTouchAdjustment;
|
|
||||||
private System.Windows.Forms.FlowLayoutPanel flowPanelRight;
|
private System.Windows.Forms.FlowLayoutPanel flowPanelRight;
|
||||||
private System.Windows.Forms.Panel panelSeparator;
|
private System.Windows.Forms.Panel panelSeparator;
|
||||||
private System.Windows.Forms.Label labelLocales;
|
private System.Windows.Forms.Label labelLocales;
|
||||||
@@ -627,7 +610,6 @@
|
|||||||
private System.Windows.Forms.ComboBox comboBoxSpellCheckLanguage;
|
private System.Windows.Forms.ComboBox comboBoxSpellCheckLanguage;
|
||||||
private System.Windows.Forms.Label labelTranslationTarget;
|
private System.Windows.Forms.Label labelTranslationTarget;
|
||||||
private System.Windows.Forms.ComboBox comboBoxTranslationTarget;
|
private System.Windows.Forms.ComboBox comboBoxTranslationTarget;
|
||||||
private System.Windows.Forms.CheckBox checkHardwareAcceleration;
|
|
||||||
private System.Windows.Forms.CheckBox checkFocusDmInput;
|
private System.Windows.Forms.CheckBox checkFocusDmInput;
|
||||||
private System.Windows.Forms.Panel panelCustomBrowser;
|
private System.Windows.Forms.Panel panelCustomBrowser;
|
||||||
private System.Windows.Forms.Button btnCustomBrowserChange;
|
private System.Windows.Forms.Button btnCustomBrowserChange;
|
||||||
@@ -638,5 +620,8 @@
|
|||||||
private System.Windows.Forms.Label labelExternalApplications;
|
private System.Windows.Forms.Label labelExternalApplications;
|
||||||
private System.Windows.Forms.Label labelFirstDayOfWeek;
|
private System.Windows.Forms.Label labelFirstDayOfWeek;
|
||||||
private System.Windows.Forms.ComboBox comboBoxFirstDayOfWeek;
|
private System.Windows.Forms.ComboBox comboBoxFirstDayOfWeek;
|
||||||
|
private System.Windows.Forms.Label labelUI;
|
||||||
|
private System.Windows.Forms.CheckBox checkHideTweetsByNftUsers;
|
||||||
|
private System.Windows.Forms.Label labelTweetDeckSettings;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user