Refactor.

Add text field to authorise dialog.
This commit is contained in:
Mikunj 2019-11-20 14:55:42 +11:00
parent dc40ff0548
commit 28a04f13af
10 changed files with 98 additions and 53 deletions

View File

@ -1,6 +1,7 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<LinearLayout <LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android" xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_margin="16dp" android:layout_margin="16dp"
@ -44,6 +45,18 @@
android:textAlignment="center" android:textAlignment="center"
android:text="word word word" /> android:text="word word word" />
<org.thoughtcrime.securesms.components.LabeledEditText
android:id="@+id/deviceNameText"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="16dp"
android:ems="10"
android:inputType="text"
android:singleLine="true"
app:labeledEditText_label="@string/view_device_linking_device_name_edit_text_description"
app:labeledEditText_background="?attr/colorBackgroundFloating"
/>
<LinearLayout <LinearLayout
android:id="@+id/buttonContainer" android:id="@+id/buttonContainer"
android:layout_width="match_parent" android:layout_width="match_parent"

View File

@ -1635,6 +1635,7 @@
<string name="view_device_linking_explanation_3">Your device has been linked successfully</string> <string name="view_device_linking_explanation_3">Your device has been linked successfully</string>
<string name="view_device_linking_authorize_button_title">Authorize</string> <string name="view_device_linking_authorize_button_title">Authorize</string>
<string name="view_device_linking_cancel_button_title">Cancel</string> <string name="view_device_linking_cancel_button_title">Cancel</string>
<string name="view_device_linking_device_name_edit_text_description">Device Name (Optional)</string>
<!-- Scan QR code fragment --> <!-- Scan QR code fragment -->
<string name="fragment_scan_qr_code_title">Scan QR Code</string> <string name="fragment_scan_qr_code_title">Scan QR Code</string>
<string name="fragment_scan_qr_code_explanation">Scan the QR code of the person you\'d like to securely message. They can find their QR code by going into Loki Messenger\'s in-app settings and clicking \"Show QR Code\".</string> <string name="fragment_scan_qr_code_explanation">Scan the QR code of the person you\'d like to securely message. They can find their QR code by going into Loki Messenger\'s in-app settings and clicking \"Show QR Code\".</string>

View File

@ -26,7 +26,6 @@ import android.content.Intent;
import android.content.SharedPreferences; import android.content.SharedPreferences;
import android.content.res.TypedArray; import android.content.res.TypedArray;
import android.graphics.drawable.Drawable; import android.graphics.drawable.Drawable;
import android.os.AsyncTask;
import android.os.Build; import android.os.Build;
import android.os.Build.VERSION; import android.os.Build.VERSION;
import android.os.Bundle; import android.os.Bundle;
@ -40,14 +39,8 @@ import android.support.v7.app.AlertDialog;
import android.support.v7.preference.Preference; import android.support.v7.preference.Preference;
import android.widget.Toast; import android.widget.Toast;
import org.jetbrains.annotations.NotNull;
import org.thoughtcrime.securesms.crypto.IdentityKeyUtil; import org.thoughtcrime.securesms.crypto.IdentityKeyUtil;
import org.thoughtcrime.securesms.database.DatabaseFactory;
import org.thoughtcrime.securesms.loki.DeviceLinkingDialog;
import org.thoughtcrime.securesms.loki.DeviceLinkingDialogDelegate;
import org.thoughtcrime.securesms.loki.DeviceLinkingView;
import org.thoughtcrime.securesms.loki.LinkedDevicesActivity; import org.thoughtcrime.securesms.loki.LinkedDevicesActivity;
import org.thoughtcrime.securesms.loki.MultiDeviceUtilities;
import org.thoughtcrime.securesms.loki.QRCodeDialog; import org.thoughtcrime.securesms.loki.QRCodeDialog;
import org.thoughtcrime.securesms.preferences.AppProtectionPreferenceFragment; import org.thoughtcrime.securesms.preferences.AppProtectionPreferenceFragment;
import org.thoughtcrime.securesms.preferences.ChatsPreferenceFragment; import org.thoughtcrime.securesms.preferences.ChatsPreferenceFragment;
@ -58,7 +51,6 @@ import org.thoughtcrime.securesms.service.KeyCachingService;
import org.thoughtcrime.securesms.util.DynamicLanguage; import org.thoughtcrime.securesms.util.DynamicLanguage;
import org.thoughtcrime.securesms.util.DynamicTheme; import org.thoughtcrime.securesms.util.DynamicTheme;
import org.thoughtcrime.securesms.util.TextSecurePreferences; import org.thoughtcrime.securesms.util.TextSecurePreferences;
import org.whispersystems.signalservice.loki.api.PairingAuthorisation;
import org.whispersystems.signalservice.loki.crypto.MnemonicCodec; import org.whispersystems.signalservice.loki.crypto.MnemonicCodec;
import org.whispersystems.signalservice.loki.utilities.Analytics; import org.whispersystems.signalservice.loki.utilities.Analytics;
import org.whispersystems.signalservice.loki.utilities.SerializationKt; import org.whispersystems.signalservice.loki.utilities.SerializationKt;

