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