Widget: add active widgets
This commit is contained in:
parent
1fe0c8a3e9
commit
cb80d8d349
matrix-sdk-android/src/main/java/im/vector/matrix/android
api/session
internal/session
vector/src/main
java/im/vector/riotx/features
home/room/detail
widgets
res
@ -98,7 +98,7 @@ data class Event(
|
||||
* @return true if event is state event.
|
||||
*/
|
||||
fun isStateEvent(): Boolean {
|
||||
return EventType.isStateEvent(getClearType())
|
||||
return stateKey != null
|
||||
}
|
||||
|
||||
// ==============================================================================================================
|
||||
|
@ -38,6 +38,8 @@ object EventType {
|
||||
|
||||
// State Events
|
||||
|
||||
const val STATE_ROOM_WIDGET_LEGACY = "im.vector.modular.widgets"
|
||||
const val STATE_ROOM_WIDGET = "m.widget"
|
||||
const val STATE_ROOM_NAME = "m.room.name"
|
||||
const val STATE_ROOM_TOPIC = "m.room.topic"
|
||||
const val STATE_ROOM_AVATAR = "m.room.avatar"
|
||||
@ -84,29 +86,6 @@ object EventType {
|
||||
// Unwedging
|
||||
internal const val DUMMY = "m.dummy"
|
||||
|
||||
private val STATE_EVENTS = listOf(
|
||||
STATE_ROOM_NAME,
|
||||
STATE_ROOM_TOPIC,
|
||||
STATE_ROOM_AVATAR,
|
||||
STATE_ROOM_MEMBER,
|
||||
STATE_ROOM_THIRD_PARTY_INVITE,
|
||||
STATE_ROOM_CREATE,
|
||||
STATE_ROOM_JOIN_RULES,
|
||||
STATE_ROOM_GUEST_ACCESS,
|
||||
STATE_ROOM_POWER_LEVELS,
|
||||
STATE_ROOM_ALIASES,
|
||||
STATE_ROOM_TOMBSTONE,
|
||||
STATE_ROOM_CANONICAL_ALIAS,
|
||||
STATE_ROOM_HISTORY_VISIBILITY,
|
||||
STATE_ROOM_RELATED_GROUPS,
|
||||
STATE_ROOM_PINNED_EVENT,
|
||||
STATE_ROOM_ENCRYPTION
|
||||
)
|
||||
|
||||
fun isStateEvent(type: String): Boolean {
|
||||
return STATE_EVENTS.contains(type)
|
||||
}
|
||||
|
||||
fun isCallEvent(type: String): Boolean {
|
||||
return type == CALL_INVITE
|
||||
|| type == CALL_CANDIDATES
|
||||
|
@ -17,7 +17,6 @@
|
||||
|
||||
package im.vector.matrix.android.api.session.room.powerlevels
|
||||
|
||||
import im.vector.matrix.android.api.session.events.model.EventType
|
||||
import im.vector.matrix.android.api.session.room.model.PowerLevelsContent
|
||||
|
||||
/**
|
||||
@ -44,11 +43,11 @@ class PowerLevelsHelper(private val powerLevelsContent: PowerLevelsContent) {
|
||||
* @param userId the user id
|
||||
* @return true if the user can send this type of event
|
||||
*/
|
||||
fun isAllowedToSend(eventType: String, userId: String): Boolean {
|
||||
return if (eventType.isNotEmpty() && userId.isNotEmpty()) {
|
||||
fun isAllowedToSend(isState: Boolean, eventType: String?, userId: String): Boolean {
|
||||
return if (userId.isNotEmpty()) {
|
||||
val powerLevel = getUserPowerLevel(userId)
|
||||
val minimumPowerLevel = powerLevelsContent.events[eventType]
|
||||
?: if (EventType.isStateEvent(eventType)) {
|
||||
?: if (isState) {
|
||||
powerLevelsContent.stateDefault
|
||||
} else {
|
||||
powerLevelsContent.eventsDefault
|
||||
@ -57,25 +56,6 @@ class PowerLevelsHelper(private val powerLevelsContent: PowerLevelsContent) {
|
||||
} else false
|
||||
}
|
||||
|
||||
/**
|
||||
* Tell if an user can send an event of a certain type
|
||||
*
|
||||
* @param eventType the event type to check for
|
||||
* @param userId the user id
|
||||
* @return true if the user can send this type of event
|
||||
*/
|
||||
fun isAllowedToSend(isState: Boolean, userId: String): Boolean {
|
||||
return if (userId.isNotEmpty()) {
|
||||
val powerLevel = getUserPowerLevel(userId)
|
||||
val minimumPowerLevel = if (isState) {
|
||||
powerLevelsContent.stateDefault
|
||||
} else {
|
||||
powerLevelsContent.eventsDefault
|
||||
}
|
||||
powerLevel >= minimumPowerLevel
|
||||
} else false
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the notification level for a dedicated key.
|
||||
*
|
||||
|
@ -20,15 +20,12 @@ import androidx.lifecycle.LiveData
|
||||
import im.vector.matrix.android.api.MatrixCallback
|
||||
import im.vector.matrix.android.api.query.QueryStringValue
|
||||
import im.vector.matrix.android.api.session.events.model.Content
|
||||
import im.vector.matrix.android.api.session.events.model.EventType
|
||||
import im.vector.matrix.android.api.util.Cancelable
|
||||
import im.vector.matrix.android.internal.session.widgets.Widget
|
||||
|
||||
interface WidgetService {
|
||||
|
||||
companion object {
|
||||
const val WIDGET_EVENT_TYPE = "im.vector.modular.widgets"
|
||||
}
|
||||
|
||||
fun getWidgetURLFormatter(): WidgetURLFormatter
|
||||
|
||||
fun getWidgetPostAPIMediator(): WidgetPostAPIMediator
|
||||
|
2
matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/sync/RoomSyncHandler.kt
2
matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/sync/RoomSyncHandler.kt
@ -240,7 +240,7 @@ internal class RoomSyncHandler @Inject constructor(private val readReceiptHandle
|
||||
eventIds.add(event.eventId)
|
||||
val ageLocalTs = event.unsignedData?.age?.let { syncLocalTimestampMillis - it }
|
||||
val eventEntity = event.toEntity(roomId, SendState.SYNCED, ageLocalTs).copyToRealmOrIgnore(realm)
|
||||
if (event.isStateEvent() && event.stateKey != null) {
|
||||
if (event.stateKey != null) {
|
||||
CurrentStateEventEntity.getOrCreate(realm, roomId, event.stateKey, event.type).apply {
|
||||
eventId = event.eventId
|
||||
root = eventEntity
|
||||
|
@ -18,6 +18,7 @@ package im.vector.matrix.android.internal.session.widgets
|
||||
|
||||
import com.zhuinden.monarchy.Monarchy
|
||||
import im.vector.matrix.android.api.session.events.model.Content
|
||||
import im.vector.matrix.android.api.session.events.model.EventType
|
||||
import im.vector.matrix.android.api.session.widgets.WidgetService
|
||||
import im.vector.matrix.android.internal.database.awaitNotEmptyResult
|
||||
import im.vector.matrix.android.internal.database.model.CurrentStateEventEntity
|
||||
@ -48,14 +49,14 @@ internal class DefaultCreateWidgetTask @Inject constructor(private val monarchy:
|
||||
executeRequest<Unit>(eventBus) {
|
||||
apiCall = roomAPI.sendStateEvent(
|
||||
roomId = params.roomId,
|
||||
stateEventType = WidgetService.WIDGET_EVENT_TYPE,
|
||||
stateEventType = EventType.STATE_ROOM_WIDGET_LEGACY,
|
||||
stateKey = params.widgetId,
|
||||
params = params.content
|
||||
)
|
||||
}
|
||||
awaitNotEmptyResult(monarchy.realmConfiguration, 30_000L) {
|
||||
CurrentStateEventEntity
|
||||
.whereStateKey(it, params.roomId, type = WidgetService.WIDGET_EVENT_TYPE, stateKey = params.widgetId)
|
||||
.whereStateKey(it, params.roomId, type = EventType.STATE_ROOM_WIDGET_LEGACY, stateKey = params.widgetId)
|
||||
.and()
|
||||
.equalTo(CurrentStateEventEntityFields.ROOT.SENDER, userId)
|
||||
}
|
||||
|
7
matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/widgets/WidgetManager.kt
7
matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/widgets/WidgetManager.kt
@ -30,7 +30,6 @@ import im.vector.matrix.android.api.session.events.model.toModel
|
||||
import im.vector.matrix.android.api.session.integrationmanager.IntegrationManagerService
|
||||
import im.vector.matrix.android.api.session.room.model.PowerLevelsContent
|
||||
import im.vector.matrix.android.api.session.room.powerlevels.PowerLevelsHelper
|
||||
import im.vector.matrix.android.api.session.widgets.WidgetService
|
||||
import im.vector.matrix.android.api.util.Cancelable
|
||||
import im.vector.matrix.android.internal.di.UserId
|
||||
import im.vector.matrix.android.internal.session.SessionScope
|
||||
@ -75,7 +74,7 @@ internal class WidgetManager @Inject constructor(private val integrationManager:
|
||||
excludedTypes: Set<String>? = null
|
||||
): LiveData<List<Widget>> {
|
||||
// Get all im.vector.modular.widgets state events in the room
|
||||
val liveWidgetEvents = stateEventDataSource.getStateEventsLive(roomId, setOf(WidgetService.WIDGET_EVENT_TYPE), widgetId)
|
||||
val liveWidgetEvents = stateEventDataSource.getStateEventsLive(roomId, setOf(EventType.STATE_ROOM_WIDGET, EventType.STATE_ROOM_WIDGET_LEGACY), widgetId)
|
||||
return Transformations.map(liveWidgetEvents) { widgetEvents ->
|
||||
widgetEvents.mapEventsToWidgets(widgetTypes, excludedTypes)
|
||||
}
|
||||
@ -88,7 +87,7 @@ internal class WidgetManager @Inject constructor(private val integrationManager:
|
||||
excludedTypes: Set<String>? = null
|
||||
): List<Widget> {
|
||||
// Get all im.vector.modular.widgets state events in the room
|
||||
val widgetEvents: List<Event> = stateEventDataSource.getStateEvents(roomId, setOf(WidgetService.WIDGET_EVENT_TYPE), widgetId)
|
||||
val widgetEvents: List<Event> = stateEventDataSource.getStateEvents(roomId, setOf(EventType.STATE_ROOM_WIDGET, EventType.STATE_ROOM_WIDGET_LEGACY), widgetId)
|
||||
return widgetEvents.mapEventsToWidgets(widgetTypes, excludedTypes)
|
||||
}
|
||||
|
||||
@ -185,6 +184,6 @@ internal class WidgetManager @Inject constructor(private val integrationManager:
|
||||
fun hasPermissionsToHandleWidgets(roomId: String): Boolean {
|
||||
val powerLevelsEvent = stateEventDataSource.getStateEvent(roomId, EventType.STATE_ROOM_POWER_LEVELS, QueryStringValue.NoCondition)
|
||||
val powerLevelsContent = powerLevelsEvent?.content?.toModel<PowerLevelsContent>() ?: return false
|
||||
return PowerLevelsHelper(powerLevelsContent).isAllowedToSend(EventType.STATE_ROOM_POWER_LEVELS, userId)
|
||||
return PowerLevelsHelper(powerLevelsContent).isAllowedToSend(true, null, userId)
|
||||
}
|
||||
}
|
||||
|
@ -147,6 +147,7 @@ import im.vector.riotx.features.home.room.detail.timeline.item.MessageInformatio
|
||||
import im.vector.riotx.features.home.room.detail.timeline.item.MessageTextItem
|
||||
import im.vector.riotx.features.home.room.detail.timeline.item.ReadReceiptData
|
||||
import im.vector.riotx.features.home.room.detail.timeline.reactions.ViewReactionsBottomSheet
|
||||
import im.vector.riotx.features.home.room.detail.widget.RoomWidgetsBannerView
|
||||
import im.vector.riotx.features.html.EventHtmlRenderer
|
||||
import im.vector.riotx.features.html.PillImageSpan
|
||||
import im.vector.riotx.features.invite.VectorInviteView
|
||||
@ -199,7 +200,7 @@ class RoomDetailFragment @Inject constructor(
|
||||
VectorInviteView.Callback,
|
||||
JumpToReadMarkerView.Callback,
|
||||
AttachmentTypeSelectorView.Callback,
|
||||
AttachmentsHelper.Callback {
|
||||
AttachmentsHelper.Callback, RoomWidgetsBannerView.Callback {
|
||||
|
||||
companion object {
|
||||
|
||||
@ -264,6 +265,8 @@ class RoomDetailFragment @Inject constructor(
|
||||
setupNotificationView()
|
||||
setupJumpToReadMarkerView()
|
||||
setupJumpToBottomView()
|
||||
setupWidgetsBannerView()
|
||||
|
||||
roomToolbarContentView.debouncedClicks {
|
||||
navigator.openRoomProfile(requireActivity(), roomDetailArgs.roomId)
|
||||
}
|
||||
@ -311,6 +314,10 @@ class RoomDetailFragment @Inject constructor(
|
||||
}
|
||||
}
|
||||
|
||||
private fun setupWidgetsBannerView() {
|
||||
roomWidgetsBannerView.callback = this
|
||||
}
|
||||
|
||||
private fun openStickerPicker(event: RoomDetailViewEvents.OpenStickerPicker) {
|
||||
navigator.openStickerPicker(this, roomDetailArgs.roomId, event.widget)
|
||||
}
|
||||
@ -323,7 +330,7 @@ class RoomDetailFragment @Inject constructor(
|
||||
val v: View = LayoutInflater.from(requireContext()).inflate(R.layout.dialog_no_sticker_pack, null)
|
||||
builder
|
||||
.setView(v)
|
||||
.setPositiveButton(R.string.yes) { _, _->
|
||||
.setPositiveButton(R.string.yes) { _, _ ->
|
||||
// Open integration manager, to the sticker installation page
|
||||
navigator.openIntegrationManager(
|
||||
context = requireContext(),
|
||||
@ -719,6 +726,7 @@ class RoomDetailFragment @Inject constructor(
|
||||
val summary = state.asyncRoomSummary()
|
||||
val inviter = state.asyncInviter()
|
||||
if (summary?.membership == Membership.JOIN) {
|
||||
roomWidgetsBannerView.render(state.activeRoomWidgets())
|
||||
scrollOnHighlightedEventCallback.timeline = roomDetailViewModel.timeline
|
||||
timelineEventController.update(state)
|
||||
inviteView.visibility = View.GONE
|
||||
@ -1455,4 +1463,8 @@ class RoomDetailFragment @Inject constructor(
|
||||
val formattedContact = contactAttachment.toHumanReadable()
|
||||
roomDetailViewModel.handle(RoomDetailAction.SendMessage(formattedContact, false))
|
||||
}
|
||||
|
||||
override fun onViewWidgetsClicked() {
|
||||
Toast.makeText(requireContext(), "Show widgets", Toast.LENGTH_SHORT).show()
|
||||
}
|
||||
}
|
||||
|
@ -158,7 +158,7 @@ class MessageInformationDataFactory @Inject constructor(private val session: Ses
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (EventType.isStateEvent(event.root.type)) {
|
||||
if (event.root.isStateEvent()) {
|
||||
// Do not warn for state event, they are always in clear
|
||||
E2EDecoration.NONE
|
||||
} else {
|
||||
|
59
vector/src/main/java/im/vector/riotx/features/home/room/detail/widget/RoomWidgetsBannerView.kt
Normal file
59
vector/src/main/java/im/vector/riotx/features/home/room/detail/widget/RoomWidgetsBannerView.kt
Normal file
@ -0,0 +1,59 @@
|
||||
/*
|
||||
* 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.home.room.detail.widget
|
||||
|
||||
import android.content.Context
|
||||
import android.util.AttributeSet
|
||||
import android.view.View
|
||||
import android.widget.RelativeLayout
|
||||
import im.vector.matrix.android.internal.session.widgets.Widget
|
||||
import im.vector.riotx.R
|
||||
import kotlinx.android.synthetic.main.view_room_widgets_banner.view.*
|
||||
|
||||
class RoomWidgetsBannerView @JvmOverloads constructor(
|
||||
context: Context,
|
||||
attrs: AttributeSet? = null,
|
||||
defStyleAttr: Int = 0
|
||||
) : RelativeLayout(context, attrs, defStyleAttr) {
|
||||
|
||||
interface Callback {
|
||||
fun onViewWidgetsClicked()
|
||||
}
|
||||
|
||||
var callback: Callback? = null
|
||||
|
||||
init {
|
||||
setupView()
|
||||
}
|
||||
|
||||
private fun setupView() {
|
||||
inflate(context, R.layout.view_room_widgets_banner, this)
|
||||
setBackgroundResource(R.drawable.bg_active_widgets_banner)
|
||||
setOnClickListener {
|
||||
callback?.onViewWidgetsClicked()
|
||||
}
|
||||
}
|
||||
|
||||
fun render(widgets: List<Widget>?) {
|
||||
if (widgets.isNullOrEmpty()) {
|
||||
visibility = View.GONE
|
||||
} else {
|
||||
visibility = View.VISIBLE
|
||||
activeWidgetsLabel.text = context.resources.getQuantityString(R.plurals.active_widgets, widgets.size, widgets.size)
|
||||
}
|
||||
}
|
||||
}
|
@ -154,7 +154,7 @@ class WidgetPostAPIHandler @AssistedInject constructor(@Assisted private val roo
|
||||
val canSend = if (powerLevelsContent == null) {
|
||||
false
|
||||
} else {
|
||||
PowerLevelsHelper(powerLevelsContent).isAllowedToSend(eventType, session.myUserId)
|
||||
PowerLevelsHelper(powerLevelsContent).isAllowedToSend(isState, eventType, session.myUserId)
|
||||
}
|
||||
if (canSend) {
|
||||
Timber.d("## canSendEvent() returns true")
|
||||
|
@ -92,7 +92,7 @@ class WidgetViewModel @AssistedInject constructor(@Assisted val initialState: Wi
|
||||
}
|
||||
|
||||
private fun subscribeToWidget() {
|
||||
asyncSubscribe(WidgetViewState::asyncWidget){
|
||||
asyncSubscribe(WidgetViewState::asyncWidget) {
|
||||
setState { copy(widgetName = it.name) }
|
||||
}
|
||||
}
|
||||
@ -113,7 +113,7 @@ class WidgetViewModel @AssistedInject constructor(@Assisted val initialState: Wi
|
||||
.mapOptional { it.content.toModel<PowerLevelsContent>() }
|
||||
.unwrap()
|
||||
.map {
|
||||
PowerLevelsHelper(it).isAllowedToSend(true, session.myUserId)
|
||||
PowerLevelsHelper(it).isAllowedToSend(true, null, session.myUserId)
|
||||
}.subscribe {
|
||||
setState { copy(canManageWidgets = it) }
|
||||
}.disposeOnClear()
|
||||
|
@ -0,0 +1,5 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<shape xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<corners android:radius="4dp" />
|
||||
<solid android:color="?attr/riotx_room_active_widgets_banner" />
|
||||
</shape>
|
@ -108,15 +108,31 @@
|
||||
app:layout_constraintTop_toBottomOf="@id/syncStateView"
|
||||
tools:listitem="@layout/item_timeline_event_base" />
|
||||
|
||||
<im.vector.riotx.core.ui.views.JumpToReadMarkerView
|
||||
android:id="@+id/jumpToReadMarkerView"
|
||||
|
||||
<FrameLayout
|
||||
android:id="@+id/bannersContainer"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:visibility="invisible"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@id/syncStateView"
|
||||
tools:visibility="visible" />
|
||||
app:layout_constraintTop_toBottomOf="@id/syncStateView">
|
||||
|
||||
<im.vector.riotx.features.home.room.detail.widget.RoomWidgetsBannerView
|
||||
android:id="@+id/roomWidgetsBannerView"
|
||||
android:layout_marginTop="8dp"
|
||||
android:layout_marginStart="8dp"
|
||||
android:layout_marginEnd="8dp"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"/>
|
||||
|
||||
<im.vector.riotx.core.ui.views.JumpToReadMarkerView
|
||||
android:id="@+id/jumpToReadMarkerView"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:visibility="invisible"
|
||||
tools:visibility="visible" />
|
||||
|
||||
</FrameLayout>
|
||||
|
||||
<im.vector.riotx.core.ui.views.NotificationAreaView
|
||||
android:id="@+id/notificationAreaView"
|
||||
|
36
vector/src/main/res/layout/view_room_widgets_banner.xml
Normal file
36
vector/src/main/res/layout/view_room_widgets_banner.xml
Normal file
@ -0,0 +1,36 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<merge xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:background="@drawable/bg_active_widgets_banner"
|
||||
tools:parentTag="android.widget.RelativeLayout">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/activeWidgetsLabel"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_centerVertical="true"
|
||||
android:gravity="center_vertical"
|
||||
android:paddingStart="12dp"
|
||||
android:paddingTop="8dp"
|
||||
android:paddingEnd="12dp"
|
||||
android:paddingBottom="8dp"
|
||||
android:background="?attr/selectableItemBackground"
|
||||
android:textColor="?riotx_text_primary_body_contrast"
|
||||
tools:text="2 active widgets" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/activeWidgetsViewAction"
|
||||
android:background="@android:color/transparent"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_alignParentEnd="true"
|
||||
android:layout_centerVertical="true"
|
||||
android:gravity="center"
|
||||
android:minWidth="48dp"
|
||||
android:text="@string/active_widget_view_action"
|
||||
android:textAllCaps="true"
|
||||
android:textColor="?attr/colorAccent" />
|
||||
|
||||
</merge>
|
@ -175,6 +175,11 @@
|
||||
<color name="riotx_attachment_selector_border_dark">#FF22262E</color>
|
||||
<color name="riotx_attachment_selector_border_black">#FF090A0C</color>
|
||||
|
||||
<attr name="riotx_room_active_widgets_banner" format="color" />
|
||||
<color name="riotx_room_active_widgets_banner_light">#EBEFF5</color>
|
||||
<color name="riotx_room_active_widgets_banner_dark">#27303A</color>
|
||||
<color name="riotx_room_active_widgets_banner_black">#27303A</color>
|
||||
|
||||
<!-- (color from RiotWeb) -->
|
||||
<attr name="riotx_keys_backup_banner_accent_color" format="color" />
|
||||
<color name="riotx_keys_backup_banner_accent_color_light">#FFF8E3</color>
|
||||
|
@ -1116,6 +1116,7 @@
|
||||
<item quantity="one">1 active widget</item>
|
||||
<item quantity="other">%d active widgets</item>
|
||||
</plurals>
|
||||
<string name="active_widget_view_action">"VIEW"</string>
|
||||
|
||||
|
||||
<string name="room_widget_activity_title">Widget</string>
|
||||
|
@ -33,6 +33,7 @@
|
||||
<item name="riotx_touch_guard_bg">@color/riotx_touch_guard_bg_black</item>
|
||||
<item name="riotx_attachment_selector_background">@color/riotx_attachment_selector_background_black</item>
|
||||
<item name="riotx_attachment_selector_border">@color/riotx_attachment_selector_border_black</item>
|
||||
<item name="riotx_room_active_widgets_banner">@color/riotx_room_active_widgets_banner_black</item>
|
||||
|
||||
<!-- Drawables -->
|
||||
<item name="riotx_highlighted_message_background">@drawable/highlighted_message_background_black</item>
|
||||
|
@ -31,6 +31,7 @@
|
||||
<item name="riotx_touch_guard_bg">@color/riotx_touch_guard_bg_dark</item>
|
||||
<item name="riotx_attachment_selector_background">@color/riotx_attachment_selector_background_dark</item>
|
||||
<item name="riotx_attachment_selector_border">@color/riotx_attachment_selector_border_dark</item>
|
||||
<item name="riotx_room_active_widgets_banner">@color/riotx_room_active_widgets_banner_dark</item>
|
||||
|
||||
<item name="riotx_keys_backup_banner_accent_color">@color/riotx_keys_backup_banner_accent_color_dark</item>
|
||||
|
||||
|
@ -32,6 +32,7 @@
|
||||
<item name="riotx_keys_backup_banner_accent_color">@color/riotx_keys_backup_banner_accent_color_light</item>
|
||||
<item name="riotx_attachment_selector_background">@color/riotx_attachment_selector_background_light</item>
|
||||
<item name="riotx_attachment_selector_border">@color/riotx_attachment_selector_border_light</item>
|
||||
<item name="riotx_room_active_widgets_banner">@color/riotx_room_active_widgets_banner_light</item>
|
||||
|
||||
<!-- Drawables -->
|
||||
<item name="riotx_highlighted_message_background">@drawable/highlighted_message_background_light</item>
|
||||
|
Loading…
x
Reference in New Issue
Block a user