mirror of
https://github.com/block/buzz.git
synced 2026-10-30 22:11:36 +00:00
## Summary Move Invite, Appearance, and Remove community into a **Community settings** section in the community-avatar sheet, above the existing switcher. Keep the sheet untitled and use circle-minus for removal. Personal Settings groups **Set status** and **Copy public key (npub)** above an untitled card containing **Display name**, **Profile description**, and **Edit photo**. Remove the leading icons from status, public key, and Send identity to desktop; keep the latter in its own untitled card. Remove the avatar status badge and top Edit action, and rename the Theme page to **Appearance**. Opening the presence chip triggers selection haptics; copying plays native iOS success feedback and confirms with “Public key (npub) copied.” ### Testing - Mobile formatting, analysis, and file-size checks passed. - 111 affected widget tests passed; all 48 settings tests passed again after the final labels and icon changes. - Final release build installed and launched on a physical iPhone in the separate Buzz Community preview, retaining its existing test account. - Full repository `just ci` was blocked by local disk exhaustion during Rust compilation. The full mobile suite passed (2,609 passed, four skipped), plus three push-unconfigured tests. The presence and copy feedback passed focused widget tests and analysis, including native iOS success-channel coverage. ### Snapshots Light and dark Flutter widget renders with fixture data. Images are GitHub attachments, not committed to the repository. The personal-settings snapshots precede the final “(npub)” label clarification. | Surface | Light | Dark | | --- | --- | --- | | Community sheet | <img src="https://github.com/user-attachments/assets/d52a192e-bd40-4263-ac2d-05d589c7ebf2" width="280" alt="Community sheet, light"> | <img src="https://github.com/user-attachments/assets/8756ebe9-b6d4-4920-8fb7-1cb7ee8ef778" width="280" alt="Community sheet, dark"> | | Personal settings | <img src="https://github.com/user-attachments/assets/962b98bd-e4cf-4cd1-8948-69b349390ceb" width="280" alt="Personal settings, light"> | <img src="https://github.com/user-attachments/assets/223bb0a8-e10e-43b1-83ea-e0955af4627a" width="280" alt="Personal settings, dark"> | | Appearance | <img src="https://github.com/user-attachments/assets/334ba797-55cb-47ce-b677-0befafb7659b" width="280" alt="Appearance, light"> | <img src="https://github.com/user-attachments/assets/79b62503-d476-4dbc-8c75-8cee0ee37e98" width="280" alt="Appearance, dark"> | --------- Signed-off-by: kenny lopez <klopez4212@gmail.com>
133 lines
3.8 KiB
Dart
133 lines
3.8 KiB
Dart
part of '../settings_page.dart';
|
|
|
|
class _ConnectionSection extends ConsumerWidget {
|
|
const _ConnectionSection({required this.identityRecoveryPageBuilder});
|
|
|
|
final WidgetBuilder identityRecoveryPageBuilder;
|
|
|
|
@override
|
|
Widget build(BuildContext context, WidgetRef ref) {
|
|
final config = ref.watch(relayConfigProvider);
|
|
final authState = ref.watch(authProvider).value;
|
|
final nsec = config.nsec;
|
|
final community = authState?.community;
|
|
|
|
if (nsec == null || nsec.isEmpty || community == null) {
|
|
return const SizedBox.shrink();
|
|
}
|
|
|
|
return AppListCard(
|
|
verticalPadding: Grid.twelve,
|
|
children: [
|
|
AppListRow(
|
|
title: 'Send identity to desktop',
|
|
subtitle: 'Scan a recovery code shown by Buzz Desktop',
|
|
trailing: const _RowChevron(),
|
|
onTap: () async {
|
|
final pairing = ref.read(pairingProvider.notifier);
|
|
final authorized = await pairing.authorizeIdentityExport(
|
|
community: community,
|
|
);
|
|
if (!authorized) {
|
|
if (!context.mounted) return;
|
|
final message = ref.read(pairingProvider).errorMessage;
|
|
if (message != null) {
|
|
ScaffoldMessenger.of(
|
|
context,
|
|
).showSnackBar(SnackBar(content: Text(message)));
|
|
}
|
|
return;
|
|
}
|
|
|
|
try {
|
|
if (!context.mounted) return;
|
|
final resumed = await _waitForResumedFrame();
|
|
if (!resumed) {
|
|
if (context.mounted) {
|
|
ScaffoldMessenger.of(context).showSnackBar(
|
|
const SnackBar(
|
|
content: Text(
|
|
'Buzz did not return to the foreground. Try again.',
|
|
),
|
|
),
|
|
);
|
|
}
|
|
return;
|
|
}
|
|
if (!context.mounted) return;
|
|
await Navigator.of(context).push(
|
|
MaterialPageRoute<void>(builder: identityRecoveryPageBuilder),
|
|
);
|
|
} finally {
|
|
pairing.reset();
|
|
}
|
|
},
|
|
),
|
|
],
|
|
);
|
|
}
|
|
}
|
|
|
|
const _resumeWaitTimeout = Duration(seconds: 5);
|
|
|
|
Future<bool> _waitForResumedFrame() async {
|
|
final binding = WidgetsBinding.instance;
|
|
if (binding.lifecycleState != AppLifecycleState.resumed) {
|
|
final resumed = Completer<void>();
|
|
final listener = AppLifecycleListener(
|
|
onResume: () {
|
|
if (!resumed.isCompleted) resumed.complete();
|
|
},
|
|
);
|
|
try {
|
|
await resumed.future.timeout(_resumeWaitTimeout);
|
|
} on TimeoutException {
|
|
return false;
|
|
} finally {
|
|
listener.dispose();
|
|
}
|
|
}
|
|
await binding.endOfFrame;
|
|
return true;
|
|
}
|
|
|
|
class _IdentityRow extends StatelessWidget {
|
|
const _IdentityRow({required this.nsec});
|
|
|
|
final String nsec;
|
|
|
|
@override
|
|
Widget build(BuildContext context) {
|
|
final privHex = nostr.Nip19.decode(payload: nsec).data;
|
|
final npub = privHex.isNotEmpty
|
|
? fullNpub(nostr.Keys(privHex).public)
|
|
: null;
|
|
|
|
// The full npub is the canonical copy/share form (never raw hex); an
|
|
// invalid identity is surfaced as unavailable and never copied.
|
|
return Semantics(
|
|
button: true,
|
|
label: 'Copy identity public key',
|
|
value: npub ?? 'Identity unavailable',
|
|
child: AppListRow(
|
|
title: 'Copy public key (npub)',
|
|
trailing: Icon(
|
|
LucideIcons.copy,
|
|
size: 18,
|
|
color: context.colors.onSurfaceVariant,
|
|
),
|
|
onTap: npub == null
|
|
? null
|
|
: () async {
|
|
await copyToClipboard(
|
|
context,
|
|
npub,
|
|
message: 'Public key (npub) copied',
|
|
);
|
|
await successHaptic();
|
|
},
|
|
),
|
|
);
|
|
}
|
|
}
|