chatapp3-flutter/lib/ui_kit/widgets/register_reward/register_reward_dialog.dart
2026-04-18 19:00:19 +08:00

324 lines
9.5 KiB
Dart

import 'dart:math' as math;
import 'package:flutter/material.dart';
import 'package:flutter_screenutil/flutter_screenutil.dart';
import 'package:flutter_smart_dialog/flutter_smart_dialog.dart';
import 'package:yumi/ui_kit/components/text/sc_text.dart';
class RegisterRewardDialogItem {
const RegisterRewardDialogItem({required this.title});
final String title;
}
class RegisterRewardDialog extends StatelessWidget {
const RegisterRewardDialog({
super.key,
required this.items,
this.title = 'Welcome to Yumi Party',
this.subtitle = 'Here are some small gifts for you',
});
static const String dialogTag = 'showRegisterRewardDialog';
static const double _dialogWidth = 340;
static const double _dialogHeight = 250;
static const double _titleWidth = 147;
static const double _titleHeight = 22;
final List<RegisterRewardDialogItem> items;
final String title;
final String subtitle;
static List<RegisterRewardDialogItem> defaultItems() {
return const [
RegisterRewardDialogItem(title: 'small gifts'),
RegisterRewardDialogItem(title: 'small gifts'),
];
}
static Future<void> show(
BuildContext context, {
List<RegisterRewardDialogItem>? items,
String title = 'Welcome to Yumi Party',
String subtitle = 'Here are some small gifts for you',
}) async {
SmartDialog.dismiss(tag: dialogTag);
await SmartDialog.show(
tag: dialogTag,
alignment: Alignment.center,
maskColor: Colors.black.withValues(alpha: 0.56),
animationType: SmartAnimationType.fade,
clickMaskDismiss: true,
builder:
(_) => RegisterRewardDialog(
items: items ?? defaultItems(),
title: title,
subtitle: subtitle,
),
);
}
@override
Widget build(BuildContext context) {
final screenWidth = MediaQuery.sizeOf(context).width;
final dialogWidth = math.min(screenWidth - 36.w, _dialogWidth.w);
return Material(
color: Colors.transparent,
child: SizedBox(
width: dialogWidth,
child: AspectRatio(
aspectRatio: _dialogWidth / _dialogHeight,
child: LayoutBuilder(
builder: (context, constraints) {
final scale = constraints.maxWidth / _dialogWidth;
return Stack(
children: [
Positioned.fill(
child: Image.asset(
_RegisterRewardAssets.dialogBackground,
fit: BoxFit.fill,
),
),
PositionedDirectional(
end: 28 * scale,
top: 52 * scale,
child: GestureDetector(
behavior: HitTestBehavior.opaque,
onTap:
() => SmartDialog.dismiss(
tag: RegisterRewardDialog.dialogTag,
),
child: Padding(
padding: EdgeInsets.all(6 * scale),
child: Image.asset(
_RegisterRewardAssets.closeIcon,
width: 14 * scale,
height: 14 * scale,
fit: BoxFit.contain,
),
),
),
),
Positioned(
top: 34 * scale,
left: 0,
right: 0,
child: Center(
child: _RegisterRewardTitle(
text: title,
width: _titleWidth * scale,
height: _titleHeight * scale,
),
),
),
Positioned(
top: 76 * scale,
left: 24 * scale,
right: 24 * scale,
child: text(
subtitle,
fontSize: 12,
fontWeight: FontWeight.w400,
textAlign: TextAlign.center,
maxLines: 2,
textColor: Colors.white,
),
),
Positioned(
left: 0,
right: 0,
bottom: 38 * scale,
child: _RegisterRewardItemsRow(items: items, scale: scale),
),
],
);
},
),
),
),
);
}
}
class _RegisterRewardTitle extends StatelessWidget {
const _RegisterRewardTitle({
required this.text,
required this.width,
required this.height,
});
final String text;
final double width;
final double height;
@override
Widget build(BuildContext context) {
const gradientColors = [
Color(0xFFFFF2BA),
Color(0xFFFFFAE3),
Color(0xFFFFF2BA),
Color(0xFFFFFBE8),
Color(0xFFFFF2BA),
];
final shadowTextStyle = TextStyle(
fontSize: 15.sp,
fontWeight: FontWeight.w500,
height: 1.0,
color: Colors.white,
shadows: const [
Shadow(color: Color(0xFF17614D), blurRadius: 4, offset: Offset.zero),
],
);
final gradientTextStyle = TextStyle(
fontSize: 15.sp,
fontWeight: FontWeight.w500,
height: 1.0,
color: Colors.white,
);
return SizedBox(
width: width,
height: height,
child: Stack(
alignment: Alignment.center,
children: [
FittedBox(
fit: BoxFit.scaleDown,
child: Text(
text,
maxLines: 1,
textAlign: TextAlign.center,
style: shadowTextStyle,
),
),
ShaderMask(
blendMode: BlendMode.srcIn,
shaderCallback: (bounds) {
return const LinearGradient(
begin: Alignment.centerLeft,
end: Alignment.centerRight,
colors: gradientColors,
).createShader(bounds);
},
child: FittedBox(
fit: BoxFit.scaleDown,
child: Text(
text,
maxLines: 1,
textAlign: TextAlign.center,
style: gradientTextStyle,
),
),
),
],
),
);
}
}
class _RegisterRewardItemsRow extends StatelessWidget {
const _RegisterRewardItemsRow({required this.items, required this.scale});
final List<RegisterRewardDialogItem> items;
final double scale;
@override
Widget build(BuildContext context) {
final visibleItems = items.take(2).toList();
return Row(
mainAxisAlignment: MainAxisAlignment.center,
mainAxisSize: MainAxisSize.min,
children: [
for (var index = 0; index < visibleItems.length; index++) ...[
_RegisterRewardItemCard(item: visibleItems[index], scale: scale),
if (index != visibleItems.length - 1) SizedBox(width: 30 * scale),
],
],
);
}
}
class _RegisterRewardItemCard extends StatelessWidget {
const _RegisterRewardItemCard({required this.item, required this.scale});
final RegisterRewardDialogItem item;
final double scale;
@override
Widget build(BuildContext context) {
return SizedBox(
width: 88 * scale,
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
SizedBox(
width: 88 * scale,
height: 88 * scale,
child: Stack(
alignment: Alignment.center,
children: [
Image.asset(
_RegisterRewardAssets.goldGlowBackground,
width: 88 * scale,
height: 88 * scale,
fit: BoxFit.fill,
),
Container(
width: 44 * scale,
height: 44 * scale,
decoration: BoxDecoration(
shape: BoxShape.circle,
color: Colors.white.withValues(alpha: 0.10),
border: Border.all(
color: Colors.white.withValues(alpha: 0.62),
width: 1.2 * scale,
),
boxShadow: [
BoxShadow(
color: Colors.white.withValues(alpha: 0.10),
blurRadius: 8 * scale,
offset: Offset.zero,
),
],
),
child: Center(
child: Container(
width: 18 * scale,
height: 18 * scale,
decoration: BoxDecoration(
shape: BoxShape.circle,
color: Colors.white.withValues(alpha: 0.18),
),
),
),
),
],
),
),
SizedBox(height: 8 * scale),
text(
item.title,
fontSize: 12,
fontWeight: FontWeight.w400,
textAlign: TextAlign.center,
maxLines: 2,
lineHeight: 1.2,
textColor: Colors.white,
),
],
),
);
}
}
class _RegisterRewardAssets {
static const String dialogBackground =
'sc_images/register_reward/dialog_background.png';
static const String goldGlowBackground =
'sc_images/register_reward/gold_glow_background.png';
static const String closeIcon = 'sc_images/register_reward/close_icon.png';
}