/* * Copyright 2014 Artem Chikin * Copyright 2014 Artem Herasymchuk * Copyright 2014 Tom Krywitsky * Copyright 2014 Henry Pabst * Copyright 2014 Bradley Simons * * 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 ca.ualberta.cmput301w14t08.geochan.fragments; import java.io.File; import java.io.FileNotFoundException; import java.io.IOException; import java.math.RoundingMode; import java.text.DecimalFormat; import java.util.ArrayList; import android.app.Activity; import android.app.AlertDialog; import android.app.ProgressDialog; import android.content.Context; import android.content.DialogInterface; import android.content.Intent; import android.graphics.Bitmap; import android.graphics.BitmapFactory; import android.media.ThumbnailUtils; import android.net.Uri; import android.os.Bundle; import android.provider.MediaStore; import android.support.v4.app.Fragment; import android.text.method.ScrollingMovementMethod; 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.view.inputmethod.InputMethodManager; import android.widget.Button; import android.widget.EditText; import android.widget.TextView; import ca.ualberta.cmput301w14t08.geochan.R; import ca.ualberta.cmput301w14t08.geochan.helpers.ImageHelper; import ca.ualberta.cmput301w14t08.geochan.helpers.Toaster; import ca.ualberta.cmput301w14t08.geochan.managers.CacheManager; import ca.ualberta.cmput301w14t08.geochan.managers.ThreadManager; import ca.ualberta.cmput301w14t08.geochan.models.Comment; import ca.ualberta.cmput301w14t08.geochan.models.FavouritesLog; import ca.ualberta.cmput301w14t08.geochan.models.GeoLocation; import ca.ualberta.cmput301w14t08.geochan.models.ThreadComment; import ca.ualberta.cmput301w14t08.geochan.models.ThreadList; /** * Allows the user to edit the text, location, and image of a comment * they have made. The user can only edit a comment that they have made if * their current hash (based on device ID and current username) matches the * hash stored in the Comment being edited. * * @author Henry Pabst * */ public class EditFragment extends Fragment { private static final int MAX_BITMAP_DIMENSIONS = 900; private Comment editComment; private ThreadComment thread; private EditText newTextPost; /** * The original thumbnail of the Comment being edited. Contained as a variable in * EditCommentFragment so that it persists and does not change as the user alters the * original Comment. */ private static Bitmap oldThumbnail; /** * The original text of the Comment being edited. Contained as a variable in * EditCommentFragment so that it persists and does not change as the user alters the * original Comment. */ private static String oldText; private boolean isThread; private File imageFile; /** * Initializes the UI of our fragment. Called only by Android. * * @param inflater The LayoutInflater to inflate any Views in the fragment. * @param container The parent View the fragment is attached to. * @param savedInstanceState Previous saved state of the fragment. */ @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { setHasOptionsMenu(false); return inflater.inflate(R.layout.fragment_edit, container, false); } /** * Creates and initialzes the menu of the fragment. Called only by Android. * * @param menu The Menu object for the fragment. * @param inflater The inflater for the menu. */ @Override public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) { // Inflate the menu; this adds items to the action bar if it is present. MenuItem item = menu.findItem(R.id.action_settings); item.setVisible(true); super.onCreateOptionsMenu(menu, inflater); } @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); } /** * Overriden method from Fragment. Determines the Comment being edited based on the id * contained in fragment arguments as well as the ThreadComment containing said Comment. * After the Comment is found the appropriate UI elements and state variables are set. */ @Override public void onStart() { super.onStart(); Bundle bundle = getArguments(); String commentId = bundle.getString("commentId"); int threadIndex = bundle.getInt("threadIndex"); boolean fromFavs = bundle.getBoolean("fromFavs"); if(fromFavs == true){ FavouritesLog log = FavouritesLog.getInstance(getActivity()); thread = log.getThreads().get(threadIndex); } else { thread = ThreadList.getThreads().get(threadIndex); } if (thread.getBodyComment().getId().equals(commentId)){ editComment = thread.getBodyComment(); isThread = true; } else { getCommentFromId(commentId, thread.getBodyComment().getChildren()); isThread = false; } if (EditFragment.oldText == null){ EditFragment.oldText = editComment.getTextPost(); TextView oldTextView = (TextView) getActivity().findViewById(R.id.old_comment_text); oldTextView.setText(EditFragment.oldText); } if (EditFragment.oldThumbnail == null && editComment.getImageThumb() != null) { EditFragment.oldThumbnail = editComment.getImageThumb(); } newTextPost = (EditText) getActivity().findViewById(R.id.editBody); newTextPost.setText(editComment.getTextPost()); newTextPost.setMovementMethod(new ScrollingMovementMethod()); } /** * Overriden method from Fragment. Sets the appropriate TextView and ImageView * if the user is returning from changing the location or image. If the user is * returning from changing the location, the new coordinates are placed on the * edit_location_button Button. */ @Override public void onResume() { super.onResume(); Bundle args = getArguments(); if (EditFragment.oldText != null) { TextView oldTextView = (TextView) getActivity().findViewById(R.id.old_comment_text); oldTextView.setText(EditFragment.oldText); } if (args != null) { if (args.containsKey("LATITUDE") && args.containsKey("LONGITUDE")) { Button locButton = (Button) getActivity().findViewById(R.id.edit_location_button); if (args.getString("LocationType") == "CURRENT_LOCATION") { locButton.setText("Current Location"); } else { GeoLocation geoLocation = editComment.getLocation(); Double lat = args.getDouble("LATITUDE"); Double lon = args.getDouble("LONGITUDE"); geoLocation.setCoordinates(lat, lon); String locationDescription = args.getString("locationDescription"); geoLocation.setLocationDescription(locationDescription); DecimalFormat format = new DecimalFormat(); format.setRoundingMode(RoundingMode.HALF_EVEN); format.setMinimumFractionDigits(0); format.setMaximumFractionDigits(4); locButton.setText("Location: Set"); } } } } /** * Sets the text post of the Comment being edited to the value entered into the * EditText by the user. */ @Override public void onPause() { super.onPause(); editComment.setTextPost(newTextPost.getText().toString()); } @Override public void onStop() { super.onStop(); } /** * Recursively finds the Comment with the passed ID and sets it to * the variable editComment. If a Comment with the passed ID is not * found in the passed ArrayList of Comments then the method is recursively * called on the children of Comments in the ArrayList. * @param id The ID of the comment to be found. * @param comments An ArrayList of Comments to start searching in. */ public void getCommentFromId(String id, ArrayList<Comment> comments){ for(Comment com: comments){ if(com.getId().equals(id)){ editComment = com; return; } else { getCommentFromId(id, com.getChildren()); } } return; } /** * Allows the user to change the image attached to their comment or remove it * entirely. Prompts the user with an AlertDialog as to which option they would like * to select. * @param view The Button pressed to call editImage. */ public void editImage(View view) { if (view.getId() == R.id.attach_image_button) { AlertDialog.Builder dialog = new AlertDialog.Builder(getActivity()); dialog.setTitle(R.string.attach_image_title); dialog.setMessage(R.string.attach_image_dialog); dialog.setPositiveButton("Gallery", new DialogInterface.OnClickListener() { public void onClick(DialogInterface arg0, int arg1) { Intent intent = new Intent(); intent.setType("image/*"); intent.setAction(Intent.ACTION_GET_CONTENT); startActivityForResult(Intent.createChooser(intent, "Test"), ImageHelper.REQUEST_GALLERY); } }); dialog.setNegativeButton("Camera", new DialogInterface.OnClickListener() { public void onClick(DialogInterface arg0, int arg1) { Intent intent = new Intent(); intent.setAction(MediaStore.ACTION_IMAGE_CAPTURE); try { imageFile = ImageHelper.createImageFile(); intent.putExtra(MediaStore.EXTRA_OUTPUT, Uri.fromFile(imageFile)); startActivityForResult(Intent.createChooser(intent, "Test"), ImageHelper.REQUEST_CAMERA); } catch (IOException e) { e.printStackTrace(); } } }); dialog.setNeutralButton("Remove Image", new DialogInterface.OnClickListener() { public void onClick(DialogInterface arg0, int arg1) { editComment.setImage(null); editComment.setImageThumb(null); } }); dialog.show(); } } /** * Overriden method from Fragment. Sets the image and thumbnail in the comment being * edited to the user selected image. Is called automatically after the user * returns from selecting an image from either the camera or photo gallery. * * @param requestCode The request code supplied to startActivityForResult. * @param resultCode The result code returned by the activity. * @param data The data returned by the activity. */ @Override public void onActivityResult(int requestCode, int resultCode, Intent data) { super.onActivityResult(requestCode, resultCode, data); Bitmap image = null; if (resultCode == Activity.RESULT_OK) { if (requestCode == ImageHelper.REQUEST_CAMERA) { Bitmap imageBitmap = null; try { imageBitmap = BitmapFactory.decodeStream(getActivity().getContentResolver().openInputStream(Uri.fromFile(imageFile))); } catch (FileNotFoundException e) { Toaster.toastShort("Error. Could not load image."); } image = scaleImage(imageBitmap); } else if (requestCode == ImageHelper.REQUEST_GALLERY) { Bitmap imageBitmap = null; try { imageBitmap = MediaStore.Images.Media.getBitmap(getActivity() .getContentResolver(), data.getData()); } catch (FileNotFoundException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } image = scaleImage(imageBitmap); } } editComment.setImage(image); Bitmap imageThumb = ThumbnailUtils.extractThumbnail(image, 100, 100); editComment.setImageThumb(imageThumb); } /** * Scales the passed bitmap down so that it does not exceed the * maximum dimensions specified in EditCommentFragment.MAX_BITMAP_DIMENSIONS. * @param bitmap The bitmap that is to be scaled down. * @return A new Bitmap that is a scaled down version of the passed Bitmap. */ private Bitmap scaleImage(Bitmap bitmap) { if (bitmap.getWidth() > MAX_BITMAP_DIMENSIONS || bitmap.getHeight() > MAX_BITMAP_DIMENSIONS) { double scalingFactor = bitmap.getWidth() * 1.0 / MAX_BITMAP_DIMENSIONS; if (bitmap.getHeight() > bitmap.getWidth()) scalingFactor = bitmap.getHeight() * 1.0 / MAX_BITMAP_DIMENSIONS; int newWidth = (int) Math.round(bitmap.getWidth() / scalingFactor); int newHeight = (int) Math.round(bitmap.getHeight() / scalingFactor); bitmap = Bitmap.createScaledBitmap(bitmap, newWidth, newHeight, true); } return bitmap; } /** * Sets the text of the comment being edited to the new text entered by the user, * sets the value of EditCommentFragment.oldText and EditCommentFragment.oldThumbnail * to null so that the state isn't preserved across comment edits, and returns the * user to their previous fragment. * * @param view The button that was pressed to call makeEdit. */ public void makeEdit(View view) { EditFragment.oldText = null; EditFragment.oldThumbnail = null; editComment.setTextPost(newTextPost.getText().toString()); ProgressDialog dialog = new ProgressDialog(getActivity()); dialog.setMessage("Posting to Server"); if (isThread) { String threadTitle = thread.getTitle(); thread.setBodyComment(editComment); ThreadManager.startPost(editComment, threadTitle, editComment.getLocation(), dialog, true); CacheManager.getInstance().serializeThreadList(ThreadList.getThreads()); } else { ThreadManager.startPost(editComment, null, editComment.getLocation(), dialog, true); } InputMethodManager inputManager = (InputMethodManager) getActivity().getSystemService( Context.INPUT_METHOD_SERVICE); inputManager.hideSoftInputFromWindow(view.getWindowToken(), InputMethodManager.HIDE_NOT_ALWAYS); getFragmentManager().popBackStackImmediate(); } }