Bladeren bron

Fix emoji detection

Signed-off-by: Mario Danic <mario@lovelyhq.com>
Mario Danic 6 jaren geleden
bovenliggende
commit
f677d95fe7

+ 3 - 2
app/src/main/java/com/nextcloud/talk/adapters/messages/MagicIncomingTextMessageViewHolder.java

@@ -36,8 +36,8 @@ import com.nextcloud.talk.application.NextcloudTalkApplication;
 import com.nextcloud.talk.models.database.UserEntity;
 import com.nextcloud.talk.models.json.chat.ChatMessage;
 import com.nextcloud.talk.utils.DisplayUtils;
+import com.nextcloud.talk.utils.EmojiDetection;
 import com.nextcloud.talk.utils.database.user.UserUtils;
-import com.nextcloud.talk.utils.emoticons.EmoticonUtils;
 import com.stfalcon.chatkit.messages.MessageHolders;
 import com.stfalcon.chatkit.utils.ShapeImageView;
 
@@ -85,6 +85,7 @@ public class MagicIncomingTextMessageViewHolder
     public void onBind(ChatMessage message) {
         super.onBind(message);
         String author;
+
         if (!TextUtils.isEmpty(author = message.getActorDisplayName())) {
             messageAuthor.setText(author);
         } else {
@@ -129,7 +130,7 @@ public class MagicIncomingTextMessageViewHolder
                 }
             }
 
-        } else if (EmoticonUtils.isMessageWithSingleEmoticonOnly(context, message.getText())) {
+        } else if (EmojiDetection.isMessageWithSingleEmoticonOnly(context, message.getText())) {
             messageString.setSpan(new RelativeSizeSpan(2.5f), 0, messageString.length(),
                     Spannable.SPAN_INCLUSIVE_EXCLUSIVE);
             layoutParams.setWrapBefore(true);

+ 2 - 2
app/src/main/java/com/nextcloud/talk/adapters/messages/MagicOutcomingTextMessageViewHolder.java

@@ -34,8 +34,8 @@ import com.nextcloud.talk.application.NextcloudTalkApplication;
 import com.nextcloud.talk.models.database.UserEntity;
 import com.nextcloud.talk.models.json.chat.ChatMessage;
 import com.nextcloud.talk.utils.DisplayUtils;
+import com.nextcloud.talk.utils.EmojiDetection;
 import com.nextcloud.talk.utils.database.user.UserUtils;
-import com.nextcloud.talk.utils.emoticons.EmoticonUtils;
 import com.stfalcon.chatkit.messages.MessageHolders;
 
 import java.util.HashMap;
@@ -98,7 +98,7 @@ public class MagicOutcomingTextMessageViewHolder extends MessageHolders.Outcomin
                 }
             }
 
