Compare commits

..

334 Commits
1.7.3 ... 1.7.9

Author SHA1 Message Date
DismissedLight
7d5faadbb5 1.7.9 hotfix package 2023-10-12 22:03:24 +08:00
DismissedLight
b7df968ea7 fix #1008 2023-10-12 21:33:35 +08:00
DismissedLight
5f6cc46774 Merge pull request #1009 from DGP-Studio/develop 2023-10-12 21:04:39 +08:00
Lightczx
a34b5a5101 style 2023-10-12 16:58:29 +08:00
Lightczx
457e3c4af2 LoadImageSurfaceAsync fix 2023-10-12 16:45:59 +08:00
Lightczx
26143079b3 app resource moved 2023-10-12 15:59:42 +08:00
DismissedLight
20ad9aec60 fix 1.7.7 log upload issue 2023-10-11 22:28:10 +08:00
DismissedLight
61dd098d95 fix #1003 2023-10-11 22:12:07 +08:00
DismissedLight
e7233fbf2a fix #1007 2023-10-11 20:50:21 +08:00
DismissedLight
8de526274a fix #1005 2023-10-10 22:28:53 +08:00
DismissedLight
5b1fb6e1dd move resources 2023-10-10 22:27:53 +08:00
DismissedLight
1584fd1428 fix mutiple display window init size incorrectness 2023-10-10 20:23:39 +08:00
Masterain
65179a340f Update README.md 2023-10-09 04:02:38 -07:00
DismissedLight
9f984b4a9b 1.7.7 package 2023-10-08 22:59:36 +08:00
DismissedLight
8a36bfb62c Merge pull request #978 from DGP-Studio/l10n_develop 2023-10-08 22:34:22 +08:00
DismissedLight
c9c8f6a5cf Merge pull request #998 from DGP-Studio/develop 2023-10-08 22:28:58 +08:00
DismissedLight
f9e1ef7ab5 fix #990 2023-10-08 22:26:40 +08:00
DismissedLight
be06a91e0f code style 2023-10-08 22:08:17 +08:00
DismissedLight
174757f94d adjust nullability annotation 2023-10-08 21:51:24 +08:00
Lightczx
1cd3ec0cdb experiment 2023-10-08 17:30:35 +08:00
Lightczx
7b17bb5a01 reset window size 2023-10-08 14:15:27 +08:00
Masterain
c3bab3c677 New translations sh.resx (Japanese) 2023-10-07 15:35:50 -07:00
DismissedLight
17f1c873ae shadow complete 2023-10-07 23:49:23 +08:00
Lightczx
313a17b7eb code style 2023-10-07 11:25:06 +08:00
Lightczx
9ad321e10d fix ci build 2023-10-07 11:15:49 +08:00
Masterain
f18dfc0baf New translations sh.resx (Japanese) 2023-10-06 15:28:34 -07:00
DismissedLight
16946c58fe fix minor request bug 2023-10-06 21:48:10 +08:00
DismissedLight
c7b931956c import reqrest 2023-10-06 21:33:09 +08:00
Masterain
6c0c5b4669 New translations sh.resx (English) 2023-10-05 15:28:01 -07:00
Masterain
0342805293 New translations sh.resx (Chinese Traditional) 2023-10-05 15:28:00 -07:00
Masterain
e0b1896336 New translations sh.resx (Korean) 2023-10-05 15:27:59 -07:00
Masterain
6d1958af4c New translations sh.resx (Japanese) 2023-10-05 15:27:58 -07:00
DismissedLight
42ab2c3000 Merge pull request #989 from Xhichn/develop 2023-10-05 12:29:01 +08:00
Xhichn
d0fb00dccd Impl GetInfoAsync 2023-10-05 10:39:00 +08:00
DismissedLight
5bc484db78 signIn improvement 2023-10-05 10:02:25 +08:00
DismissedLight
c665834f77 Merge pull request #988 from DGP-Studio/main 2023-10-05 09:41:00 +08:00
DismissedLight
81d73568a7 Merge pull request #965 from Xhichn/DailyReward 2023-10-05 09:37:54 +08:00
DismissedLight
c940ec7006 dailynote & spiralabyss adjust 2023-10-05 09:32:17 +08:00
Masterain
71e5e6f190 New translations sh.resx (English) 2023-10-04 15:21:20 -07:00
Masterain
3983eaec0f New translations sh.resx (Chinese Traditional) 2023-10-04 15:21:19 -07:00
Masterain
9392911547 New translations sh.resx (Korean) 2023-10-04 15:21:18 -07:00
Masterain
f3d1fda053 New translations sh.resx (Japanese) 2023-10-04 15:21:16 -07:00
DismissedLight
14c3a14c2d impl #902 2023-10-04 23:15:32 +08:00
DismissedLight
31568ffba9 correct naming 2023-10-04 22:20:44 +08:00
DismissedLight
3d3d004441 rename signin interface 2023-10-04 22:20:06 +08:00
Masterain
a40e5f2a80 Update Qodana configuration 2023-10-03 14:47:34 -07:00
Masterain
186da74704 Merge pull request #985 from Masterain98/main
Create CONTRIBUTING.md
2023-10-03 03:53:59 -07:00
Masterain
c532799eb1 Update Qodana configuration 2023-10-03 03:34:54 -07:00
Masterain
595e19a1df Update CONTRIBUTING.md 2023-10-03 03:24:59 -07:00
Masterain
c376c4e0e8 Create CONTRIBUTING.md
resolve #909
2023-10-03 02:46:18 -07:00
DismissedLight
07f0c37b2c attempt to fix desktop icon creation 2023-10-03 17:39:30 +08:00
DismissedLight
ecdaeccc42 view style 2023-10-03 15:14:44 +08:00
Masterain
64bbcdfc80 New translations sh.resx (English) 2023-10-02 20:29:13 -07:00
Masterain
59fccf0cba New translations sh.resx (Chinese Traditional) 2023-10-02 20:29:12 -07:00
Masterain
f860211632 New translations sh.resx (Korean) 2023-10-02 20:29:11 -07:00
Masterain
a15a8cfe2d New translations sh.resx (Japanese) 2023-10-02 20:29:10 -07:00
DismissedLight
38bed7318f fix #982 2023-10-02 15:42:56 +08:00
DismissedLight
e513b8b00b add string 2023-10-02 13:24:51 +08:00
DismissedLight
1e711172af fix #980 2023-10-02 13:23:45 +08:00
Masterain
8beb47fd2c New translations sh.resx (English) 2023-10-01 20:29:31 -07:00
DismissedLight
41ab80511e separate win32 to increate analyzer response speed 2023-10-01 16:25:39 +08:00
DismissedLight
318b6190d2 fix game convert config not save 2023-10-01 11:29:23 +08:00
Masterain
6e3dbd41c7 New translations sh.resx (English) 2023-09-30 20:10:41 -07:00
Masterain
911f667e98 New translations sh.resx (Chinese Traditional) 2023-09-30 20:10:40 -07:00
Masterain
db6537bbe4 New translations sh.resx (Korean) 2023-09-30 20:10:39 -07:00
Masterain
6b640b5e15 New translations sh.resx (Japanese) 2023-09-30 20:10:38 -07:00
DismissedLight
bfe9837b36 fix several issues 2023-10-01 11:08:24 +08:00
Xhichn
b8255e77a3 Typo fix 2023-09-28 11:42:48 +08:00
DismissedLight
500888c2d1 launch scheme fix 2023-09-27 23:54:05 +08:00
Xhichn
5141d4a567 HoYolab Daily Reward Support 2023-09-27 18:51:41 +08:00
Lightczx
a86f5e1b59 add more compatonly scheme 2023-09-27 17:20:27 +08:00
Lightczx
390b89fc82 fix multiple channel/subchannel crash & setting clear invalid cache path crash 2023-09-27 17:12:32 +08:00
DismissedLight
6d6d97c59a fix mihoyo login no login_ticket crash 2023-09-26 23:40:30 +08:00
DismissedLight
df23fe54d6 fix manual input gacha url no auth_appid crash 2023-09-26 23:31:55 +08:00
DismissedLight
8caef9af0c MultiChannel: [ChannelType:Bili] [SubChannel:Official] [IsOversea: False] 2023-09-26 23:28:58 +08:00
DismissedLight
aac0e268b0 fix hoyoverse login crash 2023-09-26 23:23:02 +08:00
DismissedLight
bafee4ba18 fix detect game account crash 2023-09-26 22:26:01 +08:00
DismissedLight
4a1dccd7ac update intrinsics 2023-09-26 21:49:18 +08:00
Lightczx
1f8e73f255 disable concurrent launch game 2023-09-26 14:16:03 +08:00
DismissedLight
53c1a0156d 1.7.6 package 2023-09-25 22:46:14 +08:00
DismissedLight
165b77aa80 Merge pull request #959 from DGP-Studio/develop 2023-09-25 22:32:54 +08:00
DismissedLight
47cd9807b2 Merge pull request #949 from DGP-Studio/l10n_develop 2023-09-25 22:31:29 +08:00
DismissedLight
cbaf1ef5ae Merge pull request #958 from DGP-Studio/develop 2023-09-25 22:30:36 +08:00
DismissedLight
c2d3bd1798 fix GI 4.1 metadata ccrash on spiralabyss & improve wiki avatar ui 2023-09-25 22:20:14 +08:00
Masterain
bfa5325a09 Create Qodana profile 2023-09-24 17:27:23 -07:00
DismissedLight
43aebf7d0c fix #956 2023-09-24 17:54:08 +08:00
DismissedLight
ffcfb8cd65 fix #948 2023-09-23 21:17:15 +08:00
DismissedLight
7d9612cf13 fix #865 2023-09-23 21:02:11 +08:00
DismissedLight
4fb997c8d0 fix non-elevated auto click 2023-09-23 15:11:08 +08:00
DismissedLight
6029acc7f1 mouse simulator 2023-09-23 14:55:47 +08:00
Lightczx
ef352303e7 remove statichutao 2023-09-22 17:31:00 +08:00
Lightczx
b5579aef6e static resouce download refactor and ui/ux improvement 2023-09-22 16:47:08 +08:00
Masterain
9c20e06387 New translations sh.resx (English) 2023-09-21 17:19:17 -07:00
Masterain
323e9fbcff New translations sh.resx (Chinese Traditional) 2023-09-21 17:19:16 -07:00
Masterain
10d947aa61 New translations sh.resx (Korean) 2023-09-21 17:19:15 -07:00
Masterain
c18581fc34 New translations sh.resx (Japanese) 2023-09-21 17:19:13 -07:00
DismissedLight
b72b5ddf91 refactor window controller 2023-09-21 22:45:40 +08:00
DismissedLight
2821f7f2af refine announcement color matching 2023-09-21 20:57:44 +08:00
Lightczx
427275d122 ui/ux 2023-09-21 17:30:42 +08:00
Lightczx
22393b612c fix #947 2023-09-21 15:03:11 +08:00
Masterain
ffc380f96d Update issue templates 2023-09-20 22:15:18 -07:00
DismissedLight
2a757dce51 UI/UX fine tuning 2023-09-20 23:50:24 +08:00
Masterain
0921671de4 Merge pull request #945 from DGP-Studio/develop
Update README.md
2023-09-19 23:31:47 -07:00
Masterain
5a99488582 Update README.md
Test purpose
2023-09-19 23:31:01 -07:00
Lightczx
a14c41d10f 1.7.5 package 2023-09-20 13:51:24 +08:00
DismissedLight
ce8aee2cb1 Merge pull request #944 from DGP-Studio/develop 2023-09-20 13:36:31 +08:00
DismissedLight
f9ffd84429 Merge pull request #943 from DGP-Studio/l10n_develop 2023-09-20 13:34:41 +08:00
Masterain
6e69064140 New translations sh.resx (English) 2023-09-19 22:34:22 -07:00
Masterain
ff315a3b58 New translations sh.resx (English) 2023-09-19 21:33:56 -07:00
Masterain
aaf28132a4 New translations sh.resx (Chinese Traditional) 2023-09-19 21:33:55 -07:00
Masterain
5730c82f84 New translations sh.resx (Korean) 2023-09-19 21:33:54 -07:00
Masterain
a71fd42d6a New translations sh.resx (Japanese) 2023-09-19 21:33:53 -07:00
Lightczx
3f818fce50 typo fix 2023-09-20 12:26:03 +08:00
Lightczx
301ead44a2 fix CI build 2023-09-20 11:38:54 +08:00
Masterain
ff79e81ff4 New translations sh.resx (English) 2023-09-19 20:33:18 -07:00
Masterain
d9e942319c New translations sh.resx (Chinese Traditional) 2023-09-19 20:33:17 -07:00
Masterain
4787798825 New translations sh.resx (Korean) 2023-09-19 20:33:16 -07:00
Masterain
fb398dbf21 New translations sh.resx (Japanese) 2023-09-19 20:33:15 -07:00
Lightczx
68a6834d39 fix #930 2023-09-20 11:28:34 +08:00
Lightczx
4285abd531 fix avatar template 2023-09-20 09:29:47 +08:00
Masterain
8b5f017bea Merge pull request #935 from DGP-Studio/l10n_develop
New Crowdin updates
2023-09-19 14:28:54 -07:00
Masterain
add9318a8e New translations sh.resx (English) 2023-09-19 13:53:06 -07:00
Masterain
997fcb0e51 New translations sh.resx (English) 2023-09-19 08:49:52 -07:00
Masterain
bd0832ca98 New translations sh.resx (Chinese Traditional) 2023-09-19 08:49:51 -07:00
Masterain
4545017a3b New translations sh.resx (Korean) 2023-09-19 08:49:50 -07:00
Masterain
d28cd36162 New translations sh.resx (Japanese) 2023-09-19 08:49:48 -07:00
DismissedLight
cf8a9581d6 spiral abyss rework done 2023-09-19 23:43:25 +08:00
Masterain
b5d12f5f5f New translations sh.resx (English) 2023-09-19 03:17:39 -07:00
Masterain
7ddf51ef91 New translations sh.resx (Chinese Traditional) 2023-09-19 03:17:38 -07:00
Masterain
c2c529f399 New translations sh.resx (Korean) 2023-09-19 03:17:35 -07:00
Masterain
63028170b8 New translations sh.resx (Japanese) 2023-09-19 03:17:34 -07:00
Lightczx
156740de14 spiral abyss rework 4 2023-09-19 17:14:17 +08:00
Masterain
db82cd70ee New translations sh.resx (Japanese) 2023-09-19 00:59:17 -07:00
Masterain
d04f6a9218 New translations sh.resx (Japanese) 2023-09-18 23:22:05 -07:00
DismissedLight
f2365604dc spiral abyss rework 3 2023-09-18 23:48:33 +08:00
Lightczx
f569f24213 ui/ux adjust 2023-09-18 16:25:58 +08:00
DismissedLight
ca468365ab Merge pull request #938 from DGP-Studio/dependabot/nuget/src/Snap.Hutao/develop/packages-8af96ff2ab 2023-09-18 15:40:37 +08:00
Lightczx
5fa8cc37e8 fix #880 2023-09-18 15:38:23 +08:00
dependabot[bot]
ab78f68df1 Bump the packages group in /src/Snap.Hutao with 2 updates
Bumps the packages group in /src/Snap.Hutao with 2 updates: [Microsoft.EntityFrameworkCore.Sqlite](https://github.com/dotnet/efcore) and [Microsoft.EntityFrameworkCore.Tools](https://github.com/dotnet/efcore).


Updates `Microsoft.EntityFrameworkCore.Sqlite` from 7.0.10 to 7.0.11
- [Release notes](https://github.com/dotnet/efcore/releases)
- [Commits](https://github.com/dotnet/efcore/compare/v7.0.10...v7.0.11)

Updates `Microsoft.EntityFrameworkCore.Tools` from 7.0.10 to 7.0.11
- [Release notes](https://github.com/dotnet/efcore/releases)
- [Commits](https://github.com/dotnet/efcore/compare/v7.0.10...v7.0.11)

---
updated-dependencies:
- dependency-name: Microsoft.EntityFrameworkCore.Sqlite
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: packages
- dependency-name: Microsoft.EntityFrameworkCore.Tools
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: packages
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-09-18 07:31:14 +00:00
Masterain
62fdd89943 New translations SH.resx (Chinese Traditional) 2023-09-18 00:05:37 -07:00
Masterain
7fa19dd830 New translations SH.resx (Chinese Traditional) 2023-09-17 22:48:26 -07:00
Masterain
f4100f1c20 New translations SH.resx (English) 2023-09-17 21:26:43 -07:00
Lightczx
7f595a6981 fix spiral abyss record refresh 2023-09-18 11:44:36 +08:00
Masterain
60f2020b6c New translations SH.resx (English) 2023-09-17 20:21:13 -07:00
Masterain
d21d59efe1 New translations SH.resx (Chinese Traditional) 2023-09-17 20:21:12 -07:00
Masterain
c14847b330 New translations SH.resx (Korean) 2023-09-17 20:21:10 -07:00
Masterain
86481b747d New translations SH.resx (Japanese) 2023-09-17 20:21:09 -07:00
Lightczx
2765a2e744 impl #875 2023-09-18 11:19:25 +08:00
Lightczx
261794927c impl #929 2023-09-18 10:02:58 +08:00
DismissedLight
68d8baa70c spiral abyss rework 2 2023-09-17 23:33:40 +08:00
Masterain
5e44dade7f New translations SH.resx (English) 2023-09-17 04:14:15 -07:00
Masterain
529eafc4e7 New translations SH.resx (Chinese Traditional) 2023-09-17 04:14:14 -07:00
Masterain
be3fa7054c New translations SH.resx (Korean) 2023-09-17 04:14:13 -07:00
Masterain
01cf457386 New translations SH.resx (Japanese) 2023-09-17 04:14:12 -07:00
DismissedLight
fb496497bf fix date format 2023-09-17 17:54:02 +08:00
Masterain
68a6af9341 Merge pull request #923 from DGP-Studio/l10n_develop
New Crowdin updates
2023-09-17 02:15:02 -07:00
Masterain
1ec5b2fa5e New translations SH.resx (English) 2023-09-17 02:08:04 -07:00
Masterain
aad57b67a6 New translations SH.resx (Chinese Traditional) 2023-09-17 01:06:47 -07:00
Masterain
9262217271 New translations SH.resx (Korean) 2023-09-17 01:06:46 -07:00
Masterain
b09e8b6bdc New translations SH.resx (Japanese) 2023-09-17 01:06:45 -07:00
Masterain
7c51a8ea6b New translations SH.resx (English) 2023-09-17 01:06:44 -07:00
DismissedLight
3db52e8184 spiral abyss rework 2023-09-17 16:05:10 +08:00
Masterain
9e660a7ae7 New translations SH.resx (Chinese Traditional) 2023-09-16 07:08:03 -07:00
Masterain
4127a1daa3 New translations SH.resx (Korean) 2023-09-16 07:08:02 -07:00
Masterain
4e07af8395 New translations SH.resx (Japanese) 2023-09-16 07:08:01 -07:00
Masterain
02707c3075 New translations SH.resx (English) 2023-09-16 07:08:00 -07:00
DismissedLight
98ca533706 add tower wave spec 2023-09-16 21:56:28 +08:00
DismissedLight
808b643b9f drop CommunityToolkit.WinUI.UI.Core 2023-09-16 19:28:34 +08:00
Masterain
d9705b94d4 New translations SH.resx (English) 2023-09-15 20:46:17 -07:00
Masterain
511471d06c New translations SH.resx (Japanese) 2023-09-15 03:10:43 -07:00
Lightczx
3b79d89f59 attempt to fix dailynote view verify 2023-09-15 17:27:28 +08:00
Masterain
fc1546e17f New translations SH.resx (Chinese Traditional) 2023-09-15 00:52:35 -07:00
Masterain
b816b0103d New translations SH.resx (Korean) 2023-09-15 00:52:34 -07:00
Masterain
51570038bc New translations SH.resx (Japanese) 2023-09-15 00:52:33 -07:00
Masterain
0b5b911709 New translations SH.resx (English) 2023-09-15 00:52:32 -07:00
Lightczx
1a22303dec impl #876 2023-09-15 15:47:07 +08:00
Masterain
51a2fe7d88 New translations SH.resx (Japanese) 2023-09-14 23:36:21 -07:00
Masterain
90c6c8ebc7 New translations SH.resx (Japanese) 2023-09-14 19:51:16 -07:00
Masterain
ed1d6240bf New translations SH.resx (Japanese) 2023-09-14 18:45:48 -07:00
Masterain
adf01172e0 New translations SH.resx (Japanese) 2023-09-14 01:09:32 -07:00
Masterain
2caf1145c9 New translations SH.resx (Japanese) 2023-09-14 00:10:43 -07:00
Masterain
33b2725a95 New translations SH.resx (Japanese) 2023-09-13 22:48:15 -07:00
Masterain
0103834e82 New translations SH.resx (Japanese) 2023-09-13 21:41:03 -07:00
Masterain
8273cd973d New translations SH.resx (Japanese) 2023-09-13 19:47:49 -07:00
DismissedLight
53c484c577 fix achievement check status save 2023-09-13 21:26:58 +08:00
DismissedLight
706f894ea5 fix #924 2023-09-13 20:56:07 +08:00
Masterain
7f31010041 New translations SH.resx (Japanese) 2023-09-13 02:17:10 -07:00
Masterain
70a17f325e New translations SH.resx (Chinese Traditional) 2023-09-13 00:30:06 -07:00
Masterain
a4d450a98e New translations SH.resx (Japanese) 2023-09-13 00:30:04 -07:00
Masterain
cce08ff728 New translations SH.resx (Chinese Traditional) 2023-09-12 07:27:55 -07:00
Masterain
669713389a New translations SH.resx (Korean) 2023-09-12 07:27:54 -07:00
Masterain
be82bc5d82 New translations SH.resx (Japanese) 2023-09-12 07:27:53 -07:00
Masterain
aa01154301 New translations SH.resx (English) 2023-09-12 07:27:51 -07:00
DismissedLight
2ff8d6d7f4 achievement versioning 2023-09-12 22:14:40 +08:00
Masterain
79f62bdbd2 New translations SH.resx (Japanese) 2023-09-12 01:30:52 -07:00
Lightczx
92c010f660 auto generate key annotations 2023-09-12 16:29:53 +08:00
Lightczx
18433814e8 salts auto generated 2023-09-12 16:11:31 +08:00
Lightczx
79c8cc78c6 Merge branch 'main' into develop 2023-09-12 15:05:23 +08:00
Lightczx
f6ec0f5d7e 1.7.4 package 2023-09-12 15:03:14 +08:00
Masterain
6e20c15c97 New translations SH.resx (Japanese) 2023-09-12 00:00:28 -07:00
Masterain
7e73710103 New translations SH.resx (English) 2023-09-12 14:50:41 +08:00
Masterain
4ba9f32ac3 New translations SH.resx (English) 2023-09-12 14:50:41 +08:00
Masterain
6cb2818161 New translations SH.resx (Chinese Traditional) 2023-09-12 14:50:41 +08:00
Masterain
34d291001b New translations SH.resx (Korean) 2023-09-12 14:50:40 +08:00
Masterain
157f64fb47 New translations SH.resx (Japanese) 2023-09-12 14:50:40 +08:00
Masterain
6b9479d27e New translations SH.resx (English) 2023-09-12 14:50:40 +08:00
Masterain
ea6cbb8d6b New translations SH.resx (English) 2023-09-12 14:50:40 +08:00
Masterain
9f94f36cf8 New translations SH.resx (English) 2023-09-12 14:50:40 +08:00
Masterain
c50dd0737c New translations SH.resx (Chinese Traditional) 2023-09-12 14:50:40 +08:00
Masterain
6f63ed55d7 New translations SH.resx (Korean) 2023-09-12 14:50:40 +08:00
Masterain
4cc16153c2 New translations SH.resx (Japanese) 2023-09-12 14:50:40 +08:00
Masterain
a214dd331a New translations SH.resx (English) 2023-09-12 14:50:40 +08:00
Masterain
e6c83390eb New translations SH.resx (Japanese) 2023-09-12 14:50:40 +08:00
Masterain
aa21e3e5e9 New translations SH.resx (Japanese) 2023-09-12 14:50:40 +08:00
Masterain
58c992e278 New translations SH.resx (Japanese) 2023-09-12 14:50:40 +08:00
Masterain
bd19bfdd52 New translations SH.resx (Japanese) 2023-09-12 14:50:40 +08:00
Masterain
7a9c1a7b3c New translations SH.resx (Japanese) 2023-09-12 14:50:40 +08:00
Masterain
c5a24ae0d7 New translations SH.resx (Chinese Traditional) 2023-09-12 14:50:40 +08:00
Masterain
6ee2899692 New translations SH.resx (English) 2023-09-12 14:50:40 +08:00
Masterain
9b3ea4496a New translations SH.resx (Chinese Traditional) 2023-09-12 14:50:40 +08:00
Masterain
96ac468a24 New translations SH.resx (Korean) 2023-09-12 14:50:40 +08:00
Masterain
0a26297446 New translations SH.resx (Japanese) 2023-09-12 14:50:40 +08:00
Masterain
de2cafd9e5 New translations SH.resx (English) 2023-09-12 14:50:40 +08:00
Masterain
3f8674ad9a New translations SH.resx (Chinese Traditional) 2023-09-12 14:50:40 +08:00
Masterain
8e1ea87993 New translations SH.resx (Korean) 2023-09-12 14:50:40 +08:00
Masterain
cdbe013310 New translations SH.resx (Japanese) 2023-09-12 14:50:40 +08:00
Masterain
a972ba0035 New translations SH.resx (English) 2023-09-12 14:50:40 +08:00
Masterain
a285dbb9b9 New translations SH.resx (Japanese) 2023-09-12 14:50:40 +08:00
Masterain
39182ce44c New translations SH.resx (English) 2023-09-12 14:50:40 +08:00
Masterain
95ad0ca574 New translations SH.resx (Chinese Traditional) 2023-09-12 14:50:40 +08:00
Masterain
3ec905f5ca New translations SH.resx (Korean) 2023-09-12 14:50:40 +08:00
Masterain
4306461ba9 New translations SH.resx (Japanese) 2023-09-12 14:50:40 +08:00
Masterain
133e767be3 New translations SH.resx (English) 2023-09-12 14:50:40 +08:00
Masterain
949cf59177 New translations SH.resx (Chinese Traditional) 2023-09-12 14:50:40 +08:00
Masterain
42e693ba8a New translations SH.resx (Korean) 2023-09-12 14:50:40 +08:00
Masterain
09d00f25f6 New translations SH.resx (Japanese) 2023-09-12 14:50:39 +08:00
Masterain
4f9828f358 New translations SH.resx (English) 2023-09-12 14:50:39 +08:00
Masterain
4f7cf08285 New translations SH.resx (Chinese Traditional) 2023-09-12 14:50:39 +08:00
Masterain
46a36a4d17 New translations SH.resx (Chinese Traditional) 2023-09-12 14:50:39 +08:00
Masterain
ef1c31732c New translations SH.resx (Korean) 2023-09-12 14:50:39 +08:00
Masterain
26a392e376 New translations SH.resx (Japanese) 2023-09-12 14:50:39 +08:00
Masterain
2731abc815 New translations SH.resx (English) 2023-09-12 14:50:39 +08:00
Masterain
c8fb7fe82a New translations SH.resx (English) 2023-09-12 14:50:39 +08:00
Masterain
d4f6cf8e02 New translations SH.resx (Chinese Traditional) 2023-09-12 14:50:39 +08:00
Masterain
a3c4965932 New translations SH.resx (Korean) 2023-09-12 14:50:39 +08:00
Masterain
e30a010931 New translations SH.resx (Japanese) 2023-09-12 14:50:39 +08:00
Masterain
8af117ea11 New translations SH.resx (English) 2023-09-12 14:50:39 +08:00
Lightczx
5f6d279dba Update SignInClient.cs 2023-09-12 14:50:39 +08:00
Lightczx
aed1171933 fix signin challenge source 2023-09-12 14:50:39 +08:00
DismissedLight
dbc81f0a93 UIIF definition 2023-09-12 14:50:39 +08:00
DismissedLight
1c7b926d76 drop AdaptiveGridView 2023-09-12 14:50:39 +08:00
Lightczx
ab2d38b142 overwrite icon when creating shortcut 2023-09-12 14:50:39 +08:00
DismissedLight
87f7e22022 fix cultivate project selection on other page 2023-09-12 14:50:39 +08:00
DismissedLight
7af57118bc improve db layer & homecard experience 2023-09-12 14:50:39 +08:00
DismissedLight
5d03f5d0b5 fix #917 2023-09-12 14:50:39 +08:00
DismissedLight
84f629c113 batch add for avatarinfo cultivation 2023-09-12 14:50:39 +08:00
DismissedLight
ecd535f9a0 boost up gacha statistics view speed 2x 2023-09-12 14:50:39 +08:00
Lightczx
d3ea7cf8ac fix bilibili server convert 2023-09-12 14:50:39 +08:00
DismissedLight
12afac8d1a fix #907 2023-09-12 14:50:39 +08:00
DismissedLight
5763f56ab2 fix #887 2023-09-12 14:50:39 +08:00
DismissedLight
a8b679acbf fix #904 2023-09-12 14:50:39 +08:00
Lightczx
25987ba5b3 add ability to create desktop shortcut 2023-09-12 14:50:39 +08:00
Lightczx
b0626a0d60 Add ability to switch powershell instance 2023-09-12 14:50:39 +08:00
Lightczx
fd16521c94 update metadata models 2023-09-12 14:50:38 +08:00
DismissedLight
eb077cc8d6 fix banner typo 2023-09-12 14:50:38 +08:00
DismissedLight
8b3a311fc2 Merge pull request #885 from DGP-Studio/l10n_develop 2023-09-12 14:49:31 +08:00
Lightczx
01e2e21979 Update SignInClient.cs 2023-09-12 14:46:34 +08:00
Lightczx
38b5e4f244 fix signin challenge source 2023-09-12 09:21:28 +08:00
DismissedLight
5fae9f6291 UIIF definition 2023-09-11 23:09:49 +08:00
DismissedLight
f23b1c012f drop AdaptiveGridView 2023-09-11 22:33:44 +08:00
DismissedLight
28813444bf Merge pull request #921 from Masterain98/main 2023-09-11 11:16:44 +08:00
Masterain
c24cca58bf Update issue templates 2023-09-10 20:11:53 -07:00
Masterain
16fb1772ab New translations SH.resx (English) 2023-09-10 18:15:23 -07:00
Lightczx
52353b7a5a overwrite icon when creating shortcut 2023-09-11 09:05:03 +08:00
Masterain
8c63a38249 New translations SH.resx (English) 2023-09-10 03:48:09 -07:00
DismissedLight
91d90cb3fa fix cultivate project selection on other page 2023-09-10 18:23:59 +08:00
Masterain
583717d601 New translations SH.resx (Chinese Traditional) 2023-09-10 02:45:01 -07:00
Masterain
dd34815b13 New translations SH.resx (Korean) 2023-09-10 02:45:00 -07:00
Masterain
8f18a89727 New translations SH.resx (Japanese) 2023-09-10 02:44:59 -07:00
Masterain
759689e2c9 New translations SH.resx (English) 2023-09-10 02:44:58 -07:00
DismissedLight
396da901a1 improve db layer & homecard experience 2023-09-10 17:38:18 +08:00
DismissedLight
f2c38bc72a fix #917 2023-09-10 12:51:14 +08:00
Masterain
b5ddc20d5f New translations SH.resx (English) 2023-09-09 15:49:58 -07:00
Masterain
f5af6e7b1a New translations SH.resx (English) 2023-09-09 14:50:21 -07:00
Masterain
772668a266 New translations SH.resx (Chinese Traditional) 2023-09-09 02:26:46 -07:00
Masterain
c342efe4be New translations SH.resx (Korean) 2023-09-09 02:26:45 -07:00
Masterain
9ff322cceb New translations SH.resx (Japanese) 2023-09-09 02:26:44 -07:00
Masterain
d2e8e6dac3 New translations SH.resx (English) 2023-09-09 02:26:43 -07:00
DismissedLight
1cbf3b548f batch add for avatarinfo cultivation 2023-09-09 17:22:38 +08:00
DismissedLight
ffd7468913 boost up gacha statistics view speed 2x 2023-09-08 20:53:06 +08:00
Masterain
1029175071 New translations SH.resx (Japanese) 2023-09-08 03:47:11 -07:00
Lightczx
b5f3cb92b2 fix bilibili server convert 2023-09-08 17:14:50 +08:00
Masterain
8d8a2af063 New translations SH.resx (Japanese) 2023-09-08 01:36:03 -07:00
Masterain
43bee2bd3e New translations SH.resx (Japanese) 2023-09-08 00:17:39 -07:00
Masterain
abce4571ea New translations SH.resx (Japanese) 2023-09-07 20:17:05 -07:00
Masterain
904335cfc9 New translations SH.resx (Japanese) 2023-09-07 19:13:07 -07:00
Masterain
e9a821e4af New translations SH.resx (Chinese Traditional) 2023-09-07 10:16:45 -07:00
Masterain
8f2d2773e1 New translations SH.resx (English) 2023-09-07 10:16:44 -07:00
Masterain
4352ba64f8 New translations SH.resx (Chinese Traditional) 2023-09-07 08:27:58 -07:00
Masterain
670c4366c4 New translations SH.resx (Korean) 2023-09-07 08:27:57 -07:00
Masterain
46c6a973c6 New translations SH.resx (Japanese) 2023-09-07 08:27:55 -07:00
Masterain
455505f0cb New translations SH.resx (English) 2023-09-07 08:27:54 -07:00
DismissedLight
8e625e19ee fix #907 2023-09-07 23:06:09 +08:00
DismissedLight
1fefcacd9a fix #887 2023-09-07 22:21:22 +08:00
Masterain
2b585964f7 New translations SH.resx (Chinese Traditional) 2023-09-07 06:58:43 -07:00
Masterain
6e541dfeb5 New translations SH.resx (Korean) 2023-09-07 06:58:42 -07:00
Masterain
2c9af48cb2 New translations SH.resx (Japanese) 2023-09-07 06:58:41 -07:00
Masterain
d384915c9d New translations SH.resx (English) 2023-09-07 06:58:40 -07:00
DismissedLight
1d923f4b24 fix #904 2023-09-07 21:51:18 +08:00
Masterain
0997532564 New translations SH.resx (Japanese) 2023-09-07 03:15:05 -07:00
Masterain
dd9053a11c New translations SH.resx (English) 2023-09-07 03:15:04 -07:00
Masterain
a8bf268fce New translations SH.resx (Chinese Traditional) 2023-09-07 02:19:29 -07:00
Masterain
44d1dd50e6 New translations SH.resx (Korean) 2023-09-07 02:19:27 -07:00
Masterain
14e98a43f6 New translations SH.resx (Japanese) 2023-09-07 02:19:26 -07:00
Masterain
69239674e6 New translations SH.resx (English) 2023-09-07 02:19:25 -07:00
Lightczx
4e972f35dd add ability to create desktop shortcut 2023-09-07 17:01:41 +08:00
Masterain
7187b913b0 New translations SH.resx (Chinese Traditional) 2023-09-07 00:04:11 -07:00
Masterain
4904ab1335 New translations SH.resx (Korean) 2023-09-07 00:04:09 -07:00
Masterain
d572bc5753 New translations SH.resx (Japanese) 2023-09-07 00:04:08 -07:00
Masterain
950c4568ee New translations SH.resx (English) 2023-09-07 00:04:07 -07:00
Lightczx
a7bf82d7e7 Add ability to switch powershell instance 2023-09-07 14:41:16 +08:00
Lightczx
42035803c1 update metadata models 2023-09-07 13:33:52 +08:00
DismissedLight
3161964bcf fix banner typo 2023-09-05 21:39:07 +08:00
DismissedLight
4da0258f7b update banner image 2023-09-05 21:24:20 +08:00
Masterain
4b2d6cc27c New translations SH.resx (Chinese Traditional) 2023-09-04 05:55:59 -07:00
Masterain
44068c4446 New translations SH.resx (Chinese Traditional) 2023-09-04 02:18:58 -07:00
Masterain
21399b3781 New translations SH.resx (Korean) 2023-09-04 02:18:57 -07:00
Masterain
dcea46edf4 New translations SH.resx (Japanese) 2023-09-04 02:18:56 -07:00
Masterain
825cc58955 New translations SH.resx (English) 2023-09-04 02:18:54 -07:00
Masterain
743cb9683b New translations SH.resx (English) 2023-09-02 07:04:24 -07:00
Masterain
2420916509 New translations SH.resx (Chinese Traditional) 2023-09-02 05:33:33 -07:00
Masterain
479b4086c2 New translations SH.resx (Korean) 2023-09-02 05:33:31 -07:00
Masterain
0626cc0a49 New translations SH.resx (Japanese) 2023-09-02 05:33:30 -07:00
Masterain
93040e6ff8 New translations SH.resx (English) 2023-09-02 05:33:29 -07:00
438 changed files with 13408 additions and 7296 deletions

View File

@@ -0,0 +1,107 @@
name: BUG Report [English Form]
description: Tell us what issue you get
title: "[ENG][Bug]: Place your Issue Title Here"
labels: ["BUG"]
body:
- type: markdown
attributes:
value: |
> **Please use one sentence to briefly describe your issue as title above**
> Please follow the instruction below to fill the form, so we can locate the issue quickly
- type: checkboxes
id: checklist
attributes:
label: Checklist
description: |-
Please complete the checklist, otherwise your issue may be ignored
options:
- label: I have read [FAQ page](https://hut.ao/advanced/FAQ.html) and [Exception page](https://hut.ao/advanced/exceptions.html) in Snap Hutao document, and my issue is not answered
required: true
- label: I and tried **search feature** in Snap Hutao document site, and no associated article
required: true
- label: My issue is not a [fixed issue](https://github.com/DGP-Studio/Snap.Hutao/issues?q=is%3Aopen+is%3Aissue+label%3A%E5%B7%B2%E4%BF%AE%E5%A4%8D), and it's not a duplicated issue
required: true
- type: input
id: winver
attributes:
label: Windows Version
description: |
Use `Win+R` and input `winver`, Windows build version is usually at the second line
placeholder: e.g. 22000.556
validations:
required: true
- type: input
id: shver
attributes:
label: Snap Hutao Version
description: You can find the version in application's title bar
placeholder: e.g. 1.4.15.0
validations:
required: true
- type: input
id: deviceid
attributes:
label: Device ID
description: |
In Snap Hutao's settings page, you can find and copy your device ID
If your issue is about program crash, please fill this so we can dump the log and locate the source easier
validations:
required: false
- type: dropdown
id: user-set-category
attributes:
label: Issue Category
description: Please select the most associated category of your issue
options:
- Installation and Environment
- Achievement
- My Character
- Game Launcher
- Realtime Note
- Develop Plan
- File Cache
- Wish Export
- Game Record
- Hutao Database
- User Interface
- Snap Hutao Cloud
- Snap Hutao Account
- Checkin
- Wiki
- Announcement
- Other
validations:
required: true
- type: textarea
id: what-happened
attributes:
label: What Happened?
description: Describe your issue in detail to help us identify the issue. **If your issue is about program crash, you should check Windows Event Viewer, and attach associated `.Net Error` details here**
validations:
required: true
- type: textarea
id: what-expected
attributes:
label: What is expected?
description: Describe expected outcome, highlight the difference with current outcome
validations:
required: false
- type: checkboxes
id: checklist-final
attributes:
label: Last Step
description: Review your Form
options:
- label: I believe the description above is detail enough to allow developers to reproduce the issue
required: true

View File

@@ -1,11 +1,12 @@
name: 问题反馈
description: 告诉我们你的问题
title: "[Bug]: 在这里填写一个合适的标题"
labels: ["BUG"]
body:
- type: markdown
attributes:
value: |
> **请在上方设置一个合适的工单标题**
> **请在上方以一句话简短地概括你的问题作为标题**
> 请按下方的要求填写完整的问题表单,以便我们更快的定位问题。
- type: checkboxes
@@ -15,15 +16,14 @@ body:
description: |-
请确保你已完整执行检查清单,否则你的 Issue 可能会被忽略
options:
- label: 并未完整阅读[胡桃工具箱文档](https://hut.ao/advanced/FAQ.html)
- label: 已阅读 Snap Hutao 文档中的[常见问题](https://hut.ao/advanced/FAQ.html)和[常见程序异常](https://hut.ao/advanced/exceptions.html),我的问题没有在文档中得到解答
required: true
- label: 知道文档站的导航栏中有**搜索功能**也没有搜索过相关关键词
- label: 我知道文档站的导航栏中有**搜索功能**且已经搜索过相关关键词
required: true
- label: 使用的操作系统是不[受支持的版本](https://hut.ao/quick-start.html#%E6%9C%80%E4%BD%8E%E7%B3%BB%E7%BB%9F%E8%A6%81%E6%B1%82)
- label: 我没有**通过搜索功能**确认其他人提出过相同或类似的问题
- label: 我不明白上述的勾选项是**一个有助于快速排查问题的检查清单**,而是随手确认的选项
- label: 的问题不是[已修复](https://github.com/DGP-Studio/Snap.Hutao/issues?q=is%3Aopen+is%3Aissue+label%3A%E5%B7%B2%E4%BF%AE%E5%A4%8D)的问题也不是一个别人已发布的**重复的**问题
required: true
- type: input
id: winver
@@ -31,7 +31,7 @@ body:
label: Windows 版本
description: |
`Win+R` 输入 `winver` 回车后在打开的窗口第二行可以找到
placeholder: 22621.1105
placeholder: 22000.556
validations:
required: true
@@ -65,13 +65,14 @@ body:
- 角色信息面板
- 游戏启动器
- 实时便笺
- 养成计算
- 用户面板
- 养成计算
- 文件缓存
- 祈愿记录
- 玩家查询
- 胡桃数据库
- 用户界面
- 胡桃云
- 胡桃帐号
- 签到
- Wiki
- 公告
@@ -83,7 +84,7 @@ body:
id: what-happened
attributes:
label: 发生了什么?
description: 详细的描述问题发生前后的行为,以便我们解决问题
description: 详细的描述问题发生前后的行为,以便我们解决问题。**如果你的问题涉及程序崩溃,你应当检查 Windows 事件查看器,并将相关的 `.Net 错误`详情附上**
validations:
required: true
@@ -94,4 +95,13 @@ body:
description: 详细的描述你期望发生的行为,突出与目前(可能不正确的)行为的不同
validations:
required: false
- type: checkboxes
id: checklist-final
attributes:
label: 最后一步
description: 回顾你的回答
options:
- label: 我认为上述的描述已经足以详细,以允许开发人员能复现该问题
required: true

View File

@@ -1,5 +1,14 @@
blank_issues_enabled: false
contact_links:
- name: 胡桃工具箱 - 官方文档
- name: Snap Hutao 官方文档 / Snap Hutao Document
url: https://hut.ao
about: 请在提出问题前阅读文档
about: 请在提出问题前阅读文档 / Read the document before submit the issue
- name: 常见问题 / FAQ
url: https://hut.ao/advanced/FAQ.html
about: 常见的用户提出的问题 / Common questions asked by users
- name: 常见程序异常 / Common Program Exceptions
url: https://hut.ao/advanced/exceptions.html
about: 用户通常能自行解决这些问题 / Users may solve these problems by themselves

View File

@@ -1,6 +1,6 @@
name: 功能请求
description: 告诉我们你的想法
title: "[Feat]: 在这里填写一个合适的标题"
name: Feature Request 功能请求
description: Tell us about your thought 告诉我们你的想法
title: "[Feat]: Place your title here 在这里填写一个合适的标题"
labels: ["功能"]
assignees:
- Lightczx
@@ -8,20 +8,21 @@ body:
- type: markdown
attributes:
value: |
Please fill the form below
请按下方的要求填写完整的问题表单。
- type: textarea
id: back
attributes:
label: 背景与动机
description: 添加此功能的理由,如果你想要实现多个功能,请分别发起多个单独的 Issue
label: Background & Motivation 背景与动机
description: Reason why this feature is needed. If multiple features is requested, please open multiple issues for each of them. 添加此功能的理由,如果你想要实现多个功能,请分别发起多个单独的 Issue
validations:
required: true
- type: textarea
id: req
attributes:
label: 想要实现或优化的功能
description: 详细的描述一下你想要的功能,描述的越具体,采纳的可能性越高
label: Detail of the Feature 想要实现或优化的功能
description: Descripbe the feaure in detail. The more detailed and convincing the desciprtion the more likyly feature will be accepted. 详细的描述一下你想要的功能,描述的越具体,采纳的可能性越高
validations:
required: true

View File

@@ -0,0 +1,26 @@
name: Qodana
on:
workflow_dispatch:
pull_request:
push:
branches:
- main
- develop
paths-ignore:
- '**.md'
- '**.yml'
- '**.resx'
jobs:
qodana:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
with:
fetch-depth: 0
- name: 'Qodana Scan'
uses: JetBrains/qodana-action@v2023.2
with:
pr-mode: false
env:
QODANA_TOKEN: ${{ secrets.QODANA_TOKEN }}

5
.gitignore vendored
View File

@@ -12,9 +12,8 @@ src/Snap.Hutao/Snap.Hutao/bin/
src/Snap.Hutao/Snap.Hutao/obj/
src/Snap.Hutao/Snap.Hutao/Snap.Hutao_TemporaryKey.pfx
src/Snap.Hutao/Snap.Hutao.Installer/bin/
src/Snap.Hutao/Snap.Hutao.Installer/obj/
src/Snap.Hutao/Snap.Hutao.Installer/Properties/PublishProfiles/FolderProfile.pubxml.user
src/Snap.Hutao/Snap.Hutao.Win32/bin/
src/Snap.Hutao/Snap.Hutao.Win32/obj/
src/Snap.Hutao/Snap.Hutao.SourceGeneration/bin/
src/Snap.Hutao/Snap.Hutao.SourceGeneration/obj/

72
CONTRIBUTING.md Normal file
View File

@@ -0,0 +1,72 @@
# Contribution Guide
## Contribute Your Code
### Setup Snap.Hutao Project
1. Download and install [Visual Studio 2022 Community](https://visualstudio.microsoft.com/downloads/)
2. Open Visual Studio Installer to complete Visual Studio installation
- You need to install `.NET desktop development`, `Desktop development with C++` and `Universal Windows Platform development` components
3. Install `Single-project MSIX Packaging Tools for VS 2022` provided by Microsoft in Visual Studio marketplace
4. Use git to clone the project `https://github.com/DGP-Studio/Snap.Hutao.git` to your local device
5. Switch git branch to `develop`
6. Open project solution with your Visual Studio and then you are ready to go
### Start Pull Request
- All code-related changes from authors' own branches are only allowed be merged to `develop` branch
- Please use [keywords](https://docs.github.com/en/get-started/writing-on-github/working-with-advanced-formatting/using-keywords-in-issues-and-pull-requests) to link your PR or commits with issues, so issues can be automatically closed once commits are merged into `main` branch.
### Test Binary Package
Once the code in updated in `develop` and `main` branches, an Azure Pipeline CI script will build the latest code to `Snap Hutao Alpha` package. Once the package is built, it will be released on [GitHub Release page](https://github.com/DGP-Studio/Snap.Hutao/releases) as a pre-released package.
You need to install [Snap.Hutao.CI.cer](https://github.com/DGP-Studio/Snap.Hutao/releases/download/2023.10.3.1/Snap.Hutao.CI.cer) certificate to your local machine, and then install the msix package in the release.
*If the latest release does not contains attached file, that means package is still in uploading process.
## Start New Issue
To help users solve problems faster and increase developers' efficiency in solving problems, Snap Hutao provides detailed documentation to explain common problems and issue templates to guide users to report program problems by submitting issues.
Before submitting a new issue, you should check the following pages:
- [FAQ](https://hut.ao/advanced/FAQ.html) Document
- [Common Program Exceptions ](https://hut.ao/en/advanced/exceptions.html)Document
- [Current Opened BUG Report Issues](https://github.com/DGP-Studio/Snap.Hutao/issues?q=is%3Aissue+is%3Aopen+label%3ABUG)
When starting a new issue, please use the issue templates:
- Describe your issue in details to help developers to reproduce the issue
- Your description of reproduction should be a step-by-step story
- If your issue is about program crash
- Remember to provide your Device ID
- Check Windows Event Viewer, and attach associated `.NET Error` details in the issue body
## Document Modification
Snap Hutao Document site is stored in repository [DGP-Studio/Snap.Hutao.Docs](https://github.com/DGP-Studio/Snap.Hutao.Docs), you can process the following steps to test the site in your local device:
1. Download and install [NodeJS 18](https://nodejs.org/en/download/)
2. Clone the repository
3. Run `npm install` in the root directory of the document project
4. Run `npm run docs:dev` to start test on 8080 port
### Localization
Snap.Hutao.Docs project structure is designed as multiple languages site. Each language has its independent folder under `docs` directory.
**If you wish to add another language document, you can [start an issue in document repository](https://github.com/DGP-Studio/Snap.Hutao.Docs/issues) to ask developer to setup an environment for you, or you can process the following steps by yourself:**
1. make a copy of `zh` folder, rename the new folder as the new language's code
2. Start your translation work in the new language folder
3. In `docs/.vuepress/sidebar` folder, duplicate `zh.ts` file
1. Rename the file to `{language_code}.ts`
2. In the line 4, change `/zh/` to `/{language_code}/`
3. Translate all `text` field
4. In `docs/.vuepress/navbar` folder, duplicate `zh.ts` file
1. Rename the file to `{language_code}.ts`
2. Replace all `/zh/` to `/{language_code}/`
3. Translate all `text` field
5. In `docs/.vuepress/config.ts`file, add your language information in `locales` and `plugins/docsearchPlugin/locales` dictionary
6. In `docs/.vuepress/theme.ts`file, add your language information in `locales` dictionary

View File

@@ -1,8 +1,8 @@
![](https://repository-images.githubusercontent.com/482734649/c47a0a8e-868d-4d07-a66f-6d4473abfe46)
![](res/HutaoRepoBanner2.png)
胡桃工具箱是一个 Windows 平台的开源的原神工具箱,旨在帮助玩家获得更好的游戏体验; 它是对官方移动端工具的一种非破坏性功能扩展,为不习惯在移动端进行原神游戏的 PC 玩家提供一个在 Windows 平台下获得接近移动端功能权利的途径
胡桃工具箱是一款以 MIT 协议开源的原神工具箱,专为现代化 Windows 平台设计,旨在改善桌面端玩家的游戏体验。通过将既有的官方资源与开发团队设计的全新 功能相结合,它提供了一套完整且实用的工具集,且无需依赖任何移动设备。它不对游戏客户端进行任何破坏性修改以确保工具箱的安全性
Snap Hutao is an open-source Genshin Impact toolbox on Windows platform, aim to provide a better gaming experience for players. It's an nondestructive feature extension from Genshin Impact's official mobile application, to provide similar feature on desktop, to allow PC gamers gain deserved benefits from mobile platforms.
Snap Hutao is an open-source Genshin Impact toolkit under MIT license, designed for modern Windows platform to improve the gaming experience for desktop players. By combining existing official resources with new features designed by the development team, it provides a complete and useful set of tools without the need to rely on mobile devices. Snap Hutao does not take any destructive modification to the game client to ensure the security of the toolkit.
## 下载使用 / Download
@@ -11,7 +11,7 @@ Snap Hutao is an open-source Genshin Impact toolbox on Windows platform, aim to
## 贡献 / Contribute
* [向我们提交 PR / Make Pull Requests](https://github.com/DGP-Studio/Snap.Hutao/pulls)
* [在 Crowdin 上进行本地化 / Translate project on Crowdin](https://translate.hut.ao/)
* [在 Crowdin 上进行本地化 / Translate Project on Crowdin](https://translate.hut.ao/)
* [为我们更新文档 / Enhance our Document ](https://github.com/DGP-Studio/Snap.Hutao.Docs)
## 特别感谢 / Special Thanks
@@ -19,7 +19,7 @@ Snap Hutao is an open-source Genshin Impact toolbox on Windows platform, aim to
* [HolographicHat](https://github.com/HolographicHat)
* [UIGF organization](https://uigf.org)
### 特定的原神项目 / Specific Genshin-related Project
### 特定的原神项目 / Specific Genshin-related Projects
* [biuuu/genshin-wish-export](https://github.com/biuuu/genshin-wish-export)
* [xunkong/xunkong](https://github.com/xunkong/xunkong)
@@ -47,4 +47,4 @@ Snap Hutao is an open-source Genshin Impact toolbox on Windows platform, aim to
## 开发 / Development
![Snap.Hutao](https://repobeats.axiom.co/api/embed/f029553fbe0c60689b1710476ec8512452163fc9.svg)
![Branch Rule](res/branch.png)
[![Star History Chart](https://api.star-history.com/svg?repos=DGP-Studio/Snap.Hutao&type=Date)](https://star-history.com/#DGP-Studio/Snap.Hutao&Date)

33
qodana.yaml Normal file
View File

@@ -0,0 +1,33 @@
#-------------------------------------------------------------------------------#
# Qodana analysis is configured by qodana.yaml file #
# https://www.jetbrains.com/help/qodana/qodana-yaml.html #
#-------------------------------------------------------------------------------#
version: "1.0"
#Specify inspection profile for code analysis
profile:
name: qodana.starter
#Enable inspections
#include:
# - name: <SomeEnabledInspectionId>
#Disable inspections
exclude:
- name: Test
paths:
- Snap.Hutao.Test
- Snap.Hutao.SourceGeneration
- name: All
paths:
- Snap.Hutao.SourceGeneration
- Snap.Hutao.Test
#Execute shell command before Qodana execution (Applied in CI/CD pipeline)
#bootstrap: sh ./prepare-qodana.sh
#Install IDE plugins before Qodana execution (Applied in CI/CD pipeline)
#plugins:
# - id: <plugin.id> #(plugin id can be found at https://plugins.jetbrains.com)
#Specify Qodana linter for analysis (Applied in CI/CD pipeline)
linter: jetbrains/qodana-dotnet:2023.2-eap

BIN
res/HutaoRepoBanner2.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 661 KiB

BIN
res/HutaoRepoBanner2.psd Normal file

Binary file not shown.

Binary file not shown.

Before

Width:  |  Height:  |  Size: 52 KiB

View File

@@ -0,0 +1,147 @@
// Copyright (c) DGP Studio. All rights reserved.
// Licensed under the MIT license.
using Microsoft.CodeAnalysis;
namespace Snap.Hutao.SourceGeneration.Automation;
[Generator(LanguageNames.CSharp)]
internal sealed class AttributeGenerator : IIncrementalGenerator
{
public void Initialize(IncrementalGeneratorInitializationContext context)
{
context.RegisterPostInitializationOutput(GenerateAllAttributes);
}
public static void GenerateAllAttributes(IncrementalGeneratorPostInitializationContext context)
{
string coreAnnotations = """
using System.Diagnostics;
namespace Snap.Hutao.Core.Annotation;
[AttributeUsage(AttributeTargets.Method, Inherited = false)]
internal sealed class CommandAttribute : Attribute
{
public CommandAttribute(string name)
{
}
public bool AllowConcurrentExecutions { get; set; }
}
[AttributeUsage(AttributeTargets.Class, Inherited = false)]
internal sealed class ConstructorGeneratedAttribute : Attribute
{
public ConstructorGeneratedAttribute()
{
}
public bool CallBaseConstructor { get; set; }
public bool ResolveHttpClient { get; set; }
}
[AttributeUsage(AttributeTargets.Class, AllowMultiple = true, Inherited = false)]
internal sealed class DependencyPropertyAttribute : Attribute
{
public DependencyPropertyAttribute(string name, Type type)
{
}
public DependencyPropertyAttribute(string name, Type type, object defaultValue)
{
}
public DependencyPropertyAttribute(string name, Type type, object defaultValue, string valueChangedCallbackName)
{
}
public bool IsAttached { get; set; }
public Type AttachedType { get; set; } = default;
}
[AttributeUsage(AttributeTargets.All, Inherited = false)]
[Conditional("DEBUG")]
internal sealed class HighQualityAttribute : Attribute
{
}
""";
context.AddSource("Snap.Hutao.Core.Annotation.Attributes.g.cs", coreAnnotations);
string coreDependencyInjectionAnnotationHttpClients = """
namespace Snap.Hutao.Core.DependencyInjection.Annotation.HttpClient;
[AttributeUsage(AttributeTargets.Class, Inherited = false)]
internal sealed class HttpClientAttribute : Attribute
{
public HttpClientAttribute(HttpClientConfiguration configuration)
{
}
public HttpClientAttribute(HttpClientConfiguration configuration, Type interfaceType)
{
}
}
internal enum HttpClientConfiguration
{
/// <summary>
/// 默认配置
/// </summary>
Default,
/// <summary>
/// 米游社请求配置
/// </summary>
XRpc,
/// <summary>
/// 米游社登录请求配置
/// </summary>
XRpc2,
/// <summary>
/// Hoyolab app
/// </summary>
XRpc3,
}
[AttributeUsage(AttributeTargets.Class, Inherited = false)]
internal sealed class PrimaryHttpMessageHandlerAttribute : Attribute
{
/// <inheritdoc cref="System.Net.Http.HttpClientHandler.MaxConnectionsPerServer"/>
public int MaxConnectionsPerServer { get; set; }
/// <summary>
/// <inheritdoc cref="System.Net.Http.HttpClientHandler.UseCookies"/>
/// </summary>
public bool UseCookies { get; set; }
}
""";
context.AddSource("Snap.Hutao.Core.DependencyInjection.Annotation.HttpClient.Attributes.g.cs", coreDependencyInjectionAnnotationHttpClients);
string coreDependencyInjectionAnnotations = """
namespace Snap.Hutao.Core.DependencyInjection.Annotation;
internal enum InjectAs
{
Singleton,
Transient,
Scoped,
}
[AttributeUsage(AttributeTargets.Class, AllowMultiple = true, Inherited = false)]
internal sealed class InjectionAttribute : Attribute
{
public InjectionAttribute(InjectAs injectAs)
{
}
public InjectionAttribute(InjectAs injectAs, Type interfaceType)
{
}
}
""";
context.AddSource("Snap.Hutao.Core.DependencyInjection.Annotation.Attributes.g.cs", coreDependencyInjectionAnnotations);
}
}

View File

@@ -95,4 +95,4 @@ internal sealed class CommandGenerator : IIncrementalGenerator
string normalizedClassName = classSymbol.ToDisplayString().Replace('<', '{').Replace('>', '}');
production.AddSource($"{normalizedClassName}.{commandName}.g.cs", code);
}
}
}

View File

@@ -0,0 +1,61 @@
// Copyright (c) DGP Studio. All rights reserved.
// Licensed under the MIT license.
using Microsoft.CodeAnalysis;
using System.Net.Http;
using System.Runtime.Serialization;
namespace Snap.Hutao.SourceGeneration.Automation;
[Generator(LanguageNames.CSharp)]
internal sealed class SaltConstantGenerator : IIncrementalGenerator
{
private static readonly HttpClient httpClient = new();
public void Initialize(IncrementalGeneratorInitializationContext context)
{
context.RegisterPostInitializationOutput(GenerateSaltContstants);
}
private static void GenerateSaltContstants(IncrementalGeneratorPostInitializationContext context)
{
string body = httpClient.GetStringAsync("https://internal.snapgenshin.cn/Archive/Salt/Latest").GetAwaiter().GetResult();
Response<SaltLatest> saltInfo = JsonParser.FromJson<Response<SaltLatest>>(body)!;
string code = $$"""
namespace Snap.Hutao.Web.Hoyolab;
internal sealed class SaltConstants
{
public const string CNVersion = "{{saltInfo.Data.CNVersion}}";
public const string CNK2 = "{{saltInfo.Data.CNK2}}";
public const string CNLK2 = "{{saltInfo.Data.CNLK2}}";
public const string OSVersion = "{{saltInfo.Data.OSVersion}}";
public const string OSK2 = "{{saltInfo.Data.OSK2}}";
public const string OSLK2 = "{{saltInfo.Data.OSLK2}}";
}
""";
context.AddSource("SaltConstants.g.cs", code);
}
private sealed class Response<T>
{
[DataMember(Name = "data")]
public T Data { get; set; } = default!;
}
internal sealed class SaltLatest
{
public string CNVersion { get; set; } = default!;
public string CNK2 { get; set; } = default!;
public string CNLK2 { get; set; } = default!;
public string OSVersion { get; set; } = default!;
public string OSK2 { get; set; } = default!;
public string OSLK2 { get; set; } = default!;
}
}

View File

@@ -8,7 +8,10 @@ internal sealed class NotNullWhenAttribute : Attribute
/// <param name="returnValue">
/// The return value condition. If the method returns this value, the associated parameter will not be null.
/// </param>
public NotNullWhenAttribute(bool returnValue) => ReturnValue = returnValue;
public NotNullWhenAttribute(bool returnValue)
{
ReturnValue = returnValue;
}
/// <summary>Gets the return value condition.</summary>
public bool ReturnValue { get; }

View File

@@ -20,7 +20,6 @@ internal sealed class HttpClientGenerator : IIncrementalGenerator
private const string HttpClientConfiguration = "Snap.Hutao.Core.DependencyInjection.Annotation.HttpClient.HttpClientConfiguration.";
private const string PrimaryHttpMessageHandlerAttributeName = "Snap.Hutao.Core.DependencyInjection.Annotation.HttpClient.PrimaryHttpMessageHandlerAttribute";
private const string UseDynamicSecretAttributeName = "Snap.Hutao.Web.Hoyolab.DynamicSecret.UseDynamicSecretAttribute";
private const string CRLF = "\r\n";
private static readonly DiagnosticDescriptor injectionShouldOmitDescriptor = new("SH201", "Injection 特性可以省略", "HttpClient 特性已将 {0} 注册为 Transient 服务", "Quality", DiagnosticSeverity.Warning, true);
@@ -134,11 +133,6 @@ internal sealed class HttpClientGenerator : IIncrementalGenerator
lineBuilder.Append(" })");
}
if (context.HasAttributeWithName(UseDynamicSecretAttributeName))
{
lineBuilder.Append(".AddHttpMessageHandler<DynamicSecretHandler>()");
}
lineBuilder.Append(';');
lines.Add(lineBuilder.ToString());

View File

@@ -89,6 +89,12 @@ internal sealed class IdentityGenerator : IIncrementalGenerator
{
return Value.GetHashCode();
}
/// <inheritdoc/>
public override string ToString()
{
return Value.ToString();
}
}
""");

View File

@@ -49,7 +49,7 @@ public class JsonSerializeTest
NumberHandling = JsonNumberHandling.AllowReadingFromString,
};
Dictionary<int,string> sample = JsonSerializer.Deserialize<Dictionary<int, string>>(SmapleNumberKeyDictionaryJson, options)!;
Dictionary<int, string> sample = JsonSerializer.Deserialize<Dictionary<int, string>>(SmapleNumberKeyDictionaryJson, options)!;
Assert.AreEqual(sample[111], "12");
}

View File

@@ -33,13 +33,23 @@ CoWaitForMultipleObjects
// USER32
AttachThreadInput
FindWindowExW
GetCursorPos
GetDC
GetDpiForWindow
GetForegroundWindow
GetWindowPlacement
GetWindowThreadProcessId
ReleaseDC
RegisterHotKey
SendInput
SetForegroundWindow
UnregisterHotKey
// COM
IPersistFile
IShellLinkW
ShellLink
SHELL_LINK_DATA_FLAGS
// WinRT
IMemoryBufferByteAccess
@@ -47,6 +57,7 @@ IMemoryBufferByteAccess
// Const value
INFINITE
WM_GETMINMAXINFO
WM_HOTKEY
WM_NCRBUTTONDOWN
WM_NCRBUTTONUP
WM_NULL
@@ -60,6 +71,4 @@ LPTHREAD_START_ROUTINE
MINMAXINFO
// System.Com
CWMO_FLAGS
D3D12CreateDevice
CWMO_FLAGS

View File

@@ -0,0 +1,25 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net7.0-windows10.0.19041.0</TargetFramework>
<ImplicitUsings>disable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>
<ItemGroup>
<None Remove="NativeMethods.json" />
<None Remove="NativeMethods.txt" />
</ItemGroup>
<ItemGroup>
<AdditionalFiles Include="NativeMethods.json" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="Microsoft.Windows.CsWin32" Version="0.3.46-beta">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
</ItemGroup>
</Project>

View File

@@ -0,0 +1,36 @@
// Copyright (c) DGP Studio. All rights reserved.
// Licensed under the MIT license.
using System.Runtime.CompilerServices;
using Windows.Win32.UI.WindowsAndMessaging;
[assembly: InternalsVisibleTo("Snap.Hutao")]
namespace Snap.Hutao.Win32;
/// <summary>
/// 结构体封送
/// </summary>
internal static class StructMarshal
{
/// <summary>
/// 构造一个新的 <see cref="Windows.Win32.UI.WindowsAndMessaging.WINDOWPLACEMENT"/>
/// </summary>
/// <returns>新的实例</returns>
public static unsafe WINDOWPLACEMENT WINDOWPLACEMENT()
{
return new() { length = SizeOf<WINDOWPLACEMENT>() };
}
/// <summary>
/// 获取结构的大小
/// </summary>
/// <typeparam name="TStruct">结构类型</typeparam>
/// <returns>结构的大小</returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static unsafe uint SizeOf<TStruct>()
where TStruct : unmanaged
{
return unchecked((uint)sizeof(TStruct));
}
}

View File

@@ -0,0 +1,72 @@
using System;
using System.Reflection;
using System.Runtime.InteropServices;
namespace Windows.Win32.CsWin32.InteropServices;
internal class WinRTCustomMarshaler : ICustomMarshaler
{
private static readonly string? AssemblyFullName = typeof(Windows.Foundation.IMemoryBuffer).Assembly.FullName;
private readonly string className;
private bool lookedForFromAbi;
private MethodInfo? fromAbiMethod;
private WinRTCustomMarshaler(string className)
{
this.className = className;
}
public static ICustomMarshaler GetInstance(string cookie)
{
return new WinRTCustomMarshaler(cookie);
}
public void CleanUpManagedData(object ManagedObj)
{
}
public void CleanUpNativeData(nint pNativeData)
{
Marshal.Release(pNativeData);
}
public int GetNativeDataSize()
{
throw new NotSupportedException();
}
public nint MarshalManagedToNative(object ManagedObj)
{
throw new NotSupportedException();
}
public object MarshalNativeToManaged(nint thisPtr)
{
return className switch
{
"Windows.System.DispatcherQueueController" => Windows.System.DispatcherQueueController.FromAbi(thisPtr),
_ => MarshalNativeToManagedSlow(thisPtr),
};
}
private object MarshalNativeToManagedSlow(nint pNativeData)
{
if (!lookedForFromAbi)
{
Type? type = Type.GetType($"{className}, {AssemblyFullName}");
fromAbiMethod = type?.GetMethod("FromAbi");
lookedForFromAbi = true;
}
if (fromAbiMethod is not null)
{
return fromAbiMethod.Invoke(default, new object[] { pNativeData })!;
}
else
{
return Marshal.GetObjectForIUnknown(pNativeData);
}
}
}

View File

@@ -14,12 +14,10 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Snap.Hutao.SourceGeneration
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Snap.Hutao.Test", "Snap.Hutao.Test\Snap.Hutao.Test.csproj", "{D691BA9F-904C-4229-87A5-E14F2EFF2F64}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Snap.Hutao.Win32", "Snap.Hutao.Win32\Snap.Hutao.Win32.csproj", "{0F7ABEB2-5107-4037-B9DC-84D288FB0801}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug As Fake Elevated|Any CPU = Debug As Fake Elevated|Any CPU
Debug As Fake Elevated|arm64 = Debug As Fake Elevated|arm64
Debug As Fake Elevated|x64 = Debug As Fake Elevated|x64
Debug As Fake Elevated|x86 = Debug As Fake Elevated|x86
Debug|Any CPU = Debug|Any CPU
Debug|arm64 = Debug|arm64
Debug|x64 = Debug|x64
@@ -30,18 +28,6 @@ Global
Release|x86 = Release|x86
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{AAAB7CF0-F299-49B8-BDB4-4C320B3EC2C7}.Debug As Fake Elevated|Any CPU.ActiveCfg = Debug As Fake Elevated|x64
{AAAB7CF0-F299-49B8-BDB4-4C320B3EC2C7}.Debug As Fake Elevated|Any CPU.Build.0 = Debug As Fake Elevated|x64
{AAAB7CF0-F299-49B8-BDB4-4C320B3EC2C7}.Debug As Fake Elevated|Any CPU.Deploy.0 = Debug As Fake Elevated|x64
{AAAB7CF0-F299-49B8-BDB4-4C320B3EC2C7}.Debug As Fake Elevated|arm64.ActiveCfg = Debug As Fake Elevated|x64
{AAAB7CF0-F299-49B8-BDB4-4C320B3EC2C7}.Debug As Fake Elevated|arm64.Build.0 = Debug As Fake Elevated|x64
{AAAB7CF0-F299-49B8-BDB4-4C320B3EC2C7}.Debug As Fake Elevated|arm64.Deploy.0 = Debug As Fake Elevated|x64
{AAAB7CF0-F299-49B8-BDB4-4C320B3EC2C7}.Debug As Fake Elevated|x64.ActiveCfg = Debug As Fake Elevated|x64
{AAAB7CF0-F299-49B8-BDB4-4C320B3EC2C7}.Debug As Fake Elevated|x64.Build.0 = Debug As Fake Elevated|x64
{AAAB7CF0-F299-49B8-BDB4-4C320B3EC2C7}.Debug As Fake Elevated|x64.Deploy.0 = Debug As Fake Elevated|x64
{AAAB7CF0-F299-49B8-BDB4-4C320B3EC2C7}.Debug As Fake Elevated|x86.ActiveCfg = Debug As Fake Elevated|x64
{AAAB7CF0-F299-49B8-BDB4-4C320B3EC2C7}.Debug As Fake Elevated|x86.Build.0 = Debug As Fake Elevated|x64
{AAAB7CF0-F299-49B8-BDB4-4C320B3EC2C7}.Debug As Fake Elevated|x86.Deploy.0 = Debug As Fake Elevated|x64
{AAAB7CF0-F299-49B8-BDB4-4C320B3EC2C7}.Debug|Any CPU.ActiveCfg = Debug|x64
{AAAB7CF0-F299-49B8-BDB4-4C320B3EC2C7}.Debug|Any CPU.Build.0 = Debug|x64
{AAAB7CF0-F299-49B8-BDB4-4C320B3EC2C7}.Debug|Any CPU.Deploy.0 = Debug|x64
@@ -66,14 +52,6 @@ Global
{AAAB7CF0-F299-49B8-BDB4-4C320B3EC2C7}.Release|x86.ActiveCfg = Release|x86
{AAAB7CF0-F299-49B8-BDB4-4C320B3EC2C7}.Release|x86.Build.0 = Release|x86
{AAAB7CF0-F299-49B8-BDB4-4C320B3EC2C7}.Release|x86.Deploy.0 = Release|x86
{8B96721E-5604-47D2-9B72-06FEBAD0CE00}.Debug As Fake Elevated|Any CPU.ActiveCfg = Debug As Fake Elevated|x64
{8B96721E-5604-47D2-9B72-06FEBAD0CE00}.Debug As Fake Elevated|Any CPU.Build.0 = Debug As Fake Elevated|x64
{8B96721E-5604-47D2-9B72-06FEBAD0CE00}.Debug As Fake Elevated|arm64.ActiveCfg = Debug As Fake Elevated|x64
{8B96721E-5604-47D2-9B72-06FEBAD0CE00}.Debug As Fake Elevated|arm64.Build.0 = Debug As Fake Elevated|x64
{8B96721E-5604-47D2-9B72-06FEBAD0CE00}.Debug As Fake Elevated|x64.ActiveCfg = Debug As Fake Elevated|x64
{8B96721E-5604-47D2-9B72-06FEBAD0CE00}.Debug As Fake Elevated|x64.Build.0 = Debug As Fake Elevated|x64
{8B96721E-5604-47D2-9B72-06FEBAD0CE00}.Debug As Fake Elevated|x86.ActiveCfg = Debug As Fake Elevated|x64
{8B96721E-5604-47D2-9B72-06FEBAD0CE00}.Debug As Fake Elevated|x86.Build.0 = Debug As Fake Elevated|x64
{8B96721E-5604-47D2-9B72-06FEBAD0CE00}.Debug|Any CPU.ActiveCfg = Debug|x64
{8B96721E-5604-47D2-9B72-06FEBAD0CE00}.Debug|Any CPU.Build.0 = Debug|x64
{8B96721E-5604-47D2-9B72-06FEBAD0CE00}.Debug|arm64.ActiveCfg = Debug|Any CPU
@@ -90,14 +68,6 @@ Global
{8B96721E-5604-47D2-9B72-06FEBAD0CE00}.Release|x64.Build.0 = Release|x64
{8B96721E-5604-47D2-9B72-06FEBAD0CE00}.Release|x86.ActiveCfg = Release|Any CPU
{8B96721E-5604-47D2-9B72-06FEBAD0CE00}.Release|x86.Build.0 = Release|Any CPU
{D691BA9F-904C-4229-87A5-E14F2EFF2F64}.Debug As Fake Elevated|Any CPU.ActiveCfg = Debug As Fake Elevated|Any CPU
{D691BA9F-904C-4229-87A5-E14F2EFF2F64}.Debug As Fake Elevated|Any CPU.Build.0 = Debug As Fake Elevated|Any CPU
{D691BA9F-904C-4229-87A5-E14F2EFF2F64}.Debug As Fake Elevated|arm64.ActiveCfg = Debug As Fake Elevated|Any CPU
{D691BA9F-904C-4229-87A5-E14F2EFF2F64}.Debug As Fake Elevated|arm64.Build.0 = Debug As Fake Elevated|Any CPU
{D691BA9F-904C-4229-87A5-E14F2EFF2F64}.Debug As Fake Elevated|x64.ActiveCfg = Debug As Fake Elevated|Any CPU
{D691BA9F-904C-4229-87A5-E14F2EFF2F64}.Debug As Fake Elevated|x64.Build.0 = Debug As Fake Elevated|Any CPU
{D691BA9F-904C-4229-87A5-E14F2EFF2F64}.Debug As Fake Elevated|x86.ActiveCfg = Debug As Fake Elevated|Any CPU
{D691BA9F-904C-4229-87A5-E14F2EFF2F64}.Debug As Fake Elevated|x86.Build.0 = Debug As Fake Elevated|Any CPU
{D691BA9F-904C-4229-87A5-E14F2EFF2F64}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{D691BA9F-904C-4229-87A5-E14F2EFF2F64}.Debug|Any CPU.Build.0 = Debug|Any CPU
{D691BA9F-904C-4229-87A5-E14F2EFF2F64}.Debug|arm64.ActiveCfg = Debug|Any CPU
@@ -114,6 +84,22 @@ Global
{D691BA9F-904C-4229-87A5-E14F2EFF2F64}.Release|x64.Build.0 = Release|Any CPU
{D691BA9F-904C-4229-87A5-E14F2EFF2F64}.Release|x86.ActiveCfg = Release|Any CPU
{D691BA9F-904C-4229-87A5-E14F2EFF2F64}.Release|x86.Build.0 = Release|Any CPU
{0F7ABEB2-5107-4037-B9DC-84D288FB0801}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{0F7ABEB2-5107-4037-B9DC-84D288FB0801}.Debug|Any CPU.Build.0 = Debug|Any CPU
{0F7ABEB2-5107-4037-B9DC-84D288FB0801}.Debug|arm64.ActiveCfg = Debug|Any CPU
{0F7ABEB2-5107-4037-B9DC-84D288FB0801}.Debug|arm64.Build.0 = Debug|Any CPU
{0F7ABEB2-5107-4037-B9DC-84D288FB0801}.Debug|x64.ActiveCfg = Debug|Any CPU
{0F7ABEB2-5107-4037-B9DC-84D288FB0801}.Debug|x64.Build.0 = Debug|Any CPU
{0F7ABEB2-5107-4037-B9DC-84D288FB0801}.Debug|x86.ActiveCfg = Debug|Any CPU
{0F7ABEB2-5107-4037-B9DC-84D288FB0801}.Debug|x86.Build.0 = Debug|Any CPU
{0F7ABEB2-5107-4037-B9DC-84D288FB0801}.Release|Any CPU.ActiveCfg = Release|Any CPU
{0F7ABEB2-5107-4037-B9DC-84D288FB0801}.Release|Any CPU.Build.0 = Release|Any CPU
{0F7ABEB2-5107-4037-B9DC-84D288FB0801}.Release|arm64.ActiveCfg = Release|Any CPU
{0F7ABEB2-5107-4037-B9DC-84D288FB0801}.Release|arm64.Build.0 = Release|Any CPU
{0F7ABEB2-5107-4037-B9DC-84D288FB0801}.Release|x64.ActiveCfg = Release|Any CPU
{0F7ABEB2-5107-4037-B9DC-84D288FB0801}.Release|x64.Build.0 = Release|Any CPU
{0F7ABEB2-5107-4037-B9DC-84D288FB0801}.Release|x86.ActiveCfg = Release|Any CPU
{0F7ABEB2-5107-4037-B9DC-84D288FB0801}.Release|x86.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE

View File

@@ -1,152 +1,30 @@
<Application
x:Class="Snap.Hutao.App"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:cwcw="using:CommunityToolkit.WinUI.Controls"
xmlns:cwuc="using:CommunityToolkit.WinUI.UI.Converters"
xmlns:muxc="using:Microsoft.UI.Xaml.Controls"
xmlns:shci="using:Snap.Hutao.Control.Image"
xmlns:shmmc="using:Snap.Hutao.Model.Metadata.Converter"
xmlns:shvc="using:Snap.Hutao.View.Converter">
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<Application.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<muxc:XamlControlsResources/>
<ResourceDictionary Source="Control/Theme/FontStyle.xaml"/>
<XamlControlsResources/>
<ResourceDictionary Source="ms-appx:///Control/Loading.xaml"/>
<ResourceDictionary Source="ms-appx:///Control/Image/CachedImage.xaml"/>
<ResourceDictionary Source="ms-appx:///Control/Theme/Card.xaml"/>
<ResourceDictionary Source="ms-appx:///Control/Theme/Color.xaml"/>
<ResourceDictionary Source="ms-appx:///Control/Theme/Converter.xaml"/>
<ResourceDictionary Source="ms-appx:///Control/Theme/CornerRadius.xaml"/>
<ResourceDictionary Source="ms-appx:///Control/Theme/FontStyle.xaml"/>
<ResourceDictionary Source="ms-appx:///Control/Theme/Glyph.xaml"/>
<ResourceDictionary Source="ms-appx:///Control/Theme/InfoBarOverride.xaml"/>
<ResourceDictionary Source="ms-appx:///Control/Theme/ItemsPanelTemplate.xaml"/>
<ResourceDictionary Source="ms-appx:///Control/Theme/NumericValue.xaml"/>
<ResourceDictionary Source="ms-appx:///Control/Theme/PageOverride.xaml"/>
<ResourceDictionary Source="ms-appx:///Control/Theme/PivotOverride.xaml"/>
<ResourceDictionary Source="ms-appx:///Control/Theme/SettingsStyle.xaml"/>
<ResourceDictionary Source="ms-appx:///Control/Theme/TransitionCollection.xaml"/>
<ResourceDictionary Source="ms-appx:///Control/Theme/Uri.xaml"/>
<ResourceDictionary Source="ms-appx:///Control/Theme/WindowOverride.xaml"/>
</ResourceDictionary.MergedDictionaries>
<ResourceDictionary.ThemeDictionaries>
<ResourceDictionary x:Key="Light">
<Color x:Key="AvatarPropertyAddValueColor">#FF74BF00</Color>
<Color x:Key="CompatBackgroundColor">#FFF4F4F4</Color>
</ResourceDictionary>
<ResourceDictionary x:Key="Dark">
<Color x:Key="AvatarPropertyAddValueColor">#FF90E800</Color>
<Color x:Key="CompatBackgroundColor">#FF242424</Color>
</ResourceDictionary>
</ResourceDictionary.ThemeDictionaries>
<!-- Modify Window title bar color -->
<StaticResource x:Key="WindowCaptionBackground" ResourceKey="ControlFillColorTransparentBrush"/>
<StaticResource x:Key="WindowCaptionBackgroundDisabled" ResourceKey="ControlFillColorTransparentBrush"/>
<!-- Page Transparent Background -->
<StaticResource x:Key="ApplicationPageBackgroundThemeBrush" ResourceKey="ControlFillColorTransparentBrush"/>
<!-- InfoBar Resource -->
<Thickness x:Key="InfoBarIconMargin">19,16,19,16</Thickness>
<Thickness x:Key="InfoBarContentRootPadding">0,0,0,0</Thickness>
<x:Double x:Key="InfoBarIconFontSize">20</x:Double>
<!-- Pivot Resource -->
<x:Double x:Key="PivotHeaderItemFontSize">16</x:Double>
<Thickness x:Key="PivotHeaderItemMargin">16,0,0,0</Thickness>
<Thickness x:Key="PivotItemMargin">0</Thickness>
<!-- CornerRadius -->
<CornerRadius x:Key="CompatCornerRadius">6</CornerRadius>
<CornerRadius x:Key="CompatCornerRadiusTop">6,6,0,0</CornerRadius>
<CornerRadius x:Key="CompatCornerRadiusRight">0,6,6,0</CornerRadius>
<CornerRadius x:Key="CompatCornerRadiusBottom">0,0,6,6</CornerRadius>
<CornerRadius x:Key="CompatCornerRadiusSmall">2</CornerRadius>
<!-- Length -->
<GridLength x:Key="CompatGridLength2">288</GridLength>
<x:Double x:Key="CompatSplitViewOpenPaneLength">212</x:Double>
<x:Double x:Key="CompatSplitViewOpenPaneLength2">304</x:Double>
<x:Double x:Key="CompatSplitViewOpenPaneLength3">320</x:Double>
<x:Double x:Key="HomeAdaptiveCardHeight">180</x:Double>
<x:Double x:Key="ContentDialogMinHeight">64</x:Double>
<x:Double x:Key="LargeAppBarButtonWidth">100</x:Double>
<!-- ProgressBar -->
<x:Double x:Key="LargeBackgroundProgressBarOpacity">0.2</x:Double>
<ThemeShadow x:Key="CompatShadow" />
<!-- Brushes -->
<SolidColorBrush x:Key="AvatarPropertyAddValueBrush" Color="{ThemeResource AvatarPropertyAddValueColor}"/>
<SolidColorBrush x:Key="BlueBrush" Color="#FF5180CB"/>
<SolidColorBrush x:Key="PurpleBrush" Color="#FFA156E0"/>
<SolidColorBrush x:Key="OrangeBrush" Color="#FFBC6932"/>
<SolidColorBrush x:Key="GuaranteePullBrush" Color="#FF0063FF"/>
<SolidColorBrush x:Key="UpPullBrush" Color="#FFFFA400"/>
<!-- Settings -->
<x:Double x:Key="SettingsCardSpacing">3</x:Double>
<x:Double x:Key="SettingsCardMinHeight">0</x:Double>
<x:Double x:Key="SettingsCardWrapThreshold">0</x:Double>
<x:Double x:Key="SettingsCardWrapNoIconThreshold">0</x:Double>
<Style
x:Key="SettingsSectionHeaderTextBlockStyle"
BasedOn="{StaticResource BodyStrongTextBlockStyle}"
TargetType="TextBlock">
<Style.Setters>
<Setter Property="Margin" Value="1,29,0,5"/>
</Style.Setters>
</Style>
<Style
x:Key="SettingsContentComboBoxStyle"
BasedOn="{StaticResource DefaultComboBoxStyle}"
TargetType="ComboBox">
<Setter Property="MinWidth" Value="120"/>
</Style>
<!-- Uris -->
<x:String x:Key="DocumentLink_MhyAccountSwitch">https://hut.ao/features/mhy-account-switch.html</x:String>
<x:String x:Key="DocumentLink_BugReport">https://hut.ao/statements/bug-report.html</x:String>
<x:String x:Key="DocumentLink_Translate">https://translate.hut.ao</x:String>
<x:String x:Key="DocumentLink_Home">https://hut.ao</x:String>
<x:String x:Key="HolographicHat_GetToken_Release">https://github.com/HolographicHat/GetToken/releases/latest</x:String>
<x:String x:Key="Sponsor_Afadian">https://afdian.net/a/DismissedLight</x:String>
<!-- Images -->
<x:String x:Key="UI_ItemIcon_None">https://static.snapgenshin.com/Bg/UI_ItemIcon_None.png</x:String>
<x:String x:Key="UI_MarkTower">https://static.snapgenshin.com/Bg/UI_MarkTower.png</x:String>
<x:String x:Key="UI_Icon_Intee_Explore_1">https://static.snapgenshin.com/Bg/UI_Icon_Intee_Explore_1.png</x:String>
<x:String x:Key="UI_MarkQuest_Events_Proce">https://static.snapgenshin.com/Bg/UI_MarkQuest_Events_Proce.png</x:String>
<x:String x:Key="UI_ItemIcon_201">https://static.snapgenshin.com/ItemIcon/UI_ItemIcon_201.png</x:String>
<x:String x:Key="UI_ItemIcon_204">https://static.snapgenshin.com/ItemIcon/UI_ItemIcon_204.png</x:String>
<x:String x:Key="UI_ItemIcon_210">https://static.snapgenshin.com/ItemIcon/UI_ItemIcon_210.png</x:String>
<x:String x:Key="UI_ItemIcon_220021">https://static.snapgenshin.com/ItemIcon/UI_ItemIcon_220021.png</x:String>
<x:String x:Key="UI_ImgSign_ItemIcon">https://static.snapgenshin.com/Bg/UI_ImgSign_ItemIcon.png</x:String>
<x:String x:Key="UI_AvatarIcon_Costume_Card">https://static.snapgenshin.com/AvatarCard/UI_AvatarIcon_Costume_Card.png</x:String>
<x:String x:Key="UI_EmotionIcon25">https://static.snapgenshin.com/EmotionIcon/UI_EmotionIcon25.png</x:String>
<x:String x:Key="UI_EmotionIcon71">https://static.snapgenshin.com/EmotionIcon/UI_EmotionIcon71.png</x:String>
<x:String x:Key="UI_EmotionIcon250">https://static.snapgenshin.com/EmotionIcon/UI_EmotionIcon250.png</x:String>
<x:String x:Key="UI_EmotionIcon272">https://static.snapgenshin.com/EmotionIcon/UI_EmotionIcon272.png</x:String>
<x:String x:Key="UI_EmotionIcon293">https://static.snapgenshin.com/EmotionIcon/UI_EmotionIcon293.png</x:String>
<!-- FontIcon Content -->
<x:String x:Key="FontIconContentAdd">&#xE710;</x:String>
<x:String x:Key="FontIconContentSetting">&#xE713;</x:String>
<x:String x:Key="FontIconContentRefresh">&#xE72C;</x:String>
<x:String x:Key="FontIconContentDelete">&#xE74D;</x:String>
<x:String x:Key="FontIconContentFolder">&#xE8B7;</x:String>
<x:String x:Key="FontIconContentCheckList">&#xE9D5;</x:String>
<x:String x:Key="FontIconContentAsteriskBadge12">&#xEDAD;</x:String>
<x:String x:Key="FontIconContentZipFolder">&#xF012;</x:String>
<!-- Converters -->
<cwuc:BoolNegationConverter x:Key="BoolNegationConverter"/>
<cwuc:BoolToVisibilityConverter x:Key="BoolToVisibilityConverter"/>
<cwuc:FileSizeToFriendlyStringConverter x:Key="FileSizeToFriendlyStringConverter"/>
<shmmc:AchievementIconConverter x:Key="AchievementIconConverter"/>
<shmmc:AvatarCardConverter x:Key="AvatarCardConverter"/>
<shmmc:AvatarIconConverter x:Key="AvatarIconConverter"/>
<shmmc:AvatarNameCardPicConverter x:Key="AvatarNameCardPicConverter"/>
<shmmc:AvatarSideIconConverter x:Key="AvatarSideIconConverter"/>
<shmmc:DescriptionsParametersDescriptor x:Key="DescParamDescriptor"/>
<shmmc:ElementNameIconConverter x:Key="ElementNameIconConverter"/>
<shmmc:EmotionIconConverter x:Key="EmotionIconConverter"/>
<shmmc:EquipIconConverter x:Key="EquipIconConverter"/>
<shmmc:GachaAvatarImgConverter x:Key="GachaAvatarImgConverter"/>
<shmmc:GachaAvatarIconConverter x:Key="GachaAvatarIconConverter"/>
<shmmc:GachaEquipIconConverter x:Key="GachaEquipIconConverter"/>
<shmmc:ItemIconConverter x:Key="ItemIconConverter"/>
<shmmc:MonsterIconConverter x:Key="MonsterIconConverter"/>
<shmmc:PropertiesParametersDescriptor x:Key="PropertyDescriptor"/>
<shmmc:QualityColorConverter x:Key="QualityColorConverter"/>
<shmmc:WeaponTypeIconConverter x:Key="WeaponTypeIconConverter"/>
<shvc:BoolToVisibilityRevertConverter x:Key="BoolToVisibilityRevertConverter"/>
<shvc:EmptyObjectToBoolConverter x:Key="EmptyObjectToBoolConverter"/>
<shvc:EmptyObjectToBoolRevertConverter x:Key="EmptyObjectToBoolRevertConverter"/>
<shvc:EmptyObjectToVisibilityConverter x:Key="EmptyObjectToVisibilityConverter"/>
<shvc:EmptyObjectToVisibilityRevertConverter x:Key="EmptyObjectToVisibilityRevertConverter"/>
<shvc:Int32ToVisibilityConverter x:Key="Int32ToVisibilityConverter"/>
<shvc:Int32ToVisibilityRevertConverter x:Key="Int32ToVisibilityRevertConverter"/>
<shvc:StringBoolConverter x:Key="StringBoolConverter"/>
<!-- Styles -->
<Style
x:Key="LargeGridViewItemStyle"
BasedOn="{StaticResource DefaultGridViewItemStyle}"
@@ -154,118 +32,19 @@
<Setter Property="Margin" Value="0,0,12,12"/>
</Style>
<Style
x:Key="SettingButtonStyle"
BasedOn="{StaticResource DefaultButtonStyle}"
TargetType="Button">
<Setter Property="BorderBrush" Value="{ThemeResource CardBorderBrush}"/>
<Setter Property="CornerRadius" Value="{ThemeResource ControlCornerRadius}"/>
<Setter Property="Padding" Value="16,6,16,6"/>
<Setter Property="HorizontalAlignment" Value="Stretch"/>
<Setter Property="HorizontalContentAlignment" Value="Center"/>
x:Name="NoneSelectionListViewItemStyle"
BasedOn="{StaticResource DefaultListViewItemStyle}"
TargetType="ListViewItem">
<Setter Property="Padding" Value="0"/>
<Setter Property="Margin" Value="0,4,0,0"/>
</Style>
<Style x:Key="BorderCardStyle" TargetType="Border">
<Setter Property="Background" Value="{ThemeResource CardBackgroundFillColorDefaultBrush}"/>
<Setter Property="BorderBrush" Value="{ThemeResource CardStrokeColorDefaultBrush}"/>
<Setter Property="BorderThickness" Value="1"/>
<Setter Property="CornerRadius" Value="{StaticResource CompatCornerRadius}"/>
<Style
x:Name="NoneSelectionGridViewItemStyle"
BasedOn="{StaticResource DefaultGridViewItemStyle}"
TargetType="GridViewItem">
<Setter Property="Padding" Value="0"/>
<Setter Property="Margin" Value="0,0,2,4"/>
</Style>
<Style x:Key="BorderGridStyle" TargetType="Grid">
<Setter Property="Background" Value="{ThemeResource CardBackgroundFillColorDefaultBrush}"/>
<Setter Property="BorderBrush" Value="{ThemeResource CardStrokeColorDefaultBrush}"/>
<Setter Property="BorderThickness" Value="1"/>
<Setter Property="CornerRadius" Value="{StaticResource CompatCornerRadius}"/>
</Style>
<Style TargetType="shci:CachedImage">
<Setter Property="Background" Value="Transparent"/>
<Setter Property="Foreground" Value="{ThemeResource ApplicationForegroundThemeBrush}"/>
<Setter Property="IsTabStop" Value="False"/>
<Setter Property="LazyLoadingThreshold" Value="300"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="shci:CachedImage">
<Grid
Background="{TemplateBinding Background}"
BorderBrush="{TemplateBinding BorderBrush}"
BorderThickness="{TemplateBinding BorderThickness}"
CornerRadius="{TemplateBinding CornerRadius}">
<Image
Name="PlaceholderImage"
HorizontalAlignment="{TemplateBinding HorizontalAlignment}"
VerticalAlignment="{TemplateBinding VerticalAlignment}"
Opacity="1.0"
Source="{TemplateBinding PlaceholderSource}"
Stretch="{TemplateBinding PlaceholderStretch}"/>
<Image
Name="Image"
HorizontalAlignment="{TemplateBinding HorizontalAlignment}"
VerticalAlignment="{TemplateBinding VerticalAlignment}"
NineGrid="{TemplateBinding NineGrid}"
Opacity="0.0"
Stretch="{TemplateBinding Stretch}"/>
<VisualStateManager.VisualStateGroups>
<VisualStateGroup x:Name="CommonStates">
<VisualState x:Name="Failed">
<Storyboard>
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="Image" Storyboard.TargetProperty="Opacity">
<DiscreteObjectKeyFrame KeyTime="0" Value="0"/>
</ObjectAnimationUsingKeyFrames>
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="PlaceholderImage" Storyboard.TargetProperty="Opacity">
<DiscreteObjectKeyFrame KeyTime="0" Value="1"/>
</ObjectAnimationUsingKeyFrames>
</Storyboard>
</VisualState>
<VisualState x:Name="Loading">
<Storyboard>
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="Image" Storyboard.TargetProperty="Opacity">
<DiscreteObjectKeyFrame KeyTime="0" Value="0"/>
</ObjectAnimationUsingKeyFrames>
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="PlaceholderImage" Storyboard.TargetProperty="Opacity">
<DiscreteObjectKeyFrame KeyTime="0" Value="1"/>
</ObjectAnimationUsingKeyFrames>
</Storyboard>
</VisualState>
<VisualState x:Name="Loaded">
<Storyboard>
<DoubleAnimation
AutoReverse="False"
BeginTime="0"
Storyboard.TargetName="Image"
Storyboard.TargetProperty="Opacity"
From="0"
To="1"
Duration="0:0:0.5"/>
<DoubleAnimation
AutoReverse="False"
BeginTime="0"
Storyboard.TargetName="PlaceholderImage"
Storyboard.TargetProperty="Opacity"
From="1"
To="0"
Duration="0:0:0.5"/>
</Storyboard>
</VisualState>
<VisualState x:Name="Unloaded"/>
</VisualStateGroup>
</VisualStateManager.VisualStateGroups>
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
<!-- ItemsPanelTemplate -->
<ItemsPanelTemplate x:Key="ItemsStackPanelTemplate">
<ItemsStackPanel/>
</ItemsPanelTemplate>
<ItemsPanelTemplate x:Key="WrapPanelTemplate">
<cwcw:WrapPanel/>
</ItemsPanelTemplate>
<ItemsPanelTemplate x:Key="HorizontalStackPanelTemplate">
<StackPanel Orientation="Horizontal"/>
</ItemsPanelTemplate>
<!-- Transitions -->
<TransitionCollection x:Key="ReorderThemeTransitions">
<ReorderThemeTransition/>
</TransitionCollection>
</ResourceDictionary>
</Application.Resources>
</Application>

View File

@@ -74,10 +74,10 @@ public sealed partial class App : Application
private void LogDiagnosticInformation()
{
RuntimeOptions hutaoOptions = serviceProvider.GetRequiredService<RuntimeOptions>();
RuntimeOptions runtimeOptions = serviceProvider.GetRequiredService<RuntimeOptions>();
logger.LogInformation("FamilyName: {name}", hutaoOptions.FamilyName);
logger.LogInformation("Version: {version}", hutaoOptions.Version);
logger.LogInformation("LocalCache: {folder}", hutaoOptions.LocalCache);
logger.LogInformation("FamilyName: {name}", runtimeOptions.FamilyName);
logger.LogInformation("Version: {version}", runtimeOptions.Version);
logger.LogInformation("LocalCache: {folder}", runtimeOptions.LocalCache);
}
}

View File

@@ -1,55 +0,0 @@
// Copyright (c) DGP Studio. All rights reserved.
// Licensed under the MIT license.
using CommunityToolkit.Mvvm.Messaging;
using CommunityToolkit.WinUI.Behaviors;
using Microsoft.UI.Xaml.Controls;
namespace Snap.Hutao.Control.Behavior;
/// <summary>
/// AppTitleBar Workaround
/// https://github.com/microsoft/microsoft-ui-xaml/issues/7756
/// </summary>
internal sealed class ComboBoxExtendsContentIntoTitleBarWorkaroundBehavior : BehaviorBase<ComboBox>
{
private readonly IMessenger messenger;
private readonly EventHandler<object> dropDownOpenedHandler;
private readonly EventHandler<object> dropDownClosedHandler;
/// <summary>
/// AppTitleBar Workaround
/// </summary>
public ComboBoxExtendsContentIntoTitleBarWorkaroundBehavior()
{
messenger = Ioc.Default.GetRequiredService<IMessenger>();
dropDownOpenedHandler = OnDropDownOpened;
dropDownClosedHandler = OnDropDownClosed;
}
/// <inheritdoc/>
protected override bool Initialize()
{
AssociatedObject.DropDownOpened += dropDownOpenedHandler;
AssociatedObject.DropDownClosed += dropDownClosedHandler;
return true;
}
/// <inheritdoc/>
protected override bool Uninitialize()
{
AssociatedObject.DropDownOpened -= dropDownOpenedHandler;
AssociatedObject.DropDownClosed -= dropDownClosedHandler;
return true;
}
private void OnDropDownOpened(object? sender, object e)
{
messenger.Send(Message.FlyoutStateChangedMessage.Open);
}
private void OnDropDownClosed(object? sender, object e)
{
messenger.Send(Message.FlyoutStateChangedMessage.Close);
}
}

View File

@@ -14,12 +14,36 @@ namespace Snap.Hutao.Control.Behavior;
[DependencyProperty("CommandParameter", typeof(object))]
internal sealed partial class InvokeCommandOnLoadedBehavior : BehaviorBase<UIElement>
{
private bool executed;
protected override void OnAttached()
{
base.OnAttached();
// FrameworkElement in a ItemsRepeater gets attached twice
if (AssociatedObject is FrameworkElement { IsLoaded: true })
{
TryExecuteCommand();
}
}
/// <inheritdoc/>
protected override void OnAssociatedObjectLoaded()
{
TryExecuteCommand();
}
private void TryExecuteCommand()
{
if (executed)
{
return;
}
if (Command is not null && Command.CanExecute(CommandParameter))
{
Command.Execute(CommandParameter);
executed = true;
}
}
}

View File

@@ -3,7 +3,7 @@
using Windows.UI;
namespace Snap.Hutao.Control;
namespace Snap.Hutao.Control.Brush;
internal sealed class ColorSegment : IColorSegment
{

View File

@@ -3,7 +3,7 @@
using Windows.UI;
namespace Snap.Hutao.Control;
namespace Snap.Hutao.Control.Brush;
internal interface IColorSegment
{

View File

@@ -7,7 +7,7 @@ using Microsoft.UI.Xaml.Media;
using Microsoft.UI.Xaml.Shapes;
using System.Runtime.InteropServices;
namespace Snap.Hutao.Control;
namespace Snap.Hutao.Control.Brush;
[DependencyProperty("Source", typeof(List<IColorSegment>), default!, nameof(OnSourceChanged))]
internal sealed partial class SegmentedBar : ContentControl

View File

@@ -2,12 +2,11 @@
// Licensed under the MIT license.
using Microsoft.UI.Xaml.Controls;
using Microsoft.UI.Xaml.Media;
using Windows.Foundation.Collections;
namespace Snap.Hutao.Control.Alternating;
namespace Snap.Hutao.Control.Collection.Alternating;
[DependencyProperty("ItemAlternateBackground", typeof(Brush))]
[DependencyProperty("ItemAlternateBackground", typeof(Microsoft.UI.Xaml.Media.Brush))]
internal sealed partial class AlternatingItemsControl : ItemsControl
{
private readonly VectorChangedEventHandler<object> itemsVectorChangedEventHandler;

View File

@@ -1,11 +1,9 @@
// Copyright (c) DGP Studio. All rights reserved.
// Licensed under the MIT license.
using Microsoft.UI.Xaml.Media;
namespace Snap.Hutao.Control.Alternating;
namespace Snap.Hutao.Control.Collection.Alternating;
internal interface IAlternatingItem
{
public Brush? Background { get; set; }
public Microsoft.UI.Xaml.Media.Brush? Background { get; set; }
}

View File

@@ -0,0 +1,23 @@
// Copyright (c) DGP Studio. All rights reserved.
// Licensed under the MIT license.
using Microsoft.UI.Xaml;
using Microsoft.UI.Xaml.Controls;
using Microsoft.UI.Xaml.Data;
namespace Snap.Hutao.Control.Collection.Selector;
[DependencyProperty("EnableMemberPath", typeof(string))]
internal sealed partial class ComboBox2 : ComboBox
{
protected override void PrepareContainerForItemOverride(DependencyObject element, object item)
{
if (element is ComboBoxItem comboBoxItem)
{
Binding binding = new() { Path = new(EnableMemberPath) };
comboBoxItem.SetBinding(IsEnabledProperty, binding);
}
base.PrepareContainerForItemOverride(element, item);
}
}

View File

@@ -11,8 +11,8 @@ public sealed partial class FrameworkElementHelper
{
private static void OnSquareLengthChanged(DependencyObject dp, DependencyPropertyChangedEventArgs e)
{
Microsoft.UI.Xaml.Controls.Control control = (Microsoft.UI.Xaml.Controls.Control)dp;
control.Width = (double)e.NewValue;
control.Height = (double)e.NewValue;
FrameworkElement element = (FrameworkElement)dp;
element.Width = (double)e.NewValue;
element.Height = (double)e.NewValue;
}
}

View File

@@ -0,0 +1,13 @@
// Copyright (c) DGP Studio. All rights reserved.
// Licensed under the MIT license.
using Microsoft.UI.Xaml;
using Microsoft.UI.Xaml.Controls;
namespace Snap.Hutao.Control.Helper;
[SuppressMessage("", "SH001")]
[DependencyProperty("IsTextSelectionEnabled", typeof(bool), false, IsAttached = true, AttachedType = typeof(InfoBar))]
public sealed partial class InfoBarHelper
{
}

View File

@@ -1,7 +1,6 @@
// Copyright (c) DGP Studio. All rights reserved.
// Licensed under the MIT license.
using CommunityToolkit.WinUI.UI.Controls;
using Microsoft.UI.Xaml.Media;
using Microsoft.UI.Xaml.Media.Imaging;
using Snap.Hutao.Core.Caching;
@@ -13,7 +12,7 @@ namespace Snap.Hutao.Control.Image;
/// 缓存图像
/// </summary>
[HighQuality]
internal sealed class CachedImage : ImageEx
internal sealed class CachedImage : Implementation.ImageEx
{
/// <summary>
/// 构造一个新的缓存图像

View File

@@ -0,0 +1,82 @@
<ResourceDictionary
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:shci="using:Snap.Hutao.Control.Image">
<Style TargetType="shci:CachedImage">
<Setter Property="Background" Value="Transparent"/>
<Setter Property="Foreground" Value="{ThemeResource ApplicationForegroundThemeBrush}"/>
<Setter Property="IsTabStop" Value="False"/>
<Setter Property="LazyLoadingThreshold" Value="256"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="shci:CachedImage">
<Grid
Background="{TemplateBinding Background}"
BorderBrush="{TemplateBinding BorderBrush}"
BorderThickness="{TemplateBinding BorderThickness}"
CornerRadius="{TemplateBinding CornerRadius}">
<Image
Name="PlaceholderImage"
HorizontalAlignment="{TemplateBinding HorizontalAlignment}"
VerticalAlignment="{TemplateBinding VerticalAlignment}"
Opacity="1.0"
Source="{TemplateBinding PlaceholderSource}"
Stretch="{TemplateBinding PlaceholderStretch}"/>
<Image
Name="Image"
HorizontalAlignment="{TemplateBinding HorizontalAlignment}"
VerticalAlignment="{TemplateBinding VerticalAlignment}"
NineGrid="{TemplateBinding NineGrid}"
Opacity="0.0"
Stretch="{TemplateBinding Stretch}"/>
<VisualStateManager.VisualStateGroups>
<VisualStateGroup x:Name="CommonStates">
<VisualState x:Name="Failed">
<Storyboard>
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="Image" Storyboard.TargetProperty="Opacity">
<DiscreteObjectKeyFrame KeyTime="0" Value="0"/>
</ObjectAnimationUsingKeyFrames>
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="PlaceholderImage" Storyboard.TargetProperty="Opacity">
<DiscreteObjectKeyFrame KeyTime="0" Value="1"/>
</ObjectAnimationUsingKeyFrames>
</Storyboard>
</VisualState>
<VisualState x:Name="Loading">
<Storyboard>
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="Image" Storyboard.TargetProperty="Opacity">
<DiscreteObjectKeyFrame KeyTime="0" Value="0"/>
</ObjectAnimationUsingKeyFrames>
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="PlaceholderImage" Storyboard.TargetProperty="Opacity">
<DiscreteObjectKeyFrame KeyTime="0" Value="1"/>
</ObjectAnimationUsingKeyFrames>
</Storyboard>
</VisualState>
<VisualState x:Name="Loaded">
<Storyboard>
<DoubleAnimation
AutoReverse="False"
BeginTime="0"
Storyboard.TargetName="Image"
Storyboard.TargetProperty="Opacity"
From="0"
To="1"
Duration="0:0:0.5"/>
<DoubleAnimation
AutoReverse="False"
BeginTime="0"
Storyboard.TargetName="PlaceholderImage"
Storyboard.TargetProperty="Opacity"
From="1"
To="0"
Duration="0:0:0.5"/>
</Storyboard>
</VisualState>
<VisualState x:Name="Unloaded"/>
</VisualStateGroup>
</VisualStateManager.VisualStateGroups>
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</ResourceDictionary>

View File

@@ -164,11 +164,26 @@ internal abstract partial class CompositionImage : Microsoft.UI.Xaml.Controls.Co
private async ValueTask<LoadedImageSurface> LoadImageSurfaceAsync(string file, CancellationToken token)
{
surfaceLoadTaskCompletionSource = new();
LoadedImageSurface surface = LoadedImageSurface.StartLoadFromUri(file.ToUri());
surface.LoadCompleted += loadedImageSourceLoadCompletedEventHandler;
await surfaceLoadTaskCompletionSource.Task.ConfigureAwait(true);
LoadImageSurfaceCompleted(surface);
return surface;
LoadedImageSurface? surface = default;
try
{
surface = LoadedImageSurface.StartLoadFromUri(file.ToUri());
surface.LoadCompleted += loadedImageSourceLoadCompletedEventHandler;
if (surface.DecodedPhysicalSize.Size() <= 0D)
{
await surfaceLoadTaskCompletionSource.Task.ConfigureAwait(true);
}
LoadImageSurfaceCompleted(surface);
return surface;
}
finally
{
if (surface is not null)
{
surface.LoadCompleted -= loadedImageSourceLoadCompletedEventHandler;
}
}
}
private async ValueTask ShowAsync(CancellationToken token)
@@ -216,7 +231,6 @@ internal abstract partial class CompositionImage : Microsoft.UI.Xaml.Controls.Co
private void OnLoadImageSurfaceLoadCompleted(LoadedImageSurface surface, LoadedImageSourceLoadCompletedEventArgs e)
{
surfaceLoadTaskCompletionSource?.TrySetResult();
surface.LoadCompleted -= loadedImageSourceLoadCompletedEventHandler;
}
private void OnSizeChanged(object sender, SizeChangedEventArgs e)

View File

@@ -5,7 +5,6 @@ using Microsoft.UI;
using Microsoft.UI.Composition;
using Microsoft.UI.Xaml;
using Microsoft.UI.Xaml.Media;
using Snap.Hutao.Win32;
namespace Snap.Hutao.Control.Image;

View File

@@ -0,0 +1,44 @@
// Copyright (c) DGP Studio. All rights reserved.
// Licensed under the MIT license.
using Microsoft.UI.Composition;
using Microsoft.UI.Xaml;
using Windows.Media.Casting;
namespace Snap.Hutao.Control.Image.Implementation;
internal class ImageEx : ImageExBase
{
private static readonly DependencyProperty NineGridProperty = DependencyProperty.Register(nameof(NineGrid), typeof(Thickness), typeof(ImageEx), new PropertyMetadata(default(Thickness)));
public ImageEx()
: base()
{
}
public Thickness NineGrid
{
get => (Thickness)GetValue(NineGridProperty);
set => SetValue(NineGridProperty, value);
}
public override CompositionBrush GetAlphaMask()
{
if (IsInitialized && Image is Microsoft.UI.Xaml.Controls.Image image)
{
return image.GetAlphaMask();
}
return default!;
}
public CastingSource GetAsCastingSource()
{
if (IsInitialized && Image is Microsoft.UI.Xaml.Controls.Image image)
{
return image.GetAsCastingSource();
}
return default!;
}
}

View File

@@ -0,0 +1,468 @@
// Copyright (c) DGP Studio. All rights reserved.
// Licensed under the MIT license.
using CommunityToolkit.WinUI;
using Microsoft.UI.Composition;
using Microsoft.UI.Xaml;
using Microsoft.UI.Xaml.Media;
using Microsoft.UI.Xaml.Media.Imaging;
using System.IO;
using Windows.Foundation;
namespace Snap.Hutao.Control.Image.Implementation;
internal delegate void ImageExFailedEventHandler(object sender, ImageExFailedEventArgs e);
internal delegate void ImageExOpenedEventHandler(object sender, ImageExOpenedEventArgs e);
[SuppressMessage("", "CA1001")]
[SuppressMessage("", "SH003")]
[TemplateVisualState(Name = LoadingState, GroupName = CommonGroup)]
[TemplateVisualState(Name = LoadedState, GroupName = CommonGroup)]
[TemplateVisualState(Name = UnloadedState, GroupName = CommonGroup)]
[TemplateVisualState(Name = FailedState, GroupName = CommonGroup)]
[TemplatePart(Name = PartImage, Type = typeof(object))]
internal abstract class ImageExBase : Microsoft.UI.Xaml.Controls.Control, IAlphaMaskProvider
{
protected const string PartImage = "Image";
protected const string CommonGroup = "CommonStates";
protected const string LoadingState = "Loading";
protected const string LoadedState = "Loaded";
protected const string UnloadedState = "Unloaded";
protected const string FailedState = "Failed";
private static readonly DependencyProperty StretchProperty = DependencyProperty.Register(nameof(Stretch), typeof(Stretch), typeof(ImageExBase), new PropertyMetadata(Stretch.Uniform));
private static readonly DependencyProperty DecodePixelHeightProperty = DependencyProperty.Register(nameof(DecodePixelHeight), typeof(int), typeof(ImageExBase), new PropertyMetadata(0));
private static readonly DependencyProperty DecodePixelTypeProperty = DependencyProperty.Register(nameof(DecodePixelType), typeof(int), typeof(ImageExBase), new PropertyMetadata(DecodePixelType.Physical));
private static readonly DependencyProperty DecodePixelWidthProperty = DependencyProperty.Register(nameof(DecodePixelWidth), typeof(int), typeof(ImageExBase), new PropertyMetadata(0));
private static readonly DependencyProperty IsCacheEnabledProperty = DependencyProperty.Register(nameof(IsCacheEnabled), typeof(bool), typeof(ImageExBase), new PropertyMetadata(false));
private static readonly DependencyProperty EnableLazyLoadingProperty = DependencyProperty.Register(nameof(EnableLazyLoading), typeof(bool), typeof(ImageExBase), new PropertyMetadata(false, EnableLazyLoadingChanged));
private static readonly DependencyProperty LazyLoadingThresholdProperty = DependencyProperty.Register(nameof(LazyLoadingThreshold), typeof(double), typeof(ImageExBase), new PropertyMetadata(default(double), LazyLoadingThresholdChanged));
private static readonly DependencyProperty PlaceholderSourceProperty = DependencyProperty.Register(nameof(PlaceholderSource), typeof(ImageSource), typeof(ImageExBase), new PropertyMetadata(default(ImageSource), PlaceholderSourceChanged));
private static readonly DependencyProperty PlaceholderStretchProperty = DependencyProperty.Register(nameof(PlaceholderStretch), typeof(Stretch), typeof(ImageExBase), new PropertyMetadata(default(Stretch)));
private static readonly DependencyProperty SourceProperty = DependencyProperty.Register(nameof(Source), typeof(object), typeof(ImageExBase), new PropertyMetadata(null, SourceChanged));
private CancellationTokenSource? tokenSource;
private object? lazyLoadingSource;
private bool isInViewport;
public event ImageExFailedEventHandler? ImageExFailed;
public event ImageExOpenedEventHandler? ImageExOpened;
public event EventHandler? ImageExInitialized;
public bool IsInitialized { get; private set; }
public int DecodePixelHeight
{
get => (int)GetValue(DecodePixelHeightProperty);
set => SetValue(DecodePixelHeightProperty, value);
}
public DecodePixelType DecodePixelType
{
get => (DecodePixelType)GetValue(DecodePixelTypeProperty);
set => SetValue(DecodePixelTypeProperty, value);
}
public int DecodePixelWidth
{
get => (int)GetValue(DecodePixelWidthProperty);
set => SetValue(DecodePixelWidthProperty, value);
}
public Stretch Stretch
{
get => (Stretch)GetValue(StretchProperty);
set => SetValue(StretchProperty, value);
}
public bool IsCacheEnabled
{
get => (bool)GetValue(IsCacheEnabledProperty);
set => SetValue(IsCacheEnabledProperty, value);
}
public bool EnableLazyLoading
{
get => (bool)GetValue(EnableLazyLoadingProperty);
set => SetValue(EnableLazyLoadingProperty, value);
}
public double LazyLoadingThreshold
{
get => (double)GetValue(LazyLoadingThresholdProperty);
set => SetValue(LazyLoadingThresholdProperty, value);
}
public ImageSource PlaceholderSource
{
get => (ImageSource)GetValue(PlaceholderSourceProperty);
set => SetValue(PlaceholderSourceProperty, value);
}
public Stretch PlaceholderStretch
{
get => (Stretch)GetValue(PlaceholderStretchProperty);
set => SetValue(PlaceholderStretchProperty, value);
}
public object Source
{
get => GetValue(SourceProperty);
set => SetValue(SourceProperty, value);
}
public bool WaitUntilLoaded
{
get => true;
}
protected object? Image { get; private set; }
public abstract CompositionBrush GetAlphaMask();
protected virtual void OnPlaceholderSourceChanged(DependencyPropertyChangedEventArgs e)
{
}
protected virtual Task<ImageSource?> ProvideCachedResourceAsync(Uri imageUri, CancellationToken token)
{
// By default we just use the built-in UWP image cache provided within the Image control.
return Task.FromResult<ImageSource?>(new BitmapImage(imageUri));
}
protected virtual void OnImageOpened(object sender, RoutedEventArgs e)
{
VisualStateManager.GoToState(this, LoadedState, true);
ImageExOpened?.Invoke(this, new ImageExOpenedEventArgs());
}
protected virtual void OnImageFailed(object sender, ExceptionRoutedEventArgs e)
{
VisualStateManager.GoToState(this, FailedState, true);
ImageExFailed?.Invoke(this, new ImageExFailedEventArgs(new FileNotFoundException(e.ErrorMessage)));
}
protected void AttachImageOpened(RoutedEventHandler handler)
{
if (Image is Microsoft.UI.Xaml.Controls.Image image)
{
image.ImageOpened += handler;
}
else if (Image is ImageBrush brush)
{
brush.ImageOpened += handler;
}
}
protected void RemoveImageOpened(RoutedEventHandler handler)
{
if (Image is Microsoft.UI.Xaml.Controls.Image image)
{
image.ImageOpened -= handler;
}
else if (Image is ImageBrush brush)
{
brush.ImageOpened -= handler;
}
}
protected void AttachImageFailed(ExceptionRoutedEventHandler handler)
{
if (Image is Microsoft.UI.Xaml.Controls.Image image)
{
image.ImageFailed += handler;
}
else if (Image is ImageBrush brush)
{
brush.ImageFailed += handler;
}
}
protected void RemoveImageFailed(ExceptionRoutedEventHandler handler)
{
if (Image is Microsoft.UI.Xaml.Controls.Image image)
{
image.ImageFailed -= handler;
}
else if (Image is ImageBrush brush)
{
brush.ImageFailed -= handler;
}
}
protected override void OnApplyTemplate()
{
RemoveImageOpened(OnImageOpened);
RemoveImageFailed(OnImageFailed);
Image = GetTemplateChild(PartImage);
IsInitialized = true;
ImageExInitialized?.Invoke(this, EventArgs.Empty);
if (Source is null || !EnableLazyLoading || isInViewport)
{
lazyLoadingSource = null;
SetSource(Source);
}
else
{
lazyLoadingSource = Source;
}
AttachImageOpened(OnImageOpened);
AttachImageFailed(OnImageFailed);
base.OnApplyTemplate();
}
private static void EnableLazyLoadingChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
if (d is ImageExBase control)
{
bool value = (bool)e.NewValue;
if (value)
{
control.LayoutUpdated += control.ImageExBase_LayoutUpdated;
control.InvalidateLazyLoading();
}
else
{
control.LayoutUpdated -= control.ImageExBase_LayoutUpdated;
}
}
}
private static void LazyLoadingThresholdChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
if (d is ImageExBase control && control.EnableLazyLoading)
{
control.InvalidateLazyLoading();
}
}
private static void PlaceholderSourceChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
if (d is ImageExBase control)
{
control.OnPlaceholderSourceChanged(e);
}
}
private static void SourceChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
if (d is not ImageExBase control)
{
return;
}
if (e.OldValue is null || e.NewValue is null || !e.OldValue.Equals(e.NewValue))
{
if (e.NewValue is null || !control.EnableLazyLoading || control.isInViewport)
{
control.lazyLoadingSource = null;
control.SetSource(e.NewValue);
}
else
{
control.lazyLoadingSource = e.NewValue;
}
}
}
private static bool IsHttpUri(Uri uri)
{
return uri.IsAbsoluteUri && (uri.Scheme == "http" || uri.Scheme == "https");
}
private void AttachSource(ImageSource? source)
{
// Setting the source at this point should call ImageExOpened/VisualStateManager.GoToState
// as we register to both the ImageOpened/ImageFailed events of the underlying control.
// We only need to call those methods if we fail in other cases before we get here.
if (Image is Microsoft.UI.Xaml.Controls.Image image)
{
image.Source = source;
}
else if (Image is ImageBrush brush)
{
brush.ImageSource = source;
}
if (source is null)
{
VisualStateManager.GoToState(this, UnloadedState, true);
}
else if (source is BitmapSource { PixelHeight: > 0, PixelWidth: > 0 })
{
VisualStateManager.GoToState(this, LoadedState, true);
ImageExOpened?.Invoke(this, new ImageExOpenedEventArgs());
}
}
[SuppressMessage("", "IDE0019")]
private async void SetSource(object? source)
{
if (!IsInitialized)
{
return;
}
tokenSource?.Cancel();
tokenSource = new CancellationTokenSource();
AttachSource(null);
if (source is null)
{
return;
}
VisualStateManager.GoToState(this, LoadingState, true);
ImageSource? imageSource = source as ImageSource;
if (imageSource is not null)
{
AttachSource(imageSource);
return;
}
Uri? uri = source as Uri;
if (uri is null)
{
string? url = source as string ?? source.ToString();
if (!Uri.TryCreate(url, UriKind.RelativeOrAbsolute, out uri))
{
VisualStateManager.GoToState(this, FailedState, true);
ImageExFailed?.Invoke(this, new ImageExFailedEventArgs(new UriFormatException("Invalid uri specified.")));
return;
}
}
if (!IsHttpUri(uri) && !uri.IsAbsoluteUri)
{
uri = new Uri("ms-appx:///" + uri.OriginalString.TrimStart('/'));
}
try
{
await LoadImageAsync(uri, tokenSource.Token).ConfigureAwait(true);
}
catch (OperationCanceledException)
{
// nothing to do as cancellation has been requested.
}
catch (Exception e)
{
VisualStateManager.GoToState(this, FailedState, true);
ImageExFailed?.Invoke(this, new ImageExFailedEventArgs(e));
}
}
private async Task LoadImageAsync(Uri imageUri, CancellationToken token)
{
if (imageUri is not null)
{
if (IsCacheEnabled)
{
ImageSource? img = await ProvideCachedResourceAsync(imageUri, token).ConfigureAwait(true);
ArgumentNullException.ThrowIfNull(tokenSource);
if (!tokenSource.IsCancellationRequested)
{
// Only attach our image if we still have a valid request.
AttachSource(img);
}
}
else if (string.Equals(imageUri.Scheme, "data", StringComparison.OrdinalIgnoreCase))
{
string source = imageUri.OriginalString;
const string base64Head = "base64,";
int index = source.IndexOf(base64Head, StringComparison.Ordinal);
if (index >= 0)
{
byte[] bytes = Convert.FromBase64String(source[(index + base64Head.Length)..]);
BitmapImage bitmap = new();
await bitmap.SetSourceAsync(new MemoryStream(bytes).AsRandomAccessStream());
ArgumentNullException.ThrowIfNull(tokenSource);
if (!tokenSource.IsCancellationRequested)
{
AttachSource(bitmap);
}
}
}
else
{
AttachSource(new BitmapImage(imageUri)
{
CreateOptions = BitmapCreateOptions.IgnoreImageCache,
});
}
}
}
private void ImageExBase_LayoutUpdated(object? sender, object e)
{
InvalidateLazyLoading();
}
private void InvalidateLazyLoading()
{
if (!IsLoaded)
{
isInViewport = false;
return;
}
// Find the first ascendant ScrollViewer, if not found, use the root element.
FrameworkElement? hostElement = default;
IEnumerable<FrameworkElement> ascendants = this.FindAscendants().OfType<FrameworkElement>();
foreach (FrameworkElement ascendant in ascendants)
{
hostElement = ascendant;
if (hostElement is Microsoft.UI.Xaml.Controls.ScrollViewer)
{
break;
}
}
if (hostElement is null)
{
isInViewport = false;
return;
}
Rect controlRect = TransformToVisual(hostElement)
.TransformBounds(new Rect(0, 0, ActualWidth, ActualHeight));
double lazyLoadingThreshold = LazyLoadingThreshold;
Rect hostRect = new(
0 - lazyLoadingThreshold,
0 - lazyLoadingThreshold,
hostElement.ActualWidth + (2 * lazyLoadingThreshold),
hostElement.ActualHeight + (2 * lazyLoadingThreshold));
if (controlRect.IntersectsWith(hostRect))
{
isInViewport = true;
if (lazyLoadingSource is not null)
{
object source = lazyLoadingSource;
lazyLoadingSource = null;
SetSource(source);
}
}
else
{
isInViewport = false;
}
}
}

View File

@@ -0,0 +1,17 @@
// Copyright (c) DGP Studio. All rights reserved.
// Licensed under the MIT license.
namespace Snap.Hutao.Control.Image.Implementation;
internal sealed class ImageExFailedEventArgs : EventArgs
{
public ImageExFailedEventArgs(Exception errorException)
{
ErrorMessage = ErrorException?.Message;
ErrorException = errorException;
}
public Exception? ErrorException { get; private set; }
public string? ErrorMessage { get; private set; }
}

View File

@@ -0,0 +1,8 @@
// Copyright (c) DGP Studio. All rights reserved.
// Licensed under the MIT license.
namespace Snap.Hutao.Control.Image.Implementation;
internal sealed class ImageExOpenedEventArgs : EventArgs
{
}

View File

@@ -0,0 +1,48 @@
// Copyright (c) DGP Studio. All rights reserved.
// Licensed under the MIT license.
using Microsoft.UI.Xaml;
namespace Snap.Hutao.Control;
[TemplateVisualState(Name = "LoadingIn", GroupName = "CommonStates")]
[TemplateVisualState(Name = "LoadingOut", GroupName = "CommonStates")]
internal class Loading : Microsoft.UI.Xaml.Controls.ContentControl
{
public static readonly DependencyProperty IsLoadingProperty = DependencyProperty.Register(nameof(IsLoading), typeof(bool), typeof(Loading), new PropertyMetadata(default(bool), IsLoadingPropertyChanged));
[SuppressMessage("", "IDE0052")]
private FrameworkElement? presenter;
public Loading()
{
DefaultStyleKey = typeof(Loading);
DefaultStyleResourceUri = new("ms-appx:///Control/Loading.xaml");
}
public bool IsLoading
{
get => (bool)GetValue(IsLoadingProperty);
set => SetValue(IsLoadingProperty, value);
}
protected override void OnApplyTemplate()
{
base.OnApplyTemplate();
Update();
}
private static void IsLoadingPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
Loading control = (Loading)d;
control.presenter ??= control.GetTemplateChild("ContentGrid") as FrameworkElement;
control?.Update();
}
private void Update()
{
VisualStateManager.GoToState(this, IsLoading ? "LoadingIn" : "LoadingOut", true);
}
}

View File

@@ -0,0 +1,85 @@
<ResourceDictionary
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:shc="using:Snap.Hutao.Control">
<Style TargetType="shc:Loading">
<Setter Property="HorizontalContentAlignment" Value="Center"/>
<Setter Property="VerticalContentAlignment" Value="Center"/>
<Setter Property="HorizontalAlignment" Value="Stretch"/>
<Setter Property="VerticalAlignment" Value="Stretch"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="shc:Loading">
<Border
x:Name="RootGrid"
Background="{TemplateBinding Background}"
BorderBrush="{TemplateBinding BorderBrush}"
BorderThickness="{TemplateBinding BorderThickness}"
Opacity="0"
Visibility="Collapsed">
<ContentPresenter
x:Name="ContentGrid"
HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}"
VerticalAlignment="{TemplateBinding VerticalContentAlignment}">
<ContentPresenter.RenderTransform>
<CompositeTransform/>
</ContentPresenter.RenderTransform>
</ContentPresenter>
<VisualStateManager.VisualStateGroups>
<VisualStateGroup x:Name="CommonStates">
<VisualState x:Name="LoadingIn">
<Storyboard>
<DoubleAnimationUsingKeyFrames Storyboard.TargetName="RootGrid" Storyboard.TargetProperty="Opacity">
<EasingDoubleKeyFrame KeyTime="0:0:0" Value="0">
<EasingDoubleKeyFrame.EasingFunction>
<QuadraticEase EasingMode="EaseInOut"/>
</EasingDoubleKeyFrame.EasingFunction>
</EasingDoubleKeyFrame>
<EasingDoubleKeyFrame KeyTime="0:0:0.3" Value="1">
<EasingDoubleKeyFrame.EasingFunction>
<QuadraticEase EasingMode="EaseInOut"/>
</EasingDoubleKeyFrame.EasingFunction>
</EasingDoubleKeyFrame>
</DoubleAnimationUsingKeyFrames>
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="RootGrid" Storyboard.TargetProperty="Visibility">
<DiscreteObjectKeyFrame KeyTime="0:0:0">
<DiscreteObjectKeyFrame.Value>
<Visibility>Visible</Visibility>
</DiscreteObjectKeyFrame.Value>
</DiscreteObjectKeyFrame>
</ObjectAnimationUsingKeyFrames>
</Storyboard>
</VisualState>
<VisualState x:Name="LoadingOut">
<Storyboard>
<DoubleAnimationUsingKeyFrames Storyboard.TargetName="RootGrid" Storyboard.TargetProperty="Opacity">
<EasingDoubleKeyFrame KeyTime="0:0:0" Value="1">
<EasingDoubleKeyFrame.EasingFunction>
<QuadraticEase EasingMode="EaseInOut"/>
</EasingDoubleKeyFrame.EasingFunction>
</EasingDoubleKeyFrame>
<EasingDoubleKeyFrame KeyTime="0:0:0.3" Value="0">
<EasingDoubleKeyFrame.EasingFunction>
<QuadraticEase EasingMode="EaseInOut"/>
</EasingDoubleKeyFrame.EasingFunction>
</EasingDoubleKeyFrame>
</DoubleAnimationUsingKeyFrames>
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="RootGrid" Storyboard.TargetProperty="Visibility">
<DiscreteObjectKeyFrame KeyTime="0:0:0.3">
<DiscreteObjectKeyFrame.Value>
<Visibility>Collapsed</Visibility>
</DiscreteObjectKeyFrame.Value>
</DiscreteObjectKeyFrame>
</ObjectAnimationUsingKeyFrames>
</Storyboard>
</VisualState>
</VisualStateGroup>
</VisualStateManager.VisualStateGroups>
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</ResourceDictionary>

View File

@@ -12,7 +12,6 @@ internal sealed class Int32Extension : MarkupExtension
protected override object ProvideValue()
{
_ = int.TryParse(Value, out int result);
return result;
return XamlBindingHelper.ConvertValue(typeof(int), Value);
}
}

View File

@@ -1,7 +1,6 @@
// Copyright (c) DGP Studio. All rights reserved.
// Licensed under the MIT license.
using Microsoft.UI.Xaml.Media;
using System.Buffers.Binary;
using System.Runtime.CompilerServices;
using Windows.UI;

View File

@@ -39,7 +39,7 @@ internal struct Rgba32
/// </summary>
/// <param name="hex">色值字符串</param>
public Rgba32(string hex)
: this(Convert.ToUInt32(hex, 16))
: this(hex.Length == 6 ? Convert.ToUInt32($"{hex}FF", 16) : Convert.ToUInt32(hex, 16))
{
}

View File

@@ -1,45 +0,0 @@
// Copyright (c) DGP Studio. All rights reserved.
// Licensed under the MIT license.
using Windows.Foundation;
namespace Snap.Hutao.Control.Panel;
/// <summary>
/// 纵横比控件
/// </summary>
[HighQuality]
[DependencyProperty("TargetWidth", typeof(double), 1.0D)]
[DependencyProperty("TargetHeight", typeof(double), 1.0D)]
internal sealed partial class AspectRatio : Microsoft.UI.Xaml.Controls.Control
{
private const double Epsilon = 2.2204460492503131e-016;
/// <inheritdoc/>
protected override Size MeasureOverride(Size availableSize)
{
double ratio = TargetWidth / TargetHeight;
double ratioAvailable = availableSize.Width / availableSize.Height;
if (Math.Abs(ratioAvailable - ratio) < Epsilon)
{
return availableSize;
}
// 更宽
if (ratioAvailable > ratio)
{
double newWidth = ratio * availableSize.Height;
return new Size(newWidth, availableSize.Height);
}
// 更高
if (ratioAvailable < ratio)
{
double newHeight = availableSize.Width / ratio;
return new Size(availableSize.Width, newHeight);
}
return availableSize;
}
}

View File

@@ -20,6 +20,7 @@ namespace Snap.Hutao.Control.Text;
/// </summary>
[HighQuality]
[DependencyProperty("Description", typeof(string), "", nameof(OnDescriptionChanged))]
[DependencyProperty("TextStyle", typeof(Style), default(Style), nameof(OnTextStyleChanged))]
internal sealed partial class DescriptionTextBlock : ContentControl
{
private static readonly int ColorTagFullLength = "<color=#FFFFFFFF></color>".Length;
@@ -40,6 +41,7 @@ internal sealed partial class DescriptionTextBlock : ContentControl
Content = new TextBlock()
{
TextWrapping = TextWrapping.Wrap,
Style = TextStyle,
};
actualThemeChangedEventHandler = OnActualThemeChanged;
@@ -54,6 +56,12 @@ internal sealed partial class DescriptionTextBlock : ContentControl
UpdateDescription(textBlock, description);
}
private static void OnTextStyleChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
TextBlock textBlock = (TextBlock)((DescriptionTextBlock)d).Content;
textBlock.Style = (Style)e.NewValue;
}
private static void UpdateDescription(TextBlock textBlock, in ReadOnlySpan<char> description)
{
textBlock.Inlines.Clear();
@@ -66,7 +74,7 @@ internal sealed partial class DescriptionTextBlock : ContentControl
{
AppendText(textBlock, description[last..i]);
AppendLineBreak(textBlock);
i += 1;
i += 2;
last = i;
}

View File

@@ -0,0 +1,182 @@
// Copyright (c) DGP Studio. All rights reserved.
// Licensed under the MIT license.
using Microsoft.UI.Text;
using Microsoft.UI.Xaml;
using Microsoft.UI.Xaml.Controls;
using Microsoft.UI.Xaml.Documents;
using Microsoft.UI.Xaml.Media;
using Snap.Hutao.Control.Extension;
using Snap.Hutao.Control.Media;
using Snap.Hutao.Control.Theme;
using Windows.Foundation;
using Windows.UI;
namespace Snap.Hutao.Control.Text;
[DependencyProperty("Description", typeof(string), "", nameof(OnDescriptionChanged))]
[DependencyProperty("TextStyle", typeof(Style), default(Style), nameof(OnTextStyleChanged))]
internal sealed partial class HtmlDescriptionTextBlock : ContentControl
{
private static readonly int ColorTagFullLength = "<color style='color:#FFFFFF;'></color>".Length;
private static readonly int ColorTagLeftLength = "<color style='color:#FFFFFF;'>".Length;
private static readonly int ItalicTagFullLength = "<i></i>".Length;
private static readonly int ItalicTagLeftLength = "<i>".Length;
private static readonly int BoldTagFullLength = "<b></b>".Length;
private static readonly int BoldTagLeftLength = "<b>".Length;
private readonly TypedEventHandler<FrameworkElement, object> actualThemeChangedEventHandler;
/// <summary>
/// 构造一个新的呈现描述文本的文本块
/// </summary>
public HtmlDescriptionTextBlock()
{
this.DisableInteraction();
Content = new TextBlock()
{
TextWrapping = TextWrapping.Wrap,
Style = TextStyle,
};
actualThemeChangedEventHandler = OnActualThemeChanged;
ActualThemeChanged += actualThemeChangedEventHandler;
}
private static void OnDescriptionChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
TextBlock textBlock = (TextBlock)((HtmlDescriptionTextBlock)d).Content;
ReadOnlySpan<char> description = (string)e.NewValue;
UpdateDescription(textBlock, description);
}
private static void OnTextStyleChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
TextBlock textBlock = (TextBlock)((HtmlDescriptionTextBlock)d).Content;
textBlock.Style = (Style)e.NewValue;
}
private static void UpdateDescription(TextBlock textBlock, in ReadOnlySpan<char> description)
{
textBlock.Inlines.Clear();
int last = 0;
for (int i = 0; i < description.Length;)
{
// newline
if (description[i..].StartsWith(@"<br>"))
{
AppendText(textBlock, description[last..i]);
AppendLineBreak(textBlock);
i += 4;
last = i;
}
// color tag
else if (description[i..].StartsWith("<c"))
{
AppendText(textBlock, description[last..i]);
string a = description.Slice(i + 21, 6).ToString();
Rgba32 color = new(a);
int length = description[(i + ColorTagLeftLength)..].IndexOf('<');
AppendColorText(textBlock, description.Slice(i + ColorTagLeftLength, length), color);
i += length + ColorTagFullLength;
last = i;
}
// italic
else if (description[i..].StartsWith("<i"))
{
AppendText(textBlock, description[last..i]);
int length = description[(i + ItalicTagLeftLength)..].IndexOf('<');
AppendItalicText(textBlock, description.Slice(i + ItalicTagLeftLength, length));
i += length + ItalicTagFullLength;
last = i;
}
// bold
else if (description[i..].StartsWith("<b"))
{
AppendText(textBlock, description[last..i]);
int length = description[(i + BoldTagLeftLength)..].IndexOf('<');
AppendBoldText(textBlock, description.Slice(i + BoldTagLeftLength, length));
i += length + BoldTagFullLength;
last = i;
}
else
{
i += 1;
}
if (i == description.Length - 1)
{
AppendText(textBlock, description[last..(i + 1)]);
}
}
}
private static void AppendText(TextBlock text, in ReadOnlySpan<char> slice)
{
text.Inlines.Add(new Run { Text = slice.ToString() });
}
private static void AppendColorText(TextBlock text, in ReadOnlySpan<char> slice, Rgba32 color)
{
Color targetColor;
if (ThemeHelper.IsDarkMode(text.ActualTheme))
{
targetColor = color;
}
else
{
// Make lighter in light mode
Hsl32 hsl = color.ToHsl();
hsl.L *= 0.3;
targetColor = Rgba32.FromHsl(hsl);
}
text.Inlines.Add(new Run
{
Text = slice.ToString(),
Foreground = new SolidColorBrush(targetColor),
});
}
private static void AppendBoldText(TextBlock text, in ReadOnlySpan<char> slice)
{
text.Inlines.Add(new Run
{
Text = slice.ToString(),
FontWeight = FontWeights.Bold,
});
}
private static void AppendItalicText(TextBlock text, in ReadOnlySpan<char> slice)
{
text.Inlines.Add(new Run
{
Text = slice.ToString(),
FontStyle = Windows.UI.Text.FontStyle.Italic,
});
}
private static void AppendLineBreak(TextBlock text)
{
text.Inlines.Add(new LineBreak());
}
private void OnActualThemeChanged(FrameworkElement sender, object args)
{
// Simply re-apply texts
UpdateDescription((TextBlock)Content, Description);
}
}

View File

@@ -0,0 +1,21 @@
<ResourceDictionary
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:cwm="using:CommunityToolkit.WinUI.Media">
<Style x:Key="BorderCardStyle" TargetType="Border">
<Setter Property="Background" Value="{ThemeResource CardBackgroundFillColorDefaultBrush}"/>
<Setter Property="BorderBrush" Value="{ThemeResource CardStrokeColorDefaultBrush}"/>
<Setter Property="BorderThickness" Value="1"/>
<Setter Property="CornerRadius" Value="{ThemeResource ControlCornerRadius}"/>
</Style>
<Style x:Key="GridCardStyle" TargetType="Grid">
<Setter Property="Background" Value="{ThemeResource CardBackgroundFillColorDefaultBrush}"/>
<Setter Property="BorderBrush" Value="{ThemeResource CardStrokeColorDefaultBrush}"/>
<Setter Property="BorderThickness" Value="1"/>
<Setter Property="CornerRadius" Value="{ThemeResource ControlCornerRadius}"/>
</Style>
<cwm:AttachedCardShadow
x:Key="CompatCardShadow"
Opacity="0.1"
Offset="0,4,0"/>
</ResourceDictionary>

View File

@@ -0,0 +1,31 @@
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<ResourceDictionary.ThemeDictionaries>
<ResourceDictionary x:Key="Light">
<Color x:Key="AvatarPropertyAddValueColor">#FF74BF00</Color>
<Color x:Key="CompatBackgroundColor">#FFF4F4F4</Color>
<Color x:Key="DarkOnlyOverlayMaskColor">#00000000</Color>
</ResourceDictionary>
<ResourceDictionary x:Key="Dark">
<Color x:Key="AvatarPropertyAddValueColor">#FF90E800</Color>
<Color x:Key="CompatBackgroundColor">#FF242424</Color>
<Color x:Key="DarkOnlyOverlayMaskColor">#60000000</Color>
</ResourceDictionary>
</ResourceDictionary.ThemeDictionaries>
<Color x:Key="BlueColor">#FF5180CB</Color>
<Color x:Key="PurpleColor">#FFA156E0</Color>
<Color x:Key="OrangeColor">#FFBC6932</Color>
<Color x:Key="GuaranteePullColor">#FF0063FF</Color>
<Color x:Key="UpPullColor">#FFFFA400</Color>
<SolidColorBrush x:Key="BlueColorBrush" Color="{ThemeResource BlueColor}"/>
<SolidColorBrush x:Key="PurpleColorBrush" Color="{ThemeResource PurpleColor}"/>
<SolidColorBrush x:Key="OrangeColorBrush" Color="{ThemeResource OrangeColor}"/>
<SolidColorBrush x:Key="GuaranteePullCoolorBrush" Color="{ThemeResource GuaranteePullColor}"/>
<SolidColorBrush x:Key="UpPullColorBrush" Color="{ThemeResource UpPullColor}"/>
<SolidColorBrush x:Key="DarkOnlyOverlayMaskColorBrush" Color="{ThemeResource DarkOnlyOverlayMaskColor}"/>
<SolidColorBrush x:Key="AvatarPropertyAddValueColorBrush" Color="{ThemeResource AvatarPropertyAddValueColor}"/>
</ResourceDictionary>

View File

@@ -0,0 +1,35 @@
<ResourceDictionary
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:cwc="using:CommunityToolkit.WinUI.Converters"
xmlns:shmmc="using:Snap.Hutao.Model.Metadata.Converter"
xmlns:shvc="using:Snap.Hutao.View.Converter">
<cwc:BoolNegationConverter x:Key="BoolNegationConverter"/>
<cwc:BoolToVisibilityConverter x:Key="BoolToVisibilityConverter"/>
<cwc:FileSizeToFriendlyStringConverter x:Key="FileSizeToFriendlyStringConverter"/>
<shmmc:AchievementIconConverter x:Key="AchievementIconConverter"/>
<shmmc:AvatarCardConverter x:Key="AvatarCardConverter"/>
<shmmc:AvatarIconConverter x:Key="AvatarIconConverter"/>
<shmmc:AvatarNameCardPicConverter x:Key="AvatarNameCardPicConverter"/>
<shmmc:AvatarSideIconConverter x:Key="AvatarSideIconConverter"/>
<shmmc:DescriptionsParametersDescriptor x:Key="DescParamDescriptor"/>
<shmmc:ElementNameIconConverter x:Key="ElementNameIconConverter"/>
<shmmc:EmotionIconConverter x:Key="EmotionIconConverter"/>
<shmmc:EquipIconConverter x:Key="EquipIconConverter"/>
<shmmc:GachaAvatarImgConverter x:Key="GachaAvatarImgConverter"/>
<shmmc:GachaAvatarIconConverter x:Key="GachaAvatarIconConverter"/>
<shmmc:GachaEquipIconConverter x:Key="GachaEquipIconConverter"/>
<shmmc:ItemIconConverter x:Key="ItemIconConverter"/>
<shmmc:MonsterIconConverter x:Key="MonsterIconConverter"/>
<shmmc:PropertiesParametersDescriptor x:Key="PropertyDescriptor"/>
<shmmc:QualityColorConverter x:Key="QualityColorConverter"/>
<shmmc:WeaponTypeIconConverter x:Key="WeaponTypeIconConverter"/>
<shvc:BoolToVisibilityRevertConverter x:Key="BoolToVisibilityRevertConverter"/>
<shvc:EmptyObjectToBoolConverter x:Key="EmptyObjectToBoolConverter"/>
<shvc:EmptyObjectToBoolRevertConverter x:Key="EmptyObjectToBoolRevertConverter"/>
<shvc:EmptyObjectToVisibilityConverter x:Key="EmptyObjectToVisibilityConverter"/>
<shvc:EmptyObjectToVisibilityRevertConverter x:Key="EmptyObjectToVisibilityRevertConverter"/>
<shvc:Int32ToVisibilityConverter x:Key="Int32ToVisibilityConverter"/>
<shvc:Int32ToVisibilityRevertConverter x:Key="Int32ToVisibilityRevertConverter"/>
<shvc:StringBoolConverter x:Key="StringBoolConverter"/>
</ResourceDictionary>

View File

@@ -0,0 +1,4 @@
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<CornerRadius x:Key="ControlCornerRadiusTop">4,4,0,0</CornerRadius>
<CornerRadius x:Key="ControlCornerRadiusBottom">0,0,4,4</CornerRadius>
</ResourceDictionary>

View File

@@ -1,4 +1,7 @@
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<ResourceDictionary.MergedDictionaries>
<XamlControlsResources/>
</ResourceDictionary.MergedDictionaries>
<FontFamily x:Key="MiSans">ms-appx:///Resource/Font/MiSans-Regular.ttf#MiSans</FontFamily>
<FontFamily x:Key="CascadiaMonoAndMiSans">ms-appx:///Resource/Font/CascadiaMono.ttf#Cascadia Mono, ms-appx:///Resource/Font/MiSans-Regular.ttf#MiSans</FontFamily>
@@ -79,13 +82,6 @@
<Setter Property="OpticalMarginAlignment" Value="TrimSideBearings"/>
</Style>
<x:Double x:Key="SecondaryTextFontSize">12</x:Double>
<Style x:Key="SecondaryTextStyle" TargetType="TextBlock">
<Setter Property="FontSize" Value="{StaticResource SecondaryTextFontSize}"/>
<Setter Property="Foreground" Value="{ThemeResource TextFillColorSecondaryBrush}"/>
</Style>
<Style BasedOn="{StaticResource DefaultMenuFlyoutItemStyle}" TargetType="MenuFlyoutItem">
<Setter Property="FontFamily" Value="{StaticResource MiSans}"/>
</Style>
@@ -97,273 +93,4 @@
<Style BasedOn="{StaticResource DefaultScrollViewerStyle}" TargetType="ScrollViewer">
<Setter Property="FontFamily" Value="{StaticResource MiSans}"/>
</Style>
<!-- TODO: When will DefaultInfoBarStyle added -->
<Style TargetType="InfoBar">
<Setter Property="FontFamily" Value="{StaticResource MiSans}"/>
<Setter Property="IsTabStop" Value="False"/>
<Setter Property="CloseButtonStyle" Value="{StaticResource InfoBarCloseButtonStyle}"/>
<Setter Property="Background" Value="Transparent"/>
<Setter Property="BorderBrush" Value="{ThemeResource InfoBarBorderBrush}"/>
<Setter Property="BorderThickness" Value="{ThemeResource InfoBarBorderThickness}"/>
<Setter Property="AutomationProperties.LandmarkType" Value="Custom"/>
<Setter Property="AutomationProperties.IsDialog" Value="True"/>
<Setter Property="CornerRadius" Value="{ThemeResource ControlCornerRadius}"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="InfoBar">
<Border
x:Name="ContentRoot"
VerticalAlignment="Top"
Background="{ThemeResource InfoBarInformationalSeverityBackgroundBrush}"
BorderBrush="{TemplateBinding BorderBrush}"
BorderThickness="{TemplateBinding BorderThickness}"
CornerRadius="{TemplateBinding CornerRadius}">
<!-- Background is used here so that it overrides the severity status color if set. -->
<Grid
MinHeight="{ThemeResource InfoBarMinHeight}"
Padding="{StaticResource InfoBarContentRootPadding}"
HorizontalAlignment="Stretch"
Background="{TemplateBinding Background}"
CornerRadius="{TemplateBinding CornerRadius}">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto"/>
<!-- Icon -->
<ColumnDefinition Width="*"/>
<!-- Title, message, and action -->
<ColumnDefinition Width="Auto"/>
<!-- Close button -->
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<Grid x:Name="StandardIconArea" Visibility="Collapsed">
<TextBlock
x:Name="IconBackground"
Grid.Column="0"
Margin="{StaticResource InfoBarIconMargin}"
VerticalAlignment="Top"
AutomationProperties.AccessibilityView="Raw"
FontFamily="{ThemeResource SymbolThemeFontFamily}"
FontSize="{StaticResource InfoBarIconFontSize}"
Foreground="{ThemeResource InfoBarInformationalSeverityIconBackground}"
Text="{StaticResource InfoBarIconBackgroundGlyph}"/>
<TextBlock
x:Name="StandardIcon"
Grid.Column="0"
Margin="{StaticResource InfoBarIconMargin}"
VerticalAlignment="Top"
FontFamily="{ThemeResource SymbolThemeFontFamily}"
FontSize="{StaticResource InfoBarIconFontSize}"
Foreground="{ThemeResource InfoBarInformationalSeverityIconForeground}"
Text="{StaticResource InfoBarInformationalIconGlyph}"/>
</Grid>
<Viewbox
x:Name="UserIconBox"
Grid.Column="0"
MaxWidth="{ThemeResource InfoBarIconFontSize}"
MaxHeight="{ThemeResource InfoBarIconFontSize}"
Margin="{ThemeResource InfoBarIconMargin}"
VerticalAlignment="Top"
Child="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=TemplateSettings.IconElement}"
Visibility="Collapsed"/>
<InfoBarPanel
Grid.Column="1"
Margin="{StaticResource InfoBarPanelMargin}"
HorizontalOrientationPadding="{StaticResource InfoBarPanelHorizontalOrientationPadding}"
VerticalOrientationPadding="{StaticResource InfoBarPanelVerticalOrientationPadding}">
<TextBlock
x:Name="Title"
FontSize="{StaticResource InfoBarTitleFontSize}"
FontWeight="{StaticResource InfoBarTitleFontWeight}"
Foreground="{ThemeResource InfoBarTitleForeground}"
InfoBarPanel.HorizontalOrientationMargin="{StaticResource InfoBarTitleHorizontalOrientationMargin}"
InfoBarPanel.VerticalOrientationMargin="{StaticResource InfoBarTitleVerticalOrientationMargin}"
Text="{TemplateBinding Title}"
TextWrapping="WrapWholeWords"/>
<TextBlock
x:Name="Message"
FontSize="{StaticResource InfoBarMessageFontSize}"
FontWeight="{StaticResource InfoBarMessageFontWeight}"
Foreground="{ThemeResource InfoBarMessageForeground}"
InfoBarPanel.HorizontalOrientationMargin="{StaticResource InfoBarMessageHorizontalOrientationMargin}"
InfoBarPanel.VerticalOrientationMargin="{StaticResource InfoBarMessageVerticalOrientationMargin}"
Text="{TemplateBinding Message}"
TextWrapping="WrapWholeWords"/>
<ContentPresenter
VerticalAlignment="Top"
Content="{TemplateBinding ActionButton}"
InfoBarPanel.HorizontalOrientationMargin="{StaticResource InfoBarActionHorizontalOrientationMargin}"
InfoBarPanel.VerticalOrientationMargin="{StaticResource InfoBarActionVerticalOrientationMargin}">
<ContentPresenter.Resources>
<Style BasedOn="{StaticResource DefaultHyperlinkButtonStyle}" TargetType="HyperlinkButton">
<Style.Setters>
<Setter Property="Margin" Value="{StaticResource InfoBarHyperlinkButtonMargin}"/>
<Setter Property="Foreground" Value="{ThemeResource InfoBarHyperlinkButtonForeground}"/>
</Style.Setters>
</Style>
</ContentPresenter.Resources>
</ContentPresenter>
</InfoBarPanel>
<ContentPresenter
Grid.Row="1"
Grid.Column="1"
Content="{TemplateBinding Content}"
ContentTemplate="{TemplateBinding ContentTemplate}"/>
<Button
Name="CloseButton"
Grid.Column="2"
Command="{TemplateBinding CloseButtonCommand}"
CommandParameter="{TemplateBinding CloseButtonCommandParameter}"
Style="{TemplateBinding CloseButtonStyle}">
<Button.Resources>
<ResourceDictionary>
<ResourceDictionary.ThemeDictionaries>
<ResourceDictionary x:Key="Default">
<StaticResource x:Key="ButtonBackground" ResourceKey="AppBarButtonBackground"/>
<StaticResource x:Key="ButtonBackgroundPointerOver" ResourceKey="AppBarButtonBackgroundPointerOver"/>
<StaticResource x:Key="ButtonBackgroundPressed" ResourceKey="AppBarButtonBackgroundPressed"/>
<StaticResource x:Key="ButtonBackgroundDisabled" ResourceKey="AppBarButtonBackgroundDisabled"/>
<StaticResource x:Key="ButtonForeground" ResourceKey="AppBarButtonForeground"/>
<StaticResource x:Key="ButtonForegroundPointerOver" ResourceKey="AppBarButtonForegroundPointerOver"/>
<StaticResource x:Key="ButtonForegroundPressed" ResourceKey="AppBarButtonForegroundPressed"/>
<StaticResource x:Key="ButtonForegroundDisabled" ResourceKey="AppBarButtonForegroundDisabled"/>
<StaticResource x:Key="ButtonBorderBrush" ResourceKey="AppBarButtonBorderBrush"/>
<StaticResource x:Key="ButtonBorderBrushPointerOver" ResourceKey="AppBarButtonBorderBrushPointerOver"/>
<StaticResource x:Key="ButtonBorderBrushPressed" ResourceKey="AppBarButtonBorderBrushPressed"/>
<StaticResource x:Key="ButtonBorderBrushDisabled" ResourceKey="AppBarButtonBorderBrushDisabled"/>
</ResourceDictionary>
<ResourceDictionary x:Key="HighContrast">
<StaticResource x:Key="ButtonBackground" ResourceKey="AppBarButtonBackground"/>
<StaticResource x:Key="ButtonBackgroundPointerOver" ResourceKey="AppBarButtonBackgroundPointerOver"/>
<StaticResource x:Key="ButtonBackgroundPressed" ResourceKey="AppBarButtonBackgroundPressed"/>
<StaticResource x:Key="ButtonBackgroundDisabled" ResourceKey="AppBarButtonBackgroundDisabled"/>
<StaticResource x:Key="ButtonForeground" ResourceKey="AppBarButtonForeground"/>
<StaticResource x:Key="ButtonForegroundPointerOver" ResourceKey="AppBarButtonForegroundPointerOver"/>
<StaticResource x:Key="ButtonForegroundPressed" ResourceKey="AppBarButtonForegroundPressed"/>
<StaticResource x:Key="ButtonForegroundDisabled" ResourceKey="AppBarButtonForegroundDisabled"/>
<StaticResource x:Key="ButtonBorderBrush" ResourceKey="AppBarButtonBorderBrush"/>
<StaticResource x:Key="ButtonBorderBrushPointerOver" ResourceKey="AppBarButtonBorderBrushPointerOver"/>
<StaticResource x:Key="ButtonBorderBrushPressed" ResourceKey="AppBarButtonBorderBrushPressed"/>
<StaticResource x:Key="ButtonBorderBrushDisabled" ResourceKey="AppBarButtonBorderBrushDisabled"/>
</ResourceDictionary>
<ResourceDictionary x:Key="Light">
<StaticResource x:Key="ButtonBackground" ResourceKey="AppBarButtonBackground"/>
<StaticResource x:Key="ButtonBackgroundPointerOver" ResourceKey="AppBarButtonBackgroundPointerOver"/>
<StaticResource x:Key="ButtonBackgroundPressed" ResourceKey="AppBarButtonBackgroundPressed"/>
<StaticResource x:Key="ButtonBackgroundDisabled" ResourceKey="AppBarButtonBackgroundDisabled"/>
<StaticResource x:Key="ButtonForeground" ResourceKey="AppBarButtonForeground"/>
<StaticResource x:Key="ButtonForegroundPointerOver" ResourceKey="AppBarButtonForegroundPointerOver"/>
<StaticResource x:Key="ButtonForegroundPressed" ResourceKey="AppBarButtonForegroundPressed"/>
<StaticResource x:Key="ButtonForegroundDisabled" ResourceKey="AppBarButtonForegroundDisabled"/>
<StaticResource x:Key="ButtonBorderBrush" ResourceKey="AppBarButtonBorderBrush"/>
<StaticResource x:Key="ButtonBorderBrushPointerOver" ResourceKey="AppBarButtonBorderBrushPointerOver"/>
<StaticResource x:Key="ButtonBorderBrushPressed" ResourceKey="AppBarButtonBorderBrushPressed"/>
<StaticResource x:Key="ButtonBorderBrushDisabled" ResourceKey="AppBarButtonBorderBrushDisabled"/>
</ResourceDictionary>
</ResourceDictionary.ThemeDictionaries>
</ResourceDictionary>
</Button.Resources>
<Viewbox
Width="{StaticResource InfoBarCloseButtonGlyphSize}"
Height="{StaticResource InfoBarCloseButtonGlyphSize}"
HorizontalAlignment="Center"
VerticalAlignment="Center">
<SymbolIcon Symbol="{StaticResource InfoBarCloseButtonSymbol}"/>
</Viewbox>
</Button>
</Grid>
<VisualStateManager.VisualStateGroups>
<VisualStateGroup x:Name="SeverityLevels">
<VisualState x:Name="Informational"/>
<VisualState x:Name="Error">
<VisualState.Setters>
<Setter Target="ContentRoot.Background" Value="{ThemeResource InfoBarErrorSeverityBackgroundBrush}"/>
<Setter Target="IconBackground.Foreground" Value="{ThemeResource InfoBarErrorSeverityIconBackground}"/>
<Setter Target="StandardIcon.Text" Value="{StaticResource InfoBarErrorIconGlyph}"/>
<Setter Target="StandardIcon.Foreground" Value="{ThemeResource InfoBarErrorSeverityIconForeground}"/>
</VisualState.Setters>
</VisualState>
<VisualState x:Name="Warning">
<VisualState.Setters>
<Setter Target="ContentRoot.Background" Value="{ThemeResource InfoBarWarningSeverityBackgroundBrush}"/>
<Setter Target="IconBackground.Foreground" Value="{ThemeResource InfoBarWarningSeverityIconBackground}"/>
<Setter Target="StandardIcon.Text" Value="{StaticResource InfoBarWarningIconGlyph}"/>
<Setter Target="StandardIcon.Foreground" Value="{ThemeResource InfoBarWarningSeverityIconForeground}"/>
</VisualState.Setters>
</VisualState>
<VisualState x:Name="Success">
<VisualState.Setters>
<Setter Target="ContentRoot.Background" Value="{ThemeResource InfoBarSuccessSeverityBackgroundBrush}"/>
<Setter Target="IconBackground.Foreground" Value="{ThemeResource InfoBarSuccessSeverityIconBackground}"/>
<Setter Target="StandardIcon.Text" Value="{StaticResource InfoBarSuccessIconGlyph}"/>
<Setter Target="StandardIcon.Foreground" Value="{ThemeResource InfoBarSuccessSeverityIconForeground}"/>
</VisualState.Setters>
</VisualState>
</VisualStateGroup>
<VisualStateGroup x:Name="IconStates">
<VisualState x:Name="StandardIconVisible">
<VisualState.Setters>
<Setter Target="UserIconBox.Visibility" Value="Collapsed"/>
<Setter Target="StandardIconArea.Visibility" Value="Visible"/>
</VisualState.Setters>
</VisualState>
<VisualState x:Name="UserIconVisible">
<VisualState.Setters>
<Setter Target="UserIconBox.Visibility" Value="Visible"/>
<Setter Target="StandardIconArea.Visibility" Value="Collapsed"/>
</VisualState.Setters>
</VisualState>
<VisualState x:Name="NoIconVisible"/>
</VisualStateGroup>
<VisualStateGroup>
<VisualState x:Name="CloseButtonVisible"/>
<VisualState x:Name="CloseButtonCollapsed">
<VisualState.Setters>
<Setter Target="CloseButton.Visibility" Value="Collapsed"/>
</VisualState.Setters>
</VisualState>
</VisualStateGroup>
<VisualStateGroup x:Name="InfoBarVisibility">
<VisualState x:Name="InfoBarVisible"/>
<VisualState x:Name="InfoBarCollapsed">
<VisualState.Setters>
<Setter Target="ContentRoot.Visibility" Value="Collapsed"/>
</VisualState.Setters>
</VisualState>
</VisualStateGroup>
<VisualStateGroup>
<VisualState x:Name="ForegroundNotSet"/>
<VisualState x:Name="ForegroundSet">
<VisualState.Setters>
<Setter Target="Title.Foreground" Value="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=Foreground}"/>
<Setter Target="Message.Foreground" Value="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=Foreground}"/>
</VisualState.Setters>
</VisualState>
</VisualStateGroup>
</VisualStateManager.VisualStateGroups>
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</ResourceDictionary>
</ResourceDictionary>

View File

@@ -0,0 +1,10 @@
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<x:String x:Key="FontIconContentAdd">&#xE710;</x:String>
<x:String x:Key="FontIconContentSetting">&#xE713;</x:String>
<x:String x:Key="FontIconContentRefresh">&#xE72C;</x:String>
<x:String x:Key="FontIconContentDelete">&#xE74D;</x:String>
<x:String x:Key="FontIconContentFolder">&#xE8B7;</x:String>
<x:String x:Key="FontIconContentCheckList">&#xE9D5;</x:String>
<x:String x:Key="FontIconContentAsteriskBadge12">&#xEDAD;</x:String>
<x:String x:Key="FontIconContentZipFolder">&#xF012;</x:String>
</ResourceDictionary>

View File

@@ -0,0 +1,265 @@
<ResourceDictionary
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:shch="using:Snap.Hutao.Control.Helper">
<Thickness x:Key="InfoBarIconMargin">19,16,19,16</Thickness>
<Thickness x:Key="InfoBarContentRootPadding">0,0,0,0</Thickness>
<x:Double x:Key="InfoBarIconFontSize">20</x:Double>
<!-- TODO: When will DefaultInfoBarStyle added -->
<Style TargetType="InfoBar">
<Setter Property="shch:InfoBarHelper.IsTextSelectionEnabled" Value="False"/>
<Setter Property="FontFamily" Value="{StaticResource MiSans}"/>
<Setter Property="IsTabStop" Value="False"/>
<Setter Property="CloseButtonStyle" Value="{StaticResource InfoBarCloseButtonStyle}"/>
<Setter Property="Background" Value="Transparent"/>
<Setter Property="BorderBrush" Value="{ThemeResource InfoBarBorderBrush}"/>
<Setter Property="BorderThickness" Value="{ThemeResource InfoBarBorderThickness}"/>
<Setter Property="AutomationProperties.LandmarkType" Value="Custom"/>
<Setter Property="AutomationProperties.IsDialog" Value="True"/>
<Setter Property="CornerRadius" Value="{ThemeResource ControlCornerRadius}"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="InfoBar">
<Border
x:Name="ContentRoot"
VerticalAlignment="Top"
Background="{ThemeResource InfoBarInformationalSeverityBackgroundBrush}"
BorderBrush="{TemplateBinding BorderBrush}"
BorderThickness="{TemplateBinding BorderThickness}"
CornerRadius="{TemplateBinding CornerRadius}">
<!-- Background is used here so that it overrides the severity status color if set. -->
<Grid
MinHeight="{ThemeResource InfoBarMinHeight}"
Padding="{StaticResource InfoBarContentRootPadding}"
HorizontalAlignment="Stretch"
Background="{TemplateBinding Background}"
CornerRadius="{TemplateBinding CornerRadius}">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto"/>
<!-- Icon -->
<ColumnDefinition Width="*"/>
<!-- Title, message, and action -->
<ColumnDefinition Width="Auto"/>
<!-- Close button -->
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<Grid x:Name="StandardIconArea" Visibility="Collapsed">
<TextBlock
x:Name="IconBackground"
Grid.Column="0"
Margin="{StaticResource InfoBarIconMargin}"
VerticalAlignment="Top"
AutomationProperties.AccessibilityView="Raw"
FontFamily="{ThemeResource SymbolThemeFontFamily}"
FontSize="{StaticResource InfoBarIconFontSize}"
Foreground="{ThemeResource InfoBarInformationalSeverityIconBackground}"
Text="{StaticResource InfoBarIconBackgroundGlyph}"/>
<TextBlock
x:Name="StandardIcon"
Grid.Column="0"
Margin="{StaticResource InfoBarIconMargin}"
VerticalAlignment="Top"
FontFamily="{ThemeResource SymbolThemeFontFamily}"
FontSize="{StaticResource InfoBarIconFontSize}"
Foreground="{ThemeResource InfoBarInformationalSeverityIconForeground}"
Text="{StaticResource InfoBarInformationalIconGlyph}"/>
</Grid>
<Viewbox
x:Name="UserIconBox"
Grid.Column="0"
MaxWidth="{ThemeResource InfoBarIconFontSize}"
MaxHeight="{ThemeResource InfoBarIconFontSize}"
Margin="{ThemeResource InfoBarIconMargin}"
VerticalAlignment="Top"
Child="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=TemplateSettings.IconElement}"
Visibility="Collapsed"/>
<InfoBarPanel
Grid.Column="1"
Margin="{StaticResource InfoBarPanelMargin}"
HorizontalOrientationPadding="{StaticResource InfoBarPanelHorizontalOrientationPadding}"
VerticalOrientationPadding="{StaticResource InfoBarPanelVerticalOrientationPadding}">
<TextBlock
x:Name="Title"
FontSize="{StaticResource InfoBarTitleFontSize}"
FontWeight="{StaticResource InfoBarTitleFontWeight}"
Foreground="{ThemeResource InfoBarTitleForeground}"
InfoBarPanel.HorizontalOrientationMargin="{StaticResource InfoBarTitleHorizontalOrientationMargin}"
InfoBarPanel.VerticalOrientationMargin="{StaticResource InfoBarTitleVerticalOrientationMargin}"
IsTextSelectionEnabled="{TemplateBinding shch:InfoBarHelper.IsTextSelectionEnabled}"
Text="{TemplateBinding Title}"
TextWrapping="WrapWholeWords"/>
<TextBlock
x:Name="Message"
FontSize="{StaticResource InfoBarMessageFontSize}"
FontWeight="{StaticResource InfoBarMessageFontWeight}"
Foreground="{ThemeResource InfoBarMessageForeground}"
InfoBarPanel.HorizontalOrientationMargin="{StaticResource InfoBarMessageHorizontalOrientationMargin}"
InfoBarPanel.VerticalOrientationMargin="{StaticResource InfoBarMessageVerticalOrientationMargin}"
IsTextSelectionEnabled="{TemplateBinding shch:InfoBarHelper.IsTextSelectionEnabled}"
Text="{TemplateBinding Message}"
TextWrapping="WrapWholeWords"/>
<ContentPresenter
VerticalAlignment="Top"
Content="{TemplateBinding ActionButton}"
InfoBarPanel.HorizontalOrientationMargin="{StaticResource InfoBarActionHorizontalOrientationMargin}"
InfoBarPanel.VerticalOrientationMargin="{StaticResource InfoBarActionVerticalOrientationMargin}">
<ContentPresenter.Resources>
<Style BasedOn="{StaticResource DefaultHyperlinkButtonStyle}" TargetType="HyperlinkButton">
<Style.Setters>
<Setter Property="Margin" Value="{StaticResource InfoBarHyperlinkButtonMargin}"/>
<Setter Property="Foreground" Value="{ThemeResource InfoBarHyperlinkButtonForeground}"/>
</Style.Setters>
</Style>
</ContentPresenter.Resources>
</ContentPresenter>
</InfoBarPanel>
<ContentPresenter
Grid.Row="1"
Grid.Column="1"
Content="{TemplateBinding Content}"
ContentTemplate="{TemplateBinding ContentTemplate}"/>
<Button
Name="CloseButton"
Grid.Column="2"
Command="{TemplateBinding CloseButtonCommand}"
CommandParameter="{TemplateBinding CloseButtonCommandParameter}"
Style="{TemplateBinding CloseButtonStyle}">
<Button.Resources>
<ResourceDictionary>
<ResourceDictionary.ThemeDictionaries>
<ResourceDictionary x:Key="Default">
<StaticResource x:Key="ButtonBackground" ResourceKey="AppBarButtonBackground"/>
<StaticResource x:Key="ButtonBackgroundPointerOver" ResourceKey="AppBarButtonBackgroundPointerOver"/>
<StaticResource x:Key="ButtonBackgroundPressed" ResourceKey="AppBarButtonBackgroundPressed"/>
<StaticResource x:Key="ButtonBackgroundDisabled" ResourceKey="AppBarButtonBackgroundDisabled"/>
<StaticResource x:Key="ButtonForeground" ResourceKey="AppBarButtonForeground"/>
<StaticResource x:Key="ButtonForegroundPointerOver" ResourceKey="AppBarButtonForegroundPointerOver"/>
<StaticResource x:Key="ButtonForegroundPressed" ResourceKey="AppBarButtonForegroundPressed"/>
<StaticResource x:Key="ButtonForegroundDisabled" ResourceKey="AppBarButtonForegroundDisabled"/>
<StaticResource x:Key="ButtonBorderBrush" ResourceKey="AppBarButtonBorderBrush"/>
<StaticResource x:Key="ButtonBorderBrushPointerOver" ResourceKey="AppBarButtonBorderBrushPointerOver"/>
<StaticResource x:Key="ButtonBorderBrushPressed" ResourceKey="AppBarButtonBorderBrushPressed"/>
<StaticResource x:Key="ButtonBorderBrushDisabled" ResourceKey="AppBarButtonBorderBrushDisabled"/>
</ResourceDictionary>
<ResourceDictionary x:Key="HighContrast">
<StaticResource x:Key="ButtonBackground" ResourceKey="AppBarButtonBackground"/>
<StaticResource x:Key="ButtonBackgroundPointerOver" ResourceKey="AppBarButtonBackgroundPointerOver"/>
<StaticResource x:Key="ButtonBackgroundPressed" ResourceKey="AppBarButtonBackgroundPressed"/>
<StaticResource x:Key="ButtonBackgroundDisabled" ResourceKey="AppBarButtonBackgroundDisabled"/>
<StaticResource x:Key="ButtonForeground" ResourceKey="AppBarButtonForeground"/>
<StaticResource x:Key="ButtonForegroundPointerOver" ResourceKey="AppBarButtonForegroundPointerOver"/>
<StaticResource x:Key="ButtonForegroundPressed" ResourceKey="AppBarButtonForegroundPressed"/>
<StaticResource x:Key="ButtonForegroundDisabled" ResourceKey="AppBarButtonForegroundDisabled"/>
<StaticResource x:Key="ButtonBorderBrush" ResourceKey="AppBarButtonBorderBrush"/>
<StaticResource x:Key="ButtonBorderBrushPointerOver" ResourceKey="AppBarButtonBorderBrushPointerOver"/>
<StaticResource x:Key="ButtonBorderBrushPressed" ResourceKey="AppBarButtonBorderBrushPressed"/>
<StaticResource x:Key="ButtonBorderBrushDisabled" ResourceKey="AppBarButtonBorderBrushDisabled"/>
</ResourceDictionary>
<ResourceDictionary x:Key="Light">
<StaticResource x:Key="ButtonBackground" ResourceKey="AppBarButtonBackground"/>
<StaticResource x:Key="ButtonBackgroundPointerOver" ResourceKey="AppBarButtonBackgroundPointerOver"/>
<StaticResource x:Key="ButtonBackgroundPressed" ResourceKey="AppBarButtonBackgroundPressed"/>
<StaticResource x:Key="ButtonBackgroundDisabled" ResourceKey="AppBarButtonBackgroundDisabled"/>
<StaticResource x:Key="ButtonForeground" ResourceKey="AppBarButtonForeground"/>
<StaticResource x:Key="ButtonForegroundPointerOver" ResourceKey="AppBarButtonForegroundPointerOver"/>
<StaticResource x:Key="ButtonForegroundPressed" ResourceKey="AppBarButtonForegroundPressed"/>
<StaticResource x:Key="ButtonForegroundDisabled" ResourceKey="AppBarButtonForegroundDisabled"/>
<StaticResource x:Key="ButtonBorderBrush" ResourceKey="AppBarButtonBorderBrush"/>
<StaticResource x:Key="ButtonBorderBrushPointerOver" ResourceKey="AppBarButtonBorderBrushPointerOver"/>
<StaticResource x:Key="ButtonBorderBrushPressed" ResourceKey="AppBarButtonBorderBrushPressed"/>
<StaticResource x:Key="ButtonBorderBrushDisabled" ResourceKey="AppBarButtonBorderBrushDisabled"/>
</ResourceDictionary>
</ResourceDictionary.ThemeDictionaries>
</ResourceDictionary>
</Button.Resources>
<Viewbox
Width="{StaticResource InfoBarCloseButtonGlyphSize}"
Height="{StaticResource InfoBarCloseButtonGlyphSize}"
HorizontalAlignment="Center"
VerticalAlignment="Center">
<SymbolIcon Symbol="{StaticResource InfoBarCloseButtonSymbol}"/>
</Viewbox>
</Button>
</Grid>
<VisualStateManager.VisualStateGroups>
<VisualStateGroup x:Name="SeverityLevels">
<VisualState x:Name="Informational"/>
<VisualState x:Name="Error">
<VisualState.Setters>
<Setter Target="ContentRoot.Background" Value="{ThemeResource InfoBarErrorSeverityBackgroundBrush}"/>
<Setter Target="IconBackground.Foreground" Value="{ThemeResource InfoBarErrorSeverityIconBackground}"/>
<Setter Target="StandardIcon.Text" Value="{StaticResource InfoBarErrorIconGlyph}"/>
<Setter Target="StandardIcon.Foreground" Value="{ThemeResource InfoBarErrorSeverityIconForeground}"/>
</VisualState.Setters>
</VisualState>
<VisualState x:Name="Warning">
<VisualState.Setters>
<Setter Target="ContentRoot.Background" Value="{ThemeResource InfoBarWarningSeverityBackgroundBrush}"/>
<Setter Target="IconBackground.Foreground" Value="{ThemeResource InfoBarWarningSeverityIconBackground}"/>
<Setter Target="StandardIcon.Text" Value="{StaticResource InfoBarWarningIconGlyph}"/>
<Setter Target="StandardIcon.Foreground" Value="{ThemeResource InfoBarWarningSeverityIconForeground}"/>
</VisualState.Setters>
</VisualState>
<VisualState x:Name="Success">
<VisualState.Setters>
<Setter Target="ContentRoot.Background" Value="{ThemeResource InfoBarSuccessSeverityBackgroundBrush}"/>
<Setter Target="IconBackground.Foreground" Value="{ThemeResource InfoBarSuccessSeverityIconBackground}"/>
<Setter Target="StandardIcon.Text" Value="{StaticResource InfoBarSuccessIconGlyph}"/>
<Setter Target="StandardIcon.Foreground" Value="{ThemeResource InfoBarSuccessSeverityIconForeground}"/>
</VisualState.Setters>
</VisualState>
</VisualStateGroup>
<VisualStateGroup x:Name="IconStates">
<VisualState x:Name="StandardIconVisible">
<VisualState.Setters>
<Setter Target="UserIconBox.Visibility" Value="Collapsed"/>
<Setter Target="StandardIconArea.Visibility" Value="Visible"/>
</VisualState.Setters>
</VisualState>
<VisualState x:Name="UserIconVisible">
<VisualState.Setters>
<Setter Target="UserIconBox.Visibility" Value="Visible"/>
<Setter Target="StandardIconArea.Visibility" Value="Collapsed"/>
</VisualState.Setters>
</VisualState>
<VisualState x:Name="NoIconVisible"/>
</VisualStateGroup>
<VisualStateGroup>
<VisualState x:Name="CloseButtonVisible"/>
<VisualState x:Name="CloseButtonCollapsed">
<VisualState.Setters>
<Setter Target="CloseButton.Visibility" Value="Collapsed"/>
</VisualState.Setters>
</VisualState>
</VisualStateGroup>
<VisualStateGroup x:Name="InfoBarVisibility">
<VisualState x:Name="InfoBarVisible"/>
<VisualState x:Name="InfoBarCollapsed">
<VisualState.Setters>
<Setter Target="ContentRoot.Visibility" Value="Collapsed"/>
</VisualState.Setters>
</VisualState>
</VisualStateGroup>
<VisualStateGroup>
<VisualState x:Name="ForegroundNotSet"/>
<VisualState x:Name="ForegroundSet">
<VisualState.Setters>
<Setter Target="Title.Foreground" Value="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=Foreground}"/>
<Setter Target="Message.Foreground" Value="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=Foreground}"/>
</VisualState.Setters>
</VisualState>
</VisualStateGroup>
</VisualStateManager.VisualStateGroups>
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</ResourceDictionary>

View File

@@ -0,0 +1,23 @@
<ResourceDictionary
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:cwcont="using:CommunityToolkit.WinUI.Controls">
<ItemsPanelTemplate x:Key="ItemsStackPanelTemplate">
<ItemsStackPanel/>
</ItemsPanelTemplate>
<ItemsPanelTemplate x:Key="WrapPanelSpacing0Template">
<cwcont:WrapPanel/>
</ItemsPanelTemplate>
<ItemsPanelTemplate x:Key="WrapPanelSpacing4Template">
<cwcont:WrapPanel HorizontalSpacing="4" VerticalSpacing="4"/>
</ItemsPanelTemplate>
<ItemsPanelTemplate x:Key="HorizontalStackPanelTemplate">
<StackPanel Orientation="Horizontal"/>
</ItemsPanelTemplate>
<ItemsPanelTemplate x:Key="UniformGridColumns5Spacing4Template">
<cwcont:UniformGrid
ColumnSpacing="4"
Columns="5"
RowSpacing="4"/>
</ItemsPanelTemplate>
</ResourceDictionary>

View File

@@ -0,0 +1,14 @@
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<!-- Length -->
<GridLength x:Key="CompatGridLength2">288</GridLength>
<x:Double x:Key="CompatSplitViewOpenPaneLength">212</x:Double>
<x:Double x:Key="CompatSplitViewOpenPaneLength2">304</x:Double>
<x:Double x:Key="CompatSplitViewOpenPaneLength3">320</x:Double>
<x:Double x:Key="HomeAdaptiveCardHeight">180</x:Double>
<x:Double x:Key="ContentDialogMinHeight">64</x:Double>
<x:Double x:Key="LargeAppBarButtonWidth">100</x:Double>
<!-- ProgressBar -->
<x:Double x:Key="LargeBackgroundProgressBarOpacity">0.2</x:Double>
</ResourceDictionary>

View File

@@ -0,0 +1,6 @@
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<!-- Page Transparent Background -->
<StaticResource x:Key="ApplicationPageBackgroundThemeBrush" ResourceKey="ControlFillColorTransparentBrush"/>
<!-- https://github.com/microsoft/microsoft-ui-xaml/issues/4811 -->
<x:Int32 x:Key="__DiscardPageOverride">0</x:Int32>
</ResourceDictionary>

View File

@@ -0,0 +1,5 @@
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<x:Double x:Key="PivotHeaderItemFontSize">16</x:Double>
<Thickness x:Key="PivotHeaderItemMargin">16,0,0,0</Thickness>
<Thickness x:Key="PivotItemMargin">0</Thickness>
</ResourceDictionary>

View File

@@ -0,0 +1,31 @@
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<!-- Settings -->
<x:Double x:Key="SettingsCardSpacing">3</x:Double>
<x:Double x:Key="SettingsCardMinHeight">0</x:Double>
<x:Double x:Key="SettingsCardWrapThreshold">0</x:Double>
<x:Double x:Key="SettingsCardWrapNoIconThreshold">0</x:Double>
<Style
x:Key="SettingsSectionHeaderTextBlockStyle"
BasedOn="{StaticResource BodyStrongTextBlockStyle}"
TargetType="TextBlock">
<Style.Setters>
<Setter Property="Margin" Value="1,29,0,5"/>
</Style.Setters>
</Style>
<Style
x:Key="SettingsContentComboBoxStyle"
BasedOn="{StaticResource DefaultComboBoxStyle}"
TargetType="ComboBox">
<Setter Property="MinWidth" Value="120"/>
</Style>
<Style
x:Key="SettingButtonStyle"
BasedOn="{StaticResource DefaultButtonStyle}"
TargetType="Button">
<Setter Property="BorderBrush" Value="{ThemeResource CardBorderBrush}"/>
<Setter Property="CornerRadius" Value="{ThemeResource ControlCornerRadius}"/>
<Setter Property="Padding" Value="16,6,16,6"/>
<Setter Property="HorizontalAlignment" Value="Stretch"/>
<Setter Property="HorizontalContentAlignment" Value="Center"/>
</Style>
</ResourceDictionary>

View File

@@ -0,0 +1,17 @@
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<TransitionCollection x:Key="ContentThemeTransitions">
<ContentThemeTransition/>
</TransitionCollection>
<TransitionCollection x:Key="EntranceThemeTransitions">
<EntranceThemeTransition/>
</TransitionCollection>
<TransitionCollection x:Key="ListViewLikeThemeTransitions">
<AddDeleteThemeTransition/>
<ContentThemeTransition/>
<ReorderThemeTransition/>
<EntranceThemeTransition IsStaggeringEnabled="False"/>
</TransitionCollection>
<TransitionCollection x:Key="ReorderThemeTransitions">
<ReorderThemeTransition/>
</TransitionCollection>
</ResourceDictionary>

View File

@@ -0,0 +1,34 @@
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<!-- DocumentLink -->
<x:String x:Key="DocumentLink_BugReport">https://hut.ao/statements/bug-report.html</x:String>
<x:String x:Key="DocumentLink_Home">https://hut.ao</x:String>
<x:String x:Key="DocumentLink_MhyAccountSwitch">https://hut.ao/features/mhy-account-switch.html</x:String>
<x:String x:Key="DocumentLink_Translate">https://translate.hut.ao</x:String>
<!-- Other -->
<x:String x:Key="HolographicHat_GetToken_Release">https://github.com/HolographicHat/GetToken/releases/latest</x:String>
<x:String x:Key="Sponsor_Afadian">https://afdian.net/a/DismissedLight</x:String>
<!-- AvatarCard -->
<x:String x:Key="UI_AvatarIcon_Costume_Card">https://static.snapgenshin.com/AvatarCard/UI_AvatarIcon_Costume_Card.png</x:String>
<!-- Bg -->
<x:String x:Key="UI_Icon_Intee_Explore_1">https://static.snapgenshin.com/Bg/UI_Icon_Intee_Explore_1.png</x:String>
<x:String x:Key="UI_ImgSign_ItemIcon">https://static.snapgenshin.com/Bg/UI_ImgSign_ItemIcon.png</x:String>
<x:String x:Key="UI_ItemIcon_None">https://static.snapgenshin.com/Bg/UI_ItemIcon_None.png</x:String>
<x:String x:Key="UI_MarkQuest_Events_Proce">https://static.snapgenshin.com/Bg/UI_MarkQuest_Events_Proce.png</x:String>
<x:String x:Key="UI_MarkTower">https://static.snapgenshin.com/Bg/UI_MarkTower.png</x:String>
<!-- ItemIcon -->
<x:String x:Key="UI_ItemIcon_201">https://static.snapgenshin.com/ItemIcon/UI_ItemIcon_201.png</x:String>
<x:String x:Key="UI_ItemIcon_204">https://static.snapgenshin.com/ItemIcon/UI_ItemIcon_204.png</x:String>
<x:String x:Key="UI_ItemIcon_210">https://static.snapgenshin.com/ItemIcon/UI_ItemIcon_210.png</x:String>
<x:String x:Key="UI_ItemIcon_220021">https://static.snapgenshin.com/ItemIcon/UI_ItemIcon_220021.png</x:String>
<!-- EmotionIcon -->
<x:String x:Key="UI_EmotionIcon25">https://static.snapgenshin.com/EmotionIcon/UI_EmotionIcon25.png</x:String>
<x:String x:Key="UI_EmotionIcon71">https://static.snapgenshin.com/EmotionIcon/UI_EmotionIcon71.png</x:String>
<x:String x:Key="UI_EmotionIcon250">https://static.snapgenshin.com/EmotionIcon/UI_EmotionIcon250.png</x:String>
<x:String x:Key="UI_EmotionIcon272">https://static.snapgenshin.com/EmotionIcon/UI_EmotionIcon272.png</x:String>
<x:String x:Key="UI_EmotionIcon293">https://static.snapgenshin.com/EmotionIcon/UI_EmotionIcon293.png</x:String>
</ResourceDictionary>

View File

@@ -0,0 +1,5 @@
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<!-- Modify Window title bar color -->
<StaticResource x:Key="WindowCaptionBackground" ResourceKey="ControlFillColorTransparentBrush"/>
<StaticResource x:Key="WindowCaptionBackgroundDisabled" ResourceKey="ControlFillColorTransparentBrush"/>
</ResourceDictionary>

View File

@@ -1,24 +0,0 @@
// Copyright (c) DGP Studio. All rights reserved.
// Licensed under the MIT license.
namespace Snap.Hutao.Core.Annotation;
/// <summary>
/// 指示此方法为命令的调用方法
/// </summary>
[AttributeUsage(AttributeTargets.Method, Inherited = false)]
internal sealed class CommandAttribute : Attribute
{
/// <summary>
/// 指示此方法为命令的调用方法
/// </summary>
/// <param name="name">命令名称</param>
public CommandAttribute(string name)
{
}
/// <summary>
/// 是否允许并行执行
/// </summary>
public bool AllowConcurrentExecutions { get; set; }
}

View File

@@ -1,28 +0,0 @@
// Copyright (c) DGP Studio. All rights reserved.
// Licensed under the MIT license.
namespace Snap.Hutao.Core.Annotation;
/// <summary>
/// 指示此类自动生成构造器
/// </summary>
[AttributeUsage(AttributeTargets.Class, Inherited = false)]
internal sealed class ConstructorGeneratedAttribute : Attribute
{
/// <summary>
/// 指示此类自动生成构造器
/// </summary>
public ConstructorGeneratedAttribute()
{
}
/// <summary>
/// 是否调用基类构造函数
/// </summary>
public bool CallBaseConstructor { get; set; }
/// <summary>
/// 在构造函数中插入 HttpClient
/// </summary>
public bool ResolveHttpClient { get; set; }
}

View File

@@ -1,24 +0,0 @@
// Copyright (c) DGP Studio. All rights reserved.
// Licensed under the MIT license.
namespace Snap.Hutao.Core.Annotation;
[AttributeUsage(AttributeTargets.Class, AllowMultiple = true, Inherited = false)]
internal sealed class DependencyPropertyAttribute : Attribute
{
public DependencyPropertyAttribute(string name, Type type)
{
}
public DependencyPropertyAttribute(string name, Type type, object defaultValue)
{
}
public DependencyPropertyAttribute(string name, Type type, object defaultValue, string valueChangedCallbackName)
{
}
public bool IsAttached { get; set; }
public Type AttachedType { get; set; } = default!;
}

View File

@@ -1,15 +0,0 @@
// Copyright (c) DGP Studio. All rights reserved.
// Licensed under the MIT license.
using System.Diagnostics;
namespace Snap.Hutao.Core.Annotation;
/// <summary>
/// 高质量代码
/// </summary>
[AttributeUsage(AttributeTargets.All, Inherited = false)]
[Conditional("DEBUG")]
internal sealed class HighQualityAttribute : Attribute
{
}

View File

@@ -30,9 +30,6 @@ internal sealed class ImageCache : IImageCache, IImageCacheFilePathOperation
[0] = TimeSpan.FromSeconds(4),
[1] = TimeSpan.FromSeconds(16),
[2] = TimeSpan.FromSeconds(64),
[3] = TimeSpan.FromSeconds(4),
[4] = TimeSpan.FromSeconds(16),
[5] = TimeSpan.FromSeconds(64),
};
private readonly ILogger logger;
@@ -173,7 +170,7 @@ internal sealed class ImageCache : IImageCache, IImageCacheFilePathOperation
int retryCount = 0;
HttpClient httpClient = httpClientFactory.CreateClient(nameof(ImageCache));
while (retryCount < 6)
while (retryCount < 3)
{
using (HttpResponseMessage message = await httpClient.GetAsync(uri, HttpCompletionOption.ResponseHeadersRead).ConfigureAwait(false))
{
@@ -191,10 +188,6 @@ internal sealed class ImageCache : IImageCache, IImageCacheFilePathOperation
switch (message.StatusCode)
{
case HttpStatusCode.NotFound:
// directly goto https://static.hut.ao
retryCount += 3;
break;
case HttpStatusCode.TooManyRequests:
{
retryCount++;
@@ -208,11 +201,6 @@ internal sealed class ImageCache : IImageCache, IImageCacheFilePathOperation
return;
}
}
if (retryCount == 3)
{
uri = new UriBuilder(uri) { Host = Web.HutaoEndpoints.StaticHutao }.Uri;
}
}
}

View File

@@ -1,30 +0,0 @@
// Copyright (c) DGP Studio. All rights reserved.
// Licensed under the MIT license.
namespace Snap.Hutao.Core.DependencyInjection.Annotation.HttpClient;
/// <summary>
/// 指示被标注的类型可注入 HttpClient
/// 由源生成器生成注入代码
/// </summary>
[HighQuality]
[AttributeUsage(AttributeTargets.Class, Inherited = false)]
internal sealed class HttpClientAttribute : Attribute
{
/// <summary>
/// 构造一个新的特性
/// </summary>
/// <param name="configuration">配置</param>
public HttpClientAttribute(HttpClientConfiguration configuration)
{
}
/// <summary>
/// 构造一个新的特性
/// </summary>
/// <param name="configuration">配置</param>
/// <param name="interfaceType">实现的接口类型</param>
public HttpClientAttribute(HttpClientConfiguration configuration, Type interfaceType)
{
}
}

View File

@@ -1,31 +0,0 @@
// Copyright (c) DGP Studio. All rights reserved.
// Licensed under the MIT license.
namespace Snap.Hutao.Core.DependencyInjection.Annotation.HttpClient;
/// <summary>
/// Http客户端配置
/// </summary>
[HighQuality]
internal enum HttpClientConfiguration
{
/// <summary>
/// 默认配置
/// </summary>
Default,
/// <summary>
/// 米游社请求配置
/// </summary>
XRpc,
/// <summary>
/// 米游社登录请求配置
/// </summary>
XRpc2,
/// <summary>
/// Hoyolab app
/// </summary>
XRpc3,
}

View File

@@ -1,20 +0,0 @@
// Copyright (c) DGP Studio. All rights reserved.
// Licensed under the MIT license.
namespace Snap.Hutao.Core.DependencyInjection.Annotation.HttpClient;
/// <summary>
/// 配置首选Http消息处理器特性
/// </summary>
[HighQuality]
[AttributeUsage(AttributeTargets.Class, Inherited = false)]
internal sealed class PrimaryHttpMessageHandlerAttribute : Attribute
{
/// <inheritdoc cref="System.Net.Http.HttpClientHandler.MaxConnectionsPerServer"/>
public int MaxConnectionsPerServer { get; set; }
/// <summary>
/// <inheritdoc cref="System.Net.Http.HttpClientHandler.UseCookies"/>
/// </summary>
public bool UseCookies { get; set; }
}

View File

@@ -1,26 +0,0 @@
// Copyright (c) DGP Studio. All rights reserved.
// Licensed under the MIT license.
namespace Snap.Hutao.Core.DependencyInjection.Annotation;
/// <summary>
/// 注入方法
/// </summary>
[HighQuality]
internal enum InjectAs
{
/// <summary>
/// 指示应注册为单例对象
/// </summary>
Singleton,
/// <summary>
/// 指示应注册为短期对象
/// </summary>
Transient,
/// <summary>
/// 指示应注册为范围对象
/// </summary>
Scoped,
}

View File

@@ -1,30 +0,0 @@
// Copyright (c) DGP Studio. All rights reserved.
// Licensed under the MIT license.
namespace Snap.Hutao.Core.DependencyInjection.Annotation;
/// <summary>
/// 指示被标注的类型可注入
/// 由源生成器生成注入代码
/// </summary>
[HighQuality]
[AttributeUsage(AttributeTargets.Class, AllowMultiple = true, Inherited = false)]
internal sealed class InjectionAttribute : Attribute
{
/// <summary>
/// 指示该类将注入为不带有接口实现的类
/// </summary>
/// <param name="injectAs">指示注入方法</param>
public InjectionAttribute(InjectAs injectAs)
{
}
/// <summary>
/// 指示该类将注入为带有接口实现的类
/// </summary>
/// <param name="injectAs">指示注入方法</param>
/// <param name="interfaceType">实现的接口类型</param>
public InjectionAttribute(InjectAs injectAs, Type interfaceType)
{
}
}

View File

@@ -44,7 +44,7 @@ internal static partial class IocHttpClientConfiguration
client.Timeout = Timeout.InfiniteTimeSpan;
client.DefaultRequestHeaders.UserAgent.ParseAdd(HoyolabOptions.UserAgent);
client.DefaultRequestHeaders.Accept.ParseAdd(ApplicationJson);
client.DefaultRequestHeaders.Add("x-rpc-app_version", HoyolabOptions.XrpcVersion);
client.DefaultRequestHeaders.Add("x-rpc-app_version", SaltConstants.CNVersion);
client.DefaultRequestHeaders.Add("x-rpc-client_type", "5");
client.DefaultRequestHeaders.Add("x-rpc-device_id", HoyolabOptions.DeviceId);
}
@@ -60,7 +60,7 @@ internal static partial class IocHttpClientConfiguration
client.DefaultRequestHeaders.Accept.ParseAdd(ApplicationJson);
client.DefaultRequestHeaders.Add("x-rpc-aigis", string.Empty);
client.DefaultRequestHeaders.Add("x-rpc-app_id", "bll8iq97cem8");
client.DefaultRequestHeaders.Add("x-rpc-app_version", HoyolabOptions.XrpcVersion);
client.DefaultRequestHeaders.Add("x-rpc-app_version", SaltConstants.CNVersion);
client.DefaultRequestHeaders.Add("x-rpc-client_type", "2");
client.DefaultRequestHeaders.Add("x-rpc-device_id", HoyolabOptions.DeviceId);
client.DefaultRequestHeaders.Add("x-rpc-game_biz", "bbs_cn");
@@ -77,7 +77,7 @@ internal static partial class IocHttpClientConfiguration
client.Timeout = Timeout.InfiniteTimeSpan;
client.DefaultRequestHeaders.UserAgent.ParseAdd(HoyolabOptions.UserAgentOversea);
client.DefaultRequestHeaders.Accept.ParseAdd(ApplicationJson);
client.DefaultRequestHeaders.Add("x-rpc-app_version", HoyolabOptions.XrpcVersionOversea);
client.DefaultRequestHeaders.Add("x-rpc-app_version", SaltConstants.OSVersion);
client.DefaultRequestHeaders.Add("x-rpc-client_type", "5");
client.DefaultRequestHeaders.Add("x-rpc-language", "zh-cn");
client.DefaultRequestHeaders.Add("x-rpc-device_id", HoyolabOptions.DeviceId);

View File

@@ -14,9 +14,7 @@ namespace Snap.Hutao.Core.ExceptionService;
internal sealed partial class ExceptionRecorder
{
private readonly ILogger<ExceptionRecorder> logger;
#if RELEASE
private readonly IServiceProvider serviceProvider;
#endif
/// <summary>
/// 记录应用程序异常
@@ -31,15 +29,11 @@ internal sealed partial class ExceptionRecorder
private void OnAppUnhandledException(object? sender, Microsoft.UI.Xaml.UnhandledExceptionEventArgs e)
{
#if RELEASE
#pragma warning disable VSTHRD002
serviceProvider
.GetRequiredService<Web.Hutao.Log.HomaLogUploadClient>()
.UploadLogAsync(serviceProvider, e.Exception)
.UploadLogAsync(e.Exception)
.GetAwaiter()
.GetResult();
#pragma warning restore VSTHRD002
#endif
logger.LogError("未经处理的全局异常:\r\n{Detail}", ExceptionFormat.Format(e.Exception));
}

View File

@@ -3,7 +3,6 @@
using CommunityToolkit.WinUI.Notifications;
using Microsoft.Extensions.Caching.Memory;
using Microsoft.UI.Xaml;
using Microsoft.Windows.AppLifecycle;
using Snap.Hutao.Core.Setting;
using Snap.Hutao.Service.DailyNote;
@@ -52,7 +51,6 @@ internal sealed partial class Activation : IActivation
private readonly IServiceProvider serviceProvider;
private readonly ICurrentWindowReference currentWindowReference;
private readonly ITaskContext taskContext;
//private readonly WeakReference<MainWindow> mainWindowReference = new(default!);
private readonly SemaphoreSlim activateSemaphore = new(1);
/// <inheritdoc/>
@@ -143,6 +141,11 @@ internal sealed partial class Activation : IActivation
// Increase launch times
LocalSetting.Set(SettingKeys.LaunchTimes, LocalSetting.Get(SettingKeys.LaunchTimes, 0) + 1);
if (StaticResource.IsAnyUnfulfilledCategoryPresent())
{
LocalSetting.Set(SettingKeys.Major1Minor7Revision0GuideState, (uint)GuideState.StaticResourceBegin);
}
if (LocalSetting.Get(SettingKeys.Major1Minor7Revision0GuideState, (uint)GuideState.Language) < (uint)GuideState.Completed)
{
await taskContext.SwitchToMainThreadAsync();
@@ -271,10 +274,18 @@ internal sealed partial class Activation : IActivation
}
else
{
await serviceProvider
.GetRequiredService<INavigationService>()
.NavigateAsync<View.Page.LaunchGamePage>(INavigationAwaiter.Default, true)
.ConfigureAwait(false);
if (currentWindowReference.Window is MainWindow)
{
await serviceProvider
.GetRequiredService<INavigationService>()
.NavigateAsync<View.Page.LaunchGamePage>(INavigationAwaiter.Default, true)
.ConfigureAwait(false);
}
else
{
// We have a non-Main Window, just exit current process anyway
Process.GetCurrentProcess().Kill();
}
}
}
}

View File

@@ -1,22 +1,23 @@
// Copyright (c) DGP Studio. All rights reserved.
// Licensed under the MIT license.
using CommunityToolkit.WinUI.Notifications;
using Microsoft.Extensions.Caching.Memory;
using Microsoft.UI.Xaml;
using Microsoft.Windows.AppLifecycle;
using Snap.Hutao.Core.Setting;
using Snap.Hutao.Service.DailyNote;
using Snap.Hutao.Service.Hutao;
using Snap.Hutao.Service.Metadata;
using Snap.Hutao.Service.Navigation;
using Snap.Hutao.ViewModel.Guide;
using System.Diagnostics;
namespace Snap.Hutao.Core.LifeCycle;
[Injection(InjectAs.Singleton, typeof(ICurrentWindowReference))]
internal sealed class CurrentWindowReference : ICurrentWindowReference
{
public Window Window { get; set; } = default!;
private readonly WeakReference<Window> reference = new(default!);
[SuppressMessage("", "SH007")]
public Window Window
{
get
{
reference.TryGetTarget(out Window? window);
return window!;
}
set => reference.SetTarget(value);
}
}

View File

@@ -1,7 +1,6 @@
// Copyright (c) DGP Studio. All rights reserved.
// Licensed under the MIT license.
using Microsoft.UI.Xaml;
using Microsoft.Windows.AppLifecycle;
namespace Snap.Hutao.Core.LifeCycle;

View File

@@ -1,55 +0,0 @@
// Copyright (c) DGP Studio. All rights reserved.
// Licensed under the MIT license.
using CommunityToolkit.Mvvm.ComponentModel;
namespace Snap.Hutao.Core.Setting;
/// <summary>
/// 功能
/// </summary>
internal sealed class Feature : ObservableObject
{
private readonly string displayName;
private readonly string description;
private readonly string settingKey;
private readonly bool defaultValue;
/// <summary>
/// 构造一个新的功能
/// </summary>
/// <param name="displayName">显示名称</param>
/// <param name="description">描述</param>
/// <param name="settingKey">键</param>
/// <param name="defaultValue">默认值</param>
public Feature(string displayName, string description, string settingKey, bool defaultValue)
{
this.displayName = displayName;
this.description = description;
this.settingKey = settingKey;
this.defaultValue = defaultValue;
}
/// <summary>
/// 显示名称
/// </summary>
public string DisplayName { get => displayName; }
/// <summary>
/// 描述
/// </summary>
public string Description { get => description; }
/// <summary>
/// 值
/// </summary>
public bool Value
{
get => LocalSetting.Get(settingKey, defaultValue);
set
{
LocalSetting.Set(settingKey, value);
OnPropertyChanged();
}
}
}

View File

@@ -1,41 +0,0 @@
// Copyright (c) DGP Studio. All rights reserved.
// Licensed under the MIT license.
using System.Collections;
namespace Snap.Hutao.Core.Setting;
/// <summary>
/// 功能选项
/// </summary>
internal sealed class FeatureOptions : IReadOnlyCollection<Feature>
{
/// <summary>
/// 启用实时便笺无感验证
/// </summary>
public Feature IsDailyNoteSilentVerificationEnabled { get; } = new(
"IsDailyNoteSilentVerificationEnabled", "启用实时便笺无感验证", "IsDailyNoteSilentVerificationEnabled", true);
/// <summary>
/// 元数据检查是否忽略
/// </summary>
public Feature IsMetadataUpdateCheckSuppressed { get; } = new(
"IsMetadataUpdateCheckSuppressed", "禁用元数据更新检查", "IsMetadataUpdateCheckSuppressed", false);
/// <inheritdoc/>
public int Count { get => 2; }
/// <inheritdoc/>
public IEnumerator<Feature> GetEnumerator()
{
// TODO: Use source generator
yield return IsDailyNoteSilentVerificationEnabled;
yield return IsMetadataUpdateCheckSuppressed;
}
/// <inheritdoc/>
IEnumerator IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
}

View File

@@ -115,7 +115,7 @@ internal static class LocalSetting
return Get<Windows.Foundation.Rect>(key, defaultValue);
}
public static ApplicationDataCompositeValue Get(string key, ApplicationDataCompositeValue defaultValue)
public static ApplicationDataCompositeValue Get(string key, ApplicationDataCompositeValue defaultValue)
{
return Get<ApplicationDataCompositeValue>(key, defaultValue);
}

View File

@@ -63,4 +63,22 @@ internal static class SettingKeys
/// 覆盖管理员权限执行命令
/// </summary>
public const string OverrideElevationRequirement = "OverrideElevationRequirement";
public const string CultivationAvatarLevelCurrent = "CultivationAvatarLevelCurrent";
public const string CultivationAvatarLevelTarget = "CultivationAvatarLevelTarget";
public const string CultivationAvatarSkillACurrent = "CultivationAvatarSkillACurrent";
public const string CultivationAvatarSkillATarget = "CultivationAvatarSkillATarget";
public const string CultivationAvatarSkillECurrent = "CultivationAvatarSkillECurrent";
public const string CultivationAvatarSkillETarget = "CultivationAvatarSkillETarget";
public const string CultivationAvatarSkillQCurrent = "CultivationAvatarSkillQCurrent";
public const string CultivationAvatarSkillQTarget = "CultivationAvatarSkillQTarget";
public const string CultivationWeapon90LevelCurrent = "CultivationWeapon90LevelCurrent";
public const string CultivationWeapon90LevelTarget = "CultivationWeapon90LevelTarget";
public const string CultivationWeapon70LevelCurrent = "CultivationWeapon70LevelCurrent";
public const string CultivationWeapon70LevelTarget = "CultivationWeapon70LevelTarget";
public const string IsHomeCardLaunchGamePresented = "IsHomeCardLaunchGamePresented";
public const string IsHomeCardGachaStatisticsPresented = "IsHomeCardGachaStatisticsPresented";
public const string IsHomeCardAchievementPresented = "IsHomeCardAchievementPresented";
public const string IsHomeCardDailyNotePresented = "IsHomeCardDailyNotePresented";
}

View File

@@ -1,84 +0,0 @@
// Copyright (c) DGP Studio. All rights reserved.
// Licensed under the MIT license.
namespace Snap.Hutao.Core.Setting;
/// <summary>
/// 静态资源
/// </summary>
[HighQuality]
internal static class StaticResource
{
/// <summary>
/// 静态资源合约
/// </summary>
public const string V1Contract = "StaticResourceV1Contract";
/// <summary>
/// 静态资源合约V2 成就图标与物品图标
/// </summary>
public const string V2Contract = "StaticResourceV2Contract";
/// <summary>
/// 静态资源合约V3 刷新 Skill Talent
/// </summary>
public const string V3Contract = "StaticResourceV3Contract";
/// <summary>
/// 静态资源合约V4 刷新 AvatarIcon
/// </summary>
public const string V4Contract = "StaticResourceV4Contract";
/// <summary>
/// 静态资源合约V5 刷新 AvatarIcon
/// </summary>
public const string V5Contract = "StaticResourceV5Contract";
/// <summary>
/// 完成所有合约
/// </summary>
public static void FulfillAllContracts()
{
SetContractsState(true);
}
/// <summary>
/// 取消完成所有合约
/// </summary>
public static void FailAllContracts()
{
SetContractsState(false);
}
/// <summary>
/// 提供的合约是否未完成
/// </summary>
/// <param name="contractKey">合约的键</param>
/// <returns>合约是否未完成</returns>
public static bool IsContractUnfulfilled(string contractKey)
{
return !LocalSetting.Get(contractKey, false);
}
/// <summary>
/// 是否有任何静态资源合约尚未完成
/// </summary>
/// <returns>静态资源合约尚未完成</returns>
public static bool IsAnyUnfulfilledContractPresent()
{
return !LocalSetting.Get(V1Contract, false)
|| (!LocalSetting.Get(V2Contract, false))
|| (!LocalSetting.Get(V3Contract, false))
|| (!LocalSetting.Get(V4Contract, false))
|| (!LocalSetting.Get(V5Contract, false));
}
private static void SetContractsState(bool state)
{
LocalSetting.Set(V1Contract, state);
LocalSetting.Set(V2Contract, state);
LocalSetting.Set(V3Contract, state);
LocalSetting.Set(V4Contract, state);
LocalSetting.Set(V5Contract, state);
}
}

View File

@@ -0,0 +1,9 @@
// Copyright (c) DGP Studio. All rights reserved.
// Licensed under the MIT license.
namespace Snap.Hutao.Core.Shell;
internal interface IShellLinkInterop
{
ValueTask<bool> TryCreateDesktopShoutcutForElevatedLaunchAsync();
}

View File

@@ -0,0 +1,56 @@
// Copyright (c) DGP Studio. All rights reserved.
// Licensed under the MIT license.
using System.IO;
using Windows.Storage;
using Windows.Win32;
using Windows.Win32.System.Com;
using Windows.Win32.UI.Shell;
using Windows.Win32.UI.WindowsAndMessaging;
namespace Snap.Hutao.Core.Shell;
[ConstructorGenerated]
[Injection(InjectAs.Transient, typeof(IShellLinkInterop))]
internal sealed partial class ShellLinkInterop : IShellLinkInterop
{
private readonly RuntimeOptions runtimeOptions;
public async ValueTask<bool> TryCreateDesktopShoutcutForElevatedLaunchAsync()
{
Uri sourceLogoUri = "ms-appx:///Assets/Logo.ico".ToUri();
string targetLogoPath = Path.Combine(runtimeOptions.DataFolder, "ShellLinkLogo.ico");
try
{
StorageFile iconFile = await StorageFile.GetFileFromApplicationUriAsync(sourceLogoUri);
using (Stream inputStream = (await iconFile.OpenReadAsync()).AsStream())
{
using (FileStream outputStream = File.Create(targetLogoPath))
{
await inputStream.CopyToAsync(outputStream).ConfigureAwait(false);
}
}
}
catch
{
return false;
}
IShellLinkW shellLink = (IShellLinkW)new ShellLink();
shellLink.SetPath("powershell");
shellLink.SetArguments($"""
-Command "Start-Process shell:AppsFolder\{runtimeOptions.FamilyName}!App -verb runas"
""");
shellLink.SetShowCmd(SHOW_WINDOW_CMD.SW_SHOWMINNOACTIVE);
shellLink.SetIconLocation(targetLogoPath, 0);
string desktop = Environment.GetFolderPath(Environment.SpecialFolder.Desktop);
string target = Path.Combine(desktop, $"{SH.AppNameAndVersion.Format(runtimeOptions.Version)}.lnk");
IPersistFile persistFile = (IPersistFile)shellLink;
persistFile.Save(target, false);
return true;
}
}

View File

@@ -5,9 +5,8 @@ using System.Buffers.Binary;
using System.Numerics;
using System.Runtime.CompilerServices;
using Windows.Graphics;
using Windows.Win32.UI.WindowsAndMessaging;
namespace Snap.Hutao.Win32;
namespace Snap.Hutao.Core;
/// <summary>
/// 结构体封送
@@ -15,27 +14,6 @@ namespace Snap.Hutao.Win32;
[HighQuality]
internal static class StructMarshal
{
/// <summary>
/// 构造一个新的 <see cref="Windows.Win32.UI.WindowsAndMessaging.WINDOWPLACEMENT"/>
/// </summary>
/// <returns>新的实例</returns>
public static unsafe WINDOWPLACEMENT WINDOWPLACEMENT()
{
return new() { length = SizeOf<WINDOWPLACEMENT>() };
}
/// <summary>
/// 获取结构的大小
/// </summary>
/// <typeparam name="TStruct">结构类型</typeparam>
/// <returns>结构的大小</returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static unsafe uint SizeOf<TStruct>()
where TStruct : unmanaged
{
return unchecked((uint)sizeof(TStruct));
}
/// <summary>
/// 使用四字节颜色代码初始化一个新的颜色
/// </summary>

View File

@@ -2,7 +2,6 @@
// Licensed under the MIT license.
using Microsoft.UI.Windowing;
using Snap.Hutao.Win32;
using Windows.Graphics;
namespace Snap.Hutao.Core.Windowing;

View File

@@ -9,23 +9,28 @@ namespace Snap.Hutao.Core.Windowing;
[HighQuality]
internal enum BackdropType
{
/// <summary>
/// 透明
/// </summary>
Transparent = -1,
/// <summary>
/// 无
/// </summary>
None,
None = 0,
/// <summary>
/// 亚克力
/// </summary>
Acrylic,
Acrylic = 1,
/// <summary>
/// 云母
/// </summary>
Mica,
Mica = 2,
/// <summary>
/// 变种云母
/// </summary>
MicaAlt,
MicaAlt = 3,
}

View File

@@ -0,0 +1,45 @@
// Copyright (c) DGP Studio. All rights reserved.
// Licensed under the MIT license.
using System.Runtime.CompilerServices;
using Windows.Graphics;
namespace Snap.Hutao.Core.Windowing;
internal readonly struct CompactRect
{
private readonly short x;
private readonly short y;
private readonly short width;
private readonly short height;
private CompactRect(int x, int y, int width, int height)
{
this.x = (short)x;
this.y = (short)y;
this.width = (short)width;
this.height = (short)height;
}
public static implicit operator RectInt32(CompactRect rect)
{
return new(rect.x, rect.y, rect.width, rect.height);
}
public static explicit operator CompactRect(RectInt32 rect)
{
return new(rect.X, rect.Y, rect.Width, rect.Height);
}
public static unsafe explicit operator CompactRect(ulong value)
{
Unsafe.SkipInit(out CompactRect rect);
*(ulong*)&rect = value;
return rect;
}
public static unsafe implicit operator ulong(CompactRect rect)
{
return *(ulong*)&rect;
}
}

View File

@@ -0,0 +1,105 @@
// Copyright (c) DGP Studio. All rights reserved.
// Licensed under the MIT license.
using System.Runtime.InteropServices;
using Windows.Win32.Foundation;
using Windows.Win32.UI.Input.KeyboardAndMouse;
using static Windows.Win32.PInvoke;
namespace Snap.Hutao.Core.Windowing.HotKey;
[SuppressMessage("", "CA1001")]
internal sealed class HotKeyController : IHotKeyController
{
private const int DefaultId = 100000;
private readonly object locker = new();
private readonly WaitCallback runMouseClickRepeatForever;
private readonly HotKeyOptions hotKeyOptions;
private readonly RuntimeOptions runtimeOptions;
private volatile CancellationTokenSource? cancellationTokenSource;
public HotKeyController(IServiceProvider serviceProvider)
{
hotKeyOptions = serviceProvider.GetRequiredService<HotKeyOptions>();
runtimeOptions = serviceProvider.GetRequiredService<RuntimeOptions>();
runMouseClickRepeatForever = MouseClickRepeatForever;
}
public bool Register(in HWND hwnd)
{
if (runtimeOptions.IsElevated)
{
return RegisterHotKey(hwnd, DefaultId, default, (uint)VIRTUAL_KEY.VK_F8);
}
return false;
}
public bool Unregister(in HWND hwnd)
{
if (runtimeOptions.IsElevated)
{
return UnregisterHotKey(hwnd, DefaultId);
}
return false;
}
public void OnHotKeyPressed(in HotKeyParameter parameter)
{
if (parameter is { Key: VIRTUAL_KEY.VK_F8, NativeModifier: 0 })
{
lock (locker)
{
if (hotKeyOptions.IsMouseClickRepeatForeverOn)
{
cancellationTokenSource?.Cancel();
cancellationTokenSource = default;
hotKeyOptions.IsMouseClickRepeatForeverOn = false;
}
else
{
cancellationTokenSource = new();
ThreadPool.QueueUserWorkItem(runMouseClickRepeatForever, cancellationTokenSource.Token);
hotKeyOptions.IsMouseClickRepeatForeverOn = true;
}
}
}
}
private static unsafe INPUT CreateInputForMouseEvent(MOUSE_EVENT_FLAGS flags)
{
INPUT input = new() { type = INPUT_TYPE.INPUT_MOUSE, };
input.Anonymous.mi.dwFlags = flags;
return input;
}
[SuppressMessage("", "SH007")]
private unsafe void MouseClickRepeatForever(object? state)
{
CancellationToken token = (CancellationToken)state!;
// We want to use this thread for a long time
while (!token.IsCancellationRequested)
{
INPUT[] inputs =
{
CreateInputForMouseEvent(MOUSE_EVENT_FLAGS.MOUSEEVENTF_LEFTDOWN),
CreateInputForMouseEvent(MOUSE_EVENT_FLAGS.MOUSEEVENTF_LEFTUP),
};
if (SendInput(inputs.AsSpan(), sizeof(INPUT)) is 0)
{
Marshal.ThrowExceptionForHR(Marshal.GetLastPInvokeError());
}
if (token.IsCancellationRequested)
{
return;
}
Thread.Sleep(Random.Shared.Next(100, 150));
}
}
}

View File

@@ -0,0 +1,14 @@
// Copyright (c) DGP Studio. All rights reserved.
// Licensed under the MIT license.
using CommunityToolkit.Mvvm.ComponentModel;
namespace Snap.Hutao.Core.Windowing.HotKey;
[Injection(InjectAs.Singleton)]
internal sealed class HotKeyOptions : ObservableObject
{
private bool isVirtualKeyF8Pressed;
public bool IsMouseClickRepeatForeverOn { get => isVirtualKeyF8Pressed; set => SetProperty(ref isVirtualKeyF8Pressed, value); }
}

View File

@@ -0,0 +1,17 @@
// Copyright (c) DGP Studio. All rights reserved.
// Licensed under the MIT license.
using Windows.Win32.UI.Input.KeyboardAndMouse;
namespace Snap.Hutao.Core.Windowing.HotKey;
internal readonly struct HotKeyParameter
{
public readonly ushort NativeModifier;
public readonly VIRTUAL_KEY Key;
public readonly HOT_KEY_MODIFIERS Modifier
{
get => (HOT_KEY_MODIFIERS)NativeModifier;
}
}

View File

@@ -0,0 +1,15 @@
// Copyright (c) DGP Studio. All rights reserved.
// Licensed under the MIT license.
using Windows.Win32.Foundation;
namespace Snap.Hutao.Core.Windowing.HotKey;
internal interface IHotKeyController
{
void OnHotKeyPressed(in HotKeyParameter parameter);
bool Register(in HWND hwnd);
bool Unregister(in HWND hwnd);
}

View File

@@ -0,0 +1,16 @@
// Copyright (c) DGP Studio. All rights reserved.
// Licensed under the MIT license.
using Windows.Win32.UI.WindowsAndMessaging;
namespace Snap.Hutao.Core.Windowing;
internal interface IMinMaxInfoHandler
{
/// <summary>
/// 处理最大最小信息
/// </summary>
/// <param name="info">信息</param>
/// <param name="scalingFactor">缩放比</param>
unsafe void HandleMinMaxInfo(ref MINMAXINFO info, double scalingFactor);
}

View File

@@ -1,8 +1,6 @@
// Copyright (c) DGP Studio. All rights reserved.
// Licensed under the MIT license.
using Windows.Win32.UI.WindowsAndMessaging;
namespace Snap.Hutao.Core.Windowing;
/// <summary>
@@ -14,11 +12,4 @@ internal interface IWindowOptionsSource
/// 窗体选项
/// </summary>
WindowOptions WindowOptions { get; }
/// <summary>
/// 处理最大最小信息
/// </summary>
/// <param name="pInfo">信息指针</param>
/// <param name="scalingFactor">缩放比</param>
unsafe void ProcessMinMaxInfo(MINMAXINFO* pInfo, double scalingFactor);
}

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