com.calgen.udacity.lego.ui.ArticleDetailFragment.java Source code

Java tutorial

Introduction

Here is the source code for com.calgen.udacity.lego.ui.ArticleDetailFragment.java

Source

/*
 * Copyright 2016 Gurupad Mamadapur
 *
 *    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 com.calgen.udacity.lego.ui;

import android.content.Intent;
import android.database.Cursor;
import android.graphics.Bitmap;
import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.Drawable;
import android.os.Build;
import android.os.Bundle;
import android.support.annotation.Nullable;
import android.support.design.widget.AppBarLayout;
import android.support.design.widget.CollapsingToolbarLayout;
import android.support.design.widget.FloatingActionButton;
import android.support.v4.app.Fragment;
import android.support.v4.app.LoaderManager;
import android.support.v4.app.ShareCompat;
import android.support.v4.content.Loader;
import android.support.v4.util.Pair;
import android.support.v7.graphics.Palette;
import android.support.v7.widget.Toolbar;
import android.text.Html;
import android.text.method.LinkMovementMethod;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.view.animation.AccelerateInterpolator;
import android.view.animation.AlphaAnimation;
import android.view.animation.Animation;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.RelativeLayout;
import android.widget.TextView;

import com.calgen.udacity.lego.R;
import com.calgen.udacity.lego.data.ArticleLoader;
import com.squareup.picasso.Callback;
import com.squareup.picasso.Picasso;

import butterknife.BindBool;
import butterknife.BindColor;
import butterknife.BindDimen;
import butterknife.BindDrawable;
import butterknife.BindView;
import butterknife.ButterKnife;
import butterknife.OnClick;

/**
 * A fragment representing a single Article detail screen. This fragment is
 * either contained in a {@link ArticleListActivity} in two-pane mode (on
 * tablets !Yet-To be implemented! ) or a {@link ArticleDetailActivity} on handsets.
 */
public class ArticleDetailFragment extends Fragment implements LoaderManager.LoaderCallbacks<Cursor> {

    public static final String ARG_ITEM_ID = "item_id";
    private static final String TAG = "ArticleDetailFragment";
    private static final String LOG_TAG = ArticleDetailFragment.class.getSimpleName();
    //@formatter:off
    @BindView(R.id.photo)
    public ImageView photoView;
    @BindView(R.id.article_title)
    public TextView titleView;
    @BindView(R.id.article_byline)
    public TextView bylineView;
    @BindView(R.id.article_body)
    public TextView bodyView;
    @Nullable
    @BindView(R.id.app_bar_layout)
    public AppBarLayout appBarLayout;
    @Nullable
    @BindView(R.id.toolbar)
    public Toolbar toolbar;
    @Nullable
    @BindView(R.id.detail_content)
    public RelativeLayout detailContent;
    @BindView(R.id.share_fab)
    public FloatingActionButton shareFab;
    @BindView(R.id.meta_bar)
    public LinearLayout metaBar;
    @BindColor(R.color.material_grey)
    public int materialGrey;
    @BindColor(R.color.primary_dark)
    public int primaryDark;
    @BindDimen(R.dimen.keyline)
    public int keyLine;
    @BindBool(R.bool.is_land)
    public boolean isLand;
    @BindDrawable(R.drawable.empty_detail)
    public Drawable placeholder;
    public boolean isDark = false;
    private int bylineThreshold = 33;
    //@formatter:on
    private View rootView;
    private Cursor cursor;
    private long itemId;
    private int overLapTopMargin;
    private int extraSideMargin;

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

    public static ArticleDetailFragment newInstance(long itemId) {
        Bundle arguments = new Bundle();
        arguments.putLong(ARG_ITEM_ID, itemId);
        ArticleDetailFragment fragment = new ArticleDetailFragment();
        fragment.setArguments(arguments);
        return fragment;
    }

