diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/CertSectionedListAdapter.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/CertSectionedListAdapter.java index e0a4df9c1..abc730292 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/CertSectionedListAdapter.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/CertSectionedListAdapter.java @@ -32,6 +32,7 @@ import org.sufficientlysecure.keychain.pgp.KeyRing; import org.sufficientlysecure.keychain.pgp.WrappedSignature; import org.sufficientlysecure.keychain.provider.KeychainContract; import org.sufficientlysecure.keychain.provider.KeychainDatabase; +import org.sufficientlysecure.keychain.ui.adapter.CertSectionedListAdapter.CertCursor; import org.sufficientlysecure.keychain.ui.util.KeyFormattingUtils; import org.sufficientlysecure.keychain.ui.util.adapter.CursorAdapter; import org.sufficientlysecure.keychain.ui.util.adapter.SectionCursorAdapter; @@ -39,7 +40,7 @@ import org.sufficientlysecure.keychain.ui.util.adapter.SectionCursorAdapter; import java.util.ArrayList; import java.util.Arrays; -public class CertSectionedListAdapter extends SectionCursorAdapter { private CertListListener mListener; @@ -162,11 +163,11 @@ public class CertSectionedListAdapter extends SectionCursorAdapter projection = new ArrayList<>(); - projection.addAll(Arrays.asList(AbstractCursor.PROJECTION)); + projection.addAll(Arrays.asList(SimpleCursor.PROJECTION)); projection.addAll(Arrays.asList( KeychainContract.Certs.MASTER_KEY_ID, KeychainContract.Certs.VERIFIED, diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/TrustIdsAdapter.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/TrustIdsAdapter.java index 5b25538c6..dd6a6595c 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/TrustIdsAdapter.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/TrustIdsAdapter.java @@ -21,7 +21,6 @@ package org.sufficientlysecure.keychain.ui.adapter; import java.util.HashMap; import java.util.List; -import android.app.Activity; import android.content.ActivityNotFoundException; import android.content.Context; import android.content.Intent; @@ -32,7 +31,7 @@ import android.database.Cursor; import android.graphics.drawable.Drawable; import android.net.Uri; import android.support.v4.content.CursorLoader; -import android.support.v4.widget.CursorAdapter; +import android.support.v7.widget.RecyclerView; import android.view.LayoutInflater; import android.view.View; import android.view.View.OnClickListener; @@ -43,9 +42,14 @@ import android.widget.TextView; import org.openintents.openpgp.util.OpenPgpApi; import org.sufficientlysecure.keychain.R; import org.sufficientlysecure.keychain.provider.KeychainContract.ApiTrustIdentity; +import org.sufficientlysecure.keychain.ui.adapter.TrustIdsAdapter.ViewHolder; +import org.sufficientlysecure.keychain.ui.util.adapter.CursorAdapter; +import org.sufficientlysecure.keychain.ui.util.adapter.CursorAdapter.SimpleCursor; +import org.sufficientlysecure.keychain.ui.util.recyclerview.RecyclerItemClickListener; +import org.sufficientlysecure.keychain.ui.util.recyclerview.RecyclerItemClickListener.OnItemClickListener; -public class TrustIdsAdapter extends CursorAdapter { +public class TrustIdsAdapter extends CursorAdapter { private static final String[] TRUST_IDS_PROJECTION = new String[] { ApiTrustIdentity._ID, ApiTrustIdentity.PACKAGE_NAME, @@ -55,39 +59,12 @@ public class TrustIdsAdapter extends CursorAdapter { private static final int INDEX_TRUST_ID = 2; - protected LayoutInflater mInflater; private HashMap appIconCache = new HashMap<>(); + private Integer expandedPosition; + private OnItemClickListener onItemClickListener; - - public TrustIdsAdapter(Context context, Cursor c, int flags) { - super(context, c, flags); - mInflater = LayoutInflater.from(context); - } - - @Override - public void bindView(View view, final Context context, Cursor cursor) { - final String packageName = cursor.getString(INDEX_PACKAGE_NAME); - final String trustId = cursor.getString(INDEX_TRUST_ID); - - TextView vTrustId = (TextView) view.findViewById(R.id.trust_id_name); - ImageView vAppIcon = (ImageView) view.findViewById(R.id.trust_id_app_icon); - ImageView vActionIcon = (ImageView) view.findViewById(R.id.trust_id_action); - - Drawable drawable = getDrawableForPackageName(packageName); - vTrustId.setText(trustId); - vAppIcon.setImageDrawable(drawable); - - if (isTrustIdActivityAvailable(packageName, trustId, context)) { - vActionIcon.setVisibility(View.VISIBLE); - vActionIcon.setOnClickListener(new OnClickListener() { - @Override - public void onClick(View view) { - launchTrustIdActivity(packageName, trustId, context); - } - }); - } else { - vActionIcon.setVisibility(View.GONE); - } + public TrustIdsAdapter(Context context, SimpleCursor simpleCursor) { + super(context, simpleCursor, FLAG_REGISTER_CONTENT_OBSERVER); } private void launchTrustIdActivity(String packageName, String trustId, Context context) { @@ -118,7 +95,7 @@ public class TrustIdsAdapter extends CursorAdapter { return appIconCache.get(packageName); } - PackageManager pm = mContext.getPackageManager(); + PackageManager pm = getContext().getPackageManager(); try { ApplicationInfo ai = pm.getApplicationInfo(packageName, 0); @@ -136,8 +113,88 @@ public class TrustIdsAdapter extends CursorAdapter { return new CursorLoader(context, baseUri, TrustIdsAdapter.TRUST_IDS_PROJECTION, null, null, null); } + public void setExpandedView(Integer position) { + if (position == null) { + if (expandedPosition != null) { + notifyItemChanged(expandedPosition); + } + expandedPosition = null; + } else if (expandedPosition == null || !expandedPosition.equals(position)) { + if (expandedPosition != null) { + notifyItemChanged(expandedPosition); + } + expandedPosition = position; + notifyItemChanged(position); + } + } + + public void setOnItemClickListener(RecyclerItemClickListener.OnItemClickListener onItemClickListener) { + this.onItemClickListener = onItemClickListener; + } + @Override - public View newView(Context context, Cursor cursor, ViewGroup parent) { - return mInflater.inflate(R.layout.view_key_trust_id_item, parent, false); + public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { + View view = LayoutInflater.from(getContext()).inflate(R.layout.view_key_trust_id_item, parent, false); + return new ViewHolder(view); + } + + @Override + public void onBindViewHolder(final ViewHolder holder, final int position) { + moveCursorOrThrow(position); + + SimpleCursor cursor = getCursor(); + final String packageName = cursor.getString(INDEX_PACKAGE_NAME); + final String trustId = cursor.getString(INDEX_TRUST_ID); + + Drawable drawable = getDrawableForPackageName(packageName); + holder.vTrustId.setText(trustId); + holder.vAppIcon.setImageDrawable(drawable); + + if (isTrustIdActivityAvailable(packageName, trustId, getContext())) { + holder.vActionIcon.setVisibility(View.VISIBLE); + holder.vActionIcon.setOnClickListener(new OnClickListener() { + @Override + public void onClick(View view) { + launchTrustIdActivity(packageName, trustId, getContext()); + } + }); + } else { + holder.vActionIcon.setVisibility(View.GONE); + } + + if (expandedPosition != null && position == expandedPosition) { + holder.vButtonBar.setVisibility(View.VISIBLE); + } else { + holder.vButtonBar.setVisibility(View.GONE); + } + + holder.itemView.setOnClickListener(new OnClickListener() { + @Override + public void onClick(View view) { + if (onItemClickListener != null) { + onItemClickListener.onItemClick(holder.itemView, position); + } + } + }); + } + + public void swapCursor(Cursor data) { + swapCursor(new SimpleCursor(data)); + } + + public static class ViewHolder extends RecyclerView.ViewHolder { + private final TextView vTrustId; + private final ImageView vAppIcon; + private final ImageView vActionIcon; + private final View vButtonBar; + + public ViewHolder(View view) { + super(view); + + vTrustId = (TextView) view.findViewById(R.id.trust_id_name); + vAppIcon = (ImageView) view.findViewById(R.id.trust_id_app_icon); + vActionIcon = (ImageView) view.findViewById(R.id.trust_id_action); + vButtonBar = view.findViewById(R.id.trust_id_button_bar); + } } } diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/keyview/ViewKeyFragment.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/keyview/ViewKeyFragment.java index f6629bd1a..1e2407fd8 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/keyview/ViewKeyFragment.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/keyview/ViewKeyFragment.java @@ -24,6 +24,8 @@ import android.os.Bundle; import android.os.Handler; import android.support.v4.app.DialogFragment; import android.support.v4.app.Fragment; +import android.support.v4.app.FragmentManager; +import android.support.v4.app.FragmentManager.OnBackStackChangedListener; import android.support.v4.app.FragmentTransaction; import android.view.LayoutInflater; import android.view.View; @@ -128,7 +130,7 @@ public class ViewKeyFragment extends LoaderFragment implements ViewKeyMvpView { mKeyserverStatusPresenter.startLoader(getLoaderManager()); mTrustIdsPresenter = new TrustIdsPresenter( - getContext(), mTrustIdsCard, LOADER_ID_TRUST_IDS, masterKeyId, false); + getContext(), mTrustIdsCard, this, LOADER_ID_TRUST_IDS, masterKeyId, false); mTrustIdsPresenter.startLoader(getLoaderManager()); } @@ -174,4 +176,28 @@ public class ViewKeyFragment extends LoaderFragment implements ViewKeyMvpView { } }); } + + @Override + public void addFakeBackStackItem(String tag, final OnBackStackPoppedListener listener) { + FragmentManager fragmentManager = getFragmentManager(); + if (fragmentManager.getBackStackEntryCount() > 0) { + return; + } + + fragmentManager.beginTransaction() + .addToBackStack("expand_trust_id") + .commitAllowingStateLoss(); + fragmentManager.executePendingTransactions(); + + fragmentManager.addOnBackStackChangedListener(new OnBackStackChangedListener() { + @Override + public void onBackStackChanged() { + FragmentManager fragMan = getFragmentManager(); + fragMan.popBackStack("expand_trust_id", FragmentManager.POP_BACK_STACK_INCLUSIVE); + fragMan.removeOnBackStackChangedListener(this); + + listener.onBackStackPopped(); + } + }); + } } diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/keyview/presenter/TrustIdsPresenter.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/keyview/presenter/TrustIdsPresenter.java index b33497958..532cc4e7a 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/keyview/presenter/TrustIdsPresenter.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/keyview/presenter/TrustIdsPresenter.java @@ -24,15 +24,18 @@ import android.os.Bundle; import android.support.v4.app.LoaderManager; import android.support.v4.app.LoaderManager.LoaderCallbacks; import android.support.v4.content.Loader; +import android.view.View; import org.sufficientlysecure.keychain.provider.KeychainContract.KeyRings; import org.sufficientlysecure.keychain.ui.adapter.TrustIdsAdapter; -import org.sufficientlysecure.keychain.ui.adapter.UserIdsAdapter; +import org.sufficientlysecure.keychain.ui.keyview.presenter.ViewKeyMvpView.OnBackStackPoppedListener; +import org.sufficientlysecure.keychain.ui.util.recyclerview.RecyclerItemClickListener.OnItemClickListener; public class TrustIdsPresenter implements LoaderCallbacks { private final Context context; private final TrustIdsMvpView view; + private final ViewKeyMvpView viewKeyMvpView; private final int loaderId; private final TrustIdsAdapter trustIdsAdapter; @@ -40,21 +43,23 @@ public class TrustIdsPresenter implements LoaderCallbacks { private final long masterKeyId; private final boolean isSecret; - public TrustIdsPresenter(Context context, TrustIdsMvpView view, int loaderId, long masterKeyId, boolean isSecret) { + public TrustIdsPresenter(Context context, TrustIdsMvpView view, ViewKeyMvpView viewKeyMvpView, int loaderId, + long masterKeyId, boolean isSecret) { this.context = context; this.view = view; + this.viewKeyMvpView = viewKeyMvpView; this.loaderId = loaderId; this.masterKeyId = masterKeyId; this.isSecret = isSecret; - trustIdsAdapter = new TrustIdsAdapter(context, null, 0); + trustIdsAdapter = new TrustIdsAdapter(context, null); view.setTrustIdAdapter(trustIdsAdapter); - view.setTrustIdClickListener(new TrustIdsClickListener() { + trustIdsAdapter.setOnItemClickListener(new OnItemClickListener() { @Override - public void onTrustIdItemClick(int position) { - + public void onItemClick(View view, int position) { + onClickTrustId(position); } }); } @@ -71,7 +76,7 @@ public class TrustIdsPresenter implements LoaderCallbacks { @Override public void onLoadFinished(Loader loader, Cursor data) { trustIdsAdapter.swapCursor(data); - view.showCard(trustIdsAdapter.getCount() > 0); + view.showCard(data.getCount() > 0); } @Override @@ -79,14 +84,19 @@ public class TrustIdsPresenter implements LoaderCallbacks { trustIdsAdapter.swapCursor(null); } + private void onClickTrustId(int position) { + trustIdsAdapter.setExpandedView(position); + + viewKeyMvpView.addFakeBackStackItem("expand_trust_id", new OnBackStackPoppedListener() { + @Override + public void onBackStackPopped() { + trustIdsAdapter.setExpandedView(null); + } + }); + } + public interface TrustIdsMvpView { void setTrustIdAdapter(TrustIdsAdapter trustIdsAdapter); void showCard(boolean show); - - void setTrustIdClickListener(TrustIdsClickListener trustIdsClickListener); - } - - public interface TrustIdsClickListener { - void onTrustIdItemClick(int position); } } \ No newline at end of file diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/keyview/presenter/ViewKeyMvpView.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/keyview/presenter/ViewKeyMvpView.java index 98399a52c..42a2b9dc6 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/keyview/presenter/ViewKeyMvpView.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/keyview/presenter/ViewKeyMvpView.java @@ -12,4 +12,10 @@ public interface ViewKeyMvpView { void startActivityAndShowResultSnackbar(Intent intent); void showDialogFragment(DialogFragment dialogFragment, final String tag); void setContentShown(boolean show, boolean animate); + + void addFakeBackStackItem(String tag, OnBackStackPoppedListener listener); + + interface OnBackStackPoppedListener { + void onBackStackPopped(); + } } diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/keyview/view/TrustIdsIdCardView.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/keyview/view/TrustIdsIdCardView.java index 93fa03750..42855e7b5 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/keyview/view/TrustIdsIdCardView.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/keyview/view/TrustIdsIdCardView.java @@ -20,45 +20,27 @@ package org.sufficientlysecure.keychain.ui.keyview.view; import android.content.Context; import android.support.v7.widget.CardView; +import android.support.v7.widget.LinearLayoutManager; +import android.support.v7.widget.RecyclerView; 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 org.sufficientlysecure.keychain.R; -import org.sufficientlysecure.keychain.ui.adapter.LinkedIdsAdapter; import org.sufficientlysecure.keychain.ui.adapter.TrustIdsAdapter; -import org.sufficientlysecure.keychain.ui.adapter.UserIdsAdapter; -import org.sufficientlysecure.keychain.ui.keyview.presenter.IdentitiesPresenter.IdentitiesCardListener; -import org.sufficientlysecure.keychain.ui.keyview.presenter.IdentitiesPresenter.IdentitiesMvpView; -import org.sufficientlysecure.keychain.ui.keyview.presenter.LinkedIdentitiesPresenter.LinkedIdsClickListener; -import org.sufficientlysecure.keychain.ui.keyview.presenter.LinkedIdentitiesPresenter.LinkedIdsMvpView; -import org.sufficientlysecure.keychain.ui.keyview.presenter.TrustIdsPresenter.TrustIdsClickListener; import org.sufficientlysecure.keychain.ui.keyview.presenter.TrustIdsPresenter.TrustIdsMvpView; public class TrustIdsIdCardView extends CardView implements TrustIdsMvpView { - private ListView vTrustIds; - - private TrustIdsClickListener trustIdsClickListener; + private RecyclerView vTrustIds; public TrustIdsIdCardView(Context context, AttributeSet attrs) { super(context, attrs); View view = LayoutInflater.from(context).inflate(R.layout.trust_ids_card, this, true); - vTrustIds = (ListView) view.findViewById(R.id.view_key_trust_ids); - vTrustIds.setOnItemClickListener(new OnItemClickListener() { - @Override - public void onItemClick(AdapterView parent, View view, int position, long id) { - if (trustIdsClickListener != null) { - trustIdsClickListener.onTrustIdItemClick(position); - } - } - }); + vTrustIds = (RecyclerView) view.findViewById(R.id.view_key_trust_ids); + vTrustIds.setLayoutManager(new LinearLayoutManager(getContext())); } @Override @@ -70,9 +52,4 @@ public class TrustIdsIdCardView extends CardView implements TrustIdsMvpView { public void showCard(boolean show) { setVisibility(show ? View.VISIBLE : View.GONE); } - - @Override - public void setTrustIdClickListener(TrustIdsClickListener trustIdsClickListener) { - this.trustIdsClickListener = trustIdsClickListener; - } } diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/util/adapter/CursorAdapter.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/util/adapter/CursorAdapter.java index e9fb2f035..06fa523d0 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/util/adapter/CursorAdapter.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/util/adapter/CursorAdapter.java @@ -27,6 +27,7 @@ import android.support.v7.widget.RecyclerView; import org.sufficientlysecure.keychain.Constants; import org.sufficientlysecure.keychain.provider.KeychainContract; +import org.sufficientlysecure.keychain.ui.util.adapter.CursorAdapter.SimpleCursor; import org.sufficientlysecure.keychain.util.Log; import java.lang.reflect.Constructor; @@ -35,7 +36,7 @@ import java.util.Arrays; import java.util.Date; import java.util.HashMap; -public abstract class CursorAdapter +public abstract class CursorAdapter extends RecyclerView.Adapter { public static final String TAG = "CursorAdapter"; @@ -58,7 +59,7 @@ public abstract class CursorAdapternot + * {@link #changeCursor(SimpleCursor)}, the returned old Cursor is not * closed. * * @param newCursor The new cursor to be used. @@ -312,10 +313,10 @@ public abstract class CursorAdapter T wrap(Cursor cursor, Class type) { + public static T wrap(Cursor cursor, Class type) { if (cursor != null) { try { Constructor constructor = type.getConstructor(Cursor.class); @@ -335,7 +336,7 @@ public abstract class CursorAdapter(cursor.getColumnCount() * 4 / 3, 0.75f); } @@ -376,12 +377,12 @@ public abstract class CursorAdapter arr = new ArrayList<>(); - arr.addAll(Arrays.asList(AbstractCursor.PROJECTION)); + arr.addAll(Arrays.asList(SimpleCursor.PROJECTION)); arr.addAll(Arrays.asList( KeychainContract.KeyRings.MASTER_KEY_ID, KeychainContract.KeyRings.USER_ID, diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/util/adapter/SectionCursorAdapter.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/util/adapter/SectionCursorAdapter.java index b4292782d..ca9f5e9f6 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/util/adapter/SectionCursorAdapter.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/util/adapter/SectionCursorAdapter.java @@ -19,7 +19,6 @@ package org.sufficientlysecure.keychain.ui.util.adapter; import android.content.Context; -import android.database.Cursor; import android.support.v4.util.SparseArrayCompat; import android.support.v7.widget.RecyclerView; import android.view.View; @@ -27,18 +26,16 @@ import android.view.ViewGroup; import com.tonicartos.superslim.LayoutManager; +import org.sufficientlysecure.keychain.ui.util.adapter.CursorAdapter.SimpleCursor; import org.sufficientlysecure.keychain.util.Log; -import org.sufficientlysecure.keychain.util.Log; - -import java.util.Objects; /** * @param section type. * @param the view holder extending {@code BaseViewHolder} that is bound to the cursor data. * @param the view holder extending {@code BaseViewHolder<>} that is bound to the section data. */ -public abstract class SectionCursorAdapter extends CursorAdapter { public static final String TAG = "SectionCursorAdapter"; diff --git a/OpenKeychain/src/main/res/layout/trust_ids_card.xml b/OpenKeychain/src/main/res/layout/trust_ids_card.xml index f99d73c10..34e43b5e5 100644 --- a/OpenKeychain/src/main/res/layout/trust_ids_card.xml +++ b/OpenKeychain/src/main/res/layout/trust_ids_card.xml @@ -12,7 +12,7 @@ android:layout_height="wrap_content" android:text="Known to Apps as" /> - + android:orientation="vertical" + android:animateLayoutChanges="true"> - - - - - + + + + + + + + + + + style="?android:buttonBarStyle"> - +