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