Skip to content

Truck Profile

This example demonstrates how to create a Flutter app that displays a truck profile and calculates routes using gem_kit package.
Users can modify truck parameters and visualize routes on the map.

truck_profile - main screen

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

Navigate to the project folder for this example to build and run the application.

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:

allprojects {
    repositories {
        google()
        mavenCentral()
        maven {
           url "${rootDir}/../plugins/gem_kit/android/build"
        }
    }
}

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

android {
    defaultConfig {
        applicationId "com.magiclane.gem_kit.examples.example_pathname"
        minSdk 21
        targetSdk flutter.targetSdk
        versionCode flutterVersionCode.toInteger()
        versionName flutterVersionName
    }
    buildTypes {
        release {
            minifyEnabled false
            shrinkResources false

            // TODO: Add your own signing config for the release build.
            // Signing with the debug keys for now, so `flutter run --release` works.
            signingConfig signingConfigs.debug
        }
    }
}

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

App entry and initialization

const projectApiToken = String.fromEnvironment('GEM_TOKEN');

void main() {
  runApp(const MyApp());
}

This code initializes the projectApiToken with the required authorization token and launches the app.

How It Works

  • Main App Setup: The main app initializes GemKit and displays a map for routing.

  • Truck Profile Modification: Users can tap a button to modify truck parameters such as height, length, width, axle weight, and more.

  • Route Calculation: Users can calculate routes based on the truck’s profile and visualize them on the map.

User Interface

class MyApp extends StatelessWidget {
  const MyApp({super.key});

  @override
  Widget build(BuildContext context) {
    return const MaterialApp(
      debugShowCheckedModeBanner: false,
      title: 'Truck Profile',
      home: MyHomePage(),
    );
  }
}

class MyHomePage extends StatefulWidget {
  const MyHomePage({super.key});

  @override
  State<MyHomePage> createState() => _MyHomePageState();
}

Main Screen with Truck Profile

class _MyHomePageState extends State<MyHomePage> {
  late GemMapController _mapController;
  final TruckProfile _truckProfile = TruckProfile();
  TaskHandler? _routingHandler;
  List<Route>? _routes;

  @override
  void dispose() {
    GemKit.release();
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        backgroundColor: Colors.deepPurple[900],
        title: const Text('Truck Profile', style: TextStyle(color: Colors.white)),
        actions: [
          if (_routingHandler == null && _routes == null)
            IconButton(
              onPressed: () => _onBuildRouteButtonPressed(context),
              icon: const Icon(Icons.route, color: Colors.white),
            ),
          if (_routingHandler != null)
            IconButton(
              onPressed: () => _onCancelRouteButtonPressed(),
              icon: const Icon(Icons.stop, color: Colors.white),
            ),
          if (_routes != null)
            IconButton(
              onPressed: () => _onClearRoutesButtonPressed(),
              icon: const Icon(Icons.clear, color: Colors.white),
            ),
        ],
      ),
      body: Stack(children: [
        GemMap(onMapCreated: _onMapCreated, appAuthorization: projectApiToken),
        if (_routes == null)
          Positioned(
            top: MediaQuery.of(context).size.height * 0.8,
            left: MediaQuery.of(context).size.width * 0.05,
            child: Container(
              decoration: BoxDecoration(
                color: Colors.deepPurple[900],
                shape: BoxShape.circle,
              ),
              child: IconButton(
                onPressed: () => showTruckProfileDialog(context, _truckProfile),
                icon: Icon(Icons.settings),
                color: Colors.white,
              ),
            ),
          )
      ]),
    );
  }

  // Additional methods for route calculation and UI interactions...
}

This code sets up the main screen with a map and functionality for modifying the truck profile and calculating routes.

Route Calculation

void _onBuildRouteButtonPressed(BuildContext context) {
  final departureLandmark = Landmark.withLatLng(latitude: 48.87126, longitude: 2.33787);
  final destinationLandmark = Landmark.withLatLng(latitude: 51.4739, longitude: -0.0302);
  final routePreferences = RoutePreferences(truckProfile: _truckProfile);

  _showSnackBar(context, message: "The route is being calculated.");

  _routingHandler = RoutingService.calculateRoute(
      [departureLandmark, destinationLandmark], routePreferences,
      (err, routes) {
    _routingHandler = null;
    ScaffoldMessenger.of(context).clearSnackBars();

    if (err == GemError.success) {
      final routesMap = _mapController.preferences.routes;
      for (final route in routes!) {
        routesMap.add(route, route == routes.first, label: route.getMapLabel());
      }
      _mapController.centerOnRoutes(routes: routes);
      setState(() {
        _routes = routes;
      });
    }
  });

  setState(() {});
}

This code handles the route calculation based on the truck’s profile and updates the UI with the calculated routes.

truck_profile - main screen

Truck Profile Modification

class TruckProfileDialog extends StatefulWidget {
  final TruckProfile truckProfile;

  const TruckProfileDialog({super.key, required this.truckProfile});

  @override
  TruckProfileDialogState createState() => TruckProfileDialogState();
}

class TruckProfileDialogState extends State<TruckProfileDialog> {
  late TruckProfile profile;

  @override
  void initState() {
    super.initState();
    profile = widget.truckProfile;
  }

  @override
  Widget build(BuildContext context) {
    return AlertDialog(
      title: Text('Truck Profile'),
      content: SingleChildScrollView(
        child: Column(
          mainAxisSize: MainAxisSize.min,
          children: [
             _buildSlider('Height', profile.height.toDouble() < 180 ? 180 : profile.height.toDouble(), 180, 400,
                 (value) {
                     setState(() {
                     profile.height = value.toInt();
                 });
             }, "cm"),
            // Additional sliders for other truck parameters...
          ],
        ),
      ),
      actions: [
        TextButton(
          onPressed: () {
            Navigator.of(context).pop(profile);
          },
          child: Text('Done'),
        ),
      ],
    );
  }

  // Method for building slider...
}

This dialog allows users to modify the truck profile parameters and returns the updated profile.

Flutter Examples

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