Coder Social home page Coder Social logo

jordond / compass Goto Github PK

View Code? Open in Web Editor NEW
161.0 161.0 8.0 1.45 MB

🧭 Kotlin Multiplatform library location toolkit for geocoding and geolocation

Home Page: https://compass.jordond.dev

License: MIT License

Kotlin 100.00%
compose compose-multiplatform geocoder geolocation kotlin kotlin-multiplatform location

compass's People

Contributors

cristan avatar jordond avatar renovate[bot] avatar writtmeyer avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar

compass's Issues

The badges in the readme don't match the versions you are using

The most minor issue you'll ever have, but the badges in your readme don't show the correct version. Kotlin is stating 1.9.23 while you are using 2.0.20. Compose Multiplatform states 1.6.1 while you are using 1.6.11. This makes your project look less well maintained than it actually is.

These versions of dependencies are automatically updated via a bot, but these bots don't update the readme.

So either change the bots that they update the readme as well, or just don't show version numbers in your badges (so go for https://img.shields.io/badge/kotlin-blue.svg?logo=kotlin and https://img.shields.io/badge/Compose%20Multiplatform-blue ).

GeoLocationFailed: Parameter specified as non-null is null

The library works fine on my emulator, but on my real device, I get a GeoLocationFailed with the message: Parameter specified as non-null is null: method dev.jordond.compass.geolocation.mobile.internal.MapperKt.toModel, parameter <this>

This happens here:

override suspend fun current(priority: Priority): Location {
    requirePermission(priority)
    return locationManager.currentLocation(priority.toAndroidPriority).toModel()
}

locationManager.currentLocation(priority.toAndroidPriority) is null, hence the toModel() crashing. This is because fusedLocationClient.addOnSuccessListener is triggered with null as its value:

location null

The big question is why this location is null while Kotlin thinks location is of type Location!. This only happened after when requesting a coarse location when no other app recently retrieved a valid location. Before null is returned, it will try to load the location for quite a long time.

The thing is, Kotlin (or more likely the annotations) is wrong. If you check out the docs, you'll see that null can be returned in the success listener:

If unable to retrieve a current location fix before timing out, null will be returned.

This apparently happens quite often when using the coarse location (issue).

You should handle this instead of crashing and returning the crash as the message.

Geolocator.isAvailable is a suspend fun

I could be missing something, but any reason why Geolocator.isAvailable is a suspend fun?

It's implemented in DefaultGeolocator:

override suspend fun isAvailable(): Boolean = withContext(dispatcher) {
    locator.isAvailable()
}

But locator.isAvailable() isn't a suspend fun, so isAvailable doesn't have to either. I think making this function not a suspend fun makes it quite a bit more usable: you can then quickly check if the GPS is turned off without having to bother with launching a coroutine.

I have created a PR, but I'm not sure if I'm missing a reason why the code works the way it does.

Update version.sh script to update version in docs/

Currently in docs/ there are a some pages that reference the version number. The value is set to 1.0.0, with the maven central badge above it.

However the version.sh script should be modified to also update any pages in docs/ that contains the version number.

[iOS] Exception when toggling "Precise Location" from device settings

Hello! I'm seeing a crash in the demo app, when I toggle off the "Precise Location" settings.

Steps to reproduce:

  1. Run app
  2. Tap "Platform" Button under Geolocation
  3. Tap "Get Current Location" Button
  4. Select "Allow While Using The App"
  5. Minimize App
  6. Go to Settings > Apps > demo > Location
  7. Toggle "Precise Location" off

Actual Result: App crashes
Expected Result: App does not crash

Screen recording:
Simulator Screen Recording - iPhone 15 Pro - 2024-06-20 at 15 05 02

Error Message:

