parent
d0681a5592
commit
220ebf93c7
|
@ -8,9 +8,11 @@ import androidx.annotation.Nullable;
|
|||
|
||||
import org.thoughtcrime.securesms.R;
|
||||
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
public class CallMeCountDownView extends androidx.appcompat.widget.AppCompatButton {
|
||||
|
||||
private int countDown;
|
||||
private long countDownToTime;
|
||||
@Nullable
|
||||
private Listener listener;
|
||||
|
||||
|
@ -26,9 +28,14 @@ public class CallMeCountDownView extends androidx.appcompat.widget.AppCompatButt
|
|||
super(context, attrs, defStyleAttr);
|
||||
}
|
||||
|
||||
public void startCountDown(int countDown) {
|
||||
this.countDown = countDown;
|
||||
updateCountDown();
|
||||
/**
|
||||
* Starts a count down to the specified {@param time}.
|
||||
*/
|
||||
public void startCountDownTo(long time) {
|
||||
if (time > 0) {
|
||||
this.countDownToTime = time;
|
||||
updateCountDown();
|
||||
}
|
||||
}
|
||||
|
||||
public void setCallEnabled() {
|
||||
|
@ -38,23 +45,24 @@ public class CallMeCountDownView extends androidx.appcompat.widget.AppCompatButt
|
|||
}
|
||||
|
||||
private void updateCountDown() {
|
||||
if (countDown > 0) {
|
||||
final long remainingMillis = countDownToTime - System.currentTimeMillis();
|
||||
|
||||
if (remainingMillis > 0) {
|
||||
setEnabled(false);
|
||||
setAlpha(0.5f);
|
||||
|
||||
countDown--;
|
||||
|
||||
int minutesRemaining = countDown / 60;
|
||||
int secondsRemaining = countDown % 60;
|
||||
int totalRemainingSeconds = (int) TimeUnit.MILLISECONDS.toSeconds(remainingMillis);
|
||||
int minutesRemaining = totalRemainingSeconds / 60;
|
||||
int secondsRemaining = totalRemainingSeconds % 60;
|
||||
|
||||
setText(getResources().getString(R.string.RegistrationActivity_call_me_instead_available_in, minutesRemaining, secondsRemaining));
|
||||
|
||||
if (listener != null) {
|
||||
listener.onRemaining(this, countDown);
|
||||
listener.onRemaining(this, totalRemainingSeconds);
|
||||
}
|
||||
|
||||
postDelayed(this::updateCountDown, 1000);
|
||||
} else if (countDown == 0) {
|
||||
postDelayed(this::updateCountDown, 250);
|
||||
} else {
|
||||
setCallEnabled();
|
||||
}
|
||||
}
|
||||
|
@ -64,6 +72,6 @@ public class CallMeCountDownView extends androidx.appcompat.widget.AppCompatButt
|
|||
}
|
||||
|
||||
public interface Listener {
|
||||
void onRemaining(@NonNull CallMeCountDownView view, int remaining);
|
||||
void onRemaining(@NonNull CallMeCountDownView view, int secondsRemaining);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -29,7 +29,7 @@ public class AccountLockedFragment extends BaseRegistrationFragment {
|
|||
|
||||
TextView description = view.findViewById(R.id.account_locked_description);
|
||||
|
||||
getModel().getTimeRemaining().observe(getViewLifecycleOwner(),
|
||||
getModel().getLockedTimeRemaining().observe(getViewLifecycleOwner(),
|
||||
t -> description.setText(getString(R.string.AccountLockedFragment__your_account_has_been_locked_to_protect_your_privacy, durationToDays(t)))
|
||||
);
|
||||
|
||||
|
|
|
@ -85,12 +85,15 @@ public final class EnterCodeFragment extends BaseRegistrationFragment {
|
|||
|
||||
noCodeReceivedHelp.setOnClickListener(v -> sendEmailToSupport());
|
||||
|
||||
getModel().getSuccessfulCodeRequestAttempts().observe(this, (attempts) -> {
|
||||
RegistrationViewModel model = getModel();
|
||||
model.getSuccessfulCodeRequestAttempts().observe(this, (attempts) -> {
|
||||
if (attempts >= 3) {
|
||||
noCodeReceivedHelp.setVisibility(View.VISIBLE);
|
||||
scrollView.postDelayed(() -> scrollView.smoothScrollTo(0, noCodeReceivedHelp.getBottom()), 15000);
|
||||
}
|
||||
});
|
||||
|
||||
model.onStartEnterCode();
|
||||
}
|
||||
|
||||
private void setOnCodeFullyEnteredListener(VerificationCodeView verificationCodeView) {
|
||||
|
@ -119,7 +122,7 @@ public final class EnterCodeFragment extends BaseRegistrationFragment {
|
|||
|
||||
@Override
|
||||
public void onV1RegistrationLockPinRequiredOrIncorrect(long timeRemaining) {
|
||||
model.setTimeRemaining(timeRemaining);
|
||||
model.setLockedTimeRemaining(timeRemaining);
|
||||
keyboard.displayLocked().addListener(new AssertedSuccessListener<Boolean>() {
|
||||
@Override
|
||||
public void onSuccess(Boolean r) {
|
||||
|
@ -131,7 +134,7 @@ public final class EnterCodeFragment extends BaseRegistrationFragment {
|
|||
|
||||
@Override
|
||||
public void onKbsRegistrationLockPinRequired(long timeRemaining, @NonNull TokenResponse tokenResponse, @NonNull String kbsStorageCredentials) {
|
||||
model.setTimeRemaining(timeRemaining);
|
||||
model.setLockedTimeRemaining(timeRemaining);
|
||||
model.setStorageCredentials(kbsStorageCredentials);
|
||||
model.setKeyBackupCurrentToken(tokenResponse);
|
||||
keyboard.displayLocked().addListener(new AssertedSuccessListener<Boolean>() {
|
||||
|
@ -170,7 +173,7 @@ public final class EnterCodeFragment extends BaseRegistrationFragment {
|
|||
@Override
|
||||
public void onKbsAccountLocked(@Nullable Long timeRemaining) {
|
||||
if (timeRemaining != null) {
|
||||
model.setTimeRemaining(timeRemaining);
|
||||
model.setLockedTimeRemaining(timeRemaining);
|
||||
}
|
||||
Navigation.findNavController(requireView()).navigate(RegistrationLockFragmentDirections.actionAccountLocked());
|
||||
}
|
||||
|
@ -249,12 +252,12 @@ public final class EnterCodeFragment extends BaseRegistrationFragment {
|
|||
}
|
||||
|
||||
private void handlePhoneCallRequest() {
|
||||
callMeCountDown.startCountDown(RegistrationConstants.SUBSEQUENT_CALL_AVAILABLE_AFTER);
|
||||
|
||||
RegistrationViewModel model = getModel();
|
||||
String captcha = model.getCaptchaToken();
|
||||
model.clearCaptchaResponse();
|
||||
|
||||
model.onCallRequested();
|
||||
|
||||
NavController navController = Navigation.findNavController(callMeCountDown);
|
||||
|
||||
RegistrationService registrationService = RegistrationService.getInstance(model.getNumber().getE164Number(), model.getRegistrationSecret());
|
||||
|
@ -301,9 +304,10 @@ public final class EnterCodeFragment extends BaseRegistrationFragment {
|
|||
public void onResume() {
|
||||
super.onResume();
|
||||
|
||||
getModel().getLiveNumber().observe(this, (s) -> header.setText(requireContext().getString(R.string.RegistrationActivity_enter_the_code_we_sent_to_s, s.getFullFormattedNumber())));
|
||||
RegistrationViewModel model = getModel();
|
||||
model.getLiveNumber().observe(this, (s) -> header.setText(requireContext().getString(R.string.RegistrationActivity_enter_the_code_we_sent_to_s, s.getFullFormattedNumber())));
|
||||
|
||||
callMeCountDown.startCountDown(RegistrationConstants.FIRST_CALL_AVAILABLE_AFTER);
|
||||
model.getCanCallAtTime().observe(this, callAtTime -> callMeCountDown.startCountDownTo(callAtTime));
|
||||
}
|
||||
|
||||
private void sendEmailToSupport() {
|
||||
|
|
|
@ -5,11 +5,8 @@ final class RegistrationConstants {
|
|||
private RegistrationConstants() {
|
||||
}
|
||||
|
||||
static final int FIRST_CALL_AVAILABLE_AFTER = 64;
|
||||
static final int SUBSEQUENT_CALL_AVAILABLE_AFTER = 300;
|
||||
static final String TERMS_AND_CONDITIONS_URL = "https://signal.org/legal";
|
||||
|
||||
static final String SIGNAL_CAPTCHA_URL = "https://signalcaptchas.org/registration/generate.html";
|
||||
static final String SIGNAL_CAPTCHA_SCHEME = "signalcaptcha://";
|
||||
static final String TERMS_AND_CONDITIONS_URL = "https://signal.org/legal";
|
||||
static final String SIGNAL_CAPTCHA_URL = "https://signalcaptchas.org/registration/generate.html";
|
||||
static final String SIGNAL_CAPTCHA_SCHEME = "signalcaptcha://";
|
||||
|
||||
}
|
||||
|
|
|
@ -28,7 +28,6 @@ import org.thoughtcrime.securesms.logging.Log;
|
|||
import org.thoughtcrime.securesms.registration.service.CodeVerificationRequest;
|
||||
import org.thoughtcrime.securesms.registration.service.RegistrationService;
|
||||
import org.thoughtcrime.securesms.registration.viewmodel.RegistrationViewModel;
|
||||
import org.thoughtcrime.securesms.util.FeatureFlags;
|
||||
import org.thoughtcrime.securesms.util.ServiceUtil;
|
||||
import org.thoughtcrime.securesms.util.concurrent.SimpleTask;
|
||||
import org.whispersystems.signalservice.internal.contacts.entities.TokenResponse;
|
||||
|
@ -104,7 +103,7 @@ public final class RegistrationLockFragment extends BaseRegistrationFragment {
|
|||
PinKeyboardType keyboardType = getPinEntryKeyboardType().getOther();
|
||||
keyboardToggle.setText(resolveKeyboardToggleText(keyboardType));
|
||||
|
||||
getModel().getTimeRemaining()
|
||||
getModel().getLockedTimeRemaining()
|
||||
.observe(getViewLifecycleOwner(), t -> timeRemaining = t);
|
||||
|
||||
TokenResponse keyBackupCurrentToken = getModel().getKeyBackupCurrentToken();
|
||||
|
@ -180,7 +179,7 @@ public final class RegistrationLockFragment extends BaseRegistrationFragment {
|
|||
|
||||
@Override
|
||||
public void onV1RegistrationLockPinRequiredOrIncorrect(long timeRemaining) {
|
||||
getModel().setTimeRemaining(timeRemaining);
|
||||
getModel().setLockedTimeRemaining(timeRemaining);
|
||||
|
||||
cancelSpinning(pinButton);
|
||||
pinEntry.getText().clear();
|
||||
|
@ -243,7 +242,7 @@ public final class RegistrationLockFragment extends BaseRegistrationFragment {
|
|||
@Override
|
||||
public void onKbsAccountLocked(@Nullable Long timeRemaining) {
|
||||
if (timeRemaining != null) {
|
||||
model.setTimeRemaining(timeRemaining);
|
||||
model.setLockedTimeRemaining(timeRemaining);
|
||||
}
|
||||
|
||||
onAccountLocked();
|
||||
|
|
|
@ -14,11 +14,15 @@ import org.whispersystems.signalservice.internal.contacts.entities.TokenResponse
|
|||
import org.whispersystems.signalservice.internal.util.JsonUtil;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
public final class RegistrationViewModel extends ViewModel {
|
||||
|
||||
private static final String TAG = Log.tag(RegistrationViewModel.class);
|
||||
|
||||
private static final long FIRST_CALL_AVAILABLE_AFTER_MS = TimeUnit.SECONDS.toMillis(64);
|
||||
private static final long SUBSEQUENT_CALL_AVAILABLE_AFTER_MS = TimeUnit.SECONDS.toMillis(300);
|
||||
|
||||
private final String secret;
|
||||
private final MutableLiveData<NumberViewState> number;
|
||||
private final MutableLiveData<String> textCodeEntered;
|
||||
|
@ -28,8 +32,9 @@ public final class RegistrationViewModel extends ViewModel {
|
|||
private final MutableLiveData<Boolean> restoreFlowShown;
|
||||
private final MutableLiveData<Integer> successfulCodeRequestAttempts;
|
||||
private final MutableLiveData<LocalCodeRequestRateLimiter> requestLimiter;
|
||||
private final MutableLiveData<String> keyBackupcurrentTokenJson;
|
||||
private final MutableLiveData<Long> timeRemaining;
|
||||
private final MutableLiveData<String> keyBackupCurrentTokenJson;
|
||||
private final MutableLiveData<Long> lockedTimeRemaining;
|
||||
private final MutableLiveData<Long> canCallAtTime;
|
||||
|
||||
public RegistrationViewModel(@NonNull SavedStateHandle savedStateHandle) {
|
||||
secret = loadValue(savedStateHandle, "REGISTRATION_SECRET", Util.getSecret(18));
|
||||
|
@ -42,8 +47,9 @@ public final class RegistrationViewModel extends ViewModel {
|
|||
restoreFlowShown = savedStateHandle.getLiveData("RESTORE_FLOW_SHOWN", false);
|
||||
successfulCodeRequestAttempts = savedStateHandle.getLiveData("SUCCESSFUL_CODE_REQUEST_ATTEMPTS", 0);
|
||||
requestLimiter = savedStateHandle.getLiveData("REQUEST_RATE_LIMITER", new LocalCodeRequestRateLimiter(60_000));
|
||||
keyBackupcurrentTokenJson = savedStateHandle.getLiveData("KBS_TOKEN");
|
||||
timeRemaining = savedStateHandle.getLiveData("TIME_REMAINING", 0L);
|
||||
keyBackupCurrentTokenJson = savedStateHandle.getLiveData("KBS_TOKEN");
|
||||
lockedTimeRemaining = savedStateHandle.getLiveData("TIME_REMAINING", 0L);
|
||||
canCallAtTime = savedStateHandle.getLiveData("CAN_CALL_AT_TIME", 0L);
|
||||
}
|
||||
|
||||
private static <T> T loadValue(@NonNull SavedStateHandle savedStateHandle, @NonNull String key, @NonNull T initialValue) {
|
||||
|
@ -161,7 +167,7 @@ public final class RegistrationViewModel extends ViewModel {
|
|||
}
|
||||
|
||||
public @Nullable TokenResponse getKeyBackupCurrentToken() {
|
||||
String json = keyBackupcurrentTokenJson.getValue();
|
||||
String json = keyBackupCurrentTokenJson.getValue();
|
||||
if (json == null) return null;
|
||||
try {
|
||||
return JsonUtil.fromJson(json, TokenResponse.class);
|
||||
|
@ -173,14 +179,26 @@ public final class RegistrationViewModel extends ViewModel {
|
|||
|
||||
public void setKeyBackupCurrentToken(TokenResponse tokenResponse) {
|
||||
String json = tokenResponse == null ? null : JsonUtil.toJson(tokenResponse);
|
||||
keyBackupcurrentTokenJson.setValue(json);
|
||||
keyBackupCurrentTokenJson.setValue(json);
|
||||
}
|
||||
|
||||
public LiveData<Long> getTimeRemaining() {
|
||||
return timeRemaining;
|
||||
public LiveData<Long> getLockedTimeRemaining() {
|
||||
return lockedTimeRemaining;
|
||||
}
|
||||
|
||||
public void setTimeRemaining(long timeRemaining) {
|
||||
this.timeRemaining.setValue(timeRemaining);
|
||||
public LiveData<Long> getCanCallAtTime() {
|
||||
return canCallAtTime;
|
||||
}
|
||||
|
||||
public void setLockedTimeRemaining(long lockedTimeRemaining) {
|
||||
this.lockedTimeRemaining.setValue(lockedTimeRemaining);
|
||||
}
|
||||
|
||||
public void onStartEnterCode() {
|
||||
canCallAtTime.setValue(System.currentTimeMillis() + FIRST_CALL_AVAILABLE_AFTER_MS);
|
||||
}
|
||||
|
||||
public void onCallRequested() {
|
||||
canCallAtTime.setValue(System.currentTimeMillis() + SUBSEQUENT_CALL_AVAILABLE_AFTER_MS);
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue