StartConversationActivity.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.content.DialogInterface;
 16import android.content.DialogInterface.OnClickListener;
 17import android.os.Bundle;
 18import android.support.v13.app.FragmentPagerAdapter;
 19import android.support.v4.view.ViewPager;
 20import android.text.Editable;
 21import android.text.TextWatcher;
 22import android.view.ContextMenu;
 23import android.view.ContextMenu.ContextMenuInfo;
 24import android.view.Menu;
 25import android.view.MenuItem;
 26import android.view.View;
 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.CheckBox;
 34import android.widget.EditText;
 35import android.widget.ListView;
 36import android.widget.Spinner;
 37import eu.siacs.conversations.R;
 38import eu.siacs.conversations.entities.Account;
 39import eu.siacs.conversations.entities.Bookmark;
 40import eu.siacs.conversations.entities.Contact;
 41import eu.siacs.conversations.entities.Conversation;
 42import eu.siacs.conversations.entities.ListItem;
 43import eu.siacs.conversations.ui.adapter.KnownHostsAdapter;
 44import eu.siacs.conversations.ui.adapter.ListItemAdapter;
 45import eu.siacs.conversations.utils.Validator;
 46
 47public class StartConversationActivity 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	public int conference_context_id;
 68	public int contact_context_id;
 69
 70	private TabListener mTabListener = new TabListener() {
 71
 72		@Override
 73		public void onTabUnselected(Tab tab, FragmentTransaction ft) {
 74			return;
 75		}
 76
 77		@Override
 78		public void onTabSelected(Tab tab, FragmentTransaction ft) {
 79			mViewPager.setCurrentItem(tab.getPosition());
 80			onTabChanged();
 81		}
 82
 83		@Override
 84		public void onTabReselected(Tab tab, FragmentTransaction ft) {
 85			return;
 86		}
 87	};
 88
 89	private ViewPager.SimpleOnPageChangeListener mOnPageChangeListener = new ViewPager.SimpleOnPageChangeListener() {
 90		@Override
 91		public void onPageSelected(int position) {
 92			getActionBar().setSelectedNavigationItem(position);
 93			onTabChanged();
 94		}
 95	};
 96
 97	private MenuItem.OnActionExpandListener mOnActionExpandListener = new MenuItem.OnActionExpandListener() {
 98
 99		@Override
100		public boolean onMenuItemActionExpand(MenuItem item) {
101			mSearchEditText.post(new Runnable() {
102
103				@Override
104				public void run() {
105					mSearchEditText.requestFocus();
106					InputMethodManager imm = (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE);
107					imm.showSoftInput(mSearchEditText,
108							InputMethodManager.SHOW_IMPLICIT);
109				}
110			});
111
112			return true;
113		}
114
115		@Override
116		public boolean onMenuItemActionCollapse(MenuItem item) {
117			InputMethodManager imm = (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE);
118			imm.hideSoftInputFromWindow(mSearchEditText.getWindowToken(),
119					InputMethodManager.HIDE_IMPLICIT_ONLY);
120			mSearchEditText.setText("");
121			filter(null);
122			return true;
123		}
124	};
125	private TextWatcher mSearchTextWatcher = new TextWatcher() {
126
127		@Override
128		public void afterTextChanged(Editable editable) {
129			filter(editable.toString());
130		}
131
132		@Override
133		public void beforeTextChanged(CharSequence s, int start, int count,
134				int after) {
135		}
136
137		@Override
138		public void onTextChanged(CharSequence s, int start, int before,
139				int count) {
140		}
141	};
142
143	@Override
144	public void onCreate(Bundle savedInstanceState) {
145		super.onCreate(savedInstanceState);
146		setContentView(R.layout.activity_start_conversation);
147		mViewPager = (ViewPager) findViewById(R.id.start_conversation_view_pager);
148		ActionBar actionBar = getActionBar();
149		actionBar.setNavigationMode(ActionBar.NAVIGATION_MODE_TABS);
150
151		mContactsTab = actionBar.newTab().setText(R.string.contacts)
152				.setTabListener(mTabListener);
153		mConferencesTab = actionBar.newTab().setText(R.string.conferences)
154				.setTabListener(mTabListener);
155		actionBar.addTab(mContactsTab);
156		actionBar.addTab(mConferencesTab);
157
158		mViewPager.setOnPageChangeListener(mOnPageChangeListener);
159		mViewPager.setAdapter(new FragmentPagerAdapter(getFragmentManager()) {
160
161			@Override
162			public int getCount() {
163				return 2;
164			}
165
166			@Override
167			public Fragment getItem(int position) {
168				if (position == 0) {
169					return mContactsListFragment;
170				} else {
171					return mConferenceListFragment;
172				}
173			}
174		});
175
176		mConferenceAdapter = new ListItemAdapter(getApplicationContext(),conferences);
177		mConferenceListFragment.setListAdapter(mConferenceAdapter);
178		mConferenceListFragment.setContextMenu(R.menu.conference_context);
179		mConferenceListFragment
180				.setOnListItemClickListener(new OnItemClickListener() {
181
182					@Override
183					public void onItemClick(AdapterView<?> arg0, View arg1,
184							int position, long arg3) {
185						openConversationForBookmark(position);
186					}
187				});
188
189		mContactsAdapter = new ListItemAdapter(getApplicationContext(),contacts);
190		mContactsListFragment.setListAdapter(mContactsAdapter);
191		mContactsListFragment.setContextMenu(R.menu.contact_context);
192		mContactsListFragment
193				.setOnListItemClickListener(new OnItemClickListener() {
194
195					@Override
196					public void onItemClick(AdapterView<?> arg0, View arg1,
197							int position, long arg3) {
198						openConversationForContact(position);
199					}
200				});
201
202	}
203
204	protected void openConversationForContact(int position) {
205		Contact contact = (Contact) contacts.get(position);
206		Conversation conversation = xmppConnectionService
207				.findOrCreateConversation(contact.getAccount(),
208						contact.getJid(), false);
209		switchToConversation(conversation);
210	}
211
212	protected void openConversationForContact() {
213		int position = contact_context_id;
214		openConversationForContact(position);
215	}
216
217	protected void openConversationForBookmark() {
218		openConversationForBookmark(conference_context_id);
219	}
220
221	protected void openConversationForBookmark(int position) {
222		Bookmark bookmark = (Bookmark) conferences.get(position);
223		Conversation conversation = xmppConnectionService
224				.findOrCreateConversation(bookmark.getAccount(),
225						bookmark.getJid(), true);
226		conversation.setBookmark(bookmark);
227		if (!conversation.getMucOptions().online()) {
228			xmppConnectionService.joinMuc(conversation);
229		}
230		if (!bookmark.autojoin()) {
231			bookmark.setAutojoin(true);
232			xmppConnectionService.pushBookmarks(bookmark.getAccount());
233		}
234		switchToConversation(conversation);
235	}
236
237	protected void openDetailsForContact() {
238		int position = contact_context_id;
239		Contact contact = (Contact) contacts.get(position);
240		switchToContactDetails(contact);
241	}
242
243	protected void deleteContact() {
244		int position = contact_context_id;
245		final Contact contact = (Contact) contacts.get(position);
246		AlertDialog.Builder builder = new AlertDialog.Builder(this);
247		builder.setNegativeButton(R.string.cancel, null);
248		builder.setTitle(R.string.action_delete_contact);
249		builder.setMessage(
250				getString(R.string.remove_contact_text,
251						contact.getJid()));
252		builder.setPositiveButton(R.string.delete,new OnClickListener() {
253			
254			@Override
255			public void onClick(DialogInterface dialog, int which) {
256				xmppConnectionService.deleteContactOnServer(contact);
257				filter(mSearchEditText.getText().toString());
258			}
259		});
260		builder.create().show();
261		
262	}
263
264	protected void deleteConference() {
265		int position = conference_context_id;
266		final Bookmark bookmark = (Bookmark) conferences.get(position);
267		
268		AlertDialog.Builder builder = new AlertDialog.Builder(this);
269		builder.setNegativeButton(R.string.cancel, null);
270		builder.setTitle(R.string.delete_bookmark);
271		builder.setMessage(
272				getString(R.string.remove_bookmark_text,
273						bookmark.getJid()));
274		builder.setPositiveButton(R.string.delete,new OnClickListener() {
275			
276			@Override
277			public void onClick(DialogInterface dialog, int which) {
278				bookmark.unregisterConversation();
279				Account account = bookmark.getAccount();
280				account.getBookmarks().remove(bookmark);
281				xmppConnectionService.pushBookmarks(account);
282				filter(mSearchEditText.getText().toString());
283			}
284		});
285		builder.create().show();
286		
287	}
288
289	protected void showCreateContactDialog() {
290		AlertDialog.Builder builder = new AlertDialog.Builder(this);
291		builder.setTitle(R.string.create_contact);
292		View dialogView = getLayoutInflater().inflate(
293				R.layout.create_contact_dialog, null);
294		final Spinner spinner = (Spinner) dialogView.findViewById(R.id.account);
295		final AutoCompleteTextView jid = (AutoCompleteTextView) dialogView
296				.findViewById(R.id.jid);
297		jid.setAdapter(new KnownHostsAdapter(this,
298				android.R.layout.simple_list_item_1, mKnownHosts));
299		populateAccountSpinner(spinner);
300		builder.setView(dialogView);
301		builder.setNegativeButton(R.string.cancel, null);
302		builder.setPositiveButton(R.string.create, null);
303		final AlertDialog dialog = builder.create();
304		dialog.show();
305		dialog.getButton(AlertDialog.BUTTON_POSITIVE).setOnClickListener(
306				new View.OnClickListener() {
307
308					@Override
309					public void onClick(View v) {
310						if (Validator.isValidJid(jid.getText().toString())) {
311							String accountJid = (String) spinner
312									.getSelectedItem();
313							String contactJid = jid.getText().toString();
314							Account account = xmppConnectionService
315									.findAccountByJid(accountJid);
316							Contact contact = account.getRoster().getContact(
317									contactJid);
318							if (contact.showInRoster()) {
319								jid.setError(getString(R.string.contact_already_exists));
320							} else {
321								xmppConnectionService.createContact(contact);
322								switchToConversation(contact);
323								dialog.dismiss();
324							}
325						} else {
326							jid.setError(getString(R.string.invalid_jid));
327						}
328					}
329				});
330
331	}
332
333	protected void showJoinConferenceDialog() {
334		AlertDialog.Builder builder = new AlertDialog.Builder(this);
335		builder.setTitle(R.string.join_conference);
336		View dialogView = getLayoutInflater().inflate(
337				R.layout.join_conference_dialog, null);
338		final Spinner spinner = (Spinner) dialogView.findViewById(R.id.account);
339		final AutoCompleteTextView jid = (AutoCompleteTextView) dialogView
340				.findViewById(R.id.jid);
341		jid.setAdapter(new KnownHostsAdapter(this,
342				android.R.layout.simple_list_item_1, mKnownConferenceHosts));
343		populateAccountSpinner(spinner);
344		final CheckBox bookmarkCheckBox = (CheckBox) dialogView
345				.findViewById(R.id.bookmark);
346		builder.setView(dialogView);
347		builder.setNegativeButton(R.string.cancel, null);
348		builder.setPositiveButton(R.string.join, null);
349		final AlertDialog dialog = builder.create();
350		dialog.show();
351		dialog.getButton(AlertDialog.BUTTON_POSITIVE).setOnClickListener(
352				new View.OnClickListener() {
353
354					@Override
355					public void onClick(View v) {
356						if (Validator.isValidJid(jid.getText().toString())) {
357							String accountJid = (String) spinner
358									.getSelectedItem();
359							String conferenceJid = jid.getText().toString();
360							Account account = xmppConnectionService
361									.findAccountByJid(accountJid);
362							if (bookmarkCheckBox.isChecked()) {
363								if (account.hasBookmarkFor(conferenceJid)) {
364									jid.setError(getString(R.string.bookmark_already_exists));
365								} else {
366									Bookmark bookmark = new Bookmark(account,
367											conferenceJid);
368									bookmark.setAutojoin(true);
369									account.getBookmarks().add(bookmark);
370									xmppConnectionService
371											.pushBookmarks(account);
372									Conversation conversation = xmppConnectionService
373											.findOrCreateConversation(account,
374													conferenceJid, true);
375									conversation.setBookmark(bookmark);
376									if (!conversation.getMucOptions().online()) {
377										xmppConnectionService.joinMuc(conversation);
378									}
379									switchToConversation(conversation);
380								}
381							} else {
382								Conversation conversation = xmppConnectionService
383										.findOrCreateConversation(account,
384												conferenceJid, true);
385								if (!conversation.getMucOptions().online()) {
386									xmppConnectionService.joinMuc(conversation);
387								}
388								switchToConversation(conversation);
389							}
390						} else {
391							jid.setError(getString(R.string.invalid_jid));
392						}
393					}
394				});
395	}
396
397	protected void switchToConversation(Contact contact) {
398		Conversation conversation = xmppConnectionService
399				.findOrCreateConversation(contact.getAccount(),
400						contact.getJid(), false);
401		switchToConversation(conversation);
402	}
403
404	private void populateAccountSpinner(Spinner spinner) {
405		ArrayAdapter<String> adapter = new ArrayAdapter<String>(this,
406				android.R.layout.simple_spinner_item, mActivatedAccounts);
407		adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
408		spinner.setAdapter(adapter);
409	}
410
411	@Override
412	public boolean onCreateOptionsMenu(Menu menu) {
413		getMenuInflater().inflate(R.menu.start_conversation, menu);
414		MenuItem menuCreateContact = (MenuItem) menu
415				.findItem(R.id.action_create_contact);
416		MenuItem menuCreateConference = (MenuItem) menu
417				.findItem(R.id.action_join_conference);
418		MenuItem menuSearchView = (MenuItem) menu.findItem(R.id.action_search);
419		menuSearchView.setOnActionExpandListener(mOnActionExpandListener);
420		View mSearchView = menuSearchView.getActionView();
421		mSearchEditText = (EditText) mSearchView
422				.findViewById(R.id.search_field);
423		mSearchEditText.addTextChangedListener(mSearchTextWatcher);
424		if (getActionBar().getSelectedNavigationIndex() == 0) {
425			menuCreateConference.setVisible(false);
426		} else {
427			menuCreateContact.setVisible(false);
428		}
429		return true;
430	}
431
432	@Override
433	public boolean onOptionsItemSelected(MenuItem item) {
434		switch (item.getItemId()) {
435		case R.id.action_create_contact:
436			showCreateContactDialog();
437			break;
438		case R.id.action_join_conference:
439			showJoinConferenceDialog();
440			break;
441		}
442		return super.onOptionsItemSelected(item);
443	}
444
445	@Override
446	void onBackendConnected() {
447		if (mSearchEditText != null) {
448			filter(mSearchEditText.getText().toString());
449		} else {
450			filter(null);
451		}
452		this.mActivatedAccounts.clear();
453		for (Account account : xmppConnectionService.getAccounts()) {
454			if (account.getStatus() != Account.STATUS_DISABLED) {
455				this.mActivatedAccounts.add(account.getJid());
456			}
457		}
458		this.mKnownHosts = xmppConnectionService.getKnownHosts();
459		this.mKnownConferenceHosts = xmppConnectionService
460				.getKnownConferenceHosts();
461	}
462
463	protected void filter(String needle) {
464		this.filterContacts(needle);
465		this.filterConferences(needle);
466	}
467
468	protected void filterContacts(String needle) {
469		this.contacts.clear();
470		for (Account account : xmppConnectionService.getAccounts()) {
471			if (account.getStatus() != Account.STATUS_DISABLED) {
472				for (Contact contact : account.getRoster().getContacts()) {
473					if (contact.showInRoster() && contact.match(needle)) {
474						this.contacts.add(contact);
475					}
476				}
477			}
478		}
479		Collections.sort(this.contacts);
480		mContactsAdapter.notifyDataSetChanged();
481	}
482
483	protected void filterConferences(String needle) {
484		this.conferences.clear();
485		for (Account account : xmppConnectionService.getAccounts()) {
486			if (account.getStatus() != Account.STATUS_DISABLED) {
487				for (Bookmark bookmark : account.getBookmarks()) {
488					if (bookmark.match(needle)) {
489						this.conferences.add(bookmark);
490					}
491				}
492			}
493		}
494		Collections.sort(this.conferences);
495		mConferenceAdapter.notifyDataSetChanged();
496	}
497
498	private void onTabChanged() {
499		invalidateOptionsMenu();
500	}
501
502	public static class MyListFragment extends ListFragment {
503		private AdapterView.OnItemClickListener mOnItemClickListener;
504		private int mResContextMenu;
505
506		public void setContextMenu(int res) {
507			this.mResContextMenu = res;
508		}
509
510		@Override
511		public void onListItemClick(ListView l, View v, int position, long id) {
512			if (mOnItemClickListener != null) {
513				mOnItemClickListener.onItemClick(l, v, position, id);
514			}
515		}
516
517		public void setOnListItemClickListener(AdapterView.OnItemClickListener l) {
518			this.mOnItemClickListener = l;
519		}
520
521		@Override
522		public void onViewCreated(View view, Bundle savedInstanceState) {
523			super.onViewCreated(view, savedInstanceState);
524			registerForContextMenu(getListView());
525		}
526
527		@Override
528		public void onCreateContextMenu(ContextMenu menu, View v,
529				ContextMenuInfo menuInfo) {
530			super.onCreateContextMenu(menu, v, menuInfo);
531			StartConversationActivity activity = (StartConversationActivity) getActivity();
532			activity.getMenuInflater().inflate(mResContextMenu, menu);
533			AdapterView.AdapterContextMenuInfo acmi = (AdapterContextMenuInfo) menuInfo;
534			if (mResContextMenu == R.menu.conference_context) {
535				activity.conference_context_id = acmi.position;
536			} else {
537				activity.contact_context_id = acmi.position;
538			}
539		}
540
541		@Override
542		public boolean onContextItemSelected(MenuItem item) {
543			StartConversationActivity activity = (StartConversationActivity) getActivity();
544			switch (item.getItemId()) {
545			case R.id.context_start_conversation:
546				activity.openConversationForContact();
547				break;
548			case R.id.context_contact_details:
549				activity.openDetailsForContact();
550				break;
551			case R.id.context_delete_contact:
552				activity.deleteContact();
553				break;
554			case R.id.context_join_conference:
555				activity.openConversationForBookmark();
556				break;
557			case R.id.context_delete_conference:
558				activity.deleteConference();
559			}
560			return true;
561		}
562	}
563}