View File

@ -0,0 +1,33 @@
package org.thoughtcrime.securesms.loki
import org.whispersystems.signalservice.loki.api.PairingAuthorisation
interface DeviceLinkingDelegate {
companion object {
fun combine(vararg delegates: DeviceLinkingDelegate?): DeviceLinkingDelegate {
val validDelegates = delegates.filterNotNull()
return object : DeviceLinkingDelegate {
override fun handleDeviceLinkAuthorized(pairingAuthorisation: PairingAuthorisation) {
for (delegate in validDelegates) { delegate.handleDeviceLinkAuthorized(pairingAuthorisation) }
}
override fun handleDeviceLinkingDialogDismissed() {
for (delegate in validDelegates) { delegate.handleDeviceLinkingDialogDismissed() }
}
override fun sendPairingAuthorizedMessage(pairingAuthorisation: PairingAuthorisation) {
for (delegate in validDelegates) { delegate.sendPairingAuthorizedMessage(pairingAuthorisation) }
}
override fun setDeviceDisplayName(hexEncodedPublicKey: String, displayName: String) {
for (delegate in validDelegates) { delegate.setDeviceDisplayName(hexEncodedPublicKey, displayName) }
}
}
}
}
fun handleDeviceLinkAuthorized(pairingAuthorisation: PairingAuthorisation) {}
fun handleDeviceLinkingDialogDismissed() {}
fun sendPairingAuthorizedMessage(pairingAuthorisation: PairingAuthorisation) {}
fun setDeviceDisplayName(hexEncodedPublicKey: String, displayName: String) {}
}

View File

