com.esri.android.ecologicalmarineunitexplorer.bottomsheet.BottomSheetFragment.java Source code

Java tutorial

Introduction

Here is the source code for com.esri.android.ecologicalmarineunitexplorer.bottomsheet.BottomSheetFragment.java

Source

/* Copyright 2017 Esri
 *
 * 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.
 *
 * For additional information, contact:
 * Environmental Systems Research Institute, Inc.
 * Attn: Contracts Dept
 * 380 New York Street
 * Redlands, California, USA 92373
 *
 * email: contracts@esri.com
 *
 */

package com.esri.android.ecologicalmarineunitexplorer.bottomsheet;

import android.content.Context;
import android.graphics.Color;
import android.graphics.drawable.GradientDrawable;
import android.graphics.drawable.StateListDrawable;
import android.os.Bundle;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.support.v4.app.Fragment;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Button;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.TextView;

import com.esri.android.ecologicalmarineunitexplorer.R;
import com.esri.android.ecologicalmarineunitexplorer.data.EMUObservation;
import com.esri.android.ecologicalmarineunitexplorer.data.WaterColumn;
import com.esri.android.ecologicalmarineunitexplorer.util.EmuHelper;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Set;

/**
 * This the view component that acts as the bottom sheet.  It shows a representation of the water column
 * found at the clicked ocean location.  It also shows information about each of the different
 * EMU layers found in the water column.  This is the View in the MVP pattern and
 * is the concrete implementation of the BottomSheetContract.View interface
 */

public class BottomSheetFragment extends Fragment implements BottomSheetContract.View {

    private LinearLayout mRoot = null;
    private LinearLayout mButtonContainer = null;
    private RecyclerView mEmuObsView = null;
    private Button mSelectedButton = null;
    private WaterColumn mWaterColumn = null;
    private BottomSheetFragment.EMUAdapter mEmuAdapter = null;

    private BottomSheetFragment.OnDetailClickedListener mButtonListener = null;

    public static BottomSheetFragment newInstance() {
        return new BottomSheetFragment();
    }

    // Define the behavior for DETAIL button
    // clicks
    public interface OnDetailClickedListener {
        void onButtonClick(int emuName);
    }

    /**
     *
     * @param savedInstance Bundle
     */
    @Override
    public final void onCreate(@NonNull final Bundle savedInstance) {
        super.onCreate(savedInstance);

        final List<EMUObservation> emuObservations = new ArrayList<>();
        mEmuAdapter = new BottomSheetFragment.EMUAdapter(getContext(), emuObservations);
    }

    /**
     *
     * @param layoutInflater LayoutInflater
     * @param container ViewGroup
     * @param savedInstance Bundle
     * @return
     */
    @Override
    @Nullable
    public View onCreateView(final LayoutInflater layoutInflater, final ViewGroup container,
            final Bundle savedInstance) {
        super.onCreateView(layoutInflater, container, savedInstance);
        mRoot = (LinearLayout) container;
        mButtonContainer = (LinearLayout) mRoot.findViewById(R.id.buttonContainer);

        mEmuObsView = (RecyclerView) mRoot.findViewById(R.id.summary_recycler_view);
        mEmuObsView.setLayoutManager(new LinearLayoutManager(getActivity()));
        mEmuObsView.setAdapter(mEmuAdapter);
        return null;
    }

    /**
     *
     * @param activity Context
     */
    @Override
    public void onAttach(final Context activity) {
        super.onAttach(activity);

        // This makes sure that the container activity has implemented
        // the callback interface. If not, it throws an exception
        try {
            mButtonListener = (BottomSheetFragment.OnDetailClickedListener) activity;
        } catch (final ClassCastException e) {
            throw new ClassCastException(
                    activity + " must implement OnRectangleTappedListener and the OnDetailClickedListener.");
        }
    }

