Files
buzz/mobile/lib/shared/community/community_grid_option.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

93 lines
2.7 KiB
Dart

import 'dart:async';
import 'package:flutter/material.dart';
import 'package:flutter_hooks/flutter_hooks.dart';
import '../theme/theme.dart';
import 'community_avatar.dart';
import 'community_grid.dart';
/// A community tile shared by onboarding and the switcher.
class CommunityGridOption extends HookWidget {
const CommunityGridOption({
super.key,
required this.id,
required this.name,
required this.relayUrl,
required this.onSelect,
this.isActive = false,
this.hidden = false,
this.enabled = true,
this.badge,
});
final String id;
final String name;
final String relayUrl;
final Future<void> Function(Rect) onSelect;
final bool isActive;
final bool hidden;
final bool enabled;
final Widget? badge;
@override
Widget build(BuildContext context) {
final avatarKey = useMemoized(GlobalKey.new);
return Semantics(
selected: isActive,
button: enabled,
child: InkWell(
key: Key('community-switcher-row-$id'),
borderRadius: BorderRadius.circular(Radii.card),
onTap: !enabled
? null
: () {
final box = avatarKey.currentContext?.findRenderObject();
if (box is RenderBox) {
unawaited(
onSelect(box.localToGlobal(Offset.zero) & box.size),
);
}
},
child: Padding(
padding: const EdgeInsets.symmetric(vertical: Grid.xxs),
child: Column(
children: [
Stack(
clipBehavior: Clip.none,
children: [
Opacity(
opacity: hidden ? 0 : 1,
child: SizedBox(
key: avatarKey,
child: ExcludeSemantics(
child: CommunityAvatar(
key: Key('community-switcher-avatar-$id'),
name: name,
relayUrl: relayUrl,
size: communityGridAvatarSize,
),
),
),
),
if (badge != null)
Positioned(
right: -Grid.twelve,
bottom: -Grid.twelve,
child: badge!,
),
],
),
const SizedBox(height: Grid.xs),
Text(
name,
textAlign: TextAlign.center,
style: context.textTheme.bodyLarge?.copyWith(
fontWeight: FontWeight.w600,
),
),
],
),
),
),
);
}
}