Compare commits

...

215 Commits

Author SHA1 Message Date
Space Time
e1b1c606e1 1.1.4 -> 1.1.5 第29次更新 2025-06-26 13:03:30 +08:00
Space Time
46de61c4f2 1.1.4 -> 1.1.5 第28次更新 2025-06-25 22:15:17 +08:00
Space Time
479c16c2a1 1.1.4 -> 1.1.5 第27次更新 2025-06-06 10:35:25 +08:00
Space Time
938ca77fc1 1.1.4 -> 1.1.5 第26次更新 2025-06-05 09:27:48 +08:00
Space Time
d9e307e647 1.1.4 -> 1.1.5 第25次更新 2025-06-05 09:09:16 +08:00
Space Time
85213b61da 1.1.4 -> 1.1.5 第24次更新 2025-06-05 08:54:06 +08:00
Space Time
bf7772a35f 1.1.4 -> 1.1.5 第23次更新 2025-06-04 21:59:22 +08:00
Space Time
188e56b57b 1.1.4 -> 1.1.5 第22次更新 2025-05-25 13:48:04 +08:00
Space Time
0150440de4 1.1.4 -> 1.1.5 第21次更新 2025-03-18 15:56:27 +08:00
Space Time
c25888bd5a 1.1.4 -> 1.1.5 第20次更新 2025-03-10 17:17:34 +08:00
Space Time
a97b04e5d9 1.1.4 -> 1.1.5 第19次更新 2025-03-03 17:03:23 +08:00
Space Time
b3dc94eb2b 1.1.4 -> 1.1.5 第18次更新 2025-03-01 12:44:47 +08:00
Space Time
597e441af5 1.1.4 -> 1.1.5 第17次更新 2025-02-25 16:30:10 +08:00
Space Time
8a81ba59dc 1.1.4 -> 1.1.5 第16次更新 2024-12-30 18:50:41 +08:00
Space Time
d748976aa9 1.1.5 (alpha) 更新 2024-12-30 16:34:12 +08:00
Space Time
f428de3fd7 1.1.4 -> 1.1.5 第15次更新 2024-12-29 22:16:58 +08:00
Space Time
bcccb73520 1.1.4 -> 1.1.5 第14次更新 2024-12-29 20:53:56 +08:00
Space Time
6fd9631d5c 1.1.4 -> 1.1.5 第13次更新 2024-12-29 20:04:24 +08:00
Space Time
2c5004f02d 1.1.4 -> 1.1.5 第12次更新 2024-12-29 19:52:54 +08:00
Space Time
8de6980f59 1.1.4 -> 1.1.5 第11次更新 2024-12-29 15:50:45 +08:00
Space Time
b1d41436de 1.1.4 -> 1.1.5 第10次更新 2024-12-29 15:13:28 +08:00
Space Time
1fd5b99e67 1.1.4 -> 1.1.5 第9次更新 2024-12-28 17:30:04 +08:00
Space Time
eecec3bbd7 1.1.4 -> 1.1.5 第8次更新 2024-12-27 22:10:50 +08:00
Space Time
ccf47c85c9 1.1.4 -> 1.1.5 第7次更新 2024-12-26 12:58:04 +08:00
Space Time
cf616b33a8 1.1.4 -> 1.1.5 第6次更新 2024-12-26 12:51:48 +08:00
Space Time
592f871778 1.1.4 -> 1.1.5 第5次更新 2024-12-26 12:46:20 +08:00
Space Time
f625d79667 1.1.4 -> 1.1.5 第4次更新 2024-12-26 12:35:53 +08:00
Space Time
80abfa8116 1.1.4 -> 1.1.5 第3次更新 2024-12-23 22:17:15 +08:00
Space Time
87d97c2f04 1.1.4 -> 1.1.5 第2次更新 2024-12-23 22:06:35 +08:00
Space Time
345c291305 1.1.4 -> 1.1.5 第1次更新 2024-12-23 13:57:39 +08:00
Space Time
5af134c7a4 1.1.4 更新 2024-12-22 00:33:56 +08:00
Space Time
bd73327fc0 1.1.3 -> 1.1.4 第93次更新 2024-12-20 22:49:08 +08:00
Space Time
1a08c65c0d 1.1.3 -> 1.1.4 第92次更新 2024-12-20 21:18:57 +08:00
Space Time
64f4bbad02 1.1.3 -> 1.1.4 第91次更新 2024-12-20 19:26:56 +08:00
Space Time
b52eb93e40 1.1.3 -> 1.1.4 第90次更新 2024-12-20 18:38:09 +08:00
Space Time
f1e9df5418 1.1.3 -> 1.1.4 第89次更新 2024-12-20 18:15:57 +08:00
Space Time
9ea750e336 1.1.3 -> 1.1.4 第88次更新 2024-12-20 17:43:50 +08:00
Space Time
e66f1eb5b2 1.1.3 -> 1.1.4 第87次更新 2024-12-20 17:19:11 +08:00
Space Time
ec5d3893fb 1.1.3 -> 1.1.4 第86次更新 2024-12-20 15:58:05 +08:00
Space Time
13d8663a6e 1.1.3 -> 1.1.4 第85次更新 2024-12-20 13:15:28 +08:00
Space Time
af28d96bf9 1.1.3 -> 1.1.4 第84次更新 2024-12-20 11:09:32 +08:00
Space Time
dcef7be238 1.1.3 -> 1.1.4 第83次更新 2024-12-20 00:50:13 +08:00
Space Time
6a7b65fe99 1.1.3 -> 1.1.4 第82次更新 2024-12-20 00:00:54 +08:00
Space Time
e962850d05 1.1.3 -> 1.1.4 第81次更新 2024-12-19 11:19:58 +08:00
Space Time
aa5765d168 1.1.3 -> 1.1.4 第80次更新 2024-12-19 10:55:54 +08:00
Space Time
ebe199d048 1.1.3 -> 1.1.4 第79次更新 2024-12-19 00:00:05 +08:00
Space Time
56185d2750 1.1.3 -> 1.1.4 第78次更新 2024-12-18 23:41:05 +08:00
Space Time
c7efd8df68 1.1.3 -> 1.1.4 第77次更新 2024-12-18 22:33:46 +08:00
Space Time
92f55711a6 1.1.3 -> 1.1.4 第76次更新 2024-12-18 21:31:25 +08:00
Space Time
b54ef3a3bb 1.1.3 -> 1.1.4 第75次更新 2024-12-18 21:22:01 +08:00
Space Time
0f3724508c 1.1.3 -> 1.1.4 第74次更新 2024-12-18 20:25:58 +08:00
Space Time
e0317c870f 1.1.3 -> 1.1.4 第73次更新 2024-12-18 20:12:08 +08:00
Space Time
49fb4cf655 1.1.3 -> 1.1.4 第72次更新 2024-12-18 20:10:21 +08:00
Space Time
419ddd8fdb 1.1.3 -> 1.1.4 第71次更新 2024-12-18 16:23:34 +08:00
Space Time
bdf34249c6 1.1.3 -> 1.1.4 第70次更新 2024-12-18 12:58:56 +08:00
Space Time
c96d51459f 1.1.3 -> 1.1.4 第69次更新 2024-12-17 22:34:20 +08:00
Space Time
536a498e65 1.1.4 (beta) 更新 2024-12-17 12:05:04 +08:00
Space Time
1e310cc69d 1.1.3 -> 1.1.4 第68次更新 2024-12-16 20:53:03 +08:00
Space Time
32871f580a 1.1.3 -> 1.1.4 第67次更新 2024-12-16 18:12:21 +08:00
Space Time
5e9ab2d928 1.1.3 -> 1.1.4 第66次更新 2024-12-16 12:19:01 +08:00
Space Time
7dd6036cec 1.1.3 -> 1.1.4 第65次更新 2024-12-16 11:36:08 +08:00
Space Time
8637b18fd2 1.1.3 -> 1.1.4 第64次更新 2024-12-16 10:47:49 +08:00
Space Time
029bd787dc 1.1.3 -> 1.1.4 第63次更新 2024-12-14 14:20:12 +08:00
Space Time
f8501fc05b 1.1.3 -> 1.1.4 第62次更新 2024-12-14 13:27:43 +08:00
Space Time
ee99628508 1.1.3 -> 1.1.4 第61次更新 2024-12-14 12:36:21 +08:00
Space Time
bf73c635d3 1.1.3 -> 1.1.4 第60次更新 2024-12-14 00:56:16 +08:00
Space Time
8dc34243bd 1.1.3 -> 1.1.4 第59次更新 2024-12-14 00:19:15 +08:00
Space Time
54f9326f29 1.1.3 -> 1.1.4 第58次更新 2024-12-14 00:12:59 +08:00
Space Time
2660c63311 1.1.3 -> 1.1.4 第57次更新 2024-12-13 23:59:11 +08:00
Space Time
dc73a30540 1.1.3 -> 1.1.4 第56次更新 2024-12-13 21:57:19 +08:00
Space Time
73de1516ea 1.1.3 -> 1.1.4 第55次更新 2024-12-13 21:25:55 +08:00
Space Time
67079cf9e0 1.1.3 -> 1.1.4 第54次更新 2024-12-13 14:05:07 +08:00
Space Time
9d50e772fd 1.1.3 -> 1.1.4 第53次更新 2024-12-12 11:06:08 +08:00
Space Time
753b53bc17 1.1.3 -> 1.1.4 第52次更新 2024-12-11 22:15:36 +08:00
Space Time
21964c0e76 1.1.3 -> 1.1.4 第51次更新 2024-12-11 22:11:09 +08:00
Space Time
ef997ad840 1.1.3 -> 1.1.4 第50次更新 2024-12-11 21:59:22 +08:00
Space Time
2b3ca3f3ee 1.1.3 -> 1.1.4 第49次更新 2024-12-11 15:36:01 +08:00
Space Time
4af0990ea6 1.1.3 -> 1.1.4 第48次更新 2024-12-11 15:17:06 +08:00
Space Time
3a95e8cbea 1.1.3 -> 1.1.4 第47次更新 2024-12-11 12:57:02 +08:00
Space Time
5a0a05e62f 1.1.3 -> 1.1.4 第46次更新 2024-12-10 22:43:01 +08:00
Space Time
6ebc22c8ea 1.1.3 -> 1.1.4 第45次更新 2024-12-10 22:06:38 +08:00
Space Time
34165391b4 1.1.3 -> 1.1.4 第44次更新 2024-12-10 19:18:16 +08:00
Space Time
2e7f4d4cf9 1.1.3 -> 1.1.4 第43次更新 2024-12-10 19:15:39 +08:00
Space Time
42bd83f4d3 1.1.3 -> 1.1.4 第42次更新 2024-12-10 16:06:48 +08:00
Space Time
4009e8ce63 1.1.3 -> 1.1.4 第41次更新 2024-12-10 00:28:46 +08:00
Space Time
66230df9a5 1.1.3 -> 1.1.4 第40次更新 2024-12-10 00:17:58 +08:00
Space Time
f7a0729eaa 1.1.3 -> 1.1.4 第39次更新 2024-12-10 00:09:19 +08:00
Space Time
73f411aca3 1.1.3 -> 1.1.4 第38次更新 2024-12-09 22:11:42 +08:00
Space Time
5e94c1e81b 1.1.3 -> 1.1.4 第37次更新 2024-12-09 21:36:22 +08:00
Space Time
dda0c2efee 1.1.3 -> 1.1.4 第36次更新 2024-12-07 22:40:17 +08:00
Space Time
688412f2b5 1.1.3 -> 1.1.4 第35次更新 2024-12-07 20:01:43 +08:00
Space Time
9709cf249b 1.1.3 -> 1.1.4 第34次更新 2024-12-07 17:22:21 +08:00
Space Time
0021b1516e 1.1.3 -> 1.1.4 第33次更新 2024-12-07 13:56:47 +08:00
Space Time
8c44b0b82a 1.1.3 -> 1.1.4 第32次更新 2024-12-07 13:06:49 +08:00
Space Time
abd180c0e7 1.1.3 -> 1.1.4 第31次更新 2024-12-07 12:22:34 +08:00
Space Time
c8bffaa96c 1.1.3 -> 1.1.4 第30次更新 2024-12-07 12:16:10 +08:00
Space Time
be23d1bce8 1.1.3 -> 1.1.4 第29次更新 2024-12-07 00:19:49 +08:00
Space Time
038e9fe7e7 1.1.3 -> 1.1.4 第28次更新 2024-12-06 23:59:26 +08:00
Space Time
8178742f62 1.1.3 -> 1.1.4 第27次更新 2024-12-06 20:16:42 +08:00
Space Time
e37ef64aca 1.1.3 -> 1.1.4 第26次更新 2024-12-06 19:38:44 +08:00
Space Time
007fea343c 1.1.3 -> 1.1.4 第25次更新 2024-12-06 16:38:18 +08:00
Space Time
fe8f73afb8 1.1.3 -> 1.1.4 第24次更新 2024-12-03 23:41:25 +08:00
Space Time
2e07e97e01 1.1.3 -> 1.1.4 第23次更新 2024-12-03 13:43:24 +08:00
Space Time
48afa92ed9 1.1.3 -> 1.1.4 第22次更新 2024-12-03 12:50:21 +08:00
Space Time
a8f408dc62 1.1.3 -> 1.1.4 第21次更新 2024-12-02 20:43:01 +08:00
Space Time
dac9459e1c 1.1.3 -> 1.1.4 第20次更新 2024-12-02 20:09:40 +08:00
Space Time
460826b1ee 1.1.3 -> 1.1.4 第19次更新 2024-12-02 19:33:04 +08:00
Space Time
426596f780 1.1.3 -> 1.1.4 第18次更新 2024-11-27 21:27:46 +08:00
Space Time
6b7542a3b9 1.1.3 -> 1.1.4 第17次更新 2024-11-27 21:15:21 +08:00
Space Time
9b1533b51c 1.1.3 -> 1.1.4 第16次更新 2024-11-25 18:54:27 +08:00
Space Time
94581ee703 1.1.3 -> 1.1.4 第15次更新 2024-11-25 18:09:36 +08:00
Space Time
144de24013 1.1.3 -> 1.1.4 第14次更新 2024-11-25 16:29:58 +08:00
Space Time
48509f46cf 1.1.3 -> 1.1.4 第13次更新 2024-11-24 22:25:33 +08:00
Space Time
21fc19059d 1.1.3 -> 1.1.4 第12次更新 2024-11-24 21:51:21 +08:00
Space Time
94ede5b64b 1.1.3 -> 1.1.4 第11次更新 2024-11-24 21:41:19 +08:00
Space Time
5bd9ef3e58 1.1.3 -> 1.1.4 第10次更新 2024-11-24 12:58:49 +08:00
Space Time
fe44a5231e 1.1.3 -> 1.1.4 第9次更新 2024-11-18 14:23:21 +08:00
Space Time
a4ff7972ae 1.1.3 -> 1.1.4 第8次更新 2024-11-15 21:33:49 +08:00
Space Time
443822902a 1.1.3 -> 1.1.4 第7次更新 2024-11-15 20:36:45 +08:00
Space Time
eef852304d 1.1.3 -> 1.1.4 第6次更新 2024-11-14 20:10:30 +08:00
Space Time
3d8f1412b4 1.1.3 -> 1.1.4 第5次更新 2024-11-13 10:59:47 +08:00
Space Time
ca92fa349d 1.1.3 -> 1.1.4 第4次更新 2024-11-12 21:17:45 +08:00
Space Time
372d900280 1.1.3 -> 1.1.4 第3次更新 2024-11-12 11:58:44 +08:00
Space Time
f100becc01 1.1.3 -> 1.1.4 第2次更新 2024-11-08 18:07:30 +08:00
Space Time
dd0064469f 1.1.3 -> 1.1.4 第1次更新 2024-11-07 22:40:41 +08:00
Space Time
27826633a1 1.1.3 更新 2024-10-21 14:42:52 +08:00
Space Time
b78c982621 1.1.2 -> 1.1.3 第21次更新 2024-10-21 13:16:07 +08:00
Space Time
3b48344946 1.1.2 -> 1.1.3 第20次更新 2024-10-21 12:00:26 +08:00
Space Time
8d8a4f016a 1.1.2 -> 1.1.3 第19次更新 2024-10-21 11:12:47 +08:00
Space Time
7932212e5f 1.1.2 -> 1.1.3 第18次更新 2024-10-21 10:50:53 +08:00
Space Time
c680f6e3f8 1.1.2 -> 1.1.3 第17次更新 2024-10-21 00:33:23 +08:00
Space Time
0c76f6ed59 1.1.2 -> 1.1.3 第16次更新 2024-10-21 00:27:12 +08:00
Space Time
37bcd63b9e 1.1.2 -> 1.1.3 第15次更新 2024-10-20 22:34:44 +08:00
Space Time
820df74051 1.1.2 -> 1.1.3 第14次更新 2024-10-20 21:11:38 +08:00
Space Time
fe2475b8fa 1.1.2 -> 1.1.3 第13次更新 2024-10-20 17:55:13 +08:00
Space Time
0a9efb4f0b 1.1.2 -> 1.1.3 第12次更新 2024-10-20 16:17:24 +08:00
Space Time
c103b860a8 1.1.2 -> 1.1.3 第11次更新 2024-10-20 12:45:18 +08:00
Space Time
bce0a8a5ca 1.1.2 -> 1.1.3 第10次更新 2024-10-20 00:35:51 +08:00
Space Time
6431a90a72 1.1.2 -> 1.1.3 第9次更新 2024-10-20 00:00:05 +08:00
Space Time
f54e470874 1.1.2 -> 1.1.3 第8次更新 2024-10-19 21:40:38 +08:00
Space Time
cfe4108590 1.1.2 -> 1.1.3 第7次更新 2024-10-16 22:35:19 +08:00
Space Time
5ba6303a8e 1.1.2 -> 1.1.3 第6次更新 2024-10-16 21:08:57 +08:00
Space Time
e016d97c71 1.1.2 -> 1.1.3 第5次更新 2024-10-16 16:55:30 +08:00
Space Time
b00e3aa8c2 1.1.2 -> 1.1.3 第4次更新 2024-10-15 11:15:31 +08:00
Space Time
a81b408f12 1.1.2 -> 1.1.3 第3次更新 2024-10-15 11:00:09 +08:00
Space Time
84b54e65de 1.1.2 -> 1.1.3 第2次更新 2024-10-10 20:03:41 +08:00
Space Time
8511a5e85d 1.1.2 -> 1.1.3 第1次更新 2024-10-09 16:23:14 +08:00
Space Time
e7fb200d97 1.1.2 更新 2024-10-07 14:22:41 +08:00
Space Time
1dbdf295cf 1.1.1 -> 1.1.2 第52次更新 2024-10-07 14:03:06 +08:00
Space Time
74f4494f45 1.1.1 -> 1.1.2 第51次更新 2024-10-07 13:59:00 +08:00
Space Time
56cbb7ec09 1.1.1 -> 1.1.2 第50次更新 2024-10-07 13:38:48 +08:00
Space Time
605c6e61a3 1.1.1 -> 1.1.2 第49次更新 2024-10-07 12:46:51 +08:00
Space Time
158ee04adc 1.1.1 -> 1.1.2 第48次更新 2024-10-07 11:48:38 +08:00
Space Time
517ff4c3b3 1.1.1 -> 1.1.2 第47次更新 2024-10-07 02:32:10 +08:00
Space Time
b0c7e551c1 1.1.1 -> 1.1.2 第46次更新 2024-10-07 00:59:04 +08:00
Space Time
5842ca0098 1.1.1 -> 1.1.2 第45次更新 2024-10-07 00:36:32 +08:00
Space Time
8e7f0a97cf 1.1.1 -> 1.1.2 第44次更新 2024-10-06 22:47:10 +08:00
Space Time
c3bcd15084 1.1.1 -> 1.1.2 第43次更新 2024-10-06 22:35:08 +08:00
Space Time
788b639c1f 1.1.1 -> 1.1.2 第42次更新 2024-10-06 21:52:19 +08:00
Space Time
f72d9bbd79 1.1.1 -> 1.1.2 第41次更新 2024-10-06 19:59:43 +08:00
Space Time
94c899d4e6 1.1.1 -> 1.1.2 第40次更新 2024-10-06 19:59:18 +08:00
Space Time
4d4b43284c 1.1.1 -> 1.1.2 第39次更新 2024-10-06 17:39:47 +08:00
Space Time
e0b671a95c 1.1.1 -> 1.1.2 第38次更新 2024-10-06 14:14:27 +08:00
Space Time
d951decd1f 1.1.1 -> 1.1.2 第37次更新 2024-10-06 14:01:43 +08:00
Space Time
35adc69eb2 1.1.1 -> 1.1.2 第36次更新 2024-10-06 13:34:38 +08:00
Space Time
c8f2a208a2 1.1.1 -> 1.1.2 第35次更新 2024-10-06 01:12:21 +08:00
Space Time
3548125178 1.1.1 -> 1.1.2 第34次更新 2024-10-06 00:32:17 +08:00
Space Time
cbab9371a0 1.1.1 -> 1.1.2 第33次更新 2024-10-05 22:39:54 +08:00
Space Time
dafd160c70 1.1.1 -> 1.1.2 第32次更新 2024-10-05 11:05:32 +08:00
Space Time
23241c8a5e 1.1.1 -> 1.1.2 第31次更新 2024-10-05 10:32:32 +08:00
Space Time
2902117840 1.1.1 -> 1.1.2 第30次更新 2024-10-05 01:07:03 +08:00
Space Time
6ad9cb3c72 1.1.1 -> 1.1.2 第29次更新 2024-10-04 21:29:12 +08:00
Space Time
57d3ede6db 1.1.1 -> 1.1.2 第28次更新 2024-10-04 21:12:20 +08:00
Space Time
b3416c9bbf 1.1.1 -> 1.1.2 第27次更新 2024-10-04 19:31:02 +08:00
Space Time
f9c6da4bb8 1.1.1 -> 1.1.2 第26次更新 2024-10-04 18:41:09 +08:00
Space Time
e61ca0a75f 1.1.1 -> 1.1.2 第25次更新 2024-10-04 18:32:28 +08:00
Space Time
f696dbb14b 1.1.1 -> 1.1.2 第24次更新 2024-10-04 17:35:31 +08:00
Space Time
c1231e3fe1 1.1.1 -> 1.1.2 第23次更新 2024-10-03 20:46:56 +08:00
Space Time
c42d7351c4 1.1.1 -> 1.1.2 第22次更新 2024-10-03 20:22:55 +08:00
Space Time
dd472b65de 1.1.1 -> 1.1.2 第21次更新 2024-10-03 19:57:51 +08:00
Space Time
091442e3c6 1.1.1 -> 1.1.2 第20次更新 2024-10-03 19:25:16 +08:00
Space Time
ee1aa2be3e 1.1.1 -> 1.1.2 第19次更新 2024-10-03 18:23:00 +08:00
Space Time
105e6ce908 1.1.1 -> 1.1.2 第18次更新 2024-10-03 11:29:44 +08:00
Space Time
db19a759ff 1.1.1 -> 1.1.2 第17次更新 2024-10-02 23:48:47 +08:00
Space Time
53384ee2ad 1.1.1 -> 1.1.2 第16次更新 2024-10-02 21:48:28 +08:00
Space Time
859e25f05e 1.1.1 -> 1.1.2 第15次更新 2024-10-02 21:36:28 +08:00
Space Time
a3b1dc6525 1.1.1 -> 1.1.2 第14次更新 2024-10-02 14:36:53 +08:00
Space Time
a25f0a9b6d 1.1.1 -> 1.1.2 第13次更新 2024-10-02 02:17:49 +08:00
Space Time
7e85989fa8 1.1.1 -> 1.1.2 第12次更新 2024-10-02 01:04:09 +08:00
Space Time
4c966e4b09 1.1.1 -> 1.1.2 第11次更新 2024-10-01 23:57:28 +08:00
Space Time
e4c772ba51 1.1.1 -> 1.1.2 第10次更新 2024-10-01 20:50:58 +08:00
Space Time
66c40aa3f4 1.1.1 -> 1.1.2 第9次更新 2024-10-01 20:44:06 +08:00
Space Time
ea201387dd 1.1.1 -> 1.1.2 第8次更新 2024-10-01 19:36:22 +08:00
Space Time
0810b64fe4 1.1.1 -> 1.1.2 第7次更新 2024-10-01 18:44:49 +08:00
Space Time
334f8a56a2 1.1.1 -> 1.1.2 第6次更新 2024-06-26 00:48:27 +08:00
Space Time
9e284e1a6a 1.1.1 -> 1.1.2 第5次更新 2024-06-23 19:00:04 +08:00
Space Time
ec8c86897f 1.1.1 -> 1.1.2 第4次更新 2024-06-23 18:34:03 +08:00
Space Time
84947471df 1.1.1 -> 1.1.2 第3次更新 2024-06-23 15:28:05 +08:00
Space Time
c378f50f22 1.1.1 -> 1.1.2 第2次更新 2024-06-14 17:12:00 +08:00
Space Time
b70a42c227 1.1.1 -> 1.1.2 第1次更新 2024-06-07 17:55:13 +08:00
Space Time
b9c3de4e75 1.1.1 更新 2024-06-07 10:14:39 +08:00
Space Time
e502c6df2e 1.1.0 -> 1.1.1 第14次更新 2024-06-07 01:52:18 +08:00
Space Time
eaaca182d4 1.1.0 -> 1.1.1 第13次更新 2024-06-07 00:59:19 +08:00
Space Time
3d307dd01f 1.1.0 -> 1.1.1 第12次更新 2024-06-06 23:52:18 +08:00
Space Time
a40b458355 1.1.0 -> 1.1.1 第11次更新 2024-06-05 16:00:15 +08:00
Space Time
2e0304fa1d 1.1.0 -> 1.1.1 第10次更新 2024-06-05 15:32:56 +08:00
Space Time
a123353068 1.1.0 -> 1.1.1 第9次更新 2024-05-30 14:22:56 +08:00
Space Time
6204dbb7e5 1.1.0 -> 1.1.1 第8次更新 2024-05-22 21:15:18 +08:00
Space Time
353d5ec8cf 1.1.0 -> 1.1.1 第7次更新 2024-05-18 20:39:36 +08:00
Space Time
9c44edfed9 1.1.0 -> 1.1.1 第6次更新 2024-05-18 19:21:53 +08:00
Space Time
a90798a22d 1.1.0 -> 1.1.1 第5次更新 2024-05-18 18:16:48 +08:00
Space Time
455ade0b2d 1.1.0 -> 1.1.1 第4次更新 2024-05-12 19:00:48 +08:00
Space Time
987a97802b 1.1.0 -> 1.1.1 第3次更新 2024-05-12 16:36:55 +08:00
Space Time
a834b7589e 1.1.0 -> 1.1.1 第2次更新 2024-05-11 22:32:05 +08:00
Space Time
45d5e7076b 1.1.0 -> 1.1.1 第1次更新 2024-04-20 19:30:00 +08:00
77 changed files with 5091 additions and 491 deletions

42
.filenesting.json Normal file
View File

@ -0,0 +1,42 @@
{
"root": true,
"dependentFileProviders": {
"add": {
"fileToFile": {
"add": {
"AboutMultilangConst.resx": [ "AboutConst.cs" ],
"AboutMultilangConst.zh.resx": [ "AboutConst.cs" ],
"MainMultilangConst.resx": [ "MainConst.cs" ],
"MainMultilangConst.zh.resx": [ "MainConst.cs" ],
"SettingsMultilangConst.resx": [ "SettingsConst.cs" ],
"SettingsMultilangConst.zh.resx": [ "SettingsConst.cs" ],
"AboutAccentButtonForegroundConv.cs": [ "AboutConv.cs" ],
"AboutVersionButtonContentConv.cs": [ "AboutConv.cs" ],
"MainAdminControlVisibilityConv.cs": [ "MainConv.cs" ],
"MainMihomoButtonContentConv.cs": [ "MainConv.cs" ],
"MainMihomoButtonIsEnabledConv.cs": [ "MainConv.cs" ],
"MainMihomoButtonToolTipConv.cs": [ "MainConv.cs" ],
"MainNginxButtonContentConv.cs": [ "MainConv.cs" ],
"MainNginxButtonIsEnabledConv.cs": [ "MainConv.cs" ],
"MainNginxButtonToolTipConv.cs": [ "MainConv.cs" ],
"MainNoClickButtonContentConv.cs": [ "MainConv.cs" ],
"MainNoClickButtonToolTipConv.cs": [ "MainConv.cs" ],
"MainProxyColumnWidthConv.cs": [ "MainConv.cs" ],
"MainSettingsBoxHintConv.cs": [ "MainConv.cs" ],
"MainSettingsBoxTextConv.cs": [ "MainConv.cs" ],
"MainSettingsBoxToolTipConv.cs": [ "MainConv.cs" ],
"MainSettingsFunctionButtonContentConv.cs": [ "MainConv.cs" ],
"MainSettingsModeButtonContentConv.cs": [ "MainConv.cs" ],
"MainBrowserButtonIsEnabledConv.cs": [ "MainConv.cs" ],
"MainUpdateHostButtonContentConv.cs": [ "MainConv.cs" ],
"MainUpdateHostButtonIsEnabledConv.cs": [ "MainConv.cs" ],
"MainWinWidthConv.cs": [ "MainConv.cs" ],
"SettingsLangsButtonContentConv.cs": [ "SettingsConv.cs" ],
"SettingsThemesButtonContentConv.cs": [ "SettingsConv.cs" ],
"SettingsWeightsButtonContentConv.cs": [ "SettingsConv.cs" ]
}
}
}
}
}

View File

