at.ac.uniklu.mobile.sportal.CalendarFragment.java Source code

Java tutorial

Introduction

Here is the source code for at.ac.uniklu.mobile.sportal.CalendarFragment.java

Source

/*
 * Copyright (c) 2014 Mario Guggenberger <mario.guggenberger@aau.at>
 *
 * This file is part of AAU Studentenportal.
 *
 * AAU Studentenportal is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * AAU Studentenportal is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with AAU Studentenportal.  If not, see <http://www.gnu.org/licenses/>.
 */

package at.ac.uniklu.mobile.sportal;

import java.util.Calendar;
import java.util.Date;
import java.util.List;
import java.util.Locale;

import android.content.Context;
import android.os.Bundle;
import android.support.v4.app.ListFragment;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.AbsListView;
import android.widget.ListView;
import android.widget.TextView;
import android.widget.AbsListView.OnScrollListener;
import at.ac.uniklu.mobile.sportal.api.Termin;
import at.ac.uniklu.mobile.sportal.model.CalendarModel;
import at.ac.uniklu.mobile.sportal.model.ModelService;
import at.ac.uniklu.mobile.sportal.ui.AsyncTask;
import at.ac.uniklu.mobile.sportal.ui.ProgressNotificationToggle;
import at.ac.uniklu.mobile.sportal.ui.Refreshable;
import at.ac.uniklu.mobile.sportal.ui.SectionedListAdapter;
import at.ac.uniklu.mobile.sportal.util.Analytics;
import at.ac.uniklu.mobile.sportal.util.MapUtils;
import at.ac.uniklu.mobile.sportal.util.UIUtils;
import at.ac.uniklu.mobile.sportal.util.Utils;

