Widget: fix loading widgets without scalar token

This commit is contained in:
ganfra 2020-06-02 16:01:58 +02:00
parent 440c21e9f3
commit 82b4415f7d
5 changed files with 73 additions and 72 deletions

View file

@ -22,14 +22,12 @@ import butterknife.BindView
import com.airbnb.mvrx.parentFragmentViewModel
import com.airbnb.mvrx.withState
import im.vector.matrix.android.api.session.widgets.model.Widget
import im.vector.matrix.android.api.session.widgets.model.WidgetType
import im.vector.riotx.R
import im.vector.riotx.core.di.ScreenComponent
import im.vector.riotx.core.extensions.cleanup
import im.vector.riotx.core.extensions.configureWith
import im.vector.riotx.core.platform.VectorBaseBottomSheetDialogFragment
import im.vector.riotx.core.resources.ColorProvider
import im.vector.riotx.core.utils.openUrlInExternalBrowser
import im.vector.riotx.features.home.room.detail.RoomDetailViewModel
import im.vector.riotx.features.home.room.detail.RoomDetailViewState
import im.vector.riotx.features.navigation.Navigator
@ -75,13 +73,8 @@ class RoomWidgetsBottomSheet : VectorBaseBottomSheetDialogFragment(), RoomWidget
}
override fun didSelectWidget(widget: Widget) = withState(roomDetailViewModel) {
if (widget.type == WidgetType.Jitsi) {
openUrlInExternalBrowser(requireContext(), widget.computedUrl)
dismiss()
} else {
navigator.openRoomWidget(requireContext(), it.roomId, widget)
dismiss()
}
navigator.openRoomWidget(requireContext(), it.roomId, widget)
dismiss()
}
companion object {

View file

@ -22,7 +22,8 @@ sealed class WidgetAction : VectorViewModelAction {
data class OnWebViewStartedToLoad(val url: String) : WidgetAction()
data class OnWebViewLoadingError(val url: String, val isHttpError: Boolean, val errorCode: Int, val errorDescription: String) : WidgetAction()
data class OnWebViewLoadingSuccess(val url: String) : WidgetAction()
object DeleteWidget: WidgetAction()
object RevokeWidget: WidgetAction()
object OnTermsReviewed: WidgetAction()
object LoadFormattedUrl : WidgetAction()
object DeleteWidget : WidgetAction()
object RevokeWidget : WidgetAction()
object OnTermsReviewed : WidgetAction()
}

View file

@ -18,6 +18,7 @@ package im.vector.riotx.features.widgets
import android.app.Activity
import android.content.Intent
import android.content.pm.PackageManager
import android.os.Bundle
import android.os.Parcelable
import android.view.Menu
@ -27,6 +28,7 @@ import androidx.appcompat.app.AlertDialog
import androidx.core.view.isInvisible
import androidx.core.view.isVisible
import com.airbnb.mvrx.Fail
import com.airbnb.mvrx.Incomplete
import com.airbnb.mvrx.Loading
import com.airbnb.mvrx.Success
import com.airbnb.mvrx.Uninitialized
@ -45,6 +47,7 @@ import im.vector.riotx.features.widgets.webview.setupForWidget
import kotlinx.android.parcel.Parcelize
import kotlinx.android.synthetic.main.fragment_room_widget.*
import timber.log.Timber
import java.net.URISyntaxException
import javax.inject.Inject
@Parcelize
@ -71,6 +74,7 @@ class WidgetFragment @Inject constructor() : VectorBaseFragment(), WebViewEventL
viewModel.getPostAPIMediator().setWebView(widgetWebView)
}
viewModel.observeViewEvents {
Timber.v("Observed view events: $it")
when (it) {
is WidgetViewEvents.DisplayTerms -> displayTerms(it)
is WidgetViewEvents.LoadFormattedURL -> loadFormattedUrl(it)
@ -78,6 +82,7 @@ class WidgetFragment @Inject constructor() : VectorBaseFragment(), WebViewEventL
is WidgetViewEvents.Failure -> displayErrorDialog(it.throwable)
}
}
viewModel.handle(WidgetAction.LoadFormattedUrl)
}
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
@ -169,58 +174,68 @@ class WidgetFragment @Inject constructor() : VectorBaseFragment(), WebViewEventL
override fun invalidate() = withState(viewModel) { state ->
Timber.v("Invalidate state: $state")
when (state.status) {
WidgetStatus.UNKNOWN -> {
// Hide all?
widgetWebView.isVisible = false
when (state.formattedURL) {
is Incomplete -> {
setStateError(null)
widgetWebView.isInvisible = true
widgetProgressBar.isIndeterminate = true
widgetProgressBar.isVisible = true
}
WidgetStatus.WIDGET_NOT_ALLOWED -> {
widgetWebView.isVisible = false
}
WidgetStatus.WIDGET_ALLOWED -> {
widgetWebView.isVisible = true
when (state.formattedURL) {
is Success -> {
setStateError(null)
when (state.webviewLoadedUrl) {
Uninitialized -> {
widgetWebView.isInvisible = true
}
is Loading -> {
setStateError(null)
widgetWebView.isInvisible = false
widgetProgressBar.isIndeterminate = true
widgetProgressBar.isVisible = true
}
is Success -> {
widgetWebView.isInvisible = false
widgetProgressBar.isVisible = false
setStateError(null)
when (state.webviewLoadedUrl) {
Uninitialized -> {
widgetWebView.isInvisible = true
}
is Loading -> {
setStateError(null)
widgetWebView.isInvisible = false
widgetProgressBar.isIndeterminate = true
widgetProgressBar.isVisible = true
}
is Success -> {
widgetWebView.isInvisible = false
widgetProgressBar.isVisible = false
setStateError(null)
}
is Fail -> {
widgetProgressBar.isInvisible = true
setStateError(state.webviewLoadedUrl.error.message)
}
}
}
is Fail -> {
// we need to show Error
widgetWebView.isInvisible = true
widgetProgressBar.isVisible = false
setStateError(state.formattedURL.error.message)
widgetProgressBar.isInvisible = true
setStateError(state.webviewLoadedUrl.error.message)
}
}
}
is Fail -> {
// we need to show Error
widgetWebView.isInvisible = true
widgetProgressBar.isVisible = false
setStateError(state.formattedURL.error.message)
}
}
}
override fun shouldOverrideUrlLoading(url: String): Boolean {
if (url.startsWith("intent://")) {
try {
val context = requireContext()
val intent = Intent.parseUri(url, Intent.URI_INTENT_SCHEME)
if (intent != null) {
val packageManager: PackageManager = context.packageManager
val info = packageManager.resolveActivity(intent, PackageManager.MATCH_DEFAULT_ONLY)
if (info != null) {
context.startActivity(intent)
} else {
val fallbackUrl = intent.getStringExtra("browser_fallback_url")
openUrlInExternalBrowser(context, fallbackUrl)
}
return true
}
} catch (e: URISyntaxException) {
Timber.d("Can't resolve intent://")
}
}
return false
}
override fun onPageStarted(url: String) {
viewModel.handle(WidgetAction.OnWebViewStartedToLoad(url))
}

View file

@ -85,7 +85,6 @@ class WidgetViewModel @AssistedInject constructor(@Assisted val initialState: Wi
}
setupName()
refreshPermissionStatus()
subscribeToPermissionStatus()
observePowerLevel()
observeWidgetIfNeeded()
subscribeToWidget()
@ -133,22 +132,14 @@ class WidgetViewModel @AssistedInject constructor(@Assisted val initialState: Wi
}
}
private fun subscribeToPermissionStatus() {
selectSubscribe(WidgetViewState::status) {
Timber.v("Widget status: $it")
if (it == WidgetStatus.WIDGET_ALLOWED) {
loadFormattedUrl()
}
}
}
fun getPostAPIMediator() = postAPIMediator
override fun handle(action: WidgetAction) {
when (action) {
is WidgetAction.OnWebViewLoadingError -> handleWebViewLoadingError(action.isHttpError, action.errorCode, action.errorDescription)
is WidgetAction.OnWebViewLoadingSuccess -> handleWebViewLoadingSuccess(action.url)
is WidgetAction.OnWebViewLoadingError -> handleWebViewLoadingError(action)
is WidgetAction.OnWebViewLoadingSuccess -> handleWebViewLoadingSuccess(action)
is WidgetAction.OnWebViewStartedToLoad -> handleWebViewStartLoading()
WidgetAction.LoadFormattedUrl -> loadFormattedUrl()
WidgetAction.DeleteWidget -> handleDeleteWidget()
WidgetAction.RevokeWidget -> handleRevokeWidget()
WidgetAction.OnTermsReviewed -> refreshPermissionStatus()
@ -232,6 +223,7 @@ class WidgetViewModel @AssistedInject constructor(@Assisted val initialState: Wi
bypassWhitelist = initialState.widgetKind == WidgetKind.INTEGRATION_MANAGER
)
setState { copy(formattedURL = Success(formattedUrl)) }
Timber.v("Post load formatted url event: $formattedUrl")
_viewEvents.post(WidgetViewEvents.LoadFormattedURL(formattedUrl))
} catch (failure: Throwable) {
if (failure is WidgetManagementFailure.TermsNotSignedException) {
@ -246,23 +238,24 @@ class WidgetViewModel @AssistedInject constructor(@Assisted val initialState: Wi
setState { copy(webviewLoadedUrl = Loading()) }
}
private fun handleWebViewLoadingSuccess(url: String) {
private fun handleWebViewLoadingSuccess(action: WidgetAction.OnWebViewLoadingSuccess) {
if (initialState.widgetKind.isAdmin()) {
postAPIMediator.injectAPI()
}
setState { copy(webviewLoadedUrl = Success(url)) }
setState { copy(webviewLoadedUrl = Success(action.url)) }
}
private fun handleWebViewLoadingError(isHttpError: Boolean, reason: Int, errorDescription: String) {
if (isHttpError) {
private fun handleWebViewLoadingError(action: WidgetAction.OnWebViewLoadingError) = withState {
if (!action.url.startsWith(it.baseUrl)) {
return@withState
}
if (action.isHttpError) {
// In case of 403, try to refresh the scalar token
withState {
if (it.formattedURL is Success && reason == HttpsURLConnection.HTTP_FORBIDDEN) {
loadFormattedUrl(true)
}
if (it.formattedURL is Success && action.errorCode == HttpsURLConnection.HTTP_FORBIDDEN) {
loadFormattedUrl(true)
}
} else {
setState { copy(webviewLoadedUrl = Fail(Throwable(errorDescription))) }
setState { copy(webviewLoadedUrl = Fail(Throwable(action.errorDescription))) }
}
}

View file

@ -10,15 +10,14 @@
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_alignParentBottom="true"
android:layout_marginBottom="0dp"
android:background="@android:color/transparent" />
<ProgressBar
android:id="@+id/widgetProgressBar"
style="@style/Widget.AppCompat.ProgressBar.Horizontal"
android:layout_width="match_parent"
android:layout_height="6dp"
android:layout_alignParentTop="true"
android:background="?colorPrimary"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerInParent="true"
android:indeterminate="true" />
<LinearLayout