179 lines
4.7 KiB
Dart
179 lines
4.7 KiB
Dart
import 'package:flutter/material.dart';
|
|
|
|
import 'package:together_mobile/common/constants.dart';
|
|
|
|
class SignTextField extends StatefulWidget {
|
|
const SignTextField({
|
|
super.key,
|
|
this.color = kPrimaryColor,
|
|
this.obscureText = false,
|
|
required this.type,
|
|
required this.labelText,
|
|
required this.controller,
|
|
required this.isError,
|
|
});
|
|
|
|
final Color color;
|
|
final bool obscureText;
|
|
final String type;
|
|
final String labelText;
|
|
final TextEditingController controller;
|
|
final void Function(String, bool) isError;
|
|
|
|
@override
|
|
State<SignTextField> createState() => _SignTextFieldState();
|
|
}
|
|
|
|
class _SignTextFieldState extends State<SignTextField> {
|
|
int _length = 0;
|
|
String? _errorText;
|
|
|
|
@override
|
|
Widget build(BuildContext context) {
|
|
return TextField(
|
|
onChanged: (String newValue) {
|
|
setState(() {
|
|
_length = newValue.characters.length;
|
|
});
|
|
setErrorText();
|
|
widget.isError(
|
|
widget.type,
|
|
(_errorText == null && widget.controller.text.isEmpty) ||
|
|
_errorText != null);
|
|
},
|
|
controller: widget.controller,
|
|
obscureText: widget.obscureText,
|
|
cursorColor: widget.color,
|
|
textAlignVertical: TextAlignVertical.bottom,
|
|
keyboardType: initTextInputType(),
|
|
decoration: InputDecoration(
|
|
errorText: _errorText,
|
|
labelText: widget.labelText,
|
|
counterText: '$_length 字符',
|
|
floatingLabelStyle: TextStyle(color: widget.color),
|
|
focusedBorder: UnderlineInputBorder(
|
|
borderSide: BorderSide(color: widget.color),
|
|
),
|
|
),
|
|
);
|
|
}
|
|
|
|
TextInputType initTextInputType() {
|
|
switch (widget.type) {
|
|
case 'email':
|
|
return TextInputType.emailAddress;
|
|
case 'code':
|
|
return TextInputType.number;
|
|
case _:
|
|
return TextInputType.visiblePassword;
|
|
}
|
|
}
|
|
|
|
void setErrorText() {
|
|
if (widget.controller.text.isEmpty) {
|
|
setState(() {
|
|
_errorText = null;
|
|
});
|
|
}
|
|
|
|
switch (widget.type) {
|
|
case 'username':
|
|
if (widget.controller.text.contains(RegExp(r'\W+'))) {
|
|
setState(() {
|
|
_errorText = '用户名只允许字母, 数字和下划线';
|
|
});
|
|
} else if (_length < 5 || _length > 20) {
|
|
setState(() {
|
|
_errorText = '用户名需为8-20个字符';
|
|
});
|
|
} else {
|
|
setState(() {
|
|
_errorText = null;
|
|
});
|
|
}
|
|
break;
|
|
|
|
case 'password' || 'password1' || 'password2':
|
|
if (widget.controller.text.contains(RegExp(r'\s'))) {
|
|
setState(() {
|
|
_errorText = '密码不能包含空格';
|
|
});
|
|
} else if (_length < 8 || _length > 30) {
|
|
setState(() {
|
|
_errorText = '密码需为8-30个字符';
|
|
});
|
|
} else {
|
|
setState(() {
|
|
_errorText = null;
|
|
});
|
|
}
|
|
break;
|
|
|
|
case 'email':
|
|
var exp = RegExp(
|
|
r'^[a-zA-Z0-9_.-]+@[a-zA-Z0-9-]+(\.[a-zA-Z0-9-]+)*\.[a-zA-Z0-9]{2,6}$');
|
|
if (!exp.hasMatch(widget.controller.text)) {
|
|
setState(() {
|
|
_errorText = '邮箱格式错误';
|
|
});
|
|
} else {
|
|
setState(() {
|
|
_errorText = null;
|
|
});
|
|
}
|
|
|
|
case 'code':
|
|
if (!RegExp(r'\d{6}').hasMatch(widget.controller.text)) {
|
|
setState(() {
|
|
_errorText = '6为数字';
|
|
});
|
|
} else if (widget.controller.text.characters.length != 6) {
|
|
_errorText = '6位数字';
|
|
} else {
|
|
setState(() {
|
|
_errorText = null;
|
|
});
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
TextField textField({
|
|
Color color = kPrimaryColor,
|
|
bool obscureText = false,
|
|
required String labelText,
|
|
required TextEditingController controller,
|
|
}) {
|
|
return TextField(
|
|
controller: controller,
|
|
obscureText: obscureText,
|
|
cursorColor: kSecondaryColor,
|
|
textAlignVertical: TextAlignVertical.bottom,
|
|
decoration: InputDecoration(
|
|
helperText: '5-10位',
|
|
errorText: 'xxx',
|
|
labelText: labelText,
|
|
floatingLabelStyle: const TextStyle(color: kSecondaryColor),
|
|
focusedBorder:
|
|
UnderlineInputBorder(borderSide: BorderSide(color: color))),
|
|
);
|
|
}
|
|
|
|
ElevatedButton elevatedButton(
|
|
{required VoidCallback onPressed,
|
|
required String text,
|
|
Color? color = kPrimaryColor}) {
|
|
return ElevatedButton(
|
|
onPressed: onPressed,
|
|
style: ElevatedButton.styleFrom(
|
|
backgroundColor: color,
|
|
elevation: 0,
|
|
fixedSize: const Size(150, 20),
|
|
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(12))),
|
|
child: Text(
|
|
text,
|
|
style: const TextStyle(fontSize: 20.0, letterSpacing: 10),
|
|
),
|
|
);
|
|
}
|