refactor: leverage new dependency features from recent updates (#5057)

This commit is contained in:
James Rich 2026-04-10 17:51:08 -05:00 committed by GitHub
parent 929e273978
commit 9c8532f80d
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
18 changed files with 47 additions and 57 deletions

View file

@ -21,8 +21,6 @@ package org.meshtastic.app.map
import android.Manifest
import android.app.Activity
import android.content.Intent
import android.graphics.Canvas
import android.graphics.Paint
import android.net.Uri
import android.view.WindowManager
import androidx.activity.compose.rememberLauncherForActivityResult
@ -56,7 +54,6 @@ import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.unit.dp
import androidx.core.graphics.createBitmap
import androidx.lifecycle.compose.collectAsStateWithLifecycle
import co.touchlab.kermit.Logger
import com.google.accompanist.permissions.ExperimentalPermissionsApi
@ -67,8 +64,6 @@ import com.google.android.gms.location.LocationResult
import com.google.android.gms.location.LocationServices
import com.google.android.gms.location.Priority
import com.google.android.gms.maps.CameraUpdateFactory
import com.google.android.gms.maps.model.BitmapDescriptor
import com.google.android.gms.maps.model.BitmapDescriptorFactory
import com.google.android.gms.maps.model.CameraPosition
import com.google.android.gms.maps.model.JointType
import com.google.android.gms.maps.model.LatLng
@ -798,7 +793,6 @@ private fun MainMapContent(
mapFilterState = mapFilterState,
myNodeNum = myNodeNum ?: 0,
isConnected = isConnected,
unicodeEmojiToBitmapProvider = ::unicodeEmojiToBitmap,
onEditWaypointRequest = onEditWaypointRequest,
selectedWaypointId = selectedWaypointId,
)
@ -1068,23 +1062,6 @@ internal fun convertIntToEmoji(unicodeCodePoint: Int): String = try {
"\uD83D\uDCCD"
}
internal fun unicodeEmojiToBitmap(icon: Int): BitmapDescriptor {
val unicodeEmoji = convertIntToEmoji(icon)
val paint =
Paint(Paint.ANTI_ALIAS_FLAG).apply {
textSize = 64f
color = android.graphics.Color.BLACK
textAlign = Paint.Align.CENTER
}
val baseline = -paint.ascent()
val width = (paint.measureText(unicodeEmoji) + 0.5f).toInt()
val height = (baseline + paint.descent() + 0.5f).toInt()
val image = createBitmap(width, height, android.graphics.Bitmap.Config.ARGB_8888)
val canvas = Canvas(image)
canvas.drawText(unicodeEmoji, width / 2f, baseline, paint)
return BitmapDescriptorFactory.fromBitmap(image)
}
@Suppress("NestedBlockDepth")
fun Uri.getFileName(context: android.content.Context): String {
var name = this.lastPathSegment ?: "layer_$nowMillis"

View file

@ -16,15 +16,22 @@
*/
package org.meshtastic.app.map.component
import androidx.compose.foundation.layout.padding
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.rememberCoroutineScope
import androidx.compose.ui.Modifier
import androidx.compose.ui.platform.LocalContext
import com.google.android.gms.maps.model.BitmapDescriptor
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
import com.google.android.gms.maps.model.LatLng
import com.google.maps.android.compose.MapsComposeExperimentalApi
import com.google.maps.android.compose.Marker
import com.google.maps.android.compose.rememberComposeBitmapDescriptor
import com.google.maps.android.compose.rememberUpdatedMarkerState
import kotlinx.coroutines.launch
import org.meshtastic.app.map.convertIntToEmoji
import org.meshtastic.core.model.util.GeoConstants.DEG_D
import org.meshtastic.core.resources.Res
import org.meshtastic.core.resources.locked
@ -32,13 +39,13 @@ import org.meshtastic.core.ui.util.showToast
import org.meshtastic.feature.map.BaseMapViewModel
import org.meshtastic.proto.Waypoint
@OptIn(MapsComposeExperimentalApi::class)
@Composable
fun WaypointMarkers(
displayableWaypoints: List<Waypoint>,
mapFilterState: BaseMapViewModel.MapFilterState,
myNodeNum: Int,
isConnected: Boolean,
unicodeEmojiToBitmapProvider: (Int) -> BitmapDescriptor,
onEditWaypointRequest: (Waypoint) -> Unit,
selectedWaypointId: Int? = null,
) {
@ -57,14 +64,16 @@ fun WaypointMarkers(
}
}
val iconCodePoint = if ((waypoint.icon ?: 0) == 0) PUSHPIN else waypoint.icon!!
val emojiText = convertIntToEmoji(iconCodePoint)
val icon =
rememberComposeBitmapDescriptor(iconCodePoint) {
Text(text = emojiText, fontSize = 32.sp, modifier = Modifier.padding(2.dp))
}
Marker(
state = markerState,
icon =
if ((waypoint.icon ?: 0) == 0) {
unicodeEmojiToBitmapProvider(PUSHPIN) // Default icon (Round Pushpin)
} else {
unicodeEmojiToBitmapProvider(waypoint.icon!!)
},
icon = icon,
title = (waypoint.name ?: "").replace('\n', ' ').replace('\b', ' '),
snippet = (waypoint.description ?: "").replace('\n', ' ').replace('\b', ' '),
visible = true,

View file

@ -16,7 +16,7 @@
*/
package org.meshtastic.app.ui
import androidx.compose.ui.test.junit4.createComposeRule
import androidx.compose.ui.test.junit4.v2.createComposeRule
import androidx.navigation3.runtime.NavKey
import androidx.navigation3.runtime.entryProvider
import androidx.navigation3.runtime.rememberNavBackStack

View file

@ -16,7 +16,7 @@
*/
package org.meshtastic.core.barcode
import androidx.compose.ui.test.junit4.createComposeRule
import androidx.compose.ui.test.junit4.v2.createComposeRule
import org.junit.Rule
import org.junit.Test
import org.junit.runner.RunWith

View file

@ -41,8 +41,6 @@ kotlin {
}
androidMain.dependencies { api(libs.androidx.core.ktx) }
val androidHostTest by getting { dependencies { implementation(libs.robolectric) } }
commonTest.dependencies { implementation(libs.kotlinx.coroutines.test) }
}
}

View file

@ -18,6 +18,7 @@ package org.meshtastic.core.database
import androidx.room3.TypeConverter
import co.touchlab.kermit.Logger
import kotlinx.serialization.ExperimentalSerializationApi
import kotlinx.serialization.json.Json
import okio.ByteString
import okio.ByteString.Companion.toByteString
@ -33,10 +34,12 @@ import org.meshtastic.proto.User
@Suppress("TooManyFunctions")
class Converters {
@OptIn(ExperimentalSerializationApi::class)
private val json = Json {
isLenient = true
ignoreUnknownKeys = true
encodeDefaults = true
exceptionsWithDebugInfo = false
}
@TypeConverter fun dataFromString(value: String): DataPacket = json.decodeFromString(DataPacket.serializer(), value)

View file

@ -63,9 +63,6 @@ kotlin {
commonTest.dependencies {
implementation(projects.core.testing)
implementation(libs.kotlinx.coroutines.test)
implementation(libs.turbine)
implementation(libs.kotest.assertions)
implementation(libs.kotest.property)
}
}
}

View file

@ -16,6 +16,7 @@
*/
package org.meshtastic.core.network.di
import kotlinx.serialization.ExperimentalSerializationApi
import kotlinx.serialization.json.Json
import org.koin.core.annotation.ComponentScan
import org.koin.core.annotation.Module
@ -24,10 +25,12 @@ import org.koin.core.annotation.Single
@Module
@ComponentScan("org.meshtastic.core.network")
class CoreNetworkModule {
@OptIn(ExperimentalSerializationApi::class)
@Single
fun provideJson(): Json = Json {
isLenient = true
ignoreUnknownKeys = true
coerceInputValues = true
exceptionsWithDebugInfo = false
}
}

View file

@ -35,6 +35,7 @@ import kotlinx.coroutines.flow.first
import kotlinx.coroutines.launch
import kotlinx.coroutines.sync.Semaphore
import kotlinx.coroutines.sync.withPermit
import kotlinx.serialization.ExperimentalSerializationApi
import kotlinx.serialization.json.Json
import okio.ByteString.Companion.toByteString
import org.koin.core.annotation.Single
@ -62,7 +63,12 @@ class MQTTRepositoryImpl(
}
private var client: MQTTClient? = null
private val json = Json { ignoreUnknownKeys = true }
@OptIn(ExperimentalSerializationApi::class)
private val json = Json {
ignoreUnknownKeys = true
exceptionsWithDebugInfo = false
}
private val scope = CoroutineScope(dispatchers.default + SupervisorJob())
private var clientJob: Job? = null
private val publishSemaphore = Semaphore(20)
@ -115,6 +121,9 @@ class MQTTRepositoryImpl(
Logger.d { "MQTT parsed JSON payload successfully" }
trySend(MqttClientProxyMessage(topic = topic, text = jsonStr, retained = packet.retain))
} catch (e: kotlinx.serialization.json.JsonDecodingException) {
@OptIn(ExperimentalSerializationApi::class)
Logger.e(e) { "Failed to parse MQTT JSON: ${e.shortMessage} (path: ${e.path})" }
} catch (e: kotlinx.serialization.SerializationException) {
Logger.e(e) { "Failed to parse MQTT JSON: ${e.message}" }
} catch (e: IllegalArgumentException) {

View file

@ -56,9 +56,6 @@ kotlin {
commonTest.dependencies {
implementation(projects.core.testing)
implementation(libs.kotlinx.coroutines.test)
implementation(libs.turbine)
implementation(libs.kotest.assertions)
implementation(libs.kotest.property)
}
}
}

View file

@ -70,9 +70,6 @@ kotlin {
implementation(projects.core.testing)
implementation(libs.junit)
implementation(libs.kotlinx.coroutines.test)
implementation(libs.turbine)
implementation(libs.kotest.assertions)
implementation(libs.kotest.property)
}
val androidHostTest by getting { dependencies { implementation(libs.androidx.test.runner) } }

View file

@ -17,7 +17,7 @@
package org.meshtastic.core.ui.component
import androidx.compose.ui.test.assertIsDisplayed
import androidx.compose.ui.test.junit4.createComposeRule
import androidx.compose.ui.test.junit4.v2.createComposeRule
import androidx.compose.ui.test.onNodeWithText
import org.junit.Rule
import org.junit.Test

View file

@ -20,7 +20,7 @@ import androidx.compose.material3.Text
import androidx.compose.runtime.CompositionLocalProvider
import androidx.compose.ui.test.assertDoesNotExist
import androidx.compose.ui.test.assertIsDisplayed
import androidx.compose.ui.test.junit4.createComposeRule
import androidx.compose.ui.test.junit4.v2.createComposeRule
import androidx.compose.ui.test.onNodeWithTag
import androidx.compose.ui.test.onNodeWithText
import androidx.compose.ui.test.performClick

View file

@ -19,7 +19,7 @@ package org.meshtastic.core.ui.util
import androidx.compose.runtime.collectAsState
import androidx.compose.runtime.getValue
import androidx.compose.ui.test.assertIsDisplayed
import androidx.compose.ui.test.junit4.createComposeRule
import androidx.compose.ui.test.junit4.v2.createComposeRule
import androidx.compose.ui.test.onNodeWithText
import androidx.compose.ui.test.performClick
import org.junit.Rule

View file

@ -58,11 +58,12 @@ kotlin {
androidMain.dependencies { implementation(libs.markdown.renderer.android) }
commonTest.dependencies { implementation(projects.core.testing) }
val androidHostTest by getting {
dependencies {
implementation(libs.junit)
implementation(libs.kotlinx.coroutines.test)
implementation(libs.androidx.compose.ui.test.junit4)
implementation(libs.androidx.test.ext.junit)
}
}

View file

@ -17,7 +17,9 @@
package org.meshtastic.feature.firmware.ota.dfu
import co.touchlab.kermit.Logger
import kotlinx.serialization.ExperimentalSerializationApi
import kotlinx.serialization.json.Json
import kotlinx.serialization.json.JsonDecodingException
private val json = Json { ignoreUnknownKeys = true }
@ -36,7 +38,11 @@ internal fun parseDfuZipEntries(entries: Map<String, ByteArray>): DfuZipPackage
val manifest =
runCatching { json.decodeFromString<DfuManifest>(manifestBytes.decodeToString()) }
.getOrElse { e -> throw DfuException.InvalidPackage("Failed to parse manifest.json: ${e.message}") }
.getOrElse { e ->
@OptIn(ExperimentalSerializationApi::class)
val detail = (e as? JsonDecodingException)?.shortMessage ?: e.message
throw DfuException.InvalidPackage("Failed to parse manifest.json: $detail")
}
val entry =
manifest.manifest.primaryEntry ?: throw DfuException.InvalidPackage("No firmware entry found in manifest.json")

View file

@ -44,7 +44,6 @@ kotlin {
implementation(libs.junit)
implementation(project.dependencies.platform(libs.androidx.compose.bom))
implementation(libs.kotlinx.coroutines.test)
implementation(libs.androidx.compose.ui.test.junit4)
}
}
}

