Fix merge conflicts

This commit is contained in:
ameba23
2022-02-10 10:53:09 +01:00
40 changed files with 580 additions and 566 deletions

View File

@@ -139,16 +139,7 @@
</activity>
<activity
android:name="org.briarproject.briar.android.account.NewOrRecoverActivity"
android:label="@string/activity_name_new_or_recover_account"
android:parentActivityName="org.briarproject.briar.android.login.StartupActivity">
<meta-data
android:name="android.support.PARENT_ACTIVITY"
android:value="org.briarproject.briar.android.login.StartupActivity" />
</activity>
<activity
android:name="org.briarproject.briar.android.socialbackup.DistributedBackupActivity"
android:name="org.briarproject.briar.android.socialbackup.SocialBackupSetupActivity"
android:label="@string/activity_name_distributed_backup"
android:parentActivityName="org.briarproject.briar.android.settings.SettingsActivity">
<meta-data
@@ -168,10 +159,11 @@
<activity
android:name="org.briarproject.briar.android.socialbackup.recover.OwnerReturnShardActivity"
android:label="@string/activity_name_recovery"
android:parentActivityName="org.briarproject.briar.android.account.NewOrRecoverActivity">
android:parentActivityName="org.briarproject.briar.android.account.SetupActivity">
<meta-data
android:name="android.support.PARENT_ACTIVITY"
android:value="org.briarproject.briar.android.account.NewOrRecoverActivity" />
android:value="org.briarproject.briar.android.account.SetupActivity" />
</activity>
<activity

View File

@@ -43,6 +43,7 @@ import org.briarproject.briar.android.remotewipe.RemoteWipeModule;
import org.briarproject.briar.android.reporting.DevReportModule;
import org.briarproject.briar.android.settings.SettingsModule;
import org.briarproject.briar.android.sharing.SharingModule;
import org.briarproject.briar.android.socialbackup.SocialBackupSetupModule;
import org.briarproject.briar.android.socialbackup.recover.CustodianReturnShardModule;
import org.briarproject.briar.android.socialbackup.recover.OwnerReturnShardModule;
import org.briarproject.briar.android.test.TestAvatarCreatorImpl;
@@ -96,7 +97,8 @@ import static org.briarproject.briar.android.TestingConstants.IS_DEBUG_BUILD;
SharingModule.class,
OwnerReturnShardModule.class,
CustodianReturnShardModule.class,
RemoteWipeModule.class
RemoteWipeModule.class,
SocialBackupSetupModule.class
})
public class AppModule {

View File

@@ -30,6 +30,7 @@ public class AuthorNameFragment extends SetupFragment {
private TextInputLayout authorNameWrapper;
private TextInputEditText authorNameInput;
private Button nextButton;
private Button recoverButton;
public static AuthorNameFragment newInstance() {
return new AuthorNameFragment();
@@ -54,6 +55,9 @@ public class AuthorNameFragment extends SetupFragment {
authorNameInput.addTextChangedListener(this);
nextButton.setOnClickListener(this);
recoverButton = v.findViewById(R.id.buttonRestoreAccount);
recoverButton.setOnClickListener(e -> viewModel.recoverClicked());
return v;
}
@@ -75,6 +79,8 @@ public class AuthorNameFragment extends SetupFragment {
boolean enabled = authorNameLength > 0 && !error;
authorNameInput.setOnEditorActionListener(enabled ? this : null);
nextButton.setEnabled(enabled);
recoverButton.setEnabled(!enabled);
// recoverButton.setVisibility(enabled ? View.INVISIBLE : View.VISIBLE);
}
@Override

View File

@@ -1,60 +0,0 @@
package org.briarproject.briar.android.account;
import android.content.Intent;
import android.os.Bundle;
import org.briarproject.briar.R;
import org.briarproject.briar.android.activity.ActivityComponent;
import org.briarproject.briar.android.activity.BaseActivity;
import org.briarproject.briar.android.fragment.BaseFragment;
import org.briarproject.briar.android.socialbackup.recover.OwnerReturnShardActivity;
import static android.content.Intent.FLAG_ACTIVITY_CLEAR_TASK;
import static android.content.Intent.FLAG_ACTIVITY_CLEAR_TOP;
import static android.content.Intent.FLAG_ACTIVITY_NEW_TASK;
import static android.content.Intent.FLAG_ACTIVITY_TASK_ON_HOME;
public class NewOrRecoverActivity extends BaseActivity implements
BaseFragment.BaseFragmentListener, SetupNewAccountChosenListener,
RecoverAccountListener {
@Override
public void injectActivity(ActivityComponent component) {
component.inject(this);
}
@Override
public void onCreate(Bundle state) {
super.onCreate(state);
// fade-in after splash screen instead of default animation
// TODO the fade in is not working
overridePendingTransition(R.anim.fade_in, R.anim.fade_out);
setContentView(R.layout.activity_fragment_container);
NewOrRecoverFragment fragment = NewOrRecoverFragment.newInstance();
showInitialFragment(fragment);
}
@Override
public void setupNewAccountChosen() {
finish();
Intent i = new Intent(this, SetupActivity.class);
i.addFlags(FLAG_ACTIVITY_NEW_TASK | FLAG_ACTIVITY_CLEAR_TOP |
FLAG_ACTIVITY_CLEAR_TASK | FLAG_ACTIVITY_TASK_ON_HOME);
startActivity(i);
}
@Override
public void recoverAccountChosen() {
finish();
Intent i = new Intent(this, OwnerReturnShardActivity.class);
i.addFlags(FLAG_ACTIVITY_NEW_TASK | FLAG_ACTIVITY_CLEAR_TOP |
FLAG_ACTIVITY_CLEAR_TASK | FLAG_ACTIVITY_TASK_ON_HOME);
startActivity(i);
}
@Override
@Deprecated
public void runOnDbThread(Runnable runnable) {
throw new RuntimeException("Don't use this deprecated method here.");
}
}

View File

@@ -1,70 +0,0 @@
package org.briarproject.briar.android.account;
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 org.briarproject.briar.R;
import org.briarproject.briar.android.activity.ActivityComponent;
import org.briarproject.briar.android.fragment.BaseFragment;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
public class NewOrRecoverFragment extends BaseFragment {
public static final String TAG = NewOrRecoverFragment.class.getName();
protected SetupNewAccountChosenListener setupNewAccountListener;
protected RecoverAccountListener recoverAccountListener;
public static NewOrRecoverFragment newInstance() {
Bundle bundle = new Bundle();
NewOrRecoverFragment fragment = new NewOrRecoverFragment();
fragment.setArguments(bundle);
return fragment;
}
@Override
public void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
requireActivity().setTitle(R.string.setup_title);
}
@Nullable
@Override
public View onCreateView(@NonNull LayoutInflater inflater, @Nullable
ViewGroup container, @Nullable Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.fragment_new_or_recover,
container, false);
Button newAccountButton = view.findViewById(R.id.buttonSetupNewAccount);
newAccountButton.setOnClickListener(e -> {
setupNewAccountListener.setupNewAccountChosen();
});
Button recoverAccountButton = view.findViewById(R.id.buttonRestoreAccount);
recoverAccountButton.setOnClickListener(e -> {
recoverAccountListener.recoverAccountChosen();
});
return view;
}
@Override
public void onAttach(Context context) {
super.onAttach(context);
setupNewAccountListener = (SetupNewAccountChosenListener) context;
recoverAccountListener = (RecoverAccountListener) context;
}
@Override
public String getUniqueTag() {
return TAG;
}
@Override
public void injectFragment(ActivityComponent component) {
component.inject(this);
}
}

View File

@@ -10,6 +10,7 @@ import org.briarproject.briar.R;
import org.briarproject.briar.android.activity.ActivityComponent;
import org.briarproject.briar.android.activity.BaseActivity;
import org.briarproject.briar.android.fragment.BaseFragment.BaseFragmentListener;
import org.briarproject.briar.android.socialbackup.recover.OwnerReturnShardActivity;
import javax.annotation.Nullable;
import javax.inject.Inject;
@@ -25,6 +26,7 @@ import static org.briarproject.briar.android.account.SetupViewModel.State.AUTHOR
import static org.briarproject.briar.android.account.SetupViewModel.State.CREATED;
import static org.briarproject.briar.android.account.SetupViewModel.State.DOZE;
import static org.briarproject.briar.android.account.SetupViewModel.State.FAILED;
import static org.briarproject.briar.android.account.SetupViewModel.State.RECOVER;
import static org.briarproject.briar.android.account.SetupViewModel.State.SET_PASSWORD;
@MethodsNotNullByDefault
@@ -60,6 +62,8 @@ public class SetupActivity extends BaseActivity
showPasswordFragment();
} else if (state == DOZE) {
showDozeFragment();
} else if (state == RECOVER) {
recover();
} else if (state == CREATED || state == FAILED) {
// TODO: Show an error if failed
showApp();
@@ -84,6 +88,13 @@ public class SetupActivity extends BaseActivity
overridePendingTransition(R.anim.screen_new_in, R.anim.screen_old_out);
}
void recover () {
// finish();
Intent i = new Intent(this, OwnerReturnShardActivity.class);
i.addFlags(FLAG_ACTIVITY_NEW_TASK);
startActivity(i);
}
@Override
@Deprecated
public void runOnDbThread(Runnable runnable) {

View File

@@ -25,13 +25,14 @@ import static org.briarproject.briar.android.account.SetupViewModel.State.AUTHOR
import static org.briarproject.briar.android.account.SetupViewModel.State.CREATED;
import static org.briarproject.briar.android.account.SetupViewModel.State.DOZE;
import static org.briarproject.briar.android.account.SetupViewModel.State.FAILED;
import static org.briarproject.briar.android.account.SetupViewModel.State.RECOVER;
import static org.briarproject.briar.android.account.SetupViewModel.State.SET_PASSWORD;
@MethodsNotNullByDefault
@ParametersNotNullByDefault
public
class SetupViewModel extends AndroidViewModel {
enum State {AUTHOR_NAME, SET_PASSWORD, DOZE, CREATED, FAILED}
enum State {AUTHOR_NAME, SET_PASSWORD, DOZE, CREATED, FAILED, RECOVER}
private static final Logger LOG =
getLogger(SetupActivity.class.getName());
@@ -117,4 +118,9 @@ class SetupViewModel extends AndroidViewModel {
}
});
}
public void recoverClicked() {
LOG.info("RECOVER CLICKED ***");
state.postEvent(RECOVER);
}
}

