From f7053600f46fce42b2df4e5e8e6920d7f9fbe822 Mon Sep 17 00:00:00 2001 From: alision <alexandre.lision@savoirfairelinux.com> Date: Tue, 9 Jul 2013 10:25:20 -0400 Subject: [PATCH] * #26858 Added fast scrollbar and alphabetic sections --- res/layout/activity_sflphone_home.xml | 3 - res/layout/frag_contact_list.xml | 1 + res/layout/header.xml | 20 ++ .../sflphone/adapters/ContactsAdapter.java | 289 ++++++++++++++++-- .../sflphone/views/CustomSlidingDrawer.java | 4 +- 5 files changed, 290 insertions(+), 27 deletions(-) create mode 100644 res/layout/header.xml diff --git a/res/layout/activity_sflphone_home.xml b/res/layout/activity_sflphone_home.xml index 1db2c458e..6495795d4 100644 --- a/res/layout/activity_sflphone_home.xml +++ b/res/layout/activity_sflphone_home.xml @@ -122,9 +122,6 @@ as that of the covered work. android:background="@color/light" android:src="@drawable/ic_btn_search" - android:clickable="true" - android:focusable="true" - android:focusableInTouchMode="true" android:gravity="center" > </ImageButton> </RelativeLayout> diff --git a/res/layout/frag_contact_list.xml b/res/layout/frag_contact_list.xml index 1002096c9..8193cde48 100644 --- a/res/layout/frag_contact_list.xml +++ b/res/layout/frag_contact_list.xml @@ -45,6 +45,7 @@ as that of the covered work. android:layout_height="match_parent" android:clickable="true" android:focusable="true" + android:fastScrollEnabled="true" android:focusableInTouchMode="true" /> <TextView diff --git a/res/layout/header.xml b/res/layout/header.xml new file mode 100644 index 000000000..3240f1165 --- /dev/null +++ b/res/layout/header.xml @@ -0,0 +1,20 @@ +<?xml version="1.0" encoding="utf-8"?> +<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" + android:layout_width="match_parent" + android:layout_height="match_parent" + android:background="@color/holo_orange_light" + android:clickable="false" + android:focusable="false" + android:orientation="vertical" > + + <TextView + android:id="@+id/header_letter" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:clickable="false" + android:focusable="false" + android:paddingLeft="5dp" + android:textSize="14sp" + android:textStyle="bold" /> + +</LinearLayout> \ No newline at end of file diff --git a/src/com/savoirfairelinux/sflphone/adapters/ContactsAdapter.java b/src/com/savoirfairelinux/sflphone/adapters/ContactsAdapter.java index f84ce078d..b27c85ff7 100644 --- a/src/com/savoirfairelinux/sflphone/adapters/ContactsAdapter.java +++ b/src/com/savoirfairelinux/sflphone/adapters/ContactsAdapter.java @@ -1,77 +1,322 @@ package com.savoirfairelinux.sflphone.adapters; import java.util.ArrayList; +import java.util.Collections; +import java.util.HashMap; +import java.util.Locale; +import java.util.Set; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import android.content.Context; +import android.util.Log; +import android.util.SparseArray; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.widget.BaseAdapter; import android.widget.ImageView; +import android.widget.SectionIndexer; import android.widget.TextView; import com.savoirfairelinux.sflphone.R; import com.savoirfairelinux.sflphone.model.CallContact; -public class ContactsAdapter extends BaseAdapter { +public class ContactsAdapter extends BaseAdapter implements SectionIndexer { private ExecutorService infos_fetcher = Executors.newCachedThreadPool(); - private ArrayList<CallContact> dataset; Context mContext; + HashMap<String, Integer> alphaIndexer; + String[] sections; + private static final String TAG = ContactsAdapter.class.getSimpleName(); public ContactsAdapter(Context context) { super(); mContext = context; - dataset = new ArrayList<CallContact>(); + alphaIndexer = new HashMap<String, Integer>(); + headers = new HeadersHolder(new ArrayList<CallContact>()); + } + + HeadersHolder headers; + private static final int TYPE_HEADER = 0; + private static final int TYPE_TRACK = 1; + + @Override + public View getView(int position, View convertView, ViewGroup parent) { + int type = getItemViewType(position); + +// Log.i(TAG, "positon" + position + " type " + type); + LayoutInflater inflater = (LayoutInflater) mContext.getSystemService(Context.LAYOUT_INFLATER_SERVICE); + + switch (type) { + case TYPE_TRACK: + return getViewTrack(position, inflater, convertView); + case TYPE_HEADER: + return getViewHeader(position, inflater, convertView); + } + return null; + } + + private View getViewHeader(int position, LayoutInflater inflater, View convertView) { + if (convertView == null) { + convertView = inflater.inflate(R.layout.header, null); + } + TextView name = (TextView) convertView.findViewById(R.id.header_letter); + name.setText(headers.getSection(position)); + return convertView; + } + + private View getViewTrack(int position, LayoutInflater inflater, View convertView) { + + if (convertView == null) { + convertView = inflater.inflate(R.layout.item_contact, null); + } + + CallContact item = headers.getCallContact(position); + + ((TextView) convertView.findViewById(R.id.display_name)).setText(item.getmDisplayName()); + ImageView photo_view = (ImageView) convertView.findViewById(R.id.photo); + + infos_fetcher.execute(new ContactPictureLoader(mContext, photo_view, item.getId())); + + return convertView; + } + + @Override + public int getCount() { + return headers.size() + headers.getSections().size(); + } + + @Override + public int getItemViewType(int pos) { + return (headers.contains(pos) ? TYPE_HEADER : TYPE_TRACK); + } + + @Override + public int getViewTypeCount() { + return 2; + } + + + + @Override + public long getItemId(int position) { + return 0; } public void removeAll() { - dataset.clear(); + headers.clear(); notifyDataSetChanged(); } - public void addAll(ArrayList<CallContact> arrayList) { - dataset.addAll(arrayList); + public void add(CallContact tr) { + headers.add(tr); + headers.buildIndex(); + } + + public void addAll(ArrayList<CallContact> tr) { + headers = new HeadersHolder(tr); notifyDataSetChanged(); } + @Override - public int getCount() { - return dataset.size(); + public int getPositionForSection(int section) { + return headers.getPositionFor(section); } @Override - public CallContact getItem(int index) { - return dataset.get(index); + public int getSectionForPosition(int position) { + return headers.getSectionFor(position); } @Override - public long getItemId(int index) { - return dataset.get(index).getId(); + public Object[] getSections() { + return headers.getSectionsArray(); + } + + public int getRealPosition(int pos) { + return headers.getTrackPosition(pos); } @Override - public View getView(int pos, View convView, ViewGroup parent) { + public CallContact getItem(int index) { + return headers.getCallContact(index); + } + + public class HeadersHolder { - View v = convView; - LayoutInflater inflater = (LayoutInflater) mContext.getSystemService(Context.LAYOUT_INFLATER_SERVICE); + public static final String TAG = "HeadersHolder"; + HashMap<String, Integer> alphaIndexer; + ArrayList<CallContact> contacts; + + String[] sectionsArray; - if (v == null) { - v = inflater.inflate(R.layout.item_contact, null); + public String[] getSectionsArray() { + return sectionsArray; } - CallContact item = dataset.get(pos); + int headersCount; + private SparseArray<Item> items = new SparseArray<Item>(); - ((TextView) v.findViewById(R.id.display_name)).setText(item.getmDisplayName()); - ImageView photo_view = (ImageView) v.findViewById(R.id.photo); + public SparseArray<Item> getItems() { + return items; + } - infos_fetcher.execute(new ContactPictureLoader(mContext, photo_view, item.getId())); + public void setItems(SparseArray<Item> items) { + this.items = items; + } + + public SparseArray<Section> getSections() { + return sections; + } + + public void setSections(SparseArray<Section> sections) { + this.sections = sections; + } + + private SparseArray<Section> sections = new SparseArray<Section>(); + + public HeadersHolder(ArrayList<CallContact> a) { + alphaIndexer = new HashMap<String, Integer>(); + contacts = a; + headersCount = 0; + buildIndex(); + } + + // public int getHeadersCount() { + // return headersCount; + // } + + private class Item { + public Item(int rpos, int headersCount2, CallContact track) { +// Log.i(TAG, "Creating Item"); + + sectionNumber = headersCount2; + realPos = rpos; + tr = track; + + } + + public int realPos; + public int sectionNumber; + public CallContact tr; + } + + private class Section { + public int startPosition; + public int number; + public String header; + + public Section(int i, int headersCount, String str) { +// Log.i(TAG, "Creating section"); + + startPosition = i + headersCount; + number = headersCount; + header = str; + + } + + @Override + public String toString() { + return header; + } + } + + public void buildIndex() { + + for (int x = 0; x < contacts.size(); x++) { + String s = contacts.get(x).getmDisplayName(); + String ch = s.substring(0, 1); + ch = ch.toUpperCase(Locale.CANADA); + if (!alphaIndexer.containsKey(ch)) { + sections.put(x + headersCount, new Section(x, headersCount, ch)); + headersCount++; + } + Integer result = alphaIndexer.put(ch, x + headersCount); + items.put(x + headersCount, new Item(x, headersCount, contacts.get(x))); + if (result == null) { + + } + } + + Set<String> sect = alphaIndexer.keySet(); + + // create a list from the set to sort + ArrayList<String> sectionList = new ArrayList<String>(sect); + Collections.sort(sectionList); + sectionsArray = new String[sectionList.size()]; + sectionList.toArray(sectionsArray); + + } + + public HashMap<String, Integer> getAlphaIndexer() { + return alphaIndexer; + } + + public int getPositionFor(int section) { + if (section == sectionsArray.length) + return sectionsArray.length; + return alphaIndexer.get(sectionsArray[section]); + } + + public int getSectionFor(int position) { + return (null != items.get(position)) ? items.get(position).sectionNumber : sections.get(position).number; + } + + public boolean contains(int pos) { + if (sections.get(pos) != null) { + return true; + } + return false; + } + + public CallContact getCallContact(int position) { + + if (items.get(position) == null) + return null; + + return items.get(position).tr; + + } + + public int size() { + return contacts.size(); + } + + public void clear() { + contacts.clear(); + + } + + public void add(CallContact tr) { + contacts.add(tr); + + } + + public void addAll(ArrayList<CallContact> tr) { + contacts.clear(); + contacts.addAll(tr); + + } + + public ArrayList<CallContact> getTracks() { + return contacts; + } + + public int getTrackPosition(int pos) { + if (sections.get(pos) != null) { + return items.get(pos + 1).realPos; + } + return items.get(pos).realPos; + } + + public CharSequence getSection(int position) { + return sections.get(position).header; + } - return v; } } diff --git a/src/com/savoirfairelinux/sflphone/views/CustomSlidingDrawer.java b/src/com/savoirfairelinux/sflphone/views/CustomSlidingDrawer.java index 7b9eb6e65..9c9748990 100644 --- a/src/com/savoirfairelinux/sflphone/views/CustomSlidingDrawer.java +++ b/src/com/savoirfairelinux/sflphone/views/CustomSlidingDrawer.java @@ -332,7 +332,7 @@ public class CustomSlidingDrawer extends ViewGroup { @Override public boolean onInterceptTouchEvent(MotionEvent event) { - Log.i(TAG, "onInterceptTouchEvent"); +// Log.i(TAG, "onInterceptTouchEvent"); if (mLocked) { Log.i(TAG, "Locked"); return false; @@ -402,7 +402,7 @@ public class CustomSlidingDrawer extends ViewGroup { return true; } - Log.i(TAG, "onTouchEvent"); +// Log.i(TAG, "onTouchEvent"); if (mTracking) { mVelocityTracker.addMovement(event); final int action = event.getAction(); -- GitLab