TF-4179 Display tag list in sidebar

This commit is contained in:
dab246
2025-11-25 18:54:54 +07:00
committed by Dat H. Pham
parent 75f55e6507
commit e2fe0a0676
8 changed files with 215 additions and 4 deletions
+5
View File
@@ -0,0 +1,5 @@
<svg width="21" height="21" viewBox="0 0 21 21" fill="none" xmlns="http://www.w3.org/2000/svg">
<path
d="M3.38581 11.5441L8.20407 16.4223C9.65945 17.8958 12.0338 17.9105 13.5073 16.4552L16.4445 13.5541C16.6197 14.3625 16.3903 15.2405 15.7582 15.8648L13.7936 17.8053C12.1563 19.4224 9.51819 19.4061 7.90111 17.7688L4.3459 14.1694C3.72466 13.5404 3.37872 12.6904 3.38419 11.8064L3.38581 11.5441ZM15.783 11.8649L12.3361 15.2694C11.5175 16.0779 10.1984 16.0698 9.38985 15.2512L4.37065 10.1694C3.74941 9.54047 3.40347 8.69047 3.40894 7.80643L3.42876 4.60387C3.43588 3.4533 4.37437 2.52635 5.52494 2.53347L8.7275 2.55328C9.61154 2.55875 10.4572 2.91518 11.0784 3.54416L15.8048 8.32942C16.7751 9.31175 16.7653 10.8946 15.783 11.8649ZM7.57214 8.37958C8.4926 8.38527 9.2434 7.64371 9.24909 6.72326C9.25479 5.8028 8.51323 5.052 7.59277 5.04631C6.67231 5.04061 5.92152 5.78217 5.91582 6.70263C5.91013 7.62309 6.65169 8.37388 7.57214 8.37958Z"
fill="#007AFF" />
</svg>

After

Width:  |  Height:  |  Size: 977 B

