Widget: Handle failures on permissions

This commit is contained in:
ganfra 2020-05-29 16:44:17 +02:00
parent 7df8b3a9bf
commit 2002252f72
8 changed files with 85 additions and 35 deletions

View file

@ -30,11 +30,14 @@ import im.vector.riotx.core.extensions.addFragment
import im.vector.riotx.core.platform.ToolbarConfigurable import im.vector.riotx.core.platform.ToolbarConfigurable
import im.vector.riotx.core.platform.VectorBaseActivity import im.vector.riotx.core.platform.VectorBaseActivity
import im.vector.riotx.features.widgets.permissions.RoomWidgetPermissionBottomSheet import im.vector.riotx.features.widgets.permissions.RoomWidgetPermissionBottomSheet
import im.vector.riotx.features.widgets.permissions.RoomWidgetPermissionViewEvents
import im.vector.riotx.features.widgets.permissions.RoomWidgetPermissionViewModel
import im.vector.riotx.features.widgets.permissions.RoomWidgetPermissionViewState
import kotlinx.android.synthetic.main.activity_widget.* import kotlinx.android.synthetic.main.activity_widget.*
import java.io.Serializable import java.io.Serializable
import javax.inject.Inject import javax.inject.Inject
class WidgetActivity : VectorBaseActivity(), ToolbarConfigurable, WidgetViewModel.Factory { class WidgetActivity : VectorBaseActivity(), ToolbarConfigurable, WidgetViewModel.Factory, RoomWidgetPermissionViewModel.Factory {
companion object { companion object {
@ -61,7 +64,10 @@ class WidgetActivity : VectorBaseActivity(), ToolbarConfigurable, WidgetViewMode
} }
@Inject lateinit var viewModelFactory: WidgetViewModel.Factory @Inject lateinit var viewModelFactory: WidgetViewModel.Factory
@Inject lateinit var permissionsViewModelFactory: RoomWidgetPermissionViewModel.Factory
private val viewModel: WidgetViewModel by viewModel() private val viewModel: WidgetViewModel by viewModel()
private val permissionViewModel: RoomWidgetPermissionViewModel by viewModel()
override fun getLayoutRes() = R.layout.activity_widget override fun getLayoutRes() = R.layout.activity_widget
@ -85,6 +91,12 @@ class WidgetActivity : VectorBaseActivity(), ToolbarConfigurable, WidgetViewMode
} }
} }
permissionViewModel.observeViewEvents {
when (it) {
is RoomWidgetPermissionViewEvents.Close -> finish()
}
}
viewModel.selectSubscribe(this, WidgetViewState::status) { ws -> viewModel.selectSubscribe(this, WidgetViewState::status) { ws ->
when (ws) { when (ws) {
WidgetStatus.UNKNOWN -> { WidgetStatus.UNKNOWN -> {
@ -95,11 +107,7 @@ class WidgetActivity : VectorBaseActivity(), ToolbarConfigurable, WidgetViewMode
return@selectSubscribe return@selectSubscribe
} else { } else {
RoomWidgetPermissionBottomSheet RoomWidgetPermissionBottomSheet
.newInstance(widgetArgs).apply { .newInstance(widgetArgs)
onFinish = { accepted ->
if (!accepted) finish()
}
}
.show(supportFragmentManager, WIDGET_PERMISSION_FRAGMENT_TAG) .show(supportFragmentManager, WIDGET_PERMISSION_FRAGMENT_TAG)
} }
} }
@ -124,6 +132,10 @@ class WidgetActivity : VectorBaseActivity(), ToolbarConfigurable, WidgetViewMode
return viewModelFactory.create(initialState) return viewModelFactory.create(initialState)
} }
override fun create(initialState: RoomWidgetPermissionViewState): RoomWidgetPermissionViewModel {
return permissionsViewModelFactory.create(initialState)
}
private fun handleClose(event: WidgetViewEvents.Close) { private fun handleClose(event: WidgetViewEvents.Close) {
if (event.content != null) { if (event.content != null) {
val intent = createResultIntent(event.content) val intent = createResultIntent(event.content)

View file

@ -24,7 +24,6 @@ import android.view.Menu
import android.view.MenuItem import android.view.MenuItem
import android.view.View import android.view.View
import androidx.appcompat.app.AlertDialog import androidx.appcompat.app.AlertDialog
import androidx.core.view.forEach
import androidx.core.view.isInvisible import androidx.core.view.isInvisible
import androidx.core.view.isVisible import androidx.core.view.isVisible
import com.airbnb.mvrx.Fail import com.airbnb.mvrx.Fail
@ -76,6 +75,7 @@ class WidgetFragment @Inject constructor() : VectorBaseFragment(), WebViewEventL
is WidgetViewEvents.DisplayTerms -> displayTerms(it) is WidgetViewEvents.DisplayTerms -> displayTerms(it)
is WidgetViewEvents.LoadFormattedURL -> loadFormattedUrl(it) is WidgetViewEvents.LoadFormattedURL -> loadFormattedUrl(it)
is WidgetViewEvents.DisplayIntegrationManager -> displayIntegrationManager(it) is WidgetViewEvents.DisplayIntegrationManager -> displayIntegrationManager(it)
is WidgetViewEvents.Failure -> displayErrorDialog(it.throwable)
} }
} }
} }

