li.barter.fragments.AbstractBarterLiFragment.java Source code

Java tutorial

Introduction

Here is the source code for li.barter.fragments.AbstractBarterLiFragment.java

Source

/*
 * Copyright (C) 2014 barter.li
 *
 * 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 li.barter.fragments;

import android.app.Activity;
import android.app.AlertDialog;
import android.content.Context;
import android.content.DialogInterface;
import android.graphics.Typeface;
import android.location.Criteria;
import android.location.LocationManager;
import android.os.Bundle;
import android.support.v4.app.Fragment;
import android.text.TextUtils;
import android.view.View;
import android.view.ViewGroup;
import android.view.inputmethod.InputMethodManager;

import com.android.volley.Request;
import com.android.volley.Request.Method;
import com.android.volley.RequestQueue;

import org.json.JSONException;
import org.json.JSONObject;

import java.util.concurrent.atomic.AtomicInteger;

import de.keyboardsurfer.android.widget.crouton.Crouton;
import li.barter.R;
import li.barter.activities.AbstractBarterLiActivity;
import li.barter.activities.AbstractBarterLiActivity.AlertStyle;
import li.barter.analytics.GoogleAnalyticsManager;
import li.barter.data.DBInterface;
import li.barter.fragments.dialogs.AddUserInfoDialogFragment;
import li.barter.http.BlMultiPartRequest;
import li.barter.http.HttpConstants;
import li.barter.http.HttpConstants.ApiEndpoints;
import li.barter.http.HttpConstants.RequestId;
import li.barter.http.IBlRequestContract;
import li.barter.http.IVolleyHelper;
import li.barter.http.ResponseInfo;
import li.barter.http.VolleyCallbacks;
import li.barter.http.VolleyCallbacks.IHttpCallbacks;
import li.barter.utils.AppConstants.FragmentTags;
import li.barter.utils.AppConstants.Keys;
import li.barter.utils.AppConstants.UserInfo;
import li.barter.utils.Utils;
import li.barter.widgets.TypefaceCache;

/**
 * Base fragment class to encapsulate common functionality. Call the init() method in the
 * onCreateView() of your fragments
 *
 * @author Vinay S Shenoy
 */
public abstract class AbstractBarterLiFragment extends Fragment implements IHttpCallbacks {

    private static final String TAG = "AbstractBarterLiFragment";

    /**
     * Flag that indicates that this fragment is attached to an Activity
     */
    private boolean mIsAttached;

    /**
     * Stores the id for the container view
     */
    protected int mContainerViewId;

    /**
     * {@link VolleyCallbacks} for encapsulating the Volley response flow
     */
    protected VolleyCallbacks mVolleyCallbacks;

    private AtomicInteger mRequestCounter;

    /**
     * Whether a screen hit should be reported to analytics
     */
    private boolean mShouldReportScreenHit;

    public boolean mRefreshBooks = false;

    /**
     * {@link AddUserInfoDialogFragment} for
     */
    private AddUserInfoDialogFragment mAddUserInfoDialogFragment;

    @Override
    public void onAttach(final Activity activity) {
        super.onAttach(activity);
        mIsAttached = true;
        final RequestQueue requestQueue = ((IVolleyHelper) activity.getApplication()).getRequestQueue();
        mVolleyCallbacks = new VolleyCallbacks(requestQueue, this);
        mRequestCounter = new AtomicInteger(0);
    }

    @Override
    public void onSaveInstanceState(Bundle outState) {
        super.onSaveInstanceState(outState);
        outState.putLong(Keys.LAST_SCREEN_TIME, Utils.getCurrentEpochTime());
    }

    /**
     * Call this method in the onCreateView() of any subclasses
     *
     * @param container          The container passed into onCreateView()
     * @param savedInstanceState The Instance state bundle passed into the onCreateView() method
     */
    protected void init(final ViewGroup container, final Bundle savedInstanceState) {
        mContainerViewId = container.getId();
        long lastScreenTime = 0l;
        if (savedInstanceState != null) {
            mAddUserInfoDialogFragment = (AddUserInfoDialogFragment) getFragmentManager()
                    .findFragmentByTag(FragmentTags.DIALOG_ADD_NAME);
            lastScreenTime = savedInstanceState.getLong(Keys.LAST_SCREEN_TIME);
        }

        if (Utils.shouldReportScreenHit(lastScreenTime)) {
            mShouldReportScreenHit = true;
        } else {
            mShouldReportScreenHit = false;
        }
    }