Uncaught Kotlin exception: kotlin.IllegalStateException: Already resumed
    at 0   demo.debug.dylib                    0x108d6614f        kfun:kotlin.Throwable#<init>(kotlin.String?){} + 119 
    at 1   demo.debug.dylib                    0x108d5f7c7        kfun:kotlin.Exception#<init>(kotlin.String?){} + 115 
    at 2   demo.debug.dylib                    0x108d5f9e7        kfun:kotlin.RuntimeException#<init>(kotlin.String?){} + 115 
    at 3   demo.debug.dylib                    0x108d5ff87        kfun:kotlin.IllegalStateException#<init>(kotlin.String?){} + 115 
    at 4   demo.debug.dylib                    0x108d6d57f        kfun:kotlin.coroutines.SafeContinuation#resumeWith(kotlin.Result<1:0>){} + 739 
    at 5   demo.debug.dylib                    0x108e95e37        kfun:kotlin.coroutines.Continuation#resumeWith(kotlin.Result<1:0>){}-trampoline + 99 
    at 6   demo.debug.dylib                    0x10825d777        kfun:dev.jordond.compass.permissions.IosLocationPermissionController.requirePermissionFor$lambda$1#internal + 351 
    at 7   demo.debug.dylib                    0x10825d98b        kfun:dev.jordond.compass.permissions.IosLocationPermissionController.$requirePermissionFor$lambda$1$FUNCTION_REFERENCE$1.invoke#internal + 87 
    at 8   demo.debug.dylib                    0x10825da8f        kfun:dev.jordond.compass.permissions.IosLocationPermissionController.$requirePermissionFor$lambda$1$FUNCTION_REFERENCE$1.$<bridge-UNNB>invoke(kotlin.Int){}#internal + 123 
    at 9   demo.debug.dylib                    0x108e9126b        kfun:kotlin.Function1#invoke(1:0){}1:1-trampoline + 107 
    at 10  demo.debug.dylib                    0x10825e943        kfun:dev.jordond.compass.permissions.mobile.internal.LocationPermissionManagerDelegate#objc:locationManagerDidChangeAuthorization: + 363 
    at 11  demo.debug.dylib                    0x10825ec13        _636f6d706173733a636f6d706173732d7065726d697373696f6e732d6d6f62696c652f55736572732f6e6174616c69652f446f63756d656e74732f4769744875622f636f6d706173732f636f6d706173732d7065726d697373696f6e732d6d6f62696c652f7372632f696f734d61696e2f6b6f746c696e2f6465762f6a6f72646f6e642f636f6d706173732f7065726d697373696f6e732f6d6f62696c652f696e7465726e616c2f4c6f636174696f6e5065726d697373696f6e4d616e6167657244656c65676174652e6b74_knbridge14 + 183 
    at 12  CoreLocation                        0x1844b3633        CLClientStopVehicleHeadingUpdates + 103707 
    at 13  CoreLocation                        0x1844b2e47        CLClientStopVehicleHeadingUpdates + 101679 
    at 14  CoreLocation                        0x1844927ff        CLClientCreateWithBundleIdentifierAndPathWithWebsiteOnSilo + 6135 
    at 15  LocationSupport                     0x18baa341b        _ZN18CLConnectionServer13handleMessageEP12CLConnectionNSt3__110shared_ptrI19CLConnectionMessageEE + 18399 
    at 16  CoreFoundation                      0x1804108e3        __CFRUNLOOP_IS_CALLING_OUT_TO_A_BLOCK__ + 19 
    at 17  CoreFoundation                      0x180410027        __CFRunLoopDoBlocks + 351 
    at 18  CoreFoundation                      0x18040aeef        __CFRunLoopRun + 2379 
    at 19  CoreFoundation                      0x18040a173        CFRunLoopRunSpecific + 571 
    at 20  GraphicsServices                    0x19050cb0f        GSEventRunModal + 159 
    at 21  UIKitCore                           0x185a0287b        -[UIApplication _run] + 867 
    at 22  UIKitCore                           0x185a06467        UIApplicationMain + 123 
    at 23  SwiftUI                             0x1c31edff3        $s7SwiftUI17KitRendererCommon33_ACC2C5639A7D76F611E170E831FCA491LLys5NeverOyXlXpFAESpySpys4Int8VGSgGXEfU_ + 163 
    at 24  SwiftUI                             0x1c31ede9b        $s7SwiftUI6runAppys5NeverOxAA0D0RzlF + 83 
    at 25  SwiftUI                             0x1c2f63f5b        $s7SwiftUI3AppPAAE4mainyyFZ + 147 
    at 26  demo.debug.dylib                    0x10821d86f        $s4demo6iOSAppV5$mainyyFZ + 39 
    at 27  demo.debug.dylib                    0x10821d91f        __debug_main_executable_dylib_entry_point + 11 (/Users/natalie/Documents/GitHub/compass/demo/iosApp/iosApp/iOSApp.swift:4:8)
    at 28  dyld                                0x102fc140f        0x0 + 4345041935 
    at 29  ???                                 0x10293a0df        0x0 + 4338196703 
    at 30  ???                                 0x35f7fffffffffff  0x0 + 243053642389651455 

