import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:supabase_flutter/supabase_flutter.dart'; import '../models/chat_message.dart'; import 'supabase_provider.dart'; import 'stream_recovery.dart'; import 'realtime_controller.dart'; /// Real-time chat messages for a swap request thread. final chatMessagesProvider = StreamProvider.family, String>(( ref, threadId, ) { final client = ref.watch(supabaseClientProvider); final wrapper = StreamRecoveryWrapper( stream: client .from('chat_messages') .stream(primaryKey: ['id']) .eq('thread_id', threadId) .order('created_at'), onPollData: () async { final data = await client .from('chat_messages') .select() .eq('thread_id', threadId) .order('created_at'); return data.map(ChatMessage.fromMap).toList(); }, fromMap: ChatMessage.fromMap, channelName: 'chat_messages_$threadId', onStatusChanged: ref.read(realtimeControllerProvider).handleChannelStatus, ); ref.onDispose(wrapper.dispose); return wrapper.stream.map((result) => result.data); }); final chatControllerProvider = Provider((ref) { final client = ref.watch(supabaseClientProvider); return ChatController(client); }); class ChatController { ChatController(this._client); final SupabaseClient _client; Future sendMessage({ required String threadId, required String body, }) async { final userId = _client.auth.currentUser?.id; if (userId == null) throw Exception('Not authenticated'); await _client.from('chat_messages').insert({ 'thread_id': threadId, 'sender_id': userId, 'body': body, }); } }