From 4c837ed9cf607b4874011d77d11bd30deaeda216 Mon Sep 17 00:00:00 2001 From: dab246 Date: Wed, 11 Mar 2026 14:41:02 +0700 Subject: [PATCH] TF-4370 Add `Description` field to Create new Label modal --- .../views/text/text_field_builder.dart | 6 ++++ .../default_input_field_widget.dart | 18 ++++++++-- .../widget/label_input_field_builder.dart | 15 ++++++++ .../widgets/create_new_label_modal.dart | 34 +++++++++++++++++++ lib/l10n/intl_messages.arb | 14 +++++++- lib/main/localizations/app_localizations.dart | 14 ++++++++ 6 files changed, 97 insertions(+), 4 deletions(-) diff --git a/core/lib/presentation/views/text/text_field_builder.dart b/core/lib/presentation/views/text/text_field_builder.dart index ce2b8e038..b39cae824 100644 --- a/core/lib/presentation/views/text/text_field_builder.dart +++ b/core/lib/presentation/views/text/text_field_builder.dart @@ -26,6 +26,8 @@ class TextFieldBuilder extends StatefulWidget { final bool autocorrect; final TextDirection textDirection; final bool readOnly; + final bool isFillContainer; + final TextAlignVertical? textAlignVertical; final MouseCursor? mouseCursor; final String? semanticLabel; @@ -36,6 +38,8 @@ class TextFieldBuilder extends StatefulWidget { this.obscureText = false, this.autoFocus = false, this.readOnly = false, + this.isFillContainer = false, + this.textAlignVertical, this.textStyle, this.textDirection = TextDirection.ltr, this.textInputAction, @@ -89,6 +93,8 @@ class _TextFieldBuilderState extends State { decoration: widget.decoration, maxLines: widget.maxLines, minLines: widget.minLines, + textAlignVertical: widget.textAlignVertical, + expands: widget.isFillContainer, keyboardAppearance: widget.keyboardAppearance, style: widget.textStyle ?? ThemeUtils.defaultTextStyleInterFont.copyWith( color: AppColor.textFieldTextColor, diff --git a/lib/features/base/widget/default_field/default_input_field_widget.dart b/lib/features/base/widget/default_field/default_input_field_widget.dart index c68ce28bf..d083f504a 100644 --- a/lib/features/base/widget/default_field/default_input_field_widget.dart +++ b/lib/features/base/widget/default_field/default_input_field_widget.dart @@ -11,7 +11,12 @@ class DefaultInputFieldWidget extends StatelessWidget { final String? hintText; final String? errorText; final Color? inputColor; + final bool hasMaxLines; + final bool isFillContainer; + final TextAlignVertical? textAlignVertical; + final double? maxHeight; final FocusNode? focusNode; + final TextInputAction? inputAction; final OnTextChange? onTextChange; final OnTextSubmitted? onTextSubmitted; @@ -22,6 +27,11 @@ class DefaultInputFieldWidget extends StatelessWidget { this.errorText, this.focusNode, this.inputColor, + this.hasMaxLines = true, + this.isFillContainer = false, + this.textAlignVertical, + this.maxHeight, + this.inputAction, this.onTextChange, this.onTextSubmitted, }); @@ -30,17 +40,19 @@ class DefaultInputFieldWidget extends StatelessWidget { Widget build(BuildContext context) { return TextFieldBuilder( controller: textEditingController, - maxLines: 1, - textInputAction: TextInputAction.next, + maxLines: hasMaxLines ? 1 : null, + textInputAction: inputAction ?? TextInputAction.next, textStyle: ThemeUtils.textStyleBodyBody3( color: inputColor ?? AppColor.m3SurfaceBackground, ), + isFillContainer: isFillContainer, + textAlignVertical: textAlignVertical, focusNode: focusNode, onTextSubmitted: onTextSubmitted, onTextChange: onTextChange, decoration: InputDecoration( constraints: BoxConstraints( - maxHeight: errorText?.isNotEmpty == true ? 60 : 40, + maxHeight: maxHeight ?? (errorText?.isNotEmpty == true ? 60 : 40), ), filled: true, fillColor: errorText?.isNotEmpty == true diff --git a/lib/features/base/widget/label_input_field_builder.dart b/lib/features/base/widget/label_input_field_builder.dart index 26ab69405..9b937e5c2 100644 --- a/lib/features/base/widget/label_input_field_builder.dart +++ b/lib/features/base/widget/label_input_field_builder.dart @@ -11,8 +11,13 @@ class LabelInputFieldBuilder extends StatelessWidget { final FocusNode? focusNode; final double? runSpacing; final double? inputFieldMaxWidth; + final double? inputFieldHeight; final bool arrangeHorizontally; final bool isLabelHasColon; + final bool hasMaxLines; + final bool isFillContainer; + final TextAlignVertical? textAlignVertical; + final TextInputAction? inputAction; final OnTextChange? onTextChange; const LabelInputFieldBuilder({ @@ -21,12 +26,17 @@ class LabelInputFieldBuilder extends StatelessWidget { required this.textEditingController, this.arrangeHorizontally = true, this.isLabelHasColon = true, + this.hasMaxLines = true, + this.isFillContainer = false, + this.textAlignVertical, this.hintText, this.errorText, this.focusNode, this.labelStyle, this.runSpacing, this.inputFieldMaxWidth, + this.inputFieldHeight, + this.inputAction, this.onTextChange, }); @@ -39,6 +49,11 @@ class LabelInputFieldBuilder extends StatelessWidget { hintText: hintText, errorText: errorText, focusNode: focusNode, + hasMaxLines: hasMaxLines, + textAlignVertical: textAlignVertical, + isFillContainer: isFillContainer, + inputAction: inputAction, + maxHeight: inputFieldHeight, onTextChange: onTextChange, ), ); diff --git a/lib/features/labels/presentation/widgets/create_new_label_modal.dart b/lib/features/labels/presentation/widgets/create_new_label_modal.dart index 727b7b35d..75a3e1417 100644 --- a/lib/features/labels/presentation/widgets/create_new_label_modal.dart +++ b/lib/features/labels/presentation/widgets/create_new_label_modal.dart @@ -55,6 +55,9 @@ class _CreateNewLabelModalState extends State { final ValueNotifier _createLabelStateNotifier = ValueNotifier(false); final TextEditingController _nameInputController = TextEditingController(); final FocusNode _nameInputFocusNode = FocusNode(); + final TextEditingController _descriptionInputController = + TextEditingController(); + final FocusNode _descriptionInputFocusNode = FocusNode(); List _labelDisplayNameList = []; Color? _selectedColor; @@ -135,6 +138,12 @@ class _CreateNewLabelModalState extends State { crossAxisAlignment: CrossAxisAlignment.start, children: [ _buildLabelNameInputField(appLocalizations), + Padding( + padding: const EdgeInsets.only(top: 16), + child: _buildLabelDescriptionInputField( + appLocalizations, + ), + ), Padding( padding: const EdgeInsets.only(top: 26, bottom: 16), child: Text( @@ -297,6 +306,29 @@ class _CreateNewLabelModalState extends State { ); } + 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( AppLocalizations appLocalizations, String value, @@ -376,6 +408,8 @@ class _CreateNewLabelModalState extends State { void dispose() { _nameInputFocusNode.dispose(); _nameInputController.dispose(); + _descriptionInputFocusNode.dispose(); + _descriptionInputController.dispose(); _labelNameErrorTextNotifier.dispose(); _labelSelectedColorNotifier.dispose(); _createLabelStateNotifier.dispose(); diff --git a/lib/l10n/intl_messages.arb b/lib/l10n/intl_messages.arb index c924b51fc..5216a394a 100644 --- a/lib/l10n/intl_messages.arb +++ b/lib/l10n/intl_messages.arb @@ -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": { "type": "text", @@ -5447,5 +5447,17 @@ "type": "text", "placeholders_order": [], "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": {} } } \ No newline at end of file diff --git a/lib/main/localizations/app_localizations.dart b/lib/main/localizations/app_localizations.dart index 23962d349..61f2497d2 100644 --- a/lib/main/localizations/app_localizations.dart +++ b/lib/main/localizations/app_localizations.dart @@ -5762,4 +5762,18 @@ class AppLocalizations { 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', + ); + } }