Fix contact fingerprint displaying

This commit is contained in:
Paul Schaub 2020-07-13 14:43:30 +02:00
parent 47ab78ba60
commit e63632ee0e
Signed by: vanitasvitae
GPG Key ID: 62BEE9264BF17311
14 changed files with 275 additions and 188 deletions

View File

@ -33,7 +33,7 @@ import butterknife.ButterKnife;
public class MainActivity extends AppCompatActivity
implements NavigationView.OnNavigationItemSelectedListener,
OnAccountListItemClickListener {
OnAccountListItemClickListener, SearchView.OnQueryTextListener {
@BindView(R.id.toolbar)
Toolbar toolbar;
@ -41,11 +41,10 @@ public class MainActivity extends AppCompatActivity
@BindView(R.id.bottom_navigation)
BottomNavigationView bottomNavigationView;
private SearchView searchView;
private ChatListFragment chatListFragment = new ChatListFragment();
private RosterFragment rosterFragment = new RosterFragment();
private AccountsFragment accountsFragment = new AccountsFragment();
private SearchView.OnQueryTextListener searchViewListeningFragment;
@Inject
AccountRepository accountRepository;
@ -55,11 +54,11 @@ public class MainActivity extends AppCompatActivity
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
ButterKnife.bind(this);
setSupportActionBar(toolbar);
MercuryImApplication.getApplication().getAppComponent().inject(this);
setSupportActionBar(toolbar);
bottomNavigationView.setOnNavigationItemSelectedListener(this::onNavigationItemSelected);
bottomNavigationView.setSelectedItemId(R.id.entry_chats);
MercuryImApplication.getApplication().getAppComponent().inject(this);
}
@Override
@ -68,7 +67,8 @@ public class MainActivity extends AppCompatActivity
getMenuInflater().inflate(R.menu.menu_main, menu);
final MenuItem searchItem = menu.findItem(R.id.action_search);
searchView = (SearchView) searchItem.getActionView();
SearchView searchView = (SearchView) searchItem.getActionView();
searchView.setOnQueryTextListener(this);
return true;
}
@ -94,15 +94,17 @@ public class MainActivity extends AppCompatActivity
case R.id.entry_chats:
transaction.replace(R.id.fragment, chatListFragment).commit();
searchViewListeningFragment = chatListFragment;
return true;
case R.id.entry_contacts:
transaction.replace(R.id.fragment, rosterFragment).commit();
searchView.setOnQueryTextListener(rosterFragment);
searchViewListeningFragment = rosterFragment;
return true;
case R.id.entry_accounts:
transaction.replace(R.id.fragment, accountsFragment).commit();
searchViewListeningFragment = accountsFragment;
return true;
}
return false;
@ -110,12 +112,23 @@ public class MainActivity extends AppCompatActivity
@Override
public void onAccountListItemClick(Account item) {
getSupportFragmentManager().beginTransaction().addToBackStack("Test")
getSupportFragmentManager().beginTransaction().addToBackStack("ACCOUNT")
.replace(R.id.fragment, new AccountDetailsFragment(item.getId())).commit();
}
@Override
public void onAccountListItemLongClick(Account item) {
new DeleteAccountDialogFragment(item.getId()).show(getSupportFragmentManager(), "DELETE");
new DeleteAccountDialogFragment(item.getId())
.show(getSupportFragmentManager(), "DELETE");
}
@Override
public boolean onQueryTextSubmit(String query) {
return searchViewListeningFragment.onQueryTextSubmit(query);
}
@Override
public boolean onQueryTextChange(String newText) {
return searchViewListeningFragment.onQueryTextChange(newText);
}
}

View File

