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.
200 lines
6.9 KiB
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),
|
|
),
|
|
),
|
|
],
|
|
),
|
|
],
|
|
),
|
|
);
|
|
}
|
|
}
|