@@ -8,8 +8,14 @@ import 'package:ikaros/api/collection/model/EpisodeCollection.dart';
88import 'package:ikaros/api/common/PagingWrap.dart' ;
99import 'package:ikaros/api/subject/EpisodeApi.dart' ;
1010import 'package:ikaros/api/subject/SubjectApi.dart' ;
11+ import 'package:ikaros/api/subject/enums/EpisodeGroup.dart' ;
1112import 'package:ikaros/api/subject/model/Episode.dart' ;
1213import 'package:ikaros/api/subject/model/Subject.dart' ;
14+ import 'package:ikaros/consts/subject_const.dart' ;
15+ import 'package:ikaros/subject/episode.dart' ;
16+ import 'package:ikaros/utils/message_utils.dart' ;
17+ import 'package:ikaros/utils/string_utils.dart' ;
18+ import 'package:ikaros/utils/time_utils.dart' ;
1319
1420class EpisodeCollectionsPage extends StatefulWidget {
1521 @override
@@ -24,7 +30,7 @@ class EpisodeCollectionsPageState extends State<EpisodeCollectionsPage> {
2430 late final ScrollController _easyRefreshScrollController = ScrollController ();
2531 List <HistoryItem > _historyItems = [];
2632 int _currentPage = 1 ;
27- int _currentSize = 10 ;
33+ final int _currentSize = 10 ;
2834 bool _hasMore = true ;
2935 String _apiBaseUrl = "" ;
3036
@@ -51,7 +57,6 @@ class EpisodeCollectionsPageState extends State<EpisodeCollectionsPage> {
5157 });
5258 }
5359
54-
5560 Future <void > _loadData () async {
5661 await _loadApiBaseUrl ();
5762
@@ -65,7 +70,8 @@ class EpisodeCollectionsPageState extends State<EpisodeCollectionsPage> {
6570 EpisodeCollection epCol = EpisodeCollection .fromJson (epColMap);
6671 Subject ? subject = await SubjectApi ().findById (epCol.subjectId ?? 0 );
6772 Episode ? episode = await EpisodeApi ().findById (epCol.episodeId);
68- var item = HistoryItem (episodeCollection: epCol, subject: subject, episode: episode);
73+ var item = HistoryItem (
74+ episodeCollection: epCol, subject: subject, episode: episode);
6975 newItems.add (item);
7076 }
7177 }
@@ -77,6 +83,8 @@ class EpisodeCollectionsPageState extends State<EpisodeCollectionsPage> {
7783 if (mounted) {
7884 _hasMore = false ;
7985 }
86+ } else {
87+ _hasMore = true ;
8088 }
8189 });
8290 }
@@ -115,34 +123,42 @@ class EpisodeCollectionsPageState extends State<EpisodeCollectionsPage> {
115123 _easyRefreshController.finishLoad (success: true , noMore: ! _hasMore);
116124 _easyRefreshController.resetLoadState ();
117125 },
118- child: ListView .builder (
119- itemCount: _historyItems.length,
120- itemBuilder: (context, index) {
121- return _buildHistoryItem (_historyItems[index]);
122- },
123- ),
126+ child: _buildListView (),
124127 ),
125128 );
126129 }
127130
128- Future <HistoryItem > _loadHistoryItemWithCollection (
129- EpisodeCollection collection) async {
130- Subject ? subject = await SubjectApi ().findById (collection.subjectId ?? 0 );
131- Episode ? episode = await EpisodeApi ().findById (collection.episodeId);
132- return HistoryItem (
133- episodeCollection: collection, subject: subject, episode: episode);
131+ Widget _buildListView () {
132+ if (_currentPage == 1 && _historyItems.isEmpty) {
133+ return const LinearProgressIndicator ();
134+ }
135+ return ListView .builder (
136+ itemCount: _historyItems.length,
137+ itemBuilder: (context, index) {
138+ return _buildHistoryItem (_historyItems[index]);
139+ },
140+ );
141+ }
142+
143+ void _handleItemClick (HistoryItem item) async {
144+ final Subject ? subject = item.subject;
145+ final Episode ? episode = item.episode;
146+ Navigator .of (context).push (MaterialPageRoute (
147+ builder: (context) => SubjectEpisodesPage (
148+ subjectId: subject! .id,
149+ selectEpisodeGroup: episode? .group,
150+ selectEpisodeSequence: episode? .sequence,
151+ )));
134152 }
135153
136154 Widget _buildHistoryItem (HistoryItem item) {
137- Subject ? subject = item.subject;
138- Episode ? episode = item.episode;
155+ final Subject ? subject = item.subject;
156+ final Episode ? episode = item.episode;
139157 return Card (
158+ key: ValueKey (item),
140159 margin: const EdgeInsets .symmetric (horizontal: 10 , vertical: 5 ),
141160 child: InkWell (
142- onTap: () {
143- // 处理点击事件
144- //print('点击了 ${item.title}');
145- },
161+ onTap: () => _handleItemClick (item),
146162 child: Padding (
147163 padding: const EdgeInsets .all (10 ),
148164 child: Column (
@@ -179,7 +195,7 @@ class EpisodeCollectionsPageState extends State<EpisodeCollectionsPage> {
179195 Row (
180196 children: [
181197 Text (
182- (episode? .sequence ?? "" ).toString (),
198+ (episode? .sequence. toInt () ?? "" ).toString (),
183199 style: const TextStyle (
184200 fontSize: 16 ,
185201 fontWeight: FontWeight .bold,
@@ -189,7 +205,8 @@ class EpisodeCollectionsPageState extends State<EpisodeCollectionsPage> {
189205 const SizedBox (width: 8 ),
190206 Expanded (
191207 child: Text (
192- episode? .name ?? "剧集无名称" ,
208+ StringUtils .emptyHint (
209+ episode? .nameCn ?? episode? .name, "剧集无名称" ),
193210 style: const TextStyle (
194211 fontSize: 16 ,
195212 fontWeight: FontWeight .bold,
@@ -200,33 +217,43 @@ class EpisodeCollectionsPageState extends State<EpisodeCollectionsPage> {
200217 ),
201218 ],
202219 ),
203- SizedBox (height: 4 ),
220+ const SizedBox (height: 4 ),
204221 // 第一行描述
205222 Text (
206- episode? .description ?? "剧集无描述" ,
223+ StringUtils . emptyHint ( episode? .description, "剧集无描述" ) ,
207224 style: TextStyle (
208225 fontSize: 14 ,
209226 color: Colors .grey[600 ],
210227 ),
211- maxLines: 2 ,
228+ maxLines: 1 ,
212229 overflow: TextOverflow .ellipsis,
213230 ),
214231 const SizedBox (height: 4 ),
215232 // 观看信息
216233 Text (
217- "当前为${episode ?.group ?? "正片" }第${episode ?.sequence ?? -1 }话" ,
218- style: TextStyle (
219- fontSize: 12 ,
220- color: Colors .grey[700 ],
234+ "条目《${subject .nameCn ?? subject .name }》的[${SubjectConst .episodeGroupCnMap [episode ?.group ?? "MAIN" ]}] 第[${episode ?.sequence .toInt () ?? -1 }]话" ,
235+ style: const TextStyle (
236+ fontSize: 14 ,
237+ color: Colors .blueAccent,
238+ ),
239+ ),
240+ const SizedBox (height: 2 ),
241+ Text (
242+ "观看进度: ${TimeUtils .formatDuration (item .episodeCollection .progress ?? 0 )} 总时长: ${TimeUtils .formatDuration (item .episodeCollection .duration ?? 0 )}" ,
243+ style: const TextStyle (
244+ fontSize: 14 ,
245+ color: Colors .blue,
221246 ),
222247 ),
223248 const SizedBox (height: 2 ),
249+ // const Spacer(),
224250 // 更新时间
225251 Text (
226- '更新于 ${item .episodeCollection .updateTime }' ,
227- style: TextStyle (
228- fontSize: 11 ,
229- color: Colors .grey[500 ],
252+ '更新于 ${TimeUtils .formatDateStringWithPattern (item .episodeCollection .updateTime .toString (), 'yyyy年MM月dd日 HH时mm分ss秒' )}' ,
253+ style: const TextStyle (
254+ fontSize: 15 ,
255+ color: Colors .black87,
256+ fontWeight: FontWeight .bold,
230257 ),
231258 ),
232259 ],
@@ -240,8 +267,7 @@ class EpisodeCollectionsPageState extends State<EpisodeCollectionsPage> {
240267 value: ((item.episodeCollection.progress ?? 0 ) /
241268 (item.episodeCollection.duration ?? 1 )),
242269 backgroundColor: Colors .grey[200 ],
243- valueColor:
244- const AlwaysStoppedAnimation <Color >(Colors .blue),
270+ valueColor: const AlwaysStoppedAnimation <Color >(Colors .blue),
245271 minHeight: 2 ,
246272 ),
247273 ],
0 commit comments