@ -0,0 +1,91 @@
package org.mercury_im.messenger.android.ui;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Switch;
import android.widget.TextView;
import androidx.annotation.NonNull;
import androidx.recyclerview.widget.RecyclerView;
import org.mercury_im.messenger.R;
import org.mercury_im.messenger.android.util.OpenPgpV4FingerprintFormatter;
import org.mercury_im.messenger.core.viewmodel.accounts.FingerprintViewItem;
import org.pgpainless.key.OpenPgpV4Fingerprint;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.List;
public class ToggleableFingerprintsAdapter extends RecyclerView.Adapter<ToggleableFingerprintsAdapter.ViewHolder> {
private final List<FingerprintViewItem> fingerprints = new ArrayList<>();
private final OnFingerprintItemToggleListener toggleListener;
private static final DateFormat dateFormat = SimpleDateFormat.getDateInstance();
public ToggleableFingerprintsAdapter(OnFingerprintItemToggleListener toggleListener) {
this.toggleListener = toggleListener;
}
public void setItems(List<FingerprintViewItem> fingerprints) {
synchronized (this.fingerprints) {
this.fingerprints.clear();
this.fingerprints.addAll(fingerprints);
this.notifyDataSetChanged();
}
}
@NonNull
@Override
public ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
View view = LayoutInflater.from(parent.getContext())
.inflate(R.layout.view_fingerprint_toggleable, parent, false);
return new ViewHolder(view);
}
@Override
public void onBindViewHolder(@NonNull ViewHolder holder, int position) {
synchronized (fingerprints) {
FingerprintViewItem f = fingerprints.get(position);
final OpenPgpV4Fingerprint fingerprint = f.getFingerprint();
holder.fingerprint.setText(OpenPgpV4FingerprintFormatter.formatOpenPgpV4Fingerprint(fingerprint));
holder.fingerprintTimestamp.setText(dateFormat.format(f.getModificationDate()));
holder.trustSwitch.setChecked(f.isTrusted());
holder.trustSwitch.setOnCheckedChangeListener(
(buttonView, isChecked) -> toggleListener.onFingerprintToggled(fingerprint, isChecked));
holder.divider.setVisibility(position == fingerprints.size() - 1 ? View.GONE : View.VISIBLE);
}
}
@Override
public int getItemCount() {
return fingerprints.size();
}
public static class ViewHolder extends RecyclerView.ViewHolder {
private final Switch trustSwitch;
private final TextView fingerprintTimestamp;
private final TextView fingerprint;
private final View divider;
public ViewHolder(@NonNull View itemView) {
super(itemView);
this.fingerprint = itemView.findViewById(R.id.fingerprint);
this.trustSwitch = itemView.findViewById(R.id.fingerprint_toggle);
this.fingerprintTimestamp = itemView.findViewById(R.id.fingerprint_timestamp);
this.divider = itemView.findViewById(R.id.divider);
}
}
public interface OnFingerprintItemToggleListener {
void onFingerprintToggled(OpenPgpV4Fingerprint fingerprint, boolean checked);
}
}

View File

