From 23c6d2402ea2722fff0e07cb7302ee6305401904 Mon Sep 17 00:00:00 2001 From: James Rich <2199651+jamesarich@users.noreply.github.com> Date: Sun, 28 Jun 2026 09:24:44 -0500 Subject: [PATCH] refactor(ui): migrate MapView dialog to Compose M3 + drop legacy material dependency (#5988) Co-authored-by: Claude Opus 4.8 --- androidApp/build.gradle.kts | 3 +- .../kotlin/org/meshtastic/app/map/MapView.kt | 87 +++++++++++-------- androidApp/src/main/res/values/styles.xml | 2 +- gradle/libs.versions.toml | 2 - 4 files changed, 53 insertions(+), 41 deletions(-) diff --git a/androidApp/build.gradle.kts b/androidApp/build.gradle.kts index 2827586ad..35eefc88f 100644 --- a/androidApp/build.gradle.kts +++ b/androidApp/build.gradle.kts @@ -235,7 +235,7 @@ dependencies { implementation(libs.jetbrains.compose.material3.adaptive) implementation(libs.jetbrains.compose.material3.adaptive.layout) implementation(libs.jetbrains.compose.material3.adaptive.navigation) - implementation(libs.material) + implementation(libs.androidx.appcompat) implementation(libs.compose.multiplatform.animation) implementation(libs.compose.multiplatform.material3) implementation(libs.compose.multiplatform.ui.tooling.preview) @@ -283,7 +283,6 @@ dependencies { googleImplementation(libs.dd.sdk.android.logs) googleImplementation(libs.dd.sdk.android.rum) googleImplementation(libs.dd.sdk.android.session.replay) - googleImplementation(libs.dd.sdk.android.session.replay.material) googleImplementation(libs.dd.sdk.android.timber) googleImplementation(libs.dd.sdk.android.trace) googleImplementation(libs.dd.sdk.android.trace.otel) diff --git a/androidApp/src/fdroid/kotlin/org/meshtastic/app/map/MapView.kt b/androidApp/src/fdroid/kotlin/org/meshtastic/app/map/MapView.kt index dba44146b..97a037072 100644 --- a/androidApp/src/fdroid/kotlin/org/meshtastic/app/map/MapView.kt +++ b/androidApp/src/fdroid/kotlin/org/meshtastic/app/map/MapView.kt @@ -67,7 +67,6 @@ import androidx.compose.ui.unit.dp import androidx.compose.ui.viewinterop.AndroidView import androidx.lifecycle.compose.collectAsStateWithLifecycle import co.touchlab.kermit.Logger -import com.google.android.material.dialog.MaterialAlertDialogBuilder import kotlinx.coroutines.launch import org.jetbrains.compose.resources.StringResource import org.jetbrains.compose.resources.stringResource @@ -229,6 +228,7 @@ fun MapView( var showDownloadButton: Boolean by remember { mutableStateOf(false) } var showEditWaypointDialog by remember { mutableStateOf(null) } + var showDeleteWaypointDialog by remember { mutableStateOf(null) } var showCacheManagerDialog by remember { mutableStateOf(false) } var showCurrentCacheInfo by remember { mutableStateOf(false) } var showPurgeTileSourceDialog by remember { mutableStateOf(false) } @@ -393,39 +393,6 @@ fun MapView( } } - fun showDeleteMarkerDialog(waypoint: Waypoint) { - val builder = MaterialAlertDialogBuilder(context) - builder.setTitle(getString(Res.string.waypoint_delete)) - builder.setNeutralButton(getString(Res.string.cancel)) { _, _ -> - Logger.d { "User canceled marker delete dialog" } - } - builder.setNegativeButton(getString(Res.string.delete_for_me)) { _, _ -> - Logger.d { "User deleted waypoint ${waypoint.id} for me" } - mapViewModel.deleteWaypoint(waypoint.id) - } - if (waypoint.locked_to in setOf(0, mapViewModel.myNodeNum ?: 0) && isConnected) { - builder.setPositiveButton(getString(Res.string.delete_for_everyone)) { _, _ -> - Logger.d { "User deleted waypoint ${waypoint.id} for everyone" } - mapViewModel.sendWaypoint(waypoint.copy(expire = 1)) - mapViewModel.deleteWaypoint(waypoint.id) - } - } - val dialog = builder.show() - for ( - button in - setOf( - androidx.appcompat.app.AlertDialog.BUTTON_NEUTRAL, - androidx.appcompat.app.AlertDialog.BUTTON_NEGATIVE, - androidx.appcompat.app.AlertDialog.BUTTON_POSITIVE, - ) - ) { - with(dialog.getButton(button)) { - textSize = 12F - isAllCaps = false - } - } - } - fun showMarkerLongPressDialog(id: Int) { performHapticFeedback() Logger.d { "marker long pressed id=$id" } @@ -434,7 +401,7 @@ fun MapView( if (waypoint.locked_to in setOf(0, mapViewModel.myNodeNum ?: 0) && isConnected) { showEditWaypointDialog = waypoint } else { - showDeleteMarkerDialog(waypoint) + showDeleteWaypointDialog = waypoint } } @@ -718,7 +685,7 @@ fun MapView( onDeleteClicked = { waypoint -> Logger.d { "User clicked delete waypoint ${waypoint.id}" } showEditWaypointDialog = null - showDeleteMarkerDialog(waypoint) + showDeleteWaypointDialog = waypoint }, onDismissRequest = { Logger.d { "User clicked cancel marker edit dialog" } @@ -726,6 +693,54 @@ fun MapView( }, ) } + + if (showDeleteWaypointDialog != null) { + val waypoint = showDeleteWaypointDialog ?: return + val canDeleteForEveryone = waypoint.locked_to in setOf(0, mapViewModel.myNodeNum ?: 0) && isConnected + androidx.compose.material3.AlertDialog( + onDismissRequest = { + Logger.d { "User canceled marker delete dialog" } + showDeleteWaypointDialog = null + }, + title = { Text(stringResource(Res.string.waypoint_delete)) }, + // Both deletes are confirmations; Cancel is the dismiss action (mirrors the old neutral button). + confirmButton = { + Column { + TextButton( + onClick = { + Logger.d { "User deleted waypoint ${waypoint.id} for me" } + mapViewModel.deleteWaypoint(waypoint.id) + showDeleteWaypointDialog = null + }, + ) { + Text(stringResource(Res.string.delete_for_me)) + } + if (canDeleteForEveryone) { + TextButton( + onClick = { + Logger.d { "User deleted waypoint ${waypoint.id} for everyone" } + mapViewModel.sendWaypoint(waypoint.copy(expire = 1)) + mapViewModel.deleteWaypoint(waypoint.id) + showDeleteWaypointDialog = null + }, + ) { + Text(stringResource(Res.string.delete_for_everyone)) + } + } + } + }, + dismissButton = { + TextButton( + onClick = { + Logger.d { "User canceled marker delete dialog" } + showDeleteWaypointDialog = null + }, + ) { + Text(stringResource(Res.string.cancel)) + } + }, + ) + } } /** F-Droid main map filter dropdown — favorites, waypoints, precision circle, and last-heard time filter slider. */ diff --git a/androidApp/src/main/res/values/styles.xml b/androidApp/src/main/res/values/styles.xml index 9cc1fbb34..36fcb9693 100644 --- a/androidApp/src/main/res/values/styles.xml +++ b/androidApp/src/main/res/values/styles.xml @@ -24,7 +24,7 @@ @drawable/ic_splash - @style/Theme.Material3.DynamicColors.DayNight.NoActionBar + @style/Theme.AppCompat.DayNight.NoActionBar diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 4f44e4017..f9d3ac8e5 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -256,7 +256,6 @@ coil-svg = { module = "io.coil-kt.coil3:coil-svg", version.ref = "coil" } dd-sdk-android-logs = { module = "com.datadoghq:dd-sdk-android-logs", version.ref = "dd-sdk-android" } dd-sdk-android-rum = { module = "com.datadoghq:dd-sdk-android-rum", version.ref = "dd-sdk-android" } dd-sdk-android-session-replay = { module = "com.datadoghq:dd-sdk-android-session-replay", version.ref = "dd-sdk-android" } -dd-sdk-android-session-replay-material = { module = "com.datadoghq:dd-sdk-android-session-replay-material", version.ref = "dd-sdk-android" } dd-sdk-android-timber = { module = "com.datadoghq:dd-sdk-android-timber", version.ref = "dd-sdk-android" } dd-sdk-android-trace = { module = "com.datadoghq:dd-sdk-android-trace", version.ref = "dd-sdk-android" } dd-sdk-android-trace-otel = { module = "com.datadoghq:dd-sdk-android-trace-otel", version.ref = "dd-sdk-android" } @@ -264,7 +263,6 @@ dokka-android-documentation-plugin = { module = "org.jetbrains.dokka:android-doc markdown-renderer = { module = "com.mikepenz:multiplatform-markdown-renderer", version.ref = "markdownRenderer" } markdown-renderer-m3 = { module = "com.mikepenz:multiplatform-markdown-renderer-m3", version.ref = "markdownRenderer" } markdown-renderer-android = { module = "com.mikepenz:multiplatform-markdown-renderer-android", version.ref = "markdownRenderer" } -material = { module = "com.google.android.material:material", version = "1.14.0" } kable-core = { module = "com.juul.kable:kable-core", version.ref = "kable" } # mqtt-client 0.4.0 split the monolith into a BOM + core + per-transport modules. The BOM pins the