Update link preview settings and add some UI polish.

master
Greyson Parrelli 2020-08-13 13:50:38 -04:00
parent 676356e800
commit ace1b8ee71
20 changed files with 336 additions and 37 deletions

View File

@ -236,6 +236,11 @@ public class InputPanel extends LinearLayout
this.linkPreview.setLoading();
}
public void setLinkPreviewNoPreview() {
this.linkPreview.setVisibility(View.VISIBLE);
this.linkPreview.setNoPreview();
}
public void setLinkPreview(@NonNull GlideRequests glideRequests, @NonNull Optional<LinkPreview> preview) {
if (preview.isPresent()) {
this.linkPreview.setVisibility(View.VISIBLE);

View File

@ -21,6 +21,9 @@ import org.thoughtcrime.securesms.util.ThemeUtil;
import okhttp3.HttpUrl;
/**
* The view shown in the compose box that represents the state of the link preview.
*/
public class LinkPreviewView extends FrameLayout {
private static final int TYPE_CONVERSATION = 0;
@ -33,6 +36,7 @@ public class LinkPreviewView extends FrameLayout {
private View divider;
private View closeButton;
private View spinner;
private View noPreview;
private int type;
private int defaultRadius;
@ -60,6 +64,7 @@ public class LinkPreviewView extends FrameLayout {
divider = findViewById(R.id.linkpreview_divider);
spinner = findViewById(R.id.linkpreview_progress_wheel);
closeButton = findViewById(R.id.linkpreview_close);
noPreview = findViewById(R.id.linkpreview_no_preview);
defaultRadius = getResources().getDimensionPixelSize(R.dimen.thumbnail_default_radius);
cornerMask = new CornerMask(this);
outliner = new Outliner();
@ -102,6 +107,15 @@ public class LinkPreviewView extends FrameLayout {
site.setVisibility(GONE);
thumbnail.setVisibility(GONE);
spinner.setVisibility(VISIBLE);
noPreview.setVisibility(INVISIBLE);
}
public void setNoPreview() {
title.setVisibility(GONE);
site.setVisibility(GONE);
thumbnail.setVisibility(GONE);
spinner.setVisibility(GONE);
noPreview.setVisibility(VISIBLE);
}
public void setLinkPreview(@NonNull GlideRequests glideRequests, @NonNull LinkPreview linkPreview, boolean showThumbnail) {
@ -109,6 +123,7 @@ public class LinkPreviewView extends FrameLayout {
site.setVisibility(VISIBLE);
thumbnail.setVisibility(VISIBLE);
spinner.setVisibility(GONE);
noPreview.setVisibility(GONE);
title.setText(linkPreview.getTitle());

View File

@ -1820,7 +1820,7 @@ public class ConversationActivity extends PassphraseRequiredActivity
private void initializeLinkPreviewObserver() {
linkPreviewViewModel = ViewModelProviders.of(this, new LinkPreviewViewModel.Factory(new LinkPreviewRepository())).get(LinkPreviewViewModel.class);
if (!TextSecurePreferences.isLinkPreviewsEnabled(this)) {
if (!SignalStore.settings().isLinkPreviewsEnabled()) {
linkPreviewViewModel.onUserCancel();
return;
}
@ -1831,6 +1831,9 @@ public class ConversationActivity extends PassphraseRequiredActivity
if (previewState.isLoading()) {
Log.d(TAG, "Loading link preview.");
inputPanel.setLinkPreviewLoading();
} else if (previewState.hasLinks() && !previewState.getLinkPreview().isPresent()) {
Log.d(TAG, "No preview found.");
inputPanel.setLinkPreviewNoPreview();
} else {
Log.d(TAG, "Setting link preview: " + previewState.getLinkPreview().isPresent());
inputPanel.setLinkPreview(glideRequests, previewState.getLinkPreview());
@ -2591,7 +2594,7 @@ public class ConversationActivity extends PassphraseRequiredActivity
buttonToggle.display(sendButton);
quickAttachmentToggle.hide();
if (!attachmentManager.isAttachmentPresent() && !linkPreviewViewModel.hasLinkPreview()) {
if (!attachmentManager.isAttachmentPresent() && !linkPreviewViewModel.hasLinkPreviewUi()) {
inlineAttachmentToggle.show();
} else {
inlineAttachmentToggle.hide();
@ -2600,7 +2603,7 @@ public class ConversationActivity extends PassphraseRequiredActivity
}
private void updateLinkPreviewState() {
if (TextSecurePreferences.isLinkPreviewsEnabled(this) && !sendButton.getSelectedTransport().isSms() && !attachmentManager.isAttachmentPresent()) {
if (SignalStore.settings().isLinkPreviewsEnabled() && !sendButton.getSelectedTransport().isSms() && !attachmentManager.isAttachmentPresent()) {
linkPreviewViewModel.onEnabled();
linkPreviewViewModel.onTextChanged(this, composeText.getTextTrimmed().toString(), composeText.getSelectionStart(), composeText.getSelectionEnd());
} else {

View File

@ -58,6 +58,7 @@ import org.thoughtcrime.securesms.jobmanager.Data;
import org.thoughtcrime.securesms.jobmanager.Job;
import org.thoughtcrime.securesms.jobmanager.JobManager;
import org.thoughtcrime.securesms.jobmanager.impl.NetworkConstraint;
import org.thoughtcrime.securesms.keyvalue.SignalStore;
import org.thoughtcrime.securesms.linkpreview.Link;
import org.thoughtcrime.securesms.linkpreview.LinkPreview;
import org.thoughtcrime.securesms.linkpreview.LinkPreviewUtil;
@ -830,7 +831,7 @@ public final class PushProcessMessageJob extends BaseJob {
}
if (configurationMessage.getLinkPreviews().isPresent()) {
TextSecurePreferences.setLinkPreviewsEnabled(context, configurationMessage.getReadReceipts().get());
SignalStore.settings().setLinkPreviewsEnabled(configurationMessage.getReadReceipts().get());
}
}
@ -966,7 +967,7 @@ public final class PushProcessMessageJob extends BaseJob {
ApplicationDependencies.getJobManager().add(new MultiDeviceConfigurationUpdateJob(TextSecurePreferences.isReadReceiptsEnabled(context),
TextSecurePreferences.isTypingIndicatorsEnabled(context),
TextSecurePreferences.isShowUnidentifiedDeliveryIndicatorsEnabled(context),
TextSecurePreferences.isLinkPreviewsEnabled(context)));
SignalStore.settings().isLinkPreviewsEnabled()));
ApplicationDependencies.getJobManager().add(new MultiDeviceStickerPackSyncJob());
}
@ -1692,7 +1693,7 @@ public final class PushProcessMessageJob extends BaseJob {
Optional<String> url = Optional.fromNullable(preview.getUrl());
Optional<String> title = Optional.fromNullable(preview.getTitle());
boolean hasContent = !TextUtils.isEmpty(title.or("")) || thumbnail.isPresent();
boolean presentInBody = url.isPresent() && Stream.of(LinkPreviewUtil.findWhitelistedUrls(message)).map(Link::getUrl).collect(Collectors.toSet()).contains(url.get());
boolean presentInBody = url.isPresent() && Stream.of(LinkPreviewUtil.findValidPreviewUrls(message)).map(Link::getUrl).collect(Collectors.toSet()).contains(url.get());
boolean validDomain = url.isPresent() && LinkPreviewUtil.isValidPreviewUrl(url.get());
if (hasContent && presentInBody && validDomain) {

View File

@ -0,0 +1,27 @@
package org.thoughtcrime.securesms.keyvalue;
import androidx.annotation.NonNull;
public final class SettingsValues extends SignalStoreValues {
public static final String LINK_PREVIEWS = "settings.link_previews";
SettingsValues(@NonNull KeyValueStore store) {
super(store);
}
@Override
void onFirstEverAppLaunch() {
getStore().beginWrite()
.putBoolean(LINK_PREVIEWS, true)
.apply();
}
public boolean isLinkPreviewsEnabled() {
return getBoolean(LINK_PREVIEWS, false);
}
public void setLinkPreviewsEnabled(boolean enabled) {
putBoolean(LINK_PREVIEWS, enabled);
}
}

View File

@ -24,6 +24,7 @@ public final class SignalStore {
private final MiscellaneousValues misc;
private final InternalValues internalValues;
private final EmojiValues emojiValues;
private final SettingsValues settingsValues;
private SignalStore() {
this.store = ApplicationDependencies.getKeyValueStore();
@ -37,6 +38,7 @@ public final class SignalStore {
this.misc = new MiscellaneousValues(store);
this.internalValues = new InternalValues(store);
this.emojiValues = new EmojiValues(store);
this.settingsValues = new SettingsValues(store);
}
public static void onFirstEverAppLaunch() {
@ -49,6 +51,7 @@ public final class SignalStore {
tooltips().onFirstEverAppLaunch();
misc().onFirstEverAppLaunch();
internalValues().onFirstEverAppLaunch();
settings().onFirstEverAppLaunch();
}
public static @NonNull KbsValues kbsValues() {
@ -91,6 +94,10 @@ public final class SignalStore {
return INSTANCE.emojiValues;
}
public static @NonNull SettingsValues settings() {
return INSTANCE.settingsValues;
}
public static @NonNull GroupsV2AuthorizationSignalStoreCache groupsV2AuthorizationCache() {
return new GroupsV2AuthorizationSignalStoreCache(getStore());
}

View File

@ -40,7 +40,7 @@ public final class LinkPreviewUtil {
/**
* @return All whitelisted URLs in the source text.
*/
public static @NonNull List<Link> findWhitelistedUrls(@NonNull String text) {
public static @NonNull List<Link> findValidPreviewUrls(@NonNull String text) {
SpannableString spannable = new SpannableString(text);
boolean found = Linkify.addLinks(spannable, Linkify.WEB_URLS);

View File

@ -41,6 +41,10 @@ public class LinkPreviewViewModel extends ViewModel {
return linkPreviewState.getValue() != null && linkPreviewState.getValue().getLinkPreview().isPresent();
}
public boolean hasLinkPreviewUi() {
return linkPreviewState.getValue() != null && linkPreviewState.getValue().hasContent();
}
public @NonNull List<LinkPreview> getActiveLinkPreviews() {
final LinkPreviewState state = linkPreviewState.getValue();
@ -61,7 +65,7 @@ public class LinkPreviewViewModel extends ViewModel {
return;
}
List<Link> links = LinkPreviewUtil.findWhitelistedUrls(text);
List<Link> links = LinkPreviewUtil.findValidPreviewUrls(text);
Optional<Link> link = links.isEmpty() ? Optional.absent() : Optional.of(links.get(0));
if (link.isPresent() && link.get().getUrl().equals(activeUrl)) {
@ -75,7 +79,7 @@ public class LinkPreviewViewModel extends ViewModel {
if (!link.isPresent() || !isCursorPositionValid(text, link.get(), cursorStart, cursorEnd)) {
activeUrl = null;
linkPreviewState.setValue(LinkPreviewState.forEmpty());
linkPreviewState.setValue(LinkPreviewState.forNoLinks());
return;
}
@ -85,7 +89,11 @@ public class LinkPreviewViewModel extends ViewModel {
activeRequest = repository.getLinkPreview(context, link.get().getUrl(), lp -> {
Util.runOnMain(() -> {
if (!userCanceled) {
linkPreviewState.setValue(LinkPreviewState.forPreview(lp));
if (lp.isPresent()) {
linkPreviewState.setValue(LinkPreviewState.forPreview(lp.get()));
} else {
linkPreviewState.setValue(LinkPreviewState.forLinksWithNoPreview());
}
}
activeRequest = null;
});
@ -103,7 +111,7 @@ public class LinkPreviewViewModel extends ViewModel {
activeUrl = null;
debouncer.clear();
linkPreviewState.setValue(LinkPreviewState.forEmpty());
linkPreviewState.setValue(LinkPreviewState.forNoLinks());
}
public void onEnabled() {
@ -133,32 +141,46 @@ public class LinkPreviewViewModel extends ViewModel {
public static class LinkPreviewState {
private final boolean isLoading;
private final boolean hasLinks;
private final Optional<LinkPreview> linkPreview;
private LinkPreviewState(boolean isLoading, Optional<LinkPreview> linkPreview) {
private LinkPreviewState(boolean isLoading, boolean hasLinks, Optional<LinkPreview> linkPreview) {
this.isLoading = isLoading;
this.hasLinks = hasLinks;
this.linkPreview = linkPreview;
}
private static LinkPreviewState forLoading() {
return new LinkPreviewState(true, Optional.absent());
return new LinkPreviewState(true, false, Optional.absent());
}
private static LinkPreviewState forPreview(@NonNull Optional<LinkPreview> linkPreview) {
return new LinkPreviewState(false, linkPreview);
private static LinkPreviewState forPreview(@NonNull LinkPreview linkPreview) {
return new LinkPreviewState(false, true, Optional.of(linkPreview));
}
private static LinkPreviewState forEmpty() {
return new LinkPreviewState(false, Optional.absent());
private static LinkPreviewState forLinksWithNoPreview() {
return new LinkPreviewState(false, true, Optional.absent());
}
private static LinkPreviewState forNoLinks() {
return new LinkPreviewState(false, false, Optional.absent());
}
public boolean isLoading() {
return isLoading;
}
public boolean hasLinks() {
return hasLinks;
}
public Optional<LinkPreview> getLinkPreview() {
return linkPreview;
}
boolean hasContent() {
return isLoading || hasLinks;
}
}
public static class Factory extends ViewModelProvider.NewInstanceFactory {

View File

@ -0,0 +1,48 @@
package org.thoughtcrime.securesms.linkpreview;
import android.content.Context;
import android.util.AttributeSet;
import android.view.View;
import android.widget.FrameLayout;
import androidx.annotation.NonNull;
import org.thoughtcrime.securesms.R;
import org.thoughtcrime.securesms.keyvalue.SignalStore;
import org.thoughtcrime.securesms.megaphone.Megaphone;
import org.thoughtcrime.securesms.megaphone.MegaphoneActionController;
public class LinkPreviewsMegaphoneView extends FrameLayout {
private View yesButton;
private View noButton;
public LinkPreviewsMegaphoneView(Context context) {
super(context);
initialize(context);
}
public LinkPreviewsMegaphoneView(Context context, AttributeSet attrs) {
super(context, attrs);
initialize(context);
}
private void initialize(@NonNull Context context) {
inflate(context, R.layout.link_previews_megaphone, this);
this.yesButton = findViewById(R.id.linkpreview_megaphone_ok);
this.noButton = findViewById(R.id.linkpreview_megaphone_disable);
}
public void present(@NonNull Megaphone megaphone, @NonNull MegaphoneActionController listener) {
this.yesButton.setOnClickListener(v -> {
SignalStore.settings().setLinkPreviewsEnabled(true);
listener.onMegaphoneCompleted(megaphone.getEvent());
});
this.noButton.setOnClickListener(v -> {
SignalStore.settings().setLinkPreviewsEnabled(false);
listener.onMegaphoneCompleted(megaphone.getEvent());
});
}
}

View File

@ -172,6 +172,9 @@ public class Megaphone {
/** Specialized style for announcing reactions. */
REACTIONS,
/** Specialized style for announcing link previews. */
LINK_PREVIEWS,
/** Basic bottom of the screen megaphone with optional snooze and action buttons. */
BASIC,

View File

@ -6,6 +6,7 @@ import android.view.View;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import org.thoughtcrime.securesms.linkpreview.LinkPreviewsMegaphoneView;
import org.thoughtcrime.securesms.reactions.ReactionsMegaphoneView;
public class MegaphoneViewBuilder {
@ -21,6 +22,8 @@ public class MegaphoneViewBuilder {
return null;
case REACTIONS:
return buildReactionsMegaphone(context, megaphone, listener);
case LINK_PREVIEWS:
return buildLinkPreviewsMegaphone(context, megaphone, listener);
case POPUP:
return buildPopupMegaphone(context, megaphone, listener);
default:
@ -46,6 +49,15 @@ public class MegaphoneViewBuilder {
return view;
}
private static @NonNull View buildLinkPreviewsMegaphone(@NonNull Context context,
@NonNull Megaphone megaphone,
@NonNull MegaphoneActionController listener)
{
LinkPreviewsMegaphoneView view = new LinkPreviewsMegaphoneView(context);
view.present(megaphone, listener);
return view;
}
private static @NonNull View buildPopupMegaphone(@NonNull Context context,
@NonNull Megaphone megaphone,
@NonNull MegaphoneActionController listener)

View File

@ -91,6 +91,7 @@ public final class Megaphones {
put(Event.PIN_REMINDER, new SignalPinReminderSchedule());
put(Event.MESSAGE_REQUESTS, shouldShowMessageRequestsMegaphone() ? ALWAYS : NEVER);
put(Event.MENTIONS, shouldShowMentionsMegaphone() ? ALWAYS : NEVER);
put(Event.LINK_PREVIEWS, SignalStore.settings().isLinkPreviewsEnabled() ? NEVER : ALWAYS);
}};
}
@ -106,6 +107,8 @@ public final class Megaphones {
return buildMessageRequestsMegaphone(context);
case MENTIONS:
return buildMentionsMegaphone();
case LINK_PREVIEWS:
return buildLinkPreviewsMegaphone();
default:
throw new IllegalArgumentException("Event not handled!");
}
@ -196,6 +199,12 @@ public final class Megaphones {
.build();
}
private static @NonNull Megaphone buildLinkPreviewsMegaphone() {
return new Megaphone.Builder(Event.LINK_PREVIEWS, Megaphone.Style.LINK_PREVIEWS)
.setMandatory(true)
.build();
}
private static boolean shouldShowMessageRequestsMegaphone() {
return Recipient.self().getProfileName() == ProfileName.EMPTY;
}
@ -209,7 +218,8 @@ public final class Megaphones {
PINS_FOR_ALL("pins_for_all"),
PIN_REMINDER("pin_reminder"),
MESSAGE_REQUESTS("message_requests"),
MENTIONS("mentions");
MENTIONS("mentions"),
LINK_PREVIEWS("link_previews");
private final String key;

View File

@ -38,12 +38,15 @@ import org.thoughtcrime.securesms.jobs.MultiDeviceConfigurationUpdateJob;
import org.thoughtcrime.securesms.jobs.RefreshAttributesJob;
import org.thoughtcrime.securesms.keyvalue.KbsValues;
import org.thoughtcrime.securesms.keyvalue.PinValues;
import org.thoughtcrime.securesms.keyvalue.SettingsValues;
import org.thoughtcrime.securesms.keyvalue.SignalStore;
import org.thoughtcrime.securesms.lock.PinHashing;
import org.thoughtcrime.securesms.lock.v2.CreateKbsPinActivity;
import org.thoughtcrime.securesms.lock.v2.KbsConstants;
import org.thoughtcrime.securesms.lock.v2.RegistrationLockUtil;
import org.thoughtcrime.securesms.logging.Log;
import org.thoughtcrime.securesms.megaphone.MegaphoneRepository;
import org.thoughtcrime.securesms.megaphone.Megaphones;
import org.thoughtcrime.securesms.pin.RegistrationLockV2Dialog;
import org.thoughtcrime.securesms.recipients.Recipient;
import org.thoughtcrime.securesms.service.KeyCachingService;
@ -90,13 +93,18 @@ public class AppProtectionPreferenceFragment extends CorrectedPreferenceFragment
this.findPreference(TextSecurePreferences.PASSPHRASE_TIMEOUT_INTERVAL_PREF).setOnPreferenceClickListener(new PassphraseIntervalClickListener());
this.findPreference(TextSecurePreferences.READ_RECEIPTS_PREF).setOnPreferenceChangeListener(new ReadReceiptToggleListener());
this.findPreference(TextSecurePreferences.TYPING_INDICATORS).setOnPreferenceChangeListener(new TypingIndicatorsToggleListener());
this.findPreference(TextSecurePreferences.LINK_PREVIEWS).setOnPreferenceChangeListener(new LinkPreviewToggleListener());
this.findPreference(PREFERENCE_CATEGORY_BLOCKED).setOnPreferenceClickListener(new BlockedContactsClickListener());
this.findPreference(TextSecurePreferences.SHOW_UNIDENTIFIED_DELIVERY_INDICATORS).setOnPreferenceChangeListener(new ShowUnidentifiedDeliveryIndicatorsChangedListener());
this.findPreference(TextSecurePreferences.UNIVERSAL_UNIDENTIFIED_ACCESS).setOnPreferenceChangeListener(new UniversalUnidentifiedAccessChangedListener());
this.findPreference(PREFERENCE_UNIDENTIFIED_LEARN_MORE).setOnPreferenceClickListener(new UnidentifiedLearnMoreClickListener());
disablePassphrase.setOnPreferenceChangeListener(new DisablePassphraseClickListener());
SwitchPreferenceCompat linkPreviewPref = (SwitchPreferenceCompat) this.findPreference(SettingsValues.LINK_PREVIEWS);
linkPreviewPref.setChecked(SignalStore.settings().isLinkPreviewsEnabled());
linkPreviewPref.setPreferenceDataStore(SignalStore.getPreferenceDataStore());
linkPreviewPref.setOnPreferenceChangeListener(new LinkPreviewToggleListener());
initializeVisibility();
}
@ -241,7 +249,7 @@ public class AppProtectionPreferenceFragment extends CorrectedPreferenceFragment
ApplicationDependencies.getJobManager().add(new MultiDeviceConfigurationUpdateJob(enabled,
TextSecurePreferences.isTypingIndicatorsEnabled(requireContext()),
TextSecurePreferences.isShowUnidentifiedDeliveryIndicatorsEnabled(getContext()),
TextSecurePreferences.isLinkPreviewsEnabled(getContext())));
SignalStore.settings().isLinkPreviewsEnabled()));
});
return true;
@ -258,7 +266,7 @@ public class AppProtectionPreferenceFragment extends CorrectedPreferenceFragment
ApplicationDependencies.getJobManager().add(new MultiDeviceConfigurationUpdateJob(TextSecurePreferences.isReadReceiptsEnabled(requireContext()),
enabled,
TextSecurePreferences.isShowUnidentifiedDeliveryIndicatorsEnabled(getContext()),
TextSecurePreferences.isLinkPreviewsEnabled(getContext())));
SignalStore.settings().isLinkPreviewsEnabled()));
if (!enabled) {
ApplicationContext.getInstance(requireContext()).getTypingStatusRepository().clear();
@ -279,6 +287,9 @@ public class AppProtectionPreferenceFragment extends CorrectedPreferenceFragment
TextSecurePreferences.isTypingIndicatorsEnabled(requireContext()),
TextSecurePreferences.isShowUnidentifiedDeliveryIndicatorsEnabled(requireContext()),
enabled));
if (enabled) {
ApplicationDependencies.getMegaphoneRepository().markFinished(Megaphones.Event.LINK_PREVIEWS);
}
});
return true;
}
@ -383,7 +394,7 @@ public class AppProtectionPreferenceFragment extends CorrectedPreferenceFragment
ApplicationDependencies.getJobManager().add(new MultiDeviceConfigurationUpdateJob(TextSecurePreferences.isReadReceiptsEnabled(getContext()),
TextSecurePreferences.isTypingIndicatorsEnabled(getContext()),
enabled,
TextSecurePreferences.isLinkPreviewsEnabled(getContext())));
SignalStore.settings().isLinkPreviewsEnabled()));
});
return true;

View File

@ -394,7 +394,7 @@ public final class StorageSyncHelper {
.setTypingIndicatorsEnabled(TextSecurePreferences.isTypingIndicatorsEnabled(context))
.setReadReceiptsEnabled(TextSecurePreferences.isReadReceiptsEnabled(context))
.setSealedSenderIndicatorsEnabled(TextSecurePreferences.isShowUnidentifiedDeliveryIndicatorsEnabled(context))
.setLinkPreviewsEnabled(TextSecurePreferences.isLinkPreviewsEnabled(context))
.setLinkPreviewsEnabled(SignalStore.settings().isLinkPreviewsEnabled())
.build();
return SignalStorageRecord.forAccount(account);
@ -414,7 +414,7 @@ public final class StorageSyncHelper {
TextSecurePreferences.setReadReceiptsEnabled(context, update.isReadReceiptsEnabled());
TextSecurePreferences.setTypingIndicatorsEnabled(context, update.isTypingIndicatorsEnabled());
TextSecurePreferences.setShowUnidentifiedDeliveryIndicatorsEnabled(context, update.isSealedSenderIndicatorsEnabled());
TextSecurePreferences.setLinkPreviewsEnabled(context, update.isLinkPreviewsEnabled());
SignalStore.settings().setLinkPreviewsEnabled(update.isLinkPreviewsEnabled());
if (fetchProfile && update.getAvatarUrlPath().isPresent()) {
ApplicationDependencies.getJobManager().add(new RetrieveProfileAvatarJob(Recipient.self(), update.getAvatarUrlPath().get()));

View File

@ -419,10 +419,6 @@ public class TextSecurePreferences {
setBooleanPreference(context, TYPING_INDICATORS, enabled);
}
public static boolean isLinkPreviewsEnabled(Context context) {
return getBooleanPreference(context, LINK_PREVIEWS, true);
}
public static void setLinkPreviewsEnabled(Context context, boolean enabled) {
setBooleanPreference(context, LINK_PREVIEWS, enabled);
}

View File

@ -0,0 +1,27 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="64dp"
android:height="64dp"
android:viewportWidth="64"
android:viewportHeight="64">
<path
android:pathData="M4,0L60,0A4,4 0,0 1,64 4L64,60A4,4 0,0 1,60 64L4,64A4,4 0,0 1,0 60L0,4A4,4 0,0 1,4 0z"
android:fillColor="#B9B9B9"/>
<path
android:pathData="M9.5,54L46.5,54A1.5,1.5 0,0 1,48 55.5L48,55.5A1.5,1.5 0,0 1,46.5 57L9.5,57A1.5,1.5 0,0 1,8 55.5L8,55.5A1.5,1.5 0,0 1,9.5 54z"
android:fillColor="#F6F6F6"/>
<path
android:pathData="M9.5,47L54.5,47A1.5,1.5 0,0 1,56 48.5L56,48.5A1.5,1.5 0,0 1,54.5 50L9.5,50A1.5,1.5 0,0 1,8 48.5L8,48.5A1.5,1.5 0,0 1,9.5 47z"
android:fillColor="#F6F6F6"/>
<path
android:pathData="M0,4C0,1.7909 1.7909,0 4,0H60C62.2091,0 64,1.7909 64,4V41H0V4Z"
android:fillColor="#2C6BED"/>
<path
android:pathData="M16.6154,10.3077m-5.5385,0a5.5385,5.5385 0,1 1,11.0769 0a5.5385,5.5385 0,1 1,-11.0769 0"
android:fillColor="#E9E9E9"/>
<path
android:pathData="M11.0126,20.8283C6.3833,20.6538 2.8877,20.8738 0,21.3893V41H64V30.4162C36.7234,28.2829 21.4363,21.2214 11.0126,20.8283Z"
android:fillColor="#6191F3"/>
<path
android:pathData="M-0,41L-0,37.3314C19.2247,32.4502 29.3199,15.9214 49.8461,16.4615C54.8182,16.5924 59.5815,17.6245 64,19.1928V41H-0Z"
android:fillColor="#7DA8FF"/>
</vector>

View File

@ -84,18 +84,31 @@
<com.pnikosis.materialishprogress.ProgressWheel
android:id="@+id/linkpreview_progress_wheel"
android:layout_width="match_parent"
android:layout_height="72dp"
android:layout_height="0dp"
android:layout_gravity="center_horizontal"
android:layout_marginBottom="8dp"
android:indeterminate="true"
android:padding="8dp"
android:visibility="gone"
app:layout_constraintBottom_toTopOf="@+id/linkpreview_divider"
app:layout_constraintBottom_toBottomOf="@+id/linkpreview_no_preview"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintTop_toTopOf="@id/linkpreview_no_preview"
app:matProg_barColor="@color/core_ultramarine"
app:matProg_progressIndeterminate="true" />
app:matProg_progressIndeterminate="true"
app:matProg_barWidth="3dp"/>
<TextView
android:id="@+id/linkpreview_no_preview"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:paddingTop="12dp"
android:paddingBottom="12dp"
android:text="@string/LinkPreviewView_no_link_preview_available"
android:gravity="center"
android:visibility="gone"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintBottom_toTopOf="@id/linkpreview_divider"/>
</androidx.constraintlayout.widget.ConstraintLayout>

View File

@ -0,0 +1,91 @@
<?xml version="1.0" encoding="utf-8"?>
<merge
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:paddingBottom="14dp"
android:clipChildren="false"
android:clipToPadding="false"
tools:parentTag="android.widget.FrameLayout">
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:paddingTop="16dp"
android:paddingStart="8dp"
android:paddingEnd="8dp"
android:paddingBottom="8dp"
android:background="?megaphone_background"
android:clickable="true">
<ImageView
android:id="@+id/linkpreview_megaphone_image"
android:layout_width="64dp"
android:layout_height="64dp"
android:layout_marginStart="8dp"
android:scaleType="centerInside"
app:srcCompat="@drawable/ic_megaphone_link_previews"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<org.thoughtcrime.securesms.components.emoji.EmojiTextView
android:id="@+id/linkpreview_megaphone_title"
style="@style/Signal.Text.Body"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginStart="12dp"
android:layout_marginEnd="8dp"
android:fontFamily="sans-serif-medium"
android:text="@string/LinkPreviewsMegaphone_preview_any_link"
app:layout_constraintStart_toEndOf="@id/linkpreview_megaphone_image"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="@id/linkpreview_megaphone_image" />
<org.thoughtcrime.securesms.components.emoji.EmojiTextView
android:id="@+id/linkpreview_megaphone_body"
style="@style/Signal.Text.Preview"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginEnd="8dp"
android:textColor="?megaphone_body_text_color"
android:text="@string/LinkPreviewsMegaphone_you_can_now_retrieve_link_previews_directly_from_any_website"
app:layout_constraintStart_toStartOf="@id/linkpreview_megaphone_title"
app:layout_constraintTop_toBottomOf="@id/linkpreview_megaphone_title"
app:layout_constraintEnd_toEndOf="parent" />
<androidx.constraintlayout.widget.Barrier
android:id="@+id/linkpreview_megaphone_content_barrier"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:barrierDirection="bottom"
app:constraint_referenced_ids="linkpreview_megaphone_image,linkpreview_megaphone_body,linkpreview_megaphone_title"/>
<Button
android:id="@+id/linkpreview_megaphone_ok"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginTop="4dp"
style="@style/Button.Borderless"
android:text="@string/ok"
app:layout_constraintStart_toEndOf="@id/linkpreview_megaphone_disable"
app:layout_constraintTop_toBottomOf="@id/linkpreview_megaphone_content_barrier"
app:layout_constraintEnd_toEndOf="parent"
tools:visibility="visible"/>
<Button
android:id="@+id/linkpreview_megaphone_disable"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginTop="4dp"
android:text="@string/LinkPreviewsMegaphone_disable"
style="@style/Button.Borderless"
app:layout_constraintTop_toBottomOf="@id/linkpreview_megaphone_content_barrier"
app:layout_constraintEnd_toStartOf="@id/linkpreview_megaphone_ok"
app:layout_constraintStart_toStartOf="parent"
tools:visibility="visible"/>
</androidx.constraintlayout.widget.ConstraintLayout>
</merge>

View File

@ -484,6 +484,14 @@
<string name="GroupManagement_learn_more">Learn more</string>
<string name="GroupManagement_invite_multiple_users">These users cant be automatically added to this group by you.\n\nTheyve been invited to join the group, and wont see any group messages until they accept.</string>
<!-- LinkPreviewsMegaphone -->
<string name="LinkPreviewsMegaphone_disable">Disable</string>
<string name="LinkPreviewsMegaphone_preview_any_link">Preview any link</string>
<string name="LinkPreviewsMegaphone_you_can_now_retrieve_link_previews_directly_from_any_website">You can now retrieve link previews directly from any website for messages you send.</string>
<!-- LinkPreviewView -->
<string name="LinkPreviewView_no_link_preview_available">No link preview available</string>
<!-- PendingMembersActivity -->
<string name="PendingMemberInvitesActivity_pending_group_invites">Pending group invites</string>
<string name="PendingMembersActivity_people_you_invited">People you invited</string>
@ -1889,8 +1897,8 @@
<string name="preferences__use_signal_for_viewing_and_storing_all_incoming_multimedia_messages">Use Signal for all incoming multimedia messages</string>
<string name="preferences__pref_enter_sends_title">Enter key sends</string>
<string name="preferences__pressing_the_enter_key_will_send_text_messages">Pressing the Enter key will send text messages</string>
<string name="preferences__send_link_previews">Send link previews</string>
<string name="preferences__previews_are_supported_for">Previews are supported for Imgur, Instagram, Pinterest, Reddit, and YouTube links</string>
<string name="preferences__generate_link_previews">Generate link previews</string>
<string name="preferences__retrieve_link_previews_from_websites_for_messages">Retrieve link previews directly from websites for messages you send.</string>
<string name="preferences__choose_identity">Choose identity</string>
<string name="preferences__choose_your_contact_entry_from_the_contacts_list">Choose your contact entry from the contacts list.</string>
<string name="preferences__change_passphrase">Change passphrase</string>

View File

@ -74,9 +74,9 @@
<org.thoughtcrime.securesms.components.SwitchPreferenceCompat
android:defaultValue="true"
android:key="pref_link_previews"
android:summary="@string/preferences__previews_are_supported_for"
android:title="@string/preferences__send_link_previews" />
android:key="settings.link_previews"
android:summary="@string/preferences__retrieve_link_previews_from_websites_for_messages"
android:title="@string/preferences__generate_link_previews" />
<Preference
android:key="preference_category_blocked"