public class CalendarFragment extends ListFragment
        implements ProgressNotificationToggle, Refreshable, OnScrollListener {

    private class CalendarSLA extends SectionedListAdapter<Termin, Date> {

        private Date mYearSwitch;
        private CharSequence mLabelNow;
        private CharSequence mLabelCancelled;

        private class HeaderViewHolder {
            public TextView text1;
            public TextView text2;
        }

        private class ItemViewHolder {
            public TextView timeText;
            public TextView roomText;
            public TextView titleText;
            public TextView labelText;
        }

        public CalendarSLA(Context context, List<Termin> list) {
            super(context, list, new CalendarSLA.HeaderDataExtractor<Termin, Date>() {
                private Calendar mCalendar = Calendar.getInstance();

                @Override
                public Date extract(Termin itemData) {
                    mCalendar.setTime(itemData.getDatum());
                    mCalendar.set(Calendar.HOUR_OF_DAY, 0);
                    mCalendar.set(Calendar.MINUTE, 0);
                    mCalendar.set(Calendar.SECOND, 0);
                    mCalendar.set(Calendar.MILLISECOND, 0);
                    return mCalendar.getTime();
                }
            }, R.layout.calendar_section_header, R.layout.calendar_date);

            Calendar c = Calendar.getInstance();
            c.set(c.get(Calendar.YEAR) + 1, Calendar.JANUARY, 1, 0, 0, 0);
            mYearSwitch = c.getTime();

            mLabelNow = context.getString(R.string.dates_now).toUpperCase(Locale.GERMAN);
            mLabelCancelled = context.getString(R.string.dates_cancelled).toUpperCase(Locale.GERMAN);
        }

        @Override
        public void updateHeaderView(View headerView, Date headerData) {
            HeaderViewHolder viewHolder;
            if (headerView.getTag() == null) {
                viewHolder = new HeaderViewHolder();
                viewHolder.text1 = (TextView) headerView.findViewById(R.id.text1);
                viewHolder.text2 = (TextView) headerView.findViewById(R.id.text2);
                headerView.setTag(viewHolder);
            } else {
                viewHolder = (HeaderViewHolder) headerView.getTag();
            }

            String day = getString(R.string.calendar_date_dayname, headerData);
            if (Utils.isToday(headerData)) {
                day = getString(R.string.dates_today);
            } else if (Utils.isTomorrow(headerData)) {
                day = getString(R.string.dates_tomorrow);
            }

            viewHolder.text1
                    .setText((headerData.after(mYearSwitch) ? getString(R.string.calendar_date_dmy, headerData)
                            : getString(R.string.calendar_date_dm, headerData)).toUpperCase(Locale.GERMAN));
            viewHolder.text2.setText(day.toUpperCase(Locale.GERMAN));
        }

        @Override
        public void updateItemView(View itemView, Termin itemData) {
            ItemViewHolder viewHolder;
            if (itemView.getTag() == null) {
                viewHolder = new ItemViewHolder();
                viewHolder.timeText = (TextView) itemView.findViewById(R.id.text_time);
                viewHolder.roomText = (TextView) itemView.findViewById(R.id.text_room);
                viewHolder.titleText = (TextView) itemView.findViewById(R.id.text_title);
                viewHolder.labelText = (TextView) itemView.findViewById(R.id.text_label);
                itemView.setTag(viewHolder);
            } else {
                viewHolder = (ItemViewHolder) itemView.getTag();
            }

            Date from = itemData.getDatum();
            Date to = itemData.getEndDate();

            viewHolder.timeText.setText(getString(R.string.calendar_timespan, from, to));
            viewHolder.roomText.setText(itemData.getRaum());
            MapUtils.linkifyRooms(viewHolder.roomText);
            viewHolder.titleText.setText(itemData.getTitleWithType());
            viewHolder.titleText.setEnabled(!itemData.isPast());

            if (itemData.isStorniert()) {
                viewHolder.labelText.setText(mLabelCancelled);
                viewHolder.labelText.setBackgroundResource(R.color.date_canceled);
                viewHolder.labelText.setVisibility(View.VISIBLE);
            } else if (itemData.isNow()) {
                viewHolder.labelText.setText(mLabelNow);
                viewHolder.labelText.setBackgroundResource(R.color.date_running);
                viewHolder.labelText.setVisibility(View.VISIBLE);
            } else {
                viewHolder.labelText.setVisibility(View.GONE);
            }
        }

    }

    private CalendarSLA mCalendarAdapter;
    private CalendarModel mCalendarModel;
    private boolean mLoading = false;
    private boolean mDashboardMode = false;

    private View mFooterView;
    private View mProgressView;

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

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
        View v = inflater.inflate(R.layout.calendar_fragment, container, false);
        mProgressView = v.findViewById(R.id.progress);
        mFooterView = inflater.inflate(R.layout.list_footer_loadingindicator, null);

        ListView listView = (ListView) v.findViewById(android.R.id.list);
        listView.addFooterView(mFooterView, null, false);
        listView.setOnScrollListener(this);

        /* change reference to inner progress indicator since hiding the footer 
           * container itself doesn't resize the layout (black box stays visible) */
        mFooterView = mFooterView.findViewById(R.id.list_progress);

        return v;
    }

    @Override
    public void onViewCreated(View view, Bundle savedInstanceState) {
        super.onViewCreated(view, savedInstanceState);
    }

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

        if (getActivity() instanceof DashboardActivity) {
            mDashboardMode = true;
        }

        if (mCalendarModel == null)
            refresh();
        else if (!mCalendarModel.isMoreDatesToLoad())
            mFooterView.setVisibility(View.GONE);
    }

    @Override
    public void progressNotificationOn() {
        mProgressView.setVisibility(View.VISIBLE);
    }

    @Override
    public void progressNotificationOff() {
        mProgressView.setVisibility(View.GONE);
    }

    @Override
    public void refresh() {
        refresh(false);
    }

    @Override
    public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) {
        /* don't do anything if the list is empty - there can't be nothing to load (yet) */
        if (totalItemCount == 0)
            return;

        int lastInScreen = firstVisibleItem + visibleItemCount;
        if ((lastInScreen == totalItemCount) && mLoading == false && mCalendarModel != null
                && mCalendarModel.isMoreDatesToLoad() && mFooterView.getVisibility() == View.VISIBLE) {
            refresh(true);
        }
    }

    @Override
    public void onScrollStateChanged(AbsListView view, int scrollState) {
    }

    public void refresh(final boolean more) {
        mLoading = true;
        new AsyncTask() {

            protected void onPreExecute() {
                if (!more) {
                    progressNotificationOn();
                    mCalendarAdapter = null;
                }
            };

            @Override
            protected void doInBackground() throws Exception {
                if (mDashboardMode) {
                    mCalendarModel = ModelService.getDashboardModel(getActivity());
                } else {
                    mCalendarModel = ModelService.getCalendarModel(getActivity(), more ? mCalendarModel : null);
                }
            }

            protected void onPostExecute() {
                mLoading = false;
                if (!more)
                    progressNotificationOff();
            };

            @Override
            protected void onException(Exception e) {
                if (isAdded()) {
                    UIUtils.processActivityRefreshException(e, getActivity());
                }
                Analytics.onError(Analytics.ERROR_GENERIC + "/" + Analytics.ACTIVITY_CALENDAR, e);
            }

            @Override
            protected void onSuccess() {
                if (!isAdded()) {
                    /* If the parent activity is already closed the fragment isn't added any more,
                     * and further processing is not only pointless overhead, but results in a NPE. */
                    // http://stackoverflow.com/questions/8289345/fragments-being-replaced-while-asynctask-is-executed-nullpointerexception-on-g#comment10547325_8290847
                    return;
                }
                if (!mCalendarModel.isMoreDatesToLoad()) {
                    mFooterView.setVisibility(View.GONE);
                }
                initListAdapter();
            }

        }.execute();
    }

    private void initListAdapter() {
        if (mCalendarAdapter == null) {
            mCalendarAdapter = new CalendarSLA(getActivity(), mCalendarModel.getDates());
            setListAdapter(mCalendarAdapter);
        } else {
            mCalendarAdapter.notifyDataSetChanged();
        }
    }
}