kgoogle-map

Enables seamless integration of Google Maps functionalities in applications with a unified API, reducing platform-specific code. Offers map rendering, marker management, camera control, and Google Places suggestions.

Android JVMKotlin/Native
GitHub stars22
Open issues0
Creation dateover 1 year ago

Last activityabout 1 year ago
Latest release1.1.1 (about 1 year ago)

KGoogleMap

KGoogleMap provides a unified API that allows developers to implement Google Maps functionalities in both Android and iOS applications with minimal platform-specific code


Maven Central

KGoogleMap is available on mavenCentral().

Thumbnail

Install

implementation("io.github.the-best-is-best:kgoogle-map:1.1.1")

iOS Setup using SPM (Swift Package Manager)

Add the following line in your Package.swift file:

dependencies: [
    .package(url: "https://github.com/the-best-is-best/KGoogleMap.git", from: "1.1.0")
]

How to use it

First in iosMain

fun MainViewController(): UIViewController
{
    IOSKLocationServices().requestPermission()
    IOSKGoogleMap.init("YOUR GOOGLE MAP KEY")

    return ComposeUIViewController { App() }
}

Second in androidMain

AndroidKGoogleMap.initialization(this, "YOUR GOOGLE MAP KEY")
setContent {
    // add this
    KLocationService().ListenerToPermission()
    App()
}

In commonMain

@Composable
internal fun App() = AppTheme {
    val mapController = remember {
        KMapController(
            initPosition = LatLng(30.01306, 31.20885),
            zoom = 15f
        )
    }

    val viewModel by remember { mutableStateOf(GoogleMapViewModel()) }
    val scope = rememberCoroutineScope()

    if (viewModel.requestPermission) {
        KLocationService().EnableLocation()
        viewModel.requestPermission = false
    }

    Column(
        modifier = Modifier
            .fillMaxSize()
            .windowInsetsPadding(WindowInsets.safeDrawing)
            .padding(16.dp),
        horizontalAlignment = Alignment.CenterHorizontally
    ) {
        Column(modifier = Modifier.fillMaxSize()) {
            TypeAhead(
                itemsProvider = { query -> viewModel.onQueryChanged(query) },
                itemToString = { it.fullText },
                onItemSelected = {
                    scope.launch {
                        viewModel.getPlaceDetails(it.placeId, 1)
                    }
                }
            )

            Spacer(Modifier.height(10.dp))

            TypeAhead(
                itemsProvider = { query -> viewModel.onQueryChanged(query) },
                itemToString = { it.fullText },
                onItemSelected = {
                    scope.launch {
                        viewModel.getPlaceDetails(it.placeId, 2)
                    }
                }
            )

            Spacer(Modifier.height(10.dp))

            ElevatedButton(onClick = { viewModel.getRoad() }) {
                Text("Fetch Road")
            }

            Box(modifier = Modifier.fillMaxSize()) {
                KGoogleMapView(
                    controller = mapController,
                    onMapLoaded ={
                        println("map loaded")
                    },
                    onMapClick = {
                        println("click loc :${it}")
                    },
                    onMapLongClick = {
                        println("long click loc :${it}")
                    }
                )
            }
        }
    }
}

class GoogleMapViewModel : ViewModel() {
    private val googlePlaces = KPlacesHelper()
    var selectedAddress1: PlaceDetails? = null
        private set
    var selectedAddress2: PlaceDetails? = null
        private set
    var directions: DirectionsResponse? = null
        private set
    private val locationService = KLocationService()
    var isGPSEnabled by mutableStateOf(true)
        private set
    var requestPermission by mutableStateOf(false)

    init {
        viewModelScope.launch {
            locationService.gpsStateFlow().collect { gps ->
                isGPSEnabled = gps
            }
        }
    }

    suspend fun onQueryChanged(query: String): List<AutocompleteSuggestion> {
        return if (query.isNotEmpty()) {
            delay(500)
            fetchSuggestions(query)
        } else {
            emptyList()
        }
    }

    fun enableGPSAndLocation() {
        requestPermission = true
    }

    private suspend fun fetchSuggestions(query: String): List<AutocompleteSuggestion> {
        return withContext(Dispatchers.IO) {
            try {
                suspendCancellableCoroutine { continuation ->
                    googlePlaces.fetchSuggestions(query) { suggestions ->
                        continuation.resume(suggestions)
                    }
                }
            } catch (e: Exception) {
                emptyList()
            }
        }
    }

    suspend fun getPlaceDetails(placeId: String, searchId: Int) {
        withContext(Dispatchers.IO) {
            googlePlaces.fetchPlaceDetails(placeId, {
                if (searchId == 1) {
                    selectedAddress1 = it
                } else {
                    selectedAddress2 = it
                }
            })
        }
    }

    fun getRoad() {
        viewModelScope.launch {
            if (selectedAddress1 != null && selectedAddress2 != null) {
                val ktorServices = KtorServices()
                directions = ktorServices.getRoadPoints(
                    selectedAddress1!!.address!!,
                    selectedAddress2!!.address!!,
                )
            }
        }
    }
}
Android JVMKotlin/Native
GitHub stars22
Open issues0
Creation dateover 1 year ago

