From 35b46ff21b12c5d2b9ba2f990619b93b375b7be4 Mon Sep 17 00:00:00 2001 From: dab246 Date: Thu, 16 Apr 2026 19:33:35 +0700 Subject: [PATCH] TF-4308 Add `NoLabelYetWidget` for choose label modal Signed-off-by: dab246 --- assets/images/ic_no_tag.svg | 5 + .../presentation/resources/image_paths.dart | 1 + .../widgets/choose_label_modal.dart | 105 ++++------------ .../widgets/list_label_with_action_modal.dart | 112 ++++++++++++++++++ .../widgets/no_label_yet_widget.dart | 109 +++++++++++++++++ .../mailbox_dashboard_view_web.dart | 1 - .../widgets/top_bar_thread_selection.dart | 5 +- lib/l10n/intl_messages.arb | 18 +++ lib/main/localizations/app_localizations.dart | 21 ++++ 9 files changed, 288 insertions(+), 89 deletions(-) create mode 100644 assets/images/ic_no_tag.svg create mode 100644 lib/features/labels/presentation/widgets/list_label_with_action_modal.dart create mode 100644 lib/features/labels/presentation/widgets/no_label_yet_widget.dart diff --git a/assets/images/ic_no_tag.svg b/assets/images/ic_no_tag.svg new file mode 100644 index 000000000..b54813ced --- /dev/null +++ b/assets/images/ic_no_tag.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/core/lib/presentation/resources/image_paths.dart b/core/lib/presentation/resources/image_paths.dart index fc47c61f4..bb65672a3 100644 --- a/core/lib/presentation/resources/image_paths.dart +++ b/core/lib/presentation/resources/image_paths.dart @@ -282,6 +282,7 @@ class ImagePaths { String get icColorPicker => _getImagePath('ic_color_picker.svg'); String get icThumbsUp => _getImagePath('ic_thumbs_up.svg'); String get icAllEmail => _getImagePath('ic_all_email.svg'); + String get icNoTag => _getImagePath('ic_no_tag.svg'); String _getImagePath(String imageName) { return AssetsPaths.images + imageName; diff --git a/lib/features/labels/presentation/widgets/choose_label_modal.dart b/lib/features/labels/presentation/widgets/choose_label_modal.dart index 78e40b1d8..06166a580 100644 --- a/lib/features/labels/presentation/widgets/choose_label_modal.dart +++ b/lib/features/labels/presentation/widgets/choose_label_modal.dart @@ -4,10 +4,10 @@ import 'package:core/presentation/extensions/color_extension.dart'; import 'package:core/presentation/resources/image_paths.dart'; import 'package:core/presentation/utils/theme_utils.dart'; import 'package:core/presentation/views/button/default_close_button_widget.dart'; -import 'package:core/presentation/views/dialog/modal_list_action_button_widget.dart'; import 'package:flutter/material.dart'; import 'package:labels/labels.dart'; -import 'package:tmail_ui_user/features/mailbox/presentation/widgets/labels/label_list_item.dart'; +import 'package:tmail_ui_user/features/labels/presentation/widgets/list_label_with_action_modal.dart'; +import 'package:tmail_ui_user/features/labels/presentation/widgets/no_label_yet_widget.dart'; import 'package:tmail_ui_user/main/localizations/app_localizations.dart'; import 'package:tmail_ui_user/main/routes/route_navigation.dart'; @@ -30,10 +30,6 @@ class ChooseLabelModal extends StatefulWidget { } class _ChooseLabelModalState extends State { - final ValueNotifier _addLabelStateNotifier = ValueNotifier(false); - final ValueNotifier> _selectedLabelStateNotifier = - ValueNotifier([]); - @override Widget build(BuildContext context) { final appLocalizations = AppLocalizations.of(context); @@ -41,6 +37,8 @@ class _ChooseLabelModalState extends State { return LayoutBuilder(builder: (_, constraints) { final currentScreenWidth = constraints.maxWidth; final currentScreenHeight = constraints.maxHeight; + double height = math.min(currentScreenHeight - 100, 645); + double width = math.min(currentScreenWidth - 32, 536); Widget bodyWidget = Container( decoration: BoxDecoration( @@ -58,11 +56,8 @@ class _ChooseLabelModalState extends State { ), ], ), - width: math.min( - currentScreenWidth - 32, - 554, - ), - constraints: BoxConstraints(maxHeight: currentScreenHeight - 100), + width: width, + height: height, clipBehavior: Clip.antiAlias, child: Stack( children: [ @@ -73,23 +68,21 @@ class _ChooseLabelModalState extends State { _buildTitle(appLocalizations), const Divider(height: 1, color: Colors.black12), _buildSubtitle(appLocalizations), - Flexible(child: _buildLabelListView()), - ValueListenableBuilder( - valueListenable: _addLabelStateNotifier, - builder: (_, value, __) { - return ModalListActionButtonWidget( - positiveLabel: appLocalizations.addLabel, - negativeLabel: appLocalizations.cancel, - padding: const EdgeInsets.symmetric( - vertical: 25, - horizontal: 25, - ), - isPositiveActionEnabled: value, - onPositiveAction: _onAddLabel, - onNegativeAction: _onCloseModal, - ); - }, - ), + if (widget.labels.isNotEmpty) + Expanded( + child: ListLabelWithActionModal( + labels: widget.labels, + imagePaths: widget.imagePaths, + onLabelAsToEmailsAction: widget.onLabelAsToEmailsAction, + onCloseModal: _onCloseModal, + ), + ) + else + Expanded( + child: Center( + child: NoLabelYetWidget(imagePaths: widget.imagePaths), + ), + ), ], ), DefaultCloseButtonWidget( @@ -137,63 +130,7 @@ class _ChooseLabelModalState extends State { ); } - Widget _buildLabelListView() { - final labelList = widget.labels; - return ListView.builder( - shrinkWrap: true, - padding: EdgeInsets.zero, - itemCount: labelList.length, - itemBuilder: (context, index) { - final label = labelList[index]; - return ValueListenableBuilder( - valueListenable: _selectedLabelStateNotifier, - builder: (_, selectedLabels, __) { - final isSelected = selectedLabels.contains(label); - return LabelListItem( - label: label, - imagePaths: widget.imagePaths, - padding: const EdgeInsetsDirectional.only( - start: 4, - end: 16, - ), - enableSelectedIcon: true, - isSelected: isSelected, - onOpenLabelCallback: _onToggleLabel, - ); - }, - ); - }, - ); - } - - void _onToggleLabel(Label selectedLabel) { - final currentLabels = _selectedLabelStateNotifier.value; - - final isAlreadySelected = currentLabels.any((label) => label.id == selectedLabel.id); - if (isAlreadySelected) { - _selectedLabelStateNotifier.value = - currentLabels.where((label) => label.id != selectedLabel.id).toList(); - } else { - _selectedLabelStateNotifier.value = [...currentLabels, selectedLabel]; - } - - _addLabelStateNotifier.value = _selectedLabelStateNotifier.value.isNotEmpty; - } - - void _onAddLabel() { - widget.onLabelAsToEmailsAction(_selectedLabelStateNotifier.value); - - popBack(); - } - void _onCloseModal() { popBack(); } - - @override - void dispose() { - _addLabelStateNotifier.dispose(); - _selectedLabelStateNotifier.dispose(); - super.dispose(); - } } diff --git a/lib/features/labels/presentation/widgets/list_label_with_action_modal.dart b/lib/features/labels/presentation/widgets/list_label_with_action_modal.dart new file mode 100644 index 000000000..67347a6a6 --- /dev/null +++ b/lib/features/labels/presentation/widgets/list_label_with_action_modal.dart @@ -0,0 +1,112 @@ +import 'package:core/presentation/resources/image_paths.dart'; +import 'package:core/presentation/views/dialog/modal_list_action_button_widget.dart'; +import 'package:flutter/material.dart'; +import 'package:labels/model/label.dart'; +import 'package:tmail_ui_user/features/labels/presentation/widgets/choose_label_modal.dart'; +import 'package:tmail_ui_user/features/mailbox/presentation/widgets/labels/label_list_item.dart'; +import 'package:tmail_ui_user/main/localizations/app_localizations.dart'; + +class ListLabelWithActionModal extends StatefulWidget { + final List