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