mirror of
https://github.com/cake-tech/cake_wallet.git
synced 2024-12-22 19:49:22 +00:00
Connect verify page with the authentication flow
Add Failure handlers to API calls
This commit is contained in:
parent
9ab2be35d2
commit
9ee5857912
9 changed files with 117 additions and 34 deletions
28
lib/core/failure.dart
Normal file
28
lib/core/failure.dart
Normal file
|
@ -0,0 +1,28 @@
|
|||
import 'package:cake_wallet/generated/i18n.dart';
|
||||
|
||||
abstract class Failure {
|
||||
const Failure(this.errorMessage);
|
||||
|
||||
final String errorMessage;
|
||||
}
|
||||
|
||||
class ServerFailure extends Failure {
|
||||
ServerFailure(int statusCode, {String error}) : super(_formatErrorMessage(statusCode, error));
|
||||
|
||||
static String _formatErrorMessage(int statusCode, String error) {
|
||||
switch (statusCode) {
|
||||
case 401:
|
||||
return S.current.unauthorized;
|
||||
case 404:
|
||||
return S.current.page_not_found;
|
||||
case 500:
|
||||
return S.current.server_failure;
|
||||
default:
|
||||
return error ?? S.current.something_went_wrong;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class UnknownFailure extends Failure {
|
||||
UnknownFailure({String errorMessage}) : super(errorMessage ?? S.current.something_went_wrong);
|
||||
}
|
|
@ -674,7 +674,7 @@ Future setup(
|
|||
return AddBalancePage(addBalanceViewModel: getIt.get<AddBalanceViewModel>());
|
||||
});
|
||||
|
||||
getIt.registerFactory(() {
|
||||
getIt.registerLazySingleton(() {
|
||||
return CakePhoneAuthViewModel(getIt.get<CakePhoneProvider>(), getIt.get<FlutterSecureStorage>());
|
||||
});
|
||||
|
||||
|
|
|
@ -1,12 +1,14 @@
|
|||
import 'dart:convert';
|
||||
|
||||
import 'package:cake_wallet/core/failure.dart';
|
||||
import 'package:dartz/dartz.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:http/http.dart' as http;
|
||||
|
||||
class CakePhoneProvider {
|
||||
final _baseUrl = 'cake-phone.cakewallet.com';
|
||||
|
||||
Future<bool> authenticate(String email) async {
|
||||
Future<Either<Failure, bool>> authenticate(String email) async {
|
||||
try {
|
||||
final headers = {'Content-Type': 'application/json'};
|
||||
final body = <String, String>{"email": email};
|
||||
|
@ -16,17 +18,20 @@ class CakePhoneProvider {
|
|||
|
||||
if (response.statusCode != 200) {
|
||||
debugPrint(response.body);
|
||||
return false;
|
||||
return Left(ServerFailure(response.statusCode, error: response.body));
|
||||
}
|
||||
|
||||
return true;
|
||||
final responseJSON = json.decode(response.body) as Map<String, dynamic>;
|
||||
final bool userExists = responseJSON['user_exists'] as bool;
|
||||
|
||||
return Right(userExists ?? false);
|
||||
} catch (err) {
|
||||
debugPrint(err.toString());
|
||||
return false;
|
||||
return Left(UnknownFailure(errorMessage: err.toString()));
|
||||
}
|
||||
}
|
||||
|
||||
Future<String> verifyEmail({@required String email, @required String code}) async {
|
||||
Future<Either<Failure, String>> verifyEmail({@required String email, @required String code}) async {
|
||||
try {
|
||||
final headers = {'Content-Type': 'application/json'};
|
||||
final body = <String, String>{
|
||||
|
@ -39,16 +44,16 @@ class CakePhoneProvider {
|
|||
|
||||
if (response.statusCode != 200) {
|
||||
debugPrint(response.body);
|
||||
return null;
|
||||
return Left(ServerFailure(response.statusCode, error: response.body));
|
||||
}
|
||||
|
||||
final responseJSON = json.decode(response.body) as Map<String, dynamic>;
|
||||
final String token = responseJSON['token'] as String;
|
||||
|
||||
return token;
|
||||
return Right(token);
|
||||
} catch (err) {
|
||||
debugPrint(err.toString());
|
||||
return null;
|
||||
return Left(UnknownFailure(errorMessage: err.toString()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -361,7 +361,7 @@ Route<dynamic> createRoute(RouteSettings settings) {
|
|||
case Routes.cakePhoneVerification:
|
||||
return MaterialPageRoute<CakePhoneVerificationPage>(
|
||||
settings: RouteSettings(name: Routes.cakePhoneVerification),
|
||||
builder: (_) => CakePhoneVerificationPage(),
|
||||
builder: (_) => CakePhoneVerificationPage(getIt.get<CakePhoneAuthViewModel>()),
|
||||
);
|
||||
|
||||
case Routes.cakePhoneProducts:
|
||||
|
|
|
@ -62,7 +62,7 @@ class CakePhoneAuthBodyState extends State<CakePhoneAuthBody> {
|
|||
if (state is ExecutedSuccessfullyState) {
|
||||
_authBar?.dismiss();
|
||||
WidgetsBinding.instance.addPostFrameCallback((_) {
|
||||
Navigator.pushNamed(context, Routes.cakePhoneVerification, arguments: _emailController.text);
|
||||
Navigator.pushNamed(context, Routes.cakePhoneVerification);
|
||||
});
|
||||
}
|
||||
|
||||
|
|
|
@ -1,6 +1,11 @@
|
|||
import 'dart:async';
|
||||
|
||||
import 'package:cake_wallet/core/execution_state.dart';
|
||||
import 'package:cake_wallet/di.dart';
|
||||
import 'package:cake_wallet/src/widgets/base_text_form_field.dart';
|
||||
import 'package:cake_wallet/utils/show_bar.dart';
|
||||
import 'package:cake_wallet/view_model/cake_phone/cake_phone_auth_view_model.dart';
|
||||
import 'package:flushbar/flushbar.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter/cupertino.dart';
|
||||
import 'package:cake_wallet/routes.dart';
|
||||
|
@ -8,12 +13,15 @@ import 'package:cake_wallet/generated/i18n.dart';
|
|||
import 'package:cake_wallet/src/widgets/primary_button.dart';
|
||||
import 'package:cake_wallet/src/screens/base_page.dart';
|
||||
import 'package:cake_wallet/src/widgets/scollable_with_bottom_section.dart';
|
||||
import 'package:mobx/mobx.dart';
|
||||
|
||||
class CakePhoneVerificationPage extends BasePage {
|
||||
CakePhoneVerificationPage();
|
||||
CakePhoneVerificationPage(this.authViewModel);
|
||||
|
||||
final CakePhoneAuthViewModel authViewModel;
|
||||
|
||||
@override
|
||||
Widget body(BuildContext context) => CakePhoneVerificationBody();
|
||||
Widget body(BuildContext context) => CakePhoneVerificationBody(authViewModel);
|
||||
|
||||
@override
|
||||
Widget middle(BuildContext context) {
|
||||
|
@ -29,7 +37,9 @@ class CakePhoneVerificationPage extends BasePage {
|
|||
}
|
||||
|
||||
class CakePhoneVerificationBody extends StatefulWidget {
|
||||
CakePhoneVerificationBody();
|
||||
CakePhoneVerificationBody(this.authViewModel);
|
||||
|
||||
final CakePhoneAuthViewModel authViewModel;
|
||||
|
||||
@override
|
||||
CakePhoneVerificationBodyState createState() => CakePhoneVerificationBodyState();
|
||||
|
@ -46,6 +56,9 @@ class CakePhoneVerificationBodyState extends State<CakePhoneVerificationBody> {
|
|||
|
||||
bool disabled = true;
|
||||
|
||||
ReactionDisposer _reaction;
|
||||
Flushbar<void> _authBar;
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
|
@ -61,6 +74,35 @@ class CakePhoneVerificationBodyState extends State<CakePhoneVerificationBody> {
|
|||
setState(() {});
|
||||
}
|
||||
});
|
||||
|
||||
_reaction ??= reaction((_) => widget.authViewModel.state, (ExecutionState state) {
|
||||
if (state is ExecutedSuccessfullyState) {
|
||||
_authBar?.dismiss();
|
||||
WidgetsBinding.instance.addPostFrameCallback((_) {
|
||||
final userExists = state.payload as bool;
|
||||
Navigator.pushNamedAndRemoveUntil(
|
||||
context,
|
||||
userExists ? Routes.cakePhoneActiveServices : Routes.cakePhoneProducts,
|
||||
ModalRoute.withName(Routes.cakePhoneWelcome),
|
||||
);
|
||||
/// reset the authentication view model
|
||||
getIt.resetLazySingleton<CakePhoneAuthViewModel>(instance: widget.authViewModel);
|
||||
});
|
||||
}
|
||||
|
||||
if (state is IsExecutingState) {
|
||||
WidgetsBinding.instance.addPostFrameCallback((_) {
|
||||
_authBar = createBar<void>(S.of(context).authentication, duration: null)..show(context);
|
||||
});
|
||||
}
|
||||
|
||||
if (state is FailureState) {
|
||||
WidgetsBinding.instance.addPostFrameCallback((_) {
|
||||
_authBar?.dismiss();
|
||||
showBar<void>(context, S.of(context).failed_authentication(state.error));
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@override
|
||||
|
@ -150,11 +192,7 @@ class CakePhoneVerificationBodyState extends State<CakePhoneVerificationBody> {
|
|||
PrimaryButton(
|
||||
onPressed: () {
|
||||
if (_formKey.currentState.validate()) {
|
||||
Navigator.pushNamedAndRemoveUntil(
|
||||
context,
|
||||
Routes.cakePhoneProducts,
|
||||
ModalRoute.withName(Routes.cakePhoneWelcome),
|
||||
);
|
||||
widget.authViewModel.verify(_codeController.text);
|
||||
} else {
|
||||
setState(() {
|
||||
_autoValidate = AutovalidateMode.always;
|
||||
|
|
|
@ -20,28 +20,35 @@ abstract class CakePhoneAuthViewModelBase with Store {
|
|||
final CakePhoneProvider _cakePhoneProvider;
|
||||
final FlutterSecureStorage _secureStorage;
|
||||
|
||||
bool _userExists = false;
|
||||
String _email = "";
|
||||
|
||||
@action
|
||||
Future<void> auth(String email) async {
|
||||
state = IsExecutingState();
|
||||
|
||||
final isSuccessfullyAuthenticated = await _cakePhoneProvider.authenticate(email);
|
||||
final result = await _cakePhoneProvider.authenticate(email);
|
||||
|
||||
if (isSuccessfullyAuthenticated) {
|
||||
state = ExecutedSuccessfullyState();
|
||||
} else {
|
||||
state = FailureState("");
|
||||
}
|
||||
result.fold(
|
||||
(failure) => state = FailureState(failure.errorMessage),
|
||||
(userExists) {
|
||||
_userExists = userExists;
|
||||
_email = email;
|
||||
state = ExecutedSuccessfullyState();
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
@action
|
||||
Future<void> verify(String email, String code) async {
|
||||
final String token = await _cakePhoneProvider.verifyEmail(email: email, code: code);
|
||||
Future<void> verify(String code) async {
|
||||
final result = await _cakePhoneProvider.verifyEmail(email: _email, code: code);
|
||||
|
||||
if (token != null) {
|
||||
state = ExecutedSuccessfullyState();
|
||||
await _secureStorage.write(key: PreferencesKey.cakePhoneTokenKey, value: token);
|
||||
} else {
|
||||
state = FailureState("");
|
||||
}
|
||||
result.fold(
|
||||
(failure) => state = FailureState(failure.errorMessage),
|
||||
(token) {
|
||||
_secureStorage.write(key: PreferencesKey.cakePhoneTokenKey, value: token);
|
||||
state = ExecutedSuccessfullyState(payload: _userExists);
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -56,6 +56,7 @@ dependencies:
|
|||
permission_handler: ^5.0.1+1
|
||||
device_display_brightness: ^0.0.6
|
||||
country_pickers: ^2.0.0
|
||||
dartz: ^0.10.1
|
||||
|
||||
dev_dependencies:
|
||||
flutter_test:
|
||||
|
|
|
@ -596,5 +596,9 @@
|
|||
"add_balance": "Add Balance",
|
||||
"forwards": "forwards",
|
||||
"invalid_email": "Invalid Email",
|
||||
"invalid_verification_code": "Invalid verification code"
|
||||
"invalid_verification_code": "Invalid verification code",
|
||||
"unauthorized": "Un-Authorized access, Please login first then try again",
|
||||
"page_not_found": "This page was temporary removed, Please check it later",
|
||||
"server_failure": "Network Error, Please try again later",
|
||||
"something_went_wrong": "Something went wrong, Please try again later"
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue