TF-4004 Add no content rules creation page

This commit is contained in:
dab246
2025-09-05 14:37:31 +07:00
committed by Dat H. Pham
parent 0194594b9f
commit 9ab62f5451
13 changed files with 338 additions and 136 deletions
+4
View File
@@ -0,0 +1,4 @@
<svg width="98" height="98" viewBox="0 0 98 98" fill="none" xmlns="http://www.w3.org/2000/svg">
<circle cx="49" cy="49" r="49" fill="#E0EDFF"/>
<path d="M44.2855 82.4224C43.7239 82.4224 43.1854 82.1993 42.7883 81.8022C42.3912 81.4052 42.1682 80.8666 42.1682 80.3051V59.9474L22.5409 38.3617C21.7683 37.5103 21.2594 36.4529 21.076 35.3179C20.8927 34.1829 21.0426 33.0191 21.5078 31.9677C21.973 30.9163 22.7334 30.0225 23.6966 29.3948C24.6599 28.7671 25.7846 28.4325 26.9343 28.4316H72.223C73.3727 28.4325 74.4975 28.7671 75.4607 29.3948C76.424 30.0225 77.1843 30.9163 77.6495 31.9677C78.1147 33.0191 78.2647 34.1829 78.0813 35.3179C77.8979 36.4529 77.389 37.5103 76.6164 38.3617L56.9892 59.9474V71.836C56.989 72.1531 56.9175 72.4662 56.7801 72.752C56.6427 73.0379 56.4428 73.2892 56.1952 73.4874L45.6088 81.9566C45.2334 82.2577 44.7667 82.422 44.2855 82.4224ZM26.9343 32.6662C26.6048 32.667 26.2827 32.7633 26.0068 32.9434C25.7309 33.1236 25.5132 33.3798 25.3799 33.6811C25.2466 33.9824 25.2035 34.3159 25.2558 34.6412C25.3081 34.9664 25.4535 35.2696 25.6745 35.514L45.8522 57.7454C46.1979 58.1256 46.3936 58.6185 46.4027 59.1323V75.9011L52.7546 70.7773V59.1323C52.7533 58.6039 52.9497 58.0941 53.3051 57.7031L73.4828 35.4716C73.6907 35.2262 73.8248 34.9269 73.8698 34.6085C73.9148 34.29 73.8687 33.9653 73.737 33.6719C73.6052 33.3785 73.3931 33.1284 73.1252 32.9504C72.8573 32.7725 72.5445 32.6739 72.223 32.6662H26.9343Z" fill="#9EBFEB"/>
</svg>

After

Width:  |  Height:  |  Size: 1.4 KiB

