import 'dart:io'; import 'package:connectivity_plus/connectivity_plus.dart'; import 'package:flutter/foundation.dart'; import 'package:flutter/gestures.dart'; import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; import 'package:flutter_svg/svg.dart'; import 'package:google_maps_flutter/google_maps_flutter.dart'; import 'package:provider/provider.dart'; import 'package:url_launcher/url_launcher.dart'; import '../../Notifiers/mapProvider.dart'; import '../../Utility/AppColors.dart'; class ContactMap extends StatefulWidget { final accId; final sessionId; const ContactMap({super.key, this.accId, this.sessionId}); @override State createState() => _ContactMapState(); } class _ContactMapState extends State { @override void initState() { super.initState(); WidgetsBinding.instance.addPostFrameCallback((_) { final provider = Provider.of( context, listen: false, ); provider.getLocationPermission(context,widget.accId,widget.sessionId); provider.nearbyServiceLocations(context,widget.accId,widget.sessionId); }); } @override Widget build(BuildContext context) { return Consumer( builder: (context, provider, child) { final isLoading = provider.isLoading; final data = provider.response?.getInTouchList; if (isLoading) { return const Scaffold( backgroundColor: AppColors.backgroundRegular, body: Center( child: CircularProgressIndicator(color: AppColors.buttonColor), ), ); } if (data == null || data.isEmpty) { return const Scaffold( backgroundColor: AppColors.backgroundRegular, body: Center( child: Text("No data found."), ), ); } return SafeArea( child: Scaffold( resizeToAvoidBottomInset: true, backgroundColor: AppColors.backgroundRegular, body: CustomScrollView( slivers: [ SliverAppBar( leading: Container(), stretch: true, backgroundColor: AppColors.backgroundRegular, onStretchTrigger: () async { final provider = Provider.of(context, listen: false); provider.nearbyServiceLocations(context,widget.accId, widget.sessionId); }, stretchTriggerOffset: 300.0, expandedHeight: MediaQuery.of(context).size.height*0.5, flexibleSpace: FlexibleSpaceBar( stretchModes: const [ StretchMode.zoomBackground, StretchMode.blurBackground, ], background: Container( width: double.infinity, decoration: const BoxDecoration(gradient: AppColors.successGradient), child: Column( children: [ SizedBox( height: MediaQuery.of(context).size.height*0.5, child: Stack( children: [ GoogleMap( myLocationEnabled: true, zoomGesturesEnabled: true, zoomControlsEnabled: true, gestureRecognizers: { Factory( () => EagerGestureRecognizer(), ), Factory( () => PanGestureRecognizer(), ), Factory( () => ScaleGestureRecognizer(), ), }, initialCameraPosition: CameraPosition( target: provider.startLocation, zoom: 14.0, ), markers: provider.markers.toSet(), mapType: MapType.normal, onMapCreated: (controller) { provider.mapController = controller; }, onCameraMove: (position) { provider.onCameraMove(context, position,widget.accId,widget.sessionId); }, onTap: (position) { provider.mapController ?.hideMarkerInfoWindow( provider.markers.isNotEmpty ? provider.markers.first.markerId : MarkerId(''), ); }, ), Container( height: 75, decoration: BoxDecoration( gradient: LinearGradient(colors: [ Color(0xFFFFFFFF), Color(0xFFFFFFFF), Color(0xFFFFFFFF).withAlpha(0), ],begin: Alignment.topCenter,end: Alignment.bottomCenter) ), padding: const EdgeInsets.symmetric( horizontal: 16, vertical: 20, ), child: SizedBox( child: Row( mainAxisAlignment: MainAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start, children: [ InkResponse( onTap: () { HapticFeedback.selectionClick(); Navigator.pop(context, true); }, child: SvgPicture.asset( "assets/svg/appbar_back.svg", height: 25, color: AppColors.nearDarkText, ), ), SizedBox(width: 10), Expanded( flex: 4, child: InkResponse( onTap: () { HapticFeedback.selectionClick(); Navigator.pop(context, true); }, child: Text( "Contact Us", overflow: TextOverflow.ellipsis, maxLines: 1, style: TextStyle( fontSize: 16, color: AppColors.nearDarkText, height: 1.1, ), ), ), ), ], ), ), ), ], ), ), ], ), ), ), ), SliverToBoxAdapter( child: Container( decoration:BoxDecoration( color: AppColors.backgroundRegular, borderRadius: BorderRadius.only( topLeft: Radius.circular(30), topRight: Radius.circular(30), ), boxShadow: [ BoxShadow( color: Colors.black.withOpacity(0.1), blurRadius: 10, offset: Offset(0, -5), ), ], ), child: ClipRRect( borderRadius: BorderRadius.only( topLeft: Radius.circular(30), topRight: Radius.circular(30), ), child: Container( padding: const EdgeInsets.symmetric(horizontal: 0), decoration: const BoxDecoration( color: AppColors.backgroundRegular, ), child: Padding( padding: const EdgeInsets.symmetric(horizontal: 12, vertical: 10), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ const SizedBox(height: 20), /// Build dynamic branch list for (var item in data) Padding( padding: const EdgeInsets.only(bottom: 8.0), child: _buildItemRow( branchName: item.branchName ?? "Unknown Branch", address: item.address ?? "No address available", phoneNo: item.telephoneNo ?? "", lat: item.latitude ?? "", long: item.longitude ?? "", ), ), const SizedBox(height: 30), ], ), ), ), ), ), ) ], ) ), ); }, ); } Widget _buildItemRow({ required String branchName, required String address, required String phoneNo, required String lat, required String long, }) { return Container( padding: const EdgeInsets.symmetric(horizontal: 12, vertical: 14), decoration: BoxDecoration( color: Colors.white, borderRadius: BorderRadius.circular(22)), child: Row( children: [ const SizedBox(width: 14), Expanded( flex: 6, child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text( branchName, style: const TextStyle( color: AppColors.normalText, fontWeight: FontWeight.w600, fontSize: 14, overflow: TextOverflow.ellipsis, ), ), const SizedBox(height: 4), Text( address, maxLines: 4, style: const TextStyle( color: AppColors.subtitleText, fontWeight: FontWeight.w400, fontSize: 14, overflow: TextOverflow.ellipsis, ), ), ], ), ), const SizedBox(width: 8), Row( children: [ InkResponse( onTap: () { // map lat & long }, child: Container( padding: const EdgeInsets.all(1), decoration: BoxDecoration( color: Colors.transparent, borderRadius: BorderRadius.circular(30)), child: SvgPicture.asset( "assets/svg/route_ic.svg", height: 42, fit: BoxFit.contain, ), ), ), const SizedBox(width: 6), InkResponse( onTap: () async { final phone = phoneNo.trim(); if (phone.isEmpty) { ScaffoldMessenger.of(context).showSnackBar( SnackBar( backgroundColor: Colors.redAccent, content: const Text( "Phone number not available", style: TextStyle(color: Colors.white), ), duration: Duration(seconds: 2), behavior: SnackBarBehavior.floating, ), ); return; } final Uri phoneUri = Uri(scheme: 'tel', path: phone); try { if (await canLaunchUrl(phoneUri)) { await launchUrl(phoneUri); } else { ScaffoldMessenger.of(context).showSnackBar( SnackBar( backgroundColor: Colors.redAccent, content: const Text( "Unable to start the call", style: TextStyle(color: Colors.white), ), duration: Duration(seconds: 2), behavior: SnackBarBehavior.floating, ), ); } } catch (e) { ScaffoldMessenger.of(context).showSnackBar( SnackBar( backgroundColor: Colors.redAccent, content: Text( "Error while trying to call: $e", style: const TextStyle(color: Colors.white), ), duration: const Duration(seconds: 2), behavior: SnackBarBehavior.floating, ), ); } }, child: Container( padding: const EdgeInsets.all(14), decoration: BoxDecoration( color: const Color(0xFF4CAF50), borderRadius: BorderRadius.circular(30), ), child: SvgPicture.asset( "assets/svg/phone_ic.svg", height: 16, color: Colors.white, fit: BoxFit.contain, ), ), ), ], ), ], ), ); } }