import 'package:flutter/material.dart'; import '../colors/app_colors.dart'; import 'package:url_launcher/url_launcher.dart'; import '../strings/consultorios_strings.dart'; import '../widgets/pill_snackbar.dart'; import '../widgets/tap_bounce.dart'; import 'clinic.dart'; /// Cartão de um consultório — reutilizado no separador Consultórios e na /// pré-visualização "Consultórios próximos" da Home. A Overpass API não /// devolve fotos, por isso a caixa de imagem é sempre um placeholder liso /// (sem ícone). class ClinicCard extends StatelessWidget { const ClinicCard({ super.key, required this.clinic, required this.isFavorite, required this.onToggleFavorite, }); final Clinic clinic; final bool isFavorite; final ValueChanged onToggleFavorite; Future _call(BuildContext context, String number) async { final uri = Uri(scheme: 'tel', path: number); try { final launched = await launchUrl(uri); if (!launched && context.mounted) { showPillSnackBar(context, ConsultoriosStrings.noPhoneAppAvailable); } } catch (e) { if (context.mounted) showPillSnackBar(context, ConsultoriosStrings.callFailed(e)); } } /// Um consultório na OSM pode listar vários contactos na mesma tag — em /// vez de tentar ligar para o texto todo (o que nem é um número válido), /// mostra-se este seletor para escolher qual dos números ligar. Future _showNumberPicker(BuildContext context) async { final chosen = await showModalBottomSheet( context: context, showDragHandle: true, backgroundColor: AppColors.pinkBackground, shape: const RoundedRectangleBorder( borderRadius: BorderRadius.vertical(top: Radius.circular(24)), ), builder: (ctx) { return SafeArea( child: Padding( padding: const EdgeInsets.fromLTRB(18, 4, 18, 18), child: Column( mainAxisSize: MainAxisSize.min, crossAxisAlignment: CrossAxisAlignment.stretch, children: [ Text( ConsultoriosStrings.chooseNumberTitle, textAlign: TextAlign.center, style: const TextStyle( fontSize: 16, fontWeight: FontWeight.w900, color: AppColors.pink, ), ), const SizedBox(height: 14), for (final number in clinic.phoneNumbers) ...[ TapBounce( scale: 0.98, child: Material( color: Colors.white, borderRadius: BorderRadius.circular(14), child: InkWell( borderRadius: BorderRadius.circular(14), onTap: () => Navigator.of(ctx).pop(number), child: Padding( padding: const EdgeInsets.symmetric( horizontal: 16, vertical: 14, ), child: Row( children: [ const Icon( Icons.call_rounded, color: AppColors.teal, size: 18, ), const SizedBox(width: 10), Expanded( child: Text( number, style: const TextStyle( fontWeight: FontWeight.w800, ), ), ), ], ), ), ), ), ), const SizedBox(height: 10), ], ], ), ), ); }, ); if (chosen != null && context.mounted) await _call(context, chosen); } @override Widget build(BuildContext context) { return Container( padding: const EdgeInsets.all(14), decoration: BoxDecoration( color: Colors.white, borderRadius: BorderRadius.circular(18), boxShadow: [ BoxShadow( color: Colors.black.withValues(alpha: 0.06), blurRadius: 14, offset: const Offset(0, 8), ), ], ), child: Column( crossAxisAlignment: CrossAxisAlignment.stretch, children: [ Row( crossAxisAlignment: CrossAxisAlignment.start, children: [ Expanded( child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Row( crossAxisAlignment: CrossAxisAlignment.start, children: [ Expanded( child: Text( clinic.name, style: const TextStyle( fontWeight: FontWeight.w900, fontSize: 14.5, color: AppColors.teal, ), ), ), TapBounce( scale: 0.85, child: InkWell( borderRadius: BorderRadius.circular(999), onTap: () => onToggleFavorite(clinic.id), child: Padding( padding: const EdgeInsets.all(2), child: Icon( isFavorite ? Icons.favorite_rounded : Icons.favorite_border_rounded, size: 20, color: isFavorite ? AppColors.pink : Colors.black.withValues(alpha: 0.3), ), ), ), ), ], ), if (clinic.distanceKm != null) ...[ const SizedBox(height: 2), Text( '${clinic.distanceKm!.toStringAsFixed(1)} ${ConsultoriosStrings.distanceKm}', style: TextStyle( fontSize: 12, fontWeight: FontWeight.w700, color: Colors.black.withValues(alpha: 0.45), ), ), ], const SizedBox(height: 6), _ClinicInfoRow( icon: Icons.access_time_rounded, text: clinic.openingHours, muted: !clinic.hasOpeningHours, ), const SizedBox(height: 3), _ClinicInfoRow( icon: Icons.place_outlined, text: clinic.address, muted: false, ), ], ), ), ], ), const SizedBox(height: 10), _buildPhoneButton(context), ], ), ); } Widget _buildPhoneButton(BuildContext context) { final numbers = clinic.phoneNumbers; final String label; final VoidCallback? onTap; if (numbers.isEmpty) { label = ConsultoriosStrings.noPhone; onTap = null; } else if (numbers.length == 1) { label = numbers.first; onTap = () => _call(context, numbers.first); } else { label = ConsultoriosStrings.chooseNumber(numbers.length); onTap = () => _showNumberPicker(context); } final enabled = onTap != null; final color = enabled ? Colors.white : Colors.black.withValues(alpha: 0.35); return TapBounce( child: Material( color: enabled ? AppColors.teal : Colors.black.withValues(alpha: 0.06), borderRadius: BorderRadius.circular(999), child: InkWell( borderRadius: BorderRadius.circular(999), onTap: onTap, child: Padding( padding: const EdgeInsets.symmetric(vertical: 11, horizontal: 12), child: Row( mainAxisAlignment: MainAxisAlignment.center, children: [ Icon( enabled ? Icons.call_rounded : Icons.call_outlined, size: 16, color: color, ), const SizedBox(width: 8), Flexible( child: Text( label, maxLines: 1, overflow: TextOverflow.ellipsis, style: TextStyle( fontWeight: FontWeight.w800, fontSize: 13, color: color, ), ), ), ], ), ), ), ), ); } } class _ClinicInfoRow extends StatelessWidget { const _ClinicInfoRow({ required this.icon, required this.text, required this.muted, }); final IconData icon; final String text; final bool muted; @override Widget build(BuildContext context) { final color = Colors.black.withValues(alpha: muted ? 0.35 : 0.6); return Row( crossAxisAlignment: CrossAxisAlignment.start, children: [ Icon(icon, size: 14, color: color), const SizedBox(width: 6), Expanded( child: Text( text, style: TextStyle( fontSize: 12, fontWeight: FontWeight.w600, fontStyle: muted ? FontStyle.italic : FontStyle.normal, color: color, ), ), ), ], ); } }