From 30521a34f465f8207c833b761cfd3636e5cb50d8 Mon Sep 17 00:00:00 2001 From: riccardocucia Date: Tue, 17 Jun 2025 10:17:30 +0200 Subject: [PATCH 1/9] ### Fixed * Fixed #29 update messages list after delete message ### Dependencies * Upgraded `supabase_flutter` to `^2.9.1` * Upgraded `meta` to `^1.16.0` --- CHANGELOG.md | 12 ++++++++++++ example/pubspec.yaml | 14 +++++++------- lib/src/class/supabase_chat_controller.dart | 18 +++++++++++++----- pubspec.yaml | 6 +++--- 4 files changed, 35 insertions(+), 15 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 0334203..06a5401 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,15 @@ +## [1.5.1] - 2025-06-17 +#### [@rickypid](https://github.com/rickypid) + +### Fixed + +* Fixed #29 update messages list after delete message + +### Dependencies + +* Upgraded `supabase_flutter` to `^2.9.1` +* Upgraded `meta` to `^1.16.0` + ## [1.5.0] - 2025-02-06 #### [@rickypid](https://github.com/rickypid) diff --git a/example/pubspec.yaml b/example/pubspec.yaml index 1357f2a..f13f00d 100644 --- a/example/pubspec.yaml +++ b/example/pubspec.yaml @@ -2,7 +2,7 @@ name: example description: A new Flutter project. publish_to: 'none' -version: 1.5.0 +version: 1.5.1 environment: sdk: '>=3.4.0 <4.0.0' @@ -11,7 +11,7 @@ dependencies: cupertino_icons: ^1.0.8 dio: ^5.8.0+1 faker: ^2.2.0 - file_picker: ^8.3.1 + file_picker: ^10.2.0 file_saver: ^0.2.14 flutter: sdk: flutter @@ -20,14 +20,14 @@ dependencies: flutter_login: ^5.0.0 flutter_supabase_chat_core: path: ../ - flutter_svg: ^2.0.17 - http: ^1.3.0 + flutter_svg: ^2.2.0 + http: ^1.4.0 image_picker: ^1.1.2 infinite_scroll_pagination: ^4.1.0 - open_filex: ^4.6.0 + open_filex: ^4.7.0 path_provider: ^2.1.5 - supabase_flutter: ^2.8.3 - timeago: ^3.7.0 + supabase_flutter: ^2.9.1 + timeago: ^3.7.1 dev_dependencies: diff --git a/lib/src/class/supabase_chat_controller.dart b/lib/src/class/supabase_chat_controller.dart index bf3301b..b507207 100644 --- a/lib/src/class/supabase_chat_controller.dart +++ b/lib/src/class/supabase_chat_controller.dart @@ -75,8 +75,15 @@ class SupabaseChatController { .order('createdAt', ascending: false) .range(pageSize * _currentPage, (_currentPage * pageSize) + pageSize); - void _onData(List> data) { - for (var val in data) { + void _onData( + List> newData, List> oldData) { + final deletedMessagesId = oldData + .map( + (e) => e['id'].toString(), + ) + .toList(); + _messages.removeWhere((element) => deletedMessagesId.contains(element.id)); + for (var val in newData) { final author = _room.users.firstWhere( (u) => u.id == val['authorId'], orElse: () => types.User(id: val['authorId'] as String), @@ -103,7 +110,7 @@ class SupabaseChatController { /// then it will be necessary to call the [loadPreviousMessages] method to get /// the next page of messages Stream> get messages { - _messagesQuery().then((value) => _onData(value)); + _messagesQuery().then((value) => _onData(value, [])); _client .channel('${_config.schema}:${_config.messagesTableName}:${_room.id}') .onPostgresChanges( @@ -115,7 +122,8 @@ class SupabaseChatController { column: 'roomId', value: _room.id, ), - callback: (payload) => _onData([payload.newRecord]), + callback: (payload) => + _onData([payload.newRecord], [payload.oldRecord]), ) .subscribe(); return _messagesController.stream; @@ -125,7 +133,7 @@ class SupabaseChatController { /// page Future loadPreviousMessages() async { _currentPage += 1; - await _messagesQuery().then((value) => _onData(value)); + await _messagesQuery().then((value) => _onData(value, [])); } /// Returns a stream of typing users from Supabase for a specified room. diff --git a/pubspec.yaml b/pubspec.yaml index 320a7a0..504e70d 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -2,7 +2,7 @@ name: flutter_supabase_chat_core description: > Actively maintained, community-driven Supabase BaaS for chat applications with an optional chat UI. -version: 1.5.0 +version: 1.5.1 homepage: https://flutter-supabase-chat-core.insideapp.it repository: https://github.com/insideapp-srl/flutter_supabase_chat_core @@ -14,9 +14,9 @@ dependencies: flutter: sdk: flutter flutter_chat_types: ^3.6.2 - meta: ^1.15.0 + meta: ^1.16.0 mime: '>=1.0.2 <3.0.0' - supabase_flutter: ^2.8.3 + supabase_flutter: ^2.9.1 uuid: ^4.5.1 dev_dependencies: From 0b9a33f21d259c5d8cebb128ef7b77821f42763c Mon Sep 17 00:00:00 2001 From: riccardocucia Date: Tue, 17 Jun 2025 10:32:17 +0200 Subject: [PATCH 2/9] ### Fixed * Fixed #29 update messages list after delete message ### Dependencies * Upgraded `supabase_flutter` to `^2.9.1` * Upgraded `meta` to `^1.16.0` --- CHANGELOG.md | 1 + lib/src/class/supabase_chat_controller.dart | 2 +- .../user_status_detector/web_platform.dart | 32 ++++++++++--------- pubspec.yaml | 1 + 4 files changed, 20 insertions(+), 16 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 06a5401..8f43bdd 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,6 +9,7 @@ * Upgraded `supabase_flutter` to `^2.9.1` * Upgraded `meta` to `^1.16.0` +* Added `web` `^1.1.1` ## [1.5.0] - 2025-02-06 #### [@rickypid](https://github.com/rickypid) diff --git a/lib/src/class/supabase_chat_controller.dart b/lib/src/class/supabase_chat_controller.dart index b507207..f9944c5 100644 --- a/lib/src/class/supabase_chat_controller.dart +++ b/lib/src/class/supabase_chat_controller.dart @@ -76,7 +76,7 @@ class SupabaseChatController { .range(pageSize * _currentPage, (_currentPage * pageSize) + pageSize); void _onData( - List> newData, List> oldData) { + List> newData, List> oldData,) { final deletedMessagesId = oldData .map( (e) => e['id'].toString(), diff --git a/lib/src/widgets/user_status_detector/web_platform.dart b/lib/src/widgets/user_status_detector/web_platform.dart index 75eb894..4450203 100644 --- a/lib/src/widgets/user_status_detector/web_platform.dart +++ b/lib/src/widgets/user_status_detector/web_platform.dart @@ -1,30 +1,32 @@ -// ignore: avoid_web_libraries_in_flutter -import 'dart:html'; - +import 'dart:js_interop'; import 'package:flutter/material.dart'; +import 'package:web/web.dart' as web; import 'platforms_widgets_binding.dart'; PlatformsWidgetsBinding getInstance() => WebWidgetsBinding(); class WebWidgetsBinding extends PlatformsWidgetsBinding { + late JSFunction _focusListener; + late JSFunction _blurListener; + @override void addObserver(WidgetsBindingObserver state) { - window.addEventListener('focus', (event) => onFocus(event, state)); - window.addEventListener('blur', (event) => onBlur(event, state)); - } + _focusListener = ((web.Event _) { + state.didChangeAppLifecycleState(AppLifecycleState.resumed); + }).toJS; - @override - void removeObserver(WidgetsBindingObserver state) { - window.removeEventListener('focus', (event) => onFocus(event, state)); - window.removeEventListener('blur', (event) => onBlur(event, state)); - } + _blurListener = ((web.Event _) { + state.didChangeAppLifecycleState(AppLifecycleState.paused); + }).toJS; - void onFocus(Event e, WidgetsBindingObserver state) { - state.didChangeAppLifecycleState(AppLifecycleState.resumed); + web.window.addEventListener('focus', _focusListener); + web.window.addEventListener('blur', _blurListener); } - void onBlur(Event e, WidgetsBindingObserver state) { - state.didChangeAppLifecycleState(AppLifecycleState.paused); + @override + void removeObserver(WidgetsBindingObserver state) { + web.window.removeEventListener('focus', _focusListener); + web.window.removeEventListener('blur', _blurListener); } } diff --git a/pubspec.yaml b/pubspec.yaml index 504e70d..f4cc8d5 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -18,6 +18,7 @@ dependencies: mime: '>=1.0.2 <3.0.0' supabase_flutter: ^2.9.1 uuid: ^4.5.1 + web: ^1.1.1 dev_dependencies: flutter_lints: ^5.0.0 From 3ee1870f45edc42f5fe796b1d9ccbcc2269801d3 Mon Sep 17 00:00:00 2001 From: riccardocucia Date: Tue, 17 Jun 2025 10:32:32 +0200 Subject: [PATCH 3/9] ### Fixed * Fixed #29 update messages list after delete message ### Dependencies * Upgraded `supabase_flutter` to `^2.9.1` * Upgraded `meta` to `^1.16.0` --- lib/src/class/supabase_chat_controller.dart | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/lib/src/class/supabase_chat_controller.dart b/lib/src/class/supabase_chat_controller.dart index f9944c5..1585902 100644 --- a/lib/src/class/supabase_chat_controller.dart +++ b/lib/src/class/supabase_chat_controller.dart @@ -76,7 +76,9 @@ class SupabaseChatController { .range(pageSize * _currentPage, (_currentPage * pageSize) + pageSize); void _onData( - List> newData, List> oldData,) { + List> newData, + List> oldData, + ) { final deletedMessagesId = oldData .map( (e) => e['id'].toString(), From e940a21a18457e9438c30d7211f90fbf508eb42a Mon Sep 17 00:00:00 2001 From: riccardocucia Date: Tue, 17 Jun 2025 16:22:54 +0200 Subject: [PATCH 4/9] ### Fixed * Fixed #29 update messages list after delete message ### Dependencies * Upgraded `supabase_flutter` to `^2.9.1` * Upgraded `meta` to `^1.16.0` --- example/lib/src/pages/room.dart | 23 +++++++++++++++++++ lib/src/class/supabase_chat_controller.dart | 25 ++++++++++++--------- lib/src/class/supabase_chat_core.dart | 8 ++++--- 3 files changed, 42 insertions(+), 14 deletions(-) diff --git a/example/lib/src/pages/room.dart b/example/lib/src/pages/room.dart index 0918b89..35454c4 100644 --- a/example/lib/src/pages/room.dart +++ b/example/lib/src/pages/room.dart @@ -223,6 +223,29 @@ class _RoomPageState extends State { enabled: true, onTextChanged: (text) => _chatController.onTyping(), ), + onMessageLongPress: (context, p1) async { + final confirm = await showDialog( + context: context, + builder: (context) => AlertDialog( + title: Text('Confirmation of deletion'), + content: Text('Do you really want to delete this message?'), + actions: [ + TextButton( + onPressed: () => Navigator.of(context).pop(false), + child: Text('Cancel'), + ), + TextButton( + onPressed: () => Navigator.of(context).pop(true), + child: Text('Delete'), + ), + ], + ), + ); + if (confirm == true) { + await _chatController.deleteMessage(widget.room.id, p1.id); + } + }, + ), ), ), diff --git a/lib/src/class/supabase_chat_controller.dart b/lib/src/class/supabase_chat_controller.dart index 1585902..f182b3d 100644 --- a/lib/src/class/supabase_chat_controller.dart +++ b/lib/src/class/supabase_chat_controller.dart @@ -77,14 +77,7 @@ class SupabaseChatController { void _onData( List> newData, - List> oldData, ) { - final deletedMessagesId = oldData - .map( - (e) => e['id'].toString(), - ) - .toList(); - _messages.removeWhere((element) => deletedMessagesId.contains(element.id)); for (var val in newData) { final author = _room.users.firstWhere( (u) => u.id == val['authorId'], @@ -112,7 +105,7 @@ class SupabaseChatController { /// then it will be necessary to call the [loadPreviousMessages] method to get /// the next page of messages Stream> get messages { - _messagesQuery().then((value) => _onData(value, [])); + _messagesQuery().then((value) => _onData(value)); _client .channel('${_config.schema}:${_config.messagesTableName}:${_room.id}') .onPostgresChanges( @@ -124,8 +117,7 @@ class SupabaseChatController { column: 'roomId', value: _room.id, ), - callback: (payload) => - _onData([payload.newRecord], [payload.oldRecord]), + callback: (payload) => _onData([payload.newRecord]), ) .subscribe(); return _messagesController.stream; @@ -135,7 +127,7 @@ class SupabaseChatController { /// page Future loadPreviousMessages() async { _currentPage += 1; - await _messagesQuery().then((value) => _onData(value, [])); + await _messagesQuery().then((value) => _onData(value)); } /// Returns a stream of typing users from Supabase for a specified room. @@ -168,6 +160,17 @@ class SupabaseChatController { 'typing': typing, }; + /// Removes message. + Future deleteMessage(String roomId, String messageId) async { + final result = + await SupabaseChatCore.instance.deleteMessage(roomId, messageId); + if (result) { + _messages.removeWhere((e) => messageId == e.id); + _messagesController.sink.add(_messages); + } + return result; + } + void dispose() { _typingChannel.untrack(); } diff --git a/lib/src/class/supabase_chat_core.dart b/lib/src/class/supabase_chat_core.dart index 4957eff..eea714c 100644 --- a/lib/src/class/supabase_chat_core.dart +++ b/lib/src/class/supabase_chat_core.dart @@ -282,13 +282,15 @@ class SupabaseChatCore { } /// Removes message. - Future deleteMessage(String roomId, String messageId) async { - await client + Future deleteMessage(String roomId, String messageId) async { + final result = await client .schema(config.schema) .from(config.messagesTableName) .delete() .eq('roomId', roomId) - .eq('id', messageId); + .eq('id', messageId) + .select(); + return result.isNotEmpty; } /// Removes room. From 216988366786c71fa89586c1116a257f1e0d7aee Mon Sep 17 00:00:00 2001 From: riccardocucia Date: Tue, 17 Jun 2025 16:44:37 +0200 Subject: [PATCH 5/9] ### Fixed * Fixed #29 update messages list after delete message ### Dependencies * Upgraded `supabase_flutter` to `^2.9.1` * Upgraded `meta` to `^1.16.0` --- example/utils/sql/02_database_trigger.sql | 70 +++++++++++------------ 1 file changed, 33 insertions(+), 37 deletions(-) diff --git a/example/utils/sql/02_database_trigger.sql b/example/utils/sql/02_database_trigger.sql index 720a357..ba261b8 100644 --- a/example/utils/sql/02_database_trigger.sql +++ b/example/utils/sql/02_database_trigger.sql @@ -30,50 +30,46 @@ AS $$ DECLARE latest_message jsonb; ts_in_milliseconds bigint; + affected_room_id bigint; BEGIN - SELECT jsonb_build_object( - 'id', id, - 'createdAt', "createdAt", - 'metadata', metadata, - 'duration', duration, - 'mimeType', "mimeType", - 'name', name, - 'remoteId', "remoteId", - 'repliedMessage', "repliedMessage", - 'roomId', "roomId", - 'showStatus', "showStatus", - 'size', size, - 'status', status, - 'type', type, - 'updatedAt', "updatedAt", - 'uri', uri, - 'waveForm', "waveForm", - 'isLoading', "isLoading", - 'height', height, - 'width', width, - 'previewData', "previewData", - 'authorId', "authorId", - 'text', text - ) - INTO latest_message - FROM chats.messages - WHERE "roomId" = NEW."roomId" - ORDER BY "createdAt" DESC - LIMIT 1; - IF latest_message IS DISTINCT FROM (SELECT "lastMessages" FROM chats.rooms WHERE id = NEW."roomId") THEN - SELECT EXTRACT(epoch FROM NOW()) * 1000 INTO ts_in_milliseconds; - UPDATE chats.rooms - SET "updatedAt" = ts_in_milliseconds, - "lastMessages" = jsonb_build_array(latest_message) - WHERE id = NEW."roomId"; - END IF; + IF TG_OP = 'DELETE' THEN + affected_room_id := OLD."roomId"; + ELSE + affected_room_id := NEW."roomId"; + END IF; + + SELECT to_jsonb(m) + INTO latest_message + FROM chats.messages m + WHERE m."roomId" = affected_room_id + ORDER BY m."createdAt" DESC + LIMIT 1; + + IF latest_message IS DISTINCT FROM ( + SELECT value FROM jsonb_array_elements( + (SELECT "lastMessages" FROM chats.rooms WHERE id = affected_room_id) + ) LIMIT 1 + ) THEN + SELECT EXTRACT(epoch FROM NOW()) * 1000 INTO ts_in_milliseconds; + + UPDATE chats.rooms + SET "updatedAt" = ts_in_milliseconds, + "lastMessages" = jsonb_build_array(latest_message) + WHERE id = affected_room_id; + END IF; + + IF TG_OP = 'DELETE' THEN + RETURN OLD; + ELSE RETURN NEW; + END IF; END; $$ LANGUAGE plpgsql; + drop trigger if exists update_last_messages_trigger on chats.messages; CREATE TRIGGER update_last_messages_trigger - AFTER INSERT OR UPDATE ON chats.messages + AFTER INSERT OR UPDATE OR DELETE ON chats.messages FOR EACH ROW EXECUTE FUNCTION chats.update_last_messages(); From 3b34b8f4da1256518ff16adef3bd5ce089ccf8a3 Mon Sep 17 00:00:00 2001 From: riccardocucia Date: Tue, 17 Jun 2025 16:45:18 +0200 Subject: [PATCH 6/9] ### Fixed * Fixed #29 update messages list after delete message ### Dependencies * Upgraded `supabase_flutter` to `^2.9.1` * Upgraded `meta` to `^1.16.0` --- CHANGELOG.md | 4 +++- pubspec.yaml | 2 +- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 8f43bdd..fdef734 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,8 @@ -## [1.5.1] - 2025-06-17 +## [1.6.0] - 2025-06-17 #### [@rickypid](https://github.com/rickypid) +ℹ️ ℹ️ **Recommended scheme migration** ℹ️ ℹ️ + ### Fixed * Fixed #29 update messages list after delete message diff --git a/pubspec.yaml b/pubspec.yaml index f4cc8d5..7e85840 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -2,7 +2,7 @@ name: flutter_supabase_chat_core description: > Actively maintained, community-driven Supabase BaaS for chat applications with an optional chat UI. -version: 1.5.1 +version: 1.6.0 homepage: https://flutter-supabase-chat-core.insideapp.it repository: https://github.com/insideapp-srl/flutter_supabase_chat_core From abd0dd938a177fa5ef9c11bd6603b61c9c414851 Mon Sep 17 00:00:00 2001 From: riccardocucia Date: Tue, 17 Jun 2025 16:48:00 +0200 Subject: [PATCH 7/9] ### Fixed * Fixed #29 update messages list after delete message ### Dependencies * Upgraded `supabase_flutter` to `^2.9.1` * Upgraded `meta` to `^1.16.0` --- example/lib/src/pages/room.dart | 1 - 1 file changed, 1 deletion(-) diff --git a/example/lib/src/pages/room.dart b/example/lib/src/pages/room.dart index 35454c4..4d713c4 100644 --- a/example/lib/src/pages/room.dart +++ b/example/lib/src/pages/room.dart @@ -245,7 +245,6 @@ class _RoomPageState extends State { await _chatController.deleteMessage(widget.room.id, p1.id); } }, - ), ), ), From 98802b15de0cd871b0cdd8e4ff14fd7aba664e01 Mon Sep 17 00:00:00 2001 From: riccardocucia Date: Tue, 17 Jun 2025 16:48:57 +0200 Subject: [PATCH 8/9] ### Fixed * Fixed #29 update messages list after delete message ### Dependencies * Upgraded `supabase_flutter` to `^2.9.1` * Upgraded `meta` to `^1.16.0` --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index fdef734..ef7a8b4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,7 @@ ### Fixed * Fixed #29 update messages list after delete message +* Fixed update room last message trigger ### Dependencies From 81461aeba29a2f6c9114d94a45e9922f074181e9 Mon Sep 17 00:00:00 2001 From: riccardocucia Date: Wed, 18 Jun 2025 11:54:19 +0200 Subject: [PATCH 9/9] ### Fixed * Fixed #29 update messages list after delete message ### Dependencies * Upgraded `supabase_flutter` to `^2.9.1` * Upgraded `meta` to `^1.16.0` --- doc/docs/guides/supabse-trigges.md | 41 +++++++++++++++++++++++++----- 1 file changed, 34 insertions(+), 7 deletions(-) diff --git a/doc/docs/guides/supabse-trigges.md b/doc/docs/guides/supabse-trigges.md index 6b2af28..b15b33a 100644 --- a/doc/docs/guides/supabse-trigges.md +++ b/doc/docs/guides/supabse-trigges.md @@ -13,20 +13,47 @@ CREATE OR REPLACE FUNCTION chats.update_last_messages() SET search_path = '' AS $$ DECLARE + latest_message jsonb; ts_in_milliseconds bigint; + affected_room_id bigint; BEGIN - SELECT EXTRACT(epoch FROM NOW()) * 1000 INTO ts_in_milliseconds; - UPDATE chats.rooms - SET "updatedAt" = ts_in_milliseconds, - "lastMessages" = jsonb_build_array(NEW) - WHERE id = NEW."roomId"; - RETURN NEW; + IF TG_OP = 'DELETE' THEN + affected_room_id := OLD."roomId"; + ELSE + affected_room_id := NEW."roomId"; + END IF; + + SELECT to_jsonb(m) + INTO latest_message + FROM chats.messages m + WHERE m."roomId" = affected_room_id + ORDER BY m."createdAt" DESC + LIMIT 1; + + IF latest_message IS DISTINCT FROM ( + SELECT value FROM jsonb_array_elements( + (SELECT "lastMessages" FROM chats.rooms WHERE id = affected_room_id) + ) LIMIT 1 + ) THEN + SELECT EXTRACT(epoch FROM NOW()) * 1000 INTO ts_in_milliseconds; + + UPDATE chats.rooms + SET "updatedAt" = ts_in_milliseconds, + "lastMessages" = jsonb_build_array(latest_message) + WHERE id = affected_room_id; + END IF; + + IF TG_OP = 'DELETE' THEN + RETURN OLD; + ELSE + RETURN NEW; + END IF; END; $$ LANGUAGE plpgsql; drop trigger if exists update_last_messages_trigger on chats.messages; CREATE TRIGGER update_last_messages_trigger - AFTER INSERT OR UPDATE ON chats.messages + AFTER INSERT OR UPDATE OR DELETE ON chats.messages FOR EACH ROW EXECUTE FUNCTION chats.update_last_messages(); ```