net.goldenspiral.fetlifeoss.ui.fragments.FetLifeFragment.java Source code

Java tutorial

Introduction

Here is the source code for net.goldenspiral.fetlifeoss.ui.fragments.FetLifeFragment.java

Source

/**
 * The MIT License (MIT)
 *
 * Copyright (c) 2015 <a href="https://bitbucket.org/malachid/fetlife-oss/src/default/Contributors.md?at=default">FetLife-OSS Contributors</a>
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 * THE SOFTWARE.
 */
package net.goldenspiral.fetlifeoss.ui.fragments;

import android.app.Activity;
import android.content.Context;
import android.content.Intent;
import android.databinding.DataBindingUtil;
import android.databinding.ViewDataBinding;
import android.net.Uri;
import android.os.Bundle;
import android.support.annotation.MenuRes;
import android.support.annotation.StringRes;
import android.support.design.widget.Snackbar;
import android.support.v4.app.Fragment;
import android.support.v4.view.MenuItemCompat;
import android.support.v7.app.ActionBar;
import android.support.v7.view.ContextThemeWrapper;
import android.support.v7.widget.ShareActionProvider;
import android.view.LayoutInflater;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
import android.view.View;
import android.view.ViewGroup;

import com.google.gson.Gson;

import net.goldenspiral.fetlifeoss.R;
import net.goldenspiral.fetlifeoss.ui.MainActivity;
import net.goldenspiral.fetlifeoss.ui.components.FetLifeDatabinder;
import net.goldenspiral.fetlifeoss.util.gson.GsonUtil;

/**
 * Created by malachi on 8/8/15.
 */
