212 lines
7.1 KiB
Dart
212 lines
7.1 KiB
Dart
import 'package:flutter/material.dart';
|
||
import '../../../../app/theme/app_colors.dart';
|
||
import '../../../../app/theme/app_typography.dart';
|
||
import '../../../../app/theme/app_spacing.dart';
|
||
|
||
/// A9. P2P转赠页面
|
||
///
|
||
/// 选择好友 → 确认转赠 → 转赠成功
|
||
/// 零区块链术语:使用"转赠"而非"转移NFT"
|
||
class TransferPage extends StatefulWidget {
|
||
const TransferPage({super.key});
|
||
|
||
@override
|
||
State<TransferPage> createState() => _TransferPageState();
|
||
}
|
||
|
||
class _TransferPageState extends State<TransferPage> {
|
||
final _searchController = TextEditingController();
|
||
String? _selectedFriend;
|
||
|
||
@override
|
||
Widget build(BuildContext context) {
|
||
return Scaffold(
|
||
appBar: AppBar(title: const Text('转赠给好友')),
|
||
body: Column(
|
||
children: [
|
||
// Coupon Info
|
||
Container(
|
||
margin: const EdgeInsets.all(20),
|
||
padding: AppSpacing.cardPadding,
|
||
decoration: BoxDecoration(
|
||
color: AppColors.surface,
|
||
borderRadius: AppSpacing.borderRadiusMd,
|
||
border: Border.all(color: AppColors.borderLight),
|
||
),
|
||
child: Row(
|
||
children: [
|
||
Container(
|
||
width: 48,
|
||
height: 48,
|
||
decoration: BoxDecoration(
|
||
color: AppColors.primarySurface,
|
||
borderRadius: AppSpacing.borderRadiusSm,
|
||
),
|
||
child: const Icon(Icons.card_giftcard_rounded, color: AppColors.primary),
|
||
),
|
||
const SizedBox(width: 12),
|
||
Expanded(
|
||
child: Column(
|
||
crossAxisAlignment: CrossAxisAlignment.start,
|
||
children: [
|
||
Text('星巴克 \$25 礼品卡', style: AppTypography.labelMedium),
|
||
Text('面值 \$25.00', style: AppTypography.bodySmall),
|
||
],
|
||
),
|
||
),
|
||
],
|
||
),
|
||
),
|
||
|
||
// Search Friend
|
||
Padding(
|
||
padding: const EdgeInsets.symmetric(horizontal: 20),
|
||
child: TextField(
|
||
controller: _searchController,
|
||
decoration: const InputDecoration(
|
||
hintText: '搜索好友(手机号/用户名)',
|
||
prefixIcon: Icon(Icons.search_rounded),
|
||
),
|
||
),
|
||
),
|
||
const SizedBox(height: 16),
|
||
|
||
// Friends List
|
||
Expanded(
|
||
child: ListView(
|
||
padding: const EdgeInsets.symmetric(horizontal: 20),
|
||
children: [
|
||
_buildFriendTile('Alice', 'alice@example.com', 'A'),
|
||
_buildFriendTile('Bob', 'bob@example.com', 'B'),
|
||
_buildFriendTile('Charlie', 'charlie@example.com', 'C'),
|
||
_buildFriendTile('Diana', 'diana@example.com', 'D'),
|
||
],
|
||
),
|
||
),
|
||
|
||
// Transfer Button
|
||
Container(
|
||
padding: const EdgeInsets.all(20),
|
||
child: SizedBox(
|
||
width: double.infinity,
|
||
height: AppSpacing.buttonHeight,
|
||
child: ElevatedButton(
|
||
onPressed: _selectedFriend != null ? () => _showConfirm(context) : null,
|
||
child: Text(_selectedFriend != null ? '转赠给 $_selectedFriend' : '请选择好友'),
|
||
),
|
||
),
|
||
),
|
||
],
|
||
),
|
||
);
|
||
}
|
||
|
||
Widget _buildFriendTile(String name, String email, String avatar) {
|
||
final isSelected = _selectedFriend == name;
|
||
return GestureDetector(
|
||
onTap: () => setState(() => _selectedFriend = name),
|
||
child: Container(
|
||
margin: const EdgeInsets.only(bottom: 8),
|
||
padding: const EdgeInsets.all(14),
|
||
decoration: BoxDecoration(
|
||
color: AppColors.surface,
|
||
borderRadius: AppSpacing.borderRadiusMd,
|
||
border: Border.all(
|
||
color: isSelected ? AppColors.primary : AppColors.borderLight,
|
||
width: isSelected ? 1.5 : 1,
|
||
),
|
||
),
|
||
child: Row(
|
||
children: [
|
||
CircleAvatar(
|
||
radius: 20,
|
||
backgroundColor: AppColors.primaryContainer,
|
||
child: Text(avatar, style: const TextStyle(color: AppColors.primary, fontWeight: FontWeight.w600)),
|
||
),
|
||
const SizedBox(width: 12),
|
||
Expanded(
|
||
child: Column(
|
||
crossAxisAlignment: CrossAxisAlignment.start,
|
||
children: [
|
||
Text(name, style: AppTypography.labelMedium),
|
||
Text(email, style: AppTypography.caption),
|
||
],
|
||
),
|
||
),
|
||
if (isSelected) const Icon(Icons.check_circle_rounded, color: AppColors.primary, size: 22),
|
||
],
|
||
),
|
||
),
|
||
);
|
||
}
|
||
|
||
void _showConfirm(BuildContext context) {
|
||
showModalBottomSheet(
|
||
context: context,
|
||
builder: (ctx) => Padding(
|
||
padding: const EdgeInsets.all(24),
|
||
child: Column(
|
||
mainAxisSize: MainAxisSize.min,
|
||
children: [
|
||
const Icon(Icons.card_giftcard_rounded, color: AppColors.primary, size: 48),
|
||
const SizedBox(height: 16),
|
||
Text('确认转赠', style: AppTypography.h2),
|
||
const SizedBox(height: 8),
|
||
Text('将 星巴克 \$25 礼品卡 转赠给 $_selectedFriend?', style: AppTypography.bodyMedium.copyWith(color: AppColors.textSecondary)),
|
||
const SizedBox(height: 8),
|
||
Text('转赠后您将不再持有此券', style: AppTypography.caption.copyWith(color: AppColors.warning)),
|
||
const SizedBox(height: 24),
|
||
Row(
|
||
children: [
|
||
Expanded(
|
||
child: OutlinedButton(
|
||
onPressed: () => Navigator.pop(ctx),
|
||
child: const Text('取消'),
|
||
),
|
||
),
|
||
const SizedBox(width: 12),
|
||
Expanded(
|
||
child: ElevatedButton(
|
||
onPressed: () {
|
||
Navigator.pop(ctx);
|
||
_showSuccess(context);
|
||
},
|
||
child: const Text('确认转赠'),
|
||
),
|
||
),
|
||
],
|
||
),
|
||
],
|
||
),
|
||
),
|
||
);
|
||
}
|
||
|
||
void _showSuccess(BuildContext context) {
|
||
showDialog(
|
||
context: context,
|
||
builder: (ctx) => AlertDialog(
|
||
content: Column(
|
||
mainAxisSize: MainAxisSize.min,
|
||
children: [
|
||
const Icon(Icons.check_circle_rounded, color: AppColors.success, size: 56),
|
||
const SizedBox(height: 16),
|
||
Text('转赠成功', style: AppTypography.h2),
|
||
const SizedBox(height: 8),
|
||
Text('$_selectedFriend 已收到您的券', style: AppTypography.bodyMedium.copyWith(color: AppColors.textSecondary)),
|
||
],
|
||
),
|
||
actions: [
|
||
TextButton(
|
||
onPressed: () {
|
||
Navigator.pop(ctx);
|
||
Navigator.pop(context);
|
||
},
|
||
child: const Text('确定'),
|
||
),
|
||
],
|
||
),
|
||
);
|
||
}
|
||
}
|