Compare commits

..

781 Commits

Author SHA1 Message Date
qhy040404
702a3d0e62 refactor launchgame resources 2024-06-17 15:01:36 +08:00
qhy040404
176535ca98 minor change 2024-06-17 13:14:03 +08:00
qhy040404
36eab42692 Add HoyoPlay API 2024-06-17 12:55:17 +08:00
Lightczx
75ea2b807f Update AsyncBarrier.cs 2024-06-17 09:57:21 +08:00
DismissedLight
e8eed46d82 Merge pull request #1725 from DGP-Studio/feat/gamerole_profilepicture 2024-06-16 22:46:47 +08:00
DismissedLight
ff9b553a19 code style 2024-06-16 22:46:24 +08:00
qhy040404
95d64c2895 make UserGameRole observable 2024-06-16 20:41:19 +08:00
qhy040404
558551c8ad rename 2024-06-16 19:14:33 +08:00
qhy040404
d05c196b7c apply changes 2024-06-16 19:04:51 +08:00
DismissedLight
502fb6dbed fix notification activation 2024-06-16 17:27:20 +08:00
qhy040404
4fa5270070 fix failed notification activate 2024-06-16 01:43:43 +08:00
DismissedLight
94fda223fc drop notification 2024-06-16 01:25:52 +08:00
Mikachu2333
18103b4deb modify alpha's tip (#1730)
Co-authored-by: LinkChou <linkchou@yandex.com>
2024-06-16 01:21:36 +08:00
qhy040404
16ac52e71d use list instead of mappppps 2024-06-16 01:19:56 +08:00
qhy040404
73825d391e fix build 2024-06-16 00:47:02 +08:00
qhy040404
3b2eeb84a7 add profile picture for each game role 2024-06-16 00:46:55 +08:00
DismissedLight
3e8655fd55 Merge pull request #1722 from DGP-Studio/feat/window
make windows transient
2024-06-15 16:04:58 +08:00
DismissedLight
fe38e14ae8 code style 2024-06-15 15:54:04 +08:00
DismissedLight
a174493819 Merge branch 'feat/window' of https://github.com/DGP-Studio/Snap.Hutao into feat/window 2024-06-15 14:32:03 +08:00
qhy040404
3a57d55c62 make windows transient 2024-06-15 14:31:29 +08:00
DismissedLight
99f35ca6db avatar property grid view rework 2024-06-15 00:43:59 +08:00
DismissedLight
c423e8b72d ProfilePicture add unlock type 2024-06-14 23:18:11 +08:00
DismissedLight
7ff78def46 fix hotkey can't register 2024-06-14 11:05:56 +08:00
qhy040404
bc9018f4bf make windows transient 2024-06-13 19:48:06 +08:00
qhy040404
107963b7ac Update issue template 2024-06-13 18:39:03 +08:00
DismissedLight
4e89406f2f Merge pull request #1721 from DGP-Studio/feat/1715 2024-06-13 16:15:21 +08:00
Lightczx
8119de3fa9 code style 2024-06-13 16:15:08 +08:00
qhy040404
7a8c233b10 review requests 2024-06-13 15:36:50 +08:00
qhy040404
cc71aa9c82 impl #1715 2024-06-13 12:51:22 +08:00
DismissedLight
4276481284 Add CachedImage Debug Layer 2024-06-11 21:05:24 +08:00
Lightczx
6f3159ae0c [skip ci] QA announcement name 2024-06-11 17:01:14 +08:00
Lightczx
c1b3412ba1 fix QA ComboBox width issue 2024-06-11 16:56:33 +08:00
Lightczx
99b3613319 fix #1688 2024-06-11 15:42:23 +08:00
Lightczx
069407abbc use weapon sort 2024-06-11 15:06:15 +08:00
DismissedLight
98c8df5c8e Merge pull request #1712 from DGP-Studio/feat/v3_cultivation 2024-06-11 14:04:49 +08:00
Lightczx
7cfcc17763 refactor 2024-06-11 14:00:48 +08:00
qhy040404
23741c4e48 exclude unavailable avatars 2024-06-11 13:12:37 +08:00
qhy040404
5f4b68d538 add cache to minimal deltas 2024-06-11 12:55:54 +08:00
Lightczx
9ef0d8c57d add SCIP solver 2024-06-11 12:31:51 +08:00
qhy040404
f0bfea51cf move to inventory service 2024-06-11 00:06:01 +08:00
DismissedLight
905454eb02 refactor 2024-06-10 23:31:38 +08:00
DismissedLight
05c3a575bc adjust db service parameter 2024-06-10 23:03:23 +08:00
DismissedLight
3e26e247cd refactor metadata abstraction 2024-06-10 22:43:50 +08:00
qhy040404
293b1e214d migrate all v2 api to v3 api 2024-06-10 22:37:56 +08:00
qhy040404
063665e77e refresh inventory 2024-06-10 22:37:55 +08:00
DismissedLight
50389ac06c Merge pull request #1713 from DGP-Studio/fix/dailynote 2024-06-10 22:12:57 +08:00
qhy040404
b99b34945e fix #1711 2024-06-10 11:05:58 +08:00
qhy040404
94a96c76bc fix #1710 2024-06-10 10:57:29 +08:00
DismissedLight
5cf3046257 Merge pull request #1694 from Mikachu2333/develop 2024-06-06 15:16:22 +08:00
Lightczx
89f8dedb57 fix url protocol launch lock 2024-06-06 13:11:24 +08:00
LinkChou
3c1e9237aa replace Uid to UID 2024-06-06 11:54:11 +08:00
LinkChou
e7cb01b302 Merge branch 'develop' of https://github.com/Mikachu2333/Snap.Hutao into develop 2024-06-06 11:48:03 +08:00
LinkChou
4cd971e166 Add some 2024-06-06 11:47:37 +08:00
Mikachu2333
7a9657f0cb Merge branch 'DGP-Studio:develop' into develop 2024-06-06 11:44:31 +08:00
Lightczx
82e6b62231 correctly free library 2024-06-06 09:29:50 +08:00
LinkChou
374c4d796d reformat 2024-06-06 07:25:11 +08:00
Mikachu2333
6e149a5be3 Update SH.resx 2024-06-06 01:44:32 +08:00
Mikachu2333
00ad0ef346 correct format 2024-06-06 01:39:10 +08:00
Mikachu2333
f22f165592 Merge branch 'develop' into develop 2024-06-06 01:33:09 +08:00
DismissedLight
5d8a39fe43 bump version 2024-06-05 21:29:28 +08:00
DismissedLight
521534be05 Merge pull request #1667 from DGP-Studio/l10n_develop 2024-06-05 21:22:17 +08:00
DismissedLight
b1364db3ac Merge pull request #1697 from DGP-Studio/opt/launch_game_activation 2024-06-05 20:35:18 +08:00
qhy040404
031cf77c27 refine LaunchGameAction 2024-06-05 19:09:57 +08:00
LinkChou
49c75dde2a Chinese text improve 2024-06-05 18:43:45 +08:00
Lightczx
3200c5e60b fix NTHeader offset 2024-06-05 17:22:45 +08:00
Lightczx
b392a6f8e5 Align HMODULE ptr 2024-06-05 17:17:52 +08:00
Lightczx
3e8e109123 use image header to fetch image size 2024-06-05 16:51:59 +08:00
Lightczx
91c886befb code style 2024-06-05 16:15:46 +08:00
Lightczx
32bdfe12af Fix Unlock Fps Attempt 2 2024-06-05 16:05:51 +08:00
Lightczx
eac67b6f44 Fix Unlock Fps Attempt 1 2024-06-05 15:28:50 +08:00
Lightczx
0dcba220c5 fix Launch Game ViewModel scope 2024-06-05 13:42:31 +08:00
Masterain
a204eaa95c New translations sh.resx (Vietnamese) 2024-06-04 18:31:38 -07:00
Masterain
35491c4eb1 New translations sh.resx (French) 2024-06-04 18:31:36 -07:00
Masterain
706401350c New translations sh.resx (Indonesian) 2024-06-04 18:31:36 -07:00
Masterain
c8ba04ee11 New translations sh.resx (English) 2024-06-04 18:31:34 -07:00
Masterain
b080a553c3 New translations sh.resx (Chinese Traditional) 2024-06-04 18:31:33 -07:00
Masterain
baf5612333 New translations sh.resx (Russian) 2024-06-04 18:31:32 -07:00
Masterain
eacd697cfe New translations sh.resx (Portuguese) 2024-06-04 18:31:31 -07:00
Masterain
11dc8e60bb New translations sh.resx (Korean) 2024-06-04 18:31:29 -07:00
Masterain
bba62996a0 New translations sh.resx (Japanese) 2024-06-04 18:31:28 -07:00
DismissedLight
db15b6a30c Merge pull request #1673 from DGP-Studio/ref/disable_web_login 2024-06-05 09:26:14 +08:00
Lightczx
1b0356b5ef fix #1669 2024-06-05 09:24:29 +08:00
qhy040404
6e498f5ede disable web login temporarily
maybe temporarily...
2024-06-04 22:30:32 +08:00
qhy040404
3117aefd54 try to fix permission 2024-06-04 21:00:27 +08:00
qhy040404
34ea240272 inline sign 2024-06-04 20:51:03 +08:00
DismissedLight
6b23ae5332 fix viewmode locker scope 2024-06-04 20:40:52 +08:00
qhy040404
c197d8a35a fix unresolved makeappx.exe 2024-06-04 20:22:47 +08:00
Lightczx
b0fa05283a code style 2024-06-04 17:19:45 +08:00
Masterain
c85a74dfc3 New translations sh.resx (Chinese Traditional) 2024-06-03 07:31:29 -07:00
DismissedLight
f7e53399b4 4.7 compatible 2024-06-03 21:49:06 +08:00
DismissedLight
52ac588a3a Merge pull request #1670 from DGP-Studio/dependabot/nuget/src/Snap.Hutao/develop/packages-7c1ae0f6e4 2024-06-03 16:21:21 +08:00
Lightczx
cd6c1f6b59 batch compute api endpoint 2024-06-03 16:18:12 +08:00
dependabot[bot]
7c734ce4aa Bump the packages group in /src/Snap.Hutao with 2 updates
Bumps the packages group in /src/Snap.Hutao with 2 updates: [MSTest.TestAdapter](https://github.com/microsoft/testfx) and [MSTest.TestFramework](https://github.com/microsoft/testfx).


Updates `MSTest.TestAdapter` from 3.4.0 to 3.4.3
- [Release notes](https://github.com/microsoft/testfx/releases)
- [Changelog](https://github.com/microsoft/testfx/blob/main/docs/Changelog.md)
- [Commits](https://github.com/microsoft/testfx/compare/v3.4.0...v3.4.3)

Updates `MSTest.TestFramework` from 3.4.0 to 3.4.3
- [Release notes](https://github.com/microsoft/testfx/releases)
- [Changelog](https://github.com/microsoft/testfx/blob/main/docs/Changelog.md)
- [Commits](https://github.com/microsoft/testfx/compare/v3.4.0...v3.4.3)

---
updated-dependencies:
- dependency-name: MSTest.TestAdapter
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: packages
- dependency-name: MSTest.TestFramework
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: packages
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-06-03 08:00:29 +00:00
DismissedLight
a640374b62 Merge pull request #1665 from DGP-Studio/feat/1663
Co-authored-by: Lightczx <1686188646@qq.com>
2024-06-03 14:11:28 +08:00
Lightczx
ca66176d64 code style 2024-06-03 14:11:00 +08:00
Lightczx
0f3a85e35c code style 2024-06-03 11:23:22 +08:00
qhy040404
4bb7316ce5 apply suggestion 2024-06-03 11:11:20 +08:00
qhy040404
7d6a9691a2 code style 2024-06-02 09:15:39 +08:00
qhy040404
1d4409aa43 code style 2024-06-02 09:10:31 +08:00
qhy040404
ea345f4854 use client to determine whether to redirect 2024-06-02 09:10:31 +08:00
qhy040404
72e163f613 auto constructor 2024-06-02 09:10:31 +08:00
qhy040404
86b04bb5a3 impl #1663 2024-06-02 09:10:31 +08:00
Masterain
5859ca3c12 New translations sh.resx (Chinese Traditional) 2024-06-01 11:19:36 -07:00
Masterain
e34e87359f New translations sh.resx (Chinese Traditional) 2024-06-01 09:51:13 -07:00
DismissedLight
53cda02071 screen capture preview 2024-06-01 22:53:56 +08:00
Masterain
ff6c682e1b New translations sh.resx (Chinese Traditional) 2024-05-31 10:16:41 -07:00
Lightczx
bae9c8a46a code style 2024-05-31 17:31:53 +08:00
Lightczx
a8baef99d7 use high performance gpu 2024-05-31 15:46:56 +08:00
Lightczx
2c47e7d1da IDXGIFactory6 2024-05-31 14:43:38 +08:00
Lightczx
2cee94a529 rename 2024-05-31 11:38:36 +08:00
Lightczx
b8b9bb2436 make launch game view model singleton 2024-05-31 10:19:41 +08:00
Lightczx
5511863d7f optimize home page load speed 2024-05-31 10:12:57 +08:00
DismissedLight
adf3f7e7b1 fix QA issues 2024-05-30 22:13:44 +08:00
DismissedLight
2232772110 adjust daily note settings to flyout 2024-05-30 21:59:49 +08:00
DismissedLight
cd343843b3 fix elevated pipe access rights 2024-05-30 21:48:04 +08:00
Lightczx
f5982f81c0 defer content load 2024-05-30 16:40:42 +08:00
Lightczx
1e38c43727 remove AlternatingItemsControl 2024-05-30 14:29:50 +08:00
Lightczx
7879f1278b Update InfoBarOverride.xaml 2024-05-30 12:59:20 +08:00
Lightczx
f8e9b4a1b3 fix pipe access control 2024-05-30 12:36:30 +08:00
Lightczx
c9ea4b358a fix #1650 2024-05-30 11:28:06 +08:00
Lightczx
75287473c5 adjust notifyicon logic and impl #1656 2024-05-30 10:39:20 +08:00
Lightczx
3948b81a48 fix #1657 2024-05-29 14:29:33 +08:00
DismissedLight
e5c751771c avoid exception when Shell_TrayWnd not ready 2024-05-28 22:34:32 +08:00
qhy040404
f7723d21a3 [skip ci] fix unexpected canceled workflow 2024-05-28 17:50:48 +08:00
Lightczx
4ce064a71a Add Vietnamese and fix guide maximized state 2024-05-28 17:28:53 +08:00
Masterain
b07c569a9e New Crowdin updates (#1634) 2024-05-28 17:07:00 +08:00
DismissedLight
c81c0c33d8 Merge pull request #1649 from DGP-Studio/dependabot/nuget/src/Snap.Hutao/develop/packages-3211eb08b6 2024-05-28 16:03:01 +08:00
DismissedLight
2274445303 Merge pull request #1645 from DGP-Studio/fix/jumplist 2024-05-28 16:02:13 +08:00
DismissedLight
271cac9a02 Merge pull request #1644 from DGP-Studio/fix/win10_notifyicon 2024-05-28 16:01:19 +08:00
Lightczx
9f8f2870ae remove blank spaces 2024-05-28 16:01:13 +08:00
DismissedLight
0cc4897354 deferload experiment 2024-05-27 23:24:03 +08:00
qhy040404
7aa4696ba5 drop else 2024-05-27 22:11:38 +08:00
dependabot[bot]
9e3ec32ae6 Bump the packages group in /src/Snap.Hutao with 3 updates
Bumps the packages group in /src/Snap.Hutao with 3 updates: [Microsoft.NET.Test.Sdk](https://github.com/microsoft/vstest), [MSTest.TestAdapter](https://github.com/microsoft/testfx) and [MSTest.TestFramework](https://github.com/microsoft/testfx).


Updates `Microsoft.NET.Test.Sdk` from 17.9.0 to 17.10.0
- [Release notes](https://github.com/microsoft/vstest/releases)
- [Changelog](https://github.com/microsoft/vstest/blob/main/docs/releases.md)
- [Commits](https://github.com/microsoft/vstest/compare/v17.9.0...v17.10.0)

Updates `MSTest.TestAdapter` from 3.3.1 to 3.4.0
- [Release notes](https://github.com/microsoft/testfx/releases)
- [Changelog](https://github.com/microsoft/testfx/blob/main/docs/Changelog.md)
- [Commits](https://github.com/microsoft/testfx/compare/v3.3.1...v3.4.0)

Updates `MSTest.TestFramework` from 3.3.1 to 3.4.0
- [Release notes](https://github.com/microsoft/testfx/releases)
- [Changelog](https://github.com/microsoft/testfx/blob/main/docs/Changelog.md)
- [Commits](https://github.com/microsoft/testfx/compare/v3.3.1...v3.4.0)

---
updated-dependencies:
- dependency-name: Microsoft.NET.Test.Sdk
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: packages
- dependency-name: MSTest.TestAdapter
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: packages
- dependency-name: MSTest.TestFramework
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: packages
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-05-27 07:57:43 +00:00
qhy040404
cd91af8ae9 use ref readonly 2024-05-27 09:29:58 +08:00
qhy040404
8680960931 clear jumplist 2024-05-26 22:10:15 +08:00
qhy040404
67f6fda900 another impl of hint when icon promoted for win10 2024-05-26 21:53:22 +08:00
DismissedLight
db4b0d3dcb Merge pull request #1641 from DGP-Studio/develop 2024-05-26 18:16:20 +08:00
DismissedLight
ec0abb4b16 bump version 2024-05-26 18:15:30 +08:00
DismissedLight
8cdf2b01f2 minor fix 2024-05-26 15:06:55 +08:00
qhy040404
c1bf3dad52 fix daily note setting 2024-05-26 11:16:46 +08:00
Lightczx
492e867391 exception refine 2024-05-24 17:16:33 +08:00
Lightczx
9cbb36f3e6 disable runtime marshaling 2024-05-24 16:54:05 +08:00
Lightczx
e15c06a194 fix build 2024-05-24 14:58:36 +08:00
Lightczx
f71a2a3d40 code style 2024-05-24 14:27:26 +08:00
DismissedLight
fb89e5f9f0 code style 2024-05-24 00:32:44 +08:00
DismissedLight
3f97f4207c Merge pull request #1636 from DGP-Studio/fix/1632
fix #1632
2024-05-23 20:14:47 +08:00
DismissedLight
a4ea798ad0 Merge pull request #1637 from DGP-Studio/feat/dailynote_prompt 2024-05-23 20:14:11 +08:00
qhy040404
80a0daf02d refine ui 2024-05-23 19:36:48 +08:00
qhy040404
c511d27b2f disable settings when not elevated 2024-05-23 19:36:48 +08:00
qhy040404
c5dcbc9c79 fix #1632 2024-05-23 19:36:48 +08:00
qhy040404
91949214ba apply suggestion 2024-05-23 19:21:29 +08:00
qhy040404
a126a330ff prompt user dailynote auto-refresh is not effective while notify icon is disabled 2024-05-23 19:21:29 +08:00
Lightczx
055846dfd6 fix notify icon context menu theme 2024-05-23 15:00:20 +08:00
DismissedLight
b68462b56e Update README.md 2024-05-23 11:46:48 +08:00
qhy040404
9d47082f47 fix #1631 2024-05-22 22:59:53 +08:00
DismissedLight
cd4516d9a7 Merge pull request #1630 from DGP-Studio/feat/1595 2024-05-22 17:02:13 +08:00
Lightczx
f7e94fe2f2 refine view 2024-05-22 16:46:06 +08:00
qhy040404
e93802d5a5 partial impl #1595 2024-05-22 15:37:04 +08:00
Lightczx
370f2fe1f7 impl #1542 2024-05-22 12:44:20 +08:00
qhy040404
c6f747a89b fix wrap layout 2024-05-21 23:53:23 +08:00
DismissedLight
cf431719df temp fix wrap layout 2024-05-21 23:14:51 +08:00
DismissedLight
c36c15f9be Merge pull request #1628 from DGP-Studio/fix/1609
fix #1609
2024-05-21 22:07:27 +08:00
DismissedLight
f80a63f557 Merge pull request #1627 from DGP-Studio/fix/1608
fix #1608
2024-05-21 22:03:48 +08:00
DismissedLight
36376f5af6 Update SH.resx 2024-05-21 22:03:10 +08:00
DismissedLight
2c057458a3 Merge pull request #1626 from DGP-Studio/fix/1613
fix #1613
2024-05-21 21:59:38 +08:00
DismissedLight
f0f50e0e30 Merge pull request #1625 from DGP-Studio/fix/1588
fix #1588
2024-05-21 21:48:25 +08:00
DismissedLight
b834daef93 Merge pull request #1619 from DGP-Studio/fix/new_dailynote_archon 2024-05-21 21:34:04 +08:00
DismissedLight
ff10543c21 Merge pull request #1615 from DGP-Studio/build/alpha 2024-05-21 21:12:58 +08:00
qhy040404
a55b25ae53 add alpha build constant 2024-05-21 17:34:45 +08:00
qhy040404
c0fbb823d4 fix empty archon quest in new added dailynote 2024-05-21 17:34:29 +08:00
qhy040404
4306af94be fix #1588 2024-05-21 17:34:03 +08:00
qhy040404
dfc83d4a34 fix #1613 2024-05-21 17:33:44 +08:00
qhy040404
c6a47eb7be fix #1608 2024-05-21 17:33:20 +08:00
qhy040404
7413a81ff4 fix #1609 2024-05-21 17:32:59 +08:00
Lightczx
24d143ea9f add France 2024-05-21 17:15:58 +08:00
DismissedLight
9f6611cd20 Merge pull request #1621 from DGP-Studio/feat/ShellNotifyIcon 2024-05-21 17:07:46 +08:00
Lightczx
784c727a38 hint when promoted 2024-05-21 17:05:55 +08:00
Lightczx
1bf517f95d add notifyicon setting 2024-05-21 15:27:10 +08:00
DismissedLight
8b9190d941 use icon path to determine guid 2024-05-19 17:04:08 +08:00
DismissedLight
16e0ab56f6 revert window scope 2024-05-19 14:48:52 +08:00
DismissedLight
b10df0bed1 revert isenabled 2024-05-19 13:25:56 +08:00
DismissedLight
c4d1f371f1 remove dailynote runtime elevation check 2024-05-19 13:09:10 +08:00
DismissedLight
92a151441b dailynote refresh refactor 2024-05-18 21:37:27 +08:00
Lightczx
faefc9c093 Update GameScreenCaptureSession.cs 2024-05-17 14:47:35 +08:00
Lightczx
c6e6d08707 capture HDR support 2024-05-17 11:59:06 +08:00
DismissedLight
4323ced7dc Update SpinWaitPolyfill.cs 2024-05-16 22:18:36 +08:00
DismissedLight
8a1781b449 fix registry watcher 2024-05-16 21:32:52 +08:00
Lightczx
72aff568b3 fixing capture 2024-05-16 17:24:36 +08:00
Masterain
8252e43bac Update alpha.yml
#1623
2024-05-15 21:18:35 -07:00
Lightczx
f15a692f03 fix window state 2024-05-16 11:11:49 +08:00
DismissedLight
5868d53cca fix rasterization scale 2024-05-15 22:51:54 +08:00
Lightczx
7d7c8d485e [skip ci] remove using 2024-05-15 17:14:29 +08:00
Lightczx
6edcf97ec9 refactor xaml window controller 2024-05-15 17:13:59 +08:00
Lightczx
f4593cd325 refactor cached image 2024-05-15 13:39:19 +08:00
Lightczx
29454b188e change alpha hint 2024-05-15 11:08:12 +08:00
Lightczx
942181561d enable feat build 2024-05-15 09:48:57 +08:00
DismissedLight
5d6e1dad01 launch game 2024-05-14 23:43:15 +08:00
DismissedLight
d52aa0d6b2 better resize policy 2024-05-14 22:19:20 +08:00
Lightczx
3ee729eacf DesktopWindowXamlSourceAccess 2024-05-14 17:31:16 +08:00
Lightczx
d3acbcde24 fix exit crashing 2024-05-13 16:33:12 +08:00
Lightczx
38e152befd window reference logic 2024-05-13 15:36:48 +08:00
DismissedLight
0f767f7e77 contextmenu 2024-05-12 22:36:22 +08:00
qhy040404
ce58e35a8f Merge pull request #1617 from DGP-Studio/typo/ci 2024-05-12 16:54:24 +08:00
目棃
a10e9e40a2 ✏️ 修正CI内容 2024-05-12 16:46:32 +08:00
Lightczx
dafd3128c2 adjust lifecycle 2024-05-11 16:23:52 +08:00
DismissedLight
0556373bcf notifyicon message 2024-05-10 22:37:59 +08:00
Lightczx
e8d3a065e6 support show icon 2024-05-10 17:30:03 +08:00
Lightczx
be223909d3 shell 2024-05-09 17:32:21 +08:00
Lightczx
7da778699b code style 2024-05-09 16:25:21 +08:00
Lightczx
5bfc790ea2 pooled frame 2024-05-08 17:30:04 +08:00
DismissedLight
fc13b85739 Merge pull request #1610 from DGP-Studio/fix/dailynotevmslim/metadata 2024-05-08 09:03:25 +08:00
qhy040404
df999dbf51 ensure metadata in slim 2024-05-07 22:35:36 +08:00
DismissedLight
688562c1dd capture 2024-05-07 21:19:26 +08:00
Lightczx
051a115f84 bump dependency version 2024-05-07 16:23:30 +08:00
Lightczx
b3d75f9fa5 impl #1607 2024-05-07 16:04:46 +08:00
DismissedLight
0b90bdaa42 Merge pull request #1555 from DGP-Studio/feat/dailynote_archon 2024-05-07 15:51:43 +08:00
Lightczx
77067d27d0 code style 2024-05-07 14:23:54 +08:00
Lightczx
e04542606e code style 2024-05-07 13:36:04 +08:00
Lightczx
5be958ff64 impl #1603 2024-05-07 11:04:21 +08:00
qhy040404
a57933388d add static resource 2024-05-06 16:58:57 +08:00
qhy040404
86c6c9574b ensure metadata 2024-05-06 16:58:57 +08:00
qhy040404
47e451df2f use different icon for different state 2024-05-06 16:58:56 +08:00
qhy040404
c8592c798b add icon 2024-05-06 16:58:56 +08:00
qhy040404
5fad960b20 fix build 2024-05-06 16:58:56 +08:00
qhy040404
44ba0a90a6 remove unnecessary abstraction 2024-05-06 16:58:56 +08:00
qhy040404
883c1ca95f refactor 2024-05-06 16:58:56 +08:00
qhy040404
1a29908e5d partial impl #1203 2024-05-06 16:58:56 +08:00
DismissedLight
3e9edd2f62 capture test 2024-05-05 15:41:46 +08:00
DismissedLight
f9c18d2555 Merge pull request #1604 from DGP-Studio/windows-graphics-capture 2024-05-04 20:20:11 +08:00
DismissedLight
b5afca256a fix build 2024-05-04 20:04:45 +08:00
DismissedLight
a0e79344b1 code style 2 2024-05-04 20:01:37 +08:00
DismissedLight
3b8eba3bb1 code style 2024-05-04 18:59:29 +08:00
DismissedLight
08a3db7dc9 capture test 2024-05-04 16:15:36 +08:00
Lightczx
c02e7b0db3 static zip download retry 2024-04-30 15:02:31 +08:00
DismissedLight
a51ede5048 Merge pull request #1592 from DGP-Studio/develop 2024-04-30 13:46:53 +08:00
Lightczx
1f31c946cc bump version 2024-04-30 13:36:34 +08:00
Lightczx
7dee4a0ea5 fix launch package convert 2024-04-30 13:35:05 +08:00
DismissedLight
2fdeaa2557 Merge pull request #1589 from DGP-Studio/develop 2024-04-30 10:26:15 +08:00
DismissedLight
fbffadd546 Merge pull request #1583 from DGP-Studio/l10n_develop 2024-04-30 10:22:20 +08:00
Lightczx
00abfe6695 bump version 2024-04-30 09:58:12 +08:00
DismissedLight
f2a4d2fa53 Merge pull request #1580 from DGP-Studio/feat/896 2024-04-30 09:43:23 +08:00
DismissedLight
4246fa3d13 Merge pull request #1587 from DGP-Studio/refactor/httpclient_recycle 2024-04-30 09:41:20 +08:00
Masterain
e0a5898b3a New translations sh.resx (English) 2024-04-29 17:55:19 -07:00
qhy040404
71ac87539f Trigger GC after disposing ViewModel 2024-04-30 00:30:11 +08:00
qhy040404
3959ce1c0a code style 2024-04-30 00:29:53 +08:00
qhy040404
a56f382f8b impl #896 2024-04-30 00:29:53 +08:00
DismissedLight
04c3498b54 fix wiki avatar/weapon margin 2024-04-29 23:53:08 +08:00
Lightczx
f304e0920f log failed download tasks 2024-04-29 16:43:08 +08:00
Lightczx
6fb276af9d refine NonRudeHWND 2024-04-29 11:44:41 +08:00
Lightczx
4bd55c308a fix exception throwing 2024-04-29 10:25:40 +08:00
Lightczx
98a9f5fec9 refine cast 2024-04-29 10:16:23 +08:00
DismissedLight
0420568e73 Merge pull request #1573 from DGP-Studio/fix/1571
fix #1571
2024-04-29 10:06:13 +08:00
Lightczx
45242ff8ce refine discord controller 2024-04-28 16:46:07 +08:00
Lightczx
074cc1194b add cancellationtoken 2024-04-28 15:43:07 +08:00
Lightczx
bd4a0f0d8e dailynote optimization 2024-04-28 15:36:59 +08:00
qhy040404
bbc2d7655c add operator 2024-04-28 14:33:31 +08:00
qhy040404
588aba1395 code style 2024-04-28 12:03:42 +08:00
qhy040404
611469beb3 fix #1571 2024-04-28 11:55:31 +08:00
Masterain
1b80f79189 New translations sh.resx (English) 2024-04-27 20:36:00 -07:00
Masterain
a8cfb7fcc4 New translations sh.resx (French) 2024-04-27 19:37:12 -07:00
Masterain
10445a73b4 New translations sh.resx (Indonesian) 2024-04-27 19:37:11 -07:00
Masterain
7d00cec7c6 New translations sh.resx (English) 2024-04-27 19:37:10 -07:00
Masterain
05674fb01a New translations sh.resx (Chinese Traditional) 2024-04-27 19:37:09 -07:00
Masterain
2c6682574f New translations sh.resx (Russian) 2024-04-27 19:37:08 -07:00
Masterain
53a95ddcb9 New translations sh.resx (Portuguese) 2024-04-27 19:37:07 -07:00
Masterain
bbfd5096d7 New translations sh.resx (Korean) 2024-04-27 19:37:06 -07:00
Masterain
24407ecc05 New translations sh.resx (Japanese) 2024-04-27 19:37:05 -07:00
DismissedLight
ff2521c02c Merge pull request #1581 from DGP-Studio/feat/custom_sa_homa_not_login_dialog 2024-04-28 10:25:15 +08:00
Lightczx
5954c1a0ab fix build failed 2024-04-26 14:49:50 +08:00
Lightczx
4dc753bf5a Merge branch 'develop' of https://github.com/DGP-Studio/Snap.Hutao into develop 2024-04-26 14:47:43 +08:00
Lightczx
bd3617c15a refactor cultivation 2024-04-26 14:47:40 +08:00
qhy040404
70da292f21 refine #1575 ui 2024-04-26 12:31:27 +08:00
DismissedLight
97c5e7d37f Merge pull request #1574 from DGP-Studio/fix/1485 2024-04-26 09:27:45 +08:00
DismissedLight
388f9d5657 Merge pull request #1575 from DGP-Studio/feat/1245 2024-04-26 09:24:50 +08:00
qhy040404
74e11f3823 impl #1245 2024-04-25 22:39:05 +08:00
qhy040404
c1305cda43 set passwordbox to a constant value 2024-04-25 22:13:48 +08:00
Lightczx
b0d5051957 refactor 2024-04-25 17:29:14 +08:00
Lightczx
6a42c36a76 optimization 2024-04-25 14:44:06 +08:00
Lightczx
7cf106ec50 avatar info optimization 2024-04-24 17:12:34 +08:00
DismissedLight
f12cd63c92 Merge pull request #1563 from DGP-Studio/fix/imagecache 2024-04-23 16:55:39 +08:00
Lightczx
c441fdb6b0 code style 2024-04-23 16:55:04 +08:00
DismissedLight
09a880525b Merge pull request #1567 from Natrium0521/develop 2024-04-23 15:58:19 +08:00
Lightczx
15212d8f21 code style 2024-04-23 15:55:53 +08:00
Natrium
a60c4bff08 fix empty announcement when localized regex not match 2024-04-23 11:52:44 +08:00
qhy040404
e02985926d code style 2024-04-23 11:33:54 +08:00
Natrium
09448b7137 fix empty announcement 2024-04-23 11:15:21 +08:00
Natrium
6487df776a Fix Announcement time display 2024-04-23 00:57:34 +08:00
DismissedLight
2be11c22df Merge pull request #1560 from DGP-Studio/feat/taskbar_elevated 2024-04-22 17:01:54 +08:00
Lightczx
9ecb3d5821 adjust HttpClient scope 2024-04-22 16:51:35 +08:00
Lightczx
ca64c3e0ef impl #1550 2024-04-22 15:56:51 +08:00
qhy040404
3fe726aa63 extract logo 2024-04-22 15:23:47 +08:00
qhy040404
6b7ffe9fe9 Update Snap.Hutao.csproj 2024-04-22 15:23:46 +08:00
qhy040404
5ed5729c4e extract launcher 2024-04-22 15:23:46 +08:00
qhy040404
9ba0066f40 allow to open elevated app from taskbar 2024-04-22 15:23:38 +08:00
Lightczx
9c639fbaa4 Merge branch 'develop' of https://github.com/DGP-Studio/Snap.Hutao into develop 2024-04-22 14:17:18 +08:00
Lightczx
a592816661 Add quest type 2024-04-22 14:17:15 +08:00
DismissedLight
ec9c5ebee1 Merge pull request #1557 from DGP-Studio/fix/geetest 2024-04-22 09:30:16 +08:00
DismissedLight
9475c19b64 Merge pull request #1556 from DGP-Studio/feat/patch_statistics 2024-04-22 09:28:45 +08:00
qhy040404
9bfe7f78ef add unsafe move and delete to file operation 2024-04-20 23:48:35 +08:00
qhy040404
88d7f0bcc7 fix miss image cache 2024-04-20 22:22:53 +08:00
qhy040404
4920da4ea2 fix geetest 2024-04-20 11:27:10 +08:00
qhy040404
99b2ccb33b add patch statistics 2024-04-20 11:06:16 +08:00
Lightczx
9b94a75d6f refactor 2024-04-19 16:18:57 +08:00
Lightczx
e390ad2839 AvatarViewBuilder 2024-04-19 15:21:59 +08:00
DismissedLight
3086d59674 Merge pull request #1552 from DGP-Studio/feat/unheld_statistics_items 2024-04-19 09:40:57 +08:00
Lightczx
cb00fdbda0 code style 2024-04-19 09:41:04 +08:00
DismissedLight
1702dfcdc6 Merge branch 'develop' into feat/unheld_statistics_items 2024-04-19 09:22:57 +08:00
Lightczx
4b54b343f9 summary factory update 2024-04-18 17:13:14 +08:00
qhy040404
292b21a759 fix build 2024-04-17 15:15:00 +08:00
qhy040404
29e9413022 code style 2024-04-17 15:11:27 +08:00
qhy040404
7c923aaa5e impl #1355 2024-04-17 15:11:27 +08:00
Lightczx
c6618be0fc InitializeDataContext 2024-04-17 15:05:26 +08:00
DismissedLight
45dd276b89 Merge pull request #1546 from DGP-Studio/revert/qr_login 2024-04-17 13:52:42 +08:00
DismissedLight
8a9fb38f49 Merge pull request #1543 from DGP-Studio/fix/chronicled_hutao_statistics 2024-04-17 13:51:56 +08:00
Lightczx
1249216491 Update HorizontalEqualPanel.cs 2024-04-17 13:50:27 +08:00
DismissedLight
4bf3f4151e Merge branch 'develop' into fix/chronicled_hutao_statistics 2024-04-17 13:40:35 +08:00
Lightczx
89d909b04f httpclient scope 2024-04-17 13:37:04 +08:00
qhy040404
2cec0f5e0e refactor GachaLog statistics 2024-04-17 11:03:38 +08:00
qhy040404
bbb97cd802 fix typo 2024-04-16 17:26:53 +08:00
qhy040404
67b058f126 fix hutao statistics unavailable 2024-04-16 17:26:53 +08:00
qhy040404
b98611ccd9 Revert "temporary fix qr login"
This reverts commit d4bd610fe2.
2024-04-16 17:26:30 +08:00
Lightczx
80d6d5eb2b fix build 2024-04-16 15:53:41 +08:00
Lightczx
f682bb57e8 refactor achievement 2024-04-16 15:51:30 +08:00
qhy040404
d8310b784f Update pull_request_template.md 2024-04-16 12:51:51 +08:00
Lightczx
486c6eb308 achievement service 2024-04-16 10:13:35 +08:00
Masterain
c5d04e09da Create pull_request_template.md 2024-04-15 18:43:38 -07:00
Lightczx
0629f7c4c9 Introducing IAppInfrastructureService 2024-04-15 17:29:20 +08:00
Lightczx
b49288a98f Update DiscordController.cs 2024-04-15 13:49:30 +08:00
Masterain
df61aa3968 Update README.md 2024-04-14 18:30:39 -07:00
DismissedLight
ee99d0b665 refactor static resource 2024-04-12 21:40:00 +08:00
Lightczx
72b62aa9c6 ServerGarbageCollection 2024-04-12 17:30:10 +08:00
Lightczx
6b031e1866 update static resource setting 2024-04-12 16:52:54 +08:00
Lightczx
59c03c7f3b update WAS to 1.5.2 2024-04-12 11:57:49 +08:00
Lightczx
c03a96b44f refine guide ui 2024-04-11 16:14:04 +08:00
DismissedLight
d5a97903d3 Merge pull request #1545 from DGP-Studio/feat/version1.10guide 2024-04-11 15:57:44 +08:00
Lightczx
7f998dc87f impl #1430 2024-04-11 15:48:11 +08:00
Lightczx
2367c4759d refactor 2024-04-10 16:53:21 +08:00
DismissedLight
043e3f07d8 Merge pull request #1539 from DGP-Studio/dependabot/nuget/src/Snap.Hutao/develop/packages-017b70aa21 2024-04-08 16:15:33 +08:00
dependabot[bot]
cd075c4dab Bump the packages group in /src/Snap.Hutao with 2 updates
Bumps the packages group in /src/Snap.Hutao with 2 updates: [MSTest.TestAdapter](https://github.com/microsoft/testfx) and [MSTest.TestFramework](https://github.com/microsoft/testfx).


Updates `MSTest.TestAdapter` from 3.2.2 to 3.3.1
- [Release notes](https://github.com/microsoft/testfx/releases)
- [Changelog](https://github.com/microsoft/testfx/blob/main/docs/Changelog.md)
- [Commits](https://github.com/microsoft/testfx/compare/v3.2.2...v3.3.1)

Updates `MSTest.TestFramework` from 3.2.2 to 3.3.1
- [Release notes](https://github.com/microsoft/testfx/releases)
- [Changelog](https://github.com/microsoft/testfx/blob/main/docs/Changelog.md)
- [Commits](https://github.com/microsoft/testfx/compare/v3.2.2...v3.3.1)

---
updated-dependencies:
- dependency-name: MSTest.TestAdapter
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: packages
- dependency-name: MSTest.TestFramework
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: packages
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-04-08 07:37:05 +00:00
Lightczx
65252f1f69 refactor launch game view model 2024-04-08 15:33:42 +08:00
DismissedLight
f5dd5f4c1d Merge pull request #1531 from DGP-Studio/feat/fix_config 2024-04-08 14:08:21 +08:00
Lightczx
27ce55f3f7 code style 2024-04-08 14:06:04 +08:00
qhy040404
311941bb89 code style 2024-04-08 14:01:59 +08:00
qhy040404
07e2489cab use header instead of another textblock 2024-04-08 12:11:46 +08:00
qhy040404
699ac60aaf apply suggestions 2024-04-08 12:00:16 +08:00
qhy040404
dc7bc7e35d fix compile error 2024-04-08 11:59:05 +08:00
qhy040404
bf67fcf3a2 add ability to fix missing config.ini 2024-04-08 11:59:05 +08:00
DismissedLight
5093246571 Merge pull request #1538 from DGP-Studio/feat/IFileOperation 2024-04-08 11:34:09 +08:00
Lightczx
94fe192581 add IFileOperation 2024-04-08 11:25:32 +08:00
Lightczx
c679032387 button builder 2024-04-08 09:40:53 +08:00
Lightczx
d119b056c7 refactor achievement viewmodel 2024-04-07 16:50:35 +08:00
Lightczx
ab95ce8ce8 code style 2024-04-07 15:07:53 +08:00
Lightczx
0ede5b158f button builder 2024-04-07 14:49:36 +08:00
Lightczx
6c9a98c2c9 refactor infobarservice 2024-04-07 13:30:38 +08:00
Lightczx
a725fc0e9e fix clamp upper bound 2024-04-07 10:46:09 +08:00
Lightczx
5251dd9343 clamp monitor index 2024-04-07 10:44:42 +08:00
Lightczx
0b71053bf9 backup&restore game config.ini 2024-04-02 16:55:53 +08:00
Lightczx
a91499171d update flow rework 2024-04-02 15:37:20 +08:00
Masterain
b6c474cc12 Update issue templates 2024-04-01 22:39:38 -07:00
Lightczx
e041def070 remove AddUserAsync 2024-04-01 16:50:33 +08:00
Masterain
2e81ddf3f4 在设置中增加低价原石购买站点链接
### Hello April 🎁
- Update Banner
2024-03-31 22:42:48 -07:00
DismissedLight
4d988e5500 Merge pull request #1527 from Masterain98/main
April Fools
2024-04-01 13:25:55 +08:00
Masterain
36aff679c0 Update Banner 2024-03-31 22:19:33 -07:00
Lightczx
d490393108 fix setting spacing 2024-03-29 16:52:37 +08:00
DismissedLight
1633f2c668 Merge pull request #1511 from DGP-Studio/readme2024 2024-03-29 15:48:37 +08:00
DismissedLight
241122eadc Merge pull request #1517 from DGP-Studio/develop 2024-03-29 15:47:39 +08:00
Masterain
339bb9292b Update SECURITY.md 2024-03-29 00:34:43 -07:00
DismissedLight
4e27d40b76 Merge pull request #1509 from DGP-Studio/l10n_develop 2024-03-29 15:29:48 +08:00
Masterain
4f42a299d1 New translations sh.resx (English) 2024-03-29 00:28:14 -07:00
Masterain
80aad5f09e New translations sh.resx (Indonesian) 2024-03-29 00:24:57 -07:00
Masterain
35370c392b New translations sh.resx (English) 2024-03-29 00:24:56 -07:00
Masterain
115dae8966 New translations sh.resx (Chinese Traditional) 2024-03-29 00:24:55 -07:00
Masterain
795e9730b9 New translations sh.resx (Russian) 2024-03-29 00:24:54 -07:00
Masterain
7dac0d6f73 New translations sh.resx (Portuguese) 2024-03-29 00:24:53 -07:00
Masterain
7c42b7e8ed New translations sh.resx (Korean) 2024-03-29 00:24:52 -07:00
Masterain
3c766f55b5 New translations sh.resx (Japanese) 2024-03-29 00:24:51 -07:00
Lightczx
38a07caeab update version 2024-03-29 15:22:49 +08:00
Lightczx
5fb55ea645 update desc 2024-03-29 15:19:43 +08:00
Masterain
aba568d8c6 New translations sh.resx (Indonesian) 2024-03-28 23:27:17 -07:00
Masterain
116bd58a81 New translations sh.resx (English) 2024-03-28 23:27:16 -07:00
Masterain
46cc5f7f1e New translations sh.resx (Chinese Traditional) 2024-03-28 23:27:15 -07:00
Masterain
3e5ca2440b New translations sh.resx (Russian) 2024-03-28 23:27:14 -07:00
Masterain
081a60f3f8 New translations sh.resx (Portuguese) 2024-03-28 23:27:13 -07:00
Masterain
4a5ddd872d New translations sh.resx (Korean) 2024-03-28 23:27:12 -07:00
Masterain
81e5159615 New translations sh.resx (Japanese) 2024-03-28 23:27:11 -07:00
Lightczx
d5eec58157 add hint for mihoyo passport login 2024-03-29 14:16:37 +08:00
Lightczx
0242d3d0ca fix #1504 2024-03-28 15:31:05 +08:00
Lightczx
3fcb4caaf1 wiki avatar title no wrap 2024-03-28 14:17:28 +08:00
DismissedLight
ae2ddee6c4 Merge pull request #1510 from GoddessLuBoYan/issue1427 2024-03-28 13:32:58 +08:00
Lightczx
089938c1c0 code style 2024-03-28 13:16:40 +08:00
Lightczx
c515f70e95 code style 2024-03-28 11:19:56 +08:00
Lightczx
317b68b1ce improve image cache 2024-03-28 11:18:09 +08:00
DismissedLight
7b5a6ccae0 Merge pull request #1513 from DGP-Studio/feat/cultivation_stat_finished 2024-03-28 11:00:33 +08:00
qhy040404
13108b6694 show finished icon if we have enough items 2024-03-27 16:23:30 +08:00
goddessluboyan
c4ff359995 修复多语言问题 2024-03-26 13:37:27 +08:00
goddessluboyan
70399f7a7d 删除调试用的信息 2024-03-26 13:37:27 +08:00
goddessluboyan
3d1a365079 实现对材料统计页面中的材料做初步排序。
更细致的排序、分类功能,需要集成观测枢功能才能进行。
2024-03-26 13:37:27 +08:00
Masterain
2b6d4af5a3 Update README.md 2024-03-25 17:48:41 -07:00
Masterain
80450660e4 Update README.md 2024-03-25 17:47:16 -07:00
Masterain
28b09d56f3 New translations sh.resx (Indonesian) 2024-03-25 07:59:18 -07:00
Masterain
995860463f New translations sh.resx (English) 2024-03-25 07:59:17 -07:00
Masterain
474d06457c New translations sh.resx (Chinese Traditional) 2024-03-25 07:59:16 -07:00
Masterain
7534729794 New translations sh.resx (Russian) 2024-03-25 07:59:15 -07:00
Masterain
167d66aa67 New translations sh.resx (Portuguese) 2024-03-25 07:59:14 -07:00
Masterain
e20a9f3ff4 New translations sh.resx (Korean) 2024-03-25 07:59:12 -07:00
Masterain
868232d98f New translations sh.resx (Japanese) 2024-03-25 07:59:11 -07:00
DismissedLight
ab1b3c02c8 Merge pull request #1500 from DGP-Studio/feat/suggestbox_not_found 2024-03-25 22:43:47 +08:00
DismissedLight
8ef5dc9302 code style 2024-03-25 22:41:58 +08:00
Masterain
4c7e02cd5c New translations sh.resx (Chinese Traditional) 2024-03-24 11:14:18 -07:00
Masterain
d8e0d74be6 New translations sh.resx (Chinese Traditional) 2024-03-24 10:09:39 -07:00
Masterain
655f97353c New translations sh.resx (Chinese Traditional) 2024-03-24 09:12:43 -07:00
qhy040404
a387e0dbf5 fix achievement search reset 2024-03-23 12:59:38 +08:00
qhy040404
8111c1e662 Disable unknown token 2024-03-23 12:58:49 +08:00
qhy040404
9cd9193425 show not found in view 2024-03-23 12:58:49 +08:00
qhy040404
d531c81fa2 show not found in search box 2024-03-23 12:58:49 +08:00
DismissedLight
1d0a72493e achievement city typedef 2024-03-21 22:27:16 +08:00
Lightczx
f2b361819b fix userview 2024-03-20 10:42:14 +08:00
qhy040404
41f7245a1a fix #1503 2024-03-19 22:46:58 +08:00
DismissedLight
889e914f7f colorized log message 2024-03-19 22:23:47 +08:00
Lightczx
9f90ec221c colorized 2024-03-19 17:30:23 +08:00
DismissedLight
8fc874fd09 Merge pull request #1498 from DGP-Studio/dependabot/nuget/src/Snap.Hutao/develop/packages-f9ad2d8712 2024-03-19 15:13:47 +08:00
Lightczx
f42ec1ea12 change banner color 2024-03-18 17:25:45 +08:00
Lightczx
5cc3cf264c refactor 2024-03-18 17:15:42 +08:00
Lightczx
e38517a2ad optimize uniformpanel 2024-03-18 16:54:17 +08:00
dependabot[bot]
cdc0fb8a82 Bump the packages group in /src/Snap.Hutao with 1 update
Bumps the packages group in /src/Snap.Hutao with 1 update: [coverlet.collector](https://github.com/coverlet-coverage/coverlet).


Updates `coverlet.collector` from 6.0.1 to 6.0.2
- [Release notes](https://github.com/coverlet-coverage/coverlet/releases)
- [Commits](https://github.com/coverlet-coverage/coverlet/compare/v6.0.1...v6.0.2)

---
updated-dependencies:
- dependency-name: coverlet.collector
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: packages
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-03-18 07:31:21 +00:00
ema
d50a6df14c upgrade SH.ja.resx translation (#1491) 2024-03-16 17:06:34 +08:00
DismissedLight
4886904530 refactor controls 2024-03-16 16:59:19 +08:00
DismissedLight
ac34376c13 Merge pull request #1484 from DGP-Studio/feat/spinwait_game_window 2024-03-16 16:57:17 +08:00
qhy040404
3bcee3d149 Apply suggestion 2024-03-16 16:05:18 +08:00
qhy040404
3d3b03851e Use SpinWait to wait game window instead of WaitForInputIdle 2024-03-16 15:59:38 +08:00
DismissedLight
dc64302424 Merge pull request #1483 from DGP-Studio/fix/theme 2024-03-16 14:57:54 +08:00
ema
db3a611c6e upgrade SH.ja.resx translation (#1491) 2024-03-16 14:54:23 +08:00
qhy040404
a2586b0ef2 fix different theme between window and dialog 2024-03-15 20:32:16 +08:00
DismissedLight
eee84a338e significantly reduce uniformstaggeredlayout resize lag 2024-03-15 20:24:32 +08:00
Lightczx
be30362b52 uniformstaggeredlayout optimization 2024-03-15 17:18:25 +08:00
Lightczx
38f36bbb82 fix gachalog page closing crash 2024-03-15 14:21:38 +08:00
Lightczx
704866b16a update dependency 2024-03-15 13:43:55 +08:00
Lightczx
ca9783bc1b corner radius on auto suggest tokenbox 2024-03-15 10:54:06 +08:00
DismissedLight
6e8e151fff fix unlocking fps 2024-03-14 20:32:06 +08:00
DismissedLight
b98dc9f5d3 fix unlocking fps 2024-03-14 19:58:01 +08:00
Masterain
206100d8ef New Crowdin updates (#1477) 2024-03-14 14:41:52 +08:00
Lightczx
1a74c7ca96 fix #1476 2024-03-14 11:24:55 +08:00
DismissedLight
88528fa28d hide zero count section 2024-03-13 21:18:11 +08:00
DismissedLight
263cea9225 Merge pull request #1475 from DGP-Studio/fix/token_ui 2024-03-13 21:09:13 +08:00
Lightczx
2879bd653a add chronicled wish cloud statistics 2024-03-13 17:25:42 +08:00
qhy040404
3d061e3bdb adjust ui 2024-03-13 16:52:46 +08:00
qhy040404
022527829e refine wiki token ui 2 2024-03-13 16:39:16 +08:00
qhy040404
0fcf10dfa7 refine wiki token ui 2024-03-13 16:16:44 +08:00
Lightczx
7fc6ecc3c3 fix gachalog overview scrollbar margin 2024-03-13 15:17:40 +08:00
DismissedLight
fad5f8ada3 Merge pull request #1473 from DGP-Studio/develop 2024-03-13 14:15:42 +08:00
Lightczx
238c2036f6 bump version 2024-03-13 14:03:49 +08:00
DismissedLight
e48f740e46 Merge pull request #1472 from DGP-Studio/l10n_develop 2024-03-13 13:57:16 +08:00
Masterain
8574a3d825 New translations sh.resx (English) 2024-03-12 22:56:21 -07:00
DismissedLight
08f27e8ee7 Merge pull request #1463 from DGP-Studio/l10n_develop 2024-03-13 13:55:23 +08:00
Lightczx
c8b3779d97 compat UIGF v3.0 2024-03-13 11:43:39 +08:00
Lightczx
54cbd9dfb9 fix web cache query provider 2024-03-13 10:45:34 +08:00
DismissedLight
65517abcb4 Merge pull request #1469 from DGP-Studio/fix/titlebar_darkmode 2024-03-13 09:04:26 +08:00
qhy040404
87c3043fd9 fix wrong titlebar color when manually manually setting the color theme 2024-03-12 22:34:32 +08:00
DismissedLight
762bc14b88 adjust ui for city banner 2024-03-12 21:35:06 +08:00
DismissedLight
51dfc7020f Merge pull request #1466 from DGP-Studio/dependabot/nuget/src/Snap.Hutao/develop/packages-ba3ce57765 2024-03-12 09:37:41 +08:00
dependabot[bot]
47dda1bebc Bump the packages group in /src/Snap.Hutao with 1 update
Bumps the packages group in /src/Snap.Hutao with 1 update: [MSTest.TestAdapter](https://github.com/microsoft/testfx).


Updates `MSTest.TestAdapter` from 3.2.1 to 3.2.2
- [Release notes](https://github.com/microsoft/testfx/releases)
- [Changelog](https://github.com/microsoft/testfx/blob/main/docs/Changelog.md)
- [Commits](https://github.com/microsoft/testfx/compare/v3.2.1...v3.2.2)

---
updated-dependencies:
- dependency-name: MSTest.TestAdapter
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: packages
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-03-11 07:12:02 +00:00
Lightczx
1a300e8b9c fix predownload latest path and name 2024-03-11 11:47:43 +08:00
Lightczx
16e8a17614 disable launchoptions by default 2024-03-11 11:24:41 +08:00
Lightczx
a5c75f9465 revert BGI process waitforinputidle 2024-03-11 11:16:23 +08:00
Lightczx
0cb59808a1 refactor unlocking fps 2024-03-11 11:01:57 +08:00
Masterain
80439ed673 New translations sh.resx (Chinese Traditional) 2024-03-10 18:37:38 -07:00
Lightczx
d632002e4b Sync Scighost/Starward#692 2024-03-11 09:33:21 +08:00
DismissedLight
cf6a972d55 Update FeedbackPage.xaml 2024-03-10 22:39:11 +08:00
DismissedLight
e1a976f02d fix theme switch dropping shadow 2024-03-10 22:28:03 +08:00
DismissedLight
dbedc2a00d fix equal panel spacing 2024-03-10 22:23:10 +08:00
DismissedLight
03312f1d52 Merge pull request #1464 from DGP-Studio/fix/horizontal_equal_panel 2024-03-10 21:37:03 +08:00
qhy040404
47f29de9c6 fix measure 2024-03-10 21:30:15 +08:00
Masterain
708da5769a New translations sh.resx (Indonesian) 2024-03-10 01:31:59 -08:00
Masterain
8bce2d3b28 New translations sh.resx (English) 2024-03-10 01:31:58 -08:00
Masterain
5252e7b451 New translations sh.resx (Chinese Traditional) 2024-03-10 01:31:56 -08:00
Masterain
2f5d884425 New translations sh.resx (Russian) 2024-03-10 01:31:55 -08:00
Masterain
5aea3695b9 New translations sh.resx (Portuguese) 2024-03-10 01:31:54 -08:00
Masterain
462e570bc1 New translations sh.resx (Korean) 2024-03-10 01:31:53 -08:00
Masterain
511d113c65 New translations sh.resx (Japanese) 2024-03-10 01:31:52 -08:00
Lightczx
2a5e7e0136 temp progress 2024-03-10 17:30:57 +08:00
Lightczx
177e7a6233 fix #1459 2024-03-10 14:29:57 +08:00
DismissedLight
bd09b303ab Merge pull request #1456 from DGP-Studio/fix/darkmode
fix #1434
2024-03-10 14:13:10 +08:00
qhy040404
5538b74939 remove WindowOptions.UseSystemBackdrop 2024-03-10 12:16:30 +08:00
qhy040404
fda289421b code style 2024-03-10 12:16:30 +08:00
qhy040404
c0abe7f7c5 fix #1434 2024-03-10 12:16:30 +08:00
DismissedLight
e95732d448 Merge pull request #1454 from DGP-Studio/fix/navigate_crash 2024-03-10 12:10:13 +08:00
DismissedLight
9e52a87d11 Merge pull request #1457 from DGP-Studio/fix/composition_image_delay 2024-03-10 12:03:29 +08:00
qhy040404
66bce570cc Update build.cake 2024-03-10 10:46:46 +08:00
qhy040404
a5091134b0 fix typo 2024-03-10 10:46:46 +08:00
qhy040404
59c9845ad0 fix navigation crash 2024-03-10 10:46:46 +08:00
qhy040404
2db829e1e2 add delay to fix blink again 2024-03-10 10:46:37 +08:00
DismissedLight
1a64328270 Update GachaTypeComparer.cs 2024-03-09 16:48:37 +08:00
DismissedLight
1c847626c7 Merge pull request #1453 from Mikachu2333/develop 2024-03-08 16:12:08 +08:00
LinkChou
062a09c632 correct 2024-03-08 12:16:55 +08:00
LinkChou
7433c1832a add tips about 'test binary package' 2024-03-07 19:41:42 +08:00
Lightczx
252649f28c fix #1429 2024-03-07 16:56:18 +08:00
Lightczx
75dda65c55 impl #1432 2024-03-07 16:53:25 +08:00
Lightczx
a9b165882f fix #1433 2024-03-07 16:49:15 +08:00
Lightczx
e41e913558 code style 2024-03-07 16:44:06 +08:00
Lightczx
2d9125d369 fix #1443 2024-03-07 16:37:26 +08:00
DismissedLight
2c7a6d152c Merge pull request #1445 from DGP-Studio/feat/1434 2024-03-07 16:27:54 +08:00
Lightczx
0c4c509fd6 code style 2024-03-07 16:27:01 +08:00
DismissedLight
7dba08451c Merge branch 'develop' into feat/1434 2024-03-07 16:20:48 +08:00
DismissedLight
a55cb89fe8 Merge pull request #1452 from DGP-Studio/fix/layoutcycle_2 2024-03-07 16:20:17 +08:00
Lightczx
4aa9557526 code style 2024-03-07 16:20:10 +08:00
qhy040404
38577f9813 apply suggestion 2024-03-07 13:37:22 +08:00
qhy040404
91361ddab5 resolve review 2024-03-07 13:26:35 +08:00
qhy040404
5ced8f6c71 impl #1434 2024-03-07 13:26:35 +08:00
qhy040404
55706e68f0 use self impl EqualPanel to fix layout cycle 2024-03-07 13:25:03 +08:00
qhy040404
63c4bb6a23 fix command bar blink 2024-03-07 13:00:52 +08:00
Lightczx
baa4b88622 refine spiralabyss team ui 2024-03-06 17:11:23 +08:00
DismissedLight
de2ce0db63 Merge pull request #1444 from DGP-Studio/feat/refresh_ui_for_team_appearence 2024-03-06 15:47:45 +08:00
Lightczx
6cbf8ca918 code style 2024-03-06 15:43:46 +08:00
DismissedLight
df125904a6 Merge branch 'develop' into feat/refresh_ui_for_team_appearence 2024-03-06 14:20:36 +08:00
Lightczx
1bad9d0928 fix #1449 2024-03-06 14:19:04 +08:00
DismissedLight
a762166db4 Merge branch 'develop' into feat/refresh_ui_for_team_appearence 2024-03-06 14:09:23 +08:00
DismissedLight
f432e5ba42 Merge pull request #1437 from DGP-Studio/activity-city-banner-compat 2024-03-06 14:07:47 +08:00
Lightczx
46dd4db25c fixup endid indexer setter 2024-03-06 14:04:04 +08:00
Lightczx
2e685182e6 fixup endid indexer getter 2024-03-06 14:01:53 +08:00
Lightczx
4f1bbd2e89 typo fix 2024-03-06 13:58:34 +08:00
qhy040404
0f5b6dda16 refresh ui for team appearance 2024-03-06 12:02:56 +08:00
Lightczx
4c38bb528f basic support 2024-03-06 11:57:37 +08:00
Lightczx
44e7f7482c minor adjustment 2024-03-06 11:55:37 +08:00
Lightczx
8a2fa3c701 factory completed 2024-03-06 11:55:37 +08:00
DismissedLight
6e10819609 Merge pull request #1441 from DGP-Studio/dependabot/nuget/src/Snap.Hutao/develop/packages-15667d2017 2024-03-06 09:16:27 +08:00
dependabot[bot]
c1b838bd97 Bump the packages group in /src/Snap.Hutao with 2 updates
Bumps the packages group in /src/Snap.Hutao with 2 updates: [MSTest.TestAdapter](https://github.com/microsoft/testfx) and [MSTest.TestFramework](https://github.com/microsoft/testfx).


Updates `MSTest.TestAdapter` from 3.2.1 to 3.2.2
- [Release notes](https://github.com/microsoft/testfx/releases)
- [Changelog](https://github.com/microsoft/testfx/blob/main/docs/Changelog.md)
- [Commits](https://github.com/microsoft/testfx/compare/v3.2.1...v3.2.2)

Updates `MSTest.TestFramework` from 3.2.1 to 3.2.2
- [Release notes](https://github.com/microsoft/testfx/releases)
- [Changelog](https://github.com/microsoft/testfx/blob/main/docs/Changelog.md)
- [Commits](https://github.com/microsoft/testfx/compare/v3.2.1...v3.2.2)

---
updated-dependencies:
- dependency-name: MSTest.TestAdapter
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: packages
- dependency-name: MSTest.TestFramework
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: packages
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-03-05 16:03:28 +00:00
DismissedLight
268c4c6c71 Merge pull request #1421 from DGP-Studio/feat/wikisuggestbox 2024-03-05 23:59:39 +08:00
DismissedLight
59dabaa5be code style 2024-03-05 23:59:23 +08:00
DismissedLight
dcac7ac792 Merge pull request #1431 from DGP-Studio/fix/minor 2024-03-05 21:45:00 +08:00
qhy040404
2ad6dad282 minor fix 2024-03-05 17:28:01 +08:00
qhy040404
4185336556 minor ui adjustment 2024-03-05 17:10:31 +08:00
qhy040404
15a627e50a init all tokens first 2024-03-05 16:55:28 +08:00
qhy040404
2ea53fd39d Frozen Dictionaries 2024-03-04 18:02:00 +08:00
qhy040404
6de3cba550 remove unused code 2024-03-04 00:09:38 +08:00
qhy040404
03c1bacfe9 maybe code style 2024-03-04 00:01:52 +08:00
qhy040404
d157476a9a minor fix 2024-03-03 21:37:44 +08:00
qhy040404
e35c03ac90 support or in wiki search 2024-03-03 21:03:28 +08:00
qhy040404
9619835cc2 migrate to TokenizingTextBox 2024-03-03 16:23:25 +08:00
qhy040404
6936a30a74 finish suggestion methods 2024-03-03 16:23:19 +08:00
Lightczx
506d198167 update to was 1.5 2024-03-01 09:30:43 +08:00
DismissedLight
9c2131cb9d Merge pull request #1426 from DGP-Studio/dependabot/nuget/src/Snap.Hutao/develop/packages-dcc47c4d6c 2024-02-27 09:21:58 +08:00
DismissedLight
896e3d49f2 Merge branch 'develop' into dependabot/nuget/src/Snap.Hutao/develop/packages-dcc47c4d6c 2024-02-27 09:21:30 +08:00
DismissedLight
7da24790c4 Merge pull request #1423 from Masterain98/main 2024-02-26 17:02:25 +08:00
DismissedLight
ebf163f200 Merge branch 'develop' into dependabot/nuget/src/Snap.Hutao/develop/packages-dcc47c4d6c 2024-02-26 16:59:23 +08:00
Lightczx
26043a6a73 Add furniture data struct 2024-02-26 16:35:36 +08:00
Masterain
ad67001556 Update LaunchGame.png 2024-02-26 15:28:25 +08:00
dependabot[bot]
428cd35a7f Bump the packages group in /src/Snap.Hutao with 3 updates
Bumps the packages group in /src/Snap.Hutao with 3 updates: [MSTest.TestAdapter](https://github.com/microsoft/testfx), [MSTest.TestFramework](https://github.com/microsoft/testfx) and [coverlet.collector](https://github.com/coverlet-coverage/coverlet).


Updates `MSTest.TestAdapter` from 3.2.1 to 3.2.2
- [Release notes](https://github.com/microsoft/testfx/releases)
- [Changelog](https://github.com/microsoft/testfx/blob/main/docs/Changelog.md)
- [Commits](https://github.com/microsoft/testfx/compare/v3.2.1...v3.2.2)

Updates `MSTest.TestFramework` from 3.2.1 to 3.2.2
- [Release notes](https://github.com/microsoft/testfx/releases)
- [Changelog](https://github.com/microsoft/testfx/blob/main/docs/Changelog.md)
- [Commits](https://github.com/microsoft/testfx/compare/v3.2.1...v3.2.2)

Updates `coverlet.collector` from 6.0.0 to 6.0.1
- [Release notes](https://github.com/coverlet-coverage/coverlet/releases)
- [Commits](https://github.com/coverlet-coverage/coverlet/compare/v6.0.0...v6.0.1)

---
updated-dependencies:
- dependency-name: MSTest.TestAdapter
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: packages
- dependency-name: MSTest.TestFramework
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: packages
- dependency-name: coverlet.collector
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: packages
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-02-26 07:16:52 +00:00
qhy040404
1cf3450264 fix static resource download 2024-02-25 23:29:45 +08:00
DismissedLight
1849ac16da adjust regex 2024-02-25 16:23:45 +08:00
DismissedLight
4e9d87af50 fix ja-jp announcement 2024-02-25 15:53:09 +08:00
DismissedLight
eb125e547f add mask when no backdrop 2024-02-24 20:24:46 +08:00
Lightczx
c17798a8c9 code style 2024-02-23 10:22:24 +08:00
DismissedLight
fa9b39d134 Merge pull request #1412 from DGP-Studio/fix/hotkey_notify 2024-02-23 09:42:10 +08:00
qhy040404
8dc85c7a25 prompt if hotkey not registered 2024-02-23 09:39:50 +08:00
DismissedLight
5845c718e1 Merge pull request #1419 from DGP-Studio/feat/real_time_bg 2024-02-23 09:36:25 +08:00
Lightczx
0c093851ed code style 2024-02-23 09:33:55 +08:00
qhy040404
04c187aa16 real time refresh background 2024-02-22 22:34:12 +08:00
Lightczx
25cf9f5356 code style 2024-02-22 10:26:43 +08:00
DismissedLight
c30c8b114a re-enable backdrop 2024-02-21 23:38:57 +08:00
DismissedLight
7a572631e9 Merge pull request #1415 from DGP-Studio/develop 2024-02-21 20:35:56 +08:00
DismissedLight
41f5a04e5a Merge branch 'main' into develop 2024-02-21 20:35:38 +08:00
DismissedLight
4f26d6efc2 update package version 2024-02-21 20:33:18 +08:00
Masterain
0d6b5e595e New Crowdin updates (#1413) 2024-02-21 20:29:41 +08:00
DismissedLight
e30bebd1a3 Update StatisticsCard.xaml 2024-02-21 20:25:56 +08:00
Masterain
ffb34c0e93 New Crowdin updates (#1411) 2024-02-21 20:25:12 +08:00
Lightczx
35b35ab649 minor fix 5 2024-02-21 16:29:30 +08:00
Lightczx
f067350cd8 minor fix 2024-02-21 15:28:05 +08:00
Lightczx
14648dafe8 adjust language order 2024-02-21 14:04:24 +08:00
Lightczx
7a7d81cfee add static resource hint for more situation 2024-02-21 13:55:07 +08:00
Lightczx
30c055e7ba impl #1373 #1389 2024-02-21 11:57:41 +08:00
qhy040404
6a922d9db6 更新 alpha.yml 2024-02-21 09:52:20 +08:00
DismissedLight
02a6e64a8c Merge pull request #1408 from DGP-Studio/fix/launch 2024-02-20 14:40:57 +08:00
qhy040404
51c4e66472 reorder launch pipeline 2024-02-20 14:37:29 +08:00
Lightczx
48875195bf add wallpaper api 2024-02-20 14:25:48 +08:00
qhy040404
a179e0e838 Update build.cake (#1405) 2024-02-20 11:54:15 +08:00
qhy040404
00c3e94e97 Update alpha.yml 2024-02-20 11:27:14 +08:00
qhy040404
eec7224c07 Update alpha.yml 2024-02-20 11:27:13 +08:00
qhy040404
85bcf37b1b Update alpha.yml 2024-02-20 10:43:27 +08:00
qhy040404
465c7035c0 Update alpha.yml 2024-02-20 10:31:23 +08:00
DismissedLight
11620816ec Merge pull request #1403 from DGP-Studio/dependabot/nuget/src/Snap.Hutao/develop/packages-a995a009f5 2024-02-20 09:07:19 +08:00
dependabot[bot]
c5b75d6f82 Bump the packages group in /src/Snap.Hutao with 1 update
Bumps the packages group in /src/Snap.Hutao with 1 update: [MSTest.TestAdapter](https://github.com/microsoft/testfx).


Updates `MSTest.TestAdapter` from 3.2.0 to 3.2.1
- [Release notes](https://github.com/microsoft/testfx/releases)
- [Changelog](https://github.com/microsoft/testfx/blob/main/docs/Changelog.md)
- [Commits](https://github.com/microsoft/testfx/compare/v.3.2.0...v3.2.1)

---
updated-dependencies:
- dependency-name: MSTest.TestAdapter
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: packages
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-02-19 09:59:22 +00:00
qhy040404
6241bbc997 Setup dependabot for actions 2024-02-19 17:57:17 +08:00
qhy040404
afbd8ec6ad Revert "Update alpha.yml"
This reverts commit 288cc841ac.
2024-02-19 17:41:32 +08:00
qhy040404
288cc841ac Update alpha.yml 2024-02-19 17:26:00 +08:00
Lightczx
a9295c0a37 impl #1388 2024-02-19 16:58:55 +08:00
DismissedLight
29cd690032 Merge pull request #1402 from DGP-Studio/dependabot/nuget/src/Snap.Hutao/develop/packages-f23264728b 2024-02-19 15:45:00 +08:00
dependabot[bot]
78d8539ae2 Bump the packages group in /src/Snap.Hutao with 2 updates
Bumps the packages group in /src/Snap.Hutao with 2 updates: [MSTest.TestAdapter](https://github.com/microsoft/testfx) and [MSTest.TestFramework](https://github.com/microsoft/testfx).


Updates `MSTest.TestAdapter` from 3.2.0 to 3.2.1
- [Release notes](https://github.com/microsoft/testfx/releases)
- [Changelog](https://github.com/microsoft/testfx/blob/main/docs/Changelog.md)
- [Commits](https://github.com/microsoft/testfx/compare/v.3.2.0...v3.2.1)

Updates `MSTest.TestFramework` from 3.2.0 to 3.2.1
- [Release notes](https://github.com/microsoft/testfx/releases)
- [Changelog](https://github.com/microsoft/testfx/blob/main/docs/Changelog.md)
- [Commits](https://github.com/microsoft/testfx/compare/v.3.2.0...v3.2.1)

---
updated-dependencies:
- dependency-name: MSTest.TestAdapter
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: packages
- dependency-name: MSTest.TestFramework
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: packages
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-02-19 07:44:34 +00:00
Lightczx
7dec87586b fix #1233 2024-02-19 11:33:27 +08:00
Lightczx
d169f355f3 impl #1233 2024-02-19 10:33:25 +08:00
qhy040404
e1784e2078 Update issue templates 2024-02-18 21:16:44 +08:00
Lightczx
32b1b698df update logging message 2024-02-18 17:30:24 +08:00
Lightczx
d6c7df1593 update gacha statistics card style 2024-02-18 15:30:05 +08:00
Lightczx
904fdf7fc9 fix #1391 2024-02-18 09:43:51 +08:00
Lightczx
b3e4ebb5d3 bump nuget package version 2024-02-18 09:33:11 +08:00
DismissedLight
09b9af4575 Merge pull request #1401 from DGP-Studio/fix/1400
fix #1400
2024-02-18 09:18:48 +08:00
Lightczx
8930548f44 code style 2024-02-18 09:19:09 +08:00
DismissedLight
34dbcc6f5d Merge pull request #1392 from DGP-Studio/dependabot/nuget/src/Snap.Hutao/develop/packages-dd5dd83d2f 2024-02-18 09:00:11 +08:00
qhy040404
75c25cec53 show warning if discord is not available 2024-02-17 14:00:23 +08:00
qhy040404
22251ca937 fix #1400 2024-02-17 11:28:36 +08:00
qhy040404
57c9531db8 fix #1365 again 2024-02-16 22:19:55 +08:00
dependabot[bot]
fd73743159 Bump the packages group in /src/Snap.Hutao with 1 update
Bumps the packages group in /src/Snap.Hutao with 1 update: [Microsoft.NET.Test.Sdk](https://github.com/microsoft/vstest).


Updates `Microsoft.NET.Test.Sdk` from 17.8.0 to 17.9.0
- [Release notes](https://github.com/microsoft/vstest/releases)
- [Changelog](https://github.com/microsoft/vstest/blob/main/docs/releases.md)
- [Commits](https://github.com/microsoft/vstest/compare/v17.8.0...v17.9.0)

---
updated-dependencies:
- dependency-name: Microsoft.NET.Test.Sdk
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: packages
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-02-12 07:47:05 +00:00
qhy040404
6594d9032d fix wrong setting state 2024-02-12 11:29:25 +08:00
DismissedLight
ae1b452697 minor fix 2024-02-09 15:40:48 +08:00
DismissedLight
bc3df782e4 Merge pull request #1380 from DGP-Studio/fix/1379
fix #1379
2024-02-09 14:16:39 +08:00
qhy040404
3ef117e683 fix #1379 2024-02-09 12:22:52 +08:00
qhy040404
8b1613d46f fix #1316 2 2024-02-09 09:23:10 +08:00
qhy040404
c2708aaedd minor fix 2024-02-09 09:19:30 +08:00
DismissedLight
db3de01eec impl #1375 2024-02-08 17:04:31 +08:00
qhy040404
635b52980b Update .gitlab-ci.yml 2024-02-07 21:13:59 +08:00
Lightczx
4988c1bd47 fixup image scale logic 2024-02-07 16:51:12 +08:00
Lightczx
fd499e372c fix #1316 2024-02-07 16:36:24 +08:00
Lightczx
a6c376cd44 fix background image switch crash 2024-02-07 16:24:56 +08:00
Lightczx
425b3789bf bump version 2024-02-07 15:08:53 +08:00
DismissedLight
a6986bc201 Merge pull request #1370 from DGP-Studio/develop
Co-authored-by: t0piy <t.tony.br01@gmail.com>
Co-authored-by: Tony <66571593+t0piy@users.noreply.github.com>
Co-authored-by: Masterain <i@irain.in>
Co-authored-by: qhy040404 <qhy040404@163.com>
Co-authored-by: qhy040404 <45379733+qhy040404@users.noreply.github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Scighost <scighost@outlook.com>
2024-02-07 14:09:49 +08:00
Masterain
301a14611a New Crowdin updates (#1339) 2024-02-07 14:05:17 +08:00
Lightczx
59db7d968a clear multiple user selection & ignore same background 2024-02-07 13:34:55 +08:00
Lightczx
45f4b46e9e add default background 2024-02-07 12:02:38 +08:00
Lightczx
82b5d9b12a revert client convertion permission check for special folder 2024-02-07 10:33:08 +08:00
DismissedLight
6fb5cfe25d Merge branch 'main' into develop 2024-02-07 09:58:21 +08:00
Lightczx
1df78345c5 fix AdvancedCollectionView compare 2024-02-07 09:12:02 +08:00
DismissedLight
fd817af9c3 refine ui 2024-02-06 23:31:24 +08:00
Lightczx
3f6efe2e24 custom background image 2024-02-06 17:31:19 +08:00
DismissedLight
ef6d88ba2e Merge pull request #1366 from DGP-Studio/refine/1334 2024-02-06 11:16:58 +08:00
Lightczx
26748e5885 generic AdvancedCollectionView 2024-02-06 11:16:59 +08:00
DismissedLight
5f180846f6 refactor 2024-02-05 23:08:00 +08:00
DismissedLight
57ea6bb34e minor style 2024-02-05 22:03:08 +08:00
qhy040404
95024e4107 refine #1334 2024-02-05 21:47:52 +08:00
DismissedLight
678ec191a6 Merge pull request #1364 from DGP-Studio/feat/notification_permission_disabled 2024-02-05 17:26:11 +08:00
Lightczx
40b26d9d3c code style 2024-02-05 17:25:59 +08:00
qhy040404
e5677e7de4 detect notification permission
And prevent the crash caused by lack of permission when sending toast
2024-02-05 16:53:50 +08:00
Lightczx
9ae8b182e7 fix empty ui alignment 2024-02-05 16:43:29 +08:00
DismissedLight
02fe498cce Merge pull request #1363 from DGP-Studio/dependabot/nuget/src/Snap.Hutao/develop/packages-dd9cc865bd 2024-02-05 15:52:16 +08:00
Lightczx
f924f78ee2 code style 2024-02-05 15:52:00 +08:00
Lightczx
977e749939 rename style 2024-02-05 15:35:02 +08:00
dependabot[bot]
f8ad3b98fc Bump the packages group in /src/Snap.Hutao with 1 update
Bumps the packages group in /src/Snap.Hutao with 1 update: [MSTest.TestAdapter](https://github.com/microsoft/testfx).


Updates `MSTest.TestAdapter` from 3.1.1 to 3.2.0
- [Release notes](https://github.com/microsoft/testfx/releases)
- [Changelog](https://github.com/microsoft/testfx/blob/main/docs/Changelog.md)
- [Commits](https://github.com/microsoft/testfx/compare/v3.1.1...v.3.2.0)

---
updated-dependencies:
- dependency-name: MSTest.TestAdapter
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: packages
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-02-05 07:13:34 +00:00
Lightczx
ee39f7fec5 refine all page ui 2024-02-05 13:55:16 +08:00
DismissedLight
c8c1d21c9b refine wiki avatar page 2024-02-04 23:29:01 +08:00
Lightczx
f06825f246 refine cultivation page 2024-02-04 11:23:52 +08:00
qhy040404
72395fdb89 say goodbye to azp 2024-02-04 11:20:36 +08:00
Lightczx
8954f7e325 support Asia length 10 uid 2024-02-04 09:30:07 +08:00
DismissedLight
976441de18 refine spiralabyss page 2024-02-03 23:13:25 +08:00
DismissedLight
60a49971f6 Merge pull request #1356 from DGP-Studio/feat/reorder 2024-02-03 21:50:20 +08:00
DismissedLight
fb5de92283 code style 2024-02-03 21:49:51 +08:00
qhy040404
046f3ace94 reorderable user 2024-02-03 17:28:50 +08:00
qhy040404
4c369ad0ad impl #1334 2024-02-03 17:28:50 +08:00
DismissedLight
7efaaae3e1 fix syntax tree parsing 2024-02-03 17:26:17 +08:00
Lightczx
446bdb2b49 syntax tree incompleted 2024-02-02 17:12:41 +08:00
Lightczx
20277b8b79 Add callconv on win32 apis 2024-02-02 10:38:40 +08:00
Lightczx
7baf125f88 Impl IReorderable 2024-02-02 10:03:46 +08:00
Lightczx
a4e782da78 refine #1316 2024-02-01 16:17:49 +08:00
Lightczx
d5551e5cdf fix #1316 2024-02-01 14:30:50 +08:00
Lightczx
f016a4a27f refine #1347 2024-02-01 09:42:55 +08:00
DismissedLight
8b931b6d89 Merge pull request #1349 from DGP-Studio/fix/1347
fix #1347
2024-02-01 09:23:40 +08:00
Lightczx
b942ceb914 codestyle 2024-02-01 09:22:52 +08:00
qhy040404
f7a49e52e0 fix #1347 2024-02-01 00:10:23 +08:00
qhy040404
d4bd610fe2 temporary fix qr login
let's play zzz :(
2024-01-31 23:00:07 +08:00
Lightczx
a3dcfd3804 metadata special name handling 2024-01-31 17:25:43 +08:00
Lightczx
592525d149 typo fix for #1344 2024-01-31 14:20:57 +08:00
Lightczx
83c4598df5 fix #1333 again 2024-01-31 11:37:48 +08:00
Masterain
31670953b0 Update issue_similarity.yml 2024-01-30 19:00:42 -08:00
DismissedLight
aa680388ad refine ui 2024-01-30 21:59:42 +08:00
Lightczx
ba4f59de30 update dynamic proxy injection 2024-01-30 17:31:23 +08:00
Lightczx
8780cf385e move class 2024-01-30 15:58:18 +08:00
Lightczx
431cdd1253 refine achievement page 2024-01-30 14:11:54 +08:00
Lightczx
9a8827fb40 fix typo 2024-01-30 11:54:09 +08:00
DismissedLight
d88a6ca301 Merge pull request #1327 from DGP-Studio/l10n_develop 2024-01-30 11:29:56 +08:00
DismissedLight
5d401794e5 Merge branch 'develop' into l10n_develop 2024-01-30 11:29:48 +08:00
Lightczx
26396443dc add 4.4 tower wave description 2024-01-30 11:18:37 +08:00
Masterain
ae2415dbca Create issue_similarity.yml 2024-01-29 18:17:37 -08:00
Lightczx
6b755d934d setting width trigger performance 2024-01-30 09:26:43 +08:00
DismissedLight
7d5b057269 Merge pull request #1337 from Scighost/develop 2024-01-30 09:21:17 +08:00
Lightczx
917c173eb2 code style 2024-01-30 09:18:11 +08:00
Scighost
28d702422e Responsive setting page 2024-01-29 20:21:30 +08:00
Lightczx
7612ab5da3 fix #1331 2024-01-29 16:37:49 +08:00
Lightczx
ab436ecb2f add package convert directory permission override 2024-01-29 16:26:50 +08:00
Lightczx
457e3ff4d5 fix #1333 2024-01-29 16:05:53 +08:00
Lightczx
224c4e52ea Activation using NamedPipe 2024-01-29 15:51:09 +08:00
DismissedLight
2a5c7b21fd Merge pull request #1335 from DGP-Studio/dependabot/nuget/src/Snap.Hutao/develop/packages-5aeabc7cca 2024-01-29 15:50:29 +08:00
dependabot[bot]
53f8291a66 Bump the packages group in /src/Snap.Hutao with 2 updates
Bumps the packages group in /src/Snap.Hutao with 2 updates: [MSTest.TestAdapter](https://github.com/microsoft/testfx) and [MSTest.TestFramework](https://github.com/microsoft/testfx).


Updates `MSTest.TestAdapter` from 3.1.1 to 3.2.0
- [Release notes](https://github.com/microsoft/testfx/releases)
- [Changelog](https://github.com/microsoft/testfx/blob/main/docs/Changelog.md)
- [Commits](https://github.com/microsoft/testfx/compare/v3.1.1...v.3.2.0)

Updates `MSTest.TestFramework` from 3.1.1 to 3.2.0
- [Release notes](https://github.com/microsoft/testfx/releases)
- [Changelog](https://github.com/microsoft/testfx/blob/main/docs/Changelog.md)
- [Commits](https://github.com/microsoft/testfx/compare/v3.1.1...v.3.2.0)

---
updated-dependencies:
- dependency-name: MSTest.TestAdapter
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: packages
- dependency-name: MSTest.TestFramework
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: packages
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-01-29 07:25:34 +00:00
DismissedLight
b621d5406a ui update 2024-01-28 21:13:50 +08:00
Masterain
12f4847aea New translations sh.resx (Portuguese) 2024-01-28 02:29:48 -08:00
Masterain
39a3d31f38 New translations sh.resx (Indonesian) 2024-01-28 02:29:47 -08:00
Masterain
70ac0b13a5 New translations sh.resx (English) 2024-01-28 02:29:46 -08:00
Masterain
a3520a4991 New translations sh.resx (Chinese Traditional) 2024-01-28 02:29:45 -08:00
Masterain
aed0284e4b New translations sh.resx (Russian) 2024-01-28 02:29:44 -08:00
Masterain
96ef07cbe5 New translations sh.resx (Korean) 2024-01-28 02:29:43 -08:00
Masterain
d1f37f37ac New translations sh.resx (Japanese) 2024-01-28 02:29:42 -08:00
DismissedLight
1fe09f3069 impl #1279 2024-01-28 17:44:15 +08:00
Masterain
5b109013a0 add workflows for stale issues (#1330) 2024-01-28 01:40:54 -08:00
DismissedLight
32d9355c3a refine http related code 2024-01-27 23:11:41 +08:00
Masterain
71f170d51e New translations sh.resx (Portuguese) 2024-01-27 01:57:10 -08:00
Masterain
60015b6354 New translations sh.resx (Indonesian) 2024-01-27 01:57:08 -08:00
Masterain
eecae3ea4f New translations sh.resx (English) 2024-01-27 01:57:07 -08:00
Masterain
1831166f1e New translations sh.resx (Chinese Traditional) 2024-01-27 01:57:06 -08:00
Masterain
a98915ea24 New translations sh.resx (Russian) 2024-01-27 01:57:05 -08:00
Masterain
0d46656f57 New translations sh.resx (Korean) 2024-01-27 01:57:04 -08:00
Masterain
c814a5c28f New translations sh.resx (Japanese) 2024-01-27 01:57:03 -08:00
DismissedLight
9c3d59cc6f fix loopback 2024-01-27 13:52:48 +08:00
DismissedLight
890cf3f3ea Merge pull request #1286 from DGP-Studio/feat/feedback_network 2024-01-27 13:02:28 +08:00
DismissedLight
196bbb54c3 code style 2024-01-27 13:01:56 +08:00
DismissedLight
0481b9e474 pt resx as analyzer files 2024-01-27 09:56:35 +08:00
qhy040404
c4f3eb68e8 code style 2024-01-27 09:19:18 +08:00
qhy040404
c2e9f3a926 verify set 2024-01-27 00:47:09 +08:00
qhy040404
fb1fe3e40f add loopback status 2024-01-27 00:38:41 +08:00
qhy040404
75ed512e4a add current proxy to feedback page 2024-01-26 22:08:38 +08:00
Masterain
dd4dd33d93 New translations sh.resx (Japanese) 2024-01-26 01:47:29 -08:00
Lightczx
1e216e9823 refine com import 2024-01-26 17:18:57 +08:00
Lightczx
f823cb5f1a ui rework 2024-01-26 15:38:00 +08:00
Lightczx
2c6d25f0a3 limit update thread count 2024-01-25 17:22:32 +08:00
Masterain
817f768263 New translations sh.resx (Portuguese) 2024-01-25 00:36:14 -08:00
Masterain
2998fbb167 New translations sh.resx (English) 2024-01-25 00:36:12 -08:00
Masterain
8f0f94054d New translations sh.resx (Russian) 2024-01-25 00:36:10 -08:00
Lightczx
17a5d4d3a2 impl #1320 2024-01-25 15:59:52 +08:00
Lightczx
a1c604e68a add required win32 apis 2024-01-25 15:50:46 +08:00
Lightczx
948ec9a822 code style 2024-01-25 12:55:26 +08:00
Lightczx
f83174d690 com interface impl IUnknown 2024-01-25 11:24:17 +08:00
Lightczx
d686debbfb manually pinvoke from win32metadata 2024-01-25 11:01:45 +08:00
qhy040404
279e107919 Update bug report template (#1317)
* 更新 CHS-bug-report.yml

* 更新 ENG-bug-report.yml
2024-01-19 01:38:17 -08:00
Lightczx
45248d75e1 pt-BR -> pt 2024-01-19 16:52:04 +08:00
Lightczx
22646cfab2 windows app sdk self contained 2024-01-19 16:25:57 +08:00
Lightczx
d0237a3c89 Add pt-BR locale 2024-01-19 15:41:11 +08:00
Tony
73c80fad10 Finish PT-BR translation (#1314) 2024-01-19 08:17:53 +08:00
Masterain
320bed9fcb New Crowdin updates (#1312)
* New translations sh.resx (Japanese)

* New translations sh.resx (Korean)

* New translations sh.resx (Russian)

* New translations sh.resx (Chinese Traditional)

* New translations sh.resx (English)

* New translations sh.resx (Indonesian)

* New translations sh.resx (Portuguese)
2024-01-17 15:10:26 -08:00
qhy040404
bb12aca3b4 Add PT translation (unfinished) (#1311)
Co-authored-by: t0piy <t.tony.br01@gmail.com>
Co-authored-by: Tony <66571593+t0piy@users.noreply.github.com>
2024-01-17 15:06:53 -08:00
DismissedLight
c7b5d98fb1 Merge pull request #1295 from DGP-Studio/fix/daily_note_task 2024-01-15 14:24:31 +08:00
qhy040404
7cc96f94f2 code style 2024-01-12 09:30:11 +08:00
qhy040404
b35355f9a3 improve daily note information 2024-01-11 20:39:02 +08:00
DismissedLight
94a5e71130 Update translations (#1294)
Co-authored-by: Masterain <i@irain.in>
2024-01-11 19:20:34 +08:00
Masterain
745815657d New Crowdin updates (#1293) 2024-01-11 19:19:43 +08:00
DismissedLight
07cdfcea28 Merge pull request #1291 from DGP-Studio/develop 2024-01-11 19:16:57 +08:00
DismissedLight
d93a9f41f3 bump version 2024-01-11 19:07:12 +08:00
qhy040404
910f099c6d reset debug console state (#1290)
Co-authored-by: DismissedLight <1686188646@qq.com>
2024-01-11 19:04:23 +08:00
Lightczx
e68449ec0c Update NativeMethods.txt 2024-01-10 17:06:23 +08:00
Lightczx
e484fbed21 update dependency 2024-01-10 10:42:35 +08:00
Masterain
88af6d28a9 New Crowdin updates (#1282)
* New translations sh.resx (Japanese)

* New translations sh.resx (Korean)

* New translations sh.resx (Russian)

* New translations sh.resx (Chinese Traditional)

* New translations sh.resx (English)

* New translations sh.resx (Indonesian)
2024-01-09 00:23:28 -08:00
Lightczx
3ab34f0992 Update HtmlDescriptionTextBlock.cs 2024-01-09 10:53:07 +08:00
Lightczx
5e875a7f18 add strings to resources 2 2024-01-09 10:38:33 +08:00
Lightczx
89d98748e8 add strings to resources 2024-01-09 10:10:31 +08:00
Masterain
d33cd894b9 New Crowdin updates (#1256)
* New translations sh.resx (Japanese)

* New translations sh.resx (Korean)

* New translations sh.resx (Russian)

* New translations sh.resx (Chinese Traditional)

* New translations sh.resx (English)

* New translations sh.resx (Indonesian)

* New translations sh.resx (Indonesian)

* New translations sh.resx (Russian)

* New translations sh.resx (Chinese Traditional)

* New translations sh.resx (Japanese)

* New translations sh.resx (Korean)

* New translations sh.resx (Russian)

* New translations sh.resx (Chinese Traditional)

* New translations sh.resx (English)

* New translations sh.resx (Indonesian)

* New translations sh.resx (Japanese)

* New translations sh.resx (Korean)

* New translations sh.resx (Russian)

* New translations sh.resx (Chinese Traditional)

* New translations sh.resx (English)

* New translations sh.resx (Indonesian)

* New translations sh.resx (Japanese)

* New translations sh.resx (Korean)

* New translations sh.resx (Russian)

* New translations sh.resx (Chinese Traditional)

* New translations sh.resx (English)

* New translations sh.resx (Indonesian)
2024-01-08 14:26:30 -08:00
DismissedLight
f0c19b419e Merge pull request #1276 from DGP-Studio/feat/dynamic_proxy 2024-01-08 22:20:30 +08:00
DismissedLight
f1d9787e45 fix method call 2024-01-08 22:18:07 +08:00
DismissedLight
5f9b4a7cb2 refactor RegistryWatcher 2024-01-08 21:55:59 +08:00
qhy040404
8710150897 use reflect to reduce code size 2024-01-08 20:19:05 +08:00
qhy040404
92c1b12764 dynamic proxy 2024-01-08 18:24:02 +08:00
Lightczx
d73bd557f3 remove settings appearance backdrop transparent 2024-01-08 16:52:37 +08:00
Lightczx
777d7d1056 remove winrt marshaller 2024-01-08 16:30:53 +08:00
Lightczx
1a944dae9c add transparent backdrop 2024-01-08 15:16:41 +08:00
Lightczx
a26c52ba97 typo 2024-01-08 11:43:45 +08:00
Lightczx
5fab03d57e Update FeedbackPage.xaml 2024-01-08 11:41:23 +08:00
Lightczx
e8a459cb41 refine #1039 2024-01-08 11:36:16 +08:00
DismissedLight
04df5a7bf1 impl #1039 2024-01-07 23:23:59 +08:00
Masterain
a93eb505d6 Update issue template 2024-01-06 22:56:17 -08:00
DismissedLight
1ebcc2fc89 add documentation client 2024-01-07 14:49:02 +08:00
DismissedLight
e9917e788d Merge pull request #1273 from DGP-Studio/feat/identify_monitor 2024-01-06 23:39:41 +08:00
DismissedLight
9665876d52 code style 2 2024-01-06 23:38:26 +08:00
DismissedLight
8921816873 code style 2024-01-06 22:57:25 +08:00
DismissedLight
2698761594 fix convert game path 2024-01-06 20:03:14 +08:00
qhy040404
3ae4210ca0 add i18n 2024-01-06 18:32:39 +08:00
qhy040404
2f5e0cbe39 impl #1261 2024-01-06 18:25:10 +08:00
DismissedLight
d3444a9435 typo 2024-01-06 15:22:40 +08:00
DismissedLight
8b6f95c3d9 add package convert check 2024-01-06 15:21:51 +08:00
DismissedLight
88b8335e5b Merge pull request #1271 from DGP-Studio/feat/refresh_data_size 2024-01-05 23:52:55 +08:00
qhy040404
061aba715b refresh data folder size after deleting server cache 2024-01-05 23:50:28 +08:00
DismissedLight
da80631b72 code style 2024-01-05 23:28:35 +08:00
DismissedLight
97acf872bc remove status when game exited 2024-01-05 23:28:05 +08:00
DismissedLight
addaf1a9e3 Merge pull request #1270 from DGP-Studio/feat/launch-pipeline 2024-01-05 22:46:00 +08:00
DismissedLight
76183901da clean up 2024-01-05 22:33:10 +08:00
Lightczx
87ee81e7fa add handlers 2024-01-05 17:29:30 +08:00
DismissedLight
f2f858de15 create infrastructure 2024-01-04 22:51:58 +08:00
DismissedLight
c434521004 Merge pull request #1265 from DGP-Studio/fix/schedule 2024-01-04 16:03:54 +08:00
Lightczx
27ed2cefc1 fix #1242 2024-01-04 16:01:52 +08:00
qhy040404
6dc1e664b0 add task register check and delete script if register is failed 2024-01-04 13:32:43 +08:00
DismissedLight
aa46b6531b Merge pull request #1264 from DGP-Studio/Masterain98-patch-1 2024-01-04 09:37:08 +08:00
Masterain
b36399f572 Update .gitlab-ci.yml 2024-01-03 17:36:45 -08:00
DismissedLight
51c3dde24b Merge pull request #1263 from DSakura207/main 2024-01-04 09:18:23 +08:00
DSakura207
2d497faaa5 Update Contributing.md 2024-01-03 18:35:47 -06:00
DSakura207
4783934b92 Add .vsconfig for installing workloads and extensions 2024-01-03 18:17:09 -06:00
DismissedLight
03d235876a Merge pull request #1260 from DGP-Studio/develop 2024-01-03 22:18:36 +08:00
DismissedLight
f49e9669af update version 2024-01-03 22:18:08 +08:00
DismissedLight
533c70caaa allow null package convert state 2024-01-03 21:53:13 +08:00
DismissedLight
dd59302bb3 fix bilibili server crash 2024-01-03 20:40:37 +08:00
1247 changed files with 52673 additions and 13445 deletions

View File

@@ -18,8 +18,8 @@ body:
options:
- label: 我已阅读 Snap Hutao 文档中的[常见问题](https://hut.ao/advanced/FAQ.html)和[常见程序异常](https://hut.ao/advanced/exceptions.html),我的问题没有在文档中得到解答
required: true
- label: 我知道文档站的导航栏中有**搜索功能**,且已经搜索过相关关键词
- label: 我知道[文档站](https://hut.ao/zh/menu.html)的导航栏中有**搜索功能**,且已经搜索过相关关键词
required: true
- label: 我的问题不是[已完成](https://github.com/DGP-Studio/Snap.Hutao/issues?q=is%3Aopen+is%3Aissue+label%3A%E5%B7%B2%E5%AE%8C%E6%88%90)的问题也不是一个别人已发布的**重复的**问题
@@ -29,18 +29,18 @@ body:
id: winver
attributes:
label: Windows 版本
description: |
description: |
`Win+R` 输入 `winver` 回车后在打开的窗口第二行可以找到
placeholder: 22000.556
validations:
required: true
- type: input
id: shver
attributes:
label: Snap Hutao 版本
description: 在应用标题,应用程序的设置界面中靠下的位置可以找到
placeholder: 1.4.15.0
description: 在应用标题,应用程序的反馈中心界面中可以找到
placeholder: 1.9.9.0
validations:
required: true
@@ -48,10 +48,10 @@ body:
id: deviceid
attributes:
label: 设备 ID
description: |
在胡桃工具箱的设置界面,你可以找到并复制你的设备 ID
description: |
在胡桃工具箱的反馈中心界面,你可以找到并复制你的设备 ID
如果你的问题涉及程序崩溃,请填写该项,这将有助于我们定位问题
如果你的程序已经无法启动,请下载并运行[工具](https://github.com/DGP-Automation/ISSUE_TEMPLATES/releases/download/diagnosis_tools/Snap.Hutao.DiagTools.exe),它将显示你的设备 ID
如果你的程序已经无法启动,请下载并运行[诊断工具](https://github.com/DGP-Automation/ISSUE_TEMPLATES/releases/download/diagnosis_tools/Snap.Hutao.Diagnostic.Tooling.exe),它将显示你的设备 ID
validations:
required: false
@@ -62,24 +62,23 @@ body:
description: 请设置一个你认为合适的分类,这将帮助我们快速定位问题
options:
- 安装和环境
- 成就管理
- 角色信息面板
- 游戏启动器
- 祈愿记录
- 成就管理
- 我的角色
- 实时便笺
- 养成计算
- 文件缓存
- 祈愿记录
- 玩家查询
- 胡桃数据库
- 用户界面
- 胡桃云
- 胡桃帐号
- 签到
- 深境螺旋/胡桃数据库
- Wiki
- 米游社账号面板
- 每日签到奖励
- 胡桃通行证/胡桃云
- 用户界面
- 文件缓存
- 公告
- 其它
validations:
required: true
required: true
- type: textarea
id: what-happened
@@ -87,7 +86,7 @@ body:
label: 发生了什么?
description: |
详细的描述问题发生前后的行为,以便我们解决问题。**如果你的问题涉及程序崩溃,你应当检查 Windows 事件查看器,并将相关的 `.Net 错误`详情附上**
如果你无法找到该日志,请下载并运行[工具](https://github.com/DGP-Automation/ISSUE_TEMPLATES/releases/download/diagnosis_tools/Snap.Hutao.DiagTools.exe),它将转储问题日志至工具运行目录中的 `Snap.Hutao Error Log.txt`
如果你无法找到该日志,请下载并运行[诊断工具](https://github.com/DGP-Automation/ISSUE_TEMPLATES/releases/download/diagnosis_tools/Snap.Hutao.DiagTools.exe),它将转储问题日志至工具运行目录中的 `Snap.Hutao Error Log.txt`
validations:
required: true
@@ -107,4 +106,3 @@ body:
options:
- label: 我认为上述的描述已经足以详细,以允许开发人员能复现该问题
required: true

View File

@@ -1,7 +1,7 @@
name: 功能请求
name: 功能请求
description: 通过这个议题来向开发团队分享你的想法
title: "[Feat]: 在这里填写一个合适的标题"
labels: ["功能", "needs-triage", "priority:none"]
labels: ["feature request", "needs-triage", "priority:none"]
assignees:
- Lightczx
body:
@@ -24,4 +24,4 @@ body:
label: 想要实现或优化的功能
description: 详细的描述一下你想要的功能,描述的越具体,采纳的可能性越高
validations:
required: true
required: true

View File

@@ -18,7 +18,7 @@ body:
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
@@ -29,18 +29,18 @@ body:
id: winver
attributes:
label: Windows Version
description: |
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
placeholder: e.g. 1.9.9.0
validations:
required: true
@@ -48,10 +48,10 @@ body:
id: deviceid
attributes:
label: Device ID
description: |
In Snap Hutao's settings page, you can find and copy your device ID
description: |
In Snap Hutao's Feedback Center, 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
If your program cannot startup, please download and run [this tool](https://github.com/DGP-Automation/ISSUE_TEMPLATES/releases/download/diagnosis_tools/Snap.Hutao.DiagTools.exe), it will shows your device ID.
If your program cannot startup, please download and run [Diagnostic Tooling](https://github.com/DGP-Automation/ISSUE_TEMPLATES/releases/download/diagnosis_tools/Snap.Hutao.Diagnostic.Tooling.exe), it will shows your device ID.
validations:
required: false
@@ -62,24 +62,23 @@ body:
description: Please select the most associated category of your issue
options:
- Installation and Environment
- Game Launcher
- Wish Export
- 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
- Spiral Abyss
- Wiki
- MiHoYo Account Panel
- Daily Checkin Reward
- Hutao Passport/Hutao Cloud
- User Interface
- File Cache
- Announcement
- Other
validations:
required: true
required: true
- type: textarea
id: what-happened
@@ -87,7 +86,7 @@ body:
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**If your program cannot startup, please download and run [this PowerShell script](https://github.com/DGP-Studio/ISSUE_TEMPLATES/releases/download/get_device_id/GetHutaoDeviceId.ps1), it will shows your device ID.
If you cannot find it, please download and run [this tool](https://github.com/DGP-Automation/ISSUE_TEMPLATES/releases/download/diagnosis_tools/Snap.Hutao.DiagTools.exe), it will dump the error log to `Snap.Hutao Error Log.txt` in the working directory of the tool.
If you cannot find it, please download and run [Diagnosis Tool](https://github.com/DGP-Automation/ISSUE_TEMPLATES/releases/download/diagnosis_tools/Snap.Hutao.DiagTools.exe), it will dump the error log to `Snap.Hutao Error Log.txt` in the working directory of the tool.
validations:
required: true
@@ -107,4 +106,3 @@ body:
options:
- label: I believe the description above is detail enough to allow developers to reproduce the issue
required: true

View File

@@ -1,7 +1,7 @@
name: Feature Request [English Form]
description: Tell us about your thought
title: "[Feat]: Place your title here"
labels: ["功能", "needs-triage", "priority:none"]
labels: ["feature request", "needs-triage", "priority:none"]
assignees:
- Lightczx
body:
@@ -22,6 +22,6 @@ body:
id: req
attributes:
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.
description: Descripbe the feaure in detail. The more detailed and convincing the desciprtion the more likyly feature will be accepted.
validations:
required: true
required: true

View File

@@ -13,4 +13,8 @@ updates:
groups:
packages:
patterns:
- "*"
- "*"
- package-ecosystem: "github-actions"
directory: "/.github/workflows" # GitHub Workflows
schedule:
interval: "weekly"

15
.github/pull_request_template.md vendored Normal file
View File

@@ -0,0 +1,15 @@
<!--- Hi, thanks for considering make a PR contribution to Snap Hutao, we appreciate your work. -->
<!--- Before you create this PR, please fill the following form and checklist -->
## Description
<!--- Describe your changes -->
## Related Issue
<!--- If there's an associated issue, please use [GitHub Keyword](https://docs.github.com/en/get-started/writing-on-github/working-with-advanced-formatting/using-keywords-in-issues-and-pull-requests) to link it -->
<!-- e.g. fix #999, resolve #999, close #999 -->
## Checklist
- [ ] The target PR branch is `develop` branch

View File

@@ -5,6 +5,18 @@ on:
branches:
- main
- develop
- 'feat/*'
paths-ignore:
- '.gitattributes'
- '.github/**'
- '.gitignore'
- '.gitmodules'
- '**.md'
- 'LICENSE'
- '**.yml'
pull_request:
branches:
- develop
paths-ignore:
- '.gitattributes'
- '.github/**'
@@ -13,16 +25,17 @@ on:
- '**.md'
- 'LICENSE'
- '**.yml'
- '**.resx'
jobs:
build:
runs-on: self-hosted
steps:
- name: Checkout
uses: actions/checkout@v4.1.1
uses: actions/checkout@v4
- name: Setup .NET
uses: actions/setup-dotnet@v4.0.0
uses: actions/setup-dotnet@v4
with:
dotnet-version: 8.0
@@ -32,22 +45,18 @@ jobs:
run: dotnet tool restore && dotnet cake
env:
VERSION_API_TOKEN: ${{ secrets.VERSION_API_TOKEN }}
- name: Sign Msix
shell: pwsh
run: |
[System.Convert]::FromBase64String("${{ secrets.CERTIFICATE }}") | Set-Content -AsByteStream temp.pfx
signtool.exe sign /debug /v /a /fd SHA256 /f temp.pfx /p ${{ secrets.PW }} ${{ github.workspace }}\src\output\Snap.Hutao.Alpha-${{ steps.cake.outputs.version }}.msix
CERTIFICATE: ${{ secrets.CERTIFICATE }}
PW: ${{ secrets.PW }}
- name: Upload signed msix
if: success()
uses: actions/upload-artifact@v3
if: success() && github.event_name != 'pull_request'
uses: actions/upload-artifact@v4
with:
name: Snap.Hutao.Alpha-${{ steps.cake.outputs.version }}
path: ${{ github.workspace }}/src/output/Snap.Hutao.Alpha-${{ steps.cake.outputs.version }}.msix
- name: Add summary
if: success()
if: success() && github.event_name != 'pull_request'
shell: pwsh
run: |
$summary = "
@@ -55,12 +64,55 @@ jobs:
> 该版本是由 CI 程序自动打包生成的 `Alpha` 测试版本,**仅供开发者测试使用**
> [!TIP]
> 普通用户请[点击这里](https://github.com/DGP-Studio/Snap.Hutao/releases/latest/)下载最新的稳定版本
> 普通用户请 [点击这里](https://github.com/DGP-Studio/Snap.Hutao/releases/latest/) 下载最新的稳定版本
> [!IMPORTANT]
> 请注意,从 Snap Hutao Alpha 2023.12.21.3 开始,我们将使用全新的 CI 证书,原有的 Snap.Hutao.CI.cer 将在几天后过期停止使用。
>
> 请安装 [DGP_Studio_CA.crt](https://github.com/DGP-Automation/Hutao-Auto-Release/releases/download/certificate-ca/DGP_Studio_CA.crt) 以安装测试版安装包
> 请先安装 **[DGP_Studio_CA.crt](https://github.com/DGP-Automation/Hutao-Auto-Release/releases/download/certificate-ca/DGP_Studio_CA.crt)** 到 **受信任的根证书颁发机构** 以安装测试版安装包
"
echo $summary >> $Env:GITHUB_STEP_SUMMARY
fallback_build:
runs-on: windows-latest
needs: build
if: failure()
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Setup .NET
uses: actions/setup-dotnet@v4
with:
dotnet-version: 8.0
- name: Cake
id: cake
shell: pwsh
run: dotnet tool restore && dotnet cake
env:
VERSION_API_TOKEN: ${{ secrets.VERSION_API_TOKEN }}
CERTIFICATE: ${{ secrets.CERTIFICATE }}
PW: ${{ secrets.PW }}
- name: Upload signed msix
if: success() && github.event_name != 'pull_request'
uses: actions/upload-artifact@v4
with:
name: Snap.Hutao.Alpha-${{ steps.cake.outputs.version }}
path: ${{ github.workspace }}/src/output/Snap.Hutao.Alpha-${{ steps.cake.outputs.version }}.msix
- name: Add summary
if: success() && github.event_name != 'pull_request'
shell: pwsh
run: |
$summary = "
> [!WARNING]
> 该版本是由 CI 程序自动打包生成的 `Alpha` 测试版本,**仅供开发者测试使用**
> [!TIP]
> 普通用户请 [点击这里](https://github.com/DGP-Studio/Snap.Hutao/releases/latest/) 下载最新的稳定版本
> [!IMPORTANT]
> 请先安装 **[DGP_Studio_CA.crt](https://github.com/DGP-Automation/Hutao-Auto-Release/releases/download/certificate-ca/DGP_Studio_CA.crt)** 到 **受信任的根证书颁发机构** 以安装测试版安装包
"
echo $summary >> $Env:GITHUB_STEP_SUMMARY

16
.github/workflows/close_stale.yml vendored Normal file
View File

@@ -0,0 +1,16 @@
name: 'Close stale issues and PRs'
on:
schedule:
- cron: '30 1 * * *'
jobs:
stale:
runs-on: ubuntu-latest
steps:
- uses: actions/stale@v9
with:
any-of-labels: 'needs-more-info,需要更多信息'
stale-issue-message: 'This issue is stale because it has been open 7 days with no activity. Remove stale label or comment or this will be closed in 3 days.'
days-before-stale: 7
days-before-close: 3
close-issue-reason: not_planned

20
.github/workflows/issue_similarity.yml vendored Normal file
View File

@@ -0,0 +1,20 @@
name: Issues Similarity Analysis
on:
issues:
types: [opened, edited]
jobs:
similarity-analysis:
runs-on: ubuntu-latest
steps:
- name: analysis
uses: actions-cool/issues-similarity-analysis@v1
with:
filter-threshold: 0.5
comment-title: '### Probable Similar Topics'
title-excludes: '[Publish]:,[Bug]:,[Feat]:,[Network]:,[ENG]'
comment-body: '${index}. ${similarity} #${number}'
show-footer: false
show-mentioned: true
since-days: 365

View File

@@ -0,0 +1,26 @@
name: 'Lock Threads'
on:
schedule:
- cron: '0 0 * * *'
workflow_dispatch:
permissions:
issues: write
pull-requests: write
discussions: write
concurrency:
group: lock-threads
jobs:
action:
runs-on: ubuntu-latest
steps:
- uses: dessant/lock-threads@v5
with:
issue-inactive-days: '30'
issue-comment: 'This issue has been automatically locked since there has not been any recent activity after it was closed. Please open a new issue for related topic.'
issue-lock-reason: 'resolved'
process-only: 'issues'
log-output: false

View File

@@ -61,6 +61,9 @@ release:
- name: "$THIS_SHA256SUMS_NAME"
url: "https://$CI_SERVER_SHELL_SSH_HOST/$CI_PROJECT_PATH/-/jobs/$THIS_JOB_ID/artifacts/raw/$THIS_SHA256SUMS_NAME?inline=false"
link_type: other
- name: "artifact_archive"
url: "https://$CI_SERVER_SHELL_SSH_HOST/$CI_PROJECT_PATH/-/jobs/$THIS_JOB_ID/artifacts/download?file_type=archive"
link_type: other
Refresh:
stage: refresh
@@ -71,3 +74,4 @@ Refresh:
script:
- apt-get install -y curl
- curl -X PATCH "$PURGE_URL"
- curl -X POST -o /dev/null "$UPLOAD_OSS_URL"

View File

@@ -4,13 +4,15 @@
### 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
1. Download and install [Visual Studio 2022 Community](https://visualstudio.microsoft.com/downloads/).
- No need to select workloads; Visual Studio will handle it automatically.
- Close Visual Studio Installer to ensure a smooth installation experience for workloads.
- If using Visual Studio 2022 17.9 preview, skip step 5, as automatic extension installation is supported in this version.
2. Use git to clone the project `https://github.com/DGP-Studio/Snap.Hutao.git` to your local device.
3. Switch to the`develop` branch using git.
4. Open the project solution with your Visual Studio. Visual Studio will prompt you to install the necessary workloads, closing and reopening automatically.
5. (For Visual Studio 2022 17.8) Install the [Single-project MSIX Packaging Tools for VS 2022](https://marketplace.visualstudio.com/items?itemName=ProjectReunion.MicrosoftSingleProjectMSIXPackagingToolsDev17) provided by Microsoft in Visual Studio marketplace.
6. Open the project solution with your Visual Studio, and you are ready to go.
### Start Pull Request

View File

@@ -1,41 +1,44 @@
![HutaoRepoBanner2-20231222](https://github.com/DGP-Studio/Snap.Hutao/assets/10614984/2d178de1-95bc-44a1-a95e-20c5f11a8628)
![HutaoRepoBanner3-en](https://github.com/DGP-Studio/Snap.Hutao/assets/10614984/7289da68-59cf-409b-bd85-4b5a01d0c091)
胡桃工具箱是一款以 MIT 协议开源的原神工具箱,专为现代化 Windows 平台设计,旨在改善桌面端玩家的游戏体验。通过将既有的官方资源与开发团队设计的全新 功能相结合,提供了一套完整且实用的工具集,且无需依赖任何移动设备。它不对游戏客户端进行任何破坏性修改以确保工具箱的安全性
胡桃工具箱是一款以 MIT 协议开源的原神工具箱,专为现代化 Windows 平台设计,旨在改善桌面端玩家的游戏体验。通过将既有的官方资源与开发团队设计的全新功能相结合,提供了一套完整且实用的工具集,且无需依赖任何移动设备。它不对游戏客户端进行任何破坏性修改以确保工具箱的安全性
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
## 安装 / Installation
![](https://ci.appveyor.com/api/projects/status/n4s40t9llru4si9y?svg=true) [![GitHub Release](https://img.shields.io/github/release/DGP-Studio/Snap.Hutao?style=flat)](https://github.com/DGP-Studio/Snap.Hutao/releases/latest) [![Github All Releases](https://img.shields.io/github/downloads/DGP-Studio/Snap.Hutao/total.svg?style=flat)]()
---
#### 使用安装器安装 / Install with Snap.Hutao.Depolyment Installer
你可以按照[快速开始](https://hut.ao/zh/quick-start.html)文档中提供的流程安装并设置 Snap Hutao
Snap.Hutao.Depolyment 是一个由 DGP-Studio 重新包装的 Windows 应用安装器,适用于缺少专业计算机知识的一般用户,可以在安装时同时解决缺少必要系统环境的问题。
You can follow the instructions in the [Quick Start](https://hut.ao/en/quick-start.html) document to install and set up Snap Hutao.
Snap.Hutao.Depolyment is a Windows application installer repackaged by DGP-Studio for the users who lacks computer knowledge and can solve the problem of missing necessary system environment at the same time as the installation.
## 本地化翻译 / Localization
[从 GitHub 发布页获取 / Download from GitHub release](https://github.com/DGP-Studio/Snap.Hutao.Deployment/releases/latest)
[![zh-TW translation](https://img.shields.io/badge/dynamic/json?color=blue&label=zh-TW&style=flat&logo=crowdin&query=%24.progress[?(@.data.languageId==%27zh-TW%27)].data.translationProgress&url=https%3A%2F%2Fbadges.awesome-crowdin.com%2Fstats-15670597-565845.json)](https://crowdin.com/project/snap-hutao)
[![en translation](https://img.shields.io/badge/dynamic/json?color=blue&label=en&style=flat&logo=crowdin&query=%24.progress[?(@.data.languageId==%27en%27)].data.translationProgress&url=https%3A%2F%2Fbadges.awesome-crowdin.com%2Fstats-15670597-565845.json)](https://crowdin.com/project/snap-hutao)
[![fr translation](https://img.shields.io/badge/dynamic/json?color=blue&label=fr&style=flat&logo=crowdin&query=%24.progress[?(@.data.languageId==%27fr%27)].data.translationProgress&url=https%3A%2F%2Fbadges.awesome-crowdin.com%2Fstats-15670597-565845.json)](https://crowdin.com/project/snap-hutao)
[![id translation](https://img.shields.io/badge/dynamic/json?color=blue&label=id&style=flat&logo=crowdin&query=%24.progress[?(@.data.languageId==%27id%27)].data.translationProgress&url=https%3A%2F%2Fbadges.awesome-crowdin.com%2Fstats-15670597-565845.json)](https://crowdin.com/project/snap-hutao)
[![ja translation](https://img.shields.io/badge/dynamic/json?color=blue&label=ja&style=flat&logo=crowdin&query=%24.progress[?(@.data.languageId==%27ja%27)].data.translationProgress&url=https%3A%2F%2Fbadges.awesome-crowdin.com%2Fstats-15670597-565845.json)](https://crowdin.com/project/snap-hutao)
[![ko translation](https://img.shields.io/badge/dynamic/json?color=blue&label=ko&style=flat&logo=crowdin&query=%24.progress[?(@.data.languageId==%27ko%27)].data.translationProgress&url=https%3A%2F%2Fbadges.awesome-crowdin.com%2Fstats-15670597-565845.json)](https://crowdin.com/project/snap-hutao)
[![pt-PT translation](https://img.shields.io/badge/dynamic/json?color=blue&label=pt-PT&style=flat&logo=crowdin&query=%24.progress[?(@.data.languageId==%27pt-PT%27)].data.translationProgress&url=https%3A%2F%2Fbadges.awesome-crowdin.com%2Fstats-15670597-565845.json)](https://crowdin.com/project/snap-hutao)
[![ru translation](https://img.shields.io/badge/dynamic/json?color=blue&label=ru&style=flat&logo=crowdin&query=%24.progress[?(@.data.languageId==%27ru%27)].data.translationProgress&url=https%3A%2F%2Fbadges.awesome-crowdin.com%2Fstats-15670597-565845.json)](https://crowdin.com/project/snap-hutao)
[![vi translation](https://img.shields.io/badge/dynamic/json?color=blue&label=vi&style=flat&logo=crowdin&query=%24.progress[?(@.data.languageId==%27vi%27)].data.translationProgress&url=https%3A%2F%2Fbadges.awesome-crowdin.com%2Fstats-15670597-565845.json)](https://crowdin.com/project/snap-hutao)
[从极狐Lab 发布页获取 / Download from Jihu Gitlab release](https://jihulab.com/DGP-Studio/Snap.Hutao.Deployment/-/releases)
Snap Hutao 使用 [Crowdin](https://translate.hut.ao/) 作为客户端文本翻译平台,在该平台上你可以为你熟悉的语言提交翻译文本。我们感谢每一个为 Snap Hutao 做出贡献的社区成员,并且欢迎更多的朋友能参与到这个项目中。
#### 使用 MSIX 包安装 / Install with MSIX Package
Snap Hutao uses [Crowdin](https://translate.hut.ao/) as a client text translation platform where you can submit translated text for languages you are familiar with. We are grateful to every community member who has contributed to Snap Hutao and welcome more friends to participate in this project.
直接使用 Snap Hutao MSIX 安装包,使用 Windows 内置的 App Installer 即可安装。如在安装中出现问题,请查阅我们的[常见问题](https://hut.ao/zh/advanced/FAQ.html)文档
## 社区 / Community
Install with Snap Hutao MSIX package, can be installed with Windows built-in App Installer. If you faced any issue, please check our [FAQ](https://hut.ao/en/advanced/FAQ.html) document.
[从 GitHub 发布页获取 / Download from GitHub release](https://github.com/DGP-Studio/Snap.Hutao/releases/latest)
[从极狐Lab 发布页获取 / Download from Jihu Gitlab release](https://jihulab.com/DGP-Studio/Snap.Hutao/-/releases)
[![Discord](https://img.shields.io/discord/952488447753465916?color=5865f2&label=%20Discord)](https://discord.gg/CcH5XtDtvR) [![QQ](https://img.shields.io/badge/QQ-EB1923?logo=tencent-qq&logoColor=white&label=567908135)](https://qm.qq.com/q/WJKykrY9W)
## 贡献 / Contribute
* [向我们提交 PR / Make Pull Requests](https://github.com/DGP-Studio/Snap.Hutao/pulls)
* [在 Crowdin 上进行本地化 / Translate Project on Crowdin](https://translate.hut.ao/)
* [为我们更新文档 / Enhance our Document ](https://github.com/DGP-Studio/Snap.Hutao.Docs)
* [向我们提交 PR / Make Pull Requests](https://hut.ao/development/contribute.html)
* [为我们更新文档 / Enhance our Document](https://github.com/DGP-Studio/Snap.Hutao.Docs)
## 特别感谢 / Special Thanks
@@ -44,23 +47,20 @@ Install with Snap Hutao MSIX package, can be installed with Windows built-in App
### 特定的原神项目 / Specific Genshin-related Projects
* [biuuu/genshin-wish-export](https://github.com/biuuu/genshin-wish-export)
* [xunkong/xunkong](https://github.com/xunkong/xunkong)
* [YuehaiTeam/cocogoat](https://github.com/YuehaiTeam/cocogoat)
* [Scighost/Starward](https://github.com/Scighost/Starward)
### 使用的技术栈 / Tech Stack
* [CommunityToolkit/dotnet](https://github.com/CommunityToolkit/dotnet)
* [CommunityToolkit/Labs-Windows](https://github.com/CommunityToolkit/Labs-Windows)
* [CommunityToolkit/Windows](https://github.com/CommunityToolkit/Windows)
* [dahall/taskscheduler](https://github.com/dahall/taskscheduler)
* [dotnet/efcore](https://github.com/dotnet/efcore)
* [dotnet/runtime](https://github.com/dotnet/runtime)
* [DotNetAnalyzers/StyleCopAnalyzers](https://github.com/DotNetAnalyzers/StyleCopAnalyzers)
* [microsoft/CsWin32](https://github.com/microsoft/CsWin32)
* [microsoft/vs-validation](https://github.com/microsoft/vs-validation)
* [microsoft/WindowsAppSDK](https://github.com/microsoft/WindowsAppSDK)
* [microsoft/microsoft-ui-xaml](https://github.com/microsoft/microsoft-ui-xaml)
* [quartznet/quartznet](https://github.com/quartznet/quartznet)
### 支撑项目 / Supporter Project
@@ -72,9 +72,9 @@ Install with Snap Hutao MSIX package, can be installed with Windows built-in App
Snap Hutao is currently using sponsored software from the following service providers.
| [![](https://www.netlify.com/v3/img/components/netlify-light.svg)](https://www.netlify.com/) | [![](https://support.crowdin.com/assets/logos/core-logo/svg/crowdin-core-logo-cDark.svg)](https://crowdin.com/) | [![](https://gitlab.cn/images/icons/logos/logo-121-75.svg)](https://gitlab.cn/) |
|:----------------------------------------------------------------------------------------------------:|:-----------------------------------------------------------------------------------------------------------------------:|:---------------------------------------------------------------------------------------:|
| [![](https://github.com/DGP-Studio/Snap.Hutao/assets/10614984/73ae8b90-f3c7-4033-b2b7-f4126331ce66)](https://about.signpath.io) | [![](https://github.com/DGP-Studio/Snap.Hutao/assets/10614984/49aed8ee-9f19-4a8a-998c-7b93ee286d65)](https://1password.com/) | [![](https://github.com/DGP-Studio/Snap.Hutao/assets/10614984/ad121220-d2d3-4f49-b215-b6d063dc229d)](https://about.signpath.io) |
|:-:|:-:|:-:|
|[![](https://github.com/DGP-Studio/Snap.Hutao/assets/10614984/73ae8b90-f3c7-4033-b2b7-f4126331ce66)](https://about.signpath.io)|[![](https://github.com/DGP-Studio/Snap.Hutao/assets/10614984/49aed8ee-9f19-4a8a-998c-7b93ee286d65)](https://1password.com/)|[![](https://github.com/DGP-Studio/Snap.Hutao/assets/10614984/ad121220-d2d3-4f49-b215-b6d063dc229d)](https://www.digitalocean.com)|
|[![jetbrains](https://github.com/DGP-Studio/Snap.Hutao/assets/36357191/4105772a-728a-4a84-9c6e-d713a5698a20)](https://www.jetbrains.com/opensource/)|||
- Netlify provides document and home page hosting service for Snap Hutao
@@ -88,6 +88,8 @@ Snap Hutao is currently using sponsored software from the following service prov
- DigitalOcean provides reliable cloud database for Snap Hutao database backup
- Jetbrains provides powerful IDE for Snap Hutao infrastructure services coding
## 开发 / Development
![Snap.Hutao](https://repobeats.axiom.co/api/embed/f029553fbe0c60689b1710476ec8512452163fc9.svg)

View File

@@ -4,8 +4,8 @@
| Version | Supported |
| ------- | ------------------ |
| >=1.6.0 | :white_check_mark: |
| <1.6.0 | :x: |
| >=1.9.0 | :white_check_mark: |
| <1.9.0 | :x: |
## Reporting a Vulnerability

View File

@@ -1,119 +0,0 @@
# CI process script for Snap.Hutao
# Usage:
# 1. Append the script in Pipelines
# 2. Upload the pfx and cer certificates to Pipelines Library secrets
# 3. Permit the pfx usage
# 4. Add a `pw` variable in the script variables, which is pfx password
# 5. Connect the GitHub in project settings
# 6. Run
trigger: none
pr: none
# trigger:
# branches:
# include:
# - main
# - develop
# paths:
# exclude:
# - README.md
# - azure-pipelines.yml
# - .github/ISSUE_TEMPLATE/*.yml
# - .github/workflows/*.yml
# - src/Snap.Hutao/Snap.Hutao/Resource/Localization/*.resx
# pr:
# branches:
# include:
# - main
# paths:
# exclude:
# - README.md
# - azure-pipelines.yml
# - .github/ISSUE_TEMPLATE/*.yml
# - .github/workflows/*.yml
# - src/Snap.Hutao/Snap.Hutao/Resource/Localization/*.resx
pool:
name: Default
demands: agent.name -equals Hutao-Server
variables:
DOTNET_SKIP_FIRST_TIME_EXPERIENCE: true
solution: '$(Build.SourcesDirectory)/src/Snap.Hutao/Snap.Hutao.sln'
project: $(Build.SourcesDirectory)/src/Snap.Hutao/Snap.Hutao/Snap.Hutao.csproj'
buildPlatform: 'x64'
buildConfiguration: 'Release'
steps:
- task: UseDotNet@2
displayName: Install dotNet
inputs:
packageType: 'sdk'
version: '8.x'
includePreviewVersions: true
- task: CmdLine@2
displayName: dotnet cake
inputs:
script: dotnet tool restore && dotnet cake
- task: MsixSigning@1
name: signMsix
displayName: Sign MSIX package
inputs:
package: '$(Build.ArtifactStagingDirectory)/Snap.Hutao.Alpha-$(version).msix'
certificate: 'DGP_Studio_CI.pfx'
passwordVariable: 'pw'
condition: succeeded()
- task: DownloadSecureFile@1
name: cerFile
displayName: Download Root CA
inputs:
secureFile: 'Snap.Hutao.CI.cer'
- task: PublishPipelineArtifact@1
inputs:
targetPath: '$(Build.ArtifactStagingDirectory)'
artifact: 'Snap.Hutao.Alpha-$(version).msix'
publishLocation: 'pipeline'
#- task: GitHubRelease@1
# inputs:
# gitHubConnection: 'github.com_Masterain'
# repositoryName: 'DGP-Automation/Hutao-Auto-Release'
# action: 'create'
# target: '$(Build.SourceVersion)'
# tagSource: 'userSpecifiedTag'
# tag: '$(version)'
# title: '$(version)'
# releaseNotesSource: 'inline'
# releaseNotesInline: |
# ## 普通用户请勿下载
# 该版本是由 CI 程序自动打包生成的 `Alpha` 测试版本,**仅供开发者测试使用**
#
# 普通用户请[点击这里](https://github.com/DGP-Studio/Snap.Hutao/releases/latest/)下载最新的稳定版本
#
# assets: |
# $(Build.ArtifactStagingDirectory)/*
# $(cerFile.secureFilePath)
# isPreRelease: true
# changeLogCompareToRelease: 'lastFullRelease'
# changeLogType: 'commitBased'
- task: rclone@1
displayName: Upload CI via Rclone
condition: and(succeeded(), eq(variables['Build.SourceBranch'], 'refs/heads/main'))
inputs:
arguments: 'copy $(Build.ArtifactStagingDirectory)/Snap.Hutao.Alpha-$(version).msix downloadDGPCN:/releases/Alpha/'
configPath: 'C:\agent\_work\_tasks\rclone.conf'
- task: rclone@1
displayName: Upload PR CI via Rclone
condition: and(succeeded(), eq(variables['Build.Reason'], 'PullRequest'))
inputs:
arguments: 'copy $(Build.ArtifactStagingDirectory)/Snap.Hutao.Alpha-$(version).msix downloadDGPCN:/releases/PR/'
configPath: 'C:\agent\_work\_tasks\rclone.conf'

View File

@@ -1,5 +1,5 @@
#tool "nuget:?package=nuget.commandline&version=6.5.0"
#addin nuget:?package=Cake.Http&version=3.0.2
#tool "nuget:?package=nuget.commandline&version=6.9.1"
#addin nuget:?package=Cake.Http&version=4.0.0
var target = Argument("target", "Build");
var configuration = Argument("configuration", "Release");
@@ -11,6 +11,18 @@ var version = "version";
var repoDir = "repoDir";
var outputPath = "outputPath";
var pfxPath = "pfxPath";
var pw = "pw";
// Extension
static ProcessArgumentBuilder AppendIf(this ProcessArgumentBuilder builder, string text, bool condition)
{
return condition ? builder.Append(text) : builder;
}
// Properties
string solution
{
get => System.IO.Path.Combine(repoDir, "src", "Snap.Hutao", "Snap.Hutao.sln");
@@ -28,43 +40,38 @@ string manifest
get => System.IO.Path.Combine(repoDir, "src", "Snap.Hutao", "Snap.Hutao", "Package.appxmanifest");
}
if (AzurePipelines.IsRunningOnAzurePipelines)
{
repoDir = AzurePipelines.Environment.Build.SourcesDirectory.FullPath;
outputPath = AzurePipelines.Environment.Build.ArtifactStagingDirectory.FullPath;
var versionAuth = HasEnvironmentVariable("VERSION_API_TOKEN") ? EnvironmentVariable("VERSION_API_TOKEN") : throw new Exception("Cannot find VERSION_API_TOKEN");
version = HttpGet(
"https://internal.snapgenshin.cn/BuildIntergration/RequestNewVersion",
new HttpSettings
{
Headers = new Dictionary<string, string>
{
{ "Authorization", versionAuth }
}
}
);
Information($"Version: {version}");
AzurePipelines.Commands.SetVariable("version", version);
}
else if (GitHubActions.IsRunningOnGitHubActions)
if (GitHubActions.IsRunningOnGitHubActions)
{
repoDir = GitHubActions.Environment.Workflow.Workspace.FullPath;
outputPath = System.IO.Path.Combine(repoDir, "src", "output");
var versionAuth = HasEnvironmentVariable("VERSION_API_TOKEN") ? EnvironmentVariable("VERSION_API_TOKEN") : throw new Exception("Cannot find VERSION_API_TOKEN");
version = HttpGet(
"https://internal.snapgenshin.cn/BuildIntergration/RequestNewVersion",
new HttpSettings
{
Headers = new Dictionary<string, string>
{
if (GitHubActions.Environment.PullRequest.IsPullRequest)
{
version = System.DateTime.Now.ToString("yyyy.M.d.0");
Information("Is Pull Request. Skip version.");
}
else
{
var versionAuth = HasEnvironmentVariable("VERSION_API_TOKEN") ? EnvironmentVariable("VERSION_API_TOKEN") : throw new Exception("Cannot find VERSION_API_TOKEN");
version = HttpGet(
"https://internal.snapgenshin.cn/BuildIntergration/RequestNewVersion",
new HttpSettings
{
Headers = new Dictionary<string, string>
{
{ "Authorization", versionAuth }
}
}
);
Information($"Version: {version}");
}
}
);
var certificateBase64 = HasEnvironmentVariable("CERTIFICATE") ? EnvironmentVariable("CERTIFICATE") : throw new Exception("Cannot find CERTIFICATE");
pw = HasEnvironmentVariable("PW") ? EnvironmentVariable("PW") : throw new Exception("Cannot find PW");
pfxPath = System.IO.Path.Combine(repoDir, "temp.pfx");
System.IO.File.WriteAllBytes(pfxPath, System.Convert.FromBase64String(certificateBase64));
Information($"Version: {version}");
}
GitHubActions.Commands.SetOutputParameter("version", version);
}
@@ -79,11 +86,29 @@ else if (AppVeyor.IsRunningOnAppVeyor)
})[..^2];
Information($"Version: {version}");
}
else // Local
{
repoDir = System.Environment.CurrentDirectory;
outputPath = System.IO.Path.Combine(repoDir, "src", "output");
version = System.DateTime.Now.ToString("yyyy.M.d.") + ((int)((System.DateTime.Now - System.DateTime.Today).TotalSeconds / 86400 * 65535)).ToString();
Information($"Version: {version}");
}
// Windows SDK
var registry = new WindowsRegistry();
var winsdkRegistry = registry.LocalMachine.OpenKey(@"SOFTWARE\Microsoft\Windows Kits\Installed Roots");
var winsdkVersion = winsdkRegistry.GetSubKeyNames().MaxBy(key => int.Parse(key.Split(".")[2]));
var winsdkPath = (string)winsdkRegistry.GetValue("KitsRoot10");
var winsdkBinPath = System.IO.Path.Combine(winsdkPath, "bin", winsdkVersion, "x64");
Information($"Windows SDK: {winsdkPath}");
Task("Build")
.IsDependentOn("Build binary package")
.IsDependentOn("Copy files")
.IsDependentOn("Build MSIX");
.IsDependentOn("Build MSIX")
.IsDependentOn("Sign");
Task("NuGet Restore")
.Does(() =>
@@ -106,7 +131,7 @@ Task("Generate AppxManifest")
var content = System.IO.File.ReadAllText(manifest);
if (AzurePipelines.IsRunningOnAzurePipelines || GitHubActions.IsRunningOnGitHubActions)
if (GitHubActions.IsRunningOnGitHubActions)
{
Information("Using CI configuraion");
content = content
@@ -122,6 +147,17 @@ Task("Generate AppxManifest")
Information("Using Release configuration");
content = System.Text.RegularExpressions.Regex.Replace(content, " Publisher=\"([^\"]*)\"", " Publisher=\"CN=SignPath Foundation, O=SignPath Foundation, L=Lewes, S=Delaware, C=US\"");
}
else
{
Information("Using Local configuration.");
content = content
.Replace("Snap Hutao", "Snap Hutao Local")
.Replace("胡桃", "胡桃 Local")
.Replace("DGP Studio", "DGP Studio CI");
content = System.Text.RegularExpressions.Regex.Replace(content, " Name=\"([^\"]*)\"", " Name=\"E8B6E2B3-D2A0-4435-A81D-2A16AAF405C7\"");
content = System.Text.RegularExpressions.Regex.Replace(content, " Publisher=\"([^\"]*)\"", " Publisher=\"E=admin@dgp-studio.cn, CN=DGP Studio CI, OU=CI, O=DGP-Studio, L=San Jose, S=CA, C=US\"");
content = System.Text.RegularExpressions.Regex.Replace(content, " Version=\"([0-9\\.]+)\"", $" Version=\"{version}\"");
}
System.IO.File.WriteAllText(manifest, content);
@@ -147,6 +183,7 @@ Task("Build binary package")
.Append("/p:AppxPackageSigningEnabled=false")
.Append("/p:AppxBundle=Never")
.Append("/p:AppxPackageOutput=" + outputPath)
.AppendIf("/p:AlphaConstants=IS_ALPHA_BUILD", !AppVeyor.IsRunningOnAppVeyor)
};
DotNetBuild(project, settings);
@@ -175,7 +212,7 @@ Task("Build MSIX")
.Does(() =>
{
var arguments = "arguments";
if (AzurePipelines.IsRunningOnAzurePipelines || GitHubActions.IsRunningOnGitHubActions)
if (GitHubActions.IsRunningOnGitHubActions)
{
arguments = "pack /d " + binPath + " /p " + System.IO.Path.Combine(outputPath, $"Snap.Hutao.Alpha-{version}.msix");
}
@@ -183,8 +220,15 @@ Task("Build MSIX")
{
arguments = "pack /d " + binPath + " /p " + System.IO.Path.Combine(outputPath, $"Snap.Hutao-{version}.msix");
}
else
{
arguments = "pack /d " + binPath + " /p " + System.IO.Path.Combine(outputPath, $"Snap.Hutao.Local-{version}.msix");
}
var makeappxPath = System.IO.Path.Combine(winsdkBinPath, "makeappx.exe");
var p = StartProcess(
"makeappx.exe",
makeappxPath,
new ProcessSettings
{
Arguments = arguments
@@ -192,7 +236,46 @@ Task("Build MSIX")
);
if (p != 0)
{
throw new InvalidOperationException("Build failed with exit code " + p);
throw new InvalidOperationException("Build MSIX failed with exit code " + p);
}
});
Task("Sign")
.IsDependentOn("Build MSIX")
.Does(() =>
{
if (AppVeyor.IsRunningOnAppVeyor)
{
Information("Move to SignPath. Skip signing.");
return;
}
else if (GitHubActions.IsRunningOnGitHubActions)
{
if (GitHubActions.Environment.PullRequest.IsPullRequest)
{
Information("Is Pull Request. Skip signing.");
return;
}
var signPath = System.IO.Path.Combine(winsdkBinPath, "signtool.exe");
var arguments = $"sign /debug /v /a /fd SHA256 /f {pfxPath} /p {pw} {System.IO.Path.Combine(outputPath, $"Snap.Hutao.Alpha-{version}.msix")}";
var p = StartProcess(
signPath,
new ProcessSettings
{
Arguments = arguments
}
);
if (p != 0)
{
throw new InvalidOperationException("Sign failed with exit code " + p);
}
}
else
{
Information("Local configuration. Skip signing.");
return;
}
});

BIN
res/Banner3-large-cn.psd Normal file

Binary file not shown.

BIN
res/Banner3-large.psd Normal file

Binary file not shown.

BIN
res/Store/chs/abyss.psd Normal file

Binary file not shown.

Binary file not shown.

Binary file not shown.

BIN
res/Store/chs/lancher.psd Normal file

Binary file not shown.

Binary file not shown.

BIN
res/Store/chs/wish.psd Normal file

Binary file not shown.

BIN
res/Store/en/abyss.psd Normal file

Binary file not shown.

Binary file not shown.

Binary file not shown.

BIN
res/Store/en/lancher.psd Normal file

Binary file not shown.

Binary file not shown.

BIN
res/Store/en/wish.psd Normal file

Binary file not shown.

View File

@@ -110,7 +110,6 @@ dotnet_diagnostic.SA1642.severity = none
dotnet_diagnostic.IDE0005.severity = warning
dotnet_diagnostic.IDE0060.severity = none
dotnet_diagnostic.IDE0290.severity = none
# SA1208: System using directives should be placed before other using directives
dotnet_diagnostic.SA1208.severity = none
@@ -124,9 +123,6 @@ dotnet_diagnostic.SA1623.severity = none
# SA1636: File header copyright text should match
dotnet_diagnostic.SA1636.severity = none
# SA1414: Tuple types in signatures should have element names
dotnet_diagnostic.SA1414.severity = none
# SA0001: XML comment analysis disabled
dotnet_diagnostic.SA0001.severity = none
csharp_style_prefer_parameter_null_checking = true:suggestion
@@ -324,8 +320,8 @@ dotnet_diagnostic.CA2227.severity = suggestion
# CA2251: 使用 “string.Equals”
dotnet_diagnostic.CA2251.severity = suggestion
csharp_style_prefer_primary_constructors = true:suggestion
dotnet_diagnostic.SA1010.severity = none
csharp_style_prefer_primary_constructors = false:none
[*.vb]
#### 命名样式 ####

11
src/Snap.Hutao/.vsconfig Normal file
View File

@@ -0,0 +1,11 @@
{
"version": "1.0",
"components": [
"Microsoft.VisualStudio.Workload.ManagedDesktop",
"Microsoft.VisualStudio.Workload.NativeDesktop",
"Microsoft.VisualStudio.Workload.Universal"
],
"extensions": [
"https://marketplace.visualstudio.com/items?itemName=ProjectReunion.MicrosoftSingleProjectMSIXPackagingToolsDev17"
]
}

View File

@@ -0,0 +1,28 @@
using System.Runtime.CompilerServices;
namespace Snap.Hutao.Test.BaseClassLibrary;
[TestClass]
public class UnsafeAccessorTest
{
[TestMethod]
public void UnsafeAccessorCanGetInterfaceProperty()
{
TestClass test = new();
int value = InternalGetInterfaceProperty(test);
Assert.AreEqual(3, value);
}
[UnsafeAccessor(UnsafeAccessorKind.Method, Name = "get_TestProperty")]
private static extern int InternalGetInterfaceProperty(ITestInterface instance);
internal interface ITestInterface
{
internal int TestProperty { get; }
}
internal sealed class TestClass : ITestInterface
{
public int TestProperty { get; } = 3;
}
}

View File

@@ -160,9 +160,39 @@ public sealed class GeniusInvokationDecoding
ushort[] testKnownResult =
[
060, 019, 001, 079, 120, 120, 129, 151, 151, 153, 153,
181, 184, 184, 185, 185, 194, 194, 200, 200, 201, 201,
217, 217, 219, 241, 241, 244, 244, 245, 245, 270, 270,
060,
019,
001,
079,
120,
120,
129,
151,
151,
153,
153,
181,
184,
184,
185,
185,
194,
194,
200,
200,
201,
201,
217,
217,
219,
241,
241,
244,
244,
245,
245,
270,
270,
];
CollectionAssert.AreEqual(resultArray, testKnownResult);

View File

@@ -6,14 +6,25 @@ namespace Snap.Hutao.Test.IncomingFeature;
public class SpiralAbyssScheduleIdTest
{
private static readonly TimeSpan Utc8 = new(8, 0, 0);
private static readonly DateTimeOffset AcrobaticsBattleIntroducedTime = new(2024, 7, 1, 4, 0, 0, Utc8);
[TestMethod]
public void Test()
{
Console.WriteLine($"当前第 {GetForDateTimeOffset(DateTimeOffset.Now)} 期");
DateTimeOffset dateTimeOffset = new(2020, 7, 1, 4, 0, 0, Utc8);
Console.WriteLine($"2020-07-01 04:00:00 为第 {GetForDateTimeOffset(dateTimeOffset)} 期");
// 2020-07-01 04:00:00 为第 1 期
// 2024-06-16 04:00:00 为第 96 期
// 2024-07-01 04:00:00 为第 97 期
// 2024-07-16 04:00:00 为第 98 期
// 2024-08-01 04:00:00 为第 99 期
Console.WriteLine($"2020-07-01 04:00:00 为第 {GetForDateTimeOffset(new(2020, 07, 01, 4, 0, 0, Utc8))} 期");
Console.WriteLine($"2024-06-16 04:00:00 为第 {GetForDateTimeOffset(new(2024, 06, 16, 4, 0, 0, Utc8))} 期");
Console.WriteLine($"2024-07-01 04:00:00 为第 {GetForDateTimeOffset(new(2024, 07, 01, 4, 0, 0, Utc8))} 期");
Console.WriteLine($"2024-07-16 04:00:00 为第 {GetForDateTimeOffset(new(2024, 07, 16, 4, 0, 0, Utc8))} 期");
Console.WriteLine($"2024-08-01 04:00:00 为第 {GetForDateTimeOffset(new(2024, 08, 01, 4, 0, 0, Utc8))} 期");
Console.WriteLine($"2024-08-16 04:00:00 为第 {GetForDateTimeOffset(new(2024, 08, 16, 4, 0, 0, Utc8))} 期");
Console.WriteLine($"2024-09-01 04:00:00 为第 {GetForDateTimeOffset(new(2024, 09, 01, 4, 0, 0, Utc8))} 期");
}
public static int GetForDateTimeOffset(DateTimeOffset dateTimeOffset)
@@ -38,6 +49,12 @@ public class SpiralAbyssScheduleIdTest
periodNum--;
}
if (dateTimeOffset >= AcrobaticsBattleIntroducedTime)
{
// 当超过 96 期时,每一个月一期
periodNum = (4 * 12 * 2) + ((periodNum - (4 * 12 * 2)) / 2);
}
return periodNum;
}
}

View File

@@ -1,5 +1,7 @@
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using System;
using System.Linq;
namespace Snap.Hutao.Test.PlatformExtensions;
@@ -10,7 +12,10 @@ public sealed class DependencyInjectionTest
.AddSingleton<IService, ServiceA>()
.AddSingleton<IService, ServiceB>()
.AddScoped<IScopedService, ServiceA>()
.AddKeyedTransient<IKeyedService, KeyedServiceA>("A")
.AddKeyedTransient<IKeyedService, KeyedServiceB>("B")
.AddTransient(typeof(IGenericService<>), typeof(GenericService<>))
.AddLogging(builder => builder.AddConsole())
.BuildServiceProvider();
[TestMethod]
@@ -41,6 +46,22 @@ public sealed class DependencyInjectionTest
}
}
[TestMethod]
public void LoggerWithInterfaceTypeCanBeResolved()
{
Assert.IsNotNull(services.GetService<ILogger<IScopedService>>());
Assert.IsNotNull(services.GetRequiredService<ILoggerFactory>().CreateLogger(nameof(IScopedService)));
}
[TestMethod]
public void KeyedServicesCanBeResolvedAsEnumerable()
{
Assert.IsNotNull(services.GetRequiredKeyedService<IKeyedService>("A"));
Assert.IsNotNull(services.GetRequiredKeyedService<IKeyedService>("B"));
Assert.AreEqual(0, services.GetServices<IKeyedService>().Count());
}
private interface IService
{
Guid Id { get; }
@@ -86,4 +107,14 @@ public sealed class DependencyInjectionTest
{
}
}
private interface IKeyedService;
private sealed class KeyedServiceA : IKeyedService
{
}
private sealed class KeyedServiceB : IKeyedService
{
}
}

View File

@@ -0,0 +1,45 @@
using System.Drawing;
using System.Net.Http;
using System.Net.Http.Json;
using System.Runtime.CompilerServices;
using System.Threading;
using System.Threading.Tasks;
namespace Snap.Hutao.Test.RuntimeBehavior;
[TestClass]
public sealed class HttpClientBehaviorTest
{
private const int MessageNotYetSent = 0;
[TestMethod]
public async Task RetrySendHttpRequestMessage()
{
using (HttpClient httpClient = new())
{
HttpRequestMessage requestMessage = new(HttpMethod.Post, "https://jsonplaceholder.typicode.com/posts");
JsonContent content = JsonContent.Create(new Point(12, 34));
requestMessage.Content = content;
using (requestMessage)
{
await httpClient.SendAsync(requestMessage).ConfigureAwait(false);
}
Interlocked.Exchange(ref GetPrivateSendStatus(requestMessage), MessageNotYetSent);
Volatile.Write(ref GetPrivateDisposed(content), false);
await httpClient.SendAsync(requestMessage).ConfigureAwait(false);
}
}
// private int _sendStatus
[UnsafeAccessor(UnsafeAccessorKind.Field, Name = "_sendStatus")]
private static extern ref int GetPrivateSendStatus(HttpRequestMessage message);
// private bool _disposed
[UnsafeAccessor(UnsafeAccessorKind.Field, Name = "_disposed")]
private static extern ref bool GetPrivateDisposed(HttpRequestMessage message);
// private bool _disposed
[UnsafeAccessor(UnsafeAccessorKind.Field, Name = "_disposed")]
private static extern ref bool GetPrivateDisposed(HttpContent content);
}

View File

@@ -1,4 +1,5 @@
using System.Collections.Generic;
using System;
using System.Collections.Generic;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
@@ -46,7 +47,14 @@ public sealed class UnsafeRuntimeBehaviorTest
Assert.AreEqual(1212, testStruct.Value4);
}
[TestMethod]
public unsafe void UnsafeUtf8StringReference()
{
void* ptr = Unsafe.AsPointer(ref MemoryMarshal.GetReference("test"u8));
GC.Collect(GC.MaxGeneration);
ReadOnlySpan<byte> bytes = MemoryMarshal.CreateReadOnlySpanFromNullTerminated((byte*)ptr);
Console.WriteLine(System.Text.Encoding.UTF8.GetString(bytes));
}
private readonly struct TestStruct
{

View File

@@ -1,4 +1,4 @@
<Project Sdk="Microsoft.NET.Sdk">
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFrameworks>net8.0</TargetFrameworks>
@@ -12,10 +12,11 @@
<ItemGroup>
<PackageReference Include="Microsoft.Extensions.DependencyInjection" Version="8.0.0" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.8.0" />
<PackageReference Include="MSTest.TestAdapter" Version="3.1.1" />
<PackageReference Include="MSTest.TestFramework" Version="3.1.1" />
<PackageReference Include="coverlet.collector" Version="6.0.0">
<PackageReference Include="Microsoft.Extensions.Logging.Console" Version="8.0.0" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.10.0" />
<PackageReference Include="MSTest.TestAdapter" Version="3.4.3" />
<PackageReference Include="MSTest.TestFramework" Version="3.4.3" />
<PackageReference Include="coverlet.collector" Version="6.0.2">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>

View File

@@ -1,11 +0,0 @@
{
"$schema": "https://raw.githubusercontent.com/microsoft/CsWin32/main/src/Microsoft.Windows.CsWin32/settings.schema.json",
"allowMarshaling": true,
"useSafeHandles": false,
"comInterop": {
"preserveSigMethods": [
"IFileOpenDialog.Show",
"IFileSaveDialog.Show"
]
}
}

View File

@@ -1,94 +0,0 @@
// COMCTL32
DefSubclassProc
RemoveWindowSubclass
SetWindowSubclass
// DWMAPI
DwmSetWindowAttribute
// GDI32
GetDeviceCaps
// KERNEL32
AllocConsole
CloseHandle
CreateEventW
CreateRemoteThread
FreeConsole
GetConsoleMode
GetModuleHandleW
GetProcAddress
GetStdHandle
K32EnumProcessModules
K32GetModuleBaseNameW
K32GetModuleInformation
ReadProcessMemory
SetConsoleMode
SetConsoleTitle
SetEvent
VirtualAlloc
VirtualAllocEx
VirtualFree
VirtualFreeEx
WaitForSingleObject
WriteProcessMemory
// OLE32
CoCreateInstance
CoWaitForMultipleObjects
// SHELL32
SHCreateItemFromParsingName
// USER32
AttachThreadInput
FindWindowExW
GetCursorPos
GetDC
GetDpiForWindow
GetForegroundWindow
GetWindowPlacement
GetWindowThreadProcessId
ReleaseDC
RegisterHotKey
SendInput
SetForegroundWindow
UnregisterHotKey
// COM
FileOpenDialog
FileSaveDialog
IFileOpenDialog
IFileSaveDialog
IPersistFile
IShellLinkDataList
IShellLinkW
ShellLink
SHELL_LINK_DATA_FLAGS
// WinRT
IMemoryBufferByteAccess
// Const value
E_FAIL
INFINITE
RPC_E_WRONG_THREAD
MAX_PATH
WM_GETMINMAXINFO
WM_HOTKEY
WM_NCRBUTTONDOWN
WM_NCRBUTTONUP
WM_NULL
// Type & Enum definition
HRESULT_FROM_WIN32
SLGP_FLAGS
// System.Threading
LPTHREAD_START_ROUTINE
// UI.WindowsAndMessaging
MINMAXINFO
// System.Com
CWMO_FLAGS

View File

@@ -1,17 +0,0 @@
using System;
using Windows.Win32.Foundation;
using Windows.Win32.System.Com;
namespace Windows.Win32;
internal static partial class PInvoke
{
/// <inheritdoc cref="CoCreateInstance(Guid*, object, CLSCTX, Guid*, out object)"/>
internal static unsafe HRESULT CoCreateInstance<TClass, TInterface>(object? pUnkOuter, CLSCTX dwClsContext, out TInterface ppv)
where TInterface : class
{
HRESULT hr = CoCreateInstance(typeof(TClass).GUID, pUnkOuter, dwClsContext, typeof(TInterface).GUID, out object o);
ppv = (TInterface)o;
return hr;
}
}

View File

@@ -1,25 +0,0 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net8.0-windows10.0.22621.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.49-beta">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
</ItemGroup>
</Project>

View File

@@ -1,24 +0,0 @@
// 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 = unchecked((uint)sizeof(WINDOWPLACEMENT)) };
}
}

View File

@@ -1,72 +0,0 @@
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

@@ -8,12 +8,11 @@ EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{9A95A964-04B1-477A-BDE7-505525B3CAD8}"
ProjectSection(SolutionItems) = preProject
.editorconfig = .editorconfig
.vsconfig = .vsconfig
EndProjectSection
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|Any CPU = Debug|Any CPU
@@ -66,22 +65,6 @@ 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

@@ -6,6 +6,8 @@
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<XamlControlsResources/>
<ResourceDictionary Source="ms-appx:///CommunityToolkit.WinUI.Controls.SettingsControls/SettingsCard/SettingsCard.xaml"/>
<ResourceDictionary Source="ms-appx:///CommunityToolkit.WinUI.Controls.TokenizingTextBox/TokenizingTextBox.xaml"/>
<ResourceDictionary Source="ms-appx:///Control/Loading.xaml"/>
<ResourceDictionary Source="ms-appx:///Control/Image/CachedImage.xaml"/>
<ResourceDictionary Source="ms-appx:///Control/Theme/Card.xaml"/>
@@ -22,16 +24,20 @@
<ResourceDictionary Source="ms-appx:///Control/Theme/PageOverride.xaml"/>
<ResourceDictionary Source="ms-appx:///Control/Theme/PivotOverride.xaml"/>
<ResourceDictionary Source="ms-appx:///Control/Theme/ScrollViewer.xaml"/>
<ResourceDictionary Source="ms-appx:///Control/Theme/SegmentedOverride.xaml"/>
<ResourceDictionary Source="ms-appx:///Control/Theme/SettingsStyle.xaml"/>
<ResourceDictionary Source="ms-appx:///Control/Theme/Thickness.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 Source="ms-appx:///View/Card/Primitive/CardProgressBar.xaml"/>
</ResourceDictionary.MergedDictionaries>
<Style
x:Key="LargeGridViewItemStyle"
BasedOn="{StaticResource DefaultGridViewItemStyle}"
TargetType="GridViewItem">
<Setter Property="HorizontalContentAlignment" Value="Stretch"/>
<Setter Property="Margin" Value="0,0,12,12"/>
</Style>
<Style

View File

@@ -3,10 +3,13 @@
using Microsoft.UI.Xaml;
using Microsoft.Windows.AppLifecycle;
using Microsoft.Windows.AppNotifications;
using Snap.Hutao.Core;
using Snap.Hutao.Core.ExceptionService;
using Snap.Hutao.Core.LifeCycle;
using Snap.Hutao.Core.Shell;
using Snap.Hutao.Core.LifeCycle.InterProcess;
using Snap.Hutao.Core.Logging;
using Snap.Hutao.Core.Windowing;
using System.Diagnostics;
namespace Snap.Hutao;
@@ -20,26 +23,24 @@ namespace Snap.Hutao;
[SuppressMessage("", "SH001")]
public sealed partial class App : Application
{
private const string ConsoleBanner = """
private const string ConsoleBanner = $"""
----------------------------------------------------------------
_____ _ _ _
/ ____| | | | | | |
| (___ _ __ __ _ _ __ | |__| | _ _ | |_ __ _ ___
\___ \ | '_ \ / _` || '_ \ | __ || | | || __|/ _` | / _ \
_____ _ _ _
/ ____| | | | | | |
| (___ _ __ __ _ _ __ | |__| | _ _ | |_ __ _ ___
\___ \ | '_ \ / _` || '_ \ | __ || | | || __|/ _` | / _ \
____) || | | || (_| || |_) |_ | | | || |_| || |_| (_| || (_) |
|_____/ |_| |_| \__,_|| .__/(_)|_| |_| \__,_| \__|\__,_| \___/
| |
|_|
|_____/ |_| |_| \__,_|| .__/(_)|_| |_| \__,_| \__|\__,_| \___/
| |
|_|
Snap.Hutao is a open source software developed by DGP Studio.
Copyright (C) 2022 - 2024 DGP Studio, All Rights Reserved.
----------------------------------------------------------------
""";
private const string AppInstanceKey = "main";
private readonly IServiceProvider serviceProvider;
private readonly IActivation activation;
private readonly IAppActivation activation;
private readonly ILogger<App> logger;
/// <summary>
@@ -50,43 +51,47 @@ public sealed partial class App : Application
{
// Load app resource
InitializeComponent();
activation = serviceProvider.GetRequiredService<IActivation>();
activation = serviceProvider.GetRequiredService<IAppActivation>();
logger = serviceProvider.GetRequiredService<ILogger<App>>();
serviceProvider.GetRequiredService<ExceptionRecorder>().Record(this);
this.serviceProvider = serviceProvider;
}
public new void Exit()
{
XamlLifetime.ApplicationExiting = true;
base.Exit();
}
/// <inheritdoc/>
protected override void OnLaunched(LaunchActivatedEventArgs args)
{
try
{
// Important: You must call AppNotificationManager::Default().Register
// before calling AppInstance.GetCurrent.GetActivatedEventArgs.
AppNotificationManager.Default.NotificationInvoked += activation.NotificationInvoked;
AppNotificationManager.Default.Register();
AppActivationArguments activatedEventArgs = AppInstance.GetCurrent().GetActivatedEventArgs();
AppInstance firstInstance = AppInstance.FindOrRegisterForKey(AppInstanceKey);
if (firstInstance.IsCurrent)
if (serviceProvider.GetRequiredService<PrivateNamedPipeClient>().TryRedirectActivationTo(activatedEventArgs))
{
logger.LogInformation(ConsoleBanner);
LogDiagnosticInformation();
// manually invoke
activation.NonRedirectToActivate(firstInstance, activatedEventArgs);
activation.InitializeWith(firstInstance);
serviceProvider.GetRequiredService<IJumpListInterop>().ConfigureAsync().SafeForget();
}
else
{
// Redirect the activation (and args) to the "main" instance, and exit.
firstInstance.RedirectActivationTo(activatedEventArgs);
Process.GetCurrentProcess().Kill();
logger.LogDebug("Application exiting on RedirectActivationTo");
Exit();
return;
}
logger.LogColorizedInformation((ConsoleBanner, ConsoleColor.DarkYellow));
LogDiagnosticInformation();
// Manually invoke
activation.Activate(HutaoActivationArguments.FromAppActivationArguments(activatedEventArgs));
activation.PostInitialization();
}
catch
catch (Exception ex)
{
// AppInstance.GetCurrent() calls failed
logger.LogError(ex, "Application failed in App.OnLaunched");
Process.GetCurrentProcess().Kill();
}
}
@@ -95,8 +100,8 @@ public sealed partial class App : Application
{
RuntimeOptions runtimeOptions = serviceProvider.GetRequiredService<RuntimeOptions>();
logger.LogInformation("FamilyName: {name}", runtimeOptions.FamilyName);
logger.LogInformation("Version: {version}", runtimeOptions.Version);
logger.LogInformation("LocalCache: {folder}", runtimeOptions.LocalCache);
logger.LogColorizedInformation(("FamilyName: {Name}", ConsoleColor.Blue), (runtimeOptions.FamilyName, ConsoleColor.Cyan));
logger.LogColorizedInformation(("Version: {Version}", ConsoleColor.Blue), (runtimeOptions.Version, ConsoleColor.Cyan));
logger.LogColorizedInformation(("LocalCache: {Path}", ConsoleColor.Blue), (runtimeOptions.LocalCache, ConsoleColor.Cyan));
}
}

View File

@@ -23,10 +23,12 @@ internal static class ControlAnimationConstants
/// <summary>
/// 图像淡入
/// </summary>
public static readonly TimeSpan ImageFadeIn = TimeSpan.FromSeconds(0.3);
public static readonly TimeSpan ImageScaleFadeIn = TimeSpan.FromSeconds(0.3);
/// <summary>
/// 图像淡出
/// </summary>
public static readonly TimeSpan ImageFadeOut = TimeSpan.FromSeconds(0.2);
public static readonly TimeSpan ImageScaleFadeOut = TimeSpan.FromSeconds(0.2);
public static readonly TimeSpan ImageOpacityFadeInOut = TimeSpan.FromSeconds(1);
}

View File

@@ -0,0 +1,102 @@
// Copyright (c) DGP Studio. All rights reserved.
// Licensed under the MIT license.
using CommunityToolkit.WinUI;
using CommunityToolkit.WinUI.Controls;
using Microsoft.UI.Xaml;
using Microsoft.UI.Xaml.Controls;
using Microsoft.UI.Xaml.Controls.Primitives;
using Snap.Hutao.Control.Extension;
using System.Collections;
namespace Snap.Hutao.Control.AutoSuggestBox;
[DependencyProperty("FilterCommand", typeof(ICommand))]
[DependencyProperty("FilterCommandParameter", typeof(object))]
[DependencyProperty("AvailableTokens", typeof(IReadOnlyDictionary<string, SearchToken>))]
internal sealed partial class AutoSuggestTokenBox : TokenizingTextBox
{
public AutoSuggestTokenBox()
{
DefaultStyleKey = typeof(TokenizingTextBox);
TextChanged += OnFilterSuggestionRequested;
QuerySubmitted += OnQuerySubmitted;
TokenItemAdding += OnTokenItemAdding;
TokenItemAdded += OnTokenItemCollectionChanged;
TokenItemRemoved += OnTokenItemCollectionChanged;
Loaded += OnLoaded;
}
private void OnLoaded(object sender, RoutedEventArgs e)
{
if (this.FindDescendant("SuggestionsPopup") is Popup { Child: Border { Child: ListView listView } border })
{
IAppResourceProvider appResourceProvider = this.ServiceProvider().GetRequiredService<IAppResourceProvider>();
listView.Background = null;
listView.Margin = appResourceProvider.GetResource<Thickness>("AutoSuggestListPadding");
border.Background = appResourceProvider.GetResource<Microsoft.UI.Xaml.Media.Brush>("AutoSuggestBoxSuggestionsListBackground");
CornerRadius overlayCornerRadius = appResourceProvider.GetResource<CornerRadius>("OverlayCornerRadius");
CornerRadiusFilterConverter cornerRadiusFilterConverter = new() { Filter = CornerRadiusFilterKind.Bottom };
border.CornerRadius = (CornerRadius)cornerRadiusFilterConverter.Convert(overlayCornerRadius, typeof(CornerRadius), default, default);
}
}
private void OnFilterSuggestionRequested(Microsoft.UI.Xaml.Controls.AutoSuggestBox sender, AutoSuggestBoxTextChangedEventArgs args)
{
if (string.IsNullOrWhiteSpace(Text))
{
sender.ItemsSource = AvailableTokens
.OrderBy(kvp => kvp.Value.Kind)
.Select(kvp => kvp.Value);
}
if (args.Reason == AutoSuggestionBoxTextChangeReason.UserInput)
{
sender.ItemsSource = AvailableTokens
.Where(kvp => kvp.Value.Value.Contains(Text, StringComparison.OrdinalIgnoreCase))
.OrderBy(kvp => kvp.Value.Kind)
.ThenBy(kvp => kvp.Value.Order)
.Select(kvp => kvp.Value)
.DefaultIfEmpty(SearchToken.NotFound);
}
}
private void OnQuerySubmitted(Microsoft.UI.Xaml.Controls.AutoSuggestBox sender, AutoSuggestBoxQuerySubmittedEventArgs args)
{
if (args.ChosenSuggestion is not null)
{
return;
}
CommandInvocation.TryExecute(FilterCommand, FilterCommandParameter);
}
private void OnTokenItemAdding(TokenizingTextBox sender, TokenItemAddingEventArgs args)
{
if (string.IsNullOrWhiteSpace(args.TokenText))
{
return;
}
if (AvailableTokens.GetValueOrDefault(args.TokenText) is { } token)
{
args.Item = token;
}
else
{
args.Cancel = true;
}
}
private void OnTokenItemCollectionChanged(TokenizingTextBox sender, object args)
{
if (args is SearchToken { Kind: SearchTokenKind.None } token)
{
((IList)sender.ItemsSource).Remove(token);
}
FilterCommand.TryExecute(FilterCommandParameter);
}
}

View File

@@ -0,0 +1,38 @@
// Copyright (c) DGP Studio. All rights reserved.
// Licensed under the MIT license.
using Windows.UI;
namespace Snap.Hutao.Control.AutoSuggestBox;
internal sealed class SearchToken
{
public static readonly SearchToken NotFound = new(SearchTokenKind.None, SH.ControlAutoSuggestBoxNotFoundValue, 0);
public SearchToken(SearchTokenKind kind, string value, int order, Uri? iconUri = null, Uri? sideIconUri = null, Color? quality = null)
{
Value = value;
Kind = kind;
IconUri = iconUri;
SideIconUri = sideIconUri;
Quality = quality;
Order = order;
}
public SearchTokenKind Kind { get; }
public string Value { get; set; } = default!;
public Uri? IconUri { get; }
public Uri? SideIconUri { get; }
public Color? Quality { get; }
public int Order { get; }
public override string ToString()
{
return Value;
}
}

View File

@@ -0,0 +1,17 @@
// Copyright (c) DGP Studio. All rights reserved.
// Licensed under the MIT license.
namespace Snap.Hutao.Control.AutoSuggestBox;
internal enum SearchTokenKind
{
None,
ItemQuality,
WeaponType,
FightProperty,
ElementName,
AssociationType,
BodyType,
Avatar,
Weapon,
}

View File

@@ -0,0 +1,51 @@
// Copyright (c) DGP Studio. All rights reserved.
// Licensed under the MIT license.
using CommunityToolkit.WinUI.Behaviors;
using Microsoft.UI.Xaml;
using Microsoft.UI.Xaml.Controls;
namespace Snap.Hutao.Control.Behavior;
[SuppressMessage("", "CA1001")]
[DependencyProperty("MilliSecondsDelay", typeof(int))]
internal sealed partial class InfoBarDelayCloseBehavior : BehaviorBase<InfoBar>
{
private readonly CancellationTokenSource closeTokenSource = new();
protected override void OnAssociatedObjectLoaded()
{
AssociatedObject.Closed += OnInfoBarClosed;
if (MilliSecondsDelay > 0)
{
DelayCoreAsync().SafeForget();
}
}
private async ValueTask DelayCoreAsync()
{
try
{
await Task.Delay(MilliSecondsDelay, closeTokenSource.Token).ConfigureAwait(true);
}
catch
{
return;
}
if (AssociatedObject is not null)
{
AssociatedObject.IsOpen = false;
}
}
private void OnInfoBarClosed(InfoBar infoBar, InfoBarClosedEventArgs args)
{
if (args.Reason is InfoBarCloseReason.CloseButton)
{
closeTokenSource.Cancel();
}
AssociatedObject.Closed -= OnInfoBarClosed;
}
}

View File

@@ -3,6 +3,7 @@
using CommunityToolkit.WinUI.Behaviors;
using Microsoft.UI.Xaml;
using Snap.Hutao.Control.Extension;
namespace Snap.Hutao.Control.Behavior;
@@ -45,10 +46,6 @@ internal sealed partial class InvokeCommandOnLoadedBehavior : BehaviorBase<UIEle
return;
}
if (Command is not null && Command.CanExecute(CommandParameter))
{
Command.Execute(CommandParameter);
executed = true;
}
executed = Command.TryExecute(CommandParameter);
}
}

View File

@@ -0,0 +1,88 @@
// Copyright (c) DGP Studio. All rights reserved.
// Licensed under the MIT license.
using CommunityToolkit.WinUI.Behaviors;
using Microsoft.UI.Xaml;
using Snap.Hutao.Control.Extension;
namespace Snap.Hutao.Control.Behavior;
[DependencyProperty("Period", typeof(TimeSpan))]
[DependencyProperty("Command", typeof(ICommand))]
[DependencyProperty("CommandParameter", typeof(object))]
internal sealed partial class PeriodicInvokeCommandOrOnActualThemeChangedBehavior : BehaviorBase<FrameworkElement>, IDisposable
{
private TaskCompletionSource acutalThemeChangedTaskCompletionSource = new();
private CancellationTokenSource periodicTimerCancellationTokenSource = new();
public void Dispose()
{
periodicTimerCancellationTokenSource.Dispose();
}
protected override bool Initialize()
{
AssociatedObject.ActualThemeChanged += OnActualThemeChanged;
return true;
}
protected override void OnAssociatedObjectLoaded()
{
RunCoreAsync().SafeForget();
}
protected override bool Uninitialize()
{
periodicTimerCancellationTokenSource.Cancel();
AssociatedObject.ActualThemeChanged -= OnActualThemeChanged;
return true;
}
private void OnActualThemeChanged(FrameworkElement sender, object args)
{
acutalThemeChangedTaskCompletionSource.TrySetResult();
periodicTimerCancellationTokenSource.Cancel();
}
private void TryExecuteCommand()
{
if (AssociatedObject is null)
{
return;
}
Command.TryExecute(CommandParameter);
}
private async ValueTask RunCoreAsync()
{
using (PeriodicTimer timer = new(Period))
{
do
{
if (!IsAttached)
{
break;
}
ITaskContext taskContext = Ioc.Default.GetRequiredService<ITaskContext>();
await taskContext.SwitchToMainThreadAsync();
TryExecuteCommand();
await taskContext.SwitchToBackgroundAsync();
try
{
Task nextTickTask = timer.WaitForNextTickAsync(periodicTimerCancellationTokenSource.Token).AsTask();
await Task.WhenAny(nextTickTask, acutalThemeChangedTaskCompletionSource.Task).ConfigureAwait(false);
}
catch (OperationCanceledException)
{
}
acutalThemeChangedTaskCompletionSource = new();
periodicTimerCancellationTokenSource = new();
}
while (true);
}
}
}

View File

@@ -13,6 +13,4 @@ namespace Snap.Hutao.Control;
/// </summary>
[HighQuality]
[DependencyProperty("DataContext", typeof(object))]
internal sealed partial class BindingProxy : DependencyObject
{
}
internal sealed partial class BindingProxy : DependencyObject;

View File

@@ -0,0 +1,8 @@
// Copyright (c) DGP Studio. All rights reserved.
// Licensed under the MIT license.
namespace Snap.Hutao.Control.Brush;
internal sealed class ColorSegmentCollection : List<IColorSegment>
{
}

View File

@@ -9,5 +9,5 @@ internal interface IColorSegment
{
Color Color { get; }
double Value { get; }
double Value { get; set; }
}

View File

@@ -9,36 +9,48 @@ using System.Runtime.InteropServices;
namespace Snap.Hutao.Control.Brush;
[DependencyProperty("Source", typeof(List<IColorSegment>), default!, nameof(OnSourceChanged))]
[DependencyProperty("Source", typeof(ColorSegmentCollection), default!, nameof(OnSourceChanged))]
internal sealed partial class SegmentedBar : ContentControl
{
private readonly LinearGradientBrush brush = new() { StartPoint = new(0, 0), EndPoint = new(1, 0), };
public SegmentedBar()
{
HorizontalContentAlignment = HorizontalAlignment.Stretch;
VerticalContentAlignment = VerticalAlignment.Stretch;
Content = new Rectangle()
{
Fill = brush,
HorizontalAlignment = HorizontalAlignment.Stretch,
VerticalAlignment = VerticalAlignment.Stretch,
};
}
private static void OnSourceChanged(DependencyObject obj, DependencyPropertyChangedEventArgs args)
{
SegmentedBar segmentedBar = (SegmentedBar)obj;
UpdateLinearGradientBrush((SegmentedBar)obj);
}
private static void UpdateLinearGradientBrush(SegmentedBar segmentedBar)
{
GradientStopCollection collection = segmentedBar.brush.GradientStops;
collection.Clear();
if (args.NewValue as List<IColorSegment> is [_, ..] list)
ColorSegmentCollection segmentCollection = segmentedBar.Source;
double total = segmentCollection.Sum(seg => seg.Value);
if (total is 0D)
{
double total = list.Sum(seg => seg.Value);
double offset = 0;
foreach (ref readonly IColorSegment segment in CollectionsMarshal.AsSpan(list))
{
collection.Add(new() { Color = segment.Color, Offset = offset, });
offset += segment.Value / total;
collection.Add(new() { Color = segment.Color, Offset = offset, });
}
return;
}
double offset = 0;
foreach (ref readonly IColorSegment segment in CollectionsMarshal.AsSpan(segmentCollection))
{
collection.Add(new() { Color = segment.Color, Offset = offset, });
offset += segment.Value / total;
collection.Add(new() { Color = segment.Color, Offset = offset, });
}
}
}

View File

@@ -0,0 +1,10 @@
// Copyright (c) DGP Studio. All rights reserved.
// Licensed under the MIT license.
namespace Snap.Hutao.Control.Builder.ButtonBase;
internal class ButtonBaseBuilder<TButton> : IButtonBaseBuilder<TButton>
where TButton : Microsoft.UI.Xaml.Controls.Primitives.ButtonBase, new()
{
public TButton Button { get; } = new();
}

View File

@@ -0,0 +1,25 @@
// Copyright (c) DGP Studio. All rights reserved.
// Licensed under the MIT license.
using Snap.Hutao.Core.Abstraction.Extension;
namespace Snap.Hutao.Control.Builder.ButtonBase;
internal static class ButtonBaseBuilderExtension
{
public static TBuilder SetContent<TBuilder, TButton>(this TBuilder builder, object? content)
where TBuilder : IButtonBaseBuilder<TButton>
where TButton : Microsoft.UI.Xaml.Controls.Primitives.ButtonBase
{
builder.Configure(builder => builder.Button.Content = content);
return builder;
}
public static TBuilder SetCommand<TBuilder, TButton>(this TBuilder builder, ICommand command)
where TBuilder : IButtonBaseBuilder<TButton>
where TButton : Microsoft.UI.Xaml.Controls.Primitives.ButtonBase
{
builder.Configure(builder => builder.Button.Command = command);
return builder;
}
}

View File

@@ -0,0 +1,8 @@
// Copyright (c) DGP Studio. All rights reserved.
// Licensed under the MIT license.
using Microsoft.UI.Xaml.Controls;
namespace Snap.Hutao.Control.Builder.ButtonBase;
internal sealed class ButtonBuilder : ButtonBaseBuilder<Button>;

View File

@@ -0,0 +1,19 @@
// Copyright (c) DGP Studio. All rights reserved.
// Licensed under the MIT license.
using Microsoft.UI.Xaml.Controls;
namespace Snap.Hutao.Control.Builder.ButtonBase;
internal static class ButtonBuilderExtension
{
public static ButtonBuilder SetContent(this ButtonBuilder builder, object? content)
{
return builder.SetContent<ButtonBuilder, Button>(content);
}
public static ButtonBuilder SetCommand(this ButtonBuilder builder, ICommand command)
{
return builder.SetCommand<ButtonBuilder, Button>(command);
}
}

View File

@@ -0,0 +1,12 @@
// Copyright (c) DGP Studio. All rights reserved.
// Licensed under the MIT license.
using Snap.Hutao.Core.Abstraction;
namespace Snap.Hutao.Control.Builder.ButtonBase;
internal interface IButtonBaseBuilder<TButton> : IBuilder
where TButton : Microsoft.UI.Xaml.Controls.Primitives.ButtonBase
{
TButton Button { get; }
}

View File

@@ -0,0 +1,763 @@
// Copyright (c) DGP Studio. All rights reserved.
// Licensed under the MIT license.
using CommunityToolkit.WinUI.Collections;
using CommunityToolkit.WinUI.Helpers;
using Microsoft.UI.Xaml.Data;
using System.Collections;
using System.Collections.ObjectModel;
using System.Collections.Specialized;
using System.Reflection;
using System.Runtime.CompilerServices;
using Windows.Foundation;
using Windows.Foundation.Collections;
using NotifyCollectionChangedAction = System.Collections.Specialized.NotifyCollectionChangedAction;
namespace Snap.Hutao.Control.Collection.AdvancedCollectionView;
internal sealed class AdvancedCollectionView<T> : IAdvancedCollectionView<T>, INotifyPropertyChanged, ISupportIncrementalLoading, IComparer<object>
where T : class
{
private readonly List<T> view;
private readonly ObservableCollection<SortDescription> sortDescriptions;
private readonly Dictionary<string, PropertyInfo?> sortProperties;
private readonly bool liveShapingEnabled;
private readonly HashSet<string?> observedFilterProperties = [];
private IList<T> source;
private Predicate<T>? filter;
private int deferCounter;
private WeakEventListener<AdvancedCollectionView<T>, object?, NotifyCollectionChangedEventArgs>? sourceWeakEventListener;
public AdvancedCollectionView()
: this([])
{
}
public AdvancedCollectionView(IList<T> source, bool isLiveShaping = false)
{
liveShapingEnabled = isLiveShaping;
view = [];
sortDescriptions = [];
sortDescriptions.CollectionChanged += SortDescriptionsCollectionChanged;
sortProperties = [];
Source = source;
}
public event EventHandler<object>? CurrentChanged;
public event CurrentChangingEventHandler? CurrentChanging;
public event PropertyChangedEventHandler? PropertyChanged;
public event VectorChangedEventHandler<object>? VectorChanged;
public IList<T> Source
{
get => source;
[MemberNotNull(nameof(source))]
set
{
if (ReferenceEquals(source, value))
{
return;
}
if (source is not null)
{
DetachPropertyChangedHandler(source);
}
source = value;
AttachPropertyChangedHandler(source);
sourceWeakEventListener?.Detach();
if (source is INotifyCollectionChanged sourceNotifyCollectionChanged)
{
sourceWeakEventListener = new WeakEventListener<AdvancedCollectionView<T>, object?, NotifyCollectionChangedEventArgs>(this)
{
// Call the actual collection changed event
OnEventAction = (source, changed, arg3) => SourceNotifyCollectionChangedCollectionChanged(source, arg3),
// The source doesn't exist anymore
OnDetachAction = (listener) =>
{
ArgumentNullException.ThrowIfNull(sourceWeakEventListener);
sourceNotifyCollectionChanged.CollectionChanged -= sourceWeakEventListener.OnEvent;
},
};
sourceNotifyCollectionChanged.CollectionChanged += sourceWeakEventListener.OnEvent;
}
HandleSourceChanged();
OnPropertyChanged();
}
}
public int Count
{
get => view.Count;
}
public bool IsReadOnly
{
get => source is null || source.IsReadOnly;
}
public IObservableVector<object> CollectionGroups
{
get => default!;
}
public T? CurrentItem
{
get => CurrentPosition > -1 && CurrentPosition < view.Count ? view[CurrentPosition] : default;
set => MoveCurrentTo(value);
}
public int CurrentPosition { get; private set; }
public bool HasMoreItems
{
get => source is ISupportIncrementalLoading { HasMoreItems: true };
}
public bool IsCurrentAfterLast
{
get => CurrentPosition >= view.Count;
}
public bool IsCurrentBeforeFirst
{
get => CurrentPosition < 0;
}
public bool CanFilter
{
get => true;
}
public Predicate<T>? Filter
{
get => filter;
set
{
if (filter == value)
{
return;
}
filter = value;
HandleFilterChanged();
}
}
public bool CanSort
{
get => true;
}
public IList<SortDescription> SortDescriptions
{
get => sortDescriptions;
}
public IEnumerable<T> SourceCollection
{
get => source;
}
public IReadOnlyList<T> View
{
get => view;
}
public T this[int index]
{
get => view[index];
set => view[index] = value;
}
public void Refresh()
{
HandleSourceChanged();
}
public void RefreshFilter()
{
HandleFilterChanged();
}
public void RefreshSorting()
{
HandleSortChanged();
}
public IEnumerator<T> GetEnumerator()
{
return view.GetEnumerator();
}
IEnumerator IEnumerable.GetEnumerator()
{
return view.GetEnumerator();
}
public void Add(T item)
{
source.Add(item);
}
public void Clear()
{
source.Clear();
}
public bool Contains(T item)
{
return view.Contains(item);
}
public void CopyTo(T[] array, int arrayIndex)
{
view.CopyTo(array, arrayIndex);
}
public bool Remove(T item)
{
source.Remove(item);
return true;
}
[SuppressMessage("", "SH007")]
public int IndexOf(T? item)
{
return view.IndexOf(item!);
}
public void Insert(int index, T item)
{
source.Insert(index, item);
}
public void RemoveAt(int index)
{
Remove(view[index]);
}
public bool MoveCurrentTo(T? item)
{
return (item is not null && item.Equals(CurrentItem)) || MoveCurrentToIndex(IndexOf(item));
}
public bool MoveCurrentToPosition(int index)
{
return MoveCurrentToIndex(index);
}
public bool MoveCurrentToFirst()
{
return MoveCurrentToIndex(0);
}
public bool MoveCurrentToLast()
{
return MoveCurrentToIndex(view.Count - 1);
}
public bool MoveCurrentToNext()
{
return MoveCurrentToIndex(CurrentPosition + 1);
}
public bool MoveCurrentToPrevious()
{
return MoveCurrentToIndex(CurrentPosition - 1);
}
public IAsyncOperation<LoadMoreItemsResult>? LoadMoreItemsAsync(uint count)
{
return (source as ISupportIncrementalLoading)?.LoadMoreItemsAsync(count);
}
public void ObserveFilterProperty(string propertyName)
{
observedFilterProperties.Add(propertyName);
}
public void ClearObservedFilterProperties()
{
observedFilterProperties.Clear();
}
public IDisposable DeferRefresh()
{
return new NotificationDeferrer(this);
}
int IComparer<object>.Compare(object? x, object? y)
{
if (sortProperties.Count <= 0)
{
Type listType = source.GetType();
Type? type;
if (listType.IsGenericType)
{
type = listType.GetGenericArguments()[0];
}
else
{
type = x?.GetType();
}
foreach (SortDescription sd in sortDescriptions)
{
if (!string.IsNullOrEmpty(sd.PropertyName))
{
sortProperties[sd.PropertyName] = type?.GetProperty(sd.PropertyName);
}
}
}
foreach (SortDescription sd in sortDescriptions)
{
object? cx, cy;
if (string.IsNullOrEmpty(sd.PropertyName))
{
cx = x;
cy = y;
}
else
{
PropertyInfo? pi = sortProperties[sd.PropertyName];
cx = pi?.GetValue(x);
cy = pi?.GetValue(y);
}
int cmp = sd.Comparer.Compare(cx, cy);
if (cmp is not 0)
{
return sd.Direction is SortDirection.Ascending ? +cmp : -cmp;
}
}
return 0;
}
internal void OnPropertyChanged([CallerMemberName] string propertyName = default!)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
private void ItemOnPropertyChanged(object? item, PropertyChangedEventArgs e)
{
if (!liveShapingEnabled)
{
return;
}
ArgumentNullException.ThrowIfNull(item);
T typedItem = (T)item;
bool? filterResult = filter?.Invoke(typedItem);
if (filterResult.HasValue && observedFilterProperties.Contains(e.PropertyName))
{
int viewIndex = view.IndexOf(typedItem);
if (viewIndex != -1 && !filterResult.Value)
{
RemoveFromView(viewIndex, typedItem);
}
else if (viewIndex == -1 && filterResult.Value)
{
int index = source.IndexOf(typedItem);
HandleItemAdded(index, typedItem);
}
}
if ((filterResult ?? true) && SortDescriptions.Any(sd => sd.PropertyName == e.PropertyName))
{
int oldIndex = view.IndexOf(typedItem);
// Check if item is in view:
if (oldIndex < 0)
{
return;
}
view.RemoveAt(oldIndex);
int targetIndex = view.BinarySearch(typedItem, this);
if (targetIndex < 0)
{
targetIndex = ~targetIndex;
}
// Only trigger expensive UI updates if the index really changed:
if (targetIndex != oldIndex)
{
OnVectorChanged(new VectorChangedEventArgs(CollectionChange.ItemRemoved, oldIndex, typedItem));
view.Insert(targetIndex, typedItem);
OnVectorChanged(new VectorChangedEventArgs(CollectionChange.ItemInserted, targetIndex, typedItem));
}
else
{
view.Insert(targetIndex, typedItem);
}
}
else if (string.IsNullOrEmpty(e.PropertyName))
{
HandleSourceChanged();
}
}
private void AttachPropertyChangedHandler(IEnumerable items)
{
if (!liveShapingEnabled || items is null)
{
return;
}
foreach (object item in items)
{
if (item is INotifyPropertyChanged notifyPropertyChanged)
{
notifyPropertyChanged.PropertyChanged += ItemOnPropertyChanged;
}
}
}
private void DetachPropertyChangedHandler(IEnumerable items)
{
if (!liveShapingEnabled || items is null)
{
return;
}
foreach (object item in items)
{
if (item is INotifyPropertyChanged notifyPropertyChanged)
{
notifyPropertyChanged.PropertyChanged -= ItemOnPropertyChanged;
}
}
}
private void HandleSortChanged()
{
sortProperties.Clear();
view.Sort(this);
sortProperties.Clear();
OnVectorChanged(new VectorChangedEventArgs(CollectionChange.Reset));
}
private void HandleFilterChanged()
{
if (filter is not null)
{
for (int index = 0; index < view.Count; index++)
{
T item = view[index];
if (filter(item))
{
continue;
}
RemoveFromView(index, item);
index--;
}
}
HashSet<T> viewHash = new(view);
int viewIndex = 0;
for (int index = 0; index < source.Count; index++)
{
T item = source[index];
if (viewHash.Contains(item))
{
viewIndex++;
continue;
}
if (HandleItemAdded(index, item, viewIndex))
{
viewIndex++;
}
}
}
private void HandleSourceChanged()
{
sortProperties.Clear();
T? currentItem = CurrentItem;
view.Clear();
foreach (T item in Source)
{
if (filter is not null && !filter(item))
{
continue;
}
if (sortDescriptions.Count > 0)
{
int targetIndex = view.BinarySearch(item, this);
if (targetIndex < 0)
{
targetIndex = ~targetIndex;
}
view.Insert(targetIndex, item);
}
else
{
view.Add(item);
}
}
sortProperties.Clear();
OnVectorChanged(new VectorChangedEventArgs(CollectionChange.Reset));
MoveCurrentTo(currentItem);
}
private void SourceNotifyCollectionChangedCollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
{
switch (e.Action)
{
case NotifyCollectionChangedAction.Add:
ArgumentNullException.ThrowIfNull(e.NewItems);
AttachPropertyChangedHandler(e.NewItems);
if (deferCounter <= 0)
{
if (e.NewItems?.Count == 1)
{
object? newItem = e.NewItems[0];
ArgumentNullException.ThrowIfNull(newItem);
HandleItemAdded(e.NewStartingIndex, (T)newItem);
}
else
{
HandleSourceChanged();
}
}
break;
case NotifyCollectionChangedAction.Remove:
ArgumentNullException.ThrowIfNull(e.OldItems);
DetachPropertyChangedHandler(e.OldItems);
if (deferCounter <= 0)
{
if (e.OldItems?.Count == 1)
{
object? oldItem = e.OldItems[0];
ArgumentNullException.ThrowIfNull(oldItem);
HandleItemRemoved(e.OldStartingIndex, (T)oldItem);
}
else
{
HandleSourceChanged();
}
}
break;
case NotifyCollectionChangedAction.Move:
case NotifyCollectionChangedAction.Replace:
case NotifyCollectionChangedAction.Reset:
if (deferCounter <= 0)
{
HandleSourceChanged();
}
break;
}
}
private bool HandleItemAdded(int newStartingIndex, T newItem, int? viewIndex = null)
{
if (filter is not null && !filter(newItem))
{
return false;
}
int newViewIndex = view.Count;
if (sortDescriptions.Count > 0)
{
sortProperties.Clear();
newViewIndex = view.BinarySearch(newItem, this);
if (newViewIndex < 0)
{
newViewIndex = ~newViewIndex;
}
}
else if (filter is not null)
{
if (source is null)
{
HandleSourceChanged();
return false;
}
if (newStartingIndex == 0 || view.Count == 0)
{
newViewIndex = 0;
}
else if (newStartingIndex == source.Count - 1)
{
newViewIndex = view.Count;
}
else if (viewIndex.HasValue)
{
newViewIndex = viewIndex.Value;
}
else
{
for (int i = 0, j = 0; i < source.Count; i++)
{
if (i == newStartingIndex)
{
newViewIndex = j;
break;
}
if (Equals(view[j], source[i]))
{
j++;
}
}
}
}
view.Insert(newViewIndex, newItem);
if (newViewIndex <= CurrentPosition)
{
CurrentPosition++;
}
OnVectorChanged(new VectorChangedEventArgs(CollectionChange.ItemInserted, newViewIndex, newItem));
return true;
}
private void HandleItemRemoved(int oldStartingIndex, T oldItem)
{
if (filter is not null && !filter(oldItem))
{
return;
}
if (oldStartingIndex < 0 || oldStartingIndex >= view.Count || !Equals(view[oldStartingIndex], oldItem))
{
oldStartingIndex = view.IndexOf(oldItem);
}
if (oldStartingIndex < 0)
{
return;
}
RemoveFromView(oldStartingIndex, oldItem);
}
private void RemoveFromView(int itemIndex, T item)
{
view.RemoveAt(itemIndex);
if (itemIndex <= CurrentPosition)
{
CurrentPosition--;
}
OnVectorChanged(new VectorChangedEventArgs(CollectionChange.ItemRemoved, itemIndex, item));
}
private void SortDescriptionsCollectionChanged(object? sender, NotifyCollectionChangedEventArgs e)
{
if (deferCounter > 0)
{
return;
}
HandleSortChanged();
}
private bool MoveCurrentToIndex(int i)
{
if (i < -1 || i >= view.Count)
{
return false;
}
if (i == CurrentPosition)
{
return false;
}
CurrentChangingEventArgs e = new();
OnCurrentChanging(e);
if (e.Cancel)
{
return false;
}
CurrentPosition = i;
OnCurrentChanged(default!);
return true;
}
private void OnCurrentChanging(CurrentChangingEventArgs e)
{
if (deferCounter > 0)
{
return;
}
CurrentChanging?.Invoke(this, e);
}
private void OnCurrentChanged(object e)
{
if (deferCounter > 0)
{
return;
}
CurrentChanged?.Invoke(this, e);
OnPropertyChanged(nameof(CurrentItem));
}
private void OnVectorChanged(IVectorChangedEventArgs e)
{
if (deferCounter > 0)
{
return;
}
VectorChanged?.Invoke(this, e);
OnPropertyChanged(nameof(Count));
}
internal sealed class NotificationDeferrer : IDisposable
{
private readonly AdvancedCollectionView<T> advancedCollectionView;
private readonly T? currentItem;
public NotificationDeferrer(AdvancedCollectionView<T> acvs)
{
advancedCollectionView = acvs;
currentItem = advancedCollectionView.CurrentItem;
advancedCollectionView.deferCounter++;
}
public void Dispose()
{
advancedCollectionView.MoveCurrentTo(currentItem);
advancedCollectionView.deferCounter--;
advancedCollectionView.Refresh();
}
}
}

View File

@@ -0,0 +1,105 @@
// Copyright (c) DGP Studio. All rights reserved.
// Licensed under the MIT license.
using CommunityToolkit.WinUI.Collections;
using Microsoft.UI.Xaml.Data;
using System.Collections;
namespace Snap.Hutao.Control.Collection.AdvancedCollectionView;
internal interface IAdvancedCollectionView<T> : ICollectionView, IEnumerable
where T : class
{
bool CanFilter { get; }
bool CanSort { get; }
object? ICollectionView.CurrentItem
{
get => CurrentItem;
}
new T? CurrentItem { get; }
Predicate<T>? Filter { get; set; }
IList<SortDescription> SortDescriptions { get; }
IEnumerable<T> SourceCollection { get; }
object IList<object>.this[int index]
{
get => this[index];
set => this[index] = (T)value;
}
new T this[int index] { get; set; }
void ICollection<object>.Add(object item)
{
Add((T)item);
}
void Add(T item);
void ClearObservedFilterProperties();
bool ICollection<object>.Contains(object item)
{
return Contains((T)item);
}
bool Contains(T item);
void ICollection<object>.CopyTo(object[] array, int arrayIndex)
{
CopyTo((T[])array, arrayIndex);
}
void CopyTo(T[] array, int arrayIndex);
IDisposable DeferRefresh();
IEnumerator<object> IEnumerable<object>.GetEnumerator()
{
return GetEnumerator();
}
new IEnumerator<T> GetEnumerator();
int IList<object>.IndexOf(object item)
{
return IndexOf((T)item);
}
int IndexOf(T item);
void IList<object>.Insert(int index, object item)
{
Insert(index, (T)item);
}
void Insert(int index, T item);
bool ICollectionView.MoveCurrentTo(object item)
{
return MoveCurrentTo((T)item);
}
bool MoveCurrentTo(T item);
void ObserveFilterProperty(string propertyName);
void Refresh();
void RefreshFilter();
void RefreshSorting();
bool ICollection<object>.Remove(object item)
{
return Remove((T)item);
}
bool Remove(T item);
}

View File

@@ -0,0 +1,19 @@
// Copyright (c) DGP Studio. All rights reserved.
// Licensed under the MIT license.
using Windows.Foundation.Collections;
namespace Snap.Hutao.Control.Collection.AdvancedCollectionView;
internal sealed class VectorChangedEventArgs : IVectorChangedEventArgs
{
public VectorChangedEventArgs(CollectionChange cc, int index = -1, object item = default!)
{
CollectionChange = cc;
Index = (uint)index;
}
public CollectionChange CollectionChange { get; }
public uint Index { get; }
}

View File

@@ -1,38 +0,0 @@
// Copyright (c) DGP Studio. All rights reserved.
// Licensed under the MIT license.
using Microsoft.UI.Xaml.Controls;
using Windows.Foundation.Collections;
namespace Snap.Hutao.Control.Collection.Alternating;
[DependencyProperty("ItemAlternateBackground", typeof(Microsoft.UI.Xaml.Media.Brush))]
internal sealed partial class AlternatingItemsControl : ItemsControl
{
private readonly VectorChangedEventHandler<object> itemsVectorChangedEventHandler;
public AlternatingItemsControl()
{
itemsVectorChangedEventHandler = OnItemsVectorChanged;
Items.VectorChanged += itemsVectorChangedEventHandler;
}
private void OnItemsVectorChanged(IObservableVector<object> items, IVectorChangedEventArgs args)
{
if (args.CollectionChange is CollectionChange.Reset)
{
int index = (int)args.Index;
for (int i = index; i < items.Count; i++)
{
if (items[i] is IAlternatingItem item)
{
item.Background = i % 2 is 0 ? default : ItemAlternateBackground;
}
else
{
break;
}
}
}
}
}

View File

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

View File

@@ -3,6 +3,7 @@
using Microsoft.UI.Xaml;
using Microsoft.UI.Xaml.Data;
using Snap.Hutao.Core.ExceptionService;
namespace Snap.Hutao.Control;
@@ -40,6 +41,6 @@ internal abstract class DependencyValueConverter<TFrom, TTo> : DependencyObject,
/// <returns>源</returns>
public virtual TFrom ConvertBack(TTo to)
{
throw Must.NeverHappen();
throw HutaoException.NotSupported();
}
}

View File

@@ -0,0 +1,18 @@
// Copyright (c) DGP Studio. All rights reserved.
// Licensed under the MIT license.
namespace Snap.Hutao.Control.Extension;
internal static class CommandInvocation
{
public static bool TryExecute(this ICommand? command, object? parameter = null)
{
if (command is not null && command.CanExecute(parameter))
{
command.Execute(parameter);
return true;
}
return false;
}
}

View File

@@ -2,11 +2,13 @@
// Licensed under the MIT license.
using Microsoft.UI.Xaml;
using System.Runtime.CompilerServices;
namespace Snap.Hutao.Control.Extension;
internal static class DependencyObjectExtension
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static IServiceProvider ServiceProvider(this DependencyObject obj)
{
return Ioc.Default;

View File

@@ -28,4 +28,20 @@ internal static class FrameworkElementExtension
frameworkElement.IsRightTapEnabled = false;
frameworkElement.IsTabStop = false;
}
public static void InitializeDataContext<TDataContext>(this FrameworkElement frameworkElement, IServiceProvider? serviceProvider = default)
where TDataContext : class
{
IServiceProvider service = serviceProvider ?? Ioc.Default;
try
{
frameworkElement.DataContext = service.GetRequiredService<TDataContext>();
}
catch (Exception ex)
{
ILogger? logger = service.GetRequiredService(typeof(ILogger<>).MakeGenericType([frameworkElement.GetType()])) as ILogger;
logger?.LogError(ex, "Failed to initialize DataContext");
throw;
}
}
}

View File

@@ -7,6 +7,8 @@ namespace Snap.Hutao.Control.Helper;
[SuppressMessage("", "SH001")]
[DependencyProperty("SquareLength", typeof(double), 0D, nameof(OnSquareLengthChanged), IsAttached = true, AttachedType = typeof(FrameworkElement))]
[DependencyProperty("IsActualThemeBindingEnabled", typeof(bool), false, nameof(OnIsActualThemeBindingEnabled), IsAttached = true, AttachedType = typeof(FrameworkElement))]
[DependencyProperty("ActualTheme", typeof(ElementTheme), ElementTheme.Default, IsAttached = true, AttachedType = typeof(FrameworkElement))]
public sealed partial class FrameworkElementHelper
{
private static void OnSquareLengthChanged(DependencyObject dp, DependencyPropertyChangedEventArgs e)
@@ -15,4 +17,22 @@ public sealed partial class FrameworkElementHelper
element.Width = (double)e.NewValue;
element.Height = (double)e.NewValue;
}
private static void OnIsActualThemeBindingEnabled(DependencyObject dp, DependencyPropertyChangedEventArgs e)
{
FrameworkElement element = (FrameworkElement)dp;
if ((bool)e.NewValue)
{
element.ActualThemeChanged += OnActualThemeChanged;
}
else
{
element.ActualThemeChanged -= OnActualThemeChanged;
}
static void OnActualThemeChanged(FrameworkElement sender, object args)
{
SetActualTheme(sender, sender.ActualTheme);
}
}
}

View File

@@ -0,0 +1,39 @@
// Copyright (c) DGP Studio. All rights reserved.
// Licensed under the MIT license.
using CommunityToolkit.WinUI;
using Microsoft.UI.Xaml;
using Microsoft.UI.Xaml.Controls;
namespace Snap.Hutao.Control.Helper;
[SuppressMessage("", "SH001")]
[DependencyProperty("PaneCornerRadius", typeof(CornerRadius), default, nameof(OnPaneCornerRadiusChanged), IsAttached = true, AttachedType = typeof(NavigationView))]
public sealed partial class NavigationViewHelper
{
private static void OnPaneCornerRadiusChanged(DependencyObject dp, DependencyPropertyChangedEventArgs args)
{
NavigationView navigationView = (NavigationView)dp;
CornerRadius newValue = (CornerRadius)args.NewValue;
if (navigationView.IsLoaded)
{
SetNavigationViewPaneCornerRadius(navigationView, newValue);
return;
}
navigationView.Loaded += (s, e) =>
{
NavigationView loadedNavigationView = (NavigationView)s;
SetNavigationViewPaneCornerRadius(loadedNavigationView, newValue);
};
}
private static void SetNavigationViewPaneCornerRadius(NavigationView navigationView, CornerRadius value)
{
if (navigationView.FindDescendant("RootSplitView") is SplitView splitView)
{
splitView.CornerRadius = value;
}
}
}

View File

@@ -7,7 +7,6 @@ using Microsoft.UI.Xaml.Controls;
namespace Snap.Hutao.Control.Helper;
[SuppressMessage("", "SH001")]
[DependencyProperty("LeftPanelMaxWidth", typeof(double), IsAttached = true, AttachedType = typeof(ScrollViewer))]
[DependencyProperty("RightPanel", typeof(UIElement), IsAttached = true, AttachedType = typeof(ScrollViewer))]
public sealed partial class ScrollViewerHelper
{

View File

@@ -20,4 +20,4 @@ public sealed partial class SettingsExpanderHelper
}
}
}
}
}

View File

@@ -0,0 +1,24 @@
// Copyright (c) DGP Studio. All rights reserved.
// Licensed under the MIT license.
using Microsoft.UI.Xaml;
namespace Snap.Hutao.Control.Helper;
[SuppressMessage("", "SH001")]
[DependencyProperty("VisibilityObject", typeof(object), null, nameof(OnVisibilityObjectChanged), IsAttached = true, AttachedType = typeof(UIElement))]
[DependencyProperty("OpacityObject", typeof(object), null, nameof(OnOpacityObjectChanged), IsAttached = true, AttachedType = typeof(UIElement))]
public sealed partial class UIElementHelper
{
private static void OnVisibilityObjectChanged(DependencyObject dp, DependencyPropertyChangedEventArgs e)
{
UIElement element = (UIElement)dp;
element.Visibility = e.NewValue is null ? Visibility.Collapsed : Visibility.Visible;
}
private static void OnOpacityObjectChanged(DependencyObject dp, DependencyPropertyChangedEventArgs e)
{
UIElement element = (UIElement)dp;
element.Opacity = e.NewValue is null ? 0D : 1D;
}
}

View File

@@ -1,8 +1,6 @@
// Copyright (c) DGP Studio. All rights reserved.
// Licensed under the MIT license.
namespace Snap.Hutao.Service.Inventroy;
namespace Snap.Hutao.Control;
internal interface IInventoryService
{
}
internal interface IXamlElementAccessor;

View File

@@ -1,10 +1,15 @@
// Copyright (c) DGP Studio. All rights reserved.
// Licensed under the MIT license.
using Microsoft.UI.Xaml.Media;
using Microsoft.UI.Xaml.Media.Imaging;
using Snap.Hutao.Control.Extension;
using Snap.Hutao.Core.Caching;
using Snap.Hutao.Core.ExceptionService;
using Snap.Hutao.Core.IO.DataTransfer;
using System.IO;
using System.Runtime.InteropServices;
using Windows.Graphics.Imaging;
using Windows.Storage.Streams;
namespace Snap.Hutao.Control.Image;
@@ -12,29 +17,32 @@ namespace Snap.Hutao.Control.Image;
/// 缓存图像
/// </summary>
[HighQuality]
internal sealed class CachedImage : Implementation.ImageEx
[DependencyProperty("SourceName", typeof(string), "Unknown")]
[DependencyProperty("CachedName", typeof(string), "Unknown")]
internal sealed partial class CachedImage : Implementation.ImageEx
{
/// <summary>
/// 构造一个新的缓存图像
/// </summary>
public CachedImage()
{
IsCacheEnabled = true;
EnableLazyLoading = false;
DefaultStyleKey = typeof(CachedImage);
DefaultStyleResourceUri = "ms-appx:///Control/Image/CachedImage.xaml".ToUri();
}
/// <inheritdoc/>
protected override async Task<ImageSource?> ProvideCachedResourceAsync(Uri imageUri, CancellationToken token)
protected override async Task<Uri?> ProvideCachedResourceAsync(Uri imageUri, CancellationToken token)
{
// We can only use Ioc to retrieve IImageCache, no IServiceProvider is available.
IImageCache imageCache = Ioc.Default.GetRequiredService<IImageCache>();
SourceName = Path.GetFileName(imageUri.ToString());
IImageCache imageCache = this.ServiceProvider().GetRequiredService<IImageCache>();
try
{
Verify.Operation(!string.IsNullOrEmpty(imageUri.Host), SH.ControlImageCachedImageInvalidResourceUri);
HutaoException.ThrowIf(string.IsNullOrEmpty(imageUri.Host), SH.ControlImageCachedImageInvalidResourceUri);
string file = await imageCache.GetFileFromCacheAsync(imageUri).ConfigureAwait(true); // BitmapImage need to be created by main thread.
CachedName = Path.GetFileName(file);
token.ThrowIfCancellationRequested(); // check token state to determine whether the operation should be canceled.
return new BitmapImage(file.ToUri()); // BitmapImage initialize with a uri will increase image quality and loading speed.
return file.ToUri();
}
catch (COMException)
{
@@ -43,4 +51,27 @@ internal sealed class CachedImage : Implementation.ImageEx
return default;
}
}
}
[Command("CopyToClipboardCommand")]
private async Task CopyToClipboard()
{
if (Image is Microsoft.UI.Xaml.Controls.Image { Source: BitmapImage bitmap })
{
using (FileStream netStream = File.OpenRead(bitmap.UriSource.LocalPath))
{
using (IRandomAccessStream fxStream = netStream.AsRandomAccessStream())
{
BitmapDecoder decoder = await BitmapDecoder.CreateAsync(fxStream);
SoftwareBitmap softwareBitmap = await decoder.GetSoftwareBitmapAsync(BitmapPixelFormat.Bgra8, BitmapAlphaMode.Premultiplied);
using (InMemoryRandomAccessStream memory = new())
{
BitmapEncoder encoder = await BitmapEncoder.CreateAsync(BitmapEncoder.BmpEncoderId, memory);
encoder.SetSoftwareBitmap(softwareBitmap);
await encoder.FlushAsync();
Ioc.Default.GetRequiredService<IClipboardProvider>().SetBitmap(memory);
}
}
}
}
}
}

View File

@@ -1,4 +1,4 @@
<ResourceDictionary
<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">
@@ -6,7 +6,6 @@
<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">
@@ -15,6 +14,13 @@
BorderBrush="{TemplateBinding BorderBrush}"
BorderThickness="{TemplateBinding BorderThickness}"
CornerRadius="{TemplateBinding CornerRadius}">
<Grid.ContextFlyout>
<MenuFlyout>
<MenuFlyoutItem IsEnabled="False" Text="{TemplateBinding SourceName}"/>
<MenuFlyoutItem IsEnabled="False" Text="{TemplateBinding CachedName}"/>
<MenuFlyoutItem Command="{Binding CopyToClipboardCommand, RelativeSource={RelativeSource TemplatedParent}}" Text="复制图像"/>
</MenuFlyout>
</Grid.ContextFlyout>
<Image
Name="PlaceholderImage"
Margin="{TemplateBinding PlaceholderMargin}"

View File

@@ -168,6 +168,7 @@ internal abstract partial class CompositionImage : Microsoft.UI.Xaml.Controls.Co
if (surface.DecodedPhysicalSize.Size() <= 0D)
{
await Task.WhenAny(surfaceLoadTaskCompletionSource.Task, Task.Delay(5000, token)).ConfigureAwait(true);
await Task.Delay(50, token).ConfigureAwait(true);
}
LoadImageSurfaceCompleted(surface);
@@ -192,7 +193,7 @@ internal abstract partial class CompositionImage : Microsoft.UI.Xaml.Controls.Co
{
await AnimationBuilder
.Create()
.Opacity(from: 0D, to: 1D, duration: ControlAnimationConstants.ImageFadeIn)
.Opacity(from: 0D, to: 1D, duration: ControlAnimationConstants.ImageScaleFadeIn)
.StartAsync(this, token)
.ConfigureAwait(true);
}
@@ -213,7 +214,7 @@ internal abstract partial class CompositionImage : Microsoft.UI.Xaml.Controls.Co
{
await AnimationBuilder
.Create()
.Opacity(from: 1D, to: 0D, duration: ControlAnimationConstants.ImageFadeOut)
.Opacity(from: 1D, to: 0D, duration: ControlAnimationConstants.ImageScaleFadeOut)
.StartAsync(this, token)
.ConfigureAwait(true);
}

View File

@@ -7,21 +7,14 @@ using Windows.Media.Casting;
namespace Snap.Hutao.Control.Image.Implementation;
internal class ImageEx : ImageExBase
[DependencyProperty("NineGrid", typeof(Thickness))]
internal partial 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)

View File

@@ -6,8 +6,6 @@ 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;
@@ -20,12 +18,6 @@ namespace Snap.Hutao.Control.Image.Implementation;
[TemplatePart(Name = PartImage, Type = typeof(object))]
[TemplatePart(Name = PartPlaceholderImage, Type = typeof(object))]
[DependencyProperty("Stretch", typeof(Stretch), Stretch.Uniform)]
[DependencyProperty("DecodePixelHeight", typeof(int), 0)]
[DependencyProperty("DecodePixelWidth", typeof(int), 0)]
[DependencyProperty("DecodePixelType", typeof(DecodePixelType), DecodePixelType.Physical)]
[DependencyProperty("IsCacheEnabled", typeof(bool), false)]
[DependencyProperty("EnableLazyLoading", typeof(bool), false, nameof(EnableLazyLoadingChanged))]
[DependencyProperty("LazyLoadingThreshold", typeof(double), default(double), nameof(LazyLoadingThresholdChanged))]
[DependencyProperty("PlaceholderSource", typeof(object), default(object))]
[DependencyProperty("PlaceholderStretch", typeof(Stretch), Stretch.Uniform)]
[DependencyProperty("PlaceholderMargin", typeof(Thickness))]
@@ -41,8 +33,6 @@ internal abstract partial class ImageExBase : Microsoft.UI.Xaml.Controls.Control
protected const string FailedState = "Failed";
private CancellationTokenSource? tokenSource;
private object? lazyLoadingSource;
private bool isInViewport;
public bool IsInitialized { get; private set; }
@@ -57,10 +47,10 @@ internal abstract partial class ImageExBase : Microsoft.UI.Xaml.Controls.Control
public abstract CompositionBrush GetAlphaMask();
protected virtual Task<ImageSource?> ProvideCachedResourceAsync(Uri imageUri, CancellationToken token)
protected virtual Task<Uri?> 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));
return Task.FromResult<Uri?>(imageUri);
}
protected virtual void OnImageOpened(object sender, RoutedEventArgs e)
@@ -79,19 +69,10 @@ internal abstract partial class ImageExBase : Microsoft.UI.Xaml.Controls.Control
RemoveImageFailed(OnImageFailed);
Image = GetTemplateChild(PartImage);
PlaceholderImage = GetTemplateChild(PartPlaceholderImage);
IsInitialized = true;
if (Source is null || !EnableLazyLoading || isInViewport)
{
lazyLoadingSource = null;
SetSource(Source);
}
else
{
lazyLoadingSource = Source;
}
SetSource(Source);
AttachImageOpened(OnImageOpened);
AttachImageFailed(OnImageFailed);
@@ -147,34 +128,6 @@ internal abstract partial class ImageExBase : Microsoft.UI.Xaml.Controls.Control
}
}
private static void EnableLazyLoadingChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
if (d is not ImageExBase control)
{
return;
}
bool value = (bool)e.NewValue;
if (value)
{
control.LayoutUpdated += control.OnImageExBaseLayoutUpdated;
control.InvalidateLazyLoading();
}
else
{
control.LayoutUpdated -= control.OnImageExBaseLayoutUpdated;
}
}
private static void LazyLoadingThresholdChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
if (d is ImageExBase control && control.EnableLazyLoading)
{
control.InvalidateLazyLoading();
}
}
private static void SourceChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
if (d is not ImageExBase control)
@@ -187,15 +140,7 @@ internal abstract partial class ImageExBase : Microsoft.UI.Xaml.Controls.Control
return;
}
if (e.NewValue is null || !control.EnableLazyLoading || control.isInViewport)
{
control.lazyLoadingSource = null;
control.SetSource(e.NewValue);
}
else
{
control.lazyLoadingSource = e.NewValue;
}
control.SetSource(e.NewValue);
}
private static bool IsHttpUri(Uri uri)
@@ -203,11 +148,8 @@ internal abstract partial class ImageExBase : Microsoft.UI.Xaml.Controls.Control
return uri.IsAbsoluteUri && (uri.Scheme == "http" || uri.Scheme == "https");
}
private void AttachSource(ImageSource? source)
private void AttachSource(BitmapImage? source, Uri? uri)
{
// 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;
@@ -221,17 +163,16 @@ internal abstract partial class ImageExBase : Microsoft.UI.Xaml.Controls.Control
{
VisualStateManager.GoToState(this, UnloadedState, true);
}
else if (source is BitmapSource { PixelHeight: > 0, PixelWidth: > 0 })
else
{
// https://learn.microsoft.com/en-us/windows/uwp/debug-test-perf/optimize-animations-and-media#optimize-image-resources
source.UriSource = uri;
VisualStateManager.GoToState(this, LoadedState, true);
}
}
private void AttachPlaceholderSource(ImageSource? source)
private void AttachPlaceholderSource(BitmapImage? source, Uri? uri)
{
// 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 (PlaceholderImage is Microsoft.UI.Xaml.Controls.Image image)
{
image.Source = source;
@@ -240,6 +181,17 @@ internal abstract partial class ImageExBase : Microsoft.UI.Xaml.Controls.Control
{
brush.ImageSource = source;
}
if (source is null)
{
VisualStateManager.GoToState(this, UnloadedState, true);
}
else
{
// https://learn.microsoft.com/en-us/windows/uwp/debug-test-perf/optimize-animations-and-media#optimize-image-resources
source.UriSource = uri;
VisualStateManager.GoToState(this, LoadedState, true);
}
}
private async void SetSource(object? source)
@@ -250,10 +202,9 @@ internal abstract partial class ImageExBase : Microsoft.UI.Xaml.Controls.Control
}
tokenSource?.Cancel();
tokenSource = new CancellationTokenSource();
AttachSource(null);
AttachSource(default, default);
if (source is null)
{
@@ -262,13 +213,6 @@ internal abstract partial class ImageExBase : Microsoft.UI.Xaml.Controls.Control
VisualStateManager.GoToState(this, LoadingState, true);
if (source as ImageSource is { } imageSource)
{
AttachSource(imageSource);
return;
}
if (source as Uri is not { } uri)
{
string? url = source as string ?? source.ToString();
@@ -311,23 +255,15 @@ internal abstract partial class ImageExBase : Microsoft.UI.Xaml.Controls.Control
}
tokenSource?.Cancel();
tokenSource = new();
tokenSource = new CancellationTokenSource();
AttachPlaceholderSource(null);
AttachPlaceholderSource(default, default);
if (source is null)
{
return;
}
if (source as ImageSource is { } imageSource)
{
AttachPlaceholderSource(imageSource);
return;
}
if (source as Uri is not { } uri)
{
string? url = source as string ?? source.ToString();
@@ -349,13 +285,13 @@ internal abstract partial class ImageExBase : Microsoft.UI.Xaml.Controls.Control
return;
}
ImageSource? img = await ProvideCachedResourceAsync(uri, tokenSource.Token).ConfigureAwait(true);
Uri? actualUri = await ProvideCachedResourceAsync(uri, tokenSource.Token).ConfigureAwait(true);
ArgumentNullException.ThrowIfNull(tokenSource);
if (!tokenSource.IsCancellationRequested)
{
// Only attach our image if we still have a valid request.
AttachPlaceholderSource(img);
AttachPlaceholderSource(new BitmapImage(), actualUri);
}
}
catch (OperationCanceledException)
@@ -374,98 +310,13 @@ internal abstract partial class ImageExBase : Microsoft.UI.Xaml.Controls.Control
return;
}
if (IsCacheEnabled)
Uri? actualUri = await ProvideCachedResourceAsync(imageUri, token).ConfigureAwait(true);
ArgumentNullException.ThrowIfNull(tokenSource);
if (!tokenSource.IsCancellationRequested)
{
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 OnImageExBaseLayoutUpdated(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;
// Only attach our image if we still have a valid request.
AttachSource(new BitmapImage(), actualUri);
}
}
}

View File

@@ -1,151 +0,0 @@
// Copyright (c) DGP Studio. All rights reserved.
// Licensed under the MIT license.
using Microsoft.UI.Composition;
using Microsoft.UI.Xaml.Controls;
using Microsoft.UI.Xaml.Hosting;
using System.Numerics;
using Windows.Foundation;
namespace Snap.Hutao.Control.Layout;
internal sealed class DefaultItemCollectionTransitionProvider : ItemCollectionTransitionProvider
{
private const double DefaultAnimationDurationInMs = 300.0;
static DefaultItemCollectionTransitionProvider()
{
AnimationSlowdownFactor = 1.0;
}
public static double AnimationSlowdownFactor { get; set; }
protected override bool ShouldAnimateCore(ItemCollectionTransition transition)
{
return true;
}
protected override void StartTransitions(IList<ItemCollectionTransition> transitions)
{
List<ItemCollectionTransition> addTransitions = [];
List<ItemCollectionTransition> removeTransitions = [];
List<ItemCollectionTransition> moveTransitions = [];
foreach (ItemCollectionTransition transition in addTransitions)
{
switch (transition.Operation)
{
case ItemCollectionTransitionOperation.Add:
addTransitions.Add(transition);
break;
case ItemCollectionTransitionOperation.Remove:
removeTransitions.Add(transition);
break;
case ItemCollectionTransitionOperation.Move:
moveTransitions.Add(transition);
break;
}
}
StartAddTransitions(addTransitions, removeTransitions.Count > 0, moveTransitions.Count > 0);
StartRemoveTransitions(removeTransitions);
StartMoveTransitions(moveTransitions, removeTransitions.Count > 0);
}
private static void StartAddTransitions(IList<ItemCollectionTransition> transitions, bool hasRemoveTransitions, bool hasMoveTransitions)
{
foreach (ItemCollectionTransition transition in transitions)
{
ItemCollectionTransitionProgress progress = transition.Start();
Visual visual = ElementCompositionPreview.GetElementVisual(progress.Element);
Compositor compositor = visual.Compositor;
ScalarKeyFrameAnimation fadeInAnimation = compositor.CreateScalarKeyFrameAnimation();
fadeInAnimation.InsertKeyFrame(0.0f, 0.0f);
if (hasMoveTransitions && hasRemoveTransitions)
{
fadeInAnimation.InsertKeyFrame(0.66f, 0.0f);
}
else if (hasMoveTransitions || hasRemoveTransitions)
{
fadeInAnimation.InsertKeyFrame(0.5f, 0.0f);
}
fadeInAnimation.InsertKeyFrame(1.0f, 1.0f);
fadeInAnimation.Duration = TimeSpan.FromMilliseconds(
DefaultAnimationDurationInMs * ((hasRemoveTransitions ? 1 : 0) + (hasMoveTransitions ? 1 : 0) + 1) * AnimationSlowdownFactor);
CompositionScopedBatch batch = compositor.CreateScopedBatch(CompositionBatchTypes.Animation);
visual.StartAnimation("Opacity", fadeInAnimation);
batch.End();
batch.Completed += (_, _) => progress.Complete();
}
}
private static void StartRemoveTransitions(IList<ItemCollectionTransition> transitions)
{
foreach (ItemCollectionTransition transition in transitions)
{
ItemCollectionTransitionProgress progress = transition.Start();
Visual visual = ElementCompositionPreview.GetElementVisual(progress.Element);
Compositor compositor = visual.Compositor;
ScalarKeyFrameAnimation fadeOutAnimation = compositor.CreateScalarKeyFrameAnimation();
fadeOutAnimation.InsertExpressionKeyFrame(0.0f, "this.CurrentValue");
fadeOutAnimation.InsertKeyFrame(1.0f, 0.0f);
fadeOutAnimation.Duration = TimeSpan.FromMilliseconds(DefaultAnimationDurationInMs * AnimationSlowdownFactor);
CompositionScopedBatch batch = compositor.CreateScopedBatch(CompositionBatchTypes.Animation);
visual.StartAnimation(nameof(Visual.Opacity), fadeOutAnimation);
batch.End();
batch.Completed += (_, _) =>
{
visual.Opacity = 1.0f;
progress.Complete();
};
}
}
private static void StartMoveTransitions(IList<ItemCollectionTransition> transitions, bool hasRemoveAnimations)
{
foreach (ItemCollectionTransition transition in transitions)
{
ItemCollectionTransitionProgress progress = transition.Start();
Visual visual = ElementCompositionPreview.GetElementVisual(progress.Element);
Compositor compositor = visual.Compositor;
CompositionScopedBatch batch = compositor.CreateScopedBatch(CompositionBatchTypes.Animation);
// Animate offset.
if (transition.OldBounds.X != transition.NewBounds.X ||
transition.OldBounds.Y != transition.NewBounds.Y)
{
AnimateOffset(visual, compositor, transition.OldBounds, transition.NewBounds, hasRemoveAnimations);
}
batch.End();
batch.Completed += (_, _) => progress.Complete();
}
}
private static void AnimateOffset(Visual visual, Compositor compositor, Rect oldBounds, Rect newBounds, bool hasRemoveAnimations)
{
Vector2KeyFrameAnimation offsetAnimation = compositor.CreateVector2KeyFrameAnimation();
offsetAnimation.SetVector2Parameter("delta", new Vector2(
(float)(oldBounds.X - newBounds.X),
(float)(oldBounds.Y - newBounds.Y)));
offsetAnimation.SetVector2Parameter("final", default);
offsetAnimation.InsertExpressionKeyFrame(0.0f, "this.CurrentValue + delta");
if (hasRemoveAnimations)
{
offsetAnimation.InsertExpressionKeyFrame(0.5f, "delta");
}
offsetAnimation.InsertExpressionKeyFrame(1.0f, "final");
offsetAnimation.Duration = TimeSpan.FromMilliseconds(
DefaultAnimationDurationInMs * ((hasRemoveAnimations ? 1 : 0) + 1) * AnimationSlowdownFactor);
visual.StartAnimation("TransformMatrix._41_42", offsetAnimation);
}
}

View File

@@ -18,14 +18,12 @@ internal sealed partial class UniformStaggeredLayout : VirtualizingLayout
protected override void InitializeForContextCore(VirtualizingLayoutContext context)
{
context.LayoutState = new UniformStaggeredLayoutState(context);
base.InitializeForContextCore(context);
}
/// <inheritdoc/>
protected override void UninitializeForContextCore(VirtualizingLayoutContext context)
{
context.LayoutState = null;
base.UninitializeForContextCore(context);
}
/// <inheritdoc/>
@@ -65,12 +63,12 @@ internal sealed partial class UniformStaggeredLayout : VirtualizingLayout
/// <inheritdoc/>
protected override Size MeasureOverride(VirtualizingLayoutContext context, Size availableSize)
{
if (context.ItemCount == 0)
if (context.ItemCount is 0)
{
return new Size(availableSize.Width, 0);
}
if ((context.RealizationRect.Width == 0) && (context.RealizationRect.Height == 0))
if ((context.RealizationRect.Width is 0) && (context.RealizationRect.Height is 0))
{
return new Size(availableSize.Width, 0.0f);
}
@@ -82,16 +80,10 @@ internal sealed partial class UniformStaggeredLayout : VirtualizingLayout
(int numberOfColumns, double columnWidth) = GetNumberOfColumnsAndWidth(availableWidth, MinItemWidth, MinColumnSpacing);
if (columnWidth != state.ColumnWidth)
{
// The items will need to be remeasured
state.Clear();
}
state.ColumnWidth = columnWidth;
// adjust for column spacing on all columns expect the first
double totalWidth = state.ColumnWidth + ((numberOfColumns - 1) * (state.ColumnWidth + MinColumnSpacing));
double totalWidth = ((state.ColumnWidth + MinColumnSpacing) * numberOfColumns) - MinColumnSpacing;
if (totalWidth > availableWidth)
{
numberOfColumns--;
@@ -103,7 +95,6 @@ internal sealed partial class UniformStaggeredLayout : VirtualizingLayout
if (numberOfColumns != state.NumberOfColumns)
{
// The items will not need to be remeasured, but they will need to go into new columns
state.ClearColumns();
}
@@ -170,7 +161,7 @@ internal sealed partial class UniformStaggeredLayout : VirtualizingLayout
item.Element.Measure(new Size(state.ColumnWidth, availableHeight));
if (item.Height != item.Element.DesiredSize.Height)
{
// this item changed size; we need to recalculate layout for everything after this
// this item changed size; we need to recalculate layout for everything after this item
state.RemoveFromIndex(i + 1);
item.Height = item.Element.DesiredSize.Height;
columnHeights[columnIndex] = item.Top + item.Height;
@@ -201,16 +192,16 @@ internal sealed partial class UniformStaggeredLayout : VirtualizingLayout
// Cycle through each column and arrange the items that are within the realization bounds
for (int columnIndex = 0; columnIndex < state.NumberOfColumns; columnIndex++)
{
UniformStaggeredColumnLayout layout = state.GetColumnLayout(columnIndex);
foreach (ref readonly UniformStaggeredItem item in CollectionsMarshal.AsSpan(layout))
foreach (ref readonly UniformStaggeredItem item in CollectionsMarshal.AsSpan(state.GetColumnLayout(columnIndex)))
{
double bottom = item.Top + item.Height;
if (bottom < context.RealizationRect.Top)
{
// element is above the realization bounds
// Element is above the realization bounds
continue;
}
// Partial or fully in the view
if (item.Top <= context.RealizationRect.Bottom)
{
double itemHorizontalOffset = (state.ColumnWidth * columnIndex) + (MinColumnSpacing * columnIndex);
@@ -229,21 +220,22 @@ internal sealed partial class UniformStaggeredLayout : VirtualizingLayout
return finalSize;
}
private static (int NumberOfColumns, double ColumnWidth) GetNumberOfColumnsAndWidth(double availableWidth, double minItemWidth, double minColumnSpacing)
private static (int NumberOfColumns, double ColumnWidth) GetNumberOfColumnsAndWidth(double availableWidth, double minItemWidth, double columnSpacing)
{
// test if the width can fit in 2 items
if ((2 * minItemWidth) + minColumnSpacing > availableWidth)
if ((2 * minItemWidth) + columnSpacing > availableWidth)
{
return (1, availableWidth);
}
int columnCount = Math.Max(1, (int)((availableWidth + minColumnSpacing) / (minItemWidth + minColumnSpacing)));
double columnWidthAddSpacing = (availableWidth + minColumnSpacing) / columnCount;
return (columnCount, columnWidthAddSpacing - minColumnSpacing);
int columnCount = Math.Max(1, (int)((availableWidth + columnSpacing) / (minItemWidth + columnSpacing)));
double columnWidthWithSpacing = (availableWidth + columnSpacing) / columnCount;
return (columnCount, columnWidthWithSpacing - columnSpacing);
}
private static int GetLowestColumnIndex(in ReadOnlySpan<double> columnHeights)
{
// We want to find the leftest column with the lowest height
int columnIndex = 0;
double height = columnHeights[0];
for (int j = 1; j < columnHeights.Length; j++)
@@ -260,13 +252,11 @@ internal sealed partial class UniformStaggeredLayout : VirtualizingLayout
private static void OnMinItemWidthChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
UniformStaggeredLayout panel = (UniformStaggeredLayout)d;
panel.InvalidateMeasure();
((UniformStaggeredLayout)d).InvalidateMeasure();
}
private static void OnSpacingChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
UniformStaggeredLayout panel = (UniformStaggeredLayout)d;
panel.InvalidateMeasure();
((UniformStaggeredLayout)d).InvalidateMeasure();
}
}

View File

@@ -1,7 +1,6 @@
// Copyright (c) DGP Studio. All rights reserved.
// Licensed under the MIT license.
using Microsoft.UI.Xaml;
using Microsoft.UI.Xaml.Controls;
using System.Runtime.InteropServices;
@@ -67,46 +66,6 @@ internal sealed class UniformStaggeredLayoutState
return columnLayout[columnIndex];
}
/// <summary>
/// Clear everything that has been calculated.
/// </summary>
internal void Clear()
{
// https://github.com/DGP-Studio/Snap.Hutao/issues/1079
// The first element must be force refreshed otherwise
// it will use the old one realized
// https://github.com/DGP-Studio/Snap.Hutao/issues/1099
// Now we need to refresh the first element of each column
// https://github.com/DGP-Studio/Snap.Hutao/issues/1099
// Finally we need to refresh the whole layout when we reset
if (context.ItemCount > 0)
{
for (int i = 0; i < context.ItemCount; i++)
{
RecycleElementAt(i);
}
}
columnLayout.Clear();
items.Clear();
}
/// <summary>
/// Clear the layout columns so they will be recalculated.
/// </summary>
internal void ClearColumns()
{
columnLayout.Clear();
}
/// <summary>
/// Gets the estimated height of the layout.
/// </summary>
/// <returns>The estimated height of the layout.</returns>
/// <remarks>
/// If all of the items have been calculated then the actual height will be returned.
/// If all of the items have not been calculated then an estimated height will be calculated based on the average height of the items.
/// </remarks>
internal double GetHeight()
{
double desiredHeight = columnLayout.Values.Max(c => c.Height);
@@ -139,10 +98,37 @@ internal sealed class UniformStaggeredLayoutState
return desiredHeight;
}
internal void Clear()
{
RecycleElements();
ClearColumns();
ClearItems();
}
internal void ClearColumns()
{
columnLayout.Clear();
}
internal void ClearItems()
{
items.Clear();
}
internal void RecycleElements()
{
if (context.ItemCount > 0)
{
for (int i = 0; i < items.Count; i++)
{
RecycleElementAt(i);
}
}
}
internal void RecycleElementAt(int index)
{
UIElement element = context.GetOrCreateElementAt(index);
context.RecycleElement(element);
context.RecycleElement(context.GetOrCreateElementAt(index));
}
internal void RemoveFromIndex(int index)
@@ -175,7 +161,7 @@ internal sealed class UniformStaggeredLayoutState
{
for (int i = startIndex; i <= endIndex; i++)
{
if (i > items.Count)
if (i >= items.Count)
{
break;
}
@@ -184,7 +170,7 @@ internal sealed class UniformStaggeredLayoutState
item.Height = 0;
item.Top = 0;
// We must recycle all elements to ensure that it gets the correct context
// We must recycle all removed elements to ensure that it gets the correct context
RecycleElementAt(i);
}

View File

@@ -0,0 +1,25 @@
// Licensed to the .NET Fou// Copyright (c) DGP Studio. All rights reserved.
// Licensed under the MIT license.
using Microsoft.UI.Xaml;
using Windows.Foundation;
namespace Snap.Hutao.Control.Layout;
internal sealed class WrapItem
{
public WrapItem(int index)
{
Index = index;
}
public static Point EmptyPosition { get; } = new(float.NegativeInfinity, float.NegativeInfinity);
public int Index { get; }
public Size Size { get; set; } = Size.Empty;
public Point Position { get; set; } = EmptyPosition;
public UIElement? Element { get; set; }
}

View File

@@ -0,0 +1,220 @@
// Copyright (c) DGP Studio. All rights reserved.
// Licensed under the MIT license.
using Microsoft.UI.Xaml;
using Microsoft.UI.Xaml.Controls;
using System.Collections.Specialized;
using Windows.Foundation;
namespace Snap.Hutao.Control.Layout;
[DependencyProperty("HorizontalSpacing", typeof(double), 0D, nameof(LayoutPropertyChanged))]
[DependencyProperty("VerticalSpacing", typeof(double), 0D, nameof(LayoutPropertyChanged))]
internal sealed partial class WrapLayout : VirtualizingLayout
{
protected override void InitializeForContextCore(VirtualizingLayoutContext context)
{
context.LayoutState = new WrapLayoutState(context);
}
protected override void UninitializeForContextCore(VirtualizingLayoutContext context)
{
context.LayoutState = default;
}
protected override void OnItemsChangedCore(VirtualizingLayoutContext context, object source, NotifyCollectionChangedEventArgs args)
{
WrapLayoutState state = (WrapLayoutState)context.LayoutState;
switch (args.Action)
{
case NotifyCollectionChangedAction.Add:
state.RemoveFromIndex(args.NewStartingIndex);
break;
case NotifyCollectionChangedAction.Move:
int minIndex = Math.Min(args.NewStartingIndex, args.OldStartingIndex);
state.RemoveFromIndex(minIndex);
state.RecycleElementAt(args.OldStartingIndex);
state.RecycleElementAt(args.NewStartingIndex);
break;
case NotifyCollectionChangedAction.Remove:
state.RemoveFromIndex(args.OldStartingIndex);
break;
case NotifyCollectionChangedAction.Replace:
state.RemoveFromIndex(args.NewStartingIndex);
state.RecycleElementAt(args.NewStartingIndex);
break;
case NotifyCollectionChangedAction.Reset:
state.Clear();
break;
}
base.OnItemsChangedCore(context, source, args);
}
protected override Size MeasureOverride(VirtualizingLayoutContext context, Size availableSize)
{
if (context.ItemCount is 0)
{
return new Size(availableSize.Width, 0);
}
if ((context.RealizationRect.Width is 0) && (context.RealizationRect.Height is 0))
{
return new Size(availableSize.Width, 0.0f);
}
Size spacing = new(HorizontalSpacing, VerticalSpacing);
WrapLayoutState state = (WrapLayoutState)context.LayoutState;
if (spacing != state.Spacing || state.AvailableWidth != availableSize.Width)
{
state.ClearPositions();
state.Spacing = spacing;
state.AvailableWidth = availableSize.Width;
}
double currentHeight = 0;
Point itemPosition = default;
for (int i = 0; i < context.ItemCount; ++i)
{
bool itemMeasured = false;
WrapItem item = state.GetItemAt(i);
if (item.Size == Size.Empty)
{
item.Element = context.GetOrCreateElementAt(i);
item.Element.Measure(availableSize);
item.Size = item.Element.DesiredSize;
itemMeasured = true;
}
Size itemSize = item.Size;
if (item.Position == WrapItem.EmptyPosition)
{
if (availableSize.Width < itemPosition.X + itemSize.Width)
{
// New Row
itemPosition.X = 0;
itemPosition.Y += currentHeight + spacing.Height;
currentHeight = 0;
}
item.Position = itemPosition;
}
itemPosition = item.Position;
double bottom = itemPosition.Y + itemSize.Height;
if (bottom < context.RealizationRect.Top)
{
// Item is "above" the bounds
if (item.Element is not null)
{
context.RecycleElement(item.Element);
item.Element = default;
}
continue;
}
else if (itemPosition.Y > context.RealizationRect.Bottom)
{
// Item is "below" the bounds.
if (item.Element is not null)
{
context.RecycleElement(item.Element);
item.Element = default;
}
// We don't need to measure anything below the bounds
break;
}
else if (!itemMeasured)
{
// Always measure elements that are within the bounds
item.Element = context.GetOrCreateElementAt(i);
item.Element.Measure(availableSize);
itemSize = item.Element.DesiredSize;
if (itemSize != item.Size)
{
// this item changed size; we need to recalculate layout for everything after this
state.RemoveFromIndex(i + 1);
item.Size = itemSize;
// did the change make it go into the new row?
if (availableSize.Width < itemPosition.X + itemSize.Width)
{
// New Row
itemPosition.X = 0;
itemPosition.Y += currentHeight + spacing.Height;
currentHeight = 0;
}
item.Position = itemPosition;
}
}
itemPosition.X += itemSize.Width + spacing.Width;
currentHeight = Math.Max(itemSize.Height, currentHeight);
}
return new Size(double.IsInfinity(availableSize.Width) ? 0 : Math.Ceiling(availableSize.Width), state.GetHeight());
}
protected override Size ArrangeOverride(VirtualizingLayoutContext context, Size finalSize)
{
if (context.ItemCount > 0)
{
WrapLayoutState state = (WrapLayoutState)context.LayoutState;
for (int i = 0; i < context.ItemCount; ++i)
{
if (!ArrangeItem(context, state.GetItemAt(i)))
{
break;
}
}
}
return finalSize;
static bool ArrangeItem(VirtualizingLayoutContext context, WrapItem item)
{
if (item.Size == Size.Empty || item.Position == WrapItem.EmptyPosition)
{
return false;
}
Size size = item.Size;
Point position = item.Position;
if (context.RealizationRect.Top <= position.Y + size.Height && position.Y <= context.RealizationRect.Bottom)
{
// place the item
UIElement child = context.GetOrCreateElementAt(item.Index);
child.Arrange(new Rect(position, size));
}
else if (position.Y > context.RealizationRect.Bottom)
{
return false;
}
return true;
}
}
private static void LayoutPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
if (d is WrapLayout layout)
{
layout.InvalidateMeasure();
layout.InvalidateArrange();
}
}
}

View File

@@ -0,0 +1,109 @@
// Copyright (c) DGP Studio. All rights reserved.
// Licensed under the MIT license.
using Microsoft.UI.Xaml.Controls;
using System.Runtime.InteropServices;
using Windows.Foundation;
namespace Snap.Hutao.Control.Layout;
internal sealed class WrapLayoutState
{
private readonly List<WrapItem> items = [];
private readonly VirtualizingLayoutContext context;
public WrapLayoutState(VirtualizingLayoutContext context)
{
this.context = context;
}
public Orientation Orientation { get; private set; }
public Size Spacing { get; set; }
public double AvailableWidth { get; set; }
public WrapItem GetItemAt(int index)
{
ArgumentOutOfRangeException.ThrowIfNegative(index);
if (index <= (items.Count - 1))
{
return items[index];
}
else
{
WrapItem item = new(index);
items.Add(item);
return item;
}
}
public void Clear()
{
for (int i = 0; i < items.Count; i++)
{
RecycleElementAt(i);
}
items.Clear();
}
public void RemoveFromIndex(int index)
{
if (index >= items.Count)
{
// Item was added/removed but we haven't realized that far yet
return;
}
int numToRemove = items.Count - index;
items.RemoveRange(index, numToRemove);
}
public void ClearPositions()
{
foreach (ref readonly WrapItem item in CollectionsMarshal.AsSpan(items))
{
item.Position = WrapItem.EmptyPosition;
}
}
public double GetHeight()
{
if (items.Count is 0)
{
return 0;
}
Point? lastPosition = default;
double maxHeight = 0;
Span<WrapItem> itemSpan = CollectionsMarshal.AsSpan(items);
for (int i = items.Count - 1; i >= 0; --i)
{
ref readonly WrapItem item = ref itemSpan[i];
if (item.Position == WrapItem.EmptyPosition || item.Size == Size.Empty)
{
continue;
}
if (lastPosition is not null && lastPosition.Value.Y > item.Position.Y)
{
// This is a row above the last item.
break;
}
lastPosition = item.Position;
maxHeight = Math.Max(maxHeight, item.Size.Height);
}
return lastPosition?.Y + maxHeight ?? 0;
}
public void RecycleElementAt(int index)
{
context.RecycleElement(context.GetOrCreateElementAt(index));
}
}

View File

@@ -2,11 +2,13 @@
// Licensed under the MIT license.
using Microsoft.UI.Xaml;
using Microsoft.UI.Xaml.Markup;
namespace Snap.Hutao.Control;
[TemplateVisualState(Name = "LoadingIn", GroupName = "CommonStates")]
[TemplateVisualState(Name = "LoadingOut", GroupName = "CommonStates")]
[TemplatePart(Name = "ContentGrid", Type = typeof(FrameworkElement))]
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));
@@ -16,7 +18,7 @@ internal class Loading : Microsoft.UI.Xaml.Controls.ContentControl
public Loading()
{
DefaultStyleKey = typeof(Loading);
DefaultStyleResourceUri = new("ms-appx:///Control/Loading.xaml");
DefaultStyleResourceUri = "ms-appx:///Control/Loading.xaml".ToUri();
}
public bool IsLoading
@@ -35,9 +37,18 @@ internal class Loading : Microsoft.UI.Xaml.Controls.ContentControl
private static void IsLoadingPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
Loading control = (Loading)d;
control.presenter ??= control.GetTemplateChild("ContentGrid") as FrameworkElement;
control?.Update();
if ((bool)e.NewValue)
{
control.presenter ??= control.GetTemplateChild("ContentGrid") as FrameworkElement;
}
else if (control.presenter is not null)
{
XamlMarkupHelper.UnloadObject(control.presenter);
control.presenter = null;
}
control.Update();
}
private void Update()

View File

@@ -3,7 +3,9 @@
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:shc="using:Snap.Hutao.Control">
<Style TargetType="shc:Loading">
<Style BasedOn="{StaticResource DefaultLoadingStyle}" TargetType="shc:Loading"/>
<Style x:Key="DefaultLoadingStyle" TargetType="shc:Loading">
<Setter Property="HorizontalContentAlignment" Value="Center"/>
<Setter Property="VerticalContentAlignment" Value="Center"/>
<Setter Property="HorizontalAlignment" Value="Stretch"/>
@@ -21,7 +23,8 @@
<ContentPresenter
x:Name="ContentGrid"
HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}"
VerticalAlignment="{TemplateBinding VerticalContentAlignment}">
VerticalAlignment="{TemplateBinding VerticalContentAlignment}"
x:Load="True">
<ContentPresenter.RenderTransform>
<CompositeTransform/>
</ContentPresenter.RenderTransform>
@@ -82,4 +85,4 @@
</Setter>
</Style>
</ResourceDictionary>
</ResourceDictionary>

View File

@@ -18,12 +18,15 @@ internal sealed class FontIconExtension : MarkupExtension
/// </summary>
public string Glyph { get; set; } = default!;
public double FontSize { get; set; } = 12;
/// <inheritdoc/>
protected override object ProvideValue()
{
return new FontIcon()
{
Glyph = Glyph,
FontSize = FontSize,
};
}
}

View File

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

View File

@@ -33,6 +33,16 @@ internal struct Bgra32
/// </summary>
public byte A;
public Bgra32(byte b, byte g, byte r, byte a)
{
B = b;
G = g;
R = r;
A = a;
}
public readonly double Luminance { get => ((0.299 * R) + (0.587 * G) + (0.114 * B)) / 255; }
/// <summary>
/// 从 Color 转换
/// </summary>
@@ -44,4 +54,11 @@ internal struct Bgra32
*(uint*)&bgra8 = BinaryPrimitives.ReverseEndianness(*(uint*)&color);
return bgra8;
}
public static unsafe implicit operator Color(Bgra32 bgra8)
{
Unsafe.SkipInit(out Color color);
*(uint*)&color = BinaryPrimitives.ReverseEndianness(*(uint*)&bgra8);
return color;
}
}

View File

@@ -8,7 +8,7 @@ namespace Snap.Hutao.Control.Media;
/// <summary>
/// Defines a color in Hue/Saturation/Lightness (HSL) space.
/// </summary>
internal struct Hsl32
internal struct Hsla32
{
/// <summary>
/// The Hue in 0..360 range.

View File

@@ -8,51 +8,26 @@ using Windows.UI;
namespace Snap.Hutao.Control.Media;
/// <summary>
/// RGBA 颜色
/// </summary>
[HighQuality]
internal struct Rgba32
{
/// <summary>
/// R
/// </summary>
public byte R;
/// <summary>
/// G
/// </summary>
public byte G;
/// <summary>
/// B
/// </summary>
public byte B;
/// <summary>
/// A
/// </summary>
public byte A;
/// <summary>
/// 构造一个新的 RGBA8 颜色
/// </summary>
/// <param name="hex">色值字符串</param>
public Rgba32(string hex)
: this(hex.Length == 6 ? Convert.ToUInt32($"{hex}FF", 16) : Convert.ToUInt32(hex, 16))
{
}
/// <summary>
/// 使用 RGBA 代码初始化新的结构
/// </summary>
/// <param name="code">RGBA 代码</param>
public unsafe Rgba32(uint code)
public unsafe Rgba32(uint xrgbaCode)
{
// RRGGBBAA -> AABBGGRR
// uint layout: 0xRRGGBBAA is AABBGGRR
// AABBGGRR -> RRGGBBAA
fixed (Rgba32* pSelf = &this)
{
*(uint*)pSelf = BinaryPrimitives.ReverseEndianness(code);
*(uint*)pSelf = BinaryPrimitives.ReverseEndianness(xrgbaCode);
}
}
@@ -66,25 +41,20 @@ internal struct Rgba32
public static unsafe implicit operator Color(Rgba32 hexColor)
{
// AABBGGRR -> BBGGRRAA
// AABBGGRR -> 000000AA
uint a = (*(uint*)&hexColor) >> 24;
// Goal : Rgba32:RRGGBBAA(0xAABBGGRR) -> Color: AARRGGBB(0xBBGGRRAA)
// Step1: Rgba32:RRGGBBAA(0xAABBGGRR) -> UInt32:AA000000(0x000000AA)
uint a = ((*(uint*)&hexColor) >> 24) & 0x000000FF;
// AABBGGRR -> BBGGRR00
uint rgb = (*(uint*)&hexColor) << 8;
// Step2: Rgba32:RRGGBBAA(0xAABBGGRR) -> UInt32:00RRGGBB(0xRRGGBB00)
uint rgb = ((*(uint*)&hexColor) << 8) & 0xFFFFFF00;
// BBGGRR00 + 000000AA
// Step2: UInt32:00RRGGBB(0xRRGGBB00) + UInt32:AA000000(0x000000AA) -> UInt32:AARRGGBB(0xRRGGBBAA)
uint rgba = rgb + a;
return *(Color*)&rgba;
}
/// <summary>
/// 从 HSL 颜色转换
/// </summary>
/// <param name="hsl">HSL 颜色</param>
/// <returns>RGBA8颜色</returns>
public static Rgba32 FromHsl(Hsl32 hsl)
public static Rgba32 FromHsl(Hsla32 hsl)
{
double chroma = (1 - Math.Abs((2 * hsl.L) - 1)) * hsl.S;
double h1 = hsl.H / 60;
@@ -137,11 +107,7 @@ internal struct Rgba32
return new(r, g, b, a);
}
/// <summary>
/// 转换到 HSL 颜色
/// </summary>
/// <returns>HSL 颜色</returns>
public readonly Hsl32 ToHsl()
public readonly Hsla32 ToHsl()
{
const double toDouble = 1.0 / 255;
double r = toDouble * R;
@@ -174,7 +140,7 @@ internal struct Rgba32
double lightness = 0.5 * (max + min);
double saturation = chroma == 0 ? 0 : chroma / (1 - Math.Abs((2 * lightness) - 1));
Hsl32 ret;
Hsla32 ret;
ret.H = 60 * h1;
ret.S = saturation;
ret.L = lightness;

View File

@@ -0,0 +1,14 @@
// Copyright (c) DGP Studio. All rights reserved.
// Licensed under the MIT license.
// Some part of this file came from:
// https://github.com/xunkong/desktop/tree/main/src/Desktop/Desktop/Pages/CharacterInfoPage.xaml.cs
namespace Snap.Hutao.Control.Media;
internal struct Rgba64
{
public Half R;
public Half G;
public Half B;
public Half A;
}

View File

@@ -1,10 +1,9 @@
// Copyright (c) DGP Studio. All rights reserved.
// Licensed under the MIT license.
using Snap.Hutao.Win32.System.WinRT;
using Windows.Foundation;
using Windows.Graphics.Imaging;
using Windows.Win32;
using Windows.Win32.System.WinRT;
using WinRT;
namespace Snap.Hutao.Control.Media;
@@ -26,8 +25,7 @@ internal static class SoftwareBitmapExtension
{
using (IMemoryBufferReference reference = buffer.CreateReference())
{
reference.As<IMemoryBufferByteAccess>().GetBuffer(out byte* data, out uint length);
Span<Bgra32> bytes = new(data, unchecked((int)length / sizeof(Bgra32)));
reference.As<IMemoryBufferByteAccess>().GetBuffer(out Span<Bgra32> bytes);
foreach (ref Bgra32 pixel in bytes)
{
byte baseAlpha = pixel.A;
@@ -40,4 +38,25 @@ internal static class SoftwareBitmapExtension
}
}
}
public static unsafe Bgra32 GetAccentColor(this SoftwareBitmap softwareBitmap)
{
using (BitmapBuffer buffer = softwareBitmap.LockBuffer(BitmapBufferAccessMode.Read))
{
using (IMemoryBufferReference reference = buffer.CreateReference())
{
reference.As<IMemoryBufferByteAccess>().GetBuffer(out Span<Bgra32> bytes);
double b = 0, g = 0, r = 0, a = 0;
foreach (ref readonly Bgra32 pixel in bytes)
{
b += pixel.B;
g += pixel.G;
r += pixel.R;
a += pixel.A;
}
return new((byte)(b / bytes.Length), (byte)(g / bytes.Length), (byte)(r / bytes.Length), (byte)(a / bytes.Length));
}
}
}
}

View File

@@ -0,0 +1,89 @@
// Copyright (c) DGP Studio. All rights reserved.
// Licensed under the MIT license.
using Microsoft.UI.Xaml;
using System.Data;
using System.Runtime.InteropServices;
using Windows.Foundation;
namespace Snap.Hutao.Control.Panel;
[DependencyProperty("Spacing", typeof(double), default(double), nameof(OnSpacingChanged))]
internal partial class EqualPanel : Microsoft.UI.Xaml.Controls.Panel
{
private double maxItemWidth;
private double maxItemHeight;
private int visibleItemsCount;
public EqualPanel()
{
RegisterPropertyChangedCallback(HorizontalAlignmentProperty, OnHorizontalAlignmentChanged);
}
protected override Size MeasureOverride(Size availableSize)
{
maxItemWidth = 0;
maxItemHeight = 0;
List<UIElement> elements = [.. Children.Where(element => element.Visibility == Visibility.Visible)];
visibleItemsCount = elements.Count;
foreach (ref readonly UIElement child in CollectionsMarshal.AsSpan(elements))
{
child.Measure(availableSize);
maxItemWidth = Math.Max(maxItemWidth, child.DesiredSize.Width);
maxItemHeight = Math.Max(maxItemHeight, child.DesiredSize.Height);
}
if (visibleItemsCount > 0)
{
// Return equal widths based on the widest item
// In very specific edge cases the AvailableWidth might be infinite resulting in a crash.
if (HorizontalAlignment is not HorizontalAlignment.Stretch || double.IsInfinity(availableSize.Width))
{
return new Size((maxItemWidth * visibleItemsCount) + (Spacing * (visibleItemsCount - 1)), maxItemHeight);
}
else
{
// Equal columns based on the available width, adjust for spacing
double totalWidth = availableSize.Width - (Spacing * (visibleItemsCount - 1));
maxItemWidth = totalWidth / visibleItemsCount;
return new Size(availableSize.Width, maxItemHeight);
}
}
else
{
return new Size(0, 0);
}
}
protected override Size ArrangeOverride(Size finalSize)
{
double x = 0;
// Check if there's more (little) width available - if so, set max item width to the maximum possible as we have an almost perfect height.
if (finalSize.Width > (visibleItemsCount * maxItemWidth) + (Spacing * (visibleItemsCount - 1)))
{
maxItemWidth = (finalSize.Width - (Spacing * (visibleItemsCount - 1))) / visibleItemsCount;
}
IEnumerable<UIElement> elements = Children.Where(static e => e.Visibility == Visibility.Visible);
foreach (UIElement child in elements)
{
child.Arrange(new Rect(x, 0, maxItemWidth, maxItemHeight));
x += maxItemWidth + Spacing;
}
return finalSize;
}
private static void OnSpacingChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
(d as EqualPanel)?.InvalidateMeasure();
}
private static void OnHorizontalAlignmentChanged(DependencyObject d, DependencyProperty dp)
{
(d as EqualPanel)?.InvalidateMeasure();
}
}

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