import 'dart:io'; import 'package:flutter/material.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:go_router/go_router.dart'; import 'package:image_picker/image_picker.dart'; import '../../core/app_colors.dart'; import '../../domain/usecase/finish_ride_usecase.dart'; import '../components/custom_app_bar.dart'; import '../components/gradient_button.dart'; import '../viewmodel/send_photo_bloc.dart'; import '../event/send_photo_event.dart'; import '../state/send_photo_state.dart'; import '../../domain/usecase/upload_scooter_photos_usecase.dart'; import '../../di/service_locator.dart' as di; class SendPhotoScreen extends StatelessWidget { final int orderId; const SendPhotoScreen({super.key, required this.orderId}); @override Widget build(BuildContext context) { return BlocProvider( create: (context) => SendPhotoBloc( di.getIt(), di.getIt(), ), child: SendPhotoView(orderId: orderId), ); } } class SendPhotoView extends StatefulWidget { final int orderId; const SendPhotoView({super.key, required this.orderId}); @override State createState() => _SendPhotoViewState(); } class _SendPhotoViewState extends State { final ImagePicker _imagePicker = ImagePicker(); // Метод для выбора фото (добавляет к существующим) Future _pickImage() async { await showModalBottomSheet( context: context, shape: const RoundedRectangleBorder( borderRadius: BorderRadius.vertical(top: Radius.circular(20)), ), builder: (BuildContext context) { return SafeArea( child: Wrap( children: [ ListTile( leading: const Icon(Icons.camera_alt), title: const Text('Сделать фото'), onTap: () { Navigator.pop(context); _getImage(ImageSource.camera); }, ), ListTile( leading: const Icon(Icons.photo_library), title: const Text('Выбрать из галереи'), onTap: () { Navigator.pop(context); _getImage(ImageSource.gallery); }, ), ListTile( leading: const Icon(Icons.cancel), title: const Text('Отмена'), onTap: () { Navigator.pop(context); }, ), ], ), ); }, ); } // ✅ Метод для получения изображения из выбранного источника Future _getImage(ImageSource source) async { final XFile? pickedFile = await _imagePicker.pickImage( source: source, imageQuality: 80, ); if (pickedFile != null && mounted) { final currentImages = context.read().state.selectedImages; context.read().add( PhotoSelected([...currentImages, pickedFile.path]), ); } } // Метод для удаления конкретного фото void _removeImage(String path) { final currentImages = context.read().state.selectedImages; final updatedList = currentImages.where((p) => p != path).toList(); context.read().add(PhotoSelected(updatedList)); } // ✅ Динамический заголовок в зависимости от количества фото String _getTopText(int photoCount) { if (photoCount == 0) { return 'Для завершения аренды\nсфотографируйте самокат'; } else if (photoCount == 1) { return 'Сделайте фото руля самоката'; } else { return 'Отправьте фото на проверку'; } } @override Widget build(BuildContext context) { return Scaffold( body: Container( width: double.infinity, decoration: const BoxDecoration(gradient: AppColors.phoneScreenBg), child: SafeArea( child: Column( children: [ Padding( padding: const EdgeInsets.symmetric(horizontal: 20, vertical: 100), child: Text( _getTopText(context.select((SendPhotoBloc bloc) => bloc.state.selectedImages.length)), textAlign: TextAlign.center, style: const TextStyle( color: Colors.white, fontSize: 20, fontWeight: FontWeight.bold, height: 1.4, ), ), ), // Основной контент центрируем Expanded( child: Center( child: SingleChildScrollView( padding: const EdgeInsets.symmetric(horizontal: 20, vertical: 20), child: Column( mainAxisAlignment: MainAxisAlignment.center, children: [ BlocBuilder( builder: (context, state) { final photoCount = state.selectedImages.length; return Wrap( spacing: 16, runSpacing: 16, alignment: WrapAlignment.center, crossAxisAlignment: WrapCrossAlignment.center, children: [ // Список выбранных фото ...state.selectedImages.map((path) => _buildPhotoThumbnail(path)), const SizedBox(height: 35), // Кнопка "Добавить", если фото меньше лимита (например, 5) if (photoCount < 2) GestureDetector( onTap: _pickImage, child: _buildAddButton(), ), ], ); }, ), const SizedBox(height: 200), // Кнопка отправки BlocConsumer( listener: (context, state) { if (state.status == SendPhotoStatus.success) { context.go('/home/checkout/${widget.orderId}', extra: state.recievedPhotoIds); } else if (state.status == SendPhotoStatus.failure) { ScaffoldMessenger.of(context).showSnackBar( SnackBar(content: Text(state.errorMessage ?? 'Ошибка')), ); } }, builder: (context, state) { final photoCount = state.selectedImages.length; final isEnabled = photoCount >= 2; return GradientButton( text: 'Отправить', onTap: isEnabled ? () => context.read().add(PhotoUploadSubmitted(widget.orderId)) : null, enabled: isEnabled, showArrows: true, height: 56, width: double.infinity, fontSize: 16, ); }, ), ], ), ), ), ), ], ), ), ), ); } // миниатюра с крестиком Widget _buildPhotoThumbnail(String path) { return Stack( clipBehavior: Clip.none, children: [ Container( width: 96, height: 96, decoration: BoxDecoration( borderRadius: BorderRadius.circular(16), boxShadow: [ BoxShadow( color: Colors.black.withOpacity(0.1), blurRadius: 8, offset: const Offset(0, 4), ) ], ), child: ClipRRect( borderRadius: BorderRadius.circular(16), child: Image.file( File(path), fit: BoxFit.cover, ), ), ), // Кнопка удаления (крестик) Positioned( top: -8, right: -8, child: GestureDetector( onTap: () => _removeImage(path), child: Container( padding: const EdgeInsets.all(4), decoration: BoxDecoration( color: Color(0xFF75FBF0), shape: BoxShape.circle, ), child: const Icon( Icons.close, size: 16, color: Color(0xFF242F51), ), ), ), ), ], ); } // Виджет кнопки добавления Widget _buildAddButton() { return Container( width: 96, height: 96, decoration: BoxDecoration( shape: BoxShape.circle, gradient: const LinearGradient( colors: [ Color(0xFF242F51), // полупрозрачный белый Color(0xFF242F51), // ещё более прозрачный ], begin: Alignment.topCenter, end: Alignment.bottomCenter, ), boxShadow: [ // Глубокое свечение BoxShadow( color: Color(0xFF8BFFAA).withOpacity(0.5), blurRadius: 50, spreadRadius: 6, offset: Offset.zero, ), // Внутреннее свечение (для объёма) BoxShadow( color: Color(0xFF8BFFAA).withOpacity(0.2), blurRadius: 10, spreadRadius: -2, offset: Offset.zero, ), ], ), child: const Center( child: Icon( Icons.add, size: 32, color: Colors.white, ), ), ); } }