@ -2,25 +2,27 @@
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:materialDesign="http://materialdesigninxaml.net/winfx/xaml/themes"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
DispatcherUnhandledException="App_DispatcherUnhandledException">
Startup="App_OnStartup" DispatcherUnhandledException="App_DispatcherUnhandledException">
<Application.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<materialDesign:BundledTheme BaseTheme="Light" PrimaryColor="Red" SecondaryColor="Orange" />
<materialDesign:BundledTheme BaseTheme="Inherit" PrimaryColor="Red" SecondaryColor="Orange" />
<ResourceDictionary Source="pack://application:,,,/MaterialDesignThemes.Wpf;component/Themes/MaterialDesign3.Defaults.xaml" />
</ResourceDictionary.MergedDictionaries>
<Style x:Key="CommonWindow" TargetType="{x:Type Window}">
<Setter Property="Background" Value="{DynamicResource MaterialDesignBackground}" />
<Setter Property="AutomationProperties.Name" Value="Sheas Cealer" />
<Setter Property="Background" Value="{DynamicResource MaterialDesignPaper}" />
<Setter Property="Foreground" Value="{DynamicResource MaterialDesignBody}" />
</Style>
<Style BasedOn="{StaticResource MaterialDesignFilledTextBox}" TargetType="{x:Type TextBox}" />
<Style BasedOn="{StaticResource MaterialDesignRaisedButton}" TargetType="{x:Type Button}">
<Setter Property="Height" Value="Auto" />
<Setter Property="Width" Value="Auto" />
<Setter Property="Background" Value="Red" />
<Setter Property="Foreground" Value="{DynamicResource MaterialDesignBackground}" />
</Style>
<Style BasedOn="{StaticResource MaterialDesignCaptionHyperlink}" TargetType="{x:Type Hyperlink}" />
</ResourceDictionary>
</Application.Resources>
</Application>

View File

