Simplify fragment transitions for mailbox pairing UI

Now, trying again always starts before scanning, so the user needs to scan the code again.
This commit is contained in:
Torsten Grote
2022-02-22 14:43:21 -03:00
parent 4390c810d1
commit 952ac2c922
11 changed files with 76 additions and 113 deletions

View File

@@ -1,59 +1,25 @@
package org.briarproject.bramble.api.mailbox;
import javax.annotation.Nullable;
public abstract class MailboxPairingState {
/**
* The QR code payload that was scanned by the user.
* This is null if the code should not be re-used anymore in this state.
*/
@Nullable
public final String qrCodePayload;
MailboxPairingState(@Nullable String qrCodePayload) {
this.qrCodePayload = qrCodePayload;
}
public static class QrCodeReceived extends MailboxPairingState {
public QrCodeReceived(String qrCodePayload) {
super(qrCodePayload);
}
}
public static class Pairing extends MailboxPairingState {
public Pairing(String qrCodePayload) {
super(qrCodePayload);
}
}
public static class Paired extends MailboxPairingState {
public Paired() {
super(null);
}
}
public static class InvalidQrCode extends MailboxPairingState {
public InvalidQrCode() {
super(null);
}
}
public static class MailboxAlreadyPaired extends MailboxPairingState {
public MailboxAlreadyPaired() {
super(null);
}
}
public static class ConnectionError extends MailboxPairingState {
public ConnectionError(String qrCodePayload) {
super(qrCodePayload);
}
}
public static class UnexpectedError extends MailboxPairingState {
public UnexpectedError(String qrCodePayload) {
super(qrCodePayload);
}
}
}

View File

