com.tweetlanes.android.core.view.ComposeBaseFragment.java Source code

Java tutorial

Introduction

Here is the source code for com.tweetlanes.android.core.view.ComposeBaseFragment.java

Source

/*
 * Copyright (C) 2013 Chris Lacy Licensed under the Apache License, Version 2.0
 * (the "License"); you may not use this file except in compliance with the
 * License. You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law
 * or agreed to in writing, software distributed under the License is
 * distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 * KIND, either express or implied. See the License for the specific language
 * governing permissions and limitations under the License.
 */

package com.tweetlanes.android.core.view;

import android.app.Activity;
import android.app.AlertDialog;
import android.content.Context;
import android.content.DialogInterface;
import android.content.pm.ActivityInfo;
import android.content.res.Configuration;
import android.os.Bundle;
import android.support.v4.app.Fragment;
import android.text.Editable;
import android.text.TextWatcher;
import android.util.TypedValue;
import android.view.LayoutInflater;
import android.view.MotionEvent;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.View.OnFocusChangeListener;
import android.view.ViewGroup;
import android.view.inputmethod.InputMethodManager;
import android.widget.AdapterView;
import android.widget.EditText;
import android.widget.ImageButton;
import android.widget.ImageView;
import android.widget.ListView;
import android.widget.TextView;
import android.widget.Toast;

import com.tweetlanes.android.core.App;
import com.tweetlanes.android.core.AppSettings;
import com.tweetlanes.android.core.Constant;
import com.tweetlanes.android.core.R;
import com.tweetlanes.android.core.model.AccountDescriptor;
import com.tweetlanes.android.core.model.ComposeTweetDefault;
import com.tweetlanes.android.core.util.LazyImageLoader;
import com.tweetlanes.android.core.widget.EditClearText;
import com.tweetlanes.android.core.widget.EditClearText.EditClearTextListener;
import com.twitter.Validator;

import org.socialnetlib.android.SocialNetConstant;
import org.tweetalib.android.TwitterManager;
import org.tweetalib.android.model.TwitterUser;

import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.Date;
import java.util.List;

abstract class ComposeBaseFragment extends Fragment {

    /*
     *
    */
    public interface ComposeListener {

        public void onShowCompose();

        public void onHideCompose();

        public void onMediaAttach();

        public void onMediaDetach();

        public void onBackButtonPressed();

        public void onStatusUpdateRequest();

        public void onStatusUpdateSuccess();

        public void onStatusHintUpdate();

        public void saveDraft(String draftAsJsonString);

        public String getDraft();
    }

    ImageButton mSendButton;
    EditClearText mEditText;
    private EditText mAutocompleteTarget;
    private TextView mCharacterCountTextView;
    private Long mShowStartTime;
    final Validator mStatusValidator = new Validator();
    private ListView mAutocompleteListView;

    ComposeListener mListener;
    private boolean mHasFocus = false;
    private boolean mIgnoreFocusChange = false;
    boolean mUpdatingStatus = false;

    /*
     *
    */
    App getApp() {
        if (getActivity() == null || getActivity().getApplication() == null) {
            return null;
        }
        return (App) getActivity().getApplication();
    }

    /*
     * (non-Javadoc)
     *
     * @see
     * android.support.v4.app.Fragment#onCreateView(android.view.LayoutInflater,
     * android.view.ViewGroup, android.os.Bundle)
     */
    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {

        View resultView = inflater.inflate(getLayoutResourceId(), null);

        mEditText = (EditClearText) resultView.findViewById(R.id.statusEditText);
        mEditText.addTextChangedListener(mTextChangedListener);
        mEditText.setOnFocusChangeListener(mOnFocusChangeListener);
        mEditText.setEditClearTextListener(mEditClearTextListener);

        mSendButton = (ImageButton) resultView.findViewById(R.id.sendTweetButton);
        mSendButton.setOnClickListener(mOnSendTweetClickListener);

        mCharacterCountTextView = (TextView) resultView.findViewById(R.id.characterCount);

        mCharacterCountTextView.setVisibility(View.VISIBLE);

        mAutocompleteListView = (ListView) resultView.findViewById(R.id.autocompleteListView);

        updateStatusHint();

        return resultView;
    }

    /*
     * (non-Javadoc)
     *
     * @see android.support.v4.app.Fragment#onPause()
     */
    @Override
    public void onPause() {
        super.onPause();

        if (hasFocus()) {
            saveCurrentAsDraft();
        }
    }

