From 062e8f544cb4873bbdd9316592da04e6d2865598 Mon Sep 17 00:00:00 2001 From: toly <1981462002@qq.com> Date: Sun, 24 Jan 2021 08:10:16 +0800 Subject: [PATCH] =?UTF-8?q?=E7=99=BB=E5=BD=95=E5=92=8C=E6=B3=A8=E5=86=8C?= =?UTF-8?q?=E9=80=BB=E8=BE=91=E6=B5=8B=E8=AF=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- lib/app/api/system_api.dart | 21 +++ lib/app/api/user_api.dart | 48 +++++- lib/app/res/path_unit.dart | 13 ++ lib/app/utils/Toast.dart | 7 +- lib/app/utils/http_utils/http_util.dart | 71 ++++++++ .../utils/http_utils/logs_interceptor.dart | 30 ++++ .../http_utils/response_interceptor.dart | 27 +++ lib/app/utils/http_utils/result_bean.dart | 28 +++ .../utils/http_utils/token_interceptor.dart | 21 +++ lib/blocs/authentic/bloc.dart | 27 +++ lib/blocs/authentic/event.dart | 42 +++++ lib/blocs/authentic/state.dart | 37 ++++ lib/blocs/login/bloc.dart | 38 +++++ lib/blocs/login/event.dart | 24 +++ lib/blocs/login/state.dart | 54 ++++++ lib/blocs/register/bloc.dart | 14 +- lib/blocs/register/state.dart | 6 + lib/model/user.dart | 34 ++++ .../permanent/code/code_widget.dart | 7 +- .../permanent/code/high_light_code.dart | 26 +-- .../permanent/code/language/dart_languge.dart | 49 ++++++ .../permanent/code/language/language.dart | 17 ++ .../permanent/markdown/markdown_widget.dart | 24 +-- .../markdown/syntax_high_lighter.dart | 98 +++++------ lib/views/pages/app/bloc_wrapper.dart | 9 + lib/views/pages/login/login_form.dart | 161 ++++++++++++------ lib/views/pages/login/login_page.dart | 49 ++---- lib/views/pages/me/me_page.dart | 36 ++-- lib/views/pages/register/register_page.dart | 109 +++++++++--- lib/views/pages/register/send_code.dart | 26 ++- 30 files changed, 932 insertions(+), 221 deletions(-) create mode 100644 lib/app/api/system_api.dart create mode 100644 lib/app/res/path_unit.dart create mode 100644 lib/app/utils/http_utils/http_util.dart create mode 100644 lib/app/utils/http_utils/logs_interceptor.dart create mode 100644 lib/app/utils/http_utils/response_interceptor.dart create mode 100644 lib/app/utils/http_utils/result_bean.dart create mode 100644 lib/app/utils/http_utils/token_interceptor.dart create mode 100644 lib/blocs/authentic/bloc.dart create mode 100644 lib/blocs/authentic/event.dart create mode 100644 lib/blocs/authentic/state.dart create mode 100644 lib/blocs/login/bloc.dart create mode 100644 lib/blocs/login/event.dart create mode 100644 lib/blocs/login/state.dart create mode 100644 lib/model/user.dart create mode 100644 lib/views/components/permanent/code/language/dart_languge.dart create mode 100644 lib/views/components/permanent/code/language/language.dart diff --git a/lib/app/api/system_api.dart b/lib/app/api/system_api.dart new file mode 100644 index 0000000..69363e9 --- /dev/null +++ b/lib/app/api/system_api.dart @@ -0,0 +1,21 @@ +import 'package:flutter/cupertino.dart'; +import 'package:flutter_unit/app/res/path_unit.dart'; +import 'package:flutter_unit/app/utils/http_utils/http_util.dart'; +import 'package:flutter_unit/app/utils/http_utils/result_bean.dart'; + +/// create by 张风捷特烈 on 2021/1/17 +/// contact me by email 1981462002@qq.com +/// 说明: + +class SystemApi { + static Future> sendEmail({@required String email}) async { + var result = + await HttpUtil.getInstance().client.post(PathUnit.sendEmail + "$email"); + + if (result.data != null) { + return ResultBean.fromData(result.data); + } + + return ResultBean.error('请求错误'); + } +} diff --git a/lib/app/api/user_api.dart b/lib/app/api/user_api.dart index add0f9e..400f08f 100644 --- a/lib/app/api/user_api.dart +++ b/lib/app/api/user_api.dart @@ -1,12 +1,52 @@ +import 'package:flutter_unit/app/res/path_unit.dart'; +import 'package:flutter_unit/app/utils/http_utils/http_util.dart'; +import 'package:flutter_unit/app/utils/http_utils/result_bean.dart'; +import 'package:flutter_unit/model/user.dart'; + /// create by 张风捷特烈 on 2021/1/17 /// contact me by email 1981462002@qq.com -/// 说明: +/// 说明: -class UserApi{ +class UserApi { + static Future> register({String email, String code}) async { + HttpUtil.getInstance().client.get(PathUnit.register); - Future register({String email,String code}){ + var result = await HttpUtil.getInstance().client.post(PathUnit.register, + data: {"email": email, "activeCode": code}).catchError((err) { + return ResultBean.error('请求错误: ${err.toString()}'); + }); + if (result.data != null) { + return ResultBean.fromData(result.data); + } + return ResultBean.error('请求错误'); } -} \ No newline at end of file + static Future> login({String username, String password}) async { + + var result = await HttpUtil.getInstance().client.post(PathUnit.login, + data: {"username": username, "password": password}).catchError((err) { + return ResultBean.error('请求错误: ${err.toString()}'); + }); + + if (result.data != null) { + if(result.data['status']){ + return ResultBean( + msg: result.data['msg'], + data: User.fromJson(result.data['data']), + status: result.data['status'], + ); + }else{ + return ResultBean( + msg: result.data['msg'], + data: null, + status: false, + ); + } + + } + + return ResultBean.error('请求错误'); + } +} diff --git a/lib/app/res/path_unit.dart b/lib/app/res/path_unit.dart new file mode 100644 index 0000000..937216c --- /dev/null +++ b/lib/app/res/path_unit.dart @@ -0,0 +1,13 @@ +/// create by 张风捷特烈 on 2021/1/17 +/// contact me by email 1981462002@qq.com +/// 说明: + +class PathUnit{ + + static const baseUrl='http://119.45.173.197:8080/api/v1'; + + static const sendEmail = '/sendEmail/'; + static const register = '/register'; + static const login = '/login'; + +} \ No newline at end of file diff --git a/lib/app/utils/Toast.dart b/lib/app/utils/Toast.dart index 67f5017..f431d62 100644 --- a/lib/app/utils/Toast.dart +++ b/lib/app/utils/Toast.dart @@ -3,12 +3,15 @@ import 'package:flutter/material.dart'; class Toast { static toast(BuildContext context, String msg, - {duration = const Duration(milliseconds: 600),SnackBarAction action}) { + {duration = const Duration(milliseconds: 600), + Color color, + SnackBarAction action}) { + Scaffold.of(context).showSnackBar(SnackBar( content: Text(msg), duration: duration, action: action, - backgroundColor: Theme.of(context).primaryColor, + backgroundColor: color??Theme.of(context).primaryColor, )); } } diff --git a/lib/app/utils/http_utils/http_util.dart b/lib/app/utils/http_utils/http_util.dart new file mode 100644 index 0000000..24a03b1 --- /dev/null +++ b/lib/app/utils/http_utils/http_util.dart @@ -0,0 +1,71 @@ + +import 'package:dio/dio.dart'; +import 'package:flutter_unit/app/res/path_unit.dart'; +import 'package:flutter_unit/app/utils/http_utils/response_interceptor.dart'; + +import 'logs_interceptor.dart'; +import 'result_bean.dart'; +import 'token_interceptor.dart'; + +const int _kReceiveTimeout = 5000; +const int _kSendTimeout = 5000; +const int _kConnectTimeout = 5000; + +class HttpUtil { + static HttpUtil _instance = HttpUtil._internal(); + Dio _dio; + + + + + static const CODE_SUCCESS = 200; + static const CODE_TIME_OUT = -1; + + factory HttpUtil() => _instance; + TokenInterceptors tokenInterceptors; + + ///通用全局单例,第一次使用时初始化 + HttpUtil._internal() { + if (null == _dio) { + _dio = Dio(BaseOptions( + baseUrl: PathUnit.baseUrl, + connectTimeout: _kReceiveTimeout, + receiveTimeout: _kConnectTimeout, + sendTimeout: _kSendTimeout, + )); + _dio.interceptors.add(LogsInterceptors()); + // _dio.interceptors.add(ResponseInterceptors()); + } + } + + static HttpUtil getInstance() { + return _instance._default(); + + } + + Dio get client => _dio; + + void setToken(String token){ + print('---token---$token-------'); + tokenInterceptors = TokenInterceptors(token: token); + _dio.interceptors.add(tokenInterceptors); + } + void deleteToken(){ + _dio.interceptors.remove(tokenInterceptors); + } + + void rebase(String baseIp) { + _dio.options.baseUrl = baseIp; + } + + //一般请求,默认域名 + HttpUtil _default() { + if (_dio != null) { + _dio.options.baseUrl=PathUnit.baseUrl; + _dio.options.headers = {}; + } + return this; + } +} + + diff --git a/lib/app/utils/http_utils/logs_interceptor.dart b/lib/app/utils/http_utils/logs_interceptor.dart new file mode 100644 index 0000000..c6787d0 --- /dev/null +++ b/lib/app/utils/http_utils/logs_interceptor.dart @@ -0,0 +1,30 @@ +import 'package:dio/dio.dart'; + +class LogsInterceptors extends InterceptorsWrapper { + @override + onRequest(RequestOptions options) async{ +// print("==========请求baseUrl:${options.baseUrl} =========="); +// print("==========请求url:${options.path} =========="); +// print('==========请求头: ' + options.headers.toString()+"=========="); +// if (options.data != null) { +// print('==========请求参数: ' + options.data.toString()+"=========="); +// } + return options; + } + + @override + onResponse(Response response)async { + if (response != null) { + var responseStr = response.toString(); + } + + return response; // continue + } + + @override + onError(DioError err) async{ + print('==========请求异常: ' + err.toString()+"=========="); + print('==========请求异常信息: ' + err.response?.toString()+"==========" ?? "=========="); + return err; + } +} \ No newline at end of file diff --git a/lib/app/utils/http_utils/response_interceptor.dart b/lib/app/utils/http_utils/response_interceptor.dart new file mode 100644 index 0000000..008204f --- /dev/null +++ b/lib/app/utils/http_utils/response_interceptor.dart @@ -0,0 +1,27 @@ +// import 'package:dio/dio.dart'; +// import 'result_bean.dart'; +// +// // 拦截返回数据,进行统一处理 +// class ResponseInterceptors extends InterceptorsWrapper { +// @override +// onResponse(Response response) async { +// RequestOptions option = response.request; +// +// if (option.contentType != null && option.contentType.contains("text")) { +// return ResultBean(data: response.data, status: true, msg: ''); +// } +// +// ///一般只需要处理200的情况,300、400、500保留错误信息,外层为http协议定义的响应码 +// if (response.statusCode == 200 || response.statusCode == 201) { +// ///内层需要根据公司实际返回结构解析,一般会有code,data,msg字段 +// bool status = response.data["status"]; +// String msg = response.data["msg"]; +// var result = response.data; +// return ResultBean( +// data: result, +// status: status, +// msg: msg, +// ); +// } +// } +// } diff --git a/lib/app/utils/http_utils/result_bean.dart b/lib/app/utils/http_utils/result_bean.dart new file mode 100644 index 0000000..e93e692 --- /dev/null +++ b/lib/app/utils/http_utils/result_bean.dart @@ -0,0 +1,28 @@ +class ResultBean { + T data; + bool status; + String msg; + + ResultBean({this.data, this.status, this.msg}); + + @override + String toString() { + return 'RepResult{data: $data, status: $status, msg:$msg}'; + } + + static ResultBean fromData(dynamic data) { + return ResultBean( + msg: data['msg'], + data: data['data'], + status: data['status'], + ); + } + + static ResultBean error(String msg) { + return ResultBean( + msg: msg, + data: null, + status: false, + ); + } +} diff --git a/lib/app/utils/http_utils/token_interceptor.dart b/lib/app/utils/http_utils/token_interceptor.dart new file mode 100644 index 0000000..398ae7f --- /dev/null +++ b/lib/app/utils/http_utils/token_interceptor.dart @@ -0,0 +1,21 @@ +import 'package:dio/dio.dart'; + +const String _kTokenKey = 'Authorization'; +const String _kTokenPrefix = 'Bearer '; + +class TokenInterceptors extends InterceptorsWrapper { + + String token; + + + TokenInterceptors({this.token=''}); + + @override + Future onRequest(RequestOptions options) async{ + // print('----RequestOptions---${options.path}------------'); + if(token.isNotEmpty){ + options.headers[_kTokenKey] = '$_kTokenPrefix$token'; + } + return options; + } +} diff --git a/lib/blocs/authentic/bloc.dart b/lib/blocs/authentic/bloc.dart new file mode 100644 index 0000000..0233030 --- /dev/null +++ b/lib/blocs/authentic/bloc.dart @@ -0,0 +1,27 @@ +import 'dart:async'; +import 'dart:io'; + +import 'package:bloc/bloc.dart'; +import 'package:flutter/foundation.dart'; +import 'package:flutter_unit/app/utils/http_utils/http_util.dart'; +import 'package:flutter_unit/blocs/authentic/state.dart'; + +import 'event.dart'; + +class AuthenticBloc extends Bloc { + AuthenticBloc() : super(AuthInitial()); + + @override + Stream mapEventToState( + AuthEvent event, + ) async* { + if (event is AppStarted) {} + + if (event is LoginOver) { + HttpUtil.getInstance().setToken(event.token); + yield AuthSuccess(event.user); + } + + if (event is LoggedOut) {} + } +} diff --git a/lib/blocs/authentic/event.dart b/lib/blocs/authentic/event.dart new file mode 100644 index 0000000..e77f29c --- /dev/null +++ b/lib/blocs/authentic/event.dart @@ -0,0 +1,42 @@ +import 'package:equatable/equatable.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_unit/model/user.dart'; + + + +///********************************验证行为******************************** + +abstract class AuthEvent extends Equatable { + const AuthEvent(); + + @override + List get props => []; +} + +class AppStarted extends AuthEvent {} + +class LoginOver extends AuthEvent { + final String token; + final User user; + + const LoginOver({@required this.token,this.user}); + + @override + List get props => [token]; + + @override + String toString() => 'LoginOver { token: $token }'; +} + +class LoggedOut extends AuthEvent { + + final bool clearUser; + final bool tokenDisable; + + LoggedOut({this.clearUser=true,this.tokenDisable=false}); +} + +class TokenDisabled extends AuthEvent { + + TokenDisabled(); +} \ No newline at end of file diff --git a/lib/blocs/authentic/state.dart b/lib/blocs/authentic/state.dart new file mode 100644 index 0000000..ade7cc4 --- /dev/null +++ b/lib/blocs/authentic/state.dart @@ -0,0 +1,37 @@ + +import 'package:equatable/equatable.dart'; +import 'package:flutter_unit/model/user.dart'; + + + +///********************************校验状态******************************** +// +abstract class AuthenticState extends Equatable { + @override + List get props => []; +} + + +class AuthInitial extends AuthenticState {} + + + +class AuthFailure extends AuthenticState { + +} + + +class LogOuted extends AuthenticState {} + +class AuthSuccess extends AuthenticState { + final User user; + + AuthSuccess(this.user); + + @override + String toString() { + return 'AuthSuccess{loginResult: $user}'; + } +} + +class AuthLoading extends AuthenticState {} \ No newline at end of file diff --git a/lib/blocs/login/bloc.dart b/lib/blocs/login/bloc.dart new file mode 100644 index 0000000..f56e530 --- /dev/null +++ b/lib/blocs/login/bloc.dart @@ -0,0 +1,38 @@ +import 'package:flutter/foundation.dart'; +import 'package:flutter_bloc/flutter_bloc.dart'; +import 'package:flutter_unit/app/api/user_api.dart'; +import 'package:flutter_unit/app/utils/http_utils/http_util.dart'; +import 'package:flutter_unit/app/utils/http_utils/result_bean.dart'; +import 'package:flutter_unit/blocs/authentic/bloc.dart'; +import 'package:flutter_unit/blocs/authentic/event.dart'; +import 'package:flutter_unit/model/user.dart'; + +import 'event.dart'; +import 'state.dart'; + +/// create by 张风捷特烈 on 2021/1/17 +/// contact me by email 1981462002@qq.com +/// 说明: + +class LoginBloc extends Bloc { + final AuthenticBloc authenticBloc; + + LoginBloc({ @required this.authenticBloc}) : super(LoginNone()); + + @override + Stream mapEventToState(LoginEvent event) async* { + if (event is DoLogin) { + yield LoginLoading(); + await Future.delayed(Duration(milliseconds: 500)); + ResultBean result = await UserApi.login(username: event.username, password: event.password); + + if (result.status) { + // 注册成功 + authenticBloc.add(LoginOver(token: result.msg,user: result.data)); + yield LoginSuccess(result.data); + } else { + yield LoginError('用户名和密码不匹配'); + } + } + } +} diff --git a/lib/blocs/login/event.dart b/lib/blocs/login/event.dart new file mode 100644 index 0000000..3740d8e --- /dev/null +++ b/lib/blocs/login/event.dart @@ -0,0 +1,24 @@ +import 'package:equatable/equatable.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_unit/model/enums.dart'; +import 'package:flutter_unit/storage/po/widget_po.dart'; +import 'package:flutter_unit/model/widget_model.dart'; + +/// create by 张风捷特烈 on 2020-03-03 +/// contact me by email 1981462002@qq.com +/// 说明: + +abstract class LoginEvent extends Equatable { + const LoginEvent(); + + @override + List get props => []; +} + +// 发送 邮箱验证 +class DoLogin extends LoginEvent { + final String username; + final String password; + + DoLogin({this.username, this.password}); +} diff --git a/lib/blocs/login/state.dart b/lib/blocs/login/state.dart new file mode 100644 index 0000000..621879f --- /dev/null +++ b/lib/blocs/login/state.dart @@ -0,0 +1,54 @@ +import 'package:equatable/equatable.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_unit/model/enums.dart'; +import 'package:flutter_unit/app/res/cons.dart'; +import 'package:flutter_unit/model/user.dart'; +import 'package:flutter_unit/model/widget_model.dart'; + +/// create by 张风捷特烈 on 2020-03-03 +/// contact me by email 1981462002@qq.com +/// 说明: 主页 Widget 列表 状态类 + +abstract class LoginState extends Equatable { + const LoginState(); + + @override + List get props => []; +} + +class LoginLoading extends LoginState { + @override + List get props => []; +} + +class LoginError extends LoginState { + final String message; + + const LoginError(this.message); + + @override + List get props => [message]; + + @override + String toString() { + return 'LoginError{message: $message}'; + } +} + +class LoginSuccess extends LoginState { + final User user; + + const LoginSuccess(this.user); + + @override + List get props => [user]; +} + +class LoginNone extends LoginState { + + + const LoginNone(); + + @override + List get props => []; +} diff --git a/lib/blocs/register/bloc.dart b/lib/blocs/register/bloc.dart index aeb8fb4..2fa2ceb 100644 --- a/lib/blocs/register/bloc.dart +++ b/lib/blocs/register/bloc.dart @@ -1,4 +1,7 @@ import 'package:flutter_bloc/flutter_bloc.dart'; +import 'package:flutter_unit/app/api/system_api.dart'; +import 'package:flutter_unit/app/api/user_api.dart'; +import 'package:flutter_unit/app/utils/http_utils/result_bean.dart'; import 'event.dart'; import 'state.dart'; @@ -8,12 +11,21 @@ import 'state.dart'; /// 说明: class RegisterBloc extends Bloc { - RegisterBloc() : super(RegisterLoading()); + RegisterBloc() : super(RegisterNone()); @override Stream mapEventToState(RegisterEvent event) async* { if (event is DoRegister) { yield RegisterLoading(); + ResultBean result = + await UserApi.register(email: event.email, code: event.code); + + // 注册成功 + if (result.data) { + yield RegisterSuccess(event.email); + }else{ + yield RegisterError(result.msg); + } } } } diff --git a/lib/blocs/register/state.dart b/lib/blocs/register/state.dart index 3dc78b2..668a1b7 100644 --- a/lib/blocs/register/state.dart +++ b/lib/blocs/register/state.dart @@ -20,6 +20,12 @@ class RegisterLoading extends RegisterState { List get props => []; } +class RegisterNone extends RegisterState { + @override + List get props => []; +} + + class RegisterError extends RegisterState { final String message; diff --git a/lib/model/user.dart b/lib/model/user.dart new file mode 100644 index 0000000..503786b --- /dev/null +++ b/lib/model/user.dart @@ -0,0 +1,34 @@ +import 'package:equatable/equatable.dart'; + +/// create by 张风捷特烈 on 2021/1/17 +/// contact me by email 1981462002@qq.com +/// 说明: + +// "userId": 1302422300380954625, +// "username": "toly", +// "email": "1981462001@qq.com", +// "activeCode": 1, +// "roles": "admin", +// "createAt": "2020-09-06T01:44:09.000+00:00", +// "updateAt": "2020-12-12T06:35:22.000+00:00" + +class User extends Equatable{ + final String username; + final String email; + final String roles; + final int userId; + + const User({this.username, this.email, this.roles, this.userId}); + + factory User.fromJson(Map map) { + return User( + username: map['username'], + email: map['email'], + roles: map['roles'], + userId: map['userId'], + ); + } + + @override + List get props => [username,email,roles,userId]; +} diff --git a/lib/views/components/permanent/code/code_widget.dart b/lib/views/components/permanent/code/code_widget.dart index be8d647..18631b6 100644 --- a/lib/views/components/permanent/code/code_widget.dart +++ b/lib/views/components/permanent/code/code_widget.dart @@ -4,6 +4,7 @@ /// 说明: import 'package:flutter/material.dart'; +import 'package:flutter_unit/views/components/permanent/code/language/dart_languge.dart'; import 'high_light_code.dart'; import 'highlighter_style.dart'; @@ -28,7 +29,11 @@ class CodeWidget extends StatelessWidget { _codeWidget = RichText( text: TextSpan( style: TextStyle(fontSize: fontSize,fontFamily: fontFamily), - children: [DartHighlighter(style).format(code)], + children: [ + CodeHighlighter( + style: style, + language: const DartLanguage() + ).format(code)], ), ); } catch (err) { diff --git a/lib/views/components/permanent/code/high_light_code.dart b/lib/views/components/permanent/code/high_light_code.dart index e3987e1..3b27c50 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/language.dart'; import 'package:string_scanner/string_scanner.dart'; import 'highlighter_style.dart'; @@ -16,31 +17,20 @@ import 'highlighter_style.dart'; abstract class Highlighter { // ignore: one_member_abstracts + Language language; TextSpan format(String src); } //暗黑模式下的高亮样式 -class DartHighlighter extends Highlighter { - DartHighlighter([this._style]) { +class CodeHighlighter extends Highlighter { + CodeHighlighter({Language language,HighlighterStyle style}) { _spans = <_HighlightSpan>[]; - _style ??= HighlighterStyle.fromColors(HighlighterStyle.lightColor); + language =this.language; + _style = style??HighlighterStyle.fromColors(HighlighterStyle.lightColor); } HighlighterStyle _style; - static const List _keywords = [ - 'abstract', 'as', 'assert', 'async', 'await', 'break', 'case', 'catch', - 'class', 'const', 'continue', 'default', 'deferred', 'do', 'dynamic', 'else', - 'enum', 'export', 'external', 'extends', 'factory', 'false', 'final', - 'finally', 'for', 'get', 'if', 'implements', 'import', 'in', 'is', 'library', - 'new', 'null', 'operator', 'part', 'rethrow', 'return', 'set', 'static', - 'super', 'switch', 'sync', 'this', 'throw', 'true', 'try', 'typedef', 'var', - 'void', 'while', 'with', 'yield' - ]; - - static const List _builtInTypes = [ - 'int', 'double', 'num', 'bool' - ]; String _src; StringScanner _scanner; @@ -226,9 +216,9 @@ class DartHighlighter extends Highlighter { if (word.startsWith('_')) word = word.substring(1); - if (_keywords.contains(word)) + if (language.containsKeywords(word)) type = _HighlightType.keyword; - else if (_builtInTypes.contains(word)) + else if (language.containsInTypes(word)) type = _HighlightType.keyword; else if (_firstLetterIsUpperCase(word)) type = _HighlightType.klass; diff --git a/lib/views/components/permanent/code/language/dart_languge.dart b/lib/views/components/permanent/code/language/dart_languge.dart new file mode 100644 index 0000000..4694cfd --- /dev/null +++ b/lib/views/components/permanent/code/language/dart_languge.dart @@ -0,0 +1,49 @@ +import 'package:flutter_unit/views/components/permanent/code/language/language.dart'; + +/// create by 张风捷特烈 on 2021/1/21 +/// contact me by email 1981462002@qq.com +/// 说明: + +class DartLanguage extends Language{ + + const DartLanguage() : super('Dart'); + + static const List _kDartKeywords = [ + 'abstract', 'as', 'assert', 'async', 'await', 'break', 'case', 'catch', + 'class', 'const', 'continue', 'default', 'deferred', 'do', 'dynamic', 'else', + 'enum', 'export', 'external', 'extends', 'factory', 'false', 'final', + 'finally', 'for', 'get', 'if', 'implements', 'import', 'in', 'is', 'library', + 'new', 'null', 'operator', 'part', 'rethrow', 'return', 'set', 'static', + 'super', 'switch', 'sync', 'this', 'throw', 'true', 'try', 'typedef', 'var', + 'void', 'while', 'with', 'yield' + ]; + + static const List _kDartInTypes = [ + 'int', 'double', 'num', 'bool' + ]; + + @override + List get keywords => [ + 'abstract', 'as', 'assert', 'async', 'await', 'break', 'case', 'catch', + 'class', 'const', 'continue', 'default', 'deferred', 'do', 'dynamic', 'else', + 'enum', 'export', 'external', 'extends', 'factory', 'false', 'final', + 'finally', 'for', 'get', 'if', 'implements', 'import', 'in', 'is', 'library', + 'new', 'null', 'operator', 'part', 'rethrow', 'return', 'set', 'static', + 'super', 'switch', 'sync', 'this', 'throw', 'true', 'try', 'typedef', 'var', + 'void', 'while', 'with', 'yield' + ]; + + @override + List get inTypes => [ + 'int', 'double', 'num', 'bool' + ]; + + @override + bool containsInTypes(String word) =>_kDartKeywords.contains(word); + + @override + bool containsKeywords(String word)=>_kDartInTypes.contains(word); + + + +} \ No newline at end of file diff --git a/lib/views/components/permanent/code/language/language.dart b/lib/views/components/permanent/code/language/language.dart new file mode 100644 index 0000000..c2ea52d --- /dev/null +++ b/lib/views/components/permanent/code/language/language.dart @@ -0,0 +1,17 @@ +/// create by 张风捷特烈 on 2021/1/21 +/// contact me by email 1981462002@qq.com +/// 说明: + +abstract class Language { + final String name; + + const Language(this.name); + + bool containsKeywords(String word); + + bool containsInTypes(String word); + + List get keywords; + + List get inTypes; +} diff --git a/lib/views/components/permanent/markdown/markdown_widget.dart b/lib/views/components/permanent/markdown/markdown_widget.dart index a85cc98..51a6a3a 100644 --- a/lib/views/components/permanent/markdown/markdown_widget.dart +++ b/lib/views/components/permanent/markdown/markdown_widget.dart @@ -18,16 +18,16 @@ class MarkdownWidget extends StatelessWidget { MarkdownStyleSheet _getCommonSheet(BuildContext context, Color codeBackground) { MarkdownStyleSheet markdownStyleSheet = MarkdownStyleSheet.fromTheme(Theme.of(context)); return markdownStyleSheet.copyWith( - codeblockDecoration: new BoxDecoration( + codeblockDecoration: BoxDecoration( borderRadius: BorderRadius.all(Radius.circular(4.0)), color: codeBackground, - border: new Border.all( + border: Border.all( color: UnitColor.subTextColor, width: 0.3))) .copyWith( - blockquoteDecoration: new BoxDecoration( + blockquoteDecoration: BoxDecoration( borderRadius: BorderRadius.all(Radius.circular(4.0)), color: UnitColor.subTextColor, - border: new Border.all( + border: Border.all( color: UnitColor.subTextColor, width: 0.3)), blockquote: TStyleUnit.smallTextWhite); } @@ -104,9 +104,9 @@ class MarkdownWidget extends StatelessWidget { _getMarkDownData(String markdownData) { ///优化图片显示 - RegExp exp = new RegExp(r'!\[.*\]\((.+)\)'); - RegExp expImg = new RegExp("|\/>)"); - RegExp expSrc = new RegExp("src=[\'\"]?([^\'\"]*)[\'\"]?"); + RegExp exp = RegExp(r'!\[.*\]\((.+)\)'); + RegExp expImg = RegExp("|\/>)"); + RegExp expSrc = RegExp("src=[\'\"]?([^\'\"]*)[\'\"]?"); String mdDataCode = markdownData; try { @@ -119,7 +119,7 @@ class MarkdownWidget extends StatelessWidget { if (!match.contains(".svg") && match.contains("http")) { ///增加点击 String src = match - .replaceAll(new RegExp(r'!\[.*\]\('), "") + .replaceAll( RegExp(r'!\[.*\]\('), "") .replaceAll(")", ""); String actionMatch = "[$match]($src)"; match = actionMatch; @@ -164,9 +164,9 @@ class MarkdownWidget extends StatelessWidget { color: _getBackgroundColor(context), padding: EdgeInsets.all(5.0), child: SingleChildScrollView( - child: new MarkdownBody( + child: MarkdownBody( styleSheet: _getStyle(context), - syntaxHighlighter: new GSYHighlighter(), + syntaxHighlighter: Highlighter(), data: _getMarkDownData(markdownData), onTapLink: (String source) { // CommonUtils.launchUrl(context, source); @@ -177,11 +177,11 @@ class MarkdownWidget extends StatelessWidget { } } -class GSYHighlighter extends SyntaxHighlighter { +class Highlighter extends SyntaxHighlighter { @override TextSpan format(String source) { String showSource = source.replaceAll("<", "<"); showSource = showSource.replaceAll(">", ">"); - return new DartSyntaxHighlighter().format(showSource); + return DartSyntaxHighlighter().format(showSource); } } diff --git a/lib/views/components/permanent/markdown/syntax_high_lighter.dart b/lib/views/components/permanent/markdown/syntax_high_lighter.dart index 0f3ad41..305bb11 100644 --- a/lib/views/components/permanent/markdown/syntax_high_lighter.dart +++ b/lib/views/components/permanent/markdown/syntax_high_lighter.dart @@ -14,16 +14,16 @@ class SyntaxHighlighterStyle { //123 static SyntaxHighlighterStyle defaultStyle() { - return new SyntaxHighlighterStyle( - baseStyle: new TextStyle(color: Color.fromRGBO(212, 212, 212, 1.0)), - numberStyle: new TextStyle(color: Colors.blue[800]), - commentStyle: new TextStyle(color: Color.fromRGBO(124, 126, 120, 1.0)), - keywordStyle: new TextStyle(color: Color.fromRGBO(228, 125, 246, 1.0)), - stringStyle: new TextStyle(color: Color.fromRGBO(150, 190, 118, 1.0)), + return SyntaxHighlighterStyle( + baseStyle: TextStyle(color: Color.fromRGBO(212, 212, 212, 1.0)), + numberStyle: TextStyle(color: Colors.blue[800]), + commentStyle: TextStyle(color: Color.fromRGBO(124, 126, 120, 1.0)), + keywordStyle: TextStyle(color: Color.fromRGBO(228, 125, 246, 1.0)), + stringStyle: TextStyle(color: Color.fromRGBO(150, 190, 118, 1.0)), punctuationStyle: - new TextStyle(color: Color.fromRGBO(212, 212, 212, 1.0)), - classStyle: new TextStyle(color: Color.fromRGBO(150, 190, 118, 1.0)), - constantStyle: new TextStyle(color: Colors.brown[500])); + TextStyle(color: Color.fromRGBO(212, 212, 212, 1.0)), + classStyle: TextStyle(color: Color.fromRGBO(150, 190, 118, 1.0)), + constantStyle: TextStyle(color: Colors.brown[500])); } final TextStyle baseStyle; @@ -82,7 +82,7 @@ class DartSyntaxHighlighter extends SyntaxCostomHighlighter { 'in', 'is', 'library', - 'new', + '', 'null', 'operator', 'part', @@ -138,7 +138,7 @@ class DartSyntaxHighlighter extends SyntaxCostomHighlighter { TextSpan format(String src) { _src = src; - _scanner = new StringScanner(_src); + _scanner = StringScanner(_src); if (_generateSpans()) { // Successfully parsed the code @@ -148,9 +148,9 @@ class DartSyntaxHighlighter extends SyntaxCostomHighlighter { for (_HighlightSpan span in _spans) { if (currentPosition != span.start) formattedText.add( - new TextSpan(text: _src.substring(currentPosition, span.start))); + TextSpan(text: _src.substring(currentPosition, span.start))); - formattedText.add(new TextSpan( + formattedText.add( TextSpan( style: span.textStyle(_style), text: span.textForSpan(_src))); currentPosition = span.end; @@ -158,12 +158,12 @@ class DartSyntaxHighlighter extends SyntaxCostomHighlighter { if (currentPosition != _src.length) formattedText.add( - new TextSpan(text: _src.substring(currentPosition, _src.length))); + TextSpan(text: _src.substring(currentPosition, _src.length))); - return new TextSpan(style: _style.baseStyle, children: formattedText); + return TextSpan(style: _style.baseStyle, children: formattedText); } else { // Parsing failed, return with only basic formatting - return new TextSpan(style: _style.baseStyle, text: src); + return TextSpan(style: _style.baseStyle, text: src); } } @@ -173,11 +173,11 @@ class DartSyntaxHighlighter extends SyntaxCostomHighlighter { try { while (!_scanner.isDone) { // Skip White space - _scanner.scan(new RegExp(r"\s+")); + _scanner.scan( RegExp(r"\s+")); // Block comments - if (_scanner.scan(new RegExp(r"/\*(.|\n)*\*/"))) { - _spans.add(new _HighlightSpan(_HighlightType.comment, + if (_scanner.scan( RegExp(r"/\*(.|\n)*\*/"))) { + _spans.add( _HighlightSpan(_HighlightType.comment, _scanner.lastMatch.start, _scanner.lastMatch.end)); continue; } @@ -188,14 +188,14 @@ class DartSyntaxHighlighter extends SyntaxCostomHighlighter { bool eof = false; int endComment; - if (_scanner.scan(new RegExp(r".*\n"))) { + if (_scanner.scan( RegExp(r".*\n"))) { endComment = _scanner.lastMatch.end - 1; } else { eof = true; endComment = _src.length; } - _spans.add(new _HighlightSpan( + _spans.add( _HighlightSpan( _HighlightType.comment, startComment, endComment)); if (eof) break; @@ -209,14 +209,14 @@ class DartSyntaxHighlighter extends SyntaxCostomHighlighter { bool eof = false; int endComment; - if (_scanner.scan(new RegExp(r".*\n"))) { + if (_scanner.scan( RegExp(r".*\n"))) { endComment = _scanner.lastMatch.end - 1; } else { eof = true; endComment = _src.length; } - _spans.add(new _HighlightSpan( + _spans.add( _HighlightSpan( _HighlightType.comment, startComment, endComment)); if (eof) break; @@ -224,84 +224,84 @@ class DartSyntaxHighlighter extends SyntaxCostomHighlighter { continue; } // Raw r"String" - if (_scanner.scan(new RegExp(r'r".*"'))) { - _spans.add(new _HighlightSpan(_HighlightType.string, + if (_scanner.scan( RegExp(r'r".*"'))) { + _spans.add( _HighlightSpan(_HighlightType.string, _scanner.lastMatch.start, _scanner.lastMatch.end)); continue; } // Raw r'String' - if (_scanner.scan(new RegExp(r"r'.*'"))) { - _spans.add(new _HighlightSpan(_HighlightType.string, + if (_scanner.scan( RegExp(r"r'.*'"))) { + _spans.add( _HighlightSpan(_HighlightType.string, _scanner.lastMatch.start, _scanner.lastMatch.end)); continue; } // Multiline """String""" - if (_scanner.scan(new RegExp(r'"""(?:[^"\\]|\\(.|\n))*"""'))) { - _spans.add(new _HighlightSpan(_HighlightType.string, + if (_scanner.scan( RegExp(r'"""(?:[^"\\]|\\(.|\n))*"""'))) { + _spans.add( _HighlightSpan(_HighlightType.string, _scanner.lastMatch.start, _scanner.lastMatch.end)); continue; } // Multiline '''String''' - if (_scanner.scan(new RegExp(r"'''(?:[^'\\]|\\(.|\n))*'''"))) { - _spans.add(new _HighlightSpan(_HighlightType.string, + if (_scanner.scan( RegExp(r"'''(?:[^'\\]|\\(.|\n))*'''"))) { + _spans.add( _HighlightSpan(_HighlightType.string, _scanner.lastMatch.start, _scanner.lastMatch.end)); continue; } // "String" - if (_scanner.scan(new RegExp(r'"(?:[^"\\]|\\.)*"'))) { - _spans.add(new _HighlightSpan(_HighlightType.string, + if (_scanner.scan( RegExp(r'"(?:[^"\\]|\\.)*"'))) { + _spans.add( _HighlightSpan(_HighlightType.string, _scanner.lastMatch.start, _scanner.lastMatch.end)); continue; } // 'String' - if (_scanner.scan(new RegExp(r"'(?:[^'\\]|\\.)*'"))) { - _spans.add(new _HighlightSpan(_HighlightType.string, + if (_scanner.scan( RegExp(r"'(?:[^'\\]|\\.)*'"))) { + _spans.add( _HighlightSpan(_HighlightType.string, _scanner.lastMatch.start, _scanner.lastMatch.end)); continue; } // Double - if (_scanner.scan(new RegExp(r"\d+\.\d+"))) { - _spans.add(new _HighlightSpan(_HighlightType.number, + if (_scanner.scan( RegExp(r"\d+\.\d+"))) { + _spans.add( _HighlightSpan(_HighlightType.number, _scanner.lastMatch.start, _scanner.lastMatch.end)); continue; } // Integer - if (_scanner.scan(new RegExp(r"\d+"))) { - _spans.add(new _HighlightSpan(_HighlightType.number, + if (_scanner.scan( RegExp(r"\d+"))) { + _spans.add( _HighlightSpan(_HighlightType.number, _scanner.lastMatch.start, _scanner.lastMatch.end)); continue; } // Punctuation - if (_scanner.scan(new RegExp(r"[\[\]{}().!=<>&\|\?\+\-\*/%\^~;:,]"))) { - _spans.add(new _HighlightSpan(_HighlightType.punctuation, + if (_scanner.scan( RegExp(r"[\[\]{}().!=<>&\|\?\+\-\*/%\^~;:,]"))) { + _spans.add( _HighlightSpan(_HighlightType.punctuation, _scanner.lastMatch.start, _scanner.lastMatch.end)); continue; } //中文 - if (_scanner.scan(new RegExp(r"[\u4e00-\u9fa5]"))) { - _spans.add(new _HighlightSpan(_HighlightType.punctuation, + if (_scanner.scan( RegExp(r"[\u4e00-\u9fa5]"))) { + _spans.add( _HighlightSpan(_HighlightType.punctuation, _scanner.lastMatch.start, _scanner.lastMatch.end)); continue; } // Metadata - if (_scanner.scan(new RegExp(r"@\w+"))) { - _spans.add(new _HighlightSpan(_HighlightType.keyword, + if (_scanner.scan( RegExp(r"@\w+"))) { + _spans.add( _HighlightSpan(_HighlightType.keyword, _scanner.lastMatch.start, _scanner.lastMatch.end)); continue; } // Words - if (_scanner.scan(new RegExp(r"\w+"))) { + if (_scanner.scan( RegExp(r"\w+"))) { _HighlightType type; String word = _scanner.lastMatch[0]; @@ -319,7 +319,7 @@ class DartSyntaxHighlighter extends SyntaxCostomHighlighter { type = _HighlightType.constant; if (type != null) { - _spans.add(new _HighlightSpan( + _spans.add( _HighlightSpan( type, _scanner.lastMatch.start, _scanner.lastMatch.end)); } } @@ -328,7 +328,7 @@ class DartSyntaxHighlighter extends SyntaxCostomHighlighter { if (lastLoopPosition == _scanner.position) { // Failed to parse this file, abort gracefully if (_spans.length > 0) { - _spans.add(new _HighlightSpan(_HighlightType.punctuation, + _spans.add( _HighlightSpan(_HighlightType.punctuation, lastLoopPosition, _scanner.string.length - 1)); _simplify(); return true; @@ -350,7 +350,7 @@ class DartSyntaxHighlighter extends SyntaxCostomHighlighter { for (int i = _spans.length - 2; i >= 0; i -= 1) { if (_spans[i].type == _spans[i + 1].type && _spans[i].end == _spans[i + 1].start) { - _spans[i] = new _HighlightSpan( + _spans[i] = _HighlightSpan( _spans[i].type, _spans[i].start, _spans[i + 1].end); _spans.removeAt(i + 1); } diff --git a/lib/views/pages/app/bloc_wrapper.dart b/lib/views/pages/app/bloc_wrapper.dart index 9512144..bdbe8dc 100644 --- a/lib/views/pages/app/bloc_wrapper.dart +++ b/lib/views/pages/app/bloc_wrapper.dart @@ -1,5 +1,8 @@ import 'package:flutter/material.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; +import 'package:flutter_unit/blocs/authentic/bloc.dart'; +import 'package:flutter_unit/blocs/login/bloc.dart'; +import 'package:flutter_unit/blocs/register/bloc.dart'; import 'package:flutter_unit/model/enums.dart'; import 'package:flutter_unit/blocs/bloc_exp.dart'; import 'package:flutter_unit/views/components/project/overlay_tool_wrapper.dart'; @@ -27,6 +30,7 @@ class _BlocWrapperState extends State { final WidgetRepository repository = WidgetDbRepository(storage); final categoryBloc = CategoryBloc(repository: CategoryDbRepository(storage)); + final authBloc = AuthenticBloc(); @override Widget build(BuildContext context) { @@ -51,6 +55,10 @@ class _BlocWrapperState extends State { create: (_) => LikeWidgetBloc(repository: repository) ..add(EventSetCollectData())), + BlocProvider(create: (_) => RegisterBloc()), + BlocProvider( + create: (_) => LoginBloc(authenticBloc: authBloc)), + BlocProvider(create: (_) => authBloc), BlocProvider( create: (_) => CategoryWidgetBloc(categoryBloc: categoryBloc)), @@ -64,6 +72,7 @@ class _BlocWrapperState extends State { @override void dispose() { categoryBloc.close(); + authBloc.close(); super.dispose(); } } diff --git a/lib/views/pages/login/login_form.dart b/lib/views/pages/login/login_form.dart index 63e4a5b..172311b 100644 --- a/lib/views/pages/login/login_form.dart +++ b/lib/views/pages/login/login_form.dart @@ -1,12 +1,14 @@ - import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; +import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:flutter_unit/app/res/toly_icon.dart'; import 'package:flutter_unit/app/router/unit_router.dart'; +import 'package:flutter_unit/app/utils/Toast.dart'; +import 'package:flutter_unit/blocs/login/bloc.dart'; +import 'package:flutter_unit/blocs/login/event.dart'; +import 'package:flutter_unit/blocs/login/state.dart'; import 'package:flutter_unit/views/components/permanent/feedback_widget.dart'; - - class LoginFrom extends StatefulWidget { @override _LoginFromState createState() => _LoginFromState(); @@ -23,19 +25,28 @@ class _LoginFromState extends State { return Column( mainAxisSize: MainAxisSize.min, children: [ - Text("FlutterUnit 登录",style: TextStyle(fontSize: 25),), - SizedBox(height: 5,), - Text("更多精彩,更多体验 ~",style: TextStyle(color: Colors.grey),), - SizedBox(height:20,), + Text( + "FlutterUnit 登录", + style: TextStyle(fontSize: 25), + ), + SizedBox( + height: 5, + ), + Text( + "更多精彩,更多体验 ~", + style: TextStyle(color: Colors.grey), + ), + SizedBox( + height: 20, + ), buildUsernameInput(), Stack( - alignment: Alignment(.8,0), + alignment: Alignment(.8, 0), children: [ buildPasswordInput(), FeedbackWidget( - onPressed: ()=> setState(() => _showPwd=!_showPwd), - child: Icon(_showPwd?TolyIcon.icon_show:TolyIcon.icon_hide) - ) + onPressed: () => setState(() => _showPwd = !_showPwd), + child: Icon(_showPwd ? TolyIcon.icon_show : TolyIcon.icon_hide)) ], ), Row( @@ -47,8 +58,8 @@ class _LoginFromState extends State { ), Spacer(), FeedbackWidget( - onEnd: (){ - Navigator.of(context).pushNamed(UnitRouter.register); + onEnd: () { + Navigator.of(context).pushReplacementNamed(UnitRouter.register); }, child: Text( "用户注册", @@ -60,7 +71,10 @@ class _LoginFromState extends State { ) ], ), - _buildBtn(), + BlocConsumer( + listener: _listenLoginState, + builder: _buildBtnByState, + ), buildOtherLogin(), const Spacer(flex: 4), ], @@ -68,33 +82,17 @@ class _LoginFromState extends State { } void _doLogIn() { + print( + '---用户名:${_usernameController.text}------密码:${_passwordController.text}---'); + String username = _usernameController.text; + String password = _passwordController.text; - print('---用户名:${_usernameController.text}------密码:${_passwordController.text}---'); + if (!_preValidate(username, password)) return; -// BlocProvider.of(context).add( -// EventLogin( -// username: _usernameController.text, -// password: _passwordController.text), -// ); + BlocProvider.of(context).add(DoLogin(username:username, password: password)); } - Widget _buildBtn() => Container( - margin: EdgeInsets.only(top: 10, left: 10, right: 10,bottom: 0), - height: 40, - width: MediaQuery.of(context).size.width, - child: - RaisedButton( - elevation: 0, - shape: RoundedRectangleBorder( - borderRadius: BorderRadius.all(Radius.circular(20))), - color: Colors.blue, - onPressed: _doLogIn, - child: Text("进入 Unit 世界", - style: TextStyle(color: Colors.white, fontSize: 18)), - ), - ); - - Widget buildUsernameInput(){ + Widget buildUsernameInput() { return Column( children: [ Container( @@ -105,13 +103,11 @@ class _LoginFromState extends State { ), borderRadius: BorderRadius.circular(15.0), ), - margin: - const EdgeInsets.symmetric(vertical: 10.0, horizontal: 10.0), + margin: const EdgeInsets.symmetric(vertical: 10.0, horizontal: 10.0), child: Row( children: [ Padding( - padding: - EdgeInsets.symmetric(vertical: 10.0, horizontal: 15.0), + padding: EdgeInsets.symmetric(vertical: 10.0, horizontal: 15.0), child: Icon( Icons.person_outline, color: Colors.grey, @@ -140,7 +136,7 @@ class _LoginFromState extends State { ); } - Widget buildPasswordInput(){ + Widget buildPasswordInput() { return Column( children: [ Container( @@ -151,13 +147,11 @@ class _LoginFromState extends State { ), borderRadius: BorderRadius.circular(15.0), ), - margin: - const EdgeInsets.symmetric(vertical: 10.0, horizontal: 10.0), + margin: const EdgeInsets.symmetric(vertical: 10.0, horizontal: 10.0), child: Row( children: [ Padding( - padding: - EdgeInsets.symmetric(vertical: 10.0, horizontal: 15.0), + padding: EdgeInsets.symmetric(vertical: 10.0, horizontal: 15.0), child: Icon( Icons.lock_outline, color: Colors.grey, @@ -186,25 +180,88 @@ class _LoginFromState extends State { ], ); } - Widget buildOtherLogin(){ + + Widget buildOtherLogin() { return Wrap( alignment: WrapAlignment.center, children: [ Padding( - padding: const EdgeInsets.only(top:30.0), + padding: const EdgeInsets.only(top: 30.0), child: Row( children: [ - Expanded(child: Divider(height: 20,)), + Expanded( + child: Divider( + height: 20, + )), Padding( padding: const EdgeInsets.all(8.0), - child: Text('第三方登录',style: TextStyle(color: Colors.grey),), + child: Text( + '第三方登录', + style: TextStyle(color: Colors.grey), + ), ), - Expanded(child: Divider(height: 20,)), + Expanded( + child: Divider( + height: 20, + )), ], ), ), - Icon(TolyIcon.icon_github,color: Colors.black, size: 30,) + Icon( + TolyIcon.icon_github, + color: Colors.black, + size: 30, + ) ], ); } + + Widget _buildBtnByState(BuildContext context, LoginState state) { + if(state is LoginLoading){ + return Container( + margin: EdgeInsets.only(top: 10, bottom: 0), + height: 40, + width: 40, + child: RaisedButton( + elevation: 0, + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.all(Radius.circular(20))), + color: Colors.blue.withOpacity(0.7), + onPressed: _doLogIn, + child: CupertinoActivityIndicator(), + )); + } + return Container( + margin: EdgeInsets.only(top: 10, left: 10, right: 10, bottom: 0), + height: 40, + width: MediaQuery.of(context).size.width, + child: RaisedButton( + elevation: 0, + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.all(Radius.circular(20))), + color: Colors.blue, + onPressed: _doLogIn, + child: Text("进入 Unit 世界", + style: TextStyle(color: Colors.white, fontSize: 18)), + )); + } + + void _listenLoginState(BuildContext context, LoginState state) { + if (state is LoginSuccess) { + Navigator.of(context).pop(); + } + if (state is LoginError) { + Toast.toast(context, '登录失败 : ${state.message}!', + color: Colors.red, duration: Duration(seconds: 2)); + } + } + + bool _preValidate(String username, String password) { + if (username.isEmpty || password.isEmpty) { + Toast.toast(context, '登录失败 : 用户名和密码不能为空!', + color: Colors.orange, duration: Duration(seconds: 2)); + return false; + } + return true; + } } diff --git a/lib/views/pages/login/login_page.dart b/lib/views/pages/login/login_page.dart index 7fc96b7..87cc94d 100644 --- a/lib/views/pages/login/login_page.dart +++ b/lib/views/pages/login/login_page.dart @@ -1,4 +1,9 @@ import 'package:flutter/material.dart'; +import 'package:flutter_bloc/flutter_bloc.dart'; +import 'package:flutter_unit/blocs/authentic/bloc.dart'; +import 'package:flutter_unit/blocs/authentic/state.dart'; +import 'package:flutter_unit/blocs/login/bloc.dart'; +import 'package:flutter_unit/blocs/login/state.dart'; import 'package:flutter_unit/views/pages/register/arc_clipper.dart'; import 'login_form.dart'; @@ -12,18 +17,8 @@ class LoginPage extends StatelessWidget { Widget build(BuildContext context) { Size winSize = MediaQuery.of(context).size; - return - -// BlocListener( -// listener: (context, state) { -// if (state is AuthSuccess) { -// Navigator.of(context).pushReplacementNamed(Router.nav); -// } -// }, -// child: - - Scaffold( - body: SingleChildScrollView( + return Scaffold( + body: SingleChildScrollView( child: Wrap(children: [ UnitArcBackground(height: winSize.height * 0.32), Container( @@ -31,37 +26,13 @@ class LoginPage extends StatelessWidget { height: winSize.height * 0.68, width: MediaQuery.of(context).size.width, padding: const EdgeInsets.only(left: 20.0, right: 20, top: 20), - child: -// -// BlocBuilder( -// builder: (_, state) { -// return - - Stack( + child: Stack( alignment: Alignment.center, children: [ LoginFrom(), -// if (state is LoginFailure) -// Positioned( -// bottom: 0, -// child: ErrorMsg( -// error: state.error, -// )), -// if (state is LoginLoading) -// LoadingView( -// text: "登录中...", -// ) ], - ) -// ); -// }, -// ), -// ) -// ] - ) - ] -// ), - ), + )) + ]), )); } } diff --git a/lib/views/pages/me/me_page.dart b/lib/views/pages/me/me_page.dart index db66df5..b68ec37 100644 --- a/lib/views/pages/me/me_page.dart +++ b/lib/views/pages/me/me_page.dart @@ -1,5 +1,10 @@ import 'package:flutter/material.dart'; +import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:flutter_unit/app/router/unit_router.dart'; +import 'package:flutter_unit/blocs/authentic/bloc.dart'; +import 'package:flutter_unit/blocs/authentic/state.dart'; +import 'package:flutter_unit/blocs/login/bloc.dart'; +import 'package:flutter_unit/blocs/login/state.dart'; import 'package:flutter_unit/views/components/permanent/circle_image.dart'; import 'package:flutter_unit/views/components/permanent/feedback_widget.dart'; @@ -30,10 +35,10 @@ class MePage extends StatelessWidget { bottom: 0, left: 40, child: FeedbackWidget( - onEnd: (){ + onEnd: () { Navigator.of(context).pushNamed(UnitRouter.login); }, - child: CircleImage( + child: CircleImage( size: 80, shadowColor: Theme.of(context).primaryColor.withAlpha(33), image: AssetImage("assets/images/icon_head.webp"), @@ -41,19 +46,28 @@ class MePage extends StatelessWidget { ), ), Positioned( - bottom: 0, - right: 20, - child: Text( - '张风捷特烈', - style: TextStyle( - fontSize: 18, color: Theme.of(context).primaryColor), - ), - ) + bottom: 0, + right: 20, + child: BlocBuilder( + builder: _buildByState, + )) ], ), - Expanded(child: MePageItem()) ], )); } + + Widget _buildByState(BuildContext context, AuthenticState state) { + if (state is AuthSuccess) { + return Text( + state.user.username, + style: TextStyle(fontSize: 18, color: Theme.of(context).primaryColor), + ); + } + return Text( + '张风捷特烈', + style: TextStyle(fontSize: 18, color: Theme.of(context).primaryColor), + ); + } } diff --git a/lib/views/pages/register/register_page.dart b/lib/views/pages/register/register_page.dart index a96a133..4bb882b 100644 --- a/lib/views/pages/register/register_page.dart +++ b/lib/views/pages/register/register_page.dart @@ -1,4 +1,16 @@ import 'package:flutter/material.dart'; +import 'package:flutter_bloc/flutter_bloc.dart'; +import 'package:flutter_unit/app/api/system_api.dart'; +import 'package:flutter_unit/app/utils/Toast.dart'; +import 'package:flutter_unit/app/utils/http_utils/result_bean.dart'; +import 'package:flutter_unit/blocs/authentic/bloc.dart'; +import 'package:flutter_unit/blocs/authentic/state.dart'; +import 'package:flutter_unit/blocs/login/bloc.dart'; +import 'package:flutter_unit/blocs/login/event.dart'; +import 'package:flutter_unit/blocs/login/state.dart'; +import 'package:flutter_unit/blocs/register/bloc.dart'; +import 'package:flutter_unit/blocs/register/event.dart'; +import 'package:flutter_unit/blocs/register/state.dart'; import 'package:flutter_unit/views/components/permanent/icon_input.dart'; import 'arc_clipper.dart'; @@ -14,8 +26,8 @@ class RegisterPage extends StatefulWidget { } class _RegisterPageState extends State { - final _usernameController = TextEditingController(text: '1981462002@qq.com'); - final _passwordController = TextEditingController(text: ''); + final _emailCtrl = TextEditingController(text: '1981462002@qq.com'); + final _codeCtrl = TextEditingController(text: ''); @override Widget build(BuildContext context) { @@ -33,7 +45,7 @@ class _RegisterPageState extends State { // color: Colors.green, child: Column( children: [ - const Text( + const Text( "FlutterUnit 注册", style: TextStyle(fontSize: 25), ), @@ -50,7 +62,7 @@ class _RegisterPageState extends State { IconInput( icon: Icons.person_outline, textFiled: TextField( - controller: _usernameController, + controller: _emailCtrl, decoration: InputDecoration( border: InputBorder.none, hintText: '请输入邮箱', @@ -58,14 +70,11 @@ class _RegisterPageState extends State { ), ), ), - - const SizedBox(height: 10), - + const SizedBox(height: 10), buildInputWithSend(), - - const Spacer(flex: 1), + const Spacer(flex: 1), _buildBtn(), - const Spacer(flex: 4), + const Spacer(flex: 4), ], ), )) @@ -80,7 +89,7 @@ class _RegisterPageState extends State { IconInput( icon: Icons.code_outlined, textFiled: TextField( - controller: _passwordController, + controller: _codeCtrl, decoration: InputDecoration( border: InputBorder.none, hintText: '请输入验证码', @@ -89,28 +98,82 @@ class _RegisterPageState extends State { ), ), CountDownWidget( - onPress: () { - - }, + onPress: _sendEmail, ) ], ); } + _sendEmail(BuildContext context) async { + if (!_checkEmail(_emailCtrl.text)) { + Toast.toast(context, '邮箱格式校验错误,请重试!', + color: Colors.orange, duration: Duration(seconds: 2)); + return; + } + + ResultBean result = + await SystemApi.sendEmail(email: _emailCtrl.text); + print(result); + if (result.status) { + Toast.toast(context, '验证码发送成功,请注意邮箱查收!', duration: Duration(seconds: 2)); + } else { + Toast.toast(context, '验证码发送失败: ${result.msg}!', + color: Colors.red, duration: Duration(seconds: 2)); + } + } + + bool _checkEmail(String email) { + if (email == null) return false; + RegExp exp = + RegExp(r'^([a-zA-Z]|[0-9])(\w|\-)+@[a-zA-Z0-9]+\.([a-zA-Z]{2,4})$'); + return exp.hasMatch(email); + } + Widget _buildBtn() => Container( margin: EdgeInsets.only(top: 10, left: 10, right: 10, bottom: 0), height: 40, width: MediaQuery.of(context).size.width, - child: RaisedButton( - elevation: 0, - shape: RoundedRectangleBorder( - borderRadius: BorderRadius.all(Radius.circular(20))), - color: Colors.blue, - onPressed: _doRegister, - child: Text("开启 Unit 新世界", - style: TextStyle(color: Colors.white, fontSize: 18)), + child: BlocConsumer( + builder: _build, + listener: _listener, ), ); - void _doRegister() {} + void _doRegister() { + BlocProvider.of(context) + .add(DoRegister(_emailCtrl.text, _codeCtrl.text)); + } + + Widget _build(BuildContext context, state) { + bool enable = state is RegisterLoading || state is RegisterSuccess; + 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)))); + } + + void _listener(BuildContext context, RegisterState state) { + if (state is RegisterError) { + Toast.toast(context, '注册失败 : ${state.message}!', + color: Colors.red, duration: Duration(seconds: 2)); + } + + if (state is RegisterSuccess) { + BlocProvider.of(context) + .add(DoLogin(username:_emailCtrl.text, password:_codeCtrl.text)); + } + } + + void _listenerLogin(BuildContext context, AuthenticState state) { + if (state is AuthSuccess) { + Navigator.pop(context); + } + } } diff --git a/lib/views/pages/register/send_code.dart b/lib/views/pages/register/send_code.dart index 3474ee3..76b60e9 100644 --- a/lib/views/pages/register/send_code.dart +++ b/lib/views/pages/register/send_code.dart @@ -7,7 +7,7 @@ import 'package:flutter/material.dart'; /// 说明: class CountDownWidget extends StatefulWidget { - final VoidCallback onPress; + final Function(BuildContext context) onPress; CountDownWidget({Key key, this.onPress}) : super(key: key); @@ -23,19 +23,27 @@ class _CountDownWidgetState extends State { @override void initState() { super.initState(); + } + @override + void dispose() { + timer?.cancel(); + super.dispose(); } @override Widget build(BuildContext context) { return TextButton( - onPressed: startTimer?null:() { - timer = Timer.periodic(Duration(seconds: 1), _update); - setState(() { - startTimer = true; - }); - }, - child: Text(startTimer?'$count 秒后重试':'获取验证码')); + onPressed: startTimer + ? null + : () { + timer = Timer.periodic(Duration(seconds: 1), _update); + setState(() { + startTimer = true; + }); + widget.onPress(context); + }, + child: Text(startTimer ? '$count 秒后重试' : '获取验证码')); } void _update(Timer timer) { @@ -43,7 +51,7 @@ class _CountDownWidgetState extends State { if (count == 0) { timer.cancel(); startTimer = false; - count=5; + count = 60; } setState(() {}); }