org.andstatus.app.msg.TimelineFragment.java Source code

Java tutorial

Introduction

Here is the source code for org.andstatus.app.msg.TimelineFragment.java

Source

/* 
 * Copyright (c) 2011-2015 yvolk (Yuri Volkov), http://yurivolkov.com
 *
 * 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.andstatus.app.msg;

import android.app.Activity;
import android.database.Cursor;
import android.database.MatrixCursor;
import android.os.Bundle;
import android.support.v4.app.ListFragment;
import android.view.LayoutInflater;
import android.view.MenuItem;
import android.view.View;
import android.view.ViewGroup;
import android.widget.AbsListView;
import android.widget.AbsListView.OnScrollListener;
import android.widget.AdapterView;
import android.widget.AdapterView.OnItemClickListener;
import android.widget.LinearLayout;

import org.andstatus.app.R;
import org.andstatus.app.context.MyPreferences;
import org.andstatus.app.data.MyDatabase;
import org.andstatus.app.data.MyDatabase.User;
import org.andstatus.app.data.TimelineSql;
import org.andstatus.app.data.TimelineViewBinder;
import org.andstatus.app.util.MyLog;
import org.andstatus.app.widget.MySimpleCursorAdapter;

import java.util.ArrayList;
import java.util.List;

/**
 * @author yvolk@yurivolkov.com
 */
public class TimelineFragment extends ListFragment implements OnScrollListener, OnItemClickListener {
    private static final int DIALOG_ID_TIMELINE_TYPE = 9;
    private static final int LOADER_ID = 1;
    private static final String ACTIVITY_PERSISTENCE_NAME = TimelineFragment.class.getSimpleName();

    private TimelineActivity mTimeline;

    /**
     * Visibility of the layout indicates whether Messages are being loaded into the list (asynchronously...)
     * The layout appears at the bottom of the list of messages
     * when new items are being loaded into the list
     */
    private LinearLayout mLoadingLayout;

    /**
     * Is saved position restored (or some default positions set)?
     */
    private boolean mPositionRestored = false;

    private boolean mIsLoading = false;

    @Override
    public void onAttach(Activity activity) {
        mTimeline = (TimelineActivity) activity;
        super.onAttach(activity);
    }

    @Override
    public void onDetach() {
        MyLog.v(this, "onDetach");
        mTimeline = null;
        super.onDetach();
    }

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
        View view = inflater.inflate(R.layout.my_list_fragment, container, false);
        mLoadingLayout = (LinearLayout) inflater.inflate(R.layout.item_loading, null);
        return view;
    }

    @Override
    public void onActivityCreated(Bundle savedInstanceState) {
        getListView().addFooterView(mLoadingLayout);

        getListView().setOnScrollListener(this);
        getListView().setOnItemClickListener(this);

        createListAdapter(getEmptyCursor());

        getListView().setOnCreateContextMenuListener(mTimeline.getContextMenu());
        super.onActivityCreated(savedInstanceState);
    }

    private void saveListPosition() {
        if (mTimeline != null) {
            mTimeline.saveListPosition();
        }
    }

    @Override
    public void onPause() {
        final String method = "onPause";
        super.onPause();
        if (MyLog.isVerboseEnabled()) {
            MyLog.v(this, method);
        }

        if (mPositionRestored) {
            setFastScrollThumb(false);
            if (!isLoading()) {
                saveListPosition();
            }
            mPositionRestored = false;
        }
    }

    private void setFastScrollThumb(boolean isVisible) {
        getListView().setFastScrollEnabled(isVisible);
    }

    // That advice doesn't fit here:
    // see http://stackoverflow.com/questions/5996885/how-to-wait-for-android-runonuithread-to-be-finished
    protected void savePositionOnUiThread() {
        Runnable runnable = new Runnable() {
            @Override
            public void run() {
                if (mPositionRestored) {
                    saveListPosition();
                }
            }
        };
        if (mTimeline != null) {
            mTimeline.runOnUiThread(runnable);
        }
    }

    @Override
    public void onItemClick(AdapterView<?> adapterView, final View view, final int position, final long id) {
        if (mTimeline != null) {
            mTimeline.onItemClick(adapterView, view, position, id);
        }
    }

    @Override
    public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) {
        if (mTimeline != null && mPositionRestored && !isLoading()) {
            mTimeline.onScroll(view, firstVisibleItem, visibleItemCount, totalItemCount);
        }
    }

    @Override
    public void onScrollStateChanged(AbsListView view, int scrollState) {
        switch (scrollState) {
        case OnScrollListener.SCROLL_STATE_IDLE:
            break;
        case OnScrollListener.SCROLL_STATE_TOUCH_SCROLL:
            break;
        case OnScrollListener.SCROLL_STATE_FLING:
            setFastScrollThumb(true);
            break;
        default:
            break;
        }
    }

    private void createListAdapter(Cursor cursor) {
        List<String> columnNames = new ArrayList<String>();
        List<Integer> viewIds = new ArrayList<Integer>();
        columnNames.add(User.AUTHOR_NAME);
        viewIds.add(R.id.message_author);
        columnNames.add(MyDatabase.Msg.BODY);
        viewIds.add(R.id.message_body);
        columnNames.add(MyDatabase.Msg.CREATED_DATE);
        viewIds.add(R.id.message_details);
        columnNames.add(MyDatabase.MsgOfUser.FAVORITED);
        viewIds.add(R.id.message_favorited);
        columnNames.add(MyDatabase.Msg._ID);
        viewIds.add(R.id.id);
        int listItemLayoutId = R.layout.message_basic;
        if (MyPreferences.showAvatars()) {
            listItemLayoutId = R.layout.message_avatar;
            columnNames.add(MyDatabase.Download.AVATAR_FILE_NAME);
            viewIds.add(R.id.avatar_image);
        }
        if (MyPreferences.showAttachedImages()) {
            columnNames.add(MyDatabase.Download.IMAGE_ID);
            viewIds.add(R.id.attached_image);
        }
        MySimpleCursorAdapter mCursorAdapter = new MySimpleCursorAdapter(mTimeline, listItemLayoutId, cursor,
                columnNames.toArray(new String[] {}), toIntArray(viewIds), 0);
        mCursorAdapter.setViewBinder(new TimelineViewBinder());

        setListAdapter(mCursorAdapter);
    }

    private Cursor getEmptyCursor() {
        return new MatrixCursor(TimelineSql.getTimelineProjection());
    }

    /**
     * See http://stackoverflow.com/questions/960431/how-to-convert-listinteger-to-int-in-java
     */
    private static int[] toIntArray(List<Integer> list) {
        int[] ret = new int[list.size()];
        for (int i = 0; i < ret.length; i++) {
            ret[i] = list.get(i);
        }
        return ret;
    }

    protected boolean isLoading() {
        return mIsLoading;
    }

    protected void setLoading(String source, boolean isLoading) {
        if (isLoading() != isLoading && mTimeline != null && !mTimeline.isFinishing()) {
            mIsLoading = isLoading;
            MyLog.v(this, source + " set isLoading to " + isLoading);
            mLoadingLayout.setVisibility(isLoading ? View.VISIBLE : View.INVISIBLE);
        }
    }

    protected void restoreListPosition(TimelineListParameters mListParameters) {
        mPositionRestored = new TimelineListPositionStorage(getListAdapter(), getListView(), mListParameters)
                .restoreListPosition();
    }

    public boolean isPositionRestored() {
        return mPositionRestored;
    }
}