View file

@ -20,6 +20,7 @@ import im.vector.matrix.android.api.session.events.model.Content
import im.vector.riotx.core.platform.VectorViewEvents import im.vector.riotx.core.platform.VectorViewEvents
sealed class WidgetViewEvents : VectorViewEvents { sealed class WidgetViewEvents : VectorViewEvents {
data class Failure(val throwable: Throwable): WidgetViewEvents()
data class Close(val content: Content? = null) : WidgetViewEvents() data class Close(val content: Content? = null) : WidgetViewEvents()
data class DisplayIntegrationManager(val integId: String?, val integType: String?) : WidgetViewEvents() data class DisplayIntegrationManager(val integId: String?, val integType: String?) : WidgetViewEvents()
data class LoadFormattedURL(val formattedURL: String) : WidgetViewEvents() data class LoadFormattedURL(val formattedURL: String) : WidgetViewEvents()

View file

@ -158,18 +158,27 @@ class WidgetViewModel @AssistedInject constructor(@Assisted val initialState: Wi
private fun handleRevokeWidget() { private fun handleRevokeWidget() {
viewModelScope.launch { viewModelScope.launch {
val widgetId = initialState.widgetId ?: return@launch val widgetId = initialState.widgetId ?: return@launch
WidgetPermissionsHelper(integrationManagerService, widgetService).changePermission(initialState.roomId, widgetId, false) try {
_viewEvents.post(WidgetViewEvents.Close()) WidgetPermissionsHelper(integrationManagerService, widgetService).changePermission(initialState.roomId, widgetId, false)
_viewEvents.post(WidgetViewEvents.Close())
} catch (failure: Throwable) {
_viewEvents.post(WidgetViewEvents.Failure(failure))
}
} }
} }
private fun handleDeleteWidget() { private fun handleDeleteWidget() {
viewModelScope.launch { viewModelScope.launch {
val widgetId = initialState.widgetId ?: return@launch val widgetId = initialState.widgetId ?: return@launch
awaitCallback<Unit> { try {
widgetService.destroyRoomWidget(initialState.roomId, widgetId, it) awaitCallback<Unit> {
_viewEvents.post(WidgetViewEvents.Close()) widgetService.destroyRoomWidget(initialState.roomId, widgetId, it)
_viewEvents.post(WidgetViewEvents.Close())
}
} catch (failure: Throwable) {
_viewEvents.post(WidgetViewEvents.Failure(failure))
} }
} }
} }

View file

@ -21,4 +21,5 @@ import im.vector.riotx.core.platform.VectorViewModelAction
sealed class RoomWidgetPermissionActions : VectorViewModelAction { sealed class RoomWidgetPermissionActions : VectorViewModelAction {
object AllowWidget: RoomWidgetPermissionActions() object AllowWidget: RoomWidgetPermissionActions()
object BlockWidget: RoomWidgetPermissionActions() object BlockWidget: RoomWidgetPermissionActions()
object DoClose: RoomWidgetPermissionActions()
} }

View file

@ -25,7 +25,7 @@ import android.widget.TextView
import butterknife.BindView import butterknife.BindView
import butterknife.OnClick import butterknife.OnClick
import com.airbnb.mvrx.MvRx import com.airbnb.mvrx.MvRx
import com.airbnb.mvrx.fragmentViewModel import com.airbnb.mvrx.activityViewModel
import com.airbnb.mvrx.withState import com.airbnb.mvrx.withState
import im.vector.matrix.android.api.util.toMatrixItem import im.vector.matrix.android.api.util.toMatrixItem
import im.vector.riotx.R import im.vector.riotx.R
@ -36,11 +36,11 @@ import im.vector.riotx.features.home.AvatarRenderer
import im.vector.riotx.features.widgets.WidgetArgs import im.vector.riotx.features.widgets.WidgetArgs
import javax.inject.Inject import javax.inject.Inject
class RoomWidgetPermissionBottomSheet : VectorBaseBottomSheetDialogFragment(), RoomWidgetPermissionViewModel.Factory { class RoomWidgetPermissionBottomSheet : VectorBaseBottomSheetDialogFragment() {
override fun getLayoutResId(): Int = R.layout.bottom_sheet_room_widget_permission override fun getLayoutResId(): Int = R.layout.bottom_sheet_room_widget_permission
private val viewModel: RoomWidgetPermissionViewModel by fragmentViewModel() private val viewModel: RoomWidgetPermissionViewModel by activityViewModel()
@BindView(R.id.bottom_sheet_widget_permission_shared_info) @BindView(R.id.bottom_sheet_widget_permission_shared_info)
lateinit var sharedInfoTextView: TextView lateinit var sharedInfoTextView: TextView
@ -55,9 +55,6 @@ class RoomWidgetPermissionBottomSheet : VectorBaseBottomSheetDialogFragment(), R
lateinit var authorAvatarView: ImageView lateinit var authorAvatarView: ImageView
@Inject lateinit var avatarRenderer: AvatarRenderer @Inject lateinit var avatarRenderer: AvatarRenderer
@Inject lateinit var viewModelFactory: RoomWidgetPermissionViewModel.Factory
var onFinish: ((Boolean) -> Unit)? = null
override val showExpanded = true override val showExpanded = true
@ -65,10 +62,6 @@ class RoomWidgetPermissionBottomSheet : VectorBaseBottomSheetDialogFragment(), R
injector.inject(this) injector.inject(this)
} }
override fun create(initialState: RoomWidgetPermissionViewState): RoomWidgetPermissionViewModel {
return viewModelFactory.create(initialState)
}
override fun invalidate() = withState(viewModel) { state -> override fun invalidate() = withState(viewModel) { state ->
super.invalidate() super.invalidate()
val permissionData = state.permissionData() ?: return@withState val permissionData = state.permissionData() ?: return@withState
@ -112,7 +105,6 @@ class RoomWidgetPermissionBottomSheet : VectorBaseBottomSheetDialogFragment(), R
viewModel.handle(RoomWidgetPermissionActions.BlockWidget) viewModel.handle(RoomWidgetPermissionActions.BlockWidget)
//optimistic dismiss //optimistic dismiss
dismiss() dismiss()
onFinish?.invoke(false)
} }
@OnClick(R.id.bottom_sheet_widget_permission_continue_button) @OnClick(R.id.bottom_sheet_widget_permission_continue_button)
@ -120,12 +112,11 @@ class RoomWidgetPermissionBottomSheet : VectorBaseBottomSheetDialogFragment(), R
viewModel.handle(RoomWidgetPermissionActions.AllowWidget) viewModel.handle(RoomWidgetPermissionActions.AllowWidget)
//optimistic dismiss //optimistic dismiss
dismiss() dismiss()
onFinish?.invoke(true)
} }
override fun onCancel(dialog: DialogInterface) { override fun onCancel(dialog: DialogInterface) {
super.onCancel(dialog) super.onCancel(dialog)
onFinish?.invoke(false) viewModel.handle(RoomWidgetPermissionActions.DoClose)
} }
companion object { companion object {

View file

@ -0,0 +1,23 @@
/*
* Copyright (c) 2020 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.riotx.features.widgets.permissions
import im.vector.riotx.core.platform.VectorViewEvents
sealed class RoomWidgetPermissionViewEvents : VectorViewEvents {
object Close : RoomWidgetPermissionViewEvents()
}

View file

@ -27,14 +27,14 @@ import im.vector.matrix.android.api.query.QueryStringValue
import im.vector.matrix.android.api.session.Session import im.vector.matrix.android.api.session.Session
import im.vector.matrix.rx.rx import im.vector.matrix.rx.rx
import im.vector.riotx.R import im.vector.riotx.R
import im.vector.riotx.core.platform.EmptyViewEvents
import im.vector.riotx.core.platform.VectorViewModel import im.vector.riotx.core.platform.VectorViewModel
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
import timber.log.Timber
import java.net.URL import java.net.URL
class RoomWidgetPermissionViewModel @AssistedInject constructor(@Assisted val initialState: RoomWidgetPermissionViewState, class RoomWidgetPermissionViewModel @AssistedInject constructor(@Assisted val initialState: RoomWidgetPermissionViewState,
private val session: Session) private val session: Session)
: VectorViewModel<RoomWidgetPermissionViewState, RoomWidgetPermissionActions, EmptyViewEvents>(initialState) { : VectorViewModel<RoomWidgetPermissionViewState, RoomWidgetPermissionActions, RoomWidgetPermissionViewEvents>(initialState) {
private val widgetService = session.widgetService() private val widgetService = session.widgetService()
private val integrationManagerService = session.integrationManagerService() private val integrationManagerService = session.integrationManagerService()
@ -86,20 +86,33 @@ class RoomWidgetPermissionViewModel @AssistedInject constructor(@Assisted val in
private fun handleRevokeWidget() = withState { state -> private fun handleRevokeWidget() = withState { state ->
viewModelScope.launch { viewModelScope.launch {
if (state.permissionData()?.isWebviewWidget.orFalse()) { try {
WidgetPermissionsHelper(integrationManagerService, widgetService).changePermission(state.roomId, state.widgetId, false) if (state.permissionData()?.isWebviewWidget.orFalse()) {
} else { WidgetPermissionsHelper(integrationManagerService, widgetService).changePermission(state.roomId, state.widgetId, false)
//TODO JITSI } else {
//TODO JITSI
}
} catch (failure: Throwable) {
Timber.v("Failure revoking widget: ${state.widgetId}")
} finally {
// We send close event in every situation
_viewEvents.post(RoomWidgetPermissionViewEvents.Close)
} }
} }
} }
private fun handleAllowWidget() = withState { state -> private fun handleAllowWidget() = withState { state ->
viewModelScope.launch { viewModelScope.launch {
if (state.permissionData()?.isWebviewWidget.orFalse()) { try {
WidgetPermissionsHelper(integrationManagerService, widgetService).changePermission(state.roomId, state.widgetId, true) if (state.permissionData()?.isWebviewWidget.orFalse()) {
} else { WidgetPermissionsHelper(integrationManagerService, widgetService).changePermission(state.roomId, state.widgetId, true)
//TODO JITSI } else {
//TODO JITSI
}
} catch (failure: Throwable) {
Timber.v("Failure allowing widget: ${state.widgetId}")
// We send close event only when it's failed
_viewEvents.post(RoomWidgetPermissionViewEvents.Close)
} }
} }
} }