mirror of
https://code.briarproject.org/briar/briar.git
synced 2026-02-16 04:39:54 +01:00
Merge branch '2162-mailbox-pairing-ui-end' into 'master'
Implement final parts of UI for pairing Briar with mailbox Closes #2162 See merge request briar/briar!1590
This commit is contained in:
@@ -1,59 +1,25 @@
|
|||||||
package org.briarproject.bramble.api.mailbox;
|
package org.briarproject.bramble.api.mailbox;
|
||||||
|
|
||||||
import javax.annotation.Nullable;
|
|
||||||
|
|
||||||
public abstract class MailboxPairingState {
|
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 static class QrCodeReceived extends MailboxPairingState {
|
||||||
public QrCodeReceived(String qrCodePayload) {
|
|
||||||
super(qrCodePayload);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static class Pairing extends MailboxPairingState {
|
public static class Pairing extends MailboxPairingState {
|
||||||
public Pairing(String qrCodePayload) {
|
|
||||||
super(qrCodePayload);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static class Paired extends MailboxPairingState {
|
public static class Paired extends MailboxPairingState {
|
||||||
public Paired() {
|
|
||||||
super(null);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static class InvalidQrCode extends MailboxPairingState {
|
public static class InvalidQrCode extends MailboxPairingState {
|
||||||
public InvalidQrCode() {
|
|
||||||
super(null);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static class MailboxAlreadyPaired extends MailboxPairingState {
|
public static class MailboxAlreadyPaired extends MailboxPairingState {
|
||||||
public MailboxAlreadyPaired() {
|
|
||||||
super(null);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static class ConnectionError extends MailboxPairingState {
|
public static class ConnectionError extends MailboxPairingState {
|
||||||
public ConnectionError(String qrCodePayload) {
|
|
||||||
super(qrCodePayload);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static class UnexpectedError extends MailboxPairingState {
|
public static class UnexpectedError extends MailboxPairingState {
|
||||||
public UnexpectedError(String qrCodePayload) {
|
|
||||||
super(qrCodePayload);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -71,7 +71,7 @@ class MailboxPairingTaskImpl implements MailboxPairingTask {
|
|||||||
this.clock = clock;
|
this.clock = clock;
|
||||||
this.api = api;
|
this.api = api;
|
||||||
this.mailboxSettingsManager = mailboxSettingsManager;
|
this.mailboxSettingsManager = mailboxSettingsManager;
|
||||||
state = new MailboxPairingState.QrCodeReceived(payload);
|
state = new MailboxPairingState.QrCodeReceived();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -100,15 +100,15 @@ class MailboxPairingTaskImpl implements MailboxPairingTask {
|
|||||||
} catch (MailboxAlreadyPairedException e) {
|
} catch (MailboxAlreadyPairedException e) {
|
||||||
onMailboxError(e, new MailboxPairingState.MailboxAlreadyPaired());
|
onMailboxError(e, new MailboxPairingState.MailboxAlreadyPaired());
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
onMailboxError(e, new MailboxPairingState.ConnectionError(payload));
|
onMailboxError(e, new MailboxPairingState.ConnectionError());
|
||||||
} catch (ApiException | DbException e) {
|
} catch (ApiException | DbException e) {
|
||||||
onMailboxError(e, new MailboxPairingState.UnexpectedError(payload));
|
onMailboxError(e, new MailboxPairingState.UnexpectedError());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void pairMailbox() throws IOException, ApiException, DbException {
|
private void pairMailbox() throws IOException, ApiException, DbException {
|
||||||
MailboxProperties mailboxProperties = decodeQrCodePayload(payload);
|
MailboxProperties mailboxProperties = decodeQrCodePayload(payload);
|
||||||
setState(new MailboxPairingState.Pairing(payload));
|
setState(new MailboxPairingState.Pairing());
|
||||||
MailboxAuthToken ownerToken = api.setup(mailboxProperties);
|
MailboxAuthToken ownerToken = api.setup(mailboxProperties);
|
||||||
MailboxProperties ownerProperties = new MailboxProperties(
|
MailboxProperties ownerProperties = new MailboxProperties(
|
||||||
mailboxProperties.getBaseUrl(), ownerToken, true);
|
mailboxProperties.getBaseUrl(), ownerToken, true);
|
||||||
|
|||||||
@@ -46,6 +46,7 @@
|
|||||||
android:icon="@mipmap/ic_launcher_round"
|
android:icon="@mipmap/ic_launcher_round"
|
||||||
android:label="@string/app_name"
|
android:label="@string/app_name"
|
||||||
android:logo="@mipmap/ic_launcher_round"
|
android:logo="@mipmap/ic_launcher_round"
|
||||||
|
android:networkSecurityConfig="@xml/network_security_config"
|
||||||
android:supportsRtl="true"
|
android:supportsRtl="true"
|
||||||
android:theme="@style/BriarTheme"
|
android:theme="@style/BriarTheme"
|
||||||
tools:ignore="GoogleAppIndexingWarning,UnusedAttribute"
|
tools:ignore="GoogleAppIndexingWarning,UnusedAttribute"
|
||||||
|
|||||||
@@ -44,9 +44,12 @@ import org.briarproject.briar.android.hotspot.ManualHotspotFragment;
|
|||||||
import org.briarproject.briar.android.hotspot.QrHotspotFragment;
|
import org.briarproject.briar.android.hotspot.QrHotspotFragment;
|
||||||
import org.briarproject.briar.android.logging.CachingLogHandler;
|
import org.briarproject.briar.android.logging.CachingLogHandler;
|
||||||
import org.briarproject.briar.android.login.SignInReminderReceiver;
|
import org.briarproject.briar.android.login.SignInReminderReceiver;
|
||||||
|
import org.briarproject.briar.android.mailbox.ErrorFragment;
|
||||||
import org.briarproject.briar.android.mailbox.MailboxScanFragment;
|
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.OfflineFragment;
|
||||||
import org.briarproject.briar.android.mailbox.SetupDownloadFragment;
|
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.ChooserFragment;
|
||||||
import org.briarproject.briar.android.removabledrive.ReceiveFragment;
|
import org.briarproject.briar.android.removabledrive.ReceiveFragment;
|
||||||
import org.briarproject.briar.android.removabledrive.SendFragment;
|
import org.briarproject.briar.android.removabledrive.SendFragment;
|
||||||
@@ -243,9 +246,15 @@ public interface AndroidComponent
|
|||||||
|
|
||||||
void inject(BluetoothIntroFragment bluetoothIntroFragment);
|
void inject(BluetoothIntroFragment bluetoothIntroFragment);
|
||||||
|
|
||||||
|
void inject(SetupIntroFragment setupIntroFragment);
|
||||||
|
|
||||||
void inject(SetupDownloadFragment setupDownloadFragment);
|
void inject(SetupDownloadFragment setupDownloadFragment);
|
||||||
|
|
||||||
void inject(MailboxScanFragment mailboxScanFragment);
|
void inject(MailboxScanFragment mailboxScanFragment);
|
||||||
|
|
||||||
void inject(OfflineFragment offlineFragment);
|
void inject(OfflineFragment offlineFragment);
|
||||||
|
|
||||||
|
void inject(ErrorFragment errorFragment);
|
||||||
|
|
||||||
|
void inject(MailboxStatusFragment mailboxStatusFragment);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -63,6 +63,13 @@ public class FinalFragment extends Fragment {
|
|||||||
|
|
||||||
private NestedScrollView scrollView;
|
private NestedScrollView scrollView;
|
||||||
protected Button buttonView;
|
protected Button buttonView;
|
||||||
|
protected final OnBackPressedCallback onBackPressedCallback =
|
||||||
|
new OnBackPressedCallback(true) {
|
||||||
|
@Override
|
||||||
|
public void handleOnBackPressed() {
|
||||||
|
onBackButtonPressed();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
@Nullable
|
@Nullable
|
||||||
@Override
|
@Override
|
||||||
@@ -95,13 +102,8 @@ public class FinalFragment extends Fragment {
|
|||||||
|
|
||||||
AppCompatActivity a = (AppCompatActivity) requireActivity();
|
AppCompatActivity a = (AppCompatActivity) requireActivity();
|
||||||
a.setTitle(args.getInt(ARG_TITLE));
|
a.setTitle(args.getInt(ARG_TITLE));
|
||||||
a.getOnBackPressedDispatcher().addCallback(
|
a.getOnBackPressedDispatcher()
|
||||||
getViewLifecycleOwner(), new OnBackPressedCallback(true) {
|
.addCallback(getViewLifecycleOwner(), onBackPressedCallback);
|
||||||
@Override
|
|
||||||
public void handleOnBackPressed() {
|
|
||||||
onBackButtonPressed();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
return v;
|
return v;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
package org.briarproject.briar.android.mailbox;
|
package org.briarproject.briar.android.mailbox;
|
||||||
|
|
||||||
|
import android.content.Context;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
import android.view.LayoutInflater;
|
import android.view.LayoutInflater;
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
@@ -10,8 +11,14 @@ import org.briarproject.bramble.api.nullsafety.ParametersNotNullByDefault;
|
|||||||
import org.briarproject.briar.R;
|
import org.briarproject.briar.R;
|
||||||
import org.briarproject.briar.android.fragment.FinalFragment;
|
import org.briarproject.briar.android.fragment.FinalFragment;
|
||||||
|
|
||||||
|
import javax.inject.Inject;
|
||||||
|
|
||||||
import androidx.annotation.Nullable;
|
import androidx.annotation.Nullable;
|
||||||
import androidx.annotation.StringRes;
|
import androidx.annotation.StringRes;
|
||||||
|
import androidx.fragment.app.FragmentActivity;
|
||||||
|
import androidx.lifecycle.ViewModelProvider;
|
||||||
|
|
||||||
|
import static org.briarproject.briar.android.AppModule.getAndroidComponent;
|
||||||
|
|
||||||
@MethodsNotNullByDefault
|
@MethodsNotNullByDefault
|
||||||
@ParametersNotNullByDefault
|
@ParametersNotNullByDefault
|
||||||
@@ -29,21 +36,33 @@ public class ErrorFragment extends FinalFragment {
|
|||||||
return f;
|
return f;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
ViewModelProvider.Factory viewModelFactory;
|
||||||
|
|
||||||
|
private MailboxViewModel viewModel;
|
||||||
|
|
||||||
|
@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
|
@Nullable
|
||||||
@Override
|
@Override
|
||||||
public View onCreateView(LayoutInflater inflater,
|
public View onCreateView(LayoutInflater inflater,
|
||||||
@Nullable ViewGroup container,
|
@Nullable ViewGroup container,
|
||||||
@Nullable Bundle savedInstanceState) {
|
@Nullable Bundle savedInstanceState) {
|
||||||
View v = super.onCreateView(inflater, container, savedInstanceState);
|
View v = super.onCreateView(inflater, container, savedInstanceState);
|
||||||
|
// Do not hijack back button events, but let the activity process them
|
||||||
|
onBackPressedCallback.remove();
|
||||||
buttonView.setText(R.string.try_again_button);
|
buttonView.setText(R.string.try_again_button);
|
||||||
|
buttonView.setOnClickListener(view -> viewModel.showDownloadFragment());
|
||||||
return v;
|
return v;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void onBackButtonPressed() {
|
|
||||||
requireActivity().getSupportFragmentManager().popBackStack();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected boolean shouldHideActionBarBackButton() {
|
protected boolean shouldHideActionBarBackButton() {
|
||||||
return false;
|
return false;
|
||||||
|
|||||||
@@ -3,19 +3,20 @@ package org.briarproject.briar.android.mailbox;
|
|||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
import android.view.MenuItem;
|
import android.view.MenuItem;
|
||||||
import android.widget.ProgressBar;
|
import android.widget.ProgressBar;
|
||||||
import android.widget.Toast;
|
|
||||||
|
|
||||||
import org.briarproject.bramble.api.mailbox.MailboxStatus;
|
import org.briarproject.bramble.api.mailbox.MailboxPairingState;
|
||||||
import org.briarproject.bramble.api.nullsafety.MethodsNotNullByDefault;
|
import org.briarproject.bramble.api.nullsafety.MethodsNotNullByDefault;
|
||||||
import org.briarproject.bramble.api.nullsafety.ParametersNotNullByDefault;
|
import org.briarproject.bramble.api.nullsafety.ParametersNotNullByDefault;
|
||||||
import org.briarproject.briar.R;
|
import org.briarproject.briar.R;
|
||||||
import org.briarproject.briar.android.activity.ActivityComponent;
|
import org.briarproject.briar.android.activity.ActivityComponent;
|
||||||
import org.briarproject.briar.android.activity.BriarActivity;
|
import org.briarproject.briar.android.activity.BriarActivity;
|
||||||
|
import org.briarproject.briar.android.fragment.FinalFragment;
|
||||||
|
|
||||||
import javax.inject.Inject;
|
import javax.inject.Inject;
|
||||||
|
|
||||||
import androidx.annotation.Nullable;
|
import androidx.annotation.Nullable;
|
||||||
import androidx.fragment.app.Fragment;
|
import androidx.fragment.app.Fragment;
|
||||||
|
import androidx.fragment.app.FragmentManager;
|
||||||
import androidx.lifecycle.ViewModelProvider;
|
import androidx.lifecycle.ViewModelProvider;
|
||||||
|
|
||||||
import static android.view.View.INVISIBLE;
|
import static android.view.View.INVISIBLE;
|
||||||
@@ -53,16 +54,20 @@ public class MailboxActivity extends BriarActivity {
|
|||||||
viewModel.getState().observeEvent(this, state -> {
|
viewModel.getState().observeEvent(this, state -> {
|
||||||
if (state instanceof MailboxState.NotSetup) {
|
if (state instanceof MailboxState.NotSetup) {
|
||||||
onNotSetup();
|
onNotSetup();
|
||||||
|
} else if (state instanceof MailboxState.ShowDownload) {
|
||||||
|
onShowDownload();
|
||||||
} else if (state instanceof MailboxState.ScanningQrCode) {
|
} else if (state instanceof MailboxState.ScanningQrCode) {
|
||||||
onScanningQrCode();
|
onScanningQrCode();
|
||||||
} else if (state instanceof MailboxState.SettingUp) {
|
} else if (state instanceof MailboxState.Pairing) {
|
||||||
onCodeScanned();
|
MailboxPairingState s =
|
||||||
} else if (state instanceof MailboxState.QrCodeWrong) {
|
((MailboxState.Pairing) state).pairingState;
|
||||||
onQrCodeWrong();
|
onMailboxPairingStateChanged(s);
|
||||||
} else if (state instanceof MailboxState.OfflineInSetup) {
|
} else if (state instanceof MailboxState.OfflineWhenPairing) {
|
||||||
onOffline();
|
onOffline();
|
||||||
} else if (state instanceof MailboxState.IsSetup) {
|
} else if (state instanceof MailboxState.CameraError) {
|
||||||
onIsSetup(((MailboxState.IsSetup) state).mailboxStatus);
|
onCameraError();
|
||||||
|
} else if (state instanceof MailboxState.IsPaired) {
|
||||||
|
onIsPaired();
|
||||||
} else {
|
} else {
|
||||||
throw new AssertionError("Unknown state: " + state);
|
throw new AssertionError("Unknown state: " + state);
|
||||||
}
|
}
|
||||||
@@ -80,9 +85,10 @@ public class MailboxActivity extends BriarActivity {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onBackPressed() {
|
public void onBackPressed() {
|
||||||
if (viewModel.getState()
|
MailboxState s = viewModel.getState().getLastValue();
|
||||||
.getLastValue() instanceof MailboxState.SettingUp) {
|
if (s instanceof MailboxState.Pairing) {
|
||||||
// don't go back in flow if we are already setting up mailbox
|
// don't go back in the flow if we are already pairing
|
||||||
|
// with the mailbox. We provide a try-again button instead.
|
||||||
supportFinishAfterTransition();
|
supportFinishAfterTransition();
|
||||||
} else {
|
} else {
|
||||||
super.onBackPressed();
|
super.onBackPressed();
|
||||||
@@ -97,22 +103,70 @@ public class MailboxActivity extends BriarActivity {
|
|||||||
.commit();
|
.commit();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void onShowDownload() {
|
||||||
|
FragmentManager fm = getSupportFragmentManager();
|
||||||
|
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(SetupDownloadFragment.TAG, 0);
|
||||||
|
} else {
|
||||||
|
showFragment(fm, new SetupDownloadFragment(),
|
||||||
|
SetupDownloadFragment.TAG);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private void onScanningQrCode() {
|
private void onScanningQrCode() {
|
||||||
showFragment(getSupportFragmentManager(), new MailboxScanFragment(),
|
showFragment(getSupportFragmentManager(), new MailboxScanFragment(),
|
||||||
MailboxScanFragment.TAG);
|
MailboxScanFragment.TAG);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void onCodeScanned() {
|
private void onMailboxPairingStateChanged(MailboxPairingState s) {
|
||||||
showFragment(getSupportFragmentManager(),
|
progressBar.setVisibility(INVISIBLE);
|
||||||
new MailboxConnectingFragment(),
|
FragmentManager fm = getSupportFragmentManager();
|
||||||
MailboxConnectingFragment.TAG, false);
|
if (fm.getBackStackEntryCount() == 0) {
|
||||||
}
|
// We re-launched into an existing state,
|
||||||
|
// need to re-populate the back stack.
|
||||||
private void onQrCodeWrong() {
|
onNotSetup();
|
||||||
Fragment f = ErrorFragment.newInstance(
|
onShowDownload();
|
||||||
R.string.mailbox_setup_qr_code_wrong_title,
|
}
|
||||||
R.string.mailbox_setup_qr_code_wrong_description);
|
Fragment f;
|
||||||
showFragment(getSupportFragmentManager(), f, ErrorFragment.TAG);
|
String tag;
|
||||||
|
if (s instanceof MailboxPairingState.QrCodeReceived) {
|
||||||
|
f = new MailboxConnectingFragment();
|
||||||
|
tag = MailboxConnectingFragment.TAG;
|
||||||
|
} else if (s instanceof MailboxPairingState.Pairing) {
|
||||||
|
f = new MailboxConnectingFragment();
|
||||||
|
tag = MailboxConnectingFragment.TAG;
|
||||||
|
} else if (s instanceof MailboxPairingState.InvalidQrCode) {
|
||||||
|
f = ErrorFragment.newInstance(
|
||||||
|
R.string.mailbox_setup_qr_code_wrong_title,
|
||||||
|
R.string.mailbox_setup_qr_code_wrong_description);
|
||||||
|
tag = ErrorFragment.TAG;
|
||||||
|
} else if (s instanceof MailboxPairingState.MailboxAlreadyPaired) {
|
||||||
|
f = ErrorFragment.newInstance(
|
||||||
|
R.string.mailbox_setup_already_paired_title,
|
||||||
|
R.string.mailbox_setup_already_paired_description);
|
||||||
|
tag = ErrorFragment.TAG;
|
||||||
|
} else if (s instanceof MailboxPairingState.ConnectionError) {
|
||||||
|
f = ErrorFragment.newInstance(
|
||||||
|
R.string.mailbox_setup_io_error_title,
|
||||||
|
R.string.mailbox_setup_io_error_description);
|
||||||
|
tag = ErrorFragment.TAG;
|
||||||
|
} else if (s instanceof MailboxPairingState.UnexpectedError) {
|
||||||
|
f = ErrorFragment.newInstance(
|
||||||
|
R.string.mailbox_setup_assertion_error_title,
|
||||||
|
R.string.mailbox_setup_assertion_error_description);
|
||||||
|
tag = ErrorFragment.TAG;
|
||||||
|
} else if (s instanceof MailboxPairingState.Paired) {
|
||||||
|
f = FinalFragment.newInstance(R.string.mailbox_setup_paired_title,
|
||||||
|
R.drawable.ic_check_circle_outline,
|
||||||
|
R.color.briar_brand_green,
|
||||||
|
R.string.mailbox_setup_paired_description);
|
||||||
|
tag = FinalFragment.TAG;
|
||||||
|
} else {
|
||||||
|
throw new IllegalStateException("Unhandled state: " + s.getClass());
|
||||||
|
}
|
||||||
|
showFragment(fm, f, tag);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void onOffline() {
|
private void onOffline() {
|
||||||
@@ -120,9 +174,17 @@ public class MailboxActivity extends BriarActivity {
|
|||||||
OfflineFragment.TAG);
|
OfflineFragment.TAG);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void onIsSetup(MailboxStatus mailboxStatus) {
|
private void onCameraError() {
|
||||||
// TODO
|
Fragment f = ErrorFragment.newInstance(
|
||||||
Toast.makeText(this, "NOT IMPLEMENTED", Toast.LENGTH_LONG).show();
|
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);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -94,7 +94,7 @@ public class MailboxScanFragment extends Fragment {
|
|||||||
logException(LOG, WARNING, e);
|
logException(LOG, WARNING, e);
|
||||||
Toast.makeText(requireContext(), R.string.camera_error,
|
Toast.makeText(requireContext(), R.string.camera_error,
|
||||||
LENGTH_LONG).show();
|
LENGTH_LONG).show();
|
||||||
requireActivity().getSupportFragmentManager().popBackStack();
|
viewModel.onCameraError();
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,41 +1,37 @@
|
|||||||
package org.briarproject.briar.android.mailbox;
|
package org.briarproject.briar.android.mailbox;
|
||||||
|
|
||||||
import org.briarproject.bramble.api.mailbox.MailboxProperties;
|
import org.briarproject.bramble.api.mailbox.MailboxPairingState;
|
||||||
import org.briarproject.bramble.api.mailbox.MailboxStatus;
|
import org.briarproject.bramble.api.mailbox.MailboxStatus;
|
||||||
|
|
||||||
import androidx.annotation.Nullable;
|
|
||||||
|
|
||||||
class MailboxState {
|
class MailboxState {
|
||||||
|
|
||||||
static class NotSetup extends MailboxState {
|
static class NotSetup extends MailboxState {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static class ShowDownload extends MailboxState {
|
||||||
|
}
|
||||||
|
|
||||||
static class ScanningQrCode extends MailboxState {
|
static class ScanningQrCode extends MailboxState {
|
||||||
}
|
}
|
||||||
|
|
||||||
static class SettingUp extends MailboxState {
|
static class Pairing extends MailboxState {
|
||||||
}
|
final MailboxPairingState pairingState;
|
||||||
|
|
||||||
static class QrCodeWrong extends MailboxState {
|
Pairing(MailboxPairingState pairingState) {
|
||||||
}
|
this.pairingState = pairingState;
|
||||||
|
|
||||||
static class OfflineInSetup extends MailboxState {
|
|
||||||
@Nullable
|
|
||||||
final MailboxProperties mailboxProperties;
|
|
||||||
|
|
||||||
OfflineInSetup(@Nullable MailboxProperties mailboxProperties) {
|
|
||||||
this.mailboxProperties = mailboxProperties;
|
|
||||||
}
|
|
||||||
|
|
||||||
OfflineInSetup() {
|
|
||||||
this(null);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static class IsSetup extends MailboxState {
|
static class OfflineWhenPairing extends MailboxState {
|
||||||
|
}
|
||||||
|
|
||||||
|
static class CameraError extends MailboxState {
|
||||||
|
}
|
||||||
|
|
||||||
|
static class IsPaired extends MailboxState {
|
||||||
final MailboxStatus mailboxStatus;
|
final MailboxStatus mailboxStatus;
|
||||||
|
|
||||||
IsSetup(MailboxStatus mailboxStatus) {
|
IsPaired(MailboxStatus mailboxStatus) {
|
||||||
this.mailboxStatus = mailboxStatus;
|
this.mailboxStatus = mailboxStatus;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,86 @@
|
|||||||
|
package org.briarproject.briar.android.mailbox;
|
||||||
|
|
||||||
|
import android.content.Context;
|
||||||
|
import android.os.Bundle;
|
||||||
|
import android.view.LayoutInflater;
|
||||||
|
import android.view.View;
|
||||||
|
import android.view.ViewGroup;
|
||||||
|
import android.widget.TextView;
|
||||||
|
|
||||||
|
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.FragmentActivity;
|
||||||
|
import androidx.lifecycle.ViewModelProvider;
|
||||||
|
|
||||||
|
import static java.util.Objects.requireNonNull;
|
||||||
|
import static org.briarproject.briar.android.AppModule.getAndroidComponent;
|
||||||
|
import static org.briarproject.briar.android.util.UiUtils.formatDate;
|
||||||
|
|
||||||
|
@MethodsNotNullByDefault
|
||||||
|
@ParametersNotNullByDefault
|
||||||
|
public class MailboxStatusFragment extends Fragment {
|
||||||
|
|
||||||
|
static final String TAG = MailboxStatusFragment.class.getName();
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
ViewModelProvider.Factory viewModelFactory;
|
||||||
|
|
||||||
|
private MailboxViewModel viewModel;
|
||||||
|
|
||||||
|
@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,
|
||||||
|
@Nullable ViewGroup container,
|
||||||
|
@Nullable Bundle savedInstanceState) {
|
||||||
|
return inflater.inflate(R.layout.fragment_mailbox_status,
|
||||||
|
container, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onViewCreated(View v, @Nullable Bundle savedInstanceState) {
|
||||||
|
super.onViewCreated(v, savedInstanceState);
|
||||||
|
MailboxState.IsPaired state =
|
||||||
|
(MailboxState.IsPaired) viewModel.getState().getLastValue();
|
||||||
|
requireNonNull(state); // TODO check assumption
|
||||||
|
TextView statusInfoView = v.findViewById(R.id.statusInfoView);
|
||||||
|
long lastSuccess = state.mailboxStatus.getTimeOfLastSuccess();
|
||||||
|
String lastConnectionText;
|
||||||
|
if (lastSuccess < 0) {
|
||||||
|
lastConnectionText =
|
||||||
|
getString(R.string.mailbox_status_connected_never);
|
||||||
|
} else {
|
||||||
|
lastConnectionText = formatDate(requireContext(), lastSuccess);
|
||||||
|
}
|
||||||
|
String statusInfoText = getString(
|
||||||
|
R.string.mailbox_status_connected_info, lastConnectionText);
|
||||||
|
statusInfoView.setText(statusInfoText);
|
||||||
|
// TODO
|
||||||
|
// * react to status changes
|
||||||
|
// * detect problems and show them
|
||||||
|
// * update connection time periodically like conversation timestamps
|
||||||
|
// * add "Check connection" button
|
||||||
|
// * add "Unlink" button with confirmation dialog
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onStart() {
|
||||||
|
super.onStart();
|
||||||
|
requireActivity().setTitle(R.string.mailbox_status_title);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -4,15 +4,14 @@ import android.app.Application;
|
|||||||
|
|
||||||
import com.google.zxing.Result;
|
import com.google.zxing.Result;
|
||||||
|
|
||||||
import org.briarproject.bramble.api.FormatException;
|
import org.briarproject.bramble.api.Consumer;
|
||||||
import org.briarproject.bramble.api.crypto.CryptoComponent;
|
|
||||||
import org.briarproject.bramble.api.db.DatabaseExecutor;
|
import org.briarproject.bramble.api.db.DatabaseExecutor;
|
||||||
import org.briarproject.bramble.api.db.TransactionManager;
|
import org.briarproject.bramble.api.db.TransactionManager;
|
||||||
import org.briarproject.bramble.api.lifecycle.IoExecutor;
|
import org.briarproject.bramble.api.lifecycle.IoExecutor;
|
||||||
import org.briarproject.bramble.api.lifecycle.LifecycleManager;
|
import org.briarproject.bramble.api.lifecycle.LifecycleManager;
|
||||||
import org.briarproject.bramble.api.mailbox.MailboxAuthToken;
|
import org.briarproject.bramble.api.mailbox.MailboxManager;
|
||||||
import org.briarproject.bramble.api.mailbox.MailboxProperties;
|
import org.briarproject.bramble.api.mailbox.MailboxPairingState;
|
||||||
import org.briarproject.bramble.api.mailbox.MailboxSettingsManager;
|
import org.briarproject.bramble.api.mailbox.MailboxPairingTask;
|
||||||
import org.briarproject.bramble.api.mailbox.MailboxStatus;
|
import org.briarproject.bramble.api.mailbox.MailboxStatus;
|
||||||
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
|
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
|
||||||
import org.briarproject.bramble.api.plugin.Plugin;
|
import org.briarproject.bramble.api.plugin.Plugin;
|
||||||
@@ -25,38 +24,34 @@ import org.briarproject.briar.android.viewmodel.DbViewModel;
|
|||||||
import org.briarproject.briar.android.viewmodel.LiveEvent;
|
import org.briarproject.briar.android.viewmodel.LiveEvent;
|
||||||
import org.briarproject.briar.android.viewmodel.MutableLiveEvent;
|
import org.briarproject.briar.android.viewmodel.MutableLiveEvent;
|
||||||
|
|
||||||
import java.nio.charset.Charset;
|
|
||||||
import java.util.Arrays;
|
|
||||||
import java.util.concurrent.Executor;
|
import java.util.concurrent.Executor;
|
||||||
import java.util.logging.Logger;
|
import java.util.logging.Logger;
|
||||||
|
|
||||||
import javax.inject.Inject;
|
import javax.inject.Inject;
|
||||||
|
|
||||||
|
import androidx.annotation.AnyThread;
|
||||||
|
import androidx.annotation.Nullable;
|
||||||
import androidx.annotation.UiThread;
|
import androidx.annotation.UiThread;
|
||||||
|
|
||||||
import static java.util.Objects.requireNonNull;
|
import static java.util.logging.Level.INFO;
|
||||||
import static java.util.logging.Level.WARNING;
|
|
||||||
import static java.util.logging.Logger.getLogger;
|
import static java.util.logging.Logger.getLogger;
|
||||||
import static org.briarproject.bramble.api.plugin.Plugin.State.ACTIVE;
|
import static org.briarproject.bramble.api.plugin.Plugin.State.ACTIVE;
|
||||||
|
|
||||||
@NotNullByDefault
|
@NotNullByDefault
|
||||||
class MailboxViewModel extends DbViewModel
|
class MailboxViewModel extends DbViewModel
|
||||||
implements QrCodeDecoder.ResultCallback {
|
implements QrCodeDecoder.ResultCallback, Consumer<MailboxPairingState> {
|
||||||
|
|
||||||
private static final Logger LOG =
|
private static final Logger LOG =
|
||||||
getLogger(MailboxViewModel.class.getName());
|
getLogger(MailboxViewModel.class.getName());
|
||||||
|
|
||||||
@SuppressWarnings("CharsetObjectCanBeUsed") // Requires minSdkVersion >= 19
|
|
||||||
private static final Charset ISO_8859_1 = Charset.forName("ISO-8859-1");
|
|
||||||
private static final int VERSION_REQUIRED = 32;
|
|
||||||
|
|
||||||
private final CryptoComponent crypto;
|
|
||||||
private final QrCodeDecoder qrCodeDecoder;
|
private final QrCodeDecoder qrCodeDecoder;
|
||||||
private final PluginManager pluginManager;
|
private final PluginManager pluginManager;
|
||||||
private final MailboxSettingsManager mailboxSettingsManager;
|
private final MailboxManager mailboxManager;
|
||||||
|
|
||||||
private final MutableLiveEvent<MailboxState> state =
|
private final MutableLiveEvent<MailboxState> state =
|
||||||
new MutableLiveEvent<>();
|
new MutableLiveEvent<>();
|
||||||
|
@Nullable
|
||||||
|
private MailboxPairingTask pairingTask = null;
|
||||||
|
|
||||||
@Inject
|
@Inject
|
||||||
MailboxViewModel(
|
MailboxViewModel(
|
||||||
@@ -66,29 +61,43 @@ class MailboxViewModel extends DbViewModel
|
|||||||
TransactionManager db,
|
TransactionManager db,
|
||||||
AndroidExecutor androidExecutor,
|
AndroidExecutor androidExecutor,
|
||||||
@IoExecutor Executor ioExecutor,
|
@IoExecutor Executor ioExecutor,
|
||||||
CryptoComponent crypto,
|
|
||||||
PluginManager pluginManager,
|
PluginManager pluginManager,
|
||||||
MailboxSettingsManager mailboxSettingsManager) {
|
MailboxManager mailboxManager) {
|
||||||
super(app, dbExecutor, lifecycleManager, db, androidExecutor);
|
super(app, dbExecutor, lifecycleManager, db, androidExecutor);
|
||||||
this.crypto = crypto;
|
|
||||||
this.pluginManager = pluginManager;
|
this.pluginManager = pluginManager;
|
||||||
this.mailboxSettingsManager = mailboxSettingsManager;
|
this.mailboxManager = mailboxManager;
|
||||||
qrCodeDecoder = new QrCodeDecoder(androidExecutor, ioExecutor, this);
|
qrCodeDecoder = new QrCodeDecoder(androidExecutor, ioExecutor, this);
|
||||||
checkIfSetup();
|
checkIfSetup();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onCleared() {
|
||||||
|
super.onCleared();
|
||||||
|
MailboxPairingTask task = pairingTask;
|
||||||
|
if (task != null) {
|
||||||
|
task.removeObserver(this);
|
||||||
|
pairingTask = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@UiThread
|
@UiThread
|
||||||
private void checkIfSetup() {
|
private void checkIfSetup() {
|
||||||
runOnDbThread(true, txn -> {
|
MailboxPairingTask task = mailboxManager.getCurrentPairingTask();
|
||||||
MailboxProperties props =
|
if (task == null) {
|
||||||
mailboxSettingsManager.getOwnMailboxProperties(txn);
|
runOnDbThread(true, txn -> {
|
||||||
if (props == null) state.postEvent(new NotSetup());
|
boolean isPaired = mailboxManager.isPaired(txn);
|
||||||
else {
|
if (isPaired) {
|
||||||
MailboxStatus mailboxStatus =
|
MailboxStatus mailboxStatus =
|
||||||
mailboxSettingsManager.getOwnMailboxStatus(txn);
|
mailboxManager.getMailboxStatus(txn);
|
||||||
state.postEvent(new MailboxState.IsSetup(mailboxStatus));
|
state.postEvent(new MailboxState.IsPaired(mailboxStatus));
|
||||||
}
|
} else {
|
||||||
}, this::handleException);
|
state.postEvent(new NotSetup());
|
||||||
|
}
|
||||||
|
}, this::handleException);
|
||||||
|
} else {
|
||||||
|
task.addObserver(this);
|
||||||
|
pairingTask = task;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@UiThread
|
@UiThread
|
||||||
@@ -96,76 +105,50 @@ class MailboxViewModel extends DbViewModel
|
|||||||
if (isTorActive()) {
|
if (isTorActive()) {
|
||||||
state.setEvent(new MailboxState.ScanningQrCode());
|
state.setEvent(new MailboxState.ScanningQrCode());
|
||||||
} else {
|
} else {
|
||||||
state.setEvent(new MailboxState.OfflineInSetup());
|
state.setEvent(new MailboxState.OfflineWhenPairing());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@UiThread
|
||||||
|
void onCameraError() {
|
||||||
|
state.setEvent(new MailboxState.CameraError());
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@IoExecutor
|
@IoExecutor
|
||||||
public void onQrCodeDecoded(Result result) {
|
public void onQrCodeDecoded(Result result) {
|
||||||
LOG.info("Got result from decoder");
|
LOG.info("Got result from decoder");
|
||||||
MailboxProperties properties;
|
onQrCodePayloadReceived(result.getText());
|
||||||
try {
|
|
||||||
properties = decodeQrCode(result.getText());
|
|
||||||
} catch (FormatException e) {
|
|
||||||
state.postEvent(new MailboxState.QrCodeWrong());
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
onMailboxPropertiesReceived(properties);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@IoExecutor
|
@AnyThread
|
||||||
// TODO move this into core #2168
|
private void onQrCodePayloadReceived(String qrCodePayload) {
|
||||||
private MailboxProperties decodeQrCode(String payload)
|
|
||||||
throws FormatException {
|
|
||||||
byte[] bytes = payload.getBytes(ISO_8859_1);
|
|
||||||
if (bytes.length != 65) {
|
|
||||||
if (LOG.isLoggable(WARNING)) {
|
|
||||||
LOG.warning("QR code length is not 65: " + bytes.length);
|
|
||||||
}
|
|
||||||
throw new FormatException();
|
|
||||||
}
|
|
||||||
int version = bytes[0] & 0xFF;
|
|
||||||
if (version != VERSION_REQUIRED) {
|
|
||||||
if (LOG.isLoggable(WARNING)) {
|
|
||||||
LOG.warning("QR code has not version " + VERSION_REQUIRED +
|
|
||||||
": " + version);
|
|
||||||
}
|
|
||||||
throw new FormatException();
|
|
||||||
}
|
|
||||||
LOG.info("QR code is valid");
|
|
||||||
byte[] onionPubKey = Arrays.copyOfRange(bytes, 1, 33);
|
|
||||||
String onionAddress = crypto.encodeOnionAddress(onionPubKey);
|
|
||||||
byte[] tokenBytes = Arrays.copyOfRange(bytes, 33, 65);
|
|
||||||
MailboxAuthToken setupToken = new MailboxAuthToken(tokenBytes);
|
|
||||||
return new MailboxProperties(onionAddress, setupToken, true);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void onMailboxPropertiesReceived(MailboxProperties properties) {
|
|
||||||
if (isTorActive()) {
|
if (isTorActive()) {
|
||||||
// TODO pass props to core #2168
|
pairingTask = mailboxManager.startPairingTask(qrCodePayload);
|
||||||
state.postEvent(new MailboxState.SettingUp());
|
pairingTask.addObserver(this);
|
||||||
} else {
|
} else {
|
||||||
state.postEvent(new MailboxState.OfflineInSetup(properties));
|
state.postEvent(new MailboxState.OfflineWhenPairing());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO ideally also move this into core #2168
|
@UiThread
|
||||||
|
@Override
|
||||||
|
public void accept(MailboxPairingState mailboxPairingState) {
|
||||||
|
if (LOG.isLoggable(INFO)) {
|
||||||
|
LOG.info("New pairing state: " +
|
||||||
|
mailboxPairingState.getClass().getSimpleName());
|
||||||
|
}
|
||||||
|
state.setEvent(new MailboxState.Pairing(mailboxPairingState));
|
||||||
|
}
|
||||||
|
|
||||||
private boolean isTorActive() {
|
private boolean isTorActive() {
|
||||||
Plugin plugin = pluginManager.getPlugin(TorConstants.ID);
|
Plugin plugin = pluginManager.getPlugin(TorConstants.ID);
|
||||||
return plugin != null && plugin.getState() == ACTIVE;
|
return plugin != null && plugin.getState() == ACTIVE;
|
||||||
}
|
}
|
||||||
|
|
||||||
@UiThread
|
@UiThread
|
||||||
void tryAgainWhenOffline() {
|
void showDownloadFragment() {
|
||||||
MailboxState.OfflineInSetup offline =
|
state.setEvent(new MailboxState.ShowDownload());
|
||||||
(MailboxState.OfflineInSetup) requireNonNull(
|
|
||||||
state.getLastValue());
|
|
||||||
if (offline.mailboxProperties == null) {
|
|
||||||
onScanButtonClicked();
|
|
||||||
} else {
|
|
||||||
onMailboxPropertiesReceived(offline.mailboxProperties);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@UiThread
|
@UiThread
|
||||||
|
|||||||
@@ -62,10 +62,7 @@ public class OfflineFragment extends Fragment {
|
|||||||
startActivity(i);
|
startActivity(i);
|
||||||
});
|
});
|
||||||
buttonView = v.findViewById(R.id.button);
|
buttonView = v.findViewById(R.id.button);
|
||||||
buttonView.setOnClickListener(view -> {
|
buttonView.setOnClickListener(view -> viewModel.showDownloadFragment());
|
||||||
getParentFragmentManager().popBackStackImmediate();
|
|
||||||
viewModel.tryAgainWhenOffline();
|
|
||||||
});
|
|
||||||
|
|
||||||
return v;
|
return v;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
package org.briarproject.briar.android.mailbox;
|
package org.briarproject.briar.android.mailbox;
|
||||||
|
|
||||||
|
import android.content.Context;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
import android.view.LayoutInflater;
|
import android.view.LayoutInflater;
|
||||||
import android.view.View;
|
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.bramble.api.nullsafety.ParametersNotNullByDefault;
|
||||||
import org.briarproject.briar.R;
|
import org.briarproject.briar.R;
|
||||||
|
|
||||||
|
import javax.inject.Inject;
|
||||||
|
|
||||||
import androidx.annotation.Nullable;
|
import androidx.annotation.Nullable;
|
||||||
import androidx.fragment.app.Fragment;
|
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 android.view.View.FOCUS_DOWN;
|
||||||
import static org.briarproject.briar.android.util.UiUtils.showFragment;
|
import static org.briarproject.briar.android.AppModule.getAndroidComponent;
|
||||||
|
|
||||||
@MethodsNotNullByDefault
|
@MethodsNotNullByDefault
|
||||||
@ParametersNotNullByDefault
|
@ParametersNotNullByDefault
|
||||||
@@ -24,8 +28,22 @@ public class SetupIntroFragment extends Fragment {
|
|||||||
|
|
||||||
static final String TAG = SetupIntroFragment.class.getName();
|
static final String TAG = SetupIntroFragment.class.getName();
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
ViewModelProvider.Factory viewModelFactory;
|
||||||
|
|
||||||
|
private MailboxViewModel viewModel;
|
||||||
|
|
||||||
private ScrollView scrollView;
|
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
|
@Nullable
|
||||||
@Override
|
@Override
|
||||||
public View onCreateView(LayoutInflater inflater,
|
public View onCreateView(LayoutInflater inflater,
|
||||||
@@ -35,11 +53,7 @@ public class SetupIntroFragment extends Fragment {
|
|||||||
container, false);
|
container, false);
|
||||||
scrollView = v.findViewById(R.id.scrollView);
|
scrollView = v.findViewById(R.id.scrollView);
|
||||||
Button button = v.findViewById(R.id.continueButton);
|
Button button = v.findViewById(R.id.continueButton);
|
||||||
button.setOnClickListener(view -> {
|
button.setOnClickListener(view -> viewModel.showDownloadFragment());
|
||||||
FragmentManager fm = getParentFragmentManager();
|
|
||||||
Fragment f = new SetupDownloadFragment();
|
|
||||||
showFragment(fm, f, SetupDownloadFragment.TAG);
|
|
||||||
});
|
|
||||||
return v;
|
return v;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -35,7 +35,7 @@
|
|||||||
android:layout_marginHorizontal="@dimen/margin_xlarge"
|
android:layout_marginHorizontal="@dimen/margin_xlarge"
|
||||||
android:layout_marginTop="@dimen/margin_xlarge"
|
android:layout_marginTop="@dimen/margin_xlarge"
|
||||||
android:layout_marginBottom="@dimen/margin_large"
|
android:layout_marginBottom="@dimen/margin_large"
|
||||||
android:text="@string/mailbox_setup_intro"
|
android:text="@string/mailbox_setup_download"
|
||||||
android:textAppearance="@style/TextAppearance.MaterialComponents.Body1"
|
android:textAppearance="@style/TextAppearance.MaterialComponents.Body1"
|
||||||
app:layout_constraintBottom_toTopOf="@+id/scanButton"
|
app:layout_constraintBottom_toTopOf="@+id/scanButton"
|
||||||
app:layout_constraintEnd_toEndOf="parent"
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
|
|||||||
@@ -0,0 +1,51 @@
|
|||||||
|
<?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:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
tools:context=".android.mailbox.MailboxActivity">
|
||||||
|
|
||||||
|
<ImageView
|
||||||
|
android:id="@+id/imageView"
|
||||||
|
android:layout_width="32dp"
|
||||||
|
android:layout_height="32dp"
|
||||||
|
android:layout_marginStart="16dp"
|
||||||
|
android:layout_marginLeft="16dp"
|
||||||
|
app:layout_constraintBottom_toBottomOf="parent"
|
||||||
|
app:layout_constraintEnd_toStartOf="@+id/statusTitleView"
|
||||||
|
app:layout_constraintHorizontal_chainStyle="packed"
|
||||||
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
|
app:layout_constraintTop_toTopOf="parent"
|
||||||
|
app:layout_constraintVertical_chainStyle="packed"
|
||||||
|
app:srcCompat="@drawable/ic_check_circle_outline"
|
||||||
|
app:tint="@color/briar_brand_green"
|
||||||
|
tools:ignore="ContentDescription" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/statusTitleView"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginHorizontal="16dp"
|
||||||
|
android:text="@string/mailbox_status_connected_title"
|
||||||
|
android:textAppearance="@style/TextAppearance.MaterialComponents.Headline6"
|
||||||
|
app:layout_constrainedWidth="true"
|
||||||
|
app:layout_constraintBottom_toBottomOf="@+id/imageView"
|
||||||
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
|
app:layout_constraintStart_toEndOf="@+id/imageView"
|
||||||
|
app:layout_constraintTop_toTopOf="@+id/imageView" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/statusInfoView"
|
||||||
|
android:layout_width="0dp"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_margin="16dp"
|
||||||
|
android:gravity="center"
|
||||||
|
app:layout_constraintBottom_toBottomOf="parent"
|
||||||
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
|
app:layout_constraintTop_toBottomOf="@+id/statusTitleView"
|
||||||
|
app:layout_constraintVertical_bias="0.0"
|
||||||
|
tools:text="@string/mailbox_status_connected_info" />
|
||||||
|
|
||||||
|
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||||
@@ -614,7 +614,7 @@
|
|||||||
|
|
||||||
<!-- Mailbox -->
|
<!-- Mailbox -->
|
||||||
<string name="mailbox_settings_title">Mailbox</string>
|
<string name="mailbox_settings_title">Mailbox</string>
|
||||||
<string name="mailbox_setup_title">Mailbox Setup</string>
|
<string name="mailbox_setup_title">Mailbox setup</string>
|
||||||
<string name="mailbox_setup_intro">A Mailbox enables your contacts to send you messages while you are offline. The Mailbox will receive your messages and store them until you come online.\n
|
<string name="mailbox_setup_intro">A Mailbox enables your contacts to send you messages while you are offline. The Mailbox will receive your messages and store them until you come online.\n
|
||||||
\nYou can install the Briar Mailbox app on a spare device. Keep it connected to power and Wi-Fi so it\'s always online.</string>
|
\nYou can install the Briar Mailbox app on a spare device. Keep it connected to power and Wi-Fi so it\'s always online.</string>
|
||||||
<string name="mailbox_setup_download">First, install the Mailbox app on another device by searching for \"Briar Mailbox\" on Google Play or wherever you downloaded Briar.\n
|
<string name="mailbox_setup_download">First, install the Mailbox app on another device by searching for \"Briar Mailbox\" on Google Play or wherever you downloaded Briar.\n
|
||||||
@@ -624,10 +624,28 @@
|
|||||||
<string name="permission_camera_qr_denied_body">You have denied access to the camera, but scanning a QR code requires using the camera.\n\nPlease consider granting access.</string>
|
<string name="permission_camera_qr_denied_body">You have denied access to the camera, but scanning a QR code requires using the camera.\n\nPlease consider granting access.</string>
|
||||||
<string name="mailbox_setup_connecting">Connecting…</string>
|
<string name="mailbox_setup_connecting">Connecting…</string>
|
||||||
<string name="mailbox_setup_qr_code_wrong_title">Wrong QR code</string>
|
<string name="mailbox_setup_qr_code_wrong_title">Wrong QR code</string>
|
||||||
<string name="mailbox_setup_qr_code_wrong_description">The scanned code is invalid. Please open the Briar Mailbox app on your mailbox device and scan the QR code it presents.</string>
|
<string name="mailbox_setup_qr_code_wrong_description">The scanned code is invalid. Please open the Briar Mailbox app on your Mailbox device and scan the QR code it presents.</string>
|
||||||
|
<string name="mailbox_setup_already_paired_title">Mailbox already linked</string>
|
||||||
|
<string name="mailbox_setup_already_paired_description">Unlink the Mailbox on your other device and try again.</string>
|
||||||
|
<string name="mailbox_setup_io_error_title">Could not connect</string>
|
||||||
|
<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>
|
||||||
<string name="tor_offline_title">Offline</string>
|
<string name="tor_offline_title">Offline</string>
|
||||||
<string name="tor_offline_description">Ensure that this device is online and connections to the internet are allowed.\n\nAfterwards, wait for the globe icon in connection settings to turn green.</string>
|
<string name="tor_offline_description">Ensure that this device is online and connections to the Internet are allowed.\n
|
||||||
|
\nAfterwards, wait for the globe icon in the connection settings screen to turn green.</string>
|
||||||
<string name="tor_offline_button_check">Check connection settings</string>
|
<string name="tor_offline_button_check">Check connection settings</string>
|
||||||
|
<string name="mailbox_status_title">Mailbox status</string>
|
||||||
|
<string name="mailbox_status_connected_title">Mailbox is running</string>
|
||||||
|
<!-- Example for string substitution: Last connection: 3min ago-->
|
||||||
|
<string name="mailbox_status_connected_info">Last connection: %s</string>
|
||||||
|
<!-- Indicates that there never was a connection to the mailbox. Last connection: Never -->
|
||||||
|
<string name="mailbox_status_connected_never">Never</string>
|
||||||
|
|
||||||
<!-- Conversation Settings -->
|
<!-- Conversation Settings -->
|
||||||
<string name="disappearing_messages_title">Disappearing messages</string>
|
<string name="disappearing_messages_title">Disappearing messages</string>
|
||||||
|
|||||||
@@ -0,0 +1,6 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<network-security-config>
|
||||||
|
<domain-config cleartextTrafficPermitted="true">
|
||||||
|
<domain includeSubdomains="true">onion</domain>
|
||||||
|
</domain-config>
|
||||||
|
</network-security-config>
|
||||||
Reference in New Issue
Block a user