    /**
     * Set the data for this view
     * @param waterColumn - A WaterColumn object containing EMUObservations to display
     */
    @Override
    public void showWaterColumn(final WaterColumn waterColumn) {
        if (waterColumn != null) {
            // Scroll to top of recycler view
            scrollToSummary(0);
            mWaterColumn = waterColumn;
            final Set<EMUObservation> emuSet = waterColumn.getEmuSet();
            final List<EMUObservation> list = new ArrayList<>();
            for (final EMUObservation observation : emuSet) {
                list.add(observation);
            }
            mEmuAdapter.setObservations(list);
            showWaterColumnButtons(waterColumn);
        }
    }

    /**
     * Dynamically add a button for each EMU represented
     * in the water column.
     * @param waterColumn - WaterColumn data object
     */
    private void showWaterColumnButtons(final WaterColumn waterColumn) {
        mButtonContainer.removeAllViews();

        // Each button will be added to layout with a layout_weight
        // relative to the ratio of the EUMObservation to
        // the depth of the water column
        final Set<EMUObservation> emuObservationSet = waterColumn.getEmuSet();
        final float depth = waterColumn.getDepth();
        final TextView tv = (TextView) mRoot.findViewById(R.id.txtBottom);
        tv.setText(getString(R.string.water_column_depth, waterColumn.getDepth()));

        int buttonId = 0;
        for (final EMUObservation observation : emuObservationSet) {
            final float relativeSize = observation.getThickness() / depth * 100;
            final Button button = new Button(getContext());
            final LinearLayout.LayoutParams layoutParams = new LinearLayout.LayoutParams(
                    ViewGroup.LayoutParams.MATCH_PARENT, 0, relativeSize);
            button.setLayoutParams(layoutParams);
            // Enable the button background to be change color based on its state (pressed, selected, or enabled)
            button.setBackground(buildStateList(observation.getEmu().getName()));

            button.setId(buttonId);
            button.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(final View v) {
                    if (mSelectedButton != null) {
                        mSelectedButton.setSelected(false);
                    }
                    button.setSelected(true);
                    mSelectedButton = button;
                    scrollToSummary(v.getId());
                }
            });
            mButtonContainer.addView(button);
            buttonId = buttonId + 1;
        }
    }

    /**
     * Build a stateful drawable for a given EMU
     * @param emuName String representing name
     * @return StateListDrawable responsive to selected, pressed, and enabled states
     */
    private static StateListDrawable buildStateList(final int emuName) {
        final StateListDrawable stateListDrawable = new StateListDrawable();

        final GradientDrawable defaultShape = new GradientDrawable();
        final int color = Color.parseColor(EmuHelper.getColorForEMUCluster(emuName));
        defaultShape.setColor(color);

        final GradientDrawable selectedPressShape = new GradientDrawable();
        selectedPressShape.setColor(color);
        selectedPressShape.setStroke(5, Color.parseColor("#f4f442"));

        stateListDrawable.addState(new int[] { android.R.attr.state_pressed }, selectedPressShape);
        stateListDrawable.addState(new int[] { android.R.attr.state_selected }, selectedPressShape);
        stateListDrawable.addState(new int[] { android.R.attr.state_enabled }, defaultShape);

        return stateListDrawable;
    }

    /**
     * Display general text summary about the water column
     * @param x String representing longitude of clicked location
     * @param y String representing latitude of clicked location
     */
    @Override
    public void showLocationSummary(final String x, final String y) {
        final TextView textView = (TextView) getActivity().findViewById(R.id.txtSummary);
        textView.setText(getString(R.string.water_column_at) + y + ", " + x + getString(R.string.lat_lng)
                + mWaterColumn.getEmuSet().size() + getString(R.string.extending_to) + mWaterColumn.getDepth()
                + getString(R.string.meters_period));

    }

    /**
     * Scroll the recycler view to given index
     * @param position - int representing index of list item
     */
    private void scrollToSummary(final int position) {

        mEmuObsView.scrollToPosition(position);
    }

    /**
     *
     * @param presenter - BottomSheetPresenter
     */
    @Override
    public void setPresenter(final BottomSheetContract.Presenter presenter) {
        // Presenter not used in this fragment
    }

    /**
     * Set selected state of a water column segment
     * @param position
     */
    private void highlightSegment(final int position) {
        final Button button = (Button) mButtonContainer.getChildAt(position);
        if (mSelectedButton != null) {
            mSelectedButton.setSelected(false);
        }
        button.setSelected(true);
        mSelectedButton = button;
    }

    public class EMUAdapter extends RecyclerView.Adapter<BottomSheetFragment.RecycleViewHolder> {

        private List<EMUObservation> emuObservations = Collections.emptyList();

        /**
         *
         * @param context Context
         * @param observations List<EMUObservation> items
         */
        public EMUAdapter(final Context context, final List<EMUObservation> observations) {
            emuObservations = observations;
        }

        /**
         * Set the observations to display
         * @param obs - List<EMUObservation> items
         */
        public void setObservations(final List<EMUObservation> obs) {
            emuObservations = obs;
            notifyDataSetChanged();
        }

        /**
         *
         * @param parent ViewGroup
         * @param viewType int
         * @return an inflated RecycleViewHolder
         */
        @Override
        public BottomSheetFragment.RecycleViewHolder onCreateViewHolder(final ViewGroup parent,
                final int viewType) {
            final LayoutInflater inflater = LayoutInflater.from(parent.getContext());
            final View emuView = inflater.inflate(R.layout.summary_layout, parent, false);

            return new BottomSheetFragment.RecycleViewHolder(emuView);
        }

        /**
         * Bind data to the view
         * @param holder - the recycle view holder
         * @param position - position of the item in the data provider
         */
        @Override
        public void onBindViewHolder(final BottomSheetFragment.RecycleViewHolder holder, final int position) {
            final EMUObservation observation = emuObservations.get(position);
            holder.txtThickness.setText(getString(R.string.layer_thickness_desc) + observation.getThickness()
                    + getString(R.string.meters));
            holder.txtName.setText(observation.getEmu().getName().toString());
            holder.txtNutrients.setText(observation.getEmu().getNutrientSummary());
            holder.txtSummary.setText(observation.getEmu().getPhysicalSummary());
            final int top = observation.getTop();
            holder.txtTop.setText(getString(R.string.below_surface_description) + top + getString(R.string.meters));
            final GradientDrawable drawable = (GradientDrawable) holder.rectangle.getDrawable();
            drawable.setColor(Color.parseColor(EmuHelper.getColorForEMUCluster(observation.getEmu().getName())));
            holder.details.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(final View v) {
                    mButtonListener.onButtonClick(observation.getEmu().getName());
                }
            });

            // Show/hide arrows
            if (position == getItemCount() - 1) {
                holder.arrowDown.setVisibility(View.INVISIBLE);
            } else {
                holder.arrowDown.setVisibility(View.VISIBLE);
            }
            // View index has changed, notify.
            highlightSegment(position);
        }

        /**
         *
         * @return an int representing size of observation list
         */
        @Override
        public int getItemCount() {

            return emuObservations.size();
        }
    }

    public class RecycleViewHolder extends RecyclerView.ViewHolder {

        public final TextView txtSummary;
        public final TextView txtNutrients;
        public final TextView txtName;
        public final TextView txtThickness;
        public final TextView txtTop;
        public final ImageView rectangle;
        public final Button details;
        public final ImageView arrowDown;

        /**
         *
         * @param emuView View
         * @return RecycleViewHolder
         */
        public RecycleViewHolder(final View emuView) {
            super(emuView);
            txtSummary = (TextView) emuView.findViewById(R.id.physical_summary);
            txtNutrients = (TextView) emuView.findViewById(R.id.nutrient_summary);
            txtName = (TextView) emuView.findViewById(R.id.txtName);
            txtThickness = (TextView) emuView.findViewById(R.id.txt_thickness);
            txtTop = (TextView) emuView.findViewById(R.id.txt_top);
            rectangle = (ImageView) emuView.findViewById(R.id.emu_rectangle);
            details = (Button) emuView.findViewById(R.id.btnDetail);
            arrowDown = (ImageView) emuView.findViewById(R.id.arrowDown);
        }
    }

}