feat(market): one-time community-rules gate before joining the market, publishing or messaging

This commit is contained in:
vjrj 2026-07-13 00:52:39 +02:00
parent a7e10eba7a
commit 5d25f65f76
7 changed files with 311 additions and 1 deletions

View file

@ -11,9 +11,11 @@ import '../services/offer_outbox.dart';
import '../services/social_connection.dart';
import '../services/social_service.dart';
import '../services/social_settings.dart';
import '../services/onboarding_store.dart';
import '../state/offers_cubit.dart';
import 'edge_fade.dart';
import 'filter_chips.dart';
import 'market_gate.dart';
import 'market_widgets.dart';
import 'theme.dart';
@ -27,12 +29,18 @@ class MarketScreen extends StatefulWidget {
required this.connection,
this.location,
this.outbox,
this.onboarding,
super.key,
});
final SocialService social;
final SocialSettings settings;
/// When set, joining the market is gated on a one-time acceptance of the
/// community rules (store UGC policies require it before content is
/// created). Null in tests no gate.
final OnboardingStore? onboarding;
/// The shared relay connection (one per identity), reused for discovery.
final SocialConnection connection;
@ -56,7 +64,24 @@ class _MarketScreenState extends State<MarketScreen> {
@override
void initState() {
super.initState();
_init();
_start();
}
/// Runs the one-time community-rules gate (when wired) before touching the
/// network; declining leaves the market.
Future<void> _start() async {
final store = widget.onboarding;
if (store != null && !await store.marketRulesAccepted()) {
// Wait for the first frame so the sheet has a surface to attach to.
await WidgetsBinding.instance.endOfFrame;
if (!mounted) return;
final ok = await ensureMarketRulesAccepted(context, store);
if (!ok) {
if (mounted) context.pop();
return;
}
}
await _init();
}
Future<void> _init() async {
@ -111,6 +136,13 @@ class _MarketScreenState extends State<MarketScreen> {
/// Publishes the user's shared lots as offers to the network, tagged with the
/// coarse area. Prompts for setup when the area isn't set.
Future<void> _shareMine() async {
// Defense in depth: publishing is what actually creates content, so the
// rules gate is re-checked here even though market entry already ran it.
final store = widget.onboarding;
if (store != null) {
final ok = await ensureMarketRulesAccepted(context, store);
if (!ok || !mounted) return;
}
final cubit = _cubit;
if (cubit == null) return;
final repo = context.read<VarietyRepository>();