Point SDK GraphQL to api-app and switch map markers query to getMarkers.

This aligns the app with the new backend endpoint/schema and keeps map marker mapping compatible with the new response shape.

Made-with: Cursor
This commit is contained in:
2026-03-02 19:22:03 +01:00
parent 8bf076697e
commit 436e165679
6 changed files with 1031 additions and 295 deletions

File diff suppressed because it is too large Load Diff

View File

@@ -39,6 +39,10 @@ apollo {
service("service") { service("service") {
packageName.set("org.db3.airmq.sdk") packageName.set("org.db3.airmq.sdk")
schemaFiles.from(file("../app/src/main/graphql/schema.graphqls")) schemaFiles.from(file("../app/src/main/graphql/schema.graphqls"))
introspection {
endpointUrl.set("https://api-app.airmq.cc/graphql")
schemaFile.set(file("../app/src/main/graphql/schema.graphqls"))
}
} }
} }
@@ -56,4 +60,6 @@ dependencies {
// Hilt // Hilt
implementation(libs.hilt.android) implementation(libs.hilt.android)
ksp(libs.hilt.compiler) ksp(libs.hilt.compiler)
testImplementation(libs.junit)
} }

View File

@@ -1,13 +1,12 @@
query MapMarkers($isOnline: Boolean) { query MapMarkers {
locations(filter: { isOnline: $isOnline }) { getMarkers {
_id _id
name name
city text
isOnline
latitude latitude
longitude longitude
metricList value
currentValue { values {
PMS25 PMS25
Count Count
} }

View File

@@ -8,24 +8,32 @@ import dagger.Provides
import dagger.hilt.InstallIn import dagger.hilt.InstallIn
import dagger.hilt.components.SingletonComponent import dagger.hilt.components.SingletonComponent
import javax.inject.Singleton import javax.inject.Singleton
import org.db3.airmq.sdk.auth.ApiTokenStore
import org.db3.airmq.sdk.auth.AuthService import org.db3.airmq.sdk.auth.AuthService
import org.db3.airmq.sdk.auth.BackendAuthGateway
import org.db3.airmq.sdk.auth.BackendAuthGatewayImpl
import org.db3.airmq.sdk.auth.FirebaseAuthService import org.db3.airmq.sdk.auth.FirebaseAuthService
import org.db3.airmq.sdk.auth.FirebaseSessionManager
import org.db3.airmq.sdk.auth.FirebaseSessionManagerImpl
import org.db3.airmq.sdk.auth.SharedPreferencesApiTokenStore
import org.db3.airmq.sdk.map.MapServiceImpl import org.db3.airmq.sdk.map.MapServiceImpl
import org.db3.airmq.sdk.map.MapService import org.db3.airmq.sdk.map.MapService
import org.db3.airmq.sdk.settings.SettingsService import org.db3.airmq.sdk.settings.SettingsService
import org.db3.airmq.sdk.settings.SettingsServiceImpl import org.db3.airmq.sdk.settings.SettingsServiceImpl
import org.db3.airmq.sdk.network.ApolloAuthInterceptor
import org.db3.airmq.sdk.network.ApolloLoggingInterceptor import org.db3.airmq.sdk.network.ApolloLoggingInterceptor
@Module @Module
@InstallIn(SingletonComponent::class) @InstallIn(SingletonComponent::class)
object SDKModule { object SDKModule {
private const val API_URL = "https://api.airmq.cc" private const val API_URL = "https://api-app.airmq.cc/"
@Provides @Provides
@Singleton @Singleton
fun provideApolloClient(): ApolloClient { fun provideApolloClient(apiTokenStore: ApiTokenStore): ApolloClient {
return ApolloClient.Builder() return ApolloClient.Builder()
.serverUrl(API_URL) .serverUrl(API_URL)
.addInterceptor(ApolloAuthInterceptor(apiTokenStore))
.addInterceptor(ApolloLoggingInterceptor()) .addInterceptor(ApolloLoggingInterceptor())
.build() .build()
} }
@@ -42,6 +50,18 @@ abstract class SDKBindModule {
@Singleton @Singleton
abstract fun bindAuthService(impl: FirebaseAuthService): AuthService abstract fun bindAuthService(impl: FirebaseAuthService): AuthService
@Binds
@Singleton
abstract fun bindApiTokenStore(impl: SharedPreferencesApiTokenStore): ApiTokenStore
@Binds
@Singleton
abstract fun bindFirebaseSessionManager(impl: FirebaseSessionManagerImpl): FirebaseSessionManager
@Binds
@Singleton
abstract fun bindBackendAuthGateway(impl: BackendAuthGatewayImpl): BackendAuthGateway
@Binds @Binds
@Singleton @Singleton
abstract fun bindMapService(impl: MapServiceImpl): MapService abstract fun bindMapService(impl: MapServiceImpl): MapService

View File

@@ -5,17 +5,20 @@ import org.db3.airmq.sdk.MapMarkersQuery
import org.db3.airmq.sdk.map.domain.MapItem import org.db3.airmq.sdk.map.domain.MapItem
class ApolloMapItemMapper @Inject constructor() { class ApolloMapItemMapper @Inject constructor() {
fun toDomain(location: MapMarkersQuery.Location, index: Int): MapItem? { fun toDomain(marker: MapMarkersQuery.GetMarker, index: Int): MapItem? {
val id = location._id.ifBlank { "location-$index" } val latitude = marker.latitude ?: return null
val longitude = marker.longitude ?: return null
val id = marker._id?.ifBlank { "marker-$index" } ?: "marker-$index"
val latestValues = marker.values?.firstOrNull()
return MapItem( return MapItem(
id = id, id = id,
title = location.name.ifBlank { id }, title = marker.name?.ifBlank { id } ?: id,
city = location.city?.ifBlank { null }, city = marker.text?.ifBlank { null },
latitude = location.latitude, latitude = latitude,
longitude = location.longitude, longitude = longitude,
isOnline = location.isOnline ?: false, isOnline = marker.value != null,
dustValue = location.currentValue?.PMS25?.toDouble(), dustValue = latestValues?.PMS25?.toDouble() ?: marker.value?.toDouble(),
radioactivityValue = location.currentValue?.Count?.toDouble() radioactivityValue = latestValues?.Count?.toDouble()
) )
} }
} }

View File

@@ -2,7 +2,6 @@ package org.db3.airmq.sdk.map
import android.util.Log import android.util.Log
import com.apollographql.apollo.ApolloClient import com.apollographql.apollo.ApolloClient
import com.apollographql.apollo.api.Optional
import javax.inject.Inject import javax.inject.Inject
import org.db3.airmq.sdk.MapMarkersQuery import org.db3.airmq.sdk.MapMarkersQuery
import org.db3.airmq.sdk.map.domain.MapItem import org.db3.airmq.sdk.map.domain.MapItem
@@ -13,17 +12,8 @@ class MapServiceImpl @Inject constructor(
) : MapService { ) : MapService {
override suspend fun fetchMapItems(showOfflineDevices: Boolean): List<MapItem> { override suspend fun fetchMapItems(showOfflineDevices: Boolean): List<MapItem> {
Log.d(TAG, "Executing MapMarkers Apollo query") Log.d(TAG, "Executing MapMarkers Apollo query")
val isOnlineFilter: Optional<Boolean?> = if (showOfflineDevices) {
Optional.Absent
} else {
Optional.Present(true)
}
val response = apolloClient val response = apolloClient
.query( .query(MapMarkersQuery())
MapMarkersQuery(
isOnline = isOnlineFilter
)
)
.execute() .execute()
response.errors?.firstOrNull()?.let { gqlError -> response.errors?.firstOrNull()?.let { gqlError ->
@@ -31,10 +21,10 @@ class MapServiceImpl @Inject constructor(
throw IllegalStateException(gqlError.message) throw IllegalStateException(gqlError.message)
} }
val mappedItems = response.data?.locations val mappedItems = response.data?.getMarkers
.orEmpty() .orEmpty()
.filterNotNull() .filterNotNull()
.mapIndexedNotNull { index, location -> mapper.toDomain(location, index) } .mapIndexedNotNull { index, marker -> mapper.toDomain(marker, index) }
Log.d(TAG, "MapMarkers Apollo query returned ${mappedItems.size} items") Log.d(TAG, "MapMarkers Apollo query returned ${mappedItems.size} items")
return mappedItems return mappedItems
} }