Allow entering a JID from 'choose contact'. thanks @singpolyma

Daniel Gultsch created

fixes #1611
fixes #1602

Change summary

src/main/java/eu/siacs/conversations/ui/ChooseContactActivity.java     |  67 
src/main/java/eu/siacs/conversations/ui/EnterJidDialog.java            | 122 
src/main/java/eu/siacs/conversations/ui/StartConversationActivity.java |  90 
src/main/java/eu/siacs/conversations/ui/XmppActivity.java              |   2 
src/main/res/layout/enter_jid_dialog.xml                               |   0 
src/main/res/menu/choose_contact.xml                                   |  10 
src/main/res/values/strings.xml                                        |   2 
7 files changed, 230 insertions(+), 63 deletions(-)

Detailed changes

src/main/java/eu/siacs/conversations/ui/ChooseContactActivity.java 🔗

@@ -19,12 +19,16 @@ import java.util.HashSet;
 import java.util.List;
 import java.util.Set;
 
+import eu.siacs.conversations.Config;
 import eu.siacs.conversations.R;
 import eu.siacs.conversations.entities.Account;
 import eu.siacs.conversations.entities.Contact;
 import eu.siacs.conversations.entities.ListItem;
+import eu.siacs.conversations.xmpp.jid.Jid;
 
 public class ChooseContactActivity extends AbstractSearchableListItemActivity {
+	private List<String> mActivatedAccounts = new ArrayList<String>();
+	private List<String> mKnownHosts;
 
 	private Set<Contact> selected;
 	private Set<String> filterContacts;
@@ -124,6 +128,15 @@ public class ChooseContactActivity extends AbstractSearchableListItemActivity {
 
 	}
 
+	@Override
+	public boolean onCreateOptionsMenu(final Menu menu) {
+		super.onCreateOptionsMenu(menu);
+		final Intent i = getIntent();
+		boolean showEnterJid = i != null && i.getBooleanExtra("show_enter_jid", false);
+		menu.findItem(R.id.action_create_contact).setVisible(showEnterJid);
+		return true;
+	}
+
 	protected void filterContacts(final String needle) {
 		getListItems().clear();
 		for (final Account account : xmppConnectionService.getAccounts()) {
@@ -153,4 +166,58 @@ public class ChooseContactActivity extends AbstractSearchableListItemActivity {
 	public void refreshUiReal() {
 		//nothing to do. This Activity doesn't implement any listeners
 	}
+
+	@Override
+	public boolean onOptionsItemSelected(MenuItem item) {
+		switch (item.getItemId()) {
+			case R.id.action_create_contact:
+				showEnterJidDialog();
+				return true;
+		}
+		return super.onOptionsItemSelected(item);
+	}
+
+	protected void showEnterJidDialog() {
+		EnterJidDialog dialog = new EnterJidDialog(
+			this, mKnownHosts, mActivatedAccounts,
+			getString(R.string.enter_contact), getString(R.string.select),
+			null, getIntent().getStringExtra("account"), true
+		);
+
+		dialog.setOnEnterJidDialogPositiveListener(new EnterJidDialog.OnEnterJidDialogPositiveListener() {
+			@Override
+			public boolean onEnterJidDialogPositive(Jid accountJid, Jid contactJid) throws EnterJidDialog.JidError {
+				final Intent request = getIntent();
+				final Intent data = new Intent();
+				data.putExtra("contact", contactJid.toString());
+				data.putExtra("account", accountJid.toString());
+				data.putExtra("conversation",
+						request.getStringExtra("conversation"));
+				data.putExtra("multiple", false);
+				setResult(RESULT_OK, data);
+				finish();
+
+				return true;
+			}
+		});
+
+		dialog.show();
+	}
+
+	@Override
+	void onBackendConnected() {
+		filterContacts();
+
+		this.mActivatedAccounts.clear();
+		for (Account account : xmppConnectionService.getAccounts()) {
+			if (account.getStatus() != Account.State.DISABLED) {
+				if (Config.DOMAIN_LOCK != null) {
+					this.mActivatedAccounts.add(account.getJid().getLocalpart());
+				} else {
+					this.mActivatedAccounts.add(account.getJid().toBareJid().toString());
+				}
+			}
+		}
+		this.mKnownHosts = xmppConnectionService.getKnownHosts();
+	}
 }

src/main/java/eu/siacs/conversations/ui/EnterJidDialog.java 🔗

@@ -0,0 +1,122 @@
+package eu.siacs.conversations.ui;
+
+import android.app.AlertDialog;
+import android.content.Context;
+import android.content.DialogInterface.OnClickListener;
+import android.content.DialogInterface;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.widget.ArrayAdapter;
+import android.widget.AutoCompleteTextView;
+import android.widget.Spinner;
+
+import java.util.List;
+
+import eu.siacs.conversations.Config;
+import eu.siacs.conversations.R;
+import eu.siacs.conversations.ui.adapter.KnownHostsAdapter;
+import eu.siacs.conversations.xmpp.jid.InvalidJidException;
+import eu.siacs.conversations.xmpp.jid.Jid;
+
+public class EnterJidDialog {
+	public static interface OnEnterJidDialogPositiveListener {
+		public boolean onEnterJidDialogPositive(Jid account, Jid contact) throws EnterJidDialog.JidError;
+	}
+
+	public static class JidError extends Exception {
+		final String msg;
+
+		public JidError(final String msg) {
+			this.msg = msg;
+		}
+
+		public String toString() {
+			return msg;
+		}
+	}
+
+	protected final AlertDialog dialog;
+	protected View.OnClickListener dialogOnClick;
+	protected OnEnterJidDialogPositiveListener listener = null;
+
+	public EnterJidDialog(
+		final Context context, List<String> knownHosts, List<String> activatedAccounts,
+		final String title, final String positiveButton,
+		final String prefilledJid, final String account, boolean allowEditJid
+	) {
+		AlertDialog.Builder builder = new AlertDialog.Builder(context);
+		builder.setTitle(title);
+		View dialogView = LayoutInflater.from(context).inflate(R.layout.enter_jid_dialog, null);
+		final Spinner spinner = (Spinner) dialogView.findViewById(R.id.account);
+		final AutoCompleteTextView jid = (AutoCompleteTextView) dialogView.findViewById(R.id.jid);
+		jid.setAdapter(new KnownHostsAdapter(context,android.R.layout.simple_list_item_1, knownHosts));
+		if (prefilledJid != null) {
+			jid.append(prefilledJid);
+			if (!allowEditJid) {
+				jid.setFocusable(false);
+				jid.setFocusableInTouchMode(false);
+				jid.setClickable(false);
+				jid.setCursorVisible(false);
+			}
+		}
+
+		ArrayAdapter<String> adapter;
+		if (account == null) {
+			adapter = new ArrayAdapter<>(context,
+				android.R.layout.simple_spinner_item, activatedAccounts);
+		} else {
+			adapter = new ArrayAdapter<>(context,
+				android.R.layout.simple_spinner_item, new String[] { account });
+			spinner.setEnabled(false);
+		}
+		adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
+		spinner.setAdapter(adapter);
+
+		builder.setView(dialogView);
+		builder.setNegativeButton(R.string.cancel, null);
+		builder.setPositiveButton(positiveButton, null);
+		this.dialog = builder.create();
+
+		this.dialogOnClick = new View.OnClickListener() {
+			@Override
+			public void onClick(final View v) {
+				final Jid accountJid;
+				try {
+					if (Config.DOMAIN_LOCK != null) {
+						accountJid = Jid.fromParts((String) spinner.getSelectedItem(), Config.DOMAIN_LOCK, null);
+					} else {
+						accountJid = Jid.fromString((String) spinner.getSelectedItem());
+					}
+				} catch (final InvalidJidException e) {
+					return;
+				}
+				final Jid contactJid;
+				try {
+					contactJid = Jid.fromString(jid.getText().toString());
+				} catch (final InvalidJidException e) {
+					jid.setError(context.getString(R.string.invalid_jid));
+					return;
+				}
+
+				if(listener != null) {
+					try {
+						if(listener.onEnterJidDialogPositive(accountJid, contactJid)) {
+							dialog.dismiss();
+						}
+					} catch(JidError error) {
+						jid.setError(error.toString());
+					}
+				}
+			}
+		};
+	}
+
+	public void setOnEnterJidDialogPositiveListener(OnEnterJidDialogPositiveListener listener) {
+		this.listener = listener;
+	}
+
+	public void show() {
+		this.dialog.show();
+		this.dialog.getButton(AlertDialog.BUTTON_POSITIVE).setOnClickListener(this.dialogOnClick);
+	}
+}

src/main/java/eu/siacs/conversations/ui/StartConversationActivity.java 🔗

@@ -349,69 +349,37 @@ public class StartConversationActivity extends XmppActivity implements OnRosterU
 
 	@SuppressLint("InflateParams")
 	protected void showCreateContactDialog(final String prefilledJid, final String fingerprint) {
-		AlertDialog.Builder builder = new AlertDialog.Builder(this);
-		builder.setTitle(R.string.create_contact);
-		View dialogView = getLayoutInflater().inflate(R.layout.create_contact_dialog, null);
-		final Spinner spinner = (Spinner) dialogView.findViewById(R.id.account);
-		final AutoCompleteTextView jid = (AutoCompleteTextView) dialogView.findViewById(R.id.jid);
-		jid.setAdapter(new KnownHostsAdapter(this,android.R.layout.simple_list_item_1, mKnownHosts));
-		if (prefilledJid != null) {
-			jid.append(prefilledJid);
-			if (fingerprint!=null) {
-				jid.setFocusable(false);
-				jid.setFocusableInTouchMode(false);
-				jid.setClickable(false);
-				jid.setCursorVisible(false);
-			}
-		}
-		populateAccountSpinner(spinner);
-		builder.setView(dialogView);
-		builder.setNegativeButton(R.string.cancel, null);
-		builder.setPositiveButton(R.string.create, null);
-		final AlertDialog dialog = builder.create();
-		dialog.show();
-		dialog.getButton(AlertDialog.BUTTON_POSITIVE).setOnClickListener(
-				new View.OnClickListener() {
+		EnterJidDialog dialog = new EnterJidDialog(
+			this, mKnownHosts, mActivatedAccounts,
+			getString(R.string.create_contact), getString(R.string.create),
+			prefilledJid, null, fingerprint == null
+		);
 
-					@Override
-					public void onClick(final View v) {
-						if (!xmppConnectionServiceBound) {
-							return;
-						}
-						final Jid accountJid;
-						try {
-							if (Config.DOMAIN_LOCK != null) {
-								accountJid = Jid.fromParts((String) spinner.getSelectedItem(), Config.DOMAIN_LOCK, null);
-							} else {
-								accountJid = Jid.fromString((String) spinner.getSelectedItem());
-							}
-						} catch (final InvalidJidException e) {
-							return;
-						}
-						final Jid contactJid;
-						try {
-							contactJid = Jid.fromString(jid.getText().toString());
-						} catch (final InvalidJidException e) {
-							jid.setError(getString(R.string.invalid_jid));
-							return;
-						}
-						final Account account = xmppConnectionService.findAccountByJid(accountJid);
-						if (account == null) {
-							dialog.dismiss();
-							return;
-						}
-						final Contact contact = account.getRoster().getContact(contactJid);
-						if (contact.showInRoster()) {
-							jid.setError(getString(R.string.contact_already_exists));
-						} else {
-							contact.addOtrFingerprint(fingerprint);
-							xmppConnectionService.createContact(contact);
-							dialog.dismiss();
-							switchToConversation(contact);
-						}
-					}
-				});
+		dialog.setOnEnterJidDialogPositiveListener(new EnterJidDialog.OnEnterJidDialogPositiveListener() {
+			@Override
+			public boolean onEnterJidDialogPositive(Jid accountJid, Jid contactJid) throws EnterJidDialog.JidError {
+				if (!xmppConnectionServiceBound) {
+					return false;
+				}
+
+				final Account account = xmppConnectionService.findAccountByJid(accountJid);
+				if (account == null) {
+					return true;
+				}
 
+				final Contact contact = account.getRoster().getContact(contactJid);
+				if (contact.showInRoster()) {
+					throw new EnterJidDialog.JidError(getString(R.string.contact_already_exists));
+				} else {
+					contact.addOtrFingerprint(fingerprint);
+					xmppConnectionService.createContact(contact);
+					switchToConversation(contact);
+					return true;
+				}
+			}
+		});
+
+		dialog.show();
 	}
 
 	@SuppressLint("InflateParams")

src/main/java/eu/siacs/conversations/ui/XmppActivity.java 🔗

@@ -469,6 +469,8 @@ public abstract class XmppActivity extends Activity {
 		intent.putExtra("filter_contacts", contacts.toArray(new String[contacts.size()]));
 		intent.putExtra("conversation", conversation.getUuid());
 		intent.putExtra("multiple", true);
+		intent.putExtra("show_enter_jid", true);
+		intent.putExtra("account", conversation.getAccount().getJid().toBareJid().toString());
 		startActivityForResult(intent, REQUEST_INVITE_TO_CONVERSATION);
 	}
 

src/main/res/menu/choose_contact.xml 🔗

@@ -1,5 +1,5 @@
 <?xml version="1.0" encoding="utf-8"?>
-<menu xmlns:android="http://schemas.android.com/apk/res/android" >
+<menu xmlns:android="http://schemas.android.com/apk/res/android">
 
     <item
         android:id="@+id/action_search"
@@ -8,4 +8,10 @@
         android:showAsAction="collapseActionView|always"
         android:title="@string/search"/>
 
-</menu>
+    <item
+        android:id="@+id/action_create_contact"
+        android:icon="?attr/icon_add_person"
+        android:showAsAction="always"
+        android:title="@string/create_contact"
+        android:visible="false"/>
+</menu>

src/main/res/values/strings.xml 🔗

@@ -226,12 +226,14 @@
 	<string name="conferences">Conferences</string>
 	<string name="search">Search</string>
 	<string name="create_contact">Create Contact</string>
+	<string name="enter_contact">Enter Contact</string>
 	<string name="join_conference">Join Conference</string>
 	<string name="delete_contact">Delete Contact</string>
 	<string name="view_contact_details">View contact details</string>
 	<string name="block_contact">Block contact</string>
 	<string name="unblock_contact">Unblock contact</string>
 	<string name="create">Create</string>
+	<string name="select">Select</string>
 	<string name="contact_already_exists">The contact already exists</string>
 	<string name="join">Join</string>
 	<string name="conference_address">Conference address</string>