Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
34 commits
Select commit Hold shift + click to select a range
9320678
Create offline toolkit module & microapp (#835)
shubham7109 May 1, 2025
7aa9ea4
Changes to initialize preplanned map area (#843)
puneet-pdx May 8, 2025
c476ab6
Enhance preplanned area list (#846)
puneet-pdx May 14, 2025
0676f2a
Add Workmanager to OfflineMapAreas (#844)
shubham7109 May 14, 2025
ec5f2b4
Wire workmanager with UI (#849)
shubham7109 May 15, 2025
e602563
Add backing properties (#850)
puneet-pdx May 15, 2025
b5b3718
Add WorkManagerRepository (#851)
puneet-pdx May 20, 2025
8c549d4
OfflineMapAreas: Doc rework (#852)
shubham7109 May 20, 2025
484a530
Add fix so that we always run the workManagerRepository funs in viewM…
puneet-pdx May 28, 2025
a28fca6
Update feature branch with latest v.next changes (#864)
shubham7109 May 28, 2025
12467b1
Add additional functionality (#859)
puneet-pdx May 29, 2025
80f1a0b
Switch between online and offline map (#865)
puneet-pdx May 29, 2025
afee028
Notification cancel fix (#866)
shubham7109 May 31, 2025
eacad89
Offline map info (#870)
shubham7109 Jun 9, 2025
c38e027
OfflineMapInfo patch changes & cleanup (#876)
shubham7109 Jun 11, 2025
2eb03d2
Add MapAreaDetails screen (#875)
puneet-pdx Jun 11, 2025
19cce5f
Changes to make OfflineRepository Singleton, to support single instan…
puneet-pdx Jun 13, 2025
730d88c
Remove usage of ExperimentalMaterial3Api and copy ModalBottomSheet (#…
puneet-pdx Jun 18, 2025
650ba13
Support map areas various fail reasons and errors (#885)
shubham7109 Jun 18, 2025
e28a493
Enhance OfflineMapAreas microapp (#893)
shubham7109 Jun 18, 2025
e831ca4
Add sheetGesturesEnabled (#894)
puneet-pdx Jun 18, 2025
db2b8f0
Init on demand map areas selector screen (#895)
shubham7109 Jun 20, 2025
0f35c3a
Init OnDemand map areas screen (#900)
puneet-pdx Jun 24, 2025
3a3b41b
Level of detail (#902)
shubham7109 Jun 24, 2025
21ff99d
Add functionality to OnDemand (#904)
shubham7109 Jun 30, 2025
3fde16a
Support in-progress download restoration (#907)
shubham7109 Jul 2, 2025
d6f2411
Offline Map Areas: Cleanup changes. (#913)
shubham7109 Jul 8, 2025
41ed570
Add bug fix (#924)
shubham7109 Jul 8, 2025
3931081
update check to determine if the device is offline (#925)
puneet-pdx Jul 8, 2025
405601c
Offline API ref documentation (#929)
shubham7109 Jul 9, 2025
f332467
Update feature branch using v.next (#933)
shubham7109 Jul 10, 2025
2956616
Revert "Update feature branch using v.next (#933)" (#938)
shubham7109 Jul 10, 2025
79195cf
Merge branch 'v.next' into feature-branches/offline-map-areas
shubham7109 Jul 10, 2025
053b898
Resolve merge by removing duplicate singleVariant
shubham7109 Jul 10, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ The ArcGIS Maps SDK for Kotlin Toolkit contains components that will simplify yo
* **[Callout](toolkit/geoview-compose#display-a-callout)** - Draws a callout on the GeoView to display Composable content.
* **[OverviewMap](toolkit/geoview-compose#display-an-overviewmap)** - a small, secondary Map View which shows a representation of the main view's current viewpoint.
* **[Legend](toolkit/legend)** - Displays a legend for a map or a scene.
* **[OfflineMapAreas](toolkit/offline)** - Allows you to take a web map offline by downloading map areas.
* **[Popup](toolkit/popup)** - View field values of features in a layer using the Popup API.
* **[Scalebar](toolkit/scalebar)** - Displays current scale reference.
* **[UtilityNetworkTrace](toolkit/utilitynetworks)** - Configure, run, and visualize UtilityNetworkTraces on a composable MapView.
Expand Down Expand Up @@ -56,6 +57,7 @@ implementation("com.esri:arcgis-maps-kotlin-toolkit-compass")
implementation("com.esri:arcgis-maps-kotlin-toolkit-featureforms")
implementation("com.esri:arcgis-maps-kotlin-toolkit-geoview-compose")
implementation("com.esri:arcgis-maps-kotlin-toolkit-legend")
implementation("com.esri:arcgis-maps-kotlin-toolkit-offline")
implementation("com.esri:arcgis-maps-kotlin-toolkit-indoors")
implementation("com.esri:arcgis-maps-kotlin-toolkit-popup")
implementation("com.esri:arcgis-maps-kotlin-toolkit-scalebar")
Expand Down
2 changes: 2 additions & 0 deletions gradle/libs.versions.toml
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ androidxTestExt = "1.2.1"
androidXTestRunner = "1.6.2"
androidXTestRules = "1.6.1"
androidxWindow = "1.3.0"
workVersion = "2.10.0"
binaryCompatibilityValidator = "0.17.0"
compileSdk = "36"
compose-navigation = "2.8.9"
Expand Down Expand Up @@ -73,6 +74,7 @@ androidx-test-rules = { group = "androidx.test", name = "rules", version.ref = "
androidx-uiautomator = { module = "androidx.test.uiautomator:uiautomator", version.ref = "uiautomator" }
androidx-window = { group = "androidx.window", name = "window", version.ref = "androidxWindow" }
androidx-window-core = { group = "androidx.window", name = "window-core", version.ref = "androidxWindow" }
androidx-work-runtime-ktx = { group = "androidx.work", name = "work-runtime-ktx", version.ref = "workVersion" }
mlkit-barcode-scanning = { module = "com.google.mlkit:barcode-scanning", version.ref = "mlkitBarcodeScanning" }
coil-bom = { group = "io.coil-kt", name = "coil-bom", version.ref = "coilBOM" }
coil = { group = "io.coil-kt", name = "coil" }
Expand Down
15 changes: 15 additions & 0 deletions microapps/OfflineMapAreasApp/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
*.iml
.gradle
/local.properties
/.idea/caches
/.idea/libraries
/.idea/modules.xml
/.idea/workspace.xml
/.idea/navEditor.xml
/.idea/assetWizardSettings.xml
.DS_Store
/build
/captures
.externalNativeBuild
.cxx
local.properties
9 changes: 9 additions & 0 deletions microapps/OfflineMapAreasApp/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
# OfflineMapAreas Micro-app

This micro-app demonstrates the use of the `OfflineMapAreas` toolkit component to take a web map offline by downloading map areas.

## Usage

ToDo…

For more information on the `OfflineMapAreas` component and how it works, see its [Readme](../../toolkit/offline).
1 change: 1 addition & 0 deletions microapps/OfflineMapAreasApp/app/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
/build
94 changes: 94 additions & 0 deletions microapps/OfflineMapAreasApp/app/build.gradle.kts
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
/*
*
* Copyright 2025 Esri
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/

plugins {
id("com.android.application")
id("org.jetbrains.kotlin.android")
id("org.jetbrains.kotlin.plugin.compose")
id("com.google.android.libraries.mapsplatform.secrets-gradle-plugin")
}

secrets {
// this file doesn't contain secrets, it just provides defaults which can be committed into git.
defaultPropertiesFileName = "secrets.defaults.properties"
}

android {
namespace = "com.arcgismaps.toolkit.offlinemapareasapp"
compileSdk = libs.versions.compileSdk.get().toInt()

defaultConfig {
applicationId ="com.arcgismaps.toolkit.offlinemapareasapp"
minSdk = libs.versions.minSdk.get().toInt()
targetSdk = libs.versions.compileSdk.get().toInt()
versionCode = 1
versionName = "1.0"

testInstrumentationRunner ="androidx.test.runner.AndroidJUnitRunner"
vectorDrawables {
useSupportLibrary = true
}
}

buildTypes {
release {
isMinifyEnabled = false
}
}
compileOptions {
sourceCompatibility = JavaVersion.VERSION_1_8
targetCompatibility = JavaVersion.VERSION_1_8
}
kotlinOptions {
jvmTarget = "1.8"
}

buildFeatures {
compose = true
buildConfig = true
}

packaging {
resources {
excludes += "/META-INF/{AL2.0,LGPL2.1}"
}
}

// Avoids an empty test report showing up in the CI integration test report.
// Remove this if tests will be added.
tasks.withType<Test> {
enabled = false
}
}

dependencies {
implementation(project(":geoview-compose"))
implementation(arcgis.mapsSdk)
implementation(project(":offline"))
implementation(project(":microapps-lib"))
implementation(platform(libs.androidx.compose.bom))
implementation(libs.bundles.composeCore)
implementation(libs.bundles.core)
implementation(libs.androidx.lifecycle.runtime.ktx)
implementation(libs.androidx.activity.compose)
implementation(libs.androidx.lifecycle.viewmodel.compose)
testImplementation(libs.bundles.unitTest)
androidTestImplementation(platform(libs.androidx.compose.bom))
androidTestImplementation(libs.bundles.composeTest)
debugImplementation(libs.bundles.debug)
}
21 changes: 21 additions & 0 deletions microapps/OfflineMapAreasApp/app/proguard-rules.pro
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
# Add project specific ProGuard rules here.
# You can control the set of applied configuration files using the
# proguardFiles setting in build.gradle.
#
# For more details, see
# http://developer.android.com/guide/developing/tools/proguard.html

# If your project uses WebView with JS, uncomment the following
# and specify the fully qualified class name to the JavaScript interface
# class:
#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
# public *;
#}

# Uncomment this to preserve the line number information for
# debugging stack traces.
#-keepattributes SourceFile,LineNumberTable

# If you keep the line number information, uncomment this to
# hide the original source file name.
#-renamesourcefileattribute SourceFile
49 changes: 49 additions & 0 deletions microapps/OfflineMapAreasApp/app/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
~
~ Copyright 2025 Esri
~
~ Licensed under the Apache License, Version 2.0 (the "License");
~ you may not use this file except in compliance with the License.
~ You may obtain a copy of the License at
~
~ http://www.apache.org/licenses/LICENSE-2.0
~
~ Unless required by applicable law or agreed to in writing, software
~ distributed under the License is distributed on an "AS IS" BASIS,
~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
~ See the License for the specific language governing permissions and
~ limitations under the License.
~
-->

<manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools">

<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.POST_NOTIFICATIONS" />
<uses-permission android:name="android.permission.FOREGROUND_SERVICE_DATA_SYNC" />

<application
android:allowBackup="true"
android:dataExtractionRules="@xml/data_extraction_rules"
android:fullBackupContent="@xml/backup_rules"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/Theme.OfflineMapAreasApp"
tools:targetApi="31">
<activity
android:name=".MainActivity"
android:exported="true"
android:theme="@style/Theme.OfflineMapAreasApp">
<intent-filter>
<action android:name="android.intent.action.MAIN" />

<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>

</manifest>
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
/*
*
* Copyright 2025 Esri
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/

package com.arcgismaps.toolkit.offlinemapareasapp

import android.Manifest.permission.POST_NOTIFICATIONS
import android.content.pm.PackageManager
import android.os.Build
import android.os.Bundle
import android.util.Log
import androidx.activity.ComponentActivity
import androidx.activity.compose.rememberLauncherForActivityResult
import androidx.activity.compose.setContent
import androidx.activity.result.contract.ActivityResultContracts.RequestPermission
import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue
import androidx.compose.ui.platform.LocalContext
import androidx.core.content.ContextCompat
import com.arcgismaps.ApiKey
import com.arcgismaps.ArcGISEnvironment
import com.arcgismaps.toolkit.offlinemapareasapp.screens.MainScreen
import com.esri.microappslib.theme.MicroAppTheme

class MainActivity : ComponentActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
ArcGISEnvironment.apiKey = ApiKey.create(BuildConfig.API_KEY)
setContent {
MicroAppTheme {
OfflineMapAreasApp()
RequestNotificationPermission(
onResult = { isGranted ->
if (!isGranted) {
Log.e("OfflineMapAreas", "Notification permission request was denied.")
}
})
}
}
}
}

@Composable
fun OfflineMapAreasApp() {
MainScreen()
}

@Composable
private fun RequestNotificationPermission(
onResult: (granted: Boolean) -> Unit
) {
// Explicit notification permissions not required for versions < 33
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.TIRAMISU) {
return onResult(true)
}

// Use the context to check for permissions
val context = LocalContext.current

// Track current permission state
var hasPermission by remember {
mutableStateOf(
value = ContextCompat.checkSelfPermission(/* context = */ context,/* permission = */
POST_NOTIFICATIONS
) == PackageManager.PERMISSION_GRANTED
)
}

// If permission is already granted
if (hasPermission) {
return onResult(true)
}

// Launcher for the permission dialog
val launcher = rememberLauncherForActivityResult(RequestPermission()) { granted ->
hasPermission = granted
onResult(granted)
}

// If permissions is not already granted, show dialog to grant request
LaunchedEffect(hasPermission) {
if (!hasPermission) {
launcher.launch(POST_NOTIFICATIONS)
}
}
}
Loading