View File

@@ -7,8 +7,6 @@ import org.briarproject.briar.android.AndroidComponent;
import org.briarproject.briar.android.StartupFailureActivity;
import org.briarproject.briar.android.account.AuthorNameFragment;
import org.briarproject.briar.android.account.DozeFragment;
import org.briarproject.briar.android.account.NewOrRecoverActivity;
import org.briarproject.briar.android.account.NewOrRecoverFragment;
import org.briarproject.briar.android.account.SetPasswordFragment;
import org.briarproject.briar.android.account.SetupActivity;
import org.briarproject.briar.android.account.UnlockActivity;
@@ -92,20 +90,19 @@ import org.briarproject.briar.android.sharing.ShareBlogFragment;
import org.briarproject.briar.android.sharing.ShareForumActivity;
import org.briarproject.briar.android.sharing.ShareForumFragment;
import org.briarproject.briar.android.sharing.SharingModule;
import org.briarproject.briar.android.socialbackup.SetupExplainerFragment;
import org.briarproject.briar.android.socialbackup.recover.CustodianRecoveryModeExplainerFragment;
import org.briarproject.briar.android.socialbackup.CustodianSelectorFragment;
import org.briarproject.briar.android.socialbackup.DistributedBackupActivity;
import org.briarproject.briar.android.socialbackup.SocialBackupSetupActivity;
import org.briarproject.briar.android.socialbackup.ExistingBackupFragment;
import org.briarproject.briar.android.socialbackup.recover.CustodianReturnShardActivity;
import org.briarproject.briar.android.socialbackup.recover.CustodianReturnShardErrorFragment;
import org.briarproject.briar.android.socialbackup.recover.CustodianReturnShardFragment;
import org.briarproject.briar.android.socialbackup.recover.CustodianReturnShardSuccessFragment;
import org.briarproject.briar.android.socialbackup.recover.OwnerRecoveryModeErrorFragment;
import org.briarproject.briar.android.socialbackup.recover.OwnerRecoveryModeExplainerFragment;
import org.briarproject.briar.android.socialbackup.recover.OwnerRecoveryModeMainFragment;
import org.briarproject.briar.android.socialbackup.recover.OwnerReturnShardActivity;
import org.briarproject.briar.android.socialbackup.recover.OwnerReturnShardFragment;
import org.briarproject.briar.android.socialbackup.ShardsSentFragment;
import org.briarproject.briar.android.socialbackup.ThresholdSelectorFragment;
import org.briarproject.briar.android.socialbackup.creation.CreateBackupModule;
import org.briarproject.briar.android.socialbackup.recover.OwnerReturnShardSuccessFragment;
@@ -114,7 +111,6 @@ import org.briarproject.briar.android.socialbackup.recover.RestoreAccountDozeFra
import org.briarproject.briar.android.socialbackup.recover.RestoreAccountSetPasswordFragment;
import org.briarproject.briar.android.splash.SplashScreenActivity;
import org.briarproject.briar.android.test.TestDataActivity;
import org.briarproject.briar.api.socialbackup.recovery.RestoreAccount;
import dagger.Component;
@@ -217,8 +213,6 @@ public interface ActivityComponent {
void inject(CrashReportActivity crashReportActivity);
void inject(NewOrRecoverActivity newOrRecoverActivity);
void inject(CustodianReturnShardActivity custodianReturnShardActivity);
void inject(OwnerReturnShardActivity ownerReturnShardActivity);
@@ -295,28 +289,22 @@ public interface ActivityComponent {
void inject(ThresholdSelectorFragment thresholdSelectorFragment);
void inject(DistributedBackupActivity distributedBackupActivity);
void inject(SocialBackupSetupActivity distributedBackupActivity);
void inject(DatabaseComponent databaseComponent);
void inject(CustodianSelectorFragment custodianSelectorFragment);
void inject(ShardsSentFragment shardsSentFragment);
void inject(OwnerRecoveryModeExplainerFragment ownerRecoveryModeExplainerFragment);
void inject(ExistingBackupFragment existingBackupFragment);
void inject(NewOrRecoverFragment newOrRecoverFragment);
void inject(CustodianRecoveryModeExplainerFragment custodianRecoveryModeExplainerFragment);
void inject(CustodianReturnShardFragment custodianReturnShardFragment);
void inject(OwnerReturnShardFragment ownerReturnShardFragment);
void inject(CustodianReturnShardSuccessFragment custodianReturnShardSuccessFragment);
void inject(RestoreAccountSetPasswordFragment restoreAccountSetPasswordFragment);
void inject(RestoreAccountDozeFragment restoreAccountDozeFragment);
@@ -340,4 +328,6 @@ public interface ActivityComponent {
void inject(RevokeRemoteWipeSuccessFragment revokeRemoteWipeSuccessFragment);
void inject(RemoteWipeSetupExplainerFragment remoteWipeSetupExplainerFragment);
void inject(SetupExplainerFragment setupExplainerFragment);
}

View File

@@ -7,7 +7,6 @@ import org.briarproject.bramble.api.nullsafety.MethodsNotNullByDefault;
import org.briarproject.bramble.api.nullsafety.ParametersNotNullByDefault;
import org.briarproject.briar.R;
import org.briarproject.briar.android.BriarService;
import org.briarproject.briar.android.account.NewOrRecoverActivity;
import org.briarproject.briar.android.account.SetupActivity;
import org.briarproject.briar.android.activity.ActivityComponent;
import org.briarproject.briar.android.activity.BaseActivity;
@@ -108,7 +107,7 @@ public class StartupActivity extends BaseActivity implements
private void onAccountDeleted() {
setResult(RESULT_CANCELED);
finish();
Intent i = new Intent(this, NewOrRecoverActivity.class);
Intent i = new Intent(this, SetupActivity.class);
i.addFlags(FLAG_ACTIVITY_NEW_TASK | FLAG_ACTIVITY_CLEAR_TOP |
FLAG_ACTIVITY_CLEAR_TASK | FLAG_ACTIVITY_TASK_ON_HOME);
startActivity(i);

View File

@@ -159,7 +159,8 @@ public class NavDrawerActivity extends BriarActivity implements
@Override
public void onDrawerOpened(View drawerView) {
super.onDrawerOpened(drawerView);
navDrawerViewModel.checkTransportsOnboarding();
// navDrawerViewModel.checkTransportsOnboarding();
navDrawerViewModel.checkSocialBackupOnboarding();
}
};
drawerLayout.addDrawerListener(drawerToggle);
@@ -168,9 +169,12 @@ public class NavDrawerActivity extends BriarActivity implements
initializeTransports();
transportsView.setAdapter(transportsAdapter);
observeOnce(navDrawerViewModel.showTransportsOnboarding(), this, show ->
observeOnce(torIcon, this, imageView ->
showTransportsOnboarding(show, imageView)));
// observeOnce(navDrawerViewModel.showTransportsOnboarding(), this, show ->
// observeOnce(torIcon, this, imageView ->
// showTransportsOnboarding(show, imageView)));
observeOnce(navDrawerViewModel.showSocialBackupOnboarding(), this,
this::showSocialBackupOnboarding);
lockManager.isLockable().observe(this, this::setLockVisible);
@@ -469,6 +473,22 @@ public class NavDrawerActivity extends BriarActivity implements
}
}
private void showSocialBackupOnboarding(boolean show) {
if (show) {
new MaterialTapTargetPrompt.Builder(NavDrawerActivity.this,
R.style.OnboardingDialogTheme)
.setTarget(R.id.nav_btn_settings)
.setPrimaryText(R.string.social_backup_onboarding_title)
.setSecondaryText(R.string.social_backup_onboarding_long)
.setFocalRadius((float) 350)
.setFocalPadding((float) 100)
.setBackgroundColour(
ContextCompat.getColor(this, R.color.briar_primary))
.show();
navDrawerViewModel.socialBackupOnboardingShown();
}
}
private static class Transport {
private final TransportId id;

View File

@@ -39,6 +39,8 @@ public class NavDrawerViewModel extends DbViewModel {
private static final String EXPIRY_DATE_WARNING = "expiryDateWarning";
private static final String SHOW_TRANSPORTS_ONBOARDING =
"showTransportsOnboarding";
private static final String SHOW_SOCIAL_BACKUP_ONBOARDING =
"showSocialBackupOnboarding";
private final SettingsManager settingsManager;
@@ -48,6 +50,8 @@ public class NavDrawerViewModel extends DbViewModel {
new MutableLiveData<>();
private final MutableLiveData<Boolean> showTransportsOnboarding =
new MutableLiveData<>();
private final MutableLiveData<Boolean> showSocialBackupOnboarding =
new MutableLiveData<>();
@Inject
NavDrawerViewModel(Application app,
@@ -142,6 +146,11 @@ public class NavDrawerViewModel extends DbViewModel {
return showTransportsOnboarding;
}
@UiThread
LiveData<Boolean> showSocialBackupOnboarding() {
return showSocialBackupOnboarding;
}
@UiThread
void checkTransportsOnboarding() {
if (showTransportsOnboarding.getValue() != null) return;
@@ -171,4 +180,35 @@ public class NavDrawerViewModel extends DbViewModel {
}
});
}
@UiThread
void checkSocialBackupOnboarding() {
if (showSocialBackupOnboarding.getValue() != null) return;
runOnDbThread(() -> {
try {
Settings settings =
settingsManager.getSettings(SETTINGS_NAMESPACE);
boolean show =
settings.getBoolean(SHOW_SOCIAL_BACKUP_ONBOARDING,
true);
showSocialBackupOnboarding.postValue(show);
} catch (DbException e) {
logException(LOG, WARNING, e);
}
});
}
@UiThread
void socialBackupOnboardingShown() {
showSocialBackupOnboarding.setValue(false);
runOnDbThread(() -> {
try {
Settings settings = new Settings();
settings.putBoolean(SHOW_SOCIAL_BACKUP_ONBOARDING, false);
settingsManager.mergeSettings(settings, SETTINGS_NAMESPACE);
} catch (DbException e) {
logException(LOG, WARNING, e);
}
});
}
}

View File

@@ -1,10 +1,12 @@
package org.briarproject.briar.android.settings;
import android.content.Intent;
import android.graphics.drawable.Drawable;
import android.net.Uri;
import android.os.Bundle;
import android.view.MenuItem;
import android.view.View;
import android.widget.ImageView;
import android.widget.TextView;
import android.widget.Toast;
@@ -12,6 +14,7 @@ import org.briarproject.bramble.api.FeatureFlags;
import org.briarproject.briar.R;
import org.briarproject.briar.android.activity.ActivityComponent;
import org.briarproject.briar.android.activity.BriarActivity;
import org.briarproject.briar.android.navdrawer.NavDrawerActivity;
import org.briarproject.briar.android.util.UiUtils;
import org.briarproject.briar.android.view.AuthorView;
@@ -19,11 +22,15 @@ import javax.inject.Inject;
import androidx.annotation.Nullable;
import androidx.appcompat.app.ActionBar;
import androidx.core.content.ContextCompat;
import androidx.lifecycle.ViewModelProvider;
import androidx.vectordrawable.graphics.drawable.VectorDrawableCompat;
import de.hdodenhof.circleimageview.CircleImageView;
import uk.co.samuelwall.materialtaptargetprompt.MaterialTapTargetPrompt;
import static android.widget.Toast.LENGTH_LONG;
import static org.briarproject.briar.android.activity.RequestCodes.REQUEST_AVATAR_IMAGE;
import static org.briarproject.briar.android.util.UiUtils.resolveColorAttribute;
public class SettingsActivity extends BriarActivity {

View File

@@ -23,6 +23,7 @@ import java.util.Collection;
import javax.inject.Inject;
import androidx.annotation.Nullable;
import androidx.lifecycle.ViewModelProvider;
import static java.util.Objects.requireNonNull;
@@ -32,6 +33,18 @@ public class CustodianSelectorFragment extends ContactSelectorFragment {
public static final String TAG = CustodianSelectorFragment.class.getName();
@Inject
ViewModelProvider.Factory viewModelFactory;
private SocialBackupSetupViewModel viewModel;
@Override
public void injectFragment(ActivityComponent component) {
component.inject(this);
viewModel = new ViewModelProvider(requireActivity(), viewModelFactory)
.get(SocialBackupSetupViewModel.class);
}
@Inject
CreateBackupController controller;
@@ -44,11 +57,6 @@ public class CustodianSelectorFragment extends ContactSelectorFragment {
return fragment;
}
@Override
public void injectFragment(ActivityComponent component) {
component.inject(this);
}
@Override
public void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
@@ -78,15 +86,19 @@ public class CustodianSelectorFragment extends ContactSelectorFragment {
int n = selectedContacts.size();
int min = 2;
boolean enough = n >= min;
int max = 7;
boolean amountIsValid = (n >= min) && (n <= max);
item.setVisible(enough);
item.setVisible(amountIsValid);
if (n == 0) {
Toast.makeText(getContext(), String.format(getString(R.string.select_at_least_n_contacts), min),
Toast.LENGTH_SHORT).show();
} else if (n < min) {
Toast.makeText(getContext(), String.format(getString(R.string.select_at_least_n_more_contacts), min - n),
Toast.LENGTH_SHORT).show();
} else if (n > max) {
Toast.makeText(getContext(), String.format(getString(R.string.select_no_more_than_n_contacts), max),
Toast.LENGTH_SHORT).show();
}
}

View File

@@ -1,112 +0,0 @@
package org.briarproject.briar.android.socialbackup;
import android.os.Bundle;
import android.widget.Toast;
import org.briarproject.bramble.api.contact.ContactId;
import org.briarproject.bramble.api.contact.ContactManager;
import org.briarproject.bramble.api.db.DatabaseComponent;
import org.briarproject.bramble.api.db.DbException;
import org.briarproject.briar.R;
import org.briarproject.briar.android.activity.ActivityComponent;
import org.briarproject.briar.android.activity.BriarActivity;
import org.briarproject.briar.android.contactselection.ContactSelectorListener;
import org.briarproject.briar.android.fragment.BaseFragment;
import org.briarproject.briar.api.socialbackup.BackupMetadata;
import org.briarproject.briar.api.socialbackup.SocialBackupManager;
import java.util.Collection;
import java.util.List;
import javax.inject.Inject;
public class DistributedBackupActivity extends BriarActivity implements
BaseFragment.BaseFragmentListener, ContactSelectorListener,
ThresholdDefinedListener,
ShardsSentFragment.ShardsSentDismissedListener {
private Collection<ContactId> custodians;
@Inject
public SocialBackupManager socialBackupManager;
@Inject
public ContactManager contactManager;
@Inject
public DatabaseComponent db;
@Override
public void injectActivity(ActivityComponent component) {
component.inject(this);
}
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_distributed_backup);
try {
db.transaction(false, txn -> {
BackupMetadata backupMetadata =
socialBackupManager.getBackupMetadata(txn);
if (backupMetadata == null) throw new DbException();
ExistingBackupFragment fragment =
ExistingBackupFragment.newInstance(backupMetadata);
showInitialFragment(fragment);
});
} catch (DbException e) {
// Check the number of contacts in the contacts list > 1
try {
if (contactManager.getContacts().size() < 2) {
Toast.makeText(this,
R.string.social_backup_not_enough_contacts,
Toast.LENGTH_LONG).show();
finish();
}
} catch (DbException dbException) {
Toast.makeText(this,
R.string.reading_contacts_error,
Toast.LENGTH_LONG).show();
finish();
}
CustodianSelectorFragment fragment =
CustodianSelectorFragment.newInstance();
showInitialFragment(fragment);
}
}
@Override
public void contactsSelected(Collection<ContactId> contacts) {
Toast.makeText(this,
String.format("Selected %d contacts", contacts.size()),
Toast.LENGTH_SHORT).show();
custodians = contacts;
ThresholdSelectorFragment fragment =
ThresholdSelectorFragment.newInstance(contacts.size());
showNextFragment(fragment);
}
@Override
public void thresholdDefined(int threshold) {
try {
db.transaction(false, txn -> {
socialBackupManager
.createBackup(txn, (List<ContactId>) custodians,
threshold);
ShardsSentFragment fragment = new ShardsSentFragment();
showNextFragment(fragment);
});
} catch (DbException e) {
Toast.makeText(this,
"There was an error when creating the backup",
Toast.LENGTH_LONG).show();
finish();
}
}
@Override
public void shardsSentDismissed() {
finish();
}
}

View File

@@ -7,6 +7,7 @@ import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;
import org.briarproject.bramble.api.db.DbException;
import org.briarproject.bramble.api.identity.Author;
import org.briarproject.briar.R;
import org.briarproject.briar.android.activity.ActivityComponent;
@@ -16,8 +17,11 @@ import org.briarproject.briar.api.socialbackup.BackupMetadata;
import java.util.ArrayList;
import java.util.List;
import javax.inject.Inject;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.lifecycle.ViewModelProvider;
public class ExistingBackupFragment extends BaseFragment {
@@ -25,19 +29,16 @@ public class ExistingBackupFragment extends BaseFragment {
private static final String CUSTODIANS = "custodians";
public static final String TAG = ExistingBackupFragment.class.getName();
public static ExistingBackupFragment newInstance(
BackupMetadata backupMetadata) {
Bundle bundle = new Bundle();
List<Author> custodians = backupMetadata.getCustodians();
ArrayList custodianNames = new ArrayList();
for (Author custodian : custodians) {
custodianNames.add(custodian.getName());
}
bundle.putStringArrayList(CUSTODIANS, custodianNames);
bundle.putInt(THRESHOLD, backupMetadata.getThreshold());
ExistingBackupFragment fragment = new ExistingBackupFragment();
fragment.setArguments(bundle);
return fragment;
@Inject
ViewModelProvider.Factory viewModelFactory;
private SocialBackupSetupViewModel viewModel;
@Override
public void injectFragment(ActivityComponent component) {
component.inject(this);
viewModel = new ViewModelProvider(requireActivity(), viewModelFactory)
.get(SocialBackupSetupViewModel.class);
}
@Override
@@ -53,20 +54,20 @@ public class ExistingBackupFragment extends BaseFragment {
ViewGroup container, @Nullable Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.fragment_existing_backup,
container, false);
Bundle args = requireArguments();
ArrayList<String> custodianNames = args.getStringArrayList(CUSTODIANS);
BackupMetadata backupMetadata = viewModel.getBackupMetadata();
List<Author> custodians = backupMetadata.getCustodians();
StringBuilder custodianNamesString = new StringBuilder();
for (String custodianName : custodianNames) {
for (Author custodian : custodians) {
custodianNamesString
.append("")
.append(custodianName)
.append(custodian.getName())
.append("\n");
}
TextView textViewThreshold = view.findViewById(R.id.textViewThreshold);
textViewThreshold.setText(getString(R.string.existing_backup_explain,
args.getInt(THRESHOLD)));
backupMetadata.getThreshold()));
TextView textViewCustodians =
view.findViewById(R.id.textViewCustodians);
textViewCustodians.setText(custodianNamesString);
@@ -79,15 +80,9 @@ public class ExistingBackupFragment extends BaseFragment {
// listener = (ShardsSentDismissedListener) context;
}
@Override
public String getUniqueTag() {
return TAG;
}
@Override
public void injectFragment(ActivityComponent component) {
component.inject(this);
}
}

View File

@@ -1,4 +1,4 @@
package org.briarproject.briar.android.socialbackup.recover;
package org.briarproject.briar.android.socialbackup;
import android.os.Bundle;
import android.view.LayoutInflater;
@@ -6,8 +6,6 @@ import android.view.View;
import android.view.ViewGroup;
import android.widget.Button;
import org.briarproject.bramble.api.nullsafety.MethodsNotNullByDefault;
import org.briarproject.bramble.api.nullsafety.ParametersNotNullByDefault;
import org.briarproject.briar.R;
import org.briarproject.briar.android.activity.ActivityComponent;
import org.briarproject.briar.android.fragment.BaseFragment;
@@ -18,37 +16,33 @@ import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.lifecycle.ViewModelProvider;
@MethodsNotNullByDefault
@ParametersNotNullByDefault
public class CustodianReturnShardSuccessFragment extends
BaseFragment {
public class SetupExplainerFragment extends BaseFragment {
public static final String TAG =
CustodianReturnShardFragment.class.getName();
SetupExplainerFragment.class.getName();
@Inject
ViewModelProvider.Factory viewModelFactory;
private CustodianReturnShardViewModel viewModel;
private SocialBackupSetupViewModel viewModel;
@Override
public void injectFragment(ActivityComponent component) {
component.inject(this);
viewModel = new ViewModelProvider(requireActivity(), viewModelFactory)
.get(CustodianReturnShardViewModel.class);
.get(SocialBackupSetupViewModel.class);
}
@Nullable
@Override
public View onCreateView(@NonNull LayoutInflater inflater,
@Nullable ViewGroup container,
@Nullable Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.fragment_recovery_custodian_done,
container, false);
public View onCreateView(@NonNull LayoutInflater inflater, @Nullable
ViewGroup container, @Nullable Bundle savedInstanceState) {
View view =
inflater.inflate(R.layout.fragment_social_backup_setup_explainer,
container, false);
Button button = view.findViewById(R.id.button);
button.setOnClickListener(e -> viewModel.onSuccessDismissed());
button.setOnClickListener(e -> viewModel.onExplainerDismissed());
return view;
}
@@ -57,3 +51,4 @@ public class CustodianReturnShardSuccessFragment extends
return TAG;
}
}

View File

@@ -1,74 +0,0 @@
package org.briarproject.briar.android.socialbackup;
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 org.briarproject.briar.R;
import org.briarproject.briar.android.activity.ActivityComponent;
import org.briarproject.briar.android.fragment.BaseFragment;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.annotation.UiThread;
public class ShardsSentFragment extends BaseFragment {
public static final String TAG = ShardsSentFragment.class.getName();
interface ShardsSentDismissedListener {
@UiThread
void shardsSentDismissed();
}
protected ShardsSentDismissedListener listener;
@Override
public void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
requireActivity().setTitle(R.string.title_distributed_backup);
}
@Nullable
@Override
public View onCreateView(@NonNull LayoutInflater inflater,
@Nullable ViewGroup container,
@Nullable Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.fragment_shards_sent,
container, false);
Button button = view.findViewById(R.id.button);
button.setOnClickListener(e -> {
listener.shardsSentDismissed();
});
return view;
}
@Override
public void onAttach(Context context) {
super.onAttach(context);
listener = (ShardsSentDismissedListener) context;
}
@Override
public String getUniqueTag() {
return TAG;
}
@Override
public void injectFragment(ActivityComponent component) {
component.inject(this);
}
public void onBackPressed() {
listener.shardsSentDismissed();
}
}

