Update registration UI.

This commit is contained in:
Greyson Parrelli
2019-02-13 11:52:55 -08:00
parent 6b476876d9
commit bf28e109d3
67 changed files with 1096 additions and 813 deletions

View File

@@ -51,6 +51,7 @@ import android.view.MenuInflater;
import android.view.MenuItem;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageView;
import android.widget.TextView;
import org.greenrobot.eventbus.EventBus;
@@ -101,10 +102,17 @@ public class ConversationListFragment extends Fragment
@SuppressWarnings("unused")
private static final String TAG = ConversationListFragment.class.getSimpleName();
private static final int[] EMPTY_IMAGES = new int[] { R.drawable.empty_inbox_1,
R.drawable.empty_inbox_2,
R.drawable.empty_inbox_3,
R.drawable.empty_inbox_4,
R.drawable.empty_inbox_5 };
private ActionMode actionMode;
private RecyclerView list;
private ReminderView reminderView;
private View emptyState;
private ImageView emptyImage;
private TextView emptySearch;
private PulsingFloatingActionButton fab;
private Locale locale;
@@ -126,6 +134,7 @@ public class ConversationListFragment extends Fragment
list = ViewUtil.findById(view, R.id.list);
fab = ViewUtil.findById(view, R.id.fab);
emptyState = ViewUtil.findById(view, R.id.empty_state);
emptyImage = ViewUtil.findById(view, R.id.empty);
emptySearch = ViewUtil.findById(view, R.id.empty_search);
if (archive) fab.setVisibility(View.GONE);
@@ -357,6 +366,7 @@ public class ConversationListFragment extends Fragment
list.setVisibility(View.INVISIBLE);
emptyState.setVisibility(View.VISIBLE);
emptySearch.setVisibility(View.INVISIBLE);
emptyImage.setImageResource(EMPTY_IMAGES[(int) (Math.random() * EMPTY_IMAGES.length)]);
fab.startPulse(3 * 1000);
} else if ((cursor == null || cursor.getCount() <= 0) && !TextUtils.isEmpty(queryFilter)) {
list.setVisibility(View.INVISIBLE);

View File

@@ -19,6 +19,8 @@ import android.support.annotation.RequiresApi;
import android.text.Editable;
import android.text.TextUtils;
import android.text.TextWatcher;
import org.thoughtcrime.securesms.components.LabeledEditText;
import org.thoughtcrime.securesms.logging.Log;
import android.view.KeyEvent;
import android.view.View;
@@ -49,6 +51,7 @@ import org.thoughtcrime.securesms.profiles.SystemProfileUtil;
import org.thoughtcrime.securesms.util.BitmapDecodingException;
import org.thoughtcrime.securesms.util.BitmapUtil;
import org.thoughtcrime.securesms.util.DynamicLanguage;
import org.thoughtcrime.securesms.util.DynamicRegistrationTheme;
import org.thoughtcrime.securesms.util.DynamicTheme;
import org.thoughtcrime.securesms.util.FileProviderUtil;
import org.thoughtcrime.securesms.util.IntentUtils;
@@ -82,7 +85,7 @@ public class CreateProfileActivity extends BaseActionBarActivity implements Inje
private static final int REQUEST_CODE_AVATAR = 1;
private final DynamicTheme dynamicTheme = new DynamicTheme();
private final DynamicTheme dynamicTheme = new DynamicRegistrationTheme();
private final DynamicLanguage dynamicLanguage = new DynamicLanguage();
@Inject SignalServiceAccountManager accountManager;
@@ -90,7 +93,7 @@ public class CreateProfileActivity extends BaseActionBarActivity implements Inje
private InputAwareLayout container;
private ImageView avatar;
private CircularProgressButton finishButton;
private EditText name;
private LabeledEditText name;
private EmojiToggle emojiToggle;
private EmojiDrawer emojiDrawer;
private View reveal;
@@ -109,7 +112,6 @@ public class CreateProfileActivity extends BaseActionBarActivity implements Inje
setContentView(R.layout.profile_create_activity);
getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE);
getSupportActionBar().setTitle(R.string.CreateProfileActivity_your_profile_info);
initializeResources();
initializeEmojiInput();
@@ -128,7 +130,7 @@ public class CreateProfileActivity extends BaseActionBarActivity implements Inje
@Override
public void onBackPressed() {
if (container.isInputOpen()) container.hideCurrentInput(name);
if (container.isInputOpen()) container.hideCurrentInput(name.getInput());
else super.onBackPressed();
}
@@ -205,7 +207,6 @@ public class CreateProfileActivity extends BaseActionBarActivity implements Inje
private void initializeResources() {
TextView skipButton = ViewUtil.findById(this, R.id.skip_button);
TextView informationLabel = ViewUtil.findById(this, R.id.information_label);
this.avatar = ViewUtil.findById(this, R.id.avatar);
this.name = ViewUtil.findById(this, R.id.name);
@@ -216,15 +217,13 @@ public class CreateProfileActivity extends BaseActionBarActivity implements Inje
this.reveal = ViewUtil.findById(this, R.id.reveal);
this.nextIntent = getIntent().getParcelableExtra(NEXT_INTENT);
this.avatar.setImageDrawable(new ResourceContactPhoto(R.drawable.ic_camera_alt_white_24dp).asDrawable(this, getResources().getColor(R.color.grey_400)));
this.avatar.setOnClickListener(view -> Permissions.with(this)
.request(Manifest.permission.CAMERA, Manifest.permission.WRITE_EXTERNAL_STORAGE)
.ifNecessary()
.onAnyResult(this::handleAvatarSelectionWithPermissions)
.execute());
this.name.addTextChangedListener(new TextWatcher() {
this.name.getInput().addTextChangedListener(new TextWatcher() {
@Override
public void beforeTextChanged(CharSequence s, int start, int count, int after) {}
@Override
@@ -232,10 +231,10 @@ public class CreateProfileActivity extends BaseActionBarActivity implements Inje
@Override
public void afterTextChanged(Editable s) {
if (s.toString().getBytes().length > ProfileCipher.NAME_PADDED_LENGTH) {
name.setError(getString(R.string.CreateProfileActivity_too_long));
name.getInput().setError(getString(R.string.CreateProfileActivity_too_long));
finishButton.setEnabled(false);
} else if (name.getError() != null || !finishButton.isEnabled()) {
name.setError(null);
} else if (name.getInput().getError() != null || !finishButton.isEnabled()) {
name.getInput().setError(null);
finishButton.setEnabled(true);
}
}
@@ -251,15 +250,6 @@ public class CreateProfileActivity extends BaseActionBarActivity implements Inje
if (nextIntent != null) startActivity(nextIntent);
finish();
});
informationLabel.setOnClickListener(view -> {
Intent intent = new Intent(Intent.ACTION_VIEW);
intent.setData(Uri.parse("https://support.signal.org/hc/en-us/articles/115001434171"));
if (getPackageManager().queryIntentActivities(intent, 0).size() > 0) {
startActivity(intent);
}
});
}
private void initializeProfileName(boolean excludeSystem) {
@@ -267,14 +257,14 @@ public class CreateProfileActivity extends BaseActionBarActivity implements Inje
String profileName = TextSecurePreferences.getProfileName(this);
name.setText(profileName);
name.setSelection(profileName.length(), profileName.length());
name.getInput().setSelection(profileName.length(), profileName.length());
} else if (!excludeSystem) {
SystemProfileUtil.getSystemProfileName(this).addListener(new ListenableFuture.Listener<String>() {
@Override
public void onSuccess(String result) {
if (!TextUtils.isEmpty(result)) {
name.setText(result);
name.setSelection(result.length(), result.length());
name.getInput().setSelection(result.length(), result.length());
}
}
@@ -338,9 +328,9 @@ public class CreateProfileActivity extends BaseActionBarActivity implements Inje
this.emojiToggle.setOnClickListener(v -> {
if (container.getCurrentInput() == emojiDrawer) {
container.showSoftkey(name);
container.showSoftkey(name.getInput());
} else {
container.show(name, emojiDrawer);
container.show(name.getInput(), emojiDrawer);
}
});
@@ -352,16 +342,16 @@ public class CreateProfileActivity extends BaseActionBarActivity implements Inje
@Override
public void onEmojiSelected(String emoji) {
final int start = name.getSelectionStart();
final int end = name.getSelectionEnd();
final int start = name.getInput().getSelectionStart();
final int end = name.getInput().getSelectionEnd();
name.getText().replace(Math.min(start, end), Math.max(start, end), emoji);
name.setSelection(start + emoji.length());
name.getInput().setSelection(start + emoji.length());
}
});
this.container.addOnKeyboardShownListener(() -> emojiToggle.setToEmoji());
this.name.setOnClickListener(v -> container.showSoftkey(name));
this.name.setOnClickListener(v -> container.showSoftkey(name.getInput()));
}
private Intent createAvatarSelectionIntent(@Nullable File captureFile, boolean includeClear, boolean includeCamera) {

View File

@@ -70,6 +70,7 @@ public class PassphraseCreateActivity extends PassphraseActivity {
TextSecurePreferences.setPasswordDisabled(PassphraseCreateActivity.this, true);
TextSecurePreferences.setReadReceiptsEnabled(PassphraseCreateActivity.this, true);
TextSecurePreferences.setTypingIndicatorsEnabled(PassphraseCreateActivity.this, true);
TextSecurePreferences.setHasSeenWelcomeScreen(PassphraseCreateActivity.this, false);
return null;
}

View File

@@ -14,6 +14,7 @@ import org.thoughtcrime.securesms.logging.Log;
import org.thoughtcrime.securesms.crypto.MasterSecretUtil;
import org.thoughtcrime.securesms.jobs.PushNotificationReceiveJob;
import org.thoughtcrime.securesms.push.SignalServiceNetworkAccess;
import org.thoughtcrime.securesms.registration.WelcomeActivity;
import org.thoughtcrime.securesms.service.KeyCachingService;
import org.thoughtcrime.securesms.util.TextSecurePreferences;
import org.thoughtcrime.securesms.util.Util;
@@ -31,6 +32,7 @@ public abstract class PassphraseRequiredActionBarActivity extends BaseActionBarA
private static final int STATE_UPGRADE_DATABASE = 3;
private static final int STATE_PROMPT_PUSH_REGISTRATION = 4;
private static final int STATE_EXPERIENCE_UPGRADE = 5;
private static final int STATE_WELCOME_SCREEN = 6;
private SignalServiceNetworkAccess networkAccess;
private BroadcastReceiver clearKeyReceiver;
@@ -132,6 +134,7 @@ public abstract class PassphraseRequiredActionBarActivity extends BaseActionBarA
case STATE_CREATE_PASSPHRASE: return getCreatePassphraseIntent();
case STATE_PROMPT_PASSPHRASE: return getPromptPassphraseIntent();
case STATE_UPGRADE_DATABASE: return getUpgradeDatabaseIntent();
case STATE_WELCOME_SCREEN: return getWelcomeIntent();
case STATE_PROMPT_PUSH_REGISTRATION: return getPushRegistrationIntent();
case STATE_EXPERIENCE_UPGRADE: return getExperienceUpgradeIntent();
default: return null;
@@ -145,6 +148,8 @@ public abstract class PassphraseRequiredActionBarActivity extends BaseActionBarA
return STATE_PROMPT_PASSPHRASE;
} else if (DatabaseUpgradeActivity.isUpdate(this)) {
return STATE_UPGRADE_DATABASE;
} else if (!TextSecurePreferences.hasSeenWelcomeScreen(this)) {
return STATE_WELCOME_SCREEN;
} else if (!TextSecurePreferences.hasPromptedPushRegistration(this)) {
return STATE_PROMPT_PUSH_REGISTRATION;
} else if (ExperienceUpgradeActivity.isUpdate(this)) {
@@ -173,6 +178,10 @@ public abstract class PassphraseRequiredActionBarActivity extends BaseActionBarA
return getRoutedIntent(ExperienceUpgradeActivity.class, getIntent());
}
private Intent getWelcomeIntent() {
return getRoutedIntent(WelcomeActivity.class, getPushRegistrationIntent());
}
private Intent getPushRegistrationIntent() {
return getRoutedIntent(RegistrationActivity.class, getCreateProfileIntent());
}

View File

@@ -3,28 +3,18 @@ package org.thoughtcrime.securesms;
import android.Manifest;
import android.animation.Animator;
import android.annotation.SuppressLint;
import android.content.ActivityNotFoundException;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.graphics.Color;
import android.net.Uri;
import android.os.AsyncTask;
import android.os.Bundle;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.support.design.widget.FloatingActionButton;
import android.support.v7.app.AlertDialog;
import android.text.Editable;
import android.text.SpannableString;
import android.text.SpannableStringBuilder;
import android.text.Spanned;
import android.text.TextPaint;
import android.text.TextUtils;
import android.text.TextWatcher;
import android.text.method.LinkMovementMethod;
import android.text.style.ClickableSpan;
import android.util.Pair;
import android.view.KeyEvent;
import android.view.LayoutInflater;
@@ -47,6 +37,7 @@ import com.google.android.gms.common.api.CommonStatusCodes;
import com.google.android.gms.common.api.Status;
import com.google.android.gms.tasks.Task;
import com.google.i18n.phonenumbers.AsYouTypeFormatter;
import com.google.i18n.phonenumbers.NumberParseException;
import com.google.i18n.phonenumbers.PhoneNumberUtil;
import com.google.i18n.phonenumbers.Phonenumber;
@@ -58,6 +49,7 @@ import org.greenrobot.eventbus.ThreadMode;
import org.thoughtcrime.securesms.animation.AnimationCompleteListener;
import org.thoughtcrime.securesms.backup.FullBackupBase;
import org.thoughtcrime.securesms.backup.FullBackupImporter;
import org.thoughtcrime.securesms.components.LabeledEditText;
import org.thoughtcrime.securesms.components.registration.CallMeCountDownView;
import org.thoughtcrime.securesms.components.registration.VerificationCodeView;
import org.thoughtcrime.securesms.components.registration.VerificationPinKeyboard;
@@ -99,6 +91,7 @@ import org.whispersystems.libsignal.util.guava.Optional;
import org.whispersystems.signalservice.api.SignalServiceAccountManager;
import org.whispersystems.signalservice.api.push.exceptions.CaptchaRequiredException;
import org.whispersystems.signalservice.api.push.exceptions.RateLimitException;
import org.whispersystems.signalservice.api.util.InvalidNumberException;
import org.whispersystems.signalservice.api.util.PhoneNumberFormatter;
import org.whispersystems.signalservice.internal.push.LockedException;
@@ -130,16 +123,13 @@ public class RegistrationActivity extends BaseActionBarActivity implements Verif
private AsYouTypeFormatter countryFormatter;
private ArrayAdapter<String> countrySpinnerAdapter;
private Spinner countrySpinner;
private TextView countryCode;
private TextView number;
private LabeledEditText countryCode;
private LabeledEditText number;
private CircularProgressButton createButton;
private TextView informationView;
private TextView informationToggleText;
private TextView title;
private TextView subtitle;
private View registrationContainer;
private View verificationContainer;
private FloatingActionButton fab;
private View restoreContainer;
private TextView restoreBackupTime;
@@ -154,6 +144,7 @@ public class RegistrationActivity extends BaseActionBarActivity implements Verif
private View pinClarificationContainer;
private CallMeCountDownView callMeCountDownView;
private View wrongNumberButton;
private VerificationPinKeyboard keyboard;
private VerificationCodeView verificationCodeView;
private RegistrationState registrationState;
@@ -169,8 +160,8 @@ public class RegistrationActivity extends BaseActionBarActivity implements Verif
initializeResources();
initializeSpinner();
initializePermissions();
initializeNumber();
initializeBackupDetection();
initializeChallengeListener();
}
@@ -203,31 +194,23 @@ public class RegistrationActivity extends BaseActionBarActivity implements Verif
}
}
@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String permissions[], @NonNull int[] grantResults) {
Permissions.onRequestPermissionsResult(this, requestCode, permissions, grantResults);
}
private void initializeResources() {
TextView skipButton = findViewById(R.id.skip_button);
TextView restoreSkipButton = findViewById(R.id.skip_restore_button);
View termsLinkView = findViewById(R.id.terms_label);
this.countrySpinner = findViewById(R.id.country_spinner);
this.countryCode = findViewById(R.id.country_code);
this.number = findViewById(R.id.number);
this.createButton = findViewById(R.id.registerButton);
this.informationView = findViewById(R.id.registration_information);
this.informationToggleText = findViewById(R.id.information_label);
this.title = findViewById(R.id.verify_header);
this.subtitle = findViewById(R.id.verify_subheader);
this.registrationContainer = findViewById(R.id.registration_container);
this.verificationContainer = findViewById(R.id.verification_container);
this.fab = findViewById(R.id.fab);
this.verificationCodeView = findViewById(R.id.code);
this.keyboard = findViewById(R.id.keyboard);
this.callMeCountDownView = findViewById(R.id.call_me_count_down);
this.wrongNumberButton = findViewById(R.id.wrong_number);
this.restoreContainer = findViewById(R.id.restore_container);
this.restoreBackupSize = findViewById(R.id.backup_size_text);
@@ -243,14 +226,12 @@ public class RegistrationActivity extends BaseActionBarActivity implements Verif
this.registrationState = new RegistrationState(RegistrationState.State.INITIAL, null, null, Optional.absent(), Optional.absent());
this.countryCode.addTextChangedListener(new CountryCodeChangedListener());
this.number.addTextChangedListener(new NumberChangedListener());
this.countryCode.getInput().addTextChangedListener(new CountryCodeChangedListener());
this.number.getInput().addTextChangedListener(new NumberChangedListener());
this.createButton.setOnClickListener(v -> handleRegister());
this.callMeCountDownView.setOnClickListener(v -> handlePhoneCallRequest());
skipButton.setOnClickListener(v -> handleCancel());
informationToggleText.setOnClickListener(new InformationToggleListener());
termsLinkView.setOnClickListener(this::onTermsLinkClicked);
restoreSkipButton.setOnClickListener(v -> displayInitialView(true));
if (getIntent().getBooleanExtra(RE_REGISTRATION_EXTRA, false)) {
@@ -264,9 +245,6 @@ public class RegistrationActivity extends BaseActionBarActivity implements Verif
else verificationCodeView.delete();
});
fab.setOnClickListener(this::onDebugClick);
fab.setRippleColor(Color.TRANSPARENT);
this.verificationCodeView.setOnCompleteListener(this);
EventBus.getDefault().register(this);
}
@@ -327,29 +305,13 @@ public class RegistrationActivity extends BaseActionBarActivity implements Verif
}
}
@SuppressLint("InlinedApi")
private void initializePermissions() {
Permissions.with(RegistrationActivity.this)
.request(Manifest.permission.WRITE_CONTACTS, Manifest.permission.READ_CONTACTS,
Manifest.permission.WRITE_EXTERNAL_STORAGE, Manifest.permission.READ_EXTERNAL_STORAGE,
Manifest.permission.READ_PHONE_STATE)
.ifNecessary()
.withRationaleDialog(getString(R.string.RegistrationActivity_signal_needs_access_to_your_contacts_and_media_in_order_to_connect_with_friends),
R.drawable.ic_contacts_white_48dp, R.drawable.ic_folder_white_48dp)
.onSomeGranted(permissions -> {
if (permissions.contains(Manifest.permission.READ_PHONE_STATE)) {
initializeNumber();
}
if (permissions.contains(Manifest.permission.WRITE_EXTERNAL_STORAGE)) {
initializeBackupDetection();
}
})
.execute();
}
@SuppressLint("StaticFieldLeak")
private void initializeBackupDetection() {
if (!Permissions.hasAll(this, Manifest.permission.WRITE_EXTERNAL_STORAGE)) {
Log.i(TAG, "Skipping backup detection. We don't have the permission.");
return;
}
if (getIntent().getBooleanExtra(RE_REGISTRATION_EXTRA, false)) return;
new AsyncTask<Void, Void, BackupUtil.BackupInfo>() {
@@ -822,16 +784,6 @@ public class RegistrationActivity extends BaseActionBarActivity implements Verif
restoreContainer.animate().translationX(0).setDuration(SCENE_TRANSITION_DURATION).setListener(null).setInterpolator(new OvershootInterpolator()).start();
}
}).start();
fab.animate().rotationBy(375f).setDuration(SCENE_TRANSITION_DURATION).setListener(new AnimationCompleteListener() {
@Override
public void onAnimationEnd(Animator animation) {
fab.clearAnimation();
fab.setImageResource(R.drawable.ic_restore_white_24dp);
fab.animate().rotationBy(360f).setDuration(SCENE_TRANSITION_DURATION).setListener(null).start();
}
}).start();
}
private void displayInitialView(boolean forwards) {
@@ -877,15 +829,6 @@ public class RegistrationActivity extends BaseActionBarActivity implements Verif
registrationContainer.animate().translationX(0).setDuration(SCENE_TRANSITION_DURATION).setListener(null).setInterpolator(new OvershootInterpolator()).start();
}
}).start();
fab.animate().rotationBy(startDirectionMultiplier * 360f).setDuration(SCENE_TRANSITION_DURATION).setListener(new AnimationCompleteListener() {
@Override
public void onAnimationEnd(Animator animation) {
fab.clearAnimation();
fab.setImageResource(R.drawable.ic_action_name);
fab.animate().rotationBy(startDirectionMultiplier * 375f).setDuration(SCENE_TRANSITION_DURATION).setListener(null).start();
}
}).start();
}
private void displayVerificationView(@NonNull String e164number, int callCountdown) {
@@ -898,42 +841,14 @@ public class RegistrationActivity extends BaseActionBarActivity implements Verif
title.animate().translationX(-1 * title.getWidth()).setDuration(SCENE_TRANSITION_DURATION).setListener(new AnimationCompleteListener() {
@Override
public void onAnimationEnd(Animator animation) {
title.setText(getString(R.string.RegistrationActivity_verify_s, e164number));
title.setText(getString(R.string.RegistrationActivity_enter_the_code_we_sent_to_s, formatNumber(e164number)));
title.clearAnimation();
title.setTranslationX(title.getWidth());
title.animate().translationX(0).setListener(null).setInterpolator(new OvershootInterpolator()).setDuration(SCENE_TRANSITION_DURATION).start();
}
}).start();
subtitle.animate().translationX(-1 * subtitle.getWidth()).setDuration(SCENE_TRANSITION_DURATION).setListener(new AnimationCompleteListener() {
@Override
public void onAnimationEnd(Animator animation) {
SpannableString subtitleDescription = new SpannableString(getString(R.string.RegistrationActivity_please_enter_the_verification_code_sent_to_s, e164number));
SpannableString wrongNumber = new SpannableString(getString(R.string.RegistrationActivity_wrong_number));
ClickableSpan clickableSpan = new ClickableSpan() {
@Override
public void onClick(View widget) {
displayInitialView(false);
registrationState = new RegistrationState(RegistrationState.State.INITIAL, null, null, Optional.absent(), Optional.absent());
}
@Override
public void updateDrawState(TextPaint paint) {
paint.setColor(Color.WHITE);
paint.setUnderlineText(true);
}
};
wrongNumber.setSpan(clickableSpan, 0, wrongNumber.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
subtitle.setText(new SpannableStringBuilder(subtitleDescription).append(" ").append(wrongNumber));
subtitle.setMovementMethod(LinkMovementMethod.getInstance());
subtitle.clearAnimation();
subtitle.setTranslationX(subtitle.getWidth());
subtitle.animate().translationX(0).setListener(null).setInterpolator(new OvershootInterpolator()).setDuration(SCENE_TRANSITION_DURATION).start();
}
}).start();
subtitle.setText("");
registrationContainer.animate().translationX(-1 * registrationContainer.getWidth()).setDuration(SCENE_TRANSITION_DURATION).setListener(new AnimationCompleteListener() {
@Override
@@ -948,16 +863,9 @@ public class RegistrationActivity extends BaseActionBarActivity implements Verif
}
}).start();
fab.animate().rotationBy(-360f).setDuration(SCENE_TRANSITION_DURATION).setListener(new AnimationCompleteListener() {
@Override
public void onAnimationEnd(Animator animation) {
fab.clearAnimation();
fab.setImageResource(R.drawable.ic_textsms_24dp);
fab.animate().rotationBy(-375f).setDuration(SCENE_TRANSITION_DURATION).setListener(null).start();
}
}).start();
this.callMeCountDownView.startCountDown(callCountdown);
this.wrongNumberButton.setOnClickListener(v -> onWrongNumberClicked());
}
private void displayPinView(String code, long lockedUntil) {
@@ -994,15 +902,6 @@ public class RegistrationActivity extends BaseActionBarActivity implements Verif
}
}).start();
fab.animate().rotationBy(-360f).setDuration(SCENE_TRANSITION_DURATION).setListener(new AnimationCompleteListener() {
@Override
public void onAnimationEnd(Animator animation) {
fab.clearAnimation();
fab.setImageResource(R.drawable.ic_lock_white_24dp);
fab.animate().rotationBy(-360f).setDuration(SCENE_TRANSITION_DURATION).setListener(null).start();
}
}).start();
pinButton.setOnClickListener(v -> handleVerifyWithPinClicked(code, pin.getText().toString()));
pinForgotButton.setOnClickListener(v -> handleForgottenPin(lockedUntil));
pin.addTextChangedListener(new TextWatcher() {
@@ -1060,15 +959,20 @@ public class RegistrationActivity extends BaseActionBarActivity implements Verif
}
}
private void onTermsLinkClicked(View v) {
private String formatNumber(@NonNull String e164Number) {
try {
Intent intent = new Intent(Intent.ACTION_VIEW, Uri.parse("https://signal.org/legal"));
startActivity(intent);
} catch (ActivityNotFoundException e) {
Toast.makeText(this, R.string.RegistrationActivity_no_browser, Toast.LENGTH_SHORT).show();
Phonenumber.PhoneNumber number = PhoneNumberUtil.getInstance().parse(e164Number, null);
return PhoneNumberUtil.getInstance().format(number, PhoneNumberUtil.PhoneNumberFormat.INTERNATIONAL);
} catch (NumberParseException e) {
return e164Number;
}
}
private void onWrongNumberClicked() {
displayInitialView(false);
registrationState = new RegistrationState(RegistrationState.State.INITIAL, null, null, Optional.absent(), Optional.absent());
}
@Subscribe(threadMode = ThreadMode.MAIN)
public void onEvent(FullBackupBase.BackupEvent event) {
if (event.getCount() == 0) restoreBackupProgress.setText(R.string.RegistrationActivity_checking);
@@ -1167,19 +1071,6 @@ public class RegistrationActivity extends BaseActionBarActivity implements Verif
}
}
private class InformationToggleListener implements View.OnClickListener {
@Override
public void onClick(View v) {
if (informationView.getVisibility() == View.VISIBLE) {
informationView.setVisibility(View.GONE);
informationToggleText.setText(R.string.RegistrationActivity_more_information);
} else {
informationView.setVisibility(View.VISIBLE);
informationToggleText.setText(R.string.RegistrationActivity_less_information);
}
}
}
private static class VerificationRequestResult {
private final String password;
private final Optional<String> fcmToken;

View File

@@ -0,0 +1,89 @@
package org.thoughtcrime.securesms.components;
import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Color;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.text.Editable;
import android.text.InputFilter;
import android.text.TextUtils;
import android.util.AttributeSet;
import android.view.View;
import android.view.ViewGroup;
import android.view.inputmethod.EditorInfo;
import android.widget.EditText;
import android.widget.FrameLayout;
import android.widget.TextView;
import org.thoughtcrime.securesms.R;
public class LabeledEditText extends FrameLayout implements View.OnFocusChangeListener {
private TextView label;
private EditText input;
private View border;
private ViewGroup textContainer;
public LabeledEditText(@NonNull Context context) {
super(context);
init(null);
}
public LabeledEditText(@NonNull Context context, @Nullable AttributeSet attrs) {
super(context, attrs);
init(attrs);
}
private void init(@Nullable AttributeSet attrs) {
inflate(getContext(), R.layout.labeled_edit_text, this);
String labelText = "";
int backgroundColor = Color.BLACK;
int textLayout = R.layout.labeled_edit_text_default;
if (attrs != null) {
TypedArray typedArray = getContext().getTheme().obtainStyledAttributes(attrs, R.styleable.LabeledEditText, 0, 0);
labelText = typedArray.getString(R.styleable.LabeledEditText_labeledEditText_label);
backgroundColor = typedArray.getColor(R.styleable.LabeledEditText_labeledEditText_background, Color.BLACK);
textLayout = typedArray.getResourceId(R.styleable.LabeledEditText_labeledEditText_textLayout, R.layout.labeled_edit_text_default);
typedArray.recycle();
}
label = findViewById(R.id.label);
border = findViewById(R.id.border);
textContainer = findViewById(R.id.text_container);
inflate(getContext(), textLayout, textContainer);
input = findViewById(R.id.input);
label.setText(labelText);
label.setBackgroundColor(backgroundColor);
if (TextUtils.isEmpty(labelText)) {
label.setVisibility(INVISIBLE);
}
input.setOnFocusChangeListener(this);
}
public EditText getInput() {
return input;
}
public void setText(String text) {
input.setText(text);
}
public Editable getText() {
return input.getText();
}
@Override
public void onFocusChange(View v, boolean hasFocus) {
border.setBackgroundResource(hasFocus ? R.drawable.labeled_edit_text_background_active
: R.drawable.labeled_edit_text_background_inactive);
}
}

View File

@@ -9,99 +9,54 @@ import android.support.annotation.Nullable;
import android.support.annotation.RequiresApi;
import android.util.AttributeSet;
import android.view.View;
import android.widget.Button;
import android.widget.ImageView;
import android.widget.RelativeLayout;
import android.widget.TextView;
import org.thoughtcrime.securesms.R;
public class CallMeCountDownView extends RelativeLayout {
public class CallMeCountDownView extends android.support.v7.widget.AppCompatButton {
private ImageView phone;
private TextView callMeText;
private TextView availableInText;
private TextView countDownText;
private int countDown;
private OnClickListener listener;
private int countDown;
public CallMeCountDownView(Context context) {
super(context);
initialize();
}
public CallMeCountDownView(Context context, AttributeSet attrs) {
super(context, attrs);
initialize();
}
public CallMeCountDownView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
initialize();
}
@RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
public CallMeCountDownView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
super(context, attrs, defStyleAttr, defStyleRes);
initialize();
}
private void initialize() {
inflate(getContext(), R.layout.registration_call_me_view, this);
this.phone = findViewById(R.id.phone_icon);
this.callMeText = findViewById(R.id.call_me_text);
this.availableInText = findViewById(R.id.available_in_text);
this.countDownText = findViewById(R.id.countdown);
}
public void setOnClickListener(@Nullable OnClickListener listener) {
this.listener = listener;
}
public void startCountDown(int countDown) {
setVisibility(View.VISIBLE);
this.phone.setColorFilter(null);
this.phone.setOnClickListener(null);
this.callMeText.setTextColor(getResources().getColor(R.color.grey_700));
this.callMeText.setOnClickListener(null);
this.availableInText.setVisibility(View.VISIBLE);
this.countDownText.setVisibility(View.VISIBLE);
this.countDown = countDown;
updateCountDown();
}
public void setCallEnabled() {
setVisibility(View.VISIBLE);
this.phone.setColorFilter(new PorterDuffColorFilter(getResources().getColor(R.color.signal_primary), PorterDuff.Mode.SRC_IN));
this.callMeText.setTextColor(getResources().getColor(R.color.signal_primary));
this.availableInText.setVisibility(View.GONE);
this.countDownText.setVisibility(View.GONE);
this.phone.setOnClickListener(v -> handlePhoneCallRequest());
this.callMeText.setOnClickListener(v -> handlePhoneCallRequest());
setText(R.string.RegistrationActivity_call);
setEnabled(true);
setAlpha(1.0f);
}
private void updateCountDown() {
if (countDown > 0) {
setEnabled(false);
setAlpha(0.5f);
countDown--;
int minutesRemaining = countDown / 60;
int secondsRemaining = countDown - (minutesRemaining * 60);
countDownText.setText(String.format("%02d:%02d", minutesRemaining, secondsRemaining));
countDownText.postDelayed(this::updateCountDown, 1000);
setText(getResources().getString(R.string.RegistrationActivity_call_me_instead_available_in, minutesRemaining, secondsRemaining));
postDelayed(this::updateCountDown, 1000);
} else if (countDown == 0) {
setCallEnabled();
}
}
private void handlePhoneCallRequest() {
if (listener != null) listener.onClick(this);
}
}

