├── .gitignore ├── .gitmodules ├── .metadata ├── CODE_OF_CONDUCT.md ├── CONTRIBUTING.md ├── HERE_NOTICE ├── LICENSE ├── README.md ├── analysis_options.yaml ├── android ├── .gitignore ├── HERE_NOTICE ├── app │ ├── build.gradle │ ├── proguard-rules.pro │ └── src │ │ ├── debug │ │ └── AndroidManifest.xml │ │ ├── main │ │ ├── AndroidManifest.xml │ │ ├── kotlin │ │ │ └── com │ │ │ │ └── example │ │ │ │ └── RefApp │ │ │ │ ├── FlutterForegroundService.kt │ │ │ │ ├── MainActivity.kt │ │ │ │ └── MainApplication.kt │ │ └── res │ │ │ ├── drawable-v24 │ │ │ └── ic_avatar.xml │ │ │ ├── drawable │ │ │ └── ic_avatar.xml │ │ │ ├── mipmap-hdpi │ │ │ ├── ic_launcher.png │ │ │ └── ic_launcher_notification.png │ │ │ ├── mipmap-mdpi │ │ │ ├── ic_launcher.png │ │ │ └── ic_launcher_notification.png │ │ │ ├── mipmap-xhdpi │ │ │ ├── ic_launcher.png │ │ │ └── ic_launcher_notification.png │ │ │ ├── mipmap-xxhdpi │ │ │ ├── ic_launcher.png │ │ │ └── ic_launcher_notification.png │ │ │ ├── mipmap-xxxhdpi │ │ │ ├── ic_launcher.png │ │ │ └── ic_launcher_notification.png │ │ │ └── values │ │ │ ├── colors.xml │ │ │ ├── strings.xml │ │ │ ├── styles.xml │ │ │ └── themes.xml │ │ └── profile │ │ └── AndroidManifest.xml ├── build.gradle ├── gradle.properties ├── gradle │ └── wrapper │ │ └── gradle-wrapper.properties └── settings.gradle ├── assets ├── app_logo.svg ├── atm_icon.svg ├── atm_icon_disabled.svg ├── car.svg ├── depart_marker.svg ├── eat_and_drink_icon.svg ├── eat_and_drink_icon_disabled.svg ├── fueling_station_icon.svg ├── fueling_station_icon_disabled.svg ├── gps.svg ├── maneuver.svg ├── map_marker.svg ├── map_marker_big.svg ├── map_marker_wp.svg ├── nothing_found.svg ├── position.svg ├── route.svg ├── scooter.svg ├── screenshots.png ├── traffic_off.svg ├── traffic_on.svg ├── truck.svg └── walk.svg ├── ios ├── .gitignore ├── Flutter │ ├── AppFrameworkInfo.plist │ ├── Debug.xcconfig │ └── Release.xcconfig ├── HERE_NOTICE ├── Podfile ├── Podfile.lock ├── Runner.xcodeproj │ ├── project.pbxproj │ ├── project.xcworkspace │ │ ├── contents.xcworkspacedata │ │ └── xcshareddata │ │ │ ├── IDEWorkspaceChecks.plist │ │ │ └── WorkspaceSettings.xcsettings │ └── xcshareddata │ │ └── xcschemes │ │ └── Runner.xcscheme ├── Runner.xcworkspace │ ├── contents.xcworkspacedata │ └── xcshareddata │ │ ├── IDEWorkspaceChecks.plist │ │ └── WorkspaceSettings.xcsettings └── Runner │ ├── AppDelegate.swift │ ├── Assets.xcassets │ ├── AppIcon.appiconset │ │ ├── Contents.json │ │ ├── Icon-App-1024x1024@1x.png │ │ ├── Icon-App-20x20@1x.png │ │ ├── Icon-App-20x20@2x.png │ │ ├── Icon-App-20x20@3x.png │ │ ├── Icon-App-29x29@1x.png │ │ ├── Icon-App-29x29@2x.png │ │ ├── Icon-App-29x29@3x.png │ │ ├── Icon-App-40x40@1x.png │ │ ├── Icon-App-40x40@2x.png │ │ ├── Icon-App-40x40@3x.png │ │ ├── Icon-App-60x60@2x.png │ │ ├── Icon-App-60x60@3x.png │ │ ├── Icon-App-76x76@1x.png │ │ ├── Icon-App-76x76@2x.png │ │ └── Icon-App-83.5x83.5@2x.png │ ├── LaunchImage.imageset │ │ ├── Contents.json │ │ ├── LaunchImage.png │ │ ├── LaunchImage@2x.png │ │ ├── LaunchImage@3x.png │ │ └── README.md │ └── avatar.imageset │ │ ├── Contents.json │ │ └── avatar.svg │ ├── Base.lproj │ ├── LaunchScreen.storyboard │ └── Main.storyboard │ ├── Info-Debug.plist │ ├── Info-Release.plist │ └── Runner-Bridging-Header.h ├── l10n.yaml ├── lib ├── common │ ├── application_preferences.dart │ ├── battery_saver_utils.dart │ ├── connection_state_monitor.dart │ ├── custom_map_style_settings.dart │ ├── device_info.dart │ ├── dismiss_keyboard_on_scroll.dart │ ├── draggable_popup_here_logo_helper.dart │ ├── error_toast.dart │ ├── extensions │ │ ├── error_handling │ │ │ ├── map_loader_error_extension.dart │ │ │ ├── routing_error_extension.dart │ │ │ └── search_error_extension.dart │ │ ├── geo_box_extensions.dart │ │ ├── location_listener_extension.dart │ │ ├── region_extensions.dart │ │ └── truck_specification_extensions.dart │ ├── file_utility.dart │ ├── gradient_elevated_button.dart │ ├── hds_icons │ │ ├── hds_assets_paths.dart │ │ └── hds_icon_widget.dart │ ├── load_custom_style_result_popup.dart │ ├── marquee_widget.dart │ ├── notifications │ │ ├── android_notifications.dart │ │ ├── ios_notifications.dart │ │ └── notifications_manager.dart │ ├── place_actions_popup.dart │ ├── reset_location_button.dart │ ├── ui_style.dart │ ├── util.dart │ └── utils │ │ └── navigation │ │ ├── location_provider_interface.dart │ │ ├── location_providers │ │ ├── positioning_location_provider.dart │ │ └── simulated_location_provider.dart │ │ ├── location_utils.dart │ │ └── position_status_listener.dart ├── download_maps │ ├── download_maps_screen.dart │ ├── map_catalog_update_handler.dart │ ├── map_loader_controller.dart │ ├── map_loader_dialogs.dart │ ├── map_region_tile_widget.dart │ ├── map_regions_list_screen.dart │ ├── map_update_progress_widget.dart │ └── storage_space_widget.dart ├── environment.dart ├── l10n │ └── app_en.arb ├── landing_screen.dart ├── main.dart ├── navigation │ ├── current_maneuver_widget.dart │ ├── maneuver_action_text_helper.dart │ ├── navigation_dialogs.dart │ ├── navigation_progress_widget.dart │ ├── navigation_screen.dart │ ├── navigation_speed_widget.dart │ ├── next_maneuver_widget.dart │ ├── rerouting_handler.dart │ ├── rerouting_indicator_widget.dart │ └── route_progress_widget.dart ├── positioning │ ├── here_privacy_notice_handler.dart │ ├── no_location_warning_widget.dart │ ├── positioning.dart │ └── positioning_engine.dart ├── route_preferences │ ├── avoidance │ │ ├── country_avoidance_screen.dart │ │ ├── road_features_avoidance_screen.dart │ │ └── route_avoidance_options_widget.dart │ ├── car_options_screen.dart │ ├── dropdown_widget.dart │ ├── enum_string_helper.dart │ ├── numeric_text_field_widget.dart │ ├── pedestrian_options_screen.dart │ ├── preferences_disclosure_row_widget.dart │ ├── preferences_row_title_widget.dart │ ├── preferences_section_title_widget.dart │ ├── route_options_widget.dart │ ├── route_preferences_model.dart │ ├── route_preferences_screen.dart │ ├── route_text_options_widget.dart │ ├── scooter_options_screen.dart │ ├── transport_modes_widget.dart │ ├── truck_hazardous_materials_screen.dart │ ├── truck_options_screen.dart │ └── truck_specifications_screen.dart ├── routing │ ├── poi_svg_helper.dart │ ├── route_details_screen.dart │ ├── route_info_widget.dart │ ├── route_poi_handler.dart │ ├── route_poi_options_button.dart │ ├── route_poi_options_item.dart │ ├── route_waypoints_list.dart │ ├── route_waypoints_widget.dart │ ├── routing_screen.dart │ ├── waypoint_info.dart │ └── waypoints_controller.dart └── search │ ├── place_details_popup.dart │ ├── recent_search_data_model.dart │ ├── search_engine_proxy.dart │ ├── search_popup.dart │ └── search_results_screen.dart ├── plugins └── README.md ├── pubspec.lock ├── pubspec.yaml ├── update_submodules.bat └── update_submodules.sh /.gitignore: -------------------------------------------------------------------------------- 1 | # Miscellaneous 2 | *.class 3 | *.log 4 | *.pyc 5 | *.swp 6 | .DS_Store 7 | .atom/ 8 | .buildlog/ 9 | .history 10 | .svn/ 11 | .env/ 12 | build.sh 13 | export-distribution.plist 14 | 15 | # IntelliJ related 16 | *.iml 17 | *.ipr 18 | *.iws 19 | .idea/ 20 | 21 | # The .vscode folder contains launch configuration and tasks you configure in 22 | # VS Code which you may wish to be included in version control, so this line 23 | # is commented out by default. 24 | .vscode/launch.json 25 | 26 | # Flutter/Dart/Pub related 27 | **/doc/api/ 28 | **/ios/Flutter/.last_build_id 29 | .dart_tool/ 30 | .flutter-plugins 31 | .flutter-plugins-dependencies 32 | .packages 33 | .pub-cache/ 34 | .pub/ 35 | /build/ 36 | 37 | # Web related 38 | lib/generated_plugin_registrant.dart 39 | 40 | # Symbolication related 41 | app.*.symbols 42 | 43 | # Obfuscation related 44 | app.*.map.json 45 | 46 | # HERE SDK 4.0 for flutter 47 | plugins/here_sdk 48 | -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "assets/here-icons"] 2 | path = assets/here-icons 3 | url = https://github.com/heremaps/here-icons.git 4 | -------------------------------------------------------------------------------- /.metadata: -------------------------------------------------------------------------------- 1 | # This file tracks properties of this Flutter project. 2 | # Used by Flutter tool to assess capabilities and perform upgrades etc. 3 | # 4 | # This file should be version controlled and should not be manually edited. 5 | 6 | version: 7 | revision: 1aafb3a8b9b0c36241c5f5b34ee914770f015818 8 | channel: stable 9 | 10 | project_type: app 11 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Contributing to the HERE SDK Reference Application for Flutter 2 | 3 | Thank you for taking the time to contribute. 4 | 5 | ## Where to start? 6 | - If you have found issues or have ideas for improvement, [please submit them](https://github.com/heremaps/here-sdk-ref-app-flutter/issues/new) or open a [pull request](https://github.com/heremaps/here-sdk-ref-app-flutter/pulls). 7 | - You can pick any [issue](https://github.com/heremaps/here-sdk-ref-app-flutter/issues) to work on, issues marked as "good first issue" could be good candidates. Before you start add a comment to explain your implementation idea, except for a minor fix. 8 | 9 | ## Signing each Commit 10 | 11 | Please sign off each commit of a pull request. There are two ways to do it: 12 | 13 | Automatically: Use `-s` (or `--signoff`) flag of `git commit` command, see example below: 14 | 15 | `$ git commit -s -m 'README.md: Fix minor spelling mistake'` 16 | 17 | Manually add `Signed-off-by:`, as shown in the example below: 18 | 19 | ``` 20 | README.md: Fix minor spelling mistake 21 | 22 | Signed-off-by: John Doe 23 | ``` 24 | 25 | Any Pull Request with commits that are not signed off will be rejected by the automatic 26 | [DCO check](https://probot.github.io/apps/dco/). A DCO is lightweight way for a contributor to confirm that they wrote or otherwise have the right to submit code or documentation to a project. 27 | -------------------------------------------------------------------------------- /analysis_options.yaml: -------------------------------------------------------------------------------- 1 | analyzer: 2 | exclude: 3 | - plugins/** 4 | -------------------------------------------------------------------------------- /android/.gitignore: -------------------------------------------------------------------------------- 1 | gradle-wrapper.jar 2 | /.gradle 3 | /captures/ 4 | /gradlew 5 | /gradlew.bat 6 | /local.properties 7 | GeneratedPluginRegistrant.java 8 | 9 | # Remember to never publicly share your keystore. 10 | # See https://flutter.dev/docs/deployment/android#reference-the-keystore-from-the-app 11 | key.properties 12 | -------------------------------------------------------------------------------- /android/app/build.gradle: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2020-2025 HERE Europe B.V. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | * 16 | * SPDX-License-Identifier: Apache-2.0 17 | * License-Filename: LICENSE 18 | */ 19 | 20 | plugins { 21 | id "com.android.application" 22 | id "kotlin-android" 23 | id "dev.flutter.flutter-gradle-plugin" 24 | } 25 | 26 | def localProperties = new Properties() 27 | def localPropertiesFile = rootProject.file('local.properties') 28 | if (localPropertiesFile.exists()) { 29 | localPropertiesFile.withReader('UTF-8') { reader -> 30 | localProperties.load(reader) 31 | } 32 | } 33 | 34 | def flutterVersionCode = localProperties.getProperty('flutter.versionCode') 35 | if (flutterVersionCode == null) { 36 | flutterVersionCode = '1' 37 | } 38 | 39 | def flutterVersionName = localProperties.getProperty('flutter.versionName') 40 | if (flutterVersionName == null) { 41 | flutterVersionName = '1.0' 42 | } 43 | 44 | android { 45 | namespace "com.example.RefApp" 46 | compileSdk 35 47 | buildToolsVersion '35.0.0' 48 | 49 | compileOptions { 50 | // Flag to enable support for the new language APIs 51 | coreLibraryDesugaringEnabled true 52 | sourceCompatibility JavaVersion.VERSION_17 53 | targetCompatibility JavaVersion.VERSION_17 54 | } 55 | kotlinOptions { 56 | jvmTarget = '17' 57 | } 58 | 59 | sourceSets { 60 | main.java.srcDirs += 'src/main/kotlin' 61 | } 62 | 63 | lintOptions { 64 | checkReleaseBuilds false 65 | disable 'InvalidPackage' 66 | } 67 | 68 | defaultConfig { 69 | // TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html). 70 | applicationId "com.example.RefApp" 71 | minSdk 24 72 | targetSdk 35 73 | versionCode flutterVersionCode.toInteger() 74 | versionName flutterVersionName 75 | multiDexEnabled true 76 | } 77 | 78 | dependencies { 79 | coreLibraryDesugaring 'com.android.tools:desugar_jdk_libs:1.2.2' 80 | } 81 | 82 | buildTypes { 83 | release { 84 | // TODO: Add your own signing config for the release build. 85 | // Signing with the debug keys for now, so `flutter run --release` works. 86 | signingConfig signingConfigs.debug 87 | proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro' 88 | } 89 | } 90 | } 91 | 92 | flutter { 93 | source '../..' 94 | } 95 | 96 | dependencies { 97 | def core_version = "1.13.1" 98 | implementation "androidx.core:core-ktx:$core_version" 99 | implementation 'androidx.localbroadcastmanager:localbroadcastmanager:1.1.0' 100 | implementation 'androidx.core:core-splashscreen:1.0.1' 101 | } 102 | -------------------------------------------------------------------------------- /android/app/proguard-rules.pro: -------------------------------------------------------------------------------- 1 | # 2 | # Copyright (C) 2020-2025 HERE Europe B.V. 3 | # 4 | # Licensed under the Apache License, Version 2.0 (the "License"); 5 | # you may not use this file except in compliance with the License. 6 | # You may obtain a copy of the License at 7 | # 8 | # http://www.apache.org/licenses/LICENSE-2.0 9 | # 10 | # Unless required by applicable law or agreed to in writing, software 11 | # distributed under the License is distributed on an "AS IS" BASIS, 12 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | # See the License for the specific language governing permissions and 14 | # limitations under the License. 15 | # 16 | # SPDX-License-Identifier: Apache-2.0 17 | # License-Filename: LICENSE 18 | # 19 | 20 | # workaround for https://github.com/flutter/flutter/issues/58479 21 | 22 | -keep class androidx.lifecycle.DefaultLifecycleObserver 23 | -dontwarn com.here.sdk.R$id 24 | -dontwarn com.here.sdk.R$layout 25 | -dontwarn com.here.sdk.R$string 26 | -dontwarn com.here.sdk.R$styleable 27 | -------------------------------------------------------------------------------- /android/app/src/debug/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 3 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /android/app/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 4 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 20 | 21 | 22 | 23 | 24 | 29 | 30 | 40 | 44 | 47 | 48 | 49 | 50 | 51 | 52 | 54 | 57 | 58 | 59 | 62 | 63 | 68 | 69 | 70 | 71 | -------------------------------------------------------------------------------- /android/app/src/main/kotlin/com/example/RefApp/MainApplication.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2020-2025 HERE Europe B.V. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | * 16 | * SPDX-License-Identifier: Apache-2.0 17 | * License-Filename: LICENSE 18 | */ 19 | 20 | package com.example.RefApp 21 | 22 | import android.app.Application; 23 | 24 | import io.flutter.embedding.engine.FlutterEngine; 25 | import io.flutter.embedding.engine.FlutterEngineCache 26 | import io.flutter.embedding.engine.dart.DartExecutor; 27 | 28 | class MainApplication : Application() { 29 | 30 | override fun onCreate() { 31 | super.onCreate() 32 | 33 | val flutterEngine = FlutterEngine(this) 34 | 35 | flutterEngine.dartExecutor.executeDartEntrypoint( 36 | DartExecutor.DartEntrypoint.createDefault()) 37 | 38 | FlutterEngineCache.getInstance().put(MainActivity.FLUTTER_ENGINE_ID, flutterEngine) 39 | } 40 | } -------------------------------------------------------------------------------- /android/app/src/main/res/drawable-v24/ic_avatar.xml: -------------------------------------------------------------------------------- 1 | 7 | 8 | 9 | 15 | 18 | 21 | 22 | 23 | 24 | 28 | 34 | 35 | -------------------------------------------------------------------------------- /android/app/src/main/res/drawable/ic_avatar.xml: -------------------------------------------------------------------------------- 1 | 7 | 8 | 9 | 13 | 14 | 15 | 18 | 23 | 24 | -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-hdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/heremaps/here-sdk-ref-app-flutter/60ab3a29917bc62de4b21c3fc1798f2cac1b8241/android/app/src/main/res/mipmap-hdpi/ic_launcher.png -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-hdpi/ic_launcher_notification.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/heremaps/here-sdk-ref-app-flutter/60ab3a29917bc62de4b21c3fc1798f2cac1b8241/android/app/src/main/res/mipmap-hdpi/ic_launcher_notification.png -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-mdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/heremaps/here-sdk-ref-app-flutter/60ab3a29917bc62de4b21c3fc1798f2cac1b8241/android/app/src/main/res/mipmap-mdpi/ic_launcher.png -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-mdpi/ic_launcher_notification.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/heremaps/here-sdk-ref-app-flutter/60ab3a29917bc62de4b21c3fc1798f2cac1b8241/android/app/src/main/res/mipmap-mdpi/ic_launcher_notification.png -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-xhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/heremaps/here-sdk-ref-app-flutter/60ab3a29917bc62de4b21c3fc1798f2cac1b8241/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-xhdpi/ic_launcher_notification.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/heremaps/here-sdk-ref-app-flutter/60ab3a29917bc62de4b21c3fc1798f2cac1b8241/android/app/src/main/res/mipmap-xhdpi/ic_launcher_notification.png -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/heremaps/here-sdk-ref-app-flutter/60ab3a29917bc62de4b21c3fc1798f2cac1b8241/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-xxhdpi/ic_launcher_notification.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/heremaps/here-sdk-ref-app-flutter/60ab3a29917bc62de4b21c3fc1798f2cac1b8241/android/app/src/main/res/mipmap-xxhdpi/ic_launcher_notification.png -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/heremaps/here-sdk-ref-app-flutter/60ab3a29917bc62de4b21c3fc1798f2cac1b8241/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_notification.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/heremaps/here-sdk-ref-app-flutter/60ab3a29917bc62de4b21c3fc1798f2cac1b8241/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_notification.png -------------------------------------------------------------------------------- /android/app/src/main/res/values/colors.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | #FF262F3A 4 | 5 | -------------------------------------------------------------------------------- /android/app/src/main/res/values/strings.xml: -------------------------------------------------------------------------------- 1 | 2 | Service to keep HERE navigation running in the background 3 | 4 | -------------------------------------------------------------------------------- /android/app/src/main/res/values/styles.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 9 | 12 | 13 | -------------------------------------------------------------------------------- /android/app/src/main/res/values/themes.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 9 | 10 | -------------------------------------------------------------------------------- /android/app/src/profile/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 3 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /android/build.gradle: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2020-2025 HERE Europe B.V. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | * 16 | * SPDX-License-Identifier: Apache-2.0 17 | * License-Filename: LICENSE 18 | */ 19 | 20 | allprojects { 21 | repositories { 22 | google() 23 | mavenCentral() 24 | } 25 | } 26 | 27 | /* To resolve the below error, we added 28 | 29 | Error: 30 | Unable to make progress running work. 31 | There are items queued for execution but none of them can be started 32 | */ 33 | gradle.startParameter.excludedTaskNames.addAll( 34 | gradle.startParameter.taskNames.findAll { it.contains("testClasses") } 35 | ) 36 | 37 | rootProject.layout.buildDirectory = file("../build") 38 | 39 | /* 40 | * After upgrading Flutter, the Android release build encountered issues with several packages, 41 | * resulting in the error: "AAPT: error: resource android:attr/lStar not found." 42 | * 43 | * To resolve this issue, we applied the following changes in our android/build.gradle file. 44 | */ 45 | subprojects { 46 | afterEvaluate { project -> 47 | tasks.withType(org.jetbrains.kotlin.gradle.tasks.KotlinCompile).all { 48 | kotlinOptions { 49 | jvmTarget = "17" 50 | } 51 | } 52 | 53 | tasks.withType(JavaCompile).configureEach { 54 | sourceCompatibility = JavaVersion.VERSION_17.toString() 55 | targetCompatibility = JavaVersion.VERSION_17.toString() 56 | options.compilerArgs += "-Xlint:-options" 57 | } 58 | 59 | // Set Kotlin JVM compile task to show a warning if the JVM target version is incorrect. 60 | // This prevents errors but still informs you if there’s a mismatch in the JVM target version. 61 | tasks.withType(org.jetbrains.kotlin.gradle.tasks.KotlinJvmCompile.class).configureEach { 62 | jvmTargetValidationMode = org.jetbrains.kotlin.gradle.dsl.jvm.JvmTargetValidationMode.WARNING 63 | } 64 | 65 | if (project.plugins.hasPlugin("com.android.application") || 66 | project.plugins.hasPlugin("com.android.library")) { 67 | project.android { 68 | compileSdk 35 69 | } 70 | 71 | android { 72 | defaultConfig { 73 | minSdk 24 // Set the minimum Android SDK version required. 74 | } 75 | } 76 | } 77 | 78 | 79 | 80 | 81 | // If the project has the 'android' property, configure namespace and testNamespace. 82 | if (project.hasProperty('android')) { 83 | project.android { 84 | // Set the namespace if not already set and the Android Gradle Plugin version is 7 or higher. 85 | if (namespace == null) { 86 | namespace project.group // Set namespace using the project's group property. 87 | } 88 | } 89 | } 90 | } 91 | } 92 | 93 | 94 | subprojects { 95 | project.layout.buildDirectory = file("${rootProject.buildDir}/${project.name}") 96 | } 97 | subprojects { 98 | project.evaluationDependsOn(':app') 99 | } 100 | 101 | tasks.register("clean", Delete) { 102 | delete rootProject.layout.buildDirectory 103 | } 104 | -------------------------------------------------------------------------------- /android/gradle.properties: -------------------------------------------------------------------------------- 1 | org.gradle.jvmargs=-Xmx1536M 2 | android.useAndroidX=true 3 | android.enableJetifier=true 4 | -------------------------------------------------------------------------------- /android/gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | #Fri Jul 22 11:13:24 CEST 2022 2 | distributionBase=GRADLE_USER_HOME 3 | distributionPath=wrapper/dists 4 | zipStoreBase=GRADLE_USER_HOME 5 | zipStorePath=wrapper/dists 6 | distributionUrl=https\://services.gradle.org/distributions/gradle-8.9-all.zip 7 | -------------------------------------------------------------------------------- /android/settings.gradle: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2020-2025 HERE Europe B.V. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | * 16 | * SPDX-License-Identifier: Apache-2.0 17 | * License-Filename: LICENSE 18 | */ 19 | 20 | pluginManagement { 21 | def flutterSdkPath = { 22 | def properties = new Properties() 23 | file("local.properties").withInputStream { properties.load(it) } 24 | def flutterSdkPath = properties.getProperty("flutter.sdk") 25 | assert flutterSdkPath != null, "flutter.sdk not set in local.properties" 26 | return flutterSdkPath 27 | } 28 | settings.ext.flutterSdkPath = flutterSdkPath() 29 | 30 | includeBuild("${settings.ext.flutterSdkPath}/packages/flutter_tools/gradle") 31 | 32 | repositories { 33 | google() 34 | mavenCentral() 35 | gradlePluginPortal() 36 | } 37 | } 38 | 39 | plugins { 40 | id "dev.flutter.flutter-plugin-loader" version "1.0.0" 41 | id "com.android.application" version '8.7.2' apply false 42 | id "org.jetbrains.kotlin.android" version "1.9.23" apply false 43 | } 44 | 45 | include ":app" 46 | -------------------------------------------------------------------------------- /assets/app_logo.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | -------------------------------------------------------------------------------- /assets/atm_icon.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /assets/atm_icon_disabled.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /assets/car.svg: -------------------------------------------------------------------------------- 1 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /assets/depart_marker.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /assets/eat_and_drink_icon.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /assets/eat_and_drink_icon_disabled.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /assets/fueling_station_icon.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /assets/fueling_station_icon_disabled.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /assets/gps.svg: -------------------------------------------------------------------------------- 1 | 16 | 17 | -------------------------------------------------------------------------------- /assets/maneuver.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /assets/map_marker.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /assets/map_marker_big.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /assets/map_marker_wp.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /assets/nothing_found.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /assets/position.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | -------------------------------------------------------------------------------- /assets/route.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /assets/scooter.svg: -------------------------------------------------------------------------------- 1 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /assets/screenshots.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/heremaps/here-sdk-ref-app-flutter/60ab3a29917bc62de4b21c3fc1798f2cac1b8241/assets/screenshots.png -------------------------------------------------------------------------------- /assets/traffic_off.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /assets/traffic_on.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /assets/truck.svg: -------------------------------------------------------------------------------- 1 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /assets/walk.svg: -------------------------------------------------------------------------------- 1 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /ios/.gitignore: -------------------------------------------------------------------------------- 1 | build 2 | *.mode1v3 3 | *.mode2v3 4 | *.moved-aside 5 | *.pbxuser 6 | *.perspectivev3 7 | **/*sync/ 8 | .sconsign.dblite 9 | .tags* 10 | **/.vagrant/ 11 | **/DerivedData/ 12 | Icon? 13 | **/Pods/ 14 | **/.symlinks/ 15 | profile 16 | xcuserdata 17 | **/.generated/ 18 | Flutter/App.framework 19 | Flutter/Flutter.framework 20 | Flutter/Flutter.podspec 21 | Flutter/Generated.xcconfig 22 | Flutter/app.flx 23 | Flutter/app.zip 24 | Flutter/flutter_assets/ 25 | Flutter/flutter_export_environment.sh 26 | ServiceDefinitions.json 27 | Runner/GeneratedPluginRegistrant.* 28 | 29 | # Exceptions to above rules. 30 | !default.mode1v3 31 | !default.mode2v3 32 | !default.pbxuser 33 | !default.perspectivev3 34 | -------------------------------------------------------------------------------- /ios/Flutter/AppFrameworkInfo.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | $(DEVELOPMENT_LANGUAGE) 7 | CFBundleExecutable 8 | App 9 | CFBundleIdentifier 10 | io.flutter.flutter.app 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | App 15 | CFBundlePackageType 16 | FMWK 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | 1.0 23 | MinimumOSVersion 24 | 15.0 25 | 26 | 27 | -------------------------------------------------------------------------------- /ios/Flutter/Debug.xcconfig: -------------------------------------------------------------------------------- 1 | #include "Pods/Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig" 2 | #include "Generated.xcconfig" 3 | -------------------------------------------------------------------------------- /ios/Flutter/Release.xcconfig: -------------------------------------------------------------------------------- 1 | #include "Pods/Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig" 2 | #include "Generated.xcconfig" 3 | -------------------------------------------------------------------------------- /ios/Podfile: -------------------------------------------------------------------------------- 1 | # Uncomment this line to define a global platform for your project 2 | platform :ios, '15.0' 3 | 4 | # CocoaPods analytics sends network stats synchronously affecting flutter build latency. 5 | ENV['COCOAPODS_DISABLE_STATS'] = 'true' 6 | 7 | project 'Runner', { 8 | 'Debug' => :debug, 9 | 'Profile' => :release, 10 | 'Release' => :release, 11 | } 12 | 13 | def flutter_root 14 | generated_xcode_build_settings_path = File.expand_path(File.join('..', 'Flutter', 'Generated.xcconfig'), __FILE__) 15 | unless File.exist?(generated_xcode_build_settings_path) 16 | raise "#{generated_xcode_build_settings_path} must exist. If you're running pod install manually, make sure flutter pub get is executed first" 17 | end 18 | 19 | File.foreach(generated_xcode_build_settings_path) do |line| 20 | matches = line.match(/FLUTTER_ROOT\=(.*)/) 21 | return matches[1].strip if matches 22 | end 23 | raise "FLUTTER_ROOT not found in #{generated_xcode_build_settings_path}. Try deleting Generated.xcconfig, then run flutter pub get" 24 | end 25 | 26 | require File.expand_path(File.join('packages', 'flutter_tools', 'bin', 'podhelper'), flutter_root) 27 | 28 | flutter_ios_podfile_setup 29 | 30 | target 'Runner' do 31 | use_frameworks! 32 | use_modular_headers! 33 | 34 | flutter_install_all_ios_pods File.dirname(File.realpath(__FILE__)) 35 | end 36 | 37 | post_install do |installer| 38 | installer.pods_project.targets.each do |target| 39 | flutter_additional_ios_build_settings(target) 40 | target.build_configurations.each do |config| 41 | 42 | # Setup permission_handler plugin. 43 | # for more information: https://github.com/BaseflowIT/flutter-permission-handler/blob/develop/permission_handler/ios/Classes/PermissionHandlerEnums.h 44 | # e.g. when you don't need camera permission, just add 'PERMISSION_CAMERA=0' 45 | config.build_settings['GCC_PREPROCESSOR_DEFINITIONS'] ||= [ 46 | '$(inherited)', 47 | 'PERMISSION_CONTACTS=0', 48 | 'PERMISSION_EVENTS=0', 49 | 'PERMISSION_MEDIA_LIBRARY=0', 50 | 'PERMISSION_REMINDERS=0', 51 | 'PERMISSION_SPEECH_RECOGNIZER=0', 52 | 'PERMISSION_LOCATION=1', 53 | 'PERMISSION_NOTIFICATIONS=1' 54 | ] 55 | config.build_settings["CODE_SIGNING_ALLOWED"] = 'NO' 56 | config.build_settings["CODE_SIGNING_REQUIRED"] = 'NO' 57 | config.build_settings["PROVISIONING_PROFILE"] = '' 58 | config.build_settings["PROVISIONING_PROFILE_SPECIFIER"] = '' 59 | config.build_settings.delete 'IPHONEOS_DEPLOYMENT_TARGET' 60 | end 61 | end 62 | end 63 | -------------------------------------------------------------------------------- /ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDEDidComputeMac32BitWarning 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | PreviewsEnabled 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 24 | 25 | 30 | 31 | 32 | 33 | 39 | 40 | 41 | 42 | 43 | 44 | 54 | 56 | 62 | 63 | 64 | 65 | 66 | 67 | 73 | 75 | 81 | 82 | 83 | 84 | 86 | 87 | 90 | 91 | 92 | -------------------------------------------------------------------------------- /ios/Runner.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /ios/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDEDidComputeMac32BitWarning 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /ios/Runner.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | PreviewsEnabled 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /ios/Runner/AppDelegate.swift: -------------------------------------------------------------------------------- 1 | import UIKit 2 | import Flutter 3 | 4 | @main 5 | @objc class AppDelegate: FlutterAppDelegate { 6 | override func application( 7 | _ application: UIApplication, 8 | didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]? 9 | ) -> Bool { 10 | GeneratedPluginRegistrant.register(with: self) 11 | UNUserNotificationCenter.current().delegate = self as? UNUserNotificationCenterDelegate 12 | return super.application(application, didFinishLaunchingWithOptions: launchOptions) 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "size" : "20x20", 5 | "idiom" : "iphone", 6 | "filename" : "Icon-App-20x20@2x.png", 7 | "scale" : "2x" 8 | }, 9 | { 10 | "size" : "20x20", 11 | "idiom" : "iphone", 12 | "filename" : "Icon-App-20x20@3x.png", 13 | "scale" : "3x" 14 | }, 15 | { 16 | "size" : "29x29", 17 | "idiom" : "iphone", 18 | "filename" : "Icon-App-29x29@1x.png", 19 | "scale" : "1x" 20 | }, 21 | { 22 | "size" : "29x29", 23 | "idiom" : "iphone", 24 | "filename" : "Icon-App-29x29@2x.png", 25 | "scale" : "2x" 26 | }, 27 | { 28 | "size" : "29x29", 29 | "idiom" : "iphone", 30 | "filename" : "Icon-App-29x29@3x.png", 31 | "scale" : "3x" 32 | }, 33 | { 34 | "size" : "40x40", 35 | "idiom" : "iphone", 36 | "filename" : "Icon-App-40x40@2x.png", 37 | "scale" : "2x" 38 | }, 39 | { 40 | "size" : "40x40", 41 | "idiom" : "iphone", 42 | "filename" : "Icon-App-40x40@3x.png", 43 | "scale" : "3x" 44 | }, 45 | { 46 | "size" : "60x60", 47 | "idiom" : "iphone", 48 | "filename" : "Icon-App-60x60@2x.png", 49 | "scale" : "2x" 50 | }, 51 | { 52 | "size" : "60x60", 53 | "idiom" : "iphone", 54 | "filename" : "Icon-App-60x60@3x.png", 55 | "scale" : "3x" 56 | }, 57 | { 58 | "size" : "20x20", 59 | "idiom" : "ipad", 60 | "filename" : "Icon-App-20x20@1x.png", 61 | "scale" : "1x" 62 | }, 63 | { 64 | "size" : "20x20", 65 | "idiom" : "ipad", 66 | "filename" : "Icon-App-20x20@2x.png", 67 | "scale" : "2x" 68 | }, 69 | { 70 | "size" : "29x29", 71 | "idiom" : "ipad", 72 | "filename" : "Icon-App-29x29@1x.png", 73 | "scale" : "1x" 74 | }, 75 | { 76 | "size" : "29x29", 77 | "idiom" : "ipad", 78 | "filename" : "Icon-App-29x29@2x.png", 79 | "scale" : "2x" 80 | }, 81 | { 82 | "size" : "40x40", 83 | "idiom" : "ipad", 84 | "filename" : "Icon-App-40x40@1x.png", 85 | "scale" : "1x" 86 | }, 87 | { 88 | "size" : "40x40", 89 | "idiom" : "ipad", 90 | "filename" : "Icon-App-40x40@2x.png", 91 | "scale" : "2x" 92 | }, 93 | { 94 | "size" : "76x76", 95 | "idiom" : "ipad", 96 | "filename" : "Icon-App-76x76@1x.png", 97 | "scale" : "1x" 98 | }, 99 | { 100 | "size" : "76x76", 101 | "idiom" : "ipad", 102 | "filename" : "Icon-App-76x76@2x.png", 103 | "scale" : "2x" 104 | }, 105 | { 106 | "size" : "83.5x83.5", 107 | "idiom" : "ipad", 108 | "filename" : "Icon-App-83.5x83.5@2x.png", 109 | "scale" : "2x" 110 | }, 111 | { 112 | "size" : "1024x1024", 113 | "idiom" : "ios-marketing", 114 | "filename" : "Icon-App-1024x1024@1x.png", 115 | "scale" : "1x" 116 | } 117 | ], 118 | "info" : { 119 | "version" : 1, 120 | "author" : "xcode" 121 | } 122 | } 123 | -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/heremaps/here-sdk-ref-app-flutter/60ab3a29917bc62de4b21c3fc1798f2cac1b8241/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/heremaps/here-sdk-ref-app-flutter/60ab3a29917bc62de4b21c3fc1798f2cac1b8241/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/heremaps/here-sdk-ref-app-flutter/60ab3a29917bc62de4b21c3fc1798f2cac1b8241/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/heremaps/here-sdk-ref-app-flutter/60ab3a29917bc62de4b21c3fc1798f2cac1b8241/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/heremaps/here-sdk-ref-app-flutter/60ab3a29917bc62de4b21c3fc1798f2cac1b8241/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/heremaps/here-sdk-ref-app-flutter/60ab3a29917bc62de4b21c3fc1798f2cac1b8241/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/heremaps/here-sdk-ref-app-flutter/60ab3a29917bc62de4b21c3fc1798f2cac1b8241/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/heremaps/here-sdk-ref-app-flutter/60ab3a29917bc62de4b21c3fc1798f2cac1b8241/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/heremaps/here-sdk-ref-app-flutter/60ab3a29917bc62de4b21c3fc1798f2cac1b8241/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/heremaps/here-sdk-ref-app-flutter/60ab3a29917bc62de4b21c3fc1798f2cac1b8241/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/heremaps/here-sdk-ref-app-flutter/60ab3a29917bc62de4b21c3fc1798f2cac1b8241/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/heremaps/here-sdk-ref-app-flutter/60ab3a29917bc62de4b21c3fc1798f2cac1b8241/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/heremaps/here-sdk-ref-app-flutter/60ab3a29917bc62de4b21c3fc1798f2cac1b8241/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/heremaps/here-sdk-ref-app-flutter/60ab3a29917bc62de4b21c3fc1798f2cac1b8241/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/heremaps/here-sdk-ref-app-flutter/60ab3a29917bc62de4b21c3fc1798f2cac1b8241/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/LaunchImage.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "filename" : "LaunchImage.png", 6 | "scale" : "1x" 7 | }, 8 | { 9 | "idiom" : "universal", 10 | "filename" : "LaunchImage@2x.png", 11 | "scale" : "2x" 12 | }, 13 | { 14 | "idiom" : "universal", 15 | "filename" : "LaunchImage@3x.png", 16 | "scale" : "3x" 17 | } 18 | ], 19 | "info" : { 20 | "version" : 1, 21 | "author" : "xcode" 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/heremaps/here-sdk-ref-app-flutter/60ab3a29917bc62de4b21c3fc1798f2cac1b8241/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/heremaps/here-sdk-ref-app-flutter/60ab3a29917bc62de4b21c3fc1798f2cac1b8241/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/heremaps/here-sdk-ref-app-flutter/60ab3a29917bc62de4b21c3fc1798f2cac1b8241/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/LaunchImage.imageset/README.md: -------------------------------------------------------------------------------- 1 | # Launch Screen Assets 2 | 3 | You can customize the launch screen with your own desired assets by replacing the image files in this directory. 4 | 5 | You can also do it by opening your Flutter project's Xcode project with `open ios/Runner.xcworkspace`, selecting `Runner/Assets.xcassets` in the Project Navigator and dropping in the desired images. -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/avatar.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "filename" : "avatar.svg", 5 | "idiom" : "universal", 6 | "scale" : "1x" 7 | }, 8 | { 9 | "idiom" : "universal", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "idiom" : "universal", 14 | "scale" : "3x" 15 | } 16 | ], 17 | "info" : { 18 | "author" : "xcode", 19 | "version" : 1 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/avatar.imageset/avatar.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | -------------------------------------------------------------------------------- /ios/Runner/Base.lproj/Main.storyboard: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /ios/Runner/Info-Debug.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | $(DEVELOPMENT_LANGUAGE) 7 | CFBundleDisplayName 8 | HERE SDK Ref App 9 | CFBundleExecutable 10 | $(EXECUTABLE_NAME) 11 | CFBundleIdentifier 12 | $(PRODUCT_BUNDLE_IDENTIFIER) 13 | CFBundleInfoDictionaryVersion 14 | 6.0 15 | CFBundleName 16 | RefApp 17 | CFBundlePackageType 18 | APPL 19 | CFBundleShortVersionString 20 | $(FLUTTER_BUILD_NAME) 21 | CFBundleSignature 22 | ???? 23 | CFBundleVersion 24 | $(FLUTTER_BUILD_NUMBER) 25 | FLTEnableImpeller 26 | 27 | LSRequiresIPhoneOS 28 | 29 | NSBonjourServices 30 | 31 | _dartobservatory._tcp 32 | 33 | NSLocationAlwaysAndWhenInUseUsageDescription 34 | This app needs to access your current location to display it on the map. 35 | NSLocationAlwaysUsageDescription 36 | This app needs to access your location at all times to provide background updates during navigation. 37 | NSLocationWhenInUseUsageDescription 38 | This app needs to access your current location to display it on the map. 39 | NSMotionUsageDescription 40 | Motion detection is needed to determine more accurate locations, when no GPS signal is found or used. 41 | UIBackgroundModes 42 | 43 | audio 44 | fetch 45 | location 46 | 47 | UILaunchStoryboardName 48 | LaunchScreen 49 | UIMainStoryboardFile 50 | Main 51 | UIRequiredDeviceCapabilities 52 | 53 | location-services 54 | gps 55 | 56 | UISupportedInterfaceOrientations 57 | 58 | UIInterfaceOrientationPortrait 59 | 60 | UISupportedInterfaceOrientations~ipad 61 | 62 | UIInterfaceOrientationPortrait 63 | UIInterfaceOrientationPortraitUpsideDown 64 | UIInterfaceOrientationLandscapeLeft 65 | UIInterfaceOrientationLandscapeRight 66 | 67 | UIViewControllerBasedStatusBarAppearance 68 | 69 | io.flutter.embedded_views_preview 70 | 71 | 72 | 73 | -------------------------------------------------------------------------------- /ios/Runner/Info-Release.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | $(DEVELOPMENT_LANGUAGE) 7 | CFBundleDisplayName 8 | HERE SDK Ref App 9 | CFBundleExecutable 10 | $(EXECUTABLE_NAME) 11 | CFBundleIdentifier 12 | $(PRODUCT_BUNDLE_IDENTIFIER) 13 | CFBundleInfoDictionaryVersion 14 | 6.0 15 | CFBundleName 16 | RefApp 17 | CFBundlePackageType 18 | APPL 19 | CFBundleShortVersionString 20 | $(FLUTTER_BUILD_NAME) 21 | CFBundleSignature 22 | ???? 23 | CFBundleVersion 24 | $(FLUTTER_BUILD_NUMBER) 25 | FLTEnableImpeller 26 | 27 | LSRequiresIPhoneOS 28 | 29 | NSLocationAlwaysAndWhenInUseUsageDescription 30 | This app needs to access your current location to display it on the map. 31 | NSLocationAlwaysUsageDescription 32 | This app needs to access your location at all times to provide background updates during navigation. 33 | NSLocationWhenInUseUsageDescription 34 | This app needs to access your current location to display it on the map. 35 | NSMotionUsageDescription 36 | Motion detection is needed to determine more accurate locations, when no GPS signal is found or used. 37 | UIBackgroundModes 38 | 39 | audio 40 | fetch 41 | location 42 | 43 | UILaunchStoryboardName 44 | LaunchScreen 45 | UIMainStoryboardFile 46 | Main 47 | UIRequiredDeviceCapabilities 48 | 49 | location-services 50 | gps 51 | 52 | UISupportedInterfaceOrientations 53 | 54 | UIInterfaceOrientationPortrait 55 | 56 | UISupportedInterfaceOrientations~ipad 57 | 58 | UIInterfaceOrientationPortrait 59 | UIInterfaceOrientationPortraitUpsideDown 60 | UIInterfaceOrientationLandscapeLeft 61 | UIInterfaceOrientationLandscapeRight 62 | 63 | UIViewControllerBasedStatusBarAppearance 64 | 65 | io.flutter.embedded_views_preview 66 | 67 | 68 | 69 | -------------------------------------------------------------------------------- /ios/Runner/Runner-Bridging-Header.h: -------------------------------------------------------------------------------- 1 | #import "GeneratedPluginRegistrant.h" 2 | -------------------------------------------------------------------------------- /l10n.yaml: -------------------------------------------------------------------------------- 1 | arb-dir: lib/l10n 2 | template-arb-file: app_en.arb 3 | output-localization-file: app_localizations.dart 4 | use-escaping: true -------------------------------------------------------------------------------- /lib/common/application_preferences.dart: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2020-2025 HERE Europe B.V. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | * 16 | * SPDX-License-Identifier: Apache-2.0 17 | * License-Filename: LICENSE 18 | */ 19 | 20 | import 'package:flutter/material.dart'; 21 | import 'package:shared_preferences/shared_preferences.dart'; 22 | 23 | /// A class that implements application preferences. 24 | class AppPreferences extends ChangeNotifier { 25 | static final _kAppOfflineParam = "use_app_offline"; 26 | static final _kShowTrafficLayersParam = "show_traffic_layers"; 27 | 28 | /// Key to track if the HERE Privacy Notice dialog was shown on first launch. 29 | static final String _kIsHerePrivacyDialogShown = 'is_here_privacy_dialog_shown'; 30 | 31 | SharedPreferences? _sharedPreferences; 32 | 33 | AppPreferences() { 34 | _initializePreferences(); 35 | } 36 | 37 | void _initializePreferences() async { 38 | _sharedPreferences = await SharedPreferences.getInstance(); 39 | notifyListeners(); 40 | } 41 | 42 | /// If true, app should use offline services. 43 | bool get useAppOffline { 44 | return _sharedPreferences?.getBool(_kAppOfflineParam) ?? false; 45 | } 46 | 47 | /// Setter for [useAppOffline] property. 48 | void set useAppOffline(bool value) { 49 | _sharedPreferences?.setBool(_kAppOfflineParam, value); 50 | notifyListeners(); 51 | } 52 | 53 | /// If true, app should show traffic flow and traffic incidents layers. 54 | bool get showTrafficLayers { 55 | return _sharedPreferences?.getBool(_kShowTrafficLayersParam) ?? true; 56 | } 57 | 58 | /// Setter for [showTrafficLayers] property. 59 | void set showTrafficLayers(bool value) { 60 | _sharedPreferences?.setBool(_kShowTrafficLayersParam, value); 61 | notifyListeners(); 62 | } 63 | 64 | /// Returns true if HERE Privacy Notice was shown. 65 | bool get isHerePrivacyDialogShown => _sharedPreferences?.getBool(_kIsHerePrivacyDialogShown) ?? false; 66 | 67 | /// Sets the HERE Privacy Notice shown flag and notifies listeners on change. 68 | void set isHerePrivacyDialogShown(bool value) { 69 | final current = _sharedPreferences?.getBool(_kIsHerePrivacyDialogShown) ?? false; 70 | if (current != value) { 71 | _sharedPreferences?.setBool(_kIsHerePrivacyDialogShown, value); 72 | notifyListeners(); 73 | } 74 | } 75 | } 76 | -------------------------------------------------------------------------------- /lib/common/battery_saver_utils.dart: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2020-2025 HERE Europe B.V. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | * 16 | * SPDX-License-Identifier: Apache-2.0 17 | * License-Filename: LICENSE 18 | */ 19 | 20 | import 'dart:io'; 21 | 22 | import 'package:battery_plus/battery_plus.dart'; 23 | import 'package:flutter/cupertino.dart'; 24 | import 'package:flutter/services.dart'; 25 | import 'package:flutter_gen/gen_l10n/app_localizations.dart'; 26 | import 'package:here_sdk_reference_application_flutter/common/util.dart'; 27 | 28 | const String _methodChannelName = 'com.example.RefApp/foreground_service_channel'; 29 | const String _methodChannelMethodName = 'openBatterySaverSettings'; 30 | const String _methodChannelMethodArgument = 'battery_saver'; 31 | 32 | // This flag can be used to show the alert dialog if it is not shown 33 | // otherwise, ignore if it is already shown. 34 | bool _isDialogInView = false; 35 | 36 | /// Opens device battery_saver settings 37 | Future openBatterySaverSetting() async { 38 | const MethodChannel channel = MethodChannel(_methodChannelName); 39 | await channel.invokeMethod(_methodChannelMethodName, _methodChannelMethodArgument); 40 | } 41 | 42 | /// Opens Android device battery_saver settings 43 | Future showBatterySaverWarningDialog(BuildContext context) async { 44 | if (!_isDialogInView) { 45 | _isDialogInView = true; 46 | final AppLocalizations localized = AppLocalizations.of(context)!; 47 | final bool openSettings = await showCommonConfirmationDialog( 48 | context: context, 49 | message: localized.batterySaverWarningText, 50 | actionTitle: localized.turnOff, 51 | ); 52 | _isDialogInView = false; 53 | if (openSettings) { 54 | openBatterySaverSetting(); 55 | } 56 | } 57 | } 58 | 59 | /// Returns [true] is battery saver is on and Platform is Android 60 | /// otherwise, returns [false]. 61 | Future isBatterySaverOn() async { 62 | return Platform.isAndroid && await Battery().isInBatterySaveMode; 63 | } 64 | -------------------------------------------------------------------------------- /lib/common/connection_state_monitor.dart: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2020-2025 HERE Europe B.V. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | * 16 | * SPDX-License-Identifier: Apache-2.0 17 | * License-Filename: LICENSE 18 | */ 19 | 20 | import 'dart:async'; 21 | 22 | import 'package:connectivity_plus/connectivity_plus.dart'; 23 | import 'package:flutter/material.dart'; 24 | 25 | import '../download_maps/map_loader_controller.dart'; 26 | 27 | class ConnectionStateMonitor extends StatefulWidget { 28 | const ConnectionStateMonitor({super.key, required this.child, required this.mapLoaderController}); 29 | 30 | final Widget child; 31 | final MapLoaderController mapLoaderController; 32 | 33 | @override 34 | State createState() => _ConnectionStateMonitorState(); 35 | } 36 | 37 | class _ConnectionStateMonitorState extends State { 38 | bool get isConnected => !_status.contains(ConnectivityResult.none); 39 | List _status = []; 40 | late StreamSubscription> _subscription; 41 | 42 | @override 43 | void initState() { 44 | super.initState(); 45 | _subscription = Connectivity().onConnectivityChanged.listen((_) async { 46 | // Check latest connectivity status on connection change. 47 | final List status = await Connectivity().checkConnectivity(); 48 | final bool hasSameConnectionStatus = _status.length == status.length && _status.every(status.contains); 49 | if (!hasSameConnectionStatus) { 50 | _status = status; 51 | if (isConnected) { 52 | // Check for any pending downloads and resume 53 | widget.mapLoaderController.resumePendingMapDownloads(); 54 | } 55 | } 56 | }); 57 | } 58 | 59 | @override 60 | void dispose() { 61 | super.dispose(); 62 | _subscription.cancel(); 63 | } 64 | 65 | @override 66 | Widget build(BuildContext context) => widget.child; 67 | } 68 | -------------------------------------------------------------------------------- /lib/common/custom_map_style_settings.dart: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2020-2025 HERE Europe B.V. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | * 16 | * SPDX-License-Identifier: Apache-2.0 17 | * License-Filename: LICENSE 18 | */ 19 | 20 | import 'package:flutter/material.dart'; 21 | 22 | /// Class used to store custom map style filepath and to inform listeners when filepath changes. 23 | class CustomMapStyleSettings extends ChangeNotifier { 24 | String? _customMapStyleFilepath; 25 | 26 | /// Getter for custom map style filepath. 27 | String? get customMapStyleFilepath => _customMapStyleFilepath; 28 | 29 | /// Setter for custom map style filepath. 30 | void set customMapStyleFilepath(String? newFilepath) { 31 | if (newFilepath != null) { 32 | _customMapStyleFilepath = newFilepath; 33 | notifyListeners(); 34 | } 35 | } 36 | 37 | /// Getter for filename of current custom map style. Empty string is returned when custom map style is not set. 38 | String get customMapStyleFilename { 39 | if (_customMapStyleFilepath == null) { 40 | return ''; 41 | } 42 | return _customMapStyleFilepath!.split('/').last; 43 | } 44 | 45 | void reset() { 46 | _customMapStyleFilepath = null; 47 | notifyListeners(); 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /lib/common/device_info.dart: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2020-2025 HERE Europe B.V. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | * 16 | * SPDX-License-Identifier: Apache-2.0 17 | * License-Filename: LICENSE 18 | */ 19 | 20 | import 'dart:io'; 21 | 22 | import 'package:device_info_plus/device_info_plus.dart'; 23 | 24 | Future getAndroidApiVersion() async { 25 | int apiVersion = -1; 26 | if (Platform.isAndroid) { 27 | final DeviceInfoPlugin deviceInfo = DeviceInfoPlugin(); 28 | final AndroidDeviceInfo androidInfo = await deviceInfo.androidInfo; 29 | apiVersion = androidInfo.version.sdkInt; 30 | } 31 | return apiVersion; 32 | } 33 | -------------------------------------------------------------------------------- /lib/common/dismiss_keyboard_on_scroll.dart: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2020-2025 HERE Europe B.V. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | * 16 | * SPDX-License-Identifier: Apache-2.0 17 | * License-Filename: LICENSE 18 | */ 19 | 20 | import 'package:flutter/material.dart'; 21 | 22 | /// A widget that hides the keyboard when the user scrolls child widget. 23 | class DismissKeyboardOnScroll extends StatelessWidget { 24 | /// Child widget. 25 | final Widget child; 26 | 27 | /// Called when the keyboard is dismissed. 28 | final Function? onDismiss; 29 | 30 | /// Constructs a widget. 31 | const DismissKeyboardOnScroll({ 32 | Key? key, 33 | required this.child, 34 | this.onDismiss, 35 | }) : super(key: key); 36 | 37 | @override 38 | Widget build(BuildContext context) { 39 | return NotificationListener( 40 | onNotification: (x) { 41 | if (x.dragDetails == null) { 42 | return false; 43 | } 44 | 45 | FocusScope.of(context).unfocus(); 46 | onDismiss?.call(); 47 | return false; 48 | }, 49 | child: child, 50 | ); 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /lib/common/draggable_popup_here_logo_helper.dart: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2020-2025 HERE Europe B.V. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | * 16 | * SPDX-License-Identifier: Apache-2.0 17 | * License-Filename: LICENSE 18 | */ 19 | 20 | import 'package:flutter/material.dart'; 21 | import 'package:flutter/scheduler.dart'; 22 | import 'package:here_sdk/core.dart'; 23 | import 'package:here_sdk/mapview.dart'; 24 | 25 | /// A widget that controls position of the HERE logo on the map. 26 | /// It observes the state and position of the child draggable sheet widget and updates the position of the logo 27 | /// to prevent it from overlapping. 28 | class DraggablePopupHereLogoHelper extends StatefulWidget { 29 | /// [HereMapController] that contains the logo. 30 | final HereMapController hereMapController; 31 | 32 | /// [Key] of the map widget. 33 | final GlobalKey hereMapKey; 34 | 35 | /// Child draggable scrollable sheet widget. 36 | final DraggableScrollableSheet draggableScrollableSheet; 37 | 38 | /// Should be true if the child sheet is disposable. 39 | final bool modal; 40 | 41 | /// Constructs a widget. 42 | DraggablePopupHereLogoHelper({ 43 | Key? key, 44 | required this.hereMapController, 45 | required this.hereMapKey, 46 | required this.draggableScrollableSheet, 47 | this.modal = false, 48 | }) : super(key: key); 49 | 50 | @override 51 | _DraggablePopupHereLogoHelperState createState() => _DraggablePopupHereLogoHelperState(); 52 | } 53 | 54 | class _DraggablePopupHereLogoHelperState extends State { 55 | bool _processEvents = true; 56 | 57 | @override 58 | void initState() { 59 | super.initState(); 60 | SchedulerBinding.instance.scheduleFrameCallback((timeStamp) => SchedulerBinding.instance.addPostFrameCallback( 61 | (timeStamp) => _updateHereLogoPosition(widget.draggableScrollableSheet.initialChildSize))); 62 | } 63 | 64 | @override 65 | Widget build(BuildContext context) { 66 | return NotificationListener( 67 | child: widget.draggableScrollableSheet, 68 | onNotification: (notification) { 69 | // The modal sheet is going to close, so don't touch the logo 70 | if (widget.modal && notification.minExtent == notification.extent) { 71 | _processEvents = false; 72 | } 73 | 74 | _updateHereLogoPosition(notification.extent); 75 | return false; 76 | }, 77 | ); 78 | } 79 | 80 | void _updateHereLogoPosition(double extent) { 81 | if (widget.hereMapKey.currentContext == null || !_processEvents) { 82 | return; 83 | } 84 | 85 | final double height = MediaQuery.of(context).size.height; 86 | final double popupHeight = height * extent; 87 | final RenderBox box = widget.hereMapKey.currentContext!.findRenderObject() as RenderBox; 88 | final double margin = (popupHeight - (height - box.paintBounds.bottom)) * widget.hereMapController.pixelScale; 89 | 90 | if (margin >= 0) { 91 | widget.hereMapController.setWatermarkLocation( 92 | Anchor2D.withHorizontalAndVertical(0.5, 1), 93 | Point2D(0, -(widget.hereMapController.watermarkSize.height / 2) - margin.truncate()), 94 | ); 95 | } else { 96 | widget.hereMapController.setWatermarkLocation( 97 | Anchor2D.withHorizontalAndVertical(0, 1), 98 | Point2D( 99 | -widget.hereMapController.watermarkSize.width / 2, 100 | -widget.hereMapController.watermarkSize.height / 2, 101 | ), 102 | ); 103 | } 104 | } 105 | } 106 | -------------------------------------------------------------------------------- /lib/common/extensions/error_handling/map_loader_error_extension.dart: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2020-2025 HERE Europe B.V. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | * 16 | * SPDX-License-Identifier: Apache-2.0 17 | * License-Filename: LICENSE 18 | */ 19 | 20 | import 'package:flutter_gen/gen_l10n/app_localizations.dart'; 21 | import 'package:here_sdk/maploader.dart' show MapLoaderError; 22 | 23 | extension MapLoaderErrorExtension on MapLoaderError { 24 | String errorMessage(AppLocalizations localized) { 25 | String message; 26 | switch (this) { 27 | case MapLoaderError.accessDenied: 28 | case MapLoaderError.forbidden: 29 | case MapLoaderError.requestLimitReached: 30 | message = localized.errorAuthenticationFailed; 31 | break; 32 | 33 | case MapLoaderError.invalidArgument: 34 | message = localized.errorNoResultFound; 35 | break; 36 | 37 | case MapLoaderError.mapManagerError: 38 | case MapLoaderError.operationCancelled: 39 | case MapLoaderError.timeOut: 40 | case MapLoaderError.unexpectedServerResponse: 41 | message = localized.errorMapLoaderErrorOccurredPleaseTryAgain; 42 | break; 43 | 44 | case MapLoaderError.migrationRequired: 45 | case MapLoaderError.protectedCacheCorrupted: 46 | message = localized.errorMapLoaderErrorPerformMigration; 47 | break; 48 | 49 | case MapLoaderError.networkConnectionError: 50 | case MapLoaderError.offline: 51 | case MapLoaderError.proxyAuthenticationFailed: 52 | case MapLoaderError.proxyServerUnreachable: 53 | case MapLoaderError.serviceUnavailable: 54 | message = localized.errorNetworkIssueOccurred; 55 | break; 56 | 57 | default: 58 | message = localized.errorMapLoaderErrorOccurred; 59 | break; 60 | } 61 | 62 | return '$message ($name)'; 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /lib/common/extensions/error_handling/routing_error_extension.dart: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2020-2025 HERE Europe B.V. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | * 16 | * SPDX-License-Identifier: Apache-2.0 17 | * License-Filename: LICENSE 18 | */ 19 | 20 | import 'package:flutter_gen/gen_l10n/app_localizations.dart'; 21 | import 'package:here_sdk/routing.dart' as Routing; 22 | 23 | extension RoutingErrorExtension on Routing.RoutingError { 24 | String errorMessage(AppLocalizations localized) { 25 | String message; 26 | switch (this) { 27 | case Routing.RoutingError.internalError: 28 | case Routing.RoutingError.forbidden: 29 | case Routing.RoutingError.exceededUsageLimit: 30 | case Routing.RoutingError.parsingError: 31 | message = localized.errorRoutingFailed; 32 | break; 33 | 34 | case Routing.RoutingError.serverUnreachable: 35 | case Routing.RoutingError.httpError: 36 | case Routing.RoutingError.timedOut: 37 | case Routing.RoutingError.offline: 38 | message = localized.errorNetworkIssueOccurred; 39 | break; 40 | 41 | case Routing.RoutingError.authenticationFailed: 42 | message = localized.errorAuthenticationFailed; 43 | break; 44 | 45 | case Routing.RoutingError.noRouteFound: 46 | case Routing.RoutingError.invalidParameter: 47 | case Routing.RoutingError.couldNotMatchDestination: 48 | case Routing.RoutingError.couldNotMatchOrigin: 49 | case Routing.RoutingError.routeLengthLimitExceeded: 50 | message = localized.errorNoResultFound; 51 | break; 52 | 53 | default: 54 | message = localized.errorRoutingFailedPleaseTryAgain; 55 | } 56 | return '$message ($name)'; 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /lib/common/extensions/error_handling/search_error_extension.dart: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2020-2025 HERE Europe B.V. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | * 16 | * SPDX-License-Identifier: Apache-2.0 17 | * License-Filename: LICENSE 18 | */ 19 | 20 | import 'package:flutter_gen/gen_l10n/app_localizations.dart'; 21 | import 'package:here_sdk/search.dart' show SearchError; 22 | 23 | extension SearchErrorExtension on SearchError { 24 | String? errorMessage(AppLocalizations localized) { 25 | String? message; 26 | switch (this) { 27 | case SearchError.operationCancelled: 28 | case SearchError.noResultsFound: 29 | message = null; 30 | 31 | case SearchError.authenticationFailed: 32 | case SearchError.forbidden: 33 | message = localized.errorAuthenticationFailed; 34 | 35 | case SearchError.maxItemsOutOfRange: 36 | case SearchError.queryTooLong: 37 | case SearchError.filterTooLong: 38 | message = localized.errorNoResultFound; 39 | 40 | case SearchError.parsingError: 41 | case SearchError.exceededUsageLimit: 42 | case SearchError.operationFailed: 43 | message = localized.errorSearchFailed; 44 | 45 | case SearchError.httpError: 46 | case SearchError.serverUnreachable: 47 | case SearchError.offline: 48 | case SearchError.proxyAuthenticationFailed: 49 | case SearchError.proxyServerUnreachable: 50 | message = localized.errorNetworkIssueOccurred; 51 | 52 | default: 53 | message = localized.errorSearchFailedPleaseTryAgain; 54 | } 55 | 56 | if (message != null) { 57 | return '$message ($name)'; 58 | } 59 | return null; 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /lib/common/extensions/geo_box_extensions.dart: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2020-2025 HERE Europe B.V. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | * 16 | * SPDX-License-Identifier: Apache-2.0 17 | * License-Filename: LICENSE 18 | */ 19 | 20 | import 'package:here_sdk/core.dart'; 21 | 22 | extension GeoBoxExtensionsNullable on GeoBox { 23 | bool get hasDiagonalLength => southWestCorner.distanceTo(northEastCorner) > 0; 24 | 25 | GeoBox expandedByPercentage(double percentage) { 26 | final double diagonalLength = southWestCorner.distanceTo(northEastCorner); 27 | final double padding = hasDiagonalLength ? diagonalLength * percentage : percentage; 28 | return expandedBy(padding, padding, padding, padding); 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /lib/common/extensions/location_listener_extension.dart: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2020-2025 HERE Europe B.V. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | * 16 | * SPDX-License-Identifier: Apache-2.0 17 | * License-Filename: LICENSE 18 | */ 19 | import 'package:here_sdk/core.dart'; 20 | 21 | extension ListLocationListenerX on List { 22 | void notifyOnLocationUpdated(Location location) { 23 | for (final LocationListener listener in this) { 24 | listener.onLocationUpdated(location); 25 | } 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /lib/common/extensions/region_extensions.dart: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2020-2025 HERE Europe B.V. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | * 16 | * SPDX-License-Identifier: Apache-2.0 17 | * License-Filename: LICENSE 18 | */ 19 | import 'package:here_sdk/maploader.dart'; 20 | 21 | extension RegionExtensions on List? { 22 | List? _getChildRegionIds(Region region) { 23 | return region.childRegions?.expand((e) { 24 | if (e.childRegions != null) { 25 | return [e.regionId, ..._getChildRegionIds(e) ?? []]; 26 | } else { 27 | return [e.regionId]; 28 | } 29 | }).toList(); 30 | } 31 | 32 | List regionIds() { 33 | if (this != null) { 34 | return this!.map((e) => [e.regionId, ..._getChildRegionIds(e) ?? []]).expand((e) => e).toList(); 35 | } else { 36 | return []; 37 | } 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /lib/common/gradient_elevated_button.dart: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2020-2025 HERE Europe B.V. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | * 16 | * SPDX-License-Identifier: Apache-2.0 17 | * License-Filename: LICENSE 18 | */ 19 | 20 | import 'package:flutter/material.dart'; 21 | 22 | import 'ui_style.dart'; 23 | 24 | /// A widget for the button with gradient background. 25 | class GradientElevatedButton extends StatelessWidget { 26 | /// Button's title. 27 | final Widget title; 28 | 29 | /// Called when the button is tapped or otherwise activated. 30 | final VoidCallback onPressed; 31 | 32 | /// Background primary color. 33 | final Color primaryColor; 34 | 35 | /// Background secondary color. 36 | final Color secondaryColor; 37 | 38 | /// Constructs the widget. 39 | GradientElevatedButton({ 40 | Key? key, 41 | required this.title, 42 | required this.onPressed, 43 | this.primaryColor = UIStyle.buttonPrimaryColor, 44 | this.secondaryColor = UIStyle.buttonSecondaryColor, 45 | }) : super(key: key); 46 | 47 | @override 48 | Widget build(BuildContext context) => ElevatedButton( 49 | style: ElevatedButton.styleFrom( 50 | padding: EdgeInsets.zero, 51 | shape: RoundedRectangleBorder( 52 | borderRadius: BorderRadius.circular(UIStyle.bigButtonHeight), 53 | ), 54 | ), 55 | child: Ink( 56 | decoration: BoxDecoration( 57 | gradient: LinearGradient( 58 | colors: [ 59 | primaryColor, 60 | secondaryColor, 61 | ], 62 | ), 63 | borderRadius: BorderRadius.circular(UIStyle.bigButtonHeight), 64 | ), 65 | child: Center( 66 | child: Padding( 67 | padding: EdgeInsets.symmetric( 68 | vertical: UIStyle.contentMarginExtraLarge, 69 | horizontal: UIStyle.contentMarginExtraHuge, 70 | ), 71 | child: DefaultTextStyle( 72 | child: title, 73 | style: TextStyle( 74 | color: Theme.of(context).colorScheme.primary, 75 | fontSize: UIStyle.hugeFontSize, 76 | ), 77 | ), 78 | ), 79 | ), 80 | ), 81 | onPressed: onPressed, 82 | ); 83 | } 84 | -------------------------------------------------------------------------------- /lib/common/hds_icons/hds_icon_widget.dart: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2025 HERE Europe B.V. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | * 16 | * SPDX-License-Identifier: Apache-2.0 17 | * License-Filename: LICENSE 18 | */ 19 | 20 | import 'package:flutter/material.dart'; 21 | import 'package:flutter_svg/flutter_svg.dart'; 22 | 23 | import '../ui_style.dart'; 24 | 25 | /// A widget for displaying icons with customizable size and color properties, 26 | /// using assets specified by [assetPath] 27 | /// 28 | /// Example: 29 | /// ```dart 30 | /// HdsIconWidget( pathForIcon, color: Colors.accents ) 31 | /// ``` 32 | 33 | class HdsIconWidget extends StatelessWidget { 34 | /// Creates an [HdsIconWidget] with default icon size ([UIStyle.bigIconSize]). 35 | const HdsIconWidget( 36 | this.assetPath, { 37 | super.key, 38 | this.color, 39 | this.width = UIStyle.bigIconSize, 40 | this.height = UIStyle.bigIconSize, 41 | this.ignoreColor = false, 42 | }); 43 | 44 | /// Creates an [HdsIconWidget] with a small icon size ([UIStyle.smallIconSize]). 45 | const HdsIconWidget.small( 46 | this.assetPath, { 47 | super.key, 48 | this.color, 49 | this.width = UIStyle.smallIconSize, 50 | this.height = UIStyle.smallIconSize, 51 | this.ignoreColor = false, 52 | }); 53 | 54 | /// Creates an [HdsIconWidget] with a medium icon size ([UIStyle.mediumIconSize]). 55 | const HdsIconWidget.medium( 56 | this.assetPath, { 57 | super.key, 58 | this.color, 59 | this.width = UIStyle.mediumIconSize, 60 | this.height = UIStyle.mediumIconSize, 61 | this.ignoreColor = false, 62 | }); 63 | 64 | /// Creates an [HdsIconWidget] with a large icon size ([UIStyle.largeIconSize]). 65 | const HdsIconWidget.large( 66 | this.assetPath, { 67 | super.key, 68 | this.color, 69 | this.width = UIStyle.largeIconSize, 70 | this.height = UIStyle.largeIconSize, 71 | this.ignoreColor = false, 72 | }); 73 | 74 | /// Path of the asset file 75 | final String assetPath; 76 | 77 | /// Color of the icon 78 | /// 79 | /// defaults to 'Theme.of(context).colorScheme.primary' 80 | final Color? color; 81 | 82 | /// Height of the icon 83 | final double height; 84 | 85 | /// Determines whether to ignore the color setting. 86 | /// If true, the color is set to null, effectively ignoring any color settings. 87 | /// If false, the color is applied based on the provided `color` value or falls back 88 | /// to `Theme.of(context).colorScheme.primary` if `color` is null. 89 | final bool ignoreColor; 90 | 91 | /// Width of the icon 92 | final double width; 93 | 94 | bool _isSvg(String filePath) => filePath.toLowerCase().endsWith('.svg'); 95 | 96 | @override 97 | Widget build(BuildContext context) { 98 | return _isSvg(assetPath) 99 | ? SvgPicture.asset( 100 | assetPath, 101 | width: width, 102 | height: height, 103 | colorFilter: ignoreColor 104 | ? null 105 | : ColorFilter.mode( 106 | color ?? Theme.of(context).colorScheme.primary, 107 | BlendMode.srcIn, 108 | ), 109 | ) 110 | : ImageIcon( 111 | AssetImage(assetPath), 112 | size: width, 113 | color: ignoreColor ? null : color ?? Theme.of(context).colorScheme.primary, 114 | ); 115 | } 116 | } 117 | -------------------------------------------------------------------------------- /lib/common/load_custom_style_result_popup.dart: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2020-2025 HERE Europe B.V. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | * 16 | * SPDX-License-Identifier: Apache-2.0 17 | * License-Filename: LICENSE 18 | */ 19 | 20 | import 'package:flutter/material.dart'; 21 | import 'package:flutter_gen/gen_l10n/app_localizations.dart'; 22 | 23 | import '../common/ui_style.dart'; 24 | 25 | /// A widget that displays load custom style result at the bottom of the screen. 26 | class LoadCustomStyleResultPopup extends StatelessWidget { 27 | static const double _kOverlayPosition = 100; 28 | static const double _kOverlayHeight = 50; 29 | 30 | /// Load custom style result, true means success, false means falure. 31 | final bool loadCustomStyleResult; 32 | 33 | /// Called when the close button is tapped or otherwise activated. 34 | final VoidCallback onClosePressed; 35 | 36 | /// Constructs a widget. 37 | LoadCustomStyleResultPopup({ 38 | Key? key, 39 | required this.loadCustomStyleResult, 40 | required this.onClosePressed, 41 | }) : super(key: key); 42 | 43 | @override 44 | Widget build(BuildContext context) { 45 | AppLocalizations localized = AppLocalizations.of(context)!; 46 | return Positioned( 47 | left: UIStyle.contentMarginMedium, 48 | right: UIStyle.contentMarginMedium, 49 | bottom: _kOverlayPosition, 50 | child: Material( 51 | shape: RoundedRectangleBorder( 52 | borderRadius: BorderRadius.all(Radius.circular(UIStyle.popupsBorderRadius)), 53 | ), 54 | color: UIStyle.loadCustomStyleResultPopupBackgroundColor, 55 | elevation: 2, 56 | child: SizedBox( 57 | height: _kOverlayHeight, 58 | child: Center( 59 | child: Row( 60 | crossAxisAlignment: CrossAxisAlignment.center, 61 | children: [ 62 | SizedBox(width: UIStyle.contentMarginLarge), 63 | Expanded( 64 | child: Text( 65 | loadCustomStyleResult ? localized.loadCustomSceneSuccess : localized.loadCustomSceneFailure, 66 | style: TextStyle( 67 | fontSize: UIStyle.bigFontSize, 68 | color: UIStyle.loadCustomStyleResultPopupTextColor, 69 | ), 70 | ), 71 | ), 72 | IconButton( 73 | icon: Icon( 74 | Icons.close, 75 | color: UIStyle.loadCustomStyleResultPopupTextColor, 76 | ), 77 | onPressed: onClosePressed, 78 | ), 79 | ], 80 | ), 81 | ), 82 | ), 83 | ), 84 | ); 85 | } 86 | } 87 | -------------------------------------------------------------------------------- /lib/common/marquee_widget.dart: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2020-2025 HERE Europe B.V. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | * 16 | * SPDX-License-Identifier: Apache-2.0 17 | * License-Filename: LICENSE 18 | */ 19 | 20 | import 'package:flutter/material.dart'; 21 | 22 | /// A Flutter widget that scrolls Widget Text. 23 | class MarqueeWidget extends StatefulWidget { 24 | static const int _kDefaultAnimationDuration = 3000; 25 | static const int _kDefaultBackDuration = 1000; 26 | static const int _kDefaultPauseDuration = 1000; 27 | 28 | /// Child widget. 29 | final Widget child; 30 | 31 | /// Scroll direction. 32 | final Axis direction; 33 | 34 | /// Animation duration. 35 | final Duration animationDuration; 36 | 37 | /// Back animation duration. 38 | final Duration backDuration; 39 | 40 | /// Pause duration. 41 | final Duration pauseDuration; 42 | 43 | /// Constructs the widget. 44 | MarqueeWidget({ 45 | required this.child, 46 | this.direction = Axis.horizontal, 47 | this.animationDuration = const Duration( 48 | milliseconds: _kDefaultAnimationDuration, 49 | ), 50 | this.backDuration = const Duration( 51 | milliseconds: _kDefaultBackDuration, 52 | ), 53 | this.pauseDuration = const Duration( 54 | milliseconds: _kDefaultPauseDuration, 55 | ), 56 | }); 57 | 58 | @override 59 | _MarqueeWidgetState createState() => _MarqueeWidgetState(); 60 | } 61 | 62 | class _MarqueeWidgetState extends State { 63 | late ScrollController _scrollController; 64 | 65 | @override 66 | void initState() { 67 | _scrollController = ScrollController(); 68 | WidgetsBinding.instance.addPostFrameCallback(scroll); 69 | super.initState(); 70 | } 71 | 72 | @override 73 | void dispose() { 74 | _scrollController.dispose(); 75 | super.dispose(); 76 | } 77 | 78 | @override 79 | Widget build(BuildContext context) { 80 | return SingleChildScrollView( 81 | child: widget.child, 82 | scrollDirection: widget.direction, 83 | controller: _scrollController, 84 | ); 85 | } 86 | 87 | void scroll(_) async { 88 | while (_scrollController.hasClients) { 89 | await Future.delayed(widget.pauseDuration); 90 | if (_scrollController.hasClients) 91 | await _scrollController.animateTo( 92 | _scrollController.position.maxScrollExtent, 93 | duration: widget.animationDuration, 94 | curve: Curves.ease, 95 | ); 96 | await Future.delayed(widget.pauseDuration); 97 | if (_scrollController.hasClients) 98 | await _scrollController.animateTo( 99 | 0.0, 100 | duration: widget.backDuration, 101 | curve: Curves.easeOut, 102 | ); 103 | } 104 | } 105 | } 106 | -------------------------------------------------------------------------------- /lib/common/notifications/android_notifications.dart: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2024-2025 HERE Europe B.V. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | * 16 | * SPDX-License-Identifier: Apache-2.0 17 | * License-Filename: LICENSE 18 | */ 19 | 20 | import 'package:flutter/services.dart'; 21 | import 'package:here_sdk_reference_application_flutter/common/file_utility.dart'; 22 | import 'package:here_sdk_reference_application_flutter/common/notifications/notifications_manager.dart'; 23 | import 'package:permission_handler/permission_handler.dart'; 24 | 25 | class AndroidNotificationsManager implements NotificationsManager { 26 | static const MethodChannel _kAndroidServiceChannel = const MethodChannel( 27 | "com.example.RefApp/foreground_service_channel", 28 | ); 29 | static const String _kTitleParam = "title"; 30 | static const String _kContentParam = "content"; 31 | static const String _kLargeIconParam = "large_icon"; 32 | static const String _kSoundEnabledParam = "sound_enabled"; 33 | static const String _kAndroidServiceStartCommand = "startService"; 34 | static const String _kAndroidServiceStopCommand = "stopService"; 35 | 36 | @override 37 | Future init() async { 38 | return await requestNotificationPermissions(); 39 | } 40 | 41 | @override 42 | Future requestNotificationPermissions() async { 43 | final PermissionStatus notificationPermission = await Permission.notification.request(); 44 | return notificationPermission.isGranted || notificationPermission.isLimited; 45 | } 46 | 47 | @override 48 | Future showNotification(NotificationBody body) async { 49 | try { 50 | final String savedImagePath = await FileUtility.saveManeuverImageFromBundle(body.imagePath); 51 | await _kAndroidServiceChannel.invokeMethod(_kAndroidServiceStartCommand, { 52 | _kTitleParam: body.title, 53 | _kContentParam: body.body, 54 | _kLargeIconParam: savedImagePath, 55 | _kSoundEnabledParam: body.presentSound, 56 | }); 57 | } catch (_) { 58 | await _kAndroidServiceChannel.invokeMethod(_kAndroidServiceStartCommand, { 59 | _kTitleParam: body.title, 60 | _kContentParam: body.body, 61 | _kSoundEnabledParam: body.presentSound, 62 | }); 63 | } 64 | } 65 | 66 | @override 67 | Future dismissNotification() async { 68 | await _kAndroidServiceChannel.invokeMethod(_kAndroidServiceStopCommand); 69 | } 70 | } 71 | -------------------------------------------------------------------------------- /lib/common/notifications/ios_notifications.dart: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2024-2025 HERE Europe B.V. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | * 16 | * SPDX-License-Identifier: Apache-2.0 17 | * License-Filename: LICENSE 18 | */ 19 | import 'package:flutter_local_notifications/flutter_local_notifications.dart'; 20 | import 'package:here_sdk_reference_application_flutter/common/file_utility.dart'; 21 | import 'package:here_sdk_reference_application_flutter/common/notifications/notifications_manager.dart'; 22 | 23 | const int _defaultNotificationId = 0; 24 | 25 | class IosNotificationsManager implements NotificationsManager { 26 | FlutterLocalNotificationsPlugin? _maneuverLocalNotificationsPlugin; 27 | 28 | @override 29 | Future init() async { 30 | if (_maneuverLocalNotificationsPlugin == null) { 31 | _maneuverLocalNotificationsPlugin = FlutterLocalNotificationsPlugin(); 32 | var initSettings = InitializationSettings( 33 | iOS: DarwinInitializationSettings(), 34 | ); 35 | await _maneuverLocalNotificationsPlugin!.initialize(initSettings); 36 | } 37 | return await requestNotificationPermissions(); 38 | } 39 | 40 | @override 41 | Future requestNotificationPermissions() async { 42 | return FlutterLocalNotificationsPlugin() 43 | .resolvePlatformSpecificImplementation() 44 | ?.requestPermissions(); 45 | } 46 | 47 | @override 48 | Future showNotification(NotificationBody body) async { 49 | late DarwinNotificationDetails iOSNotificationDetails; 50 | try { 51 | final String savedImagePath = await FileUtility.saveManeuverImageFromBundle(body.imagePath); 52 | iOSNotificationDetails = DarwinNotificationDetails( 53 | presentSound: body.presentSound, 54 | attachments: [DarwinNotificationAttachment(savedImagePath)], 55 | ); 56 | } catch (_) { 57 | iOSNotificationDetails = DarwinNotificationDetails(presentSound: body.presentSound); 58 | } 59 | 60 | var platformChannelSpecifics = NotificationDetails( 61 | iOS: iOSNotificationDetails, 62 | ); 63 | await _maneuverLocalNotificationsPlugin!.show( 64 | _defaultNotificationId, 65 | body.title, 66 | body.body, 67 | platformChannelSpecifics, 68 | ); 69 | } 70 | 71 | @override 72 | Future dismissNotification() async { 73 | _maneuverLocalNotificationsPlugin!.cancel(_defaultNotificationId); 74 | } 75 | } 76 | -------------------------------------------------------------------------------- /lib/common/notifications/notifications_manager.dart: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2024-2025 HERE Europe B.V. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | * 16 | * SPDX-License-Identifier: Apache-2.0 17 | * License-Filename: LICENSE 18 | */ 19 | class NotificationBody { 20 | final String title; 21 | final String body; 22 | final String imagePath; 23 | final bool presentSound; 24 | 25 | NotificationBody({ 26 | required this.title, 27 | required this.body, 28 | required this.imagePath, 29 | this.presentSound = true, 30 | }); 31 | } 32 | 33 | abstract class NotificationsManager { 34 | Future init(); 35 | 36 | Future showNotification(NotificationBody body); 37 | 38 | Future dismissNotification(); 39 | 40 | Future requestNotificationPermissions(); 41 | } 42 | -------------------------------------------------------------------------------- /lib/common/reset_location_button.dart: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2020-2025 HERE Europe B.V. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | * 16 | * SPDX-License-Identifier: Apache-2.0 17 | * License-Filename: LICENSE 18 | */ 19 | 20 | import 'package:flutter/material.dart'; 21 | 22 | import 'ui_style.dart'; 23 | 24 | /// A widget for the reset current location floating button. 25 | class ResetLocationButton extends StatelessWidget { 26 | /// Called when the button is tapped or otherwise activated. 27 | final VoidCallback onPressed; 28 | 29 | /// Constructs a widget. 30 | ResetLocationButton({ 31 | required this.onPressed, 32 | }); 33 | 34 | @override 35 | Widget build(BuildContext context) { 36 | return Container( 37 | width: UIStyle.mediumButtonHeight, 38 | height: UIStyle.mediumButtonHeight, 39 | child: FloatingActionButton( 40 | heroTag: null, 41 | backgroundColor: Theme.of(context).colorScheme.surface, 42 | child: Icon(Icons.gps_fixed), 43 | onPressed: onPressed, 44 | ), 45 | ); 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /lib/common/utils/navigation/location_provider_interface.dart: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2020-2025 HERE Europe B.V. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | * 16 | * SPDX-License-Identifier: Apache-2.0 17 | * License-Filename: LICENSE 18 | */ 19 | import 'package:here_sdk/core.dart'; 20 | 21 | abstract class LocationProviderInterface { 22 | void addListener(LocationListener listener); 23 | 24 | void removeListener(LocationListener listener); 25 | 26 | void removeListeners(); 27 | 28 | void start(); 29 | 30 | void stop(); 31 | } 32 | -------------------------------------------------------------------------------- /lib/common/utils/navigation/location_providers/positioning_location_provider.dart: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2020-2025 HERE Europe B.V. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | * 16 | * SPDX-License-Identifier: Apache-2.0 17 | * License-Filename: LICENSE 18 | */ 19 | 20 | import 'package:here_sdk/core.dart'; 21 | import 'package:here_sdk/location.dart'; 22 | 23 | import '../location_provider_interface.dart'; 24 | 25 | class PositioningLocationProvider extends LocationProviderInterface implements LocationListener { 26 | PositioningLocationProvider() : _locationEngine = LocationEngine(); 27 | 28 | final LocationEngine _locationEngine; 29 | final List _listeners = []; 30 | 31 | @override 32 | void start() { 33 | if (_locationEngine.lastKnownLocation != null) { 34 | onLocationUpdated(_locationEngine.lastKnownLocation!); 35 | } 36 | _locationEngine.setBackgroundLocationAllowed(true); 37 | _locationEngine.setBackgroundLocationIndicatorVisible(true); 38 | _locationEngine.setPauseLocationUpdatesAutomatically(true); 39 | _locationEngine 40 | ..addLocationListener(this) 41 | 42 | /// Important: The HERE Privacy Notice must be shown and accepted by the user 43 | /// before starting the LocationEngine. Ensure the FTU/privacy screen is displayed 44 | /// at app start-up. This method must be called every time before starting the engine. 45 | ..confirmHEREPrivacyNoticeInclusion() 46 | ..startWithLocationAccuracy(LocationAccuracy.bestAvailable); 47 | } 48 | 49 | @override 50 | void stop() { 51 | _locationEngine 52 | ..setBackgroundLocationAllowed(false) 53 | ..setBackgroundLocationIndicatorVisible(false) 54 | ..setPauseLocationUpdatesAutomatically(false) 55 | ..removeLocationListener(this) 56 | ..stop(); 57 | } 58 | 59 | @override 60 | void addListener(LocationListener listener) => _listeners.add(listener); 61 | 62 | @override 63 | void removeListener(LocationListener listener) => _listeners.remove(listener); 64 | 65 | @override 66 | void removeListeners() => _listeners.clear(); 67 | 68 | @override 69 | void onLocationUpdated(Location location) { 70 | for (final LocationListener listener in _listeners) { 71 | listener.onLocationUpdated(location); 72 | } 73 | } 74 | } 75 | -------------------------------------------------------------------------------- /lib/common/utils/navigation/location_providers/simulated_location_provider.dart: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2020-2025 HERE Europe B.V. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | * 16 | * SPDX-License-Identifier: Apache-2.0 17 | * License-Filename: LICENSE 18 | */ 19 | 20 | import 'package:here_sdk/core.dart'; 21 | import 'package:here_sdk/location.dart'; 22 | import 'package:here_sdk/navigation.dart'; 23 | import 'package:here_sdk/routing.dart'; 24 | import 'package:here_sdk_reference_application_flutter/common/extensions/location_listener_extension.dart'; 25 | import 'package:here_sdk_reference_application_flutter/common/utils/navigation/location_provider_interface.dart'; 26 | 27 | class SimulatedLocationProvider extends LocationProviderInterface implements LocationListener { 28 | SimulatedLocationProvider.withRoute(Route route, LocationSimulatorOptions options) { 29 | _simulator = LocationSimulator.withRoute(route, options); 30 | _simulator.listener = this; 31 | } 32 | 33 | late LocationSimulator _simulator; 34 | final List _listeners = []; 35 | LocationEngine? _locationEngine; 36 | 37 | void pause() => _simulator.pause(); 38 | 39 | void resume() => _simulator.resume(); 40 | 41 | @override 42 | void start() { 43 | // Start location engine to allow background mode under iOS 44 | _locationEngine = LocationEngine() 45 | ..setBackgroundLocationAllowed(true) 46 | ..setBackgroundLocationIndicatorVisible(true) 47 | ..setPauseLocationUpdatesAutomatically(true) 48 | 49 | /// Important: The HERE Privacy Notice must be shown and accepted by the user 50 | /// before starting the LocationEngine. Ensure the FTU/privacy screen is displayed 51 | /// at app start-up. This method must be called every time before starting the engine. 52 | ..confirmHEREPrivacyNoticeInclusion() 53 | ..startWithLocationAccuracy(LocationAccuracy.bestAvailable); 54 | _simulator.start(); 55 | } 56 | 57 | @override 58 | void stop() { 59 | _simulator.stop(); 60 | _locationEngine?.setBackgroundLocationAllowed(false); 61 | _locationEngine?.setBackgroundLocationIndicatorVisible(false); 62 | _locationEngine?.setPauseLocationUpdatesAutomatically(false); 63 | } 64 | 65 | @override 66 | void addListener(LocationListener listener) => _listeners.add(listener); 67 | 68 | @override 69 | void removeListener(LocationListener listener) => _listeners.remove(listener); 70 | 71 | @override 72 | void removeListeners() => _listeners.clear(); 73 | 74 | @override 75 | void onLocationUpdated(Location location) => _listeners.notifyOnLocationUpdated(location); 76 | } 77 | -------------------------------------------------------------------------------- /lib/common/utils/navigation/location_utils.dart: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2020-2025 HERE Europe B.V. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | * 16 | * SPDX-License-Identifier: Apache-2.0 17 | * License-Filename: LICENSE 18 | */ 19 | import 'package:here_sdk/navigation.dart'; 20 | import 'package:here_sdk/routing.dart' as here; 21 | import 'package:here_sdk_reference_application_flutter/common/utils/navigation/location_provider_interface.dart'; 22 | import 'package:here_sdk_reference_application_flutter/common/utils/navigation/location_providers/positioning_location_provider.dart'; 23 | import 'package:here_sdk_reference_application_flutter/common/utils/navigation/location_providers/simulated_location_provider.dart'; 24 | 25 | LocationProviderInterface createLocationProvider({ 26 | bool simulated = false, 27 | LocationSimulatorOptions? simulatorOptions, // needed if simulated == true 28 | here.Route? route, 29 | }) { 30 | assert( 31 | simulated == false || simulatorOptions != null, 32 | 'simulatorOptions are needed if simulated == true', 33 | ); 34 | assert( 35 | simulated == false || (simulated && route != null), 36 | 'track or route need to be provided if simulated == true', 37 | ); 38 | 39 | if (simulated && route != null) { 40 | return SimulatedLocationProvider.withRoute(route, simulatorOptions!); 41 | } else { 42 | return PositioningLocationProvider(); 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /lib/common/utils/navigation/position_status_listener.dart: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2020-2025 HERE Europe B.V. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | * 16 | * SPDX-License-Identifier: Apache-2.0 17 | * License-Filename: LICENSE 18 | */ 19 | import 'dart:async'; 20 | 21 | import 'package:geolocator/geolocator.dart'; 22 | import 'package:here_sdk/core.dart'; 23 | 24 | /// This abstract class defines a listener for monitoring device location positioning status changes. 25 | /// Subclasses that implement this class must provide an implementation for the 26 | /// `didDevicePositioningStatusUpdated` method, which will be called when there is a change 27 | /// in the availability of device positioning. 28 | abstract class PositioningStatusListener { 29 | /// Callback method invoked when the device's positioning status is updated. 30 | /// 31 | /// [isPositioningAvailable] - A boolean value indicating whether positioning is available 32 | /// (true if available, false if not available). 33 | void didDevicePositioningStatusUpdated({ 34 | required bool isPositioningAvailable, 35 | required bool hasPermissionsGranted, 36 | }); 37 | } 38 | 39 | class DeviceLocationServicesStatusNotifier { 40 | StreamSubscription? _serviceStatusSteam; 41 | PositioningStatusListener? _listener; 42 | 43 | /// Starts the location services status listener and will notifies about the status change. 44 | void start(PositioningStatusListener listener) { 45 | // Stop the previous status stream, if there is any. 46 | stop(); 47 | _listener = listener; 48 | _serviceStatusSteam = Geolocator.getServiceStatusStream().listen(_serviceListener); 49 | } 50 | 51 | /// Stops the location services status listener and no longer notifies about status change. 52 | Future stop() async { 53 | return _serviceStatusSteam?.cancel(); 54 | } 55 | 56 | Future _hasLocationPermissions() async { 57 | final LocationPermission permission = await Geolocator.checkPermission(); 58 | return permission == LocationPermission.always || permission == LocationPermission.whileInUse; 59 | } 60 | 61 | Future canLocateUserPositioning() async { 62 | return (await _hasLocationPermissions()) && await Geolocator.isLocationServiceEnabled(); 63 | } 64 | 65 | Future _serviceListener(ServiceStatus event) async { 66 | _listener?.didDevicePositioningStatusUpdated( 67 | isPositioningAvailable: event == ServiceStatus.enabled, 68 | hasPermissionsGranted: await _hasLocationPermissions(), 69 | ); 70 | } 71 | 72 | Future onLocationReceived(Location location) async { 73 | if (await canLocateUserPositioning()) { 74 | _listener?.didDevicePositioningStatusUpdated( 75 | isPositioningAvailable: true, 76 | hasPermissionsGranted: await _hasLocationPermissions(), 77 | ); 78 | } 79 | } 80 | } 81 | -------------------------------------------------------------------------------- /lib/download_maps/map_catalog_update_handler.dart: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2020-2025 HERE Europe B.V. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | * 16 | * SPDX-License-Identifier: Apache-2.0 17 | * License-Filename: LICENSE 18 | */ 19 | 20 | import 'package:here_sdk/maploader.dart'; 21 | 22 | abstract class MapCatalogUpdateListener { 23 | void onCatalogUpdateProgress(RegionId region, int percentage); 24 | void onCatalogUpdatePause(MapLoaderError? error); 25 | void onCatalogUpdateComplete(MapLoaderError? error); 26 | void onCatalogUpdateResume(); 27 | } 28 | 29 | class MapCatalogUpdateHandler implements CatalogUpdateProgressListener { 30 | MapCatalogUpdateHandler(this.updater, this.catalog); 31 | 32 | MapUpdater? updater; 33 | final CatalogUpdateInfo catalog; 34 | int progress = 0; 35 | CatalogUpdateTask? _task; 36 | final List _listeners = []; 37 | 38 | void start() { 39 | _task ??= updater?.updateCatalog(catalog, this); 40 | } 41 | 42 | void pause() { 43 | _task?.pause(); 44 | } 45 | 46 | void resume() { 47 | if (_task == null) { 48 | start(); 49 | } else { 50 | _task?.resume(); 51 | } 52 | } 53 | 54 | void cancel() { 55 | _task?.cancel(); 56 | } 57 | 58 | void addListener(MapCatalogUpdateListener listener) { 59 | _listeners.add(listener); 60 | } 61 | 62 | void removeListener(MapCatalogUpdateListener listener) { 63 | _listeners.remove(listener); 64 | } 65 | 66 | @override 67 | void onComplete(MapLoaderError? error) { 68 | print('Catalog update completed (error=${error?.index})'); 69 | progress = error == null ? 100 : 0; 70 | _task = null; 71 | for (final MapCatalogUpdateListener l in _listeners) { 72 | l.onCatalogUpdateComplete(error); 73 | } 74 | } 75 | 76 | @override 77 | void onPause(MapLoaderError? error) { 78 | for (final MapCatalogUpdateListener l in _listeners) { 79 | l.onCatalogUpdatePause(error); 80 | } 81 | } 82 | 83 | @override 84 | void onProgress(RegionId region, int percentage) { 85 | print('Updating catalog (id: ${region.id}) in $percentage %.'); 86 | progress = percentage; 87 | for (final MapCatalogUpdateListener l in _listeners) { 88 | l.onCatalogUpdateProgress(region, percentage); 89 | } 90 | } 91 | 92 | @override 93 | void onResume() { 94 | for (final MapCatalogUpdateListener l in _listeners) { 95 | l.onCatalogUpdateResume(); 96 | } 97 | } 98 | } 99 | -------------------------------------------------------------------------------- /lib/download_maps/map_loader_dialogs.dart: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2020-2025 HERE Europe B.V. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | * 16 | * SPDX-License-Identifier: Apache-2.0 17 | * License-Filename: LICENSE 18 | */ 19 | 20 | import 'package:flutter/cupertino.dart'; 21 | import 'package:flutter/material.dart'; 22 | import 'package:flutter_gen/gen_l10n/app_localizations.dart'; 23 | import 'package:here_sdk/maploader.dart'; 24 | 25 | import '../common/util.dart' as Util; 26 | import 'map_loader_controller.dart'; 27 | 28 | /// Shows confirmation dialog and then cancels download a [Region]. 29 | extension CancelDownloadExtension on MapLoaderController { 30 | void cancelDownloadWithConfirmation(BuildContext context, Region region, [List? childRegions]) async { 31 | this.pauseDownload(region.regionId); 32 | 33 | if (await _askForCancelMapLoading(context, region.name)) { 34 | if (childRegions != null) { 35 | this.cancelDownloads([region.regionId, ...childRegions]); 36 | } else { 37 | this.cancelDownload(region.regionId); 38 | } 39 | } else { 40 | this.resumeDownload(region.regionId); 41 | } 42 | } 43 | } 44 | 45 | /// Creates a confirmation dialog to cancel map loading. 46 | Future _askForCancelMapLoading(BuildContext context, String regionName) async { 47 | AppLocalizations appLocalizations = AppLocalizations.of(context)!; 48 | return Util.showCommonConfirmationDialog( 49 | context: context, 50 | title: Util.formatString(appLocalizations.stopMapDownloadDialogTitle, [regionName]), 51 | actionTitle: appLocalizations.stopMapDownloadButtonTitle, 52 | ); 53 | } 54 | 55 | /// Creates a map updates available dialog. 56 | Future showMapUpdatesAvailableDialog(BuildContext context) async { 57 | AppLocalizations appLocalizations = AppLocalizations.of(context)!; 58 | return Util.showCommonConfirmationDialog( 59 | context: context, 60 | title: appLocalizations.mapUpdateAvailableDialogTitle, 61 | message: appLocalizations.mapUpdateAvailableDialogMessage, 62 | actionTitle: appLocalizations.updateButtonTitle, 63 | ); 64 | } 65 | -------------------------------------------------------------------------------- /lib/download_maps/map_update_progress_widget.dart: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2020-2025 HERE Europe B.V. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | * 16 | * SPDX-License-Identifier: Apache-2.0 17 | * License-Filename: LICENSE 18 | */ 19 | 20 | import 'package:flutter/material.dart'; 21 | import 'package:flutter_gen/gen_l10n/app_localizations.dart'; 22 | import 'package:provider/provider.dart'; 23 | 24 | import 'map_loader_controller.dart'; 25 | import '../common/ui_style.dart'; 26 | 27 | /// A widget that represents the progress of the map update. 28 | class MapUpdateProgress extends StatelessWidget { 29 | MapUpdateProgress({ 30 | Key? key, 31 | }) : super(key: key); 32 | 33 | @override 34 | Widget build(BuildContext context) => Consumer( 35 | builder: (context, controller, child) => Padding( 36 | padding: EdgeInsets.all(UIStyle.contentMarginHuge), 37 | child: Column( 38 | crossAxisAlignment: CrossAxisAlignment.start, 39 | children: [ 40 | Text( 41 | AppLocalizations.of(context)!.updatingMapTitle, 42 | style: TextStyle(fontSize: UIStyle.bigFontSize, fontWeight: FontWeight.bold), 43 | ), 44 | Padding( 45 | padding: EdgeInsets.symmetric( 46 | vertical: UIStyle.contentMarginMedium, 47 | ), 48 | child: LinearProgressIndicator( 49 | value: controller.mapUpdateState != MapUpdateState.cancelling 50 | ? controller.mapUpdateProgress! / 100 51 | : null, 52 | valueColor: AlwaysStoppedAnimation(Theme.of(context).colorScheme.secondary), 53 | backgroundColor: Theme.of(context).dividerColor, 54 | ), 55 | ), 56 | Row( 57 | crossAxisAlignment: CrossAxisAlignment.center, 58 | children: [ 59 | Spacer(), 60 | if (controller.mapUpdateState == MapUpdateState.progress) 61 | _buildButton(context, Icon(Icons.pause), () => controller.pauseMapUpdate()), 62 | if (controller.mapUpdateState == MapUpdateState.paused) 63 | _buildButton(context, Icon(Icons.play_arrow), () => controller.resumeMapUpdate()), 64 | Container( 65 | width: UIStyle.contentMarginMedium, 66 | ), 67 | if (controller.mapUpdateState != MapUpdateState.cancelling) 68 | _buildButton( 69 | context, 70 | Icon( 71 | Icons.cancel, 72 | color: Colors.red, 73 | ), 74 | () => controller.cancelMapUpdate()), 75 | ], 76 | ), 77 | Divider(), 78 | ], 79 | ), 80 | ), 81 | ); 82 | 83 | Widget _buildButton(BuildContext context, Widget icon, VoidCallback onTap) => ClipOval( 84 | child: Material( 85 | child: Ink( 86 | width: UIStyle.smallButtonHeight, 87 | height: UIStyle.smallButtonHeight, 88 | color: Theme.of(context).dividerColor, 89 | child: InkWell( 90 | child: Center( 91 | child: icon, 92 | ), 93 | onTap: onTap, 94 | ), 95 | ), 96 | ), 97 | ); 98 | } 99 | -------------------------------------------------------------------------------- /lib/environment.dart: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2020-2025 HERE Europe B.V. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | * 16 | * SPDX-License-Identifier: Apache-2.0 17 | * License-Filename: LICENSE 18 | */ 19 | 20 | class Environment { 21 | static const String accessKeyId = String.fromEnvironment('HERESDK_ACCESS_KEY_ID'); 22 | static const String accessKeySecret = String.fromEnvironment('HERESDK_ACCESS_KEY_SECRET'); 23 | } 24 | -------------------------------------------------------------------------------- /lib/navigation/current_maneuver_widget.dart: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2020-2025 HERE Europe B.V. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | * 16 | * SPDX-License-Identifier: Apache-2.0 17 | * License-Filename: LICENSE 18 | */ 19 | 20 | import 'package:flutter/material.dart'; 21 | import 'package:flutter_svg/flutter_svg.dart'; 22 | import 'package:here_sdk/routing.dart' as Routing; 23 | import 'package:here_sdk_reference_application_flutter/navigation/maneuver_action_text_helper.dart'; 24 | 25 | import '../common/ui_style.dart'; 26 | import '../common/util.dart' as Util; 27 | 28 | /// A widget that displays the current navigation maneuver. 29 | class CurrentManeuver extends StatelessWidget { 30 | /// The maneuver action. 31 | final Routing.ManeuverAction action; 32 | 33 | /// Distance to the maneuver. 34 | final int distance; 35 | 36 | /// Instruction for the maneuver. 37 | final String text; 38 | 39 | /// Constructs a widget. 40 | CurrentManeuver({ 41 | required this.action, 42 | required this.distance, 43 | required this.text, 44 | }); 45 | 46 | @override 47 | Widget build(BuildContext context) { 48 | ColorScheme colorScheme = Theme.of(context).colorScheme; 49 | 50 | return Row( 51 | children: [ 52 | Padding( 53 | padding: EdgeInsets.all(UIStyle.contentMarginLarge), 54 | child: SvgPicture.asset( 55 | action.iconPath, 56 | width: UIStyle.bigButtonHeight, 57 | height: UIStyle.bigButtonHeight, 58 | ), 59 | ), 60 | Expanded( 61 | child: Column( 62 | mainAxisSize: MainAxisSize.min, 63 | crossAxisAlignment: CrossAxisAlignment.stretch, 64 | children: [ 65 | Text( 66 | Util.makeDistanceString(context, distance), 67 | style: TextStyle( 68 | color: colorScheme.surface, 69 | fontSize: UIStyle.extraHugeFontSize, 70 | ), 71 | ), 72 | Container( 73 | height: UIStyle.contentMarginSmall, 74 | ), 75 | Text( 76 | text, 77 | maxLines: 2, 78 | style: TextStyle( 79 | color: colorScheme.surface, 80 | fontSize: UIStyle.bigFontSize, 81 | ), 82 | overflow: TextOverflow.ellipsis, 83 | ), 84 | ], 85 | ), 86 | ), 87 | ], 88 | ); 89 | } 90 | } 91 | -------------------------------------------------------------------------------- /lib/navigation/navigation_dialogs.dart: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2020-2025 HERE Europe B.V. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | * 16 | * SPDX-License-Identifier: Apache-2.0 17 | * License-Filename: LICENSE 18 | */ 19 | 20 | import 'package:flutter/material.dart'; 21 | import 'package:flutter_gen/gen_l10n/app_localizations.dart'; 22 | import 'package:flutter_svg/flutter_svg.dart'; 23 | 24 | import '../common/ui_style.dart'; 25 | import '../common/util.dart' as Util; 26 | 27 | /// Creates a dialog for selecting a location source for navigation. 28 | /// There are two options available, simulation and device location. 29 | Future askForPositionSource(BuildContext context) async { 30 | AppLocalizations appLocalizations = AppLocalizations.of(context)!; 31 | 32 | return await showDialog( 33 | context: context, 34 | builder: (context) => SimpleDialog( 35 | title: Text(appLocalizations.selectPositioningDialogTitle), 36 | children: [ 37 | SimpleDialogOption( 38 | child: ListTile( 39 | leading: SvgPicture.asset( 40 | "assets/route.svg", 41 | colorFilter: ColorFilter.mode(Theme.of(context).colorScheme.onSecondary, BlendMode.srcIn), 42 | width: UIStyle.mediumIconSize, 43 | height: UIStyle.mediumIconSize, 44 | ), 45 | title: Text(appLocalizations.simulatedLocationSourceTitle), 46 | ), 47 | onPressed: () => Navigator.of(context).pop(true), 48 | ), 49 | SimpleDialogOption( 50 | child: ListTile( 51 | leading: Icon(Icons.gps_fixed), 52 | title: Text(appLocalizations.realLocationSourceTitle), 53 | ), 54 | onPressed: () => Navigator.of(context).pop(false), 55 | ), 56 | ], 57 | ), 58 | ); 59 | } 60 | 61 | /// Creates a confirmation dialog to stop navigation. 62 | Future askForExitFromNavigation(BuildContext context) async { 63 | AppLocalizations appLocalizations = AppLocalizations.of(context)!; 64 | return Util.showCommonConfirmationDialog( 65 | context: context, 66 | title: appLocalizations.stopNavigationDialogTitle, 67 | message: appLocalizations.stopNavigationDialogSubtitle, 68 | actionTitle: appLocalizations.stopNavigationAcceptButtonCaption, 69 | actionTextColor: UIStyle.stopNavigationButtonIconColor, 70 | actionBackgroundColor: UIStyle.stopNavigationButtonColor, 71 | ); 72 | } 73 | -------------------------------------------------------------------------------- /lib/navigation/next_maneuver_widget.dart: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2020-2025 HERE Europe B.V. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | * 16 | * SPDX-License-Identifier: Apache-2.0 17 | * License-Filename: LICENSE 18 | */ 19 | 20 | import 'package:flutter/material.dart'; 21 | import 'package:flutter_svg/flutter_svg.dart'; 22 | import 'package:here_sdk/routing.dart' as Routing; 23 | import 'package:here_sdk_reference_application_flutter/navigation/maneuver_action_text_helper.dart'; 24 | 25 | import '../common/ui_style.dart'; 26 | import '../common/util.dart' as Util; 27 | 28 | /// A widget that displays the upcoming navigation maneuver. 29 | class NextManeuver extends StatelessWidget { 30 | /// Upcoming maneuver action. 31 | final Routing.ManeuverAction action; 32 | 33 | /// Distance to the upcoming maneuver. 34 | final int distance; 35 | 36 | /// Instruction text for the upcoming maneuver. 37 | final String text; 38 | 39 | /// Constructs a widget. 40 | NextManeuver({ 41 | required this.action, 42 | required this.distance, 43 | required this.text, 44 | }); 45 | 46 | @override 47 | Widget build(BuildContext context) { 48 | ColorScheme colorScheme = Theme.of(context).colorScheme; 49 | 50 | return Row( 51 | children: [ 52 | Padding( 53 | padding: EdgeInsets.all(UIStyle.contentMarginLarge), 54 | child: SvgPicture.asset( 55 | action.iconPath, 56 | width: UIStyle.smallButtonHeight, 57 | height: UIStyle.smallButtonHeight, 58 | ), 59 | ), 60 | Text( 61 | Util.makeDistanceString(context, distance), 62 | style: TextStyle( 63 | color: colorScheme.surface, 64 | fontSize: UIStyle.hugeFontSize, 65 | ), 66 | ), 67 | Container( 68 | height: 0, 69 | width: UIStyle.contentMarginMedium, 70 | ), 71 | Expanded( 72 | child: Text( 73 | text, 74 | style: TextStyle( 75 | color: colorScheme.surface, 76 | fontSize: UIStyle.bigFontSize, 77 | ), 78 | ), 79 | ), 80 | ], 81 | ); 82 | } 83 | } 84 | -------------------------------------------------------------------------------- /lib/navigation/rerouting_indicator_widget.dart: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2020-2025 HERE Europe B.V. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | * 16 | * SPDX-License-Identifier: Apache-2.0 17 | * License-Filename: LICENSE 18 | */ 19 | 20 | import 'package:flutter/material.dart'; 21 | import 'package:flutter_gen/gen_l10n/app_localizations.dart'; 22 | 23 | import '../common/ui_style.dart'; 24 | 25 | /// A widget indicating that a rerouting is in progress. 26 | class ReroutingIndicator extends StatelessWidget { 27 | const ReroutingIndicator({super.key, this.title}); 28 | 29 | final String? title; 30 | 31 | @override 32 | Widget build(BuildContext context) { 33 | ColorScheme colorScheme = Theme.of(context).colorScheme; 34 | 35 | return Align( 36 | alignment: Alignment.center, 37 | child: Row( 38 | crossAxisAlignment: CrossAxisAlignment.center, 39 | children: [ 40 | SizedBox(width: UIStyle.contentMarginMedium), 41 | Padding( 42 | padding: EdgeInsets.all(UIStyle.contentMarginLarge), 43 | child: Container( 44 | width: UIStyle.bigButtonHeight, 45 | height: UIStyle.bigButtonHeight, 46 | child: CircularProgressIndicator( 47 | backgroundColor: UIStyle.reroutingProgressBackgroundColor, 48 | valueColor: AlwaysStoppedAnimation(UIStyle.reroutingProgressColor), 49 | ), 50 | ), 51 | ), 52 | Expanded( 53 | child: Text( 54 | title ?? AppLocalizations.of(context)!.reroutingInProgressText, 55 | style: TextStyle( 56 | color: colorScheme.surface, 57 | fontSize: UIStyle.extraHugeFontSize, 58 | ), 59 | ), 60 | ), 61 | ], 62 | ), 63 | ); 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /lib/route_preferences/avoidance/country_avoidance_screen.dart: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2020-2025 HERE Europe B.V. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | * 16 | * SPDX-License-Identifier: Apache-2.0 17 | * License-Filename: LICENSE 18 | */ 19 | 20 | import 'package:flutter/material.dart'; 21 | import 'package:flutter_gen/gen_l10n/app_localizations.dart'; 22 | import 'package:here_sdk/core.dart'; 23 | import 'package:here_sdk/routing.dart'; 24 | import 'package:provider/provider.dart'; 25 | 26 | import '../../common/ui_style.dart'; 27 | import '../enum_string_helper.dart'; 28 | import '../route_preferences_model.dart'; 29 | 30 | /// Country avoidance options screen widget. 31 | class CountryAvoidanceScreen extends StatelessWidget { 32 | @override 33 | Widget build(BuildContext context) { 34 | final AvoidanceOptions avoidanceOptions = 35 | context.select((RoutePreferencesModel model) => model.sharedAvoidanceOptions); 36 | 37 | Map countryCodesMap = EnumStringHelper.countryCodesMap(context); 38 | List sortedCountryNames = countryCodesMap.keys.toList()..sort(); 39 | 40 | return Scaffold( 41 | resizeToAvoidBottomInset: false, 42 | appBar: AppBar( 43 | title: Text(AppLocalizations.of(context)!.avoidCountriesTitle), 44 | ), 45 | body: Container( 46 | color: UIStyle.preferencesBackgroundColor, 47 | child: ListView.builder( 48 | itemCount: sortedCountryNames.length, 49 | itemBuilder: (context, index) { 50 | CountryCode code = countryCodesMap[sortedCountryNames[index]]!; 51 | return CheckboxListTile( 52 | title: Text(sortedCountryNames[index]), 53 | value: avoidanceOptions.countries.contains(code), 54 | onChanged: (bool? enable) { 55 | List updatedCountries = List.from(avoidanceOptions.countries); 56 | if (enable ?? false) { 57 | updatedCountries.add(code); 58 | } else { 59 | updatedCountries.remove(code); 60 | } 61 | 62 | final AvoidanceOptions newOptions = AvoidanceOptions() 63 | ..roadFeatures = avoidanceOptions.roadFeatures 64 | ..countries = updatedCountries 65 | ..avoidBoundingBoxAreasOptions = avoidanceOptions.avoidBoundingBoxAreasOptions 66 | ..zoneCategories = avoidanceOptions.zoneCategories 67 | ..segments = avoidanceOptions.segments; 68 | context.read().sharedAvoidanceOptions = newOptions; 69 | }, 70 | ); 71 | }), 72 | ), 73 | ); 74 | } 75 | } 76 | -------------------------------------------------------------------------------- /lib/route_preferences/avoidance/road_features_avoidance_screen.dart: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2020-2025 HERE Europe B.V. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | * 16 | * SPDX-License-Identifier: Apache-2.0 17 | * License-Filename: LICENSE 18 | */ 19 | 20 | import 'dart:collection'; 21 | 22 | import 'package:flutter/material.dart'; 23 | import 'package:flutter_gen/gen_l10n/app_localizations.dart'; 24 | import 'package:here_sdk/routing.dart'; 25 | import 'package:provider/provider.dart'; 26 | 27 | import '../../common/ui_style.dart'; 28 | import '../enum_string_helper.dart'; 29 | import '../route_preferences_model.dart'; 30 | 31 | /// Road features avoidance options screen widget. 32 | class RoadFeaturesAvoidanceScreen extends StatelessWidget { 33 | @override 34 | Widget build(BuildContext context) { 35 | final AvoidanceOptions avoidanceOptions = 36 | context.select((RoutePreferencesModel model) => model.sharedAvoidanceOptions); 37 | 38 | LinkedHashMap roadFeaturesMap = EnumStringHelper.sortedRoadFeaturesMap(context); 39 | 40 | return Scaffold( 41 | resizeToAvoidBottomInset: false, 42 | appBar: AppBar( 43 | title: Text(AppLocalizations.of(context)!.avoidRoadFeaturesTitle), 44 | ), 45 | body: Container( 46 | color: UIStyle.preferencesBackgroundColor, 47 | child: ListView( 48 | children: roadFeaturesMap.keys.map((String key) { 49 | return CheckboxListTile( 50 | title: Text(key), 51 | value: avoidanceOptions.roadFeatures.contains(roadFeaturesMap[key]), 52 | onChanged: (bool? enable) { 53 | RoadFeatures? changedFeature = roadFeaturesMap[key]; 54 | if (changedFeature == null) { 55 | return; 56 | } 57 | List updatedFeatures = List.from(avoidanceOptions.roadFeatures); 58 | if (enable ?? false) { 59 | updatedFeatures.add(changedFeature); 60 | } else { 61 | updatedFeatures.remove(changedFeature); 62 | } 63 | final AvoidanceOptions newOptions = AvoidanceOptions() 64 | ..roadFeatures = updatedFeatures 65 | ..countries = avoidanceOptions.countries 66 | ..avoidBoundingBoxAreasOptions = avoidanceOptions.avoidBoundingBoxAreasOptions 67 | ..zoneCategories = avoidanceOptions.zoneCategories 68 | ..segments = avoidanceOptions.segments; 69 | context.read().sharedAvoidanceOptions = newOptions; 70 | }, 71 | ); 72 | }).toList(), 73 | ), 74 | ), 75 | ); 76 | } 77 | } 78 | -------------------------------------------------------------------------------- /lib/route_preferences/avoidance/route_avoidance_options_widget.dart: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2020-2025 HERE Europe B.V. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | * 16 | * SPDX-License-Identifier: Apache-2.0 17 | * License-Filename: LICENSE 18 | */ 19 | 20 | import 'package:flutter/material.dart'; 21 | import 'package:flutter_gen/gen_l10n/app_localizations.dart'; 22 | import 'package:here_sdk/routing.dart'; 23 | import 'package:provider/provider.dart'; 24 | 25 | import '../enum_string_helper.dart'; 26 | import '../route_preferences_model.dart'; 27 | import '../preferences_section_title_widget.dart'; 28 | import '../preferences_disclosure_row_widget.dart'; 29 | import 'country_avoidance_screen.dart'; 30 | import 'road_features_avoidance_screen.dart'; 31 | 32 | /// Route avoidance options screen widget. 33 | class RouteAvoidanceOptionsWidget extends StatelessWidget { 34 | @override 35 | Widget build(BuildContext context) { 36 | final AvoidanceOptions avoidanceOptions = 37 | context.select((RoutePreferencesModel model) => model.sharedAvoidanceOptions); 38 | return Column( 39 | mainAxisSize: MainAxisSize.min, 40 | children: [ 41 | PreferencesSectionTitle(title: AppLocalizations.of(context)!.avoidanceOptionsTitle), 42 | PreferencesDisclosureRowWidget( 43 | title: AppLocalizations.of(context)!.avoidRoadFeaturesTitle, 44 | subTitle: EnumStringHelper.roadFeatureNamesToString(context, avoidanceOptions.roadFeatures), 45 | onPressed: () => 46 | Navigator.push(context, MaterialPageRoute(builder: (context) => RoadFeaturesAvoidanceScreen())), 47 | ), 48 | PreferencesDisclosureRowWidget( 49 | title: AppLocalizations.of(context)!.avoidCountriesTitle, 50 | subTitle: EnumStringHelper.countryCodeNamesToString(context, avoidanceOptions.countries), 51 | onPressed: () => Navigator.push(context, MaterialPageRoute(builder: (context) => CountryAvoidanceScreen())), 52 | ), 53 | ], 54 | ); 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /lib/route_preferences/car_options_screen.dart: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2020-2025 HERE Europe B.V. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | * 16 | * SPDX-License-Identifier: Apache-2.0 17 | * License-Filename: LICENSE 18 | */ 19 | 20 | import 'avoidance/route_avoidance_options_widget.dart'; 21 | import 'route_options_widget.dart'; 22 | import 'package:flutter/cupertino.dart'; 23 | import 'route_text_options_widget.dart'; 24 | 25 | /// Routing settings widget for car mode. 26 | class CarOptionsScreen extends StatelessWidget { 27 | @override 28 | Widget build(BuildContext context) => SafeArea( 29 | child: SingleChildScrollView( 30 | child: Column( 31 | mainAxisSize: MainAxisSize.min, 32 | children: [RouteOptionsWidget(), RouteTextOptionsWidget(), RouteAvoidanceOptionsWidget()], 33 | ), 34 | ), 35 | ); 36 | } 37 | -------------------------------------------------------------------------------- /lib/route_preferences/dropdown_widget.dart: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2020-2025 HERE Europe B.V. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | * 16 | * SPDX-License-Identifier: Apache-2.0 17 | * License-Filename: LICENSE 18 | */ 19 | 20 | import 'package:flutter/material.dart'; 21 | 22 | import 'enum_string_helper.dart'; 23 | 24 | /// Dropdown list widget. 25 | class DropdownWidget extends StatelessWidget { 26 | /// Creates a widget. 27 | DropdownWidget({ 28 | Key? key, 29 | required this.data, 30 | this.selectedValue, 31 | required this.onChanged, 32 | }) : super(key: key); 33 | 34 | /// Dropdown list items. 35 | final Map data; 36 | 37 | /// Id of the selected value. 38 | final int? selectedValue; 39 | 40 | /// Called when the selected item is changed. 41 | final ValueChanged onChanged; 42 | 43 | @override 44 | Widget build(BuildContext context) { 45 | return DropdownButton( 46 | isExpanded: true, 47 | value: selectedValue ?? EnumStringHelper.noneValueIndex, 48 | items: data.entries 49 | .map( 50 | (entry) => DropdownMenuItem( 51 | child: ListTile(title: Text(entry.value)), 52 | value: entry.key, 53 | ), 54 | ) 55 | .toList(), 56 | onChanged: (value) { 57 | if (value != null) { 58 | onChanged(value); 59 | } 60 | }, 61 | ); 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /lib/route_preferences/numeric_text_field_widget.dart: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2020-2025 HERE Europe B.V. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | * 16 | * SPDX-License-Identifier: Apache-2.0 17 | * License-Filename: LICENSE 18 | */ 19 | 20 | import 'package:flutter/material.dart'; 21 | 22 | import '../common/ui_style.dart'; 23 | 24 | /// A widget that allows to enter numeric values. 25 | class NumericTextField extends StatelessWidget { 26 | /// Initial value. 27 | final String? initialValue; 28 | 29 | /// Hint text. 30 | final String? hintText; 31 | 32 | /// True if the input value is to be interpreted as an integer, otherwise it is decimal. 33 | final bool isInteger; 34 | 35 | /// Called when the value is changed. 36 | final ValueChanged onChanged; 37 | 38 | /// Constructs a widget. 39 | NumericTextField({ 40 | Key? key, 41 | required this.isInteger, 42 | this.initialValue, 43 | this.hintText, 44 | required this.onChanged, 45 | }) : super(key: key); 46 | 47 | @override 48 | Widget build(BuildContext context) { 49 | return Container( 50 | decoration: UIStyle.roundedRectDecoration(), 51 | child: TextFormField( 52 | initialValue: initialValue ?? "", 53 | keyboardType: isInteger ? TextInputType.number : TextInputType.numberWithOptions(decimal: true), 54 | decoration: InputDecoration( 55 | hintText: hintText ?? "", 56 | border: InputBorder.none, 57 | contentPadding: EdgeInsets.symmetric(horizontal: UIStyle.contentMarginMedium), 58 | ), 59 | onChanged: onChanged, 60 | ), 61 | ); 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /lib/route_preferences/pedestrian_options_screen.dart: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2020-2025 HERE Europe B.V. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | * 16 | * SPDX-License-Identifier: Apache-2.0 17 | * License-Filename: LICENSE 18 | */ 19 | 20 | import 'route_preferences_model.dart'; 21 | import 'preferences_row_title_widget.dart'; 22 | import 'preferences_section_title_widget.dart'; 23 | import 'numeric_text_field_widget.dart'; 24 | import 'route_options_widget.dart'; 25 | import 'package:flutter/cupertino.dart'; 26 | import 'package:here_sdk/routing.dart'; 27 | import 'route_text_options_widget.dart'; 28 | import 'package:flutter_gen/gen_l10n/app_localizations.dart'; 29 | 30 | import 'package:provider/provider.dart'; 31 | 32 | /// Routing settings widget for pedestrian mode. 33 | class PedestrianOptionsScreen extends StatelessWidget { 34 | @override 35 | Widget build(BuildContext context) { 36 | final PedestrianOptions pedestrianOptions = 37 | context.select((RoutePreferencesModel model) => model.pedestrianOptions); 38 | 39 | return SafeArea( 40 | child: SingleChildScrollView( 41 | child: Column( 42 | mainAxisSize: MainAxisSize.min, 43 | children: [ 44 | RouteOptionsWidget(), 45 | RouteTextOptionsWidget(), 46 | PreferencesSectionTitle(title: AppLocalizations.of(context)!.walkSpeedTitle), 47 | PreferencesRowTitle(title: AppLocalizations.of(context)!.walkSpeedUnitTitle), 48 | NumericTextField( 49 | initialValue: pedestrianOptions.walkSpeedInMetersPerSecond.toString(), 50 | isInteger: false, 51 | onChanged: (text) { 52 | final PedestrianOptions newOptions = PedestrianOptions() 53 | ..routeOptions = pedestrianOptions.routeOptions 54 | ..textOptions = pedestrianOptions.textOptions 55 | ..avoidanceOptions = AvoidanceOptions() 56 | ..walkSpeedInMetersPerSecond = double.tryParse(text) ?? 0; 57 | context.read().pedestrianOptions = newOptions; 58 | }, 59 | ), 60 | ], 61 | ), 62 | ), 63 | ); 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /lib/route_preferences/preferences_disclosure_row_widget.dart: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2020-2025 HERE Europe B.V. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | * 16 | * SPDX-License-Identifier: Apache-2.0 17 | * License-Filename: LICENSE 18 | */ 19 | 20 | import 'package:flutter/material.dart'; 21 | 22 | import '../common/ui_style.dart'; 23 | 24 | /// Widget for preference disclosure row. 25 | class PreferencesDisclosureRowWidget extends StatelessWidget { 26 | /// Title 27 | final String title; 28 | 29 | /// Sub-title 30 | final String? subTitle; 31 | 32 | /// Called when the widget is tapped or otherwise activated. 33 | final VoidCallback onPressed; 34 | 35 | /// Constructs a widget. 36 | PreferencesDisclosureRowWidget({ 37 | required this.title, 38 | required this.onPressed, 39 | this.subTitle, 40 | }); 41 | 42 | @override 43 | Widget build(BuildContext context) { 44 | return GestureDetector( 45 | onTap: onPressed, 46 | child: Padding( 47 | padding: const EdgeInsets.only(top: UIStyle.contentMarginExtraLarge), 48 | child: Container( 49 | decoration: UIStyle.bottomDividerDecoration(), 50 | child: Row( 51 | mainAxisAlignment: MainAxisAlignment.spaceBetween, 52 | children: [ 53 | Expanded( 54 | child: Column( 55 | crossAxisAlignment: CrossAxisAlignment.start, 56 | children: [ 57 | Text( 58 | title, 59 | style: TextStyle(color: Theme.of(context).colorScheme.primary, fontSize: UIStyle.bigFontSize), 60 | ), 61 | if (subTitle?.isNotEmpty ?? false) 62 | Text( 63 | subTitle!, 64 | overflow: TextOverflow.ellipsis, 65 | style: TextStyle(color: Theme.of(context).colorScheme.onSecondary), 66 | textAlign: TextAlign.left, 67 | ) 68 | ], 69 | ), 70 | ), 71 | IconButton( 72 | icon: Icon(Icons.keyboard_arrow_right, color: Theme.of(context).colorScheme.onSecondary), 73 | onPressed: onPressed, 74 | ), 75 | ], 76 | ), 77 | ), 78 | ), 79 | ); 80 | } 81 | } 82 | -------------------------------------------------------------------------------- /lib/route_preferences/preferences_row_title_widget.dart: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2020-2025 HERE Europe B.V. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | * 16 | * SPDX-License-Identifier: Apache-2.0 17 | * License-Filename: LICENSE 18 | */ 19 | 20 | import 'package:flutter/cupertino.dart'; 21 | 22 | import '../common/ui_style.dart'; 23 | 24 | /// Widget for preference title row. 25 | class PreferencesRowTitle extends StatelessWidget { 26 | /// Title 27 | final String title; 28 | 29 | /// Constructs a widget. 30 | PreferencesRowTitle({ 31 | required this.title, 32 | }); 33 | 34 | @override 35 | Widget build(BuildContext context) { 36 | return Padding( 37 | padding: const EdgeInsets.only(top: UIStyle.contentMarginExtraLarge, bottom: UIStyle.contentMarginMedium), 38 | child: Row( 39 | children: [Text(title)], 40 | ), 41 | ); 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /lib/route_preferences/preferences_section_title_widget.dart: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2020-2025 HERE Europe B.V. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | * 16 | * SPDX-License-Identifier: Apache-2.0 17 | * License-Filename: LICENSE 18 | */ 19 | 20 | import 'package:flutter/cupertino.dart'; 21 | 22 | import '../common/ui_style.dart'; 23 | 24 | /// Widget for preference section title. 25 | class PreferencesSectionTitle extends StatelessWidget { 26 | /// Title 27 | final String title; 28 | 29 | /// Constructs a widget. 30 | PreferencesSectionTitle({ 31 | required this.title, 32 | }); 33 | 34 | @override 35 | Widget build(BuildContext context) { 36 | return Padding( 37 | padding: const EdgeInsets.only(top: UIStyle.contentMarginExtraHuge), 38 | child: Row(children: [ 39 | Text(title, style: UIStyle.optionsSectionStyle(context)), 40 | ])); 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /lib/route_preferences/route_text_options_widget.dart: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2020-2025 HERE Europe B.V. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | * 16 | * SPDX-License-Identifier: Apache-2.0 17 | * License-Filename: LICENSE 18 | */ 19 | 20 | import 'package:flutter/material.dart'; 21 | import 'package:flutter_gen/gen_l10n/app_localizations.dart'; 22 | import 'package:here_sdk/core.dart'; 23 | import 'package:here_sdk/routing.dart'; 24 | import 'package:provider/provider.dart'; 25 | 26 | import '../common/ui_style.dart'; 27 | import 'dropdown_widget.dart'; 28 | import 'enum_string_helper.dart'; 29 | import 'preferences_row_title_widget.dart'; 30 | import 'preferences_section_title_widget.dart'; 31 | import 'route_preferences_model.dart'; 32 | 33 | /// Route text options widget. 34 | class RouteTextOptionsWidget extends StatelessWidget { 35 | @override 36 | Widget build(BuildContext context) { 37 | final RouteTextOptions textOptions = context.select((RoutePreferencesModel model) => model.sharedRouteTextOptions); 38 | 39 | return Column( 40 | mainAxisSize: MainAxisSize.min, 41 | children: [ 42 | PreferencesSectionTitle(title: AppLocalizations.of(context)!.routeTextOptionsTitle), 43 | PreferencesRowTitle(title: AppLocalizations.of(context)!.unitSystemTitle), 44 | Container( 45 | decoration: UIStyle.roundedRectDecoration(), 46 | child: DropdownButtonHideUnderline( 47 | child: DropdownWidget( 48 | data: EnumStringHelper.routeUnitSystemMap(context), 49 | selectedValue: textOptions.unitSystem.index, 50 | onChanged: (unit) { 51 | final RouteTextOptions newOptions = RouteTextOptions() 52 | ..language = textOptions.language 53 | ..unitSystem = UnitSystem.values[unit]; 54 | context.read().sharedRouteTextOptions = newOptions; 55 | }, 56 | ), 57 | ), 58 | ), 59 | PreferencesRowTitle(title: AppLocalizations.of(context)!.languageCodeTitle), 60 | Container( 61 | decoration: UIStyle.roundedRectDecoration(), 62 | child: DropdownButtonHideUnderline( 63 | child: DropdownWidget( 64 | data: EnumStringHelper.routeLanguageMap(context), 65 | selectedValue: textOptions.language.index, 66 | onChanged: (language) { 67 | final RouteTextOptions newOptions = RouteTextOptions() 68 | ..language = LanguageCode.values[language] 69 | ..unitSystem = textOptions.unitSystem; 70 | context.read().sharedRouteTextOptions = newOptions; 71 | }, 72 | ), 73 | ), 74 | ), 75 | ], 76 | ); 77 | } 78 | } 79 | -------------------------------------------------------------------------------- /lib/route_preferences/scooter_options_screen.dart: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2020-2025 HERE Europe B.V. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | * 16 | * SPDX-License-Identifier: Apache-2.0 17 | * License-Filename: LICENSE 18 | */ 19 | 20 | import 'package:flutter/material.dart'; 21 | import 'package:flutter_gen/gen_l10n/app_localizations.dart'; 22 | import 'package:here_sdk/routing.dart'; 23 | import 'package:provider/provider.dart'; 24 | 25 | import 'avoidance/route_avoidance_options_widget.dart'; 26 | import 'preferences_row_title_widget.dart'; 27 | import 'preferences_section_title_widget.dart'; 28 | import 'route_options_widget.dart'; 29 | import 'route_preferences_model.dart'; 30 | import 'route_text_options_widget.dart'; 31 | 32 | /// Routing settings widget for scooter mode. 33 | class ScooterOptionsScreen extends StatelessWidget { 34 | @override 35 | Widget build(BuildContext context) { 36 | final ScooterOptions scooterOptions = context.select((RoutePreferencesModel model) => model.scooterOptions); 37 | 38 | return SafeArea( 39 | child: SingleChildScrollView( 40 | child: Column( 41 | mainAxisSize: MainAxisSize.min, 42 | children: [ 43 | RouteOptionsWidget(), 44 | RouteTextOptionsWidget(), 45 | RouteAvoidanceOptionsWidget(), 46 | PreferencesSectionTitle(title: AppLocalizations.of(context)!.highwayTitle), 47 | Row( 48 | mainAxisAlignment: MainAxisAlignment.spaceBetween, 49 | children: [ 50 | PreferencesRowTitle(title: AppLocalizations.of(context)!.allowHighwayTitle), 51 | Switch.adaptive( 52 | value: scooterOptions.allowHighway, 53 | onChanged: (value) { 54 | final ScooterOptions newOptions = ScooterOptions() 55 | ..routeOptions = scooterOptions.routeOptions 56 | ..textOptions = scooterOptions.textOptions 57 | ..avoidanceOptions = scooterOptions.avoidanceOptions 58 | ..allowHighway = value; 59 | context.read().scooterOptions = newOptions; 60 | }, 61 | ), 62 | ], 63 | ) 64 | ], 65 | ), 66 | ), 67 | ); 68 | } 69 | } 70 | -------------------------------------------------------------------------------- /lib/route_preferences/transport_modes_widget.dart: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2020-2025 HERE Europe B.V. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | * 16 | * SPDX-License-Identifier: Apache-2.0 17 | * License-Filename: LICENSE 18 | */ 19 | 20 | import 'package:flutter/material.dart'; 21 | import 'package:flutter_svg/flutter_svg.dart'; 22 | 23 | import '../common/ui_style.dart'; 24 | 25 | /// Available transport modes currently supported by the Ref App. 26 | /// The HERE SDK supports more transport modes than featured by this application. 27 | enum TransportModes { 28 | car, 29 | truck, 30 | scooter, 31 | walk, 32 | } 33 | 34 | /// Widget for switching between transport modes. 35 | class TransportModesWidget extends StatelessWidget { 36 | /// This widget's selection and animation state. 37 | final TabController tabController; 38 | 39 | /// List of transport modes to be shown. 40 | final List transportModes; 41 | 42 | /// Constructs a widget. 43 | TransportModesWidget({ 44 | Key? key, 45 | required this.tabController, 46 | this.transportModes = TransportModes.values, 47 | }) : super(key: key); 48 | 49 | @override 50 | Widget build(BuildContext context) => 51 | TabBar(controller: tabController, tabs: _buildTransportTabs(context, tabController.index)); 52 | 53 | List _buildTransportTabs(BuildContext context, int selectedIndex) { 54 | return List.generate( 55 | transportModes.length, 56 | (index) => _buildTransportTab(context, index, selectedIndex == index), 57 | ); 58 | } 59 | 60 | Widget _buildTransportTab(BuildContext context, int index, bool isSelected) { 61 | ColorScheme colorScheme = Theme.of(context).colorScheme; 62 | Color color = isSelected ? colorScheme.primary : colorScheme.onSecondary; 63 | 64 | return Tab( 65 | icon: SvgPicture.asset( 66 | transportModes[index].icon, 67 | colorFilter: ColorFilter.mode(color, BlendMode.srcIn), 68 | width: UIStyle.bigIconSize, 69 | height: UIStyle.bigIconSize, 70 | ), 71 | ); 72 | } 73 | } 74 | 75 | extension _TransportModeIcon on TransportModes { 76 | String get icon { 77 | switch (this) { 78 | case TransportModes.car: 79 | return "assets/car.svg"; 80 | case TransportModes.truck: 81 | return "assets/truck.svg"; 82 | case TransportModes.scooter: 83 | return "assets/scooter.svg"; 84 | case TransportModes.walk: 85 | return "assets/walk.svg"; 86 | } 87 | } 88 | } 89 | -------------------------------------------------------------------------------- /lib/route_preferences/truck_hazardous_materials_screen.dart: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2020-2025 HERE Europe B.V. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | * 16 | * SPDX-License-Identifier: Apache-2.0 17 | * License-Filename: LICENSE 18 | */ 19 | 20 | import 'dart:collection'; 21 | 22 | import 'package:flutter/material.dart'; 23 | import 'package:here_sdk/routing.dart'; 24 | import 'package:here_sdk/transport.dart' as Transport; 25 | import 'package:provider/provider.dart'; 26 | import 'package:flutter_gen/gen_l10n/app_localizations.dart'; 27 | 28 | import '../common/ui_style.dart'; 29 | import 'enum_string_helper.dart'; 30 | import 'route_preferences_model.dart'; 31 | 32 | /// Truck hazardous goods preferences screen widget. 33 | class TruckHazardousMaterialsScreen extends StatelessWidget { 34 | @override 35 | Widget build(BuildContext context) { 36 | final TruckOptions truckOptions = context.select((RoutePreferencesModel model) => model.truckOptions); 37 | LinkedHashMap hazardousMaterialsMap = 38 | EnumStringHelper.sortedHazardousMaterialsMap(context); 39 | 40 | return Scaffold( 41 | resizeToAvoidBottomInset: false, 42 | appBar: AppBar( 43 | title: Text(AppLocalizations.of(context)!.hazardousGoodsTitle), 44 | ), 45 | body: Container( 46 | color: UIStyle.preferencesBackgroundColor, 47 | child: ListView( 48 | children: hazardousMaterialsMap.keys.map((String key) { 49 | return CheckboxListTile( 50 | title: Text(key), 51 | value: truckOptions.hazardousMaterials.contains(hazardousMaterialsMap[key]), 52 | onChanged: (bool? enable) { 53 | Transport.HazardousMaterial changedFeature = hazardousMaterialsMap[key]!; 54 | List updatedFeatures = List.from(truckOptions.hazardousMaterials); 55 | if (enable ?? false) { 56 | updatedFeatures.add(changedFeature); 57 | } else { 58 | updatedFeatures.remove(changedFeature); 59 | } 60 | 61 | final TruckOptions newTruckOptions = TruckOptions() 62 | ..routeOptions = truckOptions.routeOptions 63 | ..textOptions = truckOptions.textOptions 64 | ..avoidanceOptions = truckOptions.avoidanceOptions 65 | ..truckSpecifications = truckOptions.truckSpecifications 66 | ..linkTunnelCategory = truckOptions.linkTunnelCategory 67 | ..hazardousMaterials = updatedFeatures; 68 | context.read().truckOptions = newTruckOptions; 69 | }, 70 | ); 71 | }).toList(), 72 | ), 73 | ), 74 | ); 75 | } 76 | } 77 | -------------------------------------------------------------------------------- /lib/routing/route_poi_options_item.dart: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2020-2025 HERE Europe B.V. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | * 16 | * SPDX-License-Identifier: Apache-2.0 17 | * License-Filename: LICENSE 18 | */ 19 | 20 | import 'package:flutter/material.dart'; 21 | 22 | /// A widget that displays a toggle button. 23 | class RoutePoiOptionsItem extends StatefulWidget { 24 | /// Checkbox value. 25 | final bool value; 26 | 27 | /// Title of the button. 28 | final Widget title; 29 | 30 | /// Called when the value is changed. 31 | final ValueChanged onChanged; 32 | 33 | /// Constructs a widget. 34 | RoutePoiOptionsItem({ 35 | this.value = false, 36 | required this.title, 37 | required this.onChanged, 38 | }); 39 | 40 | @override 41 | _RoutePoiOptionsItemState createState() => _RoutePoiOptionsItemState(); 42 | } 43 | 44 | class _RoutePoiOptionsItemState extends State { 45 | late bool _value; 46 | 47 | @override 48 | void initState() { 49 | _value = widget.value; 50 | super.initState(); 51 | } 52 | 53 | @override 54 | Widget build(BuildContext context) { 55 | return SwitchListTile( 56 | value: _value, 57 | title: widget.title, 58 | onChanged: (value) { 59 | setState(() => _value = value); 60 | widget.onChanged(value); 61 | }, 62 | ); 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /lib/routing/waypoint_info.dart: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2020-2025 HERE Europe B.V. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | * 16 | * SPDX-License-Identifier: Apache-2.0 17 | * License-Filename: LICENSE 18 | */ 19 | 20 | import 'package:here_sdk/core.dart'; 21 | import 'package:here_sdk/routing.dart' as Routing; 22 | import 'package:here_sdk/search.dart'; 23 | 24 | import '../common/util.dart' as Util; 25 | 26 | /// Source type for a waypoint. 27 | enum WayPointInfoSourceType { 28 | /// Current position. 29 | CurrentPosition, 30 | 31 | /// Arbitrary coordinates. 32 | Coordinates, 33 | 34 | /// A [Place]. 35 | Place, 36 | } 37 | 38 | /// Helper class that contains additional information about waypoint. 39 | class WayPointInfo extends Routing.Waypoint { 40 | /// Place of the waypoint. 41 | final Place? place; 42 | 43 | /// Source type. 44 | final WayPointInfoSourceType sourceType; 45 | 46 | String get title => place?.title ?? coordinates.toPrettyString(); 47 | 48 | WayPointInfo({ 49 | required GeoCoordinates coordinates, 50 | }) : place = null, 51 | sourceType = WayPointInfoSourceType.CurrentPosition, 52 | super.withDefaults(coordinates); 53 | 54 | WayPointInfo.withCoordinates({ 55 | required GeoCoordinates coordinates, 56 | }) : place = null, 57 | sourceType = WayPointInfoSourceType.Coordinates, 58 | super.withDefaults(coordinates); 59 | 60 | WayPointInfo.withPlace({ 61 | required this.place, 62 | GeoCoordinates? originalCoordinates = null, 63 | }) : sourceType = WayPointInfoSourceType.Place, 64 | super.withDefaults(originalCoordinates ?? place!.geoCoordinates!); 65 | } 66 | -------------------------------------------------------------------------------- /plugins/README.md: -------------------------------------------------------------------------------- 1 | Place the here_sdk plugin folder here! 2 | 3 | How to get the plugin folder: 4 | 5 | 1. Download the HERE SDK package for the _Navigate Edition_ from the [HERE platform](https://platform.here.com/sdk) portal. 6 | 2. Inside, you'll find zipped documentation assets and a zipped file named "heresdk-navigate-flutter-{version}.tar.gz". 7 | 3. Unzip this *.tar.gz file as it's containing the HERE SDK plugin. 8 | 4. Rename the unzipped folder to "here_sdk" and move the entire folder including its content to here. 9 | -------------------------------------------------------------------------------- /update_submodules.bat: -------------------------------------------------------------------------------- 1 | :: 2 | :: Copyright (C) 2025 HERE Europe B.V. 3 | :: 4 | :: Licensed under the Apache License, Version 2.0 (the "License"); 5 | :: you may not use this file except in compliance with the License. 6 | :: You may obtain a copy of the License at 7 | 8 | :: http://www.apache.org/licenses/LICENSE-2.0 9 | :: 10 | :: Unless required by applicable law or agreed to in writing, software 11 | :: distributed under the License is distributed on an "AS IS" BASIS, 12 | :: WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | :: See the License for the specific language governing permissions and 14 | :: limitations under the License. 15 | :: 16 | :: SPDX-License-Identifier: Apache-2.0 17 | :: License-Filename: LICENSE 18 | :: 19 | 20 | @echo off 21 | setlocal 22 | 23 | :: ---------------------------------------------------------------------------- 24 | :: Script to initialize, update, and checkout a specific submodule to a fixed commit 25 | :: This script is for projects where submodule content is not modified directly. 26 | :: ---------------------------------------------------------------------------- 27 | 28 | :: Define the submodule path and desired commit ID to sync to 29 | set "SUBMODULE_PATH=assets/here-icons" 30 | set "HERE_ICON_LIBRARY_COMMIT_ID=f17e4cb733c1cafb5dfd9e5298a007af390f8153" 31 | 32 | :: Step 1: Initialize and update the submodule recursively 33 | echo Initializing and updating submodules... 34 | git submodule update --init --recursive 35 | 36 | :: Check if the submodule update was successful 37 | if errorlevel 1 ( 38 | echo Failed to initialize and update submodules. 39 | exit /b 1 40 | ) 41 | 42 | :: Step 2: Checkout the submodule to a fixed commit ID 43 | :: This is useful when you want to pin the submodule to a specific version 44 | echo Checking out submodule "%SUBMODULE_PATH%" to commit %HERE_ICON_LIBRARY_COMMIT_ID%... 45 | pushd "%SUBMODULE_PATH%" 46 | git checkout %HERE_ICON_LIBRARY_COMMIT_ID% --force 47 | if errorlevel 1 ( 48 | echo Failed to checkout commit %HERE_ICON_LIBRARY_COMMIT_ID% in submodule "%SUBMODULE_PATH%". 49 | popd 50 | exit /b 1 51 | ) 52 | popd 53 | 54 | echo Submodule synced to commit %HERE_ICON_LIBRARY_COMMIT_ID% successfully. 55 | endlocal 56 | exit /b 0 57 | -------------------------------------------------------------------------------- /update_submodules.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # 3 | # Copyright (C) 2025 HERE Europe B.V. 4 | # 5 | # Licensed under the Apache License, Version 2.0 (the "License"); 6 | # you may not use this file except in compliance with the License. 7 | # You may obtain a copy of the License at 8 | # 9 | # http://www.apache.org/licenses/LICENSE-2.0 10 | # 11 | # Unless required by applicable law or agreed to in writing, software 12 | # distributed under the License is distributed on an "AS IS" BASIS, 13 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | # See the License for the specific language governing permissions and 15 | # limitations under the License. 16 | # 17 | # SPDX-License-Identifier: Apache-2.0 18 | # License-Filename: LICENSE 19 | # 20 | 21 | set -e 22 | 23 | HERE_ICON_LIBRARY_COMMIT_ID="f17e4cb733c1cafb5dfd9e5298a007af390f8153" 24 | 25 | # Initialize and update submodules 26 | echo "Initializing and updating submodules..." 27 | git submodule update --init --recursive 28 | git submodule foreach --recursive "git checkout $HERE_ICON_LIBRARY_COMMIT_ID --force" 29 | 30 | # Check if the submodule update was successful 31 | if [ $? -ne 0 ]; then 32 | echo "Failed to update submodules." 33 | exit 1 34 | fi 35 | 36 | echo "Submodules updated successfully." --------------------------------------------------------------------------------