-        } else if (EmoticonUtils.isMessageWithSingleEmoticonOnly(context, message.getText())) {
+        } else if (EmojiDetection.isMessageWithSingleEmoticonOnly(context, message.getText())) {
             messageString.setSpan(new RelativeSizeSpan(2.5f), 0, messageString.length(),
                     Spannable.SPAN_INCLUSIVE_EXCLUSIVE);
             layoutParams.setWrapBefore(true);

+ 99 - 0
app/src/main/java/com/nextcloud/talk/utils/EmojiDetection.java

@@ -0,0 +1,99 @@
+/*
+ * Nextcloud Talk application
+ *
+ * @author Mario Danic
+ * Copyright (C) 2017-2018 Mario Danic <mario@lovelyhq.com>
+ *
+ * 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.
+ *
+ * This program 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 this program.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ * Partly based on https://github.com/kevalpatel2106/EmoticonGIFKeyboard/blob/master/emoticongifkeyboard/src/main/java/com/kevalpatel2106/emoticongifkeyboard/internal/emoticon/EmoticonUtils.java
+ */
+
+package com.nextcloud.talk.utils;
+
+import android.content.Context;
+import android.support.annotation.NonNull;
+import android.support.annotation.Nullable;
+import android.text.TextUtils;
+
+import com.nextcloud.talk.R;
+
+import java.io.BufferedReader;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+public final class EmojiDetection {
+
+    private static Pattern regexPattern;
+
+    public static boolean isMessageWithSingleEmoticonOnly(@NonNull final Context context,
+                                                          @Nullable final CharSequence text) {
+
+        int startPosition = -1;
+        int endPosition = -1;
+        if (!TextUtils.isEmpty(text)) {
+
+
+            final Matcher matcher = getRegex(context).matcher(text);
+            while (matcher.find()) {
+                if (startPosition == -1 && endPosition == -1) {
+                    startPosition = matcher.start();
+                    endPosition = matcher.end();
+                } else {
+                    return false;
+                }
+            }
+        } else {
+            return false;
+        }
+
+        return startPosition == 0 && text.length() == endPosition;
+    }
+
+    @NonNull
+    private static Pattern getRegex(@NonNull final Context context) {
+        if (regexPattern == null) {
+            String regex = readTextFile(context, R.raw.regex);
+            regexPattern = Pattern.compile(regex);
+        }
+
+        return regexPattern;
+    }
+
+    @NonNull
+    private static String readTextFile(@NonNull Context context, int rowResource) {
+        InputStream inputStream = context.getResources().openRawResource(rowResource); // getting json
+        BufferedReader br = new BufferedReader(new InputStreamReader(inputStream));
+
+        StringBuilder builder = new StringBuilder();
+        try {
+            String sCurrentLine;
+            while ((sCurrentLine = br.readLine()) != null) builder.append(sCurrentLine);
+        } catch (IOException e) {
+            e.printStackTrace();
+        } finally {
+            try {
+                inputStream.close();
+                br.close();
+            } catch (IOException e) {
+                e.printStackTrace();
+            }
+        }
+        return builder.toString();
+    }
+
+}

+ 0 - 89
app/src/main/java/com/nextcloud/talk/utils/emoticons/EmoticonSpan.java

@@ -1,89 +0,0 @@
-/*
- * Copyright 2017 Keval Patel.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- *  Unless required by applicable law or agreed to in writing, software
- *  distributed under the License is distributed on an "AS IS" BASIS,
- *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- *  See the License for the specific language governing permissions and
- *  limitations under the License.
- */
-
-package com.nextcloud.talk.utils.emoticons;
-
-import android.content.Context;
-import android.graphics.Canvas;
-import android.graphics.Paint;
-import android.graphics.drawable.Drawable;
-import android.support.v7.content.res.AppCompatResources;
-import android.text.style.DynamicDrawableSpan;
-import android.text.style.ImageSpan;
-
-/**
- * Created by Keval Patel on 20/08/17.
- * The {@link ImageSpan} to display custom emoticon icon based on the unicode.
- *
- * @author 'https://github.com/kevalpatel2106'
- * @see <a href='https://github.com/rockerhieu/emojicon/blob/master/library/src/main/java/io/github/rockerhieu/emojicon/EmojiconSpan.java>EmojiconSpan.java</a>
- */
-
-final class EmoticonSpan extends DynamicDrawableSpan {
-    private final float mEmoticonSize;
-    private final Context mContext;
-    private final int mEmoticonIcon;
-    private Drawable mDeferredDrawable;
-
-    EmoticonSpan(final Context context, final int emoticonIcon, final float size) {
-        this.mContext = context;
-        this.mEmoticonIcon = emoticonIcon;
-        this.mEmoticonSize = size;
-    }
-
-    @SuppressWarnings("ConstantConditions")
-    @Override
-    public Drawable getDrawable() {
-        if (mDeferredDrawable == null) {
-            mDeferredDrawable = AppCompatResources.getDrawable(mContext, mEmoticonIcon);
-            mDeferredDrawable.setBounds(0, 0, (int) mEmoticonSize, (int) mEmoticonSize);
-        }
-        return mDeferredDrawable;
-    }
-
-    @Override
-    public int getSize(final Paint paint, final CharSequence text, final int start,
-                       final int end, final Paint.FontMetricsInt fontMetrics) {
-        if (fontMetrics != null) {
-            final Paint.FontMetrics paintFontMetrics = paint.getFontMetrics();
-            final float fontHeight = paintFontMetrics.descent - paintFontMetrics.ascent;
-            final float centerY = paintFontMetrics.ascent + fontHeight / 2;
-
-            fontMetrics.ascent = (int) (centerY - mEmoticonSize / 2);
-            fontMetrics.top = fontMetrics.ascent;
-            fontMetrics.bottom = (int) (centerY + mEmoticonSize / 2);
-            fontMetrics.descent = fontMetrics.bottom;
-        }
-
-        return (int) mEmoticonSize;
-    }
-
-    @Override
-    public void draw(final Canvas canvas, final CharSequence text, final int start,
-                     final int end, final float x, final int top, final int y,
-                     final int bottom, final Paint paint) {
-        final Drawable drawable = getDrawable();
-        final Paint.FontMetrics paintFontMetrics = paint.getFontMetrics();
-        final float fontHeight = paintFontMetrics.descent - paintFontMetrics.ascent;
-        final float centerY = y + paintFontMetrics.descent - fontHeight / 2;
-        final float transitionY = centerY - mEmoticonSize / 2;
-
-        canvas.save();
-        canvas.translate(x, transitionY);
-        drawable.draw(canvas);
-        canvas.restore();
-    }
-}

+ 0 - 255
app/src/main/java/com/nextcloud/talk/utils/emoticons/EmoticonUtils.java

@@ -1,255 +0,0 @@
-/*
- * Copyright 2017 Keval Patel.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- *  Unless required by applicable law or agreed to in writing, software
- *  distributed under the License is distributed on an "AS IS" BASIS,
- *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- *  See the License for the specific language governing permissions and
- *  limitations under the License.
- *
- *  Modified by Mario Danic (mario@lovelyhq.com) - Copyright 2018
- */
-
-package com.nextcloud.talk.utils.emoticons;
-
-import android.content.Context;
-import android.support.annotation.NonNull;
-import android.support.annotation.Nullable;
-import android.text.Spannable;
-import android.text.TextUtils;
-
-import com.kevalpatel2106.emoticongifkeyboard.R;
-import com.kevalpatel2106.emoticongifkeyboard.emoticons.Emoticon;
-import com.kevalpatel2106.emoticongifkeyboard.emoticons.EmoticonProvider;
-
-import java.io.BufferedReader;
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.InputStreamReader;
-import java.util.ArrayList;
-import java.util.List;
-import java.util.regex.Matcher;
-import java.util.regex.Pattern;
-
-/**
- * Created by Keval Patel on 20/08/17.
- * Utils to find emoticons from the string.
- *
- * @author 'https://github.com/kevalpatel2106'
- */
-
-public final class EmoticonUtils {
-    /**
-     * {@link Pattern} to find the supported emoticons unicodes.
-     */
-    private static Pattern sRegexPattern;
-
-    /**
-     * Private constructor.
-     */
-    private EmoticonUtils() {
-        //Do nothing
-    }
-
-    /**
-     * Replace the system emoticons with the provided custom emoticons drawable. This will find the
-     * unicodes with supported emoticons in the provided text and  will replace the emoticons with
-     * appropriate images.
-     *
-     * @param context          instance of caller.
-     * @param text             Text to replace
-     * @param emoticonProvider {@link EmoticonProvider} for emoticons images
-     * @param emoticonSize     Size of the emoticons in dp
-     * @return Modified text.
-     */
-    public static void replaceWithImages(@NonNull final Context context,
-                                         @NonNull final Spannable text,
-                                         @NonNull final EmoticonProvider emoticonProvider,
-                                         final int emoticonSize) {
-
-        final EmoticonSpan[] existingSpans = text.getSpans(0, text.length(), EmoticonSpan.class);
-        final ArrayList<Integer> existingSpanPositions = new ArrayList<>(existingSpans.length);
-        for (EmoticonSpan existingSpan : existingSpans)
-            existingSpanPositions.add(text.getSpanStart(existingSpan));
-
-        //Get location and unicode of all emoticons.
-        final List<EmoticonRange> findAllEmojis = findAllEmoticons(context, text, emoticonProvider);
-
-        //Replace all the emoticons with their relatives.
-        for (int i = 0; i < findAllEmojis.size(); i++) {
-            final EmoticonRange location = findAllEmojis.get(i);
-            if (!existingSpanPositions.contains(location.mStartPos)) {
-                text.setSpan(new EmoticonSpan(context, location.mEmoticon.getIcon(), emoticonSize),
-                        location.mStartPos,
-                        location.mEndPos,
-                        Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
-            }
-        }
-    }
-
-    /**
-     * Find all the unicodes that represents emoticons and location of starting and ending point of that emoticon.
-     *
-     * @param context          Instance of caller.
-     * @param text             Text to replace
-     * @param emoticonProvider {@link EmoticonProvider} for emoticons images
-     * @return List of {@link EmoticonRange}.
-     * @see EmoticonRange
-     */
-    @NonNull
-    private static List<EmoticonRange> findAllEmoticons(@NonNull final Context context,
-                                                        @Nullable final CharSequence text,
-                                                        @NonNull final EmoticonProvider emoticonProvider) {
-        final List<EmoticonRange> result = new ArrayList<>();
-
-        if (!TextUtils.isEmpty(text)) {
-            final Matcher matcher = getRegex(context).matcher(text);
-            while (matcher.find()) {
-                String unicode = text.subSequence(matcher.start(), matcher.end()).toString();
-                if (emoticonProvider.hasEmoticonIcon(unicode)) { //Check if the the emoticon has icon?
-                    final Emoticon found = new Emoticon(unicode, emoticonProvider.getIcon(unicode));
-
-                    //Add this emoticon to change list.
-                    result.add(new EmoticonRange(matcher.start(), matcher.end(), found));
-                }
-            }
-        }
-
-        return result;
-    }
-
-
-    public static boolean isMessageWithSingleEmoticonOnly(@NonNull final Context context,
-                                                          @Nullable final CharSequence text) {
-        final List<EmoticonRange> result = new ArrayList<>();
-
-        if (!TextUtils.isEmpty(text)) {
-
-            // Regexp acquired from https://gist.github.com/sergeychilingaryan/94902985a636658496cb69c300bba05f
-            String unicode10regexString = "(?:[\\u2700-\\u27bf]|" +
-
-                    "(?:[\\ud83c\\udde6-\\ud83c\\uddff]){2}|" +
-                    "[\\ud800\\udc00-\\uDBFF\\uDFFF]|[\\u2600-\\u26FF])[\\ufe0e\\ufe0f]?(?:[\\u0300-\\u036f\\ufe20-\\ufe23\\u20d0-\\u20f0]|[\\ud83c\\udffb-\\ud83c\\udfff])?" +
-
-                    "(?:\\u200d(?:[^\\ud800-\\udfff]|" +
-
-                    "(?:[\\ud83c\\udde6-\\ud83c\\uddff]){2}|" +
-                    "[\\ud800\\udc00-\\uDBFF\\uDFFF]|[\\u2600-\\u26FF])[\\ufe0e\\ufe0f]?(?:[\\u0300-\\u036f\\ufe20-\\ufe23\\u20d0-\\u20f0]|[\\ud83c\\udffb-\\ud83c\\udfff])?)*|" +
-
-                    "[\\u0023-\\u0039]\\ufe0f?\\u20e3|\\u3299|\\u3297|\\u303d|\\u3030|\\u24c2|[\\ud83c\\udd70-\\ud83c\\udd71]|[\\ud83c\\udd7e-\\ud83c\\udd7f]|\\ud83c\\udd8e|[\\ud83c\\udd91-\\ud83c\\udd9a]|[\\ud83c\\udde6-\\ud83c\\uddff]|[\\ud83c\\ude01-\\ud83c\\ude02]|\\ud83c\\ude1a|\\ud83c\\ude2f|[\\ud83c\\ude32-\\ud83c\\ude3a]|[\\ud83c\\ude50-\\ud83c\\ude51]|\\u203c|\\u2049|[\\u25aa-\\u25ab]|\\u25b6|\\u25c0|[\\u25fb-\\u25fe]|\\u00a9|\\u00ae|\\u2122|\\u2139|\\ud83c\\udc04|[\\u2600-\\u26FF]|\\u2b05|\\u2b06|\\u2b07|\\u2b1b|\\u2b1c|\\u2b50|\\u2b55|\\u231a|\\u231b|\\u2328|\\u23cf|[\\u23e9-\\u23f3]|[\\u23f8-\\u23fa]|\\ud83c\\udccf|\\u2934|\\u2935|[\\u2190-\\u21ff]";
-
-            final Matcher matcher = Pattern.compile(unicode10regexString, Pattern.UNICODE_CASE).matcher(text);
-            while (matcher.find()) {
-                String unicode = text.subSequence(matcher.start(), matcher.end()).toString();
-                // quick hack
-                final Emoticon found = new Emoticon(unicode, R.drawable.emoji_food);
-                //Add this emoticon to change list.
-                result.add(new EmoticonRange(matcher.start(), matcher.end(), found));
-            }
-        } else {
-            return false;
-        }
-
-        return result.size() == 1 && result.get(0).mStartPos == 0 && text.length() == result.get(0).mEndPos;
-    }
-
-    /**
-     * Load the regex to parse unicode from the shared preference if {@link #sRegexPattern} is not
-     * loaded.
-     *
-     * @param context Instance.
-     * @return Regex to find emoticon unicode from string.
-     */
-    @NonNull
-    private static Pattern getRegex(@NonNull final Context context) {
-        if (sRegexPattern == null) {
-            String regex = readTextFile(context, R.raw.regex);
-            sRegexPattern = Pattern.compile(regex);
-        }
-        return sRegexPattern;
-    }
-
-    @NonNull
-    private static String readTextFile(@NonNull Context context, int rowResource) {
-        InputStream inputStream = context.getResources().openRawResource(rowResource); // getting json
-        BufferedReader br = new BufferedReader(new InputStreamReader(inputStream));
-
-        StringBuilder builder = new StringBuilder();
-        try {
-            String sCurrentLine;
-            while ((sCurrentLine = br.readLine()) != null) builder.append(sCurrentLine);
-        } catch (IOException e) {
-            e.printStackTrace();
-        } finally {
-            try {
-                inputStream.close();
-                br.close();
-            } catch (IOException e) {
-                e.printStackTrace();
-            }
-        }
-        return builder.toString();
-    }
-
-
-    /**
-     * Range of the emoticons unicode.
-     */
-    private static final class EmoticonRange {
-
-        /**
-         * Start portion of the emoticon in string.
-         */
-        final int mStartPos;
-
-        /**
-         * End portion of the emoticon in string.
-         */
-        final int mEndPos;
-
-        /**
-         * {@link Emoticon}.
-         */
-        final Emoticon mEmoticon;
-
-        /**
-         * Private constructor.
-         *
-         * @param start    Start portion of the emoticon in string.
-         * @param end      End portion of the emoticon in string.
-         * @param emoticon {@link Emoticon}
-         */
-        private EmoticonRange(final int start,
-                              final int end,
-                              @NonNull final Emoticon emoticon) {
-            this.mStartPos = start;
-            this.mEndPos = end;
-            this.mEmoticon = emoticon;
-        }
-
-        @Override
-        public boolean equals(final Object o) {
-            if (this == o) return true;
-            if (o == null || getClass() != o.getClass()) return false;
-
-            final EmoticonRange that = (EmoticonRange) o;
-            return mStartPos == that.mStartPos
-                    && mEndPos == that.mEndPos
-                    && mEmoticon.equals(that.mEmoticon);
-        }
-
-        @Override
-        public int hashCode() {
-            int result = mStartPos;
-            result = 31 * result + mEndPos;
-            result = 31 * result + mEmoticon.hashCode();
-            return result;
-        }
-    }
-}

File diff suppressed because it is too large
+ 2 - 0
app/src/main/res/raw/regex


Some files were not shown because too many files changed in this diff