View file

@ -68,7 +68,6 @@ osmdroid-android = "6.1.20"
spotless = "8.4.0"
wire = "6.2.0"
vico = "3.1.0"
dependency-guard = "0.5.0"
kable = "0.42.0"
kmqtt = "1.0.0"
jmdns = "3.6.3"
@ -141,7 +140,6 @@ compose-multiplatform-ui-tooling-preview = { module = "org.jetbrains.compose.ui:
compose-multiplatform-resources = { module = "org.jetbrains.compose.components:components-resources", version.ref = "compose-multiplatform" }
compose-multiplatform-material3 = { module = "org.jetbrains.compose.material3:material3", version.ref = "compose-multiplatform-material3" }
# JetBrains Material 3 Adaptive (multiplatform — Android, Desktop, iOS)
jetbrains-compose-material3-adaptive = { module = "org.jetbrains.compose.material3.adaptive:adaptive", version.ref = "jetbrains-adaptive" }
jetbrains-compose-material3-adaptive-layout = { module = "org.jetbrains.compose.material3.adaptive:adaptive-layout", version.ref = "jetbrains-adaptive" }
@ -174,7 +172,6 @@ qrcode-kotlin = { module = "io.github.g0dkar:qrcode-kotlin", version.ref = "qrco
kotlin-gradlePlugin = { module = "org.jetbrains.kotlin:kotlin-gradle-plugin", version.ref = "kotlin" }
dokka-gradlePlugin = { module = "org.jetbrains.dokka:dokka-gradle-plugin", version.ref = "dokka" }
kotlinx-collections-immutable = { module = "org.jetbrains.kotlinx:kotlinx-collections-immutable", version = "0.4.0" }
kotlinx-atomicfu = { module = "org.jetbrains.kotlinx:atomicfu", version = "0.32.1" }
kotlinx-coroutines-core = { module = "org.jetbrains.kotlinx:kotlinx-coroutines-core", version.ref = "kotlinx-coroutines-android" }
@ -199,13 +196,10 @@ androidx-test-ext-junit = { module = "androidx.test.ext:junit", version = "1.3.0
androidx-test-runner = { module = "androidx.test:runner", version = "1.7.0" }
androidx-test-espresso-core = { module = "androidx.test.espresso:espresso-core", version = "3.7.0" }
junit = { module = "junit:junit", version = "4.13.2" }
junit-jupiter = { module = "org.junit.jupiter:junit-jupiter", version.ref = "junit5" }
junit-vintage-engine = { module = "org.junit.vintage:junit-vintage-engine", version.ref = "junit5" }
junit-platform-launcher = { module = "org.junit.platform:junit-platform-launcher", version.ref = "junit-platform" }
mokkery-library = { module = "dev.mokkery:mokkery-runtime", version.ref = "mokkery" }
kotest-assertions = { module = "io.kotest:kotest-assertions-core", version.ref = "kotest" }
kotest-property = { module = "io.kotest:kotest-property", version.ref = "kotest" }
kotest-framework = { module = "io.kotest:kotest-framework-engine", version.ref = "kotest" }
kotest-runner-junit6 = { module = "io.kotest:kotest-runner-junit6", version.ref = "kotest" }
robolectric = { module = "org.robolectric:robolectric", version = "4.16.1" }
turbine = { module = "app.cash.turbine:turbine", version.ref = "turbine" }