@Route(Constants.Router.STATUS_DETAIL)
public class StatusDetailActivity extends BaseActivity {
    public static final String EXTRA_STATUS = "extra_status";
    private static final String TYPE_FAVORITE_STATUS = "favorite_status";
    private static final String TYPE_DELETE_STATUS = "delete_status";

    @BindView(R.id.toolbar) Toolbar mToolbar;
    @BindView(R.id.image_avatar) CircleImageView mImageAvatar;
    @BindView(R.id.text_name) TextView mTextName;
    @BindView(R.id.text_date) TextView mTextDate;
    @BindView(R.id.text_source) TextView mTextSource;
    @BindView(R.id.text_content) TextView mTextContent;
    @BindView(R.id.image_photo) ImageView mImagePhoto;
    @BindView(R.id.view_repeat) View mViewRepeat;
    @BindView(R.id.view_comment) View mViewComment;

    private StatusRes mStatusRes;

    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_status_detail);
        ButterKnife.bind(this);

        mStatusRes = getIntent().getParcelableExtra(EXTRA_STATUS);
        initViews();
    }

    @Override
    protected void initViews() {
        mToolbar.setTitle(getString(R.string.title_status_detail));
        setSupportActionBar(mToolbar);
        getSupportActionBar().setDisplayHomeAsUpEnabled(true);

        final UserRes userRes = mStatusRes.getUser();
        String imageUrl = userRes.getProfile_image_url_large();
        Glide.with(this).load(imageUrl).into(mImageAvatar);
        mTextName.setText(userRes.getName());
        mTextDate.setText(Utils.getIntervalTime(mStatusRes.getCreated_at()));
        mTextContent.setText(
                PatternUtils.formatWeiBoContent(this, mStatusRes.getText(), mTextContent));
        mTextSource.setText(Html.fromHtml(mStatusRes.getSource()).toString());

        if (mStatusRes.getPhoto() != null) {
            Glide.with(this).load(mStatusRes.getPhoto().getLargeurl()).into(mImagePhoto);
            mImagePhoto.setVisibility(View.VISIBLE);
        } else {
            mImagePhoto.setVisibility(View.GONE);
        }

        OnClickLister onClickLister = new OnClickLister(mStatusRes);

        mImagePhoto.setOnClickListener(onClickLister);
        mViewRepeat.setOnClickListener(onClickLister);
        mViewComment.setOnClickListener(onClickLister);
        mImageAvatar.setOnClickListener(onClickLister);
    }

    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        if (mStatusRes.isIs_self()) {
            getMenuInflater().inflate(R.menu.menu_status_detail_self, menu);
        } else {
            getMenuInflater().inflate(R.menu.menu_status_deatil, menu);
        }
        return super.onCreateOptionsMenu(menu);
    }

    @Override
    public boolean onPrepareOptionsMenu(Menu menu) {
        if (mStatusRes.isFavorited()) {
            menu.findItem(R.id.action_favorite).setTitle(R.string.action_cancel_favorite);
        } else {
            menu.findItem(R.id.action_favorite).setTitle(R.string.action_favorite);
        }
        return super.onPrepareOptionsMenu(menu);
    }

    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        switch (item.getItemId()) {
            case android.R.id.home:
                finish();
                break;
            case R.id.action_delete:
                showDeleteStatusDailog(mStatusRes);
                break;
            case R.id.action_favorite:
                createOrDestroyFavorite(mStatusRes);
                break;
            case R.id.action_copy:
                copyStatus(mStatusRes);
                break;
            case R.id.action_share:
                break;
        }
        return super.onOptionsItemSelected(item);
    }

    //删除消息
    private void destoryStatuses(final StatusRes statusRes) {
        SimpleRequestCallback requestCallback =
                new SimpleRequestCallback(statusRes, TYPE_DELETE_STATUS);
        StatusesRequest request = new StatusesRequest();
        request.setId(statusRes.getId());
        HttpRequestFactory.getInstance().destroyStatus(request, requestCallback);
    }

    //收藏或取消收藏消息
    private void createOrDestroyFavorite(final StatusRes statusRes) {
        SimpleRequestCallback requestCallback =
                new SimpleRequestCallback(statusRes, TYPE_FAVORITE_STATUS);

        if (statusRes.isFavorited()) {
            HttpRequestFactory.getInstance().destroyFavorite(statusRes.getId(), requestCallback);
        } else {
            HttpRequestFactory.getInstance().createFavorite(statusRes.getId(), requestCallback);
        }
    }

    private class SimpleRequestCallback extends SimpleHttpRequestCallback<StatusRes> {
        private StatusRes statusRes;
        private String type;

        public SimpleRequestCallback(StatusRes statusRes, String type) {
            this.statusRes = statusRes;
            this.type = type;
        }

        @Override
        public void onSuccess(StatusRes responseData) {
            if (TYPE_DELETE_STATUS.equals(type)) {
                EventBus.getDefault().post(new StatusRefreshEvent(mStatusRes, TYPE_DELETE_STATUS));
                finish();
                UIUtils.showToast(StatusDetailActivity.this,
                        getString(R.string.text_delete_success));
            } else if (TYPE_FAVORITE_STATUS.equals(type)) {
                statusRes.setFavorited(!statusRes.isFavorited());
                EventBus.getDefault()
                        .post(new StatusRefreshEvent(mStatusRes, TYPE_FAVORITE_STATUS));
                UIUtils.showToast(StatusDetailActivity.this,
                        getString(R.string.text_operate_success));
            }
        }

        @Override
        public void onFail(ApiException apiException) {
            if (TYPE_DELETE_STATUS.equals(type)) {
                UIUtils.showToast(StatusDetailActivity.this, getString(R.string.text_delete_fail));
            } else if (TYPE_FAVORITE_STATUS.equals(type)) {
                statusRes.setFavorited(!statusRes.isFavorited());
                UIUtils.showToast(StatusDetailActivity.this, getString(R.string.text_operate_fail));
            }
        }
    }

    private class OnClickLister implements View.OnClickListener {
        private StatusRes statusRes;

        public OnClickLister(StatusRes statusRes) {
            this.statusRes = statusRes;
        }

        @Override
        public void onClick(View view) {
            switch (view.getId()) {
                case R.id.image_avatar:
                    Bundle userBundle = new Bundle();
                    userBundle.putParcelable(ProfileActivity.BUNDLE_USER, mStatusRes.getUser());
                    Router.build(Constants.Router.PROFILE)
                            .extras(userBundle)
                            .go(StatusDetailActivity.this);
                    break;
                case R.id.image_photo:
                    if (mStatusRes.getPhoto() != null) {
                        Bundle imageBundle = new Bundle();
                        imageBundle.putString(LargeImageActivity.BUNDLE_IMAGE_URL,
                                mStatusRes.getPhoto().getLargeurl());
                        Router.build(Constants.Router.LARGE_IMAGE)
                                .extras(imageBundle)
                                .go(StatusDetailActivity.this);
                    }
                    break;
                case R.id.view_comment:
                    Bundle commentBundle = new Bundle();
                    commentBundle.putString(WirteStatusActivity.BUNDLE_STATUS_TYPE,
                            WirteStatusActivity.BUNDLE_VALUE_STATUS_COMMENT);
                    commentBundle.putParcelable(WirteStatusActivity.BUNDLE_STATUS, statusRes);
                    Router.build(Constants.Router.WRITE_STATUS)
                            .extras(commentBundle)
                            .go(StatusDetailActivity.this);
                    break;
                case R.id.view_repeat:
                    Bundle repeatBundle = new Bundle();
                    repeatBundle.putString(WirteStatusActivity.BUNDLE_STATUS_TYPE,
                            WirteStatusActivity.BUNDLE_VALUE_STATUS_REPEAT);
                    repeatBundle.putParcelable(WirteStatusActivity.BUNDLE_STATUS, statusRes);
                    Router.build(Constants.Router.WRITE_STATUS)
                            .extras(repeatBundle)
                            .go(StatusDetailActivity.this);
                    break;
            }
        }
    }

    private void copyStatus(StatusRes statusRes) {
        ClipboardManager clipboardManager =
                (ClipboardManager) getSystemService(Context.CLIPBOARD_SERVICE);
        clipboardManager.setPrimaryClip(ClipData.newPlainText(null, statusRes.getText()));
        UIUtils.showToast(this, getString(R.string.text_copy_success));
    }

    private void showDeleteStatusDailog(final StatusRes statusRes) {
        new AlertDialog.Builder(this).setMessage(getString(R.string.text_dialog_delete_msg))
                .setPositiveButton(getString(R.string.text_dialog_positive),
                        new DialogInterface.OnClickListener() {
                            @Override
                            public void onClick(DialogInterface dialogInterface, int i) {
                                destoryStatuses(statusRes);
                            }
                        })
                .setNegativeButton(getString(R.string.text_dialog_negative),
                        new DialogInterface.OnClickListener() {
                            @Override
                            public void onClick(DialogInterface dialogInterface, int i) {

                            }
                        })
                .create()
                .show();
    }
} public class StatusAdapter extends RecyclerArrayAdapter<StatusRes> {
    private static final String TYPE_FAVORITE_STATUS = "favorite_status";
    private static final String TYPE_DELETE_STATUS = "delete_status";

    private Context mContext;

    public StatusAdapter(Context context) {
        super(context);
        mContext = context;
    }

    @Override
    public BaseViewHolder OnCreateViewHolder(ViewGroup parent, int viewType) {
        return new StatusViewHolder(parent);
    }

    public class StatusViewHolder extends BaseViewHolder<StatusRes> {
        @BindView(R.id.image_avatar) ImageView mImageAvatar;
        @BindView(R.id.text_name) TextView mTextName;
        @BindView(R.id.text_date) TextView mTextDate;
        @BindView(R.id.text_content) TextView mTextContent;
        @BindView(R.id.text_source) TextView mTextSource;
        @BindView(R.id.image_menu) ImageView mImageMenu;
        @BindView(R.id.image_photo) ImageView mImagePhoto;
        @BindView(R.id.button_favorite) Button mButtonFavorite;
        @BindView(R.id.view_favorite) View mViewFavorite;
        @BindView(R.id.view_repeat) View mViewRepeat;
        @BindView(R.id.view_comment) View mViewComment;

        public StatusViewHolder(ViewGroup parent) {
            super(parent, R.layout.item_status);
            ButterKnife.bind(this, itemView);
        }

        @Override
        public void setData(final StatusRes data) {
            final UserRes user = data.getUser();
            String imageUrl = user.getProfile_image_url_large();
            Glide.with(mContext).load(imageUrl).into(mImageAvatar);
            mTextName.setText(user.getName());
            mTextDate.setText(Utils.getIntervalTime(data.getCreated_at()));
            mTextContent.setText(
                    PatternUtils.formatWeiBoContent(mContext, data.getText(), mTextContent));
            mTextSource.setText(Html.fromHtml(data.getSource()).toString());

            if (data.getPhoto() != null) {
                Glide.with(mContext).load(data.getPhoto().getLargeurl()).into(mImagePhoto);
                mImagePhoto.setVisibility(View.VISIBLE);
            } else {
                mImagePhoto.setVisibility(View.GONE);
            }

            if (data.isFavorited()) {
                mButtonFavorite.setBackgroundResource(R.mipmap.ic_favorited);
                mButtonFavorite.setBackgroundTintList(ColorStateList.valueOf(
                        mContext.getResources().getColor(R.color.colorYellow)));
            } else {
                mButtonFavorite.setBackgroundResource(R.mipmap.ic_unfavorite);
                mButtonFavorite.setBackgroundTintList(ColorStateList.valueOf(
                        mContext.getResources().getColor(R.color.colorTextGray)));
            }

            OnClickLister onClickLister = new OnClickLister(data);

            mImageAvatar.setOnClickListener(onClickLister);
            mImageMenu.setOnClickListener(onClickLister);
            mImagePhoto.setOnClickListener(onClickLister);
            mViewFavorite.setOnClickListener(onClickLister);
            mViewRepeat.setOnClickListener(onClickLister);
            mViewComment.setOnClickListener(onClickLister);
        }
    }

    //删除消息
    private void destoryStatuses(final StatusRes statusRes) {
        SimpleRequestCallback requestCallback =
                new SimpleRequestCallback(statusRes, TYPE_DELETE_STATUS);
        StatusesRequest request = new StatusesRequest();
        request.setId(statusRes.getId());
        HttpRequestFactory.getInstance().destroyStatus(request, requestCallback);
    }

    //收藏或取消收藏消息
    private void createOrDestroyFavorite(final StatusRes statusRes) {
        SimpleRequestCallback requestCallback =
                new SimpleRequestCallback(statusRes, TYPE_FAVORITE_STATUS);

        if (statusRes.isFavorited()) {
            HttpRequestFactory.getInstance().destroyFavorite(statusRes.getId(), requestCallback);
        } else {
            HttpRequestFactory.getInstance().createFavorite(statusRes.getId(), requestCallback);
        }
    }

    private class SimpleRequestCallback extends SimpleHttpRequestCallback<StatusRes> {
        private StatusRes statusRes;
        private String type;

        public SimpleRequestCallback(StatusRes statusRes, String type) {
            this.statusRes = statusRes;
            this.type = type;
        }

        @Override
        public void onSuccess(StatusRes responseData) {
            if (TYPE_DELETE_STATUS.equals(type)) {
                remove(statusRes);
                UIUtils.showToast(mContext, mContext.getString(R.string.text_delete_success));
            }
        }

        @Override
        public void onFail(ApiException apiException) {
            if (TYPE_DELETE_STATUS.equals(type)) {
                UIUtils.showToast(mContext, mContext.getString(R.string.text_delete_fail));
            }
        }
    }

    private class OnClickLister implements View.OnClickListener {
        private StatusRes statusRes;

        public OnClickLister(StatusRes statusRes) {
            this.statusRes = statusRes;
        }

        @Override
        public void onClick(View view) {
            switch (view.getId()) {
                case R.id.image_menu:
                    showPopupMenu(view, statusRes);
                    break;
                case R.id.image_avatar:
                    Bundle userBundle = new Bundle();
                    userBundle.putParcelable(ProfileActivity.BUNDLE_USER, statusRes.getUser());
                    Router.build(Constants.Router.PROFILE).extras(userBundle).go(mContext);
                    break;
                case R.id.image_photo:
                    if (statusRes.getPhoto() != null) {
                        Bundle imageBundle = new Bundle();
                        imageBundle.putString(LargeImageActivity.BUNDLE_IMAGE_URL,
                                statusRes.getPhoto().getLargeurl());
                        Router.build(Constants.Router.LARGE_IMAGE).extras(imageBundle).go(mContext);
                    }
                    break;
                case R.id.view_favorite:
                    createOrDestroyFavorite(statusRes);
                    statusRes.setFavorited(!statusRes.isFavorited());
                    notifyDataSetChanged();
                    break;
                case R.id.view_comment:
                    Bundle commentBundle = new Bundle();
                    commentBundle.putString(WirteStatusActivity.BUNDLE_STATUS_TYPE,
                            WirteStatusActivity.BUNDLE_VALUE_STATUS_COMMENT);
                    commentBundle.putParcelable(WirteStatusActivity.BUNDLE_STATUS, statusRes);
                    Router.build(Constants.Router.WRITE_STATUS).extras(commentBundle).go(mContext);
                    break;
                case R.id.view_repeat:
                    Bundle repeatBundle = new Bundle();
                    repeatBundle.putString(WirteStatusActivity.BUNDLE_STATUS_TYPE,
                            WirteStatusActivity.BUNDLE_VALUE_STATUS_REPEAT);
                    repeatBundle.putParcelable(WirteStatusActivity.BUNDLE_STATUS, statusRes);
                    Router.build(Constants.Router.WRITE_STATUS).extras(repeatBundle).go(mContext);
                    break;
            }
        }
    }

    private void showPopupMenu(View view, final StatusRes statusRes) {
        PopupMenu popupMenu = new PopupMenu(mContext, view);
        if (statusRes.isIs_self()) {
            popupMenu.inflate(R.menu.menu_item_status_self);
        } else {
            popupMenu.inflate(R.menu.menu_item_status);
        }
        popupMenu.setOnMenuItemClickListener(new PopupMenu.OnMenuItemClickListener() {
            @Override
            public boolean onMenuItemClick(MenuItem menuItem) {
                switch (menuItem.getItemId()) {
                    case R.id.action_delete:
                        showDeleteStatusDailog(statusRes);
                        break;
                    case R.id.action_copy:
                        copyStatus(statusRes);
                        break;
                    case R.id.action_share:
                        break;
                }
                return false;
            }
        });
        popupMenu.show();
    }

    private void copyStatus(StatusRes statusRes) {
        ClipboardManager clipboardManager =
                (ClipboardManager) mContext.getSystemService(Context.CLIPBOARD_SERVICE);
        clipboardManager.setPrimaryClip(ClipData.newPlainText(null, statusRes.getText()));
        UIUtils.showToast(mContext, mContext.getString(R.string.text_copy_success));
    }

    private void showDeleteStatusDailog(final StatusRes statusRes) {
        new AlertDialog.Builder(mContext).setMessage(
                mContext.getString(R.string.text_dialog_delete_msg))
                .setPositiveButton(mContext.getString(R.string.text_dialog_positive),
                        new DialogInterface.OnClickListener() {
                            @Override
                            public void onClick(DialogInterface dialogInterface, int i) {
                                destoryStatuses(statusRes);
                            }
                        })
                .setNegativeButton(mContext.getString(R.string.text_dialog_negative),
                        new DialogInterface.OnClickListener() {
                            @Override
                            public void onClick(DialogInterface dialogInterface, int i) {

                            }
                        })
                .create()
                .show();
    }
} public class Constants {
    public static class FanFou {
        //Consumer key
        public static final String CONSUMER_KEY = "f44caedd9890e6c2dff609314544245a";
        //Consumer secret
        public static final String CONSUMER_SECRET = "376efb84d711a7e59a9792c1ab8ba1ef";
        //fanfou URL
        public static final String FANFOU_URL = "http://fanfou.com";
        //fanfou api URL
        public static final String FANFOU_API_URL = "http://api.fanfou.com";
        //Request token URL
        public static final String REQUEST_TOKEN_URL = "/oauth/request_token";
        //Access token URL
        public static final String ACCESS_TOKEN_URL = FANFOU_URL + "/oauth/access_token";
        //Authorize URL
        public static final String AUTHORIZE_URL = "/oauth/authorize";

        //******statuses******
        public static final String HOME_TIMELINE_URL = "/statuses/home_timeline.json";
        public static final String PUBLIC_TIMELIN_URL = "/statuses/public_timeline.json";
        public static final String DESTROY_STATUSES_URL = "/statuses/destroy.json";
        public static final String UPDATE_STATUSES_URL = "/statuses/update.json";
        public static final String MENTIONS_MSG_URL = "/statuses/mentions.json";
        public static final String USER_TIMELINE_URL = "/statuses/user_timeline.json";

        //******direct_messages******
        public static final String CONVERSATION_LIST_URL =
                "/direct_messages/conversation_list.json";
        public static final String CONVERSATION_URL = "/direct_messages/conversation.json";
        public static final String SEND_DIRECT_MESSAGE_URL = "/direct_messages/new.json";

        //******favorites******
        public static final String CREATE_FAVORITES_URL = "/favorites/create/{id}.json";
        public static final String DESTROY_FAVORITES_URL = "/favorites/destroy/{id}.json";
        public static final String FAVORITES_URL = "/favorites.json";

        //******users******
        public static final String USER_FRIENDS_URL = "/users/friends.json";
        public static final String USER_SHOW_URL = "/users/show.json";
        public static final String USER_FOLLOWERS_URL = "/users/followers.json";

        //******photo******
        public static final String PHOTOS_UPLOAD_URL = "/photos/upload.json";
        public static final String USER_PHOTOS_URL = "/photos/user_timeline.json";

        //******trends******
        public static final String TRENDS_LIST_URL = "/trends/list.json";

        //******search******
        public static final String SEARCH_PUBLIC_TIMELINE = "/search/public_timeline.json";
        public static final String SEARCH_USER = "/search/users.json";
        public static final String SEARCH_USER_TIMELINE = "/search/user_timeline.json";

        //******friendships******
        public static final String CREATE_FRIENDSHIP_URL = "/friendships/create.json";
        public static final String DESTROY_FRIENDSHIP_URL = "/friendships/destroy.json";
        public static final String IS_EXIST_FRIENDSHIP_URL = "/friendships/exists.json";

        //******account******
        public static final String ACCOUNT_NOTIFICATION = "/account/notification.json";

        public static final String OAUTH_VERSION_VALUE = "1.0";
        public static final String OAUTH_SIGNATURE_METHOD_VALUE = "HMAC-SHA1";
        public static final String X_AUTH_MODE_VALUE = "client_auth";

        public static String OAUTH_TOKEN;
        public static String OAUTH_TOKENSECRET;
        public static String USERNAME;
        public static String PASSWORD;
    }

    public static class HeaderName {
        public static final String AUTHORIZATION = "Authorization";
    }

    public static class HttpBody {
        public static final String MULTIPART_FORM_DATA = "multipart/form-data";
    }

    public static class XAuth {
        public static final String X_AUTH_USERNAME = "x_auth_username";
        public static final String X_AUTH_PASSWORD = "x_auth_password";
        public static final String X_AUTH_MODE = "x_auth_mode";
        public static final String OAUTH_CONSUMER_KEY = "oauth_consumer_key";
        public static final String OAUTH_SIGNATURE_METHOD = "oauth_signature_method";
        public static final String OAUTH_TIMESTAMP = "oauth_timestamp";
        public static final String OAUTH_NONCE = "oauth_nonce";
        public static final String OAUTH_VERSION = "oauth_version";
        public static final String OAUTH_TOKEN = "oauth_token";
        public static final String OAUTH_SIGNATURE = "oauth_signature";
    }

    public static class HttpMethod {
        public static final String GET = "GET";
        public static final String POST = "POST";
    }

    public static class Router {
        public static final String SCHEME = "xifan://";

        public static final String LOGIN = "login";
        public static final String MAIN = "main";
        public static final String WRITE_STATUS = "write_status";
        public static final String STATUS_DETAIL = "status_detail";
        public static final String LARGE_IMAGE = "large_image";
        public static final String USER_LIST = "user_list";
        public static final String SEARCH = "search";
        public static final String TREND_STATUSES = "trend_statuses";
        public static final String CONVERSATION = "conversation";
        public static final String SETTINGS = "settings";
        public static final String PROFILE = "profile";
        public static final String BROWSER = "browser";
    }

    public static class RequestParams {
        public static final String FORMAT_HTML = "html";
        public static final String MODE_LITE = "lite";
    }

    public static class SharedPreferences {
        public static final String NAME = "xifan";
        public static final String KEY_USER_ID = "user_id";
    }

    public static class AVOSCloud {
        public static final String APP_ID = "hNoFuqFvKx5crJBz6mMAFwPL-gzGzoHsz";
        public static final String APP_KEY = "jfEvEXMydhcRkgzL4hWWj72L";
    }

    public static class Fir {
        public static final String FIR_TOKEN = "2def92fc28bb812a895538fa54ed38d3";
    }
} public class SendStatusEvent {
    public final static String TYPE_SUCCESS = "success";
    public final static String TYPE_FAIL = "fail";

    private String type;

    public SendStatusEvent(String type) {
        this.type = type;
    }

    public String getType() {
        return type;
    }

    public void setType(String type) {
        this.type = type;
    }
} public class StatusRefreshEvent {
    public static final String TYPE_FAVORITE_STATUS = "favorite_status";
    public static final String TYPE_DELETE_STATUS = "delete_status";
    public static final String TYPE_REFRESH_STATUS = "refresh_status";

    private StatusRes statusRes;
    private String type;

    public StatusRefreshEvent(StatusRes statusRes, String type) {
        this.statusRes = statusRes;
        this.type = type;
    }

    public StatusRes getStatusRes() {
        return statusRes;
    }

    public void setStatusRes(StatusRes statusRes) {
        this.statusRes = statusRes;
    }

    public String getType() {
        return type;
    }

    public void setType(String type) {
        this.type = type;
    }
} public class HttpRequestFactory {
    //超时60s
    private static final long TIMEOUT = 60;
    private static final int CACHE_SIZE = 10 * 1024 * 1024;
    private static HttpRequestFactory mInstance;
    private ApiFactory mServiceFactory;

    public HttpRequestFactory() {
        HttpLoggingInterceptor logging = new HttpLoggingInterceptor();
        logging.setLevel(HttpLoggingInterceptor.Level.HEADERS);

        OkHttpClient okHttpClient =
                new OkHttpClient.Builder().connectTimeout(TIMEOUT, TimeUnit.SECONDS)
                        .readTimeout(TIMEOUT, TimeUnit.SECONDS)
                        .writeTimeout(TIMEOUT, TimeUnit.SECONDS)
                        .cache(getCache())
                        .addInterceptor(logging)
                        .addNetworkInterceptor(mTokenInterceptor)
                        //应用拦截器，用于离线缓存
                        .addInterceptor(mCacheInterceptor)
                        //网络拦截器，用于在线缓存
                        .addNetworkInterceptor(mCacheInterceptor)
                        .addNetworkInterceptor(new StethoInterceptor())
                        .build();

        Retrofit retrofit = new Retrofit.Builder().baseUrl(Constants.FanFou.FANFOU_API_URL)
                .addConverterFactory(ResponseConverterFactory.create())
                .addCallAdapterFactory(RxJavaCallAdapterFactory.create())
                .client(okHttpClient)
                .build();

        mServiceFactory = retrofit.create(ApiFactory.class);
    }

    public static HttpRequestFactory getInstance() {
        if (mInstance == null) {
            synchronized (HttpRequestFactory.class) {
                if (mInstance == null) {
                    mInstance = new HttpRequestFactory();
                }
            }
        }
        return mInstance;
    }

    private Cache getCache() {
        File file = new File(App.getInstance().getCacheDir(), "response");
        return new Cache(file, CACHE_SIZE);
    }

    public void getAccessToken(String username, String password, HttpRequestCallback callback) {
        subscribe(mServiceFactory.getAccessToken(Constants.FanFou.ACCESS_TOKEN_URL), callback);
    }

    public void getHomeTimeline(BaseRequestParams requestParams, HttpRequestCallback callback) {
        subscribe(mServiceFactory.getHomeTimeline(requestParams.convertToQueryMap()), callback);
    }

    public void getUserHomeTimeline(BaseRequestParams requestParams, HttpRequestCallback callback) {
        subscribe(mServiceFactory.getUserTimeline(requestParams.convertToQueryMap()), callback);
    }

    public void getPublicTimeline(BaseRequestParams requestParams, HttpRequestCallback callback) {
        subscribe(mServiceFactory.getPublicTimeline(requestParams.convertToQueryMap()), callback);
    }

    public void destroyStatus(BaseRequestParams requestParams, HttpRequestCallback callback) {
        subscribe(mServiceFactory.destroyStatus(requestParams.convertToBodyMap()), callback);
    }

    public void updateStatus(BaseRequestParams requestParams, HttpRequestCallback callback) {
        subscribe(mServiceFactory.updateStatus(requestParams.convertToBodyMap()), callback);
    }

    public void uploadPhoto(BaseRequestParams requestParams, HttpRequestCallback callback) {
        subscribe(mServiceFactory.uploadPhoto(requestParams.convertToBodyMap()), callback);
    }

    public void getUserPhotos(BaseRequestParams requestParams, HttpRequestCallback callback) {
        subscribe(mServiceFactory.getUserPhotos(requestParams.convertToQueryMap()), callback);
    }

    public void getMentions(BaseRequestParams requestParams, HttpRequestCallback callback) {
        subscribe(mServiceFactory.getMentions(requestParams.convertToQueryMap()), callback);
    }

    public void getConversationList(BaseRequestParams requestParams, HttpRequestCallback callback) {
        subscribe(mServiceFactory.getConversationList(requestParams.convertToQueryMap()), callback);
    }

    public void getConversation(BaseRequestParams requestParams, HttpRequestCallback callback) {
        subscribe(mServiceFactory.getConversation(requestParams.convertToQueryMap()), callback);
    }

    public void sendDirectMessage(BaseRequestParams requestParams, HttpRequestCallback callback) {
        subscribe(mServiceFactory.sendDirectMessage(requestParams.convertToBodyMap()), callback);
    }

    public void createFavorite(String id, HttpRequestCallback callback) {
        subscribe(mServiceFactory.createFavorite(id), callback);
    }

    public void destroyFavorite(String id, HttpRequestCallback callback) {
        subscribe(mServiceFactory.destroyFavorite(id), callback);
    }

    public void getUserFavorites(BaseRequestParams requestParams, HttpRequestCallback callback) {
        subscribe(mServiceFactory.getUserFavorites(requestParams.convertToQueryMap()), callback);
    }

    public void getFriends(BaseRequestParams requestParams, HttpRequestCallback callback) {
        subscribe(mServiceFactory.getFriends(requestParams.convertToQueryMap()), callback);
    }

    public void getFollowers(BaseRequestParams requestParams, HttpRequestCallback callback) {
        subscribe(mServiceFactory.getFollowers(requestParams.convertToQueryMap()), callback);
    }

    public void getUserInfo(BaseRequestParams requestParams, HttpRequestCallback callback) {
        subscribe(mServiceFactory.getUserInfo(requestParams.convertToQueryMap()), callback);
    }

    public void getTrends(HttpRequestCallback callback) {
        subscribe(mServiceFactory.getTrends(), callback);
    }

    public void searchPublicTimeline(BaseRequestParams requestParams,
            HttpRequestCallback callback) {
        subscribe(mServiceFactory.searchPublicTimeline(requestParams.convertToQueryMap()),
                callback);
    }

    public void searchUser(BaseRequestParams requestParams, HttpRequestCallback callback) {
        subscribe(mServiceFactory.searchUser(requestParams.convertToQueryMap()), callback);
    }

    public void searchUserTimeline(BaseRequestParams requestParams, HttpRequestCallback callback) {
        subscribe(mServiceFactory.searchUserTimeline(requestParams.convertToQueryMap()), callback);
    }

    public void createFriendship(BaseRequestParams requestParams, HttpRequestCallback callback) {
        subscribe(mServiceFactory.createFriendship(requestParams.convertToBodyMap()), callback);
    }

    public void destroyFriendship(BaseRequestParams requestParams, HttpRequestCallback callback) {
        subscribe(mServiceFactory.destoryFriendship(requestParams.convertToBodyMap()), callback);
    }

    public void isExistFriendship(BaseRequestParams requestParams, HttpRequestCallback callback) {
        subscribe(mServiceFactory.isExistFriendship(requestParams.convertToQueryMap()), callback);
    }

    public void getNotification(HttpRequestCallback callback) {
        subscribe(mServiceFactory.getNotification(), callback);
    }

    private <T> void subscribe(Observable<HttpResponseData<T>> observable,
            HttpRequestCallback callback) {
        observable.map(new HttpResponseFunc<T>())
                .subscribeOn(Schedulers.io())
                .observeOn(AndroidSchedulers.mainThread())
                .doOnSubscribe(new DoOnSubscribe(callback))
                .subscribeOn(AndroidSchedulers.mainThread())
                .onErrorResumeNext(new HttpErrorResult<T>())
                .retryWhen(new RetryWithError())
                .subscribe(new HttpSubscriber<T>(callback));
    }

    //map变换
    private class HttpResponseFunc<T> implements Func1<HttpResponseData<T>, T> {

        @Override
        public T call(HttpResponseData<T> httpResponseData) {
            return httpResponseData.getData();
        }
    }

    //在事件发送前执行，用来在界面上显示loading
    private class DoOnSubscribe implements Action0 {
        private HttpRequestCallback mCallback;

        public DoOnSubscribe(HttpRequestCallback callback) {
            mCallback = callback;
        }

        @Override
        public void call() {
            mCallback.onStart();
        }
    }

    private class HttpSubscriber<T> extends Subscriber<T> {
        private HttpRequestCallback mCallback;

        public HttpSubscriber(HttpRequestCallback callback) {
            mCallback = callback;
        }

        @Override
        public void onStart() {
        }

        @Override
        public void onCompleted() {
        }

        @Override
        public void onError(Throwable e) {
            if (e instanceof ApiException) {
                mCallback.onFail((ApiException) e);
            }
        }

        @Override
        public void onNext(T t) {
            mCallback.onSuccess(t);
        }
    }

    //异常预处理
    private class HttpErrorResult<T> implements Func1<Throwable, Observable<T>> {
        @Override
        public Observable<T> call(Throwable throwable) {
            return Observable.error(ExceptionHandle.handleException(throwable));
        }
    }

    //重试
    private class RetryWithError implements Func1<Observable<? extends Throwable>, Observable<?>> {
        //最大重试次数
        private int maxRetry = 3;
        //间隔时间ms
        private static final int INTERVAL = 1000;

        @Override
        public Observable<?> call(Observable<? extends Throwable> observable) {
            return observable.flatMap(new Func1<Throwable, Observable<?>>() {
                @Override
                public Observable<?> call(Throwable throwable) {
                    //网络超时重试
                    if (throwable instanceof ApiException) {
                        ApiException apiException = (ApiException) throwable;
                        if (apiException.getErrorCode().equals(ErrorCode.ERROR_NET_TIMEOUT)
                                && maxRetry-- > 0) {
                            return Observable.timer(INTERVAL, TimeUnit.MILLISECONDS);
                        }
                    }
                    return Observable.error(throwable);
                }
            });
        }
    }

    //TokenInterceptor add authorization
    private Interceptor mTokenInterceptor = new Interceptor() {
        @Override
        public Response intercept(Chain chain) throws IOException {
            Request originalRequest = chain.request();
            Request.Builder builder = originalRequest.newBuilder();
            Request tokenRequest = builder.header(Constants.HeaderName.AUTHORIZATION,
                    XAuthUtils.getAuthorization(originalRequest)).build();
            return chain.proceed(tokenRequest);
        }
    };

    //http 数据缓存
    private Interceptor mCacheInterceptor = new Interceptor() {
        @Override
        public Response intercept(Chain chain) throws IOException {
            Request request = chain.request();
            //无网络时走okhttp 内部缓存机制
            if (!NetUtils.isNetworkConnected(App.getInstance())) {
                //在请求首部中声明读取缓存内容
                request = request.newBuilder().cacheControl(CacheControl.FORCE_CACHE).build();
            }

            Response originalResponse = chain.proceed(request);
            Logger.d("success:" + originalResponse.isSuccessful());

            //有网络时不读缓存
            if (NetUtils.isNetworkConnected(App.getInstance())) {
                return originalResponse.newBuilder()
                        .header("Cache-Control", request.cacheControl().toString())
                        .removeHeader("Pragma")
                        .build();
            } else {
                int maxAge = 60 * 60 * 24;
                return originalResponse.newBuilder()
                        .header("Cache-Control", "public, only-if-cached, max-age=" + maxAge)
                        .removeHeader("Pragma")
                        .build();
            }
        }
    };
} public class SimpleHttpRequestCallback<T> implements HttpRequestCallback<T> {
    @Override
    public void onStart() {

    }

    @Override
    public void onSuccess(T responseData) {

    }

    @Override
    public void onFail(ApiException apiException) {

    }
} public class ApiException extends Exception {
    private String errorCode;
    private String errorMessage;

    public ApiException(String errorCode, String errorMessage) {
        this.errorCode = errorCode;
        this.errorMessage = errorMessage;
    }

    public String getErrorCode() {
        return errorCode;
    }

    public void setErrorCode(String errorCode) {
        this.errorCode = errorCode;
    }

    public String getErrorMessage() {
        return errorMessage;
    }

    public void setErrorMessage(String errorMessage) {
        this.errorMessage = errorMessage;
    }
} public class StatusesRequest extends BaseRequestParams {
    private String since_id;
    private String max_id;
    private String photo;
    private String status;
    private String in_reply_to_status_id;
    private String in_reply_to_user_id;
    private String repost_status_id;
    private String source;
    private String location;

    public String getSince_id() {
        return since_id;
    }

    public void setSince_id(String since_id) {
        this.since_id = since_id;
    }

    public String getMax_id() {
        return max_id;
    }

    public void setMax_id(String max_id) {
        this.max_id = max_id;
    }

    public String getPhoto() {
        return photo;
    }

    public void setPhoto(String photo) {
        this.photo = photo;
    }

    public String getStatus() {
        return status;
    }

    public void setStatus(String status) {
        this.status = status;
    }

    public String getIn_reply_to_status_id() {
        return in_reply_to_status_id;
    }

    public void setIn_reply_to_status_id(String in_reply_to_status_id) {
        this.in_reply_to_status_id = in_reply_to_status_id;
    }

    public String getIn_reply_to_user_id() {
        return in_reply_to_user_id;
    }

    public void setIn_reply_to_user_id(String in_reply_to_user_id) {
        this.in_reply_to_user_id = in_reply_to_user_id;
    }

    public String getRepost_status_id() {
        return repost_status_id;
    }

    public void setRepost_status_id(String repost_status_id) {
        this.repost_status_id = repost_status_id;
    }

    public String getSource() {
        return source;
    }

    public void setSource(String source) {
        this.source = source;
    }

    public String getLocation() {
        return location;
    }

    public void setLocation(String location) {
        this.location = location;
    }
} public class StatusRes implements Parcelable {

    /**
     * created_at : Wed Dec 07 05:10:05 +0000 2016
     * id : rlDs4QRRpNg
     * rawid : 204208572
     * text : 转@番茄囝 那是ps的，这才是真的「@飯否小字报 转@王兴 男人的相貌风格差别真大。左边的海明威比右边的菲茨杰拉德还小三岁呢。」
     * source : 手机上网
     * truncated : false
     * in_reply_to_status_id :
     * in_reply_to_user_id :
     * favorited : false
     * in_reply_to_screen_name :
     * is_self : false
     * repost_status_id : hwYSUzDDT3s
     * repost_user_id : frankielove
     * repost_screen_name : 番茄囝
     * repost_status : {"created_at":"Wed Dec 07 02:46:55 +0000 2016","id":"hwYSUzDDT3s","rawid":204203870,"text":"那是ps的，这才是真的「@飯否小字报
     * 转@王兴 男人的相貌风格差别真大。左边的海明威比右边的菲茨杰拉德还小三岁呢。」","source":"","truncated":false,"in_reply_to_status_id":"","in_reply_to_user_id":"","favorited":false,"in_reply_to_screen_name":"","is_self":false,"location":"广东
     * 广州","user":{"id":"frankielove","name":"番茄囝","screen_name":"番茄囝","unique_id":"~05RpvQvujBo","location":"广东
     * 广州","gender":"男","birthday":"1991-02-16","description":"傻屌","profile_image_url":"http://s3.meituan.net/v1/mss_3d027b52ec5a4d589e68050845611e68/avatar/s0/00/82/15.jpg?1228661080","profile_image_url_large":"http://s3.meituan.net/v1/mss_3d027b52ec5a4d589e68050845611e68/avatar/l0/00/82/15.jpg?1228661080","url":"http://frankie-love.blog.163.com/","protected":false,"followers_count":108,"friends_count":60,"favourites_count":79,"statuses_count":4184,"photo_count":386,"following":false,"notifications":false,"created_at":"Wed
     * Jan 30 06:32:11 +0000 2008","utc_offset":28800,"profile_background_color":"#acdae5","profile_text_color":"#222222","profile_link_color":"#0066cc","profile_sidebar_fill_color":"#e2f2da","profile_sidebar_border_color":"#b2d1a3","profile_background_image_url":"http://static.fanfou.com/img/bg/0.png","profile_background_tile":false},"photo":{"url":"http://fanfou.com/photo/3A9ElDy7VEk","imageurl":"http://photo.fanfou.com/v1/mss_3d027b52ec5a4d589e68050845611e68/ff/n0/0d/c0/zg_483018.jpg@200w_200h_1l.jpg","thumburl":"http://photo.fanfou.com/v1/mss_3d027b52ec5a4d589e68050845611e68/ff/n0/0d/c0/zg_483018.jpg@120w_120h_1l.jpg","largeurl":"http://photo.fanfou.com/v1/mss_3d027b52ec5a4d589e68050845611e68/ff/n0/0d/c0/zg_483018.jpg@596w_1l.jpg"}}
     * location : 北京 海淀区
     * user : {"id":"wangxing","name":"王兴","screen_name":"王兴","unique_id":"~vlY6PYjjoLY","location":"北京
     * 海淀区","gender":"男","birthday":"0000-02-18","description":"如果我一整天都没看到、想到、或做过什么值得在饭否上说的事，那这一天就太浑浑噩噩了。
     * 美团创始人， 饭否创始人， 校内网创始人， 非典型清华工科男。 Create like a god. Command like a king. Work like a
     * slave.","profile_image_url":"http://s3.meituan.net/v1/mss_3d027b52ec5a4d589e68050845611e68/avatar/s0/00/31/n3.jpg?1179311049","profile_image_url_large":"http://s3.meituan.net/v1/mss_3d027b52ec5a4d589e68050845611e68/avatar/l0/00/31/n3.jpg?1179311049","url":"","protected":false,"followers_count":177555,"friends_count":741,"favourites_count":117,"statuses_count":9597,"photo_count":436,"following":true,"notifications":true,"created_at":"Sat
     * May 12 14:24:26 +0000 2007","utc_offset":28800,"profile_background_color":"#dadada","profile_text_color":"#403333","profile_link_color":"#990000","profile_sidebar_fill_color":"#cccaca","profile_sidebar_border_color":"#999191","profile_background_image_url":"http://static.fanfou.com/img/bg/3.jpg","profile_background_tile":true}
     * photo : {"url":"http://fanfou.com/photo/3A9ElDy7VEk","imageurl":"http://photo.fanfou.com/v1/mss_3d027b52ec5a4d589e68050845611e68/ff/n0/0d/c0/zg_483018.jpg@200w_200h_1l.jpg","thumburl":"http://photo.fanfou.com/v1/mss_3d027b52ec5a4d589e68050845611e68/ff/n0/0d/c0/zg_483018.jpg@120w_120h_1l.jpg","largeurl":"http://photo.fanfou.com/v1/mss_3d027b52ec5a4d589e68050845611e68/ff/n0/0d/c0/zg_483018.jpg@596w_1l.jpg"}
     */

    private String created_at;
    private String id;
    private int rawid;
    private String text;
    private String source;
    private boolean truncated;
    private String in_reply_to_status_id;
    private String in_reply_to_user_id;
    private boolean favorited;
    private String in_reply_to_screen_name;
    private boolean is_self;
    private String repost_status_id;
    private String repost_user_id;
    private String repost_screen_name;
    private StatusRes repost_status;
    private String location;
    private UserRes user;
    private PhotoRes photo;

    public String getCreated_at() {
        return created_at;
    }

    public void setCreated_at(String created_at) {
        this.created_at = created_at;
    }

    public String getId() {
        return id;
    }

    public void setId(String id) {
        this.id = id;
    }

    public int getRawid() {
        return rawid;
    }

    public void setRawid(int rawid) {
        this.rawid = rawid;
    }

    public String getText() {
        return text;
    }

    public void setText(String text) {
        this.text = text;
    }

    public String getSource() {
        return source;
    }

    public void setSource(String source) {
        this.source = source;
    }

    public boolean isTruncated() {
        return truncated;
    }

    public void setTruncated(boolean truncated) {
        this.truncated = truncated;
    }

    public String getIn_reply_to_status_id() {
        return in_reply_to_status_id;
    }

    public void setIn_reply_to_status_id(String in_reply_to_status_id) {
        this.in_reply_to_status_id = in_reply_to_status_id;
    }

    public String getIn_reply_to_user_id() {
        return in_reply_to_user_id;
    }

    public void setIn_reply_to_user_id(String in_reply_to_user_id) {
        this.in_reply_to_user_id = in_reply_to_user_id;
    }

    public boolean isFavorited() {
        return favorited;
    }

    public void setFavorited(boolean favorited) {
        this.favorited = favorited;
    }

    public String getIn_reply_to_screen_name() {
        return in_reply_to_screen_name;
    }

    public void setIn_reply_to_screen_name(String in_reply_to_screen_name) {
        this.in_reply_to_screen_name = in_reply_to_screen_name;
    }

    public boolean isIs_self() {
        return is_self;
    }

    public void setIs_self(boolean is_self) {
        this.is_self = is_self;
    }

    public String getRepost_status_id() {
        return repost_status_id;
    }

    public void setRepost_status_id(String repost_status_id) {
        this.repost_status_id = repost_status_id;
    }

    public String getRepost_user_id() {
        return repost_user_id;
    }

    public void setRepost_user_id(String repost_user_id) {
        this.repost_user_id = repost_user_id;
    }

    public String getRepost_screen_name() {
        return repost_screen_name;
    }

    public void setRepost_screen_name(String repost_screen_name) {
        this.repost_screen_name = repost_screen_name;
    }

    public StatusRes getRepost_status() {
        return repost_status;
    }

    public void setRepost_status(StatusRes repost_status) {
        this.repost_status = repost_status;
    }

    public String getLocation() {
        return location;
    }

    public void setLocation(String location) {
        this.location = location;
    }

    public UserRes getUser() {
        return user;
    }

    public void setUser(UserRes user) {
        this.user = user;
    }

    public PhotoRes getPhoto() {
        return photo;
    }

    public void setPhoto(PhotoRes photo) {
        this.photo = photo;
    }

    @Override
    public int describeContents() {
        return 0;
    }

    @Override
    public void writeToParcel(Parcel dest, int flags) {
        dest.writeString(this.created_at);
        dest.writeString(this.id);
        dest.writeInt(this.rawid);
        dest.writeString(this.text);
        dest.writeString(this.source);
        dest.writeByte(this.truncated ? (byte) 1 : (byte) 0);
        dest.writeString(this.in_reply_to_status_id);
        dest.writeString(this.in_reply_to_user_id);
        dest.writeByte(this.favorited ? (byte) 1 : (byte) 0);
        dest.writeString(this.in_reply_to_screen_name);
        dest.writeByte(this.is_self ? (byte) 1 : (byte) 0);
        dest.writeString(this.repost_status_id);
        dest.writeString(this.repost_user_id);
        dest.writeString(this.repost_screen_name);
        dest.writeParcelable(this.repost_status, flags);
        dest.writeString(this.location);
        dest.writeParcelable(this.user, flags);
        dest.writeParcelable(this.photo, flags);
    }

    public StatusRes() {
    }

    protected StatusRes(Parcel in) {
        this.created_at = in.readString();
        this.id = in.readString();
        this.rawid = in.readInt();
        this.text = in.readString();
        this.source = in.readString();
        this.truncated = in.readByte() != 0;
        this.in_reply_to_status_id = in.readString();
        this.in_reply_to_user_id = in.readString();
        this.favorited = in.readByte() != 0;
        this.in_reply_to_screen_name = in.readString();
        this.is_self = in.readByte() != 0;
        this.repost_status_id = in.readString();
        this.repost_user_id = in.readString();
        this.repost_screen_name = in.readString();
        this.repost_status = in.readParcelable(StatusRes.class.getClassLoader());
        this.location = in.readString();
        this.user = in.readParcelable(UserRes.class.getClassLoader());
        this.photo = in.readParcelable(PhotoRes.class.getClassLoader());
    }

    public static final Parcelable.Creator<StatusRes> CREATOR =
            new Parcelable.Creator<StatusRes>() {
                @Override
                public StatusRes createFromParcel(Parcel source) {
                    return new StatusRes(source);
                }

                @Override
                public StatusRes[] newArray(int size) {
                    return new StatusRes[size];
                }
            };
} public final class UIUtils {
    public static void showToast(Context context, String msg) {
        Toast.makeText(context, msg, Toast.LENGTH_SHORT).show();
    }

    public static void showSnackbar(View view, String msg) {
        Snackbar.make(view, "snackbar", Snackbar.LENGTH_LONG).show();
    }

    public static void showDialog(Context context, String title,String msg, final OnDialogListener callback) {
        AlertDialog.Builder builder = new AlertDialog.Builder(context);
        if(!TextUtils.isEmpty(title)){
            builder.setTitle(title);
        }
        if(!TextUtils.isEmpty(msg)){
            builder.setMessage(msg);
        }
        builder.setNegativeButton(context.getString(R.string.text_dialog_negative),
                new DialogInterface.OnClickListener() {
                    @Override
                    public void onClick(DialogInterface dialogInterface, int i) {
                        callback.onCancel();
                    }
                });
        builder.setPositiveButton(context.getString(R.string.text_dialog_positive),
                new DialogInterface.OnClickListener() {
                    @Override
                    public void onClick(DialogInterface dialogInterface, int i) {

                        callback.onConfirm();
                    }
                });
        builder.create().show();
    }

    public static void showOkDialog(Context context, String title, String msg) {
        AlertDialog.Builder builder = new AlertDialog.Builder(context);
        if (!TextUtils.isEmpty(title)) {
            builder.setTitle(title);
        }
        if(!TextUtils.isEmpty(msg)){
            builder.setMessage(msg);
        }
        builder.setPositiveButton(context.getString(R.string.text_dialog_positive),
                new DialogInterface.OnClickListener() {
                    @Override
                    public void onClick(DialogInterface dialogInterface, int i) {
                        dialogInterface.dismiss();
                    }
                });
        builder.create().show();
    }

    public static float dip2px(Context context, float value) {
        return TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, value,
                context.getResources().getDisplayMetrics());
    }

    public static float px2dip(Context context, float value) {
        return TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_PX, value,
                context.getResources().getDisplayMetrics());
    }

    public static float getDisplayWidth(Context context) {
        return context.getResources().getDisplayMetrics().widthPixels;
    }

    public static float getDisplayHeight(Context context) {
        return context.getResources().getDisplayMetrics().heightPixels;
    }

    public interface OnDialogListener {
        void onConfirm();

        void onCancel();
    }
} public final class Utils {
    private static String FANFOU_DATE_FORMAT_STRING = "EEE MMM dd HH:mm:ss Z yyyy";
    private static SimpleDateFormat sFanFouDateFormat =
            new SimpleDateFormat(FANFOU_DATE_FORMAT_STRING, Locale.US);
    private static String SIMPLE_DATE_FORMAT_STRING = "yyyy-MM-dd HH:mm:ss";
    private static SimpleDateFormat sSimpleDateFormat =
            new SimpleDateFormat(SIMPLE_DATE_FORMAT_STRING, Locale.US);
    private static String DM_DATE_FORMAT_STRING = "yyyy年MM月dd日";
    private static SimpleDateFormat sDMDateFormat =
            new SimpleDateFormat(DM_DATE_FORMAT_STRING, Locale.US);
    private static final ParsePosition sPosition = new ParsePosition(0);

    public static final long MINUTE = 60;
    public static final long HOUR = MINUTE * 60;
    public static final long DAY = HOUR * 24;

    //格式化时间
    public static Date stringToDate(String strDate) {
        sPosition.setIndex(0);
        return sFanFouDateFormat.parse(strDate, sPosition);
    }

    public static String getDMDateFormatString(String strDate) {
        return sDMDateFormat.format(stringToDate(strDate));
    }

    public static String formatFanFouDate(Date date) {
        return sFanFouDateFormat.format(date);
    }

    //时间间隔
    public static String getIntervalTime(String strDate) {
        Date date = stringToDate(strDate);
        long lastTime = date.getTime();
        long currentTime = System.currentTimeMillis();
        long intervalSeconds = (currentTime - lastTime) / 1000;
        if (intervalSeconds < MINUTE) {
            return "刚刚";
        } else if (intervalSeconds < HOUR) {
            return intervalSeconds / MINUTE + "分钟前";
        } else if (intervalSeconds < DAY) {
            return intervalSeconds / HOUR + "小时前";
        } else {
            return intervalSeconds / DAY + "天前";
        }
    }

    //获取最后一条消息的ID
    public static String getMaxId(List<StatusRes> responseData) {
        String id = "";
        if (responseData.size() > 0) {
            id = responseData.get(responseData.size() - 1).getId();
        }
        return id;
    }

    //获取最新一条消息的ID
    public static String getSinceId(List<StatusRes> responseData) {
        String id = null;
        if (responseData.size() > 0) {
            id = responseData.get(0).getId();
        }
        return id;
    }

    //获取版本号
    public static String getVersionName() {
        return "v" + BuildConfig.VERSION_NAME;
    }
}
import android.os.Bundle;
import android.support.annotation.Nullable;
import android.support.v4.app.Fragment;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.Toolbar;
import android.view.MenuItem;
import butterknife.BindView;
import com.chenenyu.router.Router;
import com.jude.easyrecyclerview.EasyRecyclerView;
import com.jude.easyrecyclerview.adapter.RecyclerArrayAdapter;
import com.troy.xifan.R;
import com.troy.xifan.activity.StatusDetailActivity;
import com.troy.xifan.adapter.StatusAdapter;
import com.troy.xifan.config.Constants;
import com.troy.xifan.eventbus.SendStatusEvent;
import com.troy.xifan.eventbus.StatusRefreshEvent;
import com.troy.xifan.http.HttpRequestFactory;
import com.troy.xifan.http.callback.SimpleHttpRequestCallback;
import com.troy.xifan.http.exception.ApiException;
import com.troy.xifan.http.request.StatusesRequest;
import com.troy.xifan.model.response.StatusRes;
import com.troy.xifan.util.UIUtils;
import com.troy.xifan.util.Utils;
import java.util.List;
import org.greenrobot.eventbus.EventBus;
import org.greenrobot.eventbus.Subscribe;
package com.troy.xifan.fragment;


