Merge pull request #2819 from vector-im/feature/bma/lang

a11y
This commit is contained in:
Benoit Marty 2021-02-16 11:41:02 +01:00 committed by GitHub
commit 03735d9213
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
221 changed files with 651 additions and 607 deletions

View file

@ -8,6 +8,7 @@ Improvements 🙌:
- VoIP : new tiles in timeline - VoIP : new tiles in timeline
- Improve room profile UX - Improve room profile UX
- Upgrade Jitsi library from 2.9.3 to 3.1.0 - Upgrade Jitsi library from 2.9.3 to 3.1.0
- a11y improvements
Bugfix 🐛: Bugfix 🐛:
- VoIP : fix audio devices output - VoIP : fix audio devices output

View file

@ -17,6 +17,10 @@
<issue id="ButtonOrder" severity="error" /> <issue id="ButtonOrder" severity="error" />
<issue id="TextFields" severity="error" /> <issue id="TextFields" severity="error" />
<!-- Accessibility -->
<issue id="LabelFor" severity="error" />
<issue id="ContentDescription" severity="error" />
<!-- Layout --> <!-- Layout -->
<issue id="UnknownIdInLayout" severity="error" /> <issue id="UnknownIdInLayout" severity="error" />
<issue id="StringFormatCount" severity="error" /> <issue id="StringFormatCount" severity="error" />

View file

@ -159,6 +159,7 @@
<com.google.android.material.floatingactionbutton.FloatingActionButton <com.google.android.material.floatingactionbutton.FloatingActionButton
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:importantForAccessibility="no"
android:src="@drawable/ic_settings_x" /> android:src="@drawable/ic_settings_x" />
</LinearLayout> </LinearLayout>

View file

@ -21,6 +21,7 @@
div { div {
padding: 4px; padding: 4px;
} }
</style> </style>
</head> </head>
<body> <body>
@ -388,7 +389,7 @@ SOFTWARE.
<li> <li>
<b>dialogs / android-dialer</b> <b>dialogs / android-dialer</b>
<br/> <br/>
Copyright (c) 2017-present, dialog LLC <info@dlg.im> Copyright (c) 2017-present, dialog LLC &lt;info@dlg.im&gt;
</li> </li>
</ul> </ul>
<pre> <pre>
@ -570,20 +571,24 @@ Apache License
<pre> <pre>
CC-BY 4.0 CC-BY 4.0
</pre>
<ul>
<li> <li>
<b>Twitter/twemoji Graphics</b> <b>Twitter/twemoji Graphics</b>
<br/> <br/>
</li> </li>
</pre> </ul>
<pre> <pre>
ISC License ISC License
</pre>
<ul>
<li> <li>
<b>DanielMartinus / Konfetti</b> <b>DanielMartinus / Konfetti</b>
<br/> <br/>
Copyright (c) 2017 Dion Segijn Copyright (c) 2017 Dion Segijn
</li> </li>
</pre> </ul>
</body> </body>
</html> </html>

View file

@ -23,7 +23,6 @@ import im.vector.app.features.crypto.keysrequest.KeyRequestHandler
import im.vector.app.features.crypto.verification.IncomingVerificationRequestHandler import im.vector.app.features.crypto.verification.IncomingVerificationRequestHandler
import im.vector.app.features.notifications.PushRuleTriggerListener import im.vector.app.features.notifications.PushRuleTriggerListener
import im.vector.app.features.session.SessionListener import im.vector.app.features.session.SessionListener
import org.matrix.android.sdk.api.auth.AuthenticationService
import org.matrix.android.sdk.api.session.Session import org.matrix.android.sdk.api.session.Session
import timber.log.Timber import timber.log.Timber
import java.util.concurrent.atomic.AtomicReference import java.util.concurrent.atomic.AtomicReference
@ -31,8 +30,7 @@ import javax.inject.Inject
import javax.inject.Singleton import javax.inject.Singleton
@Singleton @Singleton
class ActiveSessionHolder @Inject constructor(private val authenticationService: AuthenticationService, class ActiveSessionHolder @Inject constructor(private val sessionObservableStore: ActiveSessionDataSource,
private val sessionObservableStore: ActiveSessionDataSource,
private val keyRequestHandler: KeyRequestHandler, private val keyRequestHandler: KeyRequestHandler,
private val incomingVerificationRequestHandler: IncomingVerificationRequestHandler, private val incomingVerificationRequestHandler: IncomingVerificationRequestHandler,
private val callManager: WebRtcCallManager, private val callManager: WebRtcCallManager,

View file

@ -61,7 +61,7 @@ class ExportKeysDialog {
passwordVisible = !passwordVisible passwordVisible = !passwordVisible
views.exportDialogEt.showPassword(passwordVisible) views.exportDialogEt.showPassword(passwordVisible)
views.exportDialogEtConfirm.showPassword(passwordVisible) views.exportDialogEtConfirm.showPassword(passwordVisible)
views.exportDialogShowPassword.setImageResource(if (passwordVisible) R.drawable.ic_eye_closed else R.drawable.ic_eye) views.exportDialogShowPassword.render(passwordVisible)
} }
val exportDialog = builder.show() val exportDialog = builder.show()

View file

@ -44,7 +44,7 @@ class PromptPasswordDialog {
views.promptPasswordPasswordReveal.setOnClickListener { views.promptPasswordPasswordReveal.setOnClickListener {
passwordVisible = !passwordVisible passwordVisible = !passwordVisible
views.promptPassword.showPassword(passwordVisible) views.promptPassword.showPassword(passwordVisible)
views.promptPasswordPasswordReveal.setImageResource(if (passwordVisible) R.drawable.ic_eye_closed else R.drawable.ic_eye) views.promptPasswordPasswordReveal.render(passwordVisible)
} }
AlertDialog.Builder(activity) AlertDialog.Builder(activity)

View file

@ -21,7 +21,6 @@ import androidx.core.view.isVisible
import com.airbnb.epoxy.EpoxyAttribute import com.airbnb.epoxy.EpoxyAttribute
import im.vector.app.core.epoxy.VectorEpoxyModel import im.vector.app.core.epoxy.VectorEpoxyModel
import im.vector.app.core.extensions.setTextOrHide import im.vector.app.core.extensions.setTextOrHide
import im.vector.app.features.crypto.util.toImageRes
import im.vector.app.features.home.AvatarRenderer import im.vector.app.features.home.AvatarRenderer
import org.matrix.android.sdk.api.crypto.RoomEncryptionTrustLevel import org.matrix.android.sdk.api.crypto.RoomEncryptionTrustLevel
import org.matrix.android.sdk.api.util.MatrixItem import org.matrix.android.sdk.api.util.MatrixItem
@ -47,6 +46,6 @@ abstract class BaseProfileMatrixItem<T : ProfileMatrixItem.Holder> : VectorEpoxy
holder.subtitleView.setTextOrHide(matrixId) holder.subtitleView.setTextOrHide(matrixId)
holder.editableView.isVisible = editable holder.editableView.isVisible = editable
avatarRenderer.render(matrixItem, holder.avatarImageView) 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 com.airbnb.epoxy.EpoxyModelClass
import im.vector.app.R import im.vector.app.R
import im.vector.app.core.epoxy.VectorEpoxyHolder import im.vector.app.core.epoxy.VectorEpoxyHolder
import im.vector.app.core.ui.views.ShieldImageView
@EpoxyModelClass(layout = R.layout.item_profile_matrix_item) @EpoxyModelClass(layout = R.layout.item_profile_matrix_item)
abstract class ProfileMatrixItem : BaseProfileMatrixItem<ProfileMatrixItem.Holder>() { 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 titleView by bind<TextView>(R.id.matrixItemTitle)
val subtitleView by bind<TextView>(R.id.matrixItemSubtitle) val subtitleView by bind<TextView>(R.id.matrixItemSubtitle)
val avatarImageView by bind<ImageView>(R.id.matrixItemAvatar) 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) val editableView by bind<View>(R.id.matrixItemEditable)
} }
} }

View file

