Compare commits
2 Commits
4b1942b949
...
76a03cc2fa
Author | SHA1 | Date | |
---|---|---|---|
76a03cc2fa | |||
3774760548 |
@ -106,6 +106,13 @@ files:
|
||||
extends: BackgroundEvent
|
||||
implements:
|
||||
- JsonImplementation
|
||||
# Triggered in response to a [GetBlocklistCommand]
|
||||
- name: GetBlocklistResultEvent
|
||||
extends: BackgroundEvent
|
||||
implements:
|
||||
- JsonImplementation
|
||||
attributes:
|
||||
entries: List<String>
|
||||
# Triggered by DownloadService or UploadService.
|
||||
- name: ProgressEvent
|
||||
extends: BackgroundEvent
|
||||
@ -527,6 +534,11 @@ files:
|
||||
stickerPack:
|
||||
type: StickerPack
|
||||
deserialise: true
|
||||
- name: GetBlocklistCommand
|
||||
extends: BackgroundCommand
|
||||
implements:
|
||||
- JsonImplementation
|
||||
attributes:
|
||||
generate_builder: true
|
||||
# get${builder_Name}FromJson
|
||||
builder_name: "Command"
|
||||
|
@ -1,5 +1,8 @@
|
||||
import 'dart:async';
|
||||
import 'package:get_it/get_it.dart';
|
||||
import 'package:logging/logging.dart';
|
||||
import 'package:moxxmpp/moxxmpp.dart';
|
||||
import 'package:moxxyv2/service/database/database.dart';
|
||||
import 'package:moxxyv2/service/service.dart';
|
||||
import 'package:moxxyv2/shared/events.dart';
|
||||
|
||||
@ -9,35 +12,93 @@ enum BlockPushType {
|
||||
}
|
||||
|
||||
class BlocklistService {
|
||||
BlocklistService();
|
||||
List<String>? _blocklist;
|
||||
bool _requested = false;
|
||||
bool? _supported;
|
||||
final Logger _log = Logger('BlocklistService');
|
||||
|
||||
BlocklistService() :
|
||||
_blocklistCache = List.empty(growable: true),
|
||||
_requestedBlocklist = false;
|
||||
final List<String> _blocklistCache;
|
||||
bool _requestedBlocklist;
|
||||
void onNewConnection() {
|
||||
// Invalidate the caches
|
||||
_blocklist = null;
|
||||
_requested = false;
|
||||
_supported = null;
|
||||
}
|
||||
|
||||
Future<List<String>> _requestBlocklist() async {
|
||||
final manager = GetIt.I.get<XmppConnection>().getManagerById<BlockingManager>(blockingManager)!;
|
||||
_blocklistCache
|
||||
..clear()
|
||||
..addAll(await manager.getBlocklist());
|
||||
_requestedBlocklist = true;
|
||||
return _blocklistCache;
|
||||
Future<bool> _checkSupport() async {
|
||||
return _supported ??= await GetIt.I.get<XmppConnection>()
|
||||
.getManagerById<BlockingManager>(blockingManager)!
|
||||
.isSupported();
|
||||
}
|
||||
|
||||
Future<void> _requestBlocklist() async {
|
||||
assert(_blocklist != null, 'The blocklist must be loaded from the database before requesting');
|
||||
|
||||
// Check if blocking is supported
|
||||
if (!(await _checkSupport())) {
|
||||
_log.warning('Blocklist requested but server does not support it.');
|
||||
return;
|
||||
}
|
||||
|
||||
final blocklist = await GetIt.I.get<XmppConnection>()
|
||||
.getManagerById<BlockingManager>(blockingManager)!
|
||||
.getBlocklist();
|
||||
|
||||
// Diff the received blocklist with the cache
|
||||
final newItems = List<String>.empty(growable: true);
|
||||
final removedItems = List<String>.empty(growable: true);
|
||||
final db = GetIt.I.get<DatabaseService>();
|
||||
for (final item in blocklist) {
|
||||
if (!_blocklist!.contains(item)) {
|
||||
await db.addBlocklistEntry(item);
|
||||
_blocklist!.add(item);
|
||||
newItems.add(item);
|
||||
}
|
||||
}
|
||||
|
||||
// Diff the cache with the received blocklist
|
||||
for (final item in _blocklist!) {
|
||||
if (!blocklist.contains(item)) {
|
||||
await db.removeBlocklistEntry(item);
|
||||
_blocklist!.remove(item);
|
||||
removedItems.add(item);
|
||||
}
|
||||
}
|
||||
|
||||
_requested = true;
|
||||
|
||||
// Trigger an UI event if we have anything to tell the UI
|
||||
if (newItems.isNotEmpty || removedItems.isNotEmpty) {
|
||||
sendEvent(
|
||||
BlocklistPushEvent(
|
||||
added: newItems,
|
||||
removed: removedItems,
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns the blocklist from the database
|
||||
Future<List<String>> getBlocklist() async {
|
||||
if (!_requestedBlocklist) {
|
||||
_blocklistCache
|
||||
..clear()
|
||||
..addAll(await _requestBlocklist());
|
||||
if (_blocklist == null) {
|
||||
_blocklist = await GetIt.I.get<DatabaseService>().getBlocklistEntries();
|
||||
|
||||
if (!_requested) {
|
||||
unawaited(_requestBlocklist());
|
||||
}
|
||||
|
||||
return _blocklist!;
|
||||
}
|
||||
|
||||
return _blocklistCache;
|
||||
if (!_requested) {
|
||||
unawaited(_requestBlocklist());
|
||||
}
|
||||
|
||||
return _blocklist!;
|
||||
}
|
||||
|
||||
void onUnblockAllPush() {
|
||||
_blocklistCache.clear();
|
||||
_blocklist = List<String>.empty(growable: true);
|
||||
sendEvent(
|
||||
BlocklistUnblockAllEvent(),
|
||||
);
|
||||
@ -45,21 +106,25 @@ class BlocklistService {
|
||||
|
||||
Future<void> onBlocklistPush(BlockPushType type, List<String> items) async {
|
||||
// We will fetch it later when getBlocklist is called
|
||||
if (!_requestedBlocklist) return;
|
||||
if (!_requested) return;
|
||||
|
||||
final newBlocks = List<String>.empty(growable: true);
|
||||
final removedBlocks = List<String>.empty(growable: true);
|
||||
for (final item in items) {
|
||||
switch (type) {
|
||||
case BlockPushType.block: {
|
||||
if (_blocklistCache.contains(item)) continue;
|
||||
_blocklistCache.add(item);
|
||||
if (_blocklist!.contains(item)) continue;
|
||||
_blocklist!.add(item);
|
||||
newBlocks.add(item);
|
||||
|
||||
await GetIt.I.get<DatabaseService>().addBlocklistEntry(item);
|
||||
}
|
||||
break;
|
||||
case BlockPushType.unblock: {
|
||||
_blocklistCache.removeWhere((i) => i == item);
|
||||
_blocklist!.removeWhere((i) => i == item);
|
||||
removedBlocks.add(item);
|
||||
|
||||
await GetIt.I.get<DatabaseService>().removeBlocklistEntry(item);
|
||||
}
|
||||
break;
|
||||
}
|
||||
@ -74,17 +139,47 @@ class BlocklistService {
|
||||
}
|
||||
|
||||
Future<bool> blockJid(String jid) async {
|
||||
final manager = GetIt.I.get<XmppConnection>().getManagerById<BlockingManager>(blockingManager)!;
|
||||
return manager.block([ jid ]);
|
||||
// Check if blocking is supported
|
||||
if (!(await _checkSupport())) {
|
||||
_log.warning('Blocking $jid requested but server does not support it.');
|
||||
return false;
|
||||
}
|
||||
|
||||
_blocklist!.add(jid);
|
||||
await GetIt.I.get<DatabaseService>()
|
||||
.addBlocklistEntry(jid);
|
||||
return GetIt.I.get<XmppConnection>()
|
||||
.getManagerById<BlockingManager>(blockingManager)!
|
||||
.block([jid]);
|
||||
}
|
||||
|
||||
Future<bool> unblockJid(String jid) async {
|
||||
final manager = GetIt.I.get<XmppConnection>().getManagerById<BlockingManager>(blockingManager)!;
|
||||
return manager.unblock([ jid ]);
|
||||
// Check if blocking is supported
|
||||
if (!(await _checkSupport())) {
|
||||
_log.warning('Unblocking $jid requested but server does not support it.');
|
||||
return false;
|
||||
}
|
||||
|
||||
_blocklist!.remove(jid);
|
||||
await GetIt.I.get<DatabaseService>()
|
||||
.removeBlocklistEntry(jid);
|
||||
return GetIt.I.get<XmppConnection>()
|
||||
.getManagerById<BlockingManager>(blockingManager)!
|
||||
.unblock([jid]);
|
||||
}
|
||||
|
||||
Future<bool> unblockAll() async {
|
||||
final manager = GetIt.I.get<XmppConnection>().getManagerById<BlockingManager>(blockingManager)!;
|
||||
return manager.unblockAll();
|
||||
// Check if blocking is supported
|
||||
if (!(await _checkSupport())) {
|
||||
_log.warning('Unblocking all JIDs requested but server does not support it.');
|
||||
return false;
|
||||
}
|
||||
|
||||
_blocklist!.clear();
|
||||
await GetIt.I.get<DatabaseService>()
|
||||
.removeAllBlocklistEntries();
|
||||
return GetIt.I.get<XmppConnection>()
|
||||
.getManagerById<BlockingManager>(blockingManager)!
|
||||
.unblockAll();
|
||||
}
|
||||
}
|
||||
|
@ -14,6 +14,7 @@ const xmppStateTable = 'XmppState';
|
||||
const contactsTable = 'Contacts';
|
||||
const stickersTable = 'Stickers';
|
||||
const stickerPacksTable = 'StickerPacks';
|
||||
const blocklistTable = 'Blocklist';
|
||||
|
||||
const typeString = 0;
|
||||
const typeInt = 1;
|
||||
|
@ -159,6 +159,15 @@ Future<void> createDatabase(Database db, int version) async {
|
||||
)''',
|
||||
);
|
||||
|
||||
// Blocklist
|
||||
await db.execute(
|
||||
'''
|
||||
CREATE TABLE $blocklistTable (
|
||||
jid TEXT PRIMARY KEY
|
||||
);
|
||||
''',
|
||||
);
|
||||
|
||||
// OMEMO
|
||||
await db.execute(
|
||||
'''
|
||||
|
@ -8,6 +8,7 @@ import 'package:moxxmpp/moxxmpp.dart';
|
||||
import 'package:moxxyv2/service/database/constants.dart';
|
||||
import 'package:moxxyv2/service/database/creation.dart';
|
||||
import 'package:moxxyv2/service/database/helpers.dart';
|
||||
import 'package:moxxyv2/service/database/migrations/0000_blocklist.dart';
|
||||
import 'package:moxxyv2/service/database/migrations/0000_contacts_integration.dart';
|
||||
import 'package:moxxyv2/service/database/migrations/0000_contacts_integration_avatar.dart';
|
||||
import 'package:moxxyv2/service/database/migrations/0000_contacts_integration_pseudo.dart';
|
||||
@ -79,7 +80,7 @@ class DatabaseService {
|
||||
_db = await openDatabase(
|
||||
dbPath,
|
||||
password: key,
|
||||
version: 22,
|
||||
version: 23,
|
||||
onCreate: createDatabase,
|
||||
onConfigure: (db) async {
|
||||
// In order to do schema changes during database upgrades, we disable foreign
|
||||
@ -176,6 +177,10 @@ class DatabaseService {
|
||||
_log.finest('Running migration for database version 22');
|
||||
await upgradeFromV21ToV22(db);
|
||||
}
|
||||
if (oldVersion < 23) {
|
||||
_log.finest('Running migration for database version 23');
|
||||
await upgradeFromV22ToV23(db);
|
||||
}
|
||||
},
|
||||
);
|
||||
|
||||
@ -1257,4 +1262,35 @@ class DatabaseService {
|
||||
.toList(),
|
||||
);
|
||||
}
|
||||
|
||||
Future<void> addBlocklistEntry(String jid) async {
|
||||
await _db.insert(
|
||||
blocklistTable,
|
||||
{
|
||||
'jid': jid,
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
Future<void> removeBlocklistEntry(String jid) async {
|
||||
await _db.delete(
|
||||
blocklistTable,
|
||||
where: 'jid = ?',
|
||||
whereArgs: [jid],
|
||||
);
|
||||
}
|
||||
|
||||
Future<void> removeAllBlocklistEntries() async {
|
||||
await _db.delete(
|
||||
blocklistTable,
|
||||
);
|
||||
}
|
||||
|
||||
Future<List<String>> getBlocklistEntries() async {
|
||||
final result = await _db.query(blocklistTable);
|
||||
|
||||
return result
|
||||
.map((m) => m['jid']! as String)
|
||||
.toList();
|
||||
}
|
||||
}
|
||||
|
13
lib/service/database/migrations/0000_blocklist.dart
Normal file
13
lib/service/database/migrations/0000_blocklist.dart
Normal file
@ -0,0 +1,13 @@
|
||||
import 'package:moxxyv2/service/database/constants.dart';
|
||||
import 'package:moxxyv2/shared/models/preference.dart';
|
||||
import 'package:sqflite_sqlcipher/sqflite.dart';
|
||||
|
||||
Future<void> upgradeFromV22ToV23(Database db) async {
|
||||
await db.execute(
|
||||
'''
|
||||
CREATE TABLE $blocklistTable (
|
||||
jid TEXT PRIMARY KEY
|
||||
);
|
||||
''',
|
||||
);
|
||||
}
|
@ -79,6 +79,7 @@ void setupBackgroundEventHandler() {
|
||||
EventTypeMatcher<RemoveStickerPackCommand>(performRemoveStickerPack),
|
||||
EventTypeMatcher<FetchStickerPackCommand>(performFetchStickerPack),
|
||||
EventTypeMatcher<InstallStickerPackCommand>(performStickerPackInstall),
|
||||
EventTypeMatcher<GetBlocklistCommand>(performGetBlocklist),
|
||||
]);
|
||||
|
||||
GetIt.I.registerSingleton<EventHandler>(handler);
|
||||
@ -890,3 +891,15 @@ Future<void> performStickerPackInstall(InstallStickerPackCommand command, { dyna
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> performGetBlocklist(GetBlocklistCommand command, { dynamic extra }) async {
|
||||
final id = extra as String;
|
||||
|
||||
final result = await GetIt.I.get<BlocklistService>().getBlocklist();
|
||||
sendEvent(
|
||||
GetBlocklistResultEvent(
|
||||
entries: result,
|
||||
),
|
||||
id: id,
|
||||
);
|
||||
}
|
||||
|
@ -361,7 +361,7 @@ class HttpFileTransferService {
|
||||
// Prepare file and completer.
|
||||
final file = await File(downloadedPath).create();
|
||||
final fileSink = file.openWrite(mode: FileMode.writeOnlyAppend);
|
||||
final downloadCompleter = Completer();
|
||||
final downloadCompleter = Completer<void>();
|
||||
|
||||
dio.Response<dio.ResponseBody>? response;
|
||||
|
||||
|
@ -665,6 +665,9 @@ class XmppService {
|
||||
unawaited(_initializeOmemoService(settings.jid.toString()));
|
||||
|
||||
if (!event.resumed) {
|
||||
// Reset the blocking service's cache
|
||||
GetIt.I.get<BlocklistService>().onNewConnection();
|
||||
|
||||
// Enable carbons
|
||||
final carbonsResult = await connection
|
||||
.getManagerById<CarbonsManager>(carbonsManager)!
|
||||
|
@ -1,7 +1,11 @@
|
||||
import 'package:bloc/bloc.dart';
|
||||
import 'package:freezed_annotation/freezed_annotation.dart';
|
||||
import 'package:get_it/get_it.dart';
|
||||
import 'package:moxplatform/moxplatform.dart';
|
||||
import 'package:moxxyv2/shared/commands.dart';
|
||||
import 'package:moxxyv2/shared/events.dart';
|
||||
import 'package:moxxyv2/ui/bloc/navigation_bloc.dart';
|
||||
import 'package:moxxyv2/ui/constants.dart';
|
||||
|
||||
part 'blocklist_bloc.freezed.dart';
|
||||
part 'blocklist_event.dart';
|
||||
@ -9,11 +13,44 @@ part 'blocklist_state.dart';
|
||||
|
||||
class BlocklistBloc extends Bloc<BlocklistEvent, BlocklistState> {
|
||||
BlocklistBloc() : super(BlocklistState()) {
|
||||
on<BlocklistRequestedEvent>(_onBlocklistRequested);
|
||||
on<UnblockedJidEvent>(_onJidUnblocked);
|
||||
on<UnblockedAllEvent>(_onUnblockedAll);
|
||||
on<BlocklistPushedEvent>(_onBlocklistPushed);
|
||||
}
|
||||
|
||||
Future<void> _onBlocklistRequested(BlocklistRequestedEvent event, Emitter<BlocklistState> emit) async {
|
||||
final mustDoWork = state.blocklist.isEmpty;
|
||||
|
||||
if (mustDoWork) {
|
||||
emit(
|
||||
state.copyWith(
|
||||
isWorking: true,
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
GetIt.I.get<NavigationBloc>().add(
|
||||
PushedNamedEvent(
|
||||
const NavigationDestination(blocklistRoute),
|
||||
),
|
||||
);
|
||||
|
||||
if (state.blocklist.isEmpty) {
|
||||
// ignore: cast_nullable_to_non_nullable
|
||||
final result = await MoxplatformPlugin.handler.getDataSender().sendData(
|
||||
GetBlocklistCommand(),
|
||||
) as GetBlocklistResultEvent;
|
||||
|
||||
emit(
|
||||
state.copyWith(
|
||||
blocklist: result.entries,
|
||||
isWorking: false,
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> _onJidUnblocked(UnblockedJidEvent event, Emitter<BlocklistState> emit) async {
|
||||
await MoxplatformPlugin.handler.getDataSender().sendData(
|
||||
UnblockJidCommand(
|
||||
|
@ -2,9 +2,11 @@ part of 'blocklist_bloc.dart';
|
||||
|
||||
abstract class BlocklistEvent {}
|
||||
|
||||
/// Triggered when the blocklist page has been requested
|
||||
class BlocklistRequestedEvent extends BlocklistEvent {}
|
||||
|
||||
/// Triggered when a JID is unblocked
|
||||
class UnblockedJidEvent extends BlocklistEvent {
|
||||
|
||||
UnblockedJidEvent(this.jid);
|
||||
final String jid;
|
||||
}
|
||||
@ -16,7 +18,6 @@ class UnblockedAllEvent extends BlocklistEvent {
|
||||
|
||||
/// Triggered when we receive a blocklist push
|
||||
class BlocklistPushedEvent extends BlocklistEvent {
|
||||
|
||||
BlocklistPushedEvent(this.added, this.removed);
|
||||
final List<String> added;
|
||||
final List<String> removed;
|
||||
|
@ -4,5 +4,6 @@ part of 'blocklist_bloc.dart';
|
||||
class BlocklistState with _$BlocklistState {
|
||||
factory BlocklistState({
|
||||
@Default(<String>[]) List<String> blocklist,
|
||||
@Default(false) bool isWorking,
|
||||
}) = _BlocklistState;
|
||||
}
|
||||
|
@ -23,59 +23,74 @@ class BlocklistPage extends StatelessWidget {
|
||||
Widget _buildListView(BlocklistState state) {
|
||||
// ignore: non_bool_condition,avoid_dynamic_calls
|
||||
if (state.blocklist.isEmpty) {
|
||||
return Padding(
|
||||
padding: const EdgeInsets.symmetric(horizontal: paddingVeryLarge),
|
||||
child: Column(
|
||||
children: [
|
||||
Padding(
|
||||
padding: const EdgeInsets.only(top: 8),
|
||||
child: Image.asset('assets/images/happy_news.png'),
|
||||
return Column(
|
||||
children: [
|
||||
if (state.isWorking)
|
||||
const LinearProgressIndicator(),
|
||||
|
||||
Padding(
|
||||
padding: const EdgeInsets.symmetric(horizontal: paddingVeryLarge),
|
||||
child: Column(
|
||||
children: [
|
||||
Padding(
|
||||
padding: const EdgeInsets.only(top: 8),
|
||||
child: Image.asset('assets/images/happy_news.png'),
|
||||
),
|
||||
Padding(
|
||||
padding: const EdgeInsets.only(top: 8),
|
||||
child: Text(t.pages.blocklist.noUsersBlocked),
|
||||
)
|
||||
],
|
||||
),
|
||||
Padding(
|
||||
padding: const EdgeInsets.only(top: 8),
|
||||
child: Text(t.pages.blocklist.noUsersBlocked),
|
||||
)
|
||||
],
|
||||
),
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
return ListView.builder(
|
||||
itemCount: state.blocklist.length,
|
||||
itemBuilder: (BuildContext context, int index) {
|
||||
// ignore: avoid_dynamic_calls
|
||||
final jid = state.blocklist[index];
|
||||
return Column(
|
||||
children: [
|
||||
if (state.isWorking)
|
||||
const LinearProgressIndicator(),
|
||||
|
||||
return Padding(
|
||||
padding: const EdgeInsets.symmetric(
|
||||
horizontal: 32,
|
||||
vertical: 16,
|
||||
),
|
||||
child: Row(
|
||||
children: [
|
||||
Expanded(
|
||||
child: Text(jid),
|
||||
),
|
||||
IconButton(
|
||||
icon: const Icon(Icons.delete),
|
||||
color: Colors.red,
|
||||
onPressed: () async {
|
||||
final result = await showConfirmationDialog(
|
||||
t.pages.blocklist.unblockJidConfirmTitle(jid: jid),
|
||||
t.pages.blocklist.unblockJidConfirmBody(jid: jid),
|
||||
context,
|
||||
);
|
||||
ListView.builder(
|
||||
shrinkWrap: true,
|
||||
itemCount: state.blocklist.length,
|
||||
itemBuilder: (BuildContext context, int index) {
|
||||
// ignore: avoid_dynamic_calls
|
||||
final jid = state.blocklist[index];
|
||||
|
||||
if (result) {
|
||||
// ignore: use_build_context_synchronously
|
||||
context.read<BlocklistBloc>().add(UnblockedJidEvent(jid));
|
||||
}
|
||||
},
|
||||
return Padding(
|
||||
padding: const EdgeInsets.symmetric(
|
||||
horizontal: 32,
|
||||
vertical: 16,
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
},
|
||||
child: Row(
|
||||
children: [
|
||||
Expanded(
|
||||
child: Text(jid),
|
||||
),
|
||||
IconButton(
|
||||
icon: const Icon(Icons.delete),
|
||||
color: Colors.red,
|
||||
onPressed: () async {
|
||||
final result = await showConfirmationDialog(
|
||||
t.pages.blocklist.unblockJidConfirmTitle(jid: jid),
|
||||
t.pages.blocklist.unblockJidConfirmBody(jid: jid),
|
||||
context,
|
||||
);
|
||||
|
||||
if (result) {
|
||||
// ignore: use_build_context_synchronously
|
||||
context.read<BlocklistBloc>().add(UnblockedJidEvent(jid));
|
||||
}
|
||||
},
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
},
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
@ -108,6 +123,7 @@ class BlocklistPage extends StatelessWidget {
|
||||
icon: const Icon(Icons.more_vert),
|
||||
itemBuilder: (BuildContext context) => [
|
||||
PopupMenuItem(
|
||||
enabled: state.blocklist.isNotEmpty,
|
||||
value: BlocklistOptions.unblockAll,
|
||||
child: Text(t.pages.blocklist.unblockAll),
|
||||
),
|
||||
|
@ -2,6 +2,7 @@ import 'package:flutter/foundation.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:get_it/get_it.dart';
|
||||
import 'package:moxxyv2/i18n/strings.g.dart';
|
||||
import 'package:moxxyv2/ui/bloc/blocklist_bloc.dart';
|
||||
import 'package:moxxyv2/ui/bloc/preferences_bloc.dart';
|
||||
import 'package:moxxyv2/ui/constants.dart';
|
||||
import 'package:moxxyv2/ui/helpers.dart';
|
||||
@ -76,7 +77,9 @@ class SettingsPage extends StatelessWidget {
|
||||
child: Icon(Icons.block),
|
||||
),
|
||||
onTap: () {
|
||||
Navigator.pushNamed(context, blocklistRoute);
|
||||
GetIt.I.get<BlocklistBloc>().add(
|
||||
BlocklistRequestedEvent(),
|
||||
);
|
||||
},
|
||||
),
|
||||
SettingsRow(
|
||||
|
Loading…
Reference in New Issue
Block a user