Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
11 changes: 8 additions & 3 deletions gradle/libs.versions.toml
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,11 @@ androidGradlePlugin = "8.12.2"
androidXBrowser = "1.9.0"
coil3 = "3.3.0"
coilBOM = "2.7.0"
composeBOM = "2025.08.01"
composeBOM = "2025.11.00"
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

newer version of this is available 2025.12.00

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There are some issues with the 2025.12.00 bom. Specifically this which is also going to be a toolkit wide change.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ah Ok 👍🏽

androidxCamera = "1.4.2"
androidxCore = "1.17.0"
androidxEspresso = "3.7.0"
androidxHiltNavigationCompose = "1.2.0"
androidxMaterialIcons = "1.7.8"
androidxTestExt = "1.3.0"
androidXTestRunner = "1.7.0"
androidXTestRules = "1.7.0"
Expand Down Expand Up @@ -63,7 +62,8 @@ androidx-datastore-preferences = { module = "androidx.datastore:datastore-prefer
androidx-hilt-navigation-compose = { group = "androidx.hilt", name = "hilt-navigation-compose", version.ref = "androidxHiltNavigationCompose" }
androidx-lifecycle-viewmodel-compose = { group = "androidx.lifecycle", name = "lifecycle-viewmodel-compose"}
androidx-lifecycle-runtime-compose = { group = "androidx.lifecycle", name = "lifecycle-runtime-compose"}
androidx-material-icons = { group = "androidx.compose.material", name = "material-icons-extended", version.ref = "androidxMaterialIcons"}
androidx-material-icons-core = { group = "androidx.compose.material", name = "material-icons-core" }
androidx-material-icons-extended = { group = "androidx.compose.material", name = "material-icons-extended" }
androidx-media3-exoplayer = { module = "androidx.media3:media3-exoplayer", version.ref = "media3Exoplayer" }
androidx-media3-ui = { module = "androidx.media3:media3-ui", version.ref = "media3Exoplayer" }
androidx-media3-exoplayer-dash = { module = "androidx.media3:media3-exoplayer-dash", version.ref = "media3Exoplayer" }
Expand Down Expand Up @@ -146,6 +146,11 @@ debug = [
"androidx-compose-ui-test-manifest"
]

icons = [
"androidx-material-icons-core",
"androidx-material-icons-extended"
]

unitTest = [
"junit",
"kotlinx-coroutines-test",
Expand Down
1 change: 1 addition & 0 deletions microapps/ArFlyoverApp/app/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,7 @@ dependencies {
implementation(project(":ar"))
implementation(libs.arcore)
implementation(arcgis.mapsSdk)
implementation(libs.androidx.material.icons.core)
implementation(platform(libs.androidx.compose.bom))
implementation(libs.bundles.composeCore)
implementation(libs.bundles.core)
Expand Down
1 change: 1 addition & 0 deletions microapps/ArWorldScaleApp/app/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,7 @@ dependencies {
implementation(project(":ar"))
implementation(libs.arcore)
implementation(arcgis.mapsSdk)
implementation(libs.androidx.material.icons.core)
implementation(platform(libs.androidx.compose.bom))
implementation(libs.bundles.composeCore)
implementation(libs.bundles.core)
Expand Down
1 change: 1 addition & 0 deletions microapps/CalloutApp/app/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,7 @@ dependencies {
implementation(platform(libs.androidx.compose.bom))
implementation(libs.bundles.composeCore)
implementation(libs.bundles.core)
implementation(libs.androidx.material.icons.core)
implementation(libs.androidx.activity.compose)
implementation(libs.androidx.lifecycle.viewmodel.compose)
implementation(libs.androidx.compose.navigation)
Expand Down
1 change: 1 addition & 0 deletions microapps/FeatureFormsApp/app/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,7 @@ dependencies {
implementation(libs.coil3.compose)
// compose
implementation(platform(libs.androidx.compose.bom))
implementation(libs.androidx.material.icons.core)
implementation(libs.bundles.composeCore)
implementation(libs.bundles.core)
implementation(libs.androidx.activity.compose)
Expand Down
1 change: 1 addition & 0 deletions microapps/MapViewGeometryEditorApp/app/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,7 @@ dependencies {
implementation(project(":geoview-compose"))
implementation(project(":microapps-lib"))
implementation(arcgis.mapsSdk)
implementation(libs.androidx.material.icons.core)
implementation(platform(libs.androidx.compose.bom))
implementation(libs.bundles.composeCore)
implementation(libs.bundles.core)
Expand Down
1 change: 1 addition & 0 deletions microapps/MapViewLocationDisplayApp/app/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,7 @@ dependencies {
implementation(project(":geoview-compose"))
implementation(project(":microapps-lib"))
implementation(arcgis.mapsSdk)
implementation(libs.androidx.material.icons.core)
implementation(platform(libs.androidx.compose.bom))
implementation(libs.bundles.composeCore)
implementation(libs.bundles.core)
Expand Down
1 change: 1 addition & 0 deletions microapps/MapViewSetViewpointApp/app/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,7 @@ dependencies {
implementation(project(":geoview-compose"))
implementation(project(":microapps-lib"))
implementation(arcgis.mapsSdk)
implementation(libs.androidx.material.icons.core)
implementation(platform(libs.androidx.compose.bom))
implementation(libs.bundles.composeCore)
implementation(libs.bundles.core)
Expand Down
1 change: 1 addition & 0 deletions microapps/OfflineMapAreasApp/app/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,7 @@ dependencies {
implementation(project(":offline"))
implementation(project(":microapps-lib"))
implementation(platform(libs.androidx.compose.bom))
implementation(libs.androidx.material.icons.core)
implementation(libs.bundles.composeCore)
implementation(libs.bundles.core)
implementation(libs.androidx.activity.compose)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,7 @@ dependencies {
implementation(project(":microapps-lib"))
implementation(arcgis.mapsSdk)
implementation(platform(libs.androidx.compose.bom))
implementation(libs.androidx.material.icons.core)
implementation(libs.bundles.composeCore)
implementation(libs.bundles.core)
implementation(libs.androidx.activity.compose)
Expand Down
1 change: 1 addition & 0 deletions microapps/SceneViewLightingOptionsApp/app/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,7 @@ dependencies {
implementation(project(":microapps-lib"))
implementation(arcgis.mapsSdk)
implementation(platform(libs.androidx.compose.bom))
implementation(libs.androidx.material.icons.core)
implementation(libs.bundles.composeCore)
implementation(libs.bundles.core)
implementation(libs.androidx.activity.compose)
Expand Down
1 change: 1 addition & 0 deletions microapps/SceneViewSetViewpointApp/app/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,7 @@ dependencies {
implementation(platform(libs.androidx.compose.bom))
implementation(libs.bundles.composeCore)
implementation(libs.bundles.core)
implementation(libs.androidx.material.icons.core)
implementation(libs.androidx.activity.compose)
implementation(libs.androidx.lifecycle.viewmodel.compose)
testImplementation(platform(libs.androidx.compose.bom))
Expand Down
1 change: 1 addition & 0 deletions microapps/UtilityNetworkTraceApp/app/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,7 @@ dependencies {
implementation(project(":utilitynetworks"))
implementation(arcgis.mapsSdk)
implementation(platform(libs.androidx.compose.bom))
implementation(libs.androidx.material.icons.core)
implementation(libs.bundles.composeCore)
implementation(libs.bundles.core)
implementation(libs.androidx.activity.compose)
Expand Down
1 change: 1 addition & 0 deletions toolkit/ar/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,7 @@ dependencies {
implementation(project(":geoview-compose"))
implementation(libs.arcore)
api(arcgis.mapsSdk)
implementation(libs.androidx.material.icons.core)
implementation(platform(libs.androidx.compose.bom))
implementation(libs.bundles.composeCore)
implementation(libs.bundles.core)
Expand Down
2 changes: 1 addition & 1 deletion toolkit/authentication/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -105,10 +105,10 @@ dependencies {
implementation(platform(libs.androidx.compose.bom))
implementation(libs.bundles.composeCore)
implementation(libs.bundles.core)
implementation(libs.bundles.icons)
implementation(libs.androidx.lifecycle.runtime.compose)
implementation(libs.androidx.activity.compose)
implementation(libs.androidx.browser)
implementation(libs.androidx.material.icons)
testImplementation(libs.bundles.unitTest)
androidTestImplementation(libs.bundles.composeTest)
debugImplementation(libs.bundles.debug)
Expand Down
2 changes: 1 addition & 1 deletion toolkit/featureforms/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -183,7 +183,7 @@ dependencies {
implementation(libs.androidx.compose.ui.util)
implementation(libs.bundles.core)
implementation(libs.androidx.activity.compose)
implementation(libs.androidx.material.icons)
implementation(libs.bundles.icons)
implementation(libs.bundles.camerax)
implementation(libs.mlkit.barcode.scanning)
implementation(libs.androidx.compose.navigation)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -546,7 +546,7 @@ internal fun createFieldState(
required = element.isRequired,
visible = element.isVisible,
minEpochMillis = input.min,
maxEpochMillis = input.min,
maxEpochMillis = input.max,
shouldShowTime = input.includeTime,
fieldType = element.fieldType
),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,12 +35,17 @@ import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.rounded.AccessTime
import androidx.compose.material.icons.rounded.CalendarMonth
import androidx.compose.material3.AlertDialog
import androidx.compose.material3.DatePicker
import androidx.compose.material3.DatePickerDefaults
import androidx.compose.material3.DatePickerState
import androidx.compose.material3.DisplayMode
import androidx.compose.material3.Icon
import androidx.compose.material3.IconButton
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Surface
import androidx.compose.material3.Text
import androidx.compose.material3.TextButton
import androidx.compose.material3.rememberDatePickerState
import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.runtime.key
Expand All @@ -62,10 +67,6 @@ import androidx.compose.ui.window.Dialog
import androidx.compose.ui.window.DialogProperties
import com.arcgismaps.toolkit.featureforms.R
import com.arcgismaps.toolkit.featureforms.internal.components.base.ValidationErrorState
import com.arcgismaps.toolkit.featureforms.internal.components.datetime.picker.date.DatePicker
import com.arcgismaps.toolkit.featureforms.internal.components.datetime.picker.date.DatePickerDefaults
import com.arcgismaps.toolkit.featureforms.internal.components.datetime.picker.date.DatePickerState
import com.arcgismaps.toolkit.featureforms.internal.components.datetime.picker.date.DisplayMode
import com.arcgismaps.toolkit.featureforms.internal.components.datetime.picker.time.TimePicker
import com.arcgismaps.toolkit.featureforms.internal.components.datetime.picker.time.TimePickerState
import java.time.Instant
Expand Down Expand Up @@ -114,6 +115,7 @@ private fun calcYearRangeStart(min: Long?, selectedDateTime: Long?): Int {

return year ?: DatePickerDefaults.YearRange.first
}

private fun calcYearRangeEnd(max: Long?, selectedDateTime: Long?): Int {
val year = if (max != null && selectedDateTime != null) {
if (max > selectedDateTime) {
Expand All @@ -129,6 +131,7 @@ private fun calcYearRangeEnd(max: Long?, selectedDateTime: Long?): Int {

return year ?: DatePickerDefaults.YearRange.last
}

/**
* A material3 date and time picker presented as an [AlertDialog].
*
Expand Down Expand Up @@ -157,23 +160,24 @@ internal fun DateTimePicker(
// calculate the date ranges from the state
val datePickerRange = IntRange(
start = calcYearRangeStart(state.minDateTime?.toEpochMilli(), state.selectedDateTimeMillis),
endInclusive = calcYearRangeEnd(state.maxDateTime?.toEpochMilli(), state.selectedDateTimeMillis)
endInclusive = calcYearRangeEnd(
state.maxDateTime?.toEpochMilli(),
state.selectedDateTimeMillis
)
)
// The picker input type, date or time.
val pickerInput by state.activePickerInput
// DateTime from the state's value
val dateTime by state.dateTime
// create and remember a DatePickerState

val datePickerState = rememberSaveable(dateTime, saver = DatePickerState.Saver()) {
DatePickerState(
initialSelectedDateMillis = dateTime.dateForPicker,
initialDisplayedMonthMillis = dateTime.dateForPicker
?: (state.minDateTime?.toEpochMilli() ?: state.maxDateTime?.toEpochMilli()),
datePickerRange,
DisplayMode.Picker
)
}
val datePickerState = rememberDatePickerState(
initialSelectedDateMillis = dateTime.dateForPicker,
initialDisplayedMonthMillis = dateTime.dateForPicker
?: (state.minDateTime?.toEpochMilli() ?: state.maxDateTime?.toEpochMilli()),
yearRange = datePickerRange,
initialDisplayMode = DisplayMode.Picker,
selectableDates = state
)
// create a DateTimePickerDialog
DateTimePickerDialog(
onDismissRequest = onDismissRequest
Expand Down Expand Up @@ -260,10 +264,18 @@ private fun (ColumnScope).PickerContent(
key(state.dateTime.value) {
DatePicker(
state = datePickerState,
dateValidator = { timeStamp ->
state.dateValidator(timeStamp)
title = {
title(
if (style == DateTimePickerStyle.Date) {
null
} else {
Icons.Rounded.AccessTime
}
)
},
title = { title(if (style == DateTimePickerStyle.Date) null else Icons.Rounded.AccessTime) }
colors = DatePickerDefaults.colors(
containerColor = MaterialTheme.colorScheme.surface
)
)
}
}
Expand Down Expand Up @@ -331,7 +343,7 @@ private fun PickerFooter(
// only enable Today button if today is within the range if provided
// the date validator assumes the Long is from the picker,
// i.e. offset from UTC.
enabled = state.dateValidator(
enabled = state.isSelectableDate(
UtcDateTime.create(Instant.now().toEpochMilli()).dateForPicker!!
),
modifier = Modifier.semantics { contentDescription = "current date or time button" }
Expand All @@ -344,7 +356,9 @@ private fun PickerFooter(
}
}
Spacer(modifier = Modifier.weight(1f))
TextButton(onClick = onCancelled, modifier = Modifier.semantics { contentDescription = "cancel" }) {
TextButton(
onClick = onCancelled,
modifier = Modifier.semantics { contentDescription = "cancel" }) {
Text(stringResource(R.string.cancel))
}
TextButton(onClick = onConfirmed, enabled = confirmEnabled) {
Expand Down Expand Up @@ -403,7 +417,7 @@ private object DateTimePickerDialogTokens {
* [Modifier.widthIn] is used. This is useful when different layouts are needed in portrait
* and landscape orientations.
*/
internal fun Modifier.widthWithOrientation(width: Dp) : Modifier = composed {
internal fun Modifier.widthWithOrientation(width: Dp): Modifier = composed {
val configuration = LocalConfiguration.current
if (configuration.orientation == Configuration.ORIENTATION_LANDSCAPE) {
this.widthIn(width)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@

package com.arcgismaps.toolkit.featureforms.internal.components.datetime.picker

import androidx.compose.material3.SelectableDates
import androidx.compose.runtime.Composable
import androidx.compose.runtime.State
import androidx.compose.runtime.mutableStateOf
Expand All @@ -26,6 +27,7 @@ import androidx.compose.runtime.saveable.listSaver
import androidx.compose.runtime.saveable.rememberSaveable
import com.arcgismaps.toolkit.featureforms.internal.components.base.ValidationErrorState
import com.arcgismaps.toolkit.featureforms.internal.components.datetime.formattedDateTime
import com.arcgismaps.toolkit.featureforms.internal.components.datetime.picker.UtcDateTime.Companion.createFromPickerValues
import com.arcgismaps.toolkit.featureforms.internal.components.datetime.toDateMillis
import com.arcgismaps.toolkit.featureforms.internal.components.datetime.toDateTimeInUtcZone
import com.arcgismaps.toolkit.featureforms.internal.components.datetime.toZonedDateTime
Expand Down Expand Up @@ -119,7 +121,7 @@ internal class UtcDateTime private constructor(
/**
* State for [DateTimePicker]. Use factory [DateTimePicker()] to create an instance.
*/
internal interface DateTimePickerState {
internal interface DateTimePickerState : SelectableDates {

/**
* Minimum date time allowed. This should be null if no range restriction is needed.
Expand Down Expand Up @@ -200,13 +202,6 @@ internal interface DateTimePickerState {
* is returned. Both the [minDateTime] and [maxDateTime] are included in the range.
*/
fun dateTimeValidator(timeStamp: Long): Boolean

/**
* Validates if the UTC date of the [timeStamp] is between the dates of the given datetime ranges [minDateTime]
* and [maxDateTime] if they were provided. Returns true if the validation was successful, otherwise false
* is returned. Both the [minDateTime] and [maxDateTime] are included in the range.
*/
fun dateValidator(timeStamp: Long): Boolean

/**
* Sets the [dateTime]'s time value to the current time instant in local time.
Expand Down Expand Up @@ -273,24 +268,6 @@ private class DateTimePickerStateImpl(
utcDateTime <= it
} ?: true
}

override fun dateValidator(timeStamp: Long): Boolean {
// the date validator is invoked by the date picker,
// which operates in milliseconds that are offset from UTC
// To compare it to min and max, the input must be converted
// to UTC.
val utcDate = UtcDateTime.create(timeStamp.minus(timeStamp.defaultTimeZoneOffset)).date!!
val minDate = UtcDateTime.create(minDateTime?.toEpochMilli()).date
val maxDate = UtcDateTime.create(maxDateTime?.toEpochMilli()).date

return minDate?.let { min ->
maxDate?.let { max ->
utcDate in min..max
} ?: (utcDate >= min)
} ?: maxDate?.let {
utcDate <= it
} ?: true
}

override fun now() {
val now = Instant.now().toEpochMilli().toZonedDateTime()
Expand All @@ -309,6 +286,33 @@ private class DateTimePickerStateImpl(
minute
)
}

override fun isSelectableDate(utcTimeMillis: Long): Boolean {
// The isSelectableDate is invoked by the date picker with the specific date in utc millis
// To compare it to min and max, they must be converted to utc millis as well.
val minDate = UtcDateTime.create(minDateTime?.toEpochMilli()).date
val maxDate = UtcDateTime.create(maxDateTime?.toEpochMilli()).date

return when {
minDate != null && maxDate != null -> {
utcTimeMillis in minDate..maxDate
}

minDate != null -> {
utcTimeMillis >= minDate
}

maxDate != null -> {
utcTimeMillis <= maxDate
}

else -> true
}
}

override fun isSelectableYear(year: Int): Boolean {
return true
}
}

/**
Expand Down
Loading