diff --git a/CHANGELOG.md b/CHANGELOG.md index 9073e77..66356bd 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,7 @@ +## 0.3.4 - October 25 2023 + +- Add interface methods for getting amount of unread messages + ## 0.3.3 - October 10 2023 - Add icon color property for icon buttons diff --git a/packages/flutter_community_chat/pubspec.yaml b/packages/flutter_community_chat/pubspec.yaml index 24258b3..51b24c7 100644 --- a/packages/flutter_community_chat/pubspec.yaml +++ b/packages/flutter_community_chat/pubspec.yaml @@ -1,11 +1,15 @@ +# SPDX-FileCopyrightText: 2022 Iconica +# +# SPDX-License-Identifier: GPL-3.0-or-later + name: flutter_community_chat description: A new Flutter package project. -version: 0.3.3 +version: 0.3.4 publish_to: none environment: - sdk: '>=2.18.2 <3.0.0' + sdk: '>=3.1.0 <4.0.0' flutter: ">=1.17.0" dependencies: @@ -15,12 +19,12 @@ dependencies: git: url: https://github.com/Iconica-Development/flutter_community_chat path: packages/flutter_community_chat_view - ref: 0.3.3 + ref: 0.3.4 flutter_community_chat_interface: git: url: https://github.com/Iconica-Development/flutter_community_chat path: packages/flutter_community_chat_interface - ref: 0.3.3 + ref: 0.3.4 dev_dependencies: flutter_lints: ^2.0.0 diff --git a/packages/flutter_community_chat_firebase/lib/service/firebase_chat_service.dart b/packages/flutter_community_chat_firebase/lib/service/firebase_chat_service.dart index 5d082cc..adc3554 100644 --- a/packages/flutter_community_chat_firebase/lib/service/firebase_chat_service.dart +++ b/packages/flutter_community_chat_firebase/lib/service/firebase_chat_service.dart @@ -6,7 +6,6 @@ import 'dart:async'; import 'package:cloud_firestore/cloud_firestore.dart'; import 'package:firebase_core/firebase_core.dart'; import 'package:firebase_storage/firebase_storage.dart'; -import 'package:flutter/material.dart'; import 'package:flutter_community_chat_firebase/config/firebase_chat_options.dart'; import 'package:flutter_community_chat_firebase/dto/firebase_chat_document.dart'; import 'package:flutter_community_chat_interface/flutter_community_chat_interface.dart'; @@ -197,7 +196,6 @@ class FirebaseChatService implements ChatService { StreamSubscription? chatsSubscription; controller = StreamController( onListen: () async { - debugPrint('Start listening to chats'); var currentUser = await _userService.getCurrentUser(); var userSnapshot = await _db .collection(_options.usersCollectionName) @@ -223,7 +221,6 @@ class FirebaseChatService implements ChatService { }, onCancel: () { chatsSubscription?.cancel(); - debugPrint('Stop listening to chats'); }, ); return controller.stream; @@ -416,4 +413,51 @@ class FirebaseChatService implements ChatService { return chat; } + + @override + Stream getUnreadChatsCountStream() { + // open a stream to the user's chats collection and listen to changes in this collection we will also add the amount of read chats + StreamSubscription? unreadChatSubscription; + late StreamController controller; + controller = StreamController( + onListen: () async { + var currentUser = await _userService.getCurrentUser(); + var userSnapshot = _db + .collection(_options.usersCollectionName) + .doc(currentUser?.id) + .collection('chats') + .snapshots(); + + unreadChatSubscription = userSnapshot.listen((event) { + // every chat has a field called amount_unread_messages, combine all of these fields to get the total amount of unread messages + var unreadChats = event.docs + .map((chat) => chat.data()['amount_unread_messages'] ?? 0) + .toList(); + var totalUnreadChats = unreadChats.fold( + 0, (previousValue, element) => previousValue + (element as int)); + controller.add(totalUnreadChats); + }); + }, + onCancel: () { + unreadChatSubscription?.cancel(); + }, + ); + return controller.stream; + } + + @override + Future readChat(ChatModel chat) async { + // set the amount of read chats to the amount of messages in the chat + var currentUser = await _userService.getCurrentUser(); + if (currentUser?.id == null || chat.id == null) { + return; + } + // set the amount of unread messages to 0 + await _db + .collection(_options.usersCollectionName) + .doc(currentUser!.id!) + .collection('chats') + .doc(chat.id) + .update({'amount_unread_messages': 0}); + } } diff --git a/packages/flutter_community_chat_firebase/lib/service/firebase_message_service.dart b/packages/flutter_community_chat_firebase/lib/service/firebase_message_service.dart index d34b27b..70df4f6 100644 --- a/packages/flutter_community_chat_firebase/lib/service/firebase_message_service.dart +++ b/packages/flutter_community_chat_firebase/lib/service/firebase_message_service.dart @@ -68,6 +68,28 @@ class FirebaseMessageService implements MessageService { if (chat.id != null && _controller.hasListener && (_subscription == null)) { _subscription = _startListeningForMessages(chat); } + + // update the chat counter for the other users + // get all users from the chat + // there is a field in the chat document called users that has a list of user ids + var fetchedChat = await chatReference.get(); + var chatUsers = fetchedChat.data()?['users'] as List; + // for all users except the message sender update the unread counter + for (var userId in chatUsers) { + if (userId != currentUser.id) { + var userReference = _db + .collection( + _options.usersCollectionName, + ) + .doc(userId) + .collection('chats') + .doc(chat.id); + + await userReference.update({ + 'amount_unread_messages': FieldValue.increment(1), + }); + } + } } @override diff --git a/packages/flutter_community_chat_firebase/pubspec.yaml b/packages/flutter_community_chat_firebase/pubspec.yaml index 2099781..9983944 100644 --- a/packages/flutter_community_chat_firebase/pubspec.yaml +++ b/packages/flutter_community_chat_firebase/pubspec.yaml @@ -1,10 +1,14 @@ +# SPDX-FileCopyrightText: 2022 Iconica +# +# SPDX-License-Identifier: GPL-3.0-or-later + name: flutter_community_chat_firebase description: A new Flutter package project. -version: 0.3.3 +version: 0.3.4 publish_to: none environment: - sdk: '>=2.18.2 <3.0.0' + sdk: '>=3.1.0 <4.0.0' flutter: ">=1.17.0" dependencies: @@ -19,7 +23,7 @@ dependencies: git: url: https://github.com/Iconica-Development/flutter_community_chat path: packages/flutter_community_chat_interface - ref: 0.3.3 + ref: 0.3.4 dev_dependencies: flutter_lints: ^2.0.0 diff --git a/packages/flutter_community_chat_interface/lib/src/service/chat_service.dart b/packages/flutter_community_chat_interface/lib/src/service/chat_service.dart index f42d10c..d6c649d 100644 --- a/packages/flutter_community_chat_interface/lib/src/service/chat_service.dart +++ b/packages/flutter_community_chat_interface/lib/src/service/chat_service.dart @@ -6,5 +6,7 @@ abstract class ChatService { Future getOrCreateChatByUser(ChatUserModel user); Future getChatById(String id); Future deleteChat(ChatModel chat); + Future readChat(ChatModel chat); Future storeChatIfNot(ChatModel chat); + Stream getUnreadChatsCountStream(); } diff --git a/packages/flutter_community_chat_interface/pubspec.yaml b/packages/flutter_community_chat_interface/pubspec.yaml index cd8ac09..4d0faf1 100644 --- a/packages/flutter_community_chat_interface/pubspec.yaml +++ b/packages/flutter_community_chat_interface/pubspec.yaml @@ -1,10 +1,14 @@ +# SPDX-FileCopyrightText: 2022 Iconica +# +# SPDX-License-Identifier: GPL-3.0-or-later + name: flutter_community_chat_interface description: A new Flutter package project. -version: 0.3.3 +version: 0.3.4 publish_to: none environment: - sdk: '>=2.18.2 <3.0.0' + sdk: ">=3.1.0 <4.0.0" flutter: ">=1.17.0" dependencies: @@ -12,7 +16,7 @@ dependencies: sdk: flutter flutter_data_interface: git: - url: https://github.com/Iconica-Development/flutter_data_interface + url: https://github.com/Iconica-Development/flutter_data_interface.git ref: 1.0.0 dev_dependencies: diff --git a/packages/flutter_community_chat_view/example/lib/main.dart b/packages/flutter_community_chat_view/example/lib/main.dart index 18eb8f3..782a0dc 100644 --- a/packages/flutter_community_chat_view/example/lib/main.dart +++ b/packages/flutter_community_chat_view/example/lib/main.dart @@ -19,6 +19,7 @@ class MyStatefulWidget extends StatefulWidget { class _MyStatefulWidgetState extends State { static final pietUser = ChatUserModel( + id: 'piet', firstName: 'Piet', lastName: 'Jansen', imageUrl: 'https://xsgames.co/randomusers/avatar.php?g=female', @@ -37,11 +38,7 @@ class _MyStatefulWidgetState extends State { timestamp: DateTime.now(), ), ChatTextMessageModel( - sender: ChatUserModel( - firstName: 'Jan', - lastName: 'Jansen', - imageUrl: 'https://xsgames.co/randomusers/avatar.php?g=male', - ), + sender: janUser, text: 'Met mij gaat het goed, dankje!', timestamp: DateTime.now().subtract(const Duration(days: 2)), ) @@ -109,6 +106,7 @@ class _MyStatefulWidgetState extends State { onPressChat: (chat) => Navigator.of(context).push( MaterialPageRoute( builder: (context) => ChatDetailScreen( + userId: 'piet', chat: chat, chatMessages: messageStream, options: options, @@ -120,6 +118,7 @@ class _MyStatefulWidgetState extends State { () => debugPrint('onMessageSubmit'), ); }, + onReadChat: (chat) async {}, onUploadImage: (image) async {}, ), ), diff --git a/packages/flutter_community_chat_view/example/pubspec.lock b/packages/flutter_community_chat_view/example/pubspec.lock deleted file mode 100644 index 68ae23f..0000000 --- a/packages/flutter_community_chat_view/example/pubspec.lock +++ /dev/null @@ -1,716 +0,0 @@ -# Generated by pub -# See https://dart.dev/tools/pub/glossary#lockfile -packages: - _fe_analyzer_shared: - dependency: transitive - description: - name: _fe_analyzer_shared - sha256: ae92f5d747aee634b87f89d9946000c2de774be1d6ac3e58268224348cd0101a - url: "https://pub.dev" - source: hosted - version: "61.0.0" - analyzer: - dependency: transitive - description: - name: analyzer - sha256: ea3d8652bda62982addfd92fdc2d0214e5f82e43325104990d4f4c4a2a313562 - url: "https://pub.dev" - source: hosted - version: "5.13.0" - args: - dependency: transitive - description: - name: args - sha256: eef6c46b622e0494a36c5a12d10d77fb4e855501a91c1b9ef9339326e58f0596 - url: "https://pub.dev" - source: hosted - version: "2.4.2" - async: - dependency: transitive - description: - name: async - sha256: "947bfcf187f74dbc5e146c9eb9c0f10c9f8b30743e341481c1e2ed3ecc18c20c" - url: "https://pub.dev" - source: hosted - version: "2.11.0" - boolean_selector: - dependency: transitive - description: - name: boolean_selector - sha256: "6cfb5af12253eaf2b368f07bacc5a80d1301a071c73360d746b7f2e32d762c66" - url: "https://pub.dev" - source: hosted - version: "2.1.1" - build: - dependency: transitive - description: - name: build - sha256: "80184af8b6cb3e5c1c4ec6d8544d27711700bc3e6d2efad04238c7b5290889f0" - url: "https://pub.dev" - source: hosted - version: "2.4.1" - built_collection: - dependency: transitive - description: - name: built_collection - sha256: "376e3dd27b51ea877c28d525560790aee2e6fbb5f20e2f85d5081027d94e2100" - url: "https://pub.dev" - source: hosted - version: "5.1.1" - built_value: - dependency: transitive - description: - name: built_value - sha256: a8de5955205b4d1dbbbc267daddf2178bd737e4bab8987c04a500478c9651e74 - url: "https://pub.dev" - source: hosted - version: "8.6.3" - cached_network_image: - dependency: transitive - description: - name: cached_network_image - sha256: f98972704692ba679db144261172a8e20feb145636c617af0eb4022132a6797f - url: "https://pub.dev" - source: hosted - version: "3.3.0" - cached_network_image_platform_interface: - dependency: transitive - description: - name: cached_network_image_platform_interface - sha256: "56aa42a7a01e3c9db8456d9f3f999931f1e05535b5a424271e9a38cabf066613" - url: "https://pub.dev" - source: hosted - version: "3.0.0" - cached_network_image_web: - dependency: transitive - description: - name: cached_network_image_web - sha256: "759b9a9f8f6ccbb66c185df805fac107f05730b1dab9c64626d1008cca532257" - url: "https://pub.dev" - source: hosted - version: "1.1.0" - characters: - dependency: transitive - description: - name: characters - sha256: "04a925763edad70e8443c99234dc3328f442e811f1d8fd1a72f1c8ad0f69a605" - url: "https://pub.dev" - source: hosted - version: "1.3.0" - clock: - dependency: transitive - description: - name: clock - sha256: cb6d7f03e1de671e34607e909a7213e31d7752be4fb66a86d29fe1eb14bfb5cf - url: "https://pub.dev" - source: hosted - version: "1.1.1" - code_builder: - dependency: transitive - description: - name: code_builder - sha256: "1be9be30396d7e4c0db42c35ea6ccd7cc6a1e19916b5dc64d6ac216b5544d677" - url: "https://pub.dev" - source: hosted - version: "4.7.0" - collection: - dependency: transitive - description: - name: collection - sha256: f092b211a4319e98e5ff58223576de6c2803db36221657b46c82574721240687 - url: "https://pub.dev" - source: hosted - version: "1.17.2" - convert: - dependency: transitive - description: - name: convert - sha256: "0f08b14755d163f6e2134cb58222dd25ea2a2ee8a195e53983d57c075324d592" - url: "https://pub.dev" - source: hosted - version: "3.1.1" - cross_file: - dependency: transitive - description: - name: cross_file - sha256: fd832b5384d0d6da4f6df60b854d33accaaeb63aa9e10e736a87381f08dee2cb - url: "https://pub.dev" - source: hosted - version: "0.3.3+5" - crypto: - dependency: transitive - description: - name: crypto - sha256: ff625774173754681d66daaf4a448684fb04b78f902da9cb3d308c19cc5e8bab - url: "https://pub.dev" - source: hosted - version: "3.0.3" - dart_style: - dependency: transitive - description: - name: dart_style - sha256: "1efa911ca7086affd35f463ca2fc1799584fb6aa89883cf0af8e3664d6a02d55" - url: "https://pub.dev" - source: hosted - version: "2.3.2" - fake_async: - dependency: transitive - description: - name: fake_async - sha256: "511392330127add0b769b75a987850d136345d9227c6b94c96a04cf4a391bf78" - url: "https://pub.dev" - source: hosted - version: "1.3.1" - ffi: - dependency: transitive - description: - name: ffi - sha256: "7bf0adc28a23d395f19f3f1eb21dd7cfd1dd9f8e1c50051c069122e6853bc878" - url: "https://pub.dev" - source: hosted - version: "2.1.0" - file: - dependency: transitive - description: - name: file - sha256: "5fc22d7c25582e38ad9a8515372cd9a93834027aacf1801cf01164dac0ffa08c" - url: "https://pub.dev" - source: hosted - version: "7.0.0" - file_selector_linux: - dependency: transitive - description: - name: file_selector_linux - sha256: "045d372bf19b02aeb69cacf8b4009555fb5f6f0b7ad8016e5f46dd1387ddd492" - url: "https://pub.dev" - source: hosted - version: "0.9.2+1" - file_selector_macos: - dependency: transitive - description: - name: file_selector_macos - sha256: b15c3da8bd4908b9918111fa486903f5808e388b8d1c559949f584725a6594d6 - url: "https://pub.dev" - source: hosted - version: "0.9.3+3" - file_selector_platform_interface: - dependency: transitive - description: - name: file_selector_platform_interface - sha256: "0aa47a725c346825a2bd396343ce63ac00bda6eff2fbc43eabe99737dede8262" - url: "https://pub.dev" - source: hosted - version: "2.6.1" - file_selector_windows: - dependency: transitive - description: - name: file_selector_windows - sha256: d3547240c20cabf205c7c7f01a50ecdbc413755814d6677f3cb366f04abcead0 - url: "https://pub.dev" - source: hosted - version: "0.9.3+1" - fixnum: - dependency: transitive - description: - name: fixnum - sha256: "25517a4deb0c03aa0f32fd12db525856438902d9c16536311e76cdc57b31d7d1" - url: "https://pub.dev" - source: hosted - version: "1.1.0" - flutter: - dependency: "direct main" - description: flutter - source: sdk - version: "0.0.0" - flutter_cache_manager: - dependency: transitive - description: - name: flutter_cache_manager - sha256: "8207f27539deb83732fdda03e259349046a39a4c767269285f449ade355d54ba" - url: "https://pub.dev" - source: hosted - version: "3.3.1" - flutter_community_chat_interface: - dependency: transitive - description: - path: "packages/flutter_community_chat_interface" - ref: "0.3.3" - resolved-ref: "2e79910e7767a89b1ae9232aec2c5f3bc99f8027" - url: "https://github.com/Iconica-Development/flutter_community_chat" - source: git - version: "0.3.3" - flutter_community_chat_view: - dependency: "direct main" - description: - path: ".." - relative: true - source: path - version: "0.3.3" - flutter_data_interface: - dependency: transitive - description: - path: "." - ref: "1.0.0" - resolved-ref: "500ed1d08095b33387ae3aa4ed1a2ad4d2fb2ac3" - url: "https://github.com/Iconica-Development/flutter_data_interface.git" - source: git - version: "1.0.0" - flutter_image_picker: - dependency: transitive - description: - path: "." - ref: "1.0.4" - resolved-ref: "829574e5f650cabcbd157f22b95001c9052fce0d" - url: "https://github.com/Iconica-Development/flutter_image_picker" - source: git - version: "1.0.4" - flutter_lints: - dependency: "direct dev" - description: - name: flutter_lints - sha256: a25a15ebbdfc33ab1cd26c63a6ee519df92338a9c10f122adda92938253bef04 - url: "https://pub.dev" - source: hosted - version: "2.0.3" - flutter_plugin_android_lifecycle: - dependency: transitive - description: - name: flutter_plugin_android_lifecycle - sha256: f185ac890306b5779ecbd611f52502d8d4d63d27703ef73161ca0407e815f02c - url: "https://pub.dev" - source: hosted - version: "2.0.16" - flutter_test: - dependency: "direct dev" - description: flutter - source: sdk - version: "0.0.0" - flutter_web_plugins: - dependency: transitive - description: flutter - source: sdk - version: "0.0.0" - glob: - dependency: transitive - description: - name: glob - sha256: "0e7014b3b7d4dac1ca4d6114f82bf1782ee86745b9b42a92c9289c23d8a0ab63" - url: "https://pub.dev" - source: hosted - version: "2.1.2" - http: - dependency: transitive - description: - name: http - sha256: "759d1a329847dd0f39226c688d3e06a6b8679668e350e2891a6474f8b4bb8525" - url: "https://pub.dev" - source: hosted - version: "1.1.0" - http_parser: - dependency: transitive - description: - name: http_parser - sha256: "2aa08ce0341cc9b354a498388e30986515406668dbcc4f7c950c3e715496693b" - url: "https://pub.dev" - source: hosted - version: "4.0.2" - image_picker: - dependency: transitive - description: - name: image_picker - sha256: b6951e25b795d053a6ba03af5f710069c99349de9341af95155d52665cb4607c - url: "https://pub.dev" - source: hosted - version: "0.8.9" - image_picker_android: - dependency: transitive - description: - name: image_picker_android - sha256: "0c7b83bbe2980c8a8e36e974f055e11e51675784e13a4762889feed0f3937ff2" - url: "https://pub.dev" - source: hosted - version: "0.8.8+1" - image_picker_for_web: - dependency: transitive - description: - name: image_picker_for_web - sha256: "869fe8a64771b7afbc99fc433a5f7be2fea4d1cb3d7c11a48b6b579eb9c797f0" - url: "https://pub.dev" - source: hosted - version: "2.2.0" - image_picker_ios: - dependency: transitive - description: - name: image_picker_ios - sha256: c5538cacefacac733c724be7484377923b476216ad1ead35a0d2eadcdc0fc497 - url: "https://pub.dev" - source: hosted - version: "0.8.8+2" - image_picker_linux: - dependency: transitive - description: - name: image_picker_linux - sha256: "4ed1d9bb36f7cd60aa6e6cd479779cc56a4cb4e4de8f49d487b1aaad831300fa" - url: "https://pub.dev" - source: hosted - version: "0.2.1+1" - image_picker_macos: - dependency: transitive - description: - name: image_picker_macos - sha256: "3f5ad1e8112a9a6111c46d0b57a7be2286a9a07fc6e1976fdf5be2bd31d4ff62" - url: "https://pub.dev" - source: hosted - version: "0.2.1+1" - image_picker_platform_interface: - dependency: transitive - description: - name: image_picker_platform_interface - sha256: ed9b00e63977c93b0d2d2b343685bed9c324534ba5abafbb3dfbd6a780b1b514 - url: "https://pub.dev" - source: hosted - version: "2.9.1" - image_picker_windows: - dependency: transitive - description: - name: image_picker_windows - sha256: "6ad07afc4eb1bc25f3a01084d28520496c4a3bb0cb13685435838167c9dcedeb" - url: "https://pub.dev" - source: hosted - version: "0.2.1+1" - intl: - dependency: transitive - description: - name: intl - sha256: "3bc132a9dbce73a7e4a21a17d06e1878839ffbf975568bc875c60537824b0c4d" - url: "https://pub.dev" - source: hosted - version: "0.18.1" - js: - dependency: transitive - description: - name: js - sha256: f2c445dce49627136094980615a031419f7f3eb393237e4ecd97ac15dea343f3 - url: "https://pub.dev" - source: hosted - version: "0.6.7" - lints: - dependency: transitive - description: - name: lints - sha256: "0a217c6c989d21039f1498c3ed9f3ed71b354e69873f13a8dfc3c9fe76f1b452" - url: "https://pub.dev" - source: hosted - version: "2.1.1" - logging: - dependency: transitive - description: - name: logging - sha256: "623a88c9594aa774443aa3eb2d41807a48486b5613e67599fb4c41c0ad47c340" - url: "https://pub.dev" - source: hosted - version: "1.2.0" - matcher: - dependency: transitive - description: - name: matcher - sha256: "1803e76e6653768d64ed8ff2e1e67bea3ad4b923eb5c56a295c3e634bad5960e" - url: "https://pub.dev" - source: hosted - version: "0.12.16" - material_color_utilities: - dependency: transitive - description: - name: material_color_utilities - sha256: "9528f2f296073ff54cb9fee677df673ace1218163c3bc7628093e7eed5203d41" - url: "https://pub.dev" - source: hosted - version: "0.5.0" - meta: - dependency: transitive - description: - name: meta - sha256: "3c74dbf8763d36539f114c799d8a2d87343b5067e9d796ca22b5eb8437090ee3" - url: "https://pub.dev" - source: hosted - version: "1.9.1" - mime: - dependency: transitive - description: - name: mime - sha256: e4ff8e8564c03f255408decd16e7899da1733852a9110a58fe6d1b817684a63e - url: "https://pub.dev" - source: hosted - version: "1.0.4" - mockito: - dependency: transitive - description: - name: mockito - sha256: "7d5b53bcd556c1bc7ffbe4e4d5a19c3e112b7e925e9e172dd7c6ad0630812616" - url: "https://pub.dev" - source: hosted - version: "5.4.2" - octo_image: - dependency: transitive - description: - name: octo_image - sha256: "45b40f99622f11901238e18d48f5f12ea36426d8eced9f4cbf58479c7aa2430d" - url: "https://pub.dev" - source: hosted - version: "2.0.0" - package_config: - dependency: transitive - description: - name: package_config - sha256: "1c5b77ccc91e4823a5af61ee74e6b972db1ef98c2ff5a18d3161c982a55448bd" - url: "https://pub.dev" - source: hosted - version: "2.1.0" - path: - dependency: transitive - description: - name: path - sha256: "8829d8a55c13fc0e37127c29fedf290c102f4e40ae94ada574091fe0ff96c917" - url: "https://pub.dev" - source: hosted - version: "1.8.3" - path_provider: - dependency: transitive - description: - name: path_provider - sha256: a1aa8aaa2542a6bc57e381f132af822420216c80d4781f7aa085ca3229208aaa - url: "https://pub.dev" - source: hosted - version: "2.1.1" - path_provider_android: - dependency: transitive - description: - name: path_provider_android - sha256: "6b8b19bd80da4f11ce91b2d1fb931f3006911477cec227cce23d3253d80df3f1" - url: "https://pub.dev" - source: hosted - version: "2.2.0" - path_provider_foundation: - dependency: transitive - description: - name: path_provider_foundation - sha256: "19314d595120f82aca0ba62787d58dde2cc6b5df7d2f0daf72489e38d1b57f2d" - url: "https://pub.dev" - source: hosted - version: "2.3.1" - path_provider_linux: - dependency: transitive - description: - name: path_provider_linux - sha256: f7a1fe3a634fe7734c8d3f2766ad746ae2a2884abe22e241a8b301bf5cac3279 - url: "https://pub.dev" - source: hosted - version: "2.2.1" - path_provider_platform_interface: - dependency: transitive - description: - name: path_provider_platform_interface - sha256: "94b1e0dd80970c1ce43d5d4e050a9918fce4f4a775e6142424c30a29a363265c" - url: "https://pub.dev" - source: hosted - version: "2.1.1" - path_provider_windows: - dependency: transitive - description: - name: path_provider_windows - sha256: "8bc9f22eee8690981c22aa7fc602f5c85b497a6fb2ceb35ee5a5e5ed85ad8170" - url: "https://pub.dev" - source: hosted - version: "2.2.1" - platform: - dependency: transitive - description: - name: platform - sha256: "0a279f0707af40c890e80b1e9df8bb761694c074ba7e1d4ab1bc4b728e200b59" - url: "https://pub.dev" - source: hosted - version: "3.1.3" - plugin_platform_interface: - dependency: transitive - description: - name: plugin_platform_interface - sha256: da3fdfeccc4d4ff2da8f8c556704c08f912542c5fb3cf2233ed75372384a034d - url: "https://pub.dev" - source: hosted - version: "2.1.6" - pub_semver: - dependency: transitive - description: - name: pub_semver - sha256: "40d3ab1bbd474c4c2328c91e3a7df8c6dd629b79ece4c4bd04bee496a224fb0c" - url: "https://pub.dev" - source: hosted - version: "2.1.4" - rxdart: - dependency: transitive - description: - name: rxdart - sha256: "0c7c0cedd93788d996e33041ffecda924cc54389199cde4e6a34b440f50044cb" - url: "https://pub.dev" - source: hosted - version: "0.27.7" - sky_engine: - dependency: transitive - description: flutter - source: sdk - version: "0.0.99" - source_gen: - dependency: transitive - description: - name: source_gen - sha256: fc0da689e5302edb6177fdd964efcb7f58912f43c28c2047a808f5bfff643d16 - url: "https://pub.dev" - source: hosted - version: "1.4.0" - source_span: - dependency: transitive - description: - name: source_span - sha256: "53e943d4206a5e30df338fd4c6e7a077e02254531b138a15aec3bd143c1a8b3c" - url: "https://pub.dev" - source: hosted - version: "1.10.0" - sprintf: - dependency: transitive - description: - name: sprintf - sha256: "1fc9ffe69d4df602376b52949af107d8f5703b77cda567c4d7d86a0693120f23" - url: "https://pub.dev" - source: hosted - version: "7.0.0" - sqflite: - dependency: transitive - description: - name: sqflite - sha256: "591f1602816e9c31377d5f008c2d9ef7b8aca8941c3f89cc5fd9d84da0c38a9a" - url: "https://pub.dev" - source: hosted - version: "2.3.0" - sqflite_common: - dependency: transitive - description: - name: sqflite_common - sha256: "1b92f368f44b0dee2425bb861cfa17b6f6cf3961f762ff6f941d20b33355660a" - url: "https://pub.dev" - source: hosted - version: "2.5.0" - stack_trace: - dependency: transitive - description: - name: stack_trace - sha256: c3c7d8edb15bee7f0f74debd4b9c5f3c2ea86766fe4178eb2a18eb30a0bdaed5 - url: "https://pub.dev" - source: hosted - version: "1.11.0" - stream_channel: - dependency: transitive - description: - name: stream_channel - sha256: "83615bee9045c1d322bbbd1ba209b7a749c2cbcdcb3fdd1df8eb488b3279c1c8" - url: "https://pub.dev" - source: hosted - version: "2.1.1" - string_scanner: - dependency: transitive - description: - name: string_scanner - sha256: "556692adab6cfa87322a115640c11f13cb77b3f076ddcc5d6ae3c20242bedcde" - url: "https://pub.dev" - source: hosted - version: "1.2.0" - synchronized: - dependency: transitive - description: - name: synchronized - sha256: "5fcbd27688af6082f5abd611af56ee575342c30e87541d0245f7ff99faa02c60" - url: "https://pub.dev" - source: hosted - version: "3.1.0" - term_glyph: - dependency: transitive - description: - name: term_glyph - sha256: a29248a84fbb7c79282b40b8c72a1209db169a2e0542bce341da992fe1bc7e84 - url: "https://pub.dev" - source: hosted - version: "1.2.1" - test_api: - dependency: transitive - description: - name: test_api - sha256: "75760ffd7786fffdfb9597c35c5b27eaeec82be8edfb6d71d32651128ed7aab8" - url: "https://pub.dev" - source: hosted - version: "0.6.0" - typed_data: - dependency: transitive - description: - name: typed_data - sha256: facc8d6582f16042dd49f2463ff1bd6e2c9ef9f3d5da3d9b087e244a7b564b3c - url: "https://pub.dev" - source: hosted - version: "1.3.2" - uuid: - dependency: transitive - description: - name: uuid - sha256: b715b8d3858b6fa9f68f87d20d98830283628014750c2b09b6f516c1da4af2a7 - url: "https://pub.dev" - source: hosted - version: "4.1.0" - vector_math: - dependency: transitive - description: - name: vector_math - sha256: "80b3257d1492ce4d091729e3a67a60407d227c27241d6927be0130c98e741803" - url: "https://pub.dev" - source: hosted - version: "2.1.4" - watcher: - dependency: transitive - description: - name: watcher - sha256: "3d2ad6751b3c16cf07c7fca317a1413b3f26530319181b37e3b9039b84fc01d8" - url: "https://pub.dev" - source: hosted - version: "1.1.0" - web: - dependency: transitive - description: - name: web - sha256: dc8ccd225a2005c1be616fe02951e2e342092edf968cf0844220383757ef8f10 - url: "https://pub.dev" - source: hosted - version: "0.1.4-beta" - win32: - dependency: transitive - description: - name: win32 - sha256: "350a11abd2d1d97e0cc7a28a81b781c08002aa2864d9e3f192ca0ffa18b06ed3" - url: "https://pub.dev" - source: hosted - version: "5.0.9" - xdg_directories: - dependency: transitive - description: - name: xdg_directories - sha256: "589ada45ba9e39405c198fe34eb0f607cddb2108527e658136120892beac46d2" - url: "https://pub.dev" - source: hosted - version: "1.0.3" - yaml: - dependency: transitive - description: - name: yaml - sha256: "75769501ea3489fca56601ff33454fe45507ea3bfb014161abc3b43ae25989d5" - url: "https://pub.dev" - source: hosted - version: "3.1.2" -sdks: - dart: ">=3.1.0-185.0.dev <4.0.0" - flutter: ">=3.10.0" diff --git a/packages/flutter_community_chat_view/example/pubspec.yaml b/packages/flutter_community_chat_view/example/pubspec.yaml index 843637d..8532342 100644 --- a/packages/flutter_community_chat_view/example/pubspec.yaml +++ b/packages/flutter_community_chat_view/example/pubspec.yaml @@ -10,7 +10,7 @@ publish_to: 'none' # Remove this line if you wish to publish to pub.dev version: 1.0.0+1 environment: - sdk: '>=2.18.2 <3.0.0' + sdk: '>=3.1.0 <4.0.0' dependencies: flutter: sdk: flutter @@ -18,7 +18,7 @@ dependencies: git: url: https://github.com/Iconica-Development/flutter_community_chat path: packages/flutter_community_chat_view - ref: 0.3.3 + ref: 0.3.4 dev_dependencies: flutter_test: diff --git a/packages/flutter_community_chat_view/lib/src/screens/chat_detail_screen.dart b/packages/flutter_community_chat_view/lib/src/screens/chat_detail_screen.dart index 0b8b20b..0db1157 100644 --- a/packages/flutter_community_chat_view/lib/src/screens/chat_detail_screen.dart +++ b/packages/flutter_community_chat_view/lib/src/screens/chat_detail_screen.dart @@ -2,6 +2,7 @@ // // SPDX-License-Identifier: BSD-3-Clause +import 'dart:async'; import 'dart:typed_data'; import 'package:flutter/material.dart'; @@ -10,11 +11,13 @@ import 'package:flutter_community_chat_view/src/components/chat_bottom.dart'; import 'package:flutter_community_chat_view/src/components/chat_detail_row.dart'; import 'package:flutter_community_chat_view/src/components/image_loading_snackbar.dart'; -class ChatDetailScreen extends StatelessWidget { +class ChatDetailScreen extends StatefulWidget { const ChatDetailScreen({ + required this.userId, required this.options, required this.onMessageSubmit, required this.onUploadImage, + required this.onReadChat, this.translations = const ChatTranslations(), this.chat, this.chatMessages, @@ -24,34 +27,76 @@ class ChatDetailScreen extends StatelessWidget { }); final ChatModel? chat; + + /// The id of the current user that is viewing the chat. + final String userId; + final ChatOptions options; final ChatTranslations translations; final Stream>? chatMessages; final Future Function(Uint8List image) onUploadImage; final Future Function(String text) onMessageSubmit; + // called at the start of the screen to set the chat to read + // or when a new message is received + final Future Function(ChatModel chat) onReadChat; final VoidCallback? onPressChatTitle; /// The color of the icon buttons in the chat bottom. final Color? iconColor; + @override + State createState() => _ChatDetailScreenState(); +} + +class _ChatDetailScreenState extends State { + // stream listener that needs to be disposed later + late StreamSubscription>? _chatMessagesSubscription; + late Stream>? _chatMessages; + + @override + void initState() { + super.initState(); + // create a broadcast stream from the chat messages + _chatMessages = widget.chatMessages?.asBroadcastStream(); + _chatMessagesSubscription = _chatMessages?.listen((event) { + // check if the last message is from the current user + // if so, set the chat to read + if (event.isNotEmpty && + event.last.sender.id != widget.userId && + widget.chat != null) { + widget.onReadChat(widget.chat!); + } + }); + // set the chat to read when opening the screen + if (widget.chat != null) { + widget.onReadChat(widget.chat!); + } + } + + @override + void dispose() { + _chatMessagesSubscription?.cancel(); + super.dispose(); + } + @override Widget build(BuildContext context) { Future onPressSelectImage() => showModalBottomSheet( context: context, builder: (BuildContext context) => - options.imagePickerContainerBuilder( + widget.options.imagePickerContainerBuilder( () => Navigator.of(context).pop(), - translations, + widget.translations, ), ).then( (image) async { var messenger = ScaffoldMessenger.of(context) ..showSnackBar( - getImageLoadingSnackbar(translations), + getImageLoadingSnackbar(widget.translations), ); if (image != null) { - await onUploadImage(image); + await widget.onUploadImage(image); } messenger.hideCurrentSnackBar(); @@ -62,20 +107,20 @@ class ChatDetailScreen extends StatelessWidget { appBar: AppBar( centerTitle: true, title: GestureDetector( - onTap: onPressChatTitle, + onTap: widget.onPressChatTitle, child: Row( mainAxisSize: MainAxisSize.min, - children: chat == null + children: widget.chat == null ? [] : [ - if (chat is GroupChatModel) ...[ - options.groupAvatarBuilder( - (chat! as GroupChatModel).imageUrl, + if (widget.chat is GroupChatModel) ...[ + widget.options.groupAvatarBuilder( + (widget.chat! as GroupChatModel).imageUrl, 36.0, ), - ] else if (chat is PersonalChatModel) ...[ - options.userAvatarBuilder( - (chat! as PersonalChatModel).user, + ] else if (widget.chat is PersonalChatModel) ...[ + widget.options.userAvatarBuilder( + (widget.chat! as PersonalChatModel).user, 36.0, ), ] else @@ -84,10 +129,10 @@ class ChatDetailScreen extends StatelessWidget { child: Padding( padding: const EdgeInsets.only(left: 15.5), child: Text( - (chat is GroupChatModel) - ? (chat! as GroupChatModel).title - : (chat is PersonalChatModel) - ? (chat! as PersonalChatModel) + (widget.chat is GroupChatModel) + ? (widget.chat! as GroupChatModel).title + : (widget.chat is PersonalChatModel) + ? (widget.chat! as PersonalChatModel) .user .fullName ?? '' @@ -104,13 +149,14 @@ class ChatDetailScreen extends StatelessWidget { children: [ Expanded( child: StreamBuilder>( - stream: chatMessages, + stream: _chatMessages, builder: (BuildContext context, snapshot) => ListView( reverse: true, padding: const EdgeInsets.only(top: 24.0), children: [ for (var message - in (snapshot.data ?? chat?.messages ?? []).reversed) + in (snapshot.data ?? widget.chat?.messages ?? []) + .reversed) ChatDetailRow( message: message, ), @@ -118,14 +164,14 @@ class ChatDetailScreen extends StatelessWidget { ), ), ), - if (chat != null) + if (widget.chat != null) ChatBottom( - chat: chat!, - messageInputBuilder: options.messageInputBuilder, + chat: widget.chat!, + messageInputBuilder: widget.options.messageInputBuilder, onPressSelectImage: onPressSelectImage, - onMessageSubmit: onMessageSubmit, - translations: translations, - iconColor: iconColor, + onMessageSubmit: widget.onMessageSubmit, + translations: widget.translations, + iconColor: widget.iconColor, ), ], ), diff --git a/packages/flutter_community_chat_view/pubspec.yaml b/packages/flutter_community_chat_view/pubspec.yaml index b0a456a..e7e690a 100644 --- a/packages/flutter_community_chat_view/pubspec.yaml +++ b/packages/flutter_community_chat_view/pubspec.yaml @@ -4,12 +4,12 @@ name: flutter_community_chat_view description: A standard flutter package. -version: 0.3.3 +version: 0.3.4 publish_to: none environment: - sdk: '>=2.18.2 <3.0.0' + sdk: '>=3.1.0 <4.0.0' flutter: ">=1.17.0" dependencies: @@ -20,7 +20,7 @@ dependencies: git: url: https://github.com/Iconica-Development/flutter_community_chat path: packages/flutter_community_chat_interface - ref: 0.3.3 + ref: 0.3.4 cached_network_image: ^3.2.2 flutter_image_picker: git: diff --git a/pubspec.yaml b/pubspec.yaml index c3d88e0..fe778f0 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -1,6 +1,6 @@ name: flutter_community_chat_workspace environment: - sdk: '>=2.18.0 <3.0.0' + sdk: '>=3.1.0 <4.0.0' dev_dependencies: melos: ^3.0.1