Enhance SubspaceNameDisplayWidget to handle duplicate names during editing. Introduced logic to check for existing subspace names and provide user feedback. Refactored state management for editing and submission processes, improving overall user experience and code clarity.

This commit is contained in:
Faris Armoush
2025-07-03 12:04:03 +03:00
parent c221c8499f
commit d47dc349bc

View File

@ -18,7 +18,9 @@ class SubspaceNameDisplayWidget extends StatefulWidget {
class _SubspaceNameDisplayWidgetState extends State<SubspaceNameDisplayWidget> {
late final TextEditingController _controller;
late final FocusNode _focusNode;
bool isEditing = false;
bool _isEditing = false;
bool _hasDuplicateName = false;
@override
void initState() {
_controller = TextEditingController(text: widget.subSpace.name);
@ -33,6 +35,41 @@ class _SubspaceNameDisplayWidgetState extends State<SubspaceNameDisplayWidget> {
super.dispose();
}
bool _checkForDuplicateName(String name) {
final bloc = context.read<SpaceDetailsModelBloc>();
return bloc.state.subspaces
.where((s) => s.uuid != widget.subSpace.uuid)
.any((s) => s.name.toLowerCase() == name.toLowerCase());
}
void _handleNameChange(String value) {
setState(() {
_hasDuplicateName = _checkForDuplicateName(value);
});
}
void _tryToFinishEditing() {
if (!_hasDuplicateName) {
_onFinishEditing();
}
}
void _tryToSubmit(String value) {
if (_hasDuplicateName) return;
final bloc = context.read<SpaceDetailsModelBloc>();
bloc.add(
UpdateSpaceDetailsSubspaces(
bloc.state.subspaces
.map(
(e) => e.uuid == widget.subSpace.uuid ? e.copyWith(name: value) : e,
)
.toList(),
),
);
_onFinishEditing();
}
@override
Widget build(BuildContext context) {
final textStyle = context.textTheme.bodySmall?.copyWith(
@ -40,7 +77,7 @@ class _SubspaceNameDisplayWidgetState extends State<SubspaceNameDisplayWidget> {
);
return InkWell(
onTap: () {
setState(() => isEditing = true);
setState(() => _isEditing = true);
_focusNode.requestFocus();
},
child: Chip(
@ -49,36 +86,48 @@ class _SubspaceNameDisplayWidgetState extends State<SubspaceNameDisplayWidget> {
borderRadius: BorderRadius.circular(10),
),
label: Visibility(
visible: isEditing,
visible: _isEditing,
replacement: Text(
widget.subSpace.name,
style: textStyle,
),
child: SizedBox(
width: context.screenWidth * 0.065,
height: context.screenHeight * 0.025,
child: TextField(
focusNode: _focusNode,
controller: _controller,
style: textStyle,
decoration: const InputDecoration.collapsed(hintText: ''),
onTapOutside: (_) => _onFinishEditing(),
onSubmitted: (value) {
final bloc = context.read<SpaceDetailsModelBloc>();
bloc.add(
UpdateSpaceDetailsSubspaces(
bloc.state.subspaces
.map(
(e) => e.uuid == widget.subSpace.uuid
? e.copyWith(name: value)
: e,
)
.toList(),
child: Column(
mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
SizedBox(
width: context.screenWidth * 0.065,
height: context.screenHeight * 0.025,
child: TextField(
focusNode: _focusNode,
controller: _controller,
style: textStyle?.copyWith(
color: _hasDuplicateName ? Colors.red : null,
),
);
_onFinishEditing();
},
),
decoration: const InputDecoration.collapsed(
hintText: '',
),
onChanged: _handleNameChange,
onTapOutside: (_) => _tryToFinishEditing(),
onSubmitted: _tryToSubmit,
),
),
if (_hasDuplicateName)
AnimatedSwitcher(
duration: const Duration(milliseconds: 250),
child: Visibility(
key: ValueKey(_hasDuplicateName),
visible: _hasDuplicateName,
child: Text(
'Name already exists',
style: textStyle?.copyWith(
color: Colors.red,
fontSize: 8,
),
),
),
),
],
),
),
),
@ -86,7 +135,10 @@ class _SubspaceNameDisplayWidgetState extends State<SubspaceNameDisplayWidget> {
}
void _onFinishEditing() {
setState(() => isEditing = false);
setState(() {
_isEditing = false;
_hasDuplicateName = false;
});
_focusNode.unfocus();
}
}