diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/IdentityAdapter.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/IdentityAdapter.java new file mode 100644 index 000000000..75df9ae1c --- /dev/null +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/IdentityAdapter.java @@ -0,0 +1,111 @@ +/* + * Copyright (C) 2014-2015 Dominik Schürmann + * Copyright (C) 2015 Vincent Breitmoser + * + * 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 . + */ + +package org.sufficientlysecure.keychain.ui.adapter; + + +import java.util.List; + +import android.content.Context; +import android.graphics.Typeface; +import android.support.v7.widget.RecyclerView; +import android.view.LayoutInflater; +import android.view.View; +import android.view.View.OnClickListener; +import android.view.ViewGroup; +import android.widget.TextView; + +import org.sufficientlysecure.keychain.R; +import org.sufficientlysecure.keychain.ui.adapter.IdentityAdapter.ViewHolder; +import org.sufficientlysecure.keychain.ui.keyview.loader.IdentityLoader.IdentityInfo; + + +public class IdentityAdapter extends RecyclerView.Adapter { + private final Context context; + private final LayoutInflater layoutInflater; + private List data; + + public IdentityAdapter(Context context) { + super(); + this.layoutInflater = LayoutInflater.from(context); + this.context = context; + } + + public void setData(List data) { + this.data = data; + + notifyDataSetChanged(); + } + + @Override + public void onBindViewHolder(ViewHolder holder, int position) { + IdentityInfo info = data.get(position); + + if (info.name != null) { + holder.vName.setText(info.name); + } else { + holder.vName.setText(R.string.user_id_no_name); + } + if (info.email != null) { + holder.vAddress.setText(info.email); + holder.vAddress.setVisibility(View.VISIBLE); + } else { + holder.vAddress.setVisibility(View.GONE); + } + if (info.comment != null) { + holder.vComment.setText(info.comment); + holder.vComment.setVisibility(View.VISIBLE); + } else { + holder.vComment.setVisibility(View.GONE); + } + + if (info.isPrimary) { + holder.vName.setTypeface(null, Typeface.BOLD); + holder.vAddress.setTypeface(null, Typeface.BOLD); + } else { + holder.vName.setTypeface(null, Typeface.NORMAL); + holder.vAddress.setTypeface(null, Typeface.NORMAL); + } + } + + @Override + public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { + return new ViewHolder(layoutInflater.inflate(R.layout.view_key_identity_user_id, null)); + } + + @Override + public int getItemCount() { + return data != null ? data.size() : 0; + } + + public class ViewHolder extends RecyclerView.ViewHolder { + private View v; + + private final TextView vName; + private final TextView vAddress; + private final TextView vComment; + + public ViewHolder(View view) { + super(view); + + vName = (TextView) view.findViewById(R.id.user_id_item_name); + vAddress = (TextView) view.findViewById(R.id.user_id_item_address); + vComment = (TextView) view.findViewById(R.id.user_id_item_comment); + } + } +} 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 91bbb74b4..14e6375a3 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 @@ -28,7 +28,6 @@ import android.support.v4.app.FragmentTransaction; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; -import android.widget.LinearLayout; import org.sufficientlysecure.keychain.R; import org.sufficientlysecure.keychain.compatibility.DialogFragmentWorkaround; @@ -47,7 +46,6 @@ import org.sufficientlysecure.keychain.util.Preferences; public class ViewKeyFragment extends LoaderFragment implements LinkedIdsFragMvpView, ViewKeyMvpView { - public static final String ARG_MASTER_KEY_ID = "master_key_id"; public static final String ARG_IS_SECRET = "is_secret"; diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/keyview/loader/IdentityLoader.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/keyview/loader/IdentityLoader.java new file mode 100644 index 000000000..a5070c1c8 --- /dev/null +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/keyview/loader/IdentityLoader.java @@ -0,0 +1,151 @@ +/* + * Copyright (C) 2017 Vincent Breitmoser + * + * 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 . + */ + +package org.sufficientlysecure.keychain.ui.keyview.loader; + + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + +import android.content.ContentResolver; +import android.content.Context; +import android.database.Cursor; +import android.support.v4.content.AsyncTaskLoader; +import android.util.Log; + +import org.sufficientlysecure.keychain.Constants; +import org.sufficientlysecure.keychain.provider.KeychainContract.UserPackets; +import org.sufficientlysecure.keychain.ui.keyview.loader.IdentityLoader.IdentityInfo; + + +public class IdentityLoader extends AsyncTaskLoader> { + private static final String[] USER_PACKETS_PROJECTION = new String[]{ + UserPackets._ID, + UserPackets.TYPE, + UserPackets.USER_ID, + UserPackets.ATTRIBUTE_DATA, + UserPackets.RANK, + UserPackets.VERIFIED, + UserPackets.IS_PRIMARY, + UserPackets.IS_REVOKED, + UserPackets.NAME, + UserPackets.EMAIL, + UserPackets.COMMENT, + }; + private static final int INDEX_ID = 0; + private static final int INDEX_TYPE = 1; + private static final int INDEX_USER_ID = 2; + private static final int INDEX_ATTRIBUTE_DATA = 3; + private static final int INDEX_RANK = 4; + private static final int INDEX_VERIFIED = 5; + private static final int INDEX_IS_PRIMARY = 6; + private static final int INDEX_IS_REVOKED = 7; + private static final int INDEX_NAME = 8; + private static final int INDEX_EMAIL = 9; + private static final int INDEX_COMMENT = 10; + + private static final String USER_IDS_WHERE = UserPackets.IS_REVOKED + " = 0"; + + private final ContentResolver contentResolver; + private final long masterKeyId; + + private List cachedResult; + + + public IdentityLoader(Context context, ContentResolver contentResolver, long masterKeyId) { + super(context); + + this.contentResolver = contentResolver; + this.masterKeyId = masterKeyId; + } + + @Override + public List loadInBackground() { + Cursor cursor = contentResolver.query(UserPackets.buildUserIdsUri(masterKeyId), + USER_PACKETS_PROJECTION, USER_IDS_WHERE, null, null); + if (cursor == null) { + Log.e(Constants.TAG, "Error loading key items!"); + return null; + } + + try { + ArrayList identities = new ArrayList<>(); + while (cursor.moveToNext()) { + IdentityInfo identityInfo = new IdentityInfo(masterKeyId, cursor); + identities.add(identityInfo); + } + + return Collections.unmodifiableList(identities); + } finally { + cursor.close(); + } + } + + @Override + public void deliverResult(List keySubkeyStatus) { + cachedResult = keySubkeyStatus; + + if (isStarted()) { + super.deliverResult(keySubkeyStatus); + } + } + + @Override + protected void onStartLoading() { + if (cachedResult != null) { + deliverResult(cachedResult); + } + + if (takeContentChanged() || cachedResult == null) { + forceLoad(); + } + } + + public static class IdentityInfo { + final int position; + + public final int verified; + public final byte[] data; + public final String name; + public final String email; + public final String comment; + + public boolean isPrimary; + + IdentityInfo(long masterKeyId, Cursor cursor) { + position = cursor.getPosition(); + + verified = cursor.getInt(INDEX_VERIFIED); + if (cursor.isNull(INDEX_NAME)) { + data = cursor.getBlob(INDEX_ATTRIBUTE_DATA); + + name = null; + email = null; + comment = null; + } else { + data = null; + + name = cursor.getString(INDEX_NAME); + email = cursor.getString(INDEX_EMAIL); + comment = cursor.getString(INDEX_COMMENT); + } + + isPrimary = cursor.getInt(INDEX_IS_PRIMARY) != 0; + } + } +} diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/keyview/presenter/IdentitiesPresenter.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/keyview/presenter/IdentitiesPresenter.java index 16d122abe..2d65f955d 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/keyview/presenter/IdentitiesPresenter.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/keyview/presenter/IdentitiesPresenter.java @@ -18,28 +18,29 @@ package org.sufficientlysecure.keychain.ui.keyview.presenter; +import java.util.List; + import android.content.Context; import android.content.Intent; -import android.database.Cursor; import android.os.Bundle; import android.support.v4.app.LoaderManager; import android.support.v4.app.LoaderManager.LoaderCallbacks; import android.support.v4.content.Loader; import org.sufficientlysecure.keychain.provider.KeychainContract; -import org.sufficientlysecure.keychain.provider.KeychainContract.KeyRings; import org.sufficientlysecure.keychain.ui.EditIdentitiesActivity; -import org.sufficientlysecure.keychain.ui.adapter.UserIdsAdapter; -import org.sufficientlysecure.keychain.ui.dialog.UserIdInfoDialogFragment; +import org.sufficientlysecure.keychain.ui.adapter.IdentityAdapter; +import org.sufficientlysecure.keychain.ui.keyview.loader.IdentityLoader; +import org.sufficientlysecure.keychain.ui.keyview.loader.IdentityLoader.IdentityInfo; -public class IdentitiesPresenter implements LoaderCallbacks { +public class IdentitiesPresenter implements LoaderCallbacks> { private final Context context; private final IdentitiesMvpView view; private final ViewKeyMvpView viewKeyMvpView; private final int loaderId; - private final UserIdsAdapter userIdsAdapter; + private final IdentityAdapter identitiesAdapter; private final long masterKeyId; private final boolean isSecret; @@ -54,8 +55,8 @@ public class IdentitiesPresenter implements LoaderCallbacks { this.masterKeyId = masterKeyId; this.isSecret = isSecret; - userIdsAdapter = new UserIdsAdapter(context, null, 0, !isSecret); - view.setUserIdsAdapter(userIdsAdapter); + identitiesAdapter = new IdentityAdapter(context); + view.setIdentitiesAdapter(identitiesAdapter); view.setEditIdentitiesButtonVisible(isSecret); @@ -77,29 +78,29 @@ public class IdentitiesPresenter implements LoaderCallbacks { } @Override - public Loader onCreateLoader(int id, Bundle args) { - return UserIdsAdapter.createLoader(context, KeyRings.buildUnifiedKeyRingUri(masterKeyId)); + public Loader> onCreateLoader(int id, Bundle args) { + return new IdentityLoader(context, context.getContentResolver(), masterKeyId); } @Override - public void onLoadFinished(Loader loader, Cursor data) { + public void onLoadFinished(Loader> loader, List data) { viewKeyMvpView.setContentShown(true, false); - userIdsAdapter.swapCursor(data); + identitiesAdapter.setData(data); } @Override public void onLoaderReset(Loader loader) { - userIdsAdapter.swapCursor(null); + identitiesAdapter.setData(null); } private void showUserIdInfo(final int position) { - if (!isSecret) { - final boolean isRevoked = userIdsAdapter.getIsRevoked(position); - final int isVerified = userIdsAdapter.getIsVerified(position); - - UserIdInfoDialogFragment dialogFragment = UserIdInfoDialogFragment.newInstance(isRevoked, isVerified); - viewKeyMvpView.showDialogFragment(dialogFragment, "userIdInfoDialog"); - } +// if (!isSecret) { +// final boolean isRevoked = identitiesAdapter.getIsRevoked(position); +// final int isVerified = identitiesAdapter.getIsVerified(position); +// +// UserIdInfoDialogFragment dialogFragment = UserIdInfoDialogFragment.newInstance(isRevoked, isVerified); +// viewKeyMvpView.showDialogFragment(dialogFragment, "userIdInfoDialog"); +// } } private void editIdentities() { @@ -109,7 +110,7 @@ public class IdentitiesPresenter implements LoaderCallbacks { } public interface IdentitiesMvpView { - void setUserIdsAdapter(UserIdsAdapter userIdsAdapter); + void setIdentitiesAdapter(IdentityAdapter userIdsAdapter); void setIdentitiesCardListener(IdentitiesCardListener identitiesCardListener); void setEditIdentitiesButtonVisible(boolean show); } diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/keyview/view/IdentitiesCardView.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/keyview/view/IdentitiesCardView.java index 26314f5e2..b86e0894b 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/keyview/view/IdentitiesCardView.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/keyview/view/IdentitiesCardView.java @@ -20,6 +20,8 @@ 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; @@ -29,17 +31,18 @@ import android.widget.Button; import android.widget.ListView; import org.sufficientlysecure.keychain.R; +import org.sufficientlysecure.keychain.ui.adapter.IdentityAdapter; import org.sufficientlysecure.keychain.ui.adapter.LinkedIdsAdapter; -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.util.recyclerview.RecyclerItemClickListener; public class IdentitiesCardView extends CardView implements IdentitiesMvpView, LinkedIdsMvpView { private final ListView vLinkedIds; - private final ListView vUserIds; + private final RecyclerView vIdentities; private final View vLinkedIdsDivider; private LinkedIdsClickListener linkedIdsClickListener; @@ -50,7 +53,8 @@ public class IdentitiesCardView extends CardView implements IdentitiesMvpView, L View view = LayoutInflater.from(context).inflate(R.layout.identities_card, this, true); - vUserIds = (ListView) view.findViewById(R.id.view_key_user_ids); + vIdentities = (RecyclerView) view.findViewById(R.id.view_key_user_ids); + vIdentities.setLayoutManager(new LinearLayoutManager(context)); Button userIdsEditButton = (Button) view.findViewById(R.id.view_key_card_user_ids_edit); userIdsEditButton.setOnClickListener(new OnClickListener() { @@ -62,14 +66,15 @@ public class IdentitiesCardView extends CardView implements IdentitiesMvpView, L } }); - vUserIds.setOnItemClickListener(new OnItemClickListener() { - @Override - public void onItemClick(AdapterView parent, View view, int position, long id) { - if (identitiesCardListener != null) { - identitiesCardListener.onIdentityItemClick(position); - } - } - }); + vIdentities.addOnItemTouchListener(new RecyclerItemClickListener(context, + new RecyclerItemClickListener.OnItemClickListener() { + @Override + public void onItemClick(View view, int position) { + if (identitiesCardListener != null) { + identitiesCardListener.onIdentityItemClick(position); + } + } + })); vLinkedIds = (ListView) view.findViewById(R.id.view_key_linked_ids); Button linkedIdsAddButton = (Button) view.findViewById(R.id.view_key_card_linked_ids_add); @@ -96,8 +101,8 @@ public class IdentitiesCardView extends CardView implements IdentitiesMvpView, L } @Override - public void setUserIdsAdapter(UserIdsAdapter userIdsAdapter) { - vUserIds.setAdapter(userIdsAdapter); + public void setIdentitiesAdapter(IdentityAdapter identityAdapter) { + vIdentities.setAdapter(identityAdapter); } @Override diff --git a/OpenKeychain/src/main/res/layout/identities_card.xml b/OpenKeychain/src/main/res/layout/identities_card.xml index 775b1e2d8..f460c2d14 100644 --- a/OpenKeychain/src/main/res/layout/identities_card.xml +++ b/OpenKeychain/src/main/res/layout/identities_card.xml @@ -27,7 +27,7 @@ tools:visibility="visible" /> - + + + + + + + + +