@ -19,17 +19,16 @@ package im.vector.app.core.extensions
import androidx.lifecycle.LifecycleOwner import androidx.lifecycle.LifecycleOwner
import androidx.lifecycle.LiveData import androidx.lifecycle.LiveData
import androidx.lifecycle.MutableLiveData import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.Observer
import im.vector.app.core.utils.EventObserver import im.vector.app.core.utils.EventObserver
import im.vector.app.core.utils.FirstThrottler import im.vector.app.core.utils.FirstThrottler
import im.vector.app.core.utils.LiveEvent import im.vector.app.core.utils.LiveEvent
inline fun <T> LiveData<T>.observeK(owner: LifecycleOwner, crossinline observer: (T?) -> Unit) { inline fun <T> LiveData<T>.observeK(owner: LifecycleOwner, crossinline observer: (T?) -> Unit) {
this.observe(owner, Observer { observer(it) }) this.observe(owner, { observer(it) })
} }
inline fun <T> LiveData<T>.observeNotNull(owner: LifecycleOwner, crossinline observer: (T) -> Unit) { inline fun <T> LiveData<T>.observeNotNull(owner: LifecycleOwner, crossinline observer: (T) -> Unit) {
this.observe(owner, Observer { it?.run(observer) }) this.observe(owner, { it?.run(observer) })
} }
inline fun <T> LiveData<LiveEvent<T>>.observeEvent(owner: LifecycleOwner, crossinline observer: (T) -> Unit) { inline fun <T> LiveData<LiveEvent<T>>.observeEvent(owner: LifecycleOwner, crossinline observer: (T) -> Unit) {

View file

@ -40,7 +40,6 @@ import androidx.core.view.isVisible
import androidx.fragment.app.Fragment import androidx.fragment.app.Fragment
import androidx.fragment.app.FragmentFactory import androidx.fragment.app.FragmentFactory
import androidx.fragment.app.FragmentManager import androidx.fragment.app.FragmentManager
import androidx.lifecycle.Observer
import androidx.lifecycle.ViewModelProvider import androidx.lifecycle.ViewModelProvider
import androidx.viewbinding.ViewBinding import androidx.viewbinding.ViewBinding
import com.bumptech.glide.util.Util import com.bumptech.glide.util.Util
@ -208,12 +207,12 @@ abstract class VectorBaseActivity<VB: ViewBinding> : AppCompatActivity(), HasScr
navigator = screenComponent.navigator() navigator = screenComponent.navigator()
activeSessionHolder = screenComponent.activeSessionHolder() activeSessionHolder = screenComponent.activeSessionHolder()
vectorPreferences = vectorComponent.vectorPreferences() vectorPreferences = vectorComponent.vectorPreferences()
configurationViewModel.activityRestarter.observe(this, Observer { configurationViewModel.activityRestarter.observe(this) {
if (!it.hasBeenHandled) { if (!it.hasBeenHandled) {
// Recreate the Activity because configuration has changed // Recreate the Activity because configuration has changed
restart() restart()
} }
}) }
pinLocker.getLiveState().observeNotNull(this) { pinLocker.getLiveState().observeNotNull(this) {
if (this@VectorBaseActivity !is UnlockedActivity && it == PinLocker.State.LOCKED) { if (this@VectorBaseActivity !is UnlockedActivity && it == PinLocker.State.LOCKED) {
navigator.openPinCode(this, pinStartForActivityResult, PinMode.AUTH) navigator.openPinCode(this, pinStartForActivityResult, PinMode.AUTH)

View file

@ -89,7 +89,7 @@ class KnownCallsViewHolder {
this.pipWrapper = pipWrapper this.pipWrapper = pipWrapper
this.currentCallsView?.callback = interactionListener this.currentCallsView?.callback = interactionListener
pipWrapper.setOnClickListener( pipWrapper.setOnClickListener(
DebouncedClickListener({ _ -> DebouncedClickListener({
interactionListener.onTapToReturnToCall() interactionListener.onTapToReturnToCall()
}) })
) )

View file

@ -56,6 +56,7 @@ class ReadReceiptsView @JvmOverloads constructor(
private fun setupView() { private fun setupView() {
inflate(context, R.layout.view_read_receipts, this) inflate(context, R.layout.view_read_receipts, this)
contentDescription = context.getString(R.string.a11y_view_read_receipts)
} }
fun render(readReceipts: List<ReadReceiptData>, avatarRenderer: AvatarRenderer, clickListener: OnClickListener) { fun render(readReceipts: List<ReadReceiptData>, avatarRenderer: AvatarRenderer, clickListener: OnClickListener) {

View file

@ -0,0 +1,43 @@
/*
* 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 im.vector.app.R
class RevealPasswordImageView @JvmOverloads constructor(
context: Context,
attrs: AttributeSet? = null,
defStyleAttr: Int = 0
) : AppCompatImageView(context, attrs, defStyleAttr) {
init {
render(false)
}
fun render(isPasswordShown: Boolean) {
if (isPasswordShown) {
contentDescription = context.getString(R.string.a11y_hide_password)
setImageResource(R.drawable.ic_eye_closed)
} else {
contentDescription = context.getString(R.string.a11y_show_password)
setImageResource(R.drawable.ic_eye)
}
}
}

View file

@ -0,0 +1,66 @@
/*
* 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.annotation.DrawableRes
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)
}
}
}
}
@DrawableRes
fun RoomEncryptionTrustLevel.toDrawableRes(): Int {
return when (this) {
RoomEncryptionTrustLevel.Default -> R.drawable.ic_shield_black
RoomEncryptionTrustLevel.Warning -> R.drawable.ic_shield_warning
RoomEncryptionTrustLevel.Trusted -> R.drawable.ic_shield_trusted
}
}

View file

@ -27,8 +27,8 @@ class CountUpTimer(private val intervalInMs: Long) {
private val resumed: AtomicBoolean = AtomicBoolean(false) private val resumed: AtomicBoolean = AtomicBoolean(false)
private val disposable = Observable.interval(intervalInMs, TimeUnit.MILLISECONDS) private val disposable = Observable.interval(intervalInMs, TimeUnit.MILLISECONDS)
.filter { _ -> resumed.get() } .filter { resumed.get() }
.doOnNext { _ -> elapsedTime.addAndGet(intervalInMs) } .doOnNext { elapsedTime.addAndGet(intervalInMs) }
.subscribe { .subscribe {
tickListener?.onTick(elapsedTime.get()) tickListener?.onTick(elapsedTime.get())
} }

View file

@ -49,7 +49,7 @@ open class BehaviorDataSource<T>(private val defaultValue: T? = null) : MutableD
private fun createRelay(): BehaviorRelay<T> { private fun createRelay(): BehaviorRelay<T> {
return if (defaultValue == null) { return if (defaultValue == null) {
BehaviorRelay.create<T>() BehaviorRelay.create()
} else { } else {
BehaviorRelay.createDefault(defaultValue) BehaviorRelay.createDefault(defaultValue)
} }

View file

@ -19,12 +19,11 @@ package im.vector.app.core.utils
import io.reactivex.Completable import io.reactivex.Completable
import io.reactivex.Single import io.reactivex.Single
import io.reactivex.disposables.Disposable import io.reactivex.disposables.Disposable
import io.reactivex.functions.Consumer
import io.reactivex.internal.functions.Functions import io.reactivex.internal.functions.Functions
import timber.log.Timber import timber.log.Timber
fun <T> Single<T>.subscribeLogError(): Disposable { fun <T> Single<T>.subscribeLogError(): Disposable {
return subscribe(Functions.emptyConsumer(), Consumer { Timber.e(it) }) return subscribe(Functions.emptyConsumer(), { Timber.e(it) })
} }
fun Completable.subscribeLogError(): Disposable { fun Completable.subscribeLogError(): Disposable {

View file

@ -87,14 +87,7 @@ class PromptFragment : VectorBaseFragment<FragmentReauthConfirmBinding>() {
} }
views.passwordField.showPassword(it.passwordVisible) views.passwordField.showPassword(it.passwordVisible)
views.passwordReveal.render(it.passwordVisible)
if (it.passwordVisible) {
views.passwordReveal.setImageResource(R.drawable.ic_eye_closed)
views.passwordReveal.contentDescription = getString(R.string.a11y_hide_password)
} else {
views.passwordReveal.setImageResource(R.drawable.ic_eye)
views.passwordReveal.contentDescription = getString(R.string.a11y_show_password)
}
if (it.lastErrorCode != null) { if (it.lastErrorCode != null) {
when (it.flowType) { when (it.flowType) {

View file

@ -102,7 +102,7 @@ abstract class RecyclerViewPresenter<T>(context: Context?) : AutocompletePresent
return LinearLayoutManager(context, LinearLayoutManager.VERTICAL, false) return LinearLayoutManager(context, LinearLayoutManager.VERTICAL, false)
} }
private class Observer internal constructor(private val root: DataSetObserver) : RecyclerView.AdapterDataObserver() { private class Observer constructor(private val root: DataSetObserver) : RecyclerView.AdapterDataObserver() {
override fun onChanged() { override fun onChanged() {
root.onChanged() root.onChanged()
} }

View file

@ -31,7 +31,7 @@ import org.matrix.android.sdk.api.session.room.model.RoomMemberSummary
class AutocompleteMemberPresenter @AssistedInject constructor(context: Context, class AutocompleteMemberPresenter @AssistedInject constructor(context: Context,
@Assisted val roomId: String, @Assisted val roomId: String,
private val session: Session, session: Session,
private val controller: AutocompleteMemberController private val controller: AutocompleteMemberController
) : RecyclerViewPresenter<RoomMemberSummary>(context), AutocompleteClickListener<RoomMemberSummary> { ) : RecyclerViewPresenter<RoomMemberSummary>(context), AutocompleteClickListener<RoomMemberSummary> {

View file

@ -383,7 +383,7 @@ class VectorCallActivity : VectorBaseActivity<ActivityCallBinding>(), CallContro
mode: String?): Intent { mode: String?): Intent {
return Intent(context, VectorCallActivity::class.java).apply { return Intent(context, VectorCallActivity::class.java).apply {
// what could be the best flags? // what could be the best flags?
flags = Intent.FLAG_ACTIVITY_CLEAR_TOP flags = FLAG_ACTIVITY_CLEAR_TOP
putExtra(MvRx.KEY_ARG, CallArgs(roomId, callId, otherUserId, isIncomingCall, isVideoCall)) putExtra(MvRx.KEY_ARG, CallArgs(roomId, callId, otherUserId, isIncomingCall, isVideoCall))
putExtra(EXTRA_MODE, mode) putExtra(EXTRA_MODE, mode)
} }

View file

@ -19,7 +19,6 @@ import android.app.Activity
import android.content.Context import android.content.Context
import android.content.Intent import android.content.Intent
import androidx.appcompat.app.AlertDialog import androidx.appcompat.app.AlertDialog
import androidx.lifecycle.Observer
import im.vector.app.R import im.vector.app.R
import im.vector.app.core.extensions.addFragmentToBackstack import im.vector.app.core.extensions.addFragmentToBackstack
import im.vector.app.core.extensions.observeEvent import im.vector.app.core.extensions.observeEvent
@ -54,7 +53,7 @@ class KeysBackupRestoreActivity : SimpleFragmentActivity() {
viewModel = viewModelProvider.get(KeysBackupRestoreSharedViewModel::class.java) viewModel = viewModelProvider.get(KeysBackupRestoreSharedViewModel::class.java)
viewModel.initSession(session) viewModel.initSession(session)
viewModel.keySourceModel.observe(this, Observer { keySource -> viewModel.keySourceModel.observe(this) { keySource ->
if (keySource != null && !keySource.isInQuadS && supportFragmentManager.fragments.isEmpty()) { if (keySource != null && !keySource.isInQuadS && supportFragmentManager.fragments.isEmpty()) {
val isBackupCreatedFromPassphrase = val isBackupCreatedFromPassphrase =
viewModel.keyVersionResult.value?.getAuthDataAsMegolmBackupAuthData()?.privateKeySalt != null viewModel.keyVersionResult.value?.getAuthDataAsMegolmBackupAuthData()?.privateKeySalt != null
@ -64,7 +63,7 @@ class KeysBackupRestoreActivity : SimpleFragmentActivity() {
replaceFragment(R.id.container, KeysBackupRestoreFromKeyFragment::class.java) replaceFragment(R.id.container, KeysBackupRestoreFromKeyFragment::class.java)
} }
} }
}) }
viewModel.keyVersionResultError.observeEvent(this) { message -> viewModel.keyVersionResultError.observeEvent(this) { message ->
AlertDialog.Builder(this) AlertDialog.Builder(this)
@ -111,9 +110,9 @@ class KeysBackupRestoreActivity : SimpleFragmentActivity() {
} }
} }
viewModel.loadingEvent.observe(this, Observer { viewModel.loadingEvent.observe(this) {
updateWaitingView(it) updateWaitingView(it)
}) }
viewModel.importRoomKeysFinishWithResult.observeEvent(this) { viewModel.importRoomKeysFinishWithResult.observeEvent(this) {
// set data? // set data?

View file

@ -22,7 +22,6 @@ import android.view.View
import android.view.ViewGroup import android.view.ViewGroup
import android.view.inputmethod.EditorInfo import android.view.inputmethod.EditorInfo
import androidx.core.widget.doOnTextChanged import androidx.core.widget.doOnTextChanged
import androidx.lifecycle.Observer
import im.vector.app.R import im.vector.app.R
import im.vector.app.core.extensions.registerStartForActivityResult import im.vector.app.core.extensions.registerStartForActivityResult
import im.vector.app.core.platform.VectorBaseFragment import im.vector.app.core.platform.VectorBaseFragment
@ -56,9 +55,9 @@ class KeysBackupRestoreFromKeyFragment @Inject constructor()
} }
views.keyInputLayout.error = viewModel.recoveryCodeErrorText.value views.keyInputLayout.error = viewModel.recoveryCodeErrorText.value
viewModel.recoveryCodeErrorText.observe(viewLifecycleOwner, Observer { newValue -> viewModel.recoveryCodeErrorText.observe(viewLifecycleOwner) { newValue ->
views.keyInputLayout.error = newValue views.keyInputLayout.error = newValue
}) }
views.keysRestoreButton.setOnClickListener { onRestoreFromKey() } views.keysRestoreButton.setOnClickListener { onRestoreFromKey() }
views.keysBackupImport.setOnClickListener { onImport() } views.keysBackupImport.setOnClickListener { onImport() }

View file

@ -24,7 +24,6 @@ import android.view.ViewGroup
import android.view.inputmethod.EditorInfo import android.view.inputmethod.EditorInfo
import androidx.core.text.set import androidx.core.text.set
import androidx.core.widget.doOnTextChanged import androidx.core.widget.doOnTextChanged
import androidx.lifecycle.Observer
import im.vector.app.R import im.vector.app.R
import im.vector.app.core.extensions.showPassword import im.vector.app.core.extensions.showPassword
import im.vector.app.core.platform.VectorBaseFragment import im.vector.app.core.platform.VectorBaseFragment
@ -51,17 +50,17 @@ class KeysBackupRestoreFromPassphraseFragment @Inject constructor() : VectorBase
viewModel = fragmentViewModelProvider.get(KeysBackupRestoreFromPassphraseViewModel::class.java) viewModel = fragmentViewModelProvider.get(KeysBackupRestoreFromPassphraseViewModel::class.java)
sharedViewModel = activityViewModelProvider.get(KeysBackupRestoreSharedViewModel::class.java) sharedViewModel = activityViewModelProvider.get(KeysBackupRestoreSharedViewModel::class.java)
viewModel.passphraseErrorText.observe(viewLifecycleOwner, Observer { newValue -> viewModel.passphraseErrorText.observe(viewLifecycleOwner) { newValue ->
views.keysBackupPassphraseEnterTil.error = newValue views.keysBackupPassphraseEnterTil.error = newValue
}) }
views.helperTextWithLink.text = spannableStringForHelperText() views.helperTextWithLink.text = spannableStringForHelperText()
viewModel.showPasswordMode.observe(viewLifecycleOwner, Observer { viewModel.showPasswordMode.observe(viewLifecycleOwner) {
val shouldBeVisible = it ?: false val shouldBeVisible = it ?: false
views.keysBackupPassphraseEnterEdittext.showPassword(shouldBeVisible) views.keysBackupPassphraseEnterEdittext.showPassword(shouldBeVisible)
views.keysBackupViewShowPassword.setImageResource(if (shouldBeVisible) R.drawable.ic_eye_closed else R.drawable.ic_eye) views.keysBackupViewShowPassword.render(shouldBeVisible)
}) }
views.keysBackupPassphraseEnterEdittext.setOnEditorActionListener { _, actionId, _ -> views.keysBackupPassphraseEnterEdittext.setOnEditorActionListener { _, actionId, _ ->
if (actionId == EditorInfo.IME_ACTION_DONE) { if (actionId == EditorInfo.IME_ACTION_DONE) {

View file

@ -21,7 +21,6 @@ import android.content.Intent
import androidx.appcompat.app.AlertDialog import androidx.appcompat.app.AlertDialog
import androidx.core.view.isVisible import androidx.core.view.isVisible
import androidx.fragment.app.FragmentManager import androidx.fragment.app.FragmentManager
import androidx.lifecycle.Observer
import im.vector.app.R import im.vector.app.R
import im.vector.app.core.dialogs.ExportKeysDialog import im.vector.app.core.dialogs.ExportKeysDialog
import im.vector.app.core.extensions.observeEvent import im.vector.app.core.extensions.observeEvent
@ -49,20 +48,20 @@ class KeysBackupSetupActivity : SimpleFragmentActivity() {
viewModel.showManualExport.value = intent.getBooleanExtra(EXTRA_SHOW_MANUAL_EXPORT, false) viewModel.showManualExport.value = intent.getBooleanExtra(EXTRA_SHOW_MANUAL_EXPORT, false)
viewModel.initSession(session) viewModel.initSession(session)
viewModel.isCreatingBackupVersion.observe(this, Observer { viewModel.isCreatingBackupVersion.observe(this) {
val isCreating = it ?: false val isCreating = it ?: false
if (isCreating) { if (isCreating) {
showWaitingView() showWaitingView()
} else { } else {
hideWaitingView() hideWaitingView()
} }
}) }
viewModel.loadingStatus.observe(this, Observer { viewModel.loadingStatus.observe(this) {
it?.let { it?.let {
updateWaitingView(it) updateWaitingView(it)
} }
}) }
viewModel.navigateEvent.observeEvent(this) { uxStateEvent -> viewModel.navigateEvent.observeEvent(this) { uxStateEvent ->
when (uxStateEvent) { when (uxStateEvent) {
@ -99,7 +98,7 @@ class KeysBackupSetupActivity : SimpleFragmentActivity() {
} }
} }
viewModel.prepareRecoverFailError.observe(this, Observer { error -> viewModel.prepareRecoverFailError.observe(this) { error ->
if (error != null) { if (error != null) {
AlertDialog.Builder(this) AlertDialog.Builder(this)
.setTitle(R.string.unknown_error) .setTitle(R.string.unknown_error)
@ -110,9 +109,9 @@ class KeysBackupSetupActivity : SimpleFragmentActivity() {
} }
.show() .show()
} }
}) }
viewModel.creatingBackupError.observe(this, Observer { error -> viewModel.creatingBackupError.observe(this) { error ->
if (error != null) { if (error != null) {
AlertDialog.Builder(this) AlertDialog.Builder(this)
.setTitle(R.string.unexpected_error) .setTitle(R.string.unexpected_error)
@ -123,7 +122,7 @@ class KeysBackupSetupActivity : SimpleFragmentActivity() {
} }
.show() .show()
} }
}) }
} }
private val saveStartForActivityResult = registerStartForActivityResult { activityResult -> private val saveStartForActivityResult = registerStartForActivityResult { activityResult ->

View file

@ -20,7 +20,6 @@ import android.os.Bundle
import android.view.LayoutInflater import android.view.LayoutInflater
import android.view.View import android.view.View
import android.view.ViewGroup import android.view.ViewGroup
import androidx.lifecycle.Observer
import im.vector.app.core.platform.VectorBaseFragment import im.vector.app.core.platform.VectorBaseFragment
import im.vector.app.core.utils.LiveEvent import im.vector.app.core.utils.LiveEvent
import im.vector.app.databinding.FragmentKeysBackupSetupStep1Binding import im.vector.app.databinding.FragmentKeysBackupSetupStep1Binding
@ -40,12 +39,12 @@ class KeysBackupSetupStep1Fragment @Inject constructor() : VectorBaseFragment<Fr
viewModel = activityViewModelProvider.get(KeysBackupSetupSharedViewModel::class.java) viewModel = activityViewModelProvider.get(KeysBackupSetupSharedViewModel::class.java)
viewModel.showManualExport.observe(viewLifecycleOwner, Observer { viewModel.showManualExport.observe(viewLifecycleOwner) {
val showOption = it ?: false val showOption = it ?: false
// Can't use isVisible because the kotlin compiler will crash with Back-end (JVM) Internal error: wrong code generated // Can't use isVisible because the kotlin compiler will crash with Back-end (JVM) Internal error: wrong code generated
views.keysBackupSetupStep1AdvancedOptionText.visibility = if (showOption) View.VISIBLE else View.GONE views.keysBackupSetupStep1AdvancedOptionText.visibility = if (showOption) View.VISIBLE else View.GONE
views.keysBackupSetupStep1ManualExportButton.visibility = if (showOption) View.VISIBLE else View.GONE views.keysBackupSetupStep1ManualExportButton.visibility = if (showOption) View.VISIBLE else View.GONE
}) }
views.keysBackupSetupStep1Button.setOnClickListener { onButtonClick() } views.keysBackupSetupStep1Button.setOnClickListener { onButtonClick() }
views.keysBackupSetupStep1ManualExportButton.setOnClickListener { onManualExportClick() } views.keysBackupSetupStep1ManualExportButton.setOnClickListener { onManualExportClick() }

View file

@ -21,7 +21,6 @@ import android.view.View
import android.view.ViewGroup import android.view.ViewGroup
import android.view.inputmethod.EditorInfo import android.view.inputmethod.EditorInfo
import androidx.core.widget.doOnTextChanged import androidx.core.widget.doOnTextChanged
import androidx.lifecycle.Observer
import androidx.lifecycle.viewModelScope import androidx.lifecycle.viewModelScope
import androidx.transition.TransitionManager import androidx.transition.TransitionManager
import com.nulabinc.zxcvbn.Zxcvbn import com.nulabinc.zxcvbn.Zxcvbn
@ -30,7 +29,6 @@ import im.vector.app.core.extensions.showPassword
import im.vector.app.core.platform.VectorBaseFragment import im.vector.app.core.platform.VectorBaseFragment
import im.vector.app.databinding.FragmentKeysBackupSetupStep2Binding import im.vector.app.databinding.FragmentKeysBackupSetupStep2Binding
import im.vector.app.features.settings.VectorLocale import im.vector.app.features.settings.VectorLocale
import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
import javax.inject.Inject import javax.inject.Inject
@ -69,7 +67,7 @@ class KeysBackupSetupStep2Fragment @Inject constructor() : VectorBaseFragment<Fr
* ========================================================================================== */ * ========================================================================================== */
private fun bindViewToViewModel() { private fun bindViewToViewModel() {
viewModel.passwordStrength.observe(viewLifecycleOwner, Observer { strength -> viewModel.passwordStrength.observe(viewLifecycleOwner) { strength ->
if (strength == null) { if (strength == null) {
views.keysBackupSetupStep2PassphraseStrengthLevel.strength = 0 views.keysBackupSetupStep2PassphraseStrengthLevel.strength = 0
views.keysBackupSetupStep2PassphraseEnterTil.error = null views.keysBackupSetupStep2PassphraseEnterTil.error = null
@ -91,9 +89,9 @@ class KeysBackupSetupStep2Fragment @Inject constructor() : VectorBaseFragment<Fr
views.keysBackupSetupStep2PassphraseEnterTil.error = null views.keysBackupSetupStep2PassphraseEnterTil.error = null
} }
} }
}) }
viewModel.passphrase.observe(viewLifecycleOwner, Observer<String> { newValue -> viewModel.passphrase.observe(viewLifecycleOwner) { newValue ->
if (newValue.isEmpty()) { if (newValue.isEmpty()) {
viewModel.passwordStrength.value = null viewModel.passwordStrength.value = null
} else { } else {
@ -104,28 +102,28 @@ class KeysBackupSetupStep2Fragment @Inject constructor() : VectorBaseFragment<Fr
} }
} }
} }
}) }
views.keysBackupSetupStep2PassphraseEnterEdittext.setText(viewModel.passphrase.value) views.keysBackupSetupStep2PassphraseEnterEdittext.setText(viewModel.passphrase.value)
viewModel.passphraseError.observe(viewLifecycleOwner, Observer { viewModel.passphraseError.observe(viewLifecycleOwner) {
TransitionManager.beginDelayedTransition(views.keysBackupRoot) TransitionManager.beginDelayedTransition(views.keysBackupRoot)
views.keysBackupSetupStep2PassphraseEnterTil.error = it views.keysBackupSetupStep2PassphraseEnterTil.error = it
}) }
views.keysBackupSetupStep2PassphraseConfirmEditText.setText(viewModel.confirmPassphrase.value) views.keysBackupSetupStep2PassphraseConfirmEditText.setText(viewModel.confirmPassphrase.value)
viewModel.showPasswordMode.observe(viewLifecycleOwner, Observer { viewModel.showPasswordMode.observe(viewLifecycleOwner) {
val shouldBeVisible = it ?: false val shouldBeVisible = it ?: false
views.keysBackupSetupStep2PassphraseEnterEdittext.showPassword(shouldBeVisible) views.keysBackupSetupStep2PassphraseEnterEdittext.showPassword(shouldBeVisible)
views.keysBackupSetupStep2PassphraseConfirmEditText.showPassword(shouldBeVisible) views.keysBackupSetupStep2PassphraseConfirmEditText.showPassword(shouldBeVisible)
views.keysBackupSetupStep2ShowPassword.setImageResource(if (shouldBeVisible) R.drawable.ic_eye_closed else R.drawable.ic_eye) views.keysBackupSetupStep2ShowPassword.render(shouldBeVisible)
}) }
viewModel.confirmPassphraseError.observe(viewLifecycleOwner, Observer { viewModel.confirmPassphraseError.observe(viewLifecycleOwner) {
TransitionManager.beginDelayedTransition(views.keysBackupRoot) TransitionManager.beginDelayedTransition(views.keysBackupRoot)
views.keysBackupSetupStep2PassphraseConfirmTil.error = it views.keysBackupSetupStep2PassphraseConfirmTil.error = it
}) }
views.keysBackupSetupStep2PassphraseConfirmEditText.setOnEditorActionListener { _, actionId, _ -> views.keysBackupSetupStep2PassphraseConfirmEditText.setOnEditorActionListener { _, actionId, _ ->
if (actionId == EditorInfo.IME_ACTION_DONE) { if (actionId == EditorInfo.IME_ACTION_DONE) {
@ -141,8 +139,8 @@ class KeysBackupSetupStep2Fragment @Inject constructor() : VectorBaseFragment<Fr
views.keysBackupSetupStep2Button.setOnClickListener { doNext() } views.keysBackupSetupStep2Button.setOnClickListener { doNext() }
views.keysBackupSetupStep2SkipButton.setOnClickListener { skipPassphrase() } views.keysBackupSetupStep2SkipButton.setOnClickListener { skipPassphrase() }
views.keysBackupSetupStep2PassphraseEnterEdittext.doOnTextChanged { _, _, _, _ -> onPassphraseChanged() } views.keysBackupSetupStep2PassphraseEnterEdittext.doOnTextChanged { _, _, _, _ -> onPassphraseChanged() }
views.keysBackupSetupStep2PassphraseConfirmEditText.doOnTextChanged { _, _, _, _ -> onConfirmPassphraseChanged() } views.keysBackupSetupStep2PassphraseConfirmEditText.doOnTextChanged { _, _, _, _ -> onConfirmPassphraseChanged() }
} }
private fun toggleVisibilityMode() { private fun toggleVisibilityMode() {

View file

@ -25,7 +25,6 @@ import android.widget.TextView
import android.widget.Toast import android.widget.Toast
import androidx.appcompat.app.AlertDialog import androidx.appcompat.app.AlertDialog
import androidx.core.view.isVisible import androidx.core.view.isVisible
import androidx.lifecycle.Observer
import arrow.core.Try import arrow.core.Try
import com.google.android.material.bottomsheet.BottomSheetDialog import com.google.android.material.bottomsheet.BottomSheetDialog
import im.vector.app.R import im.vector.app.R
@ -61,7 +60,7 @@ class KeysBackupSetupStep3Fragment @Inject constructor() : VectorBaseFragment<Fr
viewModel.shouldPromptOnBack = false viewModel.shouldPromptOnBack = false
viewModel.passphrase.observe(viewLifecycleOwner, Observer { viewModel.passphrase.observe(viewLifecycleOwner) {
if (it.isNullOrBlank()) { if (it.isNullOrBlank()) {
// Recovery was generated, so show key and options to save // Recovery was generated, so show key and options to save
views.keysBackupSetupStep3Label2.text = getString(R.string.keys_backup_setup_step3_text_line2_no_passphrase) views.keysBackupSetupStep3Label2.text = getString(R.string.keys_backup_setup_step3_text_line2_no_passphrase)
@ -81,7 +80,7 @@ class KeysBackupSetupStep3Fragment @Inject constructor() : VectorBaseFragment<Fr
views.keysBackupSetupStep3FinishButton.text = getString(R.string.keys_backup_setup_step3_button_title) views.keysBackupSetupStep3FinishButton.text = getString(R.string.keys_backup_setup_step3_button_title)
views.keysBackupSetupStep3RecoveryKeyText.isVisible = false views.keysBackupSetupStep3RecoveryKeyText.isVisible = false
} }
}) }
setupViews() setupViews()
} }

View file

@ -183,11 +183,11 @@ class KeyRequestHandler @Inject constructor(
denyAllRequests(mappingKey) denyAllRequests(mappingKey)
} }
alert.addButton(context.getString(R.string.share_without_verifying_short_label), Runnable { alert.addButton(context.getString(R.string.share_without_verifying_short_label), {
shareAllSessions(mappingKey) shareAllSessions(mappingKey)
}) })
alert.addButton(context.getString(R.string.ignore_request_short_label), Runnable { alert.addButton(context.getString(R.string.ignore_request_short_label), {
denyAllRequests(mappingKey) denyAllRequests(mappingKey)
}) })

View file

@ -106,6 +106,6 @@ class SharedSecuredStoragePassphraseFragment @Inject constructor(
override fun invalidate() = withState(sharedViewModel) { state -> override fun invalidate() = withState(sharedViewModel) { state ->
val shouldBeVisible = state.passphraseVisible val shouldBeVisible = state.passphraseVisible
views.ssssPassphraseEnterEdittext.showPassword(shouldBeVisible) views.ssssPassphraseEnterEdittext.showPassword(shouldBeVisible)
views.ssssViewShowPassword.setImageResource(if (shouldBeVisible) R.drawable.ic_eye_closed else R.drawable.ic_eye) views.ssssViewShowPassword.render(shouldBeVisible)
} }
} }

View file

@ -97,7 +97,7 @@ class BackupToQuadSMigrationTask @Inject constructor(
when { when {
params.passphrase?.isNotEmpty() == true -> { params.passphrase?.isNotEmpty() == true -> {
reportProgress(params, R.string.bootstrap_progress_generating_ssss) reportProgress(params, R.string.bootstrap_progress_generating_ssss)
awaitCallback<SsssKeyCreationInfo> { awaitCallback {
quadS.generateKeyWithPassphrase( quadS.generateKeyWithPassphrase(
UUID.randomUUID().toString(), UUID.randomUUID().toString(),
"ssss_key", "ssss_key",

View file

@ -109,7 +109,7 @@ class BootstrapConfirmPassphraseFragment @Inject constructor()
if (state.step is BootstrapStep.ConfirmPassphrase) { if (state.step is BootstrapStep.ConfirmPassphrase) {
val isPasswordVisible = state.step.isPasswordVisible val isPasswordVisible = state.step.isPasswordVisible
views.ssssPassphraseEnterEdittext.showPassword(isPasswordVisible, updateCursor = false) views.ssssPassphraseEnterEdittext.showPassword(isPasswordVisible, updateCursor = false)
views.ssssViewShowPassword.setImageResource(if (isPasswordVisible) R.drawable.ic_eye_closed else R.drawable.ic_eye) views.ssssViewShowPassword.render(isPasswordVisible)
} }
} }
} }

View file

@ -103,7 +103,7 @@ class BootstrapEnterPassphraseFragment @Inject constructor()
if (state.step is BootstrapStep.SetupPassphrase) { if (state.step is BootstrapStep.SetupPassphrase) {
val isPasswordVisible = state.step.isPasswordVisible val isPasswordVisible = state.step.isPasswordVisible
views.ssssPassphraseEnterEdittext.showPassword(isPasswordVisible, updateCursor = false) views.ssssPassphraseEnterEdittext.showPassword(isPasswordVisible, updateCursor = false)
views.ssssViewShowPassword.setImageResource(if (isPasswordVisible) R.drawable.ic_eye_closed else R.drawable.ic_eye) views.ssssViewShowPassword.render(isPasswordVisible)
state.passphraseStrength.invoke()?.let { strength -> state.passphraseStrength.invoke()?.let { strength ->
val score = strength.score val score = strength.score

View file

@ -133,7 +133,7 @@ class BootstrapMigrateBackupFragment @Inject constructor(
if (state.step is BootstrapStep.GetBackupSecretPassForMigration) { if (state.step is BootstrapStep.GetBackupSecretPassForMigration) {
val isPasswordVisible = state.step.isPasswordVisible val isPasswordVisible = state.step.isPasswordVisible
views.bootstrapMigrateEditText.showPassword(isPasswordVisible, updateCursor = false) views.bootstrapMigrateEditText.showPassword(isPasswordVisible, updateCursor = false)
views.bootstrapMigrateShowPassword.setImageResource(if (isPasswordVisible) R.drawable.ic_eye_closed else R.drawable.ic_eye) views.bootstrapMigrateShowPassword.render(isPasswordVisible)
} }
views.bootstrapDescriptionText.text = getString(R.string.bootstrap_migration_enter_backup_password) views.bootstrapDescriptionText.text = getString(R.string.bootstrap_migration_enter_backup_password)

View file

@ -62,8 +62,7 @@ class BootstrapSaveRecoveryKeyFragment @Inject constructor(
} }
} }
private fun downloadRecoveryKey() = withState(sharedViewModel) { _ -> private fun downloadRecoveryKey() {
val intent = Intent(Intent.ACTION_CREATE_DOCUMENT) val intent = Intent(Intent.ACTION_CREATE_DOCUMENT)
intent.addCategory(Intent.CATEGORY_OPENABLE) intent.addCategory(Intent.CATEGORY_OPENABLE)
intent.type = "text/plain" intent.type = "text/plain"

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

@ -92,13 +92,11 @@ class IncomingVerificationRequestHandler @Inject constructor(
} }
addButton( addButton(
context.getString(R.string.ignore), context.getString(R.string.ignore),
Runnable { { tx.cancel() }
tx.cancel()
}
) )
addButton( addButton(
context.getString(R.string.action_open), context.getString(R.string.action_open),
Runnable { {
(weakCurrentActivity?.get() as? VectorBaseActivity<*>)?.let { (weakCurrentActivity?.get() as? VectorBaseActivity<*>)?.let {
it.navigator.performDeviceVerification(it, tx.otherUserId, tx.transactionId) it.navigator.performDeviceVerification(it, tx.otherUserId, tx.transactionId)
} }

View file

@ -24,7 +24,6 @@ import android.view.LayoutInflater
import android.view.View import android.view.View
import android.view.ViewGroup import android.view.ViewGroup
import androidx.appcompat.app.AlertDialog import androidx.appcompat.app.AlertDialog
import androidx.core.view.isVisible
import androidx.fragment.app.Fragment import androidx.fragment.app.Fragment
import com.airbnb.mvrx.MvRx import com.airbnb.mvrx.MvRx
import com.airbnb.mvrx.fragmentViewModel import com.airbnb.mvrx.fragmentViewModel
@ -49,6 +48,7 @@ import im.vector.app.features.crypto.verification.request.VerificationRequestFra
import im.vector.app.features.home.AvatarRenderer import im.vector.app.features.home.AvatarRenderer
import im.vector.app.features.settings.VectorSettingsActivity import im.vector.app.features.settings.VectorSettingsActivity
import kotlinx.parcelize.Parcelize import kotlinx.parcelize.Parcelize
import org.matrix.android.sdk.api.crypto.RoomEncryptionTrustLevel
import org.matrix.android.sdk.api.session.Session import org.matrix.android.sdk.api.session.Session
import org.matrix.android.sdk.api.session.crypto.crosssigning.KEYBACKUP_SECRET_SSSS_NAME import org.matrix.android.sdk.api.session.crypto.crosssigning.KEYBACKUP_SECRET_SSSS_NAME
import org.matrix.android.sdk.api.session.crypto.crosssigning.MASTER_KEY_SSSS_NAME import org.matrix.android.sdk.api.session.crypto.crosssigning.MASTER_KEY_SSSS_NAME
@ -162,23 +162,22 @@ class VerificationBottomSheet : VectorBaseBottomSheetDialogFragment<BottomSheetV
if (state.sasTransactionState == VerificationTxState.Verified if (state.sasTransactionState == VerificationTxState.Verified
|| state.qrTransactionState == VerificationTxState.Verified || state.qrTransactionState == VerificationTxState.Verified
|| state.verifiedFromPrivateKeys) { || state.verifiedFromPrivateKeys) {
views.otherUserShield.setImageResource(R.drawable.ic_shield_trusted) views.otherUserShield.render(RoomEncryptionTrustLevel.Trusted)
} else { } else {
views.otherUserShield.setImageResource(R.drawable.ic_shield_warning) views.otherUserShield.render(RoomEncryptionTrustLevel.Warning)
} }
views.otherUserNameText.text = getString( views.otherUserNameText.text = getString(
if (state.selfVerificationMode) R.string.crosssigning_verify_this_session else R.string.crosssigning_verify_session if (state.selfVerificationMode) R.string.crosssigning_verify_this_session else R.string.crosssigning_verify_session
) )
views.otherUserShield.isVisible = true
} else { } else {
avatarRenderer.render(matrixItem, views.otherUserAvatarImageView) avatarRenderer.render(matrixItem, views.otherUserAvatarImageView)
if (state.sasTransactionState == VerificationTxState.Verified || state.qrTransactionState == VerificationTxState.Verified) { if (state.sasTransactionState == VerificationTxState.Verified || state.qrTransactionState == VerificationTxState.Verified) {
views.otherUserNameText.text = getString(R.string.verification_verified_user, matrixItem.getBestName()) views.otherUserNameText.text = getString(R.string.verification_verified_user, matrixItem.getBestName())
views.otherUserShield.isVisible = true views.otherUserShield.render(RoomEncryptionTrustLevel.Trusted)
} else { } else {
views.otherUserNameText.text = getString(R.string.verification_verify_user, matrixItem.getBestName()) views.otherUserNameText.text = getString(R.string.verification_verify_user, matrixItem.getBestName())
views.otherUserShield.isVisible = false views.otherUserShield.render(null)
} }
} }
} }

View file

@ -25,6 +25,7 @@ import im.vector.app.features.crypto.verification.epoxy.bottomSheetVerificationA
import im.vector.app.features.crypto.verification.epoxy.bottomSheetVerificationBigImageItem import im.vector.app.features.crypto.verification.epoxy.bottomSheetVerificationBigImageItem
import im.vector.app.features.crypto.verification.epoxy.bottomSheetVerificationNoticeItem import im.vector.app.features.crypto.verification.epoxy.bottomSheetVerificationNoticeItem
import im.vector.app.features.html.EventHtmlRenderer import im.vector.app.features.html.EventHtmlRenderer
import org.matrix.android.sdk.api.crypto.RoomEncryptionTrustLevel
import javax.inject.Inject import javax.inject.Inject
class VerificationConclusionController @Inject constructor( class VerificationConclusionController @Inject constructor(
@ -56,7 +57,7 @@ class VerificationConclusionController @Inject constructor(
bottomSheetVerificationBigImageItem { bottomSheetVerificationBigImageItem {
id("image") id("image")
imageRes(R.drawable.ic_shield_trusted) roomEncryptionTrustLevel(RoomEncryptionTrustLevel.Trusted)
} }
bottomDone() bottomDone()
@ -69,7 +70,7 @@ class VerificationConclusionController @Inject constructor(
bottomSheetVerificationBigImageItem { bottomSheetVerificationBigImageItem {
id("image") id("image")
imageRes(R.drawable.ic_shield_warning) roomEncryptionTrustLevel(RoomEncryptionTrustLevel.Warning)
} }
bottomSheetVerificationNoticeItem { bottomSheetVerificationNoticeItem {

View file

@ -16,13 +16,13 @@
*/ */
package im.vector.app.features.crypto.verification.epoxy package im.vector.app.features.crypto.verification.epoxy
import android.widget.ImageView
import androidx.core.view.ViewCompat
import com.airbnb.epoxy.EpoxyAttribute import com.airbnb.epoxy.EpoxyAttribute
import com.airbnb.epoxy.EpoxyModelClass import com.airbnb.epoxy.EpoxyModelClass
import im.vector.app.R import im.vector.app.R
import im.vector.app.core.epoxy.VectorEpoxyHolder import im.vector.app.core.epoxy.VectorEpoxyHolder
import im.vector.app.core.epoxy.VectorEpoxyModel import im.vector.app.core.epoxy.VectorEpoxyModel
import im.vector.app.core.ui.views.ShieldImageView
import org.matrix.android.sdk.api.crypto.RoomEncryptionTrustLevel
/** /**
* A action for bottom sheet. * A action for bottom sheet.
@ -31,24 +31,14 @@ import im.vector.app.core.epoxy.VectorEpoxyModel
abstract class BottomSheetVerificationBigImageItem : VectorEpoxyModel<BottomSheetVerificationBigImageItem.Holder>() { abstract class BottomSheetVerificationBigImageItem : VectorEpoxyModel<BottomSheetVerificationBigImageItem.Holder>() {
@EpoxyAttribute @EpoxyAttribute
var imageRes: Int = 0 lateinit var roomEncryptionTrustLevel: RoomEncryptionTrustLevel
@EpoxyAttribute
var contentDescription: String? = null
override fun bind(holder: Holder) { override fun bind(holder: Holder) {
super.bind(holder) super.bind(holder)
holder.image.setImageResource(imageRes) holder.image.render(roomEncryptionTrustLevel)
if (contentDescription == null) {
ViewCompat.setImportantForAccessibility(holder.image, ViewCompat.IMPORTANT_FOR_ACCESSIBILITY_NO)
} else {
ViewCompat.setImportantForAccessibility(holder.image, ViewCompat.IMPORTANT_FOR_ACCESSIBILITY_YES)
holder.image.contentDescription = contentDescription
}
} }
class Holder : VectorEpoxyHolder() { class Holder : VectorEpoxyHolder() {
val image by bind<ImageView>(R.id.itemVerificationBigImage) val image by bind<ShieldImageView>(R.id.itemVerificationBigImage)
} }
} }

View file

@ -23,6 +23,7 @@ import im.vector.app.core.resources.StringProvider
import im.vector.app.features.crypto.verification.epoxy.bottomSheetVerificationBigImageItem import im.vector.app.features.crypto.verification.epoxy.bottomSheetVerificationBigImageItem
import im.vector.app.features.crypto.verification.epoxy.bottomSheetVerificationNoticeItem import im.vector.app.features.crypto.verification.epoxy.bottomSheetVerificationNoticeItem
import im.vector.app.features.crypto.verification.epoxy.bottomSheetVerificationWaitingItem import im.vector.app.features.crypto.verification.epoxy.bottomSheetVerificationWaitingItem
import org.matrix.android.sdk.api.crypto.RoomEncryptionTrustLevel
import javax.inject.Inject import javax.inject.Inject
class VerificationQRWaitingController @Inject constructor( class VerificationQRWaitingController @Inject constructor(
@ -49,7 +50,7 @@ class VerificationQRWaitingController @Inject constructor(
bottomSheetVerificationBigImageItem { bottomSheetVerificationBigImageItem {
id("image") id("image")
imageRes(R.drawable.ic_shield_trusted) roomEncryptionTrustLevel(RoomEncryptionTrustLevel.Trusted)
} }
bottomSheetVerificationWaitingItem { bottomSheetVerificationWaitingItem {

View file

@ -25,6 +25,7 @@ import im.vector.app.features.crypto.verification.VerificationBottomSheetViewSta
import im.vector.app.features.crypto.verification.epoxy.bottomSheetVerificationActionItem import im.vector.app.features.crypto.verification.epoxy.bottomSheetVerificationActionItem
import im.vector.app.features.crypto.verification.epoxy.bottomSheetVerificationBigImageItem import im.vector.app.features.crypto.verification.epoxy.bottomSheetVerificationBigImageItem
import im.vector.app.features.crypto.verification.epoxy.bottomSheetVerificationNoticeItem import im.vector.app.features.crypto.verification.epoxy.bottomSheetVerificationNoticeItem
import org.matrix.android.sdk.api.crypto.RoomEncryptionTrustLevel
import javax.inject.Inject import javax.inject.Inject
class VerificationQrScannedByOtherController @Inject constructor( class VerificationQrScannedByOtherController @Inject constructor(
@ -58,7 +59,7 @@ class VerificationQrScannedByOtherController @Inject constructor(
bottomSheetVerificationBigImageItem { bottomSheetVerificationBigImageItem {
id("image") id("image")
imageRes(R.drawable.ic_shield_trusted) roomEncryptionTrustLevel(RoomEncryptionTrustLevel.Trusted)
} }
dividerItem { dividerItem {

View file

@ -29,7 +29,6 @@ import im.vector.app.R
import im.vector.app.core.platform.VectorViewModel import im.vector.app.core.platform.VectorViewModel
import im.vector.app.core.resources.StringProvider import im.vector.app.core.resources.StringProvider
import io.reactivex.Observable import io.reactivex.Observable
import io.reactivex.functions.BiFunction
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
import org.matrix.android.sdk.api.query.QueryStringValue import org.matrix.android.sdk.api.query.QueryStringValue
import org.matrix.android.sdk.api.session.Session import org.matrix.android.sdk.api.session.Session
@ -123,7 +122,7 @@ class GroupListViewModel @AssistedInject constructor(@Assisted initialState: Gro
session session
.rx() .rx()
.liveGroupSummaries(groupSummariesQueryParams), .liveGroupSummaries(groupSummariesQueryParams),
BiFunction { allCommunityGroup, communityGroups -> { allCommunityGroup, communityGroups ->
listOf(allCommunityGroup) + communityGroups listOf(allCommunityGroup) + communityGroups
} }
) )

View file

@ -285,10 +285,10 @@ class HomeActivity :
dismissedAction = Runnable { dismissedAction = Runnable {
homeActivityViewModel.handle(HomeActivityViewActions.PushPromptHasBeenReviewed) homeActivityViewModel.handle(HomeActivityViewActions.PushPromptHasBeenReviewed)
} }
addButton(getString(R.string.dismiss), Runnable { addButton(getString(R.string.dismiss), {
homeActivityViewModel.handle(HomeActivityViewActions.PushPromptHasBeenReviewed) homeActivityViewModel.handle(HomeActivityViewActions.PushPromptHasBeenReviewed)
}, true) }, true)
addButton(getString(R.string.settings), Runnable { addButton(getString(R.string.settings), {
(weakCurrentActivity?.get() as? VectorBaseActivity<*>)?.let { (weakCurrentActivity?.get() as? VectorBaseActivity<*>)?.let {
// action(it) // action(it)
homeActivityViewModel.handle(HomeActivityViewActions.PushPromptHasBeenReviewed) homeActivityViewModel.handle(HomeActivityViewActions.PushPromptHasBeenReviewed)

View file

@ -32,7 +32,6 @@ import im.vector.app.core.platform.VectorViewModel
import im.vector.app.core.platform.VectorViewModelAction import im.vector.app.core.platform.VectorViewModelAction
import im.vector.app.features.settings.VectorPreferences import im.vector.app.features.settings.VectorPreferences
import io.reactivex.Observable import io.reactivex.Observable
import io.reactivex.functions.Function3
import org.matrix.android.sdk.api.NoOpMatrixCallback import org.matrix.android.sdk.api.NoOpMatrixCallback
import org.matrix.android.sdk.api.extensions.orFalse import org.matrix.android.sdk.api.extensions.orFalse
import org.matrix.android.sdk.api.session.Session import org.matrix.android.sdk.api.session.Session
@ -103,7 +102,7 @@ class UnknownDeviceDetectorSharedViewModel @AssistedInject constructor(@Assisted
session.rx().liveUserCryptoDevices(session.myUserId), session.rx().liveUserCryptoDevices(session.myUserId),
session.rx().liveMyDevicesInfo(), session.rx().liveMyDevicesInfo(),
session.rx().liveCrossSigningPrivateKeys(), session.rx().liveCrossSigningPrivateKeys(),
Function3 { cryptoList, infoList, pInfo -> { cryptoList, infoList, pInfo ->
// Timber.v("## Detector trigger ${cryptoList.map { "${it.deviceId} ${it.trustLevel}" }}") // Timber.v("## Detector trigger ${cryptoList.map { "${it.deviceId} ${it.trustLevel}" }}")
// Timber.v("## Detector trigger canCrossSign ${pInfo.get().selfSigned != null}") // Timber.v("## Detector trigger canCrossSign ${pInfo.get().selfSigned != null}")
infoList infoList

View file

@ -16,7 +16,6 @@
package im.vector.app.features.home.room.breadcrumbs package im.vector.app.features.home.room.breadcrumbs
import android.view.View
import com.airbnb.epoxy.EpoxyController import com.airbnb.epoxy.EpoxyController
import im.vector.app.core.epoxy.zeroItem import im.vector.app.core.epoxy.zeroItem
import im.vector.app.core.utils.DebouncedClickListener import im.vector.app.core.utils.DebouncedClickListener
@ -65,7 +64,7 @@ class BreadcrumbsController @Inject constructor(
hasUnreadMessage(it.hasUnreadMessages) hasUnreadMessage(it.hasUnreadMessages)
hasDraft(it.userDrafts.isNotEmpty()) hasDraft(it.userDrafts.isNotEmpty())
itemClickListener( itemClickListener(
DebouncedClickListener(View.OnClickListener { _ -> DebouncedClickListener({ _ ->
listener?.onBreadcrumbClicked(it.roomId) listener?.onBreadcrumbClicked(it.roomId)
}) })
) )

View file

@ -46,6 +46,7 @@ abstract class BreadcrumbsItem : VectorEpoxyModel<BreadcrumbsItem.Holder>() {
holder.rootView.setOnClickListener(itemClickListener) holder.rootView.setOnClickListener(itemClickListener)
holder.unreadIndentIndicator.isVisible = hasUnreadMessage holder.unreadIndentIndicator.isVisible = hasUnreadMessage
avatarRenderer.render(matrixItem, holder.avatarImageView) avatarRenderer.render(matrixItem, holder.avatarImageView)
holder.avatarImageView.contentDescription = matrixItem.getBestName()
holder.unreadCounterBadgeView.render(UnreadCounterBadgeView.State(unreadNotificationCount, showHighlighted)) holder.unreadCounterBadgeView.render(UnreadCounterBadgeView.State(unreadNotificationCount, showHighlighted))
holder.draftIndentIndicator.isVisible = hasDraft holder.draftIndentIndicator.isVisible = hasDraft
holder.typingIndicator.isVisible = hasTypingUsers holder.typingIndicator.isVisible = hasTypingUsers

View file

@ -60,9 +60,9 @@ class JumpToBottomViewVisibilityManager(
} }
fun maybeShowJumpToBottomViewVisibilityWithDelay() { fun maybeShowJumpToBottomViewVisibilityWithDelay() {
debouncer.debounce("jump_to_bottom_visibility", 250, Runnable { debouncer.debounce("jump_to_bottom_visibility", 250) {
maybeShowJumpToBottomViewVisibility() maybeShowJumpToBottomViewVisibility()
}) }
} }
private fun maybeShowJumpToBottomViewVisibility() { private fun maybeShowJumpToBottomViewVisibility() {

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.call.webrtc.WebRtcCallManager
import im.vector.app.features.command.Command import im.vector.app.features.command.Command
import im.vector.app.features.crypto.keysbackup.restore.KeysBackupRestoreActivity 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.crypto.verification.VerificationBottomSheet
import im.vector.app.features.home.AvatarRenderer import im.vector.app.features.home.AvatarRenderer
import im.vector.app.features.home.room.detail.composer.TextComposerView import im.vector.app.features.home.room.detail.composer.TextComposerView
@ -537,8 +536,18 @@ class RoomDetailFragment @Inject constructor(
.Builder .Builder
.fromRootView(views.rootConstraintLayout) .fromRootView(views.rootConstraintLayout)
.setKeyboardAnimationStyle(R.style.emoji_fade_animation_style) .setKeyboardAnimationStyle(R.style.emoji_fade_animation_style)
.setOnEmojiPopupShownListener { views.composerLayout.views.composerEmojiButton.setImageResource(R.drawable.ic_keyboard) } .setOnEmojiPopupShownListener {
.setOnEmojiPopupDismissListener { views.composerLayout.views.composerEmojiButton.setImageResource(R.drawable.ic_insert_emoji) } views.composerLayout.views.composerEmojiButton.let {
it.setImageResource(R.drawable.ic_keyboard)
it.contentDescription = getString(R.string.a11y_close_emoji_picker)
}
}
.setOnEmojiPopupDismissListener {
views.composerLayout.views.composerEmojiButton.let {
it.setImageResource(R.drawable.ic_insert_emoji)
it.contentDescription = getString(R.string.a11y_open_emoji_picker)
}
}
.build(views.composerLayout.views.composerEditText) .build(views.composerLayout.views.composerEditText)
views.composerLayout.views.composerEmojiButton.debouncedClicks { views.composerLayout.views.composerEmojiButton.debouncedClicks {
@ -1193,10 +1202,7 @@ class RoomDetailFragment @Inject constructor(
avatarRenderer.render(roomSummary.toMatrixItem(), views.roomToolbarAvatarImageView) avatarRenderer.render(roomSummary.toMatrixItem(), views.roomToolbarAvatarImageView)
renderSubTitle(typingMessage, roomSummary.topic) renderSubTitle(typingMessage, roomSummary.topic)
views.roomToolbarDecorationImageView.let { views.roomToolbarDecorationImageView.render(roomSummary.roomEncryptionTrustLevel)
it.setImageResource(roomSummary.roomEncryptionTrustLevel.toImageRes())
it.isVisible = roomSummary.roomEncryptionTrustLevel != null
}
} }
} }

View file

@ -49,7 +49,6 @@ import im.vector.app.features.raw.wellknown.getElementWellknown
import im.vector.app.features.settings.VectorLocale import im.vector.app.features.settings.VectorLocale
import im.vector.app.features.settings.VectorPreferences import im.vector.app.features.settings.VectorPreferences
import io.reactivex.Observable import io.reactivex.Observable
import io.reactivex.functions.BiFunction
import io.reactivex.rxkotlin.subscribeBy import io.reactivex.rxkotlin.subscribeBy
import io.reactivex.schedulers.Schedulers import io.reactivex.schedulers.Schedulers
import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Dispatchers
@ -1331,7 +1330,7 @@ class RoomDetailViewModel @AssistedInject constructor(
.combineLatest<List<TimelineEvent>, RoomSummary, UnreadState>( .combineLatest<List<TimelineEvent>, RoomSummary, UnreadState>(
timelineEvents.observeOn(Schedulers.computation()), timelineEvents.observeOn(Schedulers.computation()),
room.rx().liveRoomSummary().unwrap(), room.rx().liveRoomSummary().unwrap(),
BiFunction { timelineEvents, roomSummary -> { timelineEvents, roomSummary ->
computeUnreadState(timelineEvents, roomSummary) computeUnreadState(timelineEvents, roomSummary)
} }
) )

View file

@ -24,7 +24,6 @@ import android.view.ViewGroup
import androidx.constraintlayout.widget.ConstraintLayout import androidx.constraintlayout.widget.ConstraintLayout
import androidx.constraintlayout.widget.ConstraintSet import androidx.constraintlayout.widget.ConstraintSet
import androidx.core.text.toSpannable import androidx.core.text.toSpannable
import androidx.core.view.isVisible
import androidx.transition.ChangeBounds import androidx.transition.ChangeBounds
import androidx.transition.Fade import androidx.transition.Fade
import androidx.transition.Transition import androidx.transition.Transition
@ -41,8 +40,8 @@ import org.matrix.android.sdk.api.crypto.RoomEncryptionTrustLevel
*/ */
class TextComposerView @JvmOverloads constructor( class TextComposerView @JvmOverloads constructor(
context: Context, context: Context,
attrs: AttributeSet? = null, attrs: AttributeSet? = null,
defStyleAttr: Int = 0) : ConstraintLayout(context, attrs, defStyleAttr) { defStyleAttr: Int = 0) : ConstraintLayout(context, attrs, defStyleAttr) {
interface Callback : ComposerEditText.Callback { interface Callback : ComposerEditText.Callback {
fun onCloseRelatedMessage() fun onCloseRelatedMessage()
@ -143,16 +142,10 @@ class TextComposerView @JvmOverloads constructor(
fun setRoomEncrypted(isEncrypted: Boolean, roomEncryptionTrustLevel: RoomEncryptionTrustLevel?) { fun setRoomEncrypted(isEncrypted: Boolean, roomEncryptionTrustLevel: RoomEncryptionTrustLevel?) {
if (isEncrypted) { if (isEncrypted) {
views.composerEditText.setHint(R.string.room_message_placeholder) views.composerEditText.setHint(R.string.room_message_placeholder)
views.composerShieldImageView.isVisible = true views.composerShieldImageView.render(roomEncryptionTrustLevel)
val shieldRes = when (roomEncryptionTrustLevel) {
RoomEncryptionTrustLevel.Trusted -> R.drawable.ic_shield_trusted
RoomEncryptionTrustLevel.Warning -> R.drawable.ic_shield_warning
else -> R.drawable.ic_shield_black
}
views.composerShieldImageView.setImageResource(shieldRes)
} else { } else {
views.composerEditText.setHint(R.string.room_message_placeholder) views.composerEditText.setHint(R.string.room_message_placeholder)
views.composerShieldImageView.isVisible = false views.composerShieldImageView.render(null)
} }
} }
} }

View file

@ -16,7 +16,6 @@
package im.vector.app.features.home.room.detail.timeline.factory package im.vector.app.features.home.room.detail.timeline.factory
import android.view.View
import im.vector.app.R import im.vector.app.R
import im.vector.app.core.resources.StringProvider import im.vector.app.core.resources.StringProvider
import im.vector.app.features.home.AvatarRenderer import im.vector.app.features.home.AvatarRenderer
@ -42,7 +41,7 @@ class DefaultItemFactory @Inject constructor(private val avatarSizeProvider: Ava
avatarRenderer = avatarRenderer, avatarRenderer = avatarRenderer,
informationData = informationData, informationData = informationData,
text = text, text = text,
itemLongClickListener = View.OnLongClickListener { view -> itemLongClickListener = { view ->
callback?.onEventLongClicked(informationData, null, view) ?: false callback?.onEventLongClicked(informationData, null, view) ?: false
}, },
readReceiptsCallback = callback readReceiptsCallback = callback

View file

@ -322,7 +322,7 @@ class MessageItemFactory @Inject constructor(
mode(ImageContentRenderer.Mode.STICKER) mode(ImageContentRenderer.Mode.STICKER)
} else { } else {
clickListener( clickListener(
DebouncedClickListener(View.OnClickListener { view -> DebouncedClickListener({ view ->
callback?.onImageMessageClicked(messageContent, data, view) callback?.onImageMessageClicked(messageContent, data, view)
})) }))
} }

View file

@ -16,7 +16,6 @@
package im.vector.app.features.home.room.detail.timeline.factory package im.vector.app.features.home.room.detail.timeline.factory
import android.view.View
import im.vector.app.features.home.AvatarRenderer import im.vector.app.features.home.AvatarRenderer
import im.vector.app.features.home.room.detail.timeline.TimelineEventController import im.vector.app.features.home.room.detail.timeline.TimelineEventController
import im.vector.app.features.home.room.detail.timeline.format.NoticeEventFormatter import im.vector.app.features.home.room.detail.timeline.format.NoticeEventFormatter
@ -41,7 +40,7 @@ class NoticeItemFactory @Inject constructor(private val eventFormatter: NoticeEv
avatarRenderer = avatarRenderer, avatarRenderer = avatarRenderer,
informationData = informationData, informationData = informationData,
noticeText = formattedText, noticeText = formattedText,
itemLongClickListener = View.OnLongClickListener { view -> itemLongClickListener = { view ->
callback?.onEventLongClicked(informationData, null, view) ?: false callback?.onEventLongClicked(informationData, null, view) ?: false
}, },
readReceiptsCallback = callback, readReceiptsCallback = callback,

View file

@ -15,7 +15,6 @@
*/ */
package im.vector.app.features.home.room.detail.timeline.helper package im.vector.app.features.home.room.detail.timeline.helper
import android.view.View
import im.vector.app.EmojiCompatFontProvider import im.vector.app.EmojiCompatFontProvider
import im.vector.app.core.utils.DebouncedClickListener import im.vector.app.core.utils.DebouncedClickListener
import im.vector.app.features.home.AvatarRenderer import im.vector.app.features.home.AvatarRenderer
@ -39,13 +38,13 @@ class MessageItemAttributesFactory @Inject constructor(
informationData = informationData, informationData = informationData,
avatarRenderer = avatarRenderer, avatarRenderer = avatarRenderer,
messageColorProvider = messageColorProvider, messageColorProvider = messageColorProvider,
itemLongClickListener = View.OnLongClickListener { view -> itemLongClickListener = { view ->
callback?.onEventLongClicked(informationData, messageContent, view) ?: false callback?.onEventLongClicked(informationData, messageContent, view) ?: false
}, },
itemClickListener = DebouncedClickListener(View.OnClickListener { view -> itemClickListener = DebouncedClickListener({ view ->
callback?.onEventCellClicked(informationData, messageContent, view) callback?.onEventCellClicked(informationData, messageContent, view)
}), }),
memberClickListener = DebouncedClickListener(View.OnClickListener { memberClickListener = DebouncedClickListener({
callback?.onMemberNameClicked(informationData) callback?.onMemberNameClicked(informationData)
}), }),
reactionPillCallback = callback, reactionPillCallback = callback,

View file

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

@ -42,10 +42,10 @@ abstract class AbsMessageItem<H : AbsMessageItem.Holder> : AbsBaseMessageItem<H>
@EpoxyAttribute @EpoxyAttribute
lateinit var attributes: Attributes lateinit var attributes: Attributes
private val _avatarClickListener = DebouncedClickListener(View.OnClickListener { private val _avatarClickListener = DebouncedClickListener({
attributes.avatarCallback?.onAvatarClicked(attributes.informationData) attributes.avatarCallback?.onAvatarClicked(attributes.informationData)
}) })
private val _memberNameClickListener = DebouncedClickListener(View.OnClickListener { private val _memberNameClickListener = DebouncedClickListener({
attributes.avatarCallback?.onMemberNameClicked(attributes.informationData) attributes.avatarCallback?.onMemberNameClicked(attributes.informationData)
}) })

View file

@ -32,7 +32,7 @@ abstract class DefaultItem : BaseEventItem<DefaultItem.Holder>() {
@EpoxyAttribute @EpoxyAttribute
lateinit var attributes: Attributes lateinit var attributes: Attributes
private val _readReceiptsClickListener = DebouncedClickListener(View.OnClickListener { private val _readReceiptsClickListener = DebouncedClickListener({
attributes.readReceiptsCallback?.onReadReceiptsClicked(attributes.informationData.readReceipts) attributes.readReceiptsCallback?.onReadReceiptsClicked(attributes.informationData.readReceipts)
}) })

View file

@ -186,14 +186,14 @@ abstract class MergedRoomCreationItem : BasedMergedItem<MergedRoomCreationItem.H
holder.setAvatarButton.isVisible = shouldSetAvatar holder.setAvatarButton.isVisible = shouldSetAvatar
if (shouldSetAvatar) { if (shouldSetAvatar) {
holder.setAvatarButton.setOnClickListener(DebouncedClickListener({ _ -> holder.setAvatarButton.setOnClickListener(DebouncedClickListener({
attributes.callback?.onTimelineItemAction(RoomDetailAction.QuickActionSetAvatar) attributes.callback?.onTimelineItemAction(RoomDetailAction.QuickActionSetAvatar)
})) }))
} }
holder.addPeopleButton.isVisible = !isDirect holder.addPeopleButton.isVisible = !isDirect
if (!isDirect) { if (!isDirect) {
holder.addPeopleButton.setOnClickListener(DebouncedClickListener({ _ -> holder.addPeopleButton.setOnClickListener(DebouncedClickListener({
attributes.callback?.onTimelineItemAction(RoomDetailAction.QuickActionInvitePeople) attributes.callback?.onTimelineItemAction(RoomDetailAction.QuickActionInvitePeople)
})) }))
} }

View file

@ -143,7 +143,7 @@ abstract class MessagePollItem : AbsMessageItem<MessagePollItem.Holder>() {
override fun bindView(itemView: View) { override fun bindView(itemView: View) {
super.bindView(itemView) super.bindView(itemView)
val buttons = listOf(button1, button2, button3, button4, button5) val buttons = listOf(button1, button2, button3, button4, button5)
val clickListener = DebouncedClickListener(View.OnClickListener { val clickListener = DebouncedClickListener({
val optionIndex = buttons.indexOf(it) val optionIndex = buttons.indexOf(it)
if (optionIndex != -1 && pollId != null) { if (optionIndex != -1 && pollId != null) {
val compatValue = if (optionIndex < optionValues?.size ?: 0) optionValues?.get(optionIndex) else null val compatValue = if (optionIndex < optionValues?.size ?: 0) optionValues?.get(optionIndex) else null

View file

@ -19,15 +19,16 @@ package im.vector.app.features.home.room.detail.timeline.item
import android.view.View import android.view.View
import android.widget.ImageView import android.widget.ImageView
import android.widget.TextView import android.widget.TextView
import androidx.core.view.isVisible
import com.airbnb.epoxy.EpoxyAttribute import com.airbnb.epoxy.EpoxyAttribute
import com.airbnb.epoxy.EpoxyModelClass import com.airbnb.epoxy.EpoxyModelClass
import im.vector.app.R import im.vector.app.R
import im.vector.app.core.epoxy.ClickListener import im.vector.app.core.epoxy.ClickListener
import im.vector.app.core.epoxy.onClick 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.core.utils.DebouncedClickListener
import im.vector.app.features.home.AvatarRenderer import im.vector.app.features.home.AvatarRenderer
import im.vector.app.features.home.room.detail.timeline.TimelineEventController 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) @EpoxyModelClass(layout = R.layout.item_timeline_event_base_noinfo)
abstract class NoticeItem : BaseEventItem<NoticeItem.Holder>() { abstract class NoticeItem : BaseEventItem<NoticeItem.Holder>() {
@ -35,7 +36,7 @@ abstract class NoticeItem : BaseEventItem<NoticeItem.Holder>() {
@EpoxyAttribute @EpoxyAttribute
lateinit var attributes: Attributes lateinit var attributes: Attributes
private val _readReceiptsClickListener = DebouncedClickListener(View.OnClickListener { private val _readReceiptsClickListener = DebouncedClickListener({
attributes.readReceiptsCallback?.onReadReceiptsClicked(attributes.informationData.readReceipts) attributes.readReceiptsCallback?.onReadReceiptsClicked(attributes.informationData.readReceipts)
}) })
@ -49,13 +50,12 @@ abstract class NoticeItem : BaseEventItem<NoticeItem.Holder>() {
when (attributes.informationData.e2eDecoration) { when (attributes.informationData.e2eDecoration) {
E2EDecoration.NONE -> { E2EDecoration.NONE -> {
holder.e2EDecorationView.isVisible = false holder.e2EDecorationView.render(null)
} }
E2EDecoration.WARN_IN_CLEAR, E2EDecoration.WARN_IN_CLEAR,
E2EDecoration.WARN_SENT_BY_UNVERIFIED, E2EDecoration.WARN_SENT_BY_UNVERIFIED,
E2EDecoration.WARN_SENT_BY_UNKNOWN -> { E2EDecoration.WARN_SENT_BY_UNKNOWN -> {
holder.e2EDecorationView.setImageResource(R.drawable.ic_shield_warning) holder.e2EDecorationView.render(RoomEncryptionTrustLevel.Warning)
holder.e2EDecorationView.isVisible = true
} }
} }
} }
@ -75,7 +75,7 @@ abstract class NoticeItem : BaseEventItem<NoticeItem.Holder>() {
class Holder : BaseHolder(STUB_ID) { class Holder : BaseHolder(STUB_ID) {
val avatarImageView by bind<ImageView>(R.id.itemNoticeAvatarView) val avatarImageView by bind<ImageView>(R.id.itemNoticeAvatarView)
val noticeTextView by bind<TextView>(R.id.itemNoticeTextView) 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( data class Attributes(

View file

@ -60,7 +60,7 @@ data class ReactionInfo(
*/ */
class ViewReactionsViewModel @AssistedInject constructor(@Assisted class ViewReactionsViewModel @AssistedInject constructor(@Assisted
initialState: DisplayReactionsViewState, initialState: DisplayReactionsViewState,
private val session: Session, session: Session,
private val dateFormatter: VectorDateFormatter private val dateFormatter: VectorDateFormatter
) : VectorViewModel<DisplayReactionsViewState, EmptyAction, EmptyViewEvents>(initialState) { ) : VectorViewModel<DisplayReactionsViewState, EmptyAction, EmptyViewEvents>(initialState) {

View file

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

View file

@ -16,7 +16,6 @@
package im.vector.app.features.home.room.list package im.vector.app.features.home.room.list
import android.view.View
import im.vector.app.R import im.vector.app.R
import im.vector.app.core.date.DateFormatKind import im.vector.app.core.date.DateFormatKind
import im.vector.app.core.date.VectorDateFormatter import im.vector.app.core.date.VectorDateFormatter
@ -109,7 +108,7 @@ class RoomSummaryItemFactory @Inject constructor(private val displayableEventFor
onLongClick?.invoke(roomSummary) ?: false onLongClick?.invoke(roomSummary) ?: false
} }
.itemClickListener( .itemClickListener(
DebouncedClickListener(View.OnClickListener { _ -> DebouncedClickListener({
onClick?.invoke(roomSummary) onClick?.invoke(roomSummary)
}) })
) )

View file

@ -29,7 +29,7 @@ import org.matrix.android.sdk.rx.rx
import org.matrix.android.sdk.rx.unwrap import org.matrix.android.sdk.rx.unwrap
class RoomListQuickActionsViewModel @AssistedInject constructor(@Assisted initialState: RoomListQuickActionsState, class RoomListQuickActionsViewModel @AssistedInject constructor(@Assisted initialState: RoomListQuickActionsState,
private val session: Session session: Session
) : VectorViewModel<RoomListQuickActionsState, EmptyAction, EmptyViewEvents>(initialState) { ) : VectorViewModel<RoomListQuickActionsState, EmptyAction, EmptyViewEvents>(initialState) {
@AssistedFactory @AssistedFactory

View file

@ -36,7 +36,6 @@ import im.vector.app.core.extensions.showPassword
import im.vector.app.core.extensions.toReducedUrl import im.vector.app.core.extensions.toReducedUrl
import im.vector.app.databinding.FragmentLoginBinding import im.vector.app.databinding.FragmentLoginBinding
import io.reactivex.Observable import io.reactivex.Observable
import io.reactivex.functions.BiFunction
import io.reactivex.rxkotlin.subscribeBy import io.reactivex.rxkotlin.subscribeBy
import org.matrix.android.sdk.api.failure.Failure import org.matrix.android.sdk.api.failure.Failure
@ -225,7 +224,7 @@ class LoginFragment @Inject constructor() : AbstractSSOLoginFragment<FragmentLog
.combineLatest( .combineLatest(
views.loginField.textChanges().map { it.trim().isNotEmpty() }, views.loginField.textChanges().map { it.trim().isNotEmpty() },
views.passwordField.textChanges().map { it.isNotEmpty() }, views.passwordField.textChanges().map { it.isNotEmpty() },
BiFunction<Boolean, Boolean, Boolean> { isLoginNotEmpty, isPasswordNotEmpty -> { isLoginNotEmpty, isPasswordNotEmpty ->
isLoginNotEmpty && isPasswordNotEmpty isLoginNotEmpty && isPasswordNotEmpty
} }
) )
@ -255,14 +254,7 @@ class LoginFragment @Inject constructor() : AbstractSSOLoginFragment<FragmentLog
private fun renderPasswordField() { private fun renderPasswordField() {
views.passwordField.showPassword(passwordShown) views.passwordField.showPassword(passwordShown)
views.passwordReveal.render(passwordShown)
if (passwordShown) {
views.passwordReveal.setImageResource(R.drawable.ic_eye_closed)
views.passwordReveal.contentDescription = getString(R.string.a11y_hide_password)
} else {
views.passwordReveal.setImageResource(R.drawable.ic_eye)
views.passwordReveal.contentDescription = getString(R.string.a11y_show_password)
}
} }
override fun resetViewModel() { override fun resetViewModel() {

View file

@ -32,7 +32,6 @@ import im.vector.app.core.extensions.showPassword
import im.vector.app.core.extensions.toReducedUrl import im.vector.app.core.extensions.toReducedUrl
import im.vector.app.databinding.FragmentLoginResetPasswordBinding import im.vector.app.databinding.FragmentLoginResetPasswordBinding
import io.reactivex.Observable import io.reactivex.Observable
import io.reactivex.functions.BiFunction
import io.reactivex.rxkotlin.subscribeBy import io.reactivex.rxkotlin.subscribeBy
import javax.inject.Inject import javax.inject.Inject
@ -69,7 +68,7 @@ class LoginResetPasswordFragment @Inject constructor() : AbstractLoginFragment<F
.combineLatest( .combineLatest(
views.resetPasswordEmail.textChanges().map { it.isEmail() }, views.resetPasswordEmail.textChanges().map { it.isEmail() },
views.passwordField.textChanges().map { it.isNotEmpty() }, views.passwordField.textChanges().map { it.isNotEmpty() },
BiFunction<Boolean, Boolean, Boolean> { isEmail, isPasswordNotEmpty -> { isEmail, isPasswordNotEmpty ->
isEmail && isPasswordNotEmpty isEmail && isPasswordNotEmpty
} }
) )
@ -127,14 +126,7 @@ class LoginResetPasswordFragment @Inject constructor() : AbstractLoginFragment<F
private fun renderPasswordField() { private fun renderPasswordField() {
views.passwordField.showPassword(passwordShown) views.passwordField.showPassword(passwordShown)
views.passwordReveal.render(passwordShown)
if (passwordShown) {
views.passwordReveal.setImageResource(R.drawable.ic_eye_closed)
views.passwordReveal.contentDescription = getString(R.string.a11y_hide_password)
} else {
views.passwordReveal.setImageResource(R.drawable.ic_eye)
views.passwordReveal.contentDescription = getString(R.string.a11y_show_password)
}
} }
override fun resetViewModel() { override fun resetViewModel() {
@ -153,9 +145,7 @@ class LoginResetPasswordFragment @Inject constructor() : AbstractLoginFragment<F
is Fail -> { is Fail -> {
views.resetPasswordEmailTil.error = errorFormatter.toHumanReadable(state.asyncResetPassword.error) views.resetPasswordEmailTil.error = errorFormatter.toHumanReadable(state.asyncResetPassword.error)
} }
is Success -> { is Success -> Unit
Unit
}
} }
} }
} }

View file

@ -74,9 +74,7 @@ class LoginResetPasswordMailConfirmationFragment @Inject constructor() : Abstrac
.setPositiveButton(R.string.ok, null) .setPositiveButton(R.string.ok, null)
.show() .show()
} }
is Success -> { is Success -> Unit
Unit
}
} }
} }
} }

View file

@ -138,7 +138,7 @@ class MatrixToBottomSheet :
fun withLink(matrixToLink: String, listener: InteractionListener?): MatrixToBottomSheet { fun withLink(matrixToLink: String, listener: InteractionListener?): MatrixToBottomSheet {
return MatrixToBottomSheet().apply { return MatrixToBottomSheet().apply {
arguments = Bundle().apply { arguments = Bundle().apply {
putParcelable(MvRx.KEY_ARG, MatrixToBottomSheet.MatrixToArgs( putParcelable(MvRx.KEY_ARG, MatrixToArgs(
matrixToLink = matrixToLink matrixToLink = matrixToLink
)) ))
} }

View file

@ -379,7 +379,7 @@ class BugReporter @Inject constructor(
if (responseCode != HttpURLConnection.HTTP_OK) { if (responseCode != HttpURLConnection.HTTP_OK) {
if (null != errorMessage) { if (null != errorMessage) {
serverError = "Failed with error $errorMessage" serverError = "Failed with error $errorMessage"
} else if (null == response || null == response.body) { } else if (response?.body == null) {
serverError = "Failed with error $responseCode" serverError = "Failed with error $responseCode"
} else { } else {
try { try {

View file

@ -26,7 +26,6 @@ import android.view.MenuItem
import android.widget.SearchView import android.widget.SearchView
import androidx.appcompat.widget.Toolbar import androidx.appcompat.widget.Toolbar
import androidx.core.view.isVisible import androidx.core.view.isVisible
import androidx.lifecycle.Observer
import com.airbnb.mvrx.viewModel import com.airbnb.mvrx.viewModel
import com.google.android.material.tabs.TabLayout import com.google.android.material.tabs.TabLayout
import com.jakewharton.rxbinding3.widget.queryTextChanges import com.jakewharton.rxbinding3.widget.queryTextChanges
@ -107,13 +106,13 @@ class EmojiReactionPickerActivity : VectorBaseActivity<ActivityEmojiReactionPick
} }
views.tabs.addOnTabSelectedListener(tabLayoutSelectionListener) views.tabs.addOnTabSelectedListener(tabLayoutSelectionListener)
viewModel.currentSection.observe(this, Observer { section -> viewModel.currentSection.observe(this) { section ->
section?.let { section?.let {
views.tabs.removeOnTabSelectedListener(tabLayoutSelectionListener) views.tabs.removeOnTabSelectedListener(tabLayoutSelectionListener)
views.tabs.getTabAt(it)?.select() views.tabs.getTabAt(it)?.select()
views.tabs.addOnTabSelectedListener(tabLayoutSelectionListener) views.tabs.addOnTabSelectedListener(tabLayoutSelectionListener)
} }
}) }
viewModel.navigateEvent.observeEvent(this) { viewModel.navigateEvent.observeEvent(this) {
if (it == EmojiChooserViewModel.NAVIGATE_FINISH) { if (it == EmojiChooserViewModel.NAVIGATE_FINISH) {

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.devices.DeviceListBottomSheet
import im.vector.app.features.roommemberprofile.powerlevel.EditPowerLevelDialogs import im.vector.app.features.roommemberprofile.powerlevel.EditPowerLevelDialogs
import kotlinx.parcelize.Parcelize 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.session.room.powerlevels.Role
import org.matrix.android.sdk.api.util.MatrixItem import org.matrix.android.sdk.api.util.MatrixItem
import javax.inject.Inject import javax.inject.Inject
@ -205,31 +206,28 @@ class RoomMemberProfileFragment @Inject constructor(
if (state.isRoomEncrypted) { if (state.isRoomEncrypted) {
headerViews.memberProfileDecorationImageView.isVisible = true headerViews.memberProfileDecorationImageView.isVisible = true
if (state.userMXCrossSigningInfo != null) { val trustLevel = if (state.userMXCrossSigningInfo != null) {
// Cross signing is enabled for this user // Cross signing is enabled for this user
val icon = if (state.userMXCrossSigningInfo.isTrusted()) { if (state.userMXCrossSigningInfo.isTrusted()) {
// User is trusted // User is trusted
if (state.allDevicesAreCrossSignedTrusted) { if (state.allDevicesAreCrossSignedTrusted) {
R.drawable.ic_shield_trusted RoomEncryptionTrustLevel.Trusted
} else { } else {
R.drawable.ic_shield_warning RoomEncryptionTrustLevel.Warning
} }
} else { } else {
R.drawable.ic_shield_black RoomEncryptionTrustLevel.Default
} }
headerViews.memberProfileDecorationImageView.setImageResource(icon)
views.matrixProfileDecorationToolbarAvatarImageView.setImageResource(icon)
} else { } else {
// Legacy // Legacy
if (state.allDevicesAreTrusted) { if (state.allDevicesAreTrusted) {
headerViews.memberProfileDecorationImageView.setImageResource(R.drawable.ic_shield_trusted) RoomEncryptionTrustLevel.Trusted
views.matrixProfileDecorationToolbarAvatarImageView.setImageResource(R.drawable.ic_shield_trusted)
} else { } else {
headerViews.memberProfileDecorationImageView.setImageResource(R.drawable.ic_shield_warning) RoomEncryptionTrustLevel.Warning
views.matrixProfileDecorationToolbarAvatarImageView.setImageResource(R.drawable.ic_shield_warning)
} }
} }
headerViews.memberProfileDecorationImageView.render(trustLevel)
views.matrixProfileDecorationToolbarAvatarImageView.render(trustLevel)
} else { } else {
headerViews.memberProfileDecorationImageView.isVisible = false 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.core.utils.startSharePlainTextIntent
import im.vector.app.databinding.FragmentMatrixProfileBinding import im.vector.app.databinding.FragmentMatrixProfileBinding
import im.vector.app.databinding.ViewStubRoomProfileHeaderBinding 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.AvatarRenderer
import im.vector.app.features.home.room.list.actions.RoomListActionsArgs import im.vector.app.features.home.room.list.actions.RoomListActionsArgs
import im.vector.app.features.home.room.list.actions.RoomListQuickActionsBottomSheet import im.vector.app.features.home.room.list.actions.RoomListQuickActionsBottomSheet
@ -204,9 +203,8 @@ class RoomProfileFragment @Inject constructor(
val matrixItem = it.toMatrixItem() val matrixItem = it.toMatrixItem()
avatarRenderer.render(matrixItem, headerViews.roomProfileAvatarView) avatarRenderer.render(matrixItem, headerViews.roomProfileAvatarView)
avatarRenderer.render(matrixItem, views.matrixProfileToolbarAvatarImageView) avatarRenderer.render(matrixItem, views.matrixProfileToolbarAvatarImageView)
headerViews.roomProfileDecorationImageView.isVisible = it.roomEncryptionTrustLevel != null headerViews.roomProfileDecorationImageView.render(it.roomEncryptionTrustLevel)
headerViews.roomProfileDecorationImageView.setImageResource(it.roomEncryptionTrustLevel.toImageRes()) views.matrixProfileDecorationToolbarAvatarImageView.render(it.roomEncryptionTrustLevel)
views.matrixProfileDecorationToolbarAvatarImageView.setImageResource(it.roomEncryptionTrustLevel.toImageRes())
} }
} }
roomProfileController.setData(state) roomProfileController.setData(state)

View file

@ -29,7 +29,6 @@ import im.vector.app.core.platform.VectorViewModel
import im.vector.app.features.powerlevel.PowerLevelsObservableFactory import im.vector.app.features.powerlevel.PowerLevelsObservableFactory
import io.reactivex.Observable import io.reactivex.Observable
import io.reactivex.android.schedulers.AndroidSchedulers import io.reactivex.android.schedulers.AndroidSchedulers
import io.reactivex.functions.BiFunction
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
import org.matrix.android.sdk.api.crypto.RoomEncryptionTrustLevel import org.matrix.android.sdk.api.crypto.RoomEncryptionTrustLevel
import org.matrix.android.sdk.api.extensions.orFalse import org.matrix.android.sdk.api.extensions.orFalse
@ -90,7 +89,7 @@ class RoomMemberListViewModel @AssistedInject constructor(@Assisted initialState
.liveStateEvent(EventType.STATE_ROOM_POWER_LEVELS, QueryStringValue.NoCondition) .liveStateEvent(EventType.STATE_ROOM_POWER_LEVELS, QueryStringValue.NoCondition)
.mapOptional { it.content.toModel<PowerLevelsContent>() } .mapOptional { it.content.toModel<PowerLevelsContent>() }
.unwrap(), .unwrap(),
BiFunction { roomMembers, powerLevelsContent -> { roomMembers, powerLevelsContent ->
buildRoomMemberSummaries(powerLevelsContent, roomMembers) buildRoomMemberSummaries(powerLevelsContent, roomMembers)
} }
) )

View file

@ -199,7 +199,6 @@ class RoomSettingsFragment @Inject constructor(
} }
RoomSettingsViewState.AvatarAction.DeleteAvatar -> { RoomSettingsViewState.AvatarAction.DeleteAvatar -> {
/* Should not happen */ /* Should not happen */
Unit
} }
is RoomSettingsViewState.AvatarAction.UpdateAvatar -> { is RoomSettingsViewState.AvatarAction.UpdateAvatar -> {
// Cancel the update of the avatar // Cancel the update of the avatar

View file

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

View file

@ -38,7 +38,7 @@ abstract class UploadsImageItem : VectorEpoxyModel<UploadsImageItem.Holder>() {
override fun bind(holder: Holder) { override fun bind(holder: Holder) {
super.bind(holder) super.bind(holder)
holder.view.setOnClickListener( holder.view.setOnClickListener(
DebouncedClickListener(View.OnClickListener { _ -> DebouncedClickListener({
listener?.onItemClicked(holder.imageView, data) listener?.onItemClicked(holder.imageView, data)
}) })
) )

View file

@ -39,7 +39,7 @@ abstract class UploadsVideoItem : VectorEpoxyModel<UploadsVideoItem.Holder>() {
override fun bind(holder: Holder) { override fun bind(holder: Holder) {
super.bind(holder) super.bind(holder)
holder.view.setOnClickListener( holder.view.setOnClickListener(
DebouncedClickListener(View.OnClickListener { _ -> DebouncedClickListener({
listener?.onItemClicked(holder.imageView, data) listener?.onItemClicked(holder.imageView, data)
}) })
) )

View file

@ -361,7 +361,7 @@ class VectorSettingsGeneralFragment @Inject constructor(
views.changePasswordNewPwdText.showPassword(passwordShown) views.changePasswordNewPwdText.showPassword(passwordShown)
views.changePasswordConfirmNewPwdText.showPassword(passwordShown) views.changePasswordConfirmNewPwdText.showPassword(passwordShown)
views.changePasswordShowPasswords.setImageResource(if (passwordShown) R.drawable.ic_eye_closed else R.drawable.ic_eye) views.changePasswordShowPasswords.render(passwordShown)
} }
val dialog = AlertDialog.Builder(activity) val dialog = AlertDialog.Builder(activity)

View file

@ -458,7 +458,7 @@ class VectorSettingsSecurityPrivacyFragment @Inject constructor(
views.importDialogShowPassword.setOnClickListener { views.importDialogShowPassword.setOnClickListener {
passwordVisible = !passwordVisible passwordVisible = !passwordVisible
views.dialogE2eKeysPassphraseEditText.showPassword(passwordVisible) views.dialogE2eKeysPassphraseEditText.showPassword(passwordVisible)
views.importDialogShowPassword.setImageResource(if (passwordVisible) R.drawable.ic_eye_closed else R.drawable.ic_eye) views.importDialogShowPassword.render(passwordVisible)
} }
views.dialogE2eKeysPassphraseEditText.addTextChangedListener(object : SimpleTextWatcher() { views.dialogE2eKeysPassphraseEditText.addTextChangedListener(object : SimpleTextWatcher() {

View file

@ -29,7 +29,6 @@ import im.vector.app.core.resources.StringProvider
import im.vector.app.features.auth.ReAuthActivity import im.vector.app.features.auth.ReAuthActivity
import im.vector.app.features.login.ReAuthHelper import im.vector.app.features.login.ReAuthHelper
import io.reactivex.Observable import io.reactivex.Observable
import io.reactivex.functions.BiFunction
import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
import org.matrix.android.sdk.api.auth.UIABaseAuth import org.matrix.android.sdk.api.auth.UIABaseAuth
@ -62,7 +61,7 @@ class CrossSigningSettingsViewModel @AssistedInject constructor(
Observable.combineLatest<List<DeviceInfo>, Optional<MXCrossSigningInfo>, Pair<List<DeviceInfo>, Optional<MXCrossSigningInfo>>>( Observable.combineLatest<List<DeviceInfo>, Optional<MXCrossSigningInfo>, Pair<List<DeviceInfo>, Optional<MXCrossSigningInfo>>>(
session.rx().liveMyDevicesInfo(), session.rx().liveMyDevicesInfo(),
session.rx().liveCrossSigningInfo(session.myUserId), session.rx().liveCrossSigningInfo(session.myUserId),
BiFunction { myDevicesInfo, mxCrossSigningInfo -> { myDevicesInfo, mxCrossSigningInfo ->
myDevicesInfo to mxCrossSigningInfo myDevicesInfo to mxCrossSigningInfo
} }
) )

View file

@ -18,7 +18,6 @@ package im.vector.app.features.settings.devices
import android.graphics.Typeface import android.graphics.Typeface
import android.view.ViewGroup import android.view.ViewGroup
import android.widget.ImageView
import android.widget.TextView import android.widget.TextView
import androidx.core.view.isVisible import androidx.core.view.isVisible
import com.airbnb.epoxy.EpoxyAttribute import com.airbnb.epoxy.EpoxyAttribute
@ -27,6 +26,7 @@ import im.vector.app.R
import im.vector.app.core.epoxy.VectorEpoxyHolder import im.vector.app.core.epoxy.VectorEpoxyHolder
import im.vector.app.core.epoxy.VectorEpoxyModel import im.vector.app.core.epoxy.VectorEpoxyModel
import im.vector.app.core.resources.ColorProvider import im.vector.app.core.resources.ColorProvider
import im.vector.app.core.ui.views.ShieldImageView
import im.vector.app.core.utils.DimensionConverter import im.vector.app.core.utils.DimensionConverter
import me.gujun.android.span.span import me.gujun.android.span.span
import org.matrix.android.sdk.internal.crypto.crosssigning.DeviceTrustLevel import org.matrix.android.sdk.internal.crypto.crosssigning.DeviceTrustLevel
@ -75,17 +75,17 @@ abstract class DeviceItem : VectorEpoxyModel<DeviceItem.Holder>() {
super.bind(holder) super.bind(holder)
holder.root.setOnClickListener { itemClickAction?.invoke() } holder.root.setOnClickListener { itemClickAction?.invoke() }
val shield = TrustUtils.shieldForTrust(
currentDevice,
trustedSession,
legacyMode,
trusted
)
if (e2eCapable) { if (e2eCapable) {
holder.trustIcon.setImageResource(shield) val shield = TrustUtils.shieldForTrust(
currentDevice,
trustedSession,
legacyMode,
trusted
)
holder.trustIcon.render(shield)
} else { } else {
holder.trustIcon.setImageDrawable(null) holder.trustIcon.render(null)
} }
val detailedModeLabels = listOf( val detailedModeLabels = listOf(
@ -152,6 +152,6 @@ abstract class DeviceItem : VectorEpoxyModel<DeviceItem.Holder>() {
val deviceLastSeenLabelText by bind<TextView>(R.id.itemDeviceLastSeenLabel) val deviceLastSeenLabelText by bind<TextView>(R.id.itemDeviceLastSeenLabel)
val deviceLastSeenText by bind<TextView>(R.id.itemDeviceLastSeen) val deviceLastSeenText by bind<TextView>(R.id.itemDeviceLastSeen)
val trustIcon by bind<ImageView>(R.id.itemDeviceTrustLevelIcon) val trustIcon by bind<ShieldImageView>(R.id.itemDeviceTrustLevelIcon)
} }
} }

View file

@ -24,6 +24,7 @@ import im.vector.app.core.resources.StringProvider
import im.vector.app.core.ui.list.GenericItem import im.vector.app.core.ui.list.GenericItem
import im.vector.app.core.ui.list.genericFooterItem import im.vector.app.core.ui.list.genericFooterItem
import im.vector.app.core.ui.list.genericItem import im.vector.app.core.ui.list.genericItem
import im.vector.app.core.ui.views.toDrawableRes
import im.vector.app.features.crypto.verification.epoxy.bottomSheetVerificationActionItem import im.vector.app.features.crypto.verification.epoxy.bottomSheetVerificationActionItem
import org.matrix.android.sdk.api.extensions.orFalse import org.matrix.android.sdk.api.extensions.orFalse
import org.matrix.android.sdk.internal.crypto.model.CryptoDeviceInfo import org.matrix.android.sdk.internal.crypto.model.CryptoDeviceInfo
@ -62,7 +63,7 @@ class DeviceVerificationInfoBottomSheetController @Inject constructor(
trustMSK = data.accountCrossSigningIsTrusted, trustMSK = data.accountCrossSigningIsTrusted,
legacyMode = !data.hasAccountCrossSigning, legacyMode = !data.hasAccountCrossSigning,
deviceTrustLevel = cryptoDeviceInfo.trustLevel deviceTrustLevel = cryptoDeviceInfo.trustLevel
) ).toDrawableRes()
if (data.hasAccountCrossSigning) { if (data.hasAccountCrossSigning) {
// Cross Signing is enabled // Cross Signing is enabled

View file

@ -35,7 +35,6 @@ import im.vector.app.core.resources.StringProvider
import im.vector.app.features.auth.ReAuthActivity import im.vector.app.features.auth.ReAuthActivity
import im.vector.app.features.login.ReAuthHelper import im.vector.app.features.login.ReAuthHelper
import io.reactivex.Observable import io.reactivex.Observable
import io.reactivex.functions.BiFunction
import io.reactivex.subjects.PublishSubject import io.reactivex.subjects.PublishSubject
import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
@ -121,7 +120,7 @@ class DevicesViewModel @AssistedInject constructor(
Observable.combineLatest<List<CryptoDeviceInfo>, List<DeviceInfo>, List<DeviceFullInfo>>( Observable.combineLatest<List<CryptoDeviceInfo>, List<DeviceInfo>, List<DeviceFullInfo>>(
session.rx().liveUserCryptoDevices(session.myUserId), session.rx().liveUserCryptoDevices(session.myUserId),
session.rx().liveMyDevicesInfo(), session.rx().liveMyDevicesInfo(),
BiFunction { cryptoList, infoList -> { cryptoList, infoList ->
infoList infoList
.sortedByDescending { it.lastSeenTs } .sortedByDescending { it.lastSeenTs }
.map { deviceInfo -> .map { deviceInfo ->
@ -239,7 +238,6 @@ class DevicesViewModel @AssistedInject constructor(
uiaContinuation?.resumeWith(Result.failure((Exception()))) uiaContinuation?.resumeWith(Result.failure((Exception())))
uiaContinuation = null uiaContinuation = null
pendingAuth = null pendingAuth = null
Unit
} }
} }
} }

View file

@ -16,38 +16,50 @@
package im.vector.app.features.settings.devices package im.vector.app.features.settings.devices
import androidx.annotation.DrawableRes import org.matrix.android.sdk.api.crypto.RoomEncryptionTrustLevel
import im.vector.app.R
import org.matrix.android.sdk.internal.crypto.crosssigning.DeviceTrustLevel import org.matrix.android.sdk.internal.crypto.crosssigning.DeviceTrustLevel
object TrustUtils { object TrustUtils {
@DrawableRes fun shieldForTrust(currentDevice: Boolean,
fun shieldForTrust(currentDevice: Boolean, trustMSK: Boolean, legacyMode: Boolean, deviceTrustLevel: DeviceTrustLevel?): Int { trustMSK: Boolean,
legacyMode: Boolean,
deviceTrustLevel: DeviceTrustLevel?): RoomEncryptionTrustLevel {
return when { return when {
currentDevice -> { currentDevice -> {
if (legacyMode) { if (legacyMode) {
// In legacy, current session is always trusted // In legacy, current session is always trusted
R.drawable.ic_shield_trusted RoomEncryptionTrustLevel.Trusted
} else { } else {
// If current session doesn't trust MSK, show red shield for current device // If current session doesn't trust MSK, show red shield for current device
R.drawable.ic_shield_trusted.takeIf { trustMSK } ?: R.drawable.ic_shield_warning if (trustMSK) {
RoomEncryptionTrustLevel.Trusted
} else {
RoomEncryptionTrustLevel.Warning
}
} }
} }
else -> { else -> {
if (legacyMode) { if (legacyMode) {
// use local trust // use local trust
R.drawable.ic_shield_trusted.takeIf { deviceTrustLevel?.locallyVerified == true } ?: R.drawable.ic_shield_warning if (deviceTrustLevel?.locallyVerified == true) {
RoomEncryptionTrustLevel.Trusted
} else {
RoomEncryptionTrustLevel.Warning
}
} else { } else {
if (trustMSK) { if (trustMSK) {
// use cross sign trust, put locally trusted in black // use cross sign trust, put locally trusted in black
R.drawable.ic_shield_trusted.takeIf { deviceTrustLevel?.crossSigningVerified == true } when {
?: R.drawable.ic_shield_black.takeIf { deviceTrustLevel?.locallyVerified == true } deviceTrustLevel?.crossSigningVerified == true -> RoomEncryptionTrustLevel.Trusted
?: R.drawable.ic_shield_warning
deviceTrustLevel?.locallyVerified == true -> RoomEncryptionTrustLevel.Default
else -> RoomEncryptionTrustLevel.Warning
}
} else { } else {
// The current session is untrusted, so displays others in black // The current session is untrusted, so displays others in black
// as we can't know the cross-signing state // as we can't know the cross-signing state
R.drawable.ic_shield_black RoomEncryptionTrustLevel.Default
} }
} }
} }

View file

@ -68,7 +68,7 @@ class AccountDataEpoxyController @Inject constructor(
genericItemWithValue { genericItemWithValue {
id(accountData.type) id(accountData.type)
title(accountData.type) title(accountData.type)
itemClickAction(DebouncedClickListener(View.OnClickListener { itemClickAction(DebouncedClickListener({
interactionListener?.didTap(accountData) interactionListener?.didTap(accountData)
})) }))
itemLongClickAction(View.OnLongClickListener { itemLongClickAction(View.OnLongClickListener {

View file

@ -67,7 +67,7 @@ class KeyRequestsFragment @Inject constructor(
override fun onPageScrollStateChanged(state: Int) { override fun onPageScrollStateChanged(state: Int) {
childFragmentManager.fragments.forEach { childFragmentManager.fragments.forEach {
setHasOptionsMenu(state == SCROLL_STATE_IDLE) it.setHasOptionsMenu(state == SCROLL_STATE_IDLE)
} }
invalidateOptionsMenu() invalidateOptionsMenu()
} }

View file

@ -59,10 +59,13 @@ abstract class PushRuleItem : EpoxyModelWithHolder<PushRuleItem.Holder>() {
if (notifAction.shouldNotify && !notifAction.soundName.isNullOrBlank()) { if (notifAction.shouldNotify && !notifAction.soundName.isNullOrBlank()) {
holder.actionIcon.setImageDrawable(ContextCompat.getDrawable(context, R.drawable.ic_action_notify_noisy)) holder.actionIcon.setImageDrawable(ContextCompat.getDrawable(context, R.drawable.ic_action_notify_noisy))
holder.actionIcon.contentDescription = context.getString(R.string.a11y_rule_notify_noisy)
} else if (notifAction.shouldNotify) { } else if (notifAction.shouldNotify) {
holder.actionIcon.setImageDrawable(ContextCompat.getDrawable(context, R.drawable.ic_action_notify_silent)) holder.actionIcon.setImageDrawable(ContextCompat.getDrawable(context, R.drawable.ic_action_notify_silent))
holder.actionIcon.contentDescription = context.getString(R.string.a11y_rule_notify_silent)
} else { } else {
holder.actionIcon.setImageDrawable(ContextCompat.getDrawable(context, R.drawable.ic_action_dont_notify)) holder.actionIcon.setImageDrawable(ContextCompat.getDrawable(context, R.drawable.ic_action_dont_notify))
holder.actionIcon.contentDescription = context.getString(R.string.a11y_rule_notify_off)
} }
val description = StringBuffer() val description = StringBuffer()

View file

@ -98,7 +98,7 @@ class NotificationTroubleshootRecyclerViewAdapter(val tests: ArrayList<Troublesh
val quickFix = test.quickFix val quickFix = test.quickFix
if (quickFix != null) { if (quickFix != null) {
troubleshootTestButton.setText(test.quickFix!!.title) troubleshootTestButton.setText(test.quickFix!!.title)
troubleshootTestButton.setOnClickListener { _ -> troubleshootTestButton.setOnClickListener {
test.quickFix!!.doFix() test.quickFix!!.doFix()
} }
troubleshootTestButton.visibility = View.VISIBLE troubleshootTestButton.visibility = View.VISIBLE

View file

@ -121,7 +121,7 @@ class IncomingShareFragment @Inject constructor(
return true return true
} }
}) })
views.sendShareButton.setOnClickListener { _ -> views.sendShareButton.setOnClickListener {
handleSendShare() handleSendShare()
} }
} }

View file

@ -19,7 +19,6 @@ package im.vector.app.features.signout.soft.epoxy
import android.os.Build import android.os.Build
import android.text.Editable import android.text.Editable
import android.widget.Button import android.widget.Button
import android.widget.ImageView
import androidx.autofill.HintConstants import androidx.autofill.HintConstants
import com.airbnb.epoxy.EpoxyAttribute import com.airbnb.epoxy.EpoxyAttribute
import com.airbnb.epoxy.EpoxyModelClass import com.airbnb.epoxy.EpoxyModelClass
@ -31,6 +30,7 @@ import im.vector.app.core.epoxy.VectorEpoxyModel
import im.vector.app.core.extensions.showPassword import im.vector.app.core.extensions.showPassword
import im.vector.app.core.platform.SimpleTextWatcher import im.vector.app.core.platform.SimpleTextWatcher
import im.vector.app.core.resources.StringProvider import im.vector.app.core.resources.StringProvider
import im.vector.app.core.ui.views.RevealPasswordImageView
@EpoxyModelClass(layout = R.layout.item_login_password_form) @EpoxyModelClass(layout = R.layout.item_login_password_form)
abstract class LoginPasswordFormItem : VectorEpoxyModel<LoginPasswordFormItem.Holder>() { abstract class LoginPasswordFormItem : VectorEpoxyModel<LoginPasswordFormItem.Holder>() {
@ -76,20 +76,13 @@ abstract class LoginPasswordFormItem : VectorEpoxyModel<LoginPasswordFormItem.Ho
private fun renderPasswordField(holder: Holder) { private fun renderPasswordField(holder: Holder) {
holder.passwordField.showPassword(passwordShown) holder.passwordField.showPassword(passwordShown)
holder.passwordReveal.render(passwordShown)
if (passwordShown) {
holder.passwordReveal.setImageResource(R.drawable.ic_eye_closed)
holder.passwordReveal.contentDescription = stringProvider.getString(R.string.a11y_hide_password)
} else {
holder.passwordReveal.setImageResource(R.drawable.ic_eye)
holder.passwordReveal.contentDescription = stringProvider.getString(R.string.a11y_show_password)
}
} }
class Holder : VectorEpoxyHolder() { class Holder : VectorEpoxyHolder() {
val passwordField by bind<TextInputEditText>(R.id.itemLoginPasswordFormPasswordField) val passwordField by bind<TextInputEditText>(R.id.itemLoginPasswordFormPasswordField)
val passwordFieldTil by bind<TextInputLayout>(R.id.itemLoginPasswordFormPasswordFieldTil) val passwordFieldTil by bind<TextInputLayout>(R.id.itemLoginPasswordFormPasswordFieldTil)
val passwordReveal by bind<ImageView>(R.id.itemLoginPasswordFormPasswordReveal) val passwordReveal by bind<RevealPasswordImageView>(R.id.itemLoginPasswordFormPasswordReveal)
val forgetPassword by bind<Button>(R.id.itemLoginPasswordFormForgetPasswordButton) val forgetPassword by bind<Button>(R.id.itemLoginPasswordFormForgetPasswordButton)
val submit by bind<Button>(R.id.itemLoginPasswordFormSubmit) val submit by bind<Button>(R.id.itemLoginPasswordFormSubmit)
} }

View file

@ -49,7 +49,7 @@ import timber.log.Timber
import javax.net.ssl.HttpsURLConnection import javax.net.ssl.HttpsURLConnection
class WidgetViewModel @AssistedInject constructor(@Assisted val initialState: WidgetViewState, class WidgetViewModel @AssistedInject constructor(@Assisted val initialState: WidgetViewState,
private val widgetPostAPIHandlerFactory: WidgetPostAPIHandler.Factory, widgetPostAPIHandlerFactory: WidgetPostAPIHandler.Factory,
private val stringProvider: StringProvider, private val stringProvider: StringProvider,
private val session: Session) private val session: Session)
: VectorViewModel<WidgetViewState, WidgetAction, WidgetViewEvents>(initialState), : VectorViewModel<WidgetViewState, WidgetAction, WidgetViewEvents>(initialState),

View file

@ -150,6 +150,7 @@
android:layout_gravity="center_horizontal" android:layout_gravity="center_horizontal"
android:layout_marginTop="10dp" android:layout_marginTop="10dp"
android:adjustViewBounds="true" android:adjustViewBounds="true"
android:contentDescription="@string/a11y_screenshot"
android:maxWidth="260dp" android:maxWidth="260dp"
android:scaleType="fitCenter" android:scaleType="fitCenter"
tools:src="@tools:sample/backgrounds/scenic" /> tools:src="@tools:sample/backgrounds/scenic" />

View file

@ -16,6 +16,7 @@
android:id="@+id/bgCallView" android:id="@+id/bgCallView"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="match_parent" android:layout_height="match_parent"
android:importantForAccessibility="no"
android:scaleType="centerCrop" android:scaleType="centerCrop"
tools:src="@tools:sample/avatars" /> tools:src="@tools:sample/avatars" />
@ -53,6 +54,7 @@
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="match_parent" android:layout_height="match_parent"
android:foreground="?attr/selectableItemBackground" android:foreground="?attr/selectableItemBackground"
android:importantForAccessibility="no"
android:scaleType="centerCrop" android:scaleType="centerCrop"
tools:src="@tools:sample/avatars" /> tools:src="@tools:sample/avatars" />
@ -61,6 +63,7 @@
android:layout_width="20dp" android:layout_width="20dp"
android:layout_height="20dp" android:layout_height="20dp"
android:layout_gravity="center" android:layout_gravity="center"
android:importantForAccessibility="no"
android:src="@drawable/ic_call_small_pause" /> android:src="@drawable/ic_call_small_pause" />
</FrameLayout> </FrameLayout>
@ -70,6 +73,7 @@
android:layout_width="80dp" android:layout_width="80dp"
android:layout_height="80dp" android:layout_height="80dp"
android:contentDescription="@string/avatar" android:contentDescription="@string/avatar"
android:importantForAccessibility="no"
android:scaleType="centerCrop" android:scaleType="centerCrop"
app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent" app:layout_constraintEnd_toEndOf="parent"
@ -81,13 +85,13 @@
android:id="@+id/smallIsHeldIcon" android:id="@+id/smallIsHeldIcon"
android:layout_width="20dp" android:layout_width="20dp"
android:layout_height="20dp" android:layout_height="20dp"
android:importantForAccessibility="no"
android:src="@drawable/ic_call_small_pause" android:src="@drawable/ic_call_small_pause"
app:layout_constraintBottom_toBottomOf="@id/otherMemberAvatar" app:layout_constraintBottom_toBottomOf="@id/otherMemberAvatar"
app:layout_constraintEnd_toEndOf="@id/otherMemberAvatar" app:layout_constraintEnd_toEndOf="@id/otherMemberAvatar"
app:layout_constraintStart_toStartOf="@id/otherMemberAvatar" app:layout_constraintStart_toStartOf="@id/otherMemberAvatar"
app:layout_constraintTop_toTopOf="@id/otherMemberAvatar" /> app:layout_constraintTop_toTopOf="@id/otherMemberAvatar" />
<TextView <TextView
android:id="@+id/participantNameText" android:id="@+id/participantNameText"
android:layout_width="0dp" android:layout_width="0dp"

View file

@ -1,6 +1,7 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/callDialPad" android:id="@+id/callDialPad"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="match_parent" android:layout_height="match_parent"
@ -27,10 +28,12 @@
android:id="@+id/callDialPadClose" android:id="@+id/callDialPadClose"
android:layout_width="@dimen/layout_touch_size" android:layout_width="@dimen/layout_touch_size"
android:layout_height="@dimen/layout_touch_size" android:layout_height="@dimen/layout_touch_size"
android:scaleType="center" android:contentDescription="@string/action_close"
app:tint="?riotx_text_primary"
android:foreground="?selectableItemBackground" android:foreground="?selectableItemBackground"
android:src="@drawable/ic_cross" /> android:scaleType="center"
android:src="@drawable/ic_cross"
app:tint="?riotx_text_primary"
tools:ignore="MissingPrefix" />
</LinearLayout> </LinearLayout>

View file

@ -1,7 +1,6 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/callControlsWrapper" android:id="@+id/callControlsWrapper"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="match_parent" android:layout_height="match_parent"

View file

@ -47,6 +47,7 @@
android:id="@+id/backupCompleteImage" android:id="@+id/backupCompleteImage"
android:layout_width="20dp" android:layout_width="20dp"
android:layout_height="20dp" android:layout_height="20dp"
android:importantForAccessibility="no"
android:visibility="gone" android:visibility="gone"
app:srcCompat="@drawable/unit_test_ok" app:srcCompat="@drawable/unit_test_ok"
tools:visibility="visible" /> tools:visibility="visible" />

View file

@ -22,6 +22,7 @@
android:layout_width="60dp" android:layout_width="60dp"
android:layout_height="60dp" android:layout_height="60dp"
android:layout_marginTop="@dimen/layout_vertical_margin_big" android:layout_marginTop="@dimen/layout_vertical_margin_big"
android:contentDescription="@string/avatar"
android:elevation="4dp" android:elevation="4dp"
android:transitionName="profile" android:transitionName="profile"
app:layout_constraintEnd_toEndOf="parent" app:layout_constraintEnd_toEndOf="parent"

View file

@ -45,6 +45,7 @@
android:layout_width="40dp" android:layout_width="40dp"
android:layout_height="40dp" android:layout_height="40dp"
android:layout_gravity="center" android:layout_gravity="center"
android:contentDescription="@string/avatar"
tools:src="@tools:sample/avatars" /> tools:src="@tools:sample/avatars" />
<LinearLayout <LinearLayout

Some files were not shown because too many files have changed in this diff Show more