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.EditText;
34import android.widget.ImageView;
35import android.widget.ListView;
36import android.widget.Spinner;
37import android.widget.TextView;
38import eu.siacs.conversations.R;
39import eu.siacs.conversations.entities.Account;
40import eu.siacs.conversations.entities.Bookmark;
41import eu.siacs.conversations.entities.Contact;
42import eu.siacs.conversations.entities.Conversation;
43import eu.siacs.conversations.entities.ListItem;
44import eu.siacs.conversations.utils.KnownHostsAdapter;
45import eu.siacs.conversations.utils.UIHelper;
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.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(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.findOrCreateConversation(bookmark.getAccount(), bookmark.getJid(), true);
224 switchToConversation(conversation);
225 }
226
227 protected void openDetailsForContact() {
228 int position = contact_context_id;
229 Contact contact = (Contact) contacts.get(position);
230 switchToContactDetails(contact);
231 }
232
233 protected void deleteContact() {
234 int position = contact_context_id;
235 Contact contact = (Contact) contacts.get(position);
236 xmppConnectionService.deleteContactOnServer(contact);
237 filter(mSearchEditText.getText().toString());
238 }
239
240 protected void showCreateContactDialog() {
241 AlertDialog.Builder builder = new AlertDialog.Builder(this);
242 builder.setTitle(R.string.create_contact);
243 View dialogView = getLayoutInflater().inflate(
244 R.layout.create_contact_dialog, null);
245 final Spinner spinner = (Spinner) dialogView.findViewById(R.id.account);
246 final AutoCompleteTextView jid = (AutoCompleteTextView) dialogView
247 .findViewById(R.id.jid);
248 jid.setAdapter(new KnownHostsAdapter(this,
249 android.R.layout.simple_list_item_1, mKnownHosts));
250 populateAccountSpinner(spinner);
251 builder.setView(dialogView);
252 builder.setNegativeButton(R.string.cancel, null);
253 builder.setPositiveButton(R.string.create, null);
254 final AlertDialog dialog = builder.create();
255 dialog.show();
256 dialog.getButton(AlertDialog.BUTTON_POSITIVE).setOnClickListener(
257 new View.OnClickListener() {
258
259 @Override
260 public void onClick(View v) {
261 if (Validator.isValidJid(jid.getText().toString())) {
262 String accountJid = (String) spinner
263 .getSelectedItem();
264 String contactJid = jid.getText().toString();
265 Account account = xmppConnectionService
266 .findAccountByJid(accountJid);
267 Contact contact = account.getRoster().getContact(
268 contactJid);
269 if (contact.showInRoster()) {
270 jid.setError(getString(R.string.contact_already_exists));
271 } else {
272 xmppConnectionService.createContact(contact);
273 switchToConversation(contact);
274 dialog.dismiss();
275 }
276 } else {
277 jid.setError(getString(R.string.invalid_jid));
278 }
279 }
280 });
281
282 }
283
284 protected void showJoinConferenceDialog() {
285 AlertDialog.Builder builder = new AlertDialog.Builder(this);
286 builder.setTitle(R.string.join_conference);
287 View dialogView = getLayoutInflater().inflate(
288 R.layout.join_conference_dialog, null);
289 final Spinner spinner = (Spinner) dialogView.findViewById(R.id.account);
290 final AutoCompleteTextView jid = (AutoCompleteTextView) dialogView
291 .findViewById(R.id.jid);
292 jid.setAdapter(new KnownHostsAdapter(this,
293 android.R.layout.simple_list_item_1, mKnownConferenceHosts));
294 populateAccountSpinner(spinner);
295 builder.setView(dialogView);
296 builder.setNegativeButton(R.string.cancel, null);
297 builder.setPositiveButton(R.string.join, null);
298 final AlertDialog dialog = builder.create();
299 dialog.show();
300 dialog.getButton(AlertDialog.BUTTON_POSITIVE).setOnClickListener(
301 new View.OnClickListener() {
302
303 @Override
304 public void onClick(View v) {
305 if (Validator.isValidJid(jid.getText().toString())) {
306 String accountJid = (String) spinner
307 .getSelectedItem();
308 String conferenceJid = jid.getText().toString();
309 Account account = xmppConnectionService
310 .findAccountByJid(accountJid);
311 Conversation conversation = xmppConnectionService
312 .findOrCreateConversation(account,
313 conferenceJid, true);
314 switchToConversation(conversation);
315 } else {
316 jid.setError(getString(R.string.invalid_jid));
317 }
318 }
319 });
320 }
321
322 protected void switchToConversation(Contact contact) {
323 Conversation conversation = xmppConnectionService
324 .findOrCreateConversation(contact.getAccount(),
325 contact.getJid(), false);
326 switchToConversation(conversation);
327 }
328
329 private void populateAccountSpinner(Spinner spinner) {
330 ArrayAdapter<String> adapter = new ArrayAdapter<String>(this,
331 android.R.layout.simple_spinner_item, mActivatedAccounts);
332 adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
333 spinner.setAdapter(adapter);
334 }
335
336 @Override
337 public boolean onCreateOptionsMenu(Menu menu) {
338 getMenuInflater().inflate(R.menu.start_conversation, menu);
339 MenuItem menuCreateContact = (MenuItem) menu
340 .findItem(R.id.action_create_contact);
341 MenuItem menuCreateConference = (MenuItem) menu
342 .findItem(R.id.action_join_conference);
343 MenuItem menuSearchView = (MenuItem) menu.findItem(R.id.action_search);
344 menuSearchView.setOnActionExpandListener(mOnActionExpandListener);
345 View mSearchView = menuSearchView.getActionView();
346 mSearchEditText = (EditText) mSearchView
347 .findViewById(R.id.search_field);
348 mSearchEditText.addTextChangedListener(mSearchTextWatcher);
349 if (getActionBar().getSelectedNavigationIndex() == 0) {
350 menuCreateConference.setVisible(false);
351 } else {
352 menuCreateContact.setVisible(false);
353 }
354 return true;
355 }
356
357 @Override
358 public boolean onOptionsItemSelected(MenuItem item) {
359 switch (item.getItemId()) {
360 case R.id.action_create_contact:
361 showCreateContactDialog();
362 break;
363 case R.id.action_join_conference:
364 showJoinConferenceDialog();
365 break;
366 }
367 return super.onOptionsItemSelected(item);
368 }
369
370 @Override
371 void onBackendConnected() {
372 if (mSearchEditText != null) {
373 filter(mSearchEditText.getText().toString());
374 } else {
375 filter(null);
376 }
377 this.mActivatedAccounts.clear();
378 for (Account account : xmppConnectionService.getAccounts()) {
379 if (account.getStatus() != Account.STATUS_DISABLED) {
380 this.mActivatedAccounts.add(account.getJid());
381 }
382 }
383 this.mKnownHosts = xmppConnectionService.getKnownHosts();
384 this.mKnownConferenceHosts = xmppConnectionService
385 .getKnownConferenceHosts();
386 }
387
388 protected void filter(String needle) {
389 this.filterContacts(needle);
390 this.filterConferences(needle);
391 }
392
393 protected void filterContacts(String needle) {
394 this.contacts.clear();
395 for (Account account : xmppConnectionService.getAccounts()) {
396 if (account.getStatus() != Account.STATUS_DISABLED) {
397 for (Contact contact : account.getRoster().getContacts()) {
398 if (contact.showInRoster() && contact.match(needle)) {
399 this.contacts.add(contact);
400 }
401 }
402 }
403 }
404 Collections.sort(this.contacts);
405 mContactsAdapter.notifyDataSetChanged();
406 }
407
408 protected void filterConferences(String needle) {
409 this.conferences.clear();
410 for (Account account : xmppConnectionService.getAccounts()) {
411 if (account.getStatus() != Account.STATUS_DISABLED) {
412 for(Bookmark bookmark : account.getBookmarks()) {
413 if (bookmark.match(needle)) {
414 this.conferences.add(bookmark);
415 }
416 }
417 }
418 }
419 Collections.sort(this.conferences);
420 mConferenceAdapter.notifyDataSetChanged();
421 }
422
423 private void onTabChanged() {
424 invalidateOptionsMenu();
425 }
426
427 private class ListItemAdapter extends ArrayAdapter<ListItem> {
428
429 public ListItemAdapter(List<ListItem> objects) {
430 super(getApplicationContext(), 0, objects);
431 }
432
433 @Override
434 public View getView(int position, View view, ViewGroup parent) {
435 LayoutInflater inflater = (LayoutInflater) getSystemService(Context.LAYOUT_INFLATER_SERVICE);
436 ListItem item = getItem(position);
437 if (view == null) {
438 view = (View) inflater.inflate(R.layout.contact, null);
439 }
440 TextView name = (TextView) view
441 .findViewById(R.id.contact_display_name);
442 TextView jid = (TextView) view.findViewById(R.id.contact_jid);
443 ImageView picture = (ImageView) view
444 .findViewById(R.id.contact_photo);
445
446 jid.setText(item.getJid());
447 name.setText(item.getDisplayName());
448 picture.setImageBitmap(UIHelper.getContactPicture(item, 48,
449 this.getContext(), false));
450 return view;
451 }
452
453 }
454
455 public static class MyListFragment extends ListFragment {
456 private AdapterView.OnItemClickListener mOnItemClickListener;
457 private int mResContextMenu;
458
459 public void setContextMenu(int res) {
460 this.mResContextMenu = res;
461 }
462
463 @Override
464 public void onListItemClick(ListView l, View v, int position, long id) {
465 if (mOnItemClickListener != null) {
466 mOnItemClickListener.onItemClick(l, v, position, id);
467 }
468 }
469
470 public void setOnListItemClickListener(AdapterView.OnItemClickListener l) {
471 this.mOnItemClickListener = l;
472 }
473
474 @Override
475 public void onViewCreated(View view, Bundle savedInstanceState) {
476 super.onViewCreated(view, savedInstanceState);
477 registerForContextMenu(getListView());
478 }
479
480 @Override
481 public void onCreateContextMenu(ContextMenu menu, View v,
482 ContextMenuInfo menuInfo) {
483 super.onCreateContextMenu(menu, v, menuInfo);
484 StartConversation activity = (StartConversation) getActivity();
485 activity.getMenuInflater().inflate(mResContextMenu,
486 menu);
487 AdapterView.AdapterContextMenuInfo acmi = (AdapterContextMenuInfo) menuInfo;
488 if (mResContextMenu == R.menu.conference_context) {
489 activity.conference_context_id = acmi.position;
490 } else {
491 activity.contact_context_id = acmi.position;
492 }
493 }
494
495 @Override
496 public boolean onContextItemSelected(MenuItem item) {
497 StartConversation activity = (StartConversation) getActivity();
498 switch (item.getItemId()) {
499 case R.id.context_start_conversation:
500 activity.openConversationForContact();
501 break;
502 case R.id.context_contact_details:
503 activity.openDetailsForContact();
504 break;
505 case R.id.context_delete_contact:
506 activity.deleteContact();
507 break;
508 case R.id.context_join_conference:
509 activity.openConversationForBookmark();
510 break;
511 }
512 return true;
513 }
514 }
515}