diff --git a/app/MyHyvesBookPlusStagram/app/src/main/java/nl/myhyvesbookplus/tagram/ProfileAdapter.java b/app/MyHyvesBookPlusStagram/app/src/main/java/nl/myhyvesbookplus/tagram/ProfileAdapter.java index 3bff416..e73a816 100644 --- a/app/MyHyvesBookPlusStagram/app/src/main/java/nl/myhyvesbookplus/tagram/ProfileAdapter.java +++ b/app/MyHyvesBookPlusStagram/app/src/main/java/nl/myhyvesbookplus/tagram/ProfileAdapter.java @@ -1,15 +1,22 @@ package nl.myhyvesbookplus.tagram; import android.content.Context; +import android.graphics.Point; +import android.graphics.Rect; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; +import android.view.animation.DecelerateInterpolator; import android.widget.BaseAdapter; import android.widget.Button; import android.widget.ImageButton; import android.widget.ImageView; import android.widget.ListView; import android.widget.TextView; +import android.animation.Animator; +import android.animation.AnimatorListenerAdapter; +import android.animation.AnimatorSet; +import android.animation.ObjectAnimator; import com.bumptech.glide.Glide; import com.firebase.ui.storage.images.FirebaseImageLoader; @@ -33,6 +40,7 @@ public class ProfileAdapter extends BaseAdapter { private TextView comment; private TextView nietSlechts; private ImageView photo; + private Animator mCurrentAnimator; ProfileAdapter(Context context, ArrayList data) { mContext = context; @@ -61,12 +69,19 @@ public class ProfileAdapter extends BaseAdapter { View newRowView = findViews(rowView); UriPost post = (UriPost) getItem(position); comment.setText(post.getComment()); - StorageReference ref = FirebaseStorage.getInstance().getReferenceFromUrl(post.getUri()); + final StorageReference ref = FirebaseStorage.getInstance().getReferenceFromUrl(post.getUri()); Glide.with(mContext) .using(new FirebaseImageLoader()) .load(ref) .into(photo); + photo.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + zoomImageFromThumb(photo, ref); + } + }); + return newRowView; } @@ -76,4 +91,141 @@ public class ProfileAdapter extends BaseAdapter { photo = (ImageView) rowView.findViewById(R.id.timeline_image_profile); return rowView; } + + /** + * https://developer.android.com/training/animation/zoom.html + * "Zooms" in a thumbnail view by assigning the high resolution image to a hidden "zoomed-in" + * image view and animating its bounds to fit the entire activity content area. + * + * @param thumbView The thumbnail view to zoom in. + * @param imageRef The high-resolution version of the image represented by the thumbnail. + */ + private void zoomImageFromThumb(final View thumbView, StorageReference imageRef) { + // If there's an animation in progress, cancel it immediately and proceed with this one. + if (mCurrentAnimator != null) { + mCurrentAnimator.cancel(); + } + + // Load the high-resolution "zoomed-in" image. + final ImageView hiddenView = (ImageView) ((MainActivity) mContext).findViewById(R.id.expanded_image_profile); + + Glide.with(mContext) + .using(new FirebaseImageLoader()) + .load(imageRef) + .into(hiddenView); + + // Calculate the starting and ending bounds for the zoomed-in image. This step + // involves lots of math. Yay, math. + final Rect startBounds = new Rect(); + final Rect finalBounds = new Rect(); + final Point globalOffset = new Point(); + + // The start bounds are the global visible rectangle of the thumbnail, and the + // final bounds are the global visible rectangle of the container view. Also + // set the container view's offset as the origin for the bounds, since that's + // the origin for the positioning animation properties (X, Y). + thumbView.getGlobalVisibleRect(startBounds); + ((MainActivity) mContext).findViewById(R.id.relative_layout_timeline_profile).getGlobalVisibleRect(finalBounds, globalOffset); + startBounds.offset(-globalOffset.x, -globalOffset.y); + finalBounds.offset(-globalOffset.x, -globalOffset.y); + + // Adjust the start bounds to be the same aspect ratio as the final bounds using the + // "center crop" technique. This prevents undesirable stretching during the animation. + // Also calculate the start scaling factor (the end scaling factor is always 1.0). + float startScale; + if ((float) finalBounds.width() / finalBounds.height() + > (float) startBounds.width() / startBounds.height()) { + // Extend start bounds horizontally + startScale = (float) startBounds.height() / finalBounds.height(); + float startWidth = startScale * finalBounds.width(); + float deltaWidth = (startWidth - startBounds.width()) / 2; + startBounds.left -= deltaWidth; + startBounds.right += deltaWidth; + } else { + // Extend start bounds vertically + startScale = (float) startBounds.width() / finalBounds.width(); + float startHeight = startScale * finalBounds.height(); + float deltaHeight = (startHeight - startBounds.height()) / 2; + startBounds.top -= deltaHeight; + startBounds.bottom += deltaHeight; + } + + // Hide the thumbnail and show the zoomed-in view. When the animation begins, + // it will position the zoomed-in view in the place of the thumbnail. + thumbView.setAlpha(0f); + hiddenView.setVisibility(View.VISIBLE); + + // Set the pivot point for SCALE_X and SCALE_Y transformations to the top-left corner of + // the zoomed-in view (the default is the center of the view). + hiddenView.setPivotX(0f); + hiddenView.setPivotY(0f); + + // Construct and run the parallel animation of the four translation and scale properties + // (X, Y, SCALE_X, and SCALE_Y). + AnimatorSet set = new AnimatorSet(); + set + .play(ObjectAnimator.ofFloat(hiddenView, View.X, startBounds.left, + finalBounds.left)) + .with(ObjectAnimator.ofFloat(hiddenView, View.Y, startBounds.top, + finalBounds.top)) + .with(ObjectAnimator.ofFloat(hiddenView, View.SCALE_X, startScale, 1f)) + .with(ObjectAnimator.ofFloat(hiddenView, View.SCALE_Y, startScale, 1f)); + set.setDuration(200); + set.setInterpolator(new DecelerateInterpolator()); + set.addListener(new AnimatorListenerAdapter() { + @Override + public void onAnimationEnd(Animator animation) { + mCurrentAnimator = null; + } + + @Override + public void onAnimationCancel(Animator animation) { + mCurrentAnimator = null; + } + }); + set.start(); + mCurrentAnimator = set; + + // Upon clicking the zoomed-in image, it should zoom back down to the original bounds + // and show the thumbnail instead of the expanded image. + final float startScaleFinal = startScale; + hiddenView.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View view) { + if (mCurrentAnimator != null) { + mCurrentAnimator.cancel(); + } + + // Animate the four positioning/sizing properties in parallel, back to their + // original values. + AnimatorSet set = new AnimatorSet(); + set + .play(ObjectAnimator.ofFloat(hiddenView, View.X, startBounds.left)) + .with(ObjectAnimator.ofFloat(hiddenView, View.Y, startBounds.top)) + .with(ObjectAnimator + .ofFloat(hiddenView, View.SCALE_X, startScaleFinal)) + .with(ObjectAnimator + .ofFloat(hiddenView, View.SCALE_Y, startScaleFinal)); + set.setDuration(200); + set.setInterpolator(new DecelerateInterpolator()); + set.addListener(new AnimatorListenerAdapter() { + @Override + public void onAnimationEnd(Animator animation) { + thumbView.setAlpha(1f); + hiddenView.setVisibility(View.GONE); + mCurrentAnimator = null; + } + + @Override + public void onAnimationCancel(Animator animation) { + thumbView.setAlpha(1f); + hiddenView.setVisibility(View.GONE); + mCurrentAnimator = null; + } + }); + set.start(); + mCurrentAnimator = set; + } + }); + } } diff --git a/app/MyHyvesBookPlusStagram/app/src/main/java/nl/myhyvesbookplus/tagram/TimeLineAdapter.java b/app/MyHyvesBookPlusStagram/app/src/main/java/nl/myhyvesbookplus/tagram/TimeLineAdapter.java index 3d6cbb4..ed92a63 100644 --- a/app/MyHyvesBookPlusStagram/app/src/main/java/nl/myhyvesbookplus/tagram/TimeLineAdapter.java +++ b/app/MyHyvesBookPlusStagram/app/src/main/java/nl/myhyvesbookplus/tagram/TimeLineAdapter.java @@ -1,21 +1,30 @@ package nl.myhyvesbookplus.tagram; import android.content.Context; +import android.graphics.Point; +import android.graphics.Rect; +import android.support.annotation.NonNull; import android.util.Log; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; +import android.view.animation.DecelerateInterpolator; import android.widget.AdapterView; import android.widget.BaseAdapter; -import android.widget.Button; import android.widget.ImageButton; import android.widget.ImageView; import android.widget.TextView; +import android.animation.Animator; +import android.animation.AnimatorListenerAdapter; +import android.animation.AnimatorSet; +import android.animation.ObjectAnimator; import com.bumptech.glide.Glide; import com.firebase.ui.storage.images.FirebaseImageLoader; -import com.google.firebase.auth.FirebaseAuth; -import com.google.firebase.auth.FirebaseUser; +import com.google.android.gms.tasks.OnCompleteListener; +import com.google.android.gms.tasks.Task; +import com.google.firebase.database.DatabaseReference; +import com.google.firebase.database.FirebaseDatabase; import com.google.firebase.storage.FirebaseStorage; import com.google.firebase.storage.StorageReference; @@ -32,11 +41,14 @@ public class TimeLineAdapter extends BaseAdapter implements AdapterView.OnItemCl private LayoutInflater mInflater; private Context mContext; private ArrayList mData; + private DatabaseReference mRef; + private Animator mCurrentAnimator; TimeLineAdapter(Context context, ArrayList data) { mContext = context; mInflater = (LayoutInflater) mContext.getSystemService(Context.LAYOUT_INFLATER_SERVICE); mData = data; + mRef = FirebaseDatabase.getInstance().getReference(); } @Override @@ -55,39 +67,54 @@ public class TimeLineAdapter extends BaseAdapter implements AdapterView.OnItemCl } @Override - public View getView(int position, View convertView, ViewGroup parent) { + public View getView(final int position, View convertView, ViewGroup parent) { View rowView = mInflater.inflate(R.layout.list_item_timeline, parent, false); TextView userName = (TextView) rowView.findViewById(R.id.username_timeline); TextView comment = (TextView) rowView.findViewById(R.id.comment_timeline); - TextView nietSlechts = (TextView) rowView.findViewById(R.id.niet_slecht_count); - ImageView photo = (ImageView) rowView.findViewById(R.id.timeline_image); - Button nietSlechtButton = (Button) rowView.findViewById(R.id.niet_slecht_button); + final TextView nietSlechts = (TextView) rowView.findViewById(R.id.niet_slecht_count); + TextView dateTime = (TextView) rowView.findViewById(R.id.timeline_date); + final ImageView photo = (ImageView) rowView.findViewById(R.id.timeline_image); + final ImageButton nietSlechtButton = (ImageButton) rowView.findViewById(R.id.niet_slecht_button); + + final UriPost post = (UriPost) getItem(position); + + nietSlechts.setText(Integer.toString(post.getNietSlechts())); + comment.setText(post.getComment()); nietSlechtButton.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { - + Log.d(TAG, "onClick: " + position); + mRef.child("posts").child(post.getDatabaseEntryName()) + .child("nietSlechts").setValue(post.getNietSlechts() + 1) + .addOnCompleteListener(new OnCompleteListener() { + @Override + public void onComplete(@NonNull Task task) { + nietSlechts.setText(Integer.toString(post.getNietSlechts() + 1)); + } + }); } }); - UriPost post = (UriPost) getItem(position); + dateTime.setText(post.getDate().toString()); - userName.setText(post.getPoster()); - nietSlechts.setText(Integer.toString(post.getNietSlechts())); - comment.setText(post.getComment()); - - StorageReference ref = FirebaseStorage.getInstance().getReferenceFromUrl(post.getUri()); + final StorageReference ref = FirebaseStorage.getInstance().getReferenceFromUrl(post.getUri()); Glide.with(mContext) .using(new FirebaseImageLoader()) .load(ref) .into(photo); + photo.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + zoomImageFromThumb(photo, ref); + } + }); return rowView; } - /** * Callback method to be invoked when an item in this AdapterView has * been clicked. @@ -106,4 +133,140 @@ public class TimeLineAdapter extends BaseAdapter implements AdapterView.OnItemCl Log.d(TAG, "onItemClick: rowNumber! "+ position); } + /** + * https://developer.android.com/training/animation/zoom.html + * "Zooms" in a thumbnail view by assigning the high resolution image to a hidden "zoomed-in" + * image view and animating its bounds to fit the entire activity content area. + * + * @param thumbView The thumbnail view to zoom in. + * @param imageRef The high-resolution version of the image represented by the thumbnail. + */ + private void zoomImageFromThumb(final View thumbView, StorageReference imageRef) { + // If there's an animation in progress, cancel it immediately and proceed with this one. + if (mCurrentAnimator != null) { + mCurrentAnimator.cancel(); + } + + // Load the high-resolution "zoomed-in" image. + final ImageView hiddenView = (ImageView) ((MainActivity) mContext).findViewById(R.id.expanded_image); + + Glide.with(mContext) + .using(new FirebaseImageLoader()) + .load(imageRef) + .into(hiddenView); + + // Calculate the starting and ending bounds for the zoomed-in image. This step + // involves lots of math. Yay, math. + final Rect startBounds = new Rect(); + final Rect finalBounds = new Rect(); + final Point globalOffset = new Point(); + + // The start bounds are the global visible rectangle of the thumbnail, and the + // final bounds are the global visible rectangle of the container view. Also + // set the container view's offset as the origin for the bounds, since that's + // the origin for the positioning animation properties (X, Y). + thumbView.getGlobalVisibleRect(startBounds); + ((MainActivity) mContext).findViewById(R.id.relative_layout_timeline).getGlobalVisibleRect(finalBounds, globalOffset); + startBounds.offset(-globalOffset.x, -globalOffset.y); + finalBounds.offset(-globalOffset.x, -globalOffset.y); + + // Adjust the start bounds to be the same aspect ratio as the final bounds using the + // "center crop" technique. This prevents undesirable stretching during the animation. + // Also calculate the start scaling factor (the end scaling factor is always 1.0). + float startScale; + if ((float) finalBounds.width() / finalBounds.height() + > (float) startBounds.width() / startBounds.height()) { + // Extend start bounds horizontally + startScale = (float) startBounds.height() / finalBounds.height(); + float startWidth = startScale * finalBounds.width(); + float deltaWidth = (startWidth - startBounds.width()) / 2; + startBounds.left -= deltaWidth; + startBounds.right += deltaWidth; + } else { + // Extend start bounds vertically + startScale = (float) startBounds.width() / finalBounds.width(); + float startHeight = startScale * finalBounds.height(); + float deltaHeight = (startHeight - startBounds.height()) / 2; + startBounds.top -= deltaHeight; + startBounds.bottom += deltaHeight; + } + + // Hide the thumbnail and show the zoomed-in view. When the animation begins, + // it will position the zoomed-in view in the place of the thumbnail. + thumbView.setAlpha(0f); + hiddenView.setVisibility(View.VISIBLE); + + // Set the pivot point for SCALE_X and SCALE_Y transformations to the top-left corner of + // the zoomed-in view (the default is the center of the view). + hiddenView.setPivotX(0f); + hiddenView.setPivotY(0f); + + // Construct and run the parallel animation of the four translation and scale properties + // (X, Y, SCALE_X, and SCALE_Y). + AnimatorSet set = new AnimatorSet(); + set + .play(ObjectAnimator.ofFloat(hiddenView, View.X, startBounds.left, + finalBounds.left)) + .with(ObjectAnimator.ofFloat(hiddenView, View.Y, startBounds.top, + finalBounds.top)) + .with(ObjectAnimator.ofFloat(hiddenView, View.SCALE_X, startScale, 1f)) + .with(ObjectAnimator.ofFloat(hiddenView, View.SCALE_Y, startScale, 1f)); + set.setDuration(200); + set.setInterpolator(new DecelerateInterpolator()); + set.addListener(new AnimatorListenerAdapter() { + @Override + public void onAnimationEnd(Animator animation) { + mCurrentAnimator = null; + } + + @Override + public void onAnimationCancel(Animator animation) { + mCurrentAnimator = null; + } + }); + set.start(); + mCurrentAnimator = set; + + // Upon clicking the zoomed-in image, it should zoom back down to the original bounds + // and show the thumbnail instead of the expanded image. + final float startScaleFinal = startScale; + hiddenView.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View view) { + if (mCurrentAnimator != null) { + mCurrentAnimator.cancel(); + } + + // Animate the four positioning/sizing properties in parallel, back to their + // original values. + AnimatorSet set = new AnimatorSet(); + set + .play(ObjectAnimator.ofFloat(hiddenView, View.X, startBounds.left)) + .with(ObjectAnimator.ofFloat(hiddenView, View.Y, startBounds.top)) + .with(ObjectAnimator + .ofFloat(hiddenView, View.SCALE_X, startScaleFinal)) + .with(ObjectAnimator + .ofFloat(hiddenView, View.SCALE_Y, startScaleFinal)); + set.setDuration(200); + set.setInterpolator(new DecelerateInterpolator()); + set.addListener(new AnimatorListenerAdapter() { + @Override + public void onAnimationEnd(Animator animation) { + thumbView.setAlpha(1f); + hiddenView.setVisibility(View.GONE); + mCurrentAnimator = null; + } + + @Override + public void onAnimationCancel(Animator animation) { + thumbView.setAlpha(1f); + hiddenView.setVisibility(View.GONE); + mCurrentAnimator = null; + } + }); + set.start(); + mCurrentAnimator = set; + } + }); + } } diff --git a/app/MyHyvesBookPlusStagram/app/src/main/java/nl/myhyvesbookplus/tagram/controller/DownloadClass.java b/app/MyHyvesBookPlusStagram/app/src/main/java/nl/myhyvesbookplus/tagram/controller/DownloadClass.java index 819b772..50cbf40 100644 --- a/app/MyHyvesBookPlusStagram/app/src/main/java/nl/myhyvesbookplus/tagram/controller/DownloadClass.java +++ b/app/MyHyvesBookPlusStagram/app/src/main/java/nl/myhyvesbookplus/tagram/controller/DownloadClass.java @@ -42,8 +42,9 @@ public class DownloadClass { public void onDataChange(DataSnapshot dataSnapshot) { for (DataSnapshot data : dataSnapshot.getChildren()) { - - mList.add(data.getValue(UriPost.class)); + UriPost tempPost = data.getValue(UriPost.class); + tempPost.setDatabaseEntryName(data.getKey()); + mList.add(tempPost); } Collections.reverse(mList); diff --git a/app/MyHyvesBookPlusStagram/app/src/main/java/nl/myhyvesbookplus/tagram/model/UriPost.java b/app/MyHyvesBookPlusStagram/app/src/main/java/nl/myhyvesbookplus/tagram/model/UriPost.java index 25358be..dc7ae7c 100644 --- a/app/MyHyvesBookPlusStagram/app/src/main/java/nl/myhyvesbookplus/tagram/model/UriPost.java +++ b/app/MyHyvesBookPlusStagram/app/src/main/java/nl/myhyvesbookplus/tagram/model/UriPost.java @@ -9,6 +9,7 @@ import java.util.Date; */ public class UriPost extends Post { private String uri; + private String databaseEntryName; public UriPost() { // Default constructor required for calls to DataSnapshot.getValue(UriPost.class) @@ -33,4 +34,12 @@ public class UriPost extends Post { public void setUri(String uri) { this.uri = uri; } + + public String getDatabaseEntryName() { + return databaseEntryName; + } + + public void setDatabaseEntryName(String databaseEntryName) { + this.databaseEntryName = databaseEntryName; + } } \ No newline at end of file diff --git a/app/MyHyvesBookPlusStagram/app/src/main/res/layout/fragment_profile_timeline.xml b/app/MyHyvesBookPlusStagram/app/src/main/res/layout/fragment_profile_timeline.xml index ea8dc3c..db6056b 100644 --- a/app/MyHyvesBookPlusStagram/app/src/main/res/layout/fragment_profile_timeline.xml +++ b/app/MyHyvesBookPlusStagram/app/src/main/res/layout/fragment_profile_timeline.xml @@ -1,4 +1,5 @@ - - \ No newline at end of file + + + \ No newline at end of file diff --git a/app/MyHyvesBookPlusStagram/app/src/main/res/layout/fragment_timeline.xml b/app/MyHyvesBookPlusStagram/app/src/main/res/layout/fragment_timeline.xml index 68e3085..0fcfcef 100644 --- a/app/MyHyvesBookPlusStagram/app/src/main/res/layout/fragment_timeline.xml +++ b/app/MyHyvesBookPlusStagram/app/src/main/res/layout/fragment_timeline.xml @@ -1,4 +1,5 @@ - + - \ No newline at end of file + \ No newline at end of file diff --git a/app/MyHyvesBookPlusStagram/app/src/main/res/layout/list_item_timeline.xml b/app/MyHyvesBookPlusStagram/app/src/main/res/layout/list_item_timeline.xml index e4d92b8..045246a 100644 --- a/app/MyHyvesBookPlusStagram/app/src/main/res/layout/list_item_timeline.xml +++ b/app/MyHyvesBookPlusStagram/app/src/main/res/layout/list_item_timeline.xml @@ -1,8 +1,7 @@ + android:layout_height="250dp" + android:layout_gravity="center" /> - - -