@ -8,13 +8,12 @@ import org.whispersystems.signalservice.loki.api.DeviceLinkingSession
import org.whispersystems.signalservice.loki.api.DeviceLinkingSessionListener import org.whispersystems.signalservice.loki.api.DeviceLinkingSessionListener
import org.whispersystems.signalservice.loki.api.PairingAuthorisation import org.whispersystems.signalservice.loki.api.PairingAuthorisation
class DeviceLinkingDialog private constructor(private val context: Context, private val mode: DeviceLinkingView.Mode, private val delegate: DeviceLinkingDialogDelegate?) : DeviceLinkingViewDelegate, DeviceLinkingSessionListener { class DeviceLinkingDialog private constructor(private val context: Context, private val mode: DeviceLinkingView.Mode, private val delegate: DeviceLinkingDelegate?) : DeviceLinkingDelegate, DeviceLinkingSessionListener {
private lateinit var view: DeviceLinkingView private lateinit var view: DeviceLinkingView
private lateinit var dialog: AlertDialog private lateinit var dialog: AlertDialog
companion object { companion object {
fun show(context: Context, mode: DeviceLinkingView.Mode, delegate: DeviceLinkingDelegate?): DeviceLinkingDialog {
fun show(context: Context, mode: DeviceLinkingView.Mode, delegate: DeviceLinkingDialogDelegate?): DeviceLinkingDialog {
val dialog = DeviceLinkingDialog(context, mode, delegate) val dialog = DeviceLinkingDialog(context, mode, delegate)
dialog.show() dialog.show()
return dialog return dialog
@ -22,8 +21,10 @@ class DeviceLinkingDialog private constructor(private val context: Context, priv
} }
private fun show() { private fun show() {
view = DeviceLinkingView(context, mode, this) val delegate = DeviceLinkingDelegate.combine(this, this.delegate)
view = DeviceLinkingView(context, mode, delegate)
dialog = AlertDialog.Builder(context).setView(view).show() dialog = AlertDialog.Builder(context).setView(view).show()
dialog.setCanceledOnTouchOutside(false)
view.dismiss = { dismiss() } view.dismiss = { dismiss() }
DeviceLinkingSession.shared.startListeningForLinkingRequests() DeviceLinkingSession.shared.startListeningForLinkingRequests()
DeviceLinkingSession.shared.addListener(this) DeviceLinkingSession.shared.addListener(this)
@ -35,20 +36,11 @@ class DeviceLinkingDialog private constructor(private val context: Context, priv
dialog.dismiss() dialog.dismiss()
} }
override fun handleDeviceLinkAuthorized(pairingAuthorisation: PairingAuthorisation) {
delegate?.handleDeviceLinkAuthorized(pairingAuthorisation)
}
override fun handleDeviceLinkingDialogDismissed() { override fun handleDeviceLinkingDialogDismissed() {
if (mode == DeviceLinkingView.Mode.Master && view.pairingAuthorisation != null) { if (mode == DeviceLinkingView.Mode.Master && view.pairingAuthorisation != null) {
val authorisation = view.pairingAuthorisation!! val authorisation = view.pairingAuthorisation!!
DatabaseFactory.getLokiPreKeyBundleDatabase(context).removePreKeyBundle(authorisation.secondaryDevicePublicKey) DatabaseFactory.getLokiPreKeyBundleDatabase(context).removePreKeyBundle(authorisation.secondaryDevicePublicKey)
} }
delegate?.handleDeviceLinkingDialogDismissed()
}
override fun sendPairingAuthorizedMessage(pairingAuthorisation: PairingAuthorisation) {
delegate?.sendPairingAuthorizedMessage(pairingAuthorisation)
} }
override fun requestUserAuthorization(authorisation: PairingAuthorisation) { override fun requestUserAuthorization(authorisation: PairingAuthorisation) {

View File

@ -1,9 +0,0 @@
package org.thoughtcrime.securesms.loki
import org.whispersystems.signalservice.loki.api.PairingAuthorisation
interface DeviceLinkingDialogDelegate {
fun handleDeviceLinkAuthorized(pairingAuthorisation: PairingAuthorisation) { }
fun handleDeviceLinkingDialogDismissed() { }
fun sendPairingAuthorizedMessage(pairingAuthorisation: PairingAuthorisation) { }
}

View File

@ -4,6 +4,8 @@ import android.content.Context
import android.graphics.Color import android.graphics.Color
import android.graphics.PorterDuff import android.graphics.PorterDuff
import android.os.Handler import android.os.Handler
import android.text.Editable
import android.text.TextWatcher
import android.util.AttributeSet import android.util.AttributeSet
import android.view.View import android.view.View
import android.widget.LinearLayout import android.widget.LinearLayout
@ -12,12 +14,10 @@ import network.loki.messenger.R
import org.thoughtcrime.securesms.util.TextSecurePreferences import org.thoughtcrime.securesms.util.TextSecurePreferences
import org.whispersystems.signalservice.loki.api.PairingAuthorisation import org.whispersystems.signalservice.loki.api.PairingAuthorisation
import org.whispersystems.signalservice.loki.crypto.MnemonicCodec import org.whispersystems.signalservice.loki.crypto.MnemonicCodec
import org.whispersystems.signalservice.loki.utilities.removing05PrefixIfNeeded
import java.io.File import java.io.File
import java.io.FileOutputStream
class DeviceLinkingView private constructor(context: Context, attrs: AttributeSet?, defStyleAttr: Int, private val mode: Mode, private var delegate: DeviceLinkingViewDelegate) : LinearLayout(context, attrs, defStyleAttr) { class DeviceLinkingView private constructor(context: Context, attrs: AttributeSet?, defStyleAttr: Int, private val mode: Mode, private var delegate: DeviceLinkingDelegate) : LinearLayout(context, attrs, defStyleAttr) {
private lateinit var languageFileDirectory: File private val languageFileDirectory: File = MnemonicUtilities.getLanguageFileDirectory(context)
var dismiss: (() -> Unit)? = null var dismiss: (() -> Unit)? = null
var pairingAuthorisation: PairingAuthorisation? = null var pairingAuthorisation: PairingAuthorisation? = null
private set private set
@ -27,12 +27,11 @@ class DeviceLinkingView private constructor(context: Context, attrs: AttributeSe
// endregion // endregion
// region Lifecycle // region Lifecycle
constructor(context: Context, mode: Mode, delegate: DeviceLinkingViewDelegate) : this(context, null, 0, mode, delegate) constructor(context: Context, mode: Mode, delegate: DeviceLinkingDelegate) : this(context, null, 0, mode, delegate)
private constructor(context: Context, attrs: AttributeSet?) : this(context, attrs, 0, Mode.Master, object : DeviceLinkingViewDelegate { }) // Just pass in a dummy mode private constructor(context: Context, attrs: AttributeSet?) : this(context, attrs, 0, Mode.Master, object : DeviceLinkingDelegate { }) // Just pass in a dummy mode
private constructor(context: Context) : this(context, null) private constructor(context: Context) : this(context, null)
init { init {
languageFileDirectory = MnemonicUtilities.getLanguageFileDirectory(context)
setUpViewHierarchy() setUpViewHierarchy()
} }
@ -57,6 +56,30 @@ class DeviceLinkingView private constructor(context: Context, attrs: AttributeSe
authorizeButton.visibility = View.GONE authorizeButton.visibility = View.GONE
authorizeButton.setOnClickListener { authorizePairing() } authorizeButton.setOnClickListener { authorizePairing() }
cancelButton.setOnClickListener { cancel() } cancelButton.setOnClickListener { cancel() }
deviceNameText.visibility = View.GONE
deviceNameText.input.addTextChangedListener(object : TextWatcher {
override fun beforeTextChanged(s: CharSequence, start: Int, count: Int, after: Int) {}
override fun onTextChanged(s: CharSequence, start: Int, before: Int, count: Int) {}
override fun afterTextChanged(s: Editable?) {
val string = s?.toString() ?: ""
when {
string.trim().length > 30 -> {
deviceNameText.input.error = "Too Long"
enableAuthorizeButton(false)
}
else -> {
deviceNameText.input.error = null
enableAuthorizeButton(true)
}
}
}
})
}
private fun enableAuthorizeButton(enabled: Boolean) {
authorizeButton.isEnabled = enabled
authorizeButton.alpha = if (enabled) 1f else 0.5f
} }
// endregion // endregion
@ -71,9 +94,10 @@ class DeviceLinkingView private constructor(context: Context, attrs: AttributeSe
titleTextView.text = resources.getString(R.string.view_device_linking_title_3) titleTextView.text = resources.getString(R.string.view_device_linking_title_3)
explanationTextView.text = resources.getString(R.string.view_device_linking_explanation_2) explanationTextView.text = resources.getString(R.string.view_device_linking_explanation_2)
mnemonicTextView.visibility = View.VISIBLE mnemonicTextView.visibility = View.VISIBLE
val hexEncodedPublicKey = pairingAuthorisation.secondaryDevicePublicKey.removing05PrefixIfNeeded() mnemonicTextView.text = MnemonicUtilities.getFirst3Words(MnemonicCodec(languageFileDirectory), pairingAuthorisation.secondaryDevicePublicKey)
mnemonicTextView.text = MnemonicCodec(languageFileDirectory).encode(hexEncodedPublicKey).split(" ").slice(0 until 3).joinToString(" ")
authorizeButton.visibility = View.VISIBLE authorizeButton.visibility = View.VISIBLE
deviceNameText.visibility = View.VISIBLE
enableAuthorizeButton(true)
} }
fun onDeviceLinkAuthorized(pairingAuthorisation: PairingAuthorisation) { fun onDeviceLinkAuthorized(pairingAuthorisation: PairingAuthorisation) {
@ -105,6 +129,7 @@ class DeviceLinkingView private constructor(context: Context, attrs: AttributeSe
if (mode != Mode.Master || pairingAuthorisation == null) { return; } if (mode != Mode.Master || pairingAuthorisation == null) { return; }
delegate.sendPairingAuthorizedMessage(pairingAuthorisation) delegate.sendPairingAuthorizedMessage(pairingAuthorisation)
delegate.handleDeviceLinkAuthorized(pairingAuthorisation) delegate.handleDeviceLinkAuthorized(pairingAuthorisation)
delegate.setDeviceDisplayName(pairingAuthorisation.secondaryDevicePublicKey, deviceNameText.text.toString().trim())
dismiss?.invoke() dismiss?.invoke()
} }

View File

@ -1,10 +0,0 @@
package org.thoughtcrime.securesms.loki
import org.whispersystems.signalservice.loki.api.PairingAuthorisation
interface DeviceLinkingViewDelegate {
fun handleDeviceLinkAuthorized(pairingAuthorisation: PairingAuthorisation) { }
fun handleDeviceLinkingDialogDismissed() { }
fun sendPairingAuthorizedMessage(pairingAuthorisation: PairingAuthorisation) { }
}

View File

@ -1,5 +1,6 @@
package org.thoughtcrime.securesms.loki package org.thoughtcrime.securesms.loki
import android.os.AsyncTask
import android.os.Bundle import android.os.Bundle
import android.view.MenuItem import android.view.MenuItem
import android.widget.Toast import android.widget.Toast
@ -10,10 +11,11 @@ import network.loki.messenger.R
import org.thoughtcrime.securesms.database.DatabaseFactory import org.thoughtcrime.securesms.database.DatabaseFactory
import org.thoughtcrime.securesms.sms.MessageSender import org.thoughtcrime.securesms.sms.MessageSender
import org.thoughtcrime.securesms.util.TextSecurePreferences import org.thoughtcrime.securesms.util.TextSecurePreferences
import org.thoughtcrime.securesms.util.Util
import org.whispersystems.signalservice.loki.api.LokiStorageAPI import org.whispersystems.signalservice.loki.api.LokiStorageAPI
import org.whispersystems.signalservice.loki.api.PairingAuthorisation import org.whispersystems.signalservice.loki.api.PairingAuthorisation
class LinkedDevicesActivity : PassphraseRequiredActionBarActivity(), DeviceLinkingDialogDelegate { class LinkedDevicesActivity : PassphraseRequiredActionBarActivity(), DeviceLinkingDelegate {
companion object { companion object {
private val TAG = DeviceActivity::class.java.simpleName private val TAG = DeviceActivity::class.java.simpleName
@ -68,7 +70,13 @@ class LinkedDevicesActivity : PassphraseRequiredActionBarActivity(), DeviceLinki
} }
override fun sendPairingAuthorizedMessage(pairingAuthorisation: PairingAuthorisation) { override fun sendPairingAuthorizedMessage(pairingAuthorisation: PairingAuthorisation) {
signAndSendPairingAuthorisationMessage(this, pairingAuthorisation) AsyncTask.execute {
this.deviceListFragment.refresh() signAndSendPairingAuthorisationMessage(this, pairingAuthorisation)
Util.runOnMain { this.deviceListFragment.refresh() }
}
}
override fun setDeviceDisplayName(hexEncodedPublicKey: String, displayName: String) {
DatabaseFactory.getLokiUserDatabase(this).setDisplayName(hexEncodedPublicKey, displayName)
} }
} }

View File

@ -32,7 +32,7 @@ import org.whispersystems.signalservice.loki.utilities.retryIfNeeded
import java.io.File import java.io.File
import java.io.FileOutputStream import java.io.FileOutputStream
class SeedActivity : BaseActionBarActivity(), DeviceLinkingDialogDelegate { class SeedActivity : BaseActionBarActivity(), DeviceLinkingDelegate {
private lateinit var languageFileDirectory: File private lateinit var languageFileDirectory: File
private var mode = Mode.Register private var mode = Mode.Register
set(newValue) { field = newValue; updateUI() } set(newValue) { field = newValue; updateUI() }