You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
HMG_Patient_App_New/lib/widgets/map/location_map_widget.dart

200 lines
6.9 KiB
Dart

import 'package:flutter/material.dart';
import 'package:hmg_patient_app_new/core/api_consts.dart';
import 'package:hmg_patient_app_new/core/app_assets.dart';
import 'package:hmg_patient_app_new/core/utils/size_utils.dart';
import 'package:hmg_patient_app_new/extensions/string_extensions.dart';
import 'package:hmg_patient_app_new/extensions/widget_extensions.dart';
import 'package:hmg_patient_app_new/theme/colors.dart';
import 'package:hmg_patient_app_new/widgets/buttons/custom_button.dart';
import 'package:maps_launcher/maps_launcher.dart';
/// A reusable location map widget that displays a static map with address and directions button
/// Can be used in any review screen (HHC, CMC, etc.)
class LocationMapWidget extends StatelessWidget {
/// The latitude coordinate of the location
final double latitude;
/// The longitude coordinate of the location
final double longitude;
/// The formatted address or location name to display
final String address;
/// The title to show above the map (e.g., "Service Location", "Hospital Location")
final String title;
/// The zoom level for the map (default: 14)
final int zoomLevel;
/// The size of the map image (default: 350x165)
final String mapSize;
/// Optional callback when directions button is pressed
/// If not provided, will use default MapsLauncher
final VoidCallback? onDirectionsTap;
/// Whether to show the address container (default: true)
final bool showAddress;
/// Whether to show the title (default: true)
final bool showTitle;
/// Custom map type (default: roadmap)
final String mapType;
final EdgeInsets? padding;
const LocationMapWidget({
super.key,
required this.latitude,
required this.longitude,
required this.address,
required this.title,
this.zoomLevel = 14,
this.mapSize = '350x165',
this.onDirectionsTap,
this.showAddress = true,
this.showTitle = true,
this.mapType = 'roadmap',
this.padding,
});
void _defaultLaunchDirections() {
if (latitude != 0.0 && longitude != 0.0) {
MapsLauncher.launchCoordinates(latitude, longitude, address);
}
}
@override
Widget build(BuildContext context) {
final String staticMapUrl =
"https://maps.googleapis.com/maps/api/staticmap?center=$latitude,$longitude&zoom=$zoomLevel&size=$mapSize&maptype=$mapType&markers=color:red%7C$latitude,$longitude&key=${ApiKeyConstants.googleMapsApiKey}";
return Container(
decoration: RoundedRectangleBorder().toSmoothCornerDecoration(
color: AppColors.whiteColor,
borderRadius: 16.r,
),
padding: padding ?? EdgeInsets.all(16.w),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
// Title
if (showTitle) ...[
Text(
title,
style: TextStyle(
fontSize: 16.f,
fontWeight: FontWeight.w700,
color: AppColors.blackColor,
letterSpacing: -0.5,
),
),
SizedBox(height: 12.h),
],
// Address display
if (showAddress) ...[
Container(
padding: EdgeInsets.symmetric(horizontal: 12.w, vertical: 14.h),
decoration: BoxDecoration(
color: AppColors.bgScaffoldColor,
borderRadius: BorderRadius.circular(12.r),
border: Border.all(
color: AppColors.greyColor.withAlpha(51),
width: 1,
),
),
child: Row(
children: [
Icon(Icons.location_on, color: AppColors.primaryRedColor, size: 20.h),
SizedBox(width: 8.w),
Expanded(
child: Text(
address,
style: TextStyle(
fontSize: 14.f,
fontWeight: FontWeight.w500,
color: AppColors.blackColor,
letterSpacing: -0.4,
),
maxLines: 2,
overflow: TextOverflow.ellipsis,
),
),
],
),
),
SizedBox(height: 16.h),
],
// Map display with bottom button overlay
Stack(
children: [
ClipRRect(
clipBehavior: Clip.hardEdge,
borderRadius: BorderRadius.circular(24.r),
child: Image.network(
staticMapUrl,
fit: BoxFit.contain,
loadingBuilder: (context, child, loadingProgress) {
if (loadingProgress == null) return child;
return Container(
height: 165.h,
decoration: BoxDecoration(
color: AppColors.bgScaffoldColor,
borderRadius: BorderRadius.circular(24.r),
),
child: Center(
child: CircularProgressIndicator(
color: AppColors.primaryRedColor,
),
),
);
},
errorBuilder: (context, error, stackTrace) {
return Container(
height: 165.h,
decoration: BoxDecoration(
color: AppColors.bgScaffoldColor,
borderRadius: BorderRadius.circular(24.r),
),
child: Center(
child: Icon(
Icons.error_outline,
size: 48.h,
color: AppColors.greyTextColor,
),
),
);
},
),
),
Positioned(
bottom: 0,
child: SizedBox(
width: MediaQuery.of(context).size.width * 0.785,
child: CustomButton(
text: "Get Directions".needTranslation,
onPressed: onDirectionsTap ?? _defaultLaunchDirections,
backgroundColor: AppColors.textColor.withValues(alpha: 0.8),
borderColor: AppColors.textColor.withValues(alpha: 0.01),
textColor: AppColors.whiteColor,
fontSize: 14.f,
fontWeight: FontWeight.w500,
borderRadius: 12.r,
padding: EdgeInsets.symmetric(horizontal: 10.w),
height: 40.h,
icon: AppAssets.directions_icon,
iconColor: AppColors.whiteColor,
iconSize: 14.h,
).paddingAll(12.h),
),
),
],
),
],
),
);
}
}