package org.thoughtcrime.securesms.loki
import android.content.Context
import android.graphics.Color
import android.graphics.PorterDuff
import android.os.Handler
import android.util.AttributeSet
import android.view.View
import android.widget.LinearLayout
import kotlinx.android.synthetic.main.view_device_linking.view.*
import network.loki.messenger.R
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.utilities.removing05PrefixIfNeeded
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 ) {
private lateinit var languageFileDirectory : File
var dismiss : ( ( ) -> Unit ) ? = null
var pairingAuthorisation : PairingAuthorisation ? = null
private set
// region Types
enum class Mode { Master , Slave }
// endregion
// region Lifecycle
constructor ( context : Context , mode : Mode , delegate : DeviceLinkingViewDelegate ) : 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 ) : this ( context , null )
init {
languageFileDirectory = MnemonicUtilities . getLanguageFileDirectory ( context )
setUpViewHierarchy ( )
}
private fun setUpViewHierarchy ( ) {
inflate ( context , R . layout . view _device _linking , this )
spinner . indeterminateDrawable . setColorFilter ( Color . WHITE , PorterDuff . Mode . SRC _IN )
val titleID = when ( mode ) {
Mode . Master -> R . string . view _device _linking _title _1
Mode . Slave -> R . string . view _device _linking _title _2
}
titleTextView . text = resources . getString ( titleID )
val explanationID = when ( mode ) {
Mode . Master -> R . string . view _device _linking _explanation _1
Mode . Slave -> R . string . view _device _linking _explanation _2
}
explanationTextView . text = resources . getString ( explanationID )
mnemonicTextView . visibility = if ( mode == Mode . Master ) View . GONE else View . VISIBLE
if ( mode == Mode . Slave ) {
val hexEncodedPublicKey = TextSecurePreferences . getLocalNumber ( context )
mnemonicTextView . text = MnemonicUtilities . getFirst3Words ( MnemonicCodec ( languageFileDirectory ) , hexEncodedPublicKey )
}
authorizeButton . visibility = View . GONE
authorizeButton . setOnClickListener { authorizePairing ( ) }
cancelButton . setOnClickListener { cancel ( ) }
}
// endregion
// region Device Linking
fun requestUserAuthorization ( pairingAuthorisation : PairingAuthorisation ) {
if ( mode != Mode . Master || pairingAuthorisation . type != PairingAuthorisation . Type . REQUEST || this . pairingAuthorisation != null ) { return }
this . pairingAuthorisation = pairingAuthorisation
spinner . visibility = View . GONE
val titleTextViewLayoutParams = titleTextView . layoutParams as LayoutParams
titleTextViewLayoutParams . topMargin = toPx ( 16 , resources )
titleTextView . layoutParams = titleTextViewLayoutParams
titleTextView . text = resources . getString ( R . string . view _device _linking _title _3 )
explanationTextView . text = resources . getString ( R . string . view _device _linking _explanation _2 )
mnemonicTextView . visibility = View . VISIBLE
val hexEncodedPublicKey = pairingAuthorisation . secondaryDevicePublicKey . removing05PrefixIfNeeded ( )
mnemonicTextView . text = MnemonicCodec ( languageFileDirectory ) . encode ( hexEncodedPublicKey ) . split ( " " ) . slice ( 0 until 3 ) . joinToString ( " " )
authorizeButton . visibility = View . VISIBLE
}
fun onDeviceLinkAuthorized ( pairingAuthorisation : PairingAuthorisation ) {
if ( mode != Mode . Slave || pairingAuthorisation . type != PairingAuthorisation . Type . GRANT || this . pairingAuthorisation != null ) { return }
this . pairingAuthorisation = pairingAuthorisation
spinner . visibility = View . GONE
val titleTextViewLayoutParams = titleTextView . layoutParams as LayoutParams
titleTextViewLayoutParams . topMargin = toPx ( 8 , resources )
titleTextView . layoutParams = titleTextViewLayoutParams
titleTextView . text = resources . getString ( R . string . view _device _linking _title _4 )
val explanationTextViewLayoutParams = explanationTextView . layoutParams as LayoutParams
explanationTextViewLayoutParams . bottomMargin = toPx ( 12 , resources )
explanationTextView . layoutParams = explanationTextViewLayoutParams
explanationTextView . text = resources . getString ( R . string . view _device _linking _explanation _3 )
titleTextView . text = resources . getString ( R . string . view _device _linking _title _4 )
mnemonicTextView . visibility = View . GONE
buttonContainer . visibility = View . GONE
cancelButton . visibility = View . GONE
Handler ( ) . postDelayed ( {
delegate . handleDeviceLinkAuthorized ( pairingAuthorisation )
dismiss ?. invoke ( )
} , 4000 )
}
// endregion
// region Interaction
private fun authorizePairing ( ) {
val pairingAuthorisation = this . pairingAuthorisation
if ( mode != Mode . Master || pairingAuthorisation == null ) { return ; }
delegate . sendPairingAuthorizedMessage ( pairingAuthorisation )
delegate . handleDeviceLinkAuthorized ( pairingAuthorisation )
dismiss ?. invoke ( )
}
private fun cancel ( ) {
delegate . handleDeviceLinkingDialogDismissed ( )
dismiss ?. invoke ( )
}
// endregion
}