    /*
     * (non-Javadoc)
     *
     * @see android.support.v4.app.Fragment#onResume()
     */
    @Override
    public void onResume() {
        super.onResume();

        if (hasFocus()) {
            showCompose();
        }
    }

    int getMaxPostLength() {
        if (getApp() == null) {
            return 140;
        }

        AccountDescriptor account = getApp().getCurrentAccount();

        if (account == null) {
            return 140;
            //best to use the lower number in case
        } else {
            return account.getSocialNetType() == SocialNetConstant.Type.Appdotnet ? 256 : 140;
        }
    }

    /*
     *
    */
    void showToast(String message) {
        if (getActivity() != null && getActivity().getApplicationContext() != null) {
            Toast.makeText(getActivity().getApplicationContext(), message, Constant.DEFAULT_TOAST_DISPLAY_TIME)
                    .show();
        }
    }

    /*
     *
    */
    void showSimpleAlert(int stringID) {
        AlertDialog alertDialog = new AlertDialog.Builder(getActivity()).create();
        alertDialog.setMessage(getString(stringID));
        alertDialog.setButton(getString(R.string.ok), new DialogInterface.OnClickListener() {

            public void onClick(DialogInterface dialog, int which) {
            }
        });
        alertDialog.show();
    }

    /*
     *
    */
    public boolean hasFocus() {
        return mHasFocus;
    }

    /*
     *
    */
    void setComposeTweetListener(ComposeListener listener) {
        mListener = listener;
    }

    /*
     *
    */
    public void releaseFocus(boolean saveCurrentTweet) {

        clearCompose(saveCurrentTweet);
        setMediaPreviewVisibility();
        hideCompose();
    }

    /*
    *
    */
    boolean hideCompose() {

        if (mHasFocus) {

            hideKeyboard();
            if (mAutocompleteListView != null) {
                mAutocompleteListView.setVisibility(View.GONE);
            }

            if (mListener != null) {
                mListener.onHideCompose();
            }
            onHideCompose();

            mHasFocus = false;
            return true;
        }
        return false;
    }

    /*
    *
    */
    void showKeyboard() {
        InputMethodManager inputMethodManager = (InputMethodManager) getActivity()
                .getSystemService(Context.INPUT_METHOD_SERVICE);
        inputMethodManager.showSoftInput(mEditText, InputMethodManager.SHOW_IMPLICIT);
    }

    void hideKeyboard() {
        InputMethodManager inputMethodManager = (InputMethodManager) getActivity()
                .getSystemService(Context.INPUT_METHOD_SERVICE);
        inputMethodManager.hideSoftInputFromWindow(mEditText.getWindowToken(), 0);
    }

    /*
    *
    */
    private final OnFocusChangeListener mOnFocusChangeListener = new OnFocusChangeListener() {

        public void onFocusChange(View v, boolean hasFocus) {
            if (hasFocus && !mIgnoreFocusChange) {
                showCompose();
                setMediaPreviewVisibility();
            }
        }
    };

    /*
     * Used as a bit of a hack to prevent the Compose Tweet view enabling when
     * coming back from the ActionBar Search
     */
    void setIgnoreFocusChange(boolean ignoreFocusChange) {
        mIgnoreFocusChange = ignoreFocusChange;
    }

    /*
    *
    */
    private final TextWatcher mTextChangedListener = new TextWatcher() {

        public void afterTextChanged(Editable s) {
            String asString = s.toString();
            configureCharacterCountForString(asString);
            if (asString == null || asString.equals("")) {
                if (mListener.getDraft() == null) {
                    setComposeTweetDefault(null);
                    updateStatusHint();
                }
            }

            autoComplete(asString, mEditText);
        }

        public void beforeTextChanged(CharSequence s, int start, int count, int after) {
        }

        public void onTextChanged(CharSequence s, int start, int before, int count) {
        }
    };