View File

@@ -0,0 +1,93 @@
package org.briarproject.briar.android.socialbackup;
import android.os.Bundle;
import android.widget.Toast;
import org.briarproject.bramble.api.contact.ContactId;
import org.briarproject.bramble.api.db.DbException;
import org.briarproject.briar.R;
import org.briarproject.briar.android.activity.ActivityComponent;
import org.briarproject.briar.android.activity.BriarActivity;
import org.briarproject.briar.android.contactselection.ContactSelectorListener;
import org.briarproject.briar.android.fragment.BaseFragment;
import java.util.Collection;
import javax.inject.Inject;
import androidx.lifecycle.ViewModelProvider;
public class SocialBackupSetupActivity extends BriarActivity implements
BaseFragment.BaseFragmentListener, ContactSelectorListener {
private SocialBackupSetupViewModel viewModel;
@Inject
ViewModelProvider.Factory viewModelFactory;
@Override
public void injectActivity(ActivityComponent component) {
component.inject(this);
viewModel = new ViewModelProvider(this, viewModelFactory)
.get(SocialBackupSetupViewModel.class);
}
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_distributed_backup);
if (viewModel.haveExistingBackup()) {
showInitialFragment(new ExistingBackupFragment());
} else {
try {
if (!viewModel.haveEnoughContacts()) {
Toast.makeText(this,
R.string.social_backup_not_enough_contacts,
Toast.LENGTH_LONG).show();
finish();
}
} catch (DbException dbException) {
Toast.makeText(this,
R.string.reading_contacts_error,
Toast.LENGTH_LONG).show();
finish();
}
showInitialFragment(new SetupExplainerFragment());
}
viewModel.getState()
.observe(this, this::onStateChanged);
}
private void onStateChanged(SocialBackupSetupViewModel.State state) {
switch (state) {
case SUCCESS:
finish();
break;
case FAILURE:
Toast.makeText(this,
"There was an error when creating the backup",
Toast.LENGTH_LONG).show();
finish();
break;
case CHOOSING_CUSTODIANS:
CustodianSelectorFragment fragment =
CustodianSelectorFragment.newInstance();
showNextFragment(fragment);
break;
}
}
@Override
public void contactsSelected(Collection<ContactId> contacts) {
Toast.makeText(this,
String.format("Selected %d contacts", contacts.size()),
Toast.LENGTH_SHORT).show();
viewModel.setCustodians(contacts);
ThresholdSelectorFragment fragment =
ThresholdSelectorFragment.newInstance(contacts.size());
showNextFragment(fragment);
}
}

