Commit 94342c3fb8dfce3d01d4d4a6ac8c82693e2084d6
1 parent
05f9b20a
feat: user util
Showing
10 changed files
with
161 additions
and
45 deletions
lib/app/splash_page.dart
1 | 1 | import 'dart:async'; |
2 | 2 | |
3 | 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 | 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 | 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 | 13 | class SplashPage extends StatelessWidget { |
10 | 14 | const SplashPage({super.key}); |
... | ... | @@ -25,13 +29,15 @@ class TransitionView extends StatefulWidget { |
25 | 29 | } |
26 | 30 | |
27 | 31 | class _TransitionViewState extends State<TransitionView> { |
28 | - | |
29 | 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 | 38 | Navigator.of(context).pushNamedAndRemoveUntil(AppRouteName.home, (route) => false); |
33 | 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 | 45 | @override |
40 | 46 | void initState() { |
41 | 47 | super.initState(); |
48 | + SpUtil.preInit(); | |
42 | 49 | startTime(); |
43 | 50 | } |
44 | 51 | |
... | ... | @@ -52,9 +59,7 @@ class _TransitionViewState extends State<TransitionView> { |
52 | 59 | image: AssetImage( |
53 | 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
lib/common/request/dao/user_dao.dart
1 | +import 'package:wow_english/common/core/user_util.dart'; | |
1 | 2 | import 'package:wow_english/models/user_entity.dart'; |
2 | 3 | |
3 | 4 | import '../apis.dart'; |
4 | 5 | import '../request_client.dart'; |
5 | 6 | |
6 | 7 | class UserDao { |
7 | - static Future<UserEntity?> login(phoneNumber, type, checkKey, checkNumber) { | |
8 | + static Future<UserEntity?> login(phoneNumber, type, checkKey, checkNumber) async { | |
8 | 9 | var params = {'phoneNum': phoneNumber, 'type': type, checkKey: checkNumber}; |
9 | - var data = requestClient.post<UserEntity>( | |
10 | + var data = await requestClient.post<UserEntity>( | |
10 | 11 | Apis.login, |
11 | 12 | data: params, |
12 | 13 | ); |
14 | + if (data != null && data.token.isNotEmpty) { | |
15 | + UserUtil.saveUser(data); | |
16 | + } | |
13 | 17 | return data; |
14 | 18 | } |
15 | 19 | } | ... | ... |
lib/common/request/exception_handler.dart
1 | 1 | import 'package:flutter_easyloading/flutter_easyloading.dart'; |
2 | +import 'package:wow_english/common/core/user_util.dart'; | |
2 | 3 | |
3 | 4 | import 'exception.dart'; |
4 | 5 | |
... | ... | @@ -7,8 +8,8 @@ bool handleException(ApiException exception, {bool Function(ApiException)? onErr |
7 | 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 | 13 | return true; |
13 | 14 | } |
14 | 15 | EasyLoading.showError(exception.message ?? ApiException.unknownException); | ... | ... |
lib/common/request/token_interceptor.dart
1 | 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 | 4 | class TokenInterceptor extends Interceptor { |
5 | 5 | @override |
6 | 6 | void onRequest(RequestOptions options, RequestInterceptorHandler handler) { |
7 | 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 | 11 | options.headers["version"] = '1.0.0'; |
12 | 12 | super.onRequest(options, handler); | ... | ... |
lib/pages/login/loginpage/bloc/login_bloc.dart
1 | 1 | import 'package:flutter/cupertino.dart'; |
2 | 2 | import 'package:flutter_bloc/flutter_bloc.dart'; |
3 | 3 | import 'package:flutter_easyloading/flutter_easyloading.dart'; |
4 | -import 'package:wow_english/common/request/config.dart'; | |
5 | 4 | import 'package:wow_english/common/request/dao/user_dao.dart'; |
6 | 5 | import 'package:wow_english/models/user_entity.dart'; |
7 | 6 | import 'package:wow_english/utils/loading.dart'; |
... | ... | @@ -72,10 +71,8 @@ class LoginBloc extends Bloc<LoginEvent, LoginState> { |
72 | 71 | try { |
73 | 72 | await loading(() async { |
74 | 73 | var user = await UserDao.login(phoneNumber, type, checkKey, checkNumber); |
75 | - print('login已执行'); | |
76 | 74 | print('user=$user'); |
77 | - RequestConfig.token = user!.token; | |
78 | - emitter.call(LoginResultChangeState(user)); | |
75 | + emitter.call(LoginResultChangeState(user!)); | |
79 | 76 | }); |
80 | 77 | } catch (e) { |
81 | 78 | print(e); | ... | ... |
lib/route/route.dart
... | ... | @@ -21,8 +21,6 @@ import 'package:wow_english/pages/user/user_page.dart'; |
21 | 21 | import 'package:wow_english/pages/video/lookvideo/look_video_page.dart'; |
22 | 22 | import 'package:wow_english/pages/voiceanswer/voice_answer_page.dart'; |
23 | 23 | |
24 | - | |
25 | - | |
26 | 24 | class AppRouteName { |
27 | 25 | static const String splash = 'splash'; |
28 | 26 | static const String login = 'login'; |
... | ... | @@ -48,6 +46,7 @@ class AppRouteName { |
48 | 46 | |
49 | 47 | class AppRouter { |
50 | 48 | static final navigatorKey = GlobalKey<NavigatorState>(); |
49 | + | |
51 | 50 | // App 根节点Context |
52 | 51 | static BuildContext get context => navigatorKey.currentContext!; |
53 | 52 | |
... | ... | @@ -56,60 +55,62 @@ class AppRouter { |
56 | 55 | case AppRouteName.splash: |
57 | 56 | return PageRouteBuilder( |
58 | 57 | opaque: false, |
59 | - pageBuilder: (_,__,___) => const SplashPage(), | |
58 | + pageBuilder: (_, __, ___) => const SplashPage(), | |
60 | 59 | transitionDuration: Duration.zero, |
61 | 60 | transitionsBuilder: (_, __, ___, child) => child); |
62 | 61 | case AppRouteName.login: |
63 | - return CupertinoPageRoute(builder: (_) => const LoginPage()); | |
62 | + return CupertinoPageRoute(builder: (_) => const LoginPage()); | |
64 | 63 | case AppRouteName.home: |
65 | - return CupertinoPageRoute(builder: (_) => const HomePage()); | |
64 | + return CupertinoPageRoute(builder: (_) => const HomePage()); | |
66 | 65 | case AppRouteName.fogPwd: |
67 | - return CupertinoPageRoute(builder: (_) => const ForgetPasswordHomePage()); | |
66 | + return CupertinoPageRoute(builder: (_) => const ForgetPasswordHomePage()); | |
68 | 67 | case AppRouteName.lesson: |
69 | - return CupertinoPageRoute(builder: (_) => const LessonPage()); | |
68 | + return CupertinoPageRoute(builder: (_) => const LessonPage()); | |
70 | 69 | case AppRouteName.listen: |
71 | - return CupertinoPageRoute(builder: (_) => const ListenPage()); | |
70 | + return CupertinoPageRoute(builder: (_) => const ListenPage()); | |
72 | 71 | case AppRouteName.shop: |
73 | - return CupertinoPageRoute(builder: (_) => const ShopHomePage()); | |
72 | + return CupertinoPageRoute(builder: (_) => const ShopHomePage()); | |
74 | 73 | case AppRouteName.exLesson: |
75 | - return CupertinoPageRoute(builder: (_) => const ExchangeLessonPage()); | |
74 | + return CupertinoPageRoute(builder: (_) => const ExchangeLessonPage()); | |
76 | 75 | case AppRouteName.exList: |
77 | - return CupertinoPageRoute(builder: (_) => const ExchangeLessonListPage()); | |
76 | + return CupertinoPageRoute(builder: (_) => const ExchangeLessonListPage()); | |
78 | 77 | case AppRouteName.reAfter: |
79 | - return CupertinoPageRoute(builder: (_) => const RepeatAfterPage()); | |
78 | + return CupertinoPageRoute(builder: (_) => const RepeatAfterPage()); | |
80 | 79 | case AppRouteName.user: |
81 | - return CupertinoPageRoute(builder: (_) => const UserPage()); | |
80 | + return CupertinoPageRoute(builder: (_) => const UserPage()); | |
82 | 81 | case AppRouteName.topicPic: |
83 | - return CupertinoPageRoute(builder: (_) => const TopicPicturePage()); | |
82 | + return CupertinoPageRoute(builder: (_) => const TopicPicturePage()); | |
84 | 83 | case AppRouteName.topicWord: |
85 | - return CupertinoPageRoute(builder: (_) => const TopicWordPage()); | |
84 | + return CupertinoPageRoute(builder: (_) => const TopicWordPage()); | |
86 | 85 | case AppRouteName.voicePic: |
87 | - return CupertinoPageRoute(builder: (_) => const VoicePicPage()); | |
86 | + return CupertinoPageRoute(builder: (_) => const VoicePicPage()); | |
88 | 87 | case AppRouteName.voiceWord: |
89 | - return CupertinoPageRoute(builder: (_) => const VoiceWordPage()); | |
88 | + return CupertinoPageRoute(builder: (_) => const VoiceWordPage()); | |
90 | 89 | case AppRouteName.voiceAnswer: |
91 | - return CupertinoPageRoute(builder: (_) => const VoiceAnswerPage()); | |
90 | + return CupertinoPageRoute(builder: (_) => const VoiceAnswerPage()); | |
92 | 91 | case AppRouteName.lookVideo: |
93 | - return CupertinoPageRoute(builder: (_) => const LookVideoPage()); | |
92 | + return CupertinoPageRoute(builder: (_) => const LookVideoPage()); | |
94 | 93 | case AppRouteName.setPwd: |
95 | 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 | 96 | case AppRouteName.webView: |
98 | 97 | final urlStr = (settings.arguments as Map)['urlStr'] as String; |
99 | 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 | 104 | case AppRouteName.tab: |
102 | 105 | return PageRouteBuilder( |
103 | 106 | opaque: false, |
104 | 107 | settings: const RouteSettings(name: AppRouteName.tab), |
105 | 108 | transitionDuration: Duration.zero, |
106 | - pageBuilder: (_,__,___) => const TabPage(), | |
109 | + pageBuilder: (_, __, ___) => const TabPage(), | |
107 | 110 | transitionsBuilder: (_, __, ___, child) => child); |
108 | 111 | default: |
109 | 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 | +} | ... | ... |