dbca8811
吴启风
fix: 修复视频兼容性并增加渲染...
|
1
2
|
import 'dart:async';
|
383462ef
吴启风
feat: 新增视频专区列表与播放功能
|
3
4
|
import 'package:cached_network_image/cached_network_image.dart';
import 'package:flutter/material.dart';
|
383462ef
吴启风
feat: 新增视频专区列表与播放功能
|
5
6
7
8
9
|
import 'package:flutter_screenutil/flutter_screenutil.dart';
import 'package:wow_english/common/dialogs/show_dialog.dart';
import 'package:wow_english/common/request/dao/video_dao.dart';
import 'package:wow_english/common/widgets/we_app_bar.dart';
import 'package:wow_english/route/route.dart';
|
dbca8811
吴启风
fix: 修复视频兼容性并增加渲染...
|
10
|
import 'package:wow_english/utils/toast_util.dart';
|
383462ef
吴启风
feat: 新增视频专区列表与播放功能
|
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
|
import 'video_zone_item.dart';
class VideoZonePage extends StatefulWidget {
const VideoZonePage({super.key});
@override
State<VideoZonePage> createState() => _VideoZonePageState();
}
class _VideoZonePageState extends State<VideoZonePage> {
late Future<List<VideoZoneItem>> _itemsFuture;
@override
void initState() {
super.initState();
|
dbca8811
吴启风
fix: 修复视频兼容性并增加渲染...
|
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
|
_itemsFuture = _loadItems();
}
Future<List<VideoZoneItem>> _loadItems() async {
try {
return await VideoDao.list().timeout(const Duration(seconds: 10));
} on TimeoutException catch (error) {
debugPrint('获取视频列表超时: $error');
showToast('视频列表加载超时,请检查网络后重试');
rethrow;
} catch (error) {
debugPrint('获取视频列表失败: $error');
showToast('视频列表加载失败,请稍后重试');
rethrow;
}
|
383462ef
吴启风
feat: 新增视频专区列表与播放功能
|
42
43
|
}
|
383462ef
吴启风
feat: 新增视频专区列表与播放功能
|
44
|
void _reload() {
|
9475aa49
吴启风
feat: 优化视频专区列表布局与...
|
45
|
setState(() {
|
dbca8811
吴启风
fix: 修复视频兼容性并增加渲染...
|
46
|
_itemsFuture = _loadItems();
|
9475aa49
吴启风
feat: 优化视频专区列表布局与...
|
47
|
});
|
383462ef
吴启风
feat: 新增视频专区列表与播放功能
|
48
49
50
51
|
}
@override
Widget build(BuildContext context) {
|
5bc84eff
吴启风
Revert "feat: 优化视...
|
52
|
return Scaffold(
|
dbca8811
吴启风
fix: 修复视频兼容性并增加渲染...
|
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
|
backgroundColor: Colors.white,
appBar: const WEAppBar(
titleText: '视频专区',
centerTitle: false,
),
body: FutureBuilder<List<VideoZoneItem>>(
future: _itemsFuture,
builder: (context, snapshot) {
if (snapshot.connectionState == ConnectionState.waiting) {
return const Center(child: CircularProgressIndicator());
}
if (snapshot.hasError) {
return _VideoLoadError(onRetry: _reload);
}
final items = snapshot.data ?? const <VideoZoneItem>[];
if (items.isEmpty) {
return const Center(
child: Text(
'暂无视频',
style: TextStyle(color: Color(0xFF999999), fontSize: 18),
|
383462ef
吴启风
feat: 新增视频专区列表与播放功能
|
73
74
|
),
);
|
dbca8811
吴启风
fix: 修复视频兼容性并增加渲染...
|
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
|
}
return RefreshIndicator(
onRefresh: () async {
final future = _loadItems();
setState(() => _itemsFuture = future);
try {
await future;
} catch (_) {
// The FutureBuilder shows the error state; _loadItems already toasts it.
}
},
child: LayoutBuilder(
builder: (context, constraints) {
final titleStyle = _VideoCard.createTitleStyle(context);
return GridView.builder(
physics: const AlwaysScrollableScrollPhysics(),
padding: EdgeInsets.fromLTRB(
14.w,
10.h,
14.w,
16.h,
),
gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
crossAxisCount: 4,
mainAxisSpacing: 14.h,
crossAxisSpacing: 12.w,
childAspectRatio: 1.55,
),
itemCount: items.length,
itemBuilder: (context, index) => _VideoCard(
item: items[index],
onTap: () => _openVideo(items, index),
titleStyle: titleStyle,
),
);
},
),
);
},
),
);
|
383462ef
吴启风
feat: 新增视频专区列表与播放功能
|
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
|
}
void _openVideo(List<VideoZoneItem> items, int index) {
final item = items[index];
if (!item.accessible || item.videoUrl.isEmpty) {
showTwoActionDialog('提示', '取消', '去购买', '购买课程后即可观看视频。', leftTap: popPage,
rightTap: () {
popPage();
pushNamed(AppRouteName.shop);
});
return;
}
Navigator.of(context).pushNamed(
AppRouteName.videoZonePlayer,
arguments: {
'items': items
.where((video) => video.accessible && video.videoUrl.isNotEmpty)
.toList(),
'initialVideoId': item.id,
},
|
5bc84eff
吴启风
Revert "feat: 优化视...
|
136
|
).then((_) => _reload());
|
383462ef
吴启风
feat: 新增视频专区列表与播放功能
|
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
|
}
}
class _VideoLoadError extends StatelessWidget {
const _VideoLoadError({required this.onRetry});
final VoidCallback onRetry;
@override
Widget build(BuildContext context) {
return Center(
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
const Text(
'视频加载失败,请稍后重试',
style: TextStyle(color: Color(0xFF999999), fontSize: 18),
),
const SizedBox(height: 12),
FilledButton(onPressed: onRetry, child: const Text('重新加载')),
],
),
);
}
}
class _VideoCard extends StatelessWidget {
|
54f62f82
吴启风
fix: 自适应视频标题高度避免文字裁切
|
164
165
166
167
168
|
const _VideoCard({
required this.item,
required this.onTap,
required this.titleStyle,
});
|
383462ef
吴启风
feat: 新增视频专区列表与播放功能
|
169
170
171
|
final VideoZoneItem item;
final VoidCallback onTap;
|
54f62f82
吴启风
fix: 自适应视频标题高度避免文字裁切
|
172
173
174
175
176
177
178
179
|
final TextStyle titleStyle;
static TextStyle createTitleStyle(BuildContext context) => TextStyle(
color: const Color(0xFF222222),
fontFamily: null,
fontSize: 17.sp,
fontWeight: FontWeight.w500,
);
|
383462ef
吴启风
feat: 新增视频专区列表与播放功能
|
180
181
182
183
|
@override
Widget build(BuildContext context) {
return InkWell(
|
c67962ab
吴启风
feat: 视频卡片点击区域和封面...
|
184
|
borderRadius: BorderRadius.circular(12.r),
|
383462ef
吴启风
feat: 新增视频专区列表与播放功能
|
185
186
187
188
|
onTap: onTap,
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
|
5bc84eff
吴启风
Revert "feat: 优化视...
|
189
|
Expanded(
|
383462ef
吴启风
feat: 新增视频专区列表与播放功能
|
190
|
child: ClipRRect(
|
c67962ab
吴启风
feat: 视频卡片点击区域和封面...
|
191
|
borderRadius: BorderRadius.circular(12.r),
|
9475aa49
吴启风
feat: 优化视频专区列表布局与...
|
192
193
194
195
196
197
198
199
200
201
202
203
|
child: CachedNetworkImage(
imageUrl: item.coverUrl,
fit: BoxFit.cover,
placeholder: (_, __) => const ColoredBox(
color: Color(0xFFF2F2F2),
child: Center(child: CircularProgressIndicator()),
),
errorWidget: (_, __, ___) => const ColoredBox(
color: Color(0xFFF2F2F2),
child: Icon(Icons.broken_image_outlined,
color: Color(0xFFAAAAAA)),
),
|
383462ef
吴启风
feat: 新增视频专区列表与播放功能
|
204
205
206
207
|
),
),
),
SizedBox(height: 5.h),
|
54f62f82
吴启风
fix: 自适应视频标题高度避免文字裁切
|
208
209
210
211
212
|
Text(
item.title,
maxLines: 1,
overflow: TextOverflow.ellipsis,
style: titleStyle,
|
383462ef
吴启风
feat: 新增视频专区列表与播放功能
|
213
214
215
216
217
218
|
),
],
),
);
}
}
|