View File

@@ -0,0 +1,20 @@
package org.briarproject.briar.android.socialbackup;
import org.briarproject.briar.android.socialbackup.recover.CustodianReturnShardViewModel;
import org.briarproject.briar.android.viewmodel.ViewModelKey;
import androidx.lifecycle.ViewModel;
import dagger.Binds;
import dagger.Module;
import dagger.multibindings.IntoMap;
@Module
public abstract class SocialBackupSetupModule {
@Binds
@IntoMap
@ViewModelKey(SocialBackupSetupViewModel.class)
abstract ViewModel bindSocialBackupSetupViewModel(
SocialBackupSetupViewModel socialBackupSetupViewModel);
}

View File

@@ -0,0 +1,106 @@
package org.briarproject.briar.android.socialbackup;
import android.app.Application;
import org.briarproject.bramble.api.contact.ContactId;
import org.briarproject.bramble.api.contact.ContactManager;
import org.briarproject.bramble.api.db.DatabaseComponent;
import org.briarproject.bramble.api.db.DbException;
import org.briarproject.briar.api.socialbackup.BackupMetadata;
import org.briarproject.briar.api.socialbackup.SocialBackupManager;
import java.util.Collection;
import java.util.List;
import javax.inject.Inject;
import androidx.annotation.NonNull;
import androidx.lifecycle.AndroidViewModel;
import androidx.lifecycle.MutableLiveData;
public class SocialBackupSetupViewModel extends AndroidViewModel {
private final SocialBackupManager socialBackupManager;
private final DatabaseComponent db;
private final ContactManager contactManager;
private BackupMetadata backupMetadata;
private Collection<ContactId> custodians;
private int threshold;
public enum State {
EXPLAINING,
CHOOSING_CUSTODIANS,
GETTING_THRESHOLD,
SUCCESS,
FAILURE
}
private final MutableLiveData<State> state =
new MutableLiveData<>();
@Inject
public SocialBackupSetupViewModel(
@NonNull Application app,
DatabaseComponent db,
SocialBackupManager socialBackupManager,
ContactManager contactManager
) {
super(app);
this.socialBackupManager = socialBackupManager;
this.db = db;
this.contactManager = contactManager;
}
public boolean haveExistingBackup() {
try {
backupMetadata = db.transactionWithNullableResult(true,
socialBackupManager::getBackupMetadata);
} catch (DbException e) {
return false;
}
return (backupMetadata != null);
}
public BackupMetadata getBackupMetadata() {
return backupMetadata;
}
public boolean haveEnoughContacts() throws DbException {
return (contactManager.getContacts().size() > 1);
}
public void setCustodians(Collection<ContactId> contacts) {
custodians = contacts;
}
public void createBackup() {
try {
db.transaction(false, txn -> {
socialBackupManager
.createBackup(txn, (List<ContactId>) custodians,
threshold);
});
} catch (DbException e) {
state.postValue(State.FAILURE);
}
}
public void setThreshold(int threshold) {
this.threshold = threshold;
createBackup();
}
public void onSuccessDismissed() {
state.postValue(State.SUCCESS);
}
public MutableLiveData<State> getState() {
return state;
}
public void onExplainerDismissed() {
state.postValue(State.CHOOSING_CUSTODIANS);
}
}

