Files
buzz/mobile/lib/features/pairing/community_link_focus.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

60 lines
1.9 KiB
Dart

import 'dart:async';
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:flutter_hooks/flutter_hooks.dart';
/// Start link motion with the native keyboard, with a hardware-keyboard fallback.
bool useCommunityLinkFocus(
BuildContext context, {
required bool enteringLink,
required FocusNode focus,
}) {
final ios = defaultTargetPlatform == TargetPlatform.iOS;
final reducedMotion = MediaQuery.disableAnimationsOf(context);
final keyboardReady = useState(false);
final enteringLinkRef = useRef(enteringLink)..value = enteringLink;
useEffect(() {
const channel = MethodChannel('buzz/community_keyboard');
Timer? fallback;
var disposed = false;
void beginOpening() {
if (disposed || !enteringLinkRef.value || keyboardReady.value) return;
fallback?.cancel();
keyboardReady.value = true;
}
if (ios && enteringLink) {
channel.setMethodCallHandler((call) async {
if (call.method != 'willShow') return;
beginOpening();
});
}
if (enteringLink) {
WidgetsBinding.instance.addPostFrameCallback((_) {
if (disposed || !context.mounted || !enteringLinkRef.value) return;
focus.requestFocus();
if (!ios ||
reducedMotion ||
MediaQuery.viewInsetsOf(context).bottom > 0) {
beginOpening();
} else {
// Hardware keyboards and older hosts may send no show notification.
fallback = Timer(const Duration(milliseconds: 350), beginOpening);
}
});
} else {
focus.unfocus();
keyboardReady.value = false;
}
return () {
disposed = true;
fallback?.cancel();
if (ios && enteringLink) channel.setMethodCallHandler(null);
};
}, [enteringLink, ios, reducedMotion]);
return keyboardReady.value;
}