refactor(group): 优化群昵称修改流程的用户体验

This commit is contained in:
Zeew 2025-08-11 15:21:17 +08:00
parent d4ffbf2165
commit 498bdb7f5d
1 changed files with 270 additions and 26 deletions

View File

@ -22,6 +22,8 @@ class GroupProfileNameCard extends StatefulWidget {
class GroupProfileNameCardState extends TIMUIKitState<GroupProfileNameCard>{
final TextEditingController controller = TextEditingController();
String? nameCard;
String? validationMessage;
bool isValid = true;
@override
Widget tuiBuild(BuildContext context, TUIKitBuildValue value) {
@ -35,6 +37,11 @@ class GroupProfileNameCardState extends TIMUIKitState<GroupProfileNameCard>{
nameCard = model.getSelfNameCard();
controller.text = nameCard ?? "";
//
if (nameCard != null && nameCard!.isNotEmpty) {
_validateNameCardRealTime(nameCard!);
}
return Container(
padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 12),
decoration: BoxDecoration(
@ -46,26 +53,7 @@ class GroupProfileNameCardState extends TIMUIKitState<GroupProfileNameCard>{
child: GestureDetector(
onTap: () async {
if (!isDesktopScreen) {
TextInputBottomSheet.showTextInputBottomSheet(
context: context,
title: TIM_t("修改我的群昵称"),
tips: TIM_t("仅限中文、字母、数字和下划线2-20个字"),
onSubmitted: (String nameCard) async {
final text = nameCard.trim();
//
if (_validateNameCard(text)) {
model.setNameCard(text);
} else {
//
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(
content: Text(TIM_t("仅限中文、字母、数字和下划线2-20个字")),
backgroundColor: Colors.red,
),
);
}
},
theme: theme);
_showNameCardInputBottomSheet(context, theme, model);
}
},
child: Column(
@ -103,8 +91,11 @@ class GroupProfileNameCardState extends TIMUIKitState<GroupProfileNameCard>{
),
if (isDesktopScreen)
Text(
TIM_t("仅限中文、字母、数字和下划线2-20个字"),
style: TextStyle(color: theme.weakTextColor, fontSize: 12),
validationMessage ?? TIM_t("仅限中文、字母、数字和下划线2-16个字"),
style: TextStyle(
color: isValid ? theme.weakTextColor : Colors.red,
fontSize: 12
),
),
if (isDesktopScreen)
Container(
@ -114,6 +105,12 @@ class GroupProfileNameCardState extends TIMUIKitState<GroupProfileNameCard>{
minLines: 1,
controller: controller,
maxLines: 1,
onChanged: (text) {
final trimmedText = text.trim();
setState(() {
_validateNameCardRealTime(trimmedText);
});
},
onSubmitted: (text) {
final trimmedText = text.trim();
//
@ -123,7 +120,7 @@ class GroupProfileNameCardState extends TIMUIKitState<GroupProfileNameCard>{
//
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(
content: Text(TIM_t("仅限中文、字母、数字和下划线2-20个字")),
content: Text(TIM_t("仅限中文、字母、数字和下划线2-16个字")),
backgroundColor: Colors.red,
),
);
@ -167,14 +164,14 @@ class GroupProfileNameCardState extends TIMUIKitState<GroupProfileNameCard>{
}
///
/// 线2-20
/// 线2-16
bool _validateNameCard(String text) {
if (text.isEmpty) {
return false;
}
// 2-20
if (text.length < 2 || text.length > 20) {
// 2-16
if (text.length < 2 || text.length > 16) {
return false;
}
@ -182,4 +179,251 @@ class GroupProfileNameCardState extends TIMUIKitState<GroupProfileNameCard>{
final RegExp regex = RegExp(r'^[\u4e00-\u9fa5a-zA-Z0-9_]+$');
return regex.hasMatch(text);
}
///
void _validateNameCardRealTime(String text) {
if (text.isEmpty) {
isValid = false;
validationMessage = TIM_t("昵称不能为空");
return;
}
if (text.length < 2) {
isValid = false;
validationMessage = TIM_t("昵称至少需要2个字符");
return;
}
if (text.length > 16) {
isValid = false;
validationMessage = TIM_t("昵称不能超过16个字符");
return;
}
// 线
final RegExp regex = RegExp(r'^[\u4e00-\u9fa5a-zA-Z0-9_]+$');
if (!regex.hasMatch(text)) {
isValid = false;
validationMessage = TIM_t("仅限中文、字母、数字和下划线");
return;
}
//
isValid = true;
validationMessage = TIM_t("昵称格式正确");
}
///
void _showNameCardInputBottomSheet(BuildContext context, TUITheme theme, model) {
TextEditingController modalController = TextEditingController();
modalController.text = nameCard ?? "";
showModalBottomSheet(
isScrollControlled: true,
context: context,
builder: (BuildContext context) {
return _NameCardInputWidget(
controller: modalController,
theme: theme,
model: model,
initialNameCard: nameCard,
);
},
);
}
}
class _NameCardInputWidget extends StatefulWidget {
final TextEditingController controller;
final TUITheme theme;
final model;
final String? initialNameCard;
const _NameCardInputWidget({
required this.controller,
required this.theme,
required this.model,
this.initialNameCard,
});
@override
_NameCardInputWidgetState createState() => _NameCardInputWidgetState();
}
class _NameCardInputWidgetState extends State<_NameCardInputWidget> {
String? modalValidationMessage;
bool modalIsValid = true;
@override
void initState() {
super.initState();
//
if (widget.initialNameCard != null && widget.initialNameCard!.isNotEmpty) {
_validateModalInput(widget.initialNameCard!);
}
}
void _validateModalInput(String text) {
setState(() {
if (text.isEmpty) {
modalIsValid = false;
modalValidationMessage = TIM_t("昵称不能为空");
} else if (text.length < 2) {
modalIsValid = false;
modalValidationMessage = TIM_t("昵称至少需要2个字符");
} else if (text.length > 16) {
modalIsValid = false;
modalValidationMessage = TIM_t("昵称不能超过16个字符");
} else {
final RegExp regex = RegExp(r'^[\u4e00-\u9fa5a-zA-Z0-9_]+$');
if (!regex.hasMatch(text)) {
modalIsValid = false;
modalValidationMessage = TIM_t("仅限中文、字母、数字和下划线");
} else {
modalIsValid = true;
modalValidationMessage = TIM_t("昵称格式正确");
}
}
});
}
bool _validateNameCard(String text) {
if (text.isEmpty) {
return false;
}
// 2-16
if (text.length < 2 || text.length > 16) {
return false;
}
// 线
final RegExp regex = RegExp(r'^[\u4e00-\u9fa5a-zA-Z0-9_]+$');
return regex.hasMatch(text);
}
@override
Widget build(BuildContext context) {
return SingleChildScrollView(
child: Container(
padding: EdgeInsets.only(
top: 16,
left: 16,
right: 16,
bottom: MediaQuery.of(context).viewInsets.bottom + 30,
),
child: Column(
mainAxisAlignment: MainAxisAlignment.start,
children: [
Padding(
padding: const EdgeInsets.only(bottom: 16),
child: Text(
TIM_t("修改我的群昵称"),
style: const TextStyle(fontWeight: FontWeight.w500, fontSize: 16),
),
),
Divider(height: 2, color: widget.theme.weakDividerColor),
TextField(
controller: widget.controller,
autofocus: true,
onChanged: (text) {
final trimmedText = text.trim();
_validateModalInput(trimmedText);
},
onSubmitted: (text) {
final trimmedText = text.trim();
if (_validateNameCard(trimmedText)) {
widget.model.setNameCard(trimmedText);
Navigator.pop(context);
} else {
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(
content: Text(TIM_t("仅限中文、字母、数字和下划线2-16个字")),
backgroundColor: Colors.red,
),
);
}
},
),
Row(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Container(
padding: const EdgeInsets.symmetric(vertical: 5),
height: 40,
child: Text(
modalValidationMessage ?? TIM_t("仅限中文、字母、数字和下划线2-16个字"),
style: TextStyle(
color: modalIsValid ? Colors.grey : Colors.red,
fontSize: 12,
),
),
),
],
),
Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Expanded(
child: Container(
margin: const EdgeInsets.only(right: 10),
child: ElevatedButton(
style: ButtonStyle(
backgroundColor: MaterialStateProperty.all(widget.theme.wideBackgroundColor),
shape: MaterialStateProperty.all(
RoundedRectangleBorder(borderRadius: BorderRadius.circular(5)),
),
),
onPressed: () {
Navigator.pop(context);
},
child: Text(
TIM_t("取消"),
style: TextStyle(color: widget.theme.darkTextColor),
),
),
),
),
Expanded(
child: ElevatedButton(
style: ButtonStyle(
shape: MaterialStateProperty.all(
RoundedRectangleBorder(borderRadius: BorderRadius.circular(5)),
),
),
onPressed: () {
final text = widget.controller.text.trim();
if (_validateNameCard(text)) {
widget.model.setNameCard(text);
Navigator.pop(context);
} else {
showDialog(
context: context,
builder: (BuildContext context) {
return AlertDialog(
title: Text(TIM_t("输入错误")),
content: Text(TIM_t("仅限中文、字母、数字和下划线2-16个字")),
actions: [
TextButton(
onPressed: () {
Navigator.of(context).pop();
},
child: Text(TIM_t("确定")),
),
],
);
},
);
}
},
child: Text(TIM_t("确定")),
),
),
],
),
],
),
),
);
}
}