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 conversation.setBookmark(bookmark);
225 switchToConversation(conversation);
226 }
227
228 protected void openDetailsForContact() {
229 int position = contact_context_id;
230 Contact contact = (Contact) contacts.get(position);
231 switchToContactDetails(contact);
232 }
233
234 protected void deleteContact() {
235 int position = contact_context_id;
236 Contact contact = (Contact) contacts.get(position);
237 xmppConnectionService.deleteContactOnServer(contact);
238 filter(mSearchEditText.getText().toString());
239 }
240
241 protected void showCreateContactDialog() {
242 AlertDialog.Builder builder = new AlertDialog.Builder(this);
243 builder.setTitle(R.string.create_contact);
244 View dialogView = getLayoutInflater().inflate(
245 R.layout.create_contact_dialog, null);
246 final Spinner spinner = (Spinner) dialogView.findViewById(R.id.account);
247 final AutoCompleteTextView jid = (AutoCompleteTextView) dialogView
248 .findViewById(R.id.jid);
249 jid.setAdapter(new KnownHostsAdapter(this,
250 android.R.layout.simple_list_item_1, mKnownHosts));
251 populateAccountSpinner(spinner);
252 builder.setView(dialogView);
253 builder.setNegativeButton(R.string.cancel, null);
254 builder.setPositiveButton(R.string.create, null);
255 final AlertDialog dialog = builder.create();
256 dialog.show();
257 dialog.getButton(AlertDialog.BUTTON_POSITIVE).setOnClickListener(
258 new View.OnClickListener() {
259
260 @Override
261 public void onClick(View v) {
262 if (Validator.isValidJid(jid.getText().toString())) {
263 String accountJid = (String) spinner
264 .getSelectedItem();
265 String contactJid = jid.getText().toString();
266 Account account = xmppConnectionService
267 .findAccountByJid(accountJid);
268 Contact contact = account.getRoster().getContact(
269 contactJid);
270 if (contact.showInRoster()) {
271 jid.setError(getString(R.string.contact_already_exists));
272 } else {
273 xmppConnectionService.createContact(contact);
274 switchToConversation(contact);
275 dialog.dismiss();
276 }
277 } else {
278 jid.setError(getString(R.string.invalid_jid));
279 }
280 }
281 });
282
283 }
284
285 protected void showJoinConferenceDialog() {
286 AlertDialog.Builder builder = new AlertDialog.Builder(this);
287 builder.setTitle(R.string.join_conference);
288 View dialogView = getLayoutInflater().inflate(
289 R.layout.join_conference_dialog, null);
290 final Spinner spinner = (Spinner) dialogView.findViewById(R.id.account);
291 final AutoCompleteTextView jid = (AutoCompleteTextView) dialogView
292 .findViewById(R.id.jid);
293 jid.setAdapter(new KnownHostsAdapter(this,
294 android.R.layout.simple_list_item_1, mKnownConferenceHosts));
295 populateAccountSpinner(spinner);
296 builder.setView(dialogView);
297 builder.setNegativeButton(R.string.cancel, null);
298 builder.setPositiveButton(R.string.join, null);
299 final AlertDialog dialog = builder.create();
300 dialog.show();
301 dialog.getButton(AlertDialog.BUTTON_POSITIVE).setOnClickListener(
302 new View.OnClickListener() {
303
304 @Override
305 public void onClick(View v) {
306 if (Validator.isValidJid(jid.getText().toString())) {
307 String accountJid = (String) spinner
308 .getSelectedItem();
309 String conferenceJid = jid.getText().toString();
310 Account account = xmppConnectionService
311 .findAccountByJid(accountJid);
312 Conversation conversation = xmppConnectionService
313 .findOrCreateConversation(account,
314 conferenceJid, true);
315 switchToConversation(conversation);
316 } else {
317 jid.setError(getString(R.string.invalid_jid));
318 }
319 }
320 });
321 }
322
323 protected void switchToConversation(Contact contact) {
324 Conversation conversation = xmppConnectionService
325 .findOrCreateConversation(contact.getAccount(),
326 contact.getJid(), false);
327 switchToConversation(conversation);
328 }
329
330 private void populateAccountSpinner(Spinner spinner) {
331 ArrayAdapter<String> adapter = new ArrayAdapter<String>(this,
332 android.R.layout.simple_spinner_item, mActivatedAccounts);
333 adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
334 spinner.setAdapter(adapter);
335 }
336
337 @Override
338 public boolean onCreateOptionsMenu(Menu menu) {
339 getMenuInflater().inflate(R.menu.start_conversation, menu);
340 MenuItem menuCreateContact = (MenuItem) menu
341 .findItem(R.id.action_create_contact);
342 MenuItem menuCreateConference = (MenuItem) menu
343 .findItem(R.id.action_join_conference);
344 MenuItem menuSearchView = (MenuItem) menu.findItem(R.id.action_search);
345 menuSearchView.setOnActionExpandListener(mOnActionExpandListener);
346 View mSearchView = menuSearchView.getActionView();
347 mSearchEditText = (EditText) mSearchView
348 .findViewById(R.id.search_field);
349 mSearchEditText.addTextChangedListener(mSearchTextWatcher);
350 if (getActionBar().getSelectedNavigationIndex() == 0) {
351 menuCreateConference.setVisible(false);
352 } else {
353 menuCreateContact.setVisible(false);
354 }
355 return true;
356 }
357
358 @Override
359 public boolean onOptionsItemSelected(MenuItem item) {
360 switch (item.getItemId()) {
361 case R.id.action_create_contact:
362 showCreateContactDialog();
363 break;
364 case R.id.action_join_conference:
365 showJoinConferenceDialog();
366 break;
367 }
368 return super.onOptionsItemSelected(item);
369 }
370
371 @Override
372 void onBackendConnected() {
373 if (mSearchEditText != null) {
374 filter(mSearchEditText.getText().toString());
375 } else {
376 filter(null);
377 }
378 this.mActivatedAccounts.clear();
379 for (Account account : xmppConnectionService.getAccounts()) {
380 if (account.getStatus() != Account.STATUS_DISABLED) {
381 this.mActivatedAccounts.add(account.getJid());
382 }
383 }
384 this.mKnownHosts = xmppConnectionService.getKnownHosts();
385 this.mKnownConferenceHosts = xmppConnectionService
386 .getKnownConferenceHosts();
387 }
388
389 protected void filter(String needle) {
390 this.filterContacts(needle);
391 this.filterConferences(needle);
392 }
393
394 protected void filterContacts(String needle) {
395 this.contacts.clear();
396 for (Account account : xmppConnectionService.getAccounts()) {
397 if (account.getStatus() != Account.STATUS_DISABLED) {
398 for (Contact contact : account.getRoster().getContacts()) {
399 if (contact.showInRoster() && contact.match(needle)) {
400 this.contacts.add(contact);
401 }
402 }
403 }
404 }
405 Collections.sort(this.contacts);
406 mContactsAdapter.notifyDataSetChanged();
407 }
408
409 protected void filterConferences(String needle) {
410 this.conferences.clear();
411 for (Account account : xmppConnectionService.getAccounts()) {
412 if (account.getStatus() != Account.STATUS_DISABLED) {
413 for(Bookmark bookmark : account.getBookmarks()) {
414 if (bookmark.match(needle)) {
415 this.conferences.add(bookmark);
416 }
417 }
418 }
419 }
420 Collections.sort(this.conferences);
421 mConferenceAdapter.notifyDataSetChanged();
422 }
423
424 private void onTabChanged() {
425 invalidateOptionsMenu();
426 }
427
428 private class ListItemAdapter extends ArrayAdapter<ListItem> {
429
430 public ListItemAdapter(List<ListItem> objects) {
431 super(getApplicationContext(), 0, objects);
432 }
433
434 @Override
435 public View getView(int position, View view, ViewGroup parent) {
436 LayoutInflater inflater = (LayoutInflater) getSystemService(Context.LAYOUT_INFLATER_SERVICE);
437 ListItem item = getItem(position);
438 if (view == null) {
439 view = (View) inflater.inflate(R.layout.contact, null);
440 }
441 TextView name = (TextView) view
442 .findViewById(R.id.contact_display_name);
443 TextView jid = (TextView) view.findViewById(R.id.contact_jid);
444 ImageView picture = (ImageView) view
445 .findViewById(R.id.contact_photo);
446
447 jid.setText(item.getJid());
448 name.setText(item.getDisplayName());
449 picture.setImageBitmap(item.getImage(48, getApplicationContext()));
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}