Fix issue #508 - support Emoji for all devices

This commit is contained in:
stom79 2018-10-24 14:52:08 +02:00
parent 765af94b09
commit db80fcf6b4
13 changed files with 249 additions and 18 deletions

View File

@ -39,6 +39,7 @@ allprojects {
repositories {
maven { url "https://jitpack.io" }
maven { url "https://maven.google.com"}
maven { url "https://oss.sonatype.org/content/repositories/snapshots" }
}
}
ext.supportLibraryVersion = '28.0.0'
@ -72,6 +73,8 @@ dependencies {
implementation 'com.github.stom79:country-picker-android:1.2.0'
implementation 'com.github.stom79:mytransl:1.5'
implementation "com.koushikdutta.async:androidasync:2.+"
implementation 'com.vanniktech:emoji-one:0.6.0-SNAPSHOT'
implementation 'com.vanniktech:emoji-twitter:0.6.0-SNAPSHOT'
playstoreImplementation "io.github.kobakei:ratethisapp:$ratethisappLibraryVersion"

View File

@ -3,6 +3,9 @@ package fr.gouv.etalab.mastodon.activities;
import android.annotation.SuppressLint;
import android.support.v7.app.AppCompatActivity;
import com.vanniktech.emoji.EmojiManager;
import com.vanniktech.emoji.one.EmojiOneProvider;
import fr.gouv.etalab.mastodon.helper.Helper;
/**
@ -14,6 +17,7 @@ import fr.gouv.etalab.mastodon.helper.Helper;
public class BaseActivity extends AppCompatActivity {
static {
Helper.installProvider();
EmojiManager.install(new EmojiOneProvider());
}
}

View File

@ -56,7 +56,6 @@ import android.view.ViewTreeObserver;
import android.view.inputmethod.InputMethodManager;
import android.widget.AdapterView;
import android.widget.ArrayAdapter;
import android.widget.AutoCompleteTextView;
import android.widget.Button;
import android.widget.CheckBox;
import android.widget.CompoundButton;
@ -81,6 +80,7 @@ import com.github.stom79.localepicker.CountryPickerListener;
import com.github.stom79.mytransl.MyTransL;
import com.github.stom79.mytransl.client.HttpsConnectionException;
import com.github.stom79.mytransl.translate.Translate;
import com.vanniktech.emoji.EmojiPopup;
import java.io.ByteArrayInputStream;
@ -119,6 +119,7 @@ import fr.gouv.etalab.mastodon.client.Glide.GlideApp;
import fr.gouv.etalab.mastodon.client.HttpsConnection;
import fr.gouv.etalab.mastodon.drawers.CustomEmojiAdapter;
import fr.gouv.etalab.mastodon.drawers.EmojisSearchAdapter;
import fr.gouv.etalab.mastodon.helper.MastalabAutoCompleteTextView;
import fr.gouv.etalab.mastodon.interfaces.OnDownloadInterface;
import fr.gouv.etalab.mastodon.interfaces.OnRetrieveEmojiInterface;
import fr.gouv.etalab.mastodon.sqlite.CustomEmojiDAO;
@ -141,6 +142,7 @@ import fr.gouv.etalab.mastodon.R;
import static fr.gouv.etalab.mastodon.helper.Helper.HOME_TIMELINE_INTENT;
import static fr.gouv.etalab.mastodon.helper.Helper.INTENT_ACTION;
import static fr.gouv.etalab.mastodon.helper.Helper.THEME_LIGHT;
import static fr.gouv.etalab.mastodon.helper.Helper.changeDrawableColor;
import static fr.gouv.etalab.mastodon.helper.Helper.convertDpToPixel;
@ -161,7 +163,7 @@ public class TootActivity extends BaseActivity implements OnRetrieveSearcAccount
private boolean isSensitive = false;
private ImageButton toot_visibility;
private Button toot_it;
private AutoCompleteTextView toot_content;
private MastalabAutoCompleteTextView toot_content;
private EditText toot_cw_content;
private Status tootReply = null;
private String tootMention = null;
@ -179,6 +181,7 @@ public class TootActivity extends BaseActivity implements OnRetrieveSearcAccount
private HorizontalScrollView picture_scrollview;
private int currentCursorPosition, searchLength;
private TextView toot_space_left;
private ImageButton toot_emoji;
private String initialContent;
private final int MY_PERMISSIONS_REQUEST_READ_EXTERNAL_STORAGE = 754;
private Account accountReply;
@ -261,6 +264,19 @@ public class TootActivity extends BaseActivity implements OnRetrieveSearcAccount
picture_scrollview = findViewById(R.id.picture_scrollview);
toot_sensitive = findViewById(R.id.toot_sensitive);
drawer_layout = findViewById(R.id.drawer_layout);
toot_emoji = findViewById(R.id.toot_emoji);
final EmojiPopup emojiPopup = EmojiPopup.Builder.fromRootView(drawer_layout).build(toot_content);
toot_emoji.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
emojiPopup.toggle(); // Toggles visibility of the Popup.
}
});
drawer_layout.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
@Override
public void onGlobalLayout() {
@ -2157,7 +2173,7 @@ public class TootActivity extends BaseActivity implements OnRetrieveSearcAccount
private void changeColor(){
final SharedPreferences sharedpreferences = getSharedPreferences(Helper.APP_PREFS, Context.MODE_PRIVATE);
int theme = sharedpreferences.getInt(Helper.SET_THEME, Helper.THEME_DARK);
if( theme == Helper.THEME_DARK) {
if( theme == Helper.THEME_DARK || theme == Helper.THEME_BLACK) {
changeDrawableColor(TootActivity.this, R.drawable.ic_public_toot, R.color.dark_text);
changeDrawableColor(TootActivity.this, R.drawable.ic_lock_open_toot, R.color.dark_text);
changeDrawableColor(TootActivity.this, R.drawable.ic_lock_outline_toot, R.color.dark_text);
@ -2166,6 +2182,7 @@ public class TootActivity extends BaseActivity implements OnRetrieveSearcAccount
changeDrawableColor(TootActivity.this, R.drawable.ic_skip_previous, R.color.dark_text);
changeDrawableColor(TootActivity.this, R.drawable.ic_skip_next, R.color.dark_text);
changeDrawableColor(TootActivity.this, R.drawable.ic_check, R.color.dark_text);
changeDrawableColor(TootActivity.this, R.drawable.emoji_one_category_smileysandpeople, R.color.dark_text);
}else {
changeDrawableColor(TootActivity.this, R.drawable.ic_public_toot, R.color.white);
changeDrawableColor(TootActivity.this, R.drawable.ic_lock_open_toot, R.color.white);
@ -2175,6 +2192,7 @@ public class TootActivity extends BaseActivity implements OnRetrieveSearcAccount
changeDrawableColor(TootActivity.this, R.drawable.ic_skip_previous, R.color.white);
changeDrawableColor(TootActivity.this, R.drawable.ic_skip_next, R.color.white);
changeDrawableColor(TootActivity.this, R.drawable.ic_check, R.color.white);
changeDrawableColor(TootActivity.this, R.drawable.emoji_one_category_smileysandpeople, R.color.black);
}
}

View File

@ -51,6 +51,7 @@ import android.widget.Toast;
import com.bumptech.glide.Glide;
import com.vanniktech.emoji.EmojiTextView;
import java.io.File;
import java.io.FileOutputStream;
@ -1075,10 +1076,10 @@ public class NotificationsListAdapter extends RecyclerView.Adapter implements On
class ViewHolder extends RecyclerView.ViewHolder {
FrameLayout card_status_container;
CustomTextView notification_status_content;
EmojiTextView notification_status_content;
TextView notification_type;
LinearLayout status_spoiler_container;
CustomTextView status_spoiler;
EmojiTextView status_spoiler;
Button status_spoiler_button;
TextView notification_account_username;
ImageView notification_account_profile;

View File

@ -69,6 +69,8 @@ import com.github.stom79.mytransl.MyTransL;
import com.github.stom79.mytransl.client.HttpsConnectionException;
import com.github.stom79.mytransl.client.Results;
import com.github.stom79.mytransl.translate.Translate;
import com.vanniktech.emoji.EmojiTextView;
import java.io.File;
import java.io.FileOutputStream;
import java.util.ArrayList;
@ -226,9 +228,9 @@ public class StatusListAdapter extends RecyclerView.Adapter implements OnPostAct
class ViewHolder extends RecyclerView.ViewHolder{
LinearLayout status_content_container;
LinearLayout status_spoiler_container;
CustomTextView status_spoiler;
EmojiTextView status_spoiler;
Button status_spoiler_button;
CustomTextView status_content;
EmojiTextView status_content;
TextView status_content_translated;
LinearLayout status_content_translated_container;
TextView status_account_username;

View File

@ -14,33 +14,106 @@ package fr.gouv.etalab.mastodon.helper;
*
* You should have received a copy of the GNU General Public License along with Mastalab; if not,
* see <http://www.gnu.org/licenses>. */
import android.annotation.SuppressLint;
import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Paint;
import android.support.annotation.CallSuper;
import android.support.annotation.DimenRes;
import android.support.annotation.Px;
import android.text.Selection;
import android.text.Spannable;
import android.util.AttributeSet;
import android.view.KeyEvent;
import android.view.MotionEvent;
import com.vanniktech.emoji.EmojiEditTextInterface;
import com.vanniktech.emoji.emoji.Emoji;
import fr.gouv.etalab.mastodon.R;
/**
* Created by Thomas on 12/05/2018.
* Allows to fix crashes with selection see: https://stackoverflow.com/a/36740247
*/
public class CustomTextView extends android.support.v7.widget.AppCompatTextView {
public class CustomTextView extends android.support.v7.widget.AppCompatTextView implements EmojiEditTextInterface {
private float emojiSize;
public CustomTextView(Context context) {
super(context);
}
public CustomTextView(Context context, AttributeSet attrs) {
super(context, attrs);
final Paint.FontMetrics fontMetrics = getPaint().getFontMetrics();
final float defaultEmojiSize = fontMetrics.descent - fontMetrics.ascent;
if (attrs == null) {
emojiSize = defaultEmojiSize;
} else {
@SuppressLint("CustomViewStyleable") final TypedArray a = getContext().obtainStyledAttributes(attrs, R.styleable.EmojiMultiAutoCompleteTextView);
try {
emojiSize = a.getDimension(R.styleable.EmojiMultiAutoCompleteTextView_emojiSize, defaultEmojiSize);
} finally {
a.recycle();
}
}
setText(getText());
}
public CustomTextView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
}
@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 float getEmojiSize() {
return emojiSize;
}
@Override @CallSuper
public void input(final Emoji emoji) {
if (emoji != null) {
final int start = getSelectionStart();
final int end = getSelectionEnd();
append(emoji.getUnicode());
}
}
@Override
public final void setEmojiSize(@Px final int pixels) {
setEmojiSize(pixels, true);
}
@Override
public final void setEmojiSize(@Px final int pixels, final boolean shouldInvalidate) {
emojiSize = pixels;
if (shouldInvalidate) {
setText(getText());
}
}
@Override
public final void setEmojiSizeRes(@DimenRes final int res) {
setEmojiSizeRes(res, true);
}
@Override
public final void setEmojiSizeRes(@DimenRes final int res, final boolean shouldInvalidate) {
setEmojiSize(getResources().getDimensionPixelSize(res), shouldInvalidate);
}
//TODO: sounds no longer needed, commented but might be removed in a next release
/*@Override
public boolean dispatchTouchEvent(final MotionEvent event) {

View File

@ -0,0 +1,108 @@
package fr.gouv.etalab.mastodon.helper;
import android.annotation.SuppressLint;
import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Paint;
import android.support.annotation.CallSuper;
import android.support.annotation.DimenRes;
import android.support.annotation.Px;
import android.util.AttributeSet;
import android.view.KeyEvent;
import com.vanniktech.emoji.EmojiEditTextInterface;
import com.vanniktech.emoji.EmojiManager;
import com.vanniktech.emoji.emoji.Emoji;
import fr.gouv.etalab.mastodon.R;
public class MastalabAutoCompleteTextView extends android.support.v7.widget.AppCompatAutoCompleteTextView implements EmojiEditTextInterface {
private float emojiSize;
public MastalabAutoCompleteTextView(Context context) {
super(context);
}
public MastalabAutoCompleteTextView(Context context, AttributeSet attrs) {
super(context, attrs);
final Paint.FontMetrics fontMetrics = getPaint().getFontMetrics();
final float defaultEmojiSize = fontMetrics.descent - fontMetrics.ascent;
if (attrs == null) {
emojiSize = defaultEmojiSize;
} else {
@SuppressLint("CustomViewStyleable") final TypedArray a = getContext().obtainStyledAttributes(attrs, R.styleable.EmojiMultiAutoCompleteTextView);
try {
emojiSize = a.getDimension(R.styleable.EmojiMultiAutoCompleteTextView_emojiSize, defaultEmojiSize);
} finally {
a.recycle();
}
}
setText(getText());
}
public MastalabAutoCompleteTextView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
}
@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);
}
@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 float getEmojiSize() {
return emojiSize;
}
@Override @CallSuper public void input(final 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 final void setEmojiSize(@Px final int pixels) {
setEmojiSize(pixels, true);
}
@Override
public final void setEmojiSize(@Px final int pixels, final boolean shouldInvalidate) {
emojiSize = pixels;
if (shouldInvalidate) {
setText(getText());
}
}
@Override
public final void setEmojiSizeRes(@DimenRes final int res) {
setEmojiSizeRes(res, true);
}
@Override
public final void setEmojiSizeRes(@DimenRes final int res, final boolean shouldInvalidate) {
setEmojiSize(getResources().getDimensionPixelSize(res), shouldInvalidate);
}
}

View File

@ -120,6 +120,16 @@
style="@style/Base.Widget.AppCompat.Button.Borderless.Colored"
android:layout_width="50dp"
android:layout_height="50dp" />
<ImageButton
android:id="@+id/toot_emoji"
android:minHeight="0dp"
android:minWidth="0dp"
android:padding="2dp"
android:src="@drawable/emoji_one_category_smileysandpeople"
style="@style/Base.Widget.AppCompat.Button.Borderless.Colored"
android:layout_width="30dp"
android:layout_height="30dp"
/>
<TextView
android:id="@+id/toot_space_left"
android:layout_width="0dp"

View File

@ -38,7 +38,7 @@
android:hint="@string/toot_cw_placeholder"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
<AutoCompleteTextView
<fr.gouv.etalab.mastodon.helper.MastalabAutoCompleteTextView
android:layout_marginTop="10dp"
android:id="@+id/toot_content"
android:gravity="top|start"
@ -121,6 +121,18 @@
style="@style/Base.Widget.AppCompat.Button.Borderless.Colored"
android:layout_width="40dp"
android:layout_height="40dp" />
<ImageButton
android:id="@+id/toot_emoji"
android:minHeight="0dp"
android:minWidth="0dp"
android:layout_gravity="center"
android:padding="2dp"
android:scaleType="fitXY"
android:src="@drawable/emoji_one_category_smileysandpeople"
style="@style/Base.Widget.AppCompat.Button.Borderless.Colored"
android:layout_width="30dp"
android:layout_height="30dp"
/>
<TextView
android:id="@+id/toot_space_left"
android:layout_width="0dp"

View File

@ -91,7 +91,7 @@
android:orientation="vertical"
android:visibility="gone"
android:layout_height="wrap_content">
<fr.gouv.etalab.mastodon.helper.CustomTextView
<com.vanniktech.emoji.EmojiTextView
android:id="@+id/status_spoiler"
android:layout_marginTop="10dp"
android:textIsSelectable="true"
@ -122,7 +122,7 @@
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<fr.gouv.etalab.mastodon.helper.CustomTextView
<com.vanniktech.emoji.EmojiTextView
android:id="@+id/notification_status_content"
android:layout_marginTop="10dp"
android:textIsSelectable="true"

View File

@ -148,7 +148,7 @@
android:orientation="vertical"
android:visibility="gone"
android:layout_height="wrap_content">
<fr.gouv.etalab.mastodon.helper.CustomTextView
<com.vanniktech.emoji.EmojiTextView
android:id="@+id/status_spoiler"
android:layout_marginTop="10dp"
android:textIsSelectable="true"
@ -178,7 +178,7 @@
android:layout_width="match_parent"
android:orientation="vertical"
android:layout_height="wrap_content">
<fr.gouv.etalab.mastodon.helper.CustomTextView
<com.vanniktech.emoji.EmojiTextView
android:id="@+id/status_content"
android:textIsSelectable="true"
android:layout_marginTop="10dp"

View File

@ -121,7 +121,7 @@
android:orientation="vertical"
android:visibility="gone"
android:layout_height="wrap_content">
<fr.gouv.etalab.mastodon.helper.CustomTextView
<com.vanniktech.emoji.EmojiTextView
android:id="@+id/status_spoiler"
android:layout_marginTop="10dp"
android:textIsSelectable="true"
@ -152,7 +152,7 @@
android:layout_marginBottom="5dp"
android:orientation="vertical"
android:layout_height="wrap_content">
<fr.gouv.etalab.mastodon.helper.CustomTextView
<com.vanniktech.emoji.EmojiTextView
android:id="@+id/status_content"
android:textIsSelectable="true"
android:layout_marginLeft="10dp"

View File

@ -110,7 +110,7 @@
android:orientation="vertical"
android:visibility="gone"
android:layout_height="wrap_content">
<fr.gouv.etalab.mastodon.helper.CustomTextView
<com.vanniktech.emoji.EmojiTextView
android:id="@+id/status_spoiler"
android:layout_marginTop="10dp"
android:textIsSelectable="true"
@ -140,7 +140,7 @@
android:layout_width="match_parent"
android:orientation="vertical"
android:layout_height="wrap_content">
<fr.gouv.etalab.mastodon.helper.CustomTextView
<com.vanniktech.emoji.EmojiTextView
android:id="@+id/status_content"
android:textIsSelectable="true"
android:layout_marginLeft="10dp"