Skip to content

Commit f9ac579

Browse files
committed
完成历史纪录
1 parent 57cfff9 commit f9ac579

File tree

4 files changed

+99
-38
lines changed

4 files changed

+99
-38
lines changed

lib/collection/episode_collections.dart

Lines changed: 62 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,14 @@ import 'package:ikaros/api/collection/model/EpisodeCollection.dart';
88
import 'package:ikaros/api/common/PagingWrap.dart';
99
import 'package:ikaros/api/subject/EpisodeApi.dart';
1010
import 'package:ikaros/api/subject/SubjectApi.dart';
11+
import 'package:ikaros/api/subject/enums/EpisodeGroup.dart';
1112
import 'package:ikaros/api/subject/model/Episode.dart';
1213
import '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

1420
class 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
],

lib/subject/episode.dart

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,8 +34,10 @@ import 'package:intl/intl.dart';
3434

3535
class SubjectEpisodesPage extends StatefulWidget {
3636
final int subjectId;
37+
final double? selectEpisodeSequence;
38+
final String? selectEpisodeGroup;
3739

38-
const SubjectEpisodesPage({super.key, required this.subjectId});
40+
const SubjectEpisodesPage({super.key, required this.subjectId, this.selectEpisodeGroup, this.selectEpisodeSequence});
3941

4042
@override
4143
State<StatefulWidget> createState() {
@@ -85,6 +87,16 @@ class _SubjectEpisodesState extends State<SubjectEpisodesPage> {
8587
.where((epRecord) => epRecord.resources.isNotEmpty)
8688
.where((epRecord) => epRecord.episode.group == EpisodeGroup.MAIN.name)
8789
.firstOrNull;
90+
// 如果指定了剧集参数,则使用剧集参数覆盖当前剧集
91+
if (widget.selectEpisodeSequence != null && widget.selectEpisodeGroup != null) {
92+
var newSelectEpisodeRecord = _episodeRecords
93+
.where((epRecord) => widget.selectEpisodeGroup == epRecord.episode.group
94+
&& widget.selectEpisodeSequence == epRecord.episode.sequence
95+
&& epRecord.resources.isNotEmpty).firstOrNull;
96+
if (newSelectEpisodeRecord != null) {
97+
_currentEpisodeRecord.value = newSelectEpisodeRecord;
98+
}
99+
}
88100
setState(() {});
89101
}
90102

lib/utils/string_utils.dart

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
class StringUtils {
2+
static String emptyHint(String? original, String hintElse) {
3+
if (original == null || original == '' || original.trim() == '') {
4+
return hintElse;
5+
}
6+
return original;
7+
}
8+
}

lib/utils/time_utils.dart

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,10 +9,25 @@ class TimeUtils {
99
return '$minutes 分 $seconds 秒';
1010
}
1111

12-
String formatDateString(String isoDate) {
12+
static String formatDateString(String isoDate) {
1313
// 解析 ISO 8601 格式的日期字符串
1414
DateTime dateTime = DateTime.parse(isoDate);
1515
// 格式化为“年-月-日”格式
1616
return DateFormat('yyyy-MM-dd').format(dateTime);
1717
}
18+
19+
static String formatDateStringWithPattern(String isoDate, String pattern) {
20+
// 解析 ISO 8601 格式的日期字符串
21+
DateTime dateTime = DateTime.parse(isoDate);
22+
// 格式化为“年-月-日”格式
23+
return DateFormat(pattern).format(dateTime);
24+
}
25+
26+
static String formatDuration(int milliseconds) {
27+
final duration = Duration(milliseconds: milliseconds);
28+
final minutes = duration.inMinutes;
29+
final seconds = duration.inSeconds.remainder(60);
30+
31+
return '${minutes}分${seconds}秒';
32+
}
1833
}

0 commit comments

Comments
 (0)