Unclear what PermissionError does

It's unclear what PermissionError does. The docs say:

Geocoding operation failed because of a permission error.

Either the user denied the permission, or the permission was denied forever.

But that's already what PermissionDenied is for. It even has a forever boolean.

So let's look at the code. It's caused by either one of these exceptions:

  • PermissionMissingException
    • This isn't used at all, thus it can simply be deleted.
  • PermissionRequestException
    • This only happens when the WeakReference requester is null at ActivityProvider. Seems like very much an unexpected error.

I would delete PermissionMissingException, PermissionRequestException and the entire PermissionError. In order to do so, I would throw an IllegalStateException in ActivityProvider instead. This makes your library quite a bit easier: right now it's quite confusing to see the difference between PermissionError and PermissionDenied.

Crash on no location found

Funny story about my PR you merged which was released in 1.2.1..

Yeah, that one now causes compass to crash, sorry. See the attached PR: I think that should fix it.

A semi-related thing: this is the only place where NotFoundException() is thrown, so this is the only place where GeocoderResult.NotFound is returned. Seems odd: you'd expect this to be thrown at the other platforms as well. Create a new issue for that?

[iOS] location settings - permission granularity

The current implementation of the library mandates that the user is prompted for "Always" authorization. It'd be great if we could have more control from the library in selecting what level of permissions we want to prompt the user with. We don't have a strong need to always be tracking the user, and would like to track them only when they're using the app.

Background Location Tracking

Hey there, awesome library!

Do you guys know, how to keep receiving location updates in kmp, while the app is running in the background?
Best regards, and thank you so much for your amazing work!

Support OpenCage out-of-the-box

It's great that we can implement our own API, but I think you should also support OpenCage as an very popular provider out of the box.

Build Project Failed after add dependency

After adding these dependency to my project

libs.version.toml :

compass = "0.1.8"
compass-geocoder = { module = "dev.jordond.compass:compass-geocoder", version.ref = "compass" }
compass-geocoder-mobile = { module = "dev.jordond.compass:compass-geocoder-mobile", version.ref = "compass" }
compass-geocoder-web-googlemaps = { module = "dev.jordond.compass:compass-geocoder-googlemaps", version.ref = "compass" }

build.gradle.kts :

