2024-12-07 02:33:51 +00:00
|
|
|
import 'dart:math';
|
|
|
|
|
|
|
|
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
|
|
|
import 'package:logging/logging.dart';
|
|
|
|
import 'package:result_monad/result_monad.dart';
|
|
|
|
import 'package:riverpod_annotation/riverpod_annotation.dart';
|
2024-12-19 21:24:37 +00:00
|
|
|
import 'package:stack_trace/stack_trace.dart';
|
2024-12-07 02:33:51 +00:00
|
|
|
|
|
|
|
import '../data/interfaces/connections_repo_intf.dart';
|
|
|
|
import '../data/objectbox/objectbox_cache.dart';
|
|
|
|
import '../data/objectbox/objectbox_connections_repo.dart';
|
|
|
|
import '../models/auth/profile.dart';
|
|
|
|
import '../models/connection.dart';
|
|
|
|
import '../models/exec_error.dart';
|
2024-12-10 13:49:20 +00:00
|
|
|
import '../models/networking/paging_data.dart';
|
2024-12-24 17:21:44 +00:00
|
|
|
import '../riverpod_controllers/networking/friendica_trending_client_services.dart';
|
2024-12-07 02:33:51 +00:00
|
|
|
import 'circles_repo_services.dart';
|
2024-12-13 04:57:57 +00:00
|
|
|
import 'networking/friendica_relationship_client_services.dart';
|
2024-12-07 02:33:51 +00:00
|
|
|
import 'persistent_info_services.dart';
|
|
|
|
|
|
|
|
part 'connection_manager_services.g.dart';
|
|
|
|
|
|
|
|
final _crLogger = Logger('ConnectionsRepoProvider');
|
|
|
|
|
|
|
|
@Riverpod(keepAlive: true)
|
|
|
|
Future<IConnectionsRepo> _connectionsRepo(Ref ref, Profile profile) async {
|
|
|
|
_crLogger.info('Creating Connections repo for $profile');
|
|
|
|
final objectBox = await ObjectBoxCache.create(
|
|
|
|
baseDir: 'profileboxcaches',
|
|
|
|
subDir: profile.id,
|
|
|
|
);
|
|
|
|
|
|
|
|
_crLogger.info('Object box object returned for $profile');
|
|
|
|
return ObjectBoxConnectionsRepo(objectBox);
|
|
|
|
}
|
|
|
|
|
|
|
|
final _crsLogger = Logger('ConnectionsRepoSyncProvider');
|
|
|
|
|
|
|
|
@Riverpod(keepAlive: true)
|
|
|
|
class _ConnectionsRepoSync extends _$ConnectionsRepoSync {
|
|
|
|
@override
|
2025-01-06 19:05:44 +00:00
|
|
|
Result<IConnectionsRepo, ExecError> build(Profile profile) {
|
2024-12-07 02:33:51 +00:00
|
|
|
_crsLogger.info('Build $profile');
|
2024-12-19 16:49:40 +00:00
|
|
|
ref.watch(_connectionsRepoProvider(profile).future).then((repo) {
|
|
|
|
state = Result.ok(repo);
|
|
|
|
ref.notifyListeners();
|
|
|
|
});
|
2025-01-06 19:05:44 +00:00
|
|
|
return Result.error(ExecError(type: ErrorType.riveprodProviderNotReady));
|
2024-12-07 02:33:51 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-12-07 14:08:05 +00:00
|
|
|
@riverpod
|
|
|
|
class ConnectionsRepoClearer extends _$ConnectionsRepoClearer {
|
|
|
|
@override
|
|
|
|
bool build(Profile profile) {
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool clear() {
|
|
|
|
return ref
|
|
|
|
.read(_connectionsRepoSyncProvider(profile))
|
|
|
|
.withResult((repo) => repo.clear())
|
|
|
|
.isSuccess;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-12-10 11:54:45 +00:00
|
|
|
@riverpod
|
|
|
|
Future<bool> connectionRepoInit(Ref ref, Profile profile) async {
|
|
|
|
await ref.read(_connectionsRepoProvider(profile).future);
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2024-12-07 02:33:51 +00:00
|
|
|
@riverpod
|
2025-07-24 19:06:49 +00:00
|
|
|
List<Connection> knownUsersByName(Ref ref, Profile profile, String userName,
|
|
|
|
{Set<ConnectionStatus>? matchingStatus}) {
|
2024-12-07 02:33:51 +00:00
|
|
|
return ref.watch(_connectionsRepoSyncProvider(profile)).fold(
|
2025-07-24 19:06:49 +00:00
|
|
|
onSuccess: (repo) {
|
|
|
|
final knownUsers = repo.getKnownUsersByName(userName);
|
|
|
|
if (matchingStatus == null) {
|
|
|
|
return knownUsers;
|
|
|
|
}
|
|
|
|
|
|
|
|
return knownUsers
|
|
|
|
.where((u) => matchingStatus.contains(u.status))
|
|
|
|
.toList();
|
|
|
|
},
|
2024-12-07 02:33:51 +00:00
|
|
|
onError: (_) => []);
|
|
|
|
}
|
|
|
|
|
|
|
|
@riverpod
|
|
|
|
Future<List<Connection>> myContacts(Ref ref, Profile profile) async {
|
|
|
|
final repo = await ref.watch(_connectionsRepoProvider(profile).future);
|
|
|
|
return repo.getMyContacts();
|
|
|
|
}
|
|
|
|
|
2024-12-17 02:46:51 +00:00
|
|
|
final _cbiLogger = Logger('ConnectionByIdProvider');
|
2024-12-20 02:30:14 +00:00
|
|
|
|
2024-12-07 02:33:51 +00:00
|
|
|
@riverpod
|
|
|
|
Result<Connection, ExecError> connectionById(
|
|
|
|
Ref ref, Profile profile, String id,
|
|
|
|
{bool forceUpdate = false}) {
|
2024-12-17 02:46:51 +00:00
|
|
|
_cbiLogger.finest('Build for $id for $profile');
|
2024-12-07 02:33:51 +00:00
|
|
|
final result = ref
|
2024-12-19 16:49:40 +00:00
|
|
|
.watch(_connectionsRepoSyncProvider(profile))
|
2024-12-07 02:33:51 +00:00
|
|
|
.andThen((repo) => repo.getById(id))
|
|
|
|
.transform((c) {
|
2024-12-19 20:01:39 +00:00
|
|
|
if (forceUpdate) {
|
2024-12-07 02:33:51 +00:00
|
|
|
ref
|
|
|
|
.read(connectionModifierProvider(profile, c).notifier)
|
2024-12-13 04:57:57 +00:00
|
|
|
.refreshConnection(true);
|
2024-12-07 02:33:51 +00:00
|
|
|
}
|
|
|
|
return c;
|
2024-12-13 04:57:57 +00:00
|
|
|
}).withError((error) {
|
2025-01-06 19:05:44 +00:00
|
|
|
if (error is ExecError &&
|
|
|
|
error.type == ErrorType.riveprodProviderNotReady) {
|
2024-12-17 02:46:51 +00:00
|
|
|
return;
|
|
|
|
}
|
2024-12-13 04:57:57 +00:00
|
|
|
final tmpConnection = Connection(id: id);
|
|
|
|
ref
|
|
|
|
.read(connectionModifierProvider(profile, tmpConnection).notifier)
|
|
|
|
.refreshConnection(true);
|
2024-12-07 02:33:51 +00:00
|
|
|
}).execErrorCast();
|
|
|
|
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
2024-12-17 02:46:51 +00:00
|
|
|
final _cbhLogger = Logger('ConnectionByHandleProvider');
|
2024-12-07 02:33:51 +00:00
|
|
|
|
|
|
|
@riverpod
|
|
|
|
Result<Connection, ExecError> connectionByHandle(
|
|
|
|
Ref ref, Profile profile, String handle) {
|
2024-12-17 02:46:51 +00:00
|
|
|
_cbhLogger.finest('Build for $handle for $profile');
|
2024-12-07 02:33:51 +00:00
|
|
|
return ref
|
2024-12-19 16:49:40 +00:00
|
|
|
.watch(_connectionsRepoSyncProvider(profile))
|
2024-12-07 02:33:51 +00:00
|
|
|
.andThen((repo) => repo.getByHandle(handle))
|
2024-12-17 02:46:51 +00:00
|
|
|
.execErrorCast();
|
2024-12-07 02:33:51 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
final _cmpLogger = Logger('ConnectionModifierProvider');
|
|
|
|
|
|
|
|
@riverpod
|
|
|
|
class ConnectionModifier extends _$ConnectionModifier {
|
|
|
|
@override
|
|
|
|
Connection build(Profile profile, Connection connection) {
|
|
|
|
return connection;
|
|
|
|
}
|
|
|
|
|
2024-12-17 02:46:51 +00:00
|
|
|
Future<void> upsertConnection(Connection update) async {
|
|
|
|
final repo = await ref.read(_connectionsRepoProvider(profile).future);
|
|
|
|
|
|
|
|
repo.getById(connection.id).match(
|
|
|
|
onSuccess: (original) {
|
|
|
|
late final Connection forUpsert;
|
|
|
|
if (update.status == ConnectionStatus.unknown) {
|
|
|
|
forUpsert = update.copy(status: original.status);
|
|
|
|
} else {
|
|
|
|
forUpsert = update;
|
|
|
|
}
|
|
|
|
|
|
|
|
repo.upsertConnection(
|
|
|
|
forUpsert,
|
|
|
|
);
|
|
|
|
state = forUpsert;
|
|
|
|
},
|
|
|
|
onError: (_) {
|
|
|
|
repo.upsertConnection(update);
|
|
|
|
state = update;
|
|
|
|
},
|
|
|
|
);
|
2024-12-20 14:45:39 +00:00
|
|
|
_sendUpdateNotifications();
|
2024-12-17 02:46:51 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2024-12-07 02:33:51 +00:00
|
|
|
Future<void> acceptFollowRequest() async {
|
|
|
|
_cmpLogger.finest(
|
|
|
|
'Attempting to accept follow request ${connection.name}: ${connection.status}');
|
2024-12-13 04:57:57 +00:00
|
|
|
|
|
|
|
await ref
|
|
|
|
.read(adjudicateFollowProvider(
|
|
|
|
profile, connection, FollowAdjudication.authorize)
|
|
|
|
.future)
|
|
|
|
.match(
|
2024-12-17 02:46:51 +00:00
|
|
|
onSuccess: (update) async {
|
2024-12-07 02:33:51 +00:00
|
|
|
_cmpLogger
|
|
|
|
.finest('Successfully followed ${update.name}: ${update.status}');
|
2024-12-17 02:46:51 +00:00
|
|
|
await upsertConnection(update);
|
2024-12-07 02:33:51 +00:00
|
|
|
},
|
|
|
|
onError: (error) {
|
2024-12-19 21:24:37 +00:00
|
|
|
_cmpLogger.severe(
|
|
|
|
'Error following ${connection.name}: $error',
|
|
|
|
Trace.current(),
|
|
|
|
);
|
2024-12-07 02:33:51 +00:00
|
|
|
},
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
Future<void> rejectFollowRequest() async {
|
|
|
|
_cmpLogger.finest(
|
|
|
|
'Attempting to accept follow request ${connection.name}: ${connection.status}');
|
2024-12-13 04:57:57 +00:00
|
|
|
await ref
|
|
|
|
.read(adjudicateFollowProvider(
|
|
|
|
profile, connection, FollowAdjudication.reject)
|
|
|
|
.future)
|
|
|
|
.match(
|
2024-12-17 02:46:51 +00:00
|
|
|
onSuccess: (update) async {
|
2024-12-07 02:33:51 +00:00
|
|
|
_cmpLogger
|
|
|
|
.finest('Successfully followed ${update.name}: ${update.status}');
|
2024-12-17 02:46:51 +00:00
|
|
|
await upsertConnection(update);
|
2024-12-07 02:33:51 +00:00
|
|
|
},
|
|
|
|
onError: (error) {
|
|
|
|
_cmpLogger.severe('Error following ${connection.name}: $error');
|
|
|
|
},
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
Future<void> ignoreFollowRequest() async {
|
|
|
|
_cmpLogger.finest(
|
|
|
|
'Attempting to accept follow request ${connection.name}: ${connection.status}');
|
2024-12-13 04:57:57 +00:00
|
|
|
await ref
|
|
|
|
.read(adjudicateFollowProvider(
|
|
|
|
profile, connection, FollowAdjudication.ignore)
|
|
|
|
.future)
|
|
|
|
.match(
|
2024-12-17 03:47:44 +00:00
|
|
|
onSuccess: (update) async {
|
2024-12-07 02:33:51 +00:00
|
|
|
_cmpLogger
|
|
|
|
.finest('Successfully followed ${update.name}: ${update.status}');
|
2024-12-17 03:47:44 +00:00
|
|
|
await upsertConnection(update);
|
2024-12-07 02:33:51 +00:00
|
|
|
},
|
|
|
|
onError: (error) {
|
|
|
|
_cmpLogger.severe('Error following ${connection.name}');
|
|
|
|
},
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
Future<void> follow() async {
|
|
|
|
_cmpLogger.finest(
|
|
|
|
'Attempting to follow ${connection.name}: ${connection.status}');
|
2024-12-13 04:57:57 +00:00
|
|
|
await ref.read(followConnectionProvider(profile, connection).future).match(
|
2024-12-17 02:46:51 +00:00
|
|
|
onSuccess: (update) async {
|
2024-12-07 02:33:51 +00:00
|
|
|
_cmpLogger
|
|
|
|
.finest('Successfully followed ${update.name}: ${update.status}');
|
2024-12-17 02:46:51 +00:00
|
|
|
await upsertConnection(update);
|
2024-12-07 02:33:51 +00:00
|
|
|
},
|
|
|
|
onError: (error) {
|
|
|
|
_cmpLogger.severe('Error following ${connection.name}');
|
|
|
|
},
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
Future<void> unfollow() async {
|
|
|
|
_cmpLogger.finest(
|
|
|
|
'Attempting to unfollow ${connection.name}: ${connection.status}');
|
2024-12-13 04:57:57 +00:00
|
|
|
await ref
|
|
|
|
.read(unFollowConnectionProvider(profile, connection).future)
|
|
|
|
.match(
|
2024-12-17 02:46:51 +00:00
|
|
|
onSuccess: (update) async {
|
2024-12-07 02:33:51 +00:00
|
|
|
_cmpLogger
|
|
|
|
.finest('Successfully unfollowed ${update.name}: ${update.status}');
|
2024-12-17 02:46:51 +00:00
|
|
|
await upsertConnection(update);
|
2024-12-07 02:33:51 +00:00
|
|
|
},
|
|
|
|
onError: (error) {
|
|
|
|
_cmpLogger.severe('Error following ${connection.name}');
|
|
|
|
},
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
void _sendUpdateNotifications() {
|
|
|
|
ref.invalidate(myContactsProvider);
|
|
|
|
ref.invalidate(connectionByIdProvider(profile, connection.id));
|
|
|
|
ref.invalidate(connectionByHandleProvider(profile, connection.handle));
|
|
|
|
}
|
|
|
|
|
|
|
|
Future<void> fullRefresh({
|
|
|
|
bool withNotifications = true,
|
|
|
|
}) async {
|
|
|
|
await ref.read(circlesProvider(profile).notifier).refresh();
|
|
|
|
await ref
|
|
|
|
.read(circlesProvider(profile).notifier)
|
|
|
|
.refreshConnectionCircleData(connection.id, false);
|
|
|
|
await ref
|
|
|
|
.read(connectionModifierProvider(profile, connection).notifier)
|
|
|
|
.refreshConnection(false);
|
|
|
|
if (withNotifications) {
|
|
|
|
ref.notifyListeners();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
Future<void> refreshConnection(bool withNotification) async {
|
2024-12-17 02:46:51 +00:00
|
|
|
_cmpLogger.finest(
|
|
|
|
'Refreshing connection data for ${connection.name} with notifications? $withNotification');
|
2024-12-13 04:57:57 +00:00
|
|
|
await ref
|
|
|
|
.read(connectionWithStatusClientProvider(profile, connection).future)
|
2024-12-07 02:33:51 +00:00
|
|
|
.match(
|
2024-12-17 02:46:51 +00:00
|
|
|
onSuccess: (update) async {
|
|
|
|
await upsertConnection(update);
|
2024-12-07 02:33:51 +00:00
|
|
|
if (withNotification) {
|
|
|
|
_sendUpdateNotifications();
|
|
|
|
}
|
|
|
|
},
|
|
|
|
onError: (error) {
|
|
|
|
_cmpLogger
|
|
|
|
.severe('Error getting updates for ${connection.name}: $error');
|
|
|
|
},
|
|
|
|
);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
@Riverpod(keepAlive: true)
|
|
|
|
class _UpdateStatusInternal extends _$UpdateStatusInternal {
|
|
|
|
@override
|
|
|
|
String build(Profile profile) {
|
|
|
|
return '';
|
|
|
|
}
|
|
|
|
|
|
|
|
void update(String update) {
|
|
|
|
state = update;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
@riverpod
|
|
|
|
String updateStatus(Ref ref, Profile profile) {
|
|
|
|
return ref.watch(_updateStatusInternalProvider(profile));
|
|
|
|
}
|
|
|
|
|
|
|
|
final _acuLogger = Logger('AllContactsUpdaterProvider');
|
|
|
|
|
|
|
|
@Riverpod(keepAlive: true)
|
|
|
|
class AllContactsUpdater extends _$AllContactsUpdater {
|
|
|
|
@override
|
|
|
|
bool build(Profile profile) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
Future<void> updateAllContacts(bool backgroundUpdate) async {
|
|
|
|
// TODO check if profile is no longer same and stop if it is between pagings and cancel if so
|
|
|
|
if (state) {
|
|
|
|
_acuLogger.info(
|
|
|
|
'updateAllContacts called but believe it is already running so skipping');
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
state = true;
|
|
|
|
_acuLogger.info('Updating all contacts');
|
2024-12-24 20:54:30 +00:00
|
|
|
|
|
|
|
final messageStart = backgroundUpdate ? 'Background ' : '';
|
|
|
|
final delay = backgroundUpdate
|
|
|
|
? const Duration(minutes: 5)
|
|
|
|
: const Duration(seconds: 10);
|
|
|
|
|
2024-12-07 02:33:51 +00:00
|
|
|
ref
|
|
|
|
.read(_updateStatusInternalProvider(profile).notifier)
|
2024-12-24 20:54:30 +00:00
|
|
|
.update('${messageStart}Updating Connections Data');
|
2024-12-07 02:33:51 +00:00
|
|
|
final originalTime = ref.read(persistentInfoProvider(profile));
|
|
|
|
await ref
|
|
|
|
.read(persistentInfoProvider(profile).notifier)
|
|
|
|
.updateLastMyConnectionUpdate(DateTime.now());
|
|
|
|
|
|
|
|
try {
|
|
|
|
final results = <String, Connection>{};
|
|
|
|
var moreResults = true;
|
|
|
|
var maxId = -1;
|
|
|
|
const limit = 50;
|
2024-12-24 20:22:06 +00:00
|
|
|
var currentPage = const PagingData(limit: limit);
|
2024-12-24 20:54:30 +00:00
|
|
|
final originalContacts = Set<Connection>.from(
|
|
|
|
ref.read(myContactsProvider(profile)).valueOrNull ?? []);
|
|
|
|
num count = 0;
|
2024-12-07 02:33:51 +00:00
|
|
|
while (moreResults) {
|
2024-12-13 04:57:57 +00:00
|
|
|
await ref
|
|
|
|
.read(getMyFollowersProvider(profile, currentPage).future)
|
|
|
|
.match(onSuccess: (followers) {
|
2024-12-24 20:54:30 +00:00
|
|
|
count += followers.data.length;
|
2024-12-07 02:33:51 +00:00
|
|
|
for (final f in followers.data) {
|
|
|
|
originalContacts.remove(f);
|
2024-12-24 20:33:04 +00:00
|
|
|
final c = f.copy(status: ConnectionStatus.theyFollowYou);
|
|
|
|
results[c.id] = c;
|
|
|
|
ref
|
|
|
|
.read(connectionModifierProvider(profile, c).notifier)
|
|
|
|
.upsertConnection(c);
|
2024-12-07 02:33:51 +00:00
|
|
|
int id = int.parse(f.id);
|
|
|
|
maxId = max(maxId, id);
|
|
|
|
}
|
|
|
|
if (followers.next != null) {
|
|
|
|
currentPage = followers.next!;
|
|
|
|
}
|
|
|
|
moreResults = followers.next != null;
|
2024-12-24 20:33:04 +00:00
|
|
|
ref
|
|
|
|
.read(_updateStatusInternalProvider(profile).notifier)
|
2024-12-24 20:54:30 +00:00
|
|
|
.update('${messageStart}Updating Followers: $count processed');
|
2024-12-07 02:33:51 +00:00
|
|
|
}, onError: (error) {
|
2024-12-19 21:24:37 +00:00
|
|
|
_acuLogger.severe(
|
|
|
|
'Error getting followers data: $error',
|
|
|
|
Trace.current(),
|
|
|
|
);
|
2024-12-07 02:33:51 +00:00
|
|
|
moreResults = false;
|
|
|
|
});
|
|
|
|
|
|
|
|
await Future.delayed(delay);
|
|
|
|
}
|
|
|
|
|
|
|
|
moreResults = true;
|
2024-12-24 20:22:06 +00:00
|
|
|
currentPage = const PagingData(limit: limit);
|
2024-12-24 20:54:30 +00:00
|
|
|
count = 0;
|
2024-12-07 02:33:51 +00:00
|
|
|
while (moreResults) {
|
2024-12-13 04:57:57 +00:00
|
|
|
await ref
|
2024-12-24 20:22:06 +00:00
|
|
|
.read(myFollowingClientProvider(profile, currentPage).future)
|
2024-12-13 04:57:57 +00:00
|
|
|
.match(onSuccess: (following) {
|
2024-12-24 20:54:30 +00:00
|
|
|
count += following.data.length;
|
2024-12-07 02:33:51 +00:00
|
|
|
for (final f in following.data) {
|
|
|
|
originalContacts.remove(f);
|
|
|
|
final newStatus = results.containsKey(f.id)
|
|
|
|
? ConnectionStatus.mutual
|
|
|
|
: ConnectionStatus.youFollowThem;
|
2024-12-24 20:33:04 +00:00
|
|
|
final c = f.copy(status: newStatus);
|
2024-12-07 02:33:51 +00:00
|
|
|
ref
|
2024-12-24 20:33:04 +00:00
|
|
|
.read(connectionModifierProvider(profile, c).notifier)
|
|
|
|
.upsertConnection(c);
|
2024-12-07 02:33:51 +00:00
|
|
|
int id = int.parse(f.id);
|
|
|
|
maxId = max(maxId, id);
|
|
|
|
}
|
|
|
|
if (following.next != null) {
|
|
|
|
currentPage = following.next!;
|
|
|
|
}
|
|
|
|
moreResults = following.next != null;
|
2024-12-24 20:33:04 +00:00
|
|
|
ref
|
|
|
|
.read(_updateStatusInternalProvider(profile).notifier)
|
2024-12-24 20:54:30 +00:00
|
|
|
.update('${messageStart}Updating Followings: $count processed');
|
2024-12-07 02:33:51 +00:00
|
|
|
}, onError: (error) {
|
2024-12-19 21:24:37 +00:00
|
|
|
_acuLogger.severe(
|
2024-12-24 20:22:06 +00:00
|
|
|
'Error getting your following data: $error',
|
2024-12-19 21:24:37 +00:00
|
|
|
Trace.current(),
|
|
|
|
);
|
2024-12-07 02:33:51 +00:00
|
|
|
});
|
|
|
|
await Future.delayed(delay);
|
|
|
|
}
|
|
|
|
|
2024-12-24 20:54:30 +00:00
|
|
|
ref
|
|
|
|
.read(_updateStatusInternalProvider(profile).notifier)
|
|
|
|
.update('${messageStart}Pruning no longer followed contacts');
|
2024-12-07 02:33:51 +00:00
|
|
|
for (final noLongerFollowed in originalContacts) {
|
2024-12-24 20:54:30 +00:00
|
|
|
final nf = noLongerFollowed.copy(status: ConnectionStatus.none);
|
2024-12-07 02:33:51 +00:00
|
|
|
ref
|
2024-12-24 20:54:30 +00:00
|
|
|
.read(connectionModifierProvider(profile, nf).notifier)
|
|
|
|
.upsertConnection(nf);
|
2024-12-07 02:33:51 +00:00
|
|
|
}
|
|
|
|
await ref
|
|
|
|
.read(persistentInfoProvider(profile).notifier)
|
|
|
|
.updateLastMyConnectionUpdate(DateTime.now());
|
|
|
|
final contactsLength =
|
|
|
|
(ref.read(myContactsProvider(profile)).valueOrNull ?? []).length;
|
|
|
|
_acuLogger.info('Done updating # Contacts:$contactsLength');
|
|
|
|
} catch (e) {
|
2024-12-19 21:24:37 +00:00
|
|
|
_acuLogger.severe(
|
|
|
|
'Exception thrown trying to update contacts: $e',
|
|
|
|
Trace.current(),
|
|
|
|
);
|
2024-12-07 02:33:51 +00:00
|
|
|
}
|
|
|
|
await ref
|
|
|
|
.read(persistentInfoProvider(profile).notifier)
|
|
|
|
.updateLastMyConnectionUpdate(originalTime);
|
|
|
|
state = false;
|
|
|
|
}
|
|
|
|
}
|
2024-12-24 17:21:44 +00:00
|
|
|
|
|
|
|
@riverpod
|
|
|
|
Future<Result<List<Connection>, ExecError>> suggestedConnections(
|
|
|
|
Ref ref, Profile profile) async {
|
|
|
|
final result =
|
|
|
|
await ref.watch(suggestedConnectionsClientProvider(profile).future);
|
|
|
|
|
|
|
|
await result.withResultAsync((suggestions) async {
|
|
|
|
for (final s in suggestions) {
|
|
|
|
await ref
|
|
|
|
.read(connectionModifierProvider(profile, s).notifier)
|
|
|
|
.upsertConnection(s);
|
|
|
|
}
|
|
|
|
});
|
|
|
|
|
|
|
|
return result;
|
|
|
|
}
|