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}