Files
buzz/mobile/lib/shared/widgets/buzz_action_tile.dart
8abc2baf0b Add mobile community invites (#5641)
## Summary
- add a permission-gated mobile community invite page
- create, copy, and natively share configurable invite links
- invite a validated npub directly with member/admin role selection
- reuse Buzz profile actions, search styling, settings rows, and modal
sheets

## Validation
- `just mobile-check`
- `flutter test` (1,275 tests)
- Pixel and iPhone review builds installed and launched

---------

Signed-off-by: kenny lopez <klopez4212@gmail.com>
Signed-off-by: Kenny Lopez <klopez4212@gmail.com>
Signed-off-by: Fast Fizz <2df81cb51f05a9d5387ef24d7b9ecb8fcdfcd1c70ffabc67061c9596e1b5b1c4@buzz.block.builderlab.xyz>
Co-authored-by: Carl <3c4caeafb646d23867f1c4832e68211d77e2561946171625f75c3ce1a3f2670f@buzz.block.builderlab.xyz>
Co-authored-by: Fast Fizz <2df81cb51f05a9d5387ef24d7b9ecb8fcdfcd1c70ffabc67061c9596e1b5b1c4@buzz.block.builderlab.xyz>
2026-08-13 17:47:44 +01:00

85 lines
2.3 KiB
Dart

import 'dart:async';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import '../theme/theme.dart';
import 'buzz_loading_indicator.dart';
/// Equal-width icon action used by profile and profile-adjacent surfaces.
class BuzzActionTile extends StatelessWidget {
/// Creates an action tile with an optional loading state.
const BuzzActionTile({
super.key,
required this.icon,
required this.label,
required this.onTap,
this.isEnabled = true,
this.isLoading = false,
this.loadingSemanticLabel,
});
/// Icon shown when the tile is not loading.
final IconData? icon;
/// Label shown below the icon.
final String label;
/// Called when the tile is tapped.
final VoidCallback onTap;
/// Whether the tile accepts taps.
final bool isEnabled;
/// Whether to show a loading indicator instead of [icon].
final bool isLoading;
/// Accessibility label for the loading indicator.
final String? loadingSemanticLabel;
@override
Widget build(BuildContext context) {
final canTap = isEnabled && !isLoading;
return GestureDetector(
onTap: canTap
? () {
unawaited(HapticFeedback.lightImpact());
onTap();
}
: null,
behavior: HitTestBehavior.opaque,
child: Opacity(
opacity: isEnabled ? 1 : 0.5,
child: Container(
width: double.infinity,
height: 68 + (Grid.xxs * 2),
decoration: BoxDecoration(
color: context.colors.surfaceContainerHighest,
borderRadius: BorderRadius.circular(Radii.dialog),
),
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
if (isLoading)
BuzzLoadingIndicator(
size: 22,
color: context.colors.onSurface,
semanticLabel: loadingSemanticLabel ?? label,
)
else
Icon(icon, size: 22, color: context.colors.onSurface),
const SizedBox(height: Grid.xxs),
Text(
label,
style: context.textTheme.labelMedium?.copyWith(
color: context.colors.onSurface,
),
),
],
),
),
),
);
}
}