/* * Copyright (C) 2014 Freddie (Musenkishi) Lust-Hed * * 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.musenkishi.wally.fragments; import android.animation.ValueAnimator; import android.app.Dialog; import android.content.DialogInterface; import android.content.Intent; import android.graphics.Bitmap; import android.graphics.Rect; import android.net.Uri; import android.os.Bundle; import android.os.Handler; import android.support.v4.app.DialogFragment; import android.support.v4.app.FragmentManager; import android.view.Display; import android.view.View; import android.view.ViewGroup; import android.view.Window; import android.view.WindowManager; import android.webkit.MimeTypeMap; import android.widget.Button; import android.widget.RelativeLayout; import com.bumptech.glide.Glide; import com.bumptech.glide.load.resource.drawable.GlideDrawable; import com.bumptech.glide.request.RequestListener; import com.bumptech.glide.request.target.Target; import com.musenkishi.wally.R; import com.musenkishi.wally.anim.interpolator.LinearOutSlowInInterpolator; import com.musenkishi.wally.observers.FileReceiver; import uk.co.senab.photoview.PhotoView; import uk.co.senab.photoview.PhotoViewAttacher; /** * Fragment used for letting the user zoom in on the image provided * Created by Musenkishi on 2014-03-29. */ public class ImageZoomFragment extends DialogFragment { public static final String TAG = "com.musenkishi.wally.fragments.ImageZoomFragment"; private static final String STATE_BITMAP = TAG + ".bitmap"; private static final String STATE_TOOLBAR_VISIBILITY = TAG + ".toolBarVisibility"; private static final String STATE_URI_FILE = TAG + ".fileUri"; private static final String STATE_URI_CONTENT = TAG + ".contentUri"; private PhotoView zoomableImageView; private PhotoViewAttacher photoViewAttacher; private Bitmap bitmap; private ViewGroup toolBar; private View progressBar; private int toolBarVisibility = View.GONE; private Uri fileUri; private Uri contentUri; private Rect rect; private int statusBarHeightCorrection; private int position; public static ImageZoomFragment newInstance(Bitmap bitmap){ ImageZoomFragment fragment = new ImageZoomFragment(bitmap); Bundle args = new Bundle(); fragment.setArguments(args); return fragment; } public static ImageZoomFragment newInstance(Bitmap bitmap, Rect rect) { ImageZoomFragment fragment = new ImageZoomFragment(bitmap, rect); Bundle args = new Bundle(); fragment.setArguments(args); return fragment; } public static ImageZoomFragment newInstance(Uri fileUri){ ImageZoomFragment fragment = new ImageZoomFragment(fileUri); Bundle args = new Bundle(); fragment.setArguments(args); return fragment; } public static ImageZoomFragment newInstance(Uri fileUri, int position) { ImageZoomFragment fragment = new ImageZoomFragment(fileUri, position); Bundle args = new Bundle(); fragment.setArguments(args); return fragment; } public ImageZoomFragment() { } public ImageZoomFragment(Bitmap bitmap, Rect rect) { this.bitmap = bitmap; this.rect = rect; } public ImageZoomFragment(Bitmap bitmap){ this.bitmap = bitmap; } public ImageZoomFragment(Uri fileUri) { this.fileUri = fileUri; } public ImageZoomFragment(Uri fileUri, int position) { this.fileUri = fileUri; this.position = position; } @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setRetainInstance(true); if (savedInstanceState != null) { if (savedInstanceState.containsKey(STATE_BITMAP)){ bitmap = savedInstanceState.getParcelable(STATE_BITMAP); } if (savedInstanceState.containsKey(STATE_TOOLBAR_VISIBILITY)){ toolBarVisibility = savedInstanceState.getInt(STATE_TOOLBAR_VISIBILITY, View.GONE); } if (savedInstanceState.containsKey(STATE_URI_FILE)){ fileUri = savedInstanceState.getParcelable(STATE_URI_FILE); } if (savedInstanceState.containsKey(STATE_URI_CONTENT)){ contentUri = savedInstanceState.getParcelable(STATE_URI_CONTENT); } } } @Override public void onStart() { super.onStart(); // safety check if (getDialog() == null) { return; } // set the animations to use on showing and hiding the dialog getDialog().getWindow().setWindowAnimations( R.style.dialog_animation_fade); // alternative way of doing it //getDialog().getWindow().getAttributes(). // windowAnimations = R.style.dialog_animation_fade; } @Override public Dialog onCreateDialog(Bundle savedInstanceState) { if (getActivity() != null) { final Dialog dialog = new Dialog(getActivity()); dialog.getWindow().requestFeature(Window.FEATURE_NO_TITLE); dialog.setContentView(R.layout.activity_image_zoom); dialog.getWindow().setBackgroundDrawableResource(R.color.Transparent); WindowManager.LayoutParams layoutParams = new WindowManager.LayoutParams(); layoutParams.copyFrom(dialog.getWindow().getAttributes()); layoutParams.width = WindowManager.LayoutParams.MATCH_PARENT; layoutParams.height = WindowManager.LayoutParams.MATCH_PARENT; dialog.getWindow().setAttributes(layoutParams); initToolbar(dialog); progressBar = dialog.findViewById(R.id.zoom_loader); zoomableImageView = (PhotoView) dialog.findViewById(R.id.image_zoom_photoview); if (bitmap != null) { if (rect != null) { animateIn(dialog); } } else if (fileUri != null){ showLoader(); Glide.with(getActivity()) .load(fileUri) .fitCenter() .listener(new RequestListener<Uri, GlideDrawable>() { @Override public boolean onException(Exception e, Uri model, Target<GlideDrawable> target, boolean isFirstResource) { return false; } @Override public boolean onResourceReady(GlideDrawable resource, Uri model, Target<GlideDrawable> target, boolean isFromMemoryCache, boolean isFirstResource) { hideLoader(); return false; } }) .into(zoomableImageView); } else { dismiss(); } photoViewAttacher = new PhotoViewAttacher(zoomableImageView); photoViewAttacher.setOnViewTapListener(new PhotoViewAttacher.OnViewTapListener() { @Override public void onViewTap(View view, float x, float y) { dismiss(); } }); return dialog; } else { return null; } } private void hideLoader() { progressBar.setVisibility(View.GONE); } private void showLoader() { progressBar.setVisibility(View.VISIBLE); } @Override public void onSaveInstanceState(Bundle outState) { outState.putInt(STATE_TOOLBAR_VISIBILITY, toolBarVisibility); if (bitmap != null) { outState.putParcelable(STATE_BITMAP, bitmap); } if (fileUri != null) { outState.putParcelable(STATE_URI_FILE, fileUri); } if (contentUri != null) { outState.putParcelable(STATE_URI_CONTENT, contentUri); } super.onSaveInstanceState(outState); } @Override public void dismiss() { if (rect != null) { animateOut(); new Handler().postDelayed(new Runnable() { @Override public void run() { dismissParent(); } }, 500); } else { dismissParent(); } } private void dismissParent() { super.dismiss(); } private void animateIn(final Dialog dialog) { RelativeLayout.LayoutParams params = (RelativeLayout.LayoutParams) zoomableImageView.getLayoutParams(); params.width = rect.right; params.height = rect.bottom; zoomableImageView.setLayoutParams(params); zoomableImageView.setX(rect.left); zoomableImageView.setY(rect.top - statusBarHeightCorrection); zoomableImageView.setAlpha(0.0f); zoomableImageView.setImageBitmap(bitmap); WindowManager win = getActivity().getWindowManager(); Display d = win.getDefaultDisplay(); int displayWidth = d.getWidth(); // Width of the actual device int displayHeight = d.getHeight() + statusBarHeightCorrection; ValueAnimator animWidth = ValueAnimator.ofInt(rect.right, displayWidth); animWidth.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { @Override public void onAnimationUpdate(ValueAnimator valueAnimator) { int val = (Integer) valueAnimator.getAnimatedValue(); ViewGroup.LayoutParams layoutParams = zoomableImageView.getLayoutParams(); layoutParams.width = val; zoomableImageView.setLayoutParams(layoutParams); } }); animWidth.setDuration(500); animWidth.setInterpolator(new LinearOutSlowInInterpolator()); animWidth.start(); ValueAnimator animHeight = ValueAnimator.ofInt(rect.bottom, displayHeight); animHeight.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { @Override public void onAnimationUpdate(ValueAnimator valueAnimator) { int val = (Integer) valueAnimator.getAnimatedValue(); ViewGroup.LayoutParams layoutParams = zoomableImageView.getLayoutParams(); layoutParams.height = val; zoomableImageView.setLayoutParams(layoutParams); } }); animHeight.setDuration(500); animHeight.setInterpolator(new LinearOutSlowInInterpolator()); animHeight.start(); if (statusBarHeightCorrection > 0) { zoomableImageView.animate() .y(0.0f) .setDuration(300) .start(); } ValueAnimator animDim = ValueAnimator.ofFloat(0.0f, 0.5f); animDim.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { @Override public void onAnimationUpdate(ValueAnimator valueAnimator) { WindowManager.LayoutParams layoutParams = new WindowManager.LayoutParams(); layoutParams.copyFrom(dialog.getWindow().getAttributes()); layoutParams.dimAmount = (Float) valueAnimator.getAnimatedValue(); dialog.getWindow().setAttributes(layoutParams); } }); animDim.setDuration(300); animDim.setStartDelay(300); animDim.start(); zoomableImageView.animate().alpha(1.0f).setDuration(300).start(); } private void animateOut() { ValueAnimator animWidth = ValueAnimator.ofInt( zoomableImageView.getMeasuredWidth(), rect.right ); animWidth.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { @Override public void onAnimationUpdate(ValueAnimator valueAnimator) { int val = (Integer) valueAnimator.getAnimatedValue(); ViewGroup.LayoutParams layoutParams = zoomableImageView.getLayoutParams(); layoutParams.width = val; zoomableImageView.setLayoutParams(layoutParams); } }); animWidth.setDuration(500); animWidth.start(); ValueAnimator animHeight = ValueAnimator.ofInt( zoomableImageView.getMeasuredHeight(), rect.bottom ); animHeight.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { @Override public void onAnimationUpdate(ValueAnimator valueAnimator) { int val = (Integer) valueAnimator.getAnimatedValue(); ViewGroup.LayoutParams layoutParams = zoomableImageView.getLayoutParams(); layoutParams.height = val; zoomableImageView.setLayoutParams(layoutParams); } }); animHeight.setDuration(500); animHeight.start(); if (statusBarHeightCorrection > 0) { zoomableImageView.animate() .y(-statusBarHeightCorrection) .setDuration(300) .start(); } zoomableImageView.animate().alpha(0.0f).setDuration(500).start(); } @Override public void onDestroyView() { if (getDialog() != null && getRetainInstance()) getDialog().setDismissMessage(null); super.onDestroyView(); } private void initToolbar(Dialog dialog) { toolBar = (ViewGroup) dialog.findViewById(R.id.zoom_toolbar); toolBar.setVisibility(toolBarVisibility); if (fileUri != null) { Button setAsButton = (Button) toolBar.findViewById(R.id.toolbar_set_as); setAsButton.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { setImageAsWallpaperPicker(fileUri); } }); } if (contentUri != null){ Button deleteButton = (Button) toolBar.findViewById(R.id.toolbar_delete); deleteButton.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { String quantityString = getResources().getQuantityString(R.plurals.wallpapers, 1); String title = String.format(getString(R.string.dialog_delete_title), quantityString); FragmentManager fragmentManager = getFragmentManager(); if (fragmentManager != null) { final MaterialDialogFragment materialDialogFragment = new MaterialDialogFragment(); materialDialogFragment.setPrimaryColor(getResources().getColor(R.color.Dialog_Button_Delete)); materialDialogFragment.setTitle(title); materialDialogFragment.setPositiveButton(R.string.dialog_delete_positive, new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialogInterface, int i) { delete(contentUri); } }); materialDialogFragment.setNegativeButton(R.string.dialog_delete_negative, new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialogInterface, int i) { materialDialogFragment.dismiss(); } }); materialDialogFragment.show(fragmentManager, MaterialDialogFragment.TAG); } } }); } } public void showFileOptions(Uri fileUri, Uri contentUri) { toolBarVisibility = View.VISIBLE; this.fileUri = fileUri; this.contentUri = contentUri; } private void setImageAsWallpaperPicker(Uri fileUri) { Intent intent = new Intent(Intent.ACTION_ATTACH_DATA); intent.setType("image/*"); MimeTypeMap map = MimeTypeMap.getSingleton(); String mimeType = map.getMimeTypeFromExtension("png"); intent.setDataAndType(fileUri, mimeType); intent.putExtra("mimeType", mimeType); intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION); startActivity(Intent.createChooser(intent, getString(R.string.action_set_as))); } private void delete(Uri contentUri) { getActivity().getContentResolver().delete(contentUri, null, null); //Not for SavedImagesFragment, but for the others to know that they should update their content (heart/unheart tiles) getActivity().sendBroadcast(new Intent(FileReceiver.GET_FILES)); dismiss(); } }