From 11224b84cbfc901f075c991e2f46d103e681caa6 Mon Sep 17 00:00:00 2001
From: James Rich <2199651+jamesarich@users.noreply.github.com>
Date: Thu, 22 May 2025 14:53:00 -0500
Subject: [PATCH] Refactor: Move ApiModule to flavor specific directories
(#1913)
---
.../java/com/geeksville/mesh/ui/NodeDetail.kt | 2 +-
network/build.gradle.kts | 10 +++
.../geeksville/mesh/network/di/ApiModule.kt | 82 +++++++++++++++++++
.../mesh/network/retrofit/NoOpApiService.kt | 35 ++++++++
.../geeksville/mesh/network/di/ApiModule.kt | 0
.../mesh/network/retrofit/ApiService.kt | 4 -
6 files changed, 128 insertions(+), 5 deletions(-)
create mode 100644 network/src/fdroid/java/com/geeksville/mesh/network/di/ApiModule.kt
create mode 100644 network/src/fdroid/java/com/geeksville/mesh/network/retrofit/NoOpApiService.kt
rename network/src/{main => google}/java/com/geeksville/mesh/network/di/ApiModule.kt (100%)
diff --git a/app/src/main/java/com/geeksville/mesh/ui/NodeDetail.kt b/app/src/main/java/com/geeksville/mesh/ui/NodeDetail.kt
index 660c8fdbc..462c9a615 100644
--- a/app/src/main/java/com/geeksville/mesh/ui/NodeDetail.kt
+++ b/app/src/main/java/com/geeksville/mesh/ui/NodeDetail.kt
@@ -384,7 +384,7 @@ fun DeviceHardwareImage(
deviceHardware: DeviceHardware,
modifier: Modifier = Modifier,
) {
- val hwImg = deviceHardware.images?.get(1) ?: deviceHardware.images?.get(0) ?: "unknown.svg"
+ val hwImg = deviceHardware.images?.getOrNull(1) ?: deviceHardware.images?.getOrNull(0) ?: "unknown.svg"
val imageUrl = "https://flasher.meshtastic.org/img/devices/$hwImg"
val listener = object : ImageRequest.Listener {
override fun onStart(request: ImageRequest) {
diff --git a/network/build.gradle.kts b/network/build.gradle.kts
index 58f6b7d61..3f0f4343b 100644
--- a/network/build.gradle.kts
+++ b/network/build.gradle.kts
@@ -23,6 +23,16 @@ android {
sourceCompatibility(JavaVersion.VERSION_17)
targetCompatibility(JavaVersion.VERSION_17)
}
+
+ flavorDimensions += "default"
+ productFlavors {
+ create("fdroid") {
+ dimension = "default"
+ }
+ create("google") {
+ dimension = "default"
+ }
+ }
}
kotlin {
diff --git a/network/src/fdroid/java/com/geeksville/mesh/network/di/ApiModule.kt b/network/src/fdroid/java/com/geeksville/mesh/network/di/ApiModule.kt
new file mode 100644
index 000000000..ba4531ea4
--- /dev/null
+++ b/network/src/fdroid/java/com/geeksville/mesh/network/di/ApiModule.kt
@@ -0,0 +1,82 @@
+/*
+ * Copyright (c) 2025 Meshtastic LLC
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+
+package com.geeksville.mesh.network.di
+
+import android.content.Context
+import coil3.ImageLoader
+import coil3.disk.DiskCache
+import coil3.memory.MemoryCache
+import coil3.network.okhttp.OkHttpNetworkFetcherFactory
+import coil3.request.crossfade
+import coil3.svg.SvgDecoder
+import coil3.util.DebugLogger
+import coil3.util.Logger
+import com.geeksville.mesh.network.BuildConfig
+import com.geeksville.mesh.network.retrofit.ApiService
+import com.geeksville.mesh.network.retrofit.NoOpApiService
+import dagger.Binds
+import dagger.Module
+import dagger.Provides
+import dagger.hilt.InstallIn
+import dagger.hilt.android.qualifiers.ApplicationContext
+import dagger.hilt.components.SingletonComponent
+import okhttp3.OkHttpClient
+import javax.inject.Singleton
+
+private const val DISK_CACHE_PERCENT = 0.02
+private const val MEMORY_CACHE_PERCENT = 0.25
+
+@InstallIn(SingletonComponent::class)
+@Module
+class ApiModule {
+
+ @Provides
+ @Singleton
+ fun provideApiService(): ApiService {
+ return NoOpApiService()
+ }
+
+ @Provides
+ @Singleton
+ fun imageLoader(
+ httpClient: OkHttpClient,
+ @ApplicationContext application: Context,
+ ): ImageLoader {
+ val sharedOkHttp = httpClient.newBuilder().build()
+ return ImageLoader.Builder(application)
+ .components {
+ add(
+ OkHttpNetworkFetcherFactory({ sharedOkHttp })
+ )
+ add(SvgDecoder.Factory())
+ }
+ .memoryCache {
+ MemoryCache.Builder()
+ .maxSizePercent(application, MEMORY_CACHE_PERCENT)
+ .build()
+ }
+ .diskCache {
+ DiskCache.Builder()
+ .maxSizePercent(DISK_CACHE_PERCENT)
+ .build()
+ }
+ .logger(if (BuildConfig.DEBUG) DebugLogger(Logger.Level.Verbose) else null)
+ .crossfade(true)
+ .build()
+ }
+}
diff --git a/network/src/fdroid/java/com/geeksville/mesh/network/retrofit/NoOpApiService.kt b/network/src/fdroid/java/com/geeksville/mesh/network/retrofit/NoOpApiService.kt
new file mode 100644
index 000000000..02415e080
--- /dev/null
+++ b/network/src/fdroid/java/com/geeksville/mesh/network/retrofit/NoOpApiService.kt
@@ -0,0 +1,35 @@
+/*
+ * Copyright (c) 2025 Meshtastic LLC
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+
+package com.geeksville.mesh.network.retrofit
+
+import com.geeksville.mesh.network.model.NetworkDeviceHardware
+import com.geeksville.mesh.network.model.NetworkFirmwareReleases
+import retrofit2.Response
+import javax.inject.Inject
+import javax.inject.Singleton
+
+@Singleton
+class NoOpApiService@Inject constructor() : ApiService {
+ override suspend fun getDeviceHardware(): Response> {
+ return Response.success(emptyList())
+ }
+
+ override suspend fun getFirmwareReleases(): Response {
+ return Response.success(NetworkFirmwareReleases(emptyList()))
+ }
+}
\ No newline at end of file
diff --git a/network/src/main/java/com/geeksville/mesh/network/di/ApiModule.kt b/network/src/google/java/com/geeksville/mesh/network/di/ApiModule.kt
similarity index 100%
rename from network/src/main/java/com/geeksville/mesh/network/di/ApiModule.kt
rename to network/src/google/java/com/geeksville/mesh/network/di/ApiModule.kt
diff --git a/network/src/main/java/com/geeksville/mesh/network/retrofit/ApiService.kt b/network/src/main/java/com/geeksville/mesh/network/retrofit/ApiService.kt
index 97c9c907b..daf513411 100644
--- a/network/src/main/java/com/geeksville/mesh/network/retrofit/ApiService.kt
+++ b/network/src/main/java/com/geeksville/mesh/network/retrofit/ApiService.kt
@@ -21,12 +21,8 @@ import com.geeksville.mesh.network.model.NetworkDeviceHardware
import com.geeksville.mesh.network.model.NetworkFirmwareReleases
import retrofit2.Response
import retrofit2.http.GET
-import retrofit2.http.Query
interface ApiService {
- @GET(".")
- suspend fun checkDeviceRegistration(@Query("deviceId") deviceId: String): Response
-
@GET("resource/deviceHardware")
suspend fun getDeviceHardware(): Response>