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