@ -7,7 +7,6 @@ import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Button;
import android.widget.Switch;
import android.widget.TextView;
import androidx.annotation.NonNull;
@ -20,14 +19,10 @@ import com.google.android.material.card.MaterialCardView;
import org.mercury_im.messenger.R;
import org.mercury_im.messenger.android.MercuryImApplication;
import org.mercury_im.messenger.android.ui.ToggleableFingerprintsAdapter;
import org.mercury_im.messenger.android.util.OpenPgpV4FingerprintFormatter;
import org.mercury_im.messenger.core.viewmodel.accounts.AccountFingerprintViewItem;
import org.pgpainless.key.OpenPgpV4Fingerprint;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.List;
import java.util.UUID;
import butterknife.BindView;
@ -59,9 +54,6 @@ public class AccountDetailsFragment extends Fragment {
private AndroidAccountDetailsViewModel viewModel;
private static final DateFormat dateFormat = SimpleDateFormat.getDateInstance();
public AccountDetailsFragment(UUID accountId) {
this.accountId = accountId;
}
@ -74,7 +66,8 @@ public class AccountDetailsFragment extends Fragment {
viewModel = new ViewModelProvider(this, factory)
.get(AndroidAccountDetailsViewModel.class);
this.adapter = new ToggleableFingerprintsAdapter(viewModel);
this.adapter = new ToggleableFingerprintsAdapter(
(fingerprint, checked) -> viewModel.markFingerprintTrusted(fingerprint, checked));
}
private void observe() {
@ -114,68 +107,4 @@ public class AccountDetailsFragment extends Fragment {
return view;
}
public static class ToggleableFingerprintsAdapter extends RecyclerView.Adapter<ToggleableFingerprintsAdapter.ViewHolder> {
private final List<AccountFingerprintViewItem> fingerprints = new ArrayList<>();
private final AndroidAccountDetailsViewModel viewModel;
public ToggleableFingerprintsAdapter(AndroidAccountDetailsViewModel viewModel) {
this.viewModel = viewModel;
}
public void setItems(List<AccountFingerprintViewItem> fingerprints) {
synchronized (this.fingerprints) {
this.fingerprints.clear();
this.fingerprints.addAll(fingerprints);
this.notifyDataSetChanged();
}
}
@NonNull
@Override
public ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
View view = LayoutInflater.from(parent.getContext())
.inflate(R.layout.view_fingerprint_toggleable, parent, false);
return new ViewHolder(view);
}
@Override
public void onBindViewHolder(@NonNull ViewHolder holder, int position) {
synchronized (fingerprints) {
AccountFingerprintViewItem f = fingerprints.get(position);
final OpenPgpV4Fingerprint fingerprint = f.getFingerprint();
holder.fingerprint.setText(OpenPgpV4FingerprintFormatter.formatOpenPgpV4Fingerprint(fingerprint));
holder.fingerprintTimestamp.setText(dateFormat.format(f.getAnnouncementDate()));
holder.trustSwitch.setChecked(f.isTrusted());
holder.trustSwitch.setOnCheckedChangeListener(
(buttonView, isChecked) -> viewModel.markFingerprintTrusted(fingerprint, isChecked));
holder.divider.setVisibility(position == fingerprints.size() - 1 ? View.GONE : View.VISIBLE);
}
}
@Override
public int getItemCount() {
return fingerprints.size();
}
public static class ViewHolder extends RecyclerView.ViewHolder {
private final Switch trustSwitch;
private final TextView fingerprintTimestamp;
private final TextView fingerprint;
private final View divider;
public ViewHolder(@NonNull View itemView) {
super(itemView);
this.fingerprint = itemView.findViewById(R.id.fingerprint);
this.trustSwitch = itemView.findViewById(R.id.fingerprint_toggle);
this.fingerprintTimestamp = itemView.findViewById(R.id.fingerprint_timestamp);
this.divider = itemView.findViewById(R.id.divider);
}
}
}
}

View File

