232 lines
7.5 KiB
Dart
232 lines
7.5 KiB
Dart
import 'package:flutter/material.dart';
|
|
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
|
|
|
import '../../global/api.dart';
|
|
import '../../global/styles.dart';
|
|
import '../../global/utils.dart';
|
|
import '../../global/widgets/ui_button.dart';
|
|
|
|
class Login extends ConsumerStatefulWidget {
|
|
const Login({super.key, required this.formKey, required this.exitNav});
|
|
|
|
final GlobalKey<FormState> formKey;
|
|
final Widget exitNav;
|
|
|
|
@override
|
|
ConsumerState<Login> createState() => _LoginState();
|
|
}
|
|
|
|
class _LoginState extends ConsumerState<Login> {
|
|
bool usingUsername = false;
|
|
final emailController = TextEditingController();
|
|
final usernameController = TextEditingController();
|
|
final passwordController = TextEditingController();
|
|
|
|
final focusNodes = [
|
|
FocusNode(),
|
|
FocusNode(),
|
|
FocusNode(),
|
|
];
|
|
|
|
@override
|
|
Widget build(BuildContext context) {
|
|
final screen = MediaQuery.of(context).size;
|
|
return Form(
|
|
key: widget.formKey,
|
|
child: Stack(
|
|
children: [
|
|
Column(
|
|
children: [
|
|
const Spacer(),
|
|
const Text(
|
|
'Login',
|
|
style: TextStyle(fontSize: 24),
|
|
),
|
|
const Spacer(flex: 2),
|
|
Row(
|
|
mainAxisAlignment: MainAxisAlignment.center,
|
|
children: [
|
|
Column(
|
|
children: [
|
|
const Padding(
|
|
padding: EdgeInsets.all(2.0),
|
|
child: Text(
|
|
'Username',
|
|
style: TextStyle(
|
|
fontSize: 16,
|
|
),
|
|
),
|
|
),
|
|
Checkbox(
|
|
activeColor: Styles.lavender,
|
|
onChanged: (bool? value) {
|
|
setState(() => usingUsername = true);
|
|
},
|
|
value: usingUsername,
|
|
),
|
|
],
|
|
),
|
|
const SizedBox(
|
|
width: 35,
|
|
),
|
|
Column(
|
|
children: [
|
|
const Padding(
|
|
padding: EdgeInsets.all(2.0),
|
|
child: Text(
|
|
'Email',
|
|
style: TextStyle(
|
|
fontSize: 16,
|
|
),
|
|
),
|
|
),
|
|
Checkbox(
|
|
activeColor: Styles.lavender,
|
|
onChanged: (bool? value) {
|
|
setState(() => usingUsername = false);
|
|
},
|
|
value: !usingUsername,
|
|
),
|
|
],
|
|
),
|
|
],
|
|
),
|
|
AnimatedSwitcher(
|
|
duration: const Duration(milliseconds: 200),
|
|
child: !usingUsername
|
|
? generateTextField(
|
|
controller: emailController,
|
|
size: screen,
|
|
text: 'Email: ',
|
|
validatorFunc: (s) {
|
|
if (s != null && s.isNotEmpty && !isEmailValid(s)) {
|
|
return 'Email entered is invalid';
|
|
}
|
|
return null;
|
|
},
|
|
index: 0)
|
|
: generateTextField(
|
|
controller: usernameController,
|
|
size: screen,
|
|
text: 'Username: ',
|
|
validatorFunc: (s) {
|
|
if (s == null || s.isEmpty) {
|
|
return 'Invalid Username';
|
|
}
|
|
if (s.length < 3) {
|
|
return 'Username Not 3 Letters Long';
|
|
}
|
|
if (s.length > 20) {
|
|
return 'Username Too Long';
|
|
}
|
|
if (!isUsernameValid(s)) {
|
|
return 'Letters, Numbers, and ., -, _ Allowed';
|
|
}
|
|
return null;
|
|
},
|
|
index: 0),
|
|
),
|
|
generateTextField(
|
|
controller: passwordController,
|
|
size: screen,
|
|
text: 'Password: ',
|
|
validatorFunc: (s) {
|
|
if (s != null && s.length < 6) {
|
|
return 'Please do a better password (you have to)';
|
|
}
|
|
return null;
|
|
},
|
|
index: 1,
|
|
isPassword: true),
|
|
const Spacer(flex: 2),
|
|
UiButton(
|
|
width: screen.width * 0.85 > 400 ? 400 : screen.width * 0.85,
|
|
showLoading: true,
|
|
onPressed: () => login(),
|
|
text: 'Submit',
|
|
color: Styles.seaweedGreen,
|
|
),
|
|
const Spacer(),
|
|
],
|
|
),
|
|
widget.exitNav,
|
|
],
|
|
),
|
|
);
|
|
}
|
|
|
|
Widget generateTextField({
|
|
required String text,
|
|
String? label,
|
|
required int index,
|
|
required TextEditingController controller,
|
|
isPassword = false,
|
|
required Size size,
|
|
required String? Function(String?) validatorFunc,
|
|
}) {
|
|
return Padding(
|
|
padding: const EdgeInsets.all(8.0),
|
|
child: Row(
|
|
children: [
|
|
Padding(
|
|
padding: const EdgeInsets.all(8.0),
|
|
child: Text(
|
|
text,
|
|
style: TextStyle(fontSize: size.width < 350 ? 16 : 20),
|
|
),
|
|
),
|
|
const Spacer(),
|
|
Container(
|
|
decoration: Styles.boxLavenderBubble,
|
|
width: size.width * 0.5 > 300 ? 300 : size.width * 0.5,
|
|
child: TextFormField(
|
|
validator: validatorFunc,
|
|
controller: controller,
|
|
decoration: Styles.inputLavenderBubble(labelText: label),
|
|
obscureText: isPassword,
|
|
focusNode: focusNodes[index],
|
|
style: const TextStyle(fontSize: 16),
|
|
onFieldSubmitted: (_) {
|
|
if (index != focusNodes.length - 1) {
|
|
focusNodes[index + 1].requestFocus();
|
|
}
|
|
},
|
|
),
|
|
),
|
|
SizedBox(
|
|
width: size.width * 0.05,
|
|
),
|
|
],
|
|
),
|
|
);
|
|
}
|
|
|
|
Future login() async {
|
|
try {
|
|
if (widget.formKey.currentState != null && !widget.formKey.currentState!.validate()) {
|
|
return;
|
|
}
|
|
final data = await ref.read(apiProvider.notifier).post(path: 'auth/login', data: {
|
|
'username': usernameController.text.isEmpty ? null : usernameController.text,
|
|
'email': emailController.text.isEmpty ? null : emailController.text,
|
|
'password': passwordController.text,
|
|
});
|
|
|
|
String message = 'Login unsuccessful';
|
|
bool success = data?['success'] == 'false';
|
|
if (data != null) {
|
|
if (data['message'] != null) {
|
|
message = data['message'];
|
|
} else if (success) {
|
|
message = 'Logged in!';
|
|
}
|
|
}
|
|
// final bool success = data?['success'] ?? false;
|
|
print(data);
|
|
showSnack(ref: ref, text: message, type: !success ? SnackType.error : SnackType.success);
|
|
} catch (err, st) {
|
|
print('Error in login: $err\n$st');
|
|
}
|
|
}
|
|
}
|