From 5f8685db32a903c0c2bbd0e69993f459d5e77586 Mon Sep 17 00:00:00 2001 From: Thomas Date: Tue, 17 May 2022 13:08:19 +0200 Subject: [PATCH] Fix issue #60 - Allow to upload gif from keyboard --- .../helper/FedilabAutoCompleteTextView.java | 198 ++++++++++++++++++ .../interfaces/EmojiEditTextInterface.java | 34 +++ .../android/ui/drawer/ComposeAdapter.java | 9 +- .../main/res/layout/drawer_status_compose.xml | 2 +- 4 files changed, 241 insertions(+), 2 deletions(-) create mode 100644 app/src/main/java/app/fedilab/android/helper/FedilabAutoCompleteTextView.java create mode 100644 app/src/main/java/app/fedilab/android/interfaces/EmojiEditTextInterface.java diff --git a/app/src/main/java/app/fedilab/android/helper/FedilabAutoCompleteTextView.java b/app/src/main/java/app/fedilab/android/helper/FedilabAutoCompleteTextView.java new file mode 100644 index 000000000..a5b2e47f3 --- /dev/null +++ b/app/src/main/java/app/fedilab/android/helper/FedilabAutoCompleteTextView.java @@ -0,0 +1,198 @@ +package app.fedilab.android.helper; + +import static app.fedilab.android.ui.drawer.ComposeAdapter.autocomplete; + +import android.content.Context; +import android.content.SharedPreferences; +import android.content.res.TypedArray; +import android.graphics.Paint; +import android.os.Build; +import android.os.Bundle; +import android.util.AttributeSet; +import android.view.KeyEvent; +import android.view.inputmethod.EditorInfo; +import android.view.inputmethod.InputConnection; + +import androidx.annotation.CallSuper; +import androidx.annotation.DimenRes; +import androidx.annotation.NonNull; +import androidx.annotation.Px; +import androidx.core.view.inputmethod.EditorInfoCompat; +import androidx.core.view.inputmethod.InputConnectionCompat; +import androidx.core.view.inputmethod.InputContentInfoCompat; +import androidx.preference.PreferenceManager; + +import com.google.android.material.textfield.MaterialAutoCompleteTextView; +import com.vanniktech.emoji.EmojiManager; +import com.vanniktech.emoji.emoji.Emoji; + +import app.fedilab.android.R; +import app.fedilab.android.interfaces.EmojiEditTextInterface; + +public class FedilabAutoCompleteTextView extends MaterialAutoCompleteTextView implements EmojiEditTextInterface { + + private float emojiSize; + private boolean emoji; + private String[] imgTypeString; + private KeyBoardInputCallbackListener keyBoardInputCallbackListener; + final InputConnectionCompat.OnCommitContentListener callback = + new InputConnectionCompat.OnCommitContentListener() { + @Override + public boolean onCommitContent(@NonNull InputContentInfoCompat inputContentInfo, + int flags, Bundle opts) { + + // read and display inputContentInfo asynchronously + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N_MR1 && (flags & + InputConnectionCompat.INPUT_CONTENT_GRANT_READ_URI_PERMISSION) != 0) { + try { + inputContentInfo.requestPermission(); + } catch (Exception e) { + return false; // return false if failed + } + } + boolean supported = false; + for (final String mimeType : imgTypeString) { + if (inputContentInfo.getDescription().hasMimeType(mimeType)) { + supported = true; + break; + } + } + if (!supported) { + return false; + } + + if (keyBoardInputCallbackListener != null) { + keyBoardInputCallbackListener.onCommitContent(inputContentInfo, flags, opts); + } + return true; // return true if succeeded + } + }; + + + public FedilabAutoCompleteTextView(Context context) { + super(context); + initView(); + } + + public FedilabAutoCompleteTextView(Context context, AttributeSet attrs) { + super(context, attrs); + + final Paint.FontMetrics fontMetrics = getPaint().getFontMetrics(); + final float defaultEmojiSize = fontMetrics.descent - fontMetrics.ascent; + final SharedPreferences sharedpreferences = PreferenceManager.getDefaultSharedPreferences(context); + emoji = sharedpreferences.getBoolean(context.getString(R.string.SET_DISPLAY_EMOJI), false); + if (attrs == null) { + emojiSize = defaultEmojiSize; + } else { + final TypedArray a = getContext().obtainStyledAttributes(attrs, R.styleable.EmojiMultiAutoCompleteTextView); + + try { + emojiSize = a.getDimension(R.styleable.EmojiMultiAutoCompleteTextView_emojiSize, defaultEmojiSize); + } finally { + a.recycle(); + } + } + + setText(getText()); + initView(); + } + + public FedilabAutoCompleteTextView(Context context, AttributeSet attrs, int defStyleAttr) { + super(context, attrs, defStyleAttr); + initView(); + } + + @Override + public InputConnection onCreateInputConnection(EditorInfo outAttrs) { + final InputConnection ic = super.onCreateInputConnection(outAttrs); + EditorInfoCompat.setContentMimeTypes(outAttrs, + imgTypeString); + return InputConnectionCompat.createWrapper(ic, outAttrs, callback); + } + + private void initView() { + imgTypeString = new String[]{"image/png", + "image/gif", + "image/jpeg", + "image/webp"}; + } + + public void setKeyBoardInputCallbackListener(KeyBoardInputCallbackListener keyBoardInputCallbackListener) { + this.keyBoardInputCallbackListener = keyBoardInputCallbackListener; + } + + @SuppressWarnings("unused") + public String[] getImgTypeString() { + return imgTypeString; + } + + @SuppressWarnings("unused") + public void setImgTypeString(String[] imgTypeString) { + this.imgTypeString = imgTypeString; + } + + @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; + if (emoji && !autocomplete) { + 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 + public final void setEmojiSize(@Px final int pixels) { + setEmojiSize(pixels, true); + } + + @Override + @CallSuper + public void input(final Emoji emoji) { + if (emoji != null && !autocomplete) { + 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, final boolean shouldInvalidate) { + emojiSize = pixels; + + if (shouldInvalidate && !autocomplete) { + 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); + } + + public interface KeyBoardInputCallbackListener { + void onCommitContent(InputContentInfoCompat inputContentInfo, + int flags, Bundle opts); + } +} diff --git a/app/src/main/java/app/fedilab/android/interfaces/EmojiEditTextInterface.java b/app/src/main/java/app/fedilab/android/interfaces/EmojiEditTextInterface.java new file mode 100644 index 000000000..620f11a0e --- /dev/null +++ b/app/src/main/java/app/fedilab/android/interfaces/EmojiEditTextInterface.java @@ -0,0 +1,34 @@ +package app.fedilab.android.interfaces; + +import androidx.annotation.DimenRes; +import androidx.annotation.Px; + +import com.vanniktech.emoji.emoji.Emoji; + +public interface EmojiEditTextInterface { + void backspace(); + + void input(Emoji emoji); + + float getEmojiSize(); + + /** + * sets the emoji size in pixels and automatically invalidates the text and renders it with the new size + */ + void setEmojiSize(@Px int pixels); + + /** + * sets the emoji size in pixels and automatically invalidates the text and renders it with the new size when {@code shouldInvalidate} is true + */ + void setEmojiSize(@Px int pixels, boolean shouldInvalidate); + + /** + * sets the emoji size in pixels with the provided resource and automatically invalidates the text and renders it with the new size + */ + void setEmojiSizeRes(@DimenRes int res); + + /** + * sets the emoji size in pixels with the provided resource and invalidates the text and renders it with the new size when {@code shouldInvalidate} is true + */ + void setEmojiSizeRes(@DimenRes int res, boolean shouldInvalidate); +} diff --git a/app/src/main/java/app/fedilab/android/ui/drawer/ComposeAdapter.java b/app/src/main/java/app/fedilab/android/ui/drawer/ComposeAdapter.java index bf5cdf0a0..1a0352d84 100644 --- a/app/src/main/java/app/fedilab/android/ui/drawer/ComposeAdapter.java +++ b/app/src/main/java/app/fedilab/android/ui/drawer/ComposeAdapter.java @@ -1135,7 +1135,14 @@ public class ComposeAdapter extends RecyclerView.Adapter { + if (inputContentInfo != null) { + Uri uri = inputContentInfo.getContentUri(); + List uris = new ArrayList<>(); + uris.add(uri); + addAttachment(position, uris); + } + }); holder.binding.content.setSelection(statusDraft.cursorPosition); if (statusDraft.setCursorToEnd) { statusDraft.setCursorToEnd = false; diff --git a/app/src/main/res/layout/drawer_status_compose.xml b/app/src/main/res/layout/drawer_status_compose.xml index 760355e34..c2f8ea26e 100644 --- a/app/src/main/res/layout/drawer_status_compose.xml +++ b/app/src/main/res/layout/drawer_status_compose.xml @@ -55,7 +55,7 @@ android:visibility="gone" app:layout_constraintTop_toBottomOf="@id/add_remove_status" /> -