de.elanev.studip.android.app.frontend.news.NewsListFragment.java Source code

Java tutorial

Introduction

Here is the source code for de.elanev.studip.android.app.frontend.news.NewsListFragment.java

Source

/*
 * Copyright (c) 2014 ELAN e.V.
 * All rights reserved. This program and the accompanying materials
 * are made available under the terms of the GNU Public License v3.0
 * which accompanies this distribution, and is available at
 * http://www.gnu.org/licenses/gpl.html
 */
package de.elanev.studip.android.app.frontend.news;

import android.app.Activity;
import android.content.Context;
import android.content.Intent;
import android.database.ContentObserver;
import android.database.Cursor;
import android.graphics.PorterDuff;
import android.net.Uri;
import android.os.Bundle;
import android.os.Handler;
import android.support.v4.app.Fragment;
import android.support.v4.app.LoaderManager.LoaderCallbacks;
import android.support.v4.content.CursorLoader;
import android.support.v4.content.Loader;
import android.support.v4.widget.SwipeRefreshLayout;
import android.text.TextUtils;
import android.view.View;
import android.view.ViewGroup;
import android.widget.AdapterView;
import android.widget.ImageView;
import android.widget.TextView;
import android.widget.Toast;

import com.android.volley.VolleyError;

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

import de.elanev.studip.android.app.R;
import de.elanev.studip.android.app.backend.db.CoursesContract;
import de.elanev.studip.android.app.backend.db.InstitutesContract;
import de.elanev.studip.android.app.backend.db.NewsContract;
import de.elanev.studip.android.app.backend.db.UsersContract;
import de.elanev.studip.android.app.backend.net.SyncHelper;
import de.elanev.studip.android.app.util.TextTools;
import de.elanev.studip.android.app.widget.ProgressListFragment;
import de.elanev.studip.android.app.widget.SectionedCursorAdapter;

/**
 * @author joern
 */
