mirror of
https://github.com/cake-tech/cake_wallet.git
synced 2025-01-08 20:09:24 +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/haven/haven.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/number_settings_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/cake_phone_auth_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:cake_wallet/core/backup_service.dart';
|
||||
|
@ -672,5 +674,11 @@ Future setup(
|
|||
return AddBalancePage(addBalanceViewModel: getIt.get<AddBalanceViewModel>());
|
||||
});
|
||||
|
||||
getIt.registerFactory(() {
|
||||
return CakePhoneAuthViewModel(getIt.get<CakePhoneProvider>(), getIt.get<FlutterSecureStorage>());
|
||||
});
|
||||
|
||||
getIt.registerLazySingleton(() => CakePhoneProvider());
|
||||
|
||||
_isSetupFinished = true;
|
||||
}
|
||||
|
|
|
@ -22,4 +22,5 @@ class PreferencesKey {
|
|||
static const bitcoinTransactionPriority = 'current_fee_priority_bitcoin';
|
||||
static const shouldShowReceiveWarning = 'should_show_receive_warning';
|
||||
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/unspent_coins/unspent_coins_details_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/monero_account_list/account_list_item.dart';
|
||||
import 'package:flutter/cupertino.dart';
|
||||
|
@ -351,7 +352,10 @@ Route<dynamic> createRoute(RouteSettings settings) {
|
|||
|
||||
return MaterialPageRoute<CakePhoneWelcomePage>(
|
||||
settings: RouteSettings(name: Routes.cakePhoneAuth),
|
||||
builder: (_) => CakePhoneAuthPage(isLogin: isLogin),
|
||||
builder: (_) => CakePhoneAuthPage(
|
||||
isLogin: isLogin,
|
||||
cakePhoneAuthViewModel: getIt.get<CakePhoneAuthViewModel>(),
|
||||
),
|
||||
);
|
||||
|
||||
case Routes.cakePhoneVerification:
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
import 'package:cake_wallet/palette.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/cupertino.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/screens/base_page.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 {
|
||||
CakePhoneAuthPage({@required this.isLogin});
|
||||
CakePhoneAuthPage({@required this.isLogin, @required this.cakePhoneAuthViewModel});
|
||||
|
||||
final bool isLogin;
|
||||
final CakePhoneAuthViewModel cakePhoneAuthViewModel;
|
||||
|
||||
@override
|
||||
Widget body(BuildContext context) => CakePhoneAuthBody(isLogin);
|
||||
Widget body(BuildContext context) => CakePhoneAuthBody(isLogin, cakePhoneAuthViewModel);
|
||||
|
||||
@override
|
||||
Widget middle(BuildContext context) {
|
||||
|
@ -30,9 +36,10 @@ class CakePhoneAuthPage extends BasePage {
|
|||
}
|
||||
|
||||
class CakePhoneAuthBody extends StatefulWidget {
|
||||
CakePhoneAuthBody(this.isLogin);
|
||||
CakePhoneAuthBody(this.isLogin, this.cakePhoneAuthViewModel);
|
||||
|
||||
final bool isLogin;
|
||||
final CakePhoneAuthViewModel cakePhoneAuthViewModel;
|
||||
|
||||
@override
|
||||
CakePhoneAuthBodyState createState() => CakePhoneAuthBodyState();
|
||||
|
@ -44,6 +51,36 @@ class CakePhoneAuthBodyState extends State<CakePhoneAuthBody> {
|
|||
|
||||
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
|
||||
Widget build(BuildContext context) {
|
||||
return Container(
|
||||
|
@ -73,10 +110,12 @@ class CakePhoneAuthBodyState extends State<CakePhoneAuthBody> {
|
|||
children: <Widget>[
|
||||
PrimaryButton(
|
||||
onPressed: () {
|
||||
if (widget.isLogin) {
|
||||
_loginCakePhone();
|
||||
if (_formKey.currentState.validate()) {
|
||||
widget.cakePhoneAuthViewModel.auth(_emailController.text);
|
||||
} else {
|
||||
_registerCakePhone();
|
||||
setState(() {
|
||||
_autoValidate = AutovalidateMode.always;
|
||||
});
|
||||
}
|
||||
},
|
||||
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