TF-4370 Add Description field to Create new Label modal

This commit is contained in:
dab246
2026-03-11 14:41:02 +07:00
committed by Dat H. Pham
parent a8dca322d4
commit 4c837ed9cf
6 changed files with 97 additions and 4 deletions
@@ -26,6 +26,8 @@ class TextFieldBuilder extends StatefulWidget {
final bool autocorrect; final bool autocorrect;
final TextDirection textDirection; final TextDirection textDirection;
final bool readOnly; final bool readOnly;
final bool isFillContainer;
final TextAlignVertical? textAlignVertical;
final MouseCursor? mouseCursor; final MouseCursor? mouseCursor;
final String? semanticLabel; final String? semanticLabel;
@@ -36,6 +38,8 @@ class TextFieldBuilder extends StatefulWidget {
this.obscureText = false, this.obscureText = false,
this.autoFocus = false, this.autoFocus = false,
this.readOnly = false, this.readOnly = false,
this.isFillContainer = false,
this.textAlignVertical,
this.textStyle, this.textStyle,
this.textDirection = TextDirection.ltr, this.textDirection = TextDirection.ltr,
this.textInputAction, this.textInputAction,
@@ -89,6 +93,8 @@ class _TextFieldBuilderState extends State<TextFieldBuilder> {
decoration: widget.decoration, decoration: widget.decoration,
maxLines: widget.maxLines, maxLines: widget.maxLines,
minLines: widget.minLines, minLines: widget.minLines,
textAlignVertical: widget.textAlignVertical,
expands: widget.isFillContainer,
keyboardAppearance: widget.keyboardAppearance, keyboardAppearance: widget.keyboardAppearance,
style: widget.textStyle ?? ThemeUtils.defaultTextStyleInterFont.copyWith( style: widget.textStyle ?? ThemeUtils.defaultTextStyleInterFont.copyWith(
color: AppColor.textFieldTextColor, color: AppColor.textFieldTextColor,
@@ -11,7 +11,12 @@ class DefaultInputFieldWidget extends StatelessWidget {
final String? hintText; final String? hintText;
final String? errorText; final String? errorText;
final Color? inputColor; final Color? inputColor;
final bool hasMaxLines;
final bool isFillContainer;
final TextAlignVertical? textAlignVertical;
final double? maxHeight;
final FocusNode? focusNode; final FocusNode? focusNode;
final TextInputAction? inputAction;
final OnTextChange? onTextChange; final OnTextChange? onTextChange;
final OnTextSubmitted? onTextSubmitted; final OnTextSubmitted? onTextSubmitted;
@@ -22,6 +27,11 @@ class DefaultInputFieldWidget extends StatelessWidget {
this.errorText, this.errorText,
this.focusNode, this.focusNode,
this.inputColor, this.inputColor,
this.hasMaxLines = true,
this.isFillContainer = false,
this.textAlignVertical,
this.maxHeight,
this.inputAction,
this.onTextChange, this.onTextChange,
this.onTextSubmitted, this.onTextSubmitted,
}); });
@@ -30,17 +40,19 @@ class DefaultInputFieldWidget extends StatelessWidget {
Widget build(BuildContext context) { Widget build(BuildContext context) {
return TextFieldBuilder( return TextFieldBuilder(
controller: textEditingController, controller: textEditingController,
maxLines: 1, maxLines: hasMaxLines ? 1 : null,
textInputAction: TextInputAction.next, textInputAction: inputAction ?? TextInputAction.next,
textStyle: ThemeUtils.textStyleBodyBody3( textStyle: ThemeUtils.textStyleBodyBody3(
color: inputColor ?? AppColor.m3SurfaceBackground, color: inputColor ?? AppColor.m3SurfaceBackground,
), ),
isFillContainer: isFillContainer,
textAlignVertical: textAlignVertical,
focusNode: focusNode, focusNode: focusNode,
onTextSubmitted: onTextSubmitted, onTextSubmitted: onTextSubmitted,
onTextChange: onTextChange, onTextChange: onTextChange,
decoration: InputDecoration( decoration: InputDecoration(
constraints: BoxConstraints( constraints: BoxConstraints(
maxHeight: errorText?.isNotEmpty == true ? 60 : 40, maxHeight: maxHeight ?? (errorText?.isNotEmpty == true ? 60 : 40),
), ),
filled: true, filled: true,
fillColor: errorText?.isNotEmpty == true fillColor: errorText?.isNotEmpty == true
@@ -11,8 +11,13 @@ class LabelInputFieldBuilder extends StatelessWidget {
final FocusNode? focusNode; final FocusNode? focusNode;
final double? runSpacing; final double? runSpacing;
final double? inputFieldMaxWidth; final double? inputFieldMaxWidth;
final double? inputFieldHeight;
final bool arrangeHorizontally; final bool arrangeHorizontally;
final bool isLabelHasColon; final bool isLabelHasColon;
final bool hasMaxLines;
final bool isFillContainer;
final TextAlignVertical? textAlignVertical;
final TextInputAction? inputAction;
final OnTextChange? onTextChange; final OnTextChange? onTextChange;
const LabelInputFieldBuilder({ const LabelInputFieldBuilder({
@@ -21,12 +26,17 @@ class LabelInputFieldBuilder extends StatelessWidget {
required this.textEditingController, required this.textEditingController,
this.arrangeHorizontally = true, this.arrangeHorizontally = true,
this.isLabelHasColon = true, this.isLabelHasColon = true,
this.hasMaxLines = true,
this.isFillContainer = false,
this.textAlignVertical,
this.hintText, this.hintText,
this.errorText, this.errorText,
this.focusNode, this.focusNode,
this.labelStyle, this.labelStyle,
this.runSpacing, this.runSpacing,
this.inputFieldMaxWidth, this.inputFieldMaxWidth,
this.inputFieldHeight,
this.inputAction,
this.onTextChange, this.onTextChange,
}); });
@@ -39,6 +49,11 @@ class LabelInputFieldBuilder extends StatelessWidget {
hintText: hintText, hintText: hintText,
errorText: errorText, errorText: errorText,
focusNode: focusNode, focusNode: focusNode,
hasMaxLines: hasMaxLines,
textAlignVertical: textAlignVertical,
isFillContainer: isFillContainer,
inputAction: inputAction,
maxHeight: inputFieldHeight,
onTextChange: onTextChange, onTextChange: onTextChange,
), ),
); );
@@ -55,6 +55,9 @@ class _CreateNewLabelModalState extends State<CreateNewLabelModal> {
final ValueNotifier<bool> _createLabelStateNotifier = ValueNotifier(false); final ValueNotifier<bool> _createLabelStateNotifier = ValueNotifier(false);
final TextEditingController _nameInputController = TextEditingController(); final TextEditingController _nameInputController = TextEditingController();
final FocusNode _nameInputFocusNode = FocusNode(); final FocusNode _nameInputFocusNode = FocusNode();
final TextEditingController _descriptionInputController =
TextEditingController();
final FocusNode _descriptionInputFocusNode = FocusNode();
List<String> _labelDisplayNameList = <String>[]; List<String> _labelDisplayNameList = <String>[];
Color? _selectedColor; Color? _selectedColor;
@@ -135,6 +138,12 @@ class _CreateNewLabelModalState extends State<CreateNewLabelModal> {
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,
children: [ children: [
_buildLabelNameInputField(appLocalizations), _buildLabelNameInputField(appLocalizations),
Padding(
padding: const EdgeInsets.only(top: 16),
child: _buildLabelDescriptionInputField(
appLocalizations,
),
),
Padding( Padding(
padding: const EdgeInsets.only(top: 26, bottom: 16), padding: const EdgeInsets.only(top: 26, bottom: 16),
child: Text( child: Text(
@@ -297,6 +306,29 @@ class _CreateNewLabelModalState extends State<CreateNewLabelModal> {
); );
} }
Widget _buildLabelDescriptionInputField(AppLocalizations appLocalizations) {
return LabelInputFieldBuilder(
label: appLocalizations.labelDescription,
hintText: appLocalizations.labelDescriptionHintText,
textEditingController: _descriptionInputController,
focusNode: _descriptionInputFocusNode,
arrangeHorizontally: false,
isLabelHasColon: false,
hasMaxLines: false,
isFillContainer: true,
labelStyle: ThemeUtils.textStyleInter600().copyWith(
fontSize: 14,
height: 18 / 14,
color: Colors.black,
),
runSpacing: 16,
inputFieldMaxWidth: double.infinity,
inputFieldHeight: 84,
textAlignVertical: TextAlignVertical.top,
inputAction: TextInputAction.newline,
);
}
void _onLabelNameInputChanged( void _onLabelNameInputChanged(
AppLocalizations appLocalizations, AppLocalizations appLocalizations,
String value, String value,
@@ -376,6 +408,8 @@ class _CreateNewLabelModalState extends State<CreateNewLabelModal> {
void dispose() { void dispose() {
_nameInputFocusNode.dispose(); _nameInputFocusNode.dispose();
_nameInputController.dispose(); _nameInputController.dispose();
_descriptionInputFocusNode.dispose();
_descriptionInputController.dispose();
_labelNameErrorTextNotifier.dispose(); _labelNameErrorTextNotifier.dispose();
_labelSelectedColorNotifier.dispose(); _labelSelectedColorNotifier.dispose();
_createLabelStateNotifier.dispose(); _createLabelStateNotifier.dispose();
+13 -1
View File
@@ -1,5 +1,5 @@
{ {
"@@last_modified": "2026-03-04T11:35:04.572137", "@@last_modified": "2026-03-11T14:39:59.601630",
"initializing_data": "Initializing data...", "initializing_data": "Initializing data...",
"@initializing_data": { "@initializing_data": {
"type": "text", "type": "text",
@@ -5447,5 +5447,17 @@
"type": "text", "type": "text",
"placeholders_order": [], "placeholders_order": [],
"placeholders": {} "placeholders": {}
},
"labelDescription": "Description (optional)",
"@labelDescription": {
"type": "text",
"placeholders_order": [],
"placeholders": {}
},
"labelDescriptionHintText": "Add a short description to explain what this label is for",
"@labelDescriptionHintText": {
"type": "text",
"placeholders_order": [],
"placeholders": {}
} }
} }
@@ -5762,4 +5762,18 @@ class AppLocalizations {
name: 'deleteALabelFailure', name: 'deleteALabelFailure',
); );
} }
String get labelDescription {
return Intl.message(
'Description (optional)',
name: 'labelDescription',
);
}
String get labelDescriptionHintText {
return Intl.message(
'Add a short description to explain what this label is for',
name: 'labelDescriptionHintText',
);
}
} }