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