feat(social): local blocklist — hide blocked authors' offers, chats and incoming messages, with unblock management
This commit is contained in:
parent
5d25f65f76
commit
11b242edbf
13 changed files with 399 additions and 4 deletions
109
apps/app_seeds/lib/ui/blocked_people.dart
Normal file
109
apps/app_seeds/lib/ui/blocked_people.dart
Normal file
|
|
@ -0,0 +1,109 @@
|
|||
import 'package:flutter/material.dart';
|
||||
|
||||
import '../di/injector.dart';
|
||||
import '../i18n/strings.g.dart';
|
||||
import '../services/profile_cache.dart';
|
||||
import '../services/social_settings.dart';
|
||||
import 'peer_avatar.dart';
|
||||
import 'theme.dart';
|
||||
|
||||
/// Management list for the local blocklist: who is blocked, with one-tap
|
||||
/// unblock. Opened from the market's sharing setup.
|
||||
class BlockedPeopleSheet extends StatefulWidget {
|
||||
const BlockedPeopleSheet({required this.settings, this.profileCache, super.key});
|
||||
|
||||
final SocialSettings settings;
|
||||
|
||||
/// Resolves peers' display names; falls back to the app-wide cache when not
|
||||
/// injected (tests pass one explicitly or leave names as short keys).
|
||||
final ProfileCache? profileCache;
|
||||
|
||||
@override
|
||||
State<BlockedPeopleSheet> createState() => _BlockedPeopleSheetState();
|
||||
}
|
||||
|
||||
class _BlockedPeopleSheetState extends State<BlockedPeopleSheet> {
|
||||
List<String>? _blocked;
|
||||
final Map<String, String> _names = {};
|
||||
|
||||
ProfileCache? get _cache =>
|
||||
widget.profileCache ??
|
||||
(getIt.isRegistered<ProfileCache>() ? getIt<ProfileCache>() : null);
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
_load();
|
||||
}
|
||||
|
||||
Future<void> _load() async {
|
||||
final blocked = (await widget.settings.blockedPubkeys()).toList()..sort();
|
||||
final cache = _cache;
|
||||
if (cache != null) {
|
||||
for (final p in blocked) {
|
||||
final name = await cache.name(p);
|
||||
if (name != null) _names[p] = name;
|
||||
}
|
||||
}
|
||||
if (mounted) setState(() => _blocked = blocked);
|
||||
}
|
||||
|
||||
Future<void> _unblock(String pubkey) async {
|
||||
await widget.settings.unblock(pubkey);
|
||||
await _load();
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final t = context.t;
|
||||
final blocked = _blocked;
|
||||
return SafeArea(
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.fromLTRB(20, 20, 20, 16),
|
||||
child: Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Text(
|
||||
t.block.manageTitle,
|
||||
style: Theme.of(context).textTheme.titleLarge?.copyWith(
|
||||
color: seedOnSurface,
|
||||
fontWeight: FontWeight.w600,
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 12),
|
||||
if (blocked == null)
|
||||
const Center(child: CircularProgressIndicator())
|
||||
else if (blocked.isEmpty)
|
||||
Text(
|
||||
t.block.manageEmpty,
|
||||
style: const TextStyle(color: seedMuted),
|
||||
)
|
||||
else
|
||||
Flexible(
|
||||
child: ListView.builder(
|
||||
shrinkWrap: true,
|
||||
itemCount: blocked.length,
|
||||
itemBuilder: (context, i) {
|
||||
final pubkey = blocked[i];
|
||||
return ListTile(
|
||||
contentPadding: EdgeInsets.zero,
|
||||
leading: PeerAvatar(
|
||||
pubkey: pubkey,
|
||||
name: _names[pubkey],
|
||||
),
|
||||
title: Text(_names[pubkey] ?? shortPubkey(pubkey)),
|
||||
trailing: TextButton(
|
||||
onPressed: () => _unblock(pubkey),
|
||||
child: Text(t.block.unblock),
|
||||
),
|
||||
);
|
||||
},
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue