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.Contact;
41import eu.siacs.conversations.entities.Conversation;
42import eu.siacs.conversations.entities.ListItem;
43import eu.siacs.conversations.utils.KnownHostsAdapter;
44import eu.siacs.conversations.utils.UIHelper;
45import eu.siacs.conversations.utils.Validator;
46
47public class StartConversation 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 private TabListener mTabListener = new TabListener() {
68
69 @Override
70 public void onTabUnselected(Tab tab, FragmentTransaction ft) {
71 return;
72 }
73
74 @Override
75 public void onTabSelected(Tab tab, FragmentTransaction ft) {
76 mViewPager.setCurrentItem(tab.getPosition());
77 onTabChanged();
78 }
79
80 @Override
81 public void onTabReselected(Tab tab, FragmentTransaction ft) {
82 return;
83 }
84 };
85
86 private ViewPager.SimpleOnPageChangeListener mOnPageChangeListener = new ViewPager.SimpleOnPageChangeListener() {
87 @Override
88 public void onPageSelected(int position) {
89 getActionBar().setSelectedNavigationItem(position);
90 onTabChanged();
91 }
92 };
93
94 private MenuItem.OnActionExpandListener mOnActionExpandListener = new MenuItem.OnActionExpandListener() {
95
96 @Override
97 public boolean onMenuItemActionExpand(MenuItem item) {
98 mSearchEditText.post(new Runnable() {
99
100 @Override
101 public void run() {
102 mSearchEditText.requestFocus();
103 InputMethodManager imm = (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE);
104 imm.showSoftInput(mSearchEditText,
105 InputMethodManager.SHOW_IMPLICIT);
106 }
107 });
108
109 return true;
110 }
111
112 @Override
113 public boolean onMenuItemActionCollapse(MenuItem item) {
114 InputMethodManager imm = (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE);
115 imm.hideSoftInputFromWindow(mSearchEditText.getWindowToken(),
116 InputMethodManager.HIDE_IMPLICIT_ONLY);
117 mSearchEditText.setText("");
118 filterContacts(null);
119 return true;
120 }
121 };
122 private TextWatcher mSearchTextWatcher = new TextWatcher() {
123
124 @Override
125 public void afterTextChanged(Editable editable) {
126 filterContacts(editable.toString());
127 }
128
129 @Override
130 public void beforeTextChanged(CharSequence s, int start, int count,
131 int after) {
132 }
133
134 @Override
135 public void onTextChanged(CharSequence s, int start, int before,
136 int count) {
137 }
138 };
139
140 @Override
141 public void onCreate(Bundle savedInstanceState) {
142 super.onCreate(savedInstanceState);
143 setContentView(R.layout.activity_start_conversation);
144 mViewPager = (ViewPager) findViewById(R.id.start_conversation_view_pager);
145 ActionBar actionBar = getActionBar();
146 actionBar.setNavigationMode(ActionBar.NAVIGATION_MODE_TABS);
147
148 mContactsTab = actionBar.newTab().setText(R.string.contacts)
149 .setTabListener(mTabListener);
150 mConferencesTab = actionBar.newTab().setText(R.string.conferences)
151 .setTabListener(mTabListener);
152 actionBar.addTab(mContactsTab);
153 actionBar.addTab(mConferencesTab);
154
155 mViewPager.setOnPageChangeListener(mOnPageChangeListener);
156 mViewPager.setAdapter(new FragmentPagerAdapter(getFragmentManager()) {
157
158 @Override
159 public int getCount() {
160 return 2;
161 }
162
163 @Override
164 public Fragment getItem(int position) {
165 if (position == 0) {
166 return mContactsListFragment;
167 } else {
168 return mConferenceListFragment;
169 }
170 }
171 });
172
173 mConferenceAdapter = new ListItemAdapter(conferences);
174 mConferenceListFragment.setListAdapter(mConferenceAdapter);
175
176 mContactsAdapter = new ListItemAdapter(contacts);
177 mContactsListFragment.setListAdapter(mContactsAdapter);
178 mContactsListFragment
179 .setOnListItemClickListener(new OnItemClickListener() {
180
181 @Override
182 public void onItemClick(AdapterView<?> arg0, View arg1,
183 int position, long arg3) {
184 openConversationForContact(position);
185 }
186 });
187
188 }
189
190 protected void openConversationForContact(int position) {
191 Contact contact = (Contact) contacts.get(position);
192 Conversation conversation = xmppConnectionService
193 .findOrCreateConversation(contact.getAccount(),
194 contact.getJid(), false);
195 switchToConversation(conversation, null, false);
196 }
197
198 protected void openDetailsForContact(int position) {
199 Contact contact = (Contact) contacts.get(position);
200 switchToContactDetails(contact);
201 }
202
203 protected void deleteContact(int position) {
204 Contact contact = (Contact) contacts.get(position);
205 xmppConnectionService.deleteContactOnServer(contact);
206 filterContacts(mSearchEditText.getText().toString());
207 }
208
209 protected void showCreateContactDialog() {
210 AlertDialog.Builder builder = new AlertDialog.Builder(this);
211 builder.setTitle(R.string.create_contact);
212 View dialogView = getLayoutInflater().inflate(
213 R.layout.create_contact_dialog, null);
214 final Spinner spinner = (Spinner) dialogView.findViewById(R.id.account);
215 final AutoCompleteTextView jid = (AutoCompleteTextView) dialogView
216 .findViewById(R.id.jid);
217 jid.setAdapter(new KnownHostsAdapter(this,
218 android.R.layout.simple_list_item_1, mKnownHosts));
219 populateAccountSpinner(spinner);
220 builder.setView(dialogView);
221 builder.setNegativeButton(R.string.cancel, null);
222 builder.setPositiveButton(R.string.create, null);
223 final AlertDialog dialog = builder.create();
224 dialog.show();
225 dialog.getButton(AlertDialog.BUTTON_POSITIVE).setOnClickListener(
226 new View.OnClickListener() {
227
228 @Override
229 public void onClick(View v) {
230 if (Validator.isValidJid(jid.getText().toString())) {
231 String accountJid = (String) spinner
232 .getSelectedItem();
233 String contactJid = jid.getText().toString();
234 Account account = xmppConnectionService
235 .findAccountByJid(accountJid);
236 Contact contact = account.getRoster().getContact(
237 contactJid);
238 if (contact.showInRoster()) {
239 jid.setError(getString(R.string.contact_already_exists));
240 } else {
241 xmppConnectionService.createContact(contact);
242 switchToConversation(contact);
243 dialog.dismiss();
244 }
245 } else {
246 jid.setError(getString(R.string.invalid_jid));
247 }
248 }
249 });
250
251 }
252
253 protected void showJoinConferenceDialog() {
254 AlertDialog.Builder builder = new AlertDialog.Builder(this);
255 builder.setTitle(R.string.join_conference);
256 View dialogView = getLayoutInflater().inflate(
257 R.layout.join_conference_dialog, null);
258 final Spinner spinner = (Spinner) dialogView.findViewById(R.id.account);
259 final AutoCompleteTextView jid = (AutoCompleteTextView) dialogView
260 .findViewById(R.id.jid);
261 jid.setAdapter(new KnownHostsAdapter(this,
262 android.R.layout.simple_list_item_1, mKnownConferenceHosts));
263 populateAccountSpinner(spinner);
264 builder.setView(dialogView);
265 builder.setNegativeButton(R.string.cancel, null);
266 builder.setPositiveButton(R.string.join, null);
267 final AlertDialog dialog = builder.create();
268 dialog.show();
269 dialog.getButton(AlertDialog.BUTTON_POSITIVE).setOnClickListener(
270 new View.OnClickListener() {
271
272 @Override
273 public void onClick(View v) {
274 if (Validator.isValidJid(jid.getText().toString())) {
275 String accountJid = (String) spinner
276 .getSelectedItem();
277 String conferenceJid = jid.getText().toString();
278 Account account = xmppConnectionService
279 .findAccountByJid(accountJid);
280 Conversation conversation = xmppConnectionService
281 .findOrCreateConversation(account,
282 conferenceJid, true);
283 switchToConversation(conversation);
284 } else {
285 jid.setError(getString(R.string.invalid_jid));
286 }
287 }
288 });
289 }
290
291 protected void switchToConversation(Contact contact) {
292 Conversation conversation = xmppConnectionService
293 .findOrCreateConversation(contact.getAccount(),
294 contact.getJid(), false);
295 switchToConversation(conversation);
296 }
297
298 private void populateAccountSpinner(Spinner spinner) {
299 ArrayAdapter<String> adapter = new ArrayAdapter<String>(this,
300 android.R.layout.simple_spinner_item, mActivatedAccounts);
301 adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
302 spinner.setAdapter(adapter);
303 }
304
305 @Override
306 public boolean onCreateOptionsMenu(Menu menu) {
307 getMenuInflater().inflate(R.menu.start_conversation, menu);
308 MenuItem menuCreateContact = (MenuItem) menu
309 .findItem(R.id.action_create_contact);
310 MenuItem menuCreateConference = (MenuItem) menu
311 .findItem(R.id.action_join_conference);
312 MenuItem menuSearchView = (MenuItem) menu.findItem(R.id.action_search);
313 menuSearchView.setOnActionExpandListener(mOnActionExpandListener);
314 View mSearchView = menuSearchView.getActionView();
315 mSearchEditText = (EditText) mSearchView
316 .findViewById(R.id.search_field);
317 mSearchEditText.addTextChangedListener(mSearchTextWatcher);
318 if (getActionBar().getSelectedNavigationIndex() == 0) {
319 menuCreateConference.setVisible(false);
320 } else {
321 menuCreateContact.setVisible(false);
322 }
323 return true;
324 }
325
326 @Override
327 public boolean onOptionsItemSelected(MenuItem item) {
328 switch (item.getItemId()) {
329 case R.id.action_create_contact:
330 showCreateContactDialog();
331 break;
332 case R.id.action_join_conference:
333 showJoinConferenceDialog();
334 break;
335 }
336 return super.onOptionsItemSelected(item);
337 }
338
339 @Override
340 void onBackendConnected() {
341 if (mSearchEditText != null) {
342 filterContacts(mSearchEditText.getText().toString());
343 } else {
344 filterContacts(null);
345 }
346 this.mActivatedAccounts.clear();
347 for (Account account : xmppConnectionService.getAccounts()) {
348 if (account.getStatus() != Account.STATUS_DISABLED) {
349 this.mActivatedAccounts.add(account.getJid());
350 }
351 }
352 this.mKnownHosts = xmppConnectionService.getKnownHosts();
353 this.mKnownConferenceHosts = xmppConnectionService
354 .getKnownConferenceHosts();
355 }
356
357 protected void filterContacts(String needle) {
358 this.contacts.clear();
359 for (Account account : xmppConnectionService.getAccounts()) {
360 if (account.getStatus() != Account.STATUS_DISABLED) {
361 for (Contact contact : account.getRoster().getContacts()) {
362 if (contact.showInRoster() && contact.match(needle)) {
363 this.contacts.add(contact);
364 }
365 }
366 }
367 }
368 Collections.sort(this.contacts);
369 mContactsAdapter.notifyDataSetChanged();
370 }
371
372 private void onTabChanged() {
373 invalidateOptionsMenu();
374 }
375
376 private class ListItemAdapter extends ArrayAdapter<ListItem> {
377
378 public ListItemAdapter(List<ListItem> objects) {
379 super(getApplicationContext(), 0, objects);
380 }
381
382 @Override
383 public View getView(int position, View view, ViewGroup parent) {
384 LayoutInflater inflater = (LayoutInflater) getSystemService(Context.LAYOUT_INFLATER_SERVICE);
385 ListItem item = getItem(position);
386 if (view == null) {
387 view = (View) inflater.inflate(R.layout.contact, null);
388 }
389 TextView name = (TextView) view
390 .findViewById(R.id.contact_display_name);
391 TextView jid = (TextView) view.findViewById(R.id.contact_jid);
392 ImageView picture = (ImageView) view
393 .findViewById(R.id.contact_photo);
394
395 jid.setText(item.getJid());
396 name.setText(item.getDisplayName());
397 picture.setImageBitmap(UIHelper.getContactPicture(item, 48,
398 this.getContext(), false));
399 return view;
400 }
401
402 }
403
404 public static class MyListFragment extends ListFragment {
405 private AdapterView.OnItemClickListener mOnItemClickListener;
406 private int mContextPosition = -1;
407
408 @Override
409 public void onListItemClick(ListView l, View v, int position, long id) {
410 if (mOnItemClickListener != null) {
411 mOnItemClickListener.onItemClick(l, v, position, id);
412 }
413 }
414
415 public void setOnListItemClickListener(AdapterView.OnItemClickListener l) {
416 this.mOnItemClickListener = l;
417 }
418
419 @Override
420 public void onViewCreated(View view, Bundle savedInstanceState) {
421 super.onViewCreated(view, savedInstanceState);
422 registerForContextMenu(getListView());
423 }
424
425 @Override
426 public void onCreateContextMenu(ContextMenu menu, View v,
427 ContextMenuInfo menuInfo) {
428 super.onCreateContextMenu(menu, v, menuInfo);
429 getActivity().getMenuInflater().inflate(R.menu.contact_context,
430 menu);
431 AdapterView.AdapterContextMenuInfo acmi = (AdapterContextMenuInfo) menuInfo;
432 this.mContextPosition = acmi.position;
433 }
434
435 @Override
436 public boolean onContextItemSelected(MenuItem item) {
437 StartConversation activity = (StartConversation) getActivity();
438 switch (item.getItemId()) {
439 case R.id.context_start_conversation:
440 activity.openConversationForContact(mContextPosition);
441 break;
442 case R.id.context_contact_details:
443 activity.openDetailsForContact(mContextPosition);
444 break;
445 case R.id.context_delete_contact:
446 activity.deleteContact(mContextPosition);
447 break;
448 }
449 return true;
450 }
451 }
452}