diff --git a/vector/src/main/java/im/vector/riotx/features/home/room/detail/widget/RoomWidgetsBottomSheet.kt b/vector/src/main/java/im/vector/riotx/features/home/room/detail/widget/RoomWidgetsBottomSheet.kt index de38dc6bba..832d4f836f 100644 --- a/vector/src/main/java/im/vector/riotx/features/home/room/detail/widget/RoomWidgetsBottomSheet.kt +++ b/vector/src/main/java/im/vector/riotx/features/home/room/detail/widget/RoomWidgetsBottomSheet.kt @@ -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 { diff --git a/vector/src/main/java/im/vector/riotx/features/widgets/WidgetAction.kt b/vector/src/main/java/im/vector/riotx/features/widgets/WidgetAction.kt index af81d8eb0f..06a27a7084 100644 --- a/vector/src/main/java/im/vector/riotx/features/widgets/WidgetAction.kt +++ b/vector/src/main/java/im/vector/riotx/features/widgets/WidgetAction.kt @@ -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() } diff --git a/vector/src/main/java/im/vector/riotx/features/widgets/WidgetFragment.kt b/vector/src/main/java/im/vector/riotx/features/widgets/WidgetFragment.kt index 762a0d7ef4..14b25d0439 100644 --- a/vector/src/main/java/im/vector/riotx/features/widgets/WidgetFragment.kt +++ b/vector/src/main/java/im/vector/riotx/features/widgets/WidgetFragment.kt @@ -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)) } diff --git a/vector/src/main/java/im/vector/riotx/features/widgets/WidgetViewModel.kt b/vector/src/main/java/im/vector/riotx/features/widgets/WidgetViewModel.kt index 8762bf574a..1a7ca0c885 100644 --- a/vector/src/main/java/im/vector/riotx/features/widgets/WidgetViewModel.kt +++ b/vector/src/main/java/im/vector/riotx/features/widgets/WidgetViewModel.kt @@ -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))) } } } diff --git a/vector/src/main/res/layout/fragment_room_widget.xml b/vector/src/main/res/layout/fragment_room_widget.xml index 4fc8f47685..05b317ebf4 100644 --- a/vector/src/main/res/layout/fragment_room_widget.xml +++ b/vector/src/main/res/layout/fragment_room_widget.xml @@ -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" />