Java tutorial
/* * 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(); } } }