diff options
Diffstat (limited to 'OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/widget')
5 files changed, 258 insertions, 7 deletions
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/widget/CertListWidget.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/widget/CertListWidget.java new file mode 100644 index 000000000..c413a00be --- /dev/null +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/widget/CertListWidget.java @@ -0,0 +1,143 @@ +package org.sufficientlysecure.keychain.ui.widget; + +import java.util.Date; + +import android.content.Context; +import android.database.Cursor; +import android.net.Uri; +import android.os.Bundle; +import android.support.v4.app.LoaderManager; +import android.support.v4.content.CursorLoader; +import android.support.v4.content.Loader; +import android.util.AttributeSet; +import android.view.View; +import android.widget.ListView; +import android.widget.TextView; +import android.widget.ViewAnimator; + +import org.ocpsoft.prettytime.PrettyTime; +import org.sufficientlysecure.keychain.R; +import org.sufficientlysecure.keychain.provider.KeychainContract; +import org.sufficientlysecure.keychain.provider.KeychainContract.Certs; + +public class CertListWidget extends ViewAnimator + implements LoaderManager.LoaderCallbacks<Cursor> { + + public static final int LOADER_ID_LINKED_CERTS = 38572; + + public static final String ARG_URI = "uri"; + public static final String ARG_IS_SECRET = "is_secret"; + + + // These are the rows that we will retrieve. + static final String[] CERTS_PROJECTION = new String[]{ + KeychainContract.Certs._ID, + KeychainContract.Certs.MASTER_KEY_ID, + KeychainContract.Certs.VERIFIED, + KeychainContract.Certs.TYPE, + KeychainContract.Certs.RANK, + KeychainContract.Certs.KEY_ID_CERTIFIER, + KeychainContract.Certs.USER_ID, + KeychainContract.Certs.SIGNER_UID, + KeychainContract.Certs.CREATION + }; + public static final int INDEX_MASTER_KEY_ID = 1; + public static final int INDEX_VERIFIED = 2; + public static final int INDEX_TYPE = 3; + public static final int INDEX_RANK = 4; + public static final int INDEX_KEY_ID_CERTIFIER = 5; + public static final int INDEX_USER_ID = 6; + public static final int INDEX_SIGNER_UID = 7; + public static final int INDEX_CREATION = 8; + + private TextView vCollapsed; + private ListView vExpanded; + private View vExpandButton; + private boolean mIsSecret; + + public CertListWidget(Context context, AttributeSet attrs) { + super(context, attrs); + } + + @Override + protected void onFinishInflate() { + super.onFinishInflate(); + + View root = getRootView(); + vCollapsed = (TextView) root.findViewById(R.id.cert_collapsed_list); + vExpanded = (ListView) root.findViewById(R.id.cert_expanded_list); + vExpandButton = root.findViewById(R.id.cert_expand_button); + + // for now + vExpandButton.setVisibility(View.GONE); + vExpandButton.setOnClickListener(new OnClickListener() { + @Override + public void onClick(View v) { + toggleExpanded(); + } + }); + + // vExpanded.setAdapter(null); + + } + + void toggleExpanded() { + setDisplayedChild(getDisplayedChild() == 1 ? 0 : 1); + } + + void setExpanded(boolean expanded) { + setDisplayedChild(expanded ? 1 : 0); + } + + @Override + public Loader<Cursor> onCreateLoader(int id, Bundle args) { + Uri uri = args.getParcelable(ARG_URI); + mIsSecret = args.getBoolean(ARG_IS_SECRET, false); + return new CursorLoader(getContext(), uri, + CERTS_PROJECTION, null, null, null); + } + + @Override + public void onLoadFinished(Loader<Cursor> loader, Cursor data) { + + if (data == null || !data.moveToFirst()) { + return; + } + + // TODO support external certificates + Date userCert = null; + while (!data.isAfterLast()) { + + int verified = data.getInt(INDEX_VERIFIED); + Date creation = new Date(data.getLong(INDEX_CREATION) * 1000); + + if (verified == Certs.VERIFIED_SECRET) { + if (userCert == null || userCert.after(creation)) { + userCert = creation; + } + } + + data.moveToNext(); + } + + if (userCert != null) { + PrettyTime format = new PrettyTime(); + if (mIsSecret) { + vCollapsed.setText("You created this identity " + + format.format(userCert) + "."); + } else { + vCollapsed.setText("You verified and confirmed this identity " + + format.format(userCert) + "."); + } + } else { + vCollapsed.setText("This identity is not yet verified or confirmed."); + } + + } + + @Override + public void onLoaderReset(Loader<Cursor> loader) { + setVisibility(View.GONE); + } + +} diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/widget/CertifyKeySpinner.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/widget/CertifyKeySpinner.java index 6cd33aada..6a51085f3 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/widget/CertifyKeySpinner.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/widget/CertifyKeySpinner.java @@ -17,25 +17,24 @@ package org.sufficientlysecure.keychain.ui.widget; - -import java.util.Arrays; -import java.util.List; - import android.content.Context; import android.database.Cursor; import android.net.Uri; import android.os.Bundle; +import android.support.annotation.StringRes; import android.support.v4.content.CursorLoader; import android.support.v4.content.Loader; import android.util.AttributeSet; import org.sufficientlysecure.keychain.Constants; +import org.sufficientlysecure.keychain.R; import org.sufficientlysecure.keychain.provider.KeychainContract; import org.sufficientlysecure.keychain.provider.KeychainDatabase; import org.sufficientlysecure.keychain.ui.adapter.KeyAdapter; public class CertifyKeySpinner extends KeySpinner { private long mHiddenMasterKeyId = Constants.key.none; + private boolean mIsSingle; public CertifyKeySpinner(Context context) { super(context); @@ -94,9 +93,11 @@ public class CertifyKeySpinner extends KeySpinner { if (!data.isNull(mIndexHasCertify)) { if (selection == -1) { selection = data.getPosition() + 1; + mIsSingle = true; } else { // if selection is already set, we have more than one certify key! // get back to "none"! + mIsSingle = false; selection = 0; } } @@ -106,6 +107,9 @@ public class CertifyKeySpinner extends KeySpinner { } } + public boolean isSingleEntry() { + return mIsSingle && getSelectedItemPosition() != 0; + } @Override boolean isItemEnabled(Cursor cursor) { @@ -128,4 +132,10 @@ public class CertifyKeySpinner extends KeySpinner { return true; } + @Override + public @StringRes int getNoneString() { + return R.string.choice_select_cert; + } + + } diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/widget/KeySpinner.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/widget/KeySpinner.java index 1884daf12..04ed35deb 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/widget/KeySpinner.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/widget/KeySpinner.java @@ -23,6 +23,7 @@ import android.database.Cursor; import android.os.Bundle; import android.os.Parcelable; import android.support.annotation.NonNull; +import android.support.annotation.StringRes; import android.support.v4.app.FragmentActivity; import android.support.v4.app.LoaderManager; import android.support.v4.content.Loader; @@ -34,6 +35,7 @@ import android.view.ViewGroup; import android.widget.AdapterView; import android.widget.BaseAdapter; import android.widget.SpinnerAdapter; +import android.widget.TextView; import org.sufficientlysecure.keychain.Constants; import org.sufficientlysecure.keychain.R; @@ -117,8 +119,7 @@ public abstract class KeySpinner extends AppCompatSpinner implements if (getContext() instanceof FragmentActivity) { ((FragmentActivity) getContext()).getSupportLoaderManager().restartLoader(LOADER_ID, null, this); } else { - throw new AssertionError("KeySpinner must be attached to FragmentActivity, this is " - + getContext().getClass()); + // ignore, this happens during preview! we use fragmentactivities everywhere either way } } @@ -226,9 +227,11 @@ public abstract class KeySpinner extends AppCompatSpinner implements return inner.getView(position -1, convertView, parent); } - return convertView != null ? convertView : + View view = convertView != null ? convertView : LayoutInflater.from(getContext()).inflate( R.layout.keyspinner_item_none, parent, false); + ((TextView) view.findViewById(R.id.keyspinner_key_name)).setText(getNoneString()); + return view; } } @@ -259,4 +262,9 @@ public abstract class KeySpinner extends AppCompatSpinner implements bundle.putLong(ARG_KEY_ID, getSelectedKeyId()); return bundle; } + + public @StringRes int getNoneString() { + return R.string.cert_none; + } + } diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/widget/PrefixedEditText.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/widget/PrefixedEditText.java new file mode 100644 index 000000000..3cbb114e8 --- /dev/null +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/widget/PrefixedEditText.java @@ -0,0 +1,45 @@ +package org.sufficientlysecure.keychain.ui.widget; + +import android.content.Context; +import android.content.res.TypedArray; +import android.graphics.*; +import android.support.annotation.NonNull; +import android.util.AttributeSet; +import android.widget.EditText; + +import org.sufficientlysecure.keychain.R; + +public class PrefixedEditText extends EditText { + + private String mPrefix; + private Rect mPrefixRect = new Rect(); + + public PrefixedEditText(Context context, AttributeSet attrs) { + super(context, attrs); + TypedArray style = context.getTheme().obtainStyledAttributes( + attrs, R.styleable.PrefixedEditText, 0, 0); + mPrefix = style.getString(R.styleable.PrefixedEditText_prefix); + if (mPrefix == null) { + mPrefix = ""; + } + } + + @Override + protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { + getPaint().getTextBounds(mPrefix, 0, mPrefix.length(), mPrefixRect); + + super.onMeasure(widthMeasureSpec, heightMeasureSpec); + } + + @Override + protected void onDraw(@NonNull Canvas canvas) { + super.onDraw(canvas); + canvas.drawText(mPrefix, super.getCompoundPaddingLeft(), getBaseline(), getPaint()); + } + + @Override + public int getCompoundPaddingLeft() { + return super.getCompoundPaddingLeft() + mPrefixRect.width(); + } + +}
\ No newline at end of file diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/widget/StatusIndicator.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/widget/StatusIndicator.java new file mode 100644 index 000000000..2784ac5f0 --- /dev/null +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/widget/StatusIndicator.java @@ -0,0 +1,45 @@ +package org.sufficientlysecure.keychain.ui.widget; + + +import android.content.Context; +import android.util.AttributeSet; +import android.view.LayoutInflater; +import android.view.animation.AnimationUtils; + +import org.sufficientlysecure.keychain.R; + + +public class StatusIndicator extends ToolableViewAnimator { + + public enum Status { + IDLE, PROGRESS, OK, ERROR + } + + public StatusIndicator(Context context) { + super(context); + + LayoutInflater.from(context).inflate(R.layout.status_indicator, this, true); + setInAnimation(AnimationUtils.loadAnimation(context, R.anim.fade_in)); + setOutAnimation(AnimationUtils.loadAnimation(context, R.anim.fade_out)); + } + + public StatusIndicator(Context context, AttributeSet attrs) { + super(context, attrs); + + LayoutInflater.from(context).inflate(R.layout.status_indicator, this, true); + setInAnimation(AnimationUtils.loadAnimation(context, R.anim.fade_in)); + setOutAnimation(AnimationUtils.loadAnimation(context, R.anim.fade_out)); + } + + @Override + public void setDisplayedChild(int whichChild) { + if (whichChild != getDisplayedChild()) { + super.setDisplayedChild(whichChild); + } + } + + public void setDisplayedChild(Status status) { + setDisplayedChild(status.ordinal()); + } + +} |