Commit ed94c3db741cfb8ab06d1d12dacb719afdec2c5a

Authored by xiaoyu
2 parents 00a7dc78 caec5687

Merge remote-tracking branch 'origin/feat-wqf-payment' into xiaoyu_cocossteve

android/app/build.gradle
@@ -93,5 +93,5 @@ dependencies { @@ -93,5 +93,5 @@ dependencies {
93 implementation 'com.geyifeng.immersionbar:immersionbar:3.2.2' 93 implementation 'com.geyifeng.immersionbar:immersionbar:3.2.2'
94 // kotlin扩展(可选) 94 // kotlin扩展(可选)
95 implementation 'com.geyifeng.immersionbar:immersionbar-ktx:3.2.2' 95 implementation 'com.geyifeng.immersionbar:immersionbar-ktx:3.2.2'
96 - implementation 'io.keyss.android.library:bjgame:1.0.2' 96 + implementation 'io.keyss.android.library:bjgame:1.0.3'
97 } 97 }
lib/app/splash_page.dart
@@ -6,6 +6,7 @@ import 'package:flutter/foundation.dart'; @@ -6,6 +6,7 @@ import 'package:flutter/foundation.dart';
6 import 'package:flutter/material.dart'; 6 import 'package:flutter/material.dart';
7 import 'package:flutter/services.dart'; 7 import 'package:flutter/services.dart';
8 import 'package:limiting_direction_csx/limiting_direction_csx.dart'; 8 import 'package:limiting_direction_csx/limiting_direction_csx.dart';
  9 +import 'package:wow_english/common/core/app_config_helper.dart';
