diff --git a/res/drawable/token_background.xml b/res/drawable/token_background.xml
new file mode 100644
index 0000000..846b16c
--- /dev/null
+++ b/res/drawable/token_background.xml
@@ -0,0 +1,12 @@
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/res/layout/contact_token.xml b/res/layout/contact_token.xml
new file mode 100644
index 0000000..fb18fc6
--- /dev/null
+++ b/res/layout/contact_token.xml
@@ -0,0 +1,16 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/res/layout/fragment_new_email.xml b/res/layout/fragment_new_email.xml
index f668af6..e3d35c6 100644
--- a/res/layout/fragment_new_email.xml
+++ b/res/layout/fragment_new_email.xml
@@ -14,15 +14,13 @@
android:layout_width="match_parent"
android:layout_height="wrap_content" />
-
+ android:layout_height="wrap_content" >
-
+
mAdapter;
+ ContactsCompletionView mRecipients;
EditText mSubject;
EditText mContent;
@@ -84,12 +90,32 @@ public class NewEmailFragment extends Fragment {
mSpinner.setAdapter(identities);
mSpinner.setSelection(mDefaultPos);
- mRecipients = (MultiAutoCompleteTextView) view.findViewById(R.id.recipients);
- mRecipients.setAdapter(null); // TODO: Implement
- mRecipients.setTokenizer(new MultiAutoCompleteTextView.CommaTokenizer());
+ List contacts = new ArrayList();
+ try {
+ for (Contact contact : I2PBote.getInstance().getAddressBook().getAll()) {
+ contacts.add(new Person(contact.getName(), contact.getBase64Dest()));
+ }
+ } catch (PasswordException e) {
+ // TODO handle
+ e.printStackTrace();
+ }
+ mAdapter = new FilteredArrayAdapter(getActivity(), android.R.layout.simple_list_item_1, contacts) {
+ @Override
+ protected boolean keepObject(Person obj, String mask) {
+ mask = mask.toLowerCase(Locale.US);
+ return obj.getName().toLowerCase(Locale.US).startsWith(mask) || obj.getAddress().toLowerCase(Locale.US).startsWith(mask);
+ }
+ };
+
+ mRecipients = (ContactsCompletionView) view.findViewById(R.id.recipients);
+ mRecipients.setAdapter(mAdapter);
mSubject = (EditText) view.findViewById(R.id.subject);
mContent = (EditText) view.findViewById(R.id.message);
+
+ if (savedInstanceState == null) {
+ mRecipients.setPrefix(getResources().getString(R.string.to));
+ }
}
@Override
@@ -124,8 +150,11 @@ public class NewEmailFragment extends Fragment {
// Bote versions to see a sender (and validate the signature).
email.setSender(ia);
- // TODO: Implement properly
- email.addRecipient(Message.RecipientType.TO, ia);
+ for (Object obj : mRecipients.getObjects()) {
+ Person person = (Person) obj;
+ email.addRecipient(Message.RecipientType.TO, new InternetAddress(
+ person.getAddress(), person.getName()));
+ }
email.setSubject(mSubject.getText().toString(), "UTF-8");
diff --git a/src/i2p/bote/android/util/ContactsCompletionView.java b/src/i2p/bote/android/util/ContactsCompletionView.java
new file mode 100644
index 0000000..d667eeb
--- /dev/null
+++ b/src/i2p/bote/android/util/ContactsCompletionView.java
@@ -0,0 +1,74 @@
+package i2p.bote.android.util;
+
+import java.security.GeneralSecurityException;
+import java.util.SortedSet;
+
+import i2p.bote.I2PBote;
+import i2p.bote.android.R;
+import i2p.bote.email.EmailDestination;
+import i2p.bote.fileencryption.PasswordException;
+import i2p.bote.packet.dht.Contact;
+import android.app.Activity;
+import android.content.Context;
+import android.util.AttributeSet;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.LinearLayout;
+import android.widget.TextView;
+
+import com.tokenautocomplete.TokenCompleteTextView;
+
+public class ContactsCompletionView extends TokenCompleteTextView {
+ public ContactsCompletionView(Context context, AttributeSet attrs) {
+ super(context, attrs);
+ allowDuplicates(false);
+ }
+
+ @Override
+ protected View getViewForObject(Object object) {
+ Person person = (Person) object;
+
+ LayoutInflater l = (LayoutInflater)getContext().getSystemService(Activity.LAYOUT_INFLATER_SERVICE);
+ LinearLayout view = (LinearLayout)l.inflate(R.layout.contact_token, (ViewGroup)ContactsCompletionView.this.getParent(), false);
+ ((TextView)view.findViewById(R.id.contact_name)).setText(person.getName());
+
+ return view;
+ }
+
+ @Override
+ protected Object defaultObject(String completionText) {
+ // Stupid simple example of guessing if we have an email or not
+ int index = completionText.indexOf('@');
+ if (index == -1) {
+ try {
+ // Check if it is a known Destination
+ Contact c = BoteHelper.getContact(completionText);
+ if (c != null)
+ return new Person(c.getName(), c.getBase64Dest());
+
+ // Check if it is a name
+ SortedSet contacts = I2PBote.getInstance().getAddressBook().getAll();
+ for (Contact contact : contacts) {
+ if (contact.getName().startsWith(completionText))
+ return new Person(contact.getName(), contact.getBase64Dest());
+ }
+
+ // Try as a new Destination
+ try {
+ new EmailDestination(completionText);
+ return new Person(completionText.substring(0, 5), completionText);
+ } catch (GeneralSecurityException e) {
+ // Not a valid Destination
+ // Assume the user meant an external address
+ return new Person(completionText, completionText.replace(" ", "") + "@example.com", true);
+ }
+ } catch (PasswordException e) {
+ // TODO handle
+ return new Person(completionText, completionText.replace(" ", "") + "@example.com", true);
+ }
+ } else {
+ return new Person(completionText.substring(0, index), completionText, true);
+ }
+ }
+}
diff --git a/src/i2p/bote/android/util/Person.java b/src/i2p/bote/android/util/Person.java
new file mode 100644
index 0000000..96ed0ea
--- /dev/null
+++ b/src/i2p/bote/android/util/Person.java
@@ -0,0 +1,27 @@
+package i2p.bote.android.util;
+
+import java.io.Serializable;
+
+public class Person implements Serializable {
+ private static final long serialVersionUID = -2874686247798691378L;
+ private String name;
+ private String address;
+ private boolean isExternal;
+
+ public Person(String n, String a) { this(n, a, false); }
+ public Person(String n, String a, boolean e) { name = n; address = a; isExternal = e; }
+
+ public String getName() { return name; }
+ public String getAddress() { return address; }
+ public boolean isExternal() { return isExternal; }
+
+ @Override
+ public boolean equals(Object other) {
+ if (!(other instanceof Person))
+ return false;
+ return address.equals(((Person)other).address);
+ }
+
+ @Override
+ public String toString() { return name; }
+}