Last activityabout 1 year ago
Latest release1.1.1 (about 1 year ago)

KGoogleMap

KGoogleMap provides a unified API that allows developers to implement Google Maps functionalities in both Android and iOS applications with minimal platform-specific code


Maven Central

KGoogleMap is available on mavenCentral().

Thumbnail

Install

implementation("io.github.the-best-is-best:kgoogle-map:1.1.1")

iOS Setup using SPM (Swift Package Manager)

Add the following line in your Package.swift file:

dependencies: [
    .package(url: "https://github.com/the-best-is-best/KGoogleMap.git", from: "1.1.0")
]

How to use it

First in iosMain

fun MainViewController(): UIViewController
{
    IOSKLocationServices().requestPermission()
    IOSKGoogleMap.init("YOUR GOOGLE MAP KEY")

    return ComposeUIViewController { App() }
}

Second in androidMain

AndroidKGoogleMap.initialization(this, "YOUR GOOGLE MAP KEY")
setContent {
    // add this
    KLocationService().ListenerToPermission()
    App()
}

In commonMain

@Composable
internal fun App() = AppTheme {
    val mapController = remember {
        KMapController(
            initPosition = LatLng(30.01306, 31.20885),
            zoom = 15f
        )
    }

    val viewModel by remember { mutableStateOf(GoogleMapViewModel()) }
    val scope = rememberCoroutineScope()

    if (viewModel.requestPermission) {
        KLocationService().EnableLocation()
        viewModel.requestPermission = false
    }

    Column(
        modifier = Modifier
            .fillMaxSize()
            .windowInsetsPadding(WindowInsets.safeDrawing)
            .padding(16.dp),
        horizontalAlignment = Alignment.CenterHorizontally
    ) {
        Column(modifier = Modifier.fillMaxSize()) {
            TypeAhead(
                itemsProvider = { query -> viewModel.onQueryChanged(query) },
                itemToString = { it.fullText },
                onItemSelected = {
                    scope.launch {
                        viewModel.getPlaceDetails(it.placeId, 1)
                    }
                }
            )

            Spacer(Modifier.height(10.dp))

            TypeAhead(
                itemsProvider = { query -> viewModel.onQueryChanged(query) },
                itemToString = { it.fullText },
                onItemSelected = {
                    scope.launch {
                        viewModel.getPlaceDetails(it.placeId, 2)
                    }
                }
            )

            Spacer(Modifier.height(10.dp))

            ElevatedButton(onClick = { viewModel.getRoad() }) {
                Text("Fetch Road")
            }

            Box(modifier = Modifier.fillMaxSize()) {
                KGoogleMapView(
                    controller = mapController,
                    onMapLoaded ={
                        println("map loaded")
                    },
                    onMapClick = {
                        println("click loc :${it}")
                    },
                    onMapLongClick = {
                        println("long click loc :${it}")
                    }
                )
            }
        }
    }
}

class GoogleMapViewModel : ViewModel() {
    private val googlePlaces = KPlacesHelper()
    var selectedAddress1: PlaceDetails? = null
        private set
    var selectedAddress2: PlaceDetails? = null
        private set
    var directions: DirectionsResponse? = null
        private set
    private val locationService = KLocationService()
    var isGPSEnabled by mutableStateOf(true)
        private set
    var requestPermission by mutableStateOf(false)

    init {
        viewModelScope.launch {
            locationService.gpsStateFlow().collect { gps ->
                isGPSEnabled = gps
            }
        }
    }

    suspend fun onQueryChanged(query: String): List<AutocompleteSuggestion> {
        return if (query.isNotEmpty()) {
            delay(500)
            fetchSuggestions(query)
        } else {
            emptyList()
        }
    }

    fun enableGPSAndLocation() {
        requestPermission = true
    }

    private suspend fun fetchSuggestions(query: String): List<AutocompleteSuggestion> {
        return withContext(Dispatchers.IO) {
            try {
                suspendCancellableCoroutine { continuation ->
                    googlePlaces.fetchSuggestions(query) { suggestions ->
                        continuation.resume(suggestions)
                    }
                }
            } catch (e: Exception) {
                emptyList()
            }
        }
    }

    suspend fun getPlaceDetails(placeId: String, searchId: Int) {
        withContext(Dispatchers.IO) {
            googlePlaces.fetchPlaceDetails(placeId, {
                if (searchId == 1) {
                    selectedAddress1 = it
                } else {
                    selectedAddress2 = it
                }
            })
        }
    }

    fun getRoad() {
        viewModelScope.launch {
            if (selectedAddress1 != null && selectedAddress2 != null) {
                val ktorServices = KtorServices()
                directions = ktorServices.getRoadPoints(
                    selectedAddress1!!.address!!,
                    selectedAddress2!!.address!!,
                )
            }
        }
    }
}