From 3aa2b91a89e663ad43995d1b9d2f8fa2f2a020bd Mon Sep 17 00:00:00 2001 From: dab246 Date: Fri, 4 Aug 2023 21:26:15 +0700 Subject: [PATCH] TF-2064 Add QuotasBannerWidget (cherry picked from commit ce85ba3d7e647a8a93a54144a840905a8c479fb0) --- .../extensions/color_extension.dart | 5 +- .../domain/extensions/quota_extensions.dart | 128 ++++++++++++++++++ .../styles/quotas_banner_styles.dart | 23 ++++ .../widget/quotas_banner_widget.dart | 77 +++++++++++ lib/l10n/intl_messages.arb | 78 +++++------ lib/main/localizations/app_localizations.dart | 73 +++++----- 6 files changed, 303 insertions(+), 81 deletions(-) create mode 100644 lib/features/quotas/domain/extensions/quota_extensions.dart create mode 100644 lib/features/quotas/presentation/styles/quotas_banner_styles.dart create mode 100644 lib/features/quotas/presentation/widget/quotas_banner_widget.dart diff --git a/core/lib/presentation/extensions/color_extension.dart b/core/lib/presentation/extensions/color_extension.dart index a7e83102e..bd60dc840 100644 --- a/core/lib/presentation/extensions/color_extension.dart +++ b/core/lib/presentation/extensions/color_extension.dart @@ -164,9 +164,8 @@ extension AppColor on Color { static const colorDeleteContactIcon = Color(0xFFAEB7C2); static const colorItemRecipientSelected = Color(0xFFDFEEFF); static const colorBackgroundQuotasWarning = Color(0xFFFFC107); - static const colorTitleQuotasWarning = Color(0xFFF05C44); - static const colorProgressQuotasWarning = Color(0xFFFFA000); - static const colorOutOfStorageQuotasWarning = Color(0xffE64646); + static const colorQuotaWarning = Color(0xFFF05C44); + static const colorQuotaError = Color(0xffE64646); static const colorThumbScrollBar = Color(0xFFAEB7C2); static const colorCreateNewIdentityButton = Color(0xFFEBEDF0); static const colorSpamReportBannerBackground = Color(0xFFBFDEFF); diff --git a/lib/features/quotas/domain/extensions/quota_extensions.dart b/lib/features/quotas/domain/extensions/quota_extensions.dart new file mode 100644 index 000000000..ea420f80a --- /dev/null +++ b/lib/features/quotas/domain/extensions/quota_extensions.dart @@ -0,0 +1,128 @@ + +import 'package:core/presentation/extensions/color_extension.dart'; +import 'package:core/presentation/resources/image_paths.dart'; +import 'package:filesize/filesize.dart'; +import 'package:flutter/material.dart'; +import 'package:jmap_dart_client/jmap/quotas/quota.dart'; +import 'package:tmail_ui_user/main/localizations/app_localizations.dart'; + +extension QuotasExtensions on Quota { + + String get usedStorageAsString => used != null ? filesize(used!.value) : ''; + + String get hardLimitStorageAsString => hardLimit != null ? filesize(hardLimit!.value) : ''; + + bool get isWarnLimitReached { + if (used != null && warnLimit != null) { + return used!.value >= warnLimit!.value * 0.9; + } else { + return false; + } + } + + bool get isHardLimitReached { + if (used != null && hardLimit != null) { + return used!.value >= hardLimit!.value; + } else { + return false; + } + } + + double get usedStoragePercent { + if (used != null && hardLimit != null && hardLimit!.value > 0) { + return used!.value / hardLimit!.value; + } else { + return 0; + } + } + + bool get allowedDisplayToQuotaBanner => storageAvailable && (isHardLimitReached || isWarnLimitReached); + + bool get storageAvailable => used != null && hardLimit != null && warnLimit != null; + + String getQuotasStateTitle(BuildContext context) { + if (isHardLimitReached) { + return AppLocalizations.of(context).textQuotasOutOfStorage; + } else { + return AppLocalizations.of(context).quotaStateLabel(usedStorageAsString, hardLimitStorageAsString); + } + } + + Color getQuotasStateTitleColor() { + if (isHardLimitReached) { + return AppColor.colorQuotaError; + } else { + return AppColor.colorLabelQuotas; + } + } + + Color getQuotasStateProgressBarColor() { + if (isHardLimitReached) { + return AppColor.colorQuotaError; + } else if (isWarnLimitReached) { + return AppColor.colorBackgroundQuotasWarning; + } else { + return AppColor.primaryColor; + } + } + + Color getQuotaBannerBackgroundColor() { + if (isHardLimitReached) { + return AppColor.colorQuotaError.withOpacity(0.12); + } else if (isWarnLimitReached) { + return AppColor.colorBackgroundQuotasWarning.withOpacity(0.12); + } else { + return AppColor.colorNetworkConnectionBannerBackground; + } + } + + String getQuotaBannerIcon(ImagePaths imagePaths) { + if (isHardLimitReached) { + return imagePaths.icQuotasOutOfStorage; + } else if (isWarnLimitReached) { + return imagePaths.icQuotasWarning; + } else { + return ''; + } + } + + String getQuotaBannerTitle(BuildContext context) { + if (isHardLimitReached) { + return AppLocalizations.of(context).quotaErrorBannerTitle; + } else if (isWarnLimitReached) { + return AppLocalizations.of(context).quotaWarningBannerTitle; + } else { + return ''; + } + } + + String getQuotaBannerMessage(BuildContext context) { + if (isHardLimitReached) { + return AppLocalizations.of(context).quotaErrorBannerMessage; + } else if (isWarnLimitReached) { + return AppLocalizations.of(context).quotaWarningBannerMessage; + } else { + return ''; + } + } + + Color getQuotaBannerTitleColor() { + if (isHardLimitReached) { + return AppColor.colorQuotaError; + } else if (isWarnLimitReached) { + return AppColor.colorQuotaWarning; + } else { + return Colors.black; + } + } + + Color getQuotaBannerMessageColor() { + if (isHardLimitReached) { + return AppColor.colorQuotaError; + } else if (isWarnLimitReached) { + return AppColor.colorQuotaWarning; + } else { + return Colors.black; + } + } +} \ No newline at end of file diff --git a/lib/features/quotas/presentation/styles/quotas_banner_styles.dart b/lib/features/quotas/presentation/styles/quotas_banner_styles.dart new file mode 100644 index 000000000..7a0e698e6 --- /dev/null +++ b/lib/features/quotas/presentation/styles/quotas_banner_styles.dart @@ -0,0 +1,23 @@ + +import 'package:core/presentation/extensions/color_extension.dart'; +import 'package:flutter/material.dart'; + +class QuotasBannerStyles { + static const double verticalPadding = 12; + static const double horizontalPadding = 16; + static const double topMargin = 8; + static const double startMargin = 16; + static const double endMargin = 16; + static const double bottomMargin = 8; + static const double iconPadding = 16; + static const double iconSize = 32; + static const double titleTextSize = 17; + static const double messageTextSize = 15; + static const double space = 8; + static const double borderRadius = 12; + + static const Color messageTextColor = AppColor.colorLabelQuotas; + + static const FontWeight titleFontWeight = FontWeight.w700; + static const FontWeight messageFontWeight = FontWeight.w400; +} \ No newline at end of file diff --git a/lib/features/quotas/presentation/widget/quotas_banner_widget.dart b/lib/features/quotas/presentation/widget/quotas_banner_widget.dart new file mode 100644 index 000000000..fdfda656f --- /dev/null +++ b/lib/features/quotas/presentation/widget/quotas_banner_widget.dart @@ -0,0 +1,77 @@ +import 'package:core/presentation/utils/responsive_utils.dart'; +import 'package:core/utils/platform_info.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_svg/flutter_svg.dart'; +import 'package:get/get.dart'; +import 'package:tmail_ui_user/features/quotas/domain/extensions/quota_extensions.dart'; +import 'package:tmail_ui_user/features/quotas/presentation/quotas_controller.dart'; +import 'package:tmail_ui_user/features/quotas/presentation/styles/quotas_banner_styles.dart'; + +class QuotasBannerWidget extends StatelessWidget { + + const QuotasBannerWidget({Key? key}) : super(key: key); + + @override + Widget build(BuildContext context) { + final controller = Get.find(); + final responsiveUtils = Get.find(); + return Obx(() { + if (controller.octetsQuota.value != null && controller.octetsQuota.value!.allowedDisplayToQuotaBanner) { + final octetQuota = controller.octetsQuota.value!; + return Container( + decoration: BoxDecoration( + color: octetQuota.getQuotaBannerBackgroundColor(), + borderRadius: const BorderRadius.all(Radius.circular(QuotasBannerStyles.borderRadius)), + ), + margin: EdgeInsetsDirectional.only( + end: QuotasBannerStyles.endMargin, + top: PlatformInfo.isWeb ? QuotasBannerStyles.topMargin : 0, + start: responsiveUtils.isWebDesktop(context) ? 0 : QuotasBannerStyles.startMargin, + bottom: responsiveUtils.isWebDesktop(context) ? 0 : QuotasBannerStyles.bottomMargin + ), + padding: const EdgeInsetsDirectional.symmetric( + horizontal: QuotasBannerStyles.horizontalPadding, + vertical: QuotasBannerStyles.verticalPadding, + ), + child: Row( + children: [ + SvgPicture.asset( + octetQuota.getQuotaBannerIcon(controller.imagePaths), + width: QuotasBannerStyles.iconSize, + height: QuotasBannerStyles.iconSize, + fit: BoxFit.fill, + ), + const SizedBox(width: QuotasBannerStyles.iconPadding), + Expanded( + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + octetQuota.getQuotaBannerTitle(context), + style: TextStyle( + fontSize: QuotasBannerStyles.titleTextSize, + fontWeight: QuotasBannerStyles.titleFontWeight, + color: octetQuota.getQuotaBannerTitleColor(), + ), + ), + const SizedBox(height: QuotasBannerStyles.space), + Text( + octetQuota.getQuotaBannerMessage(context), + style: const TextStyle( + fontSize: QuotasBannerStyles.messageTextSize, + fontWeight: QuotasBannerStyles.messageFontWeight, + color: QuotasBannerStyles.messageTextColor, + ), + ), + ], + ), + ), + ], + ), + ); + } else { + return const SizedBox.shrink(); + } + }); + } +} diff --git a/lib/l10n/intl_messages.arb b/lib/l10n/intl_messages.arb index 16f1eb08d..726266517 100644 --- a/lib/l10n/intl_messages.arb +++ b/lib/l10n/intl_messages.arb @@ -1,5 +1,5 @@ { - "@@last_modified": "2023-08-03T18:37:14.070879", + "@@last_modified": "2023-08-04T21:19:31.613036", "initializing_data": "Initializing data...", "@initializing_data": { "type": "text", @@ -2482,52 +2482,12 @@ "placeholders_order": [], "placeholders": {} }, - "textQuotasUsed": "{used} GB of {softLimit} GB Used", - "@textQuotasUsed": { - "type": "text", - "placeholders_order": [ - "used", - "softLimit" - ], - "placeholders": { - "used": {}, - "softLimit": {} - } - }, - "textQuotasRunningOutOfStorageTitle": "You are running out of storage ({progress}%).", - "@textQuotasRunningOutOfStorageTitle": { - "type": "text", - "placeholders_order": [ - "progress" - ], - "placeholders": { - "progress": {} - } - }, - "textQuotasRunningOutOfStorageContent": "Soon you won't be able to email in Team Mail. Please clean your storage or upgrade your storage to get full features in Team Mail.", - "@textQuotasRunningOutOfStorageContent": { - "type": "text", - "placeholders_order": [], - "placeholders": {} - }, "textQuotasOutOfStorage": "Out of storage", "@textQuotasOutOfStorage": { "type": "text", "placeholders_order": [], "placeholders": {} }, - "textQuotasRunOutOfStorageTitle": "You have run out of storage space", - "@textQuotasRunOutOfStorageTitle": { - "type": "text", - "placeholders_order": [], - "placeholders": {} - }, - "textQuotasRunOutOfStorageContent": "Now you temporarily can't send or get an email. Please free up or upgrade your storage to get the full features of Team Mail.", - "@textQuotasRunOutOfStorageContent": { - "type": "text", - "placeholders_order": [], - "placeholders": {} - }, "quickCreatingRule": "Create a rule with this email", "@quickCreatingRule": { "type": "text", @@ -3131,5 +3091,41 @@ "type": "text", "placeholders_order": [], "placeholders": {} + }, + "quotaStateLabel": "{used} of {limit} Used", + "@quotaStateLabel": { + "type": "text", + "placeholders_order": [ + "used", + "limit" + ], + "placeholders": { + "used": {}, + "limit": {} + } + }, + "quotaErrorBannerTitle": "You have run out of storage space", + "@quotaErrorBannerTitle": { + "type": "text", + "placeholders_order": [], + "placeholders": {} + }, + "quotaWarningBannerTitle": "You are running out of storage (99%).", + "@quotaWarningBannerTitle": { + "type": "text", + "placeholders_order": [], + "placeholders": {} + }, + "quotaWarningBannerMessage": "Soon you won't be able to email in Tmail. Please clean your storage or upgrade your storage to get full features in Tmail.", + "@quotaWarningBannerMessage": { + "type": "text", + "placeholders_order": [], + "placeholders": {} + }, + "quotaErrorBannerMessage": "Soon you won't be able to email in Tmail. Please clean your storage or upgrade your storage to get full features in Tmail.", + "@quotaErrorBannerMessage": { + "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 f788c916b..210e25dae 100644 --- a/lib/main/localizations/app_localizations.dart +++ b/lib/main/localizations/app_localizations.dart @@ -2547,29 +2547,6 @@ class AppLocalizations { ); } - String textQuotasUsed(double used, double softLimit) { - return Intl.message( - '$used GB of $softLimit GB Used', - name: 'textQuotasUsed', - args: [used, softLimit], - ); - } - - String textQuotasRunningOutOfStorageTitle(double progress) { - return Intl.message( - 'You are running out of storage ($progress%).', - name: 'textQuotasRunningOutOfStorageTitle', - args: [progress], - ); - } - - String get textQuotasRunningOutOfStorageContent { - return Intl.message( - "Soon you won't be able to email in Team Mail. Please clean your storage or upgrade your storage to get full features in Team Mail.", - name: 'textQuotasRunningOutOfStorageContent', - ); - } - String get textQuotasOutOfStorage { return Intl.message( 'Out of storage', @@ -2577,20 +2554,6 @@ class AppLocalizations { ); } - String get textQuotasRunOutOfStorageTitle { - return Intl.message( - 'You have run out of storage space', - name: 'textQuotasRunOutOfStorageTitle', - ); - } - - String get textQuotasRunOutOfStorageContent { - return Intl.message( - "Now you temporarily can't send or get an email. Please free up or upgrade your storage to get the full features of Team Mail.", - name: 'textQuotasRunOutOfStorageContent', - ); - } - String get quickCreatingRule { return Intl.message( 'Create a rule with this email', @@ -3234,4 +3197,40 @@ class AppLocalizations { 'Delete all spam emails now', name: 'deleteAllSpamEmailsNow'); } + + String quotaStateLabel(String used, String limit) { + return Intl.message( + '$used of $limit Used', + name: 'quotaStateLabel', + args: [used, limit], + ); + } + + String get quotaErrorBannerTitle { + return Intl.message( + 'You have run out of storage space', + name: 'quotaErrorBannerTitle' + ); + } + + String get quotaWarningBannerTitle { + return Intl.message( + 'You are running out of storage (99%).', + name: 'quotaWarningBannerTitle' + ); + } + + String get quotaWarningBannerMessage { + return Intl.message( + 'Soon you won\'t be able to email in Tmail. Please clean your storage or upgrade your storage to get full features in Tmail.', + name: 'quotaWarningBannerMessage' + ); + } + + String get quotaErrorBannerMessage { + return Intl.message( + 'Soon you won\'t be able to email in Tmail. Please clean your storage or upgrade your storage to get full features in Tmail.', + name: 'quotaErrorBannerMessage' + ); + } } \ No newline at end of file