import 'dart:async'; import 'package:flutter/material.dart'; import 'package:lunchpick/core/constants/app_colors.dart'; import 'package:lunchpick/core/constants/app_typography.dart'; import 'package:lunchpick/core/utils/distance_calculator.dart'; import 'package:lunchpick/domain/entities/restaurant.dart'; enum RecommendationDialogResult { confirm, reroll, autoConfirm } class RecommendationResultDialog extends StatefulWidget { final Restaurant restaurant; final Duration autoConfirmDuration; final double? currentLatitude; final double? currentLongitude; const RecommendationResultDialog({ super.key, required this.restaurant, this.autoConfirmDuration = const Duration(seconds: 12), this.currentLatitude, this.currentLongitude, }); @override State createState() => _RecommendationResultDialogState(); } class _RecommendationResultDialogState extends State { Timer? _autoConfirmTimer; bool _didComplete = false; double? _distanceKm; @override void initState() { super.initState(); _calculateDistance(); _startAutoConfirmTimer(); } @override void dispose() { _autoConfirmTimer?.cancel(); super.dispose(); } void _startAutoConfirmTimer() { _autoConfirmTimer = Timer(widget.autoConfirmDuration, () { if (!mounted || _didComplete) return; _didComplete = true; Navigator.of(context).pop(RecommendationDialogResult.autoConfirm); }); } void _calculateDistance() { final lat = widget.currentLatitude; final lon = widget.currentLongitude; if (lat == null || lon == null) return; _distanceKm = DistanceCalculator.calculateDistance( lat1: lat, lon1: lon, lat2: widget.restaurant.latitude, lon2: widget.restaurant.longitude, ); } String _formatDistance(double distanceKm) { final meters = distanceKm * 1000; if (meters >= 1000) { return '${distanceKm.toStringAsFixed(1)} km'; } return '${meters.round()} m'; } Future _handleResult(RecommendationDialogResult result) async { if (_didComplete) return; _didComplete = true; _autoConfirmTimer?.cancel(); Navigator.of(context).pop(result); } @override Widget build(BuildContext context) { final isDark = Theme.of(context).brightness == Brightness.dark; return WillPopScope( onWillPop: () async { await _handleResult(RecommendationDialogResult.confirm); return true; }, child: Dialog( backgroundColor: Colors.transparent, child: Container( decoration: BoxDecoration( color: isDark ? AppColors.darkSurface : AppColors.lightSurface, borderRadius: BorderRadius.circular(20), ), child: Column( mainAxisSize: MainAxisSize.min, children: [ Container( height: 150, decoration: BoxDecoration( color: AppColors.lightPrimary, borderRadius: const BorderRadius.vertical( top: Radius.circular(20), ), ), child: Stack( children: [ Center( child: Column( mainAxisAlignment: MainAxisAlignment.center, children: [ const Icon( Icons.restaurant_menu, size: 64, color: Colors.white, ), const SizedBox(height: 8), Text( '오늘의 추천!', style: AppTypography.heading2( false, ).copyWith(color: Colors.white), ), ], ), ), Positioned( top: 8, right: 8, child: IconButton( icon: const Icon(Icons.close, color: Colors.white), onPressed: () async { await _handleResult( RecommendationDialogResult.confirm, ); }, ), ), ], ), ), Padding( padding: const EdgeInsets.all(24), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Center( child: Text( widget.restaurant.name, style: AppTypography.heading1(isDark), textAlign: TextAlign.center, ), ), const SizedBox(height: 8), Center( child: Container( padding: const EdgeInsets.symmetric( horizontal: 12, vertical: 4, ), decoration: BoxDecoration( color: AppColors.lightPrimary.withOpacity(0.1), borderRadius: BorderRadius.circular(12), ), child: Text( '${widget.restaurant.category} > ${widget.restaurant.subCategory}', style: AppTypography.body2( isDark, ).copyWith(color: AppColors.lightPrimary), ), ), ), if (widget.restaurant.description != null) ...[ const SizedBox(height: 16), Text( widget.restaurant.description!, style: AppTypography.body2(isDark), textAlign: TextAlign.center, ), ], const SizedBox(height: 16), const Divider(), const SizedBox(height: 16), Row( children: [ Icon( Icons.location_on, size: 20, color: isDark ? AppColors.darkTextSecondary : AppColors.lightTextSecondary, ), const SizedBox(width: 8), Expanded( child: Text( widget.restaurant.roadAddress, style: AppTypography.body2(isDark), ), ), ], ), if (_distanceKm != null) ...[ const SizedBox(height: 8), Row( children: [ Icon( Icons.place, size: 20, color: AppColors.lightPrimary, ), const SizedBox(width: 8), Text( _formatDistance(_distanceKm!), style: AppTypography.body2(isDark).copyWith( color: AppColors.lightPrimary, fontWeight: FontWeight.w600, ), ), ], ), ], if (widget.restaurant.phoneNumber != null) ...[ const SizedBox(height: 8), Row( children: [ Icon( Icons.phone, size: 20, color: isDark ? AppColors.darkTextSecondary : AppColors.lightTextSecondary, ), const SizedBox(width: 8), Text( widget.restaurant.phoneNumber!, style: AppTypography.body2(isDark), ), ], ), ], const SizedBox(height: 24), Row( children: [ Expanded( child: OutlinedButton( onPressed: () async { await _handleResult( RecommendationDialogResult.reroll, ); }, style: OutlinedButton.styleFrom( padding: const EdgeInsets.symmetric(vertical: 12), side: const BorderSide( color: AppColors.lightPrimary, ), shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(8), ), ), child: const Text( '다시 뽑기', style: TextStyle(color: AppColors.lightPrimary), ), ), ), const SizedBox(width: 12), Expanded( child: ElevatedButton( onPressed: () async { await _handleResult( RecommendationDialogResult.confirm, ); }, style: ElevatedButton.styleFrom( padding: const EdgeInsets.symmetric(vertical: 12), backgroundColor: AppColors.lightPrimary, foregroundColor: Colors.white, shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(8), ), ), child: const Text('오늘의 선택!'), ), ), ], ), const SizedBox(height: 8), Text( '앱을 종료하면 자동으로 선택이 확정됩니다.', style: AppTypography.caption(isDark), textAlign: TextAlign.center, ), ], ), ), ], ), ), ), ); } }