diff --git a/lib/blocs/category/category_bloc.dart b/lib/blocs/category/category_bloc.dart index 3341f19..085ea03 100644 --- a/lib/blocs/category/category_bloc.dart +++ b/lib/blocs/category/category_bloc.dart @@ -20,11 +20,12 @@ import 'category_state.dart'; class CategoryBloc extends Bloc { final CategoryRepository repository; - CategoryBloc({@required this.repository}) : super(const CategoryEmptyState()); + CategoryBloc({@required this.repository}) : super(const CategoryLoadingState()); @override Stream mapEventToState(CategoryEvent event) async* { if (event is EventLoadCategory) { + yield const CategoryLoadingState(); // 使用 repository 加载 收藏集数据 final category = await repository.loadCategories(); yield category.isEmpty diff --git a/lib/blocs/category/category_state.dart b/lib/blocs/category/category_state.dart index 6e547f8..84c493e 100644 --- a/lib/blocs/category/category_state.dart +++ b/lib/blocs/category/category_state.dart @@ -20,6 +20,13 @@ class CategoryLoadedState extends CategoryState { List get props => [categories]; } +class CategoryLoadingState extends CategoryState { + const CategoryLoadingState(); + + List get props => []; +} + + class CategoryEmptyState extends CategoryState { const CategoryEmptyState(); diff --git a/lib/storage/dao/local_storage.dart b/lib/storage/dao/local_storage.dart index 257821e..1dc574e 100644 --- a/lib/storage/dao/local_storage.dart +++ b/lib/storage/dao/local_storage.dart @@ -7,6 +7,7 @@ import 'package:shared_preferences/shared_preferences.dart'; class LocalStorage { static String tokenKey= "token_key"; + static String userKey= "user_key"; static SharedPreferences _sp; diff --git a/lib/user_system/bloc/authentic/bloc.dart b/lib/user_system/bloc/authentic/bloc.dart index 5015dc8..b8a5a0f 100644 --- a/lib/user_system/bloc/authentic/bloc.dart +++ b/lib/user_system/bloc/authentic/bloc.dart @@ -1,8 +1,11 @@ import 'dart:async'; +import 'dart:convert'; import 'package:bloc/bloc.dart'; import 'package:flutter_unit/app/utils/http_utils/http_util.dart'; - +import 'package:flutter_unit/storage/dao/local_storage.dart'; +import 'package:flutter_unit/user_system/model/user.dart'; +import 'package:jwt_decoder/jwt_decoder.dart'; import 'event.dart'; import 'state.dart'; @@ -14,13 +17,52 @@ class AuthenticBloc extends Bloc { Stream mapEventToState( AuthEvent event, ) async* { - if (event is AppStarted) {} + if (event is AppStarted) { + String token = await LocalStorage.get(LocalStorage.tokenKey); + String userJson = await LocalStorage.get(LocalStorage.userKey); + if (token != null && userJson != null) { + bool disable = JwtDecoder.isExpired(token); + if (!disable) { + HttpUtil.getInstance().setToken(token); + yield AuthSuccess(User.fromJson(json.decode(userJson))); + }else{ + // 说明 token 过期 + await _removeToken(); + await _removeUser(); + } + } + } if (event is LoginOver) { HttpUtil.getInstance().setToken(event.token); + await _persistToken(event.token); + await _persistUser(event.user); yield AuthSuccess(event.user); } if (event is LoggedOut) {} } + + // 持久化 token + Future _persistToken(String token) async { + await LocalStorage.save(LocalStorage.tokenKey, token); + } + + + // 持久化 token + Future _removeToken() async { + await LocalStorage.remove(LocalStorage.tokenKey); + } + + // 持久化 token + Future _removeUser() async { + await LocalStorage.remove(LocalStorage.userKey); + } + + // 持久化 user + Future _persistUser(User user) async { + await LocalStorage.save(LocalStorage.userKey, json.encode(user)); + } + + } diff --git a/lib/user_system/bloc/authentic/state.dart b/lib/user_system/bloc/authentic/state.dart index af8b943..24834cd 100644 --- a/lib/user_system/bloc/authentic/state.dart +++ b/lib/user_system/bloc/authentic/state.dart @@ -34,4 +34,6 @@ class AuthSuccess extends AuthenticState { } } -class AuthLoading extends AuthenticState {} \ No newline at end of file +class AuthLoading extends AuthenticState { + +} \ No newline at end of file diff --git a/lib/user_system/bloc/register/bloc.dart b/lib/user_system/bloc/register/bloc.dart index bc972e9..67dcf7d 100644 --- a/lib/user_system/bloc/register/bloc.dart +++ b/lib/user_system/bloc/register/bloc.dart @@ -19,11 +19,15 @@ class RegisterBloc extends Bloc { ResultBean result = await UserApi.register(email: event.email, code: event.code); - // 注册成功 - if (result.data) { - yield RegisterSuccess(event.email); + if(result.data == null){ + yield RegisterError('注册失败'); }else{ - yield RegisterError(result.msg); + if (result.data) { + // 注册成功 + yield RegisterSuccess(event.email); + }else{ + yield RegisterError(result.msg); + } } } } diff --git a/lib/user_system/model/user.dart b/lib/user_system/model/user.dart index 43bcd7d..2b670f1 100644 --- a/lib/user_system/model/user.dart +++ b/lib/user_system/model/user.dart @@ -35,4 +35,13 @@ class User extends Equatable{ @override List get props => [username,email,roles,userId,userAvatar]; + + Map toJson() => { + "username": this.username, + "email": this.email, + "roles": this.roles, + "userId": this.userId, + "userAvatar": this.userAvatar, + }; + } diff --git a/lib/user_system/pages/login/login_page.dart b/lib/user_system/pages/login/login_page.dart index 8be30d0..19b25f3 100644 --- a/lib/user_system/pages/login/login_page.dart +++ b/lib/user_system/pages/login/login_page.dart @@ -14,7 +14,12 @@ class LoginPage extends StatelessWidget { return Scaffold( body: SingleChildScrollView( child: Wrap(children: [ - UnitArcBackground(height: winSize.height * 0.32), + Stack(children:[ + UnitArcBackground(height: winSize.height * 0.32), + Positioned( + top: 20, + child: BackButton(color: Colors.white)), + ]), Container( // color: Colors.green, height: winSize.height * 0.68, diff --git a/lib/user_system/pages/register/register_page.dart b/lib/user_system/pages/register/register_page.dart index cafb765..a36a36e 100644 --- a/lib/user_system/pages/register/register_page.dart +++ b/lib/user_system/pages/register/register_page.dart @@ -28,6 +28,23 @@ class _RegisterPageState extends State { final _emailCtrl = TextEditingController(text: '1981462002@qq.com'); final _codeCtrl = TextEditingController(text: ''); + ValueNotifier _enableRegister= ValueNotifier(false); + + bool get enable => _emailCtrl.text.isNotEmpty && _codeCtrl.text.isNotEmpty; + + @override + void initState() { + super.initState(); + _emailCtrl.addListener(() { + _enableRegister.value = enable; + }); + + _codeCtrl.addListener(() { + _enableRegister.value = enable; + }); + } + + @override Widget build(BuildContext context) { Size winSize = MediaQuery.of(context).size; @@ -35,7 +52,12 @@ class _RegisterPageState extends State { return Scaffold( body: SingleChildScrollView( child: Wrap(children: [ - UnitArcBackground(height: winSize.height * 0.32), + Stack(children:[ + UnitArcBackground(height: winSize.height * 0.32), + Positioned( + top: 20, + child: BackButton(color: Colors.white)), + ]), Container( width: winSize.width, height: winSize.height * 0.68, @@ -148,14 +170,20 @@ class _RegisterPageState extends State { String info = enable ? '注册中...' : '开启 Unit 新世界'; return BlocListener( listener: _listenerLogin, - child: RaisedButton( - elevation: 0, - shape: RoundedRectangleBorder( - borderRadius: BorderRadius.all(Radius.circular(20))), - color: Colors.blue, - onPressed: enable ? null : _doRegister, - child: Text(info, - style: TextStyle(color: Colors.white, fontSize: 18)))); + child: ValueListenableBuilder( + valueListenable: _enableRegister, + builder: (ctx,value,child){ + return RaisedButton( + elevation: 0, + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.all(Radius.circular(20))), + color: Colors.blue, + disabledColor: Colors.blue.withOpacity(0.6), + onPressed: (enable||!value) ? null : _doRegister, + child: Text(info, + style: TextStyle(color: Colors.white, fontSize: 18))); + }, + )); } void _listener(BuildContext context, RegisterState state) { diff --git a/lib/views/components/permanent/code/code_widget.dart b/lib/views/components/permanent/code/code_widget.dart index 18631b6..2d787eb 100644 --- a/lib/views/components/permanent/code/code_widget.dart +++ b/lib/views/components/permanent/code/code_widget.dart @@ -4,7 +4,7 @@ /// 说明: import 'package:flutter/material.dart'; -import 'package:flutter_unit/views/components/permanent/code/language/dart_languge.dart'; +import 'language/dart_languge.dart'; import 'high_light_code.dart'; import 'highlighter_style.dart'; @@ -37,6 +37,7 @@ class CodeWidget extends StatelessWidget { ), ); } catch (err) { + print(err); _codeWidget = Text(code); } body = SingleChildScrollView( diff --git a/lib/views/components/permanent/code/high_light_code.dart b/lib/views/components/permanent/code/high_light_code.dart index 3b27c50..9eecb25 100644 --- a/lib/views/components/permanent/code/high_light_code.dart +++ b/lib/views/components/permanent/code/high_light_code.dart @@ -7,6 +7,7 @@ // found in the LICENSE file. import 'package:flutter/material.dart'; +import 'package:flutter_unit/views/components/permanent/code/language/dart_languge.dart'; import 'package:flutter_unit/views/components/permanent/code/language/language.dart'; import 'package:string_scanner/string_scanner.dart'; @@ -23,9 +24,9 @@ abstract class Highlighter { // ignore: one_member_abstracts //暗黑模式下的高亮样式 class CodeHighlighter extends Highlighter { - CodeHighlighter({Language language,HighlighterStyle style}) { + CodeHighlighter({Language language= const DartLanguage(),HighlighterStyle style}) { _spans = <_HighlightSpan>[]; - language =this.language; + this.language =language; _style = style??HighlighterStyle.fromColors(HighlighterStyle.lightColor); } @@ -43,11 +44,13 @@ class CodeHighlighter extends Highlighter { _scanner = StringScanner(_src); if (_generateSpans()) { + // Successfully parsed the code final List formattedText = []; int currentPosition = 0; for (_HighlightSpan span in _spans) { + if (currentPosition != span.start) formattedText.add(TextSpan(text: _src.substring(currentPosition, span.start))); @@ -61,6 +64,7 @@ class CodeHighlighter extends Highlighter { return TextSpan(style: _style.baseStyle, children: formattedText); } else { + // Parsing failed, return with only basic formatting return TextSpan(style: _style.baseStyle, text: src); } @@ -70,6 +74,7 @@ class CodeHighlighter extends Highlighter { int lastLoopPosition = _scanner.position; while (!_scanner.isDone) { + // Skip White space _scanner.scan(RegExp(r'\s+')); @@ -102,9 +107,7 @@ class CodeHighlighter extends Highlighter { endComment )); - if (eof) - break; - + if (eof) break; continue; } @@ -211,8 +214,8 @@ class CodeHighlighter extends Highlighter { // Words if (_scanner.scan(RegExp(r'\w+'))) { _HighlightType type; - String word = _scanner.lastMatch[0]; + if (word.startsWith('_')) word = word.substring(1); @@ -233,7 +236,6 @@ class CodeHighlighter extends Highlighter { )); } } - // Check if this loop did anything if (lastLoopPosition == _scanner.position) { // Failed to parse this file, abort gracefully diff --git a/lib/views/pages/app/bloc_wrapper.dart b/lib/views/pages/app/bloc_wrapper.dart index 2485e22..301afff 100644 --- a/lib/views/pages/app/bloc_wrapper.dart +++ b/lib/views/pages/app/bloc_wrapper.dart @@ -1,6 +1,7 @@ import 'package:flutter/material.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:flutter_unit/user_system/bloc/authentic/bloc.dart'; +import 'package:flutter_unit/user_system/bloc/authentic/event.dart'; import 'package:flutter_unit/user_system/bloc/login/bloc.dart'; import 'package:flutter_unit/user_system/bloc/register/bloc.dart'; import 'package:flutter_unit/model/enums.dart'; @@ -29,7 +30,7 @@ class _BlocWrapperState extends State { final WidgetRepository repository = WidgetDbRepository(storage); final categoryBloc = CategoryBloc(repository: CategoryDbRepository(storage)); - final authBloc = AuthenticBloc(); + final authBloc = AuthenticBloc()..add(AppStarted()); @override Widget build(BuildContext context) { diff --git a/lib/views/pages/category/category_page.dart b/lib/views/pages/category/category_page.dart index 93c275a..32fe945 100644 --- a/lib/views/pages/category/category_page.dart +++ b/lib/views/pages/category/category_page.dart @@ -4,6 +4,7 @@ import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:flutter_unit/app/router/unit_router.dart'; import 'package:flutter_unit/blocs/bloc_exp.dart'; import 'package:flutter_unit/views/components/permanent/circle.dart'; +import 'package:flutter_unit/views/components/project/default/loading_shower.dart'; import 'package:flutter_unit/views/components/project/no_more_widget.dart'; import 'package:flutter_unit/model/category_model.dart'; @@ -25,6 +26,7 @@ class CategoryPage extends StatelessWidget { @override Widget build(BuildContext context) { return BlocBuilder(builder: (ctx, state) { + print(state); if (state is CategoryLoadedState) { return CustomScrollView( slivers: [ @@ -38,6 +40,7 @@ class CategoryPage extends StatelessWidget { ], ); } + if(state is CategoryLoadingState) return LoadingShower(); return EmptyCategory(); }); } diff --git a/pubspec.lock b/pubspec.lock index 0de7e32..9d35cca 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -170,6 +170,13 @@ packages: url: "https://pub.flutter-io.cn" source: hosted version: "0.16.1" + jwt_decoder: + dependency: "direct main" + description: + name: jwt_decoder + url: "https://pub.flutter-io.cn" + source: hosted + version: "1.0.4" markdown: dependency: transitive description: diff --git a/pubspec.yaml b/pubspec.yaml index 5ce9c34..c2d75b9 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -18,7 +18,7 @@ dependencies: sqflite: ^1.2.1 # 数据库 shared_preferences: ^0.5.6+3 # xml 固化 - + jwt_decoder: ^1.0.3 toggle_rotate: ^0.0.5 flutter_star: ^0.1.2 # 星星组件 url_launcher: ^5.4.2 # url