From fb817e0c3bf23344ebe5b76574ff7f6bde71fbc0 Mon Sep 17 00:00:00 2001 From: Alex Hart Date: Wed, 2 Jun 2021 13:03:41 -0300 Subject: [PATCH] Add Chat Colors onboarding. --- .../colors/ui/ChatColorSelectionAdapter.kt | 13 ++++ .../CustomChatColorCreatorPageFragment.kt | 21 +++++++ .../securesms/keyvalue/ChatColorsValues.kt | 17 +++++- .../securesms/keyvalue/OnboardingValues.java | 14 ++++- .../securesms/megaphone/Megaphone.java | 13 ++++ .../securesms/megaphone/Megaphones.java | 14 ++++- .../megaphone/OnboardingMegaphoneView.java | 50 ++++++++++++--- .../megaphone/PopupMegaphoneView.java | 13 ++-- .../res/drawable/ic_signal_appearance.xml | 26 ++++++++ app/src/main/res/drawable/ic_union.xml | 14 +++++ .../main/res/layout/gradient_tool_tooltip.xml | 61 +++++++++++++++++++ .../main/res/layout/popup_megaphone_view.xml | 2 +- app/src/main/res/raw/color_bubble_64.json | 1 + app/src/main/res/values/strings.xml | 5 ++ 14 files changed, 249 insertions(+), 15 deletions(-) create mode 100644 app/src/main/res/drawable/ic_signal_appearance.xml create mode 100644 app/src/main/res/drawable/ic_union.xml create mode 100644 app/src/main/res/layout/gradient_tool_tooltip.xml create mode 100644 app/src/main/res/raw/color_bubble_64.json diff --git a/app/src/main/java/org/thoughtcrime/securesms/conversation/colors/ui/ChatColorSelectionAdapter.kt b/app/src/main/java/org/thoughtcrime/securesms/conversation/colors/ui/ChatColorSelectionAdapter.kt index 92f5366f2..ac61adaeb 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/conversation/colors/ui/ChatColorSelectionAdapter.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/conversation/colors/ui/ChatColorSelectionAdapter.kt @@ -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) + } } } diff --git a/app/src/main/java/org/thoughtcrime/securesms/conversation/colors/ui/custom/CustomChatColorCreatorPageFragment.kt b/app/src/main/java/org/thoughtcrime/securesms/conversation/colors/ui/custom/CustomChatColorCreatorPageFragment.kt index 73e97856f..51b1195fe 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/conversation/colors/ui/custom/CustomChatColorCreatorPageFragment.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/conversation/colors/ui/custom/CustomChatColorCreatorPageFragment.kt @@ -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 { diff --git a/app/src/main/java/org/thoughtcrime/securesms/keyvalue/ChatColorsValues.kt b/app/src/main/java/org/thoughtcrime/securesms/keyvalue/ChatColorsValues.kt index 4567de374..26e7d50f8 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/keyvalue/ChatColorsValues.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/keyvalue/ChatColorsValues.kt @@ -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 = mutableListOf() + override fun getKeysToIncludeInBackup(): MutableList = 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") diff --git a/app/src/main/java/org/thoughtcrime/securesms/keyvalue/OnboardingValues.java b/app/src/main/java/org/thoughtcrime/securesms/keyvalue/OnboardingValues.java index 46fc71338..1ffe8725e 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/keyvalue/OnboardingValues.java +++ b/app/src/main/java/org/thoughtcrime/securesms/keyvalue/OnboardingValues.java @@ -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); + } } diff --git a/app/src/main/java/org/thoughtcrime/securesms/megaphone/Megaphone.java b/app/src/main/java/org/thoughtcrime/securesms/megaphone/Megaphone.java index d3e8df29b..2456833a6 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/megaphone/Megaphone.java +++ b/app/src/main/java/org/thoughtcrime/securesms/megaphone/Megaphone.java @@ -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 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 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 imageRequest) { this.imageRequest = imageRequest; return this; diff --git a/app/src/main/java/org/thoughtcrime/securesms/megaphone/Megaphones.java b/app/src/main/java/org/thoughtcrime/securesms/megaphone/Megaphones.java index 92a3fefba..0db5fa4bc 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/megaphone/Megaphones.java +++ b/app/src/main/java/org/thoughtcrime/securesms/megaphone/Megaphones.java @@ -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; diff --git a/app/src/main/java/org/thoughtcrime/securesms/megaphone/OnboardingMegaphoneView.java b/app/src/main/java/org/thoughtcrime/securesms/megaphone/OnboardingMegaphoneView.java index 05c0494a8..7c06c736e 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/megaphone/OnboardingMegaphoneView.java +++ b/app/src/main/java/org/thoughtcrime/securesms/megaphone/OnboardingMegaphoneView.java @@ -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 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); + } + } } diff --git a/app/src/main/java/org/thoughtcrime/securesms/megaphone/PopupMegaphoneView.java b/app/src/main/java/org/thoughtcrime/securesms/megaphone/PopupMegaphoneView.java index e1fd330ef..2c696e69a 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/megaphone/PopupMegaphoneView.java +++ b/app/src/main/java/org/thoughtcrime/securesms/megaphone/PopupMegaphoneView.java @@ -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); } diff --git a/app/src/main/res/drawable/ic_signal_appearance.xml b/app/src/main/res/drawable/ic_signal_appearance.xml new file mode 100644 index 000000000..cd04dc0fe --- /dev/null +++ b/app/src/main/res/drawable/ic_signal_appearance.xml @@ -0,0 +1,26 @@ + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/app/src/main/res/drawable/ic_union.xml b/app/src/main/res/drawable/ic_union.xml new file mode 100644 index 000000000..96a2a67a6 --- /dev/null +++ b/app/src/main/res/drawable/ic_union.xml @@ -0,0 +1,14 @@ + + + + + + diff --git a/app/src/main/res/layout/gradient_tool_tooltip.xml b/app/src/main/res/layout/gradient_tool_tooltip.xml new file mode 100644 index 000000000..3ae01b8e5 --- /dev/null +++ b/app/src/main/res/layout/gradient_tool_tooltip.xml @@ -0,0 +1,61 @@ + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/popup_megaphone_view.xml b/app/src/main/res/layout/popup_megaphone_view.xml index 7c25ad251..be6ead7b0 100644 --- a/app/src/main/res/layout/popup_megaphone_view.xml +++ b/app/src/main/res/layout/popup_megaphone_view.xml @@ -25,7 +25,7 @@ android:clickable="true" android:paddingBottom="16dp"> - New group Invite friends Use SMS + Appearance Signal call in progress @@ -3507,6 +3508,10 @@ Tap to replace an emoji Reset Save + Auto matches the color to the wallpaper + Drag to change the direction of the gradient + New Chat Colors + We switched up chat colors to give you more options and make chats easier to read.