    @Override
    public void onResume() {
        super.onResume();
        checkAndReportScreenHit();
    }

    /**
     * Reports a screen hit
     */
    private void checkAndReportScreenHit() {
        if (mShouldReportScreenHit) {
            final String analyticsScreenName = getAnalyticsScreenName();

            if (!TextUtils.isEmpty(analyticsScreenName)) {
                GoogleAnalyticsManager.getInstance().sendScreenHit(analyticsScreenName);
            }
        }

    }

    /**
     * Gets the screen name for reporting to google analytics. Send empty string, or
     * <code>null</code> if you don't want the Fragment tracked
     */
    protected abstract String getAnalyticsScreenName();

    /**
     * Helper method to load fragments into layout
     *
     * @param containerResId The container resource Id in the content view into which to load the
     *                       fragment
     * @param fragment       The fragment to load
     * @param tag            The fragment tag
     * @param addToBackStack Whether the transaction should be addded to the backstack
     * @param backStackTag   The tag used for the backstack tag
     */
    public void loadFragment(final int containerResId, final AbstractBarterLiFragment fragment, final String tag,
            final boolean addToBackStack, final String backStackTag) {

        if (mIsAttached) {
            ((AbstractBarterLiActivity) getActivity()).loadFragment(containerResId, fragment, tag, addToBackStack,
                    backStackTag);
        }

    }

    /**
     * Helper method to load fragments into layout
     *
     * @param containerResId The container resource Id in the content view into which to load the
     *                       fragment
     * @param fragment       The fragment to load
     * @param tag            The fragment tag
     * @param addToBackStack Whether the transaction should be addded to the backstack
     * @param backStackTag   The tag used for the backstack tag
     * @param customAnimate  Whether to provide a custom animation for the Fragment. If
     *                       <code>true</code>, the Fragment also needs to be annotated with a
     *                       {@linkplain li.barter.fragments.FragmentTransition} annotation which
     *                       describes the transition to perform. If <code>false</code>, will use
     *                       default fragment transition
     */
    public void loadFragment(final int containerResId, final AbstractBarterLiFragment fragment, final String tag,
            final boolean addToBackStack, final String backStackTag, final boolean customAnimate) {

        if (mIsAttached) {
            ((AbstractBarterLiActivity) getActivity()).loadFragment(containerResId, fragment, tag, addToBackStack,
                    backStackTag, customAnimate);
        }

    }

    @Override
    public void onDestroyView() {
        super.onDestroyView();
        mContainerViewId = 0;
    }

    @Override
    public void onDetach() {
        super.onDetach();
        mIsAttached = false;
        mVolleyCallbacks = null;
        mRequestCounter = null;
    }

    /**
     * Is the device connected to a network or not.
     *
     * @return <code>true</code> if connected, <code>false</code> otherwise
     */
    public boolean isConnectedToInternet() {
        return ((AbstractBarterLiActivity) getActivity()).isConnectedToInternet();
    }

    public void setActionBarDisplayOptions(final int displayOptions) {
        if (mIsAttached) {

            ((AbstractBarterLiActivity) getActivity()).setActionBarDisplayOptions(displayOptions);
        }
    }

    @Override
    public void onStop() {
        super.onStop();
        Crouton.clearCroutonsForActivity(getActivity());
        mVolleyCallbacks.cancelAll(getTaskTag());
        DBInterface.cancelAll(getTaskTag());
        getActivity().setProgressBarIndeterminateVisibility(false);
    }

    /**
     * Add a request on the network queue
     *
     * @param request              The {@link Request} to add
     * @param showErrorOnNoNetwork Whether an error toast should be displayed on no internet
     *                             connection
     * @param errorMsgResId        String resource Id for error message to show if no internet
     *                             connection, 0 for a default error message
     */
    protected void addRequestToQueue(final Request<?> request, final boolean showErrorOnNoNetwork,
            final int errorMsgResId, boolean addHeader) {

        if (mIsAttached) {
            request.setTag(getTaskTag());
            if (isConnectedToInternet()) {
                mRequestCounter.incrementAndGet();
                getActivity().setProgressBarIndeterminateVisibility(true);
                mVolleyCallbacks.queue(request, addHeader);
            } else if (showErrorOnNoNetwork) {
                showCrouton(errorMsgResId != 0 ? errorMsgResId : R.string.no_network_connection, AlertStyle.ERROR);
            }
        }
    }

