Files
buzz/mobile/lib/features/onboarding/hosted_join_policy_view.dart
klopez4212 e922dc08ff Unify mobile onboarding and community entry screens (#8687)
## Summary

Use consistent fullscreen screens for identity setup, community
selection, joining, and Add Community. Restore all memberships and open
the selected community; share the community grid with the switcher.

Add QR-first choices, animated link entry with 12px keyboard clearance,
a two-finger double-tap pairing toggle, and the centered reversing bee
loader. Preserve cancellation, Back, and reduced-motion behavior.

Add intentionally omits community creation and Builderlab sign-in: this
route follows sign-in and the existing-community picker.

### Related issue

Related: #8628 (native profile setup). No duplicate fullscreen
onboarding PR found.

### Testing

- Full standard and hosted-authentication mobile suites, static
analysis, and required push checks passed.
- iPhone preview iterated with Kenny; final simulator walkthrough below
uses synthetic data and does not authenticate or save account changes.
- Independent review completed; regressions cover cancellation during
loading, Add recovery after failed/conflicting memberships, retrying
skipped communities, and explicit picker stages.

Walkthrough recorded before the copy and recovery followups:


https://github.com/user-attachments/assets/bfea3ad3-1dde-40c4-8748-44c84226c292

---------

Signed-off-by: kenny lopez <klopez4212@gmail.com>
Co-authored-by: Terp <5856f6900e8e0a4e0ea1f4f8d2ee33e4753d2119bc122f94ecafc660b46c0511@buzz.block.builderlab.xyz>
2026-10-29 16:12:31 +00:00

94 lines
3.0 KiB
Dart
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import 'package:flutter/material.dart';
import 'package:flutter_hooks/flutter_hooks.dart';
import '../../shared/hosted/hosted_join_policy.dart';
import '../../shared/theme/grid.dart';
import '../../shared/widgets/onboarding_step_page.dart';
/// Consent is explicit and scoped to the policy version shown on this screen.
class HostedJoinPolicyView extends HookWidget {
const HostedJoinPolicyView({
super.key,
required this.policy,
required this.onAccept,
this.fullScreen = false,
this.onBack,
});
final HostedJoinPolicy policy;
final VoidCallback onAccept;
final bool fullScreen;
final VoidCallback? onBack;
@override
Widget build(BuildContext context) {
final ageConfirmed = useState(false);
final documents = [
if (policy.terms != null) 'terms',
if (policy.privacy != null) 'privacy policy',
];
final children = <Widget>[
if (policy.terms != null)
ExpansionTile(
tilePadding: fullScreen ? EdgeInsets.zero : null,
expandedCrossAxisAlignment: fullScreen
? CrossAxisAlignment.stretch
: null,
title: const Text('Terms of service'),
children: [
Padding(
padding: fullScreen
? const EdgeInsets.symmetric(vertical: Grid.sm)
: const EdgeInsets.all(Grid.sm),
child: SelectableText(policy.terms!),
),
],
),
if (policy.privacy != null)
ExpansionTile(
tilePadding: fullScreen ? EdgeInsets.zero : null,
expandedCrossAxisAlignment: fullScreen
? CrossAxisAlignment.stretch
: null,
title: const Text('Privacy policy'),
children: [
Padding(
padding: fullScreen
? const EdgeInsets.symmetric(vertical: Grid.sm)
: const EdgeInsets.all(Grid.sm),
child: SelectableText(policy.privacy!),
),
],
),
if (policy.ageRequired)
CheckboxListTile(
contentPadding: fullScreen ? EdgeInsets.zero : null,
value: ageConfirmed.value,
onChanged: (value) => ageConfirmed.value = value ?? false,
title: const Text('I am 18 or older'),
),
const SizedBox(height: Grid.sm),
FilledButton(
onPressed: !policy.ageRequired || ageConfirmed.value ? onAccept : null,
child: const Text('Accept and join'),
),
];
if (fullScreen) {
return OnboardingStepPage(
title: 'Join your community',
subtitle: documents.isEmpty
? null
: 'Review this community’s ${documents.join(' and ')} before joining.',
onBack: onBack ?? () {},
content: Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: children.sublist(0, children.length - 1),
),
actions: [children.last],
);
}
return Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: children,
);
}
}