Skip to content
This repository has been archived by the owner on Apr 12, 2022. It is now read-only.

Add builtin emoji support #2187

Open
wants to merge 8 commits into
base: develop
Choose a base branch
from
4 changes: 4 additions & 0 deletions vector/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -212,6 +212,10 @@ dependencies {
implementation(name: 'react-native', ext: 'aar')
implementation(name: 'react-native-locale-detector', ext: 'aar')

// Library to add the built-in emoj on the chat room
// Some changes were needed to integrate it into this project. Until the new build
// is released, the snapshot has to be used.
compile 'com.vanniktech:emoji-one:0.6.0-SNAPSHOT'

// another tracking than GA
implementation 'org.piwik.sdk:piwik-sdk:2.0.0'
Expand Down
6 changes: 6 additions & 0 deletions vector/src/main/java/im/vector/VectorApp.java
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,9 @@
import android.text.TextUtils;
import android.util.Pair;

import com.vanniktech.emoji.one.EmojiOneProvider;
import com.vanniktech.emoji.EmojiManager;

import com.facebook.stetho.Stetho;

import org.matrix.androidsdk.MXSession;
Expand Down Expand Up @@ -335,6 +338,9 @@ public void onActivityDestroyed(Activity activity) {
Log.e(LOG_TAG, "cannot create the mMarkdownParser " + e.getMessage());
}

/* Adds the provider to handle the built-in emoji */
EmojiManager.install (new EmojiOneProvider ());

// track external language updates
// local update from the settings
// or screen rotation !
Expand Down
69 changes: 69 additions & 0 deletions vector/src/main/java/im/vector/activity/VectorRoomActivity.java
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@
import android.content.res.Configuration;
import android.content.res.Resources;
import android.graphics.Color;
import android.graphics.PorterDuff;
import android.net.Uri;
import android.os.Build;
import android.os.Bundle;
Expand Down Expand Up @@ -66,6 +67,18 @@
import android.widget.TextView;
import android.widget.Toast;

import com.vanniktech.emoji.EmojiImageView;
import com.vanniktech.emoji.EmojiPopup;
import com.vanniktech.emoji.EmojiView;
import com.vanniktech.emoji.emoji.Emoji;
import com.vanniktech.emoji.listeners.OnEmojiBackspaceClickListener;
import com.vanniktech.emoji.listeners.OnEmojiClickListener;
import com.vanniktech.emoji.listeners.OnEmojiLongClickListener;
import com.vanniktech.emoji.listeners.OnEmojiPopupDismissListener;
import com.vanniktech.emoji.listeners.OnEmojiPopupShownListener;
import com.vanniktech.emoji.listeners.OnSoftKeyboardCloseListener;
import com.vanniktech.emoji.listeners.OnSoftKeyboardOpenListener;

import org.matrix.androidsdk.MXSession;
import org.matrix.androidsdk.call.IMXCall;
import org.matrix.androidsdk.call.IMXCallListener;
Expand Down Expand Up @@ -215,6 +228,12 @@ public class VectorRoomActivity extends MXCActionBarActivity implements MatrixMe

private MXLatestChatMessageCache mLatestChatMessageCache;


/**
* Popup to toggle between normal and emoji keyboards.
*/
private EmojiPopup emojiPopup;

private View mSendingMessagesLayout;
private View mSendButtonLayout;
private ImageView mSendImageView;
Expand Down Expand Up @@ -1150,6 +1169,10 @@ public void onActiveWidgetUpdate() {

refreshSelfAvatar();

/* Sets up the button to toggle an emoji keyboard */
setUpEmoji ();


// in case a "Send as" dialog was in progress when the activity was destroyed (life cycle)
mVectorRoomMediasSender.resumeResizeMediaAndSend();

Expand All @@ -1175,6 +1198,52 @@ public void onActiveWidgetUpdate() {
Log.d(LOG_TAG, "End of create");
}

/**
* Sets up everything for the emoji built-in popup.
*/
public void setUpEmoji () {

final VectorAutoCompleteTextView editText = findViewById (R.id.editText_messageBox);
final ImageView emojiButton = findViewById (R.id.room_sending_message_emoji);

ViewGroup rootView = findViewById (R.id.activity_vector_room_root_view);
emojiButton.setOnClickListener (
new View.OnClickListener () {
@Override
public void onClick (View v) {
emojiPopup.toggle ();
}
}
);

/* Sadly, lambdas aren't supported on Java 7 and that's the build platform */
emojiPopup = EmojiPopup.Builder
.fromRootView (rootView)
.setOnEmojiPopupShownListener (
new OnEmojiPopupShownListener () {
@Override
public void onEmojiPopupShown () {
/* Changes the icon to a little keyboard */
emojiButton.setImageResource (
R.drawable.emoji_keyboard
);
}
}
)
.setOnEmojiPopupDismissListener (
new OnEmojiPopupDismissListener () {
@Override
public void onEmojiPopupDismiss () {
/* Changes the icon to a little simley face */
emojiButton.setImageResource (
R.drawable.emoji_one_category_smileysandpeople
);
}
}
)
.build (editText);
}

@Override
public void onSaveInstanceState(Bundle savedInstanceState) {
// Always call the superclass so it can save the view hierarchy state
Expand Down
130 changes: 128 additions & 2 deletions vector/src/main/java/im/vector/view/VectorAutoCompleteTextView.java
Original file line number Diff line number Diff line change
Expand Up @@ -17,20 +17,30 @@
package im.vector.view;

import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Paint;
import android.os.Handler;
import android.os.Looper;
import android.support.annotation.CallSuper;
import android.support.annotation.DimenRes;
import android.support.annotation.Px;
import android.support.v7.widget.AppCompatMultiAutoCompleteTextView;
import android.text.Editable;
import android.text.InputType;
import android.text.TextUtils;
import android.util.AttributeSet;
import android.view.KeyEvent;
import android.view.View;
import android.view.ViewGroup;
import android.widget.AutoCompleteTextView;
import android.widget.Filter;
import android.widget.FrameLayout;
import android.widget.MultiAutoCompleteTextView;

import com.vanniktech.emoji.EmojiEditTextInterface;
import com.vanniktech.emoji.EmojiManager;
import com.vanniktech.emoji.emoji.Emoji;

import org.matrix.androidsdk.MXSession;
import org.matrix.androidsdk.data.Room;
import org.matrix.androidsdk.rest.model.RoomMember;
Expand All @@ -48,9 +58,12 @@
import org.matrix.androidsdk.util.Log;

/**
* Custom AppCompatMultiAutoCompleteTextView to display matrix id / displayname
* Custom AppCompatMultiAutoCompleteTextView to display matrix id / displayname, and
* to introduce messagges to be sent.
*/
public class VectorAutoCompleteTextView extends AppCompatMultiAutoCompleteTextView {
public class VectorAutoCompleteTextView extends AppCompatMultiAutoCompleteTextView
implements EmojiEditTextInterface {

private static final String LOG_TAG = VectorAutoCompleteTextView.class.getSimpleName();

// results adapter
Expand All @@ -68,20 +81,39 @@ public class VectorAutoCompleteTextView extends AppCompatMultiAutoCompleteTextVi
// add a colon when the inserted text is the first item of the string
private boolean mAddColonOnFirstItem;

/**
* Size of the emoji to be shown on this textView.
*/
private float emojiSize;

public VectorAutoCompleteTextView(Context context) {
super(context, null);
initEmoji ();
}

public VectorAutoCompleteTextView(Context context, AttributeSet attrs) {
super(context, attrs);
initEmoji ();
this.setInputType(this.getInputType() & (this.getInputType() ^ InputType.TYPE_TEXT_FLAG_AUTO_COMPLETE));
}

public VectorAutoCompleteTextView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
initEmoji ();
this.setInputType(this.getInputType() & (this.getInputType() ^ InputType.TYPE_TEXT_FLAG_AUTO_COMPLETE));
}

/**
* Initializes the emoji size.
*/
private void initEmoji () {

final Paint.FontMetrics fontMetrics = getPaint ().getFontMetrics ();
final float defaultEmojiSize = fontMetrics.descent - fontMetrics.ascent;

emojiSize = defaultEmojiSize;
}

/**
* Build the auto completions list for a session.
*
Expand Down Expand Up @@ -328,4 +360,98 @@ public CharSequence terminateToken(CharSequence text) {
}
}


/**
* Event fired when the text changes.
* Replaces the unicode charcode with the emoji image.
*/
@Override
@CallSuper
protected void onTextChanged (final CharSequence text
, final int start
, final int lengthBefore
, final int lengthAfter) {

final Paint.FontMetrics fontMetrics = getPaint ().getFontMetrics ();
final float defaultEmojiSize = fontMetrics.descent - fontMetrics.ascent;

EmojiManager.getInstance ().replaceWithImages (getContext ()
, getText ()
, emojiSize
, defaultEmojiSize
);
}


/* -------------------------------------------------------------------------- */
/* ---- Implementation of the methods inherited from the emoji interface ---- */
/* -------------------------------------------------------------------------- */

@Override
public void backspace () {

final KeyEvent event = new KeyEvent (0, 0, 0, KeyEvent.KEYCODE_DEL, 0
, 0, 0, 0, KeyEvent.KEYCODE_ENDCALL
);
dispatchKeyEvent (event);
}

@Override
public void input (Emoji emoji) {

if (emoji != null) {

final int start = getSelectionStart ();
final int end = getSelectionEnd ();

if (start < 0) {

append (emoji.getUnicode ());
} else {

getText ().replace (
Math.min (start, end)
, Math.max (start, end)
, emoji.getUnicode ()
, 0
, emoji.getUnicode ().length ()
);
}
}
}

@Override
public float getEmojiSize () {

return emojiSize;
}

@Override
public void setEmojiSize (@Px int pixels) {

setEmojiSize (pixels, true);
}

@Override
public void setEmojiSize (@Px int pixels, boolean shouldInvalidate) {

emojiSize = pixels;

if (shouldInvalidate) {

setText (getText ());
}
}

@Override
public void setEmojiSizeRes (@DimenRes int res) {

setEmojiSizeRes (res, true);
}

@Override
public void setEmojiSizeRes (@DimenRes int res, boolean shouldInvalidate) {

setEmojiSize (getResources ().getDimensionPixelSize (res), shouldInvalidate);
}
}
9 changes: 9 additions & 0 deletions vector/src/main/res/drawable/emoji_keyboard.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportHeight="24.0"
android:viewportWidth="24.0">
<path
android:fillColor="#FF000000"
android:pathData="M20,5L4,5c-1.1,0 -1.99,0.9 -1.99,2L2,17c0,1.1 0.9,2 2,2h16c1.1,0 2,-0.9 2,-2L22,7c0,-1.1 -0.9,-2 -2,-2zM11,8h2v2h-2L11,8zM11,11h2v2h-2v-2zM8,8h2v2L8,10L8,8zM8,11h2v2L8,13v-2zM7,13L5,13v-2h2v2zM7,10L5,10L5,8h2v2zM16,17L8,17v-2h8v2zM16,13h-2v-2h2v2zM16,10h-2L14,8h2v2zM19,13h-2v-2h2v2zM19,10h-2L17,8h2v2z" />
</vector>
15 changes: 15 additions & 0 deletions vector/src/main/res/layout/activity_vector_room.xml
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="@+id/activity_vector_room_root_view"
android:layout_width="match_parent"
android:layout_height="match_parent"
xmlns:tools="http://schemas.android.com/tools">
Expand Down Expand Up @@ -254,6 +255,7 @@
android:layout_height="40dp"
android:layout_centerVertical="true"
android:id="@+id/room_self_avatar"/>

</RelativeLayout>

<LinearLayout
Expand All @@ -265,6 +267,19 @@
android:minHeight="56dp"
android:layout_height="wrap_content">

<!-- Button to change between keyboard and emoji views -->
<ImageButton
android:id="@+id/room_sending_message_emoji"
android:layout_width="48dp"
android:layout_height="48dp"
android:background="?attr/selectableItemBackgroundBorderless"
android:padding="12dp"
android:scaleType="centerCrop"
app:srcCompat="@drawable/emoji_one_category_smileysandpeople"
tools:ignore="ContentDescription"
android:tint="#76CEA5"
/>

<RelativeLayout
android:layout_width="20dp"
android:layout_height="match_parent">
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -90,7 +90,7 @@
android:layout_height="14dp"
android:src="@drawable/e2e_verified" />

<TextView
<com.vanniktech.emoji.EmojiTextView
android:id="@+id/messagesAdapter_body"
android:layout_width="match_parent"
android:layout_height="wrap_content"
Expand Down Expand Up @@ -119,4 +119,4 @@

<include layout="@layout/message_read_marker" />

</LinearLayout>
</LinearLayout>
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,7 @@
android:layout_height="14dp"
android:src="@drawable/e2e_verified" />

<TextView
<com.vanniktech.emoji.EmojiTextView
android:id="@+id/messagesAdapter_body"
android:layout_width="match_parent"
android:layout_height="wrap_content"
Expand Down