Remote image between img tags displayed
This commit is contained in:
parent
b69780c8cb
commit
fad9f3708c
|
@ -37,7 +37,9 @@ import android.text.TextPaint;
|
||||||
import android.text.TextUtils;
|
import android.text.TextUtils;
|
||||||
import android.text.style.ClickableSpan;
|
import android.text.style.ClickableSpan;
|
||||||
import android.text.style.ImageSpan;
|
import android.text.style.ImageSpan;
|
||||||
|
import android.text.style.QuoteSpan;
|
||||||
import android.text.style.URLSpan;
|
import android.text.style.URLSpan;
|
||||||
|
import android.util.Log;
|
||||||
import android.util.Patterns;
|
import android.util.Patterns;
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
|
|
||||||
|
@ -70,6 +72,7 @@ import app.fedilab.android.asynctasks.UpdateAccountInfoAsyncTask;
|
||||||
import app.fedilab.android.helper.CrossActions;
|
import app.fedilab.android.helper.CrossActions;
|
||||||
import app.fedilab.android.helper.Helper;
|
import app.fedilab.android.helper.Helper;
|
||||||
import app.fedilab.android.interfaces.OnRetrieveEmojiInterface;
|
import app.fedilab.android.interfaces.OnRetrieveEmojiInterface;
|
||||||
|
import app.fedilab.android.interfaces.OnRetrieveImageInterface;
|
||||||
|
|
||||||
import static app.fedilab.android.helper.Helper.THEME_BLACK;
|
import static app.fedilab.android.helper.Helper.THEME_BLACK;
|
||||||
import static app.fedilab.android.helper.Helper.THEME_DARK;
|
import static app.fedilab.android.helper.Helper.THEME_DARK;
|
||||||
|
@ -112,6 +115,7 @@ public class Status implements Parcelable{
|
||||||
private String language;
|
private String language;
|
||||||
private boolean isTranslated = false;
|
private boolean isTranslated = false;
|
||||||
private boolean isEmojiFound = false;
|
private boolean isEmojiFound = false;
|
||||||
|
private boolean isImageFound = false;
|
||||||
private boolean isEmojiTranslateFound = false;
|
private boolean isEmojiTranslateFound = false;
|
||||||
private boolean isClickable = false;
|
private boolean isClickable = false;
|
||||||
private boolean isTranslationShown = false;
|
private boolean isTranslationShown = false;
|
||||||
|
@ -144,6 +148,7 @@ public class Status implements Parcelable{
|
||||||
private boolean shortReply = false;
|
private boolean shortReply = false;
|
||||||
|
|
||||||
private int warningFetched = -1;
|
private int warningFetched = -1;
|
||||||
|
private List<String> imageURL;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void writeToParcel(Parcel dest, int flags) {
|
public void writeToParcel(Parcel dest, int flags) {
|
||||||
|
@ -207,6 +212,7 @@ public class Status implements Parcelable{
|
||||||
dest.writeByte(this.customFeaturesDisplayed ? (byte) 1 : (byte) 0);
|
dest.writeByte(this.customFeaturesDisplayed ? (byte) 1 : (byte) 0);
|
||||||
dest.writeByte(this.shortReply ? (byte) 1 : (byte) 0);
|
dest.writeByte(this.shortReply ? (byte) 1 : (byte) 0);
|
||||||
dest.writeInt(this.warningFetched);
|
dest.writeInt(this.warningFetched);
|
||||||
|
dest.writeStringList(this.imageURL);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected Status(Parcel in) {
|
protected Status(Parcel in) {
|
||||||
|
@ -272,6 +278,7 @@ public class Status implements Parcelable{
|
||||||
this.customFeaturesDisplayed = in.readByte() != 0;
|
this.customFeaturesDisplayed = in.readByte() != 0;
|
||||||
this.shortReply = in.readByte() != 0;
|
this.shortReply = in.readByte() != 0;
|
||||||
this.warningFetched = in.readInt();
|
this.warningFetched = in.readInt();
|
||||||
|
this.imageURL = in.createStringArrayList();
|
||||||
}
|
}
|
||||||
|
|
||||||
public static final Creator<Status> CREATOR = new Creator<Status>() {
|
public static final Creator<Status> CREATOR = new Creator<Status>() {
|
||||||
|
@ -559,6 +566,9 @@ public class Status implements Parcelable{
|
||||||
return isEmojiFound;
|
return isEmojiFound;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public boolean isImageFound() {
|
||||||
|
return isImageFound;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@ -567,6 +577,10 @@ public class Status implements Parcelable{
|
||||||
isEmojiFound = emojiFound;
|
isEmojiFound = emojiFound;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void setImageFound(boolean imageFound) {
|
||||||
|
isImageFound = imageFound;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
public static void transform(Context context, Status status){
|
public static void transform(Context context, Status status){
|
||||||
|
|
||||||
|
@ -605,7 +619,60 @@ public class Status implements Parcelable{
|
||||||
content = content.replaceFirst(Pattern.quote(beforemodification), Matcher.quoteReplacement(urlText));
|
content = content.replaceFirst(Pattern.quote(beforemodification), Matcher.quoteReplacement(urlText));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Pattern imgPattern = Pattern.compile("<img [^>]*src=\"([^\"]+)\"[^>]*>");
|
||||||
|
Matcher matcher = imgPattern.matcher(content);
|
||||||
|
List<String> imgs = new ArrayList<>();
|
||||||
|
int i = 1;
|
||||||
|
while (matcher.find()) {
|
||||||
|
content = content.replaceAll(Pattern.quote(matcher.group(0)), "<br/>[media_"+i+"]<br/>");
|
||||||
|
imgs.add("[media_"+i+"]|"+matcher.group(1));
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
status.setImageURL(imgs);
|
||||||
spannableStringContent = new SpannableString(content);
|
spannableStringContent = new SpannableString(content);
|
||||||
|
final int[] j = {0};
|
||||||
|
if( status.getImageURL() != null && status.getImageURL().size() > 0){
|
||||||
|
for(String val: status.getImageURL()){
|
||||||
|
String[] valArray = val.split("\\|");
|
||||||
|
if( valArray.length > 1 ){
|
||||||
|
String contentOriginal = valArray[0];
|
||||||
|
String url = valArray[1];
|
||||||
|
Log.v(Helper.TAG,"contentOriginal: " + contentOriginal);
|
||||||
|
Log.v(Helper.TAG,"url: " + url);
|
||||||
|
Glide.with(context)
|
||||||
|
.asBitmap()
|
||||||
|
.load(url)
|
||||||
|
.into(new SimpleTarget<Bitmap>() {
|
||||||
|
@Override
|
||||||
|
public void onResourceReady(@NonNull Bitmap resource, Transition<? super Bitmap> transition) {
|
||||||
|
final String targetedEmoji = contentOriginal;
|
||||||
|
Log.v(Helper.TAG,"contentSpan.toString(): " + spannableStringContent.toString());
|
||||||
|
if (spannableStringContent != null && spannableStringContent.toString().contains(targetedEmoji)) {
|
||||||
|
//emojis can be used several times so we have to loop
|
||||||
|
Log.v(Helper.TAG,"ok: " + spannableStringContent.toString());
|
||||||
|
for (int startPosition = -1; (startPosition = spannableStringContent.toString().indexOf(targetedEmoji, startPosition + 1)) != -1; startPosition++) {
|
||||||
|
final int endPosition = startPosition + targetedEmoji.length();
|
||||||
|
Log.v(Helper.TAG,"startPosition: " + startPosition);
|
||||||
|
Log.v(Helper.TAG,"endPosition: " + endPosition);
|
||||||
|
if( endPosition <= spannableStringContent.toString().length() && endPosition >= startPosition) {
|
||||||
|
spannableStringContent.setSpan(
|
||||||
|
new ImageSpan(context,
|
||||||
|
Bitmap.createScaledBitmap(resource, (int) Helper.convertDpToPixel(300, context),
|
||||||
|
(int) Helper.convertDpToPixel(300, context), false)), startPosition,
|
||||||
|
endPosition, Spannable.SPAN_INCLUSIVE_EXCLUSIVE);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
j[0]++;
|
||||||
|
if( j[0] == (status.getImageURL().size())) {
|
||||||
|
status.setContentSpan(spannableStringContent);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
String spoilerText = "";
|
String spoilerText = "";
|
||||||
if( status.getReblog() != null && status.getReblog().getSpoiler_text() != null)
|
if( status.getReblog() != null && status.getReblog().getSpoiler_text() != null)
|
||||||
spoilerText = status.getReblog().getSpoiler_text();
|
spoilerText = status.getReblog().getSpoiler_text();
|
||||||
|
@ -704,6 +771,9 @@ public class Status implements Parcelable{
|
||||||
accountsMentionUnknown.put(key, account);
|
accountsMentionUnknown.put(key, account);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
SpannableString spannableStringT;
|
SpannableString spannableStringT;
|
||||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N)
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N)
|
||||||
spannableStringT = new SpannableString(Html.fromHtml(spannableString.toString().replaceAll("^<p>","").replaceAll("<p>","<br/><br/>").replaceAll("</p>","").replaceAll("<br />","<br/>").replaceAll("[\\s]{2}"," "), Html.FROM_HTML_MODE_LEGACY));
|
spannableStringT = new SpannableString(Html.fromHtml(spannableString.toString().replaceAll("^<p>","").replaceAll("<p>","<br/><br/>").replaceAll("</p>","").replaceAll("<br />","<br/>").replaceAll("[\\s]{2}"," "), Html.FROM_HTML_MODE_LEGACY));
|
||||||
|
@ -1057,6 +1127,75 @@ public class Status implements Parcelable{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public static void makeImage(final Context context, final OnRetrieveImageInterface listener, Status status){
|
||||||
|
|
||||||
|
if( ((Activity)context).isFinishing() )
|
||||||
|
return;
|
||||||
|
if( status.getAccount() == null)
|
||||||
|
return;
|
||||||
|
if( status.getImageURL() == null || status.getImageURL().size() == 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
SpannableString contentSpan = status.getContentSpan();
|
||||||
|
|
||||||
|
final int[] i = {0};
|
||||||
|
for (final String img : status.getImageURL()) {
|
||||||
|
final String name = img.split("\\|")[0];
|
||||||
|
final String imgURL = img.split("\\|")[1];
|
||||||
|
Glide.with(context)
|
||||||
|
.asBitmap()
|
||||||
|
.load(imgURL)
|
||||||
|
.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] == (status.getImageURL().size())) {
|
||||||
|
listener.onRetrieveImage(status,false);
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.into(new SimpleTarget<Bitmap>() {
|
||||||
|
@Override
|
||||||
|
public void onResourceReady(@NonNull Bitmap resource, Transition<? super Bitmap> transition) {
|
||||||
|
|
||||||
|
int w = resource.getWidth();
|
||||||
|
int h = resource.getHeight();
|
||||||
|
if( w > 300 ){
|
||||||
|
h = (h * 300) / w;
|
||||||
|
w = 300;
|
||||||
|
}
|
||||||
|
final String targetedEmoji = name;
|
||||||
|
if (contentSpan != null && contentSpan.toString().contains(targetedEmoji)) {
|
||||||
|
//emojis can be used several times so we have to loop
|
||||||
|
for (int startPosition = -1; (startPosition = contentSpan.toString().indexOf(targetedEmoji, startPosition + 1)) != -1; startPosition++) {
|
||||||
|
final int endPosition = startPosition + targetedEmoji.length();
|
||||||
|
if( endPosition <= contentSpan.toString().length() && endPosition >= startPosition)
|
||||||
|
contentSpan.setSpan(
|
||||||
|
new ImageSpan(context,
|
||||||
|
Bitmap.createScaledBitmap(resource, (int) Helper.convertDpToPixel(w, context),
|
||||||
|
(int) Helper.convertDpToPixel(h, context), false)), startPosition,
|
||||||
|
endPosition, Spannable.SPAN_INCLUSIVE_EXCLUSIVE);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
i[0]++;
|
||||||
|
if( i[0] == (status.getImageURL().size())) {
|
||||||
|
status.setContentSpan(contentSpan);
|
||||||
|
status.setImageFound(true);
|
||||||
|
listener.onRetrieveImage(status, false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
public static void makeEmojisTranslation(final Context context, final OnRetrieveEmojiInterface listener, Status status){
|
public static void makeEmojisTranslation(final Context context, final OnRetrieveEmojiInterface listener, Status status){
|
||||||
|
|
||||||
if( ((Activity)context).isFinishing() )
|
if( ((Activity)context).isFinishing() )
|
||||||
|
@ -1383,4 +1522,12 @@ public class Status implements Parcelable{
|
||||||
public void setWarningFetched(int warningFetched) {
|
public void setWarningFetched(int warningFetched) {
|
||||||
this.warningFetched = warningFetched;
|
this.warningFetched = warningFetched;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public List<String> getImageURL() {
|
||||||
|
return imageURL;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setImageURL(List<String> imageURL) {
|
||||||
|
this.imageURL = imageURL;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -133,6 +133,7 @@ import app.fedilab.android.helper.CustomTextView;
|
||||||
import app.fedilab.android.helper.Helper;
|
import app.fedilab.android.helper.Helper;
|
||||||
import app.fedilab.android.helper.MastalabAutoCompleteTextView;
|
import app.fedilab.android.helper.MastalabAutoCompleteTextView;
|
||||||
import app.fedilab.android.interfaces.OnPostStatusActionInterface;
|
import app.fedilab.android.interfaces.OnPostStatusActionInterface;
|
||||||
|
import app.fedilab.android.interfaces.OnRetrieveImageInterface;
|
||||||
import app.fedilab.android.interfaces.OnRetrieveRelationshipInterface;
|
import app.fedilab.android.interfaces.OnRetrieveRelationshipInterface;
|
||||||
import app.fedilab.android.interfaces.OnRetrieveRelationshipQuickReplyInterface;
|
import app.fedilab.android.interfaces.OnRetrieveRelationshipQuickReplyInterface;
|
||||||
import app.fedilab.android.interfaces.OnRetrieveSearcAccountshInterface;
|
import app.fedilab.android.interfaces.OnRetrieveSearcAccountshInterface;
|
||||||
|
@ -185,7 +186,7 @@ import static app.fedilab.android.helper.Helper.changeDrawableColor;
|
||||||
* Created by Thomas on 24/04/2017.
|
* Created by Thomas on 24/04/2017.
|
||||||
* Adapter for Status
|
* Adapter for Status
|
||||||
*/
|
*/
|
||||||
public class StatusListAdapter extends RecyclerView.Adapter implements OnPostActionInterface, OnRetrieveFeedsInterface, OnRetrieveEmojiInterface, OnRetrieveRepliesInterface, OnRetrieveCardInterface, OnPollInterface, OnRefreshCachedStatusInterface, OnRetrieveSearcAccountshInterface, OnRetrieveSearchInterface, OnPostStatusActionInterface, OnRetrieveRelationshipQuickReplyInterface {
|
public class StatusListAdapter extends RecyclerView.Adapter implements OnPostActionInterface, OnRetrieveFeedsInterface, OnRetrieveImageInterface, OnRetrieveEmojiInterface, OnRetrieveRepliesInterface, OnRetrieveCardInterface, OnPollInterface, OnRefreshCachedStatusInterface, OnRetrieveSearcAccountshInterface, OnRetrieveSearchInterface, OnPostStatusActionInterface, OnRetrieveRelationshipQuickReplyInterface {
|
||||||
|
|
||||||
private Context context;
|
private Context context;
|
||||||
private List<Status> statuses;
|
private List<Status> statuses;
|
||||||
|
@ -537,6 +538,7 @@ public class StatusListAdapter extends RecyclerView.Adapter implements OnPostAct
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
private class ViewHolderEmpty extends RecyclerView.ViewHolder{
|
private class ViewHolderEmpty extends RecyclerView.ViewHolder{
|
||||||
ViewHolderEmpty(View itemView) {
|
ViewHolderEmpty(View itemView) {
|
||||||
super(itemView);
|
super(itemView);
|
||||||
|
@ -1457,6 +1459,9 @@ public class StatusListAdapter extends RecyclerView.Adapter implements OnPostAct
|
||||||
Status.transform(context, status);
|
Status.transform(context, status);
|
||||||
if (!status.isEmojiFound())
|
if (!status.isEmojiFound())
|
||||||
Status.makeEmojis(context, this, status);
|
Status.makeEmojis(context, this, status);
|
||||||
|
if (!status.isImageFound())
|
||||||
|
Status.makeImage(context, this, status);
|
||||||
|
|
||||||
holder.status_content.setOnTouchListener(new View.OnTouchListener() {
|
holder.status_content.setOnTouchListener(new View.OnTouchListener() {
|
||||||
@Override
|
@Override
|
||||||
public boolean onTouch(View view, MotionEvent motionEvent) {
|
public boolean onTouch(View view, MotionEvent motionEvent) {
|
||||||
|
@ -4110,6 +4115,19 @@ public class StatusListAdapter extends RecyclerView.Adapter implements OnPostAct
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onRetrieveImage(Status status, boolean fromTranslation) {
|
||||||
|
if( status != null) {
|
||||||
|
if( !fromTranslation) {
|
||||||
|
status.setImageFound(true);
|
||||||
|
}else {
|
||||||
|
status.setImageFound(true);
|
||||||
|
}
|
||||||
|
notifyStatusChanged(status);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onRetrieveEmoji(Status status, boolean fromTranslation) {
|
public void onRetrieveEmoji(Status status, boolean fromTranslation) {
|
||||||
if( status != null) {
|
if( status != null) {
|
||||||
|
|
|
@ -0,0 +1,26 @@
|
||||||
|
/* Copyright 2019 Thomas Schneider
|
||||||
|
*
|
||||||
|
* This file is a part of Fedilab
|
||||||
|
*
|
||||||
|
* 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.
|
||||||
|
*
|
||||||
|
* Fedilab is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even
|
||||||
|
* the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
|
||||||
|
* Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License along with Fedilab; if not,
|
||||||
|
* see <http://www.gnu.org/licenses>. */
|
||||||
|
package app.fedilab.android.interfaces;
|
||||||
|
|
||||||
|
import app.fedilab.android.client.Entities.Status;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Created by Thomas on 19/07/2019.
|
||||||
|
* Interface when retrieving image from img tags
|
||||||
|
*/
|
||||||
|
public interface OnRetrieveImageInterface {
|
||||||
|
void onRetrieveImage(Status status, boolean fromTranslation);
|
||||||
|
}
|
Loading…
Reference in New Issue