diff --git a/lib/models/timeline.dart b/lib/models/timeline.dart index d9a0d25..3077408 100644 --- a/lib/models/timeline.dart +++ b/lib/models/timeline.dart @@ -15,6 +15,8 @@ class TimelineModel extends PropertyChangeNotifier { Map? timeline, }) : _timeline = timeline ?? {}; + late RealtimeSubscription _serverSubscription; + int _currentIndex = 0; int _memoryIndex = 0; bool _paused = false; @@ -51,6 +53,12 @@ class TimelineModel extends PropertyChangeNotifier { ); } + @override + void dispose() { + _serverSubscription.unsubscribe(timeout: Duration.zero); + super.dispose(); + } + DateTime dateAtIndex(final int index) => DateTime.parse(_timeline.keys.elementAt(index)); @@ -139,12 +147,67 @@ class TimelineModel extends PropertyChangeNotifier { Future initialize() async { setIsInitializing(true); - await refreshFromServer(); + await _listenToServer(); setIsInitializing(false); } - Future refreshFromServer() async { + void _insertMemory(final Memory memory) { + final date = DateFormat('yyyy-MM-dd').format(memory.creationDate); + if (_timeline.containsKey(date)) { + _timeline[date]!.memories.add(memory); + // Sort descending based on creation date + _timeline[date]!.memories.sort( + (a, b) => b.creationDate.compareTo(a.creationDate), + ); + } else { + _timeline[date] = MemoryPack([memory]); + } + } + + void _updateMemory(final String id, final Memory memory) { + final date = DateFormat('yyyy-MM-dd').format(memory.creationDate); + if (_timeline.containsKey(date)) { + _timeline[date]!.memories.removeWhere((m) => m.id == id); + _timeline[date]!.memories.add(memory); + // Sort descending based on creation date + _timeline[date]!.memories.sort( + (a, b) => b.creationDate.compareTo(a.creationDate), + ); + } else { + _timeline[date] = MemoryPack([memory]); + } + } + + void _deleteMemory(final String id) { + for (final date in _timeline.keys) { + _timeline[date]!.memories.removeWhere((m) => m.id == id); + } + } + + Future _onMemoriesUpdate( + final SupabaseRealtimePayload response, + ) async { + if (response == null) { + return; + } + + switch (response.eventType) { + case 'INSERT': + final memory = Memory.parse(response.newRecord!); + _insertMemory(memory); + break; + case 'UPDATE': + final memory = Memory.parse(response.newRecord!); + _updateMemory(response.oldRecord!['id'], memory); + break; + case 'DELETE': + _deleteMemory(response.oldRecord!['id']); + break; + } + } + + Future _listenToServer() async { final response = await supabase .from('memories') .select() @@ -158,6 +221,11 @@ class TimelineModel extends PropertyChangeNotifier { ..clear() ..addAll(mapFromMemoriesList(memories)); + _serverSubscription = supabase + .from('memories') + .on(SupabaseEventTypes.all, _onMemoriesUpdate) + .subscribe(); + notifyListeners(); } } diff --git a/lib/widgets/memory_sheet.dart b/lib/widgets/memory_sheet.dart index 48ad7c6..6aeadb7 100644 --- a/lib/widgets/memory_sheet.dart +++ b/lib/widgets/memory_sheet.dart @@ -12,15 +12,11 @@ import 'package:supabase_flutter/supabase_flutter.dart'; class MemorySheet extends StatefulWidget { final Memory memory; final BuildContext sheetContext; - final VoidCallback onDelete; - final VoidCallback onVisibilityChanged; const MemorySheet({ Key? key, required this.memory, required this.sheetContext, - required this.onDelete, - required this.onVisibilityChanged, }) : super(key: key); @override @@ -36,8 +32,6 @@ class _MemorySheetState extends State with Loadable { if (mounted) { Navigator.pop(context); } - - widget.onDelete(); } Future downloadFile() async { @@ -83,8 +77,6 @@ class _MemorySheetState extends State with Loadable { } else { context.showSuccessSnackBar(message: 'Your Memory is private now.'); } - - widget.onVisibilityChanged(); } catch (error) { context.showErrorSnackBar(message: 'There was an error.'); } diff --git a/lib/widgets/timeline_page.dart b/lib/widgets/timeline_page.dart index 110db90..fb425c3 100644 --- a/lib/widgets/timeline_page.dart +++ b/lib/widgets/timeline_page.dart @@ -121,12 +121,6 @@ class _TimelinePageState extends State { builder: (sheetContext) => MemorySheet( memory: timeline.currentMemory, sheetContext: sheetContext, - onDelete: () async { - timeline.removeCurrentMemory(); - }, - onVisibilityChanged: () async { - timeline.refreshFromServer(); - }, ), );