Allow keyboard rich input in chat message
This commit is contained in:
parent
f9b2c2e7b2
commit
8caf5fa96d
3 changed files with 169 additions and 4 deletions
|
@ -49,10 +49,11 @@ import android.view.WindowManager;
|
|||
import android.view.inputmethod.InputMethodManager;
|
||||
import android.widget.Button;
|
||||
import android.widget.CheckBox;
|
||||
import android.widget.EditText;
|
||||
import android.widget.ImageView;
|
||||
import android.widget.LinearLayout;
|
||||
import android.widget.TextView;
|
||||
import androidx.core.view.inputmethod.InputConnectionCompat;
|
||||
import androidx.core.view.inputmethod.InputContentInfoCompat;
|
||||
import androidx.recyclerview.widget.LinearLayoutManager;
|
||||
import androidx.recyclerview.widget.RecyclerView;
|
||||
import com.bumptech.glide.Glide;
|
||||
|
@ -88,20 +89,24 @@ import org.linphone.settings.LinphonePreferences;
|
|||
import org.linphone.utils.FileUtils;
|
||||
import org.linphone.utils.LinphoneUtils;
|
||||
import org.linphone.utils.SelectableHelper;
|
||||
import org.linphone.views.RichEditText;
|
||||
|
||||
public class ChatMessagesFragment extends Fragment
|
||||
implements ChatRoomListener,
|
||||
ContactsUpdatedListener,
|
||||
ChatMessageViewHolderClickListener,
|
||||
SelectableHelper.DeleteListener {
|
||||
SelectableHelper.DeleteListener,
|
||||
RichEditText.RichInputListener {
|
||||
private static final int ADD_PHOTO = 1337;
|
||||
private static final int MESSAGES_PER_PAGE = 20;
|
||||
private static final String INPUT_CONTENT_INFO_KEY = "COMMIT_CONTENT_INPUT_CONTENT_INFO";
|
||||
private static final String COMMIT_CONTENT_FLAGS_KEY = "COMMIT_CONTENT_FLAGS";
|
||||
|
||||
private final Handler mHandler = new Handler(Looper.getMainLooper());
|
||||
private ImageView mBackButton, mCallButton, mBackToCallButton, mGroupInfosButton;
|
||||
private ImageView mAttachImageButton, mSendMessageButton;
|
||||
private TextView mRoomLabel, mParticipantsLabel, mRemoteComposing;
|
||||
private EditText mMessageTextToSend;
|
||||
private RichEditText mMessageTextToSend;
|
||||
private LayoutInflater mInflater;
|
||||
private RecyclerView mChatEventsList;
|
||||
private LinearLayout mFilesUploadLayout;
|
||||
|
@ -121,6 +126,9 @@ public class ChatMessagesFragment extends Fragment
|
|||
private LinearLayout mTopBar;
|
||||
private ImageView mChatRoomSecurityLevel;
|
||||
|
||||
private InputContentInfoCompat mCurrentInputContentInfo;
|
||||
private int mCurrentFlags;
|
||||
|
||||
@Override
|
||||
public View onCreateView(
|
||||
LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
|
||||
|
@ -293,6 +301,7 @@ public class ChatMessagesFragment extends Fragment
|
|||
public void afterTextChanged(Editable editable) {}
|
||||
});
|
||||
mMessageTextToSend.clearFocus();
|
||||
mMessageTextToSend.setListener(this);
|
||||
|
||||
mRemoteComposing = view.findViewById(R.id.remote_composing);
|
||||
|
||||
|
@ -927,6 +936,13 @@ public class ChatMessagesFragment extends Fragment
|
|||
String path = (String) child.getTag();
|
||||
files[i] = path;
|
||||
}
|
||||
if (mCurrentInputContentInfo != null) {
|
||||
outState.putParcelable(
|
||||
INPUT_CONTENT_INFO_KEY, (Parcelable) mCurrentInputContentInfo.unwrap());
|
||||
outState.putInt(COMMIT_CONTENT_FLAGS_KEY, mCurrentFlags);
|
||||
}
|
||||
mCurrentInputContentInfo = null;
|
||||
mCurrentFlags = 0;
|
||||
outState.putStringArray("Files", files);
|
||||
super.onSaveInstanceState(outState);
|
||||
}
|
||||
|
@ -942,6 +958,14 @@ public class ChatMessagesFragment extends Fragment
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
final InputContentInfoCompat previousInputContentInfo =
|
||||
InputContentInfoCompat.wrap(
|
||||
savedInstanceState.getParcelable(INPUT_CONTENT_INFO_KEY));
|
||||
final int previousFlags = savedInstanceState.getInt(COMMIT_CONTENT_FLAGS_KEY);
|
||||
if (previousInputContentInfo != null) {
|
||||
onCommitContentInternal(previousInputContentInfo, previousFlags);
|
||||
}
|
||||
}
|
||||
|
||||
private void pickFile() {
|
||||
|
@ -1375,6 +1399,57 @@ public class ChatMessagesFragment extends Fragment
|
|||
getContactsForParticipants();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onCommitContent(
|
||||
InputContentInfoCompat inputContentInfo,
|
||||
int flags,
|
||||
Bundle opts,
|
||||
String[] contentMimeTypes) {
|
||||
try {
|
||||
if (mCurrentInputContentInfo != null) {
|
||||
mCurrentInputContentInfo.releasePermission();
|
||||
}
|
||||
} catch (Exception e) {
|
||||
Log.e("[TimelineFragment] releasePermission failed : ", e);
|
||||
} finally {
|
||||
mCurrentInputContentInfo = null;
|
||||
}
|
||||
|
||||
boolean supported = false;
|
||||
for (final String mimeType : contentMimeTypes) {
|
||||
if (inputContentInfo.getDescription().hasMimeType(mimeType)) {
|
||||
supported = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!supported) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return onCommitContentInternal(inputContentInfo, flags);
|
||||
}
|
||||
|
||||
private boolean onCommitContentInternal(InputContentInfoCompat inputContentInfo, int flags) {
|
||||
if ((flags & InputConnectionCompat.INPUT_CONTENT_GRANT_READ_URI_PERMISSION) != 0) {
|
||||
try {
|
||||
inputContentInfo.requestPermission();
|
||||
} catch (Exception e) {
|
||||
Log.e("[TimelineFragment] requestPermission failed : ", e);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (inputContentInfo.getContentUri() != null) {
|
||||
String contentUri = FileUtils.getFilePath(mContext, inputContentInfo.getContentUri());
|
||||
addImageToPendingList(contentUri);
|
||||
}
|
||||
|
||||
mCurrentInputContentInfo = inputContentInfo;
|
||||
mCurrentFlags = flags;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// This is a workaround to prevent a crash from happening while rotating the device
|
||||
private class LinphoneLinearLayoutManager extends LinearLayoutManager {
|
||||
LinphoneLinearLayoutManager(Context context, int orientation, boolean reverseLayout) {
|
||||
|
|
90
app/src/main/java/org/linphone/views/RichEditText.java
Normal file
90
app/src/main/java/org/linphone/views/RichEditText.java
Normal file
|
@ -0,0 +1,90 @@
|
|||
package org.linphone.views;
|
||||
|
||||
/*
|
||||
RichInputEditText.java
|
||||
Copyright (C) 2019 Belledonne Communications, Grenoble, France
|
||||
|
||||
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 2
|
||||
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, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
import android.annotation.SuppressLint;
|
||||
import android.content.Context;
|
||||
import android.os.Bundle;
|
||||
import android.util.AttributeSet;
|
||||
import android.view.inputmethod.EditorInfo;
|
||||
import android.view.inputmethod.InputConnection;
|
||||
import android.widget.EditText;
|
||||
import androidx.core.view.inputmethod.EditorInfoCompat;
|
||||
import androidx.core.view.inputmethod.InputConnectionCompat;
|
||||
import androidx.core.view.inputmethod.InputContentInfoCompat;
|
||||
|
||||
@SuppressLint("AppCompatCustomView")
|
||||
public class RichEditText extends EditText {
|
||||
public interface RichInputListener {
|
||||
boolean onCommitContent(
|
||||
InputContentInfoCompat inputContentInfo,
|
||||
int flags,
|
||||
Bundle opts,
|
||||
String[] contentMimeTypes);
|
||||
}
|
||||
|
||||
private RichInputListener mListener;
|
||||
private String[] mSupportedMimeTypes;
|
||||
|
||||
public RichEditText(Context context) {
|
||||
super(context);
|
||||
}
|
||||
|
||||
public RichEditText(Context context, AttributeSet attrs) {
|
||||
super(context, attrs);
|
||||
}
|
||||
|
||||
public RichEditText(Context context, AttributeSet attrs, int defStyleAttr) {
|
||||
super(context, attrs, defStyleAttr);
|
||||
}
|
||||
|
||||
public RichEditText(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
|
||||
super(context, attrs, defStyleAttr, defStyleRes);
|
||||
}
|
||||
|
||||
public void setListener(RichInputListener listener) {
|
||||
mListener = listener;
|
||||
mSupportedMimeTypes = new String[] {"image/png", "image/gif", "image/jpeg"};
|
||||
}
|
||||
|
||||
@Override
|
||||
public InputConnection onCreateInputConnection(EditorInfo editorInfo) {
|
||||
final InputConnection ic = super.onCreateInputConnection(editorInfo);
|
||||
EditorInfoCompat.setContentMimeTypes(editorInfo, mSupportedMimeTypes);
|
||||
|
||||
final InputConnectionCompat.OnCommitContentListener callback =
|
||||
new InputConnectionCompat.OnCommitContentListener() {
|
||||
@Override
|
||||
public boolean onCommitContent(
|
||||
InputContentInfoCompat inputContentInfo, int flags, Bundle opts) {
|
||||
if (mListener != null) {
|
||||
return mListener.onCommitContent(
|
||||
inputContentInfo, flags, opts, mSupportedMimeTypes);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
if (ic != null) {
|
||||
return InputConnectionCompat.createWrapper(ic, editorInfo, callback);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
|
@ -139,7 +139,7 @@
|
|||
android:padding="5dp"
|
||||
android:src="@drawable/chat_file" />
|
||||
|
||||
<EditText
|
||||
<org.linphone.views.RichEditText
|
||||
android:id="@+id/message"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
|
|
Loading…
Reference in a new issue