Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

2.4.0 , addOnPointAnnotationClickListener not working #768

Closed
M2dL1fe opened this issue Nov 13, 2024 · 7 comments
Closed

2.4.0 , addOnPointAnnotationClickListener not working #768

M2dL1fe opened this issue Nov 13, 2024 · 7 comments

Comments

@M2dL1fe
Copy link

M2dL1fe commented Nov 13, 2024

No description provided.

@M2dL1fe M2dL1fe changed the title 2.4.0 , addOnPointAnnotationClickListener invalid 2.4.0 , addOnPointAnnotationClickListener not working Nov 13, 2024
@deandreamatias
Copy link

This is a big issue that need a urgent hotfix

@tungdevpro
Copy link

same here. Currently, onPointAnnotationClick not working on Android

@1990mUkuna
Copy link

1990mUkuna commented Nov 16, 2024

Same here. currently onPointAnnotationClick not working on ios

`
import 'dart:math';
import 'dart:typed_data';
import 'dart:ui';

import 'package:flutter/material.dart';
import 'package:mapbox_maps_flutter/mapbox_maps_flutter.dart';
import 'package:permission_handler/permission_handler.dart';
import 'package:sendmemobi/home_page/pages/slot_detailts.dart';
import 'package:sendmemobi/slot/domain/entities/slots_entity.dart';
import 'package:sendmemobi/utils/const.dart';

class MapSuccessWidget extends StatefulWidget {
final List filteredSlots;
final String authUser;
const MapSuccessWidget({super.key, required this.filteredSlots, required this.authUser});

@OverRide
State createState() => _MapSuccessWidgetState();
}

class _MapSuccessWidgetState extends State {
MapboxMap? mapboxMap;
PointAnnotationManager? pointAnnotationManager;
PointAnnotation? pointAnnotation;
// Map to link PointAnnotations with SlotDataEntity
final Map<String, SlotEntity> annotationSlotMap = {};
String? authUser;
bool isBottomSheetOpen = false;
@OverRide
void initState() {
super.initState();

_requestLocationPermission();

}

Future _requestLocationPermission() async {
var status = await Permission.location.request();
if (status.isGranted) {
// Location permission granted
mapboxMap?.location.updateSettings(LocationComponentSettings(
enabled: true,
locationPuck: LocationPuck(
locationPuck3D: LocationPuck3D(
modelUri:
"https://raw.githubusercontent.comf...........",
),
),
));
} else {}
}

void _onMapCreated(MapboxMap mapboxMap) async {
this.mapboxMap = mapboxMap;
mapboxMap.location.updateSettings(LocationComponentSettings(
enabled: true,
locationPuck: LocationPuck(
locationPuck3D: LocationPuck3D(
modelUri:
"https://raw.githubusercontent.com/...........",
),
),
));

mapboxMap.annotations.createPointAnnotationManager().then((value) async {
  pointAnnotationManager = value;

  for (var slot in widget.filteredSlots) {
    _createMarker(
      slot: slot,
      currentLat: slot.departure.latitude,
      currentLong: slot.departure.longitude,
    );
  }
});

}

@OverRide
Widget build(BuildContext context) {
List markers = widget.filteredSlots.map((slot) {
return MarkerPoint(
latitude: slot.departure.latitude,
longitude: slot.departure.longitude,
);
}).toList();
CameraOptions camera = calculateCameraOptions(markers);
return Stack(
children: [
MapWidget(
key: const ValueKey("mapWidget"),
onMapCreated: (mapboxMap) {
_onMapCreated(mapboxMap);
for (var marker in markers) {
_createMarker(
currentLat: marker.latitude, currentLong: marker.longitude);
}
},
styleUri: 'mapbox://styles/mukuna90/cm0ccsz8g00s001ph0cewchfn',
cameraOptions: camera,
),
],
);
}

Future _createIconBitmap(
IconData icon, Color color, double size) async {
final PictureRecorder pictureRecorder = PictureRecorder();
final Canvas canvas = Canvas(pictureRecorder);
final Paint paint = Paint()..color = color;
final double iconSize = size;
canvas.drawCircle(
Offset(iconSize / 2, iconSize / 2),
iconSize / 2,
paint,
);
final TextPainter textPainter = TextPainter(
textDirection: TextDirection.ltr,
);
textPainter.text = TextSpan(
text: String.fromCharCode(icon.codePoint),
style: TextStyle(
fontSize: iconSize,
fontFamily: icon.fontFamily,
color: AppColors.dashboard,
),
);
textPainter.layout();
textPainter.paint(
canvas,
Offset((iconSize - textPainter.width) / 2,
(iconSize - textPainter.height) / 2),
);

final img = await pictureRecorder.endRecording().toImage(
      iconSize.toInt(),
      iconSize.toInt(),
    );
final ByteData? byteData =
    await img.toByteData(format: ImageByteFormat.png);
return byteData!.buffer.asUint8List();

}

Future _createMarker({
required double currentLat,
required double currentLong,
SlotEntity? slot,
}) async {
final Uint8List iconData =
await _createIconBitmap(Icons.person, Colors.black, 50.0);

pointAnnotationManager
    ?.create(PointAnnotationOptions(
  geometry: Point(
    coordinates: Position(
      currentLong,
      currentLat,
    ),
  ),
  iconSize: 2.5,
  iconOffset: [0.0, -10.0],
  symbolSortKey: 10,
  image: iconData,
))
    .then((PointAnnotation annotation) {
  annotationSlotMap[annotation.id] = slot!;
  pointAnnotationManager?.addOnPointAnnotationClickListener(
    MarkerClickListener(onClick: (annotation) {
      _onPointAnnotationClick(annotation);
    }),
  );
});

}

CameraOptions calculateCameraOptions(List markers) {
if (markers.isEmpty) {
return CameraOptions(
center: Point(coordinates: Position(18.423300, -33.918861)),
zoom: 5,
bearing: 0,
pitch: 0,
);
}

// Calculate the bounding box for the markers
double minLat = markers.map((m) => m.latitude).reduce(min);
double maxLat = markers.map((m) => m.latitude).reduce(max);
double minLng = markers.map((m) => m.longitude).reduce(min);
double maxLng = markers.map((m) => m.longitude).reduce(max);

// Calculate the center of the bounding box
double centerLat = (minLat + maxLat) / 2;
double centerLng = (minLng + maxLng) / 2;

// Calculate spans for latitude and longitude
double latSpan = maxLat - minLat;
double lngSpan = maxLng - minLng;

// Estimate zoom level based on the spans (ensure it's appropriate for country level)
double zoom = (latSpan > lngSpan)
    ? (6 - log(latSpan) / log(2))
    : (6 - log(lngSpan) / log(2));

zoom = zoom.clamp(3.0, 10.0);

return CameraOptions(
  center: Point(coordinates: Position(centerLng, centerLat)),
  zoom: 4,
  bearing: 0,
  pitch: 0,
);

}

void _onPointAnnotationClick(PointAnnotation annotation) {
print("Annotation clicked: ${annotation.id}");
if (isBottomSheetOpen) return; // Prevent multiple bottom sheets
isBottomSheetOpen = true;

_showSlotDetailsBottomSheet(annotation).whenComplete(() {
  isBottomSheetOpen = false; // Reset flag when bottom sheet is closed
});

}

Future _showSlotDetailsBottomSheet(
PointAnnotation annotation,
) async {
SlotEntity? slotDetails = annotationSlotMap[annotation.id];

if (slotDetails == null) {
  return;
}
showModalBottomSheet(
  context: context,
  isScrollControlled: true,
  backgroundColor: Colors.transparent,
  builder: (BuildContext context) {
    return Container(
      decoration: const BoxDecoration(
        color: AppColors.background,
        borderRadius: BorderRadius.only(
          topLeft: Radius.circular(40),
          topRight: Radius.circular(40),
        ),
      ),
      // Pass the slot object instead of just slotId
      child: SingleChildScrollView(
        child: Column(
          children: [
            SizedBox(
              height: MediaQuery.of(context).size.height * 0.5,
              child: SlotDetailtsPage(
                slotDetails: slotDetails,
                userId: authUser ?? '',
              ),
            ),
          ],
        ),
      ),
    );
  },
);

}
}

class MarkerPoint {
final double latitude;
final double longitude;

MarkerPoint({
required this.latitude,
required this.longitude,
});
}

class MarkerClickListener implements OnPointAnnotationClickListener {
final Function(PointAnnotation) onClick;

MarkerClickListener({required this.onClick});

@OverRide
void onPointAnnotationClick(PointAnnotation annotation) {
onClick(annotation);
}
}
`