public abstract class FetLifeFragment<BINDING extends ViewDataBinding> extends Fragment
        implements View.OnClickListener {
    private ShareActionProvider shareActionProvider;
    private Intent lastShareIntent = null;
    private View rootView;
    private Gson gson;

    /**
     * Default constructor.  <strong>Every</strong> fragment must have an
     * empty constructor, so it can be instantiated when restoring its
     * activity's state.  It is strongly recommended that subclasses do not
     * have other constructors with parameters, since these constructors
     * will not be called when the fragment is re-instantiated; instead,
     * arguments can be supplied by the caller with {@link #setArguments}
     * and later retrieved by the Fragment with {@link #getArguments}.
     * <p/>
     * <p>Applications should generally not implement a constructor.  The
     * first place application code an run where the fragment is ready to
     * be used is in {@link #onAttach(Activity)}, the point where the fragment
     * is actually associated with its activity.  Some applications may also
     * want to implement {@link #onInflate} to retrieve attributes from a
     * layout resource, though should take care here because this happens for
     * the fragment is attached to its activity.
     */
    public FetLifeFragment() {
        super();
    }

    protected Gson gson() {
        if (gson != null)
            return gson;
        gson = GsonUtil.instance.getBuilder().create();
        return gson;
    }

    protected <DATA> Bundle addToBundle(final Bundle bundle, @StringRes final int keyId, final DATA data) {
        return addToBundle(bundle, getResources().getString(keyId), data);
    }

    protected <DATA> Bundle addToBundle(final Bundle bundle, final String key, final DATA data) {
        bundle.putString(key, gson().toJson(data));
        return bundle;
    }

    protected <DATA> DATA getFromBundle(final Bundle bundle, @StringRes final int keyId,
            final Class<DATA> dataClass) {
        return getFromBundle(bundle, getResources().getString(keyId), dataClass);
    }

    protected <DATA> DATA getFromBundle(final Bundle bundle, final String key, final Class<DATA> dataClass) {
        if (bundle == null)
            return null;
        if (!bundle.containsKey(key))
            return null;
        return gson().fromJson(bundle.getString(key), dataClass);
    }

    /**
     * Title resource id.
     *
     * @return title resource identifier
     */
    public int getTitle() {
        return -1;
    }

    /**
     * Initialize the contents of the Activity's standard options menu.  You
     * should place your menu items in to <var>menu</var>.  For this method
     * to be called, you must have first called {@link #setHasOptionsMenu}.  See
     * {@link android.app.Activity#onCreateOptionsMenu(Menu) Activity.onCreateOptionsMenu}
     * for more information.
     *
     * @param menu     The options menu in which you place your items.
     * @param inflater
     * @see #setHasOptionsMenu
     * @see #onPrepareOptionsMenu
     * @see #onOptionsItemSelected
     */
    @Override
    public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
        menu.clear();

        int resId = getOptionMenuResId();
        if (resId == 0)
            return;

        inflater.inflate(resId, menu);
        MenuItem item = menu.findItem(R.id.menu_share);
        if (item != null) {
            shareActionProvider = (ShareActionProvider) MenuItemCompat.getActionProvider(item);
            if (lastShareIntent != null)
                shareActionProvider.setShareIntent(lastShareIntent);
        }
    }

    protected @MenuRes int getOptionMenuResId() {
        return 0;
    }

    /**
     * Report that this fragment would like to participate in populating
     * the options menu by receiving a call to {@link #onCreateOptionsMenu}
     * and related methods.
     *
     * @param hasMenu If true, the fragment has menu items to contribute.
     */
    @Override
    public void setHasOptionsMenu(boolean hasMenu) {
        super.setHasOptionsMenu(hasMenu);
        final MainActivity activity = getMainActivity();
        if (activity != null) {
            final ActionBar bar = activity.getSupportActionBar();
            if (bar != null)
                bar.invalidateOptionsMenu();
        }
    }

    private BINDING dataBinding;

    public void setRootBinding(BINDING binding) {
        this.dataBinding = binding;
        setRootView(dataBinding.getRoot());
    }

    public BINDING getRootBinding() {
        return dataBinding;
    }

    /**
     * Set the root view of this fragment so other classes (like Adapters) can get ahold of it
     *
     * @param rootView as returned by onCreateView
     */
    public void setRootView(View rootView) {
        this.rootView = rootView;
    }

    public View getRootView() {
        return rootView;
    }

    public MainActivity getMainActivity() {
        return (MainActivity) getActivity();
    }

    /**
     *
     * @param inflater The LayoutInflater object that can be used to inflate  any views in the fragment,
     * @param container If non-null, this is the parent view that the fragment's
     * UI should be attached to.  The fragment should not add the view itself,
     * but this can be used to generate the LayoutParams of the view.
     * @param theme to use for the new UI
     * @param layout to inflate
     *
     * @return Return the View for the fragment's UI, or null.
     */
    protected View inflate(final LayoutInflater inflater, final ViewGroup container, int theme, int layout) {
        // create ContextThemeWrapper from the original Activity Context with the custom theme
        final Context contextThemeWrapper = new ContextThemeWrapper(getActivity(), theme);

        // clone the inflater using the ContextThemeWrapper
        LayoutInflater localInflater = inflater.cloneInContext(contextThemeWrapper);

        // inflate the layout using the cloned inflater, not default inflater
        return localInflater.inflate(layout, container, false);
    }

    /**
     * Convenience wrapper that assumes AppTheme
     *
     * @param inflater The LayoutInflater object that can be used to inflate  any views in the fragment,
     * @param container If non-null, this is the parent view that the fragment's
     * UI should be attached to.  The fragment should not add the view itself,
     * but this can be used to generate the LayoutParams of the view.
     * @param layout to inflate
     *
     * @return Return the View for the fragment's UI, or null.
     */
    protected View inflate(final LayoutInflater inflater, final ViewGroup container, int layout) {
        return inflate(inflater, container, R.style.AppTheme, layout);
    }

    protected BINDING bind(final LayoutInflater inflater, final ViewGroup container, int theme, int layout) {
        // create ContextThemeWrapper from the original Activity Context with the custom theme
        final Context contextThemeWrapper = new ContextThemeWrapper(getActivity(), theme);

        // clone the inflater using the ContextThemeWrapper
        LayoutInflater localInflater = inflater.cloneInContext(contextThemeWrapper);

        // inflate the layout using the cloned inflater, not default inflater
        // @TODO AndroidStudio shows an error for FetLifeDatabinder - see it for details
        return DataBindingUtil.inflate(localInflater, layout, container, false, FetLifeDatabinder.INSTANCE);
    }

    protected BINDING bind(final LayoutInflater inflater, final ViewGroup container, int layout) {
        return bind(inflater, container, R.style.AppTheme, layout);
    }

    /**
     * Set this fragment to be the click listener for the given views.
     * Must call setRootView first.
     *
     * @param viewIds to bind
     * @see #setRootView
     */
    protected void setOnClickListeners(int... viewIds) {
        for (int viewId : viewIds)
            rootView.findViewById(viewId).setOnClickListener(this);
    }

    /**
     * Called when a view has been clicked.
     *
     * @param view The view that was clicked.
     */
    @Override
    public void onClick(View view) {

    }

    public void onBackPressed() {
        Activity activity = getActivity();
        if (activity != null)
            activity.finish();
    }

    /**
     * (Un)Lock the navigation drawer
     *
     * @param locked if it should be locked closed
     */
    public void setDrawerLocked(boolean locked) {
        MainActivity activity = getMainActivity();
        if (activity != null)
            activity.setDrawerLocked(locked);
    }

    /**
     * Convenience function since we are likely to do this a lot
     */
    public void snack(String fmt, Object... args) {
        Snackbar.make(getRootView(), String.format(fmt, args), Snackbar.LENGTH_LONG).show();
    }

    protected void setShareIntent(Intent intent) {
        lastShareIntent = intent;
        if (shareActionProvider != null)
            shareActionProvider.setShareIntent(intent);
    }

    protected void setShareIntent(String message) {
        final Intent sendIntent = new Intent();
        sendIntent.setAction(Intent.ACTION_SEND);
        sendIntent.putExtra(Intent.EXTRA_TITLE, getResources().getString(R.string.share_title));
        sendIntent.putExtra(Intent.EXTRA_TEXT, message);
        sendIntent.putExtra(Intent.EXTRA_REFERRER, Uri.parse(getResources().getString(R.string.share_referrer)));
        sendIntent.setType("text/plain");
        setShareIntent(sendIntent);
    }

    protected void setShareIntent(@StringRes int resId, Object... args) {
        setShareIntent(format(resId, args));
    }

    protected String format(@StringRes int resId, Object... args) {
        return String.format(getResources().getString(resId), args);
    }
}