import 'dart:async'; import 'package:flutter/material.dart'; import 'package:flutter/foundation.dart'; import 'package:flutter/widgets.dart'; import 'package:flutter_redux/flutter_redux.dart'; import 'package:invoiceninja_flutter/redux/app/app_actions.dart'; import 'package:invoiceninja_flutter/redux/dashboard/dashboard_actions.dart'; import 'package:invoiceninja_flutter/redux/ui/pref_state.dart'; import 'package:invoiceninja_flutter/ui/app/app_builder.dart'; import 'package:invoiceninja_flutter/utils/formatting.dart'; import 'package:invoiceninja_flutter/utils/platforms.dart'; import 'package:redux/redux.dart'; import 'package:invoiceninja_flutter/redux/app/app_state.dart'; import 'package:invoiceninja_flutter/redux/auth/auth_actions.dart'; import 'package:invoiceninja_flutter/ui/auth/login_view.dart'; import 'package:invoiceninja_flutter/redux/auth/auth_state.dart'; import 'package:google_sign_in/google_sign_in.dart'; class LoginScreen extends StatelessWidget { const LoginScreen({Key key}) : super(key: key); static const String route = '/login'; @override Widget build(BuildContext context) { return Scaffold( body: StoreConnector( converter: LoginVM.fromStore, builder: (context, viewModel) { return LoginView( viewModel: viewModel, ); }, ), ); } } class LoginVM { LoginVM({ @required this.isLoading, @required this.authState, @required this.onLoginPressed, @required this.onRecoverPressed, @required this.onSignUpPressed, @required this.onGoogleLoginPressed, @required this.onGoogleSignUpPressed, }); bool isLoading; AuthState authState; final Function( BuildContext, Completer completer, { @required String email, @required String password, @required String url, @required String secret, @required String oneTimePassword, }) onLoginPressed; final Function( BuildContext, Completer completer, { @required String email, @required String url, @required String secret, }) onRecoverPressed; final Function( BuildContext, Completer completer, { @required String email, @required String password, }) onSignUpPressed; final Function(BuildContext, Completer completer, {String url, String secret, String oneTimePassword}) onGoogleLoginPressed; final Function(BuildContext, Completer completer) onGoogleSignUpPressed; static LoginVM fromStore(Store store) { final GoogleSignIn _googleSignIn = GoogleSignIn( scopes: [ 'email', 'openid', 'profile', 'https://www.googleapis.com/auth/gmail.send', ], ); void _handleLogin(BuildContext context) { final layout = calculateLayout(context); store.dispatch(UserPreferencesChanged(layout: layout)); AppBuilder.of(context).rebuild(); WidgetsBinding.instance.addPostFrameCallback((duration) { if (layout == AppLayout.mobile) { store.dispatch(ViewDashboard(navigator: Navigator.of(context))); } else { store.dispatch(ViewMainScreen(navigator: Navigator.of(context))); } }); } return LoginVM( isLoading: store.state.isLoading, authState: store.state.authState, onGoogleLoginPressed: ( BuildContext context, Completer completer, { @required String url, @required String secret, @required String oneTimePassword, }) async { try { final account = await _googleSignIn.signIn(); if (account != null) { account.authentication.then((GoogleSignInAuthentication value) { store.dispatch(OAuthLoginRequest( completer: completer, idToken: value.idToken, accessToken: value.accessToken, serverAuthCode: account .displayName, // TODO fix this once PR is merged https://github.com/flutter/plugins/pull/2116 url: formatApiUrl(url.trim()), secret: secret.trim(), platform: getPlatform(context), oneTimePassword: oneTimePassword, )); completer.future.then((_) => _handleLogin(context)); }); } } catch (error) { completer.completeError(error); print(error); } }, onGoogleSignUpPressed: (BuildContext context, Completer completer) async { try { final account = await _googleSignIn.signIn(); if (account != null) { account.authentication.then((GoogleSignInAuthentication value) { store.dispatch(OAuthSignUpRequest( completer: completer, idToken: value.idToken, accessToken: value.accessToken, serverAuthCode: account .displayName, // TODO fix this once PR is merged https://github.com/flutter/plugins/pull/2116 )); completer.future.then((_) => _handleLogin(context)); }); } } catch (error) { completer.completeError(error); print(error); } }, onSignUpPressed: ( BuildContext context, Completer completer, { @required String email, @required String password, }) async { if (store.state.isLoading) { return; } store.dispatch(UserSignUpRequest( completer: completer, email: email.trim(), password: password.trim(), )); completer.future.then((_) => _handleLogin(context)); }, onRecoverPressed: ( BuildContext context, Completer completer, { @required String email, @required String url, @required String secret, }) { if (store.state.isLoading) { return; } if (url.isNotEmpty && !url.startsWith('http')) { url = 'https://' + url; } store.dispatch(RecoverPasswordRequest( completer: completer, email: email.trim(), url: formatApiUrl(url.trim()), secret: secret.trim(), )); completer.future.then((_) { print('## DONE ##'); }); }, onLoginPressed: ( BuildContext context, Completer completer, { @required String email, @required String password, @required String url, @required String secret, @required String oneTimePassword, }) async { if (store.state.isLoading) { return; } if (url.isNotEmpty && !url.startsWith('http')) { url = 'https://' + url; } store.dispatch(UserLoginRequest( completer: completer, email: email.trim(), password: password.trim(), url: formatApiUrl(url.trim()), secret: secret.trim(), platform: getPlatform(context), oneTimePassword: oneTimePassword.trim(), )); completer.future.then((_) => _handleLogin(context)); }); } }