# HG changeset patch # User Da Risk # Date 1335127761 -7200 # Node ID ab5691925a0d3a049f7d46027bbac1533d613c40 # Parent 7483a66399dec241fdcafdafefe9cfeee3d754be Implements tab in ContactListActivity. diff -r 7483a66399de -r ab5691925a0d res/layout/contactlist_group.xml --- a/res/layout/contactlist_group.xml Sun Apr 22 20:39:31 2012 +0200 +++ b/res/layout/contactlist_group.xml Sun Apr 22 22:49:21 2012 +0200 @@ -1,5 +1,35 @@ + + + \ No newline at end of file + android:paddingLeft="20dp" android:paddingRight="20dp" + beem:principalColor="@color/vert_manu" + android:id="@+id/contactlist_group" + /> diff -r 7483a66399de -r ab5691925a0d res/layout/contactlist_groupstub.xml --- a/res/layout/contactlist_groupstub.xml Sun Apr 22 20:39:31 2012 +0200 +++ b/res/layout/contactlist_groupstub.xml Sun Apr 22 22:49:21 2012 +0200 @@ -1,10 +1,36 @@ + diff -r 7483a66399de -r ab5691925a0d src/com/beem/project/beem/ui/ContactList.java --- a/src/com/beem/project/beem/ui/ContactList.java Sun Apr 22 20:39:31 2012 +0200 +++ b/src/com/beem/project/beem/ui/ContactList.java Sun Apr 22 22:49:21 2012 +0200 @@ -42,26 +42,18 @@ */ 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.HashMap; -import java.util.LinkedList; import java.util.List; import java.util.Map; -import org.jivesoftware.smack.util.StringUtils; - 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.IBinder; import android.os.RemoteException; @@ -82,16 +74,11 @@ import android.widget.AdapterView; import android.widget.AdapterView.OnItemClickListener; import android.widget.BaseAdapter; -import android.widget.Filter; -import android.widget.Filterable; import android.widget.Gallery; -import android.widget.ImageView; import android.widget.LinearLayout; -import android.widget.TextView; import com.beem.project.beem.BeemApplication; 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.service.PresenceAdapter; import com.beem.project.beem.service.aidl.IBeemRosterListener; @@ -102,8 +89,12 @@ import com.beem.project.beem.ui.dialogs.builders.ChatList; import com.beem.project.beem.ui.dialogs.builders.DeleteContact; import com.beem.project.beem.ui.dialogs.builders.ResendSubscription; +import com.beem.project.beem.ui.views.SectionTextView; import com.beem.project.beem.utils.BeemBroadcastReceiver; +import org.jivesoftware.smack.util.StringUtils; + + /** * The contact list activity displays the roster of the user. */ @@ -115,7 +106,7 @@ } private static final String TAG = "ContactList"; - private final List mListGroup = new ArrayList(); + 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. @@ -123,20 +114,17 @@ private final Map> mContactOnGroup = new HashMap>(); private final ServiceConnection mServConn = new BeemServiceConnection(); private final BeemBroadcastReceiver mReceiver = new BeemBroadcastReceiver(); + private final BeemBanner mAdapterBanner = new BeemBanner(); + private final Map contactListAdapters = new HashMap(); private final BeemRosterListener mBeemRosterListener = new BeemRosterListener(); - private List mListContact; - private String mSelectedGroup; private IRoster mRoster; - private Contact mSelectedContact; private IXmppFacade mXmppFacade; private IChatManager mChatManager; private SharedPreferences mSettings; private LayoutInflater mInflater; - private BeemBanner mAdapterBanner; private boolean mBinded; private ViewPager viewPager; - private Map contactListAdapters = new HashMap(); private ListPagerAdapter groupsPagesAdapter; private Gallery groupGallery; @@ -201,24 +189,23 @@ this.registerReceiver(mReceiver, new IntentFilter(BeemBroadcastReceiver.BEEM_CONNECTION_CLOSED)); mInflater = getLayoutInflater(); - mAdapterBanner = new BeemBanner(); - mListContact = new ArrayList(); - + viewPager = (ViewPager) findViewById(R.id.pager); + viewPager.setOnPageChangeListener(new OnPageChangeListener()); 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(); + + mListGroup.add(new GroupHolder(getString(R.string.contact_list_all_contact))); + mListGroup.add(new GroupHolder(getString(R.string.contact_list_no_group))); + mAdapterBanner.notifyDataSetChanged(); } @Override protected void onStart() { super.onStart(); - if (!mSettings.getBoolean(BeemApplication.HIDE_GROUPS_KEY, false)) - showGroups(); - else - hideGroups(); + if (!mSettings.getBoolean(BeemApplication.HIDE_GROUPS_KEY, false)) + showGroups(); + else + hideGroups(); if (!mBinded) mBinded = bindService(SERVICE_INTENT, mServConn, BIND_AUTO_CREATE); @@ -253,6 +240,65 @@ } /** + * Get a {@link ContactListAdapter} for a group. + * The {@link ContactListAdapter} will be created if it is not exist. + * @param group the group + * @return the adapter + */ + ContactListAdapter getContactListAdapter(String group) { + synchronized (contactListAdapters) { + ContactListAdapter contactListAdapter = contactListAdapters.get(group); + if (contactListAdapter == null) { + contactListAdapter = new ContactListAdapter(ContactList.this); + contactListAdapters.put(group, contactListAdapter); + if (!GroupHolder.contains(mListGroup, group)) { + GroupHolder gh = new GroupHolder(group); + mListGroup.add(mListGroup.size() - 1, gh); + groupsPagesAdapter.notifyDataSetChanged(); + mAdapterBanner.notifyDataSetChanged(); + } + } + boolean hideDisconnected = mSettings.getBoolean(BeemApplication.SHOW_OFFLINE_CONTACTS_KEY, false); + contactListAdapter.setOnlineOnly(hideDisconnected); + return contactListAdapter; + } + } + + /** + * Exectute a context menu action on a specified contact. + * @param itemId the id of the menu action + * @param contact the contact + */ + 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; + } + + } + + /** * Show the groups view. */ private void showGroups() { @@ -269,6 +315,7 @@ groupGallery = (Gallery) findViewById(R.id.contactlist_banner); groupGallery.setSelection(0); } + GroupHolder.setUniquePrincipal(mListGroup, 0); } /** @@ -280,57 +327,41 @@ 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(); - } + * 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(); + Collections.sort(rosterGroups); + List realGroups = mListGroup.subList(1, mListGroup.size() - 1); + realGroups.clear(); + realGroups.addAll(GroupHolder.createFrom(rosterGroups)); + // restore principal + GroupHolder.setUniquePrincipal(mListGroup, viewPager.getCurrentItem()); + 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)); + /** + * 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); - if (groups.isEmpty()) { - adapter = getContactListAdapter(getString(R.string.contact_list_no_group)); - adapter.put(contact); - } - } + } /** * Listener on service event. @@ -357,7 +388,6 @@ final Contact contact = mRoster.getContact(StringUtils.parseBareAddress(newName)); putContactInList(contact); } - } /** @@ -373,16 +403,16 @@ for (String cToDelete : addresses) { final Contact contact = new Contact(cToDelete); for (final ContactListAdapter adapter : contactListAdapters.values()) { - runOnUiThread(new Runnable() { - - @Override - public void run() { - adapter.remove(contact); - } - }); + runOnUiThread(new Runnable() { + + @Override + public void run() { + adapter.remove(contact); + } + }); } } - cleanBannerGroup(); + cleanBannerGroup(); } @@ -401,14 +431,14 @@ for (String cToDelete : addresses) { Contact contact = new Contact(cToDelete); for (ContactListAdapter adapter : contactListAdapters.values()) { - adapter.remove(contact); + adapter.remove(contact); } } for (String newName : addresses) { - final Contact contact = mRoster.getContact(StringUtils.parseBareAddress(newName)); - putContactInList(contact); + final Contact contact = mRoster.getContact(StringUtils.parseBareAddress(newName)); + putContactInList(contact); } - cleanBannerGroup(); + cleanBannerGroup(); } /** @@ -427,29 +457,33 @@ putContactInList(contact); } - 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); - } - }); - } + /** + * Put a contact in the different group list. + * @param contact the contact + */ + 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 banner list. */ @@ -478,11 +512,13 @@ @Override public View getView(int position, View convertView, ViewGroup parent) { - View v = convertView; + SectionTextView v = (SectionTextView) convertView; if (convertView == null) { - v = mInflater.inflate(R.layout.contactlist_group, null); + v = (SectionTextView) mInflater.inflate(R.layout.contactlist_group, null); } - ((TextView) v).setText(mListGroup.get(position)); + GroupHolder gh = (GroupHolder) getItem(position); + v.setText(gh.group); + v.setPrincipal(gh.isPrincipal); return v; } } @@ -505,19 +541,14 @@ mRoster = mXmppFacade.getRoster(); if (mRoster != null) { List tmpGroupList = mRoster.getGroupsNames(); - Collections.sort(tmpGroupList); cleanBannerGroup(); - mListGroup.addAll(1, tmpGroupList); synchronized (contactListAdapters) { - for (ContactListAdapter ca : contactListAdapters.values()) { - ca.clear(); - } + for (ContactListAdapter ca : contactListAdapters.values()) { + ca.clear(); } - groupsPagesAdapter.notifyDataSetChanged(); - mAdapterBanner.notifyDataSetChanged(); + } + assignContactToGroups(mRoster.getContactList(), tmpGroupList); - assignContactToGroups(mRoster.getContactList(), tmpGroupList); - mRoster.addRosterListener(mBeemRosterListener); Log.d(TAG, "add roster listener"); mChatManager = mXmppFacade.getChatManager(); @@ -537,7 +568,6 @@ mXmppFacade = null; mChatManager = null; mRoster = null; - mListContact.clear(); mListGroup.clear(); mContactOnGroup.clear(); mBinded = false; @@ -553,21 +583,39 @@ */ private void assignContactToGroups(List contacts, List groupNames) { for (Contact c : contacts) { - addToSpecialList(c); + addToSpecialList(c); List groups = c.getGroups(); - for (String currentGroup : groups) { - ContactListAdapter cl = getContactListAdapter(currentGroup); + for (String currentGroup : groups) { + ContactListAdapter cl = getContactListAdapter(currentGroup); cl.put(c); - } - + } } } } + /** + * Listener on page change event. + */ + private class OnPageChangeListener extends ViewPager.SimpleOnPageChangeListener { + + /** + * Create a {@link OnPageChangeListener}. + */ + public OnPageChangeListener() { + } + @Override + public void onPageSelected(int position) { + GroupHolder.setUniquePrincipal(mListGroup, position); + if (groupGallery != null) { + groupGallery.setSelection(position); + } + mAdapterBanner.notifyDataSetChanged(); + } + } /** * Event simple click on middle groupe name. @@ -586,55 +634,92 @@ } } + /** + * PagerAdapter for the contact list. + */ private class ListPagerAdapter extends FragmentPagerAdapter { - public ListPagerAdapter(FragmentManager fm, ViewPager viewPager) { - super(fm); - viewPager.setAdapter(this); - } + /** + * Create a {@link ListPagerAdapter}. + * @param fm the {@link FragmentManager} + * @param viewPager the {@link ViewPager} associate with this adapter + */ + public ListPagerAdapter(final FragmentManager fm, final 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 Fragment getItem(int position) { + String group = mListGroup.get(position).group; + ContactListFragment f = ContactListFragment.newInstance(group); + f.setListAdapter(getContactListAdapter(group)); + return f; + } - @Override - public int getCount() { - return mListGroup.size(); - } - + @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; + /** + * A holder for a group name and is principal state. + * It is an helper class to manage the state of the tabs. + */ + private static class GroupHolder { + + String group; + boolean isPrincipal; + + /** + * Create a {@link GroupHolder}. + * @param group the group name + */ + public GroupHolder(final String group) { + this.group = group; + } + + /** + * Create a list of GroupHolder. + * @param groups list of group name + * @return a list of {@link GroupHolder} + */ + public static List createFrom(List groups) { + List result = new ArrayList(); + for (String s : groups) { + result.add(new GroupHolder(s)); } - + return result; } + /** + * Test if a group exist in a list of {@link GroupHolder}. + * @param list the list + * @param group the group + * @return true if the group is in the list false otherwise + */ + public static boolean contains(List list, String group) { + for (GroupHolder groupHolder : list) { + if (groupHolder.group.equals(group)) + return true; + } + return false; + } + + /** + * Set a unique principal in the {@link GroupHolder} list. + * @param groups the list + * @param position the position of the principal + */ + public static void setUniquePrincipal(List groups, int position) { + for (GroupHolder gh : groups) { + gh.isPrincipal = false; + } + groups.get(position).isPrincipal = true; + } + } + + } diff -r 7483a66399de -r ab5691925a0d src/com/beem/project/beem/ui/ContactListFragment.java --- a/src/com/beem/project/beem/ui/ContactListFragment.java Sun Apr 22 20:39:31 2012 +0200 +++ b/src/com/beem/project/beem/ui/ContactListFragment.java Sun Apr 22 22:49:21 2012 +0200 @@ -1,30 +1,22 @@ 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;