Improve message requests, add megaphone.

This commit is contained in:
Alex Hart
2020-02-19 18:08:34 -04:00
committed by Greyson Parrelli
parent dc689d325b
commit 9e5f64c431
83 changed files with 2406 additions and 735 deletions

View File

@@ -156,7 +156,7 @@ public class Megaphone {
}
enum Style {
REACTIONS, BASIC, FULLSCREEN
REACTIONS, BASIC, FULLSCREEN, POPUP
}
public interface EventListener {

View File

@@ -50,6 +50,7 @@ public class MegaphoneRepository {
public void onFirstEverAppLaunch() {
executor.execute(() -> {
database.markFinished(Event.REACTIONS);
database.markFinished(Event.MESSAGE_REQUESTS);
resetDatabaseCache();
});
}

View File

@@ -21,6 +21,8 @@ public class MegaphoneViewBuilder {
return null;
case REACTIONS:
return buildReactionsMegaphone(context, megaphone, listener);
case POPUP:
return buildPopupMegaphone(context, megaphone, listener);
default:
throw new IllegalArgumentException("No view implemented for style!");
}
@@ -43,4 +45,13 @@ public class MegaphoneViewBuilder {
view.present(megaphone, listener);
return view;
}
private static @NonNull View buildPopupMegaphone(@NonNull Context context,
@NonNull Megaphone megaphone,
@NonNull MegaphoneActionController listener)
{
PopupMegaphoneView view = new PopupMegaphoneView(context);
view.present(megaphone, listener);
return view;
}
}

View File

@@ -9,6 +9,7 @@ import androidx.annotation.Nullable;
import com.annimon.stream.Stream;
import org.thoughtcrime.securesms.R;
import org.thoughtcrime.securesms.conversationlist.ConversationListFragment;
import org.thoughtcrime.securesms.database.model.MegaphoneRecord;
import org.thoughtcrime.securesms.dependencies.ApplicationDependencies;
import org.thoughtcrime.securesms.jobmanager.impl.NetworkConstraint;
@@ -19,6 +20,7 @@ import org.thoughtcrime.securesms.lock.v2.CreateKbsPinActivity;
import org.thoughtcrime.securesms.lock.v2.KbsMigrationActivity;
import org.thoughtcrime.securesms.lock.v2.PinUtil;
import org.thoughtcrime.securesms.logging.Log;
import org.thoughtcrime.securesms.messagerequests.MessageRequestMegaphoneActivity;
import org.thoughtcrime.securesms.profiles.ProfileName;
import org.thoughtcrime.securesms.profiles.edit.EditProfileActivity;
import org.thoughtcrime.securesms.util.FeatureFlags;
@@ -49,7 +51,8 @@ public final class Megaphones {
private static final MegaphoneSchedule ALWAYS = new ForeverSchedule(true);
private static final MegaphoneSchedule NEVER = new ForeverSchedule(false);
private static final MegaphoneSchedule EVERY_TWO_DAYS = new RecurringSchedule(TimeUnit.DAYS.toMillis(2));
static final MegaphoneSchedule EVERY_TWO_DAYS = new RecurringSchedule(TimeUnit.DAYS.toMillis(2));
private Megaphones() {}
@@ -90,8 +93,9 @@ public final class Megaphones {
return new LinkedHashMap<Event, MegaphoneSchedule>() {{
put(Event.REACTIONS, ALWAYS);
put(Event.PINS_FOR_ALL, new PinsForAllSchedule());
put(Event.PROFILE_NAMES_FOR_ALL, FeatureFlags.profileNamesMegaphoneEnabled() ? EVERY_TWO_DAYS : NEVER);
put(Event.PROFILE_NAMES_FOR_ALL, FeatureFlags.profileNamesMegaphone() ? EVERY_TWO_DAYS : NEVER);
put(Event.PIN_REMINDER, new SignalPinReminderSchedule());
put(Event.MESSAGE_REQUESTS, shouldShowMessageRequestsMegaphone() ? ALWAYS : NEVER);
}};
}
@@ -105,6 +109,8 @@ public final class Megaphones {
return buildPinReminderMegaphone(context);
case PROFILE_NAMES_FOR_ALL:
return buildProfileNamesMegaphone(context);
case MESSAGE_REQUESTS:
return buildMessageRequestsMegaphone(context);
default:
throw new IllegalArgumentException("Event not handled!");
}
@@ -195,6 +201,10 @@ public final class Megaphones {
}
private static @NonNull Megaphone buildProfileNamesMegaphone(@NonNull Context context) {
short requestCode = TextSecurePreferences.getProfileName(context) != ProfileName.EMPTY
? ConversationListFragment.PROFILE_NAMES_REQUEST_CODE_CONFIRM_NAME
: ConversationListFragment.PROFILE_NAMES_REQUEST_CODE_CREATE_NAME;
Megaphone.Builder builder = new Megaphone.Builder(Event.PROFILE_NAMES_FOR_ALL, Megaphone.Style.BASIC)
.enableSnooze(null)
.setImage(R.drawable.profile_megaphone);
@@ -204,7 +214,7 @@ public final class Megaphones {
.setBody(R.string.ProfileNamesMegaphone__this_will_be_displayed_when_you_start)
.setActionButton(R.string.ProfileNamesMegaphone__add_profile_name, (megaphone, listener) -> {
listener.onMegaphoneSnooze(Event.PROFILE_NAMES_FOR_ALL);
listener.onMegaphoneNavigationRequested(new Intent(context, EditProfileActivity.class));
listener.onMegaphoneNavigationRequested(new Intent(context, EditProfileActivity.class), requestCode);
})
.build();
} else {
@@ -212,17 +222,34 @@ public final class Megaphones {
.setBody(R.string.ProfileNamesMegaphone__your_profile_can_now_include)
.setActionButton(R.string.ProfileNamesMegaphone__confirm_name, (megaphone, listener) -> {
listener.onMegaphoneCompleted(Event.PROFILE_NAMES_FOR_ALL);
listener.onMegaphoneNavigationRequested(new Intent(context, EditProfileActivity.class));
listener.onMegaphoneNavigationRequested(new Intent(context, EditProfileActivity.class), requestCode);
})
.build();
}
}
private static @NonNull Megaphone buildMessageRequestsMegaphone(@NonNull Context context) {
return new Megaphone.Builder(Event.MESSAGE_REQUESTS, Megaphone.Style.FULLSCREEN)
.disableSnooze()
.setMandatory(true)
.setOnVisibleListener(((megaphone, listener) -> {
listener.onMegaphoneNavigationRequested(new Intent(context, MessageRequestMegaphoneActivity.class),
ConversationListFragment.MESSAGE_REQUESTS_REQUEST_CODE_CREATE_NAME);
}))
.build();
}
private static boolean shouldShowMessageRequestsMegaphone() {
boolean userHasAProfileName = TextSecurePreferences.getProfileName(ApplicationDependencies.getApplication()) != ProfileName.EMPTY;
return FeatureFlags.messageRequests() && !userHasAProfileName;
}
public enum Event {
REACTIONS("reactions"),
PINS_FOR_ALL("pins_for_all"),
PIN_REMINDER("pin_reminder"),
PROFILE_NAMES_FOR_ALL("profile_names");
PROFILE_NAMES_FOR_ALL("profile_names"),
MESSAGE_REQUESTS("message_requests");
private final String key;

View File

@@ -0,0 +1,86 @@
package org.thoughtcrime.securesms.megaphone;
import android.content.Context;
import android.util.AttributeSet;
import android.view.View;
import android.widget.Button;
import android.widget.FrameLayout;
import android.widget.ImageView;
import android.widget.TextView;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import org.thoughtcrime.securesms.R;
public class PopupMegaphoneView extends FrameLayout {
private ImageView image;
private TextView titleText;
private TextView bodyText;
private View xButton;
private Megaphone megaphone;
private MegaphoneActionController megaphoneListener;
public PopupMegaphoneView(@NonNull Context context) {
super(context);
init(context);
}
public PopupMegaphoneView(@NonNull Context context, @Nullable AttributeSet attrs) {
super(context, attrs);
init(context);
}
private void init(@NonNull Context context) {
inflate(context, R.layout.popup_megaphone_view, this);
this.image = findViewById(R.id.popup_megaphone_image);
this.titleText = findViewById(R.id.popup_megaphone_title);
this.bodyText = findViewById(R.id.popup_megaphone_body);
this.xButton = findViewById(R.id.popup_x);
}
@Override
protected void onAttachedToWindow() {
super.onAttachedToWindow();
if (megaphone != null && megaphoneListener != null && megaphone.getOnVisibleListener() != null) {
megaphone.getOnVisibleListener().onEvent(megaphone, megaphoneListener);
}
}
public void present(@NonNull Megaphone megaphone, @NonNull MegaphoneActionController megaphoneListener) {
this.megaphone = megaphone;
this.megaphoneListener = megaphoneListener;
if (megaphone.getImage() != 0) {
image.setVisibility(VISIBLE);
image.setImageResource(megaphone.getImage());
} else {
image.setVisibility(GONE);
}
if (megaphone.getTitle() != 0) {
titleText.setVisibility(VISIBLE);
titleText.setText(megaphone.getTitle());
} else {
titleText.setVisibility(GONE);
}
if (megaphone.getBody() != 0) {
bodyText.setVisibility(VISIBLE);
bodyText.setText(megaphone.getBody());
} else {
bodyText.setVisibility(GONE);
}
if (megaphone.hasButton()) {
xButton.setOnClickListener(v -> megaphone.getButtonClickListener().onEvent(megaphone, megaphoneListener));
} else {
xButton.setOnClickListener(v -> megaphoneListener.onMegaphoneCompleted(megaphone.getEvent()));
}
}
}