@ -6,6 +6,7 @@ import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import androidx.appcompat.widget.SearchView;
import androidx.fragment.app.Fragment;
import androidx.lifecycle.ViewModelProvider;
import androidx.recyclerview.widget.LinearLayoutManager;
@ -29,7 +30,7 @@ import butterknife.ButterKnife;
* Activities containing this fragment MUST implement the {@link OnAccountListItemClickListener}
* interface.
*/
public class AccountsFragment extends Fragment {
public class AccountsFragment extends Fragment implements SearchView.OnQueryTextListener {
private OnAccountListItemClickListener accountClickListener;
@ -101,4 +102,14 @@ public class AccountsFragment extends Fragment {
AddAccountDialogFragment addAccountDialogFragment = new AddAccountDialogFragment();
addAccountDialogFragment.show(getParentFragmentManager(), "addAccount");
}
@Override
public boolean onQueryTextSubmit(String query) {
return false;
}
@Override
public boolean onQueryTextChange(String newText) {
return false;
}
}

View File

@ -16,7 +16,7 @@ import org.mercury_im.messenger.android.ui.MercuryAndroidViewModel;
import org.mercury_im.messenger.core.SchedulersFacade;
import org.mercury_im.messenger.core.util.Optional;
import org.mercury_im.messenger.core.viewmodel.accounts.AccountDetailsViewModel;
import org.mercury_im.messenger.core.viewmodel.accounts.AccountFingerprintViewItem;
import org.mercury_im.messenger.core.viewmodel.accounts.FingerprintViewItem;
import org.pgpainless.key.OpenPgpV4Fingerprint;
import java.util.ArrayList;
@ -40,7 +40,7 @@ public class AndroidAccountDetailsViewModel extends AndroidViewModel implements
private final UUID accountId;
private MutableLiveData<OpenPgpV4Fingerprint> localFingerprint = new MutableLiveData<>(new OpenPgpV4Fingerprint("09858F60046289311743B90F3152226EB43287C5"));
private MutableLiveData<List<AccountFingerprintViewItem>> remoteFingerprints = new MutableLiveData<>(new ArrayList<>());
private MutableLiveData<List<FingerprintViewItem>> remoteFingerprints = new MutableLiveData<>(new ArrayList<>());
private MutableLiveData<EntityBareJid> jid = new MutableLiveData<>(JidCreate.entityBareFromOrThrowUnchecked("placeholder@place.holder"));
public AndroidAccountDetailsViewModel(@NonNull Application application, UUID accountId) {
@ -85,7 +85,7 @@ public class AndroidAccountDetailsViewModel extends AndroidViewModel implements
return localFingerprint;
}
public LiveData<List<AccountFingerprintViewItem>> getRemoteFingerprints() {
public LiveData<List<FingerprintViewItem>> getRemoteFingerprints() {
return remoteFingerprints;
}

View File

@ -10,6 +10,7 @@ import android.widget.Toast;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.appcompat.widget.SearchView;
import androidx.fragment.app.Fragment;
import androidx.lifecycle.ViewModelProvider;
import androidx.recyclerview.widget.RecyclerView;
@ -22,7 +23,7 @@ import org.mercury_im.messenger.R;
import butterknife.BindView;
import butterknife.ButterKnife;
public class ChatListFragment extends Fragment {
public class ChatListFragment extends Fragment implements SearchView.OnQueryTextListener {
private ChatListViewModel viewModel;
@ -65,4 +66,14 @@ public class ChatListFragment extends Fragment {
recyclerViewAdapter.setModels(chatModels);
});
}
@Override
public boolean onQueryTextSubmit(String query) {
return false;
}
@Override
public boolean onQueryTextChange(String newText) {
return false;
}
}

View File

@ -18,16 +18,21 @@ import androidx.annotation.Nullable;
import androidx.fragment.app.Fragment;
import androidx.lifecycle.ViewModelProvider;
import androidx.lifecycle.ViewModelStoreOwner;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
import com.google.android.material.card.MaterialCardView;
import com.google.android.material.chip.Chip;
import com.google.android.material.chip.ChipGroup;
import com.google.android.material.floatingactionbutton.ExtendedFloatingActionButton;
import org.mercury_im.messenger.android.ui.ToggleableFingerprintsAdapter;
import org.mercury_im.messenger.android.util.OpenPgpV4FingerprintFormatter;
import org.mercury_im.messenger.core.Messenger;
import org.mercury_im.messenger.R;
import org.mercury_im.messenger.android.ui.chat.ChatActivity;
import org.mercury_im.messenger.android.util.ColorUtil;
import org.mercury_im.messenger.core.viewmodel.accounts.FingerprintViewItem;
import org.pgpainless.key.OpenPgpV4Fingerprint;
import java.util.List;
@ -67,10 +72,14 @@ public class ContactDetailFragment extends Fragment {
@BindView(R.id.button_add_to_group)
Button button;
@BindView(R.id.fingerprint)
TextView fingerprint;
@BindView(R.id.fingerprint_list)
RecyclerView fingerprintRecyclerView;
@BindView(R.id.contact_fingerprints)
MaterialCardView fingerprintsLayout;
private ContactDetailViewModel viewModel;
private ToggleableFingerprintsAdapter fingerprintsAdapter;
@Nullable
@Override
@ -87,24 +96,7 @@ public class ContactDetailFragment extends Fragment {
});
}
contactName.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
AlertDialog.Builder builder = new AlertDialog.Builder(getContext());
builder.setTitle("Edit Contact Name");
final EditText editText = new EditText(getContext());
editText.setText(contactName.getText());
builder.setView(editText)
.setPositiveButton("Save", (dialog, which) -> {
Completable.fromAction(() -> viewModel.changeContactName(editText.getText().toString())).subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(() -> {}, e -> Log.e(Messenger.TAG, "Error changing contact name", e));
})
.setNegativeButton("Cancel", (dialog, which) -> dialog.cancel());
builder.show();
}
});
contactName.setOnClickListener(v -> displayChangeContactNameDialog());
button.setOnClickListener(new View.OnClickListener() {
@Override
@ -115,9 +107,29 @@ public class ContactDetailFragment extends Fragment {
}
});
fingerprintsAdapter = new ToggleableFingerprintsAdapter(
(fingerprint, checked) -> viewModel.markFingerprintTrusted(fingerprint, checked));
fingerprintRecyclerView.setAdapter(fingerprintsAdapter);
return view;
}
private void displayChangeContactNameDialog() {
AlertDialog.Builder builder = new AlertDialog.Builder(getContext());
builder.setTitle("Edit Contact Name");
final EditText editText = new EditText(getContext());
editText.setText(contactName.getText());
builder.setView(editText)
.setPositiveButton("Save", (dialog, which) -> {
Completable.fromAction(() -> viewModel.changeContactName(editText.getText().toString())).subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(() -> {}, e -> Log.e(Messenger.TAG, "Error changing contact name", e));
})
.setNegativeButton("Cancel", (dialog, which) -> dialog.cancel());
builder.show();
}
@Override
public void onAttach(Context context) {
super.onAttach(context);
@ -162,8 +174,8 @@ public class ContactDetailFragment extends Fragment {
@Override
public boolean onLongClick(View v) {
viewModel.removeContactFromRosterGroup(group)
.subscribeOn(Schedulers.io()).observeOn(AndroidSchedulers.mainThread())
.subscribe();
.subscribeOn(Schedulers.io()).observeOn(AndroidSchedulers.mainThread())
.subscribe();
return true;
}
});
@ -171,10 +183,8 @@ public class ContactDetailFragment extends Fragment {
}
}
private void setFingerprints(List<OpenPgpV4Fingerprint> fingerprints) {
if (fingerprints.isEmpty()) {
return;
}
fingerprint.setText(OpenPgpV4FingerprintFormatter.formatOpenPgpV4Fingerprint(fingerprints.get(0)));
private void setFingerprints(List<FingerprintViewItem> fingerprints) {
fingerprintsLayout.setVisibility(fingerprints.isEmpty() ? View.GONE : View.VISIBLE);
fingerprintsAdapter.setItems(fingerprints);
}
}

