Use megaphones for PIN reminders.

This commit is contained in:
Greyson Parrelli
2020-02-07 20:37:35 -05:00
parent 38e4733433
commit ddc01b539f
20 changed files with 496 additions and 244 deletions

View File

@@ -20,8 +20,8 @@ public class BasicMegaphoneView extends FrameLayout {
private Button actionButton;
private Button snoozeButton;
private Megaphone megaphone;
private MegaphoneListener megaphoneListener;
private Megaphone megaphone;
private MegaphoneActionController megaphoneListener;
public BasicMegaphoneView(@NonNull Context context) {
super(context);
@@ -52,7 +52,7 @@ public class BasicMegaphoneView extends FrameLayout {
}
}
public void present(@NonNull Megaphone megaphone, @NonNull MegaphoneListener megaphoneListener) {
public void present(@NonNull Megaphone megaphone, @NonNull MegaphoneActionController megaphoneListener) {
this.megaphone = megaphone;
this.megaphoneListener = megaphoneListener;
@@ -92,7 +92,7 @@ public class BasicMegaphoneView extends FrameLayout {
if (megaphone.canSnooze()) {
snoozeButton.setVisibility(VISIBLE);
snoozeButton.setOnClickListener(v -> {
megaphoneListener.onMegaphoneSnooze(megaphone);
megaphoneListener.onMegaphoneSnooze(megaphone.getEvent());
if (megaphone.getSnoozeListener() != null) {
megaphone.getSnoozeListener().onEvent(megaphone, megaphoneListener);

View File

@@ -139,7 +139,7 @@ public class Megaphone {
return this;
}
public @NonNull Builder setButtonText(@StringRes int buttonTextRes, @NonNull EventListener listener) {
public @NonNull Builder setActionButton(@StringRes int buttonTextRes, @NonNull EventListener listener) {
this.buttonTextRes = buttonTextRes;
this.buttonListener = listener;
return this;
@@ -160,6 +160,6 @@ public class Megaphone {
}
public interface EventListener {
void onEvent(@NonNull Megaphone megaphone, @NonNull MegaphoneListener listener);
void onEvent(@NonNull Megaphone megaphone, @NonNull MegaphoneActionController listener);
}
}

View File

@@ -1,11 +1,12 @@
package org.thoughtcrime.securesms.megaphone;
import android.app.Activity;
import android.content.Intent;
import androidx.annotation.NonNull;
import androidx.annotation.StringRes;
public interface MegaphoneListener {
public interface MegaphoneActionController {
/**
* When a megaphone wants to navigate to a specific intent.
*/
@@ -21,13 +22,18 @@ public interface MegaphoneListener {
*/
void onMegaphoneToastRequested(@NonNull String string);
/**
* When a megaphone needs a raw activity reference. Favor more specific methods when possible.
*/
@NonNull Activity getMegaphoneActivity();
/**
* When a megaphone has been snoozed via "remind me later" or a similar option.
*/
void onMegaphoneSnooze(@NonNull Megaphone megaphone);
void onMegaphoneSnooze(@NonNull Megaphones.Event event);
/**
* Called when a megaphone completed its goal.
*/
void onMegaphoneCompleted(@NonNull Megaphone megaphone);
void onMegaphoneCompleted(@NonNull Megaphones.Event event);
}

View File

@@ -12,7 +12,7 @@ public class MegaphoneViewBuilder {
public static @Nullable View build(@NonNull Context context,
@NonNull Megaphone megaphone,
@NonNull MegaphoneListener listener)
@NonNull MegaphoneActionController listener)
{
switch (megaphone.getStyle()) {
case BASIC:
@@ -28,7 +28,7 @@ public class MegaphoneViewBuilder {
private static @NonNull View buildBasicMegaphone(@NonNull Context context,
@NonNull Megaphone megaphone,
@NonNull MegaphoneListener listener)
@NonNull MegaphoneActionController listener)
{
BasicMegaphoneView view = new BasicMegaphoneView(context);
view.present(megaphone, listener);
@@ -37,7 +37,7 @@ public class MegaphoneViewBuilder {
private static @NonNull View buildReactionsMegaphone(@NonNull Context context,
@NonNull Megaphone megaphone,
@NonNull MegaphoneListener listener)
@NonNull MegaphoneActionController listener)
{
ReactionsMegaphoneView view = new ReactionsMegaphoneView(context);
view.present(megaphone, listener);

View File

@@ -12,6 +12,11 @@ import org.thoughtcrime.securesms.R;
import org.thoughtcrime.securesms.database.model.MegaphoneRecord;
import org.thoughtcrime.securesms.dependencies.ApplicationDependencies;
import org.thoughtcrime.securesms.jobmanager.impl.NetworkConstraint;
import org.thoughtcrime.securesms.keyvalue.SignalStore;
import org.thoughtcrime.securesms.lock.RegistrationLockDialog;
import org.thoughtcrime.securesms.lock.RegistrationLockReminders;
import org.thoughtcrime.securesms.lock.SignalPinReminderDialog;
import org.thoughtcrime.securesms.lock.SignalPinReminders;
import org.thoughtcrime.securesms.lock.v2.CreateKbsPinActivity;
import org.thoughtcrime.securesms.lock.v2.KbsMigrationActivity;
import org.thoughtcrime.securesms.lock.v2.PinUtil;
@@ -76,6 +81,7 @@ public final class Megaphones {
return new LinkedHashMap<Event, MegaphoneSchedule>() {{
put(Event.REACTIONS, new ForeverSchedule(true));
put(Event.PINS_FOR_ALL, new PinsForAllSchedule());
put(Event.PIN_REMINDER, new PinReminderSchedule());
}};
}
@@ -84,7 +90,9 @@ public final class Megaphones {
case REACTIONS:
return buildReactionsMegaphone();
case PINS_FOR_ALL:
return buildPinsForAllMegaphone(context, record);
return buildPinsForAllMegaphone(record);
case PIN_REMINDER:
return buildPinReminderMegaphone(context);
default:
throw new IllegalArgumentException("Event not handled!");
}
@@ -96,7 +104,7 @@ public final class Megaphones {
.build();
}
private static @NonNull Megaphone buildPinsForAllMegaphone(@NonNull Context context, @NonNull MegaphoneRecord record) {
private static @NonNull Megaphone buildPinsForAllMegaphone(@NonNull MegaphoneRecord record) {
if (PinsForAllSchedule.shouldDisplayFullScreen(record.getFirstVisible(), System.currentTimeMillis())) {
return new Megaphone.Builder(Event.PINS_FOR_ALL, Megaphone.Style.FULLSCREEN)
.setMandatory(true)
@@ -125,7 +133,7 @@ public final class Megaphones {
private static @NonNull Megaphone buildPinsForAllMegaphoneForUserWithPin(@NonNull Megaphone.Builder builder) {
return builder.setTitle(R.string.KbsMegaphone__introducing_pins)
.setBody(R.string.KbsMegaphone__your_registration_lock_is_now_called_a_pin)
.setButtonText(R.string.KbsMegaphone__update_pin, (megaphone, listener) -> {
.setActionButton(R.string.KbsMegaphone__update_pin, (megaphone, listener) -> {
Intent intent = CreateKbsPinActivity.getIntentForPinChangeFromSettings(ApplicationDependencies.getApplication());
listener.onMegaphoneNavigationRequested(intent, CreateKbsPinActivity.REQUEST_NEW_PIN);
@@ -136,7 +144,7 @@ public final class Megaphones {
private static @NonNull Megaphone buildPinsForAllMegaphoneForUserWithoutPin(@NonNull Megaphone.Builder builder) {
return builder.setTitle(R.string.KbsMegaphone__create_a_pin)
.setBody(R.string.KbsMegaphone__pins_add_another_layer_of_security_to_your_signal_account)
.setButtonText(R.string.KbsMegaphone__create_pin, (megaphone, listener) -> {
.setActionButton(R.string.KbsMegaphone__create_pin, (megaphone, listener) -> {
Intent intent = CreateKbsPinActivity.getIntentForPinCreate(ApplicationDependencies.getApplication());
listener.onMegaphoneNavigationRequested(intent, CreateKbsPinActivity.REQUEST_NEW_PIN);
@@ -144,9 +152,40 @@ public final class Megaphones {
.build();
}
private static @NonNull Megaphone buildPinReminderMegaphone(@NonNull Context context) {
return new Megaphone.Builder(Event.PIN_REMINDER, Megaphone.Style.BASIC)
.setTitle(R.string.Megaphones_verify_your_signal_pin)
.setBody(R.string.Megaphones_well_occasionally_ask_you_to_verify_your_pin)
.setImage(R.drawable.kbs_pin_megaphone)
.setActionButton(R.string.Megaphones_verify_pin, (megaphone, controller) -> {
SignalPinReminderDialog.show(controller.getMegaphoneActivity(), controller::onMegaphoneNavigationRequested, new SignalPinReminderDialog.Callback() {
@Override
public void onReminderDismissed(boolean includedFailure) {
if (includedFailure) {
SignalStore.pinValues().onEntryFailure();
}
}
@Override
public void onReminderCompleted(boolean includedFailure) {
if (includedFailure) {
SignalStore.pinValues().onEntryFailure();
} else {
SignalStore.pinValues().onEntrySuccess();
}
controller.onMegaphoneSnooze(Event.PIN_REMINDER);
controller.onMegaphoneToastRequested(context.getString(SignalPinReminders.getReminderString(SignalStore.pinValues().getCurrentInterval())));
}
});
})
.build();
}
public enum Event {
REACTIONS("reactions"),
PINS_FOR_ALL("pins_for_all");
PINS_FOR_ALL("pins_for_all"),
PIN_REMINDER("pin_reminder");
private final String key;

View File

@@ -0,0 +1,23 @@
package org.thoughtcrime.securesms.megaphone;
import org.thoughtcrime.securesms.keyvalue.SignalStore;
import org.thoughtcrime.securesms.util.FeatureFlags;
final class PinReminderSchedule implements MegaphoneSchedule {
@Override
public boolean shouldDisplay(int seenCount, long lastSeen, long firstVisible, long currentTime) {
if (!SignalStore.kbsValues().isV2RegistrationLockEnabled()) {
return false;
}
if (!FeatureFlags.pinsForAll()) {
return false;
}
long lastSuccessTime = SignalStore.pinValues().getLastSuccessfulEntryTime();
long interval = SignalStore.pinValues().getCurrentInterval();
return currentTime - lastSuccessTime >= interval;
}
}