mirror of
https://github.com/SchildiChat/SchildiChat-android.git
synced 2024-11-24 02:15:46 +03:00
Adding button to get user current location in static location sharing preview
This commit is contained in:
parent
a3a616d8df
commit
d23636900f
9 changed files with 175 additions and 13 deletions
|
@ -0,0 +1,32 @@
|
|||
/*
|
||||
* Copyright (c) 2023 New Vector Ltd
|
||||
*
|
||||
* 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 im.vector.app.features.location
|
||||
|
||||
import androidx.fragment.app.Fragment
|
||||
import com.google.android.material.dialog.MaterialAlertDialogBuilder
|
||||
import im.vector.app.R
|
||||
|
||||
fun Fragment.showUserLocationNotAvailableErrorDialog(onConfirmListener: () -> Unit) {
|
||||
MaterialAlertDialogBuilder(requireActivity())
|
||||
.setTitle(R.string.location_not_available_dialog_title)
|
||||
.setMessage(R.string.location_not_available_dialog_content)
|
||||
.setPositiveButton(R.string.ok) { _, _ ->
|
||||
onConfirmListener()
|
||||
}
|
||||
.setCancelable(false)
|
||||
.show()
|
||||
}
|
|
@ -176,14 +176,7 @@ class LocationSharingFragment :
|
|||
}
|
||||
|
||||
private fun handleLocationNotAvailableError() {
|
||||
MaterialAlertDialogBuilder(requireActivity())
|
||||
.setTitle(R.string.location_not_available_dialog_title)
|
||||
.setMessage(R.string.location_not_available_dialog_content)
|
||||
.setPositiveButton(R.string.ok) { _, _ ->
|
||||
locationSharingNavigator.quit()
|
||||
}
|
||||
.setCancelable(false)
|
||||
.show()
|
||||
showUserLocationNotAvailableErrorDialog { locationSharingNavigator.quit() }
|
||||
}
|
||||
|
||||
private fun handleLiveLocationSharingNotEnoughPermission() {
|
||||
|
|
|
@ -90,6 +90,7 @@ class LocationTracker @Inject constructor(
|
|||
|
||||
@RequiresPermission(anyOf = [Manifest.permission.ACCESS_COARSE_LOCATION, Manifest.permission.ACCESS_FINE_LOCATION])
|
||||
fun start() {
|
||||
// TODO start only if not already started
|
||||
Timber.d("start()")
|
||||
|
||||
if (locationManager == null) {
|
||||
|
|
|
@ -20,4 +20,5 @@ import im.vector.app.core.platform.VectorViewModelAction
|
|||
|
||||
sealed class LocationPreviewAction : VectorViewModelAction {
|
||||
object ShowMapLoadingError : LocationPreviewAction()
|
||||
object ZoomToUserLocation : LocationPreviewAction()
|
||||
}
|
||||
|
|
|
@ -31,13 +31,18 @@ import dagger.hilt.android.AndroidEntryPoint
|
|||
import im.vector.app.R
|
||||
import im.vector.app.core.platform.VectorBaseFragment
|
||||
import im.vector.app.core.platform.VectorMenuProvider
|
||||
import im.vector.app.core.utils.PERMISSIONS_FOR_FOREGROUND_LOCATION_SHARING
|
||||
import im.vector.app.core.utils.checkPermissions
|
||||
import im.vector.app.core.utils.onPermissionDeniedDialog
|
||||
import im.vector.app.core.utils.openLocation
|
||||
import im.vector.app.core.utils.registerForPermissionsResult
|
||||
import im.vector.app.databinding.FragmentLocationPreviewBinding
|
||||
import im.vector.app.features.home.room.detail.timeline.helper.LocationPinProvider
|
||||
import im.vector.app.features.location.DEFAULT_PIN_ID
|
||||
import im.vector.app.features.location.LocationSharingArgs
|
||||
import im.vector.app.features.location.MapState
|
||||
import im.vector.app.features.location.UrlMapProvider
|
||||
import im.vector.app.features.location.showUserLocationNotAvailableErrorDialog
|
||||
import java.lang.ref.WeakReference
|
||||
import javax.inject.Inject
|
||||
|
||||
|
@ -78,6 +83,28 @@ class LocationPreviewFragment :
|
|||
views.mapView.initialize(urlMapProvider.getMapUrl())
|
||||
loadPinDrawable()
|
||||
}
|
||||
|
||||
observeViewEvents()
|
||||
initLocateButton()
|
||||
}
|
||||
|
||||
private fun observeViewEvents() {
|
||||
viewModel.observeViewEvents {
|
||||
when (it) {
|
||||
LocationPreviewViewEvents.UserLocationNotAvailableError -> handleUserLocationNotAvailableError()
|
||||
is LocationPreviewViewEvents.ZoomToUserLocation -> handleZoomToUserLocationEvent(it)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun handleUserLocationNotAvailableError() {
|
||||
showUserLocationNotAvailableErrorDialog {
|
||||
// do nothing
|
||||
}
|
||||
}
|
||||
|
||||
private fun handleZoomToUserLocationEvent(event: LocationPreviewViewEvents.ZoomToUserLocation) {
|
||||
views.mapView.zoomToLocation(event.userLocation)
|
||||
}
|
||||
|
||||
override fun onDestroyView() {
|
||||
|
@ -124,6 +151,12 @@ class LocationPreviewFragment :
|
|||
|
||||
override fun invalidate() = withState(viewModel) { state ->
|
||||
views.mapPreviewLoadingError.isVisible = state.loadingMapHasFailed
|
||||
// TODO render pin for user location
|
||||
if(state.isLoadingUserLocation) {
|
||||
showLoadingDialog()
|
||||
} else {
|
||||
dismissLoadingDialog()
|
||||
}
|
||||
}
|
||||
|
||||
override fun getMenuRes() = R.menu.menu_location_preview
|
||||
|
@ -154,10 +187,30 @@ class LocationPreviewFragment :
|
|||
zoomOnlyOnce = true,
|
||||
userLocationData = location,
|
||||
pinId = args.locationOwnerId ?: DEFAULT_PIN_ID,
|
||||
pinDrawable = pinDrawable
|
||||
pinDrawable = pinDrawable,
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun initLocateButton() {
|
||||
views.mapView.locateButton.setOnClickListener {
|
||||
if (checkPermissions(PERMISSIONS_FOR_FOREGROUND_LOCATION_SHARING, requireActivity(), foregroundLocationResultLauncher)) {
|
||||
zoomToUserLocation()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun zoomToUserLocation() {
|
||||
viewModel.handle(LocationPreviewAction.ZoomToUserLocation)
|
||||
}
|
||||
|
||||
private val foregroundLocationResultLauncher = registerForPermissionsResult { allGranted, deniedPermanently ->
|
||||
if (allGranted) {
|
||||
zoomToUserLocation()
|
||||
} else if (deniedPermanently) {
|
||||
activity?.onPermissionDeniedDialog(R.string.denied_permission_generic)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,25 @@
|
|||
/*
|
||||
* Copyright (c) 2021 New Vector Ltd
|
||||
*
|
||||
* 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 im.vector.app.features.location.preview
|
||||
|
||||
import im.vector.app.core.platform.VectorViewEvents
|
||||
import im.vector.app.features.location.LocationData
|
||||
|
||||
sealed class LocationPreviewViewEvents : VectorViewEvents {
|
||||
data class ZoomToUserLocation(val userLocation: LocationData) : LocationPreviewViewEvents()
|
||||
object UserLocationNotAvailableError : LocationPreviewViewEvents()
|
||||
}
|
|
@ -22,12 +22,18 @@ import dagger.assisted.AssistedFactory
|
|||
import dagger.assisted.AssistedInject
|
||||
import im.vector.app.core.di.MavericksAssistedViewModelFactory
|
||||
import im.vector.app.core.di.hiltMavericksViewModelFactory
|
||||
import im.vector.app.core.platform.EmptyViewEvents
|
||||
import im.vector.app.core.platform.VectorViewModel
|
||||
import im.vector.app.features.location.LocationData
|
||||
import im.vector.app.features.location.LocationTracker
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.flow.launchIn
|
||||
import kotlinx.coroutines.flow.onEach
|
||||
import kotlinx.coroutines.launch
|
||||
|
||||
class LocationPreviewViewModel @AssistedInject constructor(
|
||||
@Assisted private val initialState: LocationPreviewViewState,
|
||||
) : VectorViewModel<LocationPreviewViewState, LocationPreviewAction, EmptyViewEvents>(initialState) {
|
||||
private val locationTracker: LocationTracker,
|
||||
) : VectorViewModel<LocationPreviewViewState, LocationPreviewAction, LocationPreviewViewEvents>(initialState), LocationTracker.Callback {
|
||||
|
||||
@AssistedFactory
|
||||
interface Factory : MavericksAssistedViewModelFactory<LocationPreviewViewModel, LocationPreviewViewState> {
|
||||
|
@ -36,13 +42,61 @@ class LocationPreviewViewModel @AssistedInject constructor(
|
|||
|
||||
companion object : MavericksViewModelFactory<LocationPreviewViewModel, LocationPreviewViewState> by hiltMavericksViewModelFactory()
|
||||
|
||||
init {
|
||||
initLocationTracking()
|
||||
}
|
||||
|
||||
private fun initLocationTracking() {
|
||||
locationTracker.addCallback(this)
|
||||
locationTracker.locations
|
||||
.onEach(::onLocationUpdate)
|
||||
.launchIn(viewModelScope)
|
||||
}
|
||||
|
||||
override fun onCleared() {
|
||||
super.onCleared()
|
||||
locationTracker.removeCallback(this)
|
||||
}
|
||||
|
||||
override fun handle(action: LocationPreviewAction) {
|
||||
when (action) {
|
||||
LocationPreviewAction.ShowMapLoadingError -> handleShowMapLoadingError()
|
||||
LocationPreviewAction.ZoomToUserLocation -> handleZoomToUserLocationAction()
|
||||
}
|
||||
}
|
||||
|
||||
private fun handleShowMapLoadingError() {
|
||||
setState { copy(loadingMapHasFailed = true) }
|
||||
}
|
||||
|
||||
private fun handleZoomToUserLocationAction() = withState { state ->
|
||||
if (!state.isLoadingUserLocation) {
|
||||
setState {
|
||||
copy(isLoadingUserLocation = true)
|
||||
}
|
||||
viewModelScope.launch(Dispatchers.Main) {
|
||||
locationTracker.start()
|
||||
locationTracker.requestLastKnownLocation()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun onNoLocationProviderAvailable() {
|
||||
_viewEvents.post(LocationPreviewViewEvents.UserLocationNotAvailableError)
|
||||
}
|
||||
|
||||
private fun onLocationUpdate(locationData: LocationData) {
|
||||
withState { state ->
|
||||
if (state.isLoadingUserLocation) {
|
||||
_viewEvents.post(LocationPreviewViewEvents.ZoomToUserLocation(locationData))
|
||||
}
|
||||
}
|
||||
|
||||
setState {
|
||||
copy(
|
||||
lastKnownUserLocation = locationData,
|
||||
isLoadingUserLocation = false,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -17,7 +17,10 @@
|
|||
package im.vector.app.features.location.preview
|
||||
|
||||
import com.airbnb.mvrx.MavericksState
|
||||
import im.vector.app.features.location.LocationData
|
||||
|
||||
data class LocationPreviewViewState(
|
||||
val loadingMapHasFailed: Boolean = false
|
||||
val loadingMapHasFailed: Boolean = false,
|
||||
val isLoadingUserLocation: Boolean = false,
|
||||
val lastKnownUserLocation: LocationData? = null,
|
||||
) : MavericksState
|
||||
|
|
|
@ -13,7 +13,7 @@
|
|||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
app:mapbox_renderTextureMode="true"
|
||||
app:showLocateButton="false" />
|
||||
app:showLocateButton="true" />
|
||||
|
||||
<im.vector.app.features.location.MapLoadingErrorView
|
||||
android:id="@+id/mapPreviewLoadingError"
|
||||
|
|
Loading…
Reference in a new issue