Merge user ids in import list for better display

This commit is contained in:
Dominik Schürmann 2014-09-21 17:58:26 +02:00
parent 1d38365a61
commit 9bd3383b49
5 changed files with 98 additions and 61 deletions

View File

@ -78,6 +78,7 @@ public class ImportKeysList extends ArrayList<ImportKeysListEntry> {
modified = true; modified = true;
} }
} }
existing.updateMergedUserIds();
return modified; return modified;
} }

View File

@ -21,6 +21,7 @@ import android.content.Context;
import android.os.Parcel; import android.os.Parcel;
import android.os.Parcelable; import android.os.Parcelable;
import org.sufficientlysecure.keychain.pgp.KeyRing;
import org.sufficientlysecure.keychain.ui.util.KeyFormattingUtils; import org.sufficientlysecure.keychain.ui.util.KeyFormattingUtils;
import org.sufficientlysecure.keychain.pgp.UncachedKeyRing; import org.sufficientlysecure.keychain.pgp.UncachedKeyRing;
import org.sufficientlysecure.keychain.pgp.UncachedPublicKey; import org.sufficientlysecure.keychain.pgp.UncachedPublicKey;
@ -28,11 +29,14 @@ import org.sufficientlysecure.keychain.pgp.UncachedPublicKey;
import java.io.Serializable; import java.io.Serializable;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Date; import java.util.Date;
import java.util.HashMap;
import java.util.HashSet;
public class ImportKeysListEntry implements Serializable, Parcelable { public class ImportKeysListEntry implements Serializable, Parcelable {
private static final long serialVersionUID = -7797972103284992662L; private static final long serialVersionUID = -7797972103284992662L;
private ArrayList<String> mUserIds; private ArrayList<String> mUserIds;
private HashMap<String, HashSet<String>> mMergedUserIds;
private long mKeyId; private long mKeyId;
private String mKeyIdHex; private String mKeyIdHex;
private boolean mRevoked; private boolean mRevoked;
@ -59,10 +63,11 @@ public class ImportKeysListEntry implements Serializable, Parcelable {
public void writeToParcel(Parcel dest, int flags) { public void writeToParcel(Parcel dest, int flags) {
dest.writeString(mPrimaryUserId); dest.writeString(mPrimaryUserId);
dest.writeStringList(mUserIds); dest.writeStringList(mUserIds);
dest.writeSerializable(mMergedUserIds);
dest.writeLong(mKeyId); dest.writeLong(mKeyId);
dest.writeByte((byte) (mRevoked ? 1 : 0)); dest.writeByte((byte) (mRevoked ? 1 : 0));
dest.writeByte((byte) (mExpired ? 1 : 0)); dest.writeByte((byte) (mExpired ? 1 : 0));
dest.writeSerializable(mDate); dest.writeLong(mDate.getTime());
dest.writeString(mFingerprintHex); dest.writeString(mFingerprintHex);
dest.writeString(mKeyIdHex); dest.writeString(mKeyIdHex);
dest.writeInt(mBitStrength); dest.writeInt(mBitStrength);
@ -79,10 +84,11 @@ public class ImportKeysListEntry implements Serializable, Parcelable {
vr.mPrimaryUserId = source.readString(); vr.mPrimaryUserId = source.readString();
vr.mUserIds = new ArrayList<String>(); vr.mUserIds = new ArrayList<String>();
source.readStringList(vr.mUserIds); source.readStringList(vr.mUserIds);
vr.mMergedUserIds = (HashMap<String, HashSet<String>>) source.readSerializable();
vr.mKeyId = source.readLong(); vr.mKeyId = source.readLong();
vr.mRevoked = source.readByte() == 1; vr.mRevoked = source.readByte() == 1;
vr.mExpired = source.readByte() == 1; vr.mExpired = source.readByte() == 1;
vr.mDate = (Date) source.readSerializable(); vr.mDate = new Date(source.readLong());
vr.mFingerprintHex = source.readString(); vr.mFingerprintHex = source.readString();
vr.mKeyIdHex = source.readString(); vr.mKeyIdHex = source.readString();
vr.mBitStrength = source.readInt(); vr.mBitStrength = source.readInt();
@ -124,7 +130,7 @@ public class ImportKeysListEntry implements Serializable, Parcelable {
} }
public void setSelected(boolean selected) { public void setSelected(boolean selected) {
this.mSelected = selected; mSelected = selected;
} }
public boolean isExpired() { public boolean isExpired() {
@ -132,7 +138,7 @@ public class ImportKeysListEntry implements Serializable, Parcelable {
} }
public void setExpired(boolean expired) { public void setExpired(boolean expired) {
this.mExpired = expired; mExpired = expired;
} }
public long getKeyId() { public long getKeyId() {
@ -140,11 +146,11 @@ public class ImportKeysListEntry implements Serializable, Parcelable {
} }
public void setKeyId(long keyId) { public void setKeyId(long keyId) {
this.mKeyId = keyId; mKeyId = keyId;
} }
public void setKeyIdHex(String keyIdHex) { public void setKeyIdHex(String keyIdHex) {
this.mKeyIdHex = keyIdHex; mKeyIdHex = keyIdHex;
} }
public boolean isRevoked() { public boolean isRevoked() {
@ -152,7 +158,7 @@ public class ImportKeysListEntry implements Serializable, Parcelable {
} }
public void setRevoked(boolean revoked) { public void setRevoked(boolean revoked) {
this.mRevoked = revoked; mRevoked = revoked;
} }
public Date getDate() { public Date getDate() {
@ -160,7 +166,7 @@ public class ImportKeysListEntry implements Serializable, Parcelable {
} }
public void setDate(Date date) { public void setDate(Date date) {
this.mDate = date; mDate = date;
} }
public String getFingerprintHex() { public String getFingerprintHex() {
@ -168,7 +174,7 @@ public class ImportKeysListEntry implements Serializable, Parcelable {
} }
public void setFingerprintHex(String fingerprintHex) { public void setFingerprintHex(String fingerprintHex) {
this.mFingerprintHex = fingerprintHex; mFingerprintHex = fingerprintHex;
} }
public Integer getBitStrength() { public Integer getBitStrength() {
@ -180,7 +186,7 @@ public class ImportKeysListEntry implements Serializable, Parcelable {
} }
public void setBitStrength(int bitStrength) { public void setBitStrength(int bitStrength) {
this.mBitStrength = bitStrength; mBitStrength = bitStrength;
} }
public String getAlgorithm() { public String getAlgorithm() {
@ -188,7 +194,7 @@ public class ImportKeysListEntry implements Serializable, Parcelable {
} }
public void setAlgorithm(String algorithm) { public void setAlgorithm(String algorithm) {
this.mAlgorithm = algorithm; mAlgorithm = algorithm;
} }
public boolean isSecretKey() { public boolean isSecretKey() {
@ -196,7 +202,7 @@ public class ImportKeysListEntry implements Serializable, Parcelable {
} }
public void setSecretKey(boolean secretKey) { public void setSecretKey(boolean secretKey) {
this.mSecretKey = secretKey; mSecretKey = secretKey;
} }
public ArrayList<String> getUserIds() { public ArrayList<String> getUserIds() {
@ -204,7 +210,8 @@ public class ImportKeysListEntry implements Serializable, Parcelable {
} }
public void setUserIds(ArrayList<String> userIds) { public void setUserIds(ArrayList<String> userIds) {
this.mUserIds = userIds; mUserIds = userIds;
updateMergedUserIds();
} }
public String getPrimaryUserId() { public String getPrimaryUserId() {
@ -239,6 +246,10 @@ public class ImportKeysListEntry implements Serializable, Parcelable {
mOrigins.add(origin); mOrigins.add(origin);
} }
public HashMap<String, HashSet<String>> getMergedUserIds() {
return mMergedUserIds;
}
/** /**
* Constructor for later querying from keyserver * Constructor for later querying from keyserver
*/ */
@ -266,6 +277,7 @@ public class ImportKeysListEntry implements Serializable, Parcelable {
mPrimaryUserId = key.getPrimaryUserIdWithFallback(); mPrimaryUserId = key.getPrimaryUserIdWithFallback();
mUserIds = key.getUnorderedUserIds(); mUserIds = key.getUnorderedUserIds();
updateMergedUserIds();
// if there was no user id flagged as primary, use the first one // if there was no user id flagged as primary, use the first one
if (mPrimaryUserId == null) { if (mPrimaryUserId == null) {
@ -284,4 +296,33 @@ public class ImportKeysListEntry implements Serializable, Parcelable {
mAlgorithm = KeyFormattingUtils.getAlgorithmInfo(context, algorithm, mBitStrength, mCurveOid); mAlgorithm = KeyFormattingUtils.getAlgorithmInfo(context, algorithm, mBitStrength, mCurveOid);
} }
public void updateMergedUserIds() {
mMergedUserIds = new HashMap<String, HashSet<String>>();
for (String userId : mUserIds) {
String[] userIdSplit = KeyRing.splitUserId(userId);
// TODO: comment field?
// name
if (userIdSplit[0] != null) {
// email
if (userIdSplit[1] != null) {
if (!mMergedUserIds.containsKey(userIdSplit[0])) {
HashSet<String> emails = new HashSet<String>();
emails.add(userIdSplit[1]);
mMergedUserIds.put(userIdSplit[0], emails);
} else {
mMergedUserIds.get(userIdSplit[0]).add(userIdSplit[1]);
}
} else {
// name only
mMergedUserIds.put(userIdSplit[0], new HashSet<String>());
}
} else {
// fallback
mMergedUserIds.put(userId, new HashSet<String>());
}
}
}
} }

View File

@ -21,7 +21,6 @@ import android.annotation.TargetApi;
import android.app.Activity; import android.app.Activity;
import android.content.Context; import android.content.Context;
import android.graphics.Color; import android.graphics.Color;
import android.media.Image;
import android.os.Build; import android.os.Build;
import android.view.LayoutInflater; import android.view.LayoutInflater;
import android.view.View; import android.view.View;
@ -35,12 +34,16 @@ import android.widget.TextView;
import org.sufficientlysecure.keychain.R; import org.sufficientlysecure.keychain.R;
import org.sufficientlysecure.keychain.keyimport.ImportKeysListEntry; import org.sufficientlysecure.keychain.keyimport.ImportKeysListEntry;
import org.sufficientlysecure.keychain.pgp.KeyRing; import org.sufficientlysecure.keychain.pgp.KeyRing;
import org.sufficientlysecure.keychain.ui.util.FormattingUtils;
import org.sufficientlysecure.keychain.ui.util.Highlighter; import org.sufficientlysecure.keychain.ui.util.Highlighter;
import org.sufficientlysecure.keychain.ui.util.KeyFormattingUtils; import org.sufficientlysecure.keychain.ui.util.KeyFormattingUtils;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator; import java.util.Iterator;
import java.util.List; import java.util.List;
import java.util.Map;
public class ImportKeysAdapter extends ArrayAdapter<ImportKeysListEntry> { public class ImportKeysAdapter extends ArrayAdapter<ImportKeysListEntry> {
protected LayoutInflater mInflater; protected LayoutInflater mInflater;
@ -112,16 +115,16 @@ public class ImportKeysAdapter extends ArrayAdapter<ImportKeysListEntry> {
ViewHolder holder; ViewHolder holder;
if (convertView == null) { if (convertView == null) {
holder = new ViewHolder(); holder = new ViewHolder();
convertView = mInflater.inflate(R.layout.import_keys_list_entry, null); convertView = mInflater.inflate(R.layout.import_keys_list_item, null);
holder.mainUserId = (TextView) convertView.findViewById(R.id.mainUserId); holder.mainUserId = (TextView) convertView.findViewById(R.id.import_item_user_id);
holder.mainUserIdRest = (TextView) convertView.findViewById(R.id.mainUserIdRest); holder.mainUserIdRest = (TextView) convertView.findViewById(R.id.import_item_user_id_email);
holder.keyId = (TextView) convertView.findViewById(R.id.subkey_item_key_id); holder.keyId = (TextView) convertView.findViewById(R.id.import_item_key_id);
holder.fingerprint = (TextView) convertView.findViewById(R.id.view_key_fingerprint); holder.fingerprint = (TextView) convertView.findViewById(R.id.import_item_fingerprint);
holder.algorithm = (TextView) convertView.findViewById(R.id.algorithm); holder.algorithm = (TextView) convertView.findViewById(R.id.import_item_algorithm);
holder.status = (ImageView) convertView.findViewById(R.id.status); holder.status = (ImageView) convertView.findViewById(R.id.import_item_status);
holder.userIdsDivider = convertView.findViewById(R.id.user_ids_divider); holder.userIdsDivider = convertView.findViewById(R.id.import_item_status_divider);
holder.userIdsList = (LinearLayout) convertView.findViewById(R.id.user_ids_list); holder.userIdsList = (LinearLayout) convertView.findViewById(R.id.import_item_user_ids_list);
holder.checkBox = (CheckBox) convertView.findViewById(R.id.selected); holder.checkBox = (CheckBox) convertView.findViewById(R.id.import_item_selected);
convertView.setTag(holder); convertView.setTag(holder);
} else { } else {
holder = (ViewHolder) convertView.getTag(); holder = (ViewHolder) convertView.getTag();
@ -192,15 +195,27 @@ public class ImportKeysAdapter extends ArrayAdapter<ImportKeysListEntry> {
// destroyLoader view from holder // destroyLoader view from holder
holder.userIdsList.removeAllViews(); holder.userIdsList.removeAllViews();
Iterator<String> it = entry.getUserIds().iterator(); HashMap<String, HashSet<String>> mergedUserIds = entry.getMergedUserIds();
// skip primary user id for (Map.Entry<String, HashSet<String>> pair : mergedUserIds.entrySet()) {
it.next(); String cUserId = pair.getKey();
while (it.hasNext()) { HashSet<String> cEmails = pair.getValue();
String uid = it.next();
TextView uidView = (TextView) mInflater.inflate( TextView uidView = (TextView) mInflater.inflate(
R.layout.import_keys_list_entry_user_id, null); R.layout.import_keys_list_entry_user_id, null);
uidView.setText(highlighter.highlight(uid)); uidView.setText(highlighter.highlight(cUserId));
uidView.setPadding(0, 0, FormattingUtils.dpToPx(getContext(), 8), 0);
holder.userIdsList.addView(uidView); holder.userIdsList.addView(uidView);
for (String email : cEmails) {
TextView emailView = (TextView) mInflater.inflate(
R.layout.import_keys_list_entry_user_id, null);
emailView.setPadding(
FormattingUtils.dpToPx(getContext(), 16), 0,
FormattingUtils.dpToPx(getContext(), 8), 0);
emailView.setText(highlighter.highlight(email));
holder.userIdsList.addView(emailView);
}
} }
} }

View File

@ -1,27 +1,7 @@
<!-- <TextView xmlns:android="http://schemas.android.com/apk/res/android"
Copyright (C) 2010-2014 Thialfihar <thi@thialfihar.org>
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/>.
-->
<TextView
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_marginRight="?android:attr/scrollbarSize" android:layout_marginRight="?android:attr/scrollbarSize"
android:singleLine="true" android:singleLine="true"
android:layout_width="fill_parent" android:layout_width="fill_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:textAppearance="?android:attr/textAppearanceSmall" android:textAppearance="?android:attr/textAppearanceSmall"
android:paddingRight="3dip"> android:paddingRight="8dp" />
</TextView>

View File

@ -11,7 +11,7 @@
android:paddingBottom="4dp"> android:paddingBottom="4dp">
<CheckBox <CheckBox
android:id="@+id/selected" android:id="@+id/import_item_selected"
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="match_parent" android:layout_height="match_parent"
android:paddingRight="8dp" android:paddingRight="8dp"
@ -39,21 +39,21 @@
android:orientation="vertical"> android:orientation="vertical">
<TextView <TextView
android:id="@+id/mainUserId" android:id="@+id/import_item_user_id"
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:text="Alice" android:text="Alice"
android:textAppearance="?android:attr/textAppearanceMedium" /> android:textAppearance="?android:attr/textAppearanceMedium" />
<TextView <TextView
android:id="@+id/mainUserIdRest" android:id="@+id/import_item_user_id_email"
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" android:text="alice@example.com"
android:textAppearance="?android:attr/textAppearanceSmall" /> android:textAppearance="?android:attr/textAppearanceSmall" />
<TextView <TextView
android:id="@+id/subkey_item_key_id" android:id="@+id/import_item_key_id"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:text="Key ID: abcd abcd abcd abcd" android:text="Key ID: abcd abcd abcd abcd"
@ -69,7 +69,7 @@
android:paddingLeft="4dp"> android:paddingLeft="4dp">
<ImageView <ImageView
android:id="@+id/status" android:id="@+id/import_item_status"
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_gravity="center" android:layout_gravity="center"
@ -77,7 +77,7 @@
android:padding="16dp" /> android:padding="16dp" />
<TextView <TextView
android:id="@+id/algorithm" android:id="@+id/import_item_algorithm"
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:text="RSA" android:text="RSA"
@ -87,7 +87,7 @@
</LinearLayout> </LinearLayout>
<View <View
android:id="@+id/user_ids_divider" android:id="@+id/import_item_status_divider"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="1dip" android:layout_height="1dip"
android:gravity="right" android:gravity="right"
@ -96,13 +96,13 @@
android:background="?android:attr/listDivider" /> android:background="?android:attr/listDivider" />
<LinearLayout <LinearLayout
android:id="@+id/user_ids_list" android:id="@+id/import_item_user_ids_list"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="match_parent" android:layout_height="match_parent"
android:orientation="vertical" /> android:orientation="vertical" />
<TextView <TextView
android:id="@+id/view_key_fingerprint" android:id="@+id/import_item_fingerprint"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:text="0000 0000 0000 0000 0000\n0000 0000 0000 0000 0000" android:text="0000 0000 0000 0000 0000\n0000 0000 0000 0000 0000"