    void autoComplete(String text, EditText editText) {
        if (mAutocompleteListView == null) {
            return;
        }

        if (text == null || text.length() == 0) {
            mAutocompleteListView.setVisibility(View.GONE);
            return;
        }

        int currentStart = editText.getSelectionStart();
        int currentEnd = editText.getSelectionEnd();
        int currentPosition = text.length() - 1;
        if (currentStart == currentEnd) {
            currentPosition = currentStart;
        }
        if (currentPosition < 0)
            currentPosition = 0;

        String lastWholeWord = "";

        for (int i = currentPosition; i > 0; i--) {
            String nextChar = text.substring(i - 1, i).toLowerCase();
            if (nextChar.equals(" ") || nextChar.equals(".")) {
                break;
            }
            lastWholeWord = nextChar + lastWholeWord;
        }

        if (lastWholeWord.startsWith("@")) {
            List<TwitterUser> autoCompleteMentions = getAutoCompleteMentions(lastWholeWord);

            mAutocompleteListView.setVisibility(View.VISIBLE);
            mAutocompleteListView
                    .setAdapter(new AutoCompleteMentionAdapter(this.getActivity(), autoCompleteMentions));
            mAutocompleteTarget = editText;
            mAutocompleteListView.setOnItemClickListener(mOnAutoCompleteItemClickListener);
        } else if (lastWholeWord.startsWith("#")) {
            List<String> autoCompleteHashtags = getAutoCompleteHashtags(lastWholeWord);

            mAutocompleteListView.setVisibility(View.VISIBLE);
            mAutocompleteListView
                    .setAdapter(new AutoCompleteHashtagAdapter(this.getActivity(), autoCompleteHashtags));
            mAutocompleteTarget = editText;
            mAutocompleteListView.setOnItemClickListener(mOnAutoCompleteItemClickListener);
        } else {
            mAutocompleteListView.setVisibility(View.GONE);
        }
    }

    private class AutoCompleteMentionAdapter extends android.widget.BaseAdapter {

        final Context mContext;
        final List<TwitterUser> mData;

        public AutoCompleteMentionAdapter(Context context, List<TwitterUser> data) {
            mContext = context;
            mData = data;
        }

        @Override
        public int getCount() {
            return mData.size();
        }

        @Override
        public TwitterUser getItem(int i) {
            return mData.get(i);
        }

        @Override
        public long getItemId(int i) {
            return getItem(i).getId();
        }

        @Override
        public View getView(int position, View convertView, ViewGroup parent) {
            View row = convertView;
            UserHolder holder;

            if (row == null) {
                LayoutInflater inflater = ((Activity) mContext).getLayoutInflater();
                row = inflater.inflate(R.layout.autocompletemention_row, parent, false);

                holder = new UserHolder();
                holder.AvatarImage = (ImageView) row.findViewById(R.id.autoCompleteAvatar);
                holder.ScreenName = (TextView) row.findViewById(R.id.autoCompleteScreenName);
                holder.FullName = (TextView) row.findViewById(R.id.autoCompleteFullName);

                int dimensionValue = mContext.getResources().getDimensionPixelSize(R.dimen.font_size_medium);
                int imageSize = (int) mContext.getResources().getDimension(R.dimen.font_size_medium);

                holder.ScreenName.setTextSize(TypedValue.COMPLEX_UNIT_PX, dimensionValue);
                holder.FullName.setTextSize(TypedValue.COMPLEX_UNIT_PX, dimensionValue);
                holder.AvatarImage.setMaxWidth(imageSize);
                holder.AvatarImage.setMaxHeight(imageSize);

                row.setTag(holder);
            } else {
                holder = (UserHolder) row.getTag();
            }

            TwitterUser user = mData.get(position);

            if (user == null) {
                return row;
            }

            holder.ScreenName.setText("@" + user.getScreenName(), TextView.BufferType.NORMAL);
            holder.FullName.setText(user.getName(), TextView.BufferType.NORMAL);
            setProfileImage(user, holder.AvatarImage);

            return row;
        }

        class UserHolder {
            public ImageView AvatarImage;
            public TextView ScreenName;
            public TextView FullName;
        }
    }

    private class AutoCompleteHashtagAdapter extends android.widget.BaseAdapter {

        final Context mContext;
        final List<String> mData;

        public AutoCompleteHashtagAdapter(Context context, List<String> data) {
            mContext = context;
            mData = data;
        }

        @Override
        public int getCount() {
            return mData.size();
        }

        @Override
        public String getItem(int i) {
            return mData.get(i);
        }

        @Override
        public long getItemId(int i) {
            return getItem(i).hashCode();
        }

        @Override
        public View getView(int position, View convertView, ViewGroup parent) {
            View row = convertView;
            HashtagHolder holder;

            if (row == null) {
                LayoutInflater inflater = ((Activity) mContext).getLayoutInflater();
                row = inflater.inflate(R.layout.autocompletehashtag_row, parent, false);

                holder = new HashtagHolder();
                holder.Hashtag = (TextView) row.findViewById(R.id.autoCompleteHashtag);

                int dimensionValue = mContext.getResources().getDimensionPixelSize(R.dimen.font_size_medium);

                holder.Hashtag.setTextSize(TypedValue.COMPLEX_UNIT_PX, dimensionValue);

                row.setTag(holder);
            } else {
                holder = (HashtagHolder) row.getTag();
            }

            String hashtag = mData.get(position);

            if (hashtag == null) {
                return row;
            }

            holder.Hashtag.setText(hashtag, TextView.BufferType.NORMAL);

            return row;
        }

