use mvp pattern for linked id card

This commit is contained in:
Vincent Breitmoser
2017-05-21 03:07:35 +02:00
parent d919180219
commit f34edae294
8 changed files with 326 additions and 290 deletions

View File

@@ -84,7 +84,6 @@ import org.sufficientlysecure.keychain.provider.KeychainContract.KeyRings;
import org.sufficientlysecure.keychain.service.ChangeUnlockParcel; import org.sufficientlysecure.keychain.service.ChangeUnlockParcel;
import org.sufficientlysecure.keychain.service.ImportKeyringParcel; import org.sufficientlysecure.keychain.service.ImportKeyringParcel;
import org.sufficientlysecure.keychain.service.input.RequiredInputParcel; import org.sufficientlysecure.keychain.service.input.RequiredInputParcel;
import org.sufficientlysecure.keychain.ui.ViewKeyFragment.PostponeType;
import org.sufficientlysecure.keychain.ui.base.BaseSecurityTokenActivity; import org.sufficientlysecure.keychain.ui.base.BaseSecurityTokenActivity;
import org.sufficientlysecure.keychain.ui.base.CryptoOperationHelper; import org.sufficientlysecure.keychain.ui.base.CryptoOperationHelper;
import org.sufficientlysecure.keychain.ui.dialog.SetPassphraseDialogFragment; import org.sufficientlysecure.keychain.ui.dialog.SetPassphraseDialogFragment;
@@ -111,7 +110,6 @@ public class ViewKeyActivity extends BaseSecurityTokenActivity implements
public static final String EXTRA_SECURITY_TOKEN_AID = "security_token_aid"; public static final String EXTRA_SECURITY_TOKEN_AID = "security_token_aid";
public static final String EXTRA_SECURITY_TOKEN_VERSION = "security_token_version"; public static final String EXTRA_SECURITY_TOKEN_VERSION = "security_token_version";
public static final String EXTRA_SECURITY_TOKEN_FINGERPRINTS = "security_token_fingerprints"; public static final String EXTRA_SECURITY_TOKEN_FINGERPRINTS = "security_token_fingerprints";
private boolean mLinkedTransition;
@Retention(RetentionPolicy.SOURCE) @Retention(RetentionPolicy.SOURCE)
@IntDef({REQUEST_QR_FINGERPRINT, REQUEST_BACKUP, REQUEST_CERTIFY, REQUEST_DELETE}) @IntDef({REQUEST_QR_FINGERPRINT, REQUEST_BACKUP, REQUEST_CERTIFY, REQUEST_DELETE})
@@ -332,11 +330,6 @@ public class ViewKeyActivity extends BaseSecurityTokenActivity implements
return; return;
} }
mLinkedTransition = getIntent().getBooleanExtra(EXTRA_LINKED_TRANSITION, false);
if (mLinkedTransition && Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
postponeEnterTransition();
}
if (Preferences.getPreferences(this).getExperimentalEnableKeybase()) { if (Preferences.getPreferences(this).getExperimentalEnableKeybase()) {
FragmentManager manager = getSupportFragmentManager(); FragmentManager manager = getSupportFragmentManager();
final ViewKeyKeybaseFragment keybaseFrag = ViewKeyKeybaseFragment.newInstance(mDataUri); final ViewKeyKeybaseFragment keybaseFrag = ViewKeyKeybaseFragment.newInstance(mDataUri);
@@ -742,8 +735,7 @@ public class ViewKeyActivity extends BaseSecurityTokenActivity implements
} }
// if the main fragment doesn't exist, or is not of the correct type, (re)create it // if the main fragment doesn't exist, or is not of the correct type, (re)create it
frag = ViewKeyFragment.newInstance(mMasterKeyId, mIsSecret, frag = ViewKeyFragment.newInstance(mMasterKeyId, mIsSecret);
mLinkedTransition ? PostponeType.LINKED : PostponeType.NONE);
// get rid of possible backstack, this fragment is always at the bottom // get rid of possible backstack, this fragment is always at the bottom
manager.popBackStack("security_token", FragmentManager.POP_BACK_STACK_INCLUSIVE); manager.popBackStack("security_token", FragmentManager.POP_BACK_STACK_INCLUSIVE);
manager.beginTransaction() manager.beginTransaction()

View File

