Add group calling tooltip and megaphone.

This commit is contained in:
Alex Hart 2020-12-14 18:26:07 -04:00 committed by Greyson Parrelli
parent 7227b43bbe
commit fa7346f79b
12 changed files with 81 additions and 9 deletions

View file

@ -374,6 +374,7 @@ public class ConversationActivity extends PassphraseRequiredActivity
private View cancelJoinRequest; private View cancelJoinRequest;
private Stub<View> mentionsSuggestions; private Stub<View> mentionsSuggestions;
private MaterialButton joinGroupCallButton; private MaterialButton joinGroupCallButton;
private boolean callingTooltipShown;
private LinkPreviewViewModel linkPreviewViewModel; private LinkPreviewViewModel linkPreviewViewModel;
private ConversationSearchViewModel searchViewModel; private ConversationSearchViewModel searchViewModel;
@ -830,6 +831,7 @@ public class ConversationActivity extends PassphraseRequiredActivity
if (groupCallViewModel != null && Boolean.TRUE.equals(groupCallViewModel.hasActiveGroupCall().getValue())) { if (groupCallViewModel != null && Boolean.TRUE.equals(groupCallViewModel.hasActiveGroupCall().getValue())) {
hideMenuItem(menu, R.id.menu_video_secure); hideMenuItem(menu, R.id.menu_video_secure);
} }
showGroupCallingTooltip();
} }
inflater.inflate(R.menu.conversation_group_options, menu); inflater.inflate(R.menu.conversation_group_options, menu);
@ -2137,6 +2139,28 @@ public class ConversationActivity extends PassphraseRequiredActivity
groupCallViewModel.groupCallHasCapacity().observe(this, hasCapacity -> joinGroupCallButton.setText(hasCapacity ? R.string.ConversationActivity_join : R.string.ConversationActivity_full)); groupCallViewModel.groupCallHasCapacity().observe(this, hasCapacity -> joinGroupCallButton.setText(hasCapacity ? R.string.ConversationActivity_join : R.string.ConversationActivity_full));
} }
private void showGroupCallingTooltip() {
if (!FeatureFlags.groupCalling() || !SignalStore.tooltips().shouldShowGroupCallingTooltip() || callingTooltipShown) {
return;
}
View anchor = findViewById(R.id.menu_video_secure);
if (anchor == null) {
Log.w(TAG, "Video Call tooltip anchor is null. Skipping tooltip...");
return;
}
callingTooltipShown = true;
SignalStore.tooltips().markGroupCallSpeakerViewSeen();
TooltipPopup.forTarget(anchor)
.setBackgroundTint(ContextCompat.getColor(this, R.color.signal_accent_green))
.setTextColor(getResources().getColor(R.color.core_white))
.setText(R.string.ConversationActivity__tap_here_to_start_a_group_call)
.setOnDismissListener(() -> SignalStore.tooltips().markGroupCallingTooltipSeen())
.show(TooltipPopup.POSITION_BELOW);
}
private void showStickerIntroductionTooltip() { private void showStickerIntroductionTooltip() {
TextSecurePreferences.setMediaKeyboardMode(this, MediaKeyboardMode.STICKER); TextSecurePreferences.setMediaKeyboardMode(this, MediaKeyboardMode.STICKER);
inputPanel.setMediaKeyboardToggleMode(true); inputPanel.setMediaKeyboardToggleMode(true);

View file

@ -103,6 +103,7 @@ import org.thoughtcrime.securesms.dependencies.ApplicationDependencies;
import org.thoughtcrime.securesms.events.ReminderUpdateEvent; import org.thoughtcrime.securesms.events.ReminderUpdateEvent;
import org.thoughtcrime.securesms.insights.InsightsLauncher; import org.thoughtcrime.securesms.insights.InsightsLauncher;
import org.thoughtcrime.securesms.jobs.ServiceOutageDetectionJob; import org.thoughtcrime.securesms.jobs.ServiceOutageDetectionJob;
import org.thoughtcrime.securesms.keyvalue.SignalStore;
import org.thoughtcrime.securesms.lock.v2.CreateKbsPinActivity; import org.thoughtcrime.securesms.lock.v2.CreateKbsPinActivity;
import org.thoughtcrime.securesms.mediasend.MediaSendActivity; import org.thoughtcrime.securesms.mediasend.MediaSendActivity;
import org.thoughtcrime.securesms.megaphone.Megaphone; import org.thoughtcrime.securesms.megaphone.Megaphone;

View file

@ -4,8 +4,12 @@ import androidx.annotation.NonNull;
public class TooltipValues extends SignalStoreValues { public class TooltipValues extends SignalStoreValues {
private static final int GROUP_CALLING_MAX_TOOLTIP_DISPLAY_COUNT = 3;
private static final String BLUR_HUD_ICON = "tooltip.blur_hud_icon"; private static final String BLUR_HUD_ICON = "tooltip.blur_hud_icon";
private static final String GROUP_CALL_SPEAKER_VIEW = "tooltip.group_call_speaker_view"; private static final String GROUP_CALL_SPEAKER_VIEW = "tooltip.group_call_speaker_view";
private static final String GROUP_CALL_TOOLTIP_DISPLAY_COUNT = "tooltip.group_call_tooltip_display_count";
TooltipValues(@NonNull KeyValueStore store) { TooltipValues(@NonNull KeyValueStore store) {
super(store); super(store);
@ -30,4 +34,16 @@ public class TooltipValues extends SignalStoreValues {
public void markGroupCallSpeakerViewSeen() { public void markGroupCallSpeakerViewSeen() {
putBoolean(GROUP_CALL_SPEAKER_VIEW, true); putBoolean(GROUP_CALL_SPEAKER_VIEW, true);
} }
public boolean shouldShowGroupCallingTooltip() {
return getInteger(GROUP_CALL_TOOLTIP_DISPLAY_COUNT, 0) < GROUP_CALLING_MAX_TOOLTIP_DISPLAY_COUNT;
}
public void markGroupCallingTooltipSeen() {
putInteger(GROUP_CALL_TOOLTIP_DISPLAY_COUNT, getInteger(GROUP_CALL_TOOLTIP_DISPLAY_COUNT, 0) + 1);
}
public void markGroupCallingLobbyEntered() {
putInteger(GROUP_CALL_TOOLTIP_DISPLAY_COUNT, Integer.MAX_VALUE);
}
} }

View file

@ -54,6 +54,7 @@ public class MegaphoneRepository {
database.markFinished(Event.MESSAGE_REQUESTS); database.markFinished(Event.MESSAGE_REQUESTS);
database.markFinished(Event.LINK_PREVIEWS); database.markFinished(Event.LINK_PREVIEWS);
database.markFinished(Event.RESEARCH); database.markFinished(Event.RESEARCH);
database.markFinished(Event.GROUP_CALLING);
resetDatabaseCache(); resetDatabaseCache();
}); });
} }

