use loader + recyclerview for identity list
This commit is contained in:
@@ -0,0 +1,111 @@
|
||||
/*
|
||||
* 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.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<ViewHolder> {
|
||||
private final Context context;
|
||||
private final LayoutInflater layoutInflater;
|
||||
private List<IdentityInfo> data;
|
||||
|
||||
public IdentityAdapter(Context context) {
|
||||
super();
|
||||
this.layoutInflater = LayoutInflater.from(context);
|
||||
this.context = context;
|
||||
}
|
||||
|
||||
public void setData(List<IdentityInfo> 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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";
|
||||
|
||||
|
||||
@@ -0,0 +1,151 @@
|
||||
/*
|
||||
* 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.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<List<IdentityInfo>> {
|
||||
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<IdentityInfo> cachedResult;
|
||||
|
||||
|
||||
public IdentityLoader(Context context, ContentResolver contentResolver, long masterKeyId) {
|
||||
super(context);
|
||||
|
||||
this.contentResolver = contentResolver;
|
||||
this.masterKeyId = masterKeyId;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<IdentityInfo> 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<IdentityInfo> 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<IdentityInfo> 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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<Cursor> {
|
||||
public class IdentitiesPresenter implements LoaderCallbacks<List<IdentityInfo>> {
|
||||
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<Cursor> {
|
||||
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<Cursor> {
|
||||
}
|
||||
|
||||
@Override
|
||||
public Loader<Cursor> onCreateLoader(int id, Bundle args) {
|
||||
return UserIdsAdapter.createLoader(context, KeyRings.buildUnifiedKeyRingUri(masterKeyId));
|
||||
public Loader<List<IdentityInfo>> onCreateLoader(int id, Bundle args) {
|
||||
return new IdentityLoader(context, context.getContentResolver(), masterKeyId);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onLoadFinished(Loader<Cursor> loader, Cursor data) {
|
||||
public void onLoadFinished(Loader<List<IdentityInfo>> loader, List<IdentityInfo> 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<Cursor> {
|
||||
}
|
||||
|
||||
public interface IdentitiesMvpView {
|
||||
void setUserIdsAdapter(UserIdsAdapter userIdsAdapter);
|
||||
void setIdentitiesAdapter(IdentityAdapter userIdsAdapter);
|
||||
void setIdentitiesCardListener(IdentitiesCardListener identitiesCardListener);
|
||||
void setEditIdentitiesButtonVisible(boolean show);
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -27,7 +27,7 @@
|
||||
tools:visibility="visible"
|
||||
/>
|
||||
|
||||
<org.sufficientlysecure.keychain.ui.widget.FixedListView
|
||||
<android.support.v7.widget.RecyclerView
|
||||
android:id="@+id/view_key_user_ids"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
|
||||
@@ -0,0 +1,31 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical"
|
||||
android:layout_marginLeft="8dp"
|
||||
android:layout_marginTop="4dp"
|
||||
android:layout_marginBottom="4dp">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/user_id_item_address"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="alice@example.com"
|
||||
android:textAppearance="?android:attr/textAppearanceMedium" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/user_id_item_name"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="Alice"
|
||||
android:textAppearance="?android:attr/textAppearanceSmall" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/user_id_item_comment"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="comment"
|
||||
android:textAppearance="?android:attr/textAppearanceSmall" />
|
||||
|
||||
</LinearLayout>
|
||||
Reference in New Issue
Block a user