package com.badoo.chateau.example.ui.widgets; import android.annotation.TargetApi; import android.content.Context; import android.content.res.TypedArray; import android.os.Build; import android.os.SystemClock; import android.support.annotation.MenuRes; import android.support.annotation.NonNull; import android.support.annotation.Nullable; import android.support.design.widget.FloatingActionButton; import android.text.Editable; import android.util.AttributeSet; import android.view.LayoutInflater; import android.view.MenuInflater; import android.view.MenuItem; import android.view.View; import android.view.ViewGroup; import android.widget.EditText; import android.widget.FrameLayout; import android.widget.ImageView; import android.widget.TextView; import com.badoo.chateau.example.R; /** * View providing a text input field, a row of icons for actions (e.g Add image, take picture, etc) and a Send button. */ public class ChatTextInputView extends FrameLayout { @Nullable private OnTypingListener mOnTypingListener; @Nullable private OnClickListener mOnSendClickListener; private EditText mEditText; private FloatingActionButton mSendEnabled; // Got two of these to workaround tinting issues on Android 4.4 private FloatingActionButton mSendDisabled; private ViewGroup mActionsContainer; private MenuItem.OnMenuItemClickListener mOnMenuItemClickedListener; private InputActionsMenu mMenu; private long mLastOnTypingNotification; // Keep track of last notification time for throttling public ChatTextInputView(Context context) { super(context); } public ChatTextInputView(Context context, AttributeSet attrs) { super(context, attrs); parseAttributes(attrs); } public ChatTextInputView(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); parseAttributes(attrs); } @TargetApi(Build.VERSION_CODES.LOLLIPOP) public ChatTextInputView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) { super(context, attrs, defStyleAttr, defStyleRes); parseAttributes(attrs); } private void parseAttributes(@NonNull AttributeSet attrs) { TypedArray a = getContext().getTheme().obtainStyledAttributes( attrs, R.styleable.ChatTextInputView, 0, 0); try { int menuRes = a.getResourceId(R.styleable.ChatTextInputView_actionMenu, -1); if (menuRes != -1) { setActions(menuRes); } } finally { a.recycle(); } } /** * Sets the listener to be invoked when the user taps the Send button. */ public void setOnSendClickListener(@Nullable OnClickListener listener) { mOnSendClickListener = listener; } /** * Sets the listener to be invoked when the user is entering text in the text field. */ public void setOnTypingListener(@Nullable OnTypingListener listener) { mOnTypingListener = listener; } /** * Sets the listener that will be invoked if an action item is clicked. */ public void setOnActionItemClickedListener(@Nullable MenuItem.OnMenuItemClickListener listener) { mOnMenuItemClickedListener = listener; } /** * Sets the actions to be displayed below the text field. Only the icon and id is used from each menu item. */ public void setActions(@MenuRes int menuRes) { mMenu = new InputActionsMenu(getContext()); new MenuInflater(getContext()).inflate(menuRes, mMenu); populateMenuIfReady(); } /** * Returns the text currently entered into the text field. * * @return the text in the text field */ @NonNull public String getText() { return mEditText.getText().toString(); } /** * Clears the text in the text field. */ public void clearText() { // On the LG G4 getText().clear() does not work so doing this instead. Thanks LG! mEditText.setText("", TextView.BufferType.EDITABLE); } @Override protected void onFinishInflate() { super.onFinishInflate(); LayoutInflater.from(getContext()).inflate(R.layout.view_chat_text_input, this); mActionsContainer = (ViewGroup) findViewById(R.id.chatTextInput_actionsContainer); mEditText = (EditText) findViewById(R.id.chatTextInput_editText); mEditText.addTextChangedListener(new SimpleTextWatcher() { @Override public void afterTextChanged(Editable s) { if (s == null) { return; } long elapsedTime = SystemClock.elapsedRealtime() - mLastOnTypingNotification; if (mOnTypingListener != null && s.length() > 0 && elapsedTime > 2000) { mLastOnTypingNotification = SystemClock.elapsedRealtime(); mOnTypingListener.onTyping(); } updateSendButtonState(s.length() > 0); } }); mSendEnabled = (FloatingActionButton) findViewById(R.id.chatTextInput_sendEnabled); mSendEnabled.setEnabled(true); mSendEnabled.setVisibility(View.GONE); mSendEnabled.setOnClickListener(v -> { if (mOnSendClickListener != null) { mOnSendClickListener.onClick(v); } }); mSendDisabled = (FloatingActionButton) findViewById(R.id.chatTextInput_sendDisabled); mSendDisabled.setEnabled(false); mSendDisabled.setVisibility(View.VISIBLE); populateMenuIfReady(); } private void updateSendButtonState(boolean enable) { if ((enable && mSendEnabled.getVisibility() == VISIBLE) || (!enable && mSendDisabled.getVisibility() == VISIBLE)) { // Already in correct state return; } if (enable) { mSendDisabled.hide(new FloatingActionButton.OnVisibilityChangedListener() { @Override public void onHidden(FloatingActionButton fab) { mSendEnabled.show(); } }); } else { mSendEnabled.hide(new FloatingActionButton.OnVisibilityChangedListener() { @Override public void onHidden(FloatingActionButton fab) { mSendDisabled.show(); } }); } } private final OnClickListener mOnActionItemViewClicked = new OnClickListener() { @Override public void onClick(View v) { if (mOnMenuItemClickedListener != null) { mOnMenuItemClickedListener.onMenuItemClick((MenuItem) v.getTag()); } } }; private void populateMenuIfReady() { if (mMenu == null || mActionsContainer == null) { return; } final LayoutInflater inflater = LayoutInflater.from(getContext()); mActionsContainer.removeAllViews(); for (int i = 0; i < mMenu.size(); i++) { MenuItem item = mMenu.getItem(i); final View itemView = inflater.inflate(R.layout.item_input_action, mActionsContainer, false); final ImageView itemIcon = (ImageView) itemView.findViewById(R.id.inputAction_image); itemView.setTag(item); itemView.setId(item.getItemId()); itemIcon.setImageDrawable(item.getIcon()); itemView.setOnClickListener(mOnActionItemViewClicked); mActionsContainer.addView(itemView); } } public interface OnTypingListener { void onTyping(); } }