mirror of
https://github.com/signalapp/Signal-Android.git
synced 2026-02-15 07:28:30 +00:00
Add key transparency UI.
This commit is contained in:
committed by
Greyson Parrelli
parent
279f9578cc
commit
69f4c89f84
@@ -28,6 +28,7 @@ import androidx.core.content.ContextCompat
|
||||
import androidx.core.graphics.drawable.toBitmap
|
||||
import androidx.core.widget.ImageViewCompat
|
||||
import androidx.interpolator.view.animation.FastOutSlowInInterpolator
|
||||
import com.google.android.material.button.MaterialButton
|
||||
import org.signal.core.util.dp
|
||||
import org.signal.libsignal.protocol.fingerprint.Fingerprint
|
||||
import org.thoughtcrime.securesms.R
|
||||
@@ -65,6 +66,7 @@ class SafetyNumberQrView : ConstraintLayout {
|
||||
val qrCodeContainer: View
|
||||
|
||||
val shareButton: ImageView
|
||||
val verifyButton: MaterialButton
|
||||
|
||||
private val loading: View
|
||||
private val qrCode: ImageView
|
||||
@@ -97,6 +99,7 @@ class SafetyNumberQrView : ConstraintLayout {
|
||||
)
|
||||
|
||||
shareButton = findViewById(R.id.share)
|
||||
verifyButton = findViewById(R.id.verify_button)
|
||||
|
||||
outlineProvider = object : ViewOutlineProvider() {
|
||||
override fun getOutline(view: View, outline: Outline) {
|
||||
|
||||
@@ -0,0 +1,135 @@
|
||||
package org.thoughtcrime.securesms.verify
|
||||
|
||||
import android.os.Bundle
|
||||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.layout.defaultMinSize
|
||||
import androidx.compose.foundation.layout.fillMaxWidth
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.material3.Icon
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.graphics.vector.ImageVector
|
||||
import androidx.compose.ui.res.stringResource
|
||||
import androidx.compose.ui.res.vectorResource
|
||||
import androidx.compose.ui.text.style.TextAlign
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.fragment.app.FragmentManager
|
||||
import org.signal.core.ui.compose.BottomSheets
|
||||
import org.signal.core.ui.compose.Buttons
|
||||
import org.signal.core.ui.compose.DayNightPreviews
|
||||
import org.signal.core.ui.compose.Previews
|
||||
import org.signal.core.ui.compose.horizontalGutters
|
||||
import org.signal.core.util.getSerializableCompat
|
||||
import org.thoughtcrime.securesms.R
|
||||
import org.thoughtcrime.securesms.compose.ComposeBottomSheetDialogFragment
|
||||
import org.thoughtcrime.securesms.util.BottomSheetUtil
|
||||
|
||||
/**
|
||||
* Bottom sheet info explaining the results of automatic key verification
|
||||
*/
|
||||
class EncryptionVerifiedSheet : ComposeBottomSheetDialogFragment() {
|
||||
|
||||
override val peekHeightPercentage: Float = 0.67f
|
||||
|
||||
companion object {
|
||||
|
||||
private const val ARG_STATUS = "arg.status"
|
||||
private const val ARG_NAME = "arg.name"
|
||||
|
||||
@JvmStatic
|
||||
fun show(fragmentManager: FragmentManager, status: AutomaticVerificationStatus, name: String) {
|
||||
EncryptionVerifiedSheet().apply {
|
||||
arguments = Bundle().apply {
|
||||
putSerializable(ARG_STATUS, status)
|
||||
putString(ARG_NAME, name)
|
||||
}
|
||||
show(fragmentManager, BottomSheetUtil.STANDARD_BOTTOM_SHEET_FRAGMENT_TAG)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
override fun SheetContent() {
|
||||
VerifiedSheet(
|
||||
verifiedStatus = requireArguments().getSerializableCompat(ARG_STATUS, AutomaticVerificationStatus::class.java)!!,
|
||||
name = requireArguments().getString(ARG_NAME, "")
|
||||
) {
|
||||
this.dismissAllowingStateLoss()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun VerifiedSheet(
|
||||
verifiedStatus: AutomaticVerificationStatus = AutomaticVerificationStatus.UNAVAILABLE_TEMPORARY,
|
||||
name: String = "",
|
||||
onClick: () -> Unit = {}
|
||||
) {
|
||||
val (icon, title, body) = when (verifiedStatus) {
|
||||
AutomaticVerificationStatus.VERIFIED -> {
|
||||
Triple(
|
||||
ImageVector.vectorResource(R.drawable.symbol_check_48),
|
||||
stringResource(R.string.EncryptionVerifiedSheet__title_success),
|
||||
stringResource(R.string.EncryptionVerifiedSheet__body_success)
|
||||
)
|
||||
}
|
||||
AutomaticVerificationStatus.UNAVAILABLE_PERMANENT -> {
|
||||
Triple(
|
||||
ImageVector.vectorResource(R.drawable.symbol_info_48),
|
||||
stringResource(R.string.EncryptionVerifiedSheet__title_unavailable),
|
||||
stringResource(R.string.EncryptionVerifiedSheet__body_unavailable)
|
||||
)
|
||||
}
|
||||
else -> {
|
||||
Triple(
|
||||
ImageVector.vectorResource(R.drawable.symbol_info_48),
|
||||
stringResource(R.string.EncryptionVerifiedSheet__title_no_longer_unavailable),
|
||||
stringResource(R.string.EncryptionVerifiedSheet__body_no_longer_unavailable, name)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
return Column(
|
||||
horizontalAlignment = Alignment.CenterHorizontally,
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.horizontalGutters()
|
||||
) {
|
||||
BottomSheets.Handle()
|
||||
Icon(
|
||||
imageVector = icon,
|
||||
contentDescription = null,
|
||||
tint = Color.Unspecified,
|
||||
modifier = Modifier.padding(top = 28.dp)
|
||||
)
|
||||
Text(
|
||||
text = title,
|
||||
style = MaterialTheme.typography.titleLarge,
|
||||
textAlign = TextAlign.Center,
|
||||
modifier = Modifier.padding(vertical = 12.dp)
|
||||
)
|
||||
Text(
|
||||
text = body,
|
||||
textAlign = TextAlign.Center,
|
||||
style = MaterialTheme.typography.bodyMedium
|
||||
)
|
||||
Buttons.LargeTonal(
|
||||
onClick = onClick,
|
||||
modifier = Modifier.defaultMinSize(minWidth = 220.dp).padding(vertical = 40.dp)
|
||||
) {
|
||||
Text(stringResource(id = android.R.string.ok))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@DayNightPreviews
|
||||
@Composable
|
||||
fun FinishedSheetSheetPreview() {
|
||||
Previews.BottomSheetContentPreview {
|
||||
VerifiedSheet()
|
||||
}
|
||||
}
|
||||
@@ -4,6 +4,7 @@ import android.content.ActivityNotFoundException
|
||||
import android.content.Context
|
||||
import android.content.DialogInterface
|
||||
import android.content.Intent
|
||||
import android.content.res.ColorStateList
|
||||
import android.os.Bundle
|
||||
import android.text.TextUtils
|
||||
import android.view.ContextMenu
|
||||
@@ -12,9 +13,9 @@ import android.view.LayoutInflater
|
||||
import android.view.MenuItem
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import android.view.ViewTreeObserver.OnScrollChangedListener
|
||||
import android.widget.Toast
|
||||
import androidx.core.content.ContextCompat
|
||||
import androidx.core.widget.ImageViewCompat
|
||||
import androidx.fragment.app.Fragment
|
||||
import androidx.lifecycle.ViewModelProvider
|
||||
import com.google.android.material.dialog.MaterialAlertDialogBuilder
|
||||
@@ -32,13 +33,14 @@ import org.thoughtcrime.securesms.recipients.RecipientId
|
||||
import org.thoughtcrime.securesms.util.RemoteConfig
|
||||
import org.thoughtcrime.securesms.util.Util
|
||||
import org.thoughtcrime.securesms.util.ViewUtil
|
||||
import org.thoughtcrime.securesms.util.visible
|
||||
import java.nio.charset.StandardCharsets
|
||||
import java.util.Locale
|
||||
|
||||
/**
|
||||
* Fragment to display a user's identity key.
|
||||
*/
|
||||
class VerifyDisplayFragment : Fragment(), OnScrollChangedListener {
|
||||
class VerifyDisplayFragment : Fragment() {
|
||||
private lateinit var viewModel: VerifySafetyNumberViewModel
|
||||
|
||||
private val binding by ViewBinderDelegate(VerifyDisplayFragmentBinding::bind)
|
||||
@@ -71,11 +73,19 @@ class VerifyDisplayFragment : Fragment(), OnScrollChangedListener {
|
||||
|
||||
updateVerifyButton(requireArguments().getBoolean(VERIFIED_STATE, false), false)
|
||||
|
||||
binding.verifyButton.setOnClickListener { updateVerifyButton(!currentVerifiedState, true) }
|
||||
binding.scrollView.viewTreeObserver?.addOnScrollChangedListener(this)
|
||||
binding.automaticVerification.visible = RemoteConfig.keyTransparency
|
||||
binding.safetyQrView.verifyButton.setOnClickListener { updateVerifyButton(!currentVerifiedState, true) }
|
||||
binding.toolbar.setNavigationOnClickListener { requireActivity().onBackPressed() }
|
||||
binding.toolbar.setTitle(R.string.AndroidManifest__verify_safety_number)
|
||||
|
||||
binding.caption.text = getString(R.string.verify_display_fragment__auto_verify_not_available)
|
||||
binding.caption.setLink(getString(R.string.verify_display_fragment__link))
|
||||
binding.caption.setLinkColor(ContextCompat.getColor(requireContext(), R.color.signal_colorPrimary))
|
||||
|
||||
viewModel.getAutomaticVerification().observe(viewLifecycleOwner) { status ->
|
||||
updateStatus(status)
|
||||
}
|
||||
|
||||
viewModel.recipient.observe(this) { recipient: Recipient -> setRecipientText(recipient) }
|
||||
viewModel.getFingerprint().observe(viewLifecycleOwner) { fingerprint: SafetyNumberFingerprint? ->
|
||||
if (fingerprint == null) {
|
||||
@@ -99,6 +109,48 @@ class VerifyDisplayFragment : Fragment(), OnScrollChangedListener {
|
||||
}
|
||||
}
|
||||
|
||||
private fun updateStatus(status: AutomaticVerificationStatus) {
|
||||
when (status) {
|
||||
AutomaticVerificationStatus.NONE -> {
|
||||
binding.autoVerifyText.text = getString(R.string.verify_display_fragment__verify_automatic)
|
||||
binding.autoVerifyIcon.setImageResource(R.drawable.symbol_key_24)
|
||||
binding.autoVerifyIcon.imageTintList = null
|
||||
binding.autoVerifyMore.visible = false
|
||||
}
|
||||
AutomaticVerificationStatus.VERIFYING -> {
|
||||
binding.autoVerifyText.text = getString(R.string.verify_display_fragment__verifying)
|
||||
binding.autoVerifyMore.visible = false
|
||||
}
|
||||
AutomaticVerificationStatus.UNAVAILABLE_PERMANENT -> {
|
||||
binding.autoVerifyText.text = getString(R.string.verify_display_fragment__encryption_unavailable)
|
||||
binding.autoVerifyIcon.setImageResource(R.drawable.symbol_info_24)
|
||||
ImageViewCompat.setImageTintList(binding.autoVerifyIcon, ColorStateList.valueOf(ContextCompat.getColor(requireContext(), R.color.signal_colorOnSurfaceVariant)))
|
||||
binding.autoVerifyMore.visible = true
|
||||
}
|
||||
AutomaticVerificationStatus.UNAVAILABLE_TEMPORARY -> {
|
||||
binding.autoVerifyText.text = getString(R.string.verify_display_fragment__encryption_unavailable)
|
||||
binding.autoVerifyIcon.setImageResource(R.drawable.symbol_info_24)
|
||||
ImageViewCompat.setImageTintList(binding.autoVerifyIcon, ColorStateList.valueOf(ContextCompat.getColor(requireContext(), R.color.signal_colorOnSurfaceVariant)))
|
||||
binding.autoVerifyMore.visible = true
|
||||
}
|
||||
AutomaticVerificationStatus.VERIFIED -> {
|
||||
binding.autoVerifyText.text = getString(R.string.verify_display_fragment__encryption_verified)
|
||||
binding.autoVerifyIcon.setImageResource(R.drawable.symbol_check_filled_circle_24)
|
||||
binding.autoVerifyIcon.imageTintList = null
|
||||
binding.autoVerifyMore.visible = true
|
||||
}
|
||||
}
|
||||
|
||||
if (status == AutomaticVerificationStatus.VERIFYING) {
|
||||
binding.autoVerifySpinner.visible = true
|
||||
binding.autoVerifyIcon.visible = false
|
||||
} else {
|
||||
binding.autoVerifySpinner.visible = false
|
||||
binding.autoVerifyIcon.visible = true
|
||||
}
|
||||
binding.autoVerifyMore.setOnClickListener { EncryptionVerifiedSheet.show(parentFragmentManager, status, viewModel.recipient.resolve().getDisplayName(requireContext())) }
|
||||
}
|
||||
|
||||
private fun initializeViewModel() {
|
||||
val recipientId = requireArguments().requireParcelableCompat(RECIPIENT_ID, RecipientId::class.java)
|
||||
val localIdentity = requireArguments().requireParcelableCompat(LOCAL_IDENTITY, IdentityKeyParcelable::class.java).get()!!
|
||||
@@ -121,7 +173,6 @@ class VerifyDisplayFragment : Fragment(), OnScrollChangedListener {
|
||||
animateFailure()
|
||||
}
|
||||
}
|
||||
ThreadUtil.postToMain { onScrollChanged() }
|
||||
}
|
||||
|
||||
override fun onCreateContextMenu(
|
||||
@@ -252,34 +303,15 @@ class VerifyDisplayFragment : Fragment(), OnScrollChangedListener {
|
||||
private fun updateVerifyButton(verified: Boolean, update: Boolean) {
|
||||
currentVerifiedState = verified
|
||||
if (verified) {
|
||||
binding.verifyButton.setText(R.string.verify_display_fragment__clear_verification)
|
||||
binding.safetyQrView.verifyButton.setText(R.string.verify_display_fragment__clear_verification)
|
||||
} else {
|
||||
binding.verifyButton.setText(R.string.verify_display_fragment__mark_as_verified)
|
||||
binding.safetyQrView.verifyButton.setText(R.string.verify_display_fragment__mark_as_verified)
|
||||
}
|
||||
if (update) {
|
||||
viewModel.updateSafetyNumberVerification(verified)
|
||||
}
|
||||
}
|
||||
|
||||
override fun onScrollChanged() {
|
||||
if (binding.scrollView.canScrollVertically(-1) && currentFingerprint != null) {
|
||||
if (binding.toolbarShadow.visibility != View.VISIBLE) {
|
||||
ViewUtil.fadeIn(binding.toolbarShadow, 250)
|
||||
}
|
||||
} else {
|
||||
if (binding.toolbarShadow.visibility != View.GONE) {
|
||||
ViewUtil.fadeOut(binding.toolbarShadow, 250)
|
||||
}
|
||||
}
|
||||
if (binding.scrollView.canScrollVertically(1)) {
|
||||
if (binding.verifyIdentityBottomShadow.visibility != View.VISIBLE) {
|
||||
ViewUtil.fadeIn(binding.verifyIdentityBottomShadow, 250)
|
||||
}
|
||||
} else {
|
||||
ViewUtil.fadeOut(binding.verifyIdentityBottomShadow, 250)
|
||||
}
|
||||
}
|
||||
|
||||
internal interface Callback {
|
||||
fun onQrCodeContainerClicked()
|
||||
}
|
||||
|
||||
@@ -39,6 +39,7 @@ class VerifySafetyNumberViewModel(
|
||||
val recipient: LiveRecipient = Recipient.live(recipientId)
|
||||
|
||||
private val fingerprintLiveData = MutableLiveData<SafetyNumberFingerprint?>()
|
||||
private val automaticVerificationLiveData = MutableLiveData(AutomaticVerificationStatus.NONE)
|
||||
|
||||
init {
|
||||
initializeFingerprints()
|
||||
@@ -69,6 +70,10 @@ class VerifySafetyNumberViewModel(
|
||||
return fingerprintLiveData
|
||||
}
|
||||
|
||||
fun getAutomaticVerification(): LiveData<AutomaticVerificationStatus> {
|
||||
return automaticVerificationLiveData
|
||||
}
|
||||
|
||||
fun updateSafetyNumberVerification(verified: Boolean) {
|
||||
val recipientId: RecipientId = recipientId
|
||||
val context: Context = AppDependencies.application
|
||||
@@ -159,3 +164,11 @@ data class SafetyNumberFingerprint(
|
||||
return result
|
||||
}
|
||||
}
|
||||
|
||||
enum class AutomaticVerificationStatus {
|
||||
NONE,
|
||||
VERIFYING,
|
||||
UNAVAILABLE_PERMANENT,
|
||||
UNAVAILABLE_TEMPORARY,
|
||||
VERIFIED
|
||||
}
|
||||
|
||||
17
app/src/main/res/drawable/symbol_check_48.xml
Normal file
17
app/src/main/res/drawable/symbol_check_48.xml
Normal file
@@ -0,0 +1,17 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="48dp"
|
||||
android:height="48dp"
|
||||
android:viewportWidth="48"
|
||||
android:viewportHeight="48">
|
||||
<path
|
||||
android:pathData="M24,24m-21.5,0a21.5,21.5 0,1 1,43 0a21.5,21.5 0,1 1,-43 0"
|
||||
android:fillColor="#D2D8FE"/>
|
||||
<path
|
||||
android:pathData="M24,5.5C13.783,5.5 5.5,13.783 5.5,24C5.5,34.217 13.783,42.5 24,42.5C34.217,42.5 42.5,34.217 42.5,24C42.5,13.783 34.217,5.5 24,5.5ZM2.5,24C2.5,12.126 12.126,2.5 24,2.5C35.874,2.5 45.5,12.126 45.5,24C45.5,35.874 35.874,45.5 24,45.5C12.126,45.5 2.5,35.874 2.5,24Z"
|
||||
android:fillColor="#3B45FD"
|
||||
android:fillType="evenOdd"/>
|
||||
<path
|
||||
android:pathData="M32.795,15.228C33.498,15.667 33.711,16.593 33.272,17.295L23.272,33.295C23.014,33.707 22.573,33.969 22.087,33.998C21.601,34.026 21.132,33.817 20.829,33.437L14.829,25.937C14.311,25.29 14.416,24.346 15.063,23.829C15.71,23.311 16.654,23.416 17.171,24.063L21.85,29.911L30.728,15.705C31.167,15.002 32.092,14.789 32.795,15.228Z"
|
||||
android:fillColor="#3B45FD"
|
||||
android:fillType="evenOdd"/>
|
||||
</vector>
|
||||
10
app/src/main/res/drawable/symbol_check_filled_circle_24.xml
Normal file
10
app/src/main/res/drawable/symbol_check_filled_circle_24.xml
Normal file
@@ -0,0 +1,10 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportWidth="24"
|
||||
android:viewportHeight="24">
|
||||
<path
|
||||
android:pathData="M12,1.5C6.201,1.5 1.5,6.201 1.5,12C1.5,17.799 6.201,22.5 12,22.5C17.799,22.5 22.5,17.799 22.5,12C22.5,6.201 17.799,1.5 12,1.5ZM16.464,7.508C16.874,7.764 16.998,8.304 16.742,8.714L11.742,16.714C11.592,16.954 11.334,17.107 11.051,17.124C10.768,17.14 10.494,17.018 10.317,16.797L7.317,13.047C7.015,12.669 7.076,12.119 7.453,11.817C7.831,11.515 8.381,11.576 8.683,11.953L10.912,14.74L15.258,7.786C15.514,7.376 16.054,7.252 16.464,7.508Z"
|
||||
android:fillColor="#4CAF50"
|
||||
android:fillType="evenOdd"/>
|
||||
</vector>
|
||||
19
app/src/main/res/drawable/symbol_info_48.xml
Normal file
19
app/src/main/res/drawable/symbol_info_48.xml
Normal file
@@ -0,0 +1,19 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="48dp"
|
||||
android:height="48dp"
|
||||
android:viewportWidth="48"
|
||||
android:viewportHeight="48">
|
||||
<path
|
||||
android:pathData="M24,24m-21.5,0a21.5,21.5 0,1 1,43 0a21.5,21.5 0,1 1,-43 0"
|
||||
android:fillColor="#D2D8FE"/>
|
||||
<path
|
||||
android:pathData="M24.604,20.263C24.775,20.277 24.977,20.31 25.181,20.413C25.463,20.557 25.693,20.787 25.837,21.069C25.94,21.273 25.973,21.475 25.987,21.646C26,21.802 26,21.987 26,22.176L26,32.5H28.5C29.19,32.5 29.75,33.06 29.75,33.75C29.75,34.44 29.19,35 28.5,35H20.5C19.81,35 19.25,34.44 19.25,33.75C19.25,33.06 19.81,32.5 20.5,32.5H23V22.75H21C20.31,22.75 19.75,22.19 19.75,21.5C19.75,20.81 20.31,20.25 21,20.25L24.074,20.25C24.263,20.25 24.448,20.25 24.604,20.263Z"
|
||||
android:fillColor="#3B45FD"/>
|
||||
<path
|
||||
android:pathData="M21.498,14.502C21.498,13.12 22.618,12 24,12C25.382,12 26.502,13.12 26.502,14.502C26.502,15.884 25.382,17.005 24,17.005C22.618,17.005 21.498,15.884 21.498,14.502Z"
|
||||
android:fillColor="#3B45FD"/>
|
||||
<path
|
||||
android:pathData="M2.5,24C2.5,12.126 12.126,2.5 24,2.5C35.874,2.5 45.5,12.126 45.5,24C45.5,35.874 35.874,45.5 24,45.5C12.126,45.5 2.5,35.874 2.5,24ZM24,5.5C13.783,5.5 5.5,13.783 5.5,24C5.5,34.217 13.783,42.5 24,42.5C34.217,42.5 42.5,34.217 42.5,24C42.5,13.783 34.217,5.5 24,5.5Z"
|
||||
android:fillColor="#3B45FD"
|
||||
android:fillType="evenOdd"/>
|
||||
</vector>
|
||||
@@ -105,7 +105,6 @@
|
||||
android:layout_marginBottom="49dp"
|
||||
android:layout_marginHorizontal="24dp"
|
||||
app:layout_constraintTop_toBottomOf="@id/qr_code_container"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
android:clickable="true"
|
||||
@@ -229,4 +228,23 @@
|
||||
android:layout_margin="24dp"
|
||||
/>
|
||||
|
||||
<com.google.android.material.button.MaterialButton
|
||||
android:id="@+id/verify_button"
|
||||
style="@style/Signal.Widget.Button.Base.Tonal"
|
||||
android:backgroundTint="@color/signal_colorSurface1"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="24dp"
|
||||
android:text="@string/verify_display_fragment__mark_as_verified"
|
||||
app:layout_constraintTop_toBottomOf="@id/number_table"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent" />
|
||||
|
||||
<Space
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="24dp"
|
||||
app:layout_constraintTop_toBottomOf="@id/verify_button"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent" />
|
||||
|
||||
</merge>
|
||||
@@ -21,21 +21,13 @@
|
||||
app:titleTextAppearance="@style/Signal.Text.TitleLarge"
|
||||
tools:title="@string/AndroidManifest__verify_safety_number" />
|
||||
|
||||
|
||||
<androidx.constraintlayout.widget.Barrier
|
||||
android:id="@+id/header_barrier"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
app:barrierDirection="bottom"
|
||||
app:constraint_referenced_ids="toolbar"/>
|
||||
|
||||
<ScrollView
|
||||
android:id="@+id/scroll_view"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="0dp"
|
||||
android:fillViewport="true"
|
||||
app:layout_constraintTop_toBottomOf="@id/header_barrier"
|
||||
app:layout_constraintBottom_toTopOf="@id/verify_button_container">
|
||||
app:layout_constraintTop_toBottomOf="@id/toolbar"
|
||||
app:layout_constraintBottom_toBottomOf="parent">
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="fill_parent"
|
||||
@@ -65,44 +57,78 @@
|
||||
android:text="@string/verify_display_fragment__pnp_verify_safety_numbers_explanation_with_s"
|
||||
android:textColor="@color/signal_colorOnSurfaceVariant"
|
||||
android:textColorLink="@color/signal_colorPrimary" />
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/automatic_verification"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical">
|
||||
|
||||
<TextView
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
style="@style/Signal.Text.TitleSmall"
|
||||
android:layout_marginStart="24dp"
|
||||
android:layout_marginVertical="12dp"
|
||||
android:text="@string/verify_display_fragment__automatic" />
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/auto_verify_container"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:background="@drawable/rounded_rectangle_38"
|
||||
android:backgroundTint="@color/signal_colorSurface1"
|
||||
android:paddingVertical="16dp"
|
||||
android:paddingHorizontal="20dp"
|
||||
android:gravity="center_vertical"
|
||||
android:layout_marginHorizontal="16dp"
|
||||
android:orientation="horizontal">
|
||||
|
||||
<ProgressBar
|
||||
android:id="@+id/auto_verify_spinner"
|
||||
android:layout_width="24dp"
|
||||
android:layout_height="24dp"
|
||||
android:indeterminate="true"
|
||||
android:indeterminateTint="@color/signal_colorOutline"
|
||||
android:visibility="visible" />
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/auto_verify_icon"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:src="@drawable/symbol_key_24" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/auto_verify_text"
|
||||
style="@style/Signal.Text.BodyLarge"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="12dp"
|
||||
android:text="@string/verify_display_fragment__verify_automatic" />
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/auto_verify_more"
|
||||
android:src="@drawable/symbol_chevron_right_compact_bold_16"
|
||||
android:layout_marginStart="2dp"
|
||||
app:tint="@color/signal_colorOutline"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content" />
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
<org.thoughtcrime.securesms.util.views.LearnMoreTextView
|
||||
android:id="@+id/caption"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginVertical="12dp"
|
||||
android:paddingHorizontal="@dimen/gutter"
|
||||
android:textAppearance="@style/Signal.Text.BodyMedium"
|
||||
android:textColor="@color/signal_colorOnSurfaceVariant" />
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
</ScrollView>
|
||||
|
||||
<View
|
||||
android:id="@+id/toolbar_shadow"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="5dp"
|
||||
android:visibility="gone"
|
||||
android:background="@drawable/toolbar_shadow"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@id/header_barrier"
|
||||
tools:visibility="visible" />
|
||||
|
||||
<View
|
||||
android:id="@+id/verify_identity_bottom_shadow"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="5dp"
|
||||
android:background="@drawable/bottom_toolbar_shadow"
|
||||
android:visibility="gone"
|
||||
app:layout_constraintBottom_toTopOf="@id/verify_button_container" />
|
||||
<FrameLayout
|
||||
android:id="@+id/verify_button_container"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="96dp"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintEnd_toStartOf="parent">
|
||||
|
||||
<com.google.android.material.button.MaterialButton
|
||||
android:id="@+id/verify_button"
|
||||
style="@style/Signal.Widget.Button.Large.Tonal"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="@dimen/dsl_settings_gutter"
|
||||
android:layout_marginTop="16dp"
|
||||
android:layout_marginEnd="@dimen/dsl_settings_gutter"
|
||||
android:layout_gravity="center_horizontal"
|
||||
android:text="@string/verify_display_fragment__mark_as_verified"
|
||||
android:textAllCaps="false" />
|
||||
</FrameLayout>
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
@@ -3822,6 +3822,32 @@
|
||||
<string name="verify_display_fragment__loading">Loading…</string>
|
||||
<string name="verify_display_fragment__mark_as_verified">Mark as verified</string>
|
||||
<string name="verify_display_fragment__clear_verification">Clear verification</string>
|
||||
<!-- Header title for automatic key verification -->
|
||||
<string name="verify_display_fragment__automatic">Automatic Key Verification</string>
|
||||
<!-- Button text to verify automatically -->
|
||||
<string name="verify_display_fragment__verify_automatic">Verify automatically</string>
|
||||
<!-- Loading text when verifying -->
|
||||
<string name="verify_display_fragment__verifying">Verifying encryption…</string>
|
||||
<!-- Success text shown when encryption is verified -->
|
||||
<string name="verify_display_fragment__encryption_verified">Encryption verified</string>
|
||||
<!-- Text shown when verification fails -->
|
||||
<string name="verify_display_fragment__encryption_unavailable">Auto-verification unavailable</string>
|
||||
<!-- Caption text explaining more about automatic verification -->
|
||||
<string name="verify_display_fragment__auto_verify_not_available">Auto-verification is not available for all chats.</string>
|
||||
<string name="verify_display_fragment__link" translatable="false">https://signal.org/redirect/safety-numbers</string>
|
||||
|
||||
<!-- Bottom sheet title when encryption is auto-verified -->
|
||||
<string name="EncryptionVerifiedSheet__title_success">Encryption was auto-verified for this chat</string>
|
||||
<!-- Bottom sheet body when encryption is auto-verified -->
|
||||
<string name="EncryptionVerifiedSheet__body_success">For contacts you’re connected to by phone number, Signal can automatically confirm whether the connection is secure using a process called key transparency. For added security, verify end-to-end encryption manually by comparing the numbers on the previous screen or scanning the code on their device.</string>
|
||||
<!-- Bottom sheet title when encryption is no longer auto-verified -->
|
||||
<string name="EncryptionVerifiedSheet__title_no_longer_unavailable">Auto-verification is no longer available for this chat</string>
|
||||
<!-- Bottom sheet body when encryption is no longer auto-verified. Placeholder is the name of the person. -->
|
||||
<string name="EncryptionVerifiedSheet__body_no_longer_unavailable">Signal can no longer automatically verify the encryption for this chat. This is likely because %1$s changed their phone number. Verify end-to-end encryption manually by comparing the numbers on the previous screen or scanning the code on their device.</string>
|
||||
<!-- Bottom sheet title when encryption cannot be auto-verified -->
|
||||
<string name="EncryptionVerifiedSheet__title_unavailable">Auto-verification not available for this chat</string>
|
||||
<!-- Bottom sheet body when encryption cannot be auto-verified -->
|
||||
<string name="EncryptionVerifiedSheet__body_unavailable">Signal can only automatically verify the encryption in chats where you’re connected to someone via a phone number. If the chat was started with a username or a group in common, verify end-to-end encryption by comparing the numbers on the previous screen or scanning the code on their device.</string>
|
||||
|
||||
<!-- Title for auto verification education sheet -->
|
||||
<string name="VerifyAutomaticallyEducationSheet__title">Signal now auto-verifies end-to-end encryption</string>
|
||||
|
||||
Reference in New Issue
Block a user