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