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 | 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<String, dynamic> json) { | @@ -11,6 +11,10 @@ UserEntity $UserEntityFromJson(Map<String, dynamic> 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<String, dynamic> json) { | @@ -27,13 +31,17 @@ UserEntity $UserEntityFromJson(Map<String, dynamic> 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<String, dynamic> $UserEntityToJson(UserEntity entity) { | @@ -42,11 +50,13 @@ Map<String, dynamic> $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 'package:wow_english/generated/json/user_entity.g.dart'; | @@ -7,14 +7,27 @@ import 'package:wow_english/generated/json/user_entity.g.dart'; | ||
| 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
lib/pages/user/user_page.dart
| @@ -3,10 +3,11 @@ import 'package:flutter_bloc/flutter_bloc.dart'; | @@ -3,10 +3,11 @@ import 'package:flutter_bloc/flutter_bloc.dart'; | ||
| 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 | +} |