Integrated address book into new email recipients field
This commit is contained in:
12
res/drawable/token_background.xml
Normal file
12
res/drawable/token_background.xml
Normal file
@@ -0,0 +1,12 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<shape xmlns:android="http://schemas.android.com/apk/res/android" >
|
||||
|
||||
<solid android:color="#ffafafaf" />
|
||||
|
||||
<corners
|
||||
android:bottomLeftRadius="5dp"
|
||||
android:bottomRightRadius="5dp"
|
||||
android:topLeftRadius="5dp"
|
||||
android:topRightRadius="5dp" />
|
||||
|
||||
</shape>
|
||||
16
res/layout/contact_token.xml
Normal file
16
res/layout/contact_token.xml
Normal file
@@ -0,0 +1,16 @@
|
||||
<?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" >
|
||||
|
||||
<TextView
|
||||
android:id="@+id/contact_name"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:background="@drawable/token_background"
|
||||
android:padding="5dp"
|
||||
android:textColor="@android:color/white"
|
||||
android:textSize="18sp" />
|
||||
|
||||
</LinearLayout>
|
||||
@@ -14,15 +14,13 @@
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content" />
|
||||
|
||||
<MultiAutoCompleteTextView
|
||||
<i2p.bote.android.util.ContactsCompletionView
|
||||
android:id="@+id/recipients"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:ems="10"
|
||||
android:hint="@string/to" >
|
||||
android:layout_height="wrap_content" >
|
||||
|
||||
<requestFocus />
|
||||
</MultiAutoCompleteTextView>
|
||||
</i2p.bote.android.util.ContactsCompletionView>
|
||||
|
||||
<EditText
|
||||
android:id="@+id/subject"
|
||||
|
||||
@@ -2,21 +2,27 @@ package i2p.bote.android;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.security.GeneralSecurityException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
|
||||
import javax.mail.Message;
|
||||
import javax.mail.MessagingException;
|
||||
import javax.mail.internet.InternetAddress;
|
||||
|
||||
import net.i2p.data.DataFormatException;
|
||||
import com.tokenautocomplete.FilteredArrayAdapter;
|
||||
|
||||
import net.i2p.data.DataFormatException;
|
||||
import i2p.bote.I2PBote;
|
||||
import i2p.bote.android.util.BoteHelper;
|
||||
import i2p.bote.android.util.ContactsCompletionView;
|
||||
import i2p.bote.android.util.Person;
|
||||
import i2p.bote.email.Attachment;
|
||||
import i2p.bote.email.Email;
|
||||
import i2p.bote.email.EmailIdentity;
|
||||
import i2p.bote.fileencryption.PasswordException;
|
||||
import i2p.bote.packet.dht.Contact;
|
||||
import android.app.Activity;
|
||||
import android.content.Context;
|
||||
import android.os.Bundle;
|
||||
@@ -29,7 +35,6 @@ import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.ArrayAdapter;
|
||||
import android.widget.EditText;
|
||||
import android.widget.MultiAutoCompleteTextView;
|
||||
import android.widget.Spinner;
|
||||
import android.widget.TextView;
|
||||
|
||||
@@ -59,7 +64,8 @@ public class NewEmailFragment extends Fragment {
|
||||
|
||||
Spinner mSpinner;
|
||||
int mDefaultPos;
|
||||
MultiAutoCompleteTextView mRecipients;
|
||||
ArrayAdapter<Person> 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<Person> contacts = new ArrayList<Person>();
|
||||
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<Person>(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");
|
||||
|
||||
|
||||
74
src/i2p/bote/android/util/ContactsCompletionView.java
Normal file
74
src/i2p/bote/android/util/ContactsCompletionView.java
Normal file
@@ -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<Contact> 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
27
src/i2p/bote/android/util/Person.java
Normal file
27
src/i2p/bote/android/util/Person.java
Normal file
@@ -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; }
|
||||
}
|
||||
Reference in New Issue
Block a user