    /**
     * A Tag to add to all async tasks. This must be unique for all Fragments types
     *
     * @return An Object that's the tag for this fragment
     */
    protected abstract Object getTaskTag();

    /**
     * Display an alert, with a string message
     *
     * @param message The message to display
     * @param style   The {@link AlertStyle} of message to display
     */
    public void showCrouton(final String message, final AlertStyle style) {
        if (mIsAttached) {
            ((AbstractBarterLiActivity) getActivity()).showCrouton(message, style);
        }
    }

    /**
     * Display an alert, with a string message
     *
     * @param messageResId The message to display
     * @param style        The {@link AlertStyle} of message to display
     */
    public void showCrouton(final int messageResId, final AlertStyle style) {
        if (mIsAttached) {
            showCrouton(getString(messageResId), style);
        }
    }

    /**
     * Display an alert, with a string message infinitely
     *
     * @param messageResId The message to display
     * @param style        The {@link AlertStyle} of message to display
     */
    public void showInfiniteCrouton(final int messageResId, final AlertStyle style) {
        if (mIsAttached) {
            showInfiniteCrouton(getString(messageResId), style);
        }
    }

    public void cancelAllCroutons() {
        if (mIsAttached) {
            ((AbstractBarterLiActivity) getActivity()).cancelAllCroutons();
        }
    }

    /**
     * Display an alert, with a string message infinitely
     *
     * @param message The message to display
     * @param style   The {@link AlertStyle} of message to display
     */
    public void showInfiniteCrouton(final String message, final AlertStyle style) {
        if (mIsAttached) {
            ((AbstractBarterLiActivity) getActivity()).showInfiniteCrouton(message, style);
        }
    }

    /**
     * Whether this Fragment is currently attached to an Activity
     *
     * @return <code>true</code> if attached, <code>false</code> otherwise
     */
    public boolean isAttached() {
        return mIsAttached;
    }

    /**
     * Sets the Action bar title, using the desired {@link Typeface} loaded from {@link
     * TypefaceCache}
     *
     * @param title The title to set for the Action Bar
     */
    public final void setActionBarTitle(final String title) {

        if (mIsAttached) {
            ((AbstractBarterLiActivity) getActivity()).setActionBarTitle(title);
        }
    }

    /**
     * Sets the Action bar title, using the desired {@link Typeface} loaded from {@link
     * TypefaceCache}
     *
     * @param titleResId The title string resource Id to set for the Action Bar
     */
    public final void setActionBarTitle(final int titleResId) {
        setActionBarTitle(getString(titleResId));
    }

    /**
     * Is the user logged in
     */
    protected boolean isLoggedIn() {
        return !TextUtils.isEmpty(UserInfo.INSTANCE.getAuthToken());
    }

    /**
     * Does the user have a first name
     */
    protected boolean hasFirstName() {
        return !TextUtils.isEmpty(UserInfo.INSTANCE.getFirstName());
    }

    /**
     * Show the dialog for the user to add his name, in case it's not already added
     */
    protected void showAddFirstNameDialog() {

        mAddUserInfoDialogFragment = new AddUserInfoDialogFragment();
        mAddUserInfoDialogFragment.show(AlertDialog.THEME_HOLO_LIGHT, 0, R.string.update_info, R.string.submit,
                R.string.cancel, 0, getFragmentManager(), true, FragmentTags.DIALOG_ADD_NAME);
    }

    /**
     * Handles the behaviour for onBackPressed().
     *
     * @return <code>true</code> If the fragment will handle onBackPressed
     */
    public boolean onBackPressed() {

        return false;

    }

    /**
     * Whether the fragment is loaded into a multipane layout
     */
    public boolean isMultipane() {

        if (isAttached()) {
            return ((AbstractBarterLiActivity) getActivity()).isMultipane();
        }

        //Incorrect call if it reaches here
        return false;
    }

