Account Setup flow rework
This commit is contained in:
parent
7d6b75b326
commit
067ea4b65b
|
@ -104,6 +104,10 @@ dependencies {
|
||||||
implementation "com.jakewharton:butterknife:$butterKnifeVersion"
|
implementation "com.jakewharton:butterknife:$butterKnifeVersion"
|
||||||
annotationProcessor "com.jakewharton:butterknife-compiler:$butterKnifeVersion"
|
annotationProcessor "com.jakewharton:butterknife-compiler:$butterKnifeVersion"
|
||||||
|
|
||||||
|
// RxBinding
|
||||||
|
implementation 'com.jakewharton.rxbinding4:rxbinding:4.0.0'
|
||||||
|
implementation 'com.jakewharton.rxbinding4:rxbinding-core:4.0.0'
|
||||||
|
|
||||||
// support libraries
|
// support libraries
|
||||||
implementation "androidx.appcompat:appcompat:$appCompatVersion"
|
implementation "androidx.appcompat:appcompat:$appCompatVersion"
|
||||||
implementation 'com.google.android.material:material:1.2.0-alpha03'
|
implementation 'com.google.android.material:material:1.2.0-alpha03'
|
||||||
|
|
|
@ -17,7 +17,9 @@
|
||||||
android:roundIcon="@drawable/ic_mercury_icon"
|
android:roundIcon="@drawable/ic_mercury_icon"
|
||||||
android:supportsRtl="true"
|
android:supportsRtl="true"
|
||||||
android:theme="@style/Theme.Mercury">
|
android:theme="@style/Theme.Mercury">
|
||||||
<activity android:name=".android.ui.ikey.IkeyBackupRestoreActivity"></activity>
|
<activity android:name=".android.crypto.ikey.IkeyBackupRestoreActivity">
|
||||||
|
|
||||||
|
</activity>
|
||||||
<activity
|
<activity
|
||||||
android:name=".android.ui.chat.ChatActivity"
|
android:name=".android.ui.chat.ChatActivity"
|
||||||
android:label="Chat" />
|
android:label="Chat" />
|
||||||
|
@ -35,6 +37,7 @@
|
||||||
android:label="@string/title_activity_settings" />
|
android:label="@string/title_activity_settings" />
|
||||||
<activity android:name=".android.ui.contacts.detail.ContactDetailActivity" />
|
<activity android:name=".android.ui.contacts.detail.ContactDetailActivity" />
|
||||||
<activity android:name=".android.ui.account.detail.AccountDetailsActivity" />
|
<activity android:name=".android.ui.account.detail.AccountDetailsActivity" />
|
||||||
|
<activity android:name=".android.ui.account.login.AddAccountActivity" />
|
||||||
|
|
||||||
<service android:name=".android.service.MercuryForegroundService" />
|
<service android:name=".android.service.MercuryForegroundService" />
|
||||||
</application>
|
</application>
|
||||||
|
|
|
@ -5,7 +5,6 @@ import android.content.Intent;
|
||||||
import android.os.Build;
|
import android.os.Build;
|
||||||
|
|
||||||
import org.jivesoftware.smack.android.AndroidSmackInitializer;
|
import org.jivesoftware.smack.android.AndroidSmackInitializer;
|
||||||
import org.jivesoftware.smackx.ping.android.ServerPingWithAlarmManager;
|
|
||||||
import org.mercury_im.messenger.android.di.component.DaggerAppComponent;
|
import org.mercury_im.messenger.android.di.component.DaggerAppComponent;
|
||||||
import org.mercury_im.messenger.android.util.AndroidLoggingHandler;
|
import org.mercury_im.messenger.android.util.AndroidLoggingHandler;
|
||||||
import org.mercury_im.messenger.core.Messenger;
|
import org.mercury_im.messenger.core.Messenger;
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
package org.mercury_im.messenger.android.ui.ikey;
|
package org.mercury_im.messenger.android.crypto.ikey;
|
||||||
|
|
||||||
import android.graphics.Bitmap;
|
import android.graphics.Bitmap;
|
||||||
|
|
||||||
|
@ -11,6 +11,7 @@ import org.mercury_im.messenger.android.MercuryImApplication;
|
||||||
import org.mercury_im.messenger.android.ui.MercuryAndroidViewModel;
|
import org.mercury_im.messenger.android.ui.MercuryAndroidViewModel;
|
||||||
import org.mercury_im.messenger.android.util.QrCodeGenerator;
|
import org.mercury_im.messenger.android.util.QrCodeGenerator;
|
||||||
import org.mercury_im.messenger.core.SchedulersFacade;
|
import org.mercury_im.messenger.core.SchedulersFacade;
|
||||||
|
import org.mercury_im.messenger.core.crypto.OpenPgpSecretKeyBackupPassphraseGenerator;
|
||||||
import org.mercury_im.messenger.core.util.Optional;
|
import org.mercury_im.messenger.core.util.Optional;
|
||||||
import org.mercury_im.messenger.core.viewmodel.ikey.IkeySecretKeyBackupCreationViewModel;
|
import org.mercury_im.messenger.core.viewmodel.ikey.IkeySecretKeyBackupCreationViewModel;
|
||||||
|
|
||||||
|
@ -22,9 +23,9 @@ import javax.inject.Inject;
|
||||||
|
|
||||||
import io.reactivex.Observable;
|
import io.reactivex.Observable;
|
||||||
|
|
||||||
public class IkeyBackupCreationAndroidViewModel extends ViewModel implements MercuryAndroidViewModel<IkeySecretKeyBackupCreationViewModel> {
|
public class AndroidIkeyBackupCreationViewModel extends ViewModel implements MercuryAndroidViewModel<IkeySecretKeyBackupCreationViewModel> {
|
||||||
|
|
||||||
private static final Logger LOGGER = Logger.getLogger(IkeyBackupCreationAndroidViewModel.class.getName());
|
private static final Logger LOGGER = Logger.getLogger(AndroidIkeyBackupCreationViewModel.class.getName());
|
||||||
|
|
||||||
MutableLiveData<OpenPgpSecretKeyBackupPassphrase> passphrase = new MutableLiveData<>();
|
MutableLiveData<OpenPgpSecretKeyBackupPassphrase> passphrase = new MutableLiveData<>();
|
||||||
MutableLiveData<Bitmap> passphraseAsQrCode = new MutableLiveData<>();
|
MutableLiveData<Bitmap> passphraseAsQrCode = new MutableLiveData<>();
|
||||||
|
@ -32,10 +33,13 @@ public class IkeyBackupCreationAndroidViewModel extends ViewModel implements Mer
|
||||||
@Inject
|
@Inject
|
||||||
IkeySecretKeyBackupCreationViewModel commonViewModel;
|
IkeySecretKeyBackupCreationViewModel commonViewModel;
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
OpenPgpSecretKeyBackupPassphraseGenerator passphraseGenerator;
|
||||||
|
|
||||||
@Inject
|
@Inject
|
||||||
SchedulersFacade schedulers;
|
SchedulersFacade schedulers;
|
||||||
|
|
||||||
public IkeyBackupCreationAndroidViewModel() {
|
public AndroidIkeyBackupCreationViewModel() {
|
||||||
MercuryImApplication.getApplication().getAppComponent().inject(this);
|
MercuryImApplication.getApplication().getAppComponent().inject(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -43,8 +47,8 @@ public class IkeyBackupCreationAndroidViewModel extends ViewModel implements Mer
|
||||||
getCommonViewModel().setAccountId(accountId);
|
getCommonViewModel().setAccountId(accountId);
|
||||||
|
|
||||||
Observable<Optional<OpenPgpSecretKeyBackupPassphrase>> passphraseObservable =
|
Observable<Optional<OpenPgpSecretKeyBackupPassphrase>> passphraseObservable =
|
||||||
//getCommonViewModel().getPassphrase()
|
getCommonViewModel().getPassphrase();
|
||||||
Observable.just(new Optional<>(new OpenPgpSecretKeyBackupPassphrase("71ZA-Y416-UA7A-7NCE-3SNM-88EF")));
|
//Observable.just(new Optional<>(passphraseGenerator.generateBackupPassphrase()));
|
||||||
|
|
||||||
addDisposable(passphraseObservable
|
addDisposable(passphraseObservable
|
||||||
.subscribeOn(schedulers.getIoScheduler())
|
.subscribeOn(schedulers.getIoScheduler())
|
|
@ -1,4 +1,4 @@
|
||||||
package org.mercury_im.messenger.android.ui.ikey;
|
package org.mercury_im.messenger.android.crypto.ikey;
|
||||||
|
|
||||||
import androidx.lifecycle.ViewModelProvider;
|
import androidx.lifecycle.ViewModelProvider;
|
||||||
|
|
||||||
|
@ -23,7 +23,7 @@ import butterknife.ButterKnife;
|
||||||
|
|
||||||
public class IkeyBackupCreationFragment extends Fragment {
|
public class IkeyBackupCreationFragment extends Fragment {
|
||||||
|
|
||||||
private IkeyBackupCreationAndroidViewModel viewModel;
|
private AndroidIkeyBackupCreationViewModel viewModel;
|
||||||
|
|
||||||
@BindView(R.id.backup_code)
|
@BindView(R.id.backup_code)
|
||||||
TextView backupCode;
|
TextView backupCode;
|
||||||
|
@ -52,7 +52,7 @@ public class IkeyBackupCreationFragment extends Fragment {
|
||||||
@Override
|
@Override
|
||||||
public void onActivityCreated(@Nullable Bundle savedInstanceState) {
|
public void onActivityCreated(@Nullable Bundle savedInstanceState) {
|
||||||
super.onActivityCreated(savedInstanceState);
|
super.onActivityCreated(savedInstanceState);
|
||||||
viewModel = new ViewModelProvider(this).get(IkeyBackupCreationAndroidViewModel.class);
|
viewModel = new ViewModelProvider(this).get(AndroidIkeyBackupCreationViewModel.class);
|
||||||
viewModel.initialize(accountId);
|
viewModel.initialize(accountId);
|
||||||
|
|
||||||
viewModel.getPassphrase().observe(getViewLifecycleOwner(), passphrase -> backupCode.setText(passphrase));
|
viewModel.getPassphrase().observe(getViewLifecycleOwner(), passphrase -> backupCode.setText(passphrase));
|
|
@ -1,4 +1,4 @@
|
||||||
package org.mercury_im.messenger.android.ui.ikey;
|
package org.mercury_im.messenger.android.crypto.ikey;
|
||||||
|
|
||||||
import androidx.appcompat.app.AppCompatActivity;
|
import androidx.appcompat.app.AppCompatActivity;
|
||||||
|
|
||||||
|
@ -11,6 +11,6 @@ public class IkeyBackupRestoreActivity extends AppCompatActivity {
|
||||||
@Override
|
@Override
|
||||||
protected void onCreate(Bundle savedInstanceState) {
|
protected void onCreate(Bundle savedInstanceState) {
|
||||||
super.onCreate(savedInstanceState);
|
super.onCreate(savedInstanceState);
|
||||||
setContentView(R.layout.activity_ikey_backup_restore);
|
setContentView(R.layout.fragment_ikey_backup_restore);
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -4,8 +4,12 @@ import org.mercury_im.messenger.android.MercuryImApplication;
|
||||||
import org.mercury_im.messenger.android.di.module.AndroidDatabaseModule;
|
import org.mercury_im.messenger.android.di.module.AndroidDatabaseModule;
|
||||||
import org.mercury_im.messenger.android.di.module.AndroidSchedulersModule;
|
import org.mercury_im.messenger.android.di.module.AndroidSchedulersModule;
|
||||||
import org.mercury_im.messenger.android.ui.account.detail.AndroidAccountDetailsViewModel;
|
import org.mercury_im.messenger.android.ui.account.detail.AndroidAccountDetailsViewModel;
|
||||||
|
import org.mercury_im.messenger.android.ui.account.login.AddAccountActivity;
|
||||||
|
import org.mercury_im.messenger.android.ui.account.login.EnterAccountDetailsFragment;
|
||||||
|
import org.mercury_im.messenger.android.ui.account.login.IkeySetupViewModel;
|
||||||
import org.mercury_im.messenger.android.ui.contacts.AndroidContactListViewModel;
|
import org.mercury_im.messenger.android.ui.contacts.AndroidContactListViewModel;
|
||||||
import org.mercury_im.messenger.android.ui.ikey.IkeyBackupCreationAndroidViewModel;
|
import org.mercury_im.messenger.android.crypto.ikey.AndroidIkeyBackupCreationViewModel;
|
||||||
|
import org.mercury_im.messenger.core.di.module.IkeyModule;
|
||||||
import org.mercury_im.messenger.core.di.module.OpenPgpModule;
|
import org.mercury_im.messenger.core.di.module.OpenPgpModule;
|
||||||
import org.mercury_im.messenger.core.di.module.RxMercuryMessageStoreFactoryModule;
|
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.RxMercuryRosterStoreFactoryModule;
|
||||||
|
@ -50,6 +54,7 @@ import dagger.Component;
|
||||||
XmppTcpConnectionFactoryModule.class,
|
XmppTcpConnectionFactoryModule.class,
|
||||||
RxMercuryMessageStoreFactoryModule.class,
|
RxMercuryMessageStoreFactoryModule.class,
|
||||||
OpenPgpModule.class,
|
OpenPgpModule.class,
|
||||||
|
IkeyModule.class,
|
||||||
RxMercuryRosterStoreFactoryModule.class,
|
RxMercuryRosterStoreFactoryModule.class,
|
||||||
StanzaIdSourceFactoryModule.class
|
StanzaIdSourceFactoryModule.class
|
||||||
})
|
})
|
||||||
|
@ -70,7 +75,7 @@ public interface AppComponent {
|
||||||
|
|
||||||
void inject(ContactDetailActivity contactDetailActivity);
|
void inject(ContactDetailActivity contactDetailActivity);
|
||||||
|
|
||||||
|
void inject(EnterAccountDetailsFragment enterAccountDetailsFragment);
|
||||||
|
|
||||||
// ViewModels
|
// ViewModels
|
||||||
|
|
||||||
|
@ -94,10 +99,13 @@ public interface AppComponent {
|
||||||
|
|
||||||
void inject(AndroidAccountDetailsViewModel accountDetailsViewModel);
|
void inject(AndroidAccountDetailsViewModel accountDetailsViewModel);
|
||||||
|
|
||||||
void inject(IkeyBackupCreationAndroidViewModel ikeyBackupCreationAndroidViewModel);
|
void inject(AndroidIkeyBackupCreationViewModel androidIkeyBackupCreationViewModel);
|
||||||
|
|
||||||
|
void inject(IkeySetupViewModel ikeySetupViewModel);
|
||||||
|
// void inject(AndroidOxSecretKeyBackupRestoreViewModel androidOxSecretKeyBackupRestoreViewModel);
|
||||||
|
|
||||||
|
|
||||||
// Common VMs
|
// Common VMs
|
||||||
void inject(LoginViewModel loginViewModel);
|
void inject(LoginViewModel loginViewModel);
|
||||||
|
|
||||||
void inject(AccountListViewModel accountsViewModel);
|
void inject(AccountListViewModel accountsViewModel);
|
||||||
|
@ -108,4 +116,5 @@ public interface AppComponent {
|
||||||
void inject(MercuryForegroundService service);
|
void inject(MercuryForegroundService service);
|
||||||
|
|
||||||
void inject(MercuryEntityCapsStore store);
|
void inject(MercuryEntityCapsStore store);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -11,11 +11,10 @@ import android.view.View;
|
||||||
import android.view.ViewGroup;
|
import android.view.ViewGroup;
|
||||||
import android.widget.Button;
|
import android.widget.Button;
|
||||||
import android.widget.TextView;
|
import android.widget.TextView;
|
||||||
|
import android.widget.Toast;
|
||||||
|
|
||||||
import androidx.annotation.NonNull;
|
import androidx.annotation.NonNull;
|
||||||
import androidx.annotation.Nullable;
|
import androidx.annotation.Nullable;
|
||||||
import androidx.appcompat.app.AppCompatActivity;
|
|
||||||
import androidx.appcompat.widget.Toolbar;
|
|
||||||
import androidx.fragment.app.Fragment;
|
import androidx.fragment.app.Fragment;
|
||||||
import androidx.lifecycle.ViewModelProvider;
|
import androidx.lifecycle.ViewModelProvider;
|
||||||
import androidx.recyclerview.widget.RecyclerView;
|
import androidx.recyclerview.widget.RecyclerView;
|
||||||
|
@ -24,7 +23,7 @@ import com.google.android.material.card.MaterialCardView;
|
||||||
|
|
||||||
import org.mercury_im.messenger.R;
|
import org.mercury_im.messenger.R;
|
||||||
import org.mercury_im.messenger.android.MercuryImApplication;
|
import org.mercury_im.messenger.android.MercuryImApplication;
|
||||||
import org.mercury_im.messenger.android.ui.ikey.IkeyBackupCreationFragment;
|
import org.mercury_im.messenger.android.crypto.ikey.IkeyBackupCreationFragment;
|
||||||
import org.mercury_im.messenger.android.ui.openpgp.ToggleableFingerprintsAdapter;
|
import org.mercury_im.messenger.android.ui.openpgp.ToggleableFingerprintsAdapter;
|
||||||
import org.mercury_im.messenger.android.ui.openpgp.OpenPgpV4FingerprintFormatter;
|
import org.mercury_im.messenger.android.ui.openpgp.OpenPgpV4FingerprintFormatter;
|
||||||
import org.mercury_im.messenger.core.util.Optional;
|
import org.mercury_im.messenger.core.util.Optional;
|
||||||
|
@ -46,6 +45,9 @@ public class AccountDetailsFragment extends Fragment {
|
||||||
@BindView(R.id.jid)
|
@BindView(R.id.jid)
|
||||||
TextView jid;
|
TextView jid;
|
||||||
|
|
||||||
|
@BindView(R.id.btn_backup)
|
||||||
|
Button localKeyCreateBackupButton;
|
||||||
|
|
||||||
@BindView(R.id.btn_share)
|
@BindView(R.id.btn_share)
|
||||||
Button localFingerprintShareButton;
|
Button localFingerprintShareButton;
|
||||||
|
|
||||||
|
@ -154,6 +156,15 @@ public class AccountDetailsFragment extends Fragment {
|
||||||
getParentFragmentManager().beginTransaction()
|
getParentFragmentManager().beginTransaction()
|
||||||
.replace(R.id.fragment, IkeyBackupCreationFragment.newInstance(accountId)).commit();
|
.replace(R.id.fragment, IkeyBackupCreationFragment.newInstance(accountId)).commit();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
localKeyCreateBackupButton.setOnClickListener(v -> {
|
||||||
|
Toast.makeText(getContext(), "Not yet implemented.", Toast.LENGTH_SHORT).show();
|
||||||
|
});
|
||||||
|
|
||||||
|
viewModel.isAccountAuthenticated().observe(this, authenticated -> {
|
||||||
|
ikeyCreateBackupButton.setEnabled(authenticated);
|
||||||
|
localKeyCreateBackupButton.setEnabled(authenticated);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
private void startShareFingerprintIntent(OpenPgpV4Fingerprint fingerprint) {
|
private void startShareFingerprintIntent(OpenPgpV4Fingerprint fingerprint) {
|
||||||
|
|
|
@ -18,6 +18,7 @@ import org.mercury_im.messenger.core.util.DefaultUtil;
|
||||||
import org.mercury_im.messenger.core.util.Optional;
|
import org.mercury_im.messenger.core.util.Optional;
|
||||||
import org.mercury_im.messenger.core.viewmodel.account.detail.AccountDetailsViewModel;
|
import org.mercury_im.messenger.core.viewmodel.account.detail.AccountDetailsViewModel;
|
||||||
import org.mercury_im.messenger.core.viewmodel.openpgp.FingerprintViewItem;
|
import org.mercury_im.messenger.core.viewmodel.openpgp.FingerprintViewItem;
|
||||||
|
import org.mercury_im.messenger.entity.Account;
|
||||||
import org.pgpainless.key.OpenPgpV4Fingerprint;
|
import org.pgpainless.key.OpenPgpV4Fingerprint;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
@ -46,6 +47,8 @@ public class AndroidAccountDetailsViewModel extends AndroidViewModel implements
|
||||||
private MutableLiveData<OpenPgpV4Fingerprint> localFingerprint = new MutableLiveData<>();
|
private MutableLiveData<OpenPgpV4Fingerprint> localFingerprint = new MutableLiveData<>();
|
||||||
private MutableLiveData<List<FingerprintViewItem>> remoteFingerprints = new MutableLiveData<>(new ArrayList<>());
|
private MutableLiveData<List<FingerprintViewItem>> remoteFingerprints = new MutableLiveData<>(new ArrayList<>());
|
||||||
private MutableLiveData<EntityBareJid> jid = new MutableLiveData<>(DefaultUtil.defaultJid());
|
private MutableLiveData<EntityBareJid> jid = new MutableLiveData<>(DefaultUtil.defaultJid());
|
||||||
|
private MutableLiveData<Boolean> accountEnabled = new MutableLiveData<>(false);
|
||||||
|
private MutableLiveData<Boolean> accountAuthenticated = new MutableLiveData<>(false);
|
||||||
|
|
||||||
public AndroidAccountDetailsViewModel(@NonNull Application application, UUID accountId) {
|
public AndroidAccountDetailsViewModel(@NonNull Application application, UUID accountId) {
|
||||||
super(application);
|
super(application);
|
||||||
|
@ -75,6 +78,18 @@ public class AndroidAccountDetailsViewModel extends AndroidViewModel implements
|
||||||
() -> LOGGER.log(Level.INFO, "observing remote fingerprint onComplete.")));
|
() -> LOGGER.log(Level.INFO, "observing remote fingerprint onComplete.")));
|
||||||
|
|
||||||
addDisposable(getCommonViewModel().getJid(accountId).subscribe(jid::postValue));
|
addDisposable(getCommonViewModel().getJid(accountId).subscribe(jid::postValue));
|
||||||
|
|
||||||
|
addDisposable(getCommonViewModel().isAccountEnabled(accountId)
|
||||||
|
.compose(schedulers.executeUiSafeObservable())
|
||||||
|
.subscribe(bool -> accountEnabled.postValue(bool),
|
||||||
|
e -> LOGGER.log(Level.SEVERE, "Error subscribing to account enabled state", e),
|
||||||
|
() -> LOGGER.log(Level.INFO, "observing account enabled state onComplete.")));
|
||||||
|
|
||||||
|
addDisposable(getCommonViewModel().isAccountAuthenticated(accountId)
|
||||||
|
.compose(schedulers.executeUiSafeObservable())
|
||||||
|
.subscribe(bool -> accountAuthenticated.postValue(bool),
|
||||||
|
e -> LOGGER.log(Level.SEVERE, "Error subscribing to account authenticated state", e),
|
||||||
|
() -> LOGGER.log(Level.INFO, "observing account authenticated state onComplete.")));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -112,10 +127,10 @@ public class AndroidAccountDetailsViewModel extends AndroidViewModel implements
|
||||||
|
|
||||||
public void onGenerateIkey() {
|
public void onGenerateIkey() {
|
||||||
addDisposable(getCommonViewModel().generateIkey(accountId)
|
addDisposable(getCommonViewModel().generateIkey(accountId)
|
||||||
.subscribeOn(schedulers.getNewThread())
|
.subscribeOn(schedulers.getNewThread())
|
||||||
.observeOn(schedulers.getUiScheduler())
|
.observeOn(schedulers.getUiScheduler())
|
||||||
.subscribe(() -> LOGGER.log(Level.INFO, "IKey generated for account " + accountId),
|
.subscribe(() -> LOGGER.log(Level.INFO, "IKey generated for account " + accountId),
|
||||||
e -> LOGGER.log(Level.SEVERE, "Could not generate Ikey", e)));
|
e -> LOGGER.log(Level.SEVERE, "Could not generate Ikey", e)));
|
||||||
}
|
}
|
||||||
|
|
||||||
public void onDeleteIkey() {
|
public void onDeleteIkey() {
|
||||||
|
@ -134,6 +149,14 @@ public class AndroidAccountDetailsViewModel extends AndroidViewModel implements
|
||||||
e -> LOGGER.log(Level.SEVERE, "Could not restore Ikey backup", e)));
|
e -> LOGGER.log(Level.SEVERE, "Could not restore Ikey backup", e)));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public LiveData<Boolean> isAccountEnabled() {
|
||||||
|
return accountEnabled;
|
||||||
|
}
|
||||||
|
|
||||||
|
public LiveData<Boolean> isAccountAuthenticated() {
|
||||||
|
return accountAuthenticated;
|
||||||
|
}
|
||||||
|
|
||||||
public static class AndroidAccountDetailsViewModelFactory implements ViewModelProvider.Factory {
|
public static class AndroidAccountDetailsViewModelFactory implements ViewModelProvider.Factory {
|
||||||
|
|
||||||
private final Application application;
|
private final Application application;
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
package org.mercury_im.messenger.android.ui.account.list;
|
package org.mercury_im.messenger.android.ui.account.list;
|
||||||
|
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
|
import android.content.Intent;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
import android.view.LayoutInflater;
|
import android.view.LayoutInflater;
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
|
@ -16,6 +17,7 @@ import com.google.android.material.floatingactionbutton.ExtendedFloatingActionBu
|
||||||
|
|
||||||
import org.mercury_im.messenger.R;
|
import org.mercury_im.messenger.R;
|
||||||
import org.mercury_im.messenger.android.ui.account.OnAccountListItemClickListener;
|
import org.mercury_im.messenger.android.ui.account.OnAccountListItemClickListener;
|
||||||
|
import org.mercury_im.messenger.android.ui.account.login.AddAccountActivity;
|
||||||
import org.mercury_im.messenger.android.ui.account.login.AddAccountDialogFragment;
|
import org.mercury_im.messenger.android.ui.account.login.AddAccountDialogFragment;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
@ -58,7 +60,10 @@ public class AccountListFragment extends Fragment implements SearchView.OnQueryT
|
||||||
public void onResume() {
|
public void onResume() {
|
||||||
super.onResume();
|
super.onResume();
|
||||||
observeViewModel();
|
observeViewModel();
|
||||||
fab.setOnClickListener(v -> displayAddAccountDialog());
|
//fab.setOnClickListener(v -> displayAddAccountDialog());
|
||||||
|
fab.setOnClickListener(v -> {
|
||||||
|
startActivity(new Intent(getContext(), AddAccountActivity.class));
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
private void observeViewModel() {
|
private void observeViewModel() {
|
||||||
|
|
|
@ -13,6 +13,7 @@ import androidx.recyclerview.widget.RecyclerView;
|
||||||
import org.jetbrains.annotations.NotNull;
|
import org.jetbrains.annotations.NotNull;
|
||||||
import org.mercury_im.messenger.R;
|
import org.mercury_im.messenger.R;
|
||||||
import org.mercury_im.messenger.android.ui.account.OnAccountListItemClickListener;
|
import org.mercury_im.messenger.android.ui.account.OnAccountListItemClickListener;
|
||||||
|
import org.mercury_im.messenger.core.connection.state.ConnectivityState;
|
||||||
import org.mercury_im.messenger.core.viewmodel.account.list.AccountViewItem;
|
import org.mercury_im.messenger.core.viewmodel.account.list.AccountViewItem;
|
||||||
import org.mercury_im.messenger.entity.Account;
|
import org.mercury_im.messenger.entity.Account;
|
||||||
import org.mercury_im.messenger.android.ui.avatar.AvatarDrawable;
|
import org.mercury_im.messenger.android.ui.avatar.AvatarDrawable;
|
||||||
|
@ -62,8 +63,9 @@ public class AccountListRecyclerViewAdapter extends RecyclerView.Adapter<Account
|
||||||
holder.jid.setText(account.getAddress());
|
holder.jid.setText(account.getAddress());
|
||||||
holder.avatar.setImageDrawable(new AvatarDrawable(account.getAddress(), account.getAddress()));
|
holder.avatar.setImageDrawable(new AvatarDrawable(account.getAddress(), account.getAddress()));
|
||||||
holder.enabled.setChecked(account.isEnabled());
|
holder.enabled.setChecked(account.isEnabled());
|
||||||
holder.enabled.setOnCheckedChangeListener((compoundButton, checked) -> {
|
holder.enabled.setEnabled(shouldSwitchBeEnabled(viewItem.getConnectivityState()));
|
||||||
if (!compoundButton.isPressed()) {
|
holder.enabled.setOnCheckedChangeListener((switch_, checked) -> {
|
||||||
|
if (!switch_.isPressed()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
viewModel.setAccountEnabled(account, checked);
|
viewModel.setAccountEnabled(account, checked);
|
||||||
|
@ -78,6 +80,12 @@ public class AccountListRecyclerViewAdapter extends RecyclerView.Adapter<Account
|
||||||
holder.mView.setOnClickListener(v -> onAccountClickListener.onAccountListItemClick(account));
|
holder.mView.setOnClickListener(v -> onAccountClickListener.onAccountListItemClick(account));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static boolean shouldSwitchBeEnabled(ConnectivityState connectivity) {
|
||||||
|
return connectivity == ConnectivityState.authenticated ||
|
||||||
|
connectivity == ConnectivityState.disconnected ||
|
||||||
|
connectivity == ConnectivityState.disconnectedOnError;
|
||||||
|
}
|
||||||
|
|
||||||
class ViewHolder extends RecyclerView.ViewHolder {
|
class ViewHolder extends RecyclerView.ViewHolder {
|
||||||
final View mView;
|
final View mView;
|
||||||
final ImageView avatar;
|
final ImageView avatar;
|
||||||
|
|
|
@ -0,0 +1,109 @@
|
||||||
|
package org.mercury_im.messenger.android.ui.account.login;
|
||||||
|
|
||||||
|
import android.os.Bundle;
|
||||||
|
|
||||||
|
import androidx.annotation.NonNull;
|
||||||
|
import androidx.annotation.Nullable;
|
||||||
|
import androidx.appcompat.app.AppCompatActivity;
|
||||||
|
import androidx.fragment.app.Fragment;
|
||||||
|
import androidx.fragment.app.FragmentActivity;
|
||||||
|
import androidx.lifecycle.ViewModelProvider;
|
||||||
|
import androidx.viewpager2.adapter.FragmentStateAdapter;
|
||||||
|
import androidx.viewpager2.widget.ViewPager2;
|
||||||
|
|
||||||
|
import org.mercury_im.messenger.R;
|
||||||
|
import org.mercury_im.messenger.android.MercuryImApplication;
|
||||||
|
import org.mercury_im.messenger.android.crypto.ikey.IkeyBackupCreationFragment;
|
||||||
|
import org.mercury_im.messenger.android.di.component.AppComponent;
|
||||||
|
import org.mercury_im.messenger.core.util.Optional;
|
||||||
|
import org.mercury_im.messenger.entity.Account;
|
||||||
|
|
||||||
|
import java.util.LinkedHashMap;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.UUID;
|
||||||
|
|
||||||
|
import butterknife.BindView;
|
||||||
|
import butterknife.ButterKnife;
|
||||||
|
import lombok.Getter;
|
||||||
|
|
||||||
|
public class AddAccountActivity extends AppCompatActivity {
|
||||||
|
|
||||||
|
@BindView(R.id.viewpager)
|
||||||
|
ViewPager2 viewPager;
|
||||||
|
|
||||||
|
private SetupPagerAdapter pagerAdapter;
|
||||||
|
|
||||||
|
private AppComponent appComponent;
|
||||||
|
private IkeySetupViewModel ikeyViewModel;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onCreate(@Nullable Bundle savedInstanceState) {
|
||||||
|
super.onCreate(savedInstanceState);
|
||||||
|
setContentView(R.layout.layout_viewpager2);
|
||||||
|
ButterKnife.bind(this);
|
||||||
|
appComponent = MercuryImApplication.getApplication().getAppComponent();
|
||||||
|
|
||||||
|
pagerAdapter = new SetupPagerAdapter(this);
|
||||||
|
viewPager.setAdapter(pagerAdapter);
|
||||||
|
viewPager.setUserInputEnabled(false); // disable swiping
|
||||||
|
|
||||||
|
ikeyViewModel = new ViewModelProvider(this).get(IkeySetupViewModel.class); // shared between fragments
|
||||||
|
}
|
||||||
|
|
||||||
|
public void loginFinished(Optional<Account> optionalAccount) {
|
||||||
|
if (optionalAccount.isPresent()) {
|
||||||
|
pagerAdapter.getFragments().put(1, IkeySetupFragment.newInstance(optionalAccount.getItem().getId()));
|
||||||
|
pagerAdapter.notifyDataSetChanged();
|
||||||
|
viewPager.setCurrentItem(1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void skipIkeySetup() {
|
||||||
|
finish();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setupIkey(UUID accountId) {
|
||||||
|
int pos = pagerAdapter.getItemCount();
|
||||||
|
pagerAdapter.getFragments().put(pos, IkeyBackupRestoreOrSkipFragment.newInstance(accountId));
|
||||||
|
pagerAdapter.notifyDataSetChanged();
|
||||||
|
viewPager.setCurrentItem(pos);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void restoreIkeyBackup(UUID accountId) {
|
||||||
|
int pos = pagerAdapter.getItemCount();
|
||||||
|
pagerAdapter.getFragments().put(pos, IkeyBackupRestoreSuccessfulFragment.newInstance(accountId));
|
||||||
|
pagerAdapter.notifyDataSetChanged();
|
||||||
|
viewPager.setCurrentItem(pos);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void generateIkeyBackup(UUID accountId) {
|
||||||
|
int pos = pagerAdapter.getItemCount();
|
||||||
|
pagerAdapter.getFragments().put(pos, IkeyBackupCreationFragment.newInstance(accountId));
|
||||||
|
pagerAdapter.notifyDataSetChanged();
|
||||||
|
viewPager.setCurrentItem(pos);
|
||||||
|
}
|
||||||
|
|
||||||
|
private class SetupPagerAdapter extends FragmentStateAdapter {
|
||||||
|
|
||||||
|
@Getter
|
||||||
|
private final Map<Integer, Fragment> fragments = new LinkedHashMap<>();
|
||||||
|
|
||||||
|
SetupPagerAdapter(@NonNull FragmentActivity fragmentActivity) {
|
||||||
|
super(fragmentActivity);
|
||||||
|
|
||||||
|
fragments.put(0, EnterAccountDetailsFragment.newInstance(appComponent));
|
||||||
|
}
|
||||||
|
|
||||||
|
@NonNull
|
||||||
|
@Override
|
||||||
|
public Fragment createFragment(int position) {
|
||||||
|
return fragments.get(position);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getItemCount() {
|
||||||
|
return fragments.size();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -44,7 +44,7 @@ public class AddAccountDialogFragment extends AppCompatDialogFragment {
|
||||||
@Override
|
@Override
|
||||||
public Dialog onCreateDialog(@Nullable Bundle savedInstanceState) {
|
public Dialog onCreateDialog(@Nullable Bundle savedInstanceState) {
|
||||||
LayoutInflater inflater = requireActivity().getLayoutInflater();
|
LayoutInflater inflater = requireActivity().getLayoutInflater();
|
||||||
View dialogView = inflater.inflate(R.layout.dialog_login, null);
|
View dialogView = inflater.inflate(R.layout.view_account_credentials, null);
|
||||||
ButterKnife.bind(this, dialogView);
|
ButterKnife.bind(this, dialogView);
|
||||||
|
|
||||||
AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
|
AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
|
||||||
|
@ -83,8 +83,8 @@ public class AddAccountDialogFragment extends AppCompatDialogFragment {
|
||||||
viewModel.getLoginPasswordError().observe(this, error -> passwordLayout.setError(error));
|
viewModel.getLoginPasswordError().observe(this, error -> passwordLayout.setError(error));
|
||||||
viewModel.isLoginButtonEnabled().observe(this, positiveButton::setEnabled);
|
viewModel.isLoginButtonEnabled().observe(this, positiveButton::setEnabled);
|
||||||
|
|
||||||
viewModel.isLoginFinished().observe(this, finished -> {
|
viewModel.isLoginFinished().observe(this, optAccount -> {
|
||||||
if (finished) {
|
if (optAccount.isPresent()) {
|
||||||
dismiss();
|
dismiss();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
|
@ -14,6 +14,7 @@ import org.mercury_im.messenger.core.account.error.PasswordError;
|
||||||
import org.mercury_im.messenger.core.account.error.UsernameError;
|
import org.mercury_im.messenger.core.account.error.UsernameError;
|
||||||
import org.mercury_im.messenger.core.util.Optional;
|
import org.mercury_im.messenger.core.util.Optional;
|
||||||
import org.mercury_im.messenger.core.viewmodel.account.LoginViewModel;
|
import org.mercury_im.messenger.core.viewmodel.account.LoginViewModel;
|
||||||
|
import org.mercury_im.messenger.entity.Account;
|
||||||
|
|
||||||
import javax.inject.Inject;
|
import javax.inject.Inject;
|
||||||
|
|
||||||
|
@ -24,7 +25,7 @@ public class AndroidLoginViewModel extends AndroidViewModel implements MercuryAn
|
||||||
private final MutableLiveData<String> loginUsernameError = new MutableLiveData<>();
|
private final MutableLiveData<String> loginUsernameError = new MutableLiveData<>();
|
||||||
private final MutableLiveData<String> loginPasswordError = new MutableLiveData<>();
|
private final MutableLiveData<String> loginPasswordError = new MutableLiveData<>();
|
||||||
private final MutableLiveData<Boolean> loginButtonEnabled = new MutableLiveData<>(true);
|
private final MutableLiveData<Boolean> loginButtonEnabled = new MutableLiveData<>(true);
|
||||||
private final MutableLiveData<Boolean> loginFinished = new MutableLiveData<>(false);
|
private final MutableLiveData<Optional<Account>> loginFinished = new MutableLiveData<>(new Optional<>());
|
||||||
|
|
||||||
@Inject
|
@Inject
|
||||||
LoginViewModel commonViewModel;
|
LoginViewModel commonViewModel;
|
||||||
|
@ -99,8 +100,8 @@ public class AndroidLoginViewModel extends AndroidViewModel implements MercuryAn
|
||||||
getCommonViewModel().dispose();
|
getCommonViewModel().dispose();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void onLoginButtonClicked() {
|
public Account onLoginButtonClicked() {
|
||||||
getCommonViewModel().login();
|
return getCommonViewModel().login();
|
||||||
}
|
}
|
||||||
|
|
||||||
public LiveData<String> getLoginUsernameError() {
|
public LiveData<String> getLoginUsernameError() {
|
||||||
|
@ -115,7 +116,7 @@ public class AndroidLoginViewModel extends AndroidViewModel implements MercuryAn
|
||||||
return loginButtonEnabled;
|
return loginButtonEnabled;
|
||||||
}
|
}
|
||||||
|
|
||||||
public LiveData<Boolean> isLoginFinished() {
|
public LiveData<Optional<Account>> isLoginFinished() {
|
||||||
return loginFinished;
|
return loginFinished;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,117 @@
|
||||||
|
package org.mercury_im.messenger.android.ui.account.login;
|
||||||
|
|
||||||
|
import android.os.Bundle;
|
||||||
|
import android.view.KeyEvent;
|
||||||
|
import android.view.LayoutInflater;
|
||||||
|
import android.view.View;
|
||||||
|
import android.view.ViewGroup;
|
||||||
|
import android.view.inputmethod.EditorInfo;
|
||||||
|
import android.widget.Button;
|
||||||
|
import android.widget.ProgressBar;
|
||||||
|
import android.widget.TextView;
|
||||||
|
|
||||||
|
import androidx.annotation.NonNull;
|
||||||
|
import androidx.annotation.Nullable;
|
||||||
|
import androidx.fragment.app.Fragment;
|
||||||
|
|
||||||
|
import com.google.android.material.textfield.TextInputEditText;
|
||||||
|
import com.google.android.material.textfield.TextInputLayout;
|
||||||
|
|
||||||
|
import org.mercury_im.messenger.R;
|
||||||
|
import org.mercury_im.messenger.android.MercuryImApplication;
|
||||||
|
import org.mercury_im.messenger.android.di.component.AppComponent;
|
||||||
|
|
||||||
|
import javax.inject.Inject;
|
||||||
|
|
||||||
|
import butterknife.BindView;
|
||||||
|
import butterknife.ButterKnife;
|
||||||
|
|
||||||
|
public class EnterAccountDetailsFragment extends Fragment {
|
||||||
|
|
||||||
|
@BindView(R.id.username_layout)
|
||||||
|
TextInputLayout usernameLayout;
|
||||||
|
|
||||||
|
@BindView(R.id.username)
|
||||||
|
TextInputEditText username;
|
||||||
|
|
||||||
|
@BindView(R.id.password_layout)
|
||||||
|
TextInputLayout passwordLayout;
|
||||||
|
|
||||||
|
@BindView(R.id.password)
|
||||||
|
TextInputEditText password;
|
||||||
|
|
||||||
|
@BindView(R.id.btn_login)
|
||||||
|
Button loginButton;
|
||||||
|
|
||||||
|
@BindView(R.id.btn_cancel)
|
||||||
|
Button cancelButton;
|
||||||
|
|
||||||
|
@BindView(R.id.progress)
|
||||||
|
ProgressBar progressBar;
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
AndroidLoginViewModel viewModel;
|
||||||
|
|
||||||
|
public EnterAccountDetailsFragment(AppComponent appComponent) {
|
||||||
|
appComponent.inject(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
@Override
|
||||||
|
public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
|
||||||
|
View view = inflater.inflate(R.layout.fragment_enter_account_credentials, container, false);
|
||||||
|
ButterKnife.bind(this, view);
|
||||||
|
return view;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
|
||||||
|
super.onViewCreated(view, savedInstanceState);
|
||||||
|
viewModel = new AndroidLoginViewModel(MercuryImApplication.getApplication());
|
||||||
|
|
||||||
|
loginButton.setOnClickListener(v -> viewModel.onLoginButtonClicked());
|
||||||
|
|
||||||
|
cancelButton.setOnClickListener(v -> getActivity().finish());
|
||||||
|
|
||||||
|
viewModel.getLoginUsernameError().observe(this, error -> usernameLayout.setError(error));
|
||||||
|
viewModel.getLoginPasswordError().observe(this, error -> passwordLayout.setError(error));
|
||||||
|
viewModel.isLoginButtonEnabled().observe(this, loginButton::setEnabled);
|
||||||
|
viewModel.isLoginButtonEnabled().observe(this, enabled ->
|
||||||
|
progressBar.setVisibility(enabled ? View.GONE : View.VISIBLE));
|
||||||
|
|
||||||
|
viewModel.isLoginFinished().observe(this, optAccount ->
|
||||||
|
((AddAccountActivity) getActivity()).loginFinished(optAccount));
|
||||||
|
|
||||||
|
username.addTextChangedListener(viewModel.getUsernameTextChangedListener());
|
||||||
|
password.addTextChangedListener(viewModel.getPasswordTextChangedListener());
|
||||||
|
|
||||||
|
username.setOnEditorActionListener(focusPasswordFieldOnEnterPressed);
|
||||||
|
password.setOnEditorActionListener(loginOnEnterPressed);
|
||||||
|
}
|
||||||
|
|
||||||
|
private final TextView.OnEditorActionListener focusPasswordFieldOnEnterPressed = new TextView.OnEditorActionListener() {
|
||||||
|
@Override
|
||||||
|
public boolean onEditorAction(TextView v, int actionId, KeyEvent event) {
|
||||||
|
if (actionId == EditorInfo.IME_ACTION_NEXT) {
|
||||||
|
password.requestFocus();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
private final TextView.OnEditorActionListener loginOnEnterPressed = new TextView.OnEditorActionListener() {
|
||||||
|
@Override
|
||||||
|
public boolean onEditorAction(TextView v, int actionId, KeyEvent event) {
|
||||||
|
if (actionId == EditorInfo.IME_ACTION_DONE || actionId == EditorInfo.IME_NULL) {
|
||||||
|
viewModel.onLoginButtonClicked();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
public static EnterAccountDetailsFragment newInstance(AppComponent appComponent) {
|
||||||
|
return new EnterAccountDetailsFragment(appComponent);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,68 @@
|
||||||
|
package org.mercury_im.messenger.android.ui.account.login;
|
||||||
|
|
||||||
|
import android.content.Context;
|
||||||
|
import android.os.Bundle;
|
||||||
|
import android.view.LayoutInflater;
|
||||||
|
import android.view.View;
|
||||||
|
import android.view.ViewGroup;
|
||||||
|
import android.widget.Button;
|
||||||
|
import android.widget.EditText;
|
||||||
|
import android.widget.ImageButton;
|
||||||
|
|
||||||
|
import androidx.annotation.NonNull;
|
||||||
|
import androidx.annotation.Nullable;
|
||||||
|
import androidx.fragment.app.Fragment;
|
||||||
|
import androidx.lifecycle.ViewModelProvider;
|
||||||
|
|
||||||
|
import org.mercury_im.messenger.R;
|
||||||
|
|
||||||
|
import java.util.UUID;
|
||||||
|
|
||||||
|
import butterknife.BindView;
|
||||||
|
import butterknife.ButterKnife;
|
||||||
|
|
||||||
|
public class IkeyBackupRestoreOrSkipFragment extends Fragment {
|
||||||
|
|
||||||
|
@BindView(R.id.btn_restore)
|
||||||
|
Button restoreButton;
|
||||||
|
|
||||||
|
@BindView(R.id.btn_new_key)
|
||||||
|
Button regenerateButton;
|
||||||
|
|
||||||
|
@BindView(R.id.edit_backup_code)
|
||||||
|
EditText backupCodeEditText;
|
||||||
|
|
||||||
|
@BindView(R.id.btn_scan)
|
||||||
|
ImageButton scanButton;
|
||||||
|
|
||||||
|
private final UUID accountId;
|
||||||
|
|
||||||
|
private IkeySetupViewModel viewModel;
|
||||||
|
|
||||||
|
IkeyBackupRestoreOrSkipFragment(UUID accountId) {
|
||||||
|
this.accountId = accountId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static IkeyBackupRestoreOrSkipFragment newInstance(UUID accountId) {
|
||||||
|
return new IkeyBackupRestoreOrSkipFragment(accountId);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
@Override
|
||||||
|
public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
|
||||||
|
View view = inflater.inflate(R.layout.fragment_ikey_backup_restore, container, false);
|
||||||
|
ButterKnife.bind(this, view);
|
||||||
|
return view;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
|
||||||
|
super.onViewCreated(view, savedInstanceState);
|
||||||
|
viewModel = new ViewModelProvider(requireActivity()).get(IkeySetupViewModel.class);
|
||||||
|
|
||||||
|
restoreButton.setOnClickListener(v ->
|
||||||
|
((AddAccountActivity) getActivity()).restoreIkeyBackup(accountId));
|
||||||
|
regenerateButton.setOnClickListener(v ->
|
||||||
|
((AddAccountActivity) getActivity()).generateIkeyBackup(accountId));
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,56 @@
|
||||||
|
package org.mercury_im.messenger.android.ui.account.login;
|
||||||
|
|
||||||
|
import android.os.Bundle;
|
||||||
|
import android.view.LayoutInflater;
|
||||||
|
import android.view.View;
|
||||||
|
import android.view.ViewGroup;
|
||||||
|
import android.widget.Button;
|
||||||
|
import android.widget.TextView;
|
||||||
|
|
||||||
|
import androidx.annotation.NonNull;
|
||||||
|
import androidx.annotation.Nullable;
|
||||||
|
import androidx.fragment.app.Fragment;
|
||||||
|
import androidx.lifecycle.ViewModelProvider;
|
||||||
|
|
||||||
|
import org.mercury_im.messenger.R;
|
||||||
|
|
||||||
|
import java.util.UUID;
|
||||||
|
|
||||||
|
import butterknife.BindView;
|
||||||
|
import butterknife.ButterKnife;
|
||||||
|
|
||||||
|
public class IkeyBackupRestoreSuccessfulFragment extends Fragment {
|
||||||
|
|
||||||
|
@BindView(R.id.btn_done)
|
||||||
|
Button doneButton;
|
||||||
|
|
||||||
|
@BindView(R.id.text)
|
||||||
|
TextView fingerprint;
|
||||||
|
|
||||||
|
private final UUID accountId;
|
||||||
|
private IkeySetupViewModel viewModel;
|
||||||
|
|
||||||
|
IkeyBackupRestoreSuccessfulFragment(UUID accountId) {
|
||||||
|
this.accountId = accountId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static IkeyBackupRestoreSuccessfulFragment newInstance(UUID accountId) {
|
||||||
|
return new IkeyBackupRestoreSuccessfulFragment(accountId);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
@Override
|
||||||
|
public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
|
||||||
|
View view = inflater.inflate(R.layout.fragment_ikey_backup_restore_success, container);
|
||||||
|
ButterKnife.bind(this, view);
|
||||||
|
return view;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
|
||||||
|
super.onViewCreated(view, savedInstanceState);
|
||||||
|
viewModel = new ViewModelProvider(requireActivity()).get(IkeySetupViewModel.class);
|
||||||
|
|
||||||
|
doneButton.setOnClickListener(v -> getActivity().finish());
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,74 @@
|
||||||
|
package org.mercury_im.messenger.android.ui.account.login;
|
||||||
|
|
||||||
|
import android.content.Context;
|
||||||
|
import android.os.Bundle;
|
||||||
|
import android.view.LayoutInflater;
|
||||||
|
import android.view.View;
|
||||||
|
import android.view.ViewGroup;
|
||||||
|
import android.widget.Button;
|
||||||
|
|
||||||
|
import androidx.annotation.NonNull;
|
||||||
|
import androidx.annotation.Nullable;
|
||||||
|
import androidx.fragment.app.Fragment;
|
||||||
|
import androidx.lifecycle.ViewModelProvider;
|
||||||
|
|
||||||
|
import org.mercury_im.messenger.R;
|
||||||
|
|
||||||
|
import java.util.UUID;
|
||||||
|
|
||||||
|
import butterknife.BindView;
|
||||||
|
import butterknife.ButterKnife;
|
||||||
|
import io.reactivex.android.schedulers.AndroidSchedulers;
|
||||||
|
import io.reactivex.schedulers.Schedulers;
|
||||||
|
|
||||||
|
public class IkeySetupFragment extends Fragment {
|
||||||
|
|
||||||
|
@BindView(R.id.btn_skip)
|
||||||
|
Button skipButton;
|
||||||
|
|
||||||
|
@BindView(R.id.btn_continue)
|
||||||
|
Button continueButton;
|
||||||
|
|
||||||
|
private final UUID accountId;
|
||||||
|
private IkeySetupViewModel viewModel;
|
||||||
|
|
||||||
|
public IkeySetupFragment(UUID accountId) {
|
||||||
|
this.accountId = accountId;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
@Override
|
||||||
|
public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
|
||||||
|
View view = inflater.inflate(R.layout.fragment_ikey_setup, container, false);
|
||||||
|
ButterKnife.bind(this, view);
|
||||||
|
return view;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static IkeySetupFragment newInstance(UUID accountId) {
|
||||||
|
return new IkeySetupFragment(accountId);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
|
||||||
|
super.onViewCreated(view, savedInstanceState);
|
||||||
|
viewModel = new ViewModelProvider(requireActivity()).get(IkeySetupViewModel.class);
|
||||||
|
viewModel.init(accountId);
|
||||||
|
|
||||||
|
skipButton.setOnClickListener(v ->
|
||||||
|
getActivity().finish());
|
||||||
|
|
||||||
|
continueButton.setOnClickListener(v -> {
|
||||||
|
viewModel.fetchBackupElement()
|
||||||
|
.subscribeOn(Schedulers.io())
|
||||||
|
.observeOn(AndroidSchedulers.mainThread())
|
||||||
|
.doOnSuccess(opt -> {
|
||||||
|
if (opt.isPresent()) {
|
||||||
|
((AddAccountActivity) getActivity()).setupIkey(accountId);
|
||||||
|
} else {
|
||||||
|
((AddAccountActivity) getActivity()).generateIkeyBackup(accountId);
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.subscribe();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,73 @@
|
||||||
|
package org.mercury_im.messenger.android.ui.account.login;
|
||||||
|
|
||||||
|
import android.app.Application;
|
||||||
|
|
||||||
|
import androidx.annotation.NonNull;
|
||||||
|
import androidx.lifecycle.AndroidViewModel;
|
||||||
|
|
||||||
|
import org.jivesoftware.smack.SmackException;
|
||||||
|
import org.jivesoftware.smack.XMPPException;
|
||||||
|
import org.jivesoftware.smackx.ikey.IkeyManager;
|
||||||
|
import org.jivesoftware.smackx.ox.element.SecretkeyElement;
|
||||||
|
import org.jivesoftware.smackx.pubsub.PubSubException;
|
||||||
|
import org.mercury_im.messenger.android.MercuryImApplication;
|
||||||
|
import org.mercury_im.messenger.core.connection.MercuryConnection;
|
||||||
|
import org.mercury_im.messenger.core.connection.MercuryConnectionManager;
|
||||||
|
import org.mercury_im.messenger.core.crypto.ikey.IkeyInitializer;
|
||||||
|
import org.mercury_im.messenger.core.util.Optional;
|
||||||
|
|
||||||
|
import java.util.UUID;
|
||||||
|
|
||||||
|
import javax.inject.Inject;
|
||||||
|
|
||||||
|
import io.reactivex.Maybe;
|
||||||
|
import io.reactivex.MaybeObserver;
|
||||||
|
import io.reactivex.Single;
|
||||||
|
|
||||||
|
public class IkeySetupViewModel extends AndroidViewModel {
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
MercuryConnectionManager connectionManager;
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
IkeyInitializer ikeyInitializer;
|
||||||
|
|
||||||
|
IkeyManager ikeyManager;
|
||||||
|
private SecretkeyElement secretkeyElement;
|
||||||
|
|
||||||
|
public IkeySetupViewModel(@NonNull Application application) {
|
||||||
|
super(application);
|
||||||
|
MercuryImApplication.getApplication().getAppComponent().inject(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void init(UUID accountId) {
|
||||||
|
MercuryConnection connection = connectionManager.getConnection(accountId);
|
||||||
|
ikeyManager = ikeyInitializer.initFor(connection);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Single<Optional<SecretkeyElement>> fetchBackupElement() {
|
||||||
|
return fetchMaybeBackupElement()
|
||||||
|
.map(Optional::new)
|
||||||
|
.toSingle(new Optional<>());
|
||||||
|
}
|
||||||
|
|
||||||
|
private Maybe<SecretkeyElement> fetchMaybeBackupElement() {
|
||||||
|
return new Maybe<SecretkeyElement>() {
|
||||||
|
@Override
|
||||||
|
protected void subscribeActual(MaybeObserver<? super SecretkeyElement> observer) {
|
||||||
|
try {
|
||||||
|
secretkeyElement = ikeyManager.fetchSecretIdentityKey();
|
||||||
|
if (secretkeyElement != null) {
|
||||||
|
observer.onSuccess(secretkeyElement);
|
||||||
|
} else {
|
||||||
|
observer.onComplete();
|
||||||
|
}
|
||||||
|
} catch (PubSubException.NotALeafNodeException e) {
|
||||||
|
observer.onComplete();
|
||||||
|
} catch (InterruptedException | XMPPException.XMPPErrorException | SmackException.NotConnectedException | SmackException.NoResponseException e) {
|
||||||
|
observer.onError(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
|
@ -6,6 +6,7 @@ import androidx.annotation.NonNull;
|
||||||
import androidx.lifecycle.AndroidViewModel;
|
import androidx.lifecycle.AndroidViewModel;
|
||||||
import androidx.lifecycle.MutableLiveData;
|
import androidx.lifecycle.MutableLiveData;
|
||||||
|
|
||||||
|
import org.mercury_im.messenger.android.MercuryImApplication;
|
||||||
import org.mercury_im.messenger.android.ui.MercuryAndroidViewModel;
|
import org.mercury_im.messenger.android.ui.MercuryAndroidViewModel;
|
||||||
import org.mercury_im.messenger.core.util.Optional;
|
import org.mercury_im.messenger.core.util.Optional;
|
||||||
import org.mercury_im.messenger.core.viewmodel.openpgp.OxBackupRestoreError;
|
import org.mercury_im.messenger.core.viewmodel.openpgp.OxBackupRestoreError;
|
||||||
|
@ -14,12 +15,14 @@ import org.mercury_im.messenger.core.viewmodel.openpgp.OxSecretKeyBackupRestoreV
|
||||||
import java.util.logging.Level;
|
import java.util.logging.Level;
|
||||||
import java.util.logging.Logger;
|
import java.util.logging.Logger;
|
||||||
|
|
||||||
|
import javax.inject.Inject;
|
||||||
|
|
||||||
public class AndroidOxSecretKeyBackupRestoreViewModel extends AndroidViewModel
|
public class AndroidOxSecretKeyBackupRestoreViewModel extends AndroidViewModel
|
||||||
implements MercuryAndroidViewModel<OxSecretKeyBackupRestoreViewModel> {
|
implements MercuryAndroidViewModel<OxSecretKeyBackupRestoreViewModel> {
|
||||||
|
|
||||||
private static final Logger LOGGER = Logger.getLogger(AndroidOxSecretKeyBackupRestoreViewModel.class.getName());
|
private static final Logger LOGGER = Logger.getLogger(AndroidOxSecretKeyBackupRestoreViewModel.class.getName());
|
||||||
|
|
||||||
//@Inject
|
// @Inject
|
||||||
OxSecretKeyBackupRestoreViewModel commonViewModel;
|
OxSecretKeyBackupRestoreViewModel commonViewModel;
|
||||||
|
|
||||||
private MutableLiveData<Optional<OxBackupRestoreError>> restoreError =
|
private MutableLiveData<Optional<OxBackupRestoreError>> restoreError =
|
||||||
|
@ -27,7 +30,7 @@ public class AndroidOxSecretKeyBackupRestoreViewModel extends AndroidViewModel
|
||||||
|
|
||||||
public AndroidOxSecretKeyBackupRestoreViewModel(@NonNull Application application) {
|
public AndroidOxSecretKeyBackupRestoreViewModel(@NonNull Application application) {
|
||||||
super(application);
|
super(application);
|
||||||
//MercuryImApplication.getApplication().getAppComponent().inject(this);
|
// MercuryImApplication.getApplication().getAppComponent().inject(this);
|
||||||
|
|
||||||
addDisposable(getCommonViewModel().observeBackupRestoreError()
|
addDisposable(getCommonViewModel().observeBackupRestoreError()
|
||||||
.subscribe(opt -> restoreError.postValue(opt),
|
.subscribe(opt -> restoreError.postValue(opt),
|
||||||
|
|
|
@ -0,0 +1,41 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:orientation="vertical" android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent">
|
||||||
|
|
||||||
|
<RelativeLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content">
|
||||||
|
|
||||||
|
<include layout="@layout/view_account_credentials">
|
||||||
|
</include>
|
||||||
|
|
||||||
|
<ProgressBar android:id="@+id/progress"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_centerInParent="true"
|
||||||
|
android:visibility="gone"/>
|
||||||
|
|
||||||
|
</RelativeLayout>
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:orientation="horizontal"
|
||||||
|
android:gravity="end">
|
||||||
|
|
||||||
|
<Button
|
||||||
|
android:id="@+id/btn_cancel"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:text="Cancel" />
|
||||||
|
|
||||||
|
<Button
|
||||||
|
android:id="@+id/btn_login"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:text="Login" />
|
||||||
|
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
</LinearLayout>
|
|
@ -4,7 +4,7 @@
|
||||||
xmlns:tools="http://schemas.android.com/tools"
|
xmlns:tools="http://schemas.android.com/tools"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="match_parent"
|
android:layout_height="match_parent"
|
||||||
tools:context=".android.ui.ikey.IkeyBackupCreationFragment">
|
tools:context=".android.crypto.ikey.IkeyBackupCreationFragment">
|
||||||
|
|
||||||
<TextView
|
<TextView
|
||||||
android:id="@+id/notice"
|
android:id="@+id/notice"
|
||||||
|
@ -17,12 +17,14 @@
|
||||||
app:layout_constraintTop_toTopOf="parent" />
|
app:layout_constraintTop_toTopOf="parent" />
|
||||||
|
|
||||||
<TextView
|
<TextView
|
||||||
|
android:id="@+id/description"
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:text="You should now write down the code below and store it somewhere safe.\nAlternatively you can scan the code below with another device to copy the identity key over."
|
android:text="You should now write down the code below and store it somewhere safe.\nAlternatively you can scan the code below with another device to copy the identity key over."
|
||||||
app:layout_constraintEnd_toEndOf="parent"
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
app:layout_constraintStart_toStartOf="parent"
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
app:layout_constraintTop_toBottomOf="@+id/notice" />
|
app:layout_constraintTop_toBottomOf="@+id/notice"
|
||||||
|
android:gravity="center"/>
|
||||||
|
|
||||||
<ImageView
|
<ImageView
|
||||||
android:id="@+id/qr_code"
|
android:id="@+id/qr_code"
|
||||||
|
@ -32,7 +34,7 @@
|
||||||
app:layout_constraintEnd_toEndOf="parent"
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
app:layout_constraintHorizontal_bias="0.497"
|
app:layout_constraintHorizontal_bias="0.497"
|
||||||
app:layout_constraintStart_toStartOf="parent"
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
app:layout_constraintTop_toBottomOf="@+id/notice"
|
app:layout_constraintTop_toBottomOf="@+id/description"
|
||||||
app:srcCompat="@drawable/ic_qr_code_scanner_black_24dp" />
|
app:srcCompat="@drawable/ic_qr_code_scanner_black_24dp" />
|
||||||
|
|
||||||
<TextView
|
<TextView
|
||||||
|
|
|
@ -1,10 +1,11 @@
|
||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||||
xmlns:tools="http://schemas.android.com/tools"
|
xmlns:tools="http://schemas.android.com/tools"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="match_parent"
|
android:layout_height="match_parent"
|
||||||
tools:context=".android.ui.ikey.IkeyBackupRestoreActivity">
|
android:orientation="vertical"
|
||||||
|
tools:context=".android.crypto.ikey.IkeyBackupRestoreActivity">
|
||||||
|
|
||||||
<TextView
|
<TextView
|
||||||
android:id="@+id/notice"
|
android:id="@+id/notice"
|
||||||
|
@ -16,22 +17,6 @@
|
||||||
app:layout_constraintStart_toStartOf="parent"
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
app:layout_constraintTop_toTopOf="parent" />
|
app:layout_constraintTop_toTopOf="parent" />
|
||||||
|
|
||||||
<LinearLayout
|
|
||||||
android:id="@+id/linearLayout"
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
app:layout_constraintEnd_toEndOf="parent"
|
|
||||||
app:layout_constraintStart_toStartOf="parent"
|
|
||||||
app:layout_constraintTop_toBottomOf="@+id/notice">
|
|
||||||
|
|
||||||
<include
|
|
||||||
layout="@layout/view_openpgp_4_fingerprint"
|
|
||||||
app:layout_constraintEnd_toEndOf="parent"
|
|
||||||
app:layout_constraintHorizontal_bias="0.0"
|
|
||||||
app:layout_constraintStart_toStartOf="parent"
|
|
||||||
tools:layout_editor_absoluteY="19dp" />
|
|
||||||
|
|
||||||
</LinearLayout>
|
|
||||||
|
|
||||||
<TextView
|
<TextView
|
||||||
android:id="@+id/textView"
|
android:id="@+id/textView"
|
||||||
|
@ -40,8 +25,7 @@
|
||||||
android:text="In order to restore the backup, please enter the backup code below."
|
android:text="In order to restore the backup, please enter the backup code below."
|
||||||
android:gravity="center"
|
android:gravity="center"
|
||||||
app:layout_constraintEnd_toEndOf="parent"
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
app:layout_constraintStart_toStartOf="parent"
|
app:layout_constraintStart_toStartOf="parent" />
|
||||||
app:layout_constraintTop_toBottomOf="@+id/linearLayout" />
|
|
||||||
|
|
||||||
<androidx.constraintlayout.widget.ConstraintLayout
|
<androidx.constraintlayout.widget.ConstraintLayout
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
|
@ -54,17 +38,18 @@
|
||||||
app:layout_constraintTop_toBottomOf="@+id/textView" >
|
app:layout_constraintTop_toBottomOf="@+id/textView" >
|
||||||
|
|
||||||
<EditText
|
<EditText
|
||||||
|
android:id="@+id/edit_backup_code"
|
||||||
android:layout_width="0dp"
|
android:layout_width="0dp"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:hint="Backup Code"
|
android:hint="Backup Code"
|
||||||
app:layout_constraintBottom_toBottomOf="parent"
|
app:layout_constraintBottom_toBottomOf="parent"
|
||||||
app:layout_constraintEnd_toStartOf="@+id/imageButton"
|
app:layout_constraintEnd_toStartOf="@+id/btn_scan"
|
||||||
app:layout_constraintStart_toStartOf="parent"
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
app:layout_constraintTop_toTopOf="parent"
|
app:layout_constraintTop_toTopOf="parent"
|
||||||
android:layout_marginEnd="8dp"/>
|
android:layout_marginEnd="8dp"/>
|
||||||
|
|
||||||
<ImageButton
|
<ImageButton
|
||||||
android:id="@+id/imageButton"
|
android:id="@+id/btn_scan"
|
||||||
android:layout_width="48dp"
|
android:layout_width="48dp"
|
||||||
android:layout_height="48dp"
|
android:layout_height="48dp"
|
||||||
android:background="@android:color/transparent"
|
android:background="@android:color/transparent"
|
||||||
|
@ -77,4 +62,24 @@
|
||||||
|
|
||||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||||
|
|
||||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
<LinearLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:orientation="horizontal"
|
||||||
|
android:gravity="end">
|
||||||
|
|
||||||
|
<Button
|
||||||
|
android:id="@+id/btn_restore"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:text="Restore"/>
|
||||||
|
|
||||||
|
<Button
|
||||||
|
android:id="@+id/btn_new_key"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:text="Generate new key"/>
|
||||||
|
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
</LinearLayout>
|
|
@ -0,0 +1,33 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:orientation="vertical" android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent">
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:text="Backup restored successfully!\nThis is your Identity Key Fingerprint:"
|
||||||
|
android:gravity="center"
|
||||||
|
/>
|
||||||
|
|
||||||
|
<include layout="@layout/view_openpgp_4_fingerprint" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:text="This key will help your contacts to decide which keys really belong to you."
|
||||||
|
android:gravity="center"/>
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:orientation="horizontal"
|
||||||
|
android:gravity="end">
|
||||||
|
<Button
|
||||||
|
android:id="@+id/btn_done"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:text="Done" />
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
</LinearLayout>
|
|
@ -0,0 +1,38 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:orientation="vertical" android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent">
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:text="Setup Simplified Encryption Key Management?"
|
||||||
|
android:gravity="center"/>
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:text="Ikey simplifies management of encryption keys when multiple devices are in use."
|
||||||
|
android:gravity="center"/>
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:orientation="horizontal"
|
||||||
|
android:gravity="end">
|
||||||
|
|
||||||
|
<Button
|
||||||
|
android:id="@+id/btn_skip"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:text="Skip" />
|
||||||
|
|
||||||
|
<Button
|
||||||
|
android:id="@+id/btn_continue"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:text="Yes, please" />
|
||||||
|
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
</LinearLayout>
|
|
@ -0,0 +1,12 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||||
|
android:orientation="vertical" android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent">
|
||||||
|
|
||||||
|
<androidx.viewpager2.widget.ViewPager2
|
||||||
|
android:id="@+id/viewpager"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent" />
|
||||||
|
|
||||||
|
</LinearLayout>
|
|
@ -5,7 +5,7 @@
|
||||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||||
android:id="@+id/login_form"
|
android:id="@+id/login_form"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="match_parent"
|
android:layout_height="wrap_content"
|
||||||
android:paddingLeft="@dimen/activity_horizontal_margin"
|
android:paddingLeft="@dimen/activity_horizontal_margin"
|
||||||
android:paddingTop="@dimen/activity_vertical_margin"
|
android:paddingTop="@dimen/activity_vertical_margin"
|
||||||
android:paddingRight="@dimen/activity_horizontal_margin"
|
android:paddingRight="@dimen/activity_horizontal_margin"
|
|
@ -3,7 +3,7 @@
|
||||||
xmlns:android="http://schemas.android.com/apk/res/android">
|
xmlns:android="http://schemas.android.com/apk/res/android">
|
||||||
|
|
||||||
<item
|
<item
|
||||||
android:id="@+id/toggle_account_enabled"
|
android:id="@+id/switch_account_enabled"
|
||||||
android:title="Enable Account"
|
android:title="Enable Account"
|
||||||
app:actionLayout="@layout/switch_item"
|
app:actionLayout="@layout/switch_item"
|
||||||
app:showAsAction="always" />
|
app:showAsAction="always" />
|
||||||
|
|
|
@ -99,6 +99,15 @@ public class MercuryConnectionManager {
|
||||||
return connectionsMap.get(id);
|
return connectionsMap.get(id);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public MercuryConnection createConnection(UUID accountId) {
|
||||||
|
Account account = accountRepository.getAccount(accountId)
|
||||||
|
.blockingGet();
|
||||||
|
if (account == null) {
|
||||||
|
throw new IllegalArgumentException("No account associated with this accountID: " + accountId);
|
||||||
|
}
|
||||||
|
return createConnection(account);
|
||||||
|
}
|
||||||
|
|
||||||
public MercuryConnection createConnection(Account account) {
|
public MercuryConnection createConnection(Account account) {
|
||||||
return new MercuryConnection(connectionFactory.createConnection(account), account);
|
return new MercuryConnection(connectionFactory.createConnection(account), account);
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,6 @@
|
||||||
|
package org.mercury_im.messenger.core.crypto;
|
||||||
|
|
||||||
|
public interface LocalOxKeyGenerationStrategy {
|
||||||
|
|
||||||
|
boolean promptForBackupRestoreIfNoLocalKeyPresent();
|
||||||
|
}
|
|
@ -4,6 +4,7 @@ import org.jivesoftware.smack.AbstractConnectionListener;
|
||||||
import org.jivesoftware.smack.XMPPConnection;
|
import org.jivesoftware.smack.XMPPConnection;
|
||||||
import org.jivesoftware.smackx.ox.OpenPgpManager;
|
import org.jivesoftware.smackx.ox.OpenPgpManager;
|
||||||
import org.jivesoftware.smackx.ox.OpenPgpSecretKeyBackupPassphrase;
|
import org.jivesoftware.smackx.ox.OpenPgpSecretKeyBackupPassphrase;
|
||||||
|
import org.jivesoftware.smackx.ox.callback.SecretKeyPassphraseCallback;
|
||||||
import org.jivesoftware.smackx.ox.crypto.OpenPgpProvider;
|
import org.jivesoftware.smackx.ox.crypto.OpenPgpProvider;
|
||||||
import org.jivesoftware.smackx.ox.crypto.PainlessOpenPgpProvider;
|
import org.jivesoftware.smackx.ox.crypto.PainlessOpenPgpProvider;
|
||||||
import org.jivesoftware.smackx.ox.exception.InvalidBackupCodeException;
|
import org.jivesoftware.smackx.ox.exception.InvalidBackupCodeException;
|
||||||
|
@ -35,6 +36,7 @@ public class MercuryOpenPgpManager {
|
||||||
private final OpenPgpRepository openPgpRepository;
|
private final OpenPgpRepository openPgpRepository;
|
||||||
private final SchedulersFacade schedulers;
|
private final SchedulersFacade schedulers;
|
||||||
private final OpenPgpSecretKeyBackupPassphraseGenerator passphraseGenerator;
|
private final OpenPgpSecretKeyBackupPassphraseGenerator passphraseGenerator;
|
||||||
|
private final LocalOxKeyGenerationStrategy keyGenerationStrategy;
|
||||||
|
|
||||||
@Inject
|
@Inject
|
||||||
public MercuryOpenPgpManager(PeerRepository peerRepository,
|
public MercuryOpenPgpManager(PeerRepository peerRepository,
|
||||||
|
@ -42,12 +44,14 @@ public class MercuryOpenPgpManager {
|
||||||
MessageRepository messageRepository,
|
MessageRepository messageRepository,
|
||||||
OpenPgpRepository openPgpRepository,
|
OpenPgpRepository openPgpRepository,
|
||||||
OpenPgpSecretKeyBackupPassphraseGenerator passphraseGenerator,
|
OpenPgpSecretKeyBackupPassphraseGenerator passphraseGenerator,
|
||||||
|
LocalOxKeyGenerationStrategy keyGenerationStrategy,
|
||||||
SchedulersFacade schedulers) {
|
SchedulersFacade schedulers) {
|
||||||
this.peerRepository = peerRepository;
|
this.peerRepository = peerRepository;
|
||||||
this.directChatRepository = directChatRepository;
|
this.directChatRepository = directChatRepository;
|
||||||
this.messageRepository = messageRepository;
|
this.messageRepository = messageRepository;
|
||||||
this.openPgpRepository = openPgpRepository;
|
this.openPgpRepository = openPgpRepository;
|
||||||
this.schedulers = schedulers;
|
this.schedulers = schedulers;
|
||||||
|
this.keyGenerationStrategy = keyGenerationStrategy;
|
||||||
this.passphraseGenerator = passphraseGenerator;
|
this.passphraseGenerator = passphraseGenerator;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -72,8 +76,8 @@ public class MercuryOpenPgpManager {
|
||||||
OpenPgpManager oxManager = OpenPgpManager.getInstanceFor(connection.getConnection());
|
OpenPgpManager oxManager = OpenPgpManager.getInstanceFor(connection.getConnection());
|
||||||
oxManager.setOpenPgpProvider(provider);
|
oxManager.setOpenPgpProvider(provider);
|
||||||
OpenPgpSecretKeyBackupPassphrase passphrase = passphraseGenerator.generateBackupPassphrase();
|
OpenPgpSecretKeyBackupPassphrase passphrase = passphraseGenerator.generateBackupPassphrase();
|
||||||
|
boolean mustGenerate = false;
|
||||||
try {
|
try {
|
||||||
boolean mustGenerate = false;
|
|
||||||
if (!oxManager.hasSecretKeysAvailable()) {
|
if (!oxManager.hasSecretKeysAvailable()) {
|
||||||
mustGenerate = true;
|
mustGenerate = true;
|
||||||
if (OpenPgpManager.serverSupportsSecretKeyBackups(connection.getConnection())) {
|
if (OpenPgpManager.serverSupportsSecretKeyBackups(connection.getConnection())) {
|
||||||
|
@ -105,4 +109,8 @@ public class MercuryOpenPgpManager {
|
||||||
e.printStackTrace();
|
e.printStackTrace();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public boolean mustPromptForRestore() {
|
||||||
|
return keyGenerationStrategy.promptForBackupRestoreIfNoLocalKeyPresent();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,9 @@
|
||||||
|
package org.mercury_im.messenger.core.crypto;
|
||||||
|
|
||||||
|
public class OxPlusIkeyKeyGenerationStrategy implements LocalOxKeyGenerationStrategy {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean promptForBackupRestoreIfNoLocalKeyPresent() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,10 @@
|
||||||
|
package org.mercury_im.messenger.core.di.component;
|
||||||
|
|
||||||
|
import static java.lang.annotation.RetentionPolicy.RUNTIME;
|
||||||
|
|
||||||
|
@java.lang.annotation.Documented
|
||||||
|
@java.lang.annotation.Retention(RUNTIME)
|
||||||
|
@javax.inject.Qualifier
|
||||||
|
public @interface Account {
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,21 @@
|
||||||
|
package org.mercury_im.messenger.core.di.component;
|
||||||
|
|
||||||
|
import java.util.UUID;
|
||||||
|
|
||||||
|
import dagger.BindsInstance;
|
||||||
|
import dagger.Component;
|
||||||
|
|
||||||
|
@Component
|
||||||
|
public interface ConnectionComponent {
|
||||||
|
|
||||||
|
ConnectionComponent getComponent();
|
||||||
|
|
||||||
|
@Component.Builder
|
||||||
|
interface Builder {
|
||||||
|
|
||||||
|
@BindsInstance Builder forAccount(@Account UUID accountId);
|
||||||
|
|
||||||
|
ConnectionComponent build();
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,19 @@
|
||||||
|
package org.mercury_im.messenger.core.di.module;
|
||||||
|
|
||||||
|
import org.mercury_im.messenger.core.crypto.LocalOxKeyGenerationStrategy;
|
||||||
|
import org.mercury_im.messenger.core.crypto.OxPlusIkeyKeyGenerationStrategy;
|
||||||
|
|
||||||
|
import javax.inject.Singleton;
|
||||||
|
|
||||||
|
import dagger.Module;
|
||||||
|
import dagger.Provides;
|
||||||
|
|
||||||
|
@Module
|
||||||
|
public class IkeyModule {
|
||||||
|
|
||||||
|
@Singleton
|
||||||
|
@Provides
|
||||||
|
static LocalOxKeyGenerationStrategy provideLocalOxKeyGenerationStrategy() {
|
||||||
|
return new OxPlusIkeyKeyGenerationStrategy();
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,39 @@
|
||||||
|
package org.mercury_im.messenger.core.di.module;
|
||||||
|
|
||||||
|
import org.jivesoftware.smackx.ikey.IkeyManager;
|
||||||
|
import org.jivesoftware.smackx.ox.OpenPgpManager;
|
||||||
|
import org.mercury_im.messenger.core.connection.MercuryConnection;
|
||||||
|
import org.mercury_im.messenger.core.connection.MercuryConnectionManager;
|
||||||
|
import org.mercury_im.messenger.core.di.component.Account;
|
||||||
|
|
||||||
|
import java.util.UUID;
|
||||||
|
|
||||||
|
import dagger.Module;
|
||||||
|
import dagger.Provides;
|
||||||
|
|
||||||
|
@Module
|
||||||
|
public class MercuryConnectionModule {
|
||||||
|
|
||||||
|
@Provides
|
||||||
|
@Account
|
||||||
|
MercuryConnection provideConnection(MercuryConnectionManager connectionManager, @Account UUID accountId) {
|
||||||
|
MercuryConnection connection = connectionManager.getConnection(accountId);
|
||||||
|
if (connection == null) {
|
||||||
|
connection = connectionManager.createConnection(accountId);
|
||||||
|
connectionManager.doRegisterConnection(connection);
|
||||||
|
}
|
||||||
|
return connection;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Provides
|
||||||
|
@Account
|
||||||
|
OpenPgpManager provideOpenPgpManager(MercuryConnection connection) {
|
||||||
|
return OpenPgpManager.getInstanceFor(connection.getConnection());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Provides
|
||||||
|
@Account
|
||||||
|
IkeyManager provideIkeyManager(MercuryConnection connection) {
|
||||||
|
return IkeyManager.getInstanceFor(connection.getConnection());
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,7 +1,9 @@
|
||||||
package org.mercury_im.messenger.core.di.module;
|
package org.mercury_im.messenger.core.di.module;
|
||||||
|
|
||||||
import org.mercury_im.messenger.core.crypto.InsecureStaticSecretKeyBackupPassphraseGenerator;
|
import org.mercury_im.messenger.core.crypto.InsecureStaticSecretKeyBackupPassphraseGenerator;
|
||||||
|
import org.mercury_im.messenger.core.crypto.LocalOxKeyGenerationStrategy;
|
||||||
import org.mercury_im.messenger.core.crypto.OpenPgpSecretKeyBackupPassphraseGenerator;
|
import org.mercury_im.messenger.core.crypto.OpenPgpSecretKeyBackupPassphraseGenerator;
|
||||||
|
import org.mercury_im.messenger.core.crypto.OxPlusIkeyKeyGenerationStrategy;
|
||||||
|
|
||||||
import javax.inject.Singleton;
|
import javax.inject.Singleton;
|
||||||
|
|
||||||
|
@ -17,5 +19,4 @@ public class OpenPgpModule {
|
||||||
// TODO: THIS MUST NEVER MAKE IT TO PRODUCTION!!!
|
// TODO: THIS MUST NEVER MAKE IT TO PRODUCTION!!!
|
||||||
return new InsecureStaticSecretKeyBackupPassphraseGenerator();
|
return new InsecureStaticSecretKeyBackupPassphraseGenerator();
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,15 +7,17 @@ import org.jxmpp.stringprep.XmppStringprepException;
|
||||||
import org.mercury_im.messenger.core.SchedulersFacade;
|
import org.mercury_im.messenger.core.SchedulersFacade;
|
||||||
import org.mercury_im.messenger.core.account.error.PasswordError;
|
import org.mercury_im.messenger.core.account.error.PasswordError;
|
||||||
import org.mercury_im.messenger.core.account.error.UsernameError;
|
import org.mercury_im.messenger.core.account.error.UsernameError;
|
||||||
import org.mercury_im.messenger.core.connection.MercuryConnection;
|
|
||||||
import org.mercury_im.messenger.core.connection.MercuryConnectionManager;
|
import org.mercury_im.messenger.core.connection.MercuryConnectionManager;
|
||||||
import org.mercury_im.messenger.core.connection.exception.InvalidCredentialsException;
|
import org.mercury_im.messenger.core.connection.exception.InvalidCredentialsException;
|
||||||
import org.mercury_im.messenger.core.connection.exception.ServerUnreachableException;
|
import org.mercury_im.messenger.core.connection.exception.ServerUnreachableException;
|
||||||
|
import org.mercury_im.messenger.core.connection.state.ConnectionState;
|
||||||
|
import org.mercury_im.messenger.core.connection.state.ConnectivityState;
|
||||||
import org.mercury_im.messenger.core.data.repository.AccountRepository;
|
import org.mercury_im.messenger.core.data.repository.AccountRepository;
|
||||||
import org.mercury_im.messenger.core.util.Optional;
|
import org.mercury_im.messenger.core.util.Optional;
|
||||||
import org.mercury_im.messenger.core.viewmodel.MercuryViewModel;
|
import org.mercury_im.messenger.core.viewmodel.MercuryViewModel;
|
||||||
import org.mercury_im.messenger.entity.Account;
|
import org.mercury_im.messenger.entity.Account;
|
||||||
|
|
||||||
|
import java.util.logging.Level;
|
||||||
import java.util.logging.Logger;
|
import java.util.logging.Logger;
|
||||||
|
|
||||||
import javax.inject.Inject;
|
import javax.inject.Inject;
|
||||||
|
@ -35,10 +37,11 @@ public class LoginViewModel implements MercuryViewModel {
|
||||||
private BehaviorSubject<Optional<UsernameError>> loginUsernameError;
|
private BehaviorSubject<Optional<UsernameError>> loginUsernameError;
|
||||||
private BehaviorSubject<Optional<PasswordError>> loginPasswordError;
|
private BehaviorSubject<Optional<PasswordError>> loginPasswordError;
|
||||||
private BehaviorSubject<Boolean> isLoginPossible;
|
private BehaviorSubject<Boolean> isLoginPossible;
|
||||||
private BehaviorSubject<Boolean> isLoginSuccessful;
|
private BehaviorSubject<Optional<Account>> isLoginSuccessful;
|
||||||
|
|
||||||
private EntityBareJid loginUsernameValue;
|
private EntityBareJid loginUsernameValue;
|
||||||
private String loginPasswordValue;
|
private String loginPasswordValue;
|
||||||
|
private Account account;
|
||||||
|
|
||||||
@Inject
|
@Inject
|
||||||
public LoginViewModel(MercuryConnectionManager connectionManager,
|
public LoginViewModel(MercuryConnectionManager connectionManager,
|
||||||
|
@ -55,7 +58,7 @@ public class LoginViewModel implements MercuryViewModel {
|
||||||
loginUsernameError = BehaviorSubject.createDefault(new Optional<>());
|
loginUsernameError = BehaviorSubject.createDefault(new Optional<>());
|
||||||
loginPasswordError = BehaviorSubject.createDefault(new Optional<>());
|
loginPasswordError = BehaviorSubject.createDefault(new Optional<>());
|
||||||
isLoginPossible = BehaviorSubject.createDefault(false);
|
isLoginPossible = BehaviorSubject.createDefault(false);
|
||||||
isLoginSuccessful = BehaviorSubject.createDefault(false);
|
isLoginSuccessful = BehaviorSubject.createDefault(new Optional<>());
|
||||||
|
|
||||||
loginUsernameValue = null;
|
loginUsernameValue = null;
|
||||||
loginPasswordValue = null;
|
loginPasswordValue = null;
|
||||||
|
@ -73,7 +76,7 @@ public class LoginViewModel implements MercuryViewModel {
|
||||||
return isLoginPossible;
|
return isLoginPossible;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Observable<Boolean> isLoginSuccessful() {
|
public Observable<Optional<Account>> isLoginSuccessful() {
|
||||||
return isLoginSuccessful;
|
return isLoginSuccessful;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -108,26 +111,48 @@ public class LoginViewModel implements MercuryViewModel {
|
||||||
isLoginPossible.onNext(loginUsernameValue != null && loginPasswordValue != null);
|
isLoginPossible.onNext(loginUsernameValue != null && loginPasswordValue != null);
|
||||||
}
|
}
|
||||||
|
|
||||||
public synchronized void login() {
|
public synchronized Account login() {
|
||||||
if (!isLoginPossible.getValue()) {
|
if (!isLoginPossible.getValue()) {
|
||||||
// Prevent race condition where account would be logged in twice
|
// Prevent race condition where account would be logged in twice
|
||||||
return;
|
return account;
|
||||||
}
|
}
|
||||||
isLoginPossible.onNext(false);
|
isLoginPossible.onNext(false);
|
||||||
|
|
||||||
Account account = createAccountEntity();
|
account = createAccountEntity();
|
||||||
|
|
||||||
//MercuryConnection connection = connectionManager.createConnection(account);
|
//MercuryConnection connection = connectionManager.createConnection(account);
|
||||||
addDisposable(accountRepository.upsertAccount(account).ignoreElement()
|
addDisposable(accountRepository.upsertAccount(account)
|
||||||
//.andThen(connection.connect())
|
//.andThen(connection.connect())
|
||||||
//.andThen(connection.login())
|
//.andThen(connection.login())
|
||||||
//.andThen(connectionManager.registerConnection(connection))
|
//.andThen(connectionManager.registerConnection(connection))
|
||||||
.subscribeOn(schedulers.getNewThread())
|
.subscribeOn(schedulers.getNewThread())
|
||||||
.observeOn(schedulers.getUiScheduler())
|
.observeOn(schedulers.getUiScheduler())
|
||||||
.subscribe(
|
.subscribe(
|
||||||
this::onLoginSuccessful,
|
a -> LOGGER.log(Level.INFO, "Account " + a + " successfully inserted."),
|
||||||
this::onLoginFailed
|
this::onLoginFailed
|
||||||
));
|
));
|
||||||
|
|
||||||
|
addDisposable(connectionManager.observeConnectionPool()
|
||||||
|
.map(cp -> {
|
||||||
|
ConnectionState state = cp.getConnectionStates().get(account.getId());
|
||||||
|
if (state == null) {
|
||||||
|
return ConnectivityState.disconnected;
|
||||||
|
} else {
|
||||||
|
return state.getConnectivity();
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.filter(s -> s == ConnectivityState.disconnectedOnError || s == ConnectivityState.authenticated)
|
||||||
|
.firstOrError()
|
||||||
|
.compose(schedulers.executeUiSafeSingle())
|
||||||
|
.subscribe(connectivityState -> {
|
||||||
|
if (connectivityState == ConnectivityState.disconnectedOnError) {
|
||||||
|
onLoginFailed(new Exception());
|
||||||
|
} else {
|
||||||
|
onLoginSuccessful(account);
|
||||||
|
}
|
||||||
|
}));
|
||||||
|
|
||||||
|
return account;
|
||||||
}
|
}
|
||||||
|
|
||||||
private Account createAccountEntity() {
|
private Account createAccountEntity() {
|
||||||
|
@ -139,11 +164,13 @@ public class LoginViewModel implements MercuryViewModel {
|
||||||
return account;
|
return account;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void onLoginSuccessful() {
|
private void onLoginSuccessful(Account account) {
|
||||||
isLoginSuccessful.onNext(true);
|
LOGGER.log(Level.INFO, "Login successful.");
|
||||||
|
isLoginSuccessful.onNext(new Optional<>(account));
|
||||||
}
|
}
|
||||||
|
|
||||||
private void onLoginFailed(Throwable error) {
|
private void onLoginFailed(Throwable error) {
|
||||||
|
LOGGER.log(Level.INFO, "Login failed!");
|
||||||
isLoginPossible.onNext(true);
|
isLoginPossible.onNext(true);
|
||||||
if (error instanceof InvalidCredentialsException) {
|
if (error instanceof InvalidCredentialsException) {
|
||||||
loginPasswordError.onNext(new Optional<>(PasswordError.incorrectPassword));
|
loginPasswordError.onNext(new Optional<>(PasswordError.incorrectPassword));
|
||||||
|
|
|
@ -14,6 +14,8 @@ import org.jxmpp.jid.EntityBareJid;
|
||||||
import org.mercury_im.messenger.core.SchedulersFacade;
|
import org.mercury_im.messenger.core.SchedulersFacade;
|
||||||
import org.mercury_im.messenger.core.connection.MercuryConnection;
|
import org.mercury_im.messenger.core.connection.MercuryConnection;
|
||||||
import org.mercury_im.messenger.core.connection.MercuryConnectionManager;
|
import org.mercury_im.messenger.core.connection.MercuryConnectionManager;
|
||||||
|
import org.mercury_im.messenger.core.connection.state.ConnectionState;
|
||||||
|
import org.mercury_im.messenger.core.connection.state.ConnectivityState;
|
||||||
import org.mercury_im.messenger.core.crypto.ikey.IkeyInitializer;
|
import org.mercury_im.messenger.core.crypto.ikey.IkeyInitializer;
|
||||||
import org.mercury_im.messenger.core.crypto.ikey.IkeyRepository;
|
import org.mercury_im.messenger.core.crypto.ikey.IkeyRepository;
|
||||||
import org.mercury_im.messenger.core.data.repository.AccountRepository;
|
import org.mercury_im.messenger.core.data.repository.AccountRepository;
|
||||||
|
@ -27,15 +29,12 @@ import org.pgpainless.key.OpenPgpV4Fingerprint;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
import java.util.logging.Level;
|
|
||||||
import java.util.logging.Logger;
|
|
||||||
|
|
||||||
import javax.inject.Inject;
|
import javax.inject.Inject;
|
||||||
|
|
||||||
import io.reactivex.Completable;
|
import io.reactivex.Completable;
|
||||||
import io.reactivex.Observable;
|
import io.reactivex.Observable;
|
||||||
import io.reactivex.Single;
|
import io.reactivex.Single;
|
||||||
import io.reactivex.disposables.Disposable;
|
|
||||||
|
|
||||||
import static org.jivesoftware.smackx.ox.util.OpenPgpPubSubUtil.PEP_NODE_PUBLIC_KEYS;
|
import static org.jivesoftware.smackx.ox.util.OpenPgpPubSubUtil.PEP_NODE_PUBLIC_KEYS;
|
||||||
|
|
||||||
|
@ -155,4 +154,18 @@ public class AccountDetailsViewModel implements MercuryViewModel {
|
||||||
SecretkeyElement secretkeyElement = ikeyManager.fetchSecretIdentityKey();
|
SecretkeyElement secretkeyElement = ikeyManager.fetchSecretIdentityKey();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Observable<Boolean> isAccountEnabled(UUID accountId) {
|
||||||
|
return accountRepository.observeAccount(accountId)
|
||||||
|
.filter(Optional::isPresent)
|
||||||
|
.map(Optional::getItem)
|
||||||
|
.map(Account::isEnabled);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Observable<Boolean> isAccountAuthenticated(UUID accountId) {
|
||||||
|
return connectionManager.getConnection(accountId)
|
||||||
|
.observeConnection()
|
||||||
|
.map(ConnectionState::getConnectivity)
|
||||||
|
.map(connectivity -> connectivity == ConnectivityState.authenticated);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -31,7 +31,7 @@ public class OxSecretKeyBackupRestoreViewModel implements MercuryViewModel {
|
||||||
private BehaviorSubject<Optional<OxBackupRestoreError>> backupRestoreError = BehaviorSubject.createDefault(new Optional<>());
|
private BehaviorSubject<Optional<OxBackupRestoreError>> backupRestoreError = BehaviorSubject.createDefault(new Optional<>());
|
||||||
private BehaviorSubject<Boolean> finished = BehaviorSubject.createDefault(false);
|
private BehaviorSubject<Boolean> finished = BehaviorSubject.createDefault(false);
|
||||||
|
|
||||||
@Inject
|
//@Inject
|
||||||
public OxSecretKeyBackupRestoreViewModel(OpenPgpManager openPgpManager) {
|
public OxSecretKeyBackupRestoreViewModel(OpenPgpManager openPgpManager) {
|
||||||
this.openPgpManager = openPgpManager;
|
this.openPgpManager = openPgpManager;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue