First semi working version of account details fragment

This commit is contained in:
Paul Schaub 2020-07-10 14:15:58 +02:00
parent b0ee219721
commit 4e1585a4bb
Signed by: vanitasvitae
GPG Key ID: 62BEE9264BF17311
18 changed files with 457 additions and 32 deletions

View File

@ -67,7 +67,7 @@ public class MercuryImApplication extends Application {
/**
* Create the Dependency Injection graph.
*/
public AppComponent createAppComponent() {
private AppComponent createAppComponent() {
AppComponent appComponent = DaggerAppComponent.builder()
.appModule(new AppModule(this))
.build();

View File

@ -3,10 +3,12 @@ package org.mercury_im.messenger.android.di.component;
import org.mercury_im.messenger.android.MercuryImApplication;
import org.mercury_im.messenger.android.di.module.AndroidDatabaseModule;
import org.mercury_im.messenger.android.di.module.AndroidSchedulersModule;
import org.mercury_im.messenger.android.ui.account.AndroidAccountDetailsViewModel;
import org.mercury_im.messenger.android.ui.ox.AndroidOxSecretKeyBackupRestoreViewModel;
import org.mercury_im.messenger.core.di.module.RxMercuryMessageStoreFactoryModule;
import org.mercury_im.messenger.core.di.module.RxMercuryRosterStoreFactoryModule;
import org.mercury_im.messenger.core.di.module.XmppTcpConnectionFactoryModule;
import org.mercury_im.messenger.core.viewmodel.accounts.AccountDetailsViewModel;
import org.mercury_im.messenger.data.di.RepositoryModule;
import org.mercury_im.messenger.android.di.module.AppModule;
import org.mercury_im.messenger.core.di.module.ViewModelModule;
@ -81,6 +83,10 @@ public interface AppComponent {
void inject(ContactDetailViewModel contactDetailViewModel);
void inject(AccountDetailsViewModel accountDetailsViewModel);
void inject(AndroidAccountDetailsViewModel accountDetailsViewModel);
//void inject(AndroidOxSecretKeyBackupRestoreViewModel viewModel);

View File

@ -102,7 +102,7 @@ public class MainActivity extends AppCompatActivity
@Override
public void onAccountListItemClick(Account item) {
getSupportFragmentManager().beginTransaction().replace(R.id.fragment, new AccountDetailsFragment()).commit();
getSupportFragmentManager().beginTransaction().replace(R.id.fragment, new AccountDetailsFragment(item.getId())).commit();
}
@Override

View File

@ -1,18 +1,32 @@
package org.mercury_im.messenger.android.ui.account;
import android.content.Context;
import android.content.Intent;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Button;
import android.widget.ListView;
import android.widget.Switch;
import android.widget.TextView;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.fragment.app.Fragment;
import androidx.lifecycle.ViewModelProvider;
import androidx.recyclerview.widget.RecyclerView;
import org.mercury_im.messenger.R;
import org.mercury_im.messenger.android.MercuryImApplication;
import org.mercury_im.messenger.android.util.OpenPgpFingerprintColorizer;
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;
import butterknife.ButterKnife;
@ -29,17 +43,132 @@ public class AccountDetailsFragment extends Fragment {
@BindView(R.id.btn_share)
Button localFingerprintShareButton;
@BindView(R.id.fingerprint)
@BindView(R.id.local_fingerprint)
TextView localFingerprint;
@BindView(R.id.fingerprint_list)
ListView externalFingerprintList;
RecyclerView externalFingerprintList;
private final UUID accountId;
private ToggleableFingerprintsAdapter adapter;
private AndroidAccountDetailsViewModel viewModel;
private static final DateFormat dateFormat = SimpleDateFormat.getDateInstance();
public AccountDetailsFragment(UUID accountId) {
this.accountId = accountId;
}
@Override
public void onAttach(@NonNull Context context) {
super.onAttach(context);
AndroidAccountDetailsViewModel.AndroidAccountDetailsViewModelFactory factory =
new AndroidAccountDetailsViewModel.AndroidAccountDetailsViewModelFactory(MercuryImApplication.getApplication(), accountId);
viewModel = new ViewModelProvider(this, factory)
.get(AndroidAccountDetailsViewModel.class);
this.adapter = new ToggleableFingerprintsAdapter(viewModel);
observe();
}
private void observe() {
viewModel.getLocalFingerprint().observe(this,
f -> localFingerprint.setText(OpenPgpFingerprintColorizer.formatOpenPgpV4Fingerprint(f)));
viewModel.getRemoteFingerprints().observe(this, adapter::setItems);
//viewModel.getJid().observe(this, jid::setText);
/*
localFingerprintShareButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Intent sendIntent = new Intent();
sendIntent.setAction(Intent.ACTION_SEND);
sendIntent.putExtra(Intent.EXTRA_TEXT, viewModel.getLocalFingerprint().getValue());
sendIntent.setType("text/plain");
Intent shareIntent = Intent.createChooser(sendIntent, null);
startActivity(shareIntent);
}
});
*/
}
@Nullable
@Override
public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.fragment_account_details, container, false);
ButterKnife.bind(this, view);
externalFingerprintList.setAdapter(adapter);
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(OpenPgpFingerprintColorizer.formatOpenPgpV4Fingerprint(fingerprint));
holder.fingerprintTimestamp.setText(dateFormat.format(f.getAnnouncementDate()));
holder.trustSwitch.setChecked(f.isTrusted());
holder.trustSwitch.setOnCheckedChangeListener(
(buttonView, isChecked) -> viewModel.markFingerprintTrusted(fingerprint, isChecked));
}
}
@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;
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);
}
}
}
}

