Skip to content

Save Favorites

In this guide, you will learn how to save/delete a favorite location and view the list of favorites.

save_favorites - example flutter screenshot

Setup

First, get an API key token, see the Getting Started guide.

Prerequisites

Make sure you completed the Environment Setup - Flutter Examples guide before starting this guide.

Build and Run

Go to the save_favorites directory within the Flutter examples directory - that is the name of this example project.

Note - the gem_kit directory containing the Maps SDK for Flutter should be in the plugins directory of the example, e.g. example_pathname/plugins/gem_kit - see the environment setup guide above.

Run: flutter pub get

Configure the native parts:

First, verify that the ANDROID_SDK_ROOT environment variable is set to the root path of your android SDK.

In android/build.gradle add the maven block as shown, within the allprojects block, for both debug and release builds:

1    allprojects {
2        repositories {
3            google()
4            mavenCentral()
5            maven {
6               url "${rootDir}/../plugins/gem_kit/android/build"
7            }
8        }
9    }

in android/app/build.gradle within the android block, in the defaultConfig block, the android SDK version minSdk must be set as shown below.

Additionally, for release builds, in android/app/build.gradle, within the android block, add the buildTypes block as shown:

Replace example_pathname with the actual project pathname

 1android {
 2    defaultConfig {
 3        applicationId "com.magiclane.gem_kit.examples.example_pathname"
 4        minSdk 21
 5        targetSdk flutter.targetSdk
 6        versionCode flutterVersionCode.toInteger()
 7        versionName flutterVersionName
 8    }
 9    buildTypes {
10        release {
11            minifyEnabled false
12            shrinkResources false
13
14            // TODO: Add your own signing config for the release build.
15            // Signing with the debug keys for now, so `flutter run --release` works.
16            signingConfig signingConfigs.debug
17        }
18    }
19}

In the ios/Podfile configuration file, at the top, set the minimum ios platform version to 14 like this:

platform :ios, '14.0'

We recommend you to run these commands after you copy the gem_kit into your project: |flutter clean |flutter pub get |and |cd ios |pod install

Then run the project:

flutter run --debug
or
flutter run --release

How It Works

This example demonstrates how to save and manage favorite locations using the ``gem_kit``package.

save_favorites - example flutter screenshot

Import Necessary Packages

First, import the required packages in your Dart code.

1import 'package:gem_kit/core.dart';
2import 'package:gem_kit/landmark_store.dart';
3import 'package:gem_kit/map.dart';
4
5import 'favorites_page.dart';
6import 'landmark_panel.dart';
7
8import 'package:flutter/material.dart';

Initialize GemKit

In the main function, initialize GemKit with your project API token.

1Future<void> main() async {
2  const projectApiToken = String.fromEnvironment('GEM_TOKEN');
3
4  await GemKit.initialize(appAuthorization: projectApiToken);
5
6  runApp(const MyApp());
7}

Build the Main Application

Define the main application widget, MyApp.

 1class MyApp extends StatelessWidget {
 2  const MyApp({super.key});
 3
 4  @override
 5  Widget build(BuildContext context) {
 6    return const MaterialApp(
 7      debugShowCheckedModeBanner: false,
 8      title: 'Save Favorites',
 9      home: MyHomePage(),
10    );
11  }
12}

Handle Map and Favorites in the Stateful Widget

Create the stateful widget, MyHomePage, which will handle the map and favorite locations functionality.

1class MyHomePage extends StatefulWidget {
2  const MyHomePage({super.key});
3
4  @override
5  State<MyHomePage> createState() => _MyHomePageState();
6}

Define State Variables and Methods

