com.xamoom.android.xamoomcontentblocks.XamoomContentFragment.java Source code

Java tutorial

Introduction

Here is the source code for com.xamoom.android.xamoomcontentblocks.XamoomContentFragment.java

Source

/*
* Copyright 2017 by xamoom GmbH <apps@xamoom.com>
*
* This file is part of some open source application.
*
* Some open source application 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 2 of the License, or (at your option) any later version.
*
* Some open source application 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 xamoom-android-sdk. If not, see <http://www.gnu.org/licenses/>.
*
* author: Raphael Seher <raphael@xamoom.com>
*/

package com.xamoom.android.xamoomcontentblocks;

import android.Manifest;
import android.app.Activity;
import android.content.Context;
import android.content.Intent;
import android.graphics.Color;
import android.nfc.Tag;
import android.os.Bundle;
import android.support.annotation.NonNull;
import android.support.v4.app.Fragment;
import android.support.v4.content.LocalBroadcastManager;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.view.animation.Animation;
import android.view.animation.AnimationUtils;

import com.xamoom.android.xamoomcontentblocks.Adapters.ContentBlockAdapter;
import com.xamoom.android.xamoomcontentblocks.ViewHolders.ContentBlock2ViewHolder;
import com.xamoom.android.xamoomcontentblocks.ViewHolders.ContentBlock3ViewHolder;
import com.xamoom.android.xamoomsdk.EnduserApi;
import com.xamoom.android.xamoomsdk.R;
import com.xamoom.android.xamoomsdk.Resource.Content;
import com.xamoom.android.xamoomsdk.Resource.ContentBlock;
import com.xamoom.android.xamoomsdk.Resource.Style;

import java.util.ArrayList;
import java.util.List;

/**
 * XamoomContentBlock is a helper for everyone to display the different contentBlocks delivered
 * from the xamoom cloud.
 *
 * ATM there are nine different contentBlocks displaying different contents from the customer.
 * In your app you can display the contentBlocks like you want, we decided to display them
 * like on our website (https://www.xm.gl).
 *
 * To get started with the XamoomContentFragment create a new Instance via {@link #newInstance(String)}.
 * You also have to adapt {@link com.xamoom.android.xamoomcontentblocks.XamoomContentFragment.OnXamoomContentFragmentInteractionListener}.
 *
 * There are two ways to use this class.
 * You can set an identifier (contentId or locationIdentifier), this fragment will download it and display it, when added to an activity.
 * Or you can set the content and the fragment will display that.
 *
 * @author Raphael Seher
 *
 * @version 0.1
 *
 */
