Last active
May 12, 2020 14:59
-
-
Save adewaleafolabi/f6478aec7b58edb041dbb2a08830c1a6 to your computer and use it in GitHub Desktop.
Mobx Issue
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import 'package:flutter/material.dart'; | |
import 'package:flutter_mobx/flutter_mobx.dart'; | |
import 'package:line_icons/line_icons.dart'; | |
import 'package:mobx/mobx.dart'; | |
import 'package:wyr_app/app_store.dart'; | |
import 'package:wyr_app/home_page.dart'; | |
import 'package:wyr_app/login_store.dart'; | |
import 'package:wyr_app/theme.dart'; | |
class LoginPage extends StatefulWidget { | |
final AppStore appStore; | |
const LoginPage({Key key, this.appStore}) : super(key: key); | |
@override | |
_LoginPageState createState() => _LoginPageState(); | |
} | |
class _LoginPageState extends State<LoginPage> { | |
final GlobalKey<ScaffoldState> _scaffoldKey = new GlobalKey<ScaffoldState>(); | |
LoginStore store; | |
ReactionDisposer _disposer; | |
ReactionDisposer _navigationDisposer; | |
_LoginPageState(); | |
@override | |
void initState() { | |
super.initState(); | |
store = LoginStore(widget.appStore); | |
store.setupValidations(); | |
_disposer = reaction( | |
(_) => store.message, | |
(AppMessage result) => _scaffoldKey.currentState.showSnackBar(SnackBar( | |
backgroundColor: | |
result.error ? Colors.red : Theme.of(context).accentColor, | |
content: Text(result.message), | |
))); | |
_navigationDisposer = reaction( | |
(_) => store.loggedIn, | |
(bool result) => Navigator.pushReplacement( | |
context, | |
MaterialPageRoute( | |
builder: (context) => HomePage( | |
appStore: widget.appStore, | |
), | |
), | |
)); | |
} | |
@override | |
void dispose() { | |
_disposer(); | |
_navigationDisposer(); | |
store.dispose(); | |
super.dispose(); | |
} | |
@override | |
Widget build(BuildContext context) { | |
final TextStyle _cardTextStyle = TextStyle( | |
fontSize: 35.0, | |
color: swatch1, | |
fontFamily: "Spartan", | |
letterSpacing: 2); | |
return Scaffold( | |
backgroundColor: Theme.of(context).primaryColor, | |
key: _scaffoldKey, | |
body: Padding( | |
padding: const EdgeInsets.only(left: 15, right: 15), | |
child: Column( | |
mainAxisAlignment: MainAxisAlignment.center, | |
children: [ | |
Image.asset( | |
"images/logo.png", | |
height: 100, | |
), | |
SizedBox( | |
height: 50, | |
), | |
Observer(builder: (_) { | |
return TextFormField( | |
style: TextStyle(color: Colors.white), | |
keyboardType: TextInputType.emailAddress, | |
onChanged: (value) => store.setUsername(value), | |
decoration: InputDecoration( | |
focusColor: Colors.red, | |
fillColor: Theme.of(context).accentColor, | |
filled: true, | |
hintText: 'Username', | |
hintStyle: TextStyle(color: Colors.white), | |
errorText: store.error.username), | |
); | |
}), | |
SizedBox( | |
height: 15, | |
), | |
Observer(builder: (_) { | |
return TextFormField( | |
style: TextStyle(color: Colors.white), | |
keyboardType: TextInputType.text, | |
obscureText: true, | |
onChanged: (value) => store.setPassword(value), | |
decoration: InputDecoration( | |
fillColor: Theme.of(context).accentColor, | |
filled: true, | |
hintText: 'Password', | |
hintStyle: TextStyle(color: Colors.white), | |
errorText: store.error.password), | |
); | |
}), | |
SizedBox( | |
height: 15, | |
), | |
Observer( | |
builder: (_) => RaisedButton( | |
shape: RoundedRectangleBorder( | |
borderRadius: BorderRadius.circular(5.0)), | |
color: Theme.of(context).accentColor, | |
textColor: Theme.of(context).primaryColor, | |
child: Padding( | |
padding: const EdgeInsets.all(15), | |
child: store.loading | |
? SizedBox( | |
width: 10, | |
height: 10, | |
child: CircularProgressIndicator( | |
valueColor: AlwaysStoppedAnimation<Color>( | |
Colors.white), | |
strokeWidth: 1, | |
), | |
) | |
: Text( | |
"Login", | |
style: TextStyle( | |
color: Colors.white, | |
), | |
), | |
), | |
onPressed: store.loading | |
? () {} | |
: () { | |
store.validateAll(); | |
if (store.loginValidationPassed) { | |
store.login(); | |
} | |
}, | |
)), | |
SizedBox( | |
height: 30, | |
), | |
Row( | |
mainAxisAlignment: MainAxisAlignment.center, | |
children: [ | |
Padding( | |
padding: const EdgeInsets.only(right: 10), | |
child: FloatingActionButton( | |
heroTag: 'Google', | |
child: Icon(LineIcons.google), | |
onPressed: () {}, | |
), | |
), | |
Padding( | |
padding: const EdgeInsets.only(right: 10), | |
child: FloatingActionButton( | |
heroTag: 'Facebook', | |
child: Icon(LineIcons.facebook_official), | |
onPressed: () {}, | |
), | |
), | |
Padding( | |
padding: const EdgeInsets.only(right: 10), | |
child: FloatingActionButton( | |
heroTag: 'Twitter', | |
child: Icon(LineIcons.twitter), | |
onPressed: () {}, | |
), | |
), | |
], | |
) | |
], | |
), | |
), | |
); | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import 'package:flutter/cupertino.dart'; | |
import 'package:grpc/grpc.dart'; | |
import 'package:mobx/mobx.dart'; | |
import 'package:string_validator/string_validator.dart'; | |
import 'package:wyr_app/app_store.dart'; | |
import 'package:jwt_decode/jwt_decode.dart'; | |
import 'package:wyr_app/service/grpc_common.dart'; | |
import 'package:wyr_app/service/wyr.pbgrpc.dart'; | |
part 'login_store.g.dart'; | |
class AppMessage { | |
bool error; | |
String message; | |
AppMessage(this.error, this.message); | |
} | |
class LoginStore = _LoginStore with _$LoginStore; | |
enum LoginFormType { LOGIN, INITIATE_RESET, COMPLETE_RESET } | |
abstract class _LoginStore with Store { | |
@observable | |
LoginFormType loginFormType = LoginFormType.LOGIN; | |
@observable | |
String username = ''; | |
@observable | |
String password = ''; | |
@observable | |
String resetToken = ''; | |
@observable | |
bool loading = false; | |
@observable | |
bool loggedIn = false; | |
@observable | |
AppMessage message; | |
final AppStore applicationStore; | |
final LoginFormErrorState error = LoginFormErrorState(); | |
final PublicClient authClient = PublicClient(GrpcClientSingleton().client); | |
_LoginStore(this.applicationStore); | |
@action | |
void setUsername(String value) { | |
username = value; | |
} | |
@action | |
void setResetToken(String value) { | |
resetToken = value; | |
} | |
@action | |
void setPassword(String value) { | |
password = value; | |
} | |
@action | |
void setProcessing(bool value) { | |
loading = value; | |
} | |
@action | |
void setLoggedIn(bool value) { | |
loggedIn = value; | |
} | |
@action | |
void setLoginFormType(LoginFormType value) { | |
loginFormType = value; | |
} | |
@action | |
void validateUsername(String value) { | |
error.username = isEmail(value) ? null : 'Not a valid username'; | |
} | |
@action | |
void validatePassword(String value) { | |
error.password = value.isNotEmpty ? null : 'Password cannot be blank'; | |
} | |
@action | |
void validateResetToken(String value) { | |
error.resetToken = value.isNotEmpty ? null : 'Not a valid reset token'; | |
} | |
@action | |
void setMessage(AppMessage value) => this.message = value; | |
@action | |
// ignore: avoid_void_async | |
Future login() async { | |
validateAll(); | |
if (!loginValidationPassed) { | |
return; | |
} | |
loading = true; | |
try { | |
UserLoginRequest request = UserLoginRequest(); | |
request.email = username; | |
request.password = password; | |
print(request.username); | |
final response = await ObservableFuture(authClient.userLogin(request)); | |
if (!response.hasJwtToken()) { | |
error.authenticationError = 'invalid account'; | |
} | |
print(Jwt.parseJwt(response.jwtToken)); | |
error.authenticationError = null; | |
loggedIn = true; | |
setMessage(AppMessage(false, 'login successful')); | |
this.message = AppMessage(false, 'login successful'); | |
} on GrpcError catch (err) { | |
print(err); | |
error.authenticationError = err.message; | |
setMessage(AppMessage(true, err.message)); | |
this.message = AppMessage(true, err.message); | |
} catch (err) { | |
print(err); | |
setMessage(AppMessage(true, err.message)); | |
this.message = AppMessage(true, err.message); | |
} | |
this.loading = false; | |
return; | |
} | |
@computed | |
bool get loginValidationPassed => !error.hasLoginValidationErrors; | |
@computed | |
bool get initPasswordResetValidationPassed => | |
!error.hasPasswordResetInitiateValidationErrors; | |
@computed | |
bool get completePasswordResetValidationPassed => | |
!error.hasPasswordResetCompleteValidationErrors; | |
List<ReactionDisposer> _disposers; | |
void setupValidations() { | |
_disposers = [ | |
reaction((_) => username, validateUsername), | |
reaction((_) => password, validatePassword), | |
reaction((_) => resetToken, validateResetToken) | |
]; | |
} | |
void dispose() { | |
for (final d in _disposers) { | |
d(); | |
} | |
} | |
void validateAll() { | |
validatePassword(password); | |
validateUsername(username); | |
} | |
} | |
class LoginFormErrorState = _LoginFormErrorState with _$LoginFormErrorState; | |
abstract class _LoginFormErrorState with Store { | |
@observable | |
String username; | |
@observable | |
String resetToken; | |
@observable | |
String password; | |
@observable | |
String authenticationError; | |
@computed | |
bool get hasLoginValidationErrors => username != null || password != null; | |
@computed | |
bool get hasPasswordResetInitiateValidationErrors => username != null; | |
@computed | |
bool get hasPasswordResetCompleteValidationErrors => | |
resetToken != null || password != null; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment