Commit c95453ce5bcaf94dde4967788c29dec4fa8e2264

Authored by Key
1 parent 6f617434

feat: User界面完善

android/app/src/main/kotlin/com/kouyuxingqiu/wow_english/MainActivity.kt
1 package com.kouyuxingqiu.wow_english 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 import io.flutter.embedding.android.FlutterActivity 11 import io.flutter.embedding.android.FlutterActivity
4 12
5 class MainActivity : FlutterActivity() { 13 class MainActivity : FlutterActivity() {
6 - // 测试有效  
7 - /*override fun onCreate(savedInstanceState: Bundle?) { 14 + override fun onCreate(savedInstanceState: Bundle?) {
8 super.onCreate(savedInstanceState) 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 class AssetsConst { 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 import 'package:flutter/material.dart'; 1 import 'package:flutter/material.dart';
4 -import 'package:flutter/services.dart';  
5 import 'package:flutter_easyloading/flutter_easyloading.dart'; 2 import 'package:flutter_easyloading/flutter_easyloading.dart';
6 -import 'package:limiting_direction_csx/limiting_direction_csx.dart';  
7 import 'package:webview_flutter/webview_flutter.dart'; 3 import 'package:webview_flutter/webview_flutter.dart';
8 import 'package:wow_english/common/widgets/we_app_bar.dart'; 4 import 'package:wow_english/common/widgets/we_app_bar.dart';
9 5
@@ -26,12 +22,11 @@ class _WowWebViewPageState extends State<WowWebViewPage> { @@ -26,12 +22,11 @@ class _WowWebViewPageState extends State<WowWebViewPage> {
26 @override 22 @override
27 void initState() { 23 void initState() {
28 super.initState(); 24 super.initState();
29 -  
30 - if (Platform.isIOS) { 25 + /*if (Platform.isIOS) {
31 LimitingDirectionCsx.setScreenDirection(DeviceDirectionMask.PortraitUpsideDown); 26 LimitingDirectionCsx.setScreenDirection(DeviceDirectionMask.PortraitUpsideDown);
32 } else { 27 } else {
33 SystemChrome.setPreferredOrientations([DeviceOrientation.portraitUp]); 28 SystemChrome.setPreferredOrientations([DeviceOrientation.portraitUp]);
34 - } 29 + }*/
35 30
36 final WebViewController controller =WebViewController() 31 final WebViewController controller =WebViewController()
37 ..setJavaScriptMode(JavaScriptMode.unrestricted) 32 ..setJavaScriptMode(JavaScriptMode.unrestricted)
@@ -69,14 +64,4 @@ class _WowWebViewPageState extends State<WowWebViewPage> { @@ -69,14 +64,4 @@ class _WowWebViewPageState extends State<WowWebViewPage> {
69 body: WebViewWidget(controller: _controller,), 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 \ No newline at end of file 67 \ No newline at end of file
  68 +}
lib/common/request/apis.dart
@@ -10,6 +10,12 @@ class Apis { @@ -10,6 +10,12 @@ class Apis {
10 /// 登出 10 /// 登出
11 static const String logout = 'logout'; 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 static const String sendSmsCode = 'system/send/code'; 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,6 +5,7 @@ import '../apis.dart';
5 import '../request_client.dart'; 5 import '../request_client.dart';
6 6
7 class UserDao { 7 class UserDao {
  8 + /// 登录
8 static Future<UserEntity?> login(phoneNumber, type, checkKey, checkNumber) async { 9 static Future<UserEntity?> login(phoneNumber, type, checkKey, checkNumber) async {
9 var params = {'phoneNum': phoneNumber, 'type': type, checkKey: checkNumber}; 10 var params = {'phoneNum': phoneNumber, 'type': type, checkKey: checkNumber};
10 var data = await requestClient.post<UserEntity>( 11 var data = await requestClient.post<UserEntity>(
@@ -17,10 +18,27 @@ class UserDao { @@ -17,10 +18,27 @@ class UserDao {
17 return data; 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,7 +16,7 @@ class OwImageWidget extends StatelessWidget {
16 width: width, 16 width: width,
17 ); 17 );
18 } 18 }
19 - return name.contains('http')? 19 + return name.startsWith('http')?
20 CachedNetworkImage( 20 CachedNetworkImage(
21 imageUrl: name, 21 imageUrl: name,
22 height: height, 22 height: height,
@@ -29,4 +29,4 @@ class OwImageWidget extends StatelessWidget { @@ -29,4 +29,4 @@ class OwImageWidget extends StatelessWidget {
29 fit: fit, 29 fit: fit,
30 ); 30 );
31 } 31 }
32 -}  
33 \ No newline at end of file 32 \ No newline at end of file
  33 +}
lib/generated/json/user_entity.g.dart
@@ -11,6 +11,10 @@ UserEntity $UserEntityFromJson(Map&lt;String, dynamic&gt; json) { @@ -11,6 +11,10 @@ UserEntity $UserEntityFromJson(Map&lt;String, dynamic&gt; json) {
11 if (name != null) { 11 if (name != null) {
12 userEntity.name = name; 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 final int? age = jsonConvert.convert<int>(json['age']); 18 final int? age = jsonConvert.convert<int>(json['age']);
15 if (age != null) { 19 if (age != null) {
16 userEntity.age = age; 20 userEntity.age = age;
@@ -27,13 +31,17 @@ UserEntity $UserEntityFromJson(Map&lt;String, dynamic&gt; json) { @@ -27,13 +31,17 @@ UserEntity $UserEntityFromJson(Map&lt;String, dynamic&gt; json) {
27 if (phoneNum != null) { 31 if (phoneNum != null) {
28 userEntity.phoneNum = phoneNum; 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 return userEntity; 46 return userEntity;
39 } 47 }
@@ -42,11 +50,13 @@ Map&lt;String, dynamic&gt; $UserEntityToJson(UserEntity entity) { @@ -42,11 +50,13 @@ Map&lt;String, dynamic&gt; $UserEntityToJson(UserEntity entity) {
42 final Map<String, dynamic> data = <String, dynamic>{}; 50 final Map<String, dynamic> data = <String, dynamic>{};
43 data['id'] = entity.id; 51 data['id'] = entity.id;
44 data['name'] = entity.name; 52 data['name'] = entity.name;
  53 + data['token'] = entity.token;
45 data['age'] = entity.age; 54 data['age'] = entity.age;
46 data['gender'] = entity.gender; 55 data['gender'] = entity.gender;
47 data['avatarUrl'] = entity.avatarUrl; 56 data['avatarUrl'] = entity.avatarUrl;
48 data['phoneNum'] = entity.phoneNum; 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 return data; 61 return data;
52 -}  
53 \ No newline at end of file 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 &#39;package:wow_english/generated/json/user_entity.g.dart&#39;; @@ -7,14 +7,27 @@ import &#39;package:wow_english/generated/json/user_entity.g.dart&#39;;
7 class UserEntity { 7 class UserEntity {
8 late int id; 8 late int id;
9 late String name; 9 late String name;
  10 +
  11 + /// 一定有也必须要有
  12 + late String token;
  13 +
  14 + //late int expireTime;
  15 +
10 int? age; 16 int? age;
11 17
12 /// 性别:0, 1 18 /// 性别:0, 1
13 int? gender; 19 int? gender;
14 String? avatarUrl; 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 UserEntity(); 32 UserEntity();
20 33
@@ -26,4 +39,21 @@ class UserEntity { @@ -26,4 +39,21 @@ class UserEntity {
26 String toString() { 39 String toString() {
27 return jsonEncode(this); 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,7 +104,7 @@ class _LoginPageView extends StatelessWidget {
104 recognizer: TapGestureRecognizer() 104 recognizer: TapGestureRecognizer()
105 ..onTap = () { 105 ..onTap = () {
106 Navigator.of(context).pushNamed(AppRouteName.webView, arguments: { 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 'webViewTitle': '用户隐私协议' 108 'webViewTitle': '用户隐私协议'
109 }); 109 });
110 }), 110 }),
@@ -116,7 +116,7 @@ class _LoginPageView extends StatelessWidget { @@ -116,7 +116,7 @@ class _LoginPageView extends StatelessWidget {
116 recognizer: TapGestureRecognizer() 116 recognizer: TapGestureRecognizer()
117 ..onTap = () { 117 ..onTap = () {
118 Navigator.of(context).pushNamed(AppRouteName.webView, arguments: { 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 'webViewTitle': '儿童隐私协议' 120 'webViewTitle': '儿童隐私协议'
121 }); 121 });
122 }) 122 })
lib/pages/user/bloc/user_bloc.dart
1 import 'package:bloc/bloc.dart'; 1 import 'package:bloc/bloc.dart';
2 import 'package:meta/meta.dart'; 2 import 'package:meta/meta.dart';
  3 +import 'package:wow_english/common/request/dao/user_dao.dart';
3 4
4 part 'user_event.dart'; 5 part 'user_event.dart';
5 part 'user_state.dart'; 6 part 'user_state.dart';
6 7
7 class UserBloc extends Bloc<UserEvent, UserState> { 8 class UserBloc extends Bloc<UserEvent, UserState> {
8 UserBloc() : super(UserInitial()) { 9 UserBloc() : super(UserInitial()) {
  10 + on<UserLogout>(_test);
9 on<UserEvent>((event, emit) { 11 on<UserEvent>((event, emit) {
10 // TODO: implement event handler 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
@@ -2,3 +2,7 @@ part of &#39;user_bloc.dart&#39;; @@ -2,3 +2,7 @@ part of &#39;user_bloc.dart&#39;;
2 2
3 @immutable 3 @immutable
4 abstract class UserEvent {} 4 abstract class UserEvent {}
  5 +
  6 +class UserStarted extends UserEvent {}
  7 +
  8 +class UserLogout extends UserEvent {}
lib/pages/user/user_page.dart
@@ -3,10 +3,11 @@ import &#39;package:flutter_bloc/flutter_bloc.dart&#39;; @@ -3,10 +3,11 @@ import &#39;package:flutter_bloc/flutter_bloc.dart&#39;;
3 import 'package:flutter_screenutil/flutter_screenutil.dart'; 3 import 'package:flutter_screenutil/flutter_screenutil.dart';
4 import 'package:wow_english/common/blocs/cachebloc/cache_bloc.dart'; 4 import 'package:wow_english/common/blocs/cachebloc/cache_bloc.dart';
5 import 'package:wow_english/common/core/assets_const.dart'; 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 import 'package:wow_english/common/widgets/we_app_bar.dart'; 7 import 'package:wow_english/common/widgets/we_app_bar.dart';
8 import 'package:wow_english/models/user_entity.dart'; 8 import 'package:wow_english/models/user_entity.dart';
9 import 'package:wow_english/pages/user/bloc/user_bloc.dart'; 9 import 'package:wow_english/pages/user/bloc/user_bloc.dart';
  10 +import 'package:wow_english/route/route.dart';
10 11
11 class UserPage extends StatelessWidget { 12 class UserPage extends StatelessWidget {
12 const UserPage({super.key}); 13 const UserPage({super.key});
@@ -15,7 +16,7 @@ class UserPage extends StatelessWidget { @@ -15,7 +16,7 @@ class UserPage extends StatelessWidget {
15 Widget build(BuildContext context) { 16 Widget build(BuildContext context) {
16 return BlocProvider( 17 return BlocProvider(
17 create: (context) => UserBloc(), 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,65 +26,152 @@ class _UserView extends StatelessWidget {
25 26
26 @override 27 @override
27 Widget build(BuildContext context) { 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 return Scaffold( 47 return Scaffold(
30 backgroundColor: Colors.white, 48 backgroundColor: Colors.white,
31 - appBar: WEAppBar(  
32 - // 测试用的  
33 - titleText: user?.name ?? '个人中心',  
34 - ), 49 + appBar: const WEAppBar(),
35 body: SingleChildScrollView( 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 child: Column( 53 child: Column(
37 mainAxisAlignment: MainAxisAlignment.center, 54 mainAxisAlignment: MainAxisAlignment.center,
38 children: <Widget>[ 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 +}