Commit c95453ce5bcaf94dde4967788c29dec4fa8e2264
1 parent
6f617434
feat: User界面完善
Showing
18 changed files
with
300 additions
and
271 deletions
android/app/src/main/kotlin/com/kouyuxingqiu/wow_english/MainActivity.kt
1 | 1 | package com.kouyuxingqiu.wow_english |
2 | 2 | |
3 | +import android.graphics.Color | |
4 | +import android.os.Build | |
5 | +import android.os.Bundle | |
6 | +import android.util.Log | |
7 | +import android.view.View | |
8 | +import androidx.core.view.WindowCompat | |
9 | +import androidx.core.view.WindowInsetsCompat | |
10 | +import androidx.core.view.WindowInsetsControllerCompat | |
3 | 11 | import io.flutter.embedding.android.FlutterActivity |
4 | 12 | |
5 | 13 | class MainActivity : FlutterActivity() { |
6 | - // 测试有效 | |
7 | - /*override fun onCreate(savedInstanceState: Bundle?) { | |
14 | + override fun onCreate(savedInstanceState: Bundle?) { | |
8 | 15 | super.onCreate(savedInstanceState) |
9 | - Toast.makeText(this, "onCreate", Toast.LENGTH_SHORT).show() | |
10 | - }*/ | |
16 | + Log.i("WowEnglish", "MainActivity onCreate") | |
17 | + } | |
18 | + | |
19 | + override fun onResume() { | |
20 | + super.onResume() | |
21 | + //setFullScreen() | |
22 | + } | |
23 | + | |
24 | + private fun setFullScreen() { | |
25 | + WindowInsetsControllerCompat(window, window.decorView).let { | |
26 | + it.hide(WindowInsetsCompat.Type.statusBars()) | |
27 | + it.hide(WindowInsetsCompat.Type.navigationBars()) | |
28 | + it.systemBarsBehavior = WindowInsetsControllerCompat.BEHAVIOR_SHOW_TRANSIENT_BARS_BY_SWIPE | |
29 | + } | |
30 | + // 导航栏横线的颜色 | |
31 | + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) { | |
32 | + window.navigationBarDividerColor = Color.TRANSPARENT | |
33 | + } | |
34 | + | |
35 | + /*window.statusBarColor = Color.TRANSPARENT | |
36 | + val controller = WindowInsetsControllerCompat(window, window.decorView) | |
37 | + // 黑色状态栏字体 | |
38 | + controller.isAppearanceLightStatusBars = false | |
39 | + // 状态栏隐藏 | |
40 | + controller.hide(WindowInsetsCompat.Type.statusBars()) | |
41 | + // 导航栏隐藏 | |
42 | + controller.hide(WindowInsetsCompat.Type.navigationBars()) | |
43 | + //window.navigationBarColor = Color.TRANSPARENT | |
44 | + // 打开沉浸式 | |
45 | + WindowCompat.setDecorFitsSystemWindows(window, false)*/ | |
46 | + } | |
11 | 47 | } | ... | ... |
lib/common/core/assets_const.dart
1 | 1 | class AssetsConst { |
2 | - static const String _assetImagePrefix = "assets/images/"; | |
3 | - static const String wowLogo = "wow_logo.png"; | |
4 | - static const String icVip = "ic_vip.png"; | |
2 | + static const String _assetImagePrefix = 'assets/images/'; | |
3 | + static const String wowLogo = '${_assetImagePrefix}wow_logo.png'; | |
4 | + static const String icVip = '${_assetImagePrefix}ic_vip.png'; | |
5 | +//static String get icVip2 =>'ic_vip.png'.assetImg; | |
5 | 6 | } | ... | ... |
lib/common/pages/wow_web_page.dart
1 | -import 'dart:io'; | |
2 | - | |
3 | 1 | import 'package:flutter/material.dart'; |
4 | -import 'package:flutter/services.dart'; | |
5 | 2 | import 'package:flutter_easyloading/flutter_easyloading.dart'; |
6 | -import 'package:limiting_direction_csx/limiting_direction_csx.dart'; | |
7 | 3 | import 'package:webview_flutter/webview_flutter.dart'; |
8 | 4 | import 'package:wow_english/common/widgets/we_app_bar.dart'; |
9 | 5 | |
... | ... | @@ -26,12 +22,11 @@ class _WowWebViewPageState extends State<WowWebViewPage> { |
26 | 22 | @override |
27 | 23 | void initState() { |
28 | 24 | super.initState(); |
29 | - | |
30 | - if (Platform.isIOS) { | |
25 | + /*if (Platform.isIOS) { | |
31 | 26 | LimitingDirectionCsx.setScreenDirection(DeviceDirectionMask.PortraitUpsideDown); |
32 | 27 | } else { |
33 | 28 | SystemChrome.setPreferredOrientations([DeviceOrientation.portraitUp]); |
34 | - } | |
29 | + }*/ | |
35 | 30 | |
36 | 31 | final WebViewController controller =WebViewController() |
37 | 32 | ..setJavaScriptMode(JavaScriptMode.unrestricted) |
... | ... | @@ -69,14 +64,4 @@ class _WowWebViewPageState extends State<WowWebViewPage> { |
69 | 64 | body: WebViewWidget(controller: _controller,), |
70 | 65 | ); |
71 | 66 | } |
72 | - | |
73 | - @override | |
74 | - void deactivate() { | |
75 | - super.deactivate(); | |
76 | - if (Platform.isIOS) { | |
77 | - LimitingDirectionCsx.setScreenDirection(DeviceDirectionMask.Landscape); | |
78 | - } else { | |
79 | - SystemChrome.setPreferredOrientations([DeviceOrientation.landscapeLeft,DeviceOrientation.landscapeRight]); | |
80 | - } | |
81 | - } | |
82 | -} | |
83 | 67 | \ No newline at end of file |
68 | +} | ... | ... |
lib/common/request/apis.dart
... | ... | @@ -10,6 +10,12 @@ class Apis { |
10 | 10 | /// 登出 |
11 | 11 | static const String logout = 'logout'; |
12 | 12 | |
13 | + /// 获取用户信息 | |
14 | + static const String getUserInfo = 'student/info'; | |
15 | + | |
16 | + /// 更新用户信息 | |
17 | + static const String setUserInfo = 'student/update/info'; | |
18 | + | |
13 | 19 | /// 发送验证码 |
14 | 20 | static const String sendSmsCode = 'system/send/code'; |
15 | 21 | ... | ... |
lib/common/request/dao/user_dao.dart
... | ... | @@ -5,6 +5,7 @@ import '../apis.dart'; |
5 | 5 | import '../request_client.dart'; |
6 | 6 | |
7 | 7 | class UserDao { |
8 | + /// 登录 | |
8 | 9 | static Future<UserEntity?> login(phoneNumber, type, checkKey, checkNumber) async { |
9 | 10 | var params = {'phoneNum': phoneNumber, 'type': type, checkKey: checkNumber}; |
10 | 11 | var data = await requestClient.post<UserEntity>( |
... | ... | @@ -17,10 +18,27 @@ class UserDao { |
17 | 18 | return data; |
18 | 19 | } |
19 | 20 | |
20 | - static Future sendCode(phoneNumber,{smsType ='login'}) async { | |
21 | - final params = {'phoneNum':phoneNumber,'smsType':smsType}; | |
22 | - await requestClient.post( | |
23 | - Apis.sendSmsCode,data: params | |
24 | - ); | |
21 | + /// 登出 | |
22 | + static Future logout() async { | |
23 | + var result = await requestClient.post(Apis.logout); | |
24 | + print('logout result=$result'); | |
25 | + UserUtil.logout(); | |
26 | + return result; | |
27 | + } | |
28 | + | |
29 | + /// 发送验证码 | |
30 | + static Future sendCode(phoneNumber, {smsType = 'login'}) async { | |
31 | + final params = {'phoneNum': phoneNumber, 'smsType': smsType}; | |
32 | + await requestClient.post(Apis.sendSmsCode, data: params); | |
33 | + } | |
34 | + | |
35 | + /// 获取用户信息 | |
36 | + static Future<UserEntity?> getUserInfo() async { | |
37 | + return await requestClient.post(Apis.getUserInfo); | |
38 | + } | |
39 | + | |
40 | + /// 更新用户信息,返回即成功,无body | |
41 | + static Future updateUserInfo(UserEntity userEntity) async { | |
42 | + return await requestClient.put(Apis.setUserInfo, data: userEntity.toUpdateJson()); | |
25 | 43 | } |
26 | 44 | } | ... | ... |
lib/common/widgets/ow_image_widget.dart
... | ... | @@ -16,7 +16,7 @@ class OwImageWidget extends StatelessWidget { |
16 | 16 | width: width, |
17 | 17 | ); |
18 | 18 | } |
19 | - return name.contains('http')? | |
19 | + return name.startsWith('http')? | |
20 | 20 | CachedNetworkImage( |
21 | 21 | imageUrl: name, |
22 | 22 | height: height, |
... | ... | @@ -29,4 +29,4 @@ class OwImageWidget extends StatelessWidget { |
29 | 29 | fit: fit, |
30 | 30 | ); |
31 | 31 | } |
32 | -} | |
33 | 32 | \ No newline at end of file |
33 | +} | ... | ... |
lib/generated/json/user_entity.g.dart
... | ... | @@ -11,6 +11,10 @@ UserEntity $UserEntityFromJson(Map<String, dynamic> json) { |
11 | 11 | if (name != null) { |
12 | 12 | userEntity.name = name; |
13 | 13 | } |
14 | + final String? token = jsonConvert.convert<String>(json['token']); | |
15 | + if (token != null) { | |
16 | + userEntity.token = token; | |
17 | + } | |
14 | 18 | final int? age = jsonConvert.convert<int>(json['age']); |
15 | 19 | if (age != null) { |
16 | 20 | userEntity.age = age; |
... | ... | @@ -27,13 +31,17 @@ UserEntity $UserEntityFromJson(Map<String, dynamic> json) { |
27 | 31 | if (phoneNum != null) { |
28 | 32 | userEntity.phoneNum = phoneNum; |
29 | 33 | } |
30 | - final String? token = jsonConvert.convert<String>(json['token']); | |
31 | - if (token != null) { | |
32 | - userEntity.token = token; | |
34 | + final int? fillUserInfo = jsonConvert.convert<int>(json['fillUserInfo']); | |
35 | + if (fillUserInfo != null) { | |
36 | + userEntity.fillUserInfo = fillUserInfo; | |
37 | + } | |
38 | + final int? nowCourseModuleId = jsonConvert.convert<int>(json['nowCourseModuleId']); | |
39 | + if (nowCourseModuleId != null) { | |
40 | + userEntity.nowCourseModuleId = nowCourseModuleId; | |
33 | 41 | } |
34 | - final int? expireTime = jsonConvert.convert<int>(json['expireTime']); | |
35 | - if (expireTime != null) { | |
36 | - userEntity.expireTime = expireTime; | |
42 | + final String? effectiveDate = jsonConvert.convert<String>(json['effectiveDate']); | |
43 | + if (effectiveDate != null) { | |
44 | + userEntity.effectiveDate = effectiveDate; | |
37 | 45 | } |
38 | 46 | return userEntity; |
39 | 47 | } |
... | ... | @@ -42,11 +50,13 @@ Map<String, dynamic> $UserEntityToJson(UserEntity entity) { |
42 | 50 | final Map<String, dynamic> data = <String, dynamic>{}; |
43 | 51 | data['id'] = entity.id; |
44 | 52 | data['name'] = entity.name; |
53 | + data['token'] = entity.token; | |
45 | 54 | data['age'] = entity.age; |
46 | 55 | data['gender'] = entity.gender; |
47 | 56 | data['avatarUrl'] = entity.avatarUrl; |
48 | 57 | data['phoneNum'] = entity.phoneNum; |
49 | - data['token'] = entity.token; | |
50 | - data['expireTime'] = entity.expireTime; | |
58 | + data['fillUserInfo'] = entity.fillUserInfo; | |
59 | + data['nowCourseModuleId'] = entity.nowCourseModuleId; | |
60 | + data['effectiveDate'] = entity.effectiveDate; | |
51 | 61 | return data; |
52 | -} | |
53 | 62 | \ No newline at end of file |
63 | +} | ... | ... |
lib/models/response_model.dart.txt deleted
1 | -import 'package:json_annotation/json_annotation.dart'; | |
2 | - | |
3 | -part 'response_model.g.dart'; | |
4 | - | |
5 | -@JsonSerializable() | |
6 | -class ResponseModel { | |
7 | - int? code; | |
8 | - dynamic data; | |
9 | - String? msg; | |
10 | - | |
11 | - ResponseModel(this.code,this.data,this.msg); | |
12 | - | |
13 | - factory ResponseModel.fromJson(Map<String, dynamic> json) => _$ResponseModelFromJson(json); | |
14 | - | |
15 | - Map<String, dynamic> toJson() => _$ResponseModelToJson(this); | |
16 | -} |
lib/models/response_model.g.dart.txt deleted
1 | -// GENERATED CODE - DO NOT MODIFY BY HAND | |
2 | - | |
3 | -part of 'response_model.dart.txt'; | |
4 | - | |
5 | -// ************************************************************************** | |
6 | -// JsonSerializableGenerator | |
7 | -// ************************************************************************** | |
8 | - | |
9 | -ResponseModel _$ResponseModelFromJson(Map<String, dynamic> json) => | |
10 | - ResponseModel( | |
11 | - json['code'] as int?, | |
12 | - json['data'], | |
13 | - json['msg'] as String?, | |
14 | - ); | |
15 | - | |
16 | -Map<String, dynamic> _$ResponseModelToJson(ResponseModel instance) => | |
17 | - <String, dynamic>{ | |
18 | - 'code': instance.code, | |
19 | - 'data': instance.data, | |
20 | - 'msg': instance.msg, | |
21 | - }; |
lib/models/user_entity.dart
... | ... | @@ -7,14 +7,27 @@ import 'package:wow_english/generated/json/user_entity.g.dart'; |
7 | 7 | class UserEntity { |
8 | 8 | late int id; |
9 | 9 | late String name; |
10 | + | |
11 | + /// 一定有也必须要有 | |
12 | + late String token; | |
13 | + | |
14 | + //late int expireTime; | |
15 | + | |
10 | 16 | int? age; |
11 | 17 | |
12 | 18 | /// 性别:0, 1 |
13 | 19 | int? gender; |
14 | 20 | String? avatarUrl; |
15 | - late String phoneNum; | |
16 | - late String token; | |
17 | - late int expireTime; | |
21 | + String? phoneNum; | |
22 | + | |
23 | + /// 用户信息是否填写 0.未填写 1.已经填写 | |
24 | + int? fillUserInfo; | |
25 | + | |
26 | + /// 当前模块Id | |
27 | + int? nowCourseModuleId; | |
28 | + | |
29 | + /// 有效时间,VIP,为null没有 | |
30 | + String? effectiveDate; | |
18 | 31 | |
19 | 32 | UserEntity(); |
20 | 33 | |
... | ... | @@ -26,4 +39,21 @@ class UserEntity { |
26 | 39 | String toString() { |
27 | 40 | return jsonEncode(this); |
28 | 41 | } |
42 | + | |
43 | + Map<String, dynamic> toUpdateJson() { | |
44 | + final Map<String, dynamic> data = <String, dynamic>{}; | |
45 | + data['name'] = name; | |
46 | + data['age'] = age; | |
47 | + data['gender'] = gender; | |
48 | + data['avatarUrl'] = avatarUrl; | |
49 | + return data; | |
50 | + } | |
51 | + | |
52 | + String getGenderString() { | |
53 | + return gender == null | |
54 | + ? '' | |
55 | + : gender == 0 | |
56 | + ? '男' | |
57 | + : '女'; | |
58 | + } | |
29 | 59 | } | ... | ... |
lib/network/api.dart.txt deleted
1 | -class Api { | |
2 | - /// app初始化配置信息 | |
3 | - // GET /system/app/config | |
4 | - // 接口地址:https://app.apifox.com/link/project/2684751/apis/api-89897678 | |
5 | - static const String appConfig = '/system/app/config'; | |
6 | - | |
7 | - /// 登陆 | |
8 | - static const String login = 'login'; | |
9 | - | |
10 | - /// 登出 | |
11 | - static const String logout = 'logout'; | |
12 | - | |
13 | - /// 发送验证码 | |
14 | - static const String sendSmsCode = '/system/send/code'; | |
15 | - | |
16 | - /// 课程模块 | |
17 | - // GET /home/courseModule | |
18 | - // 接口地址:https://app.apifox.com/link/project/2684751/apis/api-89897663 | |
19 | - static const String courseModule = '/home/courseModule'; | |
20 | - | |
21 | - /// 课程列表 | |
22 | - // GET /home/courseLesson | |
23 | - // 接口地址:https://app.apifox.com/link/project/2684751/apis/api-89897662 | |
24 | - static const String courseLesson = '/home/courseLesson'; | |
25 | -} |
lib/network/basic_configuration.dart.txt deleted
1 | -enum DevelopEvent { | |
2 | - ///开发环境 | |
3 | - dev, | |
4 | - | |
5 | - ///正式环境 | |
6 | - formal | |
7 | -} | |
8 | - | |
9 | -class BasicConfigurationManager { | |
10 | - factory BasicConfigurationManager() => _getInstance(); | |
11 | - | |
12 | - static BasicConfigurationManager? _instance; | |
13 | - | |
14 | - //服务器地址 | |
15 | - String? baseUrl; | |
16 | - | |
17 | - //SessionId | |
18 | - String? sessionId; | |
19 | - | |
20 | - BasicConfigurationManager._internal() { | |
21 | - DevelopEvent developType = DevelopEvent.dev; | |
22 | - if (developType == DevelopEvent.dev) { | |
23 | - baseUrl = 'http://wow-app.dev.kouyuxingqiu.com/'; | |
24 | - } else { | |
25 | - baseUrl = 'http://wow-app.dev.kouyuxingqiu.com/'; | |
26 | - } | |
27 | - sessionId = ''; | |
28 | - } | |
29 | - | |
30 | - static BasicConfigurationManager _getInstance() { | |
31 | - _instance ??= BasicConfigurationManager._internal(); | |
32 | - return _instance!; | |
33 | - } | |
34 | -} |
lib/network/network_manager.dart.txt deleted
1 | -import 'package:dio/dio.dart'; | |
2 | -import 'package:flutter/foundation.dart'; | |
3 | -import 'package:wow_english/models/response_model.dart'; | |
4 | -import 'package:wow_english/network/basic_configuration.dart.txt'; | |
5 | - | |
6 | -enum HttpMethod { | |
7 | - get, | |
8 | - put, | |
9 | - post, | |
10 | - head, | |
11 | - patch, | |
12 | - delete, | |
13 | -} | |
14 | - | |
15 | -class DioUtil { | |
16 | - static final Dio _dio = getDefDio(); | |
17 | - | |
18 | - static Dio getDefDio() { | |
19 | - Dio dio = Dio(); | |
20 | - dio.options = getDefOptions(); | |
21 | - return dio; | |
22 | - } | |
23 | - | |
24 | - static BaseOptions getDefOptions() { | |
25 | - final BaseOptions options = BaseOptions(); | |
26 | - options.baseUrl = BasicConfigurationManager().baseUrl ?? ''; | |
27 | - options.connectTimeout = const Duration(milliseconds: 1000); | |
28 | - options.receiveTimeout = const Duration(milliseconds: 1000); | |
29 | - return options; | |
30 | - } | |
31 | - | |
32 | - Future<void> requestData<T>( | |
33 | - HttpMethod method, | |
34 | - String path, { | |
35 | - data, | |
36 | - Function? successCallBack, | |
37 | - Function? errorCallBack, | |
38 | - Map<String, dynamic>? queryParameters, | |
39 | - ProgressCallback? onSendProgress, | |
40 | - ProgressCallback? onReceiveProgress, | |
41 | - }) async { | |
42 | - try { | |
43 | - Map<String, dynamic> headers = <String, dynamic>{}; | |
44 | - | |
45 | - if (method == HttpMethod.post) { | |
46 | - headers['content-type'] = 'application/json'; | |
47 | - } | |
48 | - Response<dynamic> response; | |
49 | - response = await _dio.request(path, | |
50 | - data: data ?? {}, | |
51 | - queryParameters: queryParameters, | |
52 | - options: Options(method: method.name, headers: headers), | |
53 | - onSendProgress: onSendProgress, | |
54 | - onReceiveProgress: onReceiveProgress); | |
55 | - int statusCode = response.statusCode ?? 0; | |
56 | - if (statusCode >= 200 && statusCode < 300) { | |
57 | - if (kDebugMode) { | |
58 | - print(response.data); | |
59 | - } | |
60 | - final ResponseModel model = ResponseModel.fromJson(response.data); | |
61 | - if (model.code == 200) { | |
62 | - successCallBack?.call(response.data); | |
63 | - } else { | |
64 | - errorCallBack?.call(model.msg); | |
65 | - } | |
66 | - } else { | |
67 | - errorCallBack?.call('请求失败'); | |
68 | - } | |
69 | - } on DioException catch (error) { | |
70 | - if (kDebugMode) { | |
71 | - print(error); | |
72 | - } | |
73 | - errorCallBack?.call("网络错误: ${error.message}"); | |
74 | - } | |
75 | - } | |
76 | -} |
lib/pages/login/loginpage/login_page.dart
... | ... | @@ -104,7 +104,7 @@ class _LoginPageView extends StatelessWidget { |
104 | 104 | recognizer: TapGestureRecognizer() |
105 | 105 | ..onTap = () { |
106 | 106 | Navigator.of(context).pushNamed(AppRouteName.webView, arguments: { |
107 | - 'urlStr': 'https://www.zhihu.com', | |
107 | + 'urlStr': 'http://page.kouyuxingqiu.com/%E7%94%A8%E6%88%B7%E6%B3%A8%E5%86%8C%E5%8F%8A%E4%BD%BF%E7%94%A8APP%E9%9A%90%E7%A7%81%E5%8D%8F%E8%AE%AE.html', | |
108 | 108 | 'webViewTitle': '用户隐私协议' |
109 | 109 | }); |
110 | 110 | }), |
... | ... | @@ -116,7 +116,7 @@ class _LoginPageView extends StatelessWidget { |
116 | 116 | recognizer: TapGestureRecognizer() |
117 | 117 | ..onTap = () { |
118 | 118 | Navigator.of(context).pushNamed(AppRouteName.webView, arguments: { |
119 | - 'urlStr': 'https://www.zhihu.com', | |
119 | + 'urlStr': 'https://ishowedu-public-images.ishowedu.com/%E5%8F%A3%E8%AF%AD%E6%98%9F%E7%90%83%E5%84%BF%E7%AB%A5%E9%9A%90%E7%A7%81%E4%BF%9D%E6%8A%A4%E6%94%BF%E7%AD%96_iShowLD%E4%BF%AE%E8%AE%A2_20210913%281%29.html', | |
120 | 120 | 'webViewTitle': '儿童隐私协议' |
121 | 121 | }); |
122 | 122 | }) | ... | ... |
lib/pages/user/bloc/user_bloc.dart
1 | 1 | import 'package:bloc/bloc.dart'; |
2 | 2 | import 'package:meta/meta.dart'; |
3 | +import 'package:wow_english/common/request/dao/user_dao.dart'; | |
3 | 4 | |
4 | 5 | part 'user_event.dart'; |
5 | 6 | part 'user_state.dart'; |
6 | 7 | |
7 | 8 | class UserBloc extends Bloc<UserEvent, UserState> { |
8 | 9 | UserBloc() : super(UserInitial()) { |
10 | + on<UserLogout>(_test); | |
9 | 11 | on<UserEvent>((event, emit) { |
10 | 12 | // TODO: implement event handler |
11 | 13 | }); |
12 | 14 | } |
15 | + | |
16 | + void _test(UserLogout event, Emitter<UserState> emitter) async { | |
17 | + print('UserBloc._test, event: $event, emitter: $emitter'); | |
18 | + await UserDao.logout(); | |
19 | + } | |
13 | 20 | } | ... | ... |
lib/pages/user/bloc/user_event.dart
lib/pages/user/user_page.dart
... | ... | @@ -3,10 +3,11 @@ import 'package:flutter_bloc/flutter_bloc.dart'; |
3 | 3 | import 'package:flutter_screenutil/flutter_screenutil.dart'; |
4 | 4 | import 'package:wow_english/common/blocs/cachebloc/cache_bloc.dart'; |
5 | 5 | import 'package:wow_english/common/core/assets_const.dart'; |
6 | -import 'package:wow_english/common/extension/string_extension.dart'; | |
6 | +import 'package:wow_english/common/widgets/ow_image_widget.dart'; | |
7 | 7 | import 'package:wow_english/common/widgets/we_app_bar.dart'; |
8 | 8 | import 'package:wow_english/models/user_entity.dart'; |
9 | 9 | import 'package:wow_english/pages/user/bloc/user_bloc.dart'; |
10 | +import 'package:wow_english/route/route.dart'; | |
10 | 11 | |
11 | 12 | class UserPage extends StatelessWidget { |
12 | 13 | const UserPage({super.key}); |
... | ... | @@ -15,7 +16,7 @@ class UserPage extends StatelessWidget { |
15 | 16 | Widget build(BuildContext context) { |
16 | 17 | return BlocProvider( |
17 | 18 | create: (context) => UserBloc(), |
18 | - child: _UserView(), | |
19 | + child: const _UserView(), | |
19 | 20 | ); |
20 | 21 | } |
21 | 22 | } |
... | ... | @@ -25,65 +26,152 @@ class _UserView extends StatelessWidget { |
25 | 26 | |
26 | 27 | @override |
27 | 28 | Widget build(BuildContext context) { |
28 | - UserEntity? user = context.read<CacheBloc>().userEntity; | |
29 | + final cacheBloc = BlocProvider.of<CacheBloc>(context); | |
30 | + final userBloc = BlocProvider.of<UserBloc>(context); | |
31 | + UserEntity user = cacheBloc.userEntity!; | |
32 | + | |
33 | + // 常规按钮的字体样式 | |
34 | + final textStyle21sp = TextStyle( | |
35 | + //fontWeight: FontWeight.w600, | |
36 | + color: const Color(0xFF333333), | |
37 | + fontSize: 21.sp, | |
38 | + ); | |
39 | + | |
40 | + // 常规按钮的样式 | |
41 | + var normalButtonStyle = ButtonStyle( | |
42 | + side: MaterialStateProperty.all(BorderSide(color: const Color(0xFF140C10), width: 1.5)), | |
43 | + shape: MaterialStateProperty.all(RoundedRectangleBorder(borderRadius: BorderRadius.circular(15.r))), | |
44 | + minimumSize: MaterialStateProperty.all(Size(double.infinity, 58.h)), | |
45 | + backgroundColor: MaterialStateProperty.all(Colors.white), | |
46 | + ); | |
29 | 47 | return Scaffold( |
30 | 48 | backgroundColor: Colors.white, |
31 | - appBar: WEAppBar( | |
32 | - // 测试用的 | |
33 | - titleText: user?.name ?? '个人中心', | |
34 | - ), | |
49 | + appBar: const WEAppBar(), | |
35 | 50 | body: SingleChildScrollView( |
51 | + //padding: EdgeInsets.symmetric(horizontal: 17.w), | |
52 | + padding: EdgeInsets.only(left: 17.w, right: 17.w, top: 10.h, bottom: 22.h), | |
36 | 53 | child: Column( |
37 | 54 | mainAxisAlignment: MainAxisAlignment.center, |
38 | 55 | children: <Widget>[ |
39 | - Container( | |
40 | - child: Image.asset(AssetsConst.wowLogo.assetImg), constraints: BoxConstraints(maxHeight: 196.h)), | |
41 | - _userInfo(context), | |
56 | + Container(child: Image.asset(AssetsConst.wowLogo), constraints: BoxConstraints(maxHeight: 196.h)), | |
57 | + 30.verticalSpace, | |
58 | + Row( | |
59 | + mainAxisAlignment: MainAxisAlignment.spaceBetween, | |
60 | + children: [ | |
61 | + CircleAvatar( | |
62 | + radius: 40.r, | |
63 | + backgroundColor: Color(0xFF140C10), | |
64 | + /*child: CircleAvatar( | |
65 | + radius: 38.5.r, | |
66 | + backgroundImage: ImageUtil.getImageProviderOnDefault(user.avatarUrl), | |
67 | + ),*/ | |
68 | + child: ClipOval( | |
69 | + child: OwImageWidget(name: user.avatarUrl ?? AssetsConst.wowLogo), | |
70 | + )), | |
71 | + 32.horizontalSpace, | |
72 | + Expanded( | |
73 | + child: Column( | |
74 | + children: [ | |
75 | + Row( | |
76 | + children: [ | |
77 | + LimitedBox( | |
78 | + maxWidth: 220.w, | |
79 | + child: Text( | |
80 | + user.name, | |
81 | + //'1231231231312312312312312312312312312312312312312', | |
82 | + style: textStyle21sp, | |
83 | + overflow: TextOverflow.ellipsis, | |
84 | + ), | |
85 | + ), | |
86 | + 14.horizontalSpace, | |
87 | + Text( | |
88 | + user.getGenderString(), | |
89 | + style: textStyle21sp, | |
90 | + ), | |
91 | + 14.horizontalSpace, | |
92 | + Offstage( | |
93 | + offstage: user.effectiveDate == null, | |
94 | + child: Image.asset( | |
95 | + AssetsConst.icVip, | |
96 | + height: 18.h, | |
97 | + ), | |
98 | + ) | |
99 | + ], | |
100 | + ), | |
101 | + Offstage( | |
102 | + offstage: user.effectiveDate == null, | |
103 | + child: Row( | |
104 | + children: [ | |
105 | + Text( | |
106 | + "${user.effectiveDate} 到期", | |
107 | + style: TextStyle( | |
108 | + color: const Color(0xFFE11212), | |
109 | + fontSize: 17.sp, | |
110 | + ), | |
111 | + ) | |
112 | + ], | |
113 | + ), | |
114 | + ) | |
115 | + ], | |
116 | + )), | |
117 | + TextButton( | |
118 | + child: Text( | |
119 | + "修改个人信息>", | |
120 | + style: textStyle21sp, | |
121 | + ), | |
122 | + onPressed: () {}, | |
123 | + ) | |
124 | + ], | |
125 | + ), | |
126 | + 30.verticalSpace, | |
127 | + OutlinedButton( | |
128 | + onPressed: () => {}, | |
129 | + style: normalButtonStyle, | |
130 | + child: Text( | |
131 | + "修改密码", | |
132 | + style: textStyle21sp, | |
133 | + ), | |
134 | + ), | |
135 | + 12.verticalSpace, | |
136 | + OutlinedButton( | |
137 | + onPressed: () => {}, | |
138 | + style: normalButtonStyle, | |
139 | + child: Text( | |
140 | + "兑换课程", | |
141 | + style: textStyle21sp, | |
142 | + )), | |
143 | + 12.verticalSpace, | |
144 | + OutlinedButton( | |
145 | + onPressed: () => { | |
146 | + Navigator.of(context).pushNamed(AppRouteName.webView, arguments: { | |
147 | + 'urlStr': 'http://page.kouyuxingqiu.com/%E7%94%A8%E6%88%B7%E6%B3%A8%E5%86%8C%E5%8F%8A%E4%BD%BF%E7%94%A8APP%E9%9A%90%E7%A7%81%E5%8D%8F%E8%AE%AE.html', | |
148 | + 'webViewTitle': '隐私协议' | |
149 | + }) | |
150 | + }, | |
151 | + style: normalButtonStyle, | |
152 | + child: Text( | |
153 | + "隐私协议", | |
154 | + style: textStyle21sp, | |
155 | + )), | |
156 | + 30.verticalSpace, | |
157 | + OutlinedButton( | |
158 | + onPressed: () => {userBloc.add(UserLogout())}, | |
159 | + style: ButtonStyle( | |
160 | + side: MaterialStateProperty.all(BorderSide(color: const Color(0xFF140C10), width: 1.5)), | |
161 | + shape: MaterialStateProperty.all(RoundedRectangleBorder(borderRadius: BorderRadius.circular(15.r))), | |
162 | + minimumSize: MaterialStateProperty.all(Size(295.w, 40.h)), | |
163 | + backgroundColor: MaterialStateProperty.all(Color(0xFFFBB621)), | |
164 | + ), | |
165 | + child: Text( | |
166 | + "退出登陆", | |
167 | + style: TextStyle( | |
168 | + //fontWeight: FontWeight.w600, | |
169 | + color: Colors.white, | |
170 | + fontSize: 17.sp, | |
171 | + ), | |
172 | + )), | |
42 | 173 | ], |
43 | 174 | ), |
44 | 175 | )); |
45 | 176 | } |
46 | - | |
47 | - Widget _userInfo(BuildContext context) { | |
48 | - return Row( | |
49 | - children: [ | |
50 | - Image.asset( | |
51 | - AssetsConst.wowLogo.assetImg, | |
52 | - width: 80, | |
53 | - height: 80, | |
54 | - ), | |
55 | - Column( | |
56 | - children: [ | |
57 | - Row( | |
58 | - children: [ | |
59 | - Text( | |
60 | - context.read<CacheBloc>().userEntity?.name ?? '----', | |
61 | - style: TextStyle( | |
62 | - color: const Color(0xFF333333), | |
63 | - fontSize: 21.sp, | |
64 | - ), | |
65 | - ), | |
66 | - //Text(context.read<CacheBloc>().userEntity?.gender ?? '--'), | |
67 | - Image.asset( | |
68 | - AssetsConst.wowLogo.assetImg, | |
69 | - height: 18.h, | |
70 | - ), | |
71 | - ], | |
72 | - ), | |
73 | - Row( | |
74 | - children: [ | |
75 | - Text( | |
76 | - "什么时候到期", | |
77 | - style: TextStyle( | |
78 | - color: const Color(0xFFE11212), | |
79 | - fontSize: 17.sp, | |
80 | - ), | |
81 | - ) | |
82 | - ], | |
83 | - ) | |
84 | - ], | |
85 | - ), | |
86 | - ], | |
87 | - ); | |
88 | - } | |
89 | 177 | } | ... | ... |
lib/utils/image_util.dart
0 → 100644
1 | +import 'package:flutter/material.dart'; | |
2 | +import 'package:wow_english/common/core/assets_const.dart'; | |
3 | + | |
4 | +class ImageUtil { | |
5 | + static ImageProvider getImageProviderOnDefault(String? uri, {scale = 1.0}) { | |
6 | + if (uri == null || uri.isEmpty) { | |
7 | + return ExactAssetImage(AssetsConst.wowLogo, scale: scale); | |
8 | + } | |
9 | + if (uri.startsWith('http')) { | |
10 | + return NetworkImage(uri); | |
11 | + } else { | |
12 | + return ExactAssetImage(uri, scale: scale); | |
13 | + } | |
14 | + //return uri.startsWith('http') ? NetworkImage(uri) : ExactAssetImage(uri, scale: 0.5) as ImageProvider?; | |
15 | + } | |
16 | +} | ... | ... |