com.examples.abelanav2.ui.PicturesFragment.java Source code

Java tutorial

Introduction

Here is the source code for com.examples.abelanav2.ui.PicturesFragment.java

Source

/*
 * Copyright 2015 Google Inc. All Rights Reserved.
 *
 * 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.examples.abelanav2.ui;

import android.app.AlertDialog;
import android.app.WallpaperManager;
import android.content.DialogInterface;
import android.os.AsyncTask;
import android.os.Bundle;
import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentTransaction;
import android.support.v7.widget.CardView;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView;
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 android.widget.EditText;
import android.widget.Toast;

import com.examples.abelanav2.R;
import com.examples.abelanav2.grpcclient.AbelanaClient;
import com.examples.abelanav2.grpcclient.AbelanaClientException;
import com.examples.abelanav2.grpcclient.PhotoInfo;
import com.examples.abelanav2.ui.utils.FloatingActionButton;
import com.examples.abelanav2.ui.utils.PhotoAdapter;

import java.io.IOException;
import java.io.InputStream;
import java.net.URL;
import java.util.ArrayList;
import java.util.List;

/**
 * This Fragment handles the display of a list of picture cards.
 * Use the {@link PicturesFragment#newInstance} factory method to
 * create an instance of this fragment.
 */
public class PicturesFragment extends Fragment
        implements View.OnClickListener, PhotoAdapter.PhotoAdapterListener, MenuItem.OnMenuItemClickListener {

    /**
     * This is the name of the argument for the mFragmentType field.
     */
    private static final String ARG_FRAGMENT_TYPE = "ArgFragmentType";
    /**
     * This is the type of the pictures list to display in this fragment: home,
     * favorites or my pictures.
     */
    private AbelanaClient.PhotoListType mFragmentType;
    /**
     * The recycler view that contains the picture cards.
     */
    private RecyclerView mRecyclerView;
    /**
     * The RecyclerView Adapter.
     */
    private PhotoAdapter mPhotoAdapter;
    /**
     * Indicates if we want to load more results or refresh completely the list.
     */
    private boolean mLoadMore = false;

    /**
     * Empty constructor.
     */
    public PicturesFragment() {
    }

    /**
     * Use this factory method to create a new instance of
     * this fragment using the provided parameters.
     * @param pFragmentType the type of pictures list for this fragment.
     * @return A new instance of fragment PicturesFragment.BackendConstants
     */
    public static PicturesFragment newInstance(AbelanaClient.PhotoListType pFragmentType) {
        PicturesFragment fragment = new PicturesFragment();
        Bundle args = new Bundle();
        args.putSerializable(ARG_FRAGMENT_TYPE, pFragmentType);
        fragment.setArguments(args);
        return fragment;
    }

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setHasOptionsMenu(true);
        if (getArguments() != null) {
            mFragmentType = (AbelanaClient.PhotoListType) getArguments().getSerializable(ARG_FRAGMENT_TYPE);
        }
    }

    @Override
    public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
        MenuItem refreshMenu = menu.add(R.string.action_refresh);
        refreshMenu.setShowAsAction(MenuItem.SHOW_AS_ACTION_ALWAYS | MenuItem.SHOW_AS_ACTION_WITH_TEXT);
        refreshMenu.setOnMenuItemClickListener(this);
        super.onCreateOptionsMenu(menu, inflater);
    }

    @Override
    public boolean onMenuItemClick(MenuItem item) {
        refreshPhotoList();
        return false;
    }

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
        View rootView;
        if (mFragmentType == AbelanaClient.PhotoListType.PHOTO_LIST_STREAM) {
            rootView = inflater.inflate(R.layout.fragment_pictures, container, false);
            FloatingActionButton floatingActionButton = (FloatingActionButton) rootView
                    .findViewById(R.id.fab_add_photo);
            floatingActionButton.setOnClickListener(this);
        } else {
            rootView = inflater.inflate(R.layout.fragment_likes, container, false);
        }
        mRecyclerView = (RecyclerView) rootView.findViewById(R.id.cardList);
        mRecyclerView.setHasFixedSize(true);
        LinearLayoutManager linearLayoutManager = new LinearLayoutManager(getActivity().getApplicationContext());
        linearLayoutManager.setOrientation(LinearLayoutManager.VERTICAL);
        mRecyclerView.setLayoutManager(linearLayoutManager);

        mPhotoAdapter = new PhotoAdapter(new ArrayList<PhotoInfo>(), mFragmentType, this, mRecyclerView, this);
        mPhotoAdapter.setOnLoadMoreListener(new PhotoAdapter.OnLoadMoreListener() {
            @Override
            public void onLoadMore() {
                loadMorePhotoList();
            }
        });
        mRecyclerView.setAdapter(mPhotoAdapter);

        refreshPhotoList();

        registerForContextMenu(mRecyclerView);

        return rootView;
    }

    /**
     * Refreshes the photo list completely.
     */
    private void refreshPhotoList() {
        mLoadMore = false;
        mRecyclerView.getLayoutManager().scrollToPosition(0);
        new LoadPhotoList().execute(mFragmentType);
    }

    /**
     * Gets more photos.
     */
    private void loadMorePhotoList() {
        mLoadMore = true;
        if (((MainActivity) getActivity()).getAbelanaClient().hasMorePages(mFragmentType)) {
            new LoadPhotoList().execute(mFragmentType);
        }
    }

    @Override
    public void onClick(View v) {
        switch (v.getId()) {
        case R.id.fab_add_photo:
            final FragmentTransaction ft = getFragmentManager().beginTransaction();
            ft.addToBackStack(null);
            ft.replace(R.id.container, UploadFragment.newInstance());
            ft.commit();
            break;
        default:
            break;
        }
    }

    /**
     * If an item is selected in the contextual menu of a picture.
     * @param item the item selected.
     * @return whether the event was handled or not.
     */
    public boolean onContextItemSelected(MenuItem item) {
        final int position = ((PhotoAdapter) mRecyclerView.getAdapter()).getPosition();
        switch (item.getItemId()) {
        case R.id.context_menu_report:
            new AlertDialog.Builder(getActivity()).setTitle(getString(R.string.photo_list_report_photo_title))
                    .setMessage(getString(R.string.photo_list_report_photo_message))
                    .setPositiveButton(R.string.report, new DialogInterface.OnClickListener() {
                        public void onClick(DialogInterface dialog, int which) {
                            new ReportTask().execute(position);
                        }
                    }).setNegativeButton(android.R.string.cancel, new DialogInterface.OnClickListener() {
                        public void onClick(DialogInterface dialog, int which) {
                            // do nothing
                        }
                    }).setIcon(android.R.drawable.ic_dialog_alert).show();
            return true;
        default:
            return super.onContextItemSelected(item);
        }
    }

    @Override
    public void onPhotoCardClick(View v, final int position) {
        ((PhotoAdapter) mRecyclerView.getAdapter()).setPosition(position);
        switch (v.getId()) {
        case R.id.imageButtonThumbsUp:
            int vote = 1;
            CardView card = (CardView) v.getParent().getParent();
            card.findViewById(R.id.imageButtonThumbsDown).setSelected(false);
            if (card.findViewById(R.id.imageButtonThumbsUp).isSelected()) {
                vote = 0;
                card.findViewById(R.id.imageButtonThumbsUp).setSelected(false);
            } else {
                card.findViewById(R.id.imageButtonThumbsUp).setSelected(true);
            }
            new VoteTask().execute(vote);
            break;
        case R.id.imageButtonThumbsDown:
            vote = -1;
            card = (CardView) v.getParent().getParent();
            card.findViewById(R.id.imageButtonThumbsUp).setSelected(false);
            if (card.findViewById(R.id.imageButtonThumbsDown).isSelected()) {
                vote = 0;
                card.findViewById(R.id.imageButtonThumbsDown).setSelected(false);
            } else {
                card.findViewById(R.id.imageButtonThumbsDown).setSelected(true);
            }
            new VoteTask().execute(vote);
            break;
        case R.id.imageButtonWallpaper:
            new AlertDialog.Builder(getActivity()).setTitle(getString(R.string.photo_list_wallpaper_title))
                    .setMessage(getString(R.string.photo_list_wallpaper_message))
                    .setPositiveButton(R.string.set_wallpaper, new DialogInterface.OnClickListener() {
                        public void onClick(DialogInterface dialog, int which) {
                            new WallpaperTask().execute();
                        }
                    }).setNegativeButton(android.R.string.cancel, new DialogInterface.OnClickListener() {
                        public void onClick(DialogInterface dialog, int which) {
                            // do nothing
                        }
                    }).setIcon(R.drawable.ic_wallpaper).show();
            break;
        case R.id.imageButtonEdit:
            final EditText editText = new EditText(getActivity().getApplicationContext());
            editText.setText(mPhotoAdapter.getPhotoList().get(position).description);
            editText.setTextColor(getResources().getColor(android.R.color.black));
            new AlertDialog.Builder(getActivity()).setTitle(getString(R.string.photo_list_edit_photo_title))
                    .setMessage(getString(R.string.photo_list_edit_photo_message)).setView(editText)
                    .setPositiveButton(R.string.edit, new DialogInterface.OnClickListener() {
                        public void onClick(DialogInterface dialog, int which) {
                            new EditTask().execute(editText.getText().toString());
                        }
                    }).setNegativeButton(android.R.string.cancel, new DialogInterface.OnClickListener() {
                        public void onClick(DialogInterface dialog, int which) {
                            // do nothing
                        }
                    }).setIcon(R.drawable.ic_edit).show();
            break;
        case R.id.imageButtonDelete:
            new AlertDialog.Builder(getActivity()).setTitle(getString(R.string.photo_list_delete_photo_title))
                    .setMessage(getString(R.string.photo_list_delete_photo_message))
                    .setPositiveButton(R.string.delete, new DialogInterface.OnClickListener() {
                        public void onClick(DialogInterface dialog, int which) {
                            new DeleteTask().execute();
                        }
                    }).setNegativeButton(android.R.string.cancel, new DialogInterface.OnClickListener() {
                        public void onClick(DialogInterface dialog, int which) {
                            // do nothing
                        }
                    }).setIcon(R.drawable.ic_delete).show();
            break;
        default:
            break;
        }

    }

    /**
     * AsyncTask used to refresh the photo list.
     * Takes the photo list type as first argument, and the string "loadMore"
     * to indicate that we want to get the next page or not.
     */
    private class LoadPhotoList extends AsyncTask<AbelanaClient.PhotoListType, Void, String> {

        /**
         * Temporary list of new photos.
         */
        private List<PhotoInfo> mNewPhotoList;

        @Override
        protected void onPreExecute() {
            //add progress item
            mPhotoAdapter.getPhotoList().add(null);
            mPhotoAdapter.notifyItemInserted(mPhotoAdapter.getPhotoList().size() - 1);
        }

        @Override
        protected String doInBackground(final AbelanaClient.PhotoListType... params) {
            try {
                mNewPhotoList = ((MainActivity) getActivity()).getAbelanaClient().getPhotoList(params[0],
                        mLoadMore);
                return null;
            } catch (AbelanaClientException e) {
                mNewPhotoList = ((MainActivity) getActivity()).getAbelanaClient().getPhotoListFromCache(params[0]);
                if (!e.getMessage().equals(getString(R.string.abelana_auth_error_message))) {
                    return getString(R.id.data_shown_from_cache);
                } else {
                    return e.getMessage();
                }
            }
        }

        @Override
        protected void onPostExecute(final String result) {
            if (result != null) {
                showErrorMessage(result);
            }
            //remove progress item
            mPhotoAdapter.getPhotoList().remove(mPhotoAdapter.getPhotoList().size() - 1);
            mPhotoAdapter.notifyItemRemoved(mPhotoAdapter.getPhotoList().size());

            int oldCount = mPhotoAdapter.getPhotoList().size();
            mPhotoAdapter.getPhotoList().clear();
            mPhotoAdapter.getPhotoList().addAll(mNewPhotoList);
            mPhotoAdapter.notifyItemRangeInserted(oldCount, mPhotoAdapter.getPhotoList().size() - oldCount);

            mPhotoAdapter.setLoaded();
        }
    }

    /**
     * AsyncTask used to report the photo.
     */
    private class ReportTask extends AsyncTask<Integer, Void, String> {

        /**
         * The position in the list of the photo.
         */
        private int mPhotoPosition;

        @Override
        protected void onPreExecute() {
        }

        @Override
        protected String doInBackground(final Integer... params) {
            try {
                mPhotoPosition = params[0];
                long photoId = mPhotoAdapter.getPhotoList().get(mPhotoPosition).photoId;
                boolean res = ((MainActivity) getActivity()).getAbelanaClient().flagPhoto(photoId);
                return (res) ? null : getString(R.string.server_error);
            } catch (AbelanaClientException e) {
                return e.getMessage();
            }
        }

        @Override
        protected void onPostExecute(final String result) {
            if (result != null) {
                showErrorMessage(result);
            } else {
                mPhotoAdapter.getPhotoList().remove(mPhotoPosition);
                mPhotoAdapter.notifyItemRemoved(mPhotoPosition);
            }
        }
    }

    /**
     * AsyncTask used to edit a photo.
     */
    private class EditTask extends AsyncTask<String, Void, String> {

        /**
         * The position in the list of the photo.
         */
        private int mPhotoPosition;

        /**
         * The new description.
         */
        private String mDescription;

        @Override
        protected void onPreExecute() {
        }

        @Override
        protected String doInBackground(final String... params) {
            try {
                mPhotoPosition = mPhotoAdapter.getPosition();
                long photoId = mPhotoAdapter.getPhotoList().get(mPhotoPosition).photoId;
                mDescription = params[0];
                if (mDescription.length() < 1) {
                    return getString(R.string.upload_photo_description_missing);
                }
                boolean res = ((MainActivity) getActivity()).getAbelanaClient().editPhoto(photoId, mDescription);
                return (res) ? null : getString(R.string.server_error);
            } catch (AbelanaClientException e) {
                return e.getMessage();
            }
        }

        @Override
        protected void onPostExecute(final String result) {
            if (result != null) {
                showErrorMessage(result);
            } else {
                PhotoInfo photo = mPhotoAdapter.getPhotoList().get(mPhotoPosition);
                photo.description = mDescription;
                mPhotoAdapter.getPhotoList().set(mPhotoPosition, photo);
                mPhotoAdapter.notifyItemChanged(mPhotoPosition);
            }
        }
    }

    /**
     * AsyncTask used to delete a photo.
     */
    private class DeleteTask extends AsyncTask<Void, Void, String> {

        /**
         * The position in the list of the photo.
         */
        private int mPhotoPosition;

        @Override
        protected void onPreExecute() {
        }

        @Override
        protected String doInBackground(final Void... params) {
            try {
                mPhotoPosition = mPhotoAdapter.getPosition();
                long photoId = mPhotoAdapter.getPhotoList().get(mPhotoPosition).photoId;
                boolean res = ((MainActivity) getActivity()).getAbelanaClient().deletePhoto(photoId);
                return (res) ? null : getString(R.string.server_error);
            } catch (AbelanaClientException e) {
                return e.getMessage();
            }
        }

        @Override
        protected void onPostExecute(final String result) {
            if (result != null) {
                showErrorMessage(result);
            } else {
                mPhotoAdapter.getPhotoList().remove(mPhotoPosition);
                mPhotoAdapter.notifyItemRemoved(mPhotoPosition);
            }
        }
    }

    /**
     * AsyncTask used to vote for a photo.
     */
    private class VoteTask extends AsyncTask<Integer, Void, String> {

        /**
         * The position in the list of the photo.
         */
        private int mPhotoPosition;
        /**
         * The new vote.
         */
        private int mVote;

        @Override
        protected void onPreExecute() {
        }

        @Override
        protected String doInBackground(final Integer... params) {
            try {
                mPhotoPosition = mPhotoAdapter.getPosition();
                mVote = params[0];
                long photoId = mPhotoAdapter.getPhotoList().get(mPhotoPosition).photoId;
                boolean res = ((MainActivity) getActivity()).getAbelanaClient().votePhoto(photoId, mVote);
                return (res) ? null : getString(R.string.server_error);
            } catch (AbelanaClientException e) {
                return e.getMessage();
            }
        }

        @Override
        protected void onPostExecute(final String result) {
            if (result != null) {
                showErrorMessage(result);
            } else {
                PhotoInfo photo = mPhotoAdapter.getPhotoList().get(mPhotoPosition);
                photo.vote = mVote;
                mPhotoAdapter.getPhotoList().set(mPhotoPosition, photo);
            }
            mPhotoAdapter.notifyItemChanged(mPhotoPosition);
        }
    }

    /**
     * AsyncTask used to set a photo as Wallapper.
     */
    private class WallpaperTask extends AsyncTask<Void, Void, String> {

        /**
         * The position in the list of the photo.
         */
        private int mPhotoPosition;

        @Override
        protected void onPreExecute() {
        }

        @Override
        protected String doInBackground(final Void... params) {
            try {
                mPhotoPosition = mPhotoAdapter.getPosition();
                String url = mPhotoAdapter.getPhotoList().get(mPhotoPosition).url;
                url = url.replace(".webp", "_o" + ".webp");
                WallpaperManager wpm = WallpaperManager.getInstance(getActivity().getApplicationContext());
                InputStream ins = new URL(url).openStream();
                wpm.setStream(ins);
                return null;
            } catch (IOException e) {
                return getString(R.string.wallpaper_error);
            }
        }

        @Override
        protected void onPostExecute(final String result) {
            if (result != null) {
                showErrorMessage(result);
            }
        }
    }

    /**
     * Displays a Toast with an error message.
     * @param message the message to display.
     */
    private void showErrorMessage(String message) {
        Toast.makeText(getActivity().getApplicationContext(), message, Toast.LENGTH_LONG).show();

        // If it is an auth error, let's redirect the user also
        if (message.equals(getString(R.string.abelana_auth_error_message))) {
            ((MainActivity) getActivity()).startGitkitActivity();
        }
    }
}