Compare commits

..

117 Commits

Author SHA1 Message Date
bggRGjQaUbCoE
358a14b3f6 chore: release 1.1.2
Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
2025-01-10 11:31:56 +08:00
bggRGjQaUbCoE
0be2cac3a0 fix: home: anim to top
Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
2025-01-10 11:21:35 +08:00
bggRGjQaUbCoE
86dd54991a fix: pgc type
Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
2025-01-10 11:08:49 +08:00
bggRGjQaUbCoE
0ece0bd7fa feat: home: cinema
Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
2025-01-10 11:02:01 +08:00
bggRGjQaUbCoE
c9fe3c6485 mod: bangumi: load more followlist
Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
2025-01-10 10:17:54 +08:00
bggRGjQaUbCoE
093b84ca3a fix: #133
Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
2025-01-10 09:30:51 +08:00
bggRGjQaUbCoE
6c4cf5a139 fix: pgc label
Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
2025-01-09 22:30:16 +08:00
bggRGjQaUbCoE
794fb9c7e4 feat: search media_ft
Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
2025-01-09 22:07:49 +08:00
bggRGjQaUbCoE
57043166a9 opt: view pgc from dynamic
Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
2025-01-09 21:47:31 +08:00
bggRGjQaUbCoE
9ab6dcff23 feat: rcmd(app)/hot: filter zone
Closes #119

Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
2025-01-09 18:44:24 +08:00
bggRGjQaUbCoE
eec4aa50f0 opt: member page
Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
2025-01-09 18:29:53 +08:00
bggRGjQaUbCoE
3d94a15d5d chore: update dep
Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
2025-01-09 18:29:52 +08:00
bggRGjQaUbCoE
dc75d59ccd opt: view pgc
Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
2025-01-09 18:37:47 +08:00
bggRGjQaUbCoE
ff00ade786 opt: archive: episode btn
Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
2025-01-09 18:37:28 +08:00
bggRGjQaUbCoE
43fcc36165 opt: viewpoint text
Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
2025-01-09 14:28:13 +08:00
bggRGjQaUbCoE
33465db0c3 opt: horizontal part view
Closes #128

Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
2025-01-09 13:53:24 +08:00
bggRGjQaUbCoE
6d9651070e opt: view pgc
Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
2025-01-09 13:04:10 +08:00
bggRGjQaUbCoE
c8ad94343a opt: unread msg
Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
2025-01-09 12:57:43 +08:00
bggRGjQaUbCoE
df81a33ae0 fix: #125
Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
2025-01-09 12:57:43 +08:00
bggRGjQaUbCoE
f4261dd8f7 opt: findClosestNumber
Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
2025-01-09 12:57:43 +08:00
bggRGjQaUbCoE
5ea594b747 opt: video: skip panel
Closes #104

Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
2025-01-09 13:09:41 +08:00
bggRGjQaUbCoE
e8c82f69d4 opt: unread msg
Closes #122

Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
2025-01-09 12:41:57 +08:00
bggRGjQaUbCoE
41dfab371e Reapply "opt: msg badge"
This reverts commit f9c365011b.
2025-01-09 12:44:59 +08:00
bggRGjQaUbCoE
7e400701df mod: handle video intro
Closes #126

Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
2025-01-09 12:25:20 +08:00
bggRGjQaUbCoE
5b1ec83a34 fix: up panel
Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
2025-01-09 11:57:54 +08:00
bggRGjQaUbCoE
adf4b6fa5d opt: cdn test
Closes #129

Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
2025-01-09 11:53:52 +08:00
bggRGjQaUbCoE
d4e33c9636 fix: request onerror
Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
2025-01-09 11:44:24 +08:00
bggRGjQaUbCoE
e8396bd313 opt: checkUpdate
Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
2025-01-08 23:18:08 +08:00
bggRGjQaUbCoE
96ea6d60e3 fix: #121
Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
2025-01-08 23:04:57 +08:00
bggRGjQaUbCoE
f9c365011b Revert "opt: msg badge"
This reverts commit 8ce5026778.
2025-01-08 22:04:54 +08:00
bggRGjQaUbCoE
8ce5026778 opt: msg badge
Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
2025-01-08 21:26:18 +08:00
bggRGjQaUbCoE
56350b181f opt: findClosestNumber
Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
2025-01-08 20:36:54 +08:00
bggRGjQaUbCoE
5982fd312b fix: filter reply
Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
2025-01-08 20:20:18 +08:00
bggRGjQaUbCoE
4d35dfe2f0 mod: mine page
Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
2025-01-08 20:12:56 +08:00
bggRGjQaUbCoE
0eac1b2c69 opt: findClosestNumber
Closes #120

Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
2025-01-08 20:09:08 +08:00
bggRGjQaUbCoE
89050c7ca8 chore: release 1.1.1
Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
2025-01-08 19:30:47 +08:00
bggRGjQaUbCoE
ae16771b5e feat: filter reply
Closes #118

Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
2025-01-08 19:28:52 +08:00
bggRGjQaUbCoE
847f42fee3 opt: reply2reply
Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
2025-01-08 19:28:48 +08:00
bggRGjQaUbCoE
8d4294ba75 feat: custom horizontal preview
Closes #117

Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
2025-01-08 19:28:48 +08:00
bggRGjQaUbCoE
0b9d4d970a opt: cdn test desc
Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
2025-01-08 19:28:48 +08:00
bggRGjQaUbCoE
34c024239d opt: mine page
Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
2025-01-08 18:45:28 +08:00
bggRGjQaUbCoE
71daa6df29 opt: member info widget
Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
2025-01-08 18:27:24 +08:00
bggRGjQaUbCoE
20c1112a10 Update android.yml
Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
2025-01-08 14:23:21 +08:00
bggRGjQaUbCoE
31e8c36653 Update ios.yml 2025-01-08 14:19:42 +08:00
bggRGjQaUbCoE
e06a3d8f22 opt: login/logout
Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
2025-01-08 13:57:36 +08:00
bggRGjQaUbCoE
c77ceea262 mod: update request onerror
Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
2025-01-08 11:58:14 +08:00
bggRGjQaUbCoE
28b6b769b2 mod: add check update
Closes #112

Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
2025-01-08 11:28:32 +08:00
bggRGjQaUbCoE
57722eb579 opt: main page
Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
2025-01-07 20:59:37 +08:00
bggRGjQaUbCoE
d4e381380a opt: msg badge
Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
2025-01-07 20:31:10 +08:00
bggRGjQaUbCoE
21fdcdb2bb opt: reply error widget
Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
2025-01-07 18:20:19 +08:00
bggRGjQaUbCoE
1a30e542a9 opt: unread badge
Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
2025-01-07 17:39:36 +08:00
bggRGjQaUbCoE
c1ce704e4e feat: home: show unread badge
Closes #107

Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
2025-01-07 17:05:38 +08:00
bggRGjQaUbCoE
30a5889215 mod: rank: filter like ratio
Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
2025-01-07 12:21:18 +08:00
bggRGjQaUbCoE
75a242de2a mod: hot: filter like ratio
Closes #108

Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
2025-01-07 12:18:13 +08:00
bggRGjQaUbCoE
a0afbb2615 mod: tmply disable grpc reply
Closes #114

Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
2025-01-07 12:00:38 +08:00
bggRGjQaUbCoE
da3c087ade fix: #115
Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
2025-01-07 11:41:35 +08:00
bggRGjQaUbCoE
4dc0389624 chore: rename to PiliPlus
Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
2025-01-07 11:20:44 +08:00
bggRGjQaUbCoE
488cb58b85 opt: speed test
Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
2025-01-07 11:03:24 +08:00
bggRGjQaUbCoE
f5b50ffcb0 feat: cdn speed test
Closes #105

Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
2025-01-07 10:26:29 +08:00
bggRGjQaUbCoE
d9474a79c1 opt: videopage: didpop
Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
2025-01-06 21:09:41 +08:00
bggRGjQaUbCoE
3a15353bc4 opt: multi del
Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
2025-01-06 18:03:09 +08:00
bggRGjQaUbCoE
b239737498 fix: vttSubtitlesIndex
Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
2025-01-06 17:55:17 +08:00
bggRGjQaUbCoE
5001f3b6d2 mod: sync flip/onlyPlayAudio from orz12/main
Closes #100

Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
2025-01-06 16:17:07 +08:00
bggRGjQaUbCoE
3d803cce9f opt: init play
Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
2025-01-06 14:32:15 +08:00
bggRGjQaUbCoE
d0046d0faf mod: partial revert
Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
2025-01-06 13:26:13 +08:00
bggRGjQaUbCoE
d59c364ba6 fix: auto play
Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
2025-01-06 12:13:31 +08:00
bggRGjQaUbCoE
fee161e99b mod: intro: author info widget
Closes #103

Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
2025-01-06 11:38:17 +08:00
bggRGjQaUbCoE
5a481dbaaf opt: query sponsorblock
Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
2025-01-06 11:16:51 +08:00
bggRGjQaUbCoE
f3279b4177 opt: reply item
Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
2025-01-06 09:48:40 +08:00
bggRGjQaUbCoE
242fde92f6 opt: history item menu
Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
2025-01-06 09:26:48 +08:00
bggRGjQaUbCoE
a9c542ac4e fix: video title
Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
2025-01-06 09:08:52 +08:00
bggRGjQaUbCoE
4aebc0aac5 feat: sponsorblock: show video label
Closes #102

Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
2025-01-06 08:59:55 +08:00
bggRGjQaUbCoE
51bf59e329 opt: intro action
Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
2025-01-06 08:59:36 +08:00
bggRGjQaUbCoE
39716cc1d4 opt: requery video url
Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
2025-01-06 08:59:15 +08:00
bggRGjQaUbCoE
50cf99720b opt: listsheet
Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
2025-01-06 08:58:56 +08:00
bggRGjQaUbCoE
214239a6f8 opt: heartbeat
Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
2025-01-06 08:58:24 +08:00
bggRGjQaUbCoE
0d63d6102f chore: update sponsorblock title
Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
2025-01-06 00:04:43 +08:00
bggRGjQaUbCoE
47e79ee7d8 opt: player
Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
2025-01-06 00:04:43 +08:00
bggRGjQaUbCoE
22e6e19500 mod: update def settings
Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
2025-01-05 23:27:44 +08:00
bggRGjQaUbCoE
8ae92b859f opt: make heartbeat when changing episode
Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
2025-01-05 21:04:35 +08:00
bggRGjQaUbCoE
78180a1dd1 opt: login
Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
2025-01-05 15:40:49 +08:00
bggRGjQaUbCoE
f47c500c5b fix: pgclabel data
Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
2025-01-05 15:25:47 +08:00
bggRGjQaUbCoE
2e65b65b1d opt: media page
Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
2025-01-05 15:11:59 +08:00
bggRGjQaUbCoE
88578393c2 opt: query bangumi url
Closes #101

Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
2025-01-05 14:56:30 +08:00
bggRGjQaUbCoE
1643db4656 opt: multi select
Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
2025-01-05 14:45:20 +08:00
bggRGjQaUbCoE
e4b8dfcada opt: view to-view video
Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
2025-01-05 14:37:01 +08:00
bggRGjQaUbCoE
1a3f5414c6 opt: send danmaku
Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
2025-01-05 13:37:34 +08:00
bggRGjQaUbCoE
789d8a77dd mod: image view
Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
2025-01-05 13:19:41 +08:00
bggRGjQaUbCoE
5efbdda107 mod: seek
Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
2025-01-05 13:19:33 +08:00
bggRGjQaUbCoE
2aa109b089 Revert "feat: custom subtitle bg stroke"
This reverts commit 168bb22670.
2025-01-05 12:15:42 +08:00
bggRGjQaUbCoE
22abc4488b opt: send danmaku panel
Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
2025-01-05 12:12:41 +08:00
bggRGjQaUbCoE
0d41731681 mod: update danmaku dep
Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
2025-01-05 11:44:25 +08:00
bggRGjQaUbCoE
f467532f9d opt: whisper data
Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
2025-01-05 11:24:12 +08:00
bggRGjQaUbCoE
daf01df5aa fix: #99
Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
2025-01-05 11:11:28 +08:00
bggRGjQaUbCoE
738c057304 fix: add sent danmaku
Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
2025-01-04 22:54:14 +08:00
bggRGjQaUbCoE
cf76cb6f63 fix: add sent danmaku
Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
2025-01-04 22:37:17 +08:00
bggRGjQaUbCoE
27e39d4de5 feat: new send danmaku panel
Closes #98

Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
2025-01-04 21:57:49 +08:00
bggRGjQaUbCoE
58fd373e8c fix: search settings item
Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
2025-01-04 17:43:54 +08:00
bggRGjQaUbCoE
76b37437d3 opt: reply item
Closes #95

Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
2025-01-04 16:51:09 +08:00
bggRGjQaUbCoE
8186307f98 opt: manul skip
Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
2025-01-04 16:04:41 +08:00
bggRGjQaUbCoE
be42ce97f8 feat: sponsorblock: manual skip
Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
2025-01-04 15:39:33 +08:00
bggRGjQaUbCoE
5f6dcc9569 mod: update bufferSize
related #93

Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
2025-01-04 15:39:03 +08:00
bggRGjQaUbCoE
4539e0e5c5 opt: rcmd settings
Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
2025-01-04 13:24:23 +08:00
bggRGjQaUbCoE
d066262cdd opt: toast text color
Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
2025-01-04 13:12:15 +08:00
bggRGjQaUbCoE
7ac4a32468 chore: update release version
Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
2025-01-04 12:36:14 +08:00
bggRGjQaUbCoE
9cf74c0db6 opt: pages
Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
2025-01-04 10:44:21 +08:00
bggRGjQaUbCoE
14f2c34d21 opt: continuePlayingPart
Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
2025-01-04 09:15:47 +08:00
bggRGjQaUbCoE
b7b4432d71 feat: continue playing part
Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
2025-01-04 08:51:00 +08:00
bggRGjQaUbCoE
0be609db3d fix: #92
Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
2025-01-03 21:52:51 +08:00
bggRGjQaUbCoE
321b7933d7 opt: code
Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
2025-01-03 21:23:55 +08:00
bggRGjQaUbCoE
1d51db0a62 fix: settings
Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
2025-01-03 18:18:06 +08:00
bggRGjQaUbCoE
18ee1d4e18 feat: search settings item
Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
2025-01-03 17:47:13 +08:00
bggRGjQaUbCoE
413a49bcb1 fix: search suggest text color
Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
2025-01-03 13:56:37 +08:00
bggRGjQaUbCoE
fd1bb0af30 mod: SliverHeaderDelegate
Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
2025-01-03 13:28:12 +08:00
bggRGjQaUbCoE
f808012ec2 opt: style settings
Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
2025-01-03 13:12:43 +08:00
bggRGjQaUbCoE
51e436faed opt: bangumi card
Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
2025-01-03 11:31:56 +08:00
bggRGjQaUbCoE
168bb22670 feat: custom subtitle bg stroke
Closes #90

Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
2025-01-03 11:20:42 +08:00
322 changed files with 8132 additions and 6489 deletions

View File

@@ -1,223 +0,0 @@
name: CI
on:
workflow_dispatch:
# push:
# branches:
# - 'main'
# paths-ignore:
# - '**.md'
# - '**.txt'
# - '.github/**'
# - '.idea/**'
# - '!.github/workflows/CI.yml'
jobs:
update_version:
name: Read and update version
runs-on: ubuntu-latest
outputs:
# 定义输出变量 version以便在其他job中引用
new_version: ${{ steps.version.outputs.new_version }}
steps:
- name: Checkout code
uses: actions/checkout@v4
with:
fetch-depth: 0
#- name: 获取first parent commit次数
# id: get-first-parent-commit-count
# run: |
# version=$(yq e .version pubspec.yaml | cut -d "+" -f 1)
# recent_release_tag=$(git tag -l | grep $version | egrep -v "[-|+]" || true)
# if [[ "x$recent_release_tag" == "x" ]]; then
# echo "当前版本tag不存在请手动生成tag."
# exit 1
# fi
# git log --oneline HEAD
# first_parent_commit_count=$(git rev-list --first-parent --count $recent_release_tag..HEAD)
# echo "count=$first_parent_commit_count" >> $GITHUB_OUTPUT
- name: 从tag获取之前的version_code与beta版本号
id: get-previous-codes
run: |
version=$(yq e .version pubspec.yaml | cut -d "+" -f 1)
last_tag=$(git tag --sort=committerdate | tail -1)
if (echo $last_tag | grep -v "+"); then
echo "Tag格式不正确"
exit 1
elif (echo $last_tag | grep -v $version); then
echo "当前版本tag不存在请手动添加tag."
exit 1
fi
version_code=$(echo $last_tag | cut -d "+" -f 2)
beta_code=$(echo $last_tag | cut -d "+" -f 1 | cut -d "." -f 4)
beta_code=${beta_code:-0}
echo "beta-code=$beta_code" >> $GITHUB_OUTPUT
echo "version-code=$version_code" >> $GITHUB_OUTPUT
- name: 更新版本号
id: version
run: |
# 读取版本号
version_name=$(yq e .version pubspec.yaml | cut -d "+" -f 1)
let beta_code=${{ steps.get-previous-codes.outputs.beta-code }}+1
let version_code=${{ steps.get-previous-codes.outputs.version-code }}+1
# 构建新版本号
NEW_VERSION=${version_name}-beta.${beta_code}+${version_code}
# 输出新版本号
echo "New version: $NEW_VERSION"
# 设置新版本号为输出变量
echo "new_version=$NEW_VERSION" >>$GITHUB_OUTPUT
android:
name: Build CI (Android)
needs: update_version
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v2
- name: 构建Java环境
uses: actions/setup-java@v3
with:
distribution: "zulu"
java-version: "17"
token: ${{secrets.GIT_TOKEN}}
- name: 检查缓存
uses: actions/cache@v2
id: cache-flutter
with:
path: /root/flutter-sdk
key: ${{ runner.os }}-flutter-${{ hashFiles('**/pubspec.lock') }}
- name: 安装Flutter
if: steps.cache-flutter.outputs.cache-hit != 'true'
uses: subosito/flutter-action@v2
with:
flutter-version: 3.24.0
channel: any
- name: 下载项目依赖
run: flutter pub get
- name: 解码生成 jks
run: echo $KEYSTORE_BASE64 | base64 -di > android/app/vvex.jks
env:
KEYSTORE_BASE64: ${{ secrets.KEYSTORE_BASE64 }}
- name: 更新版本号
id: version
run: |
# 更新pubspec.yaml文件中的版本号
sed -i "s/version: .*/version: ${{ needs.update_version.outputs.new_version }}/g" pubspec.yaml
- name: flutter build apk
run: flutter build apk --release --split-per-abi
env:
KEYSTORE_PASSWORD: ${{ secrets.KEYSTORE_PASSWORD }}
KEY_ALIAS: ${{ secrets.KEY_ALIAS }}
KEY_PASSWORD: ${{ secrets.KEY_PASSWORD}}
- name: flutter build apk
run: |
sed -i "s/version: .*/version: ${{ needs.update_version.outputs.new_version }}0/g" pubspec.yaml
flutter build apk --release
env:
KEYSTORE_PASSWORD: ${{ secrets.KEYSTORE_PASSWORD }}
KEY_ALIAS: ${{ secrets.KEY_ALIAS }}
KEY_PASSWORD: ${{ secrets.KEY_PASSWORD}}
- name: 重命名应用
run: |
version_name=$(yq e .version pubspec.yaml | cut -d "+" -f 1)
for file in build/app/outputs/flutter-apk/app-*.apk; do
if [[ $file =~ app-(.?*)release.apk ]]; then
new_file_name="build/app/outputs/flutter-apk/Pili-${BASH_REMATCH[1]}${version_name}.apk"
mv "$file" "$new_file_name"
fi
done
- name: 上传
uses: actions/upload-artifact@v3
with:
name: Pilipala-CI
path: |
build/app/outputs/flutter-apk/Pili-*.apk
iOS:
name: Build CI (iOS)
needs: update_version
runs-on: macos-latest
steps:
- name: Checkout code
uses: actions/checkout@v2
- name: 安装Flutter
if: steps.cache-flutter.outputs.cache-hit != 'true'
uses: subosito/flutter-action@v2.10.0
with:
cache: true
flutter-version: 3.24.0
- name: 更新版本号
id: version
run: |
# 更新pubspec.yaml文件中的版本号
sed -i "" "s/version: .*/version: ${{ needs.update_version.outputs.new_version }}/g" pubspec.yaml
- name: flutter build ipa
run: |
flutter build ios --release --no-codesign
ln -sf ./build/ios/iphoneos Payload
zip -r9 app.ipa Payload/runner.app
- name: 重命名应用
run: |
version_name=$(yq e .version pubspec.yaml | cut -d "+" -f 1)
for file in app.ipa; do
new_file_name="build/Pili-${version_name}.ipa"
mv "$file" "$new_file_name"
done
- name: 上传
uses: actions/upload-artifact@v3
with:
if-no-files-found: error
name: Pilipala-CI
path: |
build/Pili-*.ipa
upload:
runs-on: ubuntu-latest
needs:
- update_version
- android
- iOS
steps:
- uses: actions/download-artifact@v3
with:
name: Pilipala-CI
path: ./Pilipala-CI
- name: Upload Pre-release
uses: ncipollo/release-action@v1
with:
name: ${{ needs.update_version.outputs.new_version }}
token: ${{ secrets.GIT_TOKEN }}
commit: main
tag: ${{ needs.update_version.outputs.new_version }}
prerelease: true
allowUpdates: true
artifacts: Pilipala-CI/*

View File

@@ -10,6 +10,8 @@ jobs:
steps:
- name: 代码迁出
uses: actions/checkout@v4
with:
fetch-depth: 0
- name: 构建Java环境
uses: actions/setup-java@v4
@@ -31,9 +33,27 @@ jobs:
channel: stable
flutter-version-file: pubspec.yaml
- name: 修复3.24的stable显示中文不正确问题 // from orz12
run: |
version=$(grep -m 1 'flutter:' pubspec.yaml | awk '{print $2}')
if [ "$(echo "$version < 3.27.0" | awk '{print ($1 < $2)}')" -eq 1 ]; then
cd $FLUTTER_ROOT
git config --global user.name "orz12"
git config --global user.email "orz12@test.com"
git cherry-pick d4124bd --strategy-option theirs
# flutter precache
flutter --version
cd -
fi
- name: 下载项目依赖
run: flutter pub get
- name: 更新版本号
run: |
version_name=$(yq e .version pubspec.yaml | cut -d "+" -f 1)
sed -i "s/version: .*/version: $version_name-$(git rev-parse --short HEAD)+$(git rev-list --count HEAD)/g" pubspec.yaml
- name: Write key
run: |
if [ ! -z "${{ secrets.SIGN_KEYSTORE_BASE64 }}" ]; then

