From f362695f6e8f5330c31dd2643200cafec4b18755 Mon Sep 17 00:00:00 2001 From: otsmr Date: Thu, 29 May 2025 11:39:54 +0200 Subject: [PATCH] clean code and fix tap issue --- lib/src/views/chats/chat_list_view.dart | 4 +- .../chat_list_entry.dart | 100 ++++++ .../chat_message_entry.dart | 100 ++++++ .../chat_media_entry.dart | 95 ++++++ .../chat_reaction_row.dart | 82 +++++ .../chat_text_entry.dart | 39 +++ .../chat_text_response_columns.dart | 79 +++++ .../in_chat_media_viewer.dart | 24 +- .../sliding_response.dart | 0 ...ails_view.dart => chat_messages_view.dart} | 10 +- .../chats/components/chat_list_entry.dart | 298 ------------------ lib/src/views/chats/start_new_chat.dart | 4 +- .../views/components/user_context_menu.dart | 4 +- 13 files changed, 519 insertions(+), 320 deletions(-) create mode 100644 lib/src/views/chats/chat_messages_components/chat_list_entry.dart create mode 100644 lib/src/views/chats/chat_messages_components/chat_message_entry.dart create mode 100644 lib/src/views/chats/chat_messages_components/chat_message_entry_components/chat_media_entry.dart create mode 100644 lib/src/views/chats/chat_messages_components/chat_message_entry_components/chat_reaction_row.dart create mode 100644 lib/src/views/chats/chat_messages_components/chat_message_entry_components/chat_text_entry.dart create mode 100644 lib/src/views/chats/chat_messages_components/chat_message_entry_components/chat_text_response_columns.dart rename lib/src/views/chats/{components => chat_messages_components}/in_chat_media_viewer.dart (94%) rename lib/src/views/chats/{components => chat_messages_components}/sliding_response.dart (100%) rename lib/src/views/chats/{chat_item_details_view.dart => chat_messages_view.dart} (97%) delete mode 100644 lib/src/views/chats/components/chat_list_entry.dart diff --git a/lib/src/views/chats/chat_list_view.dart b/lib/src/views/chats/chat_list_view.dart index 8dd0be2..ea61c17 100644 --- a/lib/src/views/chats/chat_list_view.dart +++ b/lib/src/views/chats/chat_list_view.dart @@ -15,7 +15,7 @@ import 'package:twonly/src/database/tables/messages_table.dart'; import 'package:twonly/src/providers/connection_provider.dart'; import 'package:twonly/src/utils/misc.dart'; import 'package:twonly/src/views/camera/camera_send_to_view.dart'; -import 'package:twonly/src/views/chats/chat_item_details_view.dart'; +import 'package:twonly/src/views/chats/chat_messages_view.dart'; import 'package:twonly/src/views/chats/media_viewer_view.dart'; import 'package:twonly/src/views/chats/start_new_chat.dart'; import 'package:twonly/src/views/settings/settings_main_view.dart'; @@ -383,7 +383,7 @@ class _UserListItem extends State { Navigator.push( context, MaterialPageRoute(builder: (context) { - return ChatItemDetailsView(widget.user); + return ChatMessagesView(widget.user); }), ); }, diff --git a/lib/src/views/chats/chat_messages_components/chat_list_entry.dart b/lib/src/views/chats/chat_messages_components/chat_list_entry.dart new file mode 100644 index 0000000..5e9882b --- /dev/null +++ b/lib/src/views/chats/chat_messages_components/chat_list_entry.dart @@ -0,0 +1,100 @@ +import 'dart:convert'; +import 'package:flutter/material.dart'; +import 'package:twonly/src/views/chats/chat_messages_components/chat_message_entry_components/chat_media_entry.dart'; +import 'package:twonly/src/views/chats/chat_messages_components/chat_message_entry_components/chat_reaction_row.dart'; +import 'package:twonly/src/views/chats/chat_messages_components/chat_message_entry_components/chat_text_entry.dart'; +import 'package:twonly/src/views/chats/chat_messages_components/chat_message_entry_components/chat_text_response_columns.dart'; +import 'package:twonly/src/views/chats/chat_messages_components/sliding_response.dart'; +import 'package:twonly/src/database/twonly_database.dart'; +import 'package:twonly/src/model/json/message.dart'; + +class ChatListEntry extends StatefulWidget { + const ChatListEntry( + this.message, + this.contact, + this.lastMessageFromSameUser, + this.textReactions, + this.otherReactions, { + super.key, + required this.onResponseTriggered, + }); + final Message message; + final Contact contact; + final bool lastMessageFromSameUser; + final List textReactions; + final List otherReactions; + final Function(Message) onResponseTriggered; + + @override + State createState() => _ChatListEntryState(); +} + +class _ChatListEntryState extends State { + MessageContent? content; + String? textMessage; + + @override + void initState() { + super.initState(); + final msgContent = MessageContent.fromJson( + widget.message.kind, jsonDecode(widget.message.contentJson!)); + if (msgContent is TextMessageContent) { + textMessage = msgContent.text; + } + content = msgContent; + } + + @override + Widget build(BuildContext context) { + if (content == null) return Container(); + bool right = widget.message.messageOtherId == null; + + return Align( + alignment: right ? Alignment.centerRight : Alignment.centerLeft, + child: Padding( + padding: widget.lastMessageFromSameUser + ? EdgeInsets.only(top: 5, bottom: 0, right: 10, left: 10) + : EdgeInsets.only(top: 5, bottom: 20, right: 10, left: 10), + child: Column( + mainAxisAlignment: + right ? MainAxisAlignment.end : MainAxisAlignment.start, + crossAxisAlignment: + right ? CrossAxisAlignment.end : CrossAxisAlignment.start, + children: [ + SlidingResponse( + child: Stack( + alignment: right ? Alignment.centerRight : Alignment.centerLeft, + children: [ + (textMessage != null) + ? ChatTextEntry( + message: widget.message, text: textMessage!) + : ChatMediaEntry( + message: widget.message, + contact: widget.contact, + content: content!, + ), + Positioned( + bottom: 5, + left: 5, + right: 5, + child: ReactionRow( + otherReactions: widget.otherReactions, + message: widget.message, + ), + ), + ], + ), + onResponseTriggered: () { + widget.onResponseTriggered(widget.message); + }, + ), + ChatTextResponseColumns( + textReactions: widget.textReactions, + right: right, + ) + ], + ), + ), + ); + } +} diff --git a/lib/src/views/chats/chat_messages_components/chat_message_entry.dart b/lib/src/views/chats/chat_messages_components/chat_message_entry.dart new file mode 100644 index 0000000..5e9882b --- /dev/null +++ b/lib/src/views/chats/chat_messages_components/chat_message_entry.dart @@ -0,0 +1,100 @@ +import 'dart:convert'; +import 'package:flutter/material.dart'; +import 'package:twonly/src/views/chats/chat_messages_components/chat_message_entry_components/chat_media_entry.dart'; +import 'package:twonly/src/views/chats/chat_messages_components/chat_message_entry_components/chat_reaction_row.dart'; +import 'package:twonly/src/views/chats/chat_messages_components/chat_message_entry_components/chat_text_entry.dart'; +import 'package:twonly/src/views/chats/chat_messages_components/chat_message_entry_components/chat_text_response_columns.dart'; +import 'package:twonly/src/views/chats/chat_messages_components/sliding_response.dart'; +import 'package:twonly/src/database/twonly_database.dart'; +import 'package:twonly/src/model/json/message.dart'; + +class ChatListEntry extends StatefulWidget { + const ChatListEntry( + this.message, + this.contact, + this.lastMessageFromSameUser, + this.textReactions, + this.otherReactions, { + super.key, + required this.onResponseTriggered, + }); + final Message message; + final Contact contact; + final bool lastMessageFromSameUser; + final List textReactions; + final List otherReactions; + final Function(Message) onResponseTriggered; + + @override + State createState() => _ChatListEntryState(); +} + +class _ChatListEntryState extends State { + MessageContent? content; + String? textMessage; + + @override + void initState() { + super.initState(); + final msgContent = MessageContent.fromJson( + widget.message.kind, jsonDecode(widget.message.contentJson!)); + if (msgContent is TextMessageContent) { + textMessage = msgContent.text; + } + content = msgContent; + } + + @override + Widget build(BuildContext context) { + if (content == null) return Container(); + bool right = widget.message.messageOtherId == null; + + return Align( + alignment: right ? Alignment.centerRight : Alignment.centerLeft, + child: Padding( + padding: widget.lastMessageFromSameUser + ? EdgeInsets.only(top: 5, bottom: 0, right: 10, left: 10) + : EdgeInsets.only(top: 5, bottom: 20, right: 10, left: 10), + child: Column( + mainAxisAlignment: + right ? MainAxisAlignment.end : MainAxisAlignment.start, + crossAxisAlignment: + right ? CrossAxisAlignment.end : CrossAxisAlignment.start, + children: [ + SlidingResponse( + child: Stack( + alignment: right ? Alignment.centerRight : Alignment.centerLeft, + children: [ + (textMessage != null) + ? ChatTextEntry( + message: widget.message, text: textMessage!) + : ChatMediaEntry( + message: widget.message, + contact: widget.contact, + content: content!, + ), + Positioned( + bottom: 5, + left: 5, + right: 5, + child: ReactionRow( + otherReactions: widget.otherReactions, + message: widget.message, + ), + ), + ], + ), + onResponseTriggered: () { + widget.onResponseTriggered(widget.message); + }, + ), + ChatTextResponseColumns( + textReactions: widget.textReactions, + right: right, + ) + ], + ), + ), + ); + } +} diff --git a/lib/src/views/chats/chat_messages_components/chat_message_entry_components/chat_media_entry.dart b/lib/src/views/chats/chat_messages_components/chat_message_entry_components/chat_media_entry.dart new file mode 100644 index 0000000..d1af8e5 --- /dev/null +++ b/lib/src/views/chats/chat_messages_components/chat_message_entry_components/chat_media_entry.dart @@ -0,0 +1,95 @@ +import 'package:drift/drift.dart' show Value; +import 'package:flutter/material.dart'; +import 'package:twonly/globals.dart'; +import 'package:twonly/src/views/chats/chat_messages_components/in_chat_media_viewer.dart'; +import 'package:twonly/src/database/twonly_database.dart'; +import 'package:twonly/src/database/tables/messages_table.dart'; +import 'package:twonly/src/model/json/message.dart'; +import 'package:twonly/src/providers/api/api.dart'; +import 'package:twonly/src/providers/api/media_received.dart' as received; +import 'package:twonly/src/services/notification_service.dart'; +import 'package:twonly/src/views/chats/media_viewer_view.dart'; + +class ChatMediaEntry extends StatelessWidget { + const ChatMediaEntry({ + super.key, + required this.message, + required this.contact, + required this.content, + }); + + final Message message; + final Contact contact; + final MessageContent content; + + @override + Widget build(BuildContext context) { + Color color = getMessageColorFromType( + content, + context, + ); + + return GestureDetector( + onDoubleTap: () async { + if (message.openedAt == null && message.messageOtherId != null || + message.mediaStored) { + return; + } + if (await received.existsMediaFile(message.messageId, "png")) { + await encryptAndSendMessageAsync( + null, + contact.userId, + MessageJson( + kind: MessageKind.reopenedMedia, + messageId: message.messageId, + content: ReopenedMediaFileContent( + messageId: message.messageOtherId!, + ), + timestamp: DateTime.now(), + ), + pushKind: PushKind.reopenedMedia, + ); + await twonlyDatabase.messagesDao.updateMessageByMessageId( + message.messageId, + MessagesCompanion(openedAt: Value(null)), + ); + } + }, + onTap: () { + if (message.kind == MessageKind.media) { + if (message.downloadState == DownloadState.downloaded && + message.openedAt == null) { + Navigator.push( + context, + MaterialPageRoute(builder: (context) { + return MediaViewerView(contact, initialMessage: message); + }), + ); + } else if (message.downloadState == DownloadState.pending) { + received.startDownloadMedia(message, true); + } + } + }, + child: Container( + width: 150, + decoration: BoxDecoration( + border: Border.all( + color: color, + width: 1.0, + ), + borderRadius: BorderRadius.circular(12.0), + ), + child: Align( + alignment: Alignment.centerRight, + child: ClipRRect( + borderRadius: BorderRadius.circular(12), + child: InChatMediaViewer( + message: message, + contact: contact, + ), + ), + ), + ), + ); + } +} diff --git a/lib/src/views/chats/chat_messages_components/chat_message_entry_components/chat_reaction_row.dart b/lib/src/views/chats/chat_messages_components/chat_message_entry_components/chat_reaction_row.dart new file mode 100644 index 0000000..769da23 --- /dev/null +++ b/lib/src/views/chats/chat_messages_components/chat_message_entry_components/chat_reaction_row.dart @@ -0,0 +1,82 @@ +import 'dart:convert'; +import 'package:flutter/material.dart'; +import 'package:font_awesome_flutter/font_awesome_flutter.dart'; +import 'package:twonly/src/views/components/animate_icon.dart'; +import 'package:twonly/src/database/twonly_database.dart'; +import 'package:twonly/src/model/json/message.dart'; + +class ReactionRow extends StatefulWidget { + const ReactionRow( + {super.key, required this.otherReactions, required this.message}); + + final List otherReactions; + final Message message; + + @override + State createState() => _ReactionRowState(); +} + +class _ReactionRowState extends State { + @override + Widget build(BuildContext context) { + List children = []; + bool hasOneTextReaction = false; + bool hasOneReopened = false; + for (final reaction in widget.otherReactions) { + MessageContent? content = MessageContent.fromJson( + reaction.kind, jsonDecode(reaction.contentJson!)); + + if (content is ReopenedMediaFileContent) { + if (hasOneReopened) continue; + hasOneReopened = true; + children.add( + Expanded( + child: Align( + alignment: Alignment.bottomRight, + child: Padding( + padding: EdgeInsets.only(right: 3), + child: FaIcon( + FontAwesomeIcons.repeat, + size: 12, + color: Colors.white, + ), + ), + ), + ), + ); + } + // only show one reaction + if (hasOneTextReaction) continue; + + if (content is TextMessageContent) { + hasOneTextReaction = true; + if (!isEmoji(content.text)) continue; + late Widget child; + if (EmojiAnimation.animatedIcons.containsKey(content.text)) { + child = SizedBox( + height: 18, + child: EmojiAnimation(emoji: content.text), + ); + } else { + child = Text(content.text, style: TextStyle(fontSize: 14)); + } + children.insert( + 0, + Padding( + padding: EdgeInsets.only(left: 3), + child: child, + ), + ); + } + } + + if (children.isEmpty) return Container(); + + return Row( + mainAxisAlignment: widget.message.messageOtherId == null + ? MainAxisAlignment.start + : MainAxisAlignment.end, + children: children, + ); + } +} diff --git a/lib/src/views/chats/chat_messages_components/chat_message_entry_components/chat_text_entry.dart b/lib/src/views/chats/chat_messages_components/chat_message_entry_components/chat_text_entry.dart new file mode 100644 index 0000000..f0520ba --- /dev/null +++ b/lib/src/views/chats/chat_messages_components/chat_message_entry_components/chat_text_entry.dart @@ -0,0 +1,39 @@ +import 'package:flutter/material.dart'; +import 'package:twonly/src/views/chats/chat_messages_view.dart'; +import 'package:twonly/src/views/components/animate_icon.dart'; +import 'package:twonly/src/views/components/better_text.dart'; +import 'package:twonly/src/database/twonly_database.dart'; + +class ChatTextEntry extends StatelessWidget { + const ChatTextEntry({super.key, required this.message, required this.text}); + + final String text; + final Message message; + + @override + Widget build(BuildContext context) { + if (EmojiAnimation.supported(text)) { + return Container( + constraints: BoxConstraints( + maxWidth: 100, + ), + padding: EdgeInsets.symmetric( + vertical: 4, + horizontal: 10, + ), + child: EmojiAnimation(emoji: text), + ); + } + return Container( + constraints: BoxConstraints( + maxWidth: MediaQuery.of(context).size.width * 0.8, + ), + padding: EdgeInsets.symmetric(vertical: 4, horizontal: 10), + decoration: BoxDecoration( + color: getMessageColor(message), + borderRadius: BorderRadius.circular(12.0), + ), + child: BetterText(text: text), + ); + } +} diff --git a/lib/src/views/chats/chat_messages_components/chat_message_entry_components/chat_text_response_columns.dart b/lib/src/views/chats/chat_messages_components/chat_message_entry_components/chat_text_response_columns.dart new file mode 100644 index 0000000..8f08ae7 --- /dev/null +++ b/lib/src/views/chats/chat_messages_components/chat_message_entry_components/chat_text_response_columns.dart @@ -0,0 +1,79 @@ +import 'dart:convert'; +import 'package:flutter/material.dart'; +import 'package:font_awesome_flutter/font_awesome_flutter.dart'; +import 'package:twonly/src/views/chats/chat_messages_view.dart'; +import 'package:twonly/src/database/twonly_database.dart'; +import 'package:twonly/src/model/json/message.dart'; + +class ChatTextResponseColumns extends StatelessWidget { + const ChatTextResponseColumns({ + super.key, + required this.textReactions, + required this.right, + }); + + final List textReactions; + final bool right; + + @override + Widget build(BuildContext context) { + List children = []; + for (final reaction in textReactions) { + MessageContent? content = MessageContent.fromJson( + reaction.kind, jsonDecode(reaction.contentJson!)); + + if (content is TextMessageContent) { + var entries = [ + FaIcon( + FontAwesomeIcons.reply, + size: 10, + ), + SizedBox(width: 5), + Container( + constraints: BoxConstraints( + maxWidth: MediaQuery.of(context).size.width * 0.5, + ), + child: Text( + content.text, + style: TextStyle(fontSize: 14), + textAlign: right ? TextAlign.left : TextAlign.right, + )), + ]; + if (!right) { + entries = entries.reversed.toList(); + } + + Color color = getMessageColor(reaction); + + children.insert( + 0, + Container( + padding: EdgeInsets.only(top: 5, bottom: 0, right: 10, left: 10), + child: Container( + constraints: BoxConstraints( + maxWidth: MediaQuery.of(context).size.width * 0.8, + ), + padding: EdgeInsets.symmetric(vertical: 1, horizontal: 10), + decoration: BoxDecoration( + color: color, + borderRadius: BorderRadius.circular(12.0), + ), + child: Row( + mainAxisSize: MainAxisSize.min, + children: entries, + ), + ), + ), + ); + } + } + + if (children.isEmpty) return Container(); + + return Column( + crossAxisAlignment: + right ? CrossAxisAlignment.start : CrossAxisAlignment.end, + children: children, + ); + } +} diff --git a/lib/src/views/chats/components/in_chat_media_viewer.dart b/lib/src/views/chats/chat_messages_components/in_chat_media_viewer.dart similarity index 94% rename from lib/src/views/chats/components/in_chat_media_viewer.dart rename to lib/src/views/chats/chat_messages_components/in_chat_media_viewer.dart index 0418e62..36feb22 100644 --- a/lib/src/views/chats/components/in_chat_media_viewer.dart +++ b/lib/src/views/chats/chat_messages_components/in_chat_media_viewer.dart @@ -209,8 +209,6 @@ class _InChatMediaViewerState extends State { } Future onTap() async { - if (image == null && videoController == null) return; - if (widget.isInFullscreen) return; bool? removed = await Navigator.push( context, MaterialPageRoute(builder: (context) { @@ -231,8 +229,20 @@ class _InChatMediaViewerState extends State { @override Widget build(BuildContext context) { + if (image == null && video == null) { + return Padding( + padding: const EdgeInsets.all(10.0), + child: MessageSendStateIcon( + [widget.message], + mainAxisAlignment: MainAxisAlignment.center, + ), + ); + } return GestureDetector( - onTap: onTap, + onTap: + ((image == null && videoController == null) || widget.isInFullscreen) + ? null + : onTap, child: Stack( children: [ if (image != null) Image.file(image!), @@ -243,14 +253,6 @@ class _InChatMediaViewerState extends State { child: VideoPlayer(videoController!), ), ), - if (image == null && video == null) - Padding( - padding: const EdgeInsets.all(10.0), - child: MessageSendStateIcon( - [widget.message], - mainAxisAlignment: MainAxisAlignment.center, - ), - ), ], ), ); diff --git a/lib/src/views/chats/components/sliding_response.dart b/lib/src/views/chats/chat_messages_components/sliding_response.dart similarity index 100% rename from lib/src/views/chats/components/sliding_response.dart rename to lib/src/views/chats/chat_messages_components/sliding_response.dart diff --git a/lib/src/views/chats/chat_item_details_view.dart b/lib/src/views/chats/chat_messages_view.dart similarity index 97% rename from lib/src/views/chats/chat_item_details_view.dart rename to lib/src/views/chats/chat_messages_view.dart index 004a43a..f4f2c42 100644 --- a/lib/src/views/chats/chat_item_details_view.dart +++ b/lib/src/views/chats/chat_messages_view.dart @@ -5,7 +5,7 @@ import 'dart:io'; import 'package:flutter/material.dart'; import 'package:font_awesome_flutter/font_awesome_flutter.dart'; import 'package:twonly/globals.dart'; -import 'package:twonly/src/views/chats/components/chat_list_entry.dart'; +import 'package:twonly/src/views/chats/chat_messages_components/chat_message_entry.dart'; import 'package:twonly/src/views/components/animate_icon.dart'; import 'package:twonly/src/views/components/initialsavatar.dart'; import 'package:twonly/src/views/components/verified_shield.dart'; @@ -26,16 +26,16 @@ Color getMessageColor(Message message) { } /// Displays detailed information about a SampleItem. -class ChatItemDetailsView extends StatefulWidget { - const ChatItemDetailsView(this.contact, {super.key}); +class ChatMessagesView extends StatefulWidget { + const ChatMessagesView(this.contact, {super.key}); final Contact contact; @override - State createState() => _ChatItemDetailsViewState(); + State createState() => _ChatMessagesViewState(); } -class _ChatItemDetailsViewState extends State { +class _ChatMessagesViewState extends State { TextEditingController newMessageController = TextEditingController(); HashSet alreadyReportedOpened = HashSet(); late Contact user; diff --git a/lib/src/views/chats/components/chat_list_entry.dart b/lib/src/views/chats/components/chat_list_entry.dart deleted file mode 100644 index 2fdd9ea..0000000 --- a/lib/src/views/chats/components/chat_list_entry.dart +++ /dev/null @@ -1,298 +0,0 @@ -import 'dart:convert'; -import 'package:drift/drift.dart' show Value; -import 'package:flutter/material.dart'; -import 'package:font_awesome_flutter/font_awesome_flutter.dart'; -import 'package:twonly/globals.dart'; -import 'package:twonly/src/views/chats/chat_item_details_view.dart'; -import 'package:twonly/src/views/chats/components/in_chat_media_viewer.dart'; -import 'package:twonly/src/views/components/animate_icon.dart'; -import 'package:twonly/src/views/components/better_text.dart'; -import 'package:twonly/src/views/chats/components/sliding_response.dart'; -import 'package:twonly/src/database/twonly_database.dart'; -import 'package:twonly/src/database/tables/messages_table.dart'; -import 'package:twonly/src/model/json/message.dart'; -import 'package:twonly/src/providers/api/api.dart'; -import 'package:twonly/src/providers/api/media_received.dart' as received; -import 'package:twonly/src/services/notification_service.dart'; -import 'package:twonly/src/views/chats/media_viewer_view.dart'; - -class ChatListEntry extends StatelessWidget { - const ChatListEntry( - this.message, - this.contact, - this.lastMessageFromSameUser, - this.textReactions, - this.otherReactions, { - super.key, - required this.onResponseTriggered, - }); - final Message message; - final Contact contact; - final bool lastMessageFromSameUser; - final List textReactions; - final List otherReactions; - final Function(Message) onResponseTriggered; - - Widget getReactionRow() { - List children = []; - bool hasOneTextReaction = false; - bool hasOneReopened = false; - for (final reaction in otherReactions) { - MessageContent? content = MessageContent.fromJson( - reaction.kind, jsonDecode(reaction.contentJson!)); - - if (content is ReopenedMediaFileContent) { - if (hasOneReopened) continue; - hasOneReopened = true; - children.add( - Expanded( - child: Align( - alignment: Alignment.bottomRight, - child: Padding( - padding: EdgeInsets.only(right: 3), - child: FaIcon( - FontAwesomeIcons.repeat, - size: 12, - color: Colors.white, - ), - ), - ), - ), - ); - } - // only show one reaction - if (hasOneTextReaction) continue; - - if (content is TextMessageContent) { - hasOneTextReaction = true; - if (!isEmoji(content.text)) continue; - late Widget child; - if (EmojiAnimation.animatedIcons.containsKey(content.text)) { - child = SizedBox( - height: 18, - child: EmojiAnimation(emoji: content.text), - ); - } else { - child = Text(content.text, style: TextStyle(fontSize: 14)); - } - children.insert( - 0, - Padding( - padding: EdgeInsets.only(left: 3), - child: child, - ), - ); - } - } - - if (children.isEmpty) return Container(); - - return Row( - mainAxisAlignment: message.messageOtherId == null - ? MainAxisAlignment.start - : MainAxisAlignment.end, - children: children, - ); - } - - Widget getTextResponseColumns(BuildContext context, bool right) { - List children = []; - for (final reaction in textReactions) { - MessageContent? content = MessageContent.fromJson( - reaction.kind, jsonDecode(reaction.contentJson!)); - - if (content is TextMessageContent) { - var entries = [ - FaIcon( - FontAwesomeIcons.reply, - size: 10, - ), - SizedBox(width: 5), - Container( - constraints: BoxConstraints( - maxWidth: MediaQuery.of(context).size.width * 0.5, - ), - child: Text( - content.text, - style: TextStyle(fontSize: 14), - textAlign: right ? TextAlign.left : TextAlign.right, - )), - ]; - if (!right) { - entries = entries.reversed.toList(); - } - - Color color = getMessageColor(reaction); - - children.insert( - 0, - Container( - padding: EdgeInsets.only(top: 5, bottom: 0, right: 10, left: 10), - child: Container( - constraints: BoxConstraints( - maxWidth: MediaQuery.of(context).size.width * 0.8, - ), - padding: EdgeInsets.symmetric(vertical: 1, horizontal: 10), - decoration: BoxDecoration( - color: color, - borderRadius: BorderRadius.circular(12.0), - ), - child: Row( - mainAxisSize: MainAxisSize.min, - children: entries, - ), - ), - ), - ); - } - } - - if (children.isEmpty) return Container(); - - return Column( - crossAxisAlignment: - right ? CrossAxisAlignment.start : CrossAxisAlignment.end, - children: children, - ); - } - - @override - Widget build(BuildContext context) { - bool right = message.messageOtherId == null; - - MessageContent? content = - MessageContent.fromJson(message.kind, jsonDecode(message.contentJson!)); - - Widget child = Container(); - - if (content is TextMessageContent) { - if (EmojiAnimation.supported(content.text)) { - child = child = Container( - constraints: BoxConstraints( - maxWidth: 100, - ), - padding: EdgeInsets.symmetric( - vertical: 4, - horizontal: 10, - ), - child: EmojiAnimation(emoji: content.text), - ); - } else { - child = Container( - constraints: BoxConstraints( - maxWidth: MediaQuery.of(context).size.width * 0.8, - ), - padding: EdgeInsets.symmetric(vertical: 4, horizontal: 10), - decoration: BoxDecoration( - color: getMessageColor(message), - borderRadius: BorderRadius.circular(12.0), - ), - child: BetterText(text: content.text), - ); - } - } else if (content is MediaMessageContent) { - Color color = getMessageColorFromType( - content, - context, - ); - - child = GestureDetector( - onDoubleTap: () async { - if (message.openedAt == null && message.messageOtherId != null || - message.mediaStored) { - return; - } - if (await received.existsMediaFile(message.messageId, "png")) { - await encryptAndSendMessageAsync( - null, - contact.userId, - MessageJson( - kind: MessageKind.reopenedMedia, - messageId: message.messageId, - content: ReopenedMediaFileContent( - messageId: message.messageOtherId!, - ), - timestamp: DateTime.now(), - ), - pushKind: PushKind.reopenedMedia, - ); - await twonlyDatabase.messagesDao.updateMessageByMessageId( - message.messageId, - MessagesCompanion(openedAt: Value(null)), - ); - } - }, - onTap: () { - if (message.kind == MessageKind.media) { - if (message.downloadState == DownloadState.downloaded && - message.openedAt == null) { - Navigator.push( - context, - MaterialPageRoute(builder: (context) { - return MediaViewerView(contact, initialMessage: message); - }), - ); - } else if (message.downloadState == DownloadState.pending) { - received.startDownloadMedia(message, true); - } - } - }, - child: Container( - width: 150, - decoration: BoxDecoration( - border: Border.all( - color: color, - width: 1.0, - ), - borderRadius: BorderRadius.circular(12.0), - ), - child: Align( - alignment: Alignment.centerRight, - child: ClipRRect( - borderRadius: BorderRadius.circular(12), - child: InChatMediaViewer( - message: message, - contact: contact, - ), - ), - ), - ), - ); - } - - return Align( - alignment: right ? Alignment.centerRight : Alignment.centerLeft, - child: Padding( - padding: lastMessageFromSameUser - ? EdgeInsets.only(top: 5, bottom: 0, right: 10, left: 10) - : EdgeInsets.only(top: 5, bottom: 20, right: 10, left: 10), - child: Column( - mainAxisAlignment: - right ? MainAxisAlignment.end : MainAxisAlignment.start, - crossAxisAlignment: - right ? CrossAxisAlignment.end : CrossAxisAlignment.start, - children: [ - SlidingResponse( - child: Stack( - alignment: right ? Alignment.centerRight : Alignment.centerLeft, - children: [ - child, - Positioned( - bottom: 5, - left: 5, - right: 5, - child: getReactionRow(), - ), - ], - ), - onResponseTriggered: () { - onResponseTriggered(message); - }, - ), - getTextResponseColumns(context, !right) - ], - ), - ), - ); - } -} diff --git a/lib/src/views/chats/start_new_chat.dart b/lib/src/views/chats/start_new_chat.dart index 1ffb23b..689abc7 100644 --- a/lib/src/views/chats/start_new_chat.dart +++ b/lib/src/views/chats/start_new_chat.dart @@ -10,7 +10,7 @@ import 'package:twonly/src/views/components/user_context_menu.dart'; import 'package:twonly/src/database/daos/contacts_dao.dart'; import 'package:twonly/src/database/twonly_database.dart'; import 'package:twonly/src/utils/misc.dart'; -import 'package:twonly/src/views/chats/chat_item_details_view.dart'; +import 'package:twonly/src/views/chats/chat_messages_view.dart'; import 'package:twonly/src/views/chats/search_username_view.dart'; class StartNewChat extends StatefulWidget { @@ -182,7 +182,7 @@ class UserList extends StatelessWidget { Navigator.pushReplacement( context, MaterialPageRoute(builder: (context) { - return ChatItemDetailsView(user); + return ChatMessagesView(user); }), ); }, diff --git a/lib/src/views/components/user_context_menu.dart b/lib/src/views/components/user_context_menu.dart index 5d4e6a4..46fbdbb 100644 --- a/lib/src/views/components/user_context_menu.dart +++ b/lib/src/views/components/user_context_menu.dart @@ -5,7 +5,7 @@ import 'package:pie_menu/pie_menu.dart'; import 'package:twonly/globals.dart'; import 'package:twonly/src/database/twonly_database.dart'; import 'package:twonly/src/utils/misc.dart'; -import 'package:twonly/src/views/chats/chat_item_details_view.dart'; +import 'package:twonly/src/views/chats/chat_messages_view.dart'; import 'package:twonly/src/views/contact/contact_verify_view.dart'; class UserContextMenu extends StatefulWidget { @@ -66,7 +66,7 @@ class _UserContextMenuState extends State { onSelect: () { Navigator.push(context, MaterialPageRoute( builder: (context) { - return ChatItemDetailsView(widget.contact); + return ChatMessagesView(widget.contact); }, )); },