kopia lustrzana https://gitlab.com/mysocialportal/relatica
				
				
				
			
		
			
				
	
	
		
			198 wiersze
		
	
	
		
			6.1 KiB
		
	
	
	
		
			Dart
		
	
	
			
		
		
	
	
			198 wiersze
		
	
	
		
			6.1 KiB
		
	
	
	
		
			Dart
		
	
	
| import 'package:flutter/material.dart';
 | |
| import 'package:logging/logging.dart';
 | |
| import 'package:result_monad/result_monad.dart';
 | |
| 
 | |
| import '../friendica_client.dart';
 | |
| import '../globals.dart';
 | |
| import '../models/TimelineIdentifiers.dart';
 | |
| import '../models/entry_tree_item.dart';
 | |
| import '../models/exec_error.dart';
 | |
| import '../models/timeline_entry.dart';
 | |
| import 'auth_service.dart';
 | |
| 
 | |
| class EntryManagerService extends ChangeNotifier {
 | |
|   static final _logger = Logger('$EntryManagerService');
 | |
|   final Map<String, EntryTreeItem> _posts = {};
 | |
|   final List<EntryTreeItem> _orphanedComments = [];
 | |
|   final Map<String, EntryTreeItem> _allComments = {};
 | |
| 
 | |
|   FutureResult<List<EntryTreeItem>, ExecError> updateTimeline(
 | |
|       TimelineIdentifiers type, int highestId) async {
 | |
|     _logger.fine(() => 'Updating timeline');
 | |
|     final auth = getIt<AuthService>();
 | |
|     final clientResult = auth.currentClient;
 | |
|     if (clientResult.isFailure) {
 | |
|       _logger.severe('Error getting Friendica client: ${clientResult.error}');
 | |
|       return clientResult.errorCast();
 | |
|     }
 | |
| 
 | |
|     final client = clientResult.value;
 | |
|     final itemsResult =
 | |
|         await client.getTimeline(type: type, sinceId: highestId);
 | |
|     final myHandle = client.credentials.username;
 | |
|     if (itemsResult.isFailure) {
 | |
|       _logger.severe('Error getting timeline: ${itemsResult.error}');
 | |
|       return itemsResult.errorCast();
 | |
|     }
 | |
| 
 | |
|     itemsResult.value.sort((t1, t2) => t1.id.compareTo(t2.id));
 | |
|     final updatedPosts =
 | |
|         await processNewItems(itemsResult.value, myHandle, client);
 | |
|     _orphanedComments.removeWhere((element) => !element.isOrphaned);
 | |
|     _logger.finest(() =>
 | |
|         'End of update # posts: ${_posts.length}, #comments: ${_allComments.length}, #orphans: ${_orphanedComments.length}');
 | |
|     notifyListeners();
 | |
|     return Result.ok(updatedPosts);
 | |
|   }
 | |
| 
 | |
|   Future<List<EntryTreeItem>> processNewItems(
 | |
|     List<TimelineEntry> items,
 | |
|     String myHandle,
 | |
|     FriendicaClient? client,
 | |
|   ) async {
 | |
|     final updatedPosts = <EntryTreeItem>[];
 | |
|     for (final item in items) {
 | |
|       late EntryTreeItem entry;
 | |
|       final isMine = item.author == myHandle;
 | |
|       if (item.parentAuthor.isEmpty) {
 | |
|         entry = _posts.putIfAbsent(item.id,
 | |
|             () => EntryTreeItem(item, isMine: isMine, isOrphaned: false));
 | |
|         updatedPosts.add(entry);
 | |
|       } else {
 | |
|         final parentPost = _posts[item.parentId];
 | |
|         bool newEntry = false;
 | |
|         entry = _allComments.putIfAbsent(item.id, () {
 | |
|           newEntry = true;
 | |
|           return EntryTreeItem(
 | |
|             item,
 | |
|             isMine: isMine,
 | |
|             isOrphaned: parentPost == null,
 | |
|           );
 | |
|         });
 | |
| 
 | |
|         if (parentPost != null) {
 | |
|           parentPost.addChild(entry);
 | |
|           updatedPosts.add(parentPost);
 | |
|         }
 | |
| 
 | |
|         if (newEntry && entry.isOrphaned) {
 | |
|           _orphanedComments.add(entry);
 | |
|         }
 | |
|       }
 | |
|     }
 | |
| 
 | |
|     final orphansToProcess = [];
 | |
|     for (final c in _orphanedComments) {
 | |
|       final post = _posts[c.entry.parentId];
 | |
|       if (post != null) {
 | |
|         c.isOrphaned = false;
 | |
|         post.addChild(c);
 | |
|         updatedPosts.add(post);
 | |
|         continue;
 | |
|       }
 | |
| 
 | |
|       final comment = _allComments[c.entry.parentId];
 | |
|       if (comment != null) {
 | |
|         c.isOrphaned = false;
 | |
|         comment.addChild(c);
 | |
|         continue;
 | |
|       }
 | |
| 
 | |
|       if (client != null) {
 | |
|         orphansToProcess.add(c);
 | |
|       }
 | |
|     }
 | |
| 
 | |
|     for (final o in orphansToProcess) {
 | |
|       await client
 | |
|           ?.getPostOrComment(o.id, fullContext: true)
 | |
|           .andThenSuccessAsync((items) async {
 | |
|         final moreUpdatedPosts = await processNewItems(items, myHandle, null);
 | |
|         updatedPosts.addAll(moreUpdatedPosts);
 | |
|       });
 | |
|     }
 | |
|     _logger.finest(
 | |
|         'Completed processing new items ${client == null ? 'sub level' : 'top level'}');
 | |
|     return updatedPosts;
 | |
|   }
 | |
| 
 | |
|   FutureResult<EntryTreeItem, ExecError> refreshPost(EntryTreeItem item) async {
 | |
|     _logger.finest('Refreshing post: ${item.id}');
 | |
|     final auth = getIt<AuthService>();
 | |
|     final clientResult = auth.currentClient;
 | |
|     if (clientResult.isFailure) {
 | |
|       _logger.severe('Error getting Friendica client: ${clientResult.error}');
 | |
|       return clientResult.errorCast();
 | |
|     }
 | |
| 
 | |
|     final client = clientResult.value;
 | |
|     final result = await client
 | |
|         .getPostOrComment(item.id, fullContext: true)
 | |
|         .andThenSuccessAsync((items) async {
 | |
|       await processNewItems(items, client.credentials.username, null);
 | |
|     });
 | |
| 
 | |
|     return result.mapValue((_) {
 | |
|       _logger.finest('${item.id} post updated');
 | |
|       notifyListeners();
 | |
|       return _posts[item.id]!;
 | |
|     }).mapError(
 | |
|       (error) {
 | |
|         _logger.finest('${item.id} error updating: $error');
 | |
|         return ExecError(
 | |
|           type: ErrorType.localError,
 | |
|           message: error.toString(),
 | |
|         );
 | |
|       },
 | |
|     );
 | |
|   }
 | |
| 
 | |
|   FutureResult<EntryTreeItem, ExecError> toggleFavorited(
 | |
|       String id, bool newStatus,
 | |
|       {bool notify = false}) async {
 | |
|     final auth = getIt<AuthService>();
 | |
|     final clientResult = auth.currentClient;
 | |
|     if (clientResult.isFailure) {
 | |
|       _logger.severe('Error getting Friendica client: ${clientResult.error}');
 | |
|       return clientResult.errorCast();
 | |
|     }
 | |
|     final client = clientResult.value;
 | |
|     final result = await client.changeFavoriteStatus(id, newStatus);
 | |
|     if (result.isFailure) {
 | |
|       return result.errorCast();
 | |
|     }
 | |
| 
 | |
|     final update = result.value;
 | |
|     late EntryTreeItem rval;
 | |
|     if (_posts.containsKey(update.id)) {
 | |
|       rval = _posts[update.id]!.copy(entry: update);
 | |
|       _posts[update.id] = rval;
 | |
|       _updateChildrenEntities(rval, update);
 | |
|     }
 | |
| 
 | |
|     if (_allComments.containsKey(update.id)) {
 | |
|       rval = _allComments[update.id]!.copy(entry: update);
 | |
|       _allComments[update.id] = rval;
 | |
|       _updateChildrenEntities(rval, update);
 | |
|     }
 | |
| 
 | |
|     if (notify) {
 | |
|       notifyListeners();
 | |
|     }
 | |
|     return Result.ok(rval);
 | |
|   }
 | |
| 
 | |
|   void _updateChildrenEntities(EntryTreeItem item, TimelineEntry entry) {
 | |
|     final updates = item.children.where((element) => element.id == entry.id);
 | |
|     for (final u in updates) {
 | |
|       final newItem = u.copy(entry: entry);
 | |
|       item.children.remove(u);
 | |
|       item.children.add(newItem);
 | |
|     }
 | |
| 
 | |
|     for (final c in item.children) {
 | |
|       _updateChildrenEntities(c, entry);
 | |
|     }
 | |
|   }
 | |
| }
 |