View File

@@ -1,130 +0,0 @@
name: Build iOS
on:
workflow_dispatch:
push:
branches:
- 'build-ios'
paths-ignore:
- '**.md'
- '**.txt'
- '.github/**'
- '.idea/**'
- '!.github/workflows/build-ios.yml'
jobs:
update_version:
name: Read latest version
runs-on: ubuntu-latest
outputs:
# 定义输出变量 version以便在其他job中引用
new_version: ${{ steps.get-last-tag.outputs.tag}}
last_commit: ${{ steps.get-last-commit.outputs.last_commit }}
steps:
- name: Checkout code
uses: actions/checkout@v4
with:
fetch-depth: 0
- name: 获取最后一次提交
id: get-last-commit
run: |
last_commit=$(git log -1 --pretty="%h %s" --first-parent)
echo "last_commit=$last_commit" >> $GITHUB_OUTPUT
- name: 获取最后一个tag
id: get-last-tag
run: |
version=$(yq e .version pubspec.yaml | cut -d "+" -f 1)
last_tag=$(git tag --sort=committerdate | tail -1)
if (echo $last_tag | grep -v "+"); then
echo "Illegal tag!"
exit 1
elif (echo $last_tag | grep -v $version); then
echo "No tags for current version in the repo, please add one manually."
exit 1
fi
echo "tag=$last_tag" >> $GITHUB_OUTPUT
iOS:
name: Build CI (iOS)
needs: update_version
runs-on: macos-latest
steps:
- name: Checkout code
uses: actions/checkout@v4
with:
ref: ${{ github.ref_name }}
- name: 安装Flutter
if: steps.cache-flutter.outputs.cache-hit != 'true'
uses: subosito/flutter-action@v2.10.0
with:
cache: true
flutter-version: 3.24.0
- name: 更新版本号
id: version
run: |
# 更新pubspec.yaml文件中的版本号
sed -i "" "s/version: .*/version: ${{ needs.update_version.outputs.new_version }}/g" pubspec.yaml
- name: flutter build ipa
run: |
flutter build ios --release --no-codesign
ln -sf ./build/ios/iphoneos Payload
zip -r9 app.ipa Payload/runner.app
- name: 重命名应用
run: |
for file in app.ipa; do
new_file_name="build/Pili-${{ needs.update_version.outputs.new_version }}.ipa"
mv "$file" "$new_file_name"
done
- name: 上传
uses: actions/upload-artifact@v3
with:
if-no-files-found: error
name: PiliPalaX-iOS
path: |
build/Pili-*.ipa
upload:
runs-on: ubuntu-latest
needs:
- update_version
- iOS
steps:
- uses: actions/download-artifact@v3
with:
name: PiliPalaX-iOS
path: ./PiliPalaX-iOS
# - name: Upload Pre-release
# uses: ncipollo/release-action@v1
# with:
# name: ${{ needs.update_version.outputs.new_version }}
# token: ${{ secrets.GIT_TOKEN }}
# commit: main
# tag: ${{ needs.update_version.outputs.new_version }}
# prerelease: true
# allowUpdates: true
# artifacts: Pilipala-CI/*
- name: 发送到Telegram频道
uses: xireiki/channel-post@v1.0.7
with:
bot_token: ${{ secrets.BOT_TOKEN }}
chat_id: ${{ secrets.CHAT_ID }}
large_file: false
method: sendFile
path: PiliPalaX-iOS/*
parse_mode: Markdown
context: "*v${{ needs.update_version.outputs.new_version }}*\n${{ needs.update_version.outputs.last_commit }}"

View File

@@ -16,6 +16,7 @@ jobs:
uses: actions/checkout@v4
with:
ref: ${{ github.event.inputs.branch }}
fetch-depth: 0
- name: Setup flutter
uses: subosito/flutter-action@v2
@@ -23,8 +24,10 @@ jobs:
channel: stable
flutter-version-file: pubspec.yaml
- name: Set up xcode
uses: BoundfoxStudios/action-xcode-select@v1
- name: 更新版本号
run: |
version_name=$(yq e '.version' pubspec.yaml | cut -d "+" -f 1)
sed -i '' "s/version: .*/version: $version_name+$(git rev-list --count HEAD)/" pubspec.yaml
- name: Build iOS
run: |

6
.vscode/launch.json vendored
View File

