From e93d71f47ddba3359dfa505b51ae2bb0fcd4360a Mon Sep 17 00:00:00 2001 From: Ahmed Aladdin Date: Mon, 23 Dec 2024 12:46:03 +0200 Subject: [PATCH 1/2] feature: handle mentions in incoming messages --- .../view/widget/highlight_text_widget.dart | 44 +++++++++++++++++++ .../chat/view_model/chats_view_model.dart | 8 ++++ 2 files changed, 52 insertions(+) diff --git a/lib/core/view/widget/highlight_text_widget.dart b/lib/core/view/widget/highlight_text_widget.dart index 9c76747..13eb2ea 100644 --- a/lib/core/view/widget/highlight_text_widget.dart +++ b/lib/core/view/widget/highlight_text_widget.dart @@ -25,6 +25,7 @@ class HighlightTextWidget extends StatelessWidget { final TextStyle normalStyle; final TextStyle highlightStyle; final TextStyle linkStyle; + final TextStyle mentionStyle; final TextOverflow overFlow; final int? maxLines; @@ -33,6 +34,11 @@ class HighlightTextWidget extends StatelessWidget { caseSensitive: false, ); + final RegExp _mentionRegExp = RegExp( + r'@\[(.*?)\]\((.*?)\)', + caseSensitive: false, + ); + HighlightTextWidget({ super.key, required this.text, @@ -43,6 +49,11 @@ class HighlightTextWidget extends StatelessWidget { color: Palette.accent, decoration: TextDecoration.underline, ), + this.mentionStyle = const TextStyle( + color: Color.fromARGB(255, 43, 121, 255), + fontWeight: FontWeight.bold, + decoration: TextDecoration.underline, + ), this.overFlow = TextOverflow.clip, this.maxLines, }); @@ -64,9 +75,14 @@ class HighlightTextWidget extends StatelessWidget { // Find all links in the text final List linkMatches = _linkRegExp.allMatches(text).toList(); + final List mantionMatches = + _mentionRegExp.allMatches(text).toList(); final List> linkRanges = linkMatches .map((match) => MapEntry(match.start, match.end - match.start)) .toList(); + final List> mentionRanges = mantionMatches + .map((match) => MapEntry(match.start, match.end - match.start)) + .toList(); final List> highlightRanges = List.generate(text.length, (index) => MapEntry(index, 'normal')); @@ -88,6 +104,22 @@ class HighlightTextWidget extends StatelessWidget { continue; } + lowerBoundIndex = lowerBound>( + mentionRanges, + MapEntry(i, 0), // Create a temporary MapEntry with the target value + compare: (a, b) => a.key.compareTo(b.key), // Compare by the key + ); + if (lowerBoundIndex != 0) { + lowerBoundIndex = (lowerBoundIndex < mentionRanges.length && + mentionRanges[lowerBoundIndex].key == i) + ? lowerBoundIndex + : lowerBoundIndex - 1; + } + if (isHighlight(i, lowerBoundIndex, mentionRanges)) { + highlightRanges[i] = MapEntry(i, 'mention'); + continue; + } + lowerBoundIndex = lowerBound>( linkRanges, MapEntry(i, 0), // Create a temporary MapEntry with the target value @@ -158,6 +190,18 @@ class HighlightTextWidget extends StatelessWidget { ), ); break; + case 'mention': + textSpans.add( + TextSpan( + text: '@${(text.substring(index, index + length)).splitMapJoin( + _mentionRegExp, + onMatch: (m) => m.group(1)!, + onNonMatch: (m) => m, + )}', + style: mentionStyle, + ), + ); + break; } } diff --git a/lib/features/chat/view_model/chats_view_model.dart b/lib/features/chat/view_model/chats_view_model.dart index 7180b96..7cf32e5 100644 --- a/lib/features/chat/view_model/chats_view_model.dart +++ b/lib/features/chat/view_model/chats_view_model.dart @@ -58,6 +58,14 @@ class ChatsViewModel extends _$ChatsViewModel { .toList(); } + UserModel getLocalUser(String id) { + if (id == ref.read(userProvider)!.id) { + // debugPrint('!!!** returning the current user'); + return ref.read(userProvider)!; + } + return _otherUsers[id]!; + } + Future getUser(String id) async { // debugPrint('!!!** called'); if (id == ref.read(userProvider)!.id) { From 33c2e4a9c3f212ed57728ac77af5c70c46e37481 Mon Sep 17 00:00:00 2001 From: Ahmed Aladdin Date: Mon, 23 Dec 2024 12:46:19 +0200 Subject: [PATCH 2/2] refactor: remove print statements --- lib/core/services/socket_service.dart | 3 --- lib/features/auth/repository/auth_remote_repository.dart | 1 - lib/features/chat/repository/chat_local_repository.dart | 3 --- lib/features/chat/view/screens/chat_screen.dart | 1 - lib/features/chat/view_model/event_handler.dart | 6 ------ lib/features/stories/view/widget/chats_list.dart | 1 - .../stories/view/widget/colapsed_story_section.dart | 1 - .../stories/view/widget/expanded_stories_section.dart | 1 - 8 files changed, 17 deletions(-) diff --git a/lib/core/services/socket_service.dart b/lib/core/services/socket_service.dart index 5fa5cd7..022ae5b 100644 --- a/lib/core/services/socket_service.dart +++ b/lib/core/services/socket_service.dart @@ -41,9 +41,6 @@ class SocketService { void _connect() { if (isConnected || USE_MOCK_DATA) return; debugPrint('*** Entered the connect method'); - debugPrint(_serverUrl); - debugPrint(_userId); - debugPrint(_sessionId); _socket = io(_serverUrl, { // 'autoConnect': false, diff --git a/lib/features/auth/repository/auth_remote_repository.dart b/lib/features/auth/repository/auth_remote_repository.dart index 970e80b..09953aa 100644 --- a/lib/features/auth/repository/auth_remote_repository.dart +++ b/lib/features/auth/repository/auth_remote_repository.dart @@ -112,7 +112,6 @@ class AuthRemoteRepository { final message = response.data['message']; return Left(AppError(message)); } - debugPrint('========================================='); debugPrint('Get me was successful'); UserModel user = await UserModel.fromMap(response.data['data']['user']); List blockedUsers = await _handleGetBlockedUsers(sessionId); diff --git a/lib/features/chat/repository/chat_local_repository.dart b/lib/features/chat/repository/chat_local_repository.dart index 4a7dd2a..3c93aa0 100644 --- a/lib/features/chat/repository/chat_local_repository.dart +++ b/lib/features/chat/repository/chat_local_repository.dart @@ -28,13 +28,10 @@ class ChatLocalRepository { ///////////////////////////////////// // set chats Future setChats(List list, String userId) async { - debugPrint('!!! set chats locally called'); try { await _chatsBox.put(_chatsBoxKey+userId, updateMessagesFilePath(list)); - debugPrint('@@@ did put chats use key: ${_chatsBoxKey+userId} and length of: ${list.length}'); return true; } catch (e) { - debugPrint('!!! exception on saving the chats list'); debugPrint(e.toString()); return false; } diff --git a/lib/features/chat/view/screens/chat_screen.dart b/lib/features/chat/view/screens/chat_screen.dart index 6c0806e..6f16e58 100644 --- a/lib/features/chat/view/screens/chat_screen.dart +++ b/lib/features/chat/view/screens/chat_screen.dart @@ -415,7 +415,6 @@ class _ChatScreen extends ConsumerState @override Widget build(BuildContext context) { - debugPrint('&*&**&**& rebuild chat screen'); final chats = ref.watch(chatsViewModelProvider); final index = chats.indexWhere((chat) => chat.id == widget.chatId); final ChatModel? chat = diff --git a/lib/features/chat/view_model/event_handler.dart b/lib/features/chat/view_model/event_handler.dart index 264748b..e227552 100644 --- a/lib/features/chat/view_model/event_handler.dart +++ b/lib/features/chat/view_model/event_handler.dart @@ -65,9 +65,6 @@ class EventHandler { if (_isProcessing || USE_MOCK_DATA) return; // Avoid multiple loops _isProcessing = true; - debugPrint('()()() called Processing Queue'); - debugPrint('()()() ${_queue.length}'); - debugPrint('()()() $_stopRequested'); int failingCounter = 0; @@ -128,7 +125,6 @@ class EventHandler { void _onSocketConnect() { final Signaling signaling = Signaling.instance; - debugPrint('!!! connected successfully'); // receive a message _socket.on(EventType.receiveMessage.event, (response) async { print('### got a message: $response'); @@ -313,7 +309,6 @@ class EventHandler { // get a call ended _socket.on(EventType.receiveCallEnded.event, (response) async { try { - debugPrint('### got a call ended: $response'); signaling.onReceiveEndCall?.call(response); } on Exception catch (e) { debugPrint('!!! Error in receiving a call ended:\n${e.toString()}'); @@ -323,7 +318,6 @@ class EventHandler { // get updated draft _socket.on(EventType.receiveUpdatedDraft.event, (response) async { try { - debugPrint('### got a draft: $response'); _chattingController.receiveUpdatedDraft(response['chatId'], response['draft']); } on Exception catch (e) { debugPrint('!!! Error in receiving a draft:\n${e.toString()}'); diff --git a/lib/features/stories/view/widget/chats_list.dart b/lib/features/stories/view/widget/chats_list.dart index bd77949..942ec1a 100644 --- a/lib/features/stories/view/widget/chats_list.dart +++ b/lib/features/stories/view/widget/chats_list.dart @@ -24,7 +24,6 @@ class ChatsList extends ConsumerWidget { Widget build(BuildContext context, WidgetRef ref) { final chatsList = ref.watch(chatsViewModelProvider); ChatKeys.resetChatTilePrefixSubvalue(); - debugPrint('^*^*^*^*^* chat list rebuilding'); return SliverList( key: ChatKeys.chatsListKey, diff --git a/lib/features/stories/view/widget/colapsed_story_section.dart b/lib/features/stories/view/widget/colapsed_story_section.dart index 80a226f..6a4878e 100644 --- a/lib/features/stories/view/widget/colapsed_story_section.dart +++ b/lib/features/stories/view/widget/colapsed_story_section.dart @@ -25,7 +25,6 @@ class ColapsedStorySection extends ConsumerWidget { }, ); - debugPrint('Building ColapsedStorySection...'); return Row( children: [ Expanded(child: StackedOverlappedImages(users: reorderedUsers)), diff --git a/lib/features/stories/view/widget/expanded_stories_section.dart b/lib/features/stories/view/widget/expanded_stories_section.dart index d3af9b9..7ef2af0 100644 --- a/lib/features/stories/view/widget/expanded_stories_section.dart +++ b/lib/features/stories/view/widget/expanded_stories_section.dart @@ -12,7 +12,6 @@ class ExpandedStoriesSection extends ConsumerWidget { Widget build(BuildContext context, WidgetRef ref) { ref.read(usersViewModelProvider.notifier).fetchContacts(); final isLoading = ref.watch(usersViewModelProvider.select((state) => state.isLoading)); - debugPrint('Building ExpandedStoriesSection...'); return LayoutBuilder( builder: (context, constraints) {