Compare commits

..

641 Commits

Author SHA1 Message Date
bggRGjQaUbCoE
bc8907b3ef mod: show lv6_s
Closes #687

Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
2025-04-15 18:18:53 +08:00
bggRGjQaUbCoE
14f8ec37c5 opt: dyn tab
opt: reload

Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
2025-04-15 16:19:51 +08:00
bggRGjQaUbCoE
2b567e7cb3 fix: set pageTransition
Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
2025-04-15 13:46:46 +08:00
bggRGjQaUbCoE
b58a3ec044 Revert "mod: show hot label"
This reverts commit 2d0d578bb4.
2025-04-15 13:32:47 +08:00
bggRGjQaUbCoE
2d0d578bb4 mod: show hot label
Closes #683

Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
2025-04-15 13:11:47 +08:00
bggRGjQaUbCoE
54ba05c4aa Revert "opt: video cover"
This reverts commit 7cc0c83df1.
2025-04-15 13:09:46 +08:00
bggRGjQaUbCoE
27b251b06e opt: member page
Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
2025-04-15 11:48:09 +08:00
bggRGjQaUbCoE
5643ebfe48 feat: custom page transition
Closes #682

Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
2025-04-15 11:48:09 +08:00
bggRGjQaUbCoE
d9c2f6bf91 revert: dm color panel
Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
2025-04-15 11:18:47 +08:00
bggRGjQaUbCoE
3eb404a9e2 opt: search trending page
Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
2025-04-15 11:18:41 +08:00
bggRGjQaUbCoE
bc9c20c509 feat: search trending page
Closes #684

Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
2025-04-14 23:43:47 +08:00
bggRGjQaUbCoE
7cc0c83df1 opt: video cover
Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
2025-04-14 23:35:22 +08:00
bggRGjQaUbCoE
41daefa6c4 fix: MsgType.share_v2
Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
2025-04-14 18:04:02 +08:00
bggRGjQaUbCoE
38fa8a10b7 opt: emote panel
Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
2025-04-14 15:41:41 +08:00
bggRGjQaUbCoE
07d37a1209 feat: search trending
Closes #678

Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
2025-04-14 15:25:45 +08:00
bggRGjQaUbCoE
509f0d1266 fix: #680
Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
2025-04-14 15:25:45 +08:00
bggRGjQaUbCoE
7966bab62d opt: episode panel
Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
2025-04-14 13:17:04 +08:00
bggRGjQaUbCoE
a136c150ad opt: download dialog
Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
2025-04-14 11:16:56 +08:00
bggRGjQaUbCoE
a89fe6b026 mod: remove add live dm
Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
2025-04-14 11:01:49 +08:00
bggRGjQaUbCoE
56460c937d mod: send vip colorful dm
Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
2025-04-14 10:48:40 +08:00
bggRGjQaUbCoE
f2080bfb7b opt: view later from dyn
Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
2025-04-13 21:41:48 +08:00
bggRGjQaUbCoE
012d55452e opt: timeline tabbar
Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
2025-04-13 21:19:26 +08:00
bggRGjQaUbCoE
6ac482ed5e opt: pgc timeline
Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
2025-04-13 21:08:22 +08:00
bggRGjQaUbCoE
68df173558 feat: pgc timeline
Closes #653

Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
2025-04-13 20:38:24 +08:00
bggRGjQaUbCoE
d9c6c31a4d mod: remove refresh fav folder
Closes #675

Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
2025-04-13 17:18:26 +08:00
bggRGjQaUbCoE
d3d2715418 opt: add live emoticonUnique
Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
2025-04-13 15:36:30 +08:00
bggRGjQaUbCoE
a93fbd4444 opt: live send dm panel
Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
2025-04-13 15:01:26 +08:00
bggRGjQaUbCoE
9fee9a4cf1 Update README.md
Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
2025-04-13 14:49:31 +08:00
bggRGjQaUbCoE
4bbc008788 Update README.md
Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
2025-04-13 14:44:35 +08:00
bggRGjQaUbCoE
671b6e1ef7 feat: send live emote
Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
2025-04-13 14:40:19 +08:00
bggRGjQaUbCoE
634bae915a mod: save dm config
Closes #673

Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
2025-04-13 11:22:41 +08:00
bggRGjQaUbCoE
a7bbfc983e mod: show pgc renewalTime
Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
2025-04-12 21:38:13 +08:00
bggRGjQaUbCoE
17548e935e mod: show pgc renewalTime
Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
2025-04-12 21:26:50 +08:00
bggRGjQaUbCoE
15f84712cd fix: parse reply
Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
2025-04-12 20:53:59 +08:00
bggRGjQaUbCoE
2f34ae7d45 opt: show video fav menu
Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
2025-04-12 20:17:33 +08:00
bggRGjQaUbCoE
16cbe7e43c fix: query reply
Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
2025-04-12 20:12:34 +08:00
bggRGjQaUbCoE
8d633377ae feat: sort fav folder
Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
2025-04-12 18:52:29 +08:00
bggRGjQaUbCoE
0b867c254f fix: log date
Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
2025-04-12 17:00:08 +08:00
bggRGjQaUbCoE
08a47e6c1d mod: clear outdated logs
Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
2025-04-12 16:42:35 +08:00
bggRGjQaUbCoE
6c9cd8b120 fix: play all later
Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
2025-04-12 16:23:02 +08:00
bggRGjQaUbCoE
71e7219084 mod: enable autoClearCache by def
Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
2025-04-12 15:55:09 +08:00
bggRGjQaUbCoE
c13063b230 opt: FavVideoCardH
Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
2025-04-12 15:50:16 +08:00
bggRGjQaUbCoE
26ca69cb83 opt: view later tabbar
Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
2025-04-12 15:36:53 +08:00
bggRGjQaUbCoE
afc8c5f873 refa: later view page
Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
2025-04-12 15:06:44 +08:00
bggRGjQaUbCoE
4d3f739a0c mod: disable preload reply
Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
2025-04-12 09:40:29 +08:00
bggRGjQaUbCoE
1781fdb7ca fix: search arc
Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
2025-04-12 09:24:33 +08:00
bggRGjQaUbCoE
32aa37505c Update README.md
Closes #669

Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
2025-04-12 09:24:33 +08:00
bggRGjQaUbCoE
9f9ed7dd4b fix: #668
Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
2025-04-12 00:11:51 +08:00
bggRGjQaUbCoE
03e3b897cf opt: check coin
Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
2025-04-11 21:49:43 +08:00
bggRGjQaUbCoE
3bc20ce1d4 opt: DynamicCardSkeleton
Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
2025-04-11 21:44:25 +08:00
bggRGjQaUbCoE
9ce9940306 mod: specify list type
Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
2025-04-11 21:35:47 +08:00
bggRGjQaUbCoE
da35cf471e Revert "opt: DynamicCardSkeleton"
This reverts commit 3a52c1199c.
2025-04-11 20:54:53 +08:00
bggRGjQaUbCoE
c517df2c09 opt: keep member search page
fix: search arc

Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
2025-04-11 20:52:16 +08:00
My-Responsitories
02dee71670 mod: use cached coin (#667) 2025-04-11 12:15:09 +00:00
bggRGjQaUbCoE
1eadcd41f6 fix: live follow list
Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
2025-04-11 18:42:57 +08:00
bggRGjQaUbCoE
e8185535b0 opt: coin pic
Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
2025-04-11 18:20:19 +08:00
bggRGjQaUbCoE
b68bebfa2e fix: #665
Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
2025-04-11 17:56:34 +08:00
bggRGjQaUbCoE
3801bdf9d7 feat: get/check coin
Closes #661

Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
2025-04-11 17:28:58 +08:00
bggRGjQaUbCoE
9a6ba82467 fix: save panel: pgc uri
Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
2025-04-11 13:01:16 +08:00
bggRGjQaUbCoE
3a52c1199c opt: DynamicCardSkeleton
Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
2025-04-11 12:25:47 +08:00
bggRGjQaUbCoE
ea5c0584cc fix: footer
Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
2025-04-11 11:06:23 +08:00
bggRGjQaUbCoE
01b30d942b fix: state
Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
2025-04-11 10:53:59 +08:00
My-Responsitories
5aa5308a50 feat: relative slide (#662) 2025-04-11 01:57:22 +00:00
allllllllllla
de029b7043 Adapt to 16:10 tablet (#660)
* Update view.dart

* Update view_v.dart
2025-04-11 00:18:24 +08:00
bggRGjQaUbCoE
a45da453ce Revert "mod: revert success"
This reverts commit 68f03f2311.
2025-04-10 22:14:11 +08:00
dom
e1b73f4766 refa: query data (#659)
Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
2025-04-10 21:43:01 +08:00
bggRGjQaUbCoE
99b19e7b03 opt: anim save panel
Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
2025-04-10 21:15:41 +08:00
bggRGjQaUbCoE
37bd849a86 fix: #658
Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
2025-04-10 20:41:19 +08:00
bggRGjQaUbCoE
4eb6f78a38 opt: reply item
Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
2025-04-10 14:19:38 +08:00
bggRGjQaUbCoE
68f03f2311 mod: revert success
Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
2025-04-10 14:18:20 +08:00
My-Responsitories
2a60a9b393 mod: save panel use absolute time (#657) 2025-04-10 04:34:40 +00:00
My-Responsitories
1d4b08672b fix: init before speed test 2025-04-10 12:27:22 +08:00
bggRGjQaUbCoE
b0d9a1dada fix: #656
Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
2025-04-10 11:23:43 +08:00
bggRGjQaUbCoE
796494e53f mod: replace stream
Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
2025-04-10 09:38:33 +08:00
bggRGjQaUbCoE
cef7bfd534 opt: query data
fix: webdav backup

Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
2025-04-10 00:08:19 +08:00
bggRGjQaUbCoE
36ff4a0ed3 Revert "mod: tweak for xiaomi"
This reverts commit 44fa2a8c3e.
2025-04-09 20:19:39 +08:00
bggRGjQaUbCoE
6a6894030b fix: save reply type
Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
2025-04-09 18:39:19 +08:00
bggRGjQaUbCoE
497d31ddf7 opt: nav stream
Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
2025-04-09 18:22:09 +08:00
bggRGjQaUbCoE
783218429c opt: nav/searchbar stream
Closes #648

Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
2025-04-09 18:04:27 +08:00
bggRGjQaUbCoE
0ccd15047b opt: bottom sheet
Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
2025-04-09 17:06:35 +08:00
bggRGjQaUbCoE
fe2a6ec006 opt: more panel
Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
2025-04-09 15:39:39 +08:00
bggRGjQaUbCoE
a3ecf59fae opt: medialist page
Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
2025-04-09 15:24:47 +08:00
bggRGjQaUbCoE
4f4f89a1d7 opt: reply header
Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
2025-04-09 14:42:38 +08:00
bggRGjQaUbCoE
ece3bdd2e8 opt: reply page
Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
2025-04-09 14:30:08 +08:00
bggRGjQaUbCoE
f403ed1a21 opt: webdav
Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
2025-04-09 14:04:53 +08:00
bggRGjQaUbCoE
17e3a0206a opt: video play
Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
2025-04-09 13:30:52 +08:00
My-Responsitories
5da86d85de fix: memberArchive challenge (#646) 2025-04-09 05:20:39 +00:00
My-Responsitories
d3cbc95235 feat: scroll spring in history & fav (#645) 2025-04-09 05:16:29 +00:00
bggRGjQaUbCoE
a7eebcc209 opt: showEpisodes
Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
2025-04-09 12:28:02 +08:00
bggRGjQaUbCoE
fca22eb592 opt: slide padding
Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
2025-04-09 12:27:56 +08:00
bggRGjQaUbCoE
1202e5ec0f opt: search dyn
Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
2025-04-09 11:50:06 +08:00
bggRGjQaUbCoE
03830533eb opt: pages
Closes #644

Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
2025-04-09 00:28:44 +08:00
bggRGjQaUbCoE
850e5a199e fix: slide padding
Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
2025-04-08 22:33:04 +08:00
bggRGjQaUbCoE
2d11158ecd refa: search dyn
Closes #641

Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
2025-04-08 22:09:47 +08:00
bggRGjQaUbCoE
a34c18b262 feat: webdav
Closes #432

Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
2025-04-08 20:59:21 +08:00
bggRGjQaUbCoE
560b1e40cc fix: #639
Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
2025-04-08 19:09:34 +08:00
My-Responsitories
3cd512857c mod: dyn search (#638) 2025-04-08 08:38:05 +00:00
bggRGjQaUbCoE
356adbef5c opt: reply ctr tag
Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
2025-04-08 11:26:11 +08:00
bggRGjQaUbCoE
42d7445d83 opt: skip segment
Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
2025-04-08 10:50:01 +08:00
bggRGjQaUbCoE
3a0f32fce7 chore: update dm dep
Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
2025-04-08 00:22:26 +08:00
bggRGjQaUbCoE
6bc128cfda opt: save reply
Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
2025-04-07 22:49:04 +08:00
bggRGjQaUbCoE
6f2d697748 opt: query sponsor block
Closes #633

Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
2025-04-07 22:32:26 +08:00
bggRGjQaUbCoE
4de180c23a opt: save panel
Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
2025-04-07 22:22:10 +08:00
My-Responsitories
af289c533f some modifitions (#636)
* opt: MsgUnReadTypeV2

* mod: recoard history in anonymity mode
2025-04-07 13:19:24 +00:00
bggRGjQaUbCoE
82d615fbbf feat: save dyn
Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
2025-04-07 17:52:04 +08:00
dom
457f2ea6c7 Update bug-反馈.yml 2025-04-07 14:04:57 +08:00
bggRGjQaUbCoE
41ad5c45ed fix: #634
Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
2025-04-07 14:04:14 +08:00
bggRGjQaUbCoE
e9da2e8d6b opt: save reply page
Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
2025-04-07 13:48:32 +08:00
bggRGjQaUbCoE
a8cfbb12fd fix: block page state
Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
2025-04-07 13:39:57 +08:00
bggRGjQaUbCoE
6d89b7769e chore: rename imageview
Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
2025-04-07 12:40:48 +08:00
bggRGjQaUbCoE
2d86daec83 fix: #630
Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
2025-04-07 12:39:01 +08:00
bggRGjQaUbCoE
a5e8594611 feat: del msg feed
opt: msg feed

Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
2025-04-07 12:24:14 +08:00
bggRGjQaUbCoE
99810ef512 fix: dyn pubtime
Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
2025-04-07 11:30:56 +08:00
bggRGjQaUbCoE
2317b831db opt: save reply
Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
2025-04-07 11:22:44 +08:00
bggRGjQaUbCoE
e073086cf4 opt: reply item
Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
2025-04-07 10:09:34 +08:00
bggRGjQaUbCoE
b14844f459 fix: save reply
Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
2025-04-07 09:50:19 +08:00
dom
8719c8f639 feat: save reply (#629)
Closes #614

opt: more panel

Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
2025-04-07 09:22:33 +08:00
My-Responsitories
d3cec0ec72 fix #624 (#625) 2025-04-07 09:17:19 +08:00
bggRGjQaUbCoE
a8daf02610 opt: video sheet
Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
2025-04-06 15:49:40 +08:00
bggRGjQaUbCoE
f9b844fb1a mod: open link verify settings btn
Closes #622

Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
2025-04-06 12:12:17 +08:00
bggRGjQaUbCoE
6d1d6b575a opt: send dm
Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
2025-04-06 11:35:04 +08:00
bggRGjQaUbCoE
0a5a094e54 chore: update dm dep
Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
2025-04-06 11:28:05 +08:00
bggRGjQaUbCoE
754da4777a opt: live: send danmaku
Closes #618

Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
2025-04-06 11:22:19 +08:00
bggRGjQaUbCoE
216e3e606e mod: live: double tap
Closes #619

Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
2025-04-06 10:52:05 +08:00
bggRGjQaUbCoE
bb013a8fe6 mod: hide special dm by def
Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
2025-04-05 20:48:50 +08:00
bggRGjQaUbCoE
6b6449f023 mod: article: get user mid
Closes #615

Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
2025-04-05 20:28:56 +08:00
bggRGjQaUbCoE
fcf3348371 fix: add special dm
Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
2025-04-05 20:28:44 +08:00
bggRGjQaUbCoE
f90f759667 opt: jump to reply
Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
2025-04-05 16:42:34 +08:00
bggRGjQaUbCoE
b02e6c04b9 feat: special danmaku by @My-Responsitories
Closes #91
Closes #219
Closes #394
Closes #602
Closes #613

Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
2025-04-05 16:32:30 +08:00
bggRGjQaUbCoE
08dc04f874 opt: show dyn blocked item
Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
2025-04-05 14:11:01 +08:00
bggRGjQaUbCoE
4776b84c7c mod: sys msg: push dyn
Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
2025-04-05 14:10:52 +08:00
bggRGjQaUbCoE
78d13b586a fix: sys msg: push video
Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
2025-04-05 11:49:50 +08:00
bggRGjQaUbCoE
f522ecd42d chore: remove unused pack
Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
2025-04-05 11:18:15 +08:00
bggRGjQaUbCoE
44fa2a8c3e mod: tweak for xiaomi
Closes #608

Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
2025-04-05 11:18:02 +08:00
bggRGjQaUbCoE
ff30c8c2bf opt: push dyn
Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
2025-04-05 10:54:09 +08:00
bggRGjQaUbCoE
4aaaffbcea fix: dyn comment type
Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
2025-04-04 23:40:11 +08:00
bggRGjQaUbCoE
21da122902 opt: push opus
Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
2025-04-04 23:22:33 +08:00
bggRGjQaUbCoE
849904ad45 revert: push opus
Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
2025-04-04 23:16:42 +08:00
bggRGjQaUbCoE
1c0bae600f mod: add nav/search debounce option
Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
2025-04-04 21:53:30 +08:00
bggRGjQaUbCoE
f1433c6e9b mod: show reply rootText
Closes #605

Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
2025-04-04 21:17:22 +08:00
bggRGjQaUbCoE
2dc106adcb fix: reply error widget
Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
2025-04-04 20:56:37 +08:00
bggRGjQaUbCoE
df6738f607 mod: remove webview msg btn
Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
2025-04-04 18:44:26 +08:00
bggRGjQaUbCoE
ee64f1e7f1 mod: note: check login
Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
2025-04-04 18:39:36 +08:00
bggRGjQaUbCoE
d921f6176b opt: get cacheSize
Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
2025-04-04 18:31:19 +08:00
bggRGjQaUbCoE
7009c3400a mod: remove ios ua
Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
2025-04-04 18:22:47 +08:00
bggRGjQaUbCoE
7bd481b090 fix: ios message webview
Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
2025-04-04 18:00:14 +08:00
bggRGjQaUbCoE
7fafa88eb7 opt: load previous
Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
2025-04-04 17:53:11 +08:00
bggRGjQaUbCoE
cb3e57feec fix: load previous
Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
2025-04-04 16:04:59 +08:00
bggRGjQaUbCoE
9a7d73cb6b opt: load previous data
Closes #597

Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
2025-04-04 15:26:27 +08:00
bggRGjQaUbCoE
f5c2bd47d5 fix: fav: play all
Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
2025-04-04 12:14:55 +08:00
bggRGjQaUbCoE
c154d25f7a opt: episode item
Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
2025-04-04 12:03:22 +08:00
bggRGjQaUbCoE
8c259205f5 feat: record search history option
Closes #592

Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
2025-04-04 12:00:13 +08:00
bggRGjQaUbCoE
849329b66b opt: bottomnav/searchbar stream debounce
Closes #590

Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
2025-04-04 11:26:53 +08:00
bggRGjQaUbCoE
f542565dc5 mod: filter advanced dm
Closes #602

Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
2025-04-04 10:59:57 +08:00
bggRGjQaUbCoE
08aedbf0b0 feat: custom for/backward duration
Closes #366
Closes #601

Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
2025-04-04 10:43:03 +08:00
bggRGjQaUbCoE
09c8a41c52 feat: drag subtitle
Closes #588

Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
2025-04-03 20:04:56 +08:00
bggRGjQaUbCoE
6a7d14a3f8 fix: view reply
Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
2025-04-03 18:04:41 +08:00
bggRGjQaUbCoE
5b171ec044 Update README.md
Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
2025-04-03 15:23:09 +08:00
bggRGjQaUbCoE
978d634cb3 feat: set top reply
Closes #589

Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
2025-04-03 14:50:42 +08:00
bggRGjQaUbCoE
7437d8c592 feat: manual check dyn
Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
2025-04-03 13:18:24 +08:00
My-Responsitories
e190ca5868 mod: account (#591)
* fix: onLoginMain

* fix: account override

* opt: sponsor block url
2025-04-03 04:18:30 +00:00
bggRGjQaUbCoE
64fc995f6b fix: report video
Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
2025-04-03 12:02:25 +08:00
bggRGjQaUbCoE
2d0e801a1a opt: override note title
Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
2025-04-02 22:21:18 +08:00
bggRGjQaUbCoE
d409424871 opt: webview: add note
Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
2025-04-02 22:06:17 +08:00
bggRGjQaUbCoE
b855ef9865 mod: webview: intercept refresh url
Closes #587

Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
2025-04-02 21:25:39 +08:00
bggRGjQaUbCoE
86abf006d0 mod: live schedule
Closes #581

Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
2025-04-02 20:47:11 +08:00
My-Responsitories
d1a6798f2e fix: wbiSign 2025-04-02 18:52:13 +08:00
bggRGjQaUbCoE
f64d543ec7 mod: show live media notification
Closes #584

Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
2025-04-02 17:34:17 +08:00
bggRGjQaUbCoE
2abf01362c opt: medialist page
Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
2025-04-02 16:37:01 +08:00
bggRGjQaUbCoE
9bbd934f8e fix: episode panel
Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
2025-04-02 15:52:29 +08:00
bggRGjQaUbCoE
6ab72b65aa fix: video gesture
Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
2025-04-02 15:12:24 +08:00
bggRGjQaUbCoE
c39de1e245 opt: download img
Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
2025-04-02 15:05:14 +08:00
bggRGjQaUbCoE
d112843a8a fix: mid
Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
2025-04-02 13:59:52 +08:00
bggRGjQaUbCoE
89df091542 opt: video gesture
Closes #586

Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
2025-04-02 12:42:00 +08:00
bggRGjQaUbCoE
d870c36a96 mod: custom slide fs
Closes #585

Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
2025-04-02 12:33:31 +08:00
bggRGjQaUbCoE
fc55bf33d0 fix: episode cid
Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
2025-04-02 12:33:11 +08:00
bggRGjQaUbCoE
f99740ef2d refa: list sheet
Closes #369

Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
2025-04-01 23:53:32 +08:00
bggRGjQaUbCoE
f9f30a5f13 mod: tweak
Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
2025-04-01 17:19:35 +08:00
bggRGjQaUbCoE
f70cf05870 opt: member page
Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
2025-04-01 16:22:27 +08:00
bggRGjQaUbCoE
22866012ca mod: remove unused pack
Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
2025-04-01 14:06:02 +08:00
bggRGjQaUbCoE
cdb2718aeb chore: deprecate prev reply, videopage
Closes #579

Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
2025-04-01 12:48:59 +08:00
bggRGjQaUbCoE
e4f3203351 opt: show pubTs
Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
2025-03-31 21:41:15 +08:00
bggRGjQaUbCoE
d6b388ad5c opt: duration
Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
2025-03-31 18:20:50 +08:00
bggRGjQaUbCoE
61819d9f27 opt: image preview
Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
2025-03-31 17:53:35 +08:00
bggRGjQaUbCoE
3ccc7ef69d fix: bangumi mid
Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
2025-03-31 17:37:42 +08:00
bggRGjQaUbCoE
e834311664 mod: set buffer value
Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
2025-03-31 17:37:42 +08:00
bggRGjQaUbCoE
fd8dff327c fix: view staff from intro
Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
2025-03-31 16:44:41 +08:00
bggRGjQaUbCoE
a9df8cd883 opt: push following detail
Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
2025-03-31 16:38:58 +08:00
bggRGjQaUbCoE
909394965e fix: push bilibili://following/detail
Closes #576

Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
2025-03-31 16:29:49 +08:00
bggRGjQaUbCoE
2d5991e0c5 opt: query history
Closes #578

Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
2025-03-31 16:02:49 +08:00
bggRGjQaUbCoE
e7ae66a3dc fix: push bilibili://comment/msg_fold
Closes #576

Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
2025-03-31 15:34:11 +08:00
bggRGjQaUbCoE
5929150047 fix: push bilibili://following/detail
related #576

Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
2025-03-31 14:54:53 +08:00
bggRGjQaUbCoE
acb6bc569e opt: btn
Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
2025-03-31 14:54:53 +08:00
bggRGjQaUbCoE
678db34c81 opt: member page
Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
2025-03-30 21:32:36 +08:00
bggRGjQaUbCoE
134bfd43ff opt: video: charged badge
Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
2025-03-30 21:14:07 +08:00
bggRGjQaUbCoE
8712248ef2 opt: member video card
Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
2025-03-30 21:00:37 +08:00
bggRGjQaUbCoE
c97227e807 opt: hmember page 2025-03-30 20:24:32 +08:00
bggRGjQaUbCoE
40429021be feat: locate last viewed video
Closes #453

Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
2025-03-30 19:54:57 +08:00
bggRGjQaUbCoE
e89bd2fedf opt: member prInfo
Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
2025-03-30 17:16:10 +08:00
bggRGjQaUbCoE
9da3a538fb refa: horizontal member page
Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
2025-03-30 16:20:40 +08:00
bggRGjQaUbCoE
a904414f3d mod: prinfo
Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
2025-03-30 13:47:59 +08:00
bggRGjQaUbCoE
f003e8bf35 mod: member card: show prInfo
Closes #571

Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
2025-03-30 12:17:54 +08:00
bggRGjQaUbCoE
7399915357 mod: later: show progress
Closes #569

Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
2025-03-30 11:31:46 +08:00
My-Responsitories
7aa0289c1f fix: audioNormalization 2025-03-29 23:51:32 +08:00
bggRGjQaUbCoE
99d0b1c468 mod: btn to view all fav pgc
Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
2025-03-29 21:03:19 +08:00
bggRGjQaUbCoE
84a342a0e0 mod: enable retry by def
Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
2025-03-29 20:39:20 +08:00
bggRGjQaUbCoE
db1c836a3e opt: share/save video cover
Closes #563

Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
2025-03-29 20:39:20 +08:00
My-Responsitories
6539457f83 fix: select group sheet 2025-03-29 20:30:19 +08:00
My-Responsitories
82f9f48a8e opt: select dialog & feat: select subtitle if muted (#564)
* opt: select dialog

* opt: subtitle

* feat: select subtitle if muted
2025-03-29 09:52:06 +00:00
bggRGjQaUbCoE
2ddfea5cf3 fix: webview params
Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
2025-03-29 15:37:19 +08:00
bggRGjQaUbCoE
79aee2fdd9 opt: view note
Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
2025-03-29 15:13:11 +08:00
bggRGjQaUbCoE
5dc8b8e54f feat: fav article page
Closes #402

Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
2025-03-29 14:41:13 +08:00
bggRGjQaUbCoE
72fa9c51f0 feat: fav pgc page
Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
2025-03-29 13:45:14 +08:00
bggRGjQaUbCoE
6ea8ffea7a opt: note
Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
2025-03-29 11:24:39 +08:00
bggRGjQaUbCoE
eea5257da2 fix: only play audio
related #558

Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
2025-03-29 10:05:43 +08:00
bggRGjQaUbCoE
385cffefb8 fix(dep): downgrade media-kit
Closes #543
Closes #546
Closes #551
Closes #558

Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
2025-03-29 10:00:30 +08:00
bggRGjQaUbCoE
347420c531 feat: del note
Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
2025-03-29 09:53:02 +08:00
bggRGjQaUbCoE
cc774015f9 feat: fav note page
Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
2025-03-28 22:35:38 +08:00
bggRGjQaUbCoE
da3f64feab refa: fav page [wip]
Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
2025-03-28 18:38:31 +08:00
My-Responsitories
76d031e8d1 feat: parallel upload & download image (#556)
* feat: parallel upload file

* feat: parallel download file
2025-03-28 10:30:15 +00:00
bggRGjQaUbCoE
25995b0ed6 fix: #555
Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
2025-03-28 17:46:45 +08:00
bggRGjQaUbCoE
3cdd40a710 feat: create note
related #554

Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
2025-03-28 17:32:27 +08:00
bggRGjQaUbCoE
f36f8d69fc refa: subtitle
Closes #553

Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
2025-03-28 16:13:21 +08:00
bggRGjQaUbCoE
5655e6ccdf opt: article report
Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
2025-03-28 11:06:00 +08:00
bggRGjQaUbCoE
49fff821b1 feat: live/article report
Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
2025-03-28 10:57:54 +08:00
bggRGjQaUbCoE
3b34cecdcd mod: set pos
Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
2025-03-28 10:09:11 +08:00
My-Responsitories
3693d6c350 change status api (#552) 2025-03-28 01:57:50 +00:00
bggRGjQaUbCoE
54cb1a6fc0 fix: #547
Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
2025-03-27 21:54:45 +08:00
bggRGjQaUbCoE
ab7b1524b6 opt: show dm
Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
2025-03-27 21:18:17 +08:00
bggRGjQaUbCoE
2b4a27076c fix: #344
Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
2025-03-27 20:59:35 +08:00
bggRGjQaUbCoE
63a7fa95f5 fix: pip aspectRatio
related #543

Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
2025-03-27 20:44:18 +08:00
bggRGjQaUbCoE
a15b932a69 opt: query dm
Closes #544

Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
2025-03-27 20:03:41 +08:00
bggRGjQaUbCoE
3a6b6614a4 opt: video tool bar
Closes #528

Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
2025-03-27 15:43:11 +08:00
bggRGjQaUbCoE
6ff83e34f3 opt: sort fav
Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
2025-03-27 14:47:40 +08:00
bggRGjQaUbCoE
e4cadc5a40 chore: update dep
Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
2025-03-27 13:50:33 +08:00
bggRGjQaUbCoE
907d37dd4c mod: whisper: show article_card
ref orz12/main

Closes #540

Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
2025-03-27 11:10:40 +08:00
bggRGjQaUbCoE
00d30313af opt: video widget
Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
2025-03-27 10:59:16 +08:00
bggRGjQaUbCoE
950dd82e3c fix: sort fav
Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
2025-03-26 23:40:03 +08:00
bggRGjQaUbCoE
c53c3a387c fix: #539
Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
2025-03-26 23:32:57 +08:00
bggRGjQaUbCoE
5d0b2dc8e3 feat: custom app font weight
Closes #533

Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
2025-03-26 21:42:57 +08:00
bggRGjQaUbCoE
f5e9375917 mod: update qa when switching
Closes #437

Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
2025-03-26 20:40:38 +08:00
bggRGjQaUbCoE
cdfab7a7db chore: update dep
Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
2025-03-26 19:02:24 +08:00
bggRGjQaUbCoE
f3e6a59e4f chore: upgrade deps
Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
2025-03-26 17:21:41 +08:00
bggRGjQaUbCoE
239c9ca2a7 mod: top or refresh debounce
Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
2025-03-26 16:39:52 +08:00
bggRGjQaUbCoE
becb566ca8 feat: sort fav
Closes #530

Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
2025-03-26 16:21:28 +08:00
bggRGjQaUbCoE
aa378d924b opt: post segments
Closes #531

Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
2025-03-26 12:10:55 +08:00
bggRGjQaUbCoE
812f351ddd opt: intro: queryUserStat
Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
2025-03-26 12:10:55 +08:00
My-Responsitories
b9adf26ee0 opt: model & feat: filter play (#529)
* opt: model

* opt: model

* feat: filter play
2025-03-25 14:45:30 +00:00
bggRGjQaUbCoE
018cd058ca opt: set playback speed
Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
2025-03-25 21:19:11 +08:00
bggRGjQaUbCoE
cd3385be63 opt: only play audio
Closes #519

Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
2025-03-25 18:25:12 +08:00
bggRGjQaUbCoE
d4e4813c78 feat: static dm duration
Closes #479

Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
2025-03-25 17:47:11 +08:00
My-Responsitories
8030912087 Revert "fix: mixinKeyEncTab" (#527)
This reverts commit 0f78669faf.
2025-03-25 17:03:15 +08:00
bggRGjQaUbCoE
4879701008 opt: up panel
Closes #513

Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
2025-03-25 16:49:27 +08:00
bggRGjQaUbCoE
6ab8e5925e mod: remove maxConnectionsPerHost
Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
2025-03-25 15:36:52 +08:00
bggRGjQaUbCoE
52dda9964c opt: queryFollowUp
Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
2025-03-25 15:15:19 +08:00
bggRGjQaUbCoE
1825329236 fix: SetSwitchItem
Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
2025-03-25 14:52:11 +08:00
bggRGjQaUbCoE
60a650f798 fix: #526
Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
2025-03-25 14:38:12 +08:00
bggRGjQaUbCoE
0f78669faf fix: mixinKeyEncTab
Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
2025-03-25 14:13:09 +08:00
bggRGjQaUbCoE
015309b3dc opt: main: anim to top
Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
2025-03-25 14:06:19 +08:00
My-Responsitories
a74edd22c1 feat: refresh on top (#524)
* feat: refresh on top

* check ctr client

Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>

---------

Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
Co-authored-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
2025-03-25 13:46:38 +08:00
My-Responsitories
7a6085e923 refa: video model (#523) 2025-03-25 02:12:44 +00:00
bggRGjQaUbCoE
bf464994df opt: video progressbar
Closes #507
Closes #514

Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
2025-03-24 21:29:32 +08:00
bggRGjQaUbCoE
a611a88f69 opt: post segment
Closes #483

Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
2025-03-24 21:10:10 +08:00
bggRGjQaUbCoE
025b5c8e6d mod: search history
Closes #488

Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
2025-03-24 21:10:10 +08:00
bggRGjQaUbCoE
d37685f7cf opt: member page: show uname
Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
2025-03-24 21:10:10 +08:00
My-Responsitories
10a22b5186 opt: stat widget (#520) 2025-03-24 13:09:11 +00:00
bggRGjQaUbCoE
d9a74c43dc fix: del history
Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
2025-03-24 20:06:59 +08:00
bggRGjQaUbCoE
90c8aeb05d mod: history: full type
Closes #473

Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
2025-03-24 19:10:02 +08:00
bggRGjQaUbCoE
34f63612a4 fix: #517
Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
2025-03-24 14:29:54 +08:00
bggRGjQaUbCoE
edfa9a8dd1 mod: live: only play audio
Closes #465

Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
2025-03-24 14:07:42 +08:00
bggRGjQaUbCoE
95fa19f121 opt: dm widget
Closes #160
Closes #515

Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
2025-03-24 13:44:54 +08:00
bggRGjQaUbCoE
79d0d314f5 fix: #516
Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
2025-03-24 13:12:36 +08:00
bggRGjQaUbCoE
ddbf168c87 chore: update dm dep
Closes #511

Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
2025-03-24 11:37:02 +08:00
bggRGjQaUbCoE
0eee8bbac2 mod: def hwdec
Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
2025-03-24 10:50:51 +08:00
bggRGjQaUbCoE
92f02b5943 fix: search
Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
2025-03-24 10:20:43 +08:00
bggRGjQaUbCoE
f110c2a55f fix: fav search
Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
2025-03-24 10:16:01 +08:00
bggRGjQaUbCoE
8ddf42fff1 opt: switch btn
Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
2025-03-24 00:19:25 +08:00
My-Responsitories
d2c34d64c3 fix #510 2025-03-23 23:17:18 +08:00
bggRGjQaUbCoE
2341027972 mod: show switch btn when playall
Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
2025-03-23 22:19:13 +08:00
bggRGjQaUbCoE
006c9301d9 fix: follow staff
related #481

Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
2025-03-23 21:53:26 +08:00
bggRGjQaUbCoE
1f8955d0b3 opt: prev/next play
Closes #506

Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
2025-03-23 21:47:12 +08:00
bggRGjQaUbCoE
5a758ebb3a opt: play all
Closes #503

Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
2025-03-23 20:49:29 +08:00
bggRGjQaUbCoE
97bef56006 mod: live qa
Closes #464

Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
2025-03-23 20:35:16 +08:00
bggRGjQaUbCoE
96ba36ed67 fix: def subtitle stroke
Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
2025-03-23 20:34:59 +08:00
My-Responsitories
edf84fcc8f opt: blacklist (#501) 2025-03-23 11:13:07 +00:00
bggRGjQaUbCoE
a8428e52d2 opt: save subtitle
Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
2025-03-23 17:03:56 +08:00
bggRGjQaUbCoE
fd8559228e feat: save subtitle
Closes #495

Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
2025-03-23 16:27:38 +08:00
My-Responsitories
d6587cf3b6 feat: logout (#497)
* feat: logout

* update api type
2025-03-23 13:46:26 +08:00
My-Responsitories
7c3e3cb1f8 some fixes (#498)
* nologin reject headtbeat

* fix: change anonymity

* use account as key
2025-03-23 13:46:04 +08:00
bggRGjQaUbCoE
9d0ac30fad feat: follow staff
Closes #481

Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
2025-03-23 13:40:44 +08:00
bggRGjQaUbCoE
68d11d7638 feat: custom subtitle fontweight
Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
2025-03-23 12:19:25 +08:00
My-Responsitories
3881b3dc74 feat: retry before sending (#489)
* feat: retry before sending

* reduce idleTimeout
2025-03-23 12:09:11 +08:00
My-Responsitories
99b14d0f0e opt: danmaku filter (#486) 2025-03-23 12:07:57 +08:00
My-Responsitories
066f3d4132 some fix (#480)
* fix dislikeVideo

* fix profile update

* show login toast
2025-03-23 12:06:34 +08:00
My-Responsitories
b15fdfa2ff feat: account manager (#468)
* feat: account manager

* remove dep

* some fixes

* migrate accounts

* reimplement clearCookie
2025-03-19 13:19:32 +08:00
bggRGjQaUbCoE
94fa0652ac fix: #470
Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
2025-03-17 18:34:49 +08:00
bggRGjQaUbCoE
5c54e131ba opt: loadingwidget
Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
2025-03-17 14:00:11 +08:00
bggRGjQaUbCoE
1fc85fd618 mod: medialist: del btn
Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
2025-03-17 13:59:47 +08:00
bggRGjQaUbCoE
e1c561b613 fix: #467
Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
2025-03-17 00:45:35 +08:00
bggRGjQaUbCoE
950620bf9e opt: dyn panel
Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
2025-03-16 21:26:37 +08:00
bggRGjQaUbCoE
ae7a1e2373 mod: dyn: show medialist type
Closes #462

Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
2025-03-16 20:50:04 +08:00
bggRGjQaUbCoE
bddeb72d9b fix: medialist: del btn
Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
2025-03-16 18:44:32 +08:00
bggRGjQaUbCoE
b99cf4f629 opt: playall
Closes #450

Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
2025-03-16 18:19:22 +08:00
bggRGjQaUbCoE
b07cf62bdd mod: medialist: show del btn
Closes #451

Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
2025-03-16 16:36:43 +08:00
bggRGjQaUbCoE
57d2d3f5d9 fix: video page theme
mod: popscope

related #459

Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
2025-03-16 15:33:55 +08:00
My-Responsitories
7854c5e6b9 split report dialog (#460) 2025-03-16 13:34:04 +08:00
bggRGjQaUbCoE
0b8e95477c mod: handle show viewpoints btn
Closes #457

Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
2025-03-16 11:22:20 +08:00
dom
c2e9a7deb3 Update 功能请求.yml 2025-03-16 10:38:47 +08:00
bggRGjQaUbCoE
361a6a4c1d fix: get args
Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
2025-03-15 19:55:47 +08:00
bggRGjQaUbCoE
8eca9a6644 opt: live: msg bg
Closes #448

Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
2025-03-15 16:19:09 +08:00
bggRGjQaUbCoE
0770f325ab feat: subtitle stroke
Closes #446

Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
2025-03-15 15:46:07 +08:00
bggRGjQaUbCoE
98d52760b3 mod: pages
Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
2025-03-15 15:27:16 +08:00
bggRGjQaUbCoE
0ebe976b8a mod: custom enableSlideVolumeBrightness
Closes #439

Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
2025-03-14 19:47:22 +08:00
bggRGjQaUbCoE
21fe0ef288 mod: search from tag
Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
2025-03-14 12:19:30 +08:00
bggRGjQaUbCoE
28ef1890d1 fix: #438
Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
2025-03-13 22:08:06 +08:00
bggRGjQaUbCoE
d6f238c720 fix: get sortField
Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
2025-03-13 22:07:32 +08:00
bggRGjQaUbCoE
44bf9dd9e1 opt: dyn panel
Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
2025-03-13 13:49:39 +08:00
bggRGjQaUbCoE
e357da5162 opt: dyn panel
Closes #436

Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
2025-03-13 12:27:36 +08:00
bggRGjQaUbCoE
c296aa036a fix: img preview quality
Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
2025-03-13 11:54:22 +08:00
bggRGjQaUbCoE
12c46f938d mod: split dm/sub settings, add reset btn
Closes #223
Closes #361

Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
2025-03-12 18:27:08 +08:00
bggRGjQaUbCoE
b4412f5b37 opt: some widgets
Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
2025-03-12 16:45:21 +08:00
bggRGjQaUbCoE
5f2ac0d59b fix: ctr tag
Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
2025-03-12 09:37:10 +08:00
bggRGjQaUbCoE
2a73725455 opt: live room
Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
2025-03-11 22:25:13 +08:00
bggRGjQaUbCoE
a8725e64ee opt: live room
Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
2025-03-11 21:51:16 +08:00
bggRGjQaUbCoE
727ae8cd2b opt: live room
Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
2025-03-11 21:35:47 +08:00
bggRGjQaUbCoE
714f288170 opt: live room
Closes #427

Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
2025-03-11 21:10:37 +08:00
bggRGjQaUbCoE
3da64d2641 fix: share video
Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
2025-03-11 14:29:05 +08:00
My-Responsitories
2556290a6e fix #424 2025-03-11 14:11:13 +08:00
bggRGjQaUbCoE
66b547a904 fix: #424
Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
2025-03-11 13:59:58 +08:00
bggRGjQaUbCoE
c1ab273478 opt: video: long press
Closes #423

Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
2025-03-11 13:54:31 +08:00
bggRGjQaUbCoE
4aa3d5f273 opt: video sheet
Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
2025-03-11 13:44:24 +08:00
bggRGjQaUbCoE
a6a1de169b fix: video theme, view later
Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
2025-03-11 11:54:44 +08:00
bggRGjQaUbCoE
af6188be77 opt: live room bg
Closes #422

Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
2025-03-11 11:54:17 +08:00
bggRGjQaUbCoE
bd39de2109 opt: video dialog
Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
2025-03-10 23:56:51 +08:00
bggRGjQaUbCoE
33375aeb7d feat: dark video page
Closes #420

Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
2025-03-10 23:33:33 +08:00
bggRGjQaUbCoE
fafe6c1e91 opt: video page
Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
2025-03-10 21:40:59 +08:00
bggRGjQaUbCoE
68b072bf44 mod: remove unused import
Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
2025-03-10 20:19:43 +08:00
My-Responsitories
99cdec62a1 view later (#419) 2025-03-10 18:46:07 +08:00
bggRGjQaUbCoE
59797a2f5f mod: jump from invalid fav item
Closes #416

Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
2025-03-10 16:52:54 +08:00
bggRGjQaUbCoE
5cc661e314 opt: video width
Closes #417

Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
2025-03-10 15:54:38 +08:00
bggRGjQaUbCoE
2ce79d21b5 opt: view invalid user space
Closes #414

Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
2025-03-10 15:14:36 +08:00
bggRGjQaUbCoE
b75fda3596 mod: common ctr
Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
2025-03-10 11:12:52 +08:00
bggRGjQaUbCoE
2efa6f4ace mod: jump from cvid
Closes #405

Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
2025-03-09 21:42:47 +08:00
bggRGjQaUbCoE
95e50e436b mod: option show dyn actionbar
Closes #412

Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
2025-03-09 21:22:19 +08:00
bggRGjQaUbCoE
35a53bc8ac mod: option shrink video
Closes #410

Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
2025-03-09 21:00:24 +08:00
bggRGjQaUbCoE
58c16ef52e chore: add episode info api
Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
2025-03-09 20:49:53 +08:00
bggRGjQaUbCoE
847ac80d5f opt: viewpoints page
Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
2025-03-09 10:09:54 +08:00
bggRGjQaUbCoE
0408b27ca5 mod: check reply manually
Closes #407

Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
2025-03-09 09:50:06 +08:00
My-Responsitories
2949adbbfd fix: msg_feed insert type error (#411)
* fix: msg_feed insert type error

* jump to dyn secondary reply
2025-03-09 09:49:16 +08:00
dom
2f616ba237 Update and rename 功能请求.md to 功能请求.yml 2025-03-08 20:01:16 +08:00
dom
b50ead327c Update and rename bug-反馈.md to bug-反馈.yml 2025-03-08 19:56:06 +08:00
bggRGjQaUbCoE
2fe0f43cb6 fix: #404
Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
2025-03-08 08:33:03 +08:00
bggRGjQaUbCoE
b85413be9b opt: video bg
Closes #397

Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
2025-03-07 15:04:16 +08:00
bggRGjQaUbCoE
c88776c4a0 mod: try-catch nextplay
Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
2025-03-07 11:51:20 +08:00
My-Responsitories
b7cb977f2b remove duplicated code (#396)
* remove duplicated code

* partical revert

---------

Co-authored-by: dom <githubaccount56556@proton.me>
2025-03-07 11:49:46 +08:00
bggRGjQaUbCoE
3048e36d2f mod: requery dm
Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
2025-03-06 16:27:51 +08:00
bggRGjQaUbCoE
64f37fa743 opt: triple
Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
2025-03-06 13:52:37 +08:00
bggRGjQaUbCoE
737b7d0507 fix: numformat
Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
2025-03-06 13:32:44 +08:00
bggRGjQaUbCoE
973dad4176 fix: video header
Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
2025-03-06 12:26:34 +08:00
bggRGjQaUbCoE
46110adb8f fix: #391
Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
2025-03-06 12:06:00 +08:00
bggRGjQaUbCoE
b5c7ed1c34 opt: video: check title width
Closes #206

Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
2025-03-06 11:58:39 +08:00
bggRGjQaUbCoE
86678ec15a opt: triple
Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
2025-03-06 11:03:58 +08:00
bggRGjQaUbCoE
893fb63a72 mod: video appbar
Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
2025-03-06 10:48:37 +08:00
bggRGjQaUbCoE
3b717cfc58 fix: video minScale
Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
2025-03-06 10:11:10 +08:00
bggRGjQaUbCoE
ed40a91a52 opt: fullscreen triple
Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
2025-03-05 23:49:03 +08:00
bggRGjQaUbCoE
8b1bec6ed2 mod: blacklist item
Closes #390

Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
2025-03-05 23:02:32 +08:00
bggRGjQaUbCoE
a6a3476cb2 mod: video minScale
Closes #388

Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
2025-03-05 22:48:01 +08:00
bggRGjQaUbCoE
fac3c19d3f mod: show fullscreen action item
Closes #367

Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
2025-03-05 21:50:26 +08:00
bggRGjQaUbCoE
dc1451c3af opt: at me item
Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
2025-03-05 17:57:51 +08:00
bggRGjQaUbCoE
08b0a93064 mod: msg top: show time
Closes #387

Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
2025-03-05 17:39:09 +08:00
bggRGjQaUbCoE
72dd0b9e81 opt: report panel
Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
2025-03-05 17:04:16 +08:00
bggRGjQaUbCoE
8236b93717 mod: msg top item
Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
2025-03-05 17:01:22 +08:00
My-Responsitories
c4c5eee2eb fix banUid (#386) 2025-03-05 17:01:08 +08:00
My-Responsitories
5cc9c59c76 report panel (#385) 2025-03-05 15:42:04 +08:00
bggRGjQaUbCoE
bf4ecc85dd mod: article req
Closes #305

Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
2025-03-05 14:25:54 +08:00
bggRGjQaUbCoE
da5c2148ad opt: horizontal image view
Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
2025-03-05 13:42:35 +08:00
bggRGjQaUbCoE
bfcea11320 opt: dyndetail/html ctr listener
related #305

Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
2025-03-05 13:22:06 +08:00
bggRGjQaUbCoE
ed19e13630 fix: video appbar
Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
2025-03-05 11:23:51 +08:00
bggRGjQaUbCoE
6497fb6cd0 mod: common slide page
Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
2025-03-05 10:45:02 +08:00
bggRGjQaUbCoE
9c21f03df8 opt: tabbar
Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
2025-03-05 00:04:38 +08:00
bggRGjQaUbCoE
7667e73d9d fix: #383
Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
2025-03-04 23:38:38 +08:00
bggRGjQaUbCoE
ff2ed0421c mod: pages
Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
2025-03-04 22:32:09 +08:00
bggRGjQaUbCoE
56c5ad360a mod: more slide dismiss pages
Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
2025-03-04 20:35:15 +08:00
bggRGjQaUbCoE
ef644d2837 fix: #381
Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
2025-03-04 20:34:45 +08:00
bggRGjQaUbCoE
4642eda98d refa: msg top page
Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
2025-03-04 14:37:58 +08:00
bggRGjQaUbCoE
8ef163dd38 mod: refresh
Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
2025-03-04 12:06:50 +08:00
bggRGjQaUbCoE
5986add7dd feat: show video note list
Closes #376

Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
2025-03-04 11:42:41 +08:00
bggRGjQaUbCoE
c990cf1660 mod: progressbar
Closes #379

Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
2025-03-04 09:37:10 +08:00
bggRGjQaUbCoE
76c16c035e mod: show dm merged count
related #359

Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
2025-03-03 21:38:02 +08:00
My-Responsitories
d5a244ce7f update msg api (#375) 2025-03-03 17:23:19 +08:00
bggRGjQaUbCoE
432c5133e6 mod: show clear search history dialog
related #359

Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
2025-03-03 11:40:39 +08:00
bggRGjQaUbCoE
a9f9b324a9 opt: slide gesture
Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
2025-03-02 13:59:45 +08:00
bggRGjQaUbCoE
4735297285 opt: seek indicator
Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
2025-03-02 12:13:48 +08:00
bggRGjQaUbCoE
3abff4b9da opt: string ext
Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
2025-03-02 12:04:13 +08:00
bggRGjQaUbCoE
c32b98fa7f fix: thumbnail image url
Closes #360

Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
2025-03-02 11:53:51 +08:00
bggRGjQaUbCoE
a605c0fcfb mod: reenable multi seek
Closes #365

Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
2025-03-02 10:23:45 +08:00
bggRGjQaUbCoE
1e83b4557f mod: extra jump to reply
Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
2025-03-02 00:47:02 +08:00
bggRGjQaUbCoE
c3d729fc77 mod: scheme: jump to reply
Closes #362

Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
2025-03-02 00:39:39 +08:00
bggRGjQaUbCoE
00ea891784 fix: clear audio noti
Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
2025-03-01 17:53:24 +08:00
bggRGjQaUbCoE
c98dbccbd7 fix: #359
Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
2025-03-01 16:40:40 +08:00
bggRGjQaUbCoE
4a68122c31 opt: live bottom control
Closes #349

Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
2025-03-01 13:52:26 +08:00
bggRGjQaUbCoE
9c4a52de87 opt: video toolbar icon
Closes #329

Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
2025-03-01 13:32:54 +08:00
bggRGjQaUbCoE
6c11140f43 fix: #352
Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
2025-03-01 09:36:41 +08:00
bggRGjQaUbCoE
11398ca64b opt: handle response
Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
2025-03-01 09:36:41 +08:00
bggRGjQaUbCoE
312ce6e639 opt: pages
Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
2025-02-28 21:54:53 +08:00
bggRGjQaUbCoE
139b48c457 opt: dm widget
Closes #350

Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
2025-02-28 21:47:42 +08:00
bggRGjQaUbCoE
f1f478e193 fix: live: show statusbar
Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
2025-02-28 21:47:42 +08:00
bggRGjQaUbCoE
1abaf3db3f fix: #343
Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
2025-02-28 21:47:42 +08:00
bggRGjQaUbCoE
f6bfbc3ed6 mod: video sheet panel
Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
2025-02-28 20:20:39 +08:00
bggRGjQaUbCoE
d2890d72e5 fix: #341 #343 #339
Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
2025-02-28 17:48:04 +08:00
bggRGjQaUbCoE
5c029c8f64 Revert "opt: video page"
This reverts commit 82030b8d06.
2025-02-28 17:30:50 +08:00
bggRGjQaUbCoE
c37a631df2 fix: #345
Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
2025-02-28 15:57:31 +08:00
bggRGjQaUbCoE
82030b8d06 opt: video page
Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
2025-02-28 15:36:39 +08:00
bggRGjQaUbCoE
e362f75dac opt: slide gesture
Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
2025-02-28 13:10:14 +08:00
bggRGjQaUbCoE
3fecf7c0a4 fix: #339
Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
2025-02-28 11:26:03 +08:00
bggRGjQaUbCoE
801043468d fix: getPlayerKey
Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
2025-02-28 10:16:02 +08:00
bggRGjQaUbCoE
1b4f588671 fix: #339 #341
Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
2025-02-28 10:05:27 +08:00
bggRGjQaUbCoE
7ad48570f0 mod: fullscreen debounce
Closes #340

Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
2025-02-28 00:37:57 +08:00
bggRGjQaUbCoE
5b8c68303f fix: #337
Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
2025-02-27 23:52:54 +08:00
bggRGjQaUbCoE
87d3d0ca14 fix: video page v
Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
2025-02-27 21:28:14 +08:00
bggRGjQaUbCoE
b330440371 fix: video page
Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
2025-02-27 21:00:49 +08:00
bggRGjQaUbCoE
2a173ef804 fix: #334
Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
2025-02-27 20:06:46 +08:00
bggRGjQaUbCoE
bceabae06f fix: video play
Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
2025-02-27 19:05:57 +08:00
bggRGjQaUbCoE
69667c135d feat: slide to dismiss subreply page
Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
2025-02-27 18:05:34 +08:00
bggRGjQaUbCoE
587870ad71 fix: player key
Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
2025-02-27 16:52:33 +08:00
bggRGjQaUbCoE
609fab345a fix: video page v
Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
2025-02-27 16:26:54 +08:00
bggRGjQaUbCoE
29c47cee78 fix: #333
Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
2025-02-27 15:51:03 +08:00
bggRGjQaUbCoE
6a9795f561 opt: video page v
Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
2025-02-27 11:38:44 +08:00
bggRGjQaUbCoE
72e7f0aa9f Revert "fix: #333"
This reverts commit acfa384c0c.
2025-02-27 11:38:43 +08:00
bggRGjQaUbCoE
acfa384c0c fix: #333
Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
2025-02-27 09:51:21 +08:00
bggRGjQaUbCoE
c2d27ddd04 opt: video page v
Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
2025-02-27 09:28:43 +08:00
My-Responsitories
0a6950e34a enable http2 (#331) 2025-02-26 22:02:19 +08:00
My-Responsitories
1c3d77b95d opt: wbiSign (#332) 2025-02-26 22:01:38 +08:00
bggRGjQaUbCoE
fb11208bbe fix: video toolbar
Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
2025-02-26 20:23:26 +08:00
bggRGjQaUbCoE
94f05127b6 fix: #330
Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
2025-02-26 19:53:06 +08:00
bggRGjQaUbCoE
25a3046c3c fix: video page
Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
2025-02-26 18:53:31 +08:00
bggRGjQaUbCoE
f479fc37ba mod: follow tabbarview
Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
2025-02-26 18:36:25 +08:00
bggRGjQaUbCoE
3ee19a8f08 mod: show followed user verif
Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
2025-02-26 18:27:50 +08:00
bggRGjQaUbCoE
b8d2ad68dd fix: video page v
Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
2025-02-26 17:43:35 +08:00
dom
8434c488da refa: vertical video page (#328)
Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
2025-02-26 17:21:24 +08:00
bggRGjQaUbCoE
41f251ad50 fix: dyn
Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
2025-02-26 11:39:56 +08:00
bggRGjQaUbCoE
8e99ff1173 mod: search: show user verf
Closes #322

Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
2025-02-25 18:27:15 +08:00
bggRGjQaUbCoE
a921b983f5 opt: cancel seek
Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
2025-02-25 18:03:26 +08:00
bggRGjQaUbCoE
81eeda0a68 mod: video: cancellable slide seek
Closes #319

Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
2025-02-25 16:53:35 +08:00
bggRGjQaUbCoE
1a54f61355 mod: player: enable long press feedback
Closes #318

Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
2025-02-25 16:53:01 +08:00
bggRGjQaUbCoE
382cd5b73d mod: error toast
Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
2025-02-25 15:20:52 +08:00
bggRGjQaUbCoE
e236485bc7 mod: listener
Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
2025-02-25 15:20:52 +08:00
bggRGjQaUbCoE
0e69e23606 mod: video tabbarview
Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
2025-02-24 22:25:37 +08:00
bggRGjQaUbCoE
0ef85f2551 fix: search ctr
related #306

Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
2025-02-24 21:04:28 +08:00
My-Responsitories
8d3990124e revert genTraceId (#314) 2025-02-24 17:13:15 +08:00
bggRGjQaUbCoE
7f912a1781 mod: refresh
related #306

Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
2025-02-24 17:10:43 +08:00
bggRGjQaUbCoE
d9ae1dd97a fix: handle grpc response
Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
2025-02-24 16:31:04 +08:00
bggRGjQaUbCoE
307db51aec mod: filter goods reposted dyn
Closes #309

Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
2025-02-24 15:00:54 +08:00
My-Responsitories
347a704b54 replace grpc to dio (#313)
* replace grpc to dio

* load danmaku from grpc
2025-02-24 14:55:28 +08:00
My-Responsitories
9e242fb902 remove duplicate code (#312)
* remove duplicate code

* Update login.dart
2025-02-24 14:55:08 +08:00
bggRGjQaUbCoE
192cd60a4f fix: get video progress
Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
2025-02-24 10:31:14 +08:00
bggRGjQaUbCoE
a98d8511d6 Update README.md
Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
2025-02-23 21:03:05 +08:00
bggRGjQaUbCoE
811b79610c fix: live room
Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
2025-02-23 18:10:51 +08:00
bggRGjQaUbCoE
14129e8f21 mod: horizontal live room
Closes #62

Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
2025-02-23 17:15:25 +08:00
bggRGjQaUbCoE
16de044d3d mod: triple
Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
2025-02-23 15:10:31 +08:00
bggRGjQaUbCoE
e573a8a9c0 mod: fs
related #306

Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
2025-02-23 14:58:12 +08:00
bggRGjQaUbCoE
108648cabf mod: seek from url
related #208

Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
2025-02-23 11:28:13 +08:00
bggRGjQaUbCoE
8e4ce07d19 opt: parse scheme
Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
2025-02-23 11:05:50 +08:00
bggRGjQaUbCoE
09cebd70ae mod: seek from dm
Closes #208

Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
2025-02-23 10:43:35 +08:00
bggRGjQaUbCoE
6a615c408b opt: nav icon color
ref orz12/main
2025-02-22 20:37:51 +08:00
bggRGjQaUbCoE
9ebc054c8c opt: spring
Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
2025-02-22 20:17:38 +08:00
My-Responsitories
b2c520bd91 feat: custom spring (#304) 2025-02-22 17:56:36 +08:00
bggRGjQaUbCoE
6506afa732 mod: add expand dyn live panel option
Closes #302

Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
2025-02-22 16:35:25 +08:00
bggRGjQaUbCoE
d1c74b9389 Revert "mod: set user-agent"
This reverts commit 4c56fcd6a8.
2025-02-22 16:10:11 +08:00
bggRGjQaUbCoE
61ca7bc1cb opt: horizontal preview
Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
2025-02-22 12:08:36 +08:00
bggRGjQaUbCoE
f94cb2a4b5 opt: pages
Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
2025-02-21 21:27:19 +08:00
bggRGjQaUbCoE
4c56fcd6a8 mod: set user-agent
Closes #299

Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
2025-02-21 20:56:15 +08:00
bggRGjQaUbCoE
d5bb2ec165 opt: del fav folder
Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
2025-02-21 18:20:08 +08:00
bggRGjQaUbCoE
27bc68f264 opt: follow page
Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
2025-02-21 18:18:16 +08:00
bggRGjQaUbCoE
516eed76b7 mod: video sheet
Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
2025-02-21 18:04:31 +08:00
bggRGjQaUbCoE
4190c17cdc fix: #295
Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
2025-02-21 17:43:50 +08:00
bggRGjQaUbCoE
3d0fedfb61 mod: convert forEach
Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
2025-02-21 11:39:32 +08:00
bggRGjQaUbCoE
9d57deffb4 fix: filter dm midhash
Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
2025-02-21 11:17:54 +08:00
My-Responsitories
cc1951c721 fix regex & use set in uid (#296)
* fix regex count & use set in uid

* fix regex
2025-02-21 10:42:28 +08:00
bggRGjQaUbCoE
1cd8d4913d fix: #294
Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
2025-02-20 23:15:06 +08:00
bggRGjQaUbCoE
19890e29e9 mod: restore video duration
Closes #293

Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
2025-02-20 21:09:53 +08:00
bggRGjQaUbCoE
f759dba7da opt: filter danmaku
related #283

Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
2025-02-20 18:09:51 +08:00
bggRGjQaUbCoE
fb6f92a70b opt: #284
Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
2025-02-19 16:18:21 +08:00
bggRGjQaUbCoE
f22cad42d7 opt: filter data
Closes #283

Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
2025-02-19 15:42:24 +08:00
My-Responsitories
cfb6c674ea skip mcdn on parsing (#281) 2025-02-19 14:55:02 +08:00
bggRGjQaUbCoE
415c68a570 fix: typo
Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
2025-02-19 12:16:20 +08:00
bggRGjQaUbCoE
15b949bb9c mod: webview jump
Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
2025-02-19 11:42:05 +08:00
bggRGjQaUbCoE
316a9809e4 mod: delay checking dyn
Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
2025-02-18 22:42:39 +08:00
bggRGjQaUbCoE
3f5aa03056 mod: insert dyn
Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
2025-02-18 22:03:59 +08:00
bggRGjQaUbCoE
6bc33795a3 feat: create dyn antifraud
Closes #278

Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
2025-02-18 21:51:09 +08:00
bggRGjQaUbCoE
3191ae27a5 mod: repost panel
Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
2025-02-18 18:54:46 +08:00
bggRGjQaUbCoE
b25de52b9e feat: repost video
Closes #279

Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
2025-02-18 18:28:59 +08:00
bggRGjQaUbCoE
a08b4648d5 mod: try-catch biliSendCommAntifraud
Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
2025-02-18 17:07:00 +08:00
bggRGjQaUbCoE
e7a7c945de fix: biliSendCommAntifraud
related #275

Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
2025-02-18 15:48:39 +08:00
bggRGjQaUbCoE
571f358280 mod: user search widget
Closes #280

Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
2025-02-17 23:11:16 +08:00
bggRGjQaUbCoE
7ddc3adfaa feat: bili comm antifraud
Closes #275

Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
2025-02-17 21:31:55 +08:00
bggRGjQaUbCoE
957c326148 feat: anti goods reply
Closes #276

Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
2025-02-17 18:49:20 +08:00
bggRGjQaUbCoE
0b246d03a6 feat: anti goods dyn
Closes #277

Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
2025-02-17 18:49:03 +08:00
bggRGjQaUbCoE
5dd3ff32b6 fix: view forwarded dyn
Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
2025-02-16 22:00:55 +08:00
bggRGjQaUbCoE
a48d262637 mod: show member coin/like archives(web)
Closes #265

Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
2025-02-16 20:55:41 +08:00
bggRGjQaUbCoE
b5d17b5161 mod: pay coins page
related #245

Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
2025-02-16 20:34:06 +08:00
bggRGjQaUbCoE
980733ba22 fix: member contribute page
Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
2025-02-16 19:49:39 +08:00
bggRGjQaUbCoE
7043fdc35d mod: debug logout
Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
2025-02-16 15:09:53 +08:00
bggRGjQaUbCoE
81713a6bc4 mod: article: add action panel
related #235

Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
2025-02-16 15:00:49 +08:00
bggRGjQaUbCoE
959bcfaa30 mod: keep pgc index page
Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
2025-02-16 13:37:34 +08:00
bggRGjQaUbCoE
fa465f792d opt: video width
Closes #267

Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
2025-02-16 13:37:34 +08:00
bggRGjQaUbCoE
74bf78b9cd feat: pgc index page
Closes #216

Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
2025-02-16 13:15:00 +08:00
bggRGjQaUbCoE
8c408e59f6 opt: post segment panel
Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
2025-02-16 09:25:33 +08:00
bggRGjQaUbCoE
25d27e42ed fix: #263
Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
2025-02-16 09:22:09 +08:00
bggRGjQaUbCoE
0f2b0cc5f2 Revert "fix: #263"
This reverts commit 84ed34f3a7.
2025-02-16 01:01:01 +08:00
bggRGjQaUbCoE
00ea34f45d opt: video bs
Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
2025-02-15 23:42:02 +08:00
bggRGjQaUbCoE
ec936c1821 opt: video bs
Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
2025-02-15 23:00:47 +08:00
bggRGjQaUbCoE
2ff84857e7 refa: video bottom sheet
Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
2025-02-15 22:19:43 +08:00
bggRGjQaUbCoE
84ed34f3a7 fix: #263
Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
2025-02-15 21:07:56 +08:00
bggRGjQaUbCoE
f0508e1bc2 mod: disable version check when debug
Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
2025-02-15 20:40:39 +08:00
bggRGjQaUbCoE
8ea7bf36d7 fix: dyn detail: repost btn
Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
2025-02-15 20:22:47 +08:00
bggRGjQaUbCoE
8819461eed mod: dyn detail: add action panel
Closes #235

Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
2025-02-15 18:04:43 +08:00
bggRGjQaUbCoE
7c30668c87 fix: #261
Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
2025-02-15 16:41:49 +08:00
bggRGjQaUbCoE
a3424950ca fix: push dyn
Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
2025-02-15 14:33:58 +08:00
bggRGjQaUbCoE
ebc42eb05e fix: logout
Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
2025-02-15 14:25:10 +08:00
bggRGjQaUbCoE
fc6ff44471 fix: ai conclusion
Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
2025-02-15 14:23:15 +08:00
bggRGjQaUbCoE
be03377449 fix: emote
Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
2025-02-15 13:52:12 +08:00
bggRGjQaUbCoE
e52934093a opt: member tab
Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
2025-02-15 13:30:50 +08:00
bggRGjQaUbCoE
ebfd98488e mod: show staff verf
Closes #259

Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
2025-02-15 13:26:08 +08:00
bggRGjQaUbCoE
6a68af77dc mod: member tab
Closes #260

Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
2025-02-15 13:14:25 +08:00
bggRGjQaUbCoE
e5c0fb7cb2 fix: in-app webview
Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
2025-02-15 12:57:04 +08:00
bggRGjQaUbCoE
d9611cce80 opt: in-app webview
Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
2025-02-15 12:26:44 +08:00
bggRGjQaUbCoE
4b48aba2ae opt: data parse
related #258

Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
2025-02-15 12:03:43 +08:00
bggRGjQaUbCoE
47fbb6cd0e opt: whisper: msg preview
Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
2025-02-15 00:06:35 +08:00
bggRGjQaUbCoE
dae71d427c feat: whisper: revoke msg
Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
2025-02-14 23:28:48 +08:00
bggRGjQaUbCoE
46bc2ceb78 mod: scheme match
Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
2025-02-14 21:52:57 +08:00
bggRGjQaUbCoE
6f98200179 mod: whisper pic type
Closes #253

Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
2025-02-14 21:35:15 +08:00
bggRGjQaUbCoE
a57b4c56a5 fix: #257
Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
2025-02-14 21:07:56 +08:00
bggRGjQaUbCoE
6c3062ba2d feat: pure black theme
Closes #254

Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
2025-02-14 16:10:22 +08:00
bggRGjQaUbCoE
064c8a9dfe mod: page observer
Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
2025-02-14 11:15:50 +08:00
bggRGjQaUbCoE
7dd47736fb opt: better url pattern
Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
2025-02-13 22:27:16 +08:00
bggRGjQaUbCoE
84cc65489f mod: scheme match
Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
2025-02-13 17:51:52 +08:00
bggRGjQaUbCoE
2b9cb54d91 opt: view from playlist
Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
2025-02-13 17:15:48 +08:00
dom
54c7fef217 opt: jump url (#246)
Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
2025-02-13 16:53:40 +08:00
bggRGjQaUbCoE
ba74cb8c01 opt: video bottom control
Closes #244

Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
2025-02-13 15:04:44 +08:00
bggRGjQaUbCoE
675932aa69 mod: try-catch some requests
Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
2025-02-12 22:17:01 +08:00
bggRGjQaUbCoE
d996e0a7dd fix: #240
Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
2025-02-12 21:52:27 +08:00
bggRGjQaUbCoE
b6279f702a fix: #239
Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
2025-02-12 20:48:14 +08:00
bggRGjQaUbCoE
695a89b91a opt: view pgc section
Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
2025-02-12 16:14:59 +08:00
bggRGjQaUbCoE
09753b6bbd fix: #226
Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
2025-02-12 14:20:16 +08:00
bggRGjQaUbCoE
6502b97388 mod: pgc coin
Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
2025-02-12 13:24:46 +08:00
bggRGjQaUbCoE
95d84647b7 opt: coin page checkbox
Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
2025-02-12 12:59:30 +08:00
bggRGjQaUbCoE
8f5065332e fix: intro up verify
Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
2025-02-12 12:59:23 +08:00
bggRGjQaUbCoE
71c8cbb8da fix: #232
Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
2025-02-12 12:39:31 +08:00
bggRGjQaUbCoE
3217731486 mod: coin with like
Closes #231

Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
2025-02-12 12:20:06 +08:00
bggRGjQaUbCoE
a4e63fe0e8 mod: video intro: show detailed owner info
Closes #229

Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
2025-02-12 12:27:29 +08:00
bggRGjQaUbCoE
cdb8f6845c mod: history card menu
Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
2025-02-11 21:50:59 +08:00
bggRGjQaUbCoE
0a7d286c47 mod: reply2reply header
Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
2025-02-11 21:14:35 +08:00
bggRGjQaUbCoE
e17fd0071d mod: forwarded live dyn
Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
2025-02-11 21:14:35 +08:00
bggRGjQaUbCoE
a9ba30b9b9 mod: show dyn gif emote
mod: emote tabbar

opt: video progress indicator

Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
2025-02-11 18:30:01 +08:00
bggRGjQaUbCoE
4267a3b8e0 mod: member archive: show progress
Closes #225

Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
2025-02-11 17:21:06 +08:00
bggRGjQaUbCoE
50022ae635 fix: whisper: null check
related #217

Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
2025-02-11 15:20:52 +08:00
bggRGjQaUbCoE
0991621152 mod: dyn action
Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
2025-02-11 14:53:17 +08:00
bggRGjQaUbCoE
192f8924c8 fix: #217
Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
2025-02-11 14:07:43 +08:00
bggRGjQaUbCoE
51a12d7266 mod: minor tweaks
Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
2025-02-11 12:05:21 +08:00
bggRGjQaUbCoE
1417fcda6e fix: seek anim
Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
2025-02-10 21:33:57 +08:00
bggRGjQaUbCoE
6114e6f033 opt: restore scale btn
Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
2025-02-10 19:58:44 +08:00
bggRGjQaUbCoE
bc2dbc59ce mod: video scale set
Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
2025-02-10 18:51:41 +08:00
bggRGjQaUbCoE
7c5075413e mod: add restore video scale button
related #222

Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
2025-02-10 18:31:22 +08:00
bggRGjQaUbCoE
52175b0b69 mod: show reply gif emote
Closes #212

Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
2025-02-10 16:22:48 +08:00
bggRGjQaUbCoE
f0a3515279 opt: search aid/bvid
Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
2025-02-10 13:46:41 +08:00
bggRGjQaUbCoE
3c2ccf7d40 mod: check av/bv search
Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
2025-02-10 13:31:50 +08:00
bggRGjQaUbCoE
abd01e1a27 fix: reply cv jump
Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
2025-02-10 13:14:40 +08:00
bggRGjQaUbCoE
0f63976a00 mod: reply jump
Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
2025-02-10 12:04:13 +08:00
bggRGjQaUbCoE
6817eb6e56 fix: reply jump url
Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
2025-02-10 11:13:55 +08:00
bggRGjQaUbCoE
a951d42623 mod: web down
Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
2025-02-10 11:13:54 +08:00
bggRGjQaUbCoE
8f5c2bf3ba mod: dyn article: show block type
Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
2025-02-09 22:47:31 +08:00
bggRGjQaUbCoE
7744217d17 mod: grpc reply: jump to vote
Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
2025-02-09 20:59:58 +08:00
bggRGjQaUbCoE
a84c153bdd fix: later request
log #214

Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
2025-02-09 18:35:01 +08:00
bggRGjQaUbCoE
31a0a90ba4 mod: reply2relpy header
Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
2025-02-09 15:43:57 +08:00
bggRGjQaUbCoE
383ce777e3 mod: webview: handle download request
Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
2025-02-09 10:44:46 +08:00
bggRGjQaUbCoE
e7ac88ffb1 opt: reply2reply header
Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
2025-02-09 09:36:26 +08:00
bggRGjQaUbCoE
9657c77999 mod: push article
Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
2025-02-09 09:36:26 +08:00
bggRGjQaUbCoE
afd508f28b opt: persistent header
Closes #211

ref pilipala

Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
2025-02-09 00:25:25 +08:00
bggRGjQaUbCoE
634612c1a2 fix: article
Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
2025-02-08 23:50:17 +08:00
bggRGjQaUbCoE
76545397d4 mod: video push
Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
2025-02-08 23:22:25 +08:00
bggRGjQaUbCoE
d2f586a7f1 fix: push bangumi
Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
2025-02-08 23:08:58 +08:00
bggRGjQaUbCoE
7cfebcb6ed opt: webview to video
Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
2025-02-08 22:56:43 +08:00
bggRGjQaUbCoE
9a3766e7b7 opt: webview to video
Closes #209

Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
2025-02-08 21:41:19 +08:00
bggRGjQaUbCoE
588a06bece opt: article content
Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
2025-02-07 17:40:45 +08:00
bggRGjQaUbCoE
e45a126862 fix: handleWebview
Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
2025-02-07 16:39:33 +08:00
bggRGjQaUbCoE
a581945c9e feat: interactive video
Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
2025-02-07 15:38:33 +08:00
bggRGjQaUbCoE
331fd0d619 mod: intro panel
opt: pgc page

Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
2025-02-07 15:24:03 +08:00
bggRGjQaUbCoE
c6e229d571 fix: replay
Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
2025-02-06 12:09:29 +08:00
bggRGjQaUbCoE
b2c3b1ff95 fix: #199
Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
2025-02-06 12:09:08 +08:00
bggRGjQaUbCoE
3fc12fcc09 mod: widget
Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
2025-02-05 16:55:10 +08:00
bggRGjQaUbCoE
e098631553 mod: dyn square type
Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
2025-02-05 13:49:37 +08:00
bggRGjQaUbCoE
0fcd55755e mod: handleWebview
Closes #194

Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
2025-02-05 13:36:44 +08:00
bggRGjQaUbCoE
65e7c0c4f4 opt: pages
Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
2025-02-05 12:19:45 +08:00
bggRGjQaUbCoE
70aecd1e38 mod: view point
Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
2025-02-04 14:38:06 +08:00
bggRGjQaUbCoE
a40c773491 fix: interceptor
Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
2025-02-04 13:09:52 +08:00
bggRGjQaUbCoE
b4abb58a41 mod: seg bar, dyn decorate
Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
2025-02-04 11:33:23 +08:00
bggRGjQaUbCoE
e368436bc6 feat: reply: sync to dyn
Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
2025-02-03 11:43:42 +08:00
bggRGjQaUbCoE
6c96b3a7f5 fix: check reply url
Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
2025-02-03 10:49:25 +08:00
bggRGjQaUbCoE
149f0c082d fix: reply2reply mode
Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
2025-02-03 10:20:30 +08:00
bggRGjQaUbCoE
994199b5a2 fix: check reply
Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
2025-02-02 23:44:47 +08:00
bggRGjQaUbCoE
8db3d80151 fix: onVideoDetailChange
Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
2025-02-02 22:29:25 +08:00
bggRGjQaUbCoE
93af1e7c44 opt: reply check
Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
2025-02-02 22:29:10 +08:00
dom
54e90bd986 feat: comment antifraud (#193)
Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
2025-02-02 21:24:07 +08:00
bggRGjQaUbCoE
ca16551917 mod: dm chart height
Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
2025-02-02 17:18:21 +08:00
bggRGjQaUbCoE
f4977d2855 mod: def hardwareDecoding
Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
2025-02-01 18:04:16 +08:00
bggRGjQaUbCoE
bd91fb7c6d mod: show volume when hiding sysui for ios
Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
2025-02-01 17:59:22 +08:00
bggRGjQaUbCoE
e1805896f4 Revert "opt: dm chart"
This reverts commit 31a639400e.
2025-01-31 20:40:18 +08:00
bggRGjQaUbCoE
31a639400e opt: dm chart
Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
2025-01-31 16:20:59 +08:00
bggRGjQaUbCoE
d6b24561fa fix: dm chart x
Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
2025-01-31 13:32:07 +08:00
dom
7ba9646d38 feat: danmaku chart (#192)
Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
2025-01-31 11:36:05 +08:00
bggRGjQaUbCoE
58a7cf1e75 fix: image preview
Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
2025-01-30 18:03:15 +08:00
bggRGjQaUbCoE
1a327198f7 opt: video: onreset
Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
2025-01-30 15:52:59 +08:00
bggRGjQaUbCoE
e4fe91ef92 Update README.md
Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
2025-01-30 14:22:20 +08:00
bggRGjQaUbCoE
afcf817c4f fix: video duration
Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
2025-01-30 13:57:21 +08:00
bggRGjQaUbCoE
21550815db fix: seek preview image
Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
2025-01-30 12:11:44 +08:00
bggRGjQaUbCoE
02af3a18ff opt: video seek preview
Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
2025-01-30 10:08:15 +08:00
bggRGjQaUbCoE
a5a13b45cf fix: seek preview index
Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
2025-01-29 23:45:10 +08:00
bggRGjQaUbCoE
0fd232ab3a feat: video seek preview
Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
2025-01-29 21:20:58 +08:00
bggRGjQaUbCoE
8d83143ca6 opt: fav
Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
2025-01-29 15:29:20 +08:00
bggRGjQaUbCoE
74452cd622 mod: save as livephoto for ios
Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
2025-01-29 12:07:00 +08:00
bggRGjQaUbCoE
cf2e8cec54 fix: horizontal preview
Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
2025-01-28 23:27:46 +08:00
bggRGjQaUbCoE
5231faf254 opt: pages
Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
2025-01-28 21:57:57 +08:00
bggRGjQaUbCoE
959d4de78a opt: image preview
Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
2025-01-28 18:33:40 +08:00
bggRGjQaUbCoE
f5d7dc6b6a feat: live photo
Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
2025-01-28 15:40:19 +08:00
bggRGjQaUbCoE
b761c35d10 mod: show pendant/decorate
Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
2025-01-28 10:18:57 +08:00
bggRGjQaUbCoE
7f3f7f6bdd mod: dyn author panel
Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
2025-01-27 21:50:35 +08:00
bggRGjQaUbCoE
c5877b7c5e feat: custom show dyn decorate
Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
2025-01-27 21:21:28 +08:00
bggRGjQaUbCoE
9e4187ef17 mod: fetch only-fans dyn
Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
2025-01-27 18:01:32 +08:00
bggRGjQaUbCoE
bf7ce3e5a2 mod: delay reloading fav
Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
2025-01-27 17:04:25 +08:00
bggRGjQaUbCoE
2c55314491 fix: dialog title
Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
2025-01-27 16:21:00 +08:00
bggRGjQaUbCoE
d28efef672 feat: copy/move toview
Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
2025-01-27 15:17:11 +08:00
bggRGjQaUbCoE
49b631d560 feat: copy/move fav
Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
2025-01-27 14:59:00 +08:00
bggRGjQaUbCoE
896510f852 mod: fav sheet
Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
2025-01-27 13:39:33 +08:00
bggRGjQaUbCoE
1d8e469a46 feat: clean fav
Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
2025-01-27 13:26:31 +08:00
bggRGjQaUbCoE
caee40a5d9 mod: sr desc
Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
2025-01-27 11:52:45 +08:00
bggRGjQaUbCoE
7de051e6bb fix: skip listener
Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
2025-01-26 20:55:29 +08:00
bggRGjQaUbCoE
18cec3c752 mod: update android icon
Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
2025-01-26 15:22:31 +08:00
bggRGjQaUbCoE
3b46655051 fix: cdn test
Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
2025-01-26 13:06:45 +08:00
bggRGjQaUbCoE
f72ad572fb fix: cdn test
Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
2025-01-26 11:50:08 +08:00
bggRGjQaUbCoE
a57ea2adb6 mod: remove androidNotificationIcon tmply
Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
2025-01-25 22:00:26 +08:00
504 changed files with 36661 additions and 24984 deletions

View File

@@ -1,23 +0,0 @@
---
name: Bug 反馈
about: 描述你所遇到的bug
title: "[Bug] "
labels: bug
assignees: ''
---
### 问题描述
请提供一个清晰而简明的问题描述。
### 复现步骤
请提供复现该问题所需的具体步骤。
### 预期行为
请描述你期望的正确行为或结果。
### 错误日志
请提供设置->关于->错误日志中的内容粘贴在下方代码框中。如果没有请提供您的app版本号、系统版本、设备型号等相关信息。
### 相关信息
请补充截图、录屏、BV号等其他有助于解决问题的信息。

55
.github/ISSUE_TEMPLATE/bug-反馈.yml vendored Normal file
View File

@@ -0,0 +1,55 @@
name: Bug 反馈
description: 描述你所遇到的bug
labels: [ "bug" ]
title: "[Bug] "
body:
- type: checkboxes
id: checklist
attributes:
label: 检查清单
options:
- label: 之前没有人提交过类似或相同的 bug report。1
required: true
- label: 之前没有人提交过类似或相同的 bug report。2
required: true
- label: 之前没有人提交过类似或相同的 bug report。3
required: true
- label: 正在使用最新版本。
required: true
- type: textarea
id: bug
attributes:
label: 问题描述
description: 请提供一个清晰而简明的问题描述。
validations:
required: true
- type: textarea
id: steps
attributes:
label: 复现步骤
description: 请提供复现该问题所需的具体步骤。
validations:
required: true
- type: textarea
id: expected
attributes:
label: 预期行为
description: 请描述你期望的正确行为或结果。
validations:
required: true
- type: textarea
id: log
attributes:
label: 错误日志
description: 请提供设置->关于->错误日志中的内容粘贴在下方代码框中。如果没有请提供您的app版本号、系统版本、设备型号等相关信息。
- type: textarea
id: info
attributes:
label: 相关信息
description: 请补充截图、录屏、BV号等其他有助于解决问题的信息。

View File

@@ -1,20 +0,0 @@
---
name: 功能请求
about: 对于功能的一些建议
title: "[FR] "
labels: enhancement
assignees: ''
---
### 功能描述
请提供对所请求功能的清晰描述。
### 目标
请描述你希望通过这个功能实现的目标。
### 解决方案
如果你有任何关于如何实现这个功能的想法或建议,请在这里提供。
### 其他
请提供已实现该功能或类似功能的应用

43
.github/ISSUE_TEMPLATE/功能请求.yml vendored Normal file
View File

@@ -0,0 +1,43 @@
name: 功能请求
description: 对于功能的一些建议
labels: [ "enhancement" ]
title: "[FR] "
body:
- type: checkboxes
id: checklist
attributes:
label: 检查清单
options:
- label: 之前没有人提交过类似或相同的功能请求。
required: true
- label: 正在使用最新版本。
required: true
- type: textarea
id: desc
attributes:
label: 功能描述
description: 请提供对所请求功能的清晰描述。
validations:
required: true
- type: textarea
id: propose
attributes:
label: 目标
description: 请描述你希望通过这个功能实现的目标。
validations:
required: true
- type: textarea
id: solution
attributes:
label: 解决方案
description: 如果你有任何关于如何实现这个功能的想法或建议,请在这里提供。
- type: textarea
id: addition
attributes:
label: 其他
description: 请提供已实现该功能或类似功能的应用

View File

@@ -47,6 +47,27 @@
## feat
- [x] 直播弹幕发送表情
- [x] 收藏夹排序
- [x] 稍后再看`未看`/`未看完`/`已看完`分类
- [x] WebDAV 备份/恢复设置
- [x] 保存评论/动态
- [x] 高级弹幕 by [@My-Responsitories](https://github.com/My-Responsitories)
- [x] 取消/置顶评论
- [x] 记笔记
- [x] 多账号支持 by [@My-Responsitories](https://github.com/My-Responsitories)
- [x] 屏蔽带货动态/评论
- [x] 互动视频
- [x] 发评/动态反诈
- [x] 高能进度条
- [x] 滑动跳转预览视频缩略图
- [x] Live Photo
- [x] 复制/移动/排序收藏夹/稍后再看视频
- [x] 超分辨率
- [x] 合并弹幕
- [x] 会员彩色弹幕
- [x] 播放全部/继续播放/倒序播放
- [x] Cookie登录
- [x] 显示视频分段信息
- [x] 调节字幕大小
- [x] 调节全屏弹幕大小
@@ -59,7 +80,6 @@
- [x] 评论楼中楼定位点击查看的评论
- [x] 评论楼中楼按热度/时间排序
- [x] 评论点踩
- [x] 显示ops专栏
- [x] 私信发图
- [x] 投币动画
- [x] 取消/追番,更新追番状态
@@ -73,8 +93,8 @@
- [x] 筛选搜索
- [x] 转发动态
- [x] 合集图片
- [x] 删除/置顶私信
- [x] 举报用户/评论/视频
- [x] 删除/置顶/撤回私信
- [x] 举报用户/评论/视频/动态
- [x] 删除/发布文本/图片动态
- [x] 其他
@@ -144,7 +164,6 @@
- [x] 音质选择(视视频而定)
- [x] 解码格式选择(视视频而定)
- [x] 弹幕
- [ ] 直播弹幕
- [x] 字幕
- [x] 记忆播放
- [x] 视频比例:高度/宽度适应、填充、包含等

View File

@@ -1,132 +0,0 @@
<manifest
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
package="com.example.piliplus">
<!-- The INTERNET permission is required for development. Specifically,
the Flutter tool needs it to communicate with the running application
to allow setting breakpoints, to provide hot reload, etc.
-->
<uses-permission
android:name="android.permission.INTERNET"
/>
<application
android:label="PiliPlus Debug"
tools:replace="android:label">
<activity
android:name=".MainActivity"
android:exported="true"
android:launchMode="singleTask"
android:theme="@style/LaunchTheme"
android:configChanges="orientation|keyboardHidden|keyboard|screenSize|smallestScreenSize|locale|layoutDirection|fontScale|screenLayout|density|uiMode"
android:hardwareAccelerated="true"
android:windowSoftInputMode="adjustResize"
android:supportsPictureInPicture="true"
android:resizeableActivity="true"
>
<!-- Specifies an Android theme to apply to this Activity as soon as
the Android process has started. This theme is visible to the user
while the Flutter UI initializes. After that, this theme continues
to determine the Window background behind the Flutter UI. -->
<meta-data
android:name="io.flutter.embedding.android.NormalTheme"
android:resource="@style/NormalTheme"
/>
<intent-filter>
<action android:name="android.intent.action.MAIN"/>
<category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
<intent-filter android:label="PiliPlus Debug">
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />
<data android:scheme="http"/>
<data android:scheme="https"/>
<data android:host="*.bilibili.com"/>
<data android:host="*.bilibili.cn"/>
<data android:host="*.bilibili.tv"/>
<data android:host="bilibili.com"/>
<data android:host="bilibili.cn"/>
<data android:host="bilibili.tv"/>
<data android:host="b23.tv" />
<!--<data android:host="live.bilibili.com"/>-->
<!--<data android:host="www.bilibili.com"/>-->
<!--<data android:host="www.bilibili.tv"/>-->
<!--<data android:host="www.bilibili.cn"/>-->
<!--<data android:host="m.bilibili.cn"/>-->
<!--<data android:host="m.bilibili.com"/>-->
<!--<data android:host="bilibili.cn"/>-->
<!--<data android:host="bilibili.com"/>-->
<!--<data android:host="bangumi.bilibili.com"/>-->
<!--<data android:host="space.bilibili.com"/>-->
</intent-filter>
<intent-filter android:label="PiliPlus Debug">
<action android:name="android.intent.action.VIEW" />
<action android:name="android.intent.action.SEARCH" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />
<data android:scheme="bilibili"/>
<data android:host="forward" />
<data android:host="comment"
android:pathPattern="/detail/.*/.*/.*" />
<data android:host="uper" />
<data android:host="article"
android:pathPattern="/readlist" />
<data android:host="advertise" android:path="/home" />
<data android:host="clip" />
<data android:host="search" />
<data android:host="stardust-search" />
<data android:host="music" />
<data android:host="bangumi"
android:pathPattern="/season.*" />
<data android:host="bangumi" android:pathPattern="/.*" />
<data android:host="pictureshow"
android:pathPrefix="/creative_center" />
<data android:host="cliparea" />
<data android:host="im" />
<data android:host="im" android:path="/notifications" />
<data android:host="following" />
<data android:host="following"
android:pathPattern="/detail/.*" />
<data android:host="following"
android:path="/publishInfo/" />
<data android:host="laser" android:pathPattern="/.*" />
<data android:host="livearea" />
<data android:host="live" />
<data android:host="catalog" />
<data android:host="browser" />
<data android:host="user_center" />
<data android:host="login" />
<data android:host="space" />
<data android:host="author" />
<data android:host="tag" />
<data android:host="rank" />
<data android:host="external" />
<data android:host="blank" />
<data android:host="home" />
<data android:host="root" />
<data android:host="video" />
<data android:host="story" />
<data android:host="podcast" />
<data android:host="search" />
<data android:host="main" android:path="/favorite" />
<data android:host="pgc" android:path="/theater/match" />
<data android:host="pgc" android:path="/theater/square" />
<data android:host="m.bilibili.com"
android:path="/topic-detail" />
<data android:host="article" />
<data android:host="pegasus"
android:pathPattern="/channel/v2/.*" />
<data android:host="feed" android:pathPattern="/channel" />
<data android:host="vip" />
<data android:host="user_center" android:path="/vip" />
<data android:host="history" />
<data android:host="charge" android:path="/rank" />
<data android:host="assistant" />
<data android:host="assistant" />
<data android:host="feedback" />
<data android:host="auth" android:path="/launch" />
</intent-filter>
</activity>
</application>
</manifest>

View File

@@ -1,16 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:height="512dp"
android:width="512dp"
android:viewportWidth="512.0"
android:viewportHeight="512.0">
<path
android:fillColor="#FF5CB67B"
android:pathData="M456.65,256C456.65,366.81 366.81,456.65 256,456.65 145.19,456.65 55.35,366.81 55.35,256 55.35,145.18 145.19,55.35 256,55.35 366.81,55.35 456.65,145.18 456.65,256Z"
android:strokeWidth="0.783784"
android:fillType="evenOdd" />
<path
android:fillColor="#FFFFFFFF"
android:pathData="M270.04,256L156.1,256l15.61,-76.8h98.32c21.21,0 38.4,17.19 38.4,38.4 0,21.21 -17.19,38.4 -38.4,38.4zM270.04,128L202.46,128l-50.1,256h52.76l15.18,-76.8h49.73c49.49,0 89.6,-40.12 89.6,-89.6 0,-49.49 -40.11,-89.6 -89.6,-89.6z"
android:fillType="evenOdd" />
</vector>

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.0 KiB

View File

@@ -1,4 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<color name="ic_launcher_background">#FF5CB67B</color>
</resources>

View File

@@ -4,10 +4,13 @@ import io.flutter.embedding.android.FlutterActivity
import io.flutter.embedding.engine.FlutterEngine
import io.flutter.plugin.common.MethodChannel
import com.ryanheise.audioservice.AudioServiceActivity
import android.content.ComponentName
import android.content.Intent
import android.content.res.Configuration
import android.net.Uri
import android.os.Build
import android.os.Bundle
import android.provider.Settings
import android.view.WindowManager.LayoutParams
import kotlin.system.exitProcess
@@ -21,6 +24,55 @@ class MainActivity : AudioServiceActivity() {
methodChannel.setMethodCallHandler { call, result ->
if (call.method == "back") {
back()
} else if (call.method == "biliSendCommAntifraud") {
try {
val action = call.argument<Int>("action") ?: 0
val oid = call.argument<Number>("oid") ?: 0L
val type = call.argument<Int>("type") ?: 0
val rpid = call.argument<Number>("rpid") ?: 0L
val root = call.argument<Number>("root") ?: 0L
val parent = call.argument<Number>("parent") ?: 0L
val ctime = call.argument<Number>("ctime") ?: 0L
val commentText = call.argument<String>("comment_text") ?: ""
val pictures = call.argument<String?>("pictures")
val sourceId = call.argument<String>("source_id") ?: ""
val uid = call.argument<Number>("uid") ?: 0L
val cookies = call.argument<List<String>>("cookies") ?: emptyList<String>()
val intent = Intent().apply {
component = ComponentName("icu.freedomIntrovert.biliSendCommAntifraud", "icu.freedomIntrovert.biliSendCommAntifraud.ByXposedLaunchedActivity")
putExtra("action", action)
putExtra("oid", oid.toLong())
putExtra("type", type)
putExtra("rpid", rpid.toLong())
putExtra("root", root.toLong())
putExtra("parent", parent.toLong())
putExtra("ctime", ctime.toLong())
putExtra("comment_text", commentText)
if(pictures != null)
putExtra("pictures", pictures)
putExtra("source_id", sourceId)
putExtra("uid", uid.toLong())
putStringArrayListExtra("cookies", ArrayList(cookies))
}
startActivity(intent)
} catch (e: Exception) {}
} else if (call.method == "linkVerifySettings") {
try {
val intent = Intent(android.provider.Settings.ACTION_APP_OPEN_BY_DEFAULT_SETTINGS,
Uri.parse("package:" + context.packageName))
context.startActivity(intent)
} catch (t: Throwable) {
try {
val intent = Intent("android.intent.action.MAIN", Uri.parse("package:" + context.packageName))
intent.setClassName("com.android.settings", "com.android.settings.applications.InstalledAppOpenByDefaultActivity")
context.startActivity(intent)
} catch (t2: Throwable) {
val intent = Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS,
Uri.parse("package:" + context.packageName))
context.startActivity(intent)
}
}
} else {
result.notImplemented()
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.9 KiB

After

Width:  |  Height:  |  Size: 2.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.9 KiB

After

Width:  |  Height:  |  Size: 2.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.0 KiB

After

Width:  |  Height:  |  Size: 3.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.0 KiB

After

Width:  |  Height:  |  Size: 1.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.0 KiB

After

Width:  |  Height:  |  Size: 1.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.5 KiB

After

Width:  |  Height:  |  Size: 2.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.0 KiB

After

Width:  |  Height:  |  Size: 3.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.5 KiB

After

Width:  |  Height:  |  Size: 2.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 9.2 KiB

After

Width:  |  Height:  |  Size: 4.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 14 KiB

After

Width:  |  Height:  |  Size: 6.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 18 KiB

After

Width:  |  Height:  |  Size: 8.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.8 KiB

After

Width:  |  Height:  |  Size: 3.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.8 KiB

After

Width:  |  Height:  |  Size: 3.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 9.2 KiB

After

Width:  |  Height:  |  Size: 4.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 12 KiB

After

Width:  |  Height:  |  Size: 5.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 12 KiB

After

Width:  |  Height:  |  Size: 5.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 14 KiB

After

Width:  |  Height:  |  Size: 6.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 16 KiB

After

Width:  |  Height:  |  Size: 7.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 16 KiB

After

Width:  |  Height:  |  Size: 7.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 18 KiB

After

Width:  |  Height:  |  Size: 8.8 KiB

View File

@@ -1,16 +1,11 @@
<?xml version="1.0" encoding="utf-8"?>
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:height="512dp"
android:width="512dp"
android:viewportWidth="512.0"
android:viewportHeight="512.0">
android:height="108dp"
android:width="108dp"
android:viewportWidth="108.0"
android:viewportHeight="108.0">
<path
android:fillColor="#FF5CB67B"
android:pathData="M456.65,256C456.65,366.81 366.81,456.65 256,456.65 145.19,456.65 55.35,366.81 55.35,256 55.35,145.18 145.19,55.35 256,55.35 366.81,55.35 456.65,145.18 456.65,256Z"
android:strokeWidth="0.783784"
android:fillColor="@color/ic_launcher_foreground"
android:pathData="M56,54L39.78,54l2.22,-10.94h14c3.02,0 5.47,2.45 5.47,5.47 0,3.02 -2.45,5.47 -5.47,5.47zM56,35.77h-9.62l-7.13,36.45h7.51L48.92,61.29h7.08c7.05,0 12.76,-5.71 12.76,-12.76 0,-7.05 -5.71,-12.76 -12.76,-12.76z"
android:fillType="evenOdd" />
<path
android:fillColor="#FFFFFFFF"
android:pathData="M270.04,256L156.1,256l15.61,-76.8h98.32c21.21,0 38.4,17.19 38.4,38.4 0,21.21 -17.19,38.4 -38.4,38.4zM270.04,128L202.46,128l-50.1,256h52.76l15.18,-76.8h49.73c49.49,0 89.6,-40.12 89.6,-89.6 0,-49.49 -40.11,-89.6 -89.6,-89.6z"
android:fillType="evenOdd" />
</vector>
</vector>

View File

@@ -1,16 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:height="512dp"
android:width="512dp"
android:viewportWidth="512.0"
android:viewportHeight="512.0">
<path
android:fillColor="#FF5CB67B"
android:pathData="M456.65,256C456.65,366.81 366.81,456.65 256,456.65 145.19,456.65 55.35,366.81 55.35,256 55.35,145.18 145.19,55.35 256,55.35 366.81,55.35 456.65,145.18 456.65,256Z"
android:strokeWidth="0.783784"
android:fillType="evenOdd" />
<path
android:fillColor="#FFFFFFFF"
android:pathData="M270.04,256L156.1,256l15.61,-76.8h98.32c21.21,0 38.4,17.19 38.4,38.4 0,21.21 -17.19,38.4 -38.4,38.4zM270.04,128L202.46,128l-50.1,256h52.76l15.18,-76.8h49.73c49.49,0 89.6,-40.12 89.6,-89.6 0,-49.49 -40.11,-89.6 -89.6,-89.6z"
android:fillType="evenOdd" />
</vector>

View File

@@ -2,15 +2,11 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:height="24dp"
android:width="24dp"
android:viewportWidth="512.0"
android:viewportHeight="512.0">
android:viewportWidth="108.0"
android:viewportHeight="108.0">
<path
android:fillColor="#FF5CB67B"
android:pathData="M456.65,256C456.65,366.81 366.81,456.65 256,456.65 145.19,456.65 55.35,366.81 55.35,256 55.35,145.18 145.19,55.35 256,55.35 366.81,55.35 456.65,145.18 456.65,256Z"
android:strokeWidth="0.783784"
android:fillType="evenOdd" />
<path
android:fillColor="#FFFFFFFF"
android:pathData="M270.04,256L156.1,256l15.61,-76.8h98.32c21.21,0 38.4,17.19 38.4,38.4 0,21.21 -17.19,38.4 -38.4,38.4zM270.04,128L202.46,128l-50.1,256h52.76l15.18,-76.8h49.73c49.49,0 89.6,-40.12 89.6,-89.6 0,-49.49 -40.11,-89.6 -89.6,-89.6z"
android:pathData="M57.54,54L28.82,54l3.93,-19.36h24.78c5.35,0 9.68,4.33 9.68,9.68 0,5.35 -4.33,9.68 -9.68,9.68zM57.54,21.73L40.5,21.73L27.88,86.27h13.3l3.83,-19.36h12.54c12.48,0 22.59,-10.11 22.59,-22.59 0,-12.48 -10.11,-22.59 -22.59,-22.59z"
android:strokeWidth="0.252073"
android:fillType="evenOdd" />
</vector>

View File

@@ -1,14 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
<background android:drawable="@color/ic_launcher_background"/>
<foreground>
<inset
android:drawable="@drawable/ic_launcher_foreground"
android:inset="16%" />
</foreground>
<monochrome>
<inset
android:drawable="@drawable/ic_launcher_monochrome"
android:inset="16%" />
</monochrome>
</adaptive-icon>
<background android:drawable="@color/ic_launcher_background"/>
<foreground android:drawable="@drawable/ic_launcher_foreground"/>
<monochrome android:drawable="@drawable/ic_launcher_foreground" />
</adaptive-icon>

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.7 KiB

After

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.8 KiB

After

Width:  |  Height:  |  Size: 914 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.5 KiB

After

Width:  |  Height:  |  Size: 1.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.3 KiB

After

Width:  |  Height:  |  Size: 2.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.0 KiB

After

Width:  |  Height:  |  Size: 3.4 KiB

View File

@@ -0,0 +1,3 @@
<?xml version="1.0" encoding="utf-8"?>
<resources xmlns:tools="http://schemas.android.com/tools"
tools:keep="@drawable/*" />

View File

@@ -0,0 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<color name="ic_launcher_foreground">@android:color/system_accent1_100</color>
<color name="ic_launcher_background">@android:color/system_neutral1_800</color>
</resources>

View File

@@ -0,0 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<color name="ic_launcher_foreground">@android:color/system_neutral2_700</color>
<color name="ic_launcher_background">@android:color/system_accent1_100</color>
</resources>

View File

@@ -1,4 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<color name="ic_launcher_background">#FF5CB67B</color>
<color name="ic_launcher_foreground">#FF5CB67B</color>
<color name="ic_launcher_background">#FFFFFFFF</color>
</resources>

View File

@@ -18,19 +18,33 @@ subprojects {
afterEvaluate { project ->
if (project.extensions.findByName("android") != null) {
Integer pluginCompileSdk = project.android.compileSdk
if (pluginCompileSdk != null && pluginCompileSdk < 31) {
project.logger.error(
"Warning: Overriding compileSdk version in Flutter plugin: "
+ project.name
+ " from "
+ pluginCompileSdk
+ " to 31 (to work around https://issuetracker.google.com/issues/199180389)."
+ "\nIf there is not a new version of " + project.name + ", consider filing an issue against "
+ project.name
+ " to increase their compileSdk to the latest (otherwise try updating to the latest version)."
)
project.android {
compileSdk 31
if (pluginCompileSdk != null) {
if (pluginCompileSdk < 31) {
project.logger.error(
"Warning: Overriding compileSdk version in Flutter plugin: "
+ project.name
+ " from "
+ pluginCompileSdk
+ " to 31 (to work around https://issuetracker.google.com/issues/199180389)."
+ "\nIf there is not a new version of " + project.name + ", consider filing an issue against "
+ project.name
+ " to increase their compileSdk to the latest (otherwise try updating to the latest version)."
)
project.android {
compileSdk 31
}
}
if (pluginCompileSdk > 34) {
project.logger.error(
"Warning: Overriding compileSdk version in Flutter plugin: "
+ project.name
+ " from "
+ pluginCompileSdk
+ " to 34"
)
project.android {
compileSdk 34
}
}
}
}

Binary file not shown.

Binary file not shown.

After

Width:  |  Height:  |  Size: 24 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 514 B

After

Width:  |  Height:  |  Size: 915 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 524 B

After

Width:  |  Height:  |  Size: 876 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 518 B

After

Width:  |  Height:  |  Size: 1.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 541 B

After

Width:  |  Height:  |  Size: 991 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 498 B

After

Width:  |  Height:  |  Size: 912 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 539 B

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 517 B

After

Width:  |  Height:  |  Size: 1.1 KiB

BIN
assets/images/lv/lv6_s.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

View File

@@ -23,246 +23,251 @@ class Constants {
static const String userAgent =
'Mozilla/5.0 BiliDroid/1.46.2 (bbcallen@gmail.com) os/android model/vivo mobi_app/android_hd build/2001100 channel/yingyongbao innerVer/2001100 osVer/14 network/2';
static const String statistics =
'%7B%22appId%22%3A5%2C%22platform%22%3A3%2C%22version%22%3A%221.46.2%22%2C%22abtest%22%3A%22%22%7D';
//Uri.encodeComponent('{"appId": 5,"platform": 3,"version": "1.46.2","abtest": ""}');
'{"appId":5,"platform":3,"version":"1.46.2","abtest":""}';
// 请求时会自动encodeComponent
// 超分辨率滤镜
static const List<String> mpvAnime4KShaders = [
'Anime4K_Clamp_Highlights.glsl',
'Anime4K_Restore_CNN_VL.glsl',
'Anime4K_Upscale_CNN_x2_VL.glsl',
'Anime4K_AutoDownscalePre_x2.glsl',
'Anime4K_AutoDownscalePre_x4.glsl',
'Anime4K_Upscale_CNN_x2_M.glsl'
];
static const urlPattern =
r'https?://[-A-Za-z0-9+&@#/%?=~_|!:,.;]+[-A-Za-z0-9+&@#/%=~_|]';
static get goodsUrlPrefix => "https://gaoneng.bilibili.com/tetris";
// 超分辨率滤镜
static List<String> get mpvAnime4KShaders => [
'Anime4K_Clamp_Highlights.glsl',
'Anime4K_Restore_CNN_VL.glsl',
'Anime4K_Upscale_CNN_x2_VL.glsl',
'Anime4K_AutoDownscalePre_x2.glsl',
'Anime4K_AutoDownscalePre_x4.glsl',
'Anime4K_Upscale_CNN_x2_M.glsl'
];
// 超分辨率滤镜 (轻量)
static const List<String> mpvAnime4KShadersLite = [
'Anime4K_Clamp_Highlights.glsl',
'Anime4K_Restore_CNN_M.glsl',
'Anime4K_Restore_CNN_S.glsl',
'Anime4K_Upscale_CNN_x2_M.glsl',
'Anime4K_AutoDownscalePre_x2.glsl',
'Anime4K_AutoDownscalePre_x4.glsl',
'Anime4K_Upscale_CNN_x2_S.glsl'
];
static List<String> get mpvAnime4KShadersLite => [
'Anime4K_Clamp_Highlights.glsl',
'Anime4K_Restore_CNN_M.glsl',
'Anime4K_Restore_CNN_S.glsl',
'Anime4K_Upscale_CNN_x2_M.glsl',
'Anime4K_AutoDownscalePre_x2.glsl',
'Anime4K_AutoDownscalePre_x4.glsl',
'Anime4K_Upscale_CNN_x2_S.glsl'
];
//内容来自 https://passport.bilibili.com/web/generic/country/list
static const List<Map<String, dynamic>> internationalDialingPrefix = [
{"id": 1, "cname": "中国大陆", "country_id": "86"},
{"id": 5, "cname": "中国香港特别行政区", "country_id": "852"},
{"id": 2, "cname": "中国澳门特别行政区", "country_id": "853"},
{"id": 3, "cname": "中国台湾", "country_id": "886"},
{"id": 4, "cname": "美国", "country_id": "1"},
{"id": 6, "cname": "比利时", "country_id": "32"},
{"id": 7, "cname": "澳大利亚", "country_id": "61"},
{"id": 8, "cname": "法国", "country_id": "33"},
{"id": 9, "cname": "加拿大", "country_id": "1"},
{"id": 10, "cname": "日本", "country_id": "81"},
{"id": 11, "cname": "新加坡", "country_id": "65"},
{"id": 12, "cname": "韩国", "country_id": "82"},
{"id": 13, "cname": "马来西亚", "country_id": "60"},
{"id": 14, "cname": "英国", "country_id": "44"},
{"id": 15, "cname": "意大利", "country_id": "39"},
{"id": 16, "cname": "德国", "country_id": "49"},
{"id": 18, "cname": "俄罗斯", "country_id": "7"},
{"id": 19, "cname": "新西兰", "country_id": "64"}, //common:1-19
{"id": 153, "cname": "瓦利斯群岛和富图纳群岛", "country_id": "1681"},
{"id": 152, "cname": "葡萄牙", "country_id": "351"},
{"id": 151, "cname": "帕劳", "country_id": "680"},
{"id": 150, "cname": "诺福克岛", "country_id": "672"},
{"id": 149, "cname": "挪威", "country_id": "47"},
{"id": 148, "cname": "纽埃岛", "country_id": "683"},
{"id": 147, "cname": "尼日利亚", "country_id": "234"},
{"id": 146, "cname": "尼日尔", "country_id": "227"},
{"id": 145, "cname": "尼加拉瓜", "country_id": "505"},
{"id": 144, "cname": "尼泊尔", "country_id": "977"},
{"id": 143, "cname": "瑙鲁", "country_id": "674"},
{"id": 154, "cname": "格鲁吉亚", "country_id": "995"},
{"id": 155, "cname": "瑞典", "country_id": "46"},
{"id": 165, "cname": "沙特阿拉伯", "country_id": "966"},
{"id": 164, "cname": "桑给巴尔岛", "country_id": "259"},
{"id": 163, "cname": "塞舌尔共和国", "country_id": "248"},
{"id": 162, "cname": "塞浦路斯", "country_id": "357"},
{"id": 161, "cname": "塞内加尔", "country_id": "221"},
{"id": 160, "cname": "塞拉利昂", "country_id": "232"},
{"id": 159, "cname": "萨摩亚,东部", "country_id": "684"},
{"id": 158, "cname": "萨摩亚,西部", "country_id": "685"},
{"id": 157, "cname": "萨尔瓦多", "country_id": "503"},
{"id": 156, "cname": "瑞士", "country_id": "41"},
{"id": 166, "cname": "圣多美和普林西比", "country_id": "239"},
{"id": 142, "cname": "塞尔维亚", "country_id": "381"},
{"id": 141, "cname": "南非", "country_id": "27"},
{"id": 128, "cname": "毛里塔尼亚", "country_id": "222"},
{"id": 127, "cname": "毛里求斯", "country_id": "230"},
{"id": 126, "cname": "马歇尔岛", "country_id": "692"},
{"id": 125, "cname": "马提尼克岛", "country_id": "596"},
{"id": 124, "cname": "马其顿", "country_id": "389"},
{"id": 123, "cname": "马里亚纳岛", "country_id": "1670"},
{"id": 122, "cname": "马里", "country_id": "223"},
{"id": 121, "cname": "马拉维", "country_id": "265"},
{"id": 120, "cname": "马耳他", "country_id": "356"},
{"id": 119, "cname": "马尔代夫", "country_id": "960"},
{"id": 129, "cname": "蒙古", "country_id": "976"},
{"id": 130, "cname": "蒙特塞拉特岛", "country_id": "1664"},
{"id": 140, "cname": "纳米比亚", "country_id": "264"},
{"id": 139, "cname": "墨西哥", "country_id": "52"},
{"id": 138, "cname": "莫桑比克", "country_id": "258"},
{"id": 137, "cname": "摩纳哥", "country_id": "377"},
{"id": 136, "cname": "摩洛哥", "country_id": "212"},
{"id": 135, "cname": "摩尔多瓦", "country_id": "373"},
{"id": 134, "cname": "缅甸", "country_id": "95"},
{"id": 133, "cname": "密克罗尼西亚", "country_id": "691"},
{"id": 132, "cname": "秘鲁", "country_id": "51"},
{"id": 131, "cname": "孟加拉国", "country_id": "880"},
{"id": 118, "cname": "马达加斯加", "country_id": "261"},
{"id": 167, "cname": "圣卢西亚", "country_id": "1784"},
{"id": 216, "cname": "智利", "country_id": "56"},
{"id": 203, "cname": "牙买加", "country_id": "1876"},
{"id": 202, "cname": "叙利亚", "country_id": "963"},
{"id": 201, "cname": "匈牙利", "country_id": "36"},
{"id": 200, "cname": "科特迪瓦", "country_id": "225"},
{"id": 199, "cname": "希腊", "country_id": "30"},
{"id": 198, "cname": "西班牙", "country_id": "34"},
{"id": 197, "cname": "乌兹别克斯坦", "country_id": "998"},
{"id": 196, "cname": "乌拉圭", "country_id": "598"},
{"id": 195, "cname": "乌克兰", "country_id": "380"},
{"id": 194, "cname": "乌干达", "country_id": "256"},
{"id": 204, "cname": "亚美尼亚", "country_id": "374"},
{"id": 205, "cname": "也门", "country_id": "967"},
{"id": 215, "cname": "直布罗陀", "country_id": "350"},
{"id": 214, "cname": "乍得", "country_id": "235"},
{"id": 213, "cname": "赞比亚", "country_id": "260"},
{"id": 212, "cname": "越南", "country_id": "84"},
{"id": 211, "cname": "约旦", "country_id": "962"},
{"id": 210, "cname": "印尼", "country_id": "62"},
{"id": 209, "cname": "印度", "country_id": "91"},
{"id": 208, "cname": "以色列", "country_id": "972"},
{"id": 207, "cname": "伊朗", "country_id": "98"},
{"id": 206, "cname": "伊拉克", "country_id": "964"},
{"id": 193, "cname": "文莱", "country_id": "673"},
{"id": 192, "cname": "委内瑞拉", "country_id": "58"},
{"id": 191, "cname": "维珍群岛(英属)", "country_id": "1284"},
{"id": 178, "cname": "泰国", "country_id": "66"},
{"id": 177, "cname": "索马里", "country_id": "252"},
{"id": 176, "cname": "所罗门群岛", "country_id": "677"},
{"id": 175, "cname": "苏里南", "country_id": "597"},
{"id": 174, "cname": "苏丹", "country_id": "249"},
{"id": 173, "cname": "斯威士兰", "country_id": "268"},
{"id": 172, "cname": "斯洛文尼亚", "country_id": "386"},
{"id": 171, "cname": "斯洛伐克", "country_id": "421"},
{"id": 170, "cname": "斯里兰卡", "country_id": "94"},
{"id": 169, "cname": "圣皮埃尔和密克隆群岛", "country_id": "508"},
{"id": 179, "cname": "坦桑尼亚", "country_id": "255"},
{"id": 180, "cname": "汤加", "country_id": "676"},
{"id": 190, "cname": "维珍群岛(美属)", "country_id": "1340"},
{"id": 189, "cname": "瓦努阿图", "country_id": "678"},
{"id": 188, "cname": "托克劳岛", "country_id": "690"},
{"id": 187, "cname": "土库曼斯坦", "country_id": "993"},
{"id": 186, "cname": "土耳其", "country_id": "90"},
{"id": 185, "cname": "图瓦卢", "country_id": "688"},
{"id": 184, "cname": "突尼斯", "country_id": "216"},
{"id": 183, "cname": "阿森松岛", "country_id": "247"},
{"id": 182, "cname": "特立尼达和多巴哥", "country_id": "1868"},
{"id": 181, "cname": "特克斯和凯科斯", "country_id": "1649"},
{"id": 168, "cname": "圣马力诺", "country_id": "378"},
{"id": 67, "cname": "法属圭亚那", "country_id": "594"},
{"id": 54, "cname": "不丹", "country_id": "975"},
{"id": 53, "cname": "博茨瓦纳", "country_id": "267"},
{"id": 52, "cname": "伯利兹", "country_id": "501"},
{"id": 51, "cname": "玻利维亚", "country_id": "591"},
{"id": 50, "cname": "波兰", "country_id": "48"},
{"id": 49, "cname": "波黑", "country_id": "387"},
{"id": 48, "cname": "波多黎各", "country_id": "1787"},
{"id": 47, "cname": "冰岛", "country_id": "354"},
{"id": 46, "cname": "贝宁", "country_id": "229"},
{"id": 45, "cname": "保加利亚", "country_id": "359"},
{"id": 55, "cname": "布基纳法索", "country_id": "226"},
{"id": 56, "cname": "布隆迪", "country_id": "257"},
{"id": 66, "cname": "法属波利尼西亚", "country_id": "689"},
{"id": 65, "cname": "法罗岛", "country_id": "298"},
{"id": 64, "cname": "厄立特里亚", "country_id": "291"},
{"id": 63, "cname": "厄瓜多尔", "country_id": "593"},
{"id": 62, "cname": "多米尼加代表", "country_id": "1809"},
{"id": 61, "cname": "多米尼加", "country_id": "1767"},
{"id": 60, "cname": "多哥", "country_id": "228"},
{"id": 59, "cname": "迪戈加西亚岛", "country_id": "246"},
{"id": 58, "cname": "丹麦", "country_id": "45"},
{"id": 57, "cname": "赤道几内亚", "country_id": "240"},
{"id": 44, "cname": "百慕大群岛", "country_id": "1441"},
{"id": 43, "cname": "白俄罗斯", "country_id": "375"},
{"id": 42, "cname": "巴西", "country_id": "55"},
{"id": 29, "cname": "爱尔兰", "country_id": "353"},
{"id": 28, "cname": "埃塞俄比亚", "country_id": "251"},
{"id": 27, "cname": "埃及", "country_id": "20"},
{"id": 26, "cname": "阿塞拜疆", "country_id": "994"},
{"id": 25, "cname": "阿曼", "country_id": "968"},
{"id": 24, "cname": "阿联酋", "country_id": "971"},
{"id": 23, "cname": "阿根廷", "country_id": "54"},
{"id": 22, "cname": "阿富汗", "country_id": "93"},
{"id": 21, "cname": "阿尔及利亚", "country_id": "213"},
{"id": 20, "cname": "阿尔巴尼亚", "country_id": "355"},
{"id": 30, "cname": "爱沙尼亚", "country_id": "372"},
{"id": 31, "cname": "安道尔", "country_id": "376"},
{"id": 41, "cname": "巴拿马", "country_id": "507"},
{"id": 40, "cname": "巴林", "country_id": "973"},
{"id": 39, "cname": "巴拉圭", "country_id": "595"},
{"id": 38, "cname": "巴基斯坦", "country_id": "92"},
{"id": 37, "cname": "巴哈马群岛", "country_id": "1242"},
{"id": 36, "cname": "巴布亚新几内亚", "country_id": "675"},
{"id": 35, "cname": "巴巴多斯", "country_id": "1246"},
{"id": 34, "cname": "奥地利", "country_id": "43"},
{"id": 33, "cname": "安提瓜岛和巴布达", "country_id": "1268"},
{"id": 32, "cname": "安哥拉", "country_id": "244"},
{"id": 68, "cname": "非洲中部", "country_id": "236"},
{"id": 117, "cname": "罗马尼亚", "country_id": "40"},
{"id": 104, "cname": "科威特", "country_id": "965"},
{"id": 103, "cname": "科摩罗", "country_id": "269"},
{"id": 102, "cname": "开曼群岛", "country_id": "1345"},
{"id": 101, "cname": "卡塔尔", "country_id": "974"},
{"id": 100, "cname": "喀麦隆", "country_id": "237"},
{"id": 99, "cname": "聚会岛", "country_id": "262"},
{"id": 98, "cname": "津巴布韦", "country_id": "263"},
{"id": 97, "cname": "捷克", "country_id": "420"},
{"id": 96, "cname": "柬埔寨", "country_id": "855"},
{"id": 95, "cname": "加蓬", "country_id": "241"},
{"id": 105, "cname": "克罗地亚", "country_id": "385"},
{"id": 106, "cname": "肯尼亚", "country_id": "254"},
{"id": 116, "cname": "卢旺达", "country_id": "250"},
{"id": 115, "cname": "卢森堡", "country_id": "352"},
{"id": 114, "cname": "利比亚", "country_id": "218"},
{"id": 113, "cname": "利比里亚", "country_id": "231"},
{"id": 112, "cname": "立陶宛", "country_id": "370"},
{"id": 111, "cname": "黎巴嫩", "country_id": "961"},
{"id": 110, "cname": "老挝", "country_id": "856"},
{"id": 109, "cname": "莱索托", "country_id": "266"},
{"id": 108, "cname": "拉脱维亚", "country_id": "371"},
{"id": 107, "cname": "库克岛", "country_id": "682"},
{"id": 94, "cname": "加纳", "country_id": "233"},
{"id": 93, "cname": "几内亚比绍", "country_id": "245"},
{"id": 92, "cname": "几内亚", "country_id": "224"},
{"id": 79, "cname": "格林纳达", "country_id": "1473"},
{"id": 78, "cname": "哥斯达黎加", "country_id": "506"},
{"id": 77, "cname": "哥伦比亚", "country_id": "57"},
{"id": 76, "cname": "刚果(金)", "country_id": "243"},
{"id": 75, "cname": "刚果", "country_id": "242"},
{"id": 74, "cname": "冈比亚", "country_id": "220"},
{"id": 73, "cname": "福克兰岛", "country_id": "500"},
{"id": 72, "cname": "佛得角", "country_id": "238"},
{"id": 71, "cname": "芬兰", "country_id": "358"},
{"id": 70, "cname": "斐济", "country_id": "679"},
{"id": 80, "cname": "格陵兰岛", "country_id": "299"},
{"id": 81, "cname": "古巴", "country_id": "53"},
{"id": 91, "cname": "吉尔吉斯斯坦", "country_id": "996"},
{"id": 90, "cname": "吉布提", "country_id": "253"},
{"id": 89, "cname": "基里巴斯", "country_id": "686"},
{"id": 88, "cname": "维克岛", "country_id": "1808"},
{"id": 87, "cname": "洪都拉斯", "country_id": "504"},
{"id": 86, "cname": "荷兰", "country_id": "31"},
{"id": 85, "cname": "朝鲜", "country_id": "850"},
{"id": 84, "cname": "海地", "country_id": "509"},
{"id": 83, "cname": "关岛", "country_id": "1671"},
{"id": 82, "cname": "瓜德罗普岛", "country_id": "590"},
{"id": 69, "cname": "菲律宾", "country_id": "63"}
];
static List<Map<String, dynamic>> get internationalDialingPrefix => [
{"id": 1, "cname": "中国大陆", "country_id": "86"},
{"id": 5, "cname": "中国香港特别行政区", "country_id": "852"},
{"id": 2, "cname": "中国澳门特别行政区", "country_id": "853"},
{"id": 3, "cname": "中国台湾", "country_id": "886"},
{"id": 4, "cname": "美国", "country_id": "1"},
{"id": 6, "cname": "比利时", "country_id": "32"},
{"id": 7, "cname": "澳大利亚", "country_id": "61"},
{"id": 8, "cname": "法国", "country_id": "33"},
{"id": 9, "cname": "加拿大", "country_id": "1"},
{"id": 10, "cname": "日本", "country_id": "81"},
{"id": 11, "cname": "新加坡", "country_id": "65"},
{"id": 12, "cname": "韩国", "country_id": "82"},
{"id": 13, "cname": "马来西亚", "country_id": "60"},
{"id": 14, "cname": "英国", "country_id": "44"},
{"id": 15, "cname": "意大利", "country_id": "39"},
{"id": 16, "cname": "德国", "country_id": "49"},
{"id": 18, "cname": "俄罗斯", "country_id": "7"},
{"id": 19, "cname": "新西兰", "country_id": "64"}, //common:1-19
{"id": 153, "cname": "瓦利斯群岛和富图纳群岛", "country_id": "1681"},
{"id": 152, "cname": "葡萄牙", "country_id": "351"},
{"id": 151, "cname": "帕劳", "country_id": "680"},
{"id": 150, "cname": "诺福克岛", "country_id": "672"},
{"id": 149, "cname": "挪威", "country_id": "47"},
{"id": 148, "cname": "纽埃岛", "country_id": "683"},
{"id": 147, "cname": "尼日利亚", "country_id": "234"},
{"id": 146, "cname": "尼日尔", "country_id": "227"},
{"id": 145, "cname": "尼加拉瓜", "country_id": "505"},
{"id": 144, "cname": "尼泊尔", "country_id": "977"},
{"id": 143, "cname": "瑙鲁", "country_id": "674"},
{"id": 154, "cname": "格鲁吉亚", "country_id": "995"},
{"id": 155, "cname": "瑞典", "country_id": "46"},
{"id": 165, "cname": "沙特阿拉伯", "country_id": "966"},
{"id": 164, "cname": "桑给巴尔岛", "country_id": "259"},
{"id": 163, "cname": "塞舌尔共和国", "country_id": "248"},
{"id": 162, "cname": "塞浦路斯", "country_id": "357"},
{"id": 161, "cname": "塞内加尔", "country_id": "221"},
{"id": 160, "cname": "塞拉利昂", "country_id": "232"},
{"id": 159, "cname": "萨摩亚,东部", "country_id": "684"},
{"id": 158, "cname": "萨摩亚,西部", "country_id": "685"},
{"id": 157, "cname": "萨尔瓦多", "country_id": "503"},
{"id": 156, "cname": "瑞士", "country_id": "41"},
{"id": 166, "cname": "圣多美和普林西比", "country_id": "239"},
{"id": 142, "cname": "塞尔维亚", "country_id": "381"},
{"id": 141, "cname": "南非", "country_id": "27"},
{"id": 128, "cname": "毛里塔尼亚", "country_id": "222"},
{"id": 127, "cname": "毛里求斯", "country_id": "230"},
{"id": 126, "cname": "马歇尔岛", "country_id": "692"},
{"id": 125, "cname": "马提尼克岛", "country_id": "596"},
{"id": 124, "cname": "马其顿", "country_id": "389"},
{"id": 123, "cname": "马里亚纳岛", "country_id": "1670"},
{"id": 122, "cname": "马里", "country_id": "223"},
{"id": 121, "cname": "马拉维", "country_id": "265"},
{"id": 120, "cname": "马耳他", "country_id": "356"},
{"id": 119, "cname": "马尔代夫", "country_id": "960"},
{"id": 129, "cname": "蒙古", "country_id": "976"},
{"id": 130, "cname": "蒙特塞拉特岛", "country_id": "1664"},
{"id": 140, "cname": "纳米比亚", "country_id": "264"},
{"id": 139, "cname": "墨西哥", "country_id": "52"},
{"id": 138, "cname": "莫桑比克", "country_id": "258"},
{"id": 137, "cname": "摩纳哥", "country_id": "377"},
{"id": 136, "cname": "摩洛哥", "country_id": "212"},
{"id": 135, "cname": "摩尔多瓦", "country_id": "373"},
{"id": 134, "cname": "缅甸", "country_id": "95"},
{"id": 133, "cname": "密克罗尼西亚", "country_id": "691"},
{"id": 132, "cname": "秘鲁", "country_id": "51"},
{"id": 131, "cname": "孟加拉国", "country_id": "880"},
{"id": 118, "cname": "马达加斯加", "country_id": "261"},
{"id": 167, "cname": "圣卢西亚", "country_id": "1784"},
{"id": 216, "cname": "智利", "country_id": "56"},
{"id": 203, "cname": "牙买加", "country_id": "1876"},
{"id": 202, "cname": "叙利亚", "country_id": "963"},
{"id": 201, "cname": "匈牙利", "country_id": "36"},
{"id": 200, "cname": "科特迪瓦", "country_id": "225"},
{"id": 199, "cname": "希腊", "country_id": "30"},
{"id": 198, "cname": "西班牙", "country_id": "34"},
{"id": 197, "cname": "乌兹别克斯坦", "country_id": "998"},
{"id": 196, "cname": "乌拉圭", "country_id": "598"},
{"id": 195, "cname": "乌克兰", "country_id": "380"},
{"id": 194, "cname": "乌干达", "country_id": "256"},
{"id": 204, "cname": "亚美尼亚", "country_id": "374"},
{"id": 205, "cname": "也门", "country_id": "967"},
{"id": 215, "cname": "直布罗陀", "country_id": "350"},
{"id": 214, "cname": "乍得", "country_id": "235"},
{"id": 213, "cname": "赞比亚", "country_id": "260"},
{"id": 212, "cname": "越南", "country_id": "84"},
{"id": 211, "cname": "约旦", "country_id": "962"},
{"id": 210, "cname": "印尼", "country_id": "62"},
{"id": 209, "cname": "印度", "country_id": "91"},
{"id": 208, "cname": "以色列", "country_id": "972"},
{"id": 207, "cname": "伊朗", "country_id": "98"},
{"id": 206, "cname": "伊拉克", "country_id": "964"},
{"id": 193, "cname": "文莱", "country_id": "673"},
{"id": 192, "cname": "委内瑞拉", "country_id": "58"},
{"id": 191, "cname": "维珍群岛(英属)", "country_id": "1284"},
{"id": 178, "cname": "泰国", "country_id": "66"},
{"id": 177, "cname": "索马里", "country_id": "252"},
{"id": 176, "cname": "所罗门群岛", "country_id": "677"},
{"id": 175, "cname": "苏里南", "country_id": "597"},
{"id": 174, "cname": "苏丹", "country_id": "249"},
{"id": 173, "cname": "斯威士兰", "country_id": "268"},
{"id": 172, "cname": "斯洛文尼亚", "country_id": "386"},
{"id": 171, "cname": "斯洛伐克", "country_id": "421"},
{"id": 170, "cname": "斯里兰卡", "country_id": "94"},
{"id": 169, "cname": "圣皮埃尔和密克隆群岛", "country_id": "508"},
{"id": 179, "cname": "坦桑尼亚", "country_id": "255"},
{"id": 180, "cname": "汤加", "country_id": "676"},
{"id": 190, "cname": "维珍群岛(美属)", "country_id": "1340"},
{"id": 189, "cname": "瓦努阿图", "country_id": "678"},
{"id": 188, "cname": "托克劳岛", "country_id": "690"},
{"id": 187, "cname": "土库曼斯坦", "country_id": "993"},
{"id": 186, "cname": "土耳其", "country_id": "90"},
{"id": 185, "cname": "图瓦卢", "country_id": "688"},
{"id": 184, "cname": "突尼斯", "country_id": "216"},
{"id": 183, "cname": "阿森松岛", "country_id": "247"},
{"id": 182, "cname": "特立尼达和多巴哥", "country_id": "1868"},
{"id": 181, "cname": "特克斯和凯科斯", "country_id": "1649"},
{"id": 168, "cname": "圣马力诺", "country_id": "378"},
{"id": 67, "cname": "法属圭亚那", "country_id": "594"},
{"id": 54, "cname": "不丹", "country_id": "975"},
{"id": 53, "cname": "博茨瓦纳", "country_id": "267"},
{"id": 52, "cname": "伯利兹", "country_id": "501"},
{"id": 51, "cname": "玻利维亚", "country_id": "591"},
{"id": 50, "cname": "波兰", "country_id": "48"},
{"id": 49, "cname": "波黑", "country_id": "387"},
{"id": 48, "cname": "波多黎各", "country_id": "1787"},
{"id": 47, "cname": "冰岛", "country_id": "354"},
{"id": 46, "cname": "贝宁", "country_id": "229"},
{"id": 45, "cname": "保加利亚", "country_id": "359"},
{"id": 55, "cname": "布基纳法索", "country_id": "226"},
{"id": 56, "cname": "布隆迪", "country_id": "257"},
{"id": 66, "cname": "法属波利尼西亚", "country_id": "689"},
{"id": 65, "cname": "法罗岛", "country_id": "298"},
{"id": 64, "cname": "厄立特里亚", "country_id": "291"},
{"id": 63, "cname": "厄瓜多尔", "country_id": "593"},
{"id": 62, "cname": "多米尼加代表", "country_id": "1809"},
{"id": 61, "cname": "多米尼加", "country_id": "1767"},
{"id": 60, "cname": "多哥", "country_id": "228"},
{"id": 59, "cname": "迪戈加西亚岛", "country_id": "246"},
{"id": 58, "cname": "丹麦", "country_id": "45"},
{"id": 57, "cname": "赤道几内亚", "country_id": "240"},
{"id": 44, "cname": "百慕大群岛", "country_id": "1441"},
{"id": 43, "cname": "白俄罗斯", "country_id": "375"},
{"id": 42, "cname": "巴西", "country_id": "55"},
{"id": 29, "cname": "爱尔兰", "country_id": "353"},
{"id": 28, "cname": "埃塞俄比亚", "country_id": "251"},
{"id": 27, "cname": "埃及", "country_id": "20"},
{"id": 26, "cname": "阿塞拜疆", "country_id": "994"},
{"id": 25, "cname": "阿曼", "country_id": "968"},
{"id": 24, "cname": "阿联酋", "country_id": "971"},
{"id": 23, "cname": "阿根廷", "country_id": "54"},
{"id": 22, "cname": "阿富汗", "country_id": "93"},
{"id": 21, "cname": "阿尔及利亚", "country_id": "213"},
{"id": 20, "cname": "阿尔巴尼亚", "country_id": "355"},
{"id": 30, "cname": "爱沙尼亚", "country_id": "372"},
{"id": 31, "cname": "安道尔", "country_id": "376"},
{"id": 41, "cname": "巴拿马", "country_id": "507"},
{"id": 40, "cname": "巴林", "country_id": "973"},
{"id": 39, "cname": "巴拉圭", "country_id": "595"},
{"id": 38, "cname": "巴基斯坦", "country_id": "92"},
{"id": 37, "cname": "巴哈马群岛", "country_id": "1242"},
{"id": 36, "cname": "巴布亚新几内亚", "country_id": "675"},
{"id": 35, "cname": "巴巴多斯", "country_id": "1246"},
{"id": 34, "cname": "奥地利", "country_id": "43"},
{"id": 33, "cname": "安提瓜岛和巴布达", "country_id": "1268"},
{"id": 32, "cname": "安哥拉", "country_id": "244"},
{"id": 68, "cname": "非洲中部", "country_id": "236"},
{"id": 117, "cname": "罗马尼亚", "country_id": "40"},
{"id": 104, "cname": "科威特", "country_id": "965"},
{"id": 103, "cname": "科摩罗", "country_id": "269"},
{"id": 102, "cname": "开曼群岛", "country_id": "1345"},
{"id": 101, "cname": "卡塔尔", "country_id": "974"},
{"id": 100, "cname": "喀麦隆", "country_id": "237"},
{"id": 99, "cname": "聚会岛", "country_id": "262"},
{"id": 98, "cname": "津巴布韦", "country_id": "263"},
{"id": 97, "cname": "捷克", "country_id": "420"},
{"id": 96, "cname": "柬埔寨", "country_id": "855"},
{"id": 95, "cname": "加蓬", "country_id": "241"},
{"id": 105, "cname": "克罗地亚", "country_id": "385"},
{"id": 106, "cname": "肯尼亚", "country_id": "254"},
{"id": 116, "cname": "卢旺达", "country_id": "250"},
{"id": 115, "cname": "卢森堡", "country_id": "352"},
{"id": 114, "cname": "利比亚", "country_id": "218"},
{"id": 113, "cname": "利比里亚", "country_id": "231"},
{"id": 112, "cname": "立陶宛", "country_id": "370"},
{"id": 111, "cname": "黎巴嫩", "country_id": "961"},
{"id": 110, "cname": "老挝", "country_id": "856"},
{"id": 109, "cname": "莱索托", "country_id": "266"},
{"id": 108, "cname": "拉脱维亚", "country_id": "371"},
{"id": 107, "cname": "库克岛", "country_id": "682"},
{"id": 94, "cname": "加纳", "country_id": "233"},
{"id": 93, "cname": "几内亚比绍", "country_id": "245"},
{"id": 92, "cname": "几内亚", "country_id": "224"},
{"id": 79, "cname": "格林纳达", "country_id": "1473"},
{"id": 78, "cname": "哥斯达黎加", "country_id": "506"},
{"id": 77, "cname": "哥伦比亚", "country_id": "57"},
{"id": 76, "cname": "刚果(金)", "country_id": "243"},
{"id": 75, "cname": "刚果", "country_id": "242"},
{"id": 74, "cname": "冈比亚", "country_id": "220"},
{"id": 73, "cname": "福克兰岛", "country_id": "500"},
{"id": 72, "cname": "佛得角", "country_id": "238"},
{"id": 71, "cname": "芬兰", "country_id": "358"},
{"id": 70, "cname": "斐济", "country_id": "679"},
{"id": 80, "cname": "格陵兰岛", "country_id": "299"},
{"id": 81, "cname": "古巴", "country_id": "53"},
{"id": 91, "cname": "吉尔吉斯斯坦", "country_id": "996"},
{"id": 90, "cname": "吉布提", "country_id": "253"},
{"id": 89, "cname": "基里巴斯", "country_id": "686"},
{"id": 88, "cname": "维克岛", "country_id": "1808"},
{"id": 87, "cname": "洪都拉斯", "country_id": "504"},
{"id": 86, "cname": "荷兰", "country_id": "31"},
{"id": 85, "cname": "朝鲜", "country_id": "850"},
{"id": 84, "cname": "海地", "country_id": "509"},
{"id": 83, "cname": "关岛", "country_id": "1671"},
{"id": 82, "cname": "瓜德罗普岛", "country_id": "590"},
{"id": 69, "cname": "菲律宾", "country_id": "63"}
];
}

View File

@@ -87,6 +87,7 @@ class DynamicCardSkeleton extends StatelessWidget {
],
),
),
const Spacer(),
Row(
mainAxisAlignment: MainAxisAlignment.spaceAround,
children: [

View File

@@ -39,51 +39,55 @@ class VideoCardHSkeleton extends StatelessWidget {
),
// VideoContent(videoItem: videoItem)
Expanded(
child: Padding(
padding: const EdgeInsets.fromLTRB(10, 4, 6, 4),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Container(
color: Theme.of(context).colorScheme.onInverseSurface,
width: 200,
height: 11,
margin: const EdgeInsets.only(bottom: 5),
),
Container(
color: Theme.of(context).colorScheme.onInverseSurface,
width: 150,
height: 13,
),
const Spacer(),
Container(
color: Theme.of(context).colorScheme.onInverseSurface,
width: 100,
height: 13,
margin: const EdgeInsets.only(bottom: 5),
),
Row(
children: [
Container(
color: Theme.of(context)
.colorScheme
.onInverseSurface,
width: 40,
height: 13,
margin: const EdgeInsets.only(right: 8),
),
Container(
color: Theme.of(context)
.colorScheme
.onInverseSurface,
width: 40,
height: 13,
),
],
)
],
child: Padding(
padding: const EdgeInsets.fromLTRB(10, 4, 6, 4),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Container(
color:
Theme.of(context).colorScheme.onInverseSurface,
width: 200,
height: 11,
margin: const EdgeInsets.only(bottom: 5),
),
Container(
color:
Theme.of(context).colorScheme.onInverseSurface,
width: 150,
height: 13,
),
const Spacer(),
Container(
color:
Theme.of(context).colorScheme.onInverseSurface,
width: 100,
height: 13,
margin: const EdgeInsets.only(bottom: 5),
),
Row(
children: [
Container(
color: Theme.of(context)
.colorScheme
.onInverseSurface,
width: 40,
height: 13,
margin: const EdgeInsets.only(right: 8),
),
Container(
color: Theme.of(context)
.colorScheme
.onInverseSurface,
width: 40,
height: 13,
),
],
)
],
),
),
)),
),
],
),
);

View File

@@ -1,5 +1,6 @@
import 'package:PiliPlus/common/widgets/no_splash_factory.dart';
import 'package:PiliPlus/common/widgets/overlay_pop.dart';
import 'package:PiliPlus/models/model_video.dart';
import 'package:flutter/material.dart';
class AnimatedDialog extends StatefulWidget {
@@ -9,7 +10,7 @@ class AnimatedDialog extends StatefulWidget {
required this.closeFn,
});
final dynamic videoItem;
final BaseVideoItemModel videoItem;
final Function closeFn;
@override
@@ -31,13 +32,17 @@ class AnimatedDialogState extends State<AnimatedDialog>
opacityAnimation = Tween<double>(begin: 0.0, end: 0.6)
.animate(CurvedAnimation(parent: controller, curve: Curves.linear));
scaleAnimation = CurvedAnimation(parent: controller, curve: Curves.linear);
controller.addListener(() => setState(() {}));
controller.addListener(listener);
controller.forward();
}
void listener() {
setState(() {});
}
@override
void dispose() {
controller.removeListener(() {});
controller.removeListener(listener);
controller.dispose();
super.dispose();
}

View File

@@ -1,3 +1,5 @@
import 'package:PiliPlus/common/widgets/interactiveviewer_gallery/interactiveviewer_gallery.dart'
show SourceModel;
import 'package:PiliPlus/common/widgets/network_img_layer.dart';
import 'package:PiliPlus/models/dynamics/article_content_model.dart';
import 'package:PiliPlus/utils/extension.dart';
@@ -9,7 +11,9 @@ Widget articleContent({
required BuildContext context,
required List<ArticleContentModel> list,
Function(List<String>, int)? callback,
required double maxWidth,
}) {
debugPrint('articleContent');
List<String>? imgList = list
.where((item) => item.pic != null)
.toList()
@@ -55,30 +59,28 @@ Widget articleContent({
),
);
} else if (item.pic != null) {
return LayoutBuilder(
builder: (context, constraints) => Hero(
tag: item.pic!.pics!.first.url!,
child: GestureDetector(
onTap: () {
if (callback != null) {
callback(
imgList,
imgList.indexOf(item.pic!.pics!.first.url!),
);
} else {
context.imageView(
initialPage: imgList.indexOf(item.pic!.pics!.first.url!),
imgList: imgList,
);
}
},
child: NetworkImgLayer(
width: constraints.maxWidth,
height: constraints.maxWidth *
item.pic!.pics!.first.height! /
item.pic!.pics!.first.width!,
src: item.pic!.pics!.first.url,
),
return Hero(
tag: item.pic!.pics!.first.url!,
child: GestureDetector(
onTap: () {
if (callback != null) {
callback(
imgList,
imgList.indexOf(item.pic!.pics!.first.url!),
);
} else {
context.imageView(
initialPage: imgList.indexOf(item.pic!.pics!.first.url!),
imgList: imgList.map((url) => SourceModel(url: url)).toList(),
);
}
},
child: NetworkImgLayer(
width: maxWidth,
height: maxWidth *
item.pic!.pics!.first.height! /
item.pic!.pics!.first.width!,
src: item.pic!.pics!.first.url,
),
),
);

View File

@@ -484,6 +484,9 @@ class _RenderProgressBar extends RenderBox {
}
void _onDragStart(DragStartDetails details) {
if (onDragStart == null) {
return;
}
_userIsDraggingThumb = true;
_updateThumbPosition(details.localPosition);
onDragStart?.call(ThumbDragDetails(
@@ -494,6 +497,9 @@ class _RenderProgressBar extends RenderBox {
}
void _onDragUpdate(DragUpdateDetails details) {
if (onDragUpdate == null) {
return;
}
_updateThumbPosition(details.localPosition);
onDragUpdate?.call(ThumbDragDetails(
timeStamp: _currentThumbDuration(),
@@ -503,6 +509,9 @@ class _RenderProgressBar extends RenderBox {
}
void _onDragEnd(DragEndDetails details) {
if (onSeek == null) {
return;
}
onDragEnd?.call();
onSeek?.call(_currentThumbDuration());
_finishDrag();

View File

@@ -1,3 +1,4 @@
import 'package:PiliPlus/utils/extension.dart';
import 'package:flutter/material.dart';
class PBadge extends StatelessWidget {
@@ -12,10 +13,12 @@ class PBadge extends StatelessWidget {
final double? fs;
final String? semanticsLabel;
final bool bold;
final double? textScaleFactor;
final EdgeInsets? padding;
const PBadge({
super.key,
this.text,
required this.text,
this.top,
this.right,
this.bottom,
@@ -26,10 +29,16 @@ class PBadge extends StatelessWidget {
this.fs = 11,
this.semanticsLabel,
this.bold = true,
this.textScaleFactor,
this.padding,
});
@override
Widget build(BuildContext context) {
if (text.isNullOrEmpty) {
return const SizedBox.shrink();
}
ColorScheme t = Theme.of(context).colorScheme;
// 背景色
Color bgColor = t.primary;
@@ -38,20 +47,21 @@ class PBadge extends StatelessWidget {
// 边框色
Color borderColor = Colors.transparent;
if (type == 'gray') {
bgColor = Colors.black54.withOpacity(0.4);
bgColor = Colors.black45;
color = Colors.white;
}
if (type == 'color') {
} else if (type == 'color') {
bgColor = t.secondaryContainer.withOpacity(0.5);
color = t.onSecondaryContainer;
}
if (type == 'line') {
} else if (type == 'line') {
bgColor = Colors.transparent;
color = t.primary;
borderColor = t.primary;
} else if (type == 'error') {
bgColor = t.error;
color = t.onError;
}
EdgeInsets paddingStyle =
late EdgeInsets paddingStyle =
const EdgeInsets.symmetric(vertical: 2, horizontal: 3);
double fontSize = 11;
BorderRadius br = BorderRadius.circular(4);
@@ -63,14 +73,17 @@ class PBadge extends StatelessWidget {
}
Widget content = Container(
padding: paddingStyle,
padding: padding ?? paddingStyle,
decoration: BoxDecoration(
borderRadius: br,
color: bgColor,
border: Border.all(color: borderColor),
),
child: Text(
text ?? "",
text!,
textScaler: textScaleFactor != null
? TextScaler.linear(textScaleFactor!)
: null,
style: TextStyle(
height: 1,
fontSize: fs ?? fontSize,

View File

@@ -19,8 +19,16 @@ class CustomSliverPersistentHeaderDelegate
//创建child子组件
//shrinkOffsetchild偏移值minExtent~maxExtent
//overlapsContentSliverPersistentHeader覆盖其他子组件返回true否则返回false
return ColoredBox(
color: bgColor,
return DecoratedBox(
decoration: BoxDecoration(
color: bgColor,
boxShadow: [
BoxShadow(
color: bgColor,
offset: const Offset(0, -2),
),
],
),
child: child,
);
}

View File

@@ -31,3 +31,37 @@ class CustomToast extends StatelessWidget {
);
}
}
class LoadingWidget extends StatelessWidget {
const LoadingWidget({super.key, required this.msg});
///loading msg
final String msg;
@override
Widget build(BuildContext context) {
return Container(
padding: const EdgeInsets.symmetric(horizontal: 30, vertical: 20),
decoration: BoxDecoration(
color: Theme.of(context).dialogBackgroundColor,
borderRadius: BorderRadius.circular(15),
),
child: Column(mainAxisSize: MainAxisSize.min, children: [
//loading animation
CircularProgressIndicator(
strokeWidth: 3,
valueColor: AlwaysStoppedAnimation(
Theme.of(context).colorScheme.onSurfaceVariant),
),
//msg
Container(
margin: const EdgeInsets.only(top: 20),
child: Text(msg,
style: TextStyle(
color: Theme.of(context).colorScheme.onSurfaceVariant)),
),
]),
);
}
}

View File

@@ -0,0 +1,102 @@
import 'package:flutter/material.dart';
import 'package:get/get.dart';
void showConfirmDialog({
required BuildContext context,
required String title,
String? content,
required VoidCallback onConfirm,
}) {
showDialog(
context: context,
builder: (context) {
return AlertDialog(
title: Text(title),
content: content == null ? null : Text(content),
actions: [
TextButton(
onPressed: Get.back,
child: Text(
'取消',
style: TextStyle(color: Theme.of(context).colorScheme.outline),
),
),
TextButton(
onPressed: () {
Get.back();
onConfirm();
},
child: Text('确认'),
),
],
);
},
);
}
void showPgcFollowDialog({
required BuildContext context,
required String type,
required int followStatus,
required ValueChanged<int> onUpdateStatus,
}) {
Widget statusItem({
required bool enabled,
required String text,
required VoidCallback onTap,
}) {
return ListTile(
dense: true,
enabled: enabled,
title: Padding(
padding: const EdgeInsets.only(left: 10),
child: Text(
'标记为 $text',
style: const TextStyle(fontSize: 14),
),
),
trailing: !enabled ? const Icon(size: 22, Icons.check) : null,
onTap: onTap,
);
}
showDialog(
context: context,
builder: (context) => AlertDialog(
clipBehavior: Clip.hardEdge,
contentPadding: const EdgeInsets.symmetric(vertical: 12),
content: Column(
mainAxisSize: MainAxisSize.min,
children: [
...[
{'followStatus': 3, 'title': '看过'},
{'followStatus': 2, 'title': '在看'},
{'followStatus': 1, 'title': '想看'},
].map(
(Map item) => statusItem(
enabled: followStatus != item['followStatus'],
text: item['title'],
onTap: () {
Get.back();
onUpdateStatus(item['followStatus']);
},
),
),
ListTile(
dense: true,
title: Padding(
padding: EdgeInsets.only(left: 10),
child: Text(
'取消$type',
style: TextStyle(fontSize: 14),
),
),
onTap: () {
Get.back();
onUpdateStatus(-1);
},
)
],
),
));
}

View File

@@ -35,7 +35,7 @@ class DynamicSliverAppBar extends StatefulWidget {
this.stretchTriggerOffset = 100.0,
this.onStretchTrigger,
this.shape,
this.toolbarHeight = kToolbarHeight + 20,
this.toolbarHeight = kToolbarHeight,
this.leadingWidth,
this.toolbarTextStyle,
this.titleTextStyle,
@@ -43,8 +43,10 @@ class DynamicSliverAppBar extends StatefulWidget {
this.forceMaterialTransparency = false,
this.clipBehavior,
this.appBarClipper,
this.hasTabBar = false,
});
final bool hasTabBar;
final Widget? flexibleSpace;
final Widget? leading;
final bool automaticallyImplyLeading;
@@ -95,7 +97,6 @@ class _DynamicSliverAppBarState extends State<DynamicSliverAppBar> {
// As long as the height is 0 instead of the sliver app bar a sliver to box adapter will be used
// to calculate dynamically the size for the sliver app bar
double _height = 0;
Orientation? _orientation;
@override
void initState() {
@@ -103,13 +104,6 @@ class _DynamicSliverAppBarState extends State<DynamicSliverAppBar> {
_updateHeight();
}
@override
void didUpdateWidget(covariant DynamicSliverAppBar oldWidget) {
super.didUpdateWidget(oldWidget);
_updateHeight();
}
void _updateHeight() {
// Gets the new height and updates the sliver app bar. Needs to be called after the last frame has been rebuild
// otherwise this will throw an error
@@ -123,23 +117,27 @@ class _DynamicSliverAppBarState extends State<DynamicSliverAppBar> {
});
}
@override
void didChangeDependencies() {
_height = 0;
_updateHeight();
super.didChangeDependencies();
}
@override
Widget build(BuildContext context) {
//Needed to lay out the flexibleSpace the first time, so we can calculate its intrinsic height
Orientation orientation = MediaQuery.orientationOf(context);
if (_orientation != orientation) {
_orientation = orientation;
_height = 0;
}
if (_height == 0) {
return SliverToBoxAdapter(
child: Container(
child: SizedBox(
key: _childKey,
child: widget.flexibleSpace ?? SizedBox(height: kToolbarHeight),
),
);
}
MediaQuery.orientationOf(context);
return SliverAppBar(
leading: widget.leading,
automaticallyImplyLeading: widget.automaticallyImplyLeading,
@@ -168,7 +166,7 @@ class _DynamicSliverAppBarState extends State<DynamicSliverAppBar> {
onStretchTrigger: widget.onStretchTrigger,
shape: widget.shape,
toolbarHeight: widget.toolbarHeight,
expandedHeight: _height,
expandedHeight: _height + (widget.hasTabBar ? 48 : 0),
leadingWidth: widget.leadingWidth,
toolbarTextStyle: widget.toolbarTextStyle,
titleTextStyle: widget.titleTextStyle,

View File

@@ -0,0 +1,655 @@
import 'dart:math';
import 'package:PiliPlus/common/constants.dart';
import 'package:PiliPlus/common/widgets/badge.dart';
import 'package:PiliPlus/common/widgets/icon_button.dart';
import 'package:PiliPlus/common/widgets/image_save.dart';
import 'package:PiliPlus/common/widgets/keep_alive_wrapper.dart';
import 'package:PiliPlus/common/widgets/network_img_layer.dart';
import 'package:PiliPlus/common/widgets/scroll_physics.dart';
import 'package:PiliPlus/common/widgets/stat/stat.dart';
import 'package:PiliPlus/http/loading_state.dart';
import 'package:PiliPlus/http/video.dart';
import 'package:PiliPlus/models/bangumi/info.dart' as bangumi;
import 'package:PiliPlus/models/video_detail_res.dart' as video;
import 'package:PiliPlus/pages/common/common_slide_page.dart';
import 'package:PiliPlus/pages/video/detail/controller.dart';
import 'package:PiliPlus/pages/video/detail/introduction/controller.dart';
import 'package:PiliPlus/pages/video/detail/introduction/widgets/page.dart';
import 'package:PiliPlus/utils/id_utils.dart';
import 'package:PiliPlus/utils/storage.dart';
import 'package:PiliPlus/utils/utils.dart';
import 'package:flutter/material.dart';
import 'package:flutter_smart_dialog/flutter_smart_dialog.dart';
import 'package:get/get.dart';
import 'package:material_design_icons_flutter/material_design_icons_flutter.dart';
import 'package:scrollable_positioned_list/scrollable_positioned_list.dart';
enum EpisodeType { part, season, bangumi }
extension EpisodeTypeExt on EpisodeType {
String get title => ['分P', '合集', '番剧'][index];
}
class EpisodePanel extends CommonSlidePage {
const EpisodePanel({
super.key,
super.enableSlide,
required this.videoIntroController,
required this.heroTag,
required this.type,
// required this.count,
// required this.name,
required this.aid,
required this.bvid,
required this.cid,
required this.cover,
this.showTitle,
required this.list,
this.seasonId,
this.initialTabIndex = 0,
this.isSupportReverse,
this.isReversed,
this.onReverse,
required this.changeFucCall,
this.onClose,
});
final VideoIntroController videoIntroController;
final String heroTag;
final EpisodeType type;
// final int count;
// final String name;
final int? aid;
final String bvid;
final int cid;
final String? cover;
final bool? showTitle;
final List list;
final int? seasonId;
final int initialTabIndex;
final bool? isSupportReverse;
final bool? isReversed;
final Function changeFucCall;
final VoidCallback? onReverse;
final VoidCallback? onClose;
@override
State<EpisodePanel> createState() => _EpisodePanelState();
}
class _EpisodePanelState extends CommonSlidePageState<EpisodePanel>
with SingleTickerProviderStateMixin {
// tab
late final TabController _tabController = TabController(
initialIndex: widget.initialTabIndex,
length: widget.list.length,
vsync: this,
)..addListener(listener);
late final RxInt _currentTabIndex = _tabController.index.obs;
List get _getCurrEpisodes => widget.type == EpisodeType.season
? widget.list[_currentTabIndex.value].episodes
: widget.list[_currentTabIndex.value];
// item
late RxInt _currentItemIndex;
int get _findCurrentItemIndex => max(
0,
_getCurrEpisodes.indexWhere((item) => item.cid == widget.cid),
);
late final List<bool> _isReversed;
late final List<ItemScrollController> _itemScrollController;
// fav
Rx<LoadingState>? _favState;
late bool _isInit = true;
void listener() {
_currentTabIndex.value = _tabController.index;
}
@override
void didUpdateWidget(EpisodePanel oldWidget) {
super.didUpdateWidget(oldWidget);
if (widget.showTitle != false) {
return;
}
void jumpToCurrent() {
int newItemIndex = _findCurrentItemIndex;
if (_currentItemIndex.value != _findCurrentItemIndex) {
_currentItemIndex.value = newItemIndex;
try {
_itemScrollController[_currentTabIndex.value].jumpTo(
index: newItemIndex,
);
} catch (_) {}
}
}
// jump to current
if (_currentTabIndex.value != widget.initialTabIndex) {
_tabController.animateTo(
widget.initialTabIndex,
duration: const Duration(milliseconds: 200),
);
Future.delayed(const Duration(milliseconds: 300)).then((_) {
jumpToCurrent();
});
} else {
jumpToCurrent();
}
}
@override
void initState() {
super.initState();
_itemScrollController =
List.generate(widget.list.length, (_) => ItemScrollController());
_isReversed = List.generate(widget.list.length, (_) => false);
if (widget.type == EpisodeType.season && Accounts.main.isLogin) {
_favState = LoadingState.loading().obs;
VideoHttp.videoRelation(bvid: widget.bvid).then((result) {
if (result['status']) {
if (result['data']?['season_fav'] is bool) {
_favState!.value =
LoadingState.success(result['data']['season_fav']);
}
}
});
}
_currentItemIndex = _findCurrentItemIndex.obs;
WidgetsBinding.instance.addPostFrameCallback((_) {
if (mounted) {
setState(() {
_isInit = false;
});
WidgetsBinding.instance.addPostFrameCallback((_) {
try {
_itemScrollController[widget.initialTabIndex]
.jumpTo(index: _currentItemIndex.value);
} catch (_) {}
});
}
});
}
@override
void dispose() {
_tabController.removeListener(listener);
_tabController.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
if (_isInit) {
return CustomScrollView(
physics: const NeverScrollableScrollPhysics(),
);
}
return super.build(context);
}
@override
Widget get buildPage => Material(
color: widget.showTitle == false
? Colors.transparent
: Theme.of(context).colorScheme.surface,
child: Column(
children: [
_buildToolbar,
if (widget.type == EpisodeType.season &&
widget.list.length > 1) ...[
TabBar(
controller: _tabController,
padding: const EdgeInsets.only(right: 60),
isScrollable: true,
tabs: widget.list.map((item) => Tab(text: item.title)).toList(),
dividerHeight: 1,
dividerColor: Theme.of(context).dividerColor.withOpacity(0.1),
),
Expanded(
child: Material(
color: Colors.transparent,
child: tabBarView(
controller: _tabController,
children: List.generate(
widget.list.length,
(index) => _buildBody(
index,
widget.list[index].episodes,
),
),
),
),
),
] else
Expanded(
child: enableSlide ? slideList() : buildList,
),
],
),
);
@override
Widget get buildList => Material(
color: Colors.transparent,
child: _buildBody(0, _getCurrEpisodes),
);
Widget _buildBody(int index, episodes) {
return KeepAliveWrapper(
builder: (context) => ScrollablePositionedList.separated(
padding: EdgeInsets.only(
top: 7,
bottom: MediaQuery.of(context).padding.bottom + 80,
),
reverse: _isReversed[index],
itemCount: episodes.length,
physics: const AlwaysScrollableScrollPhysics(),
itemBuilder: (BuildContext context, int index) {
final episode = episodes[index];
return widget.type == EpisodeType.season &&
widget.showTitle != false &&
episode.pages.length > 1
? Column(
mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Obx(
() => _buildEpisodeItem(
episode: episode,
index: index,
length: episodes.length,
isCurrentIndex:
_currentTabIndex.value == widget.initialTabIndex
? _currentItemIndex.value == index
: false,
),
),
Padding(
padding: const EdgeInsets.symmetric(
horizontal: 12, vertical: 5),
child: PagesPanel(
list:
widget.initialTabIndex == _currentTabIndex.value &&
index == _currentItemIndex.value
? null
: episode.pages,
cover: episode.arc?.pic,
heroTag: widget.heroTag,
videoIntroController: widget.videoIntroController,
bvid: IdUtils.av2bv(episode.aid),
),
),
],
)
: Obx(
() => _buildEpisodeItem(
episode: episode,
index: index,
length: episodes.length,
isCurrentIndex:
_currentTabIndex.value == widget.initialTabIndex
? _currentItemIndex.value == index
: false,
),
);
},
itemScrollController: _itemScrollController[index],
separatorBuilder: (context, index) => const SizedBox(height: 2),
),
);
}
Widget _buildEpisodeItem({
required dynamic episode,
required int index,
required int length,
required bool isCurrentIndex,
}) {
late String title;
String? cover;
num? duration;
int? pubdate;
int? view;
int? danmaku;
switch (episode) {
case video.Part():
cover = episode.firstFrame ?? widget.cover;
title = episode.pagePart!;
duration = episode.duration;
pubdate = episode.ctime;
break;
case video.EpisodeItem():
title = episode.title!;
cover = episode.arc?.pic;
duration = episode.arc?.duration;
pubdate = episode.arc?.pubdate;
view = episode.arc?.stat?.view;
danmaku = episode.arc?.stat?.danmaku;
break;
case bangumi.EpisodeItem():
if (episode.longTitle != null && episode.longTitle != "") {
dynamic leading = episode.title ?? index + 1;
title =
"${Utils.isStringNumeric(leading) ? '$leading话' : leading} ${episode.longTitle!}";
} else {
title = episode.title!;
}
cover = episode.cover;
duration = episode.duration == null ? null : episode.duration! ~/ 1000;
pubdate = episode.pubTime;
break;
}
late final Color primary = Theme.of(context).colorScheme.primary;
return Material(
color: Colors.transparent,
child: SizedBox(
height: 98,
child: InkWell(
onTap: () {
if (episode.badge != null && episode.badge == "会员") {
dynamic userInfo = GStorage.userInfo.get('userInfoCache');
int vipStatus = 0;
if (userInfo != null) {
vipStatus = userInfo.vipStatus;
}
if (vipStatus != 1) {
SmartDialog.showToast('需要大会员');
// return;
}
}
SmartDialog.showToast('切换到:$title');
widget.onClose?.call();
if (widget.showTitle == false) {
_currentItemIndex.value = index;
}
widget.changeFucCall(
episode is bangumi.EpisodeItem ? episode.epId : null,
episode.runtimeType.toString() == "EpisodeItem"
? episode.bvid
: widget.bvid,
episode.cid,
episode.runtimeType.toString() == "EpisodeItem"
? episode.aid
: widget.aid,
cover,
);
if (widget.type == EpisodeType.season) {
try {
Get.find<VideoDetailController>(
tag: widget.videoIntroController.heroTag)
.seasonCid = episode.cid;
} catch (_) {}
}
},
onLongPress: () {
if (cover?.isNotEmpty == true) {
imageSaveDialog(context: context, title: title, cover: cover);
}
},
child: Padding(
padding: const EdgeInsets.symmetric(
horizontal: StyleString.safeSpace,
vertical: 5,
),
child: Row(
mainAxisAlignment: MainAxisAlignment.start,
children: [
if (cover?.isNotEmpty == true)
AspectRatio(
aspectRatio: StyleString.aspectRatio,
child: LayoutBuilder(
builder: (context, boxConstraints) {
return Stack(
clipBehavior: Clip.none,
children: [
NetworkImgLayer(
src: cover,
width: boxConstraints.maxWidth,
height: boxConstraints.maxHeight,
),
if (duration != null && duration > 0)
PBadge(
text: Utils.timeFormat(duration),
right: 6.0,
bottom: 6.0,
type: 'gray',
),
],
);
},
),
)
else if (isCurrentIndex)
Image.asset(
'assets/images/live.png',
color: primary,
height: 12,
semanticLabel: "正在播放:",
),
const SizedBox(width: 10),
Expanded(
child: Column(
mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Expanded(
child: Text(
title,
textAlign: TextAlign.start,
style: TextStyle(
fontSize: Theme.of(context)
.textTheme
.bodyMedium!
.fontSize,
height: 1.42,
letterSpacing: 0.3,
fontWeight: isCurrentIndex ? FontWeight.bold : null,
color: isCurrentIndex ? primary : null,
),
maxLines: 2,
overflow: TextOverflow.ellipsis,
),
),
if (pubdate != null)
Text(
Utils.dateFormat(pubdate),
maxLines: 1,
style: TextStyle(
fontSize: Theme.of(context)
.textTheme
.labelSmall!
.fontSize,
height: 1,
color: Theme.of(context).colorScheme.outline,
overflow: TextOverflow.clip,
),
),
if (view != null) ...[
const SizedBox(height: 2),
Row(
children: [
StatView(
context: context,
theme: 'gray',
value: view,
),
if (danmaku != null) ...[
const SizedBox(width: 8),
StatDanMu(
context: context,
theme: 'gray',
value: danmaku,
),
],
],
),
],
],
),
),
if (episode.badge != null) ...[
if (episode.badge == '会员')
Image.asset(
'assets/images/big-vip.png',
height: 20,
semanticLabel: "大会员",
)
else
Text(episode.badge),
const SizedBox(width: 10),
],
],
),
),
),
),
);
}
Widget _buildFavBtn(LoadingState loadingState) {
return switch (loadingState) {
Success() => mediumButton(
tooltip: loadingState.response ? '取消订阅' : '订阅',
icon: loadingState.response
? Icons.notifications_off_outlined
: Icons.notifications_active_outlined,
onPressed: () async {
dynamic result = await VideoHttp.seasonFav(
isFav: loadingState.response,
seasonId: widget.seasonId,
);
if (result['status']) {
SmartDialog.showToast('${loadingState.response ? '取消' : ''}订阅成功');
_favState!.value = LoadingState.success(!loadingState.response);
} else {
SmartDialog.showToast(result['msg']);
}
},
),
_ => const SizedBox.shrink(),
};
}
Widget get _buildReverseBtn => mediumButton(
tooltip: widget.isReversed == true ? '正序播放' : '倒序播放',
icon: widget.isReversed == true
? MdiIcons.sortDescending
: MdiIcons.sortAscending,
onPressed: () {
widget.onReverse?.call();
},
);
Widget get _buildToolbar => Container(
height: 45,
padding: EdgeInsets.symmetric(
horizontal: widget.showTitle != false ? 14 : 6),
decoration: BoxDecoration(
border: Border(
bottom: BorderSide(
color: Theme.of(context).dividerColor.withOpacity(0.1),
),
),
),
child: Row(
children: [
if (widget.showTitle != false)
Text(
widget.type.title,
style: Theme.of(context).textTheme.titleMedium,
),
if (_favState != null) Obx(() => _buildFavBtn(_favState!.value)),
mediumButton(
tooltip: '跳至顶部',
icon: Icons.vertical_align_top,
onPressed: () {
try {
_itemScrollController[_currentTabIndex.value].scrollTo(
index: !_isReversed[_currentTabIndex.value]
? 0
: _getCurrEpisodes.length - 1,
duration: const Duration(milliseconds: 200),
);
} catch (e) {
debugPrint('to top: $e');
}
},
),
mediumButton(
tooltip: '跳至底部',
icon: Icons.vertical_align_bottom,
onPressed: () {
try {
_itemScrollController[_currentTabIndex.value].scrollTo(
index: !_isReversed[_currentTabIndex.value]
? _getCurrEpisodes.length - 1
: 0,
duration: const Duration(milliseconds: 200),
);
} catch (e) {
debugPrint('to bottom: $e');
}
},
),
mediumButton(
tooltip: '跳至当前',
icon: Icons.my_location,
onPressed: () async {
try {
if (_currentTabIndex.value != widget.initialTabIndex) {
_tabController.animateTo(widget.initialTabIndex);
await Future.delayed(const Duration(milliseconds: 225));
}
_itemScrollController[_currentTabIndex.value].scrollTo(
index: _currentItemIndex.value,
duration: const Duration(milliseconds: 200),
);
} catch (_) {}
},
),
if (widget.isSupportReverse == true)
Obx(
() {
return _currentTabIndex.value == widget.initialTabIndex
? _buildReverseBtn
: const SizedBox.shrink();
},
),
const Spacer(),
Obx(
() => mediumButton(
tooltip: _isReversed[_currentTabIndex.value] ? '顺序' : '倒序',
icon: !_isReversed[_currentTabIndex.value]
? MdiIcons.sortNumericAscending
: MdiIcons.sortNumericDescending,
onPressed: () {
setState(() {
_isReversed[_currentTabIndex.value] =
!_isReversed[_currentTabIndex.value];
});
},
),
),
if (widget.onClose != null)
mediumButton(
tooltip: '关闭',
icon: Icons.close,
onPressed: widget.onClose,
),
],
),
);
}

View File

@@ -1,4 +1,8 @@
import 'package:PiliPlus/common/widgets/interactiveviewer_gallery/interactiveviewer_gallery.dart'
show SourceModel;
import 'package:PiliPlus/utils/extension.dart';
import 'package:PiliPlus/utils/utils.dart';
import 'package:cached_network_image/cached_network_image.dart';
import 'package:flutter/material.dart';
import 'package:flutter_html/flutter_html.dart';
import 'network_img_layer.dart';
@@ -11,6 +15,7 @@ Widget htmlRender({
required double constrainedWidth,
Function(List<String>, int)? callback,
}) {
debugPrint('htmlRender');
return SelectionArea(
child: Html(
data: htmlContent,
@@ -25,17 +30,11 @@ Widget htmlRender({
String imgUrl = key.contains('src')
? attributes['src'] as String
: attributes['data-src'] as String;
if (imgUrl.startsWith('//')) {
imgUrl = 'https:$imgUrl';
}
if (imgUrl.startsWith('http://')) {
imgUrl = imgUrl.replaceAll('http://', 'https://');
}
imgUrl = imgUrl.contains('@') ? imgUrl.split('@').first : imgUrl;
final bool isEmote = imgUrl.contains('/emote/');
final bool isMall = imgUrl.contains('/mall/');
if (isMall) {
return const SizedBox();
return const SizedBox.shrink();
}
// bool inTable =
// extensionContext.element!.previousElementSibling == null ||
@@ -46,6 +45,18 @@ Widget htmlRender({
// width: isEmote ? 22 : null,
// height: isEmote ? 22 : null,
// );
String? clazz = attributes['class'];
String? height = RegExp(r'max-height:(\d+)px')
.firstMatch('${attributes['style']}')
?.group(1);
if (clazz?.contains('cut-off') == true || height != null) {
return CachedNetworkImage(
width: constrainedWidth,
height: height != null ? double.parse(height) : null,
imageUrl: Utils.thumbnailImgUrl(imgUrl),
fit: BoxFit.contain,
);
}
return Hero(
tag: imgUrl,
child: GestureDetector(
@@ -54,7 +65,7 @@ Widget htmlRender({
callback([imgUrl], 0);
} else {
context.imageView(
imgList: [imgUrl],
imgList: [SourceModel(url: imgUrl)],
);
}
},

View File

@@ -22,7 +22,7 @@ Widget iconButton({
color: iconColor ?? Theme.of(context).colorScheme.onSecondaryContainer,
),
style: IconButton.styleFrom(
padding: EdgeInsets.all(0),
padding: EdgeInsets.zero,
backgroundColor:
bgColor ?? Theme.of(context).colorScheme.secondaryContainer,
),

View File

@@ -1,6 +1,7 @@
import 'dart:math';
import 'package:PiliPlus/common/constants.dart';
import 'package:PiliPlus/common/widgets/icon_button.dart';
import 'package:PiliPlus/common/widgets/network_img_layer.dart';
import 'package:PiliPlus/utils/download.dart';
import 'package:flutter/material.dart';
@@ -15,7 +16,7 @@ void imageSaveDialog({
final double imgWidth = min(Get.width, Get.height) - 8 * 2;
SmartDialog.show(
animationType: SmartAnimationType.centerScale_otherSlide,
builder: (context) => Container(
builder: (_) => Container(
width: imgWidth,
margin: const EdgeInsets.symmetric(horizontal: StyleString.safeSpace),
decoration: BoxDecoration(
@@ -71,21 +72,36 @@ void imageSaveDialog({
style: Theme.of(context).textTheme.titleSmall,
),
),
const SizedBox(width: 4),
IconButton(
tooltip: '保存封面图',
onPressed: () async {
bool saveStatus = await DownloadUtils.downloadImg(
context,
[cover ?? ''],
);
// 保存成功,自动关闭弹窗
if (saveStatus) {
if (cover?.isNotEmpty == true) ...[
const SizedBox(width: 4),
iconButton(
context: context,
tooltip: '分享',
onPressed: () {
SmartDialog.dismiss();
}
},
icon: const Icon(Icons.download, size: 20),
)
DownloadUtils.onShareImg(cover!);
},
iconSize: 20,
icon: Icons.share,
bgColor: Colors.transparent,
iconColor: Theme.of(context).colorScheme.onSurfaceVariant,
),
iconButton(
context: context,
tooltip: '保存封面图',
onPressed: () async {
bool saveStatus =
await DownloadUtils.downloadImg(context, [cover!]);
if (saveStatus) {
SmartDialog.dismiss();
}
},
iconSize: 20,
icon: Icons.download,
bgColor: Colors.transparent,
iconColor: Theme.of(context).colorScheme.onSurfaceVariant,
),
],
],
),
),

View File

@@ -2,9 +2,12 @@ import 'dart:math';
import 'package:PiliPlus/common/constants.dart';
import 'package:PiliPlus/common/widgets/badge.dart';
import 'package:PiliPlus/common/widgets/interactiveviewer_gallery/interactiveviewer_gallery.dart'
show SourceModel, SourceType;
import 'package:PiliPlus/common/widgets/network_img_layer.dart';
import 'package:PiliPlus/common/widgets/nine_grid_view.dart';
import 'package:PiliPlus/utils/extension.dart';
import 'package:PiliPlus/utils/storage.dart';
import 'package:flutter/material.dart';
class ImageModel {
@@ -12,19 +15,23 @@ class ImageModel {
required this.width,
required this.height,
required this.url,
this.liveUrl,
});
dynamic width;
dynamic height;
String url;
String? liveUrl;
bool? _isLongPic;
bool? _isLivePhoto;
dynamic get safeWidth => width ?? 1;
dynamic get safeHeight => height ?? 1;
bool get isLongPic => _isLongPic ??= (safeHeight / safeWidth) > (22 / 9);
bool get isLivePhoto => _isLivePhoto ??= liveUrl?.isNotEmpty == true;
}
Widget imageview(
Widget imageView(
double maxWidth,
List<ImageModel> picArr, {
VoidCallback? onViewImage,
@@ -83,6 +90,17 @@ Widget imageview(
);
}
late final enableLivePhoto = GStorage.enableLivePhoto;
int parseSize(size) {
return switch (size) {
int() => size,
double() => size.round(),
String() => int.tryParse(size) ?? 1,
_ => 1,
};
}
return NineGridView(
type: NineGridType.weiBo,
margin: const EdgeInsets.only(top: 6),
@@ -102,7 +120,19 @@ Widget imageview(
onViewImage?.call();
context.imageView(
initialPage: index,
imgList: picArr.map((item) => item.url).toList(),
imgList: picArr.map(
(item) {
bool isLive = item.isLivePhoto && enableLivePhoto;
return SourceModel(
sourceType:
isLive ? SourceType.livePhoto : SourceType.networkImage,
url: item.url,
liveUrl: isLive ? item.liveUrl : null,
width: isLive ? parseSize(item.width) : null,
height: isLive ? parseSize(item.height) : null,
);
},
).toList(),
onDismissed: onDismissed,
);
}
@@ -143,7 +173,14 @@ Widget imageview(
},
),
),
if (picArr[index].isLongPic)
if (picArr[index].isLivePhoto)
const PBadge(
text: 'Live',
right: 8,
bottom: 8,
type: 'gray',
)
else if (picArr[index].isLongPic)
const PBadge(
text: '长图',
right: 8,

View File

@@ -1,18 +1,16 @@
import 'dart:io';
import 'package:PiliPlus/http/init.dart';
import 'package:PiliPlus/utils/download.dart';
import 'package:PiliPlus/utils/extension.dart';
import 'package:PiliPlus/utils/storage.dart';
import 'package:PiliPlus/utils/utils.dart';
import 'package:cached_network_image/cached_network_image.dart';
import 'package:dio/dio.dart';
import 'package:device_info_plus/device_info_plus.dart';
import 'package:flutter/material.dart';
import 'package:flutter_smart_dialog/flutter_smart_dialog.dart';
import 'package:flutter/services.dart';
import 'package:get/get.dart';
import 'package:path_provider/path_provider.dart';
import 'package:share_plus/share_plus.dart';
import 'package:status_bar_control/status_bar_control.dart';
import 'package:media_kit/media_kit.dart';
import 'package:media_kit_video/media_kit_video.dart';
import 'interactive_viewer_boundary.dart';
import 'interactive_viewer.dart' as custom;
@@ -33,6 +31,24 @@ typedef IndexedFocusedWidgetBuilder = Widget Function(
typedef IndexedTagStringBuilder = String Function(int index);
enum SourceType { fileImage, networkImage, livePhoto }
class SourceModel {
final SourceType sourceType;
final String url;
final String? liveUrl;
final int? width;
final int? height;
const SourceModel({
this.sourceType = SourceType.networkImage,
required this.url,
this.liveUrl,
this.width,
this.height,
});
}
class InteractiveviewerGallery<T> extends StatefulWidget {
const InteractiveviewerGallery({
super.key,
@@ -45,17 +61,14 @@ class InteractiveviewerGallery<T> extends StatefulWidget {
this.onDismissed,
this.setStatusBar,
this.onClose,
this.isFile,
});
final bool? isFile;
final VoidCallback? onClose;
final ValueChanged? onClose;
final bool? setStatusBar;
/// The sources to show.
final List<String> sources;
final List<SourceModel> sources;
/// The index of the first source in [sources] to show.
final int initIndex;
@@ -92,17 +105,14 @@ class _InteractiveviewerGalleryState extends State<InteractiveviewerGallery>
late Offset _doubleTapLocalPosition;
int? currentIndex;
late final RxInt currentIndex = widget.initIndex.obs;
late List<bool> _thumbList;
late final int _quality = GStorage.previewQ;
@override
void initState() {
super.initState();
_thumbList = List.generate(widget.sources.length, (_) => true);
_pageController = PageController(initialPage: widget.initIndex);
_transformationController = custom.TransformationController();
@@ -110,38 +120,51 @@ class _InteractiveviewerGalleryState extends State<InteractiveviewerGallery>
_animationController = AnimationController(
vsync: this,
duration: const Duration(milliseconds: 300),
)..addListener(() {
_transformationController!.value =
_animation?.value ?? Matrix4.identity();
});
)..addListener(listener);
currentIndex = widget.initIndex;
if (widget.setStatusBar != false) {
setStatusBar();
}
if (widget.sources[currentIndex.value].sourceType == SourceType.livePhoto) {
_onPlay(currentIndex.value);
}
}
void listener() {
_transformationController!.value = _animation?.value ?? Matrix4.identity();
}
SystemUiMode? mode;
setStatusBar() async {
if (Platform.isIOS || Platform.isAndroid) {
await StatusBarControl.setHidden(
true,
animation: StatusBarAnimation.FADE,
SystemChrome.setEnabledSystemUIMode(
SystemUiMode.immersiveSticky,
);
}
if (Platform.isAndroid &&
(await DeviceInfoPlugin().androidInfo).version.sdkInt < 29) {
mode = SystemUiMode.manual;
}
}
@override
void dispose() async {
void dispose() {
widget.onClose?.call(true);
_player?.dispose();
_pageController?.dispose();
_animationController.removeListener(() {});
_animationController.removeListener(listener);
_animationController.dispose();
if (widget.setStatusBar != false) {
if (Platform.isIOS || Platform.isAndroid) {
StatusBarControl.setHidden(false, animation: StatusBarAnimation.FADE);
SystemChrome.setEnabledSystemUIMode(
mode ?? SystemUiMode.edgeToEdge,
overlays: SystemUiOverlay.values,
);
}
}
if (widget.isFile != true) {
for (int index = 0; index < widget.sources.length; index++) {
for (int index = 0; index < widget.sources.length; index++) {
if (widget.sources[index].sourceType == SourceType.networkImage) {
CachedNetworkImageProvider(_getActualUrl(index)).evict();
}
}
@@ -201,14 +224,22 @@ class _InteractiveviewerGalleryState extends State<InteractiveviewerGallery>
}
}
void _onPlay(int index) {
_player ??= Player();
_videoController ??= VideoController(_player!);
_player!.open(Media(widget.sources[index].liveUrl!));
}
/// When the page view changed its page, the source will animate back into the
/// original scale if it was scaled up.
///
/// Additionally the swipe up / down to dismiss gets enabled.
void _onPageChanged(int page) {
setState(() {
currentIndex = page;
});
_player?.pause();
currentIndex.value = page;
if (widget.sources[page].sourceType == SourceType.livePhoto) {
_onPlay(page);
}
widget.onPageChanged?.call(page);
if (_transformationController!.value != Matrix4.identity()) {
// animate the reset for the transformation of the interactive viewer
@@ -224,19 +255,24 @@ class _InteractiveviewerGalleryState extends State<InteractiveviewerGallery>
}
}
String _getActualUrl(int index) => _thumbList[index] && _quality != 100
? '${widget.sources[index]}@${_quality}q.webp'.http2https
: widget.sources[index].http2https;
String _getActualUrl(int index) {
return _quality != 100
? Utils.thumbnailImgUrl(widget.sources[index].url, _quality)
: widget.sources[index].url.http2https;
}
void onClose() {
if (widget.onClose != null) {
widget.onClose!();
widget.onClose!(false);
} else {
Get.back();
widget.onDismissed?.call(_pageController!.page!.floor());
}
}
Player? _player;
VideoController? _videoController;
@override
Widget build(BuildContext context) {
return Stack(
@@ -272,12 +308,15 @@ class _InteractiveviewerGalleryState extends State<InteractiveviewerGallery>
_doubleTapLocalPosition = details.localPosition;
},
onDoubleTap: onDoubleTap,
onLongPress: widget.isFile == true ? null : onLongPress,
onLongPress:
widget.sources[index].sourceType == SourceType.fileImage
? null
: onLongPress,
child: widget.itemBuilder != null
? widget.itemBuilder!(
context,
index,
index == currentIndex,
index == currentIndex.value,
_enablePageView,
)
: _itemBuilder(index),
@@ -321,51 +360,70 @@ class _InteractiveviewerGalleryState extends State<InteractiveviewerGallery>
if (widget.sources.length > 1)
Align(
alignment: Alignment.center,
child: Text(
"${currentIndex! + 1}/${widget.sources.length}",
style: const TextStyle(color: Colors.white),
child: Obx(
() => Text(
"${currentIndex.value + 1}/${widget.sources.length}",
style: const TextStyle(color: Colors.white),
),
),
),
if (widget.isFile != true)
if (widget.sources[currentIndex.value].sourceType !=
SourceType.fileImage)
Align(
alignment: Alignment.centerRight,
child: PopupMenuButton(
itemBuilder: (context) {
return [
PopupMenuItem(
value: 0,
onTap: () =>
onShareImg(widget.sources[currentIndex!]),
onTap: () => DownloadUtils.onShareImg(
widget.sources[currentIndex.value].url),
child: const Text("分享图片"),
),
PopupMenuItem(
value: 1,
onTap: () {
Utils.copyText(widget.sources[currentIndex!]);
Utils.copyText(
widget.sources[currentIndex.value].url);
},
child: const Text("复制链接"),
),
PopupMenuItem(
value: 2,
onTap: () {
DownloadUtils.downloadImg(
context,
[widget.sources[currentIndex!]],
this.context,
[widget.sources[currentIndex.value].url],
);
},
child: const Text("保存图片"),
),
if (widget.sources.length > 1)
PopupMenuItem(
value: 3,
onTap: () {
DownloadUtils.downloadImg(
context,
widget.sources,
this.context,
widget.sources
.map((item) => item.url)
.toList(),
);
},
child: const Text("保存全部图片"),
),
if (widget.sources[currentIndex.value].sourceType ==
SourceType.livePhoto)
PopupMenuItem(
onTap: () {
DownloadUtils.downloadLivePhoto(
context: this.context,
url: widget.sources[currentIndex.value].url,
liveUrl: widget
.sources[currentIndex.value].liveUrl!,
width:
widget.sources[currentIndex.value].width!,
height: widget
.sources[currentIndex.value].height!,
);
},
child: const Text("保存 Live Photo"),
),
];
},
child: const Icon(Icons.more_horiz, color: Colors.white),
@@ -379,51 +437,54 @@ class _InteractiveviewerGalleryState extends State<InteractiveviewerGallery>
);
}
// 图片分享
void onShareImg(String imgUrl) async {
SmartDialog.showLoading();
var response = await Request()
.get(imgUrl, options: Options(responseType: ResponseType.bytes));
final temp = await getTemporaryDirectory();
SmartDialog.dismiss();
String imgName =
"plpl_pic_${DateTime.now().toString().split('-').join()}.jpg";
var path = '${temp.path}/$imgName';
File(path).writeAsBytesSync(response.data);
Share.shareXFiles([XFile(path)], subject: imgUrl);
}
Widget _itemBuilder(index) {
return Center(
child: Hero(
tag: widget.sources[index],
child: widget.isFile == true
? Image(
filterQuality: FilterQuality.low,
image: FileImage(File(widget.sources[index])),
)
: CachedNetworkImage(
fadeInDuration: const Duration(milliseconds: 0),
fadeOutDuration: const Duration(milliseconds: 0),
imageUrl: _getActualUrl(index),
// fit: BoxFit.contain,
progressIndicatorBuilder: (context, url, progress) {
return Center(
child: SizedBox(
width: 150.0,
child: LinearProgressIndicator(
value: progress.progress ?? 0),
),
);
},
// errorListener: (value) {
// WidgetsBinding.instance.addPostFrameCallback((_) {
// setState(() {
// _thumbList[index] = false;
// });
// });
// },
),
tag: widget.sources[index].url,
child: switch (widget.sources[index].sourceType) {
SourceType.fileImage => Image(
filterQuality: FilterQuality.low,
image: FileImage(File(widget.sources[index].url)),
),
SourceType.networkImage => CachedNetworkImage(
fadeInDuration: Duration.zero,
fadeOutDuration: Duration.zero,
imageUrl: _getActualUrl(index),
placeholderFadeInDuration: Duration.zero,
placeholder: (context, url) {
return CachedNetworkImage(
fadeInDuration: Duration.zero,
fadeOutDuration: Duration.zero,
imageUrl: Utils.thumbnailImgUrl(widget.sources[index].url),
);
},
// fit: BoxFit.contain,
// progressIndicatorBuilder: (context, url, progress) {
// return Center(
// child: SizedBox(
// width: 150.0,
// child:
// LinearProgressIndicator(value: progress.progress ?? 0),
// ),
// );
// },
// errorListener: (value) {
// WidgetsBinding.instance.addPostFrameCallback((_) {
// setState(() {
// _thumbList[index] = false;
// });
// });
// },
),
SourceType.livePhoto => Obx(() => currentIndex.value == index
? IgnorePointer(
child: Video(
controller: _videoController!,
fill: Colors.transparent,
),
)
: const SizedBox.shrink()),
},
),
);
}
@@ -487,7 +548,8 @@ class _InteractiveviewerGalleryState extends State<InteractiveviewerGallery>
children: [
ListTile(
onTap: () {
onShareImg(widget.sources[currentIndex!]);
DownloadUtils.onShareImg(
widget.sources[currentIndex.value].url);
Get.back();
},
dense: true,
@@ -496,7 +558,7 @@ class _InteractiveviewerGalleryState extends State<InteractiveviewerGallery>
ListTile(
onTap: () {
Get.back();
Utils.copyText(widget.sources[currentIndex!]);
Utils.copyText(widget.sources[currentIndex.value].url);
},
dense: true,
title: const Text('复制链接', style: TextStyle(fontSize: 14)),
@@ -505,8 +567,8 @@ class _InteractiveviewerGalleryState extends State<InteractiveviewerGallery>
onTap: () {
Get.back();
DownloadUtils.downloadImg(
context,
[widget.sources[currentIndex!]],
this.context,
[widget.sources[currentIndex.value].url],
);
},
dense: true,
@@ -517,13 +579,32 @@ class _InteractiveviewerGalleryState extends State<InteractiveviewerGallery>
onTap: () {
Get.back();
DownloadUtils.downloadImg(
context,
widget.sources,
this.context,
widget.sources.map((item) => item.url).toList(),
);
},
dense: true,
title: const Text('保存全部图片', style: TextStyle(fontSize: 14)),
),
if (widget.sources[currentIndex.value].sourceType ==
SourceType.livePhoto)
ListTile(
onTap: () {
Get.back();
DownloadUtils.downloadLivePhoto(
context: this.context,
url: widget.sources[currentIndex.value].url,
liveUrl: widget.sources[currentIndex.value].liveUrl!,
width: widget.sources[currentIndex.value].width!,
height: widget.sources[currentIndex.value].height!,
);
},
dense: true,
title: const Text(
'保存 Live Photo',
style: TextStyle(fontSize: 14),
),
),
],
),
);

View File

@@ -0,0 +1,27 @@
import 'package:flutter/material.dart';
class KeepAliveWrapper extends StatefulWidget {
const KeepAliveWrapper({
super.key,
required this.builder,
this.wantKeepAlive = true,
});
final WidgetBuilder builder;
final bool wantKeepAlive;
@override
State<KeepAliveWrapper> createState() => _KeepAliveWrapperState();
}
class _KeepAliveWrapperState extends State<KeepAliveWrapper>
with AutomaticKeepAliveClientMixin {
@override
Widget build(BuildContext context) {
super.build(context);
return widget.builder(context);
}
@override
bool get wantKeepAlive => widget.wantKeepAlive;
}

View File

@@ -1,493 +0,0 @@
import 'dart:async';
import 'dart:math';
import 'package:PiliPlus/common/constants.dart';
import 'package:PiliPlus/common/widgets/icon_button.dart';
import 'package:PiliPlus/common/widgets/network_img_layer.dart';
import 'package:PiliPlus/http/video.dart';
import 'package:PiliPlus/models/bangumi/info.dart' as bangumi;
import 'package:PiliPlus/models/video_detail_res.dart' as video;
import 'package:flutter/material.dart';
import 'package:flutter_smart_dialog/flutter_smart_dialog.dart';
import 'package:material_design_icons_flutter/material_design_icons_flutter.dart';
import 'package:scrollable_positioned_list/scrollable_positioned_list.dart';
import '../../utils/storage.dart';
import '../../utils/utils.dart';
class ListSheetContent extends StatefulWidget {
const ListSheetContent({
super.key,
this.index, // tab index
this.season,
this.episodes,
this.bvid,
this.aid,
required this.currentCid,
required this.changeFucCall,
this.onClose,
this.onReverse,
this.showTitle,
this.isSupportReverse,
this.isReversed,
});
final dynamic index;
final dynamic season;
final dynamic episodes;
final String? bvid;
final int? aid;
final int currentCid;
final Function changeFucCall;
final VoidCallback? onClose;
final VoidCallback? onReverse;
final bool? showTitle;
final bool? isSupportReverse;
final bool? isReversed;
@override
State<ListSheetContent> createState() => _ListSheetContentState();
}
class _ListSheetContentState extends State<ListSheetContent>
with TickerProviderStateMixin {
late List<ItemScrollController> itemScrollController = [];
late int currentIndex = _currentIndex;
late List<bool> reverse;
int get _index => widget.index ?? 0;
late final bool _isList = widget.season != null &&
widget.season?.sections is List &&
widget.season.sections.length > 1;
dynamic get episodes =>
widget.episodes ?? widget.season?.sections[_index].episodes;
TabController? _ctr;
StreamController? _indexStream;
int? _seasonFav;
StreamController? _favStream;
@override
void didUpdateWidget(ListSheetContent oldWidget) {
super.didUpdateWidget(oldWidget);
if (widget.showTitle != false) {
return;
}
int currentIndex = _currentIndex;
void jumpToCurrent() {
if (this.currentIndex != currentIndex) {
this.currentIndex = currentIndex;
try {
itemScrollController[_index].jumpTo(
index: currentIndex,
);
} catch (_) {}
}
}
// jump to current
if (_ctr != null && widget.index != _ctr?.index) {
_ctr?.animateTo(_index, duration: const Duration(milliseconds: 200));
Future.delayed(const Duration(milliseconds: 300)).then((_) {
jumpToCurrent();
});
} else {
jumpToCurrent();
}
}
int get _currentIndex => max(
0,
_isList
? widget.season.sections[_index].episodes
.indexWhere((e) => e.cid == widget.currentCid)
: episodes.indexWhere((e) => e.cid == widget.currentCid));
@override
void initState() {
super.initState();
if (_isList) {
_indexStream ??= StreamController<int>.broadcast();
_ctr = TabController(
vsync: this,
length: widget.season.sections.length,
initialIndex: _index,
)..addListener(() {
_indexStream?.add(_ctr?.index);
});
}
itemScrollController = _isList
? List.generate(
widget.season.sections.length, (_) => ItemScrollController())
: [ItemScrollController()];
reverse = _isList
? List.generate(widget.season.sections.length, (_) => false)
: [false];
if (widget.bvid != null && widget.season != null) {
_favStream ??= StreamController<int>();
() async {
dynamic result = await VideoHttp.videoRelation(bvid: widget.bvid);
if (result['status']) {
_seasonFav = result['data']['season_fav'] ? 1 : 0;
_favStream?.add(_seasonFav);
}
}();
}
WidgetsBinding.instance.addPostFrameCallback((_) {
try {
itemScrollController[_index].jumpTo(index: currentIndex);
} catch (_) {}
});
}
@override
void dispose() {
_favStream?.close();
_favStream = null;
_indexStream?.close();
_indexStream = null;
_ctr?.removeListener(() {});
_ctr?.dispose();
super.dispose();
}
Widget buildEpisodeListItem(
dynamic episode,
int index,
int length,
bool isCurrentIndex,
) {
Color primary = Theme.of(context).colorScheme.primary;
late String title;
if (episode.runtimeType.toString() == "EpisodeItem") {
if (episode.longTitle != null && episode.longTitle != "") {
dynamic leading = episode.title ?? index + 1;
title =
"${Utils.isStringNumeric(leading) ? '$leading话' : leading} ${episode.longTitle!}";
} else {
title = episode.title!;
}
} else if (episode.runtimeType.toString() == "PageItem") {
title = episode.pagePart!;
} else if (episode.runtimeType.toString() == "Part") {
title = episode.pagePart!;
// debugPrint("未知类型:${episode.runtimeType}");
}
return ListTile(
onTap: () {
if (episode.badge != null && episode.badge == "会员") {
dynamic userInfo = GStorage.userInfo.get('userInfoCache');
int vipStatus = 0;
if (userInfo != null) {
vipStatus = userInfo.vipStatus;
}
if (vipStatus != 1) {
SmartDialog.showToast('需要大会员');
// return;
}
}
SmartDialog.showToast('切换到:$title');
widget.onClose?.call();
currentIndex = index;
widget.changeFucCall(
episode is bangumi.EpisodeItem ? episode.epId : null,
episode.runtimeType.toString() == "EpisodeItem"
? episode.bvid
: widget.bvid,
episode.cid,
episode.runtimeType.toString() == "EpisodeItem"
? episode.aid
: widget.aid,
episode is video.EpisodeItem
? episode.arc?.pic
: episode is bangumi.EpisodeItem
? episode.cover
: null,
);
},
dense: false,
leading: (episode is video.EpisodeItem && episode.arc?.pic != null) ||
(episode is video.Part && episode.firstFrame != null) ||
(episode is bangumi.EpisodeItem && episode.cover != null)
? Container(
margin: const EdgeInsets.symmetric(vertical: 6),
decoration: isCurrentIndex
? BoxDecoration(
borderRadius: BorderRadius.circular(6),
border: Border.all(
width: 1.8,
strokeAlign: BorderSide.strokeAlignOutside,
color: Theme.of(context).colorScheme.primary,
),
)
: null,
child: LayoutBuilder(
builder: (context, constraints) => NetworkImgLayer(
radius: 6,
src: episode is video.EpisodeItem
? episode.arc?.pic
: episode is bangumi.EpisodeItem
? episode.cover
: episode.firstFrame,
width: constraints.maxHeight * StyleString.aspectRatio,
height: constraints.maxHeight,
),
),
)
: isCurrentIndex
? Image.asset(
'assets/images/live.png',
color: primary,
height: 12,
semanticLabel: "正在播放:",
)
: null,
title: Text(
title,
style: TextStyle(
fontSize: 14,
fontWeight: isCurrentIndex ? FontWeight.bold : null,
color: isCurrentIndex
? primary
: Theme.of(context).colorScheme.onSurface,
),
),
trailing: Row(
mainAxisSize: MainAxisSize.min,
children: [
if (episode.badge != null) ...[
if (episode.badge == '会员')
Image.asset(
'assets/images/big-vip.png',
height: 20,
semanticLabel: "大会员",
)
else
Text(episode.badge),
const SizedBox(width: 10),
],
if (episode is! bangumi.EpisodeItem) Text('${index + 1}/$length'),
],
),
);
}
@override
Widget build(BuildContext context) {
return Container(
height: Utils.getSheetHeight(context),
color: Theme.of(context).colorScheme.surface,
child: Column(
children: [
Container(
height: 45,
padding: EdgeInsets.symmetric(
horizontal: widget.showTitle != false ? 14 : 6),
child: Row(
children: [
if (widget.showTitle != false)
Text(
'合集(${_isList ? widget.season.epCount : episodes?.length ?? ''})',
style: Theme.of(context).textTheme.titleMedium,
),
StreamBuilder(
stream: _favStream?.stream,
builder: (context, snapshot) => snapshot.hasData
? mediumButton(
tooltip: _seasonFav == 1 ? '取消订阅' : '订阅',
icon: _seasonFav == 1
? Icons.notifications_off_outlined
: Icons.notifications_active_outlined,
onPressed: () async {
dynamic result = await VideoHttp.seasonFav(
isFav: _seasonFav == 1,
seasonId: widget.season.id,
);
if (result['status']) {
SmartDialog.showToast(
'${_seasonFav == 1 ? '取消' : ''}订阅成功');
_seasonFav = _seasonFav == 1 ? 0 : 1;
_favStream?.add(_seasonFav);
} else {
SmartDialog.showToast(result['msg']);
}
},
)
: const SizedBox.shrink(),
),
mediumButton(
tooltip: '跳至顶部',
icon: Icons.vertical_align_top,
onPressed: () {
try {
itemScrollController[_ctr?.index ?? 0].scrollTo(
index: !reverse[_ctr?.index ?? 0]
? 0
: _isList
? widget.season.sections[_ctr?.index].episodes
.length -
1
: episodes.length - 1,
duration: const Duration(milliseconds: 200),
);
} catch (_) {}
},
),
mediumButton(
tooltip: '跳至底部',
icon: Icons.vertical_align_bottom,
onPressed: () {
try {
itemScrollController[_ctr?.index ?? 0].scrollTo(
index: !reverse[_ctr?.index ?? 0]
? _isList
? widget.season.sections[_ctr?.index].episodes
.length -
1
: episodes.length - 1
: 0,
duration: const Duration(milliseconds: 200),
);
} catch (_) {}
},
),
mediumButton(
tooltip: '跳至当前',
icon: Icons.my_location,
onPressed: () async {
if (_ctr != null && _ctr?.index != (_index)) {
_ctr?.animateTo(_index);
await Future.delayed(const Duration(milliseconds: 225));
}
try {
itemScrollController[_ctr?.index ?? 0].scrollTo(
index: currentIndex,
duration: const Duration(milliseconds: 200),
);
} catch (_) {}
},
),
if (widget.isSupportReverse == true)
if (!_isList)
_reverseButton
else
StreamBuilder(
stream: _indexStream?.stream,
initialData: _index,
builder: (context, snapshot) {
return snapshot.data == _index
? _reverseButton
: const SizedBox.shrink();
},
),
const Spacer(),
StreamBuilder(
stream: _indexStream?.stream,
initialData: _index,
builder: (context, snapshot) => mediumButton(
tooltip: reverse[snapshot.data] ? '顺序' : '倒序',
icon: !reverse[snapshot.data]
? MdiIcons.sortNumericAscending
: MdiIcons.sortNumericDescending,
onPressed: () {
setState(() {
reverse[_ctr?.index ?? 0] = !reverse[_ctr?.index ?? 0];
});
},
),
),
if (widget.onClose != null)
mediumButton(
tooltip: '关闭',
icon: Icons.close,
onPressed: widget.onClose,
),
],
),
),
Divider(
height: 1,
color: Theme.of(context).dividerColor.withOpacity(0.1),
),
if (_isList)
Material(
child: TabBar(
controller: _ctr,
padding: const EdgeInsets.only(right: 60),
isScrollable: true,
tabs: (widget.season.sections as List)
.map((item) => Tab(text: item.title))
.toList(),
dividerHeight: 1,
dividerColor: Theme.of(context).dividerColor.withOpacity(0.1),
),
),
Expanded(
child: _isList
? TabBarView(
controller: _ctr,
children: List.generate(
widget.season.sections.length,
(index) => _buildBody(
index, widget.season.sections[index].episodes),
),
)
: _buildBody(null, episodes),
),
],
),
);
}
Widget get _reverseButton => mediumButton(
tooltip: widget.isReversed == true ? '正序播放' : '倒序播放',
icon: widget.isReversed == true
? MdiIcons.sortDescending
: MdiIcons.sortAscending,
onPressed: () async {
if (widget.showTitle == false) {
// jump to current
if (_ctr != null && _ctr?.index != (_index)) {
_ctr?.animateTo(_index);
await Future.delayed(const Duration(milliseconds: 225));
}
try {
itemScrollController[_ctr?.index ?? 0].scrollTo(
index: currentIndex,
duration: const Duration(milliseconds: 200),
);
} catch (_) {}
}
widget.onReverse?.call();
},
);
Widget _buildBody(i, episodes) => Material(
child: ScrollablePositionedList.separated(
padding: EdgeInsets.only(
bottom: MediaQuery.of(context).padding.bottom + 80,
),
reverse: reverse[i ?? 0],
itemCount: episodes.length,
itemBuilder: (BuildContext context, int index) {
return buildEpisodeListItem(
episodes[index],
index,
episodes.length,
i != null
? i == (_index)
? currentIndex == index
: false
: currentIndex == index,
);
},
itemScrollController: itemScrollController[i ?? 0],
separatorBuilder: (context, index) => Divider(
height: 1,
color: Theme.of(context).dividerColor.withOpacity(0.1),
),
),
);
}

View File

@@ -1,5 +1,4 @@
import 'package:PiliPlus/common/widgets/http_error.dart';
import 'package:PiliPlus/utils/global_data.dart';
import 'package:flutter/material.dart';
Widget get loadingWidget => Center(child: CircularProgressIndicator());
@@ -18,27 +17,3 @@ Widget scrollErrorWidget({errMsg, callback}) => CustomScrollView(
)
],
);
Widget replyErrorWidget(context, isSliver, errMsg, onReload) => HttpError(
isSliver: isSliver,
errMsg:
'${errMsg.startsWith('gRPC Error') ? '如无法加载评论:\n关闭代理\n或设置中关闭使用gRPC加载评论\n\n' : ''}$errMsg',
callback: onReload,
extraWidget: errMsg.startsWith('gRPC Error') && GlobalData().grpcReply
? FilledButton.tonal(
onPressed: () {
GlobalData().grpcReply = false;
onReload();
},
style: ButtonStyle(
backgroundColor: WidgetStateProperty.resolveWith((states) {
return Theme.of(context).colorScheme.primary.withAlpha(20);
}),
),
child: Text(
'暂时关闭gRPC加载评论',
style: TextStyle(color: Theme.of(context).colorScheme.primary),
),
)
: null,
);

View File

@@ -1,7 +1,7 @@
import 'package:PiliPlus/utils/utils.dart';
import 'package:cached_network_image/cached_network_image.dart';
import 'package:flutter/material.dart';
import 'package:PiliPlus/utils/extension.dart';
import 'package:PiliPlus/utils/global_data.dart';
import '../constants.dart';
class NetworkImgLayer extends StatelessWidget {
@@ -22,6 +22,7 @@ class NetworkImgLayer extends StatelessWidget {
this.isLongPic,
this.callback,
this.getPlaceHolder,
this.boxFit,
});
final String? src;
@@ -38,6 +39,7 @@ class NetworkImgLayer extends StatelessWidget {
final Function? isLongPic;
final Function? callback;
final Function? getPlaceHolder;
final BoxFit? boxFit;
@override
Widget build(BuildContext context) {
@@ -56,43 +58,31 @@ class NetworkImgLayer extends StatelessWidget {
}
Widget _buildImage(context) {
late final int defaultImgQuality = GlobalData().imgQuality;
bool thumbnail = true;
int? memCacheWidth, memCacheHeight;
if (callback?.call() == true || width <= height) {
if (ignoreHeight == true || callback?.call() == true || width <= height) {
memCacheWidth = width.cacheSize(context);
} else {
memCacheHeight = height.cacheSize(context);
}
return CachedNetworkImage(
imageUrl:
'${src?.startsWith('//') == true ? 'https:$src' : src?.http2https}${type != 'emote' && type != 'cover' && thumbnail ? '@${quality ?? defaultImgQuality}q.webp' : ''}',
imageUrl: Utils.thumbnailImgUrl(src, quality),
width: width,
height: ignoreHeight == null || ignoreHeight == false ? height : null,
memCacheWidth: memCacheWidth,
memCacheHeight: memCacheHeight,
fit: BoxFit.cover,
fit: boxFit ?? BoxFit.cover,
alignment:
isLongPic?.call() == true ? Alignment.topCenter : Alignment.center,
fadeOutDuration: fadeOutDuration ?? const Duration(milliseconds: 120),
fadeInDuration: fadeInDuration ?? const Duration(milliseconds: 120),
filterQuality: FilterQuality.low,
// errorWidget: (BuildContext context, String url, Object error) =>
// placeholder(context),
placeholder: (BuildContext context, String url) =>
getPlaceHolder?.call() ?? placeholder(context),
imageBuilder: imageBuilder,
// errorListener: (value) {
// thumbnail = false;
// if (context.mounted) {
// (context as Element).markNeedsBuild();
// }
// },
);
}
Widget placeholder(BuildContext context) {
int cacheWidth = width.cacheSize(context);
return Container(
width: width,
height: height,
@@ -115,7 +105,7 @@ class NetworkImgLayer extends StatelessWidget {
: 'assets/images/loading.png',
width: width,
height: height,
cacheWidth: cacheWidth == 0 ? null : cacheWidth,
cacheWidth: width.cacheSize(context),
// cacheHeight: height.cacheSize(context),
),
),

View File

@@ -410,7 +410,7 @@ class _NineGridViewState extends State<NineGridView> {
@override
Widget build(BuildContext context) {
Widget? child = Container();
Widget? child;
double? realWidth = widget.width;
double? realHeight = widget.height;
switch (widget.type) {

View File

@@ -6,3 +6,14 @@ class Pair<T, R> {
T first;
R second;
}
class Triple<T, R, S> {
Triple({
required this.first,
required this.second,
required this.third,
});
T first;
R second;
S third;
}

View File

@@ -0,0 +1,93 @@
import 'package:flutter/material.dart';
class RadioWidget<T> extends StatelessWidget {
final T value;
final T? groupValue;
final ValueChanged<T?> onChanged;
final String title;
final EdgeInsetsGeometry? padding;
const RadioWidget({
super.key,
required this.value,
this.groupValue,
required this.onChanged,
required this.title,
this.padding,
});
Widget _child() => Row(
children: [
Radio<T>(
value: value,
groupValue: groupValue,
onChanged: onChanged,
materialTapTargetSize: MaterialTapTargetSize.shrinkWrap,
),
Text(title),
],
);
@override
Widget build(BuildContext context) {
return InkWell(
onTap: () => onChanged(value),
child: padding != null
? Padding(
padding: padding!,
child: _child(),
)
: _child(),
);
}
}
class WrapRadioOptionsGroup<T> extends StatelessWidget {
final String groupTitle;
final Map<T, String> options;
final T? selectedValue;
final ValueChanged<T?> onChanged;
final EdgeInsetsGeometry? itemPadding;
const WrapRadioOptionsGroup({
super.key,
required this.groupTitle,
required this.options,
required this.selectedValue,
required this.onChanged,
this.itemPadding,
});
@override
Widget build(BuildContext context) {
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
if (groupTitle.isNotEmpty)
Padding(
padding: const EdgeInsets.only(left: 22),
child: Text(
groupTitle,
style: TextStyle(color: Theme.of(context).colorScheme.outline),
),
),
Padding(
padding: const EdgeInsets.symmetric(horizontal: 12),
child: Wrap(
children: options.entries.map((entry) {
return IntrinsicWidth(
child: RadioWidget<T>(
value: entry.key,
groupValue: selectedValue,
onChanged: onChanged,
title: entry.value,
padding: itemPadding ?? const EdgeInsets.only(right: 10),
),
);
}).toList(),
),
),
],
);
}
}

View File

@@ -0,0 +1,225 @@
import 'package:PiliPlus/common/widgets/radio_widget.dart';
import 'package:PiliPlus/utils/extension.dart';
import 'package:flutter/material.dart';
import 'package:flutter_smart_dialog/flutter_smart_dialog.dart';
import 'package:get/get.dart';
void autoWrapReportDialog(
BuildContext context,
Map<String, Map<int, String>> options,
Future<Map> Function(int, String?, bool) onSuccess,
) {
int? reasonType;
String? reasonDesc;
bool banUid = false;
late final key = GlobalKey<FormState>();
showDialog(
context: context,
builder: (context) => StatefulBuilder(
builder: (context, setState) {
return AlertDialog(
title: const Text('举报'),
titlePadding: const EdgeInsets.only(left: 22, top: 16, right: 22),
contentPadding: const EdgeInsets.symmetric(vertical: 5),
actionsPadding:
const EdgeInsets.only(left: 16, right: 16, bottom: 10),
content: Form(
key: key,
child: Column(
mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Flexible(
child: SingleChildScrollView(
child: AnimatedSize(
duration: const Duration(milliseconds: 200),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
const Padding(
padding: EdgeInsets.only(
left: 22,
right: 22,
bottom: 5,
),
child: Text('请选择举报的理由:'),
),
...options.entries.map(
(entry) => WrapRadioOptionsGroup<int>(
groupTitle: entry.key,
options: entry.value,
selectedValue: reasonType,
onChanged: (value) =>
setState(() => reasonType = value),
),
),
if (reasonType == 0)
ReasonField(
onChanged: (value) => reasonDesc = value),
],
),
),
),
),
BanUserCheckbox(onChanged: (value) => banUid = value),
],
),
),
actions: [
TextButton(
onPressed: Get.back,
child: Text(
'取消',
style: TextStyle(color: Theme.of(context).colorScheme.outline),
),
),
TextButton(
onPressed: () async {
if (reasonType == null ||
(reasonType == 0 && key.currentState?.validate() != true)) {
return;
}
SmartDialog.showLoading();
try {
final data = await onSuccess(reasonType!, reasonDesc, banUid);
SmartDialog.dismiss();
if (data['code'] == 0) {
Get.back();
SmartDialog.showToast('举报成功');
} else {
SmartDialog.showToast(data['message']);
}
} catch (e) {
SmartDialog.dismiss();
SmartDialog.showToast('提交失败:$e');
}
},
child: const Text('确定'),
),
],
);
},
),
);
}
class ReasonField extends StatefulWidget {
final ValueChanged<String> onChanged;
String? _validator(String? value) => value.isNullOrEmpty ? '理由不能为空' : null;
const ReasonField({super.key, required this.onChanged});
@override
State<ReasonField> createState() => _ReasonFieldState();
}
class _ReasonFieldState extends State<ReasonField> {
final _controller = TextEditingController();
@override
void dispose() {
_controller.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
return Padding(
padding: const EdgeInsets.only(left: 22, top: 5, right: 22),
child: TextFormField(
controller: _controller,
autofocus: true,
minLines: 4,
maxLines: 4,
decoration: const InputDecoration(
labelText: '为帮助审核人员更快处理,请补充问题类型和出现位置等详细信息',
border: OutlineInputBorder(),
contentPadding: EdgeInsets.all(10),
),
onChanged: (value) {
widget.onChanged(value);
},
validator: widget._validator,
),
);
}
}
class BanUserCheckbox extends StatefulWidget {
final ValueChanged<bool> onChanged;
const BanUserCheckbox({super.key, required this.onChanged});
@override
State<BanUserCheckbox> createState() => _BanUserCheckboxState();
}
class _BanUserCheckboxState extends State<BanUserCheckbox> {
bool _banUid = false;
@override
Widget build(BuildContext context) {
return GestureDetector(
onTap: () {
setState(() => _banUid = !_banUid);
widget.onChanged(_banUid);
},
child: Padding(
padding: const EdgeInsets.only(left: 18, top: 10),
child: Row(
children: [
Icon(
size: 22,
_banUid
? Icons.check_box_outlined
: Icons.check_box_outline_blank,
color: _banUid
? Theme.of(context).colorScheme.primary
: Theme.of(context).colorScheme.onSurfaceVariant,
),
Text(
' 拉黑该用户',
style: TextStyle(
color: _banUid ? Theme.of(context).colorScheme.primary : null,
),
),
],
),
),
);
}
}
class ReportOptions {
// from https://s1.hdslb.com/bfs/seed/jinkela/comment-h5/static/js/605.chunks.js
static Map<String, Map<int, String>> get commentReport => {
'违反法律法规': {9: '违法违规', 2: '色情', 10: '低俗', 12: '赌博诈骗', 23: '违法信息外链'},
'谣言类不实信息': {19: '涉政谣言', 22: '虚假不实信息', 20: '涉社会事件谣言'},
'侵犯个人权益': {7: '人身攻击', 15: '侵犯隐私'},
'有害社区环境': {
1: '垃圾广告',
4: '引战',
5: '剧透',
3: '刷屏',
8: '视频不相关',
18: '违规抽奖',
17: '青少年不良信息',
},
'其他': {0: '其他'},
};
static Map<String, Map<int, String>> get dynamicReport => {
'': {
4: '垃圾广告',
8: '引战',
1: '色情',
5: '人身攻击',
3: '违法信息',
9: '涉政谣言',
10: '涉社会事件谣言',
12: '虚假不实信息',
13: '违法信息外链',
0: '其他',
},
};
}

View File

@@ -0,0 +1,559 @@
import 'dart:math';
import 'dart:typed_data';
import 'dart:ui';
import 'package:PiliPlus/common/widgets/icon_button.dart';
import 'package:PiliPlus/common/widgets/network_img_layer.dart';
import 'package:PiliPlus/grpc/app/main/community/reply/v1/reply.pb.dart';
import 'package:PiliPlus/models/dynamics/result.dart';
import 'package:PiliPlus/pages/bangumi/introduction/controller.dart';
import 'package:PiliPlus/pages/dynamics/widgets/dynamic_panel.dart';
import 'package:PiliPlus/pages/video/detail/introduction/controller.dart';
import 'package:PiliPlus/pages/video/detail/reply/widgets/reply_item_grpc.dart';
import 'package:PiliPlus/utils/download.dart';
import 'package:PiliPlus/utils/utils.dart';
import 'package:flutter/material.dart';
import 'package:flutter/rendering.dart';
import 'package:flutter_smart_dialog/flutter_smart_dialog.dart';
import 'package:get/get.dart';
import 'package:pretty_qr_code/pretty_qr_code.dart';
import 'package:saver_gallery/saver_gallery.dart';
import 'package:share_plus/share_plus.dart';
class SavePanel extends StatefulWidget {
const SavePanel({
required this.item,
// reply
this.upMid,
super.key,
});
final dynamic upMid;
final dynamic item;
@override
State<SavePanel> createState() => _SavePanelState();
static void toSavePanel({upMid, item}) {
Get.generalDialog(
barrierLabel: '',
barrierDismissible: true,
pageBuilder: (context, animation, secondaryAnimation) {
return SavePanel(upMid: upMid, item: item);
},
transitionDuration: const Duration(milliseconds: 255),
transitionBuilder: (context, animation, secondaryAnimation, child) {
var tween = Tween<double>(begin: 0, end: 1)
.chain(CurveTween(curve: Curves.easeInOut));
return FadeTransition(
opacity: animation.drive(tween),
child: child,
);
},
routeSettings: RouteSettings(arguments: Get.arguments),
);
}
}
class _SavePanelState extends State<SavePanel> {
final boundaryKey = GlobalKey();
bool showBottom = true;
// item
dynamic get _item => widget.item;
late String viewType = '查看';
late String itemType = '内容';
//reply
String? cover;
String? title;
int? pubdate;
String? uname;
String uri = '';
@override
void initState() {
super.initState();
if (_item is ReplyInfo) {
itemType = '评论';
final currentRoute = Get.currentRoute;
late final hasRoot = _item.hasRoot();
if (currentRoute.startsWith('/video')) {
try {
final heroTag = Get.arguments?['heroTag'];
late final ctr = Get.find<VideoIntroController>(tag: heroTag);
cover = ctr.videoDetail.value.pic;
title = ctr.videoDetail.value.title;
pubdate = ctr.videoDetail.value.pubdate;
uname = ctr.videoDetail.value.owner?.name;
} catch (_) {}
uri =
'bilibili://video/${_item.oid}?comment_root_id=${hasRoot ? _item.root : _item.id}${hasRoot ? '&comment_secondary_id=${_item.id}' : ''}';
try {
final heroTag = Get.arguments?['heroTag'];
late final ctr = Get.find<BangumiIntroController>(tag: heroTag);
final type = _item.type.toInt();
late final oid = _item.oid;
late final rootId = hasRoot ? _item.root : _item.id;
late final anchor = hasRoot ? 'anchor=${_item.id}&' : '';
uri =
'bilibili://comment/detail/$type/$oid/$rootId/?${anchor}enterUri=bilibili://pgc/season/ep/${ctr.epId}';
} catch (_) {}
} else if (currentRoute.startsWith('/dynamicDetail')) {
try {
DynamicItemModel dynItem = Get.arguments['item'];
uname = dynItem.modules?.moduleAuthor?.name;
final type = _item.type.toInt();
late final oid = dynItem.idStr;
late final rootId = hasRoot ? _item.root : _item.id;
late final anchor = hasRoot ? 'anchor=${_item.id}&' : '';
late final enterUri = parseDyn(dynItem);
viewType = '查看';
itemType = '评论';
uri = switch (type) {
1 ||
11 ||
12 =>
'bilibili://comment/detail/$type/${dynItem.basic!['rid_str']}/$rootId/?${anchor}enterUri=$enterUri',
_ =>
'bilibili://comment/detail/$type/$oid/$rootId/?${anchor}enterUri=$enterUri',
};
} catch (_) {}
} else if (currentRoute.startsWith('/Scaffold')) {
try {
final type = _item.type.toInt();
late final oid = Get.arguments['oid'];
late final rootId = hasRoot ? _item.root : _item.id;
late final anchor = hasRoot ? 'anchor=${_item.id}&' : '';
late final enterUri = 'bilibili://following/detail/$oid';
uri = switch (type) {
1 ||
11 ||
12 =>
'bilibili://comment/detail/$type/$oid/$rootId/?${anchor}enterUri=${Get.arguments['enterUri']}',
_ =>
'bilibili://comment/detail/$type/$oid/$rootId/?${anchor}enterUri=$enterUri',
};
} catch (_) {}
} else if (currentRoute.startsWith('/htmlRender')) {
try {
final type = _item.type.toInt();
late final oid = _item.oid;
late final rootId = hasRoot ? _item.root : _item.id;
late final anchor = hasRoot ? 'anchor=${_item.id}&' : '';
late final enterUri =
'bilibili://following/detail/${Get.parameters['id'] ?? Get.arguments?['id']}';
uri =
'bilibili://comment/detail/$type/$oid/$rootId/?${anchor}enterUri=$enterUri';
} catch (_) {}
}
debugPrint(uri);
} else if (_item is DynamicItemModel) {
uri = parseDyn(_item);
debugPrint(uri);
}
}
String parseDyn(item) {
String uri = '';
try {
switch (item.type) {
case 'DYNAMIC_TYPE_AV':
viewType = '观看';
itemType = '视频';
uri = 'bilibili://video/${item.basic!['comment_id_str']}';
break;
case 'DYNAMIC_TYPE_ARTICLE':
itemType = '专栏';
uri = 'bilibili://following/detail/${item.idStr}';
break;
case 'DYNAMIC_TYPE_LIVE_RCMD':
viewType = '观看';
itemType = '直播';
final roomId = item.modules.moduleDynamic.major.liveRcmd.roomId;
uri = 'bilibili://live/$roomId';
break;
case 'DYNAMIC_TYPE_UGC_SEASON':
viewType = '观看';
itemType = '合集';
int aid = item.modules.moduleDynamic.major.ugcSeason.aid;
uri = 'bilibili://video/$aid';
break;
case 'DYNAMIC_TYPE_PGC':
case 'DYNAMIC_TYPE_PGC_UNION':
viewType = '观看';
itemType =
item?.modules?.moduleDynamic?.major?.pgc?.badge?['text'] ?? '番剧';
final epid = item.modules.moduleDynamic.major.pgc.epid;
uri = 'bilibili://pgc/season/ep/$epid';
break;
// https://www.bilibili.com/medialist/detail/ml12345678
case 'DYNAMIC_TYPE_MEDIALIST':
itemType = '收藏夹';
final mediaId = item.modules.moduleDynamic.major.medialist!['id'];
uri = 'bilibili://medialist/detail/$mediaId';
break;
// 纯文字动态查看
// case 'DYNAMIC_TYPE_WORD':
// # 装扮/剧集点评/普通分享
// case 'DYNAMIC_TYPE_COMMON_SQUARE':
// 转发的动态
// case 'DYNAMIC_TYPE_FORWARD':
// 图文动态查看
// case 'DYNAMIC_TYPE_DRAW':
default:
itemType = '动态';
uri = 'bilibili://following/detail/${item.idStr}';
break;
}
} catch (_) {}
return uri;
}
void _onSaveOrSharePic([bool isShare = false]) async {
if (!isShare) {
if (mounted &&
!await DownloadUtils.checkPermissionDependOnSdkInt(context)) {
return;
}
}
SmartDialog.showLoading();
try {
RenderRepaintBoundary boundary = boundaryKey.currentContext!
.findRenderObject() as RenderRepaintBoundary;
var image = await boundary.toImage(pixelRatio: 3);
ByteData? byteData = await image.toByteData(format: ImageByteFormat.png);
Uint8List pngBytes = byteData!.buffer.asUint8List();
String picName =
"plpl_reply_${DateTime.now().toString().substring(0, 19).replaceAll(RegExp(r'[- :]'), '')}";
if (isShare) {
Get.back();
SmartDialog.dismiss();
Share.shareXFiles(
[
XFile.fromData(
pngBytes,
name: picName,
mimeType: 'image/png',
)
],
sharePositionOrigin: await Utils.isIpad()
? Rect.fromLTWH(0, 0, Get.width, Get.height / 2)
: null,
);
} else {
final result = await SaverGallery.saveImage(
pngBytes,
fileName: '$picName.png',
androidRelativePath: "Pictures/PiliPlus",
skipIfExists: false,
);
SmartDialog.dismiss();
if (result.isSuccess) {
Get.back();
SmartDialog.showToast('保存成功');
} else if (result.errorMessage?.isNotEmpty == true) {
SmartDialog.showToast(result.errorMessage!);
}
}
} catch (e) {
debugPrint('on save/share reply: $e');
SmartDialog.dismiss();
}
}
@override
Widget build(BuildContext context) {
return GestureDetector(
behavior: HitTestBehavior.opaque,
onTap: Get.back,
child: Stack(
clipBehavior: Clip.none,
alignment: Alignment.center,
children: [
SingleChildScrollView(
padding: const EdgeInsets.only(top: 12, bottom: 80),
child: SafeArea(
child: GestureDetector(
onTap: () {},
child: Container(
width: min(Get.width, Get.height),
margin: const EdgeInsets.symmetric(horizontal: 12),
child: RepaintBoundary(
key: boundaryKey,
child: Container(
clipBehavior: Clip.hardEdge,
decoration: BoxDecoration(
color: Theme.of(context).colorScheme.surface,
borderRadius: BorderRadius.circular(12),
),
child: AnimatedSize(
curve: Curves.easeInOut,
alignment: Alignment.topCenter,
duration: const Duration(milliseconds: 255),
child: Column(
mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
if (_item is ReplyInfo)
IgnorePointer(
child: ReplyItemGrpc(
replyItem: _item,
replyLevel: '',
needDivider: false,
upMid: widget.upMid,
),
)
else if (_item is DynamicItemModel)
IgnorePointer(
child: DynamicPanel(
item: _item,
source: 'detail',
isSave: true,
),
),
if (cover?.isNotEmpty == true &&
title?.isNotEmpty == true)
Container(
height: 81,
clipBehavior: Clip.hardEdge,
margin:
const EdgeInsets.symmetric(horizontal: 12),
padding: const EdgeInsets.all(8),
decoration: BoxDecoration(
color: Theme.of(context)
.colorScheme
.onInverseSurface,
borderRadius: BorderRadius.circular(8),
),
child: Row(
children: [
NetworkImgLayer(
radius: 6,
src: cover!,
height: MediaQuery.textScalerOf(context)
.scale(65),
width: MediaQuery.textScalerOf(context)
.scale(65) *
16 /
9,
quality: 100,
),
const SizedBox(width: 10),
Expanded(
child: Column(
crossAxisAlignment:
CrossAxisAlignment.start,
children: [
Text(
'$title\n',
maxLines: 2,
overflow: TextOverflow.ellipsis,
),
if (pubdate != null) ...[
const Spacer(),
Text(
DateTime.fromMillisecondsSinceEpoch(
pubdate! * 1000)
.toString()
.substring(0, 19),
style: TextStyle(
color: Theme.of(context)
.colorScheme
.outline,
),
),
],
],
),
),
],
),
),
showBottom
? Stack(
clipBehavior: Clip.none,
children: [
if (uri.isNotEmpty)
Align(
alignment: Alignment.centerRight,
child: Row(
children: [
Expanded(
child: Column(
mainAxisSize:
MainAxisSize.min,
crossAxisAlignment:
CrossAxisAlignment.end,
children: [
if (uname?.isNotEmpty ==
true) ...[
Text(
'@$uname',
maxLines: 1,
overflow: TextOverflow
.ellipsis,
style: TextStyle(
color:
Theme.of(context)
.colorScheme
.primary,
),
),
const SizedBox(height: 4),
],
Text(
'识别二维码,$viewType$itemType',
textAlign: TextAlign.end,
style: TextStyle(
color: Theme.of(context)
.colorScheme
.onSurfaceVariant,
),
),
const SizedBox(height: 4),
Text(
DateTime.now()
.toString()
.split('.')
.first,
textAlign: TextAlign.end,
style: TextStyle(
fontSize: 13,
color: Theme.of(context)
.colorScheme
.outline,
),
),
],
),
),
Container(
width: 100,
height: 100,
padding:
const EdgeInsets.all(12),
child: Container(
color: Get.isDarkMode
? Colors.white
: Theme.of(context)
.colorScheme
.surface,
padding:
const EdgeInsets.all(3),
child: PrettyQrView.data(
data: uri,
decoration:
const PrettyQrDecoration(
shape:
PrettyQrRoundedSymbol(
borderRadius:
BorderRadius.zero,
),
),
),
),
),
],
),
),
Align(
alignment: Alignment.centerLeft,
child: Image.asset(
'assets/images/logo/logo_2.png',
width: 100,
color: Theme.of(context)
.colorScheme
.onSurfaceVariant,
),
),
],
)
: const SizedBox(height: 12),
],
),
),
),
),
),
),
),
),
Positioned(
left: 0,
right: 0,
bottom: 0,
child: Container(
decoration: const BoxDecoration(
gradient: LinearGradient(
begin: Alignment.topCenter,
end: Alignment.bottomCenter,
colors: [
Colors.transparent,
Colors.black54,
],
),
),
padding: const EdgeInsets.only(bottom: 25, top: 10),
child: SafeArea(
top: false,
child: Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
iconButton(
size: 42,
tooltip: '关闭',
context: context,
icon: Icons.clear,
onPressed: Get.back,
bgColor: Theme.of(context).colorScheme.onInverseSurface,
iconColor: Theme.of(context).colorScheme.onSurfaceVariant,
),
const SizedBox(width: 40),
iconButton(
size: 42,
tooltip: showBottom ? '隐藏' : '显示',
context: context,
icon: showBottom
? Icons.visibility_off
: Icons.visibility,
onPressed: () => setState(() {
showBottom = !showBottom;
})),
const SizedBox(width: 40),
iconButton(
size: 42,
tooltip: '分享',
context: context,
icon: Icons.share,
onPressed: () => _onSaveOrSharePic(true),
),
const SizedBox(width: 40),
iconButton(
size: 42,
tooltip: '保存',
context: context,
icon: Icons.save_alt,
onPressed: _onSaveOrSharePic,
),
],
),
),
),
),
],
),
);
}
}

View File

@@ -0,0 +1,97 @@
import 'package:PiliPlus/utils/storage.dart';
import 'package:flutter/material.dart';
Widget videoTabBarView({
required List<Widget> children,
TabController? controller,
}) =>
TabBarView(
physics: const CustomTabBarViewClampingScrollPhysics(),
controller: controller,
children: children,
);
Widget tabBarView({
required List<Widget> children,
TabController? controller,
}) =>
TabBarView(
physics: const CustomTabBarViewScrollPhysics(),
controller: controller,
children: children,
);
class CustomTabBarViewScrollPhysics extends ScrollPhysics {
const CustomTabBarViewScrollPhysics({super.parent});
@override
CustomTabBarViewScrollPhysics applyTo(ScrollPhysics? ancestor) {
return CustomTabBarViewScrollPhysics(parent: buildParent(ancestor));
}
@override
SpringDescription get spring => CustomSpringDescription();
}
class CustomTabBarViewClampingScrollPhysics extends ClampingScrollPhysics {
const CustomTabBarViewClampingScrollPhysics({super.parent});
@override
CustomTabBarViewClampingScrollPhysics applyTo(ScrollPhysics? ancestor) {
return CustomTabBarViewClampingScrollPhysics(parent: buildParent(ancestor));
}
@override
SpringDescription get spring => CustomSpringDescription();
}
class PositionRetainedScrollPhysics extends AlwaysScrollableScrollPhysics {
const PositionRetainedScrollPhysics({super.parent, this.shouldRetain = true});
final bool shouldRetain;
@override
PositionRetainedScrollPhysics applyTo(ScrollPhysics? ancestor) {
return PositionRetainedScrollPhysics(parent: buildParent(ancestor));
}
@override
double adjustPositionForNewDimensions({
required ScrollMetrics oldPosition,
required ScrollMetrics newPosition,
required bool isScrolling,
required double velocity,
}) {
final position = super.adjustPositionForNewDimensions(
oldPosition: oldPosition,
newPosition: newPosition,
isScrolling: isScrolling,
velocity: velocity,
);
late final diff = newPosition.maxScrollExtent - oldPosition.maxScrollExtent;
if (shouldRetain && oldPosition.pixels == 0 && diff > 0) {
return position + diff;
} else {
return position;
}
}
}
class CustomSpringDescription implements SpringDescription {
@override
final mass = GStorage.springDescription[0];
@override
final stiffness = GStorage.springDescription[1];
@override
final damping = GStorage.springDescription[2];
CustomSpringDescription._();
static final _instance = CustomSpringDescription._();
factory CustomSpringDescription() => _instance;
}

View File

@@ -22,7 +22,7 @@ class Segment {
class SegmentProgressBar extends CustomPainter {
final List<Segment> segmentColors;
late double _defHeight;
double? _defHeight;
SegmentProgressBar({
required this.segmentColors,
@@ -42,6 +42,18 @@ class SegmentProgressBar extends CustomPainter {
if (segmentColors[i].title != null) {
double fontSize = 10;
_defHeight ??= (TextPainter(
text: TextSpan(
text: segmentColors[i].title,
style: TextStyle(
fontSize: fontSize,
),
),
textDirection: TextDirection.ltr,
)..layout())
.height +
2;
TextPainter getTextPainter() => TextPainter(
text: TextSpan(
text: segmentColors[i].title,
@@ -51,14 +63,12 @@ class SegmentProgressBar extends CustomPainter {
height: 1,
),
),
strutStyle: StrutStyle(height: 1, leading: 0),
strutStyle:
StrutStyle(leading: 0, height: 1, fontSize: fontSize),
textDirection: TextDirection.ltr,
)..layout();
TextPainter textPainter = getTextPainter();
if (i == 0) {
_defHeight = textPainter.height;
}
late double prevStart;
if (i != 0) {
@@ -75,7 +85,7 @@ class SegmentProgressBar extends CustomPainter {
canvas.drawRect(
Rect.fromLTRB(
0,
-_defHeight - 2,
-_defHeight!,
size.width,
0,
),
@@ -86,9 +96,9 @@ class SegmentProgressBar extends CustomPainter {
canvas.drawRect(
Rect.fromLTWH(
segmentStart,
-_defHeight - 2,
-_defHeight!,
segmentEnd == segmentStart ? 2 : segmentEnd - segmentStart,
size.height + _defHeight + 2,
size.height + _defHeight!,
),
paint,
);
@@ -98,7 +108,7 @@ class SegmentProgressBar extends CustomPainter {
: (segmentStart - prevStart - textPainter.width) / 2 +
prevStart +
1;
double textY = (-_defHeight - textPainter.height) / 2 - 1;
double textY = (-_defHeight! - textPainter.height) / 2;
textPainter.paint(canvas, Offset(textX, textY));
} else {
canvas.drawRect(

View File

@@ -39,7 +39,13 @@ class _SelfSizedHorizontalListState extends State<SelfSizedHorizontalList> {
WidgetsBinding.instance.addPostFrameCallback((v) => setState(() {}));
}
if (widget.itemCount == 0) return const SizedBox();
if (isInit) return Container(key: infoKey, child: widget.childBuilder(0));
if (isInit) {
return Container(
key: infoKey,
padding: widget.padding,
child: widget.childBuilder(0),
);
}
return SizedBox(
height: height,

View File

@@ -1,35 +0,0 @@
import 'package:flutter/material.dart';
import 'package:PiliPlus/utils/utils.dart';
Widget statDanMu({
required BuildContext context,
String? theme,
dynamic danmu,
String? size,
}) {
Map<String, Color> colorObject = {
'white': Colors.white,
'gray': Theme.of(context).colorScheme.outline.withOpacity(0.8),
'black': Theme.of(context).colorScheme.onSurface.withOpacity(0.7),
};
Color color = colorObject[theme]!;
return Row(
children: [
Icon(
Icons.subtitles_outlined,
size: 14,
color: color,
),
const SizedBox(width: 2),
Text(
Utils.numFormat(danmu!),
style: TextStyle(
fontSize: size == 'medium' ? 12 : 11,
color: color,
),
overflow: TextOverflow.clip,
semanticsLabel: '${Utils.numFormat(danmu!)}条弹幕',
)
],
);
}

View File

@@ -0,0 +1,93 @@
import 'package:PiliPlus/utils/utils.dart';
import 'package:flutter/material.dart';
abstract class _StatItemBase extends StatelessWidget {
final BuildContext context;
final Object value;
final String? theme;
final String? size;
final Color? textColor;
final double iconSize;
const _StatItemBase({
required this.context,
required this.value,
this.theme,
this.size,
this.textColor,
this.iconSize = 13,
});
IconData get iconData;
String get semanticsLabel;
Color get color {
return textColor ??
switch (theme) {
'gray' => Theme.of(context).colorScheme.outline.withOpacity(0.8),
'black' => Theme.of(context).colorScheme.onSurface.withOpacity(0.7),
_ => Colors.white,
};
}
@override
Widget build(BuildContext context) {
return Row(
children: [
Icon(
iconData,
size: iconSize,
color: color,
),
const SizedBox(width: 2),
Text(
Utils.numFormat(value),
style: TextStyle(fontSize: size == 'medium' ? 12 : 11, color: color),
overflow: TextOverflow.clip,
semanticsLabel: semanticsLabel,
)
],
);
}
}
class StatView extends _StatItemBase {
final String? goto;
const StatView({
required super.context,
required super.value,
this.goto,
super.theme,
super.size,
super.textColor,
}) : super(iconSize: 13);
@override
IconData get iconData => switch (goto) {
'picture' => Icons.remove_red_eye_outlined,
'like' => Icons.thumb_up_outlined,
'reply' => Icons.comment_outlined,
_ => Icons.play_circle_outlined,
};
@override
String get semanticsLabel =>
'${Utils.numFormat(value)}${goto == "picture" ? "浏览" : "播放"}';
}
class StatDanMu extends _StatItemBase {
const StatDanMu({
required super.context,
required super.value,
super.theme,
super.size,
super.textColor,
}) : super(iconSize: 14);
@override
IconData get iconData => Icons.subtitles_outlined;
@override
String get semanticsLabel => '${Utils.numFormat(value)}条弹幕';
}

View File

@@ -1,39 +0,0 @@
import 'package:flutter/material.dart';
import 'package:PiliPlus/utils/utils.dart';
Widget statView({
required BuildContext context,
String? theme,
dynamic view,
String? size,
String? goto,
}) {
Map<String, Color> colorObject = {
'white': Colors.white,
'gray': Theme.of(context).colorScheme.outline.withOpacity(0.8),
'black': Theme.of(context).colorScheme.onSurface.withOpacity(0.7),
};
Color color = colorObject[theme]!;
return Row(
children: [
Icon(
goto == 'picture'
? Icons.remove_red_eye_outlined
: Icons.play_circle_outlined,
size: 13,
color: color,
),
const SizedBox(width: 2),
Text(
Utils.numFormat(view!),
style: TextStyle(
fontSize: size == 'medium' ? 12 : 11,
color: color,
),
overflow: TextOverflow.clip,
semanticsLabel:
'${Utils.numFormat(view!)}${goto == "picture" ? "浏览" : "播放"}',
),
],
);
}

View File

@@ -1,15 +1,16 @@
import 'package:PiliPlus/common/widgets/image_save.dart';
import 'package:PiliPlus/common/widgets/video_progress_indicator.dart';
import 'package:PiliPlus/models/model_hot_video_item.dart';
import 'package:PiliPlus/models/model_video.dart';
import 'package:PiliPlus/models/search/result.dart';
import 'package:flutter/material.dart';
import 'package:flutter_smart_dialog/flutter_smart_dialog.dart';
import 'package:get/get.dart';
import '../../http/search.dart';
import '../../utils/utils.dart';
import '../constants.dart';
import 'badge.dart';
import 'network_img_layer.dart';
import 'stat/danmu.dart';
import 'stat/view.dart';
import 'stat/stat.dart';
import 'video_popup_menu.dart';
// 视频卡片 - 水平布局
@@ -24,8 +25,9 @@ class VideoCardH extends StatelessWidget {
this.showPubdate = false,
this.onTap,
this.onLongPress,
this.onViewLater,
});
final dynamic videoItem;
final BaseVideoItemModel videoItem;
final String source;
final bool showOwner;
final bool showView;
@@ -33,250 +35,286 @@ class VideoCardH extends StatelessWidget {
final bool showPubdate;
final VoidCallback? onTap;
final VoidCallback? onLongPress;
final ValueChanged<int>? onViewLater;
@override
Widget build(BuildContext context) {
final int aid = videoItem.aid;
final String bvid = videoItem.bvid;
final int aid = videoItem.aid!;
final String bvid = videoItem.bvid!;
String type = 'video';
try {
type = videoItem.type;
} catch (_) {}
return Stack(children: [
Semantics(
label: Utils.videoItemSemantics(videoItem),
excludeSemantics: true,
// customSemanticsActions: <CustomSemanticsAction, void Function()>{
// for (var item in actions)
// CustomSemanticsAction(
// label: item.title.isEmpty ? 'label' : item.title): item.onTap!,
// },
child: InkWell(
onLongPress: () {
if (onLongPress != null) {
onLongPress!();
} else {
imageSaveDialog(
context: context,
title: videoItem.title is String
? videoItem.title
: videoItem.title is List
? (videoItem.title as List)
.map((item) => item['text'])
.join()
: '',
cover: videoItem.pic,
);
}
},
onTap: () async {
if (onTap != null) {
onTap?.call();
return;
}
if (type == 'ketang') {
SmartDialog.showToast('课堂视频暂不支持播放');
return;
}
if (videoItem is HotVideoItemModel &&
videoItem.redirectUrl?.isNotEmpty == true) {
if (Utils.viewPgcFromUri(videoItem.redirectUrl!)) {
return;
}
}
try {
final int cid =
videoItem.cid ?? await SearchHttp.ab2c(aid: aid, bvid: bvid);
Get.toNamed(
'/video?bvid=$bvid&cid=$cid',
arguments: {
'videoItem': videoItem,
'heroTag': Utils.makeHeroTag(aid)
},
);
} catch (err) {
SmartDialog.showToast(err.toString());
}
},
child: Padding(
padding: const EdgeInsets.symmetric(
horizontal: StyleString.safeSpace,
vertical: 5,
),
child: Row(
mainAxisAlignment: MainAxisAlignment.start,
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
AspectRatio(
aspectRatio: StyleString.aspectRatio,
child: LayoutBuilder(
builder:
(BuildContext context, BoxConstraints boxConstraints) {
final double maxWidth = boxConstraints.maxWidth;
final double maxHeight = boxConstraints.maxHeight;
return Stack(
children: [
NetworkImgLayer(
src: videoItem.pic as String,
width: maxWidth,
height: maxHeight,
),
if (videoItem is HotVideoItemModel &&
videoItem.pgcLabel?.isNotEmpty == true)
PBadge(
text: videoItem.pgcLabel,
top: 6.0,
right: 6.0,
),
if (videoItem.duration != 0)
PBadge(
text: Utils.timeFormat(videoItem.duration!),
right: 6.0,
bottom: 6.0,
type: 'gray',
),
if (type != 'video')
PBadge(
text: type,
left: 6.0,
bottom: 6.0,
type: 'primary',
),
// if (videoItem.rcmdReason != null &&
// videoItem.rcmdReason.content != '')
// pBadge(videoItem.rcmdReason.content, context,
// 6.0, 6.0, null, null),
],
);
},
),
// try {
// type = videoItem.type;
// } catch (_) {}
if (videoItem is SearchVideoItemModel) {
var typeOrNull = (videoItem as SearchVideoItemModel).type;
if (typeOrNull?.isNotEmpty == true) {
type = typeOrNull!;
}
}
return Material(
color: Colors.transparent,
child: Stack(
clipBehavior: Clip.none,
children: [
Semantics(
label: Utils.videoItemSemantics(videoItem),
excludeSemantics: true,
// customSemanticsActions: <CustomSemanticsAction, void Function()>{
// for (var item in actions)
// CustomSemanticsAction(
// label: item.title.isEmpty ? 'label' : item.title): item.onTap!,
// },
child: InkWell(
onLongPress: () {
if (onLongPress != null) {
onLongPress!();
} else {
imageSaveDialog(
context: context,
title: videoItem.title,
cover: videoItem.pic,
);
}
},
onTap: () async {
if (onTap != null) {
onTap!();
return;
}
if (type == 'ketang') {
SmartDialog.showToast('课堂视频暂不支持播放');
return;
}
if ((videoItem is HotVideoItemModel) &&
(videoItem as HotVideoItemModel).redirectUrl?.isNotEmpty ==
true) {
if (Utils.viewPgcFromUri(
(videoItem as HotVideoItemModel).redirectUrl!)) {
return;
}
}
try {
final int cid = videoItem.cid ??
await SearchHttp.ab2c(aid: aid, bvid: bvid);
if (source == 'later') {
onViewLater!(cid);
} else {
Utils.toViewPage(
'bvid=$bvid&cid=$cid',
arguments: {
'videoItem': videoItem,
'heroTag': Utils.makeHeroTag(aid)
},
);
}
} catch (err) {
SmartDialog.showToast(err.toString());
}
},
child: Padding(
padding: const EdgeInsets.symmetric(
horizontal: StyleString.safeSpace,
vertical: 5,
),
videoContent(context)
],
child: Row(
mainAxisAlignment: MainAxisAlignment.start,
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
AspectRatio(
aspectRatio: StyleString.aspectRatio,
child: LayoutBuilder(
builder: (BuildContext context,
BoxConstraints boxConstraints) {
final double maxWidth = boxConstraints.maxWidth;
final double maxHeight = boxConstraints.maxHeight;
num? progress;
if (videoItem is HotVideoItemModel) {
progress =
(videoItem as HotVideoItemModel).progress;
}
return Stack(
clipBehavior: Clip.none,
children: [
NetworkImgLayer(
src: videoItem.pic,
width: maxWidth,
height: maxHeight,
),
if (videoItem is HotVideoItemModel)
PBadge(
text:
(videoItem as HotVideoItemModel).pgcLabel,
top: 6.0,
right: 6.0,
),
if (progress != null && progress != 0) ...[
PBadge(
text: progress == -1
? '已看完'
: '${Utils.timeFormat(progress)}/${Utils.timeFormat(videoItem.duration)}',
right: 6,
bottom: 8,
type: 'gray',
),
Positioned(
left: 0,
bottom: 0,
right: 0,
child: videoProgressIndicator(
progress == -1
? 1
: progress / videoItem.duration,
),
)
] else if (videoItem.duration > 0)
PBadge(
text: Utils.timeFormat(videoItem.duration),
right: 6.0,
bottom: 6.0,
type: 'gray',
),
if (type != 'video')
PBadge(
text: type,
left: 6.0,
bottom: 6.0,
type: 'primary',
),
// if (videoItem.rcmdReason != null &&
// videoItem.rcmdReason.content != '')
// pBadge(videoItem.rcmdReason.content, context,
// 6.0, 6.0, null, null),
],
);
},
),
),
const SizedBox(width: 10),
videoContent(context),
],
),
),
),
),
),
if (source == 'normal')
Positioned(
bottom: 0,
right: 12,
child: VideoPopupMenu(
size: 29,
iconSize: 17,
videoItem: videoItem,
),
),
],
),
if (source == 'normal')
Positioned(
bottom: 0,
right: 12,
child: VideoPopupMenu(
size: 29,
iconSize: 17,
videoItem: videoItem,
),
),
]);
);
}
Widget videoContent(context) {
Widget videoContent(BuildContext context) {
String pubdate = showPubdate
? Utils.dateFormat(videoItem.pubdate!, formatType: 'day')
: '';
if (pubdate != '') pubdate += ' ';
return Expanded(
child: Padding(
padding: const EdgeInsets.fromLTRB(10, 0, 6, 0),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
if (videoItem.title is String)
Expanded(
child: Text(
videoItem.title as String,
textAlign: TextAlign.start,
style: TextStyle(
fontSize: Theme.of(context).textTheme.bodyMedium!.fontSize,
height: 1.42,
letterSpacing: 0.3,
),
maxLines: 2,
overflow: TextOverflow.ellipsis,
),
)
else
Expanded(
child: RichText(
overflow: TextOverflow.ellipsis,
maxLines: 2,
textScaler: MediaQuery.textScalerOf(context),
text: TextSpan(
children: [
for (final i in videoItem.title) ...[
TextSpan(
text: i['text'] as String,
style: TextStyle(
fontSize: Theme.of(context)
.textTheme
.bodyMedium!
.fontSize,
letterSpacing: 0.3,
color: i['type'] == 'em'
? Theme.of(context).colorScheme.primary
: Theme.of(context).colorScheme.onSurface,
),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
if ((videoItem is SearchVideoItemModel) &&
(videoItem as SearchVideoItemModel).titleList?.isNotEmpty == true)
Expanded(
child: Text.rich(
overflow: TextOverflow.ellipsis,
maxLines: 2,
TextSpan(
children: [
for (var i
in (videoItem as SearchVideoItemModel).titleList!)
TextSpan(
text: i['text'],
style: TextStyle(
fontSize:
Theme.of(context).textTheme.bodyMedium!.fontSize,
height: 1.42,
letterSpacing: 0.3,
color: i['type'] == 'em'
? Theme.of(context).colorScheme.primary
: Theme.of(context).colorScheme.onSurface,
),
]
],
),
),
],
),
),
// const Spacer(),
// if (videoItem.rcmdReason != null &&
// videoItem.rcmdReason.content != '')
// Container(
// padding: const EdgeInsets.symmetric(vertical: 2, horizontal: 5),
// decoration: BoxDecoration(
// borderRadius: BorderRadius.circular(4),
// border: Border.all(
// color: Theme.of(context).colorScheme.surfaceTint),
// ),
// child: Text(
// videoItem.rcmdReason.content,
// style: TextStyle(
// fontSize: 9,
// color: Theme.of(context).colorScheme.surfaceTint),
// ),
// ),
// const SizedBox(height: 4),
if (showOwner || showPubdate)
Expanded(
flex: 0,
child: Text(
"$pubdate ${showOwner ? videoItem.owner.name : ''}",
maxLines: 1,
style: TextStyle(
fontSize: Theme.of(context).textTheme.labelSmall!.fontSize,
height: 1,
color: Theme.of(context).colorScheme.outline,
overflow: TextOverflow.clip,
),
)
else
Expanded(
child: Text(
videoItem.title,
textAlign: TextAlign.start,
style: TextStyle(
fontSize: Theme.of(context).textTheme.bodyMedium!.fontSize,
height: 1.42,
letterSpacing: 0.3,
),
maxLines: 2,
overflow: TextOverflow.ellipsis,
),
const SizedBox(height: 3),
Row(
children: [
if (showView) ...[
statView(
context: context,
theme: 'gray',
view: videoItem.stat.view as int,
),
const SizedBox(width: 8),
],
if (showDanmaku)
statDanMu(
context: context,
theme: 'gray',
danmu: videoItem.stat.danmu as int,
),
const Spacer(),
if (source == 'normal') const SizedBox(width: 24),
],
),
],
),
// const Spacer(),
// if (videoItem.rcmdReason != null &&
// videoItem.rcmdReason.content != '')
// Container(
// padding: const EdgeInsets.symmetric(vertical: 2, horizontal: 5),
// decoration: BoxDecoration(
// borderRadius: BorderRadius.circular(4),
// border: Border.all(
// color: Theme.of(context).colorScheme.surfaceTint),
// ),
// child: Text(
// videoItem.rcmdReason.content,
// style: TextStyle(
// fontSize: 9,
// color: Theme.of(context).colorScheme.surfaceTint),
// ),
// ),
// const SizedBox(height: 4),
if (showOwner || showPubdate)
Expanded(
flex: 0,
child: Text(
"$pubdate ${showOwner ? videoItem.owner.name : ''}",
maxLines: 1,
style: TextStyle(
fontSize: Theme.of(context).textTheme.labelSmall!.fontSize,
height: 1,
color: Theme.of(context).colorScheme.outline,
overflow: TextOverflow.clip,
),
),
),
const SizedBox(height: 3),
Row(
children: [
if (showView) ...[
StatView(
context: context,
theme: 'gray',
value: videoItem.stat.viewStr,
),
const SizedBox(width: 8),
],
if (showDanmaku)
StatDanMu(
context: context,
theme: 'gray',
value: videoItem.stat.danmuStr,
),
const Spacer(),
if (source == 'normal') const SizedBox(width: 24),
],
),
],
),
);
}

View File

@@ -58,7 +58,7 @@ class VideoCardHGrpc extends StatelessWidget {
return;
}
try {
PiliScheme.routePush(Uri.parse(videoItem.smallCoverV5.base.uri));
PiliScheme.routePushFromUrl(videoItem.smallCoverV5.base.uri);
} catch (err) {
SmartDialog.showToast(err.toString());
}
@@ -111,7 +111,8 @@ class VideoCardHGrpc extends StatelessWidget {
},
),
),
videoContent(context)
const SizedBox(width: 10),
videoContent(context),
],
);
},
@@ -133,58 +134,43 @@ class VideoCardHGrpc extends StatelessWidget {
Widget videoContent(context) {
return Expanded(
child: Padding(
padding: const EdgeInsets.fromLTRB(10, 0, 6, 0),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
...[
Expanded(
child: Text(
videoItem.smallCoverV5.base.title,
textAlign: TextAlign.start,
style: TextStyle(
fontSize: Theme.of(context).textTheme.bodyMedium!.fontSize,
height: 1.42,
letterSpacing: 0.3,
),
maxLines: 2,
overflow: TextOverflow.ellipsis,
),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Expanded(
child: Text(
videoItem.smallCoverV5.base.title,
textAlign: TextAlign.start,
style: TextStyle(
fontSize: Theme.of(context).textTheme.bodyMedium!.fontSize,
height: 1.42,
letterSpacing: 0.3,
),
],
// const Spacer(),
// if (videoItem.rcmdReason != null &&
// videoItem.rcmdReason.content != '')
// Container(
// padding: const EdgeInsets.symmetric(vertical: 2, horizontal: 5),
// decoration: BoxDecoration(
// borderRadius: BorderRadius.circular(4),
// border: Border.all(
// color: Theme.of(context).colorScheme.surfaceTint),
// ),
// child: Text(
// videoItem.rcmdReason.content,
// style: TextStyle(
// fontSize: 9,
// color: Theme.of(context).colorScheme.surfaceTint),
// ),
// ),
// const SizedBox(height: 4),
if (showOwner || showPubdate)
Text(
videoItem.smallCoverV5.rightDesc1,
maxLines: 1,
style: TextStyle(
fontSize: Theme.of(context).textTheme.labelMedium!.fontSize,
height: 1,
color: Theme.of(context).colorScheme.outline,
overflow: TextOverflow.clip,
),
),
const SizedBox(height: 3),
maxLines: 2,
overflow: TextOverflow.ellipsis,
),
),
// const Spacer(),
// if (videoItem.rcmdReason != null &&
// videoItem.rcmdReason.content != '')
// Container(
// padding: const EdgeInsets.symmetric(vertical: 2, horizontal: 5),
// decoration: BoxDecoration(
// borderRadius: BorderRadius.circular(4),
// border: Border.all(
// color: Theme.of(context).colorScheme.surfaceTint),
// ),
// child: Text(
// videoItem.rcmdReason.content,
// style: TextStyle(
// fontSize: 9,
// color: Theme.of(context).colorScheme.surfaceTint),
// ),
// ),
// const SizedBox(height: 4),
if (showOwner || showPubdate)
Text(
videoItem.smallCoverV5.rightDesc2,
videoItem.smallCoverV5.rightDesc1,
maxLines: 1,
style: TextStyle(
fontSize: Theme.of(context).textTheme.labelMedium!.fontSize,
@@ -193,26 +179,36 @@ class VideoCardHGrpc extends StatelessWidget {
overflow: TextOverflow.clip,
),
),
// Row(
// children: [
// if (showView) ...[
// StatView(
// theme: 'gray',
// view: videoItem.stat.view as int,
// ),
// const SizedBox(width: 8),
// ],
// if (showDanmaku)
// StatDanMu(
// theme: 'gray',
// danmu: videoItem.stat.danmu as int,
// ),
// const Spacer(),
// if (source == 'normal') const SizedBox(width: 24),
// ],
// ),
],
),
const SizedBox(height: 3),
Text(
videoItem.smallCoverV5.rightDesc2,
maxLines: 1,
style: TextStyle(
fontSize: Theme.of(context).textTheme.labelMedium!.fontSize,
height: 1,
color: Theme.of(context).colorScheme.outline,
overflow: TextOverflow.clip,
),
),
// Row(
// children: [
// if (showView) ...[
// StatView(
// theme: 'gray',
// view: videoItem.stat.view as int,
// ),
// const SizedBox(width: 8),
// ],
// if (showDanmaku)
// StatDanMu(
// theme: 'gray',
// danmu: videoItem.stat.danmu as int,
// ),
// const Spacer(),
// if (source == 'normal') const SizedBox(width: 24),
// ],
// ),
],
),
);
}

View File

@@ -1,11 +1,10 @@
import 'package:PiliPlus/common/widgets/image_save.dart';
import 'package:PiliPlus/common/widgets/stat/danmu.dart';
import 'package:PiliPlus/common/widgets/stat/view.dart';
import 'package:PiliPlus/common/widgets/stat/stat.dart';
import 'package:PiliPlus/common/widgets/video_popup_menu.dart';
import 'package:PiliPlus/common/widgets/video_progress_indicator.dart';
import 'package:PiliPlus/models/space_archive/item.dart';
import 'package:flutter/material.dart';
import 'package:flutter_smart_dialog/flutter_smart_dialog.dart';
import 'package:get/get.dart';
import '../../utils/utils.dart';
import '../constants.dart';
import 'badge.dart';
@@ -18,10 +17,12 @@ class VideoCardHMemberVideo extends StatelessWidget {
required this.videoItem,
this.onTap,
this.bvid,
this.fromViewAid,
});
final Item videoItem;
final VoidCallback? onTap;
final dynamic bvid;
final String? fromViewAid;
@override
Widget build(BuildContext context) {
@@ -43,12 +44,12 @@ class VideoCardHMemberVideo extends StatelessWidget {
return;
}
}
if (videoItem.bvid == null || videoItem.firstCid == null) {
if (videoItem.bvid == null || videoItem.cid == null) {
return;
}
try {
Get.toNamed(
'/video?bvid=${videoItem.bvid}&cid=${videoItem.firstCid}',
Utils.toViewPage(
'bvid=${videoItem.bvid}&cid=${videoItem.cid}',
arguments: {
'heroTag': Utils.makeHeroTag(videoItem.bvid),
},
@@ -83,6 +84,25 @@ class VideoCardHMemberVideo extends StatelessWidget {
width: maxWidth,
height: maxHeight,
),
if (fromViewAid == videoItem.param)
Positioned.fill(
child: DecoratedBox(
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(10),
color: Colors.black54,
),
child: Center(
child: const Text(
'上次观看',
style: TextStyle(
color: Colors.white,
fontSize: 15,
letterSpacing: 1.5,
),
),
),
),
),
if (videoItem.badges?.isNotEmpty == true)
PBadge(
text: videoItem.badges!
@@ -90,8 +110,48 @@ class VideoCardHMemberVideo extends StatelessWidget {
.join('|'),
right: 6.0,
top: 6.0,
type: videoItem.badges!.first.text == '充电专属'
? 'error'
: 'primary',
),
if (videoItem.duration != null)
if (videoItem.history != null) ...[
Builder(builder: (context) {
try {
return Positioned(
left: 0,
right: 0,
bottom: 0,
child: videoProgressIndicator(
videoItem.history!['progress'] /
videoItem.history!['duration'],
),
);
} catch (_) {
return const SizedBox.shrink();
}
}),
Builder(builder: (context) {
try {
return PBadge(
text: videoItem.history!['progress'] ==
videoItem.history!['duration']
? '已看完'
: '${Utils.timeFormat(videoItem.history!['progress'])}/${Utils.timeFormat(videoItem.history!['duration'])}',
right: 6.0,
bottom: 6.0,
type: 'gray',
);
} catch (_) {
return PBadge(
text:
Utils.timeFormat(videoItem.duration),
right: 6.0,
bottom: 6.0,
type: 'gray',
);
}
}),
] else if (videoItem.duration > 0)
PBadge(
text: Utils.timeFormat(videoItem.duration),
right: 6.0,
@@ -103,7 +163,8 @@ class VideoCardHMemberVideo extends StatelessWidget {
},
),
),
videoContent(context)
const SizedBox(width: 10),
videoContent(context),
],
);
},
@@ -125,66 +186,61 @@ class VideoCardHMemberVideo extends StatelessWidget {
Widget videoContent(context) {
return Expanded(
child: Padding(
padding: const EdgeInsets.fromLTRB(10, 0, 6, 0),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
...[
Expanded(
child: Text(
// videoItem.season?['title'] ?? videoItem.title ?? '',
videoItem.title ?? '',
textAlign: TextAlign.start,
style: TextStyle(
fontWeight: videoItem.bvid != null && videoItem.bvid == bvid
? FontWeight.bold
: null,
fontSize: Theme.of(context).textTheme.bodyMedium!.fontSize,
height: 1.42,
letterSpacing: 0.3,
color: videoItem.bvid != null && videoItem.bvid == bvid
? Theme.of(context).colorScheme.primary
: null,
),
maxLines: 2,
overflow: TextOverflow.ellipsis,
),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Expanded(
child: Text(
// videoItem.season?['title'] ?? videoItem.title ?? '',
videoItem.title,
textAlign: TextAlign.start,
style: TextStyle(
fontWeight: videoItem.bvid != null && videoItem.bvid == bvid
? FontWeight.bold
: null,
fontSize: Theme.of(context).textTheme.bodyMedium!.fontSize,
height: 1.42,
letterSpacing: 0.3,
color: videoItem.bvid != null && videoItem.bvid == bvid
? Theme.of(context).colorScheme.primary
: null,
),
maxLines: 2,
overflow: TextOverflow.ellipsis,
),
),
Text(
videoItem.season != null
? Utils.dateFormat(videoItem.season?['mtime'])
: videoItem.publishTimeText ?? '',
maxLines: 1,
style: TextStyle(
fontSize: Theme.of(context).textTheme.labelMedium!.fontSize,
height: 1,
color: Theme.of(context).colorScheme.outline,
overflow: TextOverflow.clip,
),
),
const SizedBox(height: 3),
Row(
children: [
StatView(
context: context,
theme: 'gray',
// view: videoItem.season?['view_content'] ??
// videoItem.viewContent,
value: videoItem.stat.viewStr,
),
const SizedBox(width: 8),
StatDanMu(
context: context,
theme: 'gray',
// danmu: videoItem.season?['danmaku'] ?? videoItem.danmaku,
value: videoItem.stat.danmuStr,
),
],
Text(
videoItem.season != null
? Utils.dateFormat(videoItem.season?['mtime'])
: videoItem.publishTimeText ?? '',
maxLines: 1,
style: TextStyle(
fontSize: Theme.of(context).textTheme.labelMedium!.fontSize,
height: 1,
color: Theme.of(context).colorScheme.outline,
overflow: TextOverflow.clip,
),
),
const SizedBox(height: 3),
Row(
children: [
statView(
context: context,
theme: 'gray',
// view: videoItem.season?['view_content'] ??
// videoItem.viewContent,
view: videoItem.viewContent,
),
const SizedBox(width: 8),
statDanMu(
context: context,
theme: 'gray',
// danmu: videoItem.season?['danmaku'] ?? videoItem.danmaku,
danmu: videoItem.danmaku,
),
],
),
],
),
),
],
),
);
}

View File

@@ -5,9 +5,7 @@ import 'package:flutter_smart_dialog/flutter_smart_dialog.dart';
import 'package:get/get.dart';
import '../../models/home/rcmd/result.dart';
import '../../models/model_rec_video_item.dart';
import 'stat/danmu.dart';
import 'stat/view.dart';
import '../../http/dynamics.dart';
import 'stat/stat.dart';
import '../../utils/id_utils.dart';
import '../../utils/utils.dart';
import '../constants.dart';
@@ -17,7 +15,7 @@ import 'video_popup_menu.dart';
// 视频卡片 - 垂直布局
class VideoCardV extends StatelessWidget {
final dynamic videoItem;
final BaseRecVideoItemModel videoItem;
final VoidCallback? onRemove;
const VideoCardV({
@@ -32,56 +30,19 @@ class VideoCardV extends StatelessWidget {
}
void onPushDetail(heroTag) async {
String goto = videoItem.goto;
String goto = videoItem.goto!;
switch (goto) {
case 'bangumi':
// if (videoItem.bangumiBadge == '电影') {
// SmartDialog.showToast('暂不支持电影观看');
// return;
// }
Utils.viewBangumi(epId: videoItem.param);
// SmartDialog.showLoading(msg: '资源获取中');
// var result = await SearchHttp.bangumiInfo(seasonId: null, epId: epId);
// SmartDialog.dismiss();
// if (result['status']) {
// var bangumiDetail = result['data'];
// EpisodeItem episode = result['data'].episodes.first;
// int? epId = result['data'].userStatus?.progress?.lastEpId;
// if (epId == null) {
// epId = episode.epId;
// } else {
// for (var item in result['data'].episodes) {
// if (item.epId == epId) {
// episode = item;
// break;
// }
// }
// }
// String bvid = episode.bvid!;
// int cid = episode.cid!;
// String pic = episode.cover!;
// String seasonId = bangumiDetail.seasonId;
// dynamic heroTag = Utils.makeHeroTag(cid);
// Get.toNamed(
// '/video?bvid=$bvid&cid=$cid&seasonId=$seasonId&epId=$epId',
// arguments: {
// 'pic': pic,
// 'heroTag': heroTag,
// 'videoType': SearchType.media_bangumi,
// },
// );
// } else {
// SmartDialog.showToast(result['msg']);
// }
Utils.viewBangumi(epId: videoItem.param!);
break;
case 'av':
String bvid = videoItem.bvid ?? IdUtils.av2bv(videoItem.aid);
int cid = videoItem.cid;
String bvid = videoItem.bvid ?? IdUtils.av2bv(videoItem.aid!);
int cid = videoItem.cid!;
if (cid == -1) {
cid = await SearchHttp.ab2c(aid: videoItem.aid, bvid: bvid);
}
Get.toNamed(
'/video?bvid=$bvid&cid=$cid',
Utils.toViewPage(
'bvid=$bvid&cid=$cid',
arguments: {
// 'videoItem': videoItem,
'pic': videoItem.pic,
@@ -93,32 +54,21 @@ class VideoCardV extends StatelessWidget {
case 'picture':
try {
String dynamicType = 'picture';
String uri = videoItem.uri;
String uri = videoItem.uri!;
String id = '';
if (videoItem.uri.startsWith('bilibili://article/')) {
if (uri.startsWith('bilibili://article/')) {
// https://www.bilibili.com/read/cv27063554
dynamicType = 'read';
RegExp regex = RegExp(r'\d+');
Match match = regex.firstMatch(videoItem.uri)!;
Match match = regex.firstMatch(uri)!;
String matchedNumber = match.group(0)!;
videoItem.param = int.parse(matchedNumber);
id = 'cv${videoItem.param}';
}
if (uri.startsWith('http')) {
String path = Uri.parse(uri).path;
if (isStringNumeric(path.split('/')[1])) {
// 请求接口
var res =
await DynamicsHttp.dynamicDetail(id: path.split('/')[1]);
if (res['status']) {
Get.toNamed('/dynamicDetail', arguments: {
'item': res['data'],
'floor': 1,
'action': 'detail'
});
} else {
SmartDialog.showToast(res['msg']);
}
String id = Uri.parse(uri).path.split('/')[1];
if (isStringNumeric(id)) {
Utils.pushDynFromId(id);
return;
}
}
@@ -133,8 +83,8 @@ class VideoCardV extends StatelessWidget {
}
break;
default:
SmartDialog.showToast(videoItem.goto);
Utils.handleWebview(videoItem.uri);
SmartDialog.showToast(goto);
Utils.handleWebview(videoItem.uri!);
}
}
@@ -152,7 +102,7 @@ class VideoCardV extends StatelessWidget {
clipBehavior: Clip.hardEdge,
margin: EdgeInsets.zero,
child: InkWell(
onTap: () => onPushDetail(Utils.makeHeroTag(videoItem.id)),
onTap: () => onPushDetail(Utils.makeHeroTag(videoItem.aid)),
onLongPress: () => imageSaveDialog(
context: context,
title: videoItem.title,
@@ -217,7 +167,7 @@ class VideoCardV extends StatelessWidget {
Row(
children: [
Expanded(
child: Text(videoItem.title + "\n",
child: Text("${videoItem.title}\n",
// semanticsLabel: "${videoItem.title}",
maxLines: 2,
overflow: TextOverflow.ellipsis,
@@ -261,7 +211,7 @@ class VideoCardV extends StatelessWidget {
),
const SizedBox(width: 2),
],
if (videoItem.isFollowed == 1) ...[
if (videoItem.isFollowed) ...[
const PBadge(
text: '已关注',
stack: 'normal',
@@ -297,27 +247,26 @@ class VideoCardV extends StatelessWidget {
Widget videoStat(context) {
return Row(
children: [
statView(
StatView(
context: context,
theme: 'gray',
view: videoItem.stat.view,
value: videoItem.stat.viewStr,
goto: videoItem.goto,
),
const SizedBox(width: 4),
if (videoItem.goto != 'picture')
statDanMu(
StatDanMu(
context: context,
theme: 'gray',
danmu: videoItem.stat.danmu,
value: videoItem.stat.danmuStr,
),
if (videoItem is RecVideoItemModel) ...<Widget>[
const Spacer(),
Expanded(
flex: 0,
child: RichText(
child: Text.rich(
maxLines: 1,
textScaler: MediaQuery.textScalerOf(context),
text: TextSpan(
TextSpan(
style: TextStyle(
fontSize:
Theme.of(context).textTheme.labelSmall!.fontSize,
@@ -333,14 +282,13 @@ class VideoCardV extends StatelessWidget {
],
if (videoItem is RecVideoItemAppModel &&
videoItem.desc != null &&
videoItem.desc.contains(' · ')) ...<Widget>[
videoItem.desc!.contains(' · ')) ...<Widget>[
const Spacer(),
Expanded(
flex: 0,
child: RichText(
child: Text.rich(
maxLines: 1,
textScaler: MediaQuery.textScalerOf(context),
text: TextSpan(
TextSpan(
style: TextStyle(
fontSize:
Theme.of(context).textTheme.labelSmall!.fontSize,
@@ -350,7 +298,7 @@ class VideoCardV extends StatelessWidget {
.withOpacity(0.8),
),
text: Utils.shortenChineseDateString(
videoItem.desc.split(' · ').last)),
videoItem.desc!.split(' · ').last)),
)),
const SizedBox(width: 2),
]

View File

@@ -1,8 +1,9 @@
import 'package:PiliPlus/common/widgets/image_save.dart';
import 'package:PiliPlus/http/search.dart';
import 'package:PiliPlus/models/space/item.dart';
import 'package:PiliPlus/utils/id_utils.dart';
import 'package:flutter/material.dart';
import 'package:flutter_smart_dialog/flutter_smart_dialog.dart';
import 'package:get/get.dart';
import '../../utils/utils.dart';
import '../constants.dart';
import 'badge.dart';
@@ -21,56 +22,23 @@ class VideoCardVMemberHome extends StatelessWidget {
String goto = videoItem.goto ?? '';
switch (goto) {
case 'bangumi':
// if (videoItem.bangumiBadge == '电影') {
// SmartDialog.showToast('暂不支持电影观看');
// return;
// }
// int epId = videoItem.param;
Utils.viewBangumi(epId: videoItem.param);
// SmartDialog.showLoading(msg: '资源获取中');
// var result = await SearchHttp.bangumiInfo(seasonId: null, epId: epId);
// SmartDialog.dismiss();
// if (result['status']) {
// var bangumiDetail = result['data'];
// EpisodeItem episode = result['data'].episodes.first;
// int? epId = result['data'].userStatus?.progress?.lastEpId;
// if (epId == null) {
// epId = episode.epId;
// } else {
// for (var item in result['data'].episodes) {
// if (item.epId == epId) {
// episode = item;
// break;
// }
// }
// }
// String bvid = episode.bvid!;
// int cid = episode.cid!;
// String pic = episode.cover!;
// String seasonId = bangumiDetail.seasonId;
// dynamic heroTag = Utils.makeHeroTag(cid);
// Get.toNamed(
// '/video?bvid=$bvid&cid=$cid&seasonId=$seasonId&epId=$epId',
// arguments: {
// 'pic': pic,
// 'heroTag': heroTag,
// 'videoType': SearchType.media_bangumi,
// },
// );
// } else {
// SmartDialog.showToast(result['msg']);
// }
// break;
break;
case 'av':
if (videoItem.isPgc == true && videoItem.uri?.isNotEmpty == true) {
if (Utils.viewPgcFromUri(videoItem.uri!)) {
return;
}
}
String bvid = videoItem.bvid ?? '';
Get.toNamed(
'/video?bvid=$bvid&cid=${videoItem.firstCid}',
String? aid = videoItem.param;
String? bvid = videoItem.bvid;
if (aid == null && bvid == null) {
return;
}
int? cid = videoItem.firstCid;
cid ??= await SearchHttp.ab2c(aid: aid, bvid: bvid);
Utils.toViewPage(
'bvid=${bvid ?? IdUtils.av2bv(int.parse(aid!))}&cid=$cid',
arguments: {
// 'videoItem': videoItem,
'pic': videoItem.cover,

View File

@@ -1,3 +1,4 @@
import 'package:PiliPlus/models/model_video.dart';
import 'package:PiliPlus/pages/search/widgets/search_text.dart';
import 'package:PiliPlus/utils/utils.dart';
import 'package:flutter/material.dart';
@@ -21,16 +22,16 @@ class VideoCustomAction {
}
class VideoCustomActions {
dynamic videoItem;
BaseSimpleVideoItemModel videoItem;
BuildContext context;
late List<VideoCustomAction> actions;
VoidCallback? onRemove;
VideoCustomActions(this.videoItem, this.context, [this.onRemove]) {
actions = [
if ((videoItem.bvid as String?)?.isNotEmpty == true) ...[
if (videoItem.bvid?.isNotEmpty == true) ...[
VideoCustomAction(
videoItem.bvid,
videoItem.bvid!,
'copy',
Stack(
children: [
@@ -39,7 +40,7 @@ class VideoCustomActions {
],
),
() {
Utils.copyText(videoItem.bvid);
Utils.copyText(videoItem.bvid!);
},
),
VideoCustomAction(
@@ -68,8 +69,7 @@ class VideoCustomActions {
VideoCustomAction(
'不感兴趣', 'dislike', Icon(MdiIcons.thumbDownOutline, size: 16),
() async {
String? accessKey = GStorage.localCache
.get(LocalCacheKey.accessKey, defaultValue: {})['value'];
String? accessKey = Accounts.get(AccountType.recommend).accessKey;
if (accessKey == null || accessKey == "") {
SmartDialog.showToast("请退出账号后重新登录");
return;
@@ -85,7 +85,7 @@ class VideoCustomActions {
SmartDialog.showToast("未能获取dislikeReasons或feedbacks");
return;
}
Widget actionButton(DislikeReason? r, FeedbackReason? f) {
Widget actionButton(Reason? r, Reason? f) {
return SearchText(
text: r?.name ?? f?.name ?? '未知',
onTap: (_) async {
@@ -259,13 +259,11 @@ class VideoCustomActions {
TextButton(
onPressed: () async {
var res = await VideoHttp.relationMod(
mid: videoItem.owner.mid,
mid: videoItem.owner.mid!,
act: 5,
reSrc: 11,
);
List<int> blackMidsList = GStorage.blackMidsList;
blackMidsList.insert(0, videoItem.owner.mid);
GStorage.setBlackMidsList(blackMidsList);
GStorage.setBlackMid(videoItem.owner.mid!);
Get.back();
SmartDialog.showToast(res['msg'] ?? '成功');
},

View File

@@ -0,0 +1,27 @@
import 'package:flutter/material.dart';
Widget videoProgressIndicator(double progress) => ClipRect(
clipper: ProgressClipper(),
child: ClipRRect(
borderRadius: BorderRadius.only(
bottomLeft: Radius.circular(10),
bottomRight: Radius.circular(10),
),
child: LinearProgressIndicator(
minHeight: 10,
value: progress,
),
),
);
class ProgressClipper extends CustomClipper<Rect> {
@override
Rect getClip(Size size) {
return Rect.fromLTWH(0, 6, size.width, size.height - 6);
}
@override
bool shouldReclip(CustomClipper<Rect> oldClipper) {
return false;
}
}

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