From 8761bae86b9f4fa510d4e703d1bb223d5a9ee693 Mon Sep 17 00:00:00 2001 From: PranshulGG Date: Thu, 28 May 2026 20:40:13 +0530 Subject: [PATCH] add Nominatim reverse geocoding API, repository, and domain mapper --- .../sources/address/nominatim/NominatimApi.kt | 58 +++++++++++++++++++ .../nominatim/json/NominatimAddressJson.kt | 23 ++++++++ .../nominatim/json/NominatimRepository.kt | 29 ++++++++++ .../mapper/locations/NominatimJsonMapper.kt | 17 ++++++ 4 files changed, 127 insertions(+) create mode 100644 app/src/main/java/com/pranshulgg/weather_master_app/core/network/sources/address/nominatim/NominatimApi.kt create mode 100644 app/src/main/java/com/pranshulgg/weather_master_app/core/network/sources/address/nominatim/json/NominatimAddressJson.kt create mode 100644 app/src/main/java/com/pranshulgg/weather_master_app/core/network/sources/address/nominatim/json/NominatimRepository.kt create mode 100644 app/src/main/java/com/pranshulgg/weather_master_app/data/local/mapper/locations/NominatimJsonMapper.kt diff --git a/app/src/main/java/com/pranshulgg/weather_master_app/core/network/sources/address/nominatim/NominatimApi.kt b/app/src/main/java/com/pranshulgg/weather_master_app/core/network/sources/address/nominatim/NominatimApi.kt new file mode 100644 index 000000000..e8a63c6a7 --- /dev/null +++ b/app/src/main/java/com/pranshulgg/weather_master_app/core/network/sources/address/nominatim/NominatimApi.kt @@ -0,0 +1,58 @@ +package com.pranshulgg.weather_master_app.core.network.sources.address.nominatim + +import com.pranshulgg.weather_master_app.core.network.sources.address.nominatim.json.NominatimAddressJson +import okhttp3.OkHttpClient +import okhttp3.logging.HttpLoggingInterceptor +import retrofit2.Response +import retrofit2.Retrofit +import retrofit2.converter.gson.GsonConverterFactory +import retrofit2.http.GET +import retrofit2.http.Path +import retrofit2.http.Query +import java.util.concurrent.TimeUnit + +interface NominatimApi { + + + @GET("reverse") + suspend fun reverseGeocode( + @Query("format") format: String = "jsonv2", + @Query("lat") latitude: Double, + @Query("lon") longitude: Double, + @Query("layer") layer: String = "address" + ): Response + + companion object { + const val BASE_URL = "https://nominatim.openstreetmap.org/" + + fun create(): NominatimApi { + val logging = HttpLoggingInterceptor().apply { + level = HttpLoggingInterceptor.Level.BODY + } + + + val client = OkHttpClient.Builder() + .addInterceptor(logging) + .addInterceptor { chain -> + val request = chain.request().newBuilder() + .header( + "User-Agent", + "WeatherMaster (com.pranshulgg.weathermaster; pranshul.devmain@gmail.com)" + ) + .build() + + chain.proceed(request) + } + .connectTimeout(30, TimeUnit.SECONDS) + .readTimeout(30, TimeUnit.SECONDS) + .build() + + return Retrofit.Builder() + .baseUrl(BASE_URL) + .client(client) + .addConverterFactory(GsonConverterFactory.create()) + .build() + .create(NominatimApi::class.java) + } + } +} \ No newline at end of file diff --git a/app/src/main/java/com/pranshulgg/weather_master_app/core/network/sources/address/nominatim/json/NominatimAddressJson.kt b/app/src/main/java/com/pranshulgg/weather_master_app/core/network/sources/address/nominatim/json/NominatimAddressJson.kt new file mode 100644 index 000000000..c7e7a8c9b --- /dev/null +++ b/app/src/main/java/com/pranshulgg/weather_master_app/core/network/sources/address/nominatim/json/NominatimAddressJson.kt @@ -0,0 +1,23 @@ +package com.pranshulgg.weather_master_app.core.network.sources.address.nominatim.json + +import com.google.gson.annotations.SerializedName + + +data class NominatimAddressJson( + val address: NominatimAddressDataJson +) + +data class NominatimAddressDataJson( + val city: String?, + + @SerializedName("state_district") + val stateDistrict: String?, + + val county: String?, + val road: String?, + val village: String?, + val suburb: String?, + + val state: String?, + val country: String +) \ No newline at end of file diff --git a/app/src/main/java/com/pranshulgg/weather_master_app/core/network/sources/address/nominatim/json/NominatimRepository.kt b/app/src/main/java/com/pranshulgg/weather_master_app/core/network/sources/address/nominatim/json/NominatimRepository.kt new file mode 100644 index 000000000..79918794d --- /dev/null +++ b/app/src/main/java/com/pranshulgg/weather_master_app/core/network/sources/address/nominatim/json/NominatimRepository.kt @@ -0,0 +1,29 @@ +package com.pranshulgg.weather_master_app.core.network.sources.address.nominatim.json + +import com.pranshulgg.weather_master_app.core.model.domain.location.Address +import com.pranshulgg.weather_master_app.core.network.sources.address.nominatim.NominatimApi +import com.pranshulgg.weather_master_app.data.local.mapper.locations.toDomain +import java.net.UnknownHostException +import javax.inject.Inject + +class NominatimRepository @Inject constructor( + private val api: NominatimApi +) { + suspend fun getAddress(latitude: Double?, longitude: Double?): Address? { + try { + + if (latitude == null || longitude == null) return null + + val response = api.reverseGeocode("jsonv2", latitude, longitude) + + val body = response.body() ?: throw UnknownHostException() + + val domain = body.toDomain() + + return domain + + } catch (e: Exception) { + throw e + } + } +} \ No newline at end of file diff --git a/app/src/main/java/com/pranshulgg/weather_master_app/data/local/mapper/locations/NominatimJsonMapper.kt b/app/src/main/java/com/pranshulgg/weather_master_app/data/local/mapper/locations/NominatimJsonMapper.kt new file mode 100644 index 000000000..6d02477a8 --- /dev/null +++ b/app/src/main/java/com/pranshulgg/weather_master_app/data/local/mapper/locations/NominatimJsonMapper.kt @@ -0,0 +1,17 @@ +package com.pranshulgg.weather_master_app.data.local.mapper.locations + +import com.pranshulgg.weather_master_app.core.model.domain.location.Address +import com.pranshulgg.weather_master_app.core.network.sources.address.nominatim.json.NominatimAddressJson + + +fun NominatimAddressJson.toDomain(): Address { + val city = + this.address.city ?: this.address.suburb ?: this.address.village ?: this.address.county + ?: this.address.road ?: this.address.stateDistrict ?: this.address.state + + + return Address( + city = city, + country = this.address.country + ) +} \ No newline at end of file