/**
 * Created by chenlongfei on 2016/12/1.
 */

public class HomeFragment extends BaseFragment {
    @BindView(R.id.toolbar) Toolbar mToolbar;
    @BindView(R.id.recycler_view) EasyRecyclerView mRecyclerView;

    private String mMaxId;
    private StatusAdapter mStatusAdapter;

    public static Fragment newInstance() {
        return new HomeFragment();
    }

    @Override
    public void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        EventBus.getDefault().register(this);
    }

    @Override
    public void onActivityCreated(Bundle savedInstanceState) {
        super.onActivityCreated(savedInstanceState);
        getHomeTimeline(false);
    }

    private void getHomeTimeline(final boolean loadMore) {
        StatusesRequest request = new StatusesRequest();
        request.setMax_id(loadMore ? mMaxId : null);

        HttpRequestFactory.getInstance()
                .getHomeTimeline(request, new SimpleHttpRequestCallback<List<StatusRes>>() {
                    @Override
                    public void onSuccess(List<StatusRes> responseData) {
                        if (!loadMore) {
                            mStatusAdapter.clear();
                        }
                        mStatusAdapter.addAll(responseData);
                        mStatusAdapter.notifyDataSetChanged();
                        mRecyclerView.setRefreshing(false);

                        mMaxId = Utils.getMaxId(mStatusAdapter.getAllData());
                    }

                    @Override
                    public void onFail(ApiException apiException) {