kopia lustrzana https://github.com/ryukoposting/Signal-Android
Add tooltip to opt-out of bubbles.
rodzic
63c98e92f2
commit
b6f84dfa16
|
@ -0,0 +1,16 @@
|
||||||
|
package org.thoughtcrime.securesms.components.reminder
|
||||||
|
|
||||||
|
import android.content.Context
|
||||||
|
import org.thoughtcrime.securesms.R
|
||||||
|
|
||||||
|
class BubbleOptOutReminder(context: Context) : Reminder(null, context.getString(R.string.BubbleOptOutTooltip__description)) {
|
||||||
|
|
||||||
|
init {
|
||||||
|
addAction(Action(context.getString(R.string.BubbleOptOutTooltip__turn_off), R.id.reminder_action_turn_off))
|
||||||
|
addAction(Action(context.getString(R.string.BubbleOptOutTooltip__not_now), R.id.reminder_action_not_now))
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun isDismissable(): Boolean {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,11 +1,14 @@
|
||||||
package org.thoughtcrime.securesms.components.reminder;
|
package org.thoughtcrime.securesms.components.reminder;
|
||||||
|
|
||||||
|
import android.content.Context;
|
||||||
import android.view.LayoutInflater;
|
import android.view.LayoutInflater;
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
import android.view.ViewGroup;
|
import android.view.ViewGroup;
|
||||||
import android.widget.Button;
|
import android.widget.Button;
|
||||||
|
import android.widget.TextView;
|
||||||
|
|
||||||
import androidx.annotation.NonNull;
|
import androidx.annotation.NonNull;
|
||||||
|
import androidx.core.content.ContextCompat;
|
||||||
import androidx.recyclerview.widget.RecyclerView;
|
import androidx.recyclerview.widget.RecyclerView;
|
||||||
|
|
||||||
import org.thoughtcrime.securesms.R;
|
import org.thoughtcrime.securesms.R;
|
||||||
|
@ -15,10 +18,12 @@ import java.util.List;
|
||||||
|
|
||||||
final class ReminderActionsAdapter extends RecyclerView.Adapter<ReminderActionsAdapter.ActionViewHolder> {
|
final class ReminderActionsAdapter extends RecyclerView.Adapter<ReminderActionsAdapter.ActionViewHolder> {
|
||||||
|
|
||||||
|
private final Reminder.Importance importance;
|
||||||
private final List<Reminder.Action> actions;
|
private final List<Reminder.Action> actions;
|
||||||
private final ReminderView.OnActionClickListener actionClickListener;
|
private final ReminderView.OnActionClickListener actionClickListener;
|
||||||
|
|
||||||
ReminderActionsAdapter(List<Reminder.Action> actions, ReminderView.OnActionClickListener actionClickListener) {
|
ReminderActionsAdapter(Reminder.Importance importance, List<Reminder.Action> actions, ReminderView.OnActionClickListener actionClickListener) {
|
||||||
|
this.importance = importance;
|
||||||
this.actions = Collections.unmodifiableList(actions);
|
this.actions = Collections.unmodifiableList(actions);
|
||||||
this.actionClickListener = actionClickListener;
|
this.actionClickListener = actionClickListener;
|
||||||
}
|
}
|
||||||
|
@ -26,7 +31,14 @@ final class ReminderActionsAdapter extends RecyclerView.Adapter<ReminderActionsA
|
||||||
@NonNull
|
@NonNull
|
||||||
@Override
|
@Override
|
||||||
public ActionViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
|
public ActionViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
|
||||||
return new ActionViewHolder(LayoutInflater.from(parent.getContext()).inflate(R.layout.reminder_action_button, parent, false));
|
Context context = parent.getContext();
|
||||||
|
TextView button = ((TextView) LayoutInflater.from(context).inflate(R.layout.reminder_action_button, parent, false));
|
||||||
|
|
||||||
|
if (importance == Reminder.Importance.NORMAL) {
|
||||||
|
button.setTextColor(ContextCompat.getColor(context, R.color.signal_accent_primary));
|
||||||
|
}
|
||||||
|
|
||||||
|
return new ActionViewHolder(button);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -17,6 +17,7 @@ import androidx.annotation.Nullable;
|
||||||
import androidx.core.content.ContextCompat;
|
import androidx.core.content.ContextCompat;
|
||||||
import androidx.recyclerview.widget.RecyclerView;
|
import androidx.recyclerview.widget.RecyclerView;
|
||||||
|
|
||||||
|
import org.signal.core.util.DimensionUnit;
|
||||||
import org.thoughtcrime.securesms.R;
|
import org.thoughtcrime.securesms.R;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
@ -28,6 +29,7 @@ public final class ReminderView extends FrameLayout {
|
||||||
private ProgressBar progressBar;
|
private ProgressBar progressBar;
|
||||||
private TextView progressText;
|
private TextView progressText;
|
||||||
private ViewGroup container;
|
private ViewGroup container;
|
||||||
|
private View background;
|
||||||
private ImageButton closeButton;
|
private ImageButton closeButton;
|
||||||
private TextView title;
|
private TextView title;
|
||||||
private TextView text;
|
private TextView text;
|
||||||
|
@ -56,6 +58,7 @@ public final class ReminderView extends FrameLayout {
|
||||||
progressBar = findViewById(R.id.reminder_progress);
|
progressBar = findViewById(R.id.reminder_progress);
|
||||||
progressText = findViewById(R.id.reminder_progress_text);
|
progressText = findViewById(R.id.reminder_progress_text);
|
||||||
container = findViewById(R.id.container);
|
container = findViewById(R.id.container);
|
||||||
|
background = findViewById(R.id.background);
|
||||||
closeButton = findViewById(R.id.cancel);
|
closeButton = findViewById(R.id.cancel);
|
||||||
title = findViewById(R.id.reminder_title);
|
title = findViewById(R.id.reminder_title);
|
||||||
text = findViewById(R.id.reminder_text);
|
text = findViewById(R.id.reminder_text);
|
||||||
|
@ -79,24 +82,30 @@ public final class ReminderView extends FrameLayout {
|
||||||
}
|
}
|
||||||
|
|
||||||
text.setText(reminder.getText());
|
text.setText(reminder.getText());
|
||||||
text.setTextColor(ContextCompat.getColor(getContext(), R.color.signal_button_primary_text));
|
|
||||||
|
|
||||||
switch (reminder.getImportance()) {
|
switch (reminder.getImportance()) {
|
||||||
case NORMAL:
|
case NORMAL:
|
||||||
container.setBackgroundResource(R.drawable.reminder_background_normal);
|
background.setBackgroundResource(R.drawable.reminder_background_normal);
|
||||||
|
title.setTextColor(ContextCompat.getColor(getContext(), R.color.signal_text_primary));
|
||||||
|
text.setTextColor(ContextCompat.getColor(getContext(), R.color.signal_text_primary));
|
||||||
break;
|
break;
|
||||||
case ERROR:
|
case ERROR:
|
||||||
container.setBackgroundResource(R.drawable.reminder_background_error);
|
background.setBackgroundResource(R.drawable.reminder_background_error);
|
||||||
|
title.setTextColor(ContextCompat.getColor(getContext(), R.color.core_black));
|
||||||
text.setTextColor(ContextCompat.getColor(getContext(), R.color.core_black));
|
text.setTextColor(ContextCompat.getColor(getContext(), R.color.core_black));
|
||||||
break;
|
break;
|
||||||
case TERMINAL:
|
case TERMINAL:
|
||||||
container.setBackgroundResource(R.drawable.reminder_background_terminal);
|
background.setBackgroundResource(R.drawable.reminder_background_terminal);
|
||||||
|
title.setTextColor(ContextCompat.getColor(getContext(), R.color.signal_button_primary_text));
|
||||||
|
text.setTextColor(ContextCompat.getColor(getContext(), R.color.signal_button_primary_text));
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
throw new IllegalStateException();
|
throw new IllegalStateException();
|
||||||
}
|
}
|
||||||
|
|
||||||
setOnClickListener(reminder.getOkListener());
|
if (reminder.getOkListener() != null) {
|
||||||
|
setOnClickListener(reminder.getOkListener());
|
||||||
|
}
|
||||||
|
|
||||||
closeButton.setVisibility(reminder.isDismissable() ? View.VISIBLE : View.GONE);
|
closeButton.setVisibility(reminder.isDismissable() ? View.VISIBLE : View.GONE);
|
||||||
closeButton.setOnClickListener(new OnClickListener() {
|
closeButton.setOnClickListener(new OnClickListener() {
|
||||||
|
@ -121,10 +130,12 @@ public final class ReminderView extends FrameLayout {
|
||||||
|
|
||||||
List<Reminder.Action> actions = reminder.getActions();
|
List<Reminder.Action> actions = reminder.getActions();
|
||||||
if (actions.isEmpty()) {
|
if (actions.isEmpty()) {
|
||||||
|
text.setPadding(0, 0, 0, ((int) DimensionUnit.DP.toPixels(16f)));
|
||||||
actionsRecycler.setVisibility(GONE);
|
actionsRecycler.setVisibility(GONE);
|
||||||
} else {
|
} else {
|
||||||
|
text.setPadding(0, 0, 0, 0);
|
||||||
actionsRecycler.setVisibility(VISIBLE);
|
actionsRecycler.setVisibility(VISIBLE);
|
||||||
actionsRecycler.setAdapter(new ReminderActionsAdapter(actions, this::handleActionClicked));
|
actionsRecycler.setAdapter(new ReminderActionsAdapter(reminder.getImportance(), actions, this::handleActionClicked));
|
||||||
}
|
}
|
||||||
|
|
||||||
container.setVisibility(View.VISIBLE);
|
container.setVisibility(View.VISIBLE);
|
||||||
|
|
|
@ -38,6 +38,7 @@ import android.os.Bundle;
|
||||||
import android.os.Vibrator;
|
import android.os.Vibrator;
|
||||||
import android.provider.Browser;
|
import android.provider.Browser;
|
||||||
import android.provider.ContactsContract;
|
import android.provider.ContactsContract;
|
||||||
|
import android.provider.Settings;
|
||||||
import android.text.Editable;
|
import android.text.Editable;
|
||||||
import android.text.Spannable;
|
import android.text.Spannable;
|
||||||
import android.text.SpannableString;
|
import android.text.SpannableString;
|
||||||
|
@ -124,6 +125,7 @@ import org.thoughtcrime.securesms.components.emoji.MediaKeyboard;
|
||||||
import org.thoughtcrime.securesms.components.identity.UnverifiedBannerView;
|
import org.thoughtcrime.securesms.components.identity.UnverifiedBannerView;
|
||||||
import org.thoughtcrime.securesms.components.location.SignalPlace;
|
import org.thoughtcrime.securesms.components.location.SignalPlace;
|
||||||
import org.thoughtcrime.securesms.components.mention.MentionAnnotation;
|
import org.thoughtcrime.securesms.components.mention.MentionAnnotation;
|
||||||
|
import org.thoughtcrime.securesms.components.reminder.BubbleOptOutReminder;
|
||||||
import org.thoughtcrime.securesms.components.reminder.ExpiredBuildReminder;
|
import org.thoughtcrime.securesms.components.reminder.ExpiredBuildReminder;
|
||||||
import org.thoughtcrime.securesms.components.reminder.GroupsV1MigrationSuggestionsReminder;
|
import org.thoughtcrime.securesms.components.reminder.GroupsV1MigrationSuggestionsReminder;
|
||||||
import org.thoughtcrime.securesms.components.reminder.PendingGroupJoinRequestsReminder;
|
import org.thoughtcrime.securesms.components.reminder.PendingGroupJoinRequestsReminder;
|
||||||
|
@ -1874,6 +1876,19 @@ public class ConversationActivity extends PassphraseRequiredActivity
|
||||||
});
|
});
|
||||||
reminderView.get().setOnDismissListener(() -> {
|
reminderView.get().setOnDismissListener(() -> {
|
||||||
});
|
});
|
||||||
|
} else if (isInBubble() && !SignalStore.tooltips().hasSeenBubbleOptOutTooltip() && Build.VERSION.SDK_INT > 29) {
|
||||||
|
reminderView.get().showReminder(new BubbleOptOutReminder(this));
|
||||||
|
reminderView.get().setOnActionClickListener(actionId -> {
|
||||||
|
SignalStore.tooltips().markBubbleOptOutTooltipSeen();
|
||||||
|
reminderView.get().hide();
|
||||||
|
|
||||||
|
if (actionId == R.id.reminder_action_turn_off) {
|
||||||
|
Intent intent = new Intent(Settings.ACTION_APP_NOTIFICATION_BUBBLE_SETTINGS)
|
||||||
|
.putExtra(Settings.EXTRA_APP_PACKAGE, getPackageName())
|
||||||
|
.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
|
||||||
|
startActivity(intent);
|
||||||
|
}
|
||||||
|
});
|
||||||
} else if (reminderView.resolved()) {
|
} else if (reminderView.resolved()) {
|
||||||
reminderView.get().hide();
|
reminderView.get().hide();
|
||||||
}
|
}
|
||||||
|
|
|
@ -13,6 +13,7 @@ public class TooltipValues extends SignalStoreValues {
|
||||||
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";
|
private static final String GROUP_CALL_TOOLTIP_DISPLAY_COUNT = "tooltip.group_call_tooltip_display_count";
|
||||||
private static final String MULTI_FORWARD_DIALOG = "tooltip.multi.forward.dialog";
|
private static final String MULTI_FORWARD_DIALOG = "tooltip.multi.forward.dialog";
|
||||||
|
private static final String BUBBLE_OPT_OUT = "tooltip.bubble.opt.out";
|
||||||
|
|
||||||
|
|
||||||
TooltipValues(@NonNull KeyValueStore store) {
|
TooltipValues(@NonNull KeyValueStore store) {
|
||||||
|
@ -64,4 +65,12 @@ public class TooltipValues extends SignalStoreValues {
|
||||||
public void markMultiForwardDialogSeen() {
|
public void markMultiForwardDialogSeen() {
|
||||||
putBoolean(MULTI_FORWARD_DIALOG, false);
|
putBoolean(MULTI_FORWARD_DIALOG, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public boolean hasSeenBubbleOptOutTooltip() {
|
||||||
|
return getBoolean(BUBBLE_OPT_OUT, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void markBubbleOptOutTooltipSeen() {
|
||||||
|
putBoolean(BUBBLE_OPT_OUT, true);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<selector xmlns:android="http://schemas.android.com/apk/res/android">
|
<selector xmlns:android="http://schemas.android.com/apk/res/android">
|
||||||
<item android:state_pressed="true" android:drawable="@color/core_ultramarine_dark" />
|
<item android:state_pressed="true" android:drawable="@color/signal_background_secondary" />
|
||||||
<item android:state_focused="true" android:drawable="@color/core_ultramarine" />
|
<item android:state_focused="true" android:drawable="@color/signal_background_tertiary" />
|
||||||
<item android:drawable="@color/core_ultramarine" />
|
<item android:drawable="@color/signal_background_tertiary" />
|
||||||
</selector>
|
</selector>
|
||||||
|
|
|
@ -239,7 +239,6 @@
|
||||||
android:inflatedId="@+id/review_banner"
|
android:inflatedId="@+id/review_banner"
|
||||||
android:layout="@layout/review_banner_view" />
|
android:layout="@layout/review_banner_view" />
|
||||||
|
|
||||||
|
|
||||||
</LinearLayout>
|
</LinearLayout>
|
||||||
|
|
||||||
<View
|
<View
|
||||||
|
|
|
@ -4,6 +4,7 @@
|
||||||
style="@style/Widget.AppCompat.Button.Borderless"
|
style="@style/Widget.AppCompat.Button.Borderless"
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="match_parent"
|
android:layout_height="match_parent"
|
||||||
|
android:textAllCaps="false"
|
||||||
android:textColor="@color/white"
|
android:textColor="@color/white"
|
||||||
android:textSize="14sp"
|
android:textSize="14sp"
|
||||||
android:paddingStart="16dp"
|
android:paddingStart="16dp"
|
||||||
|
|
|
@ -5,13 +5,19 @@
|
||||||
android:id="@+id/container"
|
android:id="@+id/container"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:background="@drawable/reminder_background_normal"
|
|
||||||
android:focusable="true"
|
android:focusable="true"
|
||||||
android:nextFocusRight="@+id/cancel"
|
android:nextFocusRight="@+id/cancel"
|
||||||
android:orientation="horizontal"
|
|
||||||
android:visibility="gone"
|
android:visibility="gone"
|
||||||
tools:visibility="visible">
|
tools:visibility="visible">
|
||||||
|
|
||||||
|
<View
|
||||||
|
android:id="@+id/background"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="0dp"
|
||||||
|
android:background="@drawable/reminder_background_normal"
|
||||||
|
app:layout_constraintTop_toTopOf="parent"
|
||||||
|
app:layout_constraintBottom_toBottomOf="@id/reminder_actions" />
|
||||||
|
|
||||||
<ProgressBar
|
<ProgressBar
|
||||||
android:id="@+id/reminder_progress"
|
android:id="@+id/reminder_progress"
|
||||||
style="@style/Widget.ProgressBar.Horizontal"
|
style="@style/Widget.ProgressBar.Horizontal"
|
||||||
|
@ -105,11 +111,17 @@
|
||||||
android:visibility="gone"
|
android:visibility="gone"
|
||||||
tools:visibility="visible"
|
tools:visibility="visible"
|
||||||
app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager"
|
app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager"
|
||||||
app:layout_constraintBottom_toBottomOf="parent"
|
app:layout_constraintTop_toBottomOf="@id/reminder_text"
|
||||||
app:layout_constraintEnd_toEndOf="parent"
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
app:layout_constraintStart_toStartOf="parent"
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
app:reverseLayout="true"
|
app:reverseLayout="true"
|
||||||
tools:itemCount="2"
|
tools:itemCount="2"
|
||||||
tools:listitem="@layout/reminder_action_button" />
|
tools:listitem="@layout/reminder_action_button" />
|
||||||
|
|
||||||
|
<View
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="5dp"
|
||||||
|
android:background="@drawable/toolbar_shadow"
|
||||||
|
app:layout_constraintTop_toBottomOf="@id/background" />
|
||||||
|
|
||||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||||
|
|
|
@ -12,6 +12,9 @@
|
||||||
<item name="reminder_action_gv1_suggestion_no_thanks" type="id" />
|
<item name="reminder_action_gv1_suggestion_no_thanks" type="id" />
|
||||||
<item name="reminder_action_gv1_suggestion_add_members" type="id" />
|
<item name="reminder_action_gv1_suggestion_add_members" type="id" />
|
||||||
|
|
||||||
|
<item name="reminder_action_not_now" type="id" />
|
||||||
|
<item name="reminder_action_turn_off" type="id" />
|
||||||
|
|
||||||
<item name="status_bar_guideline" type="id" />
|
<item name="status_bar_guideline" type="id" />
|
||||||
<item name="navigation_bar_guideline" type="id" />
|
<item name="navigation_bar_guideline" type="id" />
|
||||||
</resources>
|
</resources>
|
||||||
|
|
|
@ -2024,6 +2024,14 @@
|
||||||
<!-- conversation_fragment -->
|
<!-- conversation_fragment -->
|
||||||
<string name="conversation_fragment__scroll_to_the_bottom_content_description">Scroll to the bottom</string>
|
<string name="conversation_fragment__scroll_to_the_bottom_content_description">Scroll to the bottom</string>
|
||||||
|
|
||||||
|
<!-- BubbleOptOutTooltip -->
|
||||||
|
<!-- Message to inform the user of what Android chat bubbles are -->
|
||||||
|
<string name="BubbleOptOutTooltip__description">Bubbles are an Android feature that you can turn off for Signal chats.</string>
|
||||||
|
<!-- Button to dismiss the tooltip for opting out of using Android bubbles -->
|
||||||
|
<string name="BubbleOptOutTooltip__not_now">Not now</string>
|
||||||
|
<!-- Button to move to the system settings to control the use of Android bubbles -->
|
||||||
|
<string name="BubbleOptOutTooltip__turn_off">Turn off</string>
|
||||||
|
|
||||||
<!-- safety_number_change_dialog -->
|
<!-- safety_number_change_dialog -->
|
||||||
<string name="safety_number_change_dialog__safety_number_changes">Safety Number Changes</string>
|
<string name="safety_number_change_dialog__safety_number_changes">Safety Number Changes</string>
|
||||||
<string name="safety_number_change_dialog__accept">Accept</string>
|
<string name="safety_number_change_dialog__accept">Accept</string>
|
||||||
|
|
Ładowanie…
Reference in New Issue