@ -1,16 +1,64 @@
using System.Windows;
using MaterialDesignThemes.Wpf;
using Sheas_Cealer.Preses;
using Sheas_Cealer.Props;
using Sheas_Cealer.Utils;
using Sheas_Cealer.Wins;
using System;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Media;
using System.Windows.Threading;
namespace Sheas_Cealer
{
public partial class App : Application
{
protected override void OnStartup(StartupEventArgs e) => new MainWindow(e.Args).Show();
namespace Sheas_Cealer;
private void App_DispatcherUnhandledException(object sender, DispatcherUnhandledExceptionEventArgs e)
public partial class App : Application
{
private void App_OnStartup(object sender, StartupEventArgs e)
{
#region Upgrade Settings
if (Settings.Default.IsUpgradeRequired)
{
MessageBox.Show("Error: " + e.Exception.Message);
e.Handled = true;
Settings.Default.Upgrade();
Settings.Default.IsUpgradeRequired = false;
Settings.Default.Save();
}
#endregion Upgrade Settings
#region Primary Color
PaletteHelper paletteHelper = new();
Theme newTheme = paletteHelper.GetTheme();
Color newPrimaryColor = Color.FromRgb(Settings.Default.PrimaryColor.R, Settings.Default.PrimaryColor.G, Settings.Default.PrimaryColor.B);
newTheme.SetPrimaryColor(newPrimaryColor);
paletteHelper.SetTheme(newTheme);
#endregion Primary Color
#region Background Color
if (Environment.OSVersion.Version.Build < 22000)
{
Style newWindowStyle = new(typeof(Window), Current.Resources["CommonWindow"] as Style);
newWindowStyle.Setters.Add(new Setter(Window.BackgroundProperty, new DynamicResourceExtension("MaterialDesignBackground")));
Current.Resources["CommonWindow"] = newWindowStyle;
}
#endregion Background Color
#region Foreground Color
Style newButtonStyle = new(typeof(Button), Current.Resources[typeof(Button)] as Style);
(Color? newForegroundColor, Color newAccentForegroundColor) = ForegroundGenerator.GetForeground(newPrimaryColor.R, newPrimaryColor.G, newPrimaryColor.B);
newButtonStyle.Setters.Add(new Setter(Button.ForegroundProperty, newForegroundColor.HasValue ? new SolidColorBrush(newForegroundColor.Value) : new DynamicResourceExtension("MaterialDesignBackground")));
Current.Resources[typeof(Button)] = newButtonStyle;
new SettingsPres().AccentForegroundColor = newAccentForegroundColor;
#endregion Foreground Color
new MainWin().Show();
}
private void App_DispatcherUnhandledException(object sender, DispatcherUnhandledExceptionEventArgs e)
{
MessageBox.Show($"Error: {e.Exception.Message}");
e.Handled = true;
}
}

24
Consts/AboutConst.cs Normal file
View File

@ -0,0 +1,24 @@
using System.Reflection;
using System.Windows.Media;
namespace Sheas_Cealer.Consts;
internal abstract class AboutConst : AboutMultilangConst
{
public static Color AccentBlueColor => (Color)ColorConverter.ConvertFromString("#2196F3");
public static Color AccentRedColor => (Color)ColorConverter.ConvertFromString("#F44336");
public static string DeveloperButtonUrl => "https://www.spacetimee.xyz";
public static string VersionButtonVersionContent => Assembly.GetExecutingAssembly().GetName().Version!.ToString()[..^2];
public static string VersionButtonUrl => "https://github.com/SpaceTimee/Sheas-Cealer/releases/latest";
public static string EmailButtonUrl => "Zeus6_6@163.com";
public static string DocumentationButtonUrl => "https://github.com/SpaceTimee/Sheas-Cealer/wiki/Sheas-Cealer-Documentation";
public static string RepositoryButtonUrl => "https://github.com/SpaceTimee/Sheas-Cealer";
public static string PolicyButtonUrl => "https://thoughts.teambition.com/share/6264eda98adeb10041b92fda#title=Sheas_Cealer_隐私政策";
public static string AgreementButtonUrl => "https://thoughts.teambition.com/share/6264edd78adeb10041b92fdb#title=Sheas_Cealer_使用协议";
internal static string ReleaseApiUrl => "https://api.github.com/repos/SpaceTimee/Sheas-Cealer/releases/latest";
internal static string ReleaseApiUserAgent => "Sheas-Cealer";
}

135
Consts/AboutMultilangConst.Designer.cs generated Normal file
View File

@ -0,0 +1,135 @@
//------------------------------------------------------------------------------
// <auto-generated>
// 此代码由工具生成。
// 运行时版本:4.0.30319.42000
//
// 对此文件的更改可能会导致不正确的行为,并且如果
// 重新生成代码,这些更改将会丢失。
// </auto-generated>
//------------------------------------------------------------------------------
namespace Sheas_Cealer.Consts {
using System;
/// <summary>
/// 一个强类型的资源类,用于查找本地化的字符串等。
/// </summary>
// 此类是由 StronglyTypedResourceBuilder
// 类通过类似于 ResGen 或 Visual Studio 的工具自动生成的。
// 若要添加或移除成员,请编辑 .ResX 文件,然后重新运行 ResGen
// (以 /str 作为命令选项),或重新生成 VS 项目。
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "17.0.0.0")]
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
[global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
public class AboutMultilangConst {
private static global::System.Resources.ResourceManager resourceMan;
private static global::System.Globalization.CultureInfo resourceCulture;
[global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
internal AboutMultilangConst() {
}
/// <summary>
/// 返回此类使用的缓存的 ResourceManager 实例。
/// </summary>
[global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
public static global::System.Resources.ResourceManager ResourceManager {
get {
if (object.ReferenceEquals(resourceMan, null)) {
global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("Sheas_Cealer.Consts.AboutMultilangConst", typeof(AboutMultilangConst).Assembly);
resourceMan = temp;
}
return resourceMan;
}
}
/// <summary>
/// 重写当前线程的 CurrentUICulture 属性,对
/// 使用此强类型资源类的所有资源查找执行重写。
/// </summary>
[global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
public static global::System.Globalization.CultureInfo Culture {
get {
return resourceCulture;
}
set {
resourceCulture = value;
}
}
/// <summary>
/// 查找类似 Password: 的本地化字符串。
/// </summary>
public static string _ReleasePagePasswordLabel {
get {
return ResourceManager.GetString("_ReleasePagePasswordLabel", resourceCulture);
}
}
/// <summary>
/// 查找类似 EULA 的本地化字符串。
/// </summary>
public static string AgreementButtonContent {
get {
return ResourceManager.GetString("AgreementButtonContent", resourceCulture);
}
}
/// <summary>
/// 查找类似 Dev. Space Time 的本地化字符串。
/// </summary>
public static string DeveloperButtonContent {
get {
return ResourceManager.GetString("DeveloperButtonContent", resourceCulture);
}
}
/// <summary>
/// 查找类似 Docs 的本地化字符串。
/// </summary>
public static string DocumentationButtonContent {
get {
return ResourceManager.GetString("DocumentationButtonContent", resourceCulture);
}
}
/// <summary>
/// 查找类似 Email 的本地化字符串。
/// </summary>
public static string EmailButtonContent {
get {
return ResourceManager.GetString("EmailButtonContent", resourceCulture);
}
}
/// <summary>
/// 查找类似 PP 的本地化字符串。
/// </summary>
public static string PolicyButtonContent {
get {
return ResourceManager.GetString("PolicyButtonContent", resourceCulture);
}
}
/// <summary>
/// 查找类似 Repo 的本地化字符串。
/// </summary>
public static string RepositoryButtonContent {
get {
return ResourceManager.GetString("RepositoryButtonContent", resourceCulture);
}
}
/// <summary>
/// 查找类似 Ver. 的本地化字符串。
/// </summary>
public static string VersionButtonLabelContent {
get {
return ResourceManager.GetString("VersionButtonLabelContent", resourceCulture);
}
}
}
}

View File

@ -0,0 +1,144 @@
<?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>
<data name="AgreementButtonContent" xml:space="preserve">
<value>EULA</value>
</data>
<data name="DeveloperButtonContent" xml:space="preserve">
<value>Dev. Space Time</value>
</data>
<data name="DocumentationButtonContent" xml:space="preserve">
<value>Docs</value>
</data>
<data name="EmailButtonContent" xml:space="preserve">
<value>Email</value>
</data>
<data name="PolicyButtonContent" xml:space="preserve">
<value>PP</value>
</data>
<data name="RepositoryButtonContent" xml:space="preserve">
<value>Repo</value>
</data>
<data name="VersionButtonLabelContent" xml:space="preserve">
<value>Ver.</value>
</data>
<data name="_ReleasePagePasswordLabel" xml:space="preserve">
<value>Password:</value>
</data>
</root>

View File

@ -0,0 +1,124 @@
<?xml version="1.0" encoding="utf-8"?>
<root>
<!--
Microsoft ResX Schema
Version 1.3
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">1.3</resheader>
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
<data name="Name1">this is my long string</data>
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
[base64 mime encoded serialized .NET Framework object]
</data>
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
[base64 mime encoded string representing a byte array form of the .NET Framework object]
</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.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:element name="root" msdata:IsDataSet="true">
<xsd:complexType>
<xsd:choice maxOccurs="unbounded">
<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" msdata:Ordinal="1" />
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
</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>1.3</value>
</resheader>
<resheader name="reader">
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.3500.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.3500.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<data name="AgreementButtonContent" xml:space="preserve">
<value>使用协议</value>
</data>
<data name="DeveloperButtonContent" xml:space="preserve">
<value>开发者: Space Time</value>
</data>
<data name="DocumentationButtonContent" xml:space="preserve">
<value>使用文档</value>
</data>
<data name="EmailButtonContent" xml:space="preserve">
<value>联系邮箱</value>
</data>
<data name="PolicyButtonContent" xml:space="preserve">
<value>隐私政策</value>
</data>
<data name="RepositoryButtonContent" xml:space="preserve">
<value>开源地址</value>
</data>
<data name="VersionButtonLabelContent" xml:space="preserve">
<value>版本号:</value>
</data>
<data name="_ReleasePagePasswordLabel" xml:space="preserve">
<value>密码:</value>
</data>
</root>

55
Consts/MainConst.cs Normal file
View File

@ -0,0 +1,55 @@
using Microsoft.Win32;
using System;
using System.IO;
using System.Security.Principal;
using System.Text.RegularExpressions;
namespace Sheas_Cealer.Consts;
internal abstract partial class MainConst : MainMultilangConst
{
internal enum SettingsMode
{ BrowserPathMode, UpstreamUrlMode, ExtraArgsMode }
public static bool IsAdmin => new WindowsPrincipal(WindowsIdentity.GetCurrent()).IsInRole(WindowsBuiltInRole.Administrator);
internal static string EdgeBrowserRegistryPath => @"SOFTWARE\Microsoft\Windows\CurrentVersion\App Paths\msedge.exe";
internal static string ChromeBrowserRegistryPath => @"SOFTWARE\Microsoft\Windows\CurrentVersion\App Paths\chrome.exe";
internal static string BraveBrowserRegistryPath => @"SOFTWARE\Microsoft\Windows\CurrentVersion\App Paths\brave.exe";
internal static string DefaultUpstreamUrl => "https://gitlab.com/SpaceTimee/Cealing-Host/raw/main/Cealing-Host.json";
internal static string CealHostPath => Path.Combine(AppDomain.CurrentDomain.SetupInformation.ApplicationBase!, "Cealing-Host-*.json");
internal static string LocalHostPath => Path.Combine(AppDomain.CurrentDomain.SetupInformation.ApplicationBase!, "Cealing-Host-L.json");
internal static string UpstreamHostPath => Path.Combine(AppDomain.CurrentDomain.SetupInformation.ApplicationBase!, "Cealing-Host-U.json");
internal static string HostsConfPath => Path.Combine(Registry.LocalMachine.OpenSubKey(@"\SYSTEM\CurrentControlSet\Services\Tcpip\Parameters\DataBasePath")?.GetValue("DataBasePath", null)?.ToString() ?? @"C:\Windows\System32\drivers\etc", "hosts");
internal static string HostsConfStartMarker => $"# Cealing Nginx Start{Environment.NewLine}";
internal static string HostsConfEndMarker => "# Cealing Nginx End";
internal static string ConginxPath => Path.Combine(AppDomain.CurrentDomain.SetupInformation.ApplicationBase!, "Cealing-Conginx.exe");
internal static string NginxPath => Path.Combine(AppDomain.CurrentDomain.SetupInformation.ApplicationBase!, "Cealing-Nginx.exe");
internal static string NginxConfPath => Path.Combine(AppDomain.CurrentDomain.SetupInformation.ApplicationBase!, "nginx.conf");
internal static string NginxLogsPath => Path.Combine(AppDomain.CurrentDomain.SetupInformation.ApplicationBase!, "logs");
internal static string NginxErrorLogsPath => Path.Combine(NginxLogsPath, "error.log");
internal static string NginxTempPath => Path.Combine(AppDomain.CurrentDomain.SetupInformation.ApplicationBase!, "temp");
internal static string NginxCertPath => Path.Combine(AppDomain.CurrentDomain.SetupInformation.ApplicationBase!, "Cealing-Cert.pem");
internal static string NginxKeyPath => Path.Combine(AppDomain.CurrentDomain.SetupInformation.ApplicationBase!, "Cealing-Key.pem");
internal static string NginxRootCertSubjectName => "CN=Cealing Cert Root";
internal static string NginxChildCertSubjectName => "CN=Cealing Cert Child";
internal static string ComihomoPath => Path.Combine(AppDomain.CurrentDomain.SetupInformation.ApplicationBase!, "Cealing-Comihomo.exe");
internal static string MihomoPath => Path.Combine(AppDomain.CurrentDomain.SetupInformation.ApplicationBase!, "Cealing-Mihomo.exe");
internal static string MihomoConfPath => Path.Combine(AppDomain.CurrentDomain.SetupInformation.ApplicationBase!, "config.yaml");
internal static string[] MihomoNameServers => ["https://ns.net.kg/dns-query", "https://dnschina1.soraharu.com/dns-query", "https://0ms.dev/dns-query"];
internal static string NotifyIconText => "Sheas Cealer";
[GeneratedRegex("^Cealing-Host-")]
internal static partial Regex CealHostPrefixRegex();
[GeneratedRegex(@"^(https?:\/\/)?[a-zA-Z0-9](-*[a-zA-Z0-9])*(\.[a-zA-Z0-9](-*[a-zA-Z0-9])*)*(:\d{1,5})?(\/[a-zA-Z0-9.\-_\~\!\$\&\'\(\)\*\+\,\;\=\:\@\%]*)*$")]
internal static partial Regex UpstreamUrlRegex();
[GeneratedRegex(@"^(--[a-z](-?[a-z])*(=("".*"")|.*)?( --[a-z](-?[a-z])*(="".*"")?)*)?$")]
internal static partial Regex ExtraArgsRegex();
}

666
Consts/MainMultilangConst.Designer.cs generated Normal file
View File

@ -0,0 +1,666 @@
//------------------------------------------------------------------------------
// <auto-generated>
// 此代码由工具生成。
// 运行时版本:4.0.30319.42000
//
// 对此文件的更改可能会导致不正确的行为,并且如果
// 重新生成代码,这些更改将会丢失。
// </auto-generated>
//------------------------------------------------------------------------------
namespace Sheas_Cealer.Consts {
using System;
/// <summary>
/// 一个强类型的资源类,用于查找本地化的字符串等。
/// </summary>
// 此类是由 StronglyTypedResourceBuilder
// 类通过类似于 ResGen 或 Visual Studio 的工具自动生成的。
// 若要添加或移除成员,请编辑 .ResX 文件,然后重新运行 ResGen
// (以 /str 作为命令选项),或重新生成 VS 项目。
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "17.0.0.0")]
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
[global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
public class MainMultilangConst {
private static global::System.Resources.ResourceManager resourceMan;
private static global::System.Globalization.CultureInfo resourceCulture;
[global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
internal MainMultilangConst() {
}
/// <summary>
/// 返回此类使用的缓存的 ResourceManager 实例。
/// </summary>
[global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
public static global::System.Resources.ResourceManager ResourceManager {
get {
if (object.ReferenceEquals(resourceMan, null)) {
global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("Sheas_Cealer.Consts.MainMultilangConst", typeof(MainMultilangConst).Assembly);
resourceMan = temp;
}
return resourceMan;
}
}
/// <summary>
/// 重写当前线程的 CurrentUICulture 属性,对
/// 使用此强类型资源类的所有资源查找执行重写。
/// </summary>
[global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
public static global::System.Globalization.CultureInfo Culture {
get {
return resourceCulture;
}
set {
resourceCulture = value;
}
}
/// <summary>
/// 查找类似 Browser 的本地化字符串。
/// </summary>
public static string _BrowserPathDialogFilterFileType {
get {
return ResourceManager.GetString("_BrowserPathDialogFilterFileType", resourceCulture);
}
}
/// <summary>
/// 查找类似 Some cealing hosts contain syntax errors and cannot be recognized. Do you want to continue anyway? 的本地化字符串。
/// </summary>
public static string _CealHostErrorPrompt {
get {
return ResourceManager.GetString("_CealHostErrorPrompt", resourceCulture);
}
}
/// <summary>
/// 查找类似 I know you would click me, but nothing will actually happen. Whee~ 的本地化字符串。
/// </summary>
public static string _GameClickOnceMsg {
get {
return ResourceManager.GetString("_GameClickOnceMsg", resourceCulture);
}
}
/// <summary>
/// 查找类似 Ugh, what are you doing. Please stop, I don&apos;t want to hurt anyone. Stop please, this is your last chance. Ugh, I can&apos;t control it anymore 的本地化字符串。
/// </summary>
public static string _GameClickThreeMsg {
get {
return ResourceManager.GetString("_GameClickThreeMsg", resourceCulture);
}
}
/// <summary>
/// 查找类似 No no no, don&apos;t click me. Sorry, I shouldn&apos;t have lied to you, I am a cursed button, and continuing to click me will bring disaster to the entire Sheas Cealer. Please believe me. This is not a game, and there are no new features here. Listen to me and use the normal functions. Please 的本地化字符串。
/// </summary>
public static string _GameClickTwiceMsg {
get {
return ResourceManager.GetString("_GameClickTwiceMsg", resourceCulture);
}
}
/// <summary>
/// 查找类似 You defeated the evil button and saved Sheas Cealer. You are the HERO! 的本地化字符串。
/// </summary>
public static string _GameEndingMsg {
get {
return ResourceManager.GetString("_GameEndingMsg", resourceCulture);
}
}
/// <summary>
/// 查找类似 Button Remaining HP. 的本地化字符串。
/// </summary>
public static string _GameGradeMsg {
get {
return ResourceManager.GetString("_GameGradeMsg", resourceCulture);
}
}
/// <summary>
/// 查找类似 It&apos;s dead. You&apos;re the HERO of Sheas Cealer 的本地化字符串。
/// </summary>
public static string _GameReviewEndingMsg {
get {
return ResourceManager.GetString("_GameReviewEndingMsg", resourceCulture);
}
}
/// <summary>
/// 查找类似 No, please kill me. I... can&apos;t control it... 的本地化字符串。
/// </summary>
public static string _GameStartMsg {
get {
return ResourceManager.GetString("_GameStartMsg", resourceCulture);
}
}
/// <summary>
/// 查找类似 All processes of the selected browser will be closed before launching. Do you want to continue? 的本地化字符串。
/// </summary>
public static string _KillBrowserProcessPrompt {
get {
return ResourceManager.GetString("_KillBrowserProcessPrompt", resourceCulture);
}
}
/// <summary>
/// 查找类似 You are using hosts-based non-wildcard domain global cealing. Do you want to continue? 的本地化字符串。
/// </summary>
public static string _LaunchHostsNginxPrompt {
get {
return ResourceManager.GetString("_LaunchHostsNginxPrompt", resourceCulture);
}
}
/// <summary>
/// 查找类似 Mihomo failed to launch 的本地化字符串。
/// </summary>
public static string _LaunchMihomoErrorMsg {
get {
return ResourceManager.GetString("_LaunchMihomoErrorMsg", resourceCulture);
}
}
/// <summary>
/// 查找类似 Nginx failed to launch. Do you want to open the error log? 的本地化字符串。
/// </summary>
public static string _LaunchNginxErrorPrompt {
get {
return ResourceManager.GetString("_LaunchNginxErrorPrompt", resourceCulture);
}
}
/// <summary>
/// 查找类似 Warning: The proxy core is under attack and failes to conceal SNI. The SNI removal mode has been turned on urgently. Do you want to continue? 的本地化字符串。
/// </summary>
public static string _LaunchNginxFlashingPrompt {
get {
return ResourceManager.GetString("_LaunchNginxFlashingPrompt", resourceCulture);
}
}
/// <summary>
/// 查找类似 Please remember to come back and stop the proxy manually after use. Do you want to continue? 的本地化字符串。
/// </summary>
public static string _LaunchProxyPrompt {
get {
return ResourceManager.GetString("_LaunchProxyPrompt", resourceCulture);
}
}
/// <summary>
/// 查找类似 The mihomo conf contains syntax errors and cannot be recognized 的本地化字符串。
/// </summary>
public static string _MihomoConfErrorMsg {
get {
return ResourceManager.GetString("_MihomoConfErrorMsg", resourceCulture);
}
}
/// <summary>
/// 查找类似 The local port 80 is occupied. Do you want to use port {0} to continue? This may cause the http connection to fail to automatically jump to https 的本地化字符串。
/// </summary>
public static string _NginxHttpPortOccupiedPrompt {
get {
return ResourceManager.GetString("_NginxHttpPortOccupiedPrompt", resourceCulture);
}
}
/// <summary>
/// 查找类似 The local port 443 is occupied. Do you want to use port {0} to continue? This may cause the global cealing to not work properly 的本地化字符串。
/// </summary>
public static string _NginxHttpsPortOccupiedPrompt {
get {
return ResourceManager.GetString("_NginxHttpsPortOccupiedPrompt", resourceCulture);
}
}
/// <summary>
/// 查找类似 There is an update available. Do you want to update upstream host? If No it will only open the upstream host web page for you 的本地化字符串。
/// </summary>
public static string _OverrideUpstreamHostPrompt {
get {
return ResourceManager.GetString("_OverrideUpstreamHostPrompt", resourceCulture);
}
}
/// <summary>
/// 查找类似 Update successfully 的本地化字符串。
/// </summary>
public static string _UpdateUpstreamHostSuccessMsg {
get {
return ResourceManager.GetString("_UpdateUpstreamHostSuccessMsg", resourceCulture);
}
}
/// <summary>
/// 查找类似 Upstream host is already up to date 的本地化字符串。
/// </summary>
public static string _UpstreamHostUtdMsg {
get {
return ResourceManager.GetString("_UpstreamHostUtdMsg", resourceCulture);
}
}
/// <summary>
/// 查找类似 About Me 的本地化字符串。
/// </summary>
public static string AboutButtonContent {
get {
return ResourceManager.GetString("AboutButtonContent", resourceCulture);
}
}
/// <summary>
/// 查找类似 Click to open the about window 的本地化字符串。
/// </summary>
public static string AboutButtonToolTip {
get {
return ResourceManager.GetString("AboutButtonToolTip", resourceCulture);
}
}
/// <summary>
/// 查找类似 Start Cealing 的本地化字符串。
/// </summary>
public static string BrowserButtonContent {
get {
return ResourceManager.GetString("BrowserButtonContent", resourceCulture);
}
}
/// <summary>
/// 查找类似 Click to launch the injected browser 的本地化字符串。
/// </summary>
public static string BrowserButtonToolTip {
get {
return ResourceManager.GetString("BrowserButtonToolTip", resourceCulture);
}
}
/// <summary>
/// 查找类似 GLB. Purging CHA. 的本地化字符串。
/// </summary>
public static string ComihomoButtonIsInitingContent {
get {
return ResourceManager.GetString("ComihomoButtonIsInitingContent", resourceCulture);
}
}
/// <summary>
/// 查找类似 GLB. Cealing INIT. 的本地化字符串。
/// </summary>
public static string ConginxButtonIsInitingContent {
get {
return ResourceManager.GetString("ConginxButtonIsInitingContent", resourceCulture);
}
}
/// <summary>
/// 查找类似 Edit Hosts Conf 的本地化字符串。
/// </summary>
public static string EditHostsConfButtonContent {
get {
return ResourceManager.GetString("EditHostsConfButtonContent", resourceCulture);
}
}
/// <summary>
/// 查找类似 Click to edit hosts conf 的本地化字符串。
/// </summary>
public static string EditHostsConfButtonToolTip {
get {
return ResourceManager.GetString("EditHostsConfButtonToolTip", resourceCulture);
}
}
/// <summary>
/// 查找类似 Edit Local Host 的本地化字符串。
/// </summary>
public static string EditLocalHostButtonContent {
get {
return ResourceManager.GetString("EditLocalHostButtonContent", resourceCulture);
}
}
/// <summary>
/// 查找类似 Click to edit local host 的本地化字符串。
/// </summary>
public static string EditLocalHostButtonToolTip {
get {
return ResourceManager.GetString("EditLocalHostButtonToolTip", resourceCulture);
}
}
/// <summary>
/// 查找类似 Edit Mihomo Conf 的本地化字符串。
/// </summary>
public static string EditMihomoConfButtonContent {
get {
return ResourceManager.GetString("EditMihomoConfButtonContent", resourceCulture);
}
}
/// <summary>
/// 查找类似 Click to edit mihomo conf 的本地化字符串。
/// </summary>
public static string EditMihomoConfButtonToolTip {
get {
return ResourceManager.GetString("EditMihomoConfButtonToolTip", resourceCulture);
}
}
/// <summary>
/// 查找类似 Edit Nginx Conf 的本地化字符串。
/// </summary>
public static string EditNginxConfButtonContent {
get {
return ResourceManager.GetString("EditNginxConfButtonContent", resourceCulture);
}
}
/// <summary>
/// 查找类似 Click to edit nginx conf 的本地化字符串。
/// </summary>
public static string EditNginxConfButtonToolTip {
get {
return ResourceManager.GetString("EditNginxConfButtonToolTip", resourceCulture);
}
}
/// <summary>
/// 查找类似 Edit UPSTR. Host 的本地化字符串。
/// </summary>
public static string EditUpstreamHostButtonContent {
get {
return ResourceManager.GetString("EditUpstreamHostButtonContent", resourceCulture);
}
}
/// <summary>
/// 查找类似 Click to edit upstream host 的本地化字符串。
/// </summary>
public static string EditUpstreamHostButtonToolTip {
get {
return ResourceManager.GetString("EditUpstreamHostButtonToolTip", resourceCulture);
}
}
/// <summary>
/// 查找类似 GLB. Purging INIT. 的本地化字符串。
/// </summary>
public static string MihomoButtonIsInitingContent {
get {
return ResourceManager.GetString("MihomoButtonIsInitingContent", resourceCulture);
}
}
/// <summary>
/// 查找类似 Stop GLB. Purging 的本地化字符串。
/// </summary>
public static string MihomoButtonIsRunningContent {
get {
return ResourceManager.GetString("MihomoButtonIsRunningContent", resourceCulture);
}
}
/// <summary>
/// 查找类似 Click to stop the local Mihomo 的本地化字符串。
/// </summary>
public static string MihomoButtonIsRunningToolTip {
get {
return ResourceManager.GetString("MihomoButtonIsRunningToolTip", resourceCulture);
}
}
/// <summary>
/// 查找类似 Start GLB. Purging 的本地化字符串。
/// </summary>
public static string MihomoButtonIsStoppedContent {
get {
return ResourceManager.GetString("MihomoButtonIsStoppedContent", resourceCulture);
}
}
/// <summary>
/// 查找类似 Click to launch a local Mihomo 的本地化字符串。
/// </summary>
public static string MihomoButtonIsStoppedToolTip {
get {
return ResourceManager.GetString("MihomoButtonIsStoppedToolTip", resourceCulture);
}
}
/// <summary>
/// 查找类似 GLB. Purging STP. 的本地化字符串。
/// </summary>
public static string MihomoButtonIsStoppingContent {
get {
return ResourceManager.GetString("MihomoButtonIsStoppingContent", resourceCulture);
}
}
/// <summary>
/// 查找类似 GLB. Cealing INIT. 的本地化字符串。
/// </summary>
public static string NginxButtonIsInitingContent {
get {
return ResourceManager.GetString("NginxButtonIsInitingContent", resourceCulture);
}
}
/// <summary>
/// 查找类似 Stop GLB. Cealing 的本地化字符串。
/// </summary>
public static string NginxButtonIsRunningContent {
get {
return ResourceManager.GetString("NginxButtonIsRunningContent", resourceCulture);
}
}
/// <summary>
/// 查找类似 Click to stop the local Nginx 的本地化字符串。
/// </summary>
public static string NginxButtonIsRunningToolTip {
get {
return ResourceManager.GetString("NginxButtonIsRunningToolTip", resourceCulture);
}
}
/// <summary>
/// 查找类似 Start GLB. Cealing 的本地化字符串。
/// </summary>
public static string NginxButtonIsStoppedContent {
get {
return ResourceManager.GetString("NginxButtonIsStoppedContent", resourceCulture);
}
}
/// <summary>
/// 查找类似 Click to launch a local Nginx 的本地化字符串。
/// </summary>
public static string NginxButtonIsStoppedToolTip {
get {
return ResourceManager.GetString("NginxButtonIsStoppedToolTip", resourceCulture);
}
}
/// <summary>
/// 查找类似 Click Now 的本地化字符串。
/// </summary>
public static string NoClickButtonIsFlashingContent {
get {
return ResourceManager.GetString("NoClickButtonIsFlashingContent", resourceCulture);
}
}
/// <summary>
/// 查找类似 Click this button now 的本地化字符串。
/// </summary>
public static string NoClickButtonIsFlashingToolTip {
get {
return ResourceManager.GetString("NoClickButtonIsFlashingToolTip", resourceCulture);
}
}
/// <summary>
/// 查找类似 No Clicking 的本地化字符串。
/// </summary>
public static string NoClickButtonIsStoppedContent {
get {
return ResourceManager.GetString("NoClickButtonIsStoppedContent", resourceCulture);
}
}
/// <summary>
/// 查找类似 Do not click this button 的本地化字符串。
/// </summary>
public static string NoClickButtonIsStoppedToolTip {
get {
return ResourceManager.GetString("NoClickButtonIsStoppedToolTip", resourceCulture);
}
}
/// <summary>
/// 查找类似 Fill in a Chromium-based browser path 的本地化字符串。
/// </summary>
public static string SettingsBoxBrowserPathToolTip {
get {
return ResourceManager.GetString("SettingsBoxBrowserPathToolTip", resourceCulture);
}
}
/// <summary>
/// 查找类似 Fill in extra Chromium startup args 的本地化字符串。
/// </summary>
public static string SettingsBoxExtraArgsToolTip {
get {
return ResourceManager.GetString("SettingsBoxExtraArgsToolTip", resourceCulture);
}
}
/// <summary>
/// 查找类似 Fill in an upstream host URL 的本地化字符串。
/// </summary>
public static string SettingsBoxUpstreamUrlToolTip {
get {
return ResourceManager.GetString("SettingsBoxUpstreamUrlToolTip", resourceCulture);
}
}
/// <summary>
/// 查找类似 Appearance Settings 的本地化字符串。
/// </summary>
public static string SettingsButtonContent {
get {
return ResourceManager.GetString("SettingsButtonContent", resourceCulture);
}
}
/// <summary>
/// 查找类似 Click to open the settings window 的本地化字符串。
/// </summary>
public static string SettingsButtonToolTip {
get {
return ResourceManager.GetString("SettingsButtonToolTip", resourceCulture);
}
}
/// <summary>
/// 查找类似 Browse Path 的本地化字符串。
/// </summary>
public static string SettingsFunctionButtonBrowserPathContent {
get {
return ResourceManager.GetString("SettingsFunctionButtonBrowserPathContent", resourceCulture);
}
}
/// <summary>
/// 查找类似 Clear Args 的本地化字符串。
/// </summary>
public static string SettingsFunctionButtonExtraArgsContent {
get {
return ResourceManager.GetString("SettingsFunctionButtonExtraArgsContent", resourceCulture);
}
}
/// <summary>
/// 查找类似 Click to process settings 的本地化字符串。
/// </summary>
public static string SettingsFunctionButtonToolTip {
get {
return ResourceManager.GetString("SettingsFunctionButtonToolTip", resourceCulture);
}
}
/// <summary>
/// 查找类似 Reset URL 的本地化字符串。
/// </summary>
public static string SettingsFunctionButtonUpstreamUrlContent {
get {
return ResourceManager.GetString("SettingsFunctionButtonUpstreamUrlContent", resourceCulture);
}
}
/// <summary>
/// 查找类似 Browser Path 的本地化字符串。
/// </summary>
public static string SettingsModeButtonBrowserPathContent {
get {
return ResourceManager.GetString("SettingsModeButtonBrowserPathContent", resourceCulture);
}
}
/// <summary>
/// 查找类似 Extra Args 的本地化字符串。
/// </summary>
public static string SettingsModeButtonExtraArgsContent {
get {
return ResourceManager.GetString("SettingsModeButtonExtraArgsContent", resourceCulture);
}
}
/// <summary>
/// 查找类似 Click to switch settings 的本地化字符串。
/// </summary>
public static string SettingsModeButtonToolTip {
get {
return ResourceManager.GetString("SettingsModeButtonToolTip", resourceCulture);
}
}
/// <summary>
/// 查找类似 Upstream URL 的本地化字符串。
/// </summary>
public static string SettingsModeButtonUpstreamUrlContent {
get {
return ResourceManager.GetString("SettingsModeButtonUpstreamUrlContent", resourceCulture);
}
}
/// <summary>
/// 查找类似 Update Upstream Host 的本地化字符串。
/// </summary>
public static string UpdateUpstreamHostButtonContent {
get {
return ResourceManager.GetString("UpdateUpstreamHostButtonContent", resourceCulture);
}
}
/// <summary>
/// 查找类似 Click to update upstream host 的本地化字符串。
/// </summary>
public static string UpdateUpstreamHostButtonToolTip {
get {
return ResourceManager.GetString("UpdateUpstreamHostButtonToolTip", resourceCulture);
}
}
}
}

View File

@ -0,0 +1,321 @@
<?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>
<data name="AboutButtonContent" xml:space="preserve">
<value>About Me</value>
</data>
<data name="AboutButtonToolTip" xml:space="preserve">
<value>Click to open the about window</value>
</data>
<data name="BrowserButtonContent" xml:space="preserve">
<value>Start Cealing</value>
</data>
<data name="BrowserButtonToolTip" xml:space="preserve">
<value>Click to launch the injected browser</value>
</data>
<data name="ComihomoButtonIsInitingContent" xml:space="preserve">
<value>GLB. Purging CHA.</value>
</data>
<data name="ConginxButtonIsInitingContent" xml:space="preserve">
<value>GLB. Cealing INIT.</value>
</data>
<data name="EditHostsConfButtonContent" xml:space="preserve">
<value>Edit Hosts Conf</value>
</data>
<data name="EditHostsConfButtonToolTip" xml:space="preserve">
<value>Click to edit hosts conf</value>
</data>
<data name="EditLocalHostButtonContent" xml:space="preserve">
<value>Edit Local Host</value>
</data>
<data name="EditLocalHostButtonToolTip" xml:space="preserve">
<value>Click to edit local host</value>
</data>
<data name="EditMihomoConfButtonContent" xml:space="preserve">
<value>Edit Mihomo Conf</value>
</data>
<data name="EditMihomoConfButtonToolTip" xml:space="preserve">
<value>Click to edit mihomo conf</value>
</data>
<data name="EditNginxConfButtonContent" xml:space="preserve">
<value>Edit Nginx Conf</value>
</data>
<data name="EditNginxConfButtonToolTip" xml:space="preserve">
<value>Click to edit nginx conf</value>
</data>
<data name="EditUpstreamHostButtonContent" xml:space="preserve">
<value>Edit UPSTR. Host</value>
</data>
<data name="EditUpstreamHostButtonToolTip" xml:space="preserve">
<value>Click to edit upstream host</value>
</data>
<data name="MihomoButtonIsInitingContent" xml:space="preserve">
<value>GLB. Purging INIT.</value>
</data>
<data name="MihomoButtonIsRunningContent" xml:space="preserve">
<value>Stop GLB. Purging</value>
</data>
<data name="MihomoButtonIsRunningToolTip" xml:space="preserve">
<value>Click to stop the local Mihomo</value>
</data>
<data name="MihomoButtonIsStoppedContent" xml:space="preserve">
<value>Start GLB. Purging</value>
</data>
<data name="MihomoButtonIsStoppedToolTip" xml:space="preserve">
<value>Click to launch a local Mihomo</value>
</data>
<data name="MihomoButtonIsStoppingContent" xml:space="preserve">
<value>GLB. Purging STP.</value>
</data>
<data name="NginxButtonIsInitingContent" xml:space="preserve">
<value>GLB. Cealing INIT.</value>
</data>
<data name="NginxButtonIsRunningContent" xml:space="preserve">
<value>Stop GLB. Cealing</value>
</data>
<data name="NginxButtonIsRunningToolTip" xml:space="preserve">
<value>Click to stop the local Nginx</value>
</data>
<data name="NginxButtonIsStoppedContent" xml:space="preserve">
<value>Start GLB. Cealing</value>
</data>
<data name="NginxButtonIsStoppedToolTip" xml:space="preserve">
<value>Click to launch a local Nginx</value>
</data>
<data name="NoClickButtonIsFlashingContent" xml:space="preserve">
<value>Click Now</value>
</data>
<data name="NoClickButtonIsFlashingToolTip" xml:space="preserve">
<value>Click this button now</value>
</data>
<data name="NoClickButtonIsStoppedContent" xml:space="preserve">
<value>No Clicking</value>
</data>
<data name="NoClickButtonIsStoppedToolTip" xml:space="preserve">
<value>Do not click this button</value>
</data>
<data name="SettingsBoxBrowserPathToolTip" xml:space="preserve">
<value>Fill in a Chromium-based browser path</value>
</data>
<data name="SettingsBoxExtraArgsToolTip" xml:space="preserve">
<value>Fill in extra Chromium startup args</value>
</data>
<data name="SettingsBoxUpstreamUrlToolTip" xml:space="preserve">
<value>Fill in an upstream host URL</value>
</data>
<data name="SettingsButtonContent" xml:space="preserve">
<value>Appearance Settings</value>
</data>
<data name="SettingsButtonToolTip" xml:space="preserve">
<value>Click to open the settings window</value>
</data>
<data name="SettingsFunctionButtonBrowserPathContent" xml:space="preserve">
<value>Browse Path</value>
</data>
<data name="SettingsFunctionButtonExtraArgsContent" xml:space="preserve">
<value>Clear Args</value>
</data>
<data name="SettingsFunctionButtonToolTip" xml:space="preserve">
<value>Click to process settings</value>
</data>
<data name="SettingsFunctionButtonUpstreamUrlContent" xml:space="preserve">
<value>Reset URL</value>
</data>
<data name="SettingsModeButtonBrowserPathContent" xml:space="preserve">
<value>Browser Path</value>
</data>
<data name="SettingsModeButtonExtraArgsContent" xml:space="preserve">
<value>Extra Args</value>
</data>
<data name="SettingsModeButtonToolTip" xml:space="preserve">
<value>Click to switch settings</value>
</data>
<data name="SettingsModeButtonUpstreamUrlContent" xml:space="preserve">
<value>Upstream URL</value>
</data>
<data name="UpdateUpstreamHostButtonContent" xml:space="preserve">
<value>Update Upstream Host</value>
</data>
<data name="UpdateUpstreamHostButtonToolTip" xml:space="preserve">
<value>Click to update upstream host</value>
</data>
<data name="_BrowserPathDialogFilterFileType" xml:space="preserve">
<value>Browser</value>
</data>
<data name="_CealHostErrorPrompt" xml:space="preserve">
<value>Some cealing hosts contain syntax errors and cannot be recognized. Do you want to continue anyway?</value>
</data>
<data name="_GameClickOnceMsg" xml:space="preserve">
<value>I know you would click me, but nothing will actually happen. Whee~</value>
</data>
<data name="_GameClickThreeMsg" xml:space="preserve">
<value>Ugh, what are you doing. Please stop, I don't want to hurt anyone. Stop please, this is your last chance. Ugh, I can't control it anymore</value>
</data>
<data name="_GameClickTwiceMsg" xml:space="preserve">
<value>No no no, don't click me. Sorry, I shouldn't have lied to you, I am a cursed button, and continuing to click me will bring disaster to the entire Sheas Cealer. Please believe me. This is not a game, and there are no new features here. Listen to me and use the normal functions. Please</value>
</data>
<data name="_GameEndingMsg" xml:space="preserve">
<value>You defeated the evil button and saved Sheas Cealer. You are the HERO!</value>
</data>
<data name="_GameGradeMsg" xml:space="preserve">
<value>Button Remaining HP.</value>
</data>
<data name="_GameReviewEndingMsg" xml:space="preserve">
<value>It's dead. You're the HERO of Sheas Cealer</value>
</data>
<data name="_GameStartMsg" xml:space="preserve">
<value>No, please kill me. I... can't control it...</value>
</data>
<data name="_KillBrowserProcessPrompt" xml:space="preserve">
<value>All processes of the selected browser will be closed before launching. Do you want to continue?</value>
</data>
<data name="_LaunchHostsNginxPrompt" xml:space="preserve">
<value>You are using hosts-based non-wildcard domain global cealing. Do you want to continue?</value>
</data>
<data name="_LaunchMihomoErrorMsg" xml:space="preserve">
<value>Mihomo failed to launch</value>
</data>
<data name="_LaunchNginxErrorPrompt" xml:space="preserve">
<value>Nginx failed to launch. Do you want to open the error log?</value>
</data>
<data name="_LaunchNginxFlashingPrompt" xml:space="preserve">
<value>Warning: The proxy core is under attack and failes to conceal SNI. The SNI removal mode has been turned on urgently. Do you want to continue?</value>
</data>
<data name="_LaunchProxyPrompt" xml:space="preserve">
<value>Please remember to come back and stop the proxy manually after use. Do you want to continue?</value>
</data>
<data name="_MihomoConfErrorMsg" xml:space="preserve">
<value>The mihomo conf contains syntax errors and cannot be recognized</value>
</data>
<data name="_NginxHttpPortOccupiedPrompt" xml:space="preserve">
<value>The local port 80 is occupied. Do you want to use port {0} to continue? This may cause the http connection to fail to automatically jump to https</value>
</data>
<data name="_NginxHttpsPortOccupiedPrompt" xml:space="preserve">
<value>The local port 443 is occupied. Do you want to use port {0} to continue? This may cause the global cealing to not work properly</value>
</data>
<data name="_OverrideUpstreamHostPrompt" xml:space="preserve">
<value>There is an update available. Do you want to update upstream host? If No it will only open the upstream host web page for you</value>
</data>
<data name="_UpdateUpstreamHostSuccessMsg" xml:space="preserve">
<value>Update successfully</value>
</data>
<data name="_UpstreamHostUtdMsg" xml:space="preserve">
<value>Upstream host is already up to date</value>
</data>
</root>

View File

@ -0,0 +1,321 @@
<?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>
<data name="AboutButtonContent" xml:space="preserve">
<value>关于项目</value>
</data>
<data name="AboutButtonToolTip" xml:space="preserve">
<value>点击打开关于窗口</value>
</data>
<data name="BrowserButtonContent" xml:space="preserve">
<value>启动伪造</value>
</data>
<data name="BrowserButtonToolTip" xml:space="preserve">
<value>点击启动参数注入完成的浏览器</value>
</data>
<data name="ComihomoButtonIsInitingContent" xml:space="preserve">
<value>全局净化调整中</value>
</data>
<data name="ConginxButtonIsInitingContent" xml:space="preserve">
<value>全局伪造启动中</value>
</data>
<data name="EditHostsConfButtonContent" xml:space="preserve">
<value>编辑 Hosts 配置</value>
</data>
<data name="EditHostsConfButtonToolTip" xml:space="preserve">
<value>点击编辑 Hosts 配置</value>
</data>
<data name="EditLocalHostButtonContent" xml:space="preserve">
<value>编辑本地规则</value>
</data>
<data name="EditLocalHostButtonToolTip" xml:space="preserve">
<value>点击编辑本地规则</value>
</data>
<data name="EditMihomoConfButtonContent" xml:space="preserve">
<value>编辑 Mihomo 配置</value>
</data>
<data name="EditMihomoConfButtonToolTip" xml:space="preserve">
<value>点击编辑 Mihomo 配置</value>
</data>
<data name="EditNginxConfButtonContent" xml:space="preserve">
<value>编辑 Nginx 配置</value>
</data>
<data name="EditNginxConfButtonToolTip" xml:space="preserve">
<value>点击编辑 Nginx 配置</value>
</data>
<data name="EditUpstreamHostButtonContent" xml:space="preserve">
<value>编辑上游规则</value>
</data>
<data name="EditUpstreamHostButtonToolTip" xml:space="preserve">
<value>点击编辑上游规则</value>
</data>
<data name="MihomoButtonIsInitingContent" xml:space="preserve">
<value>全局净化启动中</value>
</data>
<data name="MihomoButtonIsRunningContent" xml:space="preserve">
<value>停止全局净化</value>
</data>
<data name="MihomoButtonIsRunningToolTip" xml:space="preserve">
<value>点击停止本地 Mihomo</value>
</data>
<data name="MihomoButtonIsStoppedContent" xml:space="preserve">
<value>启动全局净化</value>
</data>
<data name="MihomoButtonIsStoppedToolTip" xml:space="preserve">
<value>点击启动本地 Mihomo</value>
</data>
<data name="MihomoButtonIsStoppingContent" xml:space="preserve">
<value>全局净化停止中</value>
</data>
<data name="NginxButtonIsInitingContent" xml:space="preserve">
<value>全局伪造启动中</value>
</data>
<data name="NginxButtonIsRunningContent" xml:space="preserve">
<value>停止全局伪造</value>
</data>
<data name="NginxButtonIsRunningToolTip" xml:space="preserve">
<value>点击停止 Nginx</value>
</data>
<data name="NginxButtonIsStoppedContent" xml:space="preserve">
<value>启动全局伪造</value>
</data>
<data name="NginxButtonIsStoppedToolTip" xml:space="preserve">
<value>点击启动本地 Nginx</value>
</data>
<data name="NoClickButtonIsFlashingContent" xml:space="preserve">
<value>赶紧点我</value>
</data>
<data name="NoClickButtonIsFlashingToolTip" xml:space="preserve">
<value>赶紧点击这个按钮</value>
</data>
<data name="NoClickButtonIsStoppedContent" xml:space="preserve">
<value>不要点我</value>
</data>
<data name="NoClickButtonIsStoppedToolTip" xml:space="preserve">
<value>不要点击这个按钮</value>
</data>
<data name="SettingsBoxBrowserPathToolTip" xml:space="preserve">
<value>填入任意以 Chromium 为内核的浏览器路径</value>
</data>
<data name="SettingsBoxExtraArgsToolTip" xml:space="preserve">
<value>填入任意额外的 Chromium 启动参数</value>
</data>
<data name="SettingsBoxUpstreamUrlToolTip" xml:space="preserve">
<value>填入任意上游规则链接</value>
</data>
<data name="SettingsButtonContent" xml:space="preserve">
<value>界面设置</value>
</data>
<data name="SettingsButtonToolTip" xml:space="preserve">
<value>点击打开设置窗口</value>
</data>
<data name="SettingsFunctionButtonBrowserPathContent" xml:space="preserve">
<value>浏览路径</value>
</data>
<data name="SettingsFunctionButtonExtraArgsContent" xml:space="preserve">
<value>清除参数</value>
</data>
<data name="SettingsFunctionButtonToolTip" xml:space="preserve">
<value>点击处理设置内容</value>
</data>
<data name="SettingsFunctionButtonUpstreamUrlContent" xml:space="preserve">
<value>重置链接</value>
</data>
<data name="SettingsModeButtonBrowserPathContent" xml:space="preserve">
<value>文件路径</value>
</data>
<data name="SettingsModeButtonExtraArgsContent" xml:space="preserve">
<value>额外参数</value>
</data>
<data name="SettingsModeButtonToolTip" xml:space="preserve">
<value>点击切换设置模式</value>
</data>
<data name="SettingsModeButtonUpstreamUrlContent" xml:space="preserve">
<value>上游链接</value>
</data>
<data name="UpdateUpstreamHostButtonContent" xml:space="preserve">
<value>更新上游规则</value>
</data>
<data name="UpdateUpstreamHostButtonToolTip" xml:space="preserve">
<value>点击更新上游规则</value>
</data>
<data name="_BrowserPathDialogFilterFileType" xml:space="preserve">
<value>浏览器</value>
</data>
<data name="_CealHostErrorPrompt" xml:space="preserve">
<value>伪造规则含有语法错误,部分规则无法识别,是否仍然继续?</value>
</data>
<data name="_GameClickOnceMsg" xml:space="preserve">
<value>就知道你会点,但其实什么事情都不会发生的。嘻嘻~</value>
</data>
<data name="_GameClickThreeMsg" xml:space="preserve">
<value>呜,你在做什么。求求你不要再继续点了,我不想伤害大家。快停下,这是最后一次机会。呃,我快要控制不住了</value>
</data>
<data name="_GameClickTwiceMsg" xml:space="preserve">
<value>不不不,不要点我。对不起,我不该骗你的,我是一个受诅咒的按钮,继续点我会给整个 Sheas Cealer 带来灾难的。请相信我,这不是游戏,这里也没有新功能。听我的,去用正常的功能好吗,求求你了</value>
</data>
<data name="_GameEndingMsg" xml:space="preserve">
<value>你击败了邪恶的按钮,拯救了 Sheas Cealer你是英雄!</value>
</data>
<data name="_GameGradeMsg" xml:space="preserve">
<value>按钮剩余血量:</value>
</data>
<data name="_GameReviewEndingMsg" xml:space="preserve">
<value>它死了,你是 Sheas Cealer 的英雄</value>
</data>
<data name="_GameStartMsg" xml:space="preserve">
<value>不,求你杀了我,我... 控制不住了...</value>
</data>
<data name="_KillBrowserProcessPrompt" xml:space="preserve">
<value>启动前将关闭所选浏览器的所有进程,是否继续?</value>
</data>
<data name="_LaunchHostsNginxPrompt" xml:space="preserve">
<value>正在使用基于 Hosts 的非泛域名全局伪造,是否继续?</value>
</data>
<data name="_LaunchMihomoErrorMsg" xml:space="preserve">
<value>Mihomo 启动失败</value>
</data>
<data name="_LaunchNginxErrorPrompt" xml:space="preserve">
<value>Nginx 启动失败,是否打开错误日志?</value>
</data>
<data name="_LaunchNginxFlashingPrompt" xml:space="preserve">
<value>Warning: 代理核心正在遭受攻击,无法伪造 SNI已紧急开启 SNI 拔除模式,是否继续?</value>
</data>
<data name="_LaunchProxyPrompt" xml:space="preserve">
<value>使用完请务必记得回来手动关闭代理,是否继续?</value>
</data>
<data name="_MihomoConfErrorMsg" xml:space="preserve">
<value>Mihomo 配置文件含有语法错误,部分配置无法识别</value>
</data>
<data name="_NginxHttpPortOccupiedPrompt" xml:space="preserve">
<value>本地 80 端口被占用,是否换用 {0} 端口继续? 这可能导致 http 连接无法自动跳转到 https</value>
</data>
<data name="_NginxHttpsPortOccupiedPrompt" xml:space="preserve">
<value>本地 443 端口被占用,是否换用 {0} 端口继续? 这可能导致全局伪造无法正常工作</value>
</data>
<data name="_OverrideUpstreamHostPrompt" xml:space="preserve">
<value>上游规则有更新可用,需要更新吗?否则只为你打开上游规则网页</value>
</data>
<data name="_UpdateUpstreamHostSuccessMsg" xml:space="preserve">
<value>更新已完成</value>
</data>
<data name="_UpstreamHostUtdMsg" xml:space="preserve">
<value>上游规则已经更到最新了</value>
</data>
</root>

3
Consts/SettingsConst.cs Normal file
View File

@ -0,0 +1,3 @@
namespace Sheas_Cealer.Consts;
internal abstract class SettingsConst : SettingsMultilangConst;

198
Consts/SettingsMultilangConst.Designer.cs generated Normal file
View File

@ -0,0 +1,198 @@
//------------------------------------------------------------------------------
// <auto-generated>
// 此代码由工具生成。
// 运行时版本:4.0.30319.42000
//
// 对此文件的更改可能会导致不正确的行为,并且如果
// 重新生成代码,这些更改将会丢失。
// </auto-generated>
//------------------------------------------------------------------------------
namespace Sheas_Cealer.Consts {
using System;
/// <summary>
/// 一个强类型的资源类,用于查找本地化的字符串等。
/// </summary>
// 此类是由 StronglyTypedResourceBuilder
// 类通过类似于 ResGen 或 Visual Studio 的工具自动生成的。
// 若要添加或移除成员,请编辑 .ResX 文件,然后重新运行 ResGen
// (以 /str 作为命令选项),或重新生成 VS 项目。
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "17.0.0.0")]
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
[global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
public class SettingsMultilangConst {
private static global::System.Resources.ResourceManager resourceMan;
private static global::System.Globalization.CultureInfo resourceCulture;
[global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
internal SettingsMultilangConst() {
}
/// <summary>
/// 返回此类使用的缓存的 ResourceManager 实例。
/// </summary>
[global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
public static global::System.Resources.ResourceManager ResourceManager {
get {
if (object.ReferenceEquals(resourceMan, null)) {
global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("Sheas_Cealer.Consts.SettingsMultilangConst", typeof(SettingsMultilangConst).Assembly);
resourceMan = temp;
}
return resourceMan;
}
}
/// <summary>
/// 重写当前线程的 CurrentUICulture 属性,对
/// 使用此强类型资源类的所有资源查找执行重写。
/// </summary>
[global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
public static global::System.Globalization.CultureInfo Culture {
get {
return resourceCulture;
}
set {
resourceCulture = value;
}
}
/// <summary>
/// 查找类似 Switch successfuly, restart to refresh the windows 的本地化字符串。
/// </summary>
public static string _ChangeLangSuccessMsg {
get {
return ResourceManager.GetString("_ChangeLangSuccessMsg", resourceCulture);
}
}
/// <summary>
/// 查找类似 SWT. Color (Fully Random) 的本地化字符串。
/// </summary>
public static string ColorsButtonContent {
get {
return ResourceManager.GetString("ColorsButtonContent", resourceCulture);
}
}
/// <summary>
/// 查找类似 Click to switch colors 的本地化字符串。
/// </summary>
public static string ColorsButtonToolTip {
get {
return ResourceManager.GetString("ColorsButtonToolTip", resourceCulture);
}
}
/// <summary>
/// 查找类似 Switch Lang (中文 → En) 的本地化字符串。
/// </summary>
public static string LangsButtonChineseLangContent {
get {
return ResourceManager.GetString("LangsButtonChineseLangContent", resourceCulture);
}
}
/// <summary>
/// 查找类似 Switch Lang (En → Auto) 的本地化字符串。
/// </summary>
public static string LangsButtonEnglishLangContent {
get {
return ResourceManager.GetString("LangsButtonEnglishLangContent", resourceCulture);
}
}
/// <summary>
/// 查找类似 Switch Lang (Auto → 中文) 的本地化字符串。
/// </summary>
public static string LangsButtonInheritLangContent {
get {
return ResourceManager.GetString("LangsButtonInheritLangContent", resourceCulture);
}
}
/// <summary>
/// 查找类似 Click to switch langs 的本地化字符串。
/// </summary>
public static string LangsButtonToolTip {
get {
return ResourceManager.GetString("LangsButtonToolTip", resourceCulture);
}
}
/// <summary>
/// 查找类似 SWT. Theme (Dark → Light) 的本地化字符串。
/// </summary>
public static string ThemesButtonDarkThemeContent {
get {
return ResourceManager.GetString("ThemesButtonDarkThemeContent", resourceCulture);
}
}
/// <summary>
/// 查找类似 SWT. Theme (Auto → Dark) 的本地化字符串。
/// </summary>
public static string ThemesButtonInheritThemeContent {
get {
return ResourceManager.GetString("ThemesButtonInheritThemeContent", resourceCulture);
}
}
/// <summary>
/// 查找类似 SWT. Theme (Light → Auto) 的本地化字符串。
/// </summary>
public static string ThemesButtonLightThemeContent {
get {
return ResourceManager.GetString("ThemesButtonLightThemeContent", resourceCulture);
}
}
/// <summary>
/// 查找类似 Click to switch themes 的本地化字符串。
/// </summary>
public static string ThemesButtonToolTip {
get {
return ResourceManager.GetString("ThemesButtonToolTip", resourceCulture);
}
}
/// <summary>
/// 查找类似 SWT. Weight (Bold → Light) 的本地化字符串。
/// </summary>
public static string WeightsButtonBoldWeightContent {
get {
return ResourceManager.GetString("WeightsButtonBoldWeightContent", resourceCulture);
}
}
/// <summary>
/// 查找类似 SWT. Weight (Light → Regular) 的本地化字符串。
/// </summary>
public static string WeightsButtonLightWeightContent {
get {
return ResourceManager.GetString("WeightsButtonLightWeightContent", resourceCulture);
}
}
/// <summary>
/// 查找类似 SWT. Weight (RGL. → Bold) 的本地化字符串。
/// </summary>
public static string WeightsButtonRegularWeightContent {
get {
return ResourceManager.GetString("WeightsButtonRegularWeightContent", resourceCulture);
}
}
/// <summary>
/// 查找类似 Click to switch font weights 的本地化字符串。
/// </summary>
public static string WeightsButtonToolTip {
get {
return ResourceManager.GetString("WeightsButtonToolTip", resourceCulture);
}
}
}
}

View File

@ -0,0 +1,145 @@
<?xml version="1.0" encoding="utf-8"?>
<root>
<!--
Microsoft ResX Schema
Version 1.3
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">1.3</resheader>
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
<data name="Name1">this is my long string</data>
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
[base64 mime encoded serialized .NET Framework object]
</data>
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
[base64 mime encoded string representing a byte array form of the .NET Framework object]
</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.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:element name="root" msdata:IsDataSet="true">
<xsd:complexType>
<xsd:choice maxOccurs="unbounded">
<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" msdata:Ordinal="1" />
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
</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>1.3</value>
</resheader>
<resheader name="reader">
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.3500.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.3500.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<data name="ColorsButtonContent" xml:space="preserve">
<value>SWT. Color (Fully Random)</value>
</data>
<data name="ColorsButtonToolTip" xml:space="preserve">
<value>Click to switch colors</value>
</data>
<data name="LangsButtonChineseLangContent" xml:space="preserve">
<value>Switch Lang (中文 → En)</value>
</data>
<data name="LangsButtonEnglishLangContent" xml:space="preserve">
<value>Switch Lang (En → Auto)</value>
</data>
<data name="LangsButtonInheritLangContent" xml:space="preserve">
<value>Switch Lang (Auto → 中文)</value>
</data>
<data name="LangsButtonToolTip" xml:space="preserve">
<value>Click to switch langs</value>
</data>
<data name="ThemesButtonDarkThemeContent" xml:space="preserve">
<value>SWT. Theme (Dark → Light)</value>
</data>
<data name="ThemesButtonInheritThemeContent" xml:space="preserve">
<value>SWT. Theme (Auto → Dark)</value>
</data>
<data name="ThemesButtonLightThemeContent" xml:space="preserve">
<value>SWT. Theme (Light → Auto)</value>
</data>
<data name="ThemesButtonToolTip" xml:space="preserve">
<value>Click to switch themes</value>
</data>
<data name="WeightsButtonBoldWeightContent" xml:space="preserve">
<value>SWT. Weight (Bold → Light)</value>
</data>
<data name="WeightsButtonLightWeightContent" xml:space="preserve">
<value>SWT. Weight (Light → Regular)</value>
</data>
<data name="WeightsButtonRegularWeightContent" xml:space="preserve">
<value>SWT. Weight (RGL. → Bold)</value>
</data>
<data name="WeightsButtonToolTip" xml:space="preserve">
<value>Click to switch font weights</value>
</data>
<data name="_ChangeLangSuccessMsg" xml:space="preserve">
<value>Switch successfuly, restart to refresh the windows</value>
</data>
</root>

View File

@ -0,0 +1,145 @@
<?xml version="1.0" encoding="utf-8"?>
<root>
<!--
Microsoft ResX Schema
Version 1.3
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">1.3</resheader>
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
<data name="Name1">this is my long string</data>
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
[base64 mime encoded serialized .NET Framework object]
</data>
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
[base64 mime encoded string representing a byte array form of the .NET Framework object]
</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.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:element name="root" msdata:IsDataSet="true">
<xsd:complexType>
<xsd:choice maxOccurs="unbounded">
<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" msdata:Ordinal="1" />
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
</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>1.3</value>
</resheader>
<resheader name="reader">
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.3500.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.3500.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<data name="ColorsButtonContent" xml:space="preserve">
<value>切换颜色 (全随机)</value>
</data>
<data name="ColorsButtonToolTip" xml:space="preserve">
<value>点击切换按钮颜色</value>
</data>
<data name="LangsButtonChineseLangContent" xml:space="preserve">
<value>切换语言 (中文 → En)</value>
</data>
<data name="LangsButtonEnglishLangContent" xml:space="preserve">
<value>切换语言 (En → 系统)</value>
</data>
<data name="LangsButtonInheritLangContent" xml:space="preserve">
<value>切换语言 (系统 → 中文)</value>
</data>
<data name="LangsButtonToolTip" xml:space="preserve">
<value>点击切换界面语言</value>
</data>
<data name="ThemesButtonDarkThemeContent" xml:space="preserve">
<value>切换主题 (暗色 → 亮色)</value>
</data>
<data name="ThemesButtonInheritThemeContent" xml:space="preserve">
<value>切换主题 (系统 → 暗色)</value>
</data>
<data name="ThemesButtonLightThemeContent" xml:space="preserve">
<value>切换主题 (亮色 → 系统)</value>
</data>
<data name="ThemesButtonToolTip" xml:space="preserve">
<value>点击切换显示主题</value>
</data>
<data name="WeightsButtonBoldWeightContent" xml:space="preserve">
<value>切换字重 (粗体 → 细体)</value>
</data>
<data name="WeightsButtonLightWeightContent" xml:space="preserve">
<value>切换字重 (细体 → 标准)</value>
</data>
<data name="WeightsButtonRegularWeightContent" xml:space="preserve">
<value>切换字重 (标准 → 粗体)</value>
</data>
<data name="WeightsButtonToolTip" xml:space="preserve">
<value>点击切换字体粗细</value>
</data>
<data name="_ChangeLangSuccessMsg" xml:space="preserve">
<value>语言更改完成,重启以刷新界面</value>
</data>
</root>

View File

@ -0,0 +1,18 @@
using System;
using System.Globalization;
using System.Windows.Data;
using System.Windows.Media;
namespace Sheas_Cealer.Convs;
internal class AboutAccentButtonForegroundConv : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
Color accentForegroundColor = (Color)value;
return new SolidColorBrush(accentForegroundColor);
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) => throw new NotImplementedException();
}

7
Convs/AboutConv.cs Normal file
View File

@ -0,0 +1,7 @@
namespace Sheas_Cealer.Convs;
internal static class AboutConv
{
public static AboutAccentButtonForegroundConv AboutAccentButtonForegroundConv => new();
public static AboutVersionButtonContentConv AboutVersionButtonContentConv => new();
}

View File

@ -0,0 +1,19 @@
using System;
using System.Globalization;
using System.Windows.Data;
namespace Sheas_Cealer.Convs;
internal class AboutVersionButtonContentConv : IMultiValueConverter
{
public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture)
{
string versionButtonLabelContent = (string)values[0];
string versionButtonVersionContent = (string)values[1];
bool isSheasCealerUtd = (bool)values[2];
return $"{versionButtonLabelContent} {versionButtonVersionContent}" + (isSheasCealerUtd ? string.Empty : " *");
}
public object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture) => throw new NotImplementedException();
}

View File

@ -0,0 +1,18 @@
using System;
using System.Globalization;
using System.Windows;
using System.Windows.Data;
namespace Sheas_Cealer.Convs;
internal class MainAdminControlVisibilityConv : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
bool isAdmin = (bool)value;
return isAdmin ? Visibility.Visible : Visibility.Collapsed;
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) => throw new NotImplementedException();
}

View File

@ -0,0 +1,20 @@
using Sheas_Cealer.Consts;
using System;
using System.Globalization;
using System.IO;
using System.Windows.Data;
namespace Sheas_Cealer.Convs;
internal class MainBrowserButtonIsEnabledConv : IMultiValueConverter
{
public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture)
{
string browserPath = (string)values[0];
string extraArgs = (string)values[1];
return File.Exists(browserPath) && Path.GetFileName(browserPath).ToLowerInvariant().EndsWith(".exe") && MainConst.ExtraArgsRegex().IsMatch(extraArgs);
}
public object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture) => throw new NotImplementedException();
}

