a11y for ShieldImageView

This commit is contained in:
Benoit Marty 2021-02-12 18:47:13 +01:00
parent 1f3ff3e0f2
commit fc0c49e16e
22 changed files with 99 additions and 79 deletions

View file

@ -21,7 +21,6 @@ import androidx.core.view.isVisible
import com.airbnb.epoxy.EpoxyAttribute
import im.vector.app.core.epoxy.VectorEpoxyModel
import im.vector.app.core.extensions.setTextOrHide
import im.vector.app.features.crypto.util.toImageRes
import im.vector.app.features.home.AvatarRenderer
import org.matrix.android.sdk.api.crypto.RoomEncryptionTrustLevel
import org.matrix.android.sdk.api.util.MatrixItem
@ -47,6 +46,6 @@ abstract class BaseProfileMatrixItem<T : ProfileMatrixItem.Holder> : VectorEpoxy
holder.subtitleView.setTextOrHide(matrixId)
holder.editableView.isVisible = editable
avatarRenderer.render(matrixItem, holder.avatarImageView)
holder.avatarDecorationImageView.setImageResource(userEncryptionTrustLevel.toImageRes())
holder.avatarDecorationImageView.render(userEncryptionTrustLevel)
}
}

View file

@ -23,6 +23,7 @@ import android.widget.TextView
import com.airbnb.epoxy.EpoxyModelClass
import im.vector.app.R
import im.vector.app.core.epoxy.VectorEpoxyHolder
import im.vector.app.core.ui.views.ShieldImageView
@EpoxyModelClass(layout = R.layout.item_profile_matrix_item)
abstract class ProfileMatrixItem : BaseProfileMatrixItem<ProfileMatrixItem.Holder>() {
@ -31,7 +32,7 @@ abstract class ProfileMatrixItem : BaseProfileMatrixItem<ProfileMatrixItem.Holde
val titleView by bind<TextView>(R.id.matrixItemTitle)
val subtitleView by bind<TextView>(R.id.matrixItemSubtitle)
val avatarImageView by bind<ImageView>(R.id.matrixItemAvatar)
val avatarDecorationImageView by bind<ImageView>(R.id.matrixItemAvatarDecoration)
val avatarDecorationImageView by bind<ShieldImageView>(R.id.matrixItemAvatarDecoration)
val editableView by bind<View>(R.id.matrixItemEditable)
}
}

View file