View File

@ -14,7 +14,9 @@ import org.jivesoftware.smack.roster.PresenceEventListener;
import org.jivesoftware.smack.roster.Roster;
import org.jivesoftware.smack.roster.RosterEntry;
import org.jivesoftware.smack.roster.RosterGroup;
import org.jivesoftware.smackx.ox.store.definition.OpenPgpTrustStore;
import org.jxmpp.jid.BareJid;
import org.jxmpp.jid.EntityBareJid;
import org.jxmpp.jid.Jid;
import org.jxmpp.jid.impl.JidCreate;
import org.mercury_im.messenger.android.MercuryImApplication;
@ -22,6 +24,7 @@ import org.mercury_im.messenger.core.Messenger;
import org.mercury_im.messenger.core.SchedulersFacade;
import org.mercury_im.messenger.core.data.repository.OpenPgpRepository;
import org.mercury_im.messenger.core.data.repository.PeerRepository;
import org.mercury_im.messenger.core.viewmodel.accounts.FingerprintViewItem;
import org.mercury_im.messenger.entity.contact.Peer;
import org.mercury_im.messenger.android.ui.avatar.AvatarDrawable;
import org.mercury_im.messenger.core.util.CombinedPresenceListener;
@ -61,8 +64,7 @@ public class ContactDetailViewModel extends ViewModel {
private MutableLiveData<String> contactName = new MutableLiveData<>("Alice Wonderland");
private MutableLiveData<String> contactAccountAddress = new MutableLiveData<>("mad@hatter.lit");
private MutableLiveData<List<String>> contactGroups = new MutableLiveData<>(Collections.emptyList());
private MutableLiveData<List<OpenPgpV4Fingerprint>> contactFingerprints =
new MutableLiveData<>(Collections.singletonList(new OpenPgpV4Fingerprint("1234567890ABCDEF1234567890ABCDEF01234567")));
private MutableLiveData<List<FingerprintViewItem>> contactFingerprints = new MutableLiveData<>(Collections.emptyList());
private Roster roster;
@ -102,7 +104,7 @@ public class ContactDetailViewModel extends ViewModel {
}
}));
BareJid jid = JidCreate.entityBareFromOrThrowUnchecked(peerAddress);
EntityBareJid jid = JidCreate.entityBareFromOrThrowUnchecked(peerAddress);
Presence presence = roster.getPresence(jid);
if (presence != null) {
@ -110,7 +112,7 @@ public class ContactDetailViewModel extends ViewModel {
contactPresenceStatus.postValue(presence.getStatus());
}
disposable.add(openPgpRepository.observeFingerprintsOf(accountId, peerAddress)
disposable.add(openPgpRepository.observeFingerprints(accountId, jid)
.subscribeOn(schedulers.getIoScheduler())
.observeOn(schedulers.getUiScheduler())
.subscribe(list -> contactFingerprints.setValue(list)));
@ -200,7 +202,15 @@ public class ContactDetailViewModel extends ViewModel {
}
public LiveData<List<OpenPgpV4Fingerprint>> getContactFingerprints() {
public LiveData<List<FingerprintViewItem>> getContactFingerprints() {
return contactFingerprints;
}
public void markFingerprintTrusted(OpenPgpV4Fingerprint fingerprint, boolean checked) {
openPgpRepository.storeTrust(contactAccountId.getValue(),
JidCreate.entityBareFromOrThrowUnchecked(contactAddress.getValue()),
fingerprint,
checked ? OpenPgpTrustStore.Trust.trusted : OpenPgpTrustStore.Trust.untrusted)
.subscribe();
}
}

View File

@ -16,10 +16,10 @@
xmlns:card_view="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="16dp"
android:layout_marginStart="16dp"
android:layout_marginEnd="16dp"
android:layout_marginBottom="8dp"
android:layout_marginTop="12dp"
android:layout_marginStart="12dp"
android:layout_marginEnd="12dp"
android:layout_marginBottom="6dp"
card_view:cardElevation="4dp"
card_view:cardCornerRadius="6dp">
@ -94,10 +94,10 @@
<androidx.cardview.widget.CardView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="8dp"
android:layout_marginStart="16dp"
android:layout_marginEnd="16dp"
android:layout_marginBottom="8dp"
android:layout_marginTop="6dp"
android:layout_marginStart="12dp"
android:layout_marginEnd="12dp"
android:layout_marginBottom="6dp"
app:cardElevation="4dp"
app:cardCornerRadius="6dp">
@ -153,34 +153,14 @@
</androidx.cardview.widget.CardView>
<androidx.cardview.widget.CardView
android:layout_width="match_parent"
<include layout="@layout/view_fingerprints_card_toggleable"
android:id="@+id/contact_fingerprints"
android:layout_height="wrap_content"
android:layout_marginTop="8dp"
android:layout_marginStart="16dp"
android:layout_marginEnd="16dp"
android:layout_marginBottom="8dp"
app:cardElevation="4dp"
app:cardCornerRadius="6dp">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:padding="8dp">
<TextView
android:id="@+id/fingerprint"
tools:text="1357 B018 65B2 503C 1845\n3D20 8CAC 2A96 7854 8E35"
android:textSize="20dp"
android:typeface="monospace"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
</LinearLayout>
</androidx.cardview.widget.CardView>
android:layout_width="match_parent"
android:layout_marginStart="12dp"
android:layout_marginEnd="12dp"
android:layout_marginTop="6dp"
android:layout_marginBottom="64dp"/>
</LinearLayout>

View File

@ -3,12 +3,14 @@ package org.mercury_im.messenger.data.repository;
import org.bouncycastle.openpgp.PGPPublicKeyRing;
import org.bouncycastle.openpgp.PGPPublicKeyRingCollection;
import org.bouncycastle.openpgp.PGPSecretKeyRingCollection;
import org.jivesoftware.smackx.bytestreams.ibb.packet.Open;
import org.jivesoftware.smackx.ox.store.definition.OpenPgpTrustStore;
import org.jxmpp.jid.EntityBareJid;
import org.jxmpp.jid.impl.JidCreate;
import org.mercury_im.messenger.core.data.repository.AccountRepository;
import org.mercury_im.messenger.core.data.repository.OpenPgpRepository;
import org.mercury_im.messenger.core.util.Optional;
import org.mercury_im.messenger.core.viewmodel.accounts.FingerprintViewItem;
import org.mercury_im.messenger.data.model.AnnouncedOpenPgpContactKey;
import org.mercury_im.messenger.data.model.OpenPgpKeyFetchDate;
import org.mercury_im.messenger.data.model.OpenPgpKeyTrust;
@ -21,7 +23,6 @@ import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.Date;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
@ -29,7 +30,6 @@ import java.util.UUID;
import java.util.concurrent.ConcurrentHashMap;
import java.util.logging.Level;
import java.util.logging.Logger;
import java.util.stream.Stream;
import javax.inject.Inject;
@ -38,6 +38,7 @@ import io.reactivex.Observable;
import io.reactivex.Single;
import io.requery.Persistable;
import io.requery.query.ResultDelegate;
import io.requery.query.Tuple;
import io.requery.reactivex.ReactiveEntityStore;
public class RxOpenPgpRepository implements OpenPgpRepository {
@ -272,6 +273,34 @@ public class RxOpenPgpRepository implements OpenPgpRepository {
}));
}
@Override
public Observable<List<FingerprintViewItem>> observeFingerprints(UUID accountId, EntityBareJid owner) {
return data.select(AnnouncedOpenPgpContactKey.ACCOUNT_ID,
AnnouncedOpenPgpContactKey.OWNER,
AnnouncedOpenPgpContactKey.FINGERPRINT,
AnnouncedOpenPgpContactKey.MODIFICATION_DATE,
OpenPgpKeyFetchDate.FETCH_DATE,
OpenPgpKeyTrust.TRUST)
.from(AnnouncedOpenPgpContactKey.class)
.join(OpenPgpKeyFetchDate.class)
.on(AnnouncedOpenPgpContactKey.ACCOUNT_ID.eq(OpenPgpKeyFetchDate.ACCOUNT_ID)
.and(AnnouncedOpenPgpContactKey.OWNER.eq(OpenPgpKeyFetchDate.OWNER)
.and(AnnouncedOpenPgpContactKey.FINGERPRINT.eq(OpenPgpKeyFetchDate.FINGERPRINT))))
.join(OpenPgpKeyTrust.class)
.on(OpenPgpKeyTrust.ACCOUNT_ID.eq(AnnouncedOpenPgpContactKey.ACCOUNT_ID)
.and(OpenPgpKeyTrust.OWNER.eq(AnnouncedOpenPgpContactKey.OWNER)
.and(OpenPgpKeyTrust.FINGERPRINT.eq(AnnouncedOpenPgpContactKey.FINGERPRINT))))
.where(AnnouncedOpenPgpContactKey.ACCOUNT_ID.eq(accountId).and(AnnouncedOpenPgpContactKey.OWNER.eq(owner)))
.get().observableResult()
.map(ResultDelegate::toList)
.map(list -> {
ArrayList<FingerprintViewItem> result = new ArrayList<>(list.size());
for (Tuple tuple : list) {
result.add(new FingerprintViewItem(tuple.get(0), tuple.get(1), tuple.get(2), tuple.get(3), tuple.get(4), tuple.get(5)));
}
return result;
});
}
@Override
public Single<Map<OpenPgpV4Fingerprint, Date>> loadPublicKeyFetchDates(UUID accountId, EntityBareJid owner) {

View File

@ -5,6 +5,7 @@ import org.bouncycastle.openpgp.PGPSecretKeyRingCollection;
import org.jivesoftware.smackx.ox.store.definition.OpenPgpTrustStore;
import org.jxmpp.jid.EntityBareJid;
import org.mercury_im.messenger.core.util.Optional;
import org.mercury_im.messenger.core.viewmodel.accounts.FingerprintViewItem;
import org.pgpainless.key.OpenPgpV4Fingerprint;
import java.util.Date;
@ -55,4 +56,6 @@ public interface OpenPgpRepository {
Observable<Optional<OpenPgpV4Fingerprint>> observeLocalFingerprintOf(UUID accountId);
Observable<List<OpenPgpV4Fingerprint>> observeRemoteFingerprintsOfAccount(UUID accountId);
Observable<List<FingerprintViewItem>> observeFingerprints(UUID accountId, EntityBareJid owner);
}

View File

@ -10,8 +10,6 @@ import org.mercury_im.messenger.core.viewmodel.MercuryViewModel;
import org.mercury_im.messenger.entity.Account;
import org.pgpainless.key.OpenPgpV4Fingerprint;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.UUID;
@ -46,16 +44,8 @@ public class AccountDetailsViewModel implements MercuryViewModel {
return openPgpRepository.observeLocalFingerprintOf(accountId);
}
public Observable<List<AccountFingerprintViewItem>> observeRemoteFingerprints(UUID accountId) {
return openPgpRepository.observeRemoteFingerprintsOfAccount(accountId)
.map(list -> {
List<AccountFingerprintViewItem> viewItems = new ArrayList<>(list.size());
for (OpenPgpV4Fingerprint fingerprint : list) {
OpenPgpTrustStore.Trust trust = openPgpRepository.loadTrust(accountId, fingerprint).blockingGet();
Date announcementDate = openPgpRepository.loadAnnouncementDate(accountId, fingerprint).blockingGet();
viewItems.add(new AccountFingerprintViewItem(fingerprint, announcementDate, trust == OpenPgpTrustStore.Trust.trusted));
}
return viewItems;
});
public Observable<List<FingerprintViewItem>> observeRemoteFingerprints(UUID accountId) {
return accountRepository.getAccount(accountId).toSingle()
.flatMapObservable(account -> openPgpRepository.observeFingerprints(accountId, account.getJid()));
}
}

View File

@ -1,18 +0,0 @@
package org.mercury_im.messenger.core.viewmodel.accounts;
import org.pgpainless.key.OpenPgpV4Fingerprint;
import java.util.Date;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.ToString;
@Data
@AllArgsConstructor
@ToString
public class AccountFingerprintViewItem {
OpenPgpV4Fingerprint fingerprint;
Date announcementDate;
boolean trusted;
}

View File

@ -0,0 +1,28 @@
package org.mercury_im.messenger.core.viewmodel.accounts;
import org.jivesoftware.smackx.ox.store.definition.OpenPgpTrustStore;
import org.jxmpp.jid.EntityBareJid;
import org.pgpainless.key.OpenPgpV4Fingerprint;
import java.util.Date;
import java.util.UUID;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.ToString;
@Data
@AllArgsConstructor
@ToString
public class FingerprintViewItem {
UUID accountId;
EntityBareJid owner;
OpenPgpV4Fingerprint fingerprint;
Date modificationDate;
Date fetchDate;
OpenPgpTrustStore.Trust trusted;
public boolean isTrusted() {
return trusted == OpenPgpTrustStore.Trust.trusted;
}
}