diff --git a/app/src/main/java/fr/gouv/etalab/mastodon/client/API.java b/app/src/main/java/fr/gouv/etalab/mastodon/client/API.java index c6108a2f3..6b1a28e4c 100644 --- a/app/src/main/java/fr/gouv/etalab/mastodon/client/API.java +++ b/app/src/main/java/fr/gouv/etalab/mastodon/client/API.java @@ -1502,18 +1502,23 @@ public class API { //Retrieves emjis List emojiList = new ArrayList<>(); - JSONArray emojisTag = resobj.getJSONArray("emojis"); - if( arrayTag != null){ - for(int j = 0 ; j < emojisTag.length() ; j++){ - JSONObject emojisObj = emojisTag.getJSONObject(j); - Emojis emojis = new Emojis(); - emojis.setShortcode(emojisObj.get("shortcode").toString()); - emojis.setStatic_url(emojisObj.get("static_url").toString()); - emojis.setUrl(emojisObj.get("url").toString()); - emojiList.add(emojis); + try { + JSONArray emojisTag = resobj.getJSONArray("emojis"); + if( arrayTag != null){ + for(int j = 0 ; j < emojisTag.length() ; j++){ + JSONObject emojisObj = emojisTag.getJSONObject(j); + Emojis emojis = new Emojis(); + emojis.setShortcode(emojisObj.get("shortcode").toString()); + emojis.setStatic_url(emojisObj.get("static_url").toString()); + emojis.setUrl(emojisObj.get("url").toString()); + emojiList.add(emojis); + } } + status.setEmojis(emojiList); + }catch (Exception e){ + status.setEmojis(new ArrayList()); } - status.setEmojis(emojiList); + status.setAccount(parseAccountResponse(context, resobj.getJSONObject("account"))); status.setContent(resobj.get("content").toString()); diff --git a/app/src/main/java/fr/gouv/etalab/mastodon/client/Entities/Status.java b/app/src/main/java/fr/gouv/etalab/mastodon/client/Entities/Status.java index 9948047d3..6616ed655 100644 --- a/app/src/main/java/fr/gouv/etalab/mastodon/client/Entities/Status.java +++ b/app/src/main/java/fr/gouv/etalab/mastodon/client/Entities/Status.java @@ -17,6 +17,8 @@ package fr.gouv.etalab.mastodon.client.Entities; import android.os.Parcel; import android.os.Parcelable; +import android.text.SpannableString; + import java.util.ArrayList; import java.util.Date; import java.util.List; @@ -37,6 +39,8 @@ public class Status implements Parcelable { private Status reblog; private String content; private String content_translated; + private SpannableString contents; + private SpannableString content_translateds; private Date created_at; private int reblogs_count; private int favourites_count; @@ -56,6 +60,7 @@ public class Status implements Parcelable { private Application application; private String language; private boolean isTranslated = false; + private boolean isEmojiFound = false; private boolean isTranslationShown = false; private boolean isNew = false; private boolean isTakingScreenShot = false; @@ -388,4 +393,28 @@ public class Status implements Parcelable { public void setEmojis(List emojis) { this.emojis = emojis; } + + public SpannableString getContents() { + return contents; + } + + public void setContents(SpannableString contents) { + this.contents = contents; + } + + public SpannableString getContent_translateds() { + return content_translateds; + } + + public void setContent_translateds(SpannableString content_translateds) { + this.content_translateds = content_translateds; + } + + public boolean isEmojiFound() { + return isEmojiFound; + } + + public void setEmojiFound(boolean emojiFound) { + isEmojiFound = emojiFound; + } } diff --git a/app/src/main/java/fr/gouv/etalab/mastodon/drawers/NotificationsListAdapter.java b/app/src/main/java/fr/gouv/etalab/mastodon/drawers/NotificationsListAdapter.java index aa4a0d6ab..b98d162ea 100644 --- a/app/src/main/java/fr/gouv/etalab/mastodon/drawers/NotificationsListAdapter.java +++ b/app/src/main/java/fr/gouv/etalab/mastodon/drawers/NotificationsListAdapter.java @@ -71,6 +71,7 @@ import fr.gouv.etalab.mastodon.client.Entities.Error; import fr.gouv.etalab.mastodon.helper.CrossActions; import fr.gouv.etalab.mastodon.interfaces.OnPostActionInterface; import fr.gouv.etalab.mastodon.interfaces.OnPostNotificationsActionInterface; +import fr.gouv.etalab.mastodon.interfaces.OnRetrieveEmojiInterface; import mastodon.etalab.gouv.fr.mastodon.R; import fr.gouv.etalab.mastodon.client.Entities.Notification; import fr.gouv.etalab.mastodon.client.Entities.Status; @@ -84,7 +85,7 @@ import static fr.gouv.etalab.mastodon.helper.Helper.changeDrawableColor; * Created by Thomas on 24/04/2017. * Adapter for Status */ -public class NotificationsListAdapter extends BaseAdapter implements OnPostActionInterface, OnPostNotificationsActionInterface { +public class NotificationsListAdapter extends BaseAdapter implements OnPostActionInterface, OnPostNotificationsActionInterface, OnRetrieveEmojiInterface { private Context context; private List notifications; @@ -295,8 +296,12 @@ public class NotificationsListAdapter extends BaseAdapter implements OnPostActio content = content.substring(0, content.length() - 10); } - SpannableString spannableString = Helper.clickableElements(context, content, - status.getReblog() != null?status.getReblog().getMentions():status.getMentions(), status.getEmojis(), true); + SpannableString spannableString = Helper.clickableElements(context, status.getContent(), + status.getReblog() != null?status.getReblog().getMentions():status.getMentions(), + status.getReblog() != null?status.getReblog().getEmojis():status.getEmojis(), + position, + true, NotificationsListAdapter.this); + Typeface tf = Typeface.createFromAsset(context.getAssets(), "fonts/DroidSans-Regular.ttf"); holder.notification_status_content.setTypeface(tf); holder.notification_status_content.setText(spannableString, TextView.BufferType.SPANNABLE); @@ -908,6 +913,15 @@ public class NotificationsListAdapter extends BaseAdapter implements OnPostActio holder.status_show_more.setVisibility(View.GONE); } + @Override + public void onRetrieveEmoji(int position, SpannableString spannableString, Boolean error) { + notifications.get(position).getStatus().setContents(spannableString); + if( !notifications.get(position).getStatus().isEmojiFound()) { + notifications.get(position).getStatus().setEmojiFound(true); + notificationsListAdapter.notifyDataSetChanged(); + } + } + private class ViewHolder { CardView card_status_container; diff --git a/app/src/main/java/fr/gouv/etalab/mastodon/drawers/StatusListAdapter.java b/app/src/main/java/fr/gouv/etalab/mastodon/drawers/StatusListAdapter.java index a0b11bad8..f78a1776b 100644 --- a/app/src/main/java/fr/gouv/etalab/mastodon/drawers/StatusListAdapter.java +++ b/app/src/main/java/fr/gouv/etalab/mastodon/drawers/StatusListAdapter.java @@ -15,7 +15,6 @@ package fr.gouv.etalab.mastodon.drawers; * see . */ import android.graphics.Bitmap; -import android.graphics.Color; import android.graphics.Typeface; import android.os.Handler; import android.support.design.widget.FloatingActionButton; @@ -39,11 +38,8 @@ import android.text.Html; import android.text.Spannable; import android.text.SpannableString; import android.text.Spanned; -import android.text.TextPaint; import android.text.method.LinkMovementMethod; -import android.text.style.ClickableSpan; import android.text.style.ForegroundColorSpan; -import android.util.Log; import android.util.Patterns; import android.util.TypedValue; import android.view.LayoutInflater; @@ -83,7 +79,6 @@ import java.util.Map; import java.util.regex.Matcher; import java.util.regex.Pattern; -import fr.gouv.etalab.mastodon.activities.HashTagActivity; import fr.gouv.etalab.mastodon.activities.MediaActivity; import fr.gouv.etalab.mastodon.activities.ShowAccountActivity; import fr.gouv.etalab.mastodon.activities.ShowConversationActivity; @@ -93,12 +88,14 @@ import fr.gouv.etalab.mastodon.asynctasks.RetrieveFeedsAsyncTask; import fr.gouv.etalab.mastodon.client.API; import fr.gouv.etalab.mastodon.client.APIResponse; import fr.gouv.etalab.mastodon.client.Entities.Attachment; +import fr.gouv.etalab.mastodon.client.Entities.Emojis; import fr.gouv.etalab.mastodon.client.Entities.Error; import fr.gouv.etalab.mastodon.client.Entities.Status; import fr.gouv.etalab.mastodon.client.PatchBaseImageDownloader; import fr.gouv.etalab.mastodon.helper.CrossActions; import fr.gouv.etalab.mastodon.helper.Helper; import fr.gouv.etalab.mastodon.interfaces.OnPostActionInterface; +import fr.gouv.etalab.mastodon.interfaces.OnRetrieveEmojiInterface; import fr.gouv.etalab.mastodon.interfaces.OnRetrieveFeedsInterface; import fr.gouv.etalab.mastodon.interfaces.OnTranslatedInterface; import fr.gouv.etalab.mastodon.translation.GoogleTranslateQuery; @@ -114,7 +111,7 @@ import static fr.gouv.etalab.mastodon.helper.Helper.changeDrawableColor; * Created by Thomas on 24/04/2017. * Adapter for Status */ -public class StatusListAdapter extends BaseAdapter implements OnPostActionInterface, OnTranslatedInterface, OnRetrieveFeedsInterface { +public class StatusListAdapter extends BaseAdapter implements OnPostActionInterface, OnTranslatedInterface, OnRetrieveFeedsInterface, OnRetrieveEmojiInterface { private Context context; private List statuses; @@ -444,8 +441,11 @@ public class StatusListAdapter extends BaseAdapter implements OnPostActionInterf if( status.getContent_translated() != null && status.getContent_translated().length() > 0){ holder.status_content_translated.setMovementMethod(null); - SpannableString spannableStringTrans = Helper.clickableElements(context, status.getContent_translated(), - status.getReblog() != null?status.getReblog().getMentions():status.getMentions(), status.getEmojis(), false); + SpannableString spannableStringTrans = Helper.clickableElements(context,status.getContent_translated(), + status.getReblog() != null?status.getReblog().getMentions():status.getMentions(), + status.getReblog() != null?status.getReblog().getEmojis():status.getEmojis(), + position, + true, StatusListAdapter.this); holder.status_content_translated.setText(spannableStringTrans, TextView.BufferType.SPANNABLE); holder.status_content_translated.setOnLongClickListener(new View.OnLongClickListener() { @Override @@ -472,8 +472,14 @@ public class StatusListAdapter extends BaseAdapter implements OnPostActionInterf content = content.substring(0,content.length() -10); holder.status_content.setMovementMethod(null); final SpannableString spannableString = Helper.clickableElements(context,content, - status.getReblog() != null?status.getReblog().getMentions():status.getMentions(), status.getEmojis(), true); + status.getReblog() != null?status.getReblog().getMentions():status.getMentions(), + status.getReblog() != null?status.getReblog().getEmojis():status.getEmojis(), + position, + true, StatusListAdapter.this); holder.status_content.setText(spannableString, TextView.BufferType.SPANNABLE); + if( status.getContents() != null){ + holder.status_content.setText(status.getContents(), TextView.BufferType.SPANNABLE); + } holder.status_content.setOnLongClickListener(new View.OnLongClickListener() { @Override public boolean onLongClick(View v) { @@ -481,6 +487,8 @@ public class StatusListAdapter extends BaseAdapter implements OnPostActionInterf return false; } }); + List emojis = status.getReblog() != null ? status.getReblog().getEmojis() : status.getEmojis(); + holder.status_content.setOnTouchListener(new View.OnTouchListener() { @Override public boolean onTouch(View v, MotionEvent event) { @@ -1317,6 +1325,16 @@ public class StatusListAdapter extends BaseAdapter implements OnPostActionInterf } } + + @Override + public void onRetrieveEmoji(int position, SpannableString spannableString, Boolean error) { + statuses.get(position).setContents(spannableString); + if( !statuses.get(position).isEmojiFound()) { + statuses.get(position).setEmojiFound(true); + statusListAdapter.notifyDataSetChanged(); + } + } + @Override public void onTranslatedTextview(int position, String translatedResult, Boolean error) { if( error){ @@ -1408,6 +1426,8 @@ public class StatusListAdapter extends BaseAdapter implements OnPostActionInterf } + + private class ViewHolder { LinearLayout status_content_container; LinearLayout status_spoiler_container; diff --git a/app/src/main/java/fr/gouv/etalab/mastodon/helper/Helper.java b/app/src/main/java/fr/gouv/etalab/mastodon/helper/Helper.java index 37fc6a1b7..4570efe84 100644 --- a/app/src/main/java/fr/gouv/etalab/mastodon/helper/Helper.java +++ b/app/src/main/java/fr/gouv/etalab/mastodon/helper/Helper.java @@ -23,7 +23,6 @@ import android.graphics.PorterDuffXfermode; import android.graphics.Rect; import android.graphics.RectF; import android.support.annotation.RequiresApi; -import android.support.v7.app.ActionBarDrawerToggle; import android.support.v7.app.AlertDialog; import android.app.DownloadManager; import android.app.PendingIntent; @@ -57,20 +56,20 @@ import android.support.design.widget.NavigationView; import android.support.v4.app.NotificationCompat; import android.support.v4.app.NotificationManagerCompat; import android.support.v4.content.ContextCompat; -import android.support.v7.app.ActionBar; -import android.support.v7.widget.Toolbar; import android.text.Html; +import android.text.Spannable; import android.text.SpannableString; import android.text.Spanned; import android.text.TextPaint; import android.text.style.ClickableSpan; +import android.text.style.ImageSpan; import android.util.DisplayMetrics; +import android.util.Log; import android.util.Patterns; import android.view.Menu; import android.view.MenuItem; import android.view.SubMenu; import android.view.View; -import android.view.ViewGroup; import android.view.WindowManager; import android.webkit.CookieManager; import android.webkit.MimeTypeMap; @@ -90,7 +89,10 @@ import com.nostra13.universalimageloader.core.DisplayImageOptions; import com.nostra13.universalimageloader.core.ImageLoader; import com.nostra13.universalimageloader.core.ImageLoaderConfiguration; import com.nostra13.universalimageloader.core.assist.FailReason; +import com.nostra13.universalimageloader.core.assist.ImageSize; +import com.nostra13.universalimageloader.core.assist.ViewScaleType; import com.nostra13.universalimageloader.core.display.SimpleBitmapDisplayer; +import com.nostra13.universalimageloader.core.imageaware.NonViewAware; import com.nostra13.universalimageloader.core.listener.ImageLoadingListener; import com.nostra13.universalimageloader.core.listener.SimpleImageLoadingListener; @@ -108,7 +110,6 @@ import java.security.MessageDigest; import java.security.NoSuchAlgorithmException; import java.text.ParseException; import java.text.SimpleDateFormat; -import java.util.ArrayList; import java.util.Calendar; import java.util.Date; import java.util.HashMap; @@ -125,7 +126,6 @@ import fr.gouv.etalab.mastodon.activities.HashTagActivity; import fr.gouv.etalab.mastodon.activities.LoginActivity; import fr.gouv.etalab.mastodon.activities.MainActivity; import fr.gouv.etalab.mastodon.activities.ShowAccountActivity; -import fr.gouv.etalab.mastodon.activities.TootActivity; import fr.gouv.etalab.mastodon.activities.WebviewActivity; import fr.gouv.etalab.mastodon.asynctasks.RemoveAccountAsyncTask; import fr.gouv.etalab.mastodon.client.API; @@ -134,8 +134,7 @@ import fr.gouv.etalab.mastodon.client.Entities.Emojis; import fr.gouv.etalab.mastodon.client.Entities.Mention; import fr.gouv.etalab.mastodon.client.Entities.Status; import fr.gouv.etalab.mastodon.client.PatchBaseImageDownloader; -import fr.gouv.etalab.mastodon.fragments.DisplayNotificationsFragment; -import fr.gouv.etalab.mastodon.fragments.DisplayStatusFragment; +import fr.gouv.etalab.mastodon.interfaces.OnRetrieveEmojiInterface; import fr.gouv.etalab.mastodon.sqlite.AccountDAO; import fr.gouv.etalab.mastodon.sqlite.Sqlite; import mastodon.etalab.gouv.fr.mastodon.R; @@ -1125,6 +1124,7 @@ public class Helper { } + /** * Check if the status contents mentions & tags and fills the content with ClickableSpan * Click on account => ShowAccountActivity @@ -1134,21 +1134,9 @@ public class Helper { * @param mentions List * @return TextView */ - public static SpannableString clickableElements(final Context context, String fullContent, List mentions, List emojis, boolean useHTML) { - SpannableString spannableString; + public static SpannableString clickableElements(final Context context, String fullContent, List mentions, List emojis, final int position, boolean useHTML, final OnRetrieveEmojiInterface listener) { + final SpannableString spannableString; - - //Deals with custom emojis to change them in image - if( emojis != null && emojis.size() > 0 ) { - //Looping through accounts which are mentioned - for (final Emojis emoji : emojis) { - String targetedEmoji = ":" + emoji + ":"; - if (fullContent.contains(targetedEmoji)) { - fullContent = fullContent.replace(targetedEmoji, ""); - } - - } - } if( useHTML) { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) spannableString = new SpannableString(Html.fromHtml(fullContent, Html.FROM_HTML_MODE_LEGACY)); @@ -1193,6 +1181,37 @@ public class Helper { } } + + if( emoji != null && emojis.size() > 0 ) { + for (final Emojis emoji : emojis) { + final String targetedEmoji = ":" + emoji.getShortcode() + ":"; + if (spannableString.toString().contains(targetedEmoji)) { + //emojis can be used several times so we have to loop + for(int startPosition = -1 ; (startPosition = spannableString.toString().indexOf(targetedEmoji, startPosition + 1)) != -1 ; startPosition++){ + final int endPosition = startPosition + targetedEmoji.length(); + final int finalStartPosition = startPosition; + ImageLoader imageLoader = ImageLoader.getInstance(); + NonViewAware imageAware = new NonViewAware(new ImageSize(50, 50), ViewScaleType.CROP); + imageLoader.displayImage(emoji.getUrl(), imageAware, new SimpleImageLoadingListener() { + @Override + public void onLoadingComplete(String imageUri, View view, Bitmap loadedImage) { + super.onLoadingComplete(imageUri, view, loadedImage); + spannableString.setSpan( + new ImageSpan(context, + Bitmap.createScaledBitmap(loadedImage, (int)Helper.convertDpToPixel(20, context), + (int)Helper.convertDpToPixel(20, context), false)), finalStartPosition, + endPosition, Spannable.SPAN_INCLUSIVE_EXCLUSIVE); + listener.onRetrieveEmoji(position, spannableString, false); + } + @Override + public void onLoadingFailed(java.lang.String imageUri, android.view.View view, FailReason failReason) { + } + }); + } + } + } + } + //Deals with mention to make them clickable if( mentions != null && mentions.size() > 0 ) { //Looping through accounts which are mentioned @@ -1224,7 +1243,6 @@ public class Helper { } } - Matcher matcher = hashtagPattern.matcher(spannableString); while (matcher.find()){ int matchStart = matcher.start(1); @@ -1245,6 +1263,7 @@ public class Helper { } }, matchStart, matchEnd, Spanned.SPAN_INCLUSIVE_EXCLUSIVE); } + return spannableString; } diff --git a/app/src/main/java/fr/gouv/etalab/mastodon/interfaces/OnRetrieveEmojiInterface.java b/app/src/main/java/fr/gouv/etalab/mastodon/interfaces/OnRetrieveEmojiInterface.java new file mode 100644 index 000000000..5bc39ba7c --- /dev/null +++ b/app/src/main/java/fr/gouv/etalab/mastodon/interfaces/OnRetrieveEmojiInterface.java @@ -0,0 +1,26 @@ +/* Copyright 2017 Thomas Schneider + * + * This file is a part of Mastalab + * + * 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. + * + * Mastalab 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 Mastalab; if not, + * see . */ +package fr.gouv.etalab.mastodon.interfaces; + +import android.text.SpannableString; + + +/** + * Created by Thomas on 19/10/2017. + * Interface when retrieving emojis + */ +public interface OnRetrieveEmojiInterface { + void onRetrieveEmoji(int position, SpannableString spannableString, Boolean error); +}