From 1978a180ff5fa164d02d24cb04cf02f8d6c79e68 Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Wed, 10 Feb 2021 14:44:33 +0100 Subject: [PATCH] Compute WidgetUrl "onDemand" to properly handle the theme value --- .../sdk/api/session/widgets/WidgetService.kt | 5 ++++ .../sdk/api/session/widgets/model/Widget.kt | 1 - .../integrationmanager/IntegrationManager.kt | 2 -- .../session/widgets/DefaultWidgetService.kt | 4 +++ .../internal/session/widgets/WidgetManager.kt | 4 +++ .../session/widgets/helper/WidgetFactory.kt | 18 +++++++----- .../call/conference/JitsiCallViewModel.kt | 11 +++++-- .../sticker/StickerPickerActionHandler.kt | 2 +- .../home/room/detail/widget/RoomWidgetItem.kt | 2 +- .../app/features/themes/ThemeProvider.kt | 29 +++++++++++++++++++ .../app/features/widgets/WidgetArgsBuilder.kt | 18 +++++------- .../RoomWidgetPermissionViewModel.kt | 7 ++--- 12 files changed, 73 insertions(+), 30 deletions(-) create mode 100644 vector/src/main/java/im/vector/app/features/themes/ThemeProvider.kt diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/widgets/WidgetService.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/widgets/WidgetService.kt index 0310a3d001..bf3ff8959d 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/widgets/WidgetService.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/widgets/WidgetService.kt @@ -56,6 +56,11 @@ interface WidgetService { excludedTypes: Set? = null ): List + /** + * Return the computed URL of a widget + */ + fun getWidgetComputedUrl(widget: Widget, isLightTheme: Boolean): String? + /** * Returns the live room widgets so you can listen to them. * Some widgets can be deactivated, so be sure to check for isActive. diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/widgets/model/Widget.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/widgets/model/Widget.kt index c8465d4d2e..86aaba7f6f 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/widgets/model/Widget.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/widgets/model/Widget.kt @@ -25,7 +25,6 @@ data class Widget( val widgetId: String, val senderInfo: SenderInfo?, val isAddedByMe: Boolean, - val computedUrl: String?, val type: WidgetType ) { diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/integrationmanager/IntegrationManager.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/integrationmanager/IntegrationManager.kt index ebd57ce657..19a87103f4 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/integrationmanager/IntegrationManager.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/integrationmanager/IntegrationManager.kt @@ -37,7 +37,6 @@ import org.matrix.android.sdk.internal.session.user.accountdata.AccountDataDataS import org.matrix.android.sdk.internal.session.user.accountdata.UpdateUserAccountDataTask import org.matrix.android.sdk.internal.session.widgets.helper.WidgetFactory import org.matrix.android.sdk.internal.session.widgets.helper.extractWidgetSequence -import org.matrix.android.sdk.internal.task.TaskExecutor import timber.log.Timber import javax.inject.Inject @@ -55,7 +54,6 @@ import javax.inject.Inject */ @SessionScope internal class IntegrationManager @Inject constructor(matrixConfiguration: MatrixConfiguration, - private val taskExecutor: TaskExecutor, @SessionDatabase private val monarchy: Monarchy, private val updateUserAccountDataTask: UpdateUserAccountDataTask, private val accountDataDataSource: AccountDataDataSource, diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/widgets/DefaultWidgetService.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/widgets/DefaultWidgetService.kt index 3e4e430e3b..9f5a9360ee 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/widgets/DefaultWidgetService.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/widgets/DefaultWidgetService.kt @@ -50,6 +50,10 @@ internal class DefaultWidgetService @Inject constructor(private val widgetManage return widgetManager.getRoomWidgets(roomId, widgetId, widgetTypes, excludedTypes) } + override fun getWidgetComputedUrl(widget: Widget, isLightTheme: Boolean): String? { + return widgetManager.getWidgetComputedUrl(widget, isLightTheme) + } + override fun getRoomWidgetsLive( roomId: String, widgetId: QueryStringValue, diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/widgets/WidgetManager.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/widgets/WidgetManager.kt index 329903f15b..f841a2a245 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/widgets/WidgetManager.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/widgets/WidgetManager.kt @@ -104,6 +104,10 @@ internal class WidgetManager @Inject constructor(private val integrationManager: return widgetEvents.mapEventsToWidgets(widgetTypes, excludedTypes) } + fun getWidgetComputedUrl(widget: Widget, isLightTheme: Boolean): String? { + return widgetFactory.computeURL(widget, isLightTheme) + } + private fun List.mapEventsToWidgets(widgetTypes: Set? = null, excludedTypes: Set? = null): List { val widgetEvents = this diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/widgets/helper/WidgetFactory.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/widgets/helper/WidgetFactory.kt index 21646b8230..a469a9fe97 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/widgets/helper/WidgetFactory.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/widgets/helper/WidgetFactory.kt @@ -55,30 +55,29 @@ internal class WidgetFactory @Inject constructor(private val userDataSource: Use } } val isAddedByMe = widgetEvent.senderId == userId - val computedUrl = widgetContent.computeURL(widgetEvent.roomId, widgetId) return Widget( widgetContent = widgetContent, event = widgetEvent, widgetId = widgetId, senderInfo = senderInfo, isAddedByMe = isAddedByMe, - computedUrl = computedUrl, type = WidgetType.fromString(type) ) } // Ref: https://github.com/matrix-org/matrix-widget-api/blob/master/src/templating/url-template.ts#L29-L33 - private fun WidgetContent.computeURL(roomId: String?, widgetId: String): String? { - var computedUrl = url ?: return null + fun computeURL(widget: Widget, isLightTheme: Boolean): String? { + var computedUrl = widget.widgetContent.url ?: return null val myUser = userDataSource.getUser(userId) - val keyValue = data.mapKeys { "\$${it.key}" }.toMutableMap() + val keyValue = widget.widgetContent.data.mapKeys { "\$${it.key}" }.toMutableMap() keyValue[WIDGET_PATTERN_MATRIX_USER_ID] = userId keyValue[WIDGET_PATTERN_MATRIX_DISPLAY_NAME] = myUser?.getBestName() ?: userId keyValue[WIDGET_PATTERN_MATRIX_AVATAR_URL] = urlResolver.resolveFullSize(myUser?.avatarUrl) ?: "" - keyValue[WIDGET_PATTERN_MATRIX_WIDGET_ID] = widgetId - keyValue[WIDGET_PATTERN_MATRIX_ROOM_ID] = roomId ?: "" + keyValue[WIDGET_PATTERN_MATRIX_WIDGET_ID] = widget.widgetId + keyValue[WIDGET_PATTERN_MATRIX_ROOM_ID] = widget.event.roomId ?: "" + keyValue[WIDGET_PATTERN_THEME] = getTheme(isLightTheme) for ((key, value) in keyValue) { computedUrl = computedUrl.replace(key, URLEncoder.encode(value.toString(), "utf-8")) @@ -86,6 +85,10 @@ internal class WidgetFactory @Inject constructor(private val userDataSource: Use return computedUrl } + private fun getTheme(isLightTheme: Boolean): String { + return if (isLightTheme) "light" else "dark" + } + companion object { // Value to be replaced in URLS const val WIDGET_PATTERN_MATRIX_USER_ID = "\$matrix_user_id" @@ -93,5 +96,6 @@ internal class WidgetFactory @Inject constructor(private val userDataSource: Use const val WIDGET_PATTERN_MATRIX_AVATAR_URL = "\$matrix_avatar_url" const val WIDGET_PATTERN_MATRIX_WIDGET_ID = "\$matrix_widget_id" const val WIDGET_PATTERN_MATRIX_ROOM_ID = "\$matrix_room_id" + const val WIDGET_PATTERN_THEME = "\$theme" } } diff --git a/vector/src/main/java/im/vector/app/features/call/conference/JitsiCallViewModel.kt b/vector/src/main/java/im/vector/app/features/call/conference/JitsiCallViewModel.kt index 5a323aeb85..d5097daf08 100644 --- a/vector/src/main/java/im/vector/app/features/call/conference/JitsiCallViewModel.kt +++ b/vector/src/main/java/im/vector/app/features/call/conference/JitsiCallViewModel.kt @@ -25,6 +25,7 @@ import dagger.assisted.AssistedInject import dagger.assisted.AssistedFactory import im.vector.app.core.platform.VectorViewModel import im.vector.app.core.resources.StringProvider +import im.vector.app.features.themes.ThemeProvider import org.jitsi.meet.sdk.JitsiMeetUserInfo import org.matrix.android.sdk.api.query.QueryStringValue import org.matrix.android.sdk.api.session.Session @@ -37,7 +38,8 @@ class JitsiCallViewModel @AssistedInject constructor( @Assisted initialState: JitsiCallViewState, @Assisted val args: VectorJitsiActivity.Args, private val session: Session, - private val stringProvider: StringProvider + private val stringProvider: StringProvider, + private val themeProvider: ThemeProvider ) : VectorViewModel(initialState) { @AssistedFactory @@ -45,6 +47,8 @@ class JitsiCallViewModel @AssistedInject constructor( fun create(initialState: JitsiCallViewState, args: VectorJitsiActivity.Args): JitsiCallViewModel } + private val widgetService = session.widgetService() + init { val me = session.getRoomMember(session.myUserId, args.roomId)?.toMatrixItem() val userInfo = JitsiMeetUserInfo().apply { @@ -57,13 +61,14 @@ class JitsiCallViewModel @AssistedInject constructor( copy(userInfo = userInfo) } - session.widgetService().getRoomWidgetsLive(args.roomId, QueryStringValue.Equals(args.widgetId), WidgetType.Jitsi.values()) + widgetService.getRoomWidgetsLive(args.roomId, QueryStringValue.Equals(args.widgetId), WidgetType.Jitsi.values()) .asObservable() .distinctUntilChanged() .subscribe { val jitsiWidget = it.firstOrNull() if (jitsiWidget != null) { - val ppt = jitsiWidget.computedUrl?.let { url -> JitsiWidgetProperties(url, stringProvider) } + val ppt = widgetService.getWidgetComputedUrl(jitsiWidget, themeProvider.isLightTheme()) + ?.let { url -> JitsiWidgetProperties(url, stringProvider) } setState { copy( widget = Success(jitsiWidget), diff --git a/vector/src/main/java/im/vector/app/features/home/room/detail/sticker/StickerPickerActionHandler.kt b/vector/src/main/java/im/vector/app/features/home/room/detail/sticker/StickerPickerActionHandler.kt index d24b41ffb0..5039459c0c 100644 --- a/vector/src/main/java/im/vector/app/features/home/room/detail/sticker/StickerPickerActionHandler.kt +++ b/vector/src/main/java/im/vector/app/features/home/room/detail/sticker/StickerPickerActionHandler.kt @@ -32,7 +32,7 @@ class StickerPickerActionHandler @Inject constructor(private val session: Sessio return@withContext RoomDetailViewEvents.DisplayEnableIntegrationsWarning } val stickerWidget = session.widgetService().getUserWidgets(WidgetType.StickerPicker.values()).firstOrNull { it.isActive } - if (stickerWidget == null || stickerWidget.computedUrl.isNullOrBlank()) { + if (stickerWidget == null || stickerWidget.widgetContent.url.isNullOrBlank()) { RoomDetailViewEvents.DisplayPromptForIntegrationManager } else { RoomDetailViewEvents.OpenStickerPicker( diff --git a/vector/src/main/java/im/vector/app/features/home/room/detail/widget/RoomWidgetItem.kt b/vector/src/main/java/im/vector/app/features/home/room/detail/widget/RoomWidgetItem.kt index 33a6f627a1..662f11e7c2 100644 --- a/vector/src/main/java/im/vector/app/features/home/room/detail/widget/RoomWidgetItem.kt +++ b/vector/src/main/java/im/vector/app/features/home/room/detail/widget/RoomWidgetItem.kt @@ -43,7 +43,7 @@ abstract class RoomWidgetItem : EpoxyModelWithHolder() { override fun bind(holder: Holder) { super.bind(holder) holder.widgetName.text = widget.name - holder.widgetUrl.text = tryOrNull { URL(widget.computedUrl) }?.host ?: widget.computedUrl + holder.widgetUrl.text = tryOrNull { URL(widget.widgetContent.url) }?.host ?: widget.widgetContent.url if (iconRes != null) { holder.iconImage.isVisible = true holder.iconImage.setImageResource(iconRes!!) diff --git a/vector/src/main/java/im/vector/app/features/themes/ThemeProvider.kt b/vector/src/main/java/im/vector/app/features/themes/ThemeProvider.kt new file mode 100644 index 0000000000..77245dc4a0 --- /dev/null +++ b/vector/src/main/java/im/vector/app/features/themes/ThemeProvider.kt @@ -0,0 +1,29 @@ +/* + * 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.themes + +import android.content.Context +import javax.inject.Inject + +/** + * Injectable class to encapsulate ThemeUtils call... + */ +class ThemeProvider @Inject constructor( + private val context: Context +) { + fun isLightTheme() = ThemeUtils.isLightTheme(context) +} diff --git a/vector/src/main/java/im/vector/app/features/widgets/WidgetArgsBuilder.kt b/vector/src/main/java/im/vector/app/features/widgets/WidgetArgsBuilder.kt index 7c7424df8c..38914478e3 100644 --- a/vector/src/main/java/im/vector/app/features/widgets/WidgetArgsBuilder.kt +++ b/vector/src/main/java/im/vector/app/features/widgets/WidgetArgsBuilder.kt @@ -16,15 +16,14 @@ package im.vector.app.features.widgets -import android.content.Context import im.vector.app.core.di.ActiveSessionHolder -import im.vector.app.features.themes.ThemeUtils +import im.vector.app.features.themes.ThemeProvider import org.matrix.android.sdk.api.session.widgets.model.Widget import javax.inject.Inject class WidgetArgsBuilder @Inject constructor( private val sessionHolder: ActiveSessionHolder, - private val context: Context + private val themeProvider: ThemeProvider ) { @Suppress("UNCHECKED_CAST") @@ -52,7 +51,8 @@ class WidgetArgsBuilder @Inject constructor( @Suppress("UNCHECKED_CAST") fun buildStickerPickerArgs(roomId: String, widget: Widget): WidgetArgs { val widgetId = widget.widgetId - val baseUrl = widget.computedUrl ?: throw IllegalStateException() + val baseUrl = sessionHolder.getActiveSession().widgetService() + .getWidgetComputedUrl(widget, themeProvider.isLightTheme()) ?: throw IllegalStateException() return WidgetArgs( baseUrl = baseUrl, kind = WidgetKind.STICKER_PICKER, @@ -68,15 +68,13 @@ class WidgetArgsBuilder @Inject constructor( fun buildRoomWidgetArgs(roomId: String, widget: Widget): WidgetArgs { val widgetId = widget.widgetId - val baseUrl = widget.computedUrl ?: throw IllegalStateException() + val baseUrl = sessionHolder.getActiveSession().widgetService() + .getWidgetComputedUrl(widget, themeProvider.isLightTheme()) ?: throw IllegalStateException() return WidgetArgs( baseUrl = baseUrl, kind = WidgetKind.ROOM, roomId = roomId, - widgetId = widgetId, - urlParams = mapOf( - "theme" to getTheme() - ).filterNotNull() + widgetId = widgetId ) } @@ -86,7 +84,7 @@ class WidgetArgsBuilder @Inject constructor( } private fun getTheme(): String { - return if (ThemeUtils.isLightTheme(context)) { + return if (themeProvider.isLightTheme()) { "light" } else { "dark" diff --git a/vector/src/main/java/im/vector/app/features/widgets/permissions/RoomWidgetPermissionViewModel.kt b/vector/src/main/java/im/vector/app/features/widgets/permissions/RoomWidgetPermissionViewModel.kt index 3accc56680..844a6619b4 100644 --- a/vector/src/main/java/im/vector/app/features/widgets/permissions/RoomWidgetPermissionViewModel.kt +++ b/vector/src/main/java/im/vector/app/features/widgets/permissions/RoomWidgetPermissionViewModel.kt @@ -27,6 +27,7 @@ import im.vector.app.R import im.vector.app.core.platform.VectorViewModel import kotlinx.coroutines.launch import org.matrix.android.sdk.api.extensions.orFalse +import org.matrix.android.sdk.api.extensions.tryOrNull import org.matrix.android.sdk.api.query.QueryStringValue import org.matrix.android.sdk.api.session.Session import org.matrix.android.sdk.api.session.widgets.model.WidgetType @@ -52,11 +53,7 @@ class RoomWidgetPermissionViewModel @AssistedInject constructor(@Assisted val in .filter { it.isNotEmpty() } .map { val widget = it.first() - val domain = try { - URL(widget.computedUrl).host - } catch (e: Throwable) { - null - } + val domain = tryOrNull { URL(widget.widgetContent.url) }?.host // TODO check from widget urls the perms that should be shown? // For now put all if (widget.type == WidgetType.Jitsi) {