This commit is contained in:
Hillel Coren 2018-08-20 17:19:42 -07:00
parent 878aea966f
commit 6c7f8902e1
8 changed files with 109 additions and 65 deletions

View File

@ -18,12 +18,14 @@ class AuthRepository {
String password,
String url,
String secret,
String platform}) async {
String platform,
String oneTimePassword}) async {
final credentials = {
'token_name': 'invoice-ninja-$platform-app',
'api_secret': secret,
'email': email,
'password': password,
'one_time_password': oneTimePassword,
};
url = formatApiUrlMachine(url) + '/login';

View File

@ -5,15 +5,19 @@ import 'package:invoiceninja_flutter/redux/app/app_state.dart';
class LoadStateRequest {
final BuildContext context;
LoadStateRequest(this.context);
}
class LoadStateSuccess {
final AppState state;
LoadStateSuccess(this.state);
}
class LoadUserLogin {
final BuildContext context;
LoadUserLogin(this.context);
}
@ -31,7 +35,9 @@ class OAuthLoginRequest implements StartLoading {
final String url;
final String secret;
final String platform;
OAuthLoginRequest({this.completer, this.token, this.url, this.secret, this.platform});
OAuthLoginRequest(
{this.completer, this.token, this.url, this.secret, this.platform});
}
class UserLoginRequest implements StartLoading {
@ -41,8 +47,16 @@ class UserLoginRequest implements StartLoading {
final String url;
final String secret;
final String platform;
final String oneTimePassword;
UserLoginRequest({this.completer, this.email, this.password, this.url, this.secret, this.platform});
UserLoginRequest(
{this.completer,
this.email,
this.password,
this.url,
this.secret,
this.platform,
this.oneTimePassword});
}
class UserLoginSuccess implements StopLoading {}
@ -54,4 +68,3 @@ class UserLoginFailure implements StopLoading {
}
class UserLogout implements PersistData {}

View File

@ -63,7 +63,8 @@ Middleware<AppState> _createLoginRequest(AuthRepository repository) {
password: action.password,
url: action.url,
secret: action.secret,
platform: action.platform)
platform: action.platform,
oneTimePassword: action.oneTimePassword)
.then((data) {
_saveAuthLocal(action);

View File

@ -26,15 +26,16 @@ class _LoginState extends State<LoginView> {
final _passwordController = TextEditingController();
final _urlController = TextEditingController();
final _secretController = TextEditingController();
final _oneTimePasswordController = TextEditingController();
static final ValueKey _emailKey = Key(LoginKeys.emailKeyString);
static final ValueKey _passwordKey = Key(LoginKeys.passwordKeyString);
static final ValueKey _urlKey = Key(LoginKeys.urlKeyString);
static final ValueKey _secretKey = Key(LoginKeys.secretKeyString);
static final ValueKey _oneTimePasswordKey =
Key(LoginKeys.oneTimePasswordKeyString);
FocusNode focusNode1 = new FocusNode();
FocusNode focusNode2 = new FocusNode();
FocusNode focusNode3 = new FocusNode();
@override
void didChangeDependencies() {
@ -61,6 +62,7 @@ class _LoginState extends State<LoginView> {
Widget build(BuildContext context) {
final localization = AppLocalization.of(context);
final viewModel = widget.viewModel;
final error = viewModel.authState.error;
if (!viewModel.authState.isInitialized) {
return Container();
@ -78,53 +80,64 @@ class _LoginState extends State<LoginView> {
key: _formKey,
child: FormCard(
children: <Widget>[
TextFormField(
controller: _emailController,
key: _emailKey,
autocorrect: false,
decoration: InputDecoration(labelText: localization.email),
keyboardType: TextInputType.emailAddress,
validator: (val) => val.isEmpty || val.trim().isEmpty
? localization.pleaseEnterYourEmail
: null,
onFieldSubmitted: (String value) =>
FocusScope.of(context).requestFocus(focusNode1),
),
TextFormField(
controller: _passwordController,
key: _passwordKey,
autocorrect: false,
decoration: InputDecoration(labelText: localization.password),
validator: (val) => val.isEmpty || val.trim().isEmpty
? localization.pleaseEnterYourPassword
: null,
obscureText: true,
focusNode: focusNode1,
onFieldSubmitted: (String value) =>
FocusScope.of(context).requestFocus(focusNode2),
),
TextFormField(
controller: _urlController,
key: _urlKey,
autocorrect: false,
decoration: InputDecoration(labelText: localization.url),
validator: (val) => val.isEmpty || val.trim().isEmpty
? localization.pleaseEnterYourUrl
: null,
keyboardType: TextInputType.url,
focusNode: focusNode2,
onFieldSubmitted: (String value) =>
FocusScope.of(context).requestFocus(focusNode3),
),
TextFormField(
controller: _secretController,
key: _secretKey,
autocorrect: false,
decoration: InputDecoration(labelText: localization.secret),
obscureText: true,
focusNode: focusNode3,
),
viewModel.authState.error == null
(error != null && error.contains('2FA')) ||
_oneTimePasswordController.text.isNotEmpty
? TextFormField(
controller: _oneTimePasswordController,
key: _oneTimePasswordKey,
autocorrect: false,
decoration: InputDecoration(
labelText: localization.oneTimePassword),
)
: Column(
children: <Widget>[
TextFormField(
controller: _emailController,
key: _emailKey,
autocorrect: false,
decoration:
InputDecoration(labelText: localization.email),
keyboardType: TextInputType.emailAddress,
validator: (val) => val.isEmpty || val.trim().isEmpty
? localization.pleaseEnterYourEmail
: null,
onFieldSubmitted: (String value) =>
FocusScope.of(context).requestFocus(focusNode1),
),
TextFormField(
controller: _passwordController,
key: _passwordKey,
autocorrect: false,
decoration:
InputDecoration(labelText: localization.password),
validator: (val) => val.isEmpty || val.trim().isEmpty
? localization.pleaseEnterYourPassword
: null,
obscureText: true,
focusNode: focusNode1,
),
TextFormField(
controller: _urlController,
key: _urlKey,
autocorrect: false,
decoration:
InputDecoration(labelText: localization.url),
validator: (val) => val.isEmpty || val.trim().isEmpty
? localization.pleaseEnterYourUrl
: null,
keyboardType: TextInputType.url,
),
TextFormField(
controller: _secretController,
key: _secretKey,
autocorrect: false,
decoration:
InputDecoration(labelText: localization.secret),
obscureText: true,
),
],
),
viewModel.authState.error == null || error.contains('2FA')
? Container()
: Container(
padding: EdgeInsets.only(top: 26.0, bottom: 4.0),
@ -148,12 +161,12 @@ class _LoginState extends State<LoginView> {
if (!_formKey.currentState.validate()) {
return;
}
viewModel.onLoginPressed(
context,
_emailController.text,
_passwordController.text,
_urlController.text,
_secretController.text);
viewModel.onLoginPressed(context,
email: _emailController.text,
password: _passwordController.text,
url: _urlController.text,
secret: _secretController.text,
oneTimePassword: _oneTimePasswordController.text);
},
),
/*

View File

@ -9,7 +9,7 @@ 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.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';
@ -36,7 +36,12 @@ class LoginScreen extends StatelessWidget {
class LoginVM {
bool isLoading;
AuthState authState;
final Function(BuildContext, String, String, String, String) onLoginPressed;
final Function(BuildContext,
{String email,
String password,
String url,
String secret,
String oneTimePassword}) onLoginPressed;
final Function(BuildContext, String, String) onGoogleLoginPressed;
LoginVM({
@ -83,8 +88,12 @@ class LoginVM {
print(error);
}
},
onLoginPressed: (BuildContext context, String email, String password,
String url, String secret) async {
onLoginPressed: (BuildContext context,
{String email,
String password,
String url,
String secret,
String oneTimePassword}) async {
if (store.state.isLoading) {
return;
}
@ -97,6 +106,7 @@ class LoginVM {
url: url.trim(),
secret: secret.trim(),
platform: getPlatform(context),
oneTimePassword: oneTimePassword.trim(),
));
completer.future.then((_) => _handleLogin(context));
});

View File

@ -4,6 +4,7 @@ class LoginKeys {
static const String passwordKeyString = 'loginPassword';
static const String urlKeyString = 'loginUrl';
static const String secretKeyString = 'loginSecret';
static const String oneTimePasswordKeyString = 'loginOneTimePassword';
}
// Keys for Product Screen

View File

@ -262,6 +262,7 @@ class AppLocalization {
'activity_45': ':user deleted task :task',
'activity_46': ':user restored task :task',
'activity_47': ':user updated expense :expense',
'one_time_password': 'One Time Password',
},
'sq': {
'billing_address': 'Adresa e faturimit',
@ -7658,6 +7659,9 @@ class AppLocalization {
String get activity_47 =>
_localizedValues[locale.languageCode]['activity_47'];
String get oneTimePassword =>
_localizedValues[locale.languageCode]['one_time_password'];
String lookup(String key) {
return _localizedValues[locale.languageCode][toSnakeCase(key)] ?? key;
}

View File

@ -1,6 +1,6 @@
import 'package:flutter_driver/flutter_driver.dart';
import 'package:test/test.dart';
//import 'package:invoiceninja_flutter/ui/auth/login.dart';
//import 'package:invoiceninja_flutter/ui/auth/login_view.dart';
void main() {
group('scrolling performance test', () {