@@ -19,67 +19,49 @@
package org.sufficientlysecure.keychain.ui; package org.sufficientlysecure.keychain.ui;
import java.io.IOException;
import android.annotation.TargetApi;
import android.content.Intent; import android.content.Intent;
import android.database.Cursor; import android.database.Cursor;
import android.net.Uri; import android.net.Uri;
import android.os.Build;
import android.os.Build.VERSION_CODES;
import android.os.Bundle; import android.os.Bundle;
import android.os.Handler; import android.os.Handler;
import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentTransaction;
import android.support.v4.app.LoaderManager; import android.support.v4.app.LoaderManager;
import android.support.v4.content.Loader; import android.support.v4.content.Loader;
import android.support.v7.widget.CardView;
import android.transition.Fade;
import android.transition.Transition;
import android.transition.TransitionInflater;
import android.view.LayoutInflater; import android.view.LayoutInflater;
import android.view.View; import android.view.View;
import android.view.ViewGroup; import android.view.ViewGroup;
import android.view.ViewTreeObserver.OnPreDrawListener;
import android.widget.AdapterView; import android.widget.AdapterView;
import android.widget.AdapterView.OnItemClickListener;
import android.widget.Button; import android.widget.Button;
import android.widget.LinearLayout; import android.widget.LinearLayout;
import android.widget.ListView; import android.widget.ListView;
import android.widget.TextView;
import org.sufficientlysecure.keychain.Constants;
import org.sufficientlysecure.keychain.R; import org.sufficientlysecure.keychain.R;
import org.sufficientlysecure.keychain.compatibility.DialogFragmentWorkaround; import org.sufficientlysecure.keychain.compatibility.DialogFragmentWorkaround;
import org.sufficientlysecure.keychain.operations.results.OperationResult; import org.sufficientlysecure.keychain.operations.results.OperationResult;
import org.sufficientlysecure.keychain.provider.KeychainContract; import org.sufficientlysecure.keychain.provider.KeychainContract;
import org.sufficientlysecure.keychain.provider.KeychainContract.KeyRings; import org.sufficientlysecure.keychain.provider.KeychainContract.KeyRings;
import org.sufficientlysecure.keychain.ui.adapter.LinkedIdsAdapter;
import org.sufficientlysecure.keychain.ui.adapter.UserIdsAdapter; import org.sufficientlysecure.keychain.ui.adapter.UserIdsAdapter;
import org.sufficientlysecure.keychain.ui.base.LoaderFragment; import org.sufficientlysecure.keychain.ui.base.LoaderFragment;
import org.sufficientlysecure.keychain.ui.dialog.UserIdInfoDialogFragment; import org.sufficientlysecure.keychain.ui.dialog.UserIdInfoDialogFragment;
import org.sufficientlysecure.keychain.ui.linked.LinkedIdViewFragment;
import org.sufficientlysecure.keychain.ui.linked.LinkedIdViewFragment.OnIdentityLoadedListener;
import org.sufficientlysecure.keychain.ui.linked.LinkedIdWizard;
import org.sufficientlysecure.keychain.ui.widget.KeyHealthCardView; import org.sufficientlysecure.keychain.ui.widget.KeyHealthCardView;
import org.sufficientlysecure.keychain.ui.widget.KeyHealthPresenter; import org.sufficientlysecure.keychain.ui.widget.KeyHealthPresenter;
import org.sufficientlysecure.keychain.ui.widget.LinkedIdentitiesCardView;
import org.sufficientlysecure.keychain.ui.widget.LinkedIdentitiesPresenter;
import org.sufficientlysecure.keychain.ui.widget.LinkedIdentitiesPresenter.LinkedIdsFragMvpView;
import org.sufficientlysecure.keychain.ui.widget.SystemContactCardView; import org.sufficientlysecure.keychain.ui.widget.SystemContactCardView;
import org.sufficientlysecure.keychain.ui.widget.SystemContactPresenter; import org.sufficientlysecure.keychain.ui.widget.SystemContactPresenter;
import org.sufficientlysecure.keychain.util.Log;
import org.sufficientlysecure.keychain.util.Preferences; import org.sufficientlysecure.keychain.util.Preferences;
public class ViewKeyFragment extends LoaderFragment implements public class ViewKeyFragment extends LoaderFragment implements LoaderManager.LoaderCallbacks<Cursor>,
LoaderManager.LoaderCallbacks<Cursor> { LinkedIdsFragMvpView {
public static final String ARG_MASTER_KEY_ID = "master_key_id"; public static final String ARG_MASTER_KEY_ID = "master_key_id";
public static final String ARG_IS_SECRET = "is_secret"; public static final String ARG_IS_SECRET = "is_secret";
public static final String ARG_POSTPONE_TYPE = "postpone_type";
private ListView mUserIds; private ListView mUserIds;
enum PostponeType {
NONE, LINKED
}
boolean mIsSecret = false; boolean mIsSecret = false;
private static final int LOADER_ID_USER_IDS = 1; private static final int LOADER_ID_USER_IDS = 1;
@@ -88,16 +70,11 @@ public class ViewKeyFragment extends LoaderFragment implements
private static final int LOADER_ID_SUBKEY_STATUS = 4; private static final int LOADER_ID_SUBKEY_STATUS = 4;
private UserIdsAdapter mUserIdsAdapter; private UserIdsAdapter mUserIdsAdapter;
private LinkedIdsAdapter mLinkedIdsAdapter;
private Uri mDataUri; private Uri mDataUri;
private PostponeType mPostponeType; LinkedIdentitiesCardView mLinkedIdsCard;
LinkedIdentitiesPresenter mLinkedIdentitiesPresenter;
private ListView mLinkedIds;
private CardView mLinkedIdsCard;
private TextView mLinkedIdsEmpty;
private TextView mLinkedIdsExpander;
SystemContactCardView mSystemContactCard; SystemContactCardView mSystemContactCard;
SystemContactPresenter mSystemContactPresenter; SystemContactPresenter mSystemContactPresenter;
@@ -110,12 +87,11 @@ public class ViewKeyFragment extends LoaderFragment implements
/** /**
* Creates new instance of this fragment * Creates new instance of this fragment
*/ */
public static ViewKeyFragment newInstance(long masterKeyId, boolean isSecret, PostponeType postponeType) { public static ViewKeyFragment newInstance(long masterKeyId, boolean isSecret) {
ViewKeyFragment frag = new ViewKeyFragment(); ViewKeyFragment frag = new ViewKeyFragment();
Bundle args = new Bundle(); Bundle args = new Bundle();
args.putLong(ARG_MASTER_KEY_ID, masterKeyId); args.putLong(ARG_MASTER_KEY_ID, masterKeyId);
args.putBoolean(ARG_IS_SECRET, isSecret); args.putBoolean(ARG_IS_SECRET, isSecret);
args.putString(ARG_POSTPONE_TYPE, postponeType.toString());
frag.setArguments(args); frag.setArguments(args);
@@ -129,11 +105,7 @@ public class ViewKeyFragment extends LoaderFragment implements
mUserIds = (ListView) view.findViewById(R.id.view_key_user_ids); mUserIds = (ListView) view.findViewById(R.id.view_key_user_ids);
Button userIdsEditButton = (Button) view.findViewById(R.id.view_key_card_user_ids_edit); Button userIdsEditButton = (Button) view.findViewById(R.id.view_key_card_user_ids_edit);
mLinkedIdsCard = (CardView) view.findViewById(R.id.card_linked_ids); mLinkedIdsCard = (LinkedIdentitiesCardView) view.findViewById(R.id.card_linked_ids);
mLinkedIds = (ListView) view.findViewById(R.id.view_key_linked_ids);
mLinkedIdsExpander = (TextView) view.findViewById(R.id.view_key_linked_ids_expander);
mLinkedIdsEmpty = (TextView) view.findViewById(R.id.view_key_linked_ids_empty);
Button linkedIdsAddButton = (Button) view.findViewById(R.id.view_key_card_linked_ids_add);
userIdsEditButton.setOnClickListener(new View.OnClickListener() { userIdsEditButton.setOnClickListener(new View.OnClickListener() {
@Override @Override
@@ -142,25 +114,12 @@ public class ViewKeyFragment extends LoaderFragment implements
} }
}); });
linkedIdsAddButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
addLinkedIdentity(mDataUri);
}
});
mUserIds.setOnItemClickListener(new AdapterView.OnItemClickListener() { mUserIds.setOnItemClickListener(new AdapterView.OnItemClickListener() {
@Override @Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) { public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
showUserIdInfo(position); showUserIdInfo(position);
} }
}); });
mLinkedIds.setOnItemClickListener(new OnItemClickListener() {
@Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
showLinkedId(position);
}
});
mSystemContactCard = (SystemContactCardView) view.findViewById(R.id.linked_system_contact_card); mSystemContactCard = (SystemContactCardView) view.findViewById(R.id.linked_system_contact_card);
mKeyHealthCard = (KeyHealthCardView) view.findViewById(R.id.subkey_status_card); mKeyHealthCard = (KeyHealthCardView) view.findViewById(R.id.subkey_status_card);
@@ -174,53 +133,6 @@ public class ViewKeyFragment extends LoaderFragment implements
startActivityForResult(editIntent, 0); startActivityForResult(editIntent, 0);
} }
private void addLinkedIdentity(Uri dataUri) {
Intent intent = new Intent(getActivity(), LinkedIdWizard.class);
intent.setData(dataUri);
startActivity(intent);
getActivity().finish();
}
private void showLinkedId(final int position) {
final LinkedIdViewFragment frag;
try {
frag = mLinkedIdsAdapter.getLinkedIdFragment(mDataUri, position, mMasterKeyId);
} catch (IOException e) {
Log.e(Constants.TAG, "IOException", e);
return;
}
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
Transition trans = TransitionInflater.from(getActivity())
.inflateTransition(R.transition.linked_id_card_trans);
// setSharedElementReturnTransition(trans);
setExitTransition(new Fade());
frag.setSharedElementEnterTransition(trans);
}
getFragmentManager().beginTransaction()
.add(R.id.view_key_fragment, frag)
.hide(frag)
.commit();
frag.setOnIdentityLoadedListener(new OnIdentityLoadedListener() {
@Override
public void onIdentityLoaded() {
new Handler().post(new Runnable() {
@Override
public void run() {
getFragmentManager().beginTransaction()
.show(frag)
.addSharedElement(mLinkedIdsCard, "card_linked_ids")
.remove(ViewKeyFragment.this)
.addToBackStack("linked_id")
.commit();
}
});
}
});
}
@Override @Override
public void onActivityCreated(Bundle savedInstanceState) { public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState); super.onActivityCreated(savedInstanceState);
@@ -228,7 +140,6 @@ public class ViewKeyFragment extends LoaderFragment implements
mMasterKeyId = getArguments().getLong(ARG_MASTER_KEY_ID); mMasterKeyId = getArguments().getLong(ARG_MASTER_KEY_ID);
mDataUri = KeyRings.buildGenericKeyRingUri(mMasterKeyId); mDataUri = KeyRings.buildGenericKeyRingUri(mMasterKeyId);
mIsSecret = getArguments().getBoolean(ARG_IS_SECRET); mIsSecret = getArguments().getBoolean(ARG_IS_SECRET);
mPostponeType = PostponeType.valueOf(getArguments().getString(ARG_POSTPONE_TYPE));
// load user ids after we know if it's a secret key // load user ids after we know if it's a secret key
mUserIdsAdapter = new UserIdsAdapter(getActivity(), null, 0, !mIsSecret, null); mUserIdsAdapter = new UserIdsAdapter(getActivity(), null, 0, !mIsSecret, null);
@@ -236,9 +147,14 @@ public class ViewKeyFragment extends LoaderFragment implements
// initialize loaders, which will take care of auto-refresh on change // initialize loaders, which will take care of auto-refresh on change
getLoaderManager().initLoader(LOADER_ID_USER_IDS, null, this); getLoaderManager().initLoader(LOADER_ID_USER_IDS, null, this);
initLinkedIds(mIsSecret);
initCardButtonsVisibility(mIsSecret); initCardButtonsVisibility(mIsSecret);
if (Preferences.getPreferences(getActivity()).getExperimentalEnableLinkedIdentities()) {
mLinkedIdentitiesPresenter = new LinkedIdentitiesPresenter(
getContext(), mLinkedIdsCard, this, LOADER_ID_LINKED_IDS, mMasterKeyId, mIsSecret);
mLinkedIdentitiesPresenter.startLoader(getLoaderManager());
}
mSystemContactPresenter = new SystemContactPresenter( mSystemContactPresenter = new SystemContactPresenter(
getContext(), mSystemContactCard, LOADER_ID_LINKED_CONTACT, mMasterKeyId, mIsSecret); getContext(), mSystemContactCard, LOADER_ID_LINKED_CONTACT, mMasterKeyId, mIsSecret);
mSystemContactPresenter.startLoader(getLoaderManager()); mSystemContactPresenter.startLoader(getLoaderManager());
@@ -248,6 +164,20 @@ public class ViewKeyFragment extends LoaderFragment implements
mKeyHealthPresenter.startLoader(getLoaderManager()); mKeyHealthPresenter.startLoader(getLoaderManager());
} }
@Override
public void switchToFragment(final Fragment frag, final String backStackName) {
new Handler().post(new Runnable() {
@Override
public void run() {
getFragmentManager().beginTransaction()
.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_FADE)
.replace(R.id.view_key_fragment, frag)
.addToBackStack(backStackName)
.commit();
}
});
}
private void showUserIdInfo(final int position) { private void showUserIdInfo(final int position) {
if (!mIsSecret) { if (!mIsSecret) {
final boolean isRevoked = mUserIdsAdapter.getIsRevoked(position); final boolean isRevoked = mUserIdsAdapter.getIsRevoked(position);
@@ -283,10 +213,7 @@ public class ViewKeyFragment extends LoaderFragment implements
return UserIdsAdapter.createLoader(getActivity(), mDataUri); return UserIdsAdapter.createLoader(getActivity(), mDataUri);
} }
case LOADER_ID_LINKED_IDS: { case LOADER_ID_LINKED_IDS:
return LinkedIdsAdapter.createLoader(getActivity(), mDataUri);
}
case LOADER_ID_LINKED_CONTACT: case LOADER_ID_LINKED_CONTACT:
case LOADER_ID_SUBKEY_STATUS: { case LOADER_ID_SUBKEY_STATUS: {
throw new IllegalStateException("This callback should never end up here!"); throw new IllegalStateException("This callback should never end up here!");
@@ -315,31 +242,7 @@ public class ViewKeyFragment extends LoaderFragment implements
break; break;
} }
case LOADER_ID_LINKED_IDS: { case LOADER_ID_LINKED_IDS:
mLinkedIdsAdapter.swapCursor(data);
if (mIsSecret) {
mLinkedIdsCard.setVisibility(View.VISIBLE);
mLinkedIdsEmpty.setVisibility(mLinkedIdsAdapter.getCount() > 0 ? View.GONE : View.VISIBLE);
} else {
mLinkedIdsCard.setVisibility(mLinkedIdsAdapter.getCount() > 0 ? View.VISIBLE : View.GONE);
mLinkedIdsEmpty.setVisibility(View.GONE);
}
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP && mPostponeType == PostponeType.LINKED) {
mLinkedIdsCard.getViewTreeObserver().addOnPreDrawListener(new OnPreDrawListener() {
@TargetApi(VERSION_CODES.LOLLIPOP)
@Override
public boolean onPreDraw() {
mLinkedIdsCard.getViewTreeObserver().removeOnPreDrawListener(this);
getActivity().startPostponedEnterTransition();
return true;
}
});
}
break;
}
case LOADER_ID_LINKED_CONTACT: case LOADER_ID_LINKED_CONTACT:
case LOADER_ID_SUBKEY_STATUS: { case LOADER_ID_SUBKEY_STATUS: {
throw new IllegalStateException("This callback should never end up here!"); throw new IllegalStateException("This callback should never end up here!");
@@ -347,16 +250,6 @@ public class ViewKeyFragment extends LoaderFragment implements
} }
} }
private void initLinkedIds(boolean isSecret) {
if (!Preferences.getPreferences(getActivity()).getExperimentalEnableLinkedIdentities()) {
return;
}
mLinkedIdsAdapter = new LinkedIdsAdapter(getActivity(), null, 0, isSecret, mLinkedIdsExpander);
mLinkedIds.setAdapter(mLinkedIdsAdapter);
getLoaderManager().initLoader(LOADER_ID_LINKED_IDS, null, this);
}
private void initCardButtonsVisibility(boolean isSecret) { private void initCardButtonsVisibility(boolean isSecret) {
LinearLayout buttonsUserIdsLayout = LinearLayout buttonsUserIdsLayout =
(LinearLayout) getActivity().findViewById(R.id.view_key_card_user_ids_buttons); (LinearLayout) getActivity().findViewById(R.id.view_key_card_user_ids_buttons);
@@ -382,10 +275,6 @@ public class ViewKeyFragment extends LoaderFragment implements
mUserIdsAdapter.swapCursor(null); mUserIdsAdapter.swapCursor(null);
break; break;
} }
case LOADER_ID_LINKED_IDS: {
mLinkedIdsAdapter.swapCursor(null);
break;
}
} }
} }