View File

@ -0,0 +1,96 @@
package org.mercury_im.messenger.android.ui.account;
import android.app.Application;
import androidx.annotation.NonNull;
import androidx.lifecycle.AndroidViewModel;
import androidx.lifecycle.LiveData;
import androidx.lifecycle.MutableLiveData;
import androidx.lifecycle.ViewModel;
import androidx.lifecycle.ViewModelProvider;
import org.jxmpp.jid.EntityBareJid;
import org.mercury_im.messenger.android.MercuryImApplication;
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.pgpainless.key.OpenPgpV4Fingerprint;
import java.util.ArrayList;
import java.util.List;
import java.util.UUID;
import javax.inject.Inject;
public class AndroidAccountDetailsViewModel extends AndroidViewModel implements MercuryAndroidViewModel<AccountDetailsViewModel> {
@Inject
SchedulersFacade schedulers;
@Inject
AccountDetailsViewModel commonViewModel;
private final UUID accountId;
private MutableLiveData<OpenPgpV4Fingerprint> localFingerprint = new MutableLiveData<>();
private MutableLiveData<List<AccountFingerprintViewItem>> remoteFingerprints = new MutableLiveData<>(new ArrayList<>());
private MutableLiveData<EntityBareJid> jid;
public AndroidAccountDetailsViewModel(@NonNull Application application, UUID accountId) {
super(application);
this.accountId = accountId;
((MercuryImApplication) application).getAppComponent().inject(this);
addDisposable(getCommonViewModel().observeLocalFingerprint(accountId)
.compose(schedulers.executeUiSafeObservable())
.filter(Optional::isPresent)
.map(Optional::getItem)
.subscribe(localFingerprint::setValue));
addDisposable(getCommonViewModel().observeRemoteFingerprints(accountId)
.compose(schedulers.executeUiSafeObservable())
.subscribe(list -> remoteFingerprints.setValue(list)));
//addDisposable(getCommonViewModel().getJid(accountId).subscribe(jid::setValue));
}
@Override
public AccountDetailsViewModel getCommonViewModel() {
return commonViewModel;
}
public LiveData<EntityBareJid> getJid() {
return jid;
}
public void markFingerprintTrusted(OpenPgpV4Fingerprint fingerprint, boolean trusted) {
getCommonViewModel().markFingerprintTrusted(accountId, fingerprint, trusted);
}
public LiveData<OpenPgpV4Fingerprint> getLocalFingerprint() {
return localFingerprint;
}
public LiveData<List<AccountFingerprintViewItem>> getRemoteFingerprints() {
return remoteFingerprints;
}
public static class AndroidAccountDetailsViewModelFactory implements ViewModelProvider.Factory {
private final Application application;
private final UUID accountId;
public AndroidAccountDetailsViewModelFactory(Application application, UUID accountId) {
this.application = application;
this.accountId = accountId;
}
@NonNull
@Override
public <T extends ViewModel> T create(@NonNull Class<T> modelClass) {
return (T) new AndroidAccountDetailsViewModel(application, accountId);
}
}
}

