Add Chat Colors onboarding.

This commit is contained in:
Alex Hart
2021-06-02 13:03:41 -03:00
committed by Cody Henthorne
parent 1eae360470
commit fb817e0c3b
14 changed files with 249 additions and 15 deletions

View File

@@ -1,11 +1,15 @@
package org.thoughtcrime.securesms.conversation.colors.ui
import android.content.Context
import android.graphics.Color
import android.view.View
import android.widget.ImageView
import android.widget.TextView
import androidx.core.content.ContextCompat
import org.thoughtcrime.securesms.R
import org.thoughtcrime.securesms.components.TooltipPopup
import org.thoughtcrime.securesms.conversation.colors.ChatColors
import org.thoughtcrime.securesms.keyvalue.SignalStore
import org.thoughtcrime.securesms.util.MappingAdapter
import org.thoughtcrime.securesms.util.MappingViewHolder
import org.thoughtcrime.securesms.util.ViewUtil
@@ -83,6 +87,15 @@ class ChatColorSelectionAdapter(
val mask = model.chatColors.asCircle()
preview.setImageDrawable(mask.withFixedSize(ViewUtil.dpToPx(56)))
if (model.isAuto && SignalStore.chatColorsValues().shouldShowAutoTooltip) {
SignalStore.chatColorsValues().shouldShowAutoTooltip = false
TooltipPopup.forTarget(itemView)
.setText(R.string.ChatColorSelectionFragment__auto_matches_the_color_to_the_wallpaper)
.setBackgroundTint(ContextCompat.getColor(context, R.color.signal_accent_primary))
.setTextColor(Color.WHITE)
.show(TooltipPopup.POSITION_BELOW)
}
}
}

View File