    @Override
    public void onPreExecute(final IBlRequestContract request) {
        mRequestCounter.incrementAndGet();
        if (mIsAttached) {
            getActivity().setProgressBarIndeterminateVisibility(true);
        }
    }

    @Override
    public void onPostExecute(final IBlRequestContract request) {
        assert (mRequestCounter != null);
        if (mIsAttached && (mRequestCounter.decrementAndGet() == 0)) {
            getActivity().setProgressBarIndeterminateVisibility(false);
        }
    }

    @Override
    public abstract void onSuccess(int requestId, IBlRequestContract request, ResponseInfo response);

    @Override
    public abstract void onBadRequestError(int requestId, IBlRequestContract request, int errorCode,
            String errorMessage, Bundle errorResponseBundle);

    @Override
    public void onAuthError(final int requestId, final IBlRequestContract request) {
        //TODO Show Login Fragment and ask user to login again
    }

    @Override
    public void onOtherError(final int requestId, final IBlRequestContract request, final int errorCode) {
        //TODO Show generic network error message
    }

    /**
     * Whether this fragment will handle the particular dialog click or not
     *
     * @param dialog The dialog that was interacted with
     * @return <code>true</code> If the fragment will handle it, <code>false</code> otherwise
     */
    public boolean willHandleDialog(final DialogInterface dialog) {

        if ((mAddUserInfoDialogFragment != null) && mAddUserInfoDialogFragment.getDialog().equals(dialog)) {
            return true;
        }
        return false;
    }

    /**
     * Handle the click for the dialog. The fragment will receive this call, only if {@link
     * #willHandleDialog(DialogInterface)} returns <code>true</code>
     *
     * @param dialog The dialog that was interacted with
     * @param which  The button that was clicked
     */
    public void onDialogClick(final DialogInterface dialog, final int which) {

        if ((mAddUserInfoDialogFragment != null) && mAddUserInfoDialogFragment.getDialog().equals(dialog)) {

            if (which == DialogInterface.BUTTON_POSITIVE) {
                final String firstName = mAddUserInfoDialogFragment.getFirstName();
                final String lastName = mAddUserInfoDialogFragment.getLastName();

                if (!TextUtils.isEmpty(firstName)) {
                    updateUserInfo(firstName, lastName);
                }
            }
        }
    }

    /**
     * Updates the user info with just the first name and last name
     *
     * @param firstName The user's first name
     * @param lastName  The user's last name
     */
    public void updateUserInfo(final String firstName, final String lastName) {

        final String url = HttpConstants.getApiBaseUrl() + ApiEndpoints.UPDATE_USER_INFO;

        final JSONObject mUserProfileObject = new JSONObject();
        final JSONObject mUserProfileMasterObject = new JSONObject();
        try {
            mUserProfileObject.put(HttpConstants.FIRST_NAME, firstName);
            mUserProfileObject.put(HttpConstants.LAST_NAME, lastName);
            mUserProfileMasterObject.put(HttpConstants.USER, mUserProfileObject);

            final BlMultiPartRequest updateUserProfileRequest = new BlMultiPartRequest(Method.PUT, url, null,
                    mVolleyCallbacks);

            updateUserProfileRequest.addMultipartParam(HttpConstants.USER, "application/json",
                    mUserProfileMasterObject.toString());

            updateUserProfileRequest.setRequestId(RequestId.SAVE_USER_PROFILE);
            addRequestToQueue(updateUserProfileRequest, true, 0, true);

        } catch (final JSONException e) {
            e.printStackTrace();
        }
    }

    /**
     * Hides the keyboard
     *
     * @param view the view from which keyboard was open
     */

    public void hideKeyBoard(View view) {
        InputMethodManager imm = (InputMethodManager) getActivity().getSystemService(Context.INPUT_METHOD_SERVICE);
        imm.hideSoftInputFromWindow(view.getWindowToken(), 0);
    }

    public boolean isLocationServiceEnabled() {
        LocationManager lm = (LocationManager) getActivity().getSystemService(Context.LOCATION_SERVICE);
        Criteria criteria = new Criteria();

        String provider = lm.getBestProvider(criteria, true);
        return ((provider != null) && !LocationManager.PASSIVE_PROVIDER.equals(provider));
    }

}