net.naonedbus.fragment.impl.HorairesFragment.java Source code

Java tutorial

Introduction

Here is the source code for net.naonedbus.fragment.impl.HorairesFragment.java

Source

/**
 * Copyright (C) 2013 Romain Guefveneu.
 *   
 *  This file is part of naonedbus.
 *   
 *  Naonedbus 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.
 *  
 *  Naonedbus 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 this program.  If not, see <http://www.gnu.org/licenses/>.
 */
package net.naonedbus.fragment.impl;

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.atomic.AtomicBoolean;

import net.naonedbus.BuildConfig;
import net.naonedbus.R;
import net.naonedbus.activity.impl.AddEventActivity;
import net.naonedbus.activity.impl.CommentaireActivity;
import net.naonedbus.activity.impl.MapActivity;
import net.naonedbus.activity.impl.PlanActivity;
import net.naonedbus.activity.map.overlay.TypeOverlayItem;
import net.naonedbus.bean.Arret;
import net.naonedbus.bean.Favori;
import net.naonedbus.bean.Ligne;
import net.naonedbus.bean.Sens;
import net.naonedbus.bean.async.AsyncResult;
import net.naonedbus.bean.horaire.EmptyHoraire;
import net.naonedbus.bean.horaire.Horaire;
import net.naonedbus.fragment.CustomInfiniteListFragement;
import net.naonedbus.intent.ParamIntent;
import net.naonedbus.manager.impl.ArretManager;
import net.naonedbus.manager.impl.FavoriManager;
import net.naonedbus.manager.impl.HoraireManager;
import net.naonedbus.manager.impl.SensManager;
import net.naonedbus.utils.FormatUtils;
import net.naonedbus.widget.adapter.impl.HoraireArrayAdapter;
import net.naonedbus.widget.indexer.impl.HoraireIndexer;

import org.joda.time.DateMidnight;
import org.joda.time.DateTime;
import org.joda.time.Minutes;

import android.annotation.SuppressLint;
import android.annotation.TargetApi;
import android.app.Activity;
import android.app.DatePickerDialog;
import android.content.ActivityNotFoundException;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.os.Build;
import android.os.Bundle;
import android.provider.CalendarContract;
import android.provider.CalendarContract.Events;
import android.util.Log;
import android.view.View;
import android.widget.AdapterView;
import android.widget.AdapterView.OnItemClickListener;
import android.widget.DatePicker;
import android.widget.ListAdapter;
import android.widget.Toast;

import com.actionbarsherlock.view.Menu;
import com.actionbarsherlock.view.MenuInflater;
import com.actionbarsherlock.view.MenuItem;

public class HorairesFragment extends CustomInfiniteListFragement implements OnItemClickListener {

    private static final String LOG_TAG = "HorairesFragment";
    private static final boolean DBG = BuildConfig.DEBUG;

    public static final String PARAM_LIGNE = "ligne";
    public static final String PARAM_SENS = "sens";
    public static final String PARAM_ARRET = "arret";

    public static interface OnSensChangeListener {
        void onSensChange(Sens newSens);
    }

    private final static IntentFilter intentFilter;
    static {
        intentFilter = new IntentFilter();
        intentFilter.addAction(Intent.ACTION_TIME_TICK);
        intentFilter.addAction(Intent.ACTION_TIMEZONE_CHANGED);
        intentFilter.addAction(Intent.ACTION_TIME_CHANGED);
    }

    /**
     * Reoit les intents de notre intentFilter
     */
    private final BroadcastReceiver intentReceiver = new BroadcastReceiver() {
        @Override
        public void onReceive(final Context context, final Intent intent) {
            updateItemsTime();
        }
    };

    private final HoraireManager mHoraireManager;
    private final ArretManager mArretManager;
    private final SensManager mSensManager;
    private final FavoriManager mFavoriManager;
    private OnSensChangeListener mOnSensChangeListener;
    private HoraireArrayAdapter mAdapter;
    private final List<Horaire> mHoraires;

    private Ligne mLigne;
    private Sens mSens;
    private Arret mArret;
    private boolean mIsFirstLoad = true;
    private final AtomicBoolean mIsLoading = new AtomicBoolean(false);

    private DateMidnight mLastDayLoaded;
    private DateMidnight mDayToLoad;
    private DateTime mLastDateTimeLoaded;

