Handling map loading error in sharing and preview fragment
This commit is contained in:
parent
87ca9606b3
commit
e0e06c6ac8
@ -54,6 +54,7 @@ import im.vector.app.features.home.room.list.RoomListViewModel
|
|||||||
import im.vector.app.features.home.room.list.home.HomeRoomListViewModel
|
import im.vector.app.features.home.room.list.home.HomeRoomListViewModel
|
||||||
import im.vector.app.features.homeserver.HomeServerCapabilitiesViewModel
|
import im.vector.app.features.homeserver.HomeServerCapabilitiesViewModel
|
||||||
import im.vector.app.features.invite.InviteUsersToRoomViewModel
|
import im.vector.app.features.invite.InviteUsersToRoomViewModel
|
||||||
|
import im.vector.app.features.location.LocationPreviewViewModel
|
||||||
import im.vector.app.features.location.LocationSharingViewModel
|
import im.vector.app.features.location.LocationSharingViewModel
|
||||||
import im.vector.app.features.location.live.map.LiveLocationMapViewModel
|
import im.vector.app.features.location.live.map.LiveLocationMapViewModel
|
||||||
import im.vector.app.features.login.LoginViewModel
|
import im.vector.app.features.login.LoginViewModel
|
||||||
@ -605,6 +606,11 @@ interface MavericksViewModelModule {
|
|||||||
@MavericksViewModelKey(LocationSharingViewModel::class)
|
@MavericksViewModelKey(LocationSharingViewModel::class)
|
||||||
fun createLocationSharingViewModelFactory(factory: LocationSharingViewModel.Factory): MavericksAssistedViewModelFactory<*, *>
|
fun createLocationSharingViewModelFactory(factory: LocationSharingViewModel.Factory): MavericksAssistedViewModelFactory<*, *>
|
||||||
|
|
||||||
|
@Binds
|
||||||
|
@IntoMap
|
||||||
|
@MavericksViewModelKey(LocationPreviewViewModel::class)
|
||||||
|
fun createLocationPreviewViewModelFactory(factory: LocationPreviewViewModel.Factory): MavericksAssistedViewModelFactory<*, *>
|
||||||
|
|
||||||
@Binds
|
@Binds
|
||||||
@IntoMap
|
@IntoMap
|
||||||
@MavericksViewModelKey(VectorAttachmentViewerViewModel::class)
|
@MavericksViewModelKey(VectorAttachmentViewerViewModel::class)
|
||||||
|
@ -0,0 +1,23 @@
|
|||||||
|
/*
|
||||||
|
* 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
|
||||||
|
|
||||||
|
import im.vector.app.core.platform.VectorViewModelAction
|
||||||
|
|
||||||
|
sealed class LocationPreviewAction : VectorViewModelAction {
|
||||||
|
object ShowMapLoadingError : LocationPreviewAction()
|
||||||
|
}
|
@ -21,8 +21,11 @@ import android.view.LayoutInflater
|
|||||||
import android.view.MenuItem
|
import android.view.MenuItem
|
||||||
import android.view.View
|
import android.view.View
|
||||||
import android.view.ViewGroup
|
import android.view.ViewGroup
|
||||||
|
import androidx.core.view.isVisible
|
||||||
import androidx.lifecycle.lifecycleScope
|
import androidx.lifecycle.lifecycleScope
|
||||||
import com.airbnb.mvrx.args
|
import com.airbnb.mvrx.args
|
||||||
|
import com.airbnb.mvrx.fragmentViewModel
|
||||||
|
import com.airbnb.mvrx.withState
|
||||||
import com.mapbox.mapboxsdk.maps.MapView
|
import com.mapbox.mapboxsdk.maps.MapView
|
||||||
import im.vector.app.R
|
import im.vector.app.R
|
||||||
import im.vector.app.core.platform.VectorBaseFragment
|
import im.vector.app.core.platform.VectorBaseFragment
|
||||||
@ -44,9 +47,13 @@ class LocationPreviewFragment @Inject constructor(
|
|||||||
|
|
||||||
private val args: LocationSharingArgs by args()
|
private val args: LocationSharingArgs by args()
|
||||||
|
|
||||||
|
private val viewModel: LocationPreviewViewModel by fragmentViewModel()
|
||||||
|
|
||||||
// Keep a ref to handle properly the onDestroy callback
|
// Keep a ref to handle properly the onDestroy callback
|
||||||
private var mapView: WeakReference<MapView>? = null
|
private var mapView: WeakReference<MapView>? = null
|
||||||
|
|
||||||
|
private var mapLoadingErrorListener: MapView.OnDidFailLoadingMapListener? = null
|
||||||
|
|
||||||
override fun getBinding(inflater: LayoutInflater, container: ViewGroup?): FragmentLocationPreviewBinding {
|
override fun getBinding(inflater: LayoutInflater, container: ViewGroup?): FragmentLocationPreviewBinding {
|
||||||
return FragmentLocationPreviewBinding.inflate(layoutInflater, container, false)
|
return FragmentLocationPreviewBinding.inflate(layoutInflater, container, false)
|
||||||
}
|
}
|
||||||
@ -55,6 +62,9 @@ class LocationPreviewFragment @Inject constructor(
|
|||||||
super.onViewCreated(view, savedInstanceState)
|
super.onViewCreated(view, savedInstanceState)
|
||||||
|
|
||||||
mapView = WeakReference(views.mapView)
|
mapView = WeakReference(views.mapView)
|
||||||
|
mapLoadingErrorListener = MapView.OnDidFailLoadingMapListener {
|
||||||
|
viewModel.handle(LocationPreviewAction.ShowMapLoadingError)
|
||||||
|
}.also { views.mapView.addOnDidFailLoadingMapListener(it) }
|
||||||
views.mapView.onCreate(savedInstanceState)
|
views.mapView.onCreate(savedInstanceState)
|
||||||
|
|
||||||
lifecycleScope.launchWhenCreated {
|
lifecycleScope.launchWhenCreated {
|
||||||
@ -63,6 +73,12 @@ class LocationPreviewFragment @Inject constructor(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun onDestroyView() {
|
||||||
|
mapLoadingErrorListener?.let { mapView?.get()?.removeOnDidFailLoadingMapListener(it) }
|
||||||
|
mapLoadingErrorListener = null
|
||||||
|
super.onDestroyView()
|
||||||
|
}
|
||||||
|
|
||||||
override fun onResume() {
|
override fun onResume() {
|
||||||
super.onResume()
|
super.onResume()
|
||||||
views.mapView.onResume()
|
views.mapView.onResume()
|
||||||
@ -99,6 +115,10 @@ class LocationPreviewFragment @Inject constructor(
|
|||||||
super.onDestroy()
|
super.onDestroy()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun invalidate() = withState(viewModel) { state ->
|
||||||
|
views.mapPreviewLoadingError.isVisible = state.loadingMapHasFailed
|
||||||
|
}
|
||||||
|
|
||||||
override fun getMenuRes() = R.menu.menu_location_preview
|
override fun getMenuRes() = R.menu.menu_location_preview
|
||||||
|
|
||||||
override fun handleMenuItemSelected(item: MenuItem): Boolean {
|
override fun handleMenuItemSelected(item: MenuItem): Boolean {
|
||||||
|
@ -0,0 +1,48 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2022 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 com.airbnb.mvrx.MavericksViewModelFactory
|
||||||
|
import dagger.assisted.Assisted
|
||||||
|
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
|
||||||
|
|
||||||
|
class LocationPreviewViewModel @AssistedInject constructor(
|
||||||
|
@Assisted private val initialState: LocationPreviewViewState,
|
||||||
|
) : VectorViewModel<LocationPreviewViewState, LocationPreviewAction, EmptyViewEvents>(initialState) {
|
||||||
|
|
||||||
|
@AssistedFactory
|
||||||
|
interface Factory : MavericksAssistedViewModelFactory<LocationPreviewViewModel, LocationPreviewViewState> {
|
||||||
|
override fun create(initialState: LocationPreviewViewState): LocationPreviewViewModel
|
||||||
|
}
|
||||||
|
|
||||||
|
companion object : MavericksViewModelFactory<LocationPreviewViewModel, LocationPreviewViewState> by hiltMavericksViewModelFactory()
|
||||||
|
|
||||||
|
override fun handle(action: LocationPreviewAction) {
|
||||||
|
when (action) {
|
||||||
|
LocationPreviewAction.ShowMapLoadingError -> handleShowMapLoadingError()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun handleShowMapLoadingError() {
|
||||||
|
setState { copy(loadingMapHasFailed = true) }
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,23 @@
|
|||||||
|
/*
|
||||||
|
* 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
|
||||||
|
|
||||||
|
import com.airbnb.mvrx.MavericksState
|
||||||
|
|
||||||
|
data class LocationPreviewViewState(
|
||||||
|
val loadingMapHasFailed: Boolean = false
|
||||||
|
) : MavericksState
|
@ -25,4 +25,5 @@ sealed class LocationSharingAction : VectorViewModelAction {
|
|||||||
object ZoomToUserLocation : LocationSharingAction()
|
object ZoomToUserLocation : LocationSharingAction()
|
||||||
object LiveLocationSharingRequested : LocationSharingAction()
|
object LiveLocationSharingRequested : LocationSharingAction()
|
||||||
data class StartLiveLocationSharing(val durationMillis: Long) : LocationSharingAction()
|
data class StartLiveLocationSharing(val durationMillis: Long) : LocationSharingAction()
|
||||||
|
object ShowMapLoadingError : LocationSharingAction()
|
||||||
}
|
}
|
||||||
|
@ -24,6 +24,7 @@ import android.view.View
|
|||||||
import android.view.ViewGroup
|
import android.view.ViewGroup
|
||||||
import androidx.core.content.ContextCompat
|
import androidx.core.content.ContextCompat
|
||||||
import androidx.core.view.isGone
|
import androidx.core.view.isGone
|
||||||
|
import androidx.core.view.isVisible
|
||||||
import androidx.fragment.app.setFragmentResultListener
|
import androidx.fragment.app.setFragmentResultListener
|
||||||
import androidx.lifecycle.lifecycleScope
|
import androidx.lifecycle.lifecycleScope
|
||||||
import com.airbnb.mvrx.fragmentViewModel
|
import com.airbnb.mvrx.fragmentViewModel
|
||||||
@ -69,6 +70,7 @@ class LocationSharingFragment @Inject constructor(
|
|||||||
private var mapView: WeakReference<MapView>? = null
|
private var mapView: WeakReference<MapView>? = null
|
||||||
|
|
||||||
private var hasRenderedUserAvatar = false
|
private var hasRenderedUserAvatar = false
|
||||||
|
private var mapLoadingErrorListener: MapView.OnDidFailLoadingMapListener? = null
|
||||||
|
|
||||||
override fun getBinding(inflater: LayoutInflater, container: ViewGroup?): FragmentLocationSharingBinding {
|
override fun getBinding(inflater: LayoutInflater, container: ViewGroup?): FragmentLocationSharingBinding {
|
||||||
return FragmentLocationSharingBinding.inflate(inflater, container, false)
|
return FragmentLocationSharingBinding.inflate(inflater, container, false)
|
||||||
@ -87,6 +89,9 @@ class LocationSharingFragment @Inject constructor(
|
|||||||
super.onViewCreated(view, savedInstanceState)
|
super.onViewCreated(view, savedInstanceState)
|
||||||
|
|
||||||
mapView = WeakReference(views.mapView)
|
mapView = WeakReference(views.mapView)
|
||||||
|
mapLoadingErrorListener = MapView.OnDidFailLoadingMapListener {
|
||||||
|
viewModel.handle(LocationSharingAction.ShowMapLoadingError)
|
||||||
|
}.also { views.mapView.addOnDidFailLoadingMapListener(it) }
|
||||||
views.mapView.onCreate(savedInstanceState)
|
views.mapView.onCreate(savedInstanceState)
|
||||||
|
|
||||||
lifecycleScope.launchWhenCreated {
|
lifecycleScope.launchWhenCreated {
|
||||||
@ -112,6 +117,12 @@ class LocationSharingFragment @Inject constructor(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun onDestroyView() {
|
||||||
|
mapLoadingErrorListener?.let { mapView?.get()?.removeOnDidFailLoadingMapListener(it) }
|
||||||
|
mapLoadingErrorListener = null
|
||||||
|
super.onDestroyView()
|
||||||
|
}
|
||||||
|
|
||||||
override fun onResume() {
|
override fun onResume() {
|
||||||
super.onResume()
|
super.onResume()
|
||||||
views.mapView.onResume()
|
views.mapView.onResume()
|
||||||
@ -256,20 +267,27 @@ class LocationSharingFragment @Inject constructor(
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun updateMap(state: LocationSharingViewState) {
|
private fun updateMap(state: LocationSharingViewState) {
|
||||||
// first, update the options view
|
if (state.loadingMapHasFailed) {
|
||||||
val options: Set<LocationSharingOption> = when (state.areTargetAndUserLocationEqual) {
|
views.shareLocationOptionsPicker.render(emptySet())
|
||||||
true -> setOf(LocationSharingOption.USER_CURRENT, LocationSharingOption.USER_LIVE)
|
views.shareLocationMapLoadingError.isVisible = true
|
||||||
false -> setOf(LocationSharingOption.PINNED)
|
} else {
|
||||||
else -> emptySet()
|
// first, update the options view
|
||||||
}
|
val options: Set<LocationSharingOption> = when (state.areTargetAndUserLocationEqual) {
|
||||||
views.shareLocationOptionsPicker.render(options)
|
true -> setOf(LocationSharingOption.USER_CURRENT, LocationSharingOption.USER_LIVE)
|
||||||
|
false -> setOf(LocationSharingOption.PINNED)
|
||||||
|
else -> emptySet()
|
||||||
|
}
|
||||||
|
views.shareLocationOptionsPicker.render(options)
|
||||||
|
|
||||||
// then, update the map using the height of the options view after it has been rendered
|
// then, update the map using the height of the options view after it has been rendered
|
||||||
views.shareLocationOptionsPicker.post {
|
views.shareLocationOptionsPicker.post {
|
||||||
val mapState = state
|
val mapState = state
|
||||||
.toMapState()
|
.toMapState()
|
||||||
.copy(logoMarginBottom = views.shareLocationOptionsPicker.height)
|
.copy(logoMarginBottom = views.shareLocationOptionsPicker.height)
|
||||||
views.mapView.render(mapState)
|
views.mapView.render(mapState)
|
||||||
|
}
|
||||||
|
|
||||||
|
views.shareLocationMapLoadingError.isGone = true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -152,6 +152,7 @@ class LocationSharingViewModel @AssistedInject constructor(
|
|||||||
LocationSharingAction.ZoomToUserLocation -> handleZoomToUserLocationAction()
|
LocationSharingAction.ZoomToUserLocation -> handleZoomToUserLocationAction()
|
||||||
LocationSharingAction.LiveLocationSharingRequested -> handleLiveLocationSharingRequestedAction()
|
LocationSharingAction.LiveLocationSharingRequested -> handleLiveLocationSharingRequestedAction()
|
||||||
is LocationSharingAction.StartLiveLocationSharing -> handleStartLiveLocationSharingAction(action.durationMillis)
|
is LocationSharingAction.StartLiveLocationSharing -> handleStartLiveLocationSharingAction(action.durationMillis)
|
||||||
|
LocationSharingAction.ShowMapLoadingError -> handleShowMapLoadingError()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -211,6 +212,10 @@ class LocationSharingViewModel @AssistedInject constructor(
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun handleShowMapLoadingError() {
|
||||||
|
setState { copy(loadingMapHasFailed = true) }
|
||||||
|
}
|
||||||
|
|
||||||
private fun onLocationUpdate(locationData: LocationData) {
|
private fun onLocationUpdate(locationData: LocationData) {
|
||||||
Timber.d("onLocationUpdate()")
|
Timber.d("onLocationUpdate()")
|
||||||
setState {
|
setState {
|
||||||
|
@ -36,6 +36,7 @@ data class LocationSharingViewState(
|
|||||||
val lastKnownUserLocation: LocationData? = null,
|
val lastKnownUserLocation: LocationData? = null,
|
||||||
val locationTargetDrawable: Drawable? = null,
|
val locationTargetDrawable: Drawable? = null,
|
||||||
val canShareLiveLocation: Boolean = false,
|
val canShareLiveLocation: Boolean = false,
|
||||||
|
val loadingMapHasFailed: Boolean = false
|
||||||
) : MavericksState {
|
) : MavericksState {
|
||||||
|
|
||||||
constructor(locationSharingArgs: LocationSharingArgs) : this(
|
constructor(locationSharingArgs: LocationSharingArgs) : this(
|
||||||
|
@ -35,16 +35,6 @@
|
|||||||
app:layout_constraintStart_toStartOf="@id/mapView"
|
app:layout_constraintStart_toStartOf="@id/mapView"
|
||||||
app:layout_constraintTop_toTopOf="@id/mapView" />
|
app:layout_constraintTop_toTopOf="@id/mapView" />
|
||||||
|
|
||||||
<im.vector.app.features.location.MapLoadingErrorView
|
|
||||||
android:id="@+id/shareLocationMapLoadingError"
|
|
||||||
android:layout_width="0dp"
|
|
||||||
android:layout_height="0dp"
|
|
||||||
android:visibility="gone"
|
|
||||||
app:layout_constraintBottom_toTopOf="@id/shareLocationOptionsPicker"
|
|
||||||
app:layout_constraintEnd_toEndOf="parent"
|
|
||||||
app:layout_constraintStart_toStartOf="parent"
|
|
||||||
app:layout_constraintTop_toTopOf="parent" />
|
|
||||||
|
|
||||||
<im.vector.app.features.location.option.LocationSharingOptionPickerView
|
<im.vector.app.features.location.option.LocationSharingOptionPickerView
|
||||||
android:id="@+id/shareLocationOptionsPicker"
|
android:id="@+id/shareLocationOptionsPicker"
|
||||||
android:layout_width="0dp"
|
android:layout_width="0dp"
|
||||||
@ -62,4 +52,14 @@
|
|||||||
app:layout_constraintBottom_toBottomOf="@id/shareLocationOptionsPicker"
|
app:layout_constraintBottom_toBottomOf="@id/shareLocationOptionsPicker"
|
||||||
app:layout_constraintEnd_toEndOf="@id/shareLocationOptionsPicker" />
|
app:layout_constraintEnd_toEndOf="@id/shareLocationOptionsPicker" />
|
||||||
|
|
||||||
|
<im.vector.app.features.location.MapLoadingErrorView
|
||||||
|
android:id="@+id/shareLocationMapLoadingError"
|
||||||
|
android:layout_width="0dp"
|
||||||
|
android:layout_height="0dp"
|
||||||
|
android:visibility="gone"
|
||||||
|
app:layout_constraintBottom_toTopOf="@id/shareLocationOptionsPicker"
|
||||||
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
|
app:layout_constraintTop_toTopOf="parent" />
|
||||||
|
|
||||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||||
|
Loading…
Reference in New Issue
Block a user