move linked identities into loader structure
This commit is contained in:
@@ -284,6 +284,10 @@ public class KeychainContract {
|
|||||||
return CONTENT_URI.buildUpon().appendPath(uri.getPathSegments().get(1)).appendPath(PATH_USER_IDS).build();
|
return CONTENT_URI.buildUpon().appendPath(uri.getPathSegments().get(1)).appendPath(PATH_USER_IDS).build();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static Uri buildLinkedIdsUri(long masterKeyId) {
|
||||||
|
return CONTENT_URI.buildUpon().appendPath(Long.toString(masterKeyId)).appendPath(PATH_LINKED_IDS).build();
|
||||||
|
}
|
||||||
|
|
||||||
public static Uri buildLinkedIdsUri(Uri uri) {
|
public static Uri buildLinkedIdsUri(Uri uri) {
|
||||||
return CONTENT_URI.buildUpon().appendPath(uri.getPathSegments().get(1)).appendPath(PATH_LINKED_IDS).build();
|
return CONTENT_URI.buildUpon().appendPath(uri.getPathSegments().get(1)).appendPath(PATH_LINKED_IDS).build();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (C) 2014-2015 Dominik Schürmann <dominik@dominikschuermann.de>
|
* Copyright (C) 2017 Vincent Breitmoser <v.breitmoser@mugenguild.com>
|
||||||
* Copyright (C) 2015 Vincent Breitmoser <v.breitmoser@mugenguild.com>
|
|
||||||
*
|
*
|
||||||
* This program is free software: you can redistribute it and/or modify
|
* 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
|
* it under the terms of the GNU General Public License as published by
|
||||||
@@ -21,29 +20,47 @@ package org.sufficientlysecure.keychain.ui.adapter;
|
|||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
|
import android.animation.ObjectAnimator;
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.graphics.Typeface;
|
import android.graphics.Typeface;
|
||||||
|
import android.os.Build;
|
||||||
|
import android.os.Build.VERSION_CODES;
|
||||||
import android.support.v7.widget.RecyclerView;
|
import android.support.v7.widget.RecyclerView;
|
||||||
import android.view.LayoutInflater;
|
import android.view.LayoutInflater;
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
import android.view.View.OnClickListener;
|
|
||||||
import android.view.ViewGroup;
|
import android.view.ViewGroup;
|
||||||
|
import android.widget.ImageView;
|
||||||
import android.widget.TextView;
|
import android.widget.TextView;
|
||||||
|
|
||||||
import org.sufficientlysecure.keychain.R;
|
import org.sufficientlysecure.keychain.R;
|
||||||
|
import org.sufficientlysecure.keychain.linked.UriAttribute;
|
||||||
|
import org.sufficientlysecure.keychain.provider.KeychainContract.Certs;
|
||||||
import org.sufficientlysecure.keychain.ui.adapter.IdentityAdapter.ViewHolder;
|
import org.sufficientlysecure.keychain.ui.adapter.IdentityAdapter.ViewHolder;
|
||||||
import org.sufficientlysecure.keychain.ui.keyview.loader.IdentityLoader.IdentityInfo;
|
import org.sufficientlysecure.keychain.ui.keyview.loader.IdentityLoader.IdentityInfo;
|
||||||
|
import org.sufficientlysecure.keychain.ui.keyview.loader.IdentityLoader.LinkedIdInfo;
|
||||||
|
import org.sufficientlysecure.keychain.ui.keyview.loader.IdentityLoader.UserIdInfo;
|
||||||
|
import org.sufficientlysecure.keychain.ui.util.KeyFormattingUtils;
|
||||||
|
import org.sufficientlysecure.keychain.ui.util.KeyFormattingUtils.State;
|
||||||
|
import org.sufficientlysecure.keychain.ui.util.SubtleAttentionSeeker;
|
||||||
|
|
||||||
|
|
||||||
public class IdentityAdapter extends RecyclerView.Adapter<ViewHolder> {
|
public class IdentityAdapter extends RecyclerView.Adapter<ViewHolder> {
|
||||||
|
private static final int VIEW_TYPE_USER_ID = 0;
|
||||||
|
private static final int VIEW_TYPE_LINKED_ID = 1;
|
||||||
|
|
||||||
|
|
||||||
private final Context context;
|
private final Context context;
|
||||||
private final LayoutInflater layoutInflater;
|
private final LayoutInflater layoutInflater;
|
||||||
|
private final boolean isSecret;
|
||||||
|
|
||||||
private List<IdentityInfo> data;
|
private List<IdentityInfo> data;
|
||||||
|
|
||||||
public IdentityAdapter(Context context) {
|
|
||||||
|
public IdentityAdapter(Context context, boolean isSecret) {
|
||||||
super();
|
super();
|
||||||
this.layoutInflater = LayoutInflater.from(context);
|
this.layoutInflater = LayoutInflater.from(context);
|
||||||
this.context = context;
|
this.context = context;
|
||||||
|
this.isSecret = isSecret;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setData(List<IdentityInfo> data) {
|
public void setData(List<IdentityInfo> data) {
|
||||||
@@ -56,36 +73,37 @@ public class IdentityAdapter extends RecyclerView.Adapter<ViewHolder> {
|
|||||||
public void onBindViewHolder(ViewHolder holder, int position) {
|
public void onBindViewHolder(ViewHolder holder, int position) {
|
||||||
IdentityInfo info = data.get(position);
|
IdentityInfo info = data.get(position);
|
||||||
|
|
||||||
if (info.name != null) {
|
int viewType = getItemViewType(position);
|
||||||
holder.vName.setText(info.name);
|
if (viewType == VIEW_TYPE_USER_ID) {
|
||||||
|
((UserIdViewHolder) holder).bind((UserIdInfo) info);
|
||||||
|
} else if (viewType == VIEW_TYPE_LINKED_ID) {
|
||||||
|
((LinkedIdViewHolder) holder).bind(context, (LinkedIdInfo) info, isSecret);
|
||||||
} else {
|
} else {
|
||||||
holder.vName.setText(R.string.user_id_no_name);
|
throw new IllegalStateException("unhandled identitytype!");
|
||||||
}
|
|
||||||
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
|
@Override
|
||||||
public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
|
public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
|
||||||
return new ViewHolder(layoutInflater.inflate(R.layout.view_key_identity_user_id, null));
|
if (viewType == VIEW_TYPE_USER_ID) {
|
||||||
|
return new UserIdViewHolder(layoutInflater.inflate(R.layout.view_key_identity_user_id, parent, false));
|
||||||
|
} else if (viewType == VIEW_TYPE_LINKED_ID) {
|
||||||
|
return new LinkedIdViewHolder(layoutInflater.inflate(R.layout.linked_id_item, parent, false));
|
||||||
|
} else {
|
||||||
|
throw new IllegalStateException("unhandled identitytype!");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getItemViewType(int position) {
|
||||||
|
IdentityInfo info = data.get(position);
|
||||||
|
if (info instanceof UserIdInfo) {
|
||||||
|
return VIEW_TYPE_USER_ID;
|
||||||
|
} else if (info instanceof LinkedIdInfo) {
|
||||||
|
return VIEW_TYPE_LINKED_ID;
|
||||||
|
} else {
|
||||||
|
throw new IllegalStateException("unhandled identitytype!");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -93,19 +111,121 @@ public class IdentityAdapter extends RecyclerView.Adapter<ViewHolder> {
|
|||||||
return data != null ? data.size() : 0;
|
return data != null ? data.size() : 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
public class ViewHolder extends RecyclerView.ViewHolder {
|
public IdentityInfo getInfo(int position) {
|
||||||
private View v;
|
return data.get(position);
|
||||||
|
}
|
||||||
|
|
||||||
|
abstract static class ViewHolder extends RecyclerView.ViewHolder {
|
||||||
|
public ViewHolder(View itemView) {
|
||||||
|
super(itemView);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class LinkedIdViewHolder extends ViewHolder {
|
||||||
|
public final ImageView vVerified;
|
||||||
|
final private ImageView vIcon;
|
||||||
|
final private TextView vTitle;
|
||||||
|
final private TextView vComment;
|
||||||
|
|
||||||
|
public LinkedIdViewHolder(View view) {
|
||||||
|
super(view);
|
||||||
|
|
||||||
|
vVerified = (ImageView) view.findViewById(R.id.linked_id_certified_icon);
|
||||||
|
vIcon = (ImageView) view.findViewById(R.id.linked_id_type_icon);
|
||||||
|
vTitle = (TextView) view.findViewById(R.id.linked_id_title);
|
||||||
|
vComment = (TextView) view.findViewById(R.id.linked_id_comment);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void bind(Context context, LinkedIdInfo info, boolean isSecret) {
|
||||||
|
bindVerified(context, info, isSecret);
|
||||||
|
|
||||||
|
UriAttribute uriAttribute = info.getUriAttribute();
|
||||||
|
bind(context, uriAttribute);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void bind(Context context, UriAttribute uriAttribute) {
|
||||||
|
vTitle.setText(uriAttribute.getDisplayTitle(context));
|
||||||
|
|
||||||
|
String comment = uriAttribute.getDisplayComment(context);
|
||||||
|
if (comment != null) {
|
||||||
|
vComment.setVisibility(View.VISIBLE);
|
||||||
|
vComment.setText(comment);
|
||||||
|
} else {
|
||||||
|
vComment.setVisibility(View.GONE);
|
||||||
|
}
|
||||||
|
|
||||||
|
vIcon.setImageResource(uriAttribute.getDisplayIcon());
|
||||||
|
}
|
||||||
|
|
||||||
|
private void bindVerified(Context context, IdentityInfo info, boolean isSecret) {
|
||||||
|
if (!isSecret) {
|
||||||
|
switch (info.getVerified()) {
|
||||||
|
case Certs.VERIFIED_SECRET:
|
||||||
|
KeyFormattingUtils.setStatusImage(context, vVerified,
|
||||||
|
null, State.VERIFIED, KeyFormattingUtils.DEFAULT_COLOR);
|
||||||
|
break;
|
||||||
|
case Certs.VERIFIED_SELF:
|
||||||
|
KeyFormattingUtils.setStatusImage(context, vVerified,
|
||||||
|
null, State.UNVERIFIED, KeyFormattingUtils.DEFAULT_COLOR);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
KeyFormattingUtils.setStatusImage(context, vVerified,
|
||||||
|
null, State.INVALID, KeyFormattingUtils.DEFAULT_COLOR);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void seekAttention() {
|
||||||
|
if (Build.VERSION.SDK_INT >= VERSION_CODES.LOLLIPOP) {
|
||||||
|
ObjectAnimator anim = SubtleAttentionSeeker.tintText(vComment, 1000);
|
||||||
|
anim.setStartDelay(200);
|
||||||
|
anim.start();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static class UserIdViewHolder extends ViewHolder {
|
||||||
private final TextView vName;
|
private final TextView vName;
|
||||||
private final TextView vAddress;
|
private final TextView vAddress;
|
||||||
private final TextView vComment;
|
private final TextView vComment;
|
||||||
|
|
||||||
public ViewHolder(View view) {
|
private UserIdViewHolder(View view) {
|
||||||
super(view);
|
super(view);
|
||||||
|
|
||||||
vName = (TextView) view.findViewById(R.id.user_id_item_name);
|
vName = (TextView) view.findViewById(R.id.user_id_item_name);
|
||||||
vAddress = (TextView) view.findViewById(R.id.user_id_item_address);
|
vAddress = (TextView) view.findViewById(R.id.user_id_item_address);
|
||||||
vComment = (TextView) view.findViewById(R.id.user_id_item_comment);
|
vComment = (TextView) view.findViewById(R.id.user_id_item_comment);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void bind(UserIdInfo info) {
|
||||||
|
if (info.getName() != null) {
|
||||||
|
vName.setText(info.getName());
|
||||||
|
} else {
|
||||||
|
vName.setText(R.string.user_id_no_name);
|
||||||
|
}
|
||||||
|
if (info.getEmail() != null) {
|
||||||
|
vAddress.setText(info.getEmail());
|
||||||
|
vAddress.setVisibility(View.VISIBLE);
|
||||||
|
} else {
|
||||||
|
vAddress.setVisibility(View.GONE);
|
||||||
|
}
|
||||||
|
if (info.getComment() != null) {
|
||||||
|
vComment.setText(info.getComment());
|
||||||
|
vComment.setVisibility(View.VISIBLE);
|
||||||
|
} else {
|
||||||
|
vComment.setVisibility(View.GONE);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (info.isPrimary()) {
|
||||||
|
vName.setTypeface(null, Typeface.BOLD);
|
||||||
|
vAddress.setTypeface(null, Typeface.BOLD);
|
||||||
|
} else {
|
||||||
|
vName.setTypeface(null, Typeface.NORMAL);
|
||||||
|
vAddress.setTypeface(null, Typeface.NORMAL);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,205 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (C) 2014-2015 Dominik Schürmann <dominik@dominikschuermann.de>
|
|
||||||
* Copyright (C) 2015 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.adapter;
|
|
||||||
|
|
||||||
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.util.WeakHashMap;
|
|
||||||
|
|
||||||
import android.animation.ObjectAnimator;
|
|
||||||
import android.content.Context;
|
|
||||||
import android.database.Cursor;
|
|
||||||
import android.net.Uri;
|
|
||||||
import android.os.Build;
|
|
||||||
import android.os.Build.VERSION_CODES;
|
|
||||||
import android.support.v4.content.CursorLoader;
|
|
||||||
import android.view.LayoutInflater;
|
|
||||||
import android.view.View;
|
|
||||||
import android.view.ViewGroup;
|
|
||||||
import android.widget.ImageView;
|
|
||||||
import android.widget.TextView;
|
|
||||||
|
|
||||||
import org.sufficientlysecure.keychain.Constants;
|
|
||||||
import org.sufficientlysecure.keychain.R;
|
|
||||||
import org.sufficientlysecure.keychain.linked.LinkedAttribute;
|
|
||||||
import org.sufficientlysecure.keychain.linked.UriAttribute;
|
|
||||||
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.ui.keyview.LinkedIdViewFragment;
|
|
||||||
import org.sufficientlysecure.keychain.ui.util.KeyFormattingUtils;
|
|
||||||
import org.sufficientlysecure.keychain.ui.util.KeyFormattingUtils.State;
|
|
||||||
import org.sufficientlysecure.keychain.ui.util.SubtleAttentionSeeker;
|
|
||||||
import org.sufficientlysecure.keychain.util.FilterCursorWrapper;
|
|
||||||
import org.sufficientlysecure.keychain.util.Log;
|
|
||||||
|
|
||||||
public class LinkedIdsAdapter extends UserAttributesAdapter {
|
|
||||||
private final boolean mIsSecret;
|
|
||||||
protected LayoutInflater mInflater;
|
|
||||||
WeakHashMap<Integer,UriAttribute> mLinkedIdentityCache = new WeakHashMap<>();
|
|
||||||
|
|
||||||
public LinkedIdsAdapter(Context context, Cursor c, int flags, boolean isSecret) {
|
|
||||||
super(context, c, flags);
|
|
||||||
mInflater = LayoutInflater.from(context);
|
|
||||||
mIsSecret = isSecret;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Cursor swapCursor(Cursor cursor) {
|
|
||||||
if (cursor == null) {
|
|
||||||
return super.swapCursor(null);
|
|
||||||
}
|
|
||||||
FilterCursorWrapper filteredCursor = new FilterCursorWrapper(cursor) {
|
|
||||||
@Override
|
|
||||||
public boolean isVisible(Cursor cursor) {
|
|
||||||
UriAttribute id = getItemAtPosition(cursor);
|
|
||||||
return id instanceof LinkedAttribute;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
return super.swapCursor(filteredCursor);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void bindView(View view, Context context, Cursor cursor) {
|
|
||||||
|
|
||||||
ViewHolder holder = (ViewHolder) view.getTag();
|
|
||||||
|
|
||||||
if (!mIsSecret) {
|
|
||||||
int isVerified = cursor.getInt(INDEX_VERIFIED);
|
|
||||||
switch (isVerified) {
|
|
||||||
case Certs.VERIFIED_SECRET:
|
|
||||||
KeyFormattingUtils.setStatusImage(mContext, holder.vVerified,
|
|
||||||
null, State.VERIFIED, KeyFormattingUtils.DEFAULT_COLOR);
|
|
||||||
break;
|
|
||||||
case Certs.VERIFIED_SELF:
|
|
||||||
KeyFormattingUtils.setStatusImage(mContext, holder.vVerified,
|
|
||||||
null, State.UNVERIFIED, KeyFormattingUtils.DEFAULT_COLOR);
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
KeyFormattingUtils.setStatusImage(mContext, holder.vVerified,
|
|
||||||
null, State.INVALID, KeyFormattingUtils.DEFAULT_COLOR);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
UriAttribute id = getItemAtPosition(cursor);
|
|
||||||
holder.setData(mContext, id);
|
|
||||||
|
|
||||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
|
|
||||||
view.setTransitionName(id.mUri.toString());
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
public UriAttribute getItemAtPosition(Cursor cursor) {
|
|
||||||
int rank = cursor.getInt(INDEX_RANK);
|
|
||||||
Log.d(Constants.TAG, "requested rank: " + rank);
|
|
||||||
|
|
||||||
UriAttribute ret = mLinkedIdentityCache.get(rank);
|
|
||||||
if (ret != null) {
|
|
||||||
Log.d(Constants.TAG, "cached!");
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
Log.d(Constants.TAG, "not cached!");
|
|
||||||
|
|
||||||
try {
|
|
||||||
byte[] data = cursor.getBlob(INDEX_ATTRIBUTE_DATA);
|
|
||||||
ret = LinkedAttribute.fromAttributeData(data);
|
|
||||||
mLinkedIdentityCache.put(rank, ret);
|
|
||||||
return ret;
|
|
||||||
} catch (IOException e) {
|
|
||||||
Log.e(Constants.TAG, "could not read linked identity subpacket data", e);
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public UriAttribute getItem(int position) {
|
|
||||||
Cursor cursor = getCursor();
|
|
||||||
cursor.moveToPosition(position);
|
|
||||||
return getItemAtPosition(cursor);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public View newView(Context context, Cursor cursor, ViewGroup parent) {
|
|
||||||
View v = mInflater.inflate(R.layout.linked_id_item, null);
|
|
||||||
ViewHolder holder = new ViewHolder(v);
|
|
||||||
v.setTag(holder);
|
|
||||||
return v;
|
|
||||||
}
|
|
||||||
|
|
||||||
// don't show revoked user ids, irrelevant for average users
|
|
||||||
public static final String LINKED_IDS_WHERE = UserPackets.IS_REVOKED + " = 0";
|
|
||||||
|
|
||||||
public static CursorLoader createLoader(Context context, Uri dataUri) {
|
|
||||||
Uri baseUri = UserPackets.buildLinkedIdsUri(dataUri);
|
|
||||||
return new CursorLoader(context, baseUri,
|
|
||||||
UserIdsAdapter.USER_PACKETS_PROJECTION, LINKED_IDS_WHERE, null, null);
|
|
||||||
}
|
|
||||||
|
|
||||||
public LinkedIdViewFragment getLinkedIdFragment(int position, long masterKeyId) throws IOException {
|
|
||||||
Cursor c = getCursor();
|
|
||||||
c.moveToPosition(position);
|
|
||||||
int rank = c.getInt(UserIdsAdapter.INDEX_RANK);
|
|
||||||
|
|
||||||
Uri dataUri = UserPackets.buildLinkedIdsUri(KeyRings.buildGenericKeyRingUri(masterKeyId));
|
|
||||||
return LinkedIdViewFragment.newInstance(dataUri, rank, mIsSecret, masterKeyId);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static class ViewHolder {
|
|
||||||
final public ImageView vVerified;
|
|
||||||
final public ImageView vIcon;
|
|
||||||
final public TextView vTitle;
|
|
||||||
final public TextView vComment;
|
|
||||||
|
|
||||||
public ViewHolder(View view) {
|
|
||||||
vVerified = (ImageView) view.findViewById(R.id.linked_id_certified_icon);
|
|
||||||
vIcon = (ImageView) view.findViewById(R.id.linked_id_type_icon);
|
|
||||||
vTitle = (TextView) view.findViewById(R.id.linked_id_title);
|
|
||||||
vComment = (TextView) view.findViewById(R.id.linked_id_comment);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setData(Context context, UriAttribute id) {
|
|
||||||
|
|
||||||
vTitle.setText(id.getDisplayTitle(context));
|
|
||||||
|
|
||||||
String comment = id.getDisplayComment(context);
|
|
||||||
if (comment != null) {
|
|
||||||
vComment.setVisibility(View.VISIBLE);
|
|
||||||
vComment.setText(comment);
|
|
||||||
} else {
|
|
||||||
vComment.setVisibility(View.GONE);
|
|
||||||
}
|
|
||||||
|
|
||||||
vIcon.setImageResource(id.getDisplayIcon());
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
public void seekAttention() {
|
|
||||||
if (Build.VERSION.SDK_INT >= VERSION_CODES.LOLLIPOP) {
|
|
||||||
ObjectAnimator anim = SubtleAttentionSeeker.tintText(vComment, 1000);
|
|
||||||
anim.setStartDelay(200);
|
|
||||||
anim.start();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -17,6 +17,7 @@
|
|||||||
|
|
||||||
package org.sufficientlysecure.keychain.ui.keyview;
|
package org.sufficientlysecure.keychain.ui.keyview;
|
||||||
|
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
|
|
||||||
@@ -50,11 +51,11 @@ import android.widget.ViewAnimator;
|
|||||||
import org.sufficientlysecure.keychain.Constants;
|
import org.sufficientlysecure.keychain.Constants;
|
||||||
import org.sufficientlysecure.keychain.Constants.key;
|
import org.sufficientlysecure.keychain.Constants.key;
|
||||||
import org.sufficientlysecure.keychain.R;
|
import org.sufficientlysecure.keychain.R;
|
||||||
import org.sufficientlysecure.keychain.operations.results.LinkedVerifyResult;
|
|
||||||
import org.sufficientlysecure.keychain.linked.LinkedTokenResource;
|
|
||||||
import org.sufficientlysecure.keychain.linked.LinkedAttribute;
|
import org.sufficientlysecure.keychain.linked.LinkedAttribute;
|
||||||
import org.sufficientlysecure.keychain.linked.LinkedResource;
|
import org.sufficientlysecure.keychain.linked.LinkedResource;
|
||||||
|
import org.sufficientlysecure.keychain.linked.LinkedTokenResource;
|
||||||
import org.sufficientlysecure.keychain.linked.UriAttribute;
|
import org.sufficientlysecure.keychain.linked.UriAttribute;
|
||||||
|
import org.sufficientlysecure.keychain.operations.results.LinkedVerifyResult;
|
||||||
import org.sufficientlysecure.keychain.operations.results.OperationResult;
|
import org.sufficientlysecure.keychain.operations.results.OperationResult;
|
||||||
import org.sufficientlysecure.keychain.pgp.exception.PgpKeyNotFoundException;
|
import org.sufficientlysecure.keychain.pgp.exception.PgpKeyNotFoundException;
|
||||||
import org.sufficientlysecure.keychain.provider.KeyRepository;
|
import org.sufficientlysecure.keychain.provider.KeyRepository;
|
||||||
@@ -63,7 +64,7 @@ import org.sufficientlysecure.keychain.provider.KeychainContract.UserPackets;
|
|||||||
import org.sufficientlysecure.keychain.provider.KeychainDatabase.Tables;
|
import org.sufficientlysecure.keychain.provider.KeychainDatabase.Tables;
|
||||||
import org.sufficientlysecure.keychain.service.CertifyActionsParcel;
|
import org.sufficientlysecure.keychain.service.CertifyActionsParcel;
|
||||||
import org.sufficientlysecure.keychain.service.CertifyActionsParcel.CertifyAction;
|
import org.sufficientlysecure.keychain.service.CertifyActionsParcel.CertifyAction;
|
||||||
import org.sufficientlysecure.keychain.ui.adapter.LinkedIdsAdapter;
|
import org.sufficientlysecure.keychain.ui.adapter.IdentityAdapter;
|
||||||
import org.sufficientlysecure.keychain.ui.adapter.UserIdsAdapter;
|
import org.sufficientlysecure.keychain.ui.adapter.UserIdsAdapter;
|
||||||
import org.sufficientlysecure.keychain.ui.base.CryptoOperationFragment;
|
import org.sufficientlysecure.keychain.ui.base.CryptoOperationFragment;
|
||||||
import org.sufficientlysecure.keychain.ui.keyview.LinkedIdViewFragment.ViewHolder.VerifyState;
|
import org.sufficientlysecure.keychain.ui.keyview.LinkedIdViewFragment.ViewHolder.VerifyState;
|
||||||
@@ -217,7 +218,7 @@ public class LinkedIdViewFragment extends CryptoOperationFragment implements
|
|||||||
mViewHolder.mLinkedIdHolder.vVerified.setImageResource(R.drawable.octo_link_24dp);
|
mViewHolder.mLinkedIdHolder.vVerified.setImageResource(R.drawable.octo_link_24dp);
|
||||||
}
|
}
|
||||||
|
|
||||||
mViewHolder.mLinkedIdHolder.setData(mContext, mLinkedId);
|
mViewHolder.mLinkedIdHolder.bind(mContext, mLinkedId);
|
||||||
|
|
||||||
setShowVerifying(false);
|
setShowVerifying(false);
|
||||||
|
|
||||||
@@ -256,7 +257,7 @@ public class LinkedIdViewFragment extends CryptoOperationFragment implements
|
|||||||
private final ViewAnimator vVerifyingContainer;
|
private final ViewAnimator vVerifyingContainer;
|
||||||
private final ViewAnimator vItemCertified;
|
private final ViewAnimator vItemCertified;
|
||||||
private final View vKeySpinnerContainer;
|
private final View vKeySpinnerContainer;
|
||||||
LinkedIdsAdapter.ViewHolder mLinkedIdHolder;
|
IdentityAdapter.LinkedIdViewHolder mLinkedIdHolder;
|
||||||
|
|
||||||
private ViewAnimator vButtonSwitcher;
|
private ViewAnimator vButtonSwitcher;
|
||||||
private CertListWidget vLinkedCerts;
|
private CertListWidget vLinkedCerts;
|
||||||
@@ -274,7 +275,7 @@ public class LinkedIdViewFragment extends CryptoOperationFragment implements
|
|||||||
vKeySpinnerContainer = root.findViewById(R.id.cert_key_spincontainer);
|
vKeySpinnerContainer = root.findViewById(R.id.cert_key_spincontainer);
|
||||||
vButtonSwitcher = (ViewAnimator) root.findViewById(R.id.button_animator);
|
vButtonSwitcher = (ViewAnimator) root.findViewById(R.id.button_animator);
|
||||||
|
|
||||||
mLinkedIdHolder = new LinkedIdsAdapter.ViewHolder(root);
|
mLinkedIdHolder = new IdentityAdapter.LinkedIdViewHolder(root);
|
||||||
|
|
||||||
vButtonVerify = root.findViewById(R.id.button_verify);
|
vButtonVerify = root.findViewById(R.id.button_verify);
|
||||||
vButtonRetry = root.findViewById(R.id.button_retry);
|
vButtonRetry = root.findViewById(R.id.button_retry);
|
||||||
|
|||||||
@@ -35,30 +35,25 @@ import org.sufficientlysecure.keychain.operations.results.OperationResult;
|
|||||||
import org.sufficientlysecure.keychain.ui.base.LoaderFragment;
|
import org.sufficientlysecure.keychain.ui.base.LoaderFragment;
|
||||||
import org.sufficientlysecure.keychain.ui.keyview.presenter.IdentitiesPresenter;
|
import org.sufficientlysecure.keychain.ui.keyview.presenter.IdentitiesPresenter;
|
||||||
import org.sufficientlysecure.keychain.ui.keyview.presenter.KeyHealthPresenter;
|
import org.sufficientlysecure.keychain.ui.keyview.presenter.KeyHealthPresenter;
|
||||||
import org.sufficientlysecure.keychain.ui.keyview.presenter.LinkedIdentitiesPresenter;
|
|
||||||
import org.sufficientlysecure.keychain.ui.keyview.presenter.LinkedIdentitiesPresenter.LinkedIdsFragMvpView;
|
|
||||||
import org.sufficientlysecure.keychain.ui.keyview.presenter.SystemContactPresenter;
|
import org.sufficientlysecure.keychain.ui.keyview.presenter.SystemContactPresenter;
|
||||||
import org.sufficientlysecure.keychain.ui.keyview.presenter.ViewKeyMvpView;
|
import org.sufficientlysecure.keychain.ui.keyview.presenter.ViewKeyMvpView;
|
||||||
import org.sufficientlysecure.keychain.ui.keyview.view.IdentitiesCardView;
|
import org.sufficientlysecure.keychain.ui.keyview.view.IdentitiesCardView;
|
||||||
import org.sufficientlysecure.keychain.ui.keyview.view.KeyHealthView;
|
import org.sufficientlysecure.keychain.ui.keyview.view.KeyHealthView;
|
||||||
import org.sufficientlysecure.keychain.ui.keyview.view.SystemContactCardView;
|
import org.sufficientlysecure.keychain.ui.keyview.view.SystemContactCardView;
|
||||||
import org.sufficientlysecure.keychain.util.Preferences;
|
|
||||||
|
|
||||||
|
|
||||||
public class ViewKeyFragment extends LoaderFragment implements LinkedIdsFragMvpView, ViewKeyMvpView {
|
public class ViewKeyFragment extends LoaderFragment implements ViewKeyMvpView {
|
||||||
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";
|
||||||
|
|
||||||
boolean mIsSecret = false;
|
boolean mIsSecret = false;
|
||||||
|
|
||||||
private static final int LOADER_ID_USER_IDS = 1;
|
private static final int LOADER_IDENTITIES = 1;
|
||||||
private static final int LOADER_ID_LINKED_IDS = 2;
|
private static final int LOADER_ID_LINKED_CONTACT = 2;
|
||||||
private static final int LOADER_ID_LINKED_CONTACT = 3;
|
private static final int LOADER_ID_SUBKEY_STATUS = 3;
|
||||||
private static final int LOADER_ID_SUBKEY_STATUS = 4;
|
|
||||||
|
|
||||||
private IdentitiesCardView mIdentitiesCardView;
|
private IdentitiesCardView mIdentitiesCardView;
|
||||||
private IdentitiesPresenter mIdentitiesPresenter;
|
private IdentitiesPresenter mIdentitiesPresenter;
|
||||||
private LinkedIdentitiesPresenter mLinkedIdentitiesPresenter;
|
|
||||||
|
|
||||||
SystemContactCardView mSystemContactCard;
|
SystemContactCardView mSystemContactCard;
|
||||||
SystemContactPresenter mSystemContactPresenter;
|
SystemContactPresenter mSystemContactPresenter;
|
||||||
@@ -102,15 +97,9 @@ public class ViewKeyFragment extends LoaderFragment implements LinkedIdsFragMvpV
|
|||||||
mIsSecret = getArguments().getBoolean(ARG_IS_SECRET);
|
mIsSecret = getArguments().getBoolean(ARG_IS_SECRET);
|
||||||
|
|
||||||
mIdentitiesPresenter = new IdentitiesPresenter(
|
mIdentitiesPresenter = new IdentitiesPresenter(
|
||||||
getContext(), mIdentitiesCardView, this, LOADER_ID_USER_IDS, masterKeyId, mIsSecret);
|
getContext(), mIdentitiesCardView, this, LOADER_IDENTITIES, masterKeyId, mIsSecret);
|
||||||
mIdentitiesPresenter.startLoader(getLoaderManager());
|
mIdentitiesPresenter.startLoader(getLoaderManager());
|
||||||
|
|
||||||
if (Preferences.getPreferences(getActivity()).getExperimentalEnableLinkedIdentities()) {
|
|
||||||
mLinkedIdentitiesPresenter = new LinkedIdentitiesPresenter(
|
|
||||||
getContext(), mIdentitiesCardView, this, LOADER_ID_LINKED_IDS, masterKeyId, mIsSecret);
|
|
||||||
mLinkedIdentitiesPresenter.startLoader(getLoaderManager());
|
|
||||||
}
|
|
||||||
|
|
||||||
mSystemContactPresenter = new SystemContactPresenter(
|
mSystemContactPresenter = new SystemContactPresenter(
|
||||||
getContext(), mSystemContactCard, LOADER_ID_LINKED_CONTACT, masterKeyId, mIsSecret);
|
getContext(), mSystemContactCard, LOADER_ID_LINKED_CONTACT, masterKeyId, mIsSecret);
|
||||||
mSystemContactPresenter.startLoader(getLoaderManager());
|
mSystemContactPresenter.startLoader(getLoaderManager());
|
||||||
|
|||||||
@@ -18,6 +18,7 @@
|
|||||||
package org.sufficientlysecure.keychain.ui.keyview.loader;
|
package org.sufficientlysecure.keychain.ui.keyview.loader;
|
||||||
|
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
@@ -25,10 +26,14 @@ import java.util.List;
|
|||||||
import android.content.ContentResolver;
|
import android.content.ContentResolver;
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.database.Cursor;
|
import android.database.Cursor;
|
||||||
|
import android.support.annotation.Nullable;
|
||||||
import android.support.v4.content.AsyncTaskLoader;
|
import android.support.v4.content.AsyncTaskLoader;
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
|
|
||||||
|
import com.google.auto.value.AutoValue;
|
||||||
import org.sufficientlysecure.keychain.Constants;
|
import org.sufficientlysecure.keychain.Constants;
|
||||||
|
import org.sufficientlysecure.keychain.linked.LinkedAttribute;
|
||||||
|
import org.sufficientlysecure.keychain.linked.UriAttribute;
|
||||||
import org.sufficientlysecure.keychain.provider.KeychainContract.UserPackets;
|
import org.sufficientlysecure.keychain.provider.KeychainContract.UserPackets;
|
||||||
import org.sufficientlysecure.keychain.ui.keyview.loader.IdentityLoader.IdentityInfo;
|
import org.sufficientlysecure.keychain.ui.keyview.loader.IdentityLoader.IdentityInfo;
|
||||||
|
|
||||||
@@ -63,34 +68,84 @@ public class IdentityLoader extends AsyncTaskLoader<List<IdentityInfo>> {
|
|||||||
|
|
||||||
private final ContentResolver contentResolver;
|
private final ContentResolver contentResolver;
|
||||||
private final long masterKeyId;
|
private final long masterKeyId;
|
||||||
|
private final boolean showLinkedIds;
|
||||||
|
|
||||||
private List<IdentityInfo> cachedResult;
|
private List<IdentityInfo> cachedResult;
|
||||||
|
|
||||||
|
|
||||||
public IdentityLoader(Context context, ContentResolver contentResolver, long masterKeyId) {
|
public IdentityLoader(Context context, ContentResolver contentResolver, long masterKeyId, boolean showLinkedIds) {
|
||||||
super(context);
|
super(context);
|
||||||
|
|
||||||
this.contentResolver = contentResolver;
|
this.contentResolver = contentResolver;
|
||||||
this.masterKeyId = masterKeyId;
|
this.masterKeyId = masterKeyId;
|
||||||
|
this.showLinkedIds = showLinkedIds;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public List<IdentityInfo> loadInBackground() {
|
public List<IdentityInfo> loadInBackground() {
|
||||||
|
ArrayList<IdentityInfo> identities = new ArrayList<>();
|
||||||
|
|
||||||
|
if (showLinkedIds) {
|
||||||
|
loadLinkedIds(identities);
|
||||||
|
}
|
||||||
|
loadUserIds(identities);
|
||||||
|
|
||||||
|
return Collections.unmodifiableList(identities);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void loadLinkedIds(ArrayList<IdentityInfo> identities) {
|
||||||
|
Cursor cursor = contentResolver.query(UserPackets.buildLinkedIdsUri(masterKeyId),
|
||||||
|
USER_PACKETS_PROJECTION, USER_IDS_WHERE, null, null);
|
||||||
|
if (cursor == null) {
|
||||||
|
Log.e(Constants.TAG, "Error loading key items!");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
while (cursor.moveToNext()) {
|
||||||
|
int rank = cursor.getInt(INDEX_RANK);
|
||||||
|
int verified = cursor.getInt(INDEX_VERIFIED);
|
||||||
|
boolean isPrimary = cursor.getInt(INDEX_IS_PRIMARY) != 0;
|
||||||
|
|
||||||
|
byte[] data = cursor.getBlob(INDEX_ATTRIBUTE_DATA);
|
||||||
|
try {
|
||||||
|
UriAttribute uriAttribute = LinkedAttribute.fromAttributeData(data);
|
||||||
|
if (uriAttribute instanceof LinkedAttribute) {
|
||||||
|
LinkedIdInfo identityInfo = LinkedIdInfo.create(rank, verified, isPrimary, uriAttribute);
|
||||||
|
identities.add(identityInfo);
|
||||||
|
}
|
||||||
|
} catch (IOException e) {
|
||||||
|
Log.e(Constants.TAG, "Failed parsing uri attribute", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} finally {
|
||||||
|
cursor.close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void loadUserIds(ArrayList<IdentityInfo> identities) {
|
||||||
Cursor cursor = contentResolver.query(UserPackets.buildUserIdsUri(masterKeyId),
|
Cursor cursor = contentResolver.query(UserPackets.buildUserIdsUri(masterKeyId),
|
||||||
USER_PACKETS_PROJECTION, USER_IDS_WHERE, null, null);
|
USER_PACKETS_PROJECTION, USER_IDS_WHERE, null, null);
|
||||||
if (cursor == null) {
|
if (cursor == null) {
|
||||||
Log.e(Constants.TAG, "Error loading key items!");
|
Log.e(Constants.TAG, "Error loading key items!");
|
||||||
return null;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
ArrayList<IdentityInfo> identities = new ArrayList<>();
|
|
||||||
while (cursor.moveToNext()) {
|
while (cursor.moveToNext()) {
|
||||||
IdentityInfo identityInfo = new IdentityInfo(masterKeyId, cursor);
|
int rank = cursor.getInt(INDEX_RANK);
|
||||||
|
int verified = cursor.getInt(INDEX_VERIFIED);
|
||||||
|
boolean isPrimary = cursor.getInt(INDEX_IS_PRIMARY) != 0;
|
||||||
|
|
||||||
|
if (!cursor.isNull(INDEX_NAME) || !cursor.isNull(INDEX_EMAIL)) {
|
||||||
|
String name = cursor.getString(INDEX_NAME);
|
||||||
|
String email = cursor.getString(INDEX_EMAIL);
|
||||||
|
String comment = cursor.getString(INDEX_COMMENT);
|
||||||
|
|
||||||
|
IdentityInfo identityInfo = UserIdInfo.create(rank, verified, isPrimary, name, email, comment);
|
||||||
identities.add(identityInfo);
|
identities.add(identityInfo);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
return Collections.unmodifiableList(identities);
|
|
||||||
} finally {
|
} finally {
|
||||||
cursor.close();
|
cursor.close();
|
||||||
}
|
}
|
||||||
@@ -116,36 +171,41 @@ public class IdentityLoader extends AsyncTaskLoader<List<IdentityInfo>> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static class IdentityInfo {
|
public interface IdentityInfo {
|
||||||
final int position;
|
int getRank();
|
||||||
|
int getVerified();
|
||||||
public final int verified;
|
boolean isPrimary();
|
||||||
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;
|
@AutoValue
|
||||||
|
public abstract static class UserIdInfo implements IdentityInfo {
|
||||||
|
public abstract int getRank();
|
||||||
|
public abstract int getVerified();
|
||||||
|
public abstract boolean isPrimary();
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
public abstract String getName();
|
||||||
|
@Nullable
|
||||||
|
public abstract String getEmail();
|
||||||
|
@Nullable
|
||||||
|
public abstract String getComment();
|
||||||
|
|
||||||
|
static UserIdInfo create(int rank, int verified, boolean isPrimary, String name, String email,
|
||||||
|
String comment) {
|
||||||
|
return new AutoValue_IdentityLoader_UserIdInfo(rank, verified, isPrimary, name, email, comment);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@AutoValue
|
||||||
|
public abstract static class LinkedIdInfo implements IdentityInfo {
|
||||||
|
public abstract int getRank();
|
||||||
|
public abstract int getVerified();
|
||||||
|
public abstract boolean isPrimary();
|
||||||
|
|
||||||
|
public abstract UriAttribute getUriAttribute();
|
||||||
|
|
||||||
|
static LinkedIdInfo create(int rank, int verified, boolean isPrimary, UriAttribute uriAttribute) {
|
||||||
|
return new AutoValue_IdentityLoader_LinkedIdInfo(rank, verified, isPrimary, uriAttribute);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -18,20 +18,32 @@
|
|||||||
package org.sufficientlysecure.keychain.ui.keyview.presenter;
|
package org.sufficientlysecure.keychain.ui.keyview.presenter;
|
||||||
|
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.content.Intent;
|
import android.content.Intent;
|
||||||
|
import android.net.Uri;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
import android.support.v4.app.LoaderManager;
|
import android.support.v4.app.LoaderManager;
|
||||||
import android.support.v4.app.LoaderManager.LoaderCallbacks;
|
import android.support.v4.app.LoaderManager.LoaderCallbacks;
|
||||||
import android.support.v4.content.Loader;
|
import android.support.v4.content.Loader;
|
||||||
|
|
||||||
|
import org.sufficientlysecure.keychain.Constants;
|
||||||
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.UserPackets;
|
||||||
import org.sufficientlysecure.keychain.ui.EditIdentitiesActivity;
|
import org.sufficientlysecure.keychain.ui.EditIdentitiesActivity;
|
||||||
import org.sufficientlysecure.keychain.ui.adapter.IdentityAdapter;
|
import org.sufficientlysecure.keychain.ui.adapter.IdentityAdapter;
|
||||||
|
import org.sufficientlysecure.keychain.ui.dialog.UserIdInfoDialogFragment;
|
||||||
|
import org.sufficientlysecure.keychain.ui.keyview.LinkedIdViewFragment;
|
||||||
import org.sufficientlysecure.keychain.ui.keyview.loader.IdentityLoader;
|
import org.sufficientlysecure.keychain.ui.keyview.loader.IdentityLoader;
|
||||||
import org.sufficientlysecure.keychain.ui.keyview.loader.IdentityLoader.IdentityInfo;
|
import org.sufficientlysecure.keychain.ui.keyview.loader.IdentityLoader.IdentityInfo;
|
||||||
|
import org.sufficientlysecure.keychain.ui.keyview.loader.IdentityLoader.LinkedIdInfo;
|
||||||
|
import org.sufficientlysecure.keychain.ui.keyview.loader.IdentityLoader.UserIdInfo;
|
||||||
|
import org.sufficientlysecure.keychain.ui.linked.LinkedIdWizard;
|
||||||
|
import org.sufficientlysecure.keychain.util.Log;
|
||||||
|
import org.sufficientlysecure.keychain.util.Preferences;
|
||||||
|
|
||||||
|
|
||||||
public class IdentitiesPresenter implements LoaderCallbacks<List<IdentityInfo>> {
|
public class IdentitiesPresenter implements LoaderCallbacks<List<IdentityInfo>> {
|
||||||
@@ -55,7 +67,7 @@ public class IdentitiesPresenter implements LoaderCallbacks<List<IdentityInfo>>
|
|||||||
this.masterKeyId = masterKeyId;
|
this.masterKeyId = masterKeyId;
|
||||||
this.isSecret = isSecret;
|
this.isSecret = isSecret;
|
||||||
|
|
||||||
identitiesAdapter = new IdentityAdapter(context);
|
identitiesAdapter = new IdentityAdapter(context, isSecret);
|
||||||
view.setIdentitiesAdapter(identitiesAdapter);
|
view.setIdentitiesAdapter(identitiesAdapter);
|
||||||
|
|
||||||
view.setEditIdentitiesButtonVisible(isSecret);
|
view.setEditIdentitiesButtonVisible(isSecret);
|
||||||
@@ -63,13 +75,18 @@ public class IdentitiesPresenter implements LoaderCallbacks<List<IdentityInfo>>
|
|||||||
view.setIdentitiesCardListener(new IdentitiesCardListener() {
|
view.setIdentitiesCardListener(new IdentitiesCardListener() {
|
||||||
@Override
|
@Override
|
||||||
public void onIdentityItemClick(int position) {
|
public void onIdentityItemClick(int position) {
|
||||||
showUserIdInfo(position);
|
showIdentityInfo(position);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onClickEditIdentities() {
|
public void onClickEditIdentities() {
|
||||||
editIdentities();
|
editIdentities();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onClickAddIdentity() {
|
||||||
|
addLinkedIdentity();
|
||||||
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -79,7 +96,8 @@ public class IdentitiesPresenter implements LoaderCallbacks<List<IdentityInfo>>
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Loader<List<IdentityInfo>> onCreateLoader(int id, Bundle args) {
|
public Loader<List<IdentityInfo>> onCreateLoader(int id, Bundle args) {
|
||||||
return new IdentityLoader(context, context.getContentResolver(), masterKeyId);
|
boolean showLinkedIds = Preferences.getPreferences(context).getExperimentalEnableLinkedIdentities();
|
||||||
|
return new IdentityLoader(context, context.getContentResolver(), masterKeyId, showLinkedIds);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -93,14 +111,35 @@ public class IdentitiesPresenter implements LoaderCallbacks<List<IdentityInfo>>
|
|||||||
identitiesAdapter.setData(null);
|
identitiesAdapter.setData(null);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void showUserIdInfo(final int position) {
|
private void showIdentityInfo(final int position) {
|
||||||
// if (!isSecret) {
|
IdentityInfo info = identitiesAdapter.getInfo(position);
|
||||||
// final boolean isRevoked = identitiesAdapter.getIsRevoked(position);
|
if (info instanceof LinkedIdInfo) {
|
||||||
// final int isVerified = identitiesAdapter.getIsVerified(position);
|
showLinkedId((LinkedIdInfo) info);
|
||||||
//
|
} else if (info instanceof UserIdInfo) {
|
||||||
// UserIdInfoDialogFragment dialogFragment = UserIdInfoDialogFragment.newInstance(isRevoked, isVerified);
|
showUserIdInfo((UserIdInfo) info);
|
||||||
// viewKeyMvpView.showDialogFragment(dialogFragment, "userIdInfoDialog");
|
}
|
||||||
// }
|
}
|
||||||
|
|
||||||
|
private void showLinkedId(final LinkedIdInfo info) {
|
||||||
|
final LinkedIdViewFragment frag;
|
||||||
|
try {
|
||||||
|
Uri dataUri = UserPackets.buildLinkedIdsUri(KeyRings.buildGenericKeyRingUri(masterKeyId));
|
||||||
|
frag = LinkedIdViewFragment.newInstance(dataUri, info.getRank(), isSecret, masterKeyId);
|
||||||
|
} catch (IOException e) {
|
||||||
|
Log.e(Constants.TAG, "IOException", e);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
viewKeyMvpView.switchToFragment(frag, "linked_id");
|
||||||
|
}
|
||||||
|
|
||||||
|
private void showUserIdInfo(UserIdInfo info) {
|
||||||
|
if (!isSecret) {
|
||||||
|
final int isVerified = info.getVerified();
|
||||||
|
|
||||||
|
UserIdInfoDialogFragment dialogFragment = UserIdInfoDialogFragment.newInstance(false, isVerified);
|
||||||
|
viewKeyMvpView.showDialogFragment(dialogFragment, "userIdInfoDialog");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void editIdentities() {
|
private void editIdentities() {
|
||||||
@@ -109,6 +148,12 @@ public class IdentitiesPresenter implements LoaderCallbacks<List<IdentityInfo>>
|
|||||||
viewKeyMvpView.startActivityAndShowResultSnackbar(editIntent);
|
viewKeyMvpView.startActivityAndShowResultSnackbar(editIntent);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void addLinkedIdentity() {
|
||||||
|
Intent intent = new Intent(context, LinkedIdWizard.class);
|
||||||
|
intent.setData(KeyRings.buildUnifiedKeyRingUri(masterKeyId));
|
||||||
|
context.startActivity(intent);
|
||||||
|
}
|
||||||
|
|
||||||
public interface IdentitiesMvpView {
|
public interface IdentitiesMvpView {
|
||||||
void setIdentitiesAdapter(IdentityAdapter userIdsAdapter);
|
void setIdentitiesAdapter(IdentityAdapter userIdsAdapter);
|
||||||
void setIdentitiesCardListener(IdentitiesCardListener identitiesCardListener);
|
void setIdentitiesCardListener(IdentitiesCardListener identitiesCardListener);
|
||||||
@@ -117,6 +162,8 @@ public class IdentitiesPresenter implements LoaderCallbacks<List<IdentityInfo>>
|
|||||||
|
|
||||||
public interface IdentitiesCardListener {
|
public interface IdentitiesCardListener {
|
||||||
void onIdentityItemClick(int position);
|
void onIdentityItemClick(int position);
|
||||||
|
|
||||||
void onClickEditIdentities();
|
void onClickEditIdentities();
|
||||||
|
void onClickAddIdentity();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1,133 +0,0 @@
|
|||||||
/*
|
|
||||||
* 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.keyview.presenter;
|
|
||||||
|
|
||||||
|
|
||||||
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.keyview.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 anyDataShown = data.getCount() > 0;
|
|
||||||
view.setShowLinkedIdDivider(anyDataShown);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onLoaderReset(Loader loader) {
|
|
||||||
linkedIdsAdapter.swapCursor(null);
|
|
||||||
view.setShowLinkedIdDivider(false);
|
|
||||||
}
|
|
||||||
|
|
||||||
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");
|
|
||||||
}
|
|
||||||
|
|
||||||
public interface LinkedIdsMvpView {
|
|
||||||
void setSystemContactClickListener(LinkedIdsClickListener linkedIdsClickListener);
|
|
||||||
void setLinkedIdsAdapter(LinkedIdsAdapter linkedIdsAdapter);
|
|
||||||
|
|
||||||
void setShowLinkedIdDivider(boolean show);
|
|
||||||
}
|
|
||||||
|
|
||||||
public interface LinkedIdsFragMvpView {
|
|
||||||
void switchToFragment(Fragment frag, String backStackName);
|
|
||||||
}
|
|
||||||
|
|
||||||
public 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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -3,9 +3,12 @@ package org.sufficientlysecure.keychain.ui.keyview.presenter;
|
|||||||
|
|
||||||
import android.content.Intent;
|
import android.content.Intent;
|
||||||
import android.support.v4.app.DialogFragment;
|
import android.support.v4.app.DialogFragment;
|
||||||
|
import android.support.v4.app.Fragment;
|
||||||
|
|
||||||
|
|
||||||
public interface ViewKeyMvpView {
|
public interface ViewKeyMvpView {
|
||||||
|
void switchToFragment(Fragment frag, String backStackName);
|
||||||
|
|
||||||
void startActivityAndShowResultSnackbar(Intent intent);
|
void startActivityAndShowResultSnackbar(Intent intent);
|
||||||
void showDialogFragment(DialogFragment dialogFragment, final String tag);
|
void showDialogFragment(DialogFragment dialogFragment, final String tag);
|
||||||
void setContentShown(boolean show, boolean animate);
|
void setContentShown(boolean show, boolean animate);
|
||||||
|
|||||||
@@ -25,27 +25,19 @@ import android.support.v7.widget.RecyclerView;
|
|||||||
import android.util.AttributeSet;
|
import android.util.AttributeSet;
|
||||||
import android.view.LayoutInflater;
|
import android.view.LayoutInflater;
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
import android.widget.AdapterView;
|
|
||||||
import android.widget.AdapterView.OnItemClickListener;
|
|
||||||
import android.widget.Button;
|
import android.widget.Button;
|
||||||
import android.widget.ListView;
|
|
||||||
|
|
||||||
import org.sufficientlysecure.keychain.R;
|
import org.sufficientlysecure.keychain.R;
|
||||||
import org.sufficientlysecure.keychain.ui.adapter.IdentityAdapter;
|
import org.sufficientlysecure.keychain.ui.adapter.IdentityAdapter;
|
||||||
import org.sufficientlysecure.keychain.ui.adapter.LinkedIdsAdapter;
|
|
||||||
import org.sufficientlysecure.keychain.ui.keyview.presenter.IdentitiesPresenter.IdentitiesCardListener;
|
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.IdentitiesPresenter.IdentitiesMvpView;
|
||||||
import org.sufficientlysecure.keychain.ui.keyview.presenter.LinkedIdentitiesPresenter.LinkedIdsClickListener;
|
import org.sufficientlysecure.keychain.ui.util.recyclerview.DividerItemDecoration;
|
||||||
import org.sufficientlysecure.keychain.ui.keyview.presenter.LinkedIdentitiesPresenter.LinkedIdsMvpView;
|
|
||||||
import org.sufficientlysecure.keychain.ui.util.recyclerview.RecyclerItemClickListener;
|
import org.sufficientlysecure.keychain.ui.util.recyclerview.RecyclerItemClickListener;
|
||||||
|
|
||||||
|
|
||||||
public class IdentitiesCardView extends CardView implements IdentitiesMvpView, LinkedIdsMvpView {
|
public class IdentitiesCardView extends CardView implements IdentitiesMvpView {
|
||||||
private final ListView vLinkedIds;
|
|
||||||
private final RecyclerView vIdentities;
|
private final RecyclerView vIdentities;
|
||||||
private final View vLinkedIdsDivider;
|
|
||||||
|
|
||||||
private LinkedIdsClickListener linkedIdsClickListener;
|
|
||||||
private IdentitiesCardListener identitiesCardListener;
|
private IdentitiesCardListener identitiesCardListener;
|
||||||
|
|
||||||
public IdentitiesCardView(Context context, AttributeSet attrs) {
|
public IdentitiesCardView(Context context, AttributeSet attrs) {
|
||||||
@@ -55,6 +47,7 @@ public class IdentitiesCardView extends CardView implements IdentitiesMvpView, L
|
|||||||
|
|
||||||
vIdentities = (RecyclerView) view.findViewById(R.id.view_key_user_ids);
|
vIdentities = (RecyclerView) view.findViewById(R.id.view_key_user_ids);
|
||||||
vIdentities.setLayoutManager(new LinearLayoutManager(context));
|
vIdentities.setLayoutManager(new LinearLayoutManager(context));
|
||||||
|
vIdentities.addItemDecoration(new DividerItemDecoration(context, DividerItemDecoration.VERTICAL_LIST));
|
||||||
|
|
||||||
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);
|
||||||
userIdsEditButton.setOnClickListener(new OnClickListener() {
|
userIdsEditButton.setOnClickListener(new OnClickListener() {
|
||||||
@@ -76,28 +69,16 @@ public class IdentitiesCardView extends CardView implements IdentitiesMvpView, L
|
|||||||
}
|
}
|
||||||
}));
|
}));
|
||||||
|
|
||||||
vLinkedIds = (ListView) view.findViewById(R.id.view_key_linked_ids);
|
|
||||||
Button linkedIdsAddButton = (Button) view.findViewById(R.id.view_key_card_linked_ids_add);
|
Button linkedIdsAddButton = (Button) view.findViewById(R.id.view_key_card_linked_ids_add);
|
||||||
|
|
||||||
linkedIdsAddButton.setOnClickListener(new View.OnClickListener() {
|
linkedIdsAddButton.setOnClickListener(new View.OnClickListener() {
|
||||||
@Override
|
@Override
|
||||||
public void onClick(View v) {
|
public void onClick(View v) {
|
||||||
if (linkedIdsClickListener != null) {
|
if (identitiesCardListener != null) {
|
||||||
linkedIdsClickListener.onClickAddIdentity();
|
identitiesCardListener.onClickAddIdentity();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
vLinkedIds.setOnItemClickListener(new OnItemClickListener() {
|
|
||||||
@Override
|
|
||||||
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
|
|
||||||
if (linkedIdsClickListener != null) {
|
|
||||||
linkedIdsClickListener.onLinkedIdItemClick(position);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
vLinkedIdsDivider = view.findViewById(R.id.view_key_lid_divider);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -114,19 +95,4 @@ public class IdentitiesCardView extends CardView implements IdentitiesMvpView, L
|
|||||||
public void setEditIdentitiesButtonVisible(boolean show) {
|
public void setEditIdentitiesButtonVisible(boolean show) {
|
||||||
findViewById(R.id.view_key_card_user_ids_buttons).setVisibility(show ? View.VISIBLE : View.GONE);
|
findViewById(R.id.view_key_card_user_ids_buttons).setVisibility(show ? View.VISIBLE : View.GONE);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public void setSystemContactClickListener(LinkedIdsClickListener linkedIdsClickListener) {
|
|
||||||
this.linkedIdsClickListener = linkedIdsClickListener;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void setLinkedIdsAdapter(LinkedIdsAdapter linkedIdsAdapter) {
|
|
||||||
vLinkedIds.setAdapter(linkedIdsAdapter);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void setShowLinkedIdDivider(boolean show) {
|
|
||||||
vLinkedIdsDivider.setVisibility(show ? View.VISIBLE : View.GONE);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -67,7 +67,7 @@ public class DividerItemDecoration extends RecyclerView.ItemDecoration {
|
|||||||
final int right = parent.getWidth() - parent.getPaddingRight();
|
final int right = parent.getWidth() - parent.getPaddingRight();
|
||||||
|
|
||||||
final int childCount = parent.getChildCount();
|
final int childCount = parent.getChildCount();
|
||||||
for (int i = 0; i < childCount; i++) {
|
for (int i = 0; i < childCount -1; i++) {
|
||||||
final View child = parent.getChildAt(i);
|
final View child = parent.getChildAt(i);
|
||||||
final RecyclerView.LayoutParams params = (RecyclerView.LayoutParams) child
|
final RecyclerView.LayoutParams params = (RecyclerView.LayoutParams) child
|
||||||
.getLayoutParams();
|
.getLayoutParams();
|
||||||
@@ -83,7 +83,7 @@ public class DividerItemDecoration extends RecyclerView.ItemDecoration {
|
|||||||
final int bottom = parent.getHeight() - parent.getPaddingBottom();
|
final int bottom = parent.getHeight() - parent.getPaddingBottom();
|
||||||
|
|
||||||
final int childCount = parent.getChildCount();
|
final int childCount = parent.getChildCount();
|
||||||
for (int i = 0; i < childCount; i++) {
|
for (int i = 0; i < childCount -1; i++) {
|
||||||
final View child = parent.getChildAt(i);
|
final View child = parent.getChildAt(i);
|
||||||
final RecyclerView.LayoutParams params = (RecyclerView.LayoutParams) child
|
final RecyclerView.LayoutParams params = (RecyclerView.LayoutParams) child
|
||||||
.getLayoutParams();
|
.getLayoutParams();
|
||||||
|
|||||||
@@ -12,21 +12,6 @@
|
|||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:text="@string/section_user_ids" />
|
android:text="@string/section_user_ids" />
|
||||||
|
|
||||||
<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" />
|
|
||||||
|
|
||||||
<View
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="1dip"
|
|
||||||
android:id="@+id/view_key_lid_divider"
|
|
||||||
android:background="?android:attr/listDivider"
|
|
||||||
android:visibility="gone"
|
|
||||||
tools:visibility="visible"
|
|
||||||
/>
|
|
||||||
|
|
||||||
<android.support.v7.widget.RecyclerView
|
<android.support.v7.widget.RecyclerView
|
||||||
android:id="@+id/view_key_user_ids"
|
android:id="@+id/view_key_user_ids"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
|
|||||||
@@ -1,31 +1,33 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
xmlns:tools="http://schemas.android.com/tools"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:orientation="vertical"
|
android:orientation="vertical"
|
||||||
android:layout_marginLeft="8dp"
|
android:gravity="center_vertical"
|
||||||
android:layout_marginTop="4dp"
|
android:minHeight="?android:attr/listPreferredItemHeight"
|
||||||
android:layout_marginBottom="4dp">
|
android:paddingLeft="8dp"
|
||||||
|
android:paddingTop="4dp"
|
||||||
|
android:paddingBottom="4dp">
|
||||||
|
|
||||||
<TextView
|
<TextView
|
||||||
android:id="@+id/user_id_item_address"
|
android:id="@+id/user_id_item_address"
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:text="alice@example.com"
|
tools:text="alice@example.com"
|
||||||
android:textAppearance="?android:attr/textAppearanceMedium" />
|
android:textAppearance="?android:attr/textAppearanceMedium" />
|
||||||
|
|
||||||
<TextView
|
<TextView
|
||||||
android:id="@+id/user_id_item_name"
|
android:id="@+id/user_id_item_name"
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:text="Alice"
|
tools:text="Alice"
|
||||||
android:textAppearance="?android:attr/textAppearanceSmall" />
|
android:textAppearance="?android:attr/textAppearanceSmall" />
|
||||||
|
|
||||||
<TextView
|
<TextView
|
||||||
android:id="@+id/user_id_item_comment"
|
android:id="@+id/user_id_item_comment"
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:text="comment"
|
tools:text="comment"
|
||||||
android:textAppearance="?android:attr/textAppearanceSmall" />
|
android:textAppearance="?android:attr/textAppearanceSmall" />
|
||||||
|
|
||||||
</LinearLayout>
|
</LinearLayout>
|
||||||
|
|||||||
Reference in New Issue
Block a user