mirror of
https://github.com/oxen-io/session-android.git
synced 2025-06-08 02:48:32 +00:00
Add support for article dates in link previews.
This commit is contained in:
parent
bfed03b7b5
commit
dd8b9ff8fb
@ -23,6 +23,10 @@ import org.thoughtcrime.securesms.mms.SlidesClickedListener;
|
|||||||
import org.thoughtcrime.securesms.util.ThemeUtil;
|
import org.thoughtcrime.securesms.util.ThemeUtil;
|
||||||
import org.thoughtcrime.securesms.util.Util;
|
import org.thoughtcrime.securesms.util.Util;
|
||||||
|
|
||||||
|
import java.text.DateFormat;
|
||||||
|
import java.text.SimpleDateFormat;
|
||||||
|
import java.util.Locale;
|
||||||
|
|
||||||
import okhttp3.HttpUrl;
|
import okhttp3.HttpUrl;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -146,14 +150,24 @@ public class LinkPreviewView extends FrameLayout {
|
|||||||
description.setVisibility(GONE);
|
description.setVisibility(GONE);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
String domain = null;
|
||||||
|
|
||||||
if (!Util.isEmpty(linkPreview.getUrl())) {
|
if (!Util.isEmpty(linkPreview.getUrl())) {
|
||||||
HttpUrl url = HttpUrl.parse(linkPreview.getUrl());
|
HttpUrl url = HttpUrl.parse(linkPreview.getUrl());
|
||||||
if (url != null) {
|
if (url != null) {
|
||||||
site.setText(url.topPrivateDomain());
|
domain = url.topPrivateDomain();
|
||||||
site.setVisibility(VISIBLE);
|
|
||||||
} else {
|
|
||||||
site.setVisibility(GONE);
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (domain != null && linkPreview.getDate() > 0) {
|
||||||
|
site.setText(getContext().getString(R.string.LinkPreviewView_domain_date, domain, formatDate(linkPreview.getDate())));
|
||||||
|
site.setVisibility(VISIBLE);
|
||||||
|
} else if (domain != null) {
|
||||||
|
site.setText(domain);
|
||||||
|
site.setVisibility(VISIBLE);
|
||||||
|
} else if (linkPreview.getDate() > 0) {
|
||||||
|
site.setText(formatDate(linkPreview.getDate()));
|
||||||
|
site.setVisibility(VISIBLE);
|
||||||
} else {
|
} else {
|
||||||
site.setVisibility(GONE);
|
site.setVisibility(GONE);
|
||||||
}
|
}
|
||||||
@ -187,6 +201,11 @@ public class LinkPreviewView extends FrameLayout {
|
|||||||
: R.string.LinkPreviewView_no_link_preview_available;
|
: R.string.LinkPreviewView_no_link_preview_available;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static String formatDate(long date) {
|
||||||
|
DateFormat dateFormat = new SimpleDateFormat("MMM dd, yyyy", Locale.getDefault());
|
||||||
|
return dateFormat.format(date);
|
||||||
|
}
|
||||||
|
|
||||||
public interface CloseClickedListener {
|
public interface CloseClickedListener {
|
||||||
void onCloseClicked();
|
void onCloseClicked();
|
||||||
}
|
}
|
||||||
|
@ -1118,7 +1118,7 @@ public class MmsDatabase extends MessageDatabase {
|
|||||||
if (preview.getAttachmentId() != null) {
|
if (preview.getAttachmentId() != null) {
|
||||||
DatabaseAttachment attachment = attachmentIdMap.get(preview.getAttachmentId());
|
DatabaseAttachment attachment = attachmentIdMap.get(preview.getAttachmentId());
|
||||||
if (attachment != null) {
|
if (attachment != null) {
|
||||||
previews.add(new LinkPreview(preview.getUrl(), preview.getTitle(), preview.getDescription(), attachment));
|
previews.add(new LinkPreview(preview.getUrl(), preview.getTitle(), preview.getDescription(), preview.getDate(), attachment));
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
previews.add(preview);
|
previews.add(preview);
|
||||||
@ -1526,7 +1526,7 @@ public class MmsDatabase extends MessageDatabase {
|
|||||||
attachmentId = insertedAttachmentIds.get(preview.getThumbnail().get());
|
attachmentId = insertedAttachmentIds.get(preview.getThumbnail().get());
|
||||||
}
|
}
|
||||||
|
|
||||||
LinkPreview updatedPreview = new LinkPreview(preview.getUrl(), preview.getTitle(), preview.getDescription(), attachmentId);
|
LinkPreview updatedPreview = new LinkPreview(preview.getUrl(), preview.getTitle(), preview.getDescription(), preview.getDate(), attachmentId);
|
||||||
linkPreviewJson.put(new JSONObject(updatedPreview.serialize()));
|
linkPreviewJson.put(new JSONObject(updatedPreview.serialize()));
|
||||||
} catch (JSONException | IOException e) {
|
} catch (JSONException | IOException e) {
|
||||||
Log.w(TAG, "Failed to serialize shared contact. Skipping it.", e);
|
Log.w(TAG, "Failed to serialize shared contact. Skipping it.", e);
|
||||||
|
@ -1696,7 +1696,7 @@ public final class PushProcessMessageJob extends BaseJob {
|
|||||||
boolean validDomain = url.isPresent() && LinkPreviewUtil.isValidPreviewUrl(url.get());
|
boolean validDomain = url.isPresent() && LinkPreviewUtil.isValidPreviewUrl(url.get());
|
||||||
|
|
||||||
if (hasTitle && presentInBody && validDomain) {
|
if (hasTitle && presentInBody && validDomain) {
|
||||||
LinkPreview linkPreview = new LinkPreview(url.get(), title.or(""), description.or(""), thumbnail);
|
LinkPreview linkPreview = new LinkPreview(url.get(), title.or(""), description.or(""), preview.getDate(), thumbnail);
|
||||||
linkPreviews.add(linkPreview);
|
linkPreviews.add(linkPreview);
|
||||||
} else {
|
} else {
|
||||||
Log.w(TAG, String.format("Discarding an invalid link preview. hasTitle: %b presentInBody: %b validDomain: %b", hasTitle, presentInBody, validDomain));
|
Log.w(TAG, String.format("Discarding an invalid link preview. hasTitle: %b presentInBody: %b validDomain: %b", hasTitle, presentInBody, validDomain));
|
||||||
|
@ -315,7 +315,7 @@ public abstract class PushSendJob extends SendJob {
|
|||||||
List<Preview> getPreviewsFor(OutgoingMediaMessage mediaMessage) {
|
List<Preview> getPreviewsFor(OutgoingMediaMessage mediaMessage) {
|
||||||
return Stream.of(mediaMessage.getLinkPreviews()).map(lp -> {
|
return Stream.of(mediaMessage.getLinkPreviews()).map(lp -> {
|
||||||
SignalServiceAttachment attachment = lp.getThumbnail().isPresent() ? getAttachmentPointerFor(lp.getThumbnail().get()) : null;
|
SignalServiceAttachment attachment = lp.getThumbnail().isPresent() ? getAttachmentPointerFor(lp.getThumbnail().get()) : null;
|
||||||
return new Preview(lp.getUrl(), lp.getTitle(), lp.getDescription(), Optional.fromNullable(attachment));
|
return new Preview(lp.getUrl(), lp.getTitle(), lp.getDescription(), lp.getDate(), Optional.fromNullable(attachment));
|
||||||
}).toList();
|
}).toList();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -25,24 +25,29 @@ public class LinkPreview {
|
|||||||
@JsonProperty
|
@JsonProperty
|
||||||
private final String description;
|
private final String description;
|
||||||
|
|
||||||
|
@JsonProperty
|
||||||
|
private final long date;
|
||||||
|
|
||||||
@JsonProperty
|
@JsonProperty
|
||||||
private final AttachmentId attachmentId;
|
private final AttachmentId attachmentId;
|
||||||
|
|
||||||
@JsonIgnore
|
@JsonIgnore
|
||||||
private final Optional<Attachment> thumbnail;
|
private final Optional<Attachment> thumbnail;
|
||||||
|
|
||||||
public LinkPreview(@NonNull String url, @NonNull String title, @NonNull String description, @NonNull DatabaseAttachment thumbnail) {
|
public LinkPreview(@NonNull String url, @NonNull String title, @NonNull String description, long date, @NonNull DatabaseAttachment thumbnail) {
|
||||||
this.url = url;
|
this.url = url;
|
||||||
this.title = title;
|
this.title = title;
|
||||||
this.description = description;
|
this.description = description;
|
||||||
|
this.date = date;
|
||||||
this.thumbnail = Optional.of(thumbnail);
|
this.thumbnail = Optional.of(thumbnail);
|
||||||
this.attachmentId = thumbnail.getAttachmentId();
|
this.attachmentId = thumbnail.getAttachmentId();
|
||||||
}
|
}
|
||||||
|
|
||||||
public LinkPreview(@NonNull String url, @NonNull String title, @NonNull String description, @NonNull Optional<Attachment> thumbnail) {
|
public LinkPreview(@NonNull String url, @NonNull String title, @NonNull String description, long date, @NonNull Optional<Attachment> thumbnail) {
|
||||||
this.url = url;
|
this.url = url;
|
||||||
this.title = title;
|
this.title = title;
|
||||||
this.description = description;
|
this.description = description;
|
||||||
|
this.date = date;
|
||||||
this.thumbnail = thumbnail;
|
this.thumbnail = thumbnail;
|
||||||
this.attachmentId = null;
|
this.attachmentId = null;
|
||||||
}
|
}
|
||||||
@ -50,11 +55,13 @@ public class LinkPreview {
|
|||||||
public LinkPreview(@JsonProperty("url") @NonNull String url,
|
public LinkPreview(@JsonProperty("url") @NonNull String url,
|
||||||
@JsonProperty("title") @NonNull String title,
|
@JsonProperty("title") @NonNull String title,
|
||||||
@JsonProperty("description") @Nullable String description,
|
@JsonProperty("description") @Nullable String description,
|
||||||
|
@JsonProperty("date") long date,
|
||||||
@JsonProperty("attachmentId") @Nullable AttachmentId attachmentId)
|
@JsonProperty("attachmentId") @Nullable AttachmentId attachmentId)
|
||||||
{
|
{
|
||||||
this.url = url;
|
this.url = url;
|
||||||
this.title = title;
|
this.title = title;
|
||||||
this.description = Optional.fromNullable(description).or("");
|
this.description = Optional.fromNullable(description).or("");
|
||||||
|
this.date = date;
|
||||||
this.attachmentId = attachmentId;
|
this.attachmentId = attachmentId;
|
||||||
this.thumbnail = Optional.absent();
|
this.thumbnail = Optional.absent();
|
||||||
}
|
}
|
||||||
@ -71,6 +78,10 @@ public class LinkPreview {
|
|||||||
return description;
|
return description;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public long getDate() {
|
||||||
|
return date;
|
||||||
|
}
|
||||||
|
|
||||||
public @NonNull Optional<Attachment> getThumbnail() {
|
public @NonNull Optional<Attachment> getThumbnail() {
|
||||||
return thumbnail;
|
return thumbnail;
|
||||||
}
|
}
|
||||||
|
@ -106,7 +106,7 @@ public class LinkPreviewRepository {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (!metadata.getImageUrl().isPresent()) {
|
if (!metadata.getImageUrl().isPresent()) {
|
||||||
callback.onSuccess(new LinkPreview(url, metadata.getTitle().or(""), metadata.getDescription().or(""), Optional.absent()));
|
callback.onSuccess(new LinkPreview(url, metadata.getTitle().or(""), metadata.getDescription().or(""), metadata.getDate(), Optional.absent()));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -114,7 +114,7 @@ public class LinkPreviewRepository {
|
|||||||
if (!metadata.getTitle().isPresent() && !attachment.isPresent()) {
|
if (!metadata.getTitle().isPresent() && !attachment.isPresent()) {
|
||||||
callback.onError(Error.PREVIEW_NOT_AVAILABLE);
|
callback.onError(Error.PREVIEW_NOT_AVAILABLE);
|
||||||
} else {
|
} else {
|
||||||
callback.onSuccess(new LinkPreview(url, metadata.getTitle().or(""), metadata.getDescription().or(""), attachment));
|
callback.onSuccess(new LinkPreview(url, metadata.getTitle().or(""), metadata.getDescription().or(""), metadata.getDate(), attachment));
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -153,13 +153,14 @@ public class LinkPreviewRepository {
|
|||||||
Optional<String> title = openGraph.getTitle();
|
Optional<String> title = openGraph.getTitle();
|
||||||
Optional<String> description = openGraph.getDescription();
|
Optional<String> description = openGraph.getDescription();
|
||||||
Optional<String> imageUrl = openGraph.getImageUrl();
|
Optional<String> imageUrl = openGraph.getImageUrl();
|
||||||
|
long date = openGraph.getDate();
|
||||||
|
|
||||||
if (imageUrl.isPresent() && !LinkPreviewUtil.isValidPreviewUrl(imageUrl.get())) {
|
if (imageUrl.isPresent() && !LinkPreviewUtil.isValidPreviewUrl(imageUrl.get())) {
|
||||||
Log.i(TAG, "Image URL was invalid or for a non-whitelisted domain. Skipping.");
|
Log.i(TAG, "Image URL was invalid or for a non-whitelisted domain. Skipping.");
|
||||||
imageUrl = Optional.absent();
|
imageUrl = Optional.absent();
|
||||||
}
|
}
|
||||||
|
|
||||||
callback.accept(new Metadata(title, description, imageUrl));
|
callback.accept(new Metadata(title, description, date, imageUrl));
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -227,7 +228,7 @@ public class LinkPreviewRepository {
|
|||||||
|
|
||||||
Optional<Attachment> thumbnail = bitmapToAttachment(bitmap, Bitmap.CompressFormat.WEBP, MediaUtil.IMAGE_WEBP);
|
Optional<Attachment> thumbnail = bitmapToAttachment(bitmap, Bitmap.CompressFormat.WEBP, MediaUtil.IMAGE_WEBP);
|
||||||
|
|
||||||
callback.onSuccess(new LinkPreview(packUrl, title, "", thumbnail));
|
callback.onSuccess(new LinkPreview(packUrl, title, "", 0, thumbnail));
|
||||||
} else {
|
} else {
|
||||||
callback.onError(Error.PREVIEW_NOT_AVAILABLE);
|
callback.onError(Error.PREVIEW_NOT_AVAILABLE);
|
||||||
}
|
}
|
||||||
@ -272,7 +273,7 @@ public class LinkPreviewRepository {
|
|||||||
thumbnail = bitmapToAttachment(bitmap, Bitmap.CompressFormat.WEBP, MediaUtil.IMAGE_WEBP);
|
thumbnail = bitmapToAttachment(bitmap, Bitmap.CompressFormat.WEBP, MediaUtil.IMAGE_WEBP);
|
||||||
}
|
}
|
||||||
|
|
||||||
callback.onSuccess(new LinkPreview(groupUrl, title, description, thumbnail));
|
callback.onSuccess(new LinkPreview(groupUrl, title, description, 0, thumbnail));
|
||||||
} else {
|
} else {
|
||||||
Log.i(TAG, "Group is not locally available for preview generation, fetching from server");
|
Log.i(TAG, "Group is not locally available for preview generation, fetching from server");
|
||||||
|
|
||||||
@ -289,7 +290,7 @@ public class LinkPreviewRepository {
|
|||||||
if (bitmap != null) bitmap.recycle();
|
if (bitmap != null) bitmap.recycle();
|
||||||
}
|
}
|
||||||
|
|
||||||
callback.onSuccess(new LinkPreview(groupUrl, joinInfo.getTitle(), description, thumbnail));
|
callback.onSuccess(new LinkPreview(groupUrl, joinInfo.getTitle(), description, 0, thumbnail));
|
||||||
}
|
}
|
||||||
} catch (ExecutionException | InterruptedException | IOException | VerificationFailedException e) {
|
} catch (ExecutionException | InterruptedException | IOException | VerificationFailedException e) {
|
||||||
Log.w(TAG, "Failed to fetch group link preview.", e);
|
Log.w(TAG, "Failed to fetch group link preview.", e);
|
||||||
@ -350,16 +351,18 @@ public class LinkPreviewRepository {
|
|||||||
private static class Metadata {
|
private static class Metadata {
|
||||||
private final Optional<String> title;
|
private final Optional<String> title;
|
||||||
private final Optional<String> description;
|
private final Optional<String> description;
|
||||||
|
private final long date;
|
||||||
private final Optional<String> imageUrl;
|
private final Optional<String> imageUrl;
|
||||||
|
|
||||||
Metadata(Optional<String> title, Optional<String> description, Optional<String> imageUrl) {
|
Metadata(Optional<String> title, Optional<String> description, long date, Optional<String> imageUrl) {
|
||||||
this.title = title;
|
this.title = title;
|
||||||
this.description = description;
|
this.description = description;
|
||||||
|
this.date = date;
|
||||||
this.imageUrl = imageUrl;
|
this.imageUrl = imageUrl;
|
||||||
}
|
}
|
||||||
|
|
||||||
static Metadata empty() {
|
static Metadata empty() {
|
||||||
return new Metadata(Optional.absent(), Optional.absent(), Optional.absent());
|
return new Metadata(Optional.absent(), Optional.absent(), 0, Optional.absent());
|
||||||
}
|
}
|
||||||
|
|
||||||
Optional<String> getTitle() {
|
Optional<String> getTitle() {
|
||||||
@ -370,6 +373,10 @@ public class LinkPreviewRepository {
|
|||||||
return description;
|
return description;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
long getDate() {
|
||||||
|
return date;
|
||||||
|
}
|
||||||
|
|
||||||
Optional<String> getImageUrl() {
|
Optional<String> getImageUrl() {
|
||||||
return imageUrl;
|
return imageUrl;
|
||||||
}
|
}
|
||||||
|
@ -13,14 +13,19 @@ import android.text.util.Linkify;
|
|||||||
import com.annimon.stream.Stream;
|
import com.annimon.stream.Stream;
|
||||||
import com.google.android.collect.Sets;
|
import com.google.android.collect.Sets;
|
||||||
|
|
||||||
|
import org.thoughtcrime.securesms.logging.Log;
|
||||||
import org.thoughtcrime.securesms.stickers.StickerUrl;
|
import org.thoughtcrime.securesms.stickers.StickerUrl;
|
||||||
import org.thoughtcrime.securesms.util.Util;
|
import org.thoughtcrime.securesms.util.Util;
|
||||||
import org.whispersystems.libsignal.util.guava.Optional;
|
import org.whispersystems.libsignal.util.guava.Optional;
|
||||||
import org.whispersystems.signalservice.api.util.OptionalUtil;
|
import org.whispersystems.signalservice.api.util.OptionalUtil;
|
||||||
|
|
||||||
|
import java.text.DateFormat;
|
||||||
|
import java.text.ParseException;
|
||||||
|
import java.text.SimpleDateFormat;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Locale;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
import java.util.regex.Matcher;
|
import java.util.regex.Matcher;
|
||||||
@ -30,10 +35,13 @@ import okhttp3.HttpUrl;
|
|||||||
|
|
||||||
public final class LinkPreviewUtil {
|
public final class LinkPreviewUtil {
|
||||||
|
|
||||||
|
private static final String TAG = Log.tag(LinkPreviewUtil.class);
|
||||||
|
|
||||||
private static final Pattern DOMAIN_PATTERN = Pattern.compile("^(https?://)?([^/]+).*$");
|
private static final Pattern DOMAIN_PATTERN = Pattern.compile("^(https?://)?([^/]+).*$");
|
||||||
private static final Pattern ALL_ASCII_PATTERN = Pattern.compile("^[\\x00-\\x7F]*$");
|
private static final Pattern ALL_ASCII_PATTERN = Pattern.compile("^[\\x00-\\x7F]*$");
|
||||||
private static final Pattern ALL_NON_ASCII_PATTERN = Pattern.compile("^[^\\x00-\\x7F]*$");
|
private static final Pattern ALL_NON_ASCII_PATTERN = Pattern.compile("^[^\\x00-\\x7F]*$");
|
||||||
private static final Pattern OPEN_GRAPH_TAG_PATTERN = Pattern.compile("<\\s*meta[^>]*property\\s*=\\s*\"\\s*og:([^\"]+)\"[^>]*/?\\s*>");
|
private static final Pattern OPEN_GRAPH_TAG_PATTERN = Pattern.compile("<\\s*meta[^>]*property\\s*=\\s*\"\\s*og:([^\"]+)\"[^>]*/?\\s*>");
|
||||||
|
private static final Pattern ARTICLE_TAG_PATTERN = Pattern.compile("<\\s*meta[^>]*property\\s*=\\s*\"\\s*article:([^\"]+)\"[^>]*/?\\s*>");
|
||||||
private static final Pattern OPEN_GRAPH_CONTENT_PATTERN = Pattern.compile("content\\s*=\\s*\"([^\"]*)\"");
|
private static final Pattern OPEN_GRAPH_CONTENT_PATTERN = Pattern.compile("content\\s*=\\s*\"([^\"]*)\"");
|
||||||
private static final Pattern TITLE_PATTERN = Pattern.compile("<\\s*title[^>]*>(.*)<\\s*/title[^>]*>");
|
private static final Pattern TITLE_PATTERN = Pattern.compile("<\\s*title[^>]*>(.*)<\\s*/title[^>]*>");
|
||||||
private static final Pattern FAVICON_PATTERN = Pattern.compile("<\\s*link[^>]*rel\\s*=\\s*\".*icon.*\"[^>]*>");
|
private static final Pattern FAVICON_PATTERN = Pattern.compile("<\\s*link[^>]*rel\\s*=\\s*\".*icon.*\"[^>]*>");
|
||||||
@ -112,7 +120,22 @@ public final class LinkPreviewUtil {
|
|||||||
Matcher contentMatcher = OPEN_GRAPH_CONTENT_PATTERN.matcher(tag);
|
Matcher contentMatcher = OPEN_GRAPH_CONTENT_PATTERN.matcher(tag);
|
||||||
if (contentMatcher.find() && contentMatcher.groupCount() > 0) {
|
if (contentMatcher.find() && contentMatcher.groupCount() > 0) {
|
||||||
String content = htmlDecoder.fromEncoded(contentMatcher.group(1));
|
String content = htmlDecoder.fromEncoded(contentMatcher.group(1));
|
||||||
openGraphTags.put(property, content);
|
openGraphTags.put(property.toLowerCase(), content);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Matcher articleMatcher = ARTICLE_TAG_PATTERN.matcher(html);
|
||||||
|
|
||||||
|
while (articleMatcher.find()) {
|
||||||
|
String tag = articleMatcher.group();
|
||||||
|
String property = articleMatcher.groupCount() > 0 ? articleMatcher.group(1) : null;
|
||||||
|
|
||||||
|
if (property != null) {
|
||||||
|
Matcher contentMatcher = OPEN_GRAPH_CONTENT_PATTERN.matcher(tag);
|
||||||
|
if (contentMatcher.find() && contentMatcher.groupCount() > 0) {
|
||||||
|
String content = htmlDecoder.fromEncoded(contentMatcher.group(1));
|
||||||
|
openGraphTags.put(property.toLowerCase(), content);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -157,6 +180,10 @@ public final class LinkPreviewUtil {
|
|||||||
private static final String KEY_TITLE = "title";
|
private static final String KEY_TITLE = "title";
|
||||||
private static final String KEY_DESCRIPTION_URL = "description";
|
private static final String KEY_DESCRIPTION_URL = "description";
|
||||||
private static final String KEY_IMAGE_URL = "image";
|
private static final String KEY_IMAGE_URL = "image";
|
||||||
|
private static final String KEY_PUBLISHED_TIME_1 = "published_time";
|
||||||
|
private static final String KEY_PUBLISHED_TIME_2 = "article:published_time";
|
||||||
|
private static final String KEY_MODIFIED_TIME_1 = "modified_time";
|
||||||
|
private static final String KEY_MODIFIED_TIME_2 = "article:modified_time";
|
||||||
|
|
||||||
public OpenGraph(@NonNull Map<String, String> values, @Nullable String htmlTitle, @Nullable String faviconUrl) {
|
public OpenGraph(@NonNull Map<String, String> values, @Nullable String htmlTitle, @Nullable String faviconUrl) {
|
||||||
this.values = values;
|
this.values = values;
|
||||||
@ -172,9 +199,35 @@ public final class LinkPreviewUtil {
|
|||||||
return OptionalUtil.absentIfEmpty(Util.getFirstNonEmpty(values.get(KEY_IMAGE_URL), faviconUrl));
|
return OptionalUtil.absentIfEmpty(Util.getFirstNonEmpty(values.get(KEY_IMAGE_URL), faviconUrl));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public long getDate() {
|
||||||
|
SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ssZ", Locale.getDefault());
|
||||||
|
|
||||||
|
return Stream.of(values.get(KEY_PUBLISHED_TIME_1),
|
||||||
|
values.get(KEY_PUBLISHED_TIME_2),
|
||||||
|
values.get(KEY_MODIFIED_TIME_1),
|
||||||
|
values.get(KEY_MODIFIED_TIME_2))
|
||||||
|
.map(dateString -> parseDate(format, dateString))
|
||||||
|
.filter(time -> time > 0)
|
||||||
|
.findFirst()
|
||||||
|
.orElse(0L);
|
||||||
|
}
|
||||||
|
|
||||||
public @NonNull Optional<String> getDescription() {
|
public @NonNull Optional<String> getDescription() {
|
||||||
return OptionalUtil.absentIfEmpty(values.get(KEY_DESCRIPTION_URL));
|
return OptionalUtil.absentIfEmpty(values.get(KEY_DESCRIPTION_URL));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static long parseDate(DateFormat dateFormat, String dateString) {
|
||||||
|
if (Util.isEmpty(dateString)) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
return dateFormat.parse(dateString).getTime();
|
||||||
|
} catch (ParseException e) {
|
||||||
|
Log.w(TAG, "Failed to parse date.", e);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public interface HtmlDecoder {
|
public interface HtmlDecoder {
|
||||||
|
@ -66,6 +66,7 @@
|
|||||||
android:layout_marginStart="8dp"
|
android:layout_marginStart="8dp"
|
||||||
android:layout_marginTop="2dp"
|
android:layout_marginTop="2dp"
|
||||||
android:textColor="?linkpreview_secondary_text_color"
|
android:textColor="?linkpreview_secondary_text_color"
|
||||||
|
android:maxLines="2"
|
||||||
app:layout_constraintStart_toEndOf="@+id/linkpreview_thumbnail"
|
app:layout_constraintStart_toEndOf="@+id/linkpreview_thumbnail"
|
||||||
app:layout_constraintTop_toBottomOf="@+id/linkpreview_description"
|
app:layout_constraintTop_toBottomOf="@+id/linkpreview_description"
|
||||||
tools:text="dailybugle.com" />
|
tools:text="dailybugle.com" />
|
||||||
|
@ -497,6 +497,7 @@
|
|||||||
<!-- LinkPreviewView -->
|
<!-- LinkPreviewView -->
|
||||||
<string name="LinkPreviewView_no_link_preview_available">No link preview available</string>
|
<string name="LinkPreviewView_no_link_preview_available">No link preview available</string>
|
||||||
<string name="LinkPreviewView_this_group_link_is_not_active">This group link is not active</string>
|
<string name="LinkPreviewView_this_group_link_is_not_active">This group link is not active</string>
|
||||||
|
<string name="LinkPreviewView_domain_date">%1$s · %2$s</string>
|
||||||
|
|
||||||
<!-- LinkPreviewRepository -->
|
<!-- LinkPreviewRepository -->
|
||||||
<plurals name="LinkPreviewRepository_d_members">
|
<plurals name="LinkPreviewRepository_d_members">
|
||||||
|
@ -629,6 +629,7 @@ public class SignalServiceMessageSender {
|
|||||||
DataMessage.Preview.Builder previewBuilder = DataMessage.Preview.newBuilder();
|
DataMessage.Preview.Builder previewBuilder = DataMessage.Preview.newBuilder();
|
||||||
previewBuilder.setTitle(preview.getTitle());
|
previewBuilder.setTitle(preview.getTitle());
|
||||||
previewBuilder.setDescription(preview.getDescription());
|
previewBuilder.setDescription(preview.getDescription());
|
||||||
|
previewBuilder.setDate(preview.getDate());
|
||||||
previewBuilder.setUrl(preview.getUrl());
|
previewBuilder.setUrl(preview.getUrl());
|
||||||
|
|
||||||
if (preview.getImage().isPresent()) {
|
if (preview.getImage().isPresent()) {
|
||||||
|
@ -687,6 +687,7 @@ public final class SignalServiceContent {
|
|||||||
results.add(new SignalServiceDataMessage.Preview(preview.getUrl(),
|
results.add(new SignalServiceDataMessage.Preview(preview.getUrl(),
|
||||||
preview.getTitle(),
|
preview.getTitle(),
|
||||||
preview.getDescription(),
|
preview.getDescription(),
|
||||||
|
preview.getDate(),
|
||||||
Optional.fromNullable(attachment)));
|
Optional.fromNullable(attachment)));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -413,12 +413,14 @@ public class SignalServiceDataMessage {
|
|||||||
private final String url;
|
private final String url;
|
||||||
private final String title;
|
private final String title;
|
||||||
private final String description;
|
private final String description;
|
||||||
|
private final long date;
|
||||||
private final Optional<SignalServiceAttachment> image;
|
private final Optional<SignalServiceAttachment> image;
|
||||||
|
|
||||||
public Preview(String url, String title, String description, Optional<SignalServiceAttachment> image) {
|
public Preview(String url, String title, String description, long date, Optional<SignalServiceAttachment> image) {
|
||||||
this.url = url;
|
this.url = url;
|
||||||
this.title = title;
|
this.title = title;
|
||||||
this.description = description;
|
this.description = description;
|
||||||
|
this.date = date;
|
||||||
this.image = image;
|
this.image = image;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -434,6 +436,10 @@ public class SignalServiceDataMessage {
|
|||||||
return description;
|
return description;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public long getDate() {
|
||||||
|
return date;
|
||||||
|
}
|
||||||
|
|
||||||
public Optional<SignalServiceAttachment> getImage() {
|
public Optional<SignalServiceAttachment> getImage() {
|
||||||
return image;
|
return image;
|
||||||
}
|
}
|
||||||
|
@ -207,6 +207,7 @@ message DataMessage {
|
|||||||
optional string title = 2;
|
optional string title = 2;
|
||||||
optional AttachmentPointer image = 3;
|
optional AttachmentPointer image = 3;
|
||||||
optional string description = 4;
|
optional string description = 4;
|
||||||
|
optional uint64 date = 5;
|
||||||
}
|
}
|
||||||
|
|
||||||
message Sticker {
|
message Sticker {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user