        class HashtagHolder {
            public TextView Hashtag;
        }
    }

    private void setProfileImage(TwitterUser user, ImageView avatar) {
        String profileImageUrl = user.getProfileImageUrl(TwitterManager.ProfileImageSize.NORMAL);
        if (profileImageUrl != null) {

            if (AppSettings.get().downloadFeedImages()) {

                LazyImageLoader profileImageLoader = getApp().getProfileImageLoader();
                if (profileImageLoader != null) {

                    profileImageLoader.displayImage(profileImageUrl, avatar);
                }
            }
        }
    }

    private final AdapterView.OnItemClickListener mOnAutoCompleteItemClickListener = new AdapterView.OnItemClickListener() {
        public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
            TextView textView = (TextView) view.findViewById(R.id.autoCompleteScreenName);
            if (textView == null) {
                textView = (TextView) view.findViewById(R.id.autoCompleteHashtag);
            }

            String autoCompleteText = String.valueOf(textView.getText());
            String editText = String.valueOf(mAutocompleteTarget.getText());
            int currentStart = mAutocompleteTarget.getSelectionStart();
            int currentEnd = mAutocompleteTarget.getSelectionEnd();
            int currentPosition = editText.length() - 1;
            if (currentStart == currentEnd) {
                currentPosition = currentStart;
            }
            if (currentPosition < 0)
                currentPosition = 0;

            int autoCompleteStart = 0;

            for (int i = currentPosition; i > 0; i--) {
                String nextChar = editText.substring(i - 1, i).toLowerCase();
                if (nextChar.equals(" ") || nextChar.equals(".")) {
                    break;
                }
                autoCompleteStart = i - 1;
            }

            String newText = editText.substring(0, autoCompleteStart) + autoCompleteText + " "
                    + editText.substring(currentPosition);
            mAutocompleteTarget.setText(newText);
            mAutocompleteTarget.setSelection(autoCompleteStart + autoCompleteText.length());

            mAutocompleteListView.setVisibility(View.GONE);
        }
    };

    private ArrayList<TwitterUser> getAutoCompleteMentions(String text) {
        ArrayList<TwitterUser> list = new ArrayList<TwitterUser>();
        List<TwitterUser> users = TwitterManager.get().getFetchUserInstance().getCachedUsers();

        text = text.replace("@", "");

        for (TwitterUser user : users) {

            if (user.getScreenName().toLowerCase().contains(text.toLowerCase())
                    || user.getName().toLowerCase().contains(text.toLowerCase())) {
                list.add(user);
            }
        }

        Collections.sort(list, new SortUserName());

        return list;
    }

    private ArrayList<String> getAutoCompleteHashtags(String text) {
        ArrayList<String> list = new ArrayList<String>();
        List<String> hashtags = TwitterManager.get().getFetchStatusesInstance().getCachedHashtags();

        if (hashtags == null) {
            return list;
        }

        for (String tag : hashtags) {
            if (tag.toLowerCase().startsWith(text.toLowerCase())) {
                list.add(tag);
            }
        }

        Collections.sort(list, new SortAlpha());

        return list;
    }

    private class SortUserName implements Comparator<Object> {
        public int compare(Object o1, Object o2) {
            TwitterUser s1 = (TwitterUser) o1;
            TwitterUser s2 = (TwitterUser) o2;
            return s1.getScreenName().toLowerCase().compareTo(s2.getScreenName().toLowerCase());
        }
    }

    private class SortAlpha implements Comparator<Object> {
        public int compare(Object o1, Object o2) {
            String s1 = (String) o1;
            String s2 = (String) o2;
            return s1.toLowerCase().compareTo(s2.toLowerCase());
        }

    }

    protected void lockScreenRotation() {
        if (getActivity() != null) {
            switch (getActivity().getResources().getConfiguration().orientation) {
            case Configuration.ORIENTATION_PORTRAIT:
                getActivity().setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
                break;
            case Configuration.ORIENTATION_LANDSCAPE:
                getActivity().setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE);
                break;
            }
        }
    }

    protected void resetScreenRotation() {
        if (getActivity() != null) {
            getActivity().setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED);
        }
    }

    /*
     *
     */
    private final OnClickListener mOnSendTweetClickListener = new OnClickListener() {

        @Override
        public void onClick(View v) {
            lockScreenRotation();

            String status = mEditText.getText().toString();
            if (status == null || status.equals("")) {
                ComposeTweetDefault composeTweetDefault = getComposeTweetDefault();
                if (composeTweetDefault != null) {
                    status = composeTweetDefault.getStatus();
                }
            }

            onSendClick(status);
        }
    };

    protected abstract void onSendClick(String status);

    protected abstract void setMediaPreviewVisibility();

    /*
     */
    private final EditClearTextListener mEditClearTextListener = new EditClearTextListener() {

        @Override
        public boolean canClearText() {
            if (mShowStartTime != null) {
                long diff = new Date().getTime() - mShowStartTime.longValue();
                if (diff < 500) {
                    return false;
                }
            }
            return true;
        }

        @Override
        public boolean onBackButtonPressed() {
            if (mListener != null) {
                mListener.onBackButtonPressed();
            }
            hideCompose();
            setMediaPreviewVisibility();
            return true;
        }

        @Override
        public void onTouch(View v, MotionEvent event) {
            if (!mHasFocus) {
                showCompose();
                setMediaPreviewVisibility();
            }
        }
    };

    /*
    *
    */
    void clearCompose(boolean saveCurrentTweet) {

        if (saveCurrentTweet) {
            saveCurrentAsDraft();
            updateComposeTweetDefault();
        } else {
            setComposeTweetDefault(null);

            if (mListener != null) {
                mListener.onMediaDetach();
            }

            if (getApp() != null) {
                getApp().clearTweetDraft();
            }
        }

        // NOTE: Changing these text values causes a crash during the copy/paste
        // process.
        mEditText.setText(null);
        updateStatusHint();
    }

    /*
    *
    */
    void showCompose() {
        showCompose(null);
    }

    void showCompose(String defaultStatus) {

        if (!mHasFocus) {

            mHasFocus = true;
            mShowStartTime = new Date().getTime();
            if (defaultStatus == null) {
                if (getComposeTweetDefault() == null && mListener != null) {
                    String savedDraftAsJsonString = mListener.getDraft();
                    if (savedDraftAsJsonString != null) {
                        setComposeTweetDefault(new ComposeTweetDefault(savedDraftAsJsonString));
                    }
                }

                if (getComposeTweetDefault() != null) {
                    defaultStatus = getComposeTweetDefault().getStatus();
                }
            }
            mEditText.setText(defaultStatus);

            if (defaultStatus != null && defaultStatus.length() > 1) {
                mEditText.setSelection(defaultStatus.length());
                configureCharacterCountForString(defaultStatus);
            }

            if (mListener != null) {
                mListener.onShowCompose();
            }

            onShowCompose();
        }

        showKeyboard();
    }

    /*
    *
    */
    static String getStatusHintSnippet(String status, int maxLength) {

        if (status.length() == 0) {
            return null;
        } else if (status.length() < maxLength) {
            return status;
        }

        return status.substring(0, maxLength) + "";
    }

    /*
     *
     */
    ComposeTweetDefault _mComposeDefault;

    ComposeTweetDefault getComposeTweetDefault() {
        return _mComposeDefault;
    }

    /*
    *
    */
    void setComposeTweetDefault(ComposeTweetDefault composeTweetDefault) {
        _mComposeDefault = composeTweetDefault;
    }

    /*
    *
    */
    public void setComposeDefault(ComposeTweetDefault other) {
        if (other != null) {
            setComposeTweetDefault(new ComposeTweetDefault(other));
        } else {
            setComposeTweetDefault(null);
        }
        updateStatusHint();
    }

    /*
    *
    */
    void configureCharacterCountForString(String string) {

        if (string != null) {
            int length = mStatusValidator.getTweetLength(string);
            if (length > 0) {
                int remaining = getMaxPostLength() - length;
                if (_mComposeDefault != null && _mComposeDefault.getMediaFilePath() != null) {
                    remaining -= 22;
                }

                mCharacterCountTextView.setText("" + remaining);
            } else {
                mCharacterCountTextView.setText("" + getMaxPostLength());
            }
        } else {
            mCharacterCountTextView.setText("");
        }
    }

    protected abstract void saveCurrentAsDraft();

    protected abstract void updateStatusHint();

    protected abstract void updateComposeTweetDefault();

    protected abstract String getTweetDefaultDraft();

    protected abstract void setTweetDefaultFromDraft(String tweetDraftAsJson);

    protected abstract int getLayoutResourceId();

    protected abstract void onShowCompose();

    protected abstract void onHideCompose();
}