public class XamoomContentFragment extends Fragment
        implements ContentBlock3ViewHolder.OnContentBlock3ViewHolderInteractionListener {
    private static final String YOUTUBE_API_KEY = "0000";
    private static final String SHOW_SPOT_MAP_CONTENT_LINKS = "0001";
    private static final String CONTENT_BLOCKS = "0002";
    private static final String CONTENT = "0003";
    private static final String ENDUSER_API = "0004";
    private static final int WRITE_STORAGE_PERMISSION = 0;

    private View mRootView;
    private EnduserApi mEnduserApi;
    private RecyclerView mRecyclerView;
    private ContentBlockAdapter mContentBlockAdapter;
    private Content mContent;
    private ArrayList<ContentBlock> mContentBlocks = new ArrayList<>();
    private String mYoutubeApiKey;
    private int mBackgroundColor = Color.WHITE;

    private boolean offline = false;
    private boolean showAllBlocksWhenOffline = false;
    private boolean displayAllStoreLinks = false;
    private boolean showSpotMapContentLinks = false;
    private boolean isAnimated = false;

    /**
     * Use this factory method to create a new instance.
     * You can set a special linkcolor as hex. (e.g. "00F")
     *
     * @return XamoomContentFragment Returns an Instance of XamoomContentFragment
     */
    public static XamoomContentFragment newInstance(@NonNull String youtubeApiKey) {
        XamoomContentFragment fragment = new XamoomContentFragment();
        Bundle args = new Bundle();

        args.putString(YOUTUBE_API_KEY, youtubeApiKey);
        fragment.setArguments(args);

        return fragment;
    }

    public XamoomContentFragment() {
        mContentBlockAdapter = new ContentBlockAdapter(this, mContentBlocks, showSpotMapContentLinks,
                mYoutubeApiKey, this);
    }

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        if (getArguments() != null) {
            mYoutubeApiKey = getArguments().getString(YOUTUBE_API_KEY);
            mContentBlockAdapter.setYoutubeApiKey(mYoutubeApiKey);
        }

        if (savedInstanceState != null) {
            mYoutubeApiKey = savedInstanceState.getString(YOUTUBE_API_KEY);
            mContentBlockAdapter.setYoutubeApiKey(mYoutubeApiKey);
            showSpotMapContentLinks = savedInstanceState.getBoolean(SHOW_SPOT_MAP_CONTENT_LINKS);
            mContent = savedInstanceState.getParcelable(CONTENT);
            mContentBlocks = savedInstanceState.getParcelableArrayList(CONTENT_BLOCKS);
            mContentBlockAdapter.setContentBlocks(mContentBlocks);
            mEnduserApi = savedInstanceState.getParcelable(ENDUSER_API);
            mContentBlockAdapter.setEnduserApi(mEnduserApi);
        }
    }

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
        mRootView = inflater.inflate(R.layout.fragment_xamoom_content, container, false);
        mRootView.setBackgroundColor(mBackgroundColor);

        mRecyclerView = (RecyclerView) mRootView.findViewById(R.id.contentblock_recycler_view);
        setupRecyclerView();

        return mRootView;
    }

    @Override
    public void onStart() {
        super.onStart();

        if (!isAnimated) {
            if (mContentBlockAdapter != null) {
                mContentBlockAdapter.notifyDataSetChanged();
            }
        }
    }

    @Override
    public void onPause() {
        Intent intent = new Intent(ContentBlock2ViewHolder.RESET_YOUTUBE);
        LocalBroadcastManager.getInstance(getContext()).sendBroadcast(intent);
        super.onPause();
    }

    @Override
    public void onSaveInstanceState(Bundle outState) {
        super.onSaveInstanceState(outState);
        outState.putString(YOUTUBE_API_KEY, mYoutubeApiKey);
        outState.putBoolean(SHOW_SPOT_MAP_CONTENT_LINKS, showSpotMapContentLinks);
        outState.putParcelable(CONTENT, mContent);
        outState.putParcelableArrayList(CONTENT_BLOCKS, mContentBlocks);
        outState.putParcelable(ENDUSER_API, mEnduserApi);
    }

    @Override
    public void onDestroy() {
        if (mRecyclerView != null) {
            mRecyclerView.setAdapter(null);
            mRecyclerView.setLayoutManager(null);
        }
        mContentBlockAdapter = null;
        mRecyclerView = null;
        mContent = null;
        mContentBlocks = null;

        super.onDestroy();
    }

    /**
     * Setup the recyclerview.
     */
    private void setupRecyclerView() {
        if (mContent == null) {
            return;
        }

        mRecyclerView.setLayoutManager(new LinearLayoutManager(this.getActivity().getApplicationContext()));
        mRecyclerView.setAdapter(mContentBlockAdapter);
    }

    /**
     * If you animate this fragment, it will show the data when the animation is finished.
     */
    @Override
    public Animation onCreateAnimation(int transit, boolean enter, int nextAnim) {
        if (nextAnim != 0) {
            isAnimated = true;
            Animation anim = AnimationUtils.loadAnimation(getActivity(), nextAnim);
            anim.setAnimationListener(animationListener);
        }

        return super.onCreateAnimation(transit, enter, nextAnim);
    }

    public Animation.AnimationListener animationListener = new Animation.AnimationListener() {
        @Override
        public void onAnimationStart(Animation animation) {
        }

        @Override
        public void onAnimationEnd(Animation animation) {
            if (mContentBlockAdapter != null) {
                mContentBlockAdapter.notifyDataSetChanged();
            }
        }

        @Override
        public void onAnimationRepeat(Animation animation) {
        }
    };

    /**
     * There should always be the contents text, description and image
     * on top of the other contentBlocks.
     *
     * Here it creates a text and an image contentBlock and adds them
     * to achieve this.
     *
     * When you want to have all link ContentBlocks displayed for all
     * stores (to promote your app), you have to set {@link #displayAllStoreLinks} to true.
     */
    private void addContentTitleAndImage() {
        if (mContent.getTitle() != null && !mContent.getTitle().equalsIgnoreCase("")
                || mContent.getDescription() != null && !mContent.getDescription().equalsIgnoreCase("")) {
            ContentBlock contentBlock0 = new ContentBlock();
            contentBlock0.setTitle(mContent.getTitle());
            contentBlock0.setBlockType(-1);
            contentBlock0.setPublicStatus(true);
            contentBlock0.setText(mContent.getDescription());
            mContentBlocks.add(0, contentBlock0);
        }

        if (mContent.getPublicImageUrl() != null) {
            ContentBlock contentBlock3 = new ContentBlock();
            contentBlock3.setTitle(null);
            contentBlock3.setBlockType(3);
            contentBlock3.setPublicStatus(true);
            contentBlock3.setFileId(mContent.getPublicImageUrl());
            contentBlock3.setScaleX(0);
            mContentBlocks.add(1, contentBlock3);
        }
    }

    public void removeOfflineBlocks() {
        ArrayList<ContentBlock> removeBlocks = new ArrayList<>();
        for (ContentBlock block : mContentBlocks) {
            if (block.getBlockType() == 9 || block.getBlockType() == 7) {
                removeBlocks.add(block);
            }

            if (block.getBlockType() == 2) {
                if (block.getVideoUrl().contains("youtu") || block.getVideoUrl().contains("vimeo")) {
                    removeBlocks.add(block);
                }
            }
        }

        mContentBlocks.removeAll(removeBlocks);
    }

    /**
     * The default behaviour is that there are only Google Play Store link ContentBlocks
     * are shown.
     *
     * All others will get removed here. Except you set {@link #displayAllStoreLinks} to true.
     *
     * @param contentBlocks ContentBlocks List to manipulate
     * @return Manipulated contetnBlocks List
     */
    private ArrayList<ContentBlock> removeStoreLinks(ArrayList<ContentBlock> contentBlocks) {
        ArrayList<ContentBlock> cbToRemove = new ArrayList<>();

        for (ContentBlock contentBlock : contentBlocks) {
            if (contentBlock.getBlockType() == 4) {
                if (contentBlock.getLinkType() == 15 || contentBlock.getLinkType() == 17) {
                    cbToRemove.add(contentBlock);
                }
            }
        }

        contentBlocks.removeAll(cbToRemove);
        return contentBlocks;
    }

    @Override
    public void onAttach(Context context) {
        super.onAttach(context);

        Activity activity;
        if (context instanceof Activity) {
            activity = (Activity) context;

            try {
                OnXamoomContentFragmentInteractionListener listener = (OnXamoomContentFragmentInteractionListener) activity;
                mContentBlockAdapter.setOnXamoomContentFragmentInteractionListener(listener);
            } catch (ClassCastException e) {
                throw new ClassCastException(
                        activity.toString() + " must implement OnXamoomContentFragmentInteractionListener");
            }
        }
    }

    @Override
    public void onDetach() {
        super.onDetach();
    }

    @Override
    public void needExternalStoragePermission() {
        requestPermissions(new String[] { Manifest.permission.WRITE_EXTERNAL_STORAGE }, WRITE_STORAGE_PERMISSION);
    }

    @Override
    public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions,
            @NonNull int[] grantResults) {
        super.onRequestPermissionsResult(requestCode, permissions, grantResults);
    }

    /**
     * Implement OnXamoomContentFragmentInteractionListener and override
     * <code>clickedContentBlock(String)</code>.
     *
     * <code>clickedContentBlock(String)</code> gets called, when somebody clicks
     * a {@link com.xamoom.android.xamoomcontentblocks.ViewHolders.ContentBlock6ViewHolder} and you have to handle it. Normally you would open
     * a new activity or update the XamoomContentFragment with the passed contentId.
     */
    public interface OnXamoomContentFragmentInteractionListener {
        void clickedContentBlock(Content content);

        void clickedSpotMapContentLink(String contentId);
    }

    // getters

    public ContentBlockAdapter getContentBlockAdapter() {
        return mContentBlockAdapter;
    }

    public boolean isShowSpotMapContentLinks() {
        return showSpotMapContentLinks;
    }

    public boolean isDisplayAllStoreLinks() {
        return displayAllStoreLinks;
    }

    public RecyclerView getRecyclerView() {
        return mRecyclerView;
    }

    public List<ContentBlock> getContentBlocks() {
        return mContentBlocks;
    }

    // setters

    public void setRecyclerView(RecyclerView recyclerView) {
        mRecyclerView = recyclerView;
    }

    public void setContent(Content content) {
        setContent(content, true, false);
    }

    /**
     * Sets the content to display when fragment gets loaded.
     *
     * @param content Content to display.
     * @param addHeader Adds header (content title and content image).
     * @param offline Will notify contentBlocks to use offline functioniality and remove
     *                offline unavailable contentBlocks.
     */
    public void setContent(Content content, boolean addHeader, boolean offline) {
        if (content == null) {
            return;
        }

        this.mContent = content;
        if (mContent.getContentBlocks() != null) {
            mContentBlocks.addAll(mContent.getContentBlocks());
        }

        if (addHeader) {
            addContentTitleAndImage();
        }

        if (offline && !showAllBlocksWhenOffline) {
            this.offline = offline;
            mContentBlockAdapter.setOffline(offline);

            removeOfflineBlocks();
        }

        if (!displayAllStoreLinks) {
            mContentBlocks = removeStoreLinks(mContentBlocks);
        }
    }

    public void setBackgroundColor(int backgroundColor) {
        mBackgroundColor = backgroundColor;

        if (mRootView != null) {
            mRootView.setBackgroundColor(backgroundColor);
        }
    }

    public void setStyle(Style style) {
        mContentBlockAdapter.setStyle(style);

        if (style != null && style.getBackgroundColor() != null) {
            mBackgroundColor = Color.parseColor(style.getBackgroundColor());
        }
    }

    public void setDisplayAllStoreLinks(boolean displayAllStoreLinks) {
        this.displayAllStoreLinks = displayAllStoreLinks;
    }

    public void setShowSpotMapContentLinks(boolean showSpotMapContentLinks) {
        this.showSpotMapContentLinks = showSpotMapContentLinks;
    }

    public void setEnduserApi(EnduserApi enduserApi) {
        mEnduserApi = enduserApi;
        mContentBlockAdapter.setEnduserApi(enduserApi);
    }

    public EnduserApi getEnduserApi() {
        return mEnduserApi;
    }

    public boolean isShowAllBlocksWhenOffline() {
        return showAllBlocksWhenOffline;
    }

    public void setShowAllBlocksWhenOffline(boolean showAllBlocksWhenOffline) {
        this.showAllBlocksWhenOffline = showAllBlocksWhenOffline;
    }
}