View File

@@ -18,8 +18,11 @@
package org.sufficientlysecure.keychain.ui.adapter; package org.sufficientlysecure.keychain.ui.adapter;
import java.io.IOException;
import java.util.WeakHashMap;
import android.animation.ObjectAnimator; import android.animation.ObjectAnimator;
import android.app.Activity;
import android.content.Context; import android.content.Context;
import android.database.Cursor; import android.database.Cursor;
import android.net.Uri; import android.net.Uri;
@@ -37,6 +40,7 @@ import org.sufficientlysecure.keychain.R;
import org.sufficientlysecure.keychain.linked.LinkedAttribute; import org.sufficientlysecure.keychain.linked.LinkedAttribute;
import org.sufficientlysecure.keychain.linked.UriAttribute; import org.sufficientlysecure.keychain.linked.UriAttribute;
import org.sufficientlysecure.keychain.provider.KeychainContract.Certs; import org.sufficientlysecure.keychain.provider.KeychainContract.Certs;
import org.sufficientlysecure.keychain.provider.KeychainContract.KeyRings;
import org.sufficientlysecure.keychain.provider.KeychainContract.UserPackets; import org.sufficientlysecure.keychain.provider.KeychainContract.UserPackets;
import org.sufficientlysecure.keychain.ui.linked.LinkedIdViewFragment; import org.sufficientlysecure.keychain.ui.linked.LinkedIdViewFragment;
import org.sufficientlysecure.keychain.ui.util.KeyFormattingUtils; import org.sufficientlysecure.keychain.ui.util.KeyFormattingUtils;
@@ -45,45 +49,22 @@ import org.sufficientlysecure.keychain.ui.util.SubtleAttentionSeeker;
import org.sufficientlysecure.keychain.util.FilterCursorWrapper; import org.sufficientlysecure.keychain.util.FilterCursorWrapper;
import org.sufficientlysecure.keychain.util.Log; import org.sufficientlysecure.keychain.util.Log;
import java.io.IOException;
import java.util.WeakHashMap;
public class LinkedIdsAdapter extends UserAttributesAdapter { public class LinkedIdsAdapter extends UserAttributesAdapter {
private final boolean mIsSecret; private final boolean mIsSecret;
protected LayoutInflater mInflater; protected LayoutInflater mInflater;
WeakHashMap<Integer,UriAttribute> mLinkedIdentityCache = new WeakHashMap<>(); WeakHashMap<Integer,UriAttribute> mLinkedIdentityCache = new WeakHashMap<>();
private Cursor mUnfilteredCursor; public LinkedIdsAdapter(Context context, Cursor c, int flags, boolean isSecret) {
private TextView mExpander;
public LinkedIdsAdapter(Context context, Cursor c, int flags,
boolean isSecret, TextView expander) {
super(context, c, flags); super(context, c, flags);
mInflater = LayoutInflater.from(context); mInflater = LayoutInflater.from(context);
mIsSecret = isSecret; mIsSecret = isSecret;
if (expander != null) {
expander.setVisibility(View.GONE);
/* don't show an expander (maybe in some sort of advanced view?)
mExpander = expander;
mExpander.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
showUnfiltered();
}
});
*/
}
} }
@Override @Override
public Cursor swapCursor(Cursor cursor) { public Cursor swapCursor(Cursor cursor) {
if (cursor == null) { if (cursor == null) {
mUnfilteredCursor = null;
return super.swapCursor(null); return super.swapCursor(null);
} }
mUnfilteredCursor = cursor;
FilterCursorWrapper filteredCursor = new FilterCursorWrapper(cursor) { FilterCursorWrapper filteredCursor = new FilterCursorWrapper(cursor) {
@Override @Override
public boolean isVisible(Cursor cursor) { public boolean isVisible(Cursor cursor) {
@@ -92,25 +73,9 @@ public class LinkedIdsAdapter extends UserAttributesAdapter {
} }
}; };
if (mExpander != null) {
int hidden = filteredCursor.getHiddenCount();
if (hidden == 0) {
mExpander.setVisibility(View.GONE);
} else {
mExpander.setVisibility(View.VISIBLE);
mExpander.setText(mContext.getResources().getQuantityString(
R.plurals.linked_id_expand, hidden));
}
}
return super.swapCursor(filteredCursor); return super.swapCursor(filteredCursor);
} }
private void showUnfiltered() {
mExpander.setVisibility(View.GONE);
super.swapCursor(mUnfilteredCursor);
}
@Override @Override
public void bindView(View view, Context context, Cursor cursor) { public void bindView(View view, Context context, Cursor cursor) {
@@ -183,18 +148,18 @@ public class LinkedIdsAdapter extends UserAttributesAdapter {
// don't show revoked user ids, irrelevant for average users // don't show revoked user ids, irrelevant for average users
public static final String LINKED_IDS_WHERE = UserPackets.IS_REVOKED + " = 0"; public static final String LINKED_IDS_WHERE = UserPackets.IS_REVOKED + " = 0";
public static CursorLoader createLoader(Activity activity, Uri dataUri) { public static CursorLoader createLoader(Context context, Uri dataUri) {
Uri baseUri = UserPackets.buildLinkedIdsUri(dataUri); Uri baseUri = UserPackets.buildLinkedIdsUri(dataUri);
return new CursorLoader(activity, baseUri, return new CursorLoader(context, baseUri,
UserIdsAdapter.USER_PACKETS_PROJECTION, LINKED_IDS_WHERE, null, null); UserIdsAdapter.USER_PACKETS_PROJECTION, LINKED_IDS_WHERE, null, null);
} }
public LinkedIdViewFragment getLinkedIdFragment(Uri baseUri, int position, long masterKeyId) throws IOException { public LinkedIdViewFragment getLinkedIdFragment(int position, long masterKeyId) throws IOException {
Cursor c = getCursor(); Cursor c = getCursor();
c.moveToPosition(position); c.moveToPosition(position);
int rank = c.getInt(UserIdsAdapter.INDEX_RANK); int rank = c.getInt(UserIdsAdapter.INDEX_RANK);
Uri dataUri = UserPackets.buildLinkedIdsUri(baseUri); Uri dataUri = UserPackets.buildLinkedIdsUri(KeyRings.buildGenericKeyRingUri(masterKeyId));
return LinkedIdViewFragment.newInstance(dataUri, rank, mIsSecret, masterKeyId); return LinkedIdViewFragment.newInstance(dataUri, rank, mIsSecret, masterKeyId);
} }

View File

@@ -96,7 +96,6 @@ public class LinkedIdViewFragment extends CryptoOperationFragment implements
private Uri mDataUri; private Uri mDataUri;
private ViewHolder mViewHolder; private ViewHolder mViewHolder;
private int mLidRank; private int mLidRank;
private OnIdentityLoadedListener mIdLoadedListener;
private long mCertifyKeyId; private long mCertifyKeyId;
public static LinkedIdViewFragment newInstance(Uri dataUri, int rank, public static LinkedIdViewFragment newInstance(Uri dataUri, int rank,
@@ -156,11 +155,6 @@ public class LinkedIdViewFragment extends CryptoOperationFragment implements
// Nothing to load means break if we are *expected* to load // Nothing to load means break if we are *expected* to load
if (!cursor.moveToFirst()) { if (!cursor.moveToFirst()) {
if (mIdLoadedListener != null) {
Notify.create(getActivity(), "Error loading identity!",
Notify.LENGTH_LONG, Style.ERROR).show();
finishFragment();
}
// Or just ignore, this is probably some intermediate state during certify // Or just ignore, this is probably some intermediate state during certify
break; break;
} }
@@ -173,11 +167,6 @@ public class LinkedIdViewFragment extends CryptoOperationFragment implements
loadIdentity(linkedId, certStatus); loadIdentity(linkedId, certStatus);
if (mIdLoadedListener != null) {
mIdLoadedListener.onIdentityLoaded();
mIdLoadedListener = null;
}
} catch (IOException e) { } catch (IOException e) {
Log.e(Constants.TAG, "error parsing identity", e); Log.e(Constants.TAG, "error parsing identity", e);
Notify.create(getActivity(), "Error parsing identity!", Notify.create(getActivity(), "Error parsing identity!",
@@ -200,14 +189,6 @@ public class LinkedIdViewFragment extends CryptoOperationFragment implements
}); });
} }
public interface OnIdentityLoadedListener {
void onIdentityLoaded();
}
public void setOnIdentityLoadedListener(OnIdentityLoadedListener listener) {
mIdLoadedListener = listener;
}
private void loadIdentity(UriAttribute linkedId, int certStatus) { private void loadIdentity(UriAttribute linkedId, int certStatus) {
mLinkedId = linkedId; mLinkedId = linkedId;

View File

@@ -0,0 +1,91 @@
/*
* Copyright (C) 2017 Vincent Breitmoser <v.breitmoser@mugenguild.com>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package org.sufficientlysecure.keychain.ui.widget;
import android.content.Context;
import android.support.v7.widget.CardView;
import android.util.AttributeSet;
import android.view.LayoutInflater;
import android.view.View;
import android.widget.AdapterView;
import android.widget.AdapterView.OnItemClickListener;
import android.widget.Button;
import android.widget.ListView;
import android.widget.TextView;
import org.sufficientlysecure.keychain.R;
import org.sufficientlysecure.keychain.ui.adapter.LinkedIdsAdapter;
import org.sufficientlysecure.keychain.ui.widget.LinkedIdentitiesPresenter.LinkedIdsClickListener;
import org.sufficientlysecure.keychain.ui.widget.LinkedIdentitiesPresenter.LinkedIdsMvpView;
public class LinkedIdentitiesCardView extends CardView implements LinkedIdsMvpView {
private ListView vLinkedIds;
private TextView vLinkedIdsEmpty;
private LinkedIdsClickListener linkedIdsClickListener;
public LinkedIdentitiesCardView(Context context, AttributeSet attrs) {
super(context, attrs);
View view = LayoutInflater.from(context).inflate(R.layout.linked_identities_card, this, true);
vLinkedIds = (ListView) view.findViewById(R.id.view_key_linked_ids);
vLinkedIdsEmpty = (TextView) view.findViewById(R.id.view_key_linked_ids_empty);
Button linkedIdsAddButton = (Button) view.findViewById(R.id.view_key_card_linked_ids_add);
linkedIdsAddButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
if (linkedIdsClickListener != null) {
linkedIdsClickListener.onClickAddIdentity();
}
}
});
vLinkedIds.setOnItemClickListener(new OnItemClickListener() {
@Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
if (linkedIdsClickListener != null) {
linkedIdsClickListener.onLinkedIdItemClick(position);
}
}
});
}
@Override
public void setSystemContactClickListener(LinkedIdsClickListener linkedIdsClickListener) {
this.linkedIdsClickListener = linkedIdsClickListener;
}
@Override
public void setLinkedIdsAdapter(LinkedIdsAdapter linkedIdsAdapter) {
vLinkedIds.setAdapter(linkedIdsAdapter);
}
@Override
public void showCard(boolean visible) {
setVisibility(visible ? View.VISIBLE : View.GONE);
}
@Override
public void showEmptyView(boolean visible) {
vLinkedIdsEmpty.setVisibility(visible ? View.VISIBLE : View.GONE);
}
}

View File

@@ -0,0 +1,139 @@
/*
* Copyright (C) 2017 Vincent Breitmoser <v.breitmoser@mugenguild.com>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package org.sufficientlysecure.keychain.ui.widget;
import java.io.IOException;
import android.content.Context;
import android.content.Intent;
import android.database.Cursor;
import android.os.Bundle;
import android.support.v4.app.Fragment;
import android.support.v4.app.LoaderManager;
import android.support.v4.app.LoaderManager.LoaderCallbacks;
import android.support.v4.content.Loader;
import org.sufficientlysecure.keychain.Constants;
import org.sufficientlysecure.keychain.provider.KeychainContract.KeyRings;
import org.sufficientlysecure.keychain.ui.adapter.LinkedIdsAdapter;
import org.sufficientlysecure.keychain.ui.linked.LinkedIdViewFragment;
import org.sufficientlysecure.keychain.ui.linked.LinkedIdWizard;
import org.sufficientlysecure.keychain.util.Log;
public class LinkedIdentitiesPresenter implements LoaderCallbacks<Cursor> {
private final Context context;
private final LinkedIdsMvpView view;
private final int loaderId;
private final LinkedIdsFragMvpView fragView;
private LinkedIdsAdapter linkedIdsAdapter;
private final long masterKeyId;
private final boolean isSecret;
public LinkedIdentitiesPresenter(
Context context, LinkedIdsMvpView view, LinkedIdsFragMvpView fragView, int loaderId, long masterKeyId, boolean isSecret) {
this.context = context;
this.view = view;
this.fragView = fragView;
this.loaderId = loaderId;
this.masterKeyId = masterKeyId;
this.isSecret = isSecret;
linkedIdsAdapter = new LinkedIdsAdapter(context, null, 0, isSecret);
view.setLinkedIdsAdapter(linkedIdsAdapter);
view.setSystemContactClickListener(new LinkedIdsClickListener() {
@Override
public void onLinkedIdItemClick(int position) {
showLinkedId(position);
}
@Override
public void onClickAddIdentity() {
addLinkedIdentity();
}
});
}
public void startLoader(LoaderManager loaderManager) {
loaderManager.restartLoader(loaderId, null, this);
}
@Override
public Loader<Cursor> onCreateLoader(int id, Bundle args) {
return LinkedIdsAdapter.createLoader(context, KeyRings.buildUnifiedKeyRingUri(masterKeyId));
}
@Override
public void onLoadFinished(Loader<Cursor> loader, Cursor data) {
linkedIdsAdapter.swapCursor(data);
boolean hasLinkedIdentities = linkedIdsAdapter.getCount() > 0;
if (isSecret) {
view.showCard(true);
view.showEmptyView(!hasLinkedIdentities);
} else {
view.showCard(hasLinkedIdentities);
view.showEmptyView(false);
}
}
@Override
public void onLoaderReset(Loader loader) {
linkedIdsAdapter.swapCursor(null);
}
private void showLinkedId(final int position) {
final LinkedIdViewFragment frag;
try {
frag = linkedIdsAdapter.getLinkedIdFragment(position, masterKeyId);
} catch (IOException e) {
Log.e(Constants.TAG, "IOException", e);
return;
}
fragView.switchToFragment(frag, "linked_id");
}
interface LinkedIdsMvpView {
void setSystemContactClickListener(LinkedIdsClickListener linkedIdsClickListener);
void setLinkedIdsAdapter(LinkedIdsAdapter linkedIdsAdapter);
void showCard(boolean visible);
void showEmptyView(boolean visible);
}
public interface LinkedIdsFragMvpView {
void switchToFragment(Fragment frag, String backStackName);
}
interface LinkedIdsClickListener {
void onLinkedIdItemClick(int position);
void onClickAddIdentity();
}
private void addLinkedIdentity() {
Intent intent = new Intent(context, LinkedIdWizard.class);
intent.setData(KeyRings.buildUnifiedKeyRingUri(masterKeyId));
context.startActivity(intent);
}
}

View File

@@ -0,0 +1,50 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<TextView
style="@style/CardViewHeader"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/section_linked_identities" />
<org.sufficientlysecure.keychain.ui.widget.FixedListView
android:id="@+id/view_key_linked_ids"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="4dp" />
<TextView
android:id="@+id/view_key_linked_ids_empty"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:padding="16dp"
android:gravity="center"
android:text="@string/linked_empty" />
<LinearLayout
android:id="@+id/view_key_card_linked_ids_buttons"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="left|start"
android:orientation="vertical">
<View
android:layout_width="match_parent"
android:layout_height="1dip"
android:background="?android:attr/listDivider" />
<Button
android:id="@+id/view_key_card_linked_ids_add"
style="?android:attr/borderlessButtonStyle"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/menu_linked_add_identity"
android:textColor="@color/card_view_button" />
</LinearLayout>
</LinearLayout>

View File

@@ -22,88 +22,17 @@
card_view:cardCornerRadius="4dp" card_view:cardCornerRadius="4dp"
/> />
<android.support.v7.widget.CardView <org.sufficientlysecure.keychain.ui.widget.LinkedIdentitiesCardView
android:id="@+id/card_linked_ids" android:id="@+id/card_linked_ids"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_gravity="center" android:layout_gravity="center"
android:transitionName="card_linked_ids"
android:visibility="gone" android:visibility="gone"
card_view:cardBackgroundColor="?attr/colorCardViewBackground" card_view:cardBackgroundColor="?attr/colorCardViewBackground"
card_view:cardCornerRadius="4dp" card_view:cardCornerRadius="4dp"
card_view:cardElevation="2dp" card_view:cardElevation="2dp"
card_view:cardUseCompatPadding="true" card_view:cardUseCompatPadding="true"
tools:visibility="visible"> tools:visibility="visible" />
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<TextView
style="@style/CardViewHeader"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/section_linked_identities" />
<org.sufficientlysecure.keychain.ui.widget.FixedListView
android:id="@+id/view_key_linked_ids"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="4dp" />
<TextView
android:id="@+id/view_key_linked_ids_empty"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:padding="16dp"
android:gravity="center"
android:text="@string/linked_empty" />
<TextView
android:id="@+id/view_key_linked_ids_expander"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="4dp"
android:layout_marginTop="4dp"
android:background="?android:selectableItemBackground"
android:clickable="true"
android:drawableEnd="@drawable/ic_expand_more_black_24dp"
android:drawablePadding="3dp"
android:drawableRight="@drawable/ic_expand_more_black_24dp"
android:drawableTop="@drawable/divider"
android:gravity="center_vertical"
android:paddingLeft="8dp"
android:paddingRight="8dp"
android:text="@string/linked_ids_more_unknown"
android:visibility="gone"
tools:visibility="visible" />
<LinearLayout
android:id="@+id/view_key_card_linked_ids_buttons"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="left|start"
android:orientation="vertical">
<View
android:layout_width="match_parent"
android:layout_height="1dip"
android:background="?android:attr/listDivider" />
<Button
android:id="@+id/view_key_card_linked_ids_add"
style="?android:attr/borderlessButtonStyle"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/menu_linked_add_identity"
android:textColor="@color/card_view_button" />
</LinearLayout>
</LinearLayout>
</android.support.v7.widget.CardView>
<android.support.v7.widget.CardView <android.support.v7.widget.CardView
android:id="@+id/view_key_card_user_ids" android:id="@+id/view_key_card_user_ids"