mirror of
https://gitlab.com/mysocialportal/relatica
synced 2024-10-19 14:03:31 +00:00
233 lines
7.1 KiB
Dart
233 lines
7.1 KiB
Dart
import 'package:flutter/material.dart' hide Visibility;
|
|
import 'package:logging/logging.dart';
|
|
import 'package:result_monad/result_monad.dart';
|
|
|
|
import '../data/interfaces/groups_repo.intf.dart';
|
|
import '../friendica_client/friendica_client.dart';
|
|
import '../globals.dart';
|
|
import '../models/TimelineIdentifiers.dart';
|
|
import '../models/entry_tree_item.dart';
|
|
import '../models/exec_error.dart';
|
|
import '../models/group_data.dart';
|
|
import '../models/image_entry.dart';
|
|
import '../models/media_attachment_uploads/new_entry_media_items.dart';
|
|
import '../models/timeline.dart';
|
|
import '../models/timeline_entry.dart';
|
|
import '../models/visibility.dart';
|
|
import 'auth_service.dart';
|
|
import 'entry_manager_service.dart';
|
|
|
|
enum TimelineRefreshType {
|
|
refresh,
|
|
loadOlder,
|
|
loadNewer,
|
|
}
|
|
|
|
class TimelineManager extends ChangeNotifier {
|
|
static final _logger = Logger('$TimelineManager');
|
|
|
|
final IGroupsRepo groupsRepo;
|
|
final EntryManagerService entryManagerService;
|
|
|
|
final cachedTimelines = <TimelineIdentifiers, Timeline>{};
|
|
|
|
TimelineManager(this.groupsRepo, this.entryManagerService);
|
|
|
|
void clear() {
|
|
cachedTimelines.clear();
|
|
entryManagerService.clear();
|
|
groupsRepo.clearMyGroups();
|
|
notifyListeners();
|
|
}
|
|
|
|
Result<List<GroupData>, ExecError> getGroups() {
|
|
if (groupsRepo.getMyGroups().isEmpty) {
|
|
_refreshGroupData();
|
|
return Result.ok([]);
|
|
}
|
|
|
|
return Result.ok(groupsRepo.getMyGroups());
|
|
}
|
|
|
|
Future<void> _refreshGroupData() async {
|
|
_logger.finest('Refreshing member group data ');
|
|
await GroupsClient(getIt<AccountsService>().currentProfile)
|
|
.getGroups()
|
|
.match(
|
|
onSuccess: (groups) {
|
|
groupsRepo.addAllGroups(groups);
|
|
notifyListeners();
|
|
},
|
|
onError: (error) {
|
|
_logger.severe('Error getting list data: $error');
|
|
},
|
|
);
|
|
}
|
|
|
|
FutureResult<bool, ExecError> createNewStatus(
|
|
String text, {
|
|
String spoilerText = '',
|
|
String inReplyToId = '',
|
|
required NewEntryMediaItems newMediaItems,
|
|
required List<ImageEntry> existingMediaItems,
|
|
required Visibility visibility,
|
|
}) async {
|
|
final result = await entryManagerService.createNewStatus(
|
|
text,
|
|
spoilerText: spoilerText,
|
|
inReplyToId: inReplyToId,
|
|
mediaItems: newMediaItems,
|
|
existingMediaItems: existingMediaItems,
|
|
visibility: visibility,
|
|
);
|
|
if (result.isSuccess) {
|
|
_logger.finest('Notifying listeners of new status created');
|
|
notifyListeners();
|
|
}
|
|
return result;
|
|
}
|
|
|
|
FutureResult<bool, ExecError> editStatus(
|
|
String id,
|
|
String text, {
|
|
String spoilerText = '',
|
|
String inReplyToId = '',
|
|
required NewEntryMediaItems newMediaItems,
|
|
required List<ImageEntry> existingMediaItems,
|
|
required Visibility newMediaItemVisibility,
|
|
}) async {
|
|
final result = await entryManagerService.editStatus(id, text,
|
|
spoilerText: spoilerText,
|
|
mediaItems: newMediaItems,
|
|
existingMediaItems: existingMediaItems,
|
|
newMediaItemVisibility: newMediaItemVisibility);
|
|
if (result.isSuccess) {
|
|
_logger.finest('Notifying listeners of updated status');
|
|
notifyListeners();
|
|
}
|
|
return result;
|
|
}
|
|
|
|
Result<TimelineEntry, ExecError> getEntryById(String id) {
|
|
_logger.finest('Getting entry for $id');
|
|
return entryManagerService.getEntryById(id);
|
|
}
|
|
|
|
FutureResult<bool, ExecError> deleteEntryById(String id) async {
|
|
_logger.finest('Delete entry for $id');
|
|
final result = await entryManagerService.deleteEntryById(id);
|
|
|
|
if (result.isSuccess) {
|
|
for (final t in cachedTimelines.values) {
|
|
t.removeTimelineEntry(id);
|
|
}
|
|
}
|
|
notifyListeners();
|
|
return result;
|
|
}
|
|
|
|
Result<EntryTreeItem, ExecError> getPostTreeEntryBy(String id) {
|
|
_logger.finest('Getting post for $id');
|
|
return entryManagerService.getPostTreeEntryBy(id);
|
|
}
|
|
|
|
// refresh timeline gets statuses newer than the newest in that timeline
|
|
List<EntryTreeItem> getTimeline(TimelineIdentifiers type) {
|
|
_logger.finest('Getting timeline $type');
|
|
return cachedTimelines.putIfAbsent(type, () => Timeline(type)).posts;
|
|
}
|
|
|
|
///
|
|
/// 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 entryManagerService.refreshStatusChain(id);
|
|
if (result.isSuccess) {
|
|
for (final t in cachedTimelines.values) {
|
|
t.addOrUpdate([result.value]);
|
|
}
|
|
notifyListeners();
|
|
}
|
|
return result;
|
|
}
|
|
|
|
FutureResult<EntryTreeItem, ExecError> resharePost(String id) async {
|
|
final result = await entryManagerService.resharePost(id);
|
|
if (result.isSuccess) {
|
|
for (final t in cachedTimelines.values) {
|
|
t.addOrUpdate([result.value]);
|
|
}
|
|
notifyListeners();
|
|
}
|
|
return result;
|
|
}
|
|
|
|
FutureResult<bool, ExecError> unResharePost(String id) async {
|
|
final result = await entryManagerService.unResharePost(id);
|
|
if (result.isSuccess) {
|
|
for (final t in cachedTimelines.values) {
|
|
t.removeTimelineEntry(id);
|
|
}
|
|
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 == 0
|
|
? timeline.highestStatusId
|
|
: 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 entryManagerService.updateTimeline(type, lowestId, highestId)).match(
|
|
onSuccess: (posts) {
|
|
_logger.finest('Posts returned for adding to $type: ${posts.length}');
|
|
timeline.addOrUpdate(posts);
|
|
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 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);
|
|
}
|
|
|
|
notifyListeners();
|
|
return result;
|
|
}
|
|
// 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
|
|
// If our own has delete
|
|
}
|