mirror of
https://code.briarproject.org/briar/briar.git
synced 2026-02-13 03:09:04 +01:00
UI for error and explainer fragments
This commit is contained in:
@@ -88,6 +88,7 @@ import org.briarproject.briar.android.socialbackup.recover.CustodianReturnShardA
|
||||
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;
|
||||
@@ -302,5 +303,7 @@ public interface ActivityComponent {
|
||||
|
||||
void inject(OwnerReturnShardSuccessFragment ownerReturnShardSuccessFragment);
|
||||
|
||||
void inject(OwnerRecoveryModeErrorFragment ownerRecoveryModeErrorFragment);
|
||||
|
||||
void inject(CustodianReturnShardErrorFragment custodianReturnShardErrorFragment);
|
||||
}
|
||||
|
||||
@@ -21,6 +21,7 @@ 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;
|
||||
|
||||
@@ -30,6 +31,7 @@ public class CustodianReturnShardActivity extends BriarActivity
|
||||
private CustodianReturnShardViewModel viewModel;
|
||||
private static final Logger LOG =
|
||||
getLogger(CustodianReturnShardActivity.class.getName());
|
||||
private ContactId contactId;
|
||||
|
||||
@Inject
|
||||
ViewModelProvider.Factory viewModelFactory;
|
||||
@@ -50,35 +52,61 @@ public class CustodianReturnShardActivity extends BriarActivity
|
||||
Intent intent = getIntent();
|
||||
int id = intent.getIntExtra(CONTACT_ID, -1);
|
||||
if (id == -1) throw new IllegalStateException("No ContactId");
|
||||
ContactId contactId = new ContactId(id);
|
||||
contactId = new ContactId(id);
|
||||
|
||||
try {
|
||||
viewModel.start(contactId);
|
||||
} catch (IOException e) {
|
||||
// TODO improve this
|
||||
Toast.makeText(this,
|
||||
"It looks like you are not connected to a Wifi network",
|
||||
Toast.LENGTH_SHORT).show();
|
||||
showNextFragment(new CustodianReturnShardErrorFragment());
|
||||
return;
|
||||
// } catch (IOException e) {
|
||||
// // TODO improve this
|
||||
// Toast.makeText(this,
|
||||
// "It looks like you are not connected to a Wifi network",
|
||||
// Toast.LENGTH_SHORT).show();
|
||||
// showInitialFragment(new CustodianReturnShardErrorFragment());
|
||||
} catch (DbException e) {
|
||||
Toast.makeText(this,
|
||||
"You do not hold a backup piece for this contact",
|
||||
Toast.LENGTH_SHORT).show();
|
||||
finish();
|
||||
}
|
||||
showInitialFragment(new CustodianRecoveryModeExplainerFragment());
|
||||
}
|
||||
showInitialFragment(new CustodianRecoveryModeExplainerFragment());
|
||||
|
||||
viewModel.getContinueClicked().observeEvent(this, clicked -> {
|
||||
if (clicked) beginTransfer();
|
||||
});
|
||||
|
||||
viewModel.getShowCameraFragment().observeEvent(this, show -> {
|
||||
if (show) showCameraFragment();
|
||||
});
|
||||
viewModel.getSuccessDismissed().observeEvent(this, dismissed -> {
|
||||
if (dismissed) finish();
|
||||
});
|
||||
viewModel.getErrorTryAgain().observeEvent(this, tryAgain -> {
|
||||
if (tryAgain) beginTransfer();
|
||||
});
|
||||
viewModel.getState()
|
||||
.observe(this, this::onReturnShardStateChanged);
|
||||
}
|
||||
|
||||
private void beginTransfer() {
|
||||
try {
|
||||
viewModel.beginTransfer();
|
||||
} catch (IOException e) {
|
||||
Toast.makeText(this,
|
||||
"It looks like you are not connected to a Wifi network",
|
||||
Toast.LENGTH_SHORT).show();
|
||||
FragmentManager fm = getSupportFragmentManager();
|
||||
if (fm.findFragmentByTag(CustodianReturnShardFragment.TAG) == null) {
|
||||
BaseFragment f = new CustodianReturnShardErrorFragment();
|
||||
fm.beginTransaction()
|
||||
.replace(R.id.fragmentContainer, f, f.getUniqueTag())
|
||||
.addToBackStack(f.getUniqueTag())
|
||||
.commit();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private void onReturnShardStateChanged(CustodianTask.State state) {
|
||||
if (state instanceof CustodianTask.State.Success) {
|
||||
CustodianReturnShardSuccessFragment fragment = new CustodianReturnShardSuccessFragment();
|
||||
|
||||
@@ -41,13 +41,12 @@ public class CustodianReturnShardErrorFragment extends BaseFragment {
|
||||
public View onCreateView(@NonNull LayoutInflater inflater,
|
||||
@Nullable ViewGroup container,
|
||||
@Nullable Bundle savedInstanceState) {
|
||||
// TODO change fragment to error
|
||||
View view = inflater.inflate(R.layout.fragment_recovery_custodian_done,
|
||||
View view = inflater.inflate(R.layout.fragment_recovery_custodian_error_explainer,
|
||||
container, false);
|
||||
|
||||
Button button = view.findViewById(R.id.button);
|
||||
button.setOnClickListener(e -> viewModel.onErrorCancelled());
|
||||
// TODO try again button
|
||||
button.setOnClickListener(e -> viewModel.onErrorTryAgain());
|
||||
// TODO cancel button
|
||||
// button.setOnClickListener(e -> viewModel.onErrorCancelled());
|
||||
return view;
|
||||
}
|
||||
|
||||
|
||||
@@ -51,9 +51,9 @@ public class CustodianReturnShardViewModel extends AndroidViewModel
|
||||
private final SocialBackupManager socialBackupManager;
|
||||
private final DatabaseComponent db;
|
||||
final QrCodeDecoder qrCodeDecoder;
|
||||
private boolean wasContinueClicked = false;
|
||||
private boolean qrCodeRead = false;
|
||||
private WifiManager wifiManager;
|
||||
private final MutableLiveEvent<Boolean > continueClicked = new MutableLiveEvent<>();
|
||||
private final MutableLiveEvent<Boolean> showCameraFragment =
|
||||
new MutableLiveEvent<>();
|
||||
private final MutableLiveEvent<Boolean> successDismissed =
|
||||
@@ -111,12 +111,8 @@ public class CustodianReturnShardViewModel extends AndroidViewModel
|
||||
}
|
||||
}
|
||||
|
||||
public void start(ContactId contactId) throws DbException, IOException {
|
||||
InetAddress inetAddress = getWifiIpv4Address();
|
||||
LOG.info("Client InetAddress: " + inetAddress);
|
||||
if (inetAddress == null)
|
||||
throw new IOException("Cannot get IP on local wifi");
|
||||
|
||||
public void start(ContactId contactId) throws DbException {
|
||||
// TODO this should be transactionWithResult
|
||||
db.transaction(false, txn -> {
|
||||
if (!socialBackupManager.amCustodian(txn, contactId)) {
|
||||
throw new DbException();
|
||||
@@ -124,8 +120,6 @@ public class CustodianReturnShardViewModel extends AndroidViewModel
|
||||
returnShardPayloadBytes = socialBackupManager
|
||||
.getReturnShardPayloadBytes(txn, contactId);
|
||||
});
|
||||
task.cancel();
|
||||
task.start(this, returnShardPayloadBytes);
|
||||
}
|
||||
|
||||
@IoExecutor
|
||||
@@ -150,11 +144,21 @@ public class CustodianReturnShardViewModel extends AndroidViewModel
|
||||
}
|
||||
}
|
||||
|
||||
public void beginTransfer() throws IOException {
|
||||
InetAddress inetAddress = getWifiIpv4Address();
|
||||
LOG.info("Client InetAddress: " + inetAddress);
|
||||
if (inetAddress == null)
|
||||
throw new IOException("Cannot get IP on local wifi");
|
||||
|
||||
task.cancel();
|
||||
task.start(this, returnShardPayloadBytes);
|
||||
//TODO camera permissions
|
||||
showCameraFragment.setEvent(true);
|
||||
}
|
||||
@UiThread
|
||||
public void onContinueClicked() {
|
||||
wasContinueClicked = true;
|
||||
continueClicked.setEvent(true);
|
||||
// checkPermissions.setEvent(true);
|
||||
showCameraFragment.setEvent(true);
|
||||
}
|
||||
|
||||
@UiThread
|
||||
@@ -201,4 +205,6 @@ public class CustodianReturnShardViewModel extends AndroidViewModel
|
||||
public MutableLiveEvent<Boolean> getErrorTryAgain() {
|
||||
return errorTryAgain;
|
||||
}
|
||||
|
||||
public MutableLiveEvent<Boolean> getContinueClicked() { return continueClicked; }
|
||||
}
|
||||
|
||||
@@ -1,4 +1,57 @@
|
||||
package org.briarproject.briar.android.socialbackup.recover;
|
||||
|
||||
public class OwnerRecoveryModeErrorFragment {
|
||||
import android.os.Bundle;
|
||||
import android.view.LayoutInflater;
|
||||
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;
|
||||
|
||||
import javax.inject.Inject;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.lifecycle.ViewModelProvider;
|
||||
|
||||
@MethodsNotNullByDefault
|
||||
@ParametersNotNullByDefault
|
||||
public class OwnerRecoveryModeErrorFragment extends BaseFragment {
|
||||
public static final String TAG =
|
||||
OwnerRecoveryModeErrorFragment.class.getName();
|
||||
|
||||
@Inject
|
||||
ViewModelProvider.Factory viewModelFactory;
|
||||
|
||||
private OwnerReturnShardViewModel viewModel;
|
||||
|
||||
@Override
|
||||
public void injectFragment(ActivityComponent component) {
|
||||
component.inject(this);
|
||||
viewModel = new ViewModelProvider(requireActivity(), viewModelFactory)
|
||||
.get(OwnerReturnShardViewModel.class);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public View onCreateView(@NonNull LayoutInflater inflater,
|
||||
@Nullable ViewGroup container,
|
||||
@Nullable Bundle savedInstanceState) {
|
||||
View view = inflater.inflate(R.layout.fragment_recovery_custodian_error_explainer,
|
||||
container, false);
|
||||
Button button = view.findViewById(R.id.button);
|
||||
button.setOnClickListener(e -> viewModel.onErrorTryAgain());
|
||||
// TODO cancel button
|
||||
// button.setOnClickListener(e -> viewModel.onErrorCancelled());
|
||||
return view;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getUniqueTag() {
|
||||
return TAG;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -80,6 +80,9 @@ public class OwnerReturnShardActivity extends BaseActivity
|
||||
viewModel.getSuccessDismissed().observeEvent(this, success -> {
|
||||
if (success) onSuccessDismissed();
|
||||
});
|
||||
viewModel.getErrorTryAgain().observeEvent(this, tryAgain -> {
|
||||
if (tryAgain) onBackPressed();
|
||||
});
|
||||
viewModel.getState()
|
||||
.observe(this, this::onReturnShardStateChanged);
|
||||
}
|
||||
@@ -167,12 +170,11 @@ public class OwnerReturnShardActivity extends BaseActivity
|
||||
}
|
||||
onBackPressed();
|
||||
} else if (state instanceof SecretOwnerTask.State.Failure) {
|
||||
// TODO error screen, handle reason
|
||||
Toast.makeText(this,
|
||||
"Shard return failed!",
|
||||
Toast.LENGTH_SHORT).show();
|
||||
onBackPressed();
|
||||
// showNextFragment(new OwnerRecoveryModeExplainerFragment());
|
||||
// Toast.makeText(this,
|
||||
// "Shard return failed!",
|
||||
// Toast.LENGTH_SHORT).show();
|
||||
// onBackPressed();
|
||||
showNextFragment(new OwnerRecoveryModeErrorFragment());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -38,7 +38,7 @@ public class OwnerReturnShardSuccessFragment extends BaseFragment {
|
||||
public View onCreateView(@NonNull LayoutInflater inflater,
|
||||
@Nullable ViewGroup container,
|
||||
@Nullable Bundle savedInstanceState) {
|
||||
View view = inflater.inflate(R.layout.fragment_recovery_custodian_done,
|
||||
View view = inflater.inflate(R.layout.fragment_recovery_owner_success,
|
||||
container, false);
|
||||
|
||||
Button button = view.findViewById(R.id.button);
|
||||
|
||||
@@ -51,6 +51,8 @@ class OwnerReturnShardViewModel extends AndroidViewModel
|
||||
private final SecretOwnerTask task;
|
||||
private final RestoreAccount restoreAccount;
|
||||
|
||||
private final MutableLiveEvent<Boolean> errorTryAgain =
|
||||
new MutableLiveEvent<>();
|
||||
private final MutableLiveEvent<Boolean> showQrCodeFragment =
|
||||
new MutableLiveEvent<>();
|
||||
private final MutableLiveEvent<Boolean> successDismissed = new MutableLiveEvent<>();
|
||||
@@ -158,6 +160,10 @@ class OwnerReturnShardViewModel extends AndroidViewModel
|
||||
});
|
||||
}
|
||||
|
||||
@UiThread
|
||||
public void onErrorTryAgain() {
|
||||
errorTryAgain.setEvent(true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set to true in onPostResume() and false in onPause(). This prevents the
|
||||
@@ -236,4 +242,8 @@ class OwnerReturnShardViewModel extends AndroidViewModel
|
||||
public MutableLiveEvent<Boolean> getSuccessDismissed() {
|
||||
return successDismissed;
|
||||
}
|
||||
|
||||
public MutableLiveEvent<Boolean> getErrorTryAgain() {
|
||||
return errorTryAgain;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -31,7 +31,7 @@
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@+id/textView1"
|
||||
app:srcCompat="@drawable/qr_code_error" />
|
||||
app:srcCompat="@drawable/qr_code_social_backup_error" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/textView2"
|
||||
|
||||
@@ -31,7 +31,20 @@
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@+id/textView"
|
||||
app:srcCompat="@drawable/qr_code_intro" />
|
||||
app:srcCompat="@drawable/qr_code_social_backup" />
|
||||
|
||||
<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/imageView"
|
||||
tools:layout_editor_absoluteX="16dp" />
|
||||
|
||||
<Button
|
||||
android:id="@+id/button"
|
||||
@@ -42,6 +55,6 @@
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintHorizontal_bias="0.0"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@+id/imageView" />
|
||||
app:layout_constraintTop_toBottomOf="@+id/textViewExplain" />
|
||||
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
|
||||
@@ -31,7 +31,21 @@
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@+id/textView"
|
||||
app:srcCompat="@drawable/qr_code_intro" />
|
||||
app:srcCompat="@drawable/qr_code_social_backup" />
|
||||
|
||||
<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/recovery_explainer_extra"
|
||||
android:textSize="20sp"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintHorizontal_bias="0.0"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@+id/imageView"
|
||||
tools:layout_editor_absoluteX="16dp" />
|
||||
|
||||
<Button
|
||||
android:id="@+id/beginButton"
|
||||
@@ -42,6 +56,6 @@
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintHorizontal_bias="0.0"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@+id/imageView" />
|
||||
app:layout_constraintTop_toBottomOf="@+id/textViewExplain" />
|
||||
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
|
||||
@@ -676,19 +676,22 @@
|
||||
<!-- 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>
|
||||
<string name="recovery_failed_to_receive">Failed to receive backup piece</string>
|
||||
<string name="recovery_helpful_suggestions">Please check that bluetooth is swtiched on and that no-one but your trusted contact is able to scan the QR code</string>
|
||||
<string name="recovery_helpful_suggestions">Please check that you are both connected to the same wifi network and try again</string>
|
||||
<string name="recovery_retry">Retry</string>
|
||||
<string name="recovery_recovered_shards">Recovered backup pieces:</string>
|
||||
<string name="recovery_scan_qr_code">Show QR code</string>
|
||||
<string name="recovery_recovering_account">Recovering account…</string>
|
||||
<string name="recovery_shard_received">Account backup piece received</string>
|
||||
<string name="recovery_account_recovered">Account recovered</string>
|
||||
<string name="recovery_account_recovered_explain">You must now set a new password for your account</string>
|
||||
|
||||
<!-- recovery from the custodian's POV -->
|
||||
|
||||
<string name="custodian_recovery_explainer">You need to meet in-person to transfer backup piece</string>
|
||||
<string name="custodian_recovery_explainer_extra">Make sure you are both connected to the same wifi network, and scan the QR code on your contact\'s device to begin transferring the backup piece</string>
|
||||
<string name="custodian_recovery_failed_to_send">Failed to send backup piece</string>
|
||||
<string name="custodian_scan_code">Scan code</string>
|
||||
<string name="custodian_shard_sent">Account backup piece transmitted</string>
|
||||
|
||||
Reference in New Issue
Block a user