View File

@ -27,7 +27,7 @@ public class ChatInputFragment extends Fragment implements View.OnClickListener
EditText textInput;
@BindView(R.id.btn_media)
ImageButton addAttachement;
ImageButton addAttachment;
@BindView(R.id.btn_send)
ImageButton buttonSend;

View File

@ -4,8 +4,7 @@
android:layout_width="match_parent"
android:layout_height="match_parent"
xmlns:tools="http://schemas.android.com/tools"
android:orientation="vertical"
android:padding="12dp">
android:orientation="vertical">
<de.hdodenhof.circleimageview.CircleImageView
android:id="@+id/avatar"
@ -35,6 +34,8 @@
android:layout_height="wrap_content"
android:layout_marginTop="12dp"
android:orientation="vertical"
android:padding="12dp"
android:clipToPadding="false"
app:layout_constraintTop_toBottomOf="@id/jid">
<TextView
@ -44,13 +45,13 @@
android:textAppearance="@style/TextAppearance.AppCompat.SearchResult.Title"
android:text="Encryption Keys" />
<include layout="@layout/fragment_fingerprint_card"
<include layout="@layout/view_fingerprint_card"
android:layout_height="wrap_content"
android:layout_width="match_parent"
android:layout_marginTop="8dp"
android:layout_marginBottom="8dp"/>
<include layout="@layout/fragment_toggleable_fingerprints_card"
<include layout="@layout/view_fingerprints_card_toggleable"
android:layout_height="wrap_content"
android:layout_width="match_parent"
android:layout_marginTop="8dp"

View File

@ -1,10 +1,10 @@
<?xml version="1.0" encoding="utf-8"?>
<TextView xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/fingerprint"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:textSize="18sp"
android:typeface="monospace"
tools:text="1357 B018 65B2 503C 1845\n3D20 8CAC 2A96 7854 8E35" />
android:text="@string/test_fingerprint"
tools:text="@string/test_fingerprint" />

View File

@ -23,8 +23,9 @@
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<include
android:id="@+id/fingerprint"
android:id="@+id/local_fingerprint"
layout="@layout/view_fingerprint"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
@ -41,7 +42,7 @@
android:layout_height="wrap_content"
android:text="share"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toBottomOf="@+id/fingerprint" />
app:layout_constraintTop_toBottomOf="@+id/local_fingerprint" />
</androidx.constraintlayout.widget.ConstraintLayout>

View File

@ -2,35 +2,45 @@
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="vertical">
<include
android:id="@+id/include"
android:id="@+id/fingerprint"
layout="@layout/view_fingerprint"
android:layout_height="wrap_content"
android:layout_width="wrap_content"
android:layout_marginVertical="4dp"
app:layout_constraintBottom_toBottomOf="parent"
android:layout_height="wrap_content"
android:layout_marginTop="4dp"
android:layout_marginBottom="4dp"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<Switch
android:id="@+id/toggle"
android:id="@+id/fingerprint_toggle"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="parent"
android:layout_marginEnd="4dp"/>
android:layout_marginStart="12dp"
app:layout_constraintBottom_toTopOf="@+id/divider"
app:layout_constraintStart_toEndOf="@+id/fingerprint"
app:layout_constraintTop_toTopOf="parent" />
<TextView
android:id="@+id/fingerprint_timestamp"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
tools:text="2018-03-01T15:26:12Z"
app:layout_constraintStart_toStartOf="@id/fingerprint"
app:layout_constraintEnd_toEndOf="@id/fingerprint"
app:layout_constraintTop_toBottomOf="@id/fingerprint"
app:layout_constraintBottom_toBottomOf="parent" />
<View
android:id="@+id/divider"
android:layout_width="match_parent"
android:layout_height="1dp"
android:background="?android:attr/listDivider"
app:layout_constraintBottom_toBottomOf="parent" />
app:layout_constraintTop_toBottomOf="@id/fingerprint" />
</androidx.constraintlayout.widget.ConstraintLayout>

