Blame view

lib/pages/video/zone/video_zone_page.dart 6.45 KB
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
            ),
          ],
        ),
      );
    }
  }