Partially fix device linking

This commit is contained in:
Niels Andriesse 2020-01-17 11:38:30 +11:00
parent 0b8a21f37b
commit e95e39fdc9
6 changed files with 182 additions and 6 deletions

View File

@ -11,6 +11,7 @@
android:layout_height="match_parent" /> android:layout_height="match_parent" />
<LinearLayout <LinearLayout
android:id="@+id/emptyStateContainer"
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:gravity="center_horizontal" android:gravity="center_horizontal"

View File

@ -0,0 +1,31 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="@drawable/conversation_view_background"
android:padding="@dimen/medium_spacing"
android:orientation="vertical">
<TextView
android:id="@+id/titleTextView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:maxLines="1"
android:ellipsize="end"
android:textSize="@dimen/medium_font_size"
android:textStyle="bold"
android:textColor="@color/text"
android:text="Spiderman" />
<TextView
android:id="@+id/subtitleTextView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:maxLines="1"
android:ellipsize="end"
android:textSize="@dimen/small_font_size"
android:textColor="@color/text"
android:text="Sorry, gotta go fight crime again" />
</LinearLayout>

View File

@ -2,37 +2,67 @@ package org.thoughtcrime.securesms.loki.redesign.activities
import android.os.AsyncTask import android.os.AsyncTask
import android.os.Bundle import android.os.Bundle
import android.support.v4.app.LoaderManager
import android.support.v4.content.Loader
import android.support.v7.app.AlertDialog
import android.support.v7.widget.LinearLayoutManager import android.support.v7.widget.LinearLayoutManager
import android.view.Menu import android.view.Menu
import android.view.MenuItem import android.view.MenuItem
import android.view.View
import kotlinx.android.synthetic.main.activity_linked_devices.* import kotlinx.android.synthetic.main.activity_linked_devices.*
import network.loki.messenger.R import network.loki.messenger.R
import org.thoughtcrime.securesms.PassphraseRequiredActionBarActivity import org.thoughtcrime.securesms.PassphraseRequiredActionBarActivity
import org.thoughtcrime.securesms.devicelist.Device
import org.thoughtcrime.securesms.loki.redesign.dialogs.LinkDeviceMasterModeDialog import org.thoughtcrime.securesms.loki.redesign.dialogs.LinkDeviceMasterModeDialog
import org.thoughtcrime.securesms.loki.redesign.dialogs.LinkDeviceMasterModeDialogDelegate import org.thoughtcrime.securesms.loki.redesign.dialogs.LinkDeviceMasterModeDialogDelegate
import org.thoughtcrime.securesms.loki.signAndSendPairingAuthorisationMessage import org.thoughtcrime.securesms.loki.signAndSendPairingAuthorisationMessage
import org.thoughtcrime.securesms.util.Util import org.thoughtcrime.securesms.util.Util
import org.whispersystems.signalservice.loki.api.PairingAuthorisation import org.whispersystems.signalservice.loki.api.PairingAuthorisation
class LinkedDevicesActivity : PassphraseRequiredActionBarActivity, LinkDeviceMasterModeDialogDelegate { class LinkedDevicesActivity : PassphraseRequiredActionBarActivity, LoaderManager.LoaderCallbacks<List<Device>>, LinkDeviceMasterModeDialogDelegate {
private val linkedDevicesAdapter = LinkedDevicesAdapter(this)
private var devices = listOf<Device>()
set(value) { field = value; linkedDevicesAdapter.devices = value }
// region Lifecycle
constructor() : super() constructor() : super()
override fun onCreate(savedInstanceState: Bundle?, isReady: Boolean) { override fun onCreate(savedInstanceState: Bundle?, isReady: Boolean) {
super.onCreate(savedInstanceState, isReady) super.onCreate(savedInstanceState, isReady)
setContentView(R.layout.activity_linked_devices) setContentView(R.layout.activity_linked_devices)
supportActionBar!!.title = "Linked Devices" supportActionBar!!.title = "Linked Devices"
// val homeAdapter = LinkedDevicesAdapter(this, cursor) recyclerView.adapter = linkedDevicesAdapter
// recyclerView.adapter = homeAdapter
recyclerView.layoutManager = LinearLayoutManager(this) recyclerView.layoutManager = LinearLayoutManager(this)
linkDeviceButton.setOnClickListener { linkDevice() } linkDeviceButton.setOnClickListener { linkDevice() }
LoaderManager.getInstance(this).initLoader(0, null, this)
} }
override fun onCreateOptionsMenu(menu: Menu?): Boolean { override fun onCreateOptionsMenu(menu: Menu?): Boolean {
menuInflater.inflate(R.menu.menu_linked_devices, menu) menuInflater.inflate(R.menu.menu_linked_devices, menu)
return true return true
} }
// endregion
// region Updating
override fun onCreateLoader(id: Int, bundle: Bundle?): Loader<List<Device>> {
return LinkedDevicesLoader(this)
}
override fun onLoadFinished(loader: Loader<List<Device>>, devices: List<Device>?) {
update(devices ?: listOf())
}
override fun onLoaderReset(loader: Loader<List<Device>>) {
update(listOf())
}
private fun update(devices: List<Device>) {
this.devices = devices
emptyStateContainer.visibility = if (devices.isEmpty()) View.VISIBLE else View.GONE
}
// endregion
// region Interaction
override fun onOptionsItemSelected(item: MenuItem): Boolean { override fun onOptionsItemSelected(item: MenuItem): Boolean {
val id = item.itemId val id = item.itemId
when (id) { when (id) {
@ -43,9 +73,17 @@ class LinkedDevicesActivity : PassphraseRequiredActionBarActivity, LinkDeviceMas
} }
private fun linkDevice() { private fun linkDevice() {
val linkDeviceDialog = LinkDeviceMasterModeDialog() if (devices.isEmpty()) {
linkDeviceDialog.delegate = this val linkDeviceDialog = LinkDeviceMasterModeDialog()
linkDeviceDialog.show(supportFragmentManager, "Link Device Dialog") linkDeviceDialog.delegate = this
linkDeviceDialog.show(supportFragmentManager, "Link Device Dialog")
} else {
val builder = AlertDialog.Builder(this)
builder.setTitle("Multi Device Limit Reached")
builder.setMessage("It's currently not allowed to link more than one device.")
builder.setPositiveButton("OK", { dialog, _ -> dialog.dismiss() })
builder.create().show()
}
} }
override fun onDeviceLinkRequestAuthorized(authorization: PairingAuthorisation) { override fun onDeviceLinkRequestAuthorized(authorization: PairingAuthorisation) {
@ -60,4 +98,5 @@ class LinkedDevicesActivity : PassphraseRequiredActionBarActivity, LinkDeviceMas
override fun onDeviceLinkCanceled() { override fun onDeviceLinkCanceled() {
// Do nothing // Do nothing
} }
// endregion
} }

View File

@ -0,0 +1,28 @@
package org.thoughtcrime.securesms.loki.redesign.activities
import android.content.Context
import android.support.v7.widget.RecyclerView
import android.view.ViewGroup
import org.thoughtcrime.securesms.devicelist.Device
import org.thoughtcrime.securesms.loki.redesign.views.DeviceView
class LinkedDevicesAdapter(private val context: Context) : RecyclerView.Adapter<LinkedDevicesAdapter.ViewHolder>() {
var devices = listOf<Device>()
set(value) { field = value; notifyDataSetChanged() }
class ViewHolder(val view: DeviceView) : RecyclerView.ViewHolder(view)
override fun getItemCount(): Int {
return devices.size
}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
val view = DeviceView(context)
return ViewHolder(view)
}
override fun onBindViewHolder(viewHolder: ViewHolder, position: Int) {
val device = devices[position]
viewHolder.view.bind(device)
}
}

View File

@ -0,0 +1,33 @@
package org.thoughtcrime.securesms.loki.redesign.activities
import android.content.Context
import org.thoughtcrime.securesms.database.DatabaseFactory
import org.thoughtcrime.securesms.devicelist.Device
import org.thoughtcrime.securesms.loki.MnemonicUtilities
import org.thoughtcrime.securesms.util.AsyncLoader
import org.thoughtcrime.securesms.util.TextSecurePreferences
import org.whispersystems.signalservice.loki.api.LokiStorageAPI
import org.whispersystems.signalservice.loki.crypto.MnemonicCodec
import java.io.File
class LinkedDevicesLoader(context: Context) : AsyncLoader<List<Device>>(context) {
private val mnemonicCodec by lazy {
val languageFileDirectory = File(context.applicationInfo.dataDir)
MnemonicCodec(languageFileDirectory)
}
override fun loadInBackground(): List<Device>? {
try {
val userHexEncodedPublicKey = TextSecurePreferences.getLocalNumber(context)
val slaveDeviceHexEncodedPublicKeys = LokiStorageAPI.shared.getSecondaryDevicePublicKeys(userHexEncodedPublicKey).get()
return slaveDeviceHexEncodedPublicKeys.map { hexEncodedPublicKey ->
val shortID = MnemonicUtilities.getFirst3Words(mnemonicCodec, hexEncodedPublicKey)
val name = DatabaseFactory.getLokiUserDatabase(context).getDisplayName(hexEncodedPublicKey)
Device(hexEncodedPublicKey, shortID, name)
}.sortedBy { it.name }
} catch (e: Exception) {
return null
}
}
}

View File

@ -0,0 +1,44 @@
package org.thoughtcrime.securesms.loki.redesign.views
import android.content.Context
import android.util.AttributeSet
import android.view.LayoutInflater
import android.widget.LinearLayout
import kotlinx.android.synthetic.main.view_device.view.*
import network.loki.messenger.R
import org.thoughtcrime.securesms.devicelist.Device
class DeviceView : LinearLayout {
var device: Device? = null
// region Lifecycle
constructor(context: Context) : super(context) {
setUpViewHierarchy()
}
constructor(context: Context, attrs: AttributeSet) : super(context, attrs) {
setUpViewHierarchy()
}
constructor(context: Context, attrs: AttributeSet, defStyleAttr: Int) : super(context, attrs, defStyleAttr) {
setUpViewHierarchy()
}
constructor(context: Context, attrs: AttributeSet, defStyleAttr: Int, defStyleRes: Int) : super(context, attrs, defStyleAttr, defStyleRes) {
setUpViewHierarchy()
}
private fun setUpViewHierarchy() {
val inflater = context.applicationContext.getSystemService(Context.LAYOUT_INFLATER_SERVICE) as LayoutInflater
val contentView = inflater.inflate(R.layout.view_device, null)
addView(contentView)
}
// endregion
// region Updating
fun bind(device: Device) {
titleTextView.text = if (!device.name.isNullOrBlank()) device.name else "Unnamed Device"
subtitleTextView.text = device.shortId
}
// endregion
}