org.lytsing.android.weibo.ui.TimelineActivity.java Source code

Java tutorial

Introduction

Here is the source code for org.lytsing.android.weibo.ui.TimelineActivity.java

Source

/*
 * Copyright (C) 2012 lytsing.org
 *
 * 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 org.lytsing.android.weibo.ui;

import android.content.Intent;
import android.content.SharedPreferences;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.text.TextUtils;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.AdapterView;
import android.widget.AdapterView.OnItemClickListener;

import com.actionbarsherlock.view.Menu;
import com.actionbarsherlock.view.MenuItem;
import com.android.volley.Request.Method;
import com.android.volley.Response;
import com.android.volley.VolleyError;
import com.androidquery.AQuery;
import com.costum.android.widget.PullAndLoadListView;
import com.google.gson.Gson;
import com.sina.weibo.sdk.exception.WeiboException;
import com.sina.weibo.sdk.net.RequestListener;
import com.sina.weibo.sdk.net.WeiboParameters;
import com.sina.weibo.sdk.openapi.StatusesAPI;

import net.simonvt.menudrawer.MenuDrawer;

import org.json.JSONException;
import org.json.JSONObject;
import org.lytsing.android.weibo.Consts;
import org.lytsing.android.weibo.R;
import org.lytsing.android.weibo.core.Configuration;
import org.lytsing.android.weibo.toolbox.VolleyErrorHelper;
import org.lytsing.android.weibo.WeiboApplication;
import org.lytsing.android.weibo.adapters.StatusItemAdapter;
import org.lytsing.android.weibo.core.models.Statuses;
import org.lytsing.android.weibo.core.models.WeiboObject;
import org.lytsing.android.weibo.toolbox.GsonRequest;
import org.lytsing.android.weibo.util.Log;
import org.lytsing.android.weibo.util.Preferences;
import org.lytsing.android.weibo.util.Util;

public class TimelineActivity extends BaseActivity {

    private final int ON_SUCC_RESPONSE = 0;

    private final int ON_ERROR_RESPONSE = 1;

    private final int ERROR_CODE_RESPONSE = 2;

    private final int PER_REQUEST_COUNT = 20;

    private StatusItemAdapter mAdapter = null;

    private PullAndLoadListView mListView = null;

    private MenuDrawer mMenuDrawer;

    private Menu mOptionsMenu;

    protected long mSinceId = 0;

    protected long mMaxId = 0;

    private AQuery aq;

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        if (mAccessToken.isSessionValid()) {
            initView();
        } else {
            Intent intent = new Intent(this, AuthenticatedActivity.class);
            startActivity(intent);
        }
    }

    private Intent createComposeIntent() {
        Intent intent = new Intent(this, ComposeActivity.class);
        return intent;
    }

    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        getSupportMenuInflater().inflate(R.menu.home, menu);
        mOptionsMenu = menu;
        return true;
    }

    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        switch (item.getItemId()) {
        case android.R.id.home:
            mMenuDrawer.toggleMenu();
            break;
        case R.id.menu_compose:
            startActivity(createComposeIntent());
            break;
        case R.id.menu_refresh:
            refreshStatuses(mSinceId);
            break;
        default:
            break;
        }

        return true;
    }

    private void initView() {
        setContentView(R.layout.timeline);

        mMenuDrawer = MenuDrawer.attach(this, MenuDrawer.MENU_DRAG_WINDOW);
        mMenuDrawer.setMenuView(R.layout.menu);

        MenuFragment menu = (MenuFragment) getSupportFragmentManager().findFragmentById(R.id.left_menu);
        menu.getListView().setOnItemClickListener(new OnItemClickListener() {

            @Override
            public void onItemClick(AdapterView<?> parent, View view, int position, long id) {

                if (position == 1) {
                    Intent intent = new Intent(TimelineActivity.this, SettingsActivity.class);
                    startActivity(intent);
                }

                mMenuDrawer.setActiveView(view);
                mMenuDrawer.closeMenu();
            }
        });

        aq = new AQuery(this);

        mListView = ((PullAndLoadListView) findViewById(R.id.msg_list_item));

        // Set a listener to be invoked when the list should be refreshed.
        mListView.setOnRefreshListener(new PullAndLoadListView.OnRefreshListener() {
            @Override
            public void onRefresh() {
                // Do work to refresh the list here.
                refreshStatuses(mSinceId);
            }
        });

        mListView.setOnLoadMoreListener(new PullAndLoadListView.OnLoadMoreListener() {

            public void onLoadMore() {
                loadMoreData(mMaxId);
            }
        });

        mListView.setLastUpdated(getLastSyncTime(Preferences.PREF_LAST_SYNC_TIME));

        mAdapter = new StatusItemAdapter(this, getWeiboApplication().getImageLoader());

        requestFriendsTimeline();

        mListView.setOnItemClickListener(new OnItemClickListener() {
            @Override
            public void onItemClick(AdapterView<?> parent, View view, int position, long id) {

                // see: How to determine onItemClick for pulltorefreshlistview
                // http://stackoverflow.com/questions/10959030/how-to-determine-onitemclick-for-pulltorefreshlistview
                Statuses status = (Statuses) mListView.getItemAtPosition(position);

                if (status == null) {
                    return;
                } else {
                    Bundle bundle = new Bundle();
                    bundle.putSerializable(Consts.STATUSES_KEY, status);

                    Intent intent = new Intent(TimelineActivity.this, StatusDetailActivity.class);
                    intent.putExtras(bundle);
                    startActivity(intent);
                }
            }
        });
    }

    @Override
    protected void onRestoreInstanceState(Bundle inState) {
        super.onRestoreInstanceState(inState);
        //mMenuDrawer.restoreState(inState.getParcelable(STATE_MENUDRAWER));
    }

    @Override
    protected void onSaveInstanceState(Bundle outState) {
        //java.lang.NullPointerException at org.lytsing.android.weibo.ui.TimelineActivity.onSaveInstanceState(TimelineActivity.java:204)
        //super.onSaveInstanceState(outState);
        //outState.putParcelable(STATE_MENUDRAWER, mMenuDrawer.saveState());
    }

    @Override
    public void onBackPressed() {
        final int drawerState = mMenuDrawer.getDrawerState();
        if (drawerState == MenuDrawer.STATE_OPEN || drawerState == MenuDrawer.STATE_OPENING) {
            mMenuDrawer.closeMenu();
            return;
        }

        super.onBackPressed();
    }

    private Handler mHandler = new Handler() {
        @Override
        public void handleMessage(Message msg) {
            super.handleMessage(msg);
            switch (msg.what) {
            case ON_SUCC_RESPONSE:
                setLastSyncTime(Util.getNowLocaleTime());
                mAdapter.notifyDataSetChanged();
                mListView.onLoadMoreComplete();
                break;
            case ERROR_CODE_RESPONSE:
            case ON_ERROR_RESPONSE:
                displayToast("Error:" + (String) msg.obj);
                mListView.onLoadMoreComplete();
                break;
            default:
                break;
            }
        }
    };

    private void showLoadingIndicator() {
        aq.id(R.id.placeholder_loading).visible();
        setRefreshActionButtonState(true);
    }

    private void hideLoadingIndicator() {
        aq.id(R.id.placeholder_loading).gone();
        setRefreshActionButtonState(false);
    }

    private void showErrorIndicator() {
        aq.id(R.id.placeholder_error).visible();
    }

    private void hideErrorIndicator() {
        aq.id(R.id.placeholder_error).gone();
    }

    private String getLastSyncTime(String pre) {
        SharedPreferences prefs = Preferences.get(this);
        String time = prefs.getString(pre, "");
        return time;
    }

    private void setLastSyncTime(String time) {
        SharedPreferences.Editor editor = Preferences.get(this).edit();
        editor.putString(Preferences.PREF_LAST_SYNC_TIME, time);
        editor.commit();
    }

    private void refreshStatuses(long sinceId) {
        setRefreshActionButtonState(true);

        String url = Configuration.API_SERVER + "/statuses/friends_timeline.json";
        WeiboParameters params = new WeiboParameters();
        params.put("access_token", mAccessToken.getToken());
        params.put("since_id", sinceId);
        params.put("max_id", 0);
        params.put("count", PER_REQUEST_COUNT);
        params.put("page", 1);
        params.put("base_app", 0);
        params.put("feature", 0);

        url = url + "?" + params.encodeUrl();

        GsonRequest<WeiboObject> refreshRequest = new GsonRequest<WeiboObject>(Method.GET, url, null,
                WeiboObject.class, new Response.Listener<WeiboObject>() {

                    @Override
                    public void onResponse(WeiboObject response) {
                        final int refreshCount = response.statuses.size();
                        Log.d("newsMsgLists length == " + refreshCount);
                        if (refreshCount > 0) {
                            mSinceId = response.statuses.get(0).id;
                            mAdapter.addNewestStatuses(response.statuses);
                        }

                        mAdapter.notifyDataSetChanged();
                        // Call onRefreshComplete when the list has been
                        // refreshed.
                        mListView.onRefreshComplete();
                        mListView.setLastUpdated(getLastSyncTime(Preferences.PREF_LAST_SYNC_TIME));

                        setLastSyncTime(Util.getNowLocaleTime());

                        if (refreshCount > 0) {
                            displayToast(
                                    String.format(getResources().getString(R.string.new_blog_toast), refreshCount));
                        } else {
                            displayToast(R.string.no_new_blog_toast);
                        }

                        setRefreshActionButtonState(false);
                    }

                }, new Response.ErrorListener() {

                    @Override
                    public void onErrorResponse(VolleyError e) {
                        Util.showToast(TimelineActivity.this, "Error:" + e.getMessage());
                        setRefreshActionButtonState(false);
                    }

                });

        WeiboApplication.getWeiboApplication().addToRequestQueue(refreshRequest);
    }

    private void requestFriendsTimeline() {

        hideErrorIndicator();
        showLoadingIndicator();

        String url = Configuration.API_SERVER + "/statuses/friends_timeline.json";
        WeiboParameters params = new WeiboParameters();
        params.put("access_token", mAccessToken.getToken());
        params.put("count", PER_REQUEST_COUNT);
        params.put("page", 1);
        params.put("base_app", 0);
        params.put("feature", 0);

        url = url + "?" + params.encodeUrl();

        GsonRequest<WeiboObject> timelineRequest = new GsonRequest<WeiboObject>(Method.GET, url, null,
                WeiboObject.class, createMyReqSuccessListener(), createMyReqErrorListener());

        WeiboApplication.getWeiboApplication().addToRequestQueue(timelineRequest);
    }

    private Response.Listener<WeiboObject> createMyReqSuccessListener() {
        return new Response.Listener<WeiboObject>() {
            @Override
            public void onResponse(WeiboObject info) {
                for (Statuses status : info.statuses) {
                    mAdapter.addStatuses(status);
                    mMaxId = status.id - 1;
                }

                if (info.statuses.size() > 0) {
                    mSinceId = info.statuses.get(0).id;
                }

                hideLoadingIndicator();
                aq.id(R.id.placeholder_error).gone();

                showContents();
                mAdapter.notifyDataSetChanged();
                setLastSyncTime(Util.getNowLocaleTime());
            }
        };
    }

    private Response.ErrorListener createMyReqErrorListener() {
        return new Response.ErrorListener() {
            @Override
            public void onErrorResponse(VolleyError error) {
                Log.e(error.getMessage());
                String errorMsg = VolleyErrorHelper.getMessage(error, getApplicationContext());

                hideLoadingIndicator();
                showErrorIndicator();
                aq.id(R.id.error_msg).text(errorMsg);
                aq.id(R.id.retry_button).clicked(new OnClickListener() {

                    @Override
                    public void onClick(View v) {
                        requestFriendsTimeline();
                    }
                });
            }
        };
    }

    public void setRefreshActionButtonState(boolean refreshing) {
        if (mOptionsMenu == null) {
            return;
        }

        final MenuItem refreshItem = mOptionsMenu.findItem(R.id.menu_refresh);
        if (refreshItem != null) {
            if (refreshing) {
                refreshItem.setActionView(R.layout.actionbar_indeterminate_progress);
            } else {
                refreshItem.setActionView(null);
            }
        }
    }

    private void loadMoreData(final long maxId) {
        StatusesAPI statusAPI = new StatusesAPI(mAccessToken);
        statusAPI.friendsTimeline(0, maxId, PER_REQUEST_COUNT, 1, false, StatusesAPI.FEATURE_ALL, false,
                new RequestListener() {

                    @Override
                    public void onComplete(String result) {
                        try {
                            Message msg = Message.obtain();
                            if (TextUtils.isEmpty(result) || result.contains("error_code")) {
                                msg.what = ERROR_CODE_RESPONSE;
                                JSONObject obj = new JSONObject(result);
                                msg.obj = obj.getString("error");
                            } else {
                                msg.what = ON_SUCC_RESPONSE;
                                Gson gson = new Gson();
                                WeiboObject response = gson.fromJson(result, WeiboObject.class);

                                for (Statuses status : response.statuses) {
                                    mAdapter.addStatuses(status);
                                    mMaxId = status.id - 1;
                                }

                                if (maxId == 0 && response.statuses.size() > 0) {
                                    mSinceId = response.statuses.get(0).id;
                                }
                            }

                            mHandler.sendMessage(msg);
                        } catch (JSONException e) {
                            e.printStackTrace();
                        }
                    }

                    @Override
                    public void onWeiboException(final WeiboException e) {
                        Message msg = Message.obtain();
                        msg.what = ON_ERROR_RESPONSE;
                        msg.obj = e.getMessage();

                        mHandler.sendMessage(msg);
                    }
                });
    }

    private void showContents() {
        aq.id(R.id.timelist_list).visible();

        // FIXME: put it here, else will pop up "Tap to Refresh"
        mListView.setAdapter(mAdapter);
    }
}