mirror of
https://github.com/cake-tech/cake_wallet.git
synced 2025-01-24 11:36:21 +00:00
Create CakePhone provider to handle cake phone APIs
Add CakePhone Auth View Model to manage the authentication flow
This commit is contained in:
parent
eed908e6da
commit
9ab2be35d2
6 changed files with 160 additions and 29 deletions
|
@ -5,10 +5,12 @@ import 'package:cake_wallet/entities/wake_lock.dart';
|
||||||
import 'package:cake_wallet/monero/monero.dart';
|
import 'package:cake_wallet/monero/monero.dart';
|
||||||
import 'package:cake_wallet/haven/haven.dart';
|
import 'package:cake_wallet/haven/haven.dart';
|
||||||
import 'package:cake_wallet/bitcoin/bitcoin.dart';
|
import 'package:cake_wallet/bitcoin/bitcoin.dart';
|
||||||
|
import 'package:cake_wallet/providers/cake_phone_provider.dart';
|
||||||
import 'package:cake_wallet/src/screens/cake_phone/phone_number_service/auto_renew_settings_page.dart';
|
import 'package:cake_wallet/src/screens/cake_phone/phone_number_service/auto_renew_settings_page.dart';
|
||||||
import 'package:cake_wallet/src/screens/cake_phone/phone_number_service/number_settings_page.dart';
|
import 'package:cake_wallet/src/screens/cake_phone/phone_number_service/number_settings_page.dart';
|
||||||
import 'package:cake_wallet/src/screens/dashboard/widgets/balance_page.dart';
|
import 'package:cake_wallet/src/screens/dashboard/widgets/balance_page.dart';
|
||||||
import 'package:cake_wallet/view_model/cake_phone/add_balance_view_model.dart';
|
import 'package:cake_wallet/view_model/cake_phone/add_balance_view_model.dart';
|
||||||
|
import 'package:cake_wallet/view_model/cake_phone/cake_phone_auth_view_model.dart';
|
||||||
import 'package:cake_wallet/view_model/cake_phone/phone_plan_view_model.dart';
|
import 'package:cake_wallet/view_model/cake_phone/phone_plan_view_model.dart';
|
||||||
import 'package:cw_core/unspent_coins_info.dart';
|
import 'package:cw_core/unspent_coins_info.dart';
|
||||||
import 'package:cake_wallet/core/backup_service.dart';
|
import 'package:cake_wallet/core/backup_service.dart';
|
||||||
|
@ -672,5 +674,11 @@ Future setup(
|
||||||
return AddBalancePage(addBalanceViewModel: getIt.get<AddBalanceViewModel>());
|
return AddBalancePage(addBalanceViewModel: getIt.get<AddBalanceViewModel>());
|
||||||
});
|
});
|
||||||
|
|
||||||
|
getIt.registerFactory(() {
|
||||||
|
return CakePhoneAuthViewModel(getIt.get<CakePhoneProvider>(), getIt.get<FlutterSecureStorage>());
|
||||||
|
});
|
||||||
|
|
||||||
|
getIt.registerLazySingleton(() => CakePhoneProvider());
|
||||||
|
|
||||||
_isSetupFinished = true;
|
_isSetupFinished = true;
|
||||||
}
|
}
|
||||||
|
|
|
@ -22,4 +22,5 @@ class PreferencesKey {
|
||||||
static const bitcoinTransactionPriority = 'current_fee_priority_bitcoin';
|
static const bitcoinTransactionPriority = 'current_fee_priority_bitcoin';
|
||||||
static const shouldShowReceiveWarning = 'should_show_receive_warning';
|
static const shouldShowReceiveWarning = 'should_show_receive_warning';
|
||||||
static const shouldShowYatPopup = 'should_show_yat_popup';
|
static const shouldShowYatPopup = 'should_show_yat_popup';
|
||||||
|
static const cakePhoneTokenKey = 'cake_phone_token_key';
|
||||||
}
|
}
|
||||||
|
|
54
lib/providers/cake_phone_provider.dart
Normal file
54
lib/providers/cake_phone_provider.dart
Normal file
|
@ -0,0 +1,54 @@
|
||||||
|
import 'dart:convert';
|
||||||
|
|
||||||
|
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 {
|
||||||
|
try {
|
||||||
|
final headers = {'Content-Type': 'application/json'};
|
||||||
|
final body = <String, String>{"email": email};
|
||||||
|
|
||||||
|
final uri = Uri.https(_baseUrl, '/email');
|
||||||
|
final response = await http.post(uri, headers: headers, body: json.encode(body));
|
||||||
|
|
||||||
|
if (response.statusCode != 200) {
|
||||||
|
debugPrint(response.body);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
} catch (err) {
|
||||||
|
debugPrint(err.toString());
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<String> verifyEmail({@required String email, @required String code}) async {
|
||||||
|
try {
|
||||||
|
final headers = {'Content-Type': 'application/json'};
|
||||||
|
final body = <String, String>{
|
||||||
|
"code": code,
|
||||||
|
"email": email,
|
||||||
|
};
|
||||||
|
|
||||||
|
final uri = Uri.https(_baseUrl, '/email/verify');
|
||||||
|
final response = await http.post(uri, headers: headers, body: json.encode(body));
|
||||||
|
|
||||||
|
if (response.statusCode != 200) {
|
||||||
|
debugPrint(response.body);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
final responseJSON = json.decode(response.body) as Map<String, dynamic>;
|
||||||
|
final String token = responseJSON['token'] as String;
|
||||||
|
|
||||||
|
return token;
|
||||||
|
} catch (err) {
|
||||||
|
debugPrint(err.toString());
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -15,6 +15,7 @@ import 'package:cake_wallet/src/screens/seed/pre_seed_page.dart';
|
||||||
import 'package:cake_wallet/src/screens/support/support_page.dart';
|
import 'package:cake_wallet/src/screens/support/support_page.dart';
|
||||||
import 'package:cake_wallet/src/screens/unspent_coins/unspent_coins_details_page.dart';
|
import 'package:cake_wallet/src/screens/unspent_coins/unspent_coins_details_page.dart';
|
||||||
import 'package:cake_wallet/src/screens/unspent_coins/unspent_coins_list_page.dart';
|
import 'package:cake_wallet/src/screens/unspent_coins/unspent_coins_list_page.dart';
|
||||||
|
import 'package:cake_wallet/view_model/cake_phone/cake_phone_auth_view_model.dart';
|
||||||
import 'package:cake_wallet/view_model/cake_phone/phone_plan_view_model.dart';
|
import 'package:cake_wallet/view_model/cake_phone/phone_plan_view_model.dart';
|
||||||
import 'package:cake_wallet/view_model/monero_account_list/account_list_item.dart';
|
import 'package:cake_wallet/view_model/monero_account_list/account_list_item.dart';
|
||||||
import 'package:flutter/cupertino.dart';
|
import 'package:flutter/cupertino.dart';
|
||||||
|
@ -351,7 +352,10 @@ Route<dynamic> createRoute(RouteSettings settings) {
|
||||||
|
|
||||||
return MaterialPageRoute<CakePhoneWelcomePage>(
|
return MaterialPageRoute<CakePhoneWelcomePage>(
|
||||||
settings: RouteSettings(name: Routes.cakePhoneAuth),
|
settings: RouteSettings(name: Routes.cakePhoneAuth),
|
||||||
builder: (_) => CakePhoneAuthPage(isLogin: isLogin),
|
builder: (_) => CakePhoneAuthPage(
|
||||||
|
isLogin: isLogin,
|
||||||
|
cakePhoneAuthViewModel: getIt.get<CakePhoneAuthViewModel>(),
|
||||||
|
),
|
||||||
);
|
);
|
||||||
|
|
||||||
case Routes.cakePhoneVerification:
|
case Routes.cakePhoneVerification:
|
||||||
|
|
|
@ -1,5 +1,7 @@
|
||||||
import 'package:cake_wallet/palette.dart';
|
import 'package:cake_wallet/palette.dart';
|
||||||
import 'package:cake_wallet/src/widgets/base_text_form_field.dart';
|
import 'package:cake_wallet/src/widgets/base_text_form_field.dart';
|
||||||
|
import 'package:cake_wallet/utils/show_bar.dart';
|
||||||
|
import 'package:flushbar/flushbar.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter/cupertino.dart';
|
import 'package:flutter/cupertino.dart';
|
||||||
import 'package:cake_wallet/routes.dart';
|
import 'package:cake_wallet/routes.dart';
|
||||||
|
@ -7,14 +9,18 @@ import 'package:cake_wallet/generated/i18n.dart';
|
||||||
import 'package:cake_wallet/src/widgets/primary_button.dart';
|
import 'package:cake_wallet/src/widgets/primary_button.dart';
|
||||||
import 'package:cake_wallet/src/screens/base_page.dart';
|
import 'package:cake_wallet/src/screens/base_page.dart';
|
||||||
import 'package:cake_wallet/src/widgets/scollable_with_bottom_section.dart';
|
import 'package:cake_wallet/src/widgets/scollable_with_bottom_section.dart';
|
||||||
|
import 'package:cake_wallet/view_model/cake_phone/cake_phone_auth_view_model.dart';
|
||||||
|
import 'package:mobx/mobx.dart';
|
||||||
|
import 'package:cake_wallet/core/execution_state.dart';
|
||||||
|
|
||||||
class CakePhoneAuthPage extends BasePage {
|
class CakePhoneAuthPage extends BasePage {
|
||||||
CakePhoneAuthPage({@required this.isLogin});
|
CakePhoneAuthPage({@required this.isLogin, @required this.cakePhoneAuthViewModel});
|
||||||
|
|
||||||
final bool isLogin;
|
final bool isLogin;
|
||||||
|
final CakePhoneAuthViewModel cakePhoneAuthViewModel;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget body(BuildContext context) => CakePhoneAuthBody(isLogin);
|
Widget body(BuildContext context) => CakePhoneAuthBody(isLogin, cakePhoneAuthViewModel);
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget middle(BuildContext context) {
|
Widget middle(BuildContext context) {
|
||||||
|
@ -30,9 +36,10 @@ class CakePhoneAuthPage extends BasePage {
|
||||||
}
|
}
|
||||||
|
|
||||||
class CakePhoneAuthBody extends StatefulWidget {
|
class CakePhoneAuthBody extends StatefulWidget {
|
||||||
CakePhoneAuthBody(this.isLogin);
|
CakePhoneAuthBody(this.isLogin, this.cakePhoneAuthViewModel);
|
||||||
|
|
||||||
final bool isLogin;
|
final bool isLogin;
|
||||||
|
final CakePhoneAuthViewModel cakePhoneAuthViewModel;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
CakePhoneAuthBodyState createState() => CakePhoneAuthBodyState();
|
CakePhoneAuthBodyState createState() => CakePhoneAuthBodyState();
|
||||||
|
@ -44,6 +51,36 @@ class CakePhoneAuthBodyState extends State<CakePhoneAuthBody> {
|
||||||
|
|
||||||
AutovalidateMode _autoValidate = AutovalidateMode.disabled;
|
AutovalidateMode _autoValidate = AutovalidateMode.disabled;
|
||||||
|
|
||||||
|
ReactionDisposer _reaction;
|
||||||
|
Flushbar<void> _authBar;
|
||||||
|
|
||||||
|
@override
|
||||||
|
void initState() {
|
||||||
|
super.initState();
|
||||||
|
|
||||||
|
_reaction ??= reaction((_) => widget.cakePhoneAuthViewModel.state, (ExecutionState state) {
|
||||||
|
if (state is ExecutedSuccessfullyState) {
|
||||||
|
_authBar?.dismiss();
|
||||||
|
WidgetsBinding.instance.addPostFrameCallback((_) {
|
||||||
|
Navigator.pushNamed(context, Routes.cakePhoneVerification, arguments: _emailController.text);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
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
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return Container(
|
return Container(
|
||||||
|
@ -73,10 +110,12 @@ class CakePhoneAuthBodyState extends State<CakePhoneAuthBody> {
|
||||||
children: <Widget>[
|
children: <Widget>[
|
||||||
PrimaryButton(
|
PrimaryButton(
|
||||||
onPressed: () {
|
onPressed: () {
|
||||||
if (widget.isLogin) {
|
if (_formKey.currentState.validate()) {
|
||||||
_loginCakePhone();
|
widget.cakePhoneAuthViewModel.auth(_emailController.text);
|
||||||
} else {
|
} else {
|
||||||
_registerCakePhone();
|
setState(() {
|
||||||
|
_autoValidate = AutovalidateMode.always;
|
||||||
|
});
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
text: widget.isLogin ? S.of(context).login : S.of(context).create_account,
|
text: widget.isLogin ? S.of(context).login : S.of(context).create_account,
|
||||||
|
@ -127,26 +166,4 @@ class CakePhoneAuthBodyState extends State<CakePhoneAuthBody> {
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
void _registerCakePhone() {
|
|
||||||
// TODO: Add Registration logic
|
|
||||||
if (_formKey.currentState.validate()) {
|
|
||||||
Navigator.pushNamed(context, Routes.cakePhoneVerification);
|
|
||||||
} else {
|
|
||||||
setState(() {
|
|
||||||
_autoValidate = AutovalidateMode.always;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void _loginCakePhone() {
|
|
||||||
// TODO: Add Login logic
|
|
||||||
if (_formKey.currentState.validate()) {
|
|
||||||
Navigator.pushNamed(context, Routes.cakePhoneVerification);
|
|
||||||
} else {
|
|
||||||
setState(() {
|
|
||||||
_autoValidate = AutovalidateMode.always;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
47
lib/view_model/cake_phone/cake_phone_auth_view_model.dart
Normal file
47
lib/view_model/cake_phone/cake_phone_auth_view_model.dart
Normal file
|
@ -0,0 +1,47 @@
|
||||||
|
import 'dart:async';
|
||||||
|
import 'package:cake_wallet/entities/preferences_key.dart';
|
||||||
|
import 'package:flutter_secure_storage/flutter_secure_storage.dart';
|
||||||
|
import 'package:mobx/mobx.dart';
|
||||||
|
import 'package:cake_wallet/providers/cake_phone_provider.dart';
|
||||||
|
import 'package:cake_wallet/core/execution_state.dart';
|
||||||
|
|
||||||
|
part 'cake_phone_auth_view_model.g.dart';
|
||||||
|
|
||||||
|
class CakePhoneAuthViewModel = CakePhoneAuthViewModelBase with _$CakePhoneAuthViewModel;
|
||||||
|
|
||||||
|
abstract class CakePhoneAuthViewModelBase with Store {
|
||||||
|
CakePhoneAuthViewModelBase(this._cakePhoneProvider, this._secureStorage) {
|
||||||
|
state = InitialExecutionState();
|
||||||
|
}
|
||||||
|
|
||||||
|
@observable
|
||||||
|
ExecutionState state;
|
||||||
|
|
||||||
|
final CakePhoneProvider _cakePhoneProvider;
|
||||||
|
final FlutterSecureStorage _secureStorage;
|
||||||
|
|
||||||
|
@action
|
||||||
|
Future<void> auth(String email) async {
|
||||||
|
state = IsExecutingState();
|
||||||
|
|
||||||
|
final isSuccessfullyAuthenticated = await _cakePhoneProvider.authenticate(email);
|
||||||
|
|
||||||
|
if (isSuccessfullyAuthenticated) {
|
||||||
|
state = ExecutedSuccessfullyState();
|
||||||
|
} else {
|
||||||
|
state = FailureState("");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@action
|
||||||
|
Future<void> verify(String email, String code) async {
|
||||||
|
final String token = await _cakePhoneProvider.verifyEmail(email: email, code: code);
|
||||||
|
|
||||||
|
if (token != null) {
|
||||||
|
state = ExecutedSuccessfullyState();
|
||||||
|
await _secureStorage.write(key: PreferencesKey.cakePhoneTokenKey, value: token);
|
||||||
|
} else {
|
||||||
|
state = FailureState("");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in a new issue