Add option to select identity when composing a message

This commit is contained in:
Christian Basler 2018-02-14 17:49:39 +01:00
parent f481914a65
commit 1da0674857
6 changed files with 159 additions and 74 deletions

View File

@ -101,9 +101,8 @@ class ComposeMessageFragment : Fragment() {
parent.inventoryVector?.let { parents.add(it) }
}
}
} ?: {
throw IllegalStateException("No identity set for ComposeMessageFragment")
}.invoke()
} ?: throw IllegalStateException("No identity set for ComposeMessageFragment")
setHasOptionsMenu(true)
}
@ -115,37 +114,50 @@ class ComposeMessageFragment : Fragment() {
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
if (broadcast) {
recipient_input.visibility = View.GONE
} else {
val adapter = ContactAdapter(context!!)
recipient_input.setAdapter(adapter)
recipient_input.onItemClickListener =
AdapterView.OnItemClickListener { _, _, pos, _ -> adapter.getItem(pos) }
recipient_input.onItemSelectedListener = object : AdapterView.OnItemSelectedListener {
override fun onItemSelected(
parent: AdapterView<*>,
view: View,
position: Int,
id: Long
) {
recipient = adapter.getItem(position)
}
override fun onNothingSelected(parent: AdapterView<*>) =
Unit // leave current selection
context?.let { ctx ->
val identities = Singleton.getAddressRepository(ctx).getIdentities()
sender_input.adapter = ContactAdapter(ctx, identities, true)
val index = identities.indexOf(Singleton.getIdentity(ctx))
if (index >= 0) {
sender_input.setSelection(index)
}
recipient?.let { recipient_input.setText(it.toString()) }
}
subject_input.setText(subject)
body_input.setText(content)
when {
recipient == null -> recipient_input.requestFocus()
subject.isEmpty() -> subject_input.requestFocus()
else -> {
body_input.requestFocus()
body_input.setSelection(0)
if (broadcast) {
recipient_input.visibility = View.GONE
} else {
val adapter = ContactAdapter(
ctx,
Singleton.getAddressRepository(ctx).getContacts()
)
recipient_input.setAdapter(adapter)
recipient_input.onItemClickListener =
AdapterView.OnItemClickListener { _, _, pos, _ -> adapter.getItem(pos) }
recipient_input.onItemSelectedListener =
object : AdapterView.OnItemSelectedListener {
override fun onItemSelected(
parent: AdapterView<*>,
view: View,
position: Int,
id: Long
) {
recipient = adapter.getItem(position)
}
override fun onNothingSelected(parent: AdapterView<*>) =
Unit // leave current selection
}
recipient?.let { recipient_input.setText(it.toString()) }
}
subject_input.setText(subject)
body_input.setText(content)
when {
recipient == null -> recipient_input.requestFocus()
subject.isEmpty() -> subject_input.requestFocus()
else -> {
body_input.requestFocus()
body_input.setSelection(0)
}
}
}
}
@ -184,7 +196,7 @@ class ComposeMessageFragment : Fragment() {
private fun build(ctx: Context): Plaintext {
val builder: Plaintext.Builder
if (broadcast) {
builder = Plaintext.Builder(BROADCAST).from(identity)
builder = Plaintext.Builder(BROADCAST)
} else {
val inputString = recipient_input.text.toString()
if (recipient == null || recipient?.toString() != inputString) {
@ -203,9 +215,10 @@ class ComposeMessageFragment : Fragment() {
}
builder = Plaintext.Builder(MSG)
.from(identity)
.to(recipient)
}
val sender = sender_input.selectedItem as? ch.dissem.bitmessage.entity.BitmessageAddress
sender?.let { builder.from(it) }
if (!Preferences.requestAcknowledgements(ctx)) {
builder.preventAck()
}

View File

@ -20,25 +20,22 @@ import android.content.Context
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.BaseAdapter
import android.widget.Filter
import android.widget.Filterable
import android.widget.ImageView
import android.widget.TextView
import java.util.ArrayList
import android.widget.*
import ch.dissem.apps.abit.Identicon
import ch.dissem.apps.abit.R
import ch.dissem.apps.abit.service.Singleton
import ch.dissem.bitmessage.entity.BitmessageAddress
import java.util.*
/**
* An adapter for contacts. Can be filtered by alias or address.
*/
class ContactAdapter(ctx: Context) : BaseAdapter(), Filterable {
class ContactAdapter(
ctx: Context,
private val originalData: List<BitmessageAddress>,
private val slim: Boolean = false
) :
BaseAdapter(), Filterable {
private val inflater = LayoutInflater.from(ctx)
private val originalData = Singleton.getAddressRepository(ctx).getContacts()
private var data: List<BitmessageAddress> = originalData
override fun getCount() = data.size
@ -49,23 +46,33 @@ class ContactAdapter(ctx: Context) : BaseAdapter(), Filterable {
override fun getView(position: Int, convertView: View?, parent: ViewGroup): View {
val viewHolder = if (convertView == null) {
ViewHolder(inflater.inflate(R.layout.contact_row, parent, false))
ViewHolder(
inflater.inflate(
if (slim) {
R.layout.contact_row_slim
} else {
R.layout.contact_row
},
parent, false
)
)
} else {
convertView.tag as ViewHolder
}
val item = getItem(position)
viewHolder.avatar.setImageDrawable(Identicon(item))
viewHolder.name.text = item.toString()
viewHolder.address.text = item.address
viewHolder.address?.text = item.address
return viewHolder.view
}
override fun getFilter(): Filter = ContactFilter()
private inner class ViewHolder(val view: View) {
val avatar = view.findViewById<ImageView>(R.id.avatar)!!
val name = view.findViewById<TextView>(R.id.name)!!
val address = view.findViewById<TextView>(R.id.address)!!
val avatar: ImageView = view.findViewById(R.id.avatar)
val name: TextView = view.findViewById(R.id.name)
val address: TextView? = view.findViewById(R.id.address)
init {
view.tag = this
@ -83,27 +90,29 @@ class ContactAdapter(ctx: Context) : BaseAdapter(), Filterable {
val newValues = ArrayList<BitmessageAddress>()
originalData
.forEach { value ->
value.alias?.toLowerCase()?.let { alias ->
if (alias.startsWith(prefixString)) {
newValues.add(value)
} else {
val words = alias.split(" ".toRegex()).dropLastWhile { it.isEmpty() }.toTypedArray()
.forEach { value ->
value.alias?.toLowerCase()?.let { alias ->
if (alias.startsWith(prefixString)) {
newValues.add(value)
} else {
val words =
alias.split(" ".toRegex()).dropLastWhile { it.isEmpty() }
.toTypedArray()
for (word in words) {
if (word.startsWith(prefixString)) {
newValues.add(value)
break
}
for (word in words) {
if (word.startsWith(prefixString)) {
newValues.add(value)
break
}
}
} ?: {
val address = value.address.toLowerCase()
if (address.contains(prefixString)) {
newValues.add(value)
}
}.invoke()
}
}
} ?: {
val address = value.address.toLowerCase()
if (address.contains(prefixString)) {
newValues.add(value)
}
}.invoke()
}
results.values = newValues
results.count = newValues.size

View File

@ -0,0 +1,47 @@
<?xml version="1.0" encoding="utf-8"?><!--
~ Copyright 2015 Christian Basler
~
~ 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.
-->
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="wrap_content"
android:layout_height="wrap_content">
<ImageView
android:id="@+id/avatar"
android:layout_width="32dp"
android:layout_height="32dp"
android:layout_alignParentStart="true"
android:layout_alignParentTop="true"
android:layout_margin="4dp"
android:src="@color/colorAccent"
tools:ignore="ContentDescription" />
<TextView
android:id="@+id/name"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerVertical="true"
android:layout_toEndOf="@+id/avatar"
android:ellipsize="end"
android:lines="1"
android:paddingBottom="0dp"
android:paddingEnd="4dp"
android:paddingStart="4dp"
android:paddingTop="0dp"
android:textAppearance="?android:attr/textAppearanceMedium"
tools:text="Name" />
</RelativeLayout>

View File

@ -1,8 +1,22 @@
<?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="match_parent"
android:orientation="vertical">
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:labelFor="@id/sender_input"
android:padding="4dp"
android:text="@string/from"
android:textColor="#9b9b9b"
android:textSize="12sp" />
<Spinner
android:id="@+id/sender_input"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
<android.support.design.widget.TextInputLayout
android:layout_width="match_parent"
@ -15,7 +29,7 @@
android:layout_height="wrap_content"
android:hint="@string/to"
android:inputType="textNoSuggestions"
android:maxLines="1"/>
android:maxLines="1" />
</android.support.design.widget.TextInputLayout>
@ -29,7 +43,7 @@
android:layout_height="wrap_content"
android:hint="@string/subject"
android:inputType="textEmailSubject"
android:textAppearance="?android:attr/textAppearanceLarge"/>
android:textAppearance="?android:attr/textAppearanceLarge" />
</android.support.design.widget.TextInputLayout>
@ -41,6 +55,6 @@
android:gravity="start|top"
android:hint="@string/compose_body_hint"
android:inputType="textMultiLine|textCapSentences"
android:scrollbars="vertical"/>
android:scrollbars="vertical" />
</LinearLayout>

View File

@ -127,4 +127,5 @@ Als Alternative kann in den Einstellungen ein vertrauenswürdiger Knoten konfigu
<string name="import_data">Import</string>
<string name="import_data_summary">Nachrichten und Kontakte importieren (aber keine Identitäten)</string>
<string name="select_encoding">Kodierung auswählen</string>
<string name="from">Von</string>
</resources>

View File

@ -126,4 +126,5 @@ As an alternative you could configure a trusted node in the settings, but as of
<string name="request_acknowledgements_summary">Acknowledges allow making sure a message was received, but require additional time to send</string>
<string name="got_it">Got it</string>
<string name="select_encoding">Select encoding</string>
<string name="from">From</string>
</resources>