improved realtime update code

This commit is contained in:
Myzel394 2022-08-16 10:49:38 +02:00
parent 0519c5caab
commit e884527d85
2 changed files with 111 additions and 85 deletions

View File

@ -6,4 +6,25 @@ class MemoryPack {
const MemoryPack(this._memories); const MemoryPack(this._memories);
List<Memory> get memories => _memories; List<Memory> get memories => _memories;
void orderMemories() {
_memories.sort((a, b) => b.creationDate.compareTo(a.creationDate));
}
void updateWithNewMemory(final String memoryID, final Memory memory) {
final index = _memories.indexWhere((memory) => memory.id == memoryID);
if (index == -1) {
throw Exception('Memory not found');
}
_memories[index] = memory;
orderMemories();
}
void addMemory(final Memory memory) {
_memories.add(memory);
orderMemories();
}
} }

View File

@ -15,7 +15,7 @@ class TimelineModel extends PropertyChangeNotifier<String> {
Map<String, MemoryPack>? timeline, Map<String, MemoryPack>? timeline,
}) : _timeline = timeline ?? {}; }) : _timeline = timeline ?? {};
late RealtimeSubscription _serverSubscription; RealtimeSubscription? _serverSubscription;
int _currentIndex = 0; int _currentIndex = 0;
int _memoryIndex = 0; int _memoryIndex = 0;
@ -29,17 +29,36 @@ class TimelineModel extends PropertyChangeNotifier<String> {
bool get paused => _paused; bool get paused => _paused;
bool get isInitializing => _isInitializing; bool get isInitializing => _isInitializing;
DateTime dateAtIndex(final int index) =>
DateTime.parse(_timeline.keys.elementAt(index));
MemoryPack atIndex(final int index) => _timeline.values.elementAt(index);
MemoryPack get _currentMemoryPack => atIndex(currentIndex);
bool get _isAtLastMemory =>
_memoryIndex == _currentMemoryPack.memories.length - 1;
Memory get currentMemory =>
_currentMemoryPack.memories.elementAt(_memoryIndex);
void _removeEmptyDates() {
_timeline.removeWhere((key, value) => value.memories.isEmpty);
}
static formatCreationDateKey(final DateTime date) =>
DateFormat('yyyy-MM-dd').format(date);
static Map<String, MemoryPack> mapFromMemoriesList( static Map<String, MemoryPack> mapFromMemoriesList(
final List<Memory> memories, final List<Memory> memories,
) { ) {
final map = <String, List<Memory>>{}; final map = <String, List<Memory>>{};
for (final memory in memories) { for (final memory in memories) {
final date = DateFormat('yyyy-MM-dd').format(memory.creationDate); final key = formatCreationDateKey(memory.creationDate);
if (map.containsKey(date)) {
map[date]!.add(memory); if (map.containsKey(key)) {
map[key]!.add(memory);
} else { } else {
map[date] = [memory]; map[key] = [memory];
} }
} }
@ -55,25 +74,10 @@ class TimelineModel extends PropertyChangeNotifier<String> {
@override @override
void dispose() { void dispose() {
_serverSubscription.unsubscribe(timeout: Duration.zero); _serverSubscription?.unsubscribe(timeout: Duration.zero);
super.dispose(); super.dispose();
} }
DateTime dateAtIndex(final int index) =>
DateTime.parse(_timeline.keys.elementAt(index));
MemoryPack atIndex(final int index) => _timeline.values.elementAt(index);
MemoryPack get _currentMemoryPack => atIndex(currentIndex);
bool get _isAtLastMemory =>
_memoryIndex == _currentMemoryPack.memories.length - 1;
Memory get currentMemory =>
_currentMemoryPack.memories.elementAt(_memoryIndex);
void _removeEmptyDates() {
_timeline.removeWhere((key, value) => value.memories.isEmpty);
}
void setCurrentIndex(final int index) { void setCurrentIndex(final int index) {
_currentIndex = min(_timeline.length - 1, max(0, index)); _currentIndex = min(_timeline.length - 1, max(0, index));
notifyListeners('currentIndex'); notifyListeners('currentIndex');
@ -97,17 +101,6 @@ class TimelineModel extends PropertyChangeNotifier<String> {
notifyListeners('isInitializing'); notifyListeners('isInitializing');
} }
void removeMemory(
final int timelineIndex,
final int memoryIndex,
) {
_timeline.values.elementAt(timelineIndex).memories.removeAt(memoryIndex);
_removeEmptyDates();
notifyListeners();
}
void removeCurrentMemory() => removeMemory(_currentIndex, _memoryIndex);
void pause() => setPaused(true); void pause() => setPaused(true);
void resume() => setPaused(false); void resume() => setPaused(false);
@ -153,61 +146,41 @@ class TimelineModel extends PropertyChangeNotifier<String> {
} }
void _insertMemory(final Memory memory) { void _insertMemory(final Memory memory) {
final date = DateFormat('yyyy-MM-dd').format(memory.creationDate); final key = formatCreationDateKey(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) { if (!_timeline.containsKey(key)) {
final date = DateFormat('yyyy-MM-dd').format(memory.creationDate); _timeline[key] = MemoryPack([memory]);
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<void> _onMemoriesUpdate(
final SupabaseRealtimePayload response,
) async {
if (response == null) {
return; return;
} }
switch (response.eventType) { final memoryPack = _timeline[key]!;
case 'INSERT':
final memory = Memory.parse(response.newRecord!); memoryPack.addMemory(memory);
_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<void> _listenToServer() async { void _updateMemory(final String id, final Memory memory) {
final key = formatCreationDateKey(memory.creationDate);
if (!_timeline.containsKey(key)) {
_timeline[key] = MemoryPack([memory]);
return;
}
final memoryPack = _timeline[key]!;
memoryPack.updateWithNewMemory(id, memory);
}
void _deleteMemory(final String id) {
// Search for correct `Memory` and remove it
for (final memories in _timeline.values) {
memories.memories.removeWhere((memory) => memory.id == id);
}
_removeEmptyDates();
}
Future<void> _fetchInitialData() async {
final response = await supabase final response = await supabase
.from('memories') .from('memories')
.select() .select()
@ -220,12 +193,44 @@ class TimelineModel extends PropertyChangeNotifier<String> {
values values
..clear() ..clear()
..addAll(mapFromMemoriesList(memories)); ..addAll(mapFromMemoriesList(memories));
}
_serverSubscription = supabase Future<void> _onServerUpdate(
.from('memories') final SupabaseRealtimePayload response,
.on(SupabaseEventTypes.all, _onMemoriesUpdate) ) async {
.subscribe(); if (response == null) {
return;
}
switch (response.eventType) {
case 'INSERT':
final memory = Memory.parse(response.newRecord!);
_insertMemory(memory);
break;
case 'UPDATE':
final memoryID = response.oldRecord!['id'];
final memory = Memory.parse(response.newRecord!);
_updateMemory(memoryID, memory);
break;
case 'DELETE':
final id = response.oldRecord!['id'];
_deleteMemory(id);
break;
}
notifyListeners(); notifyListeners();
} }
Future<void> _listenToServer() async {
await _fetchInitialData();
notifyListeners();
// Watch new updates
_serverSubscription = supabase
.from('memories')
.on(SupabaseEventTypes.all, _onServerUpdate)
.subscribe();
}
} }