mirror of
https://github.com/SchildiChat/SchildiChat-android.git
synced 2024-11-27 12:00:03 +03:00
commit
03735d9213
221 changed files with 651 additions and 607 deletions
|
@ -8,6 +8,7 @@ Improvements 🙌:
|
|||
- VoIP : new tiles in timeline
|
||||
- Improve room profile UX
|
||||
- Upgrade Jitsi library from 2.9.3 to 3.1.0
|
||||
- a11y improvements
|
||||
|
||||
Bugfix 🐛:
|
||||
- VoIP : fix audio devices output
|
||||
|
|
|
@ -17,6 +17,10 @@
|
|||
<issue id="ButtonOrder" severity="error" />
|
||||
<issue id="TextFields" severity="error" />
|
||||
|
||||
<!-- Accessibility -->
|
||||
<issue id="LabelFor" severity="error" />
|
||||
<issue id="ContentDescription" severity="error" />
|
||||
|
||||
<!-- Layout -->
|
||||
<issue id="UnknownIdInLayout" severity="error" />
|
||||
<issue id="StringFormatCount" severity="error" />
|
||||
|
|
|
@ -159,6 +159,7 @@
|
|||
<com.google.android.material.floatingactionbutton.FloatingActionButton
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:importantForAccessibility="no"
|
||||
android:src="@drawable/ic_settings_x" />
|
||||
|
||||
</LinearLayout>
|
||||
|
|
|
@ -21,6 +21,7 @@
|
|||
div {
|
||||
padding: 4px;
|
||||
}
|
||||
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
|
@ -388,7 +389,7 @@ SOFTWARE.
|
|||
<li>
|
||||
<b>dialogs / android-dialer</b>
|
||||
<br/>
|
||||
Copyright (c) 2017-present, dialog LLC <info@dlg.im>
|
||||
Copyright (c) 2017-present, dialog LLC <info@dlg.im>
|
||||
</li>
|
||||
</ul>
|
||||
<pre>
|
||||
|
@ -570,20 +571,24 @@ Apache License
|
|||
|
||||
<pre>
|
||||
CC-BY 4.0
|
||||
</pre>
|
||||
<ul>
|
||||
<li>
|
||||
<b>Twitter/twemoji Graphics</b>
|
||||
<br/>
|
||||
</li>
|
||||
</pre>
|
||||
</ul>
|
||||
|
||||
<pre>
|
||||
ISC License
|
||||
</pre>
|
||||
<ul>
|
||||
<li>
|
||||
<b>DanielMartinus / Konfetti</b>
|
||||
<br/>
|
||||
Copyright (c) 2017 Dion Segijn
|
||||
</li>
|
||||
</pre>
|
||||
</ul>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
|
|
|
@ -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.notifications.PushRuleTriggerListener
|
||||
import im.vector.app.features.session.SessionListener
|
||||
import org.matrix.android.sdk.api.auth.AuthenticationService
|
||||
import org.matrix.android.sdk.api.session.Session
|
||||
import timber.log.Timber
|
||||
import java.util.concurrent.atomic.AtomicReference
|
||||
|
@ -31,8 +30,7 @@ import javax.inject.Inject
|
|||
import javax.inject.Singleton
|
||||
|
||||
@Singleton
|
||||
class ActiveSessionHolder @Inject constructor(private val authenticationService: AuthenticationService,
|
||||
private val sessionObservableStore: ActiveSessionDataSource,
|
||||
class ActiveSessionHolder @Inject constructor(private val sessionObservableStore: ActiveSessionDataSource,
|
||||
private val keyRequestHandler: KeyRequestHandler,
|
||||
private val incomingVerificationRequestHandler: IncomingVerificationRequestHandler,
|
||||
private val callManager: WebRtcCallManager,
|
||||
|
|
|
@ -61,7 +61,7 @@ class ExportKeysDialog {
|
|||
passwordVisible = !passwordVisible
|
||||
views.exportDialogEt.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()
|
||||
|
|
|
@ -44,7 +44,7 @@ class PromptPasswordDialog {
|
|||
views.promptPasswordPasswordReveal.setOnClickListener {
|
||||
passwordVisible = !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)
|
||||
|
|
|
@ -21,7 +21,6 @@ import androidx.core.view.isVisible
|
|||
import com.airbnb.epoxy.EpoxyAttribute
|
||||
import im.vector.app.core.epoxy.VectorEpoxyModel
|
||||
import im.vector.app.core.extensions.setTextOrHide
|
||||
import im.vector.app.features.crypto.util.toImageRes
|
||||
import im.vector.app.features.home.AvatarRenderer
|
||||
import org.matrix.android.sdk.api.crypto.RoomEncryptionTrustLevel
|
||||
import org.matrix.android.sdk.api.util.MatrixItem
|
||||
|
@ -47,6 +46,6 @@ abstract class BaseProfileMatrixItem<T : ProfileMatrixItem.Holder> : VectorEpoxy
|
|||
holder.subtitleView.setTextOrHide(matrixId)
|
||||
holder.editableView.isVisible = editable
|
||||
avatarRenderer.render(matrixItem, holder.avatarImageView)
|
||||
holder.avatarDecorationImageView.setImageResource(userEncryptionTrustLevel.toImageRes())
|
||||
holder.avatarDecorationImageView.render(userEncryptionTrustLevel)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -23,6 +23,7 @@ import android.widget.TextView
|
|||
import com.airbnb.epoxy.EpoxyModelClass
|
||||
import im.vector.app.R
|
||||
import im.vector.app.core.epoxy.VectorEpoxyHolder
|
||||
import im.vector.app.core.ui.views.ShieldImageView
|
||||
|
||||
@EpoxyModelClass(layout = R.layout.item_profile_matrix_item)
|
||||
abstract class ProfileMatrixItem : BaseProfileMatrixItem<ProfileMatrixItem.Holder>() {
|
||||
|
@ -31,7 +32,7 @@ abstract class ProfileMatrixItem : BaseProfileMatrixItem<ProfileMatrixItem.Holde
|
|||
val titleView by bind<TextView>(R.id.matrixItemTitle)
|
||||
val subtitleView by bind<TextView>(R.id.matrixItemSubtitle)
|
||||
val avatarImageView by bind<ImageView>(R.id.matrixItemAvatar)
|
||||
val avatarDecorationImageView by bind<ImageView>(R.id.matrixItemAvatarDecoration)
|
||||
val avatarDecorationImageView by bind<ShieldImageView>(R.id.matrixItemAvatarDecoration)
|
||||
val editableView by bind<View>(R.id.matrixItemEditable)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -19,17 +19,16 @@ package im.vector.app.core.extensions
|
|||
import androidx.lifecycle.LifecycleOwner
|
||||
import androidx.lifecycle.LiveData
|
||||
import androidx.lifecycle.MutableLiveData
|
||||
import androidx.lifecycle.Observer
|
||||
import im.vector.app.core.utils.EventObserver
|
||||
import im.vector.app.core.utils.FirstThrottler
|
||||
import im.vector.app.core.utils.LiveEvent
|
||||
|
||||
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) {
|
||||
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) {
|
||||
|
|
|
@ -40,7 +40,6 @@ import androidx.core.view.isVisible
|
|||
import androidx.fragment.app.Fragment
|
||||
import androidx.fragment.app.FragmentFactory
|
||||
import androidx.fragment.app.FragmentManager
|
||||
import androidx.lifecycle.Observer
|
||||
import androidx.lifecycle.ViewModelProvider
|
||||
import androidx.viewbinding.ViewBinding
|
||||
import com.bumptech.glide.util.Util
|
||||
|
@ -208,12 +207,12 @@ abstract class VectorBaseActivity<VB: ViewBinding> : AppCompatActivity(), HasScr
|
|||
navigator = screenComponent.navigator()
|
||||
activeSessionHolder = screenComponent.activeSessionHolder()
|
||||
vectorPreferences = vectorComponent.vectorPreferences()
|
||||
configurationViewModel.activityRestarter.observe(this, Observer {
|
||||
configurationViewModel.activityRestarter.observe(this) {
|
||||
if (!it.hasBeenHandled) {
|
||||
// Recreate the Activity because configuration has changed
|
||||
restart()
|
||||
}
|
||||
})
|
||||
}
|
||||
pinLocker.getLiveState().observeNotNull(this) {
|
||||
if (this@VectorBaseActivity !is UnlockedActivity && it == PinLocker.State.LOCKED) {
|
||||
navigator.openPinCode(this, pinStartForActivityResult, PinMode.AUTH)
|
||||
|
|
|
@ -89,7 +89,7 @@ class KnownCallsViewHolder {
|
|||
this.pipWrapper = pipWrapper
|
||||
this.currentCallsView?.callback = interactionListener
|
||||
pipWrapper.setOnClickListener(
|
||||
DebouncedClickListener({ _ ->
|
||||
DebouncedClickListener({
|
||||
interactionListener.onTapToReturnToCall()
|
||||
})
|
||||
)
|
||||
|
|
|
@ -56,6 +56,7 @@ class ReadReceiptsView @JvmOverloads constructor(
|
|||
|
||||
private fun setupView() {
|
||||
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) {
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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
|
||||
}
|
||||
}
|
|
@ -27,8 +27,8 @@ class CountUpTimer(private val intervalInMs: Long) {
|
|||
private val resumed: AtomicBoolean = AtomicBoolean(false)
|
||||
|
||||
private val disposable = Observable.interval(intervalInMs, TimeUnit.MILLISECONDS)
|
||||
.filter { _ -> resumed.get() }
|
||||
.doOnNext { _ -> elapsedTime.addAndGet(intervalInMs) }
|
||||
.filter { resumed.get() }
|
||||
.doOnNext { elapsedTime.addAndGet(intervalInMs) }
|
||||
.subscribe {
|
||||
tickListener?.onTick(elapsedTime.get())
|
||||
}
|
||||
|
|
|
@ -49,7 +49,7 @@ open class BehaviorDataSource<T>(private val defaultValue: T? = null) : MutableD
|
|||
|
||||
private fun createRelay(): BehaviorRelay<T> {
|
||||
return if (defaultValue == null) {
|
||||
BehaviorRelay.create<T>()
|
||||
BehaviorRelay.create()
|
||||
} else {
|
||||
BehaviorRelay.createDefault(defaultValue)
|
||||
}
|
||||
|
|
|
@ -19,12 +19,11 @@ package im.vector.app.core.utils
|
|||
import io.reactivex.Completable
|
||||
import io.reactivex.Single
|
||||
import io.reactivex.disposables.Disposable
|
||||
import io.reactivex.functions.Consumer
|
||||
import io.reactivex.internal.functions.Functions
|
||||
import timber.log.Timber
|
||||
|
||||
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 {
|
||||
|
|
|
@ -87,14 +87,7 @@ class PromptFragment : VectorBaseFragment<FragmentReauthConfirmBinding>() {
|
|||
}
|
||||
|
||||
views.passwordField.showPassword(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)
|
||||
}
|
||||
views.passwordReveal.render(it.passwordVisible)
|
||||
|
||||
if (it.lastErrorCode != null) {
|
||||
when (it.flowType) {
|
||||
|
|
|
@ -102,7 +102,7 @@ abstract class RecyclerViewPresenter<T>(context: Context?) : AutocompletePresent
|
|||
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() {
|
||||
root.onChanged()
|
||||
}
|
||||
|
|
|
@ -31,7 +31,7 @@ import org.matrix.android.sdk.api.session.room.model.RoomMemberSummary
|
|||
|
||||
class AutocompleteMemberPresenter @AssistedInject constructor(context: Context,
|
||||
@Assisted val roomId: String,
|
||||
private val session: Session,
|
||||
session: Session,
|
||||
private val controller: AutocompleteMemberController
|
||||
) : RecyclerViewPresenter<RoomMemberSummary>(context), AutocompleteClickListener<RoomMemberSummary> {
|
||||
|
||||
|
|
|
@ -383,7 +383,7 @@ class VectorCallActivity : VectorBaseActivity<ActivityCallBinding>(), CallContro
|
|||
mode: String?): Intent {
|
||||
return Intent(context, VectorCallActivity::class.java).apply {
|
||||
// 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(EXTRA_MODE, mode)
|
||||
}
|
||||
|
|
|
@ -19,7 +19,6 @@ import android.app.Activity
|
|||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import androidx.appcompat.app.AlertDialog
|
||||
import androidx.lifecycle.Observer
|
||||
import im.vector.app.R
|
||||
import im.vector.app.core.extensions.addFragmentToBackstack
|
||||
import im.vector.app.core.extensions.observeEvent
|
||||
|
@ -54,7 +53,7 @@ class KeysBackupRestoreActivity : SimpleFragmentActivity() {
|
|||
viewModel = viewModelProvider.get(KeysBackupRestoreSharedViewModel::class.java)
|
||||
viewModel.initSession(session)
|
||||
|
||||
viewModel.keySourceModel.observe(this, Observer { keySource ->
|
||||
viewModel.keySourceModel.observe(this) { keySource ->
|
||||
if (keySource != null && !keySource.isInQuadS && supportFragmentManager.fragments.isEmpty()) {
|
||||
val isBackupCreatedFromPassphrase =
|
||||
viewModel.keyVersionResult.value?.getAuthDataAsMegolmBackupAuthData()?.privateKeySalt != null
|
||||
|
@ -64,7 +63,7 @@ class KeysBackupRestoreActivity : SimpleFragmentActivity() {
|
|||
replaceFragment(R.id.container, KeysBackupRestoreFromKeyFragment::class.java)
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
viewModel.keyVersionResultError.observeEvent(this) { message ->
|
||||
AlertDialog.Builder(this)
|
||||
|
@ -111,9 +110,9 @@ class KeysBackupRestoreActivity : SimpleFragmentActivity() {
|
|||
}
|
||||
}
|
||||
|
||||
viewModel.loadingEvent.observe(this, Observer {
|
||||
viewModel.loadingEvent.observe(this) {
|
||||
updateWaitingView(it)
|
||||
})
|
||||
}
|
||||
|
||||
viewModel.importRoomKeysFinishWithResult.observeEvent(this) {
|
||||
// set data?
|
||||
|
|
|
@ -22,7 +22,6 @@ import android.view.View
|
|||
import android.view.ViewGroup
|
||||
import android.view.inputmethod.EditorInfo
|
||||
import androidx.core.widget.doOnTextChanged
|
||||
import androidx.lifecycle.Observer
|
||||
import im.vector.app.R
|
||||
import im.vector.app.core.extensions.registerStartForActivityResult
|
||||
import im.vector.app.core.platform.VectorBaseFragment
|
||||
|
@ -56,9 +55,9 @@ class KeysBackupRestoreFromKeyFragment @Inject constructor()
|
|||
}
|
||||
|
||||
views.keyInputLayout.error = viewModel.recoveryCodeErrorText.value
|
||||
viewModel.recoveryCodeErrorText.observe(viewLifecycleOwner, Observer { newValue ->
|
||||
viewModel.recoveryCodeErrorText.observe(viewLifecycleOwner) { newValue ->
|
||||
views.keyInputLayout.error = newValue
|
||||
})
|
||||
}
|
||||
|
||||
views.keysRestoreButton.setOnClickListener { onRestoreFromKey() }
|
||||
views.keysBackupImport.setOnClickListener { onImport() }
|
||||
|
|
|
@ -24,7 +24,6 @@ import android.view.ViewGroup
|
|||
import android.view.inputmethod.EditorInfo
|
||||
import androidx.core.text.set
|
||||
import androidx.core.widget.doOnTextChanged
|
||||
import androidx.lifecycle.Observer
|
||||
import im.vector.app.R
|
||||
import im.vector.app.core.extensions.showPassword
|
||||
import im.vector.app.core.platform.VectorBaseFragment
|
||||
|
@ -51,17 +50,17 @@ class KeysBackupRestoreFromPassphraseFragment @Inject constructor() : VectorBase
|
|||
viewModel = fragmentViewModelProvider.get(KeysBackupRestoreFromPassphraseViewModel::class.java)
|
||||
sharedViewModel = activityViewModelProvider.get(KeysBackupRestoreSharedViewModel::class.java)
|
||||
|
||||
viewModel.passphraseErrorText.observe(viewLifecycleOwner, Observer { newValue ->
|
||||
viewModel.passphraseErrorText.observe(viewLifecycleOwner) { newValue ->
|
||||
views.keysBackupPassphraseEnterTil.error = newValue
|
||||
})
|
||||
}
|
||||
|
||||
views.helperTextWithLink.text = spannableStringForHelperText()
|
||||
|
||||
viewModel.showPasswordMode.observe(viewLifecycleOwner, Observer {
|
||||
viewModel.showPasswordMode.observe(viewLifecycleOwner) {
|
||||
val shouldBeVisible = it ?: false
|
||||
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, _ ->
|
||||
if (actionId == EditorInfo.IME_ACTION_DONE) {
|
||||
|
|
|
@ -21,7 +21,6 @@ import android.content.Intent
|
|||
import androidx.appcompat.app.AlertDialog
|
||||
import androidx.core.view.isVisible
|
||||
import androidx.fragment.app.FragmentManager
|
||||
import androidx.lifecycle.Observer
|
||||
import im.vector.app.R
|
||||
import im.vector.app.core.dialogs.ExportKeysDialog
|
||||
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.initSession(session)
|
||||
|
||||
viewModel.isCreatingBackupVersion.observe(this, Observer {
|
||||
viewModel.isCreatingBackupVersion.observe(this) {
|
||||
val isCreating = it ?: false
|
||||
if (isCreating) {
|
||||
showWaitingView()
|
||||
} else {
|
||||
hideWaitingView()
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
viewModel.loadingStatus.observe(this, Observer {
|
||||
viewModel.loadingStatus.observe(this) {
|
||||
it?.let {
|
||||
updateWaitingView(it)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
viewModel.navigateEvent.observeEvent(this) { uxStateEvent ->
|
||||
when (uxStateEvent) {
|
||||
|
@ -99,7 +98,7 @@ class KeysBackupSetupActivity : SimpleFragmentActivity() {
|
|||
}
|
||||
}
|
||||
|
||||
viewModel.prepareRecoverFailError.observe(this, Observer { error ->
|
||||
viewModel.prepareRecoverFailError.observe(this) { error ->
|
||||
if (error != null) {
|
||||
AlertDialog.Builder(this)
|
||||
.setTitle(R.string.unknown_error)
|
||||
|
@ -110,9 +109,9 @@ class KeysBackupSetupActivity : SimpleFragmentActivity() {
|
|||
}
|
||||
.show()
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
viewModel.creatingBackupError.observe(this, Observer { error ->
|
||||
viewModel.creatingBackupError.observe(this) { error ->
|
||||
if (error != null) {
|
||||
AlertDialog.Builder(this)
|
||||
.setTitle(R.string.unexpected_error)
|
||||
|
@ -123,7 +122,7 @@ class KeysBackupSetupActivity : SimpleFragmentActivity() {
|
|||
}
|
||||
.show()
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
private val saveStartForActivityResult = registerStartForActivityResult { activityResult ->
|
||||
|
|
|
@ -20,7 +20,6 @@ import android.os.Bundle
|
|||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import androidx.lifecycle.Observer
|
||||
import im.vector.app.core.platform.VectorBaseFragment
|
||||
import im.vector.app.core.utils.LiveEvent
|
||||
import im.vector.app.databinding.FragmentKeysBackupSetupStep1Binding
|
||||
|
@ -40,12 +39,12 @@ class KeysBackupSetupStep1Fragment @Inject constructor() : VectorBaseFragment<Fr
|
|||
|
||||
viewModel = activityViewModelProvider.get(KeysBackupSetupSharedViewModel::class.java)
|
||||
|
||||
viewModel.showManualExport.observe(viewLifecycleOwner, Observer {
|
||||
viewModel.showManualExport.observe(viewLifecycleOwner) {
|
||||
val showOption = it ?: false
|
||||
// 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.keysBackupSetupStep1ManualExportButton.visibility = if (showOption) View.VISIBLE else View.GONE
|
||||
})
|
||||
}
|
||||
|
||||
views.keysBackupSetupStep1Button.setOnClickListener { onButtonClick() }
|
||||
views.keysBackupSetupStep1ManualExportButton.setOnClickListener { onManualExportClick() }
|
||||
|
|
|
@ -21,7 +21,6 @@ import android.view.View
|
|||
import android.view.ViewGroup
|
||||
import android.view.inputmethod.EditorInfo
|
||||
import androidx.core.widget.doOnTextChanged
|
||||
import androidx.lifecycle.Observer
|
||||
import androidx.lifecycle.viewModelScope
|
||||
import androidx.transition.TransitionManager
|
||||
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.databinding.FragmentKeysBackupSetupStep2Binding
|
||||
import im.vector.app.features.settings.VectorLocale
|
||||
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.launch
|
||||
import javax.inject.Inject
|
||||
|
@ -69,7 +67,7 @@ class KeysBackupSetupStep2Fragment @Inject constructor() : VectorBaseFragment<Fr
|
|||
* ========================================================================================== */
|
||||
|
||||
private fun bindViewToViewModel() {
|
||||
viewModel.passwordStrength.observe(viewLifecycleOwner, Observer { strength ->
|
||||
viewModel.passwordStrength.observe(viewLifecycleOwner) { strength ->
|
||||
if (strength == null) {
|
||||
views.keysBackupSetupStep2PassphraseStrengthLevel.strength = 0
|
||||
views.keysBackupSetupStep2PassphraseEnterTil.error = null
|
||||
|
@ -91,9 +89,9 @@ class KeysBackupSetupStep2Fragment @Inject constructor() : VectorBaseFragment<Fr
|
|||
views.keysBackupSetupStep2PassphraseEnterTil.error = null
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
viewModel.passphrase.observe(viewLifecycleOwner, Observer<String> { newValue ->
|
||||
viewModel.passphrase.observe(viewLifecycleOwner) { newValue ->
|
||||
if (newValue.isEmpty()) {
|
||||
viewModel.passwordStrength.value = null
|
||||
} else {
|
||||
|
@ -104,28 +102,28 @@ class KeysBackupSetupStep2Fragment @Inject constructor() : VectorBaseFragment<Fr
|
|||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
views.keysBackupSetupStep2PassphraseEnterEdittext.setText(viewModel.passphrase.value)
|
||||
|
||||
viewModel.passphraseError.observe(viewLifecycleOwner, Observer {
|
||||
viewModel.passphraseError.observe(viewLifecycleOwner) {
|
||||
TransitionManager.beginDelayedTransition(views.keysBackupRoot)
|
||||
views.keysBackupSetupStep2PassphraseEnterTil.error = it
|
||||
})
|
||||
}
|
||||
|
||||
views.keysBackupSetupStep2PassphraseConfirmEditText.setText(viewModel.confirmPassphrase.value)
|
||||
|
||||
viewModel.showPasswordMode.observe(viewLifecycleOwner, Observer {
|
||||
viewModel.showPasswordMode.observe(viewLifecycleOwner) {
|
||||
val shouldBeVisible = it ?: false
|
||||
views.keysBackupSetupStep2PassphraseEnterEdittext.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)
|
||||
views.keysBackupSetupStep2PassphraseConfirmTil.error = it
|
||||
})
|
||||
}
|
||||
|
||||
views.keysBackupSetupStep2PassphraseConfirmEditText.setOnEditorActionListener { _, actionId, _ ->
|
||||
if (actionId == EditorInfo.IME_ACTION_DONE) {
|
||||
|
@ -141,8 +139,8 @@ class KeysBackupSetupStep2Fragment @Inject constructor() : VectorBaseFragment<Fr
|
|||
views.keysBackupSetupStep2Button.setOnClickListener { doNext() }
|
||||
views.keysBackupSetupStep2SkipButton.setOnClickListener { skipPassphrase() }
|
||||
|
||||
views.keysBackupSetupStep2PassphraseEnterEdittext.doOnTextChanged { _, _, _, _ -> onPassphraseChanged() }
|
||||
views.keysBackupSetupStep2PassphraseConfirmEditText.doOnTextChanged { _, _, _, _ -> onConfirmPassphraseChanged() }
|
||||
views.keysBackupSetupStep2PassphraseEnterEdittext.doOnTextChanged { _, _, _, _ -> onPassphraseChanged() }
|
||||
views.keysBackupSetupStep2PassphraseConfirmEditText.doOnTextChanged { _, _, _, _ -> onConfirmPassphraseChanged() }
|
||||
}
|
||||
|
||||
private fun toggleVisibilityMode() {
|
||||
|
|
|
@ -25,7 +25,6 @@ import android.widget.TextView
|
|||
import android.widget.Toast
|
||||
import androidx.appcompat.app.AlertDialog
|
||||
import androidx.core.view.isVisible
|
||||
import androidx.lifecycle.Observer
|
||||
import arrow.core.Try
|
||||
import com.google.android.material.bottomsheet.BottomSheetDialog
|
||||
import im.vector.app.R
|
||||
|
@ -61,7 +60,7 @@ class KeysBackupSetupStep3Fragment @Inject constructor() : VectorBaseFragment<Fr
|
|||
|
||||
viewModel.shouldPromptOnBack = false
|
||||
|
||||
viewModel.passphrase.observe(viewLifecycleOwner, Observer {
|
||||
viewModel.passphrase.observe(viewLifecycleOwner) {
|
||||
if (it.isNullOrBlank()) {
|
||||
// Recovery was generated, so show key and options to save
|
||||
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.keysBackupSetupStep3RecoveryKeyText.isVisible = false
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
setupViews()
|
||||
}
|
||||
|
|
|
@ -183,11 +183,11 @@ class KeyRequestHandler @Inject constructor(
|
|||
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)
|
||||
})
|
||||
|
||||
alert.addButton(context.getString(R.string.ignore_request_short_label), Runnable {
|
||||
alert.addButton(context.getString(R.string.ignore_request_short_label), {
|
||||
denyAllRequests(mappingKey)
|
||||
})
|
||||
|
||||
|
|
|
@ -106,6 +106,6 @@ class SharedSecuredStoragePassphraseFragment @Inject constructor(
|
|||
override fun invalidate() = withState(sharedViewModel) { state ->
|
||||
val shouldBeVisible = state.passphraseVisible
|
||||
views.ssssPassphraseEnterEdittext.showPassword(shouldBeVisible)
|
||||
views.ssssViewShowPassword.setImageResource(if (shouldBeVisible) R.drawable.ic_eye_closed else R.drawable.ic_eye)
|
||||
views.ssssViewShowPassword.render(shouldBeVisible)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -97,7 +97,7 @@ class BackupToQuadSMigrationTask @Inject constructor(
|
|||
when {
|
||||
params.passphrase?.isNotEmpty() == true -> {
|
||||
reportProgress(params, R.string.bootstrap_progress_generating_ssss)
|
||||
awaitCallback<SsssKeyCreationInfo> {
|
||||
awaitCallback {
|
||||
quadS.generateKeyWithPassphrase(
|
||||
UUID.randomUUID().toString(),
|
||||
"ssss_key",
|
||||
|
|
|
@ -109,7 +109,7 @@ class BootstrapConfirmPassphraseFragment @Inject constructor()
|
|||
if (state.step is BootstrapStep.ConfirmPassphrase) {
|
||||
val isPasswordVisible = state.step.isPasswordVisible
|
||||
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)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -103,7 +103,7 @@ class BootstrapEnterPassphraseFragment @Inject constructor()
|
|||
if (state.step is BootstrapStep.SetupPassphrase) {
|
||||
val isPasswordVisible = state.step.isPasswordVisible
|
||||
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 ->
|
||||
val score = strength.score
|
||||
|
|
|
@ -133,7 +133,7 @@ class BootstrapMigrateBackupFragment @Inject constructor(
|
|||
if (state.step is BootstrapStep.GetBackupSecretPassForMigration) {
|
||||
val isPasswordVisible = state.step.isPasswordVisible
|
||||
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)
|
||||
|
|
|
@ -62,8 +62,7 @@ class BootstrapSaveRecoveryKeyFragment @Inject constructor(
|
|||
}
|
||||
}
|
||||
|
||||
private fun downloadRecoveryKey() = withState(sharedViewModel) { _ ->
|
||||
|
||||
private fun downloadRecoveryKey() {
|
||||
val intent = Intent(Intent.ACTION_CREATE_DOCUMENT)
|
||||
intent.addCategory(Intent.CATEGORY_OPENABLE)
|
||||
intent.type = "text/plain"
|
||||
|
|
|
@ -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
|
||||
}
|
|
@ -92,13 +92,11 @@ class IncomingVerificationRequestHandler @Inject constructor(
|
|||
}
|
||||
addButton(
|
||||
context.getString(R.string.ignore),
|
||||
Runnable {
|
||||
tx.cancel()
|
||||
}
|
||||
{ tx.cancel() }
|
||||
)
|
||||
addButton(
|
||||
context.getString(R.string.action_open),
|
||||
Runnable {
|
||||
{
|
||||
(weakCurrentActivity?.get() as? VectorBaseActivity<*>)?.let {
|
||||
it.navigator.performDeviceVerification(it, tx.otherUserId, tx.transactionId)
|
||||
}
|
||||
|
|
|
@ -24,7 +24,6 @@ import android.view.LayoutInflater
|
|||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import androidx.appcompat.app.AlertDialog
|
||||
import androidx.core.view.isVisible
|
||||
import androidx.fragment.app.Fragment
|
||||
import com.airbnb.mvrx.MvRx
|
||||
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.settings.VectorSettingsActivity
|
||||
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.crypto.crosssigning.KEYBACKUP_SECRET_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
|
||||
|| state.qrTransactionState == VerificationTxState.Verified
|
||||
|| state.verifiedFromPrivateKeys) {
|
||||
views.otherUserShield.setImageResource(R.drawable.ic_shield_trusted)
|
||||
views.otherUserShield.render(RoomEncryptionTrustLevel.Trusted)
|
||||
} else {
|
||||
views.otherUserShield.setImageResource(R.drawable.ic_shield_warning)
|
||||
views.otherUserShield.render(RoomEncryptionTrustLevel.Warning)
|
||||
}
|
||||
views.otherUserNameText.text = getString(
|
||||
if (state.selfVerificationMode) R.string.crosssigning_verify_this_session else R.string.crosssigning_verify_session
|
||||
)
|
||||
views.otherUserShield.isVisible = true
|
||||
} else {
|
||||
avatarRenderer.render(matrixItem, views.otherUserAvatarImageView)
|
||||
|
||||
if (state.sasTransactionState == VerificationTxState.Verified || state.qrTransactionState == VerificationTxState.Verified) {
|
||||
views.otherUserNameText.text = getString(R.string.verification_verified_user, matrixItem.getBestName())
|
||||
views.otherUserShield.isVisible = true
|
||||
views.otherUserShield.render(RoomEncryptionTrustLevel.Trusted)
|
||||
} else {
|
||||
views.otherUserNameText.text = getString(R.string.verification_verify_user, matrixItem.getBestName())
|
||||
views.otherUserShield.isVisible = false
|
||||
views.otherUserShield.render(null)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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.bottomSheetVerificationNoticeItem
|
||||
import im.vector.app.features.html.EventHtmlRenderer
|
||||
import org.matrix.android.sdk.api.crypto.RoomEncryptionTrustLevel
|
||||
import javax.inject.Inject
|
||||
|
||||
class VerificationConclusionController @Inject constructor(
|
||||
|
@ -56,7 +57,7 @@ class VerificationConclusionController @Inject constructor(
|
|||
|
||||
bottomSheetVerificationBigImageItem {
|
||||
id("image")
|
||||
imageRes(R.drawable.ic_shield_trusted)
|
||||
roomEncryptionTrustLevel(RoomEncryptionTrustLevel.Trusted)
|
||||
}
|
||||
|
||||
bottomDone()
|
||||
|
@ -69,7 +70,7 @@ class VerificationConclusionController @Inject constructor(
|
|||
|
||||
bottomSheetVerificationBigImageItem {
|
||||
id("image")
|
||||
imageRes(R.drawable.ic_shield_warning)
|
||||
roomEncryptionTrustLevel(RoomEncryptionTrustLevel.Warning)
|
||||
}
|
||||
|
||||
bottomSheetVerificationNoticeItem {
|
||||
|
|
|
@ -16,13 +16,13 @@
|
|||
*/
|
||||
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.EpoxyModelClass
|
||||
import im.vector.app.R
|
||||
import im.vector.app.core.epoxy.VectorEpoxyHolder
|
||||
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.
|
||||
|
@ -31,24 +31,14 @@ import im.vector.app.core.epoxy.VectorEpoxyModel
|
|||
abstract class BottomSheetVerificationBigImageItem : VectorEpoxyModel<BottomSheetVerificationBigImageItem.Holder>() {
|
||||
|
||||
@EpoxyAttribute
|
||||
var imageRes: Int = 0
|
||||
|
||||
@EpoxyAttribute
|
||||
var contentDescription: String? = null
|
||||
lateinit var roomEncryptionTrustLevel: RoomEncryptionTrustLevel
|
||||
|
||||
override fun bind(holder: Holder) {
|
||||
super.bind(holder)
|
||||
holder.image.setImageResource(imageRes)
|
||||
|
||||
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
|
||||
}
|
||||
holder.image.render(roomEncryptionTrustLevel)
|
||||
}
|
||||
|
||||
class Holder : VectorEpoxyHolder() {
|
||||
val image by bind<ImageView>(R.id.itemVerificationBigImage)
|
||||
val image by bind<ShieldImageView>(R.id.itemVerificationBigImage)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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.bottomSheetVerificationNoticeItem
|
||||
import im.vector.app.features.crypto.verification.epoxy.bottomSheetVerificationWaitingItem
|
||||
import org.matrix.android.sdk.api.crypto.RoomEncryptionTrustLevel
|
||||
import javax.inject.Inject
|
||||
|
||||
class VerificationQRWaitingController @Inject constructor(
|
||||
|
@ -49,7 +50,7 @@ class VerificationQRWaitingController @Inject constructor(
|
|||
|
||||
bottomSheetVerificationBigImageItem {
|
||||
id("image")
|
||||
imageRes(R.drawable.ic_shield_trusted)
|
||||
roomEncryptionTrustLevel(RoomEncryptionTrustLevel.Trusted)
|
||||
}
|
||||
|
||||
bottomSheetVerificationWaitingItem {
|
||||
|
|
|
@ -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.bottomSheetVerificationBigImageItem
|
||||
import im.vector.app.features.crypto.verification.epoxy.bottomSheetVerificationNoticeItem
|
||||
import org.matrix.android.sdk.api.crypto.RoomEncryptionTrustLevel
|
||||
import javax.inject.Inject
|
||||
|
||||
class VerificationQrScannedByOtherController @Inject constructor(
|
||||
|
@ -58,7 +59,7 @@ class VerificationQrScannedByOtherController @Inject constructor(
|
|||
|
||||
bottomSheetVerificationBigImageItem {
|
||||
id("image")
|
||||
imageRes(R.drawable.ic_shield_trusted)
|
||||
roomEncryptionTrustLevel(RoomEncryptionTrustLevel.Trusted)
|
||||
}
|
||||
|
||||
dividerItem {
|
||||
|
|
|
@ -29,7 +29,6 @@ import im.vector.app.R
|
|||
import im.vector.app.core.platform.VectorViewModel
|
||||
import im.vector.app.core.resources.StringProvider
|
||||
import io.reactivex.Observable
|
||||
import io.reactivex.functions.BiFunction
|
||||
import kotlinx.coroutines.launch
|
||||
import org.matrix.android.sdk.api.query.QueryStringValue
|
||||
import org.matrix.android.sdk.api.session.Session
|
||||
|
@ -123,7 +122,7 @@ class GroupListViewModel @AssistedInject constructor(@Assisted initialState: Gro
|
|||
session
|
||||
.rx()
|
||||
.liveGroupSummaries(groupSummariesQueryParams),
|
||||
BiFunction { allCommunityGroup, communityGroups ->
|
||||
{ allCommunityGroup, communityGroups ->
|
||||
listOf(allCommunityGroup) + communityGroups
|
||||
}
|
||||
)
|
||||
|
|
|
@ -285,10 +285,10 @@ class HomeActivity :
|
|||
dismissedAction = Runnable {
|
||||
homeActivityViewModel.handle(HomeActivityViewActions.PushPromptHasBeenReviewed)
|
||||
}
|
||||
addButton(getString(R.string.dismiss), Runnable {
|
||||
addButton(getString(R.string.dismiss), {
|
||||
homeActivityViewModel.handle(HomeActivityViewActions.PushPromptHasBeenReviewed)
|
||||
}, true)
|
||||
addButton(getString(R.string.settings), Runnable {
|
||||
addButton(getString(R.string.settings), {
|
||||
(weakCurrentActivity?.get() as? VectorBaseActivity<*>)?.let {
|
||||
// action(it)
|
||||
homeActivityViewModel.handle(HomeActivityViewActions.PushPromptHasBeenReviewed)
|
||||
|
|
|
@ -32,7 +32,6 @@ import im.vector.app.core.platform.VectorViewModel
|
|||
import im.vector.app.core.platform.VectorViewModelAction
|
||||
import im.vector.app.features.settings.VectorPreferences
|
||||
import io.reactivex.Observable
|
||||
import io.reactivex.functions.Function3
|
||||
import org.matrix.android.sdk.api.NoOpMatrixCallback
|
||||
import org.matrix.android.sdk.api.extensions.orFalse
|
||||
import org.matrix.android.sdk.api.session.Session
|
||||
|
@ -103,7 +102,7 @@ class UnknownDeviceDetectorSharedViewModel @AssistedInject constructor(@Assisted
|
|||
session.rx().liveUserCryptoDevices(session.myUserId),
|
||||
session.rx().liveMyDevicesInfo(),
|
||||
session.rx().liveCrossSigningPrivateKeys(),
|
||||
Function3 { cryptoList, infoList, pInfo ->
|
||||
{ cryptoList, infoList, pInfo ->
|
||||
// Timber.v("## Detector trigger ${cryptoList.map { "${it.deviceId} ${it.trustLevel}" }}")
|
||||
// Timber.v("## Detector trigger canCrossSign ${pInfo.get().selfSigned != null}")
|
||||
infoList
|
||||
|
|
|
@ -16,7 +16,6 @@
|
|||
|
||||
package im.vector.app.features.home.room.breadcrumbs
|
||||
|
||||
import android.view.View
|
||||
import com.airbnb.epoxy.EpoxyController
|
||||
import im.vector.app.core.epoxy.zeroItem
|
||||
import im.vector.app.core.utils.DebouncedClickListener
|
||||
|
@ -65,7 +64,7 @@ class BreadcrumbsController @Inject constructor(
|
|||
hasUnreadMessage(it.hasUnreadMessages)
|
||||
hasDraft(it.userDrafts.isNotEmpty())
|
||||
itemClickListener(
|
||||
DebouncedClickListener(View.OnClickListener { _ ->
|
||||
DebouncedClickListener({ _ ->
|
||||
listener?.onBreadcrumbClicked(it.roomId)
|
||||
})
|
||||
)
|
||||
|
|
|
@ -46,6 +46,7 @@ abstract class BreadcrumbsItem : VectorEpoxyModel<BreadcrumbsItem.Holder>() {
|
|||
holder.rootView.setOnClickListener(itemClickListener)
|
||||
holder.unreadIndentIndicator.isVisible = hasUnreadMessage
|
||||
avatarRenderer.render(matrixItem, holder.avatarImageView)
|
||||
holder.avatarImageView.contentDescription = matrixItem.getBestName()
|
||||
holder.unreadCounterBadgeView.render(UnreadCounterBadgeView.State(unreadNotificationCount, showHighlighted))
|
||||
holder.draftIndentIndicator.isVisible = hasDraft
|
||||
holder.typingIndicator.isVisible = hasTypingUsers
|
||||
|
|
|
@ -60,9 +60,9 @@ class JumpToBottomViewVisibilityManager(
|
|||
}
|
||||
|
||||
fun maybeShowJumpToBottomViewVisibilityWithDelay() {
|
||||
debouncer.debounce("jump_to_bottom_visibility", 250, Runnable {
|
||||
debouncer.debounce("jump_to_bottom_visibility", 250) {
|
||||
maybeShowJumpToBottomViewVisibility()
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
private fun maybeShowJumpToBottomViewVisibility() {
|
||||
|
|
|
@ -124,7 +124,6 @@ import im.vector.app.features.call.conference.JitsiCallViewModel
|
|||
import im.vector.app.features.call.webrtc.WebRtcCallManager
|
||||
import im.vector.app.features.command.Command
|
||||
import im.vector.app.features.crypto.keysbackup.restore.KeysBackupRestoreActivity
|
||||
import im.vector.app.features.crypto.util.toImageRes
|
||||
import im.vector.app.features.crypto.verification.VerificationBottomSheet
|
||||
import im.vector.app.features.home.AvatarRenderer
|
||||
import im.vector.app.features.home.room.detail.composer.TextComposerView
|
||||
|
@ -537,8 +536,18 @@ class RoomDetailFragment @Inject constructor(
|
|||
.Builder
|
||||
.fromRootView(views.rootConstraintLayout)
|
||||
.setKeyboardAnimationStyle(R.style.emoji_fade_animation_style)
|
||||
.setOnEmojiPopupShownListener { views.composerLayout.views.composerEmojiButton.setImageResource(R.drawable.ic_keyboard) }
|
||||
.setOnEmojiPopupDismissListener { views.composerLayout.views.composerEmojiButton.setImageResource(R.drawable.ic_insert_emoji) }
|
||||
.setOnEmojiPopupShownListener {
|
||||
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)
|
||||
|
||||
views.composerLayout.views.composerEmojiButton.debouncedClicks {
|
||||
|
@ -1193,10 +1202,7 @@ class RoomDetailFragment @Inject constructor(
|
|||
avatarRenderer.render(roomSummary.toMatrixItem(), views.roomToolbarAvatarImageView)
|
||||
|
||||
renderSubTitle(typingMessage, roomSummary.topic)
|
||||
views.roomToolbarDecorationImageView.let {
|
||||
it.setImageResource(roomSummary.roomEncryptionTrustLevel.toImageRes())
|
||||
it.isVisible = roomSummary.roomEncryptionTrustLevel != null
|
||||
}
|
||||
views.roomToolbarDecorationImageView.render(roomSummary.roomEncryptionTrustLevel)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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.VectorPreferences
|
||||
import io.reactivex.Observable
|
||||
import io.reactivex.functions.BiFunction
|
||||
import io.reactivex.rxkotlin.subscribeBy
|
||||
import io.reactivex.schedulers.Schedulers
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
|
@ -1331,7 +1330,7 @@ class RoomDetailViewModel @AssistedInject constructor(
|
|||
.combineLatest<List<TimelineEvent>, RoomSummary, UnreadState>(
|
||||
timelineEvents.observeOn(Schedulers.computation()),
|
||||
room.rx().liveRoomSummary().unwrap(),
|
||||
BiFunction { timelineEvents, roomSummary ->
|
||||
{ timelineEvents, roomSummary ->
|
||||
computeUnreadState(timelineEvents, roomSummary)
|
||||
}
|
||||
)
|
||||
|
|
|
@ -24,7 +24,6 @@ import android.view.ViewGroup
|
|||
import androidx.constraintlayout.widget.ConstraintLayout
|
||||
import androidx.constraintlayout.widget.ConstraintSet
|
||||
import androidx.core.text.toSpannable
|
||||
import androidx.core.view.isVisible
|
||||
import androidx.transition.ChangeBounds
|
||||
import androidx.transition.Fade
|
||||
import androidx.transition.Transition
|
||||
|
@ -41,8 +40,8 @@ import org.matrix.android.sdk.api.crypto.RoomEncryptionTrustLevel
|
|||
*/
|
||||
class TextComposerView @JvmOverloads constructor(
|
||||
context: Context,
|
||||
attrs: AttributeSet? = null,
|
||||
defStyleAttr: Int = 0) : ConstraintLayout(context, attrs, defStyleAttr) {
|
||||
attrs: AttributeSet? = null,
|
||||
defStyleAttr: Int = 0) : ConstraintLayout(context, attrs, defStyleAttr) {
|
||||
|
||||
interface Callback : ComposerEditText.Callback {
|
||||
fun onCloseRelatedMessage()
|
||||
|
@ -143,16 +142,10 @@ class TextComposerView @JvmOverloads constructor(
|
|||
fun setRoomEncrypted(isEncrypted: Boolean, roomEncryptionTrustLevel: RoomEncryptionTrustLevel?) {
|
||||
if (isEncrypted) {
|
||||
views.composerEditText.setHint(R.string.room_message_placeholder)
|
||||
views.composerShieldImageView.isVisible = true
|
||||
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)
|
||||
views.composerShieldImageView.render(roomEncryptionTrustLevel)
|
||||
} else {
|
||||
views.composerEditText.setHint(R.string.room_message_placeholder)
|
||||
views.composerShieldImageView.isVisible = false
|
||||
views.composerShieldImageView.render(null)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -16,7 +16,6 @@
|
|||
|
||||
package im.vector.app.features.home.room.detail.timeline.factory
|
||||
|
||||
import android.view.View
|
||||
import im.vector.app.R
|
||||
import im.vector.app.core.resources.StringProvider
|
||||
import im.vector.app.features.home.AvatarRenderer
|
||||
|
@ -42,7 +41,7 @@ class DefaultItemFactory @Inject constructor(private val avatarSizeProvider: Ava
|
|||
avatarRenderer = avatarRenderer,
|
||||
informationData = informationData,
|
||||
text = text,
|
||||
itemLongClickListener = View.OnLongClickListener { view ->
|
||||
itemLongClickListener = { view ->
|
||||
callback?.onEventLongClicked(informationData, null, view) ?: false
|
||||
},
|
||||
readReceiptsCallback = callback
|
||||
|
|
|
@ -322,7 +322,7 @@ class MessageItemFactory @Inject constructor(
|
|||
mode(ImageContentRenderer.Mode.STICKER)
|
||||
} else {
|
||||
clickListener(
|
||||
DebouncedClickListener(View.OnClickListener { view ->
|
||||
DebouncedClickListener({ view ->
|
||||
callback?.onImageMessageClicked(messageContent, data, view)
|
||||
}))
|
||||
}
|
||||
|
|
|
@ -16,7 +16,6 @@
|
|||
|
||||
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.room.detail.timeline.TimelineEventController
|
||||
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,
|
||||
informationData = informationData,
|
||||
noticeText = formattedText,
|
||||
itemLongClickListener = View.OnLongClickListener { view ->
|
||||
itemLongClickListener = { view ->
|
||||
callback?.onEventLongClicked(informationData, null, view) ?: false
|
||||
},
|
||||
readReceiptsCallback = callback,
|
||||
|
|
|
@ -15,7 +15,6 @@
|
|||
*/
|
||||
package im.vector.app.features.home.room.detail.timeline.helper
|
||||
|
||||
import android.view.View
|
||||
import im.vector.app.EmojiCompatFontProvider
|
||||
import im.vector.app.core.utils.DebouncedClickListener
|
||||
import im.vector.app.features.home.AvatarRenderer
|
||||
|
@ -39,13 +38,13 @@ class MessageItemAttributesFactory @Inject constructor(
|
|||
informationData = informationData,
|
||||
avatarRenderer = avatarRenderer,
|
||||
messageColorProvider = messageColorProvider,
|
||||
itemLongClickListener = View.OnLongClickListener { view ->
|
||||
itemLongClickListener = { view ->
|
||||
callback?.onEventLongClicked(informationData, messageContent, view) ?: false
|
||||
},
|
||||
itemClickListener = DebouncedClickListener(View.OnClickListener { view ->
|
||||
itemClickListener = DebouncedClickListener({ view ->
|
||||
callback?.onEventCellClicked(informationData, messageContent, view)
|
||||
}),
|
||||
memberClickListener = DebouncedClickListener(View.OnClickListener {
|
||||
memberClickListener = DebouncedClickListener({
|
||||
callback?.onMemberNameClicked(informationData)
|
||||
}),
|
||||
reactionPillCallback = callback,
|
||||
|
|
|
@ -23,11 +23,13 @@ import android.widget.TextView
|
|||
import androidx.annotation.IdRes
|
||||
import androidx.core.view.isVisible
|
||||
import im.vector.app.R
|
||||
import im.vector.app.core.ui.views.ShieldImageView
|
||||
import im.vector.app.core.utils.DebouncedClickListener
|
||||
import im.vector.app.features.home.AvatarRenderer
|
||||
import im.vector.app.features.home.room.detail.timeline.MessageColorProvider
|
||||
import im.vector.app.features.home.room.detail.timeline.TimelineEventController
|
||||
import im.vector.app.features.reactions.widget.ReactionButton
|
||||
import org.matrix.android.sdk.api.crypto.RoomEncryptionTrustLevel
|
||||
import org.matrix.android.sdk.api.session.room.send.SendState
|
||||
|
||||
/**
|
||||
|
@ -39,7 +41,7 @@ abstract class AbsBaseMessageItem<H : AbsBaseMessageItem.Holder> : BaseEventItem
|
|||
|
||||
abstract val baseAttributes: Attributes
|
||||
|
||||
private val _readReceiptsClickListener = DebouncedClickListener(View.OnClickListener {
|
||||
private val _readReceiptsClickListener = DebouncedClickListener({
|
||||
baseAttributes.readReceiptsCallback?.onReadReceiptsClicked(baseAttributes.informationData.readReceipts)
|
||||
})
|
||||
|
||||
|
@ -94,13 +96,12 @@ abstract class AbsBaseMessageItem<H : AbsBaseMessageItem.Holder> : BaseEventItem
|
|||
|
||||
when (baseAttributes.informationData.e2eDecoration) {
|
||||
E2EDecoration.NONE -> {
|
||||
holder.e2EDecorationView.isVisible = false
|
||||
holder.e2EDecorationView.render(null)
|
||||
}
|
||||
E2EDecoration.WARN_IN_CLEAR,
|
||||
E2EDecoration.WARN_SENT_BY_UNVERIFIED,
|
||||
E2EDecoration.WARN_SENT_BY_UNKNOWN -> {
|
||||
holder.e2EDecorationView.setImageResource(R.drawable.ic_shield_warning)
|
||||
holder.e2EDecorationView.isVisible = true
|
||||
holder.e2EDecorationView.render(RoomEncryptionTrustLevel.Warning)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -123,7 +124,7 @@ abstract class AbsBaseMessageItem<H : AbsBaseMessageItem.Holder> : BaseEventItem
|
|||
|
||||
abstract class Holder(@IdRes stubId: Int) : BaseEventItem.BaseHolder(stubId) {
|
||||
val reactionsContainer by bind<ViewGroup>(R.id.reactionsContainer)
|
||||
val e2EDecorationView by bind<ImageView>(R.id.messageE2EDecoration)
|
||||
val e2EDecorationView by bind<ShieldImageView>(R.id.messageE2EDecoration)
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -42,10 +42,10 @@ abstract class AbsMessageItem<H : AbsMessageItem.Holder> : AbsBaseMessageItem<H>
|
|||
@EpoxyAttribute
|
||||
lateinit var attributes: Attributes
|
||||
|
||||
private val _avatarClickListener = DebouncedClickListener(View.OnClickListener {
|
||||
private val _avatarClickListener = DebouncedClickListener({
|
||||
attributes.avatarCallback?.onAvatarClicked(attributes.informationData)
|
||||
})
|
||||
private val _memberNameClickListener = DebouncedClickListener(View.OnClickListener {
|
||||
private val _memberNameClickListener = DebouncedClickListener({
|
||||
attributes.avatarCallback?.onMemberNameClicked(attributes.informationData)
|
||||
})
|
||||
|
||||
|
|
|
@ -32,7 +32,7 @@ abstract class DefaultItem : BaseEventItem<DefaultItem.Holder>() {
|
|||
@EpoxyAttribute
|
||||
lateinit var attributes: Attributes
|
||||
|
||||
private val _readReceiptsClickListener = DebouncedClickListener(View.OnClickListener {
|
||||
private val _readReceiptsClickListener = DebouncedClickListener({
|
||||
attributes.readReceiptsCallback?.onReadReceiptsClicked(attributes.informationData.readReceipts)
|
||||
})
|
||||
|
||||
|
|
|
@ -186,14 +186,14 @@ abstract class MergedRoomCreationItem : BasedMergedItem<MergedRoomCreationItem.H
|
|||
|
||||
holder.setAvatarButton.isVisible = shouldSetAvatar
|
||||
if (shouldSetAvatar) {
|
||||
holder.setAvatarButton.setOnClickListener(DebouncedClickListener({ _ ->
|
||||
holder.setAvatarButton.setOnClickListener(DebouncedClickListener({
|
||||
attributes.callback?.onTimelineItemAction(RoomDetailAction.QuickActionSetAvatar)
|
||||
}))
|
||||
}
|
||||
|
||||
holder.addPeopleButton.isVisible = !isDirect
|
||||
if (!isDirect) {
|
||||
holder.addPeopleButton.setOnClickListener(DebouncedClickListener({ _ ->
|
||||
holder.addPeopleButton.setOnClickListener(DebouncedClickListener({
|
||||
attributes.callback?.onTimelineItemAction(RoomDetailAction.QuickActionInvitePeople)
|
||||
}))
|
||||
}
|
||||
|
|
|
@ -143,7 +143,7 @@ abstract class MessagePollItem : AbsMessageItem<MessagePollItem.Holder>() {
|
|||
override fun bindView(itemView: View) {
|
||||
super.bindView(itemView)
|
||||
val buttons = listOf(button1, button2, button3, button4, button5)
|
||||
val clickListener = DebouncedClickListener(View.OnClickListener {
|
||||
val clickListener = DebouncedClickListener({
|
||||
val optionIndex = buttons.indexOf(it)
|
||||
if (optionIndex != -1 && pollId != null) {
|
||||
val compatValue = if (optionIndex < optionValues?.size ?: 0) optionValues?.get(optionIndex) else null
|
||||
|
|
|
@ -19,15 +19,16 @@ package im.vector.app.features.home.room.detail.timeline.item
|
|||
import android.view.View
|
||||
import android.widget.ImageView
|
||||
import android.widget.TextView
|
||||
import androidx.core.view.isVisible
|
||||
import com.airbnb.epoxy.EpoxyAttribute
|
||||
import com.airbnb.epoxy.EpoxyModelClass
|
||||
import im.vector.app.R
|
||||
import im.vector.app.core.epoxy.ClickListener
|
||||
import im.vector.app.core.epoxy.onClick
|
||||
import im.vector.app.core.ui.views.ShieldImageView
|
||||
import im.vector.app.core.utils.DebouncedClickListener
|
||||
import im.vector.app.features.home.AvatarRenderer
|
||||
import im.vector.app.features.home.room.detail.timeline.TimelineEventController
|
||||
import org.matrix.android.sdk.api.crypto.RoomEncryptionTrustLevel
|
||||
|
||||
@EpoxyModelClass(layout = R.layout.item_timeline_event_base_noinfo)
|
||||
abstract class NoticeItem : BaseEventItem<NoticeItem.Holder>() {
|
||||
|
@ -35,7 +36,7 @@ abstract class NoticeItem : BaseEventItem<NoticeItem.Holder>() {
|
|||
@EpoxyAttribute
|
||||
lateinit var attributes: Attributes
|
||||
|
||||
private val _readReceiptsClickListener = DebouncedClickListener(View.OnClickListener {
|
||||
private val _readReceiptsClickListener = DebouncedClickListener({
|
||||
attributes.readReceiptsCallback?.onReadReceiptsClicked(attributes.informationData.readReceipts)
|
||||
})
|
||||
|
||||
|
@ -49,13 +50,12 @@ abstract class NoticeItem : BaseEventItem<NoticeItem.Holder>() {
|
|||
|
||||
when (attributes.informationData.e2eDecoration) {
|
||||
E2EDecoration.NONE -> {
|
||||
holder.e2EDecorationView.isVisible = false
|
||||
holder.e2EDecorationView.render(null)
|
||||
}
|
||||
E2EDecoration.WARN_IN_CLEAR,
|
||||
E2EDecoration.WARN_SENT_BY_UNVERIFIED,
|
||||
E2EDecoration.WARN_SENT_BY_UNKNOWN -> {
|
||||
holder.e2EDecorationView.setImageResource(R.drawable.ic_shield_warning)
|
||||
holder.e2EDecorationView.isVisible = true
|
||||
holder.e2EDecorationView.render(RoomEncryptionTrustLevel.Warning)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -75,7 +75,7 @@ abstract class NoticeItem : BaseEventItem<NoticeItem.Holder>() {
|
|||
class Holder : BaseHolder(STUB_ID) {
|
||||
val avatarImageView by bind<ImageView>(R.id.itemNoticeAvatarView)
|
||||
val noticeTextView by bind<TextView>(R.id.itemNoticeTextView)
|
||||
val e2EDecorationView by bind<ImageView>(R.id.messageE2EDecoration)
|
||||
val e2EDecorationView by bind<ShieldImageView>(R.id.messageE2EDecoration)
|
||||
}
|
||||
|
||||
data class Attributes(
|
||||
|
|
|
@ -60,7 +60,7 @@ data class ReactionInfo(
|
|||
*/
|
||||
class ViewReactionsViewModel @AssistedInject constructor(@Assisted
|
||||
initialState: DisplayReactionsViewState,
|
||||
private val session: Session,
|
||||
session: Session,
|
||||
private val dateFormatter: VectorDateFormatter
|
||||
) : VectorViewModel<DisplayReactionsViewState, EmptyAction, EmptyViewEvents>(initialState) {
|
||||
|
||||
|
|
|
@ -31,7 +31,7 @@ import im.vector.app.R
|
|||
import im.vector.app.core.epoxy.VectorEpoxyHolder
|
||||
import im.vector.app.core.epoxy.VectorEpoxyModel
|
||||
import im.vector.app.core.extensions.setTextOrHide
|
||||
import im.vector.app.features.crypto.util.toImageRes
|
||||
import im.vector.app.core.ui.views.ShieldImageView
|
||||
import im.vector.app.features.home.AvatarRenderer
|
||||
import org.matrix.android.sdk.api.crypto.RoomEncryptionTrustLevel
|
||||
import org.matrix.android.sdk.api.util.MatrixItem
|
||||
|
@ -73,8 +73,7 @@ abstract class RoomSummaryItem : VectorEpoxyModel<RoomSummaryItem.Holder>() {
|
|||
holder.unreadIndentIndicator.isVisible = hasUnreadMessage
|
||||
holder.draftView.isVisible = hasDraft
|
||||
avatarRenderer.render(matrixItem, holder.avatarImageView)
|
||||
holder.roomAvatarDecorationImageView.isVisible = encryptionTrustLevel != null
|
||||
holder.roomAvatarDecorationImageView.setImageResource(encryptionTrustLevel.toImageRes())
|
||||
holder.roomAvatarDecorationImageView.render(encryptionTrustLevel)
|
||||
holder.roomAvatarFailSendingImageView.isVisible = hasFailedSending
|
||||
renderSelection(holder, showSelected)
|
||||
holder.typingView.setTextOrHide(typingMessage)
|
||||
|
@ -110,7 +109,7 @@ abstract class RoomSummaryItem : VectorEpoxyModel<RoomSummaryItem.Holder>() {
|
|||
val lastEventTimeView by bind<TextView>(R.id.roomLastEventTimeView)
|
||||
val avatarCheckedImageView by bind<ImageView>(R.id.roomAvatarCheckedImageView)
|
||||
val avatarImageView by bind<ImageView>(R.id.roomAvatarImageView)
|
||||
val roomAvatarDecorationImageView by bind<ImageView>(R.id.roomAvatarDecorationImageView)
|
||||
val roomAvatarDecorationImageView by bind<ShieldImageView>(R.id.roomAvatarDecorationImageView)
|
||||
val roomAvatarFailSendingImageView by bind<ImageView>(R.id.roomAvatarFailSendingImageView)
|
||||
val rootView by bind<ViewGroup>(R.id.itemRoomLayout)
|
||||
}
|
||||
|
|
|
@ -16,7 +16,6 @@
|
|||
|
||||
package im.vector.app.features.home.room.list
|
||||
|
||||
import android.view.View
|
||||
import im.vector.app.R
|
||||
import im.vector.app.core.date.DateFormatKind
|
||||
import im.vector.app.core.date.VectorDateFormatter
|
||||
|
@ -109,7 +108,7 @@ class RoomSummaryItemFactory @Inject constructor(private val displayableEventFor
|
|||
onLongClick?.invoke(roomSummary) ?: false
|
||||
}
|
||||
.itemClickListener(
|
||||
DebouncedClickListener(View.OnClickListener { _ ->
|
||||
DebouncedClickListener({
|
||||
onClick?.invoke(roomSummary)
|
||||
})
|
||||
)
|
||||
|
|
|
@ -29,7 +29,7 @@ import org.matrix.android.sdk.rx.rx
|
|||
import org.matrix.android.sdk.rx.unwrap
|
||||
|
||||
class RoomListQuickActionsViewModel @AssistedInject constructor(@Assisted initialState: RoomListQuickActionsState,
|
||||
private val session: Session
|
||||
session: Session
|
||||
) : VectorViewModel<RoomListQuickActionsState, EmptyAction, EmptyViewEvents>(initialState) {
|
||||
|
||||
@AssistedFactory
|
||||
|
|
|
@ -36,7 +36,6 @@ import im.vector.app.core.extensions.showPassword
|
|||
import im.vector.app.core.extensions.toReducedUrl
|
||||
import im.vector.app.databinding.FragmentLoginBinding
|
||||
import io.reactivex.Observable
|
||||
import io.reactivex.functions.BiFunction
|
||||
import io.reactivex.rxkotlin.subscribeBy
|
||||
|
||||
import org.matrix.android.sdk.api.failure.Failure
|
||||
|
@ -225,7 +224,7 @@ class LoginFragment @Inject constructor() : AbstractSSOLoginFragment<FragmentLog
|
|||
.combineLatest(
|
||||
views.loginField.textChanges().map { it.trim().isNotEmpty() },
|
||||
views.passwordField.textChanges().map { it.isNotEmpty() },
|
||||
BiFunction<Boolean, Boolean, Boolean> { isLoginNotEmpty, isPasswordNotEmpty ->
|
||||
{ isLoginNotEmpty, isPasswordNotEmpty ->
|
||||
isLoginNotEmpty && isPasswordNotEmpty
|
||||
}
|
||||
)
|
||||
|
@ -255,14 +254,7 @@ class LoginFragment @Inject constructor() : AbstractSSOLoginFragment<FragmentLog
|
|||
|
||||
private fun renderPasswordField() {
|
||||
views.passwordField.showPassword(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)
|
||||
}
|
||||
views.passwordReveal.render(passwordShown)
|
||||
}
|
||||
|
||||
override fun resetViewModel() {
|
||||
|
|
|
@ -32,7 +32,6 @@ import im.vector.app.core.extensions.showPassword
|
|||
import im.vector.app.core.extensions.toReducedUrl
|
||||
import im.vector.app.databinding.FragmentLoginResetPasswordBinding
|
||||
import io.reactivex.Observable
|
||||
import io.reactivex.functions.BiFunction
|
||||
import io.reactivex.rxkotlin.subscribeBy
|
||||
|
||||
import javax.inject.Inject
|
||||
|
@ -69,7 +68,7 @@ class LoginResetPasswordFragment @Inject constructor() : AbstractLoginFragment<F
|
|||
.combineLatest(
|
||||
views.resetPasswordEmail.textChanges().map { it.isEmail() },
|
||||
views.passwordField.textChanges().map { it.isNotEmpty() },
|
||||
BiFunction<Boolean, Boolean, Boolean> { isEmail, isPasswordNotEmpty ->
|
||||
{ isEmail, isPasswordNotEmpty ->
|
||||
isEmail && isPasswordNotEmpty
|
||||
}
|
||||
)
|
||||
|
@ -127,14 +126,7 @@ class LoginResetPasswordFragment @Inject constructor() : AbstractLoginFragment<F
|
|||
|
||||
private fun renderPasswordField() {
|
||||
views.passwordField.showPassword(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)
|
||||
}
|
||||
views.passwordReveal.render(passwordShown)
|
||||
}
|
||||
|
||||
override fun resetViewModel() {
|
||||
|
@ -153,9 +145,7 @@ class LoginResetPasswordFragment @Inject constructor() : AbstractLoginFragment<F
|
|||
is Fail -> {
|
||||
views.resetPasswordEmailTil.error = errorFormatter.toHumanReadable(state.asyncResetPassword.error)
|
||||
}
|
||||
is Success -> {
|
||||
Unit
|
||||
}
|
||||
is Success -> Unit
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -74,9 +74,7 @@ class LoginResetPasswordMailConfirmationFragment @Inject constructor() : Abstrac
|
|||
.setPositiveButton(R.string.ok, null)
|
||||
.show()
|
||||
}
|
||||
is Success -> {
|
||||
Unit
|
||||
}
|
||||
is Success -> Unit
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -138,7 +138,7 @@ class MatrixToBottomSheet :
|
|||
fun withLink(matrixToLink: String, listener: InteractionListener?): MatrixToBottomSheet {
|
||||
return MatrixToBottomSheet().apply {
|
||||
arguments = Bundle().apply {
|
||||
putParcelable(MvRx.KEY_ARG, MatrixToBottomSheet.MatrixToArgs(
|
||||
putParcelable(MvRx.KEY_ARG, MatrixToArgs(
|
||||
matrixToLink = matrixToLink
|
||||
))
|
||||
}
|
||||
|
|
|
@ -379,7 +379,7 @@ class BugReporter @Inject constructor(
|
|||
if (responseCode != HttpURLConnection.HTTP_OK) {
|
||||
if (null != errorMessage) {
|
||||
serverError = "Failed with error $errorMessage"
|
||||
} else if (null == response || null == response.body) {
|
||||
} else if (response?.body == null) {
|
||||
serverError = "Failed with error $responseCode"
|
||||
} else {
|
||||
try {
|
||||
|
|
|
@ -26,7 +26,6 @@ import android.view.MenuItem
|
|||
import android.widget.SearchView
|
||||
import androidx.appcompat.widget.Toolbar
|
||||
import androidx.core.view.isVisible
|
||||
import androidx.lifecycle.Observer
|
||||
import com.airbnb.mvrx.viewModel
|
||||
import com.google.android.material.tabs.TabLayout
|
||||
import com.jakewharton.rxbinding3.widget.queryTextChanges
|
||||
|
@ -107,13 +106,13 @@ class EmojiReactionPickerActivity : VectorBaseActivity<ActivityEmojiReactionPick
|
|||
}
|
||||
views.tabs.addOnTabSelectedListener(tabLayoutSelectionListener)
|
||||
|
||||
viewModel.currentSection.observe(this, Observer { section ->
|
||||
viewModel.currentSection.observe(this) { section ->
|
||||
section?.let {
|
||||
views.tabs.removeOnTabSelectedListener(tabLayoutSelectionListener)
|
||||
views.tabs.getTabAt(it)?.select()
|
||||
views.tabs.addOnTabSelectedListener(tabLayoutSelectionListener)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
viewModel.navigateEvent.observeEvent(this) {
|
||||
if (it == EmojiChooserViewModel.NAVIGATE_FINISH) {
|
||||
|
|
|
@ -53,6 +53,7 @@ import im.vector.app.features.home.room.detail.RoomDetailPendingActionStore
|
|||
import im.vector.app.features.roommemberprofile.devices.DeviceListBottomSheet
|
||||
import im.vector.app.features.roommemberprofile.powerlevel.EditPowerLevelDialogs
|
||||
import kotlinx.parcelize.Parcelize
|
||||
import org.matrix.android.sdk.api.crypto.RoomEncryptionTrustLevel
|
||||
import org.matrix.android.sdk.api.session.room.powerlevels.Role
|
||||
import org.matrix.android.sdk.api.util.MatrixItem
|
||||
import javax.inject.Inject
|
||||
|
@ -205,31 +206,28 @@ class RoomMemberProfileFragment @Inject constructor(
|
|||
|
||||
if (state.isRoomEncrypted) {
|
||||
headerViews.memberProfileDecorationImageView.isVisible = true
|
||||
if (state.userMXCrossSigningInfo != null) {
|
||||
val trustLevel = if (state.userMXCrossSigningInfo != null) {
|
||||
// Cross signing is enabled for this user
|
||||
val icon = if (state.userMXCrossSigningInfo.isTrusted()) {
|
||||
if (state.userMXCrossSigningInfo.isTrusted()) {
|
||||
// User is trusted
|
||||
if (state.allDevicesAreCrossSignedTrusted) {
|
||||
R.drawable.ic_shield_trusted
|
||||
RoomEncryptionTrustLevel.Trusted
|
||||
} else {
|
||||
R.drawable.ic_shield_warning
|
||||
RoomEncryptionTrustLevel.Warning
|
||||
}
|
||||
} else {
|
||||
R.drawable.ic_shield_black
|
||||
RoomEncryptionTrustLevel.Default
|
||||
}
|
||||
|
||||
headerViews.memberProfileDecorationImageView.setImageResource(icon)
|
||||
views.matrixProfileDecorationToolbarAvatarImageView.setImageResource(icon)
|
||||
} else {
|
||||
// Legacy
|
||||
if (state.allDevicesAreTrusted) {
|
||||
headerViews.memberProfileDecorationImageView.setImageResource(R.drawable.ic_shield_trusted)
|
||||
views.matrixProfileDecorationToolbarAvatarImageView.setImageResource(R.drawable.ic_shield_trusted)
|
||||
RoomEncryptionTrustLevel.Trusted
|
||||
} else {
|
||||
headerViews.memberProfileDecorationImageView.setImageResource(R.drawable.ic_shield_warning)
|
||||
views.matrixProfileDecorationToolbarAvatarImageView.setImageResource(R.drawable.ic_shield_warning)
|
||||
RoomEncryptionTrustLevel.Warning
|
||||
}
|
||||
}
|
||||
headerViews.memberProfileDecorationImageView.render(trustLevel)
|
||||
views.matrixProfileDecorationToolbarAvatarImageView.render(trustLevel)
|
||||
} else {
|
||||
headerViews.memberProfileDecorationImageView.isVisible = false
|
||||
}
|
||||
|
|
|
@ -44,7 +44,6 @@ import im.vector.app.core.utils.copyToClipboard
|
|||
import im.vector.app.core.utils.startSharePlainTextIntent
|
||||
import im.vector.app.databinding.FragmentMatrixProfileBinding
|
||||
import im.vector.app.databinding.ViewStubRoomProfileHeaderBinding
|
||||
import im.vector.app.features.crypto.util.toImageRes
|
||||
import im.vector.app.features.home.AvatarRenderer
|
||||
import im.vector.app.features.home.room.list.actions.RoomListActionsArgs
|
||||
import im.vector.app.features.home.room.list.actions.RoomListQuickActionsBottomSheet
|
||||
|
@ -204,9 +203,8 @@ class RoomProfileFragment @Inject constructor(
|
|||
val matrixItem = it.toMatrixItem()
|
||||
avatarRenderer.render(matrixItem, headerViews.roomProfileAvatarView)
|
||||
avatarRenderer.render(matrixItem, views.matrixProfileToolbarAvatarImageView)
|
||||
headerViews.roomProfileDecorationImageView.isVisible = it.roomEncryptionTrustLevel != null
|
||||
headerViews.roomProfileDecorationImageView.setImageResource(it.roomEncryptionTrustLevel.toImageRes())
|
||||
views.matrixProfileDecorationToolbarAvatarImageView.setImageResource(it.roomEncryptionTrustLevel.toImageRes())
|
||||
headerViews.roomProfileDecorationImageView.render(it.roomEncryptionTrustLevel)
|
||||
views.matrixProfileDecorationToolbarAvatarImageView.render(it.roomEncryptionTrustLevel)
|
||||
}
|
||||
}
|
||||
roomProfileController.setData(state)
|
||||
|
|
|
@ -29,7 +29,6 @@ import im.vector.app.core.platform.VectorViewModel
|
|||
import im.vector.app.features.powerlevel.PowerLevelsObservableFactory
|
||||
import io.reactivex.Observable
|
||||
import io.reactivex.android.schedulers.AndroidSchedulers
|
||||
import io.reactivex.functions.BiFunction
|
||||
import kotlinx.coroutines.launch
|
||||
import org.matrix.android.sdk.api.crypto.RoomEncryptionTrustLevel
|
||||
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)
|
||||
.mapOptional { it.content.toModel<PowerLevelsContent>() }
|
||||
.unwrap(),
|
||||
BiFunction { roomMembers, powerLevelsContent ->
|
||||
{ roomMembers, powerLevelsContent ->
|
||||
buildRoomMemberSummaries(powerLevelsContent, roomMembers)
|
||||
}
|
||||
)
|
||||
|
|
|
@ -199,7 +199,6 @@ class RoomSettingsFragment @Inject constructor(
|
|||
}
|
||||
RoomSettingsViewState.AvatarAction.DeleteAvatar -> {
|
||||
/* Should not happen */
|
||||
Unit
|
||||
}
|
||||
is RoomSettingsViewState.AvatarAction.UpdateAvatar -> {
|
||||
// Cancel the update of the avatar
|
||||
|
|
|
@ -96,6 +96,7 @@ class RoomUploadsFragment @Inject constructor(
|
|||
private fun renderRoomSummary(state: RoomUploadsViewState) {
|
||||
state.roomSummary()?.let {
|
||||
views.roomUploadsToolbarTitleView.text = it.displayName
|
||||
views.roomUploadsDecorationToolbarAvatarImageView.render(it.roomEncryptionTrustLevel)
|
||||
avatarRenderer.render(it.toMatrixItem(), views.roomUploadsToolbarAvatarImageView)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -38,7 +38,7 @@ abstract class UploadsImageItem : VectorEpoxyModel<UploadsImageItem.Holder>() {
|
|||
override fun bind(holder: Holder) {
|
||||
super.bind(holder)
|
||||
holder.view.setOnClickListener(
|
||||
DebouncedClickListener(View.OnClickListener { _ ->
|
||||
DebouncedClickListener({
|
||||
listener?.onItemClicked(holder.imageView, data)
|
||||
})
|
||||
)
|
||||
|
|
|
@ -39,7 +39,7 @@ abstract class UploadsVideoItem : VectorEpoxyModel<UploadsVideoItem.Holder>() {
|
|||
override fun bind(holder: Holder) {
|
||||
super.bind(holder)
|
||||
holder.view.setOnClickListener(
|
||||
DebouncedClickListener(View.OnClickListener { _ ->
|
||||
DebouncedClickListener({
|
||||
listener?.onItemClicked(holder.imageView, data)
|
||||
})
|
||||
)
|
||||
|
|
|
@ -361,7 +361,7 @@ class VectorSettingsGeneralFragment @Inject constructor(
|
|||
views.changePasswordNewPwdText.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)
|
||||
|
|
|
@ -458,7 +458,7 @@ class VectorSettingsSecurityPrivacyFragment @Inject constructor(
|
|||
views.importDialogShowPassword.setOnClickListener {
|
||||
passwordVisible = !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() {
|
||||
|
|
|
@ -29,7 +29,6 @@ import im.vector.app.core.resources.StringProvider
|
|||
import im.vector.app.features.auth.ReAuthActivity
|
||||
import im.vector.app.features.login.ReAuthHelper
|
||||
import io.reactivex.Observable
|
||||
import io.reactivex.functions.BiFunction
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.launch
|
||||
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>>>(
|
||||
session.rx().liveMyDevicesInfo(),
|
||||
session.rx().liveCrossSigningInfo(session.myUserId),
|
||||
BiFunction { myDevicesInfo, mxCrossSigningInfo ->
|
||||
{ myDevicesInfo, mxCrossSigningInfo ->
|
||||
myDevicesInfo to mxCrossSigningInfo
|
||||
}
|
||||
)
|
||||
|
|
|
@ -18,7 +18,6 @@ package im.vector.app.features.settings.devices
|
|||
|
||||
import android.graphics.Typeface
|
||||
import android.view.ViewGroup
|
||||
import android.widget.ImageView
|
||||
import android.widget.TextView
|
||||
import androidx.core.view.isVisible
|
||||
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.VectorEpoxyModel
|
||||
import im.vector.app.core.resources.ColorProvider
|
||||
import im.vector.app.core.ui.views.ShieldImageView
|
||||
import im.vector.app.core.utils.DimensionConverter
|
||||
import me.gujun.android.span.span
|
||||
import org.matrix.android.sdk.internal.crypto.crosssigning.DeviceTrustLevel
|
||||
|
@ -75,17 +75,17 @@ abstract class DeviceItem : VectorEpoxyModel<DeviceItem.Holder>() {
|
|||
super.bind(holder)
|
||||
holder.root.setOnClickListener { itemClickAction?.invoke() }
|
||||
|
||||
val shield = TrustUtils.shieldForTrust(
|
||||
currentDevice,
|
||||
trustedSession,
|
||||
legacyMode,
|
||||
trusted
|
||||
)
|
||||
|
||||
if (e2eCapable) {
|
||||
holder.trustIcon.setImageResource(shield)
|
||||
val shield = TrustUtils.shieldForTrust(
|
||||
currentDevice,
|
||||
trustedSession,
|
||||
legacyMode,
|
||||
trusted
|
||||
)
|
||||
|
||||
holder.trustIcon.render(shield)
|
||||
} else {
|
||||
holder.trustIcon.setImageDrawable(null)
|
||||
holder.trustIcon.render(null)
|
||||
}
|
||||
|
||||
val detailedModeLabels = listOf(
|
||||
|
@ -152,6 +152,6 @@ abstract class DeviceItem : VectorEpoxyModel<DeviceItem.Holder>() {
|
|||
val deviceLastSeenLabelText by bind<TextView>(R.id.itemDeviceLastSeenLabel)
|
||||
val deviceLastSeenText by bind<TextView>(R.id.itemDeviceLastSeen)
|
||||
|
||||
val trustIcon by bind<ImageView>(R.id.itemDeviceTrustLevelIcon)
|
||||
val trustIcon by bind<ShieldImageView>(R.id.itemDeviceTrustLevelIcon)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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.genericFooterItem
|
||||
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 org.matrix.android.sdk.api.extensions.orFalse
|
||||
import org.matrix.android.sdk.internal.crypto.model.CryptoDeviceInfo
|
||||
|
@ -62,7 +63,7 @@ class DeviceVerificationInfoBottomSheetController @Inject constructor(
|
|||
trustMSK = data.accountCrossSigningIsTrusted,
|
||||
legacyMode = !data.hasAccountCrossSigning,
|
||||
deviceTrustLevel = cryptoDeviceInfo.trustLevel
|
||||
)
|
||||
).toDrawableRes()
|
||||
|
||||
if (data.hasAccountCrossSigning) {
|
||||
// Cross Signing is enabled
|
||||
|
|
|
@ -35,7 +35,6 @@ import im.vector.app.core.resources.StringProvider
|
|||
import im.vector.app.features.auth.ReAuthActivity
|
||||
import im.vector.app.features.login.ReAuthHelper
|
||||
import io.reactivex.Observable
|
||||
import io.reactivex.functions.BiFunction
|
||||
import io.reactivex.subjects.PublishSubject
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.launch
|
||||
|
@ -121,7 +120,7 @@ class DevicesViewModel @AssistedInject constructor(
|
|||
Observable.combineLatest<List<CryptoDeviceInfo>, List<DeviceInfo>, List<DeviceFullInfo>>(
|
||||
session.rx().liveUserCryptoDevices(session.myUserId),
|
||||
session.rx().liveMyDevicesInfo(),
|
||||
BiFunction { cryptoList, infoList ->
|
||||
{ cryptoList, infoList ->
|
||||
infoList
|
||||
.sortedByDescending { it.lastSeenTs }
|
||||
.map { deviceInfo ->
|
||||
|
@ -239,7 +238,6 @@ class DevicesViewModel @AssistedInject constructor(
|
|||
uiaContinuation?.resumeWith(Result.failure((Exception())))
|
||||
uiaContinuation = null
|
||||
pendingAuth = null
|
||||
Unit
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -16,38 +16,50 @@
|
|||
|
||||
package im.vector.app.features.settings.devices
|
||||
|
||||
import androidx.annotation.DrawableRes
|
||||
import im.vector.app.R
|
||||
import org.matrix.android.sdk.api.crypto.RoomEncryptionTrustLevel
|
||||
import org.matrix.android.sdk.internal.crypto.crosssigning.DeviceTrustLevel
|
||||
|
||||
object TrustUtils {
|
||||
|
||||
@DrawableRes
|
||||
fun shieldForTrust(currentDevice: Boolean, trustMSK: Boolean, legacyMode: Boolean, deviceTrustLevel: DeviceTrustLevel?): Int {
|
||||
fun shieldForTrust(currentDevice: Boolean,
|
||||
trustMSK: Boolean,
|
||||
legacyMode: Boolean,
|
||||
deviceTrustLevel: DeviceTrustLevel?): RoomEncryptionTrustLevel {
|
||||
return when {
|
||||
currentDevice -> {
|
||||
if (legacyMode) {
|
||||
// In legacy, current session is always trusted
|
||||
R.drawable.ic_shield_trusted
|
||||
RoomEncryptionTrustLevel.Trusted
|
||||
} else {
|
||||
// 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 -> {
|
||||
if (legacyMode) {
|
||||
// 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 {
|
||||
if (trustMSK) {
|
||||
// use cross sign trust, put locally trusted in black
|
||||
R.drawable.ic_shield_trusted.takeIf { deviceTrustLevel?.crossSigningVerified == true }
|
||||
?: R.drawable.ic_shield_black.takeIf { deviceTrustLevel?.locallyVerified == true }
|
||||
?: R.drawable.ic_shield_warning
|
||||
when {
|
||||
deviceTrustLevel?.crossSigningVerified == true -> RoomEncryptionTrustLevel.Trusted
|
||||
|
||||
deviceTrustLevel?.locallyVerified == true -> RoomEncryptionTrustLevel.Default
|
||||
else -> RoomEncryptionTrustLevel.Warning
|
||||
}
|
||||
} else {
|
||||
// The current session is untrusted, so displays others in black
|
||||
// as we can't know the cross-signing state
|
||||
R.drawable.ic_shield_black
|
||||
RoomEncryptionTrustLevel.Default
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -68,7 +68,7 @@ class AccountDataEpoxyController @Inject constructor(
|
|||
genericItemWithValue {
|
||||
id(accountData.type)
|
||||
title(accountData.type)
|
||||
itemClickAction(DebouncedClickListener(View.OnClickListener {
|
||||
itemClickAction(DebouncedClickListener({
|
||||
interactionListener?.didTap(accountData)
|
||||
}))
|
||||
itemLongClickAction(View.OnLongClickListener {
|
||||
|
|
|
@ -67,7 +67,7 @@ class KeyRequestsFragment @Inject constructor(
|
|||
|
||||
override fun onPageScrollStateChanged(state: Int) {
|
||||
childFragmentManager.fragments.forEach {
|
||||
setHasOptionsMenu(state == SCROLL_STATE_IDLE)
|
||||
it.setHasOptionsMenu(state == SCROLL_STATE_IDLE)
|
||||
}
|
||||
invalidateOptionsMenu()
|
||||
}
|
||||
|
|
|
@ -59,10 +59,13 @@ abstract class PushRuleItem : EpoxyModelWithHolder<PushRuleItem.Holder>() {
|
|||
|
||||
if (notifAction.shouldNotify && !notifAction.soundName.isNullOrBlank()) {
|
||||
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) {
|
||||
holder.actionIcon.setImageDrawable(ContextCompat.getDrawable(context, R.drawable.ic_action_notify_silent))
|
||||
holder.actionIcon.contentDescription = context.getString(R.string.a11y_rule_notify_silent)
|
||||
} else {
|
||||
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()
|
||||
|
|
|
@ -98,7 +98,7 @@ class NotificationTroubleshootRecyclerViewAdapter(val tests: ArrayList<Troublesh
|
|||
val quickFix = test.quickFix
|
||||
if (quickFix != null) {
|
||||
troubleshootTestButton.setText(test.quickFix!!.title)
|
||||
troubleshootTestButton.setOnClickListener { _ ->
|
||||
troubleshootTestButton.setOnClickListener {
|
||||
test.quickFix!!.doFix()
|
||||
}
|
||||
troubleshootTestButton.visibility = View.VISIBLE
|
||||
|
|
|
@ -121,7 +121,7 @@ class IncomingShareFragment @Inject constructor(
|
|||
return true
|
||||
}
|
||||
})
|
||||
views.sendShareButton.setOnClickListener { _ ->
|
||||
views.sendShareButton.setOnClickListener {
|
||||
handleSendShare()
|
||||
}
|
||||
}
|
||||
|
|
|
@ -19,7 +19,6 @@ package im.vector.app.features.signout.soft.epoxy
|
|||
import android.os.Build
|
||||
import android.text.Editable
|
||||
import android.widget.Button
|
||||
import android.widget.ImageView
|
||||
import androidx.autofill.HintConstants
|
||||
import com.airbnb.epoxy.EpoxyAttribute
|
||||
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.platform.SimpleTextWatcher
|
||||
import im.vector.app.core.resources.StringProvider
|
||||
import im.vector.app.core.ui.views.RevealPasswordImageView
|
||||
|
||||
@EpoxyModelClass(layout = R.layout.item_login_password_form)
|
||||
abstract class LoginPasswordFormItem : VectorEpoxyModel<LoginPasswordFormItem.Holder>() {
|
||||
|
@ -76,20 +76,13 @@ abstract class LoginPasswordFormItem : VectorEpoxyModel<LoginPasswordFormItem.Ho
|
|||
|
||||
private fun renderPasswordField(holder: Holder) {
|
||||
holder.passwordField.showPassword(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)
|
||||
}
|
||||
holder.passwordReveal.render(passwordShown)
|
||||
}
|
||||
|
||||
class Holder : VectorEpoxyHolder() {
|
||||
val passwordField by bind<TextInputEditText>(R.id.itemLoginPasswordFormPasswordField)
|
||||
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 submit by bind<Button>(R.id.itemLoginPasswordFormSubmit)
|
||||
}
|
||||
|
|
|
@ -49,7 +49,7 @@ import timber.log.Timber
|
|||
import javax.net.ssl.HttpsURLConnection
|
||||
|
||||
class WidgetViewModel @AssistedInject constructor(@Assisted val initialState: WidgetViewState,
|
||||
private val widgetPostAPIHandlerFactory: WidgetPostAPIHandler.Factory,
|
||||
widgetPostAPIHandlerFactory: WidgetPostAPIHandler.Factory,
|
||||
private val stringProvider: StringProvider,
|
||||
private val session: Session)
|
||||
: VectorViewModel<WidgetViewState, WidgetAction, WidgetViewEvents>(initialState),
|
||||
|
|
|
@ -150,6 +150,7 @@
|
|||
android:layout_gravity="center_horizontal"
|
||||
android:layout_marginTop="10dp"
|
||||
android:adjustViewBounds="true"
|
||||
android:contentDescription="@string/a11y_screenshot"
|
||||
android:maxWidth="260dp"
|
||||
android:scaleType="fitCenter"
|
||||
tools:src="@tools:sample/backgrounds/scenic" />
|
||||
|
|
|
@ -16,6 +16,7 @@
|
|||
android:id="@+id/bgCallView"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:importantForAccessibility="no"
|
||||
android:scaleType="centerCrop"
|
||||
tools:src="@tools:sample/avatars" />
|
||||
|
||||
|
@ -53,6 +54,7 @@
|
|||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:foreground="?attr/selectableItemBackground"
|
||||
android:importantForAccessibility="no"
|
||||
android:scaleType="centerCrop"
|
||||
tools:src="@tools:sample/avatars" />
|
||||
|
||||
|
@ -61,6 +63,7 @@
|
|||
android:layout_width="20dp"
|
||||
android:layout_height="20dp"
|
||||
android:layout_gravity="center"
|
||||
android:importantForAccessibility="no"
|
||||
android:src="@drawable/ic_call_small_pause" />
|
||||
|
||||
</FrameLayout>
|
||||
|
@ -70,6 +73,7 @@
|
|||
android:layout_width="80dp"
|
||||
android:layout_height="80dp"
|
||||
android:contentDescription="@string/avatar"
|
||||
android:importantForAccessibility="no"
|
||||
android:scaleType="centerCrop"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
|
@ -81,13 +85,13 @@
|
|||
android:id="@+id/smallIsHeldIcon"
|
||||
android:layout_width="20dp"
|
||||
android:layout_height="20dp"
|
||||
android:importantForAccessibility="no"
|
||||
android:src="@drawable/ic_call_small_pause"
|
||||
app:layout_constraintBottom_toBottomOf="@id/otherMemberAvatar"
|
||||
app:layout_constraintEnd_toEndOf="@id/otherMemberAvatar"
|
||||
app:layout_constraintStart_toStartOf="@id/otherMemberAvatar"
|
||||
app:layout_constraintTop_toTopOf="@id/otherMemberAvatar" />
|
||||
|
||||
|
||||
<TextView
|
||||
android:id="@+id/participantNameText"
|
||||
android:layout_width="0dp"
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:id="@+id/callDialPad"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
|
@ -27,10 +28,12 @@
|
|||
android:id="@+id/callDialPadClose"
|
||||
android:layout_width="@dimen/layout_touch_size"
|
||||
android:layout_height="@dimen/layout_touch_size"
|
||||
android:scaleType="center"
|
||||
app:tint="?riotx_text_primary"
|
||||
android:contentDescription="@string/action_close"
|
||||
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>
|
||||
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:id="@+id/callControlsWrapper"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
|
|
|
@ -47,6 +47,7 @@
|
|||
android:id="@+id/backupCompleteImage"
|
||||
android:layout_width="20dp"
|
||||
android:layout_height="20dp"
|
||||
android:importantForAccessibility="no"
|
||||
android:visibility="gone"
|
||||
app:srcCompat="@drawable/unit_test_ok"
|
||||
tools:visibility="visible" />
|
||||
|
|
|
@ -22,6 +22,7 @@
|
|||
android:layout_width="60dp"
|
||||
android:layout_height="60dp"
|
||||
android:layout_marginTop="@dimen/layout_vertical_margin_big"
|
||||
android:contentDescription="@string/avatar"
|
||||
android:elevation="4dp"
|
||||
android:transitionName="profile"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
|
|
|
@ -45,6 +45,7 @@
|
|||
android:layout_width="40dp"
|
||||
android:layout_height="40dp"
|
||||
android:layout_gravity="center"
|
||||
android:contentDescription="@string/avatar"
|
||||
tools:src="@tools:sample/avatars" />
|
||||
|
||||
<LinearLayout
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue