mirror of
https://code.briarproject.org/briar/briar.git
synced 2026-02-13 19:29:06 +01:00
Troubleshooting wizard for mailbox
This commit is contained in:
@@ -45,6 +45,7 @@ import org.briarproject.briar.android.hotspot.QrHotspotFragment;
|
||||
import org.briarproject.briar.android.logging.CachingLogHandler;
|
||||
import org.briarproject.briar.android.login.SignInReminderReceiver;
|
||||
import org.briarproject.briar.android.mailbox.ErrorFragment;
|
||||
import org.briarproject.briar.android.mailbox.ErrorWizardFragment;
|
||||
import org.briarproject.briar.android.mailbox.MailboxScanFragment;
|
||||
import org.briarproject.briar.android.mailbox.MailboxStatusFragment;
|
||||
import org.briarproject.briar.android.mailbox.OfflineFragment;
|
||||
@@ -257,4 +258,6 @@ public interface AndroidComponent
|
||||
void inject(ErrorFragment errorFragment);
|
||||
|
||||
void inject(MailboxStatusFragment mailboxStatusFragment);
|
||||
|
||||
void inject(ErrorWizardFragment errorWizardFragment);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,202 @@
|
||||
package org.briarproject.briar.android.mailbox;
|
||||
|
||||
import android.animation.ValueAnimator;
|
||||
import android.content.Context;
|
||||
import android.os.Bundle;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.RadioButton;
|
||||
import android.widget.RadioGroup;
|
||||
import android.widget.ScrollView;
|
||||
|
||||
import com.google.android.material.animation.ArgbEvaluatorCompat;
|
||||
|
||||
import org.briarproject.bramble.api.nullsafety.MethodsNotNullByDefault;
|
||||
import org.briarproject.bramble.api.nullsafety.ParametersNotNullByDefault;
|
||||
import org.briarproject.briar.R;
|
||||
import org.briarproject.briar.android.view.BriarButton;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import javax.inject.Inject;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.appcompat.app.AlertDialog;
|
||||
import androidx.fragment.app.Fragment;
|
||||
import androidx.fragment.app.FragmentActivity;
|
||||
import androidx.lifecycle.ViewModelProvider;
|
||||
import androidx.transition.AutoTransition;
|
||||
import androidx.transition.Transition;
|
||||
|
||||
import static android.view.View.FOCUS_DOWN;
|
||||
import static android.view.View.GONE;
|
||||
import static android.view.View.VISIBLE;
|
||||
import static androidx.core.content.ContextCompat.getColor;
|
||||
import static androidx.transition.TransitionManager.beginDelayedTransition;
|
||||
import static org.briarproject.briar.android.AppModule.getAndroidComponent;
|
||||
|
||||
@MethodsNotNullByDefault
|
||||
@ParametersNotNullByDefault
|
||||
public class ErrorWizardFragment extends Fragment {
|
||||
|
||||
static final String TAG = ErrorWizardFragment.class.getName();
|
||||
|
||||
@Inject
|
||||
ViewModelProvider.Factory viewModelFactory;
|
||||
|
||||
private MailboxViewModel viewModel;
|
||||
private ScrollView scrollView;
|
||||
private ValueAnimator colorAnim;
|
||||
private final Transition transition = new AutoTransition();
|
||||
|
||||
@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) {
|
||||
View v = inflater.inflate(R.layout.fragment_mailbox_error_wizard,
|
||||
container, false);
|
||||
scrollView = (ScrollView) v;
|
||||
|
||||
int startColor =
|
||||
getColor(v.getContext(), R.color.briar_accent);
|
||||
int endColor = getColor(v.getContext(), R.color.window_background);
|
||||
colorAnim = ValueAnimator
|
||||
.ofObject(new ArgbEvaluatorCompat(), startColor, endColor);
|
||||
colorAnim.setDuration(2500);
|
||||
|
||||
return v;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onViewCreated(View v, @Nullable Bundle savedInstanceState) {
|
||||
RadioGroup radioGroup1 = v.findViewById(R.id.radioGroup1);
|
||||
List<RadioButton> radioButtons1 = new ArrayList<>(3);
|
||||
radioButtons1.add(v.findViewById(R.id.radioButton1));
|
||||
radioButtons1.add(v.findViewById(R.id.radioButton2));
|
||||
radioButtons1.add(v.findViewById(R.id.radioButton3));
|
||||
List<View> views1 = new ArrayList<>(3);
|
||||
View info1 = v.findViewById(R.id.info1);
|
||||
views1.add(info1);
|
||||
views1.add(v.findViewById(R.id.info2));
|
||||
View info3 = v.findViewById(R.id.info3);
|
||||
views1.add(info3);
|
||||
setUpRadioGroup(radioGroup1, radioButtons1, views1);
|
||||
|
||||
RadioGroup radioGroup1_1 = info1.findViewById(R.id.radioGroup1_1);
|
||||
List<RadioButton> radioButtons1_1 = new ArrayList<>(3);
|
||||
radioButtons1_1.add(info1.findViewById(R.id.radioButton1_1));
|
||||
radioButtons1_1.add(info1.findViewById(R.id.radioButton1_2));
|
||||
radioButtons1_1.add(info1.findViewById(R.id.radioButton1_3));
|
||||
radioButtons1_1.add(info1.findViewById(R.id.radioButton1_4));
|
||||
List<View> views1_1 = new ArrayList<>(3);
|
||||
views1_1.add(info1.findViewById(R.id.info1_1_1));
|
||||
views1_1.add(info1.findViewById(R.id.info1_1_2));
|
||||
views1_1.add(info1.findViewById(R.id.info1_1_3));
|
||||
views1_1.add(info1.findViewById(R.id.info1_1_4));
|
||||
setUpRadioGroup(radioGroup1_1, radioButtons1_1, views1_1);
|
||||
|
||||
// set up unlink buttons
|
||||
BriarButton button3 = info3.findViewById(R.id.button3);
|
||||
BriarButton button1_1_1 = info1.findViewById(R.id.button1_1_1);
|
||||
BriarButton button1_1_2 = info1.findViewById(R.id.button1_1_2);
|
||||
button3.setOnClickListener(this::onUnlinkButtonClicked);
|
||||
button1_1_1.setOnClickListener(this::onUnlinkButtonClicked);
|
||||
button1_1_2.setOnClickListener(this::onUnlinkButtonClicked);
|
||||
|
||||
// set up check connection button
|
||||
BriarButton button1_1_3 = info1.findViewById(R.id.button1_1_3);
|
||||
button1_1_3.setOnClickListener(this::onCheckConnectionButtonClicked);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onStart() {
|
||||
super.onStart();
|
||||
requireActivity().setTitle(R.string.mailbox_error_wizard_title);
|
||||
}
|
||||
|
||||
private void setUpRadioGroup(RadioGroup radioGroup,
|
||||
List<RadioButton> radioButtons, List<View> views) {
|
||||
if (radioButtons.size() != views.size()) {
|
||||
throw new IllegalArgumentException();
|
||||
}
|
||||
radioGroup.setOnCheckedChangeListener((group, checkedId) -> {
|
||||
onCheckedChanged();
|
||||
for (int i = 0; i < radioButtons.size(); i++) {
|
||||
RadioButton radioButton = radioButtons.get(i);
|
||||
View view = views.get(i);
|
||||
if (checkedId == radioButton.getId()) {
|
||||
animateColor(view);
|
||||
view.setVisibility(VISIBLE);
|
||||
} else {
|
||||
view.setVisibility(GONE);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private void onUnlinkButtonClicked(View v) {
|
||||
AlertDialog.Builder builder = new AlertDialog.Builder(requireContext(),
|
||||
R.style.BriarDialogTheme);
|
||||
builder.setTitle(R.string.mailbox_status_unlink_dialog_title);
|
||||
builder.setMessage(R.string.mailbox_status_unlink_dialog_question);
|
||||
builder.setPositiveButton(R.string.cancel,
|
||||
(dialog, which) -> dialog.cancel());
|
||||
builder.setNegativeButton(R.string.mailbox_status_unlink_button,
|
||||
(dialog, which) -> viewModel.unlink());
|
||||
builder.setOnCancelListener(dialog -> ((BriarButton) v).reset());
|
||||
builder.show();
|
||||
}
|
||||
|
||||
private void onCheckConnectionButtonClicked(View v) {
|
||||
viewModel.checkConnectionFromWizard();
|
||||
}
|
||||
|
||||
private void animateColor(View v) {
|
||||
if (colorAnim.isRunning()) colorAnim.end();
|
||||
colorAnim.removeAllUpdateListeners();
|
||||
colorAnim.addUpdateListener(animation ->
|
||||
v.setBackgroundColor((int) animation.getAnimatedValue())
|
||||
);
|
||||
colorAnim.start();
|
||||
}
|
||||
|
||||
private void onCheckedChanged() {
|
||||
transition.addListener(new Transition.TransitionListener() {
|
||||
@Override
|
||||
public void onTransitionStart(@NonNull Transition transition) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onTransitionEnd(@NonNull Transition transition) {
|
||||
scrollView.fullScroll(FOCUS_DOWN);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onTransitionCancel(@NonNull Transition transition) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onTransitionPause(@NonNull Transition transition) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onTransitionResume(@NonNull Transition transition) {
|
||||
}
|
||||
});
|
||||
beginDelayedTransition(scrollView, transition);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -17,6 +17,7 @@ import org.briarproject.bramble.api.mailbox.MailboxStatus;
|
||||
import org.briarproject.bramble.api.nullsafety.MethodsNotNullByDefault;
|
||||
import org.briarproject.bramble.api.nullsafety.ParametersNotNullByDefault;
|
||||
import org.briarproject.briar.R;
|
||||
import org.briarproject.briar.android.view.BriarButton;
|
||||
|
||||
import javax.inject.Inject;
|
||||
|
||||
@@ -29,6 +30,7 @@ import androidx.fragment.app.Fragment;
|
||||
import androidx.fragment.app.FragmentActivity;
|
||||
import androidx.lifecycle.ViewModelProvider;
|
||||
|
||||
import static android.view.View.GONE;
|
||||
import static android.view.View.INVISIBLE;
|
||||
import static android.view.View.VISIBLE;
|
||||
import static androidx.core.content.ContextCompat.getColor;
|
||||
@@ -38,6 +40,7 @@ import static org.briarproject.briar.android.AppModule.getAndroidComponent;
|
||||
import static org.briarproject.briar.android.util.UiUtils.MIN_DATE_RESOLUTION;
|
||||
import static org.briarproject.briar.android.util.UiUtils.formatDate;
|
||||
import static org.briarproject.briar.android.util.UiUtils.observeOnce;
|
||||
import static org.briarproject.briar.android.util.UiUtils.showFragment;
|
||||
|
||||
@MethodsNotNullByDefault
|
||||
@ParametersNotNullByDefault
|
||||
@@ -58,6 +61,7 @@ public class MailboxStatusFragment extends Fragment {
|
||||
private ImageView imageView;
|
||||
private TextView statusTitleView;
|
||||
private TextView statusInfoView;
|
||||
private Button wizardButton;
|
||||
private Button unlinkButton;
|
||||
private ProgressBar unlinkProgress;
|
||||
|
||||
@@ -83,18 +87,11 @@ public class MailboxStatusFragment extends Fragment {
|
||||
public void onViewCreated(View v, @Nullable Bundle savedInstanceState) {
|
||||
super.onViewCreated(v, savedInstanceState);
|
||||
|
||||
Button checkButton = v.findViewById(R.id.checkButton);
|
||||
ProgressBar checkProgress = v.findViewById(R.id.checkProgress);
|
||||
checkButton.setOnClickListener(view -> {
|
||||
beginDelayedTransition((ViewGroup) v);
|
||||
checkButton.setVisibility(INVISIBLE);
|
||||
checkProgress.setVisibility(VISIBLE);
|
||||
observeOnce(viewModel.checkConnection(), this, result -> {
|
||||
beginDelayedTransition((ViewGroup) v);
|
||||
checkButton.setVisibility(VISIBLE);
|
||||
checkProgress.setVisibility(INVISIBLE);
|
||||
});
|
||||
});
|
||||
BriarButton checkButton = v.findViewById(R.id.checkButton);
|
||||
checkButton.setOnClickListener(view ->
|
||||
observeOnce(viewModel.checkConnection(), this, result ->
|
||||
checkButton.reset()
|
||||
));
|
||||
|
||||
imageView = v.findViewById(R.id.imageView);
|
||||
statusTitleView = v.findViewById(R.id.statusTitleView);
|
||||
@@ -102,8 +99,13 @@ public class MailboxStatusFragment extends Fragment {
|
||||
viewModel.getStatus()
|
||||
.observe(getViewLifecycleOwner(), this::onMailboxStateChanged);
|
||||
|
||||
// TODO
|
||||
// * Implement UI for warning user when mailbox is unreachable #2175
|
||||
wizardButton = v.findViewById(R.id.wizardButton);
|
||||
wizardButton.setOnClickListener(view -> {
|
||||
Fragment f = new ErrorWizardFragment();
|
||||
String tag = ErrorWizardFragment.TAG;
|
||||
showFragment(getParentFragmentManager(), f, tag, false);
|
||||
});
|
||||
|
||||
unlinkButton = v.findViewById(R.id.unlinkButton);
|
||||
unlinkProgress = v.findViewById(R.id.unlinkProgress);
|
||||
unlinkButton.setOnClickListener(view ->
|
||||
@@ -135,16 +137,19 @@ public class MailboxStatusFragment extends Fragment {
|
||||
title = getString(R.string.mailbox_status_connected_title);
|
||||
tintRes = R.color.briar_brand_green;
|
||||
showUnlinkWarning = true;
|
||||
wizardButton.setVisibility(GONE);
|
||||
} else if (status.getAttemptsSinceSuccess() < NUM_FAILURES) {
|
||||
iconRes = R.drawable.ic_help_outline_white;
|
||||
title = getString(R.string.mailbox_status_problem_title);
|
||||
tintRes = R.color.briar_orange_500;
|
||||
showUnlinkWarning = false;
|
||||
wizardButton.setVisibility(GONE);
|
||||
} else {
|
||||
tintRes = R.color.briar_red_500;
|
||||
title = getString(R.string.mailbox_status_failure_title);
|
||||
iconRes = R.drawable.alerts_and_states_error;
|
||||
showUnlinkWarning = false;
|
||||
wizardButton.setVisibility(VISIBLE);
|
||||
}
|
||||
imageView.setImageResource(iconRes);
|
||||
int color = getColor(requireContext(), tintRes);
|
||||
|
||||
@@ -204,11 +204,7 @@ class MailboxViewModel extends DbViewModel
|
||||
|
||||
LiveData<Boolean> checkConnection() {
|
||||
MutableLiveData<Boolean> liveData = new MutableLiveData<>();
|
||||
ioExecutor.execute(() -> {
|
||||
boolean success = mailboxManager.checkConnection();
|
||||
if (LOG.isLoggable(INFO)) {
|
||||
LOG.info("Got result from connection check: " + success);
|
||||
}
|
||||
checkConnection(success -> {
|
||||
liveData.postValue(success);
|
||||
if (!success) { // force failure screen
|
||||
MailboxStatus lastStatus = status.getValue();
|
||||
@@ -221,6 +217,23 @@ class MailboxViewModel extends DbViewModel
|
||||
return liveData;
|
||||
}
|
||||
|
||||
void checkConnectionFromWizard() {
|
||||
checkConnection(success -> {
|
||||
boolean isOnline = isTorActive();
|
||||
pairingState.postEvent(new MailboxState.IsPaired(isOnline));
|
||||
});
|
||||
}
|
||||
|
||||
private void checkConnection(@IoExecutor Consumer<Boolean> consumer) {
|
||||
ioExecutor.execute(() -> {
|
||||
boolean success = mailboxManager.checkConnection();
|
||||
if (LOG.isLoggable(INFO)) {
|
||||
LOG.info("Got result from connection check: " + success);
|
||||
}
|
||||
consumer.accept(success);
|
||||
});
|
||||
}
|
||||
|
||||
@UiThread
|
||||
void unlink() {
|
||||
ioExecutor.execute(() -> {
|
||||
|
||||
@@ -0,0 +1,75 @@
|
||||
package org.briarproject.briar.android.view;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.res.TypedArray;
|
||||
import android.util.AttributeSet;
|
||||
import android.view.LayoutInflater;
|
||||
import android.widget.Button;
|
||||
import android.widget.FrameLayout;
|
||||
import android.widget.ProgressBar;
|
||||
|
||||
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
|
||||
import org.briarproject.briar.R;
|
||||
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.appcompat.view.ContextThemeWrapper;
|
||||
import androidx.appcompat.widget.AppCompatButton;
|
||||
|
||||
import static android.content.Context.LAYOUT_INFLATER_SERVICE;
|
||||
import static androidx.transition.TransitionManager.beginDelayedTransition;
|
||||
|
||||
@NotNullByDefault
|
||||
public class BriarButton extends FrameLayout {
|
||||
|
||||
private final Button button;
|
||||
private final ProgressBar progressBar;
|
||||
|
||||
public BriarButton(Context context) {
|
||||
this(context, null);
|
||||
}
|
||||
|
||||
public BriarButton(Context context, @Nullable AttributeSet attrs) {
|
||||
this(context, attrs, 0);
|
||||
}
|
||||
|
||||
public BriarButton(Context context, @Nullable AttributeSet attrs,
|
||||
int defStyleAttr) {
|
||||
super(context, attrs, defStyleAttr);
|
||||
LayoutInflater inflater = (LayoutInflater) context
|
||||
.getSystemService(LAYOUT_INFLATER_SERVICE);
|
||||
inflater.inflate(R.layout.briar_button, this, true);
|
||||
|
||||
TypedArray attributes =
|
||||
context.obtainStyledAttributes(attrs, R.styleable.BriarButton);
|
||||
String text = attributes.getString(R.styleable.BriarButton_text);
|
||||
int style = attributes
|
||||
.getResourceId(R.styleable.BriarButton_buttonStyle, 0);
|
||||
attributes.recycle();
|
||||
|
||||
ContextThemeWrapper wrapper = new ContextThemeWrapper(context, style);
|
||||
button = new AppCompatButton(wrapper, null, style);
|
||||
button.setText(text);
|
||||
addView(button);
|
||||
progressBar = findViewById(R.id.briar_button_progress_bar);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setOnClickListener(@Nullable OnClickListener l) {
|
||||
if (l == null) button.setOnClickListener(null);
|
||||
else {
|
||||
button.setOnClickListener(v -> {
|
||||
beginDelayedTransition(this);
|
||||
progressBar.setVisibility(VISIBLE);
|
||||
button.setVisibility(INVISIBLE);
|
||||
l.onClick(this);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
public void reset() {
|
||||
beginDelayedTransition(this);
|
||||
progressBar.setVisibility(INVISIBLE);
|
||||
button.setVisibility(VISIBLE);
|
||||
}
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user