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}