public class NewsListFragment extends ProgressListFragment implements LoaderCallbacks<Cursor>,
        AdapterView.OnItemClickListener, SwipeRefreshLayout.OnRefreshListener, SyncHelper.SyncHelperCallbacks {

    public static final String TAG = NewsListFragment.class.getSimpleName();
    public static final String NEWS_SELECTOR = "news_selector";

    protected final ContentObserver mObserver = new ContentObserver(new Handler()) {
        @Override
        public void onChange(boolean selfChange) {
            if (getActivity() == null) {
                return;
            }

            Loader<Cursor> loader = getLoaderManager().getLoader(0);
            if (loader != null) {
                loader.forceLoad();
            }
        }
    };
    private NewsAdapter mNewsAdapter;

    public NewsListFragment() {
    }

    public static Fragment newInstance(int newsSelector) {
        NewsListFragment fragment = new NewsListFragment();

        Bundle args = new Bundle();
        args.putInt(NEWS_SELECTOR, newsSelector);

        fragment.setArguments(args);

        return fragment;
    }

    @Override
    public void onActivityCreated(Bundle savedInstanceState) {
        super.onActivityCreated(savedInstanceState);
        getActivity().setTitle(R.string.News);
        int newsSelector = getArguments().getInt(NEWS_SELECTOR);

        setEmptyMessage(R.string.no_news);

        mNewsAdapter = new NewsAdapter(mContext);
        if (newsSelector == NewsTabsAdapter.NEWS_GLOBAL) {
            mNewsAdapter.setShowSections(false);
            mListView.setAreHeadersSticky(false);
        }

        mListView.setOnItemClickListener(this);
        mListView.setAdapter(mNewsAdapter);

        mSwipeRefreshLayoutListView.setOnRefreshListener(this);
        mSwipeRefreshLayoutListView.setRefreshing(true);

        SyncHelper.getInstance(mContext).performNewsSync(this);
        // initialize CursorLoader
        getLoaderManager().initLoader(newsSelector, null, this);
    }

    @Override
    public void onAttach(Activity activity) {
        super.onAttach(activity);
        activity.getContentResolver().registerContentObserver(NewsContract.CONTENT_URI, true, mObserver);
    }

    @Override
    public void onDetach() {
        super.onDetach();
        getActivity().getContentResolver().unregisterContentObserver(mObserver);
    }

    public Loader<Cursor> onCreateLoader(int id, Bundle data) {
        setLoadingViewVisible(true);
        Uri uri = NewsContract.CONTENT_URI;
        String[] projection = null;

        switch (id) {
        case NewsTabsAdapter.NEWS_COURSES:
            uri = uri.buildUpon().appendPath("courses").build();
            projection = NewsQuery.PROJECTION_COURSES;
            break;
        case NewsTabsAdapter.NEWS_INSTITUTES:
            uri = uri.buildUpon().appendPath("institutes").build();
            projection = NewsQuery.PROJECTION_INSTITUTES;
            break;
        case NewsTabsAdapter.NEWS_GLOBAL:
            uri = uri.buildUpon().appendPath("global").build();
            projection = NewsQuery.PROJECTION_GLOBAL;
            break;
        }

        return new CursorLoader(getActivity(), uri, projection, NewsContract.Columns.NEWS_EXPIRE
                + " > (strftime('%s','now')-" + NewsContract.Columns.NEWS_DATE + ")", null,
                NewsContract.DEFAULT_SORT_ORDER);
    }

    public void onLoadFinished(Loader<Cursor> loader, Cursor cursor) {
        if (getActivity() == null) {
            return;
        }

        int idColumnIdx = 0;
        int titleColumnIdx = 0;

        int newsSelector = loader.getId();

        switch (newsSelector) {
        case NewsTabsAdapter.NEWS_COURSES:
            idColumnIdx = cursor.getColumnIndex(CoursesContract.Columns.Courses.COURSE_ID);

            titleColumnIdx = cursor.getColumnIndex(CoursesContract.Columns.Courses.COURSE_TITLE);

            break;
        case NewsTabsAdapter.NEWS_INSTITUTES:
            idColumnIdx = cursor.getColumnIndex(InstitutesContract.Columns.INSTITUTE_ID);

            titleColumnIdx = cursor.getColumnIndex(InstitutesContract.Columns.INSTITUTE_NAME);

            break;
        case NewsTabsAdapter.NEWS_GLOBAL:
            idColumnIdx = -1;
            titleColumnIdx = -1;
            break;
        }

        List<SectionedCursorAdapter.Section> sections = new ArrayList<SectionedCursorAdapter.Section>();
        if (idColumnIdx != -1 || titleColumnIdx != -1) {
            cursor.moveToFirst();
            String previousId = null;
            String currentId;
            while (!cursor.isAfterLast()) {

                currentId = cursor.getString(idColumnIdx);

                if (!TextUtils.equals(previousId, currentId)) {

                    SectionedCursorAdapter.Section section = new SectionedCursorAdapter.Section(
                            cursor.getPosition(), cursor.getString(titleColumnIdx));

                    sections.add(section);
                }
                previousId = currentId;
                cursor.moveToNext();
            }
        }

        mNewsAdapter.setSections(sections);
        mNewsAdapter.swapCursor(cursor);

        setLoadingViewVisible(false);
    }

    public void onLoaderReset(Loader<Cursor> loader) {
        mNewsAdapter.swapCursor(null);
    }

    @Override
    public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
        Cursor c = (Cursor) mListView.getItemAtPosition(position);
        String topic = c.getString(c.getColumnIndex(NewsContract.Columns.NEWS_TOPIC));
        String body = c.getString(c.getColumnIndex(NewsContract.Columns.NEWS_BODY));
        String name = String.format("%s %s %s %s",
                c.getString(c.getColumnIndex(UsersContract.Columns.USER_TITLE_PRE)),
                c.getString(c.getColumnIndex(UsersContract.Columns.USER_FORENAME)),
                c.getString(c.getColumnIndex(UsersContract.Columns.USER_LASTNAME)),
                c.getString(c.getColumnIndex(UsersContract.Columns.USER_TITLE_POST)));
        String userImageUrl = c.getString(c.getColumnIndex(UsersContract.Columns.USER_AVATAR_NORMAL));
        long date = c.getLong(c.getColumnIndex(NewsContract.Columns.NEWS_MKDATE));

        Bundle args = new Bundle();
        args.putString(NewsContract.Columns.NEWS_TOPIC, topic);
        args.putString(NewsContract.Columns.NEWS_BODY, body);
        args.putLong(NewsContract.Columns.NEWS_DATE, date);
        args.putString(UsersContract.Columns.USER_FORENAME, name);
        args.putString(UsersContract.Columns.USER_AVATAR_NORMAL, userImageUrl);

        Intent intent = new Intent();
        intent.setClass(getActivity(), NewsItemViewActivity.class);
        intent.putExtras(args);
        startActivity(intent);
    }

    @Override
    public void onRefresh() {
        SyncHelper.getInstance(mContext).performNewsSync(this);
    }

    @Override
    public void onSyncStarted() {
        mSwipeRefreshLayoutListView.setRefreshing(true);
    }

    @Override
    public void onSyncStateChange(int status) {
    }

    @Override
    public void onSyncFinished(int status) {
        if (status == SyncHelper.SyncHelperCallbacks.FINISHED_NEWS_SYNC) {
            mSwipeRefreshLayoutListView.setRefreshing(false);
        }
    }

    @Override
    public void onSyncError(int status, VolleyError error) {
        if (status == SyncHelper.SyncHelperCallbacks.ERROR_NEWS_SYNC && error != null
                && error.networkResponse != null && error.networkResponse.statusCode != 404) {
            if (getActivity() != null) {
                Toast.makeText(mContext, R.string.sync_error_generic, Toast.LENGTH_LONG).show();
            }
            mSwipeRefreshLayoutListView.setRefreshing(false);
        }
    }

    private interface NewsQuery {

        String[] PROJECTION_COURSES = { NewsContract.Qualified.NEWS_ID, NewsContract.Qualified.NEWS_NEWS_TOPIC,
                NewsContract.Qualified.NEWS_NEWS_BODY, NewsContract.Qualified.NEWS_NEWS_MKDATE,
                NewsContract.Qualified.NEWS_NEWS_RANGE_ID, UsersContract.Qualified.USERS_USER_TITLE_PRE,
                UsersContract.Qualified.USERS_USER_TITLE_POST, UsersContract.Qualified.USERS_USER_FORENAME,
                UsersContract.Qualified.USERS_USER_LASTNAME, UsersContract.Qualified.USERS_USER_AVATAR_NORMAL,
                CoursesContract.Qualified.Courses.COURSES_COURSE_ID,
                CoursesContract.Qualified.Courses.COURSES_COURSE_TITLE };

        String[] PROJECTION_INSTITUTES = { NewsContract.Qualified.NEWS_ID, NewsContract.Qualified.NEWS_NEWS_TOPIC,
                NewsContract.Qualified.NEWS_NEWS_BODY, NewsContract.Qualified.NEWS_NEWS_MKDATE,
                NewsContract.Qualified.NEWS_NEWS_RANGE_ID, UsersContract.Qualified.USERS_USER_TITLE_PRE,
                UsersContract.Qualified.USERS_USER_TITLE_POST, UsersContract.Qualified.USERS_USER_FORENAME,
                UsersContract.Qualified.USERS_USER_LASTNAME, UsersContract.Qualified.USERS_USER_AVATAR_NORMAL,
                InstitutesContract.Qualified.INSTITUTES_INSTITUTE_ID,
                InstitutesContract.Qualified.INSTITUTES_INSTITUTE_NAME };

        String[] PROJECTION_GLOBAL = { NewsContract.Qualified.NEWS_ID, NewsContract.Qualified.NEWS_NEWS_TOPIC,
                NewsContract.Qualified.NEWS_NEWS_BODY, NewsContract.Qualified.NEWS_NEWS_MKDATE,
                NewsContract.Qualified.NEWS_NEWS_RANGE_ID, UsersContract.Qualified.USERS_USER_TITLE_PRE,
                UsersContract.Qualified.USERS_USER_TITLE_POST, UsersContract.Qualified.USERS_USER_FORENAME,
                UsersContract.Qualified.USERS_USER_LASTNAME, UsersContract.Qualified.USERS_USER_AVATAR_NORMAL };

    }

    private class NewsAdapter extends SectionedCursorAdapter {

        public NewsAdapter(Context context) {
            super(context);
        }

        @Override
        public View newView(Context context, Cursor cursor, ViewGroup parent) {
            return getActivity().getLayoutInflater().inflate(R.layout.list_item_two_text_icon, parent, false);
        }

        @Override
        public void bindView(View view, Context context, final Cursor cursor) {
            final String newsTopic = cursor.getString(cursor.getColumnIndex(NewsContract.Columns.NEWS_TOPIC));
            final Long newsDate = cursor.getLong(cursor.getColumnIndex(NewsContract.Columns.NEWS_MKDATE));
            final String userForename = cursor
                    .getString(cursor.getColumnIndex(UsersContract.Columns.USER_FORENAME));
            final String userLastname = cursor
                    .getString(cursor.getColumnIndex(UsersContract.Columns.USER_LASTNAME));
            final String courseId = cursor.getString(cursor.getColumnIndex(NewsContract.Columns.NEWS_RANGE_ID));

            final TextView newsTopicView = (TextView) view.findViewById(R.id.text1);
            final TextView newsAuthorView = (TextView) view.findViewById(R.id.text2);
            final ImageView icon = (ImageView) view.findViewById(R.id.icon);

            switch (getArguments().getInt(NEWS_SELECTOR)) {
            //TODO: Separate icons for different course types and global
            // Seminar icon if switch fails oder entry is seminar type
            default:
            case NewsTabsAdapter.NEWS_COURSES:
                icon.setImageResource(R.drawable.ic_seminar);
                break;
            // Institute icon if institute or global entry type
            case NewsTabsAdapter.NEWS_INSTITUTES:
            case NewsTabsAdapter.NEWS_GLOBAL:
                icon.setImageResource(R.drawable.ic_action_global);
                break;
            }

            icon.setColorFilter(getResources().getColor(R.color.studip_mobile_dark), PorterDuff.Mode.SRC_IN);

            newsTopicView.setText(newsTopic);
            newsAuthorView.setText(TextTools.getLocalizedAuthorAndDateString(
                    String.format("%s %s", userForename, userLastname), newsDate, getActivity()));
        }

    }

}