    private final DatePickerDialog.OnDateSetListener mDateSetListener = new DatePickerDialog.OnDateSetListener() {
        @Override
        public void onDateSet(final DatePicker view, final int year, final int monthOfYear, final int dayOfMonth) {
            changeDate(new DateMidnight(year, monthOfYear + 1, dayOfMonth));
        }
    };

    public HorairesFragment() {
        super(R.layout.fragment_listview_section);
        mHoraireManager = HoraireManager.getInstance();
        mFavoriManager = FavoriManager.getInstance();
        mArretManager = ArretManager.getInstance();
        mSensManager = SensManager.getInstance();

        mHoraires = new ArrayList<Horaire>();
        mLastDayLoaded = new DateMidnight();
        mDayToLoad = new DateMidnight();
    }

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

        final Activity activity = getActivity();
        if (activity instanceof OnSensChangeListener) {
            setOnChangeSensListener((OnSensChangeListener) activity);
        } else {
            throw new IllegalStateException();
        }

        mLigne = getArguments().getParcelable(PARAM_LIGNE);
        mSens = getArguments().getParcelable(PARAM_SENS);
        mArret = getArguments().getParcelable(PARAM_ARRET);

        setHasOptionsMenu(true);
    }

    @Override
    public void onActivityCreated(final Bundle savedInstanceState) {
        super.onActivityCreated(savedInstanceState);
        mAdapter = new HoraireArrayAdapter(getActivity(), mHoraires);
        mAdapter.setIndexer(new HoraireIndexer());

        getListView().setOnItemClickListener(this);

        loadContent();
    }

    @Override
    public void onStart() {
        getActivity().registerReceiver(intentReceiver, intentFilter);
        super.onStart();
    }

    @Override
    public void onStop() {
        getActivity().unregisterReceiver(intentReceiver);
        super.onDestroy();
    }

    @TargetApi(Build.VERSION_CODES.ICE_CREAM_SANDWICH)
    @Override
    public void onItemClick(final AdapterView<?> parent, final View view, final int position, final long id) {
        final Horaire horaire = (Horaire) getListView().getItemAtPosition(position);

        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) {
            final String title = mArret.getNomArret();
            final String description = FormatUtils.formatTitle(
                    getString(R.string.dialog_title_menu_lignes, mLigne.getCode()), mArret.getNomArret(),
                    mSens.text);

            final Intent calIntent = new Intent(Intent.ACTION_INSERT);
            calIntent.setType("vnd.android.cursor.item/event");
            calIntent.putExtra(Events.TITLE, title);
            calIntent.putExtra(Events.DESCRIPTION, description);
            calIntent.putExtra(CalendarContract.EXTRA_EVENT_ALL_DAY, false);
            calIntent.putExtra(CalendarContract.EXTRA_EVENT_BEGIN_TIME, horaire.getHoraire().getMillis());
            calIntent.putExtra(CalendarContract.EXTRA_EVENT_END_TIME, horaire.getHoraire().getMillis());

            try {
                startActivity(calIntent);
                getActivity().overridePendingTransition(R.anim.slide_in_from_right, R.anim.half_fade_out);
            } catch (ActivityNotFoundException e) {
                addEventFallback(horaire);
            }

        } else {
            addEventFallback(horaire);
        }

    }

    private void addEventFallback(Horaire horaire) {
        final ParamIntent intent = new ParamIntent(getActivity(), AddEventActivity.class);
        intent.putExtra(AddEventActivity.PARAM_LIGNE, mLigne);
        intent.putExtra(AddEventActivity.PARAM_SENS, mSens);
        intent.putExtra(AddEventActivity.PARAM_ARRET, mArret);
        intent.putExtra(AddEventActivity.PARAM_TIMESTAMP, horaire.getHoraire().getMillis());

        startActivity(intent);
        getActivity().overridePendingTransition(R.anim.slide_in_from_right, R.anim.half_fade_out);
    }

    @Override
    protected void onLoadMoreItems() {
        if (mLastDayLoaded != null) {
            loadHoraires(mLastDayLoaded.plusDays(1));
        }
    }

    private void loadHoraires(final DateMidnight date) {
        if (mIsLoading.get() == false) {
            if (DBG)
                Log.d(LOG_TAG, "loadHoraires " + date.toString() + "\t" + mIsLoading.get());

            mDayToLoad = date;
            refreshContent();
        }
    }

    @Override
    public void onCreateOptionsMenu(final Menu menu, final MenuInflater inflater) {
        inflater.inflate(R.menu.fragment_horaires, menu);
        final MenuItem menuFavori = menu.findItem(R.id.menu_favori);

        final int icon = isFavori() ? R.drawable.ic_star : R.drawable.ic_star_outline;
        menuFavori.setIcon(icon);
        super.onCreateOptionsMenu(menu, inflater);
    }

    @Override
    public void onPrepareOptionsMenu(final Menu menu) {
        final MenuItem menuFavori = menu.findItem(R.id.menu_favori);

        final int icon = isFavori() ? R.drawable.ic_star : R.drawable.ic_star_outline;
        menuFavori.setIcon(icon);
        super.onPrepareOptionsMenu(menu);
    }

    @Override
    public boolean onOptionsItemSelected(final MenuItem item) {
        switch (item.getItemId()) {
        case R.id.menu_favori:
            onStarClick();
            break;
        case R.id.menu_place:
            showArretPlan();
            break;
        case R.id.menu_date:
            changeDate();
            break;
        case R.id.menu_date_maintenant:
            changeDateToNow();
            break;
        case R.id.menu_comment:
            menuComment();
            break;
        case R.id.menu_show_plan:
            menuShowPlan();
            break;
        case R.id.menu_sens:
            menuChangeSens();
            break;
        default:
            break;
        }
        return false;
    }

    private boolean isFavori() {
        final Favori item = mFavoriManager.getSingle(getActivity().getContentResolver(), mArret.getId());
        return (item != null);
    }

    @SuppressLint("NewApi")
    private void onStarClick() {
        if (isFavori()) {
            removeFromFavoris();
            Toast.makeText(getActivity(), R.string.toast_favori_retire, Toast.LENGTH_SHORT).show();
        } else {
            addToFavoris();
            Toast.makeText(getActivity(), R.string.toast_favori_ajout, Toast.LENGTH_SHORT).show();
        }

        getSherlockActivity().invalidateOptionsMenu();
    }

    private void changeDate() {
        final DatePickerDialog dateDialog = new DatePickerDialog(getActivity(), mDateSetListener,
                mLastDayLoaded.getYear(), mLastDayLoaded.getMonthOfYear() - 1, mLastDayLoaded.getDayOfMonth());
        dateDialog.show();
    }

    private void changeDateToNow() {
        changeDate(new DateMidnight());
    }

    private void addToFavoris() {
        mFavoriManager.addFavori(getActivity().getContentResolver(), mArret);
    }

    private void removeFromFavoris() {
        mFavoriManager.removeFavori(getActivity().getContentResolver(), mArret.getId());
    }

    protected void showArretPlan() {
        final Intent intent = new Intent(getActivity(), MapActivity.class);
        intent.putExtra(MapFragment.PARAM_ITEM_ID, mArret.getIdStation());
        intent.putExtra(MapFragment.PARAM_ITEM_TYPE, TypeOverlayItem.TYPE_STATION.getId());
        startActivity(intent);
    }

    private void menuComment() {
        final Intent intent = new Intent(getActivity(), CommentaireActivity.class);
        intent.putExtra(CommentaireActivity.PARAM_LIGNE, mLigne);
        intent.putExtra(CommentaireActivity.PARAM_SENS, mSens);
        intent.putExtra(CommentaireActivity.PARAM_ARRET, mArret);
        startActivity(intent);
    }

    private void menuShowPlan() {
        final Intent intent = new Intent(getActivity(), PlanActivity.class);
        intent.putExtra(PlanActivity.PARAM_CODE_LIGNE, mLigne.getCode());
        startActivity(intent);
    }

    @SuppressLint("NewApi")
    private void menuChangeSens() {
        Sens autreSens = null;

        // Inverser le sens
        final List<Sens> sens = mSensManager.getAll(getActivity().getContentResolver(), mLigne.getCode());
        for (final Sens sensItem : sens) {
            if (sensItem._id != mSens._id) {
                autreSens = sensItem;
                break;
            }
        }

        if (autreSens != null) {

            // Chercher l'arrt dans le nouveau sens
            final Arret arret = mArretManager.getSingle(getActivity().getContentResolver(), mLigne.getCode(),
                    autreSens.code, mArret.getNormalizedNom());

            if (arret != null) {
                mSens = autreSens;
                mArret = arret;

                mAdapter.clear();
                mAdapter.notifyDataSetChanged();

                changeDateToNow();

                if (mOnSensChangeListener != null) {
                    mOnSensChangeListener.onSensChange(mSens);
                }

                getSherlockActivity().invalidateOptionsMenu();
                return;
            }
        }
        Toast.makeText(getActivity(), getString(R.string.toast_autre_sens), Toast.LENGTH_SHORT).show();
    }

    /**
     * Clear data and reload with a new date
     * 
     * @param date
     */
    public void changeDate(final DateMidnight date) {
        mAdapter.clear();
        mIsFirstLoad = true;
        mLastDateTimeLoaded = null;

        setListAdapter(null);
        loadHoraires(date);
    }

    @Override
    protected AsyncResult<ListAdapter> loadContent(final Context context, final Bundle bundle) {
        mIsLoading.set(true);

        final AsyncResult<ListAdapter> result = new AsyncResult<ListAdapter>();

        if (DBG)
            Log.d(LOG_TAG, "\tloadContent " + mDayToLoad.toString());

        try {

            final List<Horaire> data = mHoraireManager.getSchedules(context.getContentResolver(), mArret,
                    mDayToLoad, mLastDateTimeLoaded);

            if (data.size() == 0) {
                // Si le prcdent chargement  dj charger la totalit du jour
                // actuel (ligne de nuit par exemple) ne pas rafficher le jour.
                if (((mLastDayLoaded == null || mLastDateTimeLoaded == null)
                        || !mLastDayLoaded.equals(mLastDateTimeLoaded.toDateMidnight()))) {
                    mHoraires.add(new EmptyHoraire(R.string.msg_nothing_horaires, mLastDayLoaded));
                }
            } else {
                mHoraires.addAll(data);

                final Horaire lastHoraire = mHoraires.get(mHoraires.size() - 1);
                mLastDateTimeLoaded = lastHoraire.getHoraire();
            }

            mLastDayLoaded = new DateMidnight(mDayToLoad);

            result.setResult(mAdapter);

        } catch (final Exception e) {
            result.setException(e);
        }
        return result;
    }

    @Override
    protected void onPostExecute() {
        super.onPostExecute();

        mAdapter.notifyDataSetChanged();
        updateItemsTime();

        if (DBG)
            Log.d(LOG_TAG, "\tloadContent end " + mLastDayLoaded.toString());
        mIsLoading.set(false);
    }

    /**
     * Mettre  jour les informations de dlais
     */
    private void updateItemsTime() {

        final Long currentTime = new DateTime().minusMinutes(5).withSecondOfMinute(0).withMillisOfSecond(0)
                .getMillis();
        final DateTime now = new DateTime().withSecondOfMinute(0).withMillisOfSecond(0);

        int nextHorairePosition = -1;
        int delay;

        DateTime itemDateTime;
        Horaire horaire;

        for (int i = 0; i < mAdapter.getCount(); i++) {
            horaire = mAdapter.getItem(i);

            if (horaire instanceof EmptyHoraire) {
                continue;
            }

            itemDateTime = new DateTime(horaire.getHoraire()).withSecondOfMinute(0).withMillisOfSecond(0);
            delay = Minutes.minutesBetween(now, itemDateTime).getMinutes();

            if (delay > 0 && delay < 60) {
                horaire.setDelai(getString(R.string.msg_depart_min, delay));
            } else if (delay == 0) {
                horaire.setDelai(getString(R.string.msg_depart_proche));
            } else {
                horaire.setDelai(null);
            }
            horaire.setBeforeNow(itemDateTime.isBefore(now));

            // Recherche le prochain horaire
            if (nextHorairePosition == -1
                    && (horaire.getHoraire().isAfterNow() || horaire.getHoraire().isEqualNow())) {
                nextHorairePosition = mAdapter.getPosition(horaire);
            }
        }

        // Si aucun prochain horaire n'est trouv, slectionner le dernier
        if (nextHorairePosition == -1) {
            nextHorairePosition = mAdapter.getCount() - 1;
        }

        mAdapter.notifyDataSetChanged();

        if (nextHorairePosition != -1 && mIsFirstLoad) {
            getListView().setSelection(nextHorairePosition);
            mIsFirstLoad = false;
        }
    }

    public void setOnChangeSensListener(final OnSensChangeListener l) {
        mOnSensChangeListener = l;
    }

}