relatica/lib/riverpod_controllers/blocks_services.dart

175 wiersze
5.1 KiB
Dart

import 'package:logging/logging.dart';
import 'package:result_monad/result_monad.dart';
import 'package:riverpod_annotation/riverpod_annotation.dart';
import 'package:stack_trace/stack_trace.dart';
import '../models/auth/profile.dart';
import '../models/connection.dart';
import '../models/exec_error.dart';
import '../models/networking/paged_response.dart';
import '../models/networking/paging_data.dart';
import 'connection_manager_services.dart';
import 'networking/friendica_relationship_client_services.dart';
part 'blocks_services.g.dart';
final _logger = Logger('BlocksManager');
@Riverpod(keepAlive: true)
class BlocksManager extends _$BlocksManager {
final _pages = <PagedResponse>[];
@override
Future<List<Connection>> build(Profile profile) async {
final result = await updateBlocks(withUpdate: false);
return result;
}
FutureResult<Connection, ExecError> blockConnection(
Connection connection) async {
_logger
.fine('Attempting to block ${connection.name}: ${connection.status}');
final blocks = List<Connection>.from(state.value ?? []);
final result = await ref
.read(blockConnectionProvider(profile, connection).future)
.withResultAsync((blockedUser) async {
await ref
.read(connectionModifierProvider(profile, blockedUser).notifier)
.upsertConnection(blockedUser);
});
result.match(
onSuccess: (blockedUser) {
_logger.fine(
'Successfully blocked ${blockedUser.name}: ${blockedUser.status}');
final existingIndex = blocks.indexOf(connection);
if (existingIndex < 0) {
blocks.add(blockedUser);
_sortBlocks(blocks);
} else {
blocks.removeAt(existingIndex);
blocks.insert(existingIndex, blockedUser);
}
},
onError: (error) {
_logger.severe(
'Error blocking ${connection.name}: $error', Trace.current());
},
);
state = AsyncData(blocks);
return result.execErrorCast();
}
FutureResult<Connection, ExecError> unblockConnection(
Connection connection) async {
_logger
.fine('Attempting to unblock ${connection.name}: ${connection.status}');
final blocks = List<Connection>.from(state.value ?? []);
final result = await ref
.read(unblockConnectionProvider(profile, connection).future)
.withResultAsync((unblocked) async {
await ref
.read(connectionModifierProvider(profile, unblocked).notifier)
.upsertConnection(unblocked);
});
result.match(
onSuccess: (unblockedUser) {
_logger.fine(
'Successfully unblocked ${unblockedUser.name}: ${unblockedUser.status}');
final existingIndex = blocks.indexOf(connection);
if (existingIndex >= 0) {
blocks.removeAt(existingIndex);
_sortBlocks(blocks);
}
},
onError: (error) {
_logger.severe('Error unblocking ${connection.name}: $error');
},
);
state = AsyncData(blocks);
return result.execErrorCast();
}
Future<void> updateBlock(Connection connection) async {
final blocks = List<Connection>.from(state.value ?? []);
final id = int.parse(connection.id);
final page = PagingData(minId: id - 1, maxId: id + 1);
await ref
.read(blocksClientProvider(profile, page).future)
.withResultAsync((returnedBlocks) async {
final conBlock =
returnedBlocks.data.where((b) => b.id == connection.id).toList();
if (conBlock.isEmpty) {
blocks.remove(connection);
await ref
.read(connectionModifierProvider(profile, connection).notifier)
.refreshConnection(true);
} else {
blocks.add(conBlock.first);
await ref
.read(connectionModifierProvider(profile, conBlock.first).notifier)
.upsertConnection(conBlock.first);
}
});
state = AsyncData(blocks);
}
Future<List<Connection>> updateBlocks({
bool nextOnly = false,
bool withUpdate = true,
}) async {
final blocks = state.value ?? [];
if (!nextOnly) {
blocks.clear();
_pages.clear();
}
final bootstrapping = _pages.isEmpty;
var page = bootstrapping ? PagingData() : _pages.last.next;
while (page != null) {
page = await ref
.read(blocksClientProvider(profile, page).future)
.withResult((result) {
blocks.addAll(result.data);
_pages.add(result);
})
.withError(
(error) => _logger.severe('Error getting blocks data: $error'),
)
.fold<PagingData?>(
onSuccess: (result) => result.next,
onError: (error) => null,
);
if (nextOnly) {
break;
}
}
for (final b in blocks) {
await ref
.read(connectionModifierProvider(profile, b).notifier)
.upsertConnection(b);
}
_sortBlocks(blocks);
if (withUpdate) {
state = AsyncData(blocks);
}
return blocks;
}
}
void _sortBlocks(List<Connection> blocks) {
blocks.sort(
(b1, b2) => b1.name.toLowerCase().compareTo(
b2.name.toLowerCase(),
),
);
}