package cl.monsoon.s1next.view.fragment; import android.content.Context; import android.databinding.DataBindingUtil; import android.os.Bundle; import android.support.annotation.Nullable; import android.support.design.widget.TabLayout; import android.support.v4.app.Fragment; import android.support.v4.view.ViewCompat; import android.support.v4.view.ViewPager; import android.support.v4.view.ViewPropertyAnimatorListener; import android.support.v4.view.animation.FastOutSlowInInterpolator; import android.text.Editable; import android.text.TextUtils; import android.text.TextWatcher; import android.view.LayoutInflater; import android.view.Menu; import android.view.MenuInflater; import android.view.MenuItem; import android.view.View; import android.view.ViewGroup; import android.view.WindowManager; import android.view.animation.Interpolator; import android.view.inputmethod.InputMethodManager; import android.widget.EditText; import javax.inject.Inject; import cl.monsoon.s1next.App; import cl.monsoon.s1next.R; import cl.monsoon.s1next.data.event.EmoticonClickEvent; import cl.monsoon.s1next.data.pref.GeneralPreferencesManager; import cl.monsoon.s1next.databinding.FragmentReplyBinding; import cl.monsoon.s1next.util.DeviceUtil; import cl.monsoon.s1next.util.RxJavaUtil; import cl.monsoon.s1next.util.ViewUtil; import cl.monsoon.s1next.view.adapter.EmoticonPagerAdapter; import cl.monsoon.s1next.view.dialog.ReplyRequestDialogFragment; import cl.monsoon.s1next.widget.EventBus; import rx.Subscription; /** * A Fragment shows {@link EditText} to let the user enter reply. */ public final class ReplyFragment extends Fragment { public static final String TAG = ReplyFragment.class.getName(); private static final String ARG_THREAD_ID = "thread_id"; private static final String ARG_QUOTE_POST_ID = "quote_post_id"; /** * The serialization (saved instance state) Bundle key representing whether emoticon * keyboard is showing when configuration changes. */ private static final String STATE_IS_EMOTICON_KEYBOARD_SHOWING = "is_emoticon_keyboard_showing"; @Inject EventBus mEventBus; @Inject GeneralPreferencesManager mGeneralPreferencesManager; private String mThreadId; private String mQuotePostId; private FragmentReplyBinding mFragmentReplyBinding; private EditText mReplyView; private boolean mIsEmoticonKeyboardShowing; /** * {@code mMenuEmoticon} is null before {@link #onCreateOptionsMenu(Menu, MenuInflater)}. */ @Nullable private MenuItem mMenuEmoticon; private View mEmoticonKeyboard; private final Interpolator mInterpolator = new FastOutSlowInInterpolator(); /** * {@code mMenuSend} is null when configuration changes. */ @Nullable private MenuItem mMenuSend; private Subscription mSubscription; public static ReplyFragment newInstance(String threadId, @Nullable String quotePostId) { ReplyFragment fragment = new ReplyFragment(); Bundle bundle = new Bundle(); bundle.putString(ARG_THREAD_ID, threadId); bundle.putString(ARG_QUOTE_POST_ID, quotePostId); fragment.setArguments(bundle); return fragment; } @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { mFragmentReplyBinding = DataBindingUtil.inflate(inflater, R.layout.fragment_reply, container, false); mReplyView = mFragmentReplyBinding.reply; mEmoticonKeyboard = mFragmentReplyBinding.emoticonKeyboard; return mFragmentReplyBinding.getRoot(); } @Override public void onViewCreated(View view, Bundle savedInstanceState) { super.onViewCreated(view, savedInstanceState); App.getAppComponent(getContext()).inject(this); mThreadId = getArguments().getString(ARG_THREAD_ID); mQuotePostId = getArguments().getString(ARG_QUOTE_POST_ID); mReplyView.addTextChangedListener(new TextWatcher() { @Override public void beforeTextChanged(CharSequence s, int start, int count, int after) {} @Override public void onTextChanged(CharSequence s, int start, int before, int count) {} @Override public void afterTextChanged(Editable s) { if (mMenuSend != null) { // disable send menu if the content of reply is empty mMenuSend.setEnabled(!TextUtils.isEmpty(s.toString())); } } }); setupEmoticonKeyboard(); if (savedInstanceState != null) { mIsEmoticonKeyboardShowing = savedInstanceState.getBoolean( STATE_IS_EMOTICON_KEYBOARD_SHOWING); if (mIsEmoticonKeyboardShowing) { showEmoticonKeyboard(); } } } @Override public void onActivityCreated(Bundle savedInstanceState) { super.onActivityCreated(savedInstanceState); setHasOptionsMenu(true); } @Override public void onResume() { super.onResume(); mSubscription = mEventBus.get().subscribe(o -> { if (o instanceof EmoticonClickEvent) { mReplyView.getText().replace(mReplyView.getSelectionStart(), mReplyView.getSelectionEnd(), ((EmoticonClickEvent) o).getEmoticonEntity()); } }); } @Override public void onPause() { super.onPause(); RxJavaUtil.unsubscribeIfNotNull(mSubscription); } @Override public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) { inflater.inflate(R.menu.fragment_reply, menu); mMenuEmoticon = menu.findItem(R.id.menu_emoticon); if (mIsEmoticonKeyboardShowing) { setKeyboardIcon(); } mMenuSend = menu.findItem(R.id.menu_send).setEnabled(!TextUtils.isEmpty(mReplyView.getText())); } @Override public boolean onOptionsItemSelected(MenuItem item) { switch (item.getItemId()) { case R.id.menu_emoticon: if (mIsEmoticonKeyboardShowing) { hideEmoticonKeyboard(true); } else { showEmoticonKeyboard(); } return true; case R.id.menu_send: StringBuilder stringBuilder = new StringBuilder(mReplyView.getText()); if (mGeneralPreferencesManager.isSignatureEnabled()) { stringBuilder.append("\n\n").append(DeviceUtil.getSignature(getContext())); } ReplyRequestDialogFragment.newInstance(mThreadId, mQuotePostId, stringBuilder.toString()).show(getFragmentManager(), ReplyRequestDialogFragment.TAG); return true; default: return super.onOptionsItemSelected(item); } } @Override public void onSaveInstanceState(Bundle outState) { super.onSaveInstanceState(outState); outState.putBoolean(STATE_IS_EMOTICON_KEYBOARD_SHOWING, mIsEmoticonKeyboardShowing); } private void setupEmoticonKeyboard() { ViewPager viewPager = mFragmentReplyBinding.emoticonKeyboardPager; viewPager.setAdapter(new EmoticonPagerAdapter(getActivity())); TabLayout tabLayout = mFragmentReplyBinding.emoticonKeyboardTabLayout; tabLayout.setupWithViewPager(viewPager); } private void showEmoticonKeyboard() { mIsEmoticonKeyboardShowing = true; // hide keyboard ViewUtil.setShowSoftInputOnFocus(mReplyView, false); InputMethodManager inputMethodManager = (InputMethodManager) getContext().getSystemService( Context.INPUT_METHOD_SERVICE); inputMethodManager.hideSoftInputFromWindow(mReplyView.getWindowToken(), 0); getActivity().getWindow().setSoftInputMode( WindowManager.LayoutParams.SOFT_INPUT_STATE_ALWAYS_HIDDEN); mEmoticonKeyboard.setVisibility(View.VISIBLE); // translationYBy(-mEmoticonKeyboard.getHeight()) // doesn't work when orientation change ViewCompat.animate(mEmoticonKeyboard) .alpha(1) .translationY(0) .setInterpolator(mInterpolator) .withLayer() .setListener(new EmoticonKeyboardAnimator()); setKeyboardIcon(); } public void hideEmoticonKeyboard() { hideEmoticonKeyboard(false); } private void hideEmoticonKeyboard(boolean shouldShowKeyboard) { ViewCompat.animate(mEmoticonKeyboard) .alpha(0) .translationY(mEmoticonKeyboard.getHeight()) .setInterpolator(mInterpolator) .withLayer() .setListener(new EmoticonKeyboardAnimator() { @Override public void onAnimationEnd(View view) { mEmoticonKeyboard.setVisibility(View.GONE); ViewUtil.setShowSoftInputOnFocus(mReplyView, true); getActivity().getWindow().setSoftInputMode( WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE); if (shouldShowKeyboard) { InputMethodManager inputMethodManager = (InputMethodManager) getContext().getSystemService(Context.INPUT_METHOD_SERVICE); inputMethodManager.showSoftInput(mReplyView, InputMethodManager.SHOW_IMPLICIT); } super.onAnimationEnd(view); } }); mIsEmoticonKeyboardShowing = false; setEmoticonIcon(); } private void setEmoticonIcon() { if (mMenuEmoticon != null) { mMenuEmoticon.setIcon(R.drawable.ic_menu_keyboard_24dp); mMenuEmoticon.setTitle(R.string.menu_emoticon); } } private void setKeyboardIcon() { if (mMenuEmoticon != null) { mMenuEmoticon.setIcon(R.drawable.ic_menu_keyboard_24dp); mMenuEmoticon.setTitle(R.string.menu_keyboard); } } public boolean isEmoticonKeyboardShowing() { return mIsEmoticonKeyboardShowing; } public boolean isReplyEmpty() { return mReplyView == null || TextUtils.isEmpty(mReplyView.getText()); } private class EmoticonKeyboardAnimator implements ViewPropertyAnimatorListener { @Override public void onAnimationStart(View view) { if (mMenuEmoticon != null) { mMenuEmoticon.setEnabled(false); } } @Override public void onAnimationEnd(View view) { if (mMenuEmoticon != null) { mMenuEmoticon.setEnabled(true); } } @Override public void onAnimationCancel(View view) {} } }