Skip to content

Commit 009df13

Browse files
authored
[All] Add function for getting last known location (#211)
1 parent fa955cb commit 009df13

File tree

13 files changed

+98
-0
lines changed

13 files changed

+98
-0
lines changed

compass-geolocation-browser/src/commonMain/kotlin/dev/jordond/compass/geolocation/browser/internal/DefaultBrowserLocator.kt

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,14 @@ internal class DefaultBrowserLocator : BrowserLocator {
4040
)
4141
override val locationUpdates: Flow<Location> = _locationUpdates
4242

43+
override suspend fun lastLocation(priority: Priority): Location? {
44+
try {
45+
return current(priority)
46+
} catch (error: NotFoundException) {
47+
return null
48+
}
49+
}
50+
4351
override suspend fun isAvailable(): Boolean {
4452
return navigator?.geolocation != null
4553
}

compass-geolocation-mobile/src/androidMain/kotlin/dev/jordond/compass/geolocation/mobile/MobileLocator.android.kt

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,11 @@ internal class AndroidLocator(
3333
override val locationUpdates: Flow<Location> = locationManager.locationUpdates
3434
.mapNotNull { result -> result.lastLocation?.toModel() }
3535

36+
override suspend fun lastLocation(priority: Priority): Location? {
37+
requirePermission(priority)
38+
return locationManager.lastLocation()?.toModel()
39+
}
40+
3641
override suspend fun isAvailable(): Boolean {
3742
return locationManager.locationEnabled()
3843
}

compass-geolocation-mobile/src/androidMain/kotlin/dev/jordond/compass/geolocation/mobile/internal/LocationManager.kt

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,11 +18,15 @@ import com.google.android.gms.location.Priority.PRIORITY_PASSIVE
1818
import com.google.android.gms.location.SettingsClient
1919
import com.google.android.gms.tasks.CancellationTokenSource
2020
import dev.jordond.compass.exception.NotFoundException
21+
import kotlinx.coroutines.CancellationException
2122
import kotlinx.coroutines.ExperimentalCoroutinesApi
2223
import kotlinx.coroutines.channels.BufferOverflow
2324
import kotlinx.coroutines.flow.Flow
2425
import kotlinx.coroutines.flow.MutableSharedFlow
2526
import kotlinx.coroutines.tasks.await
27+
import kotlin.coroutines.resume
28+
import kotlin.coroutines.resumeWithException
29+
import kotlin.coroutines.suspendCoroutine
2630

2731
internal class LocationManager(
2832
private val context: Context,
@@ -45,6 +49,19 @@ internal class LocationManager(
4549
LocationServices.getSettingsClient(context)
4650
}
4751

52+
suspend fun lastLocation(): Location? {
53+
return suspendCoroutine { continuation ->
54+
fusedLocationClient.lastLocation
55+
.addOnSuccessListener { location ->
56+
continuation.resume(location)
57+
}.addOnCanceledListener {
58+
continuation.resumeWithException(CancellationException())
59+
}.addOnFailureListener { exception ->
60+
continuation.resumeWithException(exception)
61+
}
62+
}
63+
}
64+
4865
suspend fun locationEnabled(): Boolean {
4966
val request = LocationSettingsRequest.Builder().addAllLocationRequests(
5067
listOf(

compass-geolocation-mobile/src/iosMain/kotlin/dev/jordond/compass/geolocation/mobile/MobileLocator.ios.kt

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,11 @@ internal class IosLocator(
4343
}
4444
}
4545

46+
override suspend fun lastLocation(priority: Priority): Location? {
47+
requirePermission()
48+
return locationDelegate.lastLocation()?.toModel()
49+
}
50+
4651
override suspend fun isAvailable(): Boolean {
4752
return CLLocationManager.locationServicesEnabled()
4853
}

compass-geolocation-mobile/src/iosMain/kotlin/dev/jordond/compass/geolocation/mobile/internal/LocationManagerDelegate.kt

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,10 @@ internal class LocationManagerDelegate : NSObject(), CLLocationManagerDelegatePr
2121
manager.delegate = this
2222
}
2323

24+
fun lastLocation(): CLLocation? {
25+
return manager.location
26+
}
27+
2428
fun monitorLocation(callback: (CLLocation) -> Unit) {
2529
locationCallback = callback
2630
}

compass-geolocation/api/android/compass-geolocation.api

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,8 @@ public abstract interface class dev/jordond/compass/geolocation/Geolocator {
1212
public abstract fun getLocationUpdates ()Lkotlinx/coroutines/flow/Flow;
1313
public abstract fun getTrackingStatus ()Lkotlinx/coroutines/flow/Flow;
1414
public abstract fun isAvailable (Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
15+
public abstract fun lastLocation (Ldev/jordond/compass/Priority;Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
16+
public abstract fun lastLocation (Ldev/jordond/compass/geolocation/LocationRequest;Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
1517
public abstract fun startTracking (Ldev/jordond/compass/geolocation/LocationRequest;Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
1618
public abstract fun stopTracking ()V
1719
public abstract fun track (Ldev/jordond/compass/geolocation/LocationRequest;)Lkotlinx/coroutines/flow/Flow;
@@ -23,6 +25,7 @@ public final class dev/jordond/compass/geolocation/Geolocator$Companion {
2325
public final class dev/jordond/compass/geolocation/Geolocator$DefaultImpls {
2426
public static synthetic fun current$default (Ldev/jordond/compass/geolocation/Geolocator;Ldev/jordond/compass/Priority;Lkotlin/coroutines/Continuation;ILjava/lang/Object;)Ljava/lang/Object;
2527
public static fun getLocationUpdates (Ldev/jordond/compass/geolocation/Geolocator;)Lkotlinx/coroutines/flow/Flow;
28+
public static synthetic fun lastLocation$default (Ldev/jordond/compass/geolocation/Geolocator;Ldev/jordond/compass/Priority;Lkotlin/coroutines/Continuation;ILjava/lang/Object;)Ljava/lang/Object;
2629
public static fun startTracking (Ldev/jordond/compass/geolocation/Geolocator;Ldev/jordond/compass/geolocation/LocationRequest;Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
2730
public static synthetic fun startTracking$default (Ldev/jordond/compass/geolocation/Geolocator;Ldev/jordond/compass/geolocation/LocationRequest;Lkotlin/coroutines/Continuation;ILjava/lang/Object;)Ljava/lang/Object;
2831
public static synthetic fun track$default (Ldev/jordond/compass/geolocation/Geolocator;Ldev/jordond/compass/geolocation/LocationRequest;ILjava/lang/Object;)Lkotlinx/coroutines/flow/Flow;
@@ -139,6 +142,7 @@ public abstract interface class dev/jordond/compass/geolocation/Locator {
139142
public abstract fun current (Ldev/jordond/compass/Priority;Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
140143
public abstract fun getLocationUpdates ()Lkotlinx/coroutines/flow/Flow;
141144
public abstract fun isAvailable (Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
145+
public abstract fun lastLocation (Ldev/jordond/compass/Priority;Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
142146
public abstract fun stopTracking ()V
143147
public abstract fun track (Ldev/jordond/compass/geolocation/LocationRequest;Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
144148
}
@@ -148,6 +152,7 @@ public final class dev/jordond/compass/geolocation/Locator$Companion {
148152

149153
public final class dev/jordond/compass/geolocation/Locator$DefaultImpls {
150154
public static synthetic fun current$default (Ldev/jordond/compass/geolocation/Locator;Ldev/jordond/compass/Priority;Lkotlin/coroutines/Continuation;ILjava/lang/Object;)Ljava/lang/Object;
155+
public static synthetic fun lastLocation$default (Ldev/jordond/compass/geolocation/Locator;Ldev/jordond/compass/Priority;Lkotlin/coroutines/Continuation;ILjava/lang/Object;)Ljava/lang/Object;
151156
public static synthetic fun track$default (Ldev/jordond/compass/geolocation/Locator;Ldev/jordond/compass/geolocation/LocationRequest;Lkotlin/coroutines/Continuation;ILjava/lang/Object;)Ljava/lang/Object;
152157
}
153158

@@ -156,6 +161,7 @@ public final class dev/jordond/compass/geolocation/NotSupportedLocator : dev/jor
156161
public fun current (Ldev/jordond/compass/Priority;Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
157162
public fun getLocationUpdates ()Lkotlinx/coroutines/flow/Flow;
158163
public fun isAvailable (Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
164+
public fun lastLocation (Ldev/jordond/compass/Priority;Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
159165
public fun stopTracking ()V
160166
public fun track (Ldev/jordond/compass/geolocation/LocationRequest;Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
161167
}

compass-geolocation/api/jvm/compass-geolocation.api

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,8 @@ public abstract interface class dev/jordond/compass/geolocation/Geolocator {
1212
public abstract fun getLocationUpdates ()Lkotlinx/coroutines/flow/Flow;
1313
public abstract fun getTrackingStatus ()Lkotlinx/coroutines/flow/Flow;
1414
public abstract fun isAvailable (Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
15+
public abstract fun lastLocation (Ldev/jordond/compass/Priority;Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
16+
public abstract fun lastLocation (Ldev/jordond/compass/geolocation/LocationRequest;Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
1517
public abstract fun startTracking (Ldev/jordond/compass/geolocation/LocationRequest;Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
1618
public abstract fun stopTracking ()V
1719
public abstract fun track (Ldev/jordond/compass/geolocation/LocationRequest;)Lkotlinx/coroutines/flow/Flow;
@@ -23,6 +25,7 @@ public final class dev/jordond/compass/geolocation/Geolocator$Companion {
2325
public final class dev/jordond/compass/geolocation/Geolocator$DefaultImpls {
2426
public static synthetic fun current$default (Ldev/jordond/compass/geolocation/Geolocator;Ldev/jordond/compass/Priority;Lkotlin/coroutines/Continuation;ILjava/lang/Object;)Ljava/lang/Object;
2527
public static fun getLocationUpdates (Ldev/jordond/compass/geolocation/Geolocator;)Lkotlinx/coroutines/flow/Flow;
28+
public static synthetic fun lastLocation$default (Ldev/jordond/compass/geolocation/Geolocator;Ldev/jordond/compass/Priority;Lkotlin/coroutines/Continuation;ILjava/lang/Object;)Ljava/lang/Object;
2629
public static fun startTracking (Ldev/jordond/compass/geolocation/Geolocator;Ldev/jordond/compass/geolocation/LocationRequest;Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
2730
public static synthetic fun startTracking$default (Ldev/jordond/compass/geolocation/Geolocator;Ldev/jordond/compass/geolocation/LocationRequest;Lkotlin/coroutines/Continuation;ILjava/lang/Object;)Ljava/lang/Object;
2831
public static synthetic fun track$default (Ldev/jordond/compass/geolocation/Geolocator;Ldev/jordond/compass/geolocation/LocationRequest;ILjava/lang/Object;)Lkotlinx/coroutines/flow/Flow;
@@ -139,6 +142,7 @@ public abstract interface class dev/jordond/compass/geolocation/Locator {
139142
public abstract fun current (Ldev/jordond/compass/Priority;Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
140143
public abstract fun getLocationUpdates ()Lkotlinx/coroutines/flow/Flow;
141144
public abstract fun isAvailable (Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
145+
public abstract fun lastLocation (Ldev/jordond/compass/Priority;Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
142146
public abstract fun stopTracking ()V
143147
public abstract fun track (Ldev/jordond/compass/geolocation/LocationRequest;Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
144148
}
@@ -148,6 +152,7 @@ public final class dev/jordond/compass/geolocation/Locator$Companion {
148152

149153
public final class dev/jordond/compass/geolocation/Locator$DefaultImpls {
150154
public static synthetic fun current$default (Ldev/jordond/compass/geolocation/Locator;Ldev/jordond/compass/Priority;Lkotlin/coroutines/Continuation;ILjava/lang/Object;)Ljava/lang/Object;
155+
public static synthetic fun lastLocation$default (Ldev/jordond/compass/geolocation/Locator;Ldev/jordond/compass/Priority;Lkotlin/coroutines/Continuation;ILjava/lang/Object;)Ljava/lang/Object;
151156
public static synthetic fun track$default (Ldev/jordond/compass/geolocation/Locator;Ldev/jordond/compass/geolocation/LocationRequest;Lkotlin/coroutines/Continuation;ILjava/lang/Object;)Ljava/lang/Object;
152157
}
153158

@@ -156,6 +161,7 @@ public final class dev/jordond/compass/geolocation/NotSupportedLocator : dev/jor
156161
public fun current (Ldev/jordond/compass/Priority;Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
157162
public fun getLocationUpdates ()Lkotlinx/coroutines/flow/Flow;
158163
public fun isAvailable (Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
164+
public fun lastLocation (Ldev/jordond/compass/Priority;Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
159165
public fun stopTracking ()V
160166
public fun track (Ldev/jordond/compass/geolocation/LocationRequest;Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
161167
}

compass-geolocation/src/commonMain/kotlin/dev/jordond/compass/geolocation/Geolocator.kt

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,22 @@ public interface Geolocator {
4141
public val locationUpdates: Flow<Location>
4242
get() = trackingStatus.filterIsInstance<TrackingStatus.Update>().map { it.location }
4343

44+
/**
45+
* Get the last known location on Android and iOS. On the web, it returns the current location.
46+
*
47+
* @param priority The priority of the location request.
48+
* @return A [GeolocatorResult] with the success or error state.
49+
*/
50+
public suspend fun lastLocation(priority: Priority = Priority.Balanced): GeolocatorResult
51+
52+
/**
53+
* Get the last known location on Android and iOS. On the web, it returns the current location.
54+
*
55+
* @param request The location request details.
56+
* @return A [GeolocatorResult] with the success or error state.
57+
*/
58+
public suspend fun lastLocation(request: LocationRequest): GeolocatorResult
59+
4460
/**
4561
* Check if location services are available.
4662
*

compass-geolocation/src/commonMain/kotlin/dev/jordond/compass/geolocation/Locator.kt

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,9 @@ public interface Locator {
2525
*/
2626
public val locationUpdates: Flow<Location>
2727

28+
29+
public suspend fun lastLocation(priority: Priority = Priority.Balanced): Location?
30+
2831
/**
2932
* Check if the platform supports geolocation.
3033
*/
@@ -86,6 +89,7 @@ public interface PermissionLocator : Locator {
8689
public object NotSupportedLocator : Locator {
8790

8891
override val locationUpdates: Flow<Location> = emptyFlow()
92+
override suspend fun lastLocation(priority: Priority): Location? = throw NotSupportedException()
8993
override suspend fun isAvailable(): Boolean = false
9094
override suspend fun current(priority: Priority): Location = throw NotSupportedException()
9195
override suspend fun track(request: LocationRequest): Flow<Location> = emptyFlow()

compass-geolocation/src/commonMain/kotlin/dev/jordond/compass/geolocation/internal/DefaultGeolocator.kt

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,12 @@ internal class DefaultGeolocator(
4343

4444
override val trackingStatus: Flow<TrackingStatus> = status
4545

46+
override suspend fun lastLocation(priority: Priority): GeolocatorResult =
47+
lastLocation(LocationRequest(priority))
48+
49+
override suspend fun lastLocation(request: LocationRequest): GeolocatorResult =
50+
handleResult(request) { locator.lastLocation(request.priority) }
51+
4652
override suspend fun isAvailable(): Boolean = locator.isAvailable()
4753

4854
override suspend fun current(request: LocationRequest): GeolocatorResult {

demo/composeApp/src/commonMain/kotlin/geolocation/GeolocationContent.kt

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ fun GeolocationContent(
2323
currentLocation: () -> Unit,
2424
startTracking: () -> Unit,
2525
stopTracking: () -> Unit,
26+
getLastLocation: () -> Unit,
2627
modifier: Modifier = Modifier,
2728
) {
2829
Column(
@@ -57,5 +58,16 @@ fun GeolocationContent(
5758
Text("Stop")
5859
}
5960
}
61+
62+
Spacer(modifier = Modifier.height(64.dp))
63+
64+
Text("Last Location")
65+
Text("Last known location: ${state.lastLocation}")
66+
67+
Row {
68+
Button(onClick = getLastLocation) {
69+
Text("Get Last Location")
70+
}
71+
}
6072
}
6173
}

demo/composeApp/src/commonMain/kotlin/geolocation/GeolocationModel.kt

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,13 @@ class GeolocationModel(private val geolocator: Geolocator) : StateScreenModel<St
3030
.launchIn(screenModelScope)
3131
}
3232

33+
fun getLastLocation() {
34+
screenModelScope.launch {
35+
val result = geolocator.lastLocation()
36+
updateState { it.copy(lastLocation = result) }
37+
}
38+
}
39+
3340
fun currentLocation() {
3441
screenModelScope.launch {
3542
updateState { it.copy(loading = true) }
@@ -55,6 +62,7 @@ class GeolocationModel(private val geolocator: Geolocator) : StateScreenModel<St
5562
val lastResult: GeolocatorResult? = null,
5663
val locationServiceAvailable: Boolean = false,
5764
val trackingLocation: TrackingStatus = TrackingStatus.Idle,
65+
val lastLocation: GeolocatorResult? = null,
5866
) {
5967

6068
val tracking = trackingLocation.isActive

demo/composeApp/src/commonMain/kotlin/geolocation/PlatformGeolocationScreen.kt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,7 @@ class PlatformGeolocationScreen : Screen {
6363
currentLocation = model::currentLocation,
6464
startTracking = model::startTracking,
6565
stopTracking = model::stopTracking,
66+
getLastLocation = model::getLastLocation,
6667
modifier = Modifier.padding(innerPadding),
6768
)
6869
}

0 commit comments

Comments
 (0)