@@ -275,6 +275,7 @@ class ImagePaths {
String get icAiMoreDetail => _getImagePath('ic_ai_more_detail.svg');
String get icAiMoreProfessional => _getImagePath('ic_ai_more_professional.svg');
String get icAiMorePolite => _getImagePath('ic_ai_more_polite.svg');
String get icTag => _getImagePath('ic_tag.svg');
String _getImagePath(String imageName) {
return AssetsPaths.images + imageName;
@@ -17,6 +17,7 @@ import 'package:tmail_ui_user/features/mailbox/presentation/model/mailbox_catego
import 'package:tmail_ui_user/features/mailbox/presentation/model/mailbox_node.dart';
import 'package:tmail_ui_user/features/mailbox/presentation/styles/mailbox_item_widget_styles.dart';
import 'package:tmail_ui_user/features/mailbox/presentation/widgets/folders_bar_widget.dart';
import 'package:tmail_ui_user/features/mailbox/presentation/widgets/labels/label_list_view.dart';
import 'package:tmail_ui_user/features/mailbox/presentation/widgets/labels/labels_bar_widget.dart';
import 'package:tmail_ui_user/features/mailbox/presentation/widgets/mailbox_app_bar.dart';
import 'package:tmail_ui_user/features/mailbox/presentation/widgets/mailbox_category_widget.dart';
@@ -338,6 +339,7 @@ abstract class BaseMailboxView extends GetWidget<MailboxController>
: const Offstage(),
)),
buildLabelsBar(context, isDesktop),
buildLabelsList(context, isDesktop),
]),
);
}
@@ -345,11 +347,11 @@ abstract class BaseMailboxView extends GetWidget<MailboxController>
Widget buildLabelsBar(BuildContext context, bool isDesktop) {
return Obx(() {
if (controller.mailboxDashBoardController.isLabelCapabilitySupported) {
final labelController = controller
.mailboxDashBoardController
.labelController;
final labelController =
controller.mailboxDashBoardController.labelController;
final labelListExpandMode = labelController.labelListExpandMode.value;
final countLabels = labelController.labels.length;
return LabelsBarWidget(
imagePaths: controller.imagePaths,
@@ -360,6 +362,7 @@ abstract class BaseMailboxView extends GetWidget<MailboxController>
: const EdgeInsetsDirectional.only(start: 24, end: 12),
labelStyle: isDesktop ? null : ThemeUtils.textStyleInter500(),
expandMode: labelListExpandMode,
countLabels: countLabels,
onToggleLabelListState: labelController.toggleLabelListState,
);
} else {
@@ -367,4 +370,29 @@ abstract class BaseMailboxView extends GetWidget<MailboxController>
}
});
}
Widget buildLabelsList(BuildContext context, bool isDesktop) {
return Obx(() {
if (controller.mailboxDashBoardController.isLabelCapabilitySupported) {
final labelController =
controller.mailboxDashBoardController.labelController;
final labelListExpandMode = labelController.labelListExpandMode.value;
final labels = labelController.labels;
return AnimatedContainer(
duration: const Duration(milliseconds: 400),
child: labelListExpandMode == ExpandMode.EXPAND && labels.isNotEmpty
? LabelListView(
labels: labels,
imagePaths: controller.imagePaths,
isDesktop: isDesktop,
)
: const Offstage(),
);
} else {
return const SizedBox.shrink();
}
});
}
}
@@ -0,0 +1,36 @@
import 'package:core/presentation/extensions/color_extension.dart';
import 'package:flutter/material.dart';
import 'package:flutter_svg/flutter_svg.dart';
import 'package:tmail_ui_user/features/mailbox/presentation/styles/mailbox_icon_widget_styles.dart';
import 'package:tmail_ui_user/features/mailbox/presentation/styles/mailbox_item_widget_styles.dart';
class LabelIconWidget extends StatelessWidget {
final String icon;
final double iconSize;
final EdgeInsetsGeometry padding;
final Color? color;
const LabelIconWidget({
super.key,
required this.icon,
this.iconSize = MailboxIconWidgetStyles.iconSize,
this.padding = const EdgeInsetsDirectional.only(
end: MailboxItemWidgetStyles.labelIconSpace,
),
this.color,
});
@override
Widget build(BuildContext context) {
return Padding(
padding: padding,
child: SvgPicture.asset(
icon,
width: iconSize,
height: iconSize,
colorFilter: color?.asFilter(),
fit: BoxFit.fill,
),
);
}
}
@@ -0,0 +1,70 @@
import 'package:core/presentation/resources/image_paths.dart';
import 'package:flutter/material.dart';
import 'package:labels/extensions/label_extension.dart';
import 'package:labels/model/label.dart';
import 'package:tmail_ui_user/features/mailbox/presentation/styles/mailbox_item_widget_styles.dart';
import 'package:tmail_ui_user/features/mailbox/presentation/widgets/labels/label_icon_widget.dart';
import 'package:tmail_ui_user/features/mailbox/presentation/widgets/labels/label_name_widget.dart';
class LabelListItem extends StatelessWidget {
final Label label;
final ImagePaths imagePaths;
final bool isDesktop;
const LabelListItem({
super.key,
required this.label,
required this.imagePaths,
this.isDesktop = false,
});
@override
Widget build(BuildContext context) {
final borderRadius = BorderRadius.all(
Radius.circular(
isDesktop
? MailboxItemWidgetStyles.mobileBorderRadius
: MailboxItemWidgetStyles.borderRadius,
),
);
return Material(
type: MaterialType.transparency,
child: InkWell(
onTap: () {},
borderRadius: borderRadius,
child: Container(
decoration: BoxDecoration(borderRadius: borderRadius),
padding: EdgeInsetsDirectional.symmetric(
horizontal: isDesktop
? MailboxItemWidgetStyles.mobileItemPadding
: MailboxItemWidgetStyles.itemPadding,
),
height: isDesktop
? MailboxItemWidgetStyles.mobileHeight
: MailboxItemWidgetStyles.height,
child: Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
LabelIconWidget(
icon: imagePaths.icTag,
color: label.backgroundColor,
padding: EdgeInsetsDirectional.only(
end: isDesktop
? MailboxItemWidgetStyles.labelIconSpace
: MailboxItemWidgetStyles.mobileLabelIconSpace,
),
),
Expanded(
child: LabelNameWidget(
name: label.safeDisplayName,
isDesktop: isDesktop,
),
),
],
),
),
),
);
}
}
@@ -0,0 +1,44 @@
import 'package:core/presentation/resources/image_paths.dart';
import 'package:flutter/material.dart';
import 'package:labels/model/label.dart';
import 'package:tmail_ui_user/features/mailbox/presentation/widgets/labels/label_list_item.dart';
class LabelListView extends StatelessWidget {
final List<Label> labels;
final ImagePaths imagePaths;
final bool isDesktop;
const LabelListView({
super.key,
required this.labels,
required this.imagePaths,
this.isDesktop = false,
});
@override
Widget build(BuildContext context) {
Widget labelListView = ListView.builder(
key: const PageStorageKey('label_list'),
shrinkWrap: true,
primary: false,
padding: EdgeInsets.zero,
itemCount: labels.length,
itemBuilder: (context, index) {
return LabelListItem(
label: labels[index],
imagePaths: imagePaths,
isDesktop: isDesktop,
);
},
);
if (!isDesktop) {
labelListView = Padding(
padding: const EdgeInsets.symmetric(horizontal: 12),
child: labelListView,
);
}
return labelListView;
}
}
@@ -0,0 +1,25 @@
import 'package:core/presentation/utils/theme_utils.dart';
import 'package:flutter/material.dart';
class LabelNameWidget extends StatelessWidget {
final String name;
final bool isDesktop;
const LabelNameWidget({
super.key,
required this.name,
this.isDesktop = false,
});
@override
Widget build(BuildContext context) {
return Text(
name,
style: isDesktop
? ThemeUtils.textStyleBodyBody3(color: Colors.black)
: ThemeUtils.textStyleInter500(),
maxLines: 1,
overflow: TextOverflow.ellipsis,
);
}
}
@@ -12,6 +12,7 @@ class LabelsBarWidget extends StatelessWidget {
final ImagePaths imagePaths;
final bool isDesktop;
final double? height;
final int countLabels;
final EdgeInsetsGeometry? padding;
final TextStyle? labelStyle;
final ExpandMode? expandMode;
@@ -22,6 +23,7 @@ class LabelsBarWidget extends StatelessWidget {
super.key,
required this.imagePaths,
this.isDesktop = false,
this.countLabels = 0,
this.height,
this.padding,
this.labelStyle,
@@ -65,7 +67,7 @@ class LabelsBarWidget extends StatelessWidget {
height: height ?? 48,
child: Row(
children: [
if (expandMode != null)
if (expandMode != null && countLabels > 0)
Expanded(
child: Row(
children: [