1
1
package cloud.pace.sdk.poikit.poi
2
2
3
+ import TileQueryRequestOuterClass
3
4
import androidx.lifecycle.LiveData
4
5
import androidx.lifecycle.MutableLiveData
5
6
import androidx.lifecycle.Observer
@@ -8,7 +9,6 @@ import cloud.pace.sdk.api.poi.POIAPI.gasStations
8
9
import cloud.pace.sdk.api.poi.generated.request.gasStations.GetGasStationAPI.getGasStation
9
10
import cloud.pace.sdk.poikit.database.GasStationDAO
10
11
import cloud.pace.sdk.poikit.poi.download.TileDownloader
11
- import cloud.pace.sdk.poikit.utils.ApiException
12
12
import cloud.pace.sdk.poikit.utils.POIKitConfig
13
13
import cloud.pace.sdk.poikit.utils.addPadding
14
14
import cloud.pace.sdk.poikit.utils.toTileQueryRequest
@@ -70,7 +70,7 @@ class VisibleRegionNotificationToken(
70
70
71
71
downloadTask = tileDownloader.load(tileRequest) {
72
72
it.onSuccess { stations ->
73
- CoroutineScope ( Dispatchers . IO ).launch {
73
+ onIOBackgroundThread {
74
74
gasStationDao.insertGasStations(stations)
75
75
76
76
withContext(Dispatchers .Main ) { loading.value = false }
@@ -89,7 +89,7 @@ class VisibleRegionNotificationToken(
89
89
90
90
it.onFailure { error ->
91
91
completion(Failure (error))
92
- MainScope ().launch { loading.value = false }
92
+ onMainThread { loading.value = false }
93
93
}
94
94
}
95
95
@@ -119,21 +119,45 @@ class IDsNotificationToken(
119
119
override fun refresh (zoomLevel : Int ) {
120
120
loading.value = true
121
121
122
- CoroutineScope (Dispatchers .IO ).launch {
123
- val tileRequest = gasStationDao.getByIds(ids).mapNotNull { it.center }.toTileQueryRequest(zoomLevel)
124
-
125
- downloadTask = tileDownloader.load(tileRequest) {
126
- it.onSuccess { stations ->
127
- CoroutineScope (Dispatchers .IO ).launch {
128
- gasStationDao.insertGasStations(stations)
129
- withContext(Dispatchers .Main ) { loading.value = false }
130
- }
131
- }
122
+ CoroutineScope (Dispatchers .Default ).launch {
123
+ val dbStations = gasStationDao.getByIds(ids)
124
+ // Gas station we don't have in the database
125
+ val missingStationIds = ids - dbStations.map { it.id }
126
+ // Database stations without location
127
+ val stationsWithoutLocations = dbStations.filter { it.center == null }.map { it.id }
128
+ // List of unknown gas station locations
129
+ val stationsToFetch = (missingStationIds + stationsWithoutLocations).toSet()
130
+
131
+ if (stationsToFetch.isNotEmpty()) {
132
+ // First fetch gas stations to get locations for tile request
133
+ try {
134
+ val tileRequest = stationsToFetch
135
+ .map {
136
+ async {
137
+ getGasStation(it)
138
+ }
139
+ }
140
+ .awaitAll()
141
+ .mapNotNull {
142
+ val latitude = it?.latitude?.toDouble()
143
+ val longitude = it?.longitude?.toDouble()
144
+ if (latitude != null && longitude != null ) {
145
+ LocationPoint (latitude, longitude)
146
+ } else {
147
+ null
148
+ }
149
+ }
150
+ .plus(dbStations.mapNotNull { it.center }) // List of gas stations we already have in the database
151
+ .toTileQueryRequest(zoomLevel)
132
152
133
- it.onFailure { error ->
134
- completion( Failure (error))
135
- MainScope ().launch { loading.value = false }
153
+ download(tileRequest)
154
+ } catch (e : Exception ) {
155
+ completion( Failure (e))
136
156
}
157
+ } else {
158
+ // We already have all gas station locations, download the data from the tiles right now
159
+ val tileRequest = dbStations.mapNotNull { it.center }.toTileQueryRequest(zoomLevel)
160
+ download(tileRequest)
137
161
}
138
162
}
139
163
@@ -144,6 +168,22 @@ class IDsNotificationToken(
144
168
gasStations.removeObserver(gasStationsObserver)
145
169
downloadTask?.cancel()
146
170
}
171
+
172
+ private suspend fun download (tileRequest : TileQueryRequestOuterClass .TileQueryRequest ) = withContext(Dispatchers .IO ) {
173
+ downloadTask = tileDownloader.load(tileRequest) {
174
+ it.onSuccess { stations ->
175
+ onIOBackgroundThread {
176
+ gasStationDao.insertGasStations(stations)
177
+ withContext(Dispatchers .Main ) { loading.value = false }
178
+ }
179
+ }
180
+
181
+ it.onFailure { error ->
182
+ completion(Failure (error))
183
+ onMainThread { loading.value = false }
184
+ }
185
+ }
186
+ }
147
187
}
148
188
149
189
class IDNotificationToken (
@@ -163,30 +203,22 @@ class IDNotificationToken(
163
203
override fun refresh (zoomLevel : Int ) {
164
204
loading.value = true
165
205
166
- GlobalScope .launch {
206
+ onIOBackgroundThread {
167
207
val location = gasStationDao.getByIds(listOf (id)).mapNotNull { it.center }.firstOrNull()
168
208
if (location != null ) {
169
209
download(location, zoomLevel)
170
210
} else {
171
- API .gasStations.getGasStation(id, false ).enqueue {
172
- onResponse = {
173
- val body = it.body()
174
- if (it.isSuccessful && body != null ) {
175
- val latitude = body.latitude?.toDouble()
176
- val longitude = body.longitude?.toDouble()
177
- if (latitude != null && longitude != null ) {
178
- download(LocationPoint (latitude, longitude), zoomLevel)
179
- } else {
180
- completion(Failure (Exception (" Latitude or longitude is null" )))
181
- }
182
- } else {
183
- completion(Failure (ApiException (it.code(), it.message(), it.requestId)))
184
- }
185
- }
186
-
187
- onFailure = {
188
- completion(Failure (it ? : Exception (" Unknown exception" )))
211
+ try {
212
+ val gasStation = getGasStation(id)
213
+ val latitude = gasStation?.latitude?.toDouble()
214
+ val longitude = gasStation?.longitude?.toDouble()
215
+ if (latitude != null && longitude != null ) {
216
+ download(LocationPoint (latitude, longitude), zoomLevel)
217
+ } else {
218
+ completion(Failure (Exception (" Latitude, longitude or gas station itself is null. Gas station ID: $id " )))
189
219
}
220
+ } catch (e: Exception ) {
221
+ completion(Failure (e))
190
222
}
191
223
}
192
224
}
@@ -202,15 +234,15 @@ class IDNotificationToken(
202
234
private fun download (location : LocationPoint , zoomLevel : Int ) {
203
235
downloadTask = tileDownloader.load(location.toTileQueryRequest(zoomLevel)) {
204
236
it.onSuccess { stations ->
205
- CoroutineScope ( Dispatchers . IO ).launch {
237
+ onIOBackgroundThread {
206
238
gasStationDao.insertGasStations(stations)
207
239
withContext(Dispatchers .Main ) { loading.value = false }
208
240
}
209
241
}
210
242
211
243
it.onFailure { error ->
212
244
completion(Failure (error))
213
- MainScope ().launch { loading.value = false }
245
+ onMainThread { loading.value = false }
214
246
}
215
247
}
216
248
}
@@ -236,15 +268,15 @@ class LocationsNotificationToken(
236
268
val tileRequest = locations.values.toTileQueryRequest(zoomLevel)
237
269
downloadTask = tileDownloader.load(tileRequest) {
238
270
it.onSuccess { stations ->
239
- CoroutineScope ( Dispatchers . IO ).launch {
271
+ onIOBackgroundThread {
240
272
gasStationDao.insertGasStations(stations)
241
273
withContext(Dispatchers .Main ) { loading.value = false }
242
274
}
243
275
}
244
276
245
277
it.onFailure { error ->
246
278
completion(Failure (error))
247
- MainScope ().launch { loading.value = false }
279
+ onMainThread { loading.value = false }
248
280
}
249
281
}
250
282
@@ -256,3 +288,22 @@ class LocationsNotificationToken(
256
288
downloadTask?.cancel()
257
289
}
258
290
}
291
+
292
+ suspend fun getGasStation (id : String ) = withContext(Dispatchers .IO ) {
293
+ suspendCancellableCoroutine< cloud.pace.sdk.api.poi.generated.model.GasStation ? > { continuation ->
294
+ API .gasStations.getGasStation(id, false ).enqueue {
295
+ onResponse = {
296
+ val body = it.body()
297
+ if (it.isSuccessful && body != null ) {
298
+ continuation.resumeIfActive(body)
299
+ } else {
300
+ continuation.resumeIfActive(null )
301
+ }
302
+ }
303
+
304
+ onFailure = {
305
+ continuation.resumeIfActive(null )
306
+ }
307
+ }
308
+ }
309
+ }
0 commit comments