mirror of
https://github.com/nextcloud/talk-android
synced 2025-03-06 14:27:24 +00:00
Fix emoji detection
Signed-off-by: Mario Danic <mario@lovelyhq.com>
This commit is contained in:
parent
d369c5d2b2
commit
f677d95fe7
@ -36,8 +36,8 @@ import com.nextcloud.talk.application.NextcloudTalkApplication;
|
|||||||
import com.nextcloud.talk.models.database.UserEntity;
|
import com.nextcloud.talk.models.database.UserEntity;
|
||||||
import com.nextcloud.talk.models.json.chat.ChatMessage;
|
import com.nextcloud.talk.models.json.chat.ChatMessage;
|
||||||
import com.nextcloud.talk.utils.DisplayUtils;
|
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.database.user.UserUtils;
|
||||||
import com.nextcloud.talk.utils.emoticons.EmoticonUtils;
|
|
||||||
import com.stfalcon.chatkit.messages.MessageHolders;
|
import com.stfalcon.chatkit.messages.MessageHolders;
|
||||||
import com.stfalcon.chatkit.utils.ShapeImageView;
|
import com.stfalcon.chatkit.utils.ShapeImageView;
|
||||||
|
|
||||||
@ -85,6 +85,7 @@ public class MagicIncomingTextMessageViewHolder
|
|||||||
public void onBind(ChatMessage message) {
|
public void onBind(ChatMessage message) {
|
||||||
super.onBind(message);
|
super.onBind(message);
|
||||||
String author;
|
String author;
|
||||||
|
|
||||||
if (!TextUtils.isEmpty(author = message.getActorDisplayName())) {
|
if (!TextUtils.isEmpty(author = message.getActorDisplayName())) {
|
||||||
messageAuthor.setText(author);
|
messageAuthor.setText(author);
|
||||||
} else {
|
} 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(),
|
messageString.setSpan(new RelativeSizeSpan(2.5f), 0, messageString.length(),
|
||||||
Spannable.SPAN_INCLUSIVE_EXCLUSIVE);
|
Spannable.SPAN_INCLUSIVE_EXCLUSIVE);
|
||||||
layoutParams.setWrapBefore(true);
|
layoutParams.setWrapBefore(true);
|
||||||
|
@ -34,8 +34,8 @@ import com.nextcloud.talk.application.NextcloudTalkApplication;
|
|||||||
import com.nextcloud.talk.models.database.UserEntity;
|
import com.nextcloud.talk.models.database.UserEntity;
|
||||||
import com.nextcloud.talk.models.json.chat.ChatMessage;
|
import com.nextcloud.talk.models.json.chat.ChatMessage;
|
||||||
import com.nextcloud.talk.utils.DisplayUtils;
|
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.database.user.UserUtils;
|
||||||
import com.nextcloud.talk.utils.emoticons.EmoticonUtils;
|
|
||||||
import com.stfalcon.chatkit.messages.MessageHolders;
|
import com.stfalcon.chatkit.messages.MessageHolders;
|
||||||
|
|
||||||
import java.util.HashMap;
|
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(),
|
messageString.setSpan(new RelativeSizeSpan(2.5f), 0, messageString.length(),
|
||||||
Spannable.SPAN_INCLUSIVE_EXCLUSIVE);
|
Spannable.SPAN_INCLUSIVE_EXCLUSIVE);
|
||||||
layoutParams.setWrapBefore(true);
|
layoutParams.setWrapBefore(true);
|
||||||
|
@ -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();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -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();
|
|
||||||
}
|
|
||||||
}
|
|
@ -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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
3
app/src/main/res/raw/regex
Normal file
3
app/src/main/res/raw/regex
Normal file
File diff suppressed because one or more lines are too long
Loading…
Reference in New Issue
Block a user