tane/apps/app_seeds/lib/ui/market_gate.dart

138 lines
4.2 KiB
Dart

import 'package:flutter/material.dart';
import 'package:go_router/go_router.dart';
import '../i18n/strings.g.dart';
import '../services/onboarding_store.dart';
import 'theme.dart';
/// Makes sure the community rules have been accepted once before the user
/// joins the market or publishes anything. Returns true when the rules are
/// (or become) accepted; false when the user declines. Play/App Store UGC
/// policies require this acceptance before content can be created.
Future<bool> ensureMarketRulesAccepted(
BuildContext context,
OnboardingStore store,
) async {
if (await store.marketRulesAccepted()) return true;
if (!context.mounted) return false;
final accepted = await showModalBottomSheet<bool>(
context: context,
isScrollControlled: true,
isDismissible: false,
enableDrag: false,
builder: (_) => const MarketGateSheet(),
);
if (accepted == true) {
await store.markMarketRulesAccepted();
return true;
}
return false;
}
/// The one-time "before you join the market" sheet: the community rules in
/// a few bullets, the publish-is-public note, and a link to the full texts.
class MarketGateSheet extends StatelessWidget {
const MarketGateSheet({super.key});
@override
Widget build(BuildContext context) {
final t = context.t;
final theme = Theme.of(context);
return SafeArea(
child: SingleChildScrollView(
padding: EdgeInsets.only(
left: 20,
right: 20,
top: 24,
bottom: 16 + MediaQuery.of(context).viewInsets.bottom,
),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisSize: MainAxisSize.min,
children: [
Text(
t.marketGate.title,
style: theme.textTheme.titleLarge?.copyWith(
color: seedOnSurface,
fontWeight: FontWeight.w600,
),
),
const SizedBox(height: 12),
Text(
t.marketGate.intro,
style: theme.textTheme.bodyMedium?.copyWith(
color: seedOnSurface,
height: 1.4,
),
),
const SizedBox(height: 12),
_Rule(t.marketGate.ruleHonest),
_Rule(t.marketGate.ruleLegal),
_Rule(t.marketGate.ruleRespect),
const SizedBox(height: 12),
Text(
t.marketGate.publicNote,
style: theme.textTheme.bodySmall?.copyWith(
color: seedMuted,
height: 1.4,
),
),
TextButton.icon(
style: TextButton.styleFrom(
padding: EdgeInsets.zero,
foregroundColor: seedGreen,
),
icon: const Icon(Icons.privacy_tip_outlined, size: 16),
label: Text(t.marketGate.viewLegal),
onPressed: () => context.push('/legal'),
),
const SizedBox(height: 8),
Row(
mainAxisAlignment: MainAxisAlignment.end,
children: [
TextButton(
onPressed: () => Navigator.of(context).pop(false),
child: Text(t.marketGate.decline),
),
const SizedBox(width: 8),
FilledButton(
onPressed: () => Navigator.of(context).pop(true),
child: Text(t.marketGate.accept),
),
],
),
],
),
),
);
}
}
class _Rule extends StatelessWidget {
const _Rule(this.text);
final String text;
@override
Widget build(BuildContext context) {
return Padding(
padding: const EdgeInsetsDirectional.only(bottom: 8),
child: Row(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
const Icon(Icons.check_circle_outline, size: 18, color: seedGreen),
const SizedBox(width: 8),
Expanded(
child: Text(
text,
style: Theme.of(context).textTheme.bodyMedium?.copyWith(
color: seedOnSurface,
height: 1.35,
),
),
),
],
),
);
}
}