rluv_client/lib/features/account/login.dart

225 lines
7.5 KiB
Dart

import 'package:colorful_print/colorful_print.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 = true;
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, at least 6 characters (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 Map<String, dynamic>? 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,
});
bool success = data?['success'] ?? false;
String message = data?['message'] ?? (success ? 'Login success!' : 'Login unsuccessful.');
printColor(data, textColor: TextColor.yellow);
showSnack(ref: ref, text: message, type: success ? SnackType.success : SnackType.error);
} catch (err, st) {
printColor('Error in login: $err\n$st', textColor: TextColor.red);
}
}
}