View File

@@ -1,12 +0,0 @@
package org.briarproject.briar.android.socialbackup;
import org.briarproject.bramble.api.db.DbException;
import androidx.annotation.UiThread;
public interface ThresholdDefinedListener {
@UiThread
void thresholdDefined(int threshold) throws DbException;
}

View File

@@ -2,6 +2,10 @@ package org.briarproject.briar.android.socialbackup;
import android.content.Context;
import android.os.Bundle;
import android.text.Spannable;
import android.text.SpannableString;
import android.text.SpannableStringBuilder;
import android.text.style.ImageSpan;
import android.view.LayoutInflater;
import android.view.Menu;
import android.view.MenuInflater;
@@ -11,22 +15,25 @@ import android.view.ViewGroup;
import android.widget.SeekBar;
import android.widget.TextView;
import org.briarproject.bramble.api.db.DbException;
import org.briarproject.briar.R;
import org.briarproject.briar.android.activity.ActivityComponent;
import org.briarproject.briar.android.fragment.BaseFragment;
import org.magmacollective.darkcrystal.secretsharingwrapper.SecretSharingWrapper;
import java.util.Arrays;
import javax.inject.Inject;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.appcompat.app.AlertDialog;
import androidx.lifecycle.ViewModelProvider;
public class ThresholdSelectorFragment extends BaseFragment {
public static final String TAG = ThresholdSelectorFragment.class.getName();
private static final String NUMBER_CUSTODIANS = "numberCustodians";
protected ThresholdDefinedListener listener;
private int numberOfCustodians;
private int threshold;
private int recommendedThreshold;
@@ -35,6 +42,18 @@ public class ThresholdSelectorFragment extends BaseFragment {
private TextView message;
private TextView mOfn;
@Inject
ViewModelProvider.Factory viewModelFactory;
private SocialBackupSetupViewModel viewModel;
@Override
public void injectFragment(ActivityComponent component) {
component.inject(this);
viewModel = new ViewModelProvider(requireActivity(), viewModelFactory)
.get(SocialBackupSetupViewModel.class);
}
public static ThresholdSelectorFragment newInstance(int numberCustodians) {
Bundle bundle = new Bundle();
bundle.putInt(NUMBER_CUSTODIANS, numberCustodians);
@@ -94,7 +113,6 @@ public class ThresholdSelectorFragment extends BaseFragment {
@Override
public void onAttach(Context context) {
super.onAttach(context);
listener = (ThresholdDefinedListener) context;
}
@@ -103,11 +121,6 @@ public class ThresholdSelectorFragment extends BaseFragment {
return TAG;
}
@Override
public void injectFragment(ActivityComponent component) {
component.inject(this);
}
@Override
public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
inflater.inflate(R.menu.define_threshold_actions, menu);
@@ -118,26 +131,42 @@ public class ThresholdSelectorFragment extends BaseFragment {
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
case R.id.action_threshold_defined:
try {
listener.thresholdDefined(threshold);
} catch (DbException e) {
e.printStackTrace();
}
viewModel.setThreshold(threshold);
showSuccessDialog();
return true;
default:
return super.onOptionsItemSelected(item);
}
}
private String buildThresholdRepresentationString() {
String thresholdRepresentationText = "";
for (int i = 0; i < threshold; i++) {
thresholdRepresentationText += getString(R.string.filled_bullet);
private void showSuccessDialog() {
AlertDialog.Builder builder = new AlertDialog.Builder(requireContext(),
R.style.BriarDialogTheme);
builder.setTitle(R.string.backup_created);
builder.setMessage(R.string.backup_done_info);
builder.setPositiveButton(R.string.ok,
(dialog, which) -> viewModel.onSuccessDismissed());
builder.setIcon(R.drawable.ic_baseline_done_outline_24);
AlertDialog dialog = builder.create();
dialog.show();
}
private SpannableStringBuilder buildThresholdRepresentationString() {
char[] charArray = new char[numberOfCustodians];
Arrays.fill(charArray, ' ');
SpannableStringBuilder string = new SpannableStringBuilder(new String(charArray));
for (int i = 0; i < numberOfCustodians; i++) {
int drawable = i < threshold
? R.drawable.ic_custodian_required
: R.drawable.ic_custodian_optional;
string.setSpan(new ImageSpan(getContext(), drawable), i,
i+1,
Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
}
for (int i = 0; i < (numberOfCustodians - threshold); i++) {
thresholdRepresentationText += getString(R.string.linear_bullet);
}
return thresholdRepresentationText;
// If we have more than 6, split it on two lines
if (numberOfCustodians > 6) string.insert(4, "\n");
return string;
}
private class SeekBarListener implements SeekBar.OnSeekBarChangeListener {

View File

@@ -32,11 +32,6 @@ public class CustodianRecoveryModeExplainerFragment extends BaseFragment {
viewModel = new ViewModelProvider(requireActivity(), viewModelFactory)
.get(CustodianReturnShardViewModel.class);
}
// @Override
// public void onCreate(@Nullable Bundle savedInstanceState) {
// super.onCreate(savedInstanceState);
// requireActivity().setTitle(R.string.title_help_recover);
// }
@Nullable
@Override

View File

@@ -13,7 +13,6 @@ import org.briarproject.briar.android.fragment.BaseFragment;
import org.briarproject.briar.api.socialbackup.recovery.CustodianTask;
import java.io.IOException;
import java.util.logging.Logger;
import javax.annotation.Nullable;
import javax.inject.Inject;
@@ -21,17 +20,12 @@ import javax.inject.Inject;
import androidx.fragment.app.FragmentManager;
import androidx.lifecycle.ViewModelProvider;
import static android.content.Intent.FLAG_ACTIVITY_CLEAR_TOP;
import static java.util.logging.Logger.getLogger;
import static org.briarproject.briar.android.conversation.ConversationActivity.CONTACT_ID;
public class CustodianReturnShardActivity extends BriarActivity
implements BaseFragment.BaseFragmentListener {
private CustodianReturnShardViewModel viewModel;
private static final Logger LOG =
getLogger(CustodianReturnShardActivity.class.getName());
private ContactId contactId;
@Inject
ViewModelProvider.Factory viewModelFactory;
@@ -52,7 +46,7 @@ public class CustodianReturnShardActivity extends BriarActivity
Intent intent = getIntent();
int id = intent.getIntExtra(CONTACT_ID, -1);
if (id == -1) throw new IllegalStateException("No ContactId");
contactId = new ContactId(id);
ContactId contactId = new ContactId(id);
try {
viewModel.start(contactId);
@@ -96,7 +90,8 @@ public class CustodianReturnShardActivity extends BriarActivity
"It looks like you are not connected to a Wifi network",
Toast.LENGTH_SHORT).show();
FragmentManager fm = getSupportFragmentManager();
if (fm.findFragmentByTag(CustodianReturnShardFragment.TAG) == null) {
if (fm.findFragmentByTag(CustodianReturnShardFragment.TAG) ==
null) {
BaseFragment f = new CustodianReturnShardErrorFragment();
fm.beginTransaction()
.replace(R.id.fragmentContainer, f, f.getUniqueTag())
@@ -106,19 +101,15 @@ public class CustodianReturnShardActivity extends BriarActivity
}
}
private void onReturnShardStateChanged(CustodianTask.State state) {
if (state instanceof CustodianTask.State.Success) {
CustodianReturnShardSuccessFragment fragment = new CustodianReturnShardSuccessFragment();
showNextFragment(fragment);
} else if (state instanceof CustodianTask.State.Failure) {
// TODO error fragment here
// TODO handle reason
Toast.makeText(this,
"Backup piece transfer failed",
Toast.LENGTH_SHORT).show();
finish();
}
if (state instanceof CustodianTask.State.Failure) {
// TODO error fragment here
// TODO handle reason
Toast.makeText(this,
"Backup piece transfer failed",
Toast.LENGTH_SHORT).show();
finish();
}
}
private void showCameraFragment() {

View File

@@ -5,6 +5,7 @@ import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.LinearLayout;
import android.widget.ProgressBar;
import android.widget.TextView;
import android.widget.Toast;
@@ -24,6 +25,7 @@ import javax.annotation.Nullable;
import javax.inject.Inject;
import androidx.annotation.UiThread;
import androidx.appcompat.app.AlertDialog;
import androidx.lifecycle.ViewModelProvider;
import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_NOSENSOR;
@@ -53,6 +55,7 @@ public class CustodianReturnShardFragment extends BaseFragment
private LinearLayout cameraOverlay;
private View statusView;
private TextView status;
private ProgressBar bottomSpinner;
public static CustodianReturnShardFragment newInstance() {
Bundle args = new Bundle();
@@ -84,6 +87,7 @@ public class CustodianReturnShardFragment extends BaseFragment
cameraOverlay = view.findViewById(R.id.camera_overlay);
statusView = view.findViewById(R.id.status_container);
status = view.findViewById(R.id.connect_status);
bottomSpinner = view.findViewById(R.id.qr_code_progress_bar);
viewModel.getState().observe(getViewLifecycleOwner(),
this::onReturnShardStateChanged);
@@ -141,7 +145,6 @@ public class CustodianReturnShardFragment extends BaseFragment
@UiThread
private void onReturnShardStateChanged(@Nullable CustodianTask.State state) {
LOG.info("State changed");
// if (state instanceof CustodianTask.State.Connecting) {
// try {
// cameraView.stop();
@@ -163,8 +166,9 @@ public class CustodianReturnShardFragment extends BaseFragment
} else if (state instanceof CustodianTask.State.ReceivingAck) {
status.setText("Receiving Ack");
} else if (state instanceof CustodianTask.State.Success) {
// TODO
status.setText(R.string.exchanging_contact_details);
statusView.setVisibility(INVISIBLE);
bottomSpinner.setVisibility(INVISIBLE);
showSuccessDialog();
} else if (state instanceof CustodianTask.State.Failure) {
// the activity will replace this fragment with an error fragment
statusView.setVisibility(INVISIBLE);
@@ -190,4 +194,15 @@ public class CustodianReturnShardFragment extends BaseFragment
requireActivity().getSupportFragmentManager().popBackStack();
}
private void showSuccessDialog() {
AlertDialog.Builder builder = new AlertDialog.Builder(requireContext(),
R.style.BriarDialogTheme);
builder.setTitle(R.string.custodian_shard_sent);
//builder.setMessage();
builder.setPositiveButton(R.string.ok,
(dialog, which) -> viewModel.onSuccessDismissed());
builder.setIcon(R.drawable.ic_baseline_done_outline_24);
AlertDialog dialog = builder.create();
dialog.show();
}
}

View File

@@ -53,7 +53,7 @@ public class CustodianReturnShardViewModel extends AndroidViewModel
final QrCodeDecoder qrCodeDecoder;
private boolean qrCodeRead = false;
private WifiManager wifiManager;
private final MutableLiveEvent<Boolean > continueClicked = new MutableLiveEvent<>();
private final MutableLiveEvent<Boolean> continueClicked = new MutableLiveEvent<>();
private final MutableLiveEvent<Boolean> showCameraFragment =
new MutableLiveEvent<>();
private final MutableLiveEvent<Boolean> successDismissed =
@@ -177,7 +177,6 @@ public class CustodianReturnShardViewModel extends AndroidViewModel
successDismissed.setEvent(true);
}
QrCodeDecoder getQrCodeDecoder() {
return qrCodeDecoder;
}

View File

@@ -44,13 +44,6 @@ public class OwnerReturnShardActivity extends BaseActivity
private OwnerReturnShardViewModel viewModel;
// private final ActivityResultLauncher<String[]> permissionLauncher =
// registerForActivityResult(
// new ActivityResultContracts.RequestMultiplePermissions(),
// r ->
// permissionManager.onRequestPermissionResult(r,
// viewModel::showQrCodeFragmentIfAllowed));
@Override
public void injectActivity(ActivityComponent component) {
component.inject(this);
@@ -154,7 +147,8 @@ public class OwnerReturnShardActivity extends BaseActivity
"WARNING: Mismatched backup piece!",
Toast.LENGTH_LONG).show();
}
boolean added = (result != RestoreAccount.AddReturnShardPayloadResult.DUPLICATE) ? true : false;
boolean added = result !=
RestoreAccount.AddReturnShardPayloadResult.DUPLICATE;
Toast.makeText(this,
"Success - got backup piece" + (added ? "" : " duplicate"),
Toast.LENGTH_SHORT).show();

View File

@@ -27,7 +27,6 @@ import androidx.lifecycle.ViewModelProvider;
import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_NOSENSOR;
import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED;
import static android.view.View.INVISIBLE;
import static android.view.View.VISIBLE;
import static android.view.ViewGroup.LayoutParams.MATCH_PARENT;
import static android.widget.LinearLayout.HORIZONTAL;
@@ -158,5 +157,4 @@ public class OwnerReturnShardFragment extends BaseFragment
protected void finish() {
requireActivity().getSupportFragmentManager().popBackStack();
}
}

View File

@@ -0,0 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:color="@color/briar_button_text_positive" android:state_enabled="true"/>
<item android:color="@color/briar_button_text_disabled" />
</selector>

View File

@@ -0,0 +1,5 @@
<vector android:height="48dp" android:tint="#660066"
android:viewportHeight="24.0" android:viewportWidth="24.0"
android:width="48dp" xmlns:android="http://schemas.android.com/apk/res/android">
<path android:fillColor="#FF000000" android:pathData="M12,12c2.21,0 4,-1.79 4,-4s-1.79,-4 -4,-4 -4,1.79 -4,4 1.79,4 4,4zM12,14c-2.67,0 -8,1.34 -8,4v2h16v-2c0,-2.66 -5.33,-4 -8,-4z"/>
</vector>

View File

@@ -0,0 +1,5 @@
<vector android:height="48dp" android:tint="#FF00FF"
android:viewportHeight="24.0" android:viewportWidth="24.0"
android:width="48dp" xmlns:android="http://schemas.android.com/apk/res/android">
<path android:fillColor="#FF000000" android:pathData="M12,12c2.21,0 4,-1.79 4,-4s-1.79,-4 -4,-4 -4,1.79 -4,4 1.79,4 4,4zM12,14c-2.67,0 -8,1.34 -8,4v2h16v-2c0,-2.66 -5.33,-4 -8,-4z"/>
</vector>

View File

@@ -0,0 +1,7 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:height="72dp"
android:width="72dp"
android:viewportWidth="24"
android:viewportHeight="24">
<path android:fillColor="#000" android:pathData="M12,5.5A3.5,3.5 0 0,1 15.5,9A3.5,3.5 0 0,1 12,12.5A3.5,3.5 0 0,1 8.5,9A3.5,3.5 0 0,1 12,5.5M5,8C5.56,8 6.08,8.15 6.53,8.42C6.38,9.85 6.8,11.27 7.66,12.38C7.16,13.34 6.16,14 5,14A3,3 0 0,1 2,11A3,3 0 0,1 5,8M19,8A3,3 0 0,1 22,11A3,3 0 0,1 19,14C17.84,14 16.84,13.34 16.34,12.38C17.2,11.27 17.62,9.85 17.47,8.42C17.92,8.15 18.44,8 19,8M5.5,18.25C5.5,16.18 8.41,14.5 12,14.5C15.59,14.5 18.5,16.18 18.5,18.25V20H5.5V18.25M0,20V18.5C0,17.11 1.89,15.94 4.45,15.6C3.86,16.28 3.5,17.22 3.5,18.25V20H0M24,20H20.5V18.25C20.5,17.22 20.14,16.28 19.55,15.6C22.11,15.94 24,17.11 24,18.5V20Z" />
</vector>

View File

@@ -16,6 +16,7 @@
app:title="@string/setup_title"
app:titleTextColor="@android:color/white" />
<include layout="@layout/fragment_start" />
<!-- <include layout="@layout/fragment_start" />-->
<include layout="@layout/fragment_new_or_recover" />
</LinearLayout>

View File

@@ -13,22 +13,38 @@
<Button
android:id="@+id/buttonSetupNewAccount"
style="@style/BriarButton"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:drawableLeft="@drawable/ic_contacts"
android:text="@string/setup_new_account"
android:drawableLeft="@drawable/ic_contacts"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
app:layout_constraintTop_toTopOf="parent"
android:drawableStart="@drawable/ic_contacts" />
<TextView
android:id="@+id/textViewExplain"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="24dp"
android:gravity="center"
android:text="@string/custodian_recovery_explainer_extra"
android:textSize="20sp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/buttonSetupNewAccount"
tools:layout_editor_absoluteX="16dp" />
<Button
android:id="@+id/buttonRestoreAccount"
android:id="@+id/buttonRestoreAccount2"
style="@style/BriarButton"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:drawableLeft="@drawable/ic_repeat"
android:text="@string/setup_restore_account"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/buttonSetupNewAccount" />
app:layout_constraintTop_toBottomOf="@+id/textViewExplain"
tools:enabled="true"
android:drawableStart="@drawable/ic_repeat" />
</androidx.constraintlayout.widget.ConstraintLayout>

View File

@@ -47,14 +47,28 @@
android:layout_height="wrap_content"
android:layout_marginTop="@dimen/margin_activity_horizontal"
android:enabled="false"
android:text="@string/setup_next"
app:layout_constraintBottom_toBottomOf="parent"
android:text="@string/setup_new_account"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toBottomOf="@+id/nickname_entry_wrapper"
app:layout_constraintVertical_bias="1.0"
tools:enabled="true" />
<Button
android:id="@+id/buttonRestoreAccount"
style="@style/BriarButtonFlat.Positive.Tiny"
android:textColor="@drawable/button_positive_tiny_disable"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="@dimen/margin_activity_horizontal"
android:text="@string/setup_restore_account"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toBottomOf="@+id/next"
app:layout_constraintVertical_bias="1.0"
tools:enabled="true" />
</androidx.constraintlayout.widget.ConstraintLayout>
</ScrollView>

View File

@@ -1,50 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<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:id="@+id/linearLayout"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingLeft="@dimen/margin_large"
android:paddingTop="@dimen/margin_medium"
android:paddingRight="@dimen/margin_large"
android:paddingBottom="@dimen/margin_medium">
<Button
android:id="@+id/button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="32dp"
android:text="@string/ok"
android:textSize="24sp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/textView2" />
<TextView
android:id="@+id/textView2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="16dp"
android:text="@string/backup_done_info"
android:gravity="center"
android:textSize="30sp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/imageView2" />
<ImageView
android:id="@+id/imageView2"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_marginStart="32dp"
android:layout_marginLeft="32dp"
android:layout_marginTop="8dp"
android:layout_marginEnd="32dp"
android:layout_marginRight="32dp"
app:layout_constraintDimensionRatio="1:1"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:srcCompat="@drawable/ic_baseline_done_outline_24" />
</androidx.constraintlayout.widget.ConstraintLayout>

View File

@@ -8,43 +8,52 @@
android:paddingLeft="@dimen/margin_large"
android:paddingTop="@dimen/margin_medium"
android:paddingRight="@dimen/margin_large"
android:paddingBottom="@dimen/margin_medium">
android:paddingBottom="@dimen/margin_medium"
tools:ignore="VectorDrawableCompat">
<TextView
android:id="@+id/textView"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="24dp"
android:gravity="center"
android:text="@string/social_backup_setup_explainer_title"
android:textSize="24sp"
app:layout_constraintTop_toTopOf="parent"
tools:layout_editor_absoluteX="16dp" />
<ImageView
android:id="@+id/imageView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="12dp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/textView"
app:srcCompat="@drawable/ic_social_backup_group" />
<TextView
android:id="@+id/textViewExplain"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="12dp"
android:gravity="center"
android:text="@string/social_backup_setup_explainer_long"
android:textSize="20sp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/imageView"
tools:layout_editor_absoluteX="16dp" />
<Button
android:id="@+id/button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="32dp"
android:text="@string/ok"
android:textSize="24sp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/textView2" />
<TextView
android:id="@+id/textView2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="16dp"
android:gravity="center"
android:text="@string/custodian_shard_sent"
android:textSize="30sp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/imageView2" />
<ImageView
android:id="@+id/imageView2"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_marginStart="32dp"
android:layout_marginLeft="32dp"
android:layout_marginTop="8dp"
android:layout_marginEnd="32dp"
android:layout_marginRight="32dp"
app:layout_constraintDimensionRatio="1:1"
android:layout_height="wrap_content"
android:layout_marginTop="24dp"
android:text="@string/social_backup_setup_explainer_button"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.0"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:srcCompat="@drawable/ic_baseline_done_outline_24" />
app:layout_constraintTop_toBottomOf="@+id/textViewExplain" />
</androidx.constraintlayout.widget.ConstraintLayout>

View File

@@ -6,6 +6,7 @@
<ProgressBar
style="?android:attr/progressBarStyleLarge"
android:id="@+id/qr_code_progress_bar"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center" />

View File

@@ -653,6 +653,8 @@
<string name="select_custodians">Select Trusted Contacts:</string>
<string name="select_at_least_n_contacts">Please select at least %d contacts</string>
<string name="select_at_least_n_more_contacts">Please select at least %d more contacts</string>
<string name="select_no_more_than_n_contacts">Too many! Please select no more than %d contacts</string>
<string name="threshold">Choose the minimum number of trusted contacts needed to restore your account</string>
<string name="threshold_disabled">Two trusted contacts will be needed to restore your account</string>
<string name="threshold_secure">Secure</string>
@@ -661,9 +663,21 @@
<string name="threshold_high_insecure">Danger of loss lower threshold recommended</string>
<string name="threshold_defined">Choose Threshold</string>
<string name="threshold_m_of_n">%d of %d contacts needed to recover your account</string>
<string name="backup_done_info">Backup pieces sent to trusted contacts</string>
<!-- Recovery from the secret owner's POV -->
<string name="backup_created">Social Backup created</string>
<string name="backup_done_info">Backup pieces sent to trusted contacts</string>
<string name="social_backup_setup_explainer_title">Backup your Briar identity and contacts list</string>
<string name="social_backup_setup_explainer_long">Choose a set of trusted contacts to send backup pieces to.\n\nYou decide how many of these contacts must help you recover your account.\n\nFor example, you can choose three trusted contacts and that any two of them are needed to recover.</string>
<string name="social_backup_setup_explainer_button">Choose trusted contacts</string>
<string name="social_backup_onboarding_title">Backup your Briar account</string>
<string name="social_backup_onboarding_long">Social backup feature allows you to recover your account with the help of trusted contacts</string>
<!-- recovery from the secret owner's POV -->
<string name="recovery_explainer">You need to meet your trusted contacts in-person to receive pieces</string>
<string name="recovery_explainer_extra">Your trusted contact must scan a QR code to initiate the transfer.\n\nYou must both be connected to the same wifi network</string>
<string name="recovery_begin">Begin</string>

View File

@@ -96,7 +96,7 @@
app:iconSpaceReserved="false">
<intent
android:targetClass="org.briarproject.briar.android.socialbackup.DistributedBackupActivity"
android:targetClass="org.briarproject.briar.android.socialbackup.SocialBackupSetupActivity"
android:targetPackage="@string/app_package" />
</Preference>