StartConversation.java

  1package eu.siacs.conversations.ui;
  2
  3import java.util.ArrayList;
  4import java.util.Collections;
  5import java.util.List;
  6
  7import android.app.ActionBar;
  8import android.app.ActionBar.Tab;
  9import android.app.ActionBar.TabListener;
 10import android.app.AlertDialog;
 11import android.app.Fragment;
 12import android.app.FragmentTransaction;
 13import android.app.ListFragment;
 14import android.content.Context;
 15import android.os.Bundle;
 16import android.support.v13.app.FragmentPagerAdapter;
 17import android.support.v4.view.ViewPager;
 18import android.text.Editable;
 19import android.text.TextWatcher;
 20import android.view.ContextMenu;
 21import android.view.ContextMenu.ContextMenuInfo;
 22import android.view.LayoutInflater;
 23import android.view.Menu;
 24import android.view.MenuItem;
 25import android.view.View;
 26import android.view.ViewGroup;
 27import android.view.inputmethod.InputMethodManager;
 28import android.widget.AdapterView;
 29import android.widget.AdapterView.AdapterContextMenuInfo;
 30import android.widget.AdapterView.OnItemClickListener;
 31import android.widget.ArrayAdapter;
 32import android.widget.AutoCompleteTextView;
 33import android.widget.EditText;
 34import android.widget.ImageView;
 35import android.widget.ListView;
 36import android.widget.Spinner;
 37import android.widget.TextView;
 38import eu.siacs.conversations.R;
 39import eu.siacs.conversations.entities.Account;
 40import eu.siacs.conversations.entities.Contact;
 41import eu.siacs.conversations.entities.Conversation;
 42import eu.siacs.conversations.entities.ListItem;
 43import eu.siacs.conversations.utils.KnownHostsAdapter;
 44import eu.siacs.conversations.utils.UIHelper;
 45import eu.siacs.conversations.utils.Validator;
 46
 47public class StartConversation extends XmppActivity {
 48
 49	private Tab mContactsTab;
 50	private Tab mConferencesTab;
 51	private ViewPager mViewPager;
 52
 53	private MyListFragment mContactsListFragment = new MyListFragment();
 54	private List<ListItem> contacts = new ArrayList<ListItem>();
 55	private ArrayAdapter<ListItem> mContactsAdapter;
 56
 57	private MyListFragment mConferenceListFragment = new MyListFragment();
 58	private List<ListItem> conferences = new ArrayList<ListItem>();
 59	private ArrayAdapter<ListItem> mConferenceAdapter;
 60
 61	private List<String> mActivatedAccounts = new ArrayList<String>();
 62	private List<String> mKnownHosts;
 63	private List<String> mKnownConferenceHosts;
 64
 65	private EditText mSearchEditText;
 66
 67	private TabListener mTabListener = new TabListener() {
 68
 69		@Override
 70		public void onTabUnselected(Tab tab, FragmentTransaction ft) {
 71			return;
 72		}
 73
 74		@Override
 75		public void onTabSelected(Tab tab, FragmentTransaction ft) {
 76			mViewPager.setCurrentItem(tab.getPosition());
 77			onTabChanged();
 78		}
 79
 80		@Override
 81		public void onTabReselected(Tab tab, FragmentTransaction ft) {
 82			return;
 83		}
 84	};
 85
 86	private ViewPager.SimpleOnPageChangeListener mOnPageChangeListener = new ViewPager.SimpleOnPageChangeListener() {
 87		@Override
 88		public void onPageSelected(int position) {
 89			getActionBar().setSelectedNavigationItem(position);
 90			onTabChanged();
 91		}
 92	};
 93
 94	private MenuItem.OnActionExpandListener mOnActionExpandListener = new MenuItem.OnActionExpandListener() {
 95
 96		@Override
 97		public boolean onMenuItemActionExpand(MenuItem item) {
 98			mSearchEditText.post(new Runnable() {
 99
100				@Override
101				public void run() {
102					mSearchEditText.requestFocus();
103					InputMethodManager imm = (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE);
104					imm.showSoftInput(mSearchEditText,
105							InputMethodManager.SHOW_IMPLICIT);
106				}
107			});
108
109			return true;
110		}
111
112		@Override
113		public boolean onMenuItemActionCollapse(MenuItem item) {
114			InputMethodManager imm = (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE);
115			imm.hideSoftInputFromWindow(mSearchEditText.getWindowToken(),
116					InputMethodManager.HIDE_IMPLICIT_ONLY);
117			mSearchEditText.setText("");
118			filterContacts(null);
119			return true;
120		}
121	};
122	private TextWatcher mSearchTextWatcher = new TextWatcher() {
123
124		@Override
125		public void afterTextChanged(Editable editable) {
126			filterContacts(editable.toString());
127		}
128
129		@Override
130		public void beforeTextChanged(CharSequence s, int start, int count,
131				int after) {
132		}
133
134		@Override
135		public void onTextChanged(CharSequence s, int start, int before,
136				int count) {
137		}
138	};
139
140	@Override
141	public void onCreate(Bundle savedInstanceState) {
142		super.onCreate(savedInstanceState);
143		setContentView(R.layout.activity_start_conversation);
144		mViewPager = (ViewPager) findViewById(R.id.start_conversation_view_pager);
145		ActionBar actionBar = getActionBar();
146		actionBar.setNavigationMode(ActionBar.NAVIGATION_MODE_TABS);
147
148		mContactsTab = actionBar.newTab().setText(R.string.contacts)
149				.setTabListener(mTabListener);
150		mConferencesTab = actionBar.newTab().setText(R.string.conferences)
151				.setTabListener(mTabListener);
152		actionBar.addTab(mContactsTab);
153		actionBar.addTab(mConferencesTab);
154
155		mViewPager.setOnPageChangeListener(mOnPageChangeListener);
156		mViewPager.setAdapter(new FragmentPagerAdapter(getFragmentManager()) {
157
158			@Override
159			public int getCount() {
160				return 2;
161			}
162
163			@Override
164			public Fragment getItem(int position) {
165				if (position == 0) {
166					return mContactsListFragment;
167				} else {
168					return mConferenceListFragment;
169				}
170			}
171		});
172
173		mConferenceAdapter = new ListItemAdapter(conferences);
174		mConferenceListFragment.setListAdapter(mConferenceAdapter);
175
176		mContactsAdapter = new ListItemAdapter(contacts);
177		mContactsListFragment.setListAdapter(mContactsAdapter);
178		mContactsListFragment
179				.setOnListItemClickListener(new OnItemClickListener() {
180
181					@Override
182					public void onItemClick(AdapterView<?> arg0, View arg1,
183							int position, long arg3) {
184						openConversationForContact(position);
185					}
186				});
187
188	}
189
190	protected void openConversationForContact(int position) {
191		Contact contact = (Contact) contacts.get(position);
192		Conversation conversation = xmppConnectionService
193				.findOrCreateConversation(contact.getAccount(),
194						contact.getJid(), false);
195		switchToConversation(conversation, null, false);
196	}
197
198	protected void openDetailsForContact(int position) {
199		Contact contact = (Contact) contacts.get(position);
200		switchToContactDetails(contact);
201	}
202
203	protected void deleteContact(int position) {
204		Contact contact = (Contact) contacts.get(position);
205		xmppConnectionService.deleteContactOnServer(contact);
206		filterContacts(mSearchEditText.getText().toString());
207	}
208
209	protected void showCreateContactDialog() {
210		AlertDialog.Builder builder = new AlertDialog.Builder(this);
211		builder.setTitle(R.string.create_contact);
212		View dialogView = getLayoutInflater().inflate(
213				R.layout.create_contact_dialog, null);
214		final Spinner spinner = (Spinner) dialogView.findViewById(R.id.account);
215		final AutoCompleteTextView jid = (AutoCompleteTextView) dialogView
216				.findViewById(R.id.jid);
217		jid.setAdapter(new KnownHostsAdapter(this,
218				android.R.layout.simple_list_item_1, mKnownHosts));
219		populateAccountSpinner(spinner);
220		builder.setView(dialogView);
221		builder.setNegativeButton(R.string.cancel, null);
222		builder.setPositiveButton(R.string.create, null);
223		final AlertDialog dialog = builder.create();
224		dialog.show();
225		dialog.getButton(AlertDialog.BUTTON_POSITIVE).setOnClickListener(
226				new View.OnClickListener() {
227
228					@Override
229					public void onClick(View v) {
230						if (Validator.isValidJid(jid.getText().toString())) {
231							String accountJid = (String) spinner
232									.getSelectedItem();
233							String contactJid = jid.getText().toString();
234							Account account = xmppConnectionService
235									.findAccountByJid(accountJid);
236							Contact contact = account.getRoster().getContact(
237									contactJid);
238							if (contact.showInRoster()) {
239								jid.setError(getString(R.string.contact_already_exists));
240							} else {
241								xmppConnectionService.createContact(contact);
242								switchToConversation(contact);
243								dialog.dismiss();
244							}
245						} else {
246							jid.setError(getString(R.string.invalid_jid));
247						}
248					}
249				});
250
251	}
252
253	protected void showJoinConferenceDialog() {
254		AlertDialog.Builder builder = new AlertDialog.Builder(this);
255		builder.setTitle(R.string.join_conference);
256		View dialogView = getLayoutInflater().inflate(
257				R.layout.join_conference_dialog, null);
258		final Spinner spinner = (Spinner) dialogView.findViewById(R.id.account);
259		final AutoCompleteTextView jid = (AutoCompleteTextView) dialogView
260				.findViewById(R.id.jid);
261		jid.setAdapter(new KnownHostsAdapter(this,
262				android.R.layout.simple_list_item_1, mKnownConferenceHosts));
263		populateAccountSpinner(spinner);
264		builder.setView(dialogView);
265		builder.setNegativeButton(R.string.cancel, null);
266		builder.setPositiveButton(R.string.join, null);
267		final AlertDialog dialog = builder.create();
268		dialog.show();
269		dialog.getButton(AlertDialog.BUTTON_POSITIVE).setOnClickListener(
270				new View.OnClickListener() {
271
272					@Override
273					public void onClick(View v) {
274						if (Validator.isValidJid(jid.getText().toString())) {
275							String accountJid = (String) spinner
276									.getSelectedItem();
277							String conferenceJid = jid.getText().toString();
278							Account account = xmppConnectionService
279									.findAccountByJid(accountJid);
280							Conversation conversation = xmppConnectionService
281									.findOrCreateConversation(account,
282											conferenceJid, true);
283							switchToConversation(conversation);
284						} else {
285							jid.setError(getString(R.string.invalid_jid));
286						}
287					}
288				});
289	}
290
291	protected void switchToConversation(Contact contact) {
292		Conversation conversation = xmppConnectionService
293				.findOrCreateConversation(contact.getAccount(),
294						contact.getJid(), false);
295		switchToConversation(conversation);
296	}
297
298	private void populateAccountSpinner(Spinner spinner) {
299		ArrayAdapter<String> adapter = new ArrayAdapter<String>(this,
300				android.R.layout.simple_spinner_item, mActivatedAccounts);
301		adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
302		spinner.setAdapter(adapter);
303	}
304
305	@Override
306	public boolean onCreateOptionsMenu(Menu menu) {
307		getMenuInflater().inflate(R.menu.start_conversation, menu);
308		MenuItem menuCreateContact = (MenuItem) menu
309				.findItem(R.id.action_create_contact);
310		MenuItem menuCreateConference = (MenuItem) menu
311				.findItem(R.id.action_join_conference);
312		MenuItem menuSearchView = (MenuItem) menu.findItem(R.id.action_search);
313		menuSearchView.setOnActionExpandListener(mOnActionExpandListener);
314		View mSearchView = menuSearchView.getActionView();
315		mSearchEditText = (EditText) mSearchView
316				.findViewById(R.id.search_field);
317		mSearchEditText.addTextChangedListener(mSearchTextWatcher);
318		if (getActionBar().getSelectedNavigationIndex() == 0) {
319			menuCreateConference.setVisible(false);
320		} else {
321			menuCreateContact.setVisible(false);
322		}
323		return true;
324	}
325
326	@Override
327	public boolean onOptionsItemSelected(MenuItem item) {
328		switch (item.getItemId()) {
329		case R.id.action_create_contact:
330			showCreateContactDialog();
331			break;
332		case R.id.action_join_conference:
333			showJoinConferenceDialog();
334			break;
335		}
336		return super.onOptionsItemSelected(item);
337	}
338
339	@Override
340	void onBackendConnected() {
341		if (mSearchEditText != null) {
342			filterContacts(mSearchEditText.getText().toString());
343		} else {
344			filterContacts(null);
345		}
346		this.mActivatedAccounts.clear();
347		for (Account account : xmppConnectionService.getAccounts()) {
348			if (account.getStatus() != Account.STATUS_DISABLED) {
349				this.mActivatedAccounts.add(account.getJid());
350			}
351		}
352		this.mKnownHosts = xmppConnectionService.getKnownHosts();
353		this.mKnownConferenceHosts = xmppConnectionService
354				.getKnownConferenceHosts();
355	}
356
357	protected void filterContacts(String needle) {
358		this.contacts.clear();
359		for (Account account : xmppConnectionService.getAccounts()) {
360			if (account.getStatus() != Account.STATUS_DISABLED) {
361				for (Contact contact : account.getRoster().getContacts()) {
362					if (contact.showInRoster() && contact.match(needle)) {
363						this.contacts.add(contact);
364					}
365				}
366			}
367		}
368		Collections.sort(this.contacts);
369		mContactsAdapter.notifyDataSetChanged();
370	}
371
372	private void onTabChanged() {
373		invalidateOptionsMenu();
374	}
375
376	private class ListItemAdapter extends ArrayAdapter<ListItem> {
377
378		public ListItemAdapter(List<ListItem> objects) {
379			super(getApplicationContext(), 0, objects);
380		}
381
382		@Override
383		public View getView(int position, View view, ViewGroup parent) {
384			LayoutInflater inflater = (LayoutInflater) getSystemService(Context.LAYOUT_INFLATER_SERVICE);
385			ListItem item = getItem(position);
386			if (view == null) {
387				view = (View) inflater.inflate(R.layout.contact, null);
388			}
389			TextView name = (TextView) view
390					.findViewById(R.id.contact_display_name);
391			TextView jid = (TextView) view.findViewById(R.id.contact_jid);
392			ImageView picture = (ImageView) view
393					.findViewById(R.id.contact_photo);
394
395			jid.setText(item.getJid());
396			name.setText(item.getDisplayName());
397			picture.setImageBitmap(UIHelper.getContactPicture(item, 48,
398					this.getContext(), false));
399			return view;
400		}
401
402	}
403
404	public static class MyListFragment extends ListFragment {
405		private AdapterView.OnItemClickListener mOnItemClickListener;
406		private int mContextPosition = -1;
407
408		@Override
409		public void onListItemClick(ListView l, View v, int position, long id) {
410			if (mOnItemClickListener != null) {
411				mOnItemClickListener.onItemClick(l, v, position, id);
412			}
413		}
414
415		public void setOnListItemClickListener(AdapterView.OnItemClickListener l) {
416			this.mOnItemClickListener = l;
417		}
418
419		@Override
420		public void onViewCreated(View view, Bundle savedInstanceState) {
421			super.onViewCreated(view, savedInstanceState);
422			registerForContextMenu(getListView());
423		}
424
425		@Override
426		public void onCreateContextMenu(ContextMenu menu, View v,
427				ContextMenuInfo menuInfo) {
428			super.onCreateContextMenu(menu, v, menuInfo);
429			getActivity().getMenuInflater().inflate(R.menu.contact_context,
430					menu);
431			AdapterView.AdapterContextMenuInfo acmi = (AdapterContextMenuInfo) menuInfo;
432			this.mContextPosition = acmi.position;
433		}
434
435		@Override
436		public boolean onContextItemSelected(MenuItem item) {
437			StartConversation activity = (StartConversation) getActivity();
438			switch (item.getItemId()) {
439			case R.id.context_start_conversation:
440				activity.openConversationForContact(mContextPosition);
441				break;
442			case R.id.context_contact_details:
443				activity.openDetailsForContact(mContextPosition);
444				break;
445			case R.id.context_delete_contact:
446				activity.deleteContact(mContextPosition);
447				break;
448			}
449			return true;
450		}
451	}
452}