    //Lifecycle start
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        if (getArguments().containsKey(ARG_ITEM_ID)) {
            itemId = getArguments().getLong(ARG_ITEM_ID);
        }
    }

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
        rootView = inflater.inflate(R.layout.fragment_article_detail, container, false);
        ButterKnife.bind(this, rootView);
        calculateMargins();
        bindViews();
        if (!isLand) {
            CollapsingToolbarLayout.LayoutParams params = new CollapsingToolbarLayout.LayoutParams(
                    ViewGroup.LayoutParams.MATCH_PARENT, overLapTopMargin);
            toolbar.setLayoutParams(params);
        } else {
            RelativeLayout.LayoutParams params = new RelativeLayout.LayoutParams(
                    ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT);
            params.setMargins(extraSideMargin, overLapTopMargin, extraSideMargin, keyLine);
            detailContent.setLayoutParams(params);
        }
        return rootView;
    }

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

        // In support library r8, calling initLoader for a fragment in a FragmentPagerAdapter in
        // the fragment's onCreate may cause the same LoaderManager to be dealt to multiple
        // fragments because their mIndex is -1 (haven't been added to the activity yet). Thus,
        // we do this in onActivityCreated.
        getLoaderManager().initLoader(0, null, this);
    }
    //Lifecycle end

    private void calculateMargins() {
        Pair<Integer, Integer> pair = Utils.getScreenWidthAndHeight(getContext());
        overLapTopMargin = (int) (pair.second * 0.4); // 40% of the height
        extraSideMargin = (int) (pair.first * 0.1); // 10% of the width

        // The following uses dark magic
        bylineThreshold = (Utils.pxToDp(pair.first) - 48) / 9;
    }

    @OnClick(R.id.share_fab)
    public void onClick() {
        startActivity(Intent.createChooser(ShareCompat.IntentBuilder.from(getActivity()).setType("text/plain")
                .setText("Some sample text").getIntent(), getString(R.string.action_share)));
    }

    private void bindViews() {
        if (rootView == null) {
            return;
        }
        if (cursor != null) {
            rootView.setAlpha(0);
            rootView.setVisibility(View.VISIBLE);
            titleView.setText(cursor.getString(ArticleLoader.Query.TITLE));
            bylineView.setText(formatByLine(Utils.getModifiedByline(cursor, getContext())));
            bodyView.setText(Html.fromHtml(cursor.getString(ArticleLoader.Query.BODY)));
            bodyView.setMovementMethod(LinkMovementMethod.getInstance());
            photoView.setMaxHeight((int) (getContext().getResources().getDisplayMetrics().heightPixels * 0.8));
            final String photoUrl = cursor.getString(ArticleLoader.Query.PHOTO_URL);
            Picasso.with(getContext()).load(photoUrl).placeholder(placeholder).into(photoView, new Callback() {
                @Override
                public void onSuccess() {
                    playAnimation(photoView);
                    final Bitmap bitmap = ((BitmapDrawable) photoView.getDrawable()).getBitmap();
                    Palette.from(bitmap).clearFilters().generate(new Palette.PaletteAsyncListener() {
                        @Override
                        public void onGenerated(Palette palette) {
                            @ColorUtils.Lightness
                            int lightness = ColorUtils.isDark(palette);
                            if (lightness == ColorUtils.LIGHTNESS_UNKNOWN) {
                                isDark = ColorUtils.isDark(bitmap, bitmap.getWidth() / 2, 0);
                            } else {
                                isDark = lightness == ColorUtils.IS_DARK;
                            }
                            int extraDarkMutedColor = ColorUtils.scrimify(palette.getDarkMutedColor(primaryDark),
                                    true, 0.7f); //70% Darker
                            metaBar.setBackgroundColor(extraDarkMutedColor);
                            if (isLand && getActivity() != null
                                    && Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
                                (getActivity()).getWindow().setStatusBarColor(extraDarkMutedColor);
                            }
                        }
                    });
                }

                @Override
                public void onError() {
                    Log.e(LOG_TAG, "onError: Couldn't load photo - " + photoUrl);
                }
            });
            if (appBarLayout != null) {
                appBarLayout.setExpanded(false, true);
            }
            rootView.animate().alpha(1).setDuration(300);
            getActivity().supportStartPostponedEnterTransition();
        } else {
            rootView.setVisibility(View.GONE);
        }
    }

    private void playAnimation(ImageView photoView) {
        Animation fadeIn = new AlphaAnimation(0, 1);
        fadeIn.setInterpolator(new AccelerateInterpolator());
        fadeIn.setDuration(500);
        photoView.startAnimation(fadeIn);
        shareFab.setVisibility(View.VISIBLE);
        shareFab.startAnimation(fadeIn);
    }

    private String formatByLine(String modifiedByline) {
        if (modifiedByline.length() > bylineThreshold) {
            return new StringBuilder(modifiedByline).insert(modifiedByline.indexOf("by"), "\n").toString();
        }
        return modifiedByline;
    }

    @Override
    public Loader<Cursor> onCreateLoader(int i, Bundle bundle) {
        return ArticleLoader.newInstanceForItemId(getActivity(), itemId);
    }

    @Override
    public void onLoadFinished(Loader<Cursor> cursorLoader, Cursor cursor) {
        if (!isAdded()) {
            if (cursor != null) {
                cursor.close();
            }
            return;
        }
        this.cursor = cursor;
        if (this.cursor != null && !this.cursor.moveToFirst()) {
            Log.e(TAG, "Error reading item detail cursor");
            this.cursor.close();
            this.cursor = null;
        }
        bindViews();
    }

    @Override
    public void onLoaderReset(Loader<Cursor> cursorLoader) {
        cursor = null;
        bindViews();
    }
}