From 37885c045482d224835c9c90bf0d4219a268ff7e Mon Sep 17 00:00:00 2001 From: enlineawork Date: Wed, 9 Sep 2026 13:57:08 -0300 Subject: [PATCH] =?UTF-8?q?F6.1=20=C2=B7=20cliente=20Android=20para=20abri?= =?UTF-8?q?r=20inspecciones?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../dhinspeccion/data/MobileInspectionOpen.kt | 103 ++++++++++++++++++ 1 file changed, 103 insertions(+) create mode 100644 android-app/app/src/main/java/com/korexlabs/dhinspeccion/data/MobileInspectionOpen.kt diff --git a/android-app/app/src/main/java/com/korexlabs/dhinspeccion/data/MobileInspectionOpen.kt b/android-app/app/src/main/java/com/korexlabs/dhinspeccion/data/MobileInspectionOpen.kt new file mode 100644 index 0000000..c0a5e64 --- /dev/null +++ b/android-app/app/src/main/java/com/korexlabs/dhinspeccion/data/MobileInspectionOpen.kt @@ -0,0 +1,103 @@ +package com.korexlabs.dhinspeccion.data + +import android.content.Context +import com.korexlabs.dhinspeccion.BuildConfig +import com.squareup.moshi.Moshi +import com.squareup.moshi.kotlin.reflect.KotlinJsonAdapterFactory +import kotlinx.coroutines.sync.Mutex +import kotlinx.coroutines.sync.withLock +import okhttp3.OkHttpClient +import retrofit2.HttpException +import retrofit2.Retrofit +import retrofit2.converter.moshi.MoshiConverterFactory +import retrofit2.http.Body +import retrofit2.http.GET +import retrofit2.http.Header +import retrofit2.http.POST +import retrofit2.http.Path + +data class MobilePlanningAsset( + val id: String, + val code: String, + val name: String, +) + +data class MobilePlanningAssetResponse( + val data: List = emptyList(), +) + +data class OpenMobileInspectionRequest( + val operationalAreaId: String, + val operatorCompanyId: String, +) + +private interface MobileInspectionOpenApi { + @GET("inspection-visits/mobile/planning-context/areas") + suspend fun areas( + @Header("Authorization") authorization: String, + ): MobilePlanningAssetResponse + + @GET("inspection-visits/mobile/planning-context/areas/{areaId}/operators") + suspend fun operators( + @Header("Authorization") authorization: String, + @Path("areaId") areaId: String, + ): MobilePlanningAssetResponse + + @POST("inspection-visits/mobile/open") + suspend fun open( + @Header("Authorization") authorization: String, + @Body request: OpenMobileInspectionRequest, + ): VisitDetail + + @POST("auth/mobile/refresh") + suspend fun refresh(@Body request: RefreshRequest): MobileSessionResponse +} + +class MobileInspectionOpenRepository(context: Context) { + private val store = SecureSessionStore(context.applicationContext) + private val refreshMutex = Mutex() + private val moshi = Moshi.Builder().addLast(KotlinJsonAdapterFactory()).build() + private val api: MobileInspectionOpenApi = Retrofit.Builder() + .baseUrl(BuildConfig.API_BASE_URL) + .client(OkHttpClient.Builder().build()) + .addConverterFactory(MoshiConverterFactory.create(moshi)) + .build() + .create(MobileInspectionOpenApi::class.java) + + suspend fun areas(): MobilePlanningAssetResponse = authorized { session -> + api.areas("Bearer ${session.accessToken}") + } + + suspend fun operators(areaId: String): MobilePlanningAssetResponse = authorized { session -> + api.operators("Bearer ${session.accessToken}", areaId) + } + + suspend fun open(areaId: String, companyId: String): VisitDetail = authorized { session -> + api.open( + "Bearer ${session.accessToken}", + OpenMobileInspectionRequest(areaId, companyId), + ) + } + + private suspend fun authorized(block: suspend (StoredSession) -> T): T { + var session = store.load() ?: throw IllegalStateException("Sesión no iniciada") + try { + return block(session) + } catch (error: HttpException) { + if (error.code() != 401) throw error + } + session = refresh(session.refreshToken) + return block(session) + } + + private suspend fun refresh(previousRefreshToken: String): StoredSession = refreshMutex.withLock { + val latest = store.load() ?: throw IllegalStateException("Sesión no iniciada") + if (latest.refreshToken != previousRefreshToken) return@withLock latest + try { + store.save(api.refresh(RefreshRequest(previousRefreshToken))) + } catch (error: Throwable) { + store.clear() + throw error + } + } +}