mirror of
https://code.briarproject.org/briar/briar.git
synced 2026-02-12 10:49:06 +01:00
Improve UI for shard return
This commit is contained in:
@@ -87,6 +87,7 @@ import org.briarproject.briar.android.socialbackup.DistributedBackupActivity;
|
||||
import org.briarproject.briar.android.socialbackup.ExistingBackupFragment;
|
||||
import org.briarproject.briar.android.socialbackup.recover.CustodianReturnShardActivity;
|
||||
import org.briarproject.briar.android.socialbackup.recover.CustodianReturnShardFragment;
|
||||
import org.briarproject.briar.android.socialbackup.recover.CustodianReturnShardSuccessFragment;
|
||||
import org.briarproject.briar.android.socialbackup.recover.OwnerRecoveryModeExplainerFragment;
|
||||
import org.briarproject.briar.android.socialbackup.recover.OwnerReturnShardActivity;
|
||||
import org.briarproject.briar.android.socialbackup.recover.OwnerReturnShardFragment;
|
||||
@@ -293,4 +294,6 @@ public interface ActivityComponent {
|
||||
void inject(CustodianReturnShardFragment custodianReturnShardFragment);
|
||||
|
||||
void inject(OwnerReturnShardFragment ownerReturnShardFragment);
|
||||
|
||||
void inject(CustodianReturnShardSuccessFragment custodianReturnShardSuccessFragment);
|
||||
}
|
||||
|
||||
@@ -61,7 +61,7 @@ public class DistributedBackupActivity extends BriarActivity implements
|
||||
@Override
|
||||
public void contactsSelected(Collection<ContactId> contacts) {
|
||||
Toast.makeText(this,
|
||||
String.format("selected %d contacts", contacts.size()),
|
||||
String.format("Selected %d contacts", contacts.size()),
|
||||
Toast.LENGTH_SHORT).show();
|
||||
custodians = contacts;
|
||||
ThresholdSelectorFragment fragment =
|
||||
|
||||
@@ -7,6 +7,7 @@ import org.briarproject.briar.android.activity.ActivityComponent;
|
||||
import org.briarproject.briar.android.activity.BriarActivity;
|
||||
import org.briarproject.briar.android.fragment.BaseFragment;
|
||||
import org.briarproject.briar.android.socialbackup.CustodianRecoveryModeExplainerFragment;
|
||||
import org.briarproject.briar.android.socialbackup.ShardsSentFragment;
|
||||
import org.briarproject.briar.api.socialbackup.recovery.CustodianTask;
|
||||
|
||||
import java.util.logging.Logger;
|
||||
@@ -59,13 +60,17 @@ public class CustodianReturnShardActivity extends BriarActivity
|
||||
viewModel.getShowCameraFragment().observeEvent(this, show -> {
|
||||
if (show) showCameraFragment();
|
||||
});
|
||||
viewModel.getSuccessDismissed().observeEvent(this, dismissed -> {
|
||||
if (dismissed) finish();
|
||||
});
|
||||
viewModel.getState()
|
||||
.observe(this, this::onReturnShardStateChanged);
|
||||
}
|
||||
|
||||
private void onReturnShardStateChanged(CustodianTask.State state) {
|
||||
if (state instanceof CustodianTask.State.Success) {
|
||||
|
||||
CustodianReturnShardSuccessFragment fragment = new CustodianReturnShardSuccessFragment();
|
||||
showNextFragment(fragment);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,59 @@
|
||||
package org.briarproject.briar.android.socialbackup.recover;
|
||||
|
||||
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 CustodianReturnShardSuccessFragment extends
|
||||
BaseFragment {
|
||||
|
||||
public static final String TAG =
|
||||
CustodianReturnShardFragment.class.getName();
|
||||
|
||||
@Inject
|
||||
ViewModelProvider.Factory viewModelFactory;
|
||||
|
||||
private CustodianReturnShardViewModel viewModel;
|
||||
|
||||
@Override
|
||||
public void injectFragment(ActivityComponent component) {
|
||||
component.inject(this);
|
||||
viewModel = new ViewModelProvider(requireActivity(), viewModelFactory)
|
||||
.get(CustodianReturnShardViewModel.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);
|
||||
|
||||
Button button = view.findViewById(R.id.button);
|
||||
button.setOnClickListener(e -> viewModel.onSuccessDismissed());
|
||||
|
||||
return view;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getUniqueTag() {
|
||||
return TAG;
|
||||
}
|
||||
}
|
||||
@@ -48,6 +48,8 @@ public class CustodianReturnShardViewModel extends AndroidViewModel
|
||||
private boolean qrCodeRead = false;
|
||||
private final MutableLiveEvent<Boolean> showCameraFragment =
|
||||
new MutableLiveEvent<>();
|
||||
private final MutableLiveEvent<Boolean> successDismissed =
|
||||
new MutableLiveEvent<>();
|
||||
private final MutableLiveData<CustodianTask.State> state =
|
||||
new MutableLiveData<>();
|
||||
final QrCodeDecoder qrCodeDecoder;
|
||||
@@ -100,6 +102,12 @@ public class CustodianReturnShardViewModel extends AndroidViewModel
|
||||
showCameraFragment.setEvent(true);
|
||||
}
|
||||
|
||||
@UiThread
|
||||
public void onSuccessDismissed() {
|
||||
successDismissed.setEvent(true);
|
||||
}
|
||||
|
||||
|
||||
QrCodeDecoder getQrCodeDecoder() {
|
||||
return qrCodeDecoder;
|
||||
}
|
||||
@@ -108,6 +116,9 @@ public class CustodianReturnShardViewModel extends AndroidViewModel
|
||||
return showCameraFragment;
|
||||
}
|
||||
|
||||
LiveEvent<Boolean> getSuccessDismissed() {
|
||||
return successDismissed;
|
||||
}
|
||||
LiveData<CustodianTask.State> getState() {
|
||||
return state;
|
||||
}
|
||||
|
||||
@@ -10,7 +10,6 @@ import org.briarproject.bramble.api.nullsafety.ParametersNotNullByDefault;
|
||||
import org.briarproject.briar.R;
|
||||
import org.briarproject.briar.android.activity.ActivityComponent;
|
||||
import org.briarproject.briar.android.activity.BaseActivity;
|
||||
import org.briarproject.briar.android.contact.add.nearby.AddNearbyContactErrorFragment;
|
||||
import org.briarproject.briar.android.fragment.BaseFragment;
|
||||
import org.briarproject.briar.api.socialbackup.recovery.SecretOwnerTask;
|
||||
|
||||
@@ -23,7 +22,6 @@ import androidx.fragment.app.FragmentManager;
|
||||
import androidx.lifecycle.ViewModelProvider;
|
||||
|
||||
import static android.content.Intent.FLAG_ACTIVITY_CLEAR_TOP;
|
||||
import static android.widget.Toast.LENGTH_LONG;
|
||||
import static java.util.logging.Logger.getLogger;
|
||||
|
||||
@MethodsNotNullByDefault
|
||||
@@ -78,10 +76,6 @@ public class OwnerReturnShardActivity extends BaseActivity
|
||||
if (state == null) {
|
||||
showInitialFragment(new OwnerRecoveryModeExplainerFragment());
|
||||
}
|
||||
// viewModel.getCheckPermissions().observeEvent(this, check ->
|
||||
// permissionManager.checkPermissions());
|
||||
// viewModel.getRequestBluetoothDiscoverable().observeEvent(this, r ->
|
||||
// requestBluetoothDiscoverable()); // never false
|
||||
viewModel.getShowQrCodeFragment().observeEvent(this, show -> {
|
||||
if (show) showQrCodeFragment();
|
||||
});
|
||||
@@ -117,6 +111,7 @@ public class OwnerReturnShardActivity extends BaseActivity
|
||||
|
||||
@Override
|
||||
public void onBackPressed() {
|
||||
// TODO should we cancel the return shard task here?
|
||||
if (viewModel.getState()
|
||||
.getValue() instanceof SecretOwnerTask.State.Failure) {
|
||||
// re-create this activity when going back in failed state
|
||||
@@ -141,47 +136,23 @@ public class OwnerReturnShardActivity extends BaseActivity
|
||||
}
|
||||
|
||||
private void onReturnShardStateChanged(SecretOwnerTask.State state) {
|
||||
// if (state instanceof ReturnShardState.SocialBackupExchangeFinished) {
|
||||
// ReturnShardState.SocialBackupExchangeResult result =
|
||||
// ((ReturnShardState.SocialBackupExchangeFinished) state).result;
|
||||
// onSocialBackupExchangeResult(result);
|
||||
// } else if (state instanceof ReturnShardState.Failed) {
|
||||
// Boolean qrCodeTooOld =
|
||||
// ((ReturnShardState.Failed) state).qrCodeTooOld;
|
||||
// onAddingContactFailed(qrCodeTooOld);
|
||||
// }
|
||||
}
|
||||
|
||||
private void onSocialBackupExchangeResult(
|
||||
ReturnShardState.SocialBackupExchangeResult result) {
|
||||
if (result instanceof ReturnShardState.SocialBackupExchangeResult.Success) {
|
||||
// String text = getString(R.string.contact_added_toast, contactName);
|
||||
Toast.makeText(this, "Shard return successful", LENGTH_LONG).show();
|
||||
supportFinishAfterTransition();
|
||||
} else if (result instanceof ReturnShardState.SocialBackupExchangeResult.Error) {
|
||||
showErrorFragment();
|
||||
} else throw new AssertionError();
|
||||
}
|
||||
|
||||
private void onAddingContactFailed(@Nullable Boolean qrCodeTooOld) {
|
||||
if (qrCodeTooOld == null) {
|
||||
showErrorFragment();
|
||||
} else {
|
||||
String msg;
|
||||
if (qrCodeTooOld) {
|
||||
msg = getString(R.string.qr_code_too_old,
|
||||
getString(R.string.app_name));
|
||||
} else {
|
||||
msg = getString(R.string.qr_code_too_new,
|
||||
getString(R.string.app_name));
|
||||
}
|
||||
showNextFragment(AddNearbyContactErrorFragment.newInstance(msg));
|
||||
if (state instanceof SecretOwnerTask.State.Success) {
|
||||
Toast.makeText(this,
|
||||
"Success - got shard",
|
||||
Toast.LENGTH_SHORT).show();
|
||||
finish();
|
||||
} else if (state instanceof SecretOwnerTask.State.Failure) {
|
||||
Toast.makeText(this,
|
||||
"Shard return failed!",
|
||||
Toast.LENGTH_SHORT).show();
|
||||
finish();
|
||||
}
|
||||
}
|
||||
|
||||
private void showErrorFragment() {
|
||||
showNextFragment(new AddNearbyContactErrorFragment());
|
||||
}
|
||||
// private void showErrorFragment() {
|
||||
// // TODO change this for an appropriate error message fragment
|
||||
// showNextFragment(new AddNearbyContactErrorFragment());
|
||||
// }
|
||||
|
||||
@Override
|
||||
@Deprecated
|
||||
|
||||
@@ -136,91 +136,12 @@ class OwnerReturnShardViewModel extends AndroidViewModel implements SecretOwnerT
|
||||
|
||||
@UiThread
|
||||
private void stopListening() {
|
||||
task.cancel();
|
||||
// KeyAgreementTask oldTask = task;
|
||||
// ioExecutor.execute(() -> {
|
||||
// if (oldTask != null) oldTask.stopListening();
|
||||
// });
|
||||
ioExecutor.execute(() -> {
|
||||
task.cancel();
|
||||
});
|
||||
}
|
||||
|
||||
// @Override
|
||||
// public void eventOccurred(Event e) {
|
||||
// if (e instanceof TransportStateEvent) {
|
||||
// TransportStateEvent t = (TransportStateEvent) e;
|
||||
// if (t.getTransportId().equals(BluetoothConstants.ID)) {
|
||||
// if (LOG.isLoggable(INFO)) {
|
||||
// LOG.info("Bluetooth state changed to " + t.getState());
|
||||
// }
|
||||
// showQrCodeFragmentIfAllowed();
|
||||
// } else if (t.getTransportId().equals(LanTcpConstants.ID)) {
|
||||
// if (LOG.isLoggable(INFO)) {
|
||||
// LOG.info("Wifi state changed to " + t.getState());
|
||||
// }
|
||||
// showQrCodeFragmentIfAllowed();
|
||||
// }
|
||||
// } else if (e instanceof KeyAgreementListeningEvent) {
|
||||
// LOG.info("KeyAgreementListeningEvent received");
|
||||
// KeyAgreementListeningEvent event = (KeyAgreementListeningEvent) e;
|
||||
// onLocalPayloadReceived(event.getLocalPayload());
|
||||
// } else if (e instanceof KeyAgreementWaitingEvent) {
|
||||
// LOG.info("KeyAgreementWaitingEvent received");
|
||||
// state.setValue(new ReturnShardState.KeyAgreementWaiting());
|
||||
// } else if (e instanceof KeyAgreementStartedEvent) {
|
||||
// LOG.info("KeyAgreementStartedEvent received");
|
||||
// state.setValue(new ReturnShardState.KeyAgreementStarted());
|
||||
// } else if (e instanceof KeyAgreementFinishedEvent) {
|
||||
// LOG.info("KeyAgreementFinishedEvent received");
|
||||
// KeyAgreementResult result =
|
||||
// ((KeyAgreementFinishedEvent) e).getResult();
|
||||
// startContactExchange(result);
|
||||
// state.setValue(new ReturnShardState.SocialBackupExchangeStarted());
|
||||
// } else if (e instanceof KeyAgreementAbortedEvent) {
|
||||
// LOG.info("KeyAgreementAbortedEvent received");
|
||||
// resetPayloadFlags();
|
||||
// state.setValue(new ReturnShardState.Failed());
|
||||
// } else if (e instanceof KeyAgreementFailedEvent) {
|
||||
// LOG.info("KeyAgreementFailedEvent received");
|
||||
// resetPayloadFlags();
|
||||
// state.setValue(new ReturnShardState.Failed());
|
||||
// }
|
||||
// }
|
||||
|
||||
@UiThread
|
||||
// private void startContactExchange(KeyAgreementResult result) {
|
||||
// TransportId t = result.getTransportId();
|
||||
// DuplexTransportConnection conn = result.getConnection();
|
||||
// SecretKey masterKey = result.getMasterKey();
|
||||
// boolean alice = result.wasAlice();
|
||||
// ioExecutor.execute(() -> {
|
||||
// try {
|
||||
// if (sending) {
|
||||
// socialBackupExchangeManager.sendReturnShard(conn, masterKey, alice, returnShardPayload);
|
||||
// } else {
|
||||
// returnShardPayload = socialBackupExchangeManager.receiveReturnShard(conn, masterKey, alice);
|
||||
// }
|
||||
// ReturnShardState.SocialBackupExchangeResult.Success
|
||||
// success =
|
||||
// new ReturnShardState.SocialBackupExchangeResult.Success();
|
||||
// state.postValue(
|
||||
// new ReturnShardState.SocialBackupExchangeFinished(success));
|
||||
// } catch (ContactExistsException e) {
|
||||
// tryToClose(conn);
|
||||
// ReturnShardState.SocialBackupExchangeResult.Error
|
||||
// error = new ReturnShardState.SocialBackupExchangeResult.Error(
|
||||
// e.getRemoteAuthor());
|
||||
// state.postValue(
|
||||
// new ReturnShardState.SocialBackupExchangeFinished(error));
|
||||
// } catch (DbException | IOException e) {
|
||||
// tryToClose(conn);
|
||||
// logException(LOG, WARNING, e);
|
||||
// ReturnShardState.SocialBackupExchangeResult.Error
|
||||
// error =
|
||||
// new ReturnShardState.SocialBackupExchangeResult.Error(null);
|
||||
// state.postValue(
|
||||
// new ReturnShardState.SocialBackupExchangeFinished(error));
|
||||
// }
|
||||
// });
|
||||
// }
|
||||
|
||||
|
||||
/**
|
||||
@@ -252,18 +173,19 @@ class OwnerReturnShardViewModel extends AndroidViewModel implements SecretOwnerT
|
||||
|
||||
@Override
|
||||
public void onStateChanged(SecretOwnerTask.State state) {
|
||||
if (state instanceof SecretOwnerTask.State.Listening) {
|
||||
DisplayMetrics dm = getApplication().getResources().getDisplayMetrics();
|
||||
ioExecutor.execute(() -> {
|
||||
byte[] payloadBytes = ((SecretOwnerTask.State.Listening) state).getLocalPayload();
|
||||
if (LOG.isLoggable(INFO)) {
|
||||
LOG.info("Local payload is " + payloadBytes.length
|
||||
+ " bytes");
|
||||
}
|
||||
// Use ISO 8859-1 to encode bytes directly as a string
|
||||
String content = new String(payloadBytes, ISO_8859_1);
|
||||
qrCodeBitmap = QrCodeUtils.createQrCode(dm, content);
|
||||
});
|
||||
}
|
||||
this.state.postValue(state);
|
||||
if (state instanceof SecretOwnerTask.State.Listening) {
|
||||
DisplayMetrics dm = getApplication().getResources().getDisplayMetrics();
|
||||
ioExecutor.execute(() -> {
|
||||
byte[] payloadBytes = ((SecretOwnerTask.State.Listening) state).getLocalPayload();
|
||||
if (LOG.isLoggable(INFO)) {
|
||||
LOG.info("Local payload is " + payloadBytes.length
|
||||
+ " bytes");
|
||||
}
|
||||
// Use ISO 8859-1 to encode bytes directly as a string
|
||||
String content = new String(payloadBytes, ISO_8859_1);
|
||||
qrCodeBitmap = QrCodeUtils.createQrCode(dm, content);
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -10,6 +10,17 @@
|
||||
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/backup_done_dismiss"
|
||||
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"
|
||||
|
||||
Reference in New Issue
Block a user