From 5ae1d1f9646c68aa940426f54da9bf17c28e1ea7 Mon Sep 17 00:00:00 2001 From: Marijn Jansen Date: Thu, 29 Jun 2017 13:19:12 +0200 Subject: [PATCH 1/5] Added NietSlechts! --- .../tagram/TimeLineAdapter.java | 31 +++++++++++++------ .../tagram/controller/DownloadClass.java | 4 ++- .../myhyvesbookplus/tagram/model/UriPost.java | 9 ++++++ .../main/res/layout/list_item_timeline.xml | 14 ++++++--- 4 files changed, 43 insertions(+), 15 deletions(-) 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 7d4dda5..197765a 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,6 +1,7 @@ package nl.myhyvesbookplus.tagram; import android.content.Context; +import android.support.annotation.NonNull; import android.util.Log; import android.view.LayoutInflater; import android.view.View; @@ -13,6 +14,9 @@ import android.widget.TextView; import com.bumptech.glide.Glide; import com.firebase.ui.storage.images.FirebaseImageLoader; +import com.google.android.gms.tasks.OnCompleteListener; +import com.google.android.gms.tasks.Task; +import com.google.firebase.database.FirebaseDatabase; import com.google.firebase.storage.FirebaseStorage; import com.google.firebase.storage.StorageReference; @@ -52,26 +56,34 @@ 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 comment = (TextView) rowView.findViewById(R.id.comment_timeline); - TextView nietSlechts = (TextView) rowView.findViewById(R.id.niet_slecht_count); + final TextView nietSlechts = (TextView) rowView.findViewById(R.id.niet_slecht_count); + TextView dateTime = (TextView) rowView.findViewById(R.id.timeline_date); ImageView photo = (ImageView) rowView.findViewById(R.id.timeline_image); - ImageButton nietSlechtButton = (ImageButton) rowView.findViewById(R.id.niet_slecht_button); + 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); + FirebaseDatabase.getInstance().getReference().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); - - nietSlechts.setText(Integer.toString(post.getNietSlechts())); - comment.setText(post.getComment()); - StorageReference ref = FirebaseStorage.getInstance().getReferenceFromUrl(post.getUri()); Glide.with(mContext) .using(new FirebaseImageLoader()) @@ -82,7 +94,6 @@ public class TimeLineAdapter extends BaseAdapter implements AdapterView.OnItemCl return rowView; } - /** * Callback method to be invoked when an item in this AdapterView has * been clicked. 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 49697b4..3624cda 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 @@ -41,7 +41,9 @@ public class DownloadClass { @Override 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); mListener.PostDownloaded(); 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/list_item_timeline.xml b/app/MyHyvesBookPlusStagram/app/src/main/res/layout/list_item_timeline.xml index 0d2006f..e3f6fa4 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,15 +1,14 @@ + android:layout_height="250dp" + android:layout_gravity="center" /> + @@ -29,12 +33,14 @@ \ No newline at end of file From af47900288ec32f84bae5fa86d96cec293212e7b Mon Sep 17 00:00:00 2001 From: Marijn Jansen Date: Thu, 29 Jun 2017 13:21:58 +0200 Subject: [PATCH 2/5] Better name for niet slechts. --- .../app/src/main/res/values-nl/strings.xml | 2 +- app/MyHyvesBookPlusStagram/app/src/main/res/values/strings.xml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/app/MyHyvesBookPlusStagram/app/src/main/res/values-nl/strings.xml b/app/MyHyvesBookPlusStagram/app/src/main/res/values-nl/strings.xml index 57fc504..a100eee 100644 --- a/app/MyHyvesBookPlusStagram/app/src/main/res/values-nl/strings.xml +++ b/app/MyHyvesBookPlusStagram/app/src/main/res/values-nl/strings.xml @@ -30,5 +30,5 @@ Foto opslaan mislukt. Zorg a.u.b. dat er genoeg ruimte op uw telefoon beschikbaar is. Het updaten van de profielfoto is mislukt. Controleer uw internetverbinding. Profielfoto aan het uploaden… - "\"Niet slecht.\"s " + \"\"Niet slecht.\"s: \" \ No newline at end of file diff --git a/app/MyHyvesBookPlusStagram/app/src/main/res/values/strings.xml b/app/MyHyvesBookPlusStagram/app/src/main/res/values/strings.xml index 7f065d9..07a5a19 100644 --- a/app/MyHyvesBookPlusStagram/app/src/main/res/values/strings.xml +++ b/app/MyHyvesBookPlusStagram/app/src/main/res/values/strings.xml @@ -22,7 +22,7 @@ profile picture Change Password Please Wait - "\"Niet slecht.\"s " + \"\"Niet slecht.\"s: \" Upload Save An e-mail was sent. Please follow its instructions. From 71d412beac63fcd1364abd48d1fe9de564a72325 Mon Sep 17 00:00:00 2001 From: Marijn Jansen Date: Thu, 29 Jun 2017 13:28:19 +0200 Subject: [PATCH 3/5] Date works --- .../java/nl/myhyvesbookplus/tagram/TimeLineAdapter.java | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) 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 197765a..d412883 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 @@ -16,6 +16,7 @@ import com.bumptech.glide.Glide; import com.firebase.ui.storage.images.FirebaseImageLoader; 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; @@ -33,11 +34,13 @@ public class TimeLineAdapter extends BaseAdapter implements AdapterView.OnItemCl private LayoutInflater mInflater; private Context mContext; private ArrayList mData; + private DatabaseReference mRef; TimeLineAdapter(Context context, ArrayList data) { mContext = context; mInflater = (LayoutInflater) mContext.getSystemService(Context.LAYOUT_INFLATER_SERVICE); mData = data; + mRef = FirebaseDatabase.getInstance().getReference(); } @Override @@ -74,7 +77,8 @@ public class TimeLineAdapter extends BaseAdapter implements AdapterView.OnItemCl @Override public void onClick(View v) { Log.d(TAG, "onClick: " + position); - FirebaseDatabase.getInstance().getReference().child("posts").child(post.getDatabaseEntryName()).child("nietSlechts").setValue(post.getNietSlechts() + 1) + mRef.child("posts").child(post.getDatabaseEntryName()) + .child("nietSlechts").setValue(post.getNietSlechts() + 1) .addOnCompleteListener(new OnCompleteListener() { @Override public void onComplete(@NonNull Task task) { @@ -84,6 +88,8 @@ public class TimeLineAdapter extends BaseAdapter implements AdapterView.OnItemCl } }); + dateTime.setText(post.getDate().toString()); + StorageReference ref = FirebaseStorage.getInstance().getReferenceFromUrl(post.getUri()); Glide.with(mContext) .using(new FirebaseImageLoader()) From 7936350ede3f54593066bcff6ca9a0e83531249d Mon Sep 17 00:00:00 2001 From: Marijn Jansen Date: Thu, 29 Jun 2017 13:35:49 +0200 Subject: [PATCH 4/5] Fix! --- .../java/nl/myhyvesbookplus/tagram/TimeLineAdapter.java | 6 ------ 1 file changed, 6 deletions(-) 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 8146347..8282574 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 @@ -8,22 +8,16 @@ import android.view.View; import android.view.ViewGroup; 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 com.bumptech.glide.Glide; import com.firebase.ui.storage.images.FirebaseImageLoader; -<<<<<<< HEAD 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.auth.FirebaseAuth; -import com.google.firebase.auth.FirebaseUser; ->>>>>>> origin/master import com.google.firebase.storage.FirebaseStorage; import com.google.firebase.storage.StorageReference; From 0a7c49b3a3bff365239c8887b793c7ffff726e4d Mon Sep 17 00:00:00 2001 From: Paul Lagerweij Date: Thu, 29 Jun 2017 15:18:12 +0200 Subject: [PATCH 5/5] added animation --- .../tagram/ProfileAdapter.java | 154 +++++++++++++++++- .../tagram/TimeLineAdapter.java | 154 +++++++++++++++++- .../res/layout/fragment_profile_timeline.xml | 11 +- .../src/main/res/layout/fragment_timeline.xml | 10 +- 4 files changed, 322 insertions(+), 7 deletions(-) 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 357876a..0535f55 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 8282574..fb8c7ef 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,16 +1,23 @@ 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.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; @@ -35,6 +42,7 @@ public class TimeLineAdapter extends BaseAdapter implements AdapterView.OnItemCl private Context mContext; private ArrayList mData; private DatabaseReference mRef; + private Animator mCurrentAnimator; TimeLineAdapter(Context context, ArrayList data) { mContext = context; @@ -66,7 +74,7 @@ public class TimeLineAdapter extends BaseAdapter implements AdapterView.OnItemCl TextView comment = (TextView) rowView.findViewById(R.id.comment_timeline); final TextView nietSlechts = (TextView) rowView.findViewById(R.id.niet_slecht_count); TextView dateTime = (TextView) rowView.findViewById(R.id.timeline_date); - ImageView photo = (ImageView) rowView.findViewById(R.id.timeline_image); + 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); @@ -91,12 +99,18 @@ public class TimeLineAdapter extends BaseAdapter implements AdapterView.OnItemCl dateTime.setText(post.getDate().toString()); - 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; } @@ -119,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/res/layout/fragment_profile_timeline.xml b/app/MyHyvesBookPlusStagram/app/src/main/res/layout/fragment_profile_timeline.xml index fd06e94..56a00ad 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 fe7a080..effb17f 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