View File

@ -4,13 +4,13 @@
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_height="wrap_content"
app:cardCornerRadius="4dp"
app:cardElevation="4dp">
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:paddingStart="12dp"
android:paddingEnd="12dp"
@ -24,11 +24,11 @@
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<ListView
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/fingerprint_list"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
tools:listitem="@layout/view_toggleable_fingerprint"
tools:listitem="@layout/view_fingerprint_toggleable"
android:layout_centerHorizontal="true"
android:layout_marginTop="8dp"
app:layout_constraintEnd_toEndOf="parent"

View File

@ -142,4 +142,6 @@
<string name="error_uknown_error">Unknown error</string>
<string name="content_description_avatar_image">Avatar Image</string>
<string name="button_delete">Delete</string>
<string name="test_fingerprint">1357 B018 65B2 503C 1845\n3D20 8CAC 2A96 7854 8E35</string>
</resources>

View File

@ -89,8 +89,8 @@ public class RepositoryModule {
@Provides
@Singleton
static OpenPgpRepository provideOpenPgpRepository(
ReactiveEntityStore<Persistable> data) {
return new RxOpenPgpRepository(data);
ReactiveEntityStore<Persistable> data, AccountRepository accountRepository) {
return new RxOpenPgpRepository(data, accountRepository);
}
@Provides

View File

@ -6,7 +6,9 @@ import org.bouncycastle.openpgp.PGPSecretKeyRingCollection;
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.data.model.AnnouncedOpenPgpContactKey;
import org.mercury_im.messenger.data.model.OpenPgpKeyFetchDate;
import org.mercury_im.messenger.data.model.OpenPgpKeyTrust;
@ -27,6 +29,7 @@ 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;
@ -43,9 +46,12 @@ public class RxOpenPgpRepository implements OpenPgpRepository {
private final ReactiveEntityStore<Persistable> data;
private final AccountRepository accountRepository;
@Inject
public RxOpenPgpRepository(ReactiveEntityStore<Persistable> data) {
public RxOpenPgpRepository(ReactiveEntityStore<Persistable> data, AccountRepository accountRepository) {
this.data = data;
this.accountRepository = accountRepository;
}
@Override
@ -158,6 +164,24 @@ public class RxOpenPgpRepository implements OpenPgpRepository {
});
}
@Override
public Single<Date> loadAnnouncementDate(UUID accountId, EntityBareJid owner, OpenPgpV4Fingerprint fingerprint) {
return data.select(AnnouncedOpenPgpContactKey.class)
.where(AnnouncedOpenPgpContactKey.ACCOUNT_ID.eq(accountId)
.and(AnnouncedOpenPgpContactKey.OWNER.eq(owner))
.and(AnnouncedOpenPgpContactKey.FINGERPRINT.eq(fingerprint)))
.get().observableResult()
.map(ResultDelegate::first)
.map(AnnouncedOpenPgpContactKey::getModificationDate)
.singleOrError();
}
@Override
public Single<Date> loadAnnouncementDate(UUID accountId, OpenPgpV4Fingerprint fingerprint) {
return accountRepository.getAccount(accountId).toSingle()
.flatMap(account -> loadAnnouncementDate(accountId, account.getJid(), fingerprint));
}
@Override
public Single<OpenPgpTrustStore.Trust> loadTrust(UUID accountId, EntityBareJid owner, OpenPgpV4Fingerprint fingerprint) {
return data.select(OpenPgpKeyTrust.class)
@ -171,6 +195,12 @@ public class RxOpenPgpRepository implements OpenPgpRepository {
.map(entity -> entity.getTrust() != null ? entity.getTrust() : OpenPgpTrustStore.Trust.undecided);
}
@Override
public Single<OpenPgpTrustStore.Trust> loadTrust(UUID accountId, OpenPgpV4Fingerprint fingerprint) {
return accountRepository.getAccount(accountId).toSingle()
.flatMap(account -> loadTrust(accountId, account.getJid(), fingerprint));
}
@Override
public Completable storeTrust(UUID accountId, EntityBareJid owner, OpenPgpV4Fingerprint fingerprint, OpenPgpTrustStore.Trust trust) {
OpenPgpKeyTrust entity = new OpenPgpKeyTrust();
@ -181,6 +211,12 @@ public class RxOpenPgpRepository implements OpenPgpRepository {
return data.upsert(entity).ignoreElement();
}
@Override
public Completable storeTrust(UUID accountId, OpenPgpV4Fingerprint fingerprint, OpenPgpTrustStore.Trust trust) {
return accountRepository.getAccount(accountId).toSingle()
.flatMapCompletable(account -> storeTrust(accountId, account.getJid(), fingerprint, trust));
}
@Override
public Observable<List<OpenPgpV4Fingerprint>> observeFingerprintsOf(UUID accountId, String peerAddress) {
return data.select(OpenPgpPublicKeyRing.class)
@ -201,6 +237,50 @@ public class RxOpenPgpRepository implements OpenPgpRepository {
});
}
@Override
public Observable<Optional<OpenPgpV4Fingerprint>> observeLocalFingerprintOf(UUID accountId) {
return data.select(OpenPgpSecretKeyRing.class)
.where(OpenPgpSecretKeyRing.ACCOUNT_ID.eq(accountId))
.get().observableResult()
.map(result -> {
OpenPgpSecretKeyRing ring = new ResultDelegate<>(result).firstOrNull();
if (ring == null) {
return new Optional<>();
} else {
return new Optional<>(new OpenPgpV4Fingerprint(
PGPainless.readKeyRing().secretKeyRing(ring.getBytes()))
);
}
});
}
@Override
public Observable<List<OpenPgpV4Fingerprint>> observeRemoteFingerprintsOfAccount(UUID accountId) {
return observeLocalFingerprintOf(accountId)
.flatMap(localFingerprint -> data.select(OpenPgpPublicKeyRing.class)
.where(OpenPgpPublicKeyRing.ACCOUNT_ID.eq(accountId))
.get().observableResult()
.map(result -> {
OpenPgpPublicKeyRing ring = new ResultDelegate<>(result).firstOrNull();
if (ring == null) {
return Collections.emptyList();
} else {
Iterator<PGPPublicKeyRing> iterator = PGPainless.readKeyRing().publicKeyRingCollection(ring.getBytes()).iterator();
List<OpenPgpV4Fingerprint> fingerprints = new ArrayList<>();
while (iterator.hasNext()) {
PGPPublicKeyRing r = iterator.next();
OpenPgpV4Fingerprint f = new OpenPgpV4Fingerprint(r);
fingerprints.add(f);
}
if (localFingerprint.isPresent()) {
fingerprints.remove(localFingerprint.getItem());
}
return fingerprints;
}
}));
}
@Override
public Single<Map<OpenPgpV4Fingerprint, Date>> loadPublicKeyFetchDates(UUID accountId, EntityBareJid owner) {
List<OpenPgpKeyFetchDate> fetchDates =

View File

@ -4,6 +4,8 @@ import org.bouncycastle.openpgp.PGPPublicKeyRingCollection;
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.entity.Account;
import org.pgpainless.key.OpenPgpV4Fingerprint;
import java.util.Date;
@ -37,9 +39,21 @@ public interface OpenPgpRepository {
Single<Map<OpenPgpV4Fingerprint, Date>> loadAnnouncedFingerprints(UUID accountId, EntityBareJid contact);
Single<Date> loadAnnouncementDate(UUID accountId, EntityBareJid owner, OpenPgpV4Fingerprint fingerprint);
Single<Date> loadAnnouncementDate(UUID accountId, OpenPgpV4Fingerprint fingerprint);
Single<OpenPgpTrustStore.Trust> loadTrust(UUID accountId, EntityBareJid owner, OpenPgpV4Fingerprint fingerprint);
Single<OpenPgpTrustStore.Trust> loadTrust(UUID accountId, OpenPgpV4Fingerprint fingerprint);
Completable storeTrust(UUID accountId, EntityBareJid owner, OpenPgpV4Fingerprint fingerprint, OpenPgpTrustStore.Trust trust);
Completable storeTrust(UUID accountId, OpenPgpV4Fingerprint fingerprint, OpenPgpTrustStore.Trust trust);
Observable<List<OpenPgpV4Fingerprint>> observeFingerprintsOf(UUID accountId, String peerAddress);
Observable<Optional<OpenPgpV4Fingerprint>> observeLocalFingerprintOf(UUID accountId);
Observable<List<OpenPgpV4Fingerprint>> observeRemoteFingerprintsOfAccount(UUID accountId);
}

View File

@ -3,6 +3,7 @@ package org.mercury_im.messenger.core.di.module;
import org.mercury_im.messenger.core.SchedulersFacade;
import org.mercury_im.messenger.core.data.repository.AccountRepository;
import org.mercury_im.messenger.core.data.repository.OpenPgpRepository;
import org.mercury_im.messenger.core.viewmodel.accounts.AccountDetailsViewModel;
import org.mercury_im.messenger.core.viewmodel.accounts.AccountsViewModel;
import org.mercury_im.messenger.core.viewmodel.accounts.LoginViewModel;
import org.mercury_im.messenger.core.xmpp.MercuryConnectionManager;
@ -32,6 +33,14 @@ public class ViewModelModule {
return new AccountsViewModel(connectionManager, accountRepository, openPgpRepository, schedulers);
}
@Provides
@Singleton
static AccountDetailsViewModel provideAccountDetailsViewModel(OpenPgpRepository openPgpRepository,
AccountRepository accountRepository,
SchedulersFacade schedulers) {
return new AccountDetailsViewModel(openPgpRepository, accountRepository, schedulers);
}
/*
@Provides
@Singleton

View File

@ -0,0 +1,61 @@
package org.mercury_im.messenger.core.viewmodel.accounts;
import org.jivesoftware.smackx.ox.store.definition.OpenPgpTrustStore;
import org.jxmpp.jid.EntityBareJid;
import org.mercury_im.messenger.core.SchedulersFacade;
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.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;
import io.reactivex.Observable;
import io.reactivex.Single;
public class AccountDetailsViewModel implements MercuryViewModel {
private final OpenPgpRepository openPgpRepository;
private final AccountRepository accountRepository;
private final SchedulersFacade schedulers;
public AccountDetailsViewModel(OpenPgpRepository openPgpRepository, AccountRepository accountRepository, SchedulersFacade schedulers) {
this.openPgpRepository = openPgpRepository;
this.accountRepository = accountRepository;
this.schedulers = schedulers;
}
public void markFingerprintTrusted(UUID accountId, OpenPgpV4Fingerprint fingerprint, boolean trusted) {
addDisposable(openPgpRepository.storeTrust(accountId, fingerprint, trusted ? OpenPgpTrustStore.Trust.trusted : OpenPgpTrustStore.Trust.untrusted)
.compose(schedulers.executeUiSafeCompletable())
.subscribe());
}
public Single<EntityBareJid> getJid(UUID accountId) {
return accountRepository.getAccount(accountId).toSingle()
.compose(schedulers.executeUiSafeSingle())
.map(Account::getJid);
}
public Observable<Optional<OpenPgpV4Fingerprint>> observeLocalFingerprint(UUID accountId) {
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;
});
}
}

View File

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