relatica/lib/services/timeline_manager.dart

120 lines
3.8 KiB
Dart
Raw Normal View History

2022-11-17 16:04:14 +00:00
import 'package:flutter/material.dart';
import 'package:logging/logging.dart';
import 'package:result_monad/result_monad.dart';
import '../globals.dart';
import '../models/TimelineIdentifiers.dart';
import '../models/entry_tree_item.dart';
import '../models/exec_error.dart';
import '../models/timeline.dart';
import 'entry_manager_service.dart';
enum TimelineRefreshType {
refresh,
loadOlder,
loadNewer,
}
2022-11-17 16:04:14 +00:00
class TimelineManager extends ChangeNotifier {
static final _logger = Logger('$TimelineManager');
final cachedTimelines = <TimelineIdentifiers, Timeline>{};
void clear() {
cachedTimelines.clear();
getIt<EntryManagerService>().clear();
notifyListeners();
}
2022-11-17 16:04:14 +00:00
// refresh timeline gets statuses newer than the newest in that timeline
Result<List<EntryTreeItem>, ExecError> getTimeline(TimelineIdentifiers type) {
_logger.finest('Getting timeline $type');
2022-11-17 16:04:14 +00:00
final posts = cachedTimelines[type]?.posts;
if (posts != null) {
return Result.ok(posts);
}
updateTimeline(type, TimelineRefreshType.refresh);
2022-11-17 16:04:14 +00:00
return Result.ok([]);
}
FutureResult<EntryTreeItem, ExecError> refreshPost(String id) async {
_logger.finest('Refreshing post $id');
final result = await getIt<EntryManagerService>().refreshPost(id);
if (result.isSuccess) {
for (final t in cachedTimelines.values) {
t.addOrUpdate([result.value]);
}
notifyListeners();
}
return result;
}
Future<void> updateTimeline(
TimelineIdentifiers type,
TimelineRefreshType refreshType,
) async {
_logger.finest('Updating w/$refreshType for timeline $type ');
final timeline = cachedTimelines.putIfAbsent(type, () => Timeline(type));
late final int lowestId;
late final int highestId;
switch (refreshType) {
case TimelineRefreshType.refresh:
lowestId = timeline.highestStatusId;
highestId = 0;
break;
case TimelineRefreshType.loadOlder:
lowestId = timeline.lowestStatusId;
highestId = 0;
break;
case TimelineRefreshType.loadNewer:
lowestId = 0;
highestId = timeline.highestStatusId;
break;
}
(await getIt<EntryManagerService>()
.updateTimeline(type, lowestId, highestId))
.match(onSuccess: (posts) {
_logger.finest('Posts returned for adding to $type: ${posts.length}');
timeline.addOrUpdate(posts);
2022-11-17 16:04:14 +00:00
notifyListeners();
}, onError: (error) {
_logger.severe('Error getting timeline: $type}');
});
}
FutureResult<EntryTreeItem, ExecError> toggleFavorited(
String id, bool newStatus) async {
_logger.finest('Attempting toggling favorite $id to $newStatus');
final result =
await getIt<EntryManagerService>().toggleFavorited(id, newStatus);
if (result.isFailure) {
_logger.finest('Error toggling favorite $id: ${result.error}');
return result;
}
final update = result.value;
for (final timeline in cachedTimelines.values) {
update.entry.parentId.isEmpty
? timeline.addOrUpdate([update])
: timeline.tryUpdateComment(update);
}
2022-11-17 16:04:14 +00:00
notifyListeners();
return result;
2022-11-17 16:04:14 +00:00
}
// All statuses get dumped into the entity mangager and get full assembled posts out of it
// Timeline keeps track of posts level only so can query timeline manager for those
// Should put backing store on timelines and entity manager so can recover from restart faster
// Have a purge caches button to start that over from scratch
// Should have a contacts manager with backing store as well
// Timeline view is new control that knows how to load timeline, scrolling around with refresh and get more
// Timeline Item view displays itself and children
// Has "Add Comment" value
// Has like/dislke
// Has reshare/quote reshare (if can get that working somehow)
// If our own has delete
2022-11-17 16:04:14 +00:00
}