2023-01-16 21:31:17 +00:00
|
|
|
import 'dart:collection';
|
2022-12-15 03:27:30 +00:00
|
|
|
import 'dart:math';
|
|
|
|
|
2022-12-08 18:37:30 +00:00
|
|
|
import 'package:flutter/material.dart';
|
|
|
|
import 'package:logging/logging.dart';
|
2022-11-18 21:50:15 +00:00
|
|
|
import 'package:result_monad/result_monad.dart';
|
|
|
|
|
2023-01-16 21:31:17 +00:00
|
|
|
import '../data/interfaces/connections_repo_intf.dart';
|
2023-01-18 04:03:50 +00:00
|
|
|
import '../data/interfaces/groups_repo.intf.dart';
|
2023-02-24 21:36:20 +00:00
|
|
|
import '../friendica_client/friendica_client.dart';
|
2023-01-24 03:37:09 +00:00
|
|
|
import '../friendica_client/paging_data.dart';
|
2022-12-08 18:37:30 +00:00
|
|
|
import '../globals.dart';
|
2022-11-18 21:50:15 +00:00
|
|
|
import '../models/connection.dart';
|
2022-12-08 18:37:30 +00:00
|
|
|
import '../models/exec_error.dart';
|
|
|
|
import '../models/group_data.dart';
|
|
|
|
import 'auth_service.dart';
|
2022-11-18 21:50:15 +00:00
|
|
|
|
2022-12-08 18:37:30 +00:00
|
|
|
class ConnectionsManager extends ChangeNotifier {
|
|
|
|
static final _logger = Logger('$ConnectionsManager');
|
2023-01-18 04:03:50 +00:00
|
|
|
late final IConnectionsRepo conRepo;
|
|
|
|
late final IGroupsRepo groupsRepo;
|
2023-01-16 21:31:17 +00:00
|
|
|
|
|
|
|
ConnectionsManager() {
|
2023-01-18 04:03:50 +00:00
|
|
|
conRepo = getIt<IConnectionsRepo>();
|
|
|
|
groupsRepo = getIt<IGroupsRepo>();
|
2022-11-18 21:50:15 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
bool addConnection(Connection connection) {
|
2023-01-18 04:03:50 +00:00
|
|
|
return conRepo.addConnection(connection);
|
2022-12-14 15:50:17 +00:00
|
|
|
}
|
|
|
|
|
2022-12-28 21:13:17 +00:00
|
|
|
List<Connection> getKnownUsersByName(String name) {
|
2023-01-18 04:03:50 +00:00
|
|
|
return conRepo.getKnownUsersByName(name);
|
2022-12-28 21:13:17 +00:00
|
|
|
}
|
|
|
|
|
2022-12-14 15:50:17 +00:00
|
|
|
bool updateConnection(Connection connection) {
|
2023-01-18 04:03:50 +00:00
|
|
|
return conRepo.updateConnection(connection);
|
2022-11-18 21:50:15 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
bool addAllConnections(Iterable<Connection> newConnections) {
|
2023-01-18 04:03:50 +00:00
|
|
|
return conRepo.addAllConnections(newConnections);
|
2022-11-18 21:50:15 +00:00
|
|
|
}
|
|
|
|
|
2022-12-19 18:59:33 +00:00
|
|
|
Future<void> acceptFollowRequest(Connection connection) async {
|
|
|
|
_logger.finest(
|
|
|
|
'Attempting to accept follow request ${connection.name}: ${connection.status}');
|
2023-02-27 03:12:40 +00:00
|
|
|
await RelationshipsClient(getIt<AccountsService>().currentProfile)
|
2023-02-24 21:36:20 +00:00
|
|
|
.acceptFollow(connection)
|
|
|
|
.match(
|
2022-12-19 18:59:33 +00:00
|
|
|
onSuccess: (update) {
|
|
|
|
_logger
|
|
|
|
.finest('Successfully followed ${update.name}: ${update.status}');
|
|
|
|
updateConnection(update);
|
|
|
|
notifyListeners();
|
|
|
|
},
|
|
|
|
onError: (error) {
|
2023-01-31 21:40:47 +00:00
|
|
|
_logger.severe('Error following ${connection.name}: $error');
|
2022-12-19 18:59:33 +00:00
|
|
|
},
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
Future<void> rejectFollowRequest(Connection connection) async {
|
|
|
|
_logger.finest(
|
|
|
|
'Attempting to accept follow request ${connection.name}: ${connection.status}');
|
2023-02-27 03:12:40 +00:00
|
|
|
await RelationshipsClient(getIt<AccountsService>().currentProfile)
|
2023-02-24 21:36:20 +00:00
|
|
|
.rejectFollow(connection)
|
|
|
|
.match(
|
2022-12-19 18:59:33 +00:00
|
|
|
onSuccess: (update) {
|
|
|
|
_logger
|
|
|
|
.finest('Successfully followed ${update.name}: ${update.status}');
|
|
|
|
updateConnection(update);
|
|
|
|
notifyListeners();
|
|
|
|
},
|
|
|
|
onError: (error) {
|
2023-01-31 21:40:47 +00:00
|
|
|
_logger.severe('Error following ${connection.name}: $error');
|
2022-12-19 18:59:33 +00:00
|
|
|
},
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
Future<void> ignoreFollowRequest(Connection connection) async {
|
|
|
|
_logger.finest(
|
|
|
|
'Attempting to accept follow request ${connection.name}: ${connection.status}');
|
2023-02-27 03:12:40 +00:00
|
|
|
await RelationshipsClient(getIt<AccountsService>().currentProfile)
|
2023-02-24 21:36:20 +00:00
|
|
|
.ignoreFollow(connection)
|
|
|
|
.match(
|
2022-12-19 18:59:33 +00:00
|
|
|
onSuccess: (update) {
|
|
|
|
_logger
|
|
|
|
.finest('Successfully followed ${update.name}: ${update.status}');
|
|
|
|
updateConnection(update);
|
|
|
|
notifyListeners();
|
|
|
|
},
|
|
|
|
onError: (error) {
|
|
|
|
_logger.severe('Error following ${connection.name}');
|
|
|
|
},
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
2022-12-14 15:50:17 +00:00
|
|
|
Future<void> follow(Connection connection) async {
|
|
|
|
_logger.finest(
|
|
|
|
'Attempting to follow ${connection.name}: ${connection.status}');
|
2023-02-27 03:12:40 +00:00
|
|
|
await RelationshipsClient(getIt<AccountsService>().currentProfile)
|
2023-02-24 21:36:20 +00:00
|
|
|
.followConnection(connection)
|
|
|
|
.match(
|
2022-12-14 15:50:17 +00:00
|
|
|
onSuccess: (update) {
|
|
|
|
_logger
|
|
|
|
.finest('Successfully followed ${update.name}: ${update.status}');
|
|
|
|
updateConnection(update);
|
|
|
|
notifyListeners();
|
|
|
|
},
|
|
|
|
onError: (error) {
|
|
|
|
_logger.severe('Error following ${connection.name}');
|
|
|
|
},
|
|
|
|
);
|
2022-12-08 18:37:30 +00:00
|
|
|
}
|
|
|
|
|
2022-12-14 15:50:17 +00:00
|
|
|
Future<void> unfollow(Connection connection) async {
|
|
|
|
_logger.finest(
|
|
|
|
'Attempting to unfollow ${connection.name}: ${connection.status}');
|
2023-02-27 03:12:40 +00:00
|
|
|
await RelationshipsClient(getIt<AccountsService>().currentProfile)
|
2023-02-24 20:56:39 +00:00
|
|
|
.unFollowConnection(connection)
|
2022-12-08 18:37:30 +00:00
|
|
|
.match(
|
2022-12-14 15:50:17 +00:00
|
|
|
onSuccess: (update) {
|
|
|
|
_logger
|
|
|
|
.finest('Successfully unfollowed ${update.name}: ${update.status}');
|
|
|
|
updateConnection(update);
|
2022-12-08 18:37:30 +00:00
|
|
|
notifyListeners();
|
|
|
|
},
|
|
|
|
onError: (error) {
|
2022-12-14 15:50:17 +00:00
|
|
|
_logger.severe('Error following ${connection.name}');
|
2022-12-08 18:37:30 +00:00
|
|
|
},
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
2023-01-18 05:15:52 +00:00
|
|
|
List<Connection> getMyContacts() {
|
2023-01-18 04:03:50 +00:00
|
|
|
return conRepo.getMyContacts();
|
2022-12-15 03:27:30 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
Future<void> updateAllContacts() async {
|
|
|
|
_logger.fine('Updating all contacts');
|
2023-02-27 03:12:40 +00:00
|
|
|
final client = RelationshipsClient(getIt<AccountsService>().currentProfile);
|
2022-12-15 03:27:30 +00:00
|
|
|
final results = <String, Connection>{};
|
|
|
|
var moreResults = true;
|
|
|
|
var maxId = -1;
|
2023-01-24 03:37:09 +00:00
|
|
|
const limit = 200;
|
|
|
|
var currentPage = PagingData(limit: limit);
|
2022-12-15 03:27:30 +00:00
|
|
|
while (moreResults) {
|
2023-01-24 03:37:09 +00:00
|
|
|
await client.getMyFollowers(currentPage).match(onSuccess: (followers) {
|
|
|
|
for (final f in followers.data) {
|
2022-12-20 22:01:30 +00:00
|
|
|
results[f.id] = f.copy(status: ConnectionStatus.theyFollowYou);
|
|
|
|
int id = int.parse(f.id);
|
|
|
|
maxId = max(maxId, id);
|
2022-12-15 03:27:30 +00:00
|
|
|
}
|
2023-01-24 03:37:09 +00:00
|
|
|
if (followers.next != null) {
|
|
|
|
currentPage = followers.next!;
|
|
|
|
}
|
|
|
|
moreResults = followers.next != null;
|
2022-12-15 03:27:30 +00:00
|
|
|
}, onError: (error) {
|
|
|
|
_logger.severe('Error getting followers data: $error');
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
moreResults = true;
|
2023-01-24 03:37:09 +00:00
|
|
|
currentPage = PagingData(limit: limit);
|
2022-12-15 03:27:30 +00:00
|
|
|
while (moreResults) {
|
2023-01-24 03:37:09 +00:00
|
|
|
await client.getMyFollowing(currentPage).match(onSuccess: (following) {
|
|
|
|
for (final f in following.data) {
|
2022-12-20 22:01:30 +00:00
|
|
|
if (results.containsKey(f.id)) {
|
|
|
|
results[f.id] = f.copy(status: ConnectionStatus.mutual);
|
|
|
|
} else {
|
|
|
|
results[f.id] = f.copy(status: ConnectionStatus.youFollowThem);
|
2022-12-15 03:27:30 +00:00
|
|
|
}
|
2022-12-20 22:01:30 +00:00
|
|
|
int id = int.parse(f.id);
|
|
|
|
maxId = max(maxId, id);
|
2022-12-15 03:27:30 +00:00
|
|
|
}
|
2023-01-24 03:37:09 +00:00
|
|
|
if (following.next != null) {
|
|
|
|
currentPage = following.next!;
|
|
|
|
}
|
|
|
|
moreResults = following.next != null;
|
2022-12-15 03:27:30 +00:00
|
|
|
}, onError: (error) {
|
|
|
|
_logger.severe('Error getting followers data: $error');
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
addAllConnections(results.values);
|
2023-01-18 04:03:50 +00:00
|
|
|
final myContacts = conRepo.getMyContacts().toList();
|
2023-01-16 21:31:17 +00:00
|
|
|
myContacts.sort((c1, c2) => c1.name.compareTo(c2.name));
|
2023-01-24 03:37:09 +00:00
|
|
|
_logger.fine('# Contacts:${myContacts.length}');
|
2022-12-15 03:27:30 +00:00
|
|
|
notifyListeners();
|
|
|
|
}
|
|
|
|
|
2023-01-18 04:03:50 +00:00
|
|
|
List<GroupData> getMyGroups() {
|
|
|
|
final myGroups = groupsRepo.getMyGroups();
|
2023-01-16 21:31:17 +00:00
|
|
|
if (myGroups.isEmpty) {
|
|
|
|
_updateMyGroups(true);
|
2022-12-14 15:50:17 +00:00
|
|
|
}
|
2023-01-16 21:31:17 +00:00
|
|
|
|
|
|
|
return myGroups;
|
2022-12-14 21:53:46 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
Result<List<GroupData>, ExecError> getGroupsForUser(String id) {
|
2023-01-18 04:03:50 +00:00
|
|
|
final result = groupsRepo.getGroupsForUser(id);
|
2023-01-16 21:31:17 +00:00
|
|
|
if (result.isSuccess) {
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (result.isFailure && result.error.type != ErrorType.notFound) {
|
|
|
|
return result;
|
2022-12-14 21:53:46 +00:00
|
|
|
}
|
|
|
|
|
2023-01-16 21:31:17 +00:00
|
|
|
_refreshGroupListData(id, true);
|
|
|
|
return Result.ok(UnmodifiableListView([]));
|
2022-12-14 21:53:46 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
FutureResult<bool, ExecError> addUserToGroup(
|
|
|
|
GroupData group, Connection connection) async {
|
|
|
|
_logger.finest('Adding ${connection.name} to group: ${group.name}');
|
2023-02-27 03:12:40 +00:00
|
|
|
final result = await GroupsClient(getIt<AccountsService>().currentProfile)
|
|
|
|
.addConnectionToGroup(group, connection);
|
2022-12-14 21:53:46 +00:00
|
|
|
result.match(
|
|
|
|
onSuccess: (_) => _refreshGroupListData(connection.id, true),
|
|
|
|
onError: (error) {
|
|
|
|
_logger
|
|
|
|
.severe('Error adding ${connection.name} to group: ${group.name}');
|
|
|
|
},
|
|
|
|
);
|
|
|
|
|
|
|
|
return result.execErrorCast();
|
|
|
|
}
|
|
|
|
|
|
|
|
FutureResult<bool, ExecError> removeUserFromGroup(
|
|
|
|
GroupData group, Connection connection) async {
|
|
|
|
_logger.finest('Removing ${connection.name} from group: ${group.name}');
|
2023-02-27 03:12:40 +00:00
|
|
|
final result = await GroupsClient(getIt<AccountsService>().currentProfile)
|
|
|
|
.removeConnectionFromGroup(group, connection);
|
2022-12-14 21:53:46 +00:00
|
|
|
result.match(
|
|
|
|
onSuccess: (_) => _refreshGroupListData(connection.id, true),
|
|
|
|
onError: (error) {
|
|
|
|
_logger.severe(
|
|
|
|
'Error removing ${connection.name} from group: ${group.name}');
|
|
|
|
},
|
|
|
|
);
|
|
|
|
|
|
|
|
return result.execErrorCast();
|
2022-12-14 15:50:17 +00:00
|
|
|
}
|
|
|
|
|
2023-01-16 21:31:17 +00:00
|
|
|
Result<Connection, ExecError> getById(String id) {
|
2023-01-18 04:03:50 +00:00
|
|
|
return conRepo.getById(id).andThenSuccess((c) {
|
2023-01-16 21:31:17 +00:00
|
|
|
if (c.status == ConnectionStatus.unknown) {
|
|
|
|
_refreshConnection(c, true);
|
|
|
|
}
|
|
|
|
return c;
|
|
|
|
}).execErrorCast();
|
2022-11-18 21:50:15 +00:00
|
|
|
}
|
|
|
|
|
2023-01-16 21:31:17 +00:00
|
|
|
Result<Connection, ExecError> getByName(String name) {
|
2023-01-18 04:03:50 +00:00
|
|
|
return conRepo.getByName(name).andThenSuccess((c) {
|
2023-01-16 21:31:17 +00:00
|
|
|
if (c.status == ConnectionStatus.unknown) {
|
|
|
|
_refreshConnection(c, true);
|
2023-01-25 18:51:53 +00:00
|
|
|
}
|
|
|
|
return c;
|
|
|
|
}).execErrorCast();
|
|
|
|
}
|
|
|
|
|
|
|
|
Result<Connection, ExecError> getByHandle(String handle) {
|
|
|
|
return conRepo.getByHandle(handle).andThenSuccess((c) {
|
|
|
|
if (c.status == ConnectionStatus.unknown) {
|
|
|
|
_refreshConnection(c, true);
|
2023-01-16 21:31:17 +00:00
|
|
|
}
|
|
|
|
return c;
|
|
|
|
}).execErrorCast();
|
2022-12-14 15:50:17 +00:00
|
|
|
}
|
|
|
|
|
2022-12-14 21:53:46 +00:00
|
|
|
Future<void> fullRefresh(Connection connection) async {
|
|
|
|
await _updateMyGroups(false);
|
|
|
|
await _refreshGroupListData(connection.id, false);
|
|
|
|
await _refreshConnection(connection, false);
|
|
|
|
notifyListeners();
|
|
|
|
}
|
|
|
|
|
|
|
|
Future<void> _refreshGroupListData(String id, bool withNotification) async {
|
2022-12-14 15:50:17 +00:00
|
|
|
_logger.finest('Refreshing member list data for Connection $id');
|
2023-02-27 03:12:40 +00:00
|
|
|
await GroupsClient(getIt<AccountsService>().currentProfile)
|
2023-02-24 20:56:39 +00:00
|
|
|
.getMemberGroupsForConnection(id)
|
2022-12-14 15:50:17 +00:00
|
|
|
.match(
|
2023-01-16 21:31:17 +00:00
|
|
|
onSuccess: (groups) {
|
2023-01-18 04:03:50 +00:00
|
|
|
groupsRepo.updateConnectionGroupData(id, groups);
|
2022-12-14 21:53:46 +00:00
|
|
|
if (withNotification) {
|
|
|
|
notifyListeners();
|
|
|
|
}
|
2022-12-14 15:50:17 +00:00
|
|
|
},
|
|
|
|
onError: (error) {
|
|
|
|
_logger.severe('Error getting list data for $id: $error');
|
|
|
|
},
|
|
|
|
);
|
|
|
|
}
|
2022-11-18 21:50:15 +00:00
|
|
|
|
2022-12-14 21:53:46 +00:00
|
|
|
Future<void> _refreshConnection(
|
|
|
|
Connection connection, bool withNotification) async {
|
2022-12-14 15:50:17 +00:00
|
|
|
_logger.finest('Refreshing connection data for ${connection.name}');
|
2023-02-27 03:12:40 +00:00
|
|
|
await RelationshipsClient(getIt<AccountsService>().currentProfile)
|
2023-02-24 20:56:39 +00:00
|
|
|
.getConnectionWithStatus(connection)
|
2022-12-14 15:50:17 +00:00
|
|
|
.match(
|
|
|
|
onSuccess: (update) {
|
|
|
|
updateConnection(update);
|
2022-12-14 21:53:46 +00:00
|
|
|
if (withNotification) {
|
|
|
|
notifyListeners();
|
|
|
|
}
|
2022-12-14 15:50:17 +00:00
|
|
|
},
|
|
|
|
onError: (error) {
|
|
|
|
_logger.severe('Error getting updates for ${connection.name}: $error');
|
|
|
|
},
|
|
|
|
);
|
2022-11-18 21:50:15 +00:00
|
|
|
}
|
2022-12-14 21:53:46 +00:00
|
|
|
|
|
|
|
Future<void> _updateMyGroups(bool withNotification) async {
|
|
|
|
_logger.finest('Refreshing my groups list');
|
2023-02-27 03:12:40 +00:00
|
|
|
await GroupsClient(getIt<AccountsService>().currentProfile)
|
2023-02-24 21:36:20 +00:00
|
|
|
.getGroups()
|
|
|
|
.match(
|
2022-12-14 21:53:46 +00:00
|
|
|
onSuccess: (groups) {
|
|
|
|
_logger.finest('Got updated groups:${groups.map((e) => e.name)}');
|
2023-01-18 04:03:50 +00:00
|
|
|
groupsRepo.clearGroups();
|
|
|
|
groupsRepo.addAllGroups(groups);
|
2022-12-14 21:53:46 +00:00
|
|
|
if (withNotification) {
|
|
|
|
notifyListeners();
|
|
|
|
}
|
|
|
|
},
|
|
|
|
onError: (error) {
|
|
|
|
_logger.severe('Error getting my groups: $error');
|
|
|
|
},
|
|
|
|
);
|
|
|
|
}
|
2022-11-18 21:50:15 +00:00
|
|
|
}
|