val commonMain by getting {
            dependencies {
                api(libs.decompose.router)
                implementation(libs.compass.geocoder)
                implementation(libs.compass.geocoder.web.googlemaps)
..

val mobileMain by creating {
            dependsOn(commonMain)
            androidMain.dependsOn(this)
            iosMain.dependsOn(this)
            dependencies {
                implementation(libs.compass.geocoder.mobile)
            }
        }

build project was failed with this log report

Execution failed for task ':composeApp:transformIosMainCInteropDependenciesMetadataForIde'.

Could not resolve all files for configuration ':composeApp:iosMainResolvableDependenciesMetadata'.
Could not find dev.jordond.compass:compass-geocoder-googlemaps:0.1.8.
Required by:
project :composeApp

perhaps anybody know the cause or fix for this issue

Dependency Dashboard

This issue lists Renovate updates and detected dependencies. Read the Dependency Dashboard docs to learn more.


Warning

Renovate failed to look up the following dependencies: Failed to look up maven package convention.multiplatform:convention.multiplatform.gradle.plugin.

Files affected: gradle/libs.versions.toml


Ignored or Blocked

These are blocked by an existing closed PR and will not be recreated unless you click a checkbox below.

Detected dependencies

github-actions
.github/workflows/ci.yml
  • actions/checkout v4
  • actions/setup-java v4
  • gradle/actions v4
  • gradle/actions v4
  • actions/checkout v4
  • actions/setup-java v4
  • actions/cache v4
  • gradle/actions v4
  • gradle/actions v4
  • actions/checkout v4
  • actions/setup-java v4
  • gradle/actions v4
  • gradle/actions v4
  • browser-actions/setup-chrome v1
.github/workflows/publish.yml
  • actions/checkout v4
  • actions/setup-java v4
  • gradle/actions v4
  • gradle/actions v4
  • actions/checkout v4
  • actions/setup-java v4
  • gradle/actions v4
  • gradle/actions v4
  • JamesIves/github-pages-deploy-action v4
gradle
gradle.properties
settings.gradle.kts
  • com.gradle.develocity 3.18
build.gradle.kts
buildLogic/gradle.properties
buildLogic/settings.gradle.kts
buildLogic/convention/build.gradle.kts
compass-autocomplete/build.gradle.kts
compass-autocomplete-geocoder-googlemaps/build.gradle.kts
compass-autocomplete-geocoder-mapbox/build.gradle.kts
compass-autocomplete-mobile/build.gradle.kts
compass-autocomplete-web/build.gradle.kts
compass-core/build.gradle.kts
compass-geocoder/build.gradle.kts
compass-geocoder-mobile/build.gradle.kts
compass-geocoder-web/build.gradle.kts
compass-geocoder-web-googlemaps/build.gradle.kts
compass-geocoder-web-mapbox/build.gradle.kts
compass-geocoder-web-opencage/build.gradle.kts
compass-geocoder-web-template/build.gradle.kts
compass-geolocation/build.gradle.kts
compass-geolocation-browser/build.gradle.kts
compass-geolocation-mobile/build.gradle.kts
compass-permissions/build.gradle.kts
compass-permissions-mobile/build.gradle.kts
compass-tools-android/build.gradle.kts
compass-tools-web/build.gradle.kts
demo/composeApp/build.gradle.kts
gradle/libs.versions.toml
  • androidx.activity:activity-compose 1.9.1
  • androidx.activity:activity-ktx 1.9.1
  • androidx.fragment:fragment-ktx 1.8.2
  • androidx.startup:startup-runtime 1.1.1
  • org.jetbrains.kotlinx:atomicfu 0.25.0
  • org.jetbrains.kotlinx:kotlinx-serialization-json 1.7.2
  • io.ktor:ktor-client-core 3.0.0-wasm2
  • io.ktor:ktor-client-okhttp 3.0.0-wasm2
  • io.ktor:ktor-client-android 3.0.0-wasm2
  • io.ktor:ktor-client-darwin 3.0.0-wasm2
  • io.ktor:ktor-client-js 3.0.0-wasm2
  • io.ktor:ktor-client-content-negotiation 3.0.0-wasm2
  • io.ktor:ktor-client-logging 3.0.0-wasm2
  • io.ktor:ktor-serialization-kotlinx-json 3.0.0-wasm2
  • androidx.compose.ui:ui-tooling 1.6.8
  • androidx.compose.ui:ui-tooling-preview 1.6.8
  • io.kotest:kotest-assertions-core 5.9.1
  • co.touchlab:kermit 2.0.4
  • com.google.android.gms:play-services-location 21.3.0
  • dev.stateholder:core 1.2.0
  • dev.stateholder:extensions-compose 1.2.0
  • dev.stateholder:extensions-voyager 1.2.0
  • cafe.adriel.voyager:voyager-navigator 1.1.0-beta02
  • cafe.adriel.voyager:voyager-screenmodel 1.1.0-beta02
  • com.android.tools.build:gradle 8.6.0
  • org.jetbrains.kotlin:kotlin-gradle-plugin 2.0.20
  • org.jetbrains.compose:compose-gradle-plugin 1.6.11
  • com.vanniktech:gradle-maven-publish-plugin 0.29.0
  • org.jetbrains.kotlin.multiplatform 2.0.20
  • org.jetbrains.compose 1.6.11
  • org.jetbrains.kotlin.plugin.compose 2.0.20
  • com.android.library 8.6.0
  • com.android.application 8.6.0
  • org.jetbrains.kotlin.android 2.0.20
  • org.jetbrains.kotlin.plugin.serialization 2.0.20
  • com.github.ben-manes.versions 0.51.0
  • org.jetbrains.kotlinx.binary-compatibility-validator 0.16.3
  • org.jetbrains.dokka 1.9.20
  • com.vanniktech.maven.publish 0.29.0
  • dev.drewhamilton.poko 0.17.0
  • convention.multiplatform 0
gradle-wrapper
gradle/wrapper/gradle-wrapper.properties
  • gradle 8.10

  • Check this box to trigger a request for Renovate to run again on this repository

[iOS] Permission dialog is not shown

First of all, thanks for making such an amazing library, I've been trying it out and it works very well. :)

One issue that I've noticed is that the location permission dialog is not shown when I launch the app on iOS. On Android it works fine. Maybe I'm missing some additional steps? I've included those two location strings in my plist.info file btw.

I'm also testing the app on my real iOS device (iPhone 15 Pro Max).

Here's my code:

@Composable
fun LocationTracking() {
    val scope = rememberCoroutineScope()
    val geoLocator = remember { Geolocator.mobile() }

    val trackingStatus by geoLocator.trackingStatus
        .collectAsState(initial = null)

    var currentLocation: Coordinates? by remember {
        mutableStateOf(null)
    }

    var currentCity: String? by remember {
        mutableStateOf(null)
    }

    LaunchedEffect(Unit) {
        geoLocator.trackingStatus.collectLatest { status ->
            when (status) {
                is TrackingStatus.Idle -> {}
                is TrackingStatus.Tracking -> {}
                is TrackingStatus.Update -> {}
                is TrackingStatus.Error -> {
                    val error: GeolocatorResult.Error = status.cause
                    println("TRACKING ERROR: $error")
                    // Show the permissions settings screen
                    val permissionDeniedForever = error.isPermissionDeniedForever()
                    println("TRACKING PERMISSION DENIED: $permissionDeniedForever")
                }
            }
        }
    }

    LaunchedEffect(Unit) {
        geoLocator.locationUpdates.collectLatest {
            currentLocation = it.coordinates
            currentCity = MobileGeocoder().placeOrNull(it.coordinates)?.locality
        }
    }

    Text(
        modifier = Modifier.fillMaxWidth(),
        textAlign = TextAlign.Center,
        text = currentCity ?: "Waiting..."
    )
    Spacer(modifier = Modifier.height(12.dp))
    Text(
        modifier = Modifier.fillMaxWidth(),
        textAlign = TextAlign.Center,
        text = "LAT: ${currentLocation?.latitude}\nLNG: ${currentLocation?.longitude}"
    )
    Spacer(modifier = Modifier.height(20.dp))
    Row(
        modifier = Modifier.fillMaxWidth(),
        verticalAlignment = Alignment.CenterVertically,
        horizontalArrangement = Arrangement.Center
    ) {
        Button(
            enabled = trackingStatus == TrackingStatus.Idle,
            onClick = {
                scope.launch(Dispatchers.IO) {
                    geoLocator.startTracking(
                        LocationRequest(
                            priority = Priority.HighAccuracy
                        )
                    )
                }
            }
        ) {
            Text(text = "Start")
        }
        Spacer(modifier = Modifier.width(20.dp))
        Button(
            enabled = trackingStatus != TrackingStatus.Idle,
            onClick = {
                scope.launch(Dispatchers.IO) {
                    geoLocator.stopTracking()
                    currentLocation = null
                    currentCity = null
                }
            }
        ) {
            Text(text = "Stop")
        }
    }
}

And this is the log that I'm seeing:

fopen failed for data file: errno = 2 (No such file or directory)
Errors found! Invalidating cache...
fopen failed for data file: errno = 2 (No such file or directory)
Errors found! Invalidating cache...

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.