View file

@ -92,6 +92,7 @@ public final class Megaphones {
put(Event.CLIENT_DEPRECATED, SignalStore.misc().isClientDeprecated() ? ALWAYS : NEVER); put(Event.CLIENT_DEPRECATED, SignalStore.misc().isClientDeprecated() ? ALWAYS : NEVER);
put(Event.RESEARCH, shouldShowResearchMegaphone(context) ? ShowForDurationSchedule.showForDays(7) : NEVER); put(Event.RESEARCH, shouldShowResearchMegaphone(context) ? ShowForDurationSchedule.showForDays(7) : NEVER);
put(Event.DONATE, shouldShowDonateMegaphone(context) ? ShowForDurationSchedule.showForDays(7) : NEVER); put(Event.DONATE, shouldShowDonateMegaphone(context) ? ShowForDurationSchedule.showForDays(7) : NEVER);
put(Event.GROUP_CALLING, shouldShowGroupCallingMegaphone() ? ALWAYS : NEVER);
}}; }};
} }
@ -113,6 +114,8 @@ public final class Megaphones {
return buildResearchMegaphone(context); return buildResearchMegaphone(context);
case DONATE: case DONATE:
return buildDonateMegaphone(context); return buildDonateMegaphone(context);
case GROUP_CALLING:
return buildGroupCallingMegaphone(context);
default: default:
throw new IllegalArgumentException("Event not handled!"); throw new IllegalArgumentException("Event not handled!");
} }
@ -239,6 +242,19 @@ public final class Megaphones {
.build(); .build();
} }
private static @NonNull Megaphone buildGroupCallingMegaphone(@NonNull Context context) {
return new Megaphone.Builder(Event.GROUP_CALLING, Megaphone.Style.BASIC)
.disableSnooze()
.setTitle(R.string.GroupCallingMegaphone__introducing_group_calls)
.setBody(R.string.GroupCallingMegaphone__open_a_new_group_to_start)
.setImage(R.drawable.ic_group_calls_megaphone)
.setActionButton(android.R.string.ok, (megaphone, controller) -> {
controller.onMegaphoneCompleted(megaphone.getEvent());
})
.setPriority(Megaphone.Priority.DEFAULT)
.build();
}
private static boolean shouldShowMessageRequestsMegaphone() { private static boolean shouldShowMessageRequestsMegaphone() {
return Recipient.self().getProfileName() == ProfileName.EMPTY; return Recipient.self().getProfileName() == ProfileName.EMPTY;
} }
@ -255,6 +271,10 @@ public final class Megaphones {
return TextSecurePreferences.wereLinkPreviewsEnabled(context) && !SignalStore.settings().isLinkPreviewsEnabled(); return TextSecurePreferences.wereLinkPreviewsEnabled(context) && !SignalStore.settings().isLinkPreviewsEnabled();
} }
private static boolean shouldShowGroupCallingMegaphone() {
return FeatureFlags.groupCalling();
}
public enum Event { public enum Event {
REACTIONS("reactions"), REACTIONS("reactions"),
PINS_FOR_ALL("pins_for_all"), PINS_FOR_ALL("pins_for_all"),
@ -263,7 +283,8 @@ public final class Megaphones {
LINK_PREVIEWS("link_previews"), LINK_PREVIEWS("link_previews"),
CLIENT_DEPRECATED("client_deprecated"), CLIENT_DEPRECATED("client_deprecated"),
RESEARCH("research"), RESEARCH("research"),
DONATE("donate"); DONATE("donate"),
GROUP_CALLING("group_calling");
private final String key; private final String key;

View file

@ -15,6 +15,7 @@ import org.thoughtcrime.securesms.components.webrtc.BroadcastVideoSink;
import org.thoughtcrime.securesms.events.CallParticipant; import org.thoughtcrime.securesms.events.CallParticipant;
import org.thoughtcrime.securesms.events.CallParticipantId; import org.thoughtcrime.securesms.events.CallParticipantId;
import org.thoughtcrime.securesms.events.WebRtcViewModel; import org.thoughtcrime.securesms.events.WebRtcViewModel;
import org.thoughtcrime.securesms.keyvalue.SignalStore;
import org.thoughtcrime.securesms.recipients.Recipient; import org.thoughtcrime.securesms.recipients.Recipient;
import org.thoughtcrime.securesms.ringrtc.RemotePeer; import org.thoughtcrime.securesms.ringrtc.RemotePeer;
import org.thoughtcrime.securesms.service.webrtc.state.WebRtcServiceState; import org.thoughtcrime.securesms.service.webrtc.state.WebRtcServiceState;
@ -57,6 +58,7 @@ public class GroupPreJoinActionProcessor extends GroupActionProcessor {
return groupCallFailure(currentState, "Unable to connect to group call", e); return groupCallFailure(currentState, "Unable to connect to group call", e);
} }
SignalStore.tooltips().markGroupCallingLobbyEntered();
return currentState.builder() return currentState.builder()
.changeCallInfoState() .changeCallInfoState()
.groupCall(groupCall) .groupCall(groupCall)

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 13 KiB

View file

@ -3,6 +3,8 @@
<color name="white">@color/core_white</color> <color name="white">@color/core_white</color>
<color name="black">@color/core_black</color> <color name="black">@color/core_black</color>
<color name="signal_accent_green">#4CAF50</color>
<color name="transparent_black_05">#0D000000</color> <color name="transparent_black_05">#0D000000</color>
<color name="transparent_black_10">#18000000</color> <color name="transparent_black_10">#18000000</color>
<color name="transparent_black_15">#26000000</color> <color name="transparent_black_15">#26000000</color>

View file

@ -243,6 +243,7 @@
<string name="ConversationActivity_recipient_is_not_a_valid_sms_or_email_address_exclamation">Recipient is not a valid SMS or email address!</string> <string name="ConversationActivity_recipient_is_not_a_valid_sms_or_email_address_exclamation">Recipient is not a valid SMS or email address!</string>
<string name="ConversationActivity_message_is_empty_exclamation">Message is empty!</string> <string name="ConversationActivity_message_is_empty_exclamation">Message is empty!</string>
<string name="ConversationActivity_group_members">Group members</string> <string name="ConversationActivity_group_members">Group members</string>
<string name="ConversationActivity__tap_here_to_start_a_group_call">Tap here to start a group call</string>
<string name="ConversationActivity_invalid_recipient">Invalid recipient!</string> <string name="ConversationActivity_invalid_recipient">Invalid recipient!</string>
<string name="ConversationActivity_added_to_home_screen">Added to home screen</string> <string name="ConversationActivity_added_to_home_screen">Added to home screen</string>
@ -484,6 +485,10 @@
<string name="DonateMegaphone_donate">Donate</string> <string name="DonateMegaphone_donate">Donate</string>
<string name="DonateMegaphone_no_thanks">No Thanks</string> <string name="DonateMegaphone_no_thanks">No Thanks</string>
<!-- GroupCallingMegaphone -->
<string name="GroupCallingMegaphone__introducing_group_calls">Introducing Group Calls</string>
<string name="GroupCallingMegaphone__open_a_new_group_to_start">Open a New Group to start a free encrypted group call</string>
<!-- DozeReminder --> <!-- DozeReminder -->
<string name="DozeReminder_optimize_for_missing_play_services">Optimize for missing Play Services</string> <string name="DozeReminder_optimize_for_missing_play_services">Optimize for missing Play Services</string>
<string name="DozeReminder_this_device_does_not_support_play_services_tap_to_disable_system_battery">This device does not support Play Services. Tap to disable system battery optimizations that prevent Signal from retrieving messages while inactive.</string> <string name="DozeReminder_this_device_does_not_support_play_services_tap_to_disable_system_battery">This device does not support Play Services. Tap to disable system battery optimizations that prevent Signal from retrieving messages while inactive.</string>