|
@ -18,17 +18,17 @@ Future<SignupResponse> signUp(context, String username, String password, String |
|
|
|
|
|
|
|
|
// TODO: Check for timeout here |
|
|
// TODO: Check for timeout here |
|
|
final resp = await http.post( |
|
|
final resp = await http.post( |
|
|
Uri.parse('${dotenv.env["SERVER_URL"]}api/v1/signup'), |
|
|
|
|
|
headers: <String, String>{ |
|
|
|
|
|
'Content-Type': 'application/json; charset=UTF-8', |
|
|
|
|
|
}, |
|
|
|
|
|
body: jsonEncode(<String, String>{ |
|
|
|
|
|
'username': username, |
|
|
|
|
|
'password': password, |
|
|
|
|
|
'confirm_password': confirmPassword, |
|
|
|
|
|
'asymmetric_public_key': rsaPubPem, |
|
|
|
|
|
'asymmetric_private_key': encRsaPriv, |
|
|
|
|
|
}), |
|
|
|
|
|
|
|
|
Uri.parse('${dotenv.env["SERVER_URL"]}api/v1/signup'), |
|
|
|
|
|
headers: <String, String>{ |
|
|
|
|
|
'Content-Type': 'application/json; charset=UTF-8', |
|
|
|
|
|
}, |
|
|
|
|
|
body: jsonEncode(<String, String>{ |
|
|
|
|
|
'username': username, |
|
|
|
|
|
'password': password, |
|
|
|
|
|
'confirm_password': confirmPassword, |
|
|
|
|
|
'asymmetric_public_key': rsaPubPem, |
|
|
|
|
|
'asymmetric_private_key': encRsaPriv, |
|
|
|
|
|
}), |
|
|
); |
|
|
); |
|
|
|
|
|
|
|
|
SignupResponse response = SignupResponse.fromJson(jsonDecode(resp.body)); |
|
|
SignupResponse response = SignupResponse.fromJson(jsonDecode(resp.body)); |
|
@ -47,17 +47,17 @@ class Signup extends StatelessWidget { |
|
|
Widget build(BuildContext context) { |
|
|
Widget build(BuildContext context) { |
|
|
return Scaffold( |
|
|
return Scaffold( |
|
|
appBar: AppBar( |
|
|
appBar: AppBar( |
|
|
title: null, |
|
|
|
|
|
automaticallyImplyLeading: true, |
|
|
|
|
|
//`true` if you want Flutter to automatically add Back Button when needed, |
|
|
|
|
|
//or `false` if you want to force your own back button every where |
|
|
|
|
|
leading: IconButton(icon: const Icon(Icons.arrow_back), |
|
|
|
|
|
onPressed:() => { |
|
|
|
|
|
Navigator.pop(context) |
|
|
|
|
|
} |
|
|
|
|
|
), |
|
|
|
|
|
backgroundColor: Colors.transparent, |
|
|
|
|
|
shadowColor: Colors.transparent, |
|
|
|
|
|
|
|
|
title: null, |
|
|
|
|
|
automaticallyImplyLeading: true, |
|
|
|
|
|
//`true` if you want Flutter to automatically add Back Button when needed, |
|
|
|
|
|
//or `false` if you want to force your own back button every where |
|
|
|
|
|
leading: IconButton(icon: const Icon(Icons.arrow_back), |
|
|
|
|
|
onPressed:() => { |
|
|
|
|
|
Navigator.pop(context) |
|
|
|
|
|
} |
|
|
|
|
|
), |
|
|
|
|
|
backgroundColor: Colors.transparent, |
|
|
|
|
|
shadowColor: Colors.transparent, |
|
|
), |
|
|
), |
|
|
body: const SafeArea( |
|
|
body: const SafeArea( |
|
|
child: SignupWidget(), |
|
|
child: SignupWidget(), |
|
@ -77,8 +77,8 @@ class SignupResponse { |
|
|
|
|
|
|
|
|
factory SignupResponse.fromJson(Map<String, dynamic> json) { |
|
|
factory SignupResponse.fromJson(Map<String, dynamic> json) { |
|
|
return SignupResponse( |
|
|
return SignupResponse( |
|
|
status: json['status'], |
|
|
|
|
|
message: json['message'], |
|
|
|
|
|
|
|
|
status: json['status'], |
|
|
|
|
|
message: json['message'], |
|
|
); |
|
|
); |
|
|
} |
|
|
} |
|
|
} |
|
|
} |
|
@ -93,9 +93,9 @@ class SignupWidget extends StatefulWidget { |
|
|
class _SignupWidgetState extends State<SignupWidget> { |
|
|
class _SignupWidgetState extends State<SignupWidget> { |
|
|
final _formKey = GlobalKey<FormState>(); |
|
|
final _formKey = GlobalKey<FormState>(); |
|
|
|
|
|
|
|
|
TextEditingController usernameController = TextEditingController(); |
|
|
|
|
|
TextEditingController passwordController = TextEditingController(); |
|
|
|
|
|
TextEditingController passwordConfirmController = TextEditingController(); |
|
|
|
|
|
|
|
|
TextEditingController _usernameController = TextEditingController(); |
|
|
|
|
|
TextEditingController _passwordController = TextEditingController(); |
|
|
|
|
|
TextEditingController _passwordConfirmController = TextEditingController(); |
|
|
|
|
|
|
|
|
@override |
|
|
@override |
|
|
Widget build(BuildContext context) { |
|
|
Widget build(BuildContext context) { |
|
@ -123,114 +123,116 @@ class _SignupWidgetState extends State<SignupWidget> { |
|
|
); |
|
|
); |
|
|
|
|
|
|
|
|
return Center( |
|
|
return Center( |
|
|
child: Form( |
|
|
|
|
|
key: _formKey, |
|
|
|
|
|
child: Center( |
|
|
|
|
|
child: Padding( |
|
|
|
|
|
padding: const EdgeInsets.only( |
|
|
|
|
|
left: 20, |
|
|
|
|
|
right: 20, |
|
|
|
|
|
top: 0, |
|
|
|
|
|
bottom: 100, |
|
|
|
|
|
), |
|
|
|
|
|
child: Column( |
|
|
|
|
|
mainAxisAlignment: MainAxisAlignment.center, |
|
|
|
|
|
crossAxisAlignment: CrossAxisAlignment.center, |
|
|
|
|
|
children: [ |
|
|
|
|
|
Text( |
|
|
|
|
|
'Sign Up', |
|
|
|
|
|
style: TextStyle( |
|
|
|
|
|
fontSize: 35, |
|
|
|
|
|
color: Theme.of(context).colorScheme.onBackground, |
|
|
|
|
|
), |
|
|
|
|
|
), |
|
|
|
|
|
const SizedBox(height: 30), |
|
|
|
|
|
TextFormField( |
|
|
|
|
|
controller: usernameController, |
|
|
|
|
|
decoration: InputDecoration( |
|
|
|
|
|
hintText: 'Username', |
|
|
|
|
|
enabledBorder: inputBorderStyle, |
|
|
|
|
|
focusedBorder: inputBorderStyle, |
|
|
|
|
|
), |
|
|
|
|
|
style: inputTextStyle, |
|
|
|
|
|
// The validator receives the text that the user has entered. |
|
|
|
|
|
validator: (value) { |
|
|
|
|
|
if (value == null || value.isEmpty) { |
|
|
|
|
|
return 'Create a username'; |
|
|
|
|
|
} |
|
|
|
|
|
return null; |
|
|
|
|
|
}, |
|
|
|
|
|
), |
|
|
|
|
|
const SizedBox(height: 10), |
|
|
|
|
|
TextFormField( |
|
|
|
|
|
controller: passwordController, |
|
|
|
|
|
obscureText: true, |
|
|
|
|
|
enableSuggestions: false, |
|
|
|
|
|
autocorrect: false, |
|
|
|
|
|
decoration: InputDecoration( |
|
|
|
|
|
hintText: 'Password', |
|
|
|
|
|
enabledBorder: inputBorderStyle, |
|
|
|
|
|
focusedBorder: inputBorderStyle, |
|
|
|
|
|
), |
|
|
|
|
|
style: inputTextStyle, |
|
|
|
|
|
// The validator receives the text that the user has entered. |
|
|
|
|
|
validator: (value) { |
|
|
|
|
|
if (value == null || value.isEmpty) { |
|
|
|
|
|
return 'Enter a password'; |
|
|
|
|
|
} |
|
|
|
|
|
return null; |
|
|
|
|
|
}, |
|
|
|
|
|
), |
|
|
|
|
|
const SizedBox(height: 10), |
|
|
|
|
|
TextFormField( |
|
|
|
|
|
controller: passwordConfirmController, |
|
|
|
|
|
obscureText: true, |
|
|
|
|
|
enableSuggestions: false, |
|
|
|
|
|
autocorrect: false, |
|
|
|
|
|
decoration: InputDecoration( |
|
|
|
|
|
hintText: 'Password', |
|
|
|
|
|
enabledBorder: inputBorderStyle, |
|
|
|
|
|
focusedBorder: inputBorderStyle, |
|
|
|
|
|
), |
|
|
|
|
|
style: inputTextStyle, |
|
|
|
|
|
// The validator receives the text that the user has entered. |
|
|
|
|
|
validator: (value) { |
|
|
|
|
|
if (value == null || value.isEmpty) { |
|
|
|
|
|
return 'Confirm your password'; |
|
|
|
|
|
} |
|
|
|
|
|
if (value != passwordController.text) { |
|
|
|
|
|
return 'Passwords do not match'; |
|
|
|
|
|
} |
|
|
|
|
|
return null; |
|
|
|
|
|
}, |
|
|
|
|
|
), |
|
|
|
|
|
const SizedBox(height: 15), |
|
|
|
|
|
ElevatedButton( |
|
|
|
|
|
style: buttonStyle, |
|
|
|
|
|
onPressed: () { |
|
|
|
|
|
if (_formKey.currentState!.validate()) { |
|
|
|
|
|
ScaffoldMessenger.of(context).showSnackBar( |
|
|
|
|
|
const SnackBar(content: Text('Processing Data')), |
|
|
|
|
|
); |
|
|
|
|
|
|
|
|
|
|
|
signUp( |
|
|
|
|
|
context, |
|
|
|
|
|
usernameController.text, |
|
|
|
|
|
passwordController.text, |
|
|
|
|
|
passwordConfirmController.text |
|
|
|
|
|
).then((value) { |
|
|
|
|
|
Navigator.of(context).popUntil((route) => route.isFirst); |
|
|
|
|
|
}).catchError((error) { |
|
|
|
|
|
print(error); // TODO: Show error on interface |
|
|
|
|
|
}); |
|
|
|
|
|
} |
|
|
|
|
|
}, |
|
|
|
|
|
child: const Text('Submit'), |
|
|
|
|
|
), |
|
|
|
|
|
], |
|
|
|
|
|
) |
|
|
|
|
|
) |
|
|
|
|
|
|
|
|
child: Form( |
|
|
|
|
|
key: _formKey, |
|
|
|
|
|
child: Center( |
|
|
|
|
|
child: Padding( |
|
|
|
|
|
padding: const EdgeInsets.only( |
|
|
|
|
|
left: 20, |
|
|
|
|
|
right: 20, |
|
|
|
|
|
top: 0, |
|
|
|
|
|
bottom: 100, |
|
|
|
|
|
), |
|
|
|
|
|
child: Column( |
|
|
|
|
|
mainAxisAlignment: MainAxisAlignment.center, |
|
|
|
|
|
crossAxisAlignment: CrossAxisAlignment.center, |
|
|
|
|
|
children: [ |
|
|
|
|
|
Text( |
|
|
|
|
|
'Sign Up', |
|
|
|
|
|
style: TextStyle( |
|
|
|
|
|
fontSize: 35, |
|
|
|
|
|
color: Theme.of(context).colorScheme.onBackground, |
|
|
|
|
|
), |
|
|
|
|
|
), |
|
|
|
|
|
const SizedBox(height: 30), |
|
|
|
|
|
TextFormField( |
|
|
|
|
|
controller: _usernameController, |
|
|
|
|
|
decoration: InputDecoration( |
|
|
|
|
|
hintText: 'Username', |
|
|
|
|
|
enabledBorder: inputBorderStyle, |
|
|
|
|
|
focusedBorder: inputBorderStyle, |
|
|
|
|
|
), |
|
|
|
|
|
style: inputTextStyle, |
|
|
|
|
|
// The validator receives the text that the user has entered. |
|
|
|
|
|
validator: (value) { |
|
|
|
|
|
if (value == null || value.isEmpty) { |
|
|
|
|
|
return 'Create a username'; |
|
|
|
|
|
} |
|
|
|
|
|
return null; |
|
|
|
|
|
}, |
|
|
|
|
|
), |
|
|
|
|
|
const SizedBox(height: 10), |
|
|
|
|
|
TextFormField( |
|
|
|
|
|
controller: _passwordController, |
|
|
|
|
|
obscureText: true, |
|
|
|
|
|
enableSuggestions: false, |
|
|
|
|
|
autocorrect: false, |
|
|
|
|
|
decoration: InputDecoration( |
|
|
|
|
|
hintText: 'Password', |
|
|
|
|
|
enabledBorder: inputBorderStyle, |
|
|
|
|
|
focusedBorder: inputBorderStyle, |
|
|
|
|
|
), |
|
|
|
|
|
style: inputTextStyle, |
|
|
|
|
|
// The validator receives the text that the user has entered. |
|
|
|
|
|
validator: (value) { |
|
|
|
|
|
if (value == null || value.isEmpty) { |
|
|
|
|
|
return 'Enter a password'; |
|
|
|
|
|
} |
|
|
|
|
|
return null; |
|
|
|
|
|
}, |
|
|
|
|
|
), |
|
|
|
|
|
const SizedBox(height: 10), |
|
|
|
|
|
TextFormField( |
|
|
|
|
|
controller: _passwordConfirmController, |
|
|
|
|
|
obscureText: true, |
|
|
|
|
|
enableSuggestions: false, |
|
|
|
|
|
autocorrect: false, |
|
|
|
|
|
decoration: InputDecoration( |
|
|
|
|
|
hintText: 'Confirm Password', |
|
|
|
|
|
enabledBorder: inputBorderStyle, |
|
|
|
|
|
focusedBorder: inputBorderStyle, |
|
|
|
|
|
), |
|
|
|
|
|
style: inputTextStyle, |
|
|
|
|
|
// The validator receives the text that the user has entered. |
|
|
|
|
|
validator: (value) { |
|
|
|
|
|
if (value == null || value.isEmpty) { |
|
|
|
|
|
return 'Confirm your password'; |
|
|
|
|
|
} |
|
|
|
|
|
if (value != _passwordController.text) { |
|
|
|
|
|
return 'Passwords do not match'; |
|
|
|
|
|
} |
|
|
|
|
|
return null; |
|
|
|
|
|
}, |
|
|
|
|
|
), |
|
|
|
|
|
const SizedBox(height: 15), |
|
|
|
|
|
ElevatedButton( |
|
|
|
|
|
style: buttonStyle, |
|
|
|
|
|
onPressed: () { |
|
|
|
|
|
if (!_formKey.currentState!.validate()) { |
|
|
|
|
|
return; |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
ScaffoldMessenger.of(context).showSnackBar( |
|
|
|
|
|
const SnackBar(content: Text('Processing Data')), |
|
|
|
|
|
); |
|
|
|
|
|
|
|
|
|
|
|
signUp( |
|
|
|
|
|
context, |
|
|
|
|
|
_usernameController.text, |
|
|
|
|
|
_passwordController.text, |
|
|
|
|
|
_passwordConfirmController.text |
|
|
|
|
|
).then((value) { |
|
|
|
|
|
Navigator.of(context).popUntil((route) => route.isFirst); |
|
|
|
|
|
}).catchError((error) { |
|
|
|
|
|
print(error); // TODO: Show error on interface |
|
|
|
|
|
}); |
|
|
|
|
|
}, |
|
|
|
|
|
child: const Text('Submit'), |
|
|
|
|
|
), |
|
|
|
|
|
], |
|
|
|
|
|
) |
|
|
) |
|
|
) |
|
|
|
|
|
) |
|
|
) |
|
|
) |
|
|
); |
|
|
); |
|
|
} |
|
|
} |
|
|