it.rainbowbreeze.keepmoving.ui.TimetableFragment.java Source code

Java tutorial

Introduction

Here is the source code for it.rainbowbreeze.keepmoving.ui.TimetableFragment.java

Source

package it.rainbowbreeze.keepmoving.ui;

import android.app.Activity;
import android.os.Bundle;
import android.support.v4.app.Fragment;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.AbsListView;
import android.widget.AdapterView;
import android.widget.Button;
import android.widget.TextView;

import javax.inject.Inject;

import it.rainbowbreeze.keepmoving.R;
import it.rainbowbreeze.keepmoving.common.ILogManager;
import it.rainbowbreeze.keepmoving.common.Utils;
import it.rainbowbreeze.keepmoving.domain.Route;
import it.rainbowbreeze.keepmoving.logic.PositionManager;

/**
 * This file is part of KeepMoving. KeepMoving 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, version 2.
 * <p/>
 * This program 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.
 * <p/>
 * You should have received a copy of the GNU General Public License along with
 * this program; if not, write to the Free Software Foundation, Inc., 51
 * Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
 * <p/>
 * Copyright Alfredo Morresi
 * <p/>
 * Created by Alfredo "Rainbowbreeze" Morresi on 02/07/14.
 */

/**
 * A fragment representing a list of Items.
 * <p />
 * Large screen devices (such as tablets) are supported by replacing the ListView
 * with a GridView.
 * <p />
 * Activities containing this fragment MUST implement the {@link it.rainbowbreeze.keepmoving.ui.TimetableFragment.OnFragmentInteractionListener}
 * interface.
 */
public class TimetableFragment extends Fragment implements AbsListView.OnItemClickListener {
    private static final String LOG_TAG = TimetableFragment.class.getSimpleName();
    // Position of the fragment in the Page adapter
    private static final String ARG_POSITION = "FragmentPosition";

    @Inject
    protected ILogManager mLogManager;

    private OnFragmentInteractionListener mListener;
    private int mFragmentPos;
    // The fragment's ListView/GridView.
    private AbsListView mListView;
    // The Adapter which will be used to populate the ListView/GridView with Views.
    private StepsArrayAdapter mAdapter;
    private TextView mLblRemainingTime;
    private TextView mLblArrivalTime;
    private boolean mRegisteredReceiver;
    private boolean mFirstDrawDone;

    // TODO making the injection mechanism working
    public static TimetableFragment newInstance(int fragmentPos, ILogManager logManager,
            PositionManager positionManager) {
        TimetableFragment fragment = new TimetableFragment();
        Bundle args = new Bundle();
        args.putInt(ARG_POSITION, fragmentPos);
        fragment.setArguments(args);
        fragment.mLogManager = logManager;
        logManager.d(LOG_TAG, "Created fragment for pos " + fragmentPos);
        return fragment;
    }

    /**
     * Mandatory empty constructor for the fragment manager to instantiate the
     * fragment (e.g. upon screen orientation changes).
     */
    public TimetableFragment() {
    }

    @Override
    public void onAttach(Activity activity) {
        super.onAttach(activity);
        // Here mFragmentPos is still not available
        mLogManager.d(LOG_TAG, "onAttach to activity " + activity);
        try {
            mListener = (OnFragmentInteractionListener) activity;
        } catch (ClassCastException e) {
            throw new ClassCastException(activity.toString() + " must implement OnFragmentInteractionListener");
        }
    }

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        if (getArguments() != null) {
            mFragmentPos = getArguments().getInt(ARG_POSITION);
        }
        mFirstDrawDone = false;
    }

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
        mLogManager.d(getLogTag(), "OnCreateView fragment views");

        View view = inflater.inflate(R.layout.fra_timetable, container, false);

        // Sets the ListView and the adapter
        mAdapter = new StepsArrayAdapter(getActivity());
        mListView = (AbsListView) view.findViewById(R.id.timetable_lstSteps);
        mListView.setAdapter(mAdapter);
        mListView.setOnItemClickListener(this);

        mLblArrivalTime = (TextView) view.findViewById(R.id.timetable_lblArrivalTime);
        mLblRemainingTime = (TextView) view.findViewById(R.id.timetable_lblRemainingTime);

        ((Button) view.findViewById(R.id.timetable_btnSendToWatch)).setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                sendToWear();
            }
        });

        // The activity calls the method to update the fragment, but sometimes fragment is still
        //  not attached
        if (!mFirstDrawDone) {
            mLogManager.d(getLogTag(), "Forcing a first draw of the fragment");
            updateUIViews(true);
        }
        return view;
    }

    /**
     * Send to Android wear
     */
    private void sendToWear() {
        mListener.sendToWear(mFragmentPos);
    }

    @Override
    public void onDestroyView() {
        super.onDestroyView();
        mLogManager.d(getLogTag(), "OnDestroyView fragment");
        mFirstDrawDone = false;
    }

    @Override
    public void onDetach() {
        super.onDetach();
        mLogManager.d(getLogTag(), "Detaching from activity " + mListener);
        mListener = null;
    }

    @Override
    public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
        if (null != mListener) {
            // Notify the active callbacks interface (the activity, if the
            // fragment is attached to one) that an item has been selected.
            //mListener.onFragmentInteraction(DummyContent.ITEMS.get(position).id);
        }
    }

    /**
     * Updates all the UI element that show some sort of time counter
     */
    public void updateUIViews(boolean fullUpdate) {
        if (fullUpdate) {
            mLogManager.d(getLogTag(), "Updating all the views");
            Route route = getRoute();
            mAdapter.setNotifyOnChange(false);
            mAdapter.clear();
            // A route always has steps, otherwise what kind of route is?
            mAdapter.addAll(route.getSteps()); //addAll automatically calls notifyDataSetChanged
            mAdapter.notifyDataSetChanged();

            mLblArrivalTime.setText(Utils.getTimeFromTimestamp(route.getArrivalTimestamp()));
        }

        mLogManager.d(getLogTag(), "Refreshing time UI elements");
        Route route = getRoute();
        int remainingTime = Utils.getRemainingMinutesToRoute(route);
        mLblRemainingTime.setText(Utils.getTimeFromTimestamp(remainingTime));
        mFirstDrawDone = true;
    }

    /**
     * Returns route data, asking them to the container activity
     * @return
     */
    private Route getRoute() {
        Route route = null;
        if (null != mListener) {
            // It asks the data to parent activity. Also acceding directly to the model may be a
            //  feasible option. I prefer to see Fragment as strictly correlated to parent
            //  activity
            route = mListener.getRouteForPosition(mFragmentPos);
        } else {
            mLogManager.w(getLogTag(), "It seems that the listener activity is not attached...");
        }
        if (null == route) {
            throw new IllegalArgumentException("Route cannot be null");
        }
        return route;
    }

    private String getLogTag() {
        return String.format("%s-pos%d", LOG_TAG, mFragmentPos);
    }

    /**
    * This interface must be implemented by activities that contain this
    * fragment to allow an interaction in this fragment to be communicated
    * to the activity and potentially other fragments contained in that
    * activity.
    * <p>
    * See the Android Training lesson <a href=
    * "http://developer.android.com/training/basics/fragments/communicating.html"
    * >Communicating with Other Fragments</a> for more information.
    */
    public interface OnFragmentInteractionListener {
        public Route getRouteForPosition(int pos);

        void sendToWear(int fragmentPos);
    }

}