relatica/lib/services/timeline_manager.dart

169 lines
5.3 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 '../models/timeline_entry.dart';
2022-11-17 16:04:14 +00:00
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();
}
FutureResult<bool, ExecError> createNewStatus(String text,
{String spoilerText = '', String inReplyToId = ''}) async {
final result = await getIt<EntryManagerService>().createNewStatus(
text,
spoilerText: spoilerText,
inReplyToId: inReplyToId,
);
if (result.isSuccess) {
_logger.finest('Notifying listeners of new status created');
notifyListeners();
}
return result;
}
Result<TimelineEntry, ExecError> getEntryById(String id) {
_logger.finest('Getting entry for $id');
return getIt<EntryManagerService>().getEntryById(id);
}
Result<EntryTreeItem, ExecError> getPostTreeEntryBy(String id) {
_logger.finest('Getting post for $id');
return getIt<EntryManagerService>().getPostTreeEntryBy(id);
}
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([]);
}
///
/// id is the id of a post or comment in the chain, including the original post.
FutureResult<EntryTreeItem, ExecError> refreshStatusChain(String id) async {
_logger.finest('Refreshing post $id');
final result = await getIt<EntryManagerService>().refreshStatusChain(id);
if (result.isSuccess) {
for (final t in cachedTimelines.values) {
t.addOrUpdate([result.value]);
}
notifyListeners();
}
return result;
}
2022-11-22 16:43:16 +00:00
FutureResult<EntryTreeItem, ExecError> resharePost(String id) async {
final result = await getIt<EntryManagerService>().resharePost(id);
if (result.isSuccess) {
for (final t in cachedTimelines.values) {
t.addOrUpdate([result.value]);
}
notifyListeners();
}
return result;
}
FutureResult<EntryTreeItem, ExecError> unResharePost(String id) async {
final result = await getIt<EntryManagerService>().unResharePost(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 + 1;
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
}