9 import 'package:wow_english/common/core/user_util.dart'; 10 import 'package:wow_english/common/core/user_util.dart';
10 import 'package:wow_english/common/extension/string_extension.dart'; 11 import 'package:wow_english/common/extension/string_extension.dart';
11 import 'package:wow_english/common/request/config.dart'; 12 import 'package:wow_english/common/request/config.dart';
@@ -44,9 +45,11 @@ class _TransitionViewState extends State<TransitionView> { @@ -44,9 +45,11 @@ class _TransitionViewState extends State<TransitionView> {
44 //Log.d('Splash读当前页面:$currentPageName'); 45 //Log.d('Splash读当前页面:$currentPageName');
45 Log.d('Splash读本地, userEntity: $userEntity'); 46 Log.d('Splash读本地, userEntity: $userEntity');
46 int apartInMilliseconds = 0; 47 int apartInMilliseconds = 0;
  48 + // 阻塞获取系统配置信息
  49 + await AppConfigHelper.getAppConfig();
47 // 调一下接口判断一下有效性再往下 50 // 调一下接口判断一下有效性再往下
48 - if (userEntity != null) {  
49 - String token = userEntity.token; 51 + if (userEntity != null && userEntity.token != null) {
  52 + String token = userEntity.token!;
50 DateTime startTime = DateTime.now(); 53 DateTime startTime = DateTime.now();
51 try { 54 try {
52 userEntity = await UserDao.getUserInfo(); 55 userEntity = await UserDao.getUserInfo();
lib/common/core/app_config_helper.dart 0 → 100644
  1 +import 'dart:ffi';
  2 +import 'dart:io';
  3 +
  4 +import 'package:flutter/cupertino.dart';
  5 +import 'package:package_info_plus/package_info_plus.dart';
  6 +import 'package:wow_english/common/core/user_util.dart';
  7 +
  8 +import '../../models/app_config_entity.dart';
  9 +import '../request/dao/system_dao.dart';
  10 +
  11 +class AppConfigHelper {
  12 +
  13 + static AppConfigEntityEntity? configEntityEntity;
  14 +
  15 + static String versionCode = '';
  16 +
  17 + /// 获取用户信息
  18 + static Future<Void?> getAppConfig() async {
  19 + configEntityEntity = await SystemDao.getAppConfig();
  20 + return null;
  21 + }
  22 +
  23 + // 是否需要隐藏...
  24 + static bool shouldHidePay() {
  25 + return configEntityEntity?.isAppReviewing() == true || UserUtil.getUser()?.phoneNum == "17730280759";
  26 + }
  27 +
  28 + // 获取app版本号
  29 + static Future<String> getAppVersion() async {
  30 + if (versionCode.isNotEmpty) {
  31 + return versionCode;
  32 + }
  33 + PackageInfo packageInfo = await PackageInfo.fromPlatform();
  34 + String version = packageInfo.version; // 版本号
  35 + String buildNumber = packageInfo.buildNumber; // 构建号
  36 + versionCode = version;
  37 +
  38 + debugPrint('versionCode=$versionCode platForm=${Platform.operatingSystem}');
  39 + return versionCode;
  40 + }
  41 +}
lib/common/core/user_util.dart
@@ -11,8 +11,6 @@ import &#39;package:wow_english/utils/sp_util.dart&#39;; @@ -11,8 +11,6 @@ import &#39;package:wow_english/utils/sp_util.dart&#39;;
11 class UserUtil { 11 class UserUtil {
12 static UserEntity? _userEntity; 12 static UserEntity? _userEntity;
13 13
14 - static String get token => _userEntity?.token ?? '';  
15 -  
16 static void saveUser(UserEntity? user) { 14 static void saveUser(UserEntity? user) {
17 if (user == null) { 15 if (user == null) {
18 _clearUserData(); 16 _clearUserData();
@@ -54,7 +52,7 @@ class UserUtil { @@ -54,7 +52,7 @@ class UserUtil {
54 SpUtil.getInstance().remove(SpConst.prefsKeyUserInfo); 52 SpUtil.getInstance().remove(SpConst.prefsKeyUserInfo);
55 } 53 }
56 54
57 - static void logout() { 55 + static void logout([bool showPasswordLoginPage = false]) {
58 _clearUserData(); 56 _clearUserData();
59 // 判断下不在Splash页就跳转 57 // 判断下不在Splash页就跳转
60 /*var currentPageName = ModalRoute.of(AppRouter.context)?.settings.name; 58 /*var currentPageName = ModalRoute.of(AppRouter.context)?.settings.name;
@@ -62,6 +60,25 @@ class UserUtil { @@ -62,6 +60,25 @@ class UserUtil {
62 if (currentPageName != AppRouteName.splash) { 60 if (currentPageName != AppRouteName.splash) {
63 Navigator.of(AppRouter.context).pushNamedAndRemoveUntil(AppRouteName.login, (route) => false); 61 Navigator.of(AppRouter.context).pushNamedAndRemoveUntil(AppRouteName.login, (route) => false);
64 }*/ 62 }*/
65 - Navigator.of(AppRouter.context).pushNamedAndRemoveUntil(AppRouteName.login, (route) => false); 63 + Navigator.of(AppRouter.context).pushNamedAndRemoveUntil(AppRouteName.login, (route) => false, arguments: {'showPasswordPage': showPasswordLoginPage});
  64 + }
  65 +
  66 + // 是否有游戏权限
  67 + static bool hasGamePermission() {
  68 + return _userEntity?.valid ?? false;
  69 + }
  70 +
  71 + // 是否登录(token是否有效)
  72 + static bool isLogined() {
  73 + return getUserToken().isNotEmpty;
  74 + }
  75 +
  76 + static String getUserToken() {
  77 + return _userEntity?.token ?? '';
  78 + }
  79 +
  80 + // (vip)剩余有效期
  81 + static int getRemainingValidity() {
  82 + return _userEntity?.validDay ?? 0;
66 } 83 }
67 } 84 }
lib/common/request/dao/system_dao.dart 0 → 100644
  1 +import '../../../models/app_config_entity.dart';
  2 +import '../request_client.dart';
  3 +
  4 +class SystemDao {
  5 +
  6 + /// 获取配置信息
  7 + static Future<AppConfigEntityEntity?> getAppConfig() async {
  8 + return await requestClient.get(Apis.appConfig);
  9 + }
  10 +}
lib/common/request/dao/user_dao.dart
@@ -16,6 +16,12 @@ class UserDao { @@ -16,6 +16,12 @@ class UserDao {
16 ); 16 );
17 if (data != null) { 17 if (data != null) {
18 UserUtil.saveUser(data); 18 UserUtil.saveUser(data);
  19 + // 由于userInfo接口不会返回token,所以这里需要再次保存一下token
  20 + final token = data.token;
  21 + //登录成功后zip一下getUserInfo,因为进入首页需要的信息在userinfo里,保证进入首页数据是最新的
  22 + data = await getUserInfo();
  23 + data?.token = token;
  24 + UserUtil.saveUser(data);
19 } 25 }
20 return data; 26 return data;
21 } 27 }
lib/common/request/token_interceptor.dart
1 import 'package:dio/dio.dart'; 1 import 'package:dio/dio.dart';
2 import 'package:wow_english/common/core/user_util.dart'; 2 import 'package:wow_english/common/core/user_util.dart';
3 3
  4 +import '../core/app_config_helper.dart';
  5 +
4 class TokenInterceptor extends Interceptor { 6 class TokenInterceptor extends Interceptor {
5 @override 7 @override
6 - void onRequest(RequestOptions options, RequestInterceptorHandler handler) { 8 + void onRequest(RequestOptions options, RequestInterceptorHandler handler) async {
7 // 判断token不为空插入, todo token的取法应该跟user在一起,这里取不到user 9 // 判断token不为空插入, todo token的取法应该跟user在一起,这里取不到user
8 - if (UserUtil.token.isNotEmpty) {  
9 - options.headers["Auth-token"] = UserUtil.token; 10 + if (UserUtil.isLogined()) {
  11 + options.headers["Auth-token"] = UserUtil.getUserToken();
10 } 12 }
11 - options.headers["version"] = '1.0.0'; 13 + // 在发送请求之前获取版本号
  14 + String version = await AppConfigHelper.getAppVersion();
  15 + options.headers["version"] = version;
12 super.onRequest(options, handler); 16 super.onRequest(options, handler);
13 } 17 }
14 } 18 }
lib/generated/json/app_config_entity.g.dart 0 → 100644
  1 +import 'package:wow_english/generated/json/base/json_convert_content.dart';
  2 +import 'package:wow_english/models/app_config_entity.dart';
  3 +
  4 +AppConfigEntityEntity $AppConfigEntityEntityFromJson(
  5 + Map<String, dynamic> json) {
  6 + final AppConfigEntityEntity appConfigEntityEntity = AppConfigEntityEntity();
  7 + final bool? androidForceUpdate = jsonConvert.convert<bool>(
  8 + json['androidForceUpdate']);
  9 + if (androidForceUpdate != null) {
  10 + appConfigEntityEntity.androidForceUpdate = androidForceUpdate;
  11 + }
  12 + final bool? androidRecommendUpdate = jsonConvert.convert<bool>(
  13 + json['androidRecommendUpdate']);
  14 + if (androidRecommendUpdate != null) {
  15 + appConfigEntityEntity.androidRecommendUpdate = androidRecommendUpdate;
  16 + }
  17 + final String? androidUpdatePackageUrl = jsonConvert.convert<String>(
  18 + json['androidUpdatePackageUrl']);
  19 + if (androidUpdatePackageUrl != null) {
  20 + appConfigEntityEntity.androidUpdatePackageUrl = androidUpdatePackageUrl;
  21 + }
  22 + final int? androidVersion = jsonConvert.convert<int>(json['androidVersion']);
  23 + if (androidVersion != null) {
  24 + appConfigEntityEntity.androidVersion = androidVersion;
  25 + }
  26 + final bool? iosForceUpdate = jsonConvert.convert<bool>(
  27 + json['iosForceUpdate']);
  28 + if (iosForceUpdate != null) {
  29 + appConfigEntityEntity.iosForceUpdate = iosForceUpdate;
  30 + }
  31 + final bool? iosRecommendUpdate = jsonConvert.convert<bool>(
  32 + json['iosRecommendUpdate']);
  33 + if (iosRecommendUpdate != null) {
  34 + appConfigEntityEntity.iosRecommendUpdate = iosRecommendUpdate;
  35 + }
  36 + final int? iosVersion = jsonConvert.convert<int>(json['iosVersion']);
  37 + if (iosVersion != null) {
  38 + appConfigEntityEntity.iosVersion = iosVersion;
  39 + }
  40 + final String? noticeBeforePurchaseUrl = jsonConvert.convert<String>(
  41 + json['noticeBeforePurchaseUrl']);
  42 + if (noticeBeforePurchaseUrl != null) {
  43 + appConfigEntityEntity.noticeBeforePurchaseUrl = noticeBeforePurchaseUrl;
  44 + }
  45 + final String? safe = jsonConvert.convert<String>(json['safe']);
  46 + if (safe != null) {
  47 + appConfigEntityEntity.safe = safe;
  48 + }
  49 + return appConfigEntityEntity;
  50 +}
  51 +
  52 +Map<String, dynamic> $AppConfigEntityEntityToJson(
  53 + AppConfigEntityEntity entity) {
  54 + final Map<String, dynamic> data = <String, dynamic>{};
  55 + data['androidForceUpdate'] = entity.androidForceUpdate;
  56 + data['androidRecommendUpdate'] = entity.androidRecommendUpdate;
  57 + data['androidUpdatePackageUrl'] = entity.androidUpdatePackageUrl;
  58 + data['androidVersion'] = entity.androidVersion;
  59 + data['iosForceUpdate'] = entity.iosForceUpdate;
  60 + data['iosRecommendUpdate'] = entity.iosRecommendUpdate;
  61 + data['iosVersion'] = entity.iosVersion;
  62 + data['noticeBeforePurchaseUrl'] = entity.noticeBeforePurchaseUrl;
  63 + data['safe'] = entity.safe;
  64 + return data;
  65 +}
  66 +
  67 +extension AppConfigEntityEntityExtension on AppConfigEntityEntity {
  68 + AppConfigEntityEntity copyWith({
  69 + bool? androidForceUpdate,
  70 + bool? androidRecommendUpdate,
  71 + String? androidUpdatePackageUrl,
  72 + int? androidVersion,
  73 + bool? iosForceUpdate,
  74 + bool? iosRecommendUpdate,
  75 + int? iosVersion,
  76 + String? noticeBeforePurchaseUrl,
  77 + String? safe,
  78 + }) {
  79 + return AppConfigEntityEntity()
  80 + ..androidForceUpdate = androidForceUpdate ?? this.androidForceUpdate
  81 + ..androidRecommendUpdate = androidRecommendUpdate ??
  82 + this.androidRecommendUpdate
  83 + ..androidUpdatePackageUrl = androidUpdatePackageUrl ??
  84 + this.androidUpdatePackageUrl
  85 + ..androidVersion = androidVersion ?? this.androidVersion
  86 + ..iosForceUpdate = iosForceUpdate ?? this.iosForceUpdate
  87 + ..iosRecommendUpdate = iosRecommendUpdate ?? this.iosRecommendUpdate
  88 + ..iosVersion = iosVersion ?? this.iosVersion
  89 + ..noticeBeforePurchaseUrl = noticeBeforePurchaseUrl ??
  90 + this.noticeBeforePurchaseUrl
  91 + ..safe = safe ?? this.safe;
  92 + }
  93 +}
0 \ No newline at end of file 94 \ No newline at end of file
lib/generated/json/base/json_convert_content.dart
@@ -5,6 +5,7 @@ @@ -5,6 +5,7 @@
5 // This file is automatically generated. DO NOT EDIT, all your changes would be lost. 5 // This file is automatically generated. DO NOT EDIT, all your changes would be lost.
6 import 'package:flutter/material.dart' show debugPrint; 6 import 'package:flutter/material.dart' show debugPrint;
7 import 'package:wow_english/models/aliyun_oss_upload_sts_entity.dart'; 7 import 'package:wow_english/models/aliyun_oss_upload_sts_entity.dart';
  8 +import 'package:wow_english/models/app_config_entity.dart';
8 import 'package:wow_english/models/course_entity.dart'; 9 import 'package:wow_english/models/course_entity.dart';
9 import 'package:wow_english/models/course_module_entity.dart'; 10 import 'package:wow_english/models/course_module_entity.dart';
10 import 'package:wow_english/models/course_process_entity.dart'; 11 import 'package:wow_english/models/course_process_entity.dart';
@@ -154,6 +155,10 @@ class JsonConvert { @@ -154,6 +155,10 @@ class JsonConvert {
154 Map<String, dynamic> e) => 155 Map<String, dynamic> e) =>
155 AliyunOssUploadStsCallbackParam.fromJson(e)).toList() as M; 156 AliyunOssUploadStsCallbackParam.fromJson(e)).toList() as M;
156 } 157 }
  158 + if (<AppConfigEntityEntity>[] is M) {
  159 + return data.map<AppConfigEntityEntity>((Map<String, dynamic> e) =>
  160 + AppConfigEntityEntity.fromJson(e)).toList() as M;
  161 + }
157 if (<CourseEntity>[] is M) { 162 if (<CourseEntity>[] is M) {
158 return data.map<CourseEntity>((Map<String, dynamic> e) => 163 return data.map<CourseEntity>((Map<String, dynamic> e) =>
159 CourseEntity.fromJson(e)).toList() as M; 164 CourseEntity.fromJson(e)).toList() as M;
@@ -231,6 +236,7 @@ class JsonConvertClassCollection { @@ -231,6 +236,7 @@ class JsonConvertClassCollection {
231 (AliyunOssUploadStsEntity).toString(): AliyunOssUploadStsEntity.fromJson, 236 (AliyunOssUploadStsEntity).toString(): AliyunOssUploadStsEntity.fromJson,
232 (AliyunOssUploadStsCallbackParam) 237 (AliyunOssUploadStsCallbackParam)
233 .toString(): AliyunOssUploadStsCallbackParam.fromJson, 238 .toString(): AliyunOssUploadStsCallbackParam.fromJson,
  239 + (AppConfigEntityEntity).toString(): AppConfigEntityEntity.fromJson,
234 (CourseEntity).toString(): CourseEntity.fromJson, 240 (CourseEntity).toString(): CourseEntity.fromJson,
235 (CourseCourseLessons).toString(): CourseCourseLessons.fromJson, 241 (CourseCourseLessons).toString(): CourseCourseLessons.fromJson,
236 (CourseModuleEntity).toString(): CourseModuleEntity.fromJson, 242 (CourseModuleEntity).toString(): CourseModuleEntity.fromJson,
lib/generated/json/user_entity.g.dart
@@ -45,6 +45,14 @@ UserEntity $UserEntityFromJson(Map&lt;String, dynamic&gt; json) { @@ -45,6 +45,14 @@ UserEntity $UserEntityFromJson(Map&lt;String, dynamic&gt; json) {
45 if (effectiveDate != null) { 45 if (effectiveDate != null) {
46 userEntity.effectiveDate = effectiveDate; 46 userEntity.effectiveDate = effectiveDate;
47 } 47 }
  48 + final int? validDay = jsonConvert.convert<int>(json['validDay']);
  49 + if (validDay != null) {
  50 + userEntity.validDay = validDay;
  51 + }
  52 + final bool? valid = jsonConvert.convert<bool>(json['valid']);
  53 + if (valid != null) {
  54 + userEntity.valid = valid;
  55 + }
48 return userEntity; 56 return userEntity;
49 } 57 }
50 58
@@ -60,6 +68,8 @@ Map&lt;String, dynamic&gt; $UserEntityToJson(UserEntity entity) { @@ -60,6 +68,8 @@ Map&lt;String, dynamic&gt; $UserEntityToJson(UserEntity entity) {
60 data['fillUserInfo'] = entity.fillUserInfo; 68 data['fillUserInfo'] = entity.fillUserInfo;
61 data['nowCourseModuleId'] = entity.nowCourseModuleId; 69 data['nowCourseModuleId'] = entity.nowCourseModuleId;
62 data['effectiveDate'] = entity.effectiveDate; 70 data['effectiveDate'] = entity.effectiveDate;
  71 + data['validDay'] = entity.validDay;
  72 + data['valid'] = entity.valid;
63 return data; 73 return data;
64 } 74 }
65 75
@@ -75,6 +85,8 @@ extension UserEntityExtension on UserEntity { @@ -75,6 +85,8 @@ extension UserEntityExtension on UserEntity {
75 int? fillUserInfo, 85 int? fillUserInfo,
76 int? nowCourseModuleId, 86 int? nowCourseModuleId,
77 String? effectiveDate, 87 String? effectiveDate,
  88 + int? validDay,
  89 + bool? valid,
78 }) { 90 }) {
79 return UserEntity() 91 return UserEntity()
80 ..id = id ?? this.id 92 ..id = id ?? this.id
@@ -86,6 +98,8 @@ extension UserEntityExtension on UserEntity { @@ -86,6 +98,8 @@ extension UserEntityExtension on UserEntity {
86 ..phoneNum = phoneNum ?? this.phoneNum 98 ..phoneNum = phoneNum ?? this.phoneNum
87 ..fillUserInfo = fillUserInfo ?? this.fillUserInfo 99 ..fillUserInfo = fillUserInfo ?? this.fillUserInfo
88 ..nowCourseModuleId = nowCourseModuleId ?? this.nowCourseModuleId 100 ..nowCourseModuleId = nowCourseModuleId ?? this.nowCourseModuleId
89 - ..effectiveDate = effectiveDate ?? this.effectiveDate; 101 + ..effectiveDate = effectiveDate ?? this.effectiveDate
  102 + ..validDay = validDay ?? this.validDay
  103 + ..valid = valid ?? this.valid;
90 } 104 }
91 } 105 }
92 \ No newline at end of file 106 \ No newline at end of file
lib/models/app_config_entity.dart 0 → 100644
  1 +import 'package:wow_english/generated/json/base/json_field.dart';
  2 +import 'dart:convert';
  3 +
  4 +import '../generated/json/app_config_entity.g.dart';
  5 +
  6 +
  7 +@JsonSerializable()
  8 +class AppConfigEntityEntity {
  9 +
  10 + // 安卓是否强制更新
  11 + bool? androidForceUpdate;
  12 +
  13 + // 安卓是否推荐更新
  14 + bool? androidRecommendUpdate;
  15 +
  16 + // 安卓更新包地址
  17 + String? androidUpdatePackageUrl;
  18 +
  19 + // 安卓当前版本号
  20 + int? androidVersion;
  21 +
  22 + bool? iosForceUpdate;
  23 +
  24 + bool? iosRecommendUpdate;
  25 +
  26 + // ios版本
  27 + int? iosVersion;
  28 +
  29 + // 购前须知图片
  30 + String? noticeBeforePurchaseUrl;
  31 +
  32 + // 当前是否安全,safe-安全 otherwise-隐藏pay
  33 + String? safe;
  34 +
  35 +
  36 + AppConfigEntityEntity();
  37 +
  38 + factory AppConfigEntityEntity.fromJson(Map<String, dynamic> json) => $AppConfigEntityEntityFromJson(json);
  39 +
  40 + Map<String, dynamic> toJson() => $AppConfigEntityEntityToJson(this);
  41 +
  42 + @override
  43 + String toString() {
  44 + return jsonEncode(this);
  45 + }
  46 +
  47 + // 是否审核中(null或者非"safe"即不安全)
  48 + bool isAppReviewing() {
  49 + return safe != "safe";
  50 + }
  51 +}
0 \ No newline at end of file 52 \ No newline at end of file
lib/models/user_entity.dart
@@ -9,7 +9,7 @@ class UserEntity { @@ -9,7 +9,7 @@ class UserEntity {
9 late String name; 9 late String name;
10 10
11 /// 一定有也必须要有 11 /// 一定有也必须要有
12 - late String token; 12 + String? token;
13 13
14 //late int expireTime; 14 //late int expireTime;
15 15
@@ -29,6 +29,12 @@ class UserEntity { @@ -29,6 +29,12 @@ class UserEntity {
29 /// 有效时间,VIP,为null没有 29 /// 有效时间,VIP,为null没有
30 String? effectiveDate; 30 String? effectiveDate;
31 31
  32 + /// 有效天数
  33 + int? validDay;
  34 +
  35 + /// 游戏权限
  36 + bool? valid;
  37 +
32 UserEntity(); 38 UserEntity();
33 39
34 factory UserEntity.fromJson(Map<String, dynamic> json) => $UserEntityFromJson(json); 40 factory UserEntity.fromJson(Map<String, dynamic> json) => $UserEntityFromJson(json);
lib/pages/home/home_page.dart
@@ -23,33 +23,30 @@ class HomePage extends StatelessWidget { @@ -23,33 +23,30 @@ class HomePage extends StatelessWidget {
23 Widget build(BuildContext context) { 23 Widget build(BuildContext context) {
24 return BlocProvider( 24 return BlocProvider(
25 create: (context) => HomeBloc(moduleId)..add(RequestDataEvent()), 25 create: (context) => HomeBloc(moduleId)..add(RequestDataEvent()),
26 - child: _HomePageView(), 26 + child: _HomePageView(context),
27 ); 27 );
28 } 28 }
29 } 29 }
30 30
31 class _HomePageView extends StatelessWidget { 31 class _HomePageView extends StatelessWidget {
  32 +
  33 + const _HomePageView(this.context);
  34 +
  35 + final BuildContext context;
  36 +
32 void _headerActionEvent(HeaderActionType type) { 37 void _headerActionEvent(HeaderActionType type) {
33 if (type == HeaderActionType.video) { 38 if (type == HeaderActionType.video) {
34 pushNamed(AppRouteName.reAfter); 39 pushNamed(AppRouteName.reAfter);
35 } else if (type == HeaderActionType.phase) { 40 } else if (type == HeaderActionType.phase) {
36 - if(UserUtil.token.isEmpty) {  
37 - pushNamed(AppRouteName.login);  
38 - } else {  
39 - pushNamed(AppRouteName.lesson);  
40 - } 41 + pushNamed(AppRouteName.lesson);
41 } else if (type == HeaderActionType.listen) { 42 } else if (type == HeaderActionType.listen) {
42 pushNamed(AppRouteName.listen); 43 pushNamed(AppRouteName.listen);
43 } else if (type == HeaderActionType.shop) { 44 } else if (type == HeaderActionType.shop) {
44 pushNamed(AppRouteName.shop); 45 pushNamed(AppRouteName.shop);
45 } else if (type == HeaderActionType.user) { 46 } else if (type == HeaderActionType.user) {
46 - if(UserUtil.token.isEmpty) {  
47 - pushNamed(AppRouteName.login);  
48 - } else {  
49 - pushNamed(AppRouteName.user);  
50 - }  
51 - } else {  
52 - 47 + pushNamed(AppRouteName.user);
  48 + } else if (type == HeaderActionType.home) {
  49 + Navigator.pop(context);
53 } 50 }
54 } 51 }
55 52
@@ -155,7 +152,7 @@ class _HomePageView extends StatelessWidget { @@ -155,7 +152,7 @@ class _HomePageView extends StatelessWidget {
155 //彩蛋 152 //彩蛋
156 return GestureDetector( 153 return GestureDetector(
157 onTap: () { 154 onTap: () {
158 - if(UserUtil.token.isEmpty) { 155 + if (!UserUtil.isLogined()) {
159 pushNamed(AppRouteName.login); 156 pushNamed(AppRouteName.login);
160 return; 157 return;
161 } 158 }
@@ -173,7 +170,7 @@ class _HomePageView extends StatelessWidget { @@ -173,7 +170,7 @@ class _HomePageView extends StatelessWidget {
173 } else { 170 } else {
174 return GestureDetector( 171 return GestureDetector(
175 onTap: () { 172 onTap: () {
176 - if(UserUtil.token.isEmpty) { 173 + if (!UserUtil.isLogined()) {
177 pushNamed(AppRouteName.login); 174 pushNamed(AppRouteName.login);
178 return; 175 return;
179 } 176 }
lib/pages/home/widgets/home_tab_header_widget.dart
1 import 'package:flutter/material.dart'; 1 import 'package:flutter/material.dart';
2 import 'package:flutter_bloc/flutter_bloc.dart'; 2 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/core/user_util.dart';  
5 import 'package:wow_english/common/extension/string_extension.dart'; 4 import 'package:wow_english/common/extension/string_extension.dart';
6 import 'package:wow_english/pages/user/bloc/user_bloc.dart'; 5 import 'package:wow_english/pages/user/bloc/user_bloc.dart';
7 -import 'package:wow_english/utils/image_util.dart';  
8 6
  7 +import '../../../common/core/app_config_helper.dart';
9 import '../../../models/course_entity.dart'; 8 import '../../../models/course_entity.dart';
10 import '../courese_module_model.dart'; 9 import '../courese_module_model.dart';
11 10
@@ -19,70 +18,89 @@ enum HeaderActionType { @@ -19,70 +18,89 @@ enum HeaderActionType {
19 //购买 18 //购买
20 shop, 19 shop,
21 //个人信息 20 //个人信息
22 - user 21 + user,
  22 + //返回到(模块选择)首页
  23 + home,
23 } 24 }
24 25
25 class HomeTabHeaderWidget extends StatelessWidget { 26 class HomeTabHeaderWidget extends StatelessWidget {
26 - const HomeTabHeaderWidget({super.key,this.entity, this.actionTap}); 27 + const HomeTabHeaderWidget({super.key, this.entity, this.actionTap});
27 28
28 final CourseEntity? entity; 29 final CourseEntity? entity;
29 final Function(HeaderActionType type)? actionTap; 30 final Function(HeaderActionType type)? actionTap;
30 31
31 @override 32 @override
32 Widget build(BuildContext context) { 33 Widget build(BuildContext context) {
33 - return BlocBuilder<UserBloc,UserState>(  
34 - builder: (context,state) { 34 + return BlocBuilder<UserBloc, UserState>(
  35 + builder: (context, state) {
35 return Container( 36 return Container(
36 height: 45, 37 height: 45,
37 width: double.infinity, 38 width: double.infinity,
38 - color: CourseModuleModel(entity?.courseModuleCode??'Phase-1').color, 39 + color:
  40 + CourseModuleModel(entity?.courseModuleCode ?? 'Phase-1').color,
39 padding: EdgeInsets.symmetric(horizontal: 9.5.w), 41 padding: EdgeInsets.symmetric(horizontal: 9.5.w),
40 child: Row( 42 child: Row(
41 children: [ 43 children: [
42 ScreenUtil().bottomBarHeight.horizontalSpace, 44 ScreenUtil().bottomBarHeight.horizontalSpace,
43 GestureDetector( 45 GestureDetector(
44 - onTap: () => actionTap?.call(HeaderActionType.user),  
45 - child: Container(  
46 - decoration: BoxDecoration(  
47 - border: Border.all(  
48 - width: 1.0,  
49 - color: const Color(0xFF140C10),  
50 - ),  
51 - borderRadius: BorderRadius.circular(21),  
52 - ),  
53 - child: CircleAvatar(  
54 - radius: 21,  
55 - backgroundImage: ImageUtil.getImageProviderOnDefault(UserUtil.getUser()?.avatarUrl),  
56 - ),  
57 - ),  
58 - ),  
59 - GestureDetector(  
60 onTap: () { 46 onTap: () {
61 if (actionTap != null) { 47 if (actionTap != null) {
62 - actionTap!(HeaderActionType.user); 48 + actionTap!(HeaderActionType.home);
63 } 49 }
64 }, 50 },
65 child: Container( 51 child: Container(
66 - margin: const EdgeInsets.only(left: 7),  
67 - padding: const EdgeInsets.all(4.0),  
68 - decoration: BoxDecoration(  
69 - color: Colors.white,  
70 - borderRadius: BorderRadius.circular(2),  
71 - border: Border.all(width: 1.0, color: const Color(0xFF140C10), style: BorderStyle.solid),  
72 - ),  
73 - child: Text(  
74 - UserUtil.getUser()?.name ?? '未登录',  
75 - style: TextStyle(color: const Color(0xFF333333), fontSize: 16.sp), 52 + alignment: Alignment.center,
  53 + child: Image.asset(
  54 + 'back_around'.assetPng,
  55 + height: 40.h,
  56 + width: 40.w,
76 ), 57 ),
77 ), 58 ),
78 ), 59 ),
  60 + // GestureDetector(
  61 + // onTap: () => actionTap?.call(HeaderActionType.user),
  62 + // child: Container(
  63 + // decoration: BoxDecoration(
  64 + // border: Border.all(
  65 + // width: 1.0,
  66 + // color: const Color(0xFF140C10),
  67 + // ),
  68 + // borderRadius: BorderRadius.circular(21),
  69 + // ),
  70 + // child: CircleAvatar(
  71 + // radius: 21,
  72 + // backgroundImage: ImageUtil.getImageProviderOnDefault(UserUtil.getUser()?.avatarUrl),
  73 + // ),
  74 + // ),
  75 + // ),
  76 + // GestureDetector(
  77 + // onTap: () {
  78 + // if (actionTap != null) {
  79 + // actionTap!(HeaderActionType.user);
  80 + // }
  81 + // },
  82 + // child: Container(
  83 + // margin: const EdgeInsets.only(left: 7),
  84 + // padding: const EdgeInsets.all(4.0),
  85 + // decoration: BoxDecoration(
  86 + // color: Colors.white,
  87 + // borderRadius: BorderRadius.circular(2),
  88 + // border: Border.all(width: 1.0, color: const Color(0xFF140C10), style: BorderStyle.solid),
  89 + // ),
  90 + // child: Text(
  91 + // UserUtil.getUser()?.name ?? '未登录',
  92 + // style: TextStyle(color: const Color(0xFF333333), fontSize: 16.sp),
  93 + // ),
  94 + // ),
  95 + // ),
79 20.horizontalSpace, 96 20.horizontalSpace,
80 Expanded( 97 Expanded(
81 child: Text( 98 child: Text(
82 - CourseModuleModel(entity?.courseModuleCode??'Phase-1').courseModuleTitle,  
83 - textAlign: TextAlign.left,  
84 - style: const TextStyle(color: Colors.white, fontSize: 30.0),  
85 - )), 99 + CourseModuleModel(entity?.courseModuleCode ?? 'Phase-1')
  100 + .courseModuleTitle,
  101 + textAlign: TextAlign.left,
  102 + style: const TextStyle(color: Colors.white, fontSize: 30.0),
  103 + )),
86 // IconButton( 104 // IconButton(
87 // onPressed: () { 105 // onPressed: () {
88 // if (actionTap != null) { 106 // if (actionTap != null) {
@@ -104,18 +122,19 @@ class HomeTabHeaderWidget extends StatelessWidget { @@ -104,18 +122,19 @@ class HomeTabHeaderWidget extends StatelessWidget {
104 } 122 }
105 }, 123 },
106 icon: Image.asset('listen'.assetPng)), 124 icon: Image.asset('listen'.assetPng)),
107 - IconButton(  
108 - onPressed: (){  
109 - if(actionTap != null) {  
110 - actionTap!(HeaderActionType.shop);  
111 - }  
112 - },  
113 - icon: Image.asset('shop'.assetPng) 125 + Visibility(
  126 + visible: !AppConfigHelper.shouldHidePay(),
  127 + child: IconButton(
  128 + onPressed: () {
  129 + if (actionTap != null) {
  130 + actionTap!(HeaderActionType.shop);
  131 + }
  132 + },
  133 + icon: Image.asset('shop'.assetPng)),
114 ), 134 ),
115 ScreenUtil().bottomBarHeight.horizontalSpace, 135 ScreenUtil().bottomBarHeight.horizontalSpace,
116 ], 136 ],
117 - )  
118 - ); 137 + ));
119 }, 138 },
120 ); 139 );
121 } 140 }
lib/pages/login/loginpage/bloc/login_bloc.dart
@@ -45,7 +45,8 @@ class LoginBloc extends Bloc&lt;LoginEvent, LoginState&gt; { @@ -45,7 +45,8 @@ class LoginBloc extends Bloc&lt;LoginEvent, LoginState&gt; {
45 45
46 bool get canSendSms => _canSendSms; 46 bool get canSendSms => _canSendSms;
47 47
48 - LoginBloc() : super(LoginInitial()) { 48 + LoginBloc(bool preferencesPasswordLogin) : super(LoginInitial()) {
  49 + _isSmsLoginType = !preferencesPasswordLogin;
49 on<RequestLoginEvent>(_requestLoginApi); 50 on<RequestLoginEvent>(_requestLoginApi);
50 on<ChangeLoginTypeEvent>(_changeLoginType); 51 on<ChangeLoginTypeEvent>(_changeLoginType);
51 on<PhoneNumChangeEvent>(_changePhoneNumber); 52 on<PhoneNumChangeEvent>(_changePhoneNumber);
lib/pages/login/loginpage/login_page.dart
@@ -11,12 +11,16 @@ import &#39;package:wow_english/route/route.dart&#39;; @@ -11,12 +11,16 @@ import &#39;package:wow_english/route/route.dart&#39;;
11 import 'bloc/login_bloc.dart'; 11 import 'bloc/login_bloc.dart';
12 12
13 class LoginPage extends StatelessWidget { 13 class LoginPage extends StatelessWidget {
14 - const LoginPage({super.key}); 14 +
  15 + // 优先展示密码登录
  16 + final bool preferencesPasswordLogin;
  17 +
  18 + const LoginPage({super.key, this.preferencesPasswordLogin = false});
15 19
16 @override 20 @override
17 Widget build(BuildContext context) { 21 Widget build(BuildContext context) {
18 return BlocProvider( 22 return BlocProvider(
19 - create: (context) => LoginBloc(), 23 + create: (context) => LoginBloc(preferencesPasswordLogin),
20 child: _LoginPageView(), 24 child: _LoginPageView(),
21 ); 25 );
22 } 26 }
@@ -30,7 +34,7 @@ class _LoginPageView extends StatelessWidget { @@ -30,7 +34,7 @@ class _LoginPageView extends StatelessWidget {
30 if (state is LoginResultChangeState) { 34 if (state is LoginResultChangeState) {
31 // 调试用 35 // 调试用
32 // Navigator.of(context).pushNamed(AppRouteName.home); 36 // Navigator.of(context).pushNamed(AppRouteName.home);
33 - pushNamedAndRemoveUntil(AppRouteName.home, (route) => false); 37 + pushNamedAndRemoveUntil(AppRouteName.moduleSelect, (route) => false);
34 } 38 }
35 }, 39 },
36 child: _buildLoginViewWidget(), 40 child: _buildLoginViewWidget(),
lib/pages/login/setpwd/set_pwd_page.dart
@@ -7,6 +7,7 @@ import &#39;package:wow_english/common/widgets/textfield_customer_widget.dart&#39;; @@ -7,6 +7,7 @@ import &#39;package:wow_english/common/widgets/textfield_customer_widget.dart&#39;;
7 import 'package:wow_english/route/route.dart'; 7 import 'package:wow_english/route/route.dart';
8 import 'package:wow_english/utils/toast_util.dart'; 8 import 'package:wow_english/utils/toast_util.dart';
9 9
  10 +import '../../../common/core/user_util.dart';
10 import 'bloc/set_pwd_bloc.dart'; 11 import 'bloc/set_pwd_bloc.dart';
11 12
12 enum SetPwdPageType { 13 enum SetPwdPageType {
@@ -59,9 +60,9 @@ class _SetPassWordPageView extends StatelessWidget { @@ -59,9 +60,9 @@ class _SetPassWordPageView extends StatelessWidget {
59 if (bloc.pageType == SetPwdPageType.initPwd) { 60 if (bloc.pageType == SetPwdPageType.initPwd) {
60 showToast('密码设置成功'); 61 showToast('密码设置成功');
61 } else { 62 } else {
62 - showToast('密码修改成功'); 63 + showToast('密码修改成功,请重新登录');
63 } 64 }
64 - pushNamedAndRemoveUntil(AppRouteName.home, (route) => false); 65 + UserUtil.logout(true);
65 } else if (state is PasswordSetFailedState) { 66 } else if (state is PasswordSetFailedState) {
66 state.message.toast(); 67 state.message.toast();
67 } 68 }
lib/pages/moduleSelect/view.dart
1 import 'package:flutter/material.dart'; 1 import 'package:flutter/material.dart';
2 import 'package:flutter_bloc/flutter_bloc.dart'; 2 import 'package:flutter_bloc/flutter_bloc.dart';
  3 +import 'package:wow_english/common/core/app_config_helper.dart';
3 import 'package:wow_english/common/extension/string_extension.dart'; 4 import 'package:wow_english/common/extension/string_extension.dart';
4 import 'package:wow_english/pages/moduleSelect/state.dart'; 5 import 'package:wow_english/pages/moduleSelect/state.dart';
5 import 'package:wow_english/pages/moduleSelect/widgets/BaseHomeHeaderWidget.dart'; 6 import 'package:wow_english/pages/moduleSelect/widgets/BaseHomeHeaderWidget.dart';
6 7
  8 +import '../../common/core/user_util.dart';
  9 +import '../../common/dialogs/show_dialog.dart';
7 import 'bloc.dart'; 10 import 'bloc.dart';
8 import 'event.dart'; 11 import 'event.dart';
9 import 'package:flutter_screenutil/flutter_screenutil.dart'; 12 import 'package:flutter_screenutil/flutter_screenutil.dart';
@@ -47,7 +50,11 @@ class _HomePageView extends StatelessWidget { @@ -47,7 +50,11 @@ class _HomePageView extends StatelessWidget {
47 Expanded( 50 Expanded(
48 child: GestureDetector( 51 child: GestureDetector(
49 onTap: () { 52 onTap: () {
50 - pushNamed(AppRouteName.home); 53 + if (UserUtil.isLogined()) {
  54 + pushNamed(AppRouteName.home);
  55 + } else {
  56 + pushNamed(AppRouteName.login);
  57 + }
51 }, 58 },
52 child: Column( 59 child: Column(
53 mainAxisAlignment: MainAxisAlignment.center, 60 mainAxisAlignment: MainAxisAlignment.center,
@@ -74,7 +81,27 @@ class _HomePageView extends StatelessWidget { @@ -74,7 +81,27 @@ class _HomePageView extends StatelessWidget {
74 Expanded( 81 Expanded(
75 child: GestureDetector( 82 child: GestureDetector(
76 onTap: () { 83 onTap: () {
77 - pushNamed(AppRouteName.games); 84 + //如果没登录先登录
  85 + if (UserUtil.isLogined()) {
  86 + if (AppConfigHelper.shouldHidePay()) {
  87 + pushNamed(AppRouteName.games);
  88 + } else {
  89 + if (UserUtil.hasGamePermission()) {
  90 + pushNamed(AppRouteName.games);
  91 + } else {
  92 + showTwoActionDialog(
  93 + '提示', '忽略', '去续费',
  94 + '您的课程已到期,请快快续费继续学习吧!', leftTap: () {
  95 + popPage();
  96 + }, rightTap: () {
  97 + popPage();
  98 + pushNamed(AppRouteName.shop);
  99 + });
  100 + }
  101 + }
  102 + } else {
  103 + pushNamed(AppRouteName.login);
  104 + }
78 }, 105 },
79 child: Column( 106 child: Column(
80 mainAxisAlignment: MainAxisAlignment.center, 107 mainAxisAlignment: MainAxisAlignment.center,
lib/pages/moduleSelect/widgets/BaseHomeHeaderWidget.dart
1 import 'package:flutter/material.dart'; 1 import 'package:flutter/material.dart';
2 import 'package:flutter_bloc/flutter_bloc.dart'; 2 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/core/app_config_helper.dart';
4 import 'package:wow_english/common/extension/string_extension.dart'; 5 import 'package:wow_english/common/extension/string_extension.dart';
5 6
6 import '../../../common/core/user_util.dart'; 7 import '../../../common/core/user_util.dart';
@@ -77,16 +78,19 @@ class BaseHomeHeaderWidget extends StatelessWidget { @@ -77,16 +78,19 @@ class BaseHomeHeaderWidget extends StatelessWidget {
77 textAlign: TextAlign.left, 78 textAlign: TextAlign.left,
78 style: TextStyle(color: Colors.white, fontSize: 30.0), 79 style: TextStyle(color: Colors.white, fontSize: 30.0),
79 )), 80 )),
80 - Row(children: <Widget>[  
81 - Image(  
82 - width: 20.0.w,  
83 - height: 20.0.h,  
84 - image: AssetImage('ic_countdown'.assetPng)),  
85 - // 替换为你的图片资源路径  
86 - const SizedBox(width: 10.0),  
87 - // 图片和文本之间的间隔  
88 - const Text('还剩29天'),  
89 - ]), 81 + Visibility(
  82 + visible: !AppConfigHelper.shouldHidePay(),
  83 + child: Row(children: <Widget>[
  84 + Image(
  85 + width: 20.0.w,
  86 + height: 20.0.h,
  87 + image: AssetImage('ic_countdown'.assetPng)),
  88 + // 替换为你的图片资源路径
  89 + const SizedBox(width: 10.0),
  90 + // 图片和文本之间的间隔
  91 + Text('还剩${UserUtil.getRemainingValidity()}天'),
  92 + ]),
  93 + ),
90 ScreenUtil().bottomBarHeight.horizontalSpace, 94 ScreenUtil().bottomBarHeight.horizontalSpace,
91 ], 95 ],
92 )); 96 ));
@@ -96,9 +100,9 @@ class BaseHomeHeaderWidget extends StatelessWidget { @@ -96,9 +100,9 @@ class BaseHomeHeaderWidget extends StatelessWidget {
96 } 100 }
97 101
98 void onUserClick() { 102 void onUserClick() {
99 - if (UserUtil.token.isEmpty) {  
100 - pushNamed(AppRouteName.login);  
101 - } else { 103 + if (UserUtil.isLogined()) {
102 pushNamed(AppRouteName.user); 104 pushNamed(AppRouteName.user);
  105 + } else {
  106 + pushNamed(AppRouteName.login);
103 } 107 }
104 } 108 }
lib/pages/shop/home/widgets/product_item.dart
@@ -4,8 +4,7 @@ import &#39;package:flutter_screenutil/flutter_screenutil.dart&#39;; @@ -4,8 +4,7 @@ import &#39;package:flutter_screenutil/flutter_screenutil.dart&#39;;
4 import 'package:wow_english/models/product_entity.dart'; 4 import 'package:wow_english/models/product_entity.dart';
5 5
6 class ProductItem extends StatelessWidget { 6 class ProductItem extends StatelessWidget {
7 - const ProductItem({super.key,  
8 - required this.onTap, this.entity}); 7 + const ProductItem({super.key, required this.onTap, this.entity});
9 8
10 final ProductEntity? entity; 9 final ProductEntity? entity;
11 10
@@ -15,52 +14,27 @@ class ProductItem extends StatelessWidget { @@ -15,52 +14,27 @@ class ProductItem extends StatelessWidget {
15 Widget build(BuildContext context) { 14 Widget build(BuildContext context) {
16 return Container( 15 return Container(
17 decoration: BoxDecoration( 16 decoration: BoxDecoration(
18 - borderRadius: BorderRadius.circular(10.r),  
19 - border: Border.all(  
20 - width: 1.0,  
21 - color: Colors.black  
22 - )  
23 - // image: DecorationImage(  
24 - // image: AssetImage(  
25 - // ''.assetPng,  
26 - // ),  
27 - // fit: BoxFit.fill  
28 - // )  
29 - ),  
30 - padding: EdgeInsets.symmetric(horizontal: 16.w,vertical: 16.h), 17 + borderRadius: BorderRadius.circular(10.r),
  18 + border: Border.all(width: 1.0, color: Colors.black)),
  19 + padding: EdgeInsets.symmetric(horizontal: 16.w, vertical: 16.h),
31 child: Row( 20 child: Row(
32 mainAxisAlignment: MainAxisAlignment.spaceBetween, 21 mainAxisAlignment: MainAxisAlignment.spaceBetween,
33 children: [ 22 children: [
34 Container( 23 Container(
35 - width: 124.w, 24 + width: 124.w, // 图片宽度
  25 + height: 124.h, // 图片高度
36 decoration: BoxDecoration( 26 decoration: BoxDecoration(
37 - border: Border.all(  
38 - width: 1.0,  
39 - color: const Color(0xFF333333),  
40 - ),  
41 - image: DecorationImage(  
42 - image: NetworkImage(entity?.picUrl ?? ''),  
43 - ) 27 + borderRadius: BorderRadius.circular(5),
  28 + // 圆角为5
  29 + border: Border.all(width: 1.w, color: const Color(0xFF333333)),
  30 + // 边框宽度为1
  31 + // 使用ClipRRect圆角会有间隙,ClipRRect在裁剪时可能会导致圆角部分的边框显示不完整。
  32 + image: DecorationImage(
  33 + image: NetworkImage(entity?.picUrl ?? ''), // 图片地址
  34 + fit: BoxFit.cover, // 图片填充方式
  35 + ),
44 ), 36 ),
45 ), 37 ),
46 - // CachedNetworkImage(  
47 - // imageUrl: entity?.picUrl ?? '',  
48 - // fit: BoxFit.fill,  
49 - // imageBuilder: (context, imageProvider) =>  
50 - // Container(  
51 - // decoration: BoxDecoration(  
52 - // border: Border.all(  
53 - // width: 1.0,  
54 - // color: const Color(0xFF333333),  
55 - // ),  
56 - // borderRadius: BorderRadius.circular(5.0),  
57 - // ),  
58 - // ),  
59 - // placeholder: (context, url) => const CircularProgressIndicator(),  
60 - // // errorWidget: (context, url, error) => const Icon(Icons.error),  
61 - // height: 124.h,  
62 - // width: 124.w,  
63 - // ),  
64 21.5.horizontalSpace, 38 21.5.horizontalSpace,
65 Expanded( 39 Expanded(
66 child: Column( 40 child: Column(
@@ -72,29 +46,24 @@ class ProductItem extends StatelessWidget { @@ -72,29 +46,24 @@ class ProductItem extends StatelessWidget {
72 softWrap: true, 46 softWrap: true,
73 textAlign: TextAlign.left, 47 textAlign: TextAlign.left,
74 style: TextStyle( 48 style: TextStyle(
75 - fontSize: 12.sp,  
76 - color: const Color(0xFF333333)  
77 - ), 49 + fontSize: 16.sp, color: const Color(0xFF333333)),
78 ), 50 ),
79 RichText( 51 RichText(
80 - text: TextSpan(  
81 - children:[  
82 - TextSpan(  
83 - text: '¥',  
84 - style: TextStyle(  
85 - fontSize: 21.sp,  
86 - color: const Color(0xFFF51A1A),  
87 - )  
88 - ),  
89 - TextSpan(  
90 - text: entity?.price?.toString() ?? '',  
91 - style: TextStyle(  
92 - fontSize: 40.sp,  
93 - color: const Color(0xFFF51A1A),  
94 - ),  
95 - )  
96 - ]  
97 - ), 52 + text: TextSpan(children: [
  53 + TextSpan(
  54 + text: '¥',
  55 + style: TextStyle(
  56 + fontSize: 21.sp,
  57 + color: const Color(0xFFF51A1A),
  58 + )),
  59 + TextSpan(
  60 + text: entity?.price?.toString() ?? '',
  61 + style: TextStyle(
  62 + fontSize: 40.sp,
  63 + color: const Color(0xFFF51A1A),
  64 + ),
  65 + )
  66 + ]),
98 ), 67 ),
99 GestureDetector( 68 GestureDetector(
100 onTap: () { 69 onTap: () {
@@ -107,8 +76,7 @@ class ProductItem extends StatelessWidget { @@ -107,8 +76,7 @@ class ProductItem extends StatelessWidget {
107 border: Border.all( 76 border: Border.all(
108 color: const Color(0xFF333333), 77 color: const Color(0xFF333333),
109 width: 1.0, 78 width: 1.0,
110 - )  
111 - ), 79 + )),
112 padding: EdgeInsets.symmetric( 80 padding: EdgeInsets.symmetric(
113 vertical: 1.h, 81 vertical: 1.h,
114 horizontal: 26.5.w, 82 horizontal: 26.5.w,
@@ -116,9 +84,7 @@ class ProductItem extends StatelessWidget { @@ -116,9 +84,7 @@ class ProductItem extends StatelessWidget {
116 child: Text( 84 child: Text(
117 '立即购买', 85 '立即购买',
118 style: TextStyle( 86 style: TextStyle(
119 - fontSize: 10.sp,  
120 - color: const Color(0xFF333333)  
121 - ), 87 + fontSize: 10.sp, color: const Color(0xFF333333)),
122 ), 88 ),
123 ), 89 ),
124 ) 90 )
@@ -129,4 +95,4 @@ class ProductItem extends StatelessWidget { @@ -129,4 +95,4 @@ class ProductItem extends StatelessWidget {
129 ), 95 ),
130 ); 96 );
131 } 97 }
132 -}  
133 \ No newline at end of file 98 \ No newline at end of file
  99 +}
lib/pages/shopping/view.dart
@@ -19,33 +19,31 @@ Widget buildRadioOption({ @@ -19,33 +19,31 @@ Widget buildRadioOption({
19 required bool isSelected, 19 required bool isSelected,
20 required ValueChanged onSelect, 20 required ValueChanged onSelect,
21 }) { 21 }) {
22 - return  
23 - GestureDetector(  
24 - onTap: () {  
25 - onSelect(value);  
26 - },  
27 - child: Row(  
28 - crossAxisAlignment: CrossAxisAlignment.center,  
29 - children: [  
30 - Image(image: icon, width: 25.0.w, height: 25.0.h, fit: BoxFit.contain),  
31 - const SizedBox(width: 10.0),  
32 - Expanded(  
33 - child: Text(  
34 - text,  
35 - style: TextStyle(color: const Color(0xFF333333), fontSize: 12.5.sp),  
36 - ), 22 + return GestureDetector(
  23 + onTap: () {
  24 + onSelect(value);
  25 + },
  26 + child: Row(
  27 + crossAxisAlignment: CrossAxisAlignment.center,
  28 + children: [
  29 + Image(image: icon, width: 25.0.w, height: 25.0.h, fit: BoxFit.contain),
  30 + const SizedBox(width: 10.0),
  31 + Expanded(
  32 + child: Text(
  33 + text,
  34 + style: TextStyle(color: const Color(0xFF333333), fontSize: 12.5.sp),
37 ), 35 ),
38 - Image(  
39 - image: isSelected  
40 - ? AssetImage('checked'.assetPng)  
41 - : AssetImage('unchecked'.assetPng),  
42 - width: 22.0.w,  
43 - height: 22.0.h,  
44 - ),  
45 - ],  
46 - ),  
47 - );  
48 - 36 + ),
  37 + Image(
  38 + image: isSelected
  39 + ? AssetImage('checked'.assetPng)
  40 + : AssetImage('unchecked'.assetPng),
  41 + width: 22.0.w,
  42 + height: 22.0.h,
  43 + ),
  44 + ],
  45 + ),
  46 + );
49 } 47 }
50 48
51 class ShoppingPage extends StatelessWidget { 49 class ShoppingPage extends StatelessWidget {
@@ -83,22 +81,22 @@ class _ShoppingView extends StatelessWidget { @@ -83,22 +81,22 @@ class _ShoppingView extends StatelessWidget {
83 child: Row( 81 child: Row(
84 crossAxisAlignment: CrossAxisAlignment.start, 82 crossAxisAlignment: CrossAxisAlignment.start,
85 children: [ 83 children: [
86 - CachedNetworkImage(  
87 - imageUrl: bloc.productData?.detailPicUrl ?? '',  
88 - imageBuilder: (context, imageProvider) => Container(  
89 - decoration: BoxDecoration(  
90 - image: DecorationImage(  
91 - image: imageProvider,  
92 - fit: BoxFit.cover,  
93 - ),  
94 - borderRadius: BorderRadius.circular(5.0), 84 + Container(
  85 + width: 210.w, // 图片宽度
  86 + height: 210.h, // 图片高度
  87 + decoration: BoxDecoration(
  88 + borderRadius: BorderRadius.circular(5.w),
  89 + // 圆角为5
  90 + border:
  91 + Border.all(width: 1.w, color: const Color(0xFF333333)),
  92 + // 边框宽度为1
  93 + // 使用ClipRRect圆角会有间隙,ClipRRect在裁剪时可能会导致圆角部分的边框显示不完整。
  94 + image: DecorationImage(
  95 + image: NetworkImage(bloc.productData?.detailPicUrl ?? ''),
  96 + // 图片地址
  97 + fit: BoxFit.cover, // 图片填充方式
95 ), 98 ),
96 ), 99 ),
97 - placeholder: (context, url) =>  
98 - const CircularProgressIndicator(),  
99 - // errorWidget: (context, url, error) => const Icon(Icons.error),  
100 - height: 210.0.h,  
101 - width: 210.0.w,  
102 ), 100 ),
103 const SizedBox(width: 35.5), 101 const SizedBox(width: 35.5),
104 Expanded(child: _paymentWidget()) 102 Expanded(child: _paymentWidget())
@@ -117,26 +115,21 @@ Widget _paymentWidget() =&gt; BlocBuilder&lt;ShoppingBloc, ShoppingState&gt;( @@ -117,26 +115,21 @@ Widget _paymentWidget() =&gt; BlocBuilder&lt;ShoppingBloc, ShoppingState&gt;(
117 crossAxisAlignment: CrossAxisAlignment.start, 115 crossAxisAlignment: CrossAxisAlignment.start,
118 children: [ 116 children: [
119 RichText( 117 RichText(
120 - text: TextSpan(  
121 - children: [  
122 - TextSpan(  
123 - text: '套餐价格:',  
124 - style:  
125 - TextStyle(color: const Color(0xFF333333), fontSize: 16.5.sp)  
126 - ),  
127 - TextSpan(  
128 - text: '¥${bloc.productData?.price ?? ''}',  
129 - style:  
130 - TextStyle(color: const Color(0xFFE5262A), fontSize: 16.5.sp)  
131 - ),  
132 - ]  
133 - ), 118 + text: TextSpan(children: [
  119 + TextSpan(
  120 + text: '套餐价格:',
  121 + style: TextStyle(
  122 + color: const Color(0xFF333333), fontSize: 16.5.sp)),
  123 + TextSpan(
  124 + text: '¥${bloc.productData?.price ?? ''}',
  125 + style: TextStyle(
  126 + color: const Color(0xFFE5262A), fontSize: 16.5.sp)),
  127 + ]),
134 ), 128 ),
135 const SizedBox(height: 14.5), 129 const SizedBox(height: 14.5),
136 Text( 130 Text(
137 '套餐名称:${bloc.productData?.name}', 131 '套餐名称:${bloc.productData?.name}',
138 - style:  
139 - TextStyle(color: const Color(0xFF333333), fontSize: 16.sp), 132 + style: TextStyle(color: const Color(0xFF333333), fontSize: 16.sp),
140 maxLines: 2, 133 maxLines: 2,
141 ), 134 ),
142 const SizedBox(height: 14.5), 135 const SizedBox(height: 14.5),
@@ -158,7 +151,8 @@ Widget _paymentWidget() =&gt; BlocBuilder&lt;ShoppingBloc, ShoppingState&gt;( @@ -158,7 +151,8 @@ Widget _paymentWidget() =&gt; BlocBuilder&lt;ShoppingBloc, ShoppingState&gt;(
158 value: PaymentChannel.wechatPay.payChannelType, 151 value: PaymentChannel.wechatPay.payChannelType,
159 icon: AssetImage('weixin'.assetPng), 152 icon: AssetImage('weixin'.assetPng),
160 text: PaymentChannel.wechatPay.payChannelName, 153 text: PaymentChannel.wechatPay.payChannelName,
161 - isSelected: bloc.curPaymentChannel.payChannelType == PaymentChannel.wechatPay.payChannelType, 154 + isSelected: bloc.curPaymentChannel.payChannelType ==
  155 + PaymentChannel.wechatPay.payChannelType,
162 onSelect: (newValue) { 156 onSelect: (newValue) {
163 bloc.add(ChangePaymentChannelEvent(PaymentChannel.wechatPay)); 157 bloc.add(ChangePaymentChannelEvent(PaymentChannel.wechatPay));
164 }, 158 },
@@ -168,7 +162,8 @@ Widget _paymentWidget() =&gt; BlocBuilder&lt;ShoppingBloc, ShoppingState&gt;( @@ -168,7 +162,8 @@ Widget _paymentWidget() =&gt; BlocBuilder&lt;ShoppingBloc, ShoppingState&gt;(
168 value: PaymentChannel.aliPay.payChannelType, 162 value: PaymentChannel.aliPay.payChannelType,
169 icon: AssetImage('zhifubao'.assetPng), 163 icon: AssetImage('zhifubao'.assetPng),
170 text: PaymentChannel.aliPay.payChannelName, 164 text: PaymentChannel.aliPay.payChannelName,
171 - isSelected: bloc.curPaymentChannel.payChannelType == PaymentChannel.aliPay.payChannelType, 165 + isSelected: bloc.curPaymentChannel.payChannelType ==
  166 + PaymentChannel.aliPay.payChannelType,
172 onSelect: (newValue) { 167 onSelect: (newValue) {
173 bloc.add(ChangePaymentChannelEvent(PaymentChannel.aliPay)); 168 bloc.add(ChangePaymentChannelEvent(PaymentChannel.aliPay));
174 }, 169 },
@@ -178,25 +173,26 @@ Widget _paymentWidget() =&gt; BlocBuilder&lt;ShoppingBloc, ShoppingState&gt;( @@ -178,25 +173,26 @@ Widget _paymentWidget() =&gt; BlocBuilder&lt;ShoppingBloc, ShoppingState&gt;(
178 mainAxisAlignment: MainAxisAlignment.spaceBetween, 173 mainAxisAlignment: MainAxisAlignment.spaceBetween,
179 children: [ 174 children: [
180 RichText( 175 RichText(
181 - text: TextSpan(  
182 - children: [  
183 - const TextSpan(  
184 - text: '需支付:',  
185 - style:  
186 - TextStyle(color: Color(0xFF333333), fontSize: 12.5, fontFamily: 'PingFangSC-Regular')  
187 - ),  
188 - TextSpan(  
189 - text: '¥${bloc.productData?.price ?? ''}',  
190 - style:  
191 - TextStyle(color: const Color(0xFFE7383B), fontSize: 41.sp, fontFamily: 'PingFangSC-Regular')  
192 - ),  
193 - ]  
194 - ), 176 + text: TextSpan(children: [
  177 + const TextSpan(
  178 + text: '需支付:',
  179 + style: TextStyle(
  180 + color: Color(0xFF333333),
  181 + fontSize: 12.5,
  182 + fontFamily: 'PingFangSC-Regular')),
  183 + TextSpan(
  184 + text: '¥${bloc.productData?.price ?? ''}',
  185 + style: TextStyle(
  186 + color: const Color(0xFFE7383B),
  187 + fontSize: 41.sp,
  188 + fontFamily: 'PingFangSC-Regular')),
  189 + ]),
195 ), 190 ),
196 // 确认支付按钮 191 // 确认支付按钮
197 GestureDetector( 192 GestureDetector(
198 onTap: () { 193 onTap: () {
199 - bloc.add(DoPayEvent(bloc.productData, bloc.curPaymentChannel)); 194 + bloc.add(
  195 + DoPayEvent(bloc.productData, bloc.curPaymentChannel));
200 }, 196 },
201 child: Image( 197 child: Image(
202 width: 105.w, 198 width: 105.w,
lib/pages/user/modify/modify_user_information_page.dart
@@ -66,7 +66,6 @@ class ModifyUserInformationPage extends StatelessWidget { @@ -66,7 +66,6 @@ class ModifyUserInformationPage extends StatelessWidget {
66 if (bloc.isChangeInfo) { 66 if (bloc.isChangeInfo) {
67 showTwoActionDialog('提示', '确定离开', '继续修改', '您的信息尚未保存',leftTap: (){ 67 showTwoActionDialog('提示', '确定离开', '继续修改', '您的信息尚未保存',leftTap: (){
68 popPage(); 68 popPage();
69 - popPage();  
70 },rightTap: (){ 69 },rightTap: (){
71 popPage(); 70 popPage();
72 }); 71 });
lib/route/route.dart
@@ -2,6 +2,7 @@ import &#39;package:flutter/cupertino.dart&#39;; @@ -2,6 +2,7 @@ import &#39;package:flutter/cupertino.dart&#39;;
2 import 'package:flutter/material.dart'; 2 import 'package:flutter/material.dart';
3 import 'package:wow_english/app/splash_page.dart'; 3 import 'package:wow_english/app/splash_page.dart';
4 import 'package:wow_english/common/pages/wow_web_page.dart'; 4 import 'package:wow_english/common/pages/wow_web_page.dart';
  5 +import 'package:wow_english/generated/json/base/json_convert_content.dart';
5 import 'package:wow_english/models/product_entity.dart'; 6 import 'package:wow_english/models/product_entity.dart';
6 import 'package:wow_english/pages/games/view.dart'; 7 import 'package:wow_english/pages/games/view.dart';
7 import 'package:wow_english/pages/home/home_page.dart'; 8 import 'package:wow_english/pages/home/home_page.dart';
@@ -91,7 +92,9 @@ class AppRouter { @@ -91,7 +92,9 @@ class AppRouter {
91 transitionDuration: Duration.zero, 92 transitionDuration: Duration.zero,
92 transitionsBuilder: (_, __, ___, child) => child); 93 transitionsBuilder: (_, __, ___, child) => child);
93 case AppRouteName.login: 94 case AppRouteName.login:
94 - return CupertinoPageRoute(builder: (_) => const LoginPage()); 95 + // 是否默认密码登录,修改密码后跳登录页,优先密码登录体验好点
  96 + final bool showPasswordPage = (settings.arguments as Map?)?.getOrNull('showPasswordPage') as bool? ?? false;
  97 + return CupertinoPageRoute(builder: (_) => LoginPage(preferencesPasswordLogin: showPasswordPage));
95 case AppRouteName.moduleSelect: 98 case AppRouteName.moduleSelect:
96 return CupertinoPageRoute(builder: (_) => const ModuleSelectPage()); 99 return CupertinoPageRoute(builder: (_) => const ModuleSelectPage());
97 case AppRouteName.games: 100 case AppRouteName.games:
pubspec.yaml
@@ -104,7 +104,7 @@ dependencies: @@ -104,7 +104,7 @@ dependencies:
104 # 阿里云oss https://pub.dev/packages/flutter_oss_aliyun 104 # 阿里云oss https://pub.dev/packages/flutter_oss_aliyun
105 flutter_oss_aliyun: ^6.2.7 105 flutter_oss_aliyun: ^6.2.7
106 # App信息 https://pub.dev/packages/package_info_plus 106 # App信息 https://pub.dev/packages/package_info_plus
107 - package_info_plus: ^4.0.2 107 + package_info_plus: ^4.2.0
108 108
109 dev_dependencies: 109 dev_dependencies:
110 build_runner: ^2.4.4 110 build_runner: ^2.4.4