import 'package:cloud_firestore/cloud_firestore.dart'; import 'package:firebase_messaging/firebase_messaging.dart'; import 'package:firebase_storage/firebase_storage.dart'; import 'package:flutter/cupertino.dart'; import 'package:flutter/foundation.dart'; import 'package:flutter/gestures.dart'; import 'package:flutter/material.dart'; import 'package:geocoding/geocoding.dart'; import 'package:geolocator/geolocator.dart'; import 'package:get/get.dart'; import 'package:google_maps_flutter/google_maps_flutter.dart'; import 'package:prosappco/constansts.dart'; import 'package:prosappco/src/authentication/authentication_repository.dart'; import 'package:prosappco/src/components/drawer_menu.dart'; import 'package:prosappco/src/components/network_utility.dart'; import 'package:prosappco/src/models/event_model.dart'; import 'package:prosappco/src/models/user_model.dart'; import 'package:prosappco/src/screens/professional.dart'; import 'package:intl/intl.dart'; import 'package:prosappco/src/screens/profile.dart'; import 'package:prosappco/src/screens/service_after.dart'; import 'package:prosappco/src/screens/service_type.dart'; import 'package:flutter/foundation.dart'; class ServiceScreen extends StatefulWidget { const ServiceScreen({super.key}); @override State createState() => _ServiceScreenState(); } class _ServiceScreenState extends State { EventoService eventoService = EventoService(); final TextEditingController _locationController = TextEditingController(); String _locationPosition = ''; String ubicacion = ''; final _profesionalController = TextEditingController(); final _serviceTypeController = TextEditingController(); final _observacionController = TextEditingController(); String professionalId = ''; int? professionalTarifa; String professionalAddress = ''; String professionalUbicacion = ''; double? professionalLatitude; double? professionalLongitude; String _serviceType = 'Servicio'; String _professional = ''; final DateFormat formatter = DateFormat('dd/MM/yyyy'); final DateTime now = DateTime.now(); DateTime? _selectedDate; TimeOfDay? _selectedTime; late GoogleMapController googleMapController; static CameraPosition initialCameraPosition = const CameraPosition( target: LatLng(7.8939100, -72.5078200), zoom: 14.4746, ); Set markers = {}; Future _determinePosition() async { bool serviceEnabled; LocationPermission permission; serviceEnabled = await Geolocator.isLocationServiceEnabled(); if (!serviceEnabled) { return Future.error('Location services are disabled'); } permission = await Geolocator.checkPermission(); if (permission == LocationPermission.denied) { permission = await Geolocator.requestPermission(); if (permission == LocationPermission.denied) { return Future.error('Location permission denied'); } } if (permission == LocationPermission.deniedForever) { return Future.error('Location permissions are permanently denied'); } Position position = await Geolocator.getCurrentPosition(); return position; } Future _selectDate(BuildContext context) async { final DateTime? picked = await showDatePicker( context: context, initialDate: now, firstDate: now, lastDate: DateTime(now.year + 1), // builder: (context, child) { // return Theme(data: ThemeData.dark(), child: child!); // }, ); if (picked != null && picked != _selectedDate) { setState(() { _selectedDate = picked; }); } } Future _selectTime(BuildContext context) async { final TimeOfDay? pickedTime = await showTimePicker( context: context, initialTime: TimeOfDay.now(), // builder: (context, child) { // return Theme(data: ThemeData.dark(), child: child!); // }, ); if (pickedTime != null) { setState(() { _selectedTime = pickedTime; }); } } Future>>> getUsersWithActiveStatus() async { var querySnapshot = await FirebaseFirestore.instance .collection('users') .where('estado', isEqualTo: 'activo') .get(); return querySnapshot.docs; } final FirebaseStorage storage = FirebaseStorage.instance; final uid = AuthenticationRepository.instance.getCurrentUserUid(); UserModel? user; final fcmToken = FirebaseMessaging.instance.getToken(); BitmapDescriptor? _markerIcon; @override void initState() { super.initState(); final userRef = FirebaseFirestore.instance.collection('users').doc(uid); if (user == null) { UserModel.getUser(uid.toString()).then( (UserModel s) => setState(() => user = s), ); } BitmapDescriptor.fromAssetImage( const ImageConfiguration(size: Size(48, 48)), 'images/pro_marke.png') .then((icon) { setState(() { _markerIcon = icon; }); }); try { getUsersWithActiveStatus().then((value) { for (var doc in value) { final element = doc.data()!; if (element['latitude'] != null && element['longitude'] != null) { markers.add( Marker( icon: _markerIcon!, markerId: MarkerId(doc.id), position: LatLng( element['latitude'], element['longitude'], ), ), ); } } }); } catch (e) { print('error coordenadas $e'); } } late String lat; late String long; var coordinates; Future getLocationName(double latitude, double longitude) async { String address; List placemarks = await placemarkFromCoordinates(latitude, longitude); Placemark place = placemarks[0]; if (place.thoroughfare != '' || place.subThoroughfare != '') { address = "${place.thoroughfare} ${place.subThoroughfare} ${place.subLocality}, ${place.locality}, ${place.administrativeArea}"; } else { address = ''; } return address; } void placeAutoComplete(String query) async { Uri uri = Uri.https("maps.googleapis.com", "maps/api/place/autocomplete/json", { "input": query, "key": apiKey, }); String? response = await NetworkUtility.fetchUrl(uri); if (response != null) { print(response); } } @override Widget build(BuildContext context) { if (kIsWeb) { return Scaffold( drawer: DrawerMenu(), appBar: AppBar( elevation: 0, title: Row( children: [ Container( padding: const EdgeInsets.only(right: 10), decoration: const BoxDecoration( border: Border( right: BorderSide( color: Colors.white, width: 1.0, ), ), ), child: const Text( 'Prosapp', ), ), const SizedBox(width: 8), TextButton( style: TextButton.styleFrom( foregroundColor: Colors.white, ), onPressed: () { showDialog( context: context, builder: (context) { return _EnterLocationDialog(); }, ); }, child: const Row( children: [ Icon(Icons.location_on), SizedBox(width: 8), Text('Ingresar mi ubicación'), SizedBox(width: 4), Icon(Icons.keyboard_arrow_down_rounded, size: 16), ], ), ), ], ), // Texto del título ), body: Container( child: ElevatedButton( onPressed: () { placeAutoComplete("Dubai"); }, style: ElevatedButton.styleFrom( backgroundColor: const Color(0xFF2BA4EC), shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(50), ), elevation: 0, minimumSize: const Size(230, 50), ), child: const Text( 'Aceptar', style: TextStyle( color: Colors.white, fontWeight: FontWeight.bold, fontSize: 18, ), ), ), ), ); } return SafeArea( child: Scaffold( backgroundColor: const Color(0xFFD6F4FF), drawer: DrawerMenu(), body: SingleChildScrollView( reverse: true, child: Column( children: [ Stack( children: [ SizedBox( height: MediaQuery.of(context).size.height * 0.6, child: GoogleMap( mapType: MapType.normal, initialCameraPosition: initialCameraPosition, markers: markers, zoomControlsEnabled: false, onMapCreated: (GoogleMapController controller) { googleMapController = controller; }, onCameraIdle: () { if (professionalAddress == '') { if (coordinates != null) { getLocationName( coordinates.latitude, coordinates.longitude) .then((locationName) { setState(() { _locationController.text = locationName; }); }); } } }, onCameraMove: (position) { setState(() { coordinates = position.target; }); }, gestureRecognizers: >{ Factory( () => EagerGestureRecognizer(), ), }, ), ), const Positioned( bottom: 25, right: 0, left: 0, top: 0, child: Icon( Icons.location_on, size: 40, color: Color(0xFFFF0000), ), ), Positioned( bottom: 10, right: 20, child: FloatingActionButton( onPressed: () async { try { Position position = await _determinePosition(); googleMapController.animateCamera( CameraUpdate.newCameraPosition( CameraPosition( target: LatLng( position.latitude, position.longitude, ), zoom: 17), ), ); setState(() {}); } catch (e) { Get.snackbar( 'ubicación desactivada', 'Por favor activa la ubicacion de tu telefono.', snackPosition: SnackPosition.TOP, ); } // markers.clear(); }, elevation: 0, child: const Icon( Icons.gps_fixed, size: 30, ), ), ), Padding( padding: const EdgeInsets.all(20.0), child: Builder( builder: (BuildContext context) { return ElevatedButton( style: ElevatedButton.styleFrom( backgroundColor: Colors.white, shape: const CircleBorder(), elevation: 3, minimumSize: const Size(50, 50), ), child: const Icon( Icons.menu, color: Colors.black, size: 30, ), onPressed: () { Scaffold.of(context).openDrawer(); }, ); }, ), ), Padding( padding: const EdgeInsets.only(top: 22, left: 100, right: 25), child: Container( decoration: BoxDecoration( borderRadius: BorderRadius.circular(50), color: Colors.white, boxShadow: [ BoxShadow( color: Colors.grey.withOpacity(0.4), spreadRadius: 1, blurRadius: 2, offset: const Offset(1, 2), ), ], ), child: Padding( padding: const EdgeInsets.symmetric(horizontal: 20), child: TextFormField( onTap: () async { final String? serviceType = await Navigator.push( context, CupertinoPageRoute( builder: (BuildContext context) { return const ServiceTypeScreen(); }, ), ) as String?; if (serviceType != null) { setState(() { _serviceType = serviceType; _serviceTypeController.text = _serviceType; }); } }, controller: _serviceTypeController, style: const TextStyle( color: Colors.black87, fontWeight: FontWeight.w600, ), readOnly: true, decoration: InputDecoration( hintText: _serviceType == '' ? 'Servicio' : _serviceType, hintStyle: const TextStyle( color: Colors.black87, fontWeight: FontWeight.w600), border: InputBorder.none, enabledBorder: InputBorder.none, ), ), ), ), ), ], ), Container( width: double.infinity, decoration: const BoxDecoration(color: Colors.white), child: Column( children: [ const SizedBox(height: 5), SizedBox( width: 320, child: Form( child: Column( children: [ Column( children: [ TextFormField( readOnly: true, controller: _locationController, decoration: const InputDecoration( prefixIcon: Icon(Icons.near_me), hintText: 'Dirección', ), ), ], ), const SizedBox(height: 15), TextFormField( controller: _profesionalController, readOnly: true, onTap: () async { final dynamic datos = await Navigator.push( context, CupertinoPageRoute( builder: (BuildContext context) { return ProfessionalScreen( profession: _serviceTypeController.text, ); }, ), ); if (datos != null) { Professional? profesional = datos[0]; ubicacion = datos[1]; if (profesional != null) { setState(() { _profesionalController.text = profesional.name.toString(); professionalId = profesional.id; professionalTarifa = profesional.tarifa ?? 0; professionalUbicacion = profesional.ubicacion; professionalLatitude = profesional.latitude; professionalLongitude = profesional.longitude; if (ubicacion == 'sitio') { professionalAddress = profesional.realAddress; _locationController.text = profesional.realAddress; if (professionalLatitude != null && professionalLatitude != 0 && professionalLongitude != null && professionalLongitude != 0) { googleMapController.animateCamera( CameraUpdate.newCameraPosition( CameraPosition( target: LatLng( professionalLatitude!, professionalLongitude!, ), zoom: 17), ), ); } } }); } } }, decoration: const InputDecoration( prefixIcon: Icon(Icons.assignment_ind_rounded), suffixIcon: Icon(Icons.arrow_drop_down), hintText: 'Seleccionar profesional'), ), const SizedBox(height: 15), Row( children: [ SizedBox( width: 180, child: TextFormField( onTap: () { if (_profesionalController .text.isNotEmpty) { _selectDate(context); } else { final snackBar = SnackBar( backgroundColor: Colors.blue, content: const Text( 'Selecciona un profesional', style: TextStyle( color: Colors.white, fontWeight: FontWeight.bold, ), ), elevation: 8.0, shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(10.0), ), ); ScaffoldMessenger.of(context) .showSnackBar(snackBar); } }, readOnly: true, decoration: InputDecoration( prefixIcon: const Icon(Icons.calendar_month), suffixIcon: _selectedDate == null ? const Icon(Icons.arrow_drop_down) : null, hintText: 'Fecha', ), controller: TextEditingController( text: _selectedDate == null ? '' : formatter.format(_selectedDate!)), ), ), SizedBox( width: 140, child: TextFormField( onTap: () { if (_profesionalController .text.isNotEmpty) { _selectTime(context); } else { final snackBar = SnackBar( backgroundColor: Colors.blue, content: const Text( 'Selecciona un profesional', style: TextStyle( color: Colors.white, fontWeight: FontWeight.bold, ), ), elevation: 8.0, shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(10.0), ), ); ScaffoldMessenger.of(context) .showSnackBar(snackBar); } }, readOnly: true, decoration: const InputDecoration( suffixIcon: Icon(Icons.arrow_drop_down), hintText: 'Hora', ), controller: TextEditingController( text: _selectedTime == null ? '' : ' ${_selectedTime!.format(context)}'), ), ), ], ), const SizedBox(height: 15), TextFormField( controller: _observacionController, decoration: const InputDecoration( prefixIcon: Icon(Icons.message_outlined), hintText: 'Observaciones'), ), const SizedBox(height: 20), ElevatedButton( onPressed: () { if (user?.name == null || user?.name == '' || user?.phoneNumber == null || user?.phoneNumber == '') { Navigator.push( context, CupertinoPageRoute( builder: (BuildContext context) { return const ProfileScreen(); }, ), ); } else { try { final DateTime combinedDate = DateTime( _selectedDate!.year, _selectedDate!.month, _selectedDate!.day, _selectedTime!.hour, _selectedTime!.minute); DateTime time2 = combinedDate .add(const Duration(hours: 2)); UserModel.getUser(uid.toString()) .then((value) { eventoService .createEvent( value.name, _observacionController.text, '$_selectedDate', '$combinedDate', '$time2', professionalId, ubicacion, _locationController.text, ubicacion != 'sitio' ? coordinates.latitude : professionalLatitude, ubicacion != 'sitio' ? coordinates.longitude : professionalLongitude, 'pendiente', professionalTarifa == 0 ? 0 : professionalTarifa, false, false, ) .then((value) { Navigator.pushReplacement( context, CupertinoPageRoute( builder: (BuildContext context) { return ServiceAfterScreen( eventoId: value, ); }, ), ); }); }); } catch (e) { Get.snackbar( 'Llena todos los campos', 'Asegurate de llenar todos los campos.', snackPosition: SnackPosition.BOTTOM, ); } } }, style: ElevatedButton.styleFrom( backgroundColor: const Color(0xFF2BA4EC), shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(50), ), elevation: 0, minimumSize: const Size(230, 50), ), child: const Text( 'Solicitar servicio', style: TextStyle( color: Colors.white, fontWeight: FontWeight.bold, fontSize: 18, ), ), ), //Text('${_selectedDate?.weekday}'), ], ), ), ), ], ), ), ], ), ), ), ); } } class _EnterLocationDialog extends StatelessWidget { const _EnterLocationDialog({super.key}); void placeAutoComplete(String query) async { Uri uri = Uri.https("maps.googleapis.com", "/maps/api/place/autocomplete/json", { "input": query, "key": apiKey, }); String? response = await NetworkUtility.fetchUrl(uri); if (response != null) { print(response); } } @override Widget build(BuildContext context) { return AlertDialog( content: SizedBox( height: 200, child: Column( children: [ const Text( 'Ingresa la ubicación', style: TextStyle( fontWeight: FontWeight.bold, fontSize: 18, ), ), const SizedBox(height: 20), TextFormField( decoration: const InputDecoration( hintText: 'Escribe tu ubicación', ), ), const SizedBox(height: 20), ElevatedButton( onPressed: () { placeAutoComplete("Dubai"); }, style: ElevatedButton.styleFrom( backgroundColor: const Color(0xFF2BA4EC), shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(50), ), elevation: 0, minimumSize: const Size(230, 50), ), child: const Text( 'Aceptar', style: TextStyle( color: Colors.white, fontWeight: FontWeight.bold, fontSize: 18, ), ), ), ], ), ), ); } }