24
Convs/MainConv.cs Normal file
View File

@ -0,0 +1,24 @@
namespace Sheas_Cealer.Convs;
internal static class MainConv
{
public static MainAdminControlVisibilityConv MainAdminControlVisibilityConv => new();
public static MainMihomoButtonContentConv MainMihomoButtonContentConv => new();
public static MainMihomoButtonIsEnabledConv MainMihomoButtonIsEnabledConv => new();
public static MainMihomoButtonToolTipConv MainMihomoButtonToolTipConv => new();
public static MainNginxButtonContentConv MainNginxButtonContentConv => new();
public static MainNginxButtonToolTipConv MainNginxButtonToolTipConv => new();
public static MainNoClickButtonContentConv MainNoClickButtonContentConv => new();
public static MainNoClickButtonToolTipConv MainNoClickButtonToolTipConv => new();
public static MainNginxButtonIsEnabledConv MainNginxButtonIsEnabledConv => new();
public static MainProxyColumnWidthConv MainProxyColumnWidthConv => new();
public static MainSettingsBoxHintConv MainSettingsBoxHintConv => new();
public static MainSettingsBoxTextConv MainSettingsBoxTextConv => new();
public static MainSettingsBoxToolTipConv MainSettingsBoxToolTipConv => new();
public static MainSettingsFunctionButtonContentConv MainSettingsFunctionButtonContentConv => new();
public static MainSettingsModeButtonContentConv MainSettingsModeButtonContentConv => new();
public static MainBrowserButtonIsEnabledConv MainBrowserButtonIsEnabledConv => new();
public static MainUpdateHostButtonContentConv MainUpdateHostButtonContentConv => new();
public static MainUpdateHostButtonIsEnabledConv MainUpdateHostButtonIsEnabledConv => new();
public static MainWinWidthConv MainWinWidthConv => new();
}

View File

@ -0,0 +1,25 @@
using Sheas_Cealer.Consts;
using System;
using System.Globalization;
using System.Windows.Data;
namespace Sheas_Cealer.Convs;
internal class MainMihomoButtonContentConv : IMultiValueConverter
{
public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture)
{
bool isMihomoRunning = (bool)values[0];
bool isComihomoIniting = (bool)values[1];
bool isMihomoIniting = (bool)values[2];
bool isCoproxyIniting = (bool)values[3];
bool isCoproxyStopping = (bool)values[4];
return isCoproxyIniting || isCoproxyStopping ? Binding.DoNothing :
isComihomoIniting ? MainConst.MihomoButtonIsStoppingContent :
isMihomoIniting ? MainConst.MihomoButtonIsInitingContent :
isMihomoRunning ? MainConst.MihomoButtonIsRunningContent : MainConst.MihomoButtonIsStoppedContent;
}
public object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture) => throw new NotImplementedException();
}

View File

@ -0,0 +1,21 @@
using System;
using System.Globalization;
using System.Windows.Data;
namespace Sheas_Cealer.Convs;
internal class MainMihomoButtonIsEnabledConv : IMultiValueConverter
{
public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture)
{
bool isCoMihomoExist = (bool)values[0];
bool isMihomoExist = (bool)values[1];
bool isCoproxyIniting = (bool)values[2];
bool isComihomoIniting = (bool)values[3];
bool isMihomoIniting = (bool)values[4];
return !isCoproxyIniting && !isComihomoIniting && !isMihomoIniting && (isCoMihomoExist || isMihomoExist);
}
public object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture) => throw new NotImplementedException();
}

View File

@ -0,0 +1,18 @@
using Sheas_Cealer.Consts;
using System;
using System.Globalization;
using System.Windows.Data;
namespace Sheas_Cealer.Convs;
internal class MainMihomoButtonToolTipConv : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
bool isMihomoRunning = (bool)value;
return isMihomoRunning ? MainConst.MihomoButtonIsRunningToolTip : MainConst.MihomoButtonIsStoppedToolTip;
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) => throw new NotImplementedException();
}

View File

@ -0,0 +1,23 @@
using Sheas_Cealer.Consts;
using System;
using System.Globalization;
using System.Windows.Data;
namespace Sheas_Cealer.Convs;
internal class MainNginxButtonContentConv : IMultiValueConverter
{
public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture)
{
bool isConginxRunning = (bool)values[0];
bool isNginxRunning = (bool)values[1];
bool isCoproxyIniting = (bool)values[2];
bool isNginxIniting = (bool)values[3];
return isCoproxyIniting ? MainConst.ConginxButtonIsInitingContent :
isNginxIniting ? MainConst.NginxButtonIsInitingContent :
isConginxRunning || isNginxRunning ? MainConst.NginxButtonIsRunningContent : MainConst.NginxButtonIsStoppedContent;
}
public object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture) => throw new NotImplementedException();
}

View File

@ -0,0 +1,22 @@
using System;
using System.Globalization;
using System.Windows.Data;
namespace Sheas_Cealer.Convs;
internal class MainNginxButtonIsEnabledConv : IMultiValueConverter
{
public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture)
{
bool isConginxExist = (bool)values[0];
bool isNginxExist = (bool)values[1];
bool isCoproxyIniting = (bool)values[2];
bool isNginxIniting = (bool)values[3];
bool isComihomoIniting = (bool)values[4];
bool isMihomoIniting = (bool)values[5];
return !isCoproxyIniting && !isNginxIniting && !isComihomoIniting && !isMihomoIniting && (isConginxExist || isNginxExist);
}
public object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture) => throw new NotImplementedException();
}

View File

@ -0,0 +1,19 @@
using Sheas_Cealer.Consts;
using System;
using System.Globalization;
using System.Windows.Data;
namespace Sheas_Cealer.Convs;
internal class MainNginxButtonToolTipConv : IMultiValueConverter
{
public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture)
{
bool isConginxRunning = (bool)values[0];
bool isNginxRunning = (bool)values[1];
return isConginxRunning || isNginxRunning ? MainConst.NginxButtonIsRunningToolTip : MainConst.NginxButtonIsStoppedToolTip;
}
public object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture) => throw new NotImplementedException();
}

View File

@ -0,0 +1,18 @@
using Sheas_Cealer.Consts;
using System;
using System.Globalization;
using System.Windows.Data;
namespace Sheas_Cealer.Convs;
internal class MainNoClickButtonContentConv : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
bool isFlashing = (bool)value;
return isFlashing ? MainConst.NoClickButtonIsFlashingContent : MainConst.NoClickButtonIsStoppedContent;
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) => throw new NotImplementedException();
}

View File

@ -0,0 +1,18 @@
using Sheas_Cealer.Consts;
using System;
using System.Globalization;
using System.Windows.Data;
namespace Sheas_Cealer.Convs;
internal class MainNoClickButtonToolTipConv : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
bool isFlashing = (bool)value;
return isFlashing ? MainConst.NoClickButtonIsFlashingToolTip : MainConst.NoClickButtonIsStoppedToolTip;
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) => throw new NotImplementedException();
}

View File

@ -0,0 +1,18 @@
using System;
using System.Globalization;
using System.Windows;
using System.Windows.Data;
namespace Sheas_Cealer.Convs;
internal class MainProxyColumnWidthConv : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
bool isAdmin = (bool)value;
return new GridLength(1, isAdmin ? GridUnitType.Star : GridUnitType.Auto);
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) => throw new NotImplementedException();
}

View File

@ -0,0 +1,25 @@
using Sheas_Cealer.Consts;
using System;
using System.Diagnostics;
using System.Globalization;
using System.Windows.Data;
namespace Sheas_Cealer.Convs;
internal class MainSettingsBoxHintConv : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
MainConst.SettingsMode settingsMode = (MainConst.SettingsMode)value;
return settingsMode switch
{
MainConst.SettingsMode.BrowserPathMode => MainConst.SettingsModeButtonBrowserPathContent,
MainConst.SettingsMode.UpstreamUrlMode => MainConst.SettingsModeButtonUpstreamUrlContent,
MainConst.SettingsMode.ExtraArgsMode => MainConst.SettingsModeButtonExtraArgsContent,
_ => throw new UnreachableException()
};
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) => throw new NotImplementedException();
}

View File

@ -0,0 +1,28 @@
using Sheas_Cealer.Consts;
using System;
using System.Diagnostics;
using System.Globalization;
using System.Windows.Data;
namespace Sheas_Cealer.Convs;
internal class MainSettingsBoxTextConv : IMultiValueConverter
{
public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture)
{
MainConst.SettingsMode settingsMode = (MainConst.SettingsMode)values[0];
string browserPath = (string)values[1];
string upstreamUrl = (string)values[2];
string extraArgs = (string)values[3];
return settingsMode switch
{
MainConst.SettingsMode.BrowserPathMode => browserPath,
MainConst.SettingsMode.UpstreamUrlMode => upstreamUrl,
MainConst.SettingsMode.ExtraArgsMode => extraArgs,
_ => throw new UnreachableException()
};
}
public object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture) => throw new NotImplementedException();
}

View File

@ -0,0 +1,25 @@
using Sheas_Cealer.Consts;
using System;
using System.Diagnostics;
using System.Globalization;
using System.Windows.Data;
namespace Sheas_Cealer.Convs;
internal class MainSettingsBoxToolTipConv : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
MainConst.SettingsMode settingsMode = (MainConst.SettingsMode)value;
return settingsMode switch
{
MainConst.SettingsMode.BrowserPathMode => MainConst.SettingsBoxBrowserPathToolTip,
MainConst.SettingsMode.UpstreamUrlMode => MainConst.SettingsBoxUpstreamUrlToolTip,
MainConst.SettingsMode.ExtraArgsMode => MainConst.SettingsBoxExtraArgsToolTip,
_ => throw new UnreachableException()
};
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) => throw new NotImplementedException();
}

View File

@ -0,0 +1,25 @@
using Sheas_Cealer.Consts;
using System;
using System.Diagnostics;
using System.Globalization;
using System.Windows.Data;
namespace Sheas_Cealer.Convs;
internal class MainSettingsFunctionButtonContentConv : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
MainConst.SettingsMode settingsMode = (MainConst.SettingsMode)value;
return settingsMode switch
{
MainConst.SettingsMode.BrowserPathMode => MainConst.SettingsFunctionButtonBrowserPathContent,
MainConst.SettingsMode.UpstreamUrlMode => MainConst.SettingsFunctionButtonUpstreamUrlContent,
MainConst.SettingsMode.ExtraArgsMode => MainConst.SettingsFunctionButtonExtraArgsContent,
_ => throw new UnreachableException()
};
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) => throw new NotImplementedException();
}

View File

@ -0,0 +1,24 @@
using Sheas_Cealer.Consts;
using System;
using System.Globalization;
using System.Windows.Data;
namespace Sheas_Cealer.Convs;
internal class MainSettingsModeButtonContentConv : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
MainConst.SettingsMode settingsMode = (MainConst.SettingsMode)value;
return settingsMode switch
{
MainConst.SettingsMode.BrowserPathMode => MainConst.SettingsModeButtonUpstreamUrlContent,
MainConst.SettingsMode.UpstreamUrlMode => MainConst.SettingsModeButtonExtraArgsContent,
MainConst.SettingsMode.ExtraArgsMode => MainConst.SettingsModeButtonBrowserPathContent,
_ => throw new NotImplementedException()
};
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) => throw new NotImplementedException();
}

View File

@ -0,0 +1,18 @@
using Sheas_Cealer.Consts;
using System;
using System.Globalization;
using System.Windows.Data;
namespace Sheas_Cealer.Convs;
internal class MainUpdateHostButtonContentConv : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
bool isUpstreamHostUtd = (bool)value;
return MainConst.UpdateUpstreamHostButtonContent + (isUpstreamHostUtd ? string.Empty : " *");
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) => throw new NotImplementedException();
}

View File

@ -0,0 +1,18 @@
using Sheas_Cealer.Consts;
using System;
using System.Globalization;
using System.Windows.Data;
namespace Sheas_Cealer.Convs;
internal class MainUpdateHostButtonIsEnabledConv : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
string upstreamUrl = (string)value;
return MainConst.UpstreamUrlRegex().IsMatch(upstreamUrl);
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) => throw new NotImplementedException();
}

17
Convs/MainWinWidthConv.cs Normal file
View File

@ -0,0 +1,17 @@
using System;
using System.Globalization;
using System.Windows.Data;
namespace Sheas_Cealer.Convs;
internal class MainWinWidthConv : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
bool isAdmin = (bool)value;
return isAdmin ? 708 : 500;
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) => throw new NotImplementedException();
}

8
Convs/SettingsConv.cs Normal file
View File

@ -0,0 +1,8 @@
namespace Sheas_Cealer.Convs;
internal static class SettingsConv
{
public static SettingsLangsButtonContentConv SettingsLangsButtonContentConv => new();
public static SettingsThemesButtonContentConv SettingsThemesButtonContentConv => new();
public static SettingsWeightsButtonContentConv SettingsWeightsButtonContentConv => new();
}

View File

@ -0,0 +1,20 @@
using Sheas_Cealer.Consts;
using System;
using System.Globalization;
using System.Windows.Data;
namespace Sheas_Cealer.Convs;
internal class SettingsLangsButtonContentConv : IValueConverter
{
public object Convert(object? value, Type targetType, object parameter, CultureInfo culture)
{
bool? isEnglishLang = value as bool?;
return isEnglishLang.HasValue ?
isEnglishLang.GetValueOrDefault() ? SettingsConst.LangsButtonEnglishLangContent : SettingsConst.LangsButtonChineseLangContent :
SettingsConst.LangsButtonInheritLangContent;
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) => throw new NotImplementedException();
}

View File

@ -0,0 +1,20 @@
using Sheas_Cealer.Consts;
using System;
using System.Globalization;
using System.Windows.Data;
namespace Sheas_Cealer.Convs;
internal class SettingsThemesButtonContentConv : IValueConverter
{
public object Convert(object? value, Type targetType, object parameter, CultureInfo culture)
{
bool? isLightMode = value as bool?;
return isLightMode.HasValue ?
isLightMode.GetValueOrDefault() ? SettingsConst.ThemesButtonLightThemeContent : SettingsConst.ThemesButtonDarkThemeContent :
SettingsConst.ThemesButtonInheritThemeContent;
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) => throw new NotImplementedException();
}

View File

@ -0,0 +1,20 @@
using Sheas_Cealer.Consts;
using System;
using System.Globalization;
using System.Windows.Data;
namespace Sheas_Cealer.Convs;
internal class SettingsWeightsButtonContentConv : IValueConverter
{
public object Convert(object? value, Type targetType, object parameter, CultureInfo culture)
{
bool? isLightWeight = value as bool?;
return isLightWeight.HasValue ?
isLightWeight.GetValueOrDefault() ? SettingsConst.WeightsButtonLightWeightContent : SettingsConst.WeightsButtonBoldWeightContent :
SettingsConst.WeightsButtonRegularWeightContent;
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) => throw new NotImplementedException();
}

9
Preses/AboutPres.cs Normal file
View File

@ -0,0 +1,9 @@
using CommunityToolkit.Mvvm.ComponentModel;
namespace Sheas_Cealer.Preses;
internal partial class AboutPres : GlobalPres
{
[ObservableProperty]
private bool isSheasCealerUtd = true;
}

44
Preses/GlobalPres.cs Normal file
View File

@ -0,0 +1,44 @@
using CommunityToolkit.Mvvm.ComponentModel;
using MaterialDesignThemes.Wpf;
using Sheas_Cealer.Consts;
using Sheas_Cealer.Props;
using Sheas_Cealer.Utils;
using System.Diagnostics;
using System.Windows;
using System.Windows.Media;
namespace Sheas_Cealer.Preses;
internal partial class GlobalPres : ObservableObject
{
internal GlobalPres()
{
IsLightTheme = Settings.Default.IsLightTheme switch
{
-1 => null,
0 => false,
1 => true,
_ => throw new UnreachableException()
};
}
[ObservableProperty]
private static bool? isLightTheme = null;
partial void OnIsLightThemeChanged(bool? value)
{
PaletteHelper paletteHelper = new();
Theme newTheme = paletteHelper.GetTheme();
newTheme.SetBaseTheme(value.HasValue ? value.Value ? BaseTheme.Light : BaseTheme.Dark : BaseTheme.Inherit);
paletteHelper.SetTheme(newTheme);
foreach (Window currentWindow in Application.Current.Windows)
BorderThemeSetter.SetBorderTheme(currentWindow, value);
Settings.Default.IsLightTheme = (sbyte)(value.HasValue ? value.Value ? 1 : 0 : -1);
Settings.Default.Save();
}
[ObservableProperty]
private static Color accentForegroundColor = AboutConst.AccentBlueColor;
}

118
Preses/MainPres.cs Normal file
View File

@ -0,0 +1,118 @@
using CommunityToolkit.Mvvm.ComponentModel;
using Microsoft.Win32;
using Sheas_Cealer.Consts;
using Sheas_Cealer.Props;
using System;
using System.Diagnostics;
using System.IO;
using File = System.IO.File;
namespace Sheas_Cealer.Preses;
internal partial class MainPres : GlobalPres
{
internal MainPres()
{
string[] args = Environment.GetCommandLineArgs();
int browserPathIndex = Array.FindIndex(args, arg => arg.Equals("-b", StringComparison.OrdinalIgnoreCase)) + 1;
int upstreamUrlIndex = Array.FindIndex(args, arg => arg.Equals("-u", StringComparison.OrdinalIgnoreCase)) + 1;
int extraArgsIndex = Array.FindIndex(args, arg => arg.Equals("-e", StringComparison.OrdinalIgnoreCase)) + 1;
BrowserPath = browserPathIndex != 0 && browserPathIndex != args.Length ? args[browserPathIndex] :
!string.IsNullOrWhiteSpace(Settings.Default.BrowserPath) ? Settings.Default.BrowserPath :
(Registry.LocalMachine.OpenSubKey(MainConst.EdgeBrowserRegistryPath)?.GetValue(string.Empty, null) ??
Registry.LocalMachine.OpenSubKey(MainConst.ChromeBrowserRegistryPath)?.GetValue(string.Empty, null) ??
Registry.LocalMachine.OpenSubKey(MainConst.BraveBrowserRegistryPath)?.GetValue(string.Empty, null) ??
string.Empty).ToString()!;
UpstreamUrl = upstreamUrlIndex == 0 || upstreamUrlIndex == args.Length ?
!string.IsNullOrWhiteSpace(Settings.Default.UpstreamUrl) ? Settings.Default.UpstreamUrl : MainConst.DefaultUpstreamUrl :
args[upstreamUrlIndex];
ExtraArgs = extraArgsIndex == 0 || extraArgsIndex == args.Length ?
!string.IsNullOrWhiteSpace(Settings.Default.ExtraArgs) ? Settings.Default.ExtraArgs : string.Empty :
args[extraArgsIndex];
}
[ObservableProperty]
private MainConst.SettingsMode settingsMode;
[ObservableProperty]
private string browserPath;
partial void OnBrowserPathChanged(string value)
{
if (!File.Exists(value) || !Path.GetFileName(value).ToLowerInvariant().EndsWith(".exe"))
return;
Settings.Default.BrowserPath = value;
Settings.Default.Save();
}
[ObservableProperty]
private string upstreamUrl;
partial void OnUpstreamUrlChanged(string value)
{
if (!MainConst.UpstreamUrlRegex().IsMatch(value))
return;
Settings.Default.UpstreamUrl = value;
Settings.Default.Save();
}
[ObservableProperty]
private string extraArgs;
partial void OnExtraArgsChanged(string value)
{
if (!MainConst.ExtraArgsRegex().IsMatch(value))
return;
Settings.Default.ExtraArgs = value;
Settings.Default.Save();
}
[ObservableProperty]
private bool isUpstreamHostUtd = true;
[ObservableProperty]
private bool isCoproxyIniting = false;
[ObservableProperty]
private bool isCoproxyStopping = false;
[ObservableProperty]
private bool isConginxExist = File.Exists(MainConst.ConginxPath);
[ObservableProperty]
private bool isNginxExist = File.Exists(MainConst.NginxPath);
[ObservableProperty]
private bool isNginxIniting = false;
[ObservableProperty]
private bool isConginxRunning = Process.GetProcessesByName(Path.GetFileNameWithoutExtension(MainConst.ConginxPath)).Length != 0;
[ObservableProperty]
private bool isNginxRunning = Process.GetProcessesByName(Path.GetFileNameWithoutExtension(MainConst.NginxPath)).Length != 0;
[ObservableProperty]
private bool isComihomoExist = File.Exists(MainConst.ComihomoPath);
[ObservableProperty]
private bool isMihomoExist = File.Exists(MainConst.MihomoPath);
[ObservableProperty]
private bool isComihomoIniting = false;
[ObservableProperty]
private bool isMihomoIniting = false;
[ObservableProperty]
private bool isComihomoRunning = Process.GetProcessesByName(Path.GetFileNameWithoutExtension(MainConst.ComihomoPath)).Length != 0;
[ObservableProperty]
private bool isMihomoRunning = Process.GetProcessesByName(Path.GetFileNameWithoutExtension(MainConst.MihomoPath)).Length != 0;
[ObservableProperty]
private bool isFlashing = false;
}

66
Preses/SettingsPres.cs Normal file
View File

