feat(social): standard NIP-56 reporting — ReportTransport in commons_core, report sheet on offers and chats, local hide + optional block

This commit is contained in:
vjrj 2026-07-13 07:56:43 +02:00
parent 11b242edbf
commit 0e7faaeb90
15 changed files with 560 additions and 15 deletions

View file

@ -0,0 +1,74 @@
import 'package:flutter/material.dart';
import 'package:flutter_localizations/flutter_localizations.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:tane/i18n/strings.g.dart';
import 'package:tane/services/social_connection.dart';
import 'package:tane/services/social_service.dart';
import 'package:tane/services/social_settings.dart';
import 'package:tane/ui/report_sheet.dart';
import '../support/test_support.dart';
void main() {
const seedHex =
'000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f';
// A connection that can never open the sheet degrades to "couldn't send".
Future<SocialConnection> offlineConnection() async => SocialConnection(
social: await SocialService.fromRootSeedHex(seedHex),
settings: SocialSettings(InMemorySecretStore()),
open: (_) async => throw StateError('offline'),
online: const Stream.empty(),
);
Widget host(SocialConnection connection, SocialSettings settings) =>
TranslationProvider(
child: MaterialApp(
localizationsDelegates: GlobalMaterialLocalizations.delegates,
home: Scaffold(
body: ReportSheet(
connection: connection,
subjectPubkey: 'ab' * 32,
settings: settings,
),
),
),
);
testWidgets('shows the reason picker, details field and block option', (
tester,
) async {
LocaleSettings.setLocaleSync(AppLocale.en);
await tester.pumpWidget(
host(await offlineConnection(), SocialSettings(InMemorySecretStore())),
);
await tester.pump();
expect(find.text('Spam or a scam'), findsOneWidget);
expect(find.text('Abusive or disrespectful'), findsOneWidget);
expect(find.text("Seeds that shouldn't be offered"), findsOneWidget);
expect(find.text('Something else'), findsOneWidget);
expect(find.text('Also block this person'), findsOneWidget);
expect(find.text('Send report'), findsOneWidget);
});
testWidgets('offline send fails softly and keeps the sheet open', (
tester,
) async {
LocaleSettings.setLocaleSync(AppLocale.en);
final settings = SocialSettings(InMemorySecretStore());
await tester.pumpWidget(host(await offlineConnection(), settings));
await tester.pump();
await tester.tap(find.byKey(const Key('report.send')));
await tester.pump(const Duration(milliseconds: 100));
expect(
find.text("Couldn't send the report — check your connection"),
findsOneWidget,
);
// Nothing was blocked as a side effect of the failed send.
expect(await settings.blockedPubkeys(), isEmpty);
expect(find.byType(ReportSheet), findsOneWidget);
});
}

View file

@ -63,6 +63,8 @@ class FakeSession implements SocialSession {
@override
RatingTransport get ratings => throw UnimplementedError();
@override
ReportTransport get reports => throw UnimplementedError();
@override
ProfileTransport get profile => throw UnimplementedError();
@override
SyncTransport get sync => throw UnimplementedError();