@@ -71,7 +71,7 @@ class MailboxPairingTaskImpl implements MailboxPairingTask {
this.clock = clock;
this.api = api;
this.mailboxSettingsManager = mailboxSettingsManager;
state = new MailboxPairingState.QrCodeReceived(payload);
state = new MailboxPairingState.QrCodeReceived();
}
@Override
@@ -100,15 +100,15 @@ class MailboxPairingTaskImpl implements MailboxPairingTask {
} catch (MailboxAlreadyPairedException e) {
onMailboxError(e, new MailboxPairingState.MailboxAlreadyPaired());
} catch (IOException e) {
onMailboxError(e, new MailboxPairingState.ConnectionError(payload));
onMailboxError(e, new MailboxPairingState.ConnectionError());
} catch (ApiException | DbException e) {
onMailboxError(e, new MailboxPairingState.UnexpectedError(payload));
onMailboxError(e, new MailboxPairingState.UnexpectedError());
}
}
private void pairMailbox() throws IOException, ApiException, DbException {
MailboxProperties mailboxProperties = decodeQrCodePayload(payload);
setState(new MailboxPairingState.Pairing(payload));
setState(new MailboxPairingState.Pairing());
MailboxAuthToken ownerToken = api.setup(mailboxProperties);
MailboxProperties ownerProperties = new MailboxProperties(
mailboxProperties.getBaseUrl(), ownerToken, true);

View File

@@ -49,6 +49,7 @@ import org.briarproject.briar.android.mailbox.MailboxScanFragment;
import org.briarproject.briar.android.mailbox.MailboxStatusFragment;
import org.briarproject.briar.android.mailbox.OfflineFragment;
import org.briarproject.briar.android.mailbox.SetupDownloadFragment;
import org.briarproject.briar.android.mailbox.SetupIntroFragment;
import org.briarproject.briar.android.removabledrive.ChooserFragment;
import org.briarproject.briar.android.removabledrive.ReceiveFragment;
import org.briarproject.briar.android.removabledrive.SendFragment;
@@ -245,6 +246,8 @@ public interface AndroidComponent
void inject(BluetoothIntroFragment bluetoothIntroFragment);
void inject(SetupIntroFragment setupIntroFragment);
void inject(SetupDownloadFragment setupDownloadFragment);
void inject(MailboxScanFragment mailboxScanFragment);

View File

@@ -59,10 +59,7 @@ public class ErrorFragment extends FinalFragment {
// Do not hijack back button events, but let the activity process them
onBackPressedCallback.remove();
buttonView.setText(R.string.try_again_button);
buttonView.setOnClickListener(view -> {
getParentFragmentManager().popBackStackImmediate();
viewModel.tryAgainAfterError();
});
buttonView.setOnClickListener(view -> viewModel.showDownloadFragment());
return v;
}

View File

@@ -54,6 +54,8 @@ public class MailboxActivity extends BriarActivity {
viewModel.getState().observeEvent(this, state -> {
if (state instanceof MailboxState.NotSetup) {
onNotSetup();
} else if (state instanceof MailboxState.ShowDownload) {
onShowDownload();
} else if (state instanceof MailboxState.ScanningQrCode) {
onScanningQrCode();
} else if (state instanceof MailboxState.Pairing) {
@@ -62,6 +64,8 @@ public class MailboxActivity extends BriarActivity {
onMailboxPairingStateChanged(s);
} else if (state instanceof MailboxState.OfflineWhenPairing) {
onOffline();
} else if (state instanceof MailboxState.CameraError) {
onCameraError();
} else if (state instanceof MailboxState.IsPaired) {
onIsPaired();
} else {
@@ -99,32 +103,38 @@ public class MailboxActivity extends BriarActivity {
.commit();
}
private void onScanningQrCode() {
private void onShowDownload() {
FragmentManager fm = getSupportFragmentManager();
if (fm.findFragmentByTag(MailboxScanFragment.TAG) != null) {
// if the scanner is already on the back stack, pop back to it
if (fm.findFragmentByTag(SetupDownloadFragment.TAG) != null) {
// if the fragment is already on the back stack, pop back to it
// instead of adding it to the stack again
fm.popBackStackImmediate(MailboxScanFragment.TAG, 0);
fm.popBackStackImmediate(SetupDownloadFragment.TAG, 0);
} else {
showFragment(fm, new MailboxScanFragment(),
MailboxScanFragment.TAG);
showFragment(fm, new SetupDownloadFragment(),
SetupDownloadFragment.TAG);
}
}
private void onScanningQrCode() {
showFragment(getSupportFragmentManager(), new MailboxScanFragment(),
MailboxScanFragment.TAG);
}
private void onMailboxPairingStateChanged(MailboxPairingState s) {
progressBar.setVisibility(INVISIBLE);
FragmentManager fm = getSupportFragmentManager();
if (fm.getBackStackEntryCount() == 0) {
// We re-launched into an existing state,
// need to re-populate the back stack.
onNotSetup();
onShowDownload();
}
Fragment f;
String tag;
if (s instanceof MailboxPairingState.QrCodeReceived) {
// ignore, showing yet another progress fragment messes with back stack
return;
f = new MailboxConnectingFragment();
tag = MailboxConnectingFragment.TAG;
} else if (s instanceof MailboxPairingState.Pairing) {
if (fm.getBackStackEntryCount() == 0) {
// We re-launched into an existing state,
// need to re-populate the back stack.
repopulateBackStack();
}
f = new MailboxConnectingFragment();
tag = MailboxConnectingFragment.TAG;
} else if (s instanceof MailboxPairingState.InvalidQrCode) {
@@ -164,18 +174,17 @@ public class MailboxActivity extends BriarActivity {
OfflineFragment.TAG);
}
private void onCameraError() {
Fragment f = ErrorFragment.newInstance(
R.string.mailbox_setup_camera_error_title,
R.string.mailbox_setup_camera_error_description);
showFragment(getSupportFragmentManager(), f, ErrorFragment.TAG);
}
private void onIsPaired() {
progressBar.setVisibility(INVISIBLE);
showFragment(getSupportFragmentManager(), new MailboxStatusFragment(),
MailboxStatusFragment.TAG, false);
}
private void repopulateBackStack() {
FragmentManager fm = getSupportFragmentManager();
onNotSetup();
showFragment(fm, new SetupDownloadFragment(),
SetupDownloadFragment.TAG);
onScanningQrCode();
}
}

View File

@@ -94,7 +94,7 @@ public class MailboxScanFragment extends Fragment {
logException(LOG, WARNING, e);
Toast.makeText(requireContext(), R.string.camera_error,
LENGTH_LONG).show();
requireActivity().getSupportFragmentManager().popBackStack();
viewModel.onCameraError();
}
}

View File

@@ -3,13 +3,14 @@ package org.briarproject.briar.android.mailbox;
import org.briarproject.bramble.api.mailbox.MailboxPairingState;
import org.briarproject.bramble.api.mailbox.MailboxStatus;
import androidx.annotation.Nullable;
class MailboxState {
static class NotSetup extends MailboxState {
}
static class ShowDownload extends MailboxState {
}
static class ScanningQrCode extends MailboxState {
}
@@ -19,24 +20,12 @@ class MailboxState {
Pairing(MailboxPairingState pairingState) {
this.pairingState = pairingState;
}
@Nullable
String getQrCodePayload() {
return pairingState.qrCodePayload;
}
}
static class OfflineWhenPairing extends MailboxState {
@Nullable
final String qrCodePayload;
}
OfflineWhenPairing(@Nullable String qrCodePayload) {
this.qrCodePayload = qrCodePayload;
}
OfflineWhenPairing() {
this(null);
}
static class CameraError extends MailboxState {
}
static class IsPaired extends MailboxState {

View File

@@ -33,7 +33,6 @@ import androidx.annotation.AnyThread;
import androidx.annotation.Nullable;
import androidx.annotation.UiThread;
import static java.util.Objects.requireNonNull;
import static java.util.logging.Level.INFO;
import static java.util.logging.Logger.getLogger;
import static org.briarproject.bramble.api.plugin.Plugin.State.ACTIVE;
@@ -110,6 +109,11 @@ class MailboxViewModel extends DbViewModel
}
}
@UiThread
void onCameraError() {
state.setEvent(new MailboxState.CameraError());
}
@Override
@IoExecutor
public void onQrCodeDecoded(Result result) {
@@ -123,7 +127,7 @@ class MailboxViewModel extends DbViewModel
pairingTask = mailboxManager.startPairingTask(qrCodePayload);
pairingTask.addObserver(this);
} else {
state.postEvent(new MailboxState.OfflineWhenPairing(qrCodePayload));
state.postEvent(new MailboxState.OfflineWhenPairing());
}
}
@@ -143,26 +147,8 @@ class MailboxViewModel extends DbViewModel
}
@UiThread
void tryAgainWhenOffline() {
MailboxState.OfflineWhenPairing offline =
(MailboxState.OfflineWhenPairing) requireNonNull(
state.getLastValue());
if (offline.qrCodePayload == null) {
onScanButtonClicked();
} else {
onQrCodePayloadReceived(offline.qrCodePayload);
}
}
@UiThread
void tryAgainAfterError() {
MailboxState.Pairing pairing = (MailboxState.Pairing)
requireNonNull(state.getLastValue());
if (pairing.getQrCodePayload() == null) {
onScanButtonClicked();
} else {
onQrCodePayloadReceived(pairing.getQrCodePayload());
}
void showDownloadFragment() {
state.setEvent(new MailboxState.ShowDownload());
}
@UiThread

View File

@@ -62,10 +62,7 @@ public class OfflineFragment extends Fragment {
startActivity(i);
});
buttonView = v.findViewById(R.id.button);
buttonView.setOnClickListener(view -> {
getParentFragmentManager().popBackStackImmediate();
viewModel.tryAgainWhenOffline();
});
buttonView.setOnClickListener(view -> viewModel.showDownloadFragment());
return v;
}

View File

@@ -1,5 +1,6 @@
package org.briarproject.briar.android.mailbox;
import android.content.Context;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
@@ -11,12 +12,15 @@ import org.briarproject.bramble.api.nullsafety.MethodsNotNullByDefault;
import org.briarproject.bramble.api.nullsafety.ParametersNotNullByDefault;
import org.briarproject.briar.R;
import javax.inject.Inject;
import androidx.annotation.Nullable;
import androidx.fragment.app.Fragment;
import androidx.fragment.app.FragmentManager;
import androidx.fragment.app.FragmentActivity;
import androidx.lifecycle.ViewModelProvider;
import static android.view.View.FOCUS_DOWN;
import static org.briarproject.briar.android.util.UiUtils.showFragment;
import static org.briarproject.briar.android.AppModule.getAndroidComponent;
@MethodsNotNullByDefault
@ParametersNotNullByDefault
@@ -24,8 +28,22 @@ public class SetupIntroFragment extends Fragment {
static final String TAG = SetupIntroFragment.class.getName();
@Inject
ViewModelProvider.Factory viewModelFactory;
private MailboxViewModel viewModel;
private ScrollView scrollView;
@Override
public void onAttach(Context context) {
super.onAttach(context);
FragmentActivity activity = requireActivity();
getAndroidComponent(activity).inject(this);
viewModel = new ViewModelProvider(activity, viewModelFactory)
.get(MailboxViewModel.class);
}
@Nullable
@Override
public View onCreateView(LayoutInflater inflater,
@@ -35,11 +53,7 @@ public class SetupIntroFragment extends Fragment {
container, false);
scrollView = v.findViewById(R.id.scrollView);
Button button = v.findViewById(R.id.continueButton);
button.setOnClickListener(view -> {
FragmentManager fm = getParentFragmentManager();
Fragment f = new SetupDownloadFragment();
showFragment(fm, f, SetupDownloadFragment.TAG);
});
button.setOnClickListener(view -> viewModel.showDownloadFragment());
return v;
}

View File

@@ -631,6 +631,8 @@
<string name="mailbox_setup_io_error_description">Ensure that both devices are connected to the internet and try again.</string>
<string name="mailbox_setup_assertion_error_title">Mailbox error</string>
<string name="mailbox_setup_assertion_error_description">Please send feedback (with anonymous data) via the Briar app if the issue persists.</string>
<string name="mailbox_setup_camera_error_title" translatable="false">@string/camera_error</string>
<string name="mailbox_setup_camera_error_description">Could not access camera. Try again, maybe after rebooting device.</string>
<string name="mailbox_setup_paired_title">Connected</string>
<string name="mailbox_setup_paired_description">Your Mailbox has been successfully linked with Briar.\n
\nKeep your Mailbox connected to power and Wi-Fi so it\'s always online.</string>