@ -0,0 +1,66 @@
using CommunityToolkit.Mvvm.ComponentModel;
using Sheas_Cealer.Props;
using System.Diagnostics;
using System.Globalization;
using System.Threading;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Markup;
namespace Sheas_Cealer.Preses;
internal partial class SettingsPres : GlobalPres
{
internal SettingsPres()
{
IsEnglishLang = Settings.Default.IsEnglishLang switch
{
-1 => null,
0 => false,
1 => true,
_ => throw new UnreachableException()
};
IsLightWeight = Settings.Default.IsLightWeight switch
{
-1 => null,
0 => false,
1 => true,
_ => throw new UnreachableException()
};
}
[ObservableProperty]
private static bool? isEnglishLang = null;
partial void OnIsEnglishLangChanged(bool? value)
{
CultureInfo newCulture = value.HasValue ? new(value.Value ? "en" : "zh") : CultureInfo.InstalledUICulture;
Thread.CurrentThread.CurrentCulture = Thread.CurrentThread.CurrentUICulture = newCulture;
foreach (Window currentWindow in Application.Current.Windows)
currentWindow.Language = XmlLanguage.GetLanguage(newCulture.IetfLanguageTag);
Settings.Default.IsEnglishLang = (sbyte)(value.HasValue ? value.Value ? 1 : 0 : -1);
Settings.Default.Save();
}
[ObservableProperty]
private static bool? isLightWeight = null;
partial void OnIsLightWeightChanged(bool? value)
{
FontWeight newWeight = value.HasValue ? value.Value ? FontWeights.Light : FontWeights.Bold : FontWeights.Regular;
Style newWindowStyle = new(typeof(Window), Application.Current.Resources["CommonWindow"] as Style);
newWindowStyle.Setters.Add(new Setter(Window.FontWeightProperty, newWeight));
Application.Current.Resources["CommonWindow"] = newWindowStyle;
Style newButtonStyle = new(typeof(Button), Application.Current.Resources[typeof(Button)] as Style);
newButtonStyle.Setters.Add(new Setter(Button.FontWeightProperty, newWeight));
Application.Current.Resources[typeof(Button)] = newButtonStyle;
Settings.Default.IsLightWeight = (sbyte)(value.HasValue ? value.Value ? 1 : 0 : -1);
Settings.Default.Save();
}
}

18
Proces/BrowserProc.cs Normal file
View File

@ -0,0 +1,18 @@
using Sheas_Core;
using System;
using System.Windows;
namespace Sheas_Cealer.Proces;
internal class BrowserProc : Proc
{
private readonly bool ShutDownAppOnProcessExit;
internal BrowserProc(string browserPath, bool shutDownAppOnProcessExit) : base(browserPath) => ShutDownAppOnProcessExit = shutDownAppOnProcessExit;
protected sealed override void Process_Exited(object? sender, EventArgs e)
{
if (ShutDownAppOnProcessExit)
Application.Current.Dispatcher.InvokeShutdown();
}
}

9
Proces/ComihomoProc.cs Normal file
View File

@ -0,0 +1,9 @@
using Sheas_Cealer.Consts;
using Sheas_Core;
namespace Sheas_Cealer.Proces;
internal class ComihomoProc : Proc
{
internal ComihomoProc() : base(MainConst.ComihomoPath) { }
}

13
Proces/ConginxProc.cs Normal file
View File

@ -0,0 +1,13 @@
using Sheas_Cealer.Consts;
using Sheas_Cealer.Utils;
using Sheas_Core;
using System;
namespace Sheas_Cealer.Proces;
internal class ConginxProc : Proc
{
internal ConginxProc() : base(MainConst.ConginxPath) { }
protected override async void Process_Exited(object? sender, EventArgs e) => await NginxCleaner.Clean();
}

9
Proces/MihomoProc.cs Normal file
View File

@ -0,0 +1,9 @@
using Sheas_Cealer.Consts;
using Sheas_Core;
namespace Sheas_Cealer.Proces;
internal class MihomoProc : Proc
{
internal MihomoProc() : base(MainConst.MihomoPath) { }
}

13
Proces/NginxProc.cs Normal file
View File

@ -0,0 +1,13 @@
using Sheas_Cealer.Consts;
using Sheas_Cealer.Utils;
using Sheas_Core;
using System;
namespace Sheas_Cealer.Proces;
internal class NginxProc : Proc
{
internal NginxProc() : base(MainConst.NginxPath) { }
protected override async void Process_Exited(object? sender, EventArgs e) => await NginxCleaner.Clean();
}

View File

@ -1,10 +0,0 @@
using System.Windows;
[assembly: ThemeInfo(
ResourceDictionaryLocation.None, //where theme specific resource dictionaries are located
//(used if a resource is not found in the page,
// or application resource dictionaries)
ResourceDictionaryLocation.SourceAssembly //where the generic resource dictionary is located
//(used if a resource is not found in the page,
// app, or any theme specific resource dictionaries)
)]

View File

@ -1,38 +0,0 @@
//------------------------------------------------------------------------------
// <auto-generated>
// 此代码由工具生成。
// 运行时版本:4.0.30319.42000
//
// 对此文件的更改可能会导致不正确的行为,并且如果
// 重新生成代码,这些更改将会丢失。
// </auto-generated>
//------------------------------------------------------------------------------
namespace Sheas_Cealer.Properties {
[global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "17.1.0.0")]
internal sealed partial class Settings : global::System.Configuration.ApplicationSettingsBase {
private static Settings defaultInstance = ((Settings)(global::System.Configuration.ApplicationSettingsBase.Synchronized(new Settings())));
public static Settings Default {
get {
return defaultInstance;
}
}
[global::System.Configuration.UserScopedSettingAttribute()]
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
[global::System.Configuration.DefaultSettingValueAttribute("")]
public string BrowserPath {
get {
return ((string)(this["BrowserPath"]));
}
set {
this["BrowserPath"] = value;
}
}
}
}

View File

@ -1,9 +0,0 @@
<?xml version='1.0' encoding='utf-8'?>
<SettingsFile xmlns="http://schemas.microsoft.com/VisualStudio/2004/01/settings" CurrentProfile="(Default)" GeneratedClassNamespace="Sheas_Cealer.Properties" GeneratedClassName="Settings">
<Profiles />
<Settings>
<Setting Name="BrowserPath" Type="System.String" Scope="User">
<Value Profile="(Default)" />
</Setting>
</Settings>
</SettingsFile>

122
Props/Settings.Designer.cs generated Normal file
View File

@ -0,0 +1,122 @@
//------------------------------------------------------------------------------
// <auto-generated>
// 此代码由工具生成。
// 运行时版本:4.0.30319.42000
//
// 对此文件的更改可能会导致不正确的行为,并且如果
// 重新生成代码,这些更改将会丢失。
// </auto-generated>
//------------------------------------------------------------------------------
namespace Sheas_Cealer.Props {
[global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "17.13.0.0")]
internal sealed partial class Settings : global::System.Configuration.ApplicationSettingsBase {
private static Settings defaultInstance = ((Settings)(global::System.Configuration.ApplicationSettingsBase.Synchronized(new Settings())));
public static Settings Default {
get {
return defaultInstance;
}
}
[global::System.Configuration.UserScopedSettingAttribute()]
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
[global::System.Configuration.DefaultSettingValueAttribute("")]
public string BrowserPath {
get {
return ((string)(this["BrowserPath"]));
}
set {
this["BrowserPath"] = value;
}
}
[global::System.Configuration.UserScopedSettingAttribute()]
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
[global::System.Configuration.DefaultSettingValueAttribute("")]
public string UpstreamUrl {
get {
return ((string)(this["UpstreamUrl"]));
}
set {
this["UpstreamUrl"] = value;
}
}
[global::System.Configuration.UserScopedSettingAttribute()]
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
[global::System.Configuration.DefaultSettingValueAttribute("")]
public string ExtraArgs {
get {
return ((string)(this["ExtraArgs"]));
}
set {
this["ExtraArgs"] = value;
}
}
[global::System.Configuration.UserScopedSettingAttribute()]
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
[global::System.Configuration.DefaultSettingValueAttribute("244, 67, 54")]
public global::System.Drawing.Color PrimaryColor {
get {
return ((global::System.Drawing.Color)(this["PrimaryColor"]));
}
set {
this["PrimaryColor"] = value;
}
}
[global::System.Configuration.UserScopedSettingAttribute()]
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
[global::System.Configuration.DefaultSettingValueAttribute("-1")]
public sbyte IsLightTheme {
get {
return ((sbyte)(this["IsLightTheme"]));
}
set {
this["IsLightTheme"] = value;
}
}
[global::System.Configuration.UserScopedSettingAttribute()]
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
[global::System.Configuration.DefaultSettingValueAttribute("-1")]
public sbyte IsEnglishLang {
get {
return ((sbyte)(this["IsEnglishLang"]));
}
set {
this["IsEnglishLang"] = value;
}
}
[global::System.Configuration.UserScopedSettingAttribute()]
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
[global::System.Configuration.DefaultSettingValueAttribute("-1")]
public sbyte IsLightWeight {
get {
return ((sbyte)(this["IsLightWeight"]));
}
set {
this["IsLightWeight"] = value;
}
}
[global::System.Configuration.UserScopedSettingAttribute()]
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
[global::System.Configuration.DefaultSettingValueAttribute("True")]
public bool IsUpgradeRequired {
get {
return ((bool)(this["IsUpgradeRequired"]));
}
set {
this["IsUpgradeRequired"] = value;
}
}
}
}

30
Props/Settings.settings Normal file
View File

@ -0,0 +1,30 @@
<?xml version='1.0' encoding='utf-8'?>
<SettingsFile xmlns="http://schemas.microsoft.com/VisualStudio/2004/01/settings" CurrentProfile="(Default)" GeneratedClassNamespace="Sheas_Cealer.Props" GeneratedClassName="Settings">
<Profiles />
<Settings>
<Setting Name="BrowserPath" Type="System.String" Scope="User">
<Value Profile="(Default)" />
</Setting>
<Setting Name="UpstreamUrl" Type="System.String" Scope="User">
<Value Profile="(Default)" />
</Setting>
<Setting Name="ExtraArgs" Type="System.String" Scope="User">
<Value Profile="(Default)" />
</Setting>
<Setting Name="PrimaryColor" Type="System.Drawing.Color" Scope="User">
<Value Profile="(Default)">244, 67, 54</Value>
</Setting>
<Setting Name="IsLightTheme" Type="System.SByte" Scope="User">
<Value Profile="(Default)">-1</Value>
</Setting>
<Setting Name="IsEnglishLang" Type="System.SByte" Scope="User">
<Value Profile="(Default)">-1</Value>
</Setting>
<Setting Name="IsLightWeight" Type="System.SByte" Scope="User">
<Value Profile="(Default)">-1</Value>
</Setting>
<Setting Name="IsUpgradeRequired" Type="System.Boolean" Scope="User">
<Value Profile="(Default)">True</Value>
</Setting>
</Settings>
</SettingsFile>

View File

