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:
parent
11b242edbf
commit
0e7faaeb90
15 changed files with 560 additions and 15 deletions
|
|
@ -92,4 +92,13 @@ void main() {
|
|||
await settings.block(' AB' * 1 + 'ab' * 31); // messy spacing/case
|
||||
expect(await settings.blockedPubkeys(), hasLength(1));
|
||||
});
|
||||
|
||||
test('hidden (reported) offers round-trip as author:id keys', () async {
|
||||
expect(await settings.hiddenOfferKeys(), isEmpty);
|
||||
await settings.hideOffer(authorPubkeyHex: 'AB' * 32, offerId: 'tomate-1');
|
||||
expect(
|
||||
await settings.hiddenOfferKeys(),
|
||||
{SocialSettings.offerKey('ab' * 32, 'tomate-1')},
|
||||
);
|
||||
});
|
||||
}
|
||||
|
|
|
|||
|
|
@ -220,6 +220,28 @@ void main() {
|
|||
await cubit.close();
|
||||
});
|
||||
|
||||
test('a hidden (reported) offer disappears without touching its author',
|
||||
() async {
|
||||
final transport = FakeOfferTransport();
|
||||
for (final id in ['lot-1', 'lot-2']) {
|
||||
await transport.publish(OfferMapper.fromSharedLot(
|
||||
lotId: id,
|
||||
authorPubkeyHex: 'ab' * 32,
|
||||
summary: 'Oferta $id',
|
||||
sharing: OfferStatus.shared,
|
||||
areaGeohash: 'sp3e9',
|
||||
));
|
||||
}
|
||||
final cubit = OffersCubit(transport);
|
||||
await cubit.discover('sp3');
|
||||
await pumpEventQueue();
|
||||
expect(cubit.state.visibleOffers, hasLength(2));
|
||||
|
||||
cubit.setHiddenOffers({'${'ab' * 32}:lot-1'});
|
||||
expect(cubit.state.visibleOffers.map((o) => o.id), ['lot-2']);
|
||||
await cubit.close();
|
||||
});
|
||||
|
||||
test('the search filter survives a refresh (re-discovery)', () async {
|
||||
final transport = FakeOfferTransport();
|
||||
await transport.publish(OfferMapper.fromSharedLot(
|
||||
|
|
|
|||
74
apps/app_seeds/test/ui/report_sheet_test.dart
Normal file
74
apps/app_seeds/test/ui/report_sheet_test.dart
Normal 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);
|
||||
});
|
||||
}
|
||||
|
|
@ -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();
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue