diff --git a/assets/images/ic_encrypted.svg b/assets/images/ic_encrypted.svg index f082a53915..4a461b2b26 100644 --- a/assets/images/ic_encrypted.svg +++ b/assets/images/ic_encrypted.svg @@ -1,7 +1,3 @@ - - - - - - + + diff --git a/assets/l10n/intl_en.arb b/assets/l10n/intl_en.arb index 06009fd63a..d8b2473239 100644 --- a/assets/l10n/intl_en.arb +++ b/assets/l10n/intl_en.arb @@ -899,7 +899,7 @@ "type": "text", "placeholders": {} }, - "friday": "Friday", + "friday": "Fri", "@friday": { "type": "text", "placeholders": {} @@ -1247,7 +1247,7 @@ "type": "text", "placeholders": {} }, - "monday": "Monday", + "monday": "Mon", "@monday": { "type": "text", "placeholders": {} @@ -1692,7 +1692,7 @@ "type": "text", "placeholders": {} }, - "saturday": "Saturday", + "saturday": "Sat", "@saturday": { "type": "text", "placeholders": {} @@ -1951,7 +1951,7 @@ "type": "text", "placeholders": {} }, - "sunday": "Sunday", + "sunday": "Sun", "@sunday": { "type": "text", "placeholders": {} @@ -1981,7 +1981,7 @@ "type": "text", "placeholders": {} }, - "thursday": "Thursday", + "thursday": "Thu", "@thursday": { "type": "text", "placeholders": {} @@ -2022,7 +2022,7 @@ "type": "text", "placeholders": {} }, - "tuesday": "Tuesday", + "tuesday": "Tue", "@tuesday": { "type": "text", "placeholders": {} @@ -2199,7 +2199,7 @@ "type": "text", "placeholders": {} }, - "wednesday": "Wednesday", + "wednesday": "Wed", "@wednesday": { "type": "text", "placeholders": {} @@ -3102,5 +3102,7 @@ "sCameraLensDirectionLabel": "Camera lens direction: {value}", "sCameraPreviewLabel": "Camera preview: {value}", "sFlashModeLabel": "Flash mode: {mode}", - "sSwitchCameraLensDirectionLabel": "Switch to the {value} camera" + "sSwitchCameraLensDirectionLabel": "Switch to the {value} camera", + "photo": "Photo", + "video": "Video" } diff --git a/assets/l10n/intl_fr.arb b/assets/l10n/intl_fr.arb index 0c0675d197..918796e827 100644 --- a/assets/l10n/intl_fr.arb +++ b/assets/l10n/intl_fr.arb @@ -809,11 +809,6 @@ "type": "text", "placeholders": {} }, - "friday": "Vendredi", - "@friday": { - "type": "text", - "placeholders": {} - }, "fromJoining": "À partir de l'entrée dans le salon", "@fromJoining": { "type": "text", @@ -1143,11 +1138,6 @@ "type": "text", "placeholders": {} }, - "monday": "Lundi", - "@monday": { - "type": "text", - "placeholders": {} - }, "muteChat": "Mettre la discussion en sourdine", "@muteChat": { "type": "text", @@ -1541,11 +1531,6 @@ "type": "text", "placeholders": {} }, - "saturday": "Samedi", - "@saturday": { - "type": "text", - "placeholders": {} - }, "saveFile": "Enregistrer le fichier", "@saveFile": { "type": "text", @@ -1785,11 +1770,6 @@ "type": "text", "placeholders": {} }, - "sunday": "Dimanche", - "@sunday": { - "type": "text", - "placeholders": {} - }, "synchronizingPleaseWait": "Synchronisation... Veuillez patienter.", "@synchronizingPleaseWait": { "type": "text", @@ -1815,11 +1795,6 @@ "type": "text", "placeholders": {} }, - "thursday": "Jeudi", - "@thursday": { - "type": "text", - "placeholders": {} - }, "title": "FluffyChat", "@title": { "description": "Title for the application", @@ -1856,11 +1831,6 @@ "type": "text", "placeholders": {} }, - "tuesday": "Mardi", - "@tuesday": { - "type": "text", - "placeholders": {} - }, "unavailable": "Indisponible", "@unavailable": { "type": "text", @@ -2031,11 +2001,6 @@ "type": "text", "placeholders": {} }, - "wednesday": "Mercredi", - "@wednesday": { - "type": "text", - "placeholders": {} - }, "weSentYouAnEmail": "Nous vous avons envoyé un message", "@weSentYouAnEmail": { "type": "text", diff --git a/assets/l10n/intl_ru.arb b/assets/l10n/intl_ru.arb index 1ffd3ef016..0947457f92 100644 --- a/assets/l10n/intl_ru.arb +++ b/assets/l10n/intl_ru.arb @@ -800,11 +800,6 @@ "type": "text", "placeholders": {} }, - "friday": "Пятница", - "@friday": { - "type": "text", - "placeholders": {} - }, "fromJoining": "С момента присоединения", "@fromJoining": { "type": "text", @@ -1134,11 +1129,6 @@ "type": "text", "placeholders": {} }, - "monday": "Понедельник", - "@monday": { - "type": "text", - "placeholders": {} - }, "muteChat": "Отключить уведомления", "@muteChat": { "type": "text", @@ -1527,11 +1517,6 @@ "type": "text", "placeholders": {} }, - "saturday": "Суббота", - "@saturday": { - "type": "text", - "placeholders": {} - }, "saveFile": "Сохранить файл", "@saveFile": { "type": "text", @@ -1770,11 +1755,6 @@ "type": "text", "placeholders": {} }, - "sunday": "Воскресенье", - "@sunday": { - "type": "text", - "placeholders": {} - }, "synchronizingPleaseWait": "Синхронизация… Пожалуйста, подождите.", "@synchronizingPleaseWait": { "type": "text", @@ -1800,11 +1780,6 @@ "type": "text", "placeholders": {} }, - "thursday": "Четверг", - "@thursday": { - "type": "text", - "placeholders": {} - }, "title": "FluffyChat", "@title": { "description": "Title for the application", @@ -1841,11 +1816,6 @@ "type": "text", "placeholders": {} }, - "tuesday": "Вторник", - "@tuesday": { - "type": "text", - "placeholders": {} - }, "unavailable": "Недоступен", "@unavailable": { "type": "text", @@ -2016,11 +1986,6 @@ "type": "text", "placeholders": {} }, - "wednesday": "Среда", - "@wednesday": { - "type": "text", - "placeholders": {} - }, "weSentYouAnEmail": "Мы отправили вам электронное письмо", "@weSentYouAnEmail": { "type": "text", diff --git a/lib/pages/chat/chat_app_bar_title.dart b/lib/pages/chat/chat_app_bar_title.dart index 8125ec8505..0e61b020ed 100644 --- a/lib/pages/chat/chat_app_bar_title.dart +++ b/lib/pages/chat/chat_app_bar_title.dart @@ -91,10 +91,11 @@ class ChatAppBarTitle extends StatelessWidget { padding: const EdgeInsets.all(2.0), child: SvgPicture.asset( ImagePaths.icEncrypted, - width: 20, - height: 20, + width: 16, + height: 16, ), ), + const SizedBox(width: 4), Flexible( child: Text( roomName ?? diff --git a/lib/pages/chat_list/chat_list.dart b/lib/pages/chat_list/chat_list.dart index b3511394dc..1d222ed917 100644 --- a/lib/pages/chat_list/chat_list.dart +++ b/lib/pages/chat_list/chat_list.dart @@ -788,7 +788,6 @@ class ChatListController extends State WidgetsBinding.instance.addPostFrameCallback((_) async { if (mounted) { Matrix.of(context).backgroundPush?.setupPush(); - await matrixState.retrievePersistedActiveClient(); } }); _checkTorBrowser(); diff --git a/lib/pages/chat_list/chat_list_body_view.dart b/lib/pages/chat_list/chat_list_body_view.dart index 86c8767d37..d946d4c341 100644 --- a/lib/pages/chat_list/chat_list_body_view.dart +++ b/lib/pages/chat_list/chat_list_body_view.dart @@ -7,7 +7,6 @@ import 'package:fluffychat/pages/chat_list/chat_list_view_builder.dart'; import 'package:fluffychat/pages/chat_list/space_view.dart'; import 'package:fluffychat/presentation/enum/chat_list/chat_list_enum.dart'; import 'package:fluffychat/resource/image_paths.dart'; -import 'package:fluffychat/utils/extension/value_notifier_extension.dart'; import 'package:fluffychat/utils/stream_extension.dart'; import 'package:fluffychat/widgets/connection_status_header.dart'; import 'package:flutter/material.dart'; @@ -148,15 +147,7 @@ class ChatListBodyView extends StatelessWidget { mainAxisSize: MainAxisSize.min, crossAxisAlignment: CrossAxisAlignment.start, children: [ - ExpandableTitleBuilder( - title: L10n.of(context)!.countPinChat( - controller.filteredRoomsForPin.length, - ), - isExpanded: isExpanded, - onTap: controller - .expandRoomsForPinNotifier.toggle, - ), - if (isExpanded) child!, + child!, ], ); }, @@ -166,33 +157,15 @@ class ChatListBodyView extends StatelessWidget { ), ), if (!controller.filteredRoomsForAllIsEmpty) - ValueListenableBuilder( - valueListenable: controller.expandRoomsForAllNotifier, - builder: (context, isExpanded, child) { - return Padding( - padding: ChatListBodyViewStyle - .paddingTopExpandableTitleBuilder, - child: Column( - mainAxisSize: MainAxisSize.min, - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - ExpandableTitleBuilder( - title: L10n.of(context)!.countAllChat( - controller.filteredRoomsForAll.length, - ), - isExpanded: isExpanded, - onTap: controller - .expandRoomsForAllNotifier.toggle, - ), - if (isExpanded) child!, - ], - ), - ); - }, - child: ChatListViewBuilder( - controller: controller, - rooms: controller.filteredRoomsForAll, - ), + Column( + mainAxisSize: MainAxisSize.min, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + ChatListViewBuilder( + controller: controller, + rooms: controller.filteredRoomsForAll, + ), + ], ), ], ), diff --git a/lib/pages/chat_list/chat_list_header_style.dart b/lib/pages/chat_list/chat_list_header_style.dart index 255f7d0fa4..749002c447 100644 --- a/lib/pages/chat_list/chat_list_header_style.dart +++ b/lib/pages/chat_list/chat_list_header_style.dart @@ -44,7 +44,7 @@ class ChatListHeaderStyle { prefixIcon: Icon( Icons.search, size: ChatListHeaderStyle.searchIconSize, - color: prefixIconColor ?? Theme.of(context).colorScheme.onSurface, + color: prefixIconColor ?? LinagoraRefColors.material().neutral[60], ), suffixIcon: const SizedBox.shrink(), ); diff --git a/lib/pages/chat_list/chat_list_item.dart b/lib/pages/chat_list/chat_list_item.dart index e1c78d5e74..15ef3afa99 100644 --- a/lib/pages/chat_list/chat_list_item.dart +++ b/lib/pages/chat_list/chat_list_item.dart @@ -1,5 +1,4 @@ import 'package:adaptive_dialog/adaptive_dialog.dart'; -import 'package:fluffychat/config/app_config.dart'; import 'package:fluffychat/presentation/mixins/chat_list_item_mixin.dart'; import 'package:fluffychat/pages/chat_list/chat_list_item_style.dart'; import 'package:fluffychat/pages/chat_list/chat_list_item_subtitle.dart'; @@ -91,66 +90,86 @@ class ChatListItem extends StatelessWidget with ChatListItemMixin { MatrixLocals(L10n.of(context)!), ); return Padding( - padding: ChatListItemStyle.paddingConversation, + padding: ChatListItemStyle.padding, child: Material( - borderRadius: BorderRadius.circular(AppConfig.borderRadius), + borderRadius: ChatListItemStyle.chatlistItemBorderRadius, clipBehavior: Clip.hardEdge, color: isSelectedItem ? Theme.of(context).colorScheme.primaryContainer : activeChat ? Theme.of(context).colorScheme.secondaryContainer : Colors.transparent, - child: InkWell( - onTap: () => clickAction(context), - onSecondaryTapDown: onSecondaryTapDown, - onLongPress: onLongPress, - child: Container( - height: ChatListItemStyle.chatItemHeight, - padding: ChatListItemStyle.paddingBody, - child: Row( - children: [ - if (isEnableSelectMode) checkBoxWidget ?? const SizedBox(), - Padding( - padding: ChatListItemStyle.paddingAvatar, - child: Stack( - children: [ - Avatar( - mxContent: room.avatar, - name: displayName, - onTap: onTapAvatar, - ), - if (_isGroupChat) - Positioned( - bottom: 0, - right: 0, - child: Container( - padding: ChatListItemStyle.paddingIconGroup, - decoration: BoxDecoration( - shape: BoxShape.circle, - color: Theme.of(context).colorScheme.onPrimary, - ), - child: Icon( - Icons.group, - size: ChatListItemStyle.groupIconSize, - color: room.isUnreadOrInvited - ? LinagoraSysColors.material() - .onSurfaceVariant - : LinagoraRefColors.material().tertiary[30], + child: Container( + decoration: BoxDecoration( + border: Border( + bottom: BorderSide( + color: + LinagoraStateLayer(LinagoraSysColors.material().surfaceTint) + .opacityLayer3, + width: ChatListItemStyle.chatListBottomBorderWidht, + ), + ), + ), + child: InkWell( + onTap: () => clickAction(context), + onSecondaryTapDown: onSecondaryTapDown, + onLongPress: onLongPress, + borderRadius: ChatListItemStyle.chatlistItemBorderRadius, + child: Container( + height: ChatListItemStyle.chatItemHeight, + padding: ChatListItemStyle.paddingBody, + decoration: BoxDecoration( + borderRadius: ChatListItemStyle.chatlistItemBorderRadius, + ), + child: Row( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + if (isEnableSelectMode) checkBoxWidget ?? const SizedBox(), + Padding( + padding: ChatListItemStyle.paddingAvatar, + child: Stack( + children: [ + Avatar( + mxContent: room.avatar, + name: displayName, + onTap: onTapAvatar, + ), + if (_isGroupChat) + Positioned( + bottom: 0, + right: 0, + child: Container( + padding: ChatListItemStyle.paddingIconGroup, + decoration: BoxDecoration( + shape: BoxShape.circle, + color: Theme.of(context).colorScheme.onPrimary, + ), + child: Icon( + Icons.group, + size: ChatListItemStyle.groupIconSize, + color: room.isUnreadOrInvited + ? LinagoraSysColors.material() + .onSurfaceVariant + : LinagoraRefColors.material().tertiary[30], + ), ), ), - ), - ], + ], + ), ), - ), - Expanded( - child: Column( - children: [ - ChatListItemTitle(room: room), - ChatListItemSubtitle(room: room), - ], + Expanded( + child: Column( + mainAxisAlignment: MainAxisAlignment.start, + children: [ + ChatListItemTitle( + room: room, + ), + ChatListItemSubtitle(room: room), + ], + ), ), - ), - ], + ], + ), ), ), ), diff --git a/lib/pages/chat_list/chat_list_item_style.dart b/lib/pages/chat_list/chat_list_item_style.dart index 56111fe7ca..953b14a99f 100644 --- a/lib/pages/chat_list/chat_list_item_style.dart +++ b/lib/pages/chat_list/chat_list_item_style.dart @@ -5,7 +5,7 @@ class ChatListItemStyle { static Color? get readIconColor => LinagoraRefColors.material().tertiary[20]; static Color? get pinnedIconColor => - LinagoraRefColors.material().tertiary[30]; + LinagoraRefColors.material().tertiary[40]; static const double readIconSize = 20; @@ -13,7 +13,7 @@ class ChatListItemStyle { static const double mentionIconWidth = 20; - static const double chatItemHeight = 85; + static const double chatItemHeight = 80; static double unreadBadgeSize( bool unread, @@ -27,14 +27,19 @@ class ChatListItemStyle { : 0.0; } - static const EdgeInsetsDirectional paddingConversation = - EdgeInsetsDirectional.symmetric( + static const EdgeInsets paddingConversation = EdgeInsets.fromLTRB( + 8, + 8, + 8, + 8, + ); + + static const EdgeInsets padding = EdgeInsets.symmetric( horizontal: 8, - vertical: 2, ); static const EdgeInsetsDirectional paddingAvatar = - EdgeInsetsDirectional.only(end: 8); + EdgeInsetsDirectional.only(start: 8, end: 8); static const EdgeInsetsDirectional paddingIconGroup = EdgeInsetsDirectional.all(4); @@ -57,4 +62,10 @@ class ChatListItemStyle { } static const double letterSpaceDisplayName = 0.15; + + static final chatlistItemBorderRadius = BorderRadius.circular(4); + + static const paddingIcon = EdgeInsets.only(bottom: 4); + + static const chatListBottomBorderWidht = 1.0; } diff --git a/lib/pages/chat_list/chat_list_item_subtitle.dart b/lib/pages/chat_list/chat_list_item_subtitle.dart index af3b8afe30..e392b86739 100644 --- a/lib/pages/chat_list/chat_list_item_subtitle.dart +++ b/lib/pages/chat_list/chat_list_item_subtitle.dart @@ -1,5 +1,6 @@ import 'package:fluffychat/config/app_config.dart'; import 'package:fluffychat/config/themes.dart'; +import 'package:fluffychat/domain/model/room/room_extension.dart'; import 'package:fluffychat/presentation/mixins/chat_list_item_mixin.dart'; import 'package:fluffychat/pages/chat_list/chat_list_item_style.dart'; import 'package:fluffychat/utils/matrix_sdk_extensions/matrix_locals.dart'; @@ -9,6 +10,7 @@ import 'package:fluffychat/widgets/matrix.dart'; import 'package:flutter/material.dart'; import 'package:flutter_gen/gen_l10n/l10n.dart'; import 'package:linagora_design_flutter/colors/linagora_ref_colors.dart'; +import 'package:linagora_design_flutter/colors/linagora_sys_colors.dart'; import 'package:matrix/matrix.dart'; class ChatListItemSubtitle extends StatelessWidget with ChatListItemMixin { @@ -25,6 +27,15 @@ class ChatListItemSubtitle extends StatelessWidget with ChatListItemMixin { room.hasNewMessages, room.notificationCount > 0, ); + final isMediaEvent = room.lastEvent?.messageType == MessageTypes.Image || + room.lastEvent?.messageType == MessageTypes.Video; + + final haveNotificationsAndMuted = + room.notificationCount > 0 && room.isMuted; + + final haveNotificationsOrUnread = + room.notificationCount > 0 || room.markedUnread; + return Row( mainAxisAlignment: MainAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start, @@ -32,17 +43,22 @@ class ChatListItemSubtitle extends StatelessWidget with ChatListItemMixin { Expanded( child: typingText.isNotEmpty ? typingTextWidget(typingText, context) - : (isGroup + : isGroup ? chatListItemSubtitleForGroup( context: context, room: room, ) - : textContentWidget( - room, - context, - isGroup, - room.isUnreadOrInvited, - )), + : isMediaEvent + ? chatlistItemMediaPreviewSubTitle( + context, + room, + ) + : textContentWidget( + room, + context, + isGroup, + room.isUnreadOrInvited, + ), ), const SizedBox(width: 8), FutureBuilder( @@ -60,39 +76,49 @@ class ChatListItemSubtitle extends StatelessWidget with ChatListItemMixin { room.lastEvent == null) { return const SizedBox.shrink(); } - final isMentionned = snapshot.data! .getAllMentionedUserIdsFromMessage(room) .contains(Matrix.of(context).client.userID); - return AnimatedContainer( - duration: TwakeThemes.animationDuration, - curve: TwakeThemes.animationCurve, - padding: const EdgeInsets.only(bottom: 4), - height: ChatListItemStyle.mentionIconWidth, - width: isMentionned && room.isUnreadOrInvited - ? ChatListItemStyle.mentionIconWidth - : 0, - decoration: BoxDecoration( - color: Theme.of(context).colorScheme.primary, - borderRadius: BorderRadius.circular(AppConfig.borderRadius), - ), - child: Center( - child: isMentionned && room.isUnreadOrInvited - ? Text( - '@', - style: TextStyle( - color: isMentionned - ? Theme.of(context).colorScheme.onPrimary - : Theme.of(context) - .colorScheme - .onPrimaryContainer, - fontSize: - Theme.of(context).textTheme.labelMedium?.fontSize, - ), - ) - : Container(), - ), - ); + return room.lastEvent?.senderId == Matrix.of(context).client.userID + ? Icon( + Icons.done_all, + color: room.lastEvent!.receipts.isEmpty + ? LinagoraRefColors.material().tertiary[30] + : LinagoraSysColors.material().secondary, + size: 20, + ) + : AnimatedContainer( + duration: TwakeThemes.animationDuration, + curve: TwakeThemes.animationCurve, + padding: const EdgeInsets.only(bottom: 4), + height: ChatListItemStyle.mentionIconWidth, + width: isMentionned && room.isUnreadOrInvited + ? ChatListItemStyle.mentionIconWidth + : 0, + decoration: BoxDecoration( + color: Theme.of(context).colorScheme.primary, + borderRadius: + BorderRadius.circular(AppConfig.borderRadius), + ), + child: Center( + child: isMentionned && room.isUnreadOrInvited + ? Text( + '@', + style: TextStyle( + color: isMentionned + ? Theme.of(context).colorScheme.onPrimary + : Theme.of(context) + .colorScheme + .onPrimaryContainer, + fontSize: Theme.of(context) + .textTheme + .labelMedium + ?.fontSize, + ), + ) + : Container(), + ), + ); }, ), const SizedBox(width: 4), @@ -110,9 +136,11 @@ class ChatListItemSubtitle extends StatelessWidget with ChatListItemMixin { color: room.highlightCount > 0 || room.membership == Membership.invite ? Theme.of(context).colorScheme.primary - : room.notificationCount > 0 || room.markedUnread - ? Theme.of(context).colorScheme.primary - : LinagoraRefColors.material().tertiary[30], + : haveNotificationsAndMuted + ? LinagoraRefColors.material().tertiary[30] + : haveNotificationsOrUnread + ? Theme.of(context).colorScheme.primary + : LinagoraRefColors.material().tertiary[30], borderRadius: BorderRadius.circular(AppConfig.borderRadius), ), child: Center( diff --git a/lib/pages/chat_list/chat_list_item_title.dart b/lib/pages/chat_list/chat_list_item_title.dart index 0fa59464df..caa5636adc 100644 --- a/lib/pages/chat_list/chat_list_item_title.dart +++ b/lib/pages/chat_list/chat_list_item_title.dart @@ -16,14 +16,11 @@ import 'package:matrix/matrix.dart'; class ChatListItemTitle extends StatelessWidget with ChatListItemMixin { final Room room; - final TextStyle? textStyle; - final DateTime? originServerTs; const ChatListItemTitle({ super.key, required this.room, - this.textStyle, this.originServerTs, }); @@ -40,26 +37,28 @@ class ChatListItemTitle extends StatelessWidget with ChatListItemMixin { children: [ Row( children: [ + Flexible( + child: Padding( + padding: ChatListItemTitleStyle.paddingRightTitle, + child: Text( + displayName, + overflow: TextOverflow.ellipsis, + maxLines: 1, + softWrap: false, + style: + ChatLitTitleTextStyleView.textStyle.textStyle(room), + ), + ), + ), if (room.encrypted) Padding( - padding: - const EdgeInsets.only(right: 4, top: 2, bottom: 2), + padding: ChatListItemTitleStyle.paddingLeftIcon, child: SvgPicture.asset( ImagePaths.icEncrypted, - width: 20, - height: 20, + width: ChatListItemTitleStyle.encryptedInconWidth, + height: ChatListItemTitleStyle.encryptedInconHeight, ), ), - Flexible( - child: Text( - displayName, - overflow: TextOverflow.ellipsis, - maxLines: 1, - softWrap: false, - style: textStyle ?? - ChatLitTitleTextStyleView.textStyle.textStyle(room), - ), - ), if (room.isFavourite) Padding( padding: ChatListItemTitleStyle.paddingLeftIcon, @@ -90,7 +89,7 @@ class ChatListItemTitle extends StatelessWidget with ChatListItemMixin { if (room.isTypingText(context)) ...[ Icon( Icons.schedule, - color: LinagoraRefColors.material().neutral[50], + color: LinagoraRefColors.material().tertiary[30], size: ChatListItemTitleStyle.iconScheduleSize, ), ], @@ -100,9 +99,7 @@ class ChatListItemTitle extends StatelessWidget with ChatListItemMixin { (originServerTs ?? room.timeCreated) .localizedTimeShort(context), style: Theme.of(context).textTheme.labelMedium?.copyWith( - color: room.isUnreadOrInvited - ? Theme.of(context).colorScheme.onSurface - : LinagoraRefColors.material().neutral[50], + color: LinagoraRefColors.material().tertiary[30], ), ), ), diff --git a/lib/pages/chat_list/chat_list_item_title_style.dart b/lib/pages/chat_list/chat_list_item_title_style.dart index f6513101e2..d802d61c4c 100644 --- a/lib/pages/chat_list/chat_list_item_title_style.dart +++ b/lib/pages/chat_list/chat_list_item_title_style.dart @@ -7,4 +7,10 @@ class ChatListItemTitleStyle { EdgeInsetsDirectional.only( start: 4, ); + static const EdgeInsetsDirectional paddingRightTitle = + EdgeInsetsDirectional.only( + end: 3, + ); + static const encryptedInconHeight = 16.0; + static const encryptedInconWidth = 14.0; } diff --git a/lib/pages/chat_list/chat_list_view_builder.dart b/lib/pages/chat_list/chat_list_view_builder.dart index eee9f8b109..cbc8eb277f 100644 --- a/lib/pages/chat_list/chat_list_view_builder.dart +++ b/lib/pages/chat_list/chat_list_view_builder.dart @@ -23,6 +23,9 @@ class ChatListViewBuilder extends StatelessWidget { physics: const NeverScrollableScrollPhysics(), itemCount: rooms.length, itemBuilder: (BuildContext context, int index) { + if (index == rooms.length) { + return const SizedBox.shrink(); + } return ValueListenableBuilder( valueListenable: controller.selectModeNotifier, builder: (context, selectMode, _) { diff --git a/lib/pages/chat_list/chat_list_view_style.dart b/lib/pages/chat_list/chat_list_view_style.dart index 6289134c67..54ae368360 100644 --- a/lib/pages/chat_list/chat_list_view_style.dart +++ b/lib/pages/chat_list/chat_list_view_style.dart @@ -38,4 +38,8 @@ class ChatListViewStyle { ? LinagoraRefColors.material().primary[50] : LinagoraRefColors.material().primary[40]; } + + static double dividerHeight = 1.0; + static double dividerIndent = 8.0; + static double dividerThickness = 1.0; } diff --git a/lib/pages/search/search_text_field.dart b/lib/pages/search/search_text_field.dart index cb4ed3ed9e..408859555a 100644 --- a/lib/pages/search/search_text_field.dart +++ b/lib/pages/search/search_text_field.dart @@ -4,6 +4,7 @@ import 'package:fluffychat/widgets/twake_components/twake_icon_button.dart'; import 'package:flutter/material.dart'; import 'package:fluffychat/pages/dialer/pip/dismiss_keyboard.dart'; import 'package:flutter_gen/gen_l10n/l10n.dart'; +import 'package:linagora_design_flutter/colors/linagora_ref_colors.dart'; class SearchTextField extends StatelessWidget { final TextEditingController textEditingController; @@ -46,7 +47,7 @@ class SearchTextField extends StatelessWidget { prefixIcon: Icon( Icons.search_outlined, size: SearchViewStyle.searchIconSize, - color: Theme.of(context).colorScheme.onSurface, + color: LinagoraRefColors.material().neutral[60], ), suffixIcon: ValueListenableBuilder( valueListenable: textEditingController, diff --git a/lib/pages/search/server_search_view.dart b/lib/pages/search/server_search_view.dart index 8be0ae054a..07a1512202 100644 --- a/lib/pages/search/server_search_view.dart +++ b/lib/pages/search/server_search_view.dart @@ -89,7 +89,7 @@ class ServerSearchMessagesList extends StatelessWidget { maxLines: 2, style: ChatLitSubSubtitleTextStyleView .textStyle - .textStyle(room), + .textStyle(room, context), ), ], ), diff --git a/lib/presentation/decorators/chat_list/subtitle_image_preview_style.dart b/lib/presentation/decorators/chat_list/subtitle_image_preview_style.dart new file mode 100644 index 0000000000..b63c4b30bc --- /dev/null +++ b/lib/presentation/decorators/chat_list/subtitle_image_preview_style.dart @@ -0,0 +1,9 @@ +import 'package:flutter/material.dart'; + +class SubtitleImagePreviewStyle { + static const double width = 20; + static const double height = 20; + static const double borderRadius = 4; + static const BoxFit fit = BoxFit.fill; + static const EdgeInsets labelPadding = EdgeInsets.only(left: 5); +} diff --git a/lib/presentation/decorators/chat_list/subtitle_text_style_decorator/subtitle_text_style_component.dart b/lib/presentation/decorators/chat_list/subtitle_text_style_decorator/subtitle_text_style_component.dart index ba8b925fcd..f2cddf4801 100644 --- a/lib/presentation/decorators/chat_list/subtitle_text_style_decorator/subtitle_text_style_component.dart +++ b/lib/presentation/decorators/chat_list/subtitle_text_style_decorator/subtitle_text_style_component.dart @@ -2,5 +2,5 @@ import 'package:flutter/material.dart'; import 'package:matrix/matrix.dart'; abstract class ChatListSubtitleTextStyleComponent { - TextStyle textStyle(Room room); + TextStyle textStyle(Room room, BuildContext context); } diff --git a/lib/presentation/decorators/chat_list/subtitle_text_style_decorator/subtitle_text_style_decorator.dart b/lib/presentation/decorators/chat_list/subtitle_text_style_decorator/subtitle_text_style_decorator.dart index c8ffb4fd67..7e1d03c7b0 100644 --- a/lib/presentation/decorators/chat_list/subtitle_text_style_decorator/subtitle_text_style_decorator.dart +++ b/lib/presentation/decorators/chat_list/subtitle_text_style_decorator/subtitle_text_style_decorator.dart @@ -18,8 +18,8 @@ class ChatListSubtitleTextStyle implements ChatListSubtitleTextStyleDecorator { ChatListSubtitleTextStyle(this._interfaceTextStyleComponent); @override - TextStyle textStyle(Room room) { - return _interfaceTextStyleComponent.textStyle(room); + TextStyle textStyle(Room room, BuildContext context) { + return _interfaceTextStyleComponent.textStyle(room, context); } @override @@ -30,8 +30,8 @@ class ChatListSubtitleTextStyle implements ChatListSubtitleTextStyleDecorator { class ReadChatListSubtitleTextStyleDecorator implements ChatListSubtitleTextStyleComponent { @override - TextStyle textStyle(Room room) { - return LinagoraTextStyle.material().bodyMedium3.copyWith( + TextStyle textStyle(Room room, BuildContext context) { + return Theme.of(context).textTheme.bodyMedium!.copyWith( color: LinagoraSysColors.material().onSurface, fontFamily: GoogleFonts.inter().fontFamily, ); @@ -45,15 +45,15 @@ class UnreadChatListSubtitleTextStyleDecorator UnreadChatListSubtitleTextStyleDecorator(this._interfaceTextStyleComponent); @override - TextStyle textStyle(Room room) { + TextStyle textStyle(Room room, BuildContext context) { if (room.isUnreadOrInvited) { - return _interfaceTextStyleComponent.textStyle(room).merge( - LinagoraTextStyle.material().bodyMedium2.copyWith( + return _interfaceTextStyleComponent.textStyle(room, context).merge( + Theme.of(context).textTheme.bodyMedium!.copyWith( color: LinagoraSysColors.material().onSurface, ), ); } else { - return _interfaceTextStyleComponent.textStyle(room); + return _interfaceTextStyleComponent.textStyle(room, context); } } @@ -69,13 +69,13 @@ class MuteChatListSubtitleTextStyleDecorator MuteChatListSubtitleTextStyleDecorator(this._interfaceTextStyleComponent); @override - TextStyle textStyle(Room room) { + TextStyle textStyle(Room room, BuildContext context) { if (room.isMuted) { - return _interfaceTextStyleComponent.textStyle(room).copyWith( - color: LinagoraRefColors.material().tertiary[20], + return _interfaceTextStyleComponent.textStyle(room, context).copyWith( + color: LinagoraSysColors.material().onSurface, ); } else { - return _interfaceTextStyleComponent.textStyle(room); + return _interfaceTextStyleComponent.textStyle(room, context); } } diff --git a/lib/presentation/decorators/chat_list/title_text_style_decorator/title_text_style_decorator.dart b/lib/presentation/decorators/chat_list/title_text_style_decorator/title_text_style_decorator.dart index bb25c10c6b..15435932f2 100644 --- a/lib/presentation/decorators/chat_list/title_text_style_decorator/title_text_style_decorator.dart +++ b/lib/presentation/decorators/chat_list/title_text_style_decorator/title_text_style_decorator.dart @@ -30,7 +30,7 @@ class ReadChatListTitleTextStyleDecorator implements ChatListTitleTextStyleComponent { @override TextStyle textStyle(Room room) { - return LinagoraTextStyle.material().bodyLarge2.copyWith( + return LinagoraTextStyle.material().bodyMedium2.copyWith( color: LinagoraSysColors.material().onSurface, fontFamily: GoogleFonts.inter().fontFamily, ); @@ -47,8 +47,9 @@ class UnreadChatListTitleTextStyleDecorator TextStyle textStyle(Room room) { if (room.isUnreadOrInvited) { return _interfaceTextStyleComponent.textStyle(room).merge( - LinagoraTextStyle.material().bodyLarge1.copyWith( + LinagoraTextStyle.material().bodyMedium2.copyWith( color: LinagoraSysColors.material().onSurface, + fontFamily: GoogleFonts.inter().fontFamily, ), ); } else { @@ -72,7 +73,7 @@ class MuteChatListTitleTextStyleDecorator final isMuted = room.pushRuleState != PushRuleState.notify; if (isMuted) { return _interfaceTextStyleComponent.textStyle(room).copyWith( - color: LinagoraRefColors.material().tertiary[20], + color: LinagoraSysColors.material().onSurface, ); } else { return _interfaceTextStyleComponent.textStyle(room); diff --git a/lib/presentation/mixins/chat_list_item_mixin.dart b/lib/presentation/mixins/chat_list_item_mixin.dart index b7c346d875..1b2edf55ed 100644 --- a/lib/presentation/mixins/chat_list_item_mixin.dart +++ b/lib/presentation/mixins/chat_list_item_mixin.dart @@ -1,9 +1,14 @@ +import 'package:fluffychat/pages/chat/events/images_builder/image_placeholder.dart'; +import 'package:fluffychat/presentation/decorators/chat_list/subtitle_image_preview_style.dart'; import 'package:fluffychat/presentation/decorators/chat_list/subtitle_text_style_decorator/subtitle_text_style_view.dart'; import 'package:fluffychat/utils/matrix_sdk_extensions/event_extension.dart'; import 'package:fluffychat/utils/matrix_sdk_extensions/matrix_locals.dart'; +import 'package:fluffychat/widgets/mxc_image.dart'; import 'package:flutter/material.dart'; import 'package:flutter_gen/gen_l10n/l10n.dart'; import 'package:linagora_design_flutter/colors/linagora_ref_colors.dart'; +import 'package:linagora_design_flutter/colors/linagora_sys_colors.dart'; +import 'package:linagora_design_flutter/style/linagora_text_style.dart'; import 'package:matrix/matrix.dart'; mixin ChatListItemMixin { @@ -39,20 +44,22 @@ mixin ChatListItemMixin { softWrap: false, maxLines: isGroup ? 1 : 2, overflow: TextOverflow.ellipsis, - style: ChatLitSubSubtitleTextStyleView.textStyle.textStyle(room), + style: LinagoraTextStyle.material().bodyMedium3.copyWith( + color: LinagoraRefColors.material().tertiary[30], + ), ); }, ); } Widget typingTextWidget(String typingText, BuildContext context) { - final displayedTypingText = "~ $typingText…"; + final displayedTypingText = "$typingText…"; return Text( displayedTypingText, - style: Theme.of(context).textTheme.labelLarge?.merge( + style: LinagoraTextStyle.material().bodyMedium2.merge( TextStyle( overflow: TextOverflow.ellipsis, - color: LinagoraRefColors.material().secondary, + color: LinagoraRefColors.material().tertiary[30], ), ), maxLines: 2, @@ -75,7 +82,7 @@ mixin ChatListItemMixin { maxLines: 1, softWrap: false, style: ChatLitSubSubtitleTextStyleView.textStyle - .textStyle(room), + .textStyle(room, context), ); }, ), @@ -96,7 +103,8 @@ mixin ChatListItemMixin { softWrap: false, maxLines: 2, overflow: TextOverflow.ellipsis, - style: ChatLitSubSubtitleTextStyleView.textStyle.textStyle(room), + style: + ChatLitSubSubtitleTextStyleView.textStyle.textStyle(room, context), ); } @@ -119,18 +127,87 @@ mixin ChatListItemMixin { softWrap: false, maxLines: 2, overflow: TextOverflow.ellipsis, - style: ChatLitSubSubtitleTextStyleView.textStyle.textStyle(room), + style: ChatLitSubSubtitleTextStyleView.textStyle + .textStyle(room, context), ); } - return Text( - "${snapshot.data!.calcDisplayname()}: $subscriptions", - softWrap: false, - maxLines: 2, - overflow: TextOverflow.ellipsis, - style: ChatLitSubSubtitleTextStyleView.textStyle.textStyle(room), + return Column( + mainAxisAlignment: MainAxisAlignment.start, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + snapshot.data!.calcDisplayname(), + overflow: TextOverflow.ellipsis, + maxLines: 1, + softWrap: false, + style: Theme.of(context).textTheme.bodyMedium!.copyWith( + color: LinagoraSysColors.material().onSurface, + ), + ), + room.lastEvent?.messageType == MessageTypes.Image || + room.lastEvent?.messageType == MessageTypes.Video + ? chatlistItemMediaPreviewSubTitle( + context, + room, + ) + : Text( + subscriptions, + softWrap: false, + maxLines: 1, + overflow: TextOverflow.ellipsis, + style: LinagoraTextStyle.material().bodyMedium3.copyWith( + color: LinagoraRefColors.material().tertiary[30], + ), + ), + ], ); }, ); } + + Widget chatlistItemMediaPreviewSubTitle( + BuildContext context, + Room room, + ) { + return Row( + children: [ + if (room.lastEvent?.status != EventStatus.synced) + const SizedBox.shrink() + else + SizedBox( + height: SubtitleImagePreviewStyle.height, + width: SubtitleImagePreviewStyle.width, + child: ClipRRect( + borderRadius: + BorderRadius.circular(SubtitleImagePreviewStyle.borderRadius), + child: MxcImage( + key: ValueKey(room.lastEvent!.eventId), + cacheKey: room.lastEvent!.eventId, + event: room.lastEvent!, + placeholder: (context) => ImagePlaceholder( + event: room.lastEvent!, + width: SubtitleImagePreviewStyle.width, + height: SubtitleImagePreviewStyle.height, + fit: SubtitleImagePreviewStyle.fit, + ), + fit: SubtitleImagePreviewStyle.fit, + enableHeroAnimation: false, + ), + ), + ), + Padding( + padding: SubtitleImagePreviewStyle.labelPadding, + child: Text( + room.lastEvent!.messageType == MessageTypes.Image + ? L10n.of(context)!.photo + : L10n.of(context)!.video, + style: LinagoraTextStyle.material() + .bodyMedium3 + .copyWith(color: LinagoraRefColors.material().tertiary[30]), + ), + ), + ], + ); + } } diff --git a/lib/widgets/layouts/adaptive_layout/app_adaptive_scaffold_body.dart b/lib/widgets/layouts/adaptive_layout/app_adaptive_scaffold_body.dart index b9520d3de3..b8b037bee9 100644 --- a/lib/widgets/layouts/adaptive_layout/app_adaptive_scaffold_body.dart +++ b/lib/widgets/layouts/adaptive_layout/app_adaptive_scaffold_body.dart @@ -164,11 +164,16 @@ class AppAdaptiveScaffoldBodyController extends State @override void initState() { + super.initState(); activeRoomIdNotifier.value = widget.activeRoomId; resetLocationPathWithLoginToken(); - getCurrentProfile(); - _handleProfileDataChange(); - super.initState(); + WidgetsBinding.instance.addPostFrameCallback((_) async { + if (mounted) { + await matrix.retrievePersistedActiveClient(); + getCurrentProfile(); + _handleProfileDataChange(); + } + }); } @override diff --git a/lib/widgets/layouts/enum/adaptive_destinations_enum.dart b/lib/widgets/layouts/enum/adaptive_destinations_enum.dart index 02175db127..4cf2ee8137 100644 --- a/lib/widgets/layouts/enum/adaptive_destinations_enum.dart +++ b/lib/widgets/layouts/enum/adaptive_destinations_enum.dart @@ -98,8 +98,10 @@ enum AdaptiveDestinationEnum { profile: profile, isSelected: false, ), - activeIcon: - BottomNavigationAvatar(profile: profile, isSelected: true), + activeIcon: BottomNavigationAvatar( + profile: profile, + isSelected: true, + ), label: L10n.of(context)!.settings, ); default: diff --git a/lib/widgets/mxc_image.dart b/lib/widgets/mxc_image.dart index be84795e4c..0b8428fb50 100644 --- a/lib/widgets/mxc_image.dart +++ b/lib/widgets/mxc_image.dart @@ -38,6 +38,7 @@ class MxcImage extends StatefulWidget { final void Function()? onTapSelectMode; final ImageData? imageData; final bool isPreview; + final bool enableHeroAnimation; /// Enable it if the image is stretched, and you don't want to resize it final bool noResize; @@ -75,6 +76,7 @@ class MxcImage extends StatefulWidget { this.closeRightColumn, this.cacheWidth, this.cacheHeight, + this.enableHeroAnimation = true, super.key, }); @@ -272,7 +274,7 @@ class _MxcImageState extends State { ) : _buildImageWidget(); - if (widget.event?.eventId != null) { + if (widget.event?.eventId != null && widget.enableHeroAnimation) { imageWidget = Hero( tag: widget.event!.eventId, child: imageWidget, diff --git a/test/utils/date_time_extension_test.dart b/test/utils/date_time_extension_test.dart index 6c449a2483..017eb1f612 100644 --- a/test/utils/date_time_extension_test.dart +++ b/test/utils/date_time_extension_test.dart @@ -64,7 +64,7 @@ void main() async { testWidgets( 'GIVEN the date time to display is Monday of current week\n' 'THEN should display the Monday\n', (WidgetTester tester) async { - const expectedDisplayText = 'Monday'; + const expectedDisplayText = 'Mon'; final currentTime = DateTime(2022, 1, 1); final timeToTest = DateTime(2021, 12, 27, 12, 5); @@ -105,7 +105,7 @@ void main() async { testWidgets( 'GIVEN the date time to display is Tuesday of current week\n' 'THEN should display Tuesday\n', (WidgetTester tester) async { - const expectedDisplayText = 'Tuesday'; + const expectedDisplayText = 'Tue'; final currentTime = DateTime(2022, 1, 1); final timeToTest = DateTime(2021, 12, 28, 12, 5); @@ -146,7 +146,7 @@ void main() async { testWidgets( 'GIVEN the date time to display is Wednesday of current week\n' 'THEN should display Wednesday\n', (WidgetTester tester) async { - const expectedDisplayText = 'Wednesday'; + const expectedDisplayText = 'Wed'; final currentTime = DateTime(2022, 1, 1); final timeToTest = DateTime(2021, 12, 29, 12, 5); @@ -187,7 +187,7 @@ void main() async { testWidgets( 'GIVEN the date time to display is Thursday of current week\n' 'THEN should display Thursday\n', (WidgetTester tester) async { - const expectedDisplayText = 'Thursday'; + const expectedDisplayText = 'Thu'; final currentTime = DateTime(2022, 1, 1); final timeToTest = DateTime(2021, 12, 30, 12, 5); @@ -228,7 +228,7 @@ void main() async { testWidgets( 'GIVEN the date time to display is Friday of current week\n' 'THEN should display Friday\n', (WidgetTester tester) async { - const expectedDisplayText = 'Friday'; + const expectedDisplayText = 'Fri'; final currentTime = DateTime(2022, 1, 1); final timeToTest = DateTime(2021, 12, 31, 12, 5); @@ -269,7 +269,7 @@ void main() async { testWidgets( 'GIVEN the date time to display is Saturday of current week\n' 'THEN should display Saturday\n', (WidgetTester tester) async { - const expectedDisplayText = 'Saturday'; + const expectedDisplayText = 'Sat'; final currentTime = DateTime(2024, 2, 25); final timeToTest = DateTime(2024, 2, 24, 12, 5); @@ -310,7 +310,7 @@ void main() async { testWidgets( 'GIVEN the date time to display is Sunday of current week\n' 'THEN should display Sunday\n', (WidgetTester tester) async { - const expectedDisplayText = 'Sunday'; + const expectedDisplayText = 'Sun'; final currentTime = DateTime(2022, 1, 1); final timeToTest = DateTime(2022, 1, 2, 12, 5); @@ -352,7 +352,7 @@ void main() async { 'GIVEN the current time is Sunday\n' 'AND the date time to display is Friday of current week\n' 'THEN should display Friday\n', (WidgetTester tester) async { - const expectedDisplayText = 'Friday'; + const expectedDisplayText = 'Fri'; final currentTime = DateTime(2024, 3, 3); final timeToTest = DateTime(2024, 3, 1, 12, 5); @@ -394,7 +394,7 @@ void main() async { 'GIVEN the current time is Sunday\n' 'AND the date time to display is Saturday of current week\n' 'THEN should display Saturday\n', (WidgetTester tester) async { - const expectedDisplayText = 'Saturday'; + const expectedDisplayText = 'Sat'; final currentTime = DateTime(2024, 3, 3); final timeToTest = DateTime(2024, 3, 2, 12, 5);