@@ -241,6 +241,7 @@ class ImagePaths {
String get icExpandArrows => _getImagePath('ic_expand_arrows.svg');
String get icPremium => _getImagePath('ic_premium.svg');
String get icCloud => _getImagePath('ic_cloud.svg');
String get icNoRules => _getImagePath('ic_no_rules.svg');
String _getImagePath(String imageName) {
return AssetsPaths.images + imageName;
@@ -75,7 +75,7 @@ class EmailRulesController extends BaseController {
}
}
void goToCreateNewRule(BuildContext context) async {
Future<void> goToCreateNewRule() async {
final accountId = _accountDashBoardController.accountId.value;
final session = _accountDashBoardController.sessionCurrent;
if (accountId != null && session != null) {
@@ -1,55 +1,101 @@
import 'package:core/presentation/state/success.dart';
import 'package:core/presentation/utils/theme_utils.dart';
import 'package:flutter/material.dart';
import 'package:get/get.dart';
import 'package:tmail_ui_user/features/base/mixin/app_loader_mixin.dart';
import 'package:tmail_ui_user/features/manage_account/presentation/base/setting_detail_view_builder.dart';
import 'package:tmail_ui_user/features/manage_account/presentation/email_rules/email_rules_controller.dart';
import 'package:tmail_ui_user/features/manage_account/presentation/email_rules/widgets/email_rules_header_widget.dart';
import 'package:tmail_ui_user/features/manage_account/presentation/email_rules/widgets/list_email_rules_widget.dart';
import 'package:tmail_ui_user/features/manage_account/presentation/email_rules/widgets/add_rule_button_widget.dart';
import 'package:tmail_ui_user/features/manage_account/presentation/email_rules/widgets/count_name_of_rules_widget.dart';
import 'package:tmail_ui_user/features/manage_account/presentation/email_rules/widgets/no_rules_widget.dart';
import 'package:tmail_ui_user/features/manage_account/presentation/menu/settings_utils.dart';
import 'package:tmail_ui_user/features/manage_account/presentation/model/account_menu_item.dart';
import 'package:tmail_ui_user/features/manage_account/presentation/widgets/setting_explanation_widget.dart';
import 'package:tmail_ui_user/features/manage_account/presentation/widgets/setting_header_widget.dart';
class EmailRulesView extends GetWidget<EmailRulesController> with AppLoaderMixin {
EmailRulesView({Key? key}) : super(key: key);
class EmailRulesView extends GetWidget<EmailRulesController> {
const EmailRulesView({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
final isDesktop = controller.responsiveUtils.isDesktop(context);
return SettingDetailViewBuilder(
responsiveUtils: controller.responsiveUtils,
backgroundColor: Colors.transparent,
child: SingleChildScrollView(
physics: const ClampingScrollPhysics(),
child: Padding(
padding: SettingsUtils.getSettingContentWithoutHeaderPadding(
context,
controller.responsiveUtils,
),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
EmailRulesHeaderWidget(
imagePaths: controller.imagePaths,
responsiveUtils: controller.responsiveUtils,
createRule: () => controller.goToCreateNewRule(context),
child: Container(
color: SettingsUtils.getContentBackgroundColor(
context,
controller.responsiveUtils,
),
decoration: SettingsUtils.getBoxDecorationForContent(
context,
controller.responsiveUtils,
),
width: double.infinity,
padding: isDesktop
? const EdgeInsetsDirectional.only(
start: 30,
end: 30,
top: 22,
)
: null,
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
if (isDesktop) ...[
Row(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Expanded(
child: SettingHeaderWidget(
menuItem: AccountMenuItem.emailRules,
textStyle: ThemeUtils.textStyleInter600().copyWith(
color: Colors.black.withValues(alpha: 0.9),
),
padding: const EdgeInsetsDirectional.only(end: 16),
),
),
AddRuleButtonWidget(
imagePaths: controller.imagePaths,
margin: const EdgeInsetsDirectional.only(
start: 169,
top: 24,
end: 57,
),
onAddRuleAction: controller.goToCreateNewRule,
),
],
),
const SizedBox(height: 14),
] else ...[
const SettingExplanationWidget(
menuItem: AccountMenuItem.emailRules,
padding: EdgeInsetsDirectional.symmetric(horizontal: 16),
isCenter: true,
textAlign: TextAlign.center,
),
Center(
child: AddRuleButtonWidget(
imagePaths: controller.imagePaths,
margin: const EdgeInsetsDirectional.only(top: 24, bottom: 16),
minWidth: 230,
onAddRuleAction: controller.goToCreateNewRule,
),
),
const SizedBox(height: 16),
_buildLoadingView(),
const ListEmailRulesWidget()
],
),
Obx(() => CountNameOfRulesWidget(
countRules: controller.listEmailRule.length,
margin: EdgeInsetsDirectional.only(
start: isDesktop ? 0 : 16,
top: 24,
),
)),
NoRulesWidget(
imagePaths: controller.imagePaths,
responsiveUtils: controller.responsiveUtils,
onAddRuleAction: controller.goToCreateNewRule,
),
],
),
),
);
}
Widget _buildLoadingView() {
return Obx(() => controller.viewState.value.fold(
(failure) => const SizedBox.shrink(),
(success) => success is LoadingState
? Padding(
padding: const EdgeInsets.only(bottom: 24),
child: loadingWidget)
: const SizedBox.shrink()
));
}
}
@@ -0,0 +1,49 @@
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/tmail_button_widget.dart';
import 'package:flutter/material.dart';
import 'package:tmail_ui_user/main/localizations/app_localizations.dart';
typedef OnAddRuleAction = void Function();
class AddRuleButtonWidget extends StatelessWidget {
final ImagePaths imagePaths;
final OnAddRuleAction onAddRuleAction;
final EdgeInsetsGeometry? margin;
final double minWidth;
const AddRuleButtonWidget({
super.key,
required this.imagePaths,
required this.onAddRuleAction,
this.margin,
this.minWidth = 161,
});
@override
Widget build(BuildContext context) {
return TMailButtonWidget(
text: AppLocalizations.of(context).addARule,
icon: imagePaths.icAddIdentity,
backgroundColor: AppColor.primaryMain,
borderRadius: 100,
height: 48,
maxWidth: 300,
minWidth: minWidth,
margin: margin,
textStyle: ThemeUtils.textStyleM3LabelLarge(color: Colors.white),
padding: const EdgeInsetsDirectional.symmetric(
horizontal: 32,
),
iconSize: 16,
iconColor: Colors.white,
iconSpace: 8,
maxLines: 1,
flexibleText: true,
textOverflow: TextOverflow.ellipsis,
mainAxisSize: MainAxisSize.min,
onTapActionCallback: onAddRuleAction,
);
}
}
@@ -0,0 +1,52 @@
import 'package:core/presentation/extensions/color_extension.dart';
import 'package:core/presentation/utils/theme_utils.dart';
import 'package:flutter/material.dart';
import 'package:tmail_ui_user/main/localizations/app_localizations.dart';
class CountNameOfRulesWidget extends StatelessWidget {
final int countRules;
final EdgeInsetsGeometry? margin;
const CountNameOfRulesWidget({
super.key,
required this.countRules,
this.margin,
});
@override
Widget build(BuildContext context) {
return Padding(
padding: margin ?? const EdgeInsetsDirectional.only(top: 38),
child: Row(
mainAxisSize: MainAxisSize.min,
children: [
Flexible(
child: Text(
AppLocalizations.of(context).nameOfRules,
style: ThemeUtils.textStyleInter600().copyWith(
fontSize: 14,
height: 20 / 14,
letterSpacing: 0.25,
color: AppColor.gray424244,
),
overflow: TextOverflow.ellipsis,
maxLines: 1,
),
),
Text(
' ${countRules > 999 ? '999+' : countRules.toString()}',
style: ThemeUtils.textStyleInter400.copyWith(
fontSize: 14,
height: 20 / 14,
letterSpacing: 0.25,
color: AppColor.gray424244,
),
overflow: TextOverflow.ellipsis,
maxLines: 1,
),
],
),
);
}
}
@@ -1,94 +0,0 @@
import 'package:core/presentation/extensions/color_extension.dart';
import 'package:core/presentation/resources/image_paths.dart';
import 'package:core/presentation/utils/responsive_utils.dart';
import 'package:core/presentation/utils/theme_utils.dart';
import 'package:core/presentation/views/button/tmail_button_widget.dart';
import 'package:flutter/material.dart';
import 'package:tmail_ui_user/features/manage_account/presentation/model/account_menu_item.dart';
import 'package:tmail_ui_user/features/manage_account/presentation/widgets/setting_explanation_widget.dart';
import 'package:tmail_ui_user/features/manage_account/presentation/widgets/setting_header_widget.dart';
import 'package:tmail_ui_user/main/localizations/app_localizations.dart';
class EmailRulesHeaderWidget extends StatelessWidget {
const EmailRulesHeaderWidget({
Key? key,
required this.createRule,
required this.imagePaths,
required this.responsiveUtils,
}) : super(key: key);
final VoidCallback createRule;
final ImagePaths imagePaths;
final ResponsiveUtils responsiveUtils;
@override
Widget build(BuildContext context) {
return Container(
width: double.infinity,
decoration: const BoxDecoration(
color: AppColor.colorBackgroundWrapIconStyleCode,
borderRadius: BorderRadius.all(Radius.circular(16)),
),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
if (responsiveUtils.isWebDesktop(context))
const SettingHeaderWidget(menuItem: AccountMenuItem.emailRules)
else
const SettingExplanationWidget(
menuItem: AccountMenuItem.emailRules,
padding: EdgeInsets.all(16),
),
Padding(
padding: const EdgeInsets.all(16),
child: _buildButtonAddNewRule(context),
),
],
),
);
}
Widget _buildButtonAddNewRule(BuildContext context) {
if (!responsiveUtils.isMobile(context)) {
return Row(
children: [
TMailButtonWidget(
key: const Key('new_rule_button'),
text: AppLocalizations.of(context).addNewRule,
icon: imagePaths.icAddNewRules,
borderRadius: 10,
backgroundColor: AppColor.colorTextButton,
iconColor: Colors.white,
minWidth: 130,
padding: const EdgeInsets.symmetric(vertical: 12,horizontal: 8),
iconSize: 20,
textStyle: ThemeUtils.defaultTextStyleInterFont.copyWith(
fontSize: 17,
color: Colors.white,
fontWeight: FontWeight.w500,
),
onTapActionCallback: createRule,
),
const Spacer(),
],
);
} else {
return TMailButtonWidget(
key: const Key('new_rule_button'),
text: AppLocalizations.of(context).addNewRule,
icon: imagePaths.icAddNewRules,
borderRadius: 10,
backgroundColor: AppColor.colorTextButton,
iconColor: Colors.white,
padding: const EdgeInsets.symmetric(vertical: 12),
iconSize: 20,
textStyle: ThemeUtils.defaultTextStyleInterFont.copyWith(
fontSize: 17,
color: Colors.white,
fontWeight: FontWeight.w500,
),
onTapActionCallback: createRule,
);
}
}
}
@@ -0,0 +1,81 @@
import 'package:core/presentation/extensions/color_extension.dart';
import 'package:core/presentation/resources/image_paths.dart';
import 'package:core/presentation/utils/responsive_utils.dart';
import 'package:core/presentation/utils/theme_utils.dart';
import 'package:core/presentation/views/dialog/confirm_dialog_button.dart';
import 'package:flutter/material.dart';
import 'package:flutter_svg/flutter_svg.dart';
import 'package:tmail_ui_user/features/manage_account/presentation/email_rules/widgets/add_rule_button_widget.dart';
import 'package:tmail_ui_user/main/localizations/app_localizations.dart';
class NoRulesWidget extends StatelessWidget {
final ImagePaths imagePaths;
final ResponsiveUtils responsiveUtils;
final OnAddRuleAction onAddRuleAction;
const NoRulesWidget({
super.key,
required this.imagePaths,
required this.responsiveUtils,
required this.onAddRuleAction,
});
@override
Widget build(BuildContext context) {
final appLocalizations = AppLocalizations.of(context);
final isMobile = responsiveUtils.isMobile(context);
return Expanded(
child: Container(
padding: EdgeInsetsDirectional.only(top: isMobile ? 48 : 32),
alignment: Alignment.topCenter,
child: SingleChildScrollView(
physics: const ClampingScrollPhysics(),
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
SvgPicture.asset(
imagePaths.icNoRules,
width: 98,
height: 98,
fit: BoxFit.fill,
),
const SizedBox(height: 12),
Text(
appLocalizations.noRulesConfigured,
style: ThemeUtils.textStyleInter600(),
textAlign: TextAlign.center,
),
const SizedBox(height: 24),
Text(
appLocalizations.messageExplanationNoRulesConfigured,
style: ThemeUtils.textStyleInter400.copyWith(
fontSize: 16,
height: 21.01 / 16,
letterSpacing: -0.15,
color: AppColor.gray424244.withValues(alpha: 0.64),
),
textAlign: TextAlign.center,
),
const SizedBox(height: 24),
Container(
constraints: const BoxConstraints(minWidth: 230),
height: 48,
child: ConfirmDialogButton(
label: AppLocalizations.of(context).createMyFirstRule,
backgroundColor: Colors.white,
textColor: AppColor.primaryMain,
borderColor: AppColor.primaryMain,
icon: imagePaths.icAddIdentity,
onTapAction: onAddRuleAction,
),
)
],
),
),
),
);
}
}
@@ -144,7 +144,7 @@ class ManageAccountDashBoardView extends GetWidget<ManageAccountDashBoardControl
}
case AccountMenuItem.emailRules:
if (controller.isRuleFilterCapabilitySupported){
return EmailRulesView();
return const EmailRulesView();
} else {
return const SizedBox.shrink();
}
@@ -106,7 +106,7 @@ class SettingsView extends GetWidget<SettingsController> {
}
case AccountMenuItem.emailRules:
if (controller.manageAccountDashboardController.isRuleFilterCapabilitySupported) {
return EmailRulesView();
return const EmailRulesView();
} else {
return const SizedBox.shrink();
}
@@ -40,8 +40,6 @@ class SettingHeaderWidget extends StatelessWidget {
letterSpacing: -0.15,
color: AppColor.gray424244.withValues(alpha: 0.64),
),
maxLines: 1,
overflow: TextOverflow.ellipsis,
),
),
];
+30
View File
@@ -4699,5 +4699,35 @@
"type": "text",
"placeholders_order": [],
"placeholders": {}
},
"addARule": "Add a rule",
"@addARule": {
"type": "text",
"placeholders_order": [],
"placeholders": {}
},
"nameOfRules": "Name of Rules",
"@nameOfRules": {
"type": "text",
"placeholders_order": [],
"placeholders": {}
},
"noRulesConfigured": "No Rules Configured",
"@noRulesConfigured": {
"type": "text",
"placeholders_order": [],
"placeholders": {}
},
"messageExplanationNoRulesConfigured": "Start by creating your first rule to automate\n email management.",
"@messageExplanationNoRulesConfigured": {
"type": "text",
"placeholders_order": [],
"placeholders": {}
},
"createMyFirstRule": "Create My First Rule",
"@createMyFirstRule": {
"type": "text",
"placeholders_order": [],
"placeholders": {}
}
}
@@ -4957,4 +4957,39 @@ class AppLocalizations {
name: 'manageMyStorage',
);
}
String get addARule {
return Intl.message(
'Add a rule',
name: 'addARule',
);
}
String get nameOfRules {
return Intl.message(
'Name of Rules',
name: 'nameOfRules',
);
}
String get noRulesConfigured {
return Intl.message(
'No Rules Configured',
name: 'noRulesConfigured',
);
}
String get messageExplanationNoRulesConfigured {
return Intl.message(
'Start by creating your first rule to automate\n email management.',
name: 'messageExplanationNoRulesConfigured',
);
}
String get createMyFirstRule {
return Intl.message(
'Create My First Rule',
name: 'createMyFirstRule',
);
}
}