diff --git a/app/build.gradle b/app/build.gradle index bb6a730b2..fb576e364 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -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" diff --git a/app/src/main/java/fr/gouv/etalab/mastodon/activities/BaseActivity.java b/app/src/main/java/fr/gouv/etalab/mastodon/activities/BaseActivity.java index 2ce82ba1b..309ea660b 100644 --- a/app/src/main/java/fr/gouv/etalab/mastodon/activities/BaseActivity.java +++ b/app/src/main/java/fr/gouv/etalab/mastodon/activities/BaseActivity.java @@ -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()); } } diff --git a/app/src/main/java/fr/gouv/etalab/mastodon/activities/TootActivity.java b/app/src/main/java/fr/gouv/etalab/mastodon/activities/TootActivity.java index b85fc8909..5a3f3f4a0 100644 --- a/app/src/main/java/fr/gouv/etalab/mastodon/activities/TootActivity.java +++ b/app/src/main/java/fr/gouv/etalab/mastodon/activities/TootActivity.java @@ -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); } } diff --git a/app/src/main/java/fr/gouv/etalab/mastodon/drawers/NotificationsListAdapter.java b/app/src/main/java/fr/gouv/etalab/mastodon/drawers/NotificationsListAdapter.java index 3336d2567..74e3a0052 100644 --- a/app/src/main/java/fr/gouv/etalab/mastodon/drawers/NotificationsListAdapter.java +++ b/app/src/main/java/fr/gouv/etalab/mastodon/drawers/NotificationsListAdapter.java @@ -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; diff --git a/app/src/main/java/fr/gouv/etalab/mastodon/drawers/StatusListAdapter.java b/app/src/main/java/fr/gouv/etalab/mastodon/drawers/StatusListAdapter.java index ad33fe6e4..21c1a3f48 100644 --- a/app/src/main/java/fr/gouv/etalab/mastodon/drawers/StatusListAdapter.java +++ b/app/src/main/java/fr/gouv/etalab/mastodon/drawers/StatusListAdapter.java @@ -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; diff --git a/app/src/main/java/fr/gouv/etalab/mastodon/helper/CustomTextView.java b/app/src/main/java/fr/gouv/etalab/mastodon/helper/CustomTextView.java index e3891a364..5a7a3703c 100644 --- a/app/src/main/java/fr/gouv/etalab/mastodon/helper/CustomTextView.java +++ b/app/src/main/java/fr/gouv/etalab/mastodon/helper/CustomTextView.java @@ -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 . */ +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) { diff --git a/app/src/main/java/fr/gouv/etalab/mastodon/helper/MastalabAutoCompleteTextView.java b/app/src/main/java/fr/gouv/etalab/mastodon/helper/MastalabAutoCompleteTextView.java new file mode 100644 index 000000000..3cbceff74 --- /dev/null +++ b/app/src/main/java/fr/gouv/etalab/mastodon/helper/MastalabAutoCompleteTextView.java @@ -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); + } +} diff --git a/app/src/main/res/layout-sw600dp/activity_toot.xml b/app/src/main/res/layout-sw600dp/activity_toot.xml index d746bcbf2..27c592133 100644 --- a/app/src/main/res/layout-sw600dp/activity_toot.xml +++ b/app/src/main/res/layout-sw600dp/activity_toot.xml @@ -120,6 +120,16 @@ style="@style/Base.Widget.AppCompat.Button.Borderless.Colored" android:layout_width="50dp" android:layout_height="50dp" /> + - + - - - - - - - -