@ -2,55 +2,70 @@
<h3 align="center">- Just Ceal It -</h3>
</br>
## 自我介绍
**Sheas Cealer**: 一只基于 **WPF(.Net8)** 的 SNI 伪造工具
## 其他语言
[English README](README_EN.md)
* 适用平台: Windows x64
## 自我介绍
**Sheas Cealer**: 一只基于 **WPF(.Net8)** 的桌面端 SNI 伪造工具
* 适用平台: Windows (Win10 之前的系统版本请使用 [1.1.0](https://github.com/SpaceTimee/Sheas-Cealer/releases/tag/1.1.0)) (其他平台请参考[相关项目](https://github.com/SpaceTimee/Sheas-Cealer#相关项目))
## 词汇解释
**[Sheas Cealer Dictionary](https://github.com/SpaceTimee/Sheas-Cealer/wiki/Sheas-Cealer-Dictionary)**
## 注意事项
1. **Cealing-Host.json** 内置伪造规则在 [Cealing Host 存储库](https://github.com/SpaceTimee/Cealing-Host) 持续更新
2. Sheas Cealer 更新时不会覆盖已有的 **Cealing-Host.json** 配置文件,如需与上游同步,需点击**更新规则**按钮 (>= 1.1.0),或**手动修改覆盖**
3. 本项目仅供**学习参考**,无意绕过任何审查设备的审查
4. 为避免不必要的麻烦,食用前请先阅读**注意事项**和**用户协议**
1. 内置伪造规则在 [Cealing Host 存储库](https://github.com/SpaceTimee/Cealing-Host) 持续更新
2. Sheas Cealer 更新时不会覆盖已有的伪造规则,如需与上游同步,需点击**更新上游规则**按钮,或**手动修改覆盖**
3. 本项目及所有相关资源仅供**抵御网络非法监听**和**开展网络安全研究**使用,无意绕过任何国家审查设备的审查
4. 为避免不必要的麻烦,使用前请先阅读[**用户协议**](https://github.com/SpaceTimee/Sheas-Cealer#用户协议)
5. Sheas Cealer 仍处于**开发阶段**,但每个正式版发布前会尽量确保其**稳定可用**
6. Github Release 中会保留目前能够使用的**所有版本**,但强烈推荐使用**最新版**
## 用户协议
1. [隐私政策](https://thoughts.teambition.com/share/6264eda98adeb10041b92fda#title=Sheas_Cealer_隐私政策)
2. [使用协议](https://thoughts.teambition.com/share/6264edd78adeb10041b92fdb#title=Sheas_Cealer_使用协议)
## 下载地址
1. Github (首选): [https://github.com/SpaceTimee/Sheas-Cealer/releases](https://github.com/SpaceTimee/Sheas-Cealer/releases)
2. 蓝奏云 (密码 3wnj) (大陆推荐): [https://spacetime.lanzouu.com/b017hp0lc](https://spacetime.lanzouu.com/b017hp0lc)
1. Github: [https://github.com/SpaceTimee/Sheas-Cealer/releases](https://github.com/SpaceTimee/Sheas-Cealer/releases)
2. 群文件 (参与内测): 参考[联系方式](https://github.com/SpaceTimee/Sheas-Cealer#联系方式)
> 出于不可抗力因素Sheas Cealer 暂时无法再提供蓝奏云下载地址,在此依旧感谢蓝奏云一直以来的免费分发服务
## 安装方式
1. Setup 安装器 (首选): 下载 Sheas Cealer Setup.exe 并运行 -> 按照提示设置即可安装
2. Zip 压缩包 (免安装): 下载 Sheas Cealer Zip.zip 并解压 -> 完成后即可直接使用
> Scd 版本: Scd 版本内置 .Net 运行时,可在缺乏 .Net 运行时的环境下运行,但代价是更大的文件体积以及更差的跨平台能力,如果没有特殊原因,不建议使用 Scd 版本
## 食用文档
**[Sheas Cealer Instruction](https://github.com/SpaceTimee/Sheas-Cealer/wiki/Sheas-Cealer-Instruction)**
**[Sheas Cealer Documentation](https://github.com/SpaceTimee/Sheas-Cealer/wiki/Sheas-Cealer-Documentation)**
## 项目构建
[Sheas Cealer Build](https://github.com/SpaceTimee/Sheas-Cealer/wiki/Sheas-Cealer-Build)
## 项目原理
利用 Chromium 内核的参数特性伪造 SNI 头,详细原理可参考[这篇文章](https://nicebowl.fun/24_8)
利用 Chromium 内核的启动参数特性伪造 SNI 拓展标记,详细原理可参考[这篇文章](https://nicebowl.fun/24_8)
## 致谢名单
* **kit: 为本项目提供全部的原理基础**
* **NiceBowl: 为本项目提供详细的原理说明**
* **Clash: 为本项目解决过一段时间的 SSL 证书匹配问题**
## 开发者
**Space Time**
## 联系方式
1. **QQ 群 (主群): 338919498**
2. TG 群 (分群) (宽松管理): [PixCealerChat](https://t.me/PixCealerChat)
3. **邮箱: Zeus6_6@163.com**
1. **QQ 群: 1034315671716266896338919498**
2. **TG 群: [PixCealerChat](https://t.me/PixCealerChat)**
3. 邮箱: Zeus6_6@163.com
## 相关项目
1. [Sheas Cealer Droid](https://github.com/SpaceTimee/Sheas-Cealer-Droid): Sheas Cealer 安卓端
2. [Sheas Cealer Nix](https://github.com/SpaceTimee/Sheas-Cealer/tree/nix): Sheas Cealer 跨平台桌面端
3. [Cealing Host](https://github.com/SpaceTimee/Cealing-Host): 最新的 Sheas Cealer 内置伪造规则
4. [Sheas Dop](https://github.com/SpaceTimee/Sheas-Dop): DNS 抗污染解析工具 (Sheas Cealer 全局净化子项目)
5. [Sheas Nginx](https://github.com/SpaceTimee/Sheas-Nginx): Pixiv Nginx 启动器 (Sheas Cealer 全局伪造 × Pixiv Nginx 合作子项目)
6. [Bot CealingCat](https://github.com/SpaceTimee/Bot-CealingCat): 提供 Sheas Cealer 相关服务的 Telegram Bot
7. [Console HostChecker](https://github.com/SpaceTimee/Console-HostChecker): Cealing Host 自动化检查脚本
8. [Console HostGenerator](https://github.com/SpaceTimee/Console-HostGenerator): Cealing Host 自动化生成脚本
## 许可证
[![FOSSA Status](https://app.fossa.com/api/projects/git%2Bgithub.com%2FSpaceTimee%2FSheas-Cealer.svg?type=large)](https://app.fossa.com/projects/git%2Bgithub.com%2FSpaceTimee%2FSheas-Cealer?ref=badge_large)

73
README_EN.md Normal file
View File

@ -0,0 +1,73 @@
<h1 align="center">Sheas ◁ Cealer</h1>
<h3 align="center">- Just Ceal It -</h3>
</br>
## Language
[中文 README](README.md)
## About
**Sheas Cealer**: A desktop SNI concealing tool based on **WPF(.Net8)**
* Applicable platform: Windows (For system versions before Win10, please use [1.1.0](https://github.com/SpaceTimee/Sheas-Cealer/releases/tag/1.1.0)) (For more platforms, please refer to [Projects](https://github.com/SpaceTimee/Sheas-Cealer#Projects))
## Vocabulary
**[Sheas Cealer Dictionary](https://github.com/SpaceTimee/Sheas-Cealer/wiki/Sheas-Cealer-Dictionary)**
## Notes
1. The Built-in Cealing Host is continuously updated in the [Cealing Host repository](https://github.com/SpaceTimee/Cealing-Host)
2. When Sheas Cealer is updated, it will not overwrite the existing configs. If you need to synchronize with the upstream, you need to click the **Update Upstream Host** button, or **manually overwrite**
3. This project and all its resources are for the sole purpose of **defending against illegal network monitoring** and **conducting network security research**, and are not intended to bypass the censorship of any country
4. Please read the [**Agreements**](https://github.com/SpaceTimee/Sheas-Cealer#Agreements) before use
5. Sheas Cealer is still in the **development stage**, but each production version will be **stable and available** before release
## Agreements
1. [Privacy Policy](https://thoughts.teambition.com/share/6264eda98adeb10041b92fda#title=Sheas_Cealer_隐私政策)
2. [EULA](https://thoughts.teambition.com/share/6264edd78adeb10041b92fdb#title=Sheas_Cealer_使用协议)
## Download
1. Github (preferred): [https://github.com/SpaceTimee/Sheas-Cealer/releases](https://github.com/SpaceTimee/Sheas-Cealer/releases)
2. Group File (participate in internal testing): Please refer to [Contacts](https://github.com/SpaceTimee/Sheas-Cealer#Contacts)
> Due to force majeure, Sheas Cealer is temporarily unable to provide the download address of Lanzou Cloud. We would like to thank Lanzou Cloud for its free distribution service
## Installation
1. Setup Installer (preferred): Download Sheas Cealer Setup.exe and run -> Then follow the prompts to install
2. Zip Package (installation-free): Download Sheas Cealer Zip.zip and unzip -> Then you can use it directly
> Scd version: The Scd version has a built-in .Net runtime and can run in an environment without a .Net runtime, but the cost is a larger file size and worse cross-platform capabilities. If there is no special reason, it is not recommended to use the Scd version
## Documentation
**[Sheas Cealer Documentation](https://github.com/SpaceTimee/Sheas-Cealer/wiki/Sheas-Cealer-Documentation)**
## Build
[Sheas Cealer Build](https://github.com/SpaceTimee/Sheas-Cealer/wiki/Sheas-Cealer-Build)
## Principles
Using the startup parameter feature of the Chromium kernel to conceal SNI. For more detailes, please refer to [this article](https://nicebowl.fun/24_8)
## Credits
* **kit: Provides all the principle foundations for this project**
* **NiceBowl: Provides detailed principle explanations for this project**
## Developer
**Space Time**
## Contacts
1. **QQ Group: 1034315671, 716266896, 338919498**
2. **TG Group: [PixCealerChat](https://t.me/PixCealerChat)**
3. Email: Zeus6_6@163.com
## Projects
1. [Sheas Cealer Droid](https://github.com/SpaceTimee/Sheas-Cealer-Droid): Sheas Cealer for Android
2. [Sheas Cealer Nix](https://github.com/SpaceTimee/Sheas-Cealer/tree/nix): Sheas Cealer cross-platform for desktop
3. [Cealing Host](https://github.com/SpaceTimee/Cealing-Host): The latest Built-in Cealing Host
4. [Sheas Dop](https://github.com/SpaceTimee/Sheas-Dop): DNS anti-pollution resolution tool (Sheas Cealer Global Cealing subproject)
5. [Sheas Nginx](https://github.com/SpaceTimee/Sheas-Nginx): Pixiv Nginx launcher (Sheas Cealer Global Purging × Pixiv Nginx cooperative subproject)
6. [Bot CealingCat](https://github.com/SpaceTimee/Bot-CealingCat): Telegram Bot providing Sheas Cealer related services
7. [Console HostChecker](https://github.com/SpaceTimee/Console-HostChecker): Cealing Host automated checking script
8. [Console HostGenerator](https://github.com/SpaceTimee/Console-HostGenerator): Cealing Host automated generation script
## License
[![FOSSA Status](https://app.fossa.com/api/projects/git%2Bgithub.com%2FSpaceTimee%2FSheas-Cealer.svg?type=large)](https://app.fossa.com/projects/git%2Bgithub.com%2FSpaceTimee%2FSheas-Cealer?ref=badge_large)
•ᴗ•

View File

@ -8,10 +8,10 @@
<PackageReleaseNotes>Just Ceal It</PackageReleaseNotes>
<Authors>Space Time</Authors>
<Company>Space Time</Company>
<AssemblyVersion>1.1.0</AssemblyVersion>
<Version>1.1.0</Version>
<FileVersion>1.1.0</FileVersion>
<InformationalVersion>1.1.0</InformationalVersion>
<AssemblyVersion>1.1.5</AssemblyVersion>
<Version>1.1.5</Version>
<FileVersion>1.1.5</FileVersion>
<InformationalVersion>1.1.5</InformationalVersion>
<PackageTags>Tool;Sheas;Cealer;Sni</PackageTags>
<ApplicationIcon>Sheas-Cealer-Logo.ico</ApplicationIcon>
<PackageIcon>Sheas Cealer Logo.png</PackageIcon>
@ -19,26 +19,22 @@
<PackageProjectUrl>https://github.com/SpaceTimee/Sheas-Cealer</PackageProjectUrl>
<RepositoryUrl>https://github.com/SpaceTimee/Sheas-Cealer</RepositoryUrl>
<RepositoryType>git</RepositoryType>
<Copyright>Copyright © 2077</Copyright>
<Copyright>Copyright © 2077</Copyright>
<OutputType>WinExe</OutputType>
<TargetFramework>net8.0-windows10.0.22000.0</TargetFramework>
<TargetFramework>net8.0-windows10.0.26100.0</TargetFramework>
<SupportedOSPlatformVersion>10.0.17763.0</SupportedOSPlatformVersion>
<WindowsSdkPackageVersion>10.0.26100.41</WindowsSdkPackageVersion>
<RootNamespace>Sheas_Cealer</RootNamespace>
<Nullable>enable</Nullable>
<UseWPF>true</UseWPF>
<UseWindowsForms>True</UseWindowsForms>
<IsPublishable>True</IsPublishable>
<AllowUnsafeBlocks>True</AllowUnsafeBlocks>
<CheckForOverflowUnderflow>True</CheckForOverflowUnderflow>
<ErrorReport>none</ErrorReport>
<NoWin32Manifest>true</NoWin32Manifest>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|AnyCPU'">
<CheckForOverflowUnderflow>True</CheckForOverflowUnderflow>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|AnyCPU'">
<CheckForOverflowUnderflow>True</CheckForOverflowUnderflow>
<AppDesignerFolder>Props</AppDesignerFolder>
<NeutralLanguage>en</NeutralLanguage>
</PropertyGroup>
<ItemGroup>
@ -49,44 +45,47 @@
</ItemGroup>
<ItemGroup>
<AdditionalFiles Remove="app.manifest" />
</ItemGroup>
<ItemGroup>
<None Remove=".filenesting.json" />
<None Remove=".gitattributes" />
<None Remove=".gitignore" />
<None Remove="README.md" />
<None Remove="README_EN.md" />
<None Remove="Sheas-Cealer-Logo.ico" />
</ItemGroup>
<ItemGroup>
<COMReference Include="IWshRuntimeLibrary">
<WrapperTool>tlbimp</WrapperTool>
<VersionMinor>0</VersionMinor>
<VersionMajor>1</VersionMajor>
<Guid>f935dc20-1cf0-11d0-adb9-00c04fd58a0b</Guid>
<Lcid>0</Lcid>
<Isolated>false</Isolated>
<EmbedInteropTypes>true</EmbedInteropTypes>
</COMReference>
</ItemGroup>
<ItemGroup>
<PackageReference Include="MaterialDesignThemes" Version="5.0.0" />
<PackageReference Include="Newtonsoft.Json" Version="13.0.3" />
<PackageReference Include="CommunityToolkit.Mvvm" Version="*" />
<PackageReference Include="MaterialDesignThemes" Version="*" />
<PackageReference Include="NginxConfigParser" Version="*" />
<PackageReference Include="YamlDotNet" Version="*" />
</ItemGroup>
<ItemGroup>
<Reference Include="Ona-Core">
<HintPath>..\Ona-Core\bin\Release\net8.0-windows10.0.22000.0\Ona-Core.dll</HintPath>
<HintPath>..\Ona-Core\bin\Release\net8.0\Ona-Core.dll</HintPath>
</Reference>
<Reference Include="Sheas-Core">
<HintPath>..\Sheas-Core\bin\Release\Sheas-Core.dll</HintPath>
<HintPath>..\Sheas-Core\bin\Release\net8.0\Sheas-Core.dll</HintPath>
</Reference>
</ItemGroup>
<ItemGroup>
<Compile Update="Properties\Settings.Designer.cs">
<Compile Update="Consts\MainMultilangConst.Designer.cs">
<DesignTime>True</DesignTime>
<AutoGen>True</AutoGen>
<DependentUpon>MainMultilangConst.resx</DependentUpon>
</Compile>
<Compile Update="Consts\SettingsMultilangConst.Designer.cs">
<DesignTime>True</DesignTime>
<AutoGen>True</AutoGen>
<DependentUpon>SettingsMultilangConst.resx</DependentUpon>
</Compile>
<Compile Update="Consts\AboutMultilangConst.Designer.cs">
<DesignTime>True</DesignTime>
<AutoGen>True</AutoGen>
<DependentUpon>AboutMultilangConst.resx</DependentUpon>
</Compile>
<Compile Update="Props\Settings.Designer.cs">
<DesignTimeSharedInput>True</DesignTimeSharedInput>
<AutoGen>True</AutoGen>
<DependentUpon>Settings.settings</DependentUpon>
@ -94,7 +93,19 @@
</ItemGroup>
<ItemGroup>
<None Update="Properties\Settings.settings">
<EmbeddedResource Update="Consts\MainMultilangConst.resx">
<Generator>PublicResXFileCodeGenerator</Generator>
<LastGenOutput>MainMultilangConst.Designer.cs</LastGenOutput>
</EmbeddedResource>
<EmbeddedResource Update="Consts\SettingsMultilangConst.resx">
<Generator>PublicResXFileCodeGenerator</Generator>
<LastGenOutput>SettingsMultilangConst.Designer.cs</LastGenOutput>
</EmbeddedResource>
<EmbeddedResource Update="Consts\AboutMultilangConst.resx">
<Generator>PublicResXFileCodeGenerator</Generator>
<LastGenOutput>AboutMultilangConst.Designer.cs</LastGenOutput>
</EmbeddedResource>
<None Update="Props\Settings.settings">
<Generator>SettingsSingleFileGenerator</Generator>
<LastGenOutput>Settings.Designer.cs</LastGenOutput>
</None>

View File

@ -4,8 +4,12 @@ Microsoft Visual Studio Solution File, Format Version 12.00
VisualStudioVersion = 17.1.32328.378
MinimumVisualStudioVersion = 10.0.40219.1
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Sheas-Cealer", "Sheas-Cealer.csproj", "{662F787A-474F-41FD-B813-645CAA89E531}"
ProjectSection(ProjectDependencies) = postProject
{42491572-0050-4CDA-9189-DFC98BDBBF73} = {42491572-0050-4CDA-9189-DFC98BDBBF73}
{76263DF7-E4E4-4846-8604-8CFCA7125E2F} = {76263DF7-E4E4-4846-8604-8CFCA7125E2F}
EndProjectSection
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Sheas-Core", "D:\Git-Repository\Sheas-Core\Sheas-Core.csproj", "{42491572-0050-4CDA-9189-DFC98BDBBF73}"
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Sheas-Core", "..\Sheas-Core\Sheas-Core.csproj", "{42491572-0050-4CDA-9189-DFC98BDBBF73}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Ona-Core", "..\Ona-Core\Ona-Core.csproj", "{76263DF7-E4E4-4846-8604-8CFCA7125E2F}"
EndProject
@ -32,6 +36,12 @@ Global
HideSolutionNode = FALSE
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
RESX_Rules = {"EnabledRules":["StringFormat","WhiteSpaceLead","WhiteSpaceTail","PunctuationLead"]}
RESX_SortFileContentOnSave = True
SolutionGuid = {33005A8D-2D3D-4101-AFF0-F68B29FE9B28}
RESX_NeutralResourcesLanguage = en-US
RESX_ConfirmAddLanguageFile = True
RESX_AutoCreateNewLanguageFiles = True
RESX_DuplicateKeyHandling = Fail
EndGlobalSection
EndGlobal

View File

@ -1,21 +0,0 @@
using System;
using System.Diagnostics;
using SheasCore;
namespace Sheas_Cealer
{
internal class Command : Proc
{
internal Command() : base("Cmd.exe")
{
}
public override void Process_OutputDataReceived(object sender, DataReceivedEventArgs e)
{
}
public override void Process_ErrorDataReceived(object sender, DataReceivedEventArgs e)
{
}
public override void Process_Exited(object sender, EventArgs e) => Environment.Exit(0);
}
}

View File

@ -1,55 +0,0 @@
using System;
using System.Runtime.InteropServices;
using System.Windows;
using System.Windows.Interop;
namespace Sheas_Cealer
{
//定义IconRemover
internal static partial class IconRemover
{
private const int GWL_EXSTYLE = -20;
private const int WS_EX_DLGMODALFRAME = 0x0001;
private const int SWP_NOSIZE = 0x0001;
private const int SWP_NOMOVE = 0x0002;
private const int SWP_NOZORDER = 0x0004;
private const int SWP_FRAMECHANGED = 0x0020;
private const uint WM_SETICON = 0x0080;
[LibraryImport("user32.dll", EntryPoint = "GetWindowLongW")]
private static partial int GetWindowLong(IntPtr hwnd, int index);
[LibraryImport("user32.dll", EntryPoint = "SetWindowLongW")]
private static partial int SetWindowLong(IntPtr hwnd, int index, int newStyle);
[LibraryImport("user32.dll")]
[return: MarshalAs(UnmanagedType.Bool)]
private static partial bool SetWindowPos(IntPtr hwnd, IntPtr hwndInsertAfter, int x, int y, int width, int height, uint flags);
[LibraryImport("user32.dll", EntryPoint = "SendMessageW")]
private static partial IntPtr SendMessage(IntPtr hwnd, uint msg, IntPtr wParam, IntPtr lParam);
internal static void RemoveIcon(Window window)
{
//获取该窗口句柄
IntPtr hwnd = new WindowInteropHelper(window).Handle;
//将窗口更改为不显示窗口图标
_ = SetWindowLong(hwnd, GWL_EXSTYLE, GetWindowLong(hwnd, GWL_EXSTYLE) | WS_EX_DLGMODALFRAME);
//更新窗口的非客户区域来显示更改
SetWindowPos(hwnd, IntPtr.Zero, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER | SWP_FRAMECHANGED);
//防止自定义图标生效
SendMessage(hwnd, WM_SETICON, new IntPtr(1), IntPtr.Zero);
SendMessage(hwnd, WM_SETICON, IntPtr.Zero, IntPtr.Zero);
}
}
//使用IconRemover
public partial class MainWindow
{
protected override void OnSourceInitialized(EventArgs e) => IconRemover.RemoveIcon(this);
}
public partial class AboutWindow
{
protected override void OnSourceInitialized(EventArgs e) => IconRemover.RemoveIcon(this);
}
}

View File

@ -0,0 +1,31 @@
using System.Runtime.InteropServices;
using System.Windows;
using System.Windows.Interop;
namespace Sheas_Cealer.Utils;
internal static partial class BorderThemeSetter
{
private const int DwmwaUseImmersiveDarkModeOld = 19;
private const int DwmwaUseImmersiveDarkMode = 20;
[LibraryImport("dwmapi.dll")]
private static partial void DwmGetWindowAttribute(nint hwnd, uint attr, out nint attrValue, uint attrSize);
[LibraryImport("dwmapi.dll")]
private static partial void DwmSetWindowAttribute(nint hwnd, uint attr, ref nint attrValue, uint attrSize);
internal static void SetBorderTheme(Window window, bool? isLightTheme)
{
nint isDarkTheme;
nint desktopHwnd = nint.Zero;
nint windowHwnd = new WindowInteropHelper(window).EnsureHandle();
if (isLightTheme.HasValue)
isDarkTheme = !isLightTheme.Value ? 1 : 0;
else
DwmGetWindowAttribute(desktopHwnd, DwmwaUseImmersiveDarkMode, out isDarkTheme, (uint)Marshal.SizeOf(typeof(nint)));
DwmSetWindowAttribute(windowHwnd, DwmwaUseImmersiveDarkModeOld, ref isDarkTheme, (uint)Marshal.SizeOf(typeof(nint)));
DwmSetWindowAttribute(windowHwnd, DwmwaUseImmersiveDarkMode, ref isDarkTheme, (uint)Marshal.SizeOf(typeof(nint)));
}
}

11
Utils/DnsFlusher.cs Normal file
View File

@ -0,0 +1,11 @@
using System.Runtime.InteropServices;
namespace Sheas_Cealer.Utils;
internal static partial class DnsFlusher
{
[LibraryImport("dnsapi.dll")]
private static partial void DnsFlushResolverCache();
internal static void FlushDns() => DnsFlushResolverCache();
}

View File

@ -0,0 +1,31 @@
using Sheas_Cealer.Consts;
using System;
using System.Windows.Media;
namespace Sheas_Cealer.Utils;
internal static class ForegroundGenerator
{
internal static (Color?, Color) GetForeground(int red, int green, int blue)
{
double redComponent = red / 255.0, greenComponent = green / 255.0, blueComponent = blue / 255.0;
double luminance = 0.2126 * GammaCorrect(redComponent) + 0.7152 * GammaCorrect(greenComponent) + 0.0722 * GammaCorrect(blueComponent);
double blackContrast = (luminance + 0.05) / 0.05;
double whiteContrast = 1.05 / (luminance + 0.05);
double hue = redComponent > greenComponent && redComponent > blueComponent ? 60 * ((greenComponent - blueComponent) / (redComponent - Math.Min(greenComponent, blueComponent)) + (greenComponent < blueComponent ? 6 : 0)) :
greenComponent > blueComponent && greenComponent > redComponent ? 60 * ((blueComponent - redComponent) / (greenComponent - Math.Min(blueComponent, redComponent)) + 2) :
blueComponent > redComponent && blueComponent > greenComponent ? 60 * ((redComponent - greenComponent) / (blueComponent - Math.Min(redComponent, greenComponent)) + 4) : 0;
double blueContrast = Math.Min(Math.Abs(hue - 206.57), 360 - Math.Abs(hue - 206.57));
double redContrast = Math.Min(Math.Abs(hue - 4.11), 360 - Math.Abs(hue - 4.11));
return (blackContrast >= 5.5 && whiteContrast >= 2.5 ? null :
blackContrast >= whiteContrast ? Colors.Black : Colors.White,
blueContrast >= redContrast ? AboutConst.AccentBlueColor : AboutConst.AccentRedColor);
}
private static double GammaCorrect(double component) => component <= 0.03928 ? component / 12.92 : Math.Pow((component + 0.055) / 1.055, 2.4);
}

38
Utils/IconRemover.cs Normal file
View File

@ -0,0 +1,38 @@
using System.Runtime.InteropServices;
using System.Windows;
using System.Windows.Interop;
namespace Sheas_Cealer.Utils;
internal static partial class IconRemover
{
private const int GwlExStyle = -20;
private const int WsExDlgModalFrame = 0x0001;
private const int SwpNoSize = 0x0001;
private const int SwpNoMove = 0x0002;
private const int SwpNoZOrder = 0x0004;
private const int SwpFrameChanged = 0x0020;
private const uint WmSetIcon = 0x0080;
[LibraryImport("user32.dll", EntryPoint = "GetWindowLongW")]
private static partial int GetWindowLong(nint hwnd, int index);
[LibraryImport("user32.dll", EntryPoint = "SetWindowLongW")]
private static partial void SetWindowLong(nint hwnd, int index, nint newStyle);
[LibraryImport("user32.dll")]
[return: MarshalAs(UnmanagedType.Bool)]
private static partial void SetWindowPos(nint hwnd, nint hwndInsertAfter, int x, int y, int width, int height, uint flags);
[LibraryImport("user32.dll", EntryPoint = "SendMessageW")]
private static partial void SendMessage(nint hwnd, uint msg, nint wParam, nint lParam);
internal static void RemoveIcon(Window window)
{
nint hwnd = new WindowInteropHelper(window).Handle;
SetWindowLong(hwnd, GwlExStyle, GetWindowLong(hwnd, GwlExStyle) | WsExDlgModalFrame);
SetWindowPos(hwnd, nint.Zero, 0, 0, 0, 0, SwpNoMove | SwpNoSize | SwpNoZOrder | SwpFrameChanged);
SendMessage(hwnd, WmSetIcon, new(1), nint.Zero);
SendMessage(hwnd, WmSetIcon, nint.Zero, nint.Zero);
}
}

35
Utils/NginxCleaner.cs Normal file
View File

@ -0,0 +1,35 @@
using Sheas_Cealer.Consts;
using System;
using System.IO;
using System.Security.Cryptography.X509Certificates;
using System.Threading.Tasks;
namespace Sheas_Cealer.Utils;
internal static class NginxCleaner
{
internal static async Task Clean()
{
string hostsContent = await File.ReadAllTextAsync(MainConst.HostsConfPath);
int hostsConfStartIndex = hostsContent.IndexOf(MainConst.HostsConfStartMarker, StringComparison.Ordinal);
int hostsConfEndIndex = hostsContent.LastIndexOf(MainConst.HostsConfEndMarker, StringComparison.Ordinal);
if (hostsConfStartIndex != -1 && hostsConfEndIndex != -1)
await File.WriteAllTextAsync(MainConst.HostsConfPath, hostsContent.Remove(hostsConfStartIndex, hostsConfEndIndex - hostsConfStartIndex + MainConst.HostsConfEndMarker.Length));
using X509Store certStore = new(StoreName.Root, StoreLocation.LocalMachine, OpenFlags.ReadWrite);
foreach (X509Certificate2 storedCert in certStore.Certificates)
if (storedCert.Subject == MainConst.NginxRootCertSubjectName)
while (true)
try
{
certStore.Remove(storedCert);
break;
}
catch { }
certStore.Close();
}
}

View File

@ -1,31 +0,0 @@
<Window x:Class="Sheas_Cealer.AboutWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d"
Style="{DynamicResource CommonWindow}"
WindowStartupLocation="CenterScreen" Height="120" Width="500" MinWidth="500" ResizeMode="NoResize" Loaded="AboutWin_Loaded" KeyDown="AboutWin_KeyDown">
<Grid Margin="5">
<Grid.RowDefinitions>
<RowDefinition Height="*" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="1.1*" />
<ColumnDefinition Width="*" />
<ColumnDefinition Width="*" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<Button x:Name="DeveloperButton" Content="开发者: Space Time" Grid.Row="0" Grid.Column="0" Grid.ColumnSpan="2" Margin="5" Foreground="#FF2196F3" ToolTip="https://www.spacetimee.xyz" Click="AboutButton_Click" />
<Button x:Name="UpdateButton" Content="版本号: ?.?.?" Grid.Row="1" Grid.Column="0" Margin="5" Foreground="#FF2196F3" ToolTip="https://spacetime.lanzouu.com/b017hp0lc" Click="AboutButton_Click" />
<Button x:Name="EmailButton" Content="联系邮箱" Grid.Row="1" Grid.Column="1" Margin="5" ToolTip="Zeus6_6@163.com" />
<Button x:Name="HomePageButton" Content="使用文档" Grid.Row="0" Grid.Column="2" Margin="5" ToolTip="https://github.com/SpaceTimee/Sheas-Cealer/wiki/Sheas-Cealer-Instruction" Click="AboutButton_Click" />
<Button x:Name="OpenSourceButton" Content="开源地址" Grid.Row="1" Grid.Column="2" Margin="5" ToolTip="https://github.com/SpaceTimee/Sheas-Cealer" Click="AboutButton_Click" />
<Button x:Name="PrivacyButton" Content="隐私政策" Grid.Row="0" Grid.Column="3" Margin="5" ToolTip="https://thoughts.teambition.com/share/6264eda98adeb10041b92fda#title=Sheas_Cealer_隐私政策" Click="AboutButton_Click" />
<Button x:Name="AgreementButton" Content="使用协议" Grid.Row="1" Grid.Column="3" Margin="5" ToolTip="https://thoughts.teambition.com/share/6264edd78adeb10041b92fdb#title=Sheas_Cealer_使用协议" Click="AboutButton_Click" />
</Grid>
</Window>

View File

@ -1,32 +0,0 @@
using System.Diagnostics;
using System.Reflection;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;
namespace Sheas_Cealer
{
public partial class AboutWindow : Window
{
internal AboutWindow()
{
InitializeComponent();
}
private void AboutWin_Loaded(object sender, RoutedEventArgs e) => UpdateButton.Content = "版本号: " + Assembly.GetExecutingAssembly().GetName().Version!.ToString()[0..^2];
private void AboutButton_Click(object sender, RoutedEventArgs e)
{
if (sender == UpdateButton)
MessageBox.Show("密码: 3wnj");
ProcessStartInfo processStartInfo = new(sender == EmailButton ? "mailto:" : string.Empty + ((Button)sender).ToolTip) { UseShellExecute = true };
Process.Start(processStartInfo);
}
private void AboutWin_KeyDown(object sender, KeyEventArgs e)
{
if (e.Key == Key.Escape)
Close();
}
}
}

View File

@ -1,38 +0,0 @@
<Window x:Class="Sheas_Cealer.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d"
Style="{DynamicResource CommonWindow}"
WindowStartupLocation="CenterScreen" SizeToContent="Height" ResizeMode="CanMinimize" Width="500" MinWidth="500" AllowDrop="True" Loaded="MainWin_Loaded" Closing="MainWin_Closing" KeyDown="MainWin_KeyDown" DragEnter="MainWin_DragEnter" Drop="MainWin_Drop">
<Grid Margin="5">
<Grid.RowDefinitions>
<RowDefinition Height="*" />
<RowDefinition Height="*" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<Grid Grid.Row="0" Margin="5">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>
<TextBox x:Name="PathBox" Text="(填入任意以 Chromium 为内核的浏览器的路径)" Foreground="#FFBFCDDB" Grid.Column="0" Margin="0,0,10,0" VerticalContentAlignment="Center" GotFocus="PathBox_GotFocus" LostFocus="PathBox_LostFocus" TextChanged="PathBox_TextChanged" PreviewDragOver="MainWin_DragEnter" />
<Button x:Name="BrowseButton" Grid.Column="2" Content="浏览" Click="BrowseButton_Click" />
</Grid>
<Button x:Name="StartButton" Content="启动伪造" Grid.Row="1" Margin="5" IsDefault="True" IsEnabled="False" Click="StartButton_Click" />
<Grid Grid.Row="2" Margin="0,5">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="*" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<Button x:Name="HostEditButton" Content="编辑规则" Grid.Column="0" Margin="5,0" Click="HostEditButton_Click" />
<Button x:Name="HostUpdateButton" Content="更新规则" Grid.Column="1" Margin="5,0" Click="HostUpdateButton_Click" />
<Button x:Name="AboutButton" Content="关于项目" Grid.Column="2" Margin="5,0" Click="AboutButton_Click" />
</Grid>
</Grid>
</Window>

View File

@ -1,189 +0,0 @@
using System;
using System.ComponentModel;
using System.Diagnostics;
using System.IO;
using System.Net.Http;
using System.Text.RegularExpressions;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Threading;
using IWshRuntimeLibrary;
using Microsoft.Win32;
using Newtonsoft.Json.Linq;
using OnaCore;
using File = System.IO.File;
namespace Sheas_Cealer
{
public partial class MainWindow : Window
{
private readonly HttpClient MAIN_CLIENT = new(); //当前窗口使用的唯一的 HttpClient
private static readonly FileSystemWatcher CEALING_HOST_WATCHER = new(AppDomain.CurrentDomain.SetupInformation.ApplicationBase!, "Cealing-Host.json") { EnableRaisingEvents = true, NotifyFilter = NotifyFilters.LastWrite };
[GeneratedRegex(@"\r")] private static partial Regex HOST_REGEX();
private static string? CEALING_ARGUMENT;
internal MainWindow(string[] args)
{
InitializeComponent();
Task.Run(() =>
{
if (args.Length > 0)
Dispatcher.Invoke(() => PathBox.Text = args[0]);
else if (!string.IsNullOrWhiteSpace(Properties.Settings.Default.BrowserPath))
Dispatcher.Invoke(() => PathBox.Text = Properties.Settings.Default.BrowserPath);
CEALING_HOST_WATCHER.Changed += CEALING_HOST_WATCHER_Changed;
CEALING_HOST_WATCHER_Changed(null!, null!);
});
}
private void MainWin_Loaded(object sender, RoutedEventArgs e) => PathBox.Focus();
private void MainWin_Closing(object sender, CancelEventArgs e) => Environment.Exit(0);
private void PathBox_GotFocus(object sender, RoutedEventArgs e)
{
if (PathBox.Foreground != Foreground)
{
//PlaceHold状态
PathBox.Text = string.Empty;
PathBox.Foreground = Foreground;
}
}
private void PathBox_LostFocus(object sender, RoutedEventArgs e)
{
if (string.IsNullOrEmpty(PathBox.Text))
{
PathBox.Text = "(填入任意以 Chromium 为内核的浏览器的路径)";
PathBox.Foreground = new SolidColorBrush(Color.FromRgb(191, 205, 219));
}
}
private void PathBox_TextChanged(object sender, TextChangedEventArgs e)
{
if (StartButton == null)
return;
if (File.Exists(PathBox.Text) && Path.GetFileName(PathBox.Text).EndsWith(".exe"))
{
StartButton.IsEnabled = true;
Properties.Settings.Default.BrowserPath = PathBox.Text;
Properties.Settings.Default.Save();
}
else
StartButton.IsEnabled = false;
}
private void MainWin_DragEnter(object sender, DragEventArgs e)
{
if (e.Data.GetDataPresent(DataFormats.FileDrop))
e.Effects = DragDropEffects.Link;
else
e.Effects = DragDropEffects.None;
e.Handled = true;
}
private void MainWin_Drop(object sender, DragEventArgs e)
{
if (e.Data.GetDataPresent(DataFormats.FileDrop))
PathBox.Text = ((string[])e.Data.GetData(DataFormats.FileDrop))[0];
}
private void BrowseButton_Click(object sender, RoutedEventArgs e)
{
OpenFileDialog openFileDialog = new() { Filter = "浏览器 (*.exe)|*.exe" };
if (openFileDialog.ShowDialog() == true)
{
PathBox.Focus();
PathBox.Text = openFileDialog.FileName;
}
}
private void StartButton_Click(object sender, RoutedEventArgs e)
{
if (string.IsNullOrWhiteSpace(CEALING_ARGUMENT))
throw new Exception("规则无法识别,请检查伪造规则是否含有语法错误");
if (MessageBox.Show("启动前将关闭所选浏览器的所有进程,是否继续?", string.Empty, MessageBoxButton.YesNo) != MessageBoxResult.Yes)
return;
IWshShortcut uncealedBrowserShortcut = (IWshShortcut)new WshShell().CreateShortcut(Path.Combine(AppDomain.CurrentDomain.SetupInformation.ApplicationBase!, @"Uncealed-Browser.lnk"));
uncealedBrowserShortcut.TargetPath = PathBox.Text;
uncealedBrowserShortcut.Description = "Created By Sheas Cealer";
uncealedBrowserShortcut.Save();
foreach (Process browserProcess in Process.GetProcessesByName(Path.GetFileNameWithoutExtension(PathBox.Text)))
{
browserProcess.Kill();
browserProcess.WaitForExit();
}
new Command().ShellRun(AppDomain.CurrentDomain.SetupInformation.ApplicationBase!, CEALING_ARGUMENT);
}
private void HostEditButton_Click(object sender, RoutedEventArgs e)
{
ProcessStartInfo processStartInfo = new(Path.Combine(AppDomain.CurrentDomain.SetupInformation.ApplicationBase!, @"Cealing-Host.json")) { UseShellExecute = true };
Process.Start(processStartInfo);
}
private async void HostUpdateButton_Click(object sender, RoutedEventArgs e)
{
const string hostUrl = @"https://gitlab.com/SpaceTimee/Cealing-Host/raw/main/Cealing-Host.json";
string hostUpdateString = await Http.GetAsync<string>(hostUrl, MAIN_CLIENT);
StreamReader hostLocalStreamReader = new(Path.Combine(AppDomain.CurrentDomain.SetupInformation.ApplicationBase!, @"Cealing-Host.json"));
string hostLocalString = hostLocalStreamReader.ReadToEnd();
hostLocalStreamReader.Close();
if (HOST_REGEX().Replace(hostLocalString, string.Empty) == hostUpdateString)
MessageBox.Show("本地伪造规则和上游一模一样");
else
{
MessageBoxResult overrideResult = MessageBox.Show("本地伪造规则和上游略有不同,需要覆盖本地吗? 否则只为你打开上游规则的网页", "", MessageBoxButton.YesNoCancel);
if (overrideResult == MessageBoxResult.Yes)
{
File.WriteAllText(Path.Combine(AppDomain.CurrentDomain.SetupInformation.ApplicationBase!, @"Cealing-Host.json"), hostUpdateString);
MessageBox.Show("更新已完成");
}
else if (overrideResult == MessageBoxResult.No)
Process.Start(new ProcessStartInfo(hostUrl) { UseShellExecute = true });
}
}
private void AboutButton_Click(object sender, RoutedEventArgs e) => new AboutWindow().ShowDialog();
private void CEALING_HOST_WATCHER_Changed(object sender, FileSystemEventArgs e)
{
try
{
string hostRules = string.Empty, hostResolverRules = string.Empty;
int ruleIndex = 0;
FileStream hostStream = new(Path.Combine(AppDomain.CurrentDomain.SetupInformation.ApplicationBase!, @"Cealing-Host.json"), FileMode.OpenOrCreate, FileAccess.Read, FileShare.ReadWrite | FileShare.Delete);
JArray hostJArray = JArray.Parse(new StreamReader(hostStream).ReadToEnd());
foreach (var hostJToken in hostJArray)
{
if (string.IsNullOrWhiteSpace(hostJToken[1]!.ToString()))
hostJToken[1] = "c" + ruleIndex;
hostResolverRules += "MAP " + hostJToken[1]!.ToString() + " " + hostJToken[2]!.ToString() + ",";
foreach (var hostName in hostJToken[0]!)
hostRules += "MAP " + hostName.ToString() + " " + hostJToken[1] + ",";
++ruleIndex;
}
CEALING_ARGUMENT = @"/c @start .\""Uncealed-Browser.lnk"" --host-rules=""" + hostRules[0..^1] + @""" --host-resolver-rules=""" + hostResolverRules[0..^1] + @""" --test-type --ignore-certificate-errors";
}
catch { CEALING_ARGUMENT = string.Empty; }
}
private void MainWin_KeyDown(object sender, KeyEventArgs e)
{
if (e.KeyboardDevice.Modifiers == ModifierKeys.Control && e.Key == Key.W)
Environment.Exit(0);
}
}
}

69
Wins/AboutWin.xaml Normal file
View File

@ -0,0 +1,69 @@
<Window x:Class="Sheas_Cealer.Wins.AboutWin"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:consts="clr-namespace:Sheas_Cealer.Consts"
xmlns:convs="clr-namespace:Sheas_Cealer.Convs"
xmlns:preses="clr-namespace:Sheas_Cealer.Preses"
mc:Ignorable="d"
WindowStartupLocation="CenterScreen" ResizeMode="NoResize" SizeToContent="Height" Width="500"
d:DataContext="{d:DesignInstance preses:AboutPres}"
Style="{DynamicResource CommonWindow}"
SourceInitialized="AboutWin_SourceInitialized" Loaded="AboutWin_Loaded" KeyDown="AboutWin_KeyDown">
<Grid Margin="5">
<Grid.RowDefinitions>
<RowDefinition Height="*" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="1.2*" />
<ColumnDefinition Width="*" />
<ColumnDefinition Width="*" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<Button Grid.Row="0" Grid.Column="0" Grid.ColumnSpan="2" Margin="5"
d:Foreground="{Binding Source={x:Static consts:AboutConst.AccentBlueColor}, Converter={x:Static convs:AboutConv.AboutAccentButtonForegroundConv}}"
Foreground="{Binding AccentForegroundColor, Converter={x:Static convs:AboutConv.AboutAccentButtonForegroundConv}}"
Content="{x:Static consts:AboutConst.DeveloperButtonContent}"
ToolTip="{x:Static consts:AboutConst.DeveloperButtonUrl}"
Click="AboutButton_Click" />
<Button Grid.Row="1" Grid.Column="0" Margin="5" d:Content="# # #: #.#.#"
d:Foreground="{Binding Source={x:Static consts:AboutConst.AccentBlueColor}, Converter={x:Static convs:AboutConv.AboutAccentButtonForegroundConv}}"
Foreground="{Binding AccentForegroundColor, Converter={x:Static convs:AboutConv.AboutAccentButtonForegroundConv}}"
ToolTip="{x:Static consts:AboutConst.VersionButtonUrl}"
Click="AboutButton_Click">
<Button.Content>
<MultiBinding Converter="{x:Static convs:AboutConv.AboutVersionButtonContentConv}">
<Binding Source="{x:Static consts:AboutConst.VersionButtonLabelContent}" />
<Binding Source="{x:Static consts:AboutConst.VersionButtonVersionContent}" />
<Binding Path="IsSheasCealerUtd" />
</MultiBinding>
</Button.Content>
</Button>
<Button x:Name="EmailButton"
Grid.Row="1" Grid.Column="1" Margin="5"
Content="{x:Static consts:AboutConst.EmailButtonContent}"
ToolTip="{x:Static consts:AboutConst.EmailButtonUrl}"
Click="AboutButton_Click" />
<Button Grid.Row="0" Grid.Column="2" Margin="5"
Content="{x:Static consts:AboutConst.DocumentationButtonContent}"
ToolTip="{x:Static consts:AboutConst.DocumentationButtonUrl}"
Click="AboutButton_Click" />
<Button Grid.Row="1" Grid.Column="2" Margin="5"
Content="{x:Static consts:AboutConst.RepositoryButtonContent}"
ToolTip="{x:Static consts:AboutConst.RepositoryButtonUrl}"
Click="AboutButton_Click" />
<Button Grid.Row="0" Grid.Column="3" Margin="5"
Content="{x:Static consts:AboutConst.PolicyButtonContent}"
ToolTip="{x:Static consts:AboutConst.PolicyButtonUrl}"
Click="AboutButton_Click" />
<Button Grid.Row="1" Grid.Column="3" Margin="5"
Content="{x:Static consts:AboutConst.AgreementButtonContent}"
ToolTip="{x:Static consts:AboutConst.AgreementButtonUrl}"
Click="AboutButton_Click" />
</Grid>
</Window>

71
Wins/AboutWin.xaml.cs Normal file
View File

@ -0,0 +1,71 @@
using Ona_Core;
using Sheas_Cealer.Consts;
using Sheas_Cealer.Preses;
using Sheas_Cealer.Utils;
using System;
using System.Diagnostics;
using System.Net.Http;
using System.Text.Json;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;
namespace Sheas_Cealer.Wins;
public partial class AboutWin : Window
{
private readonly AboutPres AboutPres;
private readonly HttpClient AboutClient = new(new HttpClientHandler { ServerCertificateCustomValidationCallback = HttpClientHandler.DangerousAcceptAnyServerCertificateValidator });
internal AboutWin()
{
InitializeComponent();
DataContext = AboutPres = new();
}
private void AboutWin_SourceInitialized(object sender, EventArgs e)
{
IconRemover.RemoveIcon(this);
BorderThemeSetter.SetBorderTheme(this, AboutPres.IsLightTheme);
}
private async void AboutWin_Loaded(object sender, RoutedEventArgs e)
{
await Task.Run(async () =>
{
try
{
AboutClient.DefaultRequestHeaders.Add("User-Agent", AboutConst.ReleaseApiUserAgent);
JsonElement releaseInfoObject = JsonDocument.Parse(await Http.GetAsync<string>(AboutConst.ReleaseApiUrl, AboutClient)).RootElement;
AboutClient.DefaultRequestHeaders.Clear();
foreach (JsonProperty releaseInfoContent in releaseInfoObject.EnumerateObject())
if (releaseInfoContent.Name == "name" && releaseInfoContent.Value.ToString() != AboutConst.VersionButtonVersionContent)
AboutPres.IsSheasCealerUtd = false;
}
catch { }
});
}
private void AboutButton_Click(object sender, RoutedEventArgs e)
{
Button senderButton = (Button)sender;
ProcessStartInfo processStartInfo = new(senderButton == EmailButton ? "mailto:" : string.Empty + senderButton.ToolTip) { UseShellExecute = true };
try { Process.Start(processStartInfo); }
catch (UnauthorizedAccessException)
{
processStartInfo.Verb = "RunAs";
Process.Start(processStartInfo);
}
}
private void AboutWin_KeyDown(object sender, KeyEventArgs e)
{
if (e.Key == Key.Escape)
Close();
}
}

222
Wins/MainWin.xaml Normal file
View File

@ -0,0 +1,222 @@
<Window x:Class="Sheas_Cealer.Wins.MainWin"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:md="http://materialdesigninxaml.net/winfx/xaml/themes"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:consts="clr-namespace:Sheas_Cealer.Consts"
xmlns:convs="clr-namespace:Sheas_Cealer.Convs"
xmlns:preses="clr-namespace:Sheas_Cealer.Preses"
mc:Ignorable="d"
AllowDrop="True"
WindowStartupLocation="CenterScreen" ResizeMode="CanMinimize" SizeToContent="Height"
d:DataContext="{d:DesignInstance preses:MainPres}"
Style="{DynamicResource CommonWindow}"
Width="{Binding Source={x:Static consts:MainConst.IsAdmin}, Converter={x:Static convs:MainConv.MainWinWidthConv}}"
SourceInitialized="MainWin_SourceInitialized" Loaded="MainWin_Loaded" Closing="MainWin_Closing" DragEnter="MainWin_DragEnter" Drop="MainWin_Drop" KeyDown="MainWin_KeyDown">
<Grid Margin="5">
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="*" />
<RowDefinition Height="*" />
<RowDefinition Height="*" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<Grid Grid.Row="0">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="*" />
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>
<Button Grid.Column="0" Margin="5" d:Content="# # # #"
Content="{Binding SettingsMode, Converter={x:Static convs:MainConv.MainSettingsModeButtonContentConv}}"
ToolTip="{x:Static consts:MainConst.SettingsModeButtonToolTip}"
Click="SettingsModeButton_Click" />
<TextBox x:Name="SettingsBox"
Grid.Column="1" Margin="5" VerticalContentAlignment="Center" md:HintAssist.IsFloating="True"
AutomationProperties.Name="{Binding SettingsMode, Converter={x:Static convs:MainConv.MainSettingsBoxHintConv}}"
md:HintAssist.Hint="{Binding SettingsMode, Converter={x:Static convs:MainConv.MainSettingsBoxHintConv}}"
ToolTip="{Binding SettingsMode, Converter={x:Static convs:MainConv.MainSettingsBoxToolTipConv}}"
TextChanged="SettingsBox_TextChanged" PreviewDragOver="MainWin_DragEnter">
<TextBox.Text>
<MultiBinding Mode="OneWay" UpdateSourceTrigger="PropertyChanged"
Converter="{x:Static convs:MainConv.MainSettingsBoxTextConv}">
<Binding Path="SettingsMode" />
<Binding Path="BrowserPath" />
<Binding Path="UpstreamUrl" />
<Binding Path="ExtraArgs" />
</MultiBinding>
</TextBox.Text>
</TextBox>
<Button Grid.Column="2" Margin="5" d:Content="# # # #"
Content="{Binding SettingsMode, Converter={x:Static convs:MainConv.MainSettingsFunctionButtonContentConv}}"
ToolTip="{x:Static consts:MainConst.SettingsFunctionButtonToolTip}"
Click="SettingsFunctionButton_Click" />
</Grid>
<Grid Grid.Row="1">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="2*" />
<ColumnDefinition Width="{Binding Source={x:Static consts:MainConst.IsAdmin}, Converter={x:Static convs:MainConv.MainProxyColumnWidthConv}}" />
<ColumnDefinition Width="{Binding Source={x:Static consts:MainConst.IsAdmin}, Converter={x:Static convs:MainConv.MainProxyColumnWidthConv}}" />
</Grid.ColumnDefinitions>
<Button IsDefault="True"
Grid.Column="0" Margin="5"
Content="{x:Static consts:MainConst.BrowserButtonContent}"
ToolTip="{x:Static consts:MainConst.BrowserButtonToolTip}"
Click="LaunchButton_Click" PreviewMouseDown="LaunchButton_PreviewMouseDown">
<Button.IsEnabled>
<MultiBinding Converter="{x:Static convs:MainConv.MainBrowserButtonIsEnabledConv}">
<Binding Path="BrowserPath" />
<Binding Path="ExtraArgs" />
</MultiBinding>
</Button.IsEnabled>
</Button>
<Button x:Name="NginxButton"
Grid.Column="1" Margin="5" d:Content="# # # #"
Visibility="{Binding Source={x:Static consts:MainConst.IsAdmin}, Converter={x:Static convs:MainConv.MainAdminControlVisibilityConv}}"
Click="LaunchButton_Click" PreviewMouseDown="LaunchButton_PreviewMouseDown">
<Button.IsEnabled>
<MultiBinding Converter="{x:Static convs:MainConv.MainNginxButtonIsEnabledConv}">
<Binding Path="IsConginxExist" />
<Binding Path="IsNginxExist" />
<Binding Path="IsCoproxyIniting" />
<Binding Path="IsNginxIniting" />
<Binding Path="IsComihomoIniting" />
<Binding Path="IsMihomoIniting" />
</MultiBinding>
</Button.IsEnabled>
<Button.Content>
<MultiBinding Converter="{x:Static convs:MainConv.MainNginxButtonContentConv}">
<Binding Path="IsConginxRunning" />
<Binding Path="IsNginxRunning" />
<Binding Path="IsCoproxyIniting" />
<Binding Path="IsNginxIniting" />
</MultiBinding>
</Button.Content>
<Button.ToolTip>
<MultiBinding Converter="{x:Static convs:MainConv.MainNginxButtonToolTipConv}">
<Binding Path="IsConginxRunning" />
<Binding Path="IsNginxRunning" />
</MultiBinding>
</Button.ToolTip>
</Button>
<Button x:Name="MihomoButton"
Grid.Column="2" Margin="5" d:Content="# # # #"
Visibility="{Binding Source={x:Static consts:MainConst.IsAdmin}, Converter={x:Static convs:MainConv.MainAdminControlVisibilityConv}}"
ToolTip="{Binding IsMihomoRunning, Converter={x:Static convs:MainConv.MainMihomoButtonToolTipConv}}"
Click="LaunchButton_Click" PreviewMouseDown="LaunchButton_PreviewMouseDown">
<Button.IsEnabled>
<MultiBinding Converter="{x:Static convs:MainConv.MainMihomoButtonIsEnabledConv}">
<Binding Path="IsComihomoExist" />
<Binding Path="IsMihomoExist" />
<Binding Path="IsCoproxyIniting" />
<Binding Path="IsComihomoIniting" />
<Binding Path="IsMihomoIniting" />
</MultiBinding>
</Button.IsEnabled>
<Button.Content>
<MultiBinding Converter="{x:Static convs:MainConv.MainMihomoButtonContentConv}">
<Binding Path="IsMihomoRunning" />
<Binding Path="IsComihomoIniting" />
<Binding Path="IsMihomoIniting" />
<Binding Path="IsCoproxyIniting" />
<Binding Path="IsCoproxyStopping" />
</MultiBinding>
</Button.Content>
</Button>
</Grid>
<Grid Grid.Row="2">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="*" />
<ColumnDefinition Width="{Binding Source={x:Static consts:MainConst.IsAdmin}, Converter={x:Static convs:MainConv.MainProxyColumnWidthConv}}" />
<ColumnDefinition Width="{Binding Source={x:Static consts:MainConst.IsAdmin}, Converter={x:Static convs:MainConv.MainProxyColumnWidthConv}}" />
</Grid.ColumnDefinitions>
<Button x:Name="EditLocalHostButton"
Grid.Column="0" Margin="5"
Content="{x:Static consts:MainConst.EditLocalHostButtonContent}"
ToolTip="{x:Static consts:MainConst.EditLocalHostButtonToolTip}"
Click="EditHostButton_Click" />
<Button Grid.Column="1" Margin="5"
Content="{x:Static consts:MainConst.EditUpstreamHostButtonContent}"
ToolTip="{x:Static consts:MainConst.EditUpstreamHostButtonToolTip}"
Click="EditHostButton_Click" />
<Button x:Name="EditNginxConfButton"
Grid.Column="2" Margin="5"
Visibility="{Binding Source={x:Static consts:MainConst.IsAdmin}, Converter={x:Static convs:MainConv.MainAdminControlVisibilityConv}}"
Content="{x:Static consts:MainConst.EditNginxConfButtonContent}"
ToolTip="{x:Static consts:MainConst.EditNginxConfButtonToolTip}"
Click="EditConfButton_Click">
<Button.IsEnabled>
<MultiBinding Converter="{x:Static convs:MainConv.MainNginxButtonIsEnabledConv}">
<Binding Path="IsConginxExist" />
<Binding Path="IsNginxExist" />
<Binding Path="IsCoproxyIniting" />
<Binding Path="IsNginxIniting" />
<Binding Path="IsComihomoIniting" />
<Binding Path="IsMihomoIniting" />
</MultiBinding>
</Button.IsEnabled>
</Button>
<Button Grid.Column="3" Margin="5"
Visibility="{Binding Source={x:Static consts:MainConst.IsAdmin}, Converter={x:Static convs:MainConv.MainAdminControlVisibilityConv}}"
Content="{x:Static consts:MainConst.EditMihomoConfButtonContent}"
ToolTip="{x:Static consts:MainConst.EditMihomoConfButtonToolTip}"
Click="EditConfButton_Click">
<Button.IsEnabled>
<MultiBinding Converter="{x:Static convs:MainConv.MainMihomoButtonIsEnabledConv}">
<Binding Path="IsComihomoExist" />
<Binding Path="IsMihomoExist" />
<Binding Path="IsCoproxyIniting" />
<Binding Path="IsComihomoIniting" />
<Binding Path="IsMihomoIniting" />
</MultiBinding>
</Button.IsEnabled>
</Button>
</Grid>
<Grid Grid.Row="3">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="{Binding Source={x:Static consts:MainConst.IsAdmin}, Converter={x:Static convs:MainConv.MainProxyColumnWidthConv}}" />
</Grid.ColumnDefinitions>
<Button Grid.Column="0" Margin="5" d:Content="# # # # # #"
IsEnabled="{Binding UpstreamUrl, Converter={x:Static convs:MainConv.MainUpdateHostButtonIsEnabledConv}}"
Content="{Binding IsUpstreamHostUtd, Converter={x:Static convs:MainConv.MainUpdateHostButtonContentConv}}"
ToolTip="{x:Static consts:MainConst.UpdateUpstreamHostButtonToolTip}"
Click="UpdateUpstreamHostButton_Click" />
<Button x:Name="EditHostsConfButton"
Grid.Column="1" Margin="5"
Visibility="{Binding Source={x:Static consts:MainConst.IsAdmin}, Converter={x:Static convs:MainConv.MainAdminControlVisibilityConv}}"
Content="{x:Static consts:MainConst.EditHostsConfButtonContent}"
ToolTip="{x:Static consts:MainConst.EditHostsConfButtonToolTip}"
Click="EditConfButton_Click" />
</Grid>
<Grid Grid.Row="4">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="{Binding Source={x:Static consts:MainConst.IsAdmin}, Converter={x:Static convs:MainConv.MainProxyColumnWidthConv}}" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<Button Grid.Column="0" Margin="5"
Content="{x:Static consts:MainConst.SettingsButtonContent}"
ToolTip="{x:Static consts:MainConst.SettingsButtonToolTip}"
Click="SettingsButton_Click" />
<Button Focusable="False"
Grid.Column="1" Margin="5" d:Content="# # # #"
Visibility="{Binding Source={x:Static consts:MainConst.IsAdmin}, Converter={x:Static convs:MainConv.MainAdminControlVisibilityConv}}"
Content="{Binding IsFlashing, Converter={x:Static convs:MainConv.MainNoClickButtonContentConv}}"
ToolTip="{Binding IsFlashing, Converter={x:Static convs:MainConv.MainNoClickButtonToolTipConv}}"
Click="NoClickButton_Click" />
<Button Grid.Column="2" Margin="5"
Content="{x:Static consts:MainConst.AboutButtonContent}"
ToolTip="{x:Static consts:MainConst.AboutButtonToolTip}"
Click="AboutButton_Click" />
</Grid>
</Grid>
</Window>

940
Wins/MainWin.xaml.cs Normal file
View File

@ -0,0 +1,940 @@
using MaterialDesignThemes.Wpf;
using Microsoft.Win32;
using NginxConfigParser;
using Ona_Core;
using Sheas_Cealer.Consts;
using Sheas_Cealer.Preses;
using Sheas_Cealer.Proces;
using Sheas_Cealer.Utils;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Diagnostics;
using System.IO;
using System.Net;
using System.Net.Http;
using System.Net.NetworkInformation;
using System.Net.Sockets;
using System.Reflection;
using System.Security.Cryptography;
using System.Security.Cryptography.X509Certificates;
using System.Text;
using System.Text.Json;
using System.Threading;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Threading;
using YamlDotNet.Serialization;
using YamlDotNet.Serialization.NamingConventions;
using File = System.IO.File;
namespace Sheas_Cealer.Wins;
public partial class MainWin : Window
{
private readonly MainPres MainPres;
private readonly HttpClient MainClient = new(new HttpClientHandler { ServerCertificateCustomValidationCallback = HttpClientHandler.DangerousAcceptAnyServerCertificateValidator });
private DispatcherTimer? HoldButtonTimer;
private readonly DispatcherTimer ProxyTimer = new() { Interval = TimeSpan.FromSeconds(0.1) };
private readonly FileSystemWatcher CealHostWatcher = new(Path.GetDirectoryName(MainConst.CealHostPath)!, Path.GetFileName(MainConst.CealHostPath)) { EnableRaisingEvents = true, NotifyFilter = NotifyFilters.LastWrite };
private readonly FileSystemWatcher NginxConfWatcher = new(Path.GetDirectoryName(MainConst.NginxConfPath)!, Path.GetFileName(MainConst.NginxConfPath)) { EnableRaisingEvents = true, NotifyFilter = NotifyFilters.LastWrite };
private readonly FileSystemWatcher MihomoConfWatcher = new(Path.GetDirectoryName(MainConst.MihomoConfPath)!, Path.GetFileName(MainConst.MihomoConfPath)) { EnableRaisingEvents = true, NotifyFilter = NotifyFilters.LastWrite };
private readonly SemaphoreSlim IsNginxLaunchingSemaphore = new(1);
private readonly SortedDictionary<string, List<(List<(string cealHostIncludeDomain, string cealHostExcludeDomain)> cealHostDomainPairs, string? cealHostSni, string cealHostIp)>?> CealHostRulesDict = [];
private string CealArgs = string.Empty;
private NginxConfig? NginxConfs;
private string? ExtraNginxConfs;
private string? ComihomoConfs;
private string? HostsComihomoConfs;
private string? MihomoConfs;
private string? ExtraMihomoConfs;
private int NginxHttpPort = 80;
private int NginxHttpsPort = 443;
private int MihomoMixedPort = 7880;
private int GameClickTime = 0;
private int GameFlashInterval = 1000;
internal MainWin()
{
InitializeComponent();
DataContext = MainPres = new();
}
private void MainWin_SourceInitialized(object sender, EventArgs e)
{
IconRemover.RemoveIcon(this);
BorderThemeSetter.SetBorderTheme(this, MainPres.IsLightTheme);
}
private async void MainWin_Loaded(object sender, RoutedEventArgs e)
{
await Task.Run(async () =>
{
ProxyTimer.Tick += ProxyTimer_Tick;
CealHostWatcher.Changed += CealHostWatcher_Changed;
NginxConfWatcher.Changed += NginxConfWatcher_Changed;
MihomoConfWatcher.Changed += MihomoConfWatcher_Changed;
ProxyTimer.Start();
foreach (string cealHostPath in Directory.GetFiles(CealHostWatcher.Path, CealHostWatcher.Filter))
CealHostWatcher_Changed(null!, new(new(), Path.GetDirectoryName(cealHostPath)!, Path.GetFileName(cealHostPath)));
if (MainConst.IsAdmin && !MainPres.IsConginxRunning && !MainPres.IsNginxRunning)
await NginxCleaner.Clean();
if (Array.Exists(Environment.GetCommandLineArgs(), arg => arg.Equals("-s", StringComparison.OrdinalIgnoreCase)))
LaunchButton_Click(null, (RoutedEventArgs)RoutedEventArgs.Empty);
UpdateUpstreamHostButton_Click(null, null!);
});
}
private async void MainWin_Closing(object sender, CancelEventArgs e)
{
if (MainPres.IsNginxIniting)
await File.WriteAllTextAsync(MainConst.NginxConfPath, ExtraNginxConfs);
if (MainPres.IsMihomoIniting)
await File.WriteAllTextAsync(MainConst.MihomoConfPath, ExtraMihomoConfs);
Application.Current.Shutdown();
}
private void MainWin_DragEnter(object sender, DragEventArgs e)
{
e.Effects = e.Data.GetDataPresent(DataFormats.FileDrop) ? DragDropEffects.Link : DragDropEffects.None;
e.Handled = true;
}
private void MainWin_Drop(object sender, DragEventArgs e)
{
if (e.Data.GetDataPresent(DataFormats.FileDrop))
MainPres.BrowserPath = (e.Data.GetData(DataFormats.FileDrop) as string[])?[0] ?? string.Empty;
}
private void SettingsBox_TextChanged(object sender, TextChangedEventArgs e)
{
switch (MainPres.SettingsMode)
{
case MainConst.SettingsMode.BrowserPathMode:
MainPres.BrowserPath = SettingsBox.Text;
return;
case MainConst.SettingsMode.UpstreamUrlMode:
MainPres.UpstreamUrl = SettingsBox.Text;
return;
case MainConst.SettingsMode.ExtraArgsMode:
MainPres.ExtraArgs = SettingsBox.Text;
return;
}
}
private void SettingsModeButton_Click(object sender, RoutedEventArgs e)
{
MainPres.SettingsMode = MainPres.SettingsMode switch
{
MainConst.SettingsMode.BrowserPathMode => MainConst.SettingsMode.UpstreamUrlMode,
MainConst.SettingsMode.UpstreamUrlMode => MainConst.SettingsMode.ExtraArgsMode,
MainConst.SettingsMode.ExtraArgsMode => MainConst.SettingsMode.BrowserPathMode,
_ => throw new UnreachableException()
};
}
private void SettingsFunctionButton_Click(object sender, RoutedEventArgs e)
{
OpenFileDialog browserPathDialog = new() { Filter = $"{MainConst._BrowserPathDialogFilterFileType} (*.exe)|*.exe" };
switch (MainPres.SettingsMode)
{
case MainConst.SettingsMode.BrowserPathMode when browserPathDialog.ShowDialog().GetValueOrDefault():
SettingsBox.Focus();
MainPres.BrowserPath = browserPathDialog.FileName;
return;
case MainConst.SettingsMode.UpstreamUrlMode:
MainPres.UpstreamUrl = MainConst.DefaultUpstreamUrl;
return;
case MainConst.SettingsMode.ExtraArgsMode:
MainPres.ExtraArgs = string.Empty;
return;
}
}
private void LaunchButton_Click(object? sender, RoutedEventArgs e)
{
if (HoldButtonTimer is { IsEnabled: false })
return;
Button? senderButton = sender as Button;
if (senderButton == NginxButton)
NginxButtonHoldTimer_Tick(null, EventArgs.Empty);
else if (senderButton == MihomoButton)
MihomoButtonHoldTimer_Tick(null, EventArgs.Empty);
else
BrowserButtonHoldTimer_Tick(sender == null, EventArgs.Empty);
}
private void LaunchButton_PreviewMouseDown(object sender, MouseButtonEventArgs e)
{
Button senderButton = (Button)sender;
HoldButtonTimer = new() { Interval = TimeSpan.FromSeconds(1) };
HoldButtonTimer.Tick += senderButton == NginxButton ? NginxButtonHoldTimer_Tick : senderButton == MihomoButton ? MihomoButtonHoldTimer_Tick : BrowserButtonHoldTimer_Tick;
HoldButtonTimer.Start();
}
private async void BrowserButtonHoldTimer_Tick(object? sender, EventArgs e)
{
HoldButtonTimer?.Stop();
if ((CealHostRulesDict.ContainsValue(null) && MessageBox.Show(MainConst._CealHostErrorPrompt, string.Empty, MessageBoxButton.YesNo) != MessageBoxResult.Yes) ||
(sender is not true && MessageBox.Show(MainConst._KillBrowserProcessPrompt, string.Empty, MessageBoxButton.YesNo) != MessageBoxResult.Yes))
return;
foreach (Process browserProcess in Process.GetProcessesByName(Path.GetFileNameWithoutExtension(MainPres.BrowserPath)))
{
browserProcess.Kill();
await browserProcess.WaitForExitAsync();
}
await Task.Run(() =>
{
new BrowserProc(MainPres.BrowserPath, sender is bool).Run(Path.GetDirectoryName(MainPres.BrowserPath)!, $"{CealArgs} {MainPres.ExtraArgs.Trim()}");
});
}
private async void NginxButtonHoldTimer_Tick(object? sender, EventArgs e)
{
HoldButtonTimer?.Stop();
if (!MainPres.IsConginxRunning && !MainPres.IsNginxRunning)
{
try
{
if ((!MainPres.IsConginxExist && !MainPres.IsNginxExist) ||
(CealHostRulesDict.ContainsValue(null!) && MessageBox.Show(MainConst._CealHostErrorPrompt, string.Empty, MessageBoxButton.YesNo) != MessageBoxResult.Yes) ||
(NginxHttpsPort != 443 && MessageBox.Show(string.Format(MainConst._NginxHttpsPortOccupiedPrompt, NginxHttpsPort), string.Empty, MessageBoxButton.YesNo) != MessageBoxResult.Yes) ||
(NginxHttpPort != 80 && MessageBox.Show(string.Format(MainConst._NginxHttpPortOccupiedPrompt, NginxHttpPort), string.Empty, MessageBoxButton.YesNo) != MessageBoxResult.Yes) ||
(sender != null && MessageBox.Show(MainConst._LaunchHostsNginxPrompt, string.Empty, MessageBoxButton.YesNo) != MessageBoxResult.Yes) ||
(MessageBox.Show(MainConst._LaunchProxyPrompt, string.Empty, MessageBoxButton.YesNo) != MessageBoxResult.Yes) ||
(MainPres.IsFlashing && MessageBox.Show(MainConst._LaunchNginxFlashingPrompt, string.Empty, MessageBoxButton.YesNo) != MessageBoxResult.Yes))
return;
if (!File.Exists(MainConst.NginxConfPath))
await File.Create(MainConst.NginxConfPath).DisposeAsync();
if (!Directory.Exists(MainConst.NginxLogsPath))
Directory.CreateDirectory(MainConst.NginxLogsPath);
if (!Directory.Exists(MainConst.NginxTempPath))
Directory.CreateDirectory(MainConst.NginxTempPath);
if (sender == null)
File.Move(MainConst.NginxPath, MainConst.ConginxPath);
RSA certKey = RSA.Create(2048);
#region Root Cert
CertificateRequest rootCertRequest = new(MainConst.NginxRootCertSubjectName, certKey, HashAlgorithmName.SHA256, RSASignaturePadding.Pkcs1);
rootCertRequest.CertificateExtensions.Add(new X509BasicConstraintsExtension(true, false, 0, false));
using X509Certificate2 rootCert = rootCertRequest.CreateSelfSigned(DateTimeOffset.UtcNow, DateTimeOffset.UtcNow.AddYears(100));
using X509Store certStore = new(StoreName.Root, StoreLocation.LocalMachine, OpenFlags.ReadWrite);
certStore.Add(rootCert);
certStore.Close();
#endregion Root Cert
#region Child Cert & Hosts
CertificateRequest childCertRequest = new(MainConst.NginxChildCertSubjectName, certKey, HashAlgorithmName.SHA256, RSASignaturePadding.Pkcs1);
SubjectAlternativeNameBuilder childCertSanBuilder = new();
string hostsConfAppendContent = MainConst.HostsConfStartMarker;
foreach (List<(List<(string cealHostIncludeDomain, string cealHostExcludeDomain)> cealHostDomainPairs, string? cealHostSni, string cealHostIp)>? cealHostRules in CealHostRulesDict.Values)
foreach ((List<(string cealHostIncludeDomain, string cealHostExcludeDomain)> cealHostDomainPairs, _, _) in cealHostRules ?? [])
foreach ((string cealHostIncludeDomain, _) in cealHostDomainPairs)
{
string cealHostIncludeDomainWithoutWildcard = cealHostIncludeDomain.TrimStart('$').TrimStart('*').TrimStart('.');
if (cealHostIncludeDomain.StartsWith('#') || cealHostIncludeDomainWithoutWildcard.Contains('*') || string.IsNullOrWhiteSpace(cealHostIncludeDomainWithoutWildcard))
continue;
if (cealHostIncludeDomain.TrimStart('$').StartsWith('*'))
{
childCertSanBuilder.AddDnsName($"*.{cealHostIncludeDomainWithoutWildcard}");
if (sender != null)
hostsConfAppendContent += $"127.0.0.1 www.{cealHostIncludeDomainWithoutWildcard}{Environment.NewLine}";
if (cealHostIncludeDomain.TrimStart('$').StartsWith("*."))
continue;
}
childCertSanBuilder.AddDnsName(cealHostIncludeDomainWithoutWildcard);
if (sender != null)
hostsConfAppendContent += $"127.0.0.1 {cealHostIncludeDomainWithoutWildcard}{Environment.NewLine}";
}
childCertRequest.CertificateExtensions.Add(childCertSanBuilder.Build());
using X509Certificate2 childCert = childCertRequest.Create(rootCert, rootCert.NotBefore, rootCert.NotAfter, Guid.NewGuid().ToByteArray());
await File.WriteAllTextAsync(MainConst.NginxCertPath, childCert.ExportCertificatePem());
await File.WriteAllTextAsync(MainConst.NginxKeyPath, certKey.ExportPkcs8PrivateKeyPem());
if (sender != null)
{
hostsConfAppendContent += MainConst.HostsConfEndMarker;
File.SetAttributes(MainConst.HostsConfPath, File.GetAttributes(MainConst.HostsConfPath) & ~FileAttributes.ReadOnly);
await File.AppendAllTextAsync(MainConst.HostsConfPath, hostsConfAppendContent);
}
#endregion Child Cert & Hosts
try
{
if (sender == null)
MainPres.IsCoproxyIniting = true;
else
MainPres.IsNginxIniting = true;
NginxConfWatcher.EnableRaisingEvents = false;
NginxConfs!.Save(MainConst.NginxConfPath);
await Task.Run(() =>
{
if (sender == null)
new ConginxProc().Run(Path.GetDirectoryName(MainConst.ConginxPath)!, @$"-c ""{Path.GetRelativePath(Path.GetDirectoryName(MainConst.ConginxPath)!, MainConst.NginxConfPath)}""");
else
new NginxProc().Run(Path.GetDirectoryName(MainConst.NginxPath)!, @$"-c ""{Path.GetRelativePath(Path.GetDirectoryName(MainConst.NginxPath)!, MainConst.NginxConfPath)}""");
});
while (true)
{
try
{
await Http.GetAsync<HttpResponseMessage>($"https://localhost:{NginxHttpsPort}", MainClient);
break;
}
catch (HttpRequestException ex)
{
if (ex.InnerException is SocketException innerEx && innerEx.SocketErrorCode != SocketError.ConnectionRefused)
break;
}
if (sender == null ? MainPres.IsConginxRunning : MainPres.IsNginxRunning)
continue;
if (MessageBox.Show(MainConst._LaunchNginxErrorPrompt, string.Empty, MessageBoxButton.YesNo) == MessageBoxResult.Yes)
Process.Start(new ProcessStartInfo(MainConst.NginxErrorLogsPath) { UseShellExecute = true });
break;
}
if (sender == null)
MihomoButtonHoldTimer_Tick(null, EventArgs.Empty);
DnsFlusher.FlushDns();
}
finally
{
await File.WriteAllTextAsync(MainConst.NginxConfPath, ExtraNginxConfs);
NginxConfWatcher.EnableRaisingEvents = true;
if (sender != null)
MainPres.IsNginxIniting = false;
}
}
finally { IsNginxLaunchingSemaphore.Release(); }
}
else
{
bool isConginxRunning = MainPres.IsConginxRunning;
if (isConginxRunning)
MainPres.IsCoproxyStopping = true;
foreach (Process nginxProcess in Process.GetProcessesByName(Path.GetFileNameWithoutExtension(isConginxRunning ? MainConst.ConginxPath : MainConst.NginxPath)))
{
nginxProcess.Exited += async (_, _) =>
{
await NginxCleaner.Clean();
NginxConfWatcher_Changed(null!, null!);
};
nginxProcess.Kill();
}
if (isConginxRunning)
{
MainPres.IsConginxRunning = false;
File.Move(MainConst.ConginxPath, MainConst.NginxPath);
MihomoButtonHoldTimer_Tick(null, EventArgs.Empty);
}
else
MainPres.IsNginxRunning = false;
}
}
private async void MihomoButtonHoldTimer_Tick(object? sender, EventArgs e)
{
HoldButtonTimer?.Stop();
if (!MainPres.IsComihomoRunning && !MainPres.IsMihomoRunning)
{
if (!MainPres.IsComihomoExist && !MainPres.IsMihomoExist)
return;
if (string.IsNullOrWhiteSpace(MihomoConfs))
throw new(MainConst._MihomoConfErrorMsg);
if (!MainPres.IsConginxRunning && !MainPres.IsCoproxyStopping && MessageBox.Show(MainConst._LaunchProxyPrompt, string.Empty, MessageBoxButton.YesNo) != MessageBoxResult.Yes)
return;
if (!File.Exists(MainConst.MihomoConfPath))
await File.Create(MainConst.MihomoConfPath).DisposeAsync();
if (MainPres.IsConginxRunning)
if (MainPres.IsMihomoExist)
{
File.Move(MainConst.MihomoPath, MainConst.ComihomoPath);
MainPres.IsComihomoExist = true;
MainPres.IsMihomoExist = false;
}
else if (MainPres.IsComihomoExist)
{
File.Move(MainConst.ComihomoPath, MainConst.MihomoPath);
MainPres.IsComihomoExist = false;
MainPres.IsMihomoExist = true;
}
try
{
if (MainPres.IsComihomoExist)
MainPres.IsComihomoIniting = true;
else
MainPres.IsMihomoIniting = true;
MihomoConfWatcher.EnableRaisingEvents = false;
await File.WriteAllTextAsync(MainConst.MihomoConfPath, !MainPres.IsConginxRunning ? MihomoConfs :
MainPres.IsComihomoExist ? HostsComihomoConfs : ComihomoConfs);
await Task.Run(() =>
{
if (MainPres.IsComihomoExist)
{
new ComihomoProc().Run(Path.GetDirectoryName(MainConst.ComihomoPath)!, @$"-d ""{Path.GetDirectoryName(MainConst.MihomoConfPath)}""");
MainPres.IsComihomoRunning = true;
}
else
{
new MihomoProc().Run(Path.GetDirectoryName(MainConst.MihomoPath)!, @$"-d ""{Path.GetDirectoryName(MainConst.MihomoConfPath)}""");
MainPres.IsMihomoRunning = true;
}
});
while (true)
{
try
{
await Http.GetAsync<HttpResponseMessage>($"http://localhost:{MihomoMixedPort}", MainClient);
break;
}
catch (HttpRequestException ex)
{
if (ex.InnerException is SocketException innerEx && innerEx.SocketErrorCode != SocketError.ConnectionRefused)
break;
}
if (MainPres.IsComihomoExist ? MainPres.IsComihomoRunning : MainPres.IsMihomoRunning)
continue;
MessageBox.Show(MainConst._LaunchMihomoErrorMsg);
break;
}
}
finally
{
await File.WriteAllTextAsync(MainConst.MihomoConfPath, ExtraMihomoConfs);
MihomoConfWatcher.EnableRaisingEvents = true;
if (MainPres.IsCoproxyIniting)
MainPres.IsCoproxyIniting = false;
else if (MainPres.IsCoproxyStopping)
MainPres.IsCoproxyStopping = false;
if (MainPres.IsComihomoExist)
MainPres.IsComihomoIniting = false;
else
MainPres.IsMihomoIniting = false;
}
}
else
{
bool isComihomoRunning = MainPres.IsComihomoRunning;
foreach (Process mihomoProcess in Process.GetProcessesByName(Path.GetFileNameWithoutExtension(isComihomoRunning ? MainConst.ComihomoPath : MainConst.MihomoPath)))
{
mihomoProcess.Exited += (_, _) => MihomoConfWatcher_Changed(null!, null!);
mihomoProcess.Kill();
}
if (isComihomoRunning)
MainPres.IsComihomoRunning = false;
else
MainPres.IsMihomoRunning = false;
if (MainPres.IsConginxRunning)
{
if (MainPres.IsCoproxyIniting)
{
File.Move(MainConst.MihomoPath, MainConst.ComihomoPath);
MainPres.IsComihomoExist = true;
MainPres.IsMihomoExist = false;
}
MihomoButtonHoldTimer_Tick(null, EventArgs.Empty);
return;
}
if (MainPres.IsComihomoExist)
{
File.Move(MainConst.ComihomoPath, MainConst.MihomoPath);
MainPres.IsComihomoExist = false;
MainPres.IsMihomoExist = true;
MainPres.IsCoproxyStopping = false;
}
else if (MainPres.IsCoproxyStopping)
MihomoButtonHoldTimer_Tick(null, EventArgs.Empty);
}
}
private async void EditHostButton_Click(object sender, RoutedEventArgs e)
{
Button senderButton = (Button)sender;
string cealHostPath = senderButton == EditLocalHostButton ? MainConst.LocalHostPath : MainConst.UpstreamHostPath;
if (!File.Exists(cealHostPath))
await File.Create(cealHostPath).DisposeAsync();
try { Process.Start(new ProcessStartInfo(cealHostPath) { UseShellExecute = true }); }
catch (UnauthorizedAccessException) { Process.Start(new ProcessStartInfo(cealHostPath) { UseShellExecute = true, Verb = "RunAs" }); }
}
private async void EditConfButton_Click(object sender, RoutedEventArgs e)
{
Button senderButton = (Button)sender;
string confPath;
if (senderButton == EditHostsConfButton)
{
confPath = MainConst.HostsConfPath;
File.SetAttributes(MainConst.HostsConfPath, File.GetAttributes(MainConst.HostsConfPath) & ~FileAttributes.ReadOnly);
}
else
{
confPath = senderButton == EditNginxConfButton ? MainConst.NginxConfPath : MainConst.MihomoConfPath;
if (!File.Exists(confPath))
await File.Create(confPath).DisposeAsync();
}
Process.Start(new ProcessStartInfo(confPath) { UseShellExecute = true });
}
private async void UpdateUpstreamHostButton_Click(object? sender, RoutedEventArgs e)
{
try
{
if (!File.Exists(MainConst.UpstreamHostPath))
await File.Create(MainConst.UpstreamHostPath).DisposeAsync();
string upstreamUpstreamHostUrl = (MainPres.UpstreamUrl.StartsWith("http://") || MainPres.UpstreamUrl.StartsWith("https://") ? string.Empty : "https://") + MainPres.UpstreamUrl;
string upstreamUpstreamHostString = await Http.GetAsync<string>(upstreamUpstreamHostUrl, MainClient);
string localUpstreamHostString = await File.ReadAllTextAsync(MainConst.UpstreamHostPath);
try { upstreamUpstreamHostString = Encoding.UTF8.GetString(Convert.FromBase64String(upstreamUpstreamHostString)); }
catch { }
if (sender == null && (localUpstreamHostString != upstreamUpstreamHostString && localUpstreamHostString.ReplaceLineEndings() != upstreamUpstreamHostString.ReplaceLineEndings()))
MainPres.IsUpstreamHostUtd = false;
else if (sender != null)
if (localUpstreamHostString == upstreamUpstreamHostString || localUpstreamHostString.ReplaceLineEndings() == upstreamUpstreamHostString.ReplaceLineEndings())
{
MainPres.IsUpstreamHostUtd = true;
MessageBox.Show(MainConst._UpstreamHostUtdMsg);
}
else
{
MessageBoxResult overrideOptionResult = MessageBox.Show(MainConst._OverrideUpstreamHostPrompt, string.Empty, MessageBoxButton.YesNoCancel);
if (overrideOptionResult == MessageBoxResult.Yes)
{
await File.WriteAllTextAsync(MainConst.UpstreamHostPath, upstreamUpstreamHostString);
MainPres.IsUpstreamHostUtd = true;
MessageBox.Show(MainConst._UpdateUpstreamHostSuccessMsg);
}
else if (overrideOptionResult == MessageBoxResult.No)
try { Process.Start(new ProcessStartInfo(upstreamUpstreamHostUrl) { UseShellExecute = true }); }
catch (UnauthorizedAccessException) { Process.Start(new ProcessStartInfo(upstreamUpstreamHostUrl) { UseShellExecute = true, Verb = "RunAs" }); }
}
}
catch when (sender == null) { }
}
private void SettingsButton_Click(object sender, RoutedEventArgs e) => new SettingsWin().ShowDialog();
private async void NoClickButton_Click(object sender, RoutedEventArgs e)
{
if (GameFlashInterval <= 10)
{
MessageBox.Show(MainConst._GameReviewEndingMsg);
return;
}
switch (++GameClickTime)
{
case 1:
MessageBox.Show(MainConst._GameClickOnceMsg);
return;
case 2:
MessageBox.Show(MainConst._GameClickTwiceMsg);
return;
case 3:
MessageBox.Show(MainConst._GameClickThreeMsg);
return;
}
if (!MainPres.IsFlashing)
{
MessageBox.Show(MainConst._GameStartMsg);
MainPres.IsFlashing = true;
NginxConfWatcher_Changed(null!, null!);
Random random = new();
while (GameFlashInterval > 10)
{
Left = random.Next(0, (int)(SystemParameters.PrimaryScreenWidth - ActualWidth));
Top = random.Next(0, (int)(SystemParameters.PrimaryScreenHeight - ActualHeight));
PaletteHelper paletteHelper = new();
Theme newTheme = paletteHelper.GetTheme();
Color newPrimaryColor = Color.FromRgb((byte)random.Next(256), (byte)random.Next(256), (byte)random.Next(256));
bool isLightTheme = random.Next(2) == 0;
newTheme.SetPrimaryColor(newPrimaryColor);
newTheme.SetBaseTheme(isLightTheme ? BaseTheme.Light : BaseTheme.Dark);
paletteHelper.SetTheme(newTheme);
foreach (Window currentWindow in Application.Current.Windows)
BorderThemeSetter.SetBorderTheme(currentWindow, isLightTheme);
Style newButtonStyle = new(typeof(Button), Application.Current.Resources[typeof(Button)] as Style);
(Color? newForegroundColor, Color newAccentForegroundColor) = ForegroundGenerator.GetForeground(newPrimaryColor.R, newPrimaryColor.G, newPrimaryColor.B);
newButtonStyle.Setters.Add(new Setter(ForegroundProperty, newForegroundColor.HasValue ? new SolidColorBrush(newForegroundColor.Value) : new DynamicResourceExtension("MaterialDesignBackground")));
Application.Current.Resources[typeof(Button)] = newButtonStyle;
MainPres.AccentForegroundColor = newAccentForegroundColor;
if (GameFlashInterval > 100)
GameFlashInterval += random.Next(1, 4);
await Task.Delay(GameFlashInterval);
}
MainPres.IsFlashing = false;
NginxConfWatcher_Changed(null!, null!);
MessageBox.Show(MainConst._GameEndingMsg);
}
else
{
switch (GameFlashInterval)
{
case > 250:
GameFlashInterval -= 150;
break;
case > 100:
GameFlashInterval = 100;
break;
case > 10:
GameFlashInterval -= 30;
break;
}
if (GameFlashInterval > 10)
MessageBox.Show($"{MainConst._GameGradeMsg} {GameFlashInterval}");
}
}
private void AboutButton_Click(object sender, RoutedEventArgs e) => new AboutWin().ShowDialog();
private void ProxyTimer_Tick(object? sender, EventArgs e)
{
MainPres.IsConginxExist = File.Exists(Path.Combine(AppDomain.CurrentDomain.SetupInformation.ApplicationBase!, Path.GetFileName(MainConst.ConginxPath)));
MainPres.IsNginxExist = File.Exists(Path.Combine(AppDomain.CurrentDomain.SetupInformation.ApplicationBase!, Path.GetFileName(MainConst.NginxPath)));
MainPres.IsConginxRunning = Process.GetProcessesByName(Path.GetFileNameWithoutExtension(MainConst.ConginxPath)).Length != 0;
MainPres.IsNginxRunning = Process.GetProcessesByName(Path.GetFileNameWithoutExtension(MainConst.NginxPath)).Length != 0;
MainPres.IsComihomoExist = File.Exists(Path.Combine(AppDomain.CurrentDomain.SetupInformation.ApplicationBase!, Path.GetFileName(MainConst.ComihomoPath)));
MainPres.IsMihomoExist = File.Exists(Path.Combine(AppDomain.CurrentDomain.SetupInformation.ApplicationBase!, Path.GetFileName(MainConst.MihomoPath)));
MainPres.IsComihomoRunning = Process.GetProcessesByName(Path.GetFileNameWithoutExtension(MainConst.ComihomoPath)).Length != 0;
MainPres.IsMihomoRunning = Process.GetProcessesByName(Path.GetFileNameWithoutExtension(MainConst.MihomoPath)).Length != 0;
}
private async void CealHostWatcher_Changed(object sender, FileSystemEventArgs e)
{
string cealHostName = MainConst.CealHostPrefixRegex().Replace(Path.GetFileNameWithoutExtension(e.Name!), string.Empty);
try
{
CealHostRulesDict[cealHostName] = [];
await using FileStream cealHostStream = new(e.FullPath, FileMode.OpenOrCreate, FileAccess.Read, FileShare.ReadWrite | FileShare.Delete);
if (cealHostStream.Length == 0)
return;
JsonDocumentOptions cealHostOptions = new() { AllowTrailingCommas = true, CommentHandling = JsonCommentHandling.Skip };
JsonElement cealHostArray = JsonDocument.Parse(cealHostStream, cealHostOptions).RootElement;
foreach (JsonElement cealHostRule in cealHostArray.EnumerateArray())
{
List<(string cealHostIncludeDomain, string cealHostExcludeDomain)> cealHostDomainPairs = [];
string? cealHostSni = cealHostRule[1].ValueKind == JsonValueKind.Null ? null :
string.IsNullOrWhiteSpace(cealHostRule[1].ToString()) ? $"{cealHostName}{CealHostRulesDict[cealHostName]!.Count}" : cealHostRule[1].ToString().Trim();
string cealHostIp = string.IsNullOrWhiteSpace(cealHostRule[2].ToString()) ? "127.0.0.1" : cealHostRule[2].ToString().Trim();
foreach (JsonElement cealHostDomain in cealHostRule[0].EnumerateArray())
{
string[] cealHostDomainPair = cealHostDomain.ToString().Split('^', 2, StringSplitOptions.TrimEntries);
if (string.IsNullOrEmpty(cealHostDomainPair[0].TrimStart('#').TrimStart('$')))
continue;
cealHostDomainPairs.Add((cealHostDomainPair[0], cealHostDomainPair.Length == 2 ? cealHostDomainPair[1] : string.Empty));
}
if (cealHostDomainPairs.Count != 0)
CealHostRulesDict[cealHostName]!.Add((cealHostDomainPairs, cealHostSni, cealHostIp));
}
}
catch { CealHostRulesDict[cealHostName] = null; }
finally
{
string hostRules = string.Empty;
string hostResolverRules = string.Empty;
int nullSniNum = 0;
foreach (KeyValuePair<string, List<(List<(string cealHostIncludeDomain, string cealHostExcludeDomain)> cealHostDomainPairs, string? cealHostSni, string cealHostIp)>?> cealHostRulesPair in CealHostRulesDict)
foreach ((List<(string cealHostIncludeDomain, string cealHostExcludeDomain)> cealHostDomainPairs, string? cealHostSni, string cealHostIp) in cealHostRulesPair.Value ?? [])
{
string cealHostSniWithoutNull = cealHostSni ?? $"{cealHostRulesPair.Key}{(cealHostRulesPair.Value ?? []).Count + ++nullSniNum}";
bool isValidCealHostDomainExist = false;
foreach ((string cealHostIncludeDomain, string cealHostExcludeDomain) in cealHostDomainPairs)
{
if (cealHostIncludeDomain.StartsWith('$'))
continue;
hostRules += $"MAP {cealHostIncludeDomain.TrimStart('#')} {cealHostSniWithoutNull}," + (!string.IsNullOrWhiteSpace(cealHostExcludeDomain) ? $"EXCLUDE {cealHostExcludeDomain}," : string.Empty);
isValidCealHostDomainExist = true;
}
if (isValidCealHostDomainExist)
hostResolverRules += $"MAP {cealHostSniWithoutNull} {cealHostIp},";
}
CealArgs = @$"--host-rules=""{hostRules.TrimEnd(',')}"" --host-resolver-rules=""{hostResolverRules.TrimEnd(',')}"" --test-type --ignore-certificate-errors";
NginxConfWatcher_Changed(null!, null!);
MihomoConfWatcher_Changed(null!, null!);
}
}
private async void NginxConfWatcher_Changed(object sender, FileSystemEventArgs e)
{
if (!MainConst.IsAdmin || (!MainPres.IsNginxExist && !MainPres.IsConginxExist))
return;
if (!File.Exists(MainConst.NginxConfPath))
await File.Create(MainConst.NginxConfPath).DisposeAsync();
if (!Directory.Exists(MainConst.NginxLogsPath))
Directory.CreateDirectory(MainConst.NginxLogsPath);
if (!Directory.Exists(MainConst.NginxTempPath))
Directory.CreateDirectory(MainConst.NginxTempPath);
NginxHttpPort = 80;
NginxHttpsPort = 443;
foreach (IPEndPoint activeTcpListener in IPGlobalProperties.GetIPGlobalProperties().GetActiveTcpListeners())
if (activeTcpListener.Port == NginxHttpPort)
NginxHttpPort++;
else if (activeTcpListener.Port == NginxHttpsPort)
NginxHttpsPort++;
else if (activeTcpListener.Port > NginxHttpsPort)
break;
await using FileStream nginxConfStream = new(MainConst.NginxConfPath, FileMode.OpenOrCreate, FileAccess.Read, FileShare.ReadWrite | FileShare.Delete);
NginxConfig extraNginxConfig = NginxConfig.Load(ExtraNginxConfs = new StreamReader(nginxConfStream).ReadToEnd());
int serverIndex = 0;
foreach (IToken extraNginxConfigToken in extraNginxConfig.GetTokens())
if (extraNginxConfigToken is GroupToken extraNginxConfigGroupToken && extraNginxConfigGroupToken.Key.Equals("http", StringComparison.InvariantCultureIgnoreCase))
{
foreach (IToken serverToken in extraNginxConfigGroupToken.Tokens)
if (serverToken is GroupToken serverGroupToken && serverGroupToken.Key.Equals("server", StringComparison.InvariantCultureIgnoreCase))
++serverIndex;
break;
}
NginxConfs = extraNginxConfig
.AddOrUpdate("worker_processes", "auto")
.AddOrUpdate("events:worker_connections", "65536")
.AddOrUpdate("http:proxy_set_header", "Host $http_host")
.AddOrUpdate("http:proxy_ssl_server_name", !MainPres.IsFlashing ? "on" : "off")
.AddOrUpdate("http:proxy_buffer_size", "14k")
.AddOrUpdate($"http:server[{serverIndex}]:listen", $"{NginxHttpPort} default_server")
.AddOrUpdate($"http:server[{serverIndex}]:return", "https://$host$request_uri");
foreach (List<(List<(string cealHostIncludeDomain, string cealHostExcludeDomain)> cealHostDomainPairs, string? cealHostSni, string cealHostIp)>? cealHostRules in CealHostRulesDict.Values)
foreach ((List<(string cealHostIncludeDomain, string cealHostExcludeDomain)> cealHostDomainPairs, string? cealHostSni, string cealHostIp) in cealHostRules ?? [])
{
string serverName = "~";
foreach ((string cealHostIncludeDomain, string cealHostExcludeDomain) in cealHostDomainPairs)
{
if (cealHostIncludeDomain.StartsWith('#'))
continue;
serverName += "^" + (!string.IsNullOrWhiteSpace(cealHostExcludeDomain) ? $"(?!{cealHostExcludeDomain.Replace(".", "\\.").Replace("*", ".*")})" : string.Empty) +
cealHostIncludeDomain.TrimStart('$').Replace(".", "\\.").Replace("*", ".*") + "$|";
}
if (serverName == "~")
continue;
++serverIndex;
NginxConfs = NginxConfs
.AddOrUpdate($"http:server[{serverIndex}]:server_name", serverName.TrimEnd('|'))
.AddOrUpdate($"http:server[{serverIndex}]:listen", $"{NginxHttpsPort} ssl")
.AddOrUpdate($"http:server[{serverIndex}]:ssl_certificate", Path.GetFileName(MainConst.NginxCertPath))
.AddOrUpdate($"http:server[{serverIndex}]:ssl_certificate_key", Path.GetFileName(MainConst.NginxKeyPath))
.AddOrUpdate($"http:server[{serverIndex}]:location", "/", true)
.AddOrUpdate($"http:server[{serverIndex}]:location:proxy_pass", $"https://{cealHostIp}");
NginxConfs = cealHostSni == null ?
NginxConfs.AddOrUpdate($"http:server[{serverIndex}]:proxy_ssl_server_name", "off") :
NginxConfs.AddOrUpdate($"http:server[{serverIndex}]:proxy_ssl_name", cealHostSni);
}
}
private async void MihomoConfWatcher_Changed(object sender, FileSystemEventArgs e)
{
if (!MainConst.IsAdmin || (!MainPres.IsMihomoExist && !MainPres.IsComihomoExist))
return;
try
{
if (!File.Exists(MainConst.MihomoConfPath))
await File.Create(MainConst.MihomoConfPath).DisposeAsync();
MihomoMixedPort = 7880;
foreach (IPEndPoint activeTcpListener in IPGlobalProperties.GetIPGlobalProperties().GetActiveTcpListeners())
if (activeTcpListener.Port == MihomoMixedPort)
MihomoMixedPort++;
else if (activeTcpListener.Port > MihomoMixedPort)
break;
await using FileStream mihomoConfStream = new(MainConst.MihomoConfPath, FileMode.OpenOrCreate, FileAccess.Read, FileShare.ReadWrite | FileShare.Delete);
Dictionary<string, object> mihomoConfDict = new DeserializerBuilder()
.WithNamingConvention(HyphenatedNamingConvention.Instance)
.IgnoreUnmatchedProperties()
.Build()
.Deserialize<Dictionary<string, object>>(ExtraMihomoConfs = await new StreamReader(mihomoConfStream).ReadToEndAsync()) ?? [];
Dictionary<string, object> hostsMihomoConfDict = new DeserializerBuilder()
.WithNamingConvention(HyphenatedNamingConvention.Instance)
.IgnoreUnmatchedProperties()
.Build()
.Deserialize<Dictionary<string, object>>(ExtraMihomoConfs = await new StreamReader(mihomoConfStream).ReadToEndAsync()) ?? [];
mihomoConfDict["mixed-port"] = hostsMihomoConfDict["mixed-port"] = MihomoMixedPort;
mihomoConfDict["tun"] = hostsMihomoConfDict["tun"] = new
{
enable = true,
stack = "system",
autoRoute = true,
autoDetectInterface = true,
dnsHijack = new[] { "any:53", "tcp://any:53" }
};
mihomoConfDict["dns"] = new
{
enable = true,
listen = ":53",
ipv6 = true,
nameserver = MainConst.MihomoNameServers
};
hostsMihomoConfDict["dns"] = new
{
enable = true,
listen = ":53",
ipv6 = true
};
MihomoConfs = new SerializerBuilder().WithNamingConvention(HyphenatedNamingConvention.Instance).Build().Serialize(mihomoConfDict);
Dictionary<string, string> mihomoHostsDict = [];
foreach (List<(List<(string cealHostIncludeDomain, string cealHostExcludeDomain)> cealHostDomainPairs, string? cealHostSni, string cealHostIp)>? cealHostRules in CealHostRulesDict.Values)
foreach ((List<(string cealHostIncludeDomain, string cealHostExcludeDomain)> cealHostDomainPairs, _, _) in cealHostRules ?? [])
foreach ((string cealHostIncludeDomain, _) in cealHostDomainPairs)
{
string cealHostIncludeDomainWithoutWildcard = cealHostIncludeDomain.TrimStart('$').TrimStart('*').TrimStart('.');
if (cealHostIncludeDomain.StartsWith('#') || cealHostIncludeDomainWithoutWildcard.Contains('*') || string.IsNullOrWhiteSpace(cealHostIncludeDomainWithoutWildcard))
continue;
if (cealHostIncludeDomain.TrimStart('$').StartsWith('*'))
{
mihomoHostsDict.TryAdd($"*.{cealHostIncludeDomainWithoutWildcard}", "127.0.0.1");
if (cealHostIncludeDomain.TrimStart('$').StartsWith("*."))
continue;
}
mihomoHostsDict.TryAdd(cealHostIncludeDomainWithoutWildcard, "127.0.0.1");
}
mihomoConfDict["hosts"] = hostsMihomoConfDict["hosts"] = mihomoHostsDict;
ComihomoConfs = new SerializerBuilder().WithNamingConvention(HyphenatedNamingConvention.Instance).Build().Serialize(mihomoConfDict);
HostsComihomoConfs = new SerializerBuilder().WithNamingConvention(HyphenatedNamingConvention.Instance).Build().Serialize(hostsMihomoConfDict);
}
catch { ComihomoConfs = HostsComihomoConfs = MihomoConfs = string.Empty; }
}
private void MainWin_KeyDown(object sender, KeyEventArgs e)
{
if (e.KeyboardDevice.Modifiers != ModifierKeys.Control)
return;
if (e.Key == Key.W)
Application.Current.Shutdown();
else if (e.Key == Key.H)
{
System.Windows.Forms.NotifyIcon notifyIcon = new() { Icon = System.Drawing.Icon.ExtractAssociatedIcon(Assembly.GetExecutingAssembly().Location), Text = MainConst.NotifyIconText, Visible = true };
notifyIcon.Click += (_, _) =>
{
Show();
notifyIcon.Dispose();
};
Hide();
}
}
}

41
Wins/SettingsWin.xaml Normal file
View File

@ -0,0 +1,41 @@
<Window x:Class="Sheas_Cealer.Wins.SettingsWin"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:consts="clr-namespace:Sheas_Cealer.Consts"
xmlns:convs="clr-namespace:Sheas_Cealer.Convs"
xmlns:preses="clr-namespace:Sheas_Cealer.Preses"
mc:Ignorable="d"
WindowStartupLocation="CenterScreen" ResizeMode="NoResize" SizeToContent="Height" Width="500"
d:DataContext="{d:DesignInstance preses:SettingsPres}"
Style="{DynamicResource CommonWindow}"
SourceInitialized="SettingsWin_SourceInitialized" KeyDown="SettingsWin_KeyDown">
<Grid Margin="5">
<Grid.RowDefinitions>
<RowDefinition Height="*" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<Button Grid.Row="0" Grid.Column="0" Margin="5" d:Content="# # # #"
Content="{Binding IsLightTheme, Converter={x:Static convs:SettingsConv.SettingsThemesButtonContentConv}}"
ToolTip="{x:Static consts:SettingsConst.ThemesButtonToolTip}"
Click="ThemesButton_Click" />
<Button Grid.Row="0" Grid.Column="1" Margin="5" d:Content="# # # #"
Content="{Binding IsEnglishLang, Converter={x:Static convs:SettingsConv.SettingsLangsButtonContentConv}}"
ToolTip="{x:Static consts:SettingsConst.LangsButtonToolTip}"
Click="LangsButton_Click" />
<Button Grid.Row="1" Grid.Column="0" Margin="5"
Content="{x:Static consts:SettingsConst.ColorsButtonContent}"
ToolTip="{x:Static consts:SettingsConst.ColorsButtonToolTip}"
Click="ColorsButton_Click" />
<Button Grid.Row="1" Grid.Column="1" Margin="5" d:Content="# # # #"
Content="{Binding IsLightWeight, Converter={x:Static convs:SettingsConv.SettingsWeightsButtonContentConv}}"
ToolTip="{x:Static consts:SettingsConst.WeightsButtonToolTip}"
Click="WeightsButton_Click" />
</Grid>
</Window>

65
Wins/SettingsWin.xaml.cs Normal file
View File

@ -0,0 +1,65 @@
using MaterialDesignThemes.Wpf;
using Sheas_Cealer.Consts;
using Sheas_Cealer.Preses;
using Sheas_Cealer.Props;
using Sheas_Cealer.Utils;
using System;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;
using System.Windows.Media;
namespace Sheas_Cealer.Wins;
public partial class SettingsWin : Window
{
private readonly SettingsPres SettingsPres;
internal SettingsWin()
{
InitializeComponent();
DataContext = SettingsPres = new();
}
private void SettingsWin_SourceInitialized(object sender, EventArgs e)
{
IconRemover.RemoveIcon(this);
BorderThemeSetter.SetBorderTheme(this, SettingsPres.IsLightTheme);
}
private void ThemesButton_Click(object sender, RoutedEventArgs e) => SettingsPres.IsLightTheme = SettingsPres.IsLightTheme.HasValue ? SettingsPres.IsLightTheme.Value ? null : true : false;
private void LangsButton_Click(object sender, RoutedEventArgs e)
{
SettingsPres.IsEnglishLang = SettingsPres.IsEnglishLang.HasValue ? SettingsPres.IsEnglishLang.Value ? null : true : false;
MessageBox.Show(SettingsConst._ChangeLangSuccessMsg);
}
private void ColorsButton_Click(object sender, RoutedEventArgs e)
{
Random random = new();
PaletteHelper paletteHelper = new();
Theme newTheme = paletteHelper.GetTheme();
Color newPrimaryColor = Color.FromRgb((byte)random.Next(256), (byte)random.Next(256), (byte)random.Next(256));
newTheme.SetPrimaryColor(newPrimaryColor);
paletteHelper.SetTheme(newTheme);
Style newButtonStyle = new(typeof(Button), Application.Current.Resources[typeof(Button)] as Style);
(Color? newForegroundColor, Color newAccentForegroundColor) = ForegroundGenerator.GetForeground(newPrimaryColor.R, newPrimaryColor.G, newPrimaryColor.B);
newButtonStyle.Setters.Add(new Setter(ForegroundProperty, newForegroundColor.HasValue ? new SolidColorBrush(newForegroundColor.Value) : new DynamicResourceExtension("MaterialDesignBackground")));
Application.Current.Resources[typeof(Button)] = newButtonStyle;
SettingsPres.AccentForegroundColor = newAccentForegroundColor;
Settings.Default.PrimaryColor = System.Drawing.Color.FromArgb(newPrimaryColor.A, newPrimaryColor.R, newPrimaryColor.G, newPrimaryColor.B);
Settings.Default.Save();
}
private void WeightsButton_Click(object sender, RoutedEventArgs e) => SettingsPres.IsLightWeight = SettingsPres.IsLightWeight.HasValue ? SettingsPres.IsLightWeight.Value ? null : true : false;
private void SettingsWin_KeyDown(object sender, KeyEventArgs e)
{
if (e.Key == Key.Escape)
Close();
}
}