Skip to content

Commit

Permalink
Update map center to use user's location at start if possible
Browse files Browse the repository at this point in the history
Part of #14
  • Loading branch information
AaroKoinsaari committed Sep 29, 2024
1 parent 0103e3a commit 90b8c4d
Show file tree
Hide file tree
Showing 2 changed files with 74 additions and 9 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
/*
* Copyright (c) 2024 Aaro Koinsaari
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package com.aarokoinsaari.accessibilitymap.utils

import android.location.Location
import android.util.Log
import com.google.android.gms.location.FusedLocationProviderClient
import com.google.android.gms.tasks.Tasks

@Suppress("TooGenericExceptionCaught")
fun FusedLocationProviderClient.getLastLocationSuspended(): Location? =
try {
Tasks.await(lastLocation)
} catch (e: SecurityException) {
Log.e("getLastLocationSuspended", "Location permission denied", e)
null
} catch (e: Exception) {
Log.e("getLastLocationSuspended", e.message, e)
null
}
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@

package com.aarokoinsaari.accessibilitymap.view.screens

import android.Manifest
import androidx.compose.animation.AnimatedVisibility
import androidx.compose.animation.fadeIn
import androidx.compose.animation.fadeOut
Expand Down Expand Up @@ -50,6 +51,7 @@ import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.layout.onGloballyPositioned
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.platform.LocalDensity
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.res.stringResource
Expand All @@ -71,10 +73,17 @@ import com.aarokoinsaari.accessibilitymap.model.WheelchairAccessStatus.PARTIALLY
import com.aarokoinsaari.accessibilitymap.model.WheelchairAccessStatus.UNKNOWN
import com.aarokoinsaari.accessibilitymap.state.MapState
import com.aarokoinsaari.accessibilitymap.utils.PlaceCategory
import com.aarokoinsaari.accessibilitymap.utils.getLastLocationSuspended
import com.aarokoinsaari.accessibilitymap.view.model.PlaceClusterItem
import com.google.accompanist.permissions.ExperimentalPermissionsApi
import com.google.accompanist.permissions.isGranted
import com.google.accompanist.permissions.rememberPermissionState
import com.google.android.gms.location.FusedLocationProviderClient
import com.google.android.gms.location.LocationServices
import com.google.android.gms.maps.CameraUpdateFactory
import com.google.android.gms.maps.model.CameraPosition
import com.google.android.gms.maps.model.LatLng
import com.google.maps.android.compose.CameraPositionState
import com.google.maps.android.compose.GoogleMap
import com.google.maps.android.compose.MapsComposeExperimentalApi
import com.google.maps.android.compose.clustering.Clustering
Expand All @@ -85,24 +94,36 @@ import kotlinx.coroutines.flow.distinctUntilChanged
import kotlinx.coroutines.flow.filter
import kotlinx.coroutines.launch

@OptIn(MapsComposeExperimentalApi::class)
@OptIn(MapsComposeExperimentalApi::class, ExperimentalPermissionsApi::class)
@Composable
fun MapScreen(
stateFlow: StateFlow<MapState>,
onIntent: (MapIntent) -> Unit = { }
) {
val vevey = LatLng(46.462, 6.841)
val state by stateFlow.collectAsState()
val context = LocalContext.current
val coroutineScope = rememberCoroutineScope()
val defaultLocation = LatLng(46.462, 6.841) // Vevey
val fusedLocationProviderClient = remember {
LocationServices.getFusedLocationProviderClient(context)
}
val locationPermissionState = rememberPermissionState(
permission = Manifest.permission.ACCESS_FINE_LOCATION
)
val cameraPositionState = rememberCameraPositionState {
position = CameraPosition.fromLatLngZoom(
state.center ?: vevey, state.zoomLevel ?: 10f
state.center ?: defaultLocation, state.zoomLevel ?: 10f
)
}
// For remembering the state when the screen is rotated for example
var showNotification by rememberSaveable { mutableStateOf(true) }

LaunchedEffect(cameraPositionState) {
LaunchedEffect(locationPermissionState.status.isGranted, cameraPositionState) {
if (locationPermissionState.status.isGranted) {
moveCameraToUserLocation(fusedLocationProviderClient, cameraPositionState)
}

// Track map movement and update state
snapshotFlow { cameraPositionState.position }
.distinctUntilChanged()
.collect { position ->
Expand All @@ -118,19 +139,18 @@ fun MapScreen(
}

// Notification is shown for either 5 seconds or until user moves the map
LaunchedEffect(Unit) {
delay(5000L)
if (showNotification) {
LaunchedEffect(cameraPositionState, showNotification) {
val delayJob = launch {
delay(5000L)
showNotification = false
}
}

LaunchedEffect(cameraPositionState) {
snapshotFlow { cameraPositionState.isMoving }
.filter { it }
.collect {
if (showNotification) {
showNotification = false
delayJob.cancel()
}
}
}
Expand Down Expand Up @@ -365,6 +385,17 @@ fun NotificationBar(
}
}

private fun moveCameraToUserLocation(
fusedLocationProviderClient: FusedLocationProviderClient,
cameraPositionState: CameraPositionState
) {
val location = fusedLocationProviderClient.getLastLocationSuspended()
location?.let {
val userLatLng = LatLng(it.latitude, it.longitude)
cameraPositionState.move(CameraUpdateFactory.newLatLngZoom(userLatLng, 15f))
}
}

private fun WheelchairAccessStatus.getWheelchairAccessibilityStatusStringRes(): Int =
when (this) {
FULLY_ACCESSIBLE -> R.string.wheelchair_access_fully_accessible
Expand Down

0 comments on commit 90b8c4d

Please sign in to comment.