@tungdevpro
Copy link

Same here. currently onPointAnnotationClick not working on ios

` import 'dart:math'; import 'dart:typed_data'; import 'dart:ui';

import 'package:flutter/material.dart'; import 'package:mapbox_maps_flutter/mapbox_maps_flutter.dart'; import 'package:permission_handler/permission_handler.dart'; import 'package:sendmemobi/home_page/pages/slot_detailts.dart'; import 'package:sendmemobi/slot/domain/entities/slots_entity.dart'; import 'package:sendmemobi/utils/const.dart';

class MapSuccessWidget extends StatefulWidget { final List filteredSlots; final String authUser; const MapSuccessWidget({super.key, required this.filteredSlots, required this.authUser});

@OverRide State createState() => _MapSuccessWidgetState(); }

class _MapSuccessWidgetState extends State { MapboxMap? mapboxMap; PointAnnotationManager? pointAnnotationManager; PointAnnotation? pointAnnotation; // Map to link PointAnnotations with SlotDataEntity final Map<String, SlotEntity> annotationSlotMap = {}; String? authUser; bool isBottomSheetOpen = false; @OverRide void initState() { super.initState();

_requestLocationPermission();

}

Future _requestLocationPermission() async { var status = await Permission.location.request(); if (status.isGranted) { // Location permission granted mapboxMap?.location.updateSettings(LocationComponentSettings( enabled: true, locationPuck: LocationPuck( locationPuck3D: LocationPuck3D( modelUri: "https://raw.githubusercontent.comf...........", ), ), )); } else {} }

void _onMapCreated(MapboxMap mapboxMap) async { this.mapboxMap = mapboxMap; mapboxMap.location.updateSettings(LocationComponentSettings( enabled: true, locationPuck: LocationPuck( locationPuck3D: LocationPuck3D( modelUri: "https://raw.githubusercontent.com/...........", ), ), ));

mapboxMap.annotations.createPointAnnotationManager().then((value) async {
  pointAnnotationManager = value;

  for (var slot in widget.filteredSlots) {
    _createMarker(
      slot: slot,
      currentLat: slot.departure.latitude,
      currentLong: slot.departure.longitude,
    );
  }
});

}

@OverRide Widget build(BuildContext context) { List markers = widget.filteredSlots.map((slot) { return MarkerPoint( latitude: slot.departure.latitude, longitude: slot.departure.longitude, ); }).toList(); CameraOptions camera = calculateCameraOptions(markers); return Stack( children: [ MapWidget( key: const ValueKey("mapWidget"), onMapCreated: (mapboxMap) { _onMapCreated(mapboxMap); for (var marker in markers) { _createMarker( currentLat: marker.latitude, currentLong: marker.longitude); } }, styleUri: 'mapbox://styles/mukuna90/cm0ccsz8g00s001ph0cewchfn', cameraOptions: camera, ), ], ); }

Future _createIconBitmap( IconData icon, Color color, double size) async { final PictureRecorder pictureRecorder = PictureRecorder(); final Canvas canvas = Canvas(pictureRecorder); final Paint paint = Paint()..color = color; final double iconSize = size; canvas.drawCircle( Offset(iconSize / 2, iconSize / 2), iconSize / 2, paint, ); final TextPainter textPainter = TextPainter( textDirection: TextDirection.ltr, ); textPainter.text = TextSpan( text: String.fromCharCode(icon.codePoint), style: TextStyle( fontSize: iconSize, fontFamily: icon.fontFamily, color: AppColors.dashboard, ), ); textPainter.layout(); textPainter.paint( canvas, Offset((iconSize - textPainter.width) / 2, (iconSize - textPainter.height) / 2), );

final img = await pictureRecorder.endRecording().toImage(
      iconSize.toInt(),
      iconSize.toInt(),
    );
final ByteData? byteData =
    await img.toByteData(format: ImageByteFormat.png);
return byteData!.buffer.asUint8List();

}

Future _createMarker({ required double currentLat, required double currentLong, SlotEntity? slot, }) async { final Uint8List iconData = await _createIconBitmap(Icons.person, Colors.black, 50.0);

pointAnnotationManager
    ?.create(PointAnnotationOptions(
  geometry: Point(
    coordinates: Position(
      currentLong,
      currentLat,
    ),
  ),
  iconSize: 2.5,
  iconOffset: [0.0, -10.0],
  symbolSortKey: 10,
  image: iconData,
))
    .then((PointAnnotation annotation) {
  annotationSlotMap[annotation.id] = slot!;
  pointAnnotationManager?.addOnPointAnnotationClickListener(
    MarkerClickListener(onClick: (annotation) {
      _onPointAnnotationClick(annotation);
    }),
  );
});

}

CameraOptions calculateCameraOptions(List markers) { if (markers.isEmpty) { return CameraOptions( center: Point(coordinates: Position(18.423300, -33.918861)), zoom: 5, bearing: 0, pitch: 0, ); }

// Calculate the bounding box for the markers
double minLat = markers.map((m) => m.latitude).reduce(min);
double maxLat = markers.map((m) => m.latitude).reduce(max);
double minLng = markers.map((m) => m.longitude).reduce(min);
double maxLng = markers.map((m) => m.longitude).reduce(max);

// Calculate the center of the bounding box
double centerLat = (minLat + maxLat) / 2;
double centerLng = (minLng + maxLng) / 2;

// Calculate spans for latitude and longitude
double latSpan = maxLat - minLat;
double lngSpan = maxLng - minLng;

// Estimate zoom level based on the spans (ensure it's appropriate for country level)
double zoom = (latSpan > lngSpan)
    ? (6 - log(latSpan) / log(2))
    : (6 - log(lngSpan) / log(2));

zoom = zoom.clamp(3.0, 10.0);

return CameraOptions(
  center: Point(coordinates: Position(centerLng, centerLat)),
  zoom: 4,
  bearing: 0,
  pitch: 0,
);

}

void _onPointAnnotationClick(PointAnnotation annotation) { print("Annotation clicked: ${annotation.id}"); if (isBottomSheetOpen) return; // Prevent multiple bottom sheets isBottomSheetOpen = true;

_showSlotDetailsBottomSheet(annotation).whenComplete(() {
  isBottomSheetOpen = false; // Reset flag when bottom sheet is closed
});

}

Future _showSlotDetailsBottomSheet( PointAnnotation annotation, ) async { SlotEntity? slotDetails = annotationSlotMap[annotation.id];

if (slotDetails == null) {
  return;
}
showModalBottomSheet(
  context: context,
  isScrollControlled: true,
  backgroundColor: Colors.transparent,
  builder: (BuildContext context) {
    return Container(
      decoration: const BoxDecoration(
        color: AppColors.background,
        borderRadius: BorderRadius.only(
          topLeft: Radius.circular(40),
          topRight: Radius.circular(40),
        ),
      ),
      // Pass the slot object instead of just slotId
      child: SingleChildScrollView(
        child: Column(
          children: [
            SizedBox(
              height: MediaQuery.of(context).size.height * 0.5,
              child: SlotDetailtsPage(
                slotDetails: slotDetails,
                userId: authUser ?? '',
              ),
            ),
          ],
        ),
      ),
    );
  },
);

} }

class MarkerPoint { final double latitude; final double longitude;

MarkerPoint({ required this.latitude, required this.longitude, }); }

class MarkerClickListener implements OnPointAnnotationClickListener { final Function(PointAnnotation) onClick;

MarkerClickListener({required this.onClick});

@OverRide void onPointAnnotationClick(PointAnnotation annotation) { onClick(annotation); } } `

My solution is to downgrade to version 2.2.0, and it works perfectly ✌️

@deandreamatias
Copy link

@evil159 can take a look here please?

@evil159
Copy link
Contributor

evil159 commented Nov 18, 2024

Hi all, this is fixed in 2.4.1, sorry for the disturbance.

@M2dL1fe M2dL1fe closed this as completed Nov 19, 2024
@1990mUkuna
Copy link

my solution : mapbox_maps_flutter: ^2.4.1

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

5 participants