import 'dart:async'; import 'package:easy_localization/easy_localization.dart'; import 'package:flutter/material.dart'; import 'package:hmg_patient_app_new/core/app_export.dart'; import 'package:hmg_patient_app_new/extensions/widget_extensions.dart'; import 'package:hmg_patient_app_new/generated/locale_keys.g.dart'; import 'package:hmg_patient_app_new/theme/colors.dart'; import 'package:huawei_map/huawei_map.dart'; class HMSMap extends StatefulWidget { final CameraPosition currentLocation; final Function(CameraPosition) onCameraMoved; final VoidCallback onCameraIdle; final MapType initialMapType; final bool compassEnabled; final bool myLocationEnabled; final bool showCenterMarker; final Completer? inputController; const HMSMap({ super.key, required this.currentLocation, required this.onCameraMoved, required this.onCameraIdle, this.initialMapType = MapType.normal, this.compassEnabled = false, this.showCenterMarker = false, this.myLocationEnabled = true, this.inputController, }); @override State createState() => _HMSMapState(); } class _HMSMapState extends State { Completer? controller; late MapType _selectedMapType; bool _showMapTypeSelector = false; final List<_MapTypeOption> _mapTypeOptions = [ _MapTypeOption(type: MapType.normal, label: LocaleKeys.normalMapType.tr(), icon: Icons.map_outlined), _MapTypeOption(type: MapType.terrain, label: LocaleKeys.terrainMapType.tr(), icon: Icons.terrain_outlined), ]; @override void initState() { super.initState(); HuaweiMapInitializer.initializeMap(); controller = widget.inputController ?? Completer(); _selectedMapType = widget.initialMapType; } void _onMapTypeSelected(MapType type) { setState(() { _selectedMapType = type; _showMapTypeSelector = false; }); } void _toggleSelector() => setState(() => _showMapTypeSelector = !_showMapTypeSelector); @override Widget build(BuildContext context) { return Stack( children: [ // ── Huawei Map ──────────────────────────────────────────────── HuaweiMap( mapType: _selectedMapType, zoomControlsEnabled: false, myLocationEnabled: widget.myLocationEnabled, myLocationButtonEnabled: false, compassEnabled: widget.compassEnabled, onCameraIdle: widget.onCameraIdle, initialCameraPosition: widget.currentLocation, onCameraMove: widget.onCameraMoved, onMapCreated: (HuaweiMapController ctrl) { controller?.complete(ctrl); }, ), // ── Centre pin marker ───────────────────────────────────────── if (widget.showCenterMarker) Align( alignment: Alignment.center, child: Icon( Icons.location_pin, size: 36.h, color: AppColors.primaryRedColor, ).paddingOnly(bottom: 24.h), ), // ── Map-type toggle + panel ─────────────────────────────────── PositionedDirectional( top: 48.h, end: 16.w, child: Column( crossAxisAlignment: CrossAxisAlignment.end, children: [ _MapTypeToggleButton( isActive: _showMapTypeSelector, onTap: _toggleSelector, ), AnimatedSwitcher( duration: const Duration(milliseconds: 220), transitionBuilder: (child, animation) => FadeTransition( opacity: animation, child: SizeTransition( sizeFactor: animation, axisAlignment: -1, child: child, ), ), child: _showMapTypeSelector ? _MapTypeSelectorPanel( options: _mapTypeOptions, selected: _selectedMapType, onSelected: _onMapTypeSelected, ) : const SizedBox.shrink(), ), ], ), ), ], ); } } // ── Toggle button ───────────────────────────────────────────────────────────── class _MapTypeToggleButton extends StatelessWidget { final bool isActive; final VoidCallback onTap; const _MapTypeToggleButton({required this.isActive, required this.onTap}); @override Widget build(BuildContext context) { return GestureDetector( onTap: onTap, child: AnimatedContainer( duration: const Duration(milliseconds: 200), width: 42.w, height: 42.h, decoration: BoxDecoration( color: isActive ? AppColors.primaryRedColor : AppColors.whiteColor, borderRadius: BorderRadius.circular(8.r), ), child: Icon( Icons.layers, size: 22.h, color: isActive ? AppColors.whiteColor : AppColors.blackBgColor, ), ), ); } } // ── Selector panel ──────────────────────────────────────────────────────────── class _MapTypeSelectorPanel extends StatelessWidget { final List<_MapTypeOption> options; final MapType selected; final ValueChanged onSelected; const _MapTypeSelectorPanel({ required this.options, required this.selected, required this.onSelected, }); @override Widget build(BuildContext context) { return Container( key: const ValueKey('map_type_panel'), margin: EdgeInsets.only(top: 8.h), padding: EdgeInsets.symmetric(vertical: 8.h, horizontal: 6.w), decoration: BoxDecoration( color: AppColors.whiteColor, borderRadius: BorderRadius.circular(12.r), ), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: options .map((opt) => _MapTypeItem( option: opt, isSelected: selected == opt.type, onTap: () => onSelected(opt.type), )) .toList(), ), ); } } // ── Single row item ─────────────────────────────────────────────────────────── class _MapTypeItem extends StatelessWidget { final _MapTypeOption option; final bool isSelected; final VoidCallback onTap; const _MapTypeItem({ required this.option, required this.isSelected, required this.onTap, }); @override Widget build(BuildContext context) { return GestureDetector( onTap: onTap, child: AnimatedContainer( duration: const Duration(milliseconds: 180), margin: EdgeInsets.symmetric(vertical: 3.h), padding: EdgeInsets.symmetric(horizontal: 10.w, vertical: 8.h), decoration: BoxDecoration( color: isSelected ? AppColors.primaryRedColor.withOpacity(0.1) : Colors.transparent, borderRadius: BorderRadius.circular(8.r), ), child: Row( mainAxisSize: MainAxisSize.min, children: [ Icon( option.icon, size: 18.h, color: isSelected ? AppColors.primaryRedColor : AppColors.blackBgColor, ), SizedBox(width: 8.w), Text( option.label, style: TextStyle( fontSize: 14.f, fontWeight: isSelected ? FontWeight.w600 : FontWeight.w400, color: isSelected ? AppColors.primaryRedColor :AppColors.blackBgColor, ), ), ], ), ), ); } } // ── Data class ──────────────────────────────────────────────────────────────── class _MapTypeOption { final MapType type; final String label; final IconData icon; const _MapTypeOption({ required this.type, required this.label, required this.icon, }); }