diff --git a/assets/images/ic_checkbox_selected.svg b/assets/images/ic_checkbox_selected.svg new file mode 100644 index 000000000..4d0935a8e --- /dev/null +++ b/assets/images/ic_checkbox_selected.svg @@ -0,0 +1,3 @@ + + + diff --git a/assets/images/ic_checkbox_unselected.svg b/assets/images/ic_checkbox_unselected.svg new file mode 100644 index 000000000..09fac05c5 --- /dev/null +++ b/assets/images/ic_checkbox_unselected.svg @@ -0,0 +1,3 @@ + + + diff --git a/core/lib/presentation/extensions/color_extension.dart b/core/lib/presentation/extensions/color_extension.dart index c639226f4..4d859cdf1 100644 --- a/core/lib/presentation/extensions/color_extension.dart +++ b/core/lib/presentation/extensions/color_extension.dart @@ -226,6 +226,8 @@ extension AppColor on Color { static const labelColor = Color(0xFF71767C); static const thumbScrollbarColor = Color(0xFFC1C1C1); static const loginViewShadowColor = Color(0x3DBCBCBC); + static const colorEmailTileCheckboxUnhover = Color(0xFFAEB7C2); + static const colorEmailTileHoverWeb = Color(0xFFDFEEFF); static const mapGradientColor = [ [Color(0xFF21D4FD), Color(0xFFB721FF)], diff --git a/core/lib/presentation/resources/image_paths.dart b/core/lib/presentation/resources/image_paths.dart index a038a0488..31228104a 100644 --- a/core/lib/presentation/resources/image_paths.dart +++ b/core/lib/presentation/resources/image_paths.dart @@ -214,6 +214,8 @@ class ImagePaths { String get icAlwaysReadReceipt => _getImagePath('ic_always_read_receipt.svg'); String get icNotification => _getImagePath('ic_notification.svg'); String get icRemoveRule => _getImagePath('ic_remove_rule.svg'); + String get icCheckboxUnselected => _getImagePath('ic_checkbox_unselected.svg'); + String get icCheckboxSelected => _getImagePath('ic_checkbox_selected.svg'); String _getImagePath(String imageName) { return AssetsPaths.images + imageName; diff --git a/core/lib/presentation/views/button/icon_button_web.dart b/core/lib/presentation/views/button/icon_button_web.dart index 880cbe56c..1269ab16e 100644 --- a/core/lib/presentation/views/button/icon_button_web.dart +++ b/core/lib/presentation/views/button/icon_button_web.dart @@ -18,19 +18,23 @@ Widget buildIconWeb({ Color? colorSelected, Color? colorFocus, ShapeBorder? shapeBorder, + EdgeInsetsGeometry? margin, }) { - return Material( - color: colorSelected ?? Colors.transparent, - shape: shapeBorder ?? const CircleBorder(), - child: IconButton( - icon: icon, - focusColor: colorFocus, - iconSize: iconSize, - constraints: minSize != null ? BoxConstraints(minWidth: minSize, minHeight: minSize) : null, - padding: iconPadding ?? const EdgeInsets.all(8.0), - splashRadius: splashRadius ?? 15, - tooltip: tooltip ?? '', - onPressed: onTap) + return Container( + margin: margin, + child: Material( + color: colorSelected ?? Colors.transparent, + shape: shapeBorder ?? const CircleBorder(), + child: IconButton( + icon: icon, + focusColor: colorFocus, + iconSize: iconSize, + constraints: minSize != null ? BoxConstraints(minWidth: minSize, minHeight: minSize) : null, + padding: iconPadding ?? const EdgeInsets.all(8.0), + splashRadius: splashRadius ?? 15, + tooltip: tooltip ?? '', + onPressed: onTap) + ), ); } diff --git a/lib/features/thread/presentation/thread_view.dart b/lib/features/thread/presentation/thread_view.dart index 5de518f76..a9515f60e 100644 --- a/lib/features/thread/presentation/thread_view.dart +++ b/lib/features/thread/presentation/thread_view.dart @@ -50,7 +50,7 @@ class ThreadView extends GetWidget @override Widget build(BuildContext context) { return GestureDetector( - onTap: () => FocusManager.instance.primaryFocus?.unfocus(), + onTap: FocusManager.instance.primaryFocus?.unfocus, child: Scaffold( resizeToAvoidBottomInset: false, backgroundColor: Colors.white, @@ -510,68 +510,62 @@ class ThreadView extends GetWidget ), background: Container( color: AppColor.colorItemRecipientSelected, - child: Padding( - padding: const EdgeInsetsDirectional.only(start: 16), - child: Align( - alignment: AlignmentDirectional.centerStart, - child: Row( - children: [ - CircleAvatar( - backgroundColor: AppColor.colorSpamReportBannerBackground, - radius: 24, - child: !presentationEmail.hasRead - ? SvgPicture.asset( - controller.imagePaths.icMarkAsRead, - fit: BoxFit.fill, - ) - : SvgPicture.asset( - controller.imagePaths.icUnreadEmail, - fit: BoxFit.fill, - colorFilter: AppColor.primaryColor.asFilter(), - ), - ), - const SizedBox(width: 11), - Text( - !presentationEmail.hasRead - ? AppLocalizations.of(context).mark_as_read - : AppLocalizations.of(context).mark_as_unread, - style: const TextStyle( - fontSize: 15, - color: AppColor.primaryColor, - ), - ), - ], + padding: const EdgeInsetsDirectional.only(start: 16), + alignment: AlignmentDirectional.centerStart, + child: Row( + children: [ + CircleAvatar( + backgroundColor: AppColor.colorSpamReportBannerBackground, + radius: 24, + child: !presentationEmail.hasRead + ? SvgPicture.asset( + controller.imagePaths.icMarkAsRead, + fit: BoxFit.fill, + ) + : SvgPicture.asset( + controller.imagePaths.icUnreadEmail, + fit: BoxFit.fill, + colorFilter: AppColor.primaryColor.asFilter(), + ), ), - ), + const SizedBox(width: 11), + Text( + !presentationEmail.hasRead + ? AppLocalizations.of(context).mark_as_read + : AppLocalizations.of(context).mark_as_unread, + style: const TextStyle( + fontSize: 15, + color: AppColor.primaryColor, + ), + ), + ], ), ), secondaryBackground: controller.isInArchiveMailbox(presentationEmail) == false ? Container( color: AppColor.colorItemRecipientSelected, padding: const EdgeInsetsDirectional.only(end: 16), - child: Align( - alignment: AlignmentDirectional.centerEnd, - child: Row( - children: [ - const Spacer(), - CircleAvatar( - backgroundColor: AppColor.colorSpamReportBannerBackground, - radius: 24, - child: SvgPicture.asset( - controller.imagePaths.icMailboxArchived, - fit: BoxFit.fill, - ) + alignment: AlignmentDirectional.centerEnd, + child: Row( + children: [ + const Spacer(), + CircleAvatar( + backgroundColor: AppColor.colorSpamReportBannerBackground, + radius: 24, + child: SvgPicture.asset( + controller.imagePaths.icMailboxArchived, + fit: BoxFit.fill, + ) + ), + const SizedBox(width: 11), + Text( + AppLocalizations.of(context).archiveMessage, + style: const TextStyle( + fontSize: 15, + color: AppColor.primaryColor, ), - const SizedBox(width: 11), - Text( - AppLocalizations.of(context).archiveMessage, - style: const TextStyle( - fontSize: 15, - color: AppColor.primaryColor, - ), - ), - ], - ), + ), + ], ), ) : null, diff --git a/lib/features/thread/presentation/widgets/email_tile_web_builder.dart b/lib/features/thread/presentation/widgets/email_tile_web_builder.dart index dfc796818..abb8241a4 100644 --- a/lib/features/thread/presentation/widgets/email_tile_web_builder.dart +++ b/lib/features/thread/presentation/widgets/email_tile_web_builder.dart @@ -331,33 +331,56 @@ class _EmailTileBuilderState extends State with BaseEmailItem widget.presentationEmail ), onHover: (value) => _hoverNotifier.value = value, + hoverColor: AppColor.colorEmailTileHoverWeb, borderRadius: const BorderRadius.all(Radius.circular(14)), child: Container( padding: widget.padding ?? _getPaddingItem(context), decoration: _getDecorationItem(), alignment: Alignment.center, child: Row(children: [ - Container( - padding: const EdgeInsetsDirectional.symmetric(horizontal: 16), - alignment: Alignment.center, - child: !widget.presentationEmail.hasRead - ? SvgPicture.asset( - imagePaths.icUnreadStatus, - width: 9, - height: 9, - fit: BoxFit.fill - ) - : const SizedBox(width: 9) + const SizedBox(width: 10), + buildIconWeb( + icon: ValueListenableBuilder( + valueListenable: _hoverNotifier, + builder: (context, isHovered, child) { + return SvgPicture.asset( + widget.presentationEmail.isSelected + ? imagePaths.icCheckboxSelected + : imagePaths.icCheckboxUnselected, + colorFilter: ColorFilter.mode( + isHovered || widget.presentationEmail.isSelected + ? AppColor.primaryColor + : AppColor.colorEmailTileCheckboxUnhover, + BlendMode.srcIn), + width: 20, + height: 20); + }, + ), + margin: const EdgeInsets.symmetric(vertical: 6), + iconPadding: EdgeInsets.zero, + minSize: 28, + tooltip: widget.presentationEmail.isSelected + ? AppLocalizations.of(context).selected + : AppLocalizations.of(context).notSelected, + onTap: () { + widget.emailActionClick?.call( + EmailActionType.selection, + widget.presentationEmail + ); + }, ), buildIconWeb( icon: SvgPicture.asset( widget.presentationEmail.hasStarred ? imagePaths.icStar : imagePaths.icUnStar, - width: 16, - height: 16, + width: 20, + height: 20, fit: BoxFit.fill ), + margin: const EdgeInsets.symmetric(vertical: 6), + iconPadding: EdgeInsets.zero, + minSize: 28, tooltip: widget.presentationEmail.hasStarred ? AppLocalizations.of(context).starred : AppLocalizations.of(context).not_starred, @@ -371,31 +394,45 @@ class _EmailTileBuilderState extends State with BaseEmailItem buildIconWeb( icon: buildIconAnsweredOrForwarded(presentationEmail: widget.presentationEmail), tooltip: messageToolTipForAnsweredOrForwarded(context, widget.presentationEmail), - iconPadding: const EdgeInsetsDirectional.only(end: 12), + margin: const EdgeInsets.symmetric(vertical: 6), + iconPadding: EdgeInsets.zero, + minSize: 28, splashRadius: 1 ), - MouseRegion( - cursor: SystemMouseCursors.click, - child: GestureDetector( - onTap: () => widget.emailActionClick?.call( - EmailActionType.selection, + buildIconWeb( + icon: widget.presentationEmail.hasRead + ? const SizedBox(width: 20, height: 20) + : Container( + alignment: Alignment.center, + width: 20, + height: 20, + child: SvgPicture.asset( + imagePaths.icUnreadStatus, + width: 9, + height: 9, + fit: BoxFit.fill + ), + ), + margin: const EdgeInsets.symmetric(vertical: 6), + iconPadding: EdgeInsets.zero, + minSize: 28, + tooltip: widget.presentationEmail.hasRead + ? null + : AppLocalizations.of(context).mark_as_read, + onTap: widget.presentationEmail.hasRead ? null : () { + widget.emailActionClick?.call( + EmailActionType.markAsRead, widget.presentationEmail - ), - child: ValueListenableBuilder( - valueListenable: _hoverNotifier, - builder: (context, value, child) { - return _buildAvatarIcon( - context: context, - isHovered: value, - iconSize: 32, - textStyle: const TextStyle( - fontSize: 12, - fontWeight: FontWeight.w600, - color: Colors.white - ) - ); - } - ), + ); + }, + ), + buildIconAvatarText( + widget.presentationEmail, + iconSize: 32, + textStyle: const TextStyle( + fontSize: 12, + fontWeight: FontWeight.w600, + color: Colors.white ), ), const SizedBox(width: 10), @@ -445,8 +482,8 @@ class _EmailTileBuilderState extends State with BaseEmailItem responsiveUtils.isDesktop(context) ) { return const BoxDecoration( - borderRadius: BorderRadius.all(Radius.circular(14)), - color: AppColor.colorItemEmailSelectedDesktop); + borderRadius: BorderRadius.all(Radius.circular(8)), + color: AppColor.colorEmailTileHoverWeb); } else if (widget.isShowingEmailContent && responsiveUtils.isTabletLarge(context)) { return const BoxDecoration(color: AppColor.colorItemEmailSelectedDesktop); } else { @@ -459,9 +496,7 @@ class _EmailTileBuilderState extends State with BaseEmailItem } EdgeInsets _getPaddingIcon(BuildContext context) { - return responsiveUtils.isDesktop(context) - ? const EdgeInsets.all(8) - : const EdgeInsets.all(5); + return const EdgeInsets.all(5); } Widget _buildListActionButtonWhenHover(BuildContext context) { @@ -479,7 +514,7 @@ class _EmailTileBuilderState extends State with BaseEmailItem ), if(!widget.presentationEmail.isDraft) buildSVGIconButton( - icon: widget.presentationEmail.hasRead ? imagePaths.icRead: imagePaths.icUnread, + icon: widget.presentationEmail.hasRead ? imagePaths.icUnread: imagePaths.icRead, iconColor: AppColor.colorActionButtonHover, iconSize: _getIconSize(context), padding: _getPaddingIcon(context), diff --git a/lib/l10n/intl_messages.arb b/lib/l10n/intl_messages.arb index 72f7bf426..870f8bed6 100644 --- a/lib/l10n/intl_messages.arb +++ b/lib/l10n/intl_messages.arb @@ -842,6 +842,18 @@ "placeholders_order": [], "placeholders": {} }, + "selected": "Selected", + "@selected": { + "type": "text", + "placeholders_order": [], + "placeholders": {} + }, + "notSelected": "Not selected", + "@notSelected": { + "type": "text", + "placeholders_order": [], + "placeholders": {} + }, "more": "More", "@more": { "type": "text", diff --git a/lib/main/localizations/app_localizations.dart b/lib/main/localizations/app_localizations.dart index 29fc74925..86a25edd8 100644 --- a/lib/main/localizations/app_localizations.dart +++ b/lib/main/localizations/app_localizations.dart @@ -870,6 +870,20 @@ class AppLocalizations { ); } + String get selected { + return Intl.message( + 'Selected', + name: 'selected', + ); + } + + String get notSelected { + return Intl.message( + 'Not selected', + name: 'notSelected', + ); + } + String get more { return Intl.message( 'More',