diff --git a/packages/core/lib/core.dart b/packages/core/lib/core.dart index 86caf03..c881e08 100644 --- a/packages/core/lib/core.dart +++ b/packages/core/lib/core.dart @@ -57,3 +57,5 @@ export 'utils/map_utils.dart'; export 'utils/network/network.dart'; export 'utils/route_utils.dart'; export 'utils/separator_input_formatter.dart'; + +export 'utils/utils.dart'; diff --git a/packages/core/lib/infrastructure/remote/dio_remote.dart b/packages/core/lib/infrastructure/remote/dio_remote.dart index 3cfcd98..473ca3e 100644 --- a/packages/core/lib/infrastructure/remote/dio_remote.dart +++ b/packages/core/lib/infrastructure/remote/dio_remote.dart @@ -37,6 +37,7 @@ class DioRemote implements IHttpClient { ProgressCallback? onReceiveProgress, T Function(Map json)? fromJson, T Function(List json)? fromJsonList, + Future Function(List json)? fromJsonListAsync, }) async { final response = await dio.get( path, @@ -45,6 +46,10 @@ class DioRemote implements IHttpClient { onReceiveProgress: onReceiveProgress, cancelToken: ApiHandler.globalCancelToken, ); + if (fromJsonListAsync != null && response.data is List) { + response.data = await fromJsonListAsync(response.data); + return DioResponse(response); + } if (fromJsonList != null && response.data is List) { response.data = fromJsonList(response.data); return DioResponse(response); diff --git a/packages/core/lib/infrastructure/remote/interfaces/i_http_client.dart b/packages/core/lib/infrastructure/remote/interfaces/i_http_client.dart index 9550c18..119222b 100644 --- a/packages/core/lib/infrastructure/remote/interfaces/i_http_client.dart +++ b/packages/core/lib/infrastructure/remote/interfaces/i_http_client.dart @@ -1,6 +1,5 @@ - -import 'dart:typed_data'; import 'package:dio/dio.dart'; + import 'i_form_data.dart'; import 'i_http_response.dart'; @@ -8,12 +7,14 @@ abstract class IHttpClient { Future init(); Future> get( - String path, { - Map? queryParameters, - Map? headers, - ProgressCallback? onReceiveProgress, - }); - + String path, { + Map? queryParameters, + Map? headers, + ProgressCallback? onReceiveProgress, + T Function(Map json)? fromJson, + T Function(List json)? fromJsonList, + Future Function(List json)? fromJsonListAsync, + }); Future> post( String path, { @@ -40,10 +41,7 @@ abstract class IHttpClient { Map? headers, }); - Future> download( - String url, { - ProgressCallback? onReceiveProgress, - }); + Future> download(String url, {ProgressCallback? onReceiveProgress}); Future> upload( String path, { diff --git a/packages/core/lib/utils/parser.dart b/packages/core/lib/utils/parser.dart new file mode 100644 index 0000000..319be03 --- /dev/null +++ b/packages/core/lib/utils/parser.dart @@ -0,0 +1,16 @@ +import 'package:flutter/foundation.dart'; + +List _parserList(Map args) { + final list = args['list'] as List; + final T Function(Map) fromJson = + args['fromJson'] as T Function(Map); + + return list.map((e) => fromJson(e as Map)).toList(); +} + +Future> parseListInIsolate( + List list, + T Function(Map) fromJson, +) async { + return compute(_parserList, {'list': list, 'fromJson': fromJson}); +} diff --git a/packages/core/lib/utils/utils.dart b/packages/core/lib/utils/utils.dart index 064ac55..ba7f6b2 100644 --- a/packages/core/lib/utils/utils.dart +++ b/packages/core/lib/utils/utils.dart @@ -1,17 +1,12 @@ -export 'mixins/pagination_controller_mixin.dart'; - -export 'network/network.dart'; - +export 'apk_updater.dart'; export 'extension/date_time_utils.dart'; export 'extension/num_utils.dart'; export 'extension/string_utils.dart'; - -export 'apk_updater.dart'; +export 'local/local_utils.dart'; export 'logger_utils.dart'; export 'map_utils.dart'; +export 'mixins/pagination_controller_mixin.dart'; +export 'network/network.dart'; +export 'parser.dart'; export 'route_utils.dart'; export 'separator_input_formatter.dart'; - - -export 'local/local_utils.dart'; - diff --git a/packages/inspection/lib/data/data_source/remote/inspection/inspection_remote_imp.dart b/packages/inspection/lib/data/data_source/remote/inspection/inspection_remote_imp.dart index 30a8110..08ac5a2 100644 --- a/packages/inspection/lib/data/data_source/remote/inspection/inspection_remote_imp.dart +++ b/packages/inspection/lib/data/data_source/remote/inspection/inspection_remote_imp.dart @@ -39,8 +39,8 @@ class InspectionRemoteDataSourceImp implements InspectionRemoteDataSource { value: value, ), headers: {'Content-Type': 'application/json'}, - fromJsonList: (json) => - json.map((item) => PoultryLocationModel.fromJson(item as Map)).toList(), + fromJsonListAsync: (json) async => + parseListInIsolate(json, (json) => PoultryLocationModel.fromJson(json)), ); return res.data; diff --git a/packages/inspection/lib/presentation/pages/inspection_map/logic.dart b/packages/inspection/lib/presentation/pages/inspection_map/logic.dart index 04ef033..b6eb8b1 100644 --- a/packages/inspection/lib/presentation/pages/inspection_map/logic.dart +++ b/packages/inspection/lib/presentation/pages/inspection_map/logic.dart @@ -57,8 +57,9 @@ class InspectionMapLogic extends GetxController { allPoultryLocation.value = Resource>.loading(); await safeCall( call: () => inspectionRepository.getNearbyLocation(), - onSuccess: (result) { + onSuccess: (result) async{ if (result != null) { + allPoultryLocation.value = Resource>.success(result); mapLogic.allLocations.value = Resource>.success(result); } else { diff --git a/packages/inspection/lib/presentation/pages/inspection_map/view.dart b/packages/inspection/lib/presentation/pages/inspection_map/view.dart index b83c6f8..044bc48 100644 --- a/packages/inspection/lib/presentation/pages/inspection_map/view.dart +++ b/packages/inspection/lib/presentation/pages/inspection_map/view.dart @@ -20,7 +20,6 @@ class InspectionMapPage extends GetView { filteringWidget: filterWidget(showIndex: 3.obs, filterIndex: 5.obs), widgets: [ MapPage(), - ObxValue((p0) => Text(p0.toString()), controller.showIndex), ObxValue((data) { if (data.value) { WidgetsBinding.instance.addPostFrameCallback((_) { @@ -66,7 +65,7 @@ class InspectionMapPage extends GetView { controller.baseLogic.searchTextController.clear(); controller.baseLogic.searchValue.value = null; controller.baseLogic.isSearchSelected.value = false; - controller. mapLogic.hasFilterOrSearch.value = false; + controller.mapLogic.hasFilterOrSearch.value = false; controller.searchedPoultryLocation.value = Resource.initial(); }, enableFeedback: true, @@ -92,7 +91,6 @@ class InspectionMapPage extends GetView { ), GestureDetector( onTap: () { - Get.back(); }, child: Assets.vec.mapSvg.svg( diff --git a/packages/inspection/lib/presentation/pages/inspection_map/widget/map/logic.dart b/packages/inspection/lib/presentation/pages/inspection_map/widget/map/logic.dart index ff05984..07a483b 100644 --- a/packages/inspection/lib/presentation/pages/inspection_map/widget/map/logic.dart +++ b/packages/inspection/lib/presentation/pages/inspection_map/widget/map/logic.dart @@ -74,6 +74,8 @@ class MapLogic extends GetxController with GetTickerProviderStateMixin { super.onClose(); } + double _deg2rad(double deg) => deg * (pi / 180); + Future determineCurrentPosition() async { isLoading.value = true; final position = await Geolocator.getCurrentPosition( @@ -95,7 +97,8 @@ class MapLogic extends GetxController with GetTickerProviderStateMixin { isLoading.value = false; } - /* void debouncedUpdateVisibleMarkers({required LatLng center, required double zoom}) { +/* + void debouncedUpdateVisibleMarkers({required LatLng center, required double zoom}) { _debounceTimer?.cancel(); _debounceTimer = Timer(const Duration(milliseconds: 300), () { final radius = getVisibleRadiusKm( @@ -105,7 +108,7 @@ class MapLogic extends GetxController with GetTickerProviderStateMixin { ); final filtered = filterNearbyMarkers( - allPoultryLocation.value.data ?? [], + all.value.data ?? [], center.latitude, center.longitude, radius, @@ -114,7 +117,8 @@ class MapLogic extends GetxController with GetTickerProviderStateMixin { final uniqueFiltered = filtered.where((e) => !existingIds.contains(e.id)).toList(); markers2.addAll(uniqueFiltered); }); - }*/ + } +*/ List filterNearbyMarkers( List allMarkers, @@ -127,13 +131,27 @@ class MapLogic extends GetxController with GetTickerProviderStateMixin { return allMarkers.where((marker) => distance(center, marker) <= radiusInMeters).toList(); } - double getVisibleRadiusKm({ - required double zoom, - required double screenWidthPx, - required double latitude, - }) { - double metersPerPixel = 156543.03392 * cos(latitude * pi / 180) / pow(2, zoom); - double visibleWidthInMeters = metersPerPixel * screenWidthPx; - return (visibleWidthInMeters / 2); // radius in Meter + double getVisibleRadiusKm({required LatLng center, required LatLng corner}) { + const earthRadius = 6371; // Km + + final dLat = _deg2rad(corner.latitude - center.latitude); + final dLng = _deg2rad(corner.longitude - center.longitude); + + final a = + sin(dLat / 2) * sin(dLat / 2) + + cos(_deg2rad(center.latitude)) * + cos(_deg2rad(corner.latitude)) * + sin(dLng / 2) * + sin(dLng / 2); + + final c = 2 * atan2(sqrt(a), sqrt(1 - a)); + return earthRadius * c; + } + + bool isInVisibleBounds(LatLng point, LatLngBounds bounds) { + return point.latitude <= bounds.north && + point.latitude >= bounds.south && + point.longitude >= bounds.west && + point.longitude <= bounds.east; } } diff --git a/packages/inspection/lib/presentation/pages/inspection_map/widget/map/view.dart b/packages/inspection/lib/presentation/pages/inspection_map/widget/map/view.dart index c532774..84a5a73 100644 --- a/packages/inspection/lib/presentation/pages/inspection_map/widget/map/view.dart +++ b/packages/inspection/lib/presentation/pages/inspection_map/widget/map/view.dart @@ -23,7 +23,11 @@ class MapPage extends GetView { ), initialZoom: 15, onPositionChanged: (camera, hasGesture) { - //controller.debouncedUpdateVisibleMarkers(center: camera.center, zoom: camera.zoom); + controller.currentZoom.value = camera.zoom; + /* controller.debouncedUpdateVisibleMarkers( + center: camera.center, + zoom: camera.zoom, + );*/ }, ), @@ -34,35 +38,14 @@ class MapPage extends GetView { ), ObxValue((markers) { - if (markers.value.status == ResourceStatus.success) { - return MarkerLayer( - markers: List.generate(markers.value.data?.length ?? 0, (index) { - final location = markers.value.data![index]; - return markerWidget( - marker: location.latLng ?? LatLng(0, 0), - onTap: () { - controller.isSelectedDetailsLocation.value = true; - controller.animatedMapController.animateTo( - dest: location.latLng ?? LatLng(0, 0), - zoom: 18, - ); - }, - ); - }), - ); - } - return Container(width: 20, height: 20, color: Colors.lightGreen); - }, controller.markerLocations), - - /* ObxValue((markers) { return MarkerClusterLayerWidget( options: MarkerClusterLayerOptions( maxClusterRadius: 80, size: const Size(40, 40), alignment: Alignment.center, padding: const EdgeInsets.all(50), - maxZoom: 15, - markers: buildMarkers(markers), + maxZoom: 18, + markers: buildMarkers(markers.value.data ?? []), builder: (context, clusterMarkers) { return Container( decoration: BoxDecoration( @@ -79,27 +62,11 @@ class MapPage extends GetView { }, ), ); - }, controller.allLocations),*/ + }, controller.markerLocations), ], ); }, controller.currentLocation), - /* Obx(() { - if (controller.baseLogic.isSearchSelected.value) { - WidgetsBinding.instance.addPostFrameCallback((_) { - if (Get.isBottomSheetOpen != true) { - Get.bottomSheet( - searchWidget(), - isDismissible: true, - ignoreSafeArea: false, - isScrollControlled: true, - ); - } - }); - } - return const SizedBox.shrink(); - }),*/ - // Uncomment the following lines to enable the search widget /* Positioned( top: 10, @@ -133,347 +100,667 @@ class MapPage extends GetView { }, controller.isLoading); } - List buildMarkers(RxList markers) { + List buildMarkers(List markers) { final visibleBounds = controller.animatedMapController.mapController.camera.visibleBounds; final isZoomedIn = controller.currentZoom > 17; final updatedMarkers = markers.map((location) { final point = LatLng(location.lat ?? 0, location.long ?? 0); - final isVisible = visibleBounds.contains(point); + final isVisible = controller.isInVisibleBounds(point, visibleBounds); - return Marker( - point: point, - width: isZoomedIn && isVisible ? 180.w : 40.h, - height: isZoomedIn && isVisible ? 50.h : 50.h, - child: GestureDetector( - onTap: () { - bool hasHatching = location.hatching != null && location.hatching!.isNotEmpty; - Get.bottomSheet( - ObxValue((data) { - return BaseBottomSheet( - height: data.value - ? hasHatching - ? 550.h - : 400.h - : 150.h, - child: Column( - spacing: 12, - children: [ - ListItemWithOutCounter( - secondChild: Column( - spacing: 8, - children: [ - Padding( - padding: EdgeInsets.symmetric(horizontal: 12.w), - child: Column( - spacing: 8, - children: [ - Row( - mainAxisAlignment: MainAxisAlignment.center, - children: [ - Text( - location.unitName ?? 'N/A', - textAlign: TextAlign.center, - style: AppFonts.yekan16.copyWith(color: AppColor.greenDark), - ), - ], - ), - Container( - height: 32.h, - padding: EdgeInsets.symmetric(horizontal: 8), - decoration: ShapeDecoration( - color: AppColor.blueLight, - shape: RoundedRectangleBorder( - side: BorderSide( - width: 1.w, - color: AppColor.blueLightHover, - ), - borderRadius: BorderRadius.circular(8), - ), - ), - child: Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - spacing: 3, + if (isZoomedIn && isVisible) { + return Marker( + point: point, + width: 180.w, + height: 50.h, + child: GestureDetector( + onTap: () { + bool hasHatching = location.hatching != null && location.hatching!.isNotEmpty; + iLog(hasHatching); + Get.bottomSheet( + ObxValue((data) { + return BaseBottomSheet( + height: data.value + ? hasHatching + ? 550.h + : 400.h + : 150.h, + child: Column( + spacing: 12, + children: [ + ListItemWithOutCounter( + secondChild: Column( + spacing: 8, + children: [ + Padding( + padding: EdgeInsets.symmetric(horizontal: 12.w), + child: Column( + spacing: 8, + children: [ + Row( + mainAxisAlignment: MainAxisAlignment.center, children: [ Text( - 'جوجه ریزی فعال', - style: AppFonts.yekan14.copyWith( - color: AppColor.textColor, - ), - ), - - Text( - hasHatching ? 'دارد' : 'ندارد', - style: AppFonts.yekan14.copyWith( - color: AppColor.blueNormal, + location.unitName ?? 'N/A', + textAlign: TextAlign.center, + style: AppFonts.yekan16.copyWith( + color: AppColor.greenDark, ), ), ], ), - ), - buildRow( - title: 'مشخصات خریدار', - value: location.user?.fullname ?? 'N/A', - ), - - buildRow( - title: 'تلفن خریدار', - value: location.user?.mobile ?? 'N/A', - valueStyle: AppFonts.yekan14.copyWith( - color: AppColor.blueNormal, - ), - ), - - Visibility( - visible: location.address?.city?.name != null, - child: buildRow( - title: 'شهر', - value: location.address?.city?.name ?? 'N/A', - ), - ), - Visibility( - visible: location.address?.address != null, - child: buildRow( - title: 'آردس', - value: location.address?.address ?? 'N/A', - ), - ), - - buildRow( - title: 'شناسه یکتا', - value: location.breedingUniqueId ?? 'N/A', - ), - ], - ), - ), - Row( - children: [ - Expanded( - child: Row( - mainAxisSize: MainAxisSize.min, - mainAxisAlignment: MainAxisAlignment.center, - spacing: 7, - children: [ - RElevated( - width: 40.h, - height: 38.h, - backgroundColor: AppColor.greenNormal, - child: Assets.vec.messageAddSvg.svg( - width: 24.w, - height: 24.h, - colorFilter: ColorFilter.mode( - Colors.white, - BlendMode.srcIn, + Container( + height: 32.h, + padding: EdgeInsets.symmetric(horizontal: 8), + decoration: ShapeDecoration( + color: AppColor.blueLight, + shape: RoundedRectangleBorder( + side: BorderSide( + width: 1.w, + color: AppColor.blueLightHover, ), + borderRadius: BorderRadius.circular(8), ), - onPressed: () {}, ), - RElevated( - width: 150.w, - height: 40.h, - backgroundColor: AppColor.blueNormal, - onPressed: () { - /* controller.setEditData(item); + child: Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + spacing: 3, + children: [ + Text( + 'جوجه ریزی فعال', + style: AppFonts.yekan14.copyWith( + color: AppColor.textColor, + ), + ), + + Text( + hasHatching ? 'دارد' : 'ندارد', + style: AppFonts.yekan14.copyWith( + color: AppColor.blueNormal, + ), + ), + ], + ), + ), + buildRow( + title: 'مشخصات خریدار', + value: location.user?.fullname ?? 'N/A', + ), + + buildRow( + title: 'تلفن خریدار', + value: location.user?.mobile ?? 'N/A', + valueStyle: AppFonts.yekan14.copyWith( + color: AppColor.blueNormal, + ), + ), + + Visibility( + visible: location.address?.city?.name != null, + child: buildRow( + title: 'شهر', + value: location.address?.city?.name ?? 'N/A', + ), + ), + Visibility( + visible: location.address?.address != null, + child: buildRow( + title: 'آردس', + value: location.address?.address ?? 'N/A', + ), + ), + + buildRow( + title: 'شناسه یکتا', + value: location.breedingUniqueId ?? 'N/A', + ), + ], + ), + ), + Row( + children: [ + Expanded( + child: Row( + mainAxisSize: MainAxisSize.min, + mainAxisAlignment: MainAxisAlignment.center, + spacing: 7, + children: [ + RElevated( + width: 40.h, + height: 38.h, + backgroundColor: AppColor.greenNormal, + child: Assets.vec.messageAddSvg.svg( + width: 24.w, + height: 24.h, + colorFilter: ColorFilter.mode( + Colors.white, + BlendMode.srcIn, + ), + ), + onPressed: () {}, + ), + RElevated( + width: 150.w, + height: 40.h, + backgroundColor: AppColor.blueNormal, + onPressed: () { + /* controller.setEditData(item); Get.bottomSheet( addOrEditBottomSheet(true), isScrollControlled: true, backgroundColor: Colors.transparent, ).whenComplete(() {});*/ - }, - child: Row( - mainAxisAlignment: MainAxisAlignment.start, - spacing: 8, - children: [ - Assets.vec.mapSvg.svg( - width: 24.w, - height: 24.h, - colorFilter: ColorFilter.mode( - Colors.white, - BlendMode.srcIn, + }, + child: Row( + mainAxisAlignment: MainAxisAlignment.start, + spacing: 8, + children: [ + Assets.vec.mapSvg.svg( + width: 24.w, + height: 24.h, + colorFilter: ColorFilter.mode( + Colors.white, + BlendMode.srcIn, + ), ), - ), - Text( - 'جزییات کامل', - style: AppFonts.yekan14Bold.copyWith( - color: Colors.white, + Text( + 'جزییات کامل', + style: AppFonts.yekan14Bold.copyWith( + color: Colors.white, + ), ), - ), - ], + ], + ), ), + ROutlinedElevated( + width: 150.w, + height: 40.h, + onPressed: () { + buildDeleteDialog( + onConfirm: () async {}, + onRefresh: () async {}, + ); + }, + borderColor: AppColor.bgIcon, + child: Row( + mainAxisAlignment: MainAxisAlignment.center, + spacing: 8, + children: [ + Assets.vec.securityTimeSvg.svg( + width: 24.w, + height: 24.h, + colorFilter: ColorFilter.mode( + AppColor.bgIcon, + BlendMode.srcIn, + ), + ), + Text( + 'سوابق بازرسی', + style: AppFonts.yekan14Bold.copyWith( + color: AppColor.bgIcon, + ), + ), + ], + ), + ), + ], + ), + ), + ], + ), + ], + ), + labelColor: AppColor.blueLight, + labelIcon: Assets.vec.cowSvg.path, + labelIconColor: AppColor.bgIcon, + onTap: () => data.value = !data.value, + selected: data.value, + child: Row( + mainAxisAlignment: MainAxisAlignment.spaceAround, + children: [ + Column( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Text( + location.unitName ?? 'N/A', + style: AppFonts.yekan10.copyWith(color: AppColor.blueNormal), + ), + Text( + location.user?.fullname ?? '', + style: AppFonts.yekan12.copyWith( + color: AppColor.darkGreyDarkHover, + ), + ), + ], + ), + Column( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Text( + 'جوجه ریزی فعال', + style: AppFonts.yekan10.copyWith(color: AppColor.blueNormal), + ), + Text( + (location.hatching != null && location.hatching!.isNotEmpty) + ? 'دارد' + : 'ندراد', + style: AppFonts.yekan12.copyWith( + color: AppColor.darkGreyDarkHover, + ), + ), + ], + ), + Assets.vec.scanBarcodeSvg.svg(), + ], + ), + ), + + Visibility( + visible: hasHatching, + child: Container( + width: Get.width, + margin: const EdgeInsets.fromLTRB(0, 0, 10, 0), + padding: EdgeInsets.all(8.r), + decoration: BoxDecoration( + borderRadius: BorderRadius.circular(8), + border: Border.all(width: 1, color: AppColor.lightGreyNormalHover), + ), + child: Column( + spacing: 8.h, + children: [ + Container( + height: 32.h, + padding: EdgeInsets.symmetric(horizontal: 8), + decoration: ShapeDecoration( + color: AppColor.blueLight, + shape: RoundedRectangleBorder( + side: BorderSide(width: 1.w, color: AppColor.blueLightHover), + borderRadius: BorderRadius.circular(8), + ), + ), + child: Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + spacing: 3, + children: [ + Text( + 'تاریخ', + style: AppFonts.yekan14.copyWith(color: AppColor.textColor), ), - ROutlinedElevated( - width: 150.w, - height: 40.h, - onPressed: () { - buildDeleteDialog( - onConfirm: () async {}, - onRefresh: () async {}, - ); - }, - borderColor: AppColor.bgIcon, - child: Row( - mainAxisAlignment: MainAxisAlignment.center, - spacing: 8, - children: [ - Assets.vec.securityTimeSvg.svg( - width: 24.w, - height: 24.h, - colorFilter: ColorFilter.mode( - AppColor.bgIcon, - BlendMode.srcIn, - ), - ), - Text( - 'سوابق بازرسی', - style: AppFonts.yekan14Bold.copyWith( - color: AppColor.bgIcon, - ), - ), - ], + + Text( + location.hatching?.first.date?.formattedJalaliDate ?? 'N/A', + style: AppFonts.yekan14.copyWith( + color: AppColor.blueNormal, ), ), ], ), ), - ], - ), - ], - ), - labelColor: AppColor.blueLight, - labelIcon: Assets.vec.cowSvg.path, - labelIconColor: AppColor.bgIcon, - onTap: () => data.value = !data.value, - selected: data.value, - child: Row( - mainAxisAlignment: MainAxisAlignment.spaceAround, - children: [ - Column( - mainAxisAlignment: MainAxisAlignment.center, - children: [ - Text( - location.unitName ?? 'N/A', - style: AppFonts.yekan10.copyWith(color: AppColor.blueNormal), + buildRow( + title: 'باقیمانده', + value: + location.hatching?.first.leftOver.separatedByComma ?? 'N/A', ), - Text( - location.user?.fullname ?? '', - style: AppFonts.yekan12.copyWith( - color: AppColor.darkGreyDarkHover, - ), + buildRow( + title: 'سن جوجه ریزی', + value: '${location.hatching?.first.chickenAge ?? 'N/A'} روز', + ), + buildRow( + title: 'شماره مجوز جوجه ریزی', + value: location.hatching?.first.licenceNumber.toString() ?? 'N/A', ), ], ), - Column( - mainAxisAlignment: MainAxisAlignment.center, - children: [ - Text( - 'جوجه ریزی فعال', - style: AppFonts.yekan10.copyWith(color: AppColor.blueNormal), - ), - Text( - (location.hatching != null && location.hatching!.isNotEmpty) - ? 'دارد' - : 'ندراد', - style: AppFonts.yekan12.copyWith( - color: AppColor.darkGreyDarkHover, - ), - ), - ], - ), - Assets.vec.scanBarcodeSvg.svg(), - ], - ), - ), - - Visibility( - visible: hasHatching, - child: Container( - width: Get.width, - margin: const EdgeInsets.fromLTRB(0, 0, 10, 0), - padding: EdgeInsets.all(8.r), - decoration: BoxDecoration( - borderRadius: BorderRadius.circular(8), - border: Border.all(width: 1, color: AppColor.lightGreyNormalHover), ), - child: Column( - spacing: 8.h, + ), + ], + ), + ); + }, controller.isSelectedDetailsLocation), + isScrollControlled: true, + isDismissible: true, + ); + }, + child: Container( + height: 30.h, + padding: EdgeInsets.all(5.r), + decoration: BoxDecoration( + color: Colors.white, + borderRadius: BorderRadius.circular(15.r), + boxShadow: [ + BoxShadow( + color: Colors.black.withValues(alpha: 0.1), + blurRadius: 5, + offset: const Offset(0, 2), + ), + ], + ), + child: Row( + mainAxisAlignment: MainAxisAlignment.center, + spacing: 8, + children: [ + Assets.vec.chickenMapMarkerSvg.svg(width: 24.w, height: 24.h), + Text(location.user?.fullname ?? '', style: AppFonts.yekan12), + ], + ), + ), + ), + ); + } else { + return Marker( + point: point, + width: 40.h, + height: 50.h, + child: GestureDetector( + onTap: () { + bool hasHatching = location.hatching != null && location.hatching!.isNotEmpty; + Get.bottomSheet( + ObxValue((data) { + return BaseBottomSheet( + height: data.value + ? hasHatching + ? 550.h + : 400.h + : 150.h, + child: Column( + spacing: 12, + children: [ + ListItemWithOutCounter( + secondChild: Column( + spacing: 8, children: [ - Container( - height: 32.h, - padding: EdgeInsets.symmetric(horizontal: 8), - decoration: ShapeDecoration( - color: AppColor.blueLight, - shape: RoundedRectangleBorder( - side: BorderSide(width: 1.w, color: AppColor.blueLightHover), - borderRadius: BorderRadius.circular(8), - ), - ), - child: Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - spacing: 3, + Padding( + padding: EdgeInsets.symmetric(horizontal: 12.w), + child: Column( + spacing: 8, children: [ - Text( - 'تاریخ', - style: AppFonts.yekan14.copyWith(color: AppColor.textColor), + Row( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Text( + location.unitName ?? 'N/A', + textAlign: TextAlign.center, + style: AppFonts.yekan16.copyWith( + color: AppColor.greenDark, + ), + ), + ], + ), + Container( + height: 32.h, + padding: EdgeInsets.symmetric(horizontal: 8), + decoration: ShapeDecoration( + color: AppColor.blueLight, + shape: RoundedRectangleBorder( + side: BorderSide( + width: 1.w, + color: AppColor.blueLightHover, + ), + borderRadius: BorderRadius.circular(8), + ), + ), + child: Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + spacing: 3, + children: [ + Text( + 'جوجه ریزی فعال', + style: AppFonts.yekan14.copyWith( + color: AppColor.textColor, + ), + ), + + Text( + hasHatching ? 'دارد' : 'ندارد', + style: AppFonts.yekan14.copyWith( + color: AppColor.blueNormal, + ), + ), + ], + ), + ), + buildRow( + title: 'مشخصات مرغدار', + value: location.user?.fullname ?? 'N/A', ), - Text( - location.hatching?.first.date?.formattedJalaliDate ?? 'N/A', - style: AppFonts.yekan14.copyWith(color: AppColor.blueNormal), + buildRow( + title: 'تلفن مرغدار', + value: location.user?.mobile ?? 'N/A', + valueStyle: AppFonts.yekan14.copyWith( + color: AppColor.blueNormal, + ), + ), + + Visibility( + visible: location.address?.city?.name != null, + child: buildRow( + title: 'شهر', + value: location.address?.city?.name ?? 'N/A', + ), + ), + Visibility( + visible: location.address?.address != null, + child: buildRow( + title: 'آردس', + value: location.address?.address ?? 'N/A', + ), + ), + + buildRow( + title: 'شناسه یکتا', + value: location.breedingUniqueId ?? 'N/A', ), ], ), ), - buildRow( - title: 'باقیمانده', - value: location.hatching?.first.leftOver.separatedByComma ?? 'N/A', - ), - buildRow( - title: 'سن جوجه ریزی', - value: '${location.hatching?.first.chickenAge ?? 'N/A'} روز', - ), - buildRow( - title: 'شماره مجوز جوجه ریزی', - value: location.hatching?.first.licenceNumber.toString() ?? 'N/A', + Row( + children: [ + Expanded( + child: Row( + mainAxisSize: MainAxisSize.min, + mainAxisAlignment: MainAxisAlignment.center, + spacing: 7, + children: [ + RElevated( + width: 40.h, + height: 38.h, + backgroundColor: AppColor.greenNormal, + child: Assets.vec.messageAddSvg.svg( + width: 24.w, + height: 24.h, + colorFilter: ColorFilter.mode( + Colors.white, + BlendMode.srcIn, + ), + ), + onPressed: () {}, + ), + RElevated( + width: 150.w, + height: 40.h, + backgroundColor: AppColor.blueNormal, + onPressed: () { + /* controller.setEditData(item); + Get.bottomSheet( + addOrEditBottomSheet(true), + isScrollControlled: true, + backgroundColor: Colors.transparent, + ).whenComplete(() {});*/ + }, + child: Row( + mainAxisAlignment: MainAxisAlignment.start, + spacing: 8, + children: [ + Assets.vec.mapSvg.svg( + width: 24.w, + height: 24.h, + colorFilter: ColorFilter.mode( + Colors.white, + BlendMode.srcIn, + ), + ), + Text( + 'جزییات کامل', + style: AppFonts.yekan14Bold.copyWith( + color: Colors.white, + ), + ), + ], + ), + ), + ROutlinedElevated( + width: 150.w, + height: 40.h, + onPressed: () { + buildDeleteDialog( + onConfirm: () async {}, + onRefresh: () async {}, + ); + }, + borderColor: AppColor.bgIcon, + child: Row( + mainAxisAlignment: MainAxisAlignment.center, + spacing: 8, + children: [ + Assets.vec.securityTimeSvg.svg( + width: 24.w, + height: 24.h, + colorFilter: ColorFilter.mode( + AppColor.bgIcon, + BlendMode.srcIn, + ), + ), + Text( + 'سوابق بازرسی', + style: AppFonts.yekan14Bold.copyWith( + color: AppColor.bgIcon, + ), + ), + ], + ), + ), + ], + ), + ), + ], ), ], ), + labelColor: AppColor.blueLight, + labelIcon: Assets.vec.cowSvg.path, + labelIconColor: AppColor.bgIcon, + onTap: () => data.value = !data.value, + selected: data.value, + child: Row( + mainAxisAlignment: MainAxisAlignment.spaceAround, + children: [ + Column( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Text( + location.unitName ?? 'N/A', + style: AppFonts.yekan10.copyWith(color: AppColor.blueNormal), + ), + Text( + location.user?.fullname ?? '', + style: AppFonts.yekan12.copyWith( + color: AppColor.darkGreyDarkHover, + ), + ), + ], + ), + Column( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Text( + 'جوجه ریزی فعال', + style: AppFonts.yekan10.copyWith(color: AppColor.blueNormal), + ), + Text( + (location.hatching != null && location.hatching!.isNotEmpty) + ? 'دارد' + : 'ندراد', + style: AppFonts.yekan12.copyWith( + color: AppColor.darkGreyDarkHover, + ), + ), + ], + ), + Assets.vec.scanBarcodeSvg.svg(), + ], + ), ), - ), - ], - ), - ); - }, controller.isSelectedDetailsLocation), - isScrollControlled: true, - isDismissible: true, - ); - }, - child: isZoomedIn && isVisible - ? Container( - height: 30.h, - padding: EdgeInsets.all(5.r), - decoration: BoxDecoration( - color: Colors.white, - borderRadius: BorderRadius.circular(15.r), - boxShadow: [ - BoxShadow( - color: Colors.black.withValues(alpha: 0.1), - blurRadius: 5, - offset: const Offset(0, 2), - ), - ], - ), - child: Row( - mainAxisAlignment: MainAxisAlignment.center, - spacing: 8, - children: [ - Assets.vec.chickenMapMarkerSvg.svg(width: 24.w, height: 24.h), - Text(location.user?.fullname ?? '', style: AppFonts.yekan12), - ], - ), - ) - : Assets.vec.chickenMapMarkerSvg.svg(width: 24.w, height: 24.h), - ), - ); + + if (hasHatching) ...{ + Container( + width: Get.width, + margin: const EdgeInsets.fromLTRB(0, 0, 10, 0), + padding: EdgeInsets.all(8.r), + decoration: BoxDecoration( + borderRadius: BorderRadius.circular(8), + border: Border.all(width: 1, color: AppColor.lightGreyNormalHover), + ), + child: Column( + spacing: 8.h, + children: [ + Container( + height: 32.h, + padding: EdgeInsets.symmetric(horizontal: 8), + decoration: ShapeDecoration( + color: AppColor.blueLight, + shape: RoundedRectangleBorder( + side: BorderSide(width: 1.w, color: AppColor.blueLightHover), + borderRadius: BorderRadius.circular(8), + ), + ), + child: Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + spacing: 3, + children: [ + Text( + 'تاریخ', + style: AppFonts.yekan14.copyWith(color: AppColor.textColor), + ), + + Text( + location.hatching?.first.date?.formattedJalaliDate ?? 'N/A', + style: AppFonts.yekan14.copyWith( + color: AppColor.blueNormal, + ), + ), + ], + ), + ), + buildRow( + title: 'باقیمانده', + value: + '${location.hatching?.first.leftOver.separatedByComma ?? 'N/A'} عدد', + ), + buildRow( + title: 'سن جوجه ریزی', + value: '${location.hatching?.first.chickenAge ?? 'N/A'} روز', + ), + buildRow( + title: 'شماره مجوز جوجه ریزی', + value: location.hatching?.first.licenceNumber.toString() ?? 'N/A', + ), + ], + ), + ), + }, + ], + ), + ); + }, controller.isSelectedDetailsLocation), + isScrollControlled: true, + isDismissible: true, + ); + }, + child: Assets.vec.chickenMapMarkerSvg.svg(width: 24.w, height: 24.h), + ), + ); + } }).toList(); return updatedMarkers;