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.view.inputmethod.InputMethodManager;
|
||||||
import android.widget.Button;
|
import android.widget.Button;
|
||||||
import android.widget.CheckBox;
|
import android.widget.CheckBox;
|
||||||
import android.widget.EditText;
|
|
||||||
import android.widget.ImageView;
|
import android.widget.ImageView;
|
||||||
import android.widget.LinearLayout;
|
import android.widget.LinearLayout;
|
||||||
import android.widget.TextView;
|
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.LinearLayoutManager;
|
||||||
import androidx.recyclerview.widget.RecyclerView;
|
import androidx.recyclerview.widget.RecyclerView;
|
||||||
import com.bumptech.glide.Glide;
|
import com.bumptech.glide.Glide;
|
||||||
|
@ -88,20 +89,24 @@ import org.linphone.settings.LinphonePreferences;
|
||||||
import org.linphone.utils.FileUtils;
|
import org.linphone.utils.FileUtils;
|
||||||
import org.linphone.utils.LinphoneUtils;
|
import org.linphone.utils.LinphoneUtils;
|
||||||
import org.linphone.utils.SelectableHelper;
|
import org.linphone.utils.SelectableHelper;
|
||||||
|
import org.linphone.views.RichEditText;
|
||||||
|
|
||||||
public class ChatMessagesFragment extends Fragment
|
public class ChatMessagesFragment extends Fragment
|
||||||
implements ChatRoomListener,
|
implements ChatRoomListener,
|
||||||
ContactsUpdatedListener,
|
ContactsUpdatedListener,
|
||||||
ChatMessageViewHolderClickListener,
|
ChatMessageViewHolderClickListener,
|
||||||
SelectableHelper.DeleteListener {
|
SelectableHelper.DeleteListener,
|
||||||
|
RichEditText.RichInputListener {
|
||||||
private static final int ADD_PHOTO = 1337;
|
private static final int ADD_PHOTO = 1337;
|
||||||
private static final int MESSAGES_PER_PAGE = 20;
|
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 final Handler mHandler = new Handler(Looper.getMainLooper());
|
||||||
private ImageView mBackButton, mCallButton, mBackToCallButton, mGroupInfosButton;
|
private ImageView mBackButton, mCallButton, mBackToCallButton, mGroupInfosButton;
|
||||||
private ImageView mAttachImageButton, mSendMessageButton;
|
private ImageView mAttachImageButton, mSendMessageButton;
|
||||||
private TextView mRoomLabel, mParticipantsLabel, mRemoteComposing;
|
private TextView mRoomLabel, mParticipantsLabel, mRemoteComposing;
|
||||||
private EditText mMessageTextToSend;
|
private RichEditText mMessageTextToSend;
|
||||||
private LayoutInflater mInflater;
|
private LayoutInflater mInflater;
|
||||||
private RecyclerView mChatEventsList;
|
private RecyclerView mChatEventsList;
|
||||||
private LinearLayout mFilesUploadLayout;
|
private LinearLayout mFilesUploadLayout;
|
||||||
|
@ -121,6 +126,9 @@ public class ChatMessagesFragment extends Fragment
|
||||||
private LinearLayout mTopBar;
|
private LinearLayout mTopBar;
|
||||||
private ImageView mChatRoomSecurityLevel;
|
private ImageView mChatRoomSecurityLevel;
|
||||||
|
|
||||||
|
private InputContentInfoCompat mCurrentInputContentInfo;
|
||||||
|
private int mCurrentFlags;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public View onCreateView(
|
public View onCreateView(
|
||||||
LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
|
LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
|
||||||
|
@ -293,6 +301,7 @@ public class ChatMessagesFragment extends Fragment
|
||||||
public void afterTextChanged(Editable editable) {}
|
public void afterTextChanged(Editable editable) {}
|
||||||
});
|
});
|
||||||
mMessageTextToSend.clearFocus();
|
mMessageTextToSend.clearFocus();
|
||||||
|
mMessageTextToSend.setListener(this);
|
||||||
|
|
||||||
mRemoteComposing = view.findViewById(R.id.remote_composing);
|
mRemoteComposing = view.findViewById(R.id.remote_composing);
|
||||||
|
|
||||||
|
@ -927,6 +936,13 @@ public class ChatMessagesFragment extends Fragment
|
||||||
String path = (String) child.getTag();
|
String path = (String) child.getTag();
|
||||||
files[i] = path;
|
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);
|
outState.putStringArray("Files", files);
|
||||||
super.onSaveInstanceState(outState);
|
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() {
|
private void pickFile() {
|
||||||
|
@ -1375,6 +1399,57 @@ public class ChatMessagesFragment extends Fragment
|
||||||
getContactsForParticipants();
|
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
|
// This is a workaround to prevent a crash from happening while rotating the device
|
||||||
private class LinphoneLinearLayoutManager extends LinearLayoutManager {
|
private class LinphoneLinearLayoutManager extends LinearLayoutManager {
|
||||||
LinphoneLinearLayoutManager(Context context, int orientation, boolean reverseLayout) {
|
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:padding="5dp"
|
||||||
android:src="@drawable/chat_file" />
|
android:src="@drawable/chat_file" />
|
||||||
|
|
||||||
<EditText
|
<org.linphone.views.RichEditText
|
||||||
android:id="@+id/message"
|
android:id="@+id/message"
|
||||||
android:layout_width="0dp"
|
android:layout_width="0dp"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
|
|
Loading…
Reference in a new issue