Browse Source

login flow

master
daivph 5 years ago
parent
commit
cbd9e3c234
21 changed files with 93 additions and 236 deletions
  1. +1
    -6
      lib/app.dart
  2. +5
    -22
      lib/authentication/bloc/authentication_bloc.dart
  3. +4
    -8
      lib/authentication/bloc/authentication_state.dart
  4. +51
    -0
      lib/data/repository/authentication_repository.dart
  5. +2
    -6
      lib/main.dart
  6. +3
    -3
      lib/presentation/screens/home/view/home_page.dart
  7. +11
    -5
      lib/presentation/screens/login/bloc/login_bloc.dart
  8. +15
    -0
      lib/presentation/screens/login/view/login_form.dart
  9. +1
    -1
      lib/presentation/screens/login/view/login_page.dart
  10. +0
    -3
      packages/authentication_repository/lib/authentication_repository.dart
  11. +0
    -34
      packages/authentication_repository/lib/src/authentication_repository.dart
  12. +0
    -12
      packages/authentication_repository/pubspec.lock
  13. +0
    -9
      packages/authentication_repository/pubspec.yaml
  14. +0
    -1
      packages/user_repository/lib/src/models/models.dart
  15. +0
    -10
      packages/user_repository/lib/src/models/user.dart
  16. +0
    -14
      packages/user_repository/lib/src/user_repository.dart
  17. +0
    -4
      packages/user_repository/lib/user_repository.dart
  18. +0
    -61
      packages/user_repository/pubspec.lock
  19. +0
    -11
      packages/user_repository/pubspec.yaml
  20. +0
    -21
      pubspec.lock
  21. +0
    -5
      pubspec.yaml

+ 1
- 6
lib/app.dart View File

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(),
), ),

+ 5
- 22
lib/authentication/bloc/authentication_bloc.dart View File

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;
}
}
} }

+ 4
- 8
lib/authentication/bloc/authentication_state.dart View File

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];
} }

+ 51
- 0
lib/data/repository/authentication_repository.dart View File

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();
}

+ 2
- 6
lib/main.dart View File

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()));
} }

+ 3
- 3
lib/presentation/screens/home/view/home_page.dart View File

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: () {

+ 11
- 5
lib/presentation/screens/login/bloc/login_bloc.dart View File

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);

+ 15
- 0
lib/presentation/screens/login/view/login_form.dart View File

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),

+ 1
- 1
lib/presentation/screens/login/view/login_page.dart View File

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';

+ 0
- 3
packages/authentication_repository/lib/authentication_repository.dart View File

library authentication_repository;

export 'src/authentication_repository.dart';

+ 0
- 34
packages/authentication_repository/lib/src/authentication_repository.dart View File

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();
}

+ 0
- 12
packages/authentication_repository/pubspec.lock View File

# 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"

+ 0
- 9
packages/authentication_repository/pubspec.yaml View File

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

+ 0
- 1
packages/user_repository/lib/src/models/models.dart View File

export 'user.dart';

+ 0
- 10
packages/user_repository/lib/src/models/user.dart View File

import 'package:equatable/equatable.dart';

class User extends Equatable {
const User(this.id);

final String id;

@override
List<Object> get props => [id];
}

+ 0
- 14
packages/user_repository/lib/src/user_repository.dart View File

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"),
);
}
}

+ 0
- 4
packages/user_repository/lib/user_repository.dart View File

library user_repository;

export 'src/models/models.dart';
export 'src/user_repository.dart';

+ 0
- 61
packages/user_repository/pubspec.lock View File

# 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"

+ 0
- 11
packages/user_repository/pubspec.yaml View File

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

+ 0
- 21
pubspec.lock View File

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:

+ 0
- 5
pubspec.yaml View File

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

Loading…
Cancel
Save