Created
September 3, 2020 16:11
-
-
Save wangerekaharun/1d664bf8b4efa1a3091e2622f72da4e1 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package ke.co.appslab.bring.ui.views.fragments | |
import android.Manifest | |
import android.annotation.SuppressLint | |
import android.app.Activity.RESULT_CANCELED | |
import android.app.Activity.RESULT_OK | |
import android.content.Intent | |
import android.content.IntentSender | |
import android.content.pm.PackageManager | |
import android.net.Uri | |
import android.os.Bundle | |
import android.os.Looper | |
import android.provider.Settings | |
import android.util.Log | |
import android.view.View | |
import androidx.core.app.ActivityCompat | |
import androidx.fragment.app.Fragment | |
import androidx.lifecycle.Lifecycle | |
import androidx.lifecycle.OnLifecycleEvent | |
import androidx.navigation.fragment.findNavController | |
import com.google.android.gms.common.api.ApiException | |
import com.google.android.gms.common.api.ResolvableApiException | |
import com.google.android.gms.location.* | |
import com.google.android.gms.maps.CameraUpdateFactory | |
import com.google.android.gms.maps.GoogleMap | |
import com.google.android.gms.maps.OnMapReadyCallback | |
import com.google.android.gms.maps.SupportMapFragment | |
import com.google.android.gms.maps.model.LatLng | |
import ke.co.appslab.bring.BuildConfig | |
import ke.co.appslab.bring.R | |
import ke.co.appslab.bring.data.models.geoaddress.AddressResponse | |
import ke.co.appslab.bring.ui.viewmodels.AddressViewModel | |
import ke.co.appslab.bring.utils.NetworkResult | |
import ke.co.appslab.bring.utils.createLocationRequest | |
import ke.co.appslab.bring.utils.toast | |
import org.koin.androidx.viewmodel.ext.android.viewModel | |
class MapFragment : Fragment(R.layout.fragment_map), OnMapReadyCallback { | |
private val locationRequest: LocationRequest by lazy { | |
createLocationRequest() | |
} | |
private val fusedLocationProviderClient: FusedLocationProviderClient by lazy { | |
LocationServices.getFusedLocationProviderClient(requireContext()) | |
} | |
private val settingsClient: SettingsClient by lazy { | |
LocationServices.getSettingsClient(requireActivity()) | |
} | |
private lateinit var locationSettingsRequest: LocationSettingsRequest | |
private lateinit var locationCallback: LocationCallback | |
private lateinit var googleMap: GoogleMap | |
private val addressViewModel: AddressViewModel by viewModel() | |
override fun onViewCreated(view: View, savedInstanceState: Bundle?) { | |
super.onViewCreated(view, savedInstanceState) | |
val mapFragment = childFragmentManager | |
.findFragmentById(R.id.mapFragment) as SupportMapFragment | |
mapFragment.getMapAsync(this) | |
createLocationCallback() | |
createLocationRequest() | |
buildLocationSettingsRequest() | |
observeAddressResponse() | |
receiveLocationUpdates() | |
} | |
private fun observeAddressResponse() { | |
addressViewModel.addressResponse.observe(viewLifecycleOwner) { addressReponse -> | |
when (addressReponse) { | |
is NetworkResult.Success -> showBottomSheet(addressReponse.data) | |
is NetworkResult.Error -> requireActivity().toast(addressReponse.exception.localizedMessage) | |
} | |
} | |
} | |
private fun showBottomSheet(addressResponse: AddressResponse?) { | |
addressResponse?.let { | |
val locationDetailsAction = | |
MapFragmentDirections.actionMapFragmentToLocationDetailsFragment(it) | |
findNavController().navigate(locationDetailsAction) | |
} | |
} | |
override fun onMapReady(map: GoogleMap) { | |
googleMap = map | |
googleMap.uiSettings.isCompassEnabled = false | |
googleMap.apply { | |
uiSettings.isCompassEnabled = false | |
uiSettings.isMyLocationButtonEnabled = true | |
} | |
receiveLocationUpdates() | |
} | |
private fun buildLocationSettingsRequest() { | |
val builder = LocationSettingsRequest.Builder() | |
builder.addLocationRequest(locationRequest) | |
locationSettingsRequest = builder.build() | |
} | |
private fun receiveLocationUpdates() { | |
when { | |
checkPermissions() -> startLocationUpdates() | |
!checkPermissions() -> requestPermissions() | |
} | |
} | |
private fun checkPermissions(): Boolean { | |
val permissionState = ActivityCompat.checkSelfPermission( | |
requireActivity(), | |
Manifest.permission.ACCESS_FINE_LOCATION | |
); | |
return permissionState == PackageManager.PERMISSION_GRANTED; | |
} | |
private fun requestPermissions() { | |
val shouldProvideRationale = ActivityCompat.shouldShowRequestPermissionRationale( | |
requireActivity(), | |
Manifest.permission.ACCESS_FINE_LOCATION | |
) | |
// Provide an additional rationale to the user. This would happen if the user denied the | |
// request previously, but didn't check the "Don't ask again" checkbox. | |
if (!shouldProvideRationale) { | |
ActivityCompat.requestPermissions( | |
requireActivity(), | |
arrayOf(Manifest.permission.ACCESS_FINE_LOCATION), | |
REQUEST_PERMISSIONS_REQUEST_CODE | |
) | |
} | |
} | |
@SuppressLint("MissingPermission") | |
private fun startLocationUpdates() { | |
settingsClient.checkLocationSettings(locationSettingsRequest) | |
.addOnSuccessListener(requireActivity()) { | |
fusedLocationProviderClient.requestLocationUpdates( | |
locationRequest, | |
locationCallback, Looper.myLooper() | |
) | |
} | |
.addOnFailureListener(requireActivity()) { e -> | |
when ((e as ApiException).statusCode) { | |
LocationSettingsStatusCodes.RESOLUTION_REQUIRED -> { | |
try { | |
// Show the dialog by calling startResolutionForResult(), and check the | |
// result in onActivityResult(). | |
val rae = e as ResolvableApiException | |
rae.startResolutionForResult(requireActivity(), REQUEST_CHECK_SETTINGS) | |
} catch (sie: IntentSender.SendIntentException) { | |
Log.i("MapFragment", "PendingIntent unable to execute request.") | |
} | |
} | |
LocationSettingsStatusCodes.SETTINGS_CHANGE_UNAVAILABLE -> { | |
val errorMessage = | |
"Location settings are inadequate, and cannot be " + "fixed here. Fix in Settings." | |
requireContext().toast(errorMessage) | |
} | |
} | |
} | |
} | |
private fun createLocationCallback() { | |
locationCallback = object : LocationCallback() { | |
override fun onLocationResult(locationResult: LocationResult) { | |
locationResult.locations.forEach { | |
val currentLatLng = LatLng(it.latitude, it.longitude) | |
googleMap.animateCamera( | |
CameraUpdateFactory.newLatLngZoom( | |
currentLatLng, | |
DEFAULT_ZOOM.toFloat() | |
) | |
) | |
googleMap.setOnCameraIdleListener { | |
//enable google map scroll | |
googleMap.uiSettings.isScrollGesturesEnabled = true | |
val positionLatLng = googleMap.cameraPosition.target | |
val addressLatLng = | |
positionLatLng.latitude.toString() + "," + positionLatLng.longitude.toString() | |
// get address | |
getAddress(addressLatLng) | |
} | |
} | |
} | |
} | |
} | |
private fun getAddress(addressLatLng: String) { | |
addressViewModel.fetchAddress(addressLatLng, getString(R.string.google_maps_key)) | |
} | |
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) { | |
when (requestCode) { | |
REQUEST_CHECK_SETTINGS -> { | |
when (resultCode) { | |
RESULT_OK -> { | |
requireActivity().toast("Permissions!") | |
receiveLocationUpdates() | |
} | |
RESULT_CANCELED -> { | |
requireActivity().toast("Permission Denied!") | |
} | |
} | |
} | |
} | |
super.onActivityResult(requestCode, resultCode, data) | |
} | |
override fun onRequestPermissionsResult( | |
requestCode: Int, | |
permissions: Array<out String>, | |
grantResults: IntArray | |
) { | |
if (requestCode == REQUEST_PERMISSIONS_REQUEST_CODE) { | |
when { | |
grantResults.isEmpty() -> // If user interaction was interrupted, the permission request is cancelled and you | |
// receive empty arrays. | |
Log.i("MapFragment", "User interaction was cancelled.") | |
grantResults[0] == PackageManager.PERMISSION_GRANTED -> { | |
Log.i( | |
"MapFragment", | |
"Permission granted, updates requested, starting location updates" | |
) | |
startLocationUpdates() | |
requireActivity().toast("Permissions!") | |
} | |
else -> { | |
// Permission denied. | |
val intent = Intent() | |
intent.action = Settings.ACTION_APPLICATION_DETAILS_SETTINGS | |
val uri = Uri.fromParts( | |
"package", | |
BuildConfig.APPLICATION_ID, null | |
) | |
intent.data = uri | |
intent.flags = Intent.FLAG_ACTIVITY_NEW_TASK | |
startActivity(intent) | |
} | |
} | |
} | |
super.onRequestPermissionsResult(requestCode, permissions, grantResults) | |
} | |
@OnLifecycleEvent(Lifecycle.Event.ON_PAUSE) | |
fun stopLocationUpdates() { | |
fusedLocationProviderClient.removeLocationUpdates(locationCallback) | |
.addOnCompleteListener(requireActivity()) { | |
} | |
} | |
companion object { | |
const val REQUEST_PERMISSIONS_REQUEST_CODE = 30 | |
const val REQUEST_CHECK_SETTINGS = 0x1 | |
const val DEFAULT_ZOOM = 17 | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment