165 lines
5.3 KiB
Dart
165 lines
5.3 KiB
Dart
import 'package:flutter/material.dart';
|
||
import 'package:flutter_lucide/flutter_lucide.dart';
|
||
|
||
import '../../../core/theme/app_colors.dart';
|
||
import '../../../core/theme/app_spacing.dart';
|
||
|
||
/// [showModalBottomSheet] 返回此值时由**外层页面**调系统相机,避免 BottomSheet 与相机 Activity 叠放导致返回后黑屏/卡死。
|
||
const String kAlbumPickerRequestCamera = '__album_picker_camera__';
|
||
|
||
/// 由外层调用 [ImagePicker](系统照片选择器 / Photo Picker),避免在 Sheet 内嵌套系统选图界面。
|
||
const String kAlbumPickerRequestGallery = '__album_picker_gallery__';
|
||
|
||
/// 底部弹层:拍照 与 从相册选择(Android 使用系统照片选择器,不申请 READ_MEDIA_*)
|
||
class AlbumPickerSheet extends StatelessWidget {
|
||
const AlbumPickerSheet({super.key});
|
||
|
||
@override
|
||
Widget build(BuildContext context) {
|
||
final bottomPad = MediaQuery.paddingOf(context).bottom;
|
||
|
||
return Material(
|
||
color: AppColors.surface,
|
||
borderRadius: const BorderRadius.vertical(top: Radius.circular(16)),
|
||
clipBehavior: Clip.antiAlias,
|
||
child: Column(
|
||
crossAxisAlignment: CrossAxisAlignment.stretch,
|
||
mainAxisSize: MainAxisSize.min,
|
||
children: [
|
||
Padding(
|
||
padding: const EdgeInsets.fromLTRB(
|
||
AppSpacing.sm,
|
||
AppSpacing.sm,
|
||
AppSpacing.sm,
|
||
AppSpacing.md,
|
||
),
|
||
child: Row(
|
||
children: [
|
||
IconButton(
|
||
onPressed: () => Navigator.of(context).pop<String?>(),
|
||
icon: const Icon(LucideIcons.x, color: AppColors.textPrimary),
|
||
),
|
||
const Expanded(
|
||
child: Text(
|
||
'Choose photo',
|
||
textAlign: TextAlign.center,
|
||
style: TextStyle(
|
||
fontSize: 17,
|
||
fontWeight: FontWeight.w600,
|
||
color: AppColors.textPrimary,
|
||
),
|
||
),
|
||
),
|
||
const SizedBox(width: 48),
|
||
],
|
||
),
|
||
),
|
||
const Divider(height: 1, color: AppColors.border),
|
||
Padding(
|
||
padding: EdgeInsets.fromLTRB(
|
||
AppSpacing.lg,
|
||
AppSpacing.lg,
|
||
AppSpacing.lg,
|
||
AppSpacing.xl + bottomPad,
|
||
),
|
||
child: Column(
|
||
children: [
|
||
_ActionCard(
|
||
icon: LucideIcons.camera,
|
||
title: 'Take photo',
|
||
subtitle: 'Use camera',
|
||
onTap: () => Navigator.of(context)
|
||
.pop<String>(kAlbumPickerRequestCamera),
|
||
),
|
||
const SizedBox(height: AppSpacing.md),
|
||
_ActionCard(
|
||
icon: LucideIcons.images,
|
||
title: 'Choose from gallery',
|
||
subtitle: 'System photo picker',
|
||
onTap: () => Navigator.of(context)
|
||
.pop<String>(kAlbumPickerRequestGallery),
|
||
),
|
||
],
|
||
),
|
||
),
|
||
],
|
||
),
|
||
);
|
||
}
|
||
}
|
||
|
||
class _ActionCard extends StatelessWidget {
|
||
const _ActionCard({
|
||
required this.icon,
|
||
required this.title,
|
||
required this.subtitle,
|
||
required this.onTap,
|
||
});
|
||
|
||
final IconData icon;
|
||
final String title;
|
||
final String subtitle;
|
||
final VoidCallback onTap;
|
||
|
||
@override
|
||
Widget build(BuildContext context) {
|
||
return Material(
|
||
color: AppColors.surfaceAlt,
|
||
borderRadius: BorderRadius.circular(14),
|
||
child: InkWell(
|
||
onTap: onTap,
|
||
borderRadius: BorderRadius.circular(14),
|
||
child: Padding(
|
||
padding: const EdgeInsets.symmetric(
|
||
horizontal: AppSpacing.lg,
|
||
vertical: AppSpacing.lg,
|
||
),
|
||
child: Row(
|
||
children: [
|
||
Container(
|
||
width: 52,
|
||
height: 52,
|
||
decoration: BoxDecoration(
|
||
color: AppColors.primary.withValues(alpha: 0.12),
|
||
borderRadius: BorderRadius.circular(12),
|
||
),
|
||
child: Icon(icon, size: 26, color: AppColors.primary),
|
||
),
|
||
const SizedBox(width: AppSpacing.lg),
|
||
Expanded(
|
||
child: Column(
|
||
crossAxisAlignment: CrossAxisAlignment.start,
|
||
children: [
|
||
Text(
|
||
title,
|
||
style: const TextStyle(
|
||
fontSize: 16,
|
||
fontWeight: FontWeight.w600,
|
||
color: AppColors.textPrimary,
|
||
),
|
||
),
|
||
const SizedBox(height: 4),
|
||
Text(
|
||
subtitle,
|
||
style: TextStyle(
|
||
fontSize: 13,
|
||
height: 1.3,
|
||
color: AppColors.textSecondary.withValues(alpha: 0.95),
|
||
),
|
||
),
|
||
],
|
||
),
|
||
),
|
||
Icon(
|
||
LucideIcons.chevron_right,
|
||
size: 20,
|
||
color: AppColors.textSecondary.withValues(alpha: 0.7),
|
||
),
|
||
],
|
||
),
|
||
),
|
||
),
|
||
);
|
||
}
|
||
}
|