@@ -11,8 +11,11 @@ import android.graphics.PointF
import android.graphics.RectF
import android.graphics.drawable.Drawable
import android.graphics.drawable.GradientDrawable
import android.os.Build
import android.os.Bundle
import android.view.View
import android.view.ViewGroup
import android.widget.PopupWindow
import android.widget.ScrollView
import android.widget.SeekBar
import androidx.annotation.ColorInt
@@ -28,6 +31,7 @@ import org.thoughtcrime.securesms.R
import org.thoughtcrime.securesms.conversation.colors.ChatColors
import org.thoughtcrime.securesms.conversation.colors.ui.ChatColorPreviewView
import org.thoughtcrime.securesms.conversation.colors.ui.ChatColorSelectionViewModel
import org.thoughtcrime.securesms.keyvalue.SignalStore
import org.thoughtcrime.securesms.util.Util
import org.thoughtcrime.securesms.util.ViewUtil
import org.thoughtcrime.securesms.util.customizeOnDraw
@@ -195,6 +199,23 @@ class CustomChatColorCreatorPageFragment :
}
}
}
if (page == 1 && SignalStore.chatColorsValues().shouldShowGradientTooltip) {
view.post {
SignalStore.chatColorsValues().shouldShowGradientTooltip = false
val contentView = layoutInflater.inflate(R.layout.gradient_tool_tooltip, view as ViewGroup, false)
val popupWindow = PopupWindow(contentView, ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT)
popupWindow.isOutsideTouchable = false
popupWindow.isFocusable = true
if (Build.VERSION.SDK_INT > 21) {
popupWindow.elevation = ViewUtil.dpToPx(8).toFloat()
}
popupWindow.showAsDropDown(gradientTool, 0, -gradientTool.measuredHeight + ViewUtil.dpToPx(48))
}
}
}
private fun createRepository(): CustomChatColorCreatorRepository {

View File

@@ -9,11 +9,26 @@ internal class ChatColorsValues internal constructor(store: KeyValueStore) : Sig
companion object {
private const val KEY_CHAT_COLORS = "chat_colors.chat_colors"
private const val KEY_CHAT_COLORS_ID = "chat_colors.chat_colors.id"
private const val KEY_CHAT_COLORS_AUTO_TOOLTIP = "chat_colors.auto.tooltip"
private const val KEY_CHAT_COLORS_GRADIENT_TOOLTIP = "chat_colors.gradient.tooltip"
}
override fun onFirstEverAppLaunch() = Unit
override fun getKeysToIncludeInBackup(): MutableList<String> = mutableListOf()
override fun getKeysToIncludeInBackup(): MutableList<String> = mutableListOf(
KEY_CHAT_COLORS,
KEY_CHAT_COLORS_ID,
KEY_CHAT_COLORS_AUTO_TOOLTIP,
KEY_CHAT_COLORS_GRADIENT_TOOLTIP
)
var shouldShowAutoTooltip: Boolean
get() = getBoolean(KEY_CHAT_COLORS_AUTO_TOOLTIP, true)
set(value) = putBoolean(KEY_CHAT_COLORS_AUTO_TOOLTIP, value)
var shouldShowGradientTooltip: Boolean
get() = getBoolean(KEY_CHAT_COLORS_GRADIENT_TOOLTIP, true)
set(value) = putBoolean(KEY_CHAT_COLORS_GRADIENT_TOOLTIP, value)
val hasChatColors: Boolean
@JvmName("hasChatColors")

View File

@@ -15,6 +15,7 @@ public final class OnboardingValues extends SignalStoreValues {
private static final String SHOW_NEW_GROUP = "onboarding.new_group";
private static final String SHOW_INVITE_FRIENDS = "onboarding.invite_friends";
private static final String SHOW_SMS = "onboarding.sms";
private static final String SHOW_APPEARANCE = "onboarding.appearance";
OnboardingValues(@NonNull KeyValueStore store) {
super(store);
@@ -25,6 +26,7 @@ public final class OnboardingValues extends SignalStoreValues {
putBoolean(SHOW_NEW_GROUP, true);
putBoolean(SHOW_INVITE_FRIENDS, true);
putBoolean(SHOW_SMS, true);
putBoolean(SHOW_APPEARANCE, true);
}
@Override
@@ -36,12 +38,14 @@ public final class OnboardingValues extends SignalStoreValues {
setShowNewGroup(false);
setShowInviteFriends(false);
setShowSms(false);
setShowAppearance(false);
}
public boolean hasOnboarding(@NonNull Context context) {
return shouldShowNewGroup() ||
shouldShowInviteFriends() ||
shouldShowSms(context);
shouldShowSms(context) ||
shouldShowAppearance();
}
public void setShowNewGroup(boolean value) {
@@ -67,4 +71,12 @@ public final class OnboardingValues extends SignalStoreValues {
public boolean shouldShowSms(@NonNull Context context) {
return getBoolean(SHOW_SMS, false) && !Util.isDefaultSmsProvider(context) && PhoneNumberFormatter.getLocalCountryCode() != 91;
}
public void setShowAppearance(boolean value) {
putBoolean(SHOW_APPEARANCE, value);
}
public boolean shouldShowAppearance() {
return getBoolean(SHOW_APPEARANCE, false);
}
}

View File

@@ -6,6 +6,7 @@ import android.graphics.drawable.Drawable;
import androidx.annotation.DrawableRes;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.annotation.RawRes;
import androidx.annotation.StringRes;
import org.thoughtcrime.securesms.dependencies.ApplicationDependencies;
@@ -25,6 +26,7 @@ public class Megaphone {
private final int titleRes;
private final int bodyRes;
private final int imageRes;
private final int lottieRes;
private final GlideRequest<Drawable> imageRequest;
private final int buttonTextRes;
private final EventListener buttonListener;
@@ -41,6 +43,7 @@ public class Megaphone {
this.titleRes = builder.titleRes;
this.bodyRes = builder.bodyRes;
this.imageRes = builder.imageRes;
this.lottieRes = builder.lottieRes;
this.imageRequest = builder.imageRequest;
this.buttonTextRes = builder.buttonTextRes;
this.buttonListener = builder.buttonListener;
@@ -74,6 +77,10 @@ public class Megaphone {
return bodyRes;
}
public @RawRes int getLottieRes() {
return lottieRes;
}
public @DrawableRes int getImageRes() {
return imageRes;
}
@@ -124,6 +131,7 @@ public class Megaphone {
private int titleRes;
private int bodyRes;
private int imageRes;
private int lottieRes;
private GlideRequest<Drawable> imageRequest;
private int buttonTextRes;
private EventListener buttonListener;
@@ -174,6 +182,11 @@ public class Megaphone {
return this;
}
public @NonNull Builder setLottie(@RawRes int lottieRes) {
this.lottieRes = lottieRes;
return this;
}
public @NonNull Builder setImageRequest(@Nullable GlideRequest<Drawable> imageRequest) {
this.imageRequest = imageRequest;
return this;

View File

@@ -103,6 +103,7 @@ public final class Megaphones {
put(Event.GROUP_CALLING, shouldShowGroupCallingMegaphone() ? ALWAYS : NEVER);
put(Event.ONBOARDING, shouldShowOnboardingMegaphone(context) ? ALWAYS : NEVER);
put(Event.NOTIFICATIONS, shouldShowNotificationsMegaphone(context) ? RecurringSchedule.every(TimeUnit.DAYS.toMillis(30)) : NEVER);
put(Event.CHAT_COLORS, ALWAYS);
}};
}
@@ -130,6 +131,8 @@ public final class Megaphones {
return buildOnboardingMegaphone();
case NOTIFICATIONS:
return buildNotificationsMegaphone(context);
case CHAT_COLORS:
return buildChatColorsMegaphone();
default:
throw new IllegalArgumentException("Event not handled!");
}
@@ -301,6 +304,14 @@ public final class Megaphones {
.build();
}
private static @NonNull Megaphone buildChatColorsMegaphone() {
return new Megaphone.Builder(Event.CHAT_COLORS, Megaphone.Style.POPUP)
.setTitle(R.string.ChatColorsMegaphone__new_chat_colors)
.setBody(R.string.ChatColorsMegaphone__we_switched_up_chat_colors)
.setLottie(R.raw.color_bubble_64)
.build();
}
private static boolean shouldShowMessageRequestsMegaphone() {
return Recipient.self().getProfileName() == ProfileName.EMPTY;
}
@@ -355,7 +366,8 @@ public final class Megaphones {
DONATE("donate"),
GROUP_CALLING("group_calling"),
ONBOARDING("onboarding"),
NOTIFICATIONS("notifications");
NOTIFICATIONS("notifications"),
CHAT_COLORS("chat_colors");
private final String key;

View File

@@ -19,10 +19,12 @@ import androidx.recyclerview.widget.RecyclerView;
import org.signal.core.util.logging.Log;
import org.thoughtcrime.securesms.InviteActivity;
import org.thoughtcrime.securesms.R;
import org.thoughtcrime.securesms.components.settings.app.AppSettingsActivity;
import org.thoughtcrime.securesms.conversationlist.ConversationListFragment;
import org.thoughtcrime.securesms.groups.ui.creategroup.CreateGroupActivity;
import org.thoughtcrime.securesms.keyvalue.SignalStore;
import org.thoughtcrime.securesms.util.SmsUtil;
import org.thoughtcrime.securesms.wallpaper.ChatWallpaperActivity;
import java.util.ArrayList;
import java.util.List;
@@ -60,9 +62,10 @@ public class OnboardingMegaphoneView extends FrameLayout {
private static class CardAdapter extends RecyclerView.Adapter<CardViewHolder> implements ActionClickListener {
private static final int TYPE_GROUP = 0;
private static final int TYPE_INVITE = 1;
private static final int TYPE_SMS = 2;
private static final int TYPE_GROUP = 0;
private static final int TYPE_INVITE = 1;
private static final int TYPE_SMS = 2;
private static final int TYPE_APPEARANCE = 3;
private final Context context;
private final MegaphoneActionController controller;
@@ -95,10 +98,11 @@ public class OnboardingMegaphoneView extends FrameLayout {
public @NonNull CardViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.onboarding_megaphone_list_item, parent, false);
switch (viewType) {
case TYPE_GROUP: return new GroupCardViewHolder(view);
case TYPE_INVITE: return new InviteCardViewHolder(view);
case TYPE_SMS: return new SmsCardViewHolder(view);
default: throw new IllegalStateException("Invalid viewType! " + viewType);
case TYPE_GROUP: return new GroupCardViewHolder(view);
case TYPE_INVITE: return new InviteCardViewHolder(view);
case TYPE_SMS: return new SmsCardViewHolder(view);
case TYPE_APPEARANCE: return new AppearanceCardViewHolder(view);
default: throw new IllegalStateException("Invalid viewType! " + viewType);
}
}
@@ -138,6 +142,10 @@ public class OnboardingMegaphoneView extends FrameLayout {
data.add(TYPE_SMS);
}
if (SignalStore.onboarding().shouldShowAppearance()) {
data.add(TYPE_APPEARANCE);
}
return data;
}
}
@@ -259,4 +267,32 @@ public class OnboardingMegaphoneView extends FrameLayout {
SignalStore.onboarding().setShowSms(false);
}
}
private static class AppearanceCardViewHolder extends CardViewHolder {
public AppearanceCardViewHolder(@NonNull View itemView) {
super(itemView);
}
@Override
int getButtonStringRes() {
return R.string.Megaphones_appearance;
}
@Override
int getImageRes() {
return R.drawable.ic_signal_appearance;
}
@Override
void onActionClicked(@NonNull MegaphoneActionController controller) {
controller.onMegaphoneNavigationRequested(ChatWallpaperActivity.createIntent(controller.getMegaphoneActivity()));
SignalStore.onboarding().setShowAppearance(false);
}
@Override
void onCloseClicked() {
SignalStore.onboarding().setShowAppearance(false);
}
}
}

View File

@@ -10,14 +10,16 @@ import android.widget.TextView;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import com.airbnb.lottie.LottieAnimationView;
import org.thoughtcrime.securesms.R;
public class PopupMegaphoneView extends FrameLayout {
private ImageView image;
private TextView titleText;
private TextView bodyText;
private View xButton;
private LottieAnimationView image;
private TextView titleText;
private TextView bodyText;
private View xButton;
private Megaphone megaphone;
private MegaphoneActionController megaphoneListener;
@@ -57,6 +59,9 @@ public class PopupMegaphoneView extends FrameLayout {
if (megaphone.getImageRequest() != null) {
image.setVisibility(VISIBLE);
megaphone.getImageRequest().into(image);
} else if (megaphone.getLottieRes() != 0) {
image.setVisibility(VISIBLE);
image.setAnimation(megaphone.getLottieRes());
} else {
image.setVisibility(GONE);
}