fedilab-Android-App/app/src/main/java/fr/gouv/etalab/mastodon/client/Entities/Status.java

1107 lines
47 KiB
Java
Raw Normal View History

2017-05-05 16:36:04 +02:00
/* Copyright 2017 Thomas Schneider
*
2017-07-10 10:33:24 +02:00
* This file is a part of Mastalab
2017-05-05 16:36:04 +02:00
*
* This program is free software; you can redistribute it and/or modify it under the terms of the
* GNU General Public License as published by the Free Software Foundation; either version 3 of the
* License, or (at your option) any later version.
*
2017-07-10 10:33:24 +02:00
* Mastalab is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even
2017-05-05 16:36:04 +02:00
* the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
* Public License for more details.
*
2017-08-04 11:11:27 +02:00
* You should have received a copy of the GNU General Public License along with Mastalab; if not,
2017-05-05 16:36:04 +02:00
* see <http://www.gnu.org/licenses>. */
package fr.gouv.etalab.mastodon.client.Entities;
2018-01-11 07:32:19 +01:00
import android.app.Activity;
2017-12-03 10:56:54 +01:00
import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
2017-12-03 10:56:54 +01:00
import android.graphics.Bitmap;
2018-08-14 18:27:21 +02:00
import android.net.Uri;
2017-12-03 10:56:54 +01:00
import android.os.Build;
import android.os.Bundle;
2017-05-26 17:20:36 +02:00
import android.os.Parcel;
import android.os.Parcelable;
2018-04-28 16:54:06 +02:00
import android.support.annotation.NonNull;
2017-12-03 10:56:54 +01:00
import android.support.annotation.Nullable;
import android.support.v4.content.ContextCompat;
2017-12-03 10:56:54 +01:00
import android.text.Html;
import android.text.Spannable;
2017-10-20 19:58:46 +02:00
import android.text.SpannableString;
2017-12-03 10:56:54 +01:00
import android.text.Spanned;
import android.text.TextPaint;
import android.text.style.ClickableSpan;
import android.text.style.ImageSpan;
import android.text.style.URLSpan;
2017-12-03 10:56:54 +01:00
import android.view.View;
import com.bumptech.glide.Glide;
import com.bumptech.glide.load.DataSource;
import com.bumptech.glide.load.engine.GlideException;
import com.bumptech.glide.request.RequestListener;
import com.bumptech.glide.request.target.SimpleTarget;
import com.bumptech.glide.request.target.Target;
import com.bumptech.glide.request.transition.Transition;
2017-10-20 19:58:46 +02:00
import java.util.ArrayList;
2017-05-05 16:36:04 +02:00
import java.util.Date;
2018-09-15 12:43:36 +02:00
import java.util.HashMap;
import java.util.Iterator;
2017-05-05 16:36:04 +02:00
import java.util.List;
2018-09-15 12:43:36 +02:00
import java.util.Map;
2017-12-03 10:56:54 +01:00
import java.util.regex.Matcher;
2018-09-01 12:42:22 +02:00
import java.util.regex.Pattern;
2017-12-03 10:56:54 +01:00
import fr.gouv.etalab.mastodon.R;
2017-12-03 10:56:54 +01:00
import fr.gouv.etalab.mastodon.activities.HashTagActivity;
2018-09-01 15:59:16 +02:00
import fr.gouv.etalab.mastodon.activities.MainActivity;
2018-10-14 17:36:18 +02:00
import fr.gouv.etalab.mastodon.activities.PeertubeActivity;
2017-12-03 10:56:54 +01:00
import fr.gouv.etalab.mastodon.activities.ShowAccountActivity;
import fr.gouv.etalab.mastodon.asynctasks.RetrieveFeedsAsyncTask;
import fr.gouv.etalab.mastodon.helper.CrossActions;
2017-12-03 10:56:54 +01:00
import fr.gouv.etalab.mastodon.helper.Helper;
import fr.gouv.etalab.mastodon.interfaces.OnRetrieveEmojiInterface;
2017-05-05 16:36:04 +02:00
2018-09-01 15:59:16 +02:00
import static fr.gouv.etalab.mastodon.helper.Helper.INTENT_ACTION;
import static fr.gouv.etalab.mastodon.helper.Helper.SEARCH_REMOTE;
import static fr.gouv.etalab.mastodon.helper.Helper.SEARCH_URL;
2018-11-02 14:42:29 +01:00
import static fr.gouv.etalab.mastodon.helper.Helper.THEME_BLACK;
import static fr.gouv.etalab.mastodon.helper.Helper.THEME_DARK;
import static fr.gouv.etalab.mastodon.helper.Helper.THEME_LIGHT;
2018-09-01 15:59:16 +02:00
2017-05-05 16:36:04 +02:00
/**
* Created by Thomas on 23/04/2017.
2017-05-26 17:20:36 +02:00
* Manage Status (ie: toots)
2017-05-05 16:36:04 +02:00
*/
2017-12-15 18:03:06 +01:00
public class Status implements Parcelable{
2017-05-05 16:36:04 +02:00
private String id;
private String uri;
private String url;
private Account account;
private String in_reply_to_id;
private String in_reply_to_account_id;
private Status reblog;
private Date created_at;
private int reblogs_count;
private int favourites_count;
2018-08-19 15:21:39 +02:00
private int replies_count;
2017-05-05 16:36:04 +02:00
private boolean reblogged;
private boolean favourited;
2018-02-15 07:55:24 +01:00
private boolean muted;
private boolean pinned;
2017-05-05 16:36:04 +02:00
private boolean sensitive;
private boolean bookmarked;
2017-05-05 16:36:04 +02:00
private String visibility;
private boolean attachmentShown = false;
2017-06-07 16:52:53 +02:00
private boolean spoilerShown = false;
private ArrayList<Attachment> media_attachments;
private List<Mention> mentions;
2017-10-20 06:57:53 +02:00
private List<Emojis> emojis;
private List<Tag> tags;
private Application application;
2017-12-20 13:57:28 +01:00
private Card card;
private String language;
private boolean isTranslated = false;
2017-10-20 19:58:46 +02:00
private boolean isEmojiFound = false;
2017-12-03 14:17:57 +01:00
private boolean isEmojiTranslateFound = false;
2017-12-03 10:56:54 +01:00
private boolean isClickable = false;
private boolean isTranslationShown = false;
2017-09-08 18:30:49 +02:00
private boolean isNew = false;
private boolean isVisible = true;
private boolean fetchMore = false;
2017-12-03 10:56:54 +01:00
private Status status;
2017-12-03 14:17:57 +01:00
private String content, contentCW, contentTranslated;
2018-08-17 11:53:21 +02:00
private SpannableString contentSpan, displayNameSpan, contentSpanCW, contentSpanTranslated;
private RetrieveFeedsAsyncTask.Type type;
private int itemViewType;
2017-12-03 10:56:54 +01:00
public Status(){
this.status = this;
}
2018-10-29 18:32:55 +01:00
private List<String> conversationProfilePicture;
2018-11-07 11:03:32 +01:00
private String webviewURL = null;
2017-05-05 16:36:04 +02:00
2017-05-26 17:20:36 +02:00
protected Status(Parcel in) {
id = in.readString();
uri = in.readString();
url = in.readString();
in_reply_to_id = in.readString();
in_reply_to_account_id = in.readString();
reblog = in.readParcelable(Status.class.getClassLoader());
account = in.readParcelable(Account.class.getClassLoader());
mentions = in.readArrayList(Mention.class.getClassLoader());
2018-11-15 19:09:44 +01:00
media_attachments = in.readArrayList(Attachment.class.getClassLoader());
emojis = in.readArrayList(Emojis.class.getClassLoader());
tags = in.readArrayList(Tag.class.getClassLoader());
2017-05-26 17:20:36 +02:00
content = in.readString();
2018-11-15 19:09:44 +01:00
created_at = (java.util.Date) in.readSerializable();
2017-12-03 14:17:57 +01:00
contentTranslated = in.readString();
2017-05-26 17:20:36 +02:00
reblogs_count = in.readInt();
itemViewType = in.readInt();
2017-05-26 17:20:36 +02:00
favourites_count = in.readInt();
2018-08-19 15:21:39 +02:00
replies_count = in.readInt();
2017-05-26 17:20:36 +02:00
reblogged = in.readByte() != 0;
favourited = in.readByte() != 0;
2018-02-15 07:55:24 +01:00
muted = in.readByte() != 0;
2017-05-26 17:20:36 +02:00
sensitive = in.readByte() != 0;
2017-12-03 14:17:57 +01:00
contentCW = in.readString();
2017-05-26 17:20:36 +02:00
visibility = in.readString();
language = in.readString();
2017-05-26 17:20:36 +02:00
attachmentShown = in.readByte() != 0;
2017-06-07 16:52:53 +02:00
spoilerShown = in.readByte() != 0;
isTranslated = in.readByte() != 0;
isTranslationShown = in.readByte() != 0;
2017-09-08 18:30:49 +02:00
isNew = in.readByte() != 0;
pinned = in.readByte() != 0;
2017-05-26 17:20:36 +02:00
}
2018-11-15 19:09:44 +01:00
@Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeString(id);
dest.writeString(uri);
dest.writeString(url);
dest.writeString(in_reply_to_id);
dest.writeString(in_reply_to_account_id);
dest.writeParcelable(reblog, flags);
dest.writeParcelable(account, flags);
dest.writeList(mentions);
dest.writeList(media_attachments);
dest.writeList(emojis);
dest.writeList(tags);
dest.writeString(content);
dest.writeSerializable(created_at);
dest.writeString(contentTranslated);
dest.writeInt(reblogs_count);
dest.writeInt(itemViewType);
dest.writeInt(favourites_count);
dest.writeInt(replies_count);
dest.writeByte((byte) (reblogged ? 1 : 0));
dest.writeByte((byte) (favourited ? 1 : 0));
dest.writeByte((byte) (muted ? 1 : 0));
dest.writeByte((byte) (sensitive ? 1 : 0));
dest.writeString(contentCW);
dest.writeString(visibility);
dest.writeString(language);
dest.writeByte((byte) (attachmentShown ? 1 : 0));
dest.writeByte((byte) (spoilerShown ? 1 : 0));
dest.writeByte((byte) (isTranslated ? 1 : 0));
dest.writeByte((byte) (isTranslationShown ? 1 : 0));
dest.writeByte((byte) (isNew ? 1 : 0));
dest.writeByte((byte) (pinned ? 1 : 0));
}
2017-12-03 10:56:54 +01:00
2017-05-26 17:20:36 +02:00
public static final Creator<Status> CREATOR = new Creator<Status>() {
@Override
public Status createFromParcel(Parcel in) {
return new Status(in);
}
@Override
public Status[] newArray(int size) {
return new Status[size];
}
};
2017-05-05 16:36:04 +02:00
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getUri() {
return uri;
}
public void setUri(String uri) {
this.uri = uri;
}
public String getUrl() {
return url;
}
public void setUrl(String url) {
this.url = url;
}
public Account getAccount() {
return account;
}
public void setAccount(Account account) {
this.account = account;
}
public String getIn_reply_to_id() {
return in_reply_to_id;
}
public void setIn_reply_to_id(String in_reply_to_id) {
this.in_reply_to_id = in_reply_to_id;
}
public String getIn_reply_to_account_id() {
return in_reply_to_account_id;
}
public void setIn_reply_to_account_id(String in_reply_to_account_id) {
this.in_reply_to_account_id = in_reply_to_account_id;
}
public String getContent() {
return content;
}
public void setContent(String content) {
//Remove UTM by default
this.content = content.replaceAll("&amp;utm_\\w+=[0-9a-zA-Z._-]*", "");
this.content = this.content.replaceAll("&utm_\\w+=[0-9a-zA-Z._-]*", "");
this.content = this.content.replaceAll("\\?utm_\\w+=[0-9a-zA-Z._-]*", "?");
2017-05-05 16:36:04 +02:00
}
public Status getReblog() {
return reblog;
}
public void setReblog(Status reblog) {
this.reblog = reblog;
}
public int getReblogs_count() {
return reblogs_count;
}
public void setReblogs_count(int reblogs_count) {
this.reblogs_count = reblogs_count;
}
public Date getCreated_at() {
return created_at;
}
public void setCreated_at(Date created_at) {
this.created_at = created_at;
}
public int getFavourites_count() {
return favourites_count;
}
public void setFavourites_count(int favourites_count) {
this.favourites_count = favourites_count;
}
2018-08-17 11:53:21 +02:00
public SpannableString getDisplayNameSpan(){
2018-08-17 16:22:26 +02:00
return this.displayNameSpan;
2018-08-17 11:53:21 +02:00
}
public void setDisplayNameSpan(SpannableString displayNameSpan){
this.displayNameSpan = displayNameSpan;
}
2017-05-05 16:36:04 +02:00
public boolean isReblogged() {
return reblogged;
}
public void setReblogged(boolean reblogged) {
this.reblogged = reblogged;
}
public boolean isFavourited() {
return favourited;
}
public void setFavourited(boolean favourited) {
this.favourited = favourited;
}
public void setPinned(boolean pinned) { this.pinned = pinned; }
public boolean isPinned() { return pinned; }
2017-05-05 16:36:04 +02:00
public boolean isSensitive() {
return sensitive;
}
public void setSensitive(boolean sensitive) {
this.sensitive = sensitive;
}
public String getSpoiler_text() {
2017-12-03 14:17:57 +01:00
return contentCW;
2017-05-05 16:36:04 +02:00
}
public void setSpoiler_text(String spoiler_text) {
2017-12-03 14:17:57 +01:00
this.contentCW = spoiler_text;
2017-05-05 16:36:04 +02:00
}
public ArrayList<Attachment> getMedia_attachments() {
2017-05-05 16:36:04 +02:00
return media_attachments;
}
public void setMedia_attachments(ArrayList<Attachment> media_attachments) {
2017-05-05 16:36:04 +02:00
this.media_attachments = media_attachments;
}
public List<Mention> getMentions() {
return mentions;
}
public void setMentions(List<Mention> mentions) {
this.mentions = mentions;
}
public List<Tag> getTags() {
return tags;
}
public void setTags(List<Tag> tags) {
this.tags = tags;
}
public Application getApplication() {
return application;
}
public void setApplication(Application application) {
this.application = application;
}
public String getVisibility() {
return visibility;
}
public void setVisibility(String visibility) {
this.visibility = visibility;
}
public boolean isAttachmentShown() {
return attachmentShown;
}
public void setAttachmentShown(boolean attachmentShown) {
this.attachmentShown = attachmentShown;
}
2017-05-26 17:20:36 +02:00
@Override
public int describeContents() {
return 0;
}
2017-06-07 16:52:53 +02:00
public boolean isSpoilerShown() {
return spoilerShown;
}
public void setSpoilerShown(boolean spoilerShown) {
this.spoilerShown = spoilerShown;
2017-05-26 17:20:36 +02:00
}
public String getLanguage() {
return language;
}
public void setLanguage(String language) {
this.language = language;
}
public boolean isTranslated() {
return isTranslated;
}
public void setTranslated(boolean translated) {
isTranslated = translated;
}
public boolean isTranslationShown() {
return isTranslationShown;
}
public void setTranslationShown(boolean translationShown) {
isTranslationShown = translationShown;
}
2017-12-03 14:17:57 +01:00
public String getContentTranslated() {
return contentTranslated;
}
2017-12-03 14:17:57 +01:00
public void setContentTranslated(String content_translated) {
this.contentTranslated = content_translated;
}
2017-08-16 18:08:16 +02:00
2017-09-08 18:30:49 +02:00
public boolean isNew() {
return isNew;
}
public void setNew(boolean aNew) {
isNew = aNew;
}
2017-09-18 20:32:36 +02:00
public boolean isVisible() {
return isVisible;
}
public void setVisible(boolean visible) {
isVisible = visible;
}
2017-10-20 06:54:21 +02:00
2017-10-20 06:57:53 +02:00
public List<Emojis> getEmojis() {
2017-10-20 06:54:21 +02:00
return emojis;
}
2017-10-20 06:57:53 +02:00
public void setEmojis(List<Emojis> emojis) {
2017-10-20 06:54:21 +02:00
this.emojis = emojis;
}
2017-10-20 19:58:46 +02:00
2017-12-03 10:56:54 +01:00
public boolean isEmojiFound() {
return isEmojiFound;
2017-10-20 19:58:46 +02:00
}
2018-11-15 19:09:44 +01:00
2017-12-03 10:56:54 +01:00
public void setEmojiFound(boolean emojiFound) {
isEmojiFound = emojiFound;
2017-10-20 19:58:46 +02:00
}
2017-12-03 10:56:54 +01:00
2018-11-16 07:33:19 +01:00
public static void transform(Context context, Status status){
2017-12-03 10:56:54 +01:00
if( ((Activity)context).isFinishing() || status == null)
2018-01-11 07:32:19 +01:00
return;
2017-12-03 11:14:52 +01:00
SpannableString spannableStringContent, spannableStringCW;
2018-04-28 16:54:06 +02:00
if( (status.getReblog() != null && status.getReblog().getContent() == null) || (status.getReblog() == null && status.getContent() == null))
return;
2018-09-01 12:42:22 +02:00
spannableStringContent = new SpannableString(status.getReblog() != null ?status.getReblog().getContent():status.getContent());
2017-12-03 10:56:54 +01:00
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N)
2018-09-19 09:08:15 +02:00
spannableStringCW = new SpannableString(Html.fromHtml(status.getReblog() != null ?status.getReblog().getSpoiler_text():status.getSpoiler_text(), Html.FROM_HTML_MODE_LEGACY));
2017-12-03 10:56:54 +01:00
else
//noinspection deprecation
spannableStringCW = new SpannableString(Html.fromHtml(status.getReblog() != null ?status.getReblog().getSpoiler_text():status.getSpoiler_text()));
2018-11-15 19:09:44 +01:00
if( spannableStringContent.length() > 0)
status.setContentSpan(treatment(context, spannableStringContent, status));
if( spannableStringCW.length() > 0)
status.setContentSpanCW(treatment(context, spannableStringCW, status));
2018-11-16 07:33:19 +01:00
2018-11-15 19:09:44 +01:00
status.setClickable(true);
2017-12-03 11:14:52 +01:00
}
2018-11-16 07:33:19 +01:00
public static void transformTranslation(Context context, Status status){
2017-12-03 11:14:52 +01:00
if( ((Activity)context).isFinishing() || status == null)
2018-01-11 07:32:19 +01:00
return;
2018-04-28 16:54:06 +02:00
if( (status.getReblog() != null && status.getReblog().getContent() == null) || (status.getReblog() == null && status.getContent() == null))
return;
2017-12-03 11:14:52 +01:00
SpannableString spannableStringTranslated;
2017-12-03 10:56:54 +01:00
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N)
2018-09-19 09:08:15 +02:00
spannableStringTranslated = new SpannableString(Html.fromHtml(status.getContentTranslated(), Html.FROM_HTML_MODE_LEGACY));
2017-12-03 10:56:54 +01:00
else
//noinspection deprecation
2017-12-03 14:17:57 +01:00
spannableStringTranslated = new SpannableString(Html.fromHtml(status.getContentTranslated()));
2017-12-03 10:56:54 +01:00
2018-11-15 19:09:44 +01:00
status.setContentSpanTranslated(treatment(context, spannableStringTranslated, status));
2018-11-16 07:33:19 +01:00
String displayName;
if( status.getReblog() != null){
displayName = status.getReblog().getAccount().getDisplay_name();
}else {
displayName = status.getAccount().getDisplay_name();
}
SpannableString displayNameSpan = new SpannableString(displayName);
status.setDisplayNameSpan(displayNameSpan);
2017-12-03 10:56:54 +01:00
}
2018-11-15 19:19:24 +01:00
public static void makeEmojis(final Context context, final OnRetrieveEmojiInterface listener, Status status){
2017-12-03 10:56:54 +01:00
2018-01-11 07:32:19 +01:00
if( ((Activity)context).isFinishing() )
return;
if( status.getAccount() == null)
return;
2018-09-07 18:51:47 +02:00
if( status.getReblog() != null && status.getReblog().getEmojis() == null)
return;
if( status.getReblog() == null && status.getEmojis() == null)
return;
2017-12-03 10:56:54 +01:00
final List<Emojis> emojis = status.getReblog() != null ? status.getReblog().getEmojis() : status.getEmojis();
2018-09-08 15:34:25 +02:00
final List<Emojis> emojisAccounts = status.getReblog() != null ?status.getReblog().getAccount().getEmojis():status.getAccount().getEmojis();
2018-08-17 16:22:26 +02:00
2018-11-15 19:09:44 +01:00
status.getAccount().makeEmojisAccount(context, null, status.getAccount());
2018-11-16 07:33:19 +01:00
SpannableString displayNameSpan = status.getDisplayNameSpan();
SpannableString contentSpan = status.getContentSpan();
SpannableString contentSpanCW = status.getContentSpanCW();
2018-08-17 16:22:26 +02:00
if( emojisAccounts != null)
emojis.addAll(emojisAccounts);
2017-12-03 10:56:54 +01:00
if( emojis != null && emojis.size() > 0 ) {
final int[] i = {0};
for (final Emojis emoji : emojis) {
Glide.with(context)
.asBitmap()
.load(emoji.getUrl())
.listener(new RequestListener<Bitmap>() {
@Override
public boolean onResourceReady(Bitmap resource, Object model, Target<Bitmap> target, DataSource dataSource, boolean isFirstResource) {
return false;
}
@Override
public boolean onLoadFailed(@Nullable GlideException e, Object model, Target target, boolean isFirstResource) {
i[0]++;
if( i[0] == (emojis.size())) {
2017-12-03 14:17:57 +01:00
listener.onRetrieveEmoji(status,false);
2017-12-03 10:56:54 +01:00
}
return false;
}
})
.into(new SimpleTarget<Bitmap>() {
@Override
2018-04-28 16:54:06 +02:00
public void onResourceReady(@NonNull Bitmap resource, Transition<? super Bitmap> transition) {
2017-12-03 10:56:54 +01:00
final String targetedEmoji = ":" + emoji.getShortcode() + ":";
2018-11-16 07:33:19 +01:00
if (contentSpan != null && contentSpan.toString().contains(targetedEmoji)) {
2017-12-03 10:56:54 +01:00
//emojis can be used several times so we have to loop
for (int startPosition = -1; (startPosition = contentSpan.toString().indexOf(targetedEmoji, startPosition + 1)) != -1; startPosition++) {
2017-12-03 10:56:54 +01:00
final int endPosition = startPosition + targetedEmoji.length();
2018-08-17 11:53:21 +02:00
if( endPosition <= contentSpan.toString().length() && endPosition >= startPosition)
2018-04-28 16:54:06 +02:00
contentSpan.setSpan(
2017-12-03 10:56:54 +01:00
new ImageSpan(context,
Bitmap.createScaledBitmap(resource, (int) Helper.convertDpToPixel(20, context),
(int) Helper.convertDpToPixel(20, context), false)), startPosition,
endPosition, Spannable.SPAN_INCLUSIVE_EXCLUSIVE);
}
}
2018-11-16 07:33:19 +01:00
if (displayNameSpan != null && displayNameSpan.toString().contains(targetedEmoji)) {
2018-08-17 11:53:21 +02:00
//emojis can be used several times so we have to loop
for (int startPosition = -1; (startPosition = displayNameSpan.toString().indexOf(targetedEmoji, startPosition + 1)) != -1; startPosition++) {
final int endPosition = startPosition + targetedEmoji.length();
if(endPosition <= displayNameSpan.toString().length() && endPosition >= startPosition)
displayNameSpan.setSpan(
new ImageSpan(context,
Bitmap.createScaledBitmap(resource, (int) Helper.convertDpToPixel(20, context),
(int) Helper.convertDpToPixel(20, context), false)), startPosition,
endPosition, Spannable.SPAN_INCLUSIVE_EXCLUSIVE);
}
}
2018-11-16 07:33:19 +01:00
status.setDisplayNameSpan(displayNameSpan);
if (contentSpanCW != null && contentSpanCW.toString().contains(targetedEmoji)) {
2017-12-03 10:56:54 +01:00
//emojis can be used several times so we have to loop
for (int startPosition = -1; (startPosition = contentSpanCW.toString().indexOf(targetedEmoji, startPosition + 1)) != -1; startPosition++) {
2017-12-03 10:56:54 +01:00
final int endPosition = startPosition + targetedEmoji.length();
2018-08-17 11:53:21 +02:00
if( endPosition <= contentSpan.toString().length() && endPosition >= startPosition)
2018-04-28 16:54:06 +02:00
contentSpanCW.setSpan(
2017-12-03 10:56:54 +01:00
new ImageSpan(context,
Bitmap.createScaledBitmap(resource, (int) Helper.convertDpToPixel(20, context),
(int) Helper.convertDpToPixel(20, context), false)), startPosition,
endPosition, Spannable.SPAN_INCLUSIVE_EXCLUSIVE);
}
}
2017-12-03 14:17:57 +01:00
i[0]++;
if( i[0] == (emojis.size())) {
2018-11-15 19:09:44 +01:00
status.setContentSpan(contentSpan);
status.setContentSpanCW(contentSpanCW);
2018-11-15 19:19:24 +01:00
status.setEmojiFound(true);
2017-12-03 14:17:57 +01:00
listener.onRetrieveEmoji(status, false);
}
}
});
}
}
}
2018-11-15 19:19:24 +01:00
public static void makeEmojisTranslation(final Context context, final OnRetrieveEmojiInterface listener, Status status){
2017-12-03 14:17:57 +01:00
2018-01-11 07:32:19 +01:00
if( ((Activity)context).isFinishing() )
return;
2017-12-03 14:17:57 +01:00
SpannableString spannableStringTranslated = null;
2018-05-12 09:41:47 +02:00
SharedPreferences sharedpreferences = context.getSharedPreferences(Helper.APP_PREFS, Context.MODE_PRIVATE);
2017-12-03 14:17:57 +01:00
if( status.getContentTranslated() != null) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N)
2018-09-19 09:08:15 +02:00
spannableStringTranslated = new SpannableString(Html.fromHtml(status.getContentTranslated(), Html.FROM_HTML_MODE_LEGACY));
2017-12-03 14:17:57 +01:00
else
//noinspection deprecation
spannableStringTranslated = new SpannableString(Html.fromHtml(status.getContentTranslated()));
}
final List<Emojis> emojis = status.getReblog() != null ? status.getReblog().getEmojis() : status.getEmojis();
if( emojis != null && emojis.size() > 0 ) {
final int[] i = {0};
for (final Emojis emoji : emojis) {
final SpannableString finalSpannableStringTranslated = spannableStringTranslated;
Glide.with(context)
.asBitmap()
.load(emoji.getUrl())
.listener(new RequestListener<Bitmap>() {
@Override
public boolean onResourceReady(Bitmap resource, Object model, Target<Bitmap> target, DataSource dataSource, boolean isFirstResource) {
return false;
}
@Override
public boolean onLoadFailed(@Nullable GlideException e, Object model, Target target, boolean isFirstResource) {
i[0]++;
if( i[0] == (emojis.size())) {
if( finalSpannableStringTranslated != null)
status.setContentSpanTranslated(finalSpannableStringTranslated);
listener.onRetrieveEmoji(status, true);
}
return false;
}
})
.into(new SimpleTarget<Bitmap>() {
@Override
2018-08-17 16:22:26 +02:00
public void onResourceReady(@NonNull Bitmap resource, Transition<? super Bitmap> transition) {
2017-12-03 14:17:57 +01:00
final String targetedEmoji = ":" + emoji.getShortcode() + ":";
2017-12-03 11:14:52 +01:00
if (finalSpannableStringTranslated != null && finalSpannableStringTranslated.toString().contains(targetedEmoji)) {
2017-12-03 10:56:54 +01:00
//emojis can be used several times so we have to loop
2017-12-03 11:14:52 +01:00
for (int startPosition = -1; (startPosition = finalSpannableStringTranslated.toString().indexOf(targetedEmoji, startPosition + 1)) != -1; startPosition++) {
2017-12-03 10:56:54 +01:00
final int endPosition = startPosition + targetedEmoji.length();
2018-08-17 16:22:26 +02:00
if( endPosition <= finalSpannableStringTranslated.toString().length() && endPosition >= startPosition)
2018-04-28 16:54:06 +02:00
finalSpannableStringTranslated.setSpan(
2017-12-03 10:56:54 +01:00
new ImageSpan(context,
Bitmap.createScaledBitmap(resource, (int) Helper.convertDpToPixel(20, context),
(int) Helper.convertDpToPixel(20, context), false)), startPosition,
endPosition, Spannable.SPAN_INCLUSIVE_EXCLUSIVE);
}
}
i[0]++;
if( i[0] == (emojis.size())) {
2017-12-03 11:14:52 +01:00
if( finalSpannableStringTranslated != null)
status.setContentSpanTranslated(finalSpannableStringTranslated);
2018-11-15 19:19:24 +01:00
status.setEmojiTranslateFound(true);
2017-12-03 14:17:57 +01:00
listener.onRetrieveEmoji(status, true);
2017-12-03 10:56:54 +01:00
}
}
});
}
}
2017-10-20 19:58:46 +02:00
}
2017-12-03 10:56:54 +01:00
2018-11-15 19:09:44 +01:00
private static SpannableString treatment(final Context context, final SpannableString spannableString, Status status){
2017-12-03 10:56:54 +01:00
URLSpan[] urls = spannableString.getSpans(0, spannableString.length(), URLSpan.class);
for(URLSpan span : urls)
spannableString.removeSpan(span);
2018-11-15 19:09:44 +01:00
List<Mention> mentions = status.getReblog() != null ? status.getReblog().getMentions() : status.getMentions();
2018-09-25 17:49:11 +02:00
SharedPreferences sharedpreferences = context.getSharedPreferences(Helper.APP_PREFS, Context.MODE_PRIVATE);
int theme = sharedpreferences.getInt(Helper.SET_THEME, Helper.THEME_DARK);
Matcher matcher;
2018-09-15 12:43:36 +02:00
Pattern linkPattern = Pattern.compile("<a href=\"([^\"]*)\"[^>]*(((?!<\\/a).)*)<\\/a>");
matcher = linkPattern.matcher(spannableString);
HashMap<String, String> targetedURL = new HashMap<>();
while (matcher.find()){
String key;
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N)
key = new SpannableString(Html.fromHtml(matcher.group(2), Html.FROM_HTML_MODE_LEGACY)).toString();
else
//noinspection deprecation
key = new SpannableString(Html.fromHtml(matcher.group(2))).toString();
key = key.substring(1);
2018-10-11 07:41:26 +02:00
if( !key.startsWith("#") && !key.startsWith("@") && !key.trim().equals("") && !matcher.group(1).contains("search?tag=")) {
2018-09-25 17:49:11 +02:00
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
targetedURL.put(key, Html.fromHtml(matcher.group(1), Html.FROM_HTML_MODE_LEGACY).toString());
}
else
targetedURL.put(key, Html.fromHtml(matcher.group(1)).toString());
}
2018-09-15 12:43:36 +02:00
}
2018-09-15 14:36:19 +02:00
String currentInstance = Helper.getLiveInstance(context);
2018-09-15 09:04:41 +02:00
//Get url to account that are unknown
2018-09-22 19:13:55 +02:00
Pattern aLink = Pattern.compile("(<\\s?a\\s?href=\"https?:\\/\\/([\\da-z\\.-]+\\.[a-z\\.]{2,10})\\/(@[\\/\\w._-]*)\"\\s?[^.]*<\\s?\\/\\s?a\\s?>)");
2018-09-01 12:42:22 +02:00
Matcher matcherALink = aLink.matcher(spannableString.toString());
2018-09-15 09:04:41 +02:00
ArrayList<Account> accountsMentionUnknown = new ArrayList<>();
while (matcherALink.find()){
String acct = matcherALink.group(3).replace("@","");
String instance = matcherALink.group(2);
2018-09-15 14:36:19 +02:00
boolean addAccount = true;
for(Mention mention: mentions){
String[] accountMentionAcct = mention.getAcct().split("@");
//Different isntance
if( accountMentionAcct.length > 1){
if( mention.getAcct().equals(acct+"@"+instance))
addAccount = false;
}else {
if( (mention.getUsername()+"@"+currentInstance).equals(acct+"@"+instance))
addAccount = false;
}
}
2018-09-16 16:23:35 +02:00
if( addAccount) {
Account account = new Account();
account.setAcct(acct);
account.setInstance(instance);
accountsMentionUnknown.add(account);
}
2018-09-15 09:04:41 +02:00
}
2018-09-22 19:13:55 +02:00
aLink = Pattern.compile("(<\\s?a\\s?href=\"(https?:\\/\\/[\\da-z\\.-]+\\.[a-z\\.]{2,10}[\\/]?[^\"@(\\/tags\\/)]*)\"\\s?[^.]*<\\s?\\/\\s?a\\s?>)");
2018-09-15 09:04:41 +02:00
matcherALink = aLink.matcher(spannableString.toString());
2018-09-01 12:42:22 +02:00
while (matcherALink.find()){
int matchStart = matcherALink.start();
int matchEnd = matcherALink.end();
final String url = spannableString.toString().substring(matcherALink.start(1), matcherALink.end(1));
2018-09-25 17:49:11 +02:00
2018-09-01 12:42:22 +02:00
if( matchEnd <= spannableString.toString().length() && matchEnd >= matchStart)
spannableString.setSpan(new ClickableSpan() {
@Override
public void onClick(View textView) {
String finalUrl = url;
if( !url.startsWith("http://") && ! url.startsWith("https://"))
finalUrl = "http://" + url;
Helper.openBrowser(context, finalUrl);
}
@Override
public void updateDrawState(TextPaint ds) {
super.updateDrawState(ds);
ds.setUnderlineText(false);
if (theme == THEME_DARK)
ds.setColor(ContextCompat.getColor(context, R.color.dark_link_toot));
else if (theme == THEME_BLACK)
ds.setColor(ContextCompat.getColor(context, R.color.black_link_toot));
else if (theme == THEME_LIGHT)
ds.setColor(ContextCompat.getColor(context, R.color.mastodonC4));
2018-09-01 12:42:22 +02:00
}
},
matchStart, matchEnd,
Spanned.SPAN_INCLUSIVE_EXCLUSIVE);
2018-11-02 14:42:29 +01:00
2018-09-01 12:42:22 +02:00
}
SpannableString spannableStringT;
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N)
2018-09-19 09:08:15 +02:00
spannableStringT = new SpannableString(Html.fromHtml(spannableString.toString().replaceAll("^<p>","").replaceAll("<p>","<br/><br/>").replaceAll("</p>",""), Html.FROM_HTML_MODE_LEGACY));
2018-09-01 12:42:22 +02:00
else
//noinspection deprecation
spannableStringT = new SpannableString(Html.fromHtml(spannableString.toString().replaceAll("^<p>","").replaceAll("<p>","<br/><br/>").replaceAll("</p>","")));
2018-11-15 19:19:24 +01:00
2018-10-10 07:58:28 +02:00
URLSpan[] spans = spannableStringT.getSpans(0, spannableStringT.length(), URLSpan.class);
for (URLSpan span : spans) {
spannableStringT.removeSpan(span);
}
2018-08-14 18:27:21 +02:00
matcher = Helper.twitterPattern.matcher(spannableStringT);
2018-08-14 18:27:21 +02:00
while (matcher.find()){
int matchStart = matcher.start(2);
int matchEnd = matcher.end();
final String twittername = matcher.group(2);
if( matchEnd <= spannableStringT.toString().length() && matchEnd >= matchStart)
spannableStringT.setSpan(new ClickableSpan() {
2018-08-14 18:27:21 +02:00
@Override
public void onClick(View textView) {
Intent intent = new Intent(Intent.ACTION_VIEW, Uri.parse("https://twitter.com/"+twittername.substring(1).replace("@twitter.com","")));
context.startActivity(intent);
}
@Override
public void updateDrawState(TextPaint ds) {
super.updateDrawState(ds);
ds.setUnderlineText(false);
if (theme == THEME_DARK)
ds.setColor(ContextCompat.getColor(context, R.color.dark_link_toot));
else if (theme == THEME_BLACK)
ds.setColor(ContextCompat.getColor(context, R.color.black_link_toot));
else if (theme == THEME_LIGHT)
ds.setColor(ContextCompat.getColor(context, R.color.mastodonC4));
2018-08-14 18:27:21 +02:00
}
}, matchStart, matchEnd, Spanned.SPAN_INCLUSIVE_EXCLUSIVE);
}
2018-09-15 09:04:41 +02:00
if( accountsMentionUnknown.size() > 0 ) {
for(Account account: accountsMentionUnknown){
String targetedAccount = "@" + account.getAcct();
if (spannableStringT.toString().toLowerCase().contains(targetedAccount.toLowerCase())) {
//Accounts can be mentioned several times so we have to loop
for(int startPosition = -1 ; (startPosition = spannableStringT.toString().toLowerCase().indexOf(targetedAccount.toLowerCase(), startPosition + 1)) != -1 ; startPosition++){
int endPosition = startPosition + targetedAccount.length();
if( endPosition <= spannableStringT.toString().length() && endPosition >= startPosition)
spannableStringT.setSpan(new ClickableSpan() {
@Override
public void onClick(View textView) {
CrossActions.doCrossProfile(context,account);
}
@Override
public void updateDrawState(TextPaint ds) {
super.updateDrawState(ds);
ds.setUnderlineText(false);
if (theme == THEME_DARK)
ds.setColor(ContextCompat.getColor(context, R.color.dark_link_toot));
else if (theme == THEME_BLACK)
ds.setColor(ContextCompat.getColor(context, R.color.black_link_toot));
else if (theme == THEME_LIGHT)
ds.setColor(ContextCompat.getColor(context, R.color.mastodonC4));
2018-09-15 09:04:41 +02:00
}
},
startPosition, endPosition,
Spanned.SPAN_INCLUSIVE_EXCLUSIVE);
}
}
}
}
2018-09-15 12:43:36 +02:00
if( targetedURL.size() > 0 ){
Iterator it = targetedURL.entrySet().iterator();
while (it.hasNext()) {
Map.Entry pair = (Map.Entry)it.next();
String key = (String) pair.getKey();
String url = (String) pair.getValue();
if (spannableStringT.toString().toLowerCase().contains(key.toLowerCase())) {
//Accounts can be mentioned several times so we have to loop
for(int startPosition = -1 ; (startPosition = spannableStringT.toString().toLowerCase().indexOf(key.toLowerCase(), startPosition + 1)) != -1 ; startPosition++){
int endPosition = startPosition + key.length();
2018-10-10 07:58:28 +02:00
2018-09-29 14:11:42 +02:00
if( endPosition <= spannableStringT.toString().length() && endPosition >= startPosition) {
2018-09-15 12:43:36 +02:00
spannableStringT.setSpan(new ClickableSpan() {
@Override
public void onClick(View textView) {
String finalUrl = url;
2018-09-22 19:13:55 +02:00
Pattern link = Pattern.compile("https?:\\/\\/([\\da-z\\.-]+\\.[a-z\\.]{2,10})\\/(@[\\w._-]*[0-9]*)(\\/[0-9]{1,})?$");
2018-09-15 12:43:36 +02:00
Matcher matcherLink = link.matcher(url);
if( matcherLink.find()){
Intent intent = new Intent(context, MainActivity.class);
intent.putExtra(INTENT_ACTION, SEARCH_REMOTE);
intent.putExtra(SEARCH_URL, url);
context.startActivity(intent);
}else {
2018-09-29 14:11:42 +02:00
link = Pattern.compile("(https?:\\/\\/[\\da-z\\.-]+\\.[a-z\\.]{2,10})\\/videos\\/watch\\/(\\w{8}-\\w{4}-\\w{4}-\\w{4}-\\w{12})$");
matcherLink = link.matcher(url);
if( matcherLink.find()){ //Peertubee video
2018-10-14 17:36:18 +02:00
Intent intent = new Intent(context, PeertubeActivity.class);
2018-09-29 14:11:42 +02:00
Bundle b = new Bundle();
2018-10-14 17:36:18 +02:00
String url = matcherLink.group(1) + "/videos/watch/" + matcherLink.group(2);
2018-09-29 14:11:42 +02:00
b.putString("peertubeLinkToFetch", url);
2018-10-14 17:36:18 +02:00
b.putString("peertube_instance", matcherLink.group(1).replace("https://","").replace("http://",""));
b.putString("video_id", matcherLink.group(2));
2018-09-29 14:11:42 +02:00
intent.putExtras(b);
context.startActivity(intent);
}else {
if( !url.startsWith("http://") && ! url.startsWith("https://"))
finalUrl = "http://" + url;
Helper.openBrowser(context, finalUrl);
}
2018-09-15 12:43:36 +02:00
}
}
@Override
public void updateDrawState(TextPaint ds) {
super.updateDrawState(ds);
ds.setUnderlineText(false);
if (theme == THEME_DARK)
ds.setColor(ContextCompat.getColor(context, R.color.dark_link_toot));
else if (theme == THEME_BLACK)
ds.setColor(ContextCompat.getColor(context, R.color.black_link_toot));
else if (theme == THEME_LIGHT)
ds.setColor(ContextCompat.getColor(context, R.color.mastodonC4));
2018-09-15 12:43:36 +02:00
}
},
startPosition, endPosition,
Spanned.SPAN_INCLUSIVE_EXCLUSIVE);
2018-09-29 14:11:42 +02:00
}
2018-09-15 12:43:36 +02:00
}
}
it.remove();
}
}
2017-12-03 10:56:54 +01:00
//Deals with mention to make them clickable
if( mentions != null && mentions.size() > 0 ) {
//Looping through accounts which are mentioned
for (final Mention mention : mentions) {
String targetedAccount = "@" + mention.getUsername();
2018-09-01 12:42:22 +02:00
if (spannableStringT.toString().toLowerCase().contains(targetedAccount.toLowerCase())) {
2017-12-03 10:56:54 +01:00
//Accounts can be mentioned several times so we have to loop
2018-09-01 12:42:22 +02:00
for(int startPosition = -1 ; (startPosition = spannableStringT.toString().toLowerCase().indexOf(targetedAccount.toLowerCase(), startPosition + 1)) != -1 ; startPosition++){
2017-12-03 10:56:54 +01:00
int endPosition = startPosition + targetedAccount.length();
2018-09-01 12:42:22 +02:00
if( endPosition <= spannableStringT.toString().length() && endPosition >= startPosition)
spannableStringT.setSpan(new ClickableSpan() {
2017-12-03 10:56:54 +01:00
@Override
public void onClick(View textView) {
2018-09-15 14:36:19 +02:00
Intent intent = new Intent(context, ShowAccountActivity.class);
Bundle b = new Bundle();
b.putString("accountId", mention.getId());
intent.putExtras(b);
context.startActivity(intent);
2017-12-03 10:56:54 +01:00
}
@Override
public void updateDrawState(TextPaint ds) {
super.updateDrawState(ds);
ds.setUnderlineText(false);
if (theme == THEME_DARK)
ds.setColor(ContextCompat.getColor(context, R.color.dark_link_toot));
else if (theme == THEME_BLACK)
ds.setColor(ContextCompat.getColor(context, R.color.black_link_toot));
else if (theme == THEME_LIGHT)
ds.setColor(ContextCompat.getColor(context, R.color.mastodonC4));
2017-12-03 10:56:54 +01:00
}
},
startPosition, endPosition,
Spanned.SPAN_INCLUSIVE_EXCLUSIVE);
}
}
}
}
2018-09-01 12:42:22 +02:00
matcher = Helper.hashtagPattern.matcher(spannableStringT);
2017-12-03 10:56:54 +01:00
while (matcher.find()){
int matchStart = matcher.start(1);
int matchEnd = matcher.end();
2018-09-01 12:42:22 +02:00
final String tag = spannableStringT.toString().substring(matchStart, matchEnd);
if( matchEnd <= spannableStringT.toString().length() && matchEnd >= matchStart)
spannableStringT.setSpan(new ClickableSpan() {
2018-04-28 16:54:06 +02:00
@Override
public void onClick(View textView) {
Intent intent = new Intent(context, HashTagActivity.class);
Bundle b = new Bundle();
b.putString("tag", tag.substring(1));
intent.putExtras(b);
context.startActivity(intent);
}
@Override
public void updateDrawState(TextPaint ds) {
super.updateDrawState(ds);
ds.setUnderlineText(false);
if (theme == THEME_DARK)
ds.setColor(ContextCompat.getColor(context, R.color.dark_link_toot));
else if (theme == THEME_BLACK)
ds.setColor(ContextCompat.getColor(context, R.color.black_link_toot));
else if (theme == THEME_LIGHT)
ds.setColor(ContextCompat.getColor(context, R.color.mastodonC4));
2018-04-28 16:54:06 +02:00
}
}, matchStart, matchEnd, Spanned.SPAN_INCLUSIVE_EXCLUSIVE);
2017-12-03 10:56:54 +01:00
}
2018-09-01 12:42:22 +02:00
return spannableStringT;
2017-10-20 19:58:46 +02:00
}
2017-12-03 10:56:54 +01:00
public SpannableString getContentSpan() {
return contentSpan;
2017-10-20 19:58:46 +02:00
}
2017-12-03 10:56:54 +01:00
public void setContentSpan(SpannableString contentSpan) {
this.contentSpan = contentSpan;
}
public SpannableString getContentSpanCW() {
return contentSpanCW;
}
public void setContentSpanCW(SpannableString contentSpanCW) {
this.contentSpanCW = contentSpanCW;
}
public SpannableString getContentSpanTranslated() {
return contentSpanTranslated;
}
public void setContentSpanTranslated(SpannableString contentSpanTranslated) {
this.contentSpanTranslated = contentSpanTranslated;
}
2018-11-15 19:09:44 +01:00
public void setClickable(boolean clickable) {
isClickable = clickable;
}
2017-12-03 10:56:54 +01:00
public boolean isClickable() {
return isClickable;
2017-10-20 19:58:46 +02:00
}
2017-12-03 14:17:57 +01:00
public boolean isEmojiTranslateFound() {
return isEmojiTranslateFound;
}
public void setEmojiTranslateFound(boolean emojiTranslateFound) {
isEmojiTranslateFound = emojiTranslateFound;
}
public boolean isFetchMore() {
return fetchMore;
}
public void setFetchMore(boolean fetchMore) {
this.fetchMore = fetchMore;
}
2017-12-07 17:48:03 +01:00
@Override
public boolean equals(Object otherStatus) {
return otherStatus != null && (otherStatus == this || otherStatus instanceof Status && this.getId().equals(((Status) otherStatus).getId()));
}
2017-12-20 13:57:28 +01:00
public Card getCard() {
return card;
}
public void setCard(Card card) {
this.card = card;
}
2018-02-15 07:55:24 +01:00
public boolean isMuted() {
return muted;
}
public void setMuted(boolean muted) {
this.muted = muted;
}
public boolean isBookmarked() {
return bookmarked;
}
public void setBookmarked(boolean bookmarked) {
this.bookmarked = bookmarked;
}
2018-08-19 15:21:39 +02:00
public int getReplies_count() {
return replies_count;
}
public void setReplies_count(int replies_count) {
this.replies_count = replies_count;
}
public RetrieveFeedsAsyncTask.Type getType() {
return type;
}
public void setType(RetrieveFeedsAsyncTask.Type type) {
this.type = type;
}
2018-10-29 18:32:55 +01:00
public List<String> getConversationProfilePicture() {
return conversationProfilePicture;
}
public void setConversationProfilePicture(List<String> conversationProfilePicture) {
this.conversationProfilePicture = conversationProfilePicture;
}
2018-11-07 11:03:32 +01:00
public String getWebviewURL() {
return webviewURL;
}
public void setWebviewURL(String webviewURL) {
this.webviewURL = webviewURL;
}
public int getItemViewType() {
return itemViewType;
}
public void setItemViewType(int itemViewType) {
this.itemViewType = itemViewType;
}
2017-05-05 16:36:04 +02:00
}