feat(proj): init
This commit is contained in:
@@ -0,0 +1,77 @@
|
||||
import 'dart:ui';
|
||||
|
||||
import 'package:flutter/cupertino.dart';
|
||||
import 'package:please_pay_me/theme/tokens.dart';
|
||||
import 'package:please_pay_me/ui/atoms/app_text.dart';
|
||||
|
||||
/// iOS has no SnackBar — the platform idiom is a floating blurred capsule
|
||||
/// (AirPods / Silent-mode style). Kept dismiss-free and auto-hiding.
|
||||
class AppToast extends StatelessWidget {
|
||||
const AppToast({
|
||||
super.key,
|
||||
required this.message,
|
||||
this.icon = CupertinoIcons.check_mark_circled_solid,
|
||||
this.tint = AppColors.accent,
|
||||
});
|
||||
|
||||
final String message;
|
||||
final IconData? icon;
|
||||
final Color tint;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return ClipRRect(
|
||||
borderRadius: BorderRadius.circular(AppRadii.capsule),
|
||||
child: BackdropFilter(
|
||||
filter: ImageFilter.blur(sigmaX: 20, sigmaY: 20),
|
||||
child: Container(
|
||||
padding: const EdgeInsets.symmetric(
|
||||
horizontal: AppSpacing.s4,
|
||||
vertical: AppSpacing.s3,
|
||||
),
|
||||
decoration: BoxDecoration(
|
||||
color: AppColors.of(context, AppColors.groupedSurface).withValues(alpha: 0.82),
|
||||
borderRadius: BorderRadius.circular(AppRadii.capsule),
|
||||
boxShadow: const [
|
||||
BoxShadow(color: Color(0x1F000000), blurRadius: 24, offset: Offset(0, 8)),
|
||||
],
|
||||
),
|
||||
child: Row(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
if (icon != null) ...[
|
||||
Icon(icon, size: 20, color: AppColors.of(context, tint)),
|
||||
const SizedBox(width: AppSpacing.s2),
|
||||
],
|
||||
Flexible(child: AppText.subhead(message, color: AppColors.label)),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> showAppToast(
|
||||
BuildContext context, {
|
||||
required String message,
|
||||
IconData? icon = CupertinoIcons.check_mark_circled_solid,
|
||||
Duration duration = const Duration(seconds: 2),
|
||||
}) async {
|
||||
final overlay = Overlay.of(context, rootOverlay: true);
|
||||
final entry = OverlayEntry(
|
||||
builder: (ctx) => Positioned(
|
||||
left: AppSpacing.s5,
|
||||
right: AppSpacing.s5,
|
||||
bottom: MediaQuery.of(ctx).padding.bottom + AppSpacing.s7,
|
||||
child: SafeArea(
|
||||
top: false,
|
||||
child: Center(child: AppToast(message: message, icon: icon)),
|
||||
),
|
||||
),
|
||||
);
|
||||
|
||||
overlay.insert(entry);
|
||||
await Future<void>.delayed(duration);
|
||||
entry.remove();
|
||||
}
|
||||
Reference in New Issue
Block a user