mirror of
https://github.com/element-hq/element-android
synced 2024-11-24 10:25:35 +03:00
Compute WidgetUrl "onDemand" to properly handle the theme value
This commit is contained in:
parent
463f2a7ad7
commit
1978a180ff
12 changed files with 73 additions and 30 deletions
|
@ -56,6 +56,11 @@ interface WidgetService {
|
|||
excludedTypes: Set<String>? = null
|
||||
): List<Widget>
|
||||
|
||||
/**
|
||||
* 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.
|
||||
|
|
|
@ -25,7 +25,6 @@ data class Widget(
|
|||
val widgetId: String,
|
||||
val senderInfo: SenderInfo?,
|
||||
val isAddedByMe: Boolean,
|
||||
val computedUrl: String?,
|
||||
val type: WidgetType
|
||||
) {
|
||||
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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<Event>.mapEventsToWidgets(widgetTypes: Set<String>? = null,
|
||||
excludedTypes: Set<String>? = null): List<Widget> {
|
||||
val widgetEvents = this
|
||||
|
|
|
@ -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"
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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<JitsiCallViewState, JitsiCallViewActions, JitsiCallViewEvents>(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),
|
||||
|
|
|
@ -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(
|
||||
|
|
|
@ -43,7 +43,7 @@ abstract class RoomWidgetItem : EpoxyModelWithHolder<RoomWidgetItem.Holder>() {
|
|||
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!!)
|
||||
|
|
|
@ -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)
|
||||
}
|
|
@ -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"
|
||||
|
|
|
@ -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) {
|
||||
|
|
Loading…
Reference in a new issue