| import 'package:authentication_repository/authentication_repository.dart'; | |||||
| import 'package:farm_tpf/presentation/screens/home/view/home_page.dart'; | import 'package:farm_tpf/presentation/screens/home/view/home_page.dart'; | ||||
| import 'package:farm_tpf/presentation/screens/login/view/login_page.dart'; | import 'package:farm_tpf/presentation/screens/login/view/login_page.dart'; | ||||
| import 'package:farm_tpf/presentation/screens/splash/view/splash_page.dart'; | import 'package:farm_tpf/presentation/screens/splash/view/splash_page.dart'; | ||||
| import 'package:flutter/material.dart'; | import 'package:flutter/material.dart'; | ||||
| import 'package:flutter_bloc/flutter_bloc.dart'; | import 'package:flutter_bloc/flutter_bloc.dart'; | ||||
| import 'package:user_repository/user_repository.dart'; | |||||
| import 'authentication/bloc/authentication_bloc.dart'; | import 'authentication/bloc/authentication_bloc.dart'; | ||||
| import 'data/repository/authentication_repository.dart'; | |||||
| class App extends StatelessWidget { | class App extends StatelessWidget { | ||||
| const App({ | const App({ | ||||
| Key key, | Key key, | ||||
| @required this.authenticationRepository, | @required this.authenticationRepository, | ||||
| @required this.userRepository, | |||||
| }) : assert(authenticationRepository != null), | }) : assert(authenticationRepository != null), | ||||
| assert(userRepository != null), | |||||
| super(key: key); | super(key: key); | ||||
| final AuthenticationRepository authenticationRepository; | final AuthenticationRepository authenticationRepository; | ||||
| final UserRepository userRepository; | |||||
| @override | @override | ||||
| Widget build(BuildContext context) { | Widget build(BuildContext context) { | ||||
| child: BlocProvider( | child: BlocProvider( | ||||
| create: (_) => AuthenticationBloc( | create: (_) => AuthenticationBloc( | ||||
| authenticationRepository: authenticationRepository, | authenticationRepository: authenticationRepository, | ||||
| userRepository: userRepository, | |||||
| ), | ), | ||||
| child: AppView(), | child: AppView(), | ||||
| ), | ), |
| import 'dart:async'; | import 'dart:async'; | ||||
| import 'package:authentication_repository/authentication_repository.dart'; | |||||
| import 'package:bloc/bloc.dart'; | import 'package:bloc/bloc.dart'; | ||||
| import 'package:equatable/equatable.dart'; | import 'package:equatable/equatable.dart'; | ||||
| import 'package:farm_tpf/data/repository/authentication_repository.dart'; | |||||
| import 'package:meta/meta.dart'; | import 'package:meta/meta.dart'; | ||||
| import 'package:user_repository/user_repository.dart'; | |||||
| part 'authentication_event.dart'; | part 'authentication_event.dart'; | ||||
| part 'authentication_state.dart'; | part 'authentication_state.dart'; | ||||
| class AuthenticationBloc | class AuthenticationBloc | ||||
| extends Bloc<AuthenticationEvent, AuthenticationState> { | extends Bloc<AuthenticationEvent, AuthenticationState> { | ||||
| AuthenticationBloc({ | |||||
| @required AuthenticationRepository authenticationRepository, | |||||
| @required UserRepository userRepository, | |||||
| }) : assert(authenticationRepository != null), | |||||
| assert(userRepository != null), | |||||
| AuthenticationBloc( | |||||
| {@required AuthenticationRepository authenticationRepository}) | |||||
| : assert(authenticationRepository != null), | |||||
| _authenticationRepository = authenticationRepository, | _authenticationRepository = authenticationRepository, | ||||
| _userRepository = userRepository, | |||||
| super(const AuthenticationState.unknown()) { | super(const AuthenticationState.unknown()) { | ||||
| _authenticationStatusSubscription = _authenticationRepository.status.listen( | _authenticationStatusSubscription = _authenticationRepository.status.listen( | ||||
| (status) => add(AuthenticationStatusChanged(status)), | (status) => add(AuthenticationStatusChanged(status)), | ||||
| } | } | ||||
| final AuthenticationRepository _authenticationRepository; | final AuthenticationRepository _authenticationRepository; | ||||
| final UserRepository _userRepository; | |||||
| StreamSubscription<AuthenticationStatus> _authenticationStatusSubscription; | StreamSubscription<AuthenticationStatus> _authenticationStatusSubscription; | ||||
| @override | @override | ||||
| case AuthenticationStatus.unauthenticated: | case AuthenticationStatus.unauthenticated: | ||||
| return const AuthenticationState.unauthenticated(); | return const AuthenticationState.unauthenticated(); | ||||
| case AuthenticationStatus.authenticated: | case AuthenticationStatus.authenticated: | ||||
| final user = await _tryGetUser(); | |||||
| return user != null | |||||
| ? AuthenticationState.authenticated(user) | |||||
| : const AuthenticationState.unauthenticated(); | |||||
| return AuthenticationState.authenticated(); | |||||
| default: | default: | ||||
| return const AuthenticationState.unknown(); | return const AuthenticationState.unknown(); | ||||
| } | } | ||||
| } | } | ||||
| Future<User> _tryGetUser() async { | |||||
| try { | |||||
| final user = await _userRepository.getUser(); | |||||
| return user; | |||||
| } on Exception { | |||||
| return null; | |||||
| } | |||||
| } | |||||
| } | } |
| part of 'authentication_bloc.dart'; | part of 'authentication_bloc.dart'; | ||||
| class AuthenticationState extends Equatable { | class AuthenticationState extends Equatable { | ||||
| const AuthenticationState._({ | |||||
| this.status = AuthenticationStatus.unknown, | |||||
| this.user, | |||||
| }); | |||||
| const AuthenticationState._({this.status = AuthenticationStatus.unknown}); | |||||
| const AuthenticationState.unknown() : this._(); | const AuthenticationState.unknown() : this._(); | ||||
| const AuthenticationState.authenticated(User user) | |||||
| : this._(status: AuthenticationStatus.authenticated, user: user); | |||||
| const AuthenticationState.authenticated() | |||||
| : this._(status: AuthenticationStatus.authenticated); | |||||
| const AuthenticationState.unauthenticated() | const AuthenticationState.unauthenticated() | ||||
| : this._(status: AuthenticationStatus.unauthenticated); | : this._(status: AuthenticationStatus.unauthenticated); | ||||
| final AuthenticationStatus status; | final AuthenticationStatus status; | ||||
| final User user; | |||||
| @override | @override | ||||
| List<Object> get props => [status, user]; | |||||
| List<Object> get props => [status]; | |||||
| } | } |
| import 'dart:async'; | |||||
| import 'package:farm_tpf/authentication/authentication.dart'; | |||||
| import 'package:farm_tpf/data/api/dio_provider.dart'; | |||||
| import 'package:farm_tpf/data/api/rest_client.dart'; | |||||
| import 'package:farm_tpf/models/user.dart'; | |||||
| import 'package:farm_tpf/models/user_request.dart'; | |||||
| import 'package:farm_tpf/utils/const_common.dart'; | |||||
| import 'package:farm_tpf/utils/pref.dart'; | |||||
| import 'package:meta/meta.dart'; | |||||
| enum AuthenticationStatus { unknown, authenticated, unauthenticated } | |||||
| class AuthenticationRepository { | |||||
| final _controller = StreamController<AuthenticationStatus>(); | |||||
| final dio = DioProvider.instance(); | |||||
| final pref = LocalPref(); | |||||
| Stream<AuthenticationStatus> get status async* { | |||||
| try { | |||||
| var token = await pref.getString(PrefKey.token_key); | |||||
| var expiredTime = await pref.getString(PrefKey.expired_time); | |||||
| int currentTime = DateTime.now().millisecondsSinceEpoch; | |||||
| bool isNotExpired = | |||||
| (currentTime - int.tryParse(expiredTime)) < ConstCommon.kExpiredTime; | |||||
| if (token.isNotEmpty && isNotExpired) { | |||||
| yield AuthenticationStatus.authenticated; | |||||
| } else { | |||||
| yield AuthenticationStatus.unauthenticated; | |||||
| } | |||||
| } catch (_) { | |||||
| yield AuthenticationStatus.unauthenticated; | |||||
| } | |||||
| yield* _controller.stream; | |||||
| } | |||||
| Future<User> signInWithCredentials(String username, String password) { | |||||
| final client = RestClient(dio); | |||||
| var result = | |||||
| client.login(UserRequest(username: username, password: password)); | |||||
| return result; | |||||
| } | |||||
| void logOut() { | |||||
| pref.saveString(PrefKey.token_key, ""); | |||||
| _controller.add(AuthenticationStatus.unauthenticated); | |||||
| } | |||||
| void dispose() => _controller.close(); | |||||
| } |
| import 'package:flutter/material.dart'; | import 'package:flutter/material.dart'; | ||||
| import 'package:authentication_repository/authentication_repository.dart'; | |||||
| import 'package:user_repository/user_repository.dart'; | |||||
| import 'app.dart'; | import 'app.dart'; | ||||
| import 'data/repository/authentication_repository.dart'; | |||||
| void main() { | void main() { | ||||
| runApp(App( | |||||
| authenticationRepository: AuthenticationRepository(), | |||||
| userRepository: UserRepository(), | |||||
| )); | |||||
| runApp(App(authenticationRepository: AuthenticationRepository())); | |||||
| } | } |
| child: Column( | child: Column( | ||||
| mainAxisSize: MainAxisSize.min, | mainAxisSize: MainAxisSize.min, | ||||
| children: <Widget>[ | children: <Widget>[ | ||||
| Text( | |||||
| 'UserID: ${context.bloc<AuthenticationBloc>().state.user.id}', | |||||
| ), | |||||
| Text("logged in." | |||||
| // 'UserID: ${context.bloc<AuthenticationBloc>().state.user.id}', | |||||
| ), | |||||
| RaisedButton( | RaisedButton( | ||||
| child: const Text('Đăng xuất'), | child: const Text('Đăng xuất'), | ||||
| onPressed: () { | onPressed: () { |
| import 'dart:async'; | import 'dart:async'; | ||||
| import 'package:authentication_repository/authentication_repository.dart'; | |||||
| import 'package:bloc/bloc.dart'; | import 'package:bloc/bloc.dart'; | ||||
| import 'package:equatable/equatable.dart'; | import 'package:equatable/equatable.dart'; | ||||
| import 'package:farm_tpf/data/repository/authentication_repository.dart'; | |||||
| import 'package:farm_tpf/presentation/screens/login/models/password.dart'; | import 'package:farm_tpf/presentation/screens/login/models/password.dart'; | ||||
| import 'package:farm_tpf/presentation/screens/login/models/username.dart'; | import 'package:farm_tpf/presentation/screens/login/models/username.dart'; | ||||
| import 'package:farm_tpf/utils/pref.dart'; | |||||
| import 'package:formz/formz.dart'; | import 'package:formz/formz.dart'; | ||||
| import 'package:meta/meta.dart'; | import 'package:meta/meta.dart'; | ||||
| super(const LoginState()); | super(const LoginState()); | ||||
| final AuthenticationRepository _authenticationRepository; | final AuthenticationRepository _authenticationRepository; | ||||
| var pref = LocalPref(); | |||||
| @override | @override | ||||
| Stream<LoginState> mapEventToState( | Stream<LoginState> mapEventToState( | ||||
| if (state.status.isValidated) { | if (state.status.isValidated) { | ||||
| yield state.copyWith(status: FormzStatus.submissionInProgress); | yield state.copyWith(status: FormzStatus.submissionInProgress); | ||||
| try { | try { | ||||
| await _authenticationRepository.logIn( | |||||
| username: state.username.value, | |||||
| password: state.password.value, | |||||
| var user = await _authenticationRepository.signInWithCredentials( | |||||
| state.username.value, | |||||
| state.password.value, | |||||
| ); | ); | ||||
| var token = user.idToken; | |||||
| pref.saveString(PrefKey.token_key, token); | |||||
| int currentTime = DateTime.now().millisecondsSinceEpoch; | |||||
| pref.saveString(PrefKey.expired_time, currentTime.toString()); | |||||
| yield state.copyWith(status: FormzStatus.submissionSuccess); | yield state.copyWith(status: FormzStatus.submissionSuccess); | ||||
| } on Exception catch (_) { | } on Exception catch (_) { | ||||
| yield state.copyWith(status: FormzStatus.submissionFailure); | yield state.copyWith(status: FormzStatus.submissionFailure); |
| import 'package:farm_tpf/authentication/authentication.dart'; | |||||
| import 'package:farm_tpf/data/repository/authentication_repository.dart'; | |||||
| import 'package:farm_tpf/presentation/custom_widgets/widget_loading.dart'; | |||||
| import 'package:farm_tpf/presentation/screens/login/bloc/login_bloc.dart'; | import 'package:farm_tpf/presentation/screens/login/bloc/login_bloc.dart'; | ||||
| import 'package:flutter/material.dart'; | import 'package:flutter/material.dart'; | ||||
| import 'package:formz/formz.dart'; | import 'package:formz/formz.dart'; | ||||
| import 'package:flutter_bloc/flutter_bloc.dart'; | import 'package:flutter_bloc/flutter_bloc.dart'; | ||||
| class LoginForm extends StatelessWidget { | class LoginForm extends StatelessWidget { | ||||
| AuthenticationBloc _authenticationBloc; | |||||
| @override | @override | ||||
| Widget build(BuildContext context) { | Widget build(BuildContext context) { | ||||
| _authenticationBloc = BlocProvider.of<AuthenticationBloc>(context); | |||||
| return BlocListener<LoginBloc, LoginState>( | return BlocListener<LoginBloc, LoginState>( | ||||
| listener: (context, state) { | listener: (context, state) { | ||||
| if (state.status.isSubmissionFailure) { | if (state.status.isSubmissionFailure) { | ||||
| LoadingDialog.hideLoadingDialog(context); | |||||
| Scaffold.of(context) | Scaffold.of(context) | ||||
| ..hideCurrentSnackBar() | ..hideCurrentSnackBar() | ||||
| ..showSnackBar( | ..showSnackBar( | ||||
| const SnackBar(content: Text('Authentication Failure')), | const SnackBar(content: Text('Authentication Failure')), | ||||
| ); | ); | ||||
| } | } | ||||
| if (state.status.isSubmissionSuccess) { | |||||
| LoadingDialog.hideLoadingDialog(context); | |||||
| _authenticationBloc.add( | |||||
| AuthenticationStatusChanged(AuthenticationStatus.authenticated)); | |||||
| } | |||||
| if (state.status.isSubmissionInProgress) { | |||||
| LoadingDialog.showLoadingDialog(context); | |||||
| } | |||||
| }, | }, | ||||
| child: Align( | child: Align( | ||||
| alignment: const Alignment(0, -1 / 3), | alignment: const Alignment(0, -1 / 3), |
| import 'package:authentication_repository/authentication_repository.dart'; | |||||
| import 'package:farm_tpf/data/repository/authentication_repository.dart'; | |||||
| import 'package:farm_tpf/presentation/screens/login/bloc/login_bloc.dart'; | import 'package:farm_tpf/presentation/screens/login/bloc/login_bloc.dart'; | ||||
| import 'package:flutter_bloc/flutter_bloc.dart'; | import 'package:flutter_bloc/flutter_bloc.dart'; | ||||
| import 'package:flutter/material.dart'; | import 'package:flutter/material.dart'; |
| library authentication_repository; | |||||
| export 'src/authentication_repository.dart'; |
| import 'dart:async'; | |||||
| import 'package:meta/meta.dart'; | |||||
| enum AuthenticationStatus { unknown, authenticated, unauthenticated } | |||||
| class AuthenticationRepository { | |||||
| final _controller = StreamController<AuthenticationStatus>(); | |||||
| Stream<AuthenticationStatus> get status async* { | |||||
| await Future<void>.delayed(const Duration(seconds: 1)); | |||||
| yield AuthenticationStatus.unauthenticated; | |||||
| yield* _controller.stream; | |||||
| } | |||||
| Future<void> logIn({ | |||||
| @required String username, | |||||
| @required String password, | |||||
| }) async { | |||||
| assert(username != null); | |||||
| assert(password != null); | |||||
| await Future.delayed( | |||||
| const Duration(milliseconds: 300), | |||||
| () => _controller.add(AuthenticationStatus.authenticated), | |||||
| ); | |||||
| } | |||||
| void logOut() { | |||||
| _controller.add(AuthenticationStatus.unauthenticated); | |||||
| } | |||||
| void dispose() => _controller.close(); | |||||
| } |
| # Generated by pub | |||||
| # See https://dart.dev/tools/pub/glossary#lockfile | |||||
| packages: | |||||
| meta: | |||||
| dependency: "direct main" | |||||
| description: | |||||
| name: meta | |||||
| url: "https://pub.dartlang.org" | |||||
| source: hosted | |||||
| version: "1.2.2" | |||||
| sdks: | |||||
| dart: ">=2.1.0 <3.0.0" |
| name: authentication_repository | |||||
| description: Dart package which manages the authentication domain. | |||||
| version: 1.0.0 | |||||
| environment: | |||||
| sdk: ">=2.1.0 <3.0.0" | |||||
| dependencies: | |||||
| meta: ^1.1.8 |
| export 'user.dart'; |
| import 'package:equatable/equatable.dart'; | |||||
| class User extends Equatable { | |||||
| const User(this.id); | |||||
| final String id; | |||||
| @override | |||||
| List<Object> get props => [id]; | |||||
| } |
| import 'dart:async'; | |||||
| import 'models/models.dart'; | |||||
| class UserRepository { | |||||
| User _user; | |||||
| Future<User> getUser() async { | |||||
| if (_user != null) return _user; | |||||
| return Future.delayed( | |||||
| const Duration(milliseconds: 300), | |||||
| () => _user = User("usertest"), | |||||
| ); | |||||
| } | |||||
| } |
| library user_repository; | |||||
| export 'src/models/models.dart'; | |||||
| export 'src/user_repository.dart'; |
| # Generated by pub | |||||
| # See https://dart.dev/tools/pub/glossary#lockfile | |||||
| packages: | |||||
| charcode: | |||||
| dependency: transitive | |||||
| description: | |||||
| name: charcode | |||||
| url: "https://pub.dartlang.org" | |||||
| source: hosted | |||||
| version: "1.1.3" | |||||
| collection: | |||||
| dependency: transitive | |||||
| description: | |||||
| name: collection | |||||
| url: "https://pub.dartlang.org" | |||||
| source: hosted | |||||
| version: "1.14.13" | |||||
| convert: | |||||
| dependency: transitive | |||||
| description: | |||||
| name: convert | |||||
| url: "https://pub.dartlang.org" | |||||
| source: hosted | |||||
| version: "2.1.1" | |||||
| crypto: | |||||
| dependency: transitive | |||||
| description: | |||||
| name: crypto | |||||
| url: "https://pub.dartlang.org" | |||||
| source: hosted | |||||
| version: "2.1.5" | |||||
| equatable: | |||||
| dependency: "direct main" | |||||
| description: | |||||
| name: equatable | |||||
| url: "https://pub.dartlang.org" | |||||
| source: hosted | |||||
| version: "1.2.3" | |||||
| meta: | |||||
| dependency: "direct main" | |||||
| description: | |||||
| name: meta | |||||
| url: "https://pub.dartlang.org" | |||||
| source: hosted | |||||
| version: "1.2.2" | |||||
| typed_data: | |||||
| dependency: transitive | |||||
| description: | |||||
| name: typed_data | |||||
| url: "https://pub.dartlang.org" | |||||
| source: hosted | |||||
| version: "1.2.0" | |||||
| uuid: | |||||
| dependency: "direct main" | |||||
| description: | |||||
| name: uuid | |||||
| url: "https://pub.dartlang.org" | |||||
| source: hosted | |||||
| version: "2.2.0" | |||||
| sdks: | |||||
| dart: ">=2.4.0 <3.0.0" |
| name: user_repository | |||||
| description: Dart package which manages the user domain. | |||||
| version: 1.0.0 | |||||
| environment: | |||||
| sdk: ">=2.1.0 <3.0.0" | |||||
| dependencies: | |||||
| equatable: ^1.2.0 | |||||
| meta: ^1.1.8 | |||||
| uuid: ^2.1.0 |
| url: "https://pub.dartlang.org" | url: "https://pub.dartlang.org" | ||||
| source: hosted | source: hosted | ||||
| version: "2.4.1" | version: "2.4.1" | ||||
| authentication_repository: | |||||
| dependency: "direct main" | |||||
| description: | |||||
| path: "packages/authentication_repository" | |||||
| relative: true | |||||
| source: path | |||||
| version: "1.0.0" | |||||
| bloc: | bloc: | ||||
| dependency: transitive | dependency: transitive | ||||
| description: | description: | ||||
| url: "https://pub.dartlang.org" | url: "https://pub.dartlang.org" | ||||
| source: hosted | source: hosted | ||||
| version: "1.1.6" | version: "1.1.6" | ||||
| user_repository: | |||||
| dependency: "direct main" | |||||
| description: | |||||
| path: "packages/user_repository" | |||||
| relative: true | |||||
| source: path | |||||
| version: "1.0.0" | |||||
| uuid: | |||||
| dependency: transitive | |||||
| description: | |||||
| name: uuid | |||||
| url: "https://pub.dartlang.org" | |||||
| source: hosted | |||||
| version: "2.2.0" | |||||
| vector_math: | vector_math: | ||||
| dependency: transitive | dependency: transitive | ||||
| description: | description: |
| dio: 3.0.9 | dio: 3.0.9 | ||||
| formz: ^0.3.0 | formz: ^0.3.0 | ||||
| authentication_repository: | |||||
| path: packages/authentication_repository | |||||
| user_repository: | |||||
| path: packages/user_repository | |||||
| dev_dependencies: | dev_dependencies: | ||||
| flutter_test: | flutter_test: | ||||
| sdk: flutter | sdk: flutter |