View File

@@ -18,23 +18,20 @@ import android.view.animation.AnimationSet;
import android.view.animation.OvershootInterpolator;
import android.view.animation.TranslateAnimation;
import android.widget.FrameLayout;
import android.widget.LinearLayout;
import android.widget.TextView;
import com.annimon.stream.Collectors;
import com.annimon.stream.Stream;
import org.thoughtcrime.securesms.R;
import org.thoughtcrime.securesms.util.ViewUtil;
import java.util.ArrayList;
import java.util.List;
public class VerificationCodeView extends FrameLayout {
private final List<View> spaces = new ArrayList<>(6);
private final List<TextView> codes = new ArrayList<>(6);
private final List<View> containers = new ArrayList<>(7);
private final List<View> containers = new ArrayList<>(6);
private OnCodeEnteredListener listener;
private int index = 0;
@@ -68,13 +65,6 @@ public class VerificationCodeView extends FrameLayout {
try {
TextView separator = findViewById(R.id.separator);
this.spaces.add(findViewById(R.id.space_zero));
this.spaces.add(findViewById(R.id.space_one));
this.spaces.add(findViewById(R.id.space_two));
this.spaces.add(findViewById(R.id.space_three));
this.spaces.add(findViewById(R.id.space_four));
this.spaces.add(findViewById(R.id.space_five));
this.codes.add(findViewById(R.id.code_zero));
this.codes.add(findViewById(R.id.code_one));
this.codes.add(findViewById(R.id.code_two));
@@ -85,25 +75,16 @@ public class VerificationCodeView extends FrameLayout {
this.containers.add(findViewById(R.id.container_zero));
this.containers.add(findViewById(R.id.container_one));
this.containers.add(findViewById(R.id.container_two));
this.containers.add(findViewById(R.id.separator_container));
this.containers.add(findViewById(R.id.container_three));
this.containers.add(findViewById(R.id.container_four));
this.containers.add(findViewById(R.id.container_five));
Stream.of(spaces).forEach(view -> view.setBackgroundColor(typedArray.getColor(R.styleable.VerificationCodeView_vcv_inputColor, Color.BLACK)));
Stream.of(spaces).forEach(view -> view.setLayoutParams(new LinearLayout.LayoutParams(typedArray.getDimensionPixelSize(R.styleable.VerificationCodeView_vcv_inputWidth, ViewUtil.dpToPx(context, 20)),
typedArray.getDimensionPixelSize(R.styleable.VerificationCodeView_vcv_inputHeight, ViewUtil.dpToPx(context, 1)))));
Stream.of(codes).forEach(textView -> textView.setTextSize(TypedValue.COMPLEX_UNIT_SP, typedArray.getDimension(R.styleable.VerificationCodeView_vcv_textSize, 30)));
Stream.of(codes).forEach(textView -> textView.setTextColor(typedArray.getColor(R.styleable.VerificationCodeView_vcv_textColor, Color.GRAY)));
Stream.of(containers).forEach(view -> {
LinearLayout.LayoutParams params = (LinearLayout.LayoutParams)view.getLayoutParams();
params.setMargins(typedArray.getDimensionPixelSize(R.styleable.VerificationCodeView_vcv_spacing, ViewUtil.dpToPx(context, 5)),
params.topMargin, params.rightMargin, params.bottomMargin);
view.setLayoutParams(params);
});
separator.setTextSize(TypedValue.COMPLEX_UNIT_SP, typedArray.getDimension(R.styleable.VerificationCodeView_vcv_textSize, 30));
separator.setTextColor(typedArray.getColor(R.styleable.VerificationCodeView_vcv_textColor, Color.GRAY));
} finally {
if (typedArray != null) typedArray.recycle();
}
@@ -118,6 +99,9 @@ public class VerificationCodeView extends FrameLayout {
public void append(int value) {
if (index >= codes.size()) return;
setInactive(containers);
setActive(containers.get(index));
TextView codeView = codes.get(index++);
Animation translateIn = new TranslateAnimation(0, 0, codeView.getHeight(), 0);
@@ -146,6 +130,8 @@ public class VerificationCodeView extends FrameLayout {
public void delete() {
if (index <= 0) return;
codes.get(--index).setText("");
setInactive(containers);
setActive(containers.get(index));
}
@MainThread
@@ -154,6 +140,15 @@ public class VerificationCodeView extends FrameLayout {
Stream.of(codes).forEach(code -> code.setText(""));
index = 0;
}
setInactive(containers);
}
private void setInactive(List<View> views) {
Stream.of(views).forEach(c -> c.setBackgroundResource(R.drawable.labeled_edit_text_background_inactive));
}
private void setActive(@NonNull View container) {
container.setBackgroundResource(R.drawable.labeled_edit_text_background_active);
}
public interface OnCodeEnteredListener {

View File

@@ -6,6 +6,18 @@ import android.content.Intent;
import android.os.Bundle;
import android.support.annotation.NonNull;
import android.text.TextUtils;
import android.content.Context;
import android.content.Intent;
import android.graphics.Bitmap;
import android.os.Bundle;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.text.TextUtils;
import android.webkit.ValueCallback;
import android.webkit.WebChromeClient;
import android.webkit.WebResourceRequest;
import android.webkit.WebResourceResponse;
import android.webkit.WebSettings;
import android.webkit.WebView;
import android.webkit.WebViewClient;

View File

@@ -0,0 +1,57 @@
package org.thoughtcrime.securesms.registration;
import android.Manifest;
import android.content.Intent;
import android.os.Build;
import android.os.Bundle;
import android.support.annotation.NonNull;
import org.thoughtcrime.securesms.BaseActionBarActivity;
import org.thoughtcrime.securesms.R;
import org.thoughtcrime.securesms.permissions.Permissions;
import org.thoughtcrime.securesms.util.CommunicationActions;
import org.thoughtcrime.securesms.util.TextSecurePreferences;
public class WelcomeActivity extends BaseActionBarActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.registration_welcome_activity);
findViewById(R.id.welcome_terms_button).setOnClickListener(v -> onTermsClicked());
findViewById(R.id.welcome_continue_button).setOnClickListener(v -> onContinueClicked());
}
@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
Permissions.onRequestPermissionsResult(this, requestCode, permissions, grantResults);
}
private void onTermsClicked() {
CommunicationActions.openBrowserLink(this, "https://signal.org/legal");
}
private void onContinueClicked() {
Permissions.with(this)
.request(Manifest.permission.WRITE_CONTACTS, Manifest.permission.READ_CONTACTS,
Manifest.permission.WRITE_EXTERNAL_STORAGE, Manifest.permission.READ_EXTERNAL_STORAGE,
Manifest.permission.READ_PHONE_STATE)
.ifNecessary()
.withRationaleDialog(getString(R.string.RegistrationActivity_signal_needs_access_to_your_contacts_and_media_in_order_to_connect_with_friends),
R.drawable.ic_contacts_white_48dp, R.drawable.ic_folder_white_48dp)
.onAnyResult(() -> {
TextSecurePreferences.setHasSeenWelcomeScreen(WelcomeActivity.this, true);
Intent nextIntent = getIntent().getParcelableExtra("next_intent");
if (nextIntent == null) {
throw new IllegalStateException("Was not supplied a next_intent.");
}
startActivity(nextIntent);
overridePendingTransition(R.anim.slide_from_right, R.anim.fade_scale_out);
finish();
})
.execute();
}
}

View File

@@ -0,0 +1,16 @@
package org.thoughtcrime.securesms.util;
import android.app.Activity;
import org.thoughtcrime.securesms.R;
public class DynamicRegistrationTheme extends DynamicTheme {
@Override
protected int getSelectedTheme(Activity activity) {
String theme = TextSecurePreferences.getTheme(activity);
if (theme.equals("dark")) return R.style.TextSecure_DarkRegistrationTheme;
return R.style.TextSecure_LightRegistrationTheme;
}
}

View File

@@ -74,6 +74,7 @@ public class TextSecurePreferences {
private static final String VERIFYING_STATE_PREF = "pref_verifying";
public static final String REGISTERED_GCM_PREF = "pref_gcm_registered";
private static final String GCM_PASSWORD_PREF = "pref_gcm_password";
private static final String SEEN_WELCOME_SCREEN_PREF = "pref_seen_welcome_screen";
private static final String PROMPTED_PUSH_REGISTRATION_PREF = "pref_prompted_push_registration";
private static final String PROMPTED_DEFAULT_SMS_PREF = "pref_prompted_default_sms";
private static final String PROMPTED_OPTIMIZE_DOZE_PREF = "pref_prompted_optimize_doze";
@@ -842,6 +843,14 @@ public class TextSecurePreferences {
return getBooleanPreference(context, SMS_DELIVERY_REPORT_PREF, false);
}
public static boolean hasSeenWelcomeScreen(Context context) {
return getBooleanPreference(context, SEEN_WELCOME_SCREEN_PREF, true);
}
public static void setHasSeenWelcomeScreen(Context context, boolean value) {
setBooleanPreference(context, SEEN_WELCOME_SCREEN_PREF, value);
}
public static boolean hasPromptedPushRegistration(Context context) {
return getBooleanPreference(context, PROMPTED_PUSH_REGISTRATION_PREF, false);
}