Commit 94342c3fb8dfce3d01d4d4a6ac8c82693e2084d6
1 parent
05f9b20a
feat: user util
Showing
10 changed files
with
161 additions
and
45 deletions
lib/app/splash_page.dart
1 | import 'dart:async'; | 1 | import 'dart:async'; |
2 | 2 | ||
3 | import 'package:flutter/material.dart'; | 3 | import 'package:flutter/material.dart'; |
4 | +import 'package:flutter_bloc/flutter_bloc.dart'; | ||
5 | +import 'package:wow_english/common/core/user_util.dart'; | ||
4 | import 'package:wow_english/common/extension/string_extension.dart'; | 6 | import 'package:wow_english/common/extension/string_extension.dart'; |
5 | -import 'package:wow_english/network/basic_configuration.dart.txt'; | 7 | +import 'package:wow_english/models/user_entity.dart'; |
6 | import 'package:wow_english/route/route.dart'; | 8 | import 'package:wow_english/route/route.dart'; |
9 | +import 'package:wow_english/utils/sp_util.dart'; | ||
7 | 10 | ||
11 | +import '../common/blocs/cachebloc/cache_bloc.dart'; | ||
8 | 12 | ||
9 | class SplashPage extends StatelessWidget { | 13 | class SplashPage extends StatelessWidget { |
10 | const SplashPage({super.key}); | 14 | const SplashPage({super.key}); |
@@ -25,13 +29,15 @@ class TransitionView extends StatefulWidget { | @@ -25,13 +29,15 @@ class TransitionView extends StatefulWidget { | ||
25 | } | 29 | } |
26 | 30 | ||
27 | class _TransitionViewState extends State<TransitionView> { | 31 | class _TransitionViewState extends State<TransitionView> { |
28 | - | ||
29 | Future startTime() async { | 32 | Future startTime() async { |
30 | - Timer(const Duration(seconds: 2),() { | ||
31 | - if(BasicConfigurationManager().sessionId!.isNotEmpty) { | 33 | + // 判断是否登录 |
34 | + UserEntity? userEntity = UserUtil.getUser(); | ||
35 | + Timer(const Duration(seconds: 2), () { | ||
36 | + if (userEntity != null && userEntity.token.isNotEmpty) { | ||
37 | + context.read<CacheBloc>().add(UserInfoChangeEvent(userEntity)); | ||
32 | Navigator.of(context).pushNamedAndRemoveUntil(AppRouteName.home, (route) => false); | 38 | Navigator.of(context).pushNamedAndRemoveUntil(AppRouteName.home, (route) => false); |
33 | } else { | 39 | } else { |
34 | - Navigator.of(context).pushNamedAndRemoveUntil(AppRouteName.login,(route) => false); | 40 | + Navigator.of(context).pushNamedAndRemoveUntil(AppRouteName.login, (route) => false); |
35 | } | 41 | } |
36 | }); | 42 | }); |
37 | } | 43 | } |
@@ -39,6 +45,7 @@ class _TransitionViewState extends State<TransitionView> { | @@ -39,6 +45,7 @@ class _TransitionViewState extends State<TransitionView> { | ||
39 | @override | 45 | @override |
40 | void initState() { | 46 | void initState() { |
41 | super.initState(); | 47 | super.initState(); |
48 | + SpUtil.preInit(); | ||
42 | startTime(); | 49 | startTime(); |
43 | } | 50 | } |
44 | 51 | ||
@@ -52,9 +59,7 @@ class _TransitionViewState extends State<TransitionView> { | @@ -52,9 +59,7 @@ class _TransitionViewState extends State<TransitionView> { | ||
52 | image: AssetImage( | 59 | image: AssetImage( |
53 | 'splash'.assetGif, | 60 | 'splash'.assetGif, |
54 | ), | 61 | ), |
55 | - fit: BoxFit.fill | ||
56 | - ) | ||
57 | - ), | 62 | + fit: BoxFit.fill)), |
58 | ), | 63 | ), |
59 | ), | 64 | ), |
60 | ); | 65 | ); |
lib/common/core/const.dart
0 → 100644
lib/common/core/user_util.dart
0 → 100644
1 | +import 'dart:convert'; | ||
2 | + | ||
3 | +import 'package:flutter/material.dart'; | ||
4 | +import 'package:wow_english/common/core/const.dart'; | ||
5 | +import 'package:wow_english/models/user_entity.dart'; | ||
6 | +import 'package:wow_english/route/route.dart'; | ||
7 | +import 'package:wow_english/utils/sp_util.dart'; | ||
8 | + | ||
9 | +class UserUtil { | ||
10 | + static String token = ''; | ||
11 | + | ||
12 | + static saveUser(UserEntity user) { | ||
13 | + token = user.token; | ||
14 | + SpUtil.getInstance().setData(SpConst.prefsKeyUserInfo, user.toString()); | ||
15 | + } | ||
16 | + | ||
17 | + static UserEntity? getUser() { | ||
18 | + String? userJson = getUserJson(); | ||
19 | + if (userJson != null && userJson.isNotEmpty) { | ||
20 | + var userEntity = UserEntity.fromJson(json.decode(userJson)); | ||
21 | + // todo 并且在有效期,计算一下, "expireTime": 2592000 倒计时需要手动转换,后面再优化 | ||
22 | + if (userEntity.token.isNotEmpty) { | ||
23 | + token = userEntity.token; | ||
24 | + return userEntity; | ||
25 | + } else { | ||
26 | + // token为空或失效的,清除sp | ||
27 | + clearUserSp(); | ||
28 | + } | ||
29 | + } | ||
30 | + return null; | ||
31 | + } | ||
32 | + | ||
33 | + static saveUserJson(String userJson) { | ||
34 | + SpUtil.getInstance().setData(SpConst.prefsKeyUserInfo, userJson); | ||
35 | + } | ||
36 | + | ||
37 | + static String? getUserJson() { | ||
38 | + return SpUtil.getInstance().get<String>(SpConst.prefsKeyUserInfo); | ||
39 | + } | ||
40 | + | ||
41 | + static clearUserSp() { | ||
42 | + token = ''; | ||
43 | + SpUtil.getInstance().remove(SpConst.prefsKeyUserInfo); | ||
44 | + } | ||
45 | + | ||
46 | + static logout() { | ||
47 | + clearUserSp(); | ||
48 | + Navigator.of(AppRouter.context).push(AppRouteName.login as Route<Object?>); | ||
49 | + } | ||
50 | +} |
lib/common/request/config.dart
1 | ///request config | 1 | ///request config |
2 | class RequestConfig { | 2 | class RequestConfig { |
3 | static String baseUrl = 'http://wow-app.dev.kouyuxingqiu.com/'; | 3 | static String baseUrl = 'http://wow-app.dev.kouyuxingqiu.com/'; |
4 | - static String token = ''; | ||
5 | static const connectTimeout = Duration(seconds: 15); | 4 | static const connectTimeout = Duration(seconds: 15); |
6 | static const successCode = 200; | 5 | static const successCode = 200; |
7 | } | 6 | } |
lib/common/request/dao/user_dao.dart
1 | +import 'package:wow_english/common/core/user_util.dart'; | ||
1 | import 'package:wow_english/models/user_entity.dart'; | 2 | import 'package:wow_english/models/user_entity.dart'; |
2 | 3 | ||
3 | import '../apis.dart'; | 4 | import '../apis.dart'; |
4 | import '../request_client.dart'; | 5 | import '../request_client.dart'; |
5 | 6 | ||
6 | class UserDao { | 7 | class UserDao { |
7 | - static Future<UserEntity?> login(phoneNumber, type, checkKey, checkNumber) { | 8 | + static Future<UserEntity?> login(phoneNumber, type, checkKey, checkNumber) async { |
8 | var params = {'phoneNum': phoneNumber, 'type': type, checkKey: checkNumber}; | 9 | var params = {'phoneNum': phoneNumber, 'type': type, checkKey: checkNumber}; |
9 | - var data = requestClient.post<UserEntity>( | 10 | + var data = await requestClient.post<UserEntity>( |
10 | Apis.login, | 11 | Apis.login, |
11 | data: params, | 12 | data: params, |
12 | ); | 13 | ); |
14 | + if (data != null && data.token.isNotEmpty) { | ||
15 | + UserUtil.saveUser(data); | ||
16 | + } | ||
13 | return data; | 17 | return data; |
14 | } | 18 | } |
15 | } | 19 | } |
lib/common/request/exception_handler.dart
1 | import 'package:flutter_easyloading/flutter_easyloading.dart'; | 1 | import 'package:flutter_easyloading/flutter_easyloading.dart'; |
2 | +import 'package:wow_english/common/core/user_util.dart'; | ||
2 | 3 | ||
3 | import 'exception.dart'; | 4 | import 'exception.dart'; |
4 | 5 | ||
@@ -7,8 +8,8 @@ bool handleException(ApiException exception, {bool Function(ApiException)? onErr | @@ -7,8 +8,8 @@ bool handleException(ApiException exception, {bool Function(ApiException)? onErr | ||
7 | return true; | 8 | return true; |
8 | } | 9 | } |
9 | 10 | ||
10 | - if (exception.code == 401) { | ||
11 | - ///todo to login | 11 | + if (exception.code == 405) { |
12 | + UserUtil.logout(); | ||
12 | return true; | 13 | return true; |
13 | } | 14 | } |
14 | EasyLoading.showError(exception.message ?? ApiException.unknownException); | 15 | EasyLoading.showError(exception.message ?? ApiException.unknownException); |
lib/common/request/token_interceptor.dart
1 | import 'package:dio/dio.dart'; | 1 | import 'package:dio/dio.dart'; |
2 | -import 'package:wow_english/common/request/config.dart'; | 2 | +import 'package:wow_english/common/core/user_util.dart'; |
3 | 3 | ||
4 | class TokenInterceptor extends Interceptor { | 4 | class TokenInterceptor extends Interceptor { |
5 | @override | 5 | @override |
6 | void onRequest(RequestOptions options, RequestInterceptorHandler handler) { | 6 | void onRequest(RequestOptions options, RequestInterceptorHandler handler) { |
7 | // 判断token不为空插入, todo token的取法应该跟user在一起,这里取不到user | 7 | // 判断token不为空插入, todo token的取法应该跟user在一起,这里取不到user |
8 | - if (RequestConfig.token.isNotEmpty) { | ||
9 | - options.headers["Auth-token"] = RequestConfig.token; | 8 | + if (UserUtil.token.isNotEmpty) { |
9 | + options.headers["Auth-token"] = UserUtil.token; | ||
10 | } | 10 | } |
11 | options.headers["version"] = '1.0.0'; | 11 | options.headers["version"] = '1.0.0'; |
12 | super.onRequest(options, handler); | 12 | super.onRequest(options, handler); |
lib/pages/login/loginpage/bloc/login_bloc.dart
1 | import 'package:flutter/cupertino.dart'; | 1 | import 'package:flutter/cupertino.dart'; |
2 | import 'package:flutter_bloc/flutter_bloc.dart'; | 2 | import 'package:flutter_bloc/flutter_bloc.dart'; |
3 | import 'package:flutter_easyloading/flutter_easyloading.dart'; | 3 | import 'package:flutter_easyloading/flutter_easyloading.dart'; |
4 | -import 'package:wow_english/common/request/config.dart'; | ||
5 | import 'package:wow_english/common/request/dao/user_dao.dart'; | 4 | import 'package:wow_english/common/request/dao/user_dao.dart'; |
6 | import 'package:wow_english/models/user_entity.dart'; | 5 | import 'package:wow_english/models/user_entity.dart'; |
7 | import 'package:wow_english/utils/loading.dart'; | 6 | import 'package:wow_english/utils/loading.dart'; |
@@ -72,10 +71,8 @@ class LoginBloc extends Bloc<LoginEvent, LoginState> { | @@ -72,10 +71,8 @@ class LoginBloc extends Bloc<LoginEvent, LoginState> { | ||
72 | try { | 71 | try { |
73 | await loading(() async { | 72 | await loading(() async { |
74 | var user = await UserDao.login(phoneNumber, type, checkKey, checkNumber); | 73 | var user = await UserDao.login(phoneNumber, type, checkKey, checkNumber); |
75 | - print('login已执行'); | ||
76 | print('user=$user'); | 74 | print('user=$user'); |
77 | - RequestConfig.token = user!.token; | ||
78 | - emitter.call(LoginResultChangeState(user)); | 75 | + emitter.call(LoginResultChangeState(user!)); |
79 | }); | 76 | }); |
80 | } catch (e) { | 77 | } catch (e) { |
81 | print(e); | 78 | print(e); |
lib/route/route.dart
@@ -21,8 +21,6 @@ import 'package:wow_english/pages/user/user_page.dart'; | @@ -21,8 +21,6 @@ import 'package:wow_english/pages/user/user_page.dart'; | ||
21 | import 'package:wow_english/pages/video/lookvideo/look_video_page.dart'; | 21 | import 'package:wow_english/pages/video/lookvideo/look_video_page.dart'; |
22 | import 'package:wow_english/pages/voiceanswer/voice_answer_page.dart'; | 22 | import 'package:wow_english/pages/voiceanswer/voice_answer_page.dart'; |
23 | 23 | ||
24 | - | ||
25 | - | ||
26 | class AppRouteName { | 24 | class AppRouteName { |
27 | static const String splash = 'splash'; | 25 | static const String splash = 'splash'; |
28 | static const String login = 'login'; | 26 | static const String login = 'login'; |
@@ -48,6 +46,7 @@ class AppRouteName { | @@ -48,6 +46,7 @@ class AppRouteName { | ||
48 | 46 | ||
49 | class AppRouter { | 47 | class AppRouter { |
50 | static final navigatorKey = GlobalKey<NavigatorState>(); | 48 | static final navigatorKey = GlobalKey<NavigatorState>(); |
49 | + | ||
51 | // App 根节点Context | 50 | // App 根节点Context |
52 | static BuildContext get context => navigatorKey.currentContext!; | 51 | static BuildContext get context => navigatorKey.currentContext!; |
53 | 52 | ||
@@ -56,60 +55,62 @@ class AppRouter { | @@ -56,60 +55,62 @@ class AppRouter { | ||
56 | case AppRouteName.splash: | 55 | case AppRouteName.splash: |
57 | return PageRouteBuilder( | 56 | return PageRouteBuilder( |
58 | opaque: false, | 57 | opaque: false, |
59 | - pageBuilder: (_,__,___) => const SplashPage(), | 58 | + pageBuilder: (_, __, ___) => const SplashPage(), |
60 | transitionDuration: Duration.zero, | 59 | transitionDuration: Duration.zero, |
61 | transitionsBuilder: (_, __, ___, child) => child); | 60 | transitionsBuilder: (_, __, ___, child) => child); |
62 | case AppRouteName.login: | 61 | case AppRouteName.login: |
63 | - return CupertinoPageRoute(builder: (_) => const LoginPage()); | 62 | + return CupertinoPageRoute(builder: (_) => const LoginPage()); |
64 | case AppRouteName.home: | 63 | case AppRouteName.home: |
65 | - return CupertinoPageRoute(builder: (_) => const HomePage()); | 64 | + return CupertinoPageRoute(builder: (_) => const HomePage()); |
66 | case AppRouteName.fogPwd: | 65 | case AppRouteName.fogPwd: |
67 | - return CupertinoPageRoute(builder: (_) => const ForgetPasswordHomePage()); | 66 | + return CupertinoPageRoute(builder: (_) => const ForgetPasswordHomePage()); |
68 | case AppRouteName.lesson: | 67 | case AppRouteName.lesson: |
69 | - return CupertinoPageRoute(builder: (_) => const LessonPage()); | 68 | + return CupertinoPageRoute(builder: (_) => const LessonPage()); |
70 | case AppRouteName.listen: | 69 | case AppRouteName.listen: |
71 | - return CupertinoPageRoute(builder: (_) => const ListenPage()); | 70 | + return CupertinoPageRoute(builder: (_) => const ListenPage()); |
72 | case AppRouteName.shop: | 71 | case AppRouteName.shop: |
73 | - return CupertinoPageRoute(builder: (_) => const ShopHomePage()); | 72 | + return CupertinoPageRoute(builder: (_) => const ShopHomePage()); |
74 | case AppRouteName.exLesson: | 73 | case AppRouteName.exLesson: |
75 | - return CupertinoPageRoute(builder: (_) => const ExchangeLessonPage()); | 74 | + return CupertinoPageRoute(builder: (_) => const ExchangeLessonPage()); |
76 | case AppRouteName.exList: | 75 | case AppRouteName.exList: |
77 | - return CupertinoPageRoute(builder: (_) => const ExchangeLessonListPage()); | 76 | + return CupertinoPageRoute(builder: (_) => const ExchangeLessonListPage()); |
78 | case AppRouteName.reAfter: | 77 | case AppRouteName.reAfter: |
79 | - return CupertinoPageRoute(builder: (_) => const RepeatAfterPage()); | 78 | + return CupertinoPageRoute(builder: (_) => const RepeatAfterPage()); |
80 | case AppRouteName.user: | 79 | case AppRouteName.user: |
81 | - return CupertinoPageRoute(builder: (_) => const UserPage()); | 80 | + return CupertinoPageRoute(builder: (_) => const UserPage()); |
82 | case AppRouteName.topicPic: | 81 | case AppRouteName.topicPic: |
83 | - return CupertinoPageRoute(builder: (_) => const TopicPicturePage()); | 82 | + return CupertinoPageRoute(builder: (_) => const TopicPicturePage()); |
84 | case AppRouteName.topicWord: | 83 | case AppRouteName.topicWord: |
85 | - return CupertinoPageRoute(builder: (_) => const TopicWordPage()); | 84 | + return CupertinoPageRoute(builder: (_) => const TopicWordPage()); |
86 | case AppRouteName.voicePic: | 85 | case AppRouteName.voicePic: |
87 | - return CupertinoPageRoute(builder: (_) => const VoicePicPage()); | 86 | + return CupertinoPageRoute(builder: (_) => const VoicePicPage()); |
88 | case AppRouteName.voiceWord: | 87 | case AppRouteName.voiceWord: |
89 | - return CupertinoPageRoute(builder: (_) => const VoiceWordPage()); | 88 | + return CupertinoPageRoute(builder: (_) => const VoiceWordPage()); |
90 | case AppRouteName.voiceAnswer: | 89 | case AppRouteName.voiceAnswer: |
91 | - return CupertinoPageRoute(builder: (_) => const VoiceAnswerPage()); | 90 | + return CupertinoPageRoute(builder: (_) => const VoiceAnswerPage()); |
92 | case AppRouteName.lookVideo: | 91 | case AppRouteName.lookVideo: |
93 | - return CupertinoPageRoute(builder: (_) => const LookVideoPage()); | 92 | + return CupertinoPageRoute(builder: (_) => const LookVideoPage()); |
94 | case AppRouteName.setPwd: | 93 | case AppRouteName.setPwd: |
95 | final phoneNum = (settings.arguments as Map)['phoneNumber'] as String; | 94 | final phoneNum = (settings.arguments as Map)['phoneNumber'] as String; |
96 | - return CupertinoPageRoute(builder: (_) => SetPassWordPage(phoneNum: phoneNum)); | 95 | + return CupertinoPageRoute(builder: (_) => SetPassWordPage(phoneNum: phoneNum)); |
97 | case AppRouteName.webView: | 96 | case AppRouteName.webView: |
98 | final urlStr = (settings.arguments as Map)['urlStr'] as String; | 97 | final urlStr = (settings.arguments as Map)['urlStr'] as String; |
99 | final webViewTitle = (settings.arguments as Map)['webViewTitle'] as String; | 98 | final webViewTitle = (settings.arguments as Map)['webViewTitle'] as String; |
100 | - return CupertinoPageRoute(builder: (_) => WowWebViewPage(urlStr: urlStr,webViewTitle: webViewTitle,)); | 99 | + return CupertinoPageRoute( |
100 | + builder: (_) => WowWebViewPage( | ||
101 | + urlStr: urlStr, | ||
102 | + webViewTitle: webViewTitle, | ||
103 | + )); | ||
101 | case AppRouteName.tab: | 104 | case AppRouteName.tab: |
102 | return PageRouteBuilder( | 105 | return PageRouteBuilder( |
103 | opaque: false, | 106 | opaque: false, |
104 | settings: const RouteSettings(name: AppRouteName.tab), | 107 | settings: const RouteSettings(name: AppRouteName.tab), |
105 | transitionDuration: Duration.zero, | 108 | transitionDuration: Duration.zero, |
106 | - pageBuilder: (_,__,___) => const TabPage(), | 109 | + pageBuilder: (_, __, ___) => const TabPage(), |
107 | transitionsBuilder: (_, __, ___, child) => child); | 110 | transitionsBuilder: (_, __, ___, child) => child); |
108 | default: | 111 | default: |
109 | return CupertinoPageRoute( | 112 | return CupertinoPageRoute( |
110 | - builder: (_) => Scaffold( | ||
111 | - body: Center( | ||
112 | - child: Text('No route defined for ${settings.name}')))); | 113 | + builder: (_) => Scaffold(body: Center(child: Text('No route defined for ${settings.name}')))); |
113 | } | 114 | } |
114 | } | 115 | } |
115 | } | 116 | } |
lib/utils/sp_util.dart
0 → 100644
1 | +import 'package:shared_preferences/shared_preferences.dart'; | ||
2 | + | ||
3 | +class SpUtil { | ||
4 | + SharedPreferences? _prefs; | ||
5 | + static SpUtil? _instance; | ||
6 | + | ||
7 | + SpUtil.of() { | ||
8 | + init(); | ||
9 | + } | ||
10 | + SpUtil._pre(SharedPreferences prefs) { | ||
11 | + _prefs = prefs; | ||
12 | + } | ||
13 | + | ||
14 | + static SpUtil getInstance() { | ||
15 | + _instance ??= SpUtil.of(); | ||
16 | + return _instance!; | ||
17 | + } | ||
18 | + | ||
19 | + void init() async { | ||
20 | + _prefs ??= await SharedPreferences.getInstance(); | ||
21 | + } | ||
22 | + | ||
23 | + static Future<SpUtil> preInit() async { | ||
24 | + if (_instance == null) { | ||
25 | + var prefs = await SharedPreferences.getInstance(); | ||
26 | + _instance = SpUtil._pre(prefs); | ||
27 | + } | ||
28 | + return _instance!; | ||
29 | + } | ||
30 | + | ||
31 | + void setData<T>(String key, T data) { | ||
32 | + if (data is String) { | ||
33 | + _prefs?.setString(key, data); | ||
34 | + } else if (data is double) { | ||
35 | + _prefs?.setDouble(key, data); | ||
36 | + } else if (data is int) { | ||
37 | + _prefs?.setInt(key, data); | ||
38 | + } else if (data is bool) { | ||
39 | + _prefs?.setBool(key, data); | ||
40 | + } else if (data is List<String>) { | ||
41 | + _prefs?.setStringList(key, data); | ||
42 | + } | ||
43 | + } | ||
44 | + | ||
45 | + void remove(String key) { | ||
46 | + _prefs?.remove(key); | ||
47 | + } | ||
48 | + | ||
49 | + T? get<T>(String key) { | ||
50 | + var value = _prefs?.get(key); | ||
51 | + if (value != null) { | ||
52 | + return value as T; | ||
53 | + } | ||
54 | + return null; | ||
55 | + } | ||
56 | +} |