Within _MyHomePageState, define the necessary state variables and methods to manage favorites.

 1class _MyHomePageState extends State<MyHomePage> {
 2  late GemMapController _mapController;
 3  Landmark? _focusedLandmark;
 4
 5  // LandmarkStore object to save landmarks.
 6  late LandmarkStore? _favoritesStore;
 7
 8  bool _isLandmarkFavorite = false;
 9
10  final favoritesStoreName = 'Favorites';
11
12  @override
13  void dispose() {
14    GemKit.release();
15    super.dispose();
16  }
17
18  @override
19  Widget build(BuildContext context) {
20    return Scaffold(
21      appBar: AppBar(
22        backgroundColor: Colors.deepPurple[900],
23        title: const Text('Favourites', style: TextStyle(color: Colors.white)),
24        actions: [
25          IconButton(
26              onPressed: () => _onFavouritesButtonPressed(context),
27              icon: const Icon(
28                Icons.favorite,
29                color: Colors.white,
30              ))
31        ],
32      ),
33      body: Stack(children: [
34        GemMap(onMapCreated: _onMapCreated),
35        if (_focusedLandmark != null)
36          Positioned(
37            bottom: 10,
38            child: LandmarkPanel(
39              onCancelTap: _onCancelLandmarkPanelTap,
40              onFavoritesTap: _onFavoritesLandmarkPanelTap,
41              isFavoriteLandmark: _isLandmarkFavorite,
42              landmark: _focusedLandmark!,
43            ),
44          )
45      ]),
46      resizeToAvoidBottomInset: false,
47    );
48  }
49
50  // The callback for when the map is ready to use.
51  void _onMapCreated(GemMapController controller) {
52    _mapController = controller;
53
54    _favoritesStore = LandmarkStoreService.getLandmarkStoreByName(favoritesStoreName);
55    _favoritesStore ??= LandmarkStoreService.createLandmarkStore(favoritesStoreName);
56
57    _registerLandmarkTapCallback();
58  }

Define Landmark Selection and Management

save_favorites - example flutter screenshot

save_favorites - example flutter screenshot

Implement methods to manage landmark selection and favorites.

 1void _registerLandmarkTapCallback() {
 2  _mapController.registerTouchCallback((pos) async {
 3    _mapController.setCursorScreenPosition(pos);
 4    final landmarks = _mapController.cursorSelectionLandmarks();
 5
 6    if (landmarks.isNotEmpty) {
 7      _highlightLandmarks(landmarks);
 8      return;
 9    }
10
11    final coordinates = _mapController.transformScreenToWgs(XyType(x: pos.x as int, y: pos.y as int));
12    if (coordinates == null) return;
13
14    final lmk = Landmark.withCoordinates(coordinates);
15    lmk.name = '${coordinates.latitude} ${coordinates.longitude}';
16    lmk.setImageFromIcon(GemIcon.searchResultsPin);
17    _highlightLandmarks([lmk]);
18  });
19}
20
21void _highlightLandmarks(List<Landmark> landmarks) {
22  _mapController.activateHighlight(landmarks);
23  final lmk = landmarks[0];
24
25  setState(() {
26    _focusedLandmark = lmk;
27  });
28
29  _mapController.centerOnCoordinates(lmk.coordinates);
30  _checkIfFavourite();
31}
32
33void _checkIfFavourite() {
34  final focusedLandmarkCoords = _focusedLandmark!.coordinates;
35  final favourites = _favoritesStore!.getLandmarks();
36
37  for (final lmk in favourites) {
38    if (focusedLandmarkCoords.latitude == lmk.coordinates.latitude &&
39        focusedLandmarkCoords.longitude == lmk.coordinates.longitude) {
40      setState(() {
41        _isLandmarkFavorite = true;
42      });
43      return;
44    }
45  }
46
47  setState(() {
48    _isLandmarkFavorite = false;
49  });
50}
51
52void _onFavoritesLandmarkPanelTap() {
53  _checkIfFavourite();
54
55  if (_isLandmarkFavorite) {
56    _favoritesStore!.removeLandmark(_focusedLandmark!);
57  } else {
58    _favoritesStore!.addLandmark(_focusedLandmark!);
59  }
60  setState(() {
61    _isLandmarkFavorite = !_isLandmarkFavorite;
62  });
63}
64
65void _onCancelLandmarkPanelTap() {
66  _mapController.deactivateAllHighlights();
67  setState(() {
68    _focusedLandmark = null;
69    _isLandmarkFavorite = false;
70  });
71}

Method to Navigate to Favorites

Implement a method to navigate to the favorites list and display it.

 1void _onFavouritesButtonPressed(BuildContext context) async {
 2  final favoritesList = _favoritesStore!.getLandmarks();
 3  final result = await Navigator.of(context).push(MaterialPageRoute<dynamic>(
 4    builder: (context) => FavoritesPage(landmarkList: favoritesList),
 5  ));
 6
 7  if (result is Landmark) {
 8    _mapController.activateHighlight([result], renderSettings: HighlightRenderSettings());
 9    _mapController.centerOnCoordinates(result.coordinates);
10    setState(() {
11      _focusedLandmark = result;
12    });
13    _checkIfFavourite();
14  }
15}

Define Favorites Page and Item Classes

Implement the favorites page and individual favorites item widgets.

 1class FavoritesPage extends StatefulWidget {
 2  final List<Landmark> landmarkList;
 3  const FavoritesPage({super.key, required this.landmarkList});
 4
 5  @override
 6  State<FavoritesPage> createState() => _FavoritesPageState();
 7}
 8
 9class _FavoritesPageState extends State<FavoritesPage> {
10  @override
11  Widget build(BuildContext context) {
12    return Scaffold(
13      appBar: AppBar(
14        foregroundColor: Colors.white,
15        automaticallyImplyLeading: true,
16        title: const Text("Favorites list"),
17        backgroundColor: Colors.deepPurple[900],
18      ),
19      body: ListView.separated(
20        padding: EdgeInsets.zero,
21        itemCount: widget.landmarkList.length,
22        separatorBuilder: (context, index) => const Divider(
23          indent: 50,
24          height: 0,
25        ),
26        itemBuilder: (context, index) {
27          final lmk = widget.landmarkList.elementAt(index);
28          return FavoritesItem(landmark: lmk);
29        },
30      ),
31    );
32  }
33}
34
35class FavoritesItem extends StatefulWidget {
36  final Landmark landmark;
37
38  const FavoritesItem({super.key, required this.landmark});
39
40  @override
41  State<FavoritesItem> createState() => _FavoritesItemState();
42}
43
44class _FavoritesItemState extends State<FavoritesItem> {
45  @override
46  Widget build(BuildContext context) {
47    return ListTile(
48      onTap: () => Navigator.of(context).pop(widget.landmark),
49      leading: Container(
50        padding: const EdgeInsets.all(8),
51        width: 50,
52        child: Image.memory(
53          widget.landmark.getImage(),
54        ),
55      ),
56      title: Text(
57        widget.landmark.name,
58        overflow: TextOverflow.fade,
59        style: const TextStyle(
60            color: Colors.black, fontSize: 14, fontWeight: FontWeight.w400),
61        maxLines: 2,
62      ),
63      subtitle: Text(
64        '${widget.landmark.coordinates.latitude}, ${widget.landmark.coordinates.longitude}',
65        overflow: TextOverflow.fade,
66        style: const TextStyle(
67            color: Colors.black, fontSize: 14, fontWeight: FontWeight.w400),
68        maxLines: 2,
69      ),
70    );
71  }
72}

Flutter Examples

Maps SDK for Flutter Examples can be downloaded or cloned with Git