@ -0,0 +1,56 @@
/*
* 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.core.ui.views
import android.content.Context
import android.util.AttributeSet
import androidx.appcompat.widget.AppCompatImageView
import androidx.core.view.isVisible
import im.vector.app.R
import org.matrix.android.sdk.api.crypto.RoomEncryptionTrustLevel
class ShieldImageView @JvmOverloads constructor(
context: Context,
attrs: AttributeSet? = null,
defStyleAttr: Int = 0
) : AppCompatImageView(context, attrs, defStyleAttr) {
init {
if (isInEditMode) {
render(RoomEncryptionTrustLevel.Trusted)
}
}
fun render(roomEncryptionTrustLevel: RoomEncryptionTrustLevel?) {
isVisible = roomEncryptionTrustLevel != null
when (roomEncryptionTrustLevel) {
RoomEncryptionTrustLevel.Default -> {
contentDescription = context.getString(R.string.a11y_trust_level_default)
setImageResource(R.drawable.ic_shield_black)
}
RoomEncryptionTrustLevel.Warning -> {
contentDescription = context.getString(R.string.a11y_trust_level_warning)
setImageResource(R.drawable.ic_shield_warning)
}
RoomEncryptionTrustLevel.Trusted -> {
contentDescription = context.getString(R.string.a11y_trust_level_trusted)
setImageResource(R.drawable.ic_shield_trusted)
}
}
}
}

View file

@ -1,32 +0,0 @@
/*
* Copyright 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.app.features.crypto.util
import androidx.annotation.DrawableRes
import im.vector.app.R
import im.vector.app.core.extensions.exhaustive
import org.matrix.android.sdk.api.crypto.RoomEncryptionTrustLevel
@DrawableRes
fun RoomEncryptionTrustLevel?.toImageRes(): Int {
return when (this) {
null -> 0
RoomEncryptionTrustLevel.Default -> R.drawable.ic_shield_black
RoomEncryptionTrustLevel.Warning -> R.drawable.ic_shield_warning
RoomEncryptionTrustLevel.Trusted -> R.drawable.ic_shield_trusted
}.exhaustive
}

View file

@ -124,7 +124,6 @@ import im.vector.app.features.call.conference.JitsiCallViewModel
import im.vector.app.features.call.webrtc.WebRtcCallManager
import im.vector.app.features.command.Command
import im.vector.app.features.crypto.keysbackup.restore.KeysBackupRestoreActivity
import im.vector.app.features.crypto.util.toImageRes
import im.vector.app.features.crypto.verification.VerificationBottomSheet
import im.vector.app.features.home.AvatarRenderer
import im.vector.app.features.home.room.detail.composer.TextComposerView
@ -1189,10 +1188,7 @@ class RoomDetailFragment @Inject constructor(
avatarRenderer.render(roomSummary.toMatrixItem(), views.roomToolbarAvatarImageView)
renderSubTitle(typingMessage, roomSummary.topic)
views.roomToolbarDecorationImageView.let {
it.setImageResource(roomSummary.roomEncryptionTrustLevel.toImageRes())
it.isVisible = roomSummary.roomEncryptionTrustLevel != null
}
views.roomToolbarDecorationImageView.render(roomSummary.roomEncryptionTrustLevel)
}
}

View file

@ -23,11 +23,13 @@ import android.widget.TextView
import androidx.annotation.IdRes
import androidx.core.view.isVisible
import im.vector.app.R
import im.vector.app.core.ui.views.ShieldImageView
import im.vector.app.core.utils.DebouncedClickListener
import im.vector.app.features.home.AvatarRenderer
import im.vector.app.features.home.room.detail.timeline.MessageColorProvider
import im.vector.app.features.home.room.detail.timeline.TimelineEventController
import im.vector.app.features.reactions.widget.ReactionButton
import org.matrix.android.sdk.api.crypto.RoomEncryptionTrustLevel
import org.matrix.android.sdk.api.session.room.send.SendState
/**
@ -94,13 +96,12 @@ abstract class AbsBaseMessageItem<H : AbsBaseMessageItem.Holder> : BaseEventItem
when (baseAttributes.informationData.e2eDecoration) {
E2EDecoration.NONE -> {
holder.e2EDecorationView.isVisible = false
holder.e2EDecorationView.render(null)
}
E2EDecoration.WARN_IN_CLEAR,
E2EDecoration.WARN_SENT_BY_UNVERIFIED,
E2EDecoration.WARN_SENT_BY_UNKNOWN -> {
holder.e2EDecorationView.setImageResource(R.drawable.ic_shield_warning)
holder.e2EDecorationView.isVisible = true
holder.e2EDecorationView.render(RoomEncryptionTrustLevel.Warning)
}
}
@ -123,7 +124,7 @@ abstract class AbsBaseMessageItem<H : AbsBaseMessageItem.Holder> : BaseEventItem
abstract class Holder(@IdRes stubId: Int) : BaseEventItem.BaseHolder(stubId) {
val reactionsContainer by bind<ViewGroup>(R.id.reactionsContainer)
val e2EDecorationView by bind<ImageView>(R.id.messageE2EDecoration)
val e2EDecorationView by bind<ShieldImageView>(R.id.messageE2EDecoration)
}
/**

View file

@ -19,15 +19,16 @@ package im.vector.app.features.home.room.detail.timeline.item
import android.view.View
import android.widget.ImageView
import android.widget.TextView
import androidx.core.view.isVisible
import com.airbnb.epoxy.EpoxyAttribute
import com.airbnb.epoxy.EpoxyModelClass
import im.vector.app.R
import im.vector.app.core.epoxy.ClickListener
import im.vector.app.core.epoxy.onClick
import im.vector.app.core.ui.views.ShieldImageView
import im.vector.app.core.utils.DebouncedClickListener
import im.vector.app.features.home.AvatarRenderer
import im.vector.app.features.home.room.detail.timeline.TimelineEventController
import org.matrix.android.sdk.api.crypto.RoomEncryptionTrustLevel
@EpoxyModelClass(layout = R.layout.item_timeline_event_base_noinfo)
abstract class NoticeItem : BaseEventItem<NoticeItem.Holder>() {
@ -49,13 +50,12 @@ abstract class NoticeItem : BaseEventItem<NoticeItem.Holder>() {
when (attributes.informationData.e2eDecoration) {
E2EDecoration.NONE -> {
holder.e2EDecorationView.isVisible = false
holder.e2EDecorationView.render(null)
}
E2EDecoration.WARN_IN_CLEAR,
E2EDecoration.WARN_SENT_BY_UNVERIFIED,
E2EDecoration.WARN_SENT_BY_UNKNOWN -> {
holder.e2EDecorationView.setImageResource(R.drawable.ic_shield_warning)
holder.e2EDecorationView.isVisible = true
holder.e2EDecorationView.render(RoomEncryptionTrustLevel.Warning)
}
}
}
@ -75,7 +75,7 @@ abstract class NoticeItem : BaseEventItem<NoticeItem.Holder>() {
class Holder : BaseHolder(STUB_ID) {
val avatarImageView by bind<ImageView>(R.id.itemNoticeAvatarView)
val noticeTextView by bind<TextView>(R.id.itemNoticeTextView)
val e2EDecorationView by bind<ImageView>(R.id.messageE2EDecoration)
val e2EDecorationView by bind<ShieldImageView>(R.id.messageE2EDecoration)
}
data class Attributes(

View file

@ -31,7 +31,7 @@ import im.vector.app.R
import im.vector.app.core.epoxy.VectorEpoxyHolder
import im.vector.app.core.epoxy.VectorEpoxyModel
import im.vector.app.core.extensions.setTextOrHide
import im.vector.app.features.crypto.util.toImageRes
import im.vector.app.core.ui.views.ShieldImageView
import im.vector.app.features.home.AvatarRenderer
import org.matrix.android.sdk.api.crypto.RoomEncryptionTrustLevel
import org.matrix.android.sdk.api.util.MatrixItem
@ -73,8 +73,7 @@ abstract class RoomSummaryItem : VectorEpoxyModel<RoomSummaryItem.Holder>() {
holder.unreadIndentIndicator.isVisible = hasUnreadMessage
holder.draftView.isVisible = hasDraft
avatarRenderer.render(matrixItem, holder.avatarImageView)
holder.roomAvatarDecorationImageView.isVisible = encryptionTrustLevel != null
holder.roomAvatarDecorationImageView.setImageResource(encryptionTrustLevel.toImageRes())
holder.roomAvatarDecorationImageView.render(encryptionTrustLevel)
holder.roomAvatarFailSendingImageView.isVisible = hasFailedSending
renderSelection(holder, showSelected)
holder.typingView.setTextOrHide(typingMessage)
@ -110,7 +109,7 @@ abstract class RoomSummaryItem : VectorEpoxyModel<RoomSummaryItem.Holder>() {
val lastEventTimeView by bind<TextView>(R.id.roomLastEventTimeView)
val avatarCheckedImageView by bind<ImageView>(R.id.roomAvatarCheckedImageView)
val avatarImageView by bind<ImageView>(R.id.roomAvatarImageView)
val roomAvatarDecorationImageView by bind<ImageView>(R.id.roomAvatarDecorationImageView)
val roomAvatarDecorationImageView by bind<ShieldImageView>(R.id.roomAvatarDecorationImageView)
val roomAvatarFailSendingImageView by bind<ImageView>(R.id.roomAvatarFailSendingImageView)
val rootView by bind<ViewGroup>(R.id.itemRoomLayout)
}

View file

@ -53,6 +53,7 @@ import im.vector.app.features.home.room.detail.RoomDetailPendingActionStore
import im.vector.app.features.roommemberprofile.devices.DeviceListBottomSheet
import im.vector.app.features.roommemberprofile.powerlevel.EditPowerLevelDialogs
import kotlinx.parcelize.Parcelize
import org.matrix.android.sdk.api.crypto.RoomEncryptionTrustLevel
import org.matrix.android.sdk.api.session.room.powerlevels.Role
import org.matrix.android.sdk.api.util.MatrixItem
import javax.inject.Inject
@ -205,31 +206,28 @@ class RoomMemberProfileFragment @Inject constructor(
if (state.isRoomEncrypted) {
headerViews.memberProfileDecorationImageView.isVisible = true
if (state.userMXCrossSigningInfo != null) {
val trustLevel = if (state.userMXCrossSigningInfo != null) {
// Cross signing is enabled for this user
val icon = if (state.userMXCrossSigningInfo.isTrusted()) {
if (state.userMXCrossSigningInfo.isTrusted()) {
// User is trusted
if (state.allDevicesAreCrossSignedTrusted) {
R.drawable.ic_shield_trusted
RoomEncryptionTrustLevel.Trusted
} else {
R.drawable.ic_shield_warning
RoomEncryptionTrustLevel.Warning
}
} else {
R.drawable.ic_shield_black
RoomEncryptionTrustLevel.Default
}
headerViews.memberProfileDecorationImageView.setImageResource(icon)
views.matrixProfileDecorationToolbarAvatarImageView.setImageResource(icon)
} else {
// Legacy
if (state.allDevicesAreTrusted) {
headerViews.memberProfileDecorationImageView.setImageResource(R.drawable.ic_shield_trusted)
views.matrixProfileDecorationToolbarAvatarImageView.setImageResource(R.drawable.ic_shield_trusted)
RoomEncryptionTrustLevel.Trusted
} else {
headerViews.memberProfileDecorationImageView.setImageResource(R.drawable.ic_shield_warning)
views.matrixProfileDecorationToolbarAvatarImageView.setImageResource(R.drawable.ic_shield_warning)
RoomEncryptionTrustLevel.Warning
}
}
headerViews.memberProfileDecorationImageView.render(trustLevel)
views.matrixProfileDecorationToolbarAvatarImageView.render(trustLevel)
} else {
headerViews.memberProfileDecorationImageView.isVisible = false
}

View file

@ -44,7 +44,6 @@ import im.vector.app.core.utils.copyToClipboard
import im.vector.app.core.utils.startSharePlainTextIntent
import im.vector.app.databinding.FragmentMatrixProfileBinding
import im.vector.app.databinding.ViewStubRoomProfileHeaderBinding
import im.vector.app.features.crypto.util.toImageRes
import im.vector.app.features.home.AvatarRenderer
import im.vector.app.features.home.room.list.actions.RoomListActionsArgs
import im.vector.app.features.home.room.list.actions.RoomListQuickActionsBottomSheet
@ -204,9 +203,8 @@ class RoomProfileFragment @Inject constructor(
val matrixItem = it.toMatrixItem()
avatarRenderer.render(matrixItem, headerViews.roomProfileAvatarView)
avatarRenderer.render(matrixItem, views.matrixProfileToolbarAvatarImageView)
headerViews.roomProfileDecorationImageView.isVisible = it.roomEncryptionTrustLevel != null
headerViews.roomProfileDecorationImageView.setImageResource(it.roomEncryptionTrustLevel.toImageRes())
views.matrixProfileDecorationToolbarAvatarImageView.setImageResource(it.roomEncryptionTrustLevel.toImageRes())
headerViews.roomProfileDecorationImageView.render(it.roomEncryptionTrustLevel)
views.matrixProfileDecorationToolbarAvatarImageView.render(it.roomEncryptionTrustLevel)
}
}
roomProfileController.setData(state)

View file

@ -96,6 +96,7 @@ class RoomUploadsFragment @Inject constructor(
private fun renderRoomSummary(state: RoomUploadsViewState) {
state.roomSummary()?.let {
views.roomUploadsToolbarTitleView.text = it.displayName
views.roomUploadsDecorationToolbarAvatarImageView.render(it.roomEncryptionTrustLevel)
avatarRenderer.render(it.toMatrixItem(), views.roomUploadsToolbarAvatarImageView)
}
}

View file

@ -60,7 +60,7 @@
tools:alpha="1"
tools:src="@tools:sample/avatars" />
<ImageView
<im.vector.app.core.ui.views.ShieldImageView
android:id="@+id/matrixProfileDecorationToolbarAvatarImageView"
android:layout_width="24dp"
android:layout_height="24dp"

View file

@ -34,7 +34,7 @@
app:layout_constraintTop_toTopOf="parent"
tools:src="@tools:sample/avatars" />
<ImageView
<im.vector.app.core.ui.views.ShieldImageView
android:id="@+id/roomToolbarDecorationImageView"
android:layout_width="20dp"
android:layout_height="20dp"

View file

@ -39,7 +39,7 @@
app:layout_constraintTop_toTopOf="parent"
tools:src="@tools:sample/avatars" />
<ImageView
<im.vector.app.core.ui.views.ShieldImageView
android:id="@+id/roomUploadsDecorationToolbarAvatarImageView"
android:layout_width="24dp"
android:layout_height="24dp"

View file

@ -26,7 +26,7 @@
app:layout_constraintTop_toTopOf="parent"
tools:src="@tools:sample/avatars" />
<ImageView
<im.vector.app.core.ui.views.ShieldImageView
android:id="@+id/matrixItemAvatarDecoration"
android:layout_width="20dp"
android:layout_height="20dp"

View file

@ -60,7 +60,7 @@
app:layout_constraintCircleRadius="30dp"
tools:ignore="MissingConstraints" />
<ImageView
<im.vector.app.core.ui.views.ShieldImageView
android:id="@+id/roomAvatarDecorationImageView"
android:layout_width="24dp"
android:layout_height="24dp"

View file

@ -65,7 +65,7 @@
android:layout_height="8dp"
android:layout_toEndOf="@id/messageStartGuideline" />
<ImageView
<im.vector.app.core.ui.views.ShieldImageView
android:id="@+id/messageE2EDecoration"
android:layout_width="16dp"
android:layout_height="16dp"

View file

@ -70,7 +70,7 @@
</FrameLayout>
<ImageView
<im.vector.app.core.ui.views.ShieldImageView
android:id="@+id/messageE2EDecoration"
android:layout_width="16dp"
android:layout_height="16dp"

View file

@ -70,7 +70,7 @@
</FrameLayout>
<ImageView
<im.vector.app.core.ui.views.ShieldImageView
android:id="@+id/messageE2EDecoration"
android:layout_width="16dp"
android:layout_height="16dp"

View file

@ -30,7 +30,7 @@
app:layout_constraintVertical_chainStyle="spread_inside"
tools:src="@tools:sample/avatars" />
<ImageView
<im.vector.app.core.ui.views.ShieldImageView
android:id="@+id/memberProfileDecorationImageView"
android:layout_width="48dp"
android:layout_height="48dp"

View file

@ -20,7 +20,7 @@
app:layout_constraintTop_toTopOf="parent"
tools:src="@tools:sample/avatars" />
<ImageView
<im.vector.app.core.ui.views.ShieldImageView
android:id="@+id/roomProfileDecorationImageView"
android:layout_width="48dp"
android:layout_height="48dp"

View file

@ -2840,4 +2840,7 @@
<string name="a11y_unsent_draft">This room has unsent draft</string>
<string name="a11y_video">Video</string>
<string name="a11y_selected">Selected</string>
<string name="a11y_trust_level_default">Default trust level</string>
<string name="a11y_trust_level_warning">Warning trust level</string>
<string name="a11y_trust_level_trusted">Trusted trust level</string>
</resources>