Commit 6f61743479801b967bad9cbdad2f4daaab64484f
1 parent
2a427e12
feat:磨耳朵/视频跟读列表页接口调整
Showing
19 changed files
with
288 additions
and
126 deletions
lib/common/request/dao/home_dao.dart
lib/common/request/dao/listen_dao.dart
1 | 1 | import 'package:wow_english/common/request/apis.dart'; |
2 | 2 | import 'package:wow_english/common/request/request_client.dart'; |
3 | +import 'package:wow_english/models/follow_read_entity.dart'; | |
4 | +import 'package:wow_english/models/listen_entity.dart'; | |
3 | 5 | |
4 | 6 | class ListenDao { |
5 | 7 | /// 磨耳朵 |
6 | - static Future listen() async { | |
7 | - var data = await requestClient.get(Apis.ears); | |
8 | + static Future<List<ListenEntity?>?> listen() async { | |
9 | + var data = await requestClient.get<List<ListenEntity?>>(Apis.ears); | |
10 | + return data; | |
11 | + } | |
12 | + | |
13 | + ///视频跟读 | |
14 | + static Future<List<FollowReadEntity?>?> followRead() async { | |
15 | + var data = await requestClient.get<List<FollowReadEntity?>>(Apis.followRead); | |
8 | 16 | return data; |
9 | 17 | } |
10 | 18 | } |
11 | 19 | \ No newline at end of file | ... | ... |
lib/common/widgets/ow_image_widget.dart
0 → 100644
1 | +import 'package:cached_network_image/cached_network_image.dart'; | |
2 | +import 'package:flutter/material.dart'; | |
3 | + | |
4 | +class OwImageWidget extends StatelessWidget { | |
5 | + const OwImageWidget({super.key, this.width, this.height, required this.name, this.fit}); | |
6 | + final double? width; | |
7 | + final double? height; | |
8 | + final BoxFit? fit; | |
9 | + final String name; | |
10 | + | |
11 | + @override | |
12 | + Widget build(BuildContext context) { | |
13 | + if (name.isEmpty) { | |
14 | + return SizedBox( | |
15 | + height: height, | |
16 | + width: width, | |
17 | + ); | |
18 | + } | |
19 | + return name.contains('http')? | |
20 | + CachedNetworkImage( | |
21 | + imageUrl: name, | |
22 | + height: height, | |
23 | + width: width, | |
24 | + fit: fit, | |
25 | + ):Image.asset( | |
26 | + name, | |
27 | + height: height, | |
28 | + width: width, | |
29 | + fit: fit, | |
30 | + ); | |
31 | + } | |
32 | +} | |
0 | 33 | \ No newline at end of file | ... | ... |
lib/generated/json/base/json_convert_content.dart
... | ... | @@ -4,6 +4,7 @@ |
4 | 4 | |
5 | 5 | // This file is automatically generated. DO NOT EDIT, all your changes would be lost. |
6 | 6 | import 'package:flutter/material.dart' show debugPrint; |
7 | +import 'package:wow_english/models/follow_read_entity.dart'; | |
7 | 8 | import 'package:wow_english/models/course_entity.dart'; |
8 | 9 | import 'package:wow_english/models/course_module_entity.dart'; |
9 | 10 | import 'package:wow_english/models/listen_entity.dart'; |
... | ... | @@ -15,6 +16,7 @@ typedef EnumConvertFunction<T> = T Function(String value); |
15 | 16 | |
16 | 17 | class JsonConvert { |
17 | 18 | static final Map<String, JsonConvertFunction> convertFuncMap = { |
19 | + (FollowReadEntity).toString(): FollowReadEntity.fromJson, | |
18 | 20 | (CourseEntity).toString(): CourseEntity.fromJson, |
19 | 21 | (CourseCourseLessons).toString(): CourseCourseLessons.fromJson, |
20 | 22 | (CourseModuleEntity).toString(): CourseModuleEntity.fromJson, |
... | ... | @@ -98,6 +100,9 @@ List<T>? convertListNotNull<T>(dynamic value, {EnumConvertFunction? enumConvert} |
98 | 100 | |
99 | 101 | //list is returned by type |
100 | 102 | static M? _getListChildType<M>(List<Map<String, dynamic>> data) { |
103 | + if(<FollowReadEntity>[] is M){ | |
104 | + return data.map<FollowReadEntity>((Map<String, dynamic> e) => FollowReadEntity.fromJson(e)).toList() as M; | |
105 | + } | |
101 | 106 | if(<CourseEntity>[] is M){ |
102 | 107 | return data.map<CourseEntity>((Map<String, dynamic> e) => CourseEntity.fromJson(e)).toList() as M; |
103 | 108 | } | ... | ... |
lib/generated/json/follow_read_entity.g.dart
0 → 100644
1 | +import 'package:wow_english/generated/json/base/json_convert_content.dart'; | |
2 | +import 'package:wow_english/models/follow_read_entity.dart'; | |
3 | + | |
4 | +FollowReadEntity $FollowReadEntityFromJson(Map<String, dynamic> json) { | |
5 | + final FollowReadEntity followReadEntity = FollowReadEntity(); | |
6 | + final String? coverUrl = jsonConvert.convert<String>(json['coverUrl']); | |
7 | + if (coverUrl != null) { | |
8 | + followReadEntity.coverUrl = coverUrl; | |
9 | + } | |
10 | + final String? createTime = jsonConvert.convert<String>(json['createTime']); | |
11 | + if (createTime != null) { | |
12 | + followReadEntity.createTime = createTime; | |
13 | + } | |
14 | + final String? deleted = jsonConvert.convert<String>(json['deleted']); | |
15 | + if (deleted != null) { | |
16 | + followReadEntity.deleted = deleted; | |
17 | + } | |
18 | + final String? id = jsonConvert.convert<String>(json['id']); | |
19 | + if (id != null) { | |
20 | + followReadEntity.id = id; | |
21 | + } | |
22 | + final bool? lock = jsonConvert.convert<bool>(json['lock']); | |
23 | + if (lock != null) { | |
24 | + followReadEntity.lock = lock; | |
25 | + } | |
26 | + final String? modifyTime = jsonConvert.convert<String>(json['modifyTime']); | |
27 | + if (modifyTime != null) { | |
28 | + followReadEntity.modifyTime = modifyTime; | |
29 | + } | |
30 | + final int? sortOrder = jsonConvert.convert<int>(json['sortOrder']); | |
31 | + if (sortOrder != null) { | |
32 | + followReadEntity.sortOrder = sortOrder; | |
33 | + } | |
34 | + final int? star = jsonConvert.convert<int>(json['star']); | |
35 | + if (star != null) { | |
36 | + followReadEntity.star = star; | |
37 | + } | |
38 | + final int? status = jsonConvert.convert<int>(json['status']); | |
39 | + if (status != null) { | |
40 | + followReadEntity.status = status; | |
41 | + } | |
42 | + final String? title = jsonConvert.convert<String>(json['title']); | |
43 | + if (title != null) { | |
44 | + followReadEntity.title = title; | |
45 | + } | |
46 | + final int? videoTotal = jsonConvert.convert<int>(json['videoTotal']); | |
47 | + if (videoTotal != null) { | |
48 | + followReadEntity.videoTotal = videoTotal; | |
49 | + } | |
50 | + return followReadEntity; | |
51 | +} | |
52 | + | |
53 | +Map<String, dynamic> $FollowReadEntityToJson(FollowReadEntity entity) { | |
54 | + final Map<String, dynamic> data = <String, dynamic>{}; | |
55 | + data['coverUrl'] = entity.coverUrl; | |
56 | + data['createTime'] = entity.createTime; | |
57 | + data['deleted'] = entity.deleted; | |
58 | + data['id'] = entity.id; | |
59 | + data['lock'] = entity.lock; | |
60 | + data['modifyTime'] = entity.modifyTime; | |
61 | + data['sortOrder'] = entity.sortOrder; | |
62 | + data['star'] = entity.star; | |
63 | + data['status'] = entity.status; | |
64 | + data['title'] = entity.title; | |
65 | + data['videoTotal'] = entity.videoTotal; | |
66 | + return data; | |
67 | +} | |
0 | 68 | \ No newline at end of file | ... | ... |
lib/models/follow_read_entity.dart
0 → 100644
1 | +import 'package:wow_english/generated/json/base/json_field.dart'; | |
2 | +import 'package:wow_english/generated/json/follow_read_entity.g.dart'; | |
3 | +import 'dart:convert'; | |
4 | + | |
5 | +@JsonSerializable() | |
6 | +class FollowReadEntity { | |
7 | + String? coverUrl; | |
8 | + String? createTime; | |
9 | + String? deleted; | |
10 | + String? id; | |
11 | + bool? lock; | |
12 | + String? modifyTime; | |
13 | + int? sortOrder; | |
14 | + int? star; | |
15 | + int? status; | |
16 | + String? title; | |
17 | + int? videoTotal; | |
18 | + | |
19 | + FollowReadEntity(); | |
20 | + | |
21 | + factory FollowReadEntity.fromJson(Map<String, dynamic> json) => $FollowReadEntityFromJson(json); | |
22 | + | |
23 | + Map<String, dynamic> toJson() => $FollowReadEntityToJson(this); | |
24 | + | |
25 | + @override | |
26 | + String toString() { | |
27 | + return jsonEncode(this); | |
28 | + } | |
29 | +} | |
0 | 30 | \ No newline at end of file | ... | ... |
lib/pages/home/home_page.dart
1 | 1 | import 'package:flutter/material.dart'; |
2 | 2 | import 'package:flutter_bloc/flutter_bloc.dart'; |
3 | +import 'package:flutter_easyloading/flutter_easyloading.dart'; | |
3 | 4 | import 'package:flutter_screenutil/flutter_screenutil.dart'; |
4 | 5 | import 'package:wow_english/common/extension/string_extension.dart'; |
5 | 6 | import 'package:wow_english/models/course_entity.dart'; |
... | ... | @@ -75,15 +76,30 @@ class _HomePageView extends StatelessWidget { |
75 | 76 | itemCount: bloc.modelData?.totalCourseLesson, |
76 | 77 | scrollDirection: Axis.horizontal, |
77 | 78 | itemBuilder: (BuildContext context, int index){ |
78 | - String? title = bloc.modelData?.courseLessons?[index]?.name; | |
79 | 79 | CourseCourseLessons? data = bloc.modelData?.courseLessons?[index]; |
80 | 80 | if (data?.courseType == 5) {//彩蛋 |
81 | - return HomeBoundsItem( | |
82 | - imageUrl: data?.coverUrl, | |
81 | + return GestureDetector( | |
82 | + onTap: (){ | |
83 | + if (data!.lock!) { | |
84 | + return; | |
85 | + } | |
86 | + EasyLoading.showToast('点击事件'); | |
87 | + }, | |
88 | + child: HomeBoundsItem( | |
89 | + imageUrl: data?.coverUrl, | |
90 | + ), | |
83 | 91 | ); |
84 | 92 | } else { |
85 | - return HomeVideoItem( | |
86 | - lessons: data, | |
93 | + return GestureDetector( | |
94 | + onTap: () { | |
95 | + if (data!.lock!) { | |
96 | + return; | |
97 | + } | |
98 | + EasyLoading.showToast('点击事件'); | |
99 | + }, | |
100 | + child: HomeVideoItem( | |
101 | + lessons: data, | |
102 | + ), | |
87 | 103 | ); |
88 | 104 | } |
89 | 105 | }) | ... | ... |
lib/pages/home/widgets/home_bouns_item.dart
1 | 1 | import 'package:flutter/cupertino.dart'; |
2 | 2 | import 'package:flutter_screenutil/flutter_screenutil.dart'; |
3 | +import 'package:wow_english/common/widgets/ow_image_widget.dart'; | |
3 | 4 | |
4 | 5 | class HomeBoundsItem extends StatelessWidget { |
5 | 6 | const HomeBoundsItem({super.key, this.imageUrl}); |
... | ... | @@ -11,7 +12,7 @@ class HomeBoundsItem extends StatelessWidget { |
11 | 12 | return SizedBox( |
12 | 13 | height: 207.h, |
13 | 14 | width: 169.w, |
14 | - child: Image.network(imageUrl??''), | |
15 | + child: OwImageWidget(name:imageUrl??''), | |
15 | 16 | ); |
16 | 17 | } |
17 | 18 | } |
18 | 19 | \ No newline at end of file | ... | ... |
lib/pages/home/widgets/home_lesson_item_widget.dart deleted
1 | -import 'package:flutter/material.dart'; | |
2 | -import 'package:flutter_screenutil/flutter_screenutil.dart'; | |
3 | - | |
4 | -class HomeLessonItem extends StatelessWidget { | |
5 | - const HomeLessonItem({super.key}); | |
6 | - | |
7 | - @override | |
8 | - Widget build(BuildContext context) { | |
9 | - return SizedBox( | |
10 | - width: 200, | |
11 | - child: ListView.builder( | |
12 | - itemCount: 5, | |
13 | - scrollDirection: Axis.horizontal, | |
14 | - physics: const NeverScrollableScrollPhysics(), | |
15 | - itemBuilder: (BuildContext context,int index){ | |
16 | - return Padding( | |
17 | - padding: EdgeInsets.symmetric(horizontal: 4.w), | |
18 | - child: Image.network( | |
19 | - 'https://gimg2.baidu.com/image_search/src=http%3A%2F%2Fsafe-img.xhscdn.com%2Fbw1%2Faa1c2213-820a-4223-8757-5f8cee318a28%3FimageView2%2F2%2Fw%2F1080%2Fformat%2Fjpg&refer=http%3A%2F%2Fsafe-img.xhscdn.com&app=2002&size=f9999,10000&q=a80&n=0&g=0n&fmt=auto?sec=1688713226&t=192b18a613683bcdc5bd76f65c9ff032', | |
20 | - width: 40, | |
21 | - fit: BoxFit.fitHeight, | |
22 | - ), | |
23 | - ); | |
24 | - }), | |
25 | - ); | |
26 | - } | |
27 | -} | |
28 | 0 | \ No newline at end of file |
lib/pages/home/widgets/home_tab_header_widget.dart
... | ... | @@ -117,14 +117,14 @@ class HomeTabHeaderWidget extends StatelessWidget { |
117 | 117 | }, |
118 | 118 | icon: Image.asset('listen'.assetPng) |
119 | 119 | ), |
120 | - IconButton( | |
121 | - onPressed: (){ | |
122 | - if(actionTap != null) { | |
123 | - actionTap!(HeaderActionType.shop); | |
124 | - } | |
125 | - }, | |
126 | - icon: Image.asset('shop'.assetPng) | |
127 | - ), | |
120 | + // IconButton( | |
121 | + // onPressed: (){ | |
122 | + // if(actionTap != null) { | |
123 | + // actionTap!(HeaderActionType.shop); | |
124 | + // } | |
125 | + // }, | |
126 | + // icon: Image.asset('shop'.assetPng) | |
127 | + // ), | |
128 | 128 | ScreenUtil().bottomBarHeight.horizontalSpace, |
129 | 129 | ], |
130 | 130 | ), | ... | ... |
lib/pages/home/widgets/home_vidoe_item.dart
1 | 1 | import 'package:flutter/material.dart'; |
2 | 2 | import 'package:flutter_screenutil/flutter_screenutil.dart'; |
3 | 3 | import 'package:wow_english/common/extension/string_extension.dart'; |
4 | +import 'package:wow_english/common/widgets/ow_image_widget.dart'; | |
4 | 5 | import 'package:wow_english/models/course_entity.dart'; |
5 | 6 | |
6 | 7 | class HomeVideoItem extends StatelessWidget { |
... | ... | @@ -16,9 +17,9 @@ class HomeVideoItem extends StatelessWidget { |
16 | 17 | width: 165.w, |
17 | 18 | padding: EdgeInsets.symmetric(horizontal: 16.w,vertical: 24.h), |
18 | 19 | decoration: BoxDecoration( |
19 | - image: DecorationImage( | |
20 | - image: AssetImage('gendubeij'.assetPng), | |
21 | - ), | |
20 | + image: DecorationImage( | |
21 | + image: AssetImage('gendubeij'.assetPng), | |
22 | + ), | |
22 | 23 | ), |
23 | 24 | child: Column( |
24 | 25 | mainAxisAlignment: MainAxisAlignment.spaceAround, |
... | ... | @@ -26,17 +27,17 @@ class HomeVideoItem extends StatelessWidget { |
26 | 27 | Expanded( |
27 | 28 | child: Container( |
28 | 29 | decoration: BoxDecoration( |
29 | - border: Border.all( | |
30 | - width: 2, | |
31 | - color: const Color(0xFF140C10), | |
30 | + border: Border.all( | |
31 | + width: 2, | |
32 | + color: const Color(0xFF140C10), | |
33 | + ), | |
34 | + borderRadius: BorderRadius.circular(6) | |
32 | 35 | ), |
33 | - borderRadius: BorderRadius.circular(6) | |
34 | - ), | |
35 | - child: Image.network( | |
36 | - lessons?.coverUrl??'', | |
36 | + child: OwImageWidget( | |
37 | + name: lessons?.coverUrl??'', | |
37 | 38 | fit: BoxFit.fill, |
38 | 39 | ), |
39 | - )), | |
40 | + )), | |
40 | 41 | 24.verticalSpace, |
41 | 42 | Container( |
42 | 43 | decoration: BoxDecoration( | ... | ... |
lib/pages/lessons/lesson_page.dart
... | ... | @@ -52,15 +52,15 @@ class _LessonPageView extends StatelessWidget { |
52 | 52 | width: 43, |
53 | 53 | ) |
54 | 54 | ), |
55 | - actions: <Widget>[ | |
56 | - IconButton( | |
57 | - icon: Image.asset('shop'.assetPng), | |
58 | - color: Colors.white, | |
59 | - onPressed: () { | |
60 | - EasyLoading.showToast('购买'); | |
61 | - }, | |
62 | - ) | |
63 | - ], | |
55 | + // actions: <Widget>[ | |
56 | + // IconButton( | |
57 | + // icon: Image.asset('shop'.assetPng), | |
58 | + // color: Colors.white, | |
59 | + // onPressed: () { | |
60 | + // EasyLoading.showToast('购买'); | |
61 | + // }, | |
62 | + // ) | |
63 | + // ], | |
64 | 64 | ), |
65 | 65 | body: _lessViewWidget(), |
66 | 66 | ), |
... | ... | @@ -88,7 +88,7 @@ class _LessonPageView extends StatelessWidget { |
88 | 88 | 32.verticalSpace, |
89 | 89 | SizedBox( |
90 | 90 | height: 32.h, |
91 | - width: double.infinity, | |
91 | + width: 66.w * bloc.listData.length, | |
92 | 92 | child: ListView.builder( |
93 | 93 | itemCount: bloc.listData.length, |
94 | 94 | scrollDirection: Axis.horizontal, |
... | ... | @@ -109,6 +109,7 @@ class _LessonPageView extends StatelessWidget { |
109 | 109 | height: bloc.currentPageIndex == index ? 32:20, |
110 | 110 | decoration: BoxDecoration( |
111 | 111 | color: bloc.currentPageIndex == index ? Colors.red:Colors.white, |
112 | + borderRadius: BorderRadius.circular(5.r), | |
112 | 113 | border: Border.all( |
113 | 114 | width: 0.5, |
114 | 115 | color: Colors.black, | ... | ... |
lib/pages/lessons/widgets/lesson_item_widget.dart
1 | 1 | import 'package:flutter/material.dart'; |
2 | 2 | import 'package:flutter_screenutil/flutter_screenutil.dart'; |
3 | 3 | import 'package:wow_english/common/extension/string_extension.dart'; |
4 | +import 'package:wow_english/common/widgets/ow_image_widget.dart'; | |
4 | 5 | import 'package:wow_english/models/course_module_entity.dart'; |
5 | 6 | |
6 | 7 | class LessonItemWidget extends StatelessWidget { |
... | ... | @@ -30,8 +31,8 @@ class LessonItemWidget extends StatelessWidget { |
30 | 31 | image: AssetImage('gendubeij'.assetPng) |
31 | 32 | ) |
32 | 33 | ), |
33 | - child: Image.network( | |
34 | - model?.picUrl??'', | |
34 | + child: OwImageWidget( | |
35 | + name: model?.picUrl??'', | |
35 | 36 | ), |
36 | 37 | ); |
37 | 38 | } |
... | ... | @@ -40,29 +41,48 @@ class LessonItemWidget extends StatelessWidget { |
40 | 41 | return Container( |
41 | 42 | padding: const EdgeInsets.all(10), |
42 | 43 | decoration: BoxDecoration( |
43 | - image: DecorationImage( | |
44 | - image: AssetImage('gendubeij'.assetPng) | |
45 | - ) | |
44 | + image: DecorationImage( | |
45 | + image: AssetImage( | |
46 | + 'gendubeij'.assetPng, | |
47 | + ), | |
48 | + fit: BoxFit.fill | |
49 | + ), | |
46 | 50 | ), |
47 | 51 | child: Column( |
48 | 52 | mainAxisAlignment: MainAxisAlignment.spaceBetween, |
49 | 53 | children: [ |
50 | 54 | Expanded( |
51 | - child: Image.network( | |
52 | - model?.picUrl??'', | |
53 | - fit: BoxFit.contain | |
55 | + child: OwImageWidget( | |
56 | + name: model?.picUrl??'', | |
54 | 57 | ), |
55 | 58 | ), |
56 | 59 | 10.verticalSpace, |
57 | 60 | Container( |
58 | - color: Colors.red, | |
61 | + decoration: BoxDecoration( | |
62 | + color: Colors.red, | |
63 | + borderRadius: BorderRadius.circular(6.r), | |
64 | + border: Border.all( | |
65 | + color: const Color(0xFF333333), | |
66 | + width: 1.0 | |
67 | + ) | |
68 | + ), | |
59 | 69 | padding: EdgeInsets.symmetric(horizontal: 10.w), |
60 | 70 | child: Column( |
61 | 71 | children: [ |
62 | - Text(model?.name??''), | |
72 | + Text( | |
73 | + model?.name??'', | |
74 | + style: TextStyle( | |
75 | + color: Colors.white, | |
76 | + fontSize: 12.sp | |
77 | + ), | |
78 | + ), | |
63 | 79 | Text( |
64 | 80 | model?.des??'', |
65 | 81 | maxLines: 1, |
82 | + style: TextStyle( | |
83 | + color: Colors.white, | |
84 | + fontSize: 12.sp | |
85 | + ), | |
66 | 86 | ) |
67 | 87 | ], |
68 | 88 | ), | ... | ... |
lib/pages/listen/bloc/listen_bloc.dart
... | ... | @@ -13,8 +13,8 @@ part 'listen_state.dart'; |
13 | 13 | |
14 | 14 | class ListenBloc extends Bloc<ListenEvent, ListenState> { |
15 | 15 | |
16 | - final List<ListenEntity?> _listData = []; | |
17 | - List<ListenEntity?> get listData => _listData; | |
16 | + List<ListenEntity?>? _listData; | |
17 | + List<ListenEntity?>? get listData => _listData; | |
18 | 18 | |
19 | 19 | ListenBloc() : super(ListenInitial()) { |
20 | 20 | on<ListenEvent>((event, emit) { |
... | ... | @@ -25,13 +25,7 @@ class ListenBloc extends Bloc<ListenEvent, ListenState> { |
25 | 25 | Future<void> requestData() async { |
26 | 26 | try { |
27 | 27 | await loading(() async { |
28 | - List<String> list = await ListenDao.listen()??[]; | |
29 | - if (list.isNotEmpty) { | |
30 | - for (String jsonStr in list) { | |
31 | - ListenEntity? data = ListenEntity.fromJson(jsonDecode(jsonStr)); | |
32 | - _listData.add(data); | |
33 | - } | |
34 | - } | |
28 | + _listData = await ListenDao.listen()??[]; | |
35 | 29 | emit(RequestListenDataState()); |
36 | 30 | }); |
37 | 31 | } catch (e) { | ... | ... |
lib/pages/listen/listen_page.dart
... | ... | @@ -40,12 +40,12 @@ class _ListenPageView extends StatelessWidget { |
40 | 40 | builder: (context, state) { |
41 | 41 | final bloc = BlocProvider.of<ListenBloc>(context); |
42 | 42 | return ListView.builder( |
43 | - itemCount: bloc.listData.length, | |
43 | + itemCount: bloc.listData?.length, | |
44 | 44 | scrollDirection: Axis.horizontal, |
45 | 45 | padding: EdgeInsets.symmetric(horizontal: 30.w,vertical: 36.h), |
46 | 46 | itemBuilder: (BuildContext context,int index){ |
47 | 47 | return ListenItemWidget( |
48 | - isLock: (index > 5), | |
48 | + entity: bloc.listData?[index], | |
49 | 49 | clickEvent: (){ |
50 | 50 | Navigator.of(context).pushNamed(AppRouteName.lookVideo,arguments: {'videoUrl':'https://cdn.cnbj1.fds.api.mi-img.com/mi-mall/7194236f31b2e1e3da0fe06cfed4ba2b.mp4'}); |
51 | 51 | }); | ... | ... |
lib/pages/listen/widgets/listen_item_widget.dart
1 | +import 'package:cached_network_image/cached_network_image.dart'; | |
1 | 2 | import 'package:flutter/material.dart'; |
2 | 3 | import 'package:flutter_screenutil/flutter_screenutil.dart'; |
3 | 4 | import 'package:wow_english/common/extension/string_extension.dart'; |
5 | +import 'package:wow_english/common/widgets/ow_image_widget.dart'; | |
6 | +import 'package:wow_english/models/listen_entity.dart'; | |
4 | 7 | |
5 | 8 | class ListenItemWidget extends StatelessWidget { |
6 | - const ListenItemWidget({super.key, this.isLock = false, required this.clickEvent}); | |
9 | + const ListenItemWidget({super.key, required this.clickEvent, this.entity}); | |
7 | 10 | |
8 | 11 | final Function() clickEvent; |
9 | 12 | |
10 | - final bool isLock; | |
13 | + final ListenEntity? entity; | |
11 | 14 | |
12 | 15 | @override |
13 | 16 | Widget build(BuildContext context) { |
... | ... | @@ -17,23 +20,24 @@ class ListenItemWidget extends StatelessWidget { |
17 | 20 | children: [ |
18 | 21 | GestureDetector( |
19 | 22 | onTap: () { |
20 | - if (!isLock) { | |
21 | - clickEvent(); | |
23 | + if (entity?.lock??false) { | |
24 | + return; | |
22 | 25 | } |
26 | + clickEvent?.call(); | |
23 | 27 | }, |
24 | 28 | child: ClipRRect( |
25 | 29 | borderRadius:BorderRadius.circular(90.r), |
26 | 30 | child: Stack( |
27 | 31 | alignment:Alignment.center, |
28 | 32 | children: [ |
29 | - Image.network( | |
30 | - 'https://gimg2.baidu.com/image_search/src=http%3A%2F%2Fsafe-img.xhscdn.com%2Fbw1%2Faa1c2213-820a-4223-8757-5f8cee318a28%3FimageView2%2F2%2Fw%2F1080%2Fformat%2Fjpg&refer=http%3A%2F%2Fsafe-img.xhscdn.com&app=2002&size=f9999,10000&q=a80&n=0&g=0n&fmt=auto?sec=1688713226&t=192b18a613683bcdc5bd76f65c9ff032', | |
31 | - height: 180.h, | |
33 | + OwImageWidget( | |
32 | 34 | width: 180.h, |
35 | + height: 180.h, | |
33 | 36 | fit: BoxFit.fill, |
37 | + name:entity?.coverUrl??'', | |
34 | 38 | ), |
35 | 39 | Visibility( |
36 | - visible: isLock, | |
40 | + visible: entity?.lock??false, | |
37 | 41 | child: Container( |
38 | 42 | height: 180.h, |
39 | 43 | width: 180.h, |
... | ... | @@ -41,7 +45,7 @@ class ListenItemWidget extends StatelessWidget { |
41 | 45 | ), |
42 | 46 | ), |
43 | 47 | Visibility( |
44 | - visible: isLock, | |
48 | + visible: entity?.lock??false, | |
45 | 49 | child: Image.asset( |
46 | 50 | 'listen_lock'.assetPng, |
47 | 51 | height: 36.h, |
... | ... | @@ -66,7 +70,7 @@ class ListenItemWidget extends StatelessWidget { |
66 | 70 | ), |
67 | 71 | alignment: Alignment.center, |
68 | 72 | child: Text( |
69 | - 'listen title', | |
73 | + entity?.title??'', | |
70 | 74 | style: TextStyle( |
71 | 75 | fontSize: 20.sp, |
72 | 76 | color: const Color(0xFF333333) | ... | ... |
lib/pages/repeatafter/bloc/repeat_after_bloc.dart
1 | 1 | import 'package:flutter/cupertino.dart'; |
2 | 2 | import 'package:flutter_bloc/flutter_bloc.dart'; |
3 | 3 | import 'package:flutter_easyloading/flutter_easyloading.dart'; |
4 | +import 'package:wow_english/common/request/dao/listen_dao.dart'; | |
5 | +import 'package:wow_english/common/request/exception.dart'; | |
6 | +import 'package:wow_english/models/follow_read_entity.dart'; | |
7 | +import 'package:wow_english/utils/loading.dart'; | |
4 | 8 | |
5 | 9 | part 'repeat_after_event.dart'; |
6 | 10 | part 'repeat_after_state.dart'; |
7 | 11 | |
8 | 12 | class RepeatAfterBloc extends Bloc<RepeatAfterEvent, RepeatAfterState> { |
13 | + | |
14 | + List<FollowReadEntity?> _listData = []; | |
15 | + List<FollowReadEntity?> get listData => _listData; | |
16 | + | |
9 | 17 | RepeatAfterBloc() : super(RepeatAfterInitial()) { |
10 | 18 | on<RepeatAfterEvent>((event, emit) { |
11 | 19 | // TODO: implement event handler |
... | ... | @@ -14,10 +22,15 @@ class RepeatAfterBloc extends Bloc<RepeatAfterEvent, RepeatAfterState> { |
14 | 22 | |
15 | 23 | |
16 | 24 | Future<void> requestData() async { |
17 | - EasyLoading.show(); | |
18 | - Future.delayed(const Duration(milliseconds: 2000),(){ | |
19 | - EasyLoading.dismiss(); | |
20 | - emit(RequestDataState()); | |
21 | - }); | |
25 | + try { | |
26 | + await loading(() async { | |
27 | + _listData = await ListenDao.followRead()??[]; | |
28 | + emit(RequestDataState()); | |
29 | + }); | |
30 | + } catch (e) { | |
31 | + if (e is ApiException) { | |
32 | + EasyLoading.showToast(e.message??'请求失败,请检查网络连接'); | |
33 | + } | |
34 | + } | |
22 | 35 | } |
23 | 36 | } | ... | ... |
lib/pages/repeatafter/repeat_after_page.dart
1 | -import 'dart:math'; | |
2 | - | |
3 | 1 | import 'package:flutter/material.dart'; |
4 | 2 | import 'package:flutter_bloc/flutter_bloc.dart'; |
5 | 3 | import 'package:flutter_easyloading/flutter_easyloading.dart'; |
6 | 4 | import 'package:wow_english/common/widgets/we_app_bar.dart'; |
5 | +import 'package:wow_english/models/follow_read_entity.dart'; | |
7 | 6 | import 'package:wow_english/pages/repeatafter/widgets/repeat_after_item.dart'; |
8 | 7 | |
9 | 8 | import 'bloc/repeat_after_bloc.dart'; |
... | ... | @@ -35,6 +34,7 @@ class _RepeatAfterPageView extends StatelessWidget { |
35 | 34 | |
36 | 35 | Widget _repeatAfterView() => BlocBuilder<RepeatAfterBloc, RepeatAfterState>( |
37 | 36 | builder: (context, state) { |
37 | + final bloc = BlocProvider.of<RepeatAfterBloc>(context); | |
38 | 38 | return Scaffold( |
39 | 39 | appBar: const WEAppBar( |
40 | 40 | titleText: '视频跟读', |
... | ... | @@ -44,16 +44,15 @@ class _RepeatAfterPageView extends StatelessWidget { |
44 | 44 | child: Container( |
45 | 45 | alignment: Alignment.center, |
46 | 46 | child: ListView.builder( |
47 | - itemCount: 10, | |
47 | + itemCount: bloc.listData.length, | |
48 | 48 | scrollDirection: Axis.horizontal, |
49 | 49 | itemBuilder: (BuildContext context,int index){ |
50 | - bool unLock = index%3==0; | |
50 | + FollowReadEntity? entity = bloc.listData[index]; | |
51 | 51 | return RepeatAfterItem( |
52 | - unLock: unLock, | |
53 | 52 | tapEvent: () { |
54 | 53 | |
55 | 54 | }, |
56 | - starNumber: !unLock?0:Random().nextInt(5) | |
55 | + entity: entity, | |
57 | 56 | ); |
58 | 57 | }), |
59 | 58 | ), | ... | ... |
lib/pages/repeatafter/widgets/repeat_after_item.dart
1 | 1 | import 'package:flutter/material.dart'; |
2 | 2 | import 'package:flutter_screenutil/flutter_screenutil.dart'; |
3 | 3 | import 'package:wow_english/common/extension/string_extension.dart'; |
4 | +import 'package:wow_english/common/widgets/ow_image_widget.dart'; | |
5 | +import 'package:wow_english/models/follow_read_entity.dart'; | |
4 | 6 | |
5 | 7 | class RepeatAfterItem extends StatelessWidget { |
6 | - const RepeatAfterItem({super.key, required this.starNumber, required this.unLock, required this.tapEvent}); | |
7 | - //分数 | |
8 | - final int starNumber; | |
9 | - //是否解锁 | |
10 | - final bool unLock; | |
8 | + const RepeatAfterItem({super.key, required this.tapEvent, this.entity}); | |
9 | + | |
10 | + final FollowReadEntity? entity; | |
11 | 11 | |
12 | 12 | final Function() tapEvent; |
13 | 13 | |
... | ... | @@ -19,8 +19,10 @@ class RepeatAfterItem extends StatelessWidget { |
19 | 19 | ), |
20 | 20 | child: GestureDetector( |
21 | 21 | onTap: (){ |
22 | - if(unLock) { | |
23 | - tapEvent(); | |
22 | + if (entity != null) { | |
23 | + if (entity?.lock??false) { | |
24 | + tapEvent(); | |
25 | + } | |
24 | 26 | } |
25 | 27 | }, |
26 | 28 | child: Stack( |
... | ... | @@ -50,8 +52,8 @@ class RepeatAfterItem extends StatelessWidget { |
50 | 52 | child: Column( |
51 | 53 | mainAxisAlignment: MainAxisAlignment.spaceBetween, |
52 | 54 | children: [ |
53 | - Image.network( | |
54 | - 'https://img.liblibai.com/web/648331d033b41.png?image_process=format,webp&x-oss-process=image/resize,w_2980,m_lfit/format,webp', | |
55 | + OwImageWidget( | |
56 | + name:entity?.coverUrl??'', | |
55 | 57 | height: 100.h, |
56 | 58 | width: 140.w, |
57 | 59 | fit: BoxFit.fitWidth, |
... | ... | @@ -60,27 +62,27 @@ class RepeatAfterItem extends StatelessWidget { |
60 | 62 | mainAxisAlignment: MainAxisAlignment.spaceBetween, |
61 | 63 | children: [ |
62 | 64 | Image.asset( |
63 | - starNumber >= 1 ? 'star_light'.assetPng:'star_dark'.assetPng, | |
65 | + (entity?.star??0) >= 1 ? 'star_light'.assetPng:'star_dark'.assetPng, | |
64 | 66 | width: 23.w, |
65 | 67 | height: 21.h, |
66 | 68 | ), |
67 | 69 | Image.asset( |
68 | - starNumber >= 2 ? 'star_light'.assetPng:'star_dark'.assetPng, | |
70 | + (entity?.star??0) >= 2 ? 'star_light'.assetPng:'star_dark'.assetPng, | |
69 | 71 | width: 23.w, |
70 | 72 | height: 21.h, |
71 | 73 | ), |
72 | 74 | Image.asset( |
73 | - starNumber >= 3 ? 'star_light'.assetPng:'star_dark'.assetPng, | |
75 | + (entity?.star??0) >= 3 ? 'star_light'.assetPng:'star_dark'.assetPng, | |
74 | 76 | width: 23.w, |
75 | 77 | height: 21.h, |
76 | 78 | ), |
77 | 79 | Image.asset( |
78 | - starNumber >= 4 ? 'star_light'.assetPng:'star_dark'.assetPng, | |
80 | + (entity?.star??0) >= 4 ? 'star_light'.assetPng:'star_dark'.assetPng, | |
79 | 81 | width: 23.w, |
80 | 82 | height: 21.h, |
81 | 83 | ), |
82 | 84 | Image.asset( |
83 | - starNumber >= 5 ? 'star_light'.assetPng:'star_dark'.assetPng, | |
85 | + (entity?.star??0) >= 5 ? 'star_light'.assetPng:'star_dark'.assetPng, | |
84 | 86 | width: 23.w, |
85 | 87 | height: 21.h, |
86 | 88 | ), |
... | ... | @@ -99,7 +101,7 @@ class RepeatAfterItem extends StatelessWidget { |
99 | 101 | ), |
100 | 102 | alignment: Alignment.center, |
101 | 103 | child: Text( |
102 | - 'video title', | |
104 | + entity?.title??'', | |
103 | 105 | style: TextStyle( |
104 | 106 | fontSize: 16.sp, |
105 | 107 | color: const Color(0xFF333333) |
... | ... | @@ -112,8 +114,8 @@ class RepeatAfterItem extends StatelessWidget { |
112 | 114 | } |
113 | 115 | |
114 | 116 | Widget _lockWidget() { |
115 | - return Offstage( | |
116 | - offstage: unLock, | |
117 | + return Visibility( | |
118 | + visible: entity?.lock??false, | |
117 | 119 | child: Container( |
118 | 120 | width: 162.w, |
119 | 121 | height: 235.h, | ... | ... |