Emojis support

This commit is contained in:
tom79 2017-10-20 19:58:46 +02:00
parent a22d61c63d
commit f36ddba6f9
6 changed files with 158 additions and 45 deletions

View File

@ -1502,18 +1502,23 @@ public class API {
//Retrieves emjis
List<Emojis> 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<Emojis>());
}
status.setEmojis(emojiList);
status.setAccount(parseAccountResponse(context, resobj.getJSONObject("account")));
status.setContent(resobj.get("content").toString());

View File

@ -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> 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;
}
}

View File

@ -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<Notification> 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;

View File

@ -15,7 +15,6 @@ package fr.gouv.etalab.mastodon.drawers;
* see <http://www.gnu.org/licenses>. */
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<Status> 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> 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;

View File

@ -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<Mention>
* @return TextView
*/
public static SpannableString clickableElements(final Context context, String fullContent, List<Mention> mentions, List<Emojis> emojis, boolean useHTML) {
SpannableString spannableString;
public static SpannableString clickableElements(final Context context, String fullContent, List<Mention> mentions, List<Emojis> 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, "<img src=\""+ emoji.getUrl()+"\" />");
}
}
}
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;
}

View File

@ -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 <http://www.gnu.org/licenses>. */
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);
}