kopia lustrzana https://gitlab.com/mysocialportal/relatica
Initial Blocks and Filters screen with initial cut at BlocksService.getBlocks
rodzic
1f37533ec2
commit
8979012034
|
@ -74,6 +74,11 @@ class StandardAppDrawer extends StatelessWidget {
|
||||||
() => context.pushNamed(ScreenPaths.messages),
|
() => context.pushNamed(ScreenPaths.messages),
|
||||||
),
|
),
|
||||||
const Divider(),
|
const Divider(),
|
||||||
|
buildMenuButton(
|
||||||
|
context,
|
||||||
|
'Blocks & Filters',
|
||||||
|
() => context.pushNamed(ScreenPaths.blocksAndFilters),
|
||||||
|
),
|
||||||
buildMenuButton(
|
buildMenuButton(
|
||||||
context,
|
context,
|
||||||
'Groups Management',
|
'Groups Management',
|
||||||
|
|
|
@ -16,6 +16,7 @@ import 'globals.dart';
|
||||||
import 'models/auth/profile.dart';
|
import 'models/auth/profile.dart';
|
||||||
import 'models/instance_info.dart';
|
import 'models/instance_info.dart';
|
||||||
import 'services/auth_service.dart';
|
import 'services/auth_service.dart';
|
||||||
|
import 'services/blocks_service.dart';
|
||||||
import 'services/connections_manager.dart';
|
import 'services/connections_manager.dart';
|
||||||
import 'services/direct_message_service.dart';
|
import 'services/direct_message_service.dart';
|
||||||
import 'services/entry_manager_service.dart';
|
import 'services/entry_manager_service.dart';
|
||||||
|
@ -120,7 +121,9 @@ Future<void> dependencyInjectionInitialization() async {
|
||||||
getIt.registerSingleton<ActiveProfileSelector<InteractionsManager>>(
|
getIt.registerSingleton<ActiveProfileSelector<InteractionsManager>>(
|
||||||
ActiveProfileSelector((p) => InteractionsManager(p))
|
ActiveProfileSelector((p) => InteractionsManager(p))
|
||||||
..subscribeToProfileSwaps());
|
..subscribeToProfileSwaps());
|
||||||
|
getIt.registerSingleton<ActiveProfileSelector<BlocksService>>(
|
||||||
|
ActiveProfileSelector((p) => BlocksService(p))
|
||||||
|
..subscribeToProfileSwaps());
|
||||||
setupUpdateTimers();
|
setupUpdateTimers();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -44,6 +44,36 @@ import 'paging_data.dart';
|
||||||
const _maxProcessingMillis = 3;
|
const _maxProcessingMillis = 3;
|
||||||
const _processingSleep = Duration(milliseconds: 1);
|
const _processingSleep = Duration(milliseconds: 1);
|
||||||
|
|
||||||
|
class BlocksClient extends FriendicaClient {
|
||||||
|
static final _logger = Logger('$DirectMessagingClient');
|
||||||
|
|
||||||
|
BlocksClient(super.credentials) : super();
|
||||||
|
|
||||||
|
FutureResult<PagedResponse<List<Connection>>, ExecError> getBlocks(
|
||||||
|
PagingData page) async {
|
||||||
|
_networkStatusService.startNotificationUpdate();
|
||||||
|
final url = 'https://$serverName/api/v1/blocks';
|
||||||
|
final request = Uri.parse('$url&${page.toQueryParameters()}');
|
||||||
|
_logger.finest(() => 'Getting blocks for $page');
|
||||||
|
final result =
|
||||||
|
await _getApiListRequest(request).transformAsync((response) async {
|
||||||
|
final blocks = <Connection>[];
|
||||||
|
|
||||||
|
final st = Stopwatch()..start();
|
||||||
|
for (final json in response.data) {
|
||||||
|
if (st.elapsedMilliseconds > _maxProcessingMillis) {
|
||||||
|
await Future.delayed(_processingSleep, () => st.reset());
|
||||||
|
}
|
||||||
|
blocks.add(ConnectionMastodonExtensions.fromJson(json));
|
||||||
|
}
|
||||||
|
return PagedResponse(blocks,
|
||||||
|
id: response.id, previous: response.previous, next: response.next);
|
||||||
|
});
|
||||||
|
_networkStatusService.finishNotificationUpdate();
|
||||||
|
return result.execErrorCast();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
class DirectMessagingClient extends FriendicaClient {
|
class DirectMessagingClient extends FriendicaClient {
|
||||||
static final _logger = Logger('$DirectMessagingClient');
|
static final _logger = Logger('$DirectMessagingClient');
|
||||||
|
|
||||||
|
|
|
@ -11,6 +11,7 @@ import 'di_initialization.dart';
|
||||||
import 'globals.dart';
|
import 'globals.dart';
|
||||||
import 'routes.dart';
|
import 'routes.dart';
|
||||||
import 'services/auth_service.dart';
|
import 'services/auth_service.dart';
|
||||||
|
import 'services/blocks_service.dart';
|
||||||
import 'services/connections_manager.dart';
|
import 'services/connections_manager.dart';
|
||||||
import 'services/direct_message_service.dart';
|
import 'services/direct_message_service.dart';
|
||||||
import 'services/entry_manager_service.dart';
|
import 'services/entry_manager_service.dart';
|
||||||
|
@ -108,7 +109,10 @@ class App extends StatelessWidget {
|
||||||
ActiveProfileSelector<InteractionsManager>>(
|
ActiveProfileSelector<InteractionsManager>>(
|
||||||
create: (_) =>
|
create: (_) =>
|
||||||
getIt<ActiveProfileSelector<InteractionsManager>>(),
|
getIt<ActiveProfileSelector<InteractionsManager>>(),
|
||||||
)
|
),
|
||||||
|
ChangeNotifierProvider<ActiveProfileSelector<BlocksService>>(
|
||||||
|
create: (_) => getIt<ActiveProfileSelector<BlocksService>>(),
|
||||||
|
),
|
||||||
],
|
],
|
||||||
child: MaterialApp.router(
|
child: MaterialApp.router(
|
||||||
useInheritedMediaQuery: true,
|
useInheritedMediaQuery: true,
|
||||||
|
|
|
@ -2,6 +2,7 @@ import 'package:go_router/go_router.dart';
|
||||||
|
|
||||||
import 'globals.dart';
|
import 'globals.dart';
|
||||||
import 'models/interaction_type_enum.dart';
|
import 'models/interaction_type_enum.dart';
|
||||||
|
import 'screens/blocks_and_filters_screen.dart';
|
||||||
import 'screens/contacts_screen.dart';
|
import 'screens/contacts_screen.dart';
|
||||||
import 'screens/editor.dart';
|
import 'screens/editor.dart';
|
||||||
import 'screens/follow_request_adjudication_screen.dart';
|
import 'screens/follow_request_adjudication_screen.dart';
|
||||||
|
@ -28,6 +29,7 @@ import 'screens/user_profile_screen.dart';
|
||||||
import 'services/auth_service.dart';
|
import 'services/auth_service.dart';
|
||||||
|
|
||||||
class ScreenPaths {
|
class ScreenPaths {
|
||||||
|
static String blocksAndFilters = '/blocksAndFilters';
|
||||||
static String thread = '/thread';
|
static String thread = '/thread';
|
||||||
static String connectHandle = '/connect';
|
static String connectHandle = '/connect';
|
||||||
static String contacts = '/contacts';
|
static String contacts = '/contacts';
|
||||||
|
@ -73,6 +75,11 @@ final appRouter = GoRouter(
|
||||||
return null;
|
return null;
|
||||||
},
|
},
|
||||||
routes: [
|
routes: [
|
||||||
|
GoRoute(
|
||||||
|
path: ScreenPaths.blocksAndFilters,
|
||||||
|
name: ScreenPaths.blocksAndFilters,
|
||||||
|
builder: (context, state) => const BlocksAndFiltersScreen(),
|
||||||
|
),
|
||||||
GoRoute(
|
GoRoute(
|
||||||
path: ScreenPaths.signin,
|
path: ScreenPaths.signin,
|
||||||
name: ScreenPaths.signin,
|
name: ScreenPaths.signin,
|
||||||
|
|
|
@ -0,0 +1,64 @@
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:go_router/go_router.dart';
|
||||||
|
import 'package:provider/provider.dart';
|
||||||
|
|
||||||
|
import '../controls/padding.dart';
|
||||||
|
import '../routes.dart';
|
||||||
|
import '../services/blocks_service.dart';
|
||||||
|
import '../utils/active_profile_selector.dart';
|
||||||
|
import '../utils/snackbar_builder.dart';
|
||||||
|
|
||||||
|
class BlocksAndFiltersScreen extends StatelessWidget {
|
||||||
|
const BlocksAndFiltersScreen({super.key});
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
final blocks = context
|
||||||
|
.watch<ActiveProfileSelector<BlocksService>>()
|
||||||
|
.activeEntry
|
||||||
|
.transform((s) => s.getBlocks())
|
||||||
|
.withError(
|
||||||
|
(error) => buildSnackbar(context, 'Error getting blocks: $error'),
|
||||||
|
)
|
||||||
|
.getValueOrElse(() => []);
|
||||||
|
return Scaffold(
|
||||||
|
appBar: AppBar(
|
||||||
|
title: const Text('Blocks & Filters'),
|
||||||
|
),
|
||||||
|
body: SafeArea(
|
||||||
|
child: Column(
|
||||||
|
children: [
|
||||||
|
const Text('Blocks'),
|
||||||
|
const VerticalPadding(),
|
||||||
|
Expanded(
|
||||||
|
child: ListView.builder(
|
||||||
|
itemBuilder: (context, index) {
|
||||||
|
final contact = blocks[index];
|
||||||
|
return ListTile(
|
||||||
|
onTap: () async {
|
||||||
|
context.pushNamed(ScreenPaths.userProfile,
|
||||||
|
params: {'id': contact.id});
|
||||||
|
},
|
||||||
|
title: Text(
|
||||||
|
'${contact.name} (${contact.handle})',
|
||||||
|
softWrap: true,
|
||||||
|
),
|
||||||
|
subtitle: Text(
|
||||||
|
'Last Status: ${contact.lastStatus?.toIso8601String() ?? "Unknown"}',
|
||||||
|
softWrap: true,
|
||||||
|
),
|
||||||
|
trailing: ElevatedButton(
|
||||||
|
onPressed: () {},
|
||||||
|
child: const Text('Unblock'),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
},
|
||||||
|
itemCount: blocks.length,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,82 @@
|
||||||
|
import 'dart:collection';
|
||||||
|
|
||||||
|
import 'package:flutter/foundation.dart';
|
||||||
|
import 'package:logging/logging.dart';
|
||||||
|
import 'package:result_monad/result_monad.dart';
|
||||||
|
|
||||||
|
import '../friendica_client/friendica_client.dart';
|
||||||
|
import '../friendica_client/paged_response.dart';
|
||||||
|
import '../friendica_client/paging_data.dart';
|
||||||
|
import '../globals.dart';
|
||||||
|
import '../models/auth/profile.dart';
|
||||||
|
import '../models/connection.dart';
|
||||||
|
import '../utils/active_profile_selector.dart';
|
||||||
|
import 'connections_manager.dart';
|
||||||
|
|
||||||
|
class BlocksService extends ChangeNotifier {
|
||||||
|
static final _logger = Logger('$BlocksService');
|
||||||
|
final Profile profile;
|
||||||
|
final _blocks = <Connection>[];
|
||||||
|
final _pages = <PagedResponse>[];
|
||||||
|
|
||||||
|
var mayHaveMore = true;
|
||||||
|
var initialized = false;
|
||||||
|
|
||||||
|
BlocksService(this.profile);
|
||||||
|
|
||||||
|
void clear() {
|
||||||
|
_blocks.clear();
|
||||||
|
_pages.clear();
|
||||||
|
mayHaveMore = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
List<Connection> getBlocks() {
|
||||||
|
if (!initialized) {
|
||||||
|
updateBlocks(nextOnly: false);
|
||||||
|
}
|
||||||
|
|
||||||
|
return UnmodifiableListView(_blocks);
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<void> updateBlocks({required bool nextOnly}) async {
|
||||||
|
if (nextOnly) {
|
||||||
|
clear();
|
||||||
|
}
|
||||||
|
final client = BlocksClient(profile);
|
||||||
|
final bootstrapping = _pages.isEmpty;
|
||||||
|
|
||||||
|
var page = bootstrapping ? PagingData() : _pages.last.next;
|
||||||
|
|
||||||
|
while (page != null) {
|
||||||
|
page = await client
|
||||||
|
.getBlocks(page)
|
||||||
|
.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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
getIt<ActiveProfileSelector<ConnectionsManager>>()
|
||||||
|
.getForProfile(profile)
|
||||||
|
.withResult((cm) => cm.upsertAllConnections(_blocks));
|
||||||
|
|
||||||
|
_blocks.sort(
|
||||||
|
(b1, b2) => b1.name.toLowerCase().compareTo(
|
||||||
|
b2.name.toLowerCase(),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
|
||||||
|
notifyListeners();
|
||||||
|
}
|
||||||
|
}
|
Ładowanie…
Reference in New Issue