diff --git a/assets/images/ic_attachment_file.svg b/assets/images/ic_attachment_file.svg
new file mode 100644
index 000000000..5dbd3c36c
--- /dev/null
+++ b/assets/images/ic_attachment_file.svg
@@ -0,0 +1,4 @@
+
diff --git a/assets/images/ic_star.svg b/assets/images/ic_flag.svg
similarity index 100%
rename from assets/images/ic_star.svg
rename to assets/images/ic_flag.svg
diff --git a/assets/images/ic_flagged.svg b/assets/images/ic_flagged.svg
new file mode 100644
index 000000000..c7ab48776
--- /dev/null
+++ b/assets/images/ic_flagged.svg
@@ -0,0 +1,3 @@
+
diff --git a/assets/images/ic_more_receiver.svg b/assets/images/ic_more_receiver.svg
new file mode 100644
index 000000000..ed84595bf
--- /dev/null
+++ b/assets/images/ic_more_receiver.svg
@@ -0,0 +1,3 @@
+
diff --git a/assets/images/ic_offline.svg b/assets/images/ic_offline.svg
new file mode 100644
index 000000000..17336fad9
--- /dev/null
+++ b/assets/images/ic_offline.svg
@@ -0,0 +1,3 @@
+
diff --git a/assets/images/ic_online.svg b/assets/images/ic_online.svg
new file mode 100644
index 000000000..0578d1d15
--- /dev/null
+++ b/assets/images/ic_online.svg
@@ -0,0 +1,3 @@
+
diff --git a/core/lib/core.dart b/core/lib/core.dart
index 5b4de79d2..6e5d7965b 100644
--- a/core/lib/core.dart
+++ b/core/lib/core.dart
@@ -3,6 +3,9 @@ library core;
// Extensions
export 'presentation/extensions/color_extension.dart';
export 'presentation/extensions/url_extension.dart';
+export 'presentation/extensions/capitalize_extension.dart';
+export 'presentation/extensions/list_extensions.dart';
+export 'domain/extensions/datetime_extension.dart';
// Utils
export 'presentation/utils/theme_utils.dart';
@@ -19,6 +22,8 @@ export 'presentation/views/text/text_builder.dart';
export 'presentation/views/responsive/responsive_widget.dart';
export 'presentation/views/list/tree_view.dart';
export 'presentation/views/button/button_builder.dart';
+export 'presentation/views/image/avatar_builder.dart';
+export 'presentation/views/list/sliver_grid_delegate_fixed_height.dart';
// Resources
export 'presentation/resources/assets_paths.dart';
diff --git a/core/lib/domain/extensions/datetime_extension.dart b/core/lib/domain/extensions/datetime_extension.dart
new file mode 100644
index 000000000..1b95a08e7
--- /dev/null
+++ b/core/lib/domain/extensions/datetime_extension.dart
@@ -0,0 +1,18 @@
+
+extension DateTimeExtension on DateTime {
+
+ bool isToday() {
+ final now = DateTime.now();
+ return now.day == this.day && now.month == this.month && now.year == this.year;
+ }
+
+ bool isYesterday() {
+ final yesterday = DateTime.now().subtract(Duration(days: 1));
+ return yesterday.day == this.day && yesterday.month == this.month && yesterday.year == this.year;
+ }
+
+ bool isThisYear() {
+ final now = DateTime.now();
+ return now.year == this.year;
+ }
+}
diff --git a/core/lib/presentation/extensions/capitalize_extension.dart b/core/lib/presentation/extensions/capitalize_extension.dart
new file mode 100644
index 000000000..339b20753
--- /dev/null
+++ b/core/lib/presentation/extensions/capitalize_extension.dart
@@ -0,0 +1,6 @@
+
+extension CapitalizeExtension on String {
+ String get inCaps => this.length > 0 ?'${this[0].toUpperCase()}${this.substring(1)}':'';
+ String get allInCaps => this.toUpperCase();
+ String get capitalizeFirstEach => this.replaceAll(RegExp(' +'), ' ').split(" ").map((str) => str.inCaps).join(" ");
+}
\ No newline at end of file
diff --git a/core/lib/presentation/extensions/color_extension.dart b/core/lib/presentation/extensions/color_extension.dart
index 17b7c8f44..23f4f4556 100644
--- a/core/lib/presentation/extensions/color_extension.dart
+++ b/core/lib/presentation/extensions/color_extension.dart
@@ -39,4 +39,11 @@ extension AppColor on Color {
static const bgMailboxListMail = Color(0xFFFBFBFF);
static const bgMessenger = Color(0xFFF2F2F5);
static const textButtonColor = Color(0xFF182952);
+ static const attachmentFileBorderColor = Color(0xFFEAEAEA);
+ static const attachmentFileNameColor = Color(0xFF182952);
+ static const attachmentFileSizeColor = Color(0xFF7E869B);
+ static const avatarColor = Color(0xFFE6E5FF);
+ static const avatarTextColor = Color(0xFF3840F7);
+ static const sentTimeTextColorUnRead = Color(0xFF182952);
+ static const subjectEmailTextColorUnRead = Color(0xFF3840F7);
}
diff --git a/core/lib/presentation/resources/image_paths.dart b/core/lib/presentation/resources/image_paths.dart
index 64824ba8a..fdd3369fe 100644
--- a/core/lib/presentation/resources/image_paths.dart
+++ b/core/lib/presentation/resources/image_paths.dart
@@ -22,10 +22,15 @@ class ImagePaths {
String get icForward => _getImagePath('ic_forward.svg');
String get icReply => _getImagePath('ic_reply.svg');
String get icReplyAll => _getImagePath('ic_reply_all.svg');
- String get icStar => _getImagePath('ic_star.svg');
+ String get icFlag => _getImagePath('ic_flag.svg');
String get icTrash => _getImagePath('ic_trash.svg');
String get icCalendar => _getImagePath('ic_calendar.svg');
String get icShare => _getImagePath('ic_share.svg');
+ String get icAttachmentFile => _getImagePath('ic_attachment_file.svg');
+ String get icOnline => _getImagePath('ic_online.svg');
+ String get icOffline => _getImagePath('ic_offline.svg');
+ String get icFlagged => _getImagePath('ic_flagged.svg');
+ String get icMoreReceiver => _getImagePath('ic_more_receiver.svg');
String _getImagePath(String imageName) {
return AssetsPaths.images + imageName;
diff --git a/core/lib/presentation/views/button/button_builder.dart b/core/lib/presentation/views/button/button_builder.dart
index 78ec79f4f..704543896 100644
--- a/core/lib/presentation/views/button/button_builder.dart
+++ b/core/lib/presentation/views/button/button_builder.dart
@@ -13,6 +13,7 @@ class ButtonBuilder {
String? _icon;
String? _text;
double? _size;
+ double? _padding;
bool? _isVertical;
Key? _key;
@@ -26,6 +27,11 @@ class ButtonBuilder {
return this;
}
+ ButtonBuilder padding(double padding) {
+ _padding = padding;
+ return this;
+ }
+
ButtonBuilder text(String text, {required bool isVertical}) {
_text = text;
_isVertical = isVertical;
@@ -66,7 +72,6 @@ class ButtonBuilder {
mainAxisAlignment: MainAxisAlignment.center,
children: [
_buildIcon(),
- SizedBox(height: 8),
_buildText(),
])
: Row(
@@ -74,7 +79,6 @@ class ButtonBuilder {
mainAxisAlignment: MainAxisAlignment.center,
children: [
_buildIcon(),
- SizedBox(width: 8),
_buildText(),
]);
} else {
@@ -82,7 +86,9 @@ class ButtonBuilder {
}
}
- Widget _buildIcon() => SvgPicture.asset(_icon ?? '', width: _size ?? 24, height: _size ?? 24, fit: BoxFit.fill);
+ Widget _buildIcon() => Padding(
+ padding: EdgeInsets.all(_padding ?? 10),
+ child: SvgPicture.asset(_icon ?? '', width: _size ?? 24, height: _size ?? 24, fit: BoxFit.fill));
Widget _buildText() {
return Text(
diff --git a/core/lib/presentation/views/image/avatar_builder.dart b/core/lib/presentation/views/image/avatar_builder.dart
new file mode 100644
index 000000000..e853eda60
--- /dev/null
+++ b/core/lib/presentation/views/image/avatar_builder.dart
@@ -0,0 +1,64 @@
+import 'package:core/presentation/extensions/color_extension.dart';
+import 'package:flutter/material.dart';
+import 'package:flutter_svg/flutter_svg.dart';
+
+class AvatarBuilder {
+ Key? _key;
+ String? _text;
+ double? _size;
+ String? _iconStatus;
+ Color? _bgColor;
+
+ AvatarBuilder key(Key key) {
+ _key = key;
+ return this;
+ }
+
+ AvatarBuilder size(double size) {
+ _size = size;
+ return this;
+ }
+
+ AvatarBuilder text(String text) {
+ _text = text;
+ return this;
+ }
+
+ AvatarBuilder iconStatus(String iconStatus) {
+ _iconStatus = iconStatus;
+ return this;
+ }
+
+ AvatarBuilder backgroundColor(Color bgColor) {
+ _bgColor = bgColor;
+ return this;
+ }
+
+ Widget build() {
+ return Container(
+ key: _key,
+ width: _size ?? 40,
+ height: _size ?? 40,
+ alignment: Alignment.center,
+ child: Stack(
+ children: [
+ Container(
+ width: _size ?? 40,
+ height: _size ?? 40,
+ alignment: Alignment.center,
+ decoration: BoxDecoration(
+ borderRadius: BorderRadius.circular((_size ?? 40) / 2),
+ border: Border.all(color: Colors.white),
+ color: _bgColor ?? AppColor.avatarColor),
+ child: Text(
+ '${_text ?? ''}',
+ style: TextStyle(fontSize: 20, color: AppColor.avatarTextColor, fontWeight: FontWeight.w500))),
+ if (_iconStatus != null && _iconStatus!.isNotEmpty)
+ Align(
+ child: SvgPicture.asset(_iconStatus!, width: 12, height: 12, fit: BoxFit.fill),
+ alignment: Alignment.bottomRight)
+ ],
+ )
+ );
+ }
+}
\ No newline at end of file
diff --git a/core/lib/presentation/views/list/sliver_grid_delegate_fixed_height.dart b/core/lib/presentation/views/list/sliver_grid_delegate_fixed_height.dart
new file mode 100644
index 000000000..85843486f
--- /dev/null
+++ b/core/lib/presentation/views/list/sliver_grid_delegate_fixed_height.dart
@@ -0,0 +1,64 @@
+import 'package:flutter/rendering.dart';
+
+class SliverGridDelegateFixedHeight
+ extends SliverGridDelegate {
+ /// Creates a delegate that makes grid layouts with a fixed number of tiles in
+ /// the cross axis.
+ ///
+ /// All of the arguments must not be null. The `mainAxisSpacing` and
+ /// `crossAxisSpacing` arguments must not be negative. The `crossAxisCount`
+ /// and `childAspectRatio` arguments must be greater than zero.
+ const SliverGridDelegateFixedHeight({
+ required this.crossAxisCount,
+ this.mainAxisSpacing = 0.0,
+ this.crossAxisSpacing = 0.0,
+ this.height = 56.0,
+ }) : assert(crossAxisCount > 0),
+ assert(mainAxisSpacing >= 0),
+ assert(crossAxisSpacing >= 0),
+ assert(height > 0);
+
+ /// The number of children in the cross axis.
+ final int crossAxisCount;
+
+ /// The number of logical pixels between each child along the main axis.
+ final double mainAxisSpacing;
+
+ /// The number of logical pixels between each child along the cross axis.
+ final double crossAxisSpacing;
+
+ /// The height of the crossAxis.
+ final double height;
+
+ bool _debugAssertIsValid() {
+ assert(crossAxisCount > 0);
+ assert(mainAxisSpacing >= 0.0);
+ assert(crossAxisSpacing >= 0.0);
+ assert(height > 0.0);
+ return true;
+ }
+
+ @override
+ SliverGridLayout getLayout(SliverConstraints constraints) {
+ assert(_debugAssertIsValid());
+ final double usableCrossAxisExtent = constraints.crossAxisExtent - crossAxisSpacing * (crossAxisCount - 1);
+ final double childCrossAxisExtent = usableCrossAxisExtent / crossAxisCount;
+ final double childMainAxisExtent = height;
+ return SliverGridRegularTileLayout(
+ crossAxisCount: crossAxisCount,
+ mainAxisStride: childMainAxisExtent + mainAxisSpacing,
+ crossAxisStride: childCrossAxisExtent + crossAxisSpacing,
+ childMainAxisExtent: childMainAxisExtent,
+ childCrossAxisExtent: childCrossAxisExtent,
+ reverseCrossAxis: axisDirectionIsReversed(constraints.crossAxisDirection),
+ );
+ }
+
+ @override
+ bool shouldRelayout(SliverGridDelegateFixedHeight oldDelegate) {
+ return oldDelegate.crossAxisCount != crossAxisCount ||
+ oldDelegate.mainAxisSpacing != mainAxisSpacing ||
+ oldDelegate.crossAxisSpacing != crossAxisSpacing ||
+ oldDelegate.height != height;
+ }
+}
diff --git a/model/lib/email/email_content.dart b/model/lib/email/email_content.dart
new file mode 100644
index 000000000..af5c633a4
--- /dev/null
+++ b/model/lib/email/email_content.dart
@@ -0,0 +1,30 @@
+
+import 'package:equatable/equatable.dart';
+import 'package:jmap_dart_client/jmap/mail/email/email.dart';
+import 'package:jmap_dart_client/jmap/mail/email/email_body_part.dart';
+import 'package:jmap_dart_client/jmap/mail/email/email_body_value.dart';
+
+class EmailContent with EquatableMixin {
+
+ final EmailId id;
+ final Set? htmlBody;
+ final Set? attachments;
+ final Map? bodyValues;
+
+ EmailContent(
+ this.id,
+ {
+ this.htmlBody,
+ this.attachments,
+ this.bodyValues
+ }
+ );
+
+ @override
+ List