@@ -5,18 +5,18 @@
"version": "0.2.0",
"configurations": [
{
"name": "pilipala",
"name": "piliplus",
"request": "launch",
"type": "dart"
},
{
"name": "pilipala (profile mode)",
"name": "piliplus (profile mode)",
"request": "launch",
"type": "dart",
"flutterMode": "profile"
},
{
"name": "pilipala (release mode)",
"name": "piliplus (release mode)",
"request": "launch",
"type": "dart",
"flutterMode": "release"

View File

@@ -1,24 +1,24 @@
<div align="center">
<img width="200" height="200" src="https://github.com/orz12/pilipala/blob/main/assets/images/logo/logo_android.png">
<img width="200" height="200" src="https://github.com/bggRGjQaUbCoE/PiliPlus/blob/main/assets/images/logo/logo_android.png">
</div>
<div align="center">
<h1>PiliPalaX</h1>
<h1>PiliPlus</h1>
<div align="center">
![GitHub repo size](https://img.shields.io/github/repo-size/bggRGjQaUbCoE/PiliPalaX)
![GitHub Repo stars](https://img.shields.io/github/stars/bggRGjQaUbCoE/PiliPalaX)
![GitHub all releases](https://img.shields.io/github/downloads/bggRGjQaUbCoE/PiliPalaX/total)
![GitHub repo size](https://img.shields.io/github/repo-size/bggRGjQaUbCoE/PiliPlus)
![GitHub Repo stars](https://img.shields.io/github/stars/bggRGjQaUbCoE/PiliPlus)
![GitHub all releases](https://img.shields.io/github/downloads/bggRGjQaUbCoE/PiliPlus/total)
</div>
<p>使用Flutter开发的BiliBili第三方客户端</p>
<img src="https://github.com/orz12/pilipala/blob/main/assets/screenshots/510shots_so.png" width="32%" alt="home" />
<img src="https://github.com/orz12/pilipala/blob/main/assets/screenshots/174shots_so.png" width="32%" alt="home" />
<img src="https://github.com/orz12/pilipala/blob/main/assets/screenshots/850shots_so.png" width="32%" alt="home" />
<img src="https://github.com/bggRGjQaUbCoE/PiliPlus/blob/main/assets/screenshots/510shots_so.png" width="32%" alt="home" />
<img src="https://github.com/bggRGjQaUbCoE/PiliPlus/blob/main/assets/screenshots/174shots_so.png" width="32%" alt="home" />
<img src="https://github.com/bggRGjQaUbCoE/PiliPlus/blob/main/assets/screenshots/850shots_so.png" width="32%" alt="home" />
<br/>
<img src="https://github.com/orz12/pilipala/blob/main/assets/screenshots/main_screen.png" width="96%" alt="home" />
<img src="https://github.com/bggRGjQaUbCoE/PiliPlus/blob/main/assets/screenshots/main_screen.png" width="96%" alt="home" />
<br/>
</div>
@@ -186,9 +186,10 @@
## 声明
此项目PiliPalaX)是个人为了兴趣而开发, 仅用于学习和测试请于下载后24小时内删除。
此项目PiliPlus)是个人为了兴趣而开发, 仅用于学习和测试请于下载后24小时内删除。
所用API皆从官方网站收集, 不提供任何破解内容。
在此致敬原作者:[guozhigq/pilipala](https://github.com/guozhigq/pilipala)
在此致敬上游作者:[orz12/PiliPalaX](https://github.com/orz12/PiliPalaX)
本仓库做了更激进的修改,感谢原作者的开源精神。
感谢使用

View File

@@ -11,7 +11,7 @@
/>
<application
android:label="PiliPalaX Debug"
android:label="PiliPlus Debug"
tools:replace="android:label">
<activity
android:name=".MainActivity"
@@ -36,7 +36,7 @@
<action android:name="android.intent.action.MAIN"/>
<category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
<intent-filter android:label="PiliPalaX Debug">
<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" />
@@ -60,7 +60,7 @@
<!--<data android:host="bangumi.bilibili.com"/>-->
<!--<data android:host="space.bilibili.com"/>-->
</intent-filter>
<intent-filter android:label="PiliPalaX Debug">
<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" />

View File

@@ -36,7 +36,7 @@
</queries>
<application
android:label="PiliPalaX"
android:label="PiliPlus"
android:name="${applicationName}"
android:icon="@mipmap/ic_launcher"
xmlns:tools="http://schemas.android.com/tools"
@@ -67,7 +67,7 @@
<action android:name="android.intent.action.MAIN"/>
<category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
<intent-filter android:label="PiliPalaX+">
<intent-filter android:label="PiliPlus">
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />
@@ -91,7 +91,7 @@
<!--<data android:host="bangumi.bilibili.com"/>-->
<!--<data android:host="space.bilibili.com"/>-->
</intent-filter>
<intent-filter android:label="PiliPalaX+">
<intent-filter android:label="PiliPlus">
<action android:name="android.intent.action.VIEW" />
<action android:name="android.intent.action.SEARCH" />
<category android:name="android.intent.category.DEFAULT" />

View File

@@ -17,7 +17,7 @@ class MainActivity : AudioServiceActivity() {
override fun configureFlutterEngine(flutterEngine: FlutterEngine) {
super.configureFlutterEngine(flutterEngine)
methodChannel = MethodChannel(flutterEngine.dartExecutor.binaryMessenger, "pilipalax")
methodChannel = MethodChannel(flutterEngine.dartExecutor.binaryMessenger, "PiliPlus")
methodChannel.setMethodCallHandler { call, result ->
if (call.method == "back") {
back()

View File

@@ -1,5 +1,5 @@
PiliPalaX is a third-party Bilibili client developed in Flutter,
fork from PiliPala (https://github.com/guozhigq/pilipala).
PiliPlus is a third-party Bilibili client developed in Flutter,
fork from PiliPalaX (https://github.com/orz12/PiliPalaX).
Top Features:

View File

@@ -1 +1 @@
PiliPalaX
PiliPlus

View File

@@ -1,5 +1,5 @@
PiliPalaX 是使用 Flutter 开发的 BiliBili 第三方客户端,
是由PiliPala仓库fork并进行了差异化开发的版本
PiliPlus 是使用 Flutter 开发的 BiliBili 第三方客户端,
是由PiliPalaX仓库fork并进行了差异化开发的版本
主要功能:

View File

@@ -1 +1 @@
PiliPalaX
PiliPlus

View File

@@ -5,7 +5,7 @@
<key>CFBundleDevelopmentRegion</key>
<string>$(DEVELOPMENT_LANGUAGE)</string>
<key>CFBundleDisplayName</key>
<string>PiliPalaX</string>
<string>PiliPlus</string>
<key>CFBundleExecutable</key>
<string>$(EXECUTABLE_NAME)</string>
<key>CFBundleIdentifier</key>
@@ -13,7 +13,7 @@
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundleName</key>
<string>PiliPalaX</string>
<string>PiliPlus</string>
<key>CFBundlePackageType</key>
<string>APPL</string>
<key>CFBundleShortVersionString</key>

View File

@@ -1,5 +1,5 @@
import 'package:flutter/material.dart';
import 'package:PiliPalaX/common/constants.dart';
import 'package:PiliPlus/common/constants.dart';
import 'skeleton.dart';

View File

@@ -1,4 +1,4 @@
import 'package:PiliPalaX/common/constants.dart';
import 'package:PiliPlus/common/constants.dart';
import 'package:flutter/material.dart';
import 'skeleton.dart';

View File

@@ -1,4 +1,4 @@
import 'package:PiliPalaX/common/constants.dart';
import 'package:PiliPlus/common/constants.dart';
import 'package:flutter/material.dart';
import 'skeleton.dart';

View File

@@ -1,5 +1,5 @@
import 'package:PiliPalaX/common/widgets/no_splash_factory.dart';
import 'package:PiliPalaX/common/widgets/overlay_pop.dart';
import 'package:PiliPlus/common/widgets/no_splash_factory.dart';
import 'package:PiliPlus/common/widgets/overlay_pop.dart';
import 'package:flutter/material.dart';
class AnimatedDialog extends StatefulWidget {

View File

@@ -1,6 +1,6 @@
import 'package:PiliPalaX/common/widgets/network_img_layer.dart';
import 'package:PiliPalaX/models/dynamics/article_content_model.dart';
import 'package:PiliPalaX/utils/extension.dart';
import 'package:PiliPlus/common/widgets/network_img_layer.dart';
import 'package:PiliPlus/models/dynamics/article_content_model.dart';
import 'package:PiliPlus/utils/extension.dart';
import 'package:cached_network_image/cached_network_image.dart';
import 'package:flutter/material.dart';
import 'package:flutter_html/flutter_html.dart';
@@ -8,6 +8,7 @@ import 'package:flutter_html/flutter_html.dart';
Widget articleContent({
required BuildContext context,
required List<ArticleContentModel> list,
Function(List<String>, int)? callback,
}) {
List<String>? imgList = list
.where((item) => item.pic != null)
@@ -59,10 +60,17 @@ Widget articleContent({
tag: item.pic!.pics!.first.url!,
child: GestureDetector(
onTap: () {
context.imageView(
initialPage: imgList.indexOf(item.pic!.pics!.first.url!),
imgList: imgList,
);
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,

View File

@@ -4,12 +4,14 @@ class CustomSliverPersistentHeaderDelegate
extends SliverPersistentHeaderDelegate {
CustomSliverPersistentHeaderDelegate({
required this.child,
required this.bgColor,
double extent = 45,
}) : _minExtent = extent,
_maxExtent = extent;
final double _minExtent;
final double _maxExtent;
final Widget child;
final Color bgColor;
@override
Widget build(
@@ -17,7 +19,10 @@ class CustomSliverPersistentHeaderDelegate
//创建child子组件
//shrinkOffsetchild偏移值minExtent~maxExtent
//overlapsContentSliverPersistentHeader覆盖其他子组件返回true否则返回false
return child;
return ColoredBox(
color: bgColor,
child: child,
);
}
//SliverPersistentHeader最大高度
@@ -31,6 +36,6 @@ class CustomSliverPersistentHeaderDelegate
@override
bool shouldRebuild(
covariant CustomSliverPersistentHeaderDelegate oldDelegate) {
return false;
return oldDelegate.bgColor != bgColor;
}
}

View File

@@ -1,5 +1,5 @@
import 'package:flutter/material.dart';
import 'package:PiliPalaX/utils/storage.dart';
import 'package:PiliPlus/utils/storage.dart';
class CustomToast extends StatelessWidget {
const CustomToast({super.key, required this.msg});
@@ -25,7 +25,7 @@ class CustomToast extends StatelessWidget {
msg,
style: TextStyle(
fontSize: 13,
color: Theme.of(context).colorScheme.primary,
color: Theme.of(context).colorScheme.onPrimaryContainer,
),
),
);

View File

@@ -1,4 +1,4 @@
import 'package:PiliPalaX/utils/extension.dart';
import 'package:PiliPlus/utils/extension.dart';
import 'package:flutter/material.dart';
import 'package:flutter_html/flutter_html.dart';
import 'network_img_layer.dart';
@@ -9,6 +9,7 @@ Widget htmlRender({
int? imgCount,
List<String>? imgList,
required double constrainedWidth,
Function(List<String>, int)? callback,
}) {
return SelectionArea(
child: Html(
@@ -49,9 +50,13 @@ Widget htmlRender({
tag: imgUrl,
child: GestureDetector(
onTap: () {
context.imageView(
imgList: [imgUrl],
);
if (callback != null) {
callback([imgUrl], 0);
} else {
context.imageView(
imgList: [imgUrl],
);
}
},
child: NetworkImgLayer(
width: isEmote ? 22 : constrainedWidth,

View File

@@ -7,6 +7,7 @@ class HttpError extends StatelessWidget {
this.errMsg,
this.callback,
this.btnText,
this.extraWidget,
super.key,
});
@@ -14,6 +15,7 @@ class HttpError extends StatelessWidget {
final String? errMsg;
final Function()? callback;
final String? btnText;
final Widget? extraWidget;
@override
Widget build(BuildContext context) {
@@ -44,8 +46,13 @@ class HttpError extends StatelessWidget {
style: Theme.of(context).textTheme.titleSmall,
),
),
if (extraWidget != null) ...[
const SizedBox(height: 10),
extraWidget!,
const SizedBox(height: 5),
],
if (callback != null) ...[
const SizedBox(height: 20),
if (extraWidget == null) const SizedBox(height: 20),
FilledButton.tonal(
onPressed: callback,
style: ButtonStyle(

View File

@@ -6,6 +6,7 @@ Widget iconButton({
required IconData icon,
required VoidCallback? onPressed,
double size = 36,
double? iconSize,
Color? bgColor,
Color? iconColor,
}) {
@@ -17,7 +18,7 @@ Widget iconButton({
onPressed: onPressed,
icon: Icon(
icon,
size: size / 2,
size: iconSize ?? size / 2,
color: iconColor ?? Theme.of(context).colorScheme.onSecondaryContainer,
),
style: IconButton.styleFrom(

View File

@@ -1,8 +1,8 @@
import 'dart:math';
import 'package:PiliPalaX/common/constants.dart';
import 'package:PiliPalaX/common/widgets/network_img_layer.dart';
import 'package:PiliPalaX/utils/download.dart';
import 'package:PiliPlus/common/constants.dart';
import 'package:PiliPlus/common/widgets/network_img_layer.dart';
import 'package:PiliPlus/utils/download.dart';
import 'package:flutter/material.dart';
import 'package:flutter_smart_dialog/flutter_smart_dialog.dart';
import 'package:get/get.dart';

View File

@@ -1,9 +1,9 @@
import 'dart:math';
import 'package:PiliPalaX/common/widgets/badge.dart';
import 'package:PiliPalaX/common/widgets/network_img_layer.dart';
import 'package:PiliPalaX/common/widgets/nine_grid_view.dart';
import 'package:PiliPalaX/utils/extension.dart';
import 'package:PiliPlus/common/widgets/badge.dart';
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:flutter/material.dart';
class ImageModel {
@@ -25,10 +25,11 @@ class ImageModel {
Widget imageview(
double maxWidth,
List<ImageModel> picArr, [
List<ImageModel> picArr, {
VoidCallback? onViewImage,
ValueChanged<int>? onDismissed,
]) {
Function(List<String>, int)? callback,
}) {
double imageWidth = (maxWidth - 2 * 5) / 3;
double imageHeight = imageWidth;
if (picArr.length == 1) {
@@ -59,12 +60,16 @@ Widget imageview(
tag: picArr[index].url,
child: GestureDetector(
onTap: () {
onViewImage?.call();
context.imageView(
initialPage: index,
imgList: picArr.map((item) => item.url).toList(),
onDismissed: onDismissed,
);
if (callback != null) {
callback(picArr.map((item) => item.url).toList(), index);
} else {
onViewImage?.call();
context.imageView(
initialPage: index,
imgList: picArr.map((item) => item.url).toList(),
onDismissed: onDismissed,
);
}
},
child: Stack(
alignment: Alignment.center,

View File

@@ -1,9 +1,10 @@
import 'dart:io';
import 'package:PiliPalaX/utils/download.dart';
import 'package:PiliPalaX/utils/extension.dart';
import 'package:PiliPalaX/utils/storage.dart';
import 'package:PiliPalaX/utils/utils.dart';
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:flutter/material.dart';
@@ -42,8 +43,11 @@ class InteractiveviewerGallery<T> extends StatefulWidget {
this.minScale = 1.0,
this.onPageChanged,
this.onDismissed,
this.setStatusBar,
});
final bool? setStatusBar;
/// The sources to show.
final List<String> sources;
@@ -108,7 +112,9 @@ class _InteractiveviewerGalleryState extends State<InteractiveviewerGallery>
});
currentIndex = widget.initIndex;
setStatusBar();
if (widget.setStatusBar != false) {
setStatusBar();
}
}
setStatusBar() async {
@@ -125,8 +131,10 @@ class _InteractiveviewerGalleryState extends State<InteractiveviewerGallery>
_pageController?.dispose();
_animationController.removeListener(() {});
_animationController.dispose();
if (Platform.isIOS || Platform.isAndroid) {
StatusBarControl.setHidden(false, animation: StatusBarAnimation.FADE);
if (widget.setStatusBar != false) {
if (Platform.isIOS || Platform.isAndroid) {
StatusBarControl.setHidden(false, animation: StatusBarAnimation.FADE);
}
}
for (int index = 0; index < widget.sources.length; index++) {
CachedNetworkImageProvider(_getActualUrl(index)).evict();
@@ -355,7 +363,7 @@ class _InteractiveviewerGalleryState extends State<InteractiveviewerGallery>
// 图片分享
void onShareImg(String imgUrl) async {
SmartDialog.showLoading();
var response = await Dio()
var response = await Request()
.get(imgUrl, options: Options(responseType: ResponseType.bytes));
final temp = await getTemporaryDirectory();
SmartDialog.dismiss();

View File

@@ -1,12 +1,12 @@
import 'dart:async';
import 'dart:math';
import 'package:PiliPalaX/common/constants.dart';
import 'package:PiliPalaX/common/widgets/icon_button.dart';
import 'package:PiliPalaX/common/widgets/network_img_layer.dart';
import 'package:PiliPalaX/http/video.dart';
import 'package:PiliPalaX/models/bangumi/info.dart' as bangumi;
import 'package:PiliPalaX/models/video_detail_res.dart' as video;
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';
@@ -79,15 +79,17 @@ class _ListSheetContentState extends State<ListSheetContent>
if (this.currentIndex != currentIndex) {
this.currentIndex = currentIndex;
try {
itemScrollController[_index].jumpTo(index: currentIndex);
itemScrollController[_index].jumpTo(
index: currentIndex,
);
} catch (_) {}
}
}
// jump to current
if (_ctr != null && widget.index != _ctr?.index) {
_ctr?.animateTo(_index);
Future.delayed(const Duration(milliseconds: 255)).then((_) {
_ctr?.animateTo(_index, duration: const Duration(milliseconds: 200));
Future.delayed(const Duration(milliseconds: 300)).then((_) {
jumpToCurrent();
});
} else {

View File

@@ -1,4 +1,4 @@
import 'package:PiliPalaX/common/widgets/http_error.dart';
import 'package:PiliPlus/common/widgets/http_error.dart';
import 'package:flutter/material.dart';
Widget get loadingWidget => Center(child: CircularProgressIndicator());
@@ -8,3 +8,12 @@ Widget errorWidget({errMsg, callback}) => HttpError(
errMsg: errMsg,
callback: callback,
);
Widget scrollErrorWidget({errMsg, callback}) => CustomScrollView(
slivers: [
HttpError(
errMsg: errMsg,
callback: callback,
)
],
);

View File

@@ -1,7 +1,7 @@
import 'package:cached_network_image/cached_network_image.dart';
import 'package:flutter/material.dart';
import 'package:PiliPalaX/utils/extension.dart';
import 'package:PiliPalaX/utils/global_data.dart';
import 'package:PiliPlus/utils/extension.dart';
import 'package:PiliPlus/utils/global_data.dart';
import '../constants.dart';
class NetworkImgLayer extends StatelessWidget {
@@ -79,8 +79,8 @@ class NetworkImgLayer extends StatelessWidget {
fadeInDuration:
fadeInDuration ?? const Duration(milliseconds: 120),
filterQuality: FilterQuality.low,
errorWidget: (BuildContext context, String url, Object error) =>
placeholder(context),
// errorWidget: (BuildContext context, String url, Object error) =>
// placeholder(context),
placeholder: (BuildContext context, String url) =>
placeholder(context),
imageBuilder: imageBuilder,

View File

@@ -1,6 +1,6 @@
import 'dart:math';
import 'package:PiliPalaX/grpc/app/card/v1/card.pb.dart' as card;
import 'package:PiliPlus/grpc/app/card/v1/card.pb.dart' as card;
import 'package:flutter/material.dart';
import 'package:get/get.dart';
import '../../utils/download.dart';

View File

@@ -40,7 +40,7 @@ class SegmentProgressBar extends CustomPainter {
if (segmentEnd > segmentStart ||
(segmentEnd == segmentStart && segmentStart > 0)) {
if (segmentColors[i].title != null) {
double fontSize = 8;
double fontSize = 10;
TextPainter getTextPainter() => TextPainter(
text: TextSpan(
@@ -65,7 +65,7 @@ class SegmentProgressBar extends CustomPainter {
double width = i == 0 ? segmentStart : segmentStart - prevStart;
while (textPainter.width > width - 2 && fontSize >= 2) {
fontSize -= 1;
fontSize -= 0.5;
textPainter = getTextPainter();
}

View File

@@ -1,5 +1,5 @@
import 'package:flutter/material.dart';
import 'package:PiliPalaX/utils/utils.dart';
import 'package:PiliPlus/utils/utils.dart';
Widget statDanMu({
required BuildContext context,

View File

@@ -1,5 +1,5 @@
import 'package:flutter/material.dart';
import 'package:PiliPalaX/utils/utils.dart';
import 'package:PiliPlus/utils/utils.dart';
Widget statView({
required BuildContext context,

View File

@@ -1,4 +1,5 @@
import 'package:PiliPalaX/common/widgets/image_save.dart';
import 'package:PiliPlus/common/widgets/image_save.dart';
import 'package:PiliPlus/models/model_hot_video_item.dart';
import 'package:flutter/material.dart';
import 'package:flutter_smart_dialog/flutter_smart_dialog.dart';
import 'package:get/get.dart';
@@ -41,7 +42,6 @@ class VideoCardH extends StatelessWidget {
try {
type = videoItem.type;
} catch (_) {}
final String heroTag = Utils.makeHeroTag(aid);
return Stack(children: [
Semantics(
label: Utils.videoItemSemantics(videoItem),
@@ -78,11 +78,22 @@ class VideoCardH extends StatelessWidget {
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': heroTag});
Get.toNamed(
'/video?bvid=$bvid&cid=$cid',
arguments: {
'videoItem': videoItem,
'heroTag': Utils.makeHeroTag(aid)
},
);
} catch (err) {
SmartDialog.showToast(err.toString());
}
@@ -105,14 +116,18 @@ class VideoCardH extends StatelessWidget {
final double maxHeight = boxConstraints.maxHeight;
return Stack(
children: [
Hero(
tag: heroTag,
child: NetworkImgLayer(
src: videoItem.pic as String,
width: maxWidth,
height: maxHeight,
),
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!),

View File

@@ -1,6 +1,6 @@
import 'package:PiliPalaX/common/widgets/image_save.dart';
import 'package:PiliPalaX/grpc/app/card/v1/card.pb.dart' as card;
import 'package:PiliPalaX/utils/app_scheme.dart';
import 'package:PiliPlus/common/widgets/image_save.dart';
import 'package:PiliPlus/grpc/app/card/v1/card.pb.dart' as card;
import 'package:PiliPlus/utils/app_scheme.dart';
import 'package:flutter/material.dart';
import 'package:flutter_smart_dialog/flutter_smart_dialog.dart';
import '../../utils/utils.dart';
@@ -59,13 +59,6 @@ class VideoCardHGrpc extends StatelessWidget {
}
try {
PiliScheme.routePush(Uri.parse(videoItem.smallCoverV5.base.uri));
// final int cid =
// videoItem.smallCoverV5.base.playerArgs.cid.toInt() ??
// await SearchHttp.ab2c(aid: aid, bvid: bvid);
// Get.toNamed('/video?bvid=$bvid&cid=$cid',
// arguments: {'heroTag': heroTag});
// Get.toNamed('/video?bvid=$bvid&cid=$cid',
// arguments: {'videoItem': videoItem, 'heroTag': heroTag});
} catch (err) {
SmartDialog.showToast(err.toString());
}

View File

@@ -1,8 +1,8 @@
import 'package:PiliPalaX/common/widgets/image_save.dart';
import 'package:PiliPalaX/common/widgets/stat/danmu.dart';
import 'package:PiliPalaX/common/widgets/stat/view.dart';
import 'package:PiliPalaX/common/widgets/video_popup_menu.dart';
import 'package:PiliPalaX/models/space_archive/item.dart';
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/video_popup_menu.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';
@@ -27,7 +27,6 @@ class VideoCardHMemberVideo extends StatelessWidget {
Widget build(BuildContext context) {
final int aid = int.tryParse(videoItem.param ?? '') ?? -1;
final String bvid = videoItem.bvid ?? '';
final String heroTag = Utils.makeHeroTag(aid);
return Stack(
children: [
InkWell(
@@ -41,9 +40,18 @@ class VideoCardHMemberVideo extends StatelessWidget {
onTap!();
return;
}
if (videoItem.isPgc == true && videoItem.uri?.isNotEmpty == true) {
if (Utils.viewPgcFromUri(videoItem.uri!)) {
return;
}
}
try {
Get.toNamed('/video?bvid=$bvid&cid=${videoItem.firstCid}',
arguments: {'heroTag': heroTag});
Get.toNamed(
'/video?bvid=$bvid&cid=${videoItem.firstCid}',
arguments: {
'heroTag': Utils.makeHeroTag(aid),
},
);
} catch (err) {
SmartDialog.showToast(err.toString());
}
@@ -68,14 +76,11 @@ class VideoCardHMemberVideo extends StatelessWidget {
final double maxHeight = boxConstraints.maxHeight;
return Stack(
children: [
Hero(
tag: heroTag,
child: NetworkImgLayer(
src: videoItem.cover,
// videoItem.season?['cover'] ?? videoItem.cover,
width: maxWidth,
height: maxHeight,
),
NetworkImgLayer(
src: videoItem.cover,
// videoItem.season?['cover'] ?? videoItem.cover,
width: maxWidth,
height: maxHeight,
),
// if (videoItem.season != null)
// PBadge(

View File

@@ -1,5 +1,5 @@
import 'package:PiliPalaX/common/widgets/image_save.dart';
import 'package:PiliPalaX/http/search.dart';
import 'package:PiliPlus/common/widgets/image_save.dart';
import 'package:PiliPlus/http/search.dart';
import 'package:flutter/material.dart';
import 'package:flutter_smart_dialog/flutter_smart_dialog.dart';
import 'package:get/get.dart';
@@ -35,12 +35,11 @@ class VideoCardV extends StatelessWidget {
String goto = videoItem.goto;
switch (goto) {
case 'bangumi':
if (videoItem.bangumiBadge == '电影') {
SmartDialog.showToast('暂不支持电影观看');
return;
}
int epId = videoItem.param;
Utils.viewBangumi(epId: epId);
// 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();
@@ -81,11 +80,14 @@ class VideoCardV extends StatelessWidget {
if (cid == -1) {
cid = await SearchHttp.ab2c(aid: videoItem.aid, bvid: bvid);
}
Get.toNamed('/video?bvid=$bvid&cid=$cid', arguments: {
// 'videoItem': videoItem,
'pic': videoItem.pic,
'heroTag': heroTag,
});
Get.toNamed(
'/video?bvid=$bvid&cid=$cid',
arguments: {
// 'videoItem': videoItem,
'pic': videoItem.pic,
'heroTag': heroTag,
},
);
break;
// 动态
case 'picture':
@@ -145,7 +147,6 @@ class VideoCardV extends StatelessWidget {
@override
Widget build(BuildContext context) {
String heroTag = Utils.makeHeroTag(videoItem.id);
return Stack(children: [
Semantics(
label: Utils.videoItemSemantics(videoItem),
@@ -158,7 +159,7 @@ class VideoCardV extends StatelessWidget {
clipBehavior: Clip.hardEdge,
margin: EdgeInsets.zero,
child: InkWell(
onTap: () async => onPushDetail(heroTag),
onTap: () => onPushDetail(Utils.makeHeroTag(videoItem.id)),
onLongPress: () => imageSaveDialog(
context: context,
title: videoItem.title,
@@ -173,13 +174,10 @@ class VideoCardV extends StatelessWidget {
double maxHeight = boxConstraints.maxHeight;
return Stack(
children: [
Hero(
tag: heroTag,
child: NetworkImgLayer(
src: videoItem.pic,
width: maxWidth,
height: maxHeight,
),
NetworkImgLayer(
src: videoItem.pic,
width: maxWidth,
height: maxHeight,
),
if (videoItem.duration > 0)
PBadge(

View File

@@ -1,5 +1,5 @@
import 'package:PiliPalaX/common/widgets/image_save.dart';
import 'package:PiliPalaX/models/space/item.dart';
import 'package:PiliPlus/common/widgets/image_save.dart';
import 'package:PiliPlus/models/space/item.dart';
import 'package:flutter/material.dart';
import 'package:flutter_smart_dialog/flutter_smart_dialog.dart';
import 'package:get/get.dart';
@@ -20,13 +20,13 @@ class VideoCardVMemberHome extends StatelessWidget {
void onPushDetail(heroTag) async {
String goto = videoItem.goto ?? '';
switch (goto) {
// case 'bangumi':
// if (videoItem.bangumiBadge == '电影') {
// SmartDialog.showToast('暂不支持电影观看');
// return;
// }
// int epId = videoItem.param;
// Utils.viewBangumi(epId: epId);
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);
@@ -63,12 +63,20 @@ class VideoCardVMemberHome extends StatelessWidget {
// }
// 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}', arguments: {
// 'videoItem': videoItem,
'pic': videoItem.cover,
'heroTag': heroTag,
});
Get.toNamed(
'/video?bvid=$bvid&cid=${videoItem.firstCid}',
arguments: {
// 'videoItem': videoItem,
'pic': videoItem.cover,
'heroTag': heroTag,
},
);
break;
// 动态
// case 'picture':
@@ -128,7 +136,6 @@ class VideoCardVMemberHome extends StatelessWidget {
@override
Widget build(BuildContext context) {
String heroTag = Utils.makeHeroTag(videoItem.bvid);
// List<VideoCustomAction> actions =
// VideoCustomActions(videoItem, context).actions;
return Stack(children: [
@@ -143,7 +150,7 @@ class VideoCardVMemberHome extends StatelessWidget {
clipBehavior: Clip.hardEdge,
margin: EdgeInsets.zero,
child: InkWell(
onTap: () async => onPushDetail(heroTag),
onTap: () => onPushDetail(Utils.makeHeroTag(videoItem.bvid)),
onLongPress: () => imageSaveDialog(
context: context,
title: videoItem.title,
@@ -158,13 +165,10 @@ class VideoCardVMemberHome extends StatelessWidget {
double maxHeight = boxConstraints.maxHeight;
return Stack(
children: [
Hero(
tag: heroTag,
child: NetworkImgLayer(
src: videoItem.cover,
width: maxWidth,
height: maxHeight,
),
NetworkImgLayer(
src: videoItem.cover,
width: maxWidth,
height: maxHeight,
),
if ((videoItem.duration ?? -1) > 0)
PBadge(

View File

@@ -1,5 +1,5 @@
import 'package:PiliPalaX/pages/search/widgets/search_text.dart';
import 'package:PiliPalaX/utils/utils.dart';
import 'package:PiliPlus/pages/search/widgets/search_text.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';
@@ -10,7 +10,7 @@ import '../../http/video.dart';
import '../../models/home/rcmd/result.dart';
import '../../pages/mine/controller.dart';
import '../../utils/storage.dart';
import 'package:PiliPalaX/models/space_archive/item.dart';
import 'package:PiliPlus/models/space_archive/item.dart';
class VideoCustomAction {
String title;

View File

@@ -1,8 +1,8 @@
import 'package:PiliPalaX/grpc/app/dynamic/v1/dynamic.pbgrpc.dart' as v1;
import 'package:PiliPalaX/grpc/app/dynamic/v2/dynamic.pbgrpc.dart' as v2;
import 'package:PiliPalaX/grpc/app/main/community/reply/v1/reply.pbgrpc.dart';
import 'package:PiliPalaX/grpc/app/playeronline/v1/playeronline.pbgrpc.dart';
import 'package:PiliPalaX/grpc/app/show/popular/v1/popular.pbgrpc.dart';
import 'package:PiliPlus/grpc/app/dynamic/v1/dynamic.pbgrpc.dart' as v1;
import 'package:PiliPlus/grpc/app/dynamic/v2/dynamic.pbgrpc.dart' as v2;
import 'package:PiliPlus/grpc/app/main/community/reply/v1/reply.pbgrpc.dart';
import 'package:PiliPlus/grpc/app/playeronline/v1/playeronline.pbgrpc.dart';
import 'package:PiliPlus/grpc/app/show/popular/v1/popular.pbgrpc.dart';
import 'package:grpc/grpc.dart';
class GrpcClient {

View File

@@ -1,21 +1,21 @@
import 'dart:convert';
import 'package:PiliPalaX/common/constants.dart';
import 'package:PiliPalaX/grpc/app/dynamic/v1/dynamic.pb.dart';
import 'package:PiliPalaX/grpc/app/dynamic/v2/dynamic.pb.dart';
import 'package:PiliPalaX/grpc/app/main/community/reply/v1/reply.pb.dart';
import 'package:PiliPalaX/grpc/app/playeronline/v1/playeronline.pbgrpc.dart';
import 'package:PiliPalaX/grpc/app/show/popular/v1/popular.pb.dart';
import 'package:PiliPalaX/grpc/device/device.pb.dart';
import 'package:PiliPalaX/grpc/fawkes/fawkes.pb.dart';
import 'package:PiliPalaX/grpc/grpc_client.dart';
import 'package:PiliPalaX/grpc/locale/locale.pb.dart';
import 'package:PiliPalaX/grpc/metadata/metadata.pb.dart';
import 'package:PiliPalaX/grpc/network/network.pb.dart' as network;
import 'package:PiliPalaX/grpc/restriction/restriction.pb.dart';
import 'package:PiliPalaX/utils/login.dart';
import 'package:PiliPalaX/utils/storage.dart';
import 'package:PiliPalaX/utils/utils.dart';
import 'package:PiliPlus/common/constants.dart';
import 'package:PiliPlus/grpc/app/dynamic/v1/dynamic.pb.dart';
import 'package:PiliPlus/grpc/app/dynamic/v2/dynamic.pb.dart';
import 'package:PiliPlus/grpc/app/main/community/reply/v1/reply.pb.dart';
import 'package:PiliPlus/grpc/app/playeronline/v1/playeronline.pbgrpc.dart';
import 'package:PiliPlus/grpc/app/show/popular/v1/popular.pb.dart';
import 'package:PiliPlus/grpc/device/device.pb.dart';
import 'package:PiliPlus/grpc/fawkes/fawkes.pb.dart';
import 'package:PiliPlus/grpc/grpc_client.dart';
import 'package:PiliPlus/grpc/locale/locale.pb.dart';
import 'package:PiliPlus/grpc/metadata/metadata.pb.dart';
import 'package:PiliPlus/grpc/network/network.pb.dart' as network;
import 'package:PiliPlus/grpc/restriction/restriction.pb.dart';
import 'package:PiliPlus/utils/login.dart';
import 'package:PiliPlus/utils/storage.dart';
import 'package:PiliPlus/utils/utils.dart';
import 'package:fixnum/src/int64.dart';
import 'package:flutter/material.dart';
import 'package:grpc/grpc.dart';

View File

@@ -390,9 +390,8 @@ class Api {
static const String bangumiList =
'/pgc/season/index/result?st=1&order=3&season_version=-1&spoken_language_type=-1&area=-1&is_finish=-1&copyright=-1&season_status=-1&season_month=-1&year=-1&style_id=-1&sort=0&season_type=1&pagesize=20&type=1';
// 我的订阅
static const String bangumiFollow =
'/x/space/bangumi/follow/list?type=1&follow_status=0&pn=1&ps=15&ts=1691544359969';
// 我的追番/追剧 ?type=1&pn=1&ps=15
static const String bangumiFollow = '/x/space/bangumi/follow/list';
// 黑名单
static const String blackLst = '/x/relation/blacks';
@@ -402,7 +401,7 @@ class Api {
// github 获取最新版
static const String latestApp =
'https://api.github.com/repos/orz12/pilipala/releases';
'https://api.github.com/repos/bggRGjQaUbCoE/PiliPlus/releases';
// 多少人在看
// https://api.bilibili.com/x/player/online/total?aid=913663681&cid=1203559746&bvid=BV1MM4y1s7NZ&ts=56427838
@@ -444,6 +443,11 @@ class Api {
// 获取指定分组下的up
static const String followUpGroup = '/x/relation/tag';
// 获取未读私信数
// https://api.vc.bilibili.com/session_svr/v1/session_svr/single_unread
static const String msgUnread =
'${HttpString.tUrl}/session_svr/v1/session_svr/single_unread';
// 获取消息中心未读信息
static const String msgFeedUnread = '/x/msgfeed/unread';
//https://api.bilibili.com/x/msgfeed/reply?platform=web&build=0&mobi_app=web

View File

@@ -1,12 +1,17 @@
import 'package:PiliPalaX/http/loading_state.dart';
import 'package:PiliPlus/http/loading_state.dart';
import '../models/bangumi/list.dart';
import 'index.dart';
class BangumiHttp {
static Future<LoadingState> bangumiList({int? page}) async {
var res =
await Request().get(Api.bangumiList, queryParameters: {'page': page});
static Future<LoadingState> bangumiList({
int? page,
int? indexType,
}) async {
var res = await Request().get(Api.bangumiList, queryParameters: {
'page': page,
if (indexType != null) 'index_type': indexType,
});
if (res.data['code'] == 0) {
BangumiListDataModel data =
BangumiListDataModel.fromJson(res.data['data']);
@@ -16,13 +21,20 @@ class BangumiHttp {
}
}
static Future<LoadingState> bangumiFollow({int? mid}) async {
var res =
await Request().get(Api.bangumiFollow, queryParameters: {'vmid': mid});
static Future<LoadingState> bangumiFollow({
dynamic mid,
required int type,
required int pn,
}) async {
var res = await Request().get(Api.bangumiFollow, queryParameters: {
'vmid': mid,
'type': type,
'pn': pn,
});
if (res.data['code'] == 0) {
BangumiListDataModel data =
BangumiListDataModel.fromJson(res.data['data']);
return LoadingState.success(data.list);
return LoadingState.success(data);
} else {
return LoadingState.error(res.data['message']);
}

View File

@@ -1,4 +1,4 @@
import 'package:PiliPalaX/http/loading_state.dart';
import 'package:PiliPlus/http/loading_state.dart';
import '../models/user/black.dart';
import 'index.dart';

View File

@@ -29,8 +29,8 @@ class DanmakaHttp {
int type = 1, //弹幕类选择(1视频弹幕 2漫画弹幕)
required int oid, // 视频cid
required String msg, //弹幕文本(长度小于 100 字符)
int mode =
1, // 弹幕类型(1滚动弹幕 4底端弹幕 5顶端弹幕 6逆向弹幕(不能使用) 7高级弹幕 8代码弹幕不能使用 9BAS弹幕pool必须为2)
// 弹幕类型(1滚动弹幕 4底端弹幕 5顶端弹幕 6逆向弹幕(不能使用) 7高级弹幕 8代码弹幕不能使用 9BAS弹幕pool必须为2)
int mode = 1,
// String? aid,// 稿件avid
// String? bvid,// bvid与aid必须有一个
required String bvid,
@@ -47,7 +47,6 @@ class DanmakaHttp {
// 构建参数对象
// assert(aid != null || bvid != null);
// assert(csrf != null || access_key != null);
assert(msg.length < 100);
// 构建参数对象
var params = <String, dynamic>{
'type': type,

View File

@@ -1,4 +1,4 @@
import 'package:PiliPalaX/http/loading_state.dart';
import 'package:PiliPlus/http/loading_state.dart';
import '../models/dynamics/result.dart';
import '../models/dynamics/up.dart';

View File

@@ -1,4 +1,4 @@
import 'package:PiliPalaX/http/loading_state.dart';
import 'package:PiliPlus/http/loading_state.dart';
import '../models/fans/result.dart';
import 'index.dart';

View File

@@ -1,6 +1,6 @@
import 'dart:convert';
import 'package:PiliPalaX/models/dynamics/article_content_model.dart';
import 'package:PiliPlus/models/dynamics/article_content_model.dart';
import 'package:dio/dio.dart';
import 'package:flutter/material.dart';
import 'package:html/dom.dart' as dom;

View File

@@ -8,7 +8,7 @@ import 'package:dio/dio.dart';
import 'package:dio/io.dart';
import 'package:dio_cookie_manager/dio_cookie_manager.dart';
import 'package:flutter/material.dart';
import 'package:PiliPalaX/utils/id_utils.dart';
import 'package:PiliPlus/utils/id_utils.dart';
import '../utils/storage.dart';
import '../utils/utils.dart';
import 'api.dart';

View File

@@ -1,5 +1,3 @@
// ignore_for_file: avoid_print
import 'package:connectivity_plus/connectivity_plus.dart';
import 'package:dio/dio.dart';
import 'package:flutter/material.dart';
@@ -46,10 +44,13 @@ class ApiInterceptor extends Interceptor {
// handler.next(err);
String url = err.requestOptions.uri.toString();
debugPrint('🌹🌹ApiInterceptor: $url');
// 屏蔽弹幕、心跳、人数请求的错误提示
if (!url.contains('heartbeat') &&
!url.contains('seg.so') &&
!url.contains('online/total')) {
if (url.contains('heartbeat') ||
url.contains('seg.so') ||
url.contains('online/total') ||
url.contains('github') ||
(url.contains('skipSegments') && err.requestOptions.method == 'GET')) {
// skip
} else {
SmartDialog.showToast(
await dioError(err) + url,
displayType: SmartToastType.onlyRefresh,

View File

@@ -1,6 +1,6 @@
import 'package:PiliPalaX/common/constants.dart';
import 'package:PiliPalaX/http/loading_state.dart';
import 'package:PiliPalaX/models/live/danmu_info.dart';
import 'package:PiliPlus/common/constants.dart';
import 'package:PiliPlus/http/loading_state.dart';
import 'package:PiliPlus/models/live/danmu_info.dart';
import 'package:dio/dio.dart';
import '../models/live/item.dart';
import '../models/live/room_info.dart';

View File

@@ -1,14 +1,14 @@
import 'dart:convert';
import 'package:PiliPalaX/common/constants.dart';
import 'package:PiliPalaX/grpc/grpc_repo.dart';
import 'package:PiliPalaX/http/constants.dart';
import 'package:PiliPalaX/http/loading_state.dart';
import 'package:PiliPalaX/models/space/data.dart';
import 'package:PiliPalaX/models/space_fav/space_fav.dart';
import 'package:PiliPalaX/pages/member/new/content/member_contribute/member_contribute.dart'
import 'package:PiliPlus/common/constants.dart';
import 'package:PiliPlus/grpc/grpc_repo.dart';
import 'package:PiliPlus/http/constants.dart';
import 'package:PiliPlus/http/loading_state.dart';
import 'package:PiliPlus/models/space/data.dart';
import 'package:PiliPlus/models/space_fav/space_fav.dart';
import 'package:PiliPlus/pages/member/new/content/member_contribute/member_contribute.dart'
show ContributeType;
import 'package:PiliPalaX/utils/storage.dart';
import 'package:PiliPlus/utils/storage.dart';
import 'package:dio/dio.dart';
import 'package:flutter/material.dart';

View File

@@ -1,6 +1,6 @@
import 'dart:math';
import 'package:PiliPalaX/http/constants.dart';
import 'package:PiliPalaX/pages/dynamics/view.dart' show ReplyOption;
import 'package:PiliPlus/http/constants.dart';
import 'package:PiliPlus/pages/dynamics/view.dart' show ReplyOption;
import 'package:dio/dio.dart';
import 'package:flutter/material.dart';

View File

@@ -1,9 +1,10 @@
import 'dart:io';
import 'package:PiliPalaX/grpc/app/main/community/reply/v1/reply.pb.dart';
import 'package:PiliPalaX/grpc/grpc_repo.dart';
import 'package:PiliPalaX/http/loading_state.dart';
import 'package:PiliPalaX/utils/storage.dart';
import 'package:PiliPlus/grpc/app/main/community/reply/v1/reply.pb.dart';
import 'package:PiliPlus/grpc/grpc_repo.dart';
import 'package:PiliPlus/http/loading_state.dart';
import 'package:PiliPlus/utils/extension.dart';
import 'package:PiliPlus/utils/storage.dart';
import 'package:dio/dio.dart';
import '../models/video/reply/data.dart';
@@ -49,7 +50,44 @@ class ReplyHttp {
options: options,
);
if (res.data['code'] == 0) {
return LoadingState.success(ReplyData.fromJson(res.data['data']));
ReplyData replyData = ReplyData.fromJson(res.data['data']);
String banWordForReply = GStorage.banWordForReply;
if (banWordForReply.isNotEmpty) {
// topReplies
if (replyData.topReplies?.isNotEmpty == true) {
replyData.topReplies!.removeWhere((item) {
bool hasMatch = RegExp(banWordForReply, caseSensitive: false)
.hasMatch(item.content?.message ?? '');
// remove subreplies
if (hasMatch.not) {
if (item.replies?.isNotEmpty == true) {
item.replies!.removeWhere((item) =>
RegExp(banWordForReply, caseSensitive: false)
.hasMatch(item.content?.message ?? ''));
}
}
return hasMatch;
});
}
// replies
if (replyData.replies?.isNotEmpty == true) {
replyData.replies!.removeWhere((item) {
bool hasMatch = RegExp(banWordForReply, caseSensitive: false)
.hasMatch(item.content?.message ?? '');
// remove subreplies
if (hasMatch.not) {
if (item.replies?.isNotEmpty == true) {
item.replies!.removeWhere((item) =>
RegExp(banWordForReply, caseSensitive: false)
.hasMatch(item.content?.message ?? ''));
}
}
return hasMatch;
});
}
}
return LoadingState.success(replyData);
} else {
return LoadingState.error(res.data['message']);
}
@@ -62,7 +100,34 @@ class ReplyHttp {
}) async {
dynamic res = await GrpcRepo.mainList(type: type, oid: oid, cursor: cursor);
if (res['status']) {
return LoadingState.success(res['data']);
MainListReply mainListReply = res['data'];
String banWordForReply = GStorage.banWordForReply;
if (banWordForReply.isNotEmpty) {
// upTop
if (mainListReply.hasUpTop() &&
RegExp(banWordForReply, caseSensitive: false)
.hasMatch(mainListReply.upTop.content.message)) {
mainListReply.clearUpTop();
}
// replies
if (mainListReply.replies.isNotEmpty) {
mainListReply.replies.removeWhere((item) {
bool hasMatch = RegExp(banWordForReply, caseSensitive: false)
.hasMatch(item.content.message);
// remove subreplies
if (hasMatch.not) {
if (item.replies.isNotEmpty) {
item.replies.removeWhere((item) =>
RegExp(banWordForReply, caseSensitive: false)
.hasMatch(item.content.message));
}
}
return hasMatch;
});
}
}
return LoadingState.success(mainListReply);
} else {
return LoadingState.error(
'${res['msg'].startsWith('gRPC Error') ? '如无法加载评论:\n关闭代理\n或设置中关闭使用gRPC加载评论\n\n' : ''}${res['msg']}');
@@ -93,33 +158,21 @@ class ReplyHttp {
options: options,
);
if (res.data['code'] == 0) {
return LoadingState.success(ReplyReplyData.fromJson(res.data['data']));
ReplyReplyData replyData = ReplyReplyData.fromJson(res.data['data']);
String banWordForReply = GStorage.banWordForReply;
if (banWordForReply.isNotEmpty) {
if (replyData.replies?.isNotEmpty == true) {
replyData.replies!.removeWhere((item) =>
RegExp(banWordForReply, caseSensitive: false)
.hasMatch(item.content?.message ?? ''));
}
}
return LoadingState.success(replyData);
} else {
return LoadingState.error(res.data['message']);
}
}
static Future<LoadingState> dialogListGrpc({
int type = 1,
required int oid,
required int root,
required int rpid,
required CursorReq cursor,
}) async {
dynamic res = await GrpcRepo.dialogList(
type: type,
oid: oid,
root: root,
rpid: rpid,
cursor: cursor,
);
if (res['status']) {
return LoadingState.success(res['data']);
} else {
return LoadingState.error(res['msg']);
}
}
static Future<LoadingState> replyReplyListGrpc({
int type = 1,
required int oid,
@@ -135,7 +188,46 @@ class ReplyHttp {
cursor: cursor,
);
if (res['status']) {
return LoadingState.success(res['data']);
DetailListReply detailListReply = res['data'];
String banWordForReply = GStorage.banWordForReply;
if (banWordForReply.isNotEmpty) {
if (detailListReply.root.replies.isNotEmpty) {
detailListReply.root.replies.removeWhere((item) =>
RegExp(banWordForReply, caseSensitive: false)
.hasMatch(item.content.message));
}
}
return LoadingState.success(detailListReply);
} else {
return LoadingState.error(res['msg']);
}
}
static Future<LoadingState> dialogListGrpc({
int type = 1,
required int oid,
required int root,
required int rpid,
required CursorReq cursor,
}) async {
dynamic res = await GrpcRepo.dialogList(
type: type,
oid: oid,
root: root,
rpid: rpid,
cursor: cursor,
);
if (res['status']) {
DialogListReply dialogListReply = res['data'];
String banWordForReply = GStorage.banWordForReply;
if (banWordForReply.isNotEmpty) {
if (dialogListReply.replies.isNotEmpty) {
dialogListReply.replies.removeWhere((item) =>
RegExp(banWordForReply, caseSensitive: false)
.hasMatch(item.content.message));
}
}
return LoadingState.success(dialogListReply);
} else {
return LoadingState.error(res['msg']);
}

View File

@@ -1,7 +1,7 @@
import 'dart:convert';
import 'package:flutter/material.dart';
import 'package:flutter_smart_dialog/flutter_smart_dialog.dart';
import 'package:PiliPalaX/http/loading_state.dart';
import 'package:PiliPlus/http/loading_state.dart';
import '../models/bangumi/info.dart';
import '../models/common/search_type.dart';
import '../models/search/hot.dart';
@@ -82,7 +82,7 @@ class SearchHttp {
int? pubEnd,
}) async {
var reqData = {
'search_type': searchType.type,
'search_type': searchType.name,
'keyword': keyword,
// 'order_sort': 0,
// 'user_type': 0,
@@ -117,7 +117,7 @@ class SearchHttp {
case SearchType.bili_user:
data = SearchUserModel.fromJson(res.data['data']);
break;
case SearchType.media_bangumi:
case SearchType.media_bangumi || SearchType.media_ft:
data = SearchMBangumiModel.fromJson(res.data['data']);
break;
case SearchType.article:
@@ -182,6 +182,7 @@ class SearchHttp {
}
final dynamic res = await Request()
.get(Api.bangumiInfo, queryParameters: <String, dynamic>{...data});
if (res.data['code'] == 0) {
return {
'status': true,

View File

@@ -1,5 +1,5 @@
import 'package:PiliPalaX/http/loading_state.dart';
import 'package:PiliPalaX/models/video/later.dart';
import 'package:PiliPlus/http/loading_state.dart';
import 'package:PiliPlus/models/video/later.dart';
import 'package:dio/dio.dart';
import 'package:flutter_smart_dialog/flutter_smart_dialog.dart';
import '../common/constants.dart';
@@ -48,7 +48,7 @@ class UserHttp {
static Future<LoadingState> userfavFolder({
required int pn,
required int ps,
required int mid,
required dynamic mid,
}) async {
var res = await Request().get(Api.userFavFolder, queryParameters: {
'pn': pn,

View File

@@ -1,8 +1,8 @@
import 'dart:convert';
import 'dart:developer';
import 'package:PiliPalaX/grpc/app/card/v1/card.pb.dart' as card;
import 'package:PiliPalaX/grpc/grpc_repo.dart';
import 'package:PiliPalaX/http/loading_state.dart';
import 'package:PiliPlus/grpc/app/card/v1/card.pb.dart' as card;
import 'package:PiliPlus/grpc/grpc_repo.dart';
import 'package:PiliPlus/http/loading_state.dart';
import 'package:dio/dio.dart';
import 'package:flutter/foundation.dart';
import '../common/constants.dart';
@@ -144,6 +144,12 @@ class VideoHttp {
(!enableRcmdDynamic ? i['card_goto'] != 'picture' : true) &&
(i['args'] != null &&
!blackMidsList.contains(i['args']['up_id']))) {
String banWordForZone = GStorage.banWordForZone;
if (banWordForZone.isNotEmpty &&
RegExp(banWordForZone, caseSensitive: false)
.hasMatch(i['args']['rname'])) {
continue;
}
RecVideoItemAppModel videoItem = RecVideoItemAppModel.fromJson(i);
if (!RecommendFilter.filter(videoItem)) {
list.add(videoItem);
@@ -168,7 +174,15 @@ class VideoHttp {
List<int> blackMidsList = GStorage.blackMidsList;
for (var i in res.data['data']['list']) {
if (!blackMidsList.contains(i['owner']['mid']) &&
!RecommendFilter.filterTitle(i['title'])) {
!RecommendFilter.filterTitle(i['title']) &&
!RecommendFilter.filterLikeRatio(
i['stat']['like'], i['stat']['view'])) {
String banWordForZone = GStorage.banWordForZone;
if (banWordForZone.isNotEmpty &&
RegExp(banWordForZone, caseSensitive: false)
.hasMatch(i['tname'])) {
continue;
}
list.add(HotVideoItemModel.fromJson(i));
}
}
@@ -229,13 +243,15 @@ class VideoHttp {
'web_location': 1550101,
});
late final isLogin = GStorage.isLogin;
try {
var res = await Request().get(
epid != null ? Api.bangumiVideoUrl : Api.videoUrl,
epid != null && isLogin ? Api.bangumiVideoUrl : Api.videoUrl,
queryParameters: params);
if (res.data['code'] == 0) {
late PlayUrlModel data;
if (epid != null) {
if (epid != null && isLogin) {
data = PlayUrlModel.fromJson(res.data['result']['video_info'])
..lastPlayTime = res.data['result']['play_view_business_info']
['user_status']['watch_progress']['current_watch_progress'];
@@ -918,6 +934,8 @@ class VideoHttp {
'status': true,
'data': subtitlesJson,
'view_points': data['view_points'],
// 'last_play_time': data['last_play_time'],
'last_play_cid': data['last_play_cid'],
};
} else {
return {'status': false, 'data': [], 'msg': res.data['message']};
@@ -1008,7 +1026,9 @@ class VideoHttp {
List<int> blackMidsList = GStorage.blackMidsList;
for (var i in res.data['data']['list']) {
if (!blackMidsList.contains(i['owner']['mid']) &&
!RecommendFilter.filterTitle(i['title'])) {
!RecommendFilter.filterTitle(i['title']) &&
!RecommendFilter.filterLikeRatio(
i['stat']['like'], i['stat']['view'])) {
list.add(HotVideoItemModel.fromJson(i));
}
}

View File

@@ -1,7 +1,7 @@
import 'dart:io';
import 'package:PiliPalaX/build_config.dart';
import 'package:PiliPalaX/utils/cache_manage.dart';
import 'package:PiliPlus/build_config.dart';
import 'package:PiliPlus/utils/cache_manage.dart';
import 'package:flex_seed_scheme/flex_seed_scheme.dart';
import 'package:flutter/services.dart';
import 'package:flutter_displaymode/flutter_displaymode.dart';
@@ -11,18 +11,18 @@ import 'package:get/get.dart';
import 'package:flutter/material.dart';
import 'package:dynamic_color/dynamic_color.dart';
import 'package:hive/hive.dart';
import 'package:PiliPalaX/common/widgets/custom_toast.dart';
import 'package:PiliPalaX/http/init.dart';
import 'package:PiliPalaX/models/common/color_type.dart';
import 'package:PiliPalaX/pages/video/detail/index.dart';
import 'package:PiliPalaX/router/app_pages.dart';
import 'package:PiliPalaX/pages/main/view.dart';
import 'package:PiliPalaX/services/service_locator.dart';
import 'package:PiliPalaX/utils/app_scheme.dart';
import 'package:PiliPalaX/utils/data.dart';
import 'package:PiliPalaX/utils/storage.dart';
import 'package:PiliPlus/common/widgets/custom_toast.dart';
import 'package:PiliPlus/http/init.dart';
import 'package:PiliPlus/models/common/color_type.dart';
import 'package:PiliPlus/pages/video/detail/index.dart';
import 'package:PiliPlus/router/app_pages.dart';
import 'package:PiliPlus/pages/main/view.dart';
import 'package:PiliPlus/services/service_locator.dart';
import 'package:PiliPlus/utils/app_scheme.dart';
import 'package:PiliPlus/utils/data.dart';
import 'package:PiliPlus/utils/storage.dart';
import 'package:media_kit/media_kit.dart'; // Provides [Player], [Media], [Playlist] etc.
import 'package:PiliPalaX/utils/recommend_filter.dart';
import 'package:PiliPlus/utils/recommend_filter.dart';
import 'package:catcher_2/catcher_2.dart';
import './services/loggeer.dart';
@@ -181,7 +181,7 @@ class MyApp extends StatelessWidget {
// PaintingBinding.instance.imageCache.maximumSizeBytes = 1000 << 20;
return GetMaterialApp(
// showSemanticsDebugger: true,
title: 'PiliPalaX',
title: 'PiliPlus',
theme: _getThemeData(
colorScheme: lightColorScheme,
isDynamic: lightDynamic != null && isDynamicColor,

View File

@@ -4,6 +4,8 @@ extension DynamicBadgeModeDesc on DynamicBadgeMode {
String get description => ['隐藏', '红点', '数字'][index];
}
extension DynamicBadgeModeCode on DynamicBadgeMode {
int get code => [0, 1, 2][index];
enum MsgUnReadType { pm, reply, at, like, sysMsg }
extension MsgUnReadTypeExt on MsgUnReadType {
String get title => ['私信', '回复我的', '@我', '收到的赞', '系统通知'][index];
}

View File

@@ -11,35 +11,35 @@ extension BusinessTypeExtension on DynamicsType {
String get labels => ['全部', '投稿', '番剧', '专栏', 'UP'][index];
}
List tabsConfig = [
{
'tag': 'all',
'value': DynamicsType.all,
'label': '全部',
'enabled': true,
},
{
'tag': 'video',
'value': DynamicsType.video,
'label': '投稿',
'enabled': true,
},
{
'tag': 'pgc',
'value': DynamicsType.pgc,
'label': '番剧',
'enabled': true,
},
{
'tag': 'article',
'value': DynamicsType.article,
'label': '专栏',
'enabled': true,
},
{
'tag': 'up',
'value': DynamicsType.up,
'label': 'UP',
'enabled': true,
},
];
List get tabsConfig => [
{
'tag': 'all',
'value': DynamicsType.all,
'label': '全部',
'enabled': true,
},
{
'tag': 'video',
'value': DynamicsType.video,
'label': '投稿',
'enabled': true,
},
{
'tag': 'pgc',
'value': DynamicsType.pgc,
'label': '番剧',
'enabled': true,
},
{
'tag': 'article',
'value': DynamicsType.article,
'label': '专栏',
'enabled': true,
},
{
'tag': 'up',
'value': DynamicsType.up,
'label': 'UP',
'enabled': true,
},
];

View File

@@ -1,43 +1,43 @@
import 'package:flutter/material.dart';
List defaultNavigationBars = [
{
'id': 0,
'icon': const Icon(
Icons.home_outlined,
size: 23,
),
'selectIcon': const Icon(
Icons.home,
size: 23,
),
'label': "首页",
'count': 0,
},
{
'id': 1,
'icon': const Icon(
Icons.motion_photos_on_outlined,
size: 21,
),
'selectIcon': const Icon(
Icons.motion_photos_on,
size: 21,
),
'label': "动态",
'count': 0,
},
{
'id': 2,
'icon': const Icon(
Icons.video_collection_outlined,
size: 21,
),
'selectIcon': const Icon(
Icons.video_collection,
size: 21,
),
'label': "媒体库",
'count': 0,
}
];
List get defaultNavigationBars => [
{
'id': 0,
'icon': const Icon(
Icons.home_outlined,
size: 23,
),
'selectIcon': const Icon(
Icons.home,
size: 23,
),
'label': "首页",
'count': 0,
},
{
'id': 1,
'icon': const Icon(
Icons.motion_photos_on_outlined,
size: 21,
),
'selectIcon': const Icon(
Icons.motion_photos_on,
size: 21,
),
'label': "动态",
'count': 0,
},
{
'id': 2,
'icon': const Icon(
Icons.video_collection_outlined,
size: 21,
),
'selectIcon': const Icon(
Icons.video_collection,
size: 21,
),
'label': "媒体库",
'count': 0,
}
];

View File

@@ -5,7 +5,7 @@ enum SearchType {
// 番剧media_bangumi,
media_bangumi,
// 影视media_ft
// media_ft,
media_ft,
// 直播间及主播live
// live,
// 直播间live_room
@@ -23,9 +23,7 @@ enum SearchType {
}
extension SearchTypeExtension on SearchType {
String get type =>
['video', 'media_bangumi', 'live_room', 'bili_user', 'article'][index];
String get label => ['视频', '番剧', '直播间', '用户', '专栏'][index];
String get label => ['视频', '番剧', '影视', '直播间', '用户', '专栏'][index];
}
// 搜索类型为视频、专栏及相簿时

View File

@@ -1,67 +1,77 @@
import 'package:PiliPalaX/pages/rank/index.dart';
import 'package:PiliPlus/pages/rank/index.dart';
import 'package:flutter/material.dart';
import 'package:get/get.dart';
import 'package:PiliPalaX/pages/bangumi/index.dart';
import 'package:PiliPalaX/pages/hot/index.dart';
import 'package:PiliPalaX/pages/live/index.dart';
import 'package:PiliPalaX/pages/rcmd/index.dart';
import 'package:PiliPlus/pages/bangumi/index.dart';
import 'package:PiliPlus/pages/hot/index.dart';
import 'package:PiliPlus/pages/live/index.dart';
import 'package:PiliPlus/pages/rcmd/index.dart';
import 'package:material_design_icons_flutter/material_design_icons_flutter.dart';
enum TabType { live, rcmd, hot, rank, bangumi }
enum TabType { live, rcmd, hot, rank, bangumi, cinema }
extension TabTypeDesc on TabType {
String get description => ['直播', '推荐', '热门', '分区', '番剧'][index];
String get id => ['live', 'rcmd', 'hot', 'rank', 'bangumi'][index];
String get description => ['直播', '推荐', '热门', '分区', '番剧', '影视'][index];
}
List tabsConfig = [
{
'icon': const Icon(
Icons.live_tv_outlined,
size: 15,
),
'label': '直播',
'type': TabType.live,
'ctr': Get.find<LiveController>,
'page': const RcmdPage(tabType: TabType.live),
},
{
'icon': const Icon(
Icons.thumb_up_off_alt_outlined,
size: 15,
),
'label': '推荐',
'type': TabType.rcmd,
'ctr': Get.find<RcmdController>,
'page': const RcmdPage(tabType: TabType.rcmd),
},
{
'icon': const Icon(
Icons.whatshot_outlined,
size: 15,
),
'label': '热门',
'type': TabType.hot,
'ctr': Get.find<HotController>,
'page': const HotPage(),
},
{
'icon': const Icon(
Icons.category_outlined,
size: 15,
),
'label': '分区',
'type': TabType.rank,
'ctr': Get.find<RankController>,
'page': const RankPage(),
},
{
'icon': const Icon(
Icons.play_circle_outlined,
size: 15,
),
'label': '番剧',
'type': TabType.bangumi,
'ctr': Get.find<BangumiController>,
'page': const BangumiPage(),
},
];
List get tabsConfig => [
{
'icon': const Icon(
Icons.live_tv_outlined,
size: 15,
),
'label': '直播',
'type': TabType.live,
'ctr': Get.find<LiveController>,
'page': const RcmdPage(tabType: TabType.live),
},
{
'icon': const Icon(
Icons.thumb_up_off_alt_outlined,
size: 15,
),
'label': '推荐',
'type': TabType.rcmd,
'ctr': Get.find<RcmdController>,
'page': const RcmdPage(tabType: TabType.rcmd),
},
{
'icon': const Icon(
Icons.whatshot_outlined,
size: 15,
),
'label': '热门',
'type': TabType.hot,
'ctr': Get.find<HotController>,
'page': const HotPage(),
},
{
'icon': const Icon(
Icons.category_outlined,
size: 15,
),
'label': '分区',
'type': TabType.rank,
'ctr': Get.find<RankController>,
'page': const RankPage(),
},
{
'icon': const Icon(
Icons.play_circle_outlined,
size: 15,
),
'label': '番剧',
'type': TabType.bangumi,
'ctr': Get.find<BangumiController>,
'page': const BangumiPage(tabType: TabType.bangumi),
},
{
'icon': Icon(
MdiIcons.theater,
size: 15,
),
'label': '影视',
'type': TabType.cinema,
'ctr': Get.find<BangumiController>,
'page': const BangumiPage(tabType: TabType.cinema),
},
];

View File

@@ -4,6 +4,7 @@ class FollowUpModel {
this.upList,
});
String? errMsg;
LiveUsers? liveUsers;
List<UpItem>? upList;

View File

@@ -1,4 +1,4 @@
import 'package:PiliPalaX/utils/id_utils.dart';
import 'package:PiliPlus/utils/id_utils.dart';
class RecVideoItemAppModel {
RecVideoItemAppModel({

View File

@@ -27,7 +27,9 @@ class HotVideoItemModel {
this.seasontype,
this.isOgv,
this.rcmdReason,
required this.checked,
this.checked,
this.pgcLabel,
this.redirectUrl,
});
int? aid;
@@ -55,7 +57,9 @@ class HotVideoItemModel {
int? seasontype;
bool? isOgv;
RcmdReason? rcmdReason;
late bool checked;
bool? checked;
String? pgcLabel;
String? redirectUrl;
HotVideoItemModel.fromJson(Map<String, dynamic> json) {
aid = json["aid"];
@@ -85,7 +89,8 @@ class HotVideoItemModel {
rcmdReason = json['rcmd_reason'] != '' && json['rcmd_reason'] != null
? RcmdReason.fromJson(json['rcmd_reason'])
: null;
checked = false;
pgcLabel = json['pgc_label'];
redirectUrl = json['redirect_url'];
}
}

View File

@@ -55,7 +55,7 @@ class AccountListModel {
mid = json['mid'];
name = json['name'] ?? '';
sex = json['sex'];
face = json['face'];
face = json['face'] ?? json['pic_url'];
sign = json['sign'];
rank = json['rank'];
level = json['level'];

View File

@@ -1,6 +1,6 @@
import 'dart:convert';
import 'package:PiliPalaX/models/msg/account.dart';
import 'package:PiliPlus/models/msg/account.dart';
class SessionDataModel {
SessionDataModel({
@@ -47,6 +47,7 @@ class SessionList {
this.liveStatus,
this.bizMsgUnreadCount,
// this.userLabel,
this.accountInfo,
});
int? talkerId;
@@ -105,6 +106,9 @@ class SessionList {
liveStatus = json["live_status"];
bizMsgUnreadCount = json["biz_msg_unread_count"];
// userLabel = json["user_label"];
accountInfo = json['account_info'] == null
? null
: AccountListModel.fromJson(json['account_info']);
}
}

View File

@@ -1,5 +1,5 @@
import 'package:PiliPalaX/utils/em.dart';
import 'package:PiliPalaX/utils/utils.dart';
import 'package:PiliPlus/utils/em.dart';
import 'package:PiliPlus/utils/utils.dart';
class SearchVideoModel {
SearchVideoModel({

View File

@@ -29,16 +29,16 @@ class SearchSuggestItem {
String? value;
String? term;
int? spid;
Widget? textRich;
dynamic textRich;
SearchSuggestItem.fromJson(Map<String, dynamic> json, String inputTerm) {
value = json['value'];
term = json['term'];
textRich = highlightText(json['name']);
textRich = json['name'];
}
}
Widget highlightText(String str) {
Widget highlightText(BuildContext context, String str) {
// 创建正则表达式,匹配 <em class="suggest_high_light">...</em> 格式的文本
RegExp regex = RegExp(r'<em class="suggest_high_light">(.*?)<\/em>');
@@ -72,7 +72,7 @@ Widget highlightText(String str) {
text: highlightedText,
style: TextStyle(
fontWeight: FontWeight.bold,
color: Theme.of(Get.context!).colorScheme.primary),
color: Theme.of(context).colorScheme.primary),
));
// 更新当前索引位置
@@ -86,7 +86,7 @@ Widget highlightText(String str) {
// 将剩余的普通文本部分添加到 children 列表中
children.add(TextSpan(
text: remainingText,
style: DefaultTextStyle.of(Get.context!).style,
style: DefaultTextStyle.of(context).style,
));
}

View File

@@ -1,4 +1,4 @@
import 'package:PiliPalaX/models/space/space_tag_bottom.dart';
import 'package:PiliPlus/models/space/space_tag_bottom.dart';
import 'package:json_annotation/json_annotation.dart';
import 'achieve.dart';

View File

@@ -13,7 +13,7 @@ import 'series.dart';
import 'setting.dart';
import 'tab.dart';
import 'tab2.dart';
import 'package:PiliPalaX/models/space_article/data.dart' as space;
import 'package:PiliPlus/models/space_article/data.dart' as space;
part 'data.g.dart';

View File

@@ -1,4 +1,4 @@
import 'package:PiliPalaX/models/space_archive/item.dart';
import 'package:PiliPlus/models/space_archive/item.dart';
import 'package:json_annotation/json_annotation.dart';
part 'season.g.dart';

View File

@@ -1,5 +1,5 @@
import 'package:PiliPalaX/models/model_owner.dart';
import 'package:PiliPalaX/models/user/fav_folder.dart';
import 'package:PiliPlus/models/model_owner.dart';
import 'package:PiliPlus/models/user/fav_folder.dart';
class FavDetailData {
FavDetailData({
@@ -47,7 +47,7 @@ class FavDetailItemData {
this.stat,
this.cid,
this.epId,
required this.checked,
this.checked,
});
int? id;
@@ -70,7 +70,7 @@ class FavDetailItemData {
Stat? stat;
int? cid;
String? epId;
late bool checked;
bool? checked;
FavDetailItemData.fromJson(Map<String, dynamic> json) {
id = json['id'];
@@ -95,7 +95,6 @@ class FavDetailItemData {
if (json['link'] != null && json['link'].contains('/bangumi')) {
epId = resolveEpId(json['link']);
}
checked = false;
}
String resolveEpId(url) {

View File

@@ -85,7 +85,7 @@ class HisListItem {
this.kid,
this.tagName,
this.liveStatus,
required this.checked,
this.checked,
});
String? title;
@@ -112,7 +112,7 @@ class HisListItem {
int? kid;
String? tagName;
int? liveStatus;
late bool checked;
bool? checked;
void isFullScreen;
HisListItem.fromJson(Map<String, dynamic> json) {
@@ -140,7 +140,6 @@ class HisListItem {
kid = json['kid'];
tagName = json['tag_name'];
liveStatus = json['live_status'];
checked = false;
}
}

View File

@@ -1,4 +1,4 @@
import 'package:PiliPalaX/models/video/play/quality.dart';
import 'package:PiliPlus/models/video/play/quality.dart';
class PlayUrlModel {
PlayUrlModel({

View File

@@ -1,4 +1,4 @@
import 'package:PiliPalaX/models/video/reply/item.dart';
import 'package:PiliPlus/models/video/reply/item.dart';
import 'config.dart';
import 'page.dart';

View File

@@ -1,8 +1,8 @@
import 'dart:convert';
import 'package:PiliPalaX/build_config.dart';
import 'package:PiliPalaX/http/constants.dart';
import 'package:PiliPalaX/services/loggeer.dart';
import 'package:PiliPlus/build_config.dart';
import 'package:PiliPlus/http/constants.dart';
import 'package:PiliPlus/services/loggeer.dart';
import 'package:cookie_jar/cookie_jar.dart';
import 'package:dio_cookie_manager/dio_cookie_manager.dart';
import 'package:flutter/material.dart';
@@ -10,10 +10,9 @@ import 'package:flutter/services.dart';
import 'package:flutter_smart_dialog/flutter_smart_dialog.dart';
import 'package:get/get.dart';
import 'package:package_info_plus/package_info_plus.dart';
import 'package:PiliPalaX/models/github/latest.dart';
import 'package:PiliPalaX/pages/setting/controller.dart';
import 'package:PiliPalaX/utils/storage.dart';
import 'package:PiliPalaX/utils/utils.dart';
import 'package:PiliPlus/models/github/latest.dart';
import 'package:PiliPlus/utils/storage.dart';
import 'package:PiliPlus/utils/utils.dart';
import '../../utils/cache_manage.dart';
class AboutPage extends StatefulWidget {
@@ -26,7 +25,7 @@ class AboutPage extends StatefulWidget {
class _AboutPageState extends State<AboutPage> {
final AboutController _aboutController = Get.put(AboutController());
static const String _sourceCodeUrl =
'https://github.com/bggRGjQaUbCoE/PiliPalaX';
'https://github.com/bggRGjQaUbCoE/PiliPlus';
static const String _originSourceCodeUrl =
'https://github.com/guozhigq/pilipala';
static const String _upstreamUrl = 'https://github.com/orz12/PiliPalaX';
@@ -60,7 +59,7 @@ class _AboutPageState extends State<AboutPage> {
)),
),
ListTile(
title: Text('PiliPalaX',
title: Text('PiliPlus',
textAlign: TextAlign.center,
style: Theme.of(context)
.textTheme
@@ -84,11 +83,15 @@ class _AboutPageState extends State<AboutPage> {
),
Obx(
() => ListTile(
// onTap: () => _aboutController.tapOnVersion(),
onTap: () => Utils.checkUpdate(false),
onLongPress: () =>
Utils.copyText(_aboutController.currentVersion.value),
title: const Text('当前版本'),
leading: const Icon(Icons.commit_outlined),
trailing: Text(_aboutController.currentVersion.value,
style: subTitleStyle),
trailing: Text(
_aboutController.currentVersion.value,
style: subTitleStyle,
),
),
),
ListTile(
@@ -100,7 +103,8 @@ Commit Hash: ${BuildConfig.commitHash}''',
),
leading: const Icon(Icons.info_outline),
onTap: () => Utils.launchURL(
'https://github.com/bggRGjQaUbCoE/PiliPalaX/commit/${BuildConfig.commitHash}'),
'https://github.com/bggRGjQaUbCoE/PiliPlus/commit/${BuildConfig.commitHash}'),
onLongPress: () => Utils.copyText(BuildConfig.commitHash),
),
// Obx(
// () => ListTile(
@@ -237,14 +241,14 @@ Commit Hash: ${BuildConfig.commitHash}''',
'cookies': cookies,
});
Utils.copyText('$res');
if (context.mounted) {
showDialog(
context: context,
builder: (context) => AlertDialog(
content: SelectableText('$res'),
),
);
}
// if (context.mounted) {
// showDialog(
// context: context,
// builder: (context) => AlertDialog(
// content: SelectableText('$res'),
// ),
// );
// }
},
),
ListTile(
@@ -437,7 +441,6 @@ Commit Hash: ${BuildConfig.commitHash}''',
}
class AboutController extends GetxController {
final SettingController settingController = Get.put(SettingController());
RxString currentVersion = ''.obs;
RxString remoteVersion = ''.obs;
LatestDataModel? remoteAppInfo;

View File

@@ -1,39 +1,91 @@
import 'package:PiliPalaX/http/loading_state.dart';
import 'package:PiliPalaX/pages/common/common_controller.dart';
import 'package:PiliPlus/http/loading_state.dart';
import 'package:PiliPlus/models/bangumi/list.dart';
import 'package:PiliPlus/models/common/tab_type.dart';
import 'package:PiliPlus/pages/common/common_controller.dart';
import 'package:PiliPlus/utils/extension.dart';
import 'package:flutter/material.dart';
import 'package:get/get.dart';
import 'package:PiliPalaX/http/bangumi.dart';
import 'package:PiliPalaX/utils/storage.dart';
import 'package:PiliPlus/http/bangumi.dart';
import 'package:PiliPlus/utils/storage.dart';
class BangumiController extends CommonController {
bool isLoadingMore = true;
RxBool userLogin = false.obs;
late int mid;
dynamic userInfo;
BangumiController({required this.tabType});
final TabType tabType;
Rx<LoadingState> followState = LoadingState.loading().obs;
bool isLoadingMore = true;
RxBool isLogin = false.obs;
int? mid;
dynamic userInfo;
@override
void onInit() {
super.onInit();
userInfo = GStorage.userInfo.get('userInfoCache');
if (userInfo != null) {
mid = userInfo.mid;
}
userLogin.value = userInfo != null;
mid = userInfo?.mid;
isLogin.value = userInfo != null;
queryData();
queryBangumiFollow();
}
// 我的订阅
Future queryBangumiFollow() async {
userInfo = userInfo ?? GStorage.userInfo.get('userInfoCache');
if (userInfo != null) {
followState.value = await BangumiHttp.bangumiFollow(mid: userInfo.mid);
if (isLogin.value) {
followController = ScrollController();
}
}
@override
Future<LoadingState> customGetData() =>
BangumiHttp.bangumiList(page: currentPage);
Future onRefresh() {
if (isLogin.value) {
followPage = 1;
followEnd = false;
}
queryBangumiFollow();
return super.onRefresh();
}
late int followPage = 1;
late RxInt followCount = (-1).obs;
late bool followLoading = false;
late bool followEnd = false;
late Rx<LoadingState> followState = LoadingState.loading().obs;
ScrollController? followController;
// 我的订阅
Future queryBangumiFollow([bool isRefresh = true]) async {
if (isLogin.value.not || followLoading || (isRefresh.not && followEnd)) {
return;
}
followLoading = true;
dynamic res = await BangumiHttp.bangumiFollow(
mid: mid,
type: tabType == TabType.bangumi ? 1 : 2,
pn: followPage,
);
if (res is Success) {
BangumiListDataModel data = res.response;
followPage++;
followEnd = data.hasNext == 0 || data.list.isNullOrEmpty;
followCount.value = data.total ?? -1;
if (isRefresh.not && followState.value is Success) {
data.list?.insertAll(0, (followState.value as Success).response);
}
followState.value = LoadingState.success(data.list);
if (isRefresh) {
followController?.animToTop();
}
} else {
followState.value = res;
}
followLoading = false;
}
@override
Future<LoadingState> customGetData() => BangumiHttp.bangumiList(
page: currentPage,
indexType: tabType == TabType.cinema ? 102 : null, // TODO: sort
);
@override
void onClose() {
followController?.dispose();
super.onClose();
}
}

View File

@@ -1,25 +1,25 @@
import 'dart:convert';
import 'package:PiliPalaX/http/init.dart';
import 'package:PiliPalaX/http/loading_state.dart';
import 'package:PiliPalaX/http/user.dart';
import 'package:PiliPalaX/pages/common/common_controller.dart';
import 'package:PiliPalaX/pages/video/detail/introduction/controller.dart';
import 'package:PiliPalaX/utils/utils.dart';
import 'package:PiliPlus/http/init.dart';
import 'package:PiliPlus/http/loading_state.dart';
import 'package:PiliPlus/http/user.dart';
import 'package:PiliPlus/pages/common/common_controller.dart';
import 'package:PiliPlus/pages/video/detail/introduction/controller.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:get/get_navigation/src/dialog/dialog_route.dart';
import 'package:PiliPalaX/http/constants.dart';
import 'package:PiliPalaX/http/search.dart';
import 'package:PiliPalaX/http/video.dart';
import 'package:PiliPalaX/models/bangumi/info.dart';
import 'package:PiliPalaX/models/user/fav_folder.dart';
import 'package:PiliPalaX/pages/video/detail/index.dart';
import 'package:PiliPalaX/pages/video/detail/reply/index.dart';
import 'package:PiliPalaX/plugin/pl_player/models/play_repeat.dart';
import 'package:PiliPalaX/utils/feed_back.dart';
import 'package:PiliPalaX/utils/storage.dart';
import 'package:PiliPlus/http/constants.dart';
import 'package:PiliPlus/http/search.dart';
import 'package:PiliPlus/http/video.dart';
import 'package:PiliPlus/models/bangumi/info.dart';
import 'package:PiliPlus/models/user/fav_folder.dart';
import 'package:PiliPlus/pages/video/detail/index.dart';
import 'package:PiliPlus/pages/video/detail/reply/index.dart';
import 'package:PiliPlus/plugin/pl_player/models/play_repeat.dart';
import 'package:PiliPlus/utils/feed_back.dart';
import 'package:PiliPlus/utils/storage.dart';
import 'package:share_plus/share_plus.dart';
import 'package:html/parser.dart' as html_parser;
import 'package:html/dom.dart' as dom;
@@ -34,6 +34,11 @@ class BangumiIntroController extends CommonController {
? int.tryParse(Get.parameters['epId']!)
: null;
late dynamic type =
Get.parameters['type'] == '1' || Get.parameters['type'] == '4'
? '追番'
: '追剧';
// 是否预渲染 骨架屏
bool preRender = false;
@@ -51,7 +56,7 @@ class BangumiIntroController extends CommonController {
// 是否收藏
RxBool hasFav = false.obs;
dynamic videoTags;
bool userLogin = false;
bool isLogin = false;
Rx<FavFolderData> favFolderData = FavFolderData().obs;
List addMediaIdsNew = [];
List delMediaIdsNew = [];
@@ -82,9 +87,9 @@ class BangumiIntroController extends CommonController {
}
}
userInfo = GStorage.userInfo.get('userInfoCache');
userLogin = userInfo != null;
isLogin = userInfo != null;
if (userLogin && epId != null) {
if (isLogin && epId != null) {
// // 获取点赞状态
// queryHasLikeVideo();
// // 获取投币状态
@@ -96,7 +101,7 @@ class BangumiIntroController extends CommonController {
queryData();
if (userLogin && seasonId != null) {
if (isLogin && seasonId != null) {
queryIsFollowed();
}
}
@@ -372,15 +377,23 @@ class BangumiIntroController extends CommonController {
// 修改分P或番剧分集
Future changeSeasonOrbangu(epId, bvid, cid, aid, cover) async {
// 重新获取视频资源
VideoDetailController videoDetailCtr =
Get.find<VideoDetailController>(tag: Get.arguments['heroTag'])
..epId = epId;
this.epId = epId;
this.bvid = bvid;
videoDetailCtr.bvid = bvid;
videoDetailCtr.cid.value = cid;
videoDetailCtr.danmakuCid.value = cid;
videoDetailCtr.queryVideoUrl();
final videoDetailCtr =
Get.find<VideoDetailController>(tag: Get.arguments['heroTag'])
..plPlayerController.pause()
..makeHeartBeat()
..playedTime = null
..videoUrl = null
..audioUrl = null
..vttSubtitlesIndex = null
..savedDanmaku = null
..epId = epId
..bvid = bvid
..cid.value = cid
..danmakuCid.value = cid
..queryVideoUrl();
if (cover is String && cover.isNotEmpty) {
videoDetailCtr.videoItem['pic'] = cover;
}
@@ -396,7 +409,7 @@ class BangumiIntroController extends CommonController {
} catch (_) {}
}
if (userLogin) {
if (isLogin) {
queryBangumiLikeCoinFav();
}
}

View File

@@ -1,24 +1,24 @@
import 'dart:async';
import 'package:PiliPalaX/common/widgets/http_error.dart';
import 'package:PiliPalaX/http/loading_state.dart';
import 'package:PiliPalaX/utils/extension.dart';
import 'package:PiliPlus/common/widgets/http_error.dart';
import 'package:PiliPlus/http/loading_state.dart';
import 'package:PiliPlus/utils/extension.dart';
import 'package:flutter/material.dart';
import 'package:flutter_smart_dialog/flutter_smart_dialog.dart';
import 'package:font_awesome_flutter/font_awesome_flutter.dart';
import 'package:get/get.dart';
import 'package:PiliPalaX/common/constants.dart';
import 'package:PiliPalaX/common/widgets/badge.dart';
import 'package:PiliPalaX/common/widgets/network_img_layer.dart';
import 'package:PiliPalaX/common/widgets/stat/danmu.dart';
import 'package:PiliPalaX/common/widgets/stat/view.dart';
import 'package:PiliPalaX/models/bangumi/info.dart';
import 'package:PiliPalaX/pages/bangumi/widgets/bangumi_panel.dart';
import 'package:PiliPalaX/pages/video/detail/index.dart';
import 'package:PiliPalaX/pages/video/detail/introduction/widgets/action_item.dart';
import 'package:PiliPalaX/pages/video/detail/introduction/widgets/action_row_item.dart';
import 'package:PiliPalaX/pages/video/detail/introduction/widgets/fav_panel.dart';
import 'package:PiliPalaX/utils/feed_back.dart';
import 'package:PiliPlus/common/constants.dart';
import 'package:PiliPlus/common/widgets/badge.dart';
import 'package:PiliPlus/common/widgets/network_img_layer.dart';
import 'package:PiliPlus/common/widgets/stat/danmu.dart';
import 'package:PiliPlus/common/widgets/stat/view.dart';
import 'package:PiliPlus/models/bangumi/info.dart';
import 'package:PiliPlus/pages/bangumi/widgets/bangumi_panel.dart';
import 'package:PiliPlus/pages/video/detail/index.dart';
import 'package:PiliPlus/pages/video/detail/introduction/widgets/action_item.dart';
import 'package:PiliPlus/pages/video/detail/introduction/widgets/action_row_item.dart';
import 'package:PiliPlus/pages/video/detail/introduction/widgets/fav_panel.dart';
import 'package:PiliPlus/utils/feed_back.dart';
import '../../../utils/utils.dart';
import 'controller.dart';
@@ -235,13 +235,17 @@ class _BangumiInfoState extends State<BangumiInfo>
Stack(
children: [
GestureDetector(
onTap: () => context.imageView(
imgList: [
!widget.isLoading
? widget.bangumiDetail!.cover!
: bangumiItem!.cover!
],
),
onTap: () {
videoDetailCtr.onViewImage();
context.imageView(
imgList: [
!widget.isLoading
? widget.bangumiDetail!.cover!
: bangumiItem!.cover!
],
onDismissed: videoDetailCtr.onDismissed,
);
},
child: Hero(
tag: !widget.isLoading
? widget.bangumiDetail!.cover!
@@ -339,8 +343,8 @@ class _BangumiInfoState extends State<BangumiInfo>
child: Text(
bangumiIntroController
.isFollowed.value
? '追番'
: '追番',
? '${bangumiIntroController.type}'
: '${bangumiIntroController.type}',
),
),
),
@@ -628,10 +632,10 @@ class _BangumiInfoState extends State<BangumiInfo>
_followDialogItem(1, '想看'),
ListTile(
dense: true,
title: const Padding(
title: Padding(
padding: EdgeInsets.only(left: 10),
child: Text(
'取消追番',
'取消${bangumiIntroController.type}',
style: TextStyle(fontSize: 14),
),
),

View File

@@ -1,7 +1,7 @@
import 'package:PiliPalaX/pages/search/widgets/search_text.dart';
import 'package:PiliPlus/pages/search/widgets/search_text.dart';
import 'package:flutter/material.dart';
import 'package:PiliPalaX/common/widgets/stat/danmu.dart';
import 'package:PiliPalaX/common/widgets/stat/view.dart';
import 'package:PiliPlus/common/widgets/stat/danmu.dart';
import 'package:PiliPlus/common/widgets/stat/view.dart';
import 'package:get/get.dart';
import '../../../../utils/utils.dart';

View File

@@ -1,22 +1,28 @@
import 'dart:async';
import 'package:PiliPalaX/common/widgets/refresh_indicator.dart';
import 'package:PiliPalaX/http/loading_state.dart';
import 'package:PiliPlus/common/widgets/loading_widget.dart';
import 'package:PiliPlus/common/widgets/refresh_indicator.dart';
import 'package:PiliPlus/http/loading_state.dart';
import 'package:PiliPlus/models/common/tab_type.dart';
import 'package:flutter/material.dart';
import 'package:flutter/rendering.dart';
import 'package:get/get.dart';
import 'package:nil/nil.dart';
import 'package:PiliPalaX/common/constants.dart';
import 'package:PiliPalaX/common/widgets/http_error.dart';
import 'package:PiliPalaX/pages/home/index.dart';
import 'package:PiliPalaX/pages/main/index.dart';
import 'package:PiliPlus/common/constants.dart';
import 'package:PiliPlus/common/widgets/http_error.dart';
import 'package:PiliPlus/pages/home/index.dart';
import 'package:PiliPlus/pages/main/index.dart';
import '../../utils/grid.dart';
import 'controller.dart';
import 'widgets/bangumi_card_v.dart';
class BangumiPage extends StatefulWidget {
const BangumiPage({super.key});
const BangumiPage({
super.key,
required this.tabType,
});
final TabType tabType;
@override
State<BangumiPage> createState() => _BangumiPageState();
@@ -24,7 +30,10 @@ class BangumiPage extends StatefulWidget {
class _BangumiPageState extends State<BangumiPage>
with AutomaticKeepAliveClientMixin {
final BangumiController _bangumiController = Get.put(BangumiController());
late final BangumiController _bangumiController = Get.put(
BangumiController(tabType: widget.tabType),
tag: widget.tabType.name,
);
@override
bool get wantKeepAlive => true;
@@ -74,7 +83,7 @@ class _BangumiPageState extends State<BangumiPage>
SliverToBoxAdapter(
child: Obx(
() => Visibility(
visible: _bangumiController.userLogin.value,
visible: _bangumiController.isLogin.value,
child: Column(
children: [
Padding(
@@ -82,14 +91,19 @@ class _BangumiPageState extends State<BangumiPage>
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text(
'最近追番',
style: Theme.of(context).textTheme.titleMedium,
Obx(
() => Text(
'最近${widget.tabType == TabType.bangumi ? '追番' : '追剧'}${_bangumiController.followCount.value == -1 ? '' : ' ${_bangumiController.followCount.value}'}',
style: Theme.of(context).textTheme.titleMedium,
),
),
IconButton(
tooltip: '刷新',
onPressed: () {
_bangumiController.queryBangumiFollow();
_bangumiController
..followPage = 1
..followEnd = false
..queryBangumiFollow();
},
icon: const Icon(
Icons.refresh,
@@ -177,9 +191,13 @@ class _BangumiPageState extends State<BangumiPage>
Widget _buildFollowList(Success loadingState) {
return ListView.builder(
controller: _bangumiController.followController,
scrollDirection: Axis.horizontal,
itemCount: loadingState.response.length,
itemBuilder: (context, index) {
if (index == loadingState.response.length - 1) {
_bangumiController.queryBangumiFollow(false);
}
return Container(
width: Grid.maxRowWidth / 2,
margin: EdgeInsets.only(
@@ -198,11 +216,20 @@ class _BangumiPageState extends State<BangumiPage>
Widget _buildFollowBody(LoadingState loadingState) {
return switch (loadingState) {
Loading() => nil,
Loading() => loadingWidget,
Success() => (loadingState.response as List?)?.isNotEmpty == true
? _buildFollowList(loadingState)
: const Center(child: Text('还没有追番')),
Error() => Center(child: Text(loadingState.errMsg)),
: Center(
child: Text(
'还没有${widget.tabType == TabType.bangumi ? '追番' : '追剧'}')),
Error() => Container(
padding: const EdgeInsets.symmetric(horizontal: 16),
alignment: Alignment.center,
child: Text(
loadingState.errMsg,
textAlign: TextAlign.center,
),
),
LoadingState() => throw UnimplementedError(),
};
}

View File

@@ -1,9 +1,9 @@
import 'package:PiliPalaX/common/widgets/image_save.dart';
import 'package:PiliPlus/common/widgets/image_save.dart';
import 'package:flutter/material.dart';
import 'package:PiliPalaX/common/constants.dart';
import 'package:PiliPalaX/common/widgets/badge.dart';
import 'package:PiliPalaX/utils/utils.dart';
import 'package:PiliPalaX/common/widgets/network_img_layer.dart';
import 'package:PiliPlus/common/constants.dart';
import 'package:PiliPlus/common/widgets/badge.dart';
import 'package:PiliPlus/utils/utils.dart';
import 'package:PiliPlus/common/widgets/network_img_layer.dart';
// 视频卡片 - 垂直布局
class BangumiCardV extends StatelessWidget {
@@ -20,110 +20,98 @@ class BangumiCardV extends StatelessWidget {
return Card(
clipBehavior: Clip.hardEdge,
margin: EdgeInsets.zero,
child: GestureDetector(
// onLongPress: () {
// if (longPress != null) {
// longPress!();
// }
// },
// onLongPressEnd: (details) {
// if (longPressEnd != null) {
// longPressEnd!();
// }
// },
child: InkWell(
onLongPress: () => imageSaveDialog(
context: context,
title: bangumiItem.title,
cover: bangumiItem.cover,
),
child: InkWell(
onTap: () async {
final int seasonId = bangumiItem.seasonId;
Utils.viewBangumi(seasonId: seasonId);
// SmartDialog.showLoading(msg: '获取中...');
// final res = await SearchHttp.bangumiInfo(seasonId: seasonId);
// SmartDialog.dismiss().then((value) {
// if (res['status']) {
// if (res['data'].episodes.isEmpty) {
// SmartDialog.showToast('资源加载失败');
// return;
// }
// EpisodeItem episode = res['data'].episodes.first;
// int? epId = res['data'].userStatus?.progress?.lastEpId;
// if (epId == null) {
// epId = episode.epId;
// } else {
// for (var item in res['data'].episodes) {
// if (item.epId == epId) {
// episode = item;
// break;
// }
// }
// }
// String bvid = episode.bvid!;
// int cid = episode.cid!;
// String pic = episode.cover!;
// // debugPrint('epId');
// // debugPrint(epId);
// String heroTag = Utils.makeHeroTag(cid);
// Get.toNamed(
// '/video?bvid=$bvid&cid=$cid&seasonId=$seasonId&epId=$epId',
// arguments: {
// 'pic': pic,
// 'heroTag': heroTag,
// 'videoType': SearchType.media_bangumi,
// 'bangumiItem': res['data'],
// },
// );
// } else {
// SmartDialog.showToast(res['msg']);
// }
// });
},
child: Column(
children: [
ClipRRect(
borderRadius: const BorderRadius.all(StyleString.imgRadius),
child: AspectRatio(
aspectRatio: 0.75,
child: LayoutBuilder(builder: (context, boxConstraints) {
final double maxWidth = boxConstraints.maxWidth;
final double maxHeight = boxConstraints.maxHeight;
return Stack(
children: [
Hero(
tag: heroTag,
child: NetworkImgLayer(
src: bangumiItem.cover,
width: maxWidth,
height: maxHeight,
),
onTap: () async {
final int seasonId = bangumiItem.seasonId;
Utils.viewBangumi(seasonId: seasonId);
// SmartDialog.showLoading(msg: '获取中...');
// final res = await SearchHttp.bangumiInfo(seasonId: seasonId);
// SmartDialog.dismiss().then((value) {
// if (res['status']) {
// if (res['data'].episodes.isEmpty) {
// SmartDialog.showToast('资源加载失败');
// return;
// }
// EpisodeItem episode = res['data'].episodes.first;
// int? epId = res['data'].userStatus?.progress?.lastEpId;
// if (epId == null) {
// epId = episode.epId;
// } else {
// for (var item in res['data'].episodes) {
// if (item.epId == epId) {
// episode = item;
// break;
// }
// }
// }
// String bvid = episode.bvid!;
// int cid = episode.cid!;
// String pic = episode.cover!;
// // debugPrint('epId');
// // debugPrint(epId);
// String heroTag = Utils.makeHeroTag(cid);
// Get.toNamed(
// '/video?bvid=$bvid&cid=$cid&seasonId=$seasonId&epId=$epId',
// arguments: {
// 'pic': pic,
// 'heroTag': heroTag,
// 'videoType': SearchType.media_bangumi,
// 'bangumiItem': res['data'],
// },
// );
// } else {
// SmartDialog.showToast(res['msg']);
// }
// });
},
child: Column(
children: [
ClipRRect(
borderRadius: const BorderRadius.all(StyleString.imgRadius),
child: AspectRatio(
aspectRatio: 0.75,
child: LayoutBuilder(builder: (context, boxConstraints) {
final double maxWidth = boxConstraints.maxWidth;
final double maxHeight = boxConstraints.maxHeight;
return Stack(
children: [
Hero(
tag: heroTag,
child: NetworkImgLayer(
src: bangumiItem.cover,
width: maxWidth,
height: maxHeight,
),
if (bangumiItem.badge != null)
PBadge(
text: bangumiItem.badge,
top: 6,
right: 6,
bottom: null,
left: null,
),
if (bangumiItem.order != null)
PBadge(
text: bangumiItem.order,
top: null,
right: null,
bottom: 6,
left: 6,
type: 'gray',
),
],
);
}),
),
),
if (bangumiItem.badge != null)
PBadge(
text: bangumiItem.badge,
top: 6,
right: 6,
bottom: null,
left: null,
),
if (bangumiItem.order != null)
PBadge(
text: bangumiItem.order,
top: null,
right: null,
bottom: 6,
left: 6,
type: 'gray',
),
],
);
}),
),
bagumiContent(context)
],
),
),
bagumiContent(context)
],
),
),
);

View File

@@ -1,9 +1,9 @@
import 'package:PiliPalaX/common/widgets/image_save.dart';
import 'package:PiliPalaX/models/space_archive/item.dart';
import 'package:PiliPlus/common/widgets/image_save.dart';
import 'package:PiliPlus/models/space_archive/item.dart';
import 'package:flutter/material.dart';
import 'package:PiliPalaX/common/constants.dart';
import 'package:PiliPalaX/utils/utils.dart';
import 'package:PiliPalaX/common/widgets/network_img_layer.dart';
import 'package:PiliPlus/common/constants.dart';
import 'package:PiliPlus/utils/utils.dart';
import 'package:PiliPlus/common/widgets/network_img_layer.dart';
// 视频卡片 - 垂直布局
class BangumiCardVMemberHome extends StatelessWidget {

View File

@@ -1,12 +1,12 @@
import 'dart:async';
import 'package:PiliPalaX/utils/utils.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:PiliPalaX/models/bangumi/info.dart';
import 'package:PiliPalaX/pages/video/detail/index.dart';
import 'package:PiliPalaX/utils/storage.dart';
import 'package:PiliPlus/models/bangumi/info.dart';
import 'package:PiliPlus/pages/video/detail/index.dart';
import 'package:PiliPlus/utils/storage.dart';
class BangumiPanel extends StatefulWidget {
const BangumiPanel({

View File

@@ -1,14 +1,14 @@
import 'package:PiliPalaX/common/widgets/loading_widget.dart';
import 'package:PiliPalaX/common/widgets/refresh_indicator.dart';
import 'package:PiliPalaX/http/loading_state.dart';
import 'package:PiliPalaX/pages/common/common_controller.dart';
import 'package:PiliPlus/common/widgets/loading_widget.dart';
import 'package:PiliPlus/common/widgets/refresh_indicator.dart';
import 'package:PiliPlus/http/loading_state.dart';
import 'package:PiliPlus/pages/common/common_controller.dart';
import 'package:flutter/material.dart';
import 'package:flutter_smart_dialog/flutter_smart_dialog.dart';
import 'package:get/get.dart';
import 'package:PiliPalaX/common/widgets/network_img_layer.dart';
import 'package:PiliPalaX/http/black.dart';
import 'package:PiliPalaX/utils/storage.dart';
import 'package:PiliPalaX/utils/utils.dart';
import 'package:PiliPlus/common/widgets/network_img_layer.dart';
import 'package:PiliPlus/http/black.dart';
import 'package:PiliPlus/utils/storage.dart';
import 'package:PiliPlus/utils/utils.dart';
class BlackListPage extends StatefulWidget {
const BlackListPage({super.key});

View File

@@ -1,5 +1,5 @@
import 'package:PiliPalaX/http/loading_state.dart';
import 'package:PiliPalaX/utils/extension.dart';
import 'package:PiliPlus/http/loading_state.dart';
import 'package:PiliPlus/utils/extension.dart';
import 'package:flutter/cupertino.dart';
import 'package:get/get.dart';

View File

@@ -1,7 +1,7 @@
import 'package:PiliPalaX/http/loading_state.dart';
import 'package:PiliPalaX/pages/common/common_controller.dart';
import 'package:PiliPlus/http/loading_state.dart';
import 'package:PiliPlus/pages/common/common_controller.dart';
import 'package:get/get.dart';
import 'package:PiliPalaX/utils/extension.dart';
import 'package:PiliPlus/utils/extension.dart';
abstract class MultiSelectController extends CommonController {
RxBool enableMultiSelect = false.obs;
@@ -9,8 +9,8 @@ abstract class MultiSelectController extends CommonController {
onSelect(int index) {
List list = (loadingState.value as Success).response;
list[index].checked = !list[index].checked;
checkedCount.value = list.where((item) => item.checked).length;
list[index].checked = !(list[index]?.checked ?? false);
checkedCount.value = list.where((item) => item.checked == true).length;
loadingState.value = LoadingState.success(list);
if (checkedCount.value == 0) {
enableMultiSelect.value = false;

View File

@@ -1,19 +1,19 @@
import 'package:PiliPalaX/grpc/app/main/community/reply/v1/reply.pb.dart';
import 'package:PiliPalaX/http/loading_state.dart';
import 'package:PiliPalaX/models/common/reply_type.dart';
import 'package:PiliPalaX/models/video/reply/data.dart';
import 'package:PiliPalaX/pages/common/common_controller.dart';
import 'package:PiliPalaX/pages/video/detail/reply_new/reply_page.dart';
import 'package:PiliPalaX/utils/extension.dart';
import 'package:PiliPalaX/utils/global_data.dart';
import 'package:PiliPalaX/utils/utils.dart';
import 'package:PiliPlus/grpc/app/main/community/reply/v1/reply.pb.dart';
import 'package:PiliPlus/http/loading_state.dart';
import 'package:PiliPlus/models/common/reply_type.dart';
import 'package:PiliPlus/models/video/reply/data.dart';
import 'package:PiliPlus/pages/common/common_controller.dart';
import 'package:PiliPlus/pages/video/detail/reply_new/reply_page.dart';
import 'package:PiliPlus/utils/extension.dart';
import 'package:PiliPlus/utils/global_data.dart';
import 'package:PiliPlus/utils/utils.dart';
import 'package:easy_debounce/easy_throttle.dart';
import 'package:flutter/material.dart';
import 'package:get/get.dart';
import 'package:PiliPalaX/models/common/reply_sort_type.dart';
import 'package:PiliPalaX/models/video/reply/item.dart';
import 'package:PiliPalaX/utils/feed_back.dart';
import 'package:PiliPalaX/utils/storage.dart';
import 'package:PiliPlus/models/common/reply_sort_type.dart';
import 'package:PiliPlus/models/video/reply/item.dart';
import 'package:PiliPlus/utils/feed_back.dart';
import 'package:PiliPlus/utils/storage.dart';
import 'package:get/get_navigation/src/dialog/dialog_route.dart';
abstract class ReplyController extends CommonController {

View File

@@ -1,6 +1,6 @@
import 'package:PiliPalaX/http/danmaku.dart';
import 'package:PiliPalaX/models/danmaku/dm.pb.dart';
import 'package:PiliPalaX/plugin/pl_player/controller.dart';
import 'package:PiliPlus/http/danmaku.dart';
import 'package:PiliPlus/models/danmaku/dm.pb.dart';
import 'package:PiliPlus/plugin/pl_player/controller.dart';
class PlDanmakuController {
PlDanmakuController(
@@ -86,7 +86,8 @@ class PlDanmakuController {
}
break;
case 1:
if (RegExp(filter['filter']).hasMatch(elem.content)) {
if (RegExp(filter['filter'], caseSensitive: false)
.hasMatch(elem.content)) {
return false;
}
break;

View File

@@ -1,14 +1,14 @@
import 'dart:async';
import 'package:PiliPalaX/utils/extension.dart';
import 'package:PiliPlus/utils/extension.dart';
import 'package:canvas_danmaku/canvas_danmaku.dart';
import 'package:flutter/material.dart';
import 'package:get/get.dart';
import 'package:PiliPalaX/models/danmaku/dm.pb.dart';
import 'package:PiliPalaX/pages/danmaku/index.dart';
import 'package:PiliPalaX/plugin/pl_player/index.dart';
import 'package:PiliPalaX/utils/danmaku.dart';
import 'package:PiliPalaX/utils/storage.dart';
import 'package:PiliPlus/models/danmaku/dm.pb.dart';
import 'package:PiliPlus/pages/danmaku/index.dart';
import 'package:PiliPlus/plugin/pl_player/index.dart';
import 'package:PiliPlus/utils/danmaku.dart';
import 'package:PiliPlus/utils/storage.dart';
/// 传入播放器控制器,监听播放进度,加载对应弹幕
class PlDanmaku extends StatefulWidget {

View File

@@ -1,7 +1,7 @@
import 'package:flutter/material.dart';
import 'package:flutter_smart_dialog/flutter_smart_dialog.dart';
import 'package:get/get.dart';
import 'package:PiliPalaX/utils/storage.dart';
import 'package:PiliPlus/utils/storage.dart';
import '../../http/danmaku_block.dart';
import '../../models/user/danmaku_block.dart';

View File

@@ -1,20 +1,21 @@
import 'package:PiliPalaX/http/follow.dart';
import 'package:PiliPalaX/pages/dynamics/tab/controller.dart';
import 'package:PiliPalaX/pages/dynamics/tab/view.dart';
import 'package:PiliPalaX/utils/extension.dart';
import 'package:PiliPlus/http/follow.dart';
import 'package:PiliPlus/pages/dynamics/tab/controller.dart';
import 'package:PiliPlus/pages/dynamics/tab/view.dart';
import 'package:PiliPlus/utils/extension.dart';
import 'package:PiliPlus/utils/url_utils.dart';
import 'package:flutter/material.dart';
import 'package:flutter_smart_dialog/flutter_smart_dialog.dart';
import 'package:get/get.dart';
import 'package:PiliPalaX/http/dynamics.dart';
import 'package:PiliPalaX/http/search.dart';
import 'package:PiliPalaX/models/common/dynamics_type.dart';
import 'package:PiliPalaX/models/dynamics/result.dart';
import 'package:PiliPalaX/models/dynamics/up.dart';
import 'package:PiliPalaX/models/live/item.dart';
import 'package:PiliPalaX/utils/feed_back.dart';
import 'package:PiliPalaX/utils/id_utils.dart';
import 'package:PiliPalaX/utils/storage.dart';
import 'package:PiliPalaX/utils/utils.dart';
import 'package:PiliPlus/http/dynamics.dart';
import 'package:PiliPlus/http/search.dart';
import 'package:PiliPlus/models/common/dynamics_type.dart';
import 'package:PiliPlus/models/dynamics/result.dart';
import 'package:PiliPlus/models/dynamics/up.dart';
import 'package:PiliPlus/models/live/item.dart';
import 'package:PiliPlus/utils/feed_back.dart';
import 'package:PiliPlus/utils/id_utils.dart';
import 'package:PiliPlus/utils/storage.dart';
import 'package:PiliPlus/utils/utils.dart';
import '../../models/follow/result.dart';
@@ -29,22 +30,28 @@ class DynamicsController extends GetxController
late TabController tabController;
RxList<int> tempBannedList = <int>[].obs;
late List<Widget> tabsPageList;
bool flag = false;
RxInt initialValue = 0.obs;
RxBool userLogin = false.obs;
dynamic userInfo;
RxBool isLogin = false.obs;
dynamic ownerMid;
dynamic face;
RxBool isLoadingDynamic = false.obs;
List<UpItem> hasUpdatedUps = <UpItem>[];
List<UpItem> allFollowedUps = <UpItem>[];
int allFollowedUpsPage = 1;
int allFollowedUpsTotal = 0;
late int currentMid = -1;
late bool showLiveItems = false;
@override
void onInit() {
userInfo = GStorage.userInfo.get('userInfoCache');
userLogin.value = userInfo != null;
super.onInit();
dynamic userInfo = GStorage.userInfo.get('userInfoCache');
ownerMid = userInfo?.mid;
face = userInfo?.face;
isLogin.value = userInfo != null;
tabController = TabController(
length: tabsConfig.length,
vsync: this,
@@ -53,9 +60,7 @@ class DynamicsController extends GetxController
);
tabsPageList =
tabsConfig.map((e) => DynamicsTabPage(dynamicsType: e['tag'])).toList();
}
void refreshNotifier() {
queryFollowUp();
}
@@ -85,12 +90,31 @@ class DynamicsController extends GetxController
arguments: {'item': item, 'floor': floor});
break;
case 'DYNAMIC_TYPE_AV':
if (item.modules.moduleDynamic.major.archive.type == 2) {
if (item.modules.moduleDynamic.major.archive.jumpUrl
.startsWith('//')) {
item.modules.moduleDynamic.major.archive.jumpUrl =
'https:${item.modules.moduleDynamic.major.archive.jumpUrl}';
}
String? redirectUrl = await UrlUtils.parseRedirectUrl(
item.modules.moduleDynamic.major.archive.jumpUrl);
if (redirectUrl != null) {
Utils.viewPgcFromUri(redirectUrl);
return;
}
}
String bvid = item.modules.moduleDynamic.major.archive.bvid;
String cover = item.modules.moduleDynamic.major.archive.cover;
try {
int cid = await SearchHttp.ab2c(bvid: bvid);
Utils.toDupNamed('/video?bvid=$bvid&cid=$cid',
arguments: {'pic': cover, 'heroTag': bvid});
Utils.toDupNamed(
'/video?bvid=$bvid&cid=$cid',
arguments: {
'pic': cover,
'heroTag': Utils.makeHeroTag(bvid),
},
);
} catch (err) {
SmartDialog.showToast(err.toString());
}
@@ -162,8 +186,13 @@ class DynamicsController extends GetxController
String bvid = IdUtils.av2bv(aid);
String cover = ugcSeason.cover!;
int cid = await SearchHttp.ab2c(bvid: bvid);
Utils.toDupNamed('/video?bvid=$bvid&cid=$cid',
arguments: {'pic': cover, 'heroTag': bvid});
Utils.toDupNamed(
'/video?bvid=$bvid&cid=$cid',
arguments: {
'pic': cover,
'heroTag': Utils.makeHeroTag(bvid),
},
);
break;
/// 番剧查看
@@ -214,7 +243,7 @@ class DynamicsController extends GetxController
return;
}
var res = await FollowHttp.followings(
vmid: userInfo.mid,
vmid: ownerMid,
pn: allFollowedUpsPage,
ps: 50,
orderType: 'attention',
@@ -237,9 +266,11 @@ class DynamicsController extends GetxController
}
Future queryFollowUp({type = 'init'}) async {
if (!userLogin.value) {
return {'status': false, 'msg': '账号未登录'};
if (!isLogin.value) {
upData.value.errMsg = '账号未登录';
upData.refresh();
}
upData.value.errMsg = null;
if (type == 'init') {
upData.value.upList = [];
upData.value.liveUsers = LiveUsers();
@@ -249,15 +280,19 @@ class DynamicsController extends GetxController
allFollowedUpsPage = 1;
Future f1 = DynamicsHttp.followUp();
Future f2 = FollowHttp.followings(
vmid: userInfo.mid,
pn: allFollowedUpsPage,
ps: 50,
orderType: 'attention');
vmid: ownerMid,
pn: allFollowedUpsPage,
ps: 50,
orderType: 'attention',
);
List<dynamic> ress = await Future.wait([f1, f2]);
if (!ress[0]['status']) {
SmartDialog.showToast("获取关注动态失败:${ress[0]['msg']}");
upData.value.errMsg = ress[0]['msg'];
upData.refresh();
} else {
upData.value.liveUsers = ress[0]['data'].liveUsers;
upData.refresh();
hasUpdatedUps = ress[0]['data'].upList!;
}
if (!ress[1]['status']) {
@@ -277,16 +312,19 @@ class DynamicsController extends GetxController
}
upData.value.upList =
allFollowedUpsTotal > 0 ? allFollowedUps : hasUpdatedUps;
return ress[0];
}
var res = await DynamicsHttp.followUp();
if (res['status']) {
upData.value = res['data'];
if (upData.value.upList!.isEmpty) {
mid.value = -1;
upData.refresh();
} else {
var res = await DynamicsHttp.followUp();
if (res['status']) {
upData.value = res['data'];
if (upData.value.upList!.isEmpty) {
mid.value = -1;
}
} else {
upData.value.errMsg = res['msg'];
upData.refresh();
}
}
return res;
}
onSelectUp(mid) async {
@@ -299,8 +337,8 @@ class DynamicsController extends GetxController
}
onRefresh() async {
queryFollowUp();
await Future.wait(<Future>[
queryFollowUp(),
Get.find<DynamicsTabController>(
tag: tabsConfig[tabController.index]['tag'])
.onRefresh()

View File

@@ -1,10 +1,11 @@
import 'package:PiliPalaX/grpc/app/main/community/reply/v1/reply.pb.dart';
import 'package:PiliPalaX/http/loading_state.dart';
import 'package:PiliPalaX/pages/common/reply_controller.dart';
import 'package:PiliPalaX/utils/global_data.dart';
import 'package:PiliPlus/grpc/app/main/community/reply/v1/reply.pb.dart';
import 'package:PiliPlus/http/loading_state.dart';
import 'package:PiliPlus/pages/common/reply_controller.dart';
import 'package:PiliPlus/utils/global_data.dart';
import 'package:PiliPlus/utils/storage.dart';
import 'package:get/get.dart';
import 'package:PiliPalaX/http/html.dart';
import 'package:PiliPalaX/http/reply.dart';
import 'package:PiliPlus/http/html.dart';
import 'package:PiliPlus/http/reply.dart';
import 'package:fixnum/fixnum.dart' as $fixnum;
class DynamicDetailController extends ReplyController {
@@ -14,6 +15,8 @@ class DynamicDetailController extends ReplyController {
dynamic item;
int? floor;
late final horizontalPreview = GStorage.horizontalPreview;
@override
void onInit() {
super.onInit();

View File

@@ -1,28 +1,29 @@
import 'dart:async';
import 'dart:math';
import 'package:PiliPalaX/common/widgets/custom_sliver_persistent_header_delegate.dart';
import 'package:PiliPalaX/common/widgets/refresh_indicator.dart';
import 'package:PiliPalaX/http/loading_state.dart';
import 'package:PiliPalaX/pages/video/detail/reply/widgets/reply_item.dart';
import 'package:PiliPalaX/pages/video/detail/reply/widgets/reply_item_grpc.dart';
import 'package:PiliPalaX/utils/extension.dart';
import 'package:PiliPalaX/utils/global_data.dart';
import 'package:PiliPalaX/utils/storage.dart';
import 'package:PiliPalaX/utils/utils.dart';
import 'package:PiliPlus/common/widgets/custom_sliver_persistent_header_delegate.dart';
import 'package:PiliPlus/common/widgets/interactiveviewer_gallery/interactiveviewer_gallery.dart';
import 'package:PiliPlus/common/widgets/refresh_indicator.dart';
import 'package:PiliPlus/http/loading_state.dart';
import 'package:PiliPlus/pages/video/detail/reply/widgets/reply_item.dart';
import 'package:PiliPlus/pages/video/detail/reply/widgets/reply_item_grpc.dart';
import 'package:PiliPlus/utils/extension.dart';
import 'package:PiliPlus/utils/global_data.dart';
import 'package:PiliPlus/utils/storage.dart';
import 'package:PiliPlus/utils/utils.dart';
import 'package:easy_debounce/easy_throttle.dart';
import 'package:flutter/material.dart';
import 'package:flutter/rendering.dart';
import 'package:get/get.dart';
import 'package:PiliPalaX/common/skeleton/video_reply.dart';
import 'package:PiliPalaX/common/widgets/http_error.dart';
import 'package:PiliPalaX/models/common/reply_type.dart';
import 'package:PiliPalaX/models/dynamics/result.dart';
import 'package:PiliPalaX/pages/dynamics/detail/index.dart';
import 'package:PiliPalaX/pages/dynamics/widgets/author_panel.dart';
import 'package:PiliPalaX/pages/video/detail/reply_reply/index.dart';
import 'package:PiliPalaX/utils/feed_back.dart';
import 'package:PiliPalaX/utils/id_utils.dart';
import 'package:PiliPlus/common/skeleton/video_reply.dart';
import 'package:PiliPlus/common/widgets/http_error.dart';
import 'package:PiliPlus/models/common/reply_type.dart';
import 'package:PiliPlus/models/dynamics/result.dart';
import 'package:PiliPlus/pages/dynamics/detail/index.dart';
import 'package:PiliPlus/pages/dynamics/widgets/author_panel.dart';
import 'package:PiliPlus/pages/video/detail/reply_reply/index.dart';
import 'package:PiliPlus/utils/feed_back.dart';
import 'package:PiliPlus/utils/id_utils.dart';
import '../../../utils/grid.dart';
import '../widgets/dynamic_panel.dart';
@@ -51,6 +52,29 @@ class _DynamicDetailPageState extends State<DynamicDetailPage>
late final List<double> _ratio = GStorage.dynamicDetailRatio;
bool get _horizontalPreview =>
context.orientation == Orientation.landscape &&
_dynamicDetailController.horizontalPreview;
late final _key = GlobalKey<ScaffoldState>();
get _getImageCallback => _horizontalPreview
? (imgList, index) {
_key.currentState?.showBottomSheet(
(context) {
return InteractiveviewerGallery(
sources: imgList,
initIndex: index,
setStatusBar: false,
);
},
enableDrag: false,
elevation: 0,
backgroundColor: Colors.transparent,
);
}
: null;
@override
void initState() {
super.initState();
@@ -299,6 +323,7 @@ class _DynamicDetailPageState extends State<DynamicDetailPage>
child: DynamicPanel(
item: _dynamicDetailController.item,
source: 'detail',
callback: _getImageCallback,
),
),
replyPersistentHeader(context),
@@ -326,6 +351,7 @@ class _DynamicDetailPageState extends State<DynamicDetailPage>
child: DynamicPanel(
item: _dynamicDetailController.item,
source: 'detail',
callback: _getImageCallback,
),
),
),
@@ -335,6 +361,7 @@ class _DynamicDetailPageState extends State<DynamicDetailPage>
Expanded(
flex: _ratio[1].toInt(),
child: Scaffold(
key: _key,
body: refreshIndicator(
onRefresh: () async {
await _dynamicDetailController.onRefresh();
@@ -400,8 +427,8 @@ class _DynamicDetailPageState extends State<DynamicDetailPage>
SliverPersistentHeader replyPersistentHeader(BuildContext context) {
return SliverPersistentHeader(
delegate: CustomSliverPersistentHeaderDelegate(
bgColor: Theme.of(context).colorScheme.surface,
child: Container(
color: Theme.of(context).colorScheme.surface,
height: 45,
padding: const EdgeInsets.only(left: 12, right: 6),
child: Row(
@@ -499,6 +526,7 @@ class _DynamicDetailPageState extends State<DynamicDetailPage>
isTop:
_dynamicDetailController.hasUpTop && index == 0,
upMid: loadingState.response.subjectControl.upMid,
callback: _getImageCallback,
)
: ReplyItem(
replyItem: loadingState.response.replies[index],
@@ -515,6 +543,7 @@ class _DynamicDetailPageState extends State<DynamicDetailPage>
);
},
onDelete: _dynamicDetailController.onMDelete,
callback: _getImageCallback,
);
}
},
@@ -527,6 +556,27 @@ class _DynamicDetailPageState extends State<DynamicDetailPage>
Error() => HttpError(
errMsg: loadingState.errMsg,
callback: _dynamicDetailController.onReload,
extraWidget: GlobalData().grpcReply
? FilledButton.tonal(
onPressed: () {
GlobalData().grpcReply = false;
_dynamicDetailController.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,
),
LoadingState() => throw UnimplementedError(),
};

View File

@@ -1,7 +1,7 @@
import 'package:PiliPalaX/http/loading_state.dart';
import 'package:PiliPalaX/http/msg.dart';
import 'package:PiliPalaX/pages/common/common_controller.dart';
import 'package:PiliPalaX/pages/main/controller.dart';
import 'package:PiliPlus/http/loading_state.dart';
import 'package:PiliPlus/http/msg.dart';
import 'package:PiliPlus/pages/common/common_controller.dart';
import 'package:PiliPlus/pages/main/controller.dart';
import 'package:flutter_smart_dialog/flutter_smart_dialog.dart';
import 'package:get/get.dart';

View File

@@ -1,15 +1,15 @@
import 'dart:async';
import 'package:PiliPalaX/common/widgets/refresh_indicator.dart';
import 'package:PiliPalaX/http/loading_state.dart';
import 'package:PiliPalaX/pages/home/controller.dart';
import 'package:PiliPalaX/pages/main/controller.dart';
import 'package:PiliPalaX/utils/storage.dart';
import 'package:PiliPlus/common/widgets/refresh_indicator.dart';
import 'package:PiliPlus/http/loading_state.dart';
import 'package:PiliPlus/pages/home/controller.dart';
import 'package:PiliPlus/pages/main/controller.dart';
import 'package:PiliPlus/utils/storage.dart';
import 'package:flutter/material.dart';
import 'package:flutter/rendering.dart';
import 'package:get/get.dart';
import 'package:PiliPalaX/common/constants.dart';
import 'package:PiliPalaX/common/widgets/http_error.dart';
import 'package:PiliPlus/common/constants.dart';
import 'package:PiliPlus/common/widgets/http_error.dart';
import 'package:waterfall_flow/waterfall_flow.dart';
import '../../../common/skeleton/dynamic_card.dart';
@@ -41,7 +41,7 @@ class _DynamicsTabPageState extends State<DynamicsTabPage>
@override
void initState() {
super.initState();
dynamicsController = Get.find<DynamicsController>();
dynamicsController = Get.put(DynamicsController());
_dynamicsTabController = Get.put(
DynamicsTabController(dynamicsType: widget.dynamicsType)
..mid = dynamicsController.mid.value,

View File

@@ -1,21 +1,19 @@
import 'dart:async';
import 'dart:io';
import 'package:PiliPalaX/common/widgets/http_error.dart';
import 'package:PiliPalaX/http/msg.dart';
import 'package:PiliPalaX/models/common/dynamics_type.dart';
import 'package:PiliPalaX/models/common/up_panel_position.dart';
import 'package:PiliPalaX/pages/dynamics/tab/controller.dart';
import 'package:PiliPlus/http/msg.dart';
import 'package:PiliPlus/models/common/dynamics_type.dart';
import 'package:PiliPlus/models/common/up_panel_position.dart';
import 'package:PiliPlus/pages/dynamics/tab/controller.dart';
import 'package:easy_debounce/easy_throttle.dart';
import 'package:flutter/material.dart';
import 'package:flutter_smart_dialog/flutter_smart_dialog.dart';
import 'package:get/get.dart';
import 'package:PiliPalaX/utils/feed_back.dart';
import 'package:PiliPalaX/utils/storage.dart';
import 'package:PiliPlus/utils/feed_back.dart';
import 'package:PiliPlus/utils/storage.dart';
import 'package:image_picker/image_picker.dart';
import 'package:intl/intl.dart';
import 'package:material_design_icons_flutter/material_design_icons_flutter.dart';
import 'package:nil/nil.dart';
import 'controller.dart';
import 'widgets/up_panel.dart';
@@ -42,9 +40,7 @@ class DynamicsPage extends StatefulWidget {
class _DynamicsPageState extends State<DynamicsPage>
with AutomaticKeepAliveClientMixin, SingleTickerProviderStateMixin {
final DynamicsController _dynamicsController = Get.put(DynamicsController());
late Future _futureBuilderFutureUp;
late UpPanelPosition upPanelPosition;
StreamSubscription? _listener;
@override
bool get wantKeepAlive => true;
@@ -64,7 +60,7 @@ class _DynamicsPageState extends State<DynamicsPage>
}),
),
onPressed: () {
if (GStorage.isLogin) {
if (_dynamicsController.isLogin.value) {
showModalBottomSheet(
context: context,
useSafeArea: true,
@@ -85,24 +81,6 @@ class _DynamicsPageState extends State<DynamicsPage>
@override
void initState() {
super.initState();
_futureBuilderFutureUp = _dynamicsController.queryFollowUp();
// _dynamicsController.tabController =
// TabController(vsync: this, length: DynamicsType.values.length);
// ..addListener(() {
// if (!_dynamicsController.tabController.indexIsChanging) {
// // if (!mounted) return;
// // debugPrint('indexChanging: ${_dynamicsController.tabController.index}');
// _dynamicsController
// .onSelectType(_dynamicsController.tabController.index);
// }
// });
_listener = _dynamicsController.userLogin.listen((status) {
if (mounted) {
setState(() {
_futureBuilderFutureUp = _dynamicsController.queryFollowUp();
});
}
});
upPanelPosition = UpPanelPosition.values[GStorage.setting.get(
SettingBoxKey.upPanelPosition,
defaultValue: UpPanelPosition.leftFixed.index)];
@@ -123,7 +101,6 @@ class _DynamicsPageState extends State<DynamicsPage>
@override
void dispose() {
_listener?.cancel();
_dynamicsController.tabController.removeListener(() {});
_dynamicsController.scrollController.removeListener(() {});
super.dispose();
@@ -136,41 +113,24 @@ class _DynamicsPageState extends State<DynamicsPage>
? Theme.of(context).colorScheme.surface
: Colors.transparent,
width: 64,
child: FutureBuilder(
future: _futureBuilderFutureUp,
builder: (context, snapshot) {
if (snapshot.connectionState == ConnectionState.done) {
if (snapshot.data == null) {
return nil;
}
// TODO: refactor
if (snapshot.data is! Map) {
return HttpError(
isSliver: false,
callback: () => setState(() {
_futureBuilderFutureUp = _dynamicsController.queryFollowUp();
}),
);
}
Map data = snapshot.data;
if (data['status']) {
return Obx(() => UpPanel(_dynamicsController.upData.value,
_dynamicsController.scrollController));
} else {
return Center(
child: IconButton(
icon: Icon(Icons.refresh),
onPressed: () {
setState(() {
_futureBuilderFutureUp =
_dynamicsController.queryFollowUp();
});
},
),
);
}
child: Obx(
() {
if (_dynamicsController.upData.value.upList == null &&
_dynamicsController.upData.value.liveUsers == null) {
return const SizedBox.shrink();
} else if (_dynamicsController.upData.value.errMsg != null) {
return Center(
child: IconButton(
icon: Icon(Icons.refresh),
onPressed: () {
_dynamicsController.queryFollowUp();
},
),
);
} else {
return nil;
return UpPanel(
dynamicsController: _dynamicsController,
);
}
},
),
@@ -332,52 +292,64 @@ class _CreatePanelState extends State<CreatePanel> {
appBar: PreferredSize(
preferredSize: Size.fromHeight(66),
child: Padding(
padding: const EdgeInsets.only(top: 16, bottom: 16),
child: Row(
padding: const EdgeInsets.all(16),
child: Stack(
children: [
const SizedBox(width: 16),
SizedBox(
width: 34,
height: 34,
child: IconButton(
tooltip: '返回',
style: ButtonStyle(
padding: WidgetStateProperty.all(EdgeInsets.zero),
backgroundColor: WidgetStateProperty.resolveWith(
(states) {
return Theme.of(context).colorScheme.secondaryContainer;
},
Positioned(
top: 0,
left: 0,
bottom: 0,
child: SizedBox(
width: 34,
height: 34,
child: IconButton(
tooltip: '返回',
style: ButtonStyle(
padding: WidgetStateProperty.all(EdgeInsets.zero),
backgroundColor: WidgetStateProperty.resolveWith(
(states) {
return Theme.of(context)
.colorScheme
.secondaryContainer;
},
),
),
onPressed: Get.back,
icon: Icon(
Icons.arrow_back_outlined,
size: 18,
color: Theme.of(context).colorScheme.onSecondaryContainer,
),
),
onPressed: Get.back,
icon: Icon(
Icons.arrow_back_outlined,
size: 18,
color: Theme.of(context).colorScheme.onSecondaryContainer,
),
),
),
const Spacer(),
const Text(
'发布动态',
style: TextStyle(fontSize: 15, fontWeight: FontWeight.bold),
),
const Spacer(),
Obx(
() => FilledButton.tonal(
onPressed: _isEnablePub.value ? _onCreate : null,
style: FilledButton.styleFrom(
padding: const EdgeInsets.symmetric(
horizontal: 20, vertical: 10),
visualDensity: const VisualDensity(
horizontal: -2,
vertical: -2,
),
),
child: Text(_publishTime == null ? '发布' : '定时发布'),
Center(
child: const Text(
'发布动态',
style: TextStyle(fontSize: 15, fontWeight: FontWeight.bold),
),
),
Positioned(
top: 0,
right: 0,
child: Obx(
() => FilledButton.tonal(
onPressed: _isEnablePub.value ? _onCreate : null,
style: FilledButton.styleFrom(
tapTargetSize: MaterialTapTargetSize.shrinkWrap,
padding: const EdgeInsets.symmetric(
horizontal: 20,
vertical: 10,
),
visualDensity: const VisualDensity(
horizontal: -2,
vertical: -2,
),
),
child: Text(_publishTime == null ? '发布' : '定时发布'),
),
),
),
const SizedBox(width: 16),
],
),
),
@@ -520,78 +492,6 @@ class _CreatePanelState extends State<CreatePanel> {
mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
PopupMenuButton(
enabled: _publishTime == null,
initialValue: _isPrivate,
onSelected: (value) {
setState(() {
_isPrivate = value;
});
},
itemBuilder: (context) => List.generate(
2,
(index) => PopupMenuItem<bool>(
value: index == 0 ? false : true,
child: Row(
mainAxisSize: MainAxisSize.min,
children: [
Icon(
size: 19,
index == 0
? Icons.visibility
: Icons.visibility_off,
),
const SizedBox(width: 4),
Text(index == 0 ? '所有人可见' : '仅自己可见'),
],
),
),
),
child: Padding(
padding: const EdgeInsets.symmetric(vertical: 2),
child: Row(
mainAxisSize: MainAxisSize.min,
children: [
Icon(
size: 19,
_isPrivate
? Icons.visibility_off
: Icons.visibility,
color: _publishTime == null
? _isPrivate
? Theme.of(context).colorScheme.error
: Theme.of(context).colorScheme.primary
: Theme.of(context).colorScheme.outline,
),
const SizedBox(width: 4),
Text(
_isPrivate ? '仅自己可见' : '所有人可见',
style: TextStyle(
height: 1,
color: _publishTime == null
? _isPrivate
? Theme.of(context).colorScheme.error
: Theme.of(context)
.colorScheme
.primary
: Theme.of(context).colorScheme.outline,
),
strutStyle: StrutStyle(leading: 0, height: 1),
),
Icon(
size: 20,
Icons.keyboard_arrow_right,
color: _publishTime == null
? _isPrivate
? Theme.of(context).colorScheme.error
: Theme.of(context).colorScheme.primary
: Theme.of(context).colorScheme.outline,
),
],
),
),
),
const SizedBox(height: 5),
PopupMenuButton(
initialValue: _replyOption,
onSelected: (item) {
@@ -627,7 +527,7 @@ class _CreatePanelState extends State<CreatePanel> {
_replyOption.iconData,
color: _replyOption == ReplyOption.close
? Theme.of(context).colorScheme.error
: Theme.of(context).colorScheme.primary,
: Theme.of(context).colorScheme.secondary,
),
const SizedBox(width: 4),
Text(
@@ -636,7 +536,7 @@ class _CreatePanelState extends State<CreatePanel> {
height: 1,
color: _replyOption == ReplyOption.close
? Theme.of(context).colorScheme.error
: Theme.of(context).colorScheme.primary,
: Theme.of(context).colorScheme.secondary,
),
strutStyle: StrutStyle(leading: 0, height: 1),
),
@@ -645,7 +545,73 @@ class _CreatePanelState extends State<CreatePanel> {
Icons.keyboard_arrow_right,
color: _replyOption == ReplyOption.close
? Theme.of(context).colorScheme.error
: Theme.of(context).colorScheme.primary,
: Theme.of(context).colorScheme.secondary,
),
],
),
),
),
const SizedBox(height: 5),
PopupMenuButton(
initialValue: _isPrivate,
onSelected: (value) {
setState(() {
_isPrivate = value;
});
},
itemBuilder: (context) => List.generate(
2,
(index) => PopupMenuItem<bool>(
enabled: _publishTime != null && index == 1
? false
: true,
value: index == 0 ? false : true,
child: Row(
mainAxisSize: MainAxisSize.min,
children: [
Icon(
size: 19,
index == 0
? Icons.visibility
: Icons.visibility_off,
),
const SizedBox(width: 4),
Text(index == 0 ? '所有人可见' : '仅自己可见'),
],
),
),
),
child: Padding(
padding: const EdgeInsets.symmetric(vertical: 2),
child: Row(
mainAxisSize: MainAxisSize.min,
children: [
Icon(
size: 19,
_isPrivate
? Icons.visibility_off
: Icons.visibility,
color: _isPrivate
? Theme.of(context).colorScheme.error
: Theme.of(context).colorScheme.secondary,
),
const SizedBox(width: 4),
Text(
_isPrivate ? '仅自己可见' : '所有人可见',
style: TextStyle(
height: 1,
color: _isPrivate
? Theme.of(context).colorScheme.error
: Theme.of(context).colorScheme.secondary,
),
strutStyle: StrutStyle(leading: 0, height: 1),
),
Icon(
size: 20,
Icons.keyboard_arrow_right,
color: _isPrivate
? Theme.of(context).colorScheme.error
: Theme.of(context).colorScheme.secondary,
),
],
),

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