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

@@ -1,24 +1,20 @@
import 'package:authentication_repository/authentication_repository.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/splash/view/splash_page.dart';
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:user_repository/user_repository.dart';

import 'authentication/bloc/authentication_bloc.dart';
import 'data/repository/authentication_repository.dart';

class App extends StatelessWidget {
const App({
Key key,
@required this.authenticationRepository,
@required this.userRepository,
}) : assert(authenticationRepository != null),
assert(userRepository != null),
super(key: key);

final AuthenticationRepository authenticationRepository;
final UserRepository userRepository;

@override
Widget build(BuildContext context) {
@@ -27,7 +23,6 @@ class App extends StatelessWidget {
child: BlocProvider(
create: (_) => AuthenticationBloc(
authenticationRepository: authenticationRepository,
userRepository: userRepository,
),
child: AppView(),
),

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

@@ -1,23 +1,19 @@
import 'dart:async';

import 'package:authentication_repository/authentication_repository.dart';
import 'package:bloc/bloc.dart';
import 'package:equatable/equatable.dart';
import 'package:farm_tpf/data/repository/authentication_repository.dart';
import 'package:meta/meta.dart';
import 'package:user_repository/user_repository.dart';

part 'authentication_event.dart';
part 'authentication_state.dart';

class AuthenticationBloc
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,
_userRepository = userRepository,
super(const AuthenticationState.unknown()) {
_authenticationStatusSubscription = _authenticationRepository.status.listen(
(status) => add(AuthenticationStatusChanged(status)),
@@ -25,7 +21,6 @@ class AuthenticationBloc
}

final AuthenticationRepository _authenticationRepository;
final UserRepository _userRepository;
StreamSubscription<AuthenticationStatus> _authenticationStatusSubscription;

@override
@@ -53,21 +48,9 @@ class AuthenticationBloc
case AuthenticationStatus.unauthenticated:
return const AuthenticationState.unauthenticated();
case AuthenticationStatus.authenticated:
final user = await _tryGetUser();
return user != null
? AuthenticationState.authenticated(user)
: const AuthenticationState.unauthenticated();
return AuthenticationState.authenticated();
default:
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

@@ -1,22 +1,18 @@
part of 'authentication_bloc.dart';

class AuthenticationState extends Equatable {
const AuthenticationState._({
this.status = AuthenticationStatus.unknown,
this.user,
});
const AuthenticationState._({this.status = AuthenticationStatus.unknown});

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()
: this._(status: AuthenticationStatus.unauthenticated);

final AuthenticationStatus status;
final User user;

@override
List<Object> get props => [status, user];
List<Object> get props => [status];
}

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

@@ -0,0 +1,51 @@
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

@@ -1,11 +1,7 @@
import 'package:flutter/material.dart';
import 'package:authentication_repository/authentication_repository.dart';
import 'package:user_repository/user_repository.dart';
import 'app.dart';
import 'data/repository/authentication_repository.dart';

void main() {
runApp(App(
authenticationRepository: AuthenticationRepository(),
userRepository: UserRepository(),
));
runApp(App(authenticationRepository: AuthenticationRepository()));
}

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

@@ -15,9 +15,9 @@ class HomePage extends StatelessWidget {
child: Column(
mainAxisSize: MainAxisSize.min,
children: <Widget>[
Text(
'UserID: ${context.bloc<AuthenticationBloc>().state.user.id}',
),
Text("logged in."
// 'UserID: ${context.bloc<AuthenticationBloc>().state.user.id}',
),
RaisedButton(
child: const Text('Đăng xuất'),
onPressed: () {

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

@@ -1,10 +1,10 @@
import 'dart:async';

import 'package:authentication_repository/authentication_repository.dart';
import 'package:bloc/bloc.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/username.dart';
import 'package:farm_tpf/utils/pref.dart';
import 'package:formz/formz.dart';
import 'package:meta/meta.dart';

@@ -19,6 +19,7 @@ class LoginBloc extends Bloc<LoginEvent, LoginState> {
super(const LoginState());

final AuthenticationRepository _authenticationRepository;
var pref = LocalPref();

@override
Stream<LoginState> mapEventToState(
@@ -62,10 +63,15 @@ class LoginBloc extends Bloc<LoginEvent, LoginState> {
if (state.status.isValidated) {
yield state.copyWith(status: FormzStatus.submissionInProgress);
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);
} on Exception catch (_) {
yield state.copyWith(status: FormzStatus.submissionFailure);

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

@@ -1,20 +1,35 @@
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:flutter/material.dart';
import 'package:formz/formz.dart';
import 'package:flutter_bloc/flutter_bloc.dart';

class LoginForm extends StatelessWidget {
AuthenticationBloc _authenticationBloc;

@override
Widget build(BuildContext context) {
_authenticationBloc = BlocProvider.of<AuthenticationBloc>(context);
return BlocListener<LoginBloc, LoginState>(
listener: (context, state) {
if (state.status.isSubmissionFailure) {
LoadingDialog.hideLoadingDialog(context);
Scaffold.of(context)
..hideCurrentSnackBar()
..showSnackBar(
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(
alignment: const Alignment(0, -1 / 3),

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

@@ -1,4 +1,4 @@
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:flutter_bloc/flutter_bloc.dart';
import 'package:flutter/material.dart';

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

@@ -1,3 +0,0 @@
library authentication_repository;

export 'src/authentication_repository.dart';

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

@@ -1,34 +0,0 @@
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

@@ -1,12 +0,0 @@
# 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

@@ -1,9 +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

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

@@ -1 +0,0 @@
export 'user.dart';

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

@@ -1,10 +0,0 @@
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

@@ -1,14 +0,0 @@
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

@@ -1,4 +0,0 @@
library user_repository;

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

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

@@ -1,61 +0,0 @@
# 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

@@ -1,11 +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

+ 0
- 21
pubspec.lock View File

@@ -36,13 +36,6 @@ packages:
url: "https://pub.dartlang.org"
source: hosted
version: "2.4.1"
authentication_repository:
dependency: "direct main"
description:
path: "packages/authentication_repository"
relative: true
source: path
version: "1.0.0"
bloc:
dependency: transitive
description:
@@ -609,20 +602,6 @@ packages:
url: "https://pub.dartlang.org"
source: hosted
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:
dependency: transitive
description:

+ 0
- 5
pubspec.yaml View File

@@ -18,11 +18,6 @@ dependencies:
dio: 3.0.9
formz: ^0.3.0

authentication_repository:
path: packages/authentication_repository
user_repository:
path: packages/user_repository

dev_dependencies:
flutter_test:
sdk: flutter

Loading…
Cancel
Save