### Run Flutter and Pod Commands for Project Setup Source: https://developer.magiclane.com/docs/flutter/get_started/Integrate_SDK Executes essential commands after copying the 'gem_kit' into the project directory. These commands include 'flutter clean' to clear build artifacts, 'flutter pub get' to fetch Dart dependencies, and 'pod install' to install iOS CocoaPods. ```Shell flutter clean flutter pub get cd ios pod install ``` -------------------------------- ### Perform Categorized Search with Maps SDK for Flutter Source: https://developer.magiclane.com/docs/flutter/search/Get_started_search This example demonstrates how to perform a text-based search using the Maps SDK for Flutter, filtering results by specific categories. It initializes search preferences, retrieves predefined categories, adds them to the preferences, and then executes a search around a given position, handling success and error cases. ```Dart const textFilter = "Paris"; final coords = Coordinates(latitude: 45, longitude: 10); final preferences = SearchPreferences( maxMatches: 40, allowFuzzyResults: true, searchMapPOIs: true, searchAddresses: false, ); final categories = GenericCategories.categories; final firstCategory = categories[0]; final secondCategory = categories[1]; preferences.landmarks.addStoreCategoryId( firstCategory.landmarkStoreId, firstCategory.id, ); preferences.landmarks.addStoreCategoryId( secondCategory.landmarkStoreId, secondCategory.id, ); TaskHandler? taskHandler = SearchService.searchAroundPosition( coords, textFilter: textFilter, preferences: preferences, (err, results) async { if (err == GemError.success) { if (results.isEmpty) { showSnackbar("No results"); } else { showSnackbar("Number of results: ${results.length}"); } } else { showSnackbar("Error: $err"); } }, ); ``` -------------------------------- ### Start Navigation Simulation with Instruction Handling in Dart Source: https://developer.magiclane.com/docs/flutter/navigation/Get_started_navigation This Dart code snippet demonstrates how to initiate a navigation simulation using `NavigationService.startSimulation`. It includes a `simulationInstructionUpdated` callback function that processes various `NavigationInstructionUpdateEvents` such as `nextTurnUpdated`, `nextTurnImageUpdated`, and `laneInfoUpdated`. The example also shows how to add a route to the map controller, set an optional `speedMultiplier` for the simulation, and enable camera following. It also briefly mentions how to cancel the navigation. ```Dart void simulationInstructionUpdated(NavigationInstruction instruction, Set events) { for (final event in events) { switch (event) { case NavigationInstructionUpdateEvents.nextTurnUpdated: showSnackbar("Turn updated"); break; case NavigationInstructionUpdateEvents.nextTurnImageUpdated: showSnackbar("Turn image updated"); break; case NavigationInstructionUpdateEvents.laneInfoUpdated: showSnackbar("Lane info updated"); break; } } final instructionText = instruction.nextTurnInstruction; // handle instruction } mapController.preferences.routes.add(route, true); TaskHandler? taskHandler = NavigationService.startSimulation( route, null, onNavigationInstruction: simulationInstructionUpdated, speedMultiplier: 2, ); // [Optional] Set the camera to follow position. // Usually we want this when in navigation mode mapController.startFollowingPosition(); // At any moment, we can cancel the navigation // NavigationService.cancelNavigation(taskHandler); ``` -------------------------------- ### Search Custom Landmarks with Maps SDK for Flutter Source: https://developer.magiclane.com/docs/flutter/search/Get_started_search This example illustrates how to enable search functionality for custom landmarks. It involves creating `Landmark` objects, adding them to a `LandmarkStore`, and then incorporating this store into the `SearchPreferences`. The search is then performed specifically against these custom landmarks, with options to exclude map POIs and addresses. ```Dart // Create the landmarks to be added Landmark landmark1 = Landmark() ..coordinates = Coordinates(latitude: 25, longitude: 30) ..name = "My Custom Landmark1"; Landmark landmark2 = Landmark() ..coordinates = Coordinates(latitude: 25.005, longitude: 30.005) ..name = "My Custom Landmark2"; // Create a store and add the landmarks LandmarkStore store = LandmarkStoreService.createLandmarkStore('LandmarksToBeSearched'); store.addLandmark(landmark1); store.addLandmark(landmark2); // Add the store to the search preferences SearchPreferences preferences = SearchPreferences(); preferences.landmarks.add(store); // If no results from the map POIs should be returned then searchMapPOIs should be set to false preferences.searchMapPOIs = false; // If no results from the addresses should be returned then searchAddresses should be set to false preferences.searchAddresses = false; // Search for landmarks SearchService.search( "My Custom Landmark", Coordinates(latitude: 25.003, longitude: 30.003), preferences: preferences, (err, results) { if (err == GemError.success) { if (results.isEmpty) { showSnackbar("No results"); } else { showSnackbar("Number of results: ${results.length}"); } } else { showSnackbar("Error: $err"); } }, ); ``` -------------------------------- ### Configure Android Location Permissions Source: https://developer.magiclane.com/docs/flutter/positioning/Get_started_positioning To enable location services on Android, add the necessary tags within the block of your android/app/main/AndroidManifest.xml file. These permissions grant access to fine, coarse, and background location data, crucial for location-based features. ```XML ``` -------------------------------- ### Start Navigation and Handle Events in Flutter Source: https://developer.magiclane.com/docs/flutter/navigation/Get_started_navigation This Dart code demonstrates how to start navigation using NavigationService.startNavigation. It defines callback functions for onNavigationInstruction to handle turn-by-turn updates, onDestinationReached for when the destination is met, and onError to manage navigation errors. It also shows how to optionally start camera following and cancel navigation. ```Dart void navigationInstructionUpdated(NavigationInstruction instruction, Set events) { for (final event in events) { switch (event) { case NavigationInstructionUpdateEvents.nextTurnUpdated: showSnackbar("Turn updated"); break; case NavigationInstructionUpdateEvents.nextTurnImageUpdated: showSnackbar("Turn image updated"); break; case NavigationInstructionUpdateEvents.laneInfoUpdated: showSnackbar("Lane info updated"); break; } } final instructionText = instruction.nextTurnInstruction; // handle instruction } void onDestinationReached(Landmark destination) { // handle destination reached } void onError(GemError err) { // handle error } TaskHandler? handler = NavigationService.startNavigation(route, null, onNavigationInstruction: navigationInstructionUpdated, onDestinationReached: onDestinationReached, onError: onError); // [Optional] Set the camera to follow position. // Usually we want this when in navigation mode mapController.startFollowingPosition(); // At any moment, we can cancel the navigation // NavigationService.cancelNavigation(taskHandler); ``` -------------------------------- ### SearchPreferences Fields Reference Source: https://developer.magiclane.com/docs/flutter/search/Get_started_search Defines the configurable fields for `SearchPreferences`, detailing their type, default value, and explanation for controlling search behavior in the Maps SDK for Flutter. ```APIDOC SearchPreferences fields: allowFuzzyResults: Type: bool Default Value: true Explanation: Allows fuzzy search results, enabling approximate matches for queries. estimateMissingHouseNumbers: Type: bool Default Value: true Explanation: Enables estimation of missing house numbers in address searches. exactMatch: Type: bool Default Value: false Explanation: Restricts results to only those that exactly match the query. maxMatches: Type: int Default Value: 40 Explanation: Specifies the maximum number of search results to return. searchAddresses: Type: bool Default Value: true Explanation: Includes addresses in the search results. This option also includes roads. searchMapPOIs: Type: bool Default Value: true Explanation: Includes points of interest (POIs) on the map in the search results. searchOnlyOnboard: Type: bool Default Value: false Explanation: Limits the search to onboard (offline) data only. thresholdDistance: Type: int Default Value: 2147483647 Explanation: Defines the maximum distance (in meters) for search results from the query location. easyAccessOnlyResults: Type: bool Default Value: false Explanation: Restricts results to locations that are easily accessible. ``` -------------------------------- ### Configure iOS Location Usage Description Source: https://developer.magiclane.com/docs/flutter/positioning/Get_started_positioning For iOS applications, you must provide a usage description for location services. Insert the NSLocationWhenInUseUsageDescription and its corresponding value within the block of your ios/Runner/Info.plist file. This string is displayed to users when the app requests location access. ```XML NSLocationWhenInUseUsageDescription Location is needed for map localization and navigation ``` -------------------------------- ### Request Location Permission in Flutter (Dart) Source: https://developer.magiclane.com/docs/flutter/positioning/Get_started_positioning This snippet demonstrates how to request 'locationWhenInUse' permission using the `permission_handler` package in Flutter. It shows how to handle different permission statuses (granted, denied, permanently denied) and, upon granting, how to initialize the live data source for position tracking using `PositionService.instance.setLiveDataSource()`. ```Dart // For Android & iOS platforms, permission_handler package is used to ask for permissions. final locationPermissionStatus = await Permission.locationWhenInUse.request(); if (locationPermissionStatus == PermissionStatus.granted) { // After the permission was granted, we can set the live data source (in most cases the GPS). // The data source should be set only once, otherwise we'll get GemError.exist error. GemError setLiveDataSourceError = PositionService.instance.setLiveDataSource(); showSnackbar("Set live datasource with result: $setLiveDataSourceError"); } if (locationPermissionStatus == PermissionStatus.denied) { // The user denied the permission showSnackbar("Location permission denied"); } if (locationPermissionStatus == PermissionStatus.permanentlyDenied) { // The user permanently denied the permission // The user should go to the app settings to enable the permission showSnackbar("Location permission permanently denied"); } ``` -------------------------------- ### Start Navigation and Listen for Events (Flutter/Dart) Source: https://developer.magiclane.com/docs/flutter/navigation/Get_started_navigation This snippet demonstrates how to initiate navigation using `NavigationService.startNavigation` and register a comprehensive set of callback functions to monitor various navigation events. These events include instruction updates, navigation start/end, waypoint/destination reached, route updates, and better route detection, allowing for detailed control and UI updates. ```Dart void onNavigationInstruction(NavigationInstruction navigationInstruction, Set events) {} void onNavigationStarted() {} void onTextToSpeechInstruction(String text) {} void onWaypointReached(Landmark landmark) {} void onDestinationReached(Landmark landmark) {} void onRouteUpdated(Route route) {} void onBetterRouteDetected( Route route, int travelTime, int delay, int timeGain) {} void onBetterRouteRejected(GemError error) {} void onBetterRouteInvalidated() {} void onSkipNextIntermediateDestinationDetected() {} TaskHandler? taskHandler = NavigationService.startNavigation( route, null, onNavigationInstruction: onNavigationInstruction, onNavigationStarted: onNavigationStarted, onTextToSpeechInstruction: onTextToSpeechInstruction, onWaypointReached: onWaypointReached, onDestinationReached: onDestinationReached, onRouteUpdated: onRouteUpdated, onBetterRouteDetected: onBetterRouteDetected, onBetterRouteRejected: onBetterRouteRejected, onBetterRouteInvalidated: onBetterRouteInvalidated, onSkipNextIntermediateDestinationDetected: onSkipNextIntermediateDestinationDetected, ); ``` -------------------------------- ### Flutter: Display Basic Map View Source: https://developer.magiclane.com/docs/flutter/maps/Get_started This comprehensive example demonstrates how to initialize and display a basic map view within a Flutter application using the GemMap widget. It includes the main application structure, StatelessWidget and StatefulWidget setup, and the basic Scaffold with an AppBar and the GemMap widget. The `onMapCreated` callback is also shown, which provides a `GemMapController` for further map functionalities. ```Dart import 'package:flutter/material.dart'; import 'package:gem_kit/core.dart'; import 'package:gem_kit/map.dart'; const projectApiToken = String.fromEnvironment('GEM_TOKEN'); void main() { runApp(const MyApp()); } class MyApp extends StatelessWidget { const MyApp({super.key}); @override Widget build(BuildContext context) { return const MaterialApp( debugShowCheckedModeBanner: false, title: 'Hello Map', home: MyHomePage(), ); } } class MyHomePage extends StatefulWidget { const MyHomePage({super.key}); @override State createState() => _MyHomePageState(); } class _MyHomePageState extends State { @override void dispose() { GemKit.release(); super.dispose(); } @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( backgroundColor: Colors.deepPurple[900], title: const Text('Hello Map', style: TextStyle(color: Colors.white)), ), body: const GemMap( appAuthorization: projectApiToken, onMapCreated: _onMapCreated, ), ); } void _onMapCreated(GemMapController mapController) { // Code executed when the map is initialized } } ``` -------------------------------- ### Flutter UI and Map Integration Setup Source: https://developer.magiclane.com/docs/flutter/examples/Map_examples/Map_gestures This code defines the basic structure for a Flutter application, including the root `MyApp` widget (a `StatelessWidget`) and the stateful `MyHomePage` widget. It sets up the `MaterialApp` with `debugShowCheckedModeBanner` set to false and 'Map Gestures' as the title, serving as the entry point for the map gesture example. ```Dart class MyApp extends StatelessWidget { const MyApp({super.key}); @override Widget build(BuildContext context) { return const MaterialApp( debugShowCheckedModeBanner: false, title: 'Map Gestures', home: MyHomePage(), ); } } class MyHomePage extends StatefulWidget { const MyHomePage({super.key}); @override State createState() => _MyHomePageState(); } ``` -------------------------------- ### Dart: Main Application Setup and Map Display with GemKit Source: https://developer.magiclane.com/docs/flutter/examples/Map_examples/Map_update This comprehensive snippet outlines the main Flutter application structure, including `main` function initialization, `GemKit` setup with auto-update settings, and the `MyApp` and `MyHomePage` widgets. It demonstrates how to integrate `GemMap` for displaying maps and navigate to a separate map update page. ```Dart void main() async { // Ensuring that all Flutter bindings are initialized WidgetsFlutterBinding.ensureInitialized(); final autoUpdate = AutoUpdateSettings( isAutoUpdateForRoadMapEnabled: false, isAutoUpdateForViewStyleHighResEnabled: false, isAutoUpdateForViewStyleLowResEnabled: false, isAutoUpdateForHumanVoiceEnabled: false, // default isAutoUpdateForComputerVoiceEnabled: false, // default isAutoUpdateForCarModelEnabled: false, // default isAutoUpdateForResourcesEnabled: false, ); GemKit.initialize( appAuthorization: projectApiToken, autoUpdateSettings: autoUpdate) .then((value) async { MapsProvider.instance.init(rootBundle); }); runApp(const MyApp()); } class MyApp extends StatelessWidget { const MyApp({super.key}); @override Widget build(BuildContext context) { return const MaterialApp( debugShowCheckedModeBanner: false, title: 'Map Update', home: MyHomePage(), ); } } class MyHomePage extends StatefulWidget { const MyHomePage({super.key}); @override State createState() => _MyHomePageState(); } class _MyHomePageState extends State { GemMapController? mapController; void onMapCreated(GemMapController controller) async { mapController = controller; } @override void dispose() { GemKit.release(); super.dispose(); } @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( backgroundColor: Colors.deepPurple[900], title: const Text('Map Update', style: TextStyle(color: Colors.white)), actions: [ IconButton( onPressed: () => _onMapButtonTap(context), icon: const Icon(Icons.map_outlined, color: Colors.white), ), ], ), body: GemMap( key: ValueKey("GemMap"), onMapCreated: onMapCreated, appAuthorization: projectApiToken, ), ); } // Method to navigate to the Maps Page. void _onMapButtonTap(BuildContext context) async { if (mapController != null) { Navigator.of(context).push( MaterialPageRoute( builder: (context) => MapsPage(), ), ); } } } ``` -------------------------------- ### Listen for Map Matched Position Updates in Flutter (Dart) Source: https://developer.magiclane.com/docs/flutter/positioning/Get_started_positioning This example demonstrates how to register a listener for map-matched position updates using `PositionService.instance.addImprovedPositionListener()`. The callback receives `GemImprovedPosition` objects, providing detailed information such as coordinates, speed, speed limit, heading angle (course), road modifiers, position quality, and horizontal/vertical accuracy, which are useful for navigation and mapping applications. ```Dart PositionService.instance.addImprovedPositionListener((GemImprovedPosition position) { // Current coordinates Coordinates coordinates = position.coordinates; print("New position: ${coordinates}"); // Speed in m/s (-1 if not available) double speed = position.speed; // Speed limit in m/s on the current road (0 if not available) double speedLimit = position.speedLimit; // Heading angle in degrees (N=0, E=90, S=180, W=270, -1 if not available) double course = position.course; // Information about current road (if it is in a tunnel, bridge, ramp, one way, etc.) Set roadModifiers = position.roadModifiers; // Quality of the current position PositionQuality fixQuality = position.fixQuality; // Horizontal and vertical accuracy in meters double accuracyHorizontal = position.accuracyH; double accuracyVertical = position.accuracyV; }); ``` -------------------------------- ### Listen for Raw Position Updates in Flutter (Dart) Source: https://developer.magiclane.com/docs/flutter/positioning/Get_started_positioning This code snippet illustrates how to subscribe to raw position updates in a Flutter application. By calling `PositionService.instance.addPositionListener()`, a callback function is registered that will continuously receive `GemPosition` objects as new raw position data becomes available from the device's sensors or data source. ```Dart PositionService.instance.addPositionListener((GemPosition position) { // Process the position }); ``` -------------------------------- ### Search for Landmarks Around a Position in Flutter Source: https://developer.magiclane.com/docs/flutter/search/Get_started_search This example illustrates how to find landmarks in the closest proximity to a given set of coordinates using `SearchService.searchAroundPosition`. It demonstrates setting `maxMatches` and `allowFuzzyResults` in `SearchPreferences` and handling the returned list of landmarks. ```Dart final coords = Coordinates(latitude: 45, longitude: 10); final preferences = SearchPreferences( maxMatches: 40, allowFuzzyResults: true, ); TaskHandler? taskHandler = SearchService.searchAroundPosition( coords, preferences: preferences, (err, results) async { // If there is an error or there aren't any results, the method will return an empty list. if (err == GemError.success) { if (results.isEmpty) { showSnackbar("No results"); } else { showSnackbar("Number of results: ${results.length}"); } } else { showSnackbar("Error: $err"); } }, ); ``` -------------------------------- ### Get Current Location using PositionService (Flutter/Dart) Source: https://developer.magiclane.com/docs/flutter/positioning/Get_started_positioning This snippet demonstrates how to synchronously retrieve the current raw location using `PositionService.instance.position`. It checks if a `GemPosition` object is returned and displays the coordinates or a 'No position' message using a Snackbar. A similar approach applies to `improvedPosition` for map-matched data. ```Dart GemPosition? position = PositionService.instance.position; if (position == null) { showSnackbar("No position"); } else { showSnackbar("Position: ${position.coordinates}"); } ``` -------------------------------- ### Flutter UI and GemMap Integration Example Source: https://developer.magiclane.com/docs/flutter/examples/Routing_navigation/Areas_alarms This comprehensive Flutter example demonstrates how to set up a basic application with a `GemMap` widget, an `AppBar` for navigation controls (route calculation, simulation), and handling geographic area notifications. It includes state management for map interactions, drawing areas on the map, and initiating route calculations using `GemMapController` and `RoutingService`. ```Dart const projectApiToken = String.fromEnvironment('GEM_TOKEN'); void main() { runApp(const MyApp()); } class MyApp extends StatelessWidget { const MyApp({super.key}); @override Widget build(BuildContext context) { return const MaterialApp( debugShowCheckedModeBanner: false, title: 'Areas Alarms', home: MyHomePage(), ); } } class MyHomePage extends StatefulWidget { const MyHomePage({super.key}); @override State createState() => _MyHomePageState(); } class _MyHomePageState extends State { late GemMapController _mapController; bool _areRoutesBuilt = false; bool _isSimulationActive = false; // We use the progress listener to cancel the route calculation. TaskHandler? _routingHandler; TaskHandler? _navigationHandler; AlarmService? _alarmService; AlarmListener? _alarmListener; String? _areaNotification; @override void dispose() { GemKit.release(); super.dispose(); } @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: const Text( "Areas Alarms", style: TextStyle(color: Colors.white), ), backgroundColor: Colors.deepPurple[900], actions: [ if (!_isSimulationActive && _areRoutesBuilt) IconButton( onPressed: _startSimulation, icon: const Icon(Icons.play_arrow, color: Colors.white), ), if (_isSimulationActive) IconButton( onPressed: _stopSimulation, icon: const Icon(Icons.stop, color: Colors.white), ), if (!_areRoutesBuilt) IconButton( onPressed: () => _onBuildRouteButtonPressed(context), icon: const Icon(Icons.route, color: Colors.white), ) ] ), body: Stack( children: [ GemMap( key: ValueKey("GemMap"), onMapCreated: _onMapCreated, appAuthorization: projectApiToken, ), if (_areaNotification != null) Positioned( bottom: MediaQuery.of(context).padding.bottom + 10, left: 0, child: BottomAlarmPanel(alarmNotification: _areaNotification), ) ] ), resizeToAvoidBottomInset: false, ); } void _onMapCreated(GemMapController controller) { _mapController = controller; // Draw area on map final marker = Marker(); final circleAreaCoords = generateCircleCoordinates(Coordinates(latitude: 50.92396, longitude: 9.54976), 200); for (final coord in circleAreaCoords) { marker.add(coord); } final markerCollection = MarkerCollection(markerType: MarkerType.polygon, name: "Circle"); markerCollection.add(marker); _mapController.preferences.markers.add(markerCollection, settings: MarkerCollectionRenderSettings(polygonFillColor: const Color.fromARGB(111, 210, 104, 102))); } // Custom method for calling calculate route and displaying the results. void _onBuildRouteButtonPressed(BuildContext context) { // Define the departure. final departureLandmark = Landmark.withLatLng( latitude: 50.92899490001731, longitude: 9.544136681645025, ); // Define the destination. final destinationLandmark = Landmark.withLatLng( latitude: 50.919902402432946, longitude: 9.55855522546262, ); // Define the route preferences. final routePreferences = RoutePreferences(); _showSnackBar(context, message: 'The route is calculating.'); // Calling the calculateRoute SDK method. // (err, results) - is a callback function that gets called when the route computing is finished. // err is an error enum, results is a list of routes. _routingHandler = RoutingService.calculateRoute( [departureLandmark, destinationLandmark], routePreferences, (err, routes) async { // If the route calculation is finished, we don't have a progress listener anymore. _routingHandler = null; ScaffoldMessenger.of(context).clearSnackBars(); // If there aren't any errors, we display the routes. if (err == GemError.success) { // Get the routes collection from map preferences. final routesMap = _mapController.preferences.routes; // Display the routes on map. for (final route in routes) { routesMap.add(route, route == routes.first); } // Center the camera on routes. ``` -------------------------------- ### Start Navigation Simulation in Flutter Source: https://developer.magiclane.com/docs/flutter/examples/Routing_navigation/Lane_instruction This Dart function `_startSimulation` initiates a simulated navigation session using the MagicLane SDK. It first checks for a main route, then starts the simulation, handling navigation instructions to update the UI and managing errors by stopping the simulation. ```Dart void _startSimulation() { final routes = _mapController.preferences.routes; _mapController.preferences.routes.clearAllButMainRoute(); if (routes.mainRoute == null) { _showSnackBar(context, message: "No main route available"); return; } _navigationHandler = NavigationService.startSimulation( routes.mainRoute!, null, onNavigationInstruction: (instruction, events) { setState(() { _isSimulationActive = true; }); currentInstruction = instruction; }, onError: (error) { setState(() { _isSimulationActive = false; _cancelRoute(); }); if (error != GemError.cancel) { _stopSimulation(); } return; }, ); _mapController.startFollowingPosition(); } ``` -------------------------------- ### SearchService.search Callback Error Values Source: https://developer.magiclane.com/docs/flutter/search/Get_started_search This documentation outlines the possible `GemError` values that can be returned by the `onCompleteCallback` function of the `SearchService.search` method. These values indicate the status or specific error encountered during a search operation, such as success, cancellation, memory issues, or network problems. ```APIDOC GemError: success: successfully completed cancel: cancelled by the user noMemory: search engine couldn't allocate the necessary memory for the operation operationTimeout: search was executed on the online service and the operation took too much time to complete (usually more than 1 min, depending on the server overload state) networkTimeout: can't establish the connection or the server didn't respond on time networkFailed: search was executed on the online service and the operation failed due to bad network connection ``` -------------------------------- ### Perform Text Search with Coordinates in Flutter Source: https://developer.magiclane.com/docs/flutter/search/Get_started_search This code demonstrates how to perform a text-based search using the `SearchService.search` method in Flutter. It takes a text query, coordinates for prioritization, and search preferences. The callback handles success, empty results, or errors. A `TaskHandler` is returned, which can be used to cancel the search, but it might be null if initialization fails. ```Dart const text = "Paris"; final coords = Coordinates(latitude: 45, longitude: 10); final preferences = SearchPreferences( maxMatches: 40, allowFuzzyResults: true, ); TaskHandler? taskHandler = SearchService.search( text, coords, preferences: preferences, (err, results) async { // If there is an error or there aren't any results, the method will return an empty list. if (err == GemError.success) { if (results.isEmpty) { showSnackbar("No results"); } else { showSnackbar("Number of results: ${results.length}"); } } else { showSnackbar("Error: $err"); } }, ); ``` -------------------------------- ### Perform Search on Overlays in Flutter Source: https://developer.magiclane.com/docs/flutter/search/Get_started_search This snippet demonstrates how to search for specific items within a map overlay, such as the safety overlay, using the `SearchService.search` method. It shows how to configure `SearchPreferences` to include specific overlay IDs and exclude map POIs or addresses, and how to handle successful results or errors. ```Dart // Get the overlay id of safety int overlayId = CommonOverlayId.safety.id; // Add the overlay to the search preferences SearchPreferences preferences = SearchPreferences(); preferences.overlays.add(overlayId); // We can set searchMapPOIs and searchAddresses to false if no results from the map POIs and addresses should be returned preferences.searchMapPOIs = false; preferences.searchAddresses = false; TaskHandler? taskHandler = SearchService.search( "Speed", Coordinates(latitude: 48.76930, longitude: 2.34483), preferences: preferences, (err, results) { if (err == GemError.success) { if (results.isEmpty) { showSnackbar("No results"); } else { mapController.centerOnCoordinates(results.first.coordinates); showSnackbar("Number of results: ${results.length}"); } } else { showSnackbar("Error: $err"); } }, ); ``` -------------------------------- ### Flutter: Initiate Style Download Source: https://developer.magiclane.com/docs/flutter/examples/Map_examples/Map_style_update This method starts the asynchronous download of a content style. It configures callbacks for download completion and progress updates, and allows downloads over charged networks. ```Dart void _startStyleDownload(ContentStoreItem styleItem) { // Download style styleItem.asyncDownload( _onStyleDownloadFinished, onProgressCallback: _onStyleDownloadProgressUpdated, allowChargedNetworks: true, ); } ``` -------------------------------- ### Configure AlarmService and AlarmListener in Dart Source: https://developer.magiclane.com/docs/flutter/alarms/Get_started_alarms This code snippet defines an AlarmListener and creates an AlarmService based on this listener. Each callback method can be specified to receive notifications about different events or topics, such as boundary crossings, monitoring state changes, tunnel entries or exits, and speed limits. Customizing these callbacks allows tailoring notifications to suit specific use cases, ensuring the system responds appropriately to various triggers or conditions. ```Dart // Create alarm listener and specify callbacks AlarmListener alarmListener = AlarmListener( onBoundaryCrossed: (entered, exited) {}, onMonitoringStateChanged: (isMonitoringActive) {}, onTunnelEntered: () {}, onTunnelLeft: () {}, onLandmarkAlarmsUpdated: () {}, onOverlayItemAlarmsUpdated: () {}, onLandmarkAlarmsPassedOver: () {}, onOverlayItemAlarmsPassedOver: () {}, onHighSpeed: (limit, insideCityArea) {}, onSpeedLimit: (speed, limit, insideCityArea) {}, onNormalSpeed: (limit, insideCityArea) {}, onEnterDayMode: () {}, onEnterNightMode: () {}, ); // Create alarm service based on the previously created listener AlarmService alarmService = AlarmService(alarmListener); ``` -------------------------------- ### Start Navigation Simulation and Position Following (Flutter/Dart) Source: https://developer.magiclane.com/docs/flutter/examples/Routing_navigation/Route_alarms This method initiates a navigation simulation using a pre-defined main route. It sets up an AlarmListener to track overlay items (like points of interest or hazards) and an AlarmService to manage these alarms. It also configures the NavigationService to handle navigation instructions, destination reached events, and errors. Finally, it starts the map camera following the user's position. ```Dart void _startSimulation() { final routes = _mapController.preferences.routes; _mapController.preferences.routes.clearAllButMainRoute(); if (routes.mainRoute == null) { _showSnackBar(context, message: "No main route available"); return; } _alarmListener = AlarmListener( onOverlayItemAlarmsUpdated: () { // The overlay item alarm list containing the overlay items that are to be intercepted OverlayItemAlarmsList overlayItemAlarms = _alarmService!.overlayItemAlarms; // The overlay items and their distance from the reference position // Sorted ascending by distance from the current position List items = overlayItemAlarms.items; if (items.isEmpty) { return; } // The closest overlay item and its associated distance OverlayItemPosition closestOverlayItem = items.first; setState(() { _closestOverlayItem = closestOverlayItem; }); }, // When the overlay item alarms are passed over onOverlayItemAlarmsPassedOver: () { setState(() { _closestOverlayItem = null; }); }, ); // Set the alarms service with the listener _alarmService = AlarmService(_alarmListener!); _alarmService!.alarmDistance = 500; // Add the social reports overlay to be tracked by the alarm service _alarmService!.overlays.add(CommonOverlayId.safety.id); _navigationHandler = NavigationService.startSimulation( routes.mainRoute!, null, onNavigationInstruction: (instruction, events) { setState(() { _isSimulationActive = true; }); }, onDestinationReached: (landmark) { _stopSimulation(); _cancelRoute(); }, onError: (error) { // If the navigation has ended or if an error occurred while navigating, remove routes and reset the closest alarm. setState(() { _isSimulationActive = false; _closestOverlayItem = null; _cancelRoute(); }); if (error != GemError.cancel) { _stopSimulation(); } return; }, ); // Set the camera to follow position. _mapController.startFollowingPosition(); } ``` -------------------------------- ### Demonstrate type conversion in SettingsService Source: https://developer.magiclane.com/docs/flutter/settings_service Shows an example of automatic type conversion when a value is stored as one type (e.g., int) and retrieved as another (e.g., String). ```Dart settings.setInt("count", 1234); String value = settings.getString("count"); // Returns '1234' ``` -------------------------------- ### Perform Step-by-Step Address Geocoding in Flutter Source: https://developer.magiclane.com/docs/flutter/search/Search_geocoding_features This example demonstrates how to use the `searchAddress` function to progressively geocode an address from a country level down to a specific house number. It starts by getting a country landmark, then searches for a city, street, and finally a house number within the previously found landmarks. ```Dart final countryLandmark = GuidedAddressSearchService.getCountryLevelItem('ESP'); showSnackbar('Country: ${countryLandmark!.name}'); // Use the address search to get a landmark for a city in Spain (e.g., Barcelona). final cityLandmark = await searchAddress( landmark: countryLandmark, detailLevel: AddressDetailLevel.city, text: 'Barcelona', ); if (cityLandmark == null) return; showSnackbar('City: ${cityLandmark.name}'); // Use the address search to get a predefined street's landmark in the city (e.g., Carrer de Mallorca). final streetLandmark = await searchAddress( landmark: cityLandmark, detailLevel: AddressDetailLevel.street, text: 'Carrer de Mallorca', ); if (streetLandmark == null) return; showSnackbar('Street: ${streetLandmark.name}'); // Use the address search to get a predefined house number's landmark on the street (e.g., House Number 401). final houseNumberLandmark = await searchAddress( landmark: streetLandmark, detailLevel: AddressDetailLevel.houseNumber, text: '401', ); if (houseNumberLandmark == null) return; showSnackbar('House number: ${houseNumberLandmark.name}'); ``` -------------------------------- ### Initialize Flutter Application with GemMap and Map Style Handling Source: https://developer.magiclane.com/docs/flutter/examples/Map_examples/Map_styles This snippet defines the main Flutter application (`MyApp`) and a stateful widget (`MyHomePage`) that integrates the `GemMap` widget. It demonstrates initializing the map controller, handling map style updates via a callback, and navigating to a map styles selection page to update the map's appearance. It requires the 'magiclane-flutter' SDK and Flutter framework. ```Dart void main() { runApp(const MyApp()); } class MyApp extends StatelessWidget { const MyApp({super.key}); @override Widget build(BuildContext context) { return const MaterialApp( debugShowCheckedModeBanner: false, title: 'Map Styles', home: MyHomePage(), ); } } class MyHomePage extends StatefulWidget { const MyHomePage({super.key}); @override State createState() => _MyHomePageState(); } class _MyHomePageState extends State { // GemMapController object used to interact with the map late GemMapController _mapController; @override void dispose() { GemKit.release(); super.dispose(); } @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( backgroundColor: Colors.deepPurple[900], title: const Text('Map Styles', style: TextStyle(color: Colors.white)), actions: [ IconButton( onPressed: () async => await _onMapButtonTap(context), icon: const Icon(Icons.map_outlined, color: Colors.white), ), ], ), body: GemMap( key: ValueKey("GemMap"), onMapCreated: _onMapCreated, appAuthorization: projectApiToken, ), ); } void _onMapCreated(GemMapController controller) async { _mapController = controller; SdkSettings.setAllowOffboardServiceOnExtraChargedNetwork( ServiceGroupType.contentService, true, ); _mapController.registerSetMapStyleCallback((styleId, stylePath, viaApi) { print("Style updated!"); }); } Future _onMapButtonTap(BuildContext context) async { final result = await Navigator.push( context, MaterialPageRoute( builder: (context) => MapStylesPage(), ), ); if (result != null) { // Handle the returned data // Wait for the map refresh to complete await Future.delayed(Duration(milliseconds: 500)); // Set selected map style _mapController.preferences.setMapStyle(result); } } } ``` -------------------------------- ### Flutter Main App Structure and Map Integration Source: https://developer.magiclane.com/docs/flutter/examples/Map_examples/Map_download This code defines the `MyHomePage` StatefulWidget, which serves as the main entry point for the application's UI. It handles the initialization of the `GemMap` widget, sets up the app bar with a map download button, and manages navigation to the `MapsPage`. It also includes a `dispose` method to release `GemKit` resources. ```dart class MyHomePage extends StatefulWidget { const MyHomePage({super.key}); @override State createState() => _MyHomePageState(); } class _MyHomePageState extends State { @override void dispose() { GemKit.release(); super.dispose(); } @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( backgroundColor: Colors.deepPurple[900], title: const Text( 'Map Download', style: TextStyle(color: Colors.white), ), actions: [ IconButton( onPressed: () => _onMapButtonTap(context), icon: const Icon( Icons.map_outlined, color: Colors.white, ), ), ], ), body: GemMap( key: ValueKey("GemMap"), onMapCreated: _onMapCreated, appAuthorization: projectApiToken, ), ); } void _onMapCreated(GemMapController controller) async { SdkSettings.setAllowOffboardServiceOnExtraChargedNetwork( ServiceGroupType.contentService, true); } void _onMapButtonTap(BuildContext context) async { Navigator.of(context).push(MaterialPageRoute( builder: (context) => const MapsPage(), )); } } ``` -------------------------------- ### Update AlarmService Listener in Flutter Source: https://developer.magiclane.com/docs/flutter/alarms/Get_started_alarms The alarm listener associated with the alarm service can be updated at any time, allowing for dynamic configuration and flexibility in handling various notifications. ```Dart AlarmListener newAlarmListener = AlarmListener(); alarmService.alarmListener = newAlarmListener; ``` -------------------------------- ### Create Flutter App with GemMap Integration Source: https://developer.magiclane.com/docs/flutter/get_started/Create_first_app This Flutter application demonstrates the integration of the GemKit SDK to display an interactive map. It sets up the main application structure, initializes the GemMap widget with an authorization token, and includes a basic app bar. The dispose method ensures proper resource release. ```Dart import 'package:flutter/material.dart'; import 'package:gem_kit/core.dart'; import 'package:gem_kit/map.dart'; const projectApiToken = String.fromEnvironment('GEM_TOKEN'); void main() { runApp(const MyApp()); } class MyApp extends StatelessWidget { const MyApp({super.key}); @override Widget build(BuildContext context) { return const MaterialApp( debugShowCheckedModeBanner: false, title: 'Hello Map', home: MyHomePage(), ); } } class MyHomePage extends StatefulWidget { const MyHomePage({super.key}); @override State createState() => _MyHomePageState(); } class _MyHomePageState extends State { @override void dispose() { GemKit.release(); super.dispose(); } @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( backgroundColor: Colors.deepPurple[900], title: const Text('Hello Map', style: TextStyle(color: Colors.white)), ), body: GemMap( appAuthorization: projectApiToken, onMapCreated: _onMapCreated, ), ); } void _onMapCreated(GemMapController mapController) { // Code executed when map initialized } } ``` -------------------------------- ### Override AlarmListener Callbacks in Flutter Source: https://developer.magiclane.com/docs/flutter/alarms/Get_started_alarms Callbacks within an AlarmListener can be overridden at any time. Only one callback per event can be assigned to a listener; registering a new callback for an event will replace the previously set one. ```Dart alarmListener.registerOnEnterDayMode(() { showSnackbar("Day mode entered"); }); ``` -------------------------------- ### Get Visible Route Interval in Flutter Map Source: https://developer.magiclane.com/docs/flutter/maps/Display_map_items/Display_routes This snippet shows how to use the `getVisibleRouteInterval` method from the `GemMapController` to retrieve the start and end distances (in meters) of the portion of a route that is currently visible on the screen. It returns `(0,0)` if the route is not visible. ```Dart Pair result = mapController.getVisibleRouteInterval(route); int startRouteVisibleIntervalMeters = result.first; int endRouteVisibleIntervalMeters = result.second; ``` -------------------------------- ### Example: Get Path-Based Roadblock Preview (Dart) Source: https://developer.magiclane.com/docs/flutter/navigation/Roadblocks Demonstrates how to use getPersistentRoadblockPathPreview to obtain a preview path for a user-defined roadblock between two coordinate objects. The returned coordinates can be used to draw the path on the UI, and the updated newPreviewStart can be used for chaining segments. ```Dart Coordinates startCoordinates = ... Coordinates endCoordinates = ... UserRoadblockPathPreviewCoordinate previewStart = UserRoadblockPathPreviewCoordinate.fromCoordinates(startCoordinates); final (coordinates, newPreviewStart, previewError) = TrafficService.getPersistentRoadblockPathPreview( from: previewStart, to: endCoordinates, transportMode: RouteTransportMode.car, ); previewStart = newPreviewStart; if (previewError != GemError.success) { print("Error $previewError during preview calculation"); } else { // Draw the path on the UI Path previewPath = Path.fromCoordinates(coordinates); controller.preferences.paths.add(previewPath); // If the user is happy with the roadblock preview, // the roadblock can be added using addPersistentRoadblockByCoordinates } ``` -------------------------------- ### Synchronous Recorder.startRecording() method call (Before Migration) Source: https://developer.magiclane.com/docs/flutter/update_guide/Migrate_to_2_12_0 This code demonstrates the previous synchronous call to `Recorder.startRecording()`. In older versions of the SDK, this method returned immediately without requiring an `await` keyword, which is no longer the case in updated versions. ```Dart Recorder recorder = Recorder.create(recorderConfig); GemError error = recorder.startRecording(); ```