aboutsummaryrefslogtreecommitdiffstats
path: root/OpenPGP-Keychain
diff options
context:
space:
mode:
authorDominik Schürmann <dominik@dominikschuermann.de>2014-01-02 21:10:08 +0100
committerDominik Schürmann <dominik@dominikschuermann.de>2014-01-02 21:10:08 +0100
commitf5da63f9882e1807c6bd2adb5205ad7482c45339 (patch)
tree95b034a7a80d2e3ea8343440d617db993f4fca59 /OpenPGP-Keychain
parent1d91804dc7943e7149d02141a46c3eb0763e2b94 (diff)
downloadopen-keychain-f5da63f9882e1807c6bd2adb5205ad7482c45339.tar.gz
open-keychain-f5da63f9882e1807c6bd2adb5205ad7482c45339.tar.bz2
open-keychain-f5da63f9882e1807c6bd2adb5205ad7482c45339.zip
New list with sticky list headers library
Diffstat (limited to 'OpenPGP-Keychain')
-rw-r--r--OpenPGP-Keychain/AndroidManifest.xml6
-rw-r--r--OpenPGP-Keychain/build.gradle3
-rw-r--r--OpenPGP-Keychain/project.properties1
-rw-r--r--OpenPGP-Keychain/res/drawable/header_selector.xml7
-rw-r--r--OpenPGP-Keychain/res/layout/key_list_public_activity.xml13
-rw-r--r--OpenPGP-Keychain/res/layout/key_list_public_fragment.xml14
-rw-r--r--OpenPGP-Keychain/res/layout/key_list_secret_activity.xml13
-rw-r--r--OpenPGP-Keychain/res/layout/stickylist_header.xml17
-rw-r--r--OpenPGP-Keychain/res/values/colors.xml5
-rw-r--r--OpenPGP-Keychain/res/values/strings.xml1
-rw-r--r--OpenPGP-Keychain/src/org/sufficientlysecure/keychain/ui/KeyListPublicFragment.java93
-rw-r--r--OpenPGP-Keychain/src/org/sufficientlysecure/keychain/ui/adapter/KeyListPublicAdapter.java80
-rw-r--r--OpenPGP-Keychain/src/se/emilsjolander/stickylistheaders/views/UnderlineTextView.java50
13 files changed, 242 insertions, 61 deletions
diff --git a/OpenPGP-Keychain/AndroidManifest.xml b/OpenPGP-Keychain/AndroidManifest.xml
index be9fe222c..8433323f4 100644
--- a/OpenPGP-Keychain/AndroidManifest.xml
+++ b/OpenPGP-Keychain/AndroidManifest.xml
@@ -88,8 +88,7 @@
android:name=".ui.KeyListPublicActivity"
android:configChanges="orientation|screenSize|keyboardHidden|keyboard"
android:label="@string/title_manage_public_keys"
- android:launchMode="singleTop"
- android:uiOptions="splitActionBarWhenNarrow" >
+ android:launchMode="singleTop" >
<!-- <intent-filter> -->
<!-- <action android:name="android.intent.action.SEARCH" /> -->
@@ -104,8 +103,7 @@
android:name=".ui.KeyListSecretActivity"
android:configChanges="orientation|screenSize|keyboardHidden|keyboard"
android:label="@string/title_manage_secret_keys"
- android:launchMode="singleTop"
- android:uiOptions="splitActionBarWhenNarrow" >
+ android:launchMode="singleTop" >
<!-- <intent-filter> -->
<!-- <action android:name="android.intent.action.SEARCH" /> -->
diff --git a/OpenPGP-Keychain/build.gradle b/OpenPGP-Keychain/build.gradle
index 80c0f05cd..f31b6908c 100644
--- a/OpenPGP-Keychain/build.gradle
+++ b/OpenPGP-Keychain/build.gradle
@@ -4,6 +4,7 @@ buildscript {
}
dependencies {
+ // NOTE: Avoid using dynamic versions (+). This breaks offline builds!
classpath 'com.android.tools.build:gradle:0.6.3'
}
}
@@ -22,7 +23,7 @@ dependencies {
compile 'com.android.support:support-v4:18.0.+' // already in actionbarsherlock
compile project(':libraries:ActionBarSherlock')
compile project(':libraries:HtmlTextView')
- compile project(':libraries:pinned-section-listview:library')
+ compile project(':libraries:StickyListHeaders:library')
}
android {
diff --git a/OpenPGP-Keychain/project.properties b/OpenPGP-Keychain/project.properties
index 7acfa6b58..8e240f3c3 100644
--- a/OpenPGP-Keychain/project.properties
+++ b/OpenPGP-Keychain/project.properties
@@ -11,3 +11,4 @@
target=android-19
android.library.reference.1=../libraries/ActionBarSherlock
android.library.reference.2=../libraries/HtmlTextView
+android.library.reference.3=../libraries/StickyListHeaders/library
diff --git a/OpenPGP-Keychain/res/drawable/header_selector.xml b/OpenPGP-Keychain/res/drawable/header_selector.xml
new file mode 100644
index 000000000..5dfb8265c
--- /dev/null
+++ b/OpenPGP-Keychain/res/drawable/header_selector.xml
@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="utf-8"?>
+<selector xmlns:android="http://schemas.android.com/apk/res/android" >
+
+ <item android:state_pressed="true" android:drawable="@color/header_pressed" />
+ <item android:drawable="@color/header_normal" />
+
+</selector> \ No newline at end of file
diff --git a/OpenPGP-Keychain/res/layout/key_list_public_activity.xml b/OpenPGP-Keychain/res/layout/key_list_public_activity.xml
index a35e23038..07ec253cc 100644
--- a/OpenPGP-Keychain/res/layout/key_list_public_activity.xml
+++ b/OpenPGP-Keychain/res/layout/key_list_public_activity.xml
@@ -8,18 +8,7 @@
android:id="@+id/key_list_public_fragment"
android:name="org.sufficientlysecure.keychain.ui.KeyListPublicFragment"
android:layout_width="match_parent"
- android:layout_height="match_parent"
+ android:layout_height="0dip"
android:layout_weight="1" />
- <TextView
- android:layout_width="match_parent"
- android:layout_height="90dp"
- android:layout_weight="1"
- android:background="@drawable/abs__ab_bottom_solid_light_holo"
- android:paddingBottom="3dp"
- android:paddingLeft="10dp"
- android:paddingRight="10dp"
- android:paddingTop="3dp"
- android:text="@string/list_information" />
-
</LinearLayout> \ No newline at end of file
diff --git a/OpenPGP-Keychain/res/layout/key_list_public_fragment.xml b/OpenPGP-Keychain/res/layout/key_list_public_fragment.xml
new file mode 100644
index 000000000..052dd4249
--- /dev/null
+++ b/OpenPGP-Keychain/res/layout/key_list_public_fragment.xml
@@ -0,0 +1,14 @@
+<?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:orientation="vertical"
+ android:paddingLeft="8dp"
+ android:paddingRight="8dp" >
+
+ <se.emilsjolander.stickylistheaders.StickyListHeadersListView
+ android:id="@+id/key_list_public_fragment_stickylist"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent" />
+
+</LinearLayout> \ No newline at end of file
diff --git a/OpenPGP-Keychain/res/layout/key_list_secret_activity.xml b/OpenPGP-Keychain/res/layout/key_list_secret_activity.xml
index d4397c444..b8df9faa7 100644
--- a/OpenPGP-Keychain/res/layout/key_list_secret_activity.xml
+++ b/OpenPGP-Keychain/res/layout/key_list_secret_activity.xml
@@ -8,18 +8,7 @@
android:id="@+id/key_list_secret_fragment"
android:name="org.sufficientlysecure.keychain.ui.KeyListSecretFragment"
android:layout_width="match_parent"
- android:layout_height="match_parent"
+ android:layout_height="0dip"
android:layout_weight="1" />
- <TextView
- android:layout_width="match_parent"
- android:layout_height="90dp"
- android:layout_weight="1"
- android:background="@drawable/abs__ab_bottom_solid_light_holo"
- android:paddingBottom="3dp"
- android:paddingLeft="10dp"
- android:paddingRight="10dp"
- android:paddingTop="3dp"
- android:text="@string/list_information" />
-
</LinearLayout> \ No newline at end of file
diff --git a/OpenPGP-Keychain/res/layout/stickylist_header.xml b/OpenPGP-Keychain/res/layout/stickylist_header.xml
new file mode 100644
index 000000000..475d1c4db
--- /dev/null
+++ b/OpenPGP-Keychain/res/layout/stickylist_header.xml
@@ -0,0 +1,17 @@
+<?xml version="1.0" encoding="utf-8"?>
+<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:background="@drawable/header_selector" >
+
+ <se.emilsjolander.stickylistheaders.views.UnderlineTextView
+ android:id="@+id/stickylist_header_text"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_gravity="start|left"
+ android:padding="5dp"
+ android:textColor="@android:color/white"
+ android:textSize="17sp"
+ android:textStyle="bold" />
+
+</RelativeLayout> \ No newline at end of file
diff --git a/OpenPGP-Keychain/res/values/colors.xml b/OpenPGP-Keychain/res/values/colors.xml
index d1dc6c1f4..7831a63a0 100644
--- a/OpenPGP-Keychain/res/values/colors.xml
+++ b/OpenPGP-Keychain/res/values/colors.xml
@@ -3,5 +3,8 @@
<color name="emphasis">#31b6e7</color>
<color name="bg_gray">#cecbce</color>
-
+ <color name="header_normal">#ffe74c3c</color>
+ <color name="header_pressed">#ffc0392b</color>
+ <color name="menu_section_header">#FFDDDDDD</color>
+
</resources> \ No newline at end of file
diff --git a/OpenPGP-Keychain/res/values/strings.xml b/OpenPGP-Keychain/res/values/strings.xml
index c3736815c..d900f5a71 100644
--- a/OpenPGP-Keychain/res/values/strings.xml
+++ b/OpenPGP-Keychain/res/values/strings.xml
@@ -210,7 +210,6 @@
<string name="lookup_unknown_key">Unknown key %s, do you want to try finding it on a keyserver?</string>
<string name="key_send_success">Successfully sent key to server</string>
<string name="key_sign_success">Successfully signed key</string>
- <string name="list_information">Long press one entry in this list to show more options!</string>
<string name="list_empty">This list is empty!</string>
<string name="nfc_successfull">Successfully sent key with NFC Beam!</string>
diff --git a/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/ui/KeyListPublicFragment.java b/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/ui/KeyListPublicFragment.java
index 3dafc84ca..8167ff439 100644
--- a/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/ui/KeyListPublicFragment.java
+++ b/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/ui/KeyListPublicFragment.java
@@ -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;
-
-public class KeyListPublicFragment extends SherlockListFragment implements
- LoaderManager.LoaderCallbacks<Cursor> {
+import com.actionbarsherlock.app.SherlockFragment;
+
+/**
+ * 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);
+ }
+
}
diff --git a/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/ui/adapter/KeyListPublicAdapter.java b/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/ui/adapter/KeyListPublicAdapter.java
index d72c9d42a..86a47d4d7 100644
--- a/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/ui/adapter/KeyListPublicAdapter.java
+++ b/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/ui/adapter/KeyListPublicAdapter.java
@@ -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;
+ }
+
}
diff --git a/OpenPGP-Keychain/src/se/emilsjolander/stickylistheaders/views/UnderlineTextView.java b/OpenPGP-Keychain/src/se/emilsjolander/stickylistheaders/views/UnderlineTextView.java
new file mode 100644
index 000000000..c202c00b8
--- /dev/null
+++ b/OpenPGP-Keychain/src/se/emilsjolander/stickylistheaders/views/UnderlineTextView.java
@@ -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);
+ }
+}