mirror of
https://github.com/chylex/TweetDuck.git
synced 2025-12-13 06:28:01 +01:00
Compare commits
1059 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| f832e04e9e | |||
| fc760b9a0c | |||
| 9addff0521 | |||
| dcaa3aab19 | |||
| 628785c68c | |||
| a5aa396fda | |||
| f53a9f05e3 | |||
| 7749b14156 | |||
| c15f339718 | |||
| 775f590bfa | |||
| 76408ea56f | |||
| a391d8ee83 | |||
| 48c38f6e1d | |||
| 37c5fba162 | |||
| 23e99b1d44 | |||
| 8432240a47 | |||
| a4bab743d6 | |||
| 60766789ab | |||
| ca014f881c | |||
| 886eabe26c | |||
| 65b7167b5f | |||
| abbdde851e | |||
| 54ac54aba6 | |||
| 184340f400 | |||
| 93dd6813e8 | |||
| b689b08711 | |||
| 1479a097d6 | |||
| e4967ea46d | |||
| 3f28f18fb4 | |||
| 1b90e0f65e | |||
| 756ed649e6 | |||
| fbc423e2a7 | |||
| f04cdb6a13 | |||
| 63b58b1cfe | |||
| 77e656d8e4 | |||
| a673957bd0 | |||
| c99a0c9974 | |||
| 0fb06d0ff2 | |||
| c51eebfe22 | |||
| a51b34b48f | |||
| 1b239bada1 | |||
| 50ab1a6ac3 | |||
| f181f1fadc | |||
| c686349922 | |||
| 5f44a1f4ad | |||
| a968938832 | |||
| 8d67f3dfdc | |||
| 973ae8cb5d | |||
| a4747b0d7b | |||
| f07640cc84 | |||
| c235c55b19 | |||
| 485ef684be | |||
| 7caca22e57 | |||
| f1d9e32bf5 | |||
| 23d5fa3107 | |||
| 4e7d8aba1c | |||
| 98ba871a71 | |||
| 3ff23c0264 | |||
| e21f89477b | |||
| f177f514f5 | |||
| af30f3b348 | |||
| 82df618429 | |||
| bb3538e270 | |||
| 71925e1126 | |||
| 93c1cbd231 | |||
| 894b890fe5 | |||
| 8e9e8f7fad | |||
| 2a0461a76f | |||
| 85f923a6fc | |||
| b35e4d4d01 | |||
| cb24a859f4 | |||
| b1ef00746f | |||
| aebe82e3a7 | |||
| 7c87856b4d | |||
| d1b1dd539f | |||
| 55eea88ace | |||
| a70f64e1f6 | |||
| fa0cb120a7 | |||
| e3080d07dc | |||
| 34726c533e | |||
| 4a0d72d2cc | |||
| fe3fc5c9f7 | |||
| 441228e2b0 | |||
| 7538aee4f2 | |||
| acf809268e | |||
| 4ebc0c10b6 | |||
| a453888ca2 | |||
| 530b44762b | |||
| f85587fb0b | |||
| edb8799b1a | |||
| e47aeb37f0 | |||
| 776e9968dc | |||
| 1898bf4731 | |||
| 78df020737 | |||
| b93f9a4b9a | |||
| 748b230ef5 | |||
| deb8dde9e1 | |||
| dbb2f10754 | |||
| 0ded03ab92 | |||
| 2198e84f3b | |||
| 14d44528b0 | |||
| eb8159ca0f | |||
| 9811f40a53 | |||
| 8de7e13aa3 | |||
| c63e6a1e49 | |||
| 5a21d2cb10 | |||
| 424c0e596c | |||
| d431b63c27 | |||
| 38c2781cd3 | |||
| 796fb348a3 | |||
| 71b306d5fd | |||
| 4c610ea32d | |||
| 4bff006743 | |||
| 1645079bc0 | |||
| 9afb58e4a7 | |||
| 2820fc8acf | |||
| 4d77a498f6 | |||
| d77de3bb12 | |||
| 29e7ad6ce6 | |||
| 1712b5120e | |||
| 06c0153cf5 | |||
| 44f7ecda6d | |||
| fb94bf1b80 | |||
| 4818652582 | |||
| c69b9784fc | |||
| 0ac244a3ea | |||
| 19a445fdab | |||
| c90a18a2c0 | |||
| 502310c413 | |||
| 6f9424d4ec | |||
| bb379fe667 | |||
| 0fd86bf214 | |||
| 29b75d4391 | |||
| a7124e5449 | |||
| a714f3480a | |||
| c10e0df898 | |||
| fba734fd5a | |||
| 27e2372097 | |||
| 7f5b99495c | |||
| 1efe2a56af | |||
| 850873aec8 | |||
| d9e6afbf36 | |||
| 7f3bd2715c | |||
| c81cb393e9 | |||
| 4800faa783 | |||
| 1087b5e1d1 | |||
| 5dc2e71976 | |||
| 28eb7d0810 | |||
| c641a92d89 | |||
| 3e57cc045f | |||
| c60a8ddf66 | |||
| 8becef3e45 | |||
| 3237634e3b | |||
| 2a4a659e39 | |||
| fcaa47c0a8 | |||
| 68ea17ccbd | |||
| 80308c7102 | |||
| 6f4a99a7cb | |||
| ac245f5128 | |||
| 7f9e9e27a0 | |||
| abf58a4aec | |||
| 5d9a700a6e | |||
| 3662b1eb1d | |||
| 34449da2b8 | |||
| 42f367f822 | |||
| 781ca0bb77 | |||
| ebe5d50dae | |||
| 00d6dc5626 | |||
| a1648c307f | |||
| b8f170ae39 | |||
| 073f1da5b4 | |||
| 6310711136 | |||
| fcac7a4ce1 | |||
| c2b1aef810 | |||
| c8ab26275c | |||
| a1fd6a2b6b | |||
| 561c08e0cc | |||
| 4658e30e89 | |||
| 225e6b369a | |||
| 0e9094a19f | |||
| 2da0e03c6c | |||
| 9a6fac5fc8 | |||
| b541f0a896 | |||
| cec7cce077 | |||
| fb13695ca5 | |||
| 20c76d06f7 | |||
| 339a11f649 | |||
| 0989400d87 | |||
| 52aacf602d | |||
| 54d70a6a17 | |||
| d980e09e0f | |||
| 2e4cb12817 | |||
| 7b91cb2e96 | |||
| 95c04a8abc | |||
| 25822fefdb | |||
| d800ee2d28 | |||
| 2a51371aca | |||
| ee5d1a47dc | |||
| b330b74347 | |||
| 11fa13f0bb | |||
| 21400d72b3 | |||
| a710cb9d4f | |||
| 3326ad52ce | |||
| c9560df851 | |||
| 74cb45118e | |||
| c79bf19e51 | |||
| 961bec0a2f | |||
| 89e4977cd1 | |||
| bfe16475db | |||
| 915d36867c | |||
| 48435af407 | |||
| 86b6ec5212 | |||
| 775e70bc45 | |||
| 9f565447d0 | |||
| 88d27bc29d | |||
| 172ae87ac6 | |||
| 91d572235e | |||
| 64d32dcb75 | |||
| 564b4283b6 | |||
| ca4d374a81 | |||
| a753806d7b | |||
| bd1692cea3 | |||
| b7ce089f08 | |||
| 8a6b47c5db | |||
| 9f1fc4df18 | |||
| c018a2a7bc | |||
| a1aebab114 | |||
| e30702e1d8 | |||
| 008ff4b055 | |||
| d7bba22e19 | |||
| 2b9a910533 | |||
| 118ebcc627 | |||
| c741767b11 | |||
| 4a09358e14 | |||
| 3f4ea1af08 | |||
| 35bb196832 | |||
| cb5b50dd42 | |||
| 8652272526 | |||
| 0f32504fde | |||
| 4735c21fc0 | |||
| ecbcbcaed4 | |||
| 1677b73ff8 | |||
| 5929067a3d | |||
| d06834617b | |||
| 9d048efe06 | |||
| 6a379bc2cd | |||
| 9f415b11b5 | |||
| b9b9193222 | |||
| 867c2d1632 | |||
| 5447afc3f5 | |||
| b5e58db242 | |||
| 8ab99619d6 | |||
| 4c7660ee65 | |||
| c1b9bde7b0 | |||
| 0e8c6c066f | |||
| 9e44a86be0 | |||
| b61479f84f | |||
| e3c709b005 | |||
| b2b3dba504 | |||
| 4d05441aa8 | |||
| 419b3ee850 | |||
| 4c31e72d29 | |||
| e3b2ff7f0e | |||
| 4c5f5e2cce | |||
| 39ae9b8ba0 | |||
| 5c7eb0535d | |||
| 235718390b | |||
| 5d4b72f224 | |||
| dc76ae9d1f | |||
| e44f4bb003 | |||
| 1fc1370d41 | |||
| 80a669c989 | |||
| 801c9eba2d | |||
| f9704d2836 | |||
| 39687171e9 | |||
| 1d73691ef4 | |||
| f8678d2515 | |||
| fb108ea18d | |||
| a7229a0677 | |||
| d0dd112b98 | |||
| 1e07120eb5 | |||
| fcd1f76cff | |||
| e400d86d75 | |||
| dca3410a5b | |||
| 9b314e2953 | |||
| 5635daf66d | |||
| 7e2e1645e9 | |||
| 4990afcdbb | |||
| c11f36dfef | |||
| abddf61c88 | |||
| 37fec7e952 | |||
| 0f6a93ae8f | |||
| 25eae334b0 | |||
| 74377d01ce | |||
| 6e78ba1e7b | |||
| 39e0dedf27 | |||
| bbe2c88802 | |||
| 586b31b63e | |||
| 041abe6d7e | |||
| a69b3cd05f | |||
| b48213e79e | |||
| 5bbc14aca5 | |||
| 8ccbf502e8 | |||
| c426ca97e2 | |||
| d9eef86a8b | |||
| 3fed921748 | |||
| 02827d53a2 | |||
| 1ad5fde9ae | |||
| 909d5ed99c | |||
| b9096df218 | |||
| 1137485c55 | |||
| 61b1155a03 | |||
| 35624bcb1c | |||
| 6e262334ed | |||
| 829d69485a | |||
| 0d32c168eb | |||
| 38d6d93f65 | |||
| 9a280492c2 | |||
| d49ee79c90 | |||
| 73b83af6b1 | |||
| 064673ef23 | |||
| 81bf93e5ab | |||
| 26d5a8ce08 | |||
| c6f5c8d91f | |||
| 63a1928468 | |||
| 27c2aee8b9 | |||
| 5219d29aca | |||
| 84955352dd | |||
| 8e05c30063 | |||
| 6f98bcafec | |||
| 4afac91bce | |||
| 6e6312f6d7 | |||
| df4c4e443d | |||
| ff40474f92 | |||
| aca06ee805 | |||
| ba8e29a9f8 | |||
| 583da2bd9f | |||
| 0ea07016b4 | |||
| 616421db9a | |||
| 293ddacd19 | |||
| 13945ec937 | |||
| 4ea6f336f8 | |||
| 58296aa266 | |||
| 742df9dff3 | |||
| 011e1f5922 | |||
| 8f67d69325 | |||
| 9ac133b605 | |||
| 538b2d26cd | |||
| cc3895c423 | |||
| 79454bfc3b | |||
| 734c7572bb | |||
| 9f93fbb161 | |||
| c78c63285e | |||
| c8cbf70a28 | |||
| 2b116d6756 | |||
| da611153cf | |||
| fd9bf4468a | |||
| fa234eb9d6 | |||
| dbfebf6a32 | |||
| 7b91e31485 | |||
| e882fc8b5e | |||
| 5a54195cac | |||
| a442adf8d5 | |||
| 38466878db | |||
| 7c86e4e743 | |||
| 41cbfb8d39 | |||
| 7c394f4b20 | |||
| c1a35e1053 | |||
| cddce8596f | |||
| c75058b1da | |||
| 1a73fcdb39 | |||
| 8e0c4f5308 | |||
| 51e2791cc7 | |||
| 130159f06c | |||
| 42d1140b55 | |||
| dfd987041a | |||
| 790d1787fd | |||
| 2a6a607c7b | |||
| b3521d2a18 | |||
| dee99caa7d | |||
| cf525a3929 | |||
| 18d658f7e1 | |||
| 1c42ab77d8 | |||
| 33d5638bb0 | |||
| 8ce92df87a | |||
| 80654449af | |||
| eee1622801 | |||
| 4c54876ecf | |||
| 1cbcd5c2da | |||
| 55253e284e | |||
| e9795cd697 | |||
| be76d9a6dc | |||
| d7cdaf2870 | |||
| 48ed0e01d1 | |||
| dca31dedde | |||
| ab7356b991 | |||
| a46a673cf8 | |||
| c8d52539ca | |||
| ed9267b6ba | |||
| b7c02d1cf8 | |||
| fb66beb29f | |||
| 8c3bf6bbc3 | |||
| b943078132 | |||
| e727617bf1 | |||
| ffaea6dcbe | |||
| bf1f72a2a4 | |||
| be0df7c5b0 | |||
| 5ab769e74d | |||
| d22ddb1731 | |||
| 9fed8c022b | |||
| a315ed90af | |||
| 1ebf3c9af2 | |||
| 0e4c923c23 | |||
| 63835b9f99 | |||
| ff17f7c132 | |||
| f4631c9b38 | |||
| 35931023ae | |||
| 6d93381760 | |||
| f1bdd5f1b2 | |||
| 1c3e2fbad7 | |||
| 29a02db07d | |||
| f1db1ba708 | |||
| c1420bac88 | |||
| 8e527fbbdf | |||
| 5ec1bcfe3f | |||
| 7226461cd0 | |||
| 6d6f383c92 | |||
| e1a6328d09 | |||
| 6e4153911a | |||
| 342f74646e | |||
| fe5191d3b5 | |||
| 504cf97c6c | |||
| f8c494c9c1 | |||
| b90d7f721a | |||
| 7936af6c9a | |||
| 52d01e3dd7 | |||
| d30d70395a | |||
| 491a3ae525 | |||
| 1eae380b08 | |||
| f091b2526e | |||
| 7548e2e202 | |||
| d9b9afbf2d | |||
| 8036659003 | |||
| f9fb4668c2 | |||
| 7047924947 | |||
| 8f6be3911a | |||
| 0d95b8eb44 | |||
| 61d2d124ff | |||
| 7b218b2544 | |||
| 87ac7daf76 | |||
| 6b4817df36 | |||
| 22d99da2e1 | |||
| 47b6cf7068 | |||
| 606c9512f8 | |||
| aef9c591e9 | |||
| 71f67e9191 | |||
| 636f2b3017 | |||
| 2de5b5c6e4 | |||
| 0cbcc8c9f3 | |||
| 96146e3dc8 | |||
| 5aaae51be1 | |||
| b98625fdbc | |||
| 09a748e9dc | |||
| 87b07c6d5b | |||
| f39e668f8d | |||
| 6ea95342a0 | |||
| c594bf5757 | |||
| cd3b198c6f | |||
| b249b5f46e | |||
| bbe3b48bcc | |||
| 3bcd056197 | |||
| 6387ab41b3 | |||
| 4df16b7f15 | |||
| ed387a2873 | |||
| 9e225530a6 | |||
| 7b23686dc6 | |||
| 4de31453fd | |||
| 4c59526e39 | |||
| 9ec1764194 | |||
| 47afa32902 | |||
| 2a09487b55 | |||
| 563c856dd3 | |||
| 69ea242408 | |||
| d6e0e0726f | |||
| 73d460d40a | |||
| 1f27d96ac9 | |||
| 93e9f28d69 | |||
| ec2e26752a | |||
| fadd95f3e6 | |||
| 00acc677e6 | |||
| 1a799881e8 | |||
| f75677593a | |||
| 19e3bd19f0 | |||
| 85701b0a3c | |||
| 014cb18dcb | |||
| e71e1c853f | |||
| ee9d9196f5 | |||
| 53c8272e01 | |||
| 7f7b6b1e2a | |||
| 405777e0f5 | |||
| df2b624cb5 | |||
| 8a48d5c2f9 | |||
| c55ee71442 | |||
| 3f82745f5b | |||
| 404187a1ae | |||
| 2b7b3f586b | |||
| 04959a3493 | |||
| 97cf4932ae | |||
| b0d88a0a37 | |||
| 67a2e40622 | |||
| 3a28556c7f | |||
| 9ecc92b9a5 | |||
| ca023be98a | |||
| 11a1423f76 | |||
| 79f6df121b | |||
| 71eade7e86 | |||
| 5f81d29036 | |||
| ec1cb5dc5f | |||
| fd969e2d55 | |||
| 37e33b77ff | |||
| f7ed7703b4 | |||
| 4bb35295ca | |||
| 1e4f673f9e | |||
| 7cadb1c403 | |||
| 37148f5093 | |||
| f6bc26789f | |||
| b3f5a88525 | |||
| 1e538d2b28 | |||
| 7d7bfb7b01 | |||
| 41d86ba440 | |||
| 3df474a8a5 | |||
| a50d6e8f47 | |||
| 6081e5b9c1 | |||
| 66ccea920c | |||
| 470d63093f | |||
| eae0507831 | |||
| 92af85d3bb | |||
| 7635af5730 | |||
| a838e89695 | |||
| b22289a8b9 | |||
| 45b3ff52c6 | |||
| 4464991f4c | |||
| b0d2f77583 | |||
| b211a4405d | |||
| 8823016d2c | |||
| 859fdc7ec1 | |||
| 028d5ed01f | |||
| 5fd5a2a436 | |||
| 79a7e7470c | |||
| 9ecef78aed | |||
| 65a837a6e1 | |||
| 6e4db4acea | |||
| 26fb977d05 | |||
| b42cd1c048 | |||
| 467f7cd12f | |||
| 66699ce9df | |||
| cf7d903932 | |||
| a7ab67925c | |||
| a474ba4260 | |||
| 09e5636e86 | |||
| 2295a875be | |||
| 82a2455afc | |||
| 268de676ee | |||
| 8fe26c07f1 | |||
| da3921b1ca | |||
| 4dd2e787d1 | |||
| ce005ae6c2 | |||
| 1513f46a11 | |||
| 7543eeb0f4 | |||
| 873242120c | |||
| 98f8095a65 | |||
| 785571a550 | |||
| 0c4bd4044e | |||
| 0319543dce | |||
| 82d70b2d7f | |||
| 62d18e010a | |||
| fc77b85083 | |||
| 50a8893f4f | |||
| 9252b3040e | |||
| d5141ed020 | |||
| 7ff9e23283 | |||
| 89854d527c | |||
| 6ff0cad2a8 | |||
| 349cfbd2d5 | |||
| 40303ef74a | |||
| 6c652122c2 | |||
| 3658e3a2aa | |||
| 2b20fcfcd1 | |||
| 554d427fef | |||
| 7cf5b23306 | |||
| b26a6098eb | |||
| 7ad927bdaf | |||
| 4ed30b3619 | |||
| edfa9264d5 | |||
| f7516b593f | |||
| 83ff998f9d | |||
| 47381e0df4 | |||
| ba62d57485 | |||
| c014c4bc24 | |||
| 5d1a3fede2 | |||
| 53b584fe45 | |||
| f53d974400 | |||
| c4b4ef19cd | |||
| 3bfc360362 | |||
| 584f16d375 | |||
| b3d84c3217 | |||
| dd14ad470e | |||
| 85b90574b8 | |||
| ee5d172468 | |||
| 7ca4b94361 | |||
| 31f1546483 | |||
| d8a88a19af | |||
| 12af79de05 | |||
| 2260dd419d | |||
| 61a940cc82 | |||
| 1bbc1e0d7e | |||
| 921294eeb3 | |||
| baaa90f49d | |||
| 4e25381770 | |||
| 272877d0ed | |||
| 555b947bf7 | |||
| da29811b16 | |||
| 241f67fd4d | |||
| eb4ce18e31 | |||
| ae99fee440 | |||
| d116ac5e56 | |||
| 28db1f4253 | |||
| 034312e676 | |||
| da83d73ba6 | |||
| 02e8dc3440 | |||
| cac6d1f889 | |||
| 68fa3294d4 | |||
| 9b983de8c9 | |||
| 3a37ee719b | |||
| 61359c2faa | |||
| 7f7c5ab35b | |||
| a1b483d20a | |||
| 04cd662d78 | |||
| da597f076f | |||
| fab3efdcf5 | |||
| a55509a34d | |||
| 84fb1c5b2b | |||
| 391a90e1df | |||
| e0fe39195d | |||
| 385fead81a | |||
| 648d1b9aa9 | |||
| 3f0028913d | |||
| 45e6ec8b0f | |||
| a3fbaa0b34 | |||
| 7102cbfb3b | |||
| c3db3ce0f2 | |||
| 7a1e7637ff | |||
| 04a78a02d3 | |||
| cb61dc742f | |||
| cd53f6e757 | |||
| c64f7daa8d | |||
| e70d792654 | |||
| 9ae533f907 | |||
| cfe92f18e3 | |||
| e2a34ea28e | |||
| ec8000360e | |||
| 57b0821e19 | |||
| 09d39df15a | |||
| 1f9db3bda6 | |||
| b7104c8828 | |||
| 5da02b4092 | |||
| 802f1e3042 | |||
| 66db0df45a | |||
| 650c2e2eb7 | |||
| 6ab3754129 | |||
| 7dca0a8cab | |||
| 7cd0b4ad54 | |||
| 97acb41eee | |||
| b916b9726e | |||
| 32d3990ace | |||
| cb1fd109cc | |||
| 0e68dd6185 | |||
| fb6502bc65 | |||
| c7e7403781 | |||
| bf224408a3 | |||
| 84b7078873 | |||
| 89e5943d8f | |||
| b78c4cb8f0 | |||
| 976ba074a8 | |||
| 5205d59b96 | |||
| e8394b9c08 | |||
| 9cd00239f9 | |||
| b6b26142f8 | |||
| 4ee99376fd | |||
| b0261342ff | |||
| 87fd2a521e | |||
| 334793c6f6 | |||
| 3e70d991bb | |||
| feec96fc5c | |||
| 765984709e | |||
| c7c9931f68 | |||
| ae64573510 | |||
| d675af5aa4 | |||
| 9480d17cfc | |||
| 5ac1df2283 | |||
| 20119db883 | |||
| a4006deb8c | |||
| 25fa3cefab | |||
| bb5161eb34 | |||
| 1bfc403a98 | |||
| 720d10e543 | |||
| 30c117672e | |||
| 6d1b5c77d1 | |||
| d1cbf608e0 | |||
| 7e3014c52d | |||
| 82beb1f5a7 | |||
| 657dc81300 | |||
| 8e22192dd3 | |||
| dc0b7d58e3 | |||
| 6919e5bdb0 | |||
| 9728a62efa | |||
| 276e070759 | |||
| fadea54f8d | |||
| 523d340ade | |||
| 96fa7efb66 | |||
| 03591f8317 | |||
| 28cc60d007 | |||
| 1fa69bdb3b | |||
| 11f5f9b72e | |||
| 61f6543041 | |||
| 0c9ab32f37 | |||
| fde984d02b | |||
| f23db31306 | |||
| 8dce99b8b3 | |||
| 342ac51cda | |||
| ba31f7ae01 | |||
| 8d0fa030f8 | |||
| d030a79c81 | |||
| 6690efc4d9 | |||
| afa8098463 | |||
| c064e579d2 | |||
| 01dc4e4714 | |||
| 6fbc246b12 | |||
| 1efe2a02f7 | |||
| ab2ab06f60 | |||
| a71d889682 | |||
| 2252d85b27 | |||
| 3f09100177 | |||
| 6b79c89f42 | |||
| 5f249d4603 | |||
| fa64309909 | |||
| c46aafdab6 | |||
| 3e9c397494 | |||
| 47935165db | |||
| be77f753e7 | |||
| 2c30613279 | |||
| d83eaec987 | |||
| e6f199a224 | |||
| 6636a2aa9e | |||
| 221bdc58fe | |||
| e48a068e9d | |||
| 3371c31e63 | |||
| aa2c60f7e9 | |||
| f7dc200684 | |||
| ad306c56c7 | |||
| 86aba1eb52 | |||
| 826f1aba7a | |||
| 8abf4364c6 | |||
| 4c45d91d4e | |||
| 3176b6cb8f | |||
| 27971e09cd | |||
| bf95ae00de | |||
| 0dbfa7e101 | |||
| 85d09c4b5e | |||
| 4f9bc40476 | |||
| 757ccbf9d3 | |||
| 4cf9730130 | |||
| 1dd0d70ab9 | |||
| 340eaece0f | |||
| c151e7cd37 | |||
| ca0baae832 | |||
| 478e6ed8df | |||
| 7388eb07ca | |||
| c38d507e50 | |||
| 5aee087a57 | |||
| 0cda3702ea | |||
| ce55226d0c | |||
| 0bab0a9963 | |||
| 34955b7083 | |||
| ba6ce072ac | |||
| f39fd00697 | |||
| 58fc1be1d5 | |||
| 1fdf9bffb6 | |||
| 2ad179ef8e | |||
| d42cc5b762 | |||
| 403658f622 | |||
| 6ca35685db | |||
| bfc6822f69 | |||
| b0386937d7 | |||
| 9436540b2f | |||
| 45b0ece342 | |||
| 5c147d3648 | |||
| 8fa68c428f | |||
| e2be90191e | |||
| 339da2f1a9 | |||
| b2cc5d50bd | |||
| f38b188046 | |||
| 9e45628e87 | |||
| bf76398627 | |||
| 81d5728964 | |||
| d76027558b | |||
| 1450cc24a3 | |||
| f41523c1b2 | |||
| 4019463e68 | |||
| 5e2e239f5e | |||
| bc7856b6c0 | |||
| e2bba8d9e1 | |||
| 520db2c32e | |||
| da71f2de2b | |||
| 6dd2c6678b | |||
| fb3d9e6d6b | |||
| 36473c2df9 | |||
| 81aa30b2ec | |||
| 85d5160782 | |||
| 44bf7b870e | |||
| 44da2e6082 | |||
| d576bc3972 | |||
| dbeb4c7205 | |||
| e5223a852e | |||
| f3884315c0 | |||
| 53cd9dc9a6 | |||
| a3666a7ab2 | |||
| ca4eb17308 | |||
| b729dca2e5 | |||
| 21354e675a | |||
| 2085ddd347 | |||
| 31a475861b | |||
| 45bdd95dc8 | |||
| 569fdec380 | |||
| 3f15ff1c06 | |||
| 506cd52255 | |||
| 300c0c6195 | |||
| 7689fe97b0 | |||
| 99ed077dbc | |||
| 65aeb6656f | |||
| e4f5766ffb | |||
| 353ac7c76b | |||
| 8073fa206b | |||
| 1a1cfa2220 | |||
| 5e93d866ad | |||
| f29e03e250 | |||
| 3775b5968d | |||
| ba6242e09d | |||
| f6b0ddddb9 | |||
| 9e8d5c6768 | |||
| ef78496d5d | |||
| 41a45a14df | |||
| 5d3721ad04 | |||
| f75bcb505c | |||
| fa365794a0 | |||
| a747ab700e | |||
| b51b017005 | |||
| b9e1dd5950 | |||
| 56bf33229b | |||
| 5740dd8c8a | |||
| d3f205287c | |||
| 53518cd6e6 | |||
| 0ff3896d51 | |||
| c64e16471b | |||
| 2f2e2b82b8 | |||
| af9a503f3c | |||
| 971affa607 | |||
| 2de5d6206e | |||
| 34e0bcc56a | |||
| bb9f09c11f | |||
| 3f5cc24a10 | |||
| 109a330c54 | |||
| 3e4cd3c92f | |||
| c6aaa4fb04 | |||
| 2de9570c38 | |||
| 3d88f57f8a | |||
| 23606f6d6c | |||
| 5a1ba1b0dc | |||
| ced5a82e07 | |||
| b4fc522f37 | |||
| a7e222f2e7 | |||
| 511e5c483c | |||
| a28fddbc4d | |||
| 780908f777 | |||
| 88e5681155 | |||
| bc197e6942 | |||
| afbfea6d43 | |||
| 662ee7382c | |||
| 12144a2bda | |||
| e11f2e54b4 | |||
| 01cb4e32eb | |||
| 1ca3541b34 | |||
| e209085960 | |||
| d1a90612c2 | |||
| 0a21c61535 | |||
| 8583a55424 | |||
| 3a7a0f63de | |||
| 2e13d08018 | |||
| f13515ba16 | |||
| 6f1884451b | |||
| d9321a9acb | |||
| 19f9614c74 | |||
| 66ce355571 | |||
| 5108649ec6 | |||
| 9308478a59 | |||
| 97d778c31c | |||
| 740195146b | |||
| 6e0717bf22 | |||
| b6a683dfe1 | |||
| dc78c68f12 | |||
| 8e01d5ec84 | |||
| b531016c7b | |||
| 188369e922 | |||
| 347c5054f9 | |||
| 6729b597c0 | |||
| 7bdbfe937c | |||
| d955713335 | |||
| 8bb69ef0ee | |||
| d258583a7f | |||
| 13d0e10dcd | |||
| 5557f79fe7 | |||
| 44ccaa0d26 | |||
| 49f12abeb3 | |||
| b1859774bc | |||
| 4283403f0e | |||
| 379191751c | |||
| 9bf396f2a8 | |||
| 87af4c96c4 | |||
| dd78a7c9de | |||
| 40e534090d | |||
| 973e0c489e | |||
| 5eb64829a5 | |||
| 5648e9e806 | |||
| 2a65e20fb9 | |||
| 1162e9b655 | |||
| b8a5c2fb9b | |||
| eccd37a3eb | |||
| ee282713f8 | |||
| c5edad9c4b | |||
| 293c01b12f | |||
| 162bbc3221 | |||
| 9f27020993 | |||
| c540cf45ca | |||
| 8bf4789646 | |||
| fd97c20d37 | |||
| 7238e17b86 | |||
| 4c44da7f4a | |||
| af7657e3f8 | |||
| bea158b0d9 | |||
| 40acb49011 | |||
| cc7fc7e994 | |||
| ddec715dda | |||
| a1365a98c0 | |||
| 9a29d4ff18 | |||
| 39816eae76 | |||
| 45a38d9570 | |||
| a230258bec | |||
| 8543205b85 | |||
| 1d169005da | |||
| f5212d88f3 | |||
| 03a93ad3f3 | |||
| 3a66fa28ab | |||
| 5f79b286f1 | |||
| f6a4e39cfc | |||
| 24d8444043 | |||
| 0b8205dc41 | |||
| 98197d1e86 | |||
| 77bcca45ce | |||
| d33d65031c | |||
| 8fe4aa386d | |||
| 05cc27b2b9 | |||
| 16ef1b3a34 | |||
| fd350528a9 | |||
| 62cd076abb | |||
| b63224a218 | |||
| 3223b3e78e | |||
| 8da95496bd | |||
| 8e1d23a53e | |||
| 2e2ad4edcf | |||
| e8ecd00a57 | |||
| e19ee6f363 | |||
| 3785efce78 | |||
| 841faf9124 | |||
| f8e14cb900 | |||
| 2ecbbdd011 | |||
| 15a39de939 | |||
| 4142206b65 | |||
| 6105658602 | |||
| a6e40be79e | |||
| 95fba6a99a | |||
| aa2e4c9845 | |||
| f4cfc40244 | |||
| 6c50bdba06 | |||
| 1f6fc491ef | |||
| 1c3a7b6ce7 | |||
| b04e260fb7 | |||
| 4a66486e1a | |||
| a335aa037a | |||
| dd4c89b9dd | |||
| ddbf6da061 | |||
| f85e0030a7 | |||
| c0271d273f | |||
| 2a1dc8beab | |||
| c5b3bc1a0b | |||
| 316b1db3f6 | |||
| 49fa7626b6 | |||
| 24edcc3402 | |||
| c53a1cbd01 | |||
| c138b13d01 | |||
| acc9b58660 | |||
| b94a6acee6 | |||
| b2892cc834 | |||
| 82a1e17b1d | |||
| 82a3cd8df2 | |||
| b39a3a05fe | |||
| f4c7eb14ec | |||
| 92ac138183 | |||
| b0fe8cf53e | |||
| 016e403309 | |||
| 4cef0fb60d | |||
| d53eff6043 | |||
| f064912ac9 | |||
| f9f0677da3 | |||
| 16180fd5d6 | |||
| 462aebb115 | |||
| 0cb3bd9cc6 | |||
| 2ef4f28740 | |||
| b02fb0934f | |||
| de363c982f | |||
| f0132f59e5 | |||
| dc32285454 | |||
| e170172870 | |||
| eba47a8196 | |||
| 907543a7cf | |||
| e8dea023ac | |||
| 8cfb6ab4f5 | |||
| c64d58143e | |||
| 991681e186 | |||
| 3c17c36f4f | |||
| 707b4b4ba2 | |||
| 413c7564aa | |||
| 453bf2dd82 | |||
| 5597d2aed0 | |||
| 3c43211b25 | |||
| ee87841ec2 | |||
| 9e5a39e9fc | |||
| 8c21011ac7 | |||
| 5f5013f021 | |||
| fe093475dc | |||
| 1c4e03ebea | |||
| 860b740db9 | |||
| bd54da85a8 | |||
| 86165b3529 | |||
| 09d028a3af | |||
| 1cb261cb6f | |||
| 82934878cc | |||
| 996c460f57 | |||
| 33e704f1ab | |||
| 2c3849bc43 |
105
.gitignore
vendored
105
.gitignore
vendored
@@ -1,6 +1,12 @@
|
|||||||
## Ignore Visual Studio temporary files, build results, and
|
## Ignore Visual Studio temporary files, build results, and
|
||||||
## files generated by popular Visual Studio add-ons.
|
## files generated by popular Visual Studio add-ons.
|
||||||
|
|
||||||
|
# TweetDuck installer builds
|
||||||
|
bld/*
|
||||||
|
!bld/*.iss
|
||||||
|
!bld/*.bat
|
||||||
|
!bld/Resources
|
||||||
|
|
||||||
# User-specific files
|
# User-specific files
|
||||||
*.suo
|
*.suo
|
||||||
*.user
|
*.user
|
||||||
@@ -17,14 +23,11 @@
|
|||||||
[Rr]eleases/
|
[Rr]eleases/
|
||||||
x64/
|
x64/
|
||||||
x86/
|
x86/
|
||||||
bld/
|
|
||||||
[Bb]in/
|
[Bb]in/
|
||||||
[Oo]bj/
|
[Oo]bj/
|
||||||
|
|
||||||
# Visual Studio 2015 cache/options directory
|
# Visual Studio 2015 cache/options directory
|
||||||
.vs/
|
.vs/
|
||||||
# Uncomment if you have tasks that create the project's static files in wwwroot
|
|
||||||
#wwwroot/
|
|
||||||
|
|
||||||
# MSTest test Results
|
# MSTest test Results
|
||||||
[Tt]est[Rr]esult*/
|
[Tt]est[Rr]esult*/
|
||||||
@@ -34,11 +37,6 @@ bld/
|
|||||||
*.VisualState.xml
|
*.VisualState.xml
|
||||||
TestResult.xml
|
TestResult.xml
|
||||||
|
|
||||||
# Build Results of an ATL Project
|
|
||||||
[Dd]ebugPS/
|
|
||||||
[Rr]eleasePS/
|
|
||||||
dlldata.c
|
|
||||||
|
|
||||||
# DNX
|
# DNX
|
||||||
project.lock.json
|
project.lock.json
|
||||||
artifacts/
|
artifacts/
|
||||||
@@ -47,7 +45,6 @@ artifacts/
|
|||||||
*_p.c
|
*_p.c
|
||||||
*_i.h
|
*_i.h
|
||||||
*.ilk
|
*.ilk
|
||||||
*.meta
|
|
||||||
*.obj
|
*.obj
|
||||||
*.pch
|
*.pch
|
||||||
*.pdb
|
*.pdb
|
||||||
@@ -68,27 +65,12 @@ artifacts/
|
|||||||
*.svclog
|
*.svclog
|
||||||
*.scc
|
*.scc
|
||||||
|
|
||||||
# Chutzpah Test files
|
|
||||||
_Chutzpah*
|
|
||||||
|
|
||||||
# Visual C++ cache files
|
|
||||||
ipch/
|
|
||||||
*.aps
|
|
||||||
*.ncb
|
|
||||||
*.opendb
|
|
||||||
*.opensdf
|
|
||||||
*.sdf
|
|
||||||
*.cachefile
|
|
||||||
|
|
||||||
# Visual Studio profiler
|
# Visual Studio profiler
|
||||||
*.psess
|
*.psess
|
||||||
*.vsp
|
*.vsp
|
||||||
*.vspx
|
*.vspx
|
||||||
*.sap
|
*.sap
|
||||||
|
|
||||||
# TFS 2012 Local Workspace
|
|
||||||
$tf/
|
|
||||||
|
|
||||||
# Guidance Automation Toolkit
|
# Guidance Automation Toolkit
|
||||||
*.gpState
|
*.gpState
|
||||||
|
|
||||||
@@ -115,33 +97,9 @@ nCrunchTemp_*
|
|||||||
*.mm.*
|
*.mm.*
|
||||||
AutoTest.Net/
|
AutoTest.Net/
|
||||||
|
|
||||||
# Web workbench (sass)
|
|
||||||
.sass-cache/
|
|
||||||
|
|
||||||
# Installshield output folder
|
|
||||||
[Ee]xpress/
|
|
||||||
|
|
||||||
# DocProject is a documentation generator add-in
|
|
||||||
DocProject/buildhelp/
|
|
||||||
DocProject/Help/*.HxT
|
|
||||||
DocProject/Help/*.HxC
|
|
||||||
DocProject/Help/*.hhc
|
|
||||||
DocProject/Help/*.hhk
|
|
||||||
DocProject/Help/*.hhp
|
|
||||||
DocProject/Help/Html2
|
|
||||||
DocProject/Help/html
|
|
||||||
|
|
||||||
# Click-Once directory
|
# Click-Once directory
|
||||||
publish/
|
publish/
|
||||||
|
|
||||||
# Publish Web Output
|
|
||||||
*.[Pp]ublish.xml
|
|
||||||
*.azurePubxml
|
|
||||||
# TODO: Comment the next line if you want to checkin your web deploy settings
|
|
||||||
# but database connection strings (with potential passwords) will be unencrypted
|
|
||||||
*.pubxml
|
|
||||||
*.publishproj
|
|
||||||
|
|
||||||
# NuGet Packages
|
# NuGet Packages
|
||||||
*.nupkg
|
*.nupkg
|
||||||
# The packages folder can be ignored because of Package Restore
|
# The packages folder can be ignored because of Package Restore
|
||||||
@@ -154,17 +112,6 @@ publish/
|
|||||||
*.nuget.props
|
*.nuget.props
|
||||||
*.nuget.targets
|
*.nuget.targets
|
||||||
|
|
||||||
# Microsoft Azure Build Output
|
|
||||||
csx/
|
|
||||||
*.build.csdef
|
|
||||||
|
|
||||||
# Microsoft Azure Emulator
|
|
||||||
ecf/
|
|
||||||
rcf/
|
|
||||||
|
|
||||||
# Microsoft Azure ApplicationInsights config file
|
|
||||||
ApplicationInsights.config
|
|
||||||
|
|
||||||
# Windows Store app package directory
|
# Windows Store app package directory
|
||||||
AppPackages/
|
AppPackages/
|
||||||
BundleArtifacts/
|
BundleArtifacts/
|
||||||
@@ -186,9 +133,6 @@ ClientBin/
|
|||||||
node_modules/
|
node_modules/
|
||||||
orleans.codegen.cs
|
orleans.codegen.cs
|
||||||
|
|
||||||
# RIA/Silverlight projects
|
|
||||||
Generated_Code/
|
|
||||||
|
|
||||||
# Backup & report files from converting an old project file
|
# Backup & report files from converting an old project file
|
||||||
# to a newer Visual Studio version. Backup files are not needed,
|
# to a newer Visual Studio version. Backup files are not needed,
|
||||||
# because we have git ;-)
|
# because we have git ;-)
|
||||||
@@ -197,40 +141,3 @@ Backup*/
|
|||||||
UpgradeLog*.XML
|
UpgradeLog*.XML
|
||||||
UpgradeLog*.htm
|
UpgradeLog*.htm
|
||||||
|
|
||||||
# SQL Server files
|
|
||||||
*.mdf
|
|
||||||
*.ldf
|
|
||||||
|
|
||||||
# Business Intelligence projects
|
|
||||||
*.rdl.data
|
|
||||||
*.bim.layout
|
|
||||||
*.bim_*.settings
|
|
||||||
|
|
||||||
# Microsoft Fakes
|
|
||||||
FakesAssemblies/
|
|
||||||
|
|
||||||
# GhostDoc plugin setting file
|
|
||||||
*.GhostDoc.xml
|
|
||||||
|
|
||||||
# Node.js Tools for Visual Studio
|
|
||||||
.ntvs_analysis.dat
|
|
||||||
|
|
||||||
# Visual Studio 6 build log
|
|
||||||
*.plg
|
|
||||||
|
|
||||||
# Visual Studio 6 workspace options file
|
|
||||||
*.opt
|
|
||||||
|
|
||||||
# Visual Studio LightSwitch build output
|
|
||||||
**/*.HTMLClient/GeneratedArtifacts
|
|
||||||
**/*.DesktopClient/GeneratedArtifacts
|
|
||||||
**/*.DesktopClient/ModelManifest.xml
|
|
||||||
**/*.Server/GeneratedArtifacts
|
|
||||||
**/*.Server/ModelManifest.xml
|
|
||||||
_Pvt_Extensions
|
|
||||||
|
|
||||||
# Paket dependency manager
|
|
||||||
.paket/paket.exe
|
|
||||||
|
|
||||||
# FAKE - F# Make
|
|
||||||
.fake/
|
|
||||||
|
|||||||
46
Configuration/Arguments.cs
Normal file
46
Configuration/Arguments.cs
Normal file
@@ -0,0 +1,46 @@
|
|||||||
|
using System;
|
||||||
|
using TweetDuck.Data;
|
||||||
|
|
||||||
|
namespace TweetDuck.Configuration{
|
||||||
|
static class Arguments{
|
||||||
|
// public args
|
||||||
|
public const string ArgDataFolder = "-datafolder";
|
||||||
|
public const string ArgLocale = "-locale";
|
||||||
|
public const string ArgLogging = "-log";
|
||||||
|
public const string ArgDebugUpdates = "-debugupdates";
|
||||||
|
|
||||||
|
// internal args
|
||||||
|
public const string ArgRestart = "-restart";
|
||||||
|
public const string ArgImportCookies = "-importcookies";
|
||||||
|
public const string ArgUpdated = "-updated";
|
||||||
|
|
||||||
|
// class data and methods
|
||||||
|
private static readonly CommandLineArgs Current = CommandLineArgs.FromStringArray('-', Environment.GetCommandLineArgs());
|
||||||
|
|
||||||
|
public static bool HasFlag(string flag){
|
||||||
|
return Current.HasFlag(flag);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static string GetValue(string key, string defaultValue){
|
||||||
|
return Current.GetValue(key, defaultValue);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static CommandLineArgs GetCurrentClean(){
|
||||||
|
CommandLineArgs args = Current.Clone();
|
||||||
|
args.RemoveFlag(ArgRestart);
|
||||||
|
args.RemoveFlag(ArgImportCookies);
|
||||||
|
args.RemoveFlag(ArgUpdated);
|
||||||
|
return args;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static CommandLineArgs GetCurrentForInstaller(){
|
||||||
|
CommandLineArgs args = GetCurrentClean();
|
||||||
|
args.AddFlag(ArgUpdated);
|
||||||
|
return args;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static string GetCurrentForInstallerCmd(){
|
||||||
|
return GetCurrentForInstaller().ToString().Replace("\"", "::");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,10 +1,18 @@
|
|||||||
using System;
|
using System;
|
||||||
|
using System.ComponentModel;
|
||||||
using System.Diagnostics;
|
using System.Diagnostics;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
|
using TweetDuck.Core.Utils;
|
||||||
|
|
||||||
|
namespace TweetDuck.Configuration{
|
||||||
|
sealed class LockManager{
|
||||||
|
private const int RetryDelay = 250;
|
||||||
|
|
||||||
|
public enum Result{
|
||||||
|
Success, HasProcess, Fail
|
||||||
|
}
|
||||||
|
|
||||||
namespace TweetDick.Configuration{
|
|
||||||
class LockManager{
|
|
||||||
private readonly string file;
|
private readonly string file;
|
||||||
private FileStream lockStream;
|
private FileStream lockStream;
|
||||||
private Process lockingProcess;
|
private Process lockingProcess;
|
||||||
@@ -13,96 +21,168 @@ namespace TweetDick.Configuration{
|
|||||||
this.file = file;
|
this.file = file;
|
||||||
}
|
}
|
||||||
|
|
||||||
private bool CreateLockFile(){
|
// Lock file
|
||||||
|
|
||||||
|
private bool ReleaseLockFileStream(){
|
||||||
if (lockStream != null){
|
if (lockStream != null){
|
||||||
throw new InvalidOperationException("Lock file already exists.");
|
|
||||||
}
|
|
||||||
|
|
||||||
try{
|
|
||||||
lockStream = new FileStream(file,FileMode.Create,FileAccess.Write,FileShare.Read);
|
|
||||||
|
|
||||||
byte[] id = BitConverter.GetBytes(Process.GetCurrentProcess().Id);
|
|
||||||
lockStream.Write(id,0,id.Length);
|
|
||||||
lockStream.Flush();
|
|
||||||
|
|
||||||
if (lockingProcess != null){
|
|
||||||
lockingProcess.Close();
|
|
||||||
lockingProcess = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}catch(Exception){
|
|
||||||
if (lockStream != null){
|
|
||||||
lockStream.Close();
|
|
||||||
lockStream.Dispose();
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public bool Lock(){
|
|
||||||
if (lockStream != null)return true;
|
|
||||||
|
|
||||||
try{
|
|
||||||
byte[] bytes = new byte[4];
|
|
||||||
|
|
||||||
using(FileStream fileStream = new FileStream(file,FileMode.Open,FileAccess.Read,FileShare.ReadWrite)){
|
|
||||||
fileStream.Read(bytes,0,4);
|
|
||||||
}
|
|
||||||
|
|
||||||
int pid = BitConverter.ToInt32(bytes,0);
|
|
||||||
|
|
||||||
try{
|
|
||||||
lockingProcess = Process.GetProcessById(pid);
|
|
||||||
}catch(ArgumentException){}
|
|
||||||
|
|
||||||
return lockingProcess == null && CreateLockFile();
|
|
||||||
}catch(DirectoryNotFoundException){
|
|
||||||
string dir = Path.GetDirectoryName(file);
|
|
||||||
|
|
||||||
if (dir != null){
|
|
||||||
Directory.CreateDirectory(dir);
|
|
||||||
return CreateLockFile();
|
|
||||||
}
|
|
||||||
}catch(FileNotFoundException){
|
|
||||||
return CreateLockFile();
|
|
||||||
}catch(Exception){
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void Unlock(){
|
|
||||||
if (lockStream != null){
|
|
||||||
lockStream.Close();
|
|
||||||
lockStream.Dispose();
|
lockStream.Dispose();
|
||||||
File.Delete(file);
|
|
||||||
|
|
||||||
lockStream = null;
|
lockStream = null;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool CloseLockingProcess(int timeout){
|
private Result TryCreateLockFile(){
|
||||||
if (lockingProcess != null){
|
void CreateLockFileStream(){
|
||||||
lockingProcess.CloseMainWindow();
|
lockStream = new FileStream(file, FileMode.Create, FileAccess.Write, FileShare.Read);
|
||||||
|
lockStream.Write(BitConverter.GetBytes(WindowsUtils.CurrentProcessID), 0, sizeof(int));
|
||||||
|
lockStream.Flush(true);
|
||||||
|
}
|
||||||
|
|
||||||
for(int waited = 0; waited < timeout && !lockingProcess.HasExited;){
|
try{
|
||||||
lockingProcess.Refresh();
|
CreateLockFileStream();
|
||||||
|
return Result.Success;
|
||||||
Thread.Sleep(100);
|
}catch(DirectoryNotFoundException){
|
||||||
waited += 100;
|
try{
|
||||||
|
CreateLockFileStream();
|
||||||
|
return Result.Success;
|
||||||
|
}catch{
|
||||||
|
ReleaseLockFileStream();
|
||||||
|
return Result.Fail;
|
||||||
}
|
}
|
||||||
|
}catch(IOException){
|
||||||
|
return Result.HasProcess;
|
||||||
|
}catch{
|
||||||
|
ReleaseLockFileStream();
|
||||||
|
return Result.Fail;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (lockingProcess.HasExited){
|
// Lock management
|
||||||
lockingProcess.Close();
|
|
||||||
lockingProcess = null;
|
public Result Lock(){
|
||||||
return true;
|
if (lockStream != null){
|
||||||
|
return Result.Success;
|
||||||
|
}
|
||||||
|
|
||||||
|
Result initialResult = TryCreateLockFile();
|
||||||
|
|
||||||
|
if (initialResult == Result.HasProcess){
|
||||||
|
try{
|
||||||
|
int pid;
|
||||||
|
|
||||||
|
using(FileStream fileStream = new FileStream(file, FileMode.Open, FileAccess.Read, FileShare.ReadWrite)){
|
||||||
|
byte[] bytes = new byte[sizeof(int)];
|
||||||
|
fileStream.Read(bytes, 0, bytes.Length);
|
||||||
|
pid = BitConverter.ToInt32(bytes, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
try{
|
||||||
|
Process foundProcess = Process.GetProcessById(pid);
|
||||||
|
|
||||||
|
using(Process currentProcess = Process.GetCurrentProcess()){
|
||||||
|
if (foundProcess.MainModule.FileVersionInfo.InternalName == currentProcess.MainModule.FileVersionInfo.InternalName){
|
||||||
|
lockingProcess = foundProcess;
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
foundProcess.Close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}catch{
|
||||||
|
// GetProcessById throws ArgumentException if the process is missing
|
||||||
|
// Process.MainModule can throw exceptions in some cases
|
||||||
|
}
|
||||||
|
|
||||||
|
return lockingProcess == null ? Result.Fail : Result.HasProcess;
|
||||||
|
}catch{
|
||||||
|
return Result.Fail;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return initialResult;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Result LockWait(int timeout){
|
||||||
|
for(int elapsed = 0; elapsed < timeout; elapsed += RetryDelay){
|
||||||
|
Result result = Lock();
|
||||||
|
|
||||||
|
if (result == Result.HasProcess){
|
||||||
|
Thread.Sleep(RetryDelay);
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return Lock();
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool Unlock(){
|
||||||
|
if (ReleaseLockFileStream()){
|
||||||
|
try{
|
||||||
|
File.Delete(file);
|
||||||
|
}catch(Exception e){
|
||||||
|
Program.Reporter.Log(e.ToString());
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Locking process
|
||||||
|
|
||||||
|
public bool RestoreLockingProcess(int failTimeout){
|
||||||
|
if (lockingProcess != null){
|
||||||
|
if (lockingProcess.MainWindowHandle == IntPtr.Zero){ // restore if the original process is in tray
|
||||||
|
NativeMethods.PostMessage(NativeMethods.HWND_BROADCAST, Program.WindowRestoreMessage, new UIntPtr((uint)lockingProcess.Id), IntPtr.Zero);
|
||||||
|
|
||||||
|
if (WindowsUtils.TrySleepUntil(() => CheckLockingProcessExited() || (lockingProcess.MainWindowHandle != IntPtr.Zero && lockingProcess.Responding), failTimeout, RetryDelay)){
|
||||||
|
return true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public bool CloseLockingProcess(int closeTimeout, int killTimeout){
|
||||||
|
if (lockingProcess != null){
|
||||||
|
try{
|
||||||
|
if (lockingProcess.CloseMainWindow()){
|
||||||
|
WindowsUtils.TrySleepUntil(CheckLockingProcessExited, closeTimeout, RetryDelay);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!lockingProcess.HasExited){
|
||||||
|
lockingProcess.Kill();
|
||||||
|
WindowsUtils.TrySleepUntil(CheckLockingProcessExited, killTimeout, RetryDelay);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (lockingProcess.HasExited){
|
||||||
|
lockingProcess.Dispose();
|
||||||
|
lockingProcess = null;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}catch(Exception ex){
|
||||||
|
if (ex is InvalidOperationException || ex is Win32Exception){
|
||||||
|
if (lockingProcess != null){
|
||||||
|
bool hasExited = CheckLockingProcessExited();
|
||||||
|
lockingProcess.Dispose();
|
||||||
|
return hasExited;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else throw;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
private bool CheckLockingProcessExited(){
|
||||||
|
lockingProcess.Refresh();
|
||||||
|
return lockingProcess.HasExited;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
73
Configuration/SystemConfig.cs
Normal file
73
Configuration/SystemConfig.cs
Normal file
@@ -0,0 +1,73 @@
|
|||||||
|
using System;
|
||||||
|
using System.IO;
|
||||||
|
using TweetDuck.Core.Utils;
|
||||||
|
using TweetDuck.Data.Serialization;
|
||||||
|
|
||||||
|
namespace TweetDuck.Configuration{
|
||||||
|
sealed class SystemConfig{
|
||||||
|
private static readonly FileSerializer<SystemConfig> Serializer = new FileSerializer<SystemConfig>{
|
||||||
|
// HandleUnknownProperties = (obj, data) => {}
|
||||||
|
};
|
||||||
|
|
||||||
|
public static readonly bool IsHardwareAccelerationSupported = File.Exists(Path.Combine(Program.ProgramPath, "libEGL.dll")) &&
|
||||||
|
File.Exists(Path.Combine(Program.ProgramPath, "libGLESv2.dll"));
|
||||||
|
|
||||||
|
// CONFIGURATION DATA
|
||||||
|
|
||||||
|
private bool _hardwareAcceleration = true;
|
||||||
|
|
||||||
|
public bool EnableBrowserGCReload { get; set; } = true;
|
||||||
|
public int BrowserMemoryThreshold { get; set; } = 400;
|
||||||
|
|
||||||
|
// SPECIAL PROPERTIES
|
||||||
|
|
||||||
|
public bool HardwareAcceleration{
|
||||||
|
get => _hardwareAcceleration && IsHardwareAccelerationSupported;
|
||||||
|
set => _hardwareAcceleration = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
// END OF CONFIG
|
||||||
|
|
||||||
|
private readonly string file;
|
||||||
|
|
||||||
|
private SystemConfig(string file){
|
||||||
|
this.file = file;
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool Save(){
|
||||||
|
try{
|
||||||
|
WindowsUtils.CreateDirectoryForFile(file);
|
||||||
|
Serializer.Write(file, this);
|
||||||
|
return true;
|
||||||
|
}catch(Exception e){
|
||||||
|
Program.Reporter.HandleException("Configuration Error", "Could not save the system configuration file.", true, e);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static SystemConfig Load(string file){
|
||||||
|
SystemConfig config = new SystemConfig(file);
|
||||||
|
|
||||||
|
try{
|
||||||
|
Serializer.Read(file, config);
|
||||||
|
return config;
|
||||||
|
}catch(FileNotFoundException){
|
||||||
|
}catch(DirectoryNotFoundException){
|
||||||
|
}catch(FormatException){
|
||||||
|
try{
|
||||||
|
using(Stream stream = new FileStream(file, FileMode.Open, FileAccess.Read, FileShare.Read)){
|
||||||
|
config.HardwareAcceleration = stream.ReadByte() > 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
config.Save();
|
||||||
|
}catch(Exception e){
|
||||||
|
Program.Reporter.HandleException("Configuration Error", "Could not update the system configuration file.", true, e);
|
||||||
|
}
|
||||||
|
}catch(Exception e){
|
||||||
|
Program.Reporter.HandleException("Configuration Error", "Could not open the system configuration file. If you continue, you will lose system specific configuration such as Hardware Acceleration.", true, e);
|
||||||
|
}
|
||||||
|
|
||||||
|
return config;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,105 +1,213 @@
|
|||||||
using System;
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
using System.Drawing;
|
using System.Drawing;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Runtime.Serialization;
|
using TweetDuck.Core;
|
||||||
using System.Runtime.Serialization.Formatters.Binary;
|
using TweetDuck.Core.Controls;
|
||||||
using System.Windows.Forms;
|
using TweetDuck.Core.Notification;
|
||||||
using TweetDick.Core.Handling;
|
using TweetDuck.Core.Utils;
|
||||||
|
using TweetDuck.Data;
|
||||||
|
using TweetDuck.Data.Serialization;
|
||||||
|
|
||||||
namespace TweetDick.Configuration{
|
namespace TweetDuck.Configuration{
|
||||||
[Serializable]
|
|
||||||
sealed class UserConfig{
|
sealed class UserConfig{
|
||||||
private static readonly IFormatter Formatter = new BinaryFormatter();
|
private static readonly FileSerializer<UserConfig> Serializer = new FileSerializer<UserConfig>{ HandleUnknownProperties = HandleUnknownProperties };
|
||||||
|
|
||||||
// START OF CONFIGURATION
|
private static void HandleUnknownProperties(UserConfig obj, Dictionary<string, string> data){
|
||||||
|
if (data.TryGetValue("EnableBrowserGCReload", out string propGCReload) && data.TryGetValue("BrowserMemoryThreshold", out string propMemThreshold)){
|
||||||
|
if (bool.TryParse(propGCReload, out bool isGCReloadEnabled) && isGCReloadEnabled && int.TryParse(propMemThreshold, out int memThreshold)){
|
||||||
|
// SystemConfig initialization was moved before UserConfig to allow for this
|
||||||
|
// TODO remove the migration soon
|
||||||
|
Program.SystemConfig.EnableBrowserGCReload = true;
|
||||||
|
Program.SystemConfig.BrowserMemoryThreshold = memThreshold;
|
||||||
|
Program.SystemConfig.Save();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public bool IgnoreMigration { get; set; }
|
data.Remove("EnableBrowserGCReload");
|
||||||
public bool IgnoreUninstallCheck { get; set; }
|
data.Remove("BrowserMemoryThreshold");
|
||||||
|
|
||||||
public bool IsMaximized { get; set; }
|
if (data.Count == 0){
|
||||||
public Point WindowLocation { get; set; }
|
obj.Save();
|
||||||
public Size WindowSize { get; set; }
|
|
||||||
|
|
||||||
public TweetNotification.Duration NotificationDuration { get; set; }
|
|
||||||
public TweetNotification.Position NotificationPosition { get; set; }
|
|
||||||
public Point CustomNotificationPosition { get; set; }
|
|
||||||
public int NotificationEdgeDistance { get; set; }
|
|
||||||
public int NotificationDisplay { get; set; }
|
|
||||||
|
|
||||||
public bool IsCustomWindowLocationSet{
|
|
||||||
get{
|
|
||||||
return WindowLocation.X != -32000 && WindowLocation.X != 32000;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool IsCustomNotificationPositionSet{
|
static UserConfig(){
|
||||||
get{
|
Serializer.RegisterTypeConverter(typeof(WindowState), WindowState.Converter);
|
||||||
return CustomNotificationPosition.X != -32000 && CustomNotificationPosition.X != 32000;
|
|
||||||
|
Serializer.RegisterTypeConverter(typeof(Point), new SingleTypeConverter<Point>{
|
||||||
|
ConvertToString = value => $"{value.X} {value.Y}",
|
||||||
|
ConvertToObject = value => {
|
||||||
|
int[] elements = StringUtils.ParseInts(value, ' ');
|
||||||
|
return new Point(elements[0], elements[1]);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
Serializer.RegisterTypeConverter(typeof(Size), new SingleTypeConverter<Size>{
|
||||||
|
ConvertToString = value => $"{value.Width} {value.Height}",
|
||||||
|
ConvertToObject = value => {
|
||||||
|
int[] elements = StringUtils.ParseInts(value, ' ');
|
||||||
|
return new Size(elements[0], elements[1]);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// CONFIGURATION DATA
|
||||||
|
|
||||||
|
public WindowState BrowserWindow { get; set; } = new WindowState();
|
||||||
|
public WindowState PluginsWindow { get; set; } = new WindowState();
|
||||||
|
|
||||||
|
public bool ExpandLinksOnHover { get; set; } = true;
|
||||||
|
public bool SwitchAccountSelectors { get; set; } = true;
|
||||||
|
public bool BestImageQuality { get; set; } = true;
|
||||||
|
public bool EnableSpellCheck { get; set; } = false;
|
||||||
|
private int _zoomLevel = 100;
|
||||||
|
private bool _muteNotifications;
|
||||||
|
|
||||||
|
private TrayIcon.Behavior _trayBehavior = TrayIcon.Behavior.Disabled;
|
||||||
|
public bool EnableTrayHighlight { get; set; } = true;
|
||||||
|
|
||||||
|
public bool EnableUpdateCheck { get; set; } = true;
|
||||||
|
public string DismissedUpdate { get; set; } = null;
|
||||||
|
|
||||||
|
public bool DisplayNotificationColumn { get; set; } = false;
|
||||||
|
public bool NotificationMediaPreviews { get; set; } = true;
|
||||||
|
public bool NotificationSkipOnLinkClick { get; set; } = false;
|
||||||
|
public bool NotificationNonIntrusiveMode { get; set; } = true;
|
||||||
|
public int NotificationIdlePauseSeconds { get; set; } = 0;
|
||||||
|
|
||||||
|
public bool DisplayNotificationTimer { get; set; } = true;
|
||||||
|
public bool NotificationTimerCountDown { get; set; } = false;
|
||||||
|
public int NotificationDurationValue { get; set; } = 25;
|
||||||
|
|
||||||
|
public TweetNotification.Position NotificationPosition { get; set; } = TweetNotification.Position.TopRight;
|
||||||
|
public Point CustomNotificationPosition { get; set; } = ControlExtensions.InvisibleLocation;
|
||||||
|
public int NotificationDisplay { get; set; } = 0;
|
||||||
|
public int NotificationEdgeDistance { get; set; } = 8;
|
||||||
|
|
||||||
|
public TweetNotification.Size NotificationSize { get; set; } = TweetNotification.Size.Auto;
|
||||||
|
public Size CustomNotificationSize { get; set; } = Size.Empty;
|
||||||
|
public int NotificationScrollSpeed { get; set; } = 10;
|
||||||
|
|
||||||
|
private string _notificationSoundPath;
|
||||||
|
|
||||||
|
public string CustomCefArgs { get; set; } = null;
|
||||||
|
public string CustomBrowserCSS { get; set; } = null;
|
||||||
|
public string CustomNotificationCSS { get; set; } = null;
|
||||||
|
|
||||||
|
// SPECIAL PROPERTIES
|
||||||
|
|
||||||
|
public bool IsCustomNotificationPositionSet => CustomNotificationPosition != ControlExtensions.InvisibleLocation;
|
||||||
|
public bool IsCustomNotificationSizeSet => CustomNotificationSize != Size.Empty;
|
||||||
|
|
||||||
|
public TwitterUtils.ImageQuality TwitterImageQuality => BestImageQuality ? TwitterUtils.ImageQuality.Orig : TwitterUtils.ImageQuality.Default;
|
||||||
|
|
||||||
|
public string NotificationSoundPath{
|
||||||
|
get => string.IsNullOrEmpty(_notificationSoundPath) ? string.Empty : _notificationSoundPath;
|
||||||
|
set => _notificationSoundPath = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool MuteNotifications{
|
||||||
|
get => _muteNotifications;
|
||||||
|
|
||||||
|
set{
|
||||||
|
if (_muteNotifications != value){
|
||||||
|
_muteNotifications = value;
|
||||||
|
MuteToggled?.Invoke(this, new EventArgs());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// END OF CONFIGURATION
|
public int ZoomLevel{
|
||||||
|
get => _zoomLevel;
|
||||||
|
|
||||||
[NonSerialized]
|
set{
|
||||||
private string file;
|
if (_zoomLevel != value){
|
||||||
|
_zoomLevel = value;
|
||||||
|
ZoomLevelChanged?.Invoke(this, new EventArgs());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private UserConfig(string file){
|
public double ZoomMultiplier => _zoomLevel/100.0;
|
||||||
|
|
||||||
|
public TrayIcon.Behavior TrayBehavior{
|
||||||
|
get => _trayBehavior;
|
||||||
|
|
||||||
|
set{
|
||||||
|
if (_trayBehavior != value){
|
||||||
|
_trayBehavior = value;
|
||||||
|
TrayBehaviorChanged?.Invoke(this, new EventArgs());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// EVENTS
|
||||||
|
|
||||||
|
public event EventHandler MuteToggled;
|
||||||
|
public event EventHandler ZoomLevelChanged;
|
||||||
|
public event EventHandler TrayBehaviorChanged;
|
||||||
|
|
||||||
|
// END OF CONFIG
|
||||||
|
|
||||||
|
private readonly string file;
|
||||||
|
|
||||||
|
public UserConfig(string file){ // TODO make private after removing UserConfigLegacy
|
||||||
this.file = file;
|
this.file = file;
|
||||||
|
|
||||||
IsMaximized = true;
|
|
||||||
WindowLocation = new Point(-32000,-32000);
|
|
||||||
NotificationDuration = TweetNotification.Duration.Medium;
|
|
||||||
NotificationPosition = TweetNotification.Position.TopRight;
|
|
||||||
CustomNotificationPosition = new Point(-32000,-32000);
|
|
||||||
NotificationEdgeDistance = 8;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool Save(){
|
public bool Save(){
|
||||||
try{
|
try{
|
||||||
string directory = Path.GetDirectoryName(file);
|
WindowsUtils.CreateDirectoryForFile(file);
|
||||||
if (directory == null)return false;
|
|
||||||
|
|
||||||
Directory.CreateDirectory(directory);
|
|
||||||
|
|
||||||
if (File.Exists(file)){
|
if (File.Exists(file)){
|
||||||
string backupFile = GetBackupFile(file);
|
string backupFile = GetBackupFile(file);
|
||||||
File.Delete(backupFile);
|
File.Delete(backupFile);
|
||||||
File.Move(file,backupFile);
|
File.Move(file, backupFile);
|
||||||
}
|
|
||||||
|
|
||||||
using(Stream stream = new FileStream(file,FileMode.Create,FileAccess.Write,FileShare.None)){
|
|
||||||
Formatter.Serialize(stream,this);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Serializer.Write(file, this);
|
||||||
return true;
|
return true;
|
||||||
}catch(Exception e){
|
}catch(Exception e){
|
||||||
Program.HandleException("Could not save the configuration file.",e);
|
Program.Reporter.HandleException("Configuration Error", "Could not save the configuration file.", true, e);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static UserConfig Load(string file){
|
public static UserConfig Load(string file){
|
||||||
UserConfig config = null;
|
Exception firstException = null;
|
||||||
|
|
||||||
for(int attempt = 0; attempt < 2; attempt++){
|
for(int attempt = 0; attempt < 2; attempt++){
|
||||||
try{
|
try{
|
||||||
using(Stream stream = new FileStream(attempt == 0 ? file : GetBackupFile(file),FileMode.Open,FileAccess.Read,FileShare.Read)){
|
UserConfig config = new UserConfig(file);
|
||||||
if ((config = Formatter.Deserialize(stream) as UserConfig) != null){
|
Serializer.Read(attempt == 0 ? file : GetBackupFile(file), config);
|
||||||
config.file = file;
|
return config;
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
break;
|
|
||||||
}catch(FileNotFoundException){
|
}catch(FileNotFoundException){
|
||||||
|
}catch(DirectoryNotFoundException){
|
||||||
|
break;
|
||||||
|
}catch(FormatException){
|
||||||
|
UserConfig config = UserConfigLegacy.Load(file);
|
||||||
|
config.Save();
|
||||||
|
return config;
|
||||||
}catch(Exception e){
|
}catch(Exception e){
|
||||||
Program.HandleException("Could not open the configuration file.",e);
|
if (attempt == 0){
|
||||||
|
firstException = e;
|
||||||
|
Program.Reporter.Log(e.ToString());
|
||||||
|
}
|
||||||
|
else if (firstException != null){
|
||||||
|
Program.Reporter.HandleException("Configuration Error", "Could not open the backup configuration file. If you continue, your program options will be reset.", true, e);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return config ?? new UserConfig(file);
|
if (firstException != null){
|
||||||
|
Program.Reporter.HandleException("Configuration Error", "Could not open the configuration file.", true, firstException);
|
||||||
|
}
|
||||||
|
|
||||||
|
return new UserConfig(file);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static string GetBackupFile(string file){
|
public static string GetBackupFile(string file){
|
||||||
return file+".bak";
|
return file+".bak";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
210
Configuration/UserConfigLegacy.cs
Normal file
210
Configuration/UserConfigLegacy.cs
Normal file
@@ -0,0 +1,210 @@
|
|||||||
|
using System;
|
||||||
|
using System.Drawing;
|
||||||
|
using System.IO;
|
||||||
|
using System.Runtime.Serialization;
|
||||||
|
using System.Runtime.Serialization.Formatters.Binary;
|
||||||
|
using TweetDuck.Core;
|
||||||
|
using TweetDuck.Core.Controls;
|
||||||
|
using TweetDuck.Core.Notification;
|
||||||
|
using TweetDuck.Data;
|
||||||
|
|
||||||
|
namespace TweetDuck.Configuration{
|
||||||
|
[Serializable]
|
||||||
|
sealed class UserConfigLegacy{ // TODO remove eventually
|
||||||
|
private static readonly IFormatter Formatter = new BinaryFormatter{ Binder = new LegacyBinder() };
|
||||||
|
|
||||||
|
private class LegacyBinder : SerializationBinder{
|
||||||
|
public override Type BindToType(string assemblyName, string typeName){
|
||||||
|
return Type.GetType(string.Format("{0}, {1}", typeName.Replace("TweetDck", "TweetDuck").Replace(".UserConfig", ".UserConfigLegacy").Replace("Core.Utils.WindowState", "Data.WindowState"), assemblyName.Replace("TweetDck", "TweetDuck")));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private const int CurrentFileVersion = 11;
|
||||||
|
|
||||||
|
// START OF CONFIGURATION
|
||||||
|
|
||||||
|
public WindowState BrowserWindow { get; set; }
|
||||||
|
public WindowState PluginsWindow { get; set; }
|
||||||
|
|
||||||
|
public bool DisplayNotificationColumn { get; set; }
|
||||||
|
public bool DisplayNotificationTimer { get; set; }
|
||||||
|
public bool NotificationTimerCountDown { get; set; }
|
||||||
|
public bool NotificationSkipOnLinkClick { get; set; }
|
||||||
|
public bool NotificationNonIntrusiveMode { get; set; }
|
||||||
|
|
||||||
|
public int NotificationIdlePauseSeconds { get; set; }
|
||||||
|
public int NotificationDurationValue { get; set; }
|
||||||
|
public int NotificationScrollSpeed { get; set; }
|
||||||
|
|
||||||
|
public TweetNotification.Position NotificationPosition { get; set; }
|
||||||
|
public Point CustomNotificationPosition { get; set; }
|
||||||
|
public int NotificationEdgeDistance { get; set; }
|
||||||
|
public int NotificationDisplay { get; set; }
|
||||||
|
|
||||||
|
public TweetNotification.Size NotificationSize { get; set; }
|
||||||
|
public Size CustomNotificationSize { get; set; }
|
||||||
|
|
||||||
|
public bool EnableSpellCheck { get; set; }
|
||||||
|
public bool ExpandLinksOnHover { get; set; }
|
||||||
|
public bool SwitchAccountSelectors { get; set; }
|
||||||
|
public bool EnableTrayHighlight { get; set; }
|
||||||
|
|
||||||
|
public bool EnableUpdateCheck { get; set; }
|
||||||
|
public string DismissedUpdate { get; set; }
|
||||||
|
|
||||||
|
public string CustomCefArgs { get; set; }
|
||||||
|
public string CustomBrowserCSS { get; set; }
|
||||||
|
public string CustomNotificationCSS { get; set; }
|
||||||
|
|
||||||
|
public string NotificationSoundPath{
|
||||||
|
get => string.IsNullOrEmpty(notificationSoundPath) ? string.Empty : notificationSoundPath;
|
||||||
|
set => notificationSoundPath = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool MuteNotifications{
|
||||||
|
get => muteNotifications;
|
||||||
|
set => muteNotifications = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int ZoomLevel{
|
||||||
|
get => zoomLevel;
|
||||||
|
set => zoomLevel = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
public TrayIcon.Behavior TrayBehavior{
|
||||||
|
get => trayBehavior;
|
||||||
|
set => trayBehavior = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
// END OF CONFIGURATION
|
||||||
|
|
||||||
|
[NonSerialized]
|
||||||
|
private string file;
|
||||||
|
|
||||||
|
private int fileVersion;
|
||||||
|
private bool muteNotifications;
|
||||||
|
private int zoomLevel;
|
||||||
|
private string notificationSoundPath;
|
||||||
|
private TrayIcon.Behavior trayBehavior;
|
||||||
|
|
||||||
|
private UserConfigLegacy(string file){
|
||||||
|
this.file = file;
|
||||||
|
|
||||||
|
BrowserWindow = new WindowState();
|
||||||
|
ZoomLevel = 100;
|
||||||
|
DisplayNotificationTimer = true;
|
||||||
|
NotificationNonIntrusiveMode = true;
|
||||||
|
NotificationPosition = TweetNotification.Position.TopRight;
|
||||||
|
CustomNotificationPosition = ControlExtensions.InvisibleLocation;
|
||||||
|
NotificationSize = TweetNotification.Size.Auto;
|
||||||
|
NotificationEdgeDistance = 8;
|
||||||
|
NotificationDurationValue = 25;
|
||||||
|
NotificationScrollSpeed = 100;
|
||||||
|
EnableUpdateCheck = true;
|
||||||
|
ExpandLinksOnHover = true;
|
||||||
|
SwitchAccountSelectors = true;
|
||||||
|
EnableTrayHighlight = true;
|
||||||
|
PluginsWindow = new WindowState();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void UpgradeFile(){
|
||||||
|
if (fileVersion == CurrentFileVersion){
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// if outdated, cycle through all versions
|
||||||
|
if (fileVersion <= 5){
|
||||||
|
DisplayNotificationTimer = true;
|
||||||
|
EnableUpdateCheck = true;
|
||||||
|
ExpandLinksOnHover = true;
|
||||||
|
BrowserWindow = new WindowState();
|
||||||
|
PluginsWindow = new WindowState();
|
||||||
|
EnableTrayHighlight = true;
|
||||||
|
NotificationDurationValue = 25;
|
||||||
|
fileVersion = 6;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (fileVersion == 6){
|
||||||
|
NotificationNonIntrusiveMode = true;
|
||||||
|
++fileVersion;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (fileVersion == 7){
|
||||||
|
ZoomLevel = 100;
|
||||||
|
++fileVersion;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (fileVersion == 8){
|
||||||
|
SwitchAccountSelectors = true;
|
||||||
|
++fileVersion;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (fileVersion == 9){
|
||||||
|
NotificationScrollSpeed = 100;
|
||||||
|
++fileVersion;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (fileVersion == 10){
|
||||||
|
NotificationSize = TweetNotification.Size.Auto;
|
||||||
|
++fileVersion;
|
||||||
|
}
|
||||||
|
|
||||||
|
// update the version
|
||||||
|
fileVersion = CurrentFileVersion;
|
||||||
|
}
|
||||||
|
|
||||||
|
public UserConfig ConvertLegacy(){
|
||||||
|
return new UserConfig(file){
|
||||||
|
BrowserWindow = BrowserWindow,
|
||||||
|
PluginsWindow = PluginsWindow,
|
||||||
|
DisplayNotificationColumn = DisplayNotificationColumn,
|
||||||
|
DisplayNotificationTimer = DisplayNotificationTimer,
|
||||||
|
NotificationTimerCountDown = NotificationTimerCountDown,
|
||||||
|
NotificationSkipOnLinkClick = NotificationSkipOnLinkClick,
|
||||||
|
NotificationNonIntrusiveMode = NotificationNonIntrusiveMode,
|
||||||
|
NotificationIdlePauseSeconds = NotificationIdlePauseSeconds,
|
||||||
|
NotificationDurationValue = NotificationDurationValue,
|
||||||
|
NotificationScrollSpeed = NotificationScrollSpeed,
|
||||||
|
NotificationPosition = NotificationPosition,
|
||||||
|
CustomNotificationPosition = CustomNotificationPosition,
|
||||||
|
NotificationEdgeDistance = NotificationEdgeDistance,
|
||||||
|
NotificationDisplay = NotificationDisplay,
|
||||||
|
NotificationSize = NotificationSize,
|
||||||
|
CustomNotificationSize = CustomNotificationSize,
|
||||||
|
EnableSpellCheck = EnableSpellCheck,
|
||||||
|
ExpandLinksOnHover = ExpandLinksOnHover,
|
||||||
|
SwitchAccountSelectors = SwitchAccountSelectors,
|
||||||
|
EnableTrayHighlight = EnableTrayHighlight,
|
||||||
|
EnableUpdateCheck = EnableUpdateCheck,
|
||||||
|
DismissedUpdate = DismissedUpdate,
|
||||||
|
CustomCefArgs = CustomCefArgs,
|
||||||
|
CustomBrowserCSS = CustomBrowserCSS,
|
||||||
|
CustomNotificationCSS = CustomNotificationCSS,
|
||||||
|
NotificationSoundPath = NotificationSoundPath,
|
||||||
|
MuteNotifications = MuteNotifications,
|
||||||
|
ZoomLevel = ZoomLevel,
|
||||||
|
TrayBehavior = TrayBehavior
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
public static UserConfig Load(string file){
|
||||||
|
UserConfigLegacy config = null;
|
||||||
|
|
||||||
|
try{
|
||||||
|
using(Stream stream = new FileStream(file, FileMode.Open, FileAccess.Read, FileShare.Read)){
|
||||||
|
if ((config = Formatter.Deserialize(stream) as UserConfigLegacy) != null){
|
||||||
|
config.file = file;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
config?.UpgradeFile();
|
||||||
|
}catch(FileNotFoundException){
|
||||||
|
}catch(DirectoryNotFoundException){
|
||||||
|
}catch(Exception e){
|
||||||
|
Program.Reporter.HandleException("Configuration Error", "Could not open the configuration file.", true, e);
|
||||||
|
}
|
||||||
|
|
||||||
|
return (config ?? new UserConfigLegacy(file)).ConvertLegacy();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,3 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
|
||||||
<configuration>
|
|
||||||
<startup><supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.0,Profile=Client"/></startup></configuration>
|
|
||||||
@@ -1,7 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
|
||||||
<packages xmlns="http://schemas.microsoft.com/packaging/2010/07/nuspec.xsd">
|
|
||||||
<package id="cef.redist.x64" version="3.2623.1396" targetFramework="net40-Client" />
|
|
||||||
<package id="cef.redist.x86" version="3.2623.1396" targetFramework="net40-Client" />
|
|
||||||
<package id="CefSharp.Common" version="49.0.0-pre02" targetFramework="net40-Client" />
|
|
||||||
<package id="CefSharp.WinForms" version="49.0.0-pre02" targetFramework="net40-Client" />
|
|
||||||
</packages>
|
|
||||||
19
Core/Bridge/CallbackBridge.cs
Normal file
19
Core/Bridge/CallbackBridge.cs
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
using System;
|
||||||
|
using System.Windows.Forms;
|
||||||
|
using TweetDuck.Core.Controls;
|
||||||
|
|
||||||
|
namespace TweetDuck.Core.Bridge{
|
||||||
|
sealed class CallbackBridge{
|
||||||
|
private readonly Control owner;
|
||||||
|
private readonly Action safeCallback;
|
||||||
|
|
||||||
|
public CallbackBridge(Control owner, Action safeCallback){
|
||||||
|
this.owner = owner;
|
||||||
|
this.safeCallback = safeCallback;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Trigger(){
|
||||||
|
owner.InvokeSafe(safeCallback);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
32
Core/Bridge/PropertyBridge.cs
Normal file
32
Core/Bridge/PropertyBridge.cs
Normal file
@@ -0,0 +1,32 @@
|
|||||||
|
using System.Text;
|
||||||
|
|
||||||
|
namespace TweetDuck.Core.Bridge{
|
||||||
|
static class PropertyBridge{
|
||||||
|
public enum Environment{
|
||||||
|
Browser, Notification
|
||||||
|
}
|
||||||
|
|
||||||
|
public static string GenerateScript(Environment environment){
|
||||||
|
string Bool(bool value){
|
||||||
|
return value ? "true;" : "false;";
|
||||||
|
}
|
||||||
|
|
||||||
|
StringBuilder build = new StringBuilder().Append("(function(x){");
|
||||||
|
|
||||||
|
build.Append("x.expandLinksOnHover=").Append(Bool(Program.UserConfig.ExpandLinksOnHover));
|
||||||
|
|
||||||
|
if (environment == Environment.Browser){
|
||||||
|
build.Append("x.switchAccountSelectors=").Append(Bool(Program.UserConfig.SwitchAccountSelectors));
|
||||||
|
build.Append("x.muteNotifications=").Append(Bool(Program.UserConfig.MuteNotifications));
|
||||||
|
build.Append("x.hasCustomNotificationSound=").Append(Bool(Program.UserConfig.NotificationSoundPath.Length > 0));
|
||||||
|
build.Append("x.notificationMediaPreviews=").Append(Bool(Program.UserConfig.NotificationMediaPreviews));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (environment == Environment.Notification){
|
||||||
|
build.Append("x.skipOnLinkClick=").Append(Bool(Program.UserConfig.NotificationSkipOnLinkClick));
|
||||||
|
}
|
||||||
|
|
||||||
|
return build.Append("})(window.$TDX=window.$TDX||{})").ToString();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
153
Core/Bridge/TweetDeckBridge.cs
Normal file
153
Core/Bridge/TweetDeckBridge.cs
Normal file
@@ -0,0 +1,153 @@
|
|||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Text;
|
||||||
|
using System.Windows.Forms;
|
||||||
|
using CefSharp;
|
||||||
|
using TweetDuck.Core.Controls;
|
||||||
|
using TweetDuck.Core.Notification;
|
||||||
|
using TweetDuck.Core.Other;
|
||||||
|
using TweetDuck.Core.Utils;
|
||||||
|
using TweetDuck.Resources;
|
||||||
|
|
||||||
|
namespace TweetDuck.Core.Bridge{
|
||||||
|
sealed class TweetDeckBridge{
|
||||||
|
public static string LastRightClickedLink = string.Empty;
|
||||||
|
public static string LastRightClickedImage = string.Empty;
|
||||||
|
public static string LastHighlightedTweet = string.Empty;
|
||||||
|
public static string LastHighlightedQuotedTweet = string.Empty;
|
||||||
|
public static string LastHighlightedTweetAuthor = string.Empty;
|
||||||
|
public static string[] LastHighlightedTweetImages = StringUtils.EmptyArray;
|
||||||
|
public static Dictionary<string, string> SessionData = new Dictionary<string, string>(2);
|
||||||
|
|
||||||
|
public static void ResetStaticProperties(){
|
||||||
|
LastRightClickedLink = LastRightClickedImage = LastHighlightedTweet = LastHighlightedQuotedTweet = LastHighlightedTweetAuthor = string.Empty;
|
||||||
|
LastHighlightedTweetImages = StringUtils.EmptyArray;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void RestoreSessionData(IFrame frame){
|
||||||
|
if (SessionData.Count > 0){
|
||||||
|
StringBuilder build = new StringBuilder().Append("window.TD_SESSION={");
|
||||||
|
|
||||||
|
foreach(KeyValuePair<string, string> kvp in SessionData){
|
||||||
|
build.Append(kvp.Key).Append(":'").Append(kvp.Value.Replace("'", "\\'")).Append("',");
|
||||||
|
}
|
||||||
|
|
||||||
|
ScriptLoader.ExecuteScript(frame, build.Append("}").ToString(), "gen:session");
|
||||||
|
SessionData.Clear();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private readonly FormBrowser form;
|
||||||
|
private readonly FormNotificationMain notification;
|
||||||
|
|
||||||
|
public TweetDeckBridge(FormBrowser form, FormNotificationMain notification){
|
||||||
|
this.form = form;
|
||||||
|
this.notification = notification;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void LoadFontSizeClass(string fsClass){
|
||||||
|
form.InvokeAsyncSafe(() => {
|
||||||
|
TweetNotification.SetFontSizeClass(fsClass);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
public void LoadNotificationHeadContents(string headContents){
|
||||||
|
form.InvokeAsyncSafe(() => {
|
||||||
|
TweetNotification.SetHeadTag(headContents);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
public void SetLastRightClickedLink(string link){
|
||||||
|
form.InvokeAsyncSafe(() => LastRightClickedLink = link);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void SetLastRightClickedImage(string link){
|
||||||
|
form.InvokeAsyncSafe(() => LastRightClickedImage = link);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void SetLastHighlightedTweet(string link, string quotedLink, string author, string imageList){
|
||||||
|
form.InvokeAsyncSafe(() => {
|
||||||
|
LastHighlightedTweet = link;
|
||||||
|
LastHighlightedQuotedTweet = quotedLink;
|
||||||
|
LastHighlightedTweetAuthor = author;
|
||||||
|
LastHighlightedTweetImages = imageList.Split(';');
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
public void OpenContextMenu(){
|
||||||
|
form.InvokeAsyncSafe(form.OpenContextMenu);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void OnTweetPopup(string columnName, string tweetHtml, int tweetCharacters, string tweetUrl, string quoteUrl){
|
||||||
|
notification.InvokeAsyncSafe(() => {
|
||||||
|
form.OnTweetNotification();
|
||||||
|
notification.ShowNotification(new TweetNotification(columnName, tweetHtml, tweetCharacters, tweetUrl, quoteUrl));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
public void OnTweetSound(){
|
||||||
|
form.InvokeAsyncSafe(() => {
|
||||||
|
form.OnTweetNotification();
|
||||||
|
form.PlayNotificationSound();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
public void DisplayTooltip(string text, bool showInNotification){
|
||||||
|
if (showInNotification){
|
||||||
|
notification.InvokeAsyncSafe(() => notification.DisplayTooltip(text));
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
form.InvokeAsyncSafe(() => form.DisplayTooltip(text));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void SetSessionData(string key, string value){
|
||||||
|
form.InvokeSafe(() => { // do not use InvokeAsyncSafe, return only after invocation
|
||||||
|
SessionData.Add(key, value);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
public void LoadNextNotification(){
|
||||||
|
notification.InvokeAsyncSafe(notification.FinishCurrentNotification);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void ScreenshotTweet(string html, int width, int height){
|
||||||
|
form.InvokeAsyncSafe(() => form.OnTweetScreenshotReady(html, width, height));
|
||||||
|
}
|
||||||
|
|
||||||
|
public void FixClipboard(){
|
||||||
|
form.InvokeAsyncSafe(WindowsUtils.ClipboardStripHtmlStyles);
|
||||||
|
}
|
||||||
|
|
||||||
|
public int GetIdleSeconds(){
|
||||||
|
return NativeMethods.GetIdleSeconds();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void OpenBrowser(string url){
|
||||||
|
BrowserUtils.OpenExternalBrowser(url);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Alert(string type, string contents){
|
||||||
|
MessageBoxIcon icon;
|
||||||
|
|
||||||
|
switch(type){
|
||||||
|
case "error": icon = MessageBoxIcon.Error; break;
|
||||||
|
case "warning": icon = MessageBoxIcon.Warning; break;
|
||||||
|
case "info": icon = MessageBoxIcon.Information; break;
|
||||||
|
default: icon = MessageBoxIcon.None; break;
|
||||||
|
}
|
||||||
|
|
||||||
|
FormMessage.Show("TweetDuck Browser Message", contents, icon, FormMessage.OK);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void CrashDebug(string message){
|
||||||
|
#if DEBUG
|
||||||
|
Log(message);
|
||||||
|
System.Diagnostics.Debugger.Break();
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Log(string data){
|
||||||
|
System.Diagnostics.Debug.WriteLine(data);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
86
Core/Controls/ControlExtensions.cs
Normal file
86
Core/Controls/ControlExtensions.cs
Normal file
@@ -0,0 +1,86 @@
|
|||||||
|
using System;
|
||||||
|
using System.Drawing;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Windows.Forms;
|
||||||
|
using TweetDuck.Core.Utils;
|
||||||
|
|
||||||
|
namespace TweetDuck.Core.Controls{
|
||||||
|
static class ControlExtensions{
|
||||||
|
public static readonly Point InvisibleLocation = new Point(-32000, -32000);
|
||||||
|
|
||||||
|
public static void InvokeSafe(this Control control, Action func){
|
||||||
|
if (control.InvokeRequired){
|
||||||
|
control.Invoke(func);
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
func();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void InvokeAsyncSafe(this Control control, Action func){
|
||||||
|
control.BeginInvoke(func);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static float GetDPIScale(this Control control){
|
||||||
|
using(Graphics graphics = control.CreateGraphics()){
|
||||||
|
return graphics.DpiY/96F;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static bool IsFullyOutsideView(this Form form){
|
||||||
|
return !Screen.AllScreens.Any(screen => screen.WorkingArea.IntersectsWith(form.Bounds));
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void MoveToCenter(this Form targetForm, Form parentForm){
|
||||||
|
targetForm.Location = new Point(parentForm.Location.X+parentForm.Width/2-targetForm.Width/2, parentForm.Location.Y+parentForm.Height/2-targetForm.Height/2);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void SetValueInstant(this ProgressBar bar, int value){
|
||||||
|
if (value == bar.Maximum){
|
||||||
|
bar.Value = value;
|
||||||
|
bar.Value = value-1;
|
||||||
|
bar.Value = value;
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
bar.Value = value+1;
|
||||||
|
bar.Value = value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void SetValueSafe(this NumericUpDown numUpDown, int value){
|
||||||
|
if (value >= numUpDown.Minimum && value <= numUpDown.Maximum){
|
||||||
|
numUpDown.Value = value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void SetValueSafe(this TrackBar trackBar, int value){
|
||||||
|
if (value >= trackBar.Minimum && value <= trackBar.Maximum){
|
||||||
|
trackBar.Value = value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static bool AlignValueToTick(this TrackBar trackBar){
|
||||||
|
if (trackBar.Value % trackBar.SmallChange != 0){
|
||||||
|
trackBar.Value = trackBar.SmallChange*(int)Math.Floor(((double)trackBar.Value/trackBar.SmallChange)+0.5);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
else return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void SetElevated(this Button button){
|
||||||
|
button.Text = " "+button.Text;
|
||||||
|
button.FlatStyle = FlatStyle.System;
|
||||||
|
NativeMethods.SendMessage(button.Handle, NativeMethods.BCM_SETSHIELD, new UIntPtr(0), new IntPtr(1));
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void EnableMultilineShortcuts(this TextBox textBox){
|
||||||
|
textBox.KeyDown += (sender, args) => {
|
||||||
|
if (args.Control && args.KeyCode == Keys.A){
|
||||||
|
((TextBox)sender).SelectAll();
|
||||||
|
args.SuppressKeyPress = true;
|
||||||
|
args.Handled = true;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
16
Core/Controls/FlatButton.cs
Normal file
16
Core/Controls/FlatButton.cs
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
using System;
|
||||||
|
using System.Windows.Forms;
|
||||||
|
|
||||||
|
namespace TweetDuck.Core.Controls{
|
||||||
|
class FlatButton : Button{
|
||||||
|
protected override bool ShowFocusCues => false;
|
||||||
|
|
||||||
|
public FlatButton(){
|
||||||
|
GotFocus += FlatButton_GotFocus;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void FlatButton_GotFocus(object sender, EventArgs e){ // removes extra border when focused
|
||||||
|
NotifyDefault(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
33
Core/Controls/FlatProgressBar.Designer.cs
generated
33
Core/Controls/FlatProgressBar.Designer.cs
generated
@@ -1,33 +0,0 @@
|
|||||||
namespace TweetDick.Core.Controls {
|
|
||||||
partial class FlatProgressBar {
|
|
||||||
/// <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 (brush != null)brush.Dispose();
|
|
||||||
|
|
||||||
if (disposing && (components != null)) {
|
|
||||||
components.Dispose();
|
|
||||||
}
|
|
||||||
base.Dispose(disposing);
|
|
||||||
}
|
|
||||||
|
|
||||||
#region Component Designer generated code
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Required method for Designer support - do not modify
|
|
||||||
/// the contents of this method with the code editor.
|
|
||||||
/// </summary>
|
|
||||||
private void InitializeComponent() {
|
|
||||||
components = new System.ComponentModel.Container();
|
|
||||||
}
|
|
||||||
|
|
||||||
#endregion
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,35 +1,37 @@
|
|||||||
using System.Drawing;
|
using System.Drawing;
|
||||||
using System.Windows.Forms;
|
using System.Windows.Forms;
|
||||||
|
|
||||||
namespace TweetDick.Core.Controls{
|
namespace TweetDuck.Core.Controls{
|
||||||
public partial class FlatProgressBar : ProgressBar{
|
sealed class FlatProgressBar : ProgressBar{
|
||||||
private SolidBrush brush;
|
private readonly SolidBrush brush;
|
||||||
|
|
||||||
public FlatProgressBar(){
|
public FlatProgressBar(){
|
||||||
SetStyle(ControlStyles.UserPaint,true);
|
brush = new SolidBrush(Color.White);
|
||||||
SetStyle(ControlStyles.OptimizedDoubleBuffer,true);
|
|
||||||
|
SetStyle(ControlStyles.UserPaint, true);
|
||||||
|
SetStyle(ControlStyles.OptimizedDoubleBuffer, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void SetValueInstant(int value){
|
public void SetValueInstant(int value){
|
||||||
if (value == Maximum){
|
ControlExtensions.SetValueInstant(this, value);
|
||||||
Value = value;
|
|
||||||
Value = value-1;
|
|
||||||
Value = value;
|
|
||||||
}
|
|
||||||
else{
|
|
||||||
Value = value+1;
|
|
||||||
Value = value;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void OnPaint(PaintEventArgs e){
|
protected override void OnPaint(PaintEventArgs e){
|
||||||
if (brush == null || brush.Color != ForeColor){
|
if (brush.Color != ForeColor){
|
||||||
brush = new SolidBrush(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){
|
||||||
|
base.Dispose(disposing);
|
||||||
|
|
||||||
|
if (disposing){
|
||||||
|
brush.Dispose();
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
23
Core/Controls/LabelVertical.cs
Normal file
23
Core/Controls/LabelVertical.cs
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
using System;
|
||||||
|
using System.Drawing;
|
||||||
|
using System.Windows.Forms;
|
||||||
|
|
||||||
|
namespace TweetDuck.Core.Controls{
|
||||||
|
sealed class LabelVertical : Label{
|
||||||
|
public int LineHeight { get; set; }
|
||||||
|
|
||||||
|
protected override void OnPaint(PaintEventArgs e){
|
||||||
|
int y = (int)Math.Floor((ClientRectangle.Height-Text.Length*LineHeight)/2F)-2; // 2 = random
|
||||||
|
|
||||||
|
using(Brush brush = new SolidBrush(ForeColor)){
|
||||||
|
foreach(char chr in Text){
|
||||||
|
string str = chr.ToString();
|
||||||
|
float x = (ClientRectangle.Width-e.Graphics.MeasureString(str, Font).Width)/2F;
|
||||||
|
|
||||||
|
e.Graphics.DrawString(str, Font, brush, x, y);
|
||||||
|
y += LineHeight;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
18
Core/Controls/NumericUpDownEx.cs
Normal file
18
Core/Controls/NumericUpDownEx.cs
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
using System.ComponentModel;
|
||||||
|
using System.Windows.Forms;
|
||||||
|
|
||||||
|
namespace TweetDuck.Core.Controls{
|
||||||
|
sealed class NumericUpDownEx : NumericUpDown{
|
||||||
|
public string TextSuffix { get; set ; }
|
||||||
|
|
||||||
|
protected override void UpdateEditText(){
|
||||||
|
base.UpdateEditText();
|
||||||
|
|
||||||
|
if (LicenseManager.UsageMode != LicenseUsageMode.Designtime){
|
||||||
|
ChangingText = true;
|
||||||
|
Text += TextSuffix;
|
||||||
|
ChangingText = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,58 +0,0 @@
|
|||||||
using System;
|
|
||||||
using System.Windows.Forms;
|
|
||||||
|
|
||||||
namespace TweetDick.Core.Controls{
|
|
||||||
public partial class RichTextLabel : RichTextBox{
|
|
||||||
/// <summary>
|
|
||||||
/// Wraps the body of a RTF formatted string with default tags and formatting.
|
|
||||||
/// </summary>
|
|
||||||
public static string Wrap(string str){
|
|
||||||
string rtf = @"{\rtf1\ansi\ansicpg1250\deff0\deflang1029{\fonttbl{\f0\fnil\fcharset0 Microsoft Sans Serif;}}";
|
|
||||||
rtf += @"{\*\generator Msftedit 4.20.69.1337;}\viewkind4\uc1\pard\sa200\sl276\slmult1\lang1036\f0\fs16 ";
|
|
||||||
rtf += str;
|
|
||||||
return rtf;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Wraps URL tags around a link.
|
|
||||||
/// </summary>
|
|
||||||
public static string AddLink(string url){
|
|
||||||
return @"{\field{\*\fldinst{HYPERLINK """+url+@"""}}{\fldrslt{\ul\cf1 "+url+@"}}}";
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Uses v5 of RichTextBox, which fixes URLs and other crap.
|
|
||||||
/// </summary>
|
|
||||||
protected override CreateParams CreateParams{
|
|
||||||
get{
|
|
||||||
CreateParams createParams = base.CreateParams;
|
|
||||||
|
|
||||||
if (Program.LoadLibrary("msftedit.dll") != IntPtr.Zero){
|
|
||||||
createParams.ClassName = "RICHEDIT50W";
|
|
||||||
}
|
|
||||||
|
|
||||||
return createParams;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public RichTextLabel(){
|
|
||||||
InitializeComponent();
|
|
||||||
|
|
||||||
SetStyle(ControlStyles.Selectable,false);
|
|
||||||
SetStyle(ControlStyles.UserMouse,true);
|
|
||||||
SetStyle(ControlStyles.SupportsTransparentBackColor,true);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void RichTextLabel_MouseEnter(object sender, EventArgs e){
|
|
||||||
Cursor = Cursors.Default;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected override void WndProc(ref Message m){
|
|
||||||
if (m.Msg == 0x204 || m.Msg == 0x205){ // WM_RBUTTONDOWN, WM_RBUTTONUP
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
base.WndProc(ref m);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
28
Core/FormBrowser.Designer.cs
generated
28
Core/FormBrowser.Designer.cs
generated
@@ -1,4 +1,4 @@
|
|||||||
namespace TweetDick.Core {
|
namespace TweetDuck.Core {
|
||||||
sealed partial class FormBrowser {
|
sealed partial class FormBrowser {
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Required designer variable.
|
/// Required designer variable.
|
||||||
@@ -23,23 +23,43 @@
|
|||||||
/// the contents of this method with the code editor.
|
/// the contents of this method with the code editor.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
private void InitializeComponent() {
|
private void InitializeComponent() {
|
||||||
System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(FormBrowser));
|
this.components = new System.ComponentModel.Container();
|
||||||
|
this.trayIcon = new TweetDuck.Core.TrayIcon(this.components);
|
||||||
|
this.toolTip = new System.Windows.Forms.ToolTip(this.components);
|
||||||
|
this.timerResize = new System.Windows.Forms.Timer(this.components);
|
||||||
this.SuspendLayout();
|
this.SuspendLayout();
|
||||||
//
|
//
|
||||||
|
// timerResize
|
||||||
|
//
|
||||||
|
this.timerResize.Interval = 500;
|
||||||
|
this.timerResize.Tick += new System.EventHandler(this.timerResize_Tick);
|
||||||
|
//
|
||||||
// FormBrowser
|
// FormBrowser
|
||||||
//
|
//
|
||||||
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
|
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
|
||||||
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
|
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
|
||||||
this.Icon = TweetDick.Properties.Resources.icon;
|
this.BackColor = TweetDuck.Core.Utils.TwitterUtils.BackgroundColor;
|
||||||
this.Location = new System.Drawing.Point(-32000, -32000);
|
this.ClientSize = new System.Drawing.Size(324, 386);
|
||||||
|
this.Icon = Properties.Resources.icon;
|
||||||
|
this.Location = TweetDuck.Core.Controls.ControlExtensions.InvisibleLocation;
|
||||||
|
this.MinimumSize = new System.Drawing.Size(340, 424);
|
||||||
this.Name = "FormBrowser";
|
this.Name = "FormBrowser";
|
||||||
this.StartPosition = System.Windows.Forms.FormStartPosition.Manual;
|
this.StartPosition = System.Windows.Forms.FormStartPosition.Manual;
|
||||||
|
this.Activated += new System.EventHandler(this.FormBrowser_Activated);
|
||||||
|
this.FormClosing += new System.Windows.Forms.FormClosingEventHandler(this.FormBrowser_FormClosing);
|
||||||
|
this.FormClosed += new System.Windows.Forms.FormClosedEventHandler(this.FormBrowser_FormClosed);
|
||||||
|
this.LocationChanged += new System.EventHandler(this.FormBrowser_LocationChanged);
|
||||||
this.ResizeEnd += new System.EventHandler(this.FormBrowser_ResizeEnd);
|
this.ResizeEnd += new System.EventHandler(this.FormBrowser_ResizeEnd);
|
||||||
|
this.Resize += new System.EventHandler(this.FormBrowser_Resize);
|
||||||
this.ResumeLayout(false);
|
this.ResumeLayout(false);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
|
private TrayIcon trayIcon;
|
||||||
|
private System.Windows.Forms.ToolTip toolTip;
|
||||||
|
private System.Windows.Forms.Timer timerResize;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,151 +1,532 @@
|
|||||||
using System.Windows.Forms;
|
using CefSharp;
|
||||||
using CefSharp.WinForms;
|
using CefSharp.WinForms;
|
||||||
using System;
|
using System;
|
||||||
using System.Linq;
|
|
||||||
using TweetDick.Configuration;
|
|
||||||
using CefSharp;
|
|
||||||
using TweetDick.Core.Handling;
|
|
||||||
using TweetDick.Core.Other;
|
|
||||||
using System.Drawing;
|
using System.Drawing;
|
||||||
using TweetDick.Resources;
|
using System.Linq;
|
||||||
|
using System.Windows.Forms;
|
||||||
|
using TweetDuck.Configuration;
|
||||||
|
using TweetDuck.Core.Bridge;
|
||||||
|
using TweetDuck.Core.Controls;
|
||||||
|
using TweetDuck.Core.Handling;
|
||||||
|
using TweetDuck.Core.Handling.General;
|
||||||
|
using TweetDuck.Core.Notification;
|
||||||
|
using TweetDuck.Core.Notification.Screenshot;
|
||||||
|
using TweetDuck.Core.Other;
|
||||||
|
using TweetDuck.Core.Other.Settings;
|
||||||
|
using TweetDuck.Core.Utils;
|
||||||
|
using TweetDuck.Plugins;
|
||||||
|
using TweetDuck.Plugins.Enums;
|
||||||
|
using TweetDuck.Plugins.Events;
|
||||||
|
using TweetDuck.Resources;
|
||||||
|
using TweetDuck.Updates;
|
||||||
|
using TweetDuck.Updates.Events;
|
||||||
|
using TweetLib.Audio;
|
||||||
|
|
||||||
namespace TweetDick.Core{
|
namespace TweetDuck.Core{
|
||||||
sealed partial class FormBrowser : Form{
|
sealed partial class FormBrowser : Form{
|
||||||
private static UserConfig Config{
|
private static UserConfig Config => Program.UserConfig;
|
||||||
get{
|
|
||||||
return Program.UserConfig;
|
public bool IsWaiting{
|
||||||
|
set{
|
||||||
|
if (value){
|
||||||
|
browser.Enabled = false;
|
||||||
|
Cursor = Cursors.WaitCursor;
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
browser.Enabled = true;
|
||||||
|
Cursor = Cursors.Default;
|
||||||
|
|
||||||
|
if (Focused){ // re-focus browser only if the window or a child is activated
|
||||||
|
browser.Focus();
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public string UpdateInstallerPath { get; private set; }
|
||||||
|
|
||||||
private readonly ChromiumWebBrowser browser;
|
private readonly ChromiumWebBrowser browser;
|
||||||
private readonly TweetDeckBridge bridge;
|
private readonly PluginManager plugins;
|
||||||
private readonly FormNotification notification;
|
private readonly UpdateHandler updates;
|
||||||
|
private readonly FormNotificationTweet notification;
|
||||||
|
private readonly ContextMenu contextMenu;
|
||||||
|
private readonly MemoryUsageTracker memoryUsageTracker;
|
||||||
|
|
||||||
private FormSettings currentFormSettings;
|
|
||||||
private FormAbout currentFormAbout;
|
|
||||||
private bool isLoaded;
|
private bool isLoaded;
|
||||||
|
private bool isBrowserReady;
|
||||||
|
private FormWindowState prevState;
|
||||||
|
|
||||||
public FormBrowser(){
|
private TweetScreenshotManager notificationScreenshotManager;
|
||||||
|
private SoundNotification soundNotification;
|
||||||
|
|
||||||
|
public FormBrowser(PluginManager pluginManager, UpdaterSettings updaterSettings){
|
||||||
InitializeComponent();
|
InitializeComponent();
|
||||||
|
|
||||||
Text = Program.BrandName;
|
Text = Program.BrandName;
|
||||||
|
|
||||||
bridge = new TweetDeckBridge(this);
|
this.plugins = pluginManager;
|
||||||
|
this.plugins.Reloaded += plugins_Reloaded;
|
||||||
|
this.plugins.PluginChangedState += plugins_PluginChangedState;
|
||||||
|
|
||||||
browser = new ChromiumWebBrowser("https://tweetdeck.twitter.com/"){ MenuHandler = new ContextMenuHandler(this) };
|
this.contextMenu = ContextMenuBrowser.CreateMenu(this);
|
||||||
browser.LoadingStateChanged += Browser_LoadingStateChanged;
|
this.memoryUsageTracker = new MemoryUsageTracker("TDGF_tryRunCleanup");
|
||||||
browser.FrameLoadEnd += Browser_FrameLoadEnd;
|
|
||||||
browser.RegisterJsObject("$TD",bridge);
|
|
||||||
|
|
||||||
|
this.notification = new FormNotificationTweet(this, plugins){
|
||||||
|
#if DEBUG
|
||||||
|
CanMoveWindow = () => (ModifierKeys & Keys.Alt) == Keys.Alt
|
||||||
|
#else
|
||||||
|
CanMoveWindow = () => false
|
||||||
|
#endif
|
||||||
|
};
|
||||||
|
|
||||||
|
this.notification.Show();
|
||||||
|
|
||||||
|
this.browser = new ChromiumWebBrowser("https://tweetdeck.twitter.com/"){
|
||||||
|
MenuHandler = new ContextMenuBrowser(this),
|
||||||
|
JsDialogHandler = new JavaScriptDialogHandler(),
|
||||||
|
LifeSpanHandler = new LifeSpanHandler(),
|
||||||
|
RequestHandler = new RequestHandlerBrowser()
|
||||||
|
};
|
||||||
|
|
||||||
|
#if DEBUG
|
||||||
|
this.browser.ConsoleMessage += BrowserUtils.HandleConsoleMessage;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
this.browser.LoadingStateChanged += browser_LoadingStateChanged;
|
||||||
|
this.browser.FrameLoadStart += browser_FrameLoadStart;
|
||||||
|
this.browser.FrameLoadEnd += browser_FrameLoadEnd;
|
||||||
|
this.browser.LoadError += browser_LoadError;
|
||||||
|
this.browser.RegisterAsyncJsObject("$TD", new TweetDeckBridge(this, notification));
|
||||||
|
this.browser.RegisterAsyncJsObject("$TDP", plugins.Bridge);
|
||||||
|
|
||||||
|
browser.BrowserSettings.BackgroundColor = (uint)TwitterUtils.BackgroundColor.ToArgb();
|
||||||
|
browser.Dock = DockStyle.None;
|
||||||
|
browser.Location = ControlExtensions.InvisibleLocation;
|
||||||
Controls.Add(browser);
|
Controls.Add(browser);
|
||||||
|
|
||||||
Disposed += (sender, args) => browser.Dispose();
|
Controls.Add(new MenuStrip{ Visible = false }); // fixes Alt freezing the program in Win 10 Anniversary Update
|
||||||
|
|
||||||
notification = new FormNotification(this,bridge,true){ CanMoveWindow = () => false };
|
Disposed += (sender, args) => {
|
||||||
notification.Show();
|
memoryUsageTracker.Dispose();
|
||||||
|
|
||||||
|
browser.Dispose();
|
||||||
|
contextMenu.Dispose();
|
||||||
|
|
||||||
|
notificationScreenshotManager?.Dispose();
|
||||||
|
soundNotification?.Dispose();
|
||||||
|
};
|
||||||
|
|
||||||
|
this.trayIcon.ClickRestore += trayIcon_ClickRestore;
|
||||||
|
this.trayIcon.ClickClose += trayIcon_ClickClose;
|
||||||
|
Config.TrayBehaviorChanged += Config_TrayBehaviorChanged;
|
||||||
|
|
||||||
|
UpdateTrayIcon();
|
||||||
|
|
||||||
|
Config.MuteToggled += Config_MuteToggled;
|
||||||
|
Config.ZoomLevelChanged += Config_ZoomLevelChanged;
|
||||||
|
|
||||||
|
this.updates = new UpdateHandler(browser, updaterSettings);
|
||||||
|
this.updates.UpdateAccepted += updates_UpdateAccepted;
|
||||||
|
this.updates.UpdateDismissed += updates_UpdateDismissed;
|
||||||
|
|
||||||
|
RestoreWindow();
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void WndProc(ref Message m){
|
private bool TryBringToFront<T>() where T : Form{
|
||||||
FormWindowState prevState = WindowState;
|
T form = Application.OpenForms.OfType<T>().FirstOrDefault();
|
||||||
base.WndProc(ref m);
|
|
||||||
|
|
||||||
if (prevState != WindowState && m.Msg == 0x0014){ // WM_ERASEBKGND
|
if (form != null){
|
||||||
FormBrowser_WindowStateChanged(this,new EventArgs());
|
form.BringToFront();
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
else return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void ShowChildForm(Form form){
|
private void ShowChildForm(Form form){
|
||||||
|
form.VisibleChanged += (sender, args) => form.MoveToCenter(this);
|
||||||
form.Show(this);
|
form.Show(this);
|
||||||
form.Location = new Point(Location.X+Width/2-form.Width/2,Location.Y+Height/2-form.Height/2);
|
}
|
||||||
|
|
||||||
|
public void ForceClose(){
|
||||||
|
trayIcon.Visible = false; // checked in FormClosing event
|
||||||
|
Close();
|
||||||
}
|
}
|
||||||
|
|
||||||
// window setup
|
// window setup
|
||||||
|
|
||||||
private void SetupWindow(){
|
private void RestoreWindow(){
|
||||||
if (Config.IsCustomWindowLocationSet){
|
Config.BrowserWindow.Restore(this, true);
|
||||||
Location = Config.WindowLocation;
|
prevState = WindowState;
|
||||||
Size = Config.WindowSize;
|
|
||||||
WindowState = Config.IsMaximized ? FormWindowState.Maximized : FormWindowState.Normal;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!Config.IsCustomWindowLocationSet || !Screen.AllScreens.Any(screen => screen.WorkingArea.IntersectsWith(Bounds))){
|
|
||||||
Location = Screen.PrimaryScreen.WorkingArea.Location;
|
|
||||||
Size = Screen.PrimaryScreen.WorkingArea.Size;
|
|
||||||
WindowState = FormWindowState.Maximized;
|
|
||||||
}
|
|
||||||
|
|
||||||
isLoaded = true;
|
isLoaded = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void OnBrowserReady(){
|
||||||
|
if (!isBrowserReady){
|
||||||
|
browser.Location = Point.Empty;
|
||||||
|
browser.Dock = DockStyle.Fill;
|
||||||
|
isBrowserReady = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void UpdateTrayIcon(){
|
||||||
|
trayIcon.Visible = Config.TrayBehavior.ShouldDisplayIcon();
|
||||||
|
}
|
||||||
|
|
||||||
// active event handlers
|
// active event handlers
|
||||||
|
|
||||||
private void Browser_LoadingStateChanged(object sender, LoadingStateChangedEventArgs e){
|
private void browser_LoadingStateChanged(object sender, LoadingStateChangedEventArgs e){
|
||||||
if (!e.IsLoading){
|
if (!e.IsLoading){
|
||||||
Invoke(new Action(SetupWindow));
|
foreach(string word in TwitterUtils.DictionaryWords){
|
||||||
browser.LoadingStateChanged -= Browser_LoadingStateChanged;
|
browser.AddWordToDictionary(word);
|
||||||
|
}
|
||||||
|
|
||||||
|
BeginInvoke(new Action(OnBrowserReady));
|
||||||
|
browser.LoadingStateChanged -= browser_LoadingStateChanged;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void Browser_FrameLoadEnd(object sender, FrameLoadEndEventArgs e){
|
private void browser_FrameLoadStart(object sender, FrameLoadStartEventArgs e){
|
||||||
if (e.Frame.IsMain){
|
if (e.Frame.IsMain){
|
||||||
string js = ScriptLoader.LoadResource("code.js");
|
memoryUsageTracker.Stop();
|
||||||
|
|
||||||
if (js != null){
|
if (Config.ZoomLevel != 100){
|
||||||
browser.ExecuteScriptAsync(js);
|
BrowserUtils.SetZoomLevel(browser.GetBrowser(), Config.ZoomLevel);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (TwitterUtils.IsTwitterWebsite(e.Frame)){
|
||||||
|
ScriptLoader.ExecuteFile(e.Frame, "twitter.js");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void browser_FrameLoadEnd(object sender, FrameLoadEndEventArgs e){
|
||||||
|
if (e.Frame.IsMain && TwitterUtils.IsTweetDeckWebsite(e.Frame)){
|
||||||
|
e.Frame.ExecuteJavaScriptAsync(TwitterUtils.BackgroundColorFix);
|
||||||
|
|
||||||
|
UpdateProperties(PropertyBridge.Environment.Browser);
|
||||||
|
TweetDeckBridge.RestoreSessionData(e.Frame);
|
||||||
|
ScriptLoader.ExecuteFile(e.Frame, "code.js");
|
||||||
|
ReinjectCustomCSS(Config.CustomBrowserCSS);
|
||||||
|
|
||||||
|
if (plugins.HasAnyPlugin(PluginEnvironment.Browser)){
|
||||||
|
ScriptLoader.ExecuteFile(e.Frame, PluginManager.PluginBrowserScriptFile);
|
||||||
|
ScriptLoader.ExecuteFile(e.Frame, PluginManager.PluginGlobalScriptFile);
|
||||||
|
plugins.ExecutePlugins(e.Frame, PluginEnvironment.Browser, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
TweetDeckBridge.ResetStaticProperties();
|
||||||
|
|
||||||
|
if (Program.SystemConfig.EnableBrowserGCReload){
|
||||||
|
memoryUsageTracker.Start(this, e.Browser, Program.SystemConfig.BrowserMemoryThreshold);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void browser_LoadError(object sender, LoadErrorEventArgs e){
|
||||||
|
if (e.ErrorCode == CefErrorCode.Aborted){
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!e.FailedUrl.StartsWith("http://td/", StringComparison.Ordinal)){
|
||||||
|
string errorPage = ScriptLoader.LoadResource("pages/error.html", true);
|
||||||
|
|
||||||
|
if (errorPage != null){
|
||||||
|
browser.LoadHtml(errorPage.Replace("{err}", BrowserUtils.GetErrorName(e.ErrorCode)), "http://td/error");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void timerResize_Tick(object sender, EventArgs e){
|
||||||
|
FormBrowser_ResizeEnd(this, e); // also stops timer
|
||||||
|
}
|
||||||
|
|
||||||
|
private void FormBrowser_Activated(object sender, EventArgs e){
|
||||||
|
if (!isLoaded)return;
|
||||||
|
|
||||||
|
trayIcon.HasNotifications = false;
|
||||||
|
|
||||||
|
if (!browser.Enabled){ // when taking a screenshot, the window is unfocused and
|
||||||
|
browser.Enabled = true; // the browser is disabled; if the user clicks back into
|
||||||
|
} // the window, enable the browser again
|
||||||
|
}
|
||||||
|
|
||||||
|
private void FormBrowser_LocationChanged(object sender, EventArgs e){
|
||||||
|
if (!isLoaded)return;
|
||||||
|
|
||||||
|
timerResize.Stop();
|
||||||
|
timerResize.Start();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void FormBrowser_Resize(object sender, EventArgs e){
|
||||||
|
if (!isLoaded)return;
|
||||||
|
|
||||||
|
if (WindowState != prevState){
|
||||||
|
prevState = WindowState;
|
||||||
|
|
||||||
|
if (WindowState == FormWindowState.Minimized){
|
||||||
|
if (Config.TrayBehavior.ShouldHideOnMinimize()){
|
||||||
|
Hide(); // hides taskbar too?! welp that works I guess
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
FormBrowser_ResizeEnd(sender, e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
timerResize.Stop();
|
||||||
|
timerResize.Start();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void FormBrowser_ResizeEnd(object sender, EventArgs e){ // also triggers when the window moves
|
private void FormBrowser_ResizeEnd(object sender, EventArgs e){ // also triggers when the window moves
|
||||||
if (!isLoaded)return;
|
if (!isLoaded)return;
|
||||||
|
|
||||||
Config.WindowLocation = Location;
|
timerResize.Stop();
|
||||||
Config.WindowSize = Size;
|
|
||||||
Config.Save();
|
if (Location != ControlExtensions.InvisibleLocation){
|
||||||
|
Config.BrowserWindow.Save(this);
|
||||||
|
Config.Save();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void FormBrowser_WindowStateChanged(object sender, EventArgs e){
|
private void FormBrowser_FormClosing(object sender, FormClosingEventArgs e){
|
||||||
if (!isLoaded)return;
|
if (!isLoaded)return;
|
||||||
|
|
||||||
Config.IsMaximized = WindowState != FormWindowState.Normal;
|
if (Config.TrayBehavior.ShouldHideOnClose() && trayIcon.Visible && e.CloseReason == CloseReason.UserClosing){
|
||||||
FormBrowser_ResizeEnd(sender,e);
|
Hide(); // hides taskbar too?! welp that works I guess
|
||||||
|
e.Cancel = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void FormBrowser_FormClosed(object sender, FormClosedEventArgs e){
|
||||||
|
if (isLoaded && UpdateInstallerPath == null){
|
||||||
|
updates.CleanupDownload();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void Config_MuteToggled(object sender, EventArgs e){
|
||||||
|
UpdateProperties(PropertyBridge.Environment.Browser);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void Config_ZoomLevelChanged(object sender, EventArgs e){
|
||||||
|
BrowserUtils.SetZoomLevel(browser.GetBrowser(), Config.ZoomLevel);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void Config_TrayBehaviorChanged(object sender, EventArgs e){
|
||||||
|
UpdateTrayIcon();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void trayIcon_ClickRestore(object sender, EventArgs e){
|
||||||
|
Show();
|
||||||
|
RestoreWindow();
|
||||||
|
Activate();
|
||||||
|
UpdateTrayIcon();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void trayIcon_ClickClose(object sender, EventArgs e){
|
||||||
|
ForceClose();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void plugins_Reloaded(object sender, PluginErrorEventArgs e){
|
||||||
|
ReloadToTweetDeck();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void plugins_PluginChangedState(object sender, PluginChangedStateEventArgs e){
|
||||||
|
browser.ExecuteScriptAsync("window.TDPF_setPluginState", e.Plugin, e.IsEnabled);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void updates_UpdateAccepted(object sender, UpdateAcceptedEventArgs e){
|
||||||
|
this.InvokeAsyncSafe(() => {
|
||||||
|
foreach(Form form in Application.OpenForms.Cast<Form>().Reverse()){
|
||||||
|
if (form is FormSettings || form is FormPlugins || form is FormAbout){
|
||||||
|
form.Close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
updates.BeginUpdateDownload(this, e.UpdateInfo, update => {
|
||||||
|
if (update.DownloadStatus == UpdateDownloadStatus.Done){
|
||||||
|
UpdateInstallerPath = update.InstallerPath;
|
||||||
|
}
|
||||||
|
|
||||||
|
ForceClose();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private void updates_UpdateDismissed(object sender, UpdateDismissedEventArgs e){
|
||||||
|
this.InvokeAsyncSafe(() => {
|
||||||
|
Config.DismissedUpdate = e.VersionTag;
|
||||||
|
Config.Save();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private void soundNotification_PlaybackError(object sender, PlaybackErrorEventArgs e){
|
||||||
|
e.Ignore = true;
|
||||||
|
|
||||||
|
using(FormMessage form = new FormMessage("Notification Sound Error", "Could not play custom notification sound.\n"+e.Message, MessageBoxIcon.Error)){
|
||||||
|
form.AddButton(FormMessage.Ignore, ControlType.Cancel | ControlType.Focused);
|
||||||
|
|
||||||
|
Button btnOpenSettings = form.AddButton("View Options");
|
||||||
|
btnOpenSettings.Width += 16;
|
||||||
|
btnOpenSettings.Location = new Point(btnOpenSettings.Location.X-16, btnOpenSettings.Location.Y);
|
||||||
|
|
||||||
|
if (form.ShowDialog() == DialogResult.OK && form.ClickedButton == btnOpenSettings){
|
||||||
|
OpenSettings(typeof(TabSettingsSounds));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void WndProc(ref Message m){
|
||||||
|
if (isLoaded){
|
||||||
|
if (m.Msg == Program.WindowRestoreMessage){
|
||||||
|
if (WindowsUtils.CurrentProcessID == m.WParam.ToInt32()){
|
||||||
|
trayIcon_ClickRestore(trayIcon, new EventArgs());
|
||||||
|
}
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
else if (m.Msg == Program.SubProcessMessage){
|
||||||
|
int processId = m.WParam.ToInt32();
|
||||||
|
|
||||||
|
if (WindowsUtils.IsChildProcess(processId)){ // child process is checked in two places for safety
|
||||||
|
BrowserProcesses.Link(m.LParam.ToInt32(), processId);
|
||||||
|
}
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isBrowserReady && m.Msg == NativeMethods.WM_PARENTNOTIFY && (m.WParam.ToInt32() & 0xFFFF) == NativeMethods.WM_XBUTTONDOWN){
|
||||||
|
browser.ExecuteScriptAsync("TDGF_onMouseClickExtra", (m.WParam.ToInt32() >> 16) & 0xFFFF);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
base.WndProc(ref m);
|
||||||
|
}
|
||||||
|
|
||||||
|
// notification helpers
|
||||||
|
|
||||||
|
public FormNotificationMain CreateNotificationForm(bool enableContextMenu){
|
||||||
|
return new FormNotificationMain(this, plugins, enableContextMenu);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void PauseNotification(){
|
||||||
|
notification.PauseNotification();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void ResumeNotification(){
|
||||||
|
notification.ResumeNotification();
|
||||||
|
}
|
||||||
|
|
||||||
|
// javascript calls
|
||||||
|
|
||||||
|
public void ReinjectCustomCSS(string css){
|
||||||
|
browser.ExecuteScriptAsync("TDGF_reinjectCustomCSS", css?.Replace(Environment.NewLine, " ") ?? string.Empty);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void UpdateProperties(PropertyBridge.Environment environment){
|
||||||
|
browser.ExecuteScriptAsync(PropertyBridge.GenerateScript(environment));
|
||||||
|
}
|
||||||
|
|
||||||
|
public void ReloadToTweetDeck(){
|
||||||
|
browser.ExecuteScriptAsync($"if(window.TDGF_reload)window.TDGF_reload();else window.location.href='{TwitterUtils.TweetDeckURL}'");
|
||||||
}
|
}
|
||||||
|
|
||||||
// callback handlers
|
// callback handlers
|
||||||
|
|
||||||
public void InvokeSafe(Action func){
|
public void OpenContextMenu(){
|
||||||
if (InvokeRequired){
|
contextMenu.Show(this, PointToClient(Cursor.Position));
|
||||||
Invoke(func);
|
|
||||||
}
|
|
||||||
else{
|
|
||||||
func();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void OpenSettings(){
|
public void OpenSettings(){
|
||||||
if (currentFormSettings != null){
|
OpenSettings(null);
|
||||||
currentFormSettings.BringToFront();
|
}
|
||||||
}
|
|
||||||
else{
|
public void OpenSettings(Type startTab){
|
||||||
currentFormSettings = new FormSettings(this);
|
if (!TryBringToFront<FormSettings>()){
|
||||||
currentFormSettings.FormClosed += (sender, args) => currentFormSettings = null;
|
bool prevEnableUpdateCheck = Config.EnableUpdateCheck;
|
||||||
ShowChildForm(currentFormSettings);
|
|
||||||
|
FormSettings form = new FormSettings(this, plugins, updates, startTab);
|
||||||
|
|
||||||
|
form.FormClosed += (sender, args) => {
|
||||||
|
if (!prevEnableUpdateCheck && Config.EnableUpdateCheck){
|
||||||
|
updates.DismissUpdate(string.Empty);
|
||||||
|
updates.Check(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!Config.EnableTrayHighlight){
|
||||||
|
trayIcon.HasNotifications = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Program.SystemConfig.EnableBrowserGCReload){
|
||||||
|
memoryUsageTracker.Start(this, browser.GetBrowser(), Program.SystemConfig.BrowserMemoryThreshold);
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
memoryUsageTracker.Stop();
|
||||||
|
}
|
||||||
|
|
||||||
|
UpdateProperties(PropertyBridge.Environment.Browser);
|
||||||
|
|
||||||
|
notification.RequiresResize = true;
|
||||||
|
form.Dispose();
|
||||||
|
};
|
||||||
|
|
||||||
|
ShowChildForm(form);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void OpenAbout(){
|
public void OpenAbout(){
|
||||||
if (currentFormAbout != null){
|
if (!TryBringToFront<FormAbout>()){
|
||||||
currentFormAbout.BringToFront();
|
ShowChildForm(new FormAbout());
|
||||||
}
|
|
||||||
else{
|
|
||||||
currentFormAbout = new FormAbout();
|
|
||||||
currentFormAbout.FormClosed += (sender, args) => currentFormAbout = null;
|
|
||||||
ShowChildForm(currentFormAbout);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void OnTweetPopup(TweetNotification tweet){
|
public void OpenPlugins(){
|
||||||
notification.ShowNotification(tweet);
|
if (!TryBringToFront<FormPlugins>()){
|
||||||
|
ShowChildForm(new FormPlugins(plugins));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void OnTweetNotification(){ // may be called multiple times, once for each type of notification
|
||||||
|
if (Config.EnableTrayHighlight && !ContainsFocus){
|
||||||
|
trayIcon.HasNotifications = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void PlayNotificationSound(){
|
||||||
|
if (Config.NotificationSoundPath.Length == 0){
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (soundNotification == null){
|
||||||
|
soundNotification = new SoundNotification();
|
||||||
|
soundNotification.PlaybackError += soundNotification_PlaybackError;
|
||||||
|
}
|
||||||
|
|
||||||
|
soundNotification.Play(Config.NotificationSoundPath);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void OnTweetScreenshotReady(string html, int width, int height){
|
||||||
|
if (notificationScreenshotManager == null){
|
||||||
|
notificationScreenshotManager = new TweetScreenshotManager(this, plugins);
|
||||||
|
}
|
||||||
|
|
||||||
|
notificationScreenshotManager.Trigger(html, width, height);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void DisplayTooltip(string text){
|
||||||
|
if (string.IsNullOrEmpty(text)){
|
||||||
|
toolTip.Hide(this);
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
Point position = PointToClient(Cursor.Position);
|
||||||
|
position.Offset(20, 10);
|
||||||
|
toolTip.Show(text, this, position);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void TriggerTweetScreenshot(){
|
||||||
|
browser.ExecuteScriptAsync("TDGF_triggerScreenshot()");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
129
Core/FormBrowser.resx
Normal file
129
Core/FormBrowser.resx
Normal file
@@ -0,0 +1,129 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<root>
|
||||||
|
<!--
|
||||||
|
Microsoft ResX Schema
|
||||||
|
|
||||||
|
Version 2.0
|
||||||
|
|
||||||
|
The primary goals of this format is to allow a simple XML format
|
||||||
|
that is mostly human readable. The generation and parsing of the
|
||||||
|
various data types are done through the TypeConverter classes
|
||||||
|
associated with the data types.
|
||||||
|
|
||||||
|
Example:
|
||||||
|
|
||||||
|
... ado.net/XML headers & schema ...
|
||||||
|
<resheader name="resmimetype">text/microsoft-resx</resheader>
|
||||||
|
<resheader name="version">2.0</resheader>
|
||||||
|
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
|
||||||
|
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
|
||||||
|
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
|
||||||
|
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
|
||||||
|
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
|
||||||
|
<value>[base64 mime encoded serialized .NET Framework object]</value>
|
||||||
|
</data>
|
||||||
|
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
|
||||||
|
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
|
||||||
|
<comment>This is a comment</comment>
|
||||||
|
</data>
|
||||||
|
|
||||||
|
There are any number of "resheader" rows that contain simple
|
||||||
|
name/value pairs.
|
||||||
|
|
||||||
|
Each data row contains a name, and value. The row also contains a
|
||||||
|
type or mimetype. Type corresponds to a .NET class that support
|
||||||
|
text/value conversion through the TypeConverter architecture.
|
||||||
|
Classes that don't support this are serialized and stored with the
|
||||||
|
mimetype set.
|
||||||
|
|
||||||
|
The mimetype is used for serialized objects, and tells the
|
||||||
|
ResXResourceReader how to depersist the object. This is currently not
|
||||||
|
extensible. For a given mimetype the value must be set accordingly:
|
||||||
|
|
||||||
|
Note - application/x-microsoft.net.object.binary.base64 is the format
|
||||||
|
that the ResXResourceWriter will generate, however the reader can
|
||||||
|
read any of the formats listed below.
|
||||||
|
|
||||||
|
mimetype: application/x-microsoft.net.object.binary.base64
|
||||||
|
value : The object must be serialized with
|
||||||
|
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
|
||||||
|
: and then encoded with base64 encoding.
|
||||||
|
|
||||||
|
mimetype: application/x-microsoft.net.object.soap.base64
|
||||||
|
value : The object must be serialized with
|
||||||
|
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
|
||||||
|
: and then encoded with base64 encoding.
|
||||||
|
|
||||||
|
mimetype: application/x-microsoft.net.object.bytearray.base64
|
||||||
|
value : The object must be serialized into a byte array
|
||||||
|
: using a System.ComponentModel.TypeConverter
|
||||||
|
: and then encoded with base64 encoding.
|
||||||
|
-->
|
||||||
|
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
|
||||||
|
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
|
||||||
|
<xsd:element name="root" msdata:IsDataSet="true">
|
||||||
|
<xsd:complexType>
|
||||||
|
<xsd:choice maxOccurs="unbounded">
|
||||||
|
<xsd:element name="metadata">
|
||||||
|
<xsd:complexType>
|
||||||
|
<xsd:sequence>
|
||||||
|
<xsd:element name="value" type="xsd:string" minOccurs="0" />
|
||||||
|
</xsd:sequence>
|
||||||
|
<xsd:attribute name="name" use="required" type="xsd:string" />
|
||||||
|
<xsd:attribute name="type" type="xsd:string" />
|
||||||
|
<xsd:attribute name="mimetype" type="xsd:string" />
|
||||||
|
<xsd:attribute ref="xml:space" />
|
||||||
|
</xsd:complexType>
|
||||||
|
</xsd:element>
|
||||||
|
<xsd:element name="assembly">
|
||||||
|
<xsd:complexType>
|
||||||
|
<xsd:attribute name="alias" type="xsd:string" />
|
||||||
|
<xsd:attribute name="name" type="xsd:string" />
|
||||||
|
</xsd:complexType>
|
||||||
|
</xsd:element>
|
||||||
|
<xsd:element name="data">
|
||||||
|
<xsd:complexType>
|
||||||
|
<xsd:sequence>
|
||||||
|
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
|
||||||
|
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
|
||||||
|
</xsd:sequence>
|
||||||
|
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
|
||||||
|
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
|
||||||
|
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
|
||||||
|
<xsd:attribute ref="xml:space" />
|
||||||
|
</xsd:complexType>
|
||||||
|
</xsd:element>
|
||||||
|
<xsd:element name="resheader">
|
||||||
|
<xsd:complexType>
|
||||||
|
<xsd:sequence>
|
||||||
|
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
|
||||||
|
</xsd:sequence>
|
||||||
|
<xsd:attribute name="name" type="xsd:string" use="required" />
|
||||||
|
</xsd:complexType>
|
||||||
|
</xsd:element>
|
||||||
|
</xsd:choice>
|
||||||
|
</xsd:complexType>
|
||||||
|
</xsd:element>
|
||||||
|
</xsd:schema>
|
||||||
|
<resheader name="resmimetype">
|
||||||
|
<value>text/microsoft-resx</value>
|
||||||
|
</resheader>
|
||||||
|
<resheader name="version">
|
||||||
|
<value>2.0</value>
|
||||||
|
</resheader>
|
||||||
|
<resheader name="reader">
|
||||||
|
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||||
|
</resheader>
|
||||||
|
<resheader name="writer">
|
||||||
|
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||||
|
</resheader>
|
||||||
|
<metadata name="trayIcon.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
|
||||||
|
<value>17, 17</value>
|
||||||
|
</metadata>
|
||||||
|
<metadata name="toolTip.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
|
||||||
|
<value>112, 17</value>
|
||||||
|
</metadata>
|
||||||
|
<metadata name="timerResize.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
|
||||||
|
<value>202, 17</value>
|
||||||
|
</metadata>
|
||||||
|
</root>
|
||||||
@@ -1,190 +0,0 @@
|
|||||||
using System.Windows.Forms;
|
|
||||||
using CefSharp;
|
|
||||||
using CefSharp.WinForms;
|
|
||||||
using System.Drawing;
|
|
||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using TweetDick.Core.Handling;
|
|
||||||
using TweetDick.Configuration;
|
|
||||||
using TweetDick.Resources;
|
|
||||||
|
|
||||||
namespace TweetDick.Core{
|
|
||||||
sealed partial class FormNotification : Form{
|
|
||||||
public Func<bool> CanMoveWindow = () => true;
|
|
||||||
|
|
||||||
private readonly Form owner;
|
|
||||||
private readonly ChromiumWebBrowser browser;
|
|
||||||
|
|
||||||
private readonly Queue<TweetNotification> tweetQueue = new Queue<TweetNotification>(4);
|
|
||||||
private readonly bool autoHide;
|
|
||||||
private int timeLeft, totalTime;
|
|
||||||
|
|
||||||
private readonly string notificationJS;
|
|
||||||
|
|
||||||
public FormNotification(Form owner, TweetDeckBridge bridge, bool autoHide){
|
|
||||||
InitializeComponent();
|
|
||||||
|
|
||||||
Text = Program.BrandName;
|
|
||||||
|
|
||||||
this.owner = owner;
|
|
||||||
this.autoHide = autoHide;
|
|
||||||
|
|
||||||
owner.FormClosed += (sender, args) => Close();
|
|
||||||
|
|
||||||
notificationJS = ScriptLoader.LoadResource("notification.js");
|
|
||||||
|
|
||||||
browser = new ChromiumWebBrowser("about:blank"){ MenuHandler = new MenuHandlerEmpty() };
|
|
||||||
browser.FrameLoadEnd += Browser_FrameLoadEnd;
|
|
||||||
|
|
||||||
if (bridge != null){
|
|
||||||
browser.RegisterJsObject("$TD",bridge);
|
|
||||||
}
|
|
||||||
|
|
||||||
panelBrowser.Controls.Add(browser);
|
|
||||||
|
|
||||||
Disposed += (sender, args) => browser.Dispose();
|
|
||||||
}
|
|
||||||
|
|
||||||
public FormNotification(Form owner, bool autoHide) : this(owner,null,autoHide){}
|
|
||||||
|
|
||||||
private void Browser_FrameLoadEnd(object sender, FrameLoadEndEventArgs e){
|
|
||||||
if (e.Frame.IsMain && notificationJS != null){
|
|
||||||
browser.ExecuteScriptAsync(notificationJS);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
protected override void WndProc(ref Message m){
|
|
||||||
if (m.Msg == 0x0112 && (m.WParam.ToInt32() & 0xFFF0) == 0xF010 && !CanMoveWindow()){ // WM_SYSCOMMAND, SC_MOVE
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
base.WndProc(ref m);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void ShowNotification(TweetNotification notification){
|
|
||||||
MoveToVisibleLocation();
|
|
||||||
|
|
||||||
tweetQueue.Enqueue(notification);
|
|
||||||
|
|
||||||
if (!timerProgress.Enabled){
|
|
||||||
LoadNextNotification();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void ShowNotificationForSettings(bool resetAnimation){
|
|
||||||
if (browser.Address == "about:blank"){
|
|
||||||
browser.Load("about:blank"); // required, otherwise shit breaks
|
|
||||||
browser.LoadHtml(TweetNotification.ExampleTweet.GenerateHtml(),"http://tweetdeck.twitter.com/");
|
|
||||||
resetAnimation = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (resetAnimation){
|
|
||||||
totalTime = timeLeft = TweetNotification.ExampleTweet.GetDisplayDuration(Program.UserConfig.NotificationDuration);
|
|
||||||
timerProgress.Start();
|
|
||||||
}
|
|
||||||
|
|
||||||
MoveToVisibleLocation();
|
|
||||||
}
|
|
||||||
|
|
||||||
public void HideNotification(){
|
|
||||||
browser.LoadHtml("","about:blank");
|
|
||||||
Location = new Point(-32000,-32000);
|
|
||||||
TopMost = false;
|
|
||||||
timerProgress.Stop();
|
|
||||||
}
|
|
||||||
|
|
||||||
private void LoadNextNotification(){
|
|
||||||
TweetNotification tweet = tweetQueue.Dequeue();
|
|
||||||
|
|
||||||
if (browser.Address == "about:blank"){
|
|
||||||
browser.Load("about:blank"); // required, otherwise shit breaks
|
|
||||||
}
|
|
||||||
|
|
||||||
browser.LoadHtml(tweet.GenerateHtml(),"http://tweetdeck.twitter.com/");
|
|
||||||
|
|
||||||
totalTime = timeLeft = tweet.GetDisplayDuration(Program.UserConfig.NotificationDuration);
|
|
||||||
timerProgress.Stop();
|
|
||||||
timerProgress.Start();
|
|
||||||
}
|
|
||||||
|
|
||||||
private void MoveToVisibleLocation(){
|
|
||||||
UserConfig config = Program.UserConfig;
|
|
||||||
Screen screen = Screen.FromControl(owner);
|
|
||||||
|
|
||||||
if (config.NotificationDisplay > 0 && config.NotificationDisplay <= Screen.AllScreens.Length){
|
|
||||||
screen = Screen.AllScreens[config.NotificationDisplay-1];
|
|
||||||
}
|
|
||||||
|
|
||||||
int edgeDist = config.NotificationEdgeDistance;
|
|
||||||
|
|
||||||
switch(config.NotificationPosition){
|
|
||||||
case TweetNotification.Position.TopLeft:
|
|
||||||
Location = new Point(screen.WorkingArea.X+edgeDist,screen.WorkingArea.Y+edgeDist);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case TweetNotification.Position.TopRight:
|
|
||||||
Location = new Point(screen.WorkingArea.X+screen.WorkingArea.Width-edgeDist-Width,screen.WorkingArea.Y+edgeDist);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case TweetNotification.Position.BottomLeft:
|
|
||||||
Location = new Point(screen.WorkingArea.X+edgeDist,screen.WorkingArea.Y+screen.WorkingArea.Height-edgeDist-Height);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case TweetNotification.Position.BottomRight:
|
|
||||||
Location = new Point(screen.WorkingArea.X+screen.WorkingArea.Width-edgeDist-Width,screen.WorkingArea.Y+screen.WorkingArea.Height-edgeDist-Height);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case TweetNotification.Position.Custom:
|
|
||||||
if (!config.IsCustomNotificationPositionSet){
|
|
||||||
config.CustomNotificationPosition = new Point(screen.WorkingArea.X+screen.WorkingArea.Width-edgeDist-Width,screen.WorkingArea.Y+edgeDist);
|
|
||||||
config.Save();
|
|
||||||
}
|
|
||||||
|
|
||||||
Location = config.CustomNotificationPosition;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
TopMost = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void timerHideProgress_Tick(object sender, EventArgs e){
|
|
||||||
if (Bounds.Contains(Cursor.Position))return;
|
|
||||||
|
|
||||||
timeLeft -= timerProgress.Interval;
|
|
||||||
progressBarTimer.SetValueInstant((int)Math.Min(1000,Math.Round(1050.0*(totalTime-timeLeft)/totalTime)));
|
|
||||||
|
|
||||||
if (timeLeft <= 0){
|
|
||||||
if (tweetQueue.Count > 0){
|
|
||||||
LoadNextNotification();
|
|
||||||
}
|
|
||||||
else if (autoHide){
|
|
||||||
HideNotification();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void FormNotification_FormClosing(object sender, FormClosingEventArgs e){
|
|
||||||
if (e.CloseReason == CloseReason.UserClosing){
|
|
||||||
HideNotification();
|
|
||||||
tweetQueue.Clear();
|
|
||||||
e.Cancel = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private class MenuHandlerEmpty : IContextMenuHandler{
|
|
||||||
public void OnBeforeContextMenu(IWebBrowser browserControl, IBrowser browser, IFrame frame, IContextMenuParams parameters, IMenuModel model){
|
|
||||||
model.Clear();
|
|
||||||
}
|
|
||||||
|
|
||||||
public bool OnContextMenuCommand(IWebBrowser browserControl, IBrowser browser, IFrame frame, IContextMenuParams parameters, CefMenuCommand commandId, CefEventFlags eventFlags){
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void OnContextMenuDismissed(IWebBrowser browserControl, IBrowser browser, IFrame frame){}
|
|
||||||
|
|
||||||
public bool RunContextMenu(IWebBrowser browserControl, IBrowser browser, IFrame frame, IContextMenuParams parameters, IMenuModel model, IRunContextMenuCallback callback){
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
147
Core/Handling/ContextMenuBase.cs
Normal file
147
Core/Handling/ContextMenuBase.cs
Normal file
@@ -0,0 +1,147 @@
|
|||||||
|
using System;
|
||||||
|
using System.IO;
|
||||||
|
using System.Text.RegularExpressions;
|
||||||
|
using System.Windows.Forms;
|
||||||
|
using CefSharp;
|
||||||
|
using TweetDuck.Core.Bridge;
|
||||||
|
using TweetDuck.Core.Controls;
|
||||||
|
using TweetDuck.Core.Utils;
|
||||||
|
|
||||||
|
namespace TweetDuck.Core.Handling{
|
||||||
|
abstract class ContextMenuBase : IContextMenuHandler{
|
||||||
|
protected static readonly bool HasDevTools = File.Exists(Path.Combine(Program.ProgramPath, "devtools_resources.pak"));
|
||||||
|
|
||||||
|
private static TwitterUtils.ImageQuality ImageQuality => Program.UserConfig.TwitterImageQuality;
|
||||||
|
|
||||||
|
private static string GetLink(IContextMenuParams parameters){
|
||||||
|
return string.IsNullOrEmpty(TweetDeckBridge.LastRightClickedLink) ? parameters.UnfilteredLinkUrl : TweetDeckBridge.LastRightClickedLink;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static string GetImage(IContextMenuParams parameters){
|
||||||
|
return string.IsNullOrEmpty(TweetDeckBridge.LastRightClickedImage) ? parameters.SourceUrl : TweetDeckBridge.LastRightClickedImage;
|
||||||
|
}
|
||||||
|
|
||||||
|
private const int MenuOpenLinkUrl = 26500;
|
||||||
|
private const int MenuCopyLinkUrl = 26501;
|
||||||
|
private const int MenuCopyUsername = 26502;
|
||||||
|
private const int MenuOpenImageUrl = 26503;
|
||||||
|
private const int MenuCopyImageUrl = 26504;
|
||||||
|
private const int MenuSaveImage = 26505;
|
||||||
|
private const int MenuSaveAllImages = 26506;
|
||||||
|
private const int MenuOpenDevTools = 26599;
|
||||||
|
|
||||||
|
private readonly Form form;
|
||||||
|
|
||||||
|
private string lastHighlightedTweetAuthor;
|
||||||
|
private string[] lastHighlightedTweetImageList;
|
||||||
|
|
||||||
|
protected ContextMenuBase(Form form){
|
||||||
|
this.form = form;
|
||||||
|
}
|
||||||
|
|
||||||
|
public virtual void OnBeforeContextMenu(IWebBrowser browserControl, IBrowser browser, IFrame frame, IContextMenuParams parameters, IMenuModel model){
|
||||||
|
bool hasTweetImage = !string.IsNullOrEmpty(TweetDeckBridge.LastRightClickedImage);
|
||||||
|
lastHighlightedTweetAuthor = TweetDeckBridge.LastHighlightedTweetAuthor;
|
||||||
|
lastHighlightedTweetImageList = TweetDeckBridge.LastHighlightedTweetImages;
|
||||||
|
|
||||||
|
if (!TwitterUtils.IsTweetDeckWebsite(frame) || browser.IsLoading){
|
||||||
|
lastHighlightedTweetAuthor = string.Empty;
|
||||||
|
lastHighlightedTweetImageList = StringUtils.EmptyArray;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (parameters.TypeFlags.HasFlag(ContextMenuType.Link) && !parameters.UnfilteredLinkUrl.EndsWith("tweetdeck.twitter.com/#", StringComparison.Ordinal) && !hasTweetImage){
|
||||||
|
if (TwitterUtils.RegexAccount.IsMatch(parameters.UnfilteredLinkUrl)){
|
||||||
|
model.AddItem((CefMenuCommand)MenuOpenLinkUrl, "Open account in browser");
|
||||||
|
model.AddItem((CefMenuCommand)MenuCopyLinkUrl, "Copy account address");
|
||||||
|
model.AddItem((CefMenuCommand)MenuCopyUsername, "Copy account username");
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
model.AddItem((CefMenuCommand)MenuOpenLinkUrl, "Open link in browser");
|
||||||
|
model.AddItem((CefMenuCommand)MenuCopyLinkUrl, "Copy link address");
|
||||||
|
}
|
||||||
|
|
||||||
|
model.AddSeparator();
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((parameters.TypeFlags.HasFlag(ContextMenuType.Media) && parameters.HasImageContents) || hasTweetImage){
|
||||||
|
model.AddItem((CefMenuCommand)MenuOpenImageUrl, "Open image in browser");
|
||||||
|
model.AddItem((CefMenuCommand)MenuCopyImageUrl, "Copy image address");
|
||||||
|
model.AddItem((CefMenuCommand)MenuSaveImage, "Save image as...");
|
||||||
|
|
||||||
|
if (lastHighlightedTweetImageList.Length > 1){
|
||||||
|
model.AddItem((CefMenuCommand)MenuSaveAllImages, "Save all images as...");
|
||||||
|
}
|
||||||
|
|
||||||
|
model.AddSeparator();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public virtual bool OnContextMenuCommand(IWebBrowser browserControl, IBrowser browser, IFrame frame, IContextMenuParams parameters, CefMenuCommand commandId, CefEventFlags eventFlags){
|
||||||
|
switch((int)commandId){
|
||||||
|
case MenuOpenLinkUrl:
|
||||||
|
BrowserUtils.OpenExternalBrowser(parameters.LinkUrl);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case MenuCopyLinkUrl:
|
||||||
|
SetClipboardText(GetLink(parameters));
|
||||||
|
break;
|
||||||
|
|
||||||
|
case MenuOpenImageUrl:
|
||||||
|
BrowserUtils.OpenExternalBrowser(TwitterUtils.GetImageLink(GetImage(parameters), ImageQuality));
|
||||||
|
break;
|
||||||
|
|
||||||
|
case MenuSaveImage:
|
||||||
|
TwitterUtils.DownloadImage(GetImage(parameters), lastHighlightedTweetAuthor, ImageQuality);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case MenuSaveAllImages:
|
||||||
|
TwitterUtils.DownloadImages(lastHighlightedTweetImageList, lastHighlightedTweetAuthor, ImageQuality);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case MenuCopyImageUrl:
|
||||||
|
SetClipboardText(TwitterUtils.GetImageLink(GetImage(parameters), ImageQuality));
|
||||||
|
break;
|
||||||
|
|
||||||
|
case MenuCopyUsername:
|
||||||
|
Match match = TwitterUtils.RegexAccount.Match(parameters.UnfilteredLinkUrl);
|
||||||
|
SetClipboardText(match.Success ? match.Groups[1].Value : parameters.UnfilteredLinkUrl);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case MenuOpenDevTools:
|
||||||
|
browserControl.ShowDevTools();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public virtual void OnContextMenuDismissed(IWebBrowser browserControl, IBrowser browser, IFrame frame){
|
||||||
|
TweetDeckBridge.LastRightClickedLink = string.Empty;
|
||||||
|
TweetDeckBridge.LastRightClickedImage = string.Empty;
|
||||||
|
}
|
||||||
|
|
||||||
|
public virtual bool RunContextMenu(IWebBrowser browserControl, IBrowser browser, IFrame frame, IContextMenuParams parameters, IMenuModel model, IRunContextMenuCallback callback){
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void SetClipboardText(string text){
|
||||||
|
form.InvokeAsyncSafe(() => WindowsUtils.SetClipboard(text, TextDataFormat.UnicodeText));
|
||||||
|
}
|
||||||
|
|
||||||
|
protected static void AddDebugMenuItems(IMenuModel model){
|
||||||
|
model.AddItem((CefMenuCommand)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();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
166
Core/Handling/ContextMenuBrowser.cs
Normal file
166
Core/Handling/ContextMenuBrowser.cs
Normal file
@@ -0,0 +1,166 @@
|
|||||||
|
using CefSharp;
|
||||||
|
using System.Windows.Forms;
|
||||||
|
using TweetDuck.Core.Bridge;
|
||||||
|
using TweetDuck.Core.Controls;
|
||||||
|
using TweetDuck.Core.Utils;
|
||||||
|
|
||||||
|
namespace TweetDuck.Core.Handling{
|
||||||
|
class ContextMenuBrowser : ContextMenuBase{
|
||||||
|
private const int MenuGlobal = 26600;
|
||||||
|
private const int MenuMute = 26601;
|
||||||
|
private const int MenuSettings = 26602;
|
||||||
|
private const int MenuPlugins = 26003;
|
||||||
|
private const int MenuAbout = 26604;
|
||||||
|
|
||||||
|
private const int MenuOpenTweetUrl = 26610;
|
||||||
|
private const int MenuCopyTweetUrl = 26611;
|
||||||
|
private const int MenuOpenQuotedTweetUrl = 26612;
|
||||||
|
private const int MenuCopyQuotedTweetUrl = 26613;
|
||||||
|
private const int MenuScreenshotTweet = 26614;
|
||||||
|
|
||||||
|
private const string TitleReloadBrowser = "Reload browser";
|
||||||
|
private const string TitleMuteNotifications = "Mute notifications";
|
||||||
|
private const string TitleSettings = "Options";
|
||||||
|
private const string TitlePlugins = "Plugins";
|
||||||
|
private const string TitleAboutProgram = "About "+Program.BrandName;
|
||||||
|
|
||||||
|
private readonly FormBrowser form;
|
||||||
|
|
||||||
|
private string lastHighlightedTweet;
|
||||||
|
private string lastHighlightedQuotedTweet;
|
||||||
|
|
||||||
|
public ContextMenuBrowser(FormBrowser form) : base(form){
|
||||||
|
this.form = form;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void OnBeforeContextMenu(IWebBrowser browserControl, IBrowser browser, IFrame frame, IContextMenuParams parameters, IMenuModel model){
|
||||||
|
model.Remove(CefMenuCommand.Back);
|
||||||
|
model.Remove(CefMenuCommand.Forward);
|
||||||
|
model.Remove(CefMenuCommand.Print);
|
||||||
|
model.Remove(CefMenuCommand.ViewSource);
|
||||||
|
RemoveSeparatorIfLast(model);
|
||||||
|
|
||||||
|
if (parameters.TypeFlags.HasFlag(ContextMenuType.Selection)){
|
||||||
|
model.AddSeparator();
|
||||||
|
}
|
||||||
|
|
||||||
|
base.OnBeforeContextMenu(browserControl, browser, frame, parameters, model);
|
||||||
|
|
||||||
|
lastHighlightedTweet = TweetDeckBridge.LastHighlightedTweet;
|
||||||
|
lastHighlightedQuotedTweet = TweetDeckBridge.LastHighlightedQuotedTweet;
|
||||||
|
|
||||||
|
if (!TwitterUtils.IsTweetDeckWebsite(frame) || browser.IsLoading){
|
||||||
|
lastHighlightedTweet = string.Empty;
|
||||||
|
lastHighlightedQuotedTweet = string.Empty;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!string.IsNullOrEmpty(lastHighlightedTweet) && (parameters.TypeFlags & (ContextMenuType.Editable | ContextMenuType.Selection)) == 0){
|
||||||
|
model.AddItem((CefMenuCommand)MenuOpenTweetUrl, "Open tweet in browser");
|
||||||
|
model.AddItem((CefMenuCommand)MenuCopyTweetUrl, "Copy tweet address");
|
||||||
|
model.AddItem((CefMenuCommand)MenuScreenshotTweet, "Screenshot tweet to clipboard");
|
||||||
|
|
||||||
|
if (!string.IsNullOrEmpty(lastHighlightedQuotedTweet)){
|
||||||
|
model.AddSeparator();
|
||||||
|
model.AddItem((CefMenuCommand)MenuOpenQuotedTweetUrl, "Open quoted tweet in browser");
|
||||||
|
model.AddItem((CefMenuCommand)MenuCopyQuotedTweetUrl, "Copy quoted tweet address");
|
||||||
|
}
|
||||||
|
|
||||||
|
model.AddSeparator();
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((parameters.TypeFlags & (ContextMenuType.Editable | ContextMenuType.Selection)) == 0){
|
||||||
|
AddSeparator(model);
|
||||||
|
|
||||||
|
IMenuModel globalMenu = model.Count == 0 ? model : model.AddSubMenu((CefMenuCommand)MenuGlobal, Program.BrandName);
|
||||||
|
|
||||||
|
globalMenu.AddItem(CefMenuCommand.Reload, TitleReloadBrowser);
|
||||||
|
globalMenu.AddCheckItem((CefMenuCommand)MenuMute, TitleMuteNotifications);
|
||||||
|
globalMenu.SetChecked((CefMenuCommand)MenuMute, Program.UserConfig.MuteNotifications);
|
||||||
|
globalMenu.AddSeparator();
|
||||||
|
|
||||||
|
globalMenu.AddItem((CefMenuCommand)MenuSettings, TitleSettings);
|
||||||
|
globalMenu.AddItem((CefMenuCommand)MenuPlugins, TitlePlugins);
|
||||||
|
globalMenu.AddItem((CefMenuCommand)MenuAbout, TitleAboutProgram);
|
||||||
|
|
||||||
|
if (HasDevTools){
|
||||||
|
globalMenu.AddSeparator();
|
||||||
|
AddDebugMenuItems(globalMenu);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
RemoveSeparatorIfLast(model);
|
||||||
|
}
|
||||||
|
|
||||||
|
public override bool OnContextMenuCommand(IWebBrowser browserControl, IBrowser browser, IFrame frame, IContextMenuParams parameters, CefMenuCommand commandId, CefEventFlags eventFlags){
|
||||||
|
if (base.OnContextMenuCommand(browserControl, browser, frame, parameters, commandId, eventFlags)){
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch((int)commandId){
|
||||||
|
case (int)CefMenuCommand.Reload:
|
||||||
|
form.InvokeAsyncSafe(form.ReloadToTweetDeck);
|
||||||
|
return true;
|
||||||
|
|
||||||
|
case MenuSettings:
|
||||||
|
form.InvokeAsyncSafe(form.OpenSettings);
|
||||||
|
return true;
|
||||||
|
|
||||||
|
case MenuAbout:
|
||||||
|
form.InvokeAsyncSafe(form.OpenAbout);
|
||||||
|
return true;
|
||||||
|
|
||||||
|
case MenuPlugins:
|
||||||
|
form.InvokeAsyncSafe(form.OpenPlugins);
|
||||||
|
return true;
|
||||||
|
|
||||||
|
case MenuMute:
|
||||||
|
form.InvokeAsyncSafe(ToggleMuteNotifications);
|
||||||
|
return true;
|
||||||
|
|
||||||
|
case MenuOpenTweetUrl:
|
||||||
|
BrowserUtils.OpenExternalBrowser(lastHighlightedTweet);
|
||||||
|
return true;
|
||||||
|
|
||||||
|
case MenuCopyTweetUrl:
|
||||||
|
SetClipboardText(lastHighlightedTweet);
|
||||||
|
return true;
|
||||||
|
|
||||||
|
case MenuScreenshotTweet:
|
||||||
|
form.InvokeAsyncSafe(form.TriggerTweetScreenshot);
|
||||||
|
return true;
|
||||||
|
|
||||||
|
case MenuOpenQuotedTweetUrl:
|
||||||
|
BrowserUtils.OpenExternalBrowser(lastHighlightedQuotedTweet);
|
||||||
|
return true;
|
||||||
|
|
||||||
|
case MenuCopyQuotedTweetUrl:
|
||||||
|
SetClipboardText(lastHighlightedQuotedTweet);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
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 = Program.UserConfig.MuteNotifications;
|
||||||
|
};
|
||||||
|
|
||||||
|
return menu;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void ToggleMuteNotifications(){
|
||||||
|
Program.UserConfig.MuteNotifications = !Program.UserConfig.MuteNotifications;
|
||||||
|
Program.UserConfig.Save();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,61 +0,0 @@
|
|||||||
using CefSharp;
|
|
||||||
|
|
||||||
namespace TweetDick.Core.Handling{
|
|
||||||
class ContextMenuHandler : IContextMenuHandler{
|
|
||||||
private const int MenuSettings = 26500;
|
|
||||||
private const int MenuAbout = 26501;
|
|
||||||
|
|
||||||
private readonly FormBrowser form;
|
|
||||||
|
|
||||||
public ContextMenuHandler(FormBrowser form){
|
|
||||||
this.form = form;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void OnBeforeContextMenu(IWebBrowser browserControl, IBrowser browser, IFrame frame, IContextMenuParams parameters, IMenuModel model){
|
|
||||||
model.Remove(CefMenuCommand.Back);
|
|
||||||
model.Remove(CefMenuCommand.Forward);
|
|
||||||
model.Remove(CefMenuCommand.Print);
|
|
||||||
model.Remove(CefMenuCommand.ViewSource);
|
|
||||||
|
|
||||||
if (model.Count > 0 && model.GetTypeAt(model.Count-1) == MenuItemType.Separator){
|
|
||||||
model.RemoveAt(model.Count-1);
|
|
||||||
}
|
|
||||||
|
|
||||||
model.AddItem(CefMenuCommand.Reload,"Reload");
|
|
||||||
model.AddSeparator();
|
|
||||||
|
|
||||||
if (TweetNotification.IsReady){
|
|
||||||
model.AddItem((CefMenuCommand)MenuSettings,"Settings");
|
|
||||||
model.AddSeparator();
|
|
||||||
}
|
|
||||||
|
|
||||||
model.AddItem((CefMenuCommand)MenuAbout,"About "+Program.BrandName);
|
|
||||||
}
|
|
||||||
|
|
||||||
public bool OnContextMenuCommand(IWebBrowser browserControl, IBrowser browser, IFrame frame, IContextMenuParams parameters, CefMenuCommand commandId, CefEventFlags eventFlags){
|
|
||||||
switch((int)commandId){
|
|
||||||
case MenuSettings:
|
|
||||||
form.InvokeSafe(() => {
|
|
||||||
form.OpenSettings();
|
|
||||||
});
|
|
||||||
|
|
||||||
return true;
|
|
||||||
|
|
||||||
case MenuAbout:
|
|
||||||
form.InvokeSafe(() => {
|
|
||||||
form.OpenAbout();
|
|
||||||
});
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void OnContextMenuDismissed(IWebBrowser browserControl, IBrowser browser, IFrame frame){}
|
|
||||||
|
|
||||||
public bool RunContextMenu(IWebBrowser browserControl, IBrowser browser, IFrame frame, IContextMenuParams parameters, IMenuModel model, IRunContextMenuCallback callback){
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
87
Core/Handling/ContextMenuNotification.cs
Normal file
87
Core/Handling/ContextMenuNotification.cs
Normal file
@@ -0,0 +1,87 @@
|
|||||||
|
using CefSharp;
|
||||||
|
using TweetDuck.Core.Controls;
|
||||||
|
using TweetDuck.Core.Notification;
|
||||||
|
|
||||||
|
namespace TweetDuck.Core.Handling{
|
||||||
|
class ContextMenuNotification : ContextMenuBase{
|
||||||
|
private const int MenuSkipTweet = 26600;
|
||||||
|
private const int MenuFreeze = 26601;
|
||||||
|
private const int MenuCopyTweetUrl = 26602;
|
||||||
|
private const int MenuCopyQuotedTweetUrl = 26603;
|
||||||
|
|
||||||
|
private readonly FormNotificationBase form;
|
||||||
|
private readonly bool enableCustomMenu;
|
||||||
|
|
||||||
|
public ContextMenuNotification(FormNotificationBase form, bool enableCustomMenu) : base(form){
|
||||||
|
this.form = form;
|
||||||
|
this.enableCustomMenu = enableCustomMenu;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void OnBeforeContextMenu(IWebBrowser browserControl, IBrowser browser, IFrame frame, IContextMenuParams parameters, IMenuModel model){
|
||||||
|
model.Clear();
|
||||||
|
|
||||||
|
if (parameters.TypeFlags.HasFlag(ContextMenuType.Selection)){
|
||||||
|
model.AddItem(CefMenuCommand.Copy, "Copy");
|
||||||
|
model.AddSeparator();
|
||||||
|
}
|
||||||
|
|
||||||
|
base.OnBeforeContextMenu(browserControl, browser, frame, parameters, model);
|
||||||
|
|
||||||
|
if (enableCustomMenu){
|
||||||
|
model.AddItem((CefMenuCommand)MenuSkipTweet, "Skip tweet");
|
||||||
|
model.AddCheckItem((CefMenuCommand)MenuFreeze, "Freeze");
|
||||||
|
model.SetChecked((CefMenuCommand)MenuFreeze, form.FreezeTimer);
|
||||||
|
model.AddSeparator();
|
||||||
|
|
||||||
|
if (!string.IsNullOrEmpty(form.CurrentTweetUrl)){
|
||||||
|
model.AddItem((CefMenuCommand)MenuCopyTweetUrl, "Copy tweet address");
|
||||||
|
|
||||||
|
if (!string.IsNullOrEmpty(form.CurrentQuoteUrl)){
|
||||||
|
model.AddItem((CefMenuCommand)MenuCopyQuotedTweetUrl, "Copy quoted tweet address");
|
||||||
|
}
|
||||||
|
|
||||||
|
model.AddSeparator();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (HasDevTools){
|
||||||
|
AddDebugMenuItems(model);
|
||||||
|
}
|
||||||
|
|
||||||
|
RemoveSeparatorIfLast(model);
|
||||||
|
|
||||||
|
form.InvokeAsyncSafe(() => form.ContextMenuOpen = true);
|
||||||
|
}
|
||||||
|
|
||||||
|
public override bool OnContextMenuCommand(IWebBrowser browserControl, IBrowser browser, IFrame frame, IContextMenuParams parameters, CefMenuCommand commandId, CefEventFlags eventFlags){
|
||||||
|
if (base.OnContextMenuCommand(browserControl, browser, frame, parameters, commandId, eventFlags)){
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch((int)commandId){
|
||||||
|
case MenuSkipTweet:
|
||||||
|
form.InvokeAsyncSafe(form.FinishCurrentNotification);
|
||||||
|
return true;
|
||||||
|
|
||||||
|
case MenuFreeze:
|
||||||
|
form.InvokeAsyncSafe(() => form.FreezeTimer = !form.FreezeTimer);
|
||||||
|
return true;
|
||||||
|
|
||||||
|
case MenuCopyTweetUrl:
|
||||||
|
SetClipboardText(form.CurrentTweetUrl);
|
||||||
|
return true;
|
||||||
|
|
||||||
|
case MenuCopyQuotedTweetUrl:
|
||||||
|
SetClipboardText(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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
15
Core/Handling/General/BrowserProcessHandler.cs
Normal file
15
Core/Handling/General/BrowserProcessHandler.cs
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
using System;
|
||||||
|
using CefSharp;
|
||||||
|
|
||||||
|
namespace TweetDuck.Core.Handling.General{
|
||||||
|
class BrowserProcessHandler : IBrowserProcessHandler{
|
||||||
|
void IBrowserProcessHandler.OnContextInitialized(){
|
||||||
|
using(IRequestContext ctx = Cef.GetGlobalRequestContext()){
|
||||||
|
ctx.SetPreference("browser.enable_spellchecking", Program.UserConfig.EnableSpellCheck, out string _);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void IBrowserProcessHandler.OnScheduleMessagePumpWork(long delay){}
|
||||||
|
void IDisposable.Dispose(){}
|
||||||
|
}
|
||||||
|
}
|
||||||
70
Core/Handling/General/JavaScriptDialogHandler.cs
Normal file
70
Core/Handling/General/JavaScriptDialogHandler.cs
Normal file
@@ -0,0 +1,70 @@
|
|||||||
|
using System.Drawing;
|
||||||
|
using System.Windows.Forms;
|
||||||
|
using CefSharp;
|
||||||
|
using CefSharp.WinForms;
|
||||||
|
using TweetDuck.Core.Controls;
|
||||||
|
using TweetDuck.Core.Other;
|
||||||
|
using TweetDuck.Core.Utils;
|
||||||
|
|
||||||
|
namespace TweetDuck.Core.Handling.General{
|
||||||
|
class JavaScriptDialogHandler : IJsDialogHandler{
|
||||||
|
bool IJsDialogHandler.OnJSDialog(IWebBrowser browserControl, IBrowser browser, string originUrl, CefJsDialogType dialogType, string messageText, string defaultPromptText, IJsDialogCallback callback, ref bool suppressMessage){
|
||||||
|
((ChromiumWebBrowser)browserControl).InvokeSafe(() => {
|
||||||
|
FormMessage form;
|
||||||
|
TextBox input = null;
|
||||||
|
|
||||||
|
if (dialogType == CefJsDialogType.Alert){
|
||||||
|
form = new FormMessage("Browser Message", messageText, MessageBoxIcon.None);
|
||||||
|
form.AddButton(FormMessage.OK, ControlType.Accept | ControlType.Focused);
|
||||||
|
}
|
||||||
|
else if (dialogType == CefJsDialogType.Confirm){
|
||||||
|
form = new FormMessage("Browser Confirmation", messageText, MessageBoxIcon.None);
|
||||||
|
form.AddButton(FormMessage.No, DialogResult.No, ControlType.Cancel);
|
||||||
|
form.AddButton(FormMessage.Yes, ControlType.Focused);
|
||||||
|
}
|
||||||
|
else if (dialogType == CefJsDialogType.Prompt){
|
||||||
|
form = new FormMessage("Browser Prompt", messageText, MessageBoxIcon.None);
|
||||||
|
form.AddButton(FormMessage.Cancel, DialogResult.Cancel, ControlType.Cancel);
|
||||||
|
form.AddButton(FormMessage.OK, ControlType.Accept | ControlType.Focused);
|
||||||
|
|
||||||
|
float dpiScale = form.GetDPIScale();
|
||||||
|
|
||||||
|
input = new TextBox{
|
||||||
|
Anchor = AnchorStyles.Left | AnchorStyles.Right | AnchorStyles.Bottom,
|
||||||
|
Location = new Point(BrowserUtils.Scale(22, dpiScale), form.ActionPanelY-BrowserUtils.Scale(46, dpiScale)),
|
||||||
|
Size = new Size(form.ClientSize.Width-BrowserUtils.Scale(44, dpiScale), 20)
|
||||||
|
};
|
||||||
|
|
||||||
|
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){}
|
||||||
|
}
|
||||||
|
}
|
||||||
30
Core/Handling/General/LifeSpanHandler.cs
Normal file
30
Core/Handling/General/LifeSpanHandler.cs
Normal file
@@ -0,0 +1,30 @@
|
|||||||
|
using CefSharp;
|
||||||
|
using TweetDuck.Core.Utils;
|
||||||
|
|
||||||
|
namespace TweetDuck.Core.Handling.General{
|
||||||
|
class LifeSpanHandler : ILifeSpanHandler{
|
||||||
|
public bool OnBeforePopup(IWebBrowser browserControl, IBrowser browser, IFrame frame, string targetUrl, string targetFrameName, WindowOpenDisposition targetDisposition, bool userGesture, IPopupFeatures popupFeatures, IWindowInfo windowInfo, IBrowserSettings browserSettings, ref bool noJavascriptAccess, out IWebBrowser newBrowser){
|
||||||
|
newBrowser = null;
|
||||||
|
|
||||||
|
switch(targetDisposition){
|
||||||
|
case WindowOpenDisposition.NewBackgroundTab:
|
||||||
|
case WindowOpenDisposition.NewForegroundTab:
|
||||||
|
case WindowOpenDisposition.NewPopup:
|
||||||
|
case WindowOpenDisposition.NewWindow:
|
||||||
|
BrowserUtils.OpenExternalBrowser(targetUrl);
|
||||||
|
return true;
|
||||||
|
|
||||||
|
default:
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void OnAfterCreated(IWebBrowser browserControl, IBrowser browser){}
|
||||||
|
|
||||||
|
public bool DoClose(IWebBrowser browserControl, IBrowser browser){
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void OnBeforeClose(IWebBrowser browserControl, IBrowser browser){}
|
||||||
|
}
|
||||||
|
}
|
||||||
68
Core/Handling/General/RequestHandlerBase.cs
Normal file
68
Core/Handling/General/RequestHandlerBase.cs
Normal file
@@ -0,0 +1,68 @@
|
|||||||
|
using System.Security.Cryptography.X509Certificates;
|
||||||
|
using CefSharp;
|
||||||
|
|
||||||
|
namespace TweetDuck.Core.Handling.General{
|
||||||
|
abstract class RequestHandlerBase : IRequestHandler{
|
||||||
|
// Browser
|
||||||
|
|
||||||
|
public virtual void OnRenderViewReady(IWebBrowser browserControl, IBrowser browser){}
|
||||||
|
|
||||||
|
public virtual void OnRenderProcessTerminated(IWebBrowser browserControl, IBrowser browser, CefTerminationStatus status){}
|
||||||
|
|
||||||
|
public virtual bool OnBeforeBrowse(IWebBrowser browserControl, IBrowser browser, IFrame frame, IRequest request, bool isRedirect){
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public virtual bool OnOpenUrlFromTab(IWebBrowser browserControl, IBrowser browser, IFrame frame, string targetUrl, WindowOpenDisposition targetDisposition, bool userGesture){
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public virtual bool OnProtocolExecution(IWebBrowser browserControl, IBrowser browser, string url){
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Resources
|
||||||
|
|
||||||
|
public virtual CefReturnValue OnBeforeResourceLoad(IWebBrowser browserControl, IBrowser browser, IFrame frame, IRequest request, IRequestCallback callback){
|
||||||
|
return CefReturnValue.Continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
public virtual void OnResourceRedirect(IWebBrowser browserControl, IBrowser browser, IFrame frame, IRequest request, IResponse response, ref string newUrl){}
|
||||||
|
|
||||||
|
public virtual bool OnResourceResponse(IWebBrowser browserControl, IBrowser browser, IFrame frame, IRequest request, IResponse response){
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public virtual IResponseFilter GetResourceResponseFilter(IWebBrowser browserControl, IBrowser browser, IFrame frame, IRequest request, IResponse response){
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public virtual void OnResourceLoadComplete(IWebBrowser browserControl, IBrowser browser, IFrame frame, IRequest request, IResponse response, UrlRequestStatus status, long receivedContentLength){}
|
||||||
|
|
||||||
|
// JavaScript & Plugins
|
||||||
|
|
||||||
|
public virtual bool OnQuotaRequest(IWebBrowser browserControl, IBrowser browser, string originUrl, long newSize, IRequestCallback callback){
|
||||||
|
callback.Dispose();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public virtual void OnPluginCrashed(IWebBrowser browserControl, IBrowser browser, string pluginPath){}
|
||||||
|
|
||||||
|
// Auth
|
||||||
|
|
||||||
|
public virtual bool GetAuthCredentials(IWebBrowser browserControl, IBrowser browser, IFrame frame, bool isProxy, string host, int port, string realm, string scheme, IAuthCallback callback){
|
||||||
|
callback.Dispose();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public virtual bool OnSelectClientCertificate(IWebBrowser browserControl, IBrowser browser, bool isProxy, string host, int port, X509Certificate2Collection certificates, ISelectClientCertificateCallback callback){
|
||||||
|
callback.Dispose();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public virtual bool OnCertificateError(IWebBrowser browserControl, IBrowser browser, CefErrorCode errorCode, string requestUrl, ISslInfo sslInfo, IRequestCallback callback){
|
||||||
|
callback.Dispose();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
38
Core/Handling/KeyboardHandlerNotification.cs
Normal file
38
Core/Handling/KeyboardHandlerNotification.cs
Normal file
@@ -0,0 +1,38 @@
|
|||||||
|
using CefSharp;
|
||||||
|
using System.Windows.Forms;
|
||||||
|
using TweetDuck.Core.Controls;
|
||||||
|
using TweetDuck.Core.Notification;
|
||||||
|
|
||||||
|
namespace TweetDuck.Core.Handling {
|
||||||
|
sealed class KeyboardHandlerNotification : IKeyboardHandler{
|
||||||
|
private readonly FormNotificationBase notification;
|
||||||
|
|
||||||
|
public KeyboardHandlerNotification(FormNotificationBase notification){
|
||||||
|
this.notification = notification;
|
||||||
|
}
|
||||||
|
|
||||||
|
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://")){
|
||||||
|
switch((Keys)windowsKeyCode){
|
||||||
|
case Keys.Enter:
|
||||||
|
notification.InvokeAsyncSafe(notification.FinishCurrentNotification);
|
||||||
|
return true;
|
||||||
|
|
||||||
|
case Keys.Escape:
|
||||||
|
notification.InvokeAsyncSafe(() => notification.HideNotification(true));
|
||||||
|
return true;
|
||||||
|
|
||||||
|
case Keys.Space:
|
||||||
|
notification.InvokeAsyncSafe(() => notification.FreezeTimer = !notification.FreezeTimer);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool IKeyboardHandler.OnKeyEvent(IWebBrowser browserControl, IBrowser browser, KeyType type, int windowsKeyCode, int nativeKeyCode, CefEventFlags modifiers, bool isSystemKey){
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
18
Core/Handling/RequestHandlerBrowser.cs
Normal file
18
Core/Handling/RequestHandlerBrowser.cs
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
using CefSharp;
|
||||||
|
using TweetDuck.Core.Handling.General;
|
||||||
|
|
||||||
|
namespace TweetDuck.Core.Handling{
|
||||||
|
class RequestHandlerBrowser : RequestHandlerBase{
|
||||||
|
public override void OnRenderProcessTerminated(IWebBrowser browserControl, IBrowser browser, CefTerminationStatus status){
|
||||||
|
browser.Reload();
|
||||||
|
}
|
||||||
|
|
||||||
|
public override CefReturnValue OnBeforeResourceLoad(IWebBrowser browserControl, IBrowser browser, IFrame frame, IRequest request, IRequestCallback callback){
|
||||||
|
if (request.ResourceType == ResourceType.Script && request.Url.Contains("analytics.")){
|
||||||
|
return CefReturnValue.Cancel;
|
||||||
|
}
|
||||||
|
|
||||||
|
return CefReturnValue.Continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
63
Core/Handling/ResourceHandlerNotification.cs
Normal file
63
Core/Handling/ResourceHandlerNotification.cs
Normal file
@@ -0,0 +1,63 @@
|
|||||||
|
using CefSharp;
|
||||||
|
using System.Collections.Specialized;
|
||||||
|
using System.IO;
|
||||||
|
using System.Text;
|
||||||
|
|
||||||
|
namespace TweetDuck.Core.Handling{
|
||||||
|
class ResourceHandlerNotification : IResourceHandler{
|
||||||
|
private readonly NameValueCollection headers = new NameValueCollection(0);
|
||||||
|
private MemoryStream dataIn;
|
||||||
|
|
||||||
|
public void SetHTML(string html){
|
||||||
|
dataIn?.Dispose();
|
||||||
|
dataIn = ResourceHandler.GetMemoryStream(html, Encoding.UTF8);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Dispose(){
|
||||||
|
if (dataIn != null){
|
||||||
|
dataIn.Dispose();
|
||||||
|
dataIn = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool IResourceHandler.ProcessRequest(IRequest request, ICallback callback){
|
||||||
|
callback.Continue();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void IResourceHandler.GetResponseHeaders(IResponse response, out long responseLength, out string redirectUrl){
|
||||||
|
redirectUrl = null;
|
||||||
|
|
||||||
|
response.MimeType = "text/html";
|
||||||
|
response.StatusCode = 200;
|
||||||
|
response.StatusText = "OK";
|
||||||
|
response.ResponseHeaders = headers;
|
||||||
|
responseLength = dataIn?.Length ?? -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool IResourceHandler.ReadResponse(Stream dataOut, out int bytesRead, ICallback callback){
|
||||||
|
callback.Dispose();
|
||||||
|
|
||||||
|
try{
|
||||||
|
int length = (int)dataIn.Length;
|
||||||
|
|
||||||
|
dataIn.CopyTo(dataOut, length);
|
||||||
|
bytesRead = length;
|
||||||
|
return true;
|
||||||
|
}catch{ // catch IOException, possibly NullReferenceException if dataIn is null
|
||||||
|
bytesRead = 0;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool IResourceHandler.CanGetCookie(Cookie cookie){
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool IResourceHandler.CanSetCookie(Cookie cookie){
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void IResourceHandler.Cancel(){}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,49 +0,0 @@
|
|||||||
using System.Diagnostics;
|
|
||||||
|
|
||||||
namespace TweetDick.Core.Handling{
|
|
||||||
class TweetDeckBridge{
|
|
||||||
private readonly FormBrowser form;
|
|
||||||
|
|
||||||
public string BrandName{
|
|
||||||
get{
|
|
||||||
return Program.BrandName;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public TweetDeckBridge(FormBrowser form){
|
|
||||||
this.form = form;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void LoadFontSizeClass(string fsClass){
|
|
||||||
form.InvokeSafe(() => {
|
|
||||||
TweetNotification.SetFontSizeClass(fsClass);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
public void LoadNotificationHeadContents(string headContents){
|
|
||||||
form.InvokeSafe(() => {
|
|
||||||
TweetNotification.SetHeadTag(headContents);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
public void OpenSettingsMenu(){
|
|
||||||
form.InvokeSafe(() => {
|
|
||||||
form.OpenSettings();
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
public void OnTweetPopup(string tweetHtml, int tweetCharacters){
|
|
||||||
form.InvokeSafe(() => {
|
|
||||||
form.OnTweetPopup(new TweetNotification(tweetHtml,tweetCharacters));
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
public void OpenBrowser(string url){
|
|
||||||
Process.Start(url);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void Log(string data){
|
|
||||||
Debug.WriteLine(data);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,82 +0,0 @@
|
|||||||
using System;
|
|
||||||
using System.Text;
|
|
||||||
|
|
||||||
namespace TweetDick.Core.Handling{
|
|
||||||
sealed class TweetNotification{
|
|
||||||
private static string FontSizeClass { get; set; }
|
|
||||||
private static string HeadTag { get; set; }
|
|
||||||
|
|
||||||
public static bool IsReady{
|
|
||||||
get{
|
|
||||||
return FontSizeClass != null && HeadTag != null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public static TweetNotification ExampleTweet{
|
|
||||||
get{
|
|
||||||
StringBuilder build = new StringBuilder();
|
|
||||||
build.Append(@"<article><div class='js-stream-item-content item-box js-show-detail'><div class='js-tweet tweet'>");
|
|
||||||
build.Append(@"<header class='tweet-header'>");
|
|
||||||
build.Append(@"<time class='tweet-timestamp js-timestamp pull-right txt-mute'><a target='_blank' rel='url' href='https://twitter.com/chylexMC' class='txt-small'>0s</a></time>");
|
|
||||||
build.Append(@"<a target='_blank' rel='user' href='https://twitter.com/chylexMC' class='account-link link-complex block'>");
|
|
||||||
build.Append(@"<div class='obj-left item-img tweet-img'><img width='48' height='48' alt='chylexMC's avatar' src='https://pbs.twimg.com/profile_images/645532929930608642/J56NBJVY_normal.png' class='tweet-avatar avatar pull-right'></div>");
|
|
||||||
build.Append(@"<div class='nbfc'><span class='account-inline txt-ellipsis'><b class='fullname link-complex-target'>chylex</b> <span class='username txt-mute'>@chylexMC</span></span></div>");
|
|
||||||
build.Append(@"</a>");
|
|
||||||
build.Append(@"</header>");
|
|
||||||
build.Append(@"<div class='tweet-body'><p class='js-tweet-text tweet-text with-linebreaks'>This is an example tweet, which lets you test the location and duration of popup notifications.</p></div>");
|
|
||||||
build.Append(@"</div></div></article>");
|
|
||||||
|
|
||||||
return new TweetNotification(build.ToString(),95);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void SetFontSizeClass(string newFSClass){
|
|
||||||
FontSizeClass = newFSClass;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void SetHeadTag(string headContents){
|
|
||||||
HeadTag = headContents;
|
|
||||||
}
|
|
||||||
|
|
||||||
public enum Position{
|
|
||||||
TopLeft, TopRight, BottomLeft, BottomRight, Custom
|
|
||||||
}
|
|
||||||
|
|
||||||
public enum Duration{
|
|
||||||
Short, Medium, Long, VeryLong
|
|
||||||
}
|
|
||||||
|
|
||||||
private readonly string html;
|
|
||||||
private readonly int characters;
|
|
||||||
|
|
||||||
public TweetNotification(string html, int characters){
|
|
||||||
this.html = html;
|
|
||||||
this.characters = characters;
|
|
||||||
}
|
|
||||||
|
|
||||||
public int GetDisplayDuration(Duration modifier){
|
|
||||||
int multiplier;
|
|
||||||
|
|
||||||
switch(modifier){
|
|
||||||
case Duration.Short: multiplier = 15; break;
|
|
||||||
case Duration.Long: multiplier = 35; break;
|
|
||||||
case Duration.VeryLong: multiplier = 45; break;
|
|
||||||
default: multiplier = 25; break;
|
|
||||||
}
|
|
||||||
|
|
||||||
return 2000+Math.Max(1000,multiplier*characters);
|
|
||||||
}
|
|
||||||
|
|
||||||
public string GenerateHtml(){
|
|
||||||
StringBuilder build = new StringBuilder();
|
|
||||||
build.Append("<!DOCTYPE html>");
|
|
||||||
build.Append("<html class='os-windows ").Append(FontSizeClass).Append("'>");
|
|
||||||
build.Append("<head>").Append(HeadTag).Append("</head>");
|
|
||||||
build.Append("<body class='hearty'><div class='app-columns-container'><div class='column' style='width:100%'>");
|
|
||||||
build.Append(html);
|
|
||||||
build.Append("</div></div></body>");
|
|
||||||
build.Append("</html>");
|
|
||||||
return build.ToString();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
52
Core/Notification/FormNotificationBase.Designer.cs
generated
Normal file
52
Core/Notification/FormNotificationBase.Designer.cs
generated
Normal file
@@ -0,0 +1,52 @@
|
|||||||
|
namespace TweetDuck.Core.Notification {
|
||||||
|
partial class FormNotificationBase {
|
||||||
|
/// <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.components = new System.ComponentModel.Container();
|
||||||
|
this.toolTip = new System.Windows.Forms.ToolTip(this.components);
|
||||||
|
this.SuspendLayout();
|
||||||
|
//
|
||||||
|
// FormNotification
|
||||||
|
//
|
||||||
|
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
|
||||||
|
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
|
||||||
|
this.BackColor = System.Drawing.SystemColors.Control;
|
||||||
|
this.ClientSize = new System.Drawing.Size(284, 122);
|
||||||
|
this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedToolWindow;
|
||||||
|
this.Location = TweetDuck.Core.Controls.ControlExtensions.InvisibleLocation;
|
||||||
|
this.MaximizeBox = false;
|
||||||
|
this.MinimizeBox = false;
|
||||||
|
this.Name = "FormNotification";
|
||||||
|
this.ShowIcon = false;
|
||||||
|
this.ShowInTaskbar = false;
|
||||||
|
this.StartPosition = System.Windows.Forms.FormStartPosition.Manual;
|
||||||
|
this.ResumeLayout(false);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
private System.Windows.Forms.ToolTip toolTip;
|
||||||
|
}
|
||||||
|
}
|
||||||
232
Core/Notification/FormNotificationBase.cs
Normal file
232
Core/Notification/FormNotificationBase.cs
Normal file
@@ -0,0 +1,232 @@
|
|||||||
|
using CefSharp;
|
||||||
|
using CefSharp.WinForms;
|
||||||
|
using System;
|
||||||
|
using System.Drawing;
|
||||||
|
using System.Windows.Forms;
|
||||||
|
using TweetDuck.Configuration;
|
||||||
|
using TweetDuck.Core.Controls;
|
||||||
|
using TweetDuck.Core.Handling;
|
||||||
|
using TweetDuck.Core.Handling.General;
|
||||||
|
using TweetDuck.Core.Utils;
|
||||||
|
|
||||||
|
namespace TweetDuck.Core.Notification{
|
||||||
|
partial class FormNotificationBase : Form{
|
||||||
|
protected Point PrimaryLocation{
|
||||||
|
get{
|
||||||
|
UserConfig config = Program.UserConfig;
|
||||||
|
Screen screen;
|
||||||
|
|
||||||
|
if (config.NotificationDisplay > 0 && config.NotificationDisplay <= Screen.AllScreens.Length){
|
||||||
|
screen = Screen.AllScreens[config.NotificationDisplay-1];
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
screen = Screen.FromControl(owner);
|
||||||
|
}
|
||||||
|
|
||||||
|
int edgeDist = config.NotificationEdgeDistance;
|
||||||
|
|
||||||
|
switch(config.NotificationPosition){
|
||||||
|
case TweetNotification.Position.TopLeft:
|
||||||
|
return new Point(screen.WorkingArea.X+edgeDist, screen.WorkingArea.Y+edgeDist);
|
||||||
|
|
||||||
|
case TweetNotification.Position.TopRight:
|
||||||
|
return new Point(screen.WorkingArea.X+screen.WorkingArea.Width-edgeDist-Width, screen.WorkingArea.Y+edgeDist);
|
||||||
|
|
||||||
|
case TweetNotification.Position.BottomLeft:
|
||||||
|
return new Point(screen.WorkingArea.X+edgeDist, screen.WorkingArea.Y+screen.WorkingArea.Height-edgeDist-Height);
|
||||||
|
|
||||||
|
case TweetNotification.Position.BottomRight:
|
||||||
|
return new Point(screen.WorkingArea.X+screen.WorkingArea.Width-edgeDist-Width, screen.WorkingArea.Y+screen.WorkingArea.Height-edgeDist-Height);
|
||||||
|
|
||||||
|
case TweetNotification.Position.Custom:
|
||||||
|
if (!config.IsCustomNotificationPositionSet){
|
||||||
|
config.CustomNotificationPosition = new Point(screen.WorkingArea.X+screen.WorkingArea.Width-edgeDist-Width, screen.WorkingArea.Y+edgeDist);
|
||||||
|
config.Save();
|
||||||
|
}
|
||||||
|
|
||||||
|
return config.CustomNotificationPosition;
|
||||||
|
}
|
||||||
|
|
||||||
|
return Location;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool IsNotificationVisible => Location != ControlExtensions.InvisibleLocation;
|
||||||
|
|
||||||
|
public new Point Location{
|
||||||
|
get => base.Location;
|
||||||
|
|
||||||
|
set{
|
||||||
|
Visible = (base.Location = value) != ControlExtensions.InvisibleLocation;
|
||||||
|
FormBorderStyle = GetBorderStyle(CanResizeWindow);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool CanResizeWindow{
|
||||||
|
get => FormBorderStyle == FormBorderStyle.Sizable || FormBorderStyle == FormBorderStyle.SizableToolWindow;
|
||||||
|
set => FormBorderStyle = GetBorderStyle(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Func<bool> CanMoveWindow { get; set; } = () => true;
|
||||||
|
protected override bool ShowWithoutActivation => true;
|
||||||
|
|
||||||
|
protected double SizeScale => dpiScale*Program.UserConfig.ZoomMultiplier;
|
||||||
|
|
||||||
|
protected readonly Form owner;
|
||||||
|
protected readonly ChromiumWebBrowser browser;
|
||||||
|
|
||||||
|
private readonly ResourceHandlerNotification resourceHandler = new ResourceHandlerNotification();
|
||||||
|
private readonly float dpiScale;
|
||||||
|
|
||||||
|
private string currentColumn;
|
||||||
|
private int pauseCounter;
|
||||||
|
|
||||||
|
public bool IsPaused => pauseCounter > 0;
|
||||||
|
|
||||||
|
public bool FreezeTimer { get; set; }
|
||||||
|
public bool ContextMenuOpen { get; set; }
|
||||||
|
public string CurrentTweetUrl { get; private set; }
|
||||||
|
public string CurrentQuoteUrl { get; private set; }
|
||||||
|
|
||||||
|
public event EventHandler Initialized;
|
||||||
|
|
||||||
|
public FormNotificationBase(Form owner, bool enableContextMenu){
|
||||||
|
InitializeComponent();
|
||||||
|
|
||||||
|
this.owner = owner;
|
||||||
|
this.owner.FormClosed += owner_FormClosed;
|
||||||
|
|
||||||
|
this.browser = new ChromiumWebBrowser("about:blank"){
|
||||||
|
MenuHandler = new ContextMenuNotification(this, enableContextMenu),
|
||||||
|
JsDialogHandler = new JavaScriptDialogHandler(),
|
||||||
|
LifeSpanHandler = new LifeSpanHandler()
|
||||||
|
};
|
||||||
|
|
||||||
|
this.browser.Dock = DockStyle.None;
|
||||||
|
this.browser.ClientSize = ClientSize;
|
||||||
|
this.browser.IsBrowserInitializedChanged += Browser_IsBrowserInitializedChanged;
|
||||||
|
|
||||||
|
#if DEBUG
|
||||||
|
this.browser.ConsoleMessage += BrowserUtils.HandleConsoleMessage;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
this.dpiScale = this.GetDPIScale();
|
||||||
|
|
||||||
|
DefaultResourceHandlerFactory handlerFactory = (DefaultResourceHandlerFactory)browser.ResourceHandlerFactory;
|
||||||
|
handlerFactory.RegisterHandler(TwitterUtils.TweetDeckURL, this.resourceHandler);
|
||||||
|
|
||||||
|
Controls.Add(browser);
|
||||||
|
|
||||||
|
Disposed += (sender, args) => {
|
||||||
|
this.browser.Dispose();
|
||||||
|
this.owner.FormClosed -= owner_FormClosed;
|
||||||
|
};
|
||||||
|
|
||||||
|
// ReSharper disable once VirtualMemberCallInContructor
|
||||||
|
UpdateTitle();
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void WndProc(ref Message m){
|
||||||
|
if (m.Msg == 0x0112 && (m.WParam.ToInt32() & 0xFFF0) == 0xF010 && !CanMoveWindow()){ // WM_SYSCOMMAND, SC_MOVE
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
base.WndProc(ref m);
|
||||||
|
}
|
||||||
|
|
||||||
|
// event handlers
|
||||||
|
|
||||||
|
private void owner_FormClosed(object sender, FormClosedEventArgs e){
|
||||||
|
Close();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void Browser_IsBrowserInitializedChanged(object sender, IsBrowserInitializedChangedEventArgs e){
|
||||||
|
if (e.IsBrowserInitialized){
|
||||||
|
Initialized?.Invoke(this, new EventArgs());
|
||||||
|
|
||||||
|
int identifier = browser.GetBrowser().Identifier;
|
||||||
|
Disposed += (sender2, args2) => BrowserProcesses.Forget(identifier);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// notification methods
|
||||||
|
|
||||||
|
public virtual void HideNotification(bool loadBlank){
|
||||||
|
if (loadBlank){
|
||||||
|
browser.Load("about:blank");
|
||||||
|
}
|
||||||
|
|
||||||
|
Location = ControlExtensions.InvisibleLocation;
|
||||||
|
currentColumn = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public virtual void FinishCurrentNotification(){}
|
||||||
|
|
||||||
|
public virtual void PauseNotification(){
|
||||||
|
if (pauseCounter++ == 0 && IsNotificationVisible){
|
||||||
|
Location = ControlExtensions.InvisibleLocation;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public virtual void ResumeNotification(){
|
||||||
|
if (pauseCounter > 0){
|
||||||
|
--pauseCounter;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected virtual string GetTweetHTML(TweetNotification tweet){
|
||||||
|
string bodyClasses = browser.Bounds.Contains(PointToClient(Cursor.Position)) ? "td-hover" : string.Empty;
|
||||||
|
return tweet.GenerateHtml(bodyClasses);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected virtual void LoadTweet(TweetNotification tweet){
|
||||||
|
CurrentTweetUrl = tweet.TweetUrl;
|
||||||
|
CurrentQuoteUrl = tweet.QuoteUrl;
|
||||||
|
currentColumn = tweet.Column;
|
||||||
|
|
||||||
|
resourceHandler.SetHTML(GetTweetHTML(tweet));
|
||||||
|
browser.Load(TwitterUtils.TweetDeckURL);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected virtual void SetNotificationSize(int width, int height){
|
||||||
|
browser.ClientSize = ClientSize = new Size(BrowserUtils.Scale(width, SizeScale), BrowserUtils.Scale(height, SizeScale));
|
||||||
|
}
|
||||||
|
|
||||||
|
protected virtual void OnNotificationReady(){
|
||||||
|
MoveToVisibleLocation();
|
||||||
|
}
|
||||||
|
|
||||||
|
protected virtual void UpdateTitle(){
|
||||||
|
Text = string.IsNullOrEmpty(currentColumn) || !Program.UserConfig.DisplayNotificationColumn ? Program.BrandName : Program.BrandName+" - "+currentColumn;
|
||||||
|
}
|
||||||
|
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private FormBorderStyle GetBorderStyle(bool sizable){
|
||||||
|
if (WindowsUtils.ShouldAvoidToolWindow && Visible){ // Visible = workaround for alt+tab
|
||||||
|
return sizable ? FormBorderStyle.Sizable : FormBorderStyle.FixedSingle;
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
return sizable ? FormBorderStyle.SizableToolWindow : FormBorderStyle.FixedToolWindow;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
namespace TweetDick.Core {
|
namespace TweetDuck.Core.Notification {
|
||||||
sealed partial class FormNotification {
|
partial class FormNotificationMain {
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Required designer variable.
|
/// Required designer variable.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -24,21 +24,15 @@
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
private void InitializeComponent() {
|
private void InitializeComponent() {
|
||||||
this.components = new System.ComponentModel.Container();
|
this.components = new System.ComponentModel.Container();
|
||||||
this.panelBrowser = new System.Windows.Forms.Panel();
|
this.timerDisplayDelay = new System.Windows.Forms.Timer(this.components);
|
||||||
this.timerProgress = new System.Windows.Forms.Timer(this.components);
|
this.timerProgress = new System.Windows.Forms.Timer(this.components);
|
||||||
this.progressBarTimer = new TweetDick.Core.Controls.FlatProgressBar();
|
this.progressBarTimer = new TweetDuck.Core.Controls.FlatProgressBar();
|
||||||
this.SuspendLayout();
|
this.SuspendLayout();
|
||||||
//
|
//
|
||||||
// panelBrowser
|
// timerDisplayDelay
|
||||||
//
|
//
|
||||||
this.panelBrowser.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left)
|
this.timerDisplayDelay.Interval = 17;
|
||||||
| System.Windows.Forms.AnchorStyles.Right)));
|
this.timerDisplayDelay.Tick += new System.EventHandler(this.timerDisplayDelay_Tick);
|
||||||
this.panelBrowser.BackColor = System.Drawing.Color.White;
|
|
||||||
this.panelBrowser.Location = new System.Drawing.Point(0, 0);
|
|
||||||
this.panelBrowser.Margin = new System.Windows.Forms.Padding(0);
|
|
||||||
this.panelBrowser.Name = "panelBrowser";
|
|
||||||
this.panelBrowser.Size = new System.Drawing.Size(284, 118);
|
|
||||||
this.panelBrowser.TabIndex = 0;
|
|
||||||
//
|
//
|
||||||
// timerProgress
|
// timerProgress
|
||||||
//
|
//
|
||||||
@@ -47,13 +41,15 @@
|
|||||||
//
|
//
|
||||||
// progressBarTimer
|
// progressBarTimer
|
||||||
//
|
//
|
||||||
|
this.progressBarTimer.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left)
|
||||||
|
| System.Windows.Forms.AnchorStyles.Right)));
|
||||||
this.progressBarTimer.BackColor = System.Drawing.SystemColors.Control;
|
this.progressBarTimer.BackColor = System.Drawing.SystemColors.Control;
|
||||||
this.progressBarTimer.ForeColor = System.Drawing.Color.FromArgb(((int)(((byte)(28)))), ((int)(((byte)(99)))), ((int)(((byte)(153)))));
|
this.progressBarTimer.ForeColor = System.Drawing.Color.FromArgb(((int)(((byte)(28)))), ((int)(((byte)(99)))), ((int)(((byte)(153)))));
|
||||||
this.progressBarTimer.Location = new System.Drawing.Point(0, 118);
|
this.progressBarTimer.Location = new System.Drawing.Point(0, 118);
|
||||||
this.progressBarTimer.Margin = new System.Windows.Forms.Padding(0);
|
this.progressBarTimer.Margin = new System.Windows.Forms.Padding(0);
|
||||||
this.progressBarTimer.Maximum = 1000;
|
this.progressBarTimer.Maximum = 1000;
|
||||||
this.progressBarTimer.Name = "progressBarTimer";
|
this.progressBarTimer.Name = "progressBarTimer";
|
||||||
this.progressBarTimer.Size = new System.Drawing.Size(284, 4);
|
this.progressBarTimer.Size = new System.Drawing.Size(284, TimerBarHeight);
|
||||||
this.progressBarTimer.TabIndex = 1;
|
this.progressBarTimer.TabIndex = 1;
|
||||||
//
|
//
|
||||||
// FormNotification
|
// FormNotification
|
||||||
@@ -63,12 +59,6 @@
|
|||||||
this.BackColor = System.Drawing.SystemColors.Control;
|
this.BackColor = System.Drawing.SystemColors.Control;
|
||||||
this.ClientSize = new System.Drawing.Size(284, 122);
|
this.ClientSize = new System.Drawing.Size(284, 122);
|
||||||
this.Controls.Add(this.progressBarTimer);
|
this.Controls.Add(this.progressBarTimer);
|
||||||
this.Controls.Add(this.panelBrowser);
|
|
||||||
this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedToolWindow;
|
|
||||||
this.Location = new System.Drawing.Point(-32000, -32000);
|
|
||||||
this.Name = "FormNotification";
|
|
||||||
this.ShowInTaskbar = false;
|
|
||||||
this.StartPosition = System.Windows.Forms.FormStartPosition.Manual;
|
|
||||||
this.FormClosing += new System.Windows.Forms.FormClosingEventHandler(this.FormNotification_FormClosing);
|
this.FormClosing += new System.Windows.Forms.FormClosingEventHandler(this.FormNotification_FormClosing);
|
||||||
this.ResumeLayout(false);
|
this.ResumeLayout(false);
|
||||||
|
|
||||||
@@ -76,8 +66,8 @@
|
|||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
private System.Windows.Forms.Panel panelBrowser;
|
private System.Windows.Forms.Timer timerDisplayDelay;
|
||||||
|
protected System.Windows.Forms.Timer timerProgress;
|
||||||
private Controls.FlatProgressBar progressBarTimer;
|
private Controls.FlatProgressBar progressBarTimer;
|
||||||
private System.Windows.Forms.Timer timerProgress;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
295
Core/Notification/FormNotificationMain.cs
Normal file
295
Core/Notification/FormNotificationMain.cs
Normal file
@@ -0,0 +1,295 @@
|
|||||||
|
using CefSharp;
|
||||||
|
using System;
|
||||||
|
using System.Drawing;
|
||||||
|
using System.Windows.Forms;
|
||||||
|
using TweetDuck.Core.Bridge;
|
||||||
|
using TweetDuck.Core.Controls;
|
||||||
|
using TweetDuck.Core.Handling;
|
||||||
|
using TweetDuck.Core.Utils;
|
||||||
|
using TweetDuck.Data;
|
||||||
|
using TweetDuck.Plugins;
|
||||||
|
using TweetDuck.Plugins.Enums;
|
||||||
|
using TweetDuck.Resources;
|
||||||
|
|
||||||
|
namespace TweetDuck.Core.Notification{
|
||||||
|
partial class FormNotificationMain : FormNotificationBase{
|
||||||
|
private const string NotificationScriptFile = "notification.js";
|
||||||
|
private const int TimerBarHeight = 4;
|
||||||
|
|
||||||
|
private static readonly string NotificationScriptIdentifier = ScriptLoader.GetRootIdentifier(NotificationScriptFile);
|
||||||
|
private static readonly string PluginScriptIdentifier = ScriptLoader.GetRootIdentifier(PluginManager.PluginNotificationScriptFile);
|
||||||
|
|
||||||
|
private static readonly string NotificationJS = ScriptLoader.LoadResource(NotificationScriptFile);
|
||||||
|
private static readonly string PluginJS = ScriptLoader.LoadResource(PluginManager.PluginNotificationScriptFile);
|
||||||
|
|
||||||
|
private readonly PluginManager plugins;
|
||||||
|
|
||||||
|
protected int timeLeft, totalTime;
|
||||||
|
protected bool pausedDuringNotification;
|
||||||
|
|
||||||
|
private readonly NativeMethods.HookProc mouseHookDelegate;
|
||||||
|
private IntPtr mouseHook;
|
||||||
|
private bool blockXButtonUp;
|
||||||
|
|
||||||
|
private bool? prevDisplayTimer;
|
||||||
|
private int? prevFontSize;
|
||||||
|
|
||||||
|
public bool RequiresResize{
|
||||||
|
get{
|
||||||
|
return !prevDisplayTimer.HasValue || !prevFontSize.HasValue || prevDisplayTimer != Program.UserConfig.DisplayNotificationTimer || prevFontSize != TweetNotification.FontSizeLevel || CanResizeWindow;
|
||||||
|
}
|
||||||
|
|
||||||
|
set{
|
||||||
|
if (value){
|
||||||
|
prevDisplayTimer = null;
|
||||||
|
prevFontSize = null;
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
prevDisplayTimer = Program.UserConfig.DisplayNotificationTimer;
|
||||||
|
prevFontSize = TweetNotification.FontSizeLevel;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private int BaseClientWidth{
|
||||||
|
get{
|
||||||
|
switch(Program.UserConfig.NotificationSize){
|
||||||
|
default:
|
||||||
|
return BrowserUtils.Scale(284, SizeScale*(1.0+0.05*TweetNotification.FontSizeLevel));
|
||||||
|
|
||||||
|
case TweetNotification.Size.Custom:
|
||||||
|
return Program.UserConfig.CustomNotificationSize.Width;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private int BaseClientHeight{
|
||||||
|
get{
|
||||||
|
switch(Program.UserConfig.NotificationSize){
|
||||||
|
default:
|
||||||
|
return BrowserUtils.Scale(122, SizeScale*(1.0+0.075*TweetNotification.FontSizeLevel));
|
||||||
|
|
||||||
|
case TweetNotification.Size.Custom:
|
||||||
|
return Program.UserConfig.CustomNotificationSize.Height;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public Size BrowserSize{
|
||||||
|
get => Program.UserConfig.DisplayNotificationTimer ? new Size(ClientSize.Width, ClientSize.Height-TimerBarHeight) : ClientSize;
|
||||||
|
}
|
||||||
|
|
||||||
|
public FormNotificationMain(FormBrowser owner, PluginManager pluginManager, bool enableContextMenu) : base(owner, enableContextMenu){
|
||||||
|
InitializeComponent();
|
||||||
|
|
||||||
|
this.plugins = pluginManager;
|
||||||
|
|
||||||
|
browser.KeyboardHandler = new KeyboardHandlerNotification(this);
|
||||||
|
|
||||||
|
browser.RegisterAsyncJsObject("$TD", new TweetDeckBridge(owner, this));
|
||||||
|
browser.RegisterAsyncJsObject("$TDP", plugins.Bridge);
|
||||||
|
|
||||||
|
browser.LoadingStateChanged += Browser_LoadingStateChanged;
|
||||||
|
browser.FrameLoadEnd += Browser_FrameLoadEnd;
|
||||||
|
|
||||||
|
mouseHookDelegate = MouseHookProc;
|
||||||
|
Disposed += (sender, args) => StopMouseHook(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
// mouse wheel hook
|
||||||
|
|
||||||
|
private void StartMouseHook(){
|
||||||
|
if (mouseHook == IntPtr.Zero){
|
||||||
|
mouseHook = NativeMethods.SetWindowsHookEx(NativeMethods.WM_MOUSE_LL, mouseHookDelegate, IntPtr.Zero, 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void StopMouseHook(bool force){
|
||||||
|
if (mouseHook != IntPtr.Zero && (force || !blockXButtonUp)){
|
||||||
|
NativeMethods.UnhookWindowsHookEx(mouseHook);
|
||||||
|
mouseHook = IntPtr.Zero;
|
||||||
|
blockXButtonUp = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private IntPtr MouseHookProc(int nCode, IntPtr wParam, IntPtr lParam){
|
||||||
|
if (nCode == 0){
|
||||||
|
int eventType = wParam.ToInt32();
|
||||||
|
|
||||||
|
if (eventType == NativeMethods.WM_MOUSEWHEEL && browser.Bounds.Contains(PointToClient(Cursor.Position))){
|
||||||
|
browser.SendMouseWheelEvent(0, 0, 0, BrowserUtils.Scale(NativeMethods.GetMouseHookData(lParam), Program.UserConfig.NotificationScrollSpeed/100.0), 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
|
||||||
|
this.InvokeAsyncSafe(FinishCurrentNotification);
|
||||||
|
}
|
||||||
|
else if (extraButton == 1){ // back button
|
||||||
|
this.InvokeAsyncSafe(Close);
|
||||||
|
}
|
||||||
|
|
||||||
|
blockXButtonUp = true;
|
||||||
|
return NativeMethods.HOOK_HANDLED;
|
||||||
|
}
|
||||||
|
else if (eventType == NativeMethods.WM_XBUTTONUP && blockXButtonUp){
|
||||||
|
blockXButtonUp = false;
|
||||||
|
|
||||||
|
if (!Visible){
|
||||||
|
StopMouseHook(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
return NativeMethods.HOOK_HANDLED;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return NativeMethods.CallNextHookEx(mouseHook, nCode, wParam, lParam);
|
||||||
|
}
|
||||||
|
|
||||||
|
// event handlers
|
||||||
|
|
||||||
|
private void FormNotification_FormClosing(object sender, FormClosingEventArgs e){
|
||||||
|
if (e.CloseReason == CloseReason.UserClosing){
|
||||||
|
HideNotification(true);
|
||||||
|
e.Cancel = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void Browser_LoadingStateChanged(object sender, LoadingStateChangedEventArgs e){
|
||||||
|
if (!e.IsLoading && browser.Address != "about:blank"){
|
||||||
|
this.InvokeSafe(() => {
|
||||||
|
Visible = true; // ensures repaint before moving the window to a visible location
|
||||||
|
timerDisplayDelay.Start();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void Browser_FrameLoadEnd(object sender, FrameLoadEndEventArgs e){
|
||||||
|
if (e.Frame.IsMain && NotificationJS != null && browser.Address != "about:blank"){
|
||||||
|
e.Frame.ExecuteJavaScriptAsync(PropertyBridge.GenerateScript(PropertyBridge.Environment.Notification));
|
||||||
|
ScriptLoader.ExecuteScript(e.Frame, NotificationJS, NotificationScriptIdentifier);
|
||||||
|
|
||||||
|
if (plugins.HasAnyPlugin(PluginEnvironment.Notification)){
|
||||||
|
ScriptLoader.ExecuteScript(e.Frame, PluginJS, PluginScriptIdentifier);
|
||||||
|
ScriptLoader.ExecuteFile(e.Frame, PluginManager.PluginGlobalScriptFile);
|
||||||
|
plugins.ExecutePlugins(e.Frame, PluginEnvironment.Notification, false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void timerDisplayDelay_Tick(object sender, EventArgs e){
|
||||||
|
OnNotificationReady();
|
||||||
|
timerDisplayDelay.Stop();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void timerHideProgress_Tick(object sender, EventArgs e){
|
||||||
|
if (Bounds.Contains(Cursor.Position) || FreezeTimer || ContextMenuOpen)return;
|
||||||
|
|
||||||
|
timeLeft -= timerProgress.Interval;
|
||||||
|
|
||||||
|
int value = BrowserUtils.Scale(1025, (totalTime-timeLeft)/(double)totalTime);
|
||||||
|
progressBarTimer.SetValueInstant(Math.Min(1000, Math.Max(0, Program.UserConfig.NotificationTimerCountDown ? 1000-value : value)));
|
||||||
|
|
||||||
|
if (timeLeft <= 0){
|
||||||
|
FinishCurrentNotification();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// notification methods
|
||||||
|
|
||||||
|
public virtual void ShowNotification(TweetNotification notification){
|
||||||
|
LoadTweet(notification);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void ShowNotificationForSettings(bool reset){
|
||||||
|
if (reset){
|
||||||
|
LoadTweet(TweetNotification.ExampleTweet);
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
PrepareAndDisplayWindow();
|
||||||
|
}
|
||||||
|
|
||||||
|
UpdateTitle();
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void HideNotification(bool loadBlank){
|
||||||
|
base.HideNotification(loadBlank);
|
||||||
|
|
||||||
|
progressBarTimer.Value = Program.UserConfig.NotificationTimerCountDown ? 1000 : 0;
|
||||||
|
timerProgress.Stop();
|
||||||
|
totalTime = 0;
|
||||||
|
|
||||||
|
StopMouseHook(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void FinishCurrentNotification(){
|
||||||
|
timerProgress.Stop();
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void PauseNotification(){
|
||||||
|
if (!IsPaused){
|
||||||
|
pausedDuringNotification = IsNotificationVisible;
|
||||||
|
timerProgress.Stop();
|
||||||
|
StopMouseHook(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
base.PauseNotification();
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void ResumeNotification(){
|
||||||
|
bool wasPaused = IsPaused;
|
||||||
|
base.ResumeNotification();
|
||||||
|
|
||||||
|
if (wasPaused && !IsPaused && pausedDuringNotification){
|
||||||
|
OnNotificationReady();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override string GetTweetHTML(TweetNotification tweet){
|
||||||
|
string html = base.GetTweetHTML(tweet);
|
||||||
|
|
||||||
|
foreach(InjectedHTML injection in plugins.Bridge.NotificationInjections){
|
||||||
|
html = injection.Inject(html);
|
||||||
|
}
|
||||||
|
|
||||||
|
return html;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void LoadTweet(TweetNotification tweet){
|
||||||
|
timerProgress.Stop();
|
||||||
|
totalTime = timeLeft = tweet.GetDisplayDuration(Program.UserConfig.NotificationDurationValue);
|
||||||
|
progressBarTimer.Value = Program.UserConfig.NotificationTimerCountDown ? 1000 : 0;
|
||||||
|
|
||||||
|
base.LoadTweet(tweet);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void SetNotificationSize(int width, int height){
|
||||||
|
if (Program.UserConfig.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);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void PrepareAndDisplayWindow(){
|
||||||
|
if (RequiresResize){
|
||||||
|
RequiresResize = false;
|
||||||
|
SetNotificationSize(BaseClientWidth, BaseClientHeight);
|
||||||
|
}
|
||||||
|
|
||||||
|
MoveToVisibleLocation();
|
||||||
|
StartMouseHook();
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void OnNotificationReady(){
|
||||||
|
PrepareAndDisplayWindow();
|
||||||
|
timerProgress.Start();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
53
Core/Notification/FormNotificationTweet.Designer.cs
generated
Normal file
53
Core/Notification/FormNotificationTweet.Designer.cs
generated
Normal file
@@ -0,0 +1,53 @@
|
|||||||
|
namespace TweetDuck.Core.Notification {
|
||||||
|
partial class FormNotificationTweet {
|
||||||
|
/// <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.components = new System.ComponentModel.Container();
|
||||||
|
this.timerCursorCheck = new System.Windows.Forms.Timer(this.components);
|
||||||
|
this.timerIdlePauseCheck = new System.Windows.Forms.Timer(this.components);
|
||||||
|
this.SuspendLayout();
|
||||||
|
//
|
||||||
|
// timerCursorCheck
|
||||||
|
//
|
||||||
|
this.timerCursorCheck.Interval = 200;
|
||||||
|
this.timerCursorCheck.Tick += new System.EventHandler(this.timerCursorCheck_Tick);
|
||||||
|
//
|
||||||
|
// timerIdlePauseCheck
|
||||||
|
//
|
||||||
|
this.timerIdlePauseCheck.Interval = 750;
|
||||||
|
this.timerIdlePauseCheck.Tick += new System.EventHandler(this.timerIdlePauseCheck_Tick);
|
||||||
|
//
|
||||||
|
// FormNotificationTweet
|
||||||
|
//
|
||||||
|
this.FormClosing += new System.Windows.Forms.FormClosingEventHandler(this.FormNotificationTweet_FormClosing);
|
||||||
|
this.ResumeLayout(true);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
private System.Windows.Forms.Timer timerCursorCheck;
|
||||||
|
private System.Windows.Forms.Timer timerIdlePauseCheck;
|
||||||
|
}
|
||||||
|
}
|
||||||
141
Core/Notification/FormNotificationTweet.cs
Normal file
141
Core/Notification/FormNotificationTweet.cs
Normal file
@@ -0,0 +1,141 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Drawing;
|
||||||
|
using TweetDuck.Plugins;
|
||||||
|
using System.Windows.Forms;
|
||||||
|
using TweetDuck.Core.Utils;
|
||||||
|
|
||||||
|
namespace TweetDuck.Core.Notification{
|
||||||
|
sealed partial class FormNotificationTweet : FormNotificationMain{
|
||||||
|
private const int NonIntrusiveIdleLimit = 30;
|
||||||
|
private const int TrimMinimum = 32;
|
||||||
|
|
||||||
|
private bool IsCursorOverNotificationArea => new Rectangle(PrimaryLocation, Size).Contains(Cursor.Position);
|
||||||
|
|
||||||
|
private readonly Queue<TweetNotification> tweetQueue = new Queue<TweetNotification>(4);
|
||||||
|
private bool needsTrim;
|
||||||
|
|
||||||
|
public FormNotificationTweet(FormBrowser owner, PluginManager pluginManager) : base(owner, pluginManager, true){
|
||||||
|
InitializeComponent();
|
||||||
|
|
||||||
|
Program.UserConfig.MuteToggled += Config_MuteToggled;
|
||||||
|
Disposed += (sender, args) => Program.UserConfig.MuteToggled -= Config_MuteToggled;
|
||||||
|
|
||||||
|
if (Program.UserConfig.MuteNotifications){
|
||||||
|
PauseNotification();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void FormNotificationTweet_FormClosing(object sender, FormClosingEventArgs e){
|
||||||
|
if (e.CloseReason == CloseReason.UserClosing){
|
||||||
|
tweetQueue.Clear(); // already canceled
|
||||||
|
TrimQueue();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void TrimQueue(){
|
||||||
|
if (needsTrim){
|
||||||
|
tweetQueue.TrimExcess();
|
||||||
|
needsTrim = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// event handlers
|
||||||
|
|
||||||
|
private void Config_MuteToggled(object sender, EventArgs e){
|
||||||
|
if (Program.UserConfig.MuteNotifications){
|
||||||
|
PauseNotification();
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
ResumeNotification();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void timerCursorCheck_Tick(object sender, EventArgs e){
|
||||||
|
if (!IsCursorOverNotificationArea){
|
||||||
|
ResumeNotification();
|
||||||
|
timerCursorCheck.Stop();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void timerIdlePauseCheck_Tick(object sender, EventArgs e){
|
||||||
|
if (NativeMethods.GetIdleSeconds() < Program.UserConfig.NotificationIdlePauseSeconds){
|
||||||
|
ResumeNotification();
|
||||||
|
timerIdlePauseCheck.Stop();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// notification methods
|
||||||
|
|
||||||
|
public override void ShowNotification(TweetNotification notification){
|
||||||
|
if (IsPaused){
|
||||||
|
tweetQueue.Enqueue(notification);
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
tweetQueue.Enqueue(notification);
|
||||||
|
UpdateTitle();
|
||||||
|
|
||||||
|
if (totalTime == 0){
|
||||||
|
LoadNextNotification();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
needsTrim |= tweetQueue.Count >= TrimMinimum;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void FinishCurrentNotification(){
|
||||||
|
if (tweetQueue.Count > 0){
|
||||||
|
LoadNextNotification();
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
HideNotification(true);
|
||||||
|
TrimQueue();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void ResumeNotification(){
|
||||||
|
bool wasPaused = IsPaused;
|
||||||
|
base.ResumeNotification();
|
||||||
|
|
||||||
|
if (wasPaused && !IsPaused && !pausedDuringNotification && tweetQueue.Count > 0){
|
||||||
|
LoadNextNotification();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void LoadNextNotification(){
|
||||||
|
if (!IsNotificationVisible){
|
||||||
|
if (Program.UserConfig.NotificationNonIntrusiveMode && IsCursorOverNotificationArea && NativeMethods.GetIdleSeconds() < NonIntrusiveIdleLimit){
|
||||||
|
if (!timerCursorCheck.Enabled){
|
||||||
|
PauseNotification();
|
||||||
|
timerCursorCheck.Start();
|
||||||
|
}
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
else if (Program.UserConfig.NotificationIdlePauseSeconds > 0 && NativeMethods.GetIdleSeconds() >= Program.UserConfig.NotificationIdlePauseSeconds){
|
||||||
|
if (!timerIdlePauseCheck.Enabled){
|
||||||
|
PauseNotification();
|
||||||
|
timerIdlePauseCheck.Start();
|
||||||
|
}
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
LoadTweet(tweetQueue.Dequeue());
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void UpdateTitle(){
|
||||||
|
base.UpdateTitle();
|
||||||
|
|
||||||
|
if (tweetQueue.Count > 0){
|
||||||
|
Text = Text+" ("+tweetQueue.Count+" more left)";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void OnNotificationReady(){
|
||||||
|
UpdateTitle();
|
||||||
|
base.OnNotificationReady();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,65 @@
|
|||||||
|
using System;
|
||||||
|
using System.Drawing;
|
||||||
|
using System.Drawing.Imaging;
|
||||||
|
using System.Windows.Forms;
|
||||||
|
using CefSharp;
|
||||||
|
using TweetDuck.Core.Bridge;
|
||||||
|
using TweetDuck.Core.Other;
|
||||||
|
using TweetDuck.Core.Utils;
|
||||||
|
using TweetDuck.Data;
|
||||||
|
using TweetDuck.Plugins;
|
||||||
|
using TweetDuck.Resources;
|
||||||
|
|
||||||
|
namespace TweetDuck.Core.Notification.Screenshot{
|
||||||
|
sealed class FormNotificationScreenshotable : FormNotificationBase{
|
||||||
|
private readonly PluginManager plugins;
|
||||||
|
|
||||||
|
public FormNotificationScreenshotable(Action callback, Form owner, PluginManager pluginManager) : base(owner, false){
|
||||||
|
this.plugins = pluginManager;
|
||||||
|
|
||||||
|
browser.RegisterAsyncJsObject("$TD_NotificationScreenshot", new CallbackBridge(this, callback));
|
||||||
|
|
||||||
|
browser.LoadingStateChanged += (sender, args) => {
|
||||||
|
if (!args.IsLoading){
|
||||||
|
using(IFrame frame = args.Browser.MainFrame){
|
||||||
|
ScriptLoader.ExecuteScript(frame, "window.setTimeout($TD_NotificationScreenshot.trigger, 129)", "gen:screenshot");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override string GetTweetHTML(TweetNotification tweet){
|
||||||
|
string html = tweet.GenerateHtml("td-screenshot", false);
|
||||||
|
|
||||||
|
foreach(InjectedHTML injection in plugins.Bridge.NotificationInjections){
|
||||||
|
html = injection.Inject(html);
|
||||||
|
}
|
||||||
|
|
||||||
|
return html;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void LoadNotificationForScreenshot(TweetNotification tweet, int width, int height){
|
||||||
|
LoadTweet(tweet);
|
||||||
|
SetNotificationSize(width, height);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void TakeScreenshot(){
|
||||||
|
IntPtr context = NativeMethods.GetDC(this.Handle);
|
||||||
|
|
||||||
|
if (context == IntPtr.Zero){
|
||||||
|
FormMessage.Error("Screenshot Failed", "Could not retrieve a graphics context handle for the notification window to take the screenshot.", FormMessage.OK);
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
using(Bitmap bmp = new Bitmap(ClientSize.Width, ClientSize.Height, PixelFormat.Format32bppRgb)){
|
||||||
|
try{
|
||||||
|
NativeMethods.RenderSourceIntoBitmap(context, bmp);
|
||||||
|
}finally{
|
||||||
|
NativeMethods.ReleaseDC(this.Handle, context);
|
||||||
|
}
|
||||||
|
|
||||||
|
Clipboard.SetImage(bmp);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
86
Core/Notification/Screenshot/TweetScreenshotManager.cs
Normal file
86
Core/Notification/Screenshot/TweetScreenshotManager.cs
Normal file
@@ -0,0 +1,86 @@
|
|||||||
|
// Uncomment to keep screenshot windows visible for debugging
|
||||||
|
// #define NO_HIDE_SCREENSHOTS
|
||||||
|
|
||||||
|
using System;
|
||||||
|
using System.Windows.Forms;
|
||||||
|
using TweetDuck.Core.Controls;
|
||||||
|
using TweetDuck.Plugins;
|
||||||
|
|
||||||
|
namespace TweetDuck.Core.Notification.Screenshot{
|
||||||
|
sealed class TweetScreenshotManager : IDisposable{
|
||||||
|
private readonly FormBrowser owner;
|
||||||
|
private readonly PluginManager plugins;
|
||||||
|
private readonly Timer timeout;
|
||||||
|
private readonly Timer disposer;
|
||||||
|
|
||||||
|
private FormNotificationScreenshotable screenshot;
|
||||||
|
|
||||||
|
public TweetScreenshotManager(FormBrowser owner, PluginManager pluginManager){
|
||||||
|
this.owner = owner;
|
||||||
|
this.plugins = pluginManager;
|
||||||
|
|
||||||
|
this.timeout = new Timer{ Interval = 8000 };
|
||||||
|
this.timeout.Tick += timeout_Tick;
|
||||||
|
|
||||||
|
this.disposer = new Timer{ Interval = 1 };
|
||||||
|
this.disposer.Tick += disposer_Tick;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void timeout_Tick(object sender, EventArgs e){
|
||||||
|
timeout.Stop();
|
||||||
|
OnFinished();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void disposer_Tick(object sender, EventArgs e){
|
||||||
|
disposer.Stop();
|
||||||
|
screenshot.Dispose();
|
||||||
|
screenshot = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Trigger(string html, int width, int height){
|
||||||
|
if (screenshot != null){
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
screenshot = new FormNotificationScreenshotable(Callback, owner, plugins){
|
||||||
|
CanMoveWindow = () => false
|
||||||
|
};
|
||||||
|
|
||||||
|
screenshot.LoadNotificationForScreenshot(new TweetNotification(string.Empty, html, 0, string.Empty, string.Empty), width, height);
|
||||||
|
screenshot.Show();
|
||||||
|
timeout.Start();
|
||||||
|
|
||||||
|
#if !(DEBUG && NO_HIDE_SCREENSHOTS)
|
||||||
|
owner.IsWaiting = true;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
private void Callback(){
|
||||||
|
if (!timeout.Enabled){
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
timeout.Stop();
|
||||||
|
screenshot.TakeScreenshot();
|
||||||
|
|
||||||
|
#if !(DEBUG && NO_HIDE_SCREENSHOTS)
|
||||||
|
OnFinished();
|
||||||
|
#else
|
||||||
|
screenshot.MoveToVisibleLocation();
|
||||||
|
screenshot.FormClosed += (sender, args) => disposer.Start();
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OnFinished(){
|
||||||
|
screenshot.Location = ControlExtensions.InvisibleLocation;
|
||||||
|
owner.IsWaiting = false;
|
||||||
|
disposer.Start();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Dispose(){
|
||||||
|
timeout.Dispose();
|
||||||
|
disposer.Dispose();
|
||||||
|
screenshot?.Dispose();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
28
Core/Notification/SoundNotification.cs
Normal file
28
Core/Notification/SoundNotification.cs
Normal file
@@ -0,0 +1,28 @@
|
|||||||
|
using System;
|
||||||
|
using TweetLib.Audio;
|
||||||
|
|
||||||
|
namespace TweetDuck.Core.Notification{
|
||||||
|
sealed class SoundNotification : IDisposable{
|
||||||
|
public string SupportedFormats => player.SupportedFormats;
|
||||||
|
public event EventHandler<PlaybackErrorEventArgs> PlaybackError;
|
||||||
|
|
||||||
|
private readonly AudioPlayer player;
|
||||||
|
|
||||||
|
public SoundNotification(){
|
||||||
|
this.player = AudioPlayer.New();
|
||||||
|
this.player.PlaybackError += Player_PlaybackError;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Play(string file){
|
||||||
|
player.Play(file);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void Player_PlaybackError(object sender, PlaybackErrorEventArgs e){
|
||||||
|
PlaybackError?.Invoke(this, e);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Dispose(){
|
||||||
|
player.Dispose();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
110
Core/Notification/TweetNotification.cs
Normal file
110
Core/Notification/TweetNotification.cs
Normal file
@@ -0,0 +1,110 @@
|
|||||||
|
using System;
|
||||||
|
using System.Text;
|
||||||
|
using TweetDuck.Resources;
|
||||||
|
|
||||||
|
namespace TweetDuck.Core.Notification{
|
||||||
|
sealed class TweetNotification{
|
||||||
|
private static string FontSizeClass { get; set; }
|
||||||
|
private static string HeadTag { get; set; }
|
||||||
|
|
||||||
|
private const string DefaultFontSizeClass = "medium";
|
||||||
|
private const string DefaultHeadTag = @"<meta charset='utf-8'><meta http-equiv='X-UA-Compatible' content='chrome=1'><link rel='stylesheet' href='https://ton.twimg.com/tweetdeck-web/web/css/font.5ef884f9f9.css'><link rel='stylesheet' href='https://ton.twimg.com/tweetdeck-web/web/css/app-dark.5631e0dd42.css'><style type='text/css'>body{background:#222426}</style>";
|
||||||
|
private const string CustomCSS = @"body:before{content:none}body{overflow-y:auto}.scroll-styled-v::-webkit-scrollbar{width:7px}.scroll-styled-v::-webkit-scrollbar-thumb{border-radius:0}.scroll-styled-v::-webkit-scrollbar-track{border-left:0}#td-skip{opacity:0;cursor:pointer;transition:opacity 0.15s ease}.td-hover #td-skip{opacity:0.75}#td-skip:hover{opacity:1}.media-size-medium{height:calc(100vh - 16px)!important;max-height:240px;border-radius:1px!important}.js-quote-detail .media-size-medium{height:calc(100vh - 28px)!important;}.js-media.margin-vm, .js-media-preview-container.margin-vm{margin-bottom:0!important}";
|
||||||
|
|
||||||
|
public static int FontSizeLevel{
|
||||||
|
get{
|
||||||
|
switch(FontSizeClass){
|
||||||
|
case "largest": return 4;
|
||||||
|
case "large": return 3;
|
||||||
|
case "medium": return 2;
|
||||||
|
case "small": return 1;
|
||||||
|
default: return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static string ExampleTweetHTML;
|
||||||
|
|
||||||
|
public static TweetNotification ExampleTweet{
|
||||||
|
get{
|
||||||
|
if (ExampleTweetHTML == null){
|
||||||
|
ExampleTweetHTML = ScriptLoader.LoadResource("pages/example.html", true);
|
||||||
|
|
||||||
|
#if DEBUG
|
||||||
|
ExampleTweetHTML = ExampleTweetHTML.Replace("</p>", @"</p><div style='margin-top:256px'>Scrollbar test padding...</div>");
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
return new TweetNotification("Home", ExampleTweetHTML, 95, string.Empty, string.Empty, true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void SetFontSizeClass(string newFSClass){
|
||||||
|
FontSizeClass = newFSClass;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void SetHeadTag(string headContents){
|
||||||
|
HeadTag = headContents;
|
||||||
|
}
|
||||||
|
|
||||||
|
public enum Position{
|
||||||
|
TopLeft, TopRight, BottomLeft, BottomRight, Custom
|
||||||
|
}
|
||||||
|
|
||||||
|
public enum Size{
|
||||||
|
Auto, Custom
|
||||||
|
}
|
||||||
|
|
||||||
|
public string Column { get; }
|
||||||
|
public string TweetUrl { get; }
|
||||||
|
public string QuoteUrl { get; }
|
||||||
|
|
||||||
|
private readonly string html;
|
||||||
|
private readonly int characters;
|
||||||
|
private readonly bool isExample;
|
||||||
|
|
||||||
|
public TweetNotification(string column, string html, int characters, string tweetUrl, string quoteUrl) : this(column, html, characters, tweetUrl, quoteUrl, false){}
|
||||||
|
|
||||||
|
private TweetNotification(string column, string html, int characters, string tweetUrl, string quoteUrl, bool isExample){
|
||||||
|
this.Column = column;
|
||||||
|
this.TweetUrl = tweetUrl;
|
||||||
|
this.QuoteUrl = quoteUrl;
|
||||||
|
|
||||||
|
this.html = html;
|
||||||
|
this.characters = characters;
|
||||||
|
this.isExample = isExample;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int GetDisplayDuration(int value){
|
||||||
|
return 2000+Math.Max(1000, value*characters);
|
||||||
|
}
|
||||||
|
|
||||||
|
public string GenerateHtml(string bodyClasses = null, bool enableCustomCSS = true){
|
||||||
|
StringBuilder build = new StringBuilder();
|
||||||
|
build.Append("<!DOCTYPE html>");
|
||||||
|
build.Append("<html class='os-windows txt-base-").Append(FontSizeClass ?? DefaultFontSizeClass).Append("'>");
|
||||||
|
build.Append("<head>").Append(HeadTag ?? DefaultHeadTag);
|
||||||
|
|
||||||
|
if (enableCustomCSS){
|
||||||
|
build.Append("<style type='text/css'>").Append(CustomCSS).Append("</style>");
|
||||||
|
|
||||||
|
if (!string.IsNullOrEmpty(Program.UserConfig.CustomNotificationCSS)){
|
||||||
|
build.Append("<style type='text/css'>").Append(Program.UserConfig.CustomNotificationCSS).Append("</style>");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
build.Append("</head>");
|
||||||
|
build.Append("<body class='scroll-styled-v");
|
||||||
|
|
||||||
|
if (!string.IsNullOrEmpty(bodyClasses)){
|
||||||
|
build.Append(' ').Append(bodyClasses);
|
||||||
|
}
|
||||||
|
|
||||||
|
build.Append('\'').Append(isExample ? " td-example-notification" : "").Append("><div class='column' style='width:100%;height:auto;overflow:initial;'>");
|
||||||
|
build.Append(html);
|
||||||
|
build.Append("</div></body>");
|
||||||
|
build.Append("</html>");
|
||||||
|
return build.ToString();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
125
Core/Other/FormAbout.Designer.cs
generated
125
Core/Other/FormAbout.Designer.cs
generated
@@ -1,4 +1,4 @@
|
|||||||
namespace TweetDick.Core.Other {
|
namespace TweetDuck.Core.Other {
|
||||||
sealed partial class FormAbout {
|
sealed partial class FormAbout {
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Required designer variable.
|
/// Required designer variable.
|
||||||
@@ -23,43 +23,134 @@
|
|||||||
/// the contents of this method with the code editor.
|
/// the contents of this method with the code editor.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
private void InitializeComponent() {
|
private void InitializeComponent() {
|
||||||
this.labelAbout = new TweetDick.Core.Controls.RichTextLabel();
|
System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(FormAbout));
|
||||||
|
this.pictureLogo = new System.Windows.Forms.PictureBox();
|
||||||
|
this.labelDescription = new System.Windows.Forms.Label();
|
||||||
|
this.labelTips = new System.Windows.Forms.LinkLabel();
|
||||||
|
this.labelWebsite = new System.Windows.Forms.LinkLabel();
|
||||||
|
this.tablePanelLinks = new System.Windows.Forms.TableLayoutPanel();
|
||||||
|
this.labelIssues = new System.Windows.Forms.LinkLabel();
|
||||||
|
((System.ComponentModel.ISupportInitialize)(this.pictureLogo)).BeginInit();
|
||||||
|
this.tablePanelLinks.SuspendLayout();
|
||||||
this.SuspendLayout();
|
this.SuspendLayout();
|
||||||
//
|
//
|
||||||
// labelAbout
|
// pictureLogo
|
||||||
//
|
//
|
||||||
this.labelAbout.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom)
|
this.pictureLogo.BackgroundImageLayout = System.Windows.Forms.ImageLayout.None;
|
||||||
|
this.pictureLogo.ErrorImage = null;
|
||||||
|
this.pictureLogo.Image = ((System.Drawing.Image)(resources.GetObject("pictureLogo.Image")));
|
||||||
|
this.pictureLogo.InitialImage = null;
|
||||||
|
this.pictureLogo.Location = new System.Drawing.Point(12, 12);
|
||||||
|
this.pictureLogo.Name = "pictureLogo";
|
||||||
|
this.pictureLogo.Size = new System.Drawing.Size(96, 96);
|
||||||
|
this.pictureLogo.TabIndex = 0;
|
||||||
|
this.pictureLogo.TabStop = false;
|
||||||
|
//
|
||||||
|
// labelDescription
|
||||||
|
//
|
||||||
|
this.labelDescription.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom)
|
||||||
| System.Windows.Forms.AnchorStyles.Left)
|
| System.Windows.Forms.AnchorStyles.Left)
|
||||||
| System.Windows.Forms.AnchorStyles.Right)));
|
| System.Windows.Forms.AnchorStyles.Right)));
|
||||||
this.labelAbout.BackColor = System.Drawing.Color.White;
|
this.labelDescription.Font = new System.Drawing.Font("Microsoft Sans Serif", 9.75F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(238)));
|
||||||
this.labelAbout.BorderStyle = System.Windows.Forms.BorderStyle.None;
|
this.labelDescription.Location = new System.Drawing.Point(114, 12);
|
||||||
this.labelAbout.Location = new System.Drawing.Point(12, 12);
|
this.labelDescription.Name = "labelDescription";
|
||||||
this.labelAbout.Name = "labelAbout";
|
this.labelDescription.Size = new System.Drawing.Size(232, 109);
|
||||||
this.labelAbout.ReadOnly = true;
|
this.labelDescription.TabIndex = 0;
|
||||||
this.labelAbout.ScrollBars = System.Windows.Forms.RichTextBoxScrollBars.None;
|
//
|
||||||
this.labelAbout.Size = new System.Drawing.Size(360, 126);
|
// labelTips
|
||||||
this.labelAbout.TabIndex = 0;
|
//
|
||||||
this.labelAbout.TabStop = false;
|
this.labelTips.Dock = System.Windows.Forms.DockStyle.Fill;
|
||||||
this.labelAbout.Text = "";
|
this.labelTips.Font = new System.Drawing.Font("Microsoft Sans Serif", 9.75F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(238)));
|
||||||
|
this.labelTips.LinkArea = new System.Windows.Forms.LinkArea(0, 0);
|
||||||
|
this.labelTips.Location = new System.Drawing.Point(117, 0);
|
||||||
|
this.labelTips.Margin = new System.Windows.Forms.Padding(0);
|
||||||
|
this.labelTips.Name = "labelTips";
|
||||||
|
this.labelTips.Size = new System.Drawing.Size(99, 16);
|
||||||
|
this.labelTips.TabIndex = 1;
|
||||||
|
this.labelTips.TabStop = true;
|
||||||
|
this.labelTips.Text = "Tips && Tricks";
|
||||||
|
this.labelTips.TextAlign = System.Drawing.ContentAlignment.MiddleCenter;
|
||||||
|
this.labelTips.LinkClicked += new System.Windows.Forms.LinkLabelLinkClickedEventHandler(this.OnLinkClicked);
|
||||||
|
//
|
||||||
|
// labelWebsite
|
||||||
|
//
|
||||||
|
this.labelWebsite.AutoSize = true;
|
||||||
|
this.labelWebsite.Dock = System.Windows.Forms.DockStyle.Fill;
|
||||||
|
this.labelWebsite.Font = new System.Drawing.Font("Microsoft Sans Serif", 9.75F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(238)));
|
||||||
|
this.labelWebsite.LinkArea = new System.Windows.Forms.LinkArea(0, 0);
|
||||||
|
this.labelWebsite.Location = new System.Drawing.Point(0, 0);
|
||||||
|
this.labelWebsite.Margin = new System.Windows.Forms.Padding(0);
|
||||||
|
this.labelWebsite.Name = "labelWebsite";
|
||||||
|
this.labelWebsite.Size = new System.Drawing.Size(117, 16);
|
||||||
|
this.labelWebsite.TabIndex = 0;
|
||||||
|
this.labelWebsite.TabStop = true;
|
||||||
|
this.labelWebsite.Text = "Official Website";
|
||||||
|
this.labelWebsite.TextAlign = System.Drawing.ContentAlignment.MiddleLeft;
|
||||||
|
this.labelWebsite.LinkClicked += new System.Windows.Forms.LinkLabelLinkClickedEventHandler(this.OnLinkClicked);
|
||||||
|
//
|
||||||
|
// tablePanelLinks
|
||||||
|
//
|
||||||
|
this.tablePanelLinks.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left)
|
||||||
|
| System.Windows.Forms.AnchorStyles.Right)));
|
||||||
|
this.tablePanelLinks.ColumnCount = 3;
|
||||||
|
this.tablePanelLinks.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 35.16F));
|
||||||
|
this.tablePanelLinks.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 29.7F));
|
||||||
|
this.tablePanelLinks.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 35.14F));
|
||||||
|
this.tablePanelLinks.Controls.Add(this.labelIssues, 2, 0);
|
||||||
|
this.tablePanelLinks.Controls.Add(this.labelWebsite, 0, 0);
|
||||||
|
this.tablePanelLinks.Controls.Add(this.labelTips, 1, 0);
|
||||||
|
this.tablePanelLinks.Location = new System.Drawing.Point(12, 124);
|
||||||
|
this.tablePanelLinks.Name = "tablePanelLinks";
|
||||||
|
this.tablePanelLinks.RowCount = 1;
|
||||||
|
this.tablePanelLinks.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 100F));
|
||||||
|
this.tablePanelLinks.Size = new System.Drawing.Size(334, 16);
|
||||||
|
this.tablePanelLinks.TabIndex = 1;
|
||||||
|
//
|
||||||
|
// labelIssues
|
||||||
|
//
|
||||||
|
this.labelIssues.Dock = System.Windows.Forms.DockStyle.Fill;
|
||||||
|
this.labelIssues.Font = new System.Drawing.Font("Microsoft Sans Serif", 9.75F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(238)));
|
||||||
|
this.labelIssues.LinkArea = new System.Windows.Forms.LinkArea(0, 0);
|
||||||
|
this.labelIssues.Location = new System.Drawing.Point(216, 0);
|
||||||
|
this.labelIssues.Margin = new System.Windows.Forms.Padding(0);
|
||||||
|
this.labelIssues.Name = "labelIssues";
|
||||||
|
this.labelIssues.Size = new System.Drawing.Size(118, 16);
|
||||||
|
this.labelIssues.TabIndex = 2;
|
||||||
|
this.labelIssues.TabStop = true;
|
||||||
|
this.labelIssues.Text = "Report an Issue";
|
||||||
|
this.labelIssues.TextAlign = System.Drawing.ContentAlignment.MiddleRight;
|
||||||
|
this.labelIssues.LinkClicked += new System.Windows.Forms.LinkLabelLinkClickedEventHandler(this.OnLinkClicked);
|
||||||
//
|
//
|
||||||
// FormAbout
|
// FormAbout
|
||||||
//
|
//
|
||||||
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
|
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
|
||||||
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
|
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
|
||||||
this.BackColor = System.Drawing.Color.White;
|
this.BackColor = System.Drawing.Color.White;
|
||||||
this.ClientSize = new System.Drawing.Size(384, 150);
|
this.ClientSize = new System.Drawing.Size(358, 152);
|
||||||
this.Controls.Add(this.labelAbout);
|
this.Controls.Add(this.tablePanelLinks);
|
||||||
|
this.Controls.Add(this.labelDescription);
|
||||||
|
this.Controls.Add(this.pictureLogo);
|
||||||
this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedDialog;
|
this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedDialog;
|
||||||
this.MaximizeBox = false;
|
this.MaximizeBox = false;
|
||||||
this.MinimizeBox = false;
|
this.MinimizeBox = false;
|
||||||
this.Name = "FormAbout";
|
this.Name = "FormAbout";
|
||||||
|
this.ShowIcon = false;
|
||||||
this.StartPosition = System.Windows.Forms.FormStartPosition.CenterParent;
|
this.StartPosition = System.Windows.Forms.FormStartPosition.CenterParent;
|
||||||
|
((System.ComponentModel.ISupportInitialize)(this.pictureLogo)).EndInit();
|
||||||
|
this.tablePanelLinks.ResumeLayout(false);
|
||||||
|
this.tablePanelLinks.PerformLayout();
|
||||||
this.ResumeLayout(false);
|
this.ResumeLayout(false);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
private Controls.RichTextLabel labelAbout;
|
private System.Windows.Forms.PictureBox pictureLogo;
|
||||||
|
private System.Windows.Forms.Label labelDescription;
|
||||||
|
private System.Windows.Forms.LinkLabel labelTips;
|
||||||
|
private System.Windows.Forms.LinkLabel labelWebsite;
|
||||||
|
private System.Windows.Forms.TableLayoutPanel tablePanelLinks;
|
||||||
|
private System.Windows.Forms.LinkLabel labelIssues;
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1,20 +1,25 @@
|
|||||||
using System.Text;
|
using System.Windows.Forms;
|
||||||
using System.Windows.Forms;
|
using TweetDuck.Core.Utils;
|
||||||
using TweetDick.Core.Controls;
|
|
||||||
|
|
||||||
namespace TweetDick.Core.Other{
|
namespace TweetDuck.Core.Other{
|
||||||
sealed partial class FormAbout : Form{
|
sealed partial class FormAbout : Form{
|
||||||
|
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;
|
Text = "About "+Program.BrandName+" "+Program.VersionTag;
|
||||||
|
|
||||||
StringBuilder build = new StringBuilder();
|
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.";
|
||||||
build.Append(@"\fs22").Append(Program.BrandName).Append(@" was created by chylex as a replacement to the discontinued TweetDeck client for Windows, and is released under the MIT license.\par ");
|
|
||||||
build.Append(@"Official Website: ").Append(RichTextLabel.AddLink(Program.Website)).Append(@"\line ");
|
labelWebsite.Links.Add(new LinkLabel.Link(0, labelWebsite.Text.Length, Program.Website));
|
||||||
build.Append(@"Source Code: ").Append(RichTextLabel.AddLink("https://github.com/chylex/TweetDick"));
|
labelTips.Links.Add(new LinkLabel.Link(0, labelTips.Text.Length, TipsLink));
|
||||||
|
labelIssues.Links.Add(new LinkLabel.Link(0, labelIssues.Text.Length, IssuesLink));
|
||||||
|
}
|
||||||
|
|
||||||
labelAbout.Rtf = RichTextLabel.Wrap(build.ToString());
|
private void OnLinkClicked(object sender, LinkLabelLinkClickedEventArgs e){
|
||||||
|
BrowserUtils.OpenExternalBrowserUnsafe(e.Link.LinkData as string);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
246
Core/Other/FormAbout.resx
Normal file
246
Core/Other/FormAbout.resx
Normal file
@@ -0,0 +1,246 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<root>
|
||||||
|
<!--
|
||||||
|
Microsoft ResX Schema
|
||||||
|
|
||||||
|
Version 2.0
|
||||||
|
|
||||||
|
The primary goals of this format is to allow a simple XML format
|
||||||
|
that is mostly human readable. The generation and parsing of the
|
||||||
|
various data types are done through the TypeConverter classes
|
||||||
|
associated with the data types.
|
||||||
|
|
||||||
|
Example:
|
||||||
|
|
||||||
|
... ado.net/XML headers & schema ...
|
||||||
|
<resheader name="resmimetype">text/microsoft-resx</resheader>
|
||||||
|
<resheader name="version">2.0</resheader>
|
||||||
|
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
|
||||||
|
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
|
||||||
|
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
|
||||||
|
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
|
||||||
|
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
|
||||||
|
<value>[base64 mime encoded serialized .NET Framework object]</value>
|
||||||
|
</data>
|
||||||
|
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
|
||||||
|
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
|
||||||
|
<comment>This is a comment</comment>
|
||||||
|
</data>
|
||||||
|
|
||||||
|
There are any number of "resheader" rows that contain simple
|
||||||
|
name/value pairs.
|
||||||
|
|
||||||
|
Each data row contains a name, and value. The row also contains a
|
||||||
|
type or mimetype. Type corresponds to a .NET class that support
|
||||||
|
text/value conversion through the TypeConverter architecture.
|
||||||
|
Classes that don't support this are serialized and stored with the
|
||||||
|
mimetype set.
|
||||||
|
|
||||||
|
The mimetype is used for serialized objects, and tells the
|
||||||
|
ResXResourceReader how to depersist the object. This is currently not
|
||||||
|
extensible. For a given mimetype the value must be set accordingly:
|
||||||
|
|
||||||
|
Note - application/x-microsoft.net.object.binary.base64 is the format
|
||||||
|
that the ResXResourceWriter will generate, however the reader can
|
||||||
|
read any of the formats listed below.
|
||||||
|
|
||||||
|
mimetype: application/x-microsoft.net.object.binary.base64
|
||||||
|
value : The object must be serialized with
|
||||||
|
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
|
||||||
|
: and then encoded with base64 encoding.
|
||||||
|
|
||||||
|
mimetype: application/x-microsoft.net.object.soap.base64
|
||||||
|
value : The object must be serialized with
|
||||||
|
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
|
||||||
|
: and then encoded with base64 encoding.
|
||||||
|
|
||||||
|
mimetype: application/x-microsoft.net.object.bytearray.base64
|
||||||
|
value : The object must be serialized into a byte array
|
||||||
|
: using a System.ComponentModel.TypeConverter
|
||||||
|
: and then encoded with base64 encoding.
|
||||||
|
-->
|
||||||
|
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
|
||||||
|
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
|
||||||
|
<xsd:element name="root" msdata:IsDataSet="true">
|
||||||
|
<xsd:complexType>
|
||||||
|
<xsd:choice maxOccurs="unbounded">
|
||||||
|
<xsd:element name="metadata">
|
||||||
|
<xsd:complexType>
|
||||||
|
<xsd:sequence>
|
||||||
|
<xsd:element name="value" type="xsd:string" minOccurs="0" />
|
||||||
|
</xsd:sequence>
|
||||||
|
<xsd:attribute name="name" use="required" type="xsd:string" />
|
||||||
|
<xsd:attribute name="type" type="xsd:string" />
|
||||||
|
<xsd:attribute name="mimetype" type="xsd:string" />
|
||||||
|
<xsd:attribute ref="xml:space" />
|
||||||
|
</xsd:complexType>
|
||||||
|
</xsd:element>
|
||||||
|
<xsd:element name="assembly">
|
||||||
|
<xsd:complexType>
|
||||||
|
<xsd:attribute name="alias" type="xsd:string" />
|
||||||
|
<xsd:attribute name="name" type="xsd:string" />
|
||||||
|
</xsd:complexType>
|
||||||
|
</xsd:element>
|
||||||
|
<xsd:element name="data">
|
||||||
|
<xsd:complexType>
|
||||||
|
<xsd:sequence>
|
||||||
|
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
|
||||||
|
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
|
||||||
|
</xsd:sequence>
|
||||||
|
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
|
||||||
|
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
|
||||||
|
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
|
||||||
|
<xsd:attribute ref="xml:space" />
|
||||||
|
</xsd:complexType>
|
||||||
|
</xsd:element>
|
||||||
|
<xsd:element name="resheader">
|
||||||
|
<xsd:complexType>
|
||||||
|
<xsd:sequence>
|
||||||
|
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
|
||||||
|
</xsd:sequence>
|
||||||
|
<xsd:attribute name="name" type="xsd:string" use="required" />
|
||||||
|
</xsd:complexType>
|
||||||
|
</xsd:element>
|
||||||
|
</xsd:choice>
|
||||||
|
</xsd:complexType>
|
||||||
|
</xsd:element>
|
||||||
|
</xsd:schema>
|
||||||
|
<resheader name="resmimetype">
|
||||||
|
<value>text/microsoft-resx</value>
|
||||||
|
</resheader>
|
||||||
|
<resheader name="version">
|
||||||
|
<value>2.0</value>
|
||||||
|
</resheader>
|
||||||
|
<resheader name="reader">
|
||||||
|
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||||
|
</resheader>
|
||||||
|
<resheader name="writer">
|
||||||
|
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||||
|
</resheader>
|
||||||
|
<assembly alias="System.Drawing" name="System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" />
|
||||||
|
<data name="pictureLogo.Image" type="System.Drawing.Bitmap, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
|
||||||
|
<value>
|
||||||
|
iVBORw0KGgoAAAANSUhEUgAAAGAAAABgCAYAAADimHc4AAAABGdBTUEAALGOfPtRkwAAACBjSFJNAACH
|
||||||
|
DwAAjA8AAP1SAACBQAAAfXkAAOmLAAA85QAAGcxzPIV3AAAKOWlDQ1BQaG90b3Nob3AgSUNDIHByb2Zp
|
||||||
|
bGUAAEjHnZZ3VFTXFofPvXd6oc0wAlKG3rvAANJ7k15FYZgZYCgDDjM0sSGiAhFFRJoiSFDEgNFQJFZE
|
||||||
|
sRAUVLAHJAgoMRhFVCxvRtaLrqy89/Ly++Osb+2z97n77L3PWhcAkqcvl5cGSwGQyhPwgzyc6RGRUXTs
|
||||||
|
AIABHmCAKQBMVka6X7B7CBDJy82FniFyAl8EAfB6WLwCcNPQM4BOB/+fpFnpfIHomAARm7M5GSwRF4g4
|
||||||
|
JUuQLrbPipgalyxmGCVmvihBEcuJOWGRDT77LLKjmNmpPLaIxTmns1PZYu4V8bZMIUfEiK+ICzO5nCwR
|
||||||
|
3xKxRoowlSviN+LYVA4zAwAUSWwXcFiJIjYRMYkfEuQi4uUA4EgJX3HcVyzgZAvEl3JJS8/hcxMSBXQd
|
||||||
|
li7d1NqaQffkZKVwBALDACYrmcln013SUtOZvBwAFu/8WTLi2tJFRbY0tba0NDQzMv2qUP91829K3NtF
|
||||||
|
ehn4uWcQrf+L7a/80hoAYMyJarPziy2uCoDOLQDI3fti0zgAgKSobx3Xv7oPTTwviQJBuo2xcVZWlhGX
|
||||||
|
wzISF/QP/U+Hv6GvvmckPu6P8tBdOfFMYYqALq4bKy0lTcinZ6QzWRy64Z+H+B8H/nUeBkGceA6fwxNF
|
||||||
|
hImmjMtLELWbx+YKuGk8Opf3n5r4D8P+pMW5FonS+BFQY4yA1HUqQH7tBygKESDR+8Vd/6NvvvgwIH55
|
||||||
|
4SqTi3P/7zf9Z8Gl4iWDm/A5ziUohM4S8jMX98TPEqABAUgCKpAHykAd6ABDYAasgC1wBG7AG/iDEBAJ
|
||||||
|
VgMWSASpgA+yQB7YBApBMdgJ9oBqUAcaQTNoBcdBJzgFzoNL4Bq4AW6D+2AUTIBnYBa8BgsQBGEhMkSB
|
||||||
|
5CEVSBPSh8wgBmQPuUG+UBAUCcVCCRAPEkJ50GaoGCqDqqF6qBn6HjoJnYeuQIPQXWgMmoZ+h97BCEyC
|
||||||
|
qbASrAUbwwzYCfaBQ+BVcAK8Bs6FC+AdcCXcAB+FO+Dz8DX4NjwKP4PnEIAQERqiihgiDMQF8UeikHiE
|
||||||
|
j6xHipAKpAFpRbqRPuQmMorMIG9RGBQFRUcZomxRnqhQFAu1BrUeVYKqRh1GdaB6UTdRY6hZ1Ec0Ga2I
|
||||||
|
1kfboL3QEegEdBa6EF2BbkK3oy+ib6Mn0K8xGAwNo42xwnhiIjFJmLWYEsw+TBvmHGYQM46Zw2Kx8lh9
|
||||||
|
rB3WH8vECrCF2CrsUexZ7BB2AvsGR8Sp4Mxw7rgoHA+Xj6vAHcGdwQ3hJnELeCm8Jt4G749n43PwpfhG
|
||||||
|
fDf+On4Cv0CQJmgT7AghhCTCJkIloZVwkfCA8JJIJKoRrYmBRC5xI7GSeIx4mThGfEuSIemRXEjRJCFp
|
||||||
|
B+kQ6RzpLuklmUzWIjuSo8gC8g5yM/kC+RH5jQRFwkjCS4ItsUGiRqJDYkjiuSReUlPSSXK1ZK5kheQJ
|
||||||
|
yeuSM1J4KS0pFymm1HqpGqmTUiNSc9IUaVNpf+lU6RLpI9JXpKdksDJaMm4ybJkCmYMyF2TGKQhFneJC
|
||||||
|
YVE2UxopFykTVAxVm+pFTaIWU7+jDlBnZWVkl8mGyWbL1sielh2lITQtmhcthVZKO04bpr1borTEaQln
|
||||||
|
yfYlrUuGlszLLZVzlOPIFcm1yd2WeydPl3eTT5bfJd8p/1ABpaCnEKiQpbBf4aLCzFLqUtulrKVFS48v
|
||||||
|
vacIK+opBimuVTyo2K84p6Ss5KGUrlSldEFpRpmm7KicpFyufEZ5WoWiYq/CVSlXOavylC5Ld6Kn0Cvp
|
||||||
|
vfRZVUVVT1Whar3qgOqCmrZaqFq+WpvaQ3WCOkM9Xr1cvUd9VkNFw08jT6NF454mXpOhmai5V7NPc15L
|
||||||
|
Wytca6tWp9aUtpy2l3audov2Ax2yjoPOGp0GnVu6GF2GbrLuPt0berCehV6iXo3edX1Y31Kfq79Pf9AA
|
||||||
|
bWBtwDNoMBgxJBk6GWYathiOGdGMfI3yjTqNnhtrGEcZ7zLuM/5oYmGSYtJoct9UxtTbNN+02/R3Mz0z
|
||||||
|
llmN2S1zsrm7+QbzLvMXy/SXcZbtX3bHgmLhZ7HVosfig6WVJd+y1XLaSsMq1qrWaoRBZQQwShiXrdHW
|
||||||
|
ztYbrE9Zv7WxtBHYHLf5zdbQNtn2iO3Ucu3lnOWNy8ft1OyYdvV2o/Z0+1j7A/ajDqoOTIcGh8eO6o5s
|
||||||
|
xybHSSddpySno07PnU2c+c7tzvMuNi7rXM65Iq4erkWuA24ybqFu1W6P3NXcE9xb3Gc9LDzWepzzRHv6
|
||||||
|
eO7yHPFS8mJ5NXvNelt5r/Pu9SH5BPtU+zz21fPl+3b7wX7efrv9HqzQXMFb0ekP/L38d/s/DNAOWBPw
|
||||||
|
YyAmMCCwJvBJkGlQXlBfMCU4JvhI8OsQ55DSkPuhOqHC0J4wybDosOaw+XDX8LLw0QjjiHUR1yIVIrmR
|
||||||
|
XVHYqLCopqi5lW4r96yciLaILoweXqW9KnvVldUKq1NWn46RjGHGnIhFx4bHHol9z/RnNjDn4rziauNm
|
||||||
|
WS6svaxnbEd2OXuaY8cp40zG28WXxU8l2CXsTphOdEisSJzhunCruS+SPJPqkuaT/ZMPJX9KCU9pS8Wl
|
||||||
|
xqae5Mnwknm9acpp2WmD6frphemja2zW7Fkzy/fhN2VAGasyugRU0c9Uv1BHuEU4lmmfWZP5Jiss60S2
|
||||||
|
dDYvuz9HL2d7zmSue+63a1FrWWt78lTzNuWNrXNaV78eWh+3vmeD+oaCDRMbPTYe3kTYlLzpp3yT/LL8
|
||||||
|
V5vDN3cXKBVsLBjf4rGlpVCikF84stV2a9021DbutoHt5turtn8sYhddLTYprih+X8IqufqN6TeV33za
|
||||||
|
Eb9joNSydP9OzE7ezuFdDrsOl0mX5ZaN7/bb3VFOLy8qf7UnZs+VimUVdXsJe4V7Ryt9K7uqNKp2Vr2v
|
||||||
|
Tqy+XeNc01arWLu9dn4fe9/Qfsf9rXVKdcV17w5wD9yp96jvaNBqqDiIOZh58EljWGPft4xvm5sUmoqb
|
||||||
|
PhziHRo9HHS4t9mqufmI4pHSFrhF2DJ9NProje9cv+tqNWytb6O1FR8Dx4THnn4f+/3wcZ/jPScYJ1p/
|
||||||
|
0Pyhtp3SXtQBdeR0zHYmdo52RXYNnvQ+2dNt293+o9GPh06pnqo5LXu69AzhTMGZT2dzz86dSz83cz7h
|
||||||
|
/HhPTM/9CxEXbvUG9g5c9Ll4+ZL7pQt9Tn1nL9tdPnXF5srJq4yrndcsr3X0W/S3/2TxU/uA5UDHdavr
|
||||||
|
XTesb3QPLh88M+QwdP6m681Lt7xuXbu94vbgcOjwnZHokdE77DtTd1PuvriXeW/h/sYH6AdFD6UeVjxS
|
||||||
|
fNTws+7PbaOWo6fHXMf6Hwc/vj/OGn/2S8Yv7ycKnpCfVEyqTDZPmU2dmnafvvF05dOJZ+nPFmYKf5X+
|
||||||
|
tfa5zvMffnP8rX82YnbiBf/Fp99LXsq/PPRq2aueuYC5R69TXy/MF72Rf3P4LeNt37vwd5MLWe+x7ys/
|
||||||
|
6H7o/ujz8cGn1E+f/gUDmPP8usTo0wAAAAlwSFlzAAAuIgAALiIBquLdkgAAEVpJREFUeF7tXQl0VNd5
|
||||||
|
Thq3Tk7tc+qmiZMm7YmdJj1OT3Gd0kTMG3mJnZQEJzaSjXETx0lqNwt2jWscQGixBAJLSMhgA8YYbIyQ
|
||||||
|
hHYJI4lFGMwioQWxyewgMdoXtKFd4u/337lPjDRv9pk3g+A75zsMWv577/fd+9/l3Rl9johu0Y/U/OIt
|
||||||
|
6sfrLwIYT2de+SJ4F/j34LfB+8Ap4L9J8uvvgfy9b4DfBO8EPy9DBBwC3gCI93fgDHAuuA7cDVaDzWAX
|
||||||
|
OAAOgcNgP9gN8vc+A4vB9eBr4M/Be8GAMiPgDIBAXwVDwbXgEbAPJC+RDToGvgfOBr8mi/UbAsIACMFp
|
||||||
|
ZRaYC7aBWuL5gh3gdvBZ8C5ZHV3hVwPQaM7hS0ETqCWQnqwDE8Apsnq6wC8GoJEPgFtAzt9aYviTPJ9k
|
||||||
|
gkGyuj6FrgagUd8CeVIcBLUaH0gcATeD35XV9wl0MQCN4OXjn8EroFZjA5m8qooE/1o2x6vwuQGouAEs
|
||||||
|
A7UadyPxOPgj2SyvwacGoMILwRsh3ThLTksx4BdkEz2GTwxABb8C8pJSqxGTgTvAb8jmegSvG4CK/QvI
|
||||||
|
O1Wtik8mXgSnyma7Da8agAo9Auq5kfI3+Shkhmy+W/CaAajI42CvrNjNRJ7jZksZXIZXDEAFWPxA3FTp
|
||||||
|
xVHQLRM8NgAFPwTejD1/InkH/biUxWl4ZAAK5LP3mynnO+JV0KWJ2W0DUNCXwVOy4Fu8zhrQ6SWqJwbk
|
||||||
|
WxQa2Mxop6fSWyk0rYlCUhspZEs9zdxSJ8iv+WuhW5vpqYw27d93nXvB26RUduGWAQg+36KwwCULv7VF
|
||||||
|
iDx3Wx1tPNxCBy92UU17P7VdHaLWniE619JLu8900Nv7m+jFLBgCM9gs/l3NmCqlqU+nt+D/msYtk3LZ
|
||||||
|
hcsGIPB/gPaPF7jyKrW+rwNZnJCUBoraUU9H63po9No1NM8++odGac/ZDno5r45C2QitESGF59gv5dVT
|
||||||
|
clUHzc5gEyb8XOaVa6DDsyMU67wBCHg7WCULsEkezi9/jEptbfKLCdzrn0s30b5znWiS6xgeuUaby1so
|
||||||
|
NKVubDSwGZzCOG3NzTdRQXW7+NnM4+b2atUDPAPeIeXTBEK4ZMA8i+Ca5Ir+LrOOOvtHKGkfcit6kp4m
|
||||||
|
sBh/zDGRqaMfzfEMh5CuZiXXUOgWE72Ua6L1Jc10qqmXRkbNo4nT2PMw2sHcESvl0wTCOGcAAv0DyFtv
|
||||||
|
rULGyAKsO9SMUERD6EnRO+t1M4F76++zTNTUNSjK9wYutvVhzujTTGGrMG/wqNCqiwX5IsA/SxmtgDBO
|
||||||
|
G7DBIqhN8oR3suEqQpnRh7watcOcU31pAvfCWUgZ1Y3Xy/YlCk+Z28rlqrTTvkwpoxUQyrEBCPCvoONz
|
||||||
|
fVTg1xkm6hkYQajr4Mktdpd5uecrE9jg5IpWWaJvwRN1SHKtaA/PCfMLmyiq2DxPaNUN5KMKg5RzHBDO
|
||||||
|
KQNSLYLZJFfgVSz3tMBDeM0BrMNlr9H6fXfJ8V7AErK7f1iW5hsMjYxSSnkjPbnxLP1vbq2YE04399KV
|
||||||
|
vmGak9/kqF0FUs5xQFj7BuAXvwM6ddDGOfiNnQ0IYxvbTrYjVWDiwkrFW6OB83DaEd/3/obOfiq71Ekt
|
||||||
|
3YOkzgg8NUTxPOdgLpiV1TE6K7vzASnrGBDCoQF8b0cz6ESyqDG77BvAOI2VxJycy7bX2q4QJoYgDVxo
|
||||||
|
7ZPR9QVv4OzNb7OyOll8mpnWTNPXnlwnZR0DQtg2AAHuAPnCkmbwieQREFZQjzCOwfPChlJs/3mt7cFo
|
||||||
|
YAPn5NTRsFwa6on3kII05zUIjt4uXv9icx099u5pCn7rKBkSynoMC1K/LuUVQBi7BswcF9gBWYzfZ5vE
|
||||||
|
RsZZnG/powjsVsXc4IYR/DtLix2POm+C9wGrPjWfK1nWl3v6MxA+FB1xxgeX6OF3TpKSdASsIiMMMK48
|
||||||
|
TkpM4RwprwDC2TUgTw3uFFEZXgo2dA4glPNgu8pruyms0HxAJnaWThrBP7v2oHnfoQd48xWBelqmHe7t
|
||||||
|
Is2kNNJ/rj9HD648RsoKC+FVwgBj/MGDUl4BhNQ2AIH/FuTLq1aNtkfuFYWfXUEo18FGHKvrofg9DfRs
|
||||||
|
mknEcjQq2ABejeiFyEKTWXyUbU4z7fSLj0z06NpTELnKLLyl6BOZVDVgDM+8R8ps14AQy4Y6S1fmAXvg
|
||||||
|
npZ/oo0iiuro2VSYkdIgVhocX0zc0hQ2YDWWt3phIdrGp5+hW1vpZxsv0SOcZrR6uy1iFAQvLvqDlNmu
|
||||||
|
Ae9aCus0IQzn8/LL3QjnHbAZpZe6RE9fsL2O/jvTJFIdlzMz2URRhZflT/oer+fX0E/ePUXBttKMI3Ia
|
||||||
|
enNfhpRZ2wAI+XnQ4amnLXLamPdxHQ1i4+IL8AqqHvMMp6vdZ65Q8en2sXW5r/HbjZVYzVRoi+sMYZwx
|
||||||
|
saxWWbj1Swhn04B/BPkQSVNgu+TUAHKefB/LzMkE3s3PXgfxsbLRFNd5XlMWZT6AkDYN+JmVsE5QLEPz
|
||||||
|
WujXGY0iZ3N60GOHqheuDgzT4++U80SqJarz5DQUXfAcQlobACE5/fAb4jRFtkdOPatLWqmrf4RSKlvo
|
||||||
|
1fzL9MSGM7TuQJ04R7nR0dDRSw8mlGqL6gpXniDjkp2xyoKULyCslQH81MutCZgNWLz7+qaI83Jz9yAm
|
||||||
|
0A5q6/HeGb2/cPxyBxnivWEAT8T7c4Mjc+5EWCsD/gbkt4JqimyP6rGA+sRosqHgWD0Zlh/WFtUVsgHL
|
||||||
|
S44aI3O/hrBWBvCboN273cwTMJaHvEKZjEgsOkNKogcrIJViJVTeaIzefi/CWhnA7zJvGiesC+TVT85x
|
||||||
|
8wPryYYXNpl3upqiukQYsKKyR1my63sIa2UAv3WU3xelKbAj8k71lXz/nE76Em09A/Tjt5B+PF0BqUw6
|
||||||
|
MogN2RSEtjKAHz+6twdg8k6Yz4NOuXceFKgorm7yTv5XmXRkVIk78H2EtjLgfpBv+moL7AR5Mv5NRp1X
|
||||||
|
byf4GzH5n3kn/6vkkbS8dCpCWxnAnzrikQFMPiRbWFAnbkXc6OAN2BNreAPmjfwvyQbEH9I0gD/yxfM3
|
||||||
|
W/BxRFqTuBrYOzj+lsSNht0nG72bfphJVddgwL8jvJUBHk3C4yhNeCXfRJfaPL+p5i+8ln4Cq59KbSHd
|
||||||
|
ZVLloLJs7/0Ib2UAL0NbxgnpCWEC75Bnp5rog7IW6ujz7dURb+NsYxdvmswpQ0tItyiWod1KTJHmMpQ3
|
||||||
|
YvxhR9qCukiekGenN4tHjU9+VENPbzpLcbtq6GS9954X+BLLtp/y7uTLNG/EmozRBd9GEVYG8Gf37LEU
|
||||||
|
0RNy7/+o8gqdae6jQxc76eCFTqqo7aTGzsBPSRdbeuihRG/3fpANiC85qkTkaB5F8Adr8CeaaArqKsUj
|
||||||
|
yiJ9by14C2/keXnpqXIV5pTYPblB8zZ9BcVYGcDH0f9nKaJH5I1ZSgMduNCF8DcOjtS0k+L13C/JBize
|
||||||
|
EWeYn3wbihpvgHwgw+/71RbUDfIo+FNuvdWl3UAFn+a+KM59vLzyUWl+IPMbFHVd97EXZgPuAb3yKSfq
|
||||||
|
ZSUeBbFFNSgi8PHRwRrzut8Xvd/Ma8FR+XYfSf4FyJ+PoymqM1TvRIakNtP098/TQ5h4psWXUnzBaRQT
|
||||||
|
uDhZ1yknXi/uei0JHZTlpbVBr6z7IoqzNkAlRHR9Ira4E/lEcv31O5Hq9Q2Qe9bCrJPU3T+EYgILPajT
|
||||||
|
r96v8F3qYSL/G5bszuKOjiLHeP2FBETkj5G0FlmDapp5amsrzfiwhh5ZPeFOpCXxNSWxnGauKaed2OI7
|
||||||
|
8eZF3RCejXqjbj5MPWYDInJfZo1RpF0D+EOX7L4nbOzqdWqTSDN8J3Kst2sVbkF+sMGj4fmNlZR2uFas
|
||||||
|
uYflg3t/mLJy11lf530Q6/+3qoaw+vkOa4xibRvAgMj8oaYTRLe+eu3UnUgt8mhgIxLKKBhLvsdXltDc
|
||||||
|
zRV0qUXfXfKHBy7pID4ongUfKpfyOmXAf00U3ubVa0+IOCzAM+vKqOxCG6qhHzbziodvOvhq0rUk0k9Q
|
||||||
|
WPpLUl4BVMG2AbOyu+4CW1j8Jx1dvXaHLDx6/09XHabU0loaHNb32cG7n1zQT3w+fkgs75r6Pwl3S3kF
|
||||||
|
UA3bBjB+vvH8CnH1WqYLzeCukEcNVhnc459YXSaGf0evvk/O2OjovGqZdnQQn/l2NQVF5G2Qso4B1bFv
|
||||||
|
gCEs/X6kmhHNoCp5NHBDBPm1ShYbTKwQPZ1723T09tfTT4hnrL2D+h9N17Zdpd9uNI88UUet9viCGAFB
|
||||||
|
r29WpKxjQJXsG8AwLtv3sbhOpxUYjZi+5hg9s+E4zVpfRT9ZeZh+nFRKP11ZRqFry+mFD6soKreakg/V
|
||||||
|
iPzuz/V/TqVJ1E2s83UVX9yE2294baPV3y5AtRwboIRnT0OgUavAko++fZR++cFxKj7VQgPDI9Q3OCKE
|
||||||
|
HhgKjLOfc03d9ErqcX1TjiVhADLJdCnnOKB6jg1gGOP2pwsntQpAbxLzw/JSCsuqprNocCCgoaOPEgrP
|
||||||
|
0MOJJeZjZT17vUo++Vz6yU4poxVQTScNWJT5XfSefvNmQqMgJhuBhirxJTQ/4wRVXGqnUT9c0Drf3E3L
|
||||||
|
IfyPON2Ina0fer0gVoxJVcNBr31g9QZtFaiucwYwjEt2xdqcCywpRgRWOph0f7m+QuT/y+1XfbrD5Ztr
|
||||||
|
24/V05wtR8Wmzr/CS7JWscWrpHyaQNWdN0AJS7vDmFh2zmYqmkiZmnjF8WBCibhbuWbPeTqMyZiXnp4Y
|
||||||
|
wgdnfF2cl7Gc3x9Db+ccr/sEa4u87l9R3hAcnvllKZ8m0BTnDWAo4VmPGldyIXZSkRalGdwzeWTwaonP
|
||||||
|
gRZlV9O6vRcoq8JEu7E0LTnXSidMHSKNHK29Qofwf76Xw99/Dz8XiRXV7z48QjPeLkOqg+gwN2BEtyRv
|
||||||
|
WCNyQqRsNuGyAQxlya44p1KRPaqGQDxhCnrvGFlYlRZf558TcwxP+IEmuCXFI8eda6RcduGWAcaFaX9p
|
||||||
|
jD/0qdOp6GYia7K8pCp4UfqXpFx24ZYBDGVB6jeNKypMt0ywoPm8p9UYkW3zI8omwm0DGIbXN//AuKKy
|
||||||
|
VxSsVaGbiWYNhrBpdenPnHhkAAMTzUwUPnxTm6C2PWrbc1IWp+GxAQxDePavxlXkpiLazO2OKfqjlMMl
|
||||||
|
eMUABruPCt1kI4HbiuVm9PY/SRlchtcMYBjCMkJQMcwJN8HEzB0tqWrIGF3wvGy+W/CqAQwlLH2aknDY
|
||||||
|
xGthzYpPBnIHW1HRYozMeUw222143QDGtD8n3yP2CcKESZaSeAOaUFpuDM+8TzbXI/jEAIZxYepfGaIL
|
||||||
|
48yVngQpiVMO2qHEFq81Lkr32p819JkBKgyLMmeYD/Bu4NHAdU8sr1Ui85+SzfIafG4Aw7go4y5jbPEy
|
||||||
|
8TzhRpobxMitGjYu3fOOMWzrV2VzvApdDFDxw3mbpyhL92aL09RATkuibhitb35agIn2h7L6PoGuBqgw
|
||||||
|
hOc8Zow7UCQayyMiIPYOnONlmow7sEeJzPPoL+Q5C78YoAI76KBpMTtXK4nlLcZV6HVqz9MUyEfkMpkr
|
||||||
|
KnuMSz/ZpETkPCyrpwv8aoCKH8zdcPe0yG0vYum6X8wTLIivRoZczQgmVQ2izBIluvBVZeHWb8nq6IqA
|
||||||
|
MMASWDX9k+GN7X8wxO5JU5aXnjeLxoKxIVI4YYzKCQKrX7cUWpiJf/n7CWW1yrJ9WcaYwpeU8Cynj419
|
||||||
|
hYAzwBJB8zbdHhyVd78xpuA5ZfHOWEzgWeixFVgSNiBldGG0DICj4uE7PyEzvx4Q6YQ/ECm+5Cgm0jxl
|
||||||
|
8Y5lyhsfPw9zpyrzU3zyp8ndRUAbwFDrZViQdlvQ/NQ7kKPvNkYX3GuIKbpPWfrJFP7IFyXu4FQYM1V5
|
||||||
|
c//3lWV7p/A70JWobfcq4dlfN4Zn3WmYn3y7GseSgYCxulhW7Bb1p+YXb1Ev0uf+H9A3E1Z4VJUaAAAA
|
||||||
|
AElFTkSuQmCC
|
||||||
|
</value>
|
||||||
|
</data>
|
||||||
|
</root>
|
||||||
78
Core/Other/FormBackgroundWork.Designer.cs
generated
78
Core/Other/FormBackgroundWork.Designer.cs
generated
@@ -1,78 +0,0 @@
|
|||||||
using TweetDick.Core.Controls;
|
|
||||||
|
|
||||||
namespace TweetDick.Core.Other {
|
|
||||||
partial class FormBackgroundWork {
|
|
||||||
/// <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.progressBarUseless = new System.Windows.Forms.ProgressBar();
|
|
||||||
this.labelDescription = new RichTextLabel();
|
|
||||||
this.SuspendLayout();
|
|
||||||
//
|
|
||||||
// progressBarUseless
|
|
||||||
//
|
|
||||||
this.progressBarUseless.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left)
|
|
||||||
| System.Windows.Forms.AnchorStyles.Right)));
|
|
||||||
this.progressBarUseless.Location = new System.Drawing.Point(12, 49);
|
|
||||||
this.progressBarUseless.MarqueeAnimationSpeed = 10;
|
|
||||||
this.progressBarUseless.Name = "progressBarUseless";
|
|
||||||
this.progressBarUseless.Size = new System.Drawing.Size(480, 23);
|
|
||||||
this.progressBarUseless.Style = System.Windows.Forms.ProgressBarStyle.Marquee;
|
|
||||||
this.progressBarUseless.TabIndex = 0;
|
|
||||||
//
|
|
||||||
// labelDescription
|
|
||||||
//
|
|
||||||
this.labelDescription.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom)
|
|
||||||
| System.Windows.Forms.AnchorStyles.Left)
|
|
||||||
| System.Windows.Forms.AnchorStyles.Right)));
|
|
||||||
this.labelDescription.BorderStyle = System.Windows.Forms.BorderStyle.None;
|
|
||||||
this.labelDescription.Location = new System.Drawing.Point(12, 12);
|
|
||||||
this.labelDescription.Name = "labelDescription";
|
|
||||||
this.labelDescription.ReadOnly = true;
|
|
||||||
this.labelDescription.ScrollBars = System.Windows.Forms.RichTextBoxScrollBars.None;
|
|
||||||
this.labelDescription.Size = new System.Drawing.Size(480, 31);
|
|
||||||
this.labelDescription.TabIndex = 1;
|
|
||||||
this.labelDescription.TabStop = false;
|
|
||||||
this.labelDescription.Text = "";
|
|
||||||
//
|
|
||||||
// FormBackgroundWork
|
|
||||||
//
|
|
||||||
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
|
|
||||||
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
|
|
||||||
this.ClientSize = new System.Drawing.Size(504, 84);
|
|
||||||
this.Controls.Add(this.labelDescription);
|
|
||||||
this.Controls.Add(this.progressBarUseless);
|
|
||||||
this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedDialog;
|
|
||||||
this.Name = "FormBackgroundWork";
|
|
||||||
this.StartPosition = System.Windows.Forms.FormStartPosition.CenterScreen;
|
|
||||||
this.Text = "TweetDeck Migration";
|
|
||||||
this.ResumeLayout(false);
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
#endregion
|
|
||||||
|
|
||||||
private System.Windows.Forms.ProgressBar progressBarUseless;
|
|
||||||
private RichTextLabel labelDescription;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,18 +0,0 @@
|
|||||||
using System;
|
|
||||||
using System.Windows.Forms;
|
|
||||||
using TweetDick.Core.Controls;
|
|
||||||
|
|
||||||
namespace TweetDick.Core.Other{
|
|
||||||
partial class FormBackgroundWork : Form{
|
|
||||||
public FormBackgroundWork(){
|
|
||||||
InitializeComponent();
|
|
||||||
|
|
||||||
labelDescription.Rtf = RichTextLabel.Wrap(@"Please, watch this informationless progress bar showcase while some magic happens in the background...");
|
|
||||||
}
|
|
||||||
|
|
||||||
public void ShowWorkDialog(Action onBegin){
|
|
||||||
Shown += (sender, args) => onBegin();
|
|
||||||
ShowDialog();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
80
Core/Other/FormMessage.Designer.cs
generated
Normal file
80
Core/Other/FormMessage.Designer.cs
generated
Normal file
@@ -0,0 +1,80 @@
|
|||||||
|
namespace TweetDuck.Core.Other {
|
||||||
|
partial class FormMessage {
|
||||||
|
/// <summary>
|
||||||
|
/// Required designer variable.
|
||||||
|
/// </summary>
|
||||||
|
private System.ComponentModel.IContainer components = null;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Clean up any resources being used.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
|
||||||
|
protected override void Dispose(bool disposing) {
|
||||||
|
if (disposing && (components != null)) {
|
||||||
|
components.Dispose();
|
||||||
|
}
|
||||||
|
base.Dispose(disposing);
|
||||||
|
}
|
||||||
|
|
||||||
|
#region Windows Form Designer generated code
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Required method for Designer support - do not modify
|
||||||
|
/// the contents of this method with the code editor.
|
||||||
|
/// </summary>
|
||||||
|
private void InitializeComponent() {
|
||||||
|
this.panelActions = new System.Windows.Forms.Panel();
|
||||||
|
this.labelMessage = new System.Windows.Forms.Label();
|
||||||
|
this.SuspendLayout();
|
||||||
|
//
|
||||||
|
// panelActions
|
||||||
|
//
|
||||||
|
this.panelActions.BackColor = System.Drawing.SystemColors.Control;
|
||||||
|
this.panelActions.Dock = System.Windows.Forms.DockStyle.Bottom;
|
||||||
|
this.panelActions.Location = new System.Drawing.Point(0, 84);
|
||||||
|
this.panelActions.Name = "panelActions";
|
||||||
|
this.panelActions.Size = new System.Drawing.Size(98, 49);
|
||||||
|
this.panelActions.TabIndex = 0;
|
||||||
|
//
|
||||||
|
// labelMessage
|
||||||
|
//
|
||||||
|
this.labelMessage.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom)
|
||||||
|
| System.Windows.Forms.AnchorStyles.Left)
|
||||||
|
| System.Windows.Forms.AnchorStyles.Right)));
|
||||||
|
this.labelMessage.AutoSize = true;
|
||||||
|
this.labelMessage.Font = System.Drawing.SystemFonts.MessageBoxFont;
|
||||||
|
this.labelMessage.Location = new System.Drawing.Point(62, 34);
|
||||||
|
this.labelMessage.Margin = new System.Windows.Forms.Padding(53, 24, 27, 24);
|
||||||
|
this.labelMessage.MaximumSize = new System.Drawing.Size(600, 0);
|
||||||
|
this.labelMessage.MinimumSize = new System.Drawing.Size(0, 24);
|
||||||
|
this.labelMessage.Name = "labelMessage";
|
||||||
|
this.labelMessage.Size = new System.Drawing.Size(0, 24);
|
||||||
|
this.labelMessage.TabIndex = 1;
|
||||||
|
this.labelMessage.SizeChanged += new System.EventHandler(this.labelMessage_SizeChanged);
|
||||||
|
//
|
||||||
|
// FormMessage
|
||||||
|
//
|
||||||
|
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
|
||||||
|
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
|
||||||
|
this.BackColor = System.Drawing.Color.White;
|
||||||
|
this.ClientSize = new System.Drawing.Size(98, 133);
|
||||||
|
this.Controls.Add(this.labelMessage);
|
||||||
|
this.Controls.Add(this.panelActions);
|
||||||
|
this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedSingle;
|
||||||
|
this.MaximizeBox = false;
|
||||||
|
this.MinimizeBox = false;
|
||||||
|
this.Name = "FormMessage";
|
||||||
|
this.ShowIcon = false;
|
||||||
|
this.StartPosition = System.Windows.Forms.FormStartPosition.CenterScreen;
|
||||||
|
this.SizeChanged += new System.EventHandler(this.FormMessage_SizeChanged);
|
||||||
|
this.ResumeLayout(false);
|
||||||
|
this.PerformLayout();
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
private System.Windows.Forms.Panel panelActions;
|
||||||
|
private System.Windows.Forms.Label labelMessage;
|
||||||
|
}
|
||||||
|
}
|
||||||
221
Core/Other/FormMessage.cs
Normal file
221
Core/Other/FormMessage.cs
Normal file
@@ -0,0 +1,221 @@
|
|||||||
|
using System;
|
||||||
|
using System.Drawing;
|
||||||
|
using System.Windows.Forms;
|
||||||
|
using TweetDuck.Core.Controls;
|
||||||
|
using TweetDuck.Core.Utils;
|
||||||
|
|
||||||
|
namespace TweetDuck.Core.Other{
|
||||||
|
[Flags]
|
||||||
|
enum ControlType{
|
||||||
|
None = 0,
|
||||||
|
Accept = 1, // triggered by pressing enter when a non-button is focused
|
||||||
|
Cancel = 2, // triggered by closing the dialog without pressing a button
|
||||||
|
Focused = 4 // active control after the dialog is showed
|
||||||
|
}
|
||||||
|
|
||||||
|
sealed partial class FormMessage : Form{
|
||||||
|
public const string OK = "OK";
|
||||||
|
public const string Yes = "Yes";
|
||||||
|
public const string No = "No";
|
||||||
|
public const string Cancel = "Cancel";
|
||||||
|
public const string Retry = "Retry";
|
||||||
|
public const string Ignore = "Ignore";
|
||||||
|
public const string Exit = "Exit";
|
||||||
|
|
||||||
|
public static bool Information(string caption, string text, string buttonAccept, string buttonCancel = null){
|
||||||
|
return Show(caption, text, MessageBoxIcon.Information, buttonAccept, buttonCancel);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static bool Warning(string caption, string text, string buttonAccept, string buttonCancel = null){
|
||||||
|
return Show(caption, text, MessageBoxIcon.Warning, buttonAccept, buttonCancel);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static bool Error(string caption, string text, string buttonAccept, string buttonCancel = null){
|
||||||
|
return Show(caption, text, MessageBoxIcon.Error, buttonAccept, buttonCancel);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static bool Question(string caption, string text, string buttonAccept, string buttonCancel = null){
|
||||||
|
return Show(caption, text, MessageBoxIcon.Question, buttonAccept, buttonCancel);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static bool Show(string caption, string text, MessageBoxIcon icon, string button){
|
||||||
|
return Show(caption, text, icon, button, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static bool Show(string caption, string text, MessageBoxIcon icon, string buttonAccept, string buttonCancel){
|
||||||
|
using(FormMessage message = new FormMessage(caption, text, icon)){
|
||||||
|
if (buttonCancel == null){
|
||||||
|
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
|
||||||
|
|
||||||
|
public Button ClickedButton { get; private set; }
|
||||||
|
|
||||||
|
public int ActionPanelY => panelActions.Location.Y;
|
||||||
|
|
||||||
|
private int ClientWidth{
|
||||||
|
get => ClientSize.Width;
|
||||||
|
set => ClientSize = new Size(value, ClientSize.Height);
|
||||||
|
}
|
||||||
|
|
||||||
|
private int ButtonDistance{
|
||||||
|
get => BrowserUtils.Scale(96, dpiScale);
|
||||||
|
}
|
||||||
|
|
||||||
|
private readonly Icon icon;
|
||||||
|
private readonly bool isReady;
|
||||||
|
private readonly float dpiScale;
|
||||||
|
|
||||||
|
private int realFormWidth, minFormWidth;
|
||||||
|
private int buttonCount;
|
||||||
|
private int prevLabelWidth, prevLabelHeight;
|
||||||
|
private bool wasLabelMultiline;
|
||||||
|
|
||||||
|
public FormMessage(string caption, string text, MessageBoxIcon messageIcon){
|
||||||
|
InitializeComponent();
|
||||||
|
|
||||||
|
this.dpiScale = this.GetDPIScale();
|
||||||
|
|
||||||
|
this.prevLabelWidth = labelMessage.Width;
|
||||||
|
this.prevLabelHeight = labelMessage.Height;
|
||||||
|
this.minFormWidth = BrowserUtils.Scale(42, dpiScale);
|
||||||
|
|
||||||
|
switch(messageIcon){
|
||||||
|
case MessageBoxIcon.Information:
|
||||||
|
icon = SystemIcons.Information;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case MessageBoxIcon.Warning:
|
||||||
|
icon = SystemIcons.Warning;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case MessageBoxIcon.Error:
|
||||||
|
icon = SystemIcons.Error;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case MessageBoxIcon.Question:
|
||||||
|
icon = SystemIcons.Question;
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
icon = null;
|
||||||
|
labelMessage.Location = new Point(BrowserUtils.Scale(19, dpiScale), labelMessage.Location.Y); // 19 instead of 9 due to larger height
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.isReady = true;
|
||||||
|
|
||||||
|
this.Text = caption;
|
||||||
|
this.labelMessage.Text = text.Replace("\r", "").Replace("\n", Environment.NewLine);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void FormMessage_SizeChanged(object sender, EventArgs e){
|
||||||
|
RecalculateButtonLocation();
|
||||||
|
}
|
||||||
|
|
||||||
|
public Button AddButton(string title, ControlType type){
|
||||||
|
return AddButton(title, DialogResult.OK, type);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Button AddButton(string title, DialogResult result = DialogResult.OK, ControlType type = ControlType.None){
|
||||||
|
Button button = new Button{
|
||||||
|
Anchor = AnchorStyles.Bottom,
|
||||||
|
Font = SystemFonts.MessageBoxFont,
|
||||||
|
Location = new Point(0, 12),
|
||||||
|
Size = new Size(BrowserUtils.Scale(88, dpiScale), BrowserUtils.Scale(26, dpiScale)),
|
||||||
|
TabIndex = buttonCount,
|
||||||
|
Text = title,
|
||||||
|
UseVisualStyleBackColor = true
|
||||||
|
};
|
||||||
|
|
||||||
|
button.Click += (sender, args) => {
|
||||||
|
ClickedButton = (Button)sender;
|
||||||
|
DialogResult = result;
|
||||||
|
Close();
|
||||||
|
};
|
||||||
|
|
||||||
|
panelActions.Controls.Add(button);
|
||||||
|
++buttonCount;
|
||||||
|
|
||||||
|
minFormWidth += ButtonDistance;
|
||||||
|
ClientWidth = Math.Max(realFormWidth, minFormWidth);
|
||||||
|
RecalculateButtonLocation();
|
||||||
|
|
||||||
|
if (type.HasFlag(ControlType.Accept)){
|
||||||
|
AcceptButton = button;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (type.HasFlag(ControlType.Cancel)){
|
||||||
|
CancelButton = button;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (type.HasFlag(ControlType.Focused)){
|
||||||
|
ActiveControl = button;
|
||||||
|
}
|
||||||
|
|
||||||
|
return button;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void AddActionControl(Control 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;
|
||||||
|
ClientWidth = Math.Max(realFormWidth, minFormWidth);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void RecalculateButtonLocation(){
|
||||||
|
int dist = ButtonDistance;
|
||||||
|
int start = ClientWidth-dist;
|
||||||
|
|
||||||
|
for(int index = 0; index < buttonCount; index++){
|
||||||
|
Control control = panelActions.Controls[index];
|
||||||
|
control.Location = new Point(start-index*dist, control.Location.Y);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void labelMessage_SizeChanged(object sender, EventArgs e){
|
||||||
|
if (!isReady){
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool isMultiline = labelMessage.Height > labelMessage.MinimumSize.Height;
|
||||||
|
int labelOffset = BrowserUtils.Scale(8, dpiScale);
|
||||||
|
|
||||||
|
if (isMultiline && !wasLabelMultiline){
|
||||||
|
labelMessage.Location = new Point(labelMessage.Location.X, labelMessage.Location.Y-labelOffset);
|
||||||
|
prevLabelHeight += labelOffset;
|
||||||
|
}
|
||||||
|
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;
|
||||||
|
ClientWidth = Math.Max(realFormWidth, minFormWidth);
|
||||||
|
Height += labelMessage.Height-prevLabelHeight;
|
||||||
|
|
||||||
|
prevLabelWidth = labelMessage.Width;
|
||||||
|
prevLabelHeight = labelMessage.Height;
|
||||||
|
wasLabelMultiline = isMultiline;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void OnPaint(PaintEventArgs e){
|
||||||
|
if (icon != null){
|
||||||
|
e.Graphics.DrawIcon(icon, BrowserUtils.Scale(25, dpiScale), 1+BrowserUtils.Scale(25, dpiScale));
|
||||||
|
}
|
||||||
|
|
||||||
|
base.OnPaint(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
110
Core/Other/FormPlugins.Designer.cs
generated
Normal file
110
Core/Other/FormPlugins.Designer.cs
generated
Normal file
@@ -0,0 +1,110 @@
|
|||||||
|
namespace TweetDuck.Core.Other {
|
||||||
|
partial class FormPlugins {
|
||||||
|
/// <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.btnClose = new System.Windows.Forms.Button();
|
||||||
|
this.btnReload = new System.Windows.Forms.Button();
|
||||||
|
this.btnOpenFolder = new System.Windows.Forms.Button();
|
||||||
|
this.flowLayoutPlugins = new TweetDuck.Plugins.Controls.PluginListFlowLayout();
|
||||||
|
this.SuspendLayout();
|
||||||
|
//
|
||||||
|
// btnClose
|
||||||
|
//
|
||||||
|
this.btnClose.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right)));
|
||||||
|
this.btnClose.AutoSize = true;
|
||||||
|
this.btnClose.Location = new System.Drawing.Point(643, 439);
|
||||||
|
this.btnClose.Name = "btnClose";
|
||||||
|
this.btnClose.Padding = new System.Windows.Forms.Padding(3, 0, 3, 0);
|
||||||
|
this.btnClose.Size = new System.Drawing.Size(49, 23);
|
||||||
|
this.btnClose.TabIndex = 1;
|
||||||
|
this.btnClose.Text = "Close";
|
||||||
|
this.btnClose.UseVisualStyleBackColor = true;
|
||||||
|
this.btnClose.Click += new System.EventHandler(this.btnClose_Click);
|
||||||
|
//
|
||||||
|
// btnReload
|
||||||
|
//
|
||||||
|
this.btnReload.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left)));
|
||||||
|
this.btnReload.AutoSize = true;
|
||||||
|
this.btnReload.Location = new System.Drawing.Point(131, 439);
|
||||||
|
this.btnReload.Name = "btnReload";
|
||||||
|
this.btnReload.Padding = new System.Windows.Forms.Padding(3, 0, 3, 0);
|
||||||
|
this.btnReload.Size = new System.Drawing.Size(71, 23);
|
||||||
|
this.btnReload.TabIndex = 2;
|
||||||
|
this.btnReload.Text = "Reload All";
|
||||||
|
this.btnReload.UseVisualStyleBackColor = true;
|
||||||
|
this.btnReload.Click += new System.EventHandler(this.btnReload_Click);
|
||||||
|
//
|
||||||
|
// btnOpenFolder
|
||||||
|
//
|
||||||
|
this.btnOpenFolder.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left)));
|
||||||
|
this.btnOpenFolder.AutoSize = true;
|
||||||
|
this.btnOpenFolder.Location = new System.Drawing.Point(12, 439);
|
||||||
|
this.btnOpenFolder.Name = "btnOpenFolder";
|
||||||
|
this.btnOpenFolder.Padding = new System.Windows.Forms.Padding(3, 0, 3, 0);
|
||||||
|
this.btnOpenFolder.Size = new System.Drawing.Size(113, 23);
|
||||||
|
this.btnOpenFolder.TabIndex = 3;
|
||||||
|
this.btnOpenFolder.Text = "Open Plugin Folder";
|
||||||
|
this.btnOpenFolder.UseVisualStyleBackColor = true;
|
||||||
|
this.btnOpenFolder.Click += new System.EventHandler(this.btnOpenFolder_Click);
|
||||||
|
//
|
||||||
|
// flowLayoutPlugins
|
||||||
|
//
|
||||||
|
this.flowLayoutPlugins.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.flowLayoutPlugins.BorderStyle = System.Windows.Forms.BorderStyle.FixedSingle;
|
||||||
|
this.flowLayoutPlugins.FlowDirection = System.Windows.Forms.FlowDirection.TopDown;
|
||||||
|
this.flowLayoutPlugins.Location = new System.Drawing.Point(12, 12);
|
||||||
|
this.flowLayoutPlugins.Name = "flowLayoutPlugins";
|
||||||
|
this.flowLayoutPlugins.Size = new System.Drawing.Size(680, 421);
|
||||||
|
this.flowLayoutPlugins.TabIndex = 0;
|
||||||
|
this.flowLayoutPlugins.WrapContents = false;
|
||||||
|
this.flowLayoutPlugins.Resize += new System.EventHandler(this.flowLayoutPlugins_Resize);
|
||||||
|
//
|
||||||
|
// FormPlugins
|
||||||
|
//
|
||||||
|
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
|
||||||
|
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
|
||||||
|
this.ClientSize = new System.Drawing.Size(704, 474);
|
||||||
|
this.Controls.Add(this.flowLayoutPlugins);
|
||||||
|
this.Controls.Add(this.btnOpenFolder);
|
||||||
|
this.Controls.Add(this.btnReload);
|
||||||
|
this.Controls.Add(this.btnClose);
|
||||||
|
this.Icon = global::TweetDuck.Properties.Resources.icon;
|
||||||
|
this.MinimumSize = new System.Drawing.Size(480, 320);
|
||||||
|
this.Name = "FormPlugins";
|
||||||
|
this.StartPosition = System.Windows.Forms.FormStartPosition.CenterParent;
|
||||||
|
this.ResumeLayout(false);
|
||||||
|
this.PerformLayout();
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
private System.Windows.Forms.Button btnClose;
|
||||||
|
private System.Windows.Forms.Button btnReload;
|
||||||
|
private System.Windows.Forms.Button btnOpenFolder;
|
||||||
|
private Plugins.Controls.PluginListFlowLayout flowLayoutPlugins;
|
||||||
|
}
|
||||||
|
}
|
||||||
93
Core/Other/FormPlugins.cs
Normal file
93
Core/Other/FormPlugins.cs
Normal file
@@ -0,0 +1,93 @@
|
|||||||
|
using System;
|
||||||
|
using System.Diagnostics;
|
||||||
|
using System.Drawing;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Windows.Forms;
|
||||||
|
using TweetDuck.Plugins;
|
||||||
|
using TweetDuck.Plugins.Controls;
|
||||||
|
|
||||||
|
namespace TweetDuck.Core.Other{
|
||||||
|
sealed partial class FormPlugins : Form{
|
||||||
|
private readonly PluginManager pluginManager;
|
||||||
|
|
||||||
|
public FormPlugins(){
|
||||||
|
InitializeComponent();
|
||||||
|
|
||||||
|
Text = Program.BrandName+" Plugins";
|
||||||
|
}
|
||||||
|
|
||||||
|
public FormPlugins(PluginManager pluginManager) : this(){
|
||||||
|
this.pluginManager = pluginManager;
|
||||||
|
|
||||||
|
Shown += (sender, args) => {
|
||||||
|
Program.UserConfig.PluginsWindow.Restore(this, false);
|
||||||
|
ReloadPluginList();
|
||||||
|
};
|
||||||
|
|
||||||
|
FormClosed += (sender, args) => {
|
||||||
|
Program.UserConfig.PluginsWindow.Save(this);
|
||||||
|
Program.UserConfig.Save();
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
private int GetPluginOrderIndex(Plugin plugin){
|
||||||
|
return !plugin.CanRun ? 0 : pluginManager.Config.IsEnabled(plugin) ? 1 : 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void ReloadPluginList(){
|
||||||
|
flowLayoutPlugins.SuspendLayout();
|
||||||
|
flowLayoutPlugins.Controls.Clear();
|
||||||
|
|
||||||
|
foreach(Plugin plugin in pluginManager.Plugins.OrderBy(GetPluginOrderIndex).ThenBy(plugin => plugin.Name)){
|
||||||
|
flowLayoutPlugins.Controls.Add(new PluginControl(pluginManager, plugin));
|
||||||
|
|
||||||
|
flowLayoutPlugins.Controls.Add(new Panel{
|
||||||
|
BackColor = Color.DimGray,
|
||||||
|
Margin = new Padding(0),
|
||||||
|
Size = new Size(1, 1)
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
flowLayoutPlugins.ResumeLayout(true);
|
||||||
|
|
||||||
|
// sorry, I guess...
|
||||||
|
Padding = new Padding(Padding.Left, Padding.Top, Padding.Right+1, Padding.Bottom);
|
||||||
|
Padding = new Padding(Padding.Left, Padding.Top, Padding.Right-1, Padding.Bottom);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void flowLayoutPlugins_Resize(object sender, EventArgs e){
|
||||||
|
if (flowLayoutPlugins.Controls.Count == 0){
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
Control lastControl = flowLayoutPlugins.Controls[flowLayoutPlugins.Controls.Count-1];
|
||||||
|
bool showScrollBar = lastControl.Location.Y+lastControl.Height >= flowLayoutPlugins.Height;
|
||||||
|
int horizontalOffset = showScrollBar ? SystemInformation.VerticalScrollBarWidth : 0;
|
||||||
|
|
||||||
|
flowLayoutPlugins.AutoScroll = showScrollBar;
|
||||||
|
flowLayoutPlugins.VerticalScroll.Visible = showScrollBar;
|
||||||
|
|
||||||
|
foreach(Control control in flowLayoutPlugins.Controls){
|
||||||
|
control.Width = flowLayoutPlugins.Width-control.Margin.Horizontal-horizontalOffset;
|
||||||
|
}
|
||||||
|
|
||||||
|
lastControl.Visible = !showScrollBar;
|
||||||
|
flowLayoutPlugins.Focus();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void btnOpenFolder_Click(object sender, EventArgs e){
|
||||||
|
using(Process.Start("explorer.exe", "\""+pluginManager.PathCustomPlugins+"\"")){}
|
||||||
|
}
|
||||||
|
|
||||||
|
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();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
317
Core/Other/FormSettings.Designer.cs
generated
317
Core/Other/FormSettings.Designer.cs
generated
@@ -1,4 +1,4 @@
|
|||||||
namespace TweetDick.Core.Other {
|
namespace TweetDuck.Core.Other {
|
||||||
sealed partial class FormSettings {
|
sealed partial class FormSettings {
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Required designer variable.
|
/// Required designer variable.
|
||||||
@@ -23,288 +23,87 @@
|
|||||||
/// the contents of this method with the code editor.
|
/// the contents of this method with the code editor.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
private void InitializeComponent() {
|
private void InitializeComponent() {
|
||||||
System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(FormSettings));
|
this.btnClose = new System.Windows.Forms.Button();
|
||||||
this.groupNotificationLocation = new System.Windows.Forms.GroupBox();
|
this.panelContents = new System.Windows.Forms.Panel();
|
||||||
this.labelDisplay = new System.Windows.Forms.Label();
|
this.panelButtons = new System.Windows.Forms.Panel();
|
||||||
this.comboBoxDisplay = new System.Windows.Forms.ComboBox();
|
this.btnManageOptions = new System.Windows.Forms.Button();
|
||||||
this.labelEdgeDistance = new System.Windows.Forms.Label();
|
|
||||||
this.trackBarEdgeDistance = new System.Windows.Forms.TrackBar();
|
|
||||||
this.radioLocCustom = new System.Windows.Forms.RadioButton();
|
|
||||||
this.radioLocBR = new System.Windows.Forms.RadioButton();
|
|
||||||
this.radioLocBL = new System.Windows.Forms.RadioButton();
|
|
||||||
this.radioLocTR = new System.Windows.Forms.RadioButton();
|
|
||||||
this.radioLocTL = new System.Windows.Forms.RadioButton();
|
|
||||||
this.groupNotificationDuration = new System.Windows.Forms.GroupBox();
|
|
||||||
this.radioDurVeryLong = new System.Windows.Forms.RadioButton();
|
|
||||||
this.radioDurLong = new System.Windows.Forms.RadioButton();
|
|
||||||
this.radioDurMedium = new System.Windows.Forms.RadioButton();
|
|
||||||
this.radioDurShort = new System.Windows.Forms.RadioButton();
|
|
||||||
this.tableLayout = new System.Windows.Forms.TableLayoutPanel();
|
|
||||||
this.groupNotificationLocation.SuspendLayout();
|
|
||||||
((System.ComponentModel.ISupportInitialize)(this.trackBarEdgeDistance)).BeginInit();
|
|
||||||
this.groupNotificationDuration.SuspendLayout();
|
|
||||||
this.tableLayout.SuspendLayout();
|
|
||||||
this.SuspendLayout();
|
this.SuspendLayout();
|
||||||
//
|
//
|
||||||
// groupNotificationLocation
|
// btnClose
|
||||||
//
|
//
|
||||||
this.groupNotificationLocation.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom)
|
this.btnClose.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right)));
|
||||||
|
this.btnClose.AutoSize = true;
|
||||||
|
this.btnClose.Location = new System.Drawing.Point(449, 447);
|
||||||
|
this.btnClose.Name = "btnClose";
|
||||||
|
this.btnClose.Padding = new System.Windows.Forms.Padding(3, 0, 3, 0);
|
||||||
|
this.btnClose.Size = new System.Drawing.Size(49, 23);
|
||||||
|
this.btnClose.TabIndex = 3;
|
||||||
|
this.btnClose.Text = "Close";
|
||||||
|
this.btnClose.UseVisualStyleBackColor = true;
|
||||||
|
this.btnClose.Click += new System.EventHandler(this.btnClose_Click);
|
||||||
|
//
|
||||||
|
// panelContents
|
||||||
|
//
|
||||||
|
this.panelContents.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom)
|
||||||
| System.Windows.Forms.AnchorStyles.Left)
|
| System.Windows.Forms.AnchorStyles.Left)
|
||||||
| System.Windows.Forms.AnchorStyles.Right)));
|
| System.Windows.Forms.AnchorStyles.Right)));
|
||||||
this.groupNotificationLocation.Controls.Add(this.labelDisplay);
|
this.panelContents.AutoScroll = true;
|
||||||
this.groupNotificationLocation.Controls.Add(this.comboBoxDisplay);
|
this.panelContents.BorderStyle = System.Windows.Forms.BorderStyle.FixedSingle;
|
||||||
this.groupNotificationLocation.Controls.Add(this.labelEdgeDistance);
|
this.panelContents.Location = new System.Drawing.Point(135, 12);
|
||||||
this.groupNotificationLocation.Controls.Add(this.trackBarEdgeDistance);
|
this.panelContents.Margin = new System.Windows.Forms.Padding(0, 3, 3, 3);
|
||||||
this.groupNotificationLocation.Controls.Add(this.radioLocCustom);
|
this.panelContents.Name = "panelContents";
|
||||||
this.groupNotificationLocation.Controls.Add(this.radioLocBR);
|
this.panelContents.Size = new System.Drawing.Size(363, 429);
|
||||||
this.groupNotificationLocation.Controls.Add(this.radioLocBL);
|
this.panelContents.TabIndex = 1;
|
||||||
this.groupNotificationLocation.Controls.Add(this.radioLocTR);
|
|
||||||
this.groupNotificationLocation.Controls.Add(this.radioLocTL);
|
|
||||||
this.groupNotificationLocation.Location = new System.Drawing.Point(6, 6);
|
|
||||||
this.groupNotificationLocation.Name = "groupNotificationLocation";
|
|
||||||
this.groupNotificationLocation.Size = new System.Drawing.Size(183, 270);
|
|
||||||
this.groupNotificationLocation.TabIndex = 0;
|
|
||||||
this.groupNotificationLocation.TabStop = false;
|
|
||||||
this.groupNotificationLocation.Text = "Notification Location";
|
|
||||||
//
|
//
|
||||||
// labelDisplay
|
// panelButtons
|
||||||
//
|
//
|
||||||
this.labelDisplay.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left)));
|
this.panelButtons.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom)
|
||||||
this.labelDisplay.AutoSize = true;
|
| System.Windows.Forms.AnchorStyles.Left)));
|
||||||
this.labelDisplay.Location = new System.Drawing.Point(6, 154);
|
this.panelButtons.BorderStyle = System.Windows.Forms.BorderStyle.FixedSingle;
|
||||||
this.labelDisplay.Name = "labelDisplay";
|
this.panelButtons.Location = new System.Drawing.Point(12, 12);
|
||||||
this.labelDisplay.Size = new System.Drawing.Size(41, 13);
|
this.panelButtons.Margin = new System.Windows.Forms.Padding(3, 3, 0, 3);
|
||||||
this.labelDisplay.TabIndex = 8;
|
this.panelButtons.Name = "panelButtons";
|
||||||
this.labelDisplay.Text = "Display";
|
this.panelButtons.Size = new System.Drawing.Size(124, 429);
|
||||||
|
this.panelButtons.TabIndex = 0;
|
||||||
//
|
//
|
||||||
// comboBoxDisplay
|
// btnManageOptions
|
||||||
//
|
//
|
||||||
this.comboBoxDisplay.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left)
|
this.btnManageOptions.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left)));
|
||||||
| System.Windows.Forms.AnchorStyles.Right)));
|
this.btnManageOptions.AutoSize = true;
|
||||||
this.comboBoxDisplay.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList;
|
this.btnManageOptions.Location = new System.Drawing.Point(12, 447);
|
||||||
this.comboBoxDisplay.FormattingEnabled = true;
|
this.btnManageOptions.Name = "btnManageOptions";
|
||||||
this.comboBoxDisplay.Location = new System.Drawing.Point(9, 170);
|
this.btnManageOptions.Padding = new System.Windows.Forms.Padding(3, 0, 3, 0);
|
||||||
this.comboBoxDisplay.Margin = new System.Windows.Forms.Padding(3, 3, 3, 12);
|
this.btnManageOptions.Size = new System.Drawing.Size(101, 23);
|
||||||
this.comboBoxDisplay.Name = "comboBoxDisplay";
|
this.btnManageOptions.TabIndex = 4;
|
||||||
this.comboBoxDisplay.Size = new System.Drawing.Size(168, 21);
|
this.btnManageOptions.Text = "Manage Options";
|
||||||
this.comboBoxDisplay.TabIndex = 7;
|
this.btnManageOptions.UseVisualStyleBackColor = true;
|
||||||
this.comboBoxDisplay.SelectedValueChanged += new System.EventHandler(this.comboBoxDisplay_SelectedValueChanged);
|
this.btnManageOptions.Click += new System.EventHandler(this.btnManageOptions_Click);
|
||||||
//
|
|
||||||
// labelEdgeDistance
|
|
||||||
//
|
|
||||||
this.labelEdgeDistance.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left)));
|
|
||||||
this.labelEdgeDistance.AutoSize = true;
|
|
||||||
this.labelEdgeDistance.Location = new System.Drawing.Point(6, 203);
|
|
||||||
this.labelEdgeDistance.Name = "labelEdgeDistance";
|
|
||||||
this.labelEdgeDistance.Size = new System.Drawing.Size(103, 13);
|
|
||||||
this.labelEdgeDistance.TabIndex = 6;
|
|
||||||
this.labelEdgeDistance.Text = "Distance From Edge";
|
|
||||||
//
|
|
||||||
// trackBarEdgeDistance
|
|
||||||
//
|
|
||||||
this.trackBarEdgeDistance.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left)
|
|
||||||
| System.Windows.Forms.AnchorStyles.Right)));
|
|
||||||
this.trackBarEdgeDistance.LargeChange = 8;
|
|
||||||
this.trackBarEdgeDistance.Location = new System.Drawing.Point(6, 219);
|
|
||||||
this.trackBarEdgeDistance.Maximum = 40;
|
|
||||||
this.trackBarEdgeDistance.Minimum = 8;
|
|
||||||
this.trackBarEdgeDistance.Name = "trackBarEdgeDistance";
|
|
||||||
this.trackBarEdgeDistance.Size = new System.Drawing.Size(171, 45);
|
|
||||||
this.trackBarEdgeDistance.SmallChange = 2;
|
|
||||||
this.trackBarEdgeDistance.TabIndex = 5;
|
|
||||||
this.trackBarEdgeDistance.TickFrequency = 2;
|
|
||||||
this.trackBarEdgeDistance.Value = 8;
|
|
||||||
this.trackBarEdgeDistance.ValueChanged += new System.EventHandler(this.trackBarEdgeDistance_ValueChanged);
|
|
||||||
//
|
|
||||||
// radioLocCustom
|
|
||||||
//
|
|
||||||
this.radioLocCustom.AutoSize = true;
|
|
||||||
this.radioLocCustom.Location = new System.Drawing.Point(7, 116);
|
|
||||||
this.radioLocCustom.Name = "radioLocCustom";
|
|
||||||
this.radioLocCustom.Size = new System.Drawing.Size(60, 17);
|
|
||||||
this.radioLocCustom.TabIndex = 4;
|
|
||||||
this.radioLocCustom.TabStop = true;
|
|
||||||
this.radioLocCustom.Text = "Custom";
|
|
||||||
this.radioLocCustom.UseVisualStyleBackColor = true;
|
|
||||||
this.radioLocCustom.CheckedChanged += new System.EventHandler(this.radioLoc_CheckedChanged);
|
|
||||||
this.radioLocCustom.Click += new System.EventHandler(this.radioLoc_Click);
|
|
||||||
//
|
|
||||||
// radioLocBR
|
|
||||||
//
|
|
||||||
this.radioLocBR.AutoSize = true;
|
|
||||||
this.radioLocBR.Location = new System.Drawing.Point(7, 92);
|
|
||||||
this.radioLocBR.Name = "radioLocBR";
|
|
||||||
this.radioLocBR.Size = new System.Drawing.Size(86, 17);
|
|
||||||
this.radioLocBR.TabIndex = 3;
|
|
||||||
this.radioLocBR.TabStop = true;
|
|
||||||
this.radioLocBR.Text = "Bottom Right";
|
|
||||||
this.radioLocBR.UseVisualStyleBackColor = true;
|
|
||||||
this.radioLocBR.CheckedChanged += new System.EventHandler(this.radioLoc_CheckedChanged);
|
|
||||||
this.radioLocBR.Click += new System.EventHandler(this.radioLoc_Click);
|
|
||||||
//
|
|
||||||
// radioLocBL
|
|
||||||
//
|
|
||||||
this.radioLocBL.AutoSize = true;
|
|
||||||
this.radioLocBL.Location = new System.Drawing.Point(7, 68);
|
|
||||||
this.radioLocBL.Name = "radioLocBL";
|
|
||||||
this.radioLocBL.Size = new System.Drawing.Size(79, 17);
|
|
||||||
this.radioLocBL.TabIndex = 2;
|
|
||||||
this.radioLocBL.TabStop = true;
|
|
||||||
this.radioLocBL.Text = "Bottom Left";
|
|
||||||
this.radioLocBL.UseVisualStyleBackColor = true;
|
|
||||||
this.radioLocBL.CheckedChanged += new System.EventHandler(this.radioLoc_CheckedChanged);
|
|
||||||
this.radioLocBL.Click += new System.EventHandler(this.radioLoc_Click);
|
|
||||||
//
|
|
||||||
// radioLocTR
|
|
||||||
//
|
|
||||||
this.radioLocTR.AutoSize = true;
|
|
||||||
this.radioLocTR.Location = new System.Drawing.Point(7, 44);
|
|
||||||
this.radioLocTR.Name = "radioLocTR";
|
|
||||||
this.radioLocTR.Size = new System.Drawing.Size(72, 17);
|
|
||||||
this.radioLocTR.TabIndex = 1;
|
|
||||||
this.radioLocTR.TabStop = true;
|
|
||||||
this.radioLocTR.Text = "Top Right";
|
|
||||||
this.radioLocTR.UseVisualStyleBackColor = true;
|
|
||||||
this.radioLocTR.CheckedChanged += new System.EventHandler(this.radioLoc_CheckedChanged);
|
|
||||||
this.radioLocTR.Click += new System.EventHandler(this.radioLoc_Click);
|
|
||||||
//
|
|
||||||
// radioLocTL
|
|
||||||
//
|
|
||||||
this.radioLocTL.AutoSize = true;
|
|
||||||
this.radioLocTL.Location = new System.Drawing.Point(7, 20);
|
|
||||||
this.radioLocTL.Name = "radioLocTL";
|
|
||||||
this.radioLocTL.Size = new System.Drawing.Size(65, 17);
|
|
||||||
this.radioLocTL.TabIndex = 0;
|
|
||||||
this.radioLocTL.TabStop = true;
|
|
||||||
this.radioLocTL.Text = "Top Left";
|
|
||||||
this.radioLocTL.UseVisualStyleBackColor = true;
|
|
||||||
this.radioLocTL.CheckedChanged += new System.EventHandler(this.radioLoc_CheckedChanged);
|
|
||||||
this.radioLocTL.Click += new System.EventHandler(this.radioLoc_Click);
|
|
||||||
//
|
|
||||||
// groupNotificationDuration
|
|
||||||
//
|
|
||||||
this.groupNotificationDuration.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left)
|
|
||||||
| System.Windows.Forms.AnchorStyles.Right)));
|
|
||||||
this.groupNotificationDuration.Controls.Add(this.radioDurVeryLong);
|
|
||||||
this.groupNotificationDuration.Controls.Add(this.radioDurLong);
|
|
||||||
this.groupNotificationDuration.Controls.Add(this.radioDurMedium);
|
|
||||||
this.groupNotificationDuration.Controls.Add(this.radioDurShort);
|
|
||||||
this.groupNotificationDuration.Location = new System.Drawing.Point(195, 6);
|
|
||||||
this.groupNotificationDuration.Name = "groupNotificationDuration";
|
|
||||||
this.groupNotificationDuration.Size = new System.Drawing.Size(183, 118);
|
|
||||||
this.groupNotificationDuration.TabIndex = 1;
|
|
||||||
this.groupNotificationDuration.TabStop = false;
|
|
||||||
this.groupNotificationDuration.Text = "Notification Duration";
|
|
||||||
//
|
|
||||||
// radioDurVeryLong
|
|
||||||
//
|
|
||||||
this.radioDurVeryLong.AutoSize = true;
|
|
||||||
this.radioDurVeryLong.Location = new System.Drawing.Point(6, 92);
|
|
||||||
this.radioDurVeryLong.Name = "radioDurVeryLong";
|
|
||||||
this.radioDurVeryLong.Size = new System.Drawing.Size(73, 17);
|
|
||||||
this.radioDurVeryLong.TabIndex = 3;
|
|
||||||
this.radioDurVeryLong.TabStop = true;
|
|
||||||
this.radioDurVeryLong.Text = "Very Long";
|
|
||||||
this.radioDurVeryLong.UseVisualStyleBackColor = true;
|
|
||||||
this.radioDurVeryLong.CheckedChanged += new System.EventHandler(this.radioDur_CheckedChanged);
|
|
||||||
this.radioDurVeryLong.Click += new System.EventHandler(this.radioDur_Click);
|
|
||||||
//
|
|
||||||
// radioDurLong
|
|
||||||
//
|
|
||||||
this.radioDurLong.AutoSize = true;
|
|
||||||
this.radioDurLong.Location = new System.Drawing.Point(6, 68);
|
|
||||||
this.radioDurLong.Name = "radioDurLong";
|
|
||||||
this.radioDurLong.Size = new System.Drawing.Size(49, 17);
|
|
||||||
this.radioDurLong.TabIndex = 2;
|
|
||||||
this.radioDurLong.TabStop = true;
|
|
||||||
this.radioDurLong.Text = "Long";
|
|
||||||
this.radioDurLong.UseVisualStyleBackColor = true;
|
|
||||||
this.radioDurLong.CheckedChanged += new System.EventHandler(this.radioDur_CheckedChanged);
|
|
||||||
this.radioDurLong.Click += new System.EventHandler(this.radioDur_Click);
|
|
||||||
//
|
|
||||||
// radioDurMedium
|
|
||||||
//
|
|
||||||
this.radioDurMedium.AutoSize = true;
|
|
||||||
this.radioDurMedium.Location = new System.Drawing.Point(6, 44);
|
|
||||||
this.radioDurMedium.Name = "radioDurMedium";
|
|
||||||
this.radioDurMedium.Size = new System.Drawing.Size(62, 17);
|
|
||||||
this.radioDurMedium.TabIndex = 1;
|
|
||||||
this.radioDurMedium.TabStop = true;
|
|
||||||
this.radioDurMedium.Text = "Medium";
|
|
||||||
this.radioDurMedium.UseVisualStyleBackColor = true;
|
|
||||||
this.radioDurMedium.CheckedChanged += new System.EventHandler(this.radioDur_CheckedChanged);
|
|
||||||
this.radioDurMedium.Click += new System.EventHandler(this.radioDur_Click);
|
|
||||||
//
|
|
||||||
// radioDurShort
|
|
||||||
//
|
|
||||||
this.radioDurShort.AutoSize = true;
|
|
||||||
this.radioDurShort.Location = new System.Drawing.Point(6, 20);
|
|
||||||
this.radioDurShort.Name = "radioDurShort";
|
|
||||||
this.radioDurShort.Size = new System.Drawing.Size(50, 17);
|
|
||||||
this.radioDurShort.TabIndex = 0;
|
|
||||||
this.radioDurShort.TabStop = true;
|
|
||||||
this.radioDurShort.Text = "Short";
|
|
||||||
this.radioDurShort.UseVisualStyleBackColor = true;
|
|
||||||
this.radioDurShort.CheckedChanged += new System.EventHandler(this.radioDur_CheckedChanged);
|
|
||||||
this.radioDurShort.Click += new System.EventHandler(this.radioDur_Click);
|
|
||||||
//
|
|
||||||
// tableLayout
|
|
||||||
//
|
|
||||||
this.tableLayout.ColumnCount = 2;
|
|
||||||
this.tableLayout.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 50F));
|
|
||||||
this.tableLayout.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 50F));
|
|
||||||
this.tableLayout.Controls.Add(this.groupNotificationLocation, 0, 0);
|
|
||||||
this.tableLayout.Controls.Add(this.groupNotificationDuration, 1, 0);
|
|
||||||
this.tableLayout.Dock = System.Windows.Forms.DockStyle.Fill;
|
|
||||||
this.tableLayout.GrowStyle = System.Windows.Forms.TableLayoutPanelGrowStyle.FixedSize;
|
|
||||||
this.tableLayout.Location = new System.Drawing.Point(0, 0);
|
|
||||||
this.tableLayout.Name = "tableLayout";
|
|
||||||
this.tableLayout.Padding = new System.Windows.Forms.Padding(3);
|
|
||||||
this.tableLayout.RowCount = 1;
|
|
||||||
this.tableLayout.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 100F));
|
|
||||||
this.tableLayout.Size = new System.Drawing.Size(384, 282);
|
|
||||||
this.tableLayout.TabIndex = 2;
|
|
||||||
//
|
//
|
||||||
// FormSettings
|
// FormSettings
|
||||||
//
|
//
|
||||||
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
|
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
|
||||||
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
|
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
|
||||||
this.ClientSize = new System.Drawing.Size(384, 282);
|
this.ClientSize = new System.Drawing.Size(510, 482);
|
||||||
this.Controls.Add(this.tableLayout);
|
this.Controls.Add(this.btnManageOptions);
|
||||||
|
this.Controls.Add(this.panelContents);
|
||||||
|
this.Controls.Add(this.panelButtons);
|
||||||
|
this.Controls.Add(this.btnClose);
|
||||||
this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedSingle;
|
this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedSingle;
|
||||||
this.Icon = TweetDick.Properties.Resources.icon;
|
this.Icon = global::TweetDuck.Properties.Resources.icon;
|
||||||
this.MaximizeBox = false;
|
this.MaximizeBox = false;
|
||||||
this.MinimizeBox = false;
|
this.MinimizeBox = false;
|
||||||
this.Name = "FormSettings";
|
this.Name = "FormSettings";
|
||||||
this.StartPosition = System.Windows.Forms.FormStartPosition.CenterParent;
|
this.StartPosition = System.Windows.Forms.FormStartPosition.CenterParent;
|
||||||
this.FormClosing += new System.Windows.Forms.FormClosingEventHandler(this.FormSettings_FormClosing);
|
this.FormClosing += new System.Windows.Forms.FormClosingEventHandler(this.FormSettings_FormClosing);
|
||||||
this.groupNotificationLocation.ResumeLayout(false);
|
|
||||||
this.groupNotificationLocation.PerformLayout();
|
|
||||||
((System.ComponentModel.ISupportInitialize)(this.trackBarEdgeDistance)).EndInit();
|
|
||||||
this.groupNotificationDuration.ResumeLayout(false);
|
|
||||||
this.groupNotificationDuration.PerformLayout();
|
|
||||||
this.tableLayout.ResumeLayout(false);
|
|
||||||
this.ResumeLayout(false);
|
this.ResumeLayout(false);
|
||||||
|
this.PerformLayout();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
private System.Windows.Forms.Button btnClose;
|
||||||
private System.Windows.Forms.GroupBox groupNotificationLocation;
|
private System.Windows.Forms.Panel panelContents;
|
||||||
private System.Windows.Forms.RadioButton radioLocCustom;
|
private System.Windows.Forms.Panel panelButtons;
|
||||||
private System.Windows.Forms.RadioButton radioLocBR;
|
private System.Windows.Forms.Button btnManageOptions;
|
||||||
private System.Windows.Forms.RadioButton radioLocBL;
|
|
||||||
private System.Windows.Forms.RadioButton radioLocTR;
|
|
||||||
private System.Windows.Forms.RadioButton radioLocTL;
|
|
||||||
private System.Windows.Forms.Label labelEdgeDistance;
|
|
||||||
private System.Windows.Forms.TrackBar trackBarEdgeDistance;
|
|
||||||
private System.Windows.Forms.GroupBox groupNotificationDuration;
|
|
||||||
private System.Windows.Forms.RadioButton radioDurVeryLong;
|
|
||||||
private System.Windows.Forms.RadioButton radioDurLong;
|
|
||||||
private System.Windows.Forms.RadioButton radioDurMedium;
|
|
||||||
private System.Windows.Forms.RadioButton radioDurShort;
|
|
||||||
private System.Windows.Forms.Label labelDisplay;
|
|
||||||
private System.Windows.Forms.ComboBox comboBoxDisplay;
|
|
||||||
private System.Windows.Forms.TableLayoutPanel tableLayout;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1,119 +1,161 @@
|
|||||||
using System;
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Drawing;
|
||||||
using System.Windows.Forms;
|
using System.Windows.Forms;
|
||||||
using TweetDick.Configuration;
|
using TweetDuck.Core.Controls;
|
||||||
using TweetDick.Core.Handling;
|
using TweetDuck.Core.Other.Settings;
|
||||||
|
using TweetDuck.Core.Other.Settings.Dialogs;
|
||||||
|
using TweetDuck.Core.Utils;
|
||||||
|
using TweetDuck.Plugins;
|
||||||
|
using TweetDuck.Updates;
|
||||||
|
|
||||||
namespace TweetDick.Core.Other{
|
namespace TweetDuck.Core.Other{
|
||||||
sealed partial class FormSettings : Form{
|
sealed partial class FormSettings : Form{
|
||||||
private static UserConfig Config{
|
private readonly FormBrowser browser;
|
||||||
get{
|
private readonly PluginManager plugins;
|
||||||
return Program.UserConfig;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private readonly FormNotification notification;
|
private readonly int buttonHeight;
|
||||||
private bool isLoaded;
|
|
||||||
|
|
||||||
public FormSettings(FormBrowser browserForm){
|
private readonly Dictionary<Type, SettingsTab> tabs = new Dictionary<Type, SettingsTab>(4);
|
||||||
|
private SettingsTab currentTab;
|
||||||
|
|
||||||
|
public FormSettings(FormBrowser browser, PluginManager plugins, UpdateHandler updates, Type startTab){
|
||||||
InitializeComponent();
|
InitializeComponent();
|
||||||
Shown += (sender, args) => isLoaded = true;
|
|
||||||
|
|
||||||
Text = Program.BrandName+" Settings";
|
Text = Program.BrandName+" Options";
|
||||||
|
|
||||||
notification = new FormNotification(browserForm,false){ CanMoveWindow = () => radioLocCustom.Checked };
|
this.browser = browser;
|
||||||
|
this.browser.PauseNotification();
|
||||||
|
|
||||||
notification.Move += (sender, args) => {
|
this.plugins = plugins;
|
||||||
if (radioLocCustom.Checked){
|
|
||||||
Config.CustomNotificationPosition = notification.Location;
|
this.buttonHeight = BrowserUtils.Scale(39, this.GetDPIScale()) | 1;
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
notification.Show(this);
|
AddButton("General", () => new TabSettingsGeneral(updates));
|
||||||
|
AddButton("Notifications", () => new TabSettingsNotifications(browser.CreateNotificationForm(false)));
|
||||||
|
AddButton("Sounds", () => new TabSettingsSounds());
|
||||||
|
AddButton("Advanced", () => new TabSettingsAdvanced(browser.ReinjectCustomCSS));
|
||||||
|
|
||||||
switch(Config.NotificationPosition){
|
SelectTab(tabs[startTab ?? typeof(TabSettingsGeneral)]);
|
||||||
case TweetNotification.Position.TopLeft: radioLocTL.Checked = true; break;
|
|
||||||
case TweetNotification.Position.TopRight: radioLocTR.Checked = true; break;
|
|
||||||
case TweetNotification.Position.BottomLeft: radioLocBL.Checked = true; break;
|
|
||||||
case TweetNotification.Position.BottomRight: radioLocBR.Checked = true; break;
|
|
||||||
case TweetNotification.Position.Custom: radioLocCustom.Checked = true; break;
|
|
||||||
}
|
|
||||||
|
|
||||||
switch(Config.NotificationDuration){
|
|
||||||
case TweetNotification.Duration.Short: radioDurShort.Checked = true; break;
|
|
||||||
case TweetNotification.Duration.Medium: radioDurMedium.Checked = true; break;
|
|
||||||
case TweetNotification.Duration.Long: radioDurLong.Checked = true; break;
|
|
||||||
case TweetNotification.Duration.VeryLong: radioDurVeryLong.Checked = true; break;
|
|
||||||
}
|
|
||||||
|
|
||||||
comboBoxDisplay.Items.Add("(Same As "+Program.BrandName+")");
|
|
||||||
|
|
||||||
foreach(Screen screen in Screen.AllScreens){
|
|
||||||
comboBoxDisplay.Items.Add(screen.DeviceName+" ("+screen.Bounds.Width+"x"+screen.Bounds.Height+")");
|
|
||||||
}
|
|
||||||
|
|
||||||
comboBoxDisplay.SelectedIndex = Math.Min(comboBoxDisplay.Items.Count-1,Config.NotificationDisplay);
|
|
||||||
|
|
||||||
trackBarEdgeDistance.Value = Config.NotificationEdgeDistance;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void FormSettings_FormClosing(object sender, FormClosingEventArgs e){
|
private void FormSettings_FormClosing(object sender, FormClosingEventArgs e){
|
||||||
Config.Save();
|
foreach(SettingsTab tab in tabs.Values){
|
||||||
|
if (tab.IsInitialized){
|
||||||
|
tab.Control.OnClosing();
|
||||||
|
tab.Control.Dispose();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Program.UserConfig.Save();
|
||||||
|
browser.ResumeNotification();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void radioLoc_CheckedChanged(object sender, EventArgs e){
|
private void btnManageOptions_Click(object sender, EventArgs e){
|
||||||
if (!isLoaded)return;
|
using(DialogSettingsManage dialog = new DialogSettingsManage(plugins)){
|
||||||
|
if (dialog.ShowDialog() == DialogResult.OK && dialog.ShouldReloadUI){
|
||||||
|
foreach(SettingsTab tab in tabs.Values){
|
||||||
|
tab.Control = null;
|
||||||
|
}
|
||||||
|
|
||||||
if (radioLocTL.Checked)Config.NotificationPosition = TweetNotification.Position.TopLeft;
|
SelectTab(currentTab);
|
||||||
else if (radioLocTR.Checked)Config.NotificationPosition = TweetNotification.Position.TopRight;
|
}
|
||||||
else if (radioLocBL.Checked)Config.NotificationPosition = TweetNotification.Position.BottomLeft;
|
}
|
||||||
else if (radioLocBR.Checked)Config.NotificationPosition = TweetNotification.Position.BottomRight;
|
}
|
||||||
else if (radioLocCustom.Checked){
|
|
||||||
if (!Config.IsCustomNotificationPositionSet){
|
private void btnClose_Click(object sender, EventArgs e){
|
||||||
Config.CustomNotificationPosition = notification.Location;
|
Close();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void AddButton<T>(string title, Func<T> constructor) where T : BaseTabSettings{
|
||||||
|
FlatButton btn = new FlatButton{
|
||||||
|
BackColor = SystemColors.Control,
|
||||||
|
FlatStyle = FlatStyle.Flat,
|
||||||
|
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;
|
||||||
|
btn.FlatAppearance.MouseDownBackColor = Color.FromArgb(179, 213, 232);
|
||||||
|
btn.FlatAppearance.MouseOverBackColor = Color.FromArgb(216, 230, 237);
|
||||||
|
|
||||||
|
panelButtons.Controls.Add(btn);
|
||||||
|
|
||||||
|
panelButtons.Controls.Add(new Panel{
|
||||||
|
BackColor = Color.DimGray,
|
||||||
|
Location = new Point(0, panelButtons.Controls[panelButtons.Controls.Count-1].Location.Y+buttonHeight),
|
||||||
|
Margin = new Padding(0),
|
||||||
|
Size = new Size(panelButtons.Width, 1)
|
||||||
|
});
|
||||||
|
|
||||||
|
tabs.Add(typeof(T), new SettingsTab(btn, constructor));
|
||||||
|
|
||||||
|
btn.Click += (sender, args) => SelectTab<T>();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void SelectTab<T>() where T : BaseTabSettings{
|
||||||
|
SelectTab(tabs[typeof(T)]);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void SelectTab(SettingsTab tab){
|
||||||
|
if (currentTab != null){
|
||||||
|
currentTab.Button.BackColor = SystemColors.Control;
|
||||||
|
}
|
||||||
|
|
||||||
|
tab.Button.BackColor = tab.Button.FlatAppearance.MouseDownBackColor;
|
||||||
|
|
||||||
|
if (!tab.IsInitialized){
|
||||||
|
foreach(Control control in tab.Control.InteractiveControls){
|
||||||
|
if (control is ComboBox){
|
||||||
|
control.MouseLeave += control_MouseLeave;
|
||||||
|
}
|
||||||
|
else if (control is TrackBar){
|
||||||
|
control.MouseWheel += control_MouseWheel;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Config.NotificationPosition = TweetNotification.Position.Custom;
|
tab.Control.OnReady();
|
||||||
|
}
|
||||||
|
|
||||||
|
panelContents.SuspendLayout();
|
||||||
|
panelContents.VerticalScroll.Value = 0; // https://gfycat.com/GrotesqueTastyAstarte
|
||||||
|
panelContents.Controls.Clear();
|
||||||
|
panelContents.Controls.Add(tab.Control);
|
||||||
|
panelContents.ResumeLayout(true);
|
||||||
|
panelContents.Focus();
|
||||||
|
|
||||||
|
currentTab = tab;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void control_MouseLeave(object sender, EventArgs e){
|
||||||
|
panelContents.Focus();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void control_MouseWheel(object sender, MouseEventArgs e){
|
||||||
|
((HandledMouseEventArgs)e).Handled = true;
|
||||||
|
panelContents.Focus();
|
||||||
|
}
|
||||||
|
|
||||||
|
private class SettingsTab{
|
||||||
|
public Button Button { get; }
|
||||||
|
|
||||||
|
public BaseTabSettings Control{
|
||||||
|
get => control ?? (control = constructor());
|
||||||
|
set => control = value;
|
||||||
}
|
}
|
||||||
|
|
||||||
comboBoxDisplay.Enabled = trackBarEdgeDistance.Enabled = !radioLocCustom.Checked;
|
public bool IsInitialized => control != null;
|
||||||
notification.ShowNotificationForSettings(false);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void radioLoc_Click(object sender, EventArgs e){
|
private readonly Func<BaseTabSettings> constructor;
|
||||||
if (!isLoaded)return;
|
private BaseTabSettings control;
|
||||||
|
|
||||||
notification.ShowNotificationForSettings(false);
|
public SettingsTab(Button button, Func<BaseTabSettings> constructor){
|
||||||
}
|
this.Button = button;
|
||||||
|
this.constructor = constructor;
|
||||||
private void comboBoxDisplay_SelectedValueChanged(object sender, EventArgs e){
|
}
|
||||||
if (!isLoaded)return;
|
|
||||||
|
|
||||||
Config.NotificationDisplay = comboBoxDisplay.SelectedIndex;
|
|
||||||
notification.ShowNotificationForSettings(false);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void trackBarEdgeDistance_ValueChanged(object sender, EventArgs e){
|
|
||||||
if (!isLoaded)return;
|
|
||||||
|
|
||||||
Config.NotificationEdgeDistance = trackBarEdgeDistance.Value;
|
|
||||||
notification.ShowNotificationForSettings(false);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void radioDur_CheckedChanged(object sender, EventArgs e){
|
|
||||||
if (!isLoaded)return;
|
|
||||||
|
|
||||||
if (radioDurShort.Checked)Config.NotificationDuration = TweetNotification.Duration.Short;
|
|
||||||
else if (radioDurMedium.Checked)Config.NotificationDuration = TweetNotification.Duration.Medium;
|
|
||||||
else if (radioDurLong.Checked)Config.NotificationDuration = TweetNotification.Duration.Long;
|
|
||||||
else if (radioDurVeryLong.Checked)Config.NotificationDuration = TweetNotification.Duration.VeryLong;
|
|
||||||
|
|
||||||
notification.ShowNotificationForSettings(true);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void radioDur_Click(object sender, EventArgs e){
|
|
||||||
if (!isLoaded)return;
|
|
||||||
|
|
||||||
notification.ShowNotificationForSettings(true);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
33
Core/Other/Settings/BaseTabSettings.cs
Normal file
33
Core/Other/Settings/BaseTabSettings.cs
Normal file
@@ -0,0 +1,33 @@
|
|||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Windows.Forms;
|
||||||
|
using TweetDuck.Configuration;
|
||||||
|
|
||||||
|
namespace TweetDuck.Core.Other.Settings{
|
||||||
|
class BaseTabSettings : UserControl{
|
||||||
|
protected static UserConfig Config => Program.UserConfig;
|
||||||
|
|
||||||
|
public IEnumerable<Control> InteractiveControls{
|
||||||
|
get{
|
||||||
|
foreach(Panel panel in Controls.OfType<Panel>()){
|
||||||
|
foreach(Control control in panel.Controls){
|
||||||
|
yield return control;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public BaseTabSettings(){
|
||||||
|
Padding = new Padding(6);
|
||||||
|
}
|
||||||
|
|
||||||
|
public virtual void OnReady(){}
|
||||||
|
public virtual void OnClosing(){}
|
||||||
|
|
||||||
|
protected static void PromptRestart(){
|
||||||
|
if (FormMessage.Information("TweetDuck Options", "The application must restart for the option to take place. Do you want to restart now?", FormMessage.Yes, FormMessage.No)){
|
||||||
|
Program.Restart();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
203
Core/Other/Settings/Dialogs/DialogSettingsCSS.Designer.cs
generated
Normal file
203
Core/Other/Settings/Dialogs/DialogSettingsCSS.Designer.cs
generated
Normal file
@@ -0,0 +1,203 @@
|
|||||||
|
namespace TweetDuck.Core.Other.Settings.Dialogs {
|
||||||
|
partial class DialogSettingsCSS {
|
||||||
|
/// <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.components = new System.ComponentModel.Container();
|
||||||
|
this.textBoxBrowserCSS = new System.Windows.Forms.TextBox();
|
||||||
|
this.btnCancel = new System.Windows.Forms.Button();
|
||||||
|
this.btnApply = new System.Windows.Forms.Button();
|
||||||
|
this.splitContainer = new System.Windows.Forms.SplitContainer();
|
||||||
|
this.labelBrowser = new System.Windows.Forms.Label();
|
||||||
|
this.labelNotification = new System.Windows.Forms.Label();
|
||||||
|
this.textBoxNotificationCSS = new System.Windows.Forms.TextBox();
|
||||||
|
this.labelWarning = new System.Windows.Forms.Label();
|
||||||
|
this.btnOpenWiki = new System.Windows.Forms.Button();
|
||||||
|
this.timerTestBrowser = new System.Windows.Forms.Timer(this.components);
|
||||||
|
((System.ComponentModel.ISupportInitialize)(this.splitContainer)).BeginInit();
|
||||||
|
this.splitContainer.Panel1.SuspendLayout();
|
||||||
|
this.splitContainer.Panel2.SuspendLayout();
|
||||||
|
this.splitContainer.SuspendLayout();
|
||||||
|
this.SuspendLayout();
|
||||||
|
//
|
||||||
|
// textBoxBrowserCSS
|
||||||
|
//
|
||||||
|
this.textBoxBrowserCSS.Dock = System.Windows.Forms.DockStyle.Bottom;
|
||||||
|
this.textBoxBrowserCSS.Font = new System.Drawing.Font("Courier New", 8.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(238)));
|
||||||
|
this.textBoxBrowserCSS.Location = new System.Drawing.Point(0, 16);
|
||||||
|
this.textBoxBrowserCSS.Margin = new System.Windows.Forms.Padding(0, 3, 0, 0);
|
||||||
|
this.textBoxBrowserCSS.Multiline = true;
|
||||||
|
this.textBoxBrowserCSS.Name = "textBoxBrowserCSS";
|
||||||
|
this.textBoxBrowserCSS.ScrollBars = System.Windows.Forms.ScrollBars.Both;
|
||||||
|
this.textBoxBrowserCSS.Size = new System.Drawing.Size(378, 253);
|
||||||
|
this.textBoxBrowserCSS.TabIndex = 1;
|
||||||
|
this.textBoxBrowserCSS.WordWrap = false;
|
||||||
|
this.textBoxBrowserCSS.KeyUp += new System.Windows.Forms.KeyEventHandler(this.textBoxBrowserCSS_KeyUp);
|
||||||
|
//
|
||||||
|
// btnCancel
|
||||||
|
//
|
||||||
|
this.btnCancel.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right)));
|
||||||
|
this.btnCancel.Location = new System.Drawing.Point(654, 287);
|
||||||
|
this.btnCancel.Name = "btnCancel";
|
||||||
|
this.btnCancel.Padding = new System.Windows.Forms.Padding(3, 0, 3, 0);
|
||||||
|
this.btnCancel.Size = new System.Drawing.Size(56, 23);
|
||||||
|
this.btnCancel.TabIndex = 2;
|
||||||
|
this.btnCancel.Text = "Cancel";
|
||||||
|
this.btnCancel.UseVisualStyleBackColor = true;
|
||||||
|
this.btnCancel.Click += new System.EventHandler(this.btnCancel_Click);
|
||||||
|
//
|
||||||
|
// btnApply
|
||||||
|
//
|
||||||
|
this.btnApply.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right)));
|
||||||
|
this.btnApply.Location = new System.Drawing.Point(716, 287);
|
||||||
|
this.btnApply.Name = "btnApply";
|
||||||
|
this.btnApply.Padding = new System.Windows.Forms.Padding(3, 0, 3, 0);
|
||||||
|
this.btnApply.Size = new System.Drawing.Size(56, 23);
|
||||||
|
this.btnApply.TabIndex = 1;
|
||||||
|
this.btnApply.Text = "Apply";
|
||||||
|
this.btnApply.UseVisualStyleBackColor = true;
|
||||||
|
this.btnApply.Click += new System.EventHandler(this.btnApply_Click);
|
||||||
|
//
|
||||||
|
// splitContainer
|
||||||
|
//
|
||||||
|
this.splitContainer.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom)
|
||||||
|
| System.Windows.Forms.AnchorStyles.Left)
|
||||||
|
| System.Windows.Forms.AnchorStyles.Right)));
|
||||||
|
this.splitContainer.Location = new System.Drawing.Point(12, 12);
|
||||||
|
this.splitContainer.Name = "splitContainer";
|
||||||
|
//
|
||||||
|
// splitContainer.Panel1
|
||||||
|
//
|
||||||
|
this.splitContainer.Panel1.Controls.Add(this.labelBrowser);
|
||||||
|
this.splitContainer.Panel1.Controls.Add(this.textBoxBrowserCSS);
|
||||||
|
this.splitContainer.Panel1MinSize = 64;
|
||||||
|
//
|
||||||
|
// splitContainer.Panel2
|
||||||
|
//
|
||||||
|
this.splitContainer.Panel2.Controls.Add(this.labelNotification);
|
||||||
|
this.splitContainer.Panel2.Controls.Add(this.textBoxNotificationCSS);
|
||||||
|
this.splitContainer.Panel2MinSize = 64;
|
||||||
|
this.splitContainer.Size = new System.Drawing.Size(760, 269);
|
||||||
|
this.splitContainer.SplitterDistance = 378;
|
||||||
|
this.splitContainer.SplitterWidth = 5;
|
||||||
|
this.splitContainer.TabIndex = 0;
|
||||||
|
//
|
||||||
|
// labelBrowser
|
||||||
|
//
|
||||||
|
this.labelBrowser.AutoSize = true;
|
||||||
|
this.labelBrowser.Location = new System.Drawing.Point(-3, 0);
|
||||||
|
this.labelBrowser.Margin = new System.Windows.Forms.Padding(0, 0, 3, 0);
|
||||||
|
this.labelBrowser.Name = "labelBrowser";
|
||||||
|
this.labelBrowser.Size = new System.Drawing.Size(45, 13);
|
||||||
|
this.labelBrowser.TabIndex = 0;
|
||||||
|
this.labelBrowser.Text = "Browser";
|
||||||
|
//
|
||||||
|
// labelNotification
|
||||||
|
//
|
||||||
|
this.labelNotification.AutoSize = true;
|
||||||
|
this.labelNotification.Location = new System.Drawing.Point(-3, 0);
|
||||||
|
this.labelNotification.Margin = new System.Windows.Forms.Padding(0, 0, 3, 0);
|
||||||
|
this.labelNotification.Name = "labelNotification";
|
||||||
|
this.labelNotification.Size = new System.Drawing.Size(60, 13);
|
||||||
|
this.labelNotification.TabIndex = 0;
|
||||||
|
this.labelNotification.Text = "Notification";
|
||||||
|
//
|
||||||
|
// textBoxNotificationCSS
|
||||||
|
//
|
||||||
|
this.textBoxNotificationCSS.Dock = System.Windows.Forms.DockStyle.Bottom;
|
||||||
|
this.textBoxNotificationCSS.Font = new System.Drawing.Font("Courier New", 8.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(238)));
|
||||||
|
this.textBoxNotificationCSS.Location = new System.Drawing.Point(0, 16);
|
||||||
|
this.textBoxNotificationCSS.Margin = new System.Windows.Forms.Padding(0, 3, 0, 0);
|
||||||
|
this.textBoxNotificationCSS.Multiline = true;
|
||||||
|
this.textBoxNotificationCSS.Name = "textBoxNotificationCSS";
|
||||||
|
this.textBoxNotificationCSS.ScrollBars = System.Windows.Forms.ScrollBars.Both;
|
||||||
|
this.textBoxNotificationCSS.Size = new System.Drawing.Size(377, 253);
|
||||||
|
this.textBoxNotificationCSS.TabIndex = 1;
|
||||||
|
this.textBoxNotificationCSS.WordWrap = false;
|
||||||
|
//
|
||||||
|
// labelWarning
|
||||||
|
//
|
||||||
|
this.labelWarning.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left)));
|
||||||
|
this.labelWarning.AutoSize = true;
|
||||||
|
this.labelWarning.Location = new System.Drawing.Point(91, 292);
|
||||||
|
this.labelWarning.Name = "labelWarning";
|
||||||
|
this.labelWarning.Size = new System.Drawing.Size(341, 13);
|
||||||
|
this.labelWarning.TabIndex = 3;
|
||||||
|
this.labelWarning.Text = "The code is not validated, please make sure there are no syntax errors.";
|
||||||
|
//
|
||||||
|
// btnOpenWiki
|
||||||
|
//
|
||||||
|
this.btnOpenWiki.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left)));
|
||||||
|
this.btnOpenWiki.Location = new System.Drawing.Point(12, 287);
|
||||||
|
this.btnOpenWiki.Name = "btnOpenWiki";
|
||||||
|
this.btnOpenWiki.Padding = new System.Windows.Forms.Padding(3, 0, 3, 0);
|
||||||
|
this.btnOpenWiki.Size = new System.Drawing.Size(73, 23);
|
||||||
|
this.btnOpenWiki.TabIndex = 4;
|
||||||
|
this.btnOpenWiki.Text = "Open Wiki";
|
||||||
|
this.btnOpenWiki.UseVisualStyleBackColor = true;
|
||||||
|
this.btnOpenWiki.Click += new System.EventHandler(this.btnOpenWiki_Click);
|
||||||
|
//
|
||||||
|
// timerTestBrowser
|
||||||
|
//
|
||||||
|
this.timerTestBrowser.Interval = 500;
|
||||||
|
this.timerTestBrowser.Tick += new System.EventHandler(this.timerTestBrowser_Tick);
|
||||||
|
//
|
||||||
|
// DialogSettingsCSS
|
||||||
|
//
|
||||||
|
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
|
||||||
|
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
|
||||||
|
this.ClientSize = new System.Drawing.Size(784, 322);
|
||||||
|
this.Controls.Add(this.btnOpenWiki);
|
||||||
|
this.Controls.Add(this.labelWarning);
|
||||||
|
this.Controls.Add(this.splitContainer);
|
||||||
|
this.Controls.Add(this.btnApply);
|
||||||
|
this.Controls.Add(this.btnCancel);
|
||||||
|
this.MinimumSize = new System.Drawing.Size(600, 160);
|
||||||
|
this.Name = "DialogSettingsCSS";
|
||||||
|
this.ShowIcon = false;
|
||||||
|
this.StartPosition = System.Windows.Forms.FormStartPosition.CenterParent;
|
||||||
|
this.splitContainer.Panel1.ResumeLayout(false);
|
||||||
|
this.splitContainer.Panel1.PerformLayout();
|
||||||
|
this.splitContainer.Panel2.ResumeLayout(false);
|
||||||
|
this.splitContainer.Panel2.PerformLayout();
|
||||||
|
((System.ComponentModel.ISupportInitialize)(this.splitContainer)).EndInit();
|
||||||
|
this.splitContainer.ResumeLayout(false);
|
||||||
|
this.ResumeLayout(false);
|
||||||
|
this.PerformLayout();
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
private System.Windows.Forms.TextBox textBoxBrowserCSS;
|
||||||
|
private System.Windows.Forms.Button btnCancel;
|
||||||
|
private System.Windows.Forms.Button btnApply;
|
||||||
|
private System.Windows.Forms.SplitContainer splitContainer;
|
||||||
|
private System.Windows.Forms.TextBox textBoxNotificationCSS;
|
||||||
|
private System.Windows.Forms.Label labelBrowser;
|
||||||
|
private System.Windows.Forms.Label labelNotification;
|
||||||
|
private System.Windows.Forms.Label labelWarning;
|
||||||
|
private System.Windows.Forms.Button btnOpenWiki;
|
||||||
|
private System.Windows.Forms.Timer timerTestBrowser;
|
||||||
|
}
|
||||||
|
}
|
||||||
51
Core/Other/Settings/Dialogs/DialogSettingsCSS.cs
Normal file
51
Core/Other/Settings/Dialogs/DialogSettingsCSS.cs
Normal file
@@ -0,0 +1,51 @@
|
|||||||
|
using System;
|
||||||
|
using System.Windows.Forms;
|
||||||
|
using TweetDuck.Core.Controls;
|
||||||
|
using TweetDuck.Core.Utils;
|
||||||
|
|
||||||
|
namespace TweetDuck.Core.Other.Settings.Dialogs{
|
||||||
|
sealed partial class DialogSettingsCSS : Form{
|
||||||
|
public string BrowserCSS => textBoxBrowserCSS.Text;
|
||||||
|
public string NotificationCSS => textBoxNotificationCSS.Text;
|
||||||
|
|
||||||
|
private readonly Action<string> reinjectBrowserCSS;
|
||||||
|
|
||||||
|
public DialogSettingsCSS(Action<string> reinjectBrowserCSS){
|
||||||
|
InitializeComponent();
|
||||||
|
|
||||||
|
Text = Program.BrandName+" Options - CSS";
|
||||||
|
|
||||||
|
this.reinjectBrowserCSS = reinjectBrowserCSS;
|
||||||
|
|
||||||
|
textBoxBrowserCSS.EnableMultilineShortcuts();
|
||||||
|
textBoxBrowserCSS.Text = Program.UserConfig.CustomBrowserCSS ?? "";
|
||||||
|
|
||||||
|
textBoxNotificationCSS.EnableMultilineShortcuts();
|
||||||
|
textBoxNotificationCSS.Text = Program.UserConfig.CustomNotificationCSS ?? "";
|
||||||
|
}
|
||||||
|
|
||||||
|
private void textBoxBrowserCSS_KeyUp(object sender, KeyEventArgs e){
|
||||||
|
timerTestBrowser.Stop();
|
||||||
|
timerTestBrowser.Start();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void timerTestBrowser_Tick(object sender, EventArgs e){
|
||||||
|
reinjectBrowserCSS(textBoxBrowserCSS.Text);
|
||||||
|
timerTestBrowser.Stop();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void btnOpenWiki_Click(object sender, EventArgs e){
|
||||||
|
BrowserUtils.OpenExternalBrowserUnsafe("https://github.com/chylex/TweetDuck/wiki");
|
||||||
|
}
|
||||||
|
|
||||||
|
private void btnApply_Click(object sender, EventArgs e){
|
||||||
|
DialogResult = DialogResult.OK;
|
||||||
|
Close();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void btnCancel_Click(object sender, EventArgs e){
|
||||||
|
DialogResult = DialogResult.Cancel;
|
||||||
|
Close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
119
Core/Other/Settings/Dialogs/DialogSettingsCefArgs.Designer.cs
generated
Normal file
119
Core/Other/Settings/Dialogs/DialogSettingsCefArgs.Designer.cs
generated
Normal file
@@ -0,0 +1,119 @@
|
|||||||
|
namespace TweetDuck.Core.Other.Settings.Dialogs {
|
||||||
|
partial class DialogSettingsCefArgs {
|
||||||
|
/// <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.textBoxArgs = new System.Windows.Forms.TextBox();
|
||||||
|
this.btnCancel = new System.Windows.Forms.Button();
|
||||||
|
this.btnApply = new System.Windows.Forms.Button();
|
||||||
|
this.btnHelp = new System.Windows.Forms.Button();
|
||||||
|
this.labelWarning = new System.Windows.Forms.Label();
|
||||||
|
this.SuspendLayout();
|
||||||
|
//
|
||||||
|
// textBoxArgs
|
||||||
|
//
|
||||||
|
this.textBoxArgs.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom)
|
||||||
|
| System.Windows.Forms.AnchorStyles.Left)
|
||||||
|
| System.Windows.Forms.AnchorStyles.Right)));
|
||||||
|
this.textBoxArgs.Font = new System.Drawing.Font("Courier New", 8.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(238)));
|
||||||
|
this.textBoxArgs.Location = new System.Drawing.Point(12, 28);
|
||||||
|
this.textBoxArgs.Multiline = true;
|
||||||
|
this.textBoxArgs.Name = "textBoxArgs";
|
||||||
|
this.textBoxArgs.Size = new System.Drawing.Size(460, 193);
|
||||||
|
this.textBoxArgs.TabIndex = 1;
|
||||||
|
//
|
||||||
|
// btnCancel
|
||||||
|
//
|
||||||
|
this.btnCancel.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right)));
|
||||||
|
this.btnCancel.Location = new System.Drawing.Point(354, 227);
|
||||||
|
this.btnCancel.Name = "btnCancel";
|
||||||
|
this.btnCancel.Padding = new System.Windows.Forms.Padding(3, 0, 3, 0);
|
||||||
|
this.btnCancel.Size = new System.Drawing.Size(56, 23);
|
||||||
|
this.btnCancel.TabIndex = 3;
|
||||||
|
this.btnCancel.Text = "Cancel";
|
||||||
|
this.btnCancel.UseVisualStyleBackColor = true;
|
||||||
|
this.btnCancel.Click += new System.EventHandler(this.btnCancel_Click);
|
||||||
|
//
|
||||||
|
// btnApply
|
||||||
|
//
|
||||||
|
this.btnApply.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right)));
|
||||||
|
this.btnApply.Location = new System.Drawing.Point(416, 227);
|
||||||
|
this.btnApply.Name = "btnApply";
|
||||||
|
this.btnApply.Padding = new System.Windows.Forms.Padding(3, 0, 3, 0);
|
||||||
|
this.btnApply.Size = new System.Drawing.Size(56, 23);
|
||||||
|
this.btnApply.TabIndex = 2;
|
||||||
|
this.btnApply.Text = "Apply";
|
||||||
|
this.btnApply.UseVisualStyleBackColor = true;
|
||||||
|
this.btnApply.Click += new System.EventHandler(this.btnApply_Click);
|
||||||
|
//
|
||||||
|
// btnHelp
|
||||||
|
//
|
||||||
|
this.btnHelp.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left)));
|
||||||
|
this.btnHelp.Location = new System.Drawing.Point(12, 227);
|
||||||
|
this.btnHelp.Name = "btnHelp";
|
||||||
|
this.btnHelp.Padding = new System.Windows.Forms.Padding(3, 0, 3, 0);
|
||||||
|
this.btnHelp.Size = new System.Drawing.Size(124, 23);
|
||||||
|
this.btnHelp.TabIndex = 4;
|
||||||
|
this.btnHelp.Text = "List of Chromium Args";
|
||||||
|
this.btnHelp.UseVisualStyleBackColor = true;
|
||||||
|
this.btnHelp.Click += new System.EventHandler(this.btnHelp_Click);
|
||||||
|
//
|
||||||
|
// labelWarning
|
||||||
|
//
|
||||||
|
this.labelWarning.AutoSize = true;
|
||||||
|
this.labelWarning.Location = new System.Drawing.Point(12, 9);
|
||||||
|
this.labelWarning.Margin = new System.Windows.Forms.Padding(3, 0, 3, 3);
|
||||||
|
this.labelWarning.Name = "labelWarning";
|
||||||
|
this.labelWarning.Size = new System.Drawing.Size(423, 13);
|
||||||
|
this.labelWarning.TabIndex = 0;
|
||||||
|
this.labelWarning.Text = "Warning: Some arguments may cause the program to stop working, edit at your own r" +
|
||||||
|
"isk.";
|
||||||
|
//
|
||||||
|
// DialogSettingsCefArgs
|
||||||
|
//
|
||||||
|
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
|
||||||
|
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
|
||||||
|
this.ClientSize = new System.Drawing.Size(484, 262);
|
||||||
|
this.Controls.Add(this.labelWarning);
|
||||||
|
this.Controls.Add(this.btnHelp);
|
||||||
|
this.Controls.Add(this.btnApply);
|
||||||
|
this.Controls.Add(this.btnCancel);
|
||||||
|
this.Controls.Add(this.textBoxArgs);
|
||||||
|
this.MinimumSize = new System.Drawing.Size(500, 160);
|
||||||
|
this.Name = "DialogSettingsCefArgs";
|
||||||
|
this.ShowIcon = false;
|
||||||
|
this.StartPosition = System.Windows.Forms.FormStartPosition.CenterParent;
|
||||||
|
this.ResumeLayout(false);
|
||||||
|
this.PerformLayout();
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
private System.Windows.Forms.TextBox textBoxArgs;
|
||||||
|
private System.Windows.Forms.Button btnCancel;
|
||||||
|
private System.Windows.Forms.Button btnApply;
|
||||||
|
private System.Windows.Forms.Button btnHelp;
|
||||||
|
private System.Windows.Forms.Label labelWarning;
|
||||||
|
}
|
||||||
|
}
|
||||||
48
Core/Other/Settings/Dialogs/DialogSettingsCefArgs.cs
Normal file
48
Core/Other/Settings/Dialogs/DialogSettingsCefArgs.cs
Normal file
@@ -0,0 +1,48 @@
|
|||||||
|
using System;
|
||||||
|
using System.Windows.Forms;
|
||||||
|
using TweetDuck.Core.Controls;
|
||||||
|
using TweetDuck.Core.Utils;
|
||||||
|
using TweetDuck.Data;
|
||||||
|
|
||||||
|
namespace TweetDuck.Core.Other.Settings.Dialogs{
|
||||||
|
sealed partial class DialogSettingsCefArgs : Form{
|
||||||
|
public string CefArgs => textBoxArgs.Text;
|
||||||
|
|
||||||
|
public DialogSettingsCefArgs(){
|
||||||
|
InitializeComponent();
|
||||||
|
|
||||||
|
Text = Program.BrandName+" Options - CEF Arguments";
|
||||||
|
|
||||||
|
textBoxArgs.EnableMultilineShortcuts();
|
||||||
|
textBoxArgs.Text = Program.UserConfig.CustomCefArgs ?? "";
|
||||||
|
textBoxArgs.Select(textBoxArgs.Text.Length, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void btnHelp_Click(object sender, EventArgs e){
|
||||||
|
BrowserUtils.OpenExternalBrowserUnsafe("http://peter.sh/experiments/chromium-command-line-switches/");
|
||||||
|
}
|
||||||
|
|
||||||
|
private void btnApply_Click(object sender, EventArgs e){
|
||||||
|
string prevArgs = Program.UserConfig.CustomCefArgs;
|
||||||
|
|
||||||
|
if (CefArgs == prevArgs){
|
||||||
|
DialogResult = DialogResult.Cancel;
|
||||||
|
Close();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
int count = CommandLineArgs.ReadCefArguments(CefArgs).Count;
|
||||||
|
string prompt = count == 0 && !string.IsNullOrWhiteSpace(prevArgs) ? "All current arguments will be removed. Continue?" : count+(count == 1 ? " argument was" : " arguments were")+" detected. Continue?";
|
||||||
|
|
||||||
|
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();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
201
Core/Other/Settings/Dialogs/DialogSettingsManage.Designer.cs
generated
Normal file
201
Core/Other/Settings/Dialogs/DialogSettingsManage.Designer.cs
generated
Normal file
@@ -0,0 +1,201 @@
|
|||||||
|
namespace TweetDuck.Core.Other.Settings.Dialogs {
|
||||||
|
partial class DialogSettingsManage {
|
||||||
|
/// <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.components = new System.ComponentModel.Container();
|
||||||
|
this.btnCancel = new System.Windows.Forms.Button();
|
||||||
|
this.btnContinue = new System.Windows.Forms.Button();
|
||||||
|
this.cbConfig = new System.Windows.Forms.CheckBox();
|
||||||
|
this.cbSession = new System.Windows.Forms.CheckBox();
|
||||||
|
this.cbPluginData = new System.Windows.Forms.CheckBox();
|
||||||
|
this.toolTip = new System.Windows.Forms.ToolTip(this.components);
|
||||||
|
this.panelExport = new System.Windows.Forms.Panel();
|
||||||
|
this.panelDecision = new System.Windows.Forms.Panel();
|
||||||
|
this.radioReset = new System.Windows.Forms.RadioButton();
|
||||||
|
this.radioExport = new System.Windows.Forms.RadioButton();
|
||||||
|
this.radioImport = new System.Windows.Forms.RadioButton();
|
||||||
|
this.panelExport.SuspendLayout();
|
||||||
|
this.panelDecision.SuspendLayout();
|
||||||
|
this.SuspendLayout();
|
||||||
|
//
|
||||||
|
// btnCancel
|
||||||
|
//
|
||||||
|
this.btnCancel.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right)));
|
||||||
|
this.btnCancel.Location = new System.Drawing.Point(176, 97);
|
||||||
|
this.btnCancel.Name = "btnCancel";
|
||||||
|
this.btnCancel.Padding = new System.Windows.Forms.Padding(3, 0, 3, 0);
|
||||||
|
this.btnCancel.Size = new System.Drawing.Size(56, 23);
|
||||||
|
this.btnCancel.TabIndex = 4;
|
||||||
|
this.btnCancel.Text = "Cancel";
|
||||||
|
this.btnCancel.UseVisualStyleBackColor = true;
|
||||||
|
this.btnCancel.Click += new System.EventHandler(this.btnCancel_Click);
|
||||||
|
//
|
||||||
|
// btnContinue
|
||||||
|
//
|
||||||
|
this.btnContinue.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right)));
|
||||||
|
this.btnContinue.AutoSize = true;
|
||||||
|
this.btnContinue.Enabled = false;
|
||||||
|
this.btnContinue.Location = new System.Drawing.Point(125, 97);
|
||||||
|
this.btnContinue.Name = "btnContinue";
|
||||||
|
this.btnContinue.Padding = new System.Windows.Forms.Padding(3, 0, 3, 0);
|
||||||
|
this.btnContinue.Size = new System.Drawing.Size(45, 23);
|
||||||
|
this.btnContinue.TabIndex = 3;
|
||||||
|
this.btnContinue.Text = "Next";
|
||||||
|
this.btnContinue.UseVisualStyleBackColor = true;
|
||||||
|
this.btnContinue.Click += new System.EventHandler(this.btnContinue_Click);
|
||||||
|
//
|
||||||
|
// cbConfig
|
||||||
|
//
|
||||||
|
this.cbConfig.AutoSize = true;
|
||||||
|
this.cbConfig.Location = new System.Drawing.Point(0, 3);
|
||||||
|
this.cbConfig.Name = "cbConfig";
|
||||||
|
this.cbConfig.Size = new System.Drawing.Size(104, 17);
|
||||||
|
this.cbConfig.TabIndex = 0;
|
||||||
|
this.cbConfig.Text = "Program Options";
|
||||||
|
this.toolTip.SetToolTip(this.cbConfig, "Interface, notification, and update options.");
|
||||||
|
this.cbConfig.UseVisualStyleBackColor = true;
|
||||||
|
this.cbConfig.CheckedChanged += new System.EventHandler(this.cbConfig_CheckedChanged);
|
||||||
|
//
|
||||||
|
// cbSession
|
||||||
|
//
|
||||||
|
this.cbSession.AutoSize = true;
|
||||||
|
this.cbSession.Location = new System.Drawing.Point(0, 27);
|
||||||
|
this.cbSession.Name = "cbSession";
|
||||||
|
this.cbSession.Size = new System.Drawing.Size(92, 17);
|
||||||
|
this.cbSession.TabIndex = 1;
|
||||||
|
this.cbSession.Text = "Login Session";
|
||||||
|
this.toolTip.SetToolTip(this.cbSession, "A token that allows logging into the\r\ncurrent TweetDeck account.");
|
||||||
|
this.cbSession.UseVisualStyleBackColor = true;
|
||||||
|
this.cbSession.CheckedChanged += new System.EventHandler(this.cbSession_CheckedChanged);
|
||||||
|
//
|
||||||
|
// cbPluginData
|
||||||
|
//
|
||||||
|
this.cbPluginData.AutoSize = true;
|
||||||
|
this.cbPluginData.Location = new System.Drawing.Point(0, 51);
|
||||||
|
this.cbPluginData.Name = "cbPluginData";
|
||||||
|
this.cbPluginData.Size = new System.Drawing.Size(81, 17);
|
||||||
|
this.cbPluginData.TabIndex = 2;
|
||||||
|
this.cbPluginData.Text = "Plugin Data";
|
||||||
|
this.toolTip.SetToolTip(this.cbPluginData, "Data files generated by plugins.\r\nDoes not include the plugins themselves.");
|
||||||
|
this.cbPluginData.UseVisualStyleBackColor = true;
|
||||||
|
this.cbPluginData.CheckedChanged += new System.EventHandler(this.cbPluginData_CheckedChanged);
|
||||||
|
//
|
||||||
|
// panelExport
|
||||||
|
//
|
||||||
|
this.panelExport.Controls.Add(this.cbConfig);
|
||||||
|
this.panelExport.Controls.Add(this.cbPluginData);
|
||||||
|
this.panelExport.Controls.Add(this.cbSession);
|
||||||
|
this.panelExport.Location = new System.Drawing.Point(12, 12);
|
||||||
|
this.panelExport.Name = "panelExport";
|
||||||
|
this.panelExport.Size = new System.Drawing.Size(220, 79);
|
||||||
|
this.panelExport.TabIndex = 5;
|
||||||
|
this.panelExport.Visible = false;
|
||||||
|
//
|
||||||
|
// panelDecision
|
||||||
|
//
|
||||||
|
this.panelDecision.Controls.Add(this.radioReset);
|
||||||
|
this.panelDecision.Controls.Add(this.radioExport);
|
||||||
|
this.panelDecision.Controls.Add(this.radioImport);
|
||||||
|
this.panelDecision.Location = new System.Drawing.Point(12, 12);
|
||||||
|
this.panelDecision.Name = "panelDecision";
|
||||||
|
this.panelDecision.Size = new System.Drawing.Size(220, 79);
|
||||||
|
this.panelDecision.TabIndex = 6;
|
||||||
|
//
|
||||||
|
// radioReset
|
||||||
|
//
|
||||||
|
this.radioReset.AutoSize = true;
|
||||||
|
this.radioReset.Location = new System.Drawing.Point(3, 49);
|
||||||
|
this.radioReset.Name = "radioReset";
|
||||||
|
this.radioReset.Size = new System.Drawing.Size(104, 17);
|
||||||
|
this.radioReset.TabIndex = 2;
|
||||||
|
this.radioReset.TabStop = true;
|
||||||
|
this.radioReset.Text = "Restore Defaults";
|
||||||
|
this.radioReset.UseVisualStyleBackColor = true;
|
||||||
|
this.radioReset.CheckedChanged += new System.EventHandler(this.radioDecision_CheckedChanged);
|
||||||
|
//
|
||||||
|
// radioExport
|
||||||
|
//
|
||||||
|
this.radioExport.AutoSize = true;
|
||||||
|
this.radioExport.Location = new System.Drawing.Point(3, 26);
|
||||||
|
this.radioExport.Name = "radioExport";
|
||||||
|
this.radioExport.Size = new System.Drawing.Size(87, 17);
|
||||||
|
this.radioExport.TabIndex = 1;
|
||||||
|
this.radioExport.TabStop = true;
|
||||||
|
this.radioExport.Text = "Export Profile";
|
||||||
|
this.radioExport.UseVisualStyleBackColor = true;
|
||||||
|
this.radioExport.CheckedChanged += new System.EventHandler(this.radioDecision_CheckedChanged);
|
||||||
|
//
|
||||||
|
// radioImport
|
||||||
|
//
|
||||||
|
this.radioImport.AutoSize = true;
|
||||||
|
this.radioImport.Location = new System.Drawing.Point(3, 3);
|
||||||
|
this.radioImport.Name = "radioImport";
|
||||||
|
this.radioImport.Size = new System.Drawing.Size(86, 17);
|
||||||
|
this.radioImport.TabIndex = 0;
|
||||||
|
this.radioImport.TabStop = true;
|
||||||
|
this.radioImport.Text = "Import Profile";
|
||||||
|
this.radioImport.UseVisualStyleBackColor = true;
|
||||||
|
this.radioImport.CheckedChanged += new System.EventHandler(this.radioDecision_CheckedChanged);
|
||||||
|
//
|
||||||
|
// DialogSettingsManage
|
||||||
|
//
|
||||||
|
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
|
||||||
|
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
|
||||||
|
this.ClientSize = new System.Drawing.Size(244, 132);
|
||||||
|
this.Controls.Add(this.panelDecision);
|
||||||
|
this.Controls.Add(this.panelExport);
|
||||||
|
this.Controls.Add(this.btnContinue);
|
||||||
|
this.Controls.Add(this.btnCancel);
|
||||||
|
this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedSingle;
|
||||||
|
this.MaximizeBox = false;
|
||||||
|
this.MinimizeBox = false;
|
||||||
|
this.MinimumSize = new System.Drawing.Size(200, 170);
|
||||||
|
this.Name = "DialogSettingsManage";
|
||||||
|
this.ShowIcon = false;
|
||||||
|
this.StartPosition = System.Windows.Forms.FormStartPosition.CenterParent;
|
||||||
|
this.Text = "Manage Options";
|
||||||
|
this.panelExport.ResumeLayout(false);
|
||||||
|
this.panelExport.PerformLayout();
|
||||||
|
this.panelDecision.ResumeLayout(false);
|
||||||
|
this.panelDecision.PerformLayout();
|
||||||
|
this.ResumeLayout(false);
|
||||||
|
this.PerformLayout();
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
private System.Windows.Forms.Button btnCancel;
|
||||||
|
private System.Windows.Forms.Button btnContinue;
|
||||||
|
private System.Windows.Forms.CheckBox cbConfig;
|
||||||
|
private System.Windows.Forms.CheckBox cbSession;
|
||||||
|
private System.Windows.Forms.CheckBox cbPluginData;
|
||||||
|
private System.Windows.Forms.ToolTip toolTip;
|
||||||
|
private System.Windows.Forms.Panel panelExport;
|
||||||
|
private System.Windows.Forms.Panel panelDecision;
|
||||||
|
private System.Windows.Forms.RadioButton radioReset;
|
||||||
|
private System.Windows.Forms.RadioButton radioExport;
|
||||||
|
private System.Windows.Forms.RadioButton radioImport;
|
||||||
|
}
|
||||||
|
}
|
||||||
170
Core/Other/Settings/Dialogs/DialogSettingsManage.cs
Normal file
170
Core/Other/Settings/Dialogs/DialogSettingsManage.cs
Normal file
@@ -0,0 +1,170 @@
|
|||||||
|
using System;
|
||||||
|
using System.Windows.Forms;
|
||||||
|
using TweetDuck.Core.Other.Settings.Export;
|
||||||
|
using TweetDuck.Plugins;
|
||||||
|
|
||||||
|
namespace TweetDuck.Core.Other.Settings.Dialogs{
|
||||||
|
sealed partial class DialogSettingsManage : Form{
|
||||||
|
private enum State{
|
||||||
|
Deciding, Import, Export
|
||||||
|
}
|
||||||
|
|
||||||
|
public ExportFileFlags Flags{
|
||||||
|
get => selectedFlags;
|
||||||
|
|
||||||
|
set{
|
||||||
|
// this will call events and SetFlag, which also updates the UI
|
||||||
|
cbConfig.Checked = value.HasFlag(ExportFileFlags.Config);
|
||||||
|
cbSession.Checked = value.HasFlag(ExportFileFlags.Session);
|
||||||
|
cbPluginData.Checked = value.HasFlag(ExportFileFlags.PluginData);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool ShouldReloadUI { get; private set; }
|
||||||
|
|
||||||
|
private readonly PluginManager plugins;
|
||||||
|
private State currentState;
|
||||||
|
|
||||||
|
private ExportManager importManager;
|
||||||
|
private ExportFileFlags selectedFlags = ExportFileFlags.None;
|
||||||
|
|
||||||
|
public DialogSettingsManage(PluginManager plugins){
|
||||||
|
InitializeComponent();
|
||||||
|
|
||||||
|
this.plugins = plugins;
|
||||||
|
this.currentState = State.Deciding;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void radioDecision_CheckedChanged(object sender, EventArgs e){
|
||||||
|
btnContinue.Enabled = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void cbConfig_CheckedChanged(object sender, EventArgs e){
|
||||||
|
SetFlag(ExportFileFlags.Config, cbConfig.Checked);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void cbSession_CheckedChanged(object sender, EventArgs e){
|
||||||
|
SetFlag(ExportFileFlags.Session, cbSession.Checked);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void cbPluginData_CheckedChanged(object sender, EventArgs e){
|
||||||
|
SetFlag(ExportFileFlags.PluginData, cbPluginData.Checked);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void btnContinue_Click(object sender, EventArgs e){
|
||||||
|
string file;
|
||||||
|
|
||||||
|
switch(currentState){
|
||||||
|
case State.Deciding:
|
||||||
|
// Reset
|
||||||
|
if (radioReset.Checked){
|
||||||
|
if (FormMessage.Warning("Reset TweetDuck Options", "This will reset all of your program options. Plugins will not be affected. Do you want to proceed?", FormMessage.Yes, FormMessage.No)){
|
||||||
|
Program.ResetConfig();
|
||||||
|
|
||||||
|
ShouldReloadUI = true;
|
||||||
|
DialogResult = DialogResult.OK;
|
||||||
|
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){
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
file = dialog.FileName;
|
||||||
|
}
|
||||||
|
|
||||||
|
importManager = new ExportManager(file, plugins);
|
||||||
|
currentState = State.Import;
|
||||||
|
|
||||||
|
Text = "Import Profile";
|
||||||
|
Flags = importManager.GetImportFlags();
|
||||||
|
|
||||||
|
cbConfig.Enabled = cbConfig.Checked;
|
||||||
|
cbSession.Enabled = cbSession.Checked;
|
||||||
|
cbPluginData.Enabled = cbPluginData.Checked;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Export
|
||||||
|
else if (radioExport.Checked){
|
||||||
|
currentState = State.Export;
|
||||||
|
|
||||||
|
Text = "Export Profile";
|
||||||
|
btnContinue.Text = "Export Profile";
|
||||||
|
Flags = ExportFileFlags.All & ~ExportFileFlags.Session;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Continue...
|
||||||
|
panelDecision.Visible = false;
|
||||||
|
panelExport.Visible = true;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case State.Import:
|
||||||
|
if (importManager.Import(Flags)){
|
||||||
|
if (!importManager.IsRestarting){
|
||||||
|
ShouldReloadUI = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
Program.Reporter.HandleException("Profile Import Error", "An exception happened while importing TweetDuck profile.", true, importManager.LastException);
|
||||||
|
}
|
||||||
|
|
||||||
|
DialogResult = DialogResult.OK;
|
||||||
|
Close();
|
||||||
|
break;
|
||||||
|
|
||||||
|
case State.Export:
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
Program.UserConfig.Save();
|
||||||
|
ExportManager manager = new ExportManager(file, plugins);
|
||||||
|
|
||||||
|
if (!manager.Export(Flags)){
|
||||||
|
Program.Reporter.HandleException("Profile Export Error", "An exception happened while exporting TweetDuck profile.", true, manager.LastException);
|
||||||
|
}
|
||||||
|
|
||||||
|
DialogResult = DialogResult.OK;
|
||||||
|
Close();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void btnCancel_Click(object sender, EventArgs e){
|
||||||
|
DialogResult = DialogResult.Cancel;
|
||||||
|
Close();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void SetFlag(ExportFileFlags flag, bool enable){
|
||||||
|
selectedFlags = enable ? selectedFlags | flag : selectedFlags & ~flag;
|
||||||
|
btnContinue.Enabled = selectedFlags != ExportFileFlags.None;
|
||||||
|
|
||||||
|
if (currentState == State.Import){
|
||||||
|
btnContinue.Text = selectedFlags.HasFlag(ExportFileFlags.Session) ? "Import && Restart" : "Import Profile";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
159
Core/Other/Settings/Dialogs/DialogSettingsRestart.Designer.cs
generated
Normal file
159
Core/Other/Settings/Dialogs/DialogSettingsRestart.Designer.cs
generated
Normal file
@@ -0,0 +1,159 @@
|
|||||||
|
namespace TweetDuck.Core.Other.Settings.Dialogs {
|
||||||
|
partial class DialogSettingsRestart {
|
||||||
|
/// <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.components = new System.ComponentModel.Container();
|
||||||
|
this.btnCancel = new System.Windows.Forms.Button();
|
||||||
|
this.btnRestart = new System.Windows.Forms.Button();
|
||||||
|
this.cbLogging = new System.Windows.Forms.CheckBox();
|
||||||
|
this.toolTip = new System.Windows.Forms.ToolTip(this.components);
|
||||||
|
this.cbDebugUpdates = new System.Windows.Forms.CheckBox();
|
||||||
|
this.labelLocale = new System.Windows.Forms.Label();
|
||||||
|
this.comboLocale = new System.Windows.Forms.ComboBox();
|
||||||
|
this.labelDataFolder = new System.Windows.Forms.Label();
|
||||||
|
this.tbDataFolder = new System.Windows.Forms.TextBox();
|
||||||
|
this.SuspendLayout();
|
||||||
|
//
|
||||||
|
// btnCancel
|
||||||
|
//
|
||||||
|
this.btnCancel.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right)));
|
||||||
|
this.btnCancel.Location = new System.Drawing.Point(160, 171);
|
||||||
|
this.btnCancel.Name = "btnCancel";
|
||||||
|
this.btnCancel.Padding = new System.Windows.Forms.Padding(3, 0, 3, 0);
|
||||||
|
this.btnCancel.Size = new System.Drawing.Size(56, 23);
|
||||||
|
this.btnCancel.TabIndex = 7;
|
||||||
|
this.btnCancel.Text = "Cancel";
|
||||||
|
this.btnCancel.UseVisualStyleBackColor = true;
|
||||||
|
this.btnCancel.Click += new System.EventHandler(this.btnCancel_Click);
|
||||||
|
//
|
||||||
|
// btnRestart
|
||||||
|
//
|
||||||
|
this.btnRestart.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right)));
|
||||||
|
this.btnRestart.Location = new System.Drawing.Point(97, 171);
|
||||||
|
this.btnRestart.Name = "btnRestart";
|
||||||
|
this.btnRestart.Padding = new System.Windows.Forms.Padding(3, 0, 3, 0);
|
||||||
|
this.btnRestart.Size = new System.Drawing.Size(57, 23);
|
||||||
|
this.btnRestart.TabIndex = 6;
|
||||||
|
this.btnRestart.Text = "Restart";
|
||||||
|
this.btnRestart.UseVisualStyleBackColor = true;
|
||||||
|
this.btnRestart.Click += new System.EventHandler(this.btnRestart_Click);
|
||||||
|
//
|
||||||
|
// cbLogging
|
||||||
|
//
|
||||||
|
this.cbLogging.AutoSize = true;
|
||||||
|
this.cbLogging.Location = new System.Drawing.Point(12, 12);
|
||||||
|
this.cbLogging.Name = "cbLogging";
|
||||||
|
this.cbLogging.Size = new System.Drawing.Size(64, 17);
|
||||||
|
this.cbLogging.TabIndex = 0;
|
||||||
|
this.cbLogging.Text = "Logging";
|
||||||
|
this.toolTip.SetToolTip(this.cbLogging, "Logging JavaScript output into a\r\ndebug.txt file in the data folder.");
|
||||||
|
this.cbLogging.UseVisualStyleBackColor = true;
|
||||||
|
//
|
||||||
|
// cbDebugUpdates
|
||||||
|
//
|
||||||
|
this.cbDebugUpdates.AutoSize = true;
|
||||||
|
this.cbDebugUpdates.Location = new System.Drawing.Point(12, 35);
|
||||||
|
this.cbDebugUpdates.Name = "cbDebugUpdates";
|
||||||
|
this.cbDebugUpdates.Size = new System.Drawing.Size(127, 17);
|
||||||
|
this.cbDebugUpdates.TabIndex = 1;
|
||||||
|
this.cbDebugUpdates.Text = "Pre-Release Updates";
|
||||||
|
this.toolTip.SetToolTip(this.cbDebugUpdates, "Allows updating to pre-releases.");
|
||||||
|
this.cbDebugUpdates.UseVisualStyleBackColor = true;
|
||||||
|
//
|
||||||
|
// labelLocale
|
||||||
|
//
|
||||||
|
this.labelLocale.AutoSize = true;
|
||||||
|
this.labelLocale.Location = new System.Drawing.Point(12, 67);
|
||||||
|
this.labelLocale.Margin = new System.Windows.Forms.Padding(3, 12, 3, 0);
|
||||||
|
this.labelLocale.Name = "labelLocale";
|
||||||
|
this.labelLocale.Size = new System.Drawing.Size(39, 13);
|
||||||
|
this.labelLocale.TabIndex = 2;
|
||||||
|
this.labelLocale.Text = "Locale";
|
||||||
|
//
|
||||||
|
// comboLocale
|
||||||
|
//
|
||||||
|
this.comboLocale.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left)
|
||||||
|
| System.Windows.Forms.AnchorStyles.Right)));
|
||||||
|
this.comboLocale.FormattingEnabled = true;
|
||||||
|
this.comboLocale.Location = new System.Drawing.Point(15, 83);
|
||||||
|
this.comboLocale.Name = "comboLocale";
|
||||||
|
this.comboLocale.Size = new System.Drawing.Size(201, 21);
|
||||||
|
this.comboLocale.TabIndex = 3;
|
||||||
|
//
|
||||||
|
// labelDataFolder
|
||||||
|
//
|
||||||
|
this.labelDataFolder.AutoSize = true;
|
||||||
|
this.labelDataFolder.Location = new System.Drawing.Point(12, 119);
|
||||||
|
this.labelDataFolder.Margin = new System.Windows.Forms.Padding(3, 12, 3, 0);
|
||||||
|
this.labelDataFolder.Name = "labelDataFolder";
|
||||||
|
this.labelDataFolder.Size = new System.Drawing.Size(62, 13);
|
||||||
|
this.labelDataFolder.TabIndex = 4;
|
||||||
|
this.labelDataFolder.Text = "Data Folder";
|
||||||
|
//
|
||||||
|
// tbDataFolder
|
||||||
|
//
|
||||||
|
this.tbDataFolder.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left)
|
||||||
|
| System.Windows.Forms.AnchorStyles.Right)));
|
||||||
|
this.tbDataFolder.Location = new System.Drawing.Point(15, 135);
|
||||||
|
this.tbDataFolder.Name = "tbDataFolder";
|
||||||
|
this.tbDataFolder.Size = new System.Drawing.Size(201, 20);
|
||||||
|
this.tbDataFolder.TabIndex = 5;
|
||||||
|
//
|
||||||
|
// DialogSettingsRestart
|
||||||
|
//
|
||||||
|
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
|
||||||
|
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
|
||||||
|
this.ClientSize = new System.Drawing.Size(228, 206);
|
||||||
|
this.Controls.Add(this.tbDataFolder);
|
||||||
|
this.Controls.Add(this.labelDataFolder);
|
||||||
|
this.Controls.Add(this.comboLocale);
|
||||||
|
this.Controls.Add(this.labelLocale);
|
||||||
|
this.Controls.Add(this.cbDebugUpdates);
|
||||||
|
this.Controls.Add(this.cbLogging);
|
||||||
|
this.Controls.Add(this.btnRestart);
|
||||||
|
this.Controls.Add(this.btnCancel);
|
||||||
|
this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedSingle;
|
||||||
|
this.MaximizeBox = false;
|
||||||
|
this.MinimizeBox = false;
|
||||||
|
this.Name = "DialogSettingsRestart";
|
||||||
|
this.ShowIcon = false;
|
||||||
|
this.StartPosition = System.Windows.Forms.FormStartPosition.CenterParent;
|
||||||
|
this.ResumeLayout(false);
|
||||||
|
this.PerformLayout();
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
private System.Windows.Forms.Button btnCancel;
|
||||||
|
private System.Windows.Forms.Button btnRestart;
|
||||||
|
private System.Windows.Forms.CheckBox cbLogging;
|
||||||
|
private System.Windows.Forms.ToolTip toolTip;
|
||||||
|
private System.Windows.Forms.CheckBox cbDebugUpdates;
|
||||||
|
private System.Windows.Forms.Label labelLocale;
|
||||||
|
private System.Windows.Forms.ComboBox comboLocale;
|
||||||
|
private System.Windows.Forms.Label labelDataFolder;
|
||||||
|
private System.Windows.Forms.TextBox tbDataFolder;
|
||||||
|
}
|
||||||
|
}
|
||||||
62
Core/Other/Settings/Dialogs/DialogSettingsRestart.cs
Normal file
62
Core/Other/Settings/Dialogs/DialogSettingsRestart.cs
Normal file
@@ -0,0 +1,62 @@
|
|||||||
|
using System;
|
||||||
|
using System.IO;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Windows.Forms;
|
||||||
|
using TweetDuck.Configuration;
|
||||||
|
using TweetDuck.Data;
|
||||||
|
|
||||||
|
namespace TweetDuck.Core.Other.Settings.Dialogs{
|
||||||
|
sealed partial class DialogSettingsRestart : Form{
|
||||||
|
private const string DefaultLocale = "en-US";
|
||||||
|
|
||||||
|
public CommandLineArgs Args { get; private set; }
|
||||||
|
|
||||||
|
public DialogSettingsRestart(CommandLineArgs currentArgs){
|
||||||
|
InitializeComponent();
|
||||||
|
|
||||||
|
try{
|
||||||
|
object[] locales = Directory.EnumerateFiles(Path.Combine(Program.ProgramPath, "locales"), "*.pak", SearchOption.TopDirectoryOnly).Select(Path.GetFileNameWithoutExtension).ToArray<object>();
|
||||||
|
comboLocale.Items.AddRange(locales);
|
||||||
|
}catch{
|
||||||
|
comboLocale.Items.Add(DefaultLocale);
|
||||||
|
}
|
||||||
|
|
||||||
|
cbLogging.Checked = currentArgs.HasFlag(Arguments.ArgLogging);
|
||||||
|
cbDebugUpdates.Checked = currentArgs.HasFlag(Arguments.ArgDebugUpdates);
|
||||||
|
comboLocale.SelectedItem = currentArgs.GetValue(Arguments.ArgLocale, DefaultLocale);
|
||||||
|
tbDataFolder.Text = currentArgs.GetValue(Arguments.ArgDataFolder, string.Empty);
|
||||||
|
|
||||||
|
Text = Program.BrandName+" Arguments";
|
||||||
|
}
|
||||||
|
|
||||||
|
private void btnRestart_Click(object sender, EventArgs e){
|
||||||
|
Args = new CommandLineArgs();
|
||||||
|
|
||||||
|
if (cbLogging.Checked){
|
||||||
|
Args.AddFlag(Arguments.ArgLogging);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (cbDebugUpdates.Checked){
|
||||||
|
Args.AddFlag(Arguments.ArgDebugUpdates);
|
||||||
|
}
|
||||||
|
|
||||||
|
string locale = comboLocale.SelectedItem as string;
|
||||||
|
|
||||||
|
if (!string.IsNullOrWhiteSpace(locale) && locale != DefaultLocale){
|
||||||
|
Args.SetValue(Arguments.ArgLocale, locale);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!string.IsNullOrWhiteSpace(tbDataFolder.Text)){
|
||||||
|
Args.SetValue(Arguments.ArgDataFolder, tbDataFolder.Text);
|
||||||
|
}
|
||||||
|
|
||||||
|
DialogResult = DialogResult.OK;
|
||||||
|
Close();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void btnCancel_Click(object sender, EventArgs e){
|
||||||
|
DialogResult = DialogResult.Cancel;
|
||||||
|
Close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
12
Core/Other/Settings/Export/ExportFileFlags.cs
Normal file
12
Core/Other/Settings/Export/ExportFileFlags.cs
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
using System;
|
||||||
|
|
||||||
|
namespace TweetDuck.Core.Other.Settings.Export{
|
||||||
|
[Flags]
|
||||||
|
enum ExportFileFlags{
|
||||||
|
None = 0,
|
||||||
|
Config = 1,
|
||||||
|
Session = 2,
|
||||||
|
PluginData = 4,
|
||||||
|
All = Config|Session|PluginData
|
||||||
|
}
|
||||||
|
}
|
||||||
184
Core/Other/Settings/Export/ExportManager.cs
Normal file
184
Core/Other/Settings/Export/ExportManager.cs
Normal file
@@ -0,0 +1,184 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.IO;
|
||||||
|
using System.Linq;
|
||||||
|
using TweetDuck.Configuration;
|
||||||
|
using TweetDuck.Data;
|
||||||
|
using TweetDuck.Plugins;
|
||||||
|
using TweetDuck.Plugins.Enums;
|
||||||
|
|
||||||
|
namespace TweetDuck.Core.Other.Settings.Export{
|
||||||
|
sealed class ExportManager{
|
||||||
|
private static readonly string CookiesPath = Path.Combine(Program.StoragePath, "Cookies");
|
||||||
|
private static readonly string TempCookiesPath = Path.Combine(Program.StoragePath, "CookiesTmp");
|
||||||
|
|
||||||
|
public bool IsRestarting { get; private set; }
|
||||||
|
public Exception LastException { get; private set; }
|
||||||
|
|
||||||
|
private readonly string file;
|
||||||
|
private readonly PluginManager plugins;
|
||||||
|
|
||||||
|
public ExportManager(string file, PluginManager plugins){
|
||||||
|
this.file = file;
|
||||||
|
this.plugins = plugins;
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool Export(ExportFileFlags flags){
|
||||||
|
try{
|
||||||
|
using(CombinedFileStream stream = new CombinedFileStream(new FileStream(file, FileMode.Create, FileAccess.Write, FileShare.None))){
|
||||||
|
if (flags.HasFlag(ExportFileFlags.Config)){
|
||||||
|
stream.WriteFile("config", Program.UserConfigFilePath);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (flags.HasFlag(ExportFileFlags.PluginData)){
|
||||||
|
stream.WriteFile("plugin.config", Program.PluginConfigFilePath);
|
||||||
|
|
||||||
|
foreach(Plugin plugin in plugins.Plugins){
|
||||||
|
foreach(PathInfo path in EnumerateFilesRelative(plugin.GetPluginFolder(PluginFolder.Data))){
|
||||||
|
try{
|
||||||
|
stream.WriteFile(new string[]{ "plugin.data", plugin.Identifier, path.Relative }, path.Full);
|
||||||
|
}catch(ArgumentOutOfRangeException e){
|
||||||
|
FormMessage.Warning("Export Profile", "Could not include a plugin file in the export. "+e.Message, FormMessage.OK);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (flags.HasFlag(ExportFileFlags.Session)){
|
||||||
|
stream.WriteFile("cookies", CookiesPath);
|
||||||
|
}
|
||||||
|
|
||||||
|
stream.Flush();
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}catch(Exception e){
|
||||||
|
LastException = e;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public ExportFileFlags GetImportFlags(){
|
||||||
|
ExportFileFlags flags = ExportFileFlags.None;
|
||||||
|
|
||||||
|
try{
|
||||||
|
using(CombinedFileStream stream = new CombinedFileStream(new FileStream(file, FileMode.Open, FileAccess.Read, FileShare.None))){
|
||||||
|
string key;
|
||||||
|
|
||||||
|
while((key = stream.SkipFile()) != null){
|
||||||
|
switch(key){
|
||||||
|
case "config":
|
||||||
|
flags |= ExportFileFlags.Config;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case "plugin.config":
|
||||||
|
case "plugin.data":
|
||||||
|
flags |= ExportFileFlags.PluginData;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case "cookies":
|
||||||
|
flags |= ExportFileFlags.Session;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}catch(Exception e){
|
||||||
|
LastException = e;
|
||||||
|
flags = ExportFileFlags.None;
|
||||||
|
}
|
||||||
|
|
||||||
|
return flags;
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool Import(ExportFileFlags flags){
|
||||||
|
try{
|
||||||
|
HashSet<string> missingPlugins = new HashSet<string>();
|
||||||
|
|
||||||
|
using(CombinedFileStream stream = new CombinedFileStream(new FileStream(file, FileMode.Open, FileAccess.Read, FileShare.None))){
|
||||||
|
CombinedFileStream.Entry entry;
|
||||||
|
|
||||||
|
while((entry = stream.ReadFile()) != null){
|
||||||
|
switch(entry.KeyName){
|
||||||
|
case "config":
|
||||||
|
if (flags.HasFlag(ExportFileFlags.Config)){
|
||||||
|
entry.WriteToFile(Program.UserConfigFilePath);
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
|
||||||
|
case "plugin.config":
|
||||||
|
if (flags.HasFlag(ExportFileFlags.PluginData)){
|
||||||
|
entry.WriteToFile(Program.PluginConfigFilePath);
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
|
||||||
|
case "plugin.data":
|
||||||
|
if (flags.HasFlag(ExportFileFlags.PluginData)){
|
||||||
|
string[] value = entry.KeyValue;
|
||||||
|
|
||||||
|
entry.WriteToFile(Path.Combine(Program.PluginDataPath, value[0], value[1]), true);
|
||||||
|
|
||||||
|
if (!plugins.IsPluginInstalled(value[0])){
|
||||||
|
missingPlugins.Add(value[0]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
|
||||||
|
case "cookies":
|
||||||
|
if (flags.HasFlag(ExportFileFlags.Session)){
|
||||||
|
entry.WriteToFile(Path.Combine(Program.StoragePath, TempCookiesPath));
|
||||||
|
IsRestarting = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (missingPlugins.Count > 0){
|
||||||
|
FormMessage.Information("Importing TweetDuck Profile", "Detected missing plugins when importing plugin data:\n"+string.Join("\n", missingPlugins), FormMessage.OK);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (IsRestarting){
|
||||||
|
Program.Restart(Arguments.ArgImportCookies);
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
Program.ReloadConfig();
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}catch(Exception e){
|
||||||
|
LastException = e;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void ImportCookies(){
|
||||||
|
if (File.Exists(TempCookiesPath)){
|
||||||
|
try{
|
||||||
|
if (File.Exists(CookiesPath)){
|
||||||
|
File.Delete(CookiesPath);
|
||||||
|
}
|
||||||
|
|
||||||
|
File.Move(TempCookiesPath, CookiesPath);
|
||||||
|
}catch(Exception e){
|
||||||
|
Program.Reporter.HandleException("Profile Import Error", "Could not import the cookie file to restore login session.", true, e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static IEnumerable<PathInfo> EnumerateFilesRelative(string root){
|
||||||
|
return Directory.Exists(root) ? Directory.EnumerateFiles(root, "*.*", SearchOption.AllDirectories).Select(fullPath => new PathInfo{
|
||||||
|
Full = fullPath,
|
||||||
|
Relative = fullPath.Substring(root.Length).TrimStart(Path.DirectorySeparatorChar, Path.AltDirectorySeparatorChar) // strip leading separator character
|
||||||
|
}) : Enumerable.Empty<PathInfo>();
|
||||||
|
}
|
||||||
|
|
||||||
|
private class PathInfo{
|
||||||
|
public string Full { get; set; }
|
||||||
|
public string Relative { get; set; }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
290
Core/Other/Settings/TabSettingsAdvanced.Designer.cs
generated
Normal file
290
Core/Other/Settings/TabSettingsAdvanced.Designer.cs
generated
Normal file
@@ -0,0 +1,290 @@
|
|||||||
|
namespace TweetDuck.Core.Other.Settings {
|
||||||
|
partial class TabSettingsAdvanced {
|
||||||
|
/// <summary>
|
||||||
|
/// Required designer variable.
|
||||||
|
/// </summary>
|
||||||
|
private System.ComponentModel.IContainer components = null;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Clean up any resources being used.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
|
||||||
|
protected override void Dispose(bool disposing) {
|
||||||
|
if (disposing && (components != null)) {
|
||||||
|
components.Dispose();
|
||||||
|
}
|
||||||
|
base.Dispose(disposing);
|
||||||
|
}
|
||||||
|
|
||||||
|
#region Component Designer generated code
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Required method for Designer support - do not modify
|
||||||
|
/// the contents of this method with the code editor.
|
||||||
|
/// </summary>
|
||||||
|
private void InitializeComponent() {
|
||||||
|
this.components = new System.ComponentModel.Container();
|
||||||
|
this.btnClearCache = new System.Windows.Forms.Button();
|
||||||
|
this.checkHardwareAcceleration = new System.Windows.Forms.CheckBox();
|
||||||
|
this.toolTip = new System.Windows.Forms.ToolTip(this.components);
|
||||||
|
this.btnEditCefArgs = new System.Windows.Forms.Button();
|
||||||
|
this.btnEditCSS = new System.Windows.Forms.Button();
|
||||||
|
this.btnRestartArgs = new System.Windows.Forms.Button();
|
||||||
|
this.btnRestart = new System.Windows.Forms.Button();
|
||||||
|
this.btnOpenAppFolder = new System.Windows.Forms.Button();
|
||||||
|
this.btnOpenDataFolder = new System.Windows.Forms.Button();
|
||||||
|
this.numMemoryThreshold = new TweetDuck.Core.Controls.NumericUpDownEx();
|
||||||
|
this.checkBrowserGCReload = new System.Windows.Forms.CheckBox();
|
||||||
|
this.labelApp = new System.Windows.Forms.Label();
|
||||||
|
this.panelApp = new System.Windows.Forms.Panel();
|
||||||
|
this.labelPerformance = new System.Windows.Forms.Label();
|
||||||
|
this.panelPerformance = new System.Windows.Forms.Panel();
|
||||||
|
this.labelMemoryUsage = new System.Windows.Forms.Label();
|
||||||
|
this.panelConfiguration = new System.Windows.Forms.Panel();
|
||||||
|
this.labelConfiguration = new System.Windows.Forms.Label();
|
||||||
|
((System.ComponentModel.ISupportInitialize)(this.numMemoryThreshold)).BeginInit();
|
||||||
|
this.panelApp.SuspendLayout();
|
||||||
|
this.panelPerformance.SuspendLayout();
|
||||||
|
this.panelConfiguration.SuspendLayout();
|
||||||
|
this.SuspendLayout();
|
||||||
|
//
|
||||||
|
// btnClearCache
|
||||||
|
//
|
||||||
|
this.btnClearCache.Location = new System.Drawing.Point(5, 28);
|
||||||
|
this.btnClearCache.Margin = new System.Windows.Forms.Padding(5, 3, 3, 3);
|
||||||
|
this.btnClearCache.Name = "btnClearCache";
|
||||||
|
this.btnClearCache.Size = new System.Drawing.Size(144, 23);
|
||||||
|
this.btnClearCache.TabIndex = 1;
|
||||||
|
this.btnClearCache.Text = "Clear Cache (calculating)";
|
||||||
|
this.toolTip.SetToolTip(this.btnClearCache, "Clearing cache will free up space taken by downloaded images and other resources.");
|
||||||
|
this.btnClearCache.UseVisualStyleBackColor = true;
|
||||||
|
//
|
||||||
|
// checkHardwareAcceleration
|
||||||
|
//
|
||||||
|
this.checkHardwareAcceleration.AutoSize = true;
|
||||||
|
this.checkHardwareAcceleration.Location = new System.Drawing.Point(6, 5);
|
||||||
|
this.checkHardwareAcceleration.Margin = new System.Windows.Forms.Padding(6, 5, 3, 3);
|
||||||
|
this.checkHardwareAcceleration.Name = "checkHardwareAcceleration";
|
||||||
|
this.checkHardwareAcceleration.Size = new System.Drawing.Size(134, 17);
|
||||||
|
this.checkHardwareAcceleration.TabIndex = 0;
|
||||||
|
this.checkHardwareAcceleration.Text = "Hardware Acceleration";
|
||||||
|
this.toolTip.SetToolTip(this.checkHardwareAcceleration, "Uses graphics card to improve performance. Disable if you experience\r\nvisual glitches. This option will not be exported in a profile.");
|
||||||
|
this.checkHardwareAcceleration.UseVisualStyleBackColor = true;
|
||||||
|
//
|
||||||
|
// btnEditCefArgs
|
||||||
|
//
|
||||||
|
this.btnEditCefArgs.Location = new System.Drawing.Point(5, 3);
|
||||||
|
this.btnEditCefArgs.Margin = new System.Windows.Forms.Padding(5, 3, 3, 3);
|
||||||
|
this.btnEditCefArgs.Name = "btnEditCefArgs";
|
||||||
|
this.btnEditCefArgs.Size = new System.Drawing.Size(144, 23);
|
||||||
|
this.btnEditCefArgs.TabIndex = 0;
|
||||||
|
this.btnEditCefArgs.Text = "Edit CEF Arguments";
|
||||||
|
this.toolTip.SetToolTip(this.btnEditCefArgs, "Set custom command line arguments for Chromium Embedded Framework.");
|
||||||
|
this.btnEditCefArgs.UseVisualStyleBackColor = true;
|
||||||
|
//
|
||||||
|
// btnEditCSS
|
||||||
|
//
|
||||||
|
this.btnEditCSS.Location = new System.Drawing.Point(155, 3);
|
||||||
|
this.btnEditCSS.Name = "btnEditCSS";
|
||||||
|
this.btnEditCSS.Size = new System.Drawing.Size(144, 23);
|
||||||
|
this.btnEditCSS.TabIndex = 1;
|
||||||
|
this.btnEditCSS.Text = "Edit CSS";
|
||||||
|
this.toolTip.SetToolTip(this.btnEditCSS, "Set custom CSS for browser and notification windows.");
|
||||||
|
this.btnEditCSS.UseVisualStyleBackColor = true;
|
||||||
|
//
|
||||||
|
// btnRestartArgs
|
||||||
|
//
|
||||||
|
this.btnRestartArgs.Location = new System.Drawing.Point(155, 32);
|
||||||
|
this.btnRestartArgs.Name = "btnRestartArgs";
|
||||||
|
this.btnRestartArgs.Size = new System.Drawing.Size(144, 23);
|
||||||
|
this.btnRestartArgs.TabIndex = 3;
|
||||||
|
this.btnRestartArgs.Text = "Restart with Arguments";
|
||||||
|
this.toolTip.SetToolTip(this.btnRestartArgs, "Restarts the program with customizable\r\ncommand line arguments.");
|
||||||
|
this.btnRestartArgs.UseVisualStyleBackColor = true;
|
||||||
|
//
|
||||||
|
// btnRestart
|
||||||
|
//
|
||||||
|
this.btnRestart.Location = new System.Drawing.Point(155, 3);
|
||||||
|
this.btnRestart.Name = "btnRestart";
|
||||||
|
this.btnRestart.Size = new System.Drawing.Size(144, 23);
|
||||||
|
this.btnRestart.TabIndex = 2;
|
||||||
|
this.btnRestart.Text = "Restart the Program";
|
||||||
|
this.toolTip.SetToolTip(this.btnRestart, "Restarts the program using the same command\r\nline arguments that were used at launch.");
|
||||||
|
this.btnRestart.UseVisualStyleBackColor = true;
|
||||||
|
//
|
||||||
|
// btnOpenAppFolder
|
||||||
|
//
|
||||||
|
this.btnOpenAppFolder.Location = new System.Drawing.Point(5, 3);
|
||||||
|
this.btnOpenAppFolder.Margin = new System.Windows.Forms.Padding(5, 3, 3, 3);
|
||||||
|
this.btnOpenAppFolder.Name = "btnOpenAppFolder";
|
||||||
|
this.btnOpenAppFolder.Size = new System.Drawing.Size(144, 23);
|
||||||
|
this.btnOpenAppFolder.TabIndex = 0;
|
||||||
|
this.btnOpenAppFolder.Text = "Open Program Folder";
|
||||||
|
this.toolTip.SetToolTip(this.btnOpenAppFolder, "Opens the folder where the app is located.");
|
||||||
|
this.btnOpenAppFolder.UseVisualStyleBackColor = true;
|
||||||
|
//
|
||||||
|
// btnOpenDataFolder
|
||||||
|
//
|
||||||
|
this.btnOpenDataFolder.Location = new System.Drawing.Point(5, 32);
|
||||||
|
this.btnOpenDataFolder.Margin = new System.Windows.Forms.Padding(5, 3, 3, 3);
|
||||||
|
this.btnOpenDataFolder.Name = "btnOpenDataFolder";
|
||||||
|
this.btnOpenDataFolder.Size = new System.Drawing.Size(144, 23);
|
||||||
|
this.btnOpenDataFolder.TabIndex = 1;
|
||||||
|
this.btnOpenDataFolder.Text = "Open Data Folder";
|
||||||
|
this.toolTip.SetToolTip(this.btnOpenDataFolder, "Opens the folder where your profile data is located.");
|
||||||
|
this.btnOpenDataFolder.UseVisualStyleBackColor = true;
|
||||||
|
//
|
||||||
|
// numMemoryThreshold
|
||||||
|
//
|
||||||
|
this.numMemoryThreshold.Increment = new decimal(new int[] {
|
||||||
|
50,
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
0});
|
||||||
|
this.numMemoryThreshold.Location = new System.Drawing.Point(202, 82);
|
||||||
|
this.numMemoryThreshold.Maximum = 2000;
|
||||||
|
this.numMemoryThreshold.Minimum = 200;
|
||||||
|
this.numMemoryThreshold.Name = "numMemoryThreshold";
|
||||||
|
this.numMemoryThreshold.Size = new System.Drawing.Size(97, 20);
|
||||||
|
this.numMemoryThreshold.TabIndex = 4;
|
||||||
|
this.numMemoryThreshold.TextSuffix = " MB";
|
||||||
|
this.toolTip.SetToolTip(this.numMemoryThreshold, "Minimum amount of memory usage by the browser process to trigger the cleanup.\r\nThis is not a limit, the usage is allowed to exceed this value.");
|
||||||
|
this.numMemoryThreshold.Value = 400;
|
||||||
|
//
|
||||||
|
// checkBrowserGCReload
|
||||||
|
//
|
||||||
|
this.checkBrowserGCReload.AutoSize = true;
|
||||||
|
this.checkBrowserGCReload.Location = new System.Drawing.Point(6, 84);
|
||||||
|
this.checkBrowserGCReload.Margin = new System.Windows.Forms.Padding(6, 5, 3, 3);
|
||||||
|
this.checkBrowserGCReload.Name = "checkBrowserGCReload";
|
||||||
|
this.checkBrowserGCReload.Size = new System.Drawing.Size(190, 17);
|
||||||
|
this.checkBrowserGCReload.TabIndex = 3;
|
||||||
|
this.checkBrowserGCReload.Text = "Enable Browser Memory Threshold";
|
||||||
|
this.toolTip.SetToolTip(this.checkBrowserGCReload, "Automatically reloads TweetDeck to save memory. This option only works if\r\nthe browser is in a \'default state\', i.e. all modals and drawers are closed, and\r\nall columns are scrolled to top. This option will not be exported in a profile.");
|
||||||
|
this.checkBrowserGCReload.UseVisualStyleBackColor = true;
|
||||||
|
//
|
||||||
|
// labelApp
|
||||||
|
//
|
||||||
|
this.labelApp.AutoSize = true;
|
||||||
|
this.labelApp.Font = new System.Drawing.Font("Microsoft Sans Serif", 12F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(238)));
|
||||||
|
this.labelApp.Location = new System.Drawing.Point(6, 8);
|
||||||
|
this.labelApp.Margin = new System.Windows.Forms.Padding(0, 2, 0, 0);
|
||||||
|
this.labelApp.Name = "labelApp";
|
||||||
|
this.labelApp.Size = new System.Drawing.Size(38, 20);
|
||||||
|
this.labelApp.TabIndex = 0;
|
||||||
|
this.labelApp.Text = "App";
|
||||||
|
//
|
||||||
|
// panelApp
|
||||||
|
//
|
||||||
|
this.panelApp.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left)
|
||||||
|
| System.Windows.Forms.AnchorStyles.Right)));
|
||||||
|
this.panelApp.Controls.Add(this.btnOpenDataFolder);
|
||||||
|
this.panelApp.Controls.Add(this.btnOpenAppFolder);
|
||||||
|
this.panelApp.Controls.Add(this.btnRestart);
|
||||||
|
this.panelApp.Controls.Add(this.btnRestartArgs);
|
||||||
|
this.panelApp.Location = new System.Drawing.Point(9, 31);
|
||||||
|
this.panelApp.Name = "panelApp";
|
||||||
|
this.panelApp.Size = new System.Drawing.Size(322, 59);
|
||||||
|
this.panelApp.TabIndex = 1;
|
||||||
|
//
|
||||||
|
// labelPerformance
|
||||||
|
//
|
||||||
|
this.labelPerformance.AutoSize = true;
|
||||||
|
this.labelPerformance.Font = new System.Drawing.Font("Microsoft Sans Serif", 12F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(238)));
|
||||||
|
this.labelPerformance.Location = new System.Drawing.Point(6, 114);
|
||||||
|
this.labelPerformance.Margin = new System.Windows.Forms.Padding(0, 21, 0, 0);
|
||||||
|
this.labelPerformance.Name = "labelPerformance";
|
||||||
|
this.labelPerformance.Size = new System.Drawing.Size(100, 20);
|
||||||
|
this.labelPerformance.TabIndex = 2;
|
||||||
|
this.labelPerformance.Text = "Performance";
|
||||||
|
//
|
||||||
|
// panelPerformance
|
||||||
|
//
|
||||||
|
this.panelPerformance.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left)
|
||||||
|
| System.Windows.Forms.AnchorStyles.Right)));
|
||||||
|
this.panelPerformance.Controls.Add(this.checkBrowserGCReload);
|
||||||
|
this.panelPerformance.Controls.Add(this.numMemoryThreshold);
|
||||||
|
this.panelPerformance.Controls.Add(this.labelMemoryUsage);
|
||||||
|
this.panelPerformance.Controls.Add(this.checkHardwareAcceleration);
|
||||||
|
this.panelPerformance.Controls.Add(this.btnClearCache);
|
||||||
|
this.panelPerformance.Location = new System.Drawing.Point(9, 137);
|
||||||
|
this.panelPerformance.Name = "panelPerformance";
|
||||||
|
this.panelPerformance.Size = new System.Drawing.Size(322, 105);
|
||||||
|
this.panelPerformance.TabIndex = 3;
|
||||||
|
//
|
||||||
|
// labelMemoryUsage
|
||||||
|
//
|
||||||
|
this.labelMemoryUsage.AutoSize = true;
|
||||||
|
this.labelMemoryUsage.Location = new System.Drawing.Point(3, 66);
|
||||||
|
this.labelMemoryUsage.Margin = new System.Windows.Forms.Padding(3, 12, 3, 0);
|
||||||
|
this.labelMemoryUsage.Name = "labelMemoryUsage";
|
||||||
|
this.labelMemoryUsage.Size = new System.Drawing.Size(78, 13);
|
||||||
|
this.labelMemoryUsage.TabIndex = 2;
|
||||||
|
this.labelMemoryUsage.Text = "Memory Usage";
|
||||||
|
//
|
||||||
|
// panelConfiguration
|
||||||
|
//
|
||||||
|
this.panelConfiguration.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left)
|
||||||
|
| System.Windows.Forms.AnchorStyles.Right)));
|
||||||
|
this.panelConfiguration.Controls.Add(this.btnEditCSS);
|
||||||
|
this.panelConfiguration.Controls.Add(this.btnEditCefArgs);
|
||||||
|
this.panelConfiguration.Location = new System.Drawing.Point(9, 289);
|
||||||
|
this.panelConfiguration.Name = "panelConfiguration";
|
||||||
|
this.panelConfiguration.Size = new System.Drawing.Size(322, 29);
|
||||||
|
this.panelConfiguration.TabIndex = 5;
|
||||||
|
//
|
||||||
|
// labelConfiguration
|
||||||
|
//
|
||||||
|
this.labelConfiguration.AutoSize = true;
|
||||||
|
this.labelConfiguration.Font = new System.Drawing.Font("Microsoft Sans Serif", 12F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(238)));
|
||||||
|
this.labelConfiguration.Location = new System.Drawing.Point(6, 266);
|
||||||
|
this.labelConfiguration.Margin = new System.Windows.Forms.Padding(0, 21, 0, 0);
|
||||||
|
this.labelConfiguration.Name = "labelConfiguration";
|
||||||
|
this.labelConfiguration.Size = new System.Drawing.Size(104, 20);
|
||||||
|
this.labelConfiguration.TabIndex = 4;
|
||||||
|
this.labelConfiguration.Text = "Configuration";
|
||||||
|
//
|
||||||
|
// TabSettingsAdvanced
|
||||||
|
//
|
||||||
|
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
|
||||||
|
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
|
||||||
|
this.Controls.Add(this.labelConfiguration);
|
||||||
|
this.Controls.Add(this.panelConfiguration);
|
||||||
|
this.Controls.Add(this.panelPerformance);
|
||||||
|
this.Controls.Add(this.labelPerformance);
|
||||||
|
this.Controls.Add(this.panelApp);
|
||||||
|
this.Controls.Add(this.labelApp);
|
||||||
|
this.Name = "TabSettingsAdvanced";
|
||||||
|
this.Size = new System.Drawing.Size(340, 328);
|
||||||
|
((System.ComponentModel.ISupportInitialize)(this.numMemoryThreshold)).EndInit();
|
||||||
|
this.panelApp.ResumeLayout(false);
|
||||||
|
this.panelPerformance.ResumeLayout(false);
|
||||||
|
this.panelPerformance.PerformLayout();
|
||||||
|
this.panelConfiguration.ResumeLayout(false);
|
||||||
|
this.ResumeLayout(false);
|
||||||
|
this.PerformLayout();
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
private System.Windows.Forms.Button btnClearCache;
|
||||||
|
private System.Windows.Forms.CheckBox checkHardwareAcceleration;
|
||||||
|
private System.Windows.Forms.ToolTip toolTip;
|
||||||
|
private System.Windows.Forms.Button btnEditCefArgs;
|
||||||
|
private System.Windows.Forms.Button btnEditCSS;
|
||||||
|
private System.Windows.Forms.Button btnRestartArgs;
|
||||||
|
private System.Windows.Forms.Button btnRestart;
|
||||||
|
private System.Windows.Forms.Button btnOpenAppFolder;
|
||||||
|
private System.Windows.Forms.Button btnOpenDataFolder;
|
||||||
|
private System.Windows.Forms.Label labelApp;
|
||||||
|
private System.Windows.Forms.Panel panelApp;
|
||||||
|
private System.Windows.Forms.Label labelPerformance;
|
||||||
|
private System.Windows.Forms.Panel panelPerformance;
|
||||||
|
private System.Windows.Forms.Panel panelConfiguration;
|
||||||
|
private System.Windows.Forms.Label labelConfiguration;
|
||||||
|
private System.Windows.Forms.Label labelMemoryUsage;
|
||||||
|
private Controls.NumericUpDownEx numMemoryThreshold;
|
||||||
|
private System.Windows.Forms.CheckBox checkBrowserGCReload;
|
||||||
|
}
|
||||||
|
}
|
||||||
147
Core/Other/Settings/TabSettingsAdvanced.cs
Normal file
147
Core/Other/Settings/TabSettingsAdvanced.cs
Normal file
@@ -0,0 +1,147 @@
|
|||||||
|
using System;
|
||||||
|
using System.Diagnostics;
|
||||||
|
using System.Windows.Forms;
|
||||||
|
using TweetDuck.Configuration;
|
||||||
|
using TweetDuck.Core.Controls;
|
||||||
|
using TweetDuck.Core.Other.Settings.Dialogs;
|
||||||
|
using TweetDuck.Core.Utils;
|
||||||
|
|
||||||
|
namespace TweetDuck.Core.Other.Settings{
|
||||||
|
partial class TabSettingsAdvanced : BaseTabSettings{
|
||||||
|
private static SystemConfig SysConfig => Program.SystemConfig;
|
||||||
|
|
||||||
|
private readonly Action<string> reinjectBrowserCSS;
|
||||||
|
|
||||||
|
public TabSettingsAdvanced(Action<string> reinjectBrowserCSS){
|
||||||
|
InitializeComponent();
|
||||||
|
|
||||||
|
this.reinjectBrowserCSS = reinjectBrowserCSS;
|
||||||
|
|
||||||
|
if (SystemConfig.IsHardwareAccelerationSupported){
|
||||||
|
checkHardwareAcceleration.Checked = SysConfig.HardwareAcceleration;
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
checkHardwareAcceleration.Enabled = false;
|
||||||
|
checkHardwareAcceleration.Checked = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
checkBrowserGCReload.Checked = SysConfig.EnableBrowserGCReload;
|
||||||
|
numMemoryThreshold.Enabled = checkBrowserGCReload.Checked;
|
||||||
|
numMemoryThreshold.SetValueSafe(SysConfig.BrowserMemoryThreshold);
|
||||||
|
|
||||||
|
BrowserCache.CalculateCacheSize(bytes => this.InvokeSafe(() => {
|
||||||
|
if (bytes == -1L){
|
||||||
|
btnClearCache.Text = "Clear Cache (unknown size)";
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
btnClearCache.Text = "Clear Cache ("+(int)Math.Ceiling(bytes/(1024.0*1024.0))+" MB)";
|
||||||
|
}
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void OnReady(){
|
||||||
|
btnClearCache.Click += btnClearCache_Click;
|
||||||
|
checkHardwareAcceleration.CheckedChanged += checkHardwareAcceleration_CheckedChanged;
|
||||||
|
|
||||||
|
checkBrowserGCReload.CheckedChanged += checkBrowserGCReload_CheckedChanged;
|
||||||
|
numMemoryThreshold.ValueChanged += numMemoryThreshold_ValueChanged;
|
||||||
|
|
||||||
|
btnEditCefArgs.Click += btnEditCefArgs_Click;
|
||||||
|
btnEditCSS.Click += btnEditCSS_Click;
|
||||||
|
|
||||||
|
btnOpenAppFolder.Click += btnOpenAppFolder_Click;
|
||||||
|
btnOpenDataFolder.Click += btnOpenDataFolder_Click;
|
||||||
|
btnRestart.Click += btnRestart_Click;
|
||||||
|
btnRestartArgs.Click += btnRestartArgs_Click;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void OnClosing(){
|
||||||
|
SysConfig.Save();
|
||||||
|
}
|
||||||
|
|
||||||
|
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 checkHardwareAcceleration_CheckedChanged(object sender, EventArgs e){
|
||||||
|
SysConfig.HardwareAcceleration = checkHardwareAcceleration.Checked;
|
||||||
|
PromptRestart(); // calls OnClosing
|
||||||
|
}
|
||||||
|
|
||||||
|
private void checkBrowserGCReload_CheckedChanged(object sender, EventArgs e){
|
||||||
|
SysConfig.EnableBrowserGCReload = checkBrowserGCReload.Checked;
|
||||||
|
numMemoryThreshold.Enabled = checkBrowserGCReload.Checked;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void numMemoryThreshold_ValueChanged(object sender, EventArgs e){
|
||||||
|
SysConfig.BrowserMemoryThreshold = (int)numMemoryThreshold.Value;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void btnEditCefArgs_Click(object sender, EventArgs e){
|
||||||
|
DialogSettingsCefArgs form = new DialogSettingsCefArgs();
|
||||||
|
|
||||||
|
form.VisibleChanged += (sender2, args2) => {
|
||||||
|
form.MoveToCenter(ParentForm);
|
||||||
|
};
|
||||||
|
|
||||||
|
form.FormClosed += (sender2, args2) => {
|
||||||
|
NativeMethods.SetFormDisabled(ParentForm, false);
|
||||||
|
|
||||||
|
if (form.DialogResult == DialogResult.OK){
|
||||||
|
Config.CustomCefArgs = form.CefArgs;
|
||||||
|
PromptRestart();
|
||||||
|
form.Dispose();
|
||||||
|
}
|
||||||
|
else form.Dispose();
|
||||||
|
};
|
||||||
|
|
||||||
|
form.Show(ParentForm);
|
||||||
|
NativeMethods.SetFormDisabled(ParentForm, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void btnEditCSS_Click(object sender, EventArgs e){
|
||||||
|
DialogSettingsCSS form = new DialogSettingsCSS(reinjectBrowserCSS);
|
||||||
|
|
||||||
|
form.VisibleChanged += (sender2, args2) => {
|
||||||
|
form.MoveToCenter(ParentForm);
|
||||||
|
};
|
||||||
|
|
||||||
|
form.FormClosed += (sender2, args2) => {
|
||||||
|
NativeMethods.SetFormDisabled(ParentForm, false);
|
||||||
|
|
||||||
|
if (form.DialogResult == DialogResult.OK){
|
||||||
|
Config.CustomBrowserCSS = form.BrowserCSS;
|
||||||
|
Config.CustomNotificationCSS = form.NotificationCSS;
|
||||||
|
}
|
||||||
|
|
||||||
|
reinjectBrowserCSS(Config.CustomBrowserCSS); // reinject on cancel too, because the CSS is updated while typing
|
||||||
|
form.Dispose();
|
||||||
|
};
|
||||||
|
|
||||||
|
form.Show(ParentForm);
|
||||||
|
NativeMethods.SetFormDisabled(ParentForm, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void btnOpenAppFolder_Click(object sender, EventArgs e){
|
||||||
|
using(Process.Start("explorer.exe", "\""+Program.ProgramPath+"\"")){}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void btnOpenDataFolder_Click(object sender, EventArgs e){
|
||||||
|
using(Process.Start("explorer.exe", "\""+Program.StoragePath+"\"")){}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void btnRestart_Click(object sender, EventArgs e){
|
||||||
|
Program.Restart();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void btnRestartArgs_Click(object sender, EventArgs e){
|
||||||
|
using(DialogSettingsRestart dialog = new DialogSettingsRestart(Arguments.GetCurrentClean())){
|
||||||
|
if (dialog.ShowDialog() == DialogResult.OK){
|
||||||
|
Program.RestartWithArgs(dialog.Args);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
318
Core/Other/Settings/TabSettingsGeneral.Designer.cs
generated
Normal file
318
Core/Other/Settings/TabSettingsGeneral.Designer.cs
generated
Normal file
@@ -0,0 +1,318 @@
|
|||||||
|
namespace TweetDuck.Core.Other.Settings {
|
||||||
|
partial class TabSettingsGeneral {
|
||||||
|
/// <summary>
|
||||||
|
/// Required designer variable.
|
||||||
|
/// </summary>
|
||||||
|
private System.ComponentModel.IContainer components = null;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Clean up any resources being used.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
|
||||||
|
protected override void Dispose(bool disposing) {
|
||||||
|
if (disposing && (components != null)) {
|
||||||
|
components.Dispose();
|
||||||
|
}
|
||||||
|
base.Dispose(disposing);
|
||||||
|
}
|
||||||
|
|
||||||
|
#region Component Designer generated code
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Required method for Designer support - do not modify
|
||||||
|
/// the contents of this method with the code editor.
|
||||||
|
/// </summary>
|
||||||
|
private void InitializeComponent() {
|
||||||
|
this.components = new System.ComponentModel.Container();
|
||||||
|
this.checkExpandLinks = new System.Windows.Forms.CheckBox();
|
||||||
|
this.comboBoxTrayType = new System.Windows.Forms.ComboBox();
|
||||||
|
this.toolTip = new System.Windows.Forms.ToolTip(this.components);
|
||||||
|
this.checkTrayHighlight = new System.Windows.Forms.CheckBox();
|
||||||
|
this.checkSpellCheck = new System.Windows.Forms.CheckBox();
|
||||||
|
this.checkUpdateNotifications = new System.Windows.Forms.CheckBox();
|
||||||
|
this.btnCheckUpdates = new System.Windows.Forms.Button();
|
||||||
|
this.labelZoomValue = new System.Windows.Forms.Label();
|
||||||
|
this.checkSwitchAccountSelectors = new System.Windows.Forms.CheckBox();
|
||||||
|
this.labelTrayIcon = new System.Windows.Forms.Label();
|
||||||
|
this.trackBarZoom = new System.Windows.Forms.TrackBar();
|
||||||
|
this.labelZoom = new System.Windows.Forms.Label();
|
||||||
|
this.zoomUpdateTimer = new System.Windows.Forms.Timer(this.components);
|
||||||
|
this.labelUI = new System.Windows.Forms.Label();
|
||||||
|
this.panelUI = new System.Windows.Forms.Panel();
|
||||||
|
this.labelTray = new System.Windows.Forms.Label();
|
||||||
|
this.panelUpdates = new System.Windows.Forms.Panel();
|
||||||
|
this.panelTray = new System.Windows.Forms.Panel();
|
||||||
|
this.labelUpdates = new System.Windows.Forms.Label();
|
||||||
|
this.checkBestImageQuality = new System.Windows.Forms.CheckBox();
|
||||||
|
((System.ComponentModel.ISupportInitialize)(this.trackBarZoom)).BeginInit();
|
||||||
|
this.panelUI.SuspendLayout();
|
||||||
|
this.panelUpdates.SuspendLayout();
|
||||||
|
this.panelTray.SuspendLayout();
|
||||||
|
this.SuspendLayout();
|
||||||
|
//
|
||||||
|
// checkExpandLinks
|
||||||
|
//
|
||||||
|
this.checkExpandLinks.AutoSize = true;
|
||||||
|
this.checkExpandLinks.Location = new System.Drawing.Point(6, 5);
|
||||||
|
this.checkExpandLinks.Margin = new System.Windows.Forms.Padding(6, 5, 3, 3);
|
||||||
|
this.checkExpandLinks.Name = "checkExpandLinks";
|
||||||
|
this.checkExpandLinks.Size = new System.Drawing.Size(166, 17);
|
||||||
|
this.checkExpandLinks.TabIndex = 0;
|
||||||
|
this.checkExpandLinks.Text = "Expand Links When Hovered";
|
||||||
|
this.toolTip.SetToolTip(this.checkExpandLinks, "Expands links inside the tweets. If disabled,\r\nthe full links show up in a tooltip instead.");
|
||||||
|
this.checkExpandLinks.UseVisualStyleBackColor = true;
|
||||||
|
//
|
||||||
|
// comboBoxTrayType
|
||||||
|
//
|
||||||
|
this.comboBoxTrayType.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList;
|
||||||
|
this.comboBoxTrayType.FormattingEnabled = true;
|
||||||
|
this.comboBoxTrayType.Location = new System.Drawing.Point(5, 5);
|
||||||
|
this.comboBoxTrayType.Margin = new System.Windows.Forms.Padding(5, 5, 3, 3);
|
||||||
|
this.comboBoxTrayType.Name = "comboBoxTrayType";
|
||||||
|
this.comboBoxTrayType.Size = new System.Drawing.Size(144, 21);
|
||||||
|
this.comboBoxTrayType.TabIndex = 0;
|
||||||
|
this.toolTip.SetToolTip(this.comboBoxTrayType, "Changes behavior of the Tray icon.\r\nRight-click the icon for an action menu.");
|
||||||
|
//
|
||||||
|
// checkTrayHighlight
|
||||||
|
//
|
||||||
|
this.checkTrayHighlight.AutoSize = true;
|
||||||
|
this.checkTrayHighlight.Location = new System.Drawing.Point(6, 56);
|
||||||
|
this.checkTrayHighlight.Margin = new System.Windows.Forms.Padding(6, 5, 3, 3);
|
||||||
|
this.checkTrayHighlight.Name = "checkTrayHighlight";
|
||||||
|
this.checkTrayHighlight.Size = new System.Drawing.Size(103, 17);
|
||||||
|
this.checkTrayHighlight.TabIndex = 2;
|
||||||
|
this.checkTrayHighlight.Text = "Enable Highlight";
|
||||||
|
this.toolTip.SetToolTip(this.checkTrayHighlight, "Highlights the tray icon if there are new tweets.\r\nOnly works for columns with popup or audio notifications.\r\nThe icon resets when the main window is restored.");
|
||||||
|
this.checkTrayHighlight.UseVisualStyleBackColor = true;
|
||||||
|
//
|
||||||
|
// checkSpellCheck
|
||||||
|
//
|
||||||
|
this.checkSpellCheck.AutoSize = true;
|
||||||
|
this.checkSpellCheck.Location = new System.Drawing.Point(6, 74);
|
||||||
|
this.checkSpellCheck.Margin = new System.Windows.Forms.Padding(6, 3, 3, 3);
|
||||||
|
this.checkSpellCheck.Name = "checkSpellCheck";
|
||||||
|
this.checkSpellCheck.Size = new System.Drawing.Size(119, 17);
|
||||||
|
this.checkSpellCheck.TabIndex = 3;
|
||||||
|
this.checkSpellCheck.Text = "Enable Spell Check";
|
||||||
|
this.toolTip.SetToolTip(this.checkSpellCheck, "Underlines words that are spelled incorrectly.");
|
||||||
|
this.checkSpellCheck.UseVisualStyleBackColor = true;
|
||||||
|
//
|
||||||
|
// checkUpdateNotifications
|
||||||
|
//
|
||||||
|
this.checkUpdateNotifications.AutoSize = true;
|
||||||
|
this.checkUpdateNotifications.Location = new System.Drawing.Point(6, 5);
|
||||||
|
this.checkUpdateNotifications.Margin = new System.Windows.Forms.Padding(6, 5, 3, 3);
|
||||||
|
this.checkUpdateNotifications.Name = "checkUpdateNotifications";
|
||||||
|
this.checkUpdateNotifications.Size = new System.Drawing.Size(165, 17);
|
||||||
|
this.checkUpdateNotifications.TabIndex = 0;
|
||||||
|
this.checkUpdateNotifications.Text = "Check Updates Automatically";
|
||||||
|
this.toolTip.SetToolTip(this.checkUpdateNotifications, "Checks for updates every hour.\r\nIf an update is dismissed, it will not appear again.");
|
||||||
|
this.checkUpdateNotifications.UseVisualStyleBackColor = true;
|
||||||
|
//
|
||||||
|
// btnCheckUpdates
|
||||||
|
//
|
||||||
|
this.btnCheckUpdates.Location = new System.Drawing.Point(5, 28);
|
||||||
|
this.btnCheckUpdates.Margin = new System.Windows.Forms.Padding(5, 3, 3, 3);
|
||||||
|
this.btnCheckUpdates.Name = "btnCheckUpdates";
|
||||||
|
this.btnCheckUpdates.Size = new System.Drawing.Size(144, 23);
|
||||||
|
this.btnCheckUpdates.TabIndex = 1;
|
||||||
|
this.btnCheckUpdates.Text = "Check Updates Now";
|
||||||
|
this.toolTip.SetToolTip(this.btnCheckUpdates, "Forces an update check, even for updates that had been dismissed.");
|
||||||
|
this.btnCheckUpdates.UseVisualStyleBackColor = true;
|
||||||
|
//
|
||||||
|
// labelZoomValue
|
||||||
|
//
|
||||||
|
this.labelZoomValue.BackColor = System.Drawing.Color.Transparent;
|
||||||
|
this.labelZoomValue.Location = new System.Drawing.Point(141, 123);
|
||||||
|
this.labelZoomValue.Margin = new System.Windows.Forms.Padding(0, 0, 3, 0);
|
||||||
|
this.labelZoomValue.Name = "labelZoomValue";
|
||||||
|
this.labelZoomValue.Size = new System.Drawing.Size(38, 13);
|
||||||
|
this.labelZoomValue.TabIndex = 6;
|
||||||
|
this.labelZoomValue.Text = "100%";
|
||||||
|
this.labelZoomValue.TextAlign = System.Drawing.ContentAlignment.TopRight;
|
||||||
|
this.toolTip.SetToolTip(this.labelZoomValue, "Changes the zoom level.\r\nAlso affects notifications and screenshots.");
|
||||||
|
//
|
||||||
|
// checkSwitchAccountSelectors
|
||||||
|
//
|
||||||
|
this.checkSwitchAccountSelectors.AutoSize = true;
|
||||||
|
this.checkSwitchAccountSelectors.Location = new System.Drawing.Point(6, 28);
|
||||||
|
this.checkSwitchAccountSelectors.Margin = new System.Windows.Forms.Padding(6, 3, 3, 3);
|
||||||
|
this.checkSwitchAccountSelectors.Name = "checkSwitchAccountSelectors";
|
||||||
|
this.checkSwitchAccountSelectors.Size = new System.Drawing.Size(172, 17);
|
||||||
|
this.checkSwitchAccountSelectors.TabIndex = 1;
|
||||||
|
this.checkSwitchAccountSelectors.Text = "Shift Selects Multiple Accounts";
|
||||||
|
this.toolTip.SetToolTip(this.checkSwitchAccountSelectors, "When (re)tweeting, click to select a single account or hold Shift to\r\nselect multiple accounts, instead of TweetDeck\'s default behavior.");
|
||||||
|
this.checkSwitchAccountSelectors.UseVisualStyleBackColor = true;
|
||||||
|
//
|
||||||
|
// labelTrayIcon
|
||||||
|
//
|
||||||
|
this.labelTrayIcon.AutoSize = true;
|
||||||
|
this.labelTrayIcon.Location = new System.Drawing.Point(3, 38);
|
||||||
|
this.labelTrayIcon.Margin = new System.Windows.Forms.Padding(3, 9, 3, 0);
|
||||||
|
this.labelTrayIcon.Name = "labelTrayIcon";
|
||||||
|
this.labelTrayIcon.Size = new System.Drawing.Size(52, 13);
|
||||||
|
this.labelTrayIcon.TabIndex = 1;
|
||||||
|
this.labelTrayIcon.Text = "Tray Icon";
|
||||||
|
//
|
||||||
|
// trackBarZoom
|
||||||
|
//
|
||||||
|
this.trackBarZoom.AutoSize = false;
|
||||||
|
this.trackBarZoom.BackColor = System.Drawing.SystemColors.Control;
|
||||||
|
this.trackBarZoom.LargeChange = 25;
|
||||||
|
this.trackBarZoom.Location = new System.Drawing.Point(3, 122);
|
||||||
|
this.trackBarZoom.Maximum = 200;
|
||||||
|
this.trackBarZoom.Minimum = 50;
|
||||||
|
this.trackBarZoom.Name = "trackBarZoom";
|
||||||
|
this.trackBarZoom.Size = new System.Drawing.Size(148, 30);
|
||||||
|
this.trackBarZoom.SmallChange = 5;
|
||||||
|
this.trackBarZoom.TabIndex = 5;
|
||||||
|
this.trackBarZoom.TickFrequency = 25;
|
||||||
|
this.trackBarZoom.Value = 100;
|
||||||
|
//
|
||||||
|
// labelZoom
|
||||||
|
//
|
||||||
|
this.labelZoom.AutoSize = true;
|
||||||
|
this.labelZoom.Location = new System.Drawing.Point(3, 106);
|
||||||
|
this.labelZoom.Margin = new System.Windows.Forms.Padding(3, 12, 3, 0);
|
||||||
|
this.labelZoom.Name = "labelZoom";
|
||||||
|
this.labelZoom.Size = new System.Drawing.Size(34, 13);
|
||||||
|
this.labelZoom.TabIndex = 4;
|
||||||
|
this.labelZoom.Text = "Zoom";
|
||||||
|
//
|
||||||
|
// zoomUpdateTimer
|
||||||
|
//
|
||||||
|
this.zoomUpdateTimer.Interval = 250;
|
||||||
|
this.zoomUpdateTimer.Tick += new System.EventHandler(this.zoomUpdateTimer_Tick);
|
||||||
|
//
|
||||||
|
// labelUI
|
||||||
|
//
|
||||||
|
this.labelUI.AutoSize = true;
|
||||||
|
this.labelUI.Font = new System.Drawing.Font("Microsoft Sans Serif", 12F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(238)));
|
||||||
|
this.labelUI.Location = new System.Drawing.Point(6, 8);
|
||||||
|
this.labelUI.Margin = new System.Windows.Forms.Padding(0, 2, 0, 0);
|
||||||
|
this.labelUI.Name = "labelUI";
|
||||||
|
this.labelUI.Size = new System.Drawing.Size(111, 20);
|
||||||
|
this.labelUI.TabIndex = 0;
|
||||||
|
this.labelUI.Text = "User Interface";
|
||||||
|
//
|
||||||
|
// panelUI
|
||||||
|
//
|
||||||
|
this.panelUI.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left)
|
||||||
|
| System.Windows.Forms.AnchorStyles.Right)));
|
||||||
|
this.panelUI.Controls.Add(this.checkBestImageQuality);
|
||||||
|
this.panelUI.Controls.Add(this.checkExpandLinks);
|
||||||
|
this.panelUI.Controls.Add(this.checkSwitchAccountSelectors);
|
||||||
|
this.panelUI.Controls.Add(this.checkSpellCheck);
|
||||||
|
this.panelUI.Controls.Add(this.labelZoom);
|
||||||
|
this.panelUI.Controls.Add(this.labelZoomValue);
|
||||||
|
this.panelUI.Controls.Add(this.trackBarZoom);
|
||||||
|
this.panelUI.Location = new System.Drawing.Point(9, 31);
|
||||||
|
this.panelUI.Name = "panelUI";
|
||||||
|
this.panelUI.Size = new System.Drawing.Size(322, 157);
|
||||||
|
this.panelUI.TabIndex = 1;
|
||||||
|
//
|
||||||
|
// labelTray
|
||||||
|
//
|
||||||
|
this.labelTray.AutoSize = true;
|
||||||
|
this.labelTray.Font = new System.Drawing.Font("Microsoft Sans Serif", 12F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(238)));
|
||||||
|
this.labelTray.Location = new System.Drawing.Point(6, 212);
|
||||||
|
this.labelTray.Margin = new System.Windows.Forms.Padding(0, 21, 0, 0);
|
||||||
|
this.labelTray.Name = "labelTray";
|
||||||
|
this.labelTray.Size = new System.Drawing.Size(96, 20);
|
||||||
|
this.labelTray.TabIndex = 2;
|
||||||
|
this.labelTray.Text = "System Tray";
|
||||||
|
//
|
||||||
|
// panelUpdates
|
||||||
|
//
|
||||||
|
this.panelUpdates.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left)
|
||||||
|
| System.Windows.Forms.AnchorStyles.Right)));
|
||||||
|
this.panelUpdates.Controls.Add(this.checkUpdateNotifications);
|
||||||
|
this.panelUpdates.Controls.Add(this.btnCheckUpdates);
|
||||||
|
this.panelUpdates.Location = new System.Drawing.Point(9, 358);
|
||||||
|
this.panelUpdates.Name = "panelUpdates";
|
||||||
|
this.panelUpdates.Size = new System.Drawing.Size(322, 55);
|
||||||
|
this.panelUpdates.TabIndex = 5;
|
||||||
|
//
|
||||||
|
// panelTray
|
||||||
|
//
|
||||||
|
this.panelTray.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left)
|
||||||
|
| System.Windows.Forms.AnchorStyles.Right)));
|
||||||
|
this.panelTray.Controls.Add(this.checkTrayHighlight);
|
||||||
|
this.panelTray.Controls.Add(this.comboBoxTrayType);
|
||||||
|
this.panelTray.Controls.Add(this.labelTrayIcon);
|
||||||
|
this.panelTray.Location = new System.Drawing.Point(9, 235);
|
||||||
|
this.panelTray.Name = "panelTray";
|
||||||
|
this.panelTray.Size = new System.Drawing.Size(322, 76);
|
||||||
|
this.panelTray.TabIndex = 3;
|
||||||
|
//
|
||||||
|
// labelUpdates
|
||||||
|
//
|
||||||
|
this.labelUpdates.AutoSize = true;
|
||||||
|
this.labelUpdates.Font = new System.Drawing.Font("Microsoft Sans Serif", 12F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(238)));
|
||||||
|
this.labelUpdates.Location = new System.Drawing.Point(6, 335);
|
||||||
|
this.labelUpdates.Margin = new System.Windows.Forms.Padding(0, 21, 0, 0);
|
||||||
|
this.labelUpdates.Name = "labelUpdates";
|
||||||
|
this.labelUpdates.Size = new System.Drawing.Size(70, 20);
|
||||||
|
this.labelUpdates.TabIndex = 4;
|
||||||
|
this.labelUpdates.Text = "Updates";
|
||||||
|
//
|
||||||
|
// checkBestImageQuality
|
||||||
|
//
|
||||||
|
this.checkBestImageQuality.AutoSize = true;
|
||||||
|
this.checkBestImageQuality.Location = new System.Drawing.Point(6, 51);
|
||||||
|
this.checkBestImageQuality.Margin = new System.Windows.Forms.Padding(6, 3, 3, 3);
|
||||||
|
this.checkBestImageQuality.Name = "checkBestImageQuality";
|
||||||
|
this.checkBestImageQuality.Size = new System.Drawing.Size(114, 17);
|
||||||
|
this.checkBestImageQuality.TabIndex = 2;
|
||||||
|
this.checkBestImageQuality.Text = "Best Image Quality";
|
||||||
|
this.toolTip.SetToolTip(this.checkBestImageQuality, "When right-clicking a tweet image, the context menu options\r\nwill use links to the original image size (:orig in the URL).");
|
||||||
|
this.checkBestImageQuality.UseVisualStyleBackColor = true;
|
||||||
|
//
|
||||||
|
// TabSettingsGeneral
|
||||||
|
//
|
||||||
|
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
|
||||||
|
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
|
||||||
|
this.Controls.Add(this.labelUpdates);
|
||||||
|
this.Controls.Add(this.panelTray);
|
||||||
|
this.Controls.Add(this.panelUpdates);
|
||||||
|
this.Controls.Add(this.labelTray);
|
||||||
|
this.Controls.Add(this.panelUI);
|
||||||
|
this.Controls.Add(this.labelUI);
|
||||||
|
this.Name = "TabSettingsGeneral";
|
||||||
|
this.Size = new System.Drawing.Size(340, 422);
|
||||||
|
((System.ComponentModel.ISupportInitialize)(this.trackBarZoom)).EndInit();
|
||||||
|
this.panelUI.ResumeLayout(false);
|
||||||
|
this.panelUI.PerformLayout();
|
||||||
|
this.panelUpdates.ResumeLayout(false);
|
||||||
|
this.panelUpdates.PerformLayout();
|
||||||
|
this.panelTray.ResumeLayout(false);
|
||||||
|
this.panelTray.PerformLayout();
|
||||||
|
this.ResumeLayout(false);
|
||||||
|
this.PerformLayout();
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
private System.Windows.Forms.CheckBox checkExpandLinks;
|
||||||
|
private System.Windows.Forms.ComboBox comboBoxTrayType;
|
||||||
|
private System.Windows.Forms.ToolTip toolTip;
|
||||||
|
private System.Windows.Forms.Label labelTrayIcon;
|
||||||
|
private System.Windows.Forms.CheckBox checkTrayHighlight;
|
||||||
|
private System.Windows.Forms.CheckBox checkSpellCheck;
|
||||||
|
private System.Windows.Forms.CheckBox checkUpdateNotifications;
|
||||||
|
private System.Windows.Forms.Button btnCheckUpdates;
|
||||||
|
private System.Windows.Forms.Label labelZoom;
|
||||||
|
private System.Windows.Forms.Label labelZoomValue;
|
||||||
|
private System.Windows.Forms.TrackBar trackBarZoom;
|
||||||
|
private System.Windows.Forms.Timer zoomUpdateTimer;
|
||||||
|
private System.Windows.Forms.CheckBox checkSwitchAccountSelectors;
|
||||||
|
private System.Windows.Forms.Label labelUI;
|
||||||
|
private System.Windows.Forms.Panel panelUI;
|
||||||
|
private System.Windows.Forms.Label labelTray;
|
||||||
|
private System.Windows.Forms.Panel panelUpdates;
|
||||||
|
private System.Windows.Forms.Panel panelTray;
|
||||||
|
private System.Windows.Forms.Label labelUpdates;
|
||||||
|
private System.Windows.Forms.CheckBox checkBestImageQuality;
|
||||||
|
}
|
||||||
|
}
|
||||||
122
Core/Other/Settings/TabSettingsGeneral.cs
Normal file
122
Core/Other/Settings/TabSettingsGeneral.cs
Normal file
@@ -0,0 +1,122 @@
|
|||||||
|
using System;
|
||||||
|
using TweetDuck.Core.Controls;
|
||||||
|
using TweetDuck.Updates;
|
||||||
|
using TweetDuck.Updates.Events;
|
||||||
|
|
||||||
|
namespace TweetDuck.Core.Other.Settings{
|
||||||
|
partial class TabSettingsGeneral : BaseTabSettings{
|
||||||
|
private readonly UpdateHandler updates;
|
||||||
|
private int updateCheckEventId = -1;
|
||||||
|
|
||||||
|
public TabSettingsGeneral(UpdateHandler updates){
|
||||||
|
InitializeComponent();
|
||||||
|
|
||||||
|
this.updates = updates;
|
||||||
|
this.updates.CheckFinished += updates_CheckFinished;
|
||||||
|
Disposed += (sender, args) => this.updates.CheckFinished -= updates_CheckFinished;
|
||||||
|
|
||||||
|
comboBoxTrayType.Items.Add("Disabled");
|
||||||
|
comboBoxTrayType.Items.Add("Display Icon Only");
|
||||||
|
comboBoxTrayType.Items.Add("Minimize to Tray");
|
||||||
|
comboBoxTrayType.Items.Add("Close to Tray");
|
||||||
|
comboBoxTrayType.Items.Add("Combined");
|
||||||
|
comboBoxTrayType.SelectedIndex = Math.Min(Math.Max((int)Config.TrayBehavior, 0), comboBoxTrayType.Items.Count-1);
|
||||||
|
|
||||||
|
toolTip.SetToolTip(trackBarZoom, toolTip.GetToolTip(labelZoomValue));
|
||||||
|
trackBarZoom.SetValueSafe(Config.ZoomLevel);
|
||||||
|
labelZoomValue.Text = trackBarZoom.Value+"%";
|
||||||
|
|
||||||
|
checkExpandLinks.Checked = Config.ExpandLinksOnHover;
|
||||||
|
checkSwitchAccountSelectors.Checked = Config.SwitchAccountSelectors;
|
||||||
|
checkBestImageQuality.Checked = Config.BestImageQuality;
|
||||||
|
checkSpellCheck.Checked = Config.EnableSpellCheck;
|
||||||
|
checkTrayHighlight.Checked = Config.EnableTrayHighlight;
|
||||||
|
|
||||||
|
checkUpdateNotifications.Checked = Config.EnableUpdateCheck;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void OnReady(){
|
||||||
|
checkExpandLinks.CheckedChanged += checkExpandLinks_CheckedChanged;
|
||||||
|
checkSwitchAccountSelectors.CheckedChanged += checkSwitchAccountSelectors_CheckedChanged;
|
||||||
|
checkBestImageQuality.CheckedChanged += checkBestImageQuality_CheckedChanged;
|
||||||
|
checkSpellCheck.CheckedChanged += checkSpellCheck_CheckedChanged;
|
||||||
|
trackBarZoom.ValueChanged += trackBarZoom_ValueChanged;
|
||||||
|
|
||||||
|
comboBoxTrayType.SelectedIndexChanged += comboBoxTrayType_SelectedIndexChanged;
|
||||||
|
checkTrayHighlight.CheckedChanged += checkTrayHighlight_CheckedChanged;
|
||||||
|
|
||||||
|
checkUpdateNotifications.CheckedChanged += checkUpdateNotifications_CheckedChanged;
|
||||||
|
btnCheckUpdates.Click += btnCheckUpdates_Click;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void OnClosing(){
|
||||||
|
Config.ZoomLevel = trackBarZoom.Value;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void checkExpandLinks_CheckedChanged(object sender, EventArgs e){
|
||||||
|
Config.ExpandLinksOnHover = checkExpandLinks.Checked;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void checkSwitchAccountSelectors_CheckedChanged(object sender, EventArgs e){
|
||||||
|
Config.SwitchAccountSelectors = checkSwitchAccountSelectors.Checked;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void checkBestImageQuality_CheckedChanged(object sender, EventArgs e){
|
||||||
|
Config.BestImageQuality = checkBestImageQuality.Checked;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void checkSpellCheck_CheckedChanged(object sender, EventArgs e){
|
||||||
|
Config.EnableSpellCheck = checkSpellCheck.Checked;
|
||||||
|
PromptRestart();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void trackBarZoom_ValueChanged(object sender, EventArgs e){
|
||||||
|
if (trackBarZoom.AlignValueToTick()){
|
||||||
|
zoomUpdateTimer.Stop();
|
||||||
|
zoomUpdateTimer.Start();
|
||||||
|
labelZoomValue.Text = trackBarZoom.Value+"%";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void comboBoxTrayType_SelectedIndexChanged(object sender, EventArgs e){
|
||||||
|
Config.TrayBehavior = (TrayIcon.Behavior)comboBoxTrayType.SelectedIndex;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void checkTrayHighlight_CheckedChanged(object sender, EventArgs e){
|
||||||
|
Config.EnableTrayHighlight = checkTrayHighlight.Checked;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void checkUpdateNotifications_CheckedChanged(object sender, EventArgs e){
|
||||||
|
Config.EnableUpdateCheck = checkUpdateNotifications.Checked;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void btnCheckUpdates_Click(object sender, EventArgs e){
|
||||||
|
updateCheckEventId = updates.Check(true);
|
||||||
|
|
||||||
|
if (updateCheckEventId == -1){
|
||||||
|
FormMessage.Warning("Unsupported System", "Sorry, your system is no longer supported.", FormMessage.OK);
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
btnCheckUpdates.Enabled = false;
|
||||||
|
updates.DismissUpdate(string.Empty);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void updates_CheckFinished(object sender, UpdateCheckEventArgs e){
|
||||||
|
this.InvokeAsyncSafe(() => {
|
||||||
|
if (e.EventId == updateCheckEventId){
|
||||||
|
btnCheckUpdates.Enabled = true;
|
||||||
|
|
||||||
|
if (!e.UpdateAvailable){
|
||||||
|
FormMessage.Information("No Updates Available", "Your version of TweetDuck is up to date.", FormMessage.OK);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private void zoomUpdateTimer_Tick(object sender, EventArgs e){
|
||||||
|
Config.ZoomLevel = trackBarZoom.Value;
|
||||||
|
zoomUpdateTimer.Stop();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
620
Core/Other/Settings/TabSettingsNotifications.Designer.cs
generated
Normal file
620
Core/Other/Settings/TabSettingsNotifications.Designer.cs
generated
Normal file
@@ -0,0 +1,620 @@
|
|||||||
|
namespace TweetDuck.Core.Other.Settings {
|
||||||
|
partial class TabSettingsNotifications {
|
||||||
|
/// <summary>
|
||||||
|
/// Required designer variable.
|
||||||
|
/// </summary>
|
||||||
|
private System.ComponentModel.IContainer components = null;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Clean up any resources being used.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
|
||||||
|
protected override void Dispose(bool disposing) {
|
||||||
|
if (disposing && (components != null)) {
|
||||||
|
components.Dispose();
|
||||||
|
}
|
||||||
|
base.Dispose(disposing);
|
||||||
|
}
|
||||||
|
|
||||||
|
#region Component Designer generated code
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Required method for Designer support - do not modify
|
||||||
|
/// the contents of this method with the code editor.
|
||||||
|
/// </summary>
|
||||||
|
private void InitializeComponent() {
|
||||||
|
this.components = new System.ComponentModel.Container();
|
||||||
|
this.labelEdgeDistanceValue = new System.Windows.Forms.Label();
|
||||||
|
this.labelDisplay = new System.Windows.Forms.Label();
|
||||||
|
this.comboBoxDisplay = new System.Windows.Forms.ComboBox();
|
||||||
|
this.labelEdgeDistance = new System.Windows.Forms.Label();
|
||||||
|
this.radioLocCustom = new System.Windows.Forms.RadioButton();
|
||||||
|
this.radioLocBR = new System.Windows.Forms.RadioButton();
|
||||||
|
this.radioLocBL = new System.Windows.Forms.RadioButton();
|
||||||
|
this.radioLocTR = new System.Windows.Forms.RadioButton();
|
||||||
|
this.radioLocTL = new System.Windows.Forms.RadioButton();
|
||||||
|
this.trackBarEdgeDistance = new System.Windows.Forms.TrackBar();
|
||||||
|
this.tableLayoutDurationButtons = new System.Windows.Forms.TableLayoutPanel();
|
||||||
|
this.btnDurationMedium = new TweetDuck.Core.Controls.FlatButton();
|
||||||
|
this.btnDurationLong = new TweetDuck.Core.Controls.FlatButton();
|
||||||
|
this.btnDurationShort = new TweetDuck.Core.Controls.FlatButton();
|
||||||
|
this.labelDurationValue = new System.Windows.Forms.Label();
|
||||||
|
this.trackBarDuration = new System.Windows.Forms.TrackBar();
|
||||||
|
this.checkSkipOnLinkClick = new System.Windows.Forms.CheckBox();
|
||||||
|
this.checkColumnName = new System.Windows.Forms.CheckBox();
|
||||||
|
this.labelIdlePause = new System.Windows.Forms.Label();
|
||||||
|
this.comboBoxIdlePause = new System.Windows.Forms.ComboBox();
|
||||||
|
this.checkNonIntrusive = new System.Windows.Forms.CheckBox();
|
||||||
|
this.checkTimerCountDown = new System.Windows.Forms.CheckBox();
|
||||||
|
this.checkNotificationTimer = new System.Windows.Forms.CheckBox();
|
||||||
|
this.toolTip = new System.Windows.Forms.ToolTip(this.components);
|
||||||
|
this.radioSizeAuto = new System.Windows.Forms.RadioButton();
|
||||||
|
this.radioSizeCustom = new System.Windows.Forms.RadioButton();
|
||||||
|
this.labelGeneral = new System.Windows.Forms.Label();
|
||||||
|
this.panelGeneral = new System.Windows.Forms.Panel();
|
||||||
|
this.labelScrollSpeedValue = new System.Windows.Forms.Label();
|
||||||
|
this.trackBarScrollSpeed = new System.Windows.Forms.TrackBar();
|
||||||
|
this.labelScrollSpeed = new System.Windows.Forms.Label();
|
||||||
|
this.labelLocation = new System.Windows.Forms.Label();
|
||||||
|
this.panelLocation = new System.Windows.Forms.Panel();
|
||||||
|
this.panelTimer = new System.Windows.Forms.Panel();
|
||||||
|
this.labelDuration = new System.Windows.Forms.Label();
|
||||||
|
this.labelTimer = new System.Windows.Forms.Label();
|
||||||
|
this.labelSize = new System.Windows.Forms.Label();
|
||||||
|
this.panelMiscellaneous = new System.Windows.Forms.Panel();
|
||||||
|
this.durationUpdateTimer = new System.Windows.Forms.Timer(this.components);
|
||||||
|
this.checkMediaPreviews = new System.Windows.Forms.CheckBox();
|
||||||
|
((System.ComponentModel.ISupportInitialize)(this.trackBarEdgeDistance)).BeginInit();
|
||||||
|
this.tableLayoutDurationButtons.SuspendLayout();
|
||||||
|
((System.ComponentModel.ISupportInitialize)(this.trackBarDuration)).BeginInit();
|
||||||
|
this.panelGeneral.SuspendLayout();
|
||||||
|
((System.ComponentModel.ISupportInitialize)(this.trackBarScrollSpeed)).BeginInit();
|
||||||
|
this.panelLocation.SuspendLayout();
|
||||||
|
this.panelTimer.SuspendLayout();
|
||||||
|
this.panelMiscellaneous.SuspendLayout();
|
||||||
|
this.SuspendLayout();
|
||||||
|
//
|
||||||
|
// labelEdgeDistanceValue
|
||||||
|
//
|
||||||
|
this.labelEdgeDistanceValue.Location = new System.Drawing.Point(147, 129);
|
||||||
|
this.labelEdgeDistanceValue.Margin = new System.Windows.Forms.Padding(0, 0, 3, 0);
|
||||||
|
this.labelEdgeDistanceValue.Name = "labelEdgeDistanceValue";
|
||||||
|
this.labelEdgeDistanceValue.Size = new System.Drawing.Size(34, 13);
|
||||||
|
this.labelEdgeDistanceValue.TabIndex = 9;
|
||||||
|
this.labelEdgeDistanceValue.Text = "0 px";
|
||||||
|
this.labelEdgeDistanceValue.TextAlign = System.Drawing.ContentAlignment.TopRight;
|
||||||
|
//
|
||||||
|
// labelDisplay
|
||||||
|
//
|
||||||
|
this.labelDisplay.AutoSize = true;
|
||||||
|
this.labelDisplay.Location = new System.Drawing.Point(3, 60);
|
||||||
|
this.labelDisplay.Margin = new System.Windows.Forms.Padding(3, 12, 3, 0);
|
||||||
|
this.labelDisplay.Name = "labelDisplay";
|
||||||
|
this.labelDisplay.Size = new System.Drawing.Size(41, 13);
|
||||||
|
this.labelDisplay.TabIndex = 5;
|
||||||
|
this.labelDisplay.Text = "Display";
|
||||||
|
//
|
||||||
|
// comboBoxDisplay
|
||||||
|
//
|
||||||
|
this.comboBoxDisplay.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left)
|
||||||
|
| System.Windows.Forms.AnchorStyles.Right)));
|
||||||
|
this.comboBoxDisplay.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList;
|
||||||
|
this.comboBoxDisplay.FormattingEnabled = true;
|
||||||
|
this.comboBoxDisplay.Location = new System.Drawing.Point(5, 76);
|
||||||
|
this.comboBoxDisplay.Margin = new System.Windows.Forms.Padding(5, 3, 3, 3);
|
||||||
|
this.comboBoxDisplay.Name = "comboBoxDisplay";
|
||||||
|
this.comboBoxDisplay.Size = new System.Drawing.Size(144, 21);
|
||||||
|
this.comboBoxDisplay.TabIndex = 6;
|
||||||
|
//
|
||||||
|
// labelEdgeDistance
|
||||||
|
//
|
||||||
|
this.labelEdgeDistance.AutoSize = true;
|
||||||
|
this.labelEdgeDistance.Location = new System.Drawing.Point(3, 112);
|
||||||
|
this.labelEdgeDistance.Margin = new System.Windows.Forms.Padding(3, 12, 3, 0);
|
||||||
|
this.labelEdgeDistance.Name = "labelEdgeDistance";
|
||||||
|
this.labelEdgeDistance.Size = new System.Drawing.Size(103, 13);
|
||||||
|
this.labelEdgeDistance.TabIndex = 7;
|
||||||
|
this.labelEdgeDistance.Text = "Distance From Edge";
|
||||||
|
//
|
||||||
|
// radioLocCustom
|
||||||
|
//
|
||||||
|
this.radioLocCustom.Location = new System.Drawing.Point(205, 4);
|
||||||
|
this.radioLocCustom.Margin = new System.Windows.Forms.Padding(5, 4, 3, 3);
|
||||||
|
this.radioLocCustom.Name = "radioLocCustom";
|
||||||
|
this.radioLocCustom.Size = new System.Drawing.Size(65, 41);
|
||||||
|
this.radioLocCustom.TabIndex = 4;
|
||||||
|
this.radioLocCustom.TabStop = true;
|
||||||
|
this.radioLocCustom.Text = "Custom";
|
||||||
|
this.toolTip.SetToolTip(this.radioLocCustom, "Drag the example notification window to the desired location.");
|
||||||
|
this.radioLocCustom.UseVisualStyleBackColor = true;
|
||||||
|
//
|
||||||
|
// radioLocBR
|
||||||
|
//
|
||||||
|
this.radioLocBR.Location = new System.Drawing.Point(105, 28);
|
||||||
|
this.radioLocBR.Margin = new System.Windows.Forms.Padding(5, 4, 3, 3);
|
||||||
|
this.radioLocBR.Name = "radioLocBR";
|
||||||
|
this.radioLocBR.Size = new System.Drawing.Size(92, 17);
|
||||||
|
this.radioLocBR.TabIndex = 3;
|
||||||
|
this.radioLocBR.TabStop = true;
|
||||||
|
this.radioLocBR.Text = "Bottom Right";
|
||||||
|
this.radioLocBR.UseVisualStyleBackColor = true;
|
||||||
|
//
|
||||||
|
// radioLocBL
|
||||||
|
//
|
||||||
|
this.radioLocBL.Location = new System.Drawing.Point(5, 28);
|
||||||
|
this.radioLocBL.Margin = new System.Windows.Forms.Padding(5, 4, 3, 3);
|
||||||
|
this.radioLocBL.Name = "radioLocBL";
|
||||||
|
this.radioLocBL.Size = new System.Drawing.Size(92, 17);
|
||||||
|
this.radioLocBL.TabIndex = 2;
|
||||||
|
this.radioLocBL.TabStop = true;
|
||||||
|
this.radioLocBL.Text = "Bottom Left";
|
||||||
|
this.radioLocBL.UseVisualStyleBackColor = true;
|
||||||
|
//
|
||||||
|
// radioLocTR
|
||||||
|
//
|
||||||
|
this.radioLocTR.Location = new System.Drawing.Point(105, 4);
|
||||||
|
this.radioLocTR.Margin = new System.Windows.Forms.Padding(5, 4, 3, 3);
|
||||||
|
this.radioLocTR.Name = "radioLocTR";
|
||||||
|
this.radioLocTR.Size = new System.Drawing.Size(92, 17);
|
||||||
|
this.radioLocTR.TabIndex = 1;
|
||||||
|
this.radioLocTR.TabStop = true;
|
||||||
|
this.radioLocTR.Text = "Top Right";
|
||||||
|
this.radioLocTR.UseVisualStyleBackColor = true;
|
||||||
|
//
|
||||||
|
// radioLocTL
|
||||||
|
//
|
||||||
|
this.radioLocTL.Location = new System.Drawing.Point(5, 4);
|
||||||
|
this.radioLocTL.Margin = new System.Windows.Forms.Padding(5, 4, 3, 3);
|
||||||
|
this.radioLocTL.Name = "radioLocTL";
|
||||||
|
this.radioLocTL.Size = new System.Drawing.Size(92, 17);
|
||||||
|
this.radioLocTL.TabIndex = 0;
|
||||||
|
this.radioLocTL.TabStop = true;
|
||||||
|
this.radioLocTL.Text = "Top Left";
|
||||||
|
this.radioLocTL.UseVisualStyleBackColor = true;
|
||||||
|
//
|
||||||
|
// trackBarEdgeDistance
|
||||||
|
//
|
||||||
|
this.trackBarEdgeDistance.AutoSize = false;
|
||||||
|
this.trackBarEdgeDistance.LargeChange = 8;
|
||||||
|
this.trackBarEdgeDistance.Location = new System.Drawing.Point(5, 128);
|
||||||
|
this.trackBarEdgeDistance.Maximum = 40;
|
||||||
|
this.trackBarEdgeDistance.Minimum = 8;
|
||||||
|
this.trackBarEdgeDistance.Name = "trackBarEdgeDistance";
|
||||||
|
this.trackBarEdgeDistance.Size = new System.Drawing.Size(148, 30);
|
||||||
|
this.trackBarEdgeDistance.SmallChange = 2;
|
||||||
|
this.trackBarEdgeDistance.TabIndex = 8;
|
||||||
|
this.trackBarEdgeDistance.TickFrequency = 4;
|
||||||
|
this.trackBarEdgeDistance.Value = 8;
|
||||||
|
//
|
||||||
|
// tableLayoutDurationButtons
|
||||||
|
//
|
||||||
|
this.tableLayoutDurationButtons.ColumnCount = 3;
|
||||||
|
this.tableLayoutDurationButtons.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 32F));
|
||||||
|
this.tableLayoutDurationButtons.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 36F));
|
||||||
|
this.tableLayoutDurationButtons.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 32F));
|
||||||
|
this.tableLayoutDurationButtons.Controls.Add(this.btnDurationMedium, 0, 0);
|
||||||
|
this.tableLayoutDurationButtons.Controls.Add(this.btnDurationLong, 1, 0);
|
||||||
|
this.tableLayoutDurationButtons.Controls.Add(this.btnDurationShort, 0, 0);
|
||||||
|
this.tableLayoutDurationButtons.Location = new System.Drawing.Point(3, 113);
|
||||||
|
this.tableLayoutDurationButtons.Name = "tableLayoutDurationButtons";
|
||||||
|
this.tableLayoutDurationButtons.RowCount = 1;
|
||||||
|
this.tableLayoutDurationButtons.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 100F));
|
||||||
|
this.tableLayoutDurationButtons.Size = new System.Drawing.Size(171, 27);
|
||||||
|
this.tableLayoutDurationButtons.TabIndex = 5;
|
||||||
|
//
|
||||||
|
// btnDurationMedium
|
||||||
|
//
|
||||||
|
this.btnDurationMedium.Dock = System.Windows.Forms.DockStyle.Fill;
|
||||||
|
this.btnDurationMedium.FlatAppearance.BorderColor = System.Drawing.Color.Gray;
|
||||||
|
this.btnDurationMedium.FlatAppearance.MouseDownBackColor = System.Drawing.SystemColors.ControlLight;
|
||||||
|
this.btnDurationMedium.FlatAppearance.MouseOverBackColor = System.Drawing.Color.White;
|
||||||
|
this.btnDurationMedium.FlatStyle = System.Windows.Forms.FlatStyle.Flat;
|
||||||
|
this.btnDurationMedium.Location = new System.Drawing.Point(55, 1);
|
||||||
|
this.btnDurationMedium.Margin = new System.Windows.Forms.Padding(1);
|
||||||
|
this.btnDurationMedium.Name = "btnDurationMedium";
|
||||||
|
this.btnDurationMedium.Size = new System.Drawing.Size(59, 25);
|
||||||
|
this.btnDurationMedium.TabIndex = 1;
|
||||||
|
this.btnDurationMedium.Text = "Medium";
|
||||||
|
this.btnDurationMedium.UseVisualStyleBackColor = true;
|
||||||
|
//
|
||||||
|
// btnDurationLong
|
||||||
|
//
|
||||||
|
this.btnDurationLong.Dock = System.Windows.Forms.DockStyle.Fill;
|
||||||
|
this.btnDurationLong.FlatAppearance.BorderColor = System.Drawing.Color.Gray;
|
||||||
|
this.btnDurationLong.FlatAppearance.MouseDownBackColor = System.Drawing.SystemColors.ControlLight;
|
||||||
|
this.btnDurationLong.FlatAppearance.MouseOverBackColor = System.Drawing.Color.White;
|
||||||
|
this.btnDurationLong.FlatStyle = System.Windows.Forms.FlatStyle.Flat;
|
||||||
|
this.btnDurationLong.Location = new System.Drawing.Point(116, 1);
|
||||||
|
this.btnDurationLong.Margin = new System.Windows.Forms.Padding(1);
|
||||||
|
this.btnDurationLong.Name = "btnDurationLong";
|
||||||
|
this.btnDurationLong.Size = new System.Drawing.Size(54, 25);
|
||||||
|
this.btnDurationLong.TabIndex = 2;
|
||||||
|
this.btnDurationLong.Text = "Long";
|
||||||
|
this.btnDurationLong.UseVisualStyleBackColor = true;
|
||||||
|
//
|
||||||
|
// btnDurationShort
|
||||||
|
//
|
||||||
|
this.btnDurationShort.Dock = System.Windows.Forms.DockStyle.Fill;
|
||||||
|
this.btnDurationShort.FlatAppearance.BorderColor = System.Drawing.Color.Gray;
|
||||||
|
this.btnDurationShort.FlatAppearance.MouseDownBackColor = System.Drawing.SystemColors.ControlLight;
|
||||||
|
this.btnDurationShort.FlatAppearance.MouseOverBackColor = System.Drawing.Color.White;
|
||||||
|
this.btnDurationShort.FlatStyle = System.Windows.Forms.FlatStyle.Flat;
|
||||||
|
this.btnDurationShort.Location = new System.Drawing.Point(1, 1);
|
||||||
|
this.btnDurationShort.Margin = new System.Windows.Forms.Padding(1);
|
||||||
|
this.btnDurationShort.Name = "btnDurationShort";
|
||||||
|
this.btnDurationShort.Size = new System.Drawing.Size(52, 25);
|
||||||
|
this.btnDurationShort.TabIndex = 0;
|
||||||
|
this.btnDurationShort.Text = "Short";
|
||||||
|
this.btnDurationShort.UseVisualStyleBackColor = true;
|
||||||
|
//
|
||||||
|
// labelDurationValue
|
||||||
|
//
|
||||||
|
this.labelDurationValue.BackColor = System.Drawing.Color.Transparent;
|
||||||
|
this.labelDurationValue.Location = new System.Drawing.Point(147, 77);
|
||||||
|
this.labelDurationValue.Margin = new System.Windows.Forms.Padding(0, 0, 3, 0);
|
||||||
|
this.labelDurationValue.Name = "labelDurationValue";
|
||||||
|
this.labelDurationValue.Size = new System.Drawing.Size(48, 13);
|
||||||
|
this.labelDurationValue.TabIndex = 4;
|
||||||
|
this.labelDurationValue.Text = "0 ms/c";
|
||||||
|
this.labelDurationValue.TextAlign = System.Drawing.ContentAlignment.TopRight;
|
||||||
|
this.toolTip.SetToolTip(this.labelDurationValue, "Milliseconds per character.");
|
||||||
|
//
|
||||||
|
// trackBarDuration
|
||||||
|
//
|
||||||
|
this.trackBarDuration.AutoSize = false;
|
||||||
|
this.trackBarDuration.Location = new System.Drawing.Point(3, 76);
|
||||||
|
this.trackBarDuration.Maximum = 60;
|
||||||
|
this.trackBarDuration.Minimum = 10;
|
||||||
|
this.trackBarDuration.Name = "trackBarDuration";
|
||||||
|
this.trackBarDuration.Size = new System.Drawing.Size(148, 30);
|
||||||
|
this.trackBarDuration.TabIndex = 3;
|
||||||
|
this.trackBarDuration.TickFrequency = 5;
|
||||||
|
this.trackBarDuration.Value = 25;
|
||||||
|
//
|
||||||
|
// checkSkipOnLinkClick
|
||||||
|
//
|
||||||
|
this.checkSkipOnLinkClick.AutoSize = true;
|
||||||
|
this.checkSkipOnLinkClick.Location = new System.Drawing.Point(6, 51);
|
||||||
|
this.checkSkipOnLinkClick.Margin = new System.Windows.Forms.Padding(6, 3, 3, 3);
|
||||||
|
this.checkSkipOnLinkClick.Name = "checkSkipOnLinkClick";
|
||||||
|
this.checkSkipOnLinkClick.Size = new System.Drawing.Size(113, 17);
|
||||||
|
this.checkSkipOnLinkClick.TabIndex = 2;
|
||||||
|
this.checkSkipOnLinkClick.Text = "Skip On Link Click";
|
||||||
|
this.toolTip.SetToolTip(this.checkSkipOnLinkClick, "Skips current notification when a link\r\ninside the notification is clicked.");
|
||||||
|
this.checkSkipOnLinkClick.UseVisualStyleBackColor = true;
|
||||||
|
//
|
||||||
|
// checkColumnName
|
||||||
|
//
|
||||||
|
this.checkColumnName.AutoSize = true;
|
||||||
|
this.checkColumnName.Location = new System.Drawing.Point(6, 5);
|
||||||
|
this.checkColumnName.Margin = new System.Windows.Forms.Padding(6, 5, 3, 3);
|
||||||
|
this.checkColumnName.Name = "checkColumnName";
|
||||||
|
this.checkColumnName.Size = new System.Drawing.Size(129, 17);
|
||||||
|
this.checkColumnName.TabIndex = 0;
|
||||||
|
this.checkColumnName.Text = "Display Column Name";
|
||||||
|
this.toolTip.SetToolTip(this.checkColumnName, "Shows column name each notification originated\r\nfrom in the notification window title.");
|
||||||
|
this.checkColumnName.UseVisualStyleBackColor = true;
|
||||||
|
//
|
||||||
|
// labelIdlePause
|
||||||
|
//
|
||||||
|
this.labelIdlePause.AutoSize = true;
|
||||||
|
this.labelIdlePause.Location = new System.Drawing.Point(3, 106);
|
||||||
|
this.labelIdlePause.Margin = new System.Windows.Forms.Padding(3, 12, 3, 0);
|
||||||
|
this.labelIdlePause.Name = "labelIdlePause";
|
||||||
|
this.labelIdlePause.Size = new System.Drawing.Size(89, 13);
|
||||||
|
this.labelIdlePause.TabIndex = 4;
|
||||||
|
this.labelIdlePause.Text = "Pause When Idle";
|
||||||
|
//
|
||||||
|
// comboBoxIdlePause
|
||||||
|
//
|
||||||
|
this.comboBoxIdlePause.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList;
|
||||||
|
this.comboBoxIdlePause.FormattingEnabled = true;
|
||||||
|
this.comboBoxIdlePause.Location = new System.Drawing.Point(5, 122);
|
||||||
|
this.comboBoxIdlePause.Margin = new System.Windows.Forms.Padding(5, 3, 3, 3);
|
||||||
|
this.comboBoxIdlePause.Name = "comboBoxIdlePause";
|
||||||
|
this.comboBoxIdlePause.Size = new System.Drawing.Size(144, 21);
|
||||||
|
this.comboBoxIdlePause.TabIndex = 5;
|
||||||
|
this.toolTip.SetToolTip(this.comboBoxIdlePause, "Pauses new notifications after going idle for a set amount of time.");
|
||||||
|
//
|
||||||
|
// checkNonIntrusive
|
||||||
|
//
|
||||||
|
this.checkNonIntrusive.AutoSize = true;
|
||||||
|
this.checkNonIntrusive.Location = new System.Drawing.Point(6, 74);
|
||||||
|
this.checkNonIntrusive.Margin = new System.Windows.Forms.Padding(6, 3, 3, 3);
|
||||||
|
this.checkNonIntrusive.Name = "checkNonIntrusive";
|
||||||
|
this.checkNonIntrusive.Size = new System.Drawing.Size(128, 17);
|
||||||
|
this.checkNonIntrusive.TabIndex = 3;
|
||||||
|
this.checkNonIntrusive.Text = "Non-Intrusive Popups";
|
||||||
|
this.toolTip.SetToolTip(this.checkNonIntrusive, "When not idle and the cursor is within the notification window area,\r\nit will be delayed until the cursor moves away to prevent accidental clicks.");
|
||||||
|
this.checkNonIntrusive.UseVisualStyleBackColor = true;
|
||||||
|
//
|
||||||
|
// checkTimerCountDown
|
||||||
|
//
|
||||||
|
this.checkTimerCountDown.AutoSize = true;
|
||||||
|
this.checkTimerCountDown.Location = new System.Drawing.Point(6, 28);
|
||||||
|
this.checkTimerCountDown.Margin = new System.Windows.Forms.Padding(6, 3, 3, 3);
|
||||||
|
this.checkTimerCountDown.Name = "checkTimerCountDown";
|
||||||
|
this.checkTimerCountDown.Size = new System.Drawing.Size(119, 17);
|
||||||
|
this.checkTimerCountDown.TabIndex = 1;
|
||||||
|
this.checkTimerCountDown.Text = "Timer Counts Down";
|
||||||
|
this.toolTip.SetToolTip(this.checkTimerCountDown, "The notification timer counts down instead of up.");
|
||||||
|
this.checkTimerCountDown.UseVisualStyleBackColor = true;
|
||||||
|
//
|
||||||
|
// checkNotificationTimer
|
||||||
|
//
|
||||||
|
this.checkNotificationTimer.AutoSize = true;
|
||||||
|
this.checkNotificationTimer.Location = new System.Drawing.Point(6, 5);
|
||||||
|
this.checkNotificationTimer.Margin = new System.Windows.Forms.Padding(6, 5, 3, 3);
|
||||||
|
this.checkNotificationTimer.Name = "checkNotificationTimer";
|
||||||
|
this.checkNotificationTimer.Size = new System.Drawing.Size(145, 17);
|
||||||
|
this.checkNotificationTimer.TabIndex = 0;
|
||||||
|
this.checkNotificationTimer.Text = "Display Notification Timer";
|
||||||
|
this.checkNotificationTimer.UseVisualStyleBackColor = true;
|
||||||
|
//
|
||||||
|
// radioSizeAuto
|
||||||
|
//
|
||||||
|
this.radioSizeAuto.Location = new System.Drawing.Point(6, 4);
|
||||||
|
this.radioSizeAuto.Margin = new System.Windows.Forms.Padding(5, 4, 3, 3);
|
||||||
|
this.radioSizeAuto.Name = "radioSizeAuto";
|
||||||
|
this.radioSizeAuto.Size = new System.Drawing.Size(92, 17);
|
||||||
|
this.radioSizeAuto.TabIndex = 0;
|
||||||
|
this.radioSizeAuto.TabStop = true;
|
||||||
|
this.radioSizeAuto.Text = "Auto";
|
||||||
|
this.toolTip.SetToolTip(this.radioSizeAuto, "Notification size is based on the font size and browser zoom level.");
|
||||||
|
this.radioSizeAuto.UseVisualStyleBackColor = true;
|
||||||
|
//
|
||||||
|
// radioSizeCustom
|
||||||
|
//
|
||||||
|
this.radioSizeCustom.Location = new System.Drawing.Point(106, 4);
|
||||||
|
this.radioSizeCustom.Margin = new System.Windows.Forms.Padding(5, 4, 3, 3);
|
||||||
|
this.radioSizeCustom.Name = "radioSizeCustom";
|
||||||
|
this.radioSizeCustom.Size = new System.Drawing.Size(92, 17);
|
||||||
|
this.radioSizeCustom.TabIndex = 1;
|
||||||
|
this.radioSizeCustom.TabStop = true;
|
||||||
|
this.radioSizeCustom.Text = "Custom";
|
||||||
|
this.toolTip.SetToolTip(this.radioSizeCustom, "Resize the example notification window to the desired size.");
|
||||||
|
this.radioSizeCustom.UseVisualStyleBackColor = true;
|
||||||
|
//
|
||||||
|
// labelGeneral
|
||||||
|
//
|
||||||
|
this.labelGeneral.AutoSize = true;
|
||||||
|
this.labelGeneral.Font = new System.Drawing.Font("Microsoft Sans Serif", 12F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(238)));
|
||||||
|
this.labelGeneral.Location = new System.Drawing.Point(6, 8);
|
||||||
|
this.labelGeneral.Margin = new System.Windows.Forms.Padding(0, 2, 0, 0);
|
||||||
|
this.labelGeneral.Name = "labelGeneral";
|
||||||
|
this.labelGeneral.Size = new System.Drawing.Size(66, 20);
|
||||||
|
this.labelGeneral.TabIndex = 0;
|
||||||
|
this.labelGeneral.Text = "General";
|
||||||
|
//
|
||||||
|
// panelGeneral
|
||||||
|
//
|
||||||
|
this.panelGeneral.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left)
|
||||||
|
| System.Windows.Forms.AnchorStyles.Right)));
|
||||||
|
this.panelGeneral.Controls.Add(this.checkMediaPreviews);
|
||||||
|
this.panelGeneral.Controls.Add(this.checkColumnName);
|
||||||
|
this.panelGeneral.Controls.Add(this.checkSkipOnLinkClick);
|
||||||
|
this.panelGeneral.Controls.Add(this.checkNonIntrusive);
|
||||||
|
this.panelGeneral.Controls.Add(this.labelIdlePause);
|
||||||
|
this.panelGeneral.Controls.Add(this.comboBoxIdlePause);
|
||||||
|
this.panelGeneral.Location = new System.Drawing.Point(9, 31);
|
||||||
|
this.panelGeneral.Name = "panelGeneral";
|
||||||
|
this.panelGeneral.Size = new System.Drawing.Size(322, 149);
|
||||||
|
this.panelGeneral.TabIndex = 1;
|
||||||
|
//
|
||||||
|
// labelScrollSpeedValue
|
||||||
|
//
|
||||||
|
this.labelScrollSpeedValue.Location = new System.Drawing.Point(147, 53);
|
||||||
|
this.labelScrollSpeedValue.Margin = new System.Windows.Forms.Padding(0, 0, 3, 0);
|
||||||
|
this.labelScrollSpeedValue.Name = "labelScrollSpeedValue";
|
||||||
|
this.labelScrollSpeedValue.Size = new System.Drawing.Size(34, 13);
|
||||||
|
this.labelScrollSpeedValue.TabIndex = 4;
|
||||||
|
this.labelScrollSpeedValue.Text = "100%";
|
||||||
|
this.labelScrollSpeedValue.TextAlign = System.Drawing.ContentAlignment.TopRight;
|
||||||
|
//
|
||||||
|
// trackBarScrollSpeed
|
||||||
|
//
|
||||||
|
this.trackBarScrollSpeed.AutoSize = false;
|
||||||
|
this.trackBarScrollSpeed.LargeChange = 25;
|
||||||
|
this.trackBarScrollSpeed.Location = new System.Drawing.Point(5, 52);
|
||||||
|
this.trackBarScrollSpeed.Maximum = 200;
|
||||||
|
this.trackBarScrollSpeed.Minimum = 25;
|
||||||
|
this.trackBarScrollSpeed.Name = "trackBarScrollSpeed";
|
||||||
|
this.trackBarScrollSpeed.Size = new System.Drawing.Size(148, 30);
|
||||||
|
this.trackBarScrollSpeed.SmallChange = 5;
|
||||||
|
this.trackBarScrollSpeed.TabIndex = 3;
|
||||||
|
this.trackBarScrollSpeed.TickFrequency = 25;
|
||||||
|
this.trackBarScrollSpeed.Value = 100;
|
||||||
|
//
|
||||||
|
// labelScrollSpeed
|
||||||
|
//
|
||||||
|
this.labelScrollSpeed.AutoSize = true;
|
||||||
|
this.labelScrollSpeed.Location = new System.Drawing.Point(3, 36);
|
||||||
|
this.labelScrollSpeed.Margin = new System.Windows.Forms.Padding(3, 12, 3, 0);
|
||||||
|
this.labelScrollSpeed.Name = "labelScrollSpeed";
|
||||||
|
this.labelScrollSpeed.Size = new System.Drawing.Size(67, 13);
|
||||||
|
this.labelScrollSpeed.TabIndex = 2;
|
||||||
|
this.labelScrollSpeed.Text = "Scroll Speed";
|
||||||
|
//
|
||||||
|
// labelLocation
|
||||||
|
//
|
||||||
|
this.labelLocation.AutoSize = true;
|
||||||
|
this.labelLocation.Font = new System.Drawing.Font("Microsoft Sans Serif", 12F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(238)));
|
||||||
|
this.labelLocation.Location = new System.Drawing.Point(6, 395);
|
||||||
|
this.labelLocation.Margin = new System.Windows.Forms.Padding(0, 21, 0, 0);
|
||||||
|
this.labelLocation.Name = "labelLocation";
|
||||||
|
this.labelLocation.Size = new System.Drawing.Size(70, 20);
|
||||||
|
this.labelLocation.TabIndex = 4;
|
||||||
|
this.labelLocation.Text = "Location";
|
||||||
|
//
|
||||||
|
// panelLocation
|
||||||
|
//
|
||||||
|
this.panelLocation.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left)
|
||||||
|
| System.Windows.Forms.AnchorStyles.Right)));
|
||||||
|
this.panelLocation.Controls.Add(this.labelEdgeDistanceValue);
|
||||||
|
this.panelLocation.Controls.Add(this.radioLocTL);
|
||||||
|
this.panelLocation.Controls.Add(this.labelDisplay);
|
||||||
|
this.panelLocation.Controls.Add(this.trackBarEdgeDistance);
|
||||||
|
this.panelLocation.Controls.Add(this.comboBoxDisplay);
|
||||||
|
this.panelLocation.Controls.Add(this.radioLocTR);
|
||||||
|
this.panelLocation.Controls.Add(this.labelEdgeDistance);
|
||||||
|
this.panelLocation.Controls.Add(this.radioLocBL);
|
||||||
|
this.panelLocation.Controls.Add(this.radioLocCustom);
|
||||||
|
this.panelLocation.Controls.Add(this.radioLocBR);
|
||||||
|
this.panelLocation.Location = new System.Drawing.Point(9, 418);
|
||||||
|
this.panelLocation.Name = "panelLocation";
|
||||||
|
this.panelLocation.Size = new System.Drawing.Size(322, 165);
|
||||||
|
this.panelLocation.TabIndex = 5;
|
||||||
|
//
|
||||||
|
// panelTimer
|
||||||
|
//
|
||||||
|
this.panelTimer.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left)
|
||||||
|
| System.Windows.Forms.AnchorStyles.Right)));
|
||||||
|
this.panelTimer.Controls.Add(this.labelDuration);
|
||||||
|
this.panelTimer.Controls.Add(this.checkNotificationTimer);
|
||||||
|
this.panelTimer.Controls.Add(this.tableLayoutDurationButtons);
|
||||||
|
this.panelTimer.Controls.Add(this.checkTimerCountDown);
|
||||||
|
this.panelTimer.Controls.Add(this.labelDurationValue);
|
||||||
|
this.panelTimer.Controls.Add(this.trackBarDuration);
|
||||||
|
this.panelTimer.Location = new System.Drawing.Point(9, 227);
|
||||||
|
this.panelTimer.Name = "panelTimer";
|
||||||
|
this.panelTimer.Size = new System.Drawing.Size(322, 144);
|
||||||
|
this.panelTimer.TabIndex = 3;
|
||||||
|
//
|
||||||
|
// labelDuration
|
||||||
|
//
|
||||||
|
this.labelDuration.AutoSize = true;
|
||||||
|
this.labelDuration.Location = new System.Drawing.Point(3, 60);
|
||||||
|
this.labelDuration.Margin = new System.Windows.Forms.Padding(3, 12, 3, 0);
|
||||||
|
this.labelDuration.Name = "labelDuration";
|
||||||
|
this.labelDuration.Size = new System.Drawing.Size(47, 13);
|
||||||
|
this.labelDuration.TabIndex = 2;
|
||||||
|
this.labelDuration.Text = "Duration";
|
||||||
|
//
|
||||||
|
// labelTimer
|
||||||
|
//
|
||||||
|
this.labelTimer.AutoSize = true;
|
||||||
|
this.labelTimer.Font = new System.Drawing.Font("Microsoft Sans Serif", 12F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(238)));
|
||||||
|
this.labelTimer.Location = new System.Drawing.Point(6, 204);
|
||||||
|
this.labelTimer.Margin = new System.Windows.Forms.Padding(0, 21, 0, 0);
|
||||||
|
this.labelTimer.Name = "labelTimer";
|
||||||
|
this.labelTimer.Size = new System.Drawing.Size(48, 20);
|
||||||
|
this.labelTimer.TabIndex = 2;
|
||||||
|
this.labelTimer.Text = "Timer";
|
||||||
|
//
|
||||||
|
// labelSize
|
||||||
|
//
|
||||||
|
this.labelSize.AutoSize = true;
|
||||||
|
this.labelSize.Font = new System.Drawing.Font("Microsoft Sans Serif", 12F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(238)));
|
||||||
|
this.labelSize.Location = new System.Drawing.Point(6, 607);
|
||||||
|
this.labelSize.Margin = new System.Windows.Forms.Padding(0, 21, 0, 0);
|
||||||
|
this.labelSize.Name = "labelSize";
|
||||||
|
this.labelSize.Size = new System.Drawing.Size(40, 20);
|
||||||
|
this.labelSize.TabIndex = 6;
|
||||||
|
this.labelSize.Text = "Size";
|
||||||
|
//
|
||||||
|
// panelMiscellaneous
|
||||||
|
//
|
||||||
|
this.panelMiscellaneous.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left)
|
||||||
|
| System.Windows.Forms.AnchorStyles.Right)));
|
||||||
|
this.panelMiscellaneous.Controls.Add(this.radioSizeCustom);
|
||||||
|
this.panelMiscellaneous.Controls.Add(this.radioSizeAuto);
|
||||||
|
this.panelMiscellaneous.Controls.Add(this.labelScrollSpeedValue);
|
||||||
|
this.panelMiscellaneous.Controls.Add(this.trackBarScrollSpeed);
|
||||||
|
this.panelMiscellaneous.Controls.Add(this.labelScrollSpeed);
|
||||||
|
this.panelMiscellaneous.Location = new System.Drawing.Point(9, 630);
|
||||||
|
this.panelMiscellaneous.Name = "panelMiscellaneous";
|
||||||
|
this.panelMiscellaneous.Size = new System.Drawing.Size(322, 92);
|
||||||
|
this.panelMiscellaneous.TabIndex = 7;
|
||||||
|
//
|
||||||
|
// durationUpdateTimer
|
||||||
|
//
|
||||||
|
this.durationUpdateTimer.Interval = 200;
|
||||||
|
this.durationUpdateTimer.Tick += new System.EventHandler(this.durationUpdateTimer_Tick);
|
||||||
|
//
|
||||||
|
// checkMediaPreviews
|
||||||
|
//
|
||||||
|
this.checkMediaPreviews.AutoSize = true;
|
||||||
|
this.checkMediaPreviews.Location = new System.Drawing.Point(6, 28);
|
||||||
|
this.checkMediaPreviews.Margin = new System.Windows.Forms.Padding(6, 3, 3, 3);
|
||||||
|
this.checkMediaPreviews.Name = "checkMediaPreviews";
|
||||||
|
this.checkMediaPreviews.Size = new System.Drawing.Size(131, 17);
|
||||||
|
this.checkMediaPreviews.TabIndex = 1;
|
||||||
|
this.checkMediaPreviews.Text = "Show Media Previews";
|
||||||
|
this.toolTip.SetToolTip(this.checkMediaPreviews, "Shows image and video thumbnails in the notification window.");
|
||||||
|
this.checkMediaPreviews.UseVisualStyleBackColor = true;
|
||||||
|
//
|
||||||
|
// TabSettingsNotifications
|
||||||
|
//
|
||||||
|
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
|
||||||
|
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
|
||||||
|
this.Controls.Add(this.panelMiscellaneous);
|
||||||
|
this.Controls.Add(this.labelSize);
|
||||||
|
this.Controls.Add(this.labelTimer);
|
||||||
|
this.Controls.Add(this.panelLocation);
|
||||||
|
this.Controls.Add(this.labelLocation);
|
||||||
|
this.Controls.Add(this.panelGeneral);
|
||||||
|
this.Controls.Add(this.labelGeneral);
|
||||||
|
this.Controls.Add(this.panelTimer);
|
||||||
|
this.Name = "TabSettingsNotifications";
|
||||||
|
this.Size = new System.Drawing.Size(340, 731);
|
||||||
|
this.ParentChanged += new System.EventHandler(this.TabSettingsNotifications_ParentChanged);
|
||||||
|
((System.ComponentModel.ISupportInitialize)(this.trackBarEdgeDistance)).EndInit();
|
||||||
|
this.tableLayoutDurationButtons.ResumeLayout(false);
|
||||||
|
((System.ComponentModel.ISupportInitialize)(this.trackBarDuration)).EndInit();
|
||||||
|
this.panelGeneral.ResumeLayout(false);
|
||||||
|
this.panelGeneral.PerformLayout();
|
||||||
|
((System.ComponentModel.ISupportInitialize)(this.trackBarScrollSpeed)).EndInit();
|
||||||
|
this.panelLocation.ResumeLayout(false);
|
||||||
|
this.panelLocation.PerformLayout();
|
||||||
|
this.panelTimer.ResumeLayout(false);
|
||||||
|
this.panelTimer.PerformLayout();
|
||||||
|
this.panelMiscellaneous.ResumeLayout(false);
|
||||||
|
this.panelMiscellaneous.PerformLayout();
|
||||||
|
this.ResumeLayout(false);
|
||||||
|
this.PerformLayout();
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
private System.Windows.Forms.Label labelDisplay;
|
||||||
|
private System.Windows.Forms.ComboBox comboBoxDisplay;
|
||||||
|
private System.Windows.Forms.Label labelEdgeDistance;
|
||||||
|
private System.Windows.Forms.TrackBar trackBarEdgeDistance;
|
||||||
|
private System.Windows.Forms.RadioButton radioLocCustom;
|
||||||
|
private System.Windows.Forms.RadioButton radioLocBR;
|
||||||
|
private System.Windows.Forms.RadioButton radioLocBL;
|
||||||
|
private System.Windows.Forms.RadioButton radioLocTR;
|
||||||
|
private System.Windows.Forms.RadioButton radioLocTL;
|
||||||
|
private System.Windows.Forms.ToolTip toolTip;
|
||||||
|
private System.Windows.Forms.Label labelEdgeDistanceValue;
|
||||||
|
private System.Windows.Forms.Label labelDurationValue;
|
||||||
|
private System.Windows.Forms.TrackBar trackBarDuration;
|
||||||
|
private System.Windows.Forms.TableLayoutPanel tableLayoutDurationButtons;
|
||||||
|
private TweetDuck.Core.Controls.FlatButton btnDurationMedium;
|
||||||
|
private TweetDuck.Core.Controls.FlatButton btnDurationLong;
|
||||||
|
private TweetDuck.Core.Controls.FlatButton btnDurationShort;
|
||||||
|
private System.Windows.Forms.CheckBox checkNonIntrusive;
|
||||||
|
private System.Windows.Forms.Label labelIdlePause;
|
||||||
|
private System.Windows.Forms.ComboBox comboBoxIdlePause;
|
||||||
|
private System.Windows.Forms.CheckBox checkColumnName;
|
||||||
|
private System.Windows.Forms.CheckBox checkSkipOnLinkClick;
|
||||||
|
private System.Windows.Forms.CheckBox checkTimerCountDown;
|
||||||
|
private System.Windows.Forms.CheckBox checkNotificationTimer;
|
||||||
|
private System.Windows.Forms.Label labelGeneral;
|
||||||
|
private System.Windows.Forms.Panel panelGeneral;
|
||||||
|
private System.Windows.Forms.Label labelLocation;
|
||||||
|
private System.Windows.Forms.Panel panelLocation;
|
||||||
|
private System.Windows.Forms.Panel panelTimer;
|
||||||
|
private System.Windows.Forms.Label labelTimer;
|
||||||
|
private System.Windows.Forms.Label labelScrollSpeedValue;
|
||||||
|
private System.Windows.Forms.TrackBar trackBarScrollSpeed;
|
||||||
|
private System.Windows.Forms.Label labelScrollSpeed;
|
||||||
|
private System.Windows.Forms.Label labelSize;
|
||||||
|
private System.Windows.Forms.Panel panelMiscellaneous;
|
||||||
|
private System.Windows.Forms.Label labelDuration;
|
||||||
|
private System.Windows.Forms.Timer durationUpdateTimer;
|
||||||
|
private System.Windows.Forms.RadioButton radioSizeCustom;
|
||||||
|
private System.Windows.Forms.RadioButton radioSizeAuto;
|
||||||
|
private System.Windows.Forms.CheckBox checkMediaPreviews;
|
||||||
|
}
|
||||||
|
}
|
||||||
262
Core/Other/Settings/TabSettingsNotifications.cs
Normal file
262
Core/Other/Settings/TabSettingsNotifications.cs
Normal file
@@ -0,0 +1,262 @@
|
|||||||
|
using System;
|
||||||
|
using System.Windows.Forms;
|
||||||
|
using TweetDuck.Core.Controls;
|
||||||
|
using TweetDuck.Core.Notification;
|
||||||
|
|
||||||
|
namespace TweetDuck.Core.Other.Settings{
|
||||||
|
partial class TabSettingsNotifications : BaseTabSettings{
|
||||||
|
private static readonly int[] IdlePauseSeconds = { 0, 30, 60, 120, 300 };
|
||||||
|
|
||||||
|
private readonly FormNotificationMain notification;
|
||||||
|
|
||||||
|
public TabSettingsNotifications(FormNotificationMain notification){
|
||||||
|
InitializeComponent();
|
||||||
|
|
||||||
|
this.notification = notification;
|
||||||
|
|
||||||
|
this.notification.Initialized += (sender, args) => {
|
||||||
|
this.InvokeAsyncSafe(() => {
|
||||||
|
this.notification.ShowNotificationForSettings(true);
|
||||||
|
this.notification.Move += notification_Move;
|
||||||
|
this.notification.ResizeEnd += notification_ResizeEnd;
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
this.notification.Activated += notification_Activated;
|
||||||
|
this.notification.Show();
|
||||||
|
|
||||||
|
switch(Config.NotificationPosition){
|
||||||
|
case TweetNotification.Position.TopLeft: radioLocTL.Checked = true; break;
|
||||||
|
case TweetNotification.Position.TopRight: radioLocTR.Checked = true; break;
|
||||||
|
case TweetNotification.Position.BottomLeft: radioLocBL.Checked = true; break;
|
||||||
|
case TweetNotification.Position.BottomRight: radioLocBR.Checked = true; break;
|
||||||
|
case TweetNotification.Position.Custom: radioLocCustom.Checked = true; break;
|
||||||
|
}
|
||||||
|
|
||||||
|
comboBoxDisplay.Enabled = trackBarEdgeDistance.Enabled = !radioLocCustom.Checked;
|
||||||
|
|
||||||
|
switch(Config.NotificationSize){
|
||||||
|
case TweetNotification.Size.Auto: radioSizeAuto.Checked = true; break;
|
||||||
|
case TweetNotification.Size.Custom: radioSizeCustom.Checked = true; break;
|
||||||
|
}
|
||||||
|
|
||||||
|
toolTip.SetToolTip(trackBarDuration, toolTip.GetToolTip(labelDurationValue));
|
||||||
|
trackBarDuration.SetValueSafe(Config.NotificationDurationValue);
|
||||||
|
labelDurationValue.Text = Config.NotificationDurationValue+" ms/c";
|
||||||
|
|
||||||
|
comboBoxIdlePause.Items.Add("Disabled");
|
||||||
|
comboBoxIdlePause.Items.Add("30 seconds");
|
||||||
|
comboBoxIdlePause.Items.Add("1 minute");
|
||||||
|
comboBoxIdlePause.Items.Add("2 minutes");
|
||||||
|
comboBoxIdlePause.Items.Add("5 minutes");
|
||||||
|
comboBoxIdlePause.SelectedIndex = Math.Max(0, Array.FindIndex(IdlePauseSeconds, val => val == Config.NotificationIdlePauseSeconds));
|
||||||
|
|
||||||
|
comboBoxDisplay.Items.Add("(Same as TweetDuck)");
|
||||||
|
|
||||||
|
foreach(Screen screen in Screen.AllScreens){
|
||||||
|
comboBoxDisplay.Items.Add(screen.DeviceName.TrimStart('\\', '.')+" ("+screen.Bounds.Width+"x"+screen.Bounds.Height+")");
|
||||||
|
}
|
||||||
|
|
||||||
|
comboBoxDisplay.SelectedIndex = Math.Min(comboBoxDisplay.Items.Count-1, Config.NotificationDisplay);
|
||||||
|
|
||||||
|
checkColumnName.Checked = Config.DisplayNotificationColumn;
|
||||||
|
checkNotificationTimer.Checked = Config.DisplayNotificationTimer;
|
||||||
|
checkTimerCountDown.Enabled = checkNotificationTimer.Checked;
|
||||||
|
checkTimerCountDown.Checked = Config.NotificationTimerCountDown;
|
||||||
|
checkMediaPreviews.Checked = Config.NotificationMediaPreviews;
|
||||||
|
checkSkipOnLinkClick.Checked = Config.NotificationSkipOnLinkClick;
|
||||||
|
checkNonIntrusive.Checked = Config.NotificationNonIntrusiveMode;
|
||||||
|
|
||||||
|
trackBarScrollSpeed.SetValueSafe(Config.NotificationScrollSpeed);
|
||||||
|
labelScrollSpeedValue.Text = trackBarScrollSpeed.Value+"%";
|
||||||
|
|
||||||
|
trackBarEdgeDistance.SetValueSafe(Config.NotificationEdgeDistance);
|
||||||
|
labelEdgeDistanceValue.Text = trackBarEdgeDistance.Value+" px";
|
||||||
|
|
||||||
|
this.notification.CanMoveWindow = () => radioLocCustom.Checked;
|
||||||
|
this.notification.CanResizeWindow = radioSizeCustom.Checked;
|
||||||
|
|
||||||
|
Disposed += (sender, args) => this.notification.Dispose();
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void OnReady(){
|
||||||
|
radioLocTL.CheckedChanged += radioLoc_CheckedChanged;
|
||||||
|
radioLocTR.CheckedChanged += radioLoc_CheckedChanged;
|
||||||
|
radioLocBL.CheckedChanged += radioLoc_CheckedChanged;
|
||||||
|
radioLocBR.CheckedChanged += radioLoc_CheckedChanged;
|
||||||
|
radioLocCustom.Click += radioLocCustom_Click;
|
||||||
|
|
||||||
|
radioSizeAuto.CheckedChanged += radioSize_CheckedChanged;
|
||||||
|
radioSizeCustom.Click += radioSizeCustom_Click;
|
||||||
|
|
||||||
|
trackBarDuration.ValueChanged += trackBarDuration_ValueChanged;
|
||||||
|
btnDurationShort.Click += btnDurationShort_Click;
|
||||||
|
btnDurationMedium.Click += btnDurationMedium_Click;
|
||||||
|
btnDurationLong.Click += btnDurationLong_Click;
|
||||||
|
|
||||||
|
checkColumnName.CheckedChanged += checkColumnName_CheckedChanged;
|
||||||
|
checkNotificationTimer.CheckedChanged += checkNotificationTimer_CheckedChanged;
|
||||||
|
checkTimerCountDown.CheckedChanged += checkTimerCountDown_CheckedChanged;
|
||||||
|
checkMediaPreviews.CheckedChanged += checkMediaPreviews_CheckedChanged;
|
||||||
|
checkSkipOnLinkClick.CheckedChanged += checkSkipOnLinkClick_CheckedChanged;
|
||||||
|
checkNonIntrusive.CheckedChanged += checkNonIntrusive_CheckedChanged;
|
||||||
|
|
||||||
|
comboBoxIdlePause.SelectedValueChanged += comboBoxIdlePause_SelectedValueChanged;
|
||||||
|
trackBarScrollSpeed.ValueChanged += trackBarScrollSpeed_ValueChanged;
|
||||||
|
|
||||||
|
comboBoxDisplay.SelectedValueChanged += comboBoxDisplay_SelectedValueChanged;
|
||||||
|
trackBarEdgeDistance.ValueChanged += trackBarEdgeDistance_ValueChanged;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void TabSettingsNotifications_ParentChanged(object sender, EventArgs e){
|
||||||
|
if (Parent == null){
|
||||||
|
notification.HideNotification(false);
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
notification.ShowNotificationForSettings(true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void notification_Activated(object sender, EventArgs e){
|
||||||
|
notification.Hide();
|
||||||
|
notification.Activated -= notification_Activated;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void notification_Move(object sender, EventArgs e){
|
||||||
|
if (radioLocCustom.Checked && notification.Location != ControlExtensions.InvisibleLocation){
|
||||||
|
Config.CustomNotificationPosition = notification.Location;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void notification_ResizeEnd(object sender, EventArgs e){
|
||||||
|
if (radioSizeCustom.Checked){
|
||||||
|
Config.CustomNotificationSize = notification.BrowserSize;
|
||||||
|
notification.ShowNotificationForSettings(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void radioLoc_CheckedChanged(object sender, EventArgs e){
|
||||||
|
if (radioLocTL.Checked)Config.NotificationPosition = TweetNotification.Position.TopLeft;
|
||||||
|
else if (radioLocTR.Checked)Config.NotificationPosition = TweetNotification.Position.TopRight;
|
||||||
|
else if (radioLocBL.Checked)Config.NotificationPosition = TweetNotification.Position.BottomLeft;
|
||||||
|
else if (radioLocBR.Checked)Config.NotificationPosition = TweetNotification.Position.BottomRight;
|
||||||
|
|
||||||
|
comboBoxDisplay.Enabled = trackBarEdgeDistance.Enabled = true;
|
||||||
|
notification.ShowNotificationForSettings(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void radioLocCustom_Click(object sender, EventArgs e){
|
||||||
|
if (!Config.IsCustomNotificationPositionSet){
|
||||||
|
Config.CustomNotificationPosition = notification.Location;
|
||||||
|
}
|
||||||
|
|
||||||
|
Config.NotificationPosition = TweetNotification.Position.Custom;
|
||||||
|
|
||||||
|
comboBoxDisplay.Enabled = trackBarEdgeDistance.Enabled = false;
|
||||||
|
notification.ShowNotificationForSettings(false);
|
||||||
|
|
||||||
|
if (notification.IsFullyOutsideView() && FormMessage.Question("Notification is outside view", "The notification seems to be outside of view, would you like to reset its position?", FormMessage.Yes, FormMessage.No)){
|
||||||
|
Config.NotificationPosition = TweetNotification.Position.TopRight;
|
||||||
|
notification.MoveToVisibleLocation();
|
||||||
|
|
||||||
|
Config.CustomNotificationPosition = notification.Location;
|
||||||
|
|
||||||
|
Config.NotificationPosition = TweetNotification.Position.Custom;
|
||||||
|
notification.MoveToVisibleLocation();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void radioSize_CheckedChanged(object sender, EventArgs e){
|
||||||
|
if (radioSizeAuto.Checked)Config.NotificationSize = TweetNotification.Size.Auto;
|
||||||
|
|
||||||
|
notification.ShowNotificationForSettings(false);
|
||||||
|
notification.CanResizeWindow = false; // must be after ShowNotificationForSettings
|
||||||
|
}
|
||||||
|
|
||||||
|
private void radioSizeCustom_Click(object sender, EventArgs e){
|
||||||
|
if (!Config.IsCustomNotificationSizeSet){
|
||||||
|
Config.CustomNotificationSize = notification.BrowserSize;
|
||||||
|
}
|
||||||
|
|
||||||
|
Config.NotificationSize = TweetNotification.Size.Custom;
|
||||||
|
|
||||||
|
notification.CanResizeWindow = true;
|
||||||
|
notification.ShowNotificationForSettings(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void trackBarDuration_ValueChanged(object sender, EventArgs e){
|
||||||
|
durationUpdateTimer.Stop();
|
||||||
|
durationUpdateTimer.Start();
|
||||||
|
|
||||||
|
Config.NotificationDurationValue = trackBarDuration.Value;
|
||||||
|
labelDurationValue.Text = Config.NotificationDurationValue+" ms/c";
|
||||||
|
}
|
||||||
|
|
||||||
|
private void btnDurationShort_Click(object sender, EventArgs e){
|
||||||
|
trackBarDuration.Value = 15;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void btnDurationMedium_Click(object sender, EventArgs e){
|
||||||
|
trackBarDuration.Value = 25;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void btnDurationLong_Click(object sender, EventArgs e){
|
||||||
|
trackBarDuration.Value = 35;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void checkColumnName_CheckedChanged(object sender, EventArgs e){
|
||||||
|
Config.DisplayNotificationColumn = checkColumnName.Checked;
|
||||||
|
notification.ShowNotificationForSettings(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void checkNotificationTimer_CheckedChanged(object sender, EventArgs e){
|
||||||
|
Config.DisplayNotificationTimer = checkNotificationTimer.Checked;
|
||||||
|
checkTimerCountDown.Enabled = checkNotificationTimer.Checked;
|
||||||
|
notification.ShowNotificationForSettings(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void checkTimerCountDown_CheckedChanged(object sender, EventArgs e){
|
||||||
|
Config.NotificationTimerCountDown = checkTimerCountDown.Checked;
|
||||||
|
notification.ShowNotificationForSettings(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void checkMediaPreviews_CheckedChanged(object sender, EventArgs e){
|
||||||
|
Config.NotificationMediaPreviews = checkMediaPreviews.Checked;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void checkSkipOnLinkClick_CheckedChanged(object sender, EventArgs e){
|
||||||
|
Config.NotificationSkipOnLinkClick = checkSkipOnLinkClick.Checked;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void checkNonIntrusive_CheckedChanged(object sender, EventArgs e){
|
||||||
|
Config.NotificationNonIntrusiveMode = checkNonIntrusive.Checked;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void comboBoxIdlePause_SelectedValueChanged(object sender, EventArgs e){
|
||||||
|
Config.NotificationIdlePauseSeconds = IdlePauseSeconds[comboBoxIdlePause.SelectedIndex];
|
||||||
|
}
|
||||||
|
|
||||||
|
private void trackBarScrollSpeed_ValueChanged(object sender, EventArgs e){
|
||||||
|
if (trackBarScrollSpeed.AlignValueToTick()){
|
||||||
|
labelScrollSpeedValue.Text = trackBarScrollSpeed.Value+"%";
|
||||||
|
Config.NotificationScrollSpeed = trackBarScrollSpeed.Value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void comboBoxDisplay_SelectedValueChanged(object sender, EventArgs e){
|
||||||
|
Config.NotificationDisplay = comboBoxDisplay.SelectedIndex;
|
||||||
|
notification.ShowNotificationForSettings(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void trackBarEdgeDistance_ValueChanged(object sender, EventArgs e){
|
||||||
|
labelEdgeDistanceValue.Text = trackBarEdgeDistance.Value+" px";
|
||||||
|
Config.NotificationEdgeDistance = trackBarEdgeDistance.Value;
|
||||||
|
notification.ShowNotificationForSettings(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void durationUpdateTimer_Tick(object sender, EventArgs e){
|
||||||
|
notification.ShowNotificationForSettings(true);
|
||||||
|
durationUpdateTimer.Stop();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
131
Core/Other/Settings/TabSettingsSounds.Designer.cs
generated
Normal file
131
Core/Other/Settings/TabSettingsSounds.Designer.cs
generated
Normal file
@@ -0,0 +1,131 @@
|
|||||||
|
namespace TweetDuck.Core.Other.Settings {
|
||||||
|
partial class TabSettingsSounds {
|
||||||
|
/// <summary>
|
||||||
|
/// Required designer variable.
|
||||||
|
/// </summary>
|
||||||
|
private System.ComponentModel.IContainer components = null;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Clean up any resources being used.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
|
||||||
|
protected override void Dispose(bool disposing) {
|
||||||
|
if (disposing && (components != null)) {
|
||||||
|
components.Dispose();
|
||||||
|
}
|
||||||
|
base.Dispose(disposing);
|
||||||
|
}
|
||||||
|
|
||||||
|
#region Component Designer generated code
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Required method for Designer support - do not modify
|
||||||
|
/// the contents of this method with the code editor.
|
||||||
|
/// </summary>
|
||||||
|
private void InitializeComponent() {
|
||||||
|
this.components = new System.ComponentModel.Container();
|
||||||
|
this.toolTip = new System.Windows.Forms.ToolTip(this.components);
|
||||||
|
this.btnPlaySound = new System.Windows.Forms.Button();
|
||||||
|
this.btnResetSound = new System.Windows.Forms.Button();
|
||||||
|
this.btnBrowseSound = new System.Windows.Forms.Button();
|
||||||
|
this.tbCustomSound = new System.Windows.Forms.TextBox();
|
||||||
|
this.labelSoundNotification = new System.Windows.Forms.Label();
|
||||||
|
this.panelSoundNotification = new System.Windows.Forms.Panel();
|
||||||
|
this.panelSoundNotification.SuspendLayout();
|
||||||
|
this.SuspendLayout();
|
||||||
|
//
|
||||||
|
// btnPlaySound
|
||||||
|
//
|
||||||
|
this.btnPlaySound.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right)));
|
||||||
|
this.btnPlaySound.AutoSize = true;
|
||||||
|
this.btnPlaySound.Location = new System.Drawing.Point(203, 29);
|
||||||
|
this.btnPlaySound.Name = "btnPlaySound";
|
||||||
|
this.btnPlaySound.Padding = new System.Windows.Forms.Padding(3, 0, 3, 0);
|
||||||
|
this.btnPlaySound.Size = new System.Drawing.Size(43, 23);
|
||||||
|
this.btnPlaySound.TabIndex = 2;
|
||||||
|
this.btnPlaySound.Text = "Play";
|
||||||
|
this.btnPlaySound.UseVisualStyleBackColor = true;
|
||||||
|
//
|
||||||
|
// btnResetSound
|
||||||
|
//
|
||||||
|
this.btnResetSound.AutoSize = true;
|
||||||
|
this.btnResetSound.Location = new System.Drawing.Point(3, 29);
|
||||||
|
this.btnResetSound.Name = "btnResetSound";
|
||||||
|
this.btnResetSound.Padding = new System.Windows.Forms.Padding(3, 0, 3, 0);
|
||||||
|
this.btnResetSound.Size = new System.Drawing.Size(51, 23);
|
||||||
|
this.btnResetSound.TabIndex = 3;
|
||||||
|
this.btnResetSound.Text = "Reset";
|
||||||
|
this.btnResetSound.UseVisualStyleBackColor = true;
|
||||||
|
//
|
||||||
|
// btnBrowseSound
|
||||||
|
//
|
||||||
|
this.btnBrowseSound.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right)));
|
||||||
|
this.btnBrowseSound.AutoSize = true;
|
||||||
|
this.btnBrowseSound.Location = new System.Drawing.Point(252, 29);
|
||||||
|
this.btnBrowseSound.Name = "btnBrowseSound";
|
||||||
|
this.btnBrowseSound.Padding = new System.Windows.Forms.Padding(3, 0, 3, 0);
|
||||||
|
this.btnBrowseSound.Size = new System.Drawing.Size(67, 23);
|
||||||
|
this.btnBrowseSound.TabIndex = 1;
|
||||||
|
this.btnBrowseSound.Text = "Browse...";
|
||||||
|
this.btnBrowseSound.UseVisualStyleBackColor = true;
|
||||||
|
//
|
||||||
|
// tbCustomSound
|
||||||
|
//
|
||||||
|
this.tbCustomSound.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left)
|
||||||
|
| System.Windows.Forms.AnchorStyles.Right)));
|
||||||
|
this.tbCustomSound.Location = new System.Drawing.Point(3, 3);
|
||||||
|
this.tbCustomSound.Name = "tbCustomSound";
|
||||||
|
this.tbCustomSound.Size = new System.Drawing.Size(316, 20);
|
||||||
|
this.tbCustomSound.TabIndex = 0;
|
||||||
|
this.toolTip.SetToolTip(this.tbCustomSound, "When empty, the default TweetDeck sound notification is used.");
|
||||||
|
//
|
||||||
|
// labelSoundNotification
|
||||||
|
//
|
||||||
|
this.labelSoundNotification.AutoSize = true;
|
||||||
|
this.labelSoundNotification.Font = new System.Drawing.Font("Microsoft Sans Serif", 12F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(238)));
|
||||||
|
this.labelSoundNotification.Location = new System.Drawing.Point(6, 8);
|
||||||
|
this.labelSoundNotification.Margin = new System.Windows.Forms.Padding(0, 2, 0, 0);
|
||||||
|
this.labelSoundNotification.Name = "labelSoundNotification";
|
||||||
|
this.labelSoundNotification.Size = new System.Drawing.Size(198, 20);
|
||||||
|
this.labelSoundNotification.TabIndex = 1;
|
||||||
|
this.labelSoundNotification.Text = "Custom Sound Notification";
|
||||||
|
//
|
||||||
|
// panelSoundNotification
|
||||||
|
//
|
||||||
|
this.panelSoundNotification.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left)
|
||||||
|
| System.Windows.Forms.AnchorStyles.Right)));
|
||||||
|
this.panelSoundNotification.Controls.Add(this.btnPlaySound);
|
||||||
|
this.panelSoundNotification.Controls.Add(this.tbCustomSound);
|
||||||
|
this.panelSoundNotification.Controls.Add(this.btnResetSound);
|
||||||
|
this.panelSoundNotification.Controls.Add(this.btnBrowseSound);
|
||||||
|
this.panelSoundNotification.Location = new System.Drawing.Point(9, 31);
|
||||||
|
this.panelSoundNotification.Name = "panelSoundNotification";
|
||||||
|
this.panelSoundNotification.Size = new System.Drawing.Size(322, 56);
|
||||||
|
this.panelSoundNotification.TabIndex = 2;
|
||||||
|
//
|
||||||
|
// TabSettingsSounds
|
||||||
|
//
|
||||||
|
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
|
||||||
|
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
|
||||||
|
this.Controls.Add(this.panelSoundNotification);
|
||||||
|
this.Controls.Add(this.labelSoundNotification);
|
||||||
|
this.Name = "TabSettingsSounds";
|
||||||
|
this.Size = new System.Drawing.Size(340, 97);
|
||||||
|
this.panelSoundNotification.ResumeLayout(false);
|
||||||
|
this.panelSoundNotification.PerformLayout();
|
||||||
|
this.ResumeLayout(false);
|
||||||
|
this.PerformLayout();
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
private System.Windows.Forms.ToolTip toolTip;
|
||||||
|
private System.Windows.Forms.Button btnResetSound;
|
||||||
|
private System.Windows.Forms.Button btnBrowseSound;
|
||||||
|
private System.Windows.Forms.TextBox tbCustomSound;
|
||||||
|
private System.Windows.Forms.Button btnPlaySound;
|
||||||
|
private System.Windows.Forms.Label labelSoundNotification;
|
||||||
|
private System.Windows.Forms.Panel panelSoundNotification;
|
||||||
|
}
|
||||||
|
}
|
||||||
67
Core/Other/Settings/TabSettingsSounds.cs
Normal file
67
Core/Other/Settings/TabSettingsSounds.cs
Normal file
@@ -0,0 +1,67 @@
|
|||||||
|
using System;
|
||||||
|
using System.Drawing;
|
||||||
|
using System.IO;
|
||||||
|
using System.Windows.Forms;
|
||||||
|
using TweetDuck.Core.Notification;
|
||||||
|
using TweetLib.Audio;
|
||||||
|
|
||||||
|
namespace TweetDuck.Core.Other.Settings{
|
||||||
|
partial class TabSettingsSounds : BaseTabSettings{
|
||||||
|
private readonly SoundNotification soundNotification;
|
||||||
|
|
||||||
|
public TabSettingsSounds(){
|
||||||
|
InitializeComponent();
|
||||||
|
|
||||||
|
soundNotification = new SoundNotification();
|
||||||
|
soundNotification.PlaybackError += sound_PlaybackError;
|
||||||
|
|
||||||
|
tbCustomSound.Text = Config.NotificationSoundPath;
|
||||||
|
tbCustomSound_TextChanged(tbCustomSound, new EventArgs());
|
||||||
|
|
||||||
|
Disposed += (sender, args) => soundNotification.Dispose();
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void OnReady(){
|
||||||
|
tbCustomSound.TextChanged += tbCustomSound_TextChanged;
|
||||||
|
btnPlaySound.Click += btnPlaySound_Click;
|
||||||
|
btnBrowseSound.Click += btnBrowseSound_Click;
|
||||||
|
btnResetSound.Click += btnResetSound_Click;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void OnClosing(){
|
||||||
|
Config.NotificationSoundPath = tbCustomSound.Text;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void tbCustomSound_TextChanged(object sender, EventArgs e){
|
||||||
|
bool isEmpty = string.IsNullOrEmpty(tbCustomSound.Text);
|
||||||
|
tbCustomSound.ForeColor = isEmpty || File.Exists(tbCustomSound.Text) ? SystemColors.WindowText : Color.Red;
|
||||||
|
btnPlaySound.Enabled = !isEmpty;
|
||||||
|
btnResetSound.Enabled = !isEmpty;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void btnPlaySound_Click(object sender, EventArgs e){
|
||||||
|
soundNotification.Play(tbCustomSound.Text);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void sound_PlaybackError(object sender, PlaybackErrorEventArgs e){
|
||||||
|
FormMessage.Error("Notification Sound Error", "Could not play custom notification sound.\n"+e.Message, FormMessage.OK);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void btnBrowseSound_Click(object sender, EventArgs e){
|
||||||
|
using(OpenFileDialog dialog = new OpenFileDialog{
|
||||||
|
AutoUpgradeEnabled = true,
|
||||||
|
DereferenceLinks = true,
|
||||||
|
Title = "Custom Notification Sound",
|
||||||
|
Filter = "Sound file ("+soundNotification.SupportedFormats+")|"+soundNotification.SupportedFormats+"|All files (*.*)|*.*"
|
||||||
|
}){
|
||||||
|
if (dialog.ShowDialog() == DialogResult.OK){
|
||||||
|
tbCustomSound.Text = dialog.FileName;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void btnResetSound_Click(object sender, EventArgs e){
|
||||||
|
tbCustomSound.Text = string.Empty;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
namespace TweetDick.Core.Controls {
|
namespace TweetDuck.Core {
|
||||||
partial class RichTextLabel {
|
partial class TrayIcon {
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Required designer variable.
|
/// Required designer variable.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -23,19 +23,19 @@
|
|||||||
/// 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.SuspendLayout();
|
this.components = new System.ComponentModel.Container();
|
||||||
|
this.notifyIcon = new System.Windows.Forms.NotifyIcon(this.components);
|
||||||
//
|
//
|
||||||
// RichTextLabel
|
// notifyIcon
|
||||||
//
|
//
|
||||||
this.BorderStyle = System.Windows.Forms.BorderStyle.None;
|
this.notifyIcon.MouseClick += new System.Windows.Forms.MouseEventHandler(this.trayIcon_MouseClick);
|
||||||
this.ReadOnly = true;
|
//
|
||||||
this.TabStop = false;
|
// TrayIcon
|
||||||
this.MouseEnter += new System.EventHandler(this.RichTextLabel_MouseEnter);
|
//
|
||||||
this.ResumeLayout(false);
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
|
private System.Windows.Forms.NotifyIcon notifyIcon;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
99
Core/TrayIcon.cs
Normal file
99
Core/TrayIcon.cs
Normal file
@@ -0,0 +1,99 @@
|
|||||||
|
using System;
|
||||||
|
using System.ComponentModel;
|
||||||
|
using System.Windows.Forms;
|
||||||
|
|
||||||
|
namespace TweetDuck.Core{
|
||||||
|
partial class TrayIcon : Component{
|
||||||
|
public enum Behavior{ // keep order
|
||||||
|
Disabled, DisplayOnly, MinimizeToTray, CloseToTray, Combined
|
||||||
|
}
|
||||||
|
|
||||||
|
public event EventHandler ClickRestore;
|
||||||
|
public event EventHandler ClickClose;
|
||||||
|
|
||||||
|
public bool Visible{
|
||||||
|
get => notifyIcon.Visible;
|
||||||
|
|
||||||
|
set{
|
||||||
|
if (value){
|
||||||
|
notifyIcon.Icon = Properties.Resources.icon_tray;
|
||||||
|
}
|
||||||
|
|
||||||
|
notifyIcon.Visible = value;
|
||||||
|
hasNotifications = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool HasNotifications{
|
||||||
|
get{
|
||||||
|
return hasNotifications;
|
||||||
|
}
|
||||||
|
|
||||||
|
set{
|
||||||
|
if (hasNotifications != value && Visible){
|
||||||
|
notifyIcon.Icon = value ? Properties.Resources.icon_tray_new : Properties.Resources.icon_tray;
|
||||||
|
hasNotifications = value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private readonly ContextMenu contextMenu;
|
||||||
|
private bool hasNotifications;
|
||||||
|
|
||||||
|
public TrayIcon(){
|
||||||
|
InitializeComponent();
|
||||||
|
|
||||||
|
this.contextMenu = new ContextMenu();
|
||||||
|
this.contextMenu.MenuItems.Add("Restore", menuItemRestore_Click);
|
||||||
|
this.contextMenu.MenuItems.Add("Mute notifications", menuItemMuteNotifications_Click);
|
||||||
|
this.contextMenu.MenuItems.Add("Close", menuItemClose_Click);
|
||||||
|
this.contextMenu.Popup += contextMenu_Popup;
|
||||||
|
|
||||||
|
this.notifyIcon.ContextMenu = contextMenu;
|
||||||
|
this.notifyIcon.Text = Program.BrandName;
|
||||||
|
}
|
||||||
|
|
||||||
|
public TrayIcon(IContainer container) : this(){
|
||||||
|
container.Add(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
// event handlers
|
||||||
|
|
||||||
|
private void trayIcon_MouseClick(object sender, MouseEventArgs e){
|
||||||
|
if (e.Button == MouseButtons.Left){
|
||||||
|
menuItemRestore_Click(sender, e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void contextMenu_Popup(object sender, EventArgs e){
|
||||||
|
contextMenu.MenuItems[1].Checked = Program.UserConfig.MuteNotifications;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void menuItemRestore_Click(object sender, EventArgs e){
|
||||||
|
ClickRestore?.Invoke(this, e);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void menuItemMuteNotifications_Click(object sender, EventArgs e){
|
||||||
|
Program.UserConfig.MuteNotifications = !contextMenu.MenuItems[1].Checked;
|
||||||
|
Program.UserConfig.Save();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void menuItemClose_Click(object sender, EventArgs e){
|
||||||
|
ClickClose?.Invoke(this, e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static class BehaviorExtensions{
|
||||||
|
public static bool ShouldDisplayIcon(this TrayIcon.Behavior behavior){
|
||||||
|
return behavior != TrayIcon.Behavior.Disabled;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static bool ShouldHideOnMinimize(this TrayIcon.Behavior behavior){
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
50
Core/Utils/BrowserCache.cs
Normal file
50
Core/Utils/BrowserCache.cs
Normal file
@@ -0,0 +1,50 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.IO;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using System.Linq;
|
||||||
|
|
||||||
|
namespace TweetDuck.Core.Utils{
|
||||||
|
static class BrowserCache{
|
||||||
|
private static bool ClearOnExit { get; set; }
|
||||||
|
|
||||||
|
private static readonly string CacheFolder = Path.Combine(Program.StoragePath, "Cache");
|
||||||
|
|
||||||
|
private static IEnumerable<string> CacheFiles{
|
||||||
|
get{
|
||||||
|
return Directory.EnumerateFiles(CacheFolder);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void CalculateCacheSize(Action<long> callbackBytes){
|
||||||
|
Task<long> task = new Task<long>(() => {
|
||||||
|
return CacheFiles.Select(file => {
|
||||||
|
try{
|
||||||
|
return new FileInfo(file).Length;
|
||||||
|
}catch{
|
||||||
|
return 0L;
|
||||||
|
}
|
||||||
|
}).Sum();
|
||||||
|
});
|
||||||
|
|
||||||
|
task.ContinueWith(originalTask => callbackBytes(originalTask.Exception == null ? originalTask.Result : -1L), TaskContinuationOptions.ExecuteSynchronously);
|
||||||
|
task.Start();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void SetClearOnExit(){
|
||||||
|
ClearOnExit = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void Exit(){
|
||||||
|
if (ClearOnExit){
|
||||||
|
foreach(string file in CacheFiles){
|
||||||
|
try{
|
||||||
|
File.Delete(file);
|
||||||
|
}catch{
|
||||||
|
// welp, too bad
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
26
Core/Utils/BrowserProcesses.cs
Normal file
26
Core/Utils/BrowserProcesses.cs
Normal file
@@ -0,0 +1,26 @@
|
|||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Diagnostics;
|
||||||
|
using CefSharp;
|
||||||
|
|
||||||
|
namespace TweetDuck.Core.Utils{
|
||||||
|
static class BrowserProcesses{
|
||||||
|
private static readonly Dictionary<int, int> PIDs = new Dictionary<int, int>();
|
||||||
|
|
||||||
|
public static void Link(int identifier, int pid){
|
||||||
|
PIDs[identifier] = pid;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void Forget(int identifier){
|
||||||
|
PIDs.Remove(identifier);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Process FindProcess(IBrowser browser){
|
||||||
|
if (PIDs.TryGetValue(browser.Identifier, out int pid) && WindowsUtils.IsChildProcess(pid)){ // child process is checked in two places for safety
|
||||||
|
return Process.GetProcessById(pid);
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
116
Core/Utils/BrowserUtils.cs
Normal file
116
Core/Utils/BrowserUtils.cs
Normal file
@@ -0,0 +1,116 @@
|
|||||||
|
using CefSharp;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Diagnostics;
|
||||||
|
using System.IO;
|
||||||
|
using System.Net;
|
||||||
|
using System.Windows.Forms;
|
||||||
|
using TweetDuck.Core.Other;
|
||||||
|
|
||||||
|
namespace TweetDuck.Core.Utils{
|
||||||
|
static class BrowserUtils{
|
||||||
|
public static string HeaderAcceptLanguage{
|
||||||
|
get{
|
||||||
|
string culture = Program.Culture.Name;
|
||||||
|
|
||||||
|
if (culture == "en"){
|
||||||
|
return "en-us,en";
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
return culture.ToLower()+",en;q=0.9";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static string HeaderUserAgent => Program.BrandName+" "+Application.ProductVersion;
|
||||||
|
|
||||||
|
public static void SetupCefArgs(IDictionary<string, string> args){
|
||||||
|
if (!Program.SystemConfig.HardwareAcceleration){
|
||||||
|
args["disable-gpu"] = "1";
|
||||||
|
args["disable-gpu-vsync"] = "1";
|
||||||
|
}
|
||||||
|
|
||||||
|
args["disable-extensions"] = "1";
|
||||||
|
args["disable-plugins-discovery"] = "1";
|
||||||
|
args["enable-system-flash"] = "0";
|
||||||
|
|
||||||
|
if (args.TryGetValue("js-flags", out string jsFlags)){
|
||||||
|
args["js-flags"] = "--expose-gc "+jsFlags;
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
args["js-flags"] = "--expose-gc";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static bool IsValidUrl(string url){
|
||||||
|
if (Uri.TryCreate(url, UriKind.Absolute, out Uri uri)){
|
||||||
|
string scheme = uri.Scheme;
|
||||||
|
return scheme == Uri.UriSchemeHttp || scheme == Uri.UriSchemeHttps || scheme == Uri.UriSchemeFtp || scheme == Uri.UriSchemeMailto;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void OpenExternalBrowser(string url){
|
||||||
|
if (string.IsNullOrWhiteSpace(url))return;
|
||||||
|
|
||||||
|
if (IsValidUrl(url)){
|
||||||
|
OpenExternalBrowserUnsafe(url);
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
FormMessage.Warning("Blocked URL", "A potentially malicious URL was blocked from opening:\n"+url, FormMessage.OK);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void OpenExternalBrowserUnsafe(string url){
|
||||||
|
using(Process.Start(url)){}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static string GetFileNameFromUrl(string url){
|
||||||
|
string file = Path.GetFileName(new Uri(url).AbsolutePath);
|
||||||
|
return string.IsNullOrEmpty(file) ? null : file;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static string GetErrorName(CefErrorCode code){
|
||||||
|
return StringUtils.ConvertPascalCaseToScreamingSnakeCase(Enum.GetName(typeof(CefErrorCode), code) ?? string.Empty);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static WebClient DownloadFileAsync(string url, string target, Action onSuccess, Action<Exception> onFailure){
|
||||||
|
WebClient client = new WebClient{ Proxy = null };
|
||||||
|
client.Headers[HttpRequestHeader.UserAgent] = HeaderUserAgent;
|
||||||
|
|
||||||
|
client.DownloadFileCompleted += (sender, args) => {
|
||||||
|
if (args.Cancelled){
|
||||||
|
try{
|
||||||
|
File.Delete(target);
|
||||||
|
}catch{
|
||||||
|
// didn't want it deleted anyways
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (args.Error != null){
|
||||||
|
onFailure?.Invoke(args.Error);
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
onSuccess?.Invoke();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
client.DownloadFileAsync(new Uri(url), target);
|
||||||
|
return client;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static int Scale(int baseValue, double scaleFactor){
|
||||||
|
return (int)Math.Round(baseValue*scaleFactor);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void SetZoomLevel(IBrowser browser, int percentage){
|
||||||
|
browser.GetHost().SetZoomLevel(Math.Log(percentage/100.0, 1.2));
|
||||||
|
}
|
||||||
|
|
||||||
|
#if DEBUG
|
||||||
|
public static void HandleConsoleMessage(object sender, ConsoleMessageEventArgs e){
|
||||||
|
Debug.WriteLine("[Console] {0} ({1}:{2})", e.Message, e.Source, e.Line);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
}
|
||||||
91
Core/Utils/MemoryUsageTracker.cs
Normal file
91
Core/Utils/MemoryUsageTracker.cs
Normal file
@@ -0,0 +1,91 @@
|
|||||||
|
using System;
|
||||||
|
using System.Diagnostics;
|
||||||
|
using System.Timers;
|
||||||
|
using System.Windows.Forms;
|
||||||
|
using CefSharp;
|
||||||
|
using Timer = System.Timers.Timer;
|
||||||
|
|
||||||
|
namespace TweetDuck.Core.Utils{
|
||||||
|
sealed class MemoryUsageTracker : IDisposable{
|
||||||
|
private const int IntervalMemoryCheck = 60000*30; // 30 minutes
|
||||||
|
private const int IntervalCleanupAttempt = 60000*5; // 5 minutes
|
||||||
|
|
||||||
|
private readonly string script;
|
||||||
|
private readonly Timer timer;
|
||||||
|
private Form owner;
|
||||||
|
private IBrowser browser;
|
||||||
|
|
||||||
|
private long threshold;
|
||||||
|
private bool needsCleanup;
|
||||||
|
|
||||||
|
public MemoryUsageTracker(string cleanupFunctionName){
|
||||||
|
this.script = $"window.{cleanupFunctionName} && window.{cleanupFunctionName}()";
|
||||||
|
|
||||||
|
this.timer = new Timer{ Interval = IntervalMemoryCheck };
|
||||||
|
this.timer.Elapsed += timer_Elapsed;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Start(Form owner, IBrowser browser, int thresholdMB){
|
||||||
|
Stop();
|
||||||
|
|
||||||
|
this.owner = owner;
|
||||||
|
this.browser = browser;
|
||||||
|
this.threshold = thresholdMB*1024L*1024L;
|
||||||
|
this.timer.SynchronizingObject = owner;
|
||||||
|
this.timer.Start();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Stop(){
|
||||||
|
timer.Stop();
|
||||||
|
timer.SynchronizingObject = null;
|
||||||
|
owner = null;
|
||||||
|
browser = null;
|
||||||
|
SetNeedsCleanup(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Dispose(){
|
||||||
|
timer.SynchronizingObject = null;
|
||||||
|
timer.Dispose();
|
||||||
|
owner = null;
|
||||||
|
browser = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void SetNeedsCleanup(bool value){
|
||||||
|
if (needsCleanup != value){
|
||||||
|
needsCleanup = value;
|
||||||
|
timer.Interval = value ? IntervalCleanupAttempt : IntervalMemoryCheck; // restarts timer
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void timer_Elapsed(object sender, ElapsedEventArgs e){
|
||||||
|
if (owner == null || browser == null){
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (needsCleanup){
|
||||||
|
if (!owner.ContainsFocus){
|
||||||
|
using(IFrame frame = browser.MainFrame){
|
||||||
|
frame.EvaluateScriptAsync(script).ContinueWith(task => {
|
||||||
|
JavascriptResponse response = task.Result;
|
||||||
|
|
||||||
|
if (response.Success && (response.Result as bool? ?? false)){
|
||||||
|
SetNeedsCleanup(false);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
try{
|
||||||
|
using(Process process = BrowserProcesses.FindProcess(browser)){
|
||||||
|
if (process?.PrivateMemorySize64 > threshold){
|
||||||
|
SetNeedsCleanup(true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}catch{
|
||||||
|
// ignore I guess?
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
144
Core/Utils/NativeMethods.cs
Normal file
144
Core/Utils/NativeMethods.cs
Normal file
@@ -0,0 +1,144 @@
|
|||||||
|
using System;
|
||||||
|
using System.Diagnostics.CodeAnalysis;
|
||||||
|
using System.Drawing;
|
||||||
|
using System.Runtime.InteropServices;
|
||||||
|
using System.Windows.Forms;
|
||||||
|
|
||||||
|
namespace TweetDuck.Core.Utils{
|
||||||
|
[SuppressMessage("ReSharper", "FieldCanBeMadeReadOnly.Local")]
|
||||||
|
[SuppressMessage("ReSharper", "MemberCanBePrivate.Local")]
|
||||||
|
static class NativeMethods{
|
||||||
|
public static readonly IntPtr HWND_BROADCAST = new IntPtr(0xFFFF);
|
||||||
|
public static readonly IntPtr HOOK_HANDLED = new IntPtr(-1);
|
||||||
|
|
||||||
|
public const int HWND_TOPMOST = -1;
|
||||||
|
public const uint SWP_NOACTIVATE = 0x0010;
|
||||||
|
public const int WS_DISABLED = 0x08000000;
|
||||||
|
public const int GWL_STYLE = -16;
|
||||||
|
|
||||||
|
public const int SB_HORZ = 0;
|
||||||
|
public const int BCM_SETSHIELD = 0x160C;
|
||||||
|
|
||||||
|
public const int WM_MOUSE_LL = 14;
|
||||||
|
public const int WM_MOUSEWHEEL = 0x020A;
|
||||||
|
public const int WM_XBUTTONDOWN = 0x020B;
|
||||||
|
public const int WM_XBUTTONUP = 0x020C;
|
||||||
|
public const int WM_PARENTNOTIFY = 0x0210;
|
||||||
|
|
||||||
|
[StructLayout(LayoutKind.Sequential)]
|
||||||
|
private struct LASTINPUTINFO{
|
||||||
|
public static readonly uint Size = (uint)Marshal.SizeOf(typeof(LASTINPUTINFO));
|
||||||
|
|
||||||
|
public uint cbSize;
|
||||||
|
public uint dwTime;
|
||||||
|
}
|
||||||
|
|
||||||
|
[StructLayout(LayoutKind.Sequential)]
|
||||||
|
private struct POINT{
|
||||||
|
public int X;
|
||||||
|
public int Y;
|
||||||
|
}
|
||||||
|
|
||||||
|
[StructLayout(LayoutKind.Sequential)]
|
||||||
|
private struct MSLLHOOKSTRUCT{
|
||||||
|
public POINT pt;
|
||||||
|
public int mouseData;
|
||||||
|
public int flags;
|
||||||
|
public int time;
|
||||||
|
public UIntPtr dwExtraInfo;
|
||||||
|
}
|
||||||
|
|
||||||
|
public delegate IntPtr HookProc(int nCode, IntPtr wParam, IntPtr lParam);
|
||||||
|
|
||||||
|
[DllImport("user32.dll", EntryPoint = "SetWindowPos")]
|
||||||
|
private static extern bool SetWindowPos(int hWnd, int hWndOrder, int x, int y, int width, int height, uint flags);
|
||||||
|
|
||||||
|
[DllImport("user32.dll")]
|
||||||
|
private static extern bool GetLastInputInfo(ref LASTINPUTINFO info);
|
||||||
|
|
||||||
|
[DllImport("user32.dll")]
|
||||||
|
public static extern IntPtr GetDC(IntPtr hWnd);
|
||||||
|
|
||||||
|
[DllImport("user32.dll")]
|
||||||
|
public static extern bool ReleaseDC(IntPtr hWnd, IntPtr hDC);
|
||||||
|
|
||||||
|
[DllImport("gdi32.dll")]
|
||||||
|
[return: MarshalAs(UnmanagedType.Bool)]
|
||||||
|
private static extern bool BitBlt(IntPtr hdc, int nXDest, int nYDest, int nWidth, int nHeight, IntPtr hdcSrc, int nXSrc, int nYSrc, uint dwRop);
|
||||||
|
|
||||||
|
[DllImport("user32.dll")]
|
||||||
|
public static extern IntPtr SendMessage(IntPtr hWnd, uint msg, UIntPtr wParam, IntPtr lParam);
|
||||||
|
|
||||||
|
[DllImport("user32.dll")]
|
||||||
|
public static extern bool PostMessage(IntPtr hWnd, uint msg, UIntPtr wParam, IntPtr lParam);
|
||||||
|
|
||||||
|
[DllImport("user32.dll")]
|
||||||
|
public static extern uint RegisterWindowMessage(string messageName);
|
||||||
|
|
||||||
|
[DllImport("user32.dll")]
|
||||||
|
[return: MarshalAs(UnmanagedType.Bool)]
|
||||||
|
public static extern bool ShowScrollBar(IntPtr hWnd, int wBar, bool bShow);
|
||||||
|
|
||||||
|
[DllImport("user32.dll")]
|
||||||
|
public static extern IntPtr SetWindowsHookEx(int idHook, HookProc lpfn, IntPtr hInstance, int threadId);
|
||||||
|
|
||||||
|
[DllImport("user32.dll")]
|
||||||
|
public static extern bool UnhookWindowsHookEx(IntPtr idHook);
|
||||||
|
|
||||||
|
[DllImport("user32.dll")]
|
||||||
|
public static extern IntPtr CallNextHookEx(IntPtr idHook, int nCode, IntPtr wParam, IntPtr lParam);
|
||||||
|
|
||||||
|
[DllImport("user32.dll")]
|
||||||
|
private static extern int GetWindowLong(IntPtr hWnd, int nIndex);
|
||||||
|
|
||||||
|
[DllImport("user32.dll")]
|
||||||
|
private static extern int SetWindowLong(IntPtr hWnd, int nIndex, int dwNewLong);
|
||||||
|
|
||||||
|
public static void SetFormPos(Form form, int hWndOrder, uint flags){
|
||||||
|
SetWindowPos(form.Handle.ToInt32(), hWndOrder, form.Left, form.Top, form.Width, form.Height, flags);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void SetFormDisabled(Form form, bool disabled){
|
||||||
|
if (disabled){
|
||||||
|
SetWindowLong(form.Handle, GWL_STYLE, GetWindowLong(form.Handle, GWL_STYLE) | WS_DISABLED);
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
SetWindowLong(form.Handle, GWL_STYLE, GetWindowLong(form.Handle, GWL_STYLE) & ~WS_DISABLED);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static int GetMouseHookData(IntPtr ptr){
|
||||||
|
return Marshal.PtrToStructure<MSLLHOOKSTRUCT>(ptr).mouseData >> 16;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static int GetIdleSeconds(){
|
||||||
|
LASTINPUTINFO info = new LASTINPUTINFO();
|
||||||
|
info.cbSize = LASTINPUTINFO.Size;
|
||||||
|
|
||||||
|
if (!GetLastInputInfo(ref info)){
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint ticks;
|
||||||
|
|
||||||
|
unchecked{
|
||||||
|
ticks = (uint)Environment.TickCount;
|
||||||
|
}
|
||||||
|
|
||||||
|
int seconds = (int)Math.Floor(TimeSpan.FromMilliseconds(ticks-info.dwTime).TotalSeconds);
|
||||||
|
return Math.Max(0, seconds); // ignore rollover after several weeks of uptime
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void RenderSourceIntoBitmap(IntPtr source, Bitmap target){
|
||||||
|
using(Graphics graphics = Graphics.FromImage(target)){
|
||||||
|
IntPtr graphicsHandle = graphics.GetHdc();
|
||||||
|
|
||||||
|
try{
|
||||||
|
BitBlt(graphicsHandle, 0, 0, target.Width, target.Height, source, 0, 0, 0x00CC0020);
|
||||||
|
}finally{
|
||||||
|
graphics.ReleaseHdc(graphicsHandle);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
22
Core/Utils/StringUtils.cs
Normal file
22
Core/Utils/StringUtils.cs
Normal file
@@ -0,0 +1,22 @@
|
|||||||
|
using System;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text.RegularExpressions;
|
||||||
|
|
||||||
|
namespace TweetDuck.Core.Utils{
|
||||||
|
static class StringUtils{
|
||||||
|
public static readonly string[] EmptyArray = new string[0];
|
||||||
|
|
||||||
|
public static string ExtractBefore(string str, char search, int startIndex = 0){
|
||||||
|
int index = str.IndexOf(search, startIndex);
|
||||||
|
return index == -1 ? str : str.Substring(0, index);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static int[] ParseInts(string str, char separator){
|
||||||
|
return str.Split(new char[]{ separator }, StringSplitOptions.RemoveEmptyEntries).Select(int.Parse).ToArray();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static string ConvertPascalCaseToScreamingSnakeCase(string str){
|
||||||
|
return Regex.Replace(str, @"(\p{Ll})(\P{Ll})|(\P{Ll})(\P{Ll}\p{Ll})", "$1$3_$2$4").ToUpper();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
106
Core/Utils/TwitterUtils.cs
Normal file
106
Core/Utils/TwitterUtils.cs
Normal file
@@ -0,0 +1,106 @@
|
|||||||
|
using System;
|
||||||
|
using CefSharp;
|
||||||
|
using System.Drawing;
|
||||||
|
using System.IO;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text.RegularExpressions;
|
||||||
|
using System.Windows.Forms;
|
||||||
|
using TweetDuck.Core.Other;
|
||||||
|
|
||||||
|
namespace TweetDuck.Core.Utils{
|
||||||
|
static class TwitterUtils{
|
||||||
|
public const string TweetDeckURL = "https://tweetdeck.twitter.com";
|
||||||
|
|
||||||
|
public static readonly Color BackgroundColor = Color.FromArgb(28, 99, 153);
|
||||||
|
public const string BackgroundColorFix = "let e=document.createElement('style');document.head.appendChild(e);e.innerHTML='body::before{background:#1c6399!important}'";
|
||||||
|
|
||||||
|
private static readonly Lazy<Regex> RegexAccountLazy = new Lazy<Regex>(() => new Regex(@"^https?://twitter\.com/([^/]+)/?$", RegexOptions.Compiled), false);
|
||||||
|
public static Regex RegexAccount => RegexAccountLazy.Value;
|
||||||
|
|
||||||
|
public static readonly string[] DictionaryWords = {
|
||||||
|
"tweetdeck", "TweetDeck", "tweetduck", "TweetDuck", "TD"
|
||||||
|
};
|
||||||
|
|
||||||
|
public enum ImageQuality{
|
||||||
|
Default, Orig
|
||||||
|
}
|
||||||
|
|
||||||
|
public static bool IsTweetDeckWebsite(IFrame frame){
|
||||||
|
return frame.Url.Contains("//tweetdeck.twitter.com/");
|
||||||
|
}
|
||||||
|
|
||||||
|
public static bool IsTwitterWebsite(IFrame frame){
|
||||||
|
return frame.Url.Contains("//twitter.com/");
|
||||||
|
}
|
||||||
|
|
||||||
|
private static string ExtractImageBaseLink(string url){
|
||||||
|
int dot = url.LastIndexOf('/');
|
||||||
|
return dot == -1 ? url : StringUtils.ExtractBefore(url, ':', dot);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static string GetImageLink(string url, ImageQuality quality){
|
||||||
|
if (quality == ImageQuality.Orig){
|
||||||
|
string result = ExtractImageBaseLink(url);
|
||||||
|
|
||||||
|
if (result != url || url.Contains("//pbs.twimg.com/media/")){
|
||||||
|
result += ":orig";
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
return url;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void DownloadImage(string url, string username, ImageQuality quality){
|
||||||
|
DownloadImages(new string[]{ url }, username, quality);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void DownloadImages(string[] urls, string username, ImageQuality quality){
|
||||||
|
if (urls.Length == 0){
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
string firstImageLink = GetImageLink(urls[0], quality);
|
||||||
|
int qualityIndex = firstImageLink.IndexOf(':', firstImageLink.LastIndexOf('/'));
|
||||||
|
|
||||||
|
string file = BrowserUtils.GetFileNameFromUrl(ExtractImageBaseLink(firstImageLink));
|
||||||
|
string ext = Path.GetExtension(file); // includes dot
|
||||||
|
|
||||||
|
string[] fileNameParts = qualityIndex == -1 ? new string[]{
|
||||||
|
Path.ChangeExtension(file, null)
|
||||||
|
} : new string[]{
|
||||||
|
username,
|
||||||
|
Path.ChangeExtension(file, null),
|
||||||
|
firstImageLink.Substring(qualityIndex+1)
|
||||||
|
};
|
||||||
|
|
||||||
|
using(SaveFileDialog dialog = new SaveFileDialog{
|
||||||
|
AutoUpgradeEnabled = true,
|
||||||
|
OverwritePrompt = urls.Length == 1,
|
||||||
|
Title = "Save image",
|
||||||
|
FileName = $"{string.Join(" ", fileNameParts.Where(part => part.Length > 0))}{ext}",
|
||||||
|
Filter = (urls.Length == 1 ? "Image" : "Images")+(string.IsNullOrEmpty(ext) ? " (unknown)|*.*" : $" (*{ext})|*{ext}")
|
||||||
|
}){
|
||||||
|
if (dialog.ShowDialog() == DialogResult.OK){
|
||||||
|
void OnFailure(Exception ex){
|
||||||
|
FormMessage.Error("Image Download", "An error occurred while downloading the image: "+ex.Message, FormMessage.OK);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (urls.Length == 1){
|
||||||
|
BrowserUtils.DownloadFileAsync(firstImageLink, dialog.FileName, null, OnFailure);
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
string pathBase = Path.ChangeExtension(dialog.FileName, null);
|
||||||
|
string pathExt = Path.GetExtension(dialog.FileName);
|
||||||
|
|
||||||
|
for(int index = 0; index < urls.Length; index++){
|
||||||
|
BrowserUtils.DownloadFileAsync(GetImageLink(urls[index], quality), $"{pathBase} {index+1}{pathExt}", null, OnFailure);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
143
Core/Utils/WindowsUtils.cs
Normal file
143
Core/Utils/WindowsUtils.cs
Normal file
@@ -0,0 +1,143 @@
|
|||||||
|
using System;
|
||||||
|
using System.Diagnostics;
|
||||||
|
using System.IO;
|
||||||
|
using System.Management;
|
||||||
|
using System.Runtime.InteropServices;
|
||||||
|
using System.Text.RegularExpressions;
|
||||||
|
using System.Threading;
|
||||||
|
using System.Windows.Forms;
|
||||||
|
|
||||||
|
namespace TweetDuck.Core.Utils{
|
||||||
|
static class WindowsUtils{
|
||||||
|
private static readonly Lazy<Regex> RegexStripHtmlStyles = new Lazy<Regex>(() => new Regex(@"\s?(?:style|class)="".*?"""), false);
|
||||||
|
private static readonly Lazy<Regex> RegexOffsetClipboardHtml = new Lazy<Regex>(() => new Regex(@"(?<=EndHTML:|EndFragment:)(\d+)"), false);
|
||||||
|
|
||||||
|
public static int CurrentProcessID { get; }
|
||||||
|
public static bool ShouldAvoidToolWindow { get; }
|
||||||
|
|
||||||
|
static WindowsUtils(){
|
||||||
|
using(Process me = Process.GetCurrentProcess()){
|
||||||
|
CurrentProcessID = me.Id;
|
||||||
|
}
|
||||||
|
|
||||||
|
Version ver = Environment.OSVersion.Version;
|
||||||
|
ShouldAvoidToolWindow = ver.Major == 6 && ver.Minor == 2; // windows 8/10
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void CreateDirectoryForFile(string file){
|
||||||
|
string dir = Path.GetDirectoryName(file);
|
||||||
|
|
||||||
|
if (dir == null){
|
||||||
|
throw new ArgumentException("Invalid file path: "+file);
|
||||||
|
}
|
||||||
|
else if (dir.Length > 0){
|
||||||
|
Directory.CreateDirectory(dir);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static bool CheckFolderWritePermission(string path){
|
||||||
|
string testFile = Path.Combine(path, ".test");
|
||||||
|
|
||||||
|
try{
|
||||||
|
Directory.CreateDirectory(path);
|
||||||
|
|
||||||
|
using(File.Create(testFile)){}
|
||||||
|
File.Delete(testFile);
|
||||||
|
return true;
|
||||||
|
}catch{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Process StartProcess(string file, string arguments, bool runElevated){
|
||||||
|
ProcessStartInfo processInfo = new ProcessStartInfo{
|
||||||
|
FileName = file,
|
||||||
|
Arguments = arguments
|
||||||
|
};
|
||||||
|
|
||||||
|
if (runElevated){
|
||||||
|
processInfo.Verb = "runas";
|
||||||
|
}
|
||||||
|
|
||||||
|
return Process.Start(processInfo);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static bool TrySleepUntil(Func<bool> test, int timeoutMillis, int timeStepMillis){
|
||||||
|
for(int waited = 0; waited < timeoutMillis; waited += timeStepMillis){
|
||||||
|
if (test()){
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
Thread.Sleep(timeStepMillis);
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void TryDeleteFolderWhenAble(string path, int timeout){
|
||||||
|
new Thread(() => {
|
||||||
|
TrySleepUntil(() => {
|
||||||
|
try{
|
||||||
|
Directory.Delete(path, true);
|
||||||
|
return true;
|
||||||
|
}catch(DirectoryNotFoundException){
|
||||||
|
return true;
|
||||||
|
}catch{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}, timeout, 500);
|
||||||
|
}).Start();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static bool IsChildProcess(int pid){
|
||||||
|
try{
|
||||||
|
using(ManagementObjectSearcher searcher = new ManagementObjectSearcher("SELECT ParentProcessId FROM Win32_Process WHERE ProcessId = "+pid)){
|
||||||
|
foreach(ManagementBaseObject obj in searcher.Get()){
|
||||||
|
return (uint)obj["ParentProcessId"] == CurrentProcessID;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}catch{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void ClipboardStripHtmlStyles(){
|
||||||
|
if (!Clipboard.ContainsText(TextDataFormat.Html)){
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
string originalText = Clipboard.GetText(TextDataFormat.UnicodeText);
|
||||||
|
string originalHtml = Clipboard.GetText(TextDataFormat.Html);
|
||||||
|
|
||||||
|
string updatedHtml = RegexStripHtmlStyles.Value.Replace(originalHtml, string.Empty);
|
||||||
|
|
||||||
|
int removed = originalHtml.Length-updatedHtml.Length;
|
||||||
|
updatedHtml = RegexOffsetClipboardHtml.Value.Replace(updatedHtml, match => (int.Parse(match.Value)-removed).ToString().PadLeft(match.Value.Length, '0'));
|
||||||
|
|
||||||
|
DataObject obj = new DataObject();
|
||||||
|
obj.SetText(originalText, TextDataFormat.UnicodeText);
|
||||||
|
obj.SetText(updatedHtml, TextDataFormat.Html);
|
||||||
|
SetClipboardData(obj);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void SetClipboard(string text, TextDataFormat format){
|
||||||
|
if (string.IsNullOrEmpty(text)){
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
DataObject obj = new DataObject();
|
||||||
|
obj.SetText(text, format);
|
||||||
|
SetClipboardData(obj);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void SetClipboardData(DataObject obj){
|
||||||
|
try{
|
||||||
|
Clipboard.SetDataObject(obj);
|
||||||
|
}catch(ExternalException e){
|
||||||
|
Program.Reporter.HandleException("Clipboard Error", "TweetDuck could not access the clipboard as it is currently used by another process.", true, e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
130
Data/CombinedFileStream.cs
Normal file
130
Data/CombinedFileStream.cs
Normal file
@@ -0,0 +1,130 @@
|
|||||||
|
using System;
|
||||||
|
using System.IO;
|
||||||
|
using System.Text;
|
||||||
|
using TweetDuck.Core.Utils;
|
||||||
|
|
||||||
|
namespace TweetDuck.Data{
|
||||||
|
sealed class CombinedFileStream : IDisposable{
|
||||||
|
public const char KeySeparator = '|';
|
||||||
|
|
||||||
|
private readonly Stream stream;
|
||||||
|
|
||||||
|
public CombinedFileStream(Stream stream){
|
||||||
|
this.stream = stream;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void WriteFile(string[] identifier, string path){
|
||||||
|
WriteFile(string.Join(KeySeparator.ToString(), identifier), path);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void WriteFile(string identifier, string path){
|
||||||
|
byte[] name = Encoding.UTF8.GetBytes(identifier);
|
||||||
|
|
||||||
|
if (name.Length > 255){
|
||||||
|
throw new ArgumentOutOfRangeException("Identifier cannot be 256 or more characters long: "+identifier);
|
||||||
|
}
|
||||||
|
|
||||||
|
byte[] contents;
|
||||||
|
|
||||||
|
using(FileStream fileStream = new FileStream(path, FileMode.Open, FileAccess.Read, FileShare.ReadWrite)){
|
||||||
|
int index = 0;
|
||||||
|
int left = (int)fileStream.Length;
|
||||||
|
|
||||||
|
contents = new byte[left];
|
||||||
|
|
||||||
|
while(left > 0){
|
||||||
|
int read = fileStream.Read(contents, index, left);
|
||||||
|
index += read;
|
||||||
|
left -= read;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
stream.WriteByte((byte)name.Length);
|
||||||
|
stream.Write(name, 0, name.Length);
|
||||||
|
stream.Write(BitConverter.GetBytes(contents.Length), 0, 4);
|
||||||
|
stream.Write(contents, 0, contents.Length);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Entry ReadFile(){
|
||||||
|
int nameLength = stream.ReadByte();
|
||||||
|
|
||||||
|
if (nameLength == -1){
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
byte[] name = new byte[nameLength];
|
||||||
|
stream.Read(name, 0, nameLength);
|
||||||
|
|
||||||
|
byte[] contentLength = new byte[4];
|
||||||
|
stream.Read(contentLength, 0, 4);
|
||||||
|
|
||||||
|
byte[] contents = new byte[BitConverter.ToInt32(contentLength, 0)];
|
||||||
|
stream.Read(contents, 0, contents.Length);
|
||||||
|
|
||||||
|
return new Entry(Encoding.UTF8.GetString(name), contents);
|
||||||
|
}
|
||||||
|
|
||||||
|
public string SkipFile(){
|
||||||
|
int nameLength = stream.ReadByte();
|
||||||
|
|
||||||
|
if (nameLength == -1){
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
byte[] name = new byte[nameLength];
|
||||||
|
stream.Read(name, 0, nameLength);
|
||||||
|
|
||||||
|
byte[] contentLength = new byte[4];
|
||||||
|
stream.Read(contentLength, 0, 4);
|
||||||
|
|
||||||
|
stream.Position += BitConverter.ToInt32(contentLength, 0);
|
||||||
|
|
||||||
|
string keyName = Encoding.UTF8.GetString(name);
|
||||||
|
return StringUtils.ExtractBefore(keyName, KeySeparator);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Flush(){
|
||||||
|
stream.Flush();
|
||||||
|
}
|
||||||
|
|
||||||
|
void IDisposable.Dispose(){
|
||||||
|
stream.Dispose();
|
||||||
|
}
|
||||||
|
|
||||||
|
public class Entry{
|
||||||
|
public string Identifier { get; }
|
||||||
|
|
||||||
|
public string KeyName{
|
||||||
|
get{
|
||||||
|
return StringUtils.ExtractBefore(Identifier, KeySeparator);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public string[] KeyValue{
|
||||||
|
get{
|
||||||
|
int index = Identifier.IndexOf(KeySeparator);
|
||||||
|
return index == -1 ? StringUtils.EmptyArray : Identifier.Substring(index+1).Split(KeySeparator);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private readonly byte[] contents;
|
||||||
|
|
||||||
|
public Entry(string identifier, byte[] contents){
|
||||||
|
this.Identifier = identifier;
|
||||||
|
this.contents = contents;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void WriteToFile(string path){
|
||||||
|
File.WriteAllBytes(path, contents);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void WriteToFile(string path, bool createDirectory){
|
||||||
|
if (createDirectory){
|
||||||
|
WindowsUtils.CreateDirectoryForFile(path);
|
||||||
|
}
|
||||||
|
|
||||||
|
File.WriteAllBytes(path, contents);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
137
Data/CommandLineArgs.cs
Normal file
137
Data/CommandLineArgs.cs
Normal file
@@ -0,0 +1,137 @@
|
|||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Text;
|
||||||
|
using System.Text.RegularExpressions;
|
||||||
|
|
||||||
|
namespace TweetDuck.Data{
|
||||||
|
sealed class CommandLineArgs{
|
||||||
|
public static CommandLineArgs FromStringArray(char entryChar, string[] array){
|
||||||
|
CommandLineArgs args = new CommandLineArgs();
|
||||||
|
ReadStringArray(entryChar, array, args);
|
||||||
|
return args;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void ReadStringArray(char entryChar, string[] array, CommandLineArgs targetArgs){
|
||||||
|
for(int index = 0; index < array.Length; index++){
|
||||||
|
string entry = array[index];
|
||||||
|
|
||||||
|
if (entry.Length > 0 && entry[0] == entryChar){
|
||||||
|
if (index < array.Length-1){
|
||||||
|
string potentialValue = array[index+1];
|
||||||
|
|
||||||
|
if (potentialValue.Length > 0 && potentialValue[0] == entryChar){
|
||||||
|
targetArgs.AddFlag(entry);
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
targetArgs.SetValue(entry, potentialValue);
|
||||||
|
++index;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
targetArgs.AddFlag(entry);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static CommandLineArgs ReadCefArguments(string argumentString){
|
||||||
|
CommandLineArgs args = new CommandLineArgs();
|
||||||
|
|
||||||
|
if (string.IsNullOrWhiteSpace(argumentString)){
|
||||||
|
return args;
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach(Match match in Regex.Matches(argumentString, @"([^=\s]+(?:=(?:\S*""[^""]*?""\S*|\S*))?)")){
|
||||||
|
string matchValue = match.Value;
|
||||||
|
|
||||||
|
int indexEquals = matchValue.IndexOf('=');
|
||||||
|
string key, value;
|
||||||
|
|
||||||
|
if (indexEquals == -1){
|
||||||
|
key = matchValue.TrimStart('-');
|
||||||
|
value = "1";
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
key = matchValue.Substring(0, indexEquals).TrimStart('-');
|
||||||
|
value = matchValue.Substring(indexEquals+1).Trim('"');
|
||||||
|
}
|
||||||
|
|
||||||
|
if (key.Length != 0){
|
||||||
|
args.SetValue(key, value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return args;
|
||||||
|
}
|
||||||
|
|
||||||
|
private readonly HashSet<string> flags = new HashSet<string>();
|
||||||
|
private readonly Dictionary<string, string> values = new Dictionary<string, string>();
|
||||||
|
|
||||||
|
public int Count => flags.Count+values.Count;
|
||||||
|
|
||||||
|
public void AddFlag(string flag){
|
||||||
|
flags.Add(flag.ToLower());
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool HasFlag(string flag){
|
||||||
|
return flags.Contains(flag.ToLower());
|
||||||
|
}
|
||||||
|
|
||||||
|
public void RemoveFlag(string flag){
|
||||||
|
flags.Remove(flag.ToLower());
|
||||||
|
}
|
||||||
|
|
||||||
|
public void SetValue(string key, string value){
|
||||||
|
values[key.ToLower()] = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool HasValue(string key){
|
||||||
|
return values.ContainsKey(key.ToLower());
|
||||||
|
}
|
||||||
|
|
||||||
|
public string GetValue(string key, string defaultValue){
|
||||||
|
return values.TryGetValue(key.ToLower(), out string val) ? val : defaultValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void RemoveValue(string key){
|
||||||
|
values.Remove(key.ToLower());
|
||||||
|
}
|
||||||
|
|
||||||
|
public CommandLineArgs Clone(){
|
||||||
|
CommandLineArgs copy = new CommandLineArgs();
|
||||||
|
|
||||||
|
foreach(string flag in flags){
|
||||||
|
copy.AddFlag(flag);
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach(KeyValuePair<string, string> kvp in values){
|
||||||
|
copy.SetValue(kvp.Key, kvp.Value);
|
||||||
|
}
|
||||||
|
|
||||||
|
return copy;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void ToDictionary(IDictionary<string, string> target){
|
||||||
|
foreach(string flag in flags){
|
||||||
|
target[flag] = "1";
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach(KeyValuePair<string, string> kvp in values){
|
||||||
|
target[kvp.Key] = kvp.Value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public override string ToString(){
|
||||||
|
StringBuilder build = new StringBuilder();
|
||||||
|
|
||||||
|
foreach(string flag in flags){
|
||||||
|
build.Append(flag).Append(' ');
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach(KeyValuePair<string, string> kvp in values){
|
||||||
|
build.Append(kvp.Key).Append(" \"").Append(kvp.Value).Append("\" ");
|
||||||
|
}
|
||||||
|
|
||||||
|
return build.Length == 0 ? string.Empty : build.Remove(build.Length-1, 1).ToString();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
37
Data/InjectedHTML.cs
Normal file
37
Data/InjectedHTML.cs
Normal file
@@ -0,0 +1,37 @@
|
|||||||
|
using System;
|
||||||
|
|
||||||
|
namespace TweetDuck.Data{
|
||||||
|
sealed class InjectedHTML{
|
||||||
|
public enum Position{
|
||||||
|
Before, After
|
||||||
|
}
|
||||||
|
|
||||||
|
private readonly Position position;
|
||||||
|
private readonly string search;
|
||||||
|
private readonly string html;
|
||||||
|
|
||||||
|
public InjectedHTML(Position position, string search, string html){
|
||||||
|
this.position = position;
|
||||||
|
this.search = search;
|
||||||
|
this.html = html;
|
||||||
|
}
|
||||||
|
|
||||||
|
public string Inject(string targetHTML){
|
||||||
|
int index = targetHTML.IndexOf(search, StringComparison.Ordinal);
|
||||||
|
|
||||||
|
if (index == -1){
|
||||||
|
return targetHTML;
|
||||||
|
}
|
||||||
|
|
||||||
|
int cutIndex;
|
||||||
|
|
||||||
|
switch(position){
|
||||||
|
case Position.Before: cutIndex = index; break;
|
||||||
|
case Position.After: cutIndex = index+search.Length; break;
|
||||||
|
default: return targetHTML;
|
||||||
|
}
|
||||||
|
|
||||||
|
return targetHTML.Insert(cutIndex, html);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
146
Data/Serialization/FileSerializer.cs
Normal file
146
Data/Serialization/FileSerializer.cs
Normal file
@@ -0,0 +1,146 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.IO;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Reflection;
|
||||||
|
using System.Runtime.Serialization;
|
||||||
|
|
||||||
|
namespace TweetDuck.Data.Serialization{
|
||||||
|
sealed class FileSerializer<T>{
|
||||||
|
private const string NewLineReal = "\r\n";
|
||||||
|
private const string NewLineCustom = "\r~\n";
|
||||||
|
|
||||||
|
private static readonly ITypeConverter BasicSerializerObj = new BasicTypeConverter();
|
||||||
|
|
||||||
|
public delegate void HandleUnknownPropertiesHandler(T obj, Dictionary<string, string> data);
|
||||||
|
public HandleUnknownPropertiesHandler HandleUnknownProperties { get; set; }
|
||||||
|
|
||||||
|
private readonly Dictionary<string, PropertyInfo> props;
|
||||||
|
private readonly Dictionary<Type, ITypeConverter> converters;
|
||||||
|
|
||||||
|
public FileSerializer(){
|
||||||
|
this.props = typeof(T).GetProperties(BindingFlags.Instance | BindingFlags.Public).Where(prop => prop.CanWrite).ToDictionary(prop => prop.Name);
|
||||||
|
this.converters = new Dictionary<Type, ITypeConverter>();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void RegisterTypeConverter(Type type, ITypeConverter converter){
|
||||||
|
converters[type] = converter;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Write(string file, T obj){
|
||||||
|
using(StreamWriter writer = new StreamWriter(new FileStream(file, FileMode.Create, FileAccess.Write, FileShare.None))){
|
||||||
|
foreach(KeyValuePair<string, PropertyInfo> prop in props){
|
||||||
|
Type type = prop.Value.PropertyType;
|
||||||
|
object value = prop.Value.GetValue(obj);
|
||||||
|
|
||||||
|
if (!converters.TryGetValue(type, out ITypeConverter serializer)) {
|
||||||
|
serializer = BasicSerializerObj;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (serializer.TryWriteType(type, value, out string converted)){
|
||||||
|
if (converted != null){
|
||||||
|
writer.Write($"{prop.Key} {converted.Replace(Environment.NewLine, NewLineCustom)}");
|
||||||
|
writer.Write(NewLineReal);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
throw new SerializationException($"Invalid serialization type, conversion failed for: {type}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Read(string file, T obj){
|
||||||
|
Dictionary<string, string> unknownProperties = new Dictionary<string, string>(4);
|
||||||
|
|
||||||
|
using(StreamReader reader = new StreamReader(new FileStream(file, FileMode.Open, FileAccess.Read, FileShare.Read))){
|
||||||
|
if (reader.Peek() <= 1){
|
||||||
|
throw new FormatException("Input appears to be a binary file.");
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach(string line in reader.ReadToEnd().Split(new string[]{ NewLineReal }, StringSplitOptions.RemoveEmptyEntries)){
|
||||||
|
int space = line.IndexOf(' ');
|
||||||
|
|
||||||
|
if (space == -1){
|
||||||
|
throw new SerializationException($"Invalid file format, missing separator: {line}");
|
||||||
|
}
|
||||||
|
|
||||||
|
string property = line.Substring(0, space);
|
||||||
|
string value = line.Substring(space+1).Replace(NewLineCustom, Environment.NewLine);
|
||||||
|
|
||||||
|
if (props.TryGetValue(property, out PropertyInfo info)){
|
||||||
|
if (!converters.TryGetValue(info.PropertyType, out ITypeConverter serializer)) {
|
||||||
|
serializer = BasicSerializerObj;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (serializer.TryReadType(info.PropertyType, value, out object converted)){
|
||||||
|
info.SetValue(obj, converted);
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
throw new SerializationException($"Invalid file format, cannot convert value: {value} (property: {property})");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
unknownProperties[property] = value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (unknownProperties.Count > 0){
|
||||||
|
HandleUnknownProperties?.Invoke(obj, unknownProperties);
|
||||||
|
|
||||||
|
if (unknownProperties.Count > 0){
|
||||||
|
throw new SerializationException($"Invalid file format, unknown properties: {string.Join(", ", unknownProperties.Keys)}+");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private class BasicTypeConverter : ITypeConverter{
|
||||||
|
bool ITypeConverter.TryWriteType(Type type, object value, out string converted){
|
||||||
|
switch(Type.GetTypeCode(type)){
|
||||||
|
case TypeCode.Boolean:
|
||||||
|
converted = value.ToString();
|
||||||
|
return true;
|
||||||
|
|
||||||
|
case TypeCode.Int32:
|
||||||
|
converted = ((int)value).ToString(); // cast required for enums
|
||||||
|
return true;
|
||||||
|
|
||||||
|
case TypeCode.String:
|
||||||
|
converted = value?.ToString();
|
||||||
|
return true;
|
||||||
|
|
||||||
|
default:
|
||||||
|
converted = null;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ITypeConverter.TryReadType(Type type, string value, out object converted){
|
||||||
|
switch(Type.GetTypeCode(type)){
|
||||||
|
case TypeCode.Boolean:
|
||||||
|
if (bool.TryParse(value, out bool b)){
|
||||||
|
converted = b;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
else goto default;
|
||||||
|
|
||||||
|
case TypeCode.Int32:
|
||||||
|
if (int.TryParse(value, out int i)){
|
||||||
|
converted = i;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
else goto default;
|
||||||
|
|
||||||
|
case TypeCode.String:
|
||||||
|
converted = value;
|
||||||
|
return true;
|
||||||
|
|
||||||
|
default:
|
||||||
|
converted = null;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
8
Data/Serialization/ITypeConverter.cs
Normal file
8
Data/Serialization/ITypeConverter.cs
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
using System;
|
||||||
|
|
||||||
|
namespace TweetDuck.Data.Serialization{
|
||||||
|
interface ITypeConverter{
|
||||||
|
bool TryWriteType(Type type, object value, out string converted);
|
||||||
|
bool TryReadType(Type type, string value, out object converted);
|
||||||
|
}
|
||||||
|
}
|
||||||
28
Data/Serialization/SingleTypeConverter.cs
Normal file
28
Data/Serialization/SingleTypeConverter.cs
Normal file
@@ -0,0 +1,28 @@
|
|||||||
|
using System;
|
||||||
|
|
||||||
|
namespace TweetDuck.Data.Serialization{
|
||||||
|
sealed class SingleTypeConverter<T> : ITypeConverter{
|
||||||
|
public Func<T, string> ConvertToString { get; set; }
|
||||||
|
public Func<string, T> ConvertToObject { get; set; }
|
||||||
|
|
||||||
|
bool ITypeConverter.TryWriteType(Type type, object value, out string converted){
|
||||||
|
try{
|
||||||
|
converted = ConvertToString((T)value);
|
||||||
|
return true;
|
||||||
|
}catch{
|
||||||
|
converted = null;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ITypeConverter.TryReadType(Type type, string value, out object converted){
|
||||||
|
try{
|
||||||
|
converted = ConvertToObject(value);
|
||||||
|
return true;
|
||||||
|
}catch{
|
||||||
|
converted = null;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
102
Data/TwoKeyDictionary.cs
Normal file
102
Data/TwoKeyDictionary.cs
Normal file
@@ -0,0 +1,102 @@
|
|||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
|
||||||
|
namespace TweetDuck.Data{
|
||||||
|
sealed class TwoKeyDictionary<K1, K2, V>{
|
||||||
|
private readonly Dictionary<K1, Dictionary<K2, V>> dict;
|
||||||
|
private readonly int innerCapacity;
|
||||||
|
|
||||||
|
public TwoKeyDictionary() : this(16, 16){}
|
||||||
|
|
||||||
|
public TwoKeyDictionary(int outerCapacity, int innerCapacity){
|
||||||
|
this.dict = new Dictionary<K1, Dictionary<K2, V>>(outerCapacity);
|
||||||
|
this.innerCapacity = innerCapacity;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Properties
|
||||||
|
|
||||||
|
public V this[K1 outerKey, K2 innerKey]{
|
||||||
|
get{ // throws on missing key
|
||||||
|
return dict[outerKey][innerKey];
|
||||||
|
}
|
||||||
|
|
||||||
|
set{
|
||||||
|
if (!dict.TryGetValue(outerKey, out Dictionary<K2, V> innerDict)){
|
||||||
|
dict.Add(outerKey, innerDict = new Dictionary<K2, V>(innerCapacity));
|
||||||
|
}
|
||||||
|
|
||||||
|
innerDict[innerKey] = value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public IEnumerable<V> InnerValues{
|
||||||
|
get{
|
||||||
|
foreach(Dictionary<K2, V> innerDict in dict.Values){
|
||||||
|
foreach(V value in innerDict.Values){
|
||||||
|
yield return value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Members
|
||||||
|
|
||||||
|
public void Add(K1 outerKey, K2 innerKey, V value){ // throws on duplicate
|
||||||
|
if (!dict.TryGetValue(outerKey, out Dictionary<K2, V> innerDict)){
|
||||||
|
dict.Add(outerKey, innerDict = new Dictionary<K2, V>(innerCapacity));
|
||||||
|
}
|
||||||
|
|
||||||
|
innerDict.Add(innerKey, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Clear(){
|
||||||
|
dict.Clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Clear(K1 outerKey){ // throws on missing key, but keeps the key unlike Remove(K1)
|
||||||
|
dict[outerKey].Clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool Contains(K1 outerKey){
|
||||||
|
return dict.ContainsKey(outerKey);
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool Contains(K1 outerKey, K2 innerKey){
|
||||||
|
Dictionary<K2, V> innerDict;
|
||||||
|
return dict.TryGetValue(outerKey, out innerDict) && innerDict.ContainsKey(innerKey);
|
||||||
|
}
|
||||||
|
|
||||||
|
public int Count(){
|
||||||
|
return dict.Values.Sum(d => d.Count);
|
||||||
|
}
|
||||||
|
|
||||||
|
public int Count(K1 outerKey){ // throws on missing key
|
||||||
|
return dict[outerKey].Count;
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool Remove(K1 outerKey){
|
||||||
|
return dict.Remove(outerKey);
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool Remove(K1 outerKey, K2 innerKey){
|
||||||
|
if (dict.TryGetValue(outerKey, out Dictionary<K2, V> innerDict) && innerDict.Remove(innerKey)){
|
||||||
|
if (innerDict.Count == 0) {
|
||||||
|
dict.Remove(outerKey);
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
else return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool TryGetValue(K1 outerKey, K2 innerKey, out V value){
|
||||||
|
if (dict.TryGetValue(outerKey, out Dictionary<K2, V> innerDict)){
|
||||||
|
return innerDict.TryGetValue(innerKey, out value);
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
value = default(V);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
44
Data/WindowState.cs
Normal file
44
Data/WindowState.cs
Normal file
@@ -0,0 +1,44 @@
|
|||||||
|
using System;
|
||||||
|
using System.Drawing;
|
||||||
|
using System.Windows.Forms;
|
||||||
|
using TweetDuck.Core.Controls;
|
||||||
|
using TweetDuck.Core.Utils;
|
||||||
|
using TweetDuck.Data.Serialization;
|
||||||
|
|
||||||
|
namespace TweetDuck.Data{
|
||||||
|
[Serializable] // TODO remove attribute with UserConfigLegacy
|
||||||
|
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'
|
||||||
|
};
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
168
Migration/FormMigrationQuestion.Designer.cs
generated
168
Migration/FormMigrationQuestion.Designer.cs
generated
@@ -1,168 +0,0 @@
|
|||||||
using TweetDick.Core.Controls;
|
|
||||||
|
|
||||||
namespace TweetDick.Migration {
|
|
||||||
partial class FormMigrationQuestion {
|
|
||||||
/// <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.btnIgnore = new System.Windows.Forms.Button();
|
|
||||||
this.panelButtons = new System.Windows.Forms.FlowLayoutPanel();
|
|
||||||
this.btnAskLater = new System.Windows.Forms.Button();
|
|
||||||
this.btnCopy = new System.Windows.Forms.Button();
|
|
||||||
this.btnMigrate = new System.Windows.Forms.Button();
|
|
||||||
this.btnMigrateUninstall = new System.Windows.Forms.Button();
|
|
||||||
this.labelQuestion = new RichTextLabel();
|
|
||||||
this.panelButtons.SuspendLayout();
|
|
||||||
this.SuspendLayout();
|
|
||||||
//
|
|
||||||
// btnIgnore
|
|
||||||
//
|
|
||||||
this.btnIgnore.AutoSize = true;
|
|
||||||
this.btnIgnore.AutoSizeMode = System.Windows.Forms.AutoSizeMode.GrowAndShrink;
|
|
||||||
this.btnIgnore.Location = new System.Drawing.Point(356, 0);
|
|
||||||
this.btnIgnore.Margin = new System.Windows.Forms.Padding(3, 0, 0, 0);
|
|
||||||
this.btnIgnore.Name = "btnIgnore";
|
|
||||||
this.btnIgnore.Padding = new System.Windows.Forms.Padding(3, 0, 3, 0);
|
|
||||||
this.btnIgnore.Size = new System.Drawing.Size(53, 23);
|
|
||||||
this.btnIgnore.TabIndex = 1;
|
|
||||||
this.btnIgnore.Text = "Ignore";
|
|
||||||
this.btnIgnore.UseVisualStyleBackColor = true;
|
|
||||||
this.btnIgnore.Click += new System.EventHandler(this.btnIgnore_Click);
|
|
||||||
//
|
|
||||||
// panelButtons
|
|
||||||
//
|
|
||||||
this.panelButtons.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left)
|
|
||||||
| System.Windows.Forms.AnchorStyles.Right)));
|
|
||||||
this.panelButtons.Controls.Add(this.btnAskLater);
|
|
||||||
this.panelButtons.Controls.Add(this.btnIgnore);
|
|
||||||
this.panelButtons.Controls.Add(this.btnCopy);
|
|
||||||
this.panelButtons.Controls.Add(this.btnMigrate);
|
|
||||||
this.panelButtons.Controls.Add(this.btnMigrateUninstall);
|
|
||||||
this.panelButtons.FlowDirection = System.Windows.Forms.FlowDirection.RightToLeft;
|
|
||||||
this.panelButtons.Location = new System.Drawing.Point(12, 87);
|
|
||||||
this.panelButtons.Name = "panelButtons";
|
|
||||||
this.panelButtons.Size = new System.Drawing.Size(480, 23);
|
|
||||||
this.panelButtons.TabIndex = 0;
|
|
||||||
//
|
|
||||||
// btnAskLater
|
|
||||||
//
|
|
||||||
this.btnAskLater.AutoSize = true;
|
|
||||||
this.btnAskLater.AutoSizeMode = System.Windows.Forms.AutoSizeMode.GrowAndShrink;
|
|
||||||
this.btnAskLater.Location = new System.Drawing.Point(412, 0);
|
|
||||||
this.btnAskLater.Margin = new System.Windows.Forms.Padding(3, 0, 0, 0);
|
|
||||||
this.btnAskLater.Name = "btnAskLater";
|
|
||||||
this.btnAskLater.Padding = new System.Windows.Forms.Padding(3, 0, 3, 0);
|
|
||||||
this.btnAskLater.Size = new System.Drawing.Size(68, 23);
|
|
||||||
this.btnAskLater.TabIndex = 0;
|
|
||||||
this.btnAskLater.Text = "Ask Later";
|
|
||||||
this.btnAskLater.UseVisualStyleBackColor = true;
|
|
||||||
this.btnAskLater.Click += new System.EventHandler(this.btnAskLater_Click);
|
|
||||||
//
|
|
||||||
// btnCopy
|
|
||||||
//
|
|
||||||
this.btnCopy.AutoSize = true;
|
|
||||||
this.btnCopy.AutoSizeMode = System.Windows.Forms.AutoSizeMode.GrowAndShrink;
|
|
||||||
this.btnCopy.Location = new System.Drawing.Point(303, 0);
|
|
||||||
this.btnCopy.Margin = new System.Windows.Forms.Padding(3, 0, 3, 0);
|
|
||||||
this.btnCopy.Name = "btnCopy";
|
|
||||||
this.btnCopy.Padding = new System.Windows.Forms.Padding(3, 0, 3, 0);
|
|
||||||
this.btnCopy.Size = new System.Drawing.Size(47, 23);
|
|
||||||
this.btnCopy.TabIndex = 2;
|
|
||||||
this.btnCopy.Text = "Copy";
|
|
||||||
this.btnCopy.UseVisualStyleBackColor = true;
|
|
||||||
this.btnCopy.Click += new System.EventHandler(this.btnCopy_Click);
|
|
||||||
//
|
|
||||||
// btnMigrate
|
|
||||||
//
|
|
||||||
this.btnMigrate.AutoSize = true;
|
|
||||||
this.btnMigrate.AutoSizeMode = System.Windows.Forms.AutoSizeMode.GrowAndShrink;
|
|
||||||
this.btnMigrate.Location = new System.Drawing.Point(239, 0);
|
|
||||||
this.btnMigrate.Margin = new System.Windows.Forms.Padding(3, 0, 3, 0);
|
|
||||||
this.btnMigrate.Name = "btnMigrate";
|
|
||||||
this.btnMigrate.Padding = new System.Windows.Forms.Padding(3, 0, 3, 0);
|
|
||||||
this.btnMigrate.Size = new System.Drawing.Size(58, 23);
|
|
||||||
this.btnMigrate.TabIndex = 3;
|
|
||||||
this.btnMigrate.Text = "Migrate";
|
|
||||||
this.btnMigrate.UseVisualStyleBackColor = true;
|
|
||||||
this.btnMigrate.Click += new System.EventHandler(this.btnMigrate_Click);
|
|
||||||
//
|
|
||||||
// btnMigrateUninstall
|
|
||||||
//
|
|
||||||
this.btnMigrateUninstall.AutoSize = true;
|
|
||||||
this.btnMigrateUninstall.AutoSizeMode = System.Windows.Forms.AutoSizeMode.GrowAndShrink;
|
|
||||||
this.btnMigrateUninstall.Location = new System.Drawing.Point(135, 0);
|
|
||||||
this.btnMigrateUninstall.Margin = new System.Windows.Forms.Padding(0, 0, 3, 0);
|
|
||||||
this.btnMigrateUninstall.Name = "btnMigrateUninstall";
|
|
||||||
this.btnMigrateUninstall.Padding = new System.Windows.Forms.Padding(3, 0, 3, 0);
|
|
||||||
this.btnMigrateUninstall.Size = new System.Drawing.Size(98, 23);
|
|
||||||
this.btnMigrateUninstall.TabIndex = 4;
|
|
||||||
this.btnMigrateUninstall.Text = "Migrate && Purge";
|
|
||||||
this.btnMigrateUninstall.UseVisualStyleBackColor = true;
|
|
||||||
this.btnMigrateUninstall.Click += new System.EventHandler(this.btnMigrateUninstall_Click);
|
|
||||||
//
|
|
||||||
// labelQuestion
|
|
||||||
//
|
|
||||||
this.labelQuestion.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.labelQuestion.BorderStyle = System.Windows.Forms.BorderStyle.None;
|
|
||||||
this.labelQuestion.Location = new System.Drawing.Point(49, 9);
|
|
||||||
this.labelQuestion.Margin = new System.Windows.Forms.Padding(40, 3, 3, 3);
|
|
||||||
this.labelQuestion.Name = "labelQuestion";
|
|
||||||
this.labelQuestion.ReadOnly = true;
|
|
||||||
this.labelQuestion.ScrollBars = System.Windows.Forms.RichTextBoxScrollBars.None;
|
|
||||||
this.labelQuestion.Size = new System.Drawing.Size(443, 72);
|
|
||||||
this.labelQuestion.TabIndex = 2;
|
|
||||||
this.labelQuestion.TabStop = false;
|
|
||||||
this.labelQuestion.Text = "";
|
|
||||||
//
|
|
||||||
// FormMigrationQuestion
|
|
||||||
//
|
|
||||||
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
|
|
||||||
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
|
|
||||||
this.ClientSize = new System.Drawing.Size(504, 122);
|
|
||||||
this.Controls.Add(this.labelQuestion);
|
|
||||||
this.Controls.Add(this.panelButtons);
|
|
||||||
this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedDialog;
|
|
||||||
this.MaximizeBox = false;
|
|
||||||
this.MinimizeBox = false;
|
|
||||||
this.Name = "FormMigrationQuestion";
|
|
||||||
this.StartPosition = System.Windows.Forms.FormStartPosition.CenterScreen;
|
|
||||||
this.Text = "TweetDeck Migration";
|
|
||||||
this.panelButtons.ResumeLayout(false);
|
|
||||||
this.panelButtons.PerformLayout();
|
|
||||||
this.ResumeLayout(false);
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
#endregion
|
|
||||||
|
|
||||||
private System.Windows.Forms.Button btnIgnore;
|
|
||||||
private System.Windows.Forms.FlowLayoutPanel panelButtons;
|
|
||||||
private System.Windows.Forms.Button btnCopy;
|
|
||||||
private System.Windows.Forms.Button btnMigrate;
|
|
||||||
private RichTextLabel labelQuestion;
|
|
||||||
private System.Windows.Forms.Button btnAskLater;
|
|
||||||
private System.Windows.Forms.Button btnMigrateUninstall;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,47 +0,0 @@
|
|||||||
using System;
|
|
||||||
using System.Drawing;
|
|
||||||
using System.Windows.Forms;
|
|
||||||
using TweetDick.Core.Controls;
|
|
||||||
|
|
||||||
namespace TweetDick.Migration{
|
|
||||||
partial class FormMigrationQuestion : Form{
|
|
||||||
public MigrationDecision Decision { get; private set; }
|
|
||||||
|
|
||||||
public FormMigrationQuestion(){
|
|
||||||
InitializeComponent();
|
|
||||||
|
|
||||||
labelQuestion.Rtf = RichTextLabel.Wrap(@"Hey there, I found some TweetDeck data! Do you want to \b Migrate\b0 it and delete the old data folder, \b Copy\b0 it and keep the folder, \b Ignore\b0 the request forever, or do you need some more time for the decision?\par You may also \b Migrate & Purge\b0 which uninstalls TweetDeck too!");
|
|
||||||
}
|
|
||||||
|
|
||||||
protected override void OnPaint(PaintEventArgs e){
|
|
||||||
e.Graphics.DrawIcon(SystemIcons.Question,10,10);
|
|
||||||
base.OnPaint(e);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void btnMigrateUninstall_Click(object sender, EventArgs e){
|
|
||||||
Close(MigrationDecision.MigratePurge);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void btnMigrate_Click(object sender, EventArgs e){
|
|
||||||
Close(MigrationDecision.Migrate);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void btnCopy_Click(object sender, EventArgs e){
|
|
||||||
Close(MigrationDecision.Copy);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void btnIgnore_Click(object sender, EventArgs e){
|
|
||||||
Close(MigrationDecision.Ignore);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void btnAskLater_Click(object sender, EventArgs e){
|
|
||||||
Close(MigrationDecision.AskLater);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void Close(MigrationDecision decision){
|
|
||||||
Decision = decision;
|
|
||||||
DialogResult = DialogResult.OK;
|
|
||||||
Close();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,42 +0,0 @@
|
|||||||
using System;
|
|
||||||
using Shell32;
|
|
||||||
using System.IO;
|
|
||||||
|
|
||||||
namespace TweetDick.Migration.Helpers{
|
|
||||||
sealed class LnkEditor{
|
|
||||||
private readonly ShellLinkObject obj;
|
|
||||||
|
|
||||||
public LnkEditor(string file){
|
|
||||||
try{
|
|
||||||
Shell shell = new Shell();
|
|
||||||
Folder folder = shell.NameSpace(Path.GetDirectoryName(file));
|
|
||||||
FolderItem item = folder.Items().Item(Path.GetFileName(file));
|
|
||||||
|
|
||||||
obj = item.GetLink as ShellLinkObject;
|
|
||||||
}catch(Exception){
|
|
||||||
obj = null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void SetComment(string newComment){
|
|
||||||
if (obj == null)return;
|
|
||||||
obj.Description = newComment;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void SetPath(string newPath){
|
|
||||||
if (obj == null)return;
|
|
||||||
obj.Path = newPath;
|
|
||||||
obj.SetIconLocation(newPath,0);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void SetWorkingDirectory(string newWorkingDirectory){
|
|
||||||
if (obj == null)return;
|
|
||||||
obj.WorkingDirectory = newWorkingDirectory;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void Save(){
|
|
||||||
if (obj == null)return;
|
|
||||||
obj.Save();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,15 +0,0 @@
|
|||||||
using System;
|
|
||||||
using System.Diagnostics;
|
|
||||||
using System.Linq;
|
|
||||||
|
|
||||||
namespace TweetDick.Migration.Helpers{
|
|
||||||
static class ProgramProcessSearch{
|
|
||||||
public static Process FindProcessWithWindowByName(string name){
|
|
||||||
try{
|
|
||||||
return Process.GetProcessesByName(name).FirstOrDefault(process => process.MainWindowHandle != IntPtr.Zero);
|
|
||||||
}catch(Exception){
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,43 +0,0 @@
|
|||||||
using System;
|
|
||||||
using System.Linq;
|
|
||||||
using Microsoft.Win32;
|
|
||||||
|
|
||||||
namespace TweetDick.Migration.Helpers{
|
|
||||||
static class ProgramRegistrySearch{
|
|
||||||
public static string FindByDisplayName(string displayName){
|
|
||||||
Predicate<RegistryKey> predicate = key => displayName.Equals(key.GetValue("DisplayName") as string,StringComparison.OrdinalIgnoreCase);
|
|
||||||
string guid;
|
|
||||||
|
|
||||||
return FindMatchingSubKey(Registry.LocalMachine,@"SOFTWARE\Wow6432Node\Microsoft\Windows\CurrentVersion\Uninstall",predicate,out guid) ||
|
|
||||||
FindMatchingSubKey(Registry.LocalMachine,@"SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall",predicate,out guid) ||
|
|
||||||
FindMatchingSubKey(Registry.CurrentUser,@"SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall",predicate,out guid)
|
|
||||||
? guid : null;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static bool FindMatchingSubKey(RegistryKey keyHandle, string path, Predicate<RegistryKey> predicate, out string guid){
|
|
||||||
string outputId = null;
|
|
||||||
|
|
||||||
try{
|
|
||||||
RegistryKey parentKey = keyHandle.OpenSubKey(path,false);
|
|
||||||
if (parentKey == null)throw new InvalidOperationException();
|
|
||||||
|
|
||||||
foreach(RegistryKey subKey in parentKey.GetSubKeyNames().Select(subName => parentKey.OpenSubKey(subName,false)).Where(subKey => subKey != null)){
|
|
||||||
if (predicate(subKey)){
|
|
||||||
outputId = subKey.Name.Substring(subKey.Name.LastIndexOf('\\')+1);
|
|
||||||
subKey.Close();
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
subKey.Close();
|
|
||||||
}
|
|
||||||
|
|
||||||
parentKey.Close();
|
|
||||||
}catch(Exception){
|
|
||||||
guid = null;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
return (guid = outputId) != null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,28 +0,0 @@
|
|||||||
namespace TweetDick.Migration{
|
|
||||||
enum MigrationDecision{
|
|
||||||
/// <summary>
|
|
||||||
/// Copies the important files and then deletes the TweetDeck folder.
|
|
||||||
/// </summary>
|
|
||||||
Migrate,
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Does exactly what <see cref="Migrate"/> does, but also silently uninstalls TweetDeck.
|
|
||||||
/// </summary>
|
|
||||||
MigratePurge,
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Copies the important files without deleting the TweetDeck folder.
|
|
||||||
/// </summary>
|
|
||||||
Copy,
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Does not copy any files and does not ask the user about data migration again.
|
|
||||||
/// </summary>
|
|
||||||
Ignore,
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Does not copy any files but asks the user again when the program is re-ran.
|
|
||||||
/// </summary>
|
|
||||||
AskLater
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user