New list with sticky list headers library
This commit is contained in:
@@ -24,6 +24,9 @@ import org.sufficientlysecure.keychain.provider.KeychainContract.KeyRings;
|
||||
import org.sufficientlysecure.keychain.provider.KeychainContract.UserIds;
|
||||
import org.sufficientlysecure.keychain.ui.adapter.KeyListPublicAdapter;
|
||||
|
||||
import se.emilsjolander.stickylistheaders.ApiLevelTooLowException;
|
||||
import se.emilsjolander.stickylistheaders.StickyListHeadersListView;
|
||||
import android.annotation.SuppressLint;
|
||||
import android.content.Intent;
|
||||
import android.database.Cursor;
|
||||
import android.net.Uri;
|
||||
@@ -31,58 +34,84 @@ import android.os.Bundle;
|
||||
import android.support.v4.app.LoaderManager;
|
||||
import android.support.v4.content.CursorLoader;
|
||||
import android.support.v4.content.Loader;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.AdapterView;
|
||||
import android.widget.AdapterView.OnItemClickListener;
|
||||
|
||||
import com.actionbarsherlock.app.SherlockListFragment;
|
||||
import com.actionbarsherlock.app.SherlockFragment;
|
||||
|
||||
public class KeyListPublicFragment extends SherlockListFragment implements
|
||||
LoaderManager.LoaderCallbacks<Cursor> {
|
||||
/**
|
||||
* Public key list with sticky list headers.
|
||||
*
|
||||
* - uses StickyListHeaders library
|
||||
* - custom adapter: KeyListPublicAdapter
|
||||
*
|
||||
* TODO:
|
||||
* - fix loader with spinning animation
|
||||
* - fix design
|
||||
* - fix view holder in adapter
|
||||
*
|
||||
*/
|
||||
public class KeyListPublicFragment extends SherlockFragment implements
|
||||
AdapterView.OnItemClickListener, LoaderManager.LoaderCallbacks<Cursor> {
|
||||
|
||||
private KeyListPublicActivity mKeyListPublicActivity;
|
||||
|
||||
private KeyListPublicAdapter mAdapter;
|
||||
|
||||
StickyListHeadersListView stickyList;
|
||||
|
||||
/**
|
||||
* Define Adapter and Loader on create of Activity
|
||||
*/
|
||||
@SuppressLint("NewApi")
|
||||
@Override
|
||||
public void onActivityCreated(Bundle savedInstanceState) {
|
||||
super.onActivityCreated(savedInstanceState);
|
||||
|
||||
mKeyListPublicActivity = (KeyListPublicActivity) getActivity();
|
||||
|
||||
getListView().setOnItemClickListener(new OnItemClickListener() {
|
||||
@Override
|
||||
public void onItemClick(AdapterView<?> adapterView, View view, int position, long id) {
|
||||
// start key view on click
|
||||
Intent detailsIntent = new Intent(mKeyListPublicActivity, KeyViewActivity.class);
|
||||
detailsIntent.setData(KeychainContract.KeyRings.buildPublicKeyRingsUri(Long
|
||||
.toString(id)));
|
||||
startActivity(detailsIntent);
|
||||
}
|
||||
});
|
||||
stickyList = (StickyListHeadersListView) getActivity().findViewById(
|
||||
R.id.key_list_public_fragment_stickylist);
|
||||
|
||||
stickyList.setOnItemClickListener(this);
|
||||
// stickyList.setOnHeaderClickListener(this);
|
||||
// stickyList.setOnStickyHeaderOffsetChangedListener(this);
|
||||
// mStickyList.addHeaderView(inflater.inflate(R.layout.list_header, null));
|
||||
// mStickyList.addFooterView(inflater.inflate(R.layout.list_footer, null));
|
||||
// stickyList.setEmptyView(findViewById(R.id.empty));
|
||||
stickyList.setAreHeadersSticky(true);
|
||||
stickyList.setDrawingListUnderStickyHeader(true);
|
||||
stickyList.setFastScrollEnabled(true);
|
||||
try {
|
||||
stickyList.setFastScrollAlwaysVisible(true);
|
||||
} catch (ApiLevelTooLowException e) {
|
||||
}
|
||||
|
||||
// Give some text to display if there is no data. In a real
|
||||
// application this would come from a resource.
|
||||
setEmptyText(getString(R.string.list_empty));
|
||||
|
||||
// We have a menu item to show in action bar.
|
||||
setHasOptionsMenu(true);
|
||||
// setEmptyText(getString(R.string.list_empty));
|
||||
|
||||
// Start out with a progress indicator.
|
||||
setListShown(false);
|
||||
// setListShown(false);
|
||||
|
||||
// Create an empty adapter we will use to display the loaded data.
|
||||
mAdapter = new KeyListPublicAdapter(mKeyListPublicActivity, null, Id.type.public_key);
|
||||
setListAdapter(mAdapter);
|
||||
// mAdapter = new KeyListPublicAdapter(mKeyListPublicActivity, null, Id.type.public_key);
|
||||
// setListAdapter(mAdapter);
|
||||
// stickyList.setAdapter(mAdapter);
|
||||
|
||||
// Prepare the loader. Either re-connect with an existing one,
|
||||
// or start a new one.
|
||||
getLoaderManager().initLoader(0, null, this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
|
||||
View view = inflater.inflate(R.layout.key_list_public_fragment, container, false);
|
||||
return view;
|
||||
}
|
||||
|
||||
// These are the rows that we will retrieve.
|
||||
static final String[] PROJECTION = new String[] { KeyRings._ID, KeyRings.MASTER_KEY_ID,
|
||||
UserIds.USER_ID };
|
||||
@@ -104,13 +133,19 @@ public class KeyListPublicFragment extends SherlockListFragment implements
|
||||
public void onLoadFinished(Loader<Cursor> loader, Cursor data) {
|
||||
// Swap the new cursor in. (The framework will take care of closing the
|
||||
// old cursor once we return.)
|
||||
mAdapter.swapCursor(data);
|
||||
// mAdapter.swapCursor(data);
|
||||
int userIdIndex = data.getColumnIndex(UserIds.USER_ID);
|
||||
|
||||
mAdapter = new KeyListPublicAdapter(mKeyListPublicActivity, data, Id.type.public_key,
|
||||
userIdIndex);
|
||||
|
||||
stickyList.setAdapter(mAdapter);
|
||||
|
||||
// The list should now be shown.
|
||||
if (isResumed()) {
|
||||
setListShown(true);
|
||||
// setListShown(true);
|
||||
} else {
|
||||
setListShownNoAnimation(true);
|
||||
// setListShownNoAnimation(true);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -122,4 +157,12 @@ public class KeyListPublicFragment extends SherlockListFragment implements
|
||||
mAdapter.swapCursor(null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onItemClick(AdapterView<?> adapterView, View view, int position, long id) {
|
||||
// start key view on click
|
||||
Intent detailsIntent = new Intent(mKeyListPublicActivity, KeyViewActivity.class);
|
||||
detailsIntent.setData(KeychainContract.KeyRings.buildPublicKeyRingsUri(Long.toString(id)));
|
||||
startActivity(detailsIntent);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -17,30 +17,40 @@
|
||||
|
||||
package org.sufficientlysecure.keychain.ui.adapter;
|
||||
|
||||
import org.sufficientlysecure.keychain.Constants;
|
||||
import org.sufficientlysecure.keychain.R;
|
||||
import org.sufficientlysecure.keychain.helper.OtherHelper;
|
||||
import org.sufficientlysecure.keychain.provider.KeychainContract.UserIds;
|
||||
import org.sufficientlysecure.keychain.util.SectionCursorAdapter;
|
||||
import org.sufficientlysecure.keychain.util.Log;
|
||||
|
||||
import se.emilsjolander.stickylistheaders.StickyListHeadersAdapter;
|
||||
import android.content.Context;
|
||||
import android.database.Cursor;
|
||||
import android.support.v4.widget.CursorAdapter;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.TextView;
|
||||
|
||||
public class KeyListPublicAdapter extends SectionCursorAdapter {
|
||||
|
||||
/**
|
||||
* - implements StickyListHeadersAdapter from library - uses view holder pattern for performance
|
||||
*
|
||||
*/
|
||||
public class KeyListPublicAdapter extends CursorAdapter implements StickyListHeadersAdapter {
|
||||
private LayoutInflater mInflater;
|
||||
|
||||
public KeyListPublicAdapter(Context context, Cursor c, int flags) {
|
||||
super(context, c, android.R.layout.preference_category, 2); // TODO: 2 is user id
|
||||
int mSectionColumnIndex;
|
||||
|
||||
public KeyListPublicAdapter(Context context, Cursor c, int flags, int sectionColumnIndex) {
|
||||
super(context, c, flags);
|
||||
|
||||
mInflater = LayoutInflater.from(context);
|
||||
mSectionColumnIndex = sectionColumnIndex;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void bindView(View view, Context context, Cursor cursor) {
|
||||
// TODO: view holder pattern?
|
||||
int userIdIndex = cursor.getColumnIndex(UserIds.USER_ID);
|
||||
|
||||
TextView mainUserId = (TextView) view.findViewById(R.id.mainUserId);
|
||||
@@ -74,4 +84,64 @@ public class KeyListPublicAdapter extends SectionCursorAdapter {
|
||||
return mInflater.inflate(R.layout.key_list_group_item, null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public View getHeaderView(int position, View convertView, ViewGroup parent) {
|
||||
|
||||
HeaderViewHolder holder;
|
||||
if (convertView == null) {
|
||||
holder = new HeaderViewHolder();
|
||||
convertView = mInflater.inflate(R.layout.stickylist_header, parent, false);
|
||||
holder.text = (TextView) convertView.findViewById(R.id.stickylist_header_text);
|
||||
convertView.setTag(holder);
|
||||
} else {
|
||||
holder = (HeaderViewHolder) convertView.getTag();
|
||||
}
|
||||
|
||||
if (!mDataValid) {
|
||||
// no data available at this point
|
||||
Log.d(Constants.TAG, "getHeaderView: No data available at this point!");
|
||||
return convertView;
|
||||
}
|
||||
|
||||
// similar to getView in CursorAdapter
|
||||
if (!mCursor.moveToPosition(position)) {
|
||||
throw new IllegalStateException("couldn't move cursor to position " + position);
|
||||
}
|
||||
|
||||
// set header text as first char in name
|
||||
String headerText = "" + mCursor.getString(mSectionColumnIndex).subSequence(0, 1).charAt(0);
|
||||
holder.text.setText(headerText);
|
||||
return convertView;
|
||||
}
|
||||
|
||||
/**
|
||||
* Remember that these have to be static, position=1 should always return the same Id that is.
|
||||
*/
|
||||
@Override
|
||||
public long getHeaderId(int position) {
|
||||
if (!mDataValid) {
|
||||
// no data available at this point
|
||||
Log.d(Constants.TAG, "getHeaderView: No data available at this point!");
|
||||
return -1;
|
||||
}
|
||||
|
||||
// similar to getView in CursorAdapter
|
||||
if (!mCursor.moveToPosition(position)) {
|
||||
throw new IllegalStateException("couldn't move cursor to position " + position);
|
||||
}
|
||||
|
||||
// return the first character of the name as ID because this is what
|
||||
// headers are based upon
|
||||
return mCursor.getString(mSectionColumnIndex).subSequence(0, 1).charAt(0);
|
||||
}
|
||||
|
||||
class HeaderViewHolder {
|
||||
TextView text;
|
||||
}
|
||||
|
||||
class ViewHolder {
|
||||
TextView mainUserId;
|
||||
TextView mainUserIdRest;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,50 @@
|
||||
package se.emilsjolander.stickylistheaders.views;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.res.Resources;
|
||||
import android.graphics.Canvas;
|
||||
import android.graphics.Paint;
|
||||
import android.util.AttributeSet;
|
||||
import android.util.TypedValue;
|
||||
import android.widget.TextView;
|
||||
|
||||
/**
|
||||
* @author Eric Frohnhoefer
|
||||
*/
|
||||
public class UnderlineTextView extends TextView {
|
||||
private final Paint mPaint = new Paint();
|
||||
private int mUnderlineHeight = 0;
|
||||
|
||||
public UnderlineTextView(Context context) {
|
||||
this(context, null);
|
||||
}
|
||||
|
||||
public UnderlineTextView(Context context, AttributeSet attrs) {
|
||||
this(context, attrs, 0);
|
||||
}
|
||||
|
||||
public UnderlineTextView(Context context, AttributeSet attrs, int defStyle) {
|
||||
super(context, attrs, defStyle);
|
||||
|
||||
init(context, attrs);
|
||||
}
|
||||
|
||||
private void init(Context context, AttributeSet attrs) {
|
||||
Resources r = getResources();
|
||||
mUnderlineHeight = (int)TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 2, r.getDisplayMetrics());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setPadding(int left, int top, int right, int bottom) {
|
||||
super.setPadding(left, top, right, bottom + mUnderlineHeight);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onDraw(Canvas canvas) {
|
||||
super.onDraw(canvas);
|
||||
|
||||
// Draw the underline the same color as the text
|
||||
mPaint.setColor(getTextColors().getDefaultColor());
|
||||
canvas.drawRect(0, getHeight() - mUnderlineHeight, getWidth(), getHeight(), mPaint);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user