# HG changeset patch # User Da Risk # Date 1330473200 -3600 # Node ID 02aafc8b2220e34692d8397abac9c1f8dd2179b2 # Parent 142f330bd3f6cdddbb6bbebe1f90b1df1d5b6602 Implements swiping on contact list by using android compat ViewPager diff -r 142f330bd3f6 -r 02aafc8b2220 libs/android-support-v13.jar Binary file libs/android-support-v13.jar has changed diff -r 142f330bd3f6 -r 02aafc8b2220 project.properties --- a/project.properties Fri Apr 06 17:43:01 2012 +0200 +++ b/project.properties Wed Feb 29 00:53:20 2012 +0100 @@ -8,4 +8,4 @@ # project structure. # Project target. -target=android-8 +target=android-15 diff -r 142f330bd3f6 -r 02aafc8b2220 res/layout/contactlist.xml --- a/res/layout/contactlist.xml Fri Apr 06 17:43:01 2012 +0200 +++ b/res/layout/contactlist.xml Wed Feb 29 00:53:20 2012 +0100 @@ -4,12 +4,21 @@ android:orientation="vertical"> + + + + + diff -r 142f330bd3f6 -r 02aafc8b2220 src/com/beem/project/beem/ui/ContactList.java --- a/src/com/beem/project/beem/ui/ContactList.java Fri Apr 06 17:43:01 2012 +0200 +++ b/src/com/beem/project/beem/ui/ContactList.java Wed Feb 29 00:53:20 2012 +0100 @@ -42,33 +42,36 @@ */ package com.beem.project.beem.ui; +import java.io.IOException; +import java.io.InputStream; import java.util.ArrayList; import java.util.Collections; -import java.util.Comparator; import java.util.HashMap; import java.util.LinkedList; import java.util.List; import java.util.Map; -import java.io.InputStream; -import java.io.IOException; import org.jivesoftware.smack.util.StringUtils; -import android.app.Activity; import android.app.Dialog; import android.content.ComponentName; import android.content.Intent; import android.content.IntentFilter; import android.content.ServiceConnection; import android.content.SharedPreferences; +import android.graphics.drawable.Drawable; +import android.graphics.drawable.LayerDrawable; import android.net.Uri; import android.os.Bundle; -import android.os.Handler; import android.os.IBinder; import android.os.RemoteException; import android.preference.PreferenceManager; +import android.support.v4.app.Fragment; +import android.support.v4.app.FragmentActivity; +import android.support.v4.app.FragmentManager; +import android.support.v4.app.FragmentPagerAdapter; +import android.support.v4.view.ViewPager; import android.util.Log; -import android.view.ContextMenu; import android.view.LayoutInflater; import android.view.Menu; import android.view.MenuInflater; @@ -77,7 +80,6 @@ import android.view.ViewGroup; import android.view.ViewStub; import android.widget.AdapterView; -import android.widget.AdapterView.AdapterContextMenuInfo; import android.widget.AdapterView.OnItemClickListener; import android.widget.BaseAdapter; import android.widget.Filter; @@ -85,13 +87,10 @@ import android.widget.Gallery; import android.widget.ImageView; import android.widget.LinearLayout; -import android.widget.ListView; import android.widget.TextView; -import android.graphics.drawable.Drawable; -import android.graphics.drawable.LayerDrawable; +import com.beem.project.beem.BeemApplication; import com.beem.project.beem.R; -import com.beem.project.beem.BeemApplication; import com.beem.project.beem.providers.AvatarProvider; import com.beem.project.beem.service.Contact; import com.beem.project.beem.service.PresenceAdapter; @@ -104,13 +103,11 @@ import com.beem.project.beem.ui.dialogs.builders.DeleteContact; import com.beem.project.beem.ui.dialogs.builders.ResendSubscription; import com.beem.project.beem.utils.BeemBroadcastReceiver; -import com.beem.project.beem.utils.SortedList; -import com.beem.project.beem.utils.Status; /** * The contact list activity displays the roster of the user. */ -public class ContactList extends Activity { +public class ContactList extends FragmentActivity { private static final Intent SERVICE_INTENT = new Intent(); static { @@ -118,19 +115,15 @@ } private static final String TAG = "ContactList"; - private final BeemContactList mAdapterContactList = new BeemContactList(); private final List mListGroup = new ArrayList(); /** Map containing a list of the different contacts of a given group. * Each list is a @{link SortedList} so there is no need to sort it again. * */ private final Map> mContactOnGroup = new HashMap>(); - private final BeemContactListOnClick mOnContactClick = new BeemContactListOnClick(); - private final Handler mHandler = new Handler(); private final ServiceConnection mServConn = new BeemServiceConnection(); private final BeemBroadcastReceiver mReceiver = new BeemBroadcastReceiver(); - private final ComparatorContactListByStatusAndName mComparator = - new ComparatorContactListByStatusAndName(); + private final BeemRosterListener mBeemRosterListener = new BeemRosterListener(); private List mListContact; private String mSelectedGroup; @@ -142,6 +135,10 @@ private LayoutInflater mInflater; private BeemBanner mAdapterBanner; private boolean mBinded; + private ViewPager viewPager; + private Map contactListAdapters = new HashMap(); + private ListPagerAdapter groupsPagesAdapter; + private Gallery groupGallery; /** * Constructor. @@ -194,86 +191,6 @@ } } - @Override - public void onCreateContextMenu(ContextMenu menu, View v, ContextMenu.ContextMenuInfo menuInfo) { - super.onCreateContextMenu(menu, v, menuInfo); - MenuInflater inflater = getMenuInflater(); - inflater.inflate(R.menu.contactlist_context, menu); - AdapterContextMenuInfo info = (AdapterView.AdapterContextMenuInfo) menuInfo; - Contact c = mListContact.get(info.position); - try { - mSelectedContact = mRoster.getContact(c.getJID()); - } catch (RemoteException e) { - e.printStackTrace(); - } - menu.setHeaderTitle(mSelectedContact.getJID()); - } - - @Override - public boolean onContextItemSelected(MenuItem item) { - Intent in; - boolean result; - if (mSelectedContact != null) { - switch (item.getItemId()) { - case R.id.contact_list_context_menu_chat_item: - List res = mSelectedContact.getMRes(); - if (res.isEmpty()) { - result = false; - break; - } - for (String resv : res) { - in = new Intent(this, Chat.class); - in.setData(mSelectedContact.toUri(resv)); - item.getSubMenu().add(resv).setIntent(in); - } - result = true; - break; - case R.id.contact_list_context_menu_call_item: - try { - mXmppFacade.call(mSelectedContact.getJID() + "/psi"); - result = true; - } catch (RemoteException e) { - e.printStackTrace(); - } - result = true; - break; - case R.id.contact_list_context_menu_user_info: - item.getSubMenu().setHeaderTitle(mSelectedContact.getJID()); - result = true; - break; - case R.id.contact_list_context_menu_userinfo_alias: - Dialog alias = new Alias(ContactList.this, mRoster, mSelectedContact).create(); - alias.show(); - result = true; - break; - case R.id.contact_list_context_menu_userinfo_group: - in = new Intent(this, GroupList.class); - in.putExtra("contact", mSelectedContact); - startActivity(in); - result = true; - break; - case R.id.contact_list_context_menu_userinfo_subscription: - Dialog subscription = new ResendSubscription(ContactList.this, - mXmppFacade, mSelectedContact).create(); - subscription.show(); - result = true; - break; - case R.id.contact_list_context_menu_userinfo_block: - result = true; - break; - case R.id.contact_list_context_menu_userinfo_delete: - Dialog delete = new DeleteContact(ContactList.this, mRoster, mSelectedContact).create(); - delete.show(); - result = true; - break; - default: - result = super.onContextItemSelected(item); - break; - } - return result; - } - return super.onContextItemSelected(item); - } @Override protected void onCreate(Bundle saveBundle) { @@ -284,17 +201,25 @@ this.registerReceiver(mReceiver, new IntentFilter(BeemBroadcastReceiver.BEEM_CONNECTION_CLOSED)); mInflater = getLayoutInflater(); - mAdapterBanner = new BeemBanner(mInflater, mListGroup); + mAdapterBanner = new BeemBanner(); mListContact = new ArrayList(); - ListView listView = (ListView) findViewById(R.id.contactlist); - listView.setOnItemClickListener(mOnContactClick); - registerForContextMenu(listView); - listView.setAdapter(mAdapterContactList); + + viewPager = (ViewPager) findViewById(R.id.pager); + groupsPagesAdapter = new ListPagerAdapter(getSupportFragmentManager(), viewPager); + + mListGroup.add(getString(R.string.contact_list_all_contact)); + mListGroup.add(getString(R.string.contact_list_no_group)); + mAdapterBanner.notifyDataSetChanged(); } @Override - protected void onResume() { - super.onResume(); + protected void onStart() { + super.onStart(); + if (!mSettings.getBoolean(BeemApplication.HIDE_GROUPS_KEY, false)) + showGroups(); + else + hideGroups(); + if (!mBinded) mBinded = bindService(SERVICE_INTENT, mServConn, BIND_AUTO_CREATE); } @@ -328,17 +253,6 @@ } /** - * Build and display the contact list. - * @param group name of the contact list. - */ - private void buildContactList(String group) { - mListContact = mContactOnGroup.get(group); - mSelectedGroup = group; - Log.d(TAG, "buildContactList for group " + group); - mAdapterContactList.notifyDataSetChanged(); - } - - /** * Show the groups view. */ private void showGroups() { @@ -346,14 +260,14 @@ ViewStub stub = (ViewStub) findViewById(R.id.contactlist_stub); if (stub != null) { View v = stub.inflate(); - Gallery g = (Gallery) v.findViewById(R.id.contactlist_banner); - g.setOnItemClickListener(new OnItemClickGroupName()); - g.setAdapter(mAdapterBanner); - g.setSelection(0); + groupGallery = (Gallery) v.findViewById(R.id.contactlist_banner); + groupGallery.setOnItemClickListener(new OnItemClickGroupName()); + groupGallery.setAdapter(mAdapterBanner); + groupGallery.setSelection(0); } else { ((LinearLayout) findViewById(R.id.contactlist_groupstub)).setVisibility(View.VISIBLE); - Gallery g = (Gallery) findViewById(R.id.contactlist_banner); - g.setSelection(0); + groupGallery = (Gallery) findViewById(R.id.contactlist_banner); + groupGallery.setSelection(0); } } @@ -366,7 +280,59 @@ v.setVisibility(View.GONE); } + ContactListAdapter getContactListAdapter(String group) { + synchronized (contactListAdapters) { + ContactListAdapter contactListAdapter = contactListAdapters.get(group); + if (contactListAdapter == null) { + contactListAdapter = new ContactListAdapter(ContactList.this); + contactListAdapters.put(group, contactListAdapter); + if (!mListGroup.contains(group)) { + mListGroup.add(mListGroup.size() - 1, group); + groupsPagesAdapter.notifyDataSetChanged(); + mAdapterBanner.notifyDataSetChanged(); + } + } + boolean hideDisconnected = mSettings.getBoolean(BeemApplication.SHOW_OFFLINE_CONTACTS_KEY, false); + contactListAdapter.setOnlineOnly(hideDisconnected); + return contactListAdapter; + } + } + /** + * Remove old groups on the banner. + * @throws RemoteException if an error occur when communicating with the service + */ + private void cleanBannerGroup() throws RemoteException { + if (mListGroup.size() <= 2) + return; + List rosterGroups = mRoster.getGroupsNames(); + List realGroups = mListGroup.subList(1, mListGroup.size() - 1); + realGroups.clear(); + realGroups.addAll(rosterGroups); + mAdapterBanner.notifyDataSetChanged(); + groupsPagesAdapter.notifyDataSetChanged(); + } + + /** + * Add a contact to the special list No Group and All contacts. + * The contact will be added if the list is not the current list otherwise + * the list must be modified in a Handler. + * + * @param contact the contact to add. + */ + private void addToSpecialList(Contact contact) { + List groups = contact.getGroups(); + + ContactListAdapter adapter = getContactListAdapter(getString(R.string.contact_list_all_contact)); + adapter.put(contact); + if (groups.isEmpty()) { + adapter = getContactListAdapter(getString(R.string.contact_list_no_group)); + adapter.put(contact); + } + + } + + /** * Listener on service event. */ private class BeemRosterListener extends IBeemRosterListener.Stub { @@ -387,30 +353,11 @@ */ @Override public void onEntriesAdded(final List addresses) throws RemoteException { - final boolean hideDisconnected = mSettings.getBoolean(BeemApplication.SHOW_OFFLINE_CONTACTS_KEY, false); for (String newName : addresses) { - Contact contact = mRoster.getContact(newName); - boolean visible = !hideDisconnected || Status.statusOnline(contact.getStatus()); - List groups = contact.getGroups(); - if (visible) { - for (String group : groups) { - if (!mListGroup.contains(group)) { - mListGroup.add(mListGroup.size() - 1, group); - List tmplist = new SortedList(new LinkedList(), mComparator); - mContactOnGroup.put(group, tmplist); - } - List contactByGroups = mContactOnGroup.get(group); - if (mSelectedGroup.equals(group)) { - updateCurrentList(group, contact); - continue; - } - contactByGroups.add(contact); - } - - // add the contact to all and no groups - addToSpecialList(contact); - } + final Contact contact = mRoster.getContact(StringUtils.parseBareAddress(newName)); + putContactInList(contact); } + } /** @@ -424,26 +371,18 @@ public void onEntriesDeleted(final List addresses) throws RemoteException { Log.d(TAG, "onEntries deleted " + addresses); for (String cToDelete : addresses) { - Contact contact = new Contact(cToDelete); - for (Map.Entry> entry : mContactOnGroup.entrySet()) { - List contactByGroups = entry.getValue(); - if (mSelectedGroup.equals(entry.getKey())) { - updateCurrentList(entry.getKey(), contact); - continue; - } - contactByGroups.remove(contact); + final Contact contact = new Contact(cToDelete); + for (final ContactListAdapter adapter : contactListAdapters.values()) { + runOnUiThread(new Runnable() { + + @Override + public void run() { + adapter.remove(contact); + } + }); } + } cleanBannerGroup(); - } - - mHandler.post(new Runnable() { - public void run() { - mSelectedGroup = getString(R.string.contact_list_all_contact); - mListContact = mContactOnGroup.get(mSelectedGroup); - - mAdapterContactList.notifyDataSetChanged(); - } - }); } @@ -458,38 +397,18 @@ */ @Override public void onEntriesUpdated(final List addresses) throws RemoteException { - final boolean hideDisconnected = mSettings.getBoolean(BeemApplication.SHOW_OFFLINE_CONTACTS_KEY, false); - for (String adr : addresses) { - Contact contact = mRoster.getContact(adr); - boolean visible = !hideDisconnected || Status.statusOnline(contact.getStatus()); - List groups = contact.getGroups(); - for (Map.Entry> entry : mContactOnGroup.entrySet()) { - List contactByGroups = entry.getValue(); - if (mSelectedGroup.equals(entry.getKey())) { - updateCurrentList(entry.getKey(), contact); - continue; - } - contactByGroups.remove(contact); - if (visible) { - for (String group : groups) { - if (!mListGroup.contains(group)) { - mListGroup.add(mListGroup.size() - 1, group); - List tmplist = new SortedList( - new LinkedList(), mComparator); - mContactOnGroup.put(group, tmplist); - } - mContactOnGroup.get(group).remove(contact); - } - } - - } - - // add the contact to all and no groups - if (visible) { - addToSpecialList(contact); + Log.d(TAG, "onEntries updated " + addresses); + for (String cToDelete : addresses) { + Contact contact = new Contact(cToDelete); + for (ContactListAdapter adapter : contactListAdapters.values()) { + adapter.remove(contact); } } - cleanBannerGroup(); + for (String newName : addresses) { + final Contact contact = mRoster.getContact(StringUtils.parseBareAddress(newName)); + putContactInList(contact); + } + cleanBannerGroup(); } /** @@ -504,266 +423,52 @@ @Override public void onPresenceChanged(PresenceAdapter presence) throws RemoteException { String from = presence.getFrom(); - final boolean hideDisconnected = mSettings.getBoolean(BeemApplication.SHOW_OFFLINE_CONTACTS_KEY, false); final Contact contact = mRoster.getContact(StringUtils.parseBareAddress(from)); - boolean visible = !hideDisconnected || Status.statusOnline(contact.getStatus()); - List groups = contact.getGroups(); - for (Map.Entry> entry : mContactOnGroup.entrySet()) { - List contactByGroups = entry.getValue(); - if (mSelectedGroup.equals(entry.getKey())) { - updateCurrentList(entry.getKey(), contact); - continue; - } - contactByGroups.remove(contact); - if (visible) { - if (groups.contains(entry.getKey())) { - contactByGroups.add(contact); - } - } - } - if (visible) { - addToSpecialList(contact); - } - } - - /** - * Add a contact to the special list No Group and All contacts. - * The contact will be added if the list is not the current list otherwise - * the list must be modified in a Handler. - * - * @param contact the contact to add. - */ - private void addToSpecialList(Contact contact) { - List groups = contact.getGroups(); - List list = mContactOnGroup.get(getString(R.string.contact_list_all_contact)); - if (list != mListContact) { - list.add(contact); - } - list = mContactOnGroup.get(getString(R.string.contact_list_no_group)); - if (list != mListContact && groups.isEmpty()) { - list.add(contact); - } + putContactInList(contact); } - /** - * Update the current list with the status of contact. - * - * @param listName name of the current list - * @param contact contact to update - */ - private void updateCurrentList(String listName, final Contact contact) { - final boolean hideDisconnected = mSettings.getBoolean(BeemApplication.SHOW_OFFLINE_CONTACTS_KEY, false); - final List groups = contact.getGroups(); - String noGroup = getString(R.string.contact_list_no_group); - String allGroup = getString(R.string.contact_list_all_contact); - final boolean add = ((!hideDisconnected || Status.statusOnline(contact.getStatus())) && // must show and - ( - (listName.equals(noGroup) && groups.isEmpty()) || // in no group - groups.contains(listName) || // or in current - listName.equals(allGroup) // or in all - )); - mHandler.post(new Runnable() { - public void run() { - mListContact.remove(contact); - if (add) { - mListContact.add(contact); - } - mAdapterContactList.notifyDataSetChanged(); - } - }); - - } - - /** - * Remove old groups on the banner. - * @throws RemoteException if an error occur when communicating with the service - */ - private void cleanBannerGroup() throws RemoteException { - List rosterGroups = mRoster.getGroupsNames(); - List realGroups = mListGroup.subList(1, mListContact.size() - 1); - realGroups.retainAll(rosterGroups); - } - + private void putContactInList(final Contact contact) { + List groups = contact.getGroups(); + for (final String group : groups) { + runOnUiThread(new Runnable() { + + @Override + public void run() { + ContactListAdapter contactListAdapter = getContactListAdapter(group); + contactListAdapter.put(contact); + } + }); + } + + runOnUiThread(new Runnable() { + + @Override + public void run() { + addToSpecialList(contact); + } + }); + } } - + /** - * Adapter contact list. + * Adapter banner list. */ - private class BeemContactList extends BaseAdapter implements Filterable { - - private final ContactFilter mFilter; + private class BeemBanner extends BaseAdapter { /** * Constructor. */ - public BeemContactList() { - mFilter = new ContactFilter(); - } - - /** - * {@inheritDoc} - */ - @Override - public int getCount() { - return mListContact.size(); - } - - /** - * {@inheritDoc} - */ - @Override - public Object getItem(int position) { - return mListContact.get(position); - } - - /** - * {@inheritDoc} - */ - @Override - public long getItemId(int position) { - return mListContact.get(position).hashCode(); - } - - - /** - * {@inheritDoc} - */ - @Override - public View getView(int position, View convertView, ViewGroup parent) { - View v = convertView; - if (convertView == null) { - v = mInflater.inflate(R.layout.contactlistcontact, null); - } - Contact c = mListContact.get(position); - if (mRoster != null) { - try { - c = mRoster.getContact(c.getJID()); - } catch (RemoteException e) { - e.printStackTrace(); - } - } - bindView(v, c); - return v; - } - - @Override - public Filter getFilter() { - return mFilter; - } - - /** - * Adapte curContact to the view. - * @param view the row view. - * @param curContact the current contact. - */ - private void bindView(View view, Contact curContact) { - if (curContact != null) { - TextView v = (TextView) view.findViewById(R.id.contactlistpseudo); - v.setText(curContact.getName()); - v = (TextView) view.findViewById(R.id.contactlistmsgperso); - v.setText(curContact.getMsgState()); - ImageView img = (ImageView) view.findViewById(R.id.avatar); - String avatarId = curContact.getAvatarId(); - int contactStatus = curContact.getStatus(); - Drawable avatar = getAvatarStatusDrawable(avatarId); - img.setImageDrawable(avatar); - img.setImageLevel(contactStatus); - } - } - - /** - * Get a LayerDrawable containing the avatar and the status icon. - * The status icon will change with the level of the drawable. - * @param avatarId the avatar id to retrieve or null to get default - * @return a LayerDrawable - */ - private Drawable getAvatarStatusDrawable(String avatarId) { - Drawable avatarDrawable = null; - if (avatarId != null) { - Uri uri = AvatarProvider.CONTENT_URI.buildUpon().appendPath(avatarId).build(); - InputStream in = null; - try { - try { - in = getContentResolver().openInputStream(uri); - avatarDrawable = Drawable.createFromStream(in, avatarId); - } finally { - if (in != null) - in.close(); - } - } catch (IOException e) { - Log.w(TAG, "Error while setting the avatar " + avatarId, e); - } - } - if (avatarDrawable == null) - avatarDrawable = getResources().getDrawable(R.drawable.beem_launcher_icon_silver); - LayerDrawable ld = (LayerDrawable) getResources().getDrawable(R.drawable.avatar_status); - ld.setLayerInset(1, 36, 36, 0, 0); - ld.setDrawableByLayerId(R.id.avatar, avatarDrawable); - return ld; - } - - /** - * A Filter which select Contact to display by searching in ther Jid. - */ - private class ContactFilter extends Filter { - - /** - * Create a ContactFilter. - */ - public ContactFilter() { } - - @Override - protected Filter.FilterResults performFiltering(CharSequence constraint) { - Log.d(TAG, "performFiltering"); - List result = mListContact; - if (constraint.length() > 0) { - result = new LinkedList(); - for (Contact c : mContactOnGroup.get(mSelectedGroup)) { - if (c.getJID().contains(constraint)) - result.add(c); - } - } - Filter.FilterResults fr = new Filter.FilterResults(); - fr.values = result; - fr.count = result.size(); - return fr; - } - - @Override - protected void publishResults(CharSequence constraint, Filter.FilterResults results) { - Log.d(TAG, "publishResults"); - List contacts = (List) results.values; - mListContact = contacts; - notifyDataSetChanged(); - } - } - } - - /** - * Adapter banner list. - */ - private static class BeemBanner extends BaseAdapter { - private List mGroups; - private LayoutInflater mInflater; - - /** - * Constructor. - * @param inflater the inflater use to create the view for the banner - * @param groups list of the differents groups to adapt - */ - public BeemBanner(final LayoutInflater inflater, final List groups) { - mGroups = groups; - mInflater = inflater; + public BeemBanner() { } @Override public int getCount() { - return mGroups.size(); + return mListGroup.size(); } @Override public Object getItem(int position) { - return mGroups.get(position); + return mListGroup.get(position); } @Override @@ -777,7 +482,7 @@ if (convertView == null) { v = mInflater.inflate(R.layout.contactlist_group, null); } - ((TextView) v).setText(mGroups.get(position)); + ((TextView) v).setText(mListGroup.get(position)); return v; } } @@ -801,18 +506,18 @@ if (mRoster != null) { List tmpGroupList = mRoster.getGroupsNames(); Collections.sort(tmpGroupList); - mListGroup.clear(); - mListGroup.add(getString(R.string.contact_list_all_contact)); - mListGroup.addAll(tmpGroupList); - mListGroup.add(getString(R.string.contact_list_no_group)); + cleanBannerGroup(); + mListGroup.addAll(1, tmpGroupList); + synchronized (contactListAdapters) { + for (ContactListAdapter ca : contactListAdapters.values()) { + ca.clear(); + } + } + groupsPagesAdapter.notifyDataSetChanged(); + mAdapterBanner.notifyDataSetChanged(); + assignContactToGroups(mRoster.getContactList(), tmpGroupList); - makeSortedList(mContactOnGroup); - if (!mSettings.getBoolean(BeemApplication.HIDE_GROUPS_KEY, false)) - showGroups(); - else - hideGroups(); - String group = getString(R.string.contact_list_all_contact); - buildContactList(group); + mRoster.addRosterListener(mBeemRosterListener); Log.d(TAG, "add roster listener"); mChatManager = mXmppFacade.getChatManager(); @@ -836,6 +541,7 @@ mListGroup.clear(); mContactOnGroup.clear(); mBinded = false; + } /** @@ -846,91 +552,23 @@ * @param groupNames list of existing groups */ private void assignContactToGroups(List contacts, List groupNames) { - boolean hideDisconnected = mSettings.getBoolean(BeemApplication.SHOW_OFFLINE_CONTACTS_KEY, false); - mContactOnGroup.clear(); - List all = new LinkedList(); - List noGroups = new LinkedList(); - for (String group : groupNames) { - mContactOnGroup.put(group, new LinkedList()); + for (Contact c : contacts) { + addToSpecialList(c); + + List groups = c.getGroups(); + + for (String currentGroup : groups) { + ContactListAdapter cl = getContactListAdapter(currentGroup); + cl.put(c); + } + } - for (Contact c : contacts) { - if (hideDisconnected && !Status.statusOnline(c.getStatus())) { - continue; - } - all.add(c); - List groups = c.getGroups(); - if (groups.isEmpty()) - noGroups.add(c); - else { - for (String currentGroup : groups) { - List contactsByGroups = mContactOnGroup.get(currentGroup); - contactsByGroups.add(c); - } - } - } - mContactOnGroup.put(getString(R.string.contact_list_no_group), noGroups); - mContactOnGroup.put(getString(R.string.contact_list_all_contact), all); } - /** - * Make the List of the map became Insertion sorted list. - * - * @param map the map to convert. - */ - private void makeSortedList(Map> map) { - for (Map.Entry> entry : map.entrySet()) { - List l = entry.getValue(); - entry.setValue(new SortedList(l, mComparator)); - } - } } - - /** - * Comparator Contact by status and name. - */ - private static class ComparatorContactListByStatusAndName implements Comparator { - /** - * Constructor. - */ - public ComparatorContactListByStatusAndName() { - } - - @Override - public int compare(T c1, T c2) { - if (((Contact) c1).getStatus() < ((Contact) c2).getStatus()) { - return 1; - } else if (((Contact) c1).getStatus() > ((Contact) c2).getStatus()) { - return -1; - } else - return ((Contact) c1).getName().compareToIgnoreCase(((Contact) c2).getName()); - } - } - - /** - * Event simple click on item of the contact list. - */ - private class BeemContactListOnClick implements OnItemClickListener { - /** - * Constructor. - */ - public BeemContactListOnClick() { - } - - /** - * {@inheritDoc} - */ - @Override - public void onItemClick(AdapterView arg0, View v, int pos, long lpos) { - Contact c = mListContact.get(pos); - Intent i = new Intent(ContactList.this, Chat.class); - i.setData(c.toUri()); - startActivity(i); - } - } - /** * Event simple click on middle groupe name. */ @@ -944,9 +582,59 @@ @Override public void onItemClick(AdapterView arg0, View v, int i, long l) { - String group = mListGroup.get(i); - buildContactList(group); + viewPager.setCurrentItem(i, true); } } + private class ListPagerAdapter extends FragmentPagerAdapter { + + public ListPagerAdapter(FragmentManager fm, ViewPager viewPager) { + super(fm); + viewPager.setAdapter(this); + } + + @Override + public Fragment getItem(int position) { + String group = mListGroup.get(position); + ContactListFragment f = ContactListFragment.newInstance(group); + f.setListAdapter(getContactListAdapter(group)); + return f; + } + + @Override + public int getCount() { + return mListGroup.size(); + } + + } + + void doContextMenuAction(int itemId, Contact contact) { + switch (itemId) { + case R.id.contact_list_context_menu_call_item: + try { + mXmppFacade.call(contact.getJID() + "/psi"); + } catch (RemoteException e) { + e.printStackTrace(); + } + break; + case R.id.contact_list_context_menu_userinfo_alias: + Dialog alias = new Alias(ContactList.this, mRoster, contact).create(); + alias.show(); + break; + case R.id.contact_list_context_menu_userinfo_subscription: + Dialog subscription = new ResendSubscription(ContactList.this, + mXmppFacade, contact).create(); + subscription.show(); + break; + case R.id.contact_list_context_menu_userinfo_delete: + Dialog delete = new DeleteContact(ContactList.this, mRoster, contact).create(); + delete.show(); + break; + default: + Log.w(TAG, "Context menu action not supported" + itemId); + break; + } + + } + } diff -r 142f330bd3f6 -r 02aafc8b2220 src/com/beem/project/beem/ui/ContactListAdapter.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/com/beem/project/beem/ui/ContactListAdapter.java Wed Feb 29 00:53:20 2012 +0100 @@ -0,0 +1,231 @@ +package com.beem.project.beem.ui; + +import java.io.IOException; +import java.io.InputStream; +import java.util.Comparator; +import java.util.LinkedList; +import java.util.List; + +import android.content.Context; +import android.graphics.drawable.Drawable; +import android.graphics.drawable.LayerDrawable; +import android.net.Uri; +import android.util.Log; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.BaseAdapter; +import android.widget.Filter; +import android.widget.Filterable; +import android.widget.ImageView; +import android.widget.TextView; + +import com.beem.project.beem.R; +import com.beem.project.beem.providers.AvatarProvider; +import com.beem.project.beem.service.Contact; +import com.beem.project.beem.utils.SortedList; +import com.beem.project.beem.utils.Status; + +public class ContactListAdapter extends BaseAdapter implements Filterable { + private static final String TAG = ContactListAdapter.class.getSimpleName(); + private final ComparatorContactListByStatusAndName mComparator = + new ComparatorContactListByStatusAndName(); + private List mCurrentList; + private final List allContacts = new SortedList(new LinkedList(), mComparator); + private final List onlineContacts = new SortedList(new LinkedList(), mComparator); + private final Filter mFilter = new ContactFilter(); + private final Context context; + private LayoutInflater mInflater; + + + private boolean showOnlineOnly; + + public ContactListAdapter(Context c) { + mCurrentList = allContacts; + context = c; + mInflater = (LayoutInflater) c.getSystemService(Context.LAYOUT_INFLATER_SERVICE); + } + + @Override + public int getCount() { + return mCurrentList.size(); + } + + + @Override + public Object getItem(int position) { + return mCurrentList.get(position); + } + + + @Override + public long getItemId(int position) { + return mCurrentList.get(position).hashCode(); + } + + @Override + public View getView(int position, View convertView, ViewGroup parent) { + View v = convertView; + if (convertView == null) { + v = mInflater.inflate(R.layout.contactlistcontact, null); + } + Contact c = mCurrentList.get(position); + bindView(v, c); + return v; + } + + public void put(Contact c) { + put(c, allContacts); + if (Status.statusOnline(c.getStatus())) + put(c, onlineContacts); + notifyDataSetChanged(); + } + + public void remove(Contact c) { + allContacts.remove(c); + onlineContacts.remove(c); + notifyDataSetChanged(); + } + + + public void clear() { + allContacts.clear(); + onlineContacts.clear(); + notifyDataSetChanged(); + } + + @Override + public Filter getFilter() { + return mFilter; + } + + /** + * Adapte curContact to the view. + * @param view the row view. + * @param curContact the current contact. + */ + private void bindView(View view, Contact curContact) { + if (curContact != null) { + TextView v = (TextView) view.findViewById(R.id.contactlistpseudo); + v.setText(curContact.getName()); + v = (TextView) view.findViewById(R.id.contactlistmsgperso); + v.setText(curContact.getMsgState()); + ImageView img = (ImageView) view.findViewById(R.id.avatar); + String avatarId = curContact.getAvatarId(); + int contactStatus = curContact.getStatus(); + Drawable avatar = getAvatarStatusDrawable(avatarId); + img.setImageDrawable(avatar); + img.setImageLevel(contactStatus); + } + } + + /** + * Get a LayerDrawable containing the avatar and the status icon. + * The status icon will change with the level of the drawable. + * @param avatarId the avatar id to retrieve or null to get default + * @return a LayerDrawable + */ + private Drawable getAvatarStatusDrawable(String avatarId) { + Drawable avatarDrawable = null; + if (avatarId != null) { + Uri uri = AvatarProvider.CONTENT_URI.buildUpon().appendPath(avatarId).build(); + InputStream in = null; + try { + try { + in = context.getContentResolver().openInputStream(uri); + avatarDrawable = Drawable.createFromStream(in, avatarId); + } finally { + if (in != null) + in.close(); + } + } catch (IOException e) { + Log.w(TAG, "Error while setting the avatar " + avatarId, e); + } + } + if (avatarDrawable == null) + avatarDrawable = context.getResources().getDrawable(R.drawable.beem_launcher_icon_silver); + LayerDrawable ld = (LayerDrawable) context.getResources().getDrawable(R.drawable.avatar_status); + ld.setLayerInset(1, 36, 36, 0, 0); + ld.setDrawableByLayerId(R.id.avatar, avatarDrawable); + return ld; + } + + private void put(Contact c, List list) { + list.remove(c); + list.add(c); + } + + public boolean isOnlineOnly() { + return showOnlineOnly; + } + + public void setOnlineOnly(boolean online) { + if (online != showOnlineOnly) { + showOnlineOnly = online; + mCurrentList = showOnlineOnly ? onlineContacts : allContacts; + notifyDataSetChanged(); + } + } + + + /** + * Comparator Contact by status and name. + */ + private static class ComparatorContactListByStatusAndName implements Comparator { + /** + * Constructor. + */ + public ComparatorContactListByStatusAndName() { + } + + @Override + public int compare(T c1, T c2) { + if (((Contact) c1).getStatus() < ((Contact) c2).getStatus()) { + return 1; + } else if (((Contact) c1).getStatus() > ((Contact) c2).getStatus()) { + return -1; + } else + return ((Contact) c1).getName().compareToIgnoreCase(((Contact) c2).getName()); + } + } + + + /** + * A Filter which select Contact to display by searching in ther Jid. + */ + private class ContactFilter extends Filter { + + /** + * Create a ContactFilter. + */ + public ContactFilter() { } + + @Override + protected Filter.FilterResults performFiltering(CharSequence constraint) { + Log.d(TAG, "performFiltering"); + List result = mCurrentList; + if (constraint.length() > 0) { + result = new LinkedList(); + for (Contact c : mCurrentList) { + if (c.getJID().contains(constraint)) + result.add(c); + } + } + Filter.FilterResults fr = new Filter.FilterResults(); + fr.values = result; + fr.count = result.size(); + return fr; + } + + @Override + protected void publishResults(CharSequence constraint, Filter.FilterResults results) { + Log.d(TAG, "publishResults"); + List contacts = (List) results.values; + mCurrentList = contacts; + notifyDataSetChanged(); + } + } + + + +} diff -r 142f330bd3f6 -r 02aafc8b2220 src/com/beem/project/beem/ui/ContactListFragment.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/com/beem/project/beem/ui/ContactListFragment.java Wed Feb 29 00:53:20 2012 +0100 @@ -0,0 +1,145 @@ +package com.beem.project.beem.ui; + +import java.util.LinkedList; +import java.util.List; + +import android.app.Activity; +import android.app.Dialog; +import android.content.Intent; +import android.os.Bundle; +import android.os.RemoteException; +import android.support.v4.app.ListFragment; +import android.util.Log; +import android.view.ContextMenu; +import android.view.MenuInflater; +import android.view.MenuItem; +import android.view.View; +import android.widget.AdapterView; +import android.widget.AdapterView.AdapterContextMenuInfo; +import android.widget.Filter; +import android.widget.ListAdapter; +import android.widget.ListView; + +import com.beem.project.beem.R; +import com.beem.project.beem.service.Contact; +import com.beem.project.beem.ui.dialogs.builders.Alias; +import com.beem.project.beem.ui.dialogs.builders.DeleteContact; +import com.beem.project.beem.ui.dialogs.builders.ResendSubscription; + +public class ContactListFragment extends ListFragment { + private String group; + private ContactList hostActivity; + private Contact mSelectedContact; + + public static ContactListFragment newInstance(String group) { + ContactListFragment f = new ContactListFragment(); + Bundle b = new Bundle(); + b.putString("group", group); + f.setArguments(b); + return f; + } + + @Override + public void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + parseArguments(); + } + + @Override + public void onAttach(Activity activity) { + super.onAttach(activity); + hostActivity = (ContactList) activity; + } + + @Override + public void onActivityCreated(Bundle savedInstanceState) { + super.onActivityCreated(savedInstanceState); + ListAdapter adapter = hostActivity.getContactListAdapter(group); + setListAdapter(adapter); + registerForContextMenu(getListView()); + } + + @Override + public void onListItemClick(ListView l, View v, int position, long id) { + ContactListAdapter a = (ContactListAdapter) getListAdapter(); + Contact c = (Contact) a.getItem(position); + Intent i = new Intent(getActivity(), Chat.class); + i.setData(c.toUri()); + startActivity(i); + } + + + + @Override + public void onCreateContextMenu(ContextMenu menu, View v, ContextMenu.ContextMenuInfo menuInfo) { + super.onCreateContextMenu(menu, v, menuInfo); + MenuInflater inflater = hostActivity.getMenuInflater(); + inflater.inflate(R.menu.contactlist_context, menu); + AdapterContextMenuInfo info = (AdapterView.AdapterContextMenuInfo) menuInfo; + mSelectedContact = (Contact) getListAdapter().getItem(info.position); + menu.setHeaderTitle(mSelectedContact.getJID()); + } + + private void parseArguments() { + Bundle b = getArguments(); + if (b == null) + return; + group = b.getString("group"); + } + + @Override + public boolean onContextItemSelected(MenuItem item) { + Intent in; + boolean result = false; + if (mSelectedContact != null) { + switch (item.getItemId()) { + case R.id.contact_list_context_menu_chat_item: + List res = mSelectedContact.getMRes(); + if (res.isEmpty()) { + break; + } + for (String resv : res) { + in = new Intent(hostActivity, Chat.class); + in.setData(mSelectedContact.toUri(resv)); + item.getSubMenu().add(resv).setIntent(in); + } + result = true; + break; + case R.id.contact_list_context_menu_call_item: + hostActivity.doContextMenuAction(item.getItemId(), mSelectedContact); + break; + case R.id.contact_list_context_menu_user_info: + item.getSubMenu().setHeaderTitle(mSelectedContact.getJID()); + result = true; + break; + case R.id.contact_list_context_menu_userinfo_alias: + hostActivity.doContextMenuAction(item.getItemId(), mSelectedContact); + result = true; + break; + case R.id.contact_list_context_menu_userinfo_group: + in = new Intent(hostActivity, GroupList.class); + in.putExtra("contact", mSelectedContact); + startActivity(in); + result = true; + break; + case R.id.contact_list_context_menu_userinfo_subscription: + hostActivity.doContextMenuAction(item.getItemId(), mSelectedContact); + result = true; + break; + case R.id.contact_list_context_menu_userinfo_block: + result = true; + break; + case R.id.contact_list_context_menu_userinfo_delete: + hostActivity.doContextMenuAction(item.getItemId(), mSelectedContact); + result = true; + break; + default